Skip to content

Commit 847bebd

Browse files
committed
View runs from Queues page
1 parent 3d2e428 commit 847bebd

File tree

2 files changed

+135
-29
lines changed
  • apps/webapp/app
    • components/primitives
    • routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.queues

2 files changed

+135
-29
lines changed

apps/webapp/app/components/primitives/Buttons.tsx

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -163,6 +163,8 @@ const allVariants = {
163163
variant: variant,
164164
};
165165

166+
export type ButtonVariant = keyof typeof variant;
167+
166168
export type ButtonContentPropsType = {
167169
children?: React.ReactNode;
168170
LeadingIcon?: RenderIcon;
@@ -173,7 +175,7 @@ export type ButtonContentPropsType = {
173175
textAlignLeft?: boolean;
174176
className?: string;
175177
shortcut?: ShortcutDefinition;
176-
variant: keyof typeof variant;
178+
variant: ButtonVariant;
177179
shortcutPosition?: "before-trailing-icon" | "after-trailing-icon";
178180
tooltip?: ReactNode;
179181
iconSpacing?: string;

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

Lines changed: 132 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ import { Feedback } from "~/components/Feedback";
3030
import { PageBody, PageContainer } from "~/components/layout/AppLayout";
3131
import { BigNumber } from "~/components/metrics/BigNumber";
3232
import { Badge } from "~/components/primitives/Badge";
33-
import { Button, LinkButton } from "~/components/primitives/Buttons";
33+
import { Button, ButtonVariant, LinkButton } from "~/components/primitives/Buttons";
3434
import { Callout } from "~/components/primitives/Callout";
3535
import { Dialog, DialogContent, DialogHeader, DialogTrigger } from "~/components/primitives/Dialog";
3636
import { FormButtons } from "~/components/primitives/FormButtons";
@@ -66,13 +66,14 @@ import { EnvironmentQueuePresenter } from "~/presenters/v3/EnvironmentQueuePrese
6666
import { QueueListPresenter } from "~/presenters/v3/QueueListPresenter.server";
6767
import { requireUserId } from "~/services/session.server";
6868
import { cn } from "~/utils/cn";
69-
import { docsPath, EnvironmentParamSchema, v3BillingPath } from "~/utils/pathBuilder";
69+
import { docsPath, EnvironmentParamSchema, v3BillingPath, v3RunsPath } from "~/utils/pathBuilder";
7070
import { PauseEnvironmentService } from "~/v3/services/pauseEnvironment.server";
7171
import { PauseQueueService } from "~/v3/services/pauseQueue.server";
7272
import { useCurrentPlan } from "../_app.orgs.$organizationSlug/route";
7373
import { Header3 } from "~/components/primitives/Headers";
7474
import { Input } from "~/components/primitives/Input";
7575
import { useThrottle } from "~/hooks/useThrottle";
76+
import { RunsIcon } from "~/assets/icons/RunsIcon";
7677

7778
const SearchParamsSchema = z.object({
7879
query: z.string().optional(),
@@ -272,7 +273,20 @@ export default function Page() {
272273
value={environment.queued}
273274
suffix={env.paused && environment.queued > 0 ? "paused" : undefined}
274275
animate
275-
accessory={<EnvironmentPauseResumeButton env={env} />}
276+
accessory={
277+
<div className="flex items-start gap-1">
278+
<LinkButton
279+
variant="tertiary/small"
280+
to={v3RunsPath(organization, project, env, {
281+
statuses: ["PENDING"],
282+
period: "30d",
283+
})}
284+
>
285+
View runs
286+
</LinkButton>
287+
<EnvironmentPauseResumeButton env={env} />
288+
</div>
289+
}
276290
valueClassName={env.paused ? "text-warning" : undefined}
277291
compactThreshold={1000000}
278292
/>
@@ -291,6 +305,17 @@ export default function Page() {
291305
"At concurrency limit"
292306
) : undefined
293307
}
308+
accessory={
309+
<LinkButton
310+
variant="tertiary/small"
311+
to={v3RunsPath(organization, project, env, {
312+
statuses: ["DEQUEUED", "EXECUTING"],
313+
period: "30d",
314+
})}
315+
>
316+
View runs
317+
</LinkButton>
318+
}
294319
compactThreshold={1000000}
295320
/>
296321
<BigNumber
@@ -397,6 +422,9 @@ export default function Page() {
397422
queues.map((queue) => {
398423
const limit = queue.concurrencyLimit ?? environment.concurrencyLimit;
399424
const isAtLimit = queue.running === limit;
425+
const queueFilterableName = `${queue.type === "task" ? "task/" : ""}${
426+
queue.name
427+
}`;
400428
return (
401429
<TableRow key={queue.name}>
402430
<TableCell>
@@ -477,6 +505,66 @@ export default function Page() {
477505
hiddenButtons={
478506
!queue.paused && <QueuePauseResumeButton queue={queue} />
479507
}
508+
popoverContent={
509+
<>
510+
{queue.paused ? (
511+
<QueuePauseResumeButton
512+
queue={queue}
513+
variant="minimal/small"
514+
fullWidth
515+
showTooltip={false}
516+
/>
517+
) : (
518+
<QueuePauseResumeButton
519+
queue={queue}
520+
variant="minimal/small"
521+
fullWidth
522+
showTooltip={false}
523+
/>
524+
)}
525+
<LinkButton
526+
variant="minimal/small"
527+
to={v3RunsPath(organization, project, env, {
528+
queues: [queueFilterableName],
529+
period: "30d",
530+
})}
531+
fullWidth
532+
textAlignLeft
533+
LeadingIcon={RunsIcon}
534+
leadingIconClassName="text-indigo-500"
535+
>
536+
View all runs
537+
</LinkButton>
538+
<LinkButton
539+
variant="minimal/small"
540+
to={v3RunsPath(organization, project, env, {
541+
queues: [queueFilterableName],
542+
statuses: ["PENDING"],
543+
period: "30d",
544+
})}
545+
fullWidth
546+
textAlignLeft
547+
LeadingIcon={RectangleStackIcon}
548+
leadingIconClassName="text-queues"
549+
>
550+
View queued runs
551+
</LinkButton>
552+
<LinkButton
553+
variant="minimal/small"
554+
to={v3RunsPath(organization, project, env, {
555+
queues: [queueFilterableName],
556+
statuses: ["DEQUEUED", "EXECUTING"],
557+
period: "30d",
558+
})}
559+
fullWidth
560+
textAlignLeft
561+
LeadingIcon={Spinner}
562+
leadingIconClassName="size-4 animate-none"
563+
>
564+
View running runs
565+
</LinkButton>
566+
</>
567+
}
480568
/>
481569
</TableRow>
482570
);
@@ -630,40 +718,56 @@ function EnvironmentPauseResumeButton({
630718

631719
function QueuePauseResumeButton({
632720
queue,
721+
variant = "tertiary/small",
722+
fullWidth = false,
723+
showTooltip = true,
633724
}: {
634725
/** The "id" here is a friendlyId */
635726
queue: { id: string; name: string; paused: boolean };
727+
variant?: ButtonVariant;
728+
fullWidth?: boolean;
729+
showTooltip?: boolean;
636730
}) {
637731
const navigation = useNavigation();
638732
const [isOpen, setIsOpen] = useState(false);
639733

734+
const button = (
735+
<Button
736+
type="button"
737+
variant={variant}
738+
LeadingIcon={queue.paused ? PlayIcon : PauseIcon}
739+
leadingIconClassName={queue.paused ? "text-success" : "text-warning"}
740+
fullWidth={fullWidth}
741+
textAlignLeft={fullWidth}
742+
>
743+
{queue.paused ? "Resume..." : "Pause..."}
744+
</Button>
745+
);
746+
747+
const trigger = showTooltip ? (
748+
<div>
749+
<TooltipProvider disableHoverableContent={true}>
750+
<Tooltip>
751+
<TooltipTrigger asChild>
752+
<div>
753+
<DialogTrigger asChild>{button}</DialogTrigger>
754+
</div>
755+
</TooltipTrigger>
756+
<TooltipContent side="right" className={"text-xs"}>
757+
{queue.paused
758+
? `Resume processing runs in queue "${queue.name}"`
759+
: `Pause processing runs in queue "${queue.name}"`}
760+
</TooltipContent>
761+
</Tooltip>
762+
</TooltipProvider>
763+
</div>
764+
) : (
765+
<DialogTrigger asChild>{button}</DialogTrigger>
766+
);
767+
640768
return (
641769
<Dialog open={isOpen} onOpenChange={setIsOpen}>
642-
<div>
643-
<TooltipProvider disableHoverableContent={true}>
644-
<Tooltip>
645-
<TooltipTrigger asChild>
646-
<div>
647-
<DialogTrigger asChild>
648-
<Button
649-
type="button"
650-
variant="tertiary/small"
651-
LeadingIcon={queue.paused ? PlayIcon : PauseIcon}
652-
leadingIconClassName={queue.paused ? "text-success" : "text-warning"}
653-
>
654-
{queue.paused ? "Resume..." : "Pause..."}
655-
</Button>
656-
</DialogTrigger>
657-
</div>
658-
</TooltipTrigger>
659-
<TooltipContent side="right" className={"text-xs"}>
660-
{queue.paused
661-
? `Resume processing runs in queue "${queue.name}"`
662-
: `Pause processing runs in queue "${queue.name}"`}
663-
</TooltipContent>
664-
</Tooltip>
665-
</TooltipProvider>
666-
</div>
770+
{trigger}
667771
<DialogContent>
668772
<DialogHeader>{queue.paused ? "Resume queue?" : "Pause queue?"}</DialogHeader>
669773
<div className="flex flex-col gap-3 pt-3">

0 commit comments

Comments
 (0)