-
Notifications
You must be signed in to change notification settings - Fork 23
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Closes #1354 fix: improve playbook run as suggested in the PR feat: add duration and date columns to the runs list
- Loading branch information
1 parent
857f1fd
commit 37b3579
Showing
12 changed files
with
640 additions
and
34 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
import { relativeDateTime } from "../../../utils/date"; | ||
import { PlaybookRunAction } from "./PlaybookRunsActions"; | ||
import PlaybookRunsStatus from "./PlaybookRunsStatus"; | ||
|
||
type PlaybookRunsActionItemProps = { | ||
action: PlaybookRunAction; | ||
onClick?: () => void; | ||
isSelected?: boolean; | ||
}; | ||
|
||
export default function PlaybookRunsActionItem({ | ||
action, | ||
onClick = () => {}, | ||
isSelected = false | ||
}: PlaybookRunsActionItemProps) { | ||
return ( | ||
<div | ||
role="button" | ||
onClick={onClick} | ||
key={action.id} | ||
className={`flex flex-row items-center justify-between px-4 py-2 bg-white border border-gray-200 hover:bg-gray-200 rounded cursor-pointer ${ | ||
isSelected ? "bg-gray-200" : "" | ||
}`} | ||
> | ||
<div className="flex flex-col"> | ||
<div className="flex flex-row gap-2 text-sm font-medium text-gray-600"> | ||
<PlaybookRunsStatus status={action.status} hideStatusLabel /> | ||
{action.name} | ||
</div> | ||
<div className={`text-xs flex flex-row gap-1 items-center`}></div> | ||
</div> | ||
<div className="flex flex-col"> | ||
<div className="text-sm font-medium text-gray-600"> | ||
{" "} | ||
{!isSelected | ||
? relativeDateTime(action.start_time!, action.end_time) | ||
: relativeDateTime(action.start_time!)} | ||
</div> | ||
</div> | ||
</div> | ||
); | ||
} |
86 changes: 86 additions & 0 deletions
86
src/components/Playbooks/Runs/PlaybookRunsActions.stories.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,86 @@ | ||
import { StoryObj } from "@storybook/react"; | ||
import PlaybookRunsActions, { | ||
PlaybookRunWithActions | ||
} from "./PlaybookRunsActions"; | ||
|
||
export default { | ||
title: "PlaybookRunsActions", | ||
component: PlaybookRunsActions | ||
}; | ||
|
||
const mockPlaybookRun: PlaybookRunWithActions = { | ||
id: "1", | ||
playbook_id: "1", | ||
status: "completed", | ||
created_at: "2021-08-19T07:00:00.000Z", | ||
start_time: "2021-08-19T07:00:00.000Z", | ||
end_time: "2021-08-19T07:00:00.000Z", | ||
created_by: { | ||
id: "1", | ||
name: "John Doe", | ||
email: "" | ||
}, | ||
component_id: "1", | ||
parameters: {}, | ||
component: { | ||
id: "1", | ||
name: "Topology 1", | ||
icon: "TopologyIcon" | ||
}, | ||
actions: [ | ||
{ | ||
id: "1", | ||
name: "Action 1", | ||
status: "completed", | ||
end_time: "2021-08-19T07:00:00.000Z", | ||
start_time: "2021-08-19T07:00:00.000Z", | ||
playbook_run_id: "1", | ||
result: `You can also use variant modifiers to target media queries like responsive breakpoints, dark mode, prefers-reduced-motion, and more. For example, use md:font-serif to apply the font-serif utility at only medium screen sizes and above. | ||
You can also use variant modifiers to target media queries like responsive breakpoints, dark mode, prefers-reduced-motion, and more. For example, use md:font-serif to apply the font-serif utility at only medium screen sizes and above. | ||
You can also use variant modifiers to target media queries like responsive breakpoints, dark mode, prefers-reduced-motion, and more. For example, use md:font-serif to apply the font-serif utility at only medium screen sizes and above. | ||
You can also use variant modifiers to target media queries like responsive breakpoints, dark mode, prefers-reduced-motion, and more. For example, use md:font-serif to apply the font-serif utility at only medium screen sizes and above.`, | ||
error: "" | ||
}, | ||
{ | ||
id: "2", | ||
name: "Action 2", | ||
status: "completed", | ||
end_time: "2021-08-19T07:00:00.000Z", | ||
start_time: "2021-08-19T07:00:00.000Z", | ||
playbook_run_id: "1", | ||
result: `You can also use variant modifiers to target media queries like responsive breakpoints, dark mode, prefers-reduced-motion, and more. For example, use md:font-serif to apply the font-serif utility at only medium screen sizes and above. | ||
You can also use variant modifiers to target media queries like responsive breakpoints, dark mode, prefers-reduced-motion, and more. For example, use md:font-serif to apply the font-serif utility at only medium screen sizes and above.`, | ||
error: "" | ||
}, | ||
{ | ||
id: "3", | ||
name: "Action 3", | ||
status: "pending", | ||
end_time: undefined, | ||
error: "", | ||
result: "", | ||
start_time: "2021-08-19T07:00:00.000Z", | ||
playbook_run_id: "1" | ||
}, | ||
{ | ||
id: "4", | ||
name: "Action 4", | ||
status: "running", | ||
end_time: undefined, | ||
error: "", | ||
result: "", | ||
start_time: "2021-08-19T07:00:00.000Z", | ||
playbook_run_id: "1" | ||
} | ||
] | ||
}; | ||
|
||
type Story = StoryObj<typeof PlaybookRunsActions>; | ||
|
||
export const Default: Story = { | ||
render: () => <PlaybookRunsActions data={mockPlaybookRun} /> | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,119 @@ | ||
import { ReactNode, useMemo, useState } from "react"; | ||
import { Link } from "react-router-dom"; | ||
import { relativeDateTime } from "../../../utils/date"; | ||
import { Avatar } from "../../Avatar"; | ||
import { Icon } from "../../Icon"; | ||
import PlaybookRunsActionItem from "./PlaybookRunsActionItem"; | ||
import { PlaybookRun, PlaybookRunStatus } from "./PlaybookRunsList"; | ||
import PlaybookRunsStatus from "./PlaybookRunsStatus"; | ||
|
||
export type PlaybookRunAction = { | ||
id: string; | ||
name: string; | ||
status: PlaybookRunStatus; | ||
playbook_run_id: string; | ||
start_time?: string; | ||
end_time?: string; | ||
result?: { | ||
stdout?: string; | ||
}; | ||
error?: string; | ||
}; | ||
|
||
export type PlaybookRunWithActions = PlaybookRun & { | ||
actions: PlaybookRunAction[]; | ||
}; | ||
|
||
type PlaybookRunActionsProps = { | ||
data: PlaybookRunWithActions; | ||
}; | ||
|
||
export default function PlaybookRunsActions({ data }: PlaybookRunActionsProps) { | ||
const [selectedAction, setSelectedAction] = useState<PlaybookRunAction>(); | ||
|
||
const headerContent = useMemo( | ||
() => | ||
new Map<string, ReactNode>([ | ||
[ | ||
"Playbook", | ||
<Link | ||
className="text-blue-500 hover:underline" | ||
to={`/playbooks/${data.playbook_id}`} | ||
> | ||
{data.playbooks?.name} | ||
</Link> | ||
], | ||
[ | ||
"Component", | ||
<Link | ||
className="text-blue-500 hover:underline" | ||
to={`/topologies/${data.component_id}`} | ||
> | ||
<Icon name={data.component?.icon} className="mr-1 h-5 w-5" /> | ||
{data.component?.name} | ||
</Link> | ||
], | ||
[ | ||
"Status", | ||
<div className="flex flex-row gap-2 items-center"> | ||
<PlaybookRunsStatus status={data.status} /> | ||
</div> | ||
], | ||
["Start Time", relativeDateTime(data.start_time)], | ||
["Duration", relativeDateTime(data.start_time, data.end_time)], | ||
[ | ||
"Triggered By", | ||
data.created_by ? ( | ||
<div className="flex flex-row gap-2"> | ||
<Avatar user={data.created_by} />{" "} | ||
<span>{data.created_by.name}</span> | ||
</div> | ||
) : null | ||
] | ||
]), | ||
[data] | ||
); | ||
|
||
return ( | ||
<div className="flex flex-col flex-1 gap-4"> | ||
<div className="flex flex-row gap-2 px-4 py-2"> | ||
{Array.from(headerContent).map(([label, value]) => ( | ||
<div key={label} className=" flex flex-col gap-2 px-2"> | ||
<div className="text-sm overflow-hidden truncate text-gray-500"> | ||
{label} | ||
</div> | ||
<div className="flex justify-start break-all text-sm font-semibold"> | ||
{value} | ||
</div> | ||
</div> | ||
))} | ||
</div> | ||
<div className="flex flex-row h-full"> | ||
<div className="flex flex-col w-[30rem] h-full px-2 border-r border-gray-200"> | ||
<div className="flex flex-row items-center justify-between px-4 py-2 mb-2 border-b border-gray-100"> | ||
<div className="font-semibold text-gray-600">Actions</div> | ||
</div> | ||
<div className="flex flex-col flex-1 overflow-y-auto gap-2"> | ||
{data.actions.map((action) => ( | ||
<PlaybookRunsActionItem | ||
isSelected={selectedAction?.id === action.id} | ||
key={action.id} | ||
action={action} | ||
onClick={() => setSelectedAction(action)} | ||
/> | ||
))} | ||
</div> | ||
</div> | ||
<div className="flex flex-col flex-1 h-full font-mono px-4 py-2 text-white bg-gray-700"> | ||
{selectedAction && ( | ||
<div className="flex flex-col gap-2 whitespace-pre-wrap "> | ||
{selectedAction.result?.stdout | ||
? selectedAction.result.stdout | ||
: selectedAction.error || "No result"} | ||
</div> | ||
)} | ||
</div> | ||
</div> | ||
</div> | ||
); | ||
} |
Oops, something went wrong.