@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.
- package/.env.api +6 -0
- package/.env.iframe +2 -0
- package/.env.manifest +2 -0
- package/.envrc +1 -0
- package/.eslintrc.cjs +17 -0
- package/.github/workflows/ci.yml +46 -0
- package/.github/workflows/publish.yml +44 -0
- package/.husky/pre-push +2 -0
- package/.prettierignore +2 -0
- package/.prettierrc.json +13 -0
- package/LICENSE +201 -0
- package/README.md +84 -0
- package/flake.lock +61 -0
- package/flake.nix +23 -0
- package/index.html +13 -0
- package/package.json +93 -0
- package/postcss.config.js +5 -0
- package/public/logos/eci.svg +23 -0
- package/public/logos/eqty.svg +3 -0
- package/public/manifests/B-200-merged.json +773 -0
- package/public/manifests/amd-sev.json +426 -0
- package/public/manifests/anchors.json +609 -0
- package/public/manifests/association-no-metadata.json +1393 -0
- package/public/manifests/association.json +1402 -0
- package/public/manifests/eqty-docker.json +562 -0
- package/public/manifests/governance.json +1324 -0
- package/public/manifests/intel-tdx-with-nvidia.json +441 -0
- package/public/manifests/intel-tdx.json +404 -0
- package/public/manifests/iroh-collections.json +1285 -0
- package/public/manifests/model-signing.json +1536 -0
- package/public/manifests/multiple-registrations.json +129 -0
- package/public/manifests/no-vcs.json +114 -0
- package/public/manifests/storage.json +294 -0
- package/public/manifests/sub-graphs.json +1 -0
- package/src/animations/variants.ts +52 -0
- package/src/app/apiClient/integrityService/fetchAttributes.ts +29 -0
- package/src/app/apiClient/integrityService/fetchManifest.ts +28 -0
- package/src/app/apiClient/integrityService/types.ts +12 -0
- package/src/app/components/integrityService/IntegrityService.tsx +105 -0
- package/src/app/components/integrityService/components/AuthButton.tsx +26 -0
- package/src/app/components/integrityService/components/FiltersModal.tsx +214 -0
- package/src/app/components/integrityService/components/FiltersToggle.tsx +28 -0
- package/src/app/components/manifestViewer/ManifestViewer.tsx +90 -0
- package/src/app/components/manifestViewer/components/ManifestButtons.tsx +215 -0
- package/src/app/config.json +23 -0
- package/src/app/config.ts +28 -0
- package/src/app/pages/index.tsx +34 -0
- package/src/app/stores/manifestStore.ts +19 -0
- package/src/app/utils/appMode.ts +37 -0
- package/src/assets/fonts/TWKLausanne-300.woff +0 -0
- package/src/assets/fonts/TWKLausanne-300.woff2 +0 -0
- package/src/assets/fonts/TWKLausanne-400.woff +0 -0
- package/src/assets/fonts/TWKLausanne-400.woff2 +0 -0
- package/src/assets/fonts/TWKLausanne-500.woff +0 -0
- package/src/assets/fonts/TWKLausanne-500.woff2 +0 -0
- package/src/assets/fonts/TWKLausanne-600.woff +0 -0
- package/src/assets/fonts/TWKLausanne-600.woff2 +0 -0
- package/src/assets/vectors/eqtylab.svg +6 -0
- package/src/components/app-header.tsx +61 -0
- package/src/components/dark-mode-switch.tsx +16 -0
- package/src/components/ui/accordion.tsx +47 -0
- package/src/components/ui/certificate-chain.tsx +60 -0
- package/src/components/ui/certificate-code.tsx +39 -0
- package/src/components/ui/details.tsx +20 -0
- package/src/components/ui/display-code.tsx +47 -0
- package/src/components/ui/panel-label.tsx +12 -0
- package/src/components/ui/verify-state-badge.tsx +32 -0
- package/src/explorer-component/LineageExplorer.tsx +89 -0
- package/src/explorer-component/components/CustomEdge.tsx +28 -0
- package/src/explorer-component/components/LineageFlow.tsx +220 -0
- package/src/explorer-component/components/NodeIconLoader.tsx +26 -0
- package/src/explorer-component/components/nodes/ComputationNode.tsx +56 -0
- package/src/explorer-component/components/nodes/CustomNode.tsx +112 -0
- package/src/explorer-component/components/nodes/index.ts +4 -0
- package/src/explorer-component/components/nodes/nodes.tsx +144 -0
- package/src/explorer-component/components/nodes/types.ts +167 -0
- package/src/explorer-component/components/sidebar/SectionList.tsx +54 -0
- package/src/explorer-component/components/sidebar/SectionTitle.tsx +10 -0
- package/src/explorer-component/components/sidebar/Sidebar.tsx +70 -0
- package/src/explorer-component/components/sidebar/SidebarWrapper.tsx +76 -0
- package/src/explorer-component/components/sidebar/sections/CustomSection.tsx +238 -0
- package/src/explorer-component/components/sidebar/sections/FileViewer.tsx +229 -0
- package/src/explorer-component/components/sidebar/sections/GovernanceSection.tsx +52 -0
- package/src/explorer-component/components/sidebar/sections/RegistrationSection.tsx +254 -0
- package/src/explorer-component/components/sidebar/sections/SigstoreSection.tsx +37 -0
- package/src/explorer-component/components/sidebar/sections/StorageSection.tsx +73 -0
- package/src/explorer-component/components/sidebar/sections/custom/IrohCollectionsView.tsx +139 -0
- package/src/explorer-component/components/sidebar/sections/registration/VerificationIcon.tsx +108 -0
- package/src/explorer-component/components/sidebar/sections/registration/actor/ActorBadge.tsx +62 -0
- package/src/explorer-component/components/sidebar/sections/registration/actor/svg/AMDLogo.tsx +40 -0
- package/src/explorer-component/components/sidebar/sections/registration/actor/svg/AzureLogo.tsx +65 -0
- package/src/explorer-component/components/sidebar/sections/registration/actor/svg/IntelLogo.tsx +24 -0
- package/src/explorer-component/components/sidebar/sections/registration/actor/svg/NvidiaLogo.tsx +27 -0
- package/src/explorer-component/components/sidebar/sections/registration/verifierClient.ts +13 -0
- package/src/explorer-component/icons/AttributionIcon.svg +6 -0
- package/src/explorer-component/icons/BenchmarkIcon.svg +6 -0
- package/src/explorer-component/icons/BenchmarkResultIcon.svg +6 -0
- package/src/explorer-component/icons/CertificateIcon.svg +6 -0
- package/src/explorer-component/icons/CodeIcon.svg +6 -0
- package/src/explorer-component/icons/ComputationIcon.svg +6 -0
- package/src/explorer-component/icons/DataIcon.svg +6 -0
- package/src/explorer-component/icons/DatabaseIcon.svg +6 -0
- package/src/explorer-component/icons/DatasetIcon.svg +6 -0
- package/src/explorer-component/icons/DeltaLakeIcon.svg +7 -0
- package/src/explorer-component/icons/DocumentIcon.svg +6 -0
- package/src/explorer-component/icons/MediaIcon.svg +6 -0
- package/src/explorer-component/icons/ModelIcon.svg +6 -0
- package/src/explorer-component/icons/TeamIcon.svg +3 -0
- package/src/explorer-component/icons/TokenIcon.svg +6 -0
- package/src/explorer-component/icons/UnknownIcon.svg +6 -0
- package/src/explorer-component/icons/index.ts +35 -0
- package/src/explorer-component/index.ts +5 -0
- package/src/explorer-component/integrityTypes/AnchorTypes.ts +31 -0
- package/src/explorer-component/integrityTypes/StatementTypes.ts +333 -0
- package/src/explorer-component/integrityTypes/VCTypes.ts +85 -0
- package/src/explorer-component/integrityTypes/types.ts +3 -0
- package/src/explorer-component/utils/config.ts +163 -0
- package/src/explorer-component/utils/formatTimestamp.ts +5 -0
- package/src/explorer-component/utils/generateGraph.ts +271 -0
- package/src/explorer-component/utils/layoutGraph.ts +148 -0
- package/src/explorer-component/utils/resolveIrohBlobs.ts +117 -0
- package/src/explorer-component/utils/statementHelpers.ts +252 -0
- package/src/explorer-component/utils/stripPrefix.ts +4 -0
- package/src/hooks/use-mobile.tsx +19 -0
- package/src/index.ts +3 -0
- package/src/lib/resource-types.ts +31 -0
- package/src/lib/use-escape-key.tsx +16 -0
- package/src/lib/utils.ts +19 -0
- package/src/main.css +82 -0
- package/src/main.tsx +39 -0
- package/src/v-comp-viewer/components/container-did-details.tsx +53 -0
- package/src/v-comp-viewer/components/system-did-details.tsx +356 -0
- package/src/v-comp-viewer/useVComp.ts +196 -0
- package/src/v-comp-viewer/utils.tsx +824 -0
- package/src/vite-env.d.ts +1 -0
- package/tsconfig.json +33 -0
- package/tsconfig.node.json +10 -0
- package/vercel.json +13 -0
- package/vite.app.config.ts +48 -0
- package/vite.lib.config.ts +61 -0
|
@@ -0,0 +1,254 @@
|
|
|
1
|
+
import { IconButton } from "@eqtylab/equality";
|
|
2
|
+
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@eqtylab/equality";
|
|
3
|
+
|
|
4
|
+
import { DataNodeRegistration, LineageNode } from "../../nodes/types";
|
|
5
|
+
import { StatementVerficationIcon, VCVerficationIcon } from "./registration/VerificationIcon";
|
|
6
|
+
import { ActorBadge } from "./registration/actor/ActorBadge";
|
|
7
|
+
import {
|
|
8
|
+
Actor,
|
|
9
|
+
Anchor,
|
|
10
|
+
Statement,
|
|
11
|
+
ComputationStatement,
|
|
12
|
+
VcStatement,
|
|
13
|
+
RegistrationTypes,
|
|
14
|
+
} from "@/explorer-component/integrityTypes/types";
|
|
15
|
+
import SectionTitle from "../SectionTitle";
|
|
16
|
+
import { SectionList } from "../SectionList";
|
|
17
|
+
import ContainerDidDetails from "@/v-comp-viewer/components/container-did-details";
|
|
18
|
+
import { ParsedManifest, UploadVerification } from "@/v-comp-viewer/utils";
|
|
19
|
+
import SystemDidDetails from "@/v-comp-viewer/components/system-did-details";
|
|
20
|
+
import { useEffect, useState } from "react";
|
|
21
|
+
import { formatTimestamp } from "@/explorer-component/utils/formatTimestamp";
|
|
22
|
+
import DisplayCode from "@/components/ui/display-code";
|
|
23
|
+
|
|
24
|
+
type Props = {
|
|
25
|
+
node: LineageNode;
|
|
26
|
+
vCompData: ParsedManifest | null;
|
|
27
|
+
vCompVerifyData: UploadVerification | null;
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
const RegistrationSection = ({ node, vCompData, vCompVerifyData }: Props) => {
|
|
31
|
+
const sidebarData = node?.data.sidebarData;
|
|
32
|
+
|
|
33
|
+
if (sidebarData && "registrations" in sidebarData) {
|
|
34
|
+
// Display Registration(s) for Data Node
|
|
35
|
+
const registrations = sidebarData.registrations;
|
|
36
|
+
|
|
37
|
+
if (!registrations) return null;
|
|
38
|
+
|
|
39
|
+
return (
|
|
40
|
+
<div>
|
|
41
|
+
<SectionTitle title="Registration" />
|
|
42
|
+
<MultipleRegistrationsDisplay
|
|
43
|
+
node={node}
|
|
44
|
+
registrations={registrations}
|
|
45
|
+
vCompData={vCompData}
|
|
46
|
+
vCompVerifyData={vCompVerifyData}
|
|
47
|
+
/>
|
|
48
|
+
</div>
|
|
49
|
+
);
|
|
50
|
+
} else if (sidebarData && "statement" in sidebarData) {
|
|
51
|
+
// Display Registration for Compute Node
|
|
52
|
+
return (
|
|
53
|
+
<div>
|
|
54
|
+
<SectionTitle title="Registration" />
|
|
55
|
+
<RegistrationDisplay
|
|
56
|
+
node={node}
|
|
57
|
+
statement={sidebarData.statement}
|
|
58
|
+
registeredByActor={sidebarData.registeredByActor}
|
|
59
|
+
executedOnActor={sidebarData.executedOnActor}
|
|
60
|
+
operatedByActor={sidebarData.operatedByActor}
|
|
61
|
+
anchor={sidebarData.anchor}
|
|
62
|
+
vc={sidebarData.vcStatement}
|
|
63
|
+
vCompData={vCompData}
|
|
64
|
+
vCompVerifyData={vCompVerifyData}
|
|
65
|
+
/>
|
|
66
|
+
</div>
|
|
67
|
+
);
|
|
68
|
+
}
|
|
69
|
+
};
|
|
70
|
+
|
|
71
|
+
const MultipleRegistrationsDisplay = ({
|
|
72
|
+
node,
|
|
73
|
+
registrations,
|
|
74
|
+
vCompData,
|
|
75
|
+
vCompVerifyData,
|
|
76
|
+
}: {
|
|
77
|
+
node: LineageNode;
|
|
78
|
+
registrations: DataNodeRegistration[];
|
|
79
|
+
storedOn?: string;
|
|
80
|
+
vCompData: ParsedManifest | null;
|
|
81
|
+
vCompVerifyData: UploadVerification | null;
|
|
82
|
+
}) => {
|
|
83
|
+
const [statementIndex, setStatementIndex] = useState(0);
|
|
84
|
+
|
|
85
|
+
const handleStatementIndexChange = (index: number) => {
|
|
86
|
+
setStatementIndex(index);
|
|
87
|
+
};
|
|
88
|
+
|
|
89
|
+
useEffect(() => {
|
|
90
|
+
setStatementIndex(0);
|
|
91
|
+
}, [node]);
|
|
92
|
+
|
|
93
|
+
const { statement, registeredByActor, anchors, vcs } = registrations[statementIndex] || registrations[0];
|
|
94
|
+
|
|
95
|
+
return (
|
|
96
|
+
<RegistrationDisplay
|
|
97
|
+
node={node}
|
|
98
|
+
handleStatementIndexChange={handleStatementIndexChange}
|
|
99
|
+
statement={statement}
|
|
100
|
+
registrations={registrations}
|
|
101
|
+
registeredByActor={registeredByActor}
|
|
102
|
+
anchor={anchors}
|
|
103
|
+
vc={vcs}
|
|
104
|
+
vCompData={vCompData}
|
|
105
|
+
vCompVerifyData={vCompVerifyData}
|
|
106
|
+
/>
|
|
107
|
+
);
|
|
108
|
+
};
|
|
109
|
+
|
|
110
|
+
const RegistrationDisplay = ({
|
|
111
|
+
node,
|
|
112
|
+
handleStatementIndexChange,
|
|
113
|
+
statement,
|
|
114
|
+
registrations,
|
|
115
|
+
registeredByActor,
|
|
116
|
+
executedOnActor,
|
|
117
|
+
operatedByActor,
|
|
118
|
+
anchor,
|
|
119
|
+
vc,
|
|
120
|
+
vCompData,
|
|
121
|
+
vCompVerifyData,
|
|
122
|
+
}: {
|
|
123
|
+
node: LineageNode;
|
|
124
|
+
handleStatementIndexChange?: (index: number) => void;
|
|
125
|
+
statement: Statement;
|
|
126
|
+
registrations?: DataNodeRegistration[];
|
|
127
|
+
registeredByActor?: Actor;
|
|
128
|
+
executedOnActor?: Actor;
|
|
129
|
+
operatedByActor?: Actor;
|
|
130
|
+
anchor?: Anchor;
|
|
131
|
+
vc?: VcStatement[];
|
|
132
|
+
vCompData: ParsedManifest | null;
|
|
133
|
+
vCompVerifyData: UploadVerification | null;
|
|
134
|
+
}) => {
|
|
135
|
+
const isComputeNode = node.type === "ComputationNode";
|
|
136
|
+
|
|
137
|
+
const registeredByContainerInfo = (vCompData && vCompData.containers[statement.registeredBy]) || null;
|
|
138
|
+
|
|
139
|
+
const executedOnSystemInfo =
|
|
140
|
+
(vCompData && vCompData.systems[(statement as ComputationStatement).executedOn || ""]) || null;
|
|
141
|
+
|
|
142
|
+
const data = [
|
|
143
|
+
{
|
|
144
|
+
label: "Node ID",
|
|
145
|
+
value: <DisplayCode value={node.id} />,
|
|
146
|
+
offsetTopLabel: true,
|
|
147
|
+
},
|
|
148
|
+
// {
|
|
149
|
+
// label: "SubGraph",
|
|
150
|
+
// value: <p> {node.data.sub_graph?.name} </p>,
|
|
151
|
+
// },
|
|
152
|
+
{
|
|
153
|
+
label: isComputeNode ? "Timestamp" : "Instance",
|
|
154
|
+
value:
|
|
155
|
+
registrations && registrations.length > 1 && handleStatementIndexChange ? (
|
|
156
|
+
<Select onValueChange={(value) => handleStatementIndexChange(parseInt(value))} defaultValue="0">
|
|
157
|
+
<SelectTrigger>
|
|
158
|
+
<SelectValue placeholder="Select a statement" />
|
|
159
|
+
</SelectTrigger>
|
|
160
|
+
<SelectContent>
|
|
161
|
+
{registrations.map((registration, index) => {
|
|
162
|
+
const id = registration.statement.id;
|
|
163
|
+
const timestamp = formatTimestamp(registration.statement.timestamp);
|
|
164
|
+
return (
|
|
165
|
+
<SelectItem value={String(index)} key={id}>
|
|
166
|
+
{`${id.split("cid:")[1].slice(0, 5)}...${id.slice(-4)} (${timestamp})`}
|
|
167
|
+
</SelectItem>
|
|
168
|
+
);
|
|
169
|
+
})}
|
|
170
|
+
</SelectContent>
|
|
171
|
+
</Select>
|
|
172
|
+
) : statement ? (
|
|
173
|
+
<p>{formatTimestamp(statement.timestamp)}</p>
|
|
174
|
+
) : null,
|
|
175
|
+
offsetTopLabel: registrations && registrations.length > 1 ? true : false,
|
|
176
|
+
},
|
|
177
|
+
{
|
|
178
|
+
label: "Registered By",
|
|
179
|
+
value: statement && <ActorBadge didString={statement.registeredBy} actor={registeredByActor} />,
|
|
180
|
+
offsetTopLabel: true,
|
|
181
|
+
},
|
|
182
|
+
{
|
|
183
|
+
value: isComputeNode && registeredByContainerInfo && (
|
|
184
|
+
<ContainerDidDetails containerInfo={registeredByContainerInfo} />
|
|
185
|
+
),
|
|
186
|
+
},
|
|
187
|
+
{
|
|
188
|
+
label: "Executed On",
|
|
189
|
+
value: statement.type == RegistrationTypes.Computation &&
|
|
190
|
+
(statement as ComputationStatement).executedOn && (
|
|
191
|
+
<ActorBadge
|
|
192
|
+
didString={(statement as ComputationStatement).executedOn || ""}
|
|
193
|
+
actor={executedOnActor}
|
|
194
|
+
/>
|
|
195
|
+
),
|
|
196
|
+
offsetTopLabel: true,
|
|
197
|
+
},
|
|
198
|
+
{
|
|
199
|
+
value: isComputeNode && executedOnSystemInfo && (
|
|
200
|
+
<SystemDidDetails systemInfo={executedOnSystemInfo} vCompVerifyData={vCompVerifyData} />
|
|
201
|
+
),
|
|
202
|
+
},
|
|
203
|
+
{
|
|
204
|
+
label: "Operated By",
|
|
205
|
+
value: statement.type == RegistrationTypes.Computation &&
|
|
206
|
+
(statement as ComputationStatement).operatedBy && (
|
|
207
|
+
<ActorBadge
|
|
208
|
+
didString={(statement as ComputationStatement).operatedBy || ""}
|
|
209
|
+
actor={operatedByActor}
|
|
210
|
+
/>
|
|
211
|
+
),
|
|
212
|
+
offsetTopLabel: true,
|
|
213
|
+
},
|
|
214
|
+
{
|
|
215
|
+
label: "Anchors",
|
|
216
|
+
value: anchor && (
|
|
217
|
+
<div className="space-y-2">
|
|
218
|
+
{anchor.locations.map((location) => {
|
|
219
|
+
return (
|
|
220
|
+
<div className="space-y-2" key={`${location.type}:${location.txHash}`}>
|
|
221
|
+
<DisplayCode
|
|
222
|
+
value={`${location.type}:${location.txHash}`}
|
|
223
|
+
actions={
|
|
224
|
+
<IconButton
|
|
225
|
+
name="ExternalLink"
|
|
226
|
+
href={location.urls?.[0]}
|
|
227
|
+
label="View"
|
|
228
|
+
onClick={() => console.log("Open clicked")}
|
|
229
|
+
/>
|
|
230
|
+
}
|
|
231
|
+
/>
|
|
232
|
+
</div>
|
|
233
|
+
);
|
|
234
|
+
})}
|
|
235
|
+
</div>
|
|
236
|
+
),
|
|
237
|
+
offsetTopLabel: true,
|
|
238
|
+
},
|
|
239
|
+
{
|
|
240
|
+
label: "Statement",
|
|
241
|
+
value: statement && <StatementVerficationIcon statement={statement} displayText={true} />,
|
|
242
|
+
},
|
|
243
|
+
{
|
|
244
|
+
label: "Credential",
|
|
245
|
+
value: statement && (
|
|
246
|
+
<VCVerficationIcon vc={vc?.[0].credential} statementId={statement.id} displayText={true} />
|
|
247
|
+
),
|
|
248
|
+
},
|
|
249
|
+
];
|
|
250
|
+
|
|
251
|
+
return <SectionList data={data} />;
|
|
252
|
+
};
|
|
253
|
+
|
|
254
|
+
export default RegistrationSection;
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { CodeBlock } from "@eqtylab/equality";
|
|
2
|
+
import { LineageNode } from "../../nodes/types";
|
|
3
|
+
import SectionTitle from "../SectionTitle";
|
|
4
|
+
import { Fragment } from "react/jsx-runtime";
|
|
5
|
+
|
|
6
|
+
const SigstoreSection = ({ node }: { node: LineageNode }) => {
|
|
7
|
+
const sidebarData = node?.data.sidebarData;
|
|
8
|
+
|
|
9
|
+
if (!sidebarData || !("sigstoreBundles" in sidebarData)) return null;
|
|
10
|
+
|
|
11
|
+
const bundles = sidebarData.sigstoreBundles;
|
|
12
|
+
if (!bundles || bundles.length === 0) return null;
|
|
13
|
+
|
|
14
|
+
return (
|
|
15
|
+
<div className="overflow-auto w-full">
|
|
16
|
+
<SectionTitle title="Sigstore Bundles" />
|
|
17
|
+
<div className="space-y-4 mt-6">
|
|
18
|
+
{bundles.map((bundle, idx) => (
|
|
19
|
+
<Fragment key={idx}>
|
|
20
|
+
<CodeBlock
|
|
21
|
+
title={`Sigstore Bundle (${idx + 1})`}
|
|
22
|
+
code={JSON.stringify(bundle, null, 2)}
|
|
23
|
+
language="json"
|
|
24
|
+
/>
|
|
25
|
+
<CodeBlock
|
|
26
|
+
title={`DSSE Payload (${idx + 1})`}
|
|
27
|
+
code={JSON.stringify(JSON.parse(atob(bundle.dsseEnvelope.payload)), null, 2)}
|
|
28
|
+
language="json"
|
|
29
|
+
/>
|
|
30
|
+
</Fragment>
|
|
31
|
+
))}
|
|
32
|
+
</div>
|
|
33
|
+
</div>
|
|
34
|
+
);
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
export default SigstoreSection;
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import { Button } from "@eqtylab/equality";
|
|
2
|
+
|
|
3
|
+
import SectionTitle from "@/explorer-component/components/sidebar/SectionTitle";
|
|
4
|
+
import { DataNodeSidebarData, LineageNode } from "@/explorer-component/components/nodes/types";
|
|
5
|
+
import { SectionList } from "@/explorer-component/components/sidebar/SectionList";
|
|
6
|
+
import { formatTimestamp } from "@/explorer-component/utils/formatTimestamp";
|
|
7
|
+
import { FileViewer } from "./FileViewer";
|
|
8
|
+
import DisplayCode from "@/components/ui/display-code";
|
|
9
|
+
|
|
10
|
+
const StorageSection = ({ node }: { node: LineageNode }) => {
|
|
11
|
+
const storage = (node.data.sidebarData as DataNodeSidebarData)?.storage;
|
|
12
|
+
|
|
13
|
+
if (!storage) return null;
|
|
14
|
+
|
|
15
|
+
const data = [
|
|
16
|
+
{
|
|
17
|
+
label: "Context",
|
|
18
|
+
value: <DisplayCode value={storage.statement.context} />,
|
|
19
|
+
offsetTopLabel: true,
|
|
20
|
+
},
|
|
21
|
+
{
|
|
22
|
+
label: "Data",
|
|
23
|
+
value: <DisplayCode value={storage.statement.data} />,
|
|
24
|
+
offsetTopLabel: true,
|
|
25
|
+
},
|
|
26
|
+
{
|
|
27
|
+
label: "Registration ID",
|
|
28
|
+
value: <DisplayCode value={storage.statement.id} />,
|
|
29
|
+
offsetTopLabel: true,
|
|
30
|
+
},
|
|
31
|
+
{
|
|
32
|
+
label: "Operated By",
|
|
33
|
+
value: <DisplayCode value={storage.statement.operatedBy} />,
|
|
34
|
+
offsetTopLabel: true,
|
|
35
|
+
},
|
|
36
|
+
{
|
|
37
|
+
label: "Registered By",
|
|
38
|
+
value: <DisplayCode value={storage.statement.registeredBy} />,
|
|
39
|
+
offsetTopLabel: true,
|
|
40
|
+
},
|
|
41
|
+
{
|
|
42
|
+
label: "Stored On",
|
|
43
|
+
value: storage.statement.storedOn && (
|
|
44
|
+
<div className="space-y-2">
|
|
45
|
+
<DisplayCode value={storage.statement.storedOn} />
|
|
46
|
+
<FileViewer
|
|
47
|
+
filename="Stored On"
|
|
48
|
+
language="json"
|
|
49
|
+
content={JSON.stringify(storage.metadata, null, 2)}
|
|
50
|
+
>
|
|
51
|
+
<Button variant="tertiary" size="sm">
|
|
52
|
+
View json
|
|
53
|
+
</Button>
|
|
54
|
+
</FileViewer>
|
|
55
|
+
</div>
|
|
56
|
+
),
|
|
57
|
+
offsetTopLabel: true,
|
|
58
|
+
},
|
|
59
|
+
{
|
|
60
|
+
label: "Timestamp",
|
|
61
|
+
value: <p>{formatTimestamp(storage.statement.timestamp)}</p>,
|
|
62
|
+
},
|
|
63
|
+
];
|
|
64
|
+
|
|
65
|
+
return (
|
|
66
|
+
<div>
|
|
67
|
+
<SectionTitle title="Storage" />
|
|
68
|
+
<SectionList data={data} />
|
|
69
|
+
</div>
|
|
70
|
+
);
|
|
71
|
+
};
|
|
72
|
+
|
|
73
|
+
export default StorageSection;
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
import { useEffect, useState } from "react";
|
|
2
|
+
import { Download } from "lucide-react";
|
|
3
|
+
import { Button, TableContainer, TableBody, TableCell, TableHead, TableHeader, TableRow } from "@eqtylab/equality";
|
|
4
|
+
|
|
5
|
+
import { FileViewer } from "../FileViewer";
|
|
6
|
+
import { IrohData } from "../../../nodes/types";
|
|
7
|
+
import DisplayCode from "@/components/ui/display-code";
|
|
8
|
+
|
|
9
|
+
const TEXT_FILE_EXTS = [
|
|
10
|
+
"txt",
|
|
11
|
+
"md",
|
|
12
|
+
"json",
|
|
13
|
+
"csv",
|
|
14
|
+
"xml",
|
|
15
|
+
"yaml",
|
|
16
|
+
"yml",
|
|
17
|
+
"html",
|
|
18
|
+
"htm",
|
|
19
|
+
"js",
|
|
20
|
+
"jsx",
|
|
21
|
+
"ts",
|
|
22
|
+
"tsx",
|
|
23
|
+
"css",
|
|
24
|
+
"scss",
|
|
25
|
+
"sass",
|
|
26
|
+
"less",
|
|
27
|
+
"py",
|
|
28
|
+
"java",
|
|
29
|
+
"c",
|
|
30
|
+
"cpp",
|
|
31
|
+
"h",
|
|
32
|
+
"hpp",
|
|
33
|
+
"cs",
|
|
34
|
+
"php",
|
|
35
|
+
"sh",
|
|
36
|
+
"bat",
|
|
37
|
+
"ps1",
|
|
38
|
+
"r",
|
|
39
|
+
"rb",
|
|
40
|
+
"rs",
|
|
41
|
+
"go",
|
|
42
|
+
"pl",
|
|
43
|
+
"perl",
|
|
44
|
+
"sas",
|
|
45
|
+
"sql",
|
|
46
|
+
"log",
|
|
47
|
+
"ini",
|
|
48
|
+
"conf",
|
|
49
|
+
"config",
|
|
50
|
+
];
|
|
51
|
+
|
|
52
|
+
const filenameIsForText = (filename: string) => {
|
|
53
|
+
const extension = filename.split(".").pop();
|
|
54
|
+
return TEXT_FILE_EXTS.includes(extension || "");
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
export interface IrohCollectionViewProps {
|
|
58
|
+
data: IrohData[] | null | undefined | string;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
const IrohCollectionView = ({ data }: IrohCollectionViewProps) => {
|
|
62
|
+
const [dataUrls, setDataUrls] = useState<Record<string, string | undefined>>({});
|
|
63
|
+
|
|
64
|
+
useEffect(() => {
|
|
65
|
+
if (!data || typeof data === "string") return;
|
|
66
|
+
|
|
67
|
+
const precalculatedDataUrls: Record<string, string | undefined> = {};
|
|
68
|
+
|
|
69
|
+
data.forEach((item) => {
|
|
70
|
+
const key = item.path;
|
|
71
|
+
const data = item.data && filenameIsForText(item.path) ? item.data.toString() : null;
|
|
72
|
+
const blob = data ? new Blob([data], { type: "text/plain" }) : undefined;
|
|
73
|
+
const dataUrl = blob ? URL.createObjectURL(blob) : undefined;
|
|
74
|
+
precalculatedDataUrls[key] = dataUrl;
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
setDataUrls(precalculatedDataUrls);
|
|
78
|
+
|
|
79
|
+
// This needs to be done in a useEffect so we can revoke the URLs when the component unmounts
|
|
80
|
+
return () => {
|
|
81
|
+
Object.values(precalculatedDataUrls).forEach((url) => {
|
|
82
|
+
if (url) URL.revokeObjectURL(url);
|
|
83
|
+
});
|
|
84
|
+
};
|
|
85
|
+
}, [data]);
|
|
86
|
+
|
|
87
|
+
if (!data || typeof data === "string") return <p> No data</p>;
|
|
88
|
+
|
|
89
|
+
const hasActions =
|
|
90
|
+
data.filter((item) => {
|
|
91
|
+
const data = item.data && filenameIsForText(item.path) ? item.data.toString() : null;
|
|
92
|
+
return data !== null;
|
|
93
|
+
}).length > 0;
|
|
94
|
+
|
|
95
|
+
return (
|
|
96
|
+
<div className="mt-4 overflow-hidden rounded-md border border-border max-w-full">
|
|
97
|
+
<TableContainer style={{ tableLayout: "fixed" }}>
|
|
98
|
+
<TableHeader>
|
|
99
|
+
<TableRow>
|
|
100
|
+
<TableHead className={hasActions ? "" : "w-[65%]"}>Path</TableHead>
|
|
101
|
+
<TableHead className={hasActions ? "" : "w-[35%]"}>CID</TableHead>
|
|
102
|
+
{hasActions && <TableHead className="w-52">Actions</TableHead>}
|
|
103
|
+
</TableRow>
|
|
104
|
+
</TableHeader>
|
|
105
|
+
<TableBody>
|
|
106
|
+
{data.map((item) => {
|
|
107
|
+
const data = item.data && filenameIsForText(item.path) ? item.data.toString() : null;
|
|
108
|
+
return (
|
|
109
|
+
<TableRow key={item.path}>
|
|
110
|
+
<TableCell className="font-medium whitespace-pre-wrap break-all">{item.path}</TableCell>
|
|
111
|
+
<TableCell>
|
|
112
|
+
<DisplayCode value={item.cid.toString()} truncate={true} />
|
|
113
|
+
</TableCell>
|
|
114
|
+
{data && dataUrls[item.path] && (
|
|
115
|
+
<TableCell>
|
|
116
|
+
<div className="flex items-center gap-2">
|
|
117
|
+
<FileViewer filename={item.path} content={data} buttonText="View" />
|
|
118
|
+
<Button
|
|
119
|
+
variant="tertiary"
|
|
120
|
+
size="sm"
|
|
121
|
+
prefix={<Download />}
|
|
122
|
+
href={dataUrls[item.path]}
|
|
123
|
+
download={item.path}
|
|
124
|
+
>
|
|
125
|
+
Download
|
|
126
|
+
</Button>
|
|
127
|
+
</div>
|
|
128
|
+
</TableCell>
|
|
129
|
+
)}
|
|
130
|
+
</TableRow>
|
|
131
|
+
);
|
|
132
|
+
})}
|
|
133
|
+
</TableBody>
|
|
134
|
+
</TableContainer>
|
|
135
|
+
</div>
|
|
136
|
+
);
|
|
137
|
+
};
|
|
138
|
+
|
|
139
|
+
export default IrohCollectionView;
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
import { Button } from "@eqtylab/equality";
|
|
2
|
+
|
|
3
|
+
import { useState, useEffect } from "react";
|
|
4
|
+
import { FileViewer } from "../FileViewer";
|
|
5
|
+
import { VerifiableCredential, Statement, StatementToJSON } from "@/explorer-component/integrityTypes/types";
|
|
6
|
+
import { initVerifier, getVerifier } from "./verifierClient";
|
|
7
|
+
import VerifyStateBadge from "@/components/ui/verify-state-badge";
|
|
8
|
+
import { useManifestStore } from "@/app/stores/manifestStore";
|
|
9
|
+
|
|
10
|
+
// type VerificationType = "ZK" | "TEE" | null;
|
|
11
|
+
// type VerificationResult = {
|
|
12
|
+
// verificationStatus: NodeVerification;
|
|
13
|
+
// verificationType: VerificationType;
|
|
14
|
+
// };
|
|
15
|
+
|
|
16
|
+
type VerificationState = "verifying" | "unverified" | "verified";
|
|
17
|
+
|
|
18
|
+
type Props = {
|
|
19
|
+
displayText?: boolean;
|
|
20
|
+
onClick?: () => {};
|
|
21
|
+
};
|
|
22
|
+
type VCVerifyProps = Props & {
|
|
23
|
+
vc?: VerifiableCredential;
|
|
24
|
+
statementId?: string;
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
type StatementVerifyProps = Props & {
|
|
28
|
+
statement: Statement;
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
export const StatementVerficationIcon = ({ statement, displayText, onClick }: StatementVerifyProps) => {
|
|
32
|
+
const [verifyState, setVerifyState] = useState<VerificationState>("verifying");
|
|
33
|
+
const manifest = useManifestStore((state) => state.manifest);
|
|
34
|
+
|
|
35
|
+
const statementJson = StatementToJSON(statement);
|
|
36
|
+
useEffect(() => {
|
|
37
|
+
const getVerification = async () => {
|
|
38
|
+
try {
|
|
39
|
+
await initVerifier(); // safe to call multiple times
|
|
40
|
+
const verifier = getVerifier();
|
|
41
|
+
const contexts = manifest?.contexts ?? {};
|
|
42
|
+
if (!(await verifier.verify_statement(JSON.stringify(statementJson), contexts))) {
|
|
43
|
+
setVerifyState("unverified");
|
|
44
|
+
} else {
|
|
45
|
+
setVerifyState("verified");
|
|
46
|
+
}
|
|
47
|
+
} catch {
|
|
48
|
+
setVerifyState("unverified");
|
|
49
|
+
}
|
|
50
|
+
};
|
|
51
|
+
if (statement) getVerification();
|
|
52
|
+
}, [statement, manifest]);
|
|
53
|
+
|
|
54
|
+
if (!statement) {
|
|
55
|
+
return (
|
|
56
|
+
<FileViewer content={" "} filename="Statement.json" buttonText="View">
|
|
57
|
+
<VerifyStateBadge state="unverified" displayText={displayText} />
|
|
58
|
+
</FileViewer>
|
|
59
|
+
);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
return (
|
|
63
|
+
<div className="flex items-center gap-2">
|
|
64
|
+
<VerifyStateBadge state={verifyState} displayText={displayText} />
|
|
65
|
+
<FileViewer statement={statement} filename="Statement.json" buttonText="View">
|
|
66
|
+
<Button variant="tertiary" size="sm" onClick={onClick}>
|
|
67
|
+
View json
|
|
68
|
+
</Button>
|
|
69
|
+
</FileViewer>
|
|
70
|
+
</div>
|
|
71
|
+
);
|
|
72
|
+
};
|
|
73
|
+
|
|
74
|
+
export const VCVerficationIcon = ({ vc, statementId, displayText, onClick }: VCVerifyProps) => {
|
|
75
|
+
const [verifyState, setVerifyState] = useState<VerificationState>("verifying");
|
|
76
|
+
|
|
77
|
+
useEffect(() => {
|
|
78
|
+
const getVerification = async () => {
|
|
79
|
+
try {
|
|
80
|
+
await initVerifier(); // safe to call multiple times
|
|
81
|
+
const verifier = getVerifier();
|
|
82
|
+
if (!(await verifier.verify_vc(JSON.stringify(vc), statementId || ""))) {
|
|
83
|
+
setVerifyState("unverified");
|
|
84
|
+
} else {
|
|
85
|
+
setVerifyState("verified");
|
|
86
|
+
}
|
|
87
|
+
} catch {
|
|
88
|
+
setVerifyState("unverified");
|
|
89
|
+
}
|
|
90
|
+
};
|
|
91
|
+
if (vc && statementId) getVerification();
|
|
92
|
+
}, [vc, statementId]);
|
|
93
|
+
|
|
94
|
+
if (!vc || !statementId) {
|
|
95
|
+
return <VerifyStateBadge state="unverified" displayText={displayText} />;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
return (
|
|
99
|
+
<div className="flex items-center gap-2">
|
|
100
|
+
<VerifyStateBadge state={verifyState} displayText={displayText} />
|
|
101
|
+
<FileViewer content={JSON.stringify(vc, null, 2)} filename="VC.json" buttonText="View">
|
|
102
|
+
<Button variant="tertiary" size="sm" onClick={onClick}>
|
|
103
|
+
View json
|
|
104
|
+
</Button>
|
|
105
|
+
</FileViewer>
|
|
106
|
+
</div>
|
|
107
|
+
);
|
|
108
|
+
};
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import NvidiaLogo from "./svg/NvidiaLogo";
|
|
2
|
+
import AMDLogo from "./svg/AMDLogo";
|
|
3
|
+
import IntelLogo from "./svg/IntelLogo";
|
|
4
|
+
import AzureLogo from "./svg/AzureLogo";
|
|
5
|
+
import { Actor, TeeEnvType } from "@/explorer-component/integrityTypes/VCTypes.ts";
|
|
6
|
+
import DisplayCode from "@/components/ui/display-code";
|
|
7
|
+
import { TwoColumnListItem } from "@/explorer-component/components/sidebar/SectionList";
|
|
8
|
+
|
|
9
|
+
export interface ActorBadgeProps {
|
|
10
|
+
didString: string;
|
|
11
|
+
actor?: Actor;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export function ActorBadge({ didString, actor }: ActorBadgeProps) {
|
|
15
|
+
if (!actor) return <DisplayCode value={didString} />;
|
|
16
|
+
|
|
17
|
+
const { did, teeEnv, usesNvidia, metadata } = actor;
|
|
18
|
+
|
|
19
|
+
const bottomRow = teeEnv || usesNvidia;
|
|
20
|
+
|
|
21
|
+
return (
|
|
22
|
+
<DisplayCode
|
|
23
|
+
value={did}
|
|
24
|
+
slot={
|
|
25
|
+
<div className="space-y-2">
|
|
26
|
+
{metadata && Object.entries(metadata).length > 0 ? (
|
|
27
|
+
<div className="grid grid-cols-[2fr_5fr] gap-3 max-w-lg">
|
|
28
|
+
{Object.entries(metadata).map(([key, value]) => (
|
|
29
|
+
<TwoColumnListItem label={key} value={value} key={key} />
|
|
30
|
+
))}
|
|
31
|
+
</div>
|
|
32
|
+
) : (
|
|
33
|
+
<p className="text-xs">No additional data available</p>
|
|
34
|
+
)}
|
|
35
|
+
{bottomRow && (
|
|
36
|
+
<div className="flex flex-wrap items-center gap-2">
|
|
37
|
+
{renderTeeEnvLogo(teeEnv)}
|
|
38
|
+
{usesNvidia && <NvidiaLogo />}
|
|
39
|
+
</div>
|
|
40
|
+
)}
|
|
41
|
+
</div>
|
|
42
|
+
}
|
|
43
|
+
/>
|
|
44
|
+
);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
function renderTeeEnvLogo(teeEnv: TeeEnvType) {
|
|
48
|
+
if (!teeEnv) return null;
|
|
49
|
+
|
|
50
|
+
switch (teeEnv) {
|
|
51
|
+
case "AMD SEV":
|
|
52
|
+
return <AMDLogo />;
|
|
53
|
+
case "Intel TDX":
|
|
54
|
+
return <IntelLogo />;
|
|
55
|
+
case "Azure":
|
|
56
|
+
return <AzureLogo />;
|
|
57
|
+
case "EQTY Docker":
|
|
58
|
+
return <div>VComp Container</div>;
|
|
59
|
+
default:
|
|
60
|
+
return null;
|
|
61
|
+
}
|
|
62
|
+
}
|