Skip to content

Commit 0cd9ffa

Browse files
committed
Extract common elements across the standard and scheduled test task forms
1 parent 59e95a9 commit 0cd9ffa

File tree

2 files changed

+121
-110
lines changed

2 files changed

+121
-110
lines changed

apps/webapp/app/presenters/v3/TestTaskPresenter.server.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -137,7 +137,7 @@ export class TestTaskPresenter {
137137
id: task.queueId,
138138
},
139139
select: {
140-
id: true,
140+
friendlyId: true,
141141
name: true,
142142
type: true,
143143
paused: true,
@@ -221,7 +221,7 @@ export class TestTaskPresenter {
221221
triggerSource: "STANDARD",
222222
queue: taskQueue
223223
? {
224-
id: taskQueue.id,
224+
id: taskQueue.friendlyId,
225225
name: taskQueue.name.replace(/^task\//, ""),
226226
type: queueTypeFromType(taskQueue.type),
227227
paused: taskQueue.paused,

apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.test.tasks.$taskParam/route.tsx

Lines changed: 119 additions & 108 deletions
Original file line numberDiff line numberDiff line change
@@ -170,12 +170,38 @@ export default function Page() {
170170
return <div></div>;
171171
}
172172

173+
const params = useParams();
174+
const queueFetcher = useFetcher<typeof queuesLoader>();
175+
176+
useEffect(() => {
177+
if (params.organizationSlug && params.projectParam && params.envParam) {
178+
const searchParams = new URLSearchParams();
179+
searchParams.set("type", "custom");
180+
searchParams.set("per_page", "100");
181+
182+
queueFetcher.load(
183+
`/resources/orgs/${params.organizationSlug}/projects/${params.projectParam}/env/${
184+
params.envParam
185+
}/queues?${searchParams.toString()}`
186+
);
187+
}
188+
}, [params.organizationSlug, params.projectParam, params.envParam]);
189+
190+
const defaultTaskQueue = result.task.queue;
191+
const queues = useMemo(() => {
192+
const customQueues = queueFetcher.data?.queues ?? [];
193+
194+
return defaultTaskQueue && !customQueues.some((q) => q.id === defaultTaskQueue.id)
195+
? [defaultTaskQueue, ...customQueues]
196+
: customQueues;
197+
}, [queueFetcher.data?.queues, defaultTaskQueue]);
198+
173199
switch (result.task.triggerSource) {
174200
case "STANDARD": {
175201
return (
176202
<StandardTaskForm
177203
task={result.task.task}
178-
defaultQueue={result.task.queue}
204+
queues={queues}
179205
runs={result.task.runs}
180206
versions={result.task.latestVersions}
181207
disableVersionSelection={result.disableVersionSelection}
@@ -193,6 +219,9 @@ export default function Page() {
193219
/>
194220
);
195221
}
222+
default: {
223+
return result.task satisfies never;
224+
}
196225
}
197226
}
198227

@@ -209,14 +238,14 @@ const machinePresets = [
209238

210239
function StandardTaskForm({
211240
task,
212-
defaultQueue,
241+
queues,
213242
runs,
214243
versions,
215244
disableVersionSelection,
216245
allowArbitraryQueues,
217246
}: {
218247
task: TestTask["task"];
219-
defaultQueue: TestTask["queue"];
248+
queues: Required<TestTask>["queue"][];
220249
runs: StandardRun[];
221250
versions: string[];
222251
disableVersionSelection: boolean;
@@ -225,7 +254,6 @@ function StandardTaskForm({
225254
const environment = useEnvironment();
226255
const { value, replace } = useSearchParams();
227256
const tab = value("tab");
228-
const params = useParams();
229257

230258
//form submission
231259
const lastSubmission = useActionData();
@@ -270,50 +298,14 @@ function StandardTaskForm({
270298
);
271299
const [tagsValue, setTagsValue] = useState<string[]>(selectedCodeSample?.runTags ?? []);
272300

273-
const queueFetcher = useFetcher<typeof queuesLoader>();
274-
275-
useEffect(() => {
276-
if (params.organizationSlug && params.projectParam && params.envParam) {
277-
const searchParams = new URLSearchParams();
278-
searchParams.set("type", "custom");
279-
searchParams.set("per_page", "100");
280-
281-
queueFetcher.load(
282-
`/resources/orgs/${params.organizationSlug}/projects/${params.projectParam}/env/${
283-
params.envParam
284-
}/queues?${searchParams.toString()}`
285-
);
286-
}
287-
}, [params.organizationSlug, params.projectParam, params.envParam]);
288-
289-
const queues = useMemo(() => {
290-
const defaultQueueItem = defaultQueue
291-
? {
292-
value: defaultQueue.type === "task" ? `task/${defaultQueue.name}` : defaultQueue.name,
293-
label: defaultQueue.name,
294-
type: defaultQueue.type,
295-
paused: defaultQueue.paused,
296-
}
297-
: undefined;
298-
299-
if (!queueFetcher.data?.queues) {
300-
return defaultQueueItem ? [defaultQueueItem] : [];
301-
}
302-
303-
const customQueues = queueFetcher.data?.queues.map((queue) => ({
304-
value: queue.name,
305-
label: queue.name,
306-
type: queue.type,
307-
paused: queue.paused,
308-
}));
309-
310-
return defaultQueueItem && !customQueues.some((q) => q.value === defaultQueueItem.value)
311-
? [defaultQueueItem, ...customQueues]
312-
: customQueues;
313-
}, [queueFetcher.data?.queues, defaultQueue]);
301+
const queueItems = queues.map((q) => ({
302+
value: q.type === "task" ? `task/${q.name}` : q.name,
303+
label: q.name,
304+
type: q.type,
305+
paused: q.paused,
306+
}));
314307

315308
const fetcher = useFetcher();
316-
const [isRecentRunsPopoverOpen, setIsRecentRunsPopoverOpen] = useState(false);
317309
const [
318310
form,
319311
{
@@ -379,67 +371,21 @@ function StandardTaskForm({
379371
</TabButton>
380372
</div>
381373
<div className="flex items-center gap-3">
382-
<Popover open={isRecentRunsPopoverOpen} onOpenChange={setIsRecentRunsPopoverOpen}>
383-
<PopoverTrigger asChild>
384-
{runs.length === 0 ? (
385-
<SimpleTooltip
386-
button={
387-
<Button
388-
type="button"
389-
variant="tertiary/small"
390-
LeadingIcon={ClockIcon}
391-
disabled={true}
392-
>
393-
Recent runs
394-
</Button>
395-
}
396-
content="No runs yet"
397-
/>
398-
) : (
399-
<Button type="button" variant="tertiary/small" LeadingIcon={ClockIcon}>
400-
Recent runs
401-
</Button>
402-
)}
403-
</PopoverTrigger>
404-
<PopoverContent className="min-w-[279px] p-0" align="end" sideOffset={6}>
405-
<div className="max-h-80 overflow-y-auto">
406-
<div className="p-1">
407-
{runs.map((run) => (
408-
<button
409-
key={run.id}
410-
type="button"
411-
onClick={() => {
412-
setPayload(run.payload);
413-
run.seedMetadata && setMetadata(run.seedMetadata);
414-
setSelectedCodeSampleId(run.id);
415-
setIsRecentRunsPopoverOpen(false);
416-
setTtlValue(run.ttlSeconds);
417-
setConcurrencyKeyValue(run.concurrencyKey);
418-
setMaxAttemptsValue(run.maxAttempts);
419-
setMaxDurationValue(run.maxDurationInSeconds);
420-
setTagsValue(run.runTags ?? []);
421-
setQueueValue(run.queue);
422-
setMachineValue(run.machinePreset);
423-
}}
424-
className="flex w-full items-center gap-2 rounded-sm px-2 py-2 outline-none transition-colors focus-custom hover:bg-charcoal-900 "
425-
>
426-
<div className="flex flex-col items-start">
427-
<Paragraph variant="small">
428-
<DateTime date={run.createdAt} showTooltip={false} />
429-
</Paragraph>
430-
<div className="flex items-center gap-2 text-xs text-text-dimmed">
431-
<div>
432-
Run <span className="font-mono">{run.friendlyId.slice(-8)}</span>
433-
</div>
434-
<TaskRunStatusCombo status={run.status} />
435-
</div>
436-
</div>
437-
</button>
438-
))}
439-
</div>
440-
</div>
441-
</PopoverContent>
442-
</Popover>
374+
<RecentRunsPopover
375+
runs={runs}
376+
onRunSelected={(run) => {
377+
setPayload(run.payload);
378+
run.seedMetadata && setMetadata(run.seedMetadata);
379+
setSelectedCodeSampleId(run.id);
380+
setTtlValue(run.ttlSeconds);
381+
setConcurrencyKeyValue(run.concurrencyKey);
382+
setMaxAttemptsValue(run.maxAttempts);
383+
setMaxDurationValue(run.maxDurationInSeconds);
384+
setTagsValue(run.runTags ?? []);
385+
setQueueValue(run.queue);
386+
setMachineValue(run.machinePreset);
387+
}}
388+
/>
443389
</div>
444390
</TabContainer>
445391
<ResizablePanelGroup orientation="horizontal">
@@ -524,7 +470,7 @@ function StandardTaskForm({
524470
placeholder="Select queue"
525471
variant="tertiary/small"
526472
dropdownIcon
527-
items={queues}
473+
items={queueItems}
528474
filter={{ keys: ["label"] }}
529475
value={queueValue}
530476
setValue={setQueueValue}
@@ -892,3 +838,68 @@ function ScheduledTaskForm({
892838
</Form>
893839
);
894840
}
841+
842+
function RecentRunsPopover<T extends StandardRun | ScheduledRun>({
843+
runs,
844+
onRunSelected,
845+
}: {
846+
runs: T[];
847+
onRunSelected: (run: T) => void;
848+
}) {
849+
const [isRecentRunsPopoverOpen, setIsRecentRunsPopoverOpen] = useState(false);
850+
851+
return (
852+
<Popover open={isRecentRunsPopoverOpen} onOpenChange={setIsRecentRunsPopoverOpen}>
853+
<PopoverTrigger asChild>
854+
{runs.length === 0 ? (
855+
<SimpleTooltip
856+
button={
857+
<Button
858+
type="button"
859+
variant="tertiary/small"
860+
LeadingIcon={ClockIcon}
861+
disabled={true}
862+
>
863+
Recent runs
864+
</Button>
865+
}
866+
content="No runs yet"
867+
/>
868+
) : (
869+
<Button type="button" variant="tertiary/small" LeadingIcon={ClockIcon}>
870+
Recent runs
871+
</Button>
872+
)}
873+
</PopoverTrigger>
874+
<PopoverContent className="min-w-[279px] p-0" align="end" sideOffset={6}>
875+
<div className="max-h-80 overflow-y-auto">
876+
<div className="p-1">
877+
{runs.map((run) => (
878+
<button
879+
key={run.id}
880+
type="button"
881+
onClick={() => {
882+
onRunSelected(run);
883+
setIsRecentRunsPopoverOpen(false);
884+
}}
885+
className="flex w-full items-center gap-2 rounded-sm px-2 py-2 outline-none transition-colors focus-custom hover:bg-charcoal-900 "
886+
>
887+
<div className="flex flex-col items-start">
888+
<Paragraph variant="small">
889+
<DateTime date={run.createdAt} showTooltip={false} />
890+
</Paragraph>
891+
<div className="flex items-center gap-2 text-xs text-text-dimmed">
892+
<div>
893+
Run <span className="font-mono">{run.friendlyId.slice(-8)}</span>
894+
</div>
895+
<TaskRunStatusCombo status={run.status} />
896+
</div>
897+
</div>
898+
</button>
899+
))}
900+
</div>
901+
</div>
902+
</PopoverContent>
903+
</Popover>
904+
);
905+
}

0 commit comments

Comments
 (0)