@eqtylab/explorer 0.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (140) hide show
  1. package/.env.api +6 -0
  2. package/.env.iframe +2 -0
  3. package/.env.manifest +2 -0
  4. package/.envrc +1 -0
  5. package/.eslintrc.cjs +17 -0
  6. package/.github/workflows/ci.yml +46 -0
  7. package/.github/workflows/publish.yml +44 -0
  8. package/.husky/pre-push +2 -0
  9. package/.prettierignore +2 -0
  10. package/.prettierrc.json +13 -0
  11. package/LICENSE +201 -0
  12. package/README.md +84 -0
  13. package/flake.lock +61 -0
  14. package/flake.nix +23 -0
  15. package/index.html +13 -0
  16. package/package.json +93 -0
  17. package/postcss.config.js +5 -0
  18. package/public/logos/eci.svg +23 -0
  19. package/public/logos/eqty.svg +3 -0
  20. package/public/manifests/B-200-merged.json +773 -0
  21. package/public/manifests/amd-sev.json +426 -0
  22. package/public/manifests/anchors.json +609 -0
  23. package/public/manifests/association-no-metadata.json +1393 -0
  24. package/public/manifests/association.json +1402 -0
  25. package/public/manifests/eqty-docker.json +562 -0
  26. package/public/manifests/governance.json +1324 -0
  27. package/public/manifests/intel-tdx-with-nvidia.json +441 -0
  28. package/public/manifests/intel-tdx.json +404 -0
  29. package/public/manifests/iroh-collections.json +1285 -0
  30. package/public/manifests/model-signing.json +1536 -0
  31. package/public/manifests/multiple-registrations.json +129 -0
  32. package/public/manifests/no-vcs.json +114 -0
  33. package/public/manifests/storage.json +294 -0
  34. package/public/manifests/sub-graphs.json +1 -0
  35. package/src/animations/variants.ts +52 -0
  36. package/src/app/apiClient/integrityService/fetchAttributes.ts +29 -0
  37. package/src/app/apiClient/integrityService/fetchManifest.ts +28 -0
  38. package/src/app/apiClient/integrityService/types.ts +12 -0
  39. package/src/app/components/integrityService/IntegrityService.tsx +105 -0
  40. package/src/app/components/integrityService/components/AuthButton.tsx +26 -0
  41. package/src/app/components/integrityService/components/FiltersModal.tsx +214 -0
  42. package/src/app/components/integrityService/components/FiltersToggle.tsx +28 -0
  43. package/src/app/components/manifestViewer/ManifestViewer.tsx +90 -0
  44. package/src/app/components/manifestViewer/components/ManifestButtons.tsx +215 -0
  45. package/src/app/config.json +23 -0
  46. package/src/app/config.ts +28 -0
  47. package/src/app/pages/index.tsx +34 -0
  48. package/src/app/stores/manifestStore.ts +19 -0
  49. package/src/app/utils/appMode.ts +37 -0
  50. package/src/assets/fonts/TWKLausanne-300.woff +0 -0
  51. package/src/assets/fonts/TWKLausanne-300.woff2 +0 -0
  52. package/src/assets/fonts/TWKLausanne-400.woff +0 -0
  53. package/src/assets/fonts/TWKLausanne-400.woff2 +0 -0
  54. package/src/assets/fonts/TWKLausanne-500.woff +0 -0
  55. package/src/assets/fonts/TWKLausanne-500.woff2 +0 -0
  56. package/src/assets/fonts/TWKLausanne-600.woff +0 -0
  57. package/src/assets/fonts/TWKLausanne-600.woff2 +0 -0
  58. package/src/assets/vectors/eqtylab.svg +6 -0
  59. package/src/components/app-header.tsx +61 -0
  60. package/src/components/dark-mode-switch.tsx +16 -0
  61. package/src/components/ui/accordion.tsx +47 -0
  62. package/src/components/ui/certificate-chain.tsx +60 -0
  63. package/src/components/ui/certificate-code.tsx +39 -0
  64. package/src/components/ui/details.tsx +20 -0
  65. package/src/components/ui/display-code.tsx +47 -0
  66. package/src/components/ui/panel-label.tsx +12 -0
  67. package/src/components/ui/verify-state-badge.tsx +32 -0
  68. package/src/explorer-component/LineageExplorer.tsx +89 -0
  69. package/src/explorer-component/components/CustomEdge.tsx +28 -0
  70. package/src/explorer-component/components/LineageFlow.tsx +220 -0
  71. package/src/explorer-component/components/NodeIconLoader.tsx +26 -0
  72. package/src/explorer-component/components/nodes/ComputationNode.tsx +56 -0
  73. package/src/explorer-component/components/nodes/CustomNode.tsx +112 -0
  74. package/src/explorer-component/components/nodes/index.ts +4 -0
  75. package/src/explorer-component/components/nodes/nodes.tsx +144 -0
  76. package/src/explorer-component/components/nodes/types.ts +167 -0
  77. package/src/explorer-component/components/sidebar/SectionList.tsx +54 -0
  78. package/src/explorer-component/components/sidebar/SectionTitle.tsx +10 -0
  79. package/src/explorer-component/components/sidebar/Sidebar.tsx +70 -0
  80. package/src/explorer-component/components/sidebar/SidebarWrapper.tsx +76 -0
  81. package/src/explorer-component/components/sidebar/sections/CustomSection.tsx +238 -0
  82. package/src/explorer-component/components/sidebar/sections/FileViewer.tsx +229 -0
  83. package/src/explorer-component/components/sidebar/sections/GovernanceSection.tsx +52 -0
  84. package/src/explorer-component/components/sidebar/sections/RegistrationSection.tsx +254 -0
  85. package/src/explorer-component/components/sidebar/sections/SigstoreSection.tsx +37 -0
  86. package/src/explorer-component/components/sidebar/sections/StorageSection.tsx +73 -0
  87. package/src/explorer-component/components/sidebar/sections/custom/IrohCollectionsView.tsx +139 -0
  88. package/src/explorer-component/components/sidebar/sections/registration/VerificationIcon.tsx +108 -0
  89. package/src/explorer-component/components/sidebar/sections/registration/actor/ActorBadge.tsx +62 -0
  90. package/src/explorer-component/components/sidebar/sections/registration/actor/svg/AMDLogo.tsx +40 -0
  91. package/src/explorer-component/components/sidebar/sections/registration/actor/svg/AzureLogo.tsx +65 -0
  92. package/src/explorer-component/components/sidebar/sections/registration/actor/svg/IntelLogo.tsx +24 -0
  93. package/src/explorer-component/components/sidebar/sections/registration/actor/svg/NvidiaLogo.tsx +27 -0
  94. package/src/explorer-component/components/sidebar/sections/registration/verifierClient.ts +13 -0
  95. package/src/explorer-component/icons/AttributionIcon.svg +6 -0
  96. package/src/explorer-component/icons/BenchmarkIcon.svg +6 -0
  97. package/src/explorer-component/icons/BenchmarkResultIcon.svg +6 -0
  98. package/src/explorer-component/icons/CertificateIcon.svg +6 -0
  99. package/src/explorer-component/icons/CodeIcon.svg +6 -0
  100. package/src/explorer-component/icons/ComputationIcon.svg +6 -0
  101. package/src/explorer-component/icons/DataIcon.svg +6 -0
  102. package/src/explorer-component/icons/DatabaseIcon.svg +6 -0
  103. package/src/explorer-component/icons/DatasetIcon.svg +6 -0
  104. package/src/explorer-component/icons/DeltaLakeIcon.svg +7 -0
  105. package/src/explorer-component/icons/DocumentIcon.svg +6 -0
  106. package/src/explorer-component/icons/MediaIcon.svg +6 -0
  107. package/src/explorer-component/icons/ModelIcon.svg +6 -0
  108. package/src/explorer-component/icons/TeamIcon.svg +3 -0
  109. package/src/explorer-component/icons/TokenIcon.svg +6 -0
  110. package/src/explorer-component/icons/UnknownIcon.svg +6 -0
  111. package/src/explorer-component/icons/index.ts +35 -0
  112. package/src/explorer-component/index.ts +5 -0
  113. package/src/explorer-component/integrityTypes/AnchorTypes.ts +31 -0
  114. package/src/explorer-component/integrityTypes/StatementTypes.ts +333 -0
  115. package/src/explorer-component/integrityTypes/VCTypes.ts +85 -0
  116. package/src/explorer-component/integrityTypes/types.ts +3 -0
  117. package/src/explorer-component/utils/config.ts +163 -0
  118. package/src/explorer-component/utils/formatTimestamp.ts +5 -0
  119. package/src/explorer-component/utils/generateGraph.ts +271 -0
  120. package/src/explorer-component/utils/layoutGraph.ts +148 -0
  121. package/src/explorer-component/utils/resolveIrohBlobs.ts +117 -0
  122. package/src/explorer-component/utils/statementHelpers.ts +252 -0
  123. package/src/explorer-component/utils/stripPrefix.ts +4 -0
  124. package/src/hooks/use-mobile.tsx +19 -0
  125. package/src/index.ts +3 -0
  126. package/src/lib/resource-types.ts +31 -0
  127. package/src/lib/use-escape-key.tsx +16 -0
  128. package/src/lib/utils.ts +19 -0
  129. package/src/main.css +82 -0
  130. package/src/main.tsx +39 -0
  131. package/src/v-comp-viewer/components/container-did-details.tsx +53 -0
  132. package/src/v-comp-viewer/components/system-did-details.tsx +356 -0
  133. package/src/v-comp-viewer/useVComp.ts +196 -0
  134. package/src/v-comp-viewer/utils.tsx +824 -0
  135. package/src/vite-env.d.ts +1 -0
  136. package/tsconfig.json +33 -0
  137. package/tsconfig.node.json +10 -0
  138. package/vercel.json +13 -0
  139. package/vite.app.config.ts +48 -0
  140. package/vite.lib.config.ts +61 -0
@@ -0,0 +1,144 @@
1
+ import {
2
+ Brain,
3
+ Database,
4
+ Cpu,
5
+ Wrench,
6
+ Shield,
7
+ FileText,
8
+ Table,
9
+ MessageSquareText,
10
+ MessageSquareCode,
11
+ MessageSquareMore,
12
+ MessageSquareQuote,
13
+ Coins,
14
+ Zap,
15
+ Bot,
16
+ Box,
17
+ LineChart,
18
+ Code,
19
+ Fence,
20
+ Settings2,
21
+ } from "lucide-react";
22
+
23
+ export const NODES_STYLES = {
24
+ default: {
25
+ backgroundColor: "bg-resource-unknown",
26
+ hoverBorderColor: "hover:border-resource-unknown hover:before:border-resource-unknown",
27
+ activeStyle: "border-resource-unknown",
28
+ icon: <Box className="size-5 text-white" />,
29
+ },
30
+ dataset: {
31
+ backgroundColor: "bg-resource-dataset",
32
+ hoverBorderColor: "hover:border-resource-dataset hover:before:border-resource-dataset",
33
+ activeStyle: "border-resource-dataset",
34
+ icon: <Table className="size-5 text-white" />,
35
+ },
36
+ model: {
37
+ backgroundColor: "bg-resource-model",
38
+ hoverBorderColor: "hover:border-resource-model hover:before:border-resource-model",
39
+ activeStyle: "border-resource-model",
40
+ icon: <Brain className="size-5 text-white" />,
41
+ },
42
+ code: {
43
+ backgroundColor: "bg-resource-code",
44
+ hoverBorderColor: "hover:border-resource-code hover:before:border-resource-code",
45
+ activeStyle: "border-resource-code",
46
+ icon: <Code className="size-5 text-white" />,
47
+ },
48
+ document: {
49
+ backgroundColor: "bg-resource-document",
50
+ hoverBorderColor: "hover:border-resource-document hover:before:border-resource-document",
51
+ activeStyle: "border-resource-document",
52
+ icon: <FileText className="size-5 text-white" />,
53
+ },
54
+ prompt: {
55
+ backgroundColor: "bg-resource-prompt",
56
+ hoverBorderColor: "hover:border-resource-prompt hover:before:border-resource-prompt",
57
+ activeStyle: "border-resource-prompt",
58
+ icon: <MessageSquareText className="size-5 text-white" />,
59
+ },
60
+ token: {
61
+ backgroundColor: "bg-resource-token",
62
+ hoverBorderColor: "hover:border-resource-token hover:before:border-resource-token",
63
+ activeStyle: "border-resource-token",
64
+ icon: <Coins className="size-5 text-white" />,
65
+ },
66
+ inference: {
67
+ backgroundColor: "bg-resource-inference",
68
+ hoverBorderColor: "hover:border-resource-inference hover:before:border-resource-inference",
69
+ activeStyle: "border-resource-inference",
70
+ icon: <Zap className="size-5 text-white" />,
71
+ },
72
+ tool: {
73
+ backgroundColor: "bg-resource-tools",
74
+ hoverBorderColor: "hover:border-resource-tools hover:before:border-resource-tools",
75
+ activeStyle: "border-resource-tools",
76
+ icon: <Wrench className="size-5 text-white" />,
77
+ },
78
+ benchmarks: {
79
+ backgroundColor: "bg-resource-benchmark",
80
+ hoverBorderColor: "hover:border-resource-benchmark hover:before:border-resource-benchmark",
81
+ activeStyle: "border-resource-benchmark",
82
+ icon: <LineChart className="size-5 text-white" />,
83
+ },
84
+ benchmark: {
85
+ backgroundColor: "bg-resource-benchmark",
86
+ hoverBorderColor: "hover:border-resource-benchmark hover:before:border-resource-benchmark",
87
+ activeStyle: "border-resource-benchmark",
88
+ icon: <LineChart className="size-5 text-white" />,
89
+ },
90
+ guards: {
91
+ backgroundColor: "bg-resource-guard",
92
+ hoverBorderColor: "hover:border-resource-guards hover:before:border-resource-guard",
93
+ activeStyle: "border-resource-guard",
94
+ icon: <Shield className="size-5 text-white" />,
95
+ },
96
+ agent: {
97
+ backgroundColor: "bg-resource-agent",
98
+ hoverBorderColor: "hover:border-resource-agent hover:before:border-resource-agent",
99
+ activeStyle: "border-resource-agent",
100
+ icon: <Bot className="size-5 text-white" />,
101
+ },
102
+ guardrail: {
103
+ backgroundColor: "bg-resource-guardrail",
104
+ hoverBorderColor: "hover:border-resource-guardrail hover:before:border-resource-guardrail",
105
+ activeStyle: "border-resource-guardrail",
106
+ icon: <Fence className="size-5 text-white" />,
107
+ },
108
+ computation: {
109
+ backgroundColor: "bg-resource-compute",
110
+ hoverBorderColor: "hover:border-resource-compute hover:before:border-resource-compute",
111
+ activeStyle: "border-resource-compute",
112
+ icon: <Cpu className="size-5 text-white" />,
113
+ },
114
+ "system-prompt": {
115
+ backgroundColor: "bg-resource-system-prompt",
116
+ hoverBorderColor: "hover:border-resource-system-prompt hover:before:border-resource-system-prompt",
117
+ activeStyle: "border-resource-system-prompt",
118
+ icon: <MessageSquareCode className="size-5 text-white" />,
119
+ },
120
+ context: {
121
+ backgroundColor: "bg-resource-context",
122
+ hoverBorderColor: "hover:border-resource-context hover:before:border-resource-context",
123
+ activeStyle: "border-resource-context",
124
+ icon: <MessageSquareQuote className="size-5 text-white" />,
125
+ },
126
+ reasoning: {
127
+ backgroundColor: "bg-resource-reasoning",
128
+ hoverBorderColor: "hover:border-resource-reasoning hover:before:border-resource-reasoning",
129
+ activeStyle: "border-resource-reasoning",
130
+ icon: <MessageSquareMore className="size-5 text-white" />,
131
+ },
132
+ "system-parameters": {
133
+ backgroundColor: "bg-resource-system-parameters",
134
+ hoverBorderColor: "hover:border-resource-system-parameters hover:before:border-resource-system-parameters",
135
+ activeStyle: "border-resource-system-parameters",
136
+ icon: <Settings2 className="size-5 text-white" />,
137
+ },
138
+ database: {
139
+ backgroundColor: "bg-resource-database",
140
+ hoverBorderColor: "hover:border-resource-database hover:before:border-resource-database",
141
+ activeStyle: "border-resource-database",
142
+ icon: <Database className="size-5 text-white" />,
143
+ },
144
+ };
@@ -0,0 +1,167 @@
1
+ /// This types file is for types used directly by the Explorer
2
+ import { v4 as uuidv4 } from "uuid";
3
+ import { Node, Edge } from "reactflow";
4
+ import { Actor, VerifiableCredential, Anchor } from "../../integrityTypes/types";
5
+ import {
6
+ GovernanceStatement,
7
+ MetadataStatement,
8
+ Statement,
9
+ StorageStatement,
10
+ VcStatement,
11
+ SigstoreBundle,
12
+ } from "../../integrityTypes/StatementTypes";
13
+
14
+ // Custom edge to support dagre layout
15
+ export type LineageEdge = Edge<EdgeData>;
16
+
17
+ export type EdgeData = {
18
+ // Used for custom styling when highlighting a subgraph in the lineage
19
+ isInSubGraph: boolean;
20
+ };
21
+
22
+ export function createEdge(source: string, target: string): LineageEdge {
23
+ const edge: LineageEdge = {
24
+ id: uuidv4(),
25
+ source: source,
26
+ target: target,
27
+ type: "custom-edge",
28
+ data: {
29
+ isInSubGraph: true,
30
+ },
31
+ };
32
+ return edge;
33
+ }
34
+
35
+ export type LineageNode = Node<NodeData>;
36
+
37
+ // Custom data we add to the node to support later processing and display
38
+ export type NodeData = {
39
+ // Display Items
40
+ label: string;
41
+ nodeShape: NodeShape;
42
+ icon: string;
43
+ displayType: string;
44
+ size: NodeSize;
45
+ customIcons?: Record<string, string>; // User supplied icons
46
+ sub_graph?: SubgraphInfo; // Graph the node belongs too
47
+
48
+ // Used to display the "handles" that the edges attach to
49
+ hasSuccessorNode: boolean;
50
+ hasPrecedingNode: boolean;
51
+
52
+ // Used for custom styling when highlighting a subgraph in the lineage
53
+ isInSubGraph: boolean;
54
+ sidebarData: DataNodeSidebarData | ComputeNodeSidebarData | null;
55
+ isActive: boolean;
56
+ };
57
+
58
+ export type MetadataLineage = {
59
+ statement: MetadataStatement;
60
+ metadata: object;
61
+ vc?: VerifiableCredential;
62
+ };
63
+
64
+ export type DataNodeRegistration = {
65
+ // can have multiple VCs and Anchors for a single statement
66
+ statement: Statement;
67
+ registeredByActor: Actor; // Actor (user DID) information
68
+ anchors?: Anchor;
69
+ vcs?: VcStatement[];
70
+ };
71
+
72
+ export type StorageLineage = {
73
+ statement: StorageStatement;
74
+ metadata: object;
75
+ };
76
+
77
+ export type DataNodeSidebarData = {
78
+ // Additional data for the sidebar
79
+ registrations?: DataNodeRegistration[];
80
+ metadata?: object[]; // User supplied metadata items
81
+ metadataLineage?: MetadataLineage[]; // Metadata Statement(s) corresponding VCs for the data
82
+ sourceData?: IrohData[] | string; // list of iroh files or single file blob
83
+ storage?: StorageLineage;
84
+ governance?: GovernanceStatement;
85
+ sigstoreBundles?: SigstoreBundle[];
86
+ };
87
+
88
+ export type ComputeNodeSidebarData = {
89
+ statement: Statement; // the integrity statement and anchor if available
90
+ metadata?: object; // User supplied metadata items
91
+ metadataLineage?: MetadataLineage[]; // Metadata Statement corresponding VCs for the data
92
+ vcStatement?: VcStatement[]; // integrity VC statement
93
+ registeredByActor: Actor; // Actor (user DID) information
94
+ executedOnActor?: Actor; // Actor (user DID) information
95
+ operatedByActor?: Actor; // Actor (user DID) information
96
+ sourceData?: IrohData[] | string; // list of iroh files or single file blob
97
+ anchor?: Anchor;
98
+ governance?: GovernanceStatement;
99
+ };
100
+
101
+ export type IrohData = {
102
+ path: string; // name of file in the collection
103
+ cid: string; // CID of the file
104
+ data: string | null; // Decoded data from the file
105
+ };
106
+
107
+ export const defaultNodeSize = { width: 200, height: 50 };
108
+ export type NodeShape = "round" | "square";
109
+ export type NodeUIComponent = "CustomNode" | "ComputationNode";
110
+ export type NodeSize = {
111
+ width: number;
112
+ height: number;
113
+ };
114
+ export type NodeConfig = {
115
+ displayType: string;
116
+ shape: NodeShape;
117
+ icon: string;
118
+ component: NodeUIComponent;
119
+ size: NodeSize;
120
+ };
121
+
122
+ export function createDefaultNode(
123
+ id: string,
124
+ nodeConfig: NodeConfig,
125
+ label: string,
126
+ customIcons?: Record<string, string>,
127
+ graph?: Subgraph,
128
+ ): LineageNode {
129
+ const node: LineageNode = {
130
+ id: id,
131
+ type: nodeConfig.component,
132
+ data: {
133
+ label: label,
134
+ nodeShape: nodeConfig.shape,
135
+ icon: nodeConfig.icon,
136
+ displayType: nodeConfig.displayType,
137
+ size: nodeConfig.size,
138
+ hasSuccessorNode: true,
139
+ hasPrecedingNode: true,
140
+ isInSubGraph: true,
141
+ sidebarData: null,
142
+ customIcons: customIcons,
143
+ isActive: false,
144
+ sub_graph: graph,
145
+ },
146
+ position: { x: 0, y: 0 },
147
+ };
148
+
149
+ return node;
150
+ }
151
+
152
+ /// Structure of the V4 Manifest (with graphs)
153
+ export interface GraphManifest {
154
+ graphs: Array<Subgraph>;
155
+ blobs: Record<string, string>;
156
+ anchors?: Anchor[];
157
+ }
158
+
159
+ export interface Subgraph extends SubgraphInfo {
160
+ statements: Array<object>;
161
+ }
162
+
163
+ export interface SubgraphInfo {
164
+ id: string;
165
+ name: string;
166
+ parent?: string;
167
+ }
@@ -0,0 +1,54 @@
1
+ import { Fragment } from "react/jsx-runtime";
2
+ import { cn } from "@/lib/utils";
3
+ interface DataProps {
4
+ label?: string;
5
+ value: React.ReactNode;
6
+ offsetTopLabel?: boolean;
7
+ }
8
+
9
+ export const SectionList = ({ data, className }: { data: DataProps[]; className?: string }) => {
10
+ return (
11
+ <SectionListWrapper className={cn("mt-6", className)}>
12
+ {data.map((item, index) => {
13
+ if (!item.value) return null;
14
+
15
+ if (!item.label) return <OneColumnListItem key={index} value={item.value} />;
16
+
17
+ return <TwoColumnListItem key={`${item.label}-${index}`} {...item} />;
18
+ })}
19
+ </SectionListWrapper>
20
+ );
21
+ };
22
+
23
+ export const SectionListWrapper = ({ children, className }: { children: React.ReactNode; className?: string }) => {
24
+ return <div className={cn("grid grid-cols-[7.125rem_minmax(0,1fr)] gap-x-3 gap-y-4", className)}>{children}</div>;
25
+ };
26
+
27
+ export const TwoColumnListItem = ({ label, value, offsetTopLabel = false }: DataProps) => {
28
+ return (
29
+ <Fragment>
30
+ <h5
31
+ className={cn(
32
+ "text-sm font-medium text-text-secondary text-right capitalize",
33
+ offsetTopLabel ? "mt-2" : "",
34
+ )}
35
+ >
36
+ {label}
37
+ </h5>
38
+ <div className="w-full text-sm break-all">{value}</div>
39
+ </Fragment>
40
+ );
41
+ };
42
+
43
+ const OneColumnListItem = ({ value }: DataProps) => {
44
+ return <div className="col-span-2 w-full">{value}</div>;
45
+ };
46
+
47
+ export const SectionInnerTitle = ({ title }: { title: string }) => {
48
+ return (
49
+ <div className="col-span-2 w-full flex items-center gap-3">
50
+ <h5 className="font-medium text-sm">{title}</h5>
51
+ <div className="h-px bg-border flex-1" />
52
+ </div>
53
+ );
54
+ };
@@ -0,0 +1,10 @@
1
+ const SectionTitle = ({ title, renderRightContent }: { title: string; renderRightContent?: () => React.ReactNode }) => {
2
+ return (
3
+ <div className="border-b border-border pb-3 flex items-center justify-between w-full">
4
+ <h3 className="text-lg font-medium">{title}</h3>
5
+ {renderRightContent && renderRightContent()}
6
+ </div>
7
+ );
8
+ };
9
+
10
+ export default SectionTitle;
@@ -0,0 +1,70 @@
1
+ import { IconButton } from "@eqtylab/equality";
2
+
3
+ import { LineageNode } from "../nodes/types.ts";
4
+ import RegistrationSection from "./sections/RegistrationSection.tsx";
5
+ import CustomSection from "./sections/CustomSection.tsx";
6
+ import { cn } from "@/lib/utils.ts";
7
+ import { NODES_STYLES } from "../nodes/nodes.tsx";
8
+ import { ParsedManifest, UploadVerification } from "@/v-comp-viewer/utils.tsx";
9
+ import GovernanceSection from "./sections/GovernanceSection.tsx";
10
+ import StorageSection from "./sections/StorageSection.tsx";
11
+ import SigstoreSection from "./sections/SigstoreSection.tsx";
12
+ import SidebarWrapper from "./SidebarWrapper.tsx";
13
+
14
+ type Props = {
15
+ node: LineageNode | null;
16
+ onCloseClick: () => void;
17
+ vCompData: ParsedManifest | null;
18
+ vCompVerifyData: UploadVerification | null;
19
+ };
20
+
21
+ const Sidebar = ({ node, onCloseClick, vCompData, vCompVerifyData }: Props) => {
22
+ if (!node) {
23
+ return null;
24
+ }
25
+
26
+ console.log("Sidebar node data:", node.data);
27
+
28
+ const nodeType = (() => {
29
+ if (!node.data.displayType) return "default";
30
+ switch (node.data.displayType) {
31
+ case "Unknown":
32
+ return "default";
33
+ default:
34
+ return node.data.displayType.toLowerCase();
35
+ }
36
+ })() as keyof typeof NODES_STYLES;
37
+
38
+ const nodeStyle = NODES_STYLES[nodeType] || NODES_STYLES["default"];
39
+
40
+ return (
41
+ <SidebarWrapper>
42
+ {/* Header */}
43
+ <div className="flex items-center justify-between gap-4 bg-[linear-gradient(90deg,rgba(226,204,255,0.2)_0%,rgba(136,122,153,0.1)_100%)] py-3 pl-6 pr-4">
44
+ <div className="flex items-center gap-2">
45
+ <div
46
+ className={cn(
47
+ "flex size-10 items-center justify-center rounded-full",
48
+ nodeStyle.backgroundColor,
49
+ )}
50
+ >
51
+ {nodeStyle.icon}
52
+ </div>
53
+ <h2 className="text-xl font-semibold capitalize">{node.data.displayType}</h2>
54
+ </div>
55
+
56
+ <IconButton name="X" size="md" onClick={onCloseClick}></IconButton>
57
+ </div>
58
+ {/* Content */}
59
+ <div className="grid gap-10 pb-14 pl-6 pr-7 pt-6 bg-background-raised">
60
+ <RegistrationSection node={node} vCompData={vCompData} vCompVerifyData={vCompVerifyData} />
61
+ <CustomSection node={node} />
62
+ <GovernanceSection node={node} />
63
+ <StorageSection node={node} />
64
+ <SigstoreSection node={node} />
65
+ </div>
66
+ </SidebarWrapper>
67
+ );
68
+ };
69
+
70
+ export default Sidebar;
@@ -0,0 +1,76 @@
1
+ import { cn } from "@/lib/utils.ts";
2
+ import { GripVertical } from "lucide-react";
3
+ import { useState, useRef, useEffect } from "react";
4
+
5
+ type Props = {
6
+ children: React.ReactNode;
7
+ };
8
+
9
+ const MIN_WIDTH = 34.3 * 16; // 34.3rem in pixels
10
+
11
+ const SidebarWrapper = ({ children }: Props) => {
12
+ const [width, setWidth] = useState(MIN_WIDTH);
13
+ const [isResizing, setIsResizing] = useState(false);
14
+ const sidebarRef = useRef<HTMLDivElement>(null);
15
+
16
+ useEffect(() => {
17
+ const handleMouseMove = (e: MouseEvent) => {
18
+ if (!isResizing || !sidebarRef.current) return;
19
+
20
+ // Calculate new width based on right edge of viewport minus cursor position
21
+ const newWidth = window.innerWidth - e.clientX;
22
+ const clampedWidth = Math.max(MIN_WIDTH, newWidth);
23
+ setWidth(clampedWidth);
24
+ };
25
+
26
+ const handleMouseUp = () => {
27
+ setIsResizing(false);
28
+ };
29
+
30
+ if (isResizing) {
31
+ document.addEventListener("mousemove", handleMouseMove);
32
+ document.addEventListener("mouseup", handleMouseUp);
33
+ document.body.style.cursor = "ew-resize";
34
+ document.body.style.userSelect = "none";
35
+ }
36
+
37
+ return () => {
38
+ document.removeEventListener("mousemove", handleMouseMove);
39
+ document.removeEventListener("mouseup", handleMouseUp);
40
+ document.body.style.cursor = "";
41
+ document.body.style.userSelect = "";
42
+ };
43
+ }, [isResizing]);
44
+
45
+ const handleMouseDown = () => {
46
+ setIsResizing(true);
47
+ };
48
+
49
+ return (
50
+ <div
51
+ ref={sidebarRef}
52
+ className="absolute right-0 top-0 z-40 h-full max-w-[80%]"
53
+ style={{ width: `${width}px` }}
54
+ >
55
+ <div
56
+ className={cn(
57
+ "flex h-full w-full flex-col overflow-auto border-l border-border bg-background-raised transition-all duration-500",
58
+ )}
59
+ >
60
+ {children}
61
+ </div>
62
+ {/* Drag handle */}
63
+ <button
64
+ onMouseDown={handleMouseDown}
65
+ className={cn(
66
+ "absolute top-1/2 left-0 -translate-y-1/2 -translate-x-6 hover:text-brand-primary transition-colors duration-300 px-1 py-3 border-border rounded-s-md border-y border-l bg-background-raised",
67
+ isResizing ? "cursor-grabbing" : "cursor-grab",
68
+ )}
69
+ >
70
+ <GripVertical className="size-4" />
71
+ </button>
72
+ </div>
73
+ );
74
+ };
75
+
76
+ export default SidebarWrapper;