Give the Team tab sub-sections of its own
The Team tab was five cards stacked on one page: the rota, the escalation ladder, the alert sources, the dead man's switches and the membership.07914d5split the Admin tab for three reasons, and all three were sharper here. There was no way to link somebody to the escalation ladder, which is the thing a team owner most often has to be talked through. There was no way to the switches but scrolling past a month of rota -- and the rota became a month grid in v0.18.0, which made the page taller rather than shorter. And the poll loop refetched six endpoints every tick however little of the page you were looking at. Each is now a route: /team/rota, /team/members, /team/escalation, /team/sources, /team/deadman, reached from the same strip of links the Admin tab uses, with /team an overview. A page fetches only what it shows, so the switches are one GET and the sources are one, where every tick used to be six. Three of the five fetch the member list besides their own endpoint, and for the same reason each time: a rota entry, a ladder target and a role are all a person, and the page has to be able to name them. The overview is the one that fetches everything, because saying how much of each there is means asking each of them -- who is on call today, how many members and owners, how many ladder levels and whether a fallback follows them, how many keys and how many never used, how many switches. That is what it is for; a strip that already links to the five does not need a second menu that repeats it. team.js owns the table of its six routes, as admin.js owns its four, and app.js parses against both rather than keeping a third list to drift from them. The table carries a title beside the label where the strip's word is too thin to name a page on its own: "Sources" is a fine tab and a poor browser tab, so that page titles as Alert sources and the switches keep their apostrophe in the top bar. menuItem left admin.js for ui.js as menuCard, since both tabs now open on one, and its CSS went from .admin-menu* to .overview-*. That is the rename .user-link -> .row-link was in v0.18.0, for the same reason: the class was named after the first page that used it rather than after what it is. The read-only notice a member sees is now on the overview only. It explains why the controls further down are missing, and a page that is nothing but the rota grid has no controls to explain. The team picker sits above the strip, because it changes the subject of all five, and it drops the ladder draft when it moves -- an unsaved edit belongs to the team it was started in. No server change. Extensionless paths already fall back to index.html, so /team/rota survives a reload the way /admin/users/{id} does, and no endpoint, payload or permission moved. Nobody has looked at this in a browser, the caveat07914d5anda6fa673carried. What is checked is the wiring, and rather more of it than last time: every sub-page was rendered against a stub fetch and a pocket DOM, each with exactly one aria-current and fetching only the endpoints named above; and app.js itself was booted the same way and walked through all seventeen URLs the app has, which resolve to one section each with the right title -- the six new ones, the four Admin ones, both subject pages, and /incidents/42 and /nonsense still falling to the queue. Whether six entries scroll cleanly at phone width is not checked. Claude-Session: https://claude.ai/code/session_01RHPj4ggeFdEjKKfm4SHbD7
This commit is contained in:
@@ -40,22 +40,26 @@ function parseRoute(pathname) {
|
||||
const g = pathname.match(/^\/admin\/teams\/(\d+)\/?$/);
|
||||
if (g) return { section: 'adminteam', team: Number(g[1]) };
|
||||
const name = pathname.replace(/^\/|\/$/g, '');
|
||||
// The Admin tab's sub-sections are routes of their own. admin.js owns the
|
||||
// table of them, since it also builds the strip that links to them.
|
||||
// The Admin and Team tabs' sub-sections are routes of their own. Each view
|
||||
// owns the table of its own, since each also builds the strip that links to
|
||||
// them; /team is in team.TABS as the overview, so it is matched here too.
|
||||
const t = admin.TABS.find((x) => x.path === `/${name}`);
|
||||
if (t) return { section: 'admin', tab: t.tab };
|
||||
if (name === 'oncall' || name === 'alerts' || name === 'team' || name === 'more') return { section: name };
|
||||
const tt = team.TABS.find((x) => x.path === `/${name}`);
|
||||
if (tt) return { section: 'team', tab: tt.tab };
|
||||
if (name === 'oncall' || name === 'alerts' || name === 'more') return { section: name };
|
||||
return { section: 'queue', incident: null };
|
||||
}
|
||||
|
||||
// What the top bar and the document title call this route. Admin's sub-sections
|
||||
// are pages in their own right, so they say which one rather than "Admin" four
|
||||
// times; the overview keeps the tab's own name.
|
||||
// What the top bar and the document title call this route. The sub-sections of
|
||||
// Admin and Team are pages in their own right, so they say which one rather
|
||||
// than the tab's name four or six times; either overview keeps the tab's own
|
||||
// name. A tab may carry a `title` where its strip label is too short to name a
|
||||
// page on its own.
|
||||
function title(r) {
|
||||
const t = r.section === 'admin' && r.tab
|
||||
? admin.TABS.find((x) => x.tab === r.tab)
|
||||
: null;
|
||||
return t ? t.label : SECTIONS[r.section].title;
|
||||
const tabs = r.section === 'admin' ? admin.TABS : r.section === 'team' ? team.TABS : null;
|
||||
const t = tabs && r.tab ? tabs.find((x) => x.tab === r.tab) : null;
|
||||
return t ? (t.title || t.label) : SECTIONS[r.section].title;
|
||||
}
|
||||
|
||||
let route = parseRoute(location.pathname);
|
||||
|
||||
Reference in New Issue
Block a user