change appearance of example tasks (#975)
This commit is contained in:
@@ -7,6 +7,7 @@ import { SampleCase, sampleCases } from "../types";
|
||||
import { CreateNewTaskForm } from "./CreateNewTaskForm";
|
||||
import { SavedTaskForm } from "./SavedTaskForm";
|
||||
import { TaskGenerationApiResponse, WorkflowParameter } from "@/api/types";
|
||||
import { Skeleton } from "@/components/ui/skeleton";
|
||||
|
||||
function CreateNewTaskFormPage() {
|
||||
const { template } = useParams();
|
||||
@@ -80,7 +81,16 @@ function CreateNewTaskFormPage() {
|
||||
}
|
||||
|
||||
if (isFetching) {
|
||||
return <div>Loading...</div>;
|
||||
return (
|
||||
<div className="space-y-4">
|
||||
<header>
|
||||
<h1 className="text-3xl">Edit Task Template</h1>
|
||||
</header>
|
||||
<Skeleton className="h-96" />
|
||||
<Skeleton className="h-20" />
|
||||
<Skeleton className="h-20" />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
const navigationPayload = data.workflow_definition.parameters.find(
|
||||
|
||||
@@ -10,11 +10,6 @@ import { AxiosError } from "axios";
|
||||
import { useState } from "react";
|
||||
import { useNavigate } from "react-router-dom";
|
||||
import { stringify as convertToYAML } from "yaml";
|
||||
import {
|
||||
ScrollArea,
|
||||
ScrollAreaViewport,
|
||||
ScrollBar,
|
||||
} from "@/components/ui/scroll-area";
|
||||
|
||||
function createTemplateTaskFromTaskGenerationParameters(
|
||||
values: TaskGenerationApiResponse,
|
||||
@@ -48,12 +43,47 @@ function createTemplateTaskFromTaskGenerationParameters(
|
||||
};
|
||||
}
|
||||
|
||||
const examplePrompts = [
|
||||
"What is the top post on hackernews?",
|
||||
"Navigate to Google Finance and search for AAPL",
|
||||
"What is the top NYT bestseller?",
|
||||
"What is the top ranked football team?",
|
||||
"Find the top selling electrical connector on finditparts",
|
||||
const exampleCases = [
|
||||
{
|
||||
key: "finditparts",
|
||||
label: "Find a product and add it to cart",
|
||||
},
|
||||
{
|
||||
key: "geico",
|
||||
label: "Geico - generate an insurance quote",
|
||||
},
|
||||
{
|
||||
key: "job_application",
|
||||
label: "Apply to a job",
|
||||
},
|
||||
{
|
||||
key: "california_edd",
|
||||
label: "California EDD",
|
||||
},
|
||||
{
|
||||
key: "contact_us_forms",
|
||||
label: "Fill a contact us form",
|
||||
},
|
||||
{
|
||||
key: "bci_seguros",
|
||||
label: "Generate an auto insurance quote",
|
||||
},
|
||||
{
|
||||
key: "hackernews",
|
||||
label: "Get the top post on Hackernews",
|
||||
},
|
||||
{
|
||||
key: "AAPLStockPrice",
|
||||
label: "Get the stock price of AAPL",
|
||||
},
|
||||
{
|
||||
key: "NYTBestseller",
|
||||
label: "Get the top NYT bestseller",
|
||||
},
|
||||
{
|
||||
key: "topRankedFootballTeam",
|
||||
label: "Get the top ranked football team",
|
||||
},
|
||||
];
|
||||
|
||||
function PromptBox() {
|
||||
@@ -150,26 +180,21 @@ function PromptBox() {
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<ScrollArea>
|
||||
<ScrollAreaViewport className="h-full w-full rounded-[inherit]">
|
||||
<div className="flex gap-4 rounded-sm bg-slate-elevation1 p-4">
|
||||
{examplePrompts.map((examplePrompt) => {
|
||||
return (
|
||||
<div
|
||||
key={examplePrompt}
|
||||
className="cursor-pointer whitespace-nowrap rounded-sm bg-slate-elevation3 px-4 py-3 hover:bg-slate-elevation5"
|
||||
onClick={() => {
|
||||
setPrompt(examplePrompt);
|
||||
}}
|
||||
>
|
||||
{examplePrompt}
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
</ScrollAreaViewport>
|
||||
<ScrollBar orientation="horizontal" />
|
||||
</ScrollArea>
|
||||
<div className="flex flex-wrap justify-center gap-4 rounded-sm bg-slate-elevation1 p-4">
|
||||
{exampleCases.map((example) => {
|
||||
return (
|
||||
<div
|
||||
key={example.key}
|
||||
className="cursor-pointer whitespace-nowrap rounded-sm bg-slate-elevation3 px-4 py-3 hover:bg-slate-elevation5"
|
||||
onClick={() => {
|
||||
navigate(`/create/${example.key}`);
|
||||
}}
|
||||
>
|
||||
{example.label}
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -17,6 +17,7 @@ import { stringify as convertToYAML } from "yaml";
|
||||
import { SavedTaskCard } from "./SavedTaskCard";
|
||||
import { useState } from "react";
|
||||
import { cn } from "@/util/utils";
|
||||
import { Skeleton } from "@/components/ui/skeleton";
|
||||
|
||||
function createEmptyTaskTemplate() {
|
||||
return {
|
||||
@@ -53,7 +54,9 @@ function SavedTasks() {
|
||||
const navigate = useNavigate();
|
||||
const [hovering, setHovering] = useState(false);
|
||||
|
||||
const { data } = useQuery<Array<WorkflowApiResponse>>({
|
||||
const { data, isLoading: savedTasksIsLoading } = useQuery<
|
||||
Array<WorkflowApiResponse>
|
||||
>({
|
||||
queryKey: ["savedTasks"],
|
||||
queryFn: async () => {
|
||||
const client = await getClient(credentialGetter);
|
||||
@@ -113,10 +116,8 @@ function SavedTasks() {
|
||||
"bg-slate-900": hovering,
|
||||
})}
|
||||
>
|
||||
<CardTitle className="font-normal">New Template</CardTitle>
|
||||
<CardDescription className="overflow-hidden text-ellipsis whitespace-nowrap text-slate-400">
|
||||
Create your own template
|
||||
</CardDescription>
|
||||
<CardTitle className="font-normal">New Task</CardTitle>
|
||||
<CardDescription>{"https://.."}</CardDescription>
|
||||
</CardHeader>
|
||||
<CardContent
|
||||
className={cn(
|
||||
@@ -138,6 +139,13 @@ function SavedTasks() {
|
||||
)}
|
||||
</CardContent>
|
||||
</Card>
|
||||
{savedTasksIsLoading && (
|
||||
<>
|
||||
<Skeleton className="h-56" />
|
||||
<Skeleton className="h-56" />
|
||||
<Skeleton className="h-56" />
|
||||
</>
|
||||
)}
|
||||
{data?.map((workflow) => {
|
||||
return (
|
||||
<SavedTaskCard
|
||||
|
||||
@@ -1,95 +1,12 @@
|
||||
import { useNavigate } from "react-router-dom";
|
||||
import { getSample } from "../data/sampleTaskData";
|
||||
import { SampleCase } from "../types";
|
||||
import { PromptBox } from "./PromptBox";
|
||||
import { SavedTasks } from "./SavedTasks";
|
||||
import { SwitchBar } from "@/components/SwitchBar";
|
||||
import { useState } from "react";
|
||||
import { TaskTemplateCard } from "./TaskTemplateCard";
|
||||
|
||||
const templateSamples: {
|
||||
[key in SampleCase]: {
|
||||
title: string;
|
||||
description: string;
|
||||
};
|
||||
} = {
|
||||
blank: {
|
||||
title: "Blank",
|
||||
description: "Create task from a blank template",
|
||||
},
|
||||
geico: {
|
||||
title: "Geico",
|
||||
description: "Generate an auto insurance quote",
|
||||
},
|
||||
finditparts: {
|
||||
title: "Finditparts",
|
||||
description: "Find a product and add it to cart",
|
||||
},
|
||||
california_edd: {
|
||||
title: "California EDD",
|
||||
description: "Fill the employer services online enrollment form",
|
||||
},
|
||||
bci_seguros: {
|
||||
title: "BCI Seguros",
|
||||
description: "Generate an auto insurance quote",
|
||||
},
|
||||
job_application: {
|
||||
title: "Job Application",
|
||||
description: "Fill a job application form",
|
||||
},
|
||||
contact_us_forms: {
|
||||
title: "Contact Us Forms",
|
||||
description: "Fill a contact us form on a random website",
|
||||
},
|
||||
};
|
||||
|
||||
const templateSwitchOptions = [
|
||||
{
|
||||
label: "Skyvern Templates",
|
||||
value: "skyvern",
|
||||
},
|
||||
{
|
||||
label: "My Templates",
|
||||
value: "user",
|
||||
},
|
||||
];
|
||||
|
||||
function TaskTemplates() {
|
||||
const navigate = useNavigate();
|
||||
const [templateSwitchValue, setTemplateSwitchValue] =
|
||||
useState<(typeof templateSwitchOptions)[number]["value"]>("skyvern");
|
||||
|
||||
return (
|
||||
<div className="space-y-8">
|
||||
<PromptBox />
|
||||
<section>
|
||||
<SwitchBar
|
||||
value={templateSwitchValue}
|
||||
onChange={setTemplateSwitchValue}
|
||||
options={templateSwitchOptions}
|
||||
/>
|
||||
</section>
|
||||
<section>
|
||||
{templateSwitchValue === "skyvern" ? (
|
||||
<div className="grid grid-cols-4 gap-4">
|
||||
{Object.entries(templateSamples).map(([sampleKey, sample]) => {
|
||||
return (
|
||||
<TaskTemplateCard
|
||||
key={sampleKey}
|
||||
title={sample.title}
|
||||
description={getSample(sampleKey as SampleCase).url}
|
||||
body={sample.description}
|
||||
onClick={() => {
|
||||
navigate(`/create/${sampleKey}`);
|
||||
}}
|
||||
/>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
) : (
|
||||
<SavedTasks />
|
||||
)}
|
||||
</section>
|
||||
<h2 className="text-3xl">My Tasks</h2>
|
||||
<SavedTasks />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -308,6 +308,61 @@ export const geico = {
|
||||
errorCodeMapping: null,
|
||||
};
|
||||
|
||||
export const hackernews = {
|
||||
url: "https://news.ycombinator.com",
|
||||
navigationGoal:
|
||||
"Navigate to the Hacker News homepage and identify the top post. COMPLETE when the title and URL of the top post are extracted. Ensure that the top post is the first post listed on the page.",
|
||||
dataExtractionGoal:
|
||||
"Extract the title and URL of the top post on the Hacker News homepage.",
|
||||
navigationPayload: null,
|
||||
extractedInformationSchema: null,
|
||||
webhookCallbackUrl: null,
|
||||
totpIdentifier: null,
|
||||
totpVerificationUrl: null,
|
||||
errorCodeMapping: null,
|
||||
};
|
||||
|
||||
export const AAPLStockPrice = {
|
||||
url: "https://www.google.com/finance",
|
||||
navigationGoal:
|
||||
"Navigate to the search bar on Google Finance, type 'AAPL', and press Enter. COMPLETE when the search results for AAPL are displayed and the stock price is extracted.",
|
||||
dataExtractionGoal: "Extract the stock price for AAPL",
|
||||
navigationPayload: null,
|
||||
extractedInformationSchema: null,
|
||||
webhookCallbackUrl: null,
|
||||
totpIdentifier: null,
|
||||
totpVerificationUrl: null,
|
||||
errorCodeMapping: null,
|
||||
};
|
||||
|
||||
export const NYTBestseller = {
|
||||
url: "https://www.nytimes.com/books/best-sellers",
|
||||
navigationGoal:
|
||||
"Navigate to the NYT Bestsellers page and identify the top book listed. COMPLETE when the title and author of the top book are identified.",
|
||||
dataExtractionGoal:
|
||||
"Extract the title, author, and rating of the top NYT Bestseller from the page.",
|
||||
navigationPayload: null,
|
||||
extractedInformationSchema: null,
|
||||
webhookCallbackUrl: null,
|
||||
totpIdentifier: null,
|
||||
totpVerificationUrl: null,
|
||||
errorCodeMapping: null,
|
||||
};
|
||||
|
||||
export const topRankedFootballTeam = {
|
||||
url: "https://www.fifa.com/fifa-world-ranking/",
|
||||
navigationGoal:
|
||||
"Navigate to the FIFA World Ranking page and identify the top ranked football team. COMPLETE when the name of the top ranked football team is found and displayed.",
|
||||
dataExtractionGoal:
|
||||
"Extract the name of the top ranked football team from the FIFA World Ranking page.",
|
||||
navigationPayload: null,
|
||||
extractedInformationSchema: null,
|
||||
webhookCallbackUrl: null,
|
||||
totpIdentifier: null,
|
||||
totpVerificationUrl: null,
|
||||
errorCodeMapping: null,
|
||||
};
|
||||
|
||||
export function getSample(sample: SampleCase) {
|
||||
switch (sample) {
|
||||
case "geico": {
|
||||
@@ -338,6 +393,18 @@ export function getSample(sample: SampleCase) {
|
||||
},
|
||||
};
|
||||
}
|
||||
case "hackernews": {
|
||||
return hackernews;
|
||||
}
|
||||
case "AAPLStockPrice": {
|
||||
return AAPLStockPrice;
|
||||
}
|
||||
case "NYTBestseller": {
|
||||
return NYTBestseller;
|
||||
}
|
||||
case "topRankedFootballTeam": {
|
||||
return topRankedFootballTeam;
|
||||
}
|
||||
case "blank": {
|
||||
return blank;
|
||||
}
|
||||
|
||||
@@ -8,6 +8,10 @@ export const sampleCases = [
|
||||
"bci_seguros",
|
||||
"job_application",
|
||||
"contact_us_forms",
|
||||
"hackernews",
|
||||
"AAPLStockPrice",
|
||||
"NYTBestseller",
|
||||
"topRankedFootballTeam",
|
||||
] as const;
|
||||
|
||||
export type SampleCase = (typeof sampleCases)[number];
|
||||
|
||||
Reference in New Issue
Block a user