Skip to content

Commit 09fae6a

Browse files
committed
feat: improve queue limits override interface
Refactor the queue limit override dialog to use a more intuitive layout with Fieldset and InputGroup components. Add support for managing multiple rate limit entries with add/remove functionality and improve input handling for better user experience.
1 parent 3f08bb9 commit 09fae6a

1 file changed

Lines changed: 126 additions & 107 deletions

File tree

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

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

Lines changed: 126 additions & 107 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,9 @@ import {
55
ChatBubbleLeftEllipsisIcon,
66
PauseIcon,
77
PlayIcon,
8+
PlusIcon,
89
RectangleStackIcon,
10+
XMarkIcon,
911
} from "@heroicons/react/20/solid";
1012
import { DialogClose } from "@radix-ui/react-dialog";
1113
import { Form, useNavigation, useSearchParams, type MetaFunction } from "@remix-run/react";
@@ -28,9 +30,12 @@ import { Badge } from "~/components/primitives/Badge";
2830
import { Button, LinkButton, type ButtonVariant } from "~/components/primitives/Buttons";
2931
import { Callout } from "~/components/primitives/Callout";
3032
import { Dialog, DialogContent, DialogHeader, DialogTrigger } from "~/components/primitives/Dialog";
33+
import { Fieldset } from "~/components/primitives/Fieldset";
3134
import { FormButtons } from "~/components/primitives/FormButtons";
3235
import { Header3 } from "~/components/primitives/Headers";
3336
import { Input } from "~/components/primitives/Input";
37+
import { InputGroup } from "~/components/primitives/InputGroup";
38+
import { Label } from "~/components/primitives/Label";
3439
import { SearchInput } from "~/components/primitives/SearchInput";
3540
import { NavBar, PageAccessories, PageTitle } from "~/components/primitives/PageHeader";
3641
import { PaginationControls } from "~/components/primitives/Pagination";
@@ -944,7 +949,7 @@ function QueueOverrideLimitsButton({
944949
queue.concurrencyLimit?.toString() ?? environmentConcurrencyLimit.toString()
945950
);
946951
const [rateLimits, setRateLimits] = useState<Array<{ limit: number; window: number }>>(
947-
queue.rateLimit ?? []
952+
queue.rateLimit && queue.rateLimit.length > 0 ? queue.rateLimit : [{ limit: 0, window: 0 }]
948953
);
949954

950955
const isOverridden = !!queue.concurrency?.overriddenAt || (queue.rateLimit && queue.rateLimit.length > 0);
@@ -969,35 +974,35 @@ function QueueOverrideLimitsButton({
969974
title={isOverridden ? "Edit override…" : "Override limit…"}
970975
/>
971976
</DialogTrigger>
972-
<DialogContent>
973-
<DialogHeader>
977+
<DialogContent className="p-0 pt-2.5 md:max-w-lg">
978+
<DialogHeader className="px-4">
974979
{isOverridden ? "Edit limits override" : "Override limits"}
975980
</DialogHeader>
976-
<div className="flex flex-col gap-3 pt-3">
977-
{isOverridden ? (
978-
<Paragraph>
979-
This queue's limits are currently overridden.
980-
{typeof queue.concurrency?.base === "number" &&
981-
` The original concurrency limit set in code was ${queue.concurrency.base}.`}{" "}
982-
You can update the override or remove it to restore the{" "}
983-
{typeof queue.concurrency?.base === "number"
984-
? "limit set in code"
985-
: "environment concurrency limit"}
986-
.
987-
</Paragraph>
988-
) : (
989-
<Paragraph>
990-
Override this queue's limits. The current concurrency limit is {currentLimit}, which is
991-
set {queue.concurrencyLimit !== null ? "in code" : "by the environment"}.
992-
</Paragraph>
993-
)}
994-
<Form method="post" onSubmit={() => setIsOpen(false)} className="space-y-3">
995-
<input type="hidden" name="friendlyId" value={queue.id} />
996-
<input type="hidden" name="rateLimits" value={JSON.stringify(rateLimits)} />
997-
<div className="space-y-2">
998-
<label htmlFor="concurrencyLimit" className="text-sm text-text-bright">
999-
Concurrency limit
1000-
</label>
981+
<Form method="post" onSubmit={() => setIsOpen(false)}>
982+
<input type="hidden" name="friendlyId" value={queue.id} />
983+
<input type="hidden" name="rateLimits" value={JSON.stringify(rateLimits.filter(rl => rl.limit > 0 && rl.window > 0))} />
984+
985+
<Fieldset className="max-h-[70vh] overflow-y-auto p-4 scrollbar-thin scrollbar-track-transparent scrollbar-thumb-charcoal-600 space-y-4">
986+
{isOverridden ? (
987+
<Paragraph>
988+
This queue's limits are currently overridden.
989+
{typeof queue.concurrency?.base === "number" &&
990+
` The original concurrency limit set in code was ${queue.concurrency.base}.`}{" "}
991+
You can update the override or remove it to restore the{" "}
992+
{typeof queue.concurrency?.base === "number"
993+
? "limit set in code"
994+
: "environment concurrency limit"}
995+
.
996+
</Paragraph>
997+
) : (
998+
<Paragraph>
999+
Override this queue's limits. The current concurrency limit is {currentLimit}, which is
1000+
set {queue.concurrencyLimit !== null ? "in code" : "by the environment"}.
1001+
</Paragraph>
1002+
)}
1003+
1004+
<InputGroup fullWidth>
1005+
<Label htmlFor="concurrencyLimit">Concurrency limit</Label>
10011006
<Input
10021007
type="number"
10031008
name="concurrencyLimit"
@@ -1009,100 +1014,114 @@ function QueueOverrideLimitsButton({
10091014
placeholder={currentLimit.toString()}
10101015
autoFocus
10111016
/>
1012-
</div>
1017+
</InputGroup>
10131018

1014-
<div className="space-y-2">
1015-
<label className="text-sm text-text-bright">Rate limits</label>
1019+
<InputGroup fullWidth>
1020+
<div className="grid w-full grid-cols-[1fr_1fr] gap-1.5">
1021+
<Label>Rate limit</Label>
1022+
<Label>Window (seconds)</Label>
1023+
</div>
10161024
{rateLimits.map((rl, index) => (
1017-
<div key={index} className="flex items-center gap-2">
1018-
<Input
1019-
type="number"
1020-
min="1"
1021-
value={rl.limit}
1022-
onChange={(e) => {
1023-
const newLimits = [...rateLimits];
1024-
newLimits[index].limit = parseInt(e.target.value, 10);
1025-
setRateLimits(newLimits);
1026-
}}
1027-
placeholder="Limit"
1028-
/>
1029-
<span className="text-text-dimmed">per</span>
1025+
<div key={index} className="grid w-full grid-cols-[1fr_1fr] gap-1.5">
10301026
<Input
10311027
type="number"
10321028
min="1"
1033-
value={rl.window}
1029+
value={rl.limit || ""}
10341030
onChange={(e) => {
10351031
const newLimits = [...rateLimits];
1036-
newLimits[index].window = parseInt(e.target.value, 10);
1032+
newLimits[index].limit = parseInt(e.target.value, 10) || 0;
10371033
setRateLimits(newLimits);
10381034
}}
1039-
placeholder="Window (s)"
1035+
placeholder="e.g. 10"
10401036
/>
1041-
<span className="text-text-dimmed">seconds</span>
1042-
<Button
1043-
type="button"
1044-
variant="tertiary/small"
1045-
onClick={() => {
1046-
const newLimits = [...rateLimits];
1047-
newLimits.splice(index, 1);
1048-
setRateLimits(newLimits);
1049-
}}
1050-
>
1051-
Remove
1052-
</Button>
1037+
<div className="flex items-start gap-1">
1038+
<div className="grow">
1039+
<Input
1040+
type="number"
1041+
min="1"
1042+
value={rl.window || ""}
1043+
onChange={(e) => {
1044+
const newLimits = [...rateLimits];
1045+
newLimits[index].window = parseInt(e.target.value, 10) || 0;
1046+
setRateLimits(newLimits);
1047+
}}
1048+
placeholder="e.g. 60"
1049+
/>
1050+
</div>
1051+
{rateLimits.length > 1 && (
1052+
<Button
1053+
type="button"
1054+
variant="minimal/medium"
1055+
onClick={() => {
1056+
const newLimits = [...rateLimits];
1057+
newLimits.splice(index, 1);
1058+
setRateLimits(newLimits);
1059+
}}
1060+
LeadingIcon={XMarkIcon}
1061+
/>
1062+
)}
1063+
</div>
10531064
</div>
10541065
))}
1055-
<Button
1056-
type="button"
1057-
variant="secondary/small"
1058-
onClick={() => setRateLimits([...rateLimits, { limit: 10, window: 60 }])}
1059-
>
1060-
Add rate limit
1061-
</Button>
1062-
</div>
1063-
1064-
<FormButtons
1065-
defaultAction={{
1066-
name: "action",
1067-
value: "queue-override",
1068-
disabled: isLoading || !concurrencyLimit,
1069-
}}
1070-
confirmButton={
1066+
<div className="flex items-center justify-between gap-4">
1067+
<Paragraph variant="extra-small">
1068+
Tip: You can also set dynamic rate limits in your code.
1069+
</Paragraph>
10711070
<Button
1072-
type="submit"
1073-
name="action"
1074-
value="queue-override"
1075-
disabled={isLoading || !concurrencyLimit}
1076-
variant="primary/medium"
1077-
LeadingIcon={isLoading && <Spinner color="white" />}
1078-
shortcut={{ modifiers: ["mod"], key: "enter" }}
1071+
type="button"
1072+
variant="tertiary/medium"
1073+
className="w-fit"
1074+
onClick={() => setRateLimits([...rateLimits, { limit: 0, window: 0 }])}
1075+
LeadingIcon={PlusIcon}
10791076
>
1080-
{isOverridden ? "Update override" : "Override limit"}
1077+
Add another
10811078
</Button>
1082-
}
1083-
cancelButton={
1084-
<div className="flex items-center justify-between gap-2">
1085-
{isOverridden && (
1086-
<Button
1087-
type="submit"
1088-
name="action"
1089-
value="queue-remove-override"
1090-
disabled={isLoading}
1091-
variant="danger/medium"
1092-
>
1093-
Remove override
1094-
</Button>
1095-
)}
1096-
<DialogClose asChild>
1097-
<Button type="button" variant="tertiary/medium">
1098-
Cancel
1099-
</Button>
1100-
</DialogClose>
1101-
</div>
1102-
}
1103-
/>
1104-
</Form>
1105-
</div>
1079+
</div>
1080+
</InputGroup>
1081+
</Fieldset>
1082+
1083+
<FormButtons
1084+
className="px-4 pb-4"
1085+
defaultAction={{
1086+
name: "action",
1087+
value: "queue-override",
1088+
disabled: isLoading || !concurrencyLimit,
1089+
}}
1090+
confirmButton={
1091+
<Button
1092+
type="submit"
1093+
name="action"
1094+
value="queue-override"
1095+
disabled={isLoading || !concurrencyLimit}
1096+
variant="primary/medium"
1097+
LeadingIcon={isLoading && <Spinner color="white" />}
1098+
shortcut={{ modifiers: ["mod"], key: "enter" }}
1099+
>
1100+
{isOverridden ? "Update override" : "Override limit"}
1101+
</Button>
1102+
}
1103+
cancelButton={
1104+
<div className="flex items-center justify-between gap-2">
1105+
{isOverridden && (
1106+
<Button
1107+
type="submit"
1108+
name="action"
1109+
value="queue-remove-override"
1110+
disabled={isLoading}
1111+
variant="danger/medium"
1112+
>
1113+
Remove override
1114+
</Button>
1115+
)}
1116+
<DialogClose asChild>
1117+
<Button type="button" variant="tertiary/medium">
1118+
Cancel
1119+
</Button>
1120+
</DialogClose>
1121+
</div>
1122+
}
1123+
/>
1124+
</Form>
11061125
</DialogContent>
11071126
</Dialog>
11081127
);

0 commit comments

Comments
 (0)