Skip to content

Commit fbcbb81

Browse files
committed
Use sigma as the graph library
1 parent 087cac9 commit fbcbb81

18 files changed

+727
-771
lines changed

package.json

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
"eslint-config-prettier": "^10.0.1",
3232
"eslint-plugin-svelte": "^2.46.1",
3333
"globals": "^15.14.0",
34+
"graphology-types": "^0.24.8",
3435
"jsdom": "^25.0.1",
3536
"prettier": "^3.4.2",
3637
"prettier-plugin-svelte": "^3.3.3",
@@ -49,13 +50,18 @@
4950
},
5051
"packageManager": "[email protected]+sha512.e5a7e52a4183a02d5931057f7a0dbff9d5e9ce3161e33fa68ae392125b79282a8a8a470a51dfc8a0ed86221442eb2fb57019b0990ed24fab519bf0e1bc5ccfc4",
5152
"dependencies": {
52-
"@carbon/charts-svelte": "^1.22.17",
5353
"@carbon/layout": "^11.29.0",
5454
"@carbon/styles": "^1.75.0",
55+
"@carbon/themes": "^11.46.0",
5556
"@carbon/type": "^11.35.0",
5657
"@cyclonedx/cyclonedx-library": "^7.1.0",
58+
"@dagrejs/dagre": "^1.1.4",
5759
"@ibm/plex": "^6.4.1",
5860
"carbon-components-svelte": "^0.87.5",
59-
"carbon-icons-svelte": "^13.2.0"
61+
"carbon-icons-svelte": "^13.2.0",
62+
"graphology": "^0.26.0",
63+
"graphology-shortest-path": "^2.1.0",
64+
"graphology-simple-path": "^0.2.0",
65+
"sigma": "^3.0.1"
6066
}
6167
}

pnpm-lock.yaml

Lines changed: 137 additions & 687 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/lib/components/Bom.svelte

Lines changed: 36 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -6,25 +6,39 @@
66
import ComponentsTreeChart from '$lib/components/ComponentsTreeChart.svelte';
77
import ComponentModal from '$lib/components/ComponentModal.svelte';
88
import { Document } from 'carbon-icons-svelte';
9-
import { createTreeDataFromBom } from '$lib/tree';
10-
import type { TreeItem } from '$lib/models/tree';
119
1210
let { bom = null }: { bom: Bom | null } = $props();
1311
1412
let selectedComponentForModal: Component | undefined = $state();
1513
let selectedComponentRefInTreeView: string | undefined = $state();
14+
let selectedComponentRefInTreeGraph: string | undefined = $state();
15+
let searchValueInTable: string = $state('');
1616
1717
function searchComponentInTreeView(id: string) {
1818
selectedComponentRefInTreeView = id;
1919
}
2020
21+
function searchComponentInTreeGraph(id: string) {
22+
selectedTabIndex = 1; // Switch to graph tab
23+
selectedComponentRefInTreeGraph = id;
24+
}
25+
2126
function showComponentModal(component?: Component) {
2227
selectedComponentForModal = component;
2328
}
2429
25-
let treeData: TreeItem[] | undefined = $derived.by(() => {
26-
if (bom) {
27-
return createTreeDataFromBom(bom);
30+
function searchForComponentInTable(ref: string) {
31+
selectedTabIndex = 0; // Switch to table tab
32+
searchValueInTable = ref;
33+
}
34+
35+
let selectedTabIndex: number = $state(0); // for lazy-loading the chart
36+
37+
let showGraph: boolean = $state(false);
38+
39+
$effect.pre(() => {
40+
if (selectedTabIndex === 1) {
41+
showGraph = true;
2842
}
2943
});
3044
</script>
@@ -50,33 +64,34 @@
5064
{/if}
5165
{#if bom.components}
5266
<section class="tabs">
53-
<Tabs type="default">
67+
<Tabs type="default" bind:selected={selectedTabIndex}>
5468
<Tab label="Table" />
5569
<Tab label="Chart" />
5670
<svelte:fragment slot="content">
5771
<TabContent>
58-
{#if treeData}
59-
<div class="tab__tile">
60-
<ComponentsTreeView
61-
nodes={treeData}
62-
selectedComponentRef={selectedComponentRefInTreeView}
63-
/>
64-
</div>
65-
{/if}
72+
<div class="tab__tile">
73+
<ComponentsTreeView {bom} selectedComponentRef={selectedComponentRefInTreeView} />
74+
</div>
6675
<div class="tab__tile">
6776
<ComponentsTable
6877
components={bom.components}
69-
searchComponent={searchComponentInTreeView}
78+
{searchComponentInTreeView}
79+
{searchComponentInTreeGraph}
7080
showComponentDetails={showComponentModal}
81+
searchValue={searchValueInTable}
7182
/>
7283
</div>
7384
</TabContent>
7485
<TabContent>
75-
{#if treeData}
76-
<div class="tab__tile">
77-
<ComponentsTreeChart {bom} nodes={treeData} />
78-
</div>
79-
{/if}
86+
<div class="tab__tile">
87+
{#if showGraph}
88+
<ComponentsTreeChart
89+
{bom}
90+
selectedComponentRef={selectedComponentRefInTreeGraph}
91+
searchForComponent={searchForComponentInTable}
92+
/>
93+
{/if}
94+
</div>
8095
</TabContent>
8196
</svelte:fragment>
8297
</Tabs>
@@ -110,7 +125,7 @@
110125
}
111126
112127
.tab__tile {
113-
background-color: theme.$layer-01;
128+
background-color: theme.$layer;
114129
padding: layout.$spacing-05;
115130
}
116131

src/lib/components/ComponentsTable.svelte

Lines changed: 36 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -9,16 +9,20 @@
99
} from 'carbon-components-svelte';
1010
import type { DataTableRow } from 'carbon-components-svelte/src/DataTable/DataTable.svelte';
1111
import type { Component } from '$lib/cyclonedx/models';
12-
import { Document, Search } from 'carbon-icons-svelte';
12+
import { DecisionTree, Document, TreeView } from 'carbon-icons-svelte';
1313
1414
let {
1515
components,
16-
searchComponent,
17-
showComponentDetails
16+
searchComponentInTreeView,
17+
searchComponentInTreeGraph,
18+
showComponentDetails,
19+
searchValue = ''
1820
}: {
1921
components: Component[];
20-
searchComponent: (id: string) => void;
22+
searchComponentInTreeView: (id: string) => void;
23+
searchComponentInTreeGraph: (id: string) => void;
2124
showComponentDetails: (component: Component) => void;
25+
searchValue: string;
2226
} = $props();
2327
2428
let rows: DataTableRow[] = $derived.by(() => {
@@ -65,25 +69,34 @@
6569
>
6670
<Toolbar>
6771
<ToolbarContent>
68-
<ToolbarSearch persistent shouldFilterRows />
72+
<ToolbarSearch persistent shouldFilterRows value={searchValue} />
6973
</ToolbarContent>
7074
</Toolbar>
7175
<svelte:fragment slot="cell" let:row let:cell>
7276
{#if cell.key === 'actions'}
73-
<Button
74-
size="small"
75-
icon={Search}
76-
iconDescription="Show component in dependency tree"
77-
kind="ghost"
78-
on:click={() => searchComponent(row.id)}
79-
/>
80-
<Button
81-
size="small"
82-
icon={Document}
83-
iconDescription="Show details"
84-
kind="ghost"
85-
on:click={() => showComponentDetailsForRow(row)}
86-
/>
77+
<div class="actions">
78+
<Button
79+
size="small"
80+
icon={TreeView}
81+
iconDescription="Show component in dependency tree view"
82+
kind="ghost"
83+
on:click={() => searchComponentInTreeView(row.id)}
84+
/>
85+
<Button
86+
size="small"
87+
icon={DecisionTree}
88+
iconDescription="Show component in dependency tree graph"
89+
kind="ghost"
90+
on:click={() => searchComponentInTreeGraph(row.id)}
91+
/>
92+
<Button
93+
size="small"
94+
icon={Document}
95+
iconDescription="Show details"
96+
kind="ghost"
97+
on:click={() => showComponentDetailsForRow(row)}
98+
/>
99+
</div>
87100
{:else}{cell.value}{/if}
88101
</svelte:fragment>
89102
</DataTable>
@@ -100,4 +113,8 @@
100113
p {
101114
margin-bottom: layout.$spacing-04;
102115
}
116+
117+
.actions {
118+
white-space: nowrap;
119+
}
103120
</style>

0 commit comments

Comments
 (0)