Skip to content

Commit a2a9b6d

Browse files
samejrclaude
andcommitted
Validate ?types= URL param against known UnifiedTaskKind values
A shareable URL with a typo or stale kind name previously produced an unrecoverable "No tasks match your filters" state — the unrecognised strings became valid Set entries with no UI affordance to remove them. Filter unknown values out at the parse site. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent 4f7f57a commit a2a9b6d

1 file changed

Lines changed: 12 additions & 2 deletions

File tree

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

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

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -159,6 +159,16 @@ const KIND_OPTIONS: { value: UnifiedTaskKind; label: string }[] = [
159159
{ value: "SCHEDULED", label: "Scheduled" },
160160
];
161161

162+
const VALID_KINDS = new Set<UnifiedTaskKind>(KIND_OPTIONS.map((o) => o.value));
163+
164+
/** Parse `?types=…` URL values, dropping anything that isn't a known
165+
* `UnifiedTaskKind`. Without this, a shareable URL with a typo would
166+
* produce a filter that matches nothing and the user gets stuck on
167+
* "No tasks match your filters" with no way to recover. */
168+
function parseTypesParam(values: string[]): UnifiedTaskKind[] {
169+
return values.filter((v): v is UnifiedTaskKind => VALID_KINDS.has(v as UnifiedTaskKind));
170+
}
171+
162172
const PAGE_SIZE = 25;
163173

164174
export default function Page() {
@@ -206,7 +216,7 @@ export default function Page() {
206216
}, []);
207217

208218
const selectedTypes = useMemo(() => {
209-
const raw = values("types") as UnifiedTaskKind[];
219+
const raw = parseTypesParam(values("types"));
210220
return raw.length > 0 ? new Set(raw) : null; // null = all
211221
}, [values]);
212222

@@ -488,7 +498,7 @@ function RunningCell({ state }: { state: UnifiedRunningState | undefined }) {
488498

489499
function TaskTypeFilter() {
490500
const { values, replace } = useSearchParams();
491-
const raw = values("types") as UnifiedTaskKind[];
501+
const raw = parseTypesParam(values("types"));
492502
const isAll = raw.length === 0 || raw.length === KIND_OPTIONS.length;
493503
// No filter → preselect everything so users can uncheck from "all".
494504
const popoverValue = isAll ? KIND_OPTIONS.map((k) => k.value) : raw;

0 commit comments

Comments
 (0)