diff --git a/src/components/MetadataCards.tsx b/src/components/MetadataCards.tsx index e96facc2..c004e073 100644 --- a/src/components/MetadataCards.tsx +++ b/src/components/MetadataCards.tsx @@ -10,6 +10,7 @@ import { Codesnippet } from "./CodeSnippet"; import { CollapsibleCard } from "./CollapsibleCard"; import { KeyValue } from "./KeyValue"; import { NestedCollapsible } from "./NestedCollapsible"; +import { isUrl } from "../lib/url"; type Props = { metadata: MetadataMap }; @@ -18,7 +19,11 @@ export function MetadataCards({ metadata }: Props) { return ( <> {dictMetadata.map((metadataObj, idx) => ( - + } + title={Object.keys({ metadataObj })[0]} + /> ))} ); @@ -55,9 +60,21 @@ export function UncategorizedCard({ metadata, title }: Props & { title?: string {(() => { if (isString(value) && regex.test(value)) { return ; + } + if (isString(value) && isUrl(value)) { + return ( + + {value} + + ); } else { return ( -
+
{isString(value) ? value : JSON.stringify(value)}
); diff --git a/src/components/NestedCollapsible.tsx b/src/components/NestedCollapsible.tsx index 71c7fc56..d5ad0028 100644 --- a/src/components/NestedCollapsible.tsx +++ b/src/components/NestedCollapsible.tsx @@ -1,5 +1,5 @@ -/* eslint-disable @typescript-eslint/no-explicit-any */ -import { renderAnyToString } from "@/lib/strings"; +import { isArray, isObject, isString } from "@/lib/type-guards"; +import { isUrl } from "@/lib/url"; import { CollapsibleHeaderProps } from "@zenml-io/react-component-library"; import { Tooltip, @@ -14,7 +14,7 @@ import { KeyValue } from "./KeyValue"; type Props = { intent?: CollapsibleHeaderProps["intent"]; - data?: { [key: string]: any }; + data?: { [key: string]: unknown }; title: ReactNode; contentClassName?: string; className?: string; @@ -30,15 +30,15 @@ export function NestedCollapsible({ children, className }: PropsWithChildren) { - const objects: { [key: string]: any } = {}; - const nonObjects: { [key: string]: any } = {}; - const arrays: { [key: string]: any } = {}; + const objects: { [key: string]: Record } = {}; + const nonObjects: { [key: string]: unknown } = {}; + const arrays: { [key: string]: unknown[] } = {}; const regex = /^$/; for (const [key, value] of Object.entries(data || {})) { - if (typeof value === "object" && value !== null && !Array.isArray(value)) { - objects[key] = value; - } else if (Array.isArray(value)) { + if (isObject(value)) { + objects[key] = value as Record; + } else if (isArray(value)) { arrays[key] = value; } else { nonObjects[key] = value; @@ -74,14 +74,23 @@ export function NestedCollapsible({ } value={ <> - {typeof value === "boolean" ? ( -
{JSON.stringify(value)}
- ) : regex.test(value) ? ( + {isString(value) && regex.test(value) ? ( ) : value === null ? ( -
null
+
null
+ ) : isString(value) && isUrl(value) ? ( + + {value} + ) : ( -
{value}
+
+ {isString(value) ? value : JSON.stringify(value)} +
)} } @@ -101,13 +110,11 @@ export function NestedCollapsible({ ); } -function RenderArray({ title, value }: { title: string; value: any }) { - const simpleValues: any[] = value.filter( - (val: any) => (!Array.isArray(val) && typeof val !== "object") || val === null - ); - const nestedValues: any[] = value.filter( - (val: any) => Array.isArray(val) || typeof val === "object" +function RenderArray({ title, value }: { title: string; value: unknown[] }) { + const simpleValues: unknown[] = value.filter( + (val) => (!isArray(val) && !isObject(val)) || val === null ); + const nestedValues: unknown[] = value.filter((val) => isArray(val) || isObject); return ( <> @@ -125,16 +132,40 @@ function RenderArray({ title, value }: { title: string; value: any }) { } - value={
{renderAnyToString(value)}
} + value={ +
+ {value === null ? ( +
null
+ ) : isString(value) && isUrl(value) ? ( + + {value} + + ) : ( +
+ {isString(value) ? value : JSON.stringify(value)} +
+ )} +
+ } /> ))} )} {nestedValues.length > 0 && (
    - {nestedValues.map((val: any, index: number) => ( + {nestedValues.map((val, index: number) => (
  • - + | unknown[]>} + />
  • ))}
diff --git a/src/components/dag-visualizer/layout/real-data.ts b/src/components/dag-visualizer/layout/real-data.ts index f8783b8a..9c8e32b5 100644 --- a/src/components/dag-visualizer/layout/real-data.ts +++ b/src/components/dag-visualizer/layout/real-data.ts @@ -32,7 +32,7 @@ function extractNodes(stepConfig: StepDict) { id: version.id, placeholderId, type: "artifact", - data: { ...version, name: version.body?.artifact.name || outputName } + data: { ...version, name: outputName } }); }); }); diff --git a/src/lib/url.ts b/src/lib/url.ts index f06021af..ad139b2c 100644 --- a/src/lib/url.ts +++ b/src/lib/url.ts @@ -32,3 +32,7 @@ export function sanitizeUrl(url = "about:blank"): string { } export const urlSchema = z.string().url(); + +export function isUrl(probe: string) { + return urlSchema.safeParse(probe).success; +} diff --git a/src/types/pipeline-runs.ts b/src/types/pipeline-runs.ts index f0192e2b..e954d413 100644 --- a/src/types/pipeline-runs.ts +++ b/src/types/pipeline-runs.ts @@ -15,7 +15,6 @@ type ArtifactNodeDetails = ArtifactVersion & { name: string }; export type ArtifactNode = { id: string; placeholderId: string; - helperId?: string; type: "artifact"; data: ArtifactNodeDetails; }; @@ -23,7 +22,6 @@ export type ArtifactNode = { export type StepNode = { id: string; placeholderId: string; - helperId?: string; type: "step"; data: Step; };