From 71361cf5bd97838eae9f5e8a1b51d557107d06be Mon Sep 17 00:00:00 2001 From: Lasserich Date: Thu, 30 Oct 2025 10:53:28 +0100 Subject: [PATCH 1/7] feat: filter button + tinted nodes --- src/components/Graphs/Graph.module.css | 36 ++++++++++- src/components/Graphs/Graph.tsx | 86 ++++++++++++++++---------- src/components/Graphs/useGraph.ts | 14 +++-- 3 files changed, 95 insertions(+), 41 deletions(-) diff --git a/src/components/Graphs/Graph.module.css b/src/components/Graphs/Graph.module.css index 15887d86..5f75ad4b 100644 --- a/src/components/Graphs/Graph.module.css +++ b/src/components/Graphs/Graph.module.css @@ -3,12 +3,39 @@ height: 600px; overflow: hidden; font-family: var(--sapFontFamily); + position: relative; } .graphColumn { flex: 1; display: flex; flex-direction: column; + background-color: #ffffff; +} + +.topLegendContainer { + position: absolute; + top: 1rem; + right: 1rem; + display: flex; + align-items: center; + z-index: 2; +} + +.filterIcon { + display: flex; + align-items: center; + cursor: pointer; + padding: 4px; + border-radius: 8px; + transition: background-color 0.2s ease; + background-color: rgba(255, 255, 255, 0.9); + box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1); + margin-left: 0.5rem; +} + +.filterIcon:hover { + background-color: var(--sapButton_Hover_Background, #f0f0f0); } .graphHeader { @@ -45,7 +72,6 @@ color: var(--sapTextColor, #222); } -/* Remove the default fieldset frame when used for grouping only */ .fieldsetReset { border: 0; margin: 0; @@ -53,7 +79,13 @@ min-inline-size: 0; } -/* React Flow Controls dark mode */ +.popoverButtonContainer { + display: flex; + flex-direction: column; + gap: 0.5rem; + padding: 0.5rem; +} + :global([data-theme='dark'] .react-flow__controls) { background-color: rgba(28, 28, 28, 0.9); border: 1px solid rgba(255, 255, 255, 0.15); diff --git a/src/components/Graphs/Graph.tsx b/src/components/Graphs/Graph.tsx index 3d215da4..84b3ab7d 100644 --- a/src/components/Graphs/Graph.tsx +++ b/src/components/Graphs/Graph.tsx @@ -1,7 +1,7 @@ import React, { useState, useCallback, useMemo } from 'react'; -import { ReactFlow, Background, Controls, MarkerType, Node, Panel } from '@xyflow/react'; +import { ReactFlow, Background, Controls, MarkerType, Node } from '@xyflow/react'; +import { Button, Popover } from '@ui5/webcomponents-react'; import type { NodeProps } from '@xyflow/react'; -import { RadioButton, FlexBox, FlexBoxAlignItems } from '@ui5/webcomponents-react'; import styles from './Graph.module.css'; import '@xyflow/react/dist/style.css'; import { NodeData, ColorBy } from './types'; @@ -32,7 +32,8 @@ const Graph: React.FC = () => { const { t } = useTranslation(); const { openInAside } = useSplitter(); const { isDarkTheme } = useTheme(); - const [colorBy, setColorBy] = useState('provider'); + const [colorBy, setColorBy] = useState('source'); + const [filterPopoverOpen, setFilterPopoverOpen] = useState(false); const handleYamlClick = useCallback( (item: ManagedResourceItem) => { @@ -92,37 +93,56 @@ const Graph: React.FC = () => { > - - -
-
- {t('Graphs.colorizedTitle')} - setColorBy('provider')} - /> - setColorBy('source')} - /> - setColorBy('flux')} - /> -
-
-
-
- - - + +
+ + setFilterPopoverOpen(false)} + placement="Top" + > +
+ + + +
+
+
+
+
); diff --git a/src/components/Graphs/useGraph.ts b/src/components/Graphs/useGraph.ts index d8c53531..e452fb99 100644 --- a/src/components/Graphs/useGraph.ts +++ b/src/components/Graphs/useGraph.ts @@ -24,14 +24,17 @@ function buildGraph( treeData.forEach((n) => { const colorKey: string = colorBy === 'source' ? n.providerType : colorBy === 'flux' ? (n.fluxName ?? 'default') : n.providerConfigName; - const node: Node = { + const borderColor = colorMap[colorKey] || '#ccc'; + const backgroundColor = `${borderColor}08`; + + const node: Node = { id: n.id, type: 'custom', data: { ...n }, style: { - border: `2px solid ${colorMap[colorKey] || '#ccc'}`, + border: `2px solid ${borderColor}`, borderRadius: 8, - backgroundColor: 'var(--sapTile_Background, #fff)', + backgroundColor, width: nodeWidth, height: nodeHeight, }, @@ -53,8 +56,7 @@ function buildGraph( id: `e-${n.parentId}-${n.id}`, source: n.parentId, target: n.id, - markerEnd: { type: MarkerType.ArrowClosed }, - }); + style: { strokeWidth: 2, stroke: '#888' }, }); } n.extraRefs?.forEach((refId) => { if (nodeMap.has(refId)) { @@ -63,7 +65,7 @@ function buildGraph( id: `e-${refId}-${n.id}`, source: refId, target: n.id, - markerEnd: { type: MarkerType.ArrowClosed }, + style: { strokeWidth: 2, stroke: '#888' }, }); } }); From 62a9f30f807636faba26585287dae7b0e435afac Mon Sep 17 00:00:00 2001 From: Lasserich Date: Thu, 30 Oct 2025 11:10:54 +0100 Subject: [PATCH 2/7] fix: linting --- src/components/Graphs/Graph.tsx | 4 ++-- src/components/Graphs/useGraph.ts | 11 ++++++----- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/src/components/Graphs/Graph.tsx b/src/components/Graphs/Graph.tsx index 84b3ab7d..150deaeb 100644 --- a/src/components/Graphs/Graph.tsx +++ b/src/components/Graphs/Graph.tsx @@ -96,12 +96,12 @@ const Graph: React.FC = () => {
- + setFilterPopoverOpen(false)} placement="Top" + onClose={() => setFilterPopoverOpen(false)} >
- - -
-
-
-
-
+ + ); diff --git a/src/components/Graphs/Legend.module.css b/src/components/Graphs/Legend.module.css index bcc02f5b..a4236e15 100644 --- a/src/components/Graphs/Legend.module.css +++ b/src/components/Graphs/Legend.module.css @@ -1,22 +1,36 @@ +.legendWrapper { + display: flex; + align-items: flex-start; + gap: 1rem; +} + .legendContainer { padding: 1rem; - min-width: 220px; - max-width: 300px; - max-height: 280px; + min-width: 150px; + max-width: 250px; + max-height: 120px; border: 1px solid var(--sapList_BorderColor, #ccc); border-radius: 8px; background-color: var(--sapTile_Background, #fff); - margin: 1rem; box-shadow: 0 2px 6px rgba(0, 0, 0, 0.15); - overflow: auto; - align-self: flex-start; + overflow-y: auto; color: var(--sapTextColor, #222); font-size: var(--sapFontSize); } -.legendTitle { - margin-bottom: 10px; - color: var(--sapTitleColor, var(--sapTextColor, #222)); +.colorFilterContainer { + padding: 1rem; + border: 1px solid var(--sapList_BorderColor, #ccc); + border-radius: 8px; + background-color: var(--sapTile_Background, #fff); + box-shadow: 0 2px 6px rgba(0, 0, 0, 0.15); + color: var(--sapTextColor, #222); + font-size: var(--sapFontSize); + display: flex; + justify-content: center; + align-items: center; + height: 16px; + width: 16px; } .legendRow { @@ -30,9 +44,29 @@ } .legendColorBox { - width: 16px; - height: 16px; + width: 14px; + height: 14px; margin-right: 8px; border-radius: 3px; border: 1px solid var(--sapList_BorderColor, #999); +} + +.popoverContent { + padding: 0.5rem; + min-width: 150px; +} + +.popoverHeader { + margin: 0 0 0.5rem 0; + padding: 0 0 0.5rem 0; + border-bottom: 1px solid var(--sapList_BorderColor, #e0e0e0); + font-size: var(--sapFontSize, 14px); + font-weight: 600; + color: var(--sapTextColor, #222); +} + +.popoverButtonContainer { + display: flex; + flex-direction: column; + gap: 0.25rem; } \ No newline at end of file diff --git a/src/components/Graphs/Legend.tsx b/src/components/Graphs/Legend.tsx index 8c4f5cc1..d4393521 100644 --- a/src/components/Graphs/Legend.tsx +++ b/src/components/Graphs/Legend.tsx @@ -1,5 +1,9 @@ -import React from 'react'; +import React, { useId, useState } from 'react'; +import { Button, Popover } from '@ui5/webcomponents-react'; +import { useTranslation } from 'react-i18next'; +import { ColorBy } from './types'; import styles from './Legend.module.css'; + export interface LegendItem { name: string; color: string; @@ -7,17 +11,73 @@ export interface LegendItem { interface LegendProps { legendItems: LegendItem[]; + colorBy: ColorBy; + onColorByChange: (colorBy: ColorBy) => void; } -export const Legend: React.FC = ({ legendItems }) => { +export const Legend: React.FC = ({ legendItems, colorBy, onColorByChange }) => { + const { t } = useTranslation(); + const [colorPopoverOpen, setColorPopoverOpen] = useState(false); + const colorButtonId = useId(); + return ( -
- {legendItems.map(({ name, color }) => ( -
-
- {name} -
- ))} +
+
+ {legendItems.map(({ name, color }) => ( +
+
+ {name} +
+ ))} +
+
+ setColorPopoverOpen(false)} + > +
+

{t('Graphs.colorBy')}

+
+ + + +
+
+
+
); }; From 2338bd9292c47cb57d81a72ac808d0fa756a5a8c Mon Sep 17 00:00:00 2001 From: Lasserich Date: Wed, 12 Nov 2025 18:05:45 +0100 Subject: [PATCH 6/7] fix: linting --- src/components/Graphs/Graph.tsx | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/components/Graphs/Graph.tsx b/src/components/Graphs/Graph.tsx index 8d2f37b9..57add1eb 100644 --- a/src/components/Graphs/Graph.tsx +++ b/src/components/Graphs/Graph.tsx @@ -93,11 +93,7 @@ const Graph: React.FC = () => { - +
From dc863bcd2690edcb6efb315fd097c9070d38b7e6 Mon Sep 17 00:00:00 2001 From: Lasserich Date: Mon, 17 Nov 2025 12:36:45 +0100 Subject: [PATCH 7/7] fix: review changes --- public/locales/en.json | 1 - src/components/Graphs/Graph.module.css | 1 - 2 files changed, 2 deletions(-) diff --git a/public/locales/en.json b/public/locales/en.json index 2bf8988e..f6fd2513 100644 --- a/public/locales/en.json +++ b/public/locales/en.json @@ -351,7 +351,6 @@ "Graphs": { "colorsProvider": "Provider", "colorsProviderConfig": "Provider Config", - "colorizedTitle": "Group by", "colorBy": "Color by", "colorsFlux": "Flux", "loadingError": "Error loading graph data", diff --git a/src/components/Graphs/Graph.module.css b/src/components/Graphs/Graph.module.css index f2905026..7da8ba0e 100644 --- a/src/components/Graphs/Graph.module.css +++ b/src/components/Graphs/Graph.module.css @@ -3,7 +3,6 @@ height: 600px; padding: 2px; font-family: var(--sapFontFamily); - position: relative; } .graphColumn {