Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 6 additions & 6 deletions tavern/internal/www/build/asset-manifest.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion tavern/internal/www/build/index.html

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 0 additions & 4 deletions tavern/internal/www/build/static/css/main.6e7013ae.css

This file was deleted.

1 change: 0 additions & 1 deletion tavern/internal/www/build/static/css/main.6e7013ae.css.map

This file was deleted.

4 changes: 4 additions & 0 deletions tavern/internal/www/build/static/css/main.77f543a0.css

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions tavern/internal/www/build/static/css/main.77f543a0.css.map

Large diffs are not rendered by default.

3 changes: 3 additions & 0 deletions tavern/internal/www/build/static/js/main.cb0cd145.js

Large diffs are not rendered by default.

Large diffs are not rendered by default.

3 changes: 0 additions & 3 deletions tavern/internal/www/build/static/js/main.eb12c6d7.js

This file was deleted.

59 changes: 59 additions & 0 deletions tavern/internal/www/src/components/tavern-base-ui/badge/Badge.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
/* eslint-disable react/jsx-props-no-spreading */
import { FC, useMemo } from "react";
import { solidBadge } from "./BadgeStyles";
import { VariantProps } from "tailwind-variants";

// extend the base button attributes
interface BadgeProps {
leftIcon?: React.ReactElement;
rightIcon?: React.ReactElement;
className?: string,
children: any,
badgeStyle?: VariantProps<typeof solidBadge>;
}

const Badge: FC<BadgeProps> = (
{ children, leftIcon, rightIcon, badgeStyle, className, ...rest }
) => {

// determine icon placement
const { newIcon: icon, iconPlacement } = useMemo(() => {
let newIcon = rightIcon || leftIcon;

return {
newIcon,
iconPlacement: rightIcon ? ("right" as const) : ("left" as const),
};
}, [leftIcon, rightIcon]);

const renderBadgeVariant = () => {
return solidBadge({ ...badgeStyle, className })
}

return (
<div
className={renderBadgeVariant()}
{...rest}
>
{/** render icon before */}
{icon && iconPlacement === "left" ? (
<span className={`inline-flex shrink-0 self-center ${children}`}>{icon}</span>
) : null}

{children}

{/** render icon after */}
{icon && iconPlacement === "right" ? (
<span className={`inline-flex shrink-0 self-center ${children}`}>{icon}</span>
) : null}
</div>
);
};

// set default props
Badge.defaultProps = {
leftIcon: undefined,
rightIcon: undefined,
};

export default Badge;
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import { tv } from 'tailwind-variants';

export const baseBadge = tv({
base: 'py-1 px-2 rounded text-xs font-semibold',
});

// create solid Badge styles
export const solidBadge = tv({
extend: baseBadge,
variants: {
color: {
purple:
'btn-primary',
red: 'bg-red-600 text-white',
gray: 'bg-gray-200 text-gray-900',
green: ' bg-green-600 text-white'
},
},
});

//create outline Badge styles
export const outlineBadge = tv({
extend: baseBadge,
base: 'ring-1',
variants: {
color: {
purple: 'text-purple-800 ring-purple-800',
red: 'text-red-600 ring-red-800',
gray: 'text-gray-900 ring-gray-500',
green: ' bg-green-600 text-white'
},
},
});

//create ghost Badge styles
export const ghostBadge = tv({
extend: baseBadge,
variants: {
color: {
purple: 'text-purple-800',
red: 'text-red-800',
gray: 'text-gray-900',
green: ' bg-green-600 text-white'
},
},
});
39 changes: 39 additions & 0 deletions tavern/internal/www/src/features/task-card/TaskCard.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import { Task } from "../../utils/consts";
import { FC } from "react";
import TaskTimeStamp from "./components/TaskTimeStamp";
import TaskCreator from "./components/TaskCreator";
import TaskStatusBadge from "./components/TaskStatusBadge";
import TaskHostBeacon from "./components/TaskHostBeacon";
import TaskParameters from "./components/TaskParameters";
import TaskResults from "./components/TaskResults";

interface TaskCardType {
task: Task
}

const TaskCard: FC<TaskCardType> = (
{ task }
) => {
return (
<div className=" border-2 border-gray-200 px-8 py-5 w-full rounded-lg gap-4 grid grid-cols-1 lg:grid-cols-2">
<div className="flex flex-col gap-6 col-span-1">
<div className="flex flex-col gap-1">
<div className="flex flex-row gap-2 items-center">
<h3 className="text-lg font-semibold">
{task.quest?.name}
</h3>
<TaskStatusBadge task={task} />
</div>
</div>
<TaskHostBeacon beaconData={task.beacon} />
<TaskTimeStamp {...task} />
<TaskParameters quest={task?.quest} />
<TaskCreator creatorData={task?.quest?.creator} />
</div>
<div className="flex flex-col gap-2 col-span-1">
<TaskResults output={task?.output} error={task?.error} quest={task?.quest} />
</div>
</div>
);
};
export default TaskCard;
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import { Image } from "@chakra-ui/react";
import { FC } from "react";
import { UserType } from "../../../utils/consts";

interface TaskCreatorType {
creatorData: UserType | undefined;
}
const TaskCreator: FC<TaskCreatorType> = ({
creatorData
}) => {

if (!creatorData) {
return null;
}

return (
<div className="flex flex-row gap-4">
<Image
className="mt-1 w-5"
borderRadius='full'
boxSize='18px'
src={creatorData.photoURL}
alt={`Profile of ${creatorData.name}`}
/>
<div className="text-gray-600">
{creatorData.name}
</div>
</div>
)
}
export default TaskCreator;
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import { BugAntIcon } from "@heroicons/react/24/outline";
import Badge from "../../../components/tavern-base-ui/badge/Badge";
import { FC } from "react";
import { BeaconType } from "../../../utils/consts";
import { checkIfBeaconOffline } from "../../../utils/utils";

interface TaskHostBeaconType {
beaconData: BeaconType
}

const TaskHostBeacon: FC<TaskHostBeaconType> = ({ beaconData }) => {
const {
host,
principal,
name
} = beaconData;
const beaconOffline = checkIfBeaconOffline(beaconData);

return (
<div className=" flex flex-row gap-4">
<BugAntIcon className="h-5 w-5 mt-2" />
<div className="flex flex-col gap-1 ">
<div className="text-gray-600">
{name}@{host.name}
</div>
<div className="flex flex-row gap-2 flex-wrap">
{(principal && principal !== "") &&
<Badge badgeStyle={{ color: "gray" }}>{principal}</Badge>
}
{(host?.primaryIP && host?.primaryIP !== "") &&
<Badge badgeStyle={{ color: "gray" }}>{host?.primaryIP}</Badge>
}
{host?.platform &&
<Badge badgeStyle={{ color: "gray" }}>{host?.platform}</Badge>
}
{host?.tags && host?.tags.map((tag: any) => {
return <Badge key={tag.id} badgeStyle={{ color: "gray" }}>{tag.name}</Badge>
})}
{beaconOffline && <Badge badgeStyle={{ color: "gray" }}>Offline</Badge>}
</div>
</div>
</div>
);
};
export default TaskHostBeacon;
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import { FC } from "react";
import { QuestProps, TomeParams } from "../../../utils/consts";
import { constructTomeParams } from "../../../utils/utils";
import { WrenchScrewdriverIcon } from "@heroicons/react/24/outline";

interface TaskParametersType {
quest?: QuestProps
}
const TaskParameters: FC<TaskParametersType> = ({
quest
}) => {
const params = constructTomeParams(quest?.parameters, quest?.tome?.paramDefs);

return (
<div className="flex flex-row gap-4">
<WrenchScrewdriverIcon className="h-5 w-5 mt-1" />
<div className="flex flex-col gap-1 ">
<div className="text-gray-600">
Tome parameters
</div>
{params.map((paramDef: TomeParams) => {
if (paramDef.value) {
return (
<div className="flex flex-row gap-1 text-xs" key={paramDef.name}>
<div className="font-semibold">
{paramDef.name}:
</div>
<div>
{paramDef.value}
</div>
</div>
)
}
else {
return null;
}
})}
</div>
</div>
);
};
export default TaskParameters;
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import { FC } from "react";
import { Task } from "../../../utils/consts";
import { CodeBlock, tomorrow } from "react-code-blocks";
import { BookOpenIcon } from "@heroicons/react/24/outline";

interface TaskResultsType extends Pick<Task, 'error' | 'output' | 'quest'> { };

const TaskResults: FC<TaskResultsType> = ({
error,
output,
quest
}) => {
return (
<div className="flex flex-row gap-4">
<BookOpenIcon className="h-5 w-5 mt-1" />
<div className="flex flex-col gap-1 ">
<div className="text-gray-600">
Tome: {quest?.tome?.name}
</div>
<div className="flex flex-col gap-2 text-sm max-h-80 overflow-y-scroll">
{error ? (
<CodeBlock
className="-ml-2"
text={error}
language={""}
showLineNumbers={false}
theme={tomorrow}
codeBlock
/>
) : output && output?.length > 0 ? (
<CodeBlock
className="-ml-2"
text={output}
language={""}
showLineNumbers={false}
theme={tomorrow}
codeBlock
/>
) : (
<div className="mt-2 text-gray-600">No output available</div>
)}
</div>
</div>
</div>
);
};
export default TaskResults;
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import React from "react";

import Badge from "../../../components/tavern-base-ui/badge/Badge";

type Props = {
task: any;
}
const TaskStatusBadge = (props: Props) => {
const { task } = props;

if (task.error.length > 0) return <Badge badgeStyle={{ color: 'red' }} >Error</Badge>;
else if (task.execFinishedAt) return <Badge badgeStyle={{ color: 'green' }} >Finished</Badge>;
else if (task.execStartedAt) return <Badge badgeStyle={{ color: 'gray' }} >In progress</Badge>;
else return <Badge badgeStyle={{ color: 'gray' }} >Queued</Badge>;
}
export default TaskStatusBadge;
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import { FC, ReactElement } from "react";
import { Task } from "../../../utils/consts";
import { ClockIcon } from "@heroicons/react/24/outline";

interface TaskTimeStampType extends Pick<Task, 'createdAt' | 'execStartedAt' | 'execFinishedAt'> { };

const TaskTimeStamp: FC<TaskTimeStampType> = ({
createdAt,
execStartedAt,
execFinishedAt
}): ReactElement => {
const createdTime = new Date(createdAt || "");
const startTime = new Date(execStartedAt || "");
const finishTime = new Date(execFinishedAt || "");

return (
<div className="flex flex-row gap-4">
<ClockIcon className="h-5 w-5 mt-1" />
<div className="flex flex-col gap-1 ">
<div className="text-gray-600">Status</div>
{createdAt && <span className="text-xs">{`Created at ${createdTime.toLocaleTimeString()} on ${createdTime.toDateString()}`}</span>}
{execStartedAt && <span className="text-xs">{`Started at ${startTime.toLocaleTimeString()} on ${startTime.toDateString()}`}</span>}
{execFinishedAt && <span className="text-xs">{`Finished at ${finishTime.toLocaleTimeString()} on ${finishTime.toDateString()}`}</span>}
</div>
</div>
);
}
export default TaskTimeStamp;
Loading