From 8f45920dfa782a8ab34b0dc53bb053dd4845d50a Mon Sep 17 00:00:00 2001 From: Remington Breeze Date: Tue, 23 Jul 2024 16:43:36 -0700 Subject: [PATCH 01/17] fix(ui): incorrect DAG rendering for singular forward connection to node with multiple backward connections (#2334) Signed-off-by: Remington Breeze --- .../features/project/pipelines/utils/graph.ts | 31 ++++++++++++------- 1 file changed, 20 insertions(+), 11 deletions(-) diff --git a/ui/src/features/project/pipelines/utils/graph.ts b/ui/src/features/project/pipelines/utils/graph.ts index 4a9b97e2f..3fdedebfe 100644 --- a/ui/src/features/project/pipelines/utils/graph.ts +++ b/ui/src/features/project/pipelines/utils/graph.ts @@ -44,7 +44,10 @@ export const nodeStubFor = (type: NodeType) => { }; export const getConnectors = (g: graphlib.Graph) => { - const groups: { [key: string]: { [key: string]: ConnectorsType[][] } } = {}; + const forward: { [key: string]: { [key: string]: ConnectorsType[][] } } = {}; + const backward: { [key: string]: { [key: string]: boolean } } = {}; + + // horizontal edges are only between nodes where the parent has only one child and the child has only one parent g.edges().map((item) => { const edge = g.edge(item); const points = edge.points; @@ -71,22 +74,28 @@ export const getConnectors = (g: graphlib.Graph) => { lines.push({ x: cx, y: cy, width, angle, color: edge['color'] }); } - const fromGr = groups[from] || {}; - groups[from] = { ...fromGr, [to]: [...(fromGr[to] || []), lines] }; + const fromGr = forward[from] || {}; + forward[from] = { ...fromGr, [to]: [...(fromGr[to] || []), lines] }; + + const backwardGr = backward[to] || {}; + backward[to] = { ...backwardGr, [from]: true }; }); - for (const fromKey in groups) { - if (Object.keys(groups[fromKey] || {}).length === 1) { - for (const group of Object.values(groups[fromKey])) { - group.forEach((lines) => { - lines.forEach((line) => { - line.angle = 0; + for (const fromKey in forward) { + if (Object.keys(forward[fromKey] || {}).length === 1) { + for (const toKey of Object.keys(forward[fromKey])) { + if (Object.keys(backward[toKey] || {}).length === 1) { + const group = forward[fromKey][toKey]; + group.forEach((lines) => { + lines.forEach((line) => { + line.angle = 0; + }); }); - }); + } } } } - return Object.values(groups).flatMap((group) => + return Object.values(forward).flatMap((group) => Object.values(group).flatMap((item) => Object.values(item)) ); }; From e0a6b019946546fd9b49a03074cc285e075f49ee Mon Sep 17 00:00:00 2001 From: Remington Breeze Date: Tue, 23 Jul 2024 17:27:14 -0700 Subject: [PATCH 02/17] fix(ui): properly display stage indicators in timeline after migration (#2336) Signed-off-by: Remington Breeze --- ui/src/features/project/pipelines/pipelines.tsx | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/ui/src/features/project/pipelines/pipelines.tsx b/ui/src/features/project/pipelines/pipelines.tsx index 5ed290e90..ebf42a813 100644 --- a/ui/src/features/project/pipelines/pipelines.tsx +++ b/ui/src/features/project/pipelines/pipelines.tsx @@ -165,8 +165,12 @@ export const Pipelines = () => { const stagesPerFreight: { [key: string]: Stage[] } = {}; const subscribersByStage = {} as { [key: string]: Set }; (data?.stages || []).forEach((stage) => { - const items = stagesPerFreight[stage.status?.currentFreight?.name || ''] || []; - stagesPerFreight[stage.status?.currentFreight?.name || ''] = [...items, stage]; + (getCurrentFreight(stage) || []).forEach((f) => { + if (!stagesPerFreight[f.name || '']) { + stagesPerFreight[f.name || ''] = []; + } + stagesPerFreight[f.name || ''].push(stage); + }); stage?.spec?.subscriptions?.upstreamStages.forEach((item) => { if (!subscribersByStage[item.name || '']) { subscribersByStage[item.name || ''] = new Set(); From 1f1bace7e75a9c71696a733132691c72c8426a59 Mon Sep 17 00:00:00 2001 From: Remington Breeze Date: Tue, 23 Jul 2024 17:39:59 -0700 Subject: [PATCH 03/17] feat(ui): visual + layout improvements (#2284) Signed-off-by: Remington Breeze --- .../create-freight/artifact-menu-group.tsx | 2 +- .../create-freight/artifact-menu-item.tsx | 2 +- .../create-freight/create-freight.tsx | 14 +- .../features/create-freight/image-table.tsx | 2 +- .../create-freight/truncated-copyable.tsx | 5 +- .../freight-timeline/freight-contents.tsx | 13 +- .../freight-timeline-header.tsx | 187 +++++++++--------- .../freight-timeline-wrapper.tsx | 2 +- .../freight-timeline/freight-timeline.less | 8 + .../freight-timeline.module.less | 4 +- .../freight-timeline/freight-timeline.tsx | 2 +- .../list/project-item/stage-popover.tsx | 2 +- ui/src/features/project/pipelines/images.tsx | 10 +- .../project/pipelines/nodes/repo-node.tsx | 4 +- .../features/project/pipelines/pipelines.tsx | 91 +++++---- .../project/settings/project-settings.tsx | 8 +- ui/src/pages/downloads.tsx | 4 +- ui/src/pages/project.tsx | 41 ++-- 18 files changed, 206 insertions(+), 195 deletions(-) create mode 100644 ui/src/features/freight-timeline/freight-timeline.less diff --git a/ui/src/features/create-freight/artifact-menu-group.tsx b/ui/src/features/create-freight/artifact-menu-group.tsx index 9a13be91e..aeff556fa 100644 --- a/ui/src/features/create-freight/artifact-menu-group.tsx +++ b/ui/src/features/create-freight/artifact-menu-group.tsx @@ -19,7 +19,7 @@ export const ArtifactMenuGroup = ({ }) => items?.length > 0 && (
-
+
{label}
diff --git a/ui/src/features/create-freight/artifact-menu-item.tsx b/ui/src/features/create-freight/artifact-menu-item.tsx index fa0ad704d..e4c4a8b99 100644 --- a/ui/src/features/create-freight/artifact-menu-item.tsx +++ b/ui/src/features/create-freight/artifact-menu-item.tsx @@ -12,7 +12,7 @@ export const ArtifactMenuItem = ({ onClick, selected, children }: ArtifactMenuIt
diff --git a/ui/src/features/create-freight/create-freight.tsx b/ui/src/features/create-freight/create-freight.tsx index 003a64b15..98268a6aa 100644 --- a/ui/src/features/create-freight/create-freight.tsx +++ b/ui/src/features/create-freight/create-freight.tsx @@ -1,5 +1,5 @@ import { useMutation } from '@connectrpc/connect-query'; -import { faDocker, faGit } from '@fortawesome/free-brands-svg-icons'; +import { faDocker, faGitAlt } from '@fortawesome/free-brands-svg-icons'; import { faAnchor } from '@fortawesome/free-solid-svg-icons'; import { Button, message } from 'antd'; import { useMemo, useState } from 'react'; @@ -221,7 +221,7 @@ export const CreateFreight = ({ return (
-
FREIGHT CONTENTS
+
FREIGHT CONTENTS
{Object.keys(chosenItems)?.length > 0 ? ( <> @@ -251,24 +251,24 @@ export const CreateFreight = ({ ) : ( -
+
Freight contents will appear here once you select artifacts below.
)}
{warehouse ? ( -
-
+
+
- +
) : ( -
Please select a warehouse to continue.
+
Please select a warehouse to continue.
)}
); diff --git a/ui/src/features/create-freight/image-table.tsx b/ui/src/features/create-freight/image-table.tsx index 4672207bc..47286c010 100644 --- a/ui/src/features/create-freight/image-table.tsx +++ b/ui/src/features/create-freight/image-table.tsx @@ -40,7 +40,7 @@ export const ImageTable = ({ {record?.gitRepoURL} ) : ( - + ) }, { diff --git a/ui/src/features/create-freight/truncated-copyable.tsx b/ui/src/features/create-freight/truncated-copyable.tsx index c275ec0d3..ae17b8eff 100644 --- a/ui/src/features/create-freight/truncated-copyable.tsx +++ b/ui/src/features/create-freight/truncated-copyable.tsx @@ -14,10 +14,7 @@ export const TruncatedCopyable = ({ text }: { text?: string }) => { setTimeout(() => setCopied(false), 1000); }} > - +
{text}
diff --git a/ui/src/features/freight-timeline/freight-contents.tsx b/ui/src/features/freight-timeline/freight-contents.tsx index 732a02447..a102b4790 100644 --- a/ui/src/features/freight-timeline/freight-contents.tsx +++ b/ui/src/features/freight-timeline/freight-contents.tsx @@ -1,4 +1,4 @@ -import { faDocker, faGit } from '@fortawesome/free-brands-svg-icons'; +import { faDocker, faGitAlt } from '@fortawesome/free-brands-svg-icons'; import { IconDefinition, faAnchor } from '@fortawesome/free-solid-svg-icons'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { Tooltip } from 'antd'; @@ -16,7 +16,7 @@ export const FreightContents = (props: { dark?: boolean; }) => { const { freight, highlighted, horizontal, dark } = props; - const linkClass = `${highlighted ? 'text-blue-600' : 'text-gray-400'} hover:text-blue-500 underline hover:underline max-w-full min-w-0 flex-shrink`; + const linkClass = `${highlighted ? 'text-blue-500' : 'text-gray-400'} hover:text-blue-400 hover:underline max-w-full min-w-0 flex-shrink`; const FreightContentItem = (props: { icon: IconDefinition; @@ -30,14 +30,17 @@ export const FreightContents = (props: { 'flex-col p-1 w-full': !horizontal, 'mr-2 p-2 max-w-60 flex-shrink': horizontal, 'bg-black text-white': dark, - 'bg-neutral-300': !dark + 'bg-white': !dark && highlighted && !horizontal, + 'border border-solid border-gray-200': !dark && !highlighted && !horizontal, + 'bg-gray-200': !dark && horizontal })} overlay={props.overlay} title={props.title} > } - icon={faGit} + icon={faGitAlt} href={`${c.repoURL?.replace('.git', '')}/commit/${c.id}`} > {c.tag && c.tag.length > 12 diff --git a/ui/src/features/freight-timeline/freight-timeline-header.tsx b/ui/src/features/freight-timeline/freight-timeline-header.tsx index 3cdd48f31..3144f7763 100644 --- a/ui/src/features/freight-timeline/freight-timeline-header.tsx +++ b/ui/src/features/freight-timeline/freight-timeline-header.tsx @@ -19,6 +19,8 @@ import { Warehouse } from '@ui/gen/v1alpha1/generated_pb'; import { FreightTimelineAction } from '../project/pipelines/types'; +import './freight-timeline.less'; + export const FreightTimelineHeader = ({ promotingStage, action, @@ -60,73 +62,77 @@ export const FreightTimelineHeader = ({ const navigate = useNavigate(); - return ( -
-
- {action ? ( - <> -
- - {promotingStage && action != 'manualApproval' ? ( - <> - PROMOTING{' '} - {action === 'promoteSubscribers' - ? `TO ${(downstreamSubs || []).length} DOWNSTREAM SUBSCRIBERS (${downstreamSubs?.join(', ')}) OF` - : ''}{' '} - STAGE :{' '} -
- {promotingStage.toUpperCase()} -
- - Available freight are any which have been verified in{' '} - {action === 'promote' && 'any immediately upstream stage OR approved for'}{' '} - this stage. - - } - > - - - - ) : ( - <>MANUALLY APPROVING FREIGHT - )} -
+ const headerButtonStyle = 'bg-transparent text-gray-500 -mb-1 mr-2 text-xs'; -
- CANCEL -
- - ) : ( - <> -
- - FREIGHT TIMELINE -
- {collapsable && ( - - - {(Object.keys(warehouses) || []).length > 1 && ( -
- setSelectedWarehouse(value)} + size='small' + labelRender={({ label }) =>
{label}
} + optionRender={(opt) => ( +
+
{opt.label}
+
+ )} + options={[ + ...(Object.keys(warehouses) || []).map((w) => ({ value: w, label: w })), + { + value: '', + label: 'All warehouses' + } + ]} + /> +
+ )} + + )}
); }; diff --git a/ui/src/features/freight-timeline/freight-timeline-wrapper.tsx b/ui/src/features/freight-timeline/freight-timeline-wrapper.tsx index 310ca4fd8..defcb6782 100644 --- a/ui/src/features/freight-timeline/freight-timeline-wrapper.tsx +++ b/ui/src/features/freight-timeline/freight-timeline-wrapper.tsx @@ -1,6 +1,6 @@ export const FreightTimelineWrapper = ({ children }: { children: React.ReactNode }) => { return ( -
+
diff --git a/ui/src/features/project/list/project-item/stage-popover.tsx b/ui/src/features/project/list/project-item/stage-popover.tsx index 8d4a6a582..832a4f73d 100644 --- a/ui/src/features/project/list/project-item/stage-popover.tsx +++ b/ui/src/features/project/list/project-item/stage-popover.tsx @@ -41,7 +41,7 @@ export const StagePopover = ({ project, stage }: { project?: string; stage?: Sta }); const _label = ({ children }: { children: string }) => ( -
{children}
+
{children}
); const navigate = useNavigate(); diff --git a/ui/src/features/project/pipelines/images.tsx b/ui/src/features/project/pipelines/images.tsx index f4259db61..e6dbce36c 100644 --- a/ui/src/features/project/pipelines/images.tsx +++ b/ui/src/features/project/pipelines/images.tsx @@ -53,7 +53,7 @@ const ImageTagRow = ({ return (
void; }) => { - const colors = useContext(ColorContext); + const { stageColorMap: colors } = useContext(ColorContext); const images = useMemo(() => { const images = new Map>(); stages.forEach((stage) => { @@ -169,8 +169,8 @@ export const Images = ({ }, [imageURL]); return ( -
-

+
+

IMAGES
@@ -227,7 +227,7 @@ const Select = ({ options: { label?: string; value: string }[]; }) => (