Skip to content

Commit 05f8f61

Browse files
authored
Cleanup PipelineDetails (#1468)
## Description <!-- Please provide a brief description of the changes made in this pull request. Include any relevant context or reasoning for the changes. --> Move PipelineDetails onto UI Primitives and ContextPanel Blocks for closer visual consistency with TaskDetails. As part of this, files were moved to a new `Context` folder. Additionally, a new `PipelineIO` component was added, which is very similar to the existing `ArtifactsList` but slightly different in how it handles data (and uses new Block components). As such, for this PR only the `ArtifactsList` and `PipelineIO` components live side-by-side in the directory. One is consumed by PipelineDetails, the other by RunDetails. `ArtifactsList` is then removed completely when RunDetails is migrated and cleaned up in the next PR. Most of the visual aspects of `ArtifactsList` are included in `PipelineIO`. **A note on Duplicate Efforts:** There was no intent to create a duplicate artifact/IO list. `PipelineIO` was created before `ArtifactsList` came into being and when I compared the two to see the similarities I decided to adopt the UI of `ArtifactsList` into the functionality/structure of `PipelineIO`. This PR also fixes some text overflow bugs in the artifact list. ## Related Issue and Pull requests <!-- Link to any related issues using the format #<issue-number> --> Shopify/oasis-frontend#401 ## Type of Change <!-- Please delete options that are not relevant --> - [x] Cleanup/Refactor ## Checklist <!-- Please ensure the following are completed before submitting the PR --> - [ ] I have tested this does not break current pipelines / runs functionality - [ ] I have tested the changes on staging ## Screenshots (if applicable) | Before | After | | --- | --- | | ![image.png](https://app.graphite.com/user-attachments/assets/28552f71-fd75-4e99-863f-9e52255774c8.png) | ![image.png](https://app.graphite.com/user-attachments/assets/e69c1a6e-f956-4f8d-97a2-2f2219d42456.png) | ## Test Instructions <!-- Detail steps and prerequisites for testing the changes in this PR --> No change to app functionality. UI update only. Confirm that the interface works and shows info as expected. ## Additional Comments <!-- Add any additional context or information that reviewers might need to know regarding this PR -->
1 parent 41e0814 commit 05f8f61

File tree

7 files changed

+309
-286
lines changed

7 files changed

+309
-286
lines changed
Lines changed: 140 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,140 @@
1+
import { useEffect, useState } from "react";
2+
3+
import { useValidationIssueNavigation } from "@/components/Editor/hooks/useValidationIssueNavigation";
4+
import { ActionBlock } from "@/components/shared/ContextPanel/Blocks/ActionBlock";
5+
import { ContentBlock } from "@/components/shared/ContextPanel/Blocks/ContentBlock";
6+
import { ListBlock } from "@/components/shared/ContextPanel/Blocks/ListBlock";
7+
import { TextBlock } from "@/components/shared/ContextPanel/Blocks/TextBlock";
8+
import { CopyText } from "@/components/shared/CopyText/CopyText";
9+
import { TaskImplementation } from "@/components/shared/TaskDetails";
10+
import { BlockStack } from "@/components/ui/layout";
11+
import useToastNotification from "@/hooks/useToastNotification";
12+
import { useComponentSpec } from "@/providers/ComponentSpecProvider";
13+
import { getComponentFileFromList } from "@/utils/componentStore";
14+
import { USER_PIPELINES_LIST_NAME } from "@/utils/constants";
15+
16+
import PipelineIO from "../../shared/ArtifactsList/PipelineIO";
17+
import { PipelineValidationList } from "./PipelineValidationList";
18+
import RenamePipeline from "./RenamePipeline";
19+
20+
const PipelineDetails = () => {
21+
const notify = useToastNotification();
22+
const {
23+
componentSpec,
24+
digest,
25+
isComponentTreeValid,
26+
globalValidationIssues,
27+
} = useComponentSpec();
28+
29+
const { handleIssueClick, groupedIssues } = useValidationIssueNavigation(
30+
globalValidationIssues,
31+
);
32+
33+
// State for file metadata
34+
const [fileMeta, setFileMeta] = useState<{
35+
creationTime?: Date;
36+
modificationTime?: Date;
37+
createdBy?: string;
38+
}>({});
39+
40+
// Fetch file metadata on mount or when componentSpec.name changes
41+
useEffect(() => {
42+
const fetchMeta = async () => {
43+
if (!componentSpec.name) return;
44+
45+
try {
46+
const file = await getComponentFileFromList(
47+
USER_PIPELINES_LIST_NAME,
48+
componentSpec.name,
49+
);
50+
if (file) {
51+
setFileMeta({
52+
creationTime: file.creationTime,
53+
modificationTime: file.modificationTime,
54+
createdBy: file.componentRef.spec.metadata?.annotations?.author,
55+
});
56+
}
57+
} catch (error) {
58+
const message = error instanceof Error ? error.message : String(error);
59+
notify("Failed to fetch file metadata: " + message, "error");
60+
}
61+
};
62+
fetchMeta();
63+
}, [componentSpec.name]);
64+
65+
const metadata = [
66+
{
67+
label: "Created by",
68+
value: fileMeta.createdBy,
69+
},
70+
{
71+
label: "Created at",
72+
value: fileMeta.creationTime?.toLocaleString(),
73+
},
74+
{
75+
label: "Last updated",
76+
value: fileMeta.modificationTime?.toLocaleString(),
77+
},
78+
];
79+
80+
const annotations = Object.entries(
81+
componentSpec.metadata?.annotations || {},
82+
).map(([key, value]) => ({ label: key, value: String(value) }));
83+
84+
const actions = [
85+
<RenamePipeline key="rename-pipeline-action" />,
86+
<TaskImplementation
87+
key="pipeline-implementation-action"
88+
displayName={componentSpec.name ?? "Pipeline"}
89+
componentSpec={componentSpec}
90+
showInlineContent={false}
91+
/>,
92+
];
93+
94+
return (
95+
<BlockStack
96+
gap="4"
97+
className="h-full px-2"
98+
data-context-panel="pipeline-details"
99+
>
100+
<CopyText className="text-lg font-semibold">
101+
{componentSpec.name ?? "Unnamed Pipeline"}
102+
</CopyText>
103+
104+
<ActionBlock actions={actions} />
105+
106+
<ListBlock items={metadata} marker="none" />
107+
108+
{componentSpec.description && (
109+
<TextBlock title="Description" text={componentSpec.description} />
110+
)}
111+
112+
{digest && (
113+
<TextBlock
114+
title="Digest"
115+
text={digest}
116+
copyable
117+
className="bg-secondary p-2 rounded-md border"
118+
mono
119+
/>
120+
)}
121+
122+
{annotations.length > 0 && (
123+
<ListBlock title="Annotations" items={annotations} marker="none" />
124+
)}
125+
126+
<PipelineIO />
127+
128+
<ContentBlock title="Validations">
129+
<PipelineValidationList
130+
isComponentTreeValid={isComponentTreeValid}
131+
groupedIssues={groupedIssues}
132+
totalIssueCount={globalValidationIssues.length}
133+
onIssueSelect={handleIssueClick}
134+
/>
135+
</ContentBlock>
136+
</BlockStack>
137+
);
138+
};
139+
140+
export default PipelineDetails;

src/components/Editor/components/PipelineValidationList/PipelineValidationList.tsx renamed to src/components/Editor/Context/PipelineValidationList.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ import { cn } from "@/lib/utils";
2020
import { pluralize } from "@/utils/string";
2121
import type { ComponentValidationIssue } from "@/utils/validations";
2222

23-
import type { ValidationIssueGroup } from "../../hooks/useValidationIssueNavigation";
23+
import type { ValidationIssueGroup } from "../hooks/useValidationIssueNavigation";
2424

2525
interface PipelineValidationListProps {
2626
isComponentTreeValid: boolean;
@@ -75,13 +75,13 @@ export const PipelineValidationList = ({
7575
title={`${totalIssueCount} ${pluralize(totalIssueCount, "issue")} detected`}
7676
>
7777
<Paragraph size="sm" className="mb-4">
78-
{" "}
7978
Select an item to jump to its location in the pipeline.
8079
</Paragraph>
8180

8281
<BlockStack gap="2">
8382
{groupedIssues.map((group) => {
8483
const isOpen = openGroups.has(group.pathKey);
84+
8585
return (
8686
<Collapsible
8787
key={group.pathKey}

src/components/Editor/RenamePipeline.tsx renamed to src/components/Editor/Context/RenamePipeline.tsx

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,13 @@ import { useLocation, useNavigate } from "@tanstack/react-router";
22
import { Edit3 } from "lucide-react";
33

44
import TooltipButton from "@/components/shared/Buttons/TooltipButton";
5+
import { PipelineNameDialog } from "@/components/shared/Dialogs";
56
import useToastNotification from "@/hooks/useToastNotification";
67
import { useComponentSpec } from "@/providers/ComponentSpecProvider";
78
import { APP_ROUTES } from "@/routes/router";
89
import { renameComponentFileInList } from "@/utils/componentStore";
910
import { USER_PIPELINES_LIST_NAME } from "@/utils/constants";
1011

11-
import { PipelineNameDialog } from "../shared/Dialogs";
12-
1312
const RenamePipeline = () => {
1413
const { componentSpec, saveComponentSpec } = useComponentSpec();
1514
const notify = useToastNotification();

0 commit comments

Comments
 (0)