Skip to content

Commit 8316610

Browse files
authored
feat: filter button for graph view (#354)
1 parent e95cce8 commit 8316610

File tree

6 files changed

+132
-84
lines changed

6 files changed

+132
-84
lines changed

public/locales/en.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -351,7 +351,7 @@
351351
"Graphs": {
352352
"colorsProvider": "Provider",
353353
"colorsProviderConfig": "Provider Config",
354-
"colorizedTitle": "Group by: ",
354+
"colorBy": "Color by",
355355
"colorsFlux": "Flux",
356356
"loadingError": "Error loading graph data",
357357
"loadingGraph": "Loading graph data...",

src/components/Graphs/Graph.module.css

Lines changed: 4 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,30 +1,21 @@
11
.graphContainer {
22
display: flex;
33
height: 600px;
4-
overflow: hidden;
4+
padding: 2px;
55
font-family: var(--sapFontFamily);
66
}
77

88
.graphColumn {
99
flex: 1;
1010
display: flex;
1111
flex-direction: column;
12+
background-color: var(--sapTile_Background, #fff);
1213
}
1314

14-
.graphHeader {
15-
padding: 0.5rem;
15+
.panelContent {
1616
display: flex;
17+
align-items: flex-start;
1718
gap: 1rem;
18-
align-items: center;
19-
color: var(--sapTextColor, #222);
20-
font-size: var(--sapFontSize);
21-
}
22-
23-
.graphToolbar {
24-
padding: 0.5rem;
25-
display: flex;
26-
gap: 1rem;
27-
align-items: center;
2819
}
2920

3021
.message {
@@ -40,20 +31,6 @@
4031
color: #c00;
4132
}
4233

43-
.colorizedTitle {
44-
font-weight: 500;
45-
color: var(--sapTextColor, #222);
46-
}
47-
48-
/* Remove the default fieldset frame when used for grouping only */
49-
.fieldsetReset {
50-
border: 0;
51-
margin: 0;
52-
padding: 0;
53-
min-inline-size: 0;
54-
}
55-
56-
/* React Flow Controls dark mode */
5734
:global([data-theme='dark'] .react-flow__controls) {
5835
background-color: rgba(28, 28, 28, 0.9);
5936
border: 1px solid rgba(255, 255, 255, 0.15);

src/components/Graphs/Graph.tsx

Lines changed: 4 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import React, { useState, useCallback, useMemo } from 'react';
22
import { ReactFlow, Background, Controls, MarkerType, Node, Panel } from '@xyflow/react';
3+
34
import type { NodeProps } from '@xyflow/react';
4-
import { RadioButton, FlexBox, FlexBoxAlignItems } from '@ui5/webcomponents-react';
55
import styles from './Graph.module.css';
66
import '@xyflow/react/dist/style.css';
77
import { NodeData, ColorBy } from './types';
@@ -32,7 +32,7 @@ const Graph: React.FC = () => {
3232
const { t } = useTranslation();
3333
const { openInAside } = useSplitter();
3434
const { isDarkTheme } = useTheme();
35-
const [colorBy, setColorBy] = useState<ColorBy>('provider');
35+
const [colorBy, setColorBy] = useState<ColorBy>('source');
3636

3737
const handleYamlClick = useCallback(
3838
(item: ManagedResourceItem) => {
@@ -92,35 +92,8 @@ const Graph: React.FC = () => {
9292
>
9393
<Controls showInteractive={false} />
9494
<Background />
95-
<Panel position="top-left">
96-
<FlexBox alignItems={FlexBoxAlignItems.Center} role="radiogroup">
97-
<fieldset className={styles.fieldsetReset}>
98-
<div className={styles.graphHeader}>
99-
<span className={styles.colorizedTitle}>{t('Graphs.colorizedTitle')}</span>
100-
<RadioButton
101-
name="colorBy"
102-
text={t('Graphs.colorsProviderConfig')}
103-
checked={colorBy === 'provider'}
104-
onChange={() => setColorBy('provider')}
105-
/>
106-
<RadioButton
107-
name="colorBy"
108-
text={t('Graphs.colorsProvider')}
109-
checked={colorBy === 'source'}
110-
onChange={() => setColorBy('source')}
111-
/>
112-
<RadioButton
113-
name="colorBy"
114-
text={t('Graphs.colorsFlux')}
115-
checked={colorBy === 'flux'}
116-
onChange={() => setColorBy('flux')}
117-
/>
118-
</div>
119-
</fieldset>
120-
</FlexBox>
121-
</Panel>
122-
<Panel position="top-right">
123-
<Legend legendItems={legendItems} />
95+
<Panel position="top-right" className={styles.panelContent}>
96+
<Legend legendItems={legendItems} colorBy={colorBy} onColorByChange={setColorBy} />
12497
</Panel>
12598
</ReactFlow>
12699
</div>
Lines changed: 45 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,36 @@
1+
.legendWrapper {
2+
display: flex;
3+
align-items: flex-start;
4+
gap: 1rem;
5+
}
6+
17
.legendContainer {
28
padding: 1rem;
3-
min-width: 220px;
4-
max-width: 300px;
5-
max-height: 280px;
9+
min-width: 150px;
10+
max-width: 250px;
11+
max-height: 120px;
612
border: 1px solid var(--sapList_BorderColor, #ccc);
713
border-radius: 8px;
814
background-color: var(--sapTile_Background, #fff);
9-
margin: 1rem;
1015
box-shadow: 0 2px 6px rgba(0, 0, 0, 0.15);
11-
overflow: auto;
12-
align-self: flex-start;
16+
overflow-y: auto;
1317
color: var(--sapTextColor, #222);
1418
font-size: var(--sapFontSize);
1519
}
1620

17-
.legendTitle {
18-
margin-bottom: 10px;
19-
color: var(--sapTitleColor, var(--sapTextColor, #222));
21+
.colorFilterContainer {
22+
padding: 1rem;
23+
border: 1px solid var(--sapList_BorderColor, #ccc);
24+
border-radius: 8px;
25+
background-color: var(--sapTile_Background, #fff);
26+
box-shadow: 0 2px 6px rgba(0, 0, 0, 0.15);
27+
color: var(--sapTextColor, #222);
28+
font-size: var(--sapFontSize);
29+
display: flex;
30+
justify-content: center;
31+
align-items: center;
32+
height: 16px;
33+
width: 16px;
2034
}
2135

2236
.legendRow {
@@ -30,9 +44,29 @@
3044
}
3145

3246
.legendColorBox {
33-
width: 16px;
34-
height: 16px;
47+
width: 14px;
48+
height: 14px;
3549
margin-right: 8px;
3650
border-radius: 3px;
3751
border: 1px solid var(--sapList_BorderColor, #999);
52+
}
53+
54+
.popoverContent {
55+
padding: 0.5rem;
56+
min-width: 150px;
57+
}
58+
59+
.popoverHeader {
60+
margin: 0 0 0.5rem 0;
61+
padding: 0 0 0.5rem 0;
62+
border-bottom: 1px solid var(--sapList_BorderColor, #e0e0e0);
63+
font-size: var(--sapFontSize, 14px);
64+
font-weight: 600;
65+
color: var(--sapTextColor, #222);
66+
}
67+
68+
.popoverButtonContainer {
69+
display: flex;
70+
flex-direction: column;
71+
gap: 0.25rem;
3872
}

src/components/Graphs/Legend.tsx

Lines changed: 69 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,83 @@
1-
import React from 'react';
1+
import React, { useId, useState } from 'react';
2+
import { Button, Popover } from '@ui5/webcomponents-react';
3+
import { useTranslation } from 'react-i18next';
4+
import { ColorBy } from './types';
25
import styles from './Legend.module.css';
6+
37
export interface LegendItem {
48
name: string;
59
color: string;
610
}
711

812
interface LegendProps {
913
legendItems: LegendItem[];
14+
colorBy: ColorBy;
15+
onColorByChange: (colorBy: ColorBy) => void;
1016
}
1117

12-
export const Legend: React.FC<LegendProps> = ({ legendItems }) => {
18+
export const Legend: React.FC<LegendProps> = ({ legendItems, colorBy, onColorByChange }) => {
19+
const { t } = useTranslation();
20+
const [colorPopoverOpen, setColorPopoverOpen] = useState(false);
21+
const colorButtonId = useId();
22+
1323
return (
14-
<div className={styles.legendContainer}>
15-
{legendItems.map(({ name, color }) => (
16-
<div key={name} className={styles.legendRow}>
17-
<div className={styles.legendColorBox} style={{ backgroundColor: color }} />
18-
<span>{name}</span>
19-
</div>
20-
))}
24+
<div className={styles.legendWrapper}>
25+
<div className={styles.legendContainer}>
26+
{legendItems.map(({ name, color }) => (
27+
<div key={name} className={styles.legendRow}>
28+
<div className={styles.legendColorBox} style={{ backgroundColor: color }} />
29+
<span>{name}</span>
30+
</div>
31+
))}
32+
</div>
33+
<div className={styles.colorFilterContainer}>
34+
<Popover
35+
opener={colorButtonId}
36+
open={colorPopoverOpen}
37+
placement="Bottom"
38+
onClose={() => setColorPopoverOpen(false)}
39+
>
40+
<div className={styles.popoverContent}>
41+
<h4 className={styles.popoverHeader}>{t('Graphs.colorBy')}</h4>
42+
<div className={styles.popoverButtonContainer}>
43+
<Button
44+
design={colorBy === 'source' ? 'Emphasized' : 'Default'}
45+
onClick={() => {
46+
onColorByChange('source');
47+
setColorPopoverOpen(false);
48+
}}
49+
>
50+
{t('Graphs.colorsProvider')}
51+
</Button>
52+
<Button
53+
design={colorBy === 'provider' ? 'Emphasized' : 'Default'}
54+
onClick={() => {
55+
onColorByChange('provider');
56+
setColorPopoverOpen(false);
57+
}}
58+
>
59+
{t('Graphs.colorsProviderConfig')}
60+
</Button>
61+
<Button
62+
design={colorBy === 'flux' ? 'Emphasized' : 'Default'}
63+
onClick={() => {
64+
onColorByChange('flux');
65+
setColorPopoverOpen(false);
66+
}}
67+
>
68+
{t('Graphs.colorsFlux')}
69+
</Button>
70+
</div>
71+
</div>
72+
</Popover>
73+
<Button
74+
id={colorButtonId}
75+
design="Transparent"
76+
icon="palette"
77+
tooltip={t('Graphs.colorBy')}
78+
onClick={() => setColorPopoverOpen(!colorPopoverOpen)}
79+
/>
80+
</div>
2181
</div>
2282
);
2383
};

src/components/Graphs/useGraph.ts

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import { useMemo, useEffect, useState } from 'react';
22
import { useApiResource, useProvidersConfigResource } from '../../lib/api/useApiResource';
33
import { ManagedResourcesRequest } from '../../lib/api/types/crossplane/listManagedResources';
44
import { resourcesInterval } from '../../lib/shared/constants';
5-
import { Node, Edge, Position, MarkerType } from '@xyflow/react';
5+
import { Node, Edge, Position } from '@xyflow/react';
66
import dagre from 'dagre';
77
import { NodeData, ColorBy } from './types';
88
import { buildTreeData, generateColorMap } from './graphUtils';
@@ -24,14 +24,18 @@ function buildGraph(
2424
treeData.forEach((n) => {
2525
const colorKey: string =
2626
colorBy === 'source' ? n.providerType : colorBy === 'flux' ? (n.fluxName ?? 'default') : n.providerConfigName;
27+
const borderColor = colorMap[colorKey] || '#ccc';
28+
//some opacity for background
29+
const backgroundColor = `${borderColor}08`;
30+
2731
const node: Node<NodeData> = {
2832
id: n.id,
2933
type: 'custom',
3034
data: { ...n },
3135
style: {
32-
border: `2px solid ${colorMap[colorKey] || '#ccc'}`,
36+
border: `2px solid ${borderColor}`,
3337
borderRadius: 8,
34-
backgroundColor: 'var(--sapTile_Background, #fff)',
38+
backgroundColor,
3539
width: nodeWidth,
3640
height: nodeHeight,
3741
},
@@ -53,7 +57,7 @@ function buildGraph(
5357
id: `e-${n.parentId}-${n.id}`,
5458
source: n.parentId,
5559
target: n.id,
56-
markerEnd: { type: MarkerType.ArrowClosed },
60+
style: { strokeWidth: 2, stroke: '#888' },
5761
});
5862
}
5963
n.extraRefs?.forEach((refId) => {
@@ -63,7 +67,7 @@ function buildGraph(
6367
id: `e-${refId}-${n.id}`,
6468
source: refId,
6569
target: n.id,
66-
markerEnd: { type: MarkerType.ArrowClosed },
70+
style: { strokeWidth: 2, stroke: '#888' },
6771
});
6872
}
6973
});

0 commit comments

Comments
 (0)