From 4b881cac48c6f70d3dc2666c48259d93ab9c3440 Mon Sep 17 00:00:00 2001 From: Remington Breeze Date: Tue, 6 Aug 2024 14:48:03 -0700 Subject: [PATCH 1/3] fix(ui): hide subscriptions per warehouse in DAG Signed-off-by: Remington Breeze --- ui/src/features/project/pipelines/pipelines.tsx | 11 ++++++++--- .../pipelines/utils/use-pipeline-graph.ts | 16 ++++++++-------- 2 files changed, 16 insertions(+), 11 deletions(-) diff --git a/ui/src/features/project/pipelines/pipelines.tsx b/ui/src/features/project/pipelines/pipelines.tsx index 136cf0265..a90320b8c 100644 --- a/ui/src/features/project/pipelines/pipelines.tsx +++ b/ui/src/features/project/pipelines/pipelines.tsx @@ -111,7 +111,7 @@ export const Pipelines = ({ project }: { project: Project }) => { const [highlightedStages, setHighlightedStages] = React.useState<{ [key: string]: boolean }>({}); const [hideSubscriptions, setHideSubscriptions] = useLocalStorage( `${name}-hideSubscriptions`, - false + {} ); const [selectedWarehouse, setSelectedWarehouse] = React.useState(''); @@ -517,8 +517,13 @@ export const Pipelines = ({ project }: { project: Project }) => { {node.type === NodeType.WAREHOUSE && ( setHideSubscriptions(!hideSubscriptions)} - icon={hideSubscriptions ? faEye : faEyeSlash} + onClick={() => + setHideSubscriptions({ + ...hideSubscriptions, + [node.warehouseName]: !hideSubscriptions[node.warehouseName] + }) + } + icon={hideSubscriptions[node.warehouseName] ? faEye : faEyeSlash} begin={true} /> )} diff --git a/ui/src/features/project/pipelines/utils/use-pipeline-graph.ts b/ui/src/features/project/pipelines/utils/use-pipeline-graph.ts index 20222b280..5bd87e381 100644 --- a/ui/src/features/project/pipelines/utils/use-pipeline-graph.ts +++ b/ui/src/features/project/pipelines/utils/use-pipeline-graph.ts @@ -21,7 +21,7 @@ import { IndexCache } from './index-cache'; const initializeNodes = ( warehouses: Warehouse[], stages: Stage[], - hideSubscriptions: boolean, + hideSubscriptions: { [key: string]: boolean }, project?: string ): [AnyNodeType[], ColorMap] => { const warehouseMap = {} as { [key: string]: Warehouse }; @@ -78,14 +78,14 @@ const initializeNodes = ( return n; }); - if (!hideSubscriptions) { - warehouses.forEach((w) => { - // create subscription nodes - w?.spec?.subscriptions?.forEach((sub) => { + warehouses.forEach((w) => { + // create subscription nodes + w?.spec?.subscriptions?.forEach((sub) => { + if (w.metadata?.name && !hideSubscriptions[w.metadata.name]) { nodes.push(newSubscriptionNode(sub, w.metadata?.name || '')); - }); + } }); - } + }); const warehouseColorMap = getColors(project || '', warehouses, 'warehouses'); @@ -97,7 +97,7 @@ export const usePipelineGraph = ( project: string | undefined, stages: Stage[], warehouses: Warehouse[], - hideSubscriptions: boolean + hideSubscriptions: { [key: string]: boolean } ): [DagreNode[], ConnectorsType[][], BoxType, Stage[], ColorMap, ColorMap] => { return useMemo(() => { if (!stages || !warehouses || !project) { From 36b3341ed6a2abfa2bc21a092ad6ea5ab8ba3601 Mon Sep 17 00:00:00 2001 From: Remington Breeze Date: Wed, 14 Aug 2024 16:58:01 -0700 Subject: [PATCH 2/3] hide subs instead of rerendering DAG Signed-off-by: Remington Breeze --- .../features/project/pipelines/pipelines.tsx | 23 ++++--------------- 1 file changed, 5 insertions(+), 18 deletions(-) diff --git a/ui/src/features/project/pipelines/pipelines.tsx b/ui/src/features/project/pipelines/pipelines.tsx index a90320b8c..711e71b74 100644 --- a/ui/src/features/project/pipelines/pipelines.tsx +++ b/ui/src/features/project/pipelines/pipelines.tsx @@ -111,7 +111,7 @@ export const Pipelines = ({ project }: { project: Project }) => { const [highlightedStages, setHighlightedStages] = React.useState<{ [key: string]: boolean }>({}); const [hideSubscriptions, setHideSubscriptions] = useLocalStorage( `${name}-hideSubscriptions`, - {} + false ); const [selectedWarehouse, setSelectedWarehouse] = React.useState(''); @@ -133,7 +133,6 @@ export const Pipelines = ({ project }: { project: Project }) => { allFreight.forEach((f) => { if ( !selectedWarehouse || - f.warehouse === selectedWarehouse || (f?.origin?.kind === 'Warehouse' && f?.origin.name === selectedWarehouse) ) { filteredFreight.push(f); @@ -192,12 +191,6 @@ export const Pipelines = ({ project }: { project: Project }) => { } stagesPerFreight[f.name || ''].push(stage); }); - stage?.spec?.subscriptions?.upstreamStages.forEach((item) => { - if (!subscribersByStage[item.name || '']) { - subscribersByStage[item.name || ''] = new Set(); - } - subscribersByStage[item.name || ''].add(stage?.metadata?.name || ''); - }); stage?.spec?.requestedFreight?.forEach((item) => { if (!item.sources?.direct) { (item?.sources?.stages || []).forEach((name) => { @@ -414,11 +407,10 @@ export const Pipelines = ({ project }: { project: Project }) => { (acc, cur) => acc || cur?.origin?.kind === 'Warehouse', false ); - let currentWarehouse = currentFreight[0]?.warehouse || ''; - if (currentWarehouse === '' && isWarehouseKind) { + let currentWarehouse = ''; + if (isWarehouseKind) { currentWarehouse = currentFreight[0]?.origin?.name || - node.data?.spec?.subscriptions?.warehouse || node.data?.spec?.requestedFreight[0]?.origin?.name || ''; } @@ -517,13 +509,8 @@ export const Pipelines = ({ project }: { project: Project }) => { {node.type === NodeType.WAREHOUSE && ( - setHideSubscriptions({ - ...hideSubscriptions, - [node.warehouseName]: !hideSubscriptions[node.warehouseName] - }) - } - icon={hideSubscriptions[node.warehouseName] ? faEye : faEyeSlash} + onClick={() => setHideSubscriptions(!hideSubscriptions)} + icon={hideSubscriptions ? faEye : faEyeSlash} begin={true} /> )} From abec7564d24debe12429cba98dbeff37d7bbef6a Mon Sep 17 00:00:00 2001 From: Remington Breeze Date: Wed, 14 Aug 2024 16:58:12 -0700 Subject: [PATCH 3/3] hide subs instead of rerendering DAG Signed-off-by: Remington Breeze --- .../project/pipelines/nodes/repo-node.tsx | 7 +- .../features/project/pipelines/pipelines.tsx | 49 ++++++---- ui/src/features/project/pipelines/types.ts | 2 + .../features/project/pipelines/utils/graph.ts | 17 ++-- .../pipelines/utils/use-pipeline-graph.ts | 92 +++++-------------- 5 files changed, 68 insertions(+), 99 deletions(-) diff --git a/ui/src/features/project/pipelines/nodes/repo-node.tsx b/ui/src/features/project/pipelines/nodes/repo-node.tsx index e6f6837c1..a1f4ba6a0 100644 --- a/ui/src/features/project/pipelines/nodes/repo-node.tsx +++ b/ui/src/features/project/pipelines/nodes/repo-node.tsx @@ -29,6 +29,7 @@ type Props = { nodeData: RepoNodeType; children?: React.ReactNode; onClick?: () => void; + hidden?: boolean; }; const ico = { @@ -38,7 +39,7 @@ const ico = { [NodeType.REPO_CHART]: faAnchor }; -export const RepoNode = ({ nodeData, children, onClick }: Props) => { +export const RepoNode = ({ nodeData, children, onClick, hidden }: Props) => { const { warehouseColorMap } = useContext(ColorContext); const type = nodeData.type; const value = @@ -47,6 +48,10 @@ export const RepoNode = ({ nodeData, children, onClick }: Props) => { : type === NodeType.WAREHOUSE ? nodeData?.data?.metadata?.name || '' : nodeData?.data?.repoURL || ''; + + if (hidden) { + return null; + } return (
{ const [nodes, connectors, box, sortedStages, stageColorMap, warehouseColorMap] = usePipelineGraph( name, data?.stages || [], - warehouseData?.warehouses || [], - hideSubscriptions + warehouseData?.warehouses || [] ); const { mutate: manualApproveAction } = useMutation(approveFreight, { @@ -459,6 +458,9 @@ export const Pipelines = ({ project }: { project: Project }) => { ) : (
))} {connectors?.map((connector) => - connector.map((line, i) => ( -
- )) + connector.map((line, i) => + hideSubscriptions[line.to] && line.from === 'subscription' ? null : ( +
+ ) + ) )}
diff --git a/ui/src/features/project/pipelines/types.ts b/ui/src/features/project/pipelines/types.ts index fb832ee21..6a32c17fb 100644 --- a/ui/src/features/project/pipelines/types.ts +++ b/ui/src/features/project/pipelines/types.ts @@ -99,6 +99,8 @@ export interface ConnectorsType { width: number; angle: number; color: string; + from: string; + to: string; } export interface BoxType { diff --git a/ui/src/features/project/pipelines/utils/graph.ts b/ui/src/features/project/pipelines/utils/graph.ts index 39835b08e..a7d9f102f 100644 --- a/ui/src/features/project/pipelines/utils/graph.ts +++ b/ui/src/features/project/pipelines/utils/graph.ts @@ -6,14 +6,13 @@ import { AnyNodeType, ConnectorsType, NodeType, RepoNodeType } from '../types'; export const LINE_THICKNESS = 2; -export const initNodeArray = (s: Stage) => - [ - { - data: s, - type: NodeType.STAGE, - color: '#000' - } - ] as AnyNodeType[]; +export const initNode = (s: Stage) => { + return { + data: s, + type: NodeType.STAGE, + color: '#000' + } as AnyNodeType; +}; export const getNodeType = (sub: RepoSubscription) => sub.chart ? NodeType.REPO_CHART : sub.image ? NodeType.REPO_IMAGE : NodeType.REPO_GIT; @@ -57,7 +56,7 @@ export const getConnectors = (g: graphlib.Graph) => { const cy = (y1 + y2) / 2 - LINE_THICKNESS / 2; const angle = Math.atan2(y1 - y2, x1 - x2) * (180 / Math.PI); - lines.push({ x: cx, y: cy, width, angle, color: edge['color'] }); + lines.push({ x: cx, y: cy, width, angle, color: edge['color'], from, to }); } const fromGr = forward[from] || {}; diff --git a/ui/src/features/project/pipelines/utils/use-pipeline-graph.ts b/ui/src/features/project/pipelines/utils/use-pipeline-graph.ts index 5bd87e381..3737ece41 100644 --- a/ui/src/features/project/pipelines/utils/use-pipeline-graph.ts +++ b/ui/src/features/project/pipelines/utils/use-pipeline-graph.ts @@ -2,7 +2,7 @@ import { graphlib, layout } from 'dagre'; import { useMemo } from 'react'; import { ColorMap, getColors } from '@ui/features/stage/utils'; -import { FreightRequest, Stage, Warehouse } from '@ui/gen/v1alpha1/generated_pb'; +import { Stage, Warehouse } from '@ui/gen/v1alpha1/generated_pb'; import { AnyNodeType, @@ -15,76 +15,45 @@ import { getNodeDimensions } from '../types'; -import { getConnectors, initNodeArray, newSubscriptionNode } from './graph'; +import { getConnectors, initNode, newSubscriptionNode } from './graph'; import { IndexCache } from './index-cache'; const initializeNodes = ( warehouses: Warehouse[], stages: Stage[], - hideSubscriptions: { [key: string]: boolean }, project?: string ): [AnyNodeType[], ColorMap] => { - const warehouseMap = {} as { [key: string]: Warehouse }; const warehouseNodeMap = {} as { [key: string]: RepoNodeType }; + const nodes = []; (warehouses || []).forEach((w: Warehouse) => { - warehouseMap[w?.metadata?.name || ''] = w; - warehouseNodeMap[w.metadata?.name || ''] = NewWarehouseNode(w); - }); - - const nodes = stages.slice().flatMap((stage) => { - const n = initNodeArray(stage); - - let requestedFreight = stage.spec?.requestedFreight; - const legacySubscription = stage.spec?.subscriptions?.warehouse; - if (!requestedFreight || (stage.spec?.requestedFreight?.length === 0 && legacySubscription)) { - requestedFreight = [ - { - origin: { - kind: 'Warehouse', - name: legacySubscription - }, - sources: { - direct: true - } - } - ] as FreightRequest[]; + const warehouseName = w?.metadata?.name; + if (warehouseName) { + w?.spec?.subscriptions?.forEach((sub) => { + nodes.push(newSubscriptionNode(sub, warehouseName)); + }); + warehouseNodeMap[warehouseName] = NewWarehouseNode(w); } + }); - (requestedFreight || []).forEach((f) => { + stages.forEach((stage) => { + (stage.spec?.requestedFreight || []).forEach((f) => { if (f?.origin?.kind === 'Warehouse' && f?.sources?.direct) { const warehouseName = f.origin?.name; - // create warehouse nodes if (warehouseName) { - const cur = warehouseMap[warehouseName]; - if (!warehouseNodeMap[warehouseName] && cur) { - // if warehouse node does not yet exist, create it and add this stage as its first child - warehouseNodeMap[warehouseName] = NewWarehouseNode(cur, [stage.metadata?.name || '']); - } else { - // the warehouse node already exists, so add this stage to its children - const stageNames = [ + // the warehouse node will already exist, unless a stage references a missing warehouse + warehouseNodeMap[warehouseName] = { + ...warehouseNodeMap[warehouseName], + stageNames: [ ...(warehouseNodeMap[warehouseName]?.stageNames || []), stage.metadata?.name || '' - ]; - warehouseNodeMap[warehouseName] = { - ...warehouseNodeMap[warehouseName], - stageNames - }; - } + ] + }; } } }); - return n; - }); - - warehouses.forEach((w) => { - // create subscription nodes - w?.spec?.subscriptions?.forEach((sub) => { - if (w.metadata?.name && !hideSubscriptions[w.metadata.name]) { - nodes.push(newSubscriptionNode(sub, w.metadata?.name || '')); - } - }); + nodes.push(initNode(stage)); }); const warehouseColorMap = getColors(project || '', warehouses, 'warehouses'); @@ -96,8 +65,7 @@ const initializeNodes = ( export const usePipelineGraph = ( project: string | undefined, stages: Stage[], - warehouses: Warehouse[], - hideSubscriptions: { [key: string]: boolean } + warehouses: Warehouse[] ): [DagreNode[], ConnectorsType[][], BoxType, Stage[], ColorMap, ColorMap] => { return useMemo(() => { if (!stages || !warehouses || !project) { @@ -108,12 +76,7 @@ export const usePipelineGraph = ( g.setGraph({ rankdir: 'LR' }); g.setDefaultEdgeLabel(() => ({})); - const [myNodes, warehouseColorMap] = initializeNodes( - warehouses, - stages, - hideSubscriptions, - project - ); + const [myNodes, warehouseColorMap] = initializeNodes(warehouses, stages, project); const parentIndexCache = new IndexCache((node, warehouseName) => { return node.type === NodeType.WAREHOUSE && node.warehouseName === warehouseName; }); @@ -145,15 +108,6 @@ export const usePipelineGraph = ( }); } }); - - (stage?.spec?.subscriptions?.upstreamStages || []).forEach((upstreamStage, i) => { - g.setEdge( - String(subscriberIndexCache.get(upstreamStage.name || '', myNodes)), - String(index), - {}, - String(`${upstreamStage.name || ''} ${curStageName} ${i}`) - ); - }); } else if (item.type === NodeType.WAREHOUSE) { // this is a warehouse node let i = 0; @@ -179,7 +133,7 @@ export const usePipelineGraph = ( { color: warehouseColorMap[item.warehouseName] }, - `${item.warehouseName} ${index}` + `subscription ${item.warehouseName} ${index}` ); } }); @@ -228,5 +182,5 @@ export const usePipelineGraph = ( }); return [nodes, connectors, box, sortedStages, stageColorMap, warehouseColorMap]; - }, [stages, warehouses, hideSubscriptions, project]); + }, [stages, warehouses, project]); };