@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,215 @@
|
|
|
1
|
+
import { useMemo, useState } from "react";
|
|
2
|
+
import { Upload } from "lucide-react";
|
|
3
|
+
import {
|
|
4
|
+
Badge,
|
|
5
|
+
Button,
|
|
6
|
+
IconButton,
|
|
7
|
+
Select,
|
|
8
|
+
SelectContent,
|
|
9
|
+
SelectItem,
|
|
10
|
+
SelectTrigger,
|
|
11
|
+
SelectValue,
|
|
12
|
+
Dialog,
|
|
13
|
+
DialogContainer,
|
|
14
|
+
DialogHeader,
|
|
15
|
+
DialogTitle,
|
|
16
|
+
DialogContent,
|
|
17
|
+
} from "@eqtylab/equality";
|
|
18
|
+
|
|
19
|
+
import { Config } from "@/app/config";
|
|
20
|
+
import { cn } from "@/lib/utils";
|
|
21
|
+
import { detectUploadsFromFile, UploadsMap, UploadValue, UploadKey } from "@/v-comp-viewer/utils";
|
|
22
|
+
|
|
23
|
+
interface ManifestButtonsProps {
|
|
24
|
+
config: Config;
|
|
25
|
+
handleSampleManifestSelected: (event: string) => void;
|
|
26
|
+
handleFileChange: (file: File) => void;
|
|
27
|
+
allowArtifactsUploads: boolean;
|
|
28
|
+
handleDetectedUploads: (detected: UploadValue[]) => void;
|
|
29
|
+
onFilesSelected: (files: FileList | null) => void;
|
|
30
|
+
uploads: UploadsMap;
|
|
31
|
+
hasManifest: boolean;
|
|
32
|
+
handleDeleteManifest: () => void;
|
|
33
|
+
handleDeleteUpload: (kind: Exclude<UploadKey, "manifest">) => void;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
const ManifestButtons = ({
|
|
37
|
+
config,
|
|
38
|
+
handleSampleManifestSelected,
|
|
39
|
+
handleFileChange,
|
|
40
|
+
allowArtifactsUploads,
|
|
41
|
+
handleDetectedUploads,
|
|
42
|
+
onFilesSelected,
|
|
43
|
+
uploads,
|
|
44
|
+
hasManifest,
|
|
45
|
+
handleDeleteManifest,
|
|
46
|
+
handleDeleteUpload,
|
|
47
|
+
}: ManifestButtonsProps) => {
|
|
48
|
+
const [selectedManifest, setSelectedManifest] = useState<string>("");
|
|
49
|
+
const [isModalOpen, setIsModalOpen] = useState(false);
|
|
50
|
+
const [isDragOver, setIsDragOver] = useState(false);
|
|
51
|
+
|
|
52
|
+
const labels = useMemo(
|
|
53
|
+
() => [
|
|
54
|
+
{ key: "compose" as const, label: "Docker Compose (.yaml)", isUploaded: !!uploads.compose },
|
|
55
|
+
{ key: "cmdline" as const, label: "Kernel Command Line (.txt, .cmdline)", isUploaded: !!uploads.cmdline },
|
|
56
|
+
{ key: "ovmf" as const, label: "Firmware (.ovmf)", isUploaded: !!uploads.ovmf },
|
|
57
|
+
{ key: "initrd" as const, label: "Initial Ram Disk (.gz, .initrd, .img)", isUploaded: !!uploads.initrd },
|
|
58
|
+
{ key: "kernel" as const, label: "Kernel (.bin, .img)", isUploaded: !!uploads.kernel },
|
|
59
|
+
],
|
|
60
|
+
[uploads],
|
|
61
|
+
);
|
|
62
|
+
|
|
63
|
+
return (
|
|
64
|
+
<div className="flex gap-2">
|
|
65
|
+
{config.manifests && config.manifests.length > 0 && (
|
|
66
|
+
<Select
|
|
67
|
+
value={selectedManifest}
|
|
68
|
+
onValueChange={(value) => {
|
|
69
|
+
setSelectedManifest(value);
|
|
70
|
+
handleSampleManifestSelected(value);
|
|
71
|
+
}}
|
|
72
|
+
>
|
|
73
|
+
<SelectTrigger id="select-default" className="min-w-52">
|
|
74
|
+
<SelectValue placeholder="Select a sample manifest" />
|
|
75
|
+
</SelectTrigger>
|
|
76
|
+
<SelectContent>
|
|
77
|
+
{config.manifests.map((file) => (
|
|
78
|
+
<SelectItem key={file} value={file}>
|
|
79
|
+
{file}
|
|
80
|
+
</SelectItem>
|
|
81
|
+
))}
|
|
82
|
+
</SelectContent>
|
|
83
|
+
</Select>
|
|
84
|
+
)}
|
|
85
|
+
<Button variant="primary" onClick={() => setIsModalOpen(true)} prefix={<Upload />}>
|
|
86
|
+
Upload Files
|
|
87
|
+
</Button>
|
|
88
|
+
<Dialog open={isModalOpen} onOpenChange={() => setIsModalOpen(false)}>
|
|
89
|
+
<DialogContainer className="max-w-4xl!">
|
|
90
|
+
<DialogHeader>
|
|
91
|
+
<DialogTitle>Upload Files</DialogTitle>
|
|
92
|
+
</DialogHeader>
|
|
93
|
+
<DialogContent className="grid grid-cols-1 sm:grid-cols-2 gap-4">
|
|
94
|
+
<div
|
|
95
|
+
className={cn(
|
|
96
|
+
"flex relative flex-col items-center justify-center gap-4 bg-background/60 border border-dashed border-border rounded-md px-4 py-8",
|
|
97
|
+
isDragOver ? "bg-card-background" : "",
|
|
98
|
+
)}
|
|
99
|
+
onDragOver={(e) => {
|
|
100
|
+
e.preventDefault();
|
|
101
|
+
setIsDragOver(true);
|
|
102
|
+
}}
|
|
103
|
+
onDragLeave={() => setIsDragOver(false)}
|
|
104
|
+
onDrop={(e) => {
|
|
105
|
+
e.preventDefault();
|
|
106
|
+
setIsDragOver(false);
|
|
107
|
+
const files = Array.from(e.dataTransfer.files);
|
|
108
|
+
if (files.length > 0) {
|
|
109
|
+
if (allowArtifactsUploads) {
|
|
110
|
+
// Process each file
|
|
111
|
+
files.forEach(async (file) => {
|
|
112
|
+
const detected = await detectUploadsFromFile(file);
|
|
113
|
+
handleDetectedUploads(detected);
|
|
114
|
+
});
|
|
115
|
+
} else {
|
|
116
|
+
handleFileChange(files[0]);
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
}}
|
|
120
|
+
>
|
|
121
|
+
<input
|
|
122
|
+
type="file"
|
|
123
|
+
id="file-input"
|
|
124
|
+
className="absolute inset-0 opacity-0 cursor-pointer"
|
|
125
|
+
onChange={(e) => {
|
|
126
|
+
const files = e.target.files;
|
|
127
|
+
|
|
128
|
+
if (!files) return;
|
|
129
|
+
|
|
130
|
+
if (allowArtifactsUploads) {
|
|
131
|
+
handleFileChange(files[0]);
|
|
132
|
+
onFilesSelected(files);
|
|
133
|
+
} else {
|
|
134
|
+
handleFileChange(files[0]);
|
|
135
|
+
}
|
|
136
|
+
}}
|
|
137
|
+
multiple={allowArtifactsUploads}
|
|
138
|
+
/>
|
|
139
|
+
<div className="space-y-2">
|
|
140
|
+
<div className="rounded-full bg-text-primary/10 p-3 mx-auto w-max">
|
|
141
|
+
<Upload className="size-5" />
|
|
142
|
+
</div>
|
|
143
|
+
<p className="text-sm font-medium">Drag Files Here to Upload</p>
|
|
144
|
+
</div>
|
|
145
|
+
<div className="flex items-center gap-2">
|
|
146
|
+
<p className="text-sm font-medium">or</p>
|
|
147
|
+
<Button variant="primary" size="sm" prefix={<Upload />}>
|
|
148
|
+
Choose Files
|
|
149
|
+
</Button>
|
|
150
|
+
</div>
|
|
151
|
+
</div>
|
|
152
|
+
<div className="space-y-2">
|
|
153
|
+
<h4 className="text-sm font-medium">Uploaded Files</h4>
|
|
154
|
+
<div className="space-y-2">
|
|
155
|
+
<UploadLabel
|
|
156
|
+
label="Eqty Manifest (.json)"
|
|
157
|
+
isUploaded={hasManifest}
|
|
158
|
+
handleDeleteUpload={() => {
|
|
159
|
+
setSelectedManifest("");
|
|
160
|
+
handleDeleteManifest();
|
|
161
|
+
}}
|
|
162
|
+
/>
|
|
163
|
+
<div className={cn("h-px bg-border", !allowArtifactsUploads ? "opacity-20" : "")} />
|
|
164
|
+
{labels.map((item) => (
|
|
165
|
+
<UploadLabel
|
|
166
|
+
key={item.label}
|
|
167
|
+
label={item.label}
|
|
168
|
+
isUploaded={item.isUploaded}
|
|
169
|
+
handleDeleteUpload={() => handleDeleteUpload(item.key)}
|
|
170
|
+
className={!allowArtifactsUploads ? "opacity-20" : ""}
|
|
171
|
+
/>
|
|
172
|
+
))}
|
|
173
|
+
</div>
|
|
174
|
+
</div>
|
|
175
|
+
</DialogContent>
|
|
176
|
+
</DialogContainer>
|
|
177
|
+
</Dialog>
|
|
178
|
+
</div>
|
|
179
|
+
);
|
|
180
|
+
};
|
|
181
|
+
|
|
182
|
+
export default ManifestButtons;
|
|
183
|
+
|
|
184
|
+
const UploadLabel = ({
|
|
185
|
+
label,
|
|
186
|
+
isUploaded,
|
|
187
|
+
handleDeleteUpload,
|
|
188
|
+
className,
|
|
189
|
+
}: {
|
|
190
|
+
label: string;
|
|
191
|
+
isUploaded: boolean;
|
|
192
|
+
handleDeleteUpload: () => void;
|
|
193
|
+
className?: string;
|
|
194
|
+
}) => {
|
|
195
|
+
return (
|
|
196
|
+
<div
|
|
197
|
+
className={cn(
|
|
198
|
+
"flex items-center justify-between gap-4 border border-border rounded-md py-1 pl-2 pr-1 bg-background/60 transition-all duration-300",
|
|
199
|
+
className,
|
|
200
|
+
)}
|
|
201
|
+
>
|
|
202
|
+
<div className="flex items-center gap-2">
|
|
203
|
+
{isUploaded && <Badge variant="success" display="icon-only" />}
|
|
204
|
+
<p className="text-sm font-medium">{label}</p>
|
|
205
|
+
</div>
|
|
206
|
+
<IconButton
|
|
207
|
+
name="Trash2"
|
|
208
|
+
size="sm"
|
|
209
|
+
onClick={handleDeleteUpload}
|
|
210
|
+
variant="danger"
|
|
211
|
+
disabled={!isUploaded}
|
|
212
|
+
></IconButton>
|
|
213
|
+
</div>
|
|
214
|
+
);
|
|
215
|
+
};
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
{
|
|
2
|
+
"display": {
|
|
3
|
+
"logo": "logos/eqty.svg"
|
|
4
|
+
},
|
|
5
|
+
"manifests": [
|
|
6
|
+
"amd-sev",
|
|
7
|
+
"anchors",
|
|
8
|
+
"association-no-metadata",
|
|
9
|
+
"association",
|
|
10
|
+
"B-200-merged",
|
|
11
|
+
"eqty-docker",
|
|
12
|
+
"governance",
|
|
13
|
+
"intel-tdx-with-nvidia",
|
|
14
|
+
"intel-tdx",
|
|
15
|
+
"iroh-collections",
|
|
16
|
+
"model-signing",
|
|
17
|
+
"multiple-registrations",
|
|
18
|
+
"no-vcs",
|
|
19
|
+
"storage",
|
|
20
|
+
"sub-graphs"
|
|
21
|
+
],
|
|
22
|
+
"nodeOverrides": {}
|
|
23
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import type { NodeConfig } from "@/explorer-component";
|
|
2
|
+
import { ExplorerConfig, buildNodeConfig } from "@/explorer-component";
|
|
3
|
+
|
|
4
|
+
import appConfigRaw from "./config.json";
|
|
5
|
+
const appConfig = appConfigRaw as JsonConfig;
|
|
6
|
+
|
|
7
|
+
export type JsonConfig = {
|
|
8
|
+
display: { logo: string };
|
|
9
|
+
manifests: string[];
|
|
10
|
+
nodeOverrides?: { [key: string]: Partial<NodeConfig> };
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
export type Config = ExplorerConfig & {
|
|
14
|
+
display: {
|
|
15
|
+
logo: string;
|
|
16
|
+
};
|
|
17
|
+
manifests: string[];
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
export function loadConfig(): Config {
|
|
21
|
+
const nodesConfig = buildNodeConfig(appConfig.nodeOverrides);
|
|
22
|
+
|
|
23
|
+
return {
|
|
24
|
+
...nodesConfig,
|
|
25
|
+
display: appConfig.display,
|
|
26
|
+
manifests: appConfig.manifests,
|
|
27
|
+
};
|
|
28
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { useSearchParams } from "react-router-dom";
|
|
2
|
+
|
|
3
|
+
import ManifestViewer from "@/app/components/manifestViewer/ManifestViewer.tsx";
|
|
4
|
+
import IntegrityService from "@/app/components/integrityService/IntegrityService.tsx";
|
|
5
|
+
import { getEnvVarAppMode, AppMode } from "@/app/utils/appMode.ts";
|
|
6
|
+
import { Auth0Provider } from "@auth0/auth0-react";
|
|
7
|
+
import { loadConfig } from "@/app/config";
|
|
8
|
+
|
|
9
|
+
const Component = () => {
|
|
10
|
+
const [searchParams] = useSearchParams();
|
|
11
|
+
|
|
12
|
+
const appMode = getEnvVarAppMode(searchParams.get("appmode"));
|
|
13
|
+
const config = loadConfig();
|
|
14
|
+
|
|
15
|
+
if (appMode === AppMode.INTEGRITY_SERVICE) {
|
|
16
|
+
return (
|
|
17
|
+
<Auth0Provider
|
|
18
|
+
domain={import.meta.env.VITE_AUTH0_DOMAIN}
|
|
19
|
+
clientId={import.meta.env.VITE_AUTH0_CLIENT_ID}
|
|
20
|
+
authorizationParams={{
|
|
21
|
+
redirect_uri: window.location.origin,
|
|
22
|
+
}}
|
|
23
|
+
useRefreshTokens={true}
|
|
24
|
+
cacheLocation="localstorage"
|
|
25
|
+
>
|
|
26
|
+
<IntegrityService searchParams={searchParams} config={config} />
|
|
27
|
+
</Auth0Provider>
|
|
28
|
+
);
|
|
29
|
+
} else {
|
|
30
|
+
return <ManifestViewer config={config} />;
|
|
31
|
+
}
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
export { Component };
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { create } from "zustand";
|
|
2
|
+
|
|
3
|
+
export type ManifestStore = {
|
|
4
|
+
manifest: any | null;
|
|
5
|
+
setManifest: (manifestJson: any) => void;
|
|
6
|
+
getManifest: () => any | null;
|
|
7
|
+
};
|
|
8
|
+
|
|
9
|
+
export const useManifestStore = create<ManifestStore>()((set, get) => ({
|
|
10
|
+
manifest: null,
|
|
11
|
+
setManifest: (manifestJson) => {
|
|
12
|
+
set({ manifest: manifestJson });
|
|
13
|
+
},
|
|
14
|
+
|
|
15
|
+
getManifest: () => {
|
|
16
|
+
const manifest = get().manifest;
|
|
17
|
+
return manifest;
|
|
18
|
+
},
|
|
19
|
+
}));
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
enum AppMode {
|
|
2
|
+
MANIFEST_VIEWER = "manifestviewer",
|
|
3
|
+
INTEGRITY_SERVICE = "integrityservice",
|
|
4
|
+
EMBEDDED_IFRAME = "iframe",
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
const appModeValues = Object.values(AppMode);
|
|
8
|
+
|
|
9
|
+
// Type guard to check if a string is a valid AppMode
|
|
10
|
+
const isAppMode = (value: string): value is AppMode => {
|
|
11
|
+
return appModeValues.includes(value as AppMode);
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
// Pass an appmode string to get the AppMode enum value, or use appmode env var
|
|
15
|
+
const getEnvVarAppMode = (urlAppMode: string | null): AppMode => {
|
|
16
|
+
if (urlAppMode) {
|
|
17
|
+
const appMode = strToAppMode(urlAppMode);
|
|
18
|
+
return appMode;
|
|
19
|
+
} else {
|
|
20
|
+
const appMode = strToAppMode(import.meta.env.VITE_APP_MODE);
|
|
21
|
+
return appMode;
|
|
22
|
+
}
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
const strToAppMode = (appMode: string | undefined): AppMode => {
|
|
26
|
+
if (!appMode) {
|
|
27
|
+
return AppMode.EMBEDDED_IFRAME;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
const appModeLower = appMode.toLowerCase();
|
|
31
|
+
|
|
32
|
+
const mode: AppMode = isAppMode(appModeLower) ? appModeLower : AppMode.MANIFEST_VIEWER;
|
|
33
|
+
|
|
34
|
+
return mode;
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
export { AppMode, getEnvVarAppMode };
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
<svg width="100" height="20" viewBox="0 0 100 20" fill="#0D0D0D" xmlns="http://www.w3.org/2000/svg">
|
|
2
|
+
<path d="M4.1556 11.8551H12.479V7.86308H4.1556V4.40998H13.0578V0.417969H0.00390625V19.9988H13.3572V15.9868H4.1556V11.8551Z" />
|
|
3
|
+
<path d="M58.8646 0.419162L54.4135 7.48503L49.9624 0.419162H31.4395V4.41118H37.188V15.9681H31.0802C31.3996 15.5689 31.6591 15.1497 31.8986 14.7106C32.6171 13.3134 32.9964 11.7166 32.9964 9.98004C32.9964 8.56287 32.7369 7.20559 32.2579 6.00798C31.7589 4.79042 31.0602 3.71258 30.182 2.83433C29.3038 1.93613 28.2459 1.23753 27.0283 0.738523C25.8307 0.239521 24.5133 0 23.1361 0C21.7589 0 20.4215 0.259481 19.2239 0.738523C18.0263 1.23753 16.9684 1.93613 16.0702 2.83433C15.192 3.73254 14.4934 4.79042 13.9944 6.00798C13.4954 7.22555 13.2559 8.56287 13.2559 9.98004C13.2559 11.3972 13.5153 12.7545 13.9944 13.9521C14.4934 15.1697 15.192 16.2475 16.0702 17.1258C16.9485 18.024 18.0064 18.7226 19.2239 19.2216C20.4215 19.7206 21.7389 19.9601 23.1361 19.9601H41.3397V4.39122H47.5074L52.3377 11.7166V19.9601H56.4894V11.7565L63.9345 0.419162H58.8646ZM28.2858 12.3154C28.0263 13.0339 27.667 13.6727 27.188 14.2116C26.709 14.7505 26.1301 15.1896 25.4515 15.509C24.7728 15.8283 23.9944 15.988 23.1161 15.988C22.2379 15.988 21.4395 15.8283 20.7608 15.509C20.0822 15.1896 19.4834 14.7505 19.0243 14.2116C18.5453 13.6727 18.166 13.0339 17.9265 12.3154C17.667 11.5768 17.5273 10.7984 17.5273 9.98004C17.5273 9.16168 17.667 8.38323 17.9265 7.64471C18.186 6.92615 18.5453 6.28743 19.0243 5.7485C19.5034 5.20958 20.0822 4.77046 20.7608 4.4511C21.4395 4.13174 22.2379 3.97206 23.1161 3.97206C23.9944 3.97206 24.7728 4.13174 25.4515 4.4511C26.1301 4.77046 26.7289 5.20958 27.188 5.7485C27.667 6.28743 28.0463 6.92615 28.2858 7.64471C28.5453 8.38323 28.685 9.16168 28.685 9.98004C28.685 10.7984 28.5453 11.5768 28.2858 12.3154Z" />
|
|
4
|
+
<path d="M78.687 1.61719L71.8406 17.3457H64.8546V1.61719H63.2578V18.8028H72.8985L74.8347 14.232H83.9365L85.8127 18.8028H87.6091L80.3836 1.61719H78.687ZM75.4534 12.7749L79.4654 3.35371L83.3576 12.7749H75.4534Z" />
|
|
5
|
+
<path d="M99.1846 12.3353C99.005 11.8363 98.7455 11.3972 98.3862 11.0379C98.0469 10.6786 97.6477 10.3792 97.1687 10.1597C96.6896 9.94011 96.1906 9.80039 95.6118 9.76047V9.72055C96.6298 9.50099 97.4082 9.08183 97.9072 8.44311C98.4262 7.80438 98.6856 7.02594 98.6856 6.16766C98.6856 5.18961 98.526 4.41117 98.1866 3.83233C97.8473 3.23353 97.4282 2.77444 96.9092 2.45508C96.3902 2.11576 95.7914 1.8962 95.1328 1.7964C94.4741 1.6966 93.8154 1.63672 93.1767 1.63672H88.2266V18.8223H93.7156C94.2944 18.8223 94.9331 18.7625 95.5918 18.6227C96.2705 18.503 96.8892 18.2435 97.4681 17.9042C98.0469 17.5449 98.526 17.0659 98.9052 16.4271C99.2844 15.8084 99.484 14.99 99.484 14.012C99.4641 13.3932 99.3643 12.8343 99.1846 12.3353ZM93.3763 3.07384C93.8753 3.07384 94.3543 3.11376 94.8134 3.21357C95.2725 3.31337 95.6717 3.47305 96.011 3.71257C96.3503 3.95209 96.6298 4.27145 96.8294 4.65069C97.029 5.04989 97.1288 5.54889 97.1288 6.1477C97.1288 6.42714 97.0888 6.72654 96.989 7.06586C96.8892 7.40518 96.6896 7.70458 96.4102 8.00398C96.1108 8.30338 95.7116 8.54291 95.1926 8.74251C94.6737 8.94211 93.995 9.04191 93.1767 9.04191H89.8433L89.8234 3.07384H93.3763ZM97.7076 15.0699C97.6078 15.4491 97.3882 15.8084 97.0888 16.1477C96.7894 16.487 96.3304 16.7665 95.7715 17.006C95.1926 17.2255 94.4341 17.3453 93.496 17.3453H89.8234V10.499H93.7355C94.2345 10.499 94.7335 10.5589 95.2326 10.6986C95.7316 10.8184 96.1707 11.0379 96.5499 11.3174C96.9292 11.5968 97.2485 11.976 97.488 12.4152C97.7276 12.8742 97.8473 13.4132 97.8473 14.0319C97.8673 14.3513 97.8074 14.6906 97.7076 15.0699Z" />
|
|
6
|
+
</svg>
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import ManifestButtons from "@/app/components/manifestViewer/components/ManifestButtons";
|
|
2
|
+
import EQTYLabLogo from "@/assets/vectors/eqtylab.svg";
|
|
3
|
+
import { DarkModeSwitch } from "@/components/dark-mode-switch";
|
|
4
|
+
import { Config } from "@/app/config";
|
|
5
|
+
import { UploadsMap, UploadValue, UploadKey } from "@/v-comp-viewer/utils";
|
|
6
|
+
|
|
7
|
+
interface AppHeaderProps {
|
|
8
|
+
config: Config;
|
|
9
|
+
useSampleManifest: (event: string) => void;
|
|
10
|
+
handleFileChange: (file: File) => void;
|
|
11
|
+
allowArtifactsUploads: boolean;
|
|
12
|
+
handleDetectedUploads: (detected: UploadValue[]) => void;
|
|
13
|
+
onFilesSelected: (files: FileList | null) => void;
|
|
14
|
+
uploads: UploadsMap;
|
|
15
|
+
hasManifest: boolean;
|
|
16
|
+
handleDeleteManifest: () => void;
|
|
17
|
+
handleDeleteUpload: (kind: Exclude<UploadKey, "manifest">) => void;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export function AppHeader({
|
|
21
|
+
config,
|
|
22
|
+
useSampleManifest,
|
|
23
|
+
handleFileChange,
|
|
24
|
+
allowArtifactsUploads,
|
|
25
|
+
handleDetectedUploads,
|
|
26
|
+
onFilesSelected,
|
|
27
|
+
uploads,
|
|
28
|
+
hasManifest,
|
|
29
|
+
handleDeleteManifest,
|
|
30
|
+
handleDeleteUpload,
|
|
31
|
+
}: AppHeaderProps) {
|
|
32
|
+
return (
|
|
33
|
+
<header className="w-full border-b border-border bg-background py-3.5 px-4 z-50">
|
|
34
|
+
<div className="flex w-full items-center justify-between">
|
|
35
|
+
<div className="flex items-center gap-3">
|
|
36
|
+
<div className="[&>svg]:h-auto [&>svg]:w-28 [&>svg]:fill-text-primary">
|
|
37
|
+
<EQTYLabLogo />
|
|
38
|
+
</div>
|
|
39
|
+
<div className="h-6 w-px bg-text-primary/20" />
|
|
40
|
+
<span className="text-lg text-brand-lineage-explorer">Lineage Explorer</span>
|
|
41
|
+
</div>
|
|
42
|
+
|
|
43
|
+
<div className="flex items-center gap-4">
|
|
44
|
+
<DarkModeSwitch />
|
|
45
|
+
<ManifestButtons
|
|
46
|
+
config={config}
|
|
47
|
+
handleSampleManifestSelected={useSampleManifest}
|
|
48
|
+
handleFileChange={handleFileChange}
|
|
49
|
+
allowArtifactsUploads={allowArtifactsUploads}
|
|
50
|
+
handleDetectedUploads={handleDetectedUploads}
|
|
51
|
+
onFilesSelected={onFilesSelected}
|
|
52
|
+
uploads={uploads}
|
|
53
|
+
hasManifest={hasManifest}
|
|
54
|
+
handleDeleteManifest={handleDeleteManifest}
|
|
55
|
+
handleDeleteUpload={handleDeleteUpload}
|
|
56
|
+
/>
|
|
57
|
+
</div>
|
|
58
|
+
</div>
|
|
59
|
+
</header>
|
|
60
|
+
);
|
|
61
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { Switch, useTheme } from "@eqtylab/equality";
|
|
2
|
+
import { Moon, Sun } from "lucide-react";
|
|
3
|
+
|
|
4
|
+
export function DarkModeSwitch() {
|
|
5
|
+
const [theme, setTheme] = useTheme();
|
|
6
|
+
const displayToggle = !!theme; // Only display the toggle once the theme has initialised, to avoid rendering incorrect state initially
|
|
7
|
+
|
|
8
|
+
return displayToggle ? (
|
|
9
|
+
<Switch
|
|
10
|
+
checked={theme === "dark"}
|
|
11
|
+
size="sm"
|
|
12
|
+
onCheckedChange={(checked) => setTheme(checked ? "dark" : "light")}
|
|
13
|
+
thumbIcon={theme === "dark" ? <Moon /> : <Sun />}
|
|
14
|
+
/>
|
|
15
|
+
) : null;
|
|
16
|
+
}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
import * as AccordionPrimitive from "@radix-ui/react-accordion";
|
|
3
|
+
import { ChevronDown } from "lucide-react";
|
|
4
|
+
import { cn } from "@/lib/utils";
|
|
5
|
+
|
|
6
|
+
interface AccordionTriggerProps extends React.ComponentPropsWithoutRef<typeof AccordionPrimitive.Trigger> {
|
|
7
|
+
children: React.ReactNode;
|
|
8
|
+
className?: string;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
const AccordionTrigger = React.forwardRef<HTMLButtonElement, AccordionTriggerProps>(
|
|
12
|
+
({ children, className, ...props }, forwardedRef) => (
|
|
13
|
+
<AccordionPrimitive.Header>
|
|
14
|
+
<AccordionPrimitive.Trigger
|
|
15
|
+
className={cn(
|
|
16
|
+
"flex gap-2 group items-center text-sm w-full data-[state=open]:[&_svg]:rotate-0 data-[state=closed]:[&_svg]:-rotate-90",
|
|
17
|
+
className,
|
|
18
|
+
)}
|
|
19
|
+
{...props}
|
|
20
|
+
ref={forwardedRef}
|
|
21
|
+
>
|
|
22
|
+
<div className="group-hover:bg-lilac-button rounded-md p-1 transition-all duration-300">
|
|
23
|
+
<ChevronDown aria-hidden className="size-4 transition-all duration-300" />
|
|
24
|
+
</div>
|
|
25
|
+
{children}
|
|
26
|
+
<div className="flex-1 h-px bg-border w-full ml-2" />
|
|
27
|
+
</AccordionPrimitive.Trigger>
|
|
28
|
+
</AccordionPrimitive.Header>
|
|
29
|
+
),
|
|
30
|
+
);
|
|
31
|
+
|
|
32
|
+
AccordionTrigger.displayName = AccordionPrimitive.Trigger.displayName;
|
|
33
|
+
|
|
34
|
+
interface AccordionContentProps extends React.ComponentPropsWithoutRef<typeof AccordionPrimitive.Content> {
|
|
35
|
+
children: React.ReactNode;
|
|
36
|
+
className?: string;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
const AccordionContent = React.forwardRef<HTMLDivElement, AccordionContentProps>(
|
|
40
|
+
({ children, className, ...props }, forwardedRef) => (
|
|
41
|
+
<AccordionPrimitive.Content className={cn("", className)} {...props} ref={forwardedRef}>
|
|
42
|
+
<div>{children}</div>
|
|
43
|
+
</AccordionPrimitive.Content>
|
|
44
|
+
),
|
|
45
|
+
);
|
|
46
|
+
|
|
47
|
+
export { AccordionPrimitive as Accordion, AccordionTrigger, AccordionContent };
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { SectionListWrapper, TwoColumnListItem } from "@/explorer-component/components/sidebar/SectionList";
|
|
2
|
+
import { formatInTimeZone } from "date-fns-tz";
|
|
3
|
+
|
|
4
|
+
const CerificateChain = ({ chainItems }: { chainItems: unknown[] }) => {
|
|
5
|
+
return (
|
|
6
|
+
<div className="space-y-4 my-4">
|
|
7
|
+
{chainItems.map((cert: unknown) => {
|
|
8
|
+
const c = cert as {
|
|
9
|
+
subject: { attributes: Array<{ shortName: string; value: string }> };
|
|
10
|
+
issuer: { attributes: Array<{ shortName: string; value: string }> };
|
|
11
|
+
validity: { notBefore: Date; notAfter: Date };
|
|
12
|
+
signature: string;
|
|
13
|
+
};
|
|
14
|
+
const subject = c.subject.attributes.map((attr) => `${attr.shortName}=${attr.value}`).join(", ");
|
|
15
|
+
const issuer = c.issuer.attributes.map((attr) => `${attr.shortName}=${attr.value}`).join(", ");
|
|
16
|
+
const validFrom = c.validity.notBefore.toISOString();
|
|
17
|
+
const validTo = c.validity.notAfter.toISOString();
|
|
18
|
+
|
|
19
|
+
const items = [
|
|
20
|
+
{
|
|
21
|
+
label: "Subject",
|
|
22
|
+
value: (
|
|
23
|
+
<div className="rounded-md border border-border bg-foreground/5 px-2 py-1">
|
|
24
|
+
<code className="whitespace-pre-wrap break-words text-xs">{subject}</code>
|
|
25
|
+
</div>
|
|
26
|
+
),
|
|
27
|
+
},
|
|
28
|
+
{
|
|
29
|
+
label: "Issuer",
|
|
30
|
+
value: (
|
|
31
|
+
<div className="rounded-md border border-border bg-foreground/5 px-2 py-1">
|
|
32
|
+
<code className="whitespace-pre-wrap break-words text-xs">{issuer}</code>
|
|
33
|
+
</div>
|
|
34
|
+
),
|
|
35
|
+
},
|
|
36
|
+
{
|
|
37
|
+
label: "Valid From",
|
|
38
|
+
value: <p>{formatInTimeZone(validFrom, "UTC", "HH:mm:ss MMMM d, yyyy")}</p>,
|
|
39
|
+
},
|
|
40
|
+
{
|
|
41
|
+
label: "Valid To",
|
|
42
|
+
value: <p>{formatInTimeZone(validTo, "UTC", "HH:mm:ss MMMM d, yyyy")}</p>,
|
|
43
|
+
},
|
|
44
|
+
];
|
|
45
|
+
|
|
46
|
+
return (
|
|
47
|
+
<div key={c.signature} className="border-b border-border pb-4 last:border-b-0">
|
|
48
|
+
<SectionListWrapper>
|
|
49
|
+
{items.map((item) => (
|
|
50
|
+
<TwoColumnListItem key={item.label} {...item} />
|
|
51
|
+
))}
|
|
52
|
+
</SectionListWrapper>
|
|
53
|
+
</div>
|
|
54
|
+
);
|
|
55
|
+
})}
|
|
56
|
+
</div>
|
|
57
|
+
);
|
|
58
|
+
};
|
|
59
|
+
|
|
60
|
+
export default CerificateChain;
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { CopyButton } from "@eqtylab/equality";
|
|
2
|
+
|
|
3
|
+
import { cn } from "@/lib/utils";
|
|
4
|
+
import { Validated } from "@/v-comp-viewer/utils";
|
|
5
|
+
import VerifyStateBadge, { VerificationStateType } from "./verify-state-badge";
|
|
6
|
+
|
|
7
|
+
interface CertificateCodeProps {
|
|
8
|
+
className?: string;
|
|
9
|
+
code: string;
|
|
10
|
+
validated?: Validated;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
const CertificateCode = ({ className, code, validated }: CertificateCodeProps) => {
|
|
14
|
+
const validatedState: Partial<Record<Validated, VerificationStateType>> = {
|
|
15
|
+
valid: "verified",
|
|
16
|
+
partial: "partial",
|
|
17
|
+
invalid: "unverified",
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
return (
|
|
21
|
+
<div className={cn("space-y-2", className)}>
|
|
22
|
+
<div className="grid grid-cols-[1fr_auto] justify-between">
|
|
23
|
+
{validated && (
|
|
24
|
+
<div>
|
|
25
|
+
<VerifyStateBadge state={validatedState[validated]!} displayText={true} />
|
|
26
|
+
</div>
|
|
27
|
+
)}
|
|
28
|
+
<CopyButton value={code} className="col-start-2" />
|
|
29
|
+
</div>
|
|
30
|
+
<div className="overflow-hidden rounded-md border border-border bg-foreground/5 p-2 text-xs">
|
|
31
|
+
<div className="styled-vertical-scrollbar max-h-24 overflow-y-auto">
|
|
32
|
+
<code className="whitespace-pre-wrap break-all">{code}</code>
|
|
33
|
+
</div>
|
|
34
|
+
</div>
|
|
35
|
+
</div>
|
|
36
|
+
);
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
export default CertificateCode;
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { Accordion, AccordionTrigger, AccordionContent } from "@/components/ui/accordion";
|
|
2
|
+
import { cn } from "@/lib/utils";
|
|
3
|
+
|
|
4
|
+
interface DetailsProps {
|
|
5
|
+
className?: string;
|
|
6
|
+
innerClassName?: string;
|
|
7
|
+
title: string;
|
|
8
|
+
content: React.ReactNode;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
const Details = ({ title, content, className, innerClassName }: DetailsProps) => (
|
|
12
|
+
<Accordion.Root type="single" collapsible className={className}>
|
|
13
|
+
<Accordion.Item value={title} className={cn("data-[state=open]:border-b border-border", innerClassName)}>
|
|
14
|
+
<AccordionTrigger className="font-medium text-sm">{title}</AccordionTrigger>
|
|
15
|
+
<AccordionContent>{content}</AccordionContent>
|
|
16
|
+
</Accordion.Item>
|
|
17
|
+
</Accordion.Root>
|
|
18
|
+
);
|
|
19
|
+
|
|
20
|
+
export default Details;
|