Skip to content

Commit e06eeee

Browse files
authored
quick-start page (#1117)
## Description Closes #966 Closes Shopify/oasis-frontend#317 Adds Quick Start page with example pipelines. <!-- Please provide a brief description of the changes made in this pull request. Include any relevant context or reasoning for the changes. --> ## Demo <!-- Link to any related issues using the format #<issue-number> --> ## [Screen Recording 2025-10-20 at 4.31.44 PM.mov <span class="graphite__hidden">(uploaded via Graphite)</span> <img class="graphite__hidden" src="https://app.graphite.dev/user-attachments/thumbnails/f8a4db9c-b27a-49f4-89d1-01a7f00e020c.mov" />](https://app.graphite.dev/user-attachments/video/f8a4db9c-b27a-49f4-89d1-01a7f00e020c.mov) ## Type of Change <!-- Please delete options that are not relevant --> - [ ] Bug fix - [x] New feature - [ ] Improvement - [ ] Cleanup/Refactor - [ ] Breaking change - [ ] Documentation update ## Checklist <!-- Please ensure the following are completed before submitting the PR --> - [x] I have tested this does not break current pipelines / runs functionality - [ ] I have tested the changes on staging <!-- Include any screenshots that might help explain the changes or provide visual context --> ## Test Instructions 1. Open "Quick start" page to get to the example pipelines <!-- Detail steps and prerequisites for testing the changes in this PR --> ## Additional Comments Future of the "Quick Start" page could be AI assisted start.
1 parent e014654 commit e06eeee

15 files changed

+4052
-4
lines changed
282 KB
Loading

public/example-pipelines/Pytorch pipeline.pipeline.component.yaml

Lines changed: 608 additions & 0 deletions
Large diffs are not rendered by default.
323 KB
Loading

public/example-pipelines/Tfx pipeline.pipeline.component.yaml

Lines changed: 1274 additions & 0 deletions
Large diffs are not rendered by default.
303 KB
Loading

public/example-pipelines/Vertex AI AutoML Tables pipeline.pipeline.component.yaml

Lines changed: 1288 additions & 0 deletions
Large diffs are not rendered by default.
261 KB
Loading

public/example-pipelines/XGBoost pipeline.pipeline.component.yaml

Lines changed: 634 additions & 0 deletions
Large diffs are not rendered by default.

src/components/Home/PipelineSection/PipelineSection.tsx

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { type ChangeEvent, useCallback, useEffect, useState } from "react";
22

33
import NewPipelineButton from "@/components/shared/NewPipelineButton";
4+
import QuickStartCards from "@/components/shared/QuickStart/QuickStartCards";
45
import { withSuspenseWrapper } from "@/components/shared/SuspenseWrapper";
56
import { Alert, AlertDescription, AlertTitle } from "@/components/ui/alert";
67
import { Button } from "@/components/ui/button";
@@ -18,7 +19,7 @@ import {
1819
TableHeader,
1920
TableRow,
2021
} from "@/components/ui/table";
21-
import { Paragraph } from "@/components/ui/typography";
22+
import { Paragraph, Text } from "@/components/ui/typography";
2223
import {
2324
type ComponentFileEntry,
2425
getAllComponentFilesFromList,
@@ -140,9 +141,19 @@ export const PipelineSection = withSuspenseWrapper(() => {
140141

141142
if (pipelines.size === 0) {
142143
return (
143-
<BlockStack gap="2" align="center" className="mt-4">
144-
<Paragraph>No pipelines found.</Paragraph>
145-
<NewPipelineButton />
144+
<BlockStack gap="4" align="center">
145+
<BlockStack gap="2">
146+
<Paragraph size="md" tone="subdued">
147+
You don&apos;t have any pipelines yet. Get started with a template
148+
below.
149+
</Paragraph>
150+
151+
<QuickStartCards />
152+
</BlockStack>
153+
<BlockStack align="center" gap="2">
154+
<Text tone="subdued">Or start from scratch with</Text>
155+
<NewPipelineButton />
156+
</BlockStack>
146157
</BlockStack>
147158
);
148159
}
Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
import { useMutation } from "@tanstack/react-query";
2+
import { useNavigate } from "@tanstack/react-router";
3+
4+
import { InfoBox } from "@/components/shared/InfoBox";
5+
import { Badge } from "@/components/ui/badge";
6+
import {
7+
Card,
8+
CardContent,
9+
CardDescription,
10+
CardHeader,
11+
CardTitle,
12+
} from "@/components/ui/card";
13+
import { BlockStack, InlineStack } from "@/components/ui/layout";
14+
import { Spinner } from "@/components/ui/spinner";
15+
import { Paragraph } from "@/components/ui/typography";
16+
import useToastNotification from "@/hooks/useToastNotification";
17+
import { cn } from "@/lib/utils";
18+
import { EDITOR_PATH } from "@/routes/router";
19+
20+
import { importPipelineFromUrl } from "./importPipelineFromUrl";
21+
import { type SamplePipeline, samplePipelines } from "./samplePipelines";
22+
23+
const QuickStartCards = () => {
24+
const navigate = useNavigate();
25+
const notify = useToastNotification();
26+
27+
const {
28+
mutate: importPipeline,
29+
isPending,
30+
error,
31+
} = useMutation({
32+
mutationFn: async (url: string) => await importPipelineFromUrl(url),
33+
onSuccess: (result) => {
34+
notify(`Pipeline "${result.name}" created successfully`, "success");
35+
navigate({
36+
to: `${EDITOR_PATH}/${encodeURIComponent(result.name)}`,
37+
});
38+
},
39+
});
40+
41+
return (
42+
<BlockStack>
43+
{!!error && (
44+
<InfoBox title="Error importing pipeline" variant="error">
45+
<Paragraph>{error.message}</Paragraph>
46+
</InfoBox>
47+
)}
48+
49+
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 gap-6">
50+
{samplePipelines.map((pipeline: SamplePipeline) => (
51+
<Card
52+
key={pipeline.name}
53+
className={cn(
54+
"overflow-hidden hover:shadow-lg transition-shadow duration-200 cursor-pointer group",
55+
isPending && "opacity-50 pointer-events-none",
56+
)}
57+
onClick={() => importPipeline(pipeline.url)}
58+
>
59+
<div className="aspect-video relative bg-gradient-to-br from-gray-100 to-gray-200 overflow-hidden relative">
60+
<img
61+
src={pipeline.previewImage}
62+
alt={pipeline.name}
63+
className="w-full h-full object-cover group-hover:scale-105 transition-transform duration-200"
64+
onError={(e) => {
65+
// If image fails to load, hide it and show fallback gradient
66+
e.currentTarget.style.display = "none";
67+
}}
68+
/>
69+
{isPending && (
70+
<div className="absolute inset-0 flex items-center justify-center">
71+
<Spinner size={20} />
72+
</div>
73+
)}
74+
</div>
75+
<CardHeader>
76+
<CardTitle className="text-lg line-clamp-2">
77+
{pipeline.name}
78+
</CardTitle>
79+
<CardDescription className="line-clamp-3">
80+
{pipeline.description}
81+
</CardDescription>
82+
</CardHeader>
83+
<CardContent>
84+
{pipeline.tags && pipeline.tags.length > 0 && (
85+
<InlineStack
86+
gap="1"
87+
wrap="wrap"
88+
blockAlign="start"
89+
align="start"
90+
>
91+
{pipeline.tags.map((tag: string) => (
92+
<Badge size="sm" key={tag}>
93+
{tag}
94+
</Badge>
95+
))}
96+
</InlineStack>
97+
)}
98+
</CardContent>
99+
</Card>
100+
))}
101+
</div>
102+
103+
{samplePipelines.length === 0 && (
104+
<InfoBox title="No sample pipelines available yet." variant="info">
105+
<Paragraph>No sample pipelines available yet.</Paragraph>
106+
</InfoBox>
107+
)}
108+
</BlockStack>
109+
);
110+
};
111+
112+
export default QuickStartCards;

0 commit comments

Comments
 (0)