Skip to content

Where people and agents ship software together. The open-source git platform for the whole job: issues, agents, checks and deploys to the edge.

Commit

Web: a work item's extra sessions link to Work's Sessions filtered to it

The work panel said "N more on its repositories' Sessions pages", which no longer exist. It links to /<ws>/-/work/sessions?item=N, which now filters to one work item's sessions and says so with a chip that clears it.

G1T-Session:
ses_01m56vafhge7ttrgs5288dpxvb
syntaqxcommitted Parent983bb1cBrowse files
4 files+34−80/4 viewed
+11−2
286286 export function SessionsFiltersBar({ workspace, filters, repos, people, me }: { workspace: string; filters: SessionsFilters; repos: string[]; people: string[]; me: string | null }) {
287287 const [open, setOpen] = useState(false);
288288 const to = (change: Partial<SessionsFilters>) => `${sessionsPath(workspace)}${sessionsQuery({ ...filters, ...change })}`;
289− const count = [filters.repo, filters.person, filters.harness, filters.kind].filter(Boolean).length;
290− const clear = to({ repo: null, person: null, harness: null, kind: null });
289+ const count = [filters.repo, filters.person, filters.harness, filters.kind, filters.item].filter(Boolean).length;
290+ const clear = to({ repo: null, person: null, harness: null, kind: null, item: null });
291+ // A work item's own sessions (`?item=12`, from its page): said, with the way back to all of them.
292+ const onItem = filters.item ? (
293+ <Link to={to({ item: null })} className="inline-flex h-8 items-center gap-1 rounded-md border border-line px-2.5 text-xs text-fg-soft hover:text-fg" aria-label={`On #${filters.item}: show sessions on every work item`}>
294+ On #{filters.item}
295+ <X size={12} />
296+ </Link>
297+ ) : null;
291298 const everyone = me ? [me, ...people.filter((name) => name !== me)] : people;
292299 const menus: { title: string; active: string | null; any: string; field: keyof SessionsFilters; options: { key: string; label: ReactNode }[] }[] = [
293300 { title: "Repository", active: filters.repo, any: "Any repository", field: "repo", options: repos.map((name) => ({ key: name, label: <span className="font-mono text-[0.8125rem]">{name}</span> })) },
298305 return (
299306 <>
300307 <div className="hidden flex-wrap items-center gap-2 sm:flex">
308+ {onItem}
301309 {menus.map((menu) => (
302310 <FilterMenu
303311 key={menu.title}
327335 Filters
328336 {count > 0 && <span className="rounded-full bg-accent px-1.5 text-[0.6875rem] leading-4.5 font-bold text-bg tabular-nums">{count}</span>}
329337 </Button>
338+ {onItem}
330339 {filters.repo && <span className="min-w-0 truncate font-mono text-xs text-muted">{filters.repo}</span>}
331340 </div>
332341 <BottomSheet open={open} onOpenChange={setOpen} title="Filters">
+9−1
5656
5757 test("Sessions keeps its filters in the address and drops what it does not know", () => {
5858 const filters = sessionsFilters(new URLSearchParams("repo=web&person=@bo&harness=codex&kind=bogus&state=recent"));
59− assert.deepEqual(filters, { state: "recent", repo: "web", person: "bo", harness: "codex", kind: null });
59+ assert.deepEqual(filters, { state: "recent", repo: "web", person: "bo", harness: "codex", kind: null, item: null });
6060 assert.equal(sessionsQuery(filters), "?state=recent&repo=web&person=bo&harness=codex");
6161 assert.equal(sessionsQuery({ state: "live" }), "");
6262 assert.equal(narrowed(filters), true);
6363 assert.equal(narrowed(sessionsFilters(new URLSearchParams("state=recent"))), false);
6464 });
6565
66+test("Sessions can be a work item's own: ?item=12", () => {
67+ const filters = sessionsFilters(new URLSearchParams("state=recent&item=12"));
68+ assert.equal(filters.item, 12);
69+ assert.equal(narrowed(filters), true);
70+ assert.equal(sessionsQuery(filters), "?state=recent&item=12");
71+ for (const bad of ["0", "-3", "x", "1.5"]) assert.equal(sessionsFilters(new URLSearchParams(`item=${bad}`)).item, null, bad);
72+});
73+
6674 test("live sessions come apart from those that ended, most recently heard from first", () => {
6775 const sessions = [
6876 listed("old", { state: "ended" }),
+6−3
5151 person: string | null;
5252 harness: Harness | null;
5353 kind: SessionKind | null;
54+ /** The work item they are on, by number: a work item's own sessions. */
55+ item: number | null;
5456 };
5557
5658 const HARNESSES = Object.keys(HARNESS_NAMES) as Harness[];
6668 person: text("person"),
6769 harness: harness && (HARNESSES as string[]).includes(harness) ? (harness as Harness) : null,
6870 kind: kind && (KINDS as string[]).includes(kind) ? (kind as SessionKind) : null,
71+ item: /^\d+$/.test(query.get("item") ?? "") && Number(query.get("item")) > 0 ? Number(query.get("item")) : null,
6972 };
7073 }
7174
7376 export function sessionsQuery(filters: Partial<SessionsFilters>): string {
7477 const query = new URLSearchParams();
7578 if (filters.state === "recent") query.set("state", "recent");
76− for (const key of ["repo", "person", "harness", "kind"] as const) {
79+ for (const key of ["repo", "person", "harness", "kind", "item"] as const) {
7780 const value = filters[key];
78− if (value) query.set(key, value);
81+ if (value) query.set(key, String(value));
7982 }
8083 const text = query.toString();
8184 return text ? `?${text}` : "";
8386
8487 /** Whether any filter narrows the list. */
8588 export function narrowed(filters: SessionsFilters): boolean {
86− return Boolean(filters.repo || filters.person || filters.harness || filters.kind);
89+ return Boolean(filters.repo || filters.person || filters.harness || filters.kind || filters.item);
8790 }
8891
8992 /**
+8−2
3838 const viewer = getViewer(context);
3939 const workspace = params.owner.toLowerCase();
4040 const filters = sessionsFilters(new URL(request.url).searchParams);
41− const narrow = { repo: filters.repo ?? undefined, person: filters.person ?? undefined, harness: filters.harness ?? undefined, kind: filters.kind ?? undefined };
41+ const narrow = {
42+ repo: filters.repo ?? undefined,
43+ person: filters.person ?? undefined,
44+ harness: filters.harness ?? undefined,
45+ kind: filters.kind ?? undefined,
46+ item: filters.item ?? undefined,
47+ };
4248 const every = filters.state === "recent";
4349 // What is going now is what the page is about; what ended, a part of its own.
4450 const [now, ended] = await Promise.all([
265271 icon={<History size={15} className="text-faint" />}
266272 title="Recent"
267273 aside={
268− <Link to={sessionsPath(workspace, { state: "recent", repo: filters.repo, person: filters.person, harness: filters.harness, kind: filters.kind })} className="hover:text-fg">
274+ <Link to={sessionsPath(workspace, { state: "recent", repo: filters.repo, person: filters.person, harness: filters.harness, kind: filters.kind, item: filters.item ? String(filters.item) : null })} className="hover:text-fg">
269275 Every session
270276 </Link>
271277 }

Comments

Sign in to comment.