The module now offers two tiles in the + picker, Plan and Teams, sharing the one Planning Center connection and the one poll. Existing Plan tiles are untouched: they carry no variant, and the shell keeps handing those the module-level settings.
The Teams tile
The current plan's team and position assignments — each team as a band of its people, with the person's photo, their position and a dot for confirmed / unconfirmed / declined. Declined people are struck through and dimmed.
Photos are proxied and cached by the module (GET /team-avatar/<planPersonId>), so no browser ever talks to Planning Center and the CDN address never reaches one. A person Planning Center has no photo for gets their initials, and so does a photo that fails to load.
Its settings, all per tile
Where
What it holds
Loose, at the top
Columns (fit the tile, or one / two / three) and a switch per team
Top bar
A template, with people / team / confirmed counts as variables
Colors
Team headers, Tint teams (each team its own), tint the rows too, header fade, and the confirmed / unconfirmed / declined colours
Show
Top bar, team headers, team counts, avatars, positions, group by position, status, person notes, declined people, unconfirmed people, teams nobody is on
Two Teams tiles on one dashboard can therefore show quite different things — one team with photos on one, a plain checklist of everybody on another.
The gear obeys rules 5 and 8: no help and no label over three words anywhere in it (the template's placeholder line is the documented exception), only hide-toggles inside Show, and everything else in a group of its own.
Server
team_members?include=team,person rides a slow lane: re-read when the plan changes, otherwise at most once a minute. It can never fail the plan read — a lost roster keeps the last good one and reports why.
The service type's own team list is read as well, cached ten minutes. Planning Center only returns a team from team_members once somebody is scheduled on it, so that list is the only way to show a team nobody has signed up for — which is the one a booth most wants to see.
GET /teams feeds the tile's team switches and always answers 200 with a list.
Status letters (C / U / D) are matched on the first letter and anything unknown counts as unconfirmed. Photo and include handling are defensive in the same way the items read already is: an account that refuses include is read again without it.
No shell changes
Picker entries carrying their own instanceSchema, the color field and multiselect with allByDefault all already exist. Nothing outside modules/pco-plan/ and the mock changed.
Verified
Against tools/pco-mock.js, which grew team_members, the service type's teams and stand-in avatar images — including a declined person, people with no photo and a team nobody is on:
Four tiles side by side (three Teams with different settings, one Plan) each render independently; the Plan tile is unchanged.
Team filtering, declined and unconfirmed filtering; group by position; one, two, three and auto columns; per-team tints; row tints.
Avatars load through the proxy, fall back to initials, and are served from cache on later asks. An unknown person id is a 404.
Planning Center killed mid-run: the tile goes red with a reason and keeps the last good roster; it recovers by itself when the mock returns. Admin re-init with tiles open, tile removal, and the existing 43 tests all pass.
Endpoint use confirmed from the mock's log: the plan was read 8 times while the roster was read 3 and the team list twice.
Not yet verified against the real API — the Planning Center connector in this session answers 401, so the live shapes are checked on a booth after the update, as 1.6.0 was. The attributes used are the documented ones (name, status, team_position_name, photo_thumbnail, notes, decline_reason, plus the included Team.name / Team.sequence and Person.avatar), and every one of them has a fallback.
The module now offers **two tiles** in the + picker, **Plan** and **Teams**, sharing the one Planning Center connection and the one poll. Existing Plan tiles are untouched: they carry no variant, and the shell keeps handing those the module-level settings.
## The Teams tile
The current plan's team and position assignments — each team as a band of its people, with the person's photo, their position and a dot for confirmed / unconfirmed / declined. Declined people are struck through and dimmed.
Photos are proxied and cached by the module (`GET /team-avatar/<planPersonId>`), so no browser ever talks to Planning Center and the CDN address never reaches one. A person Planning Center has no photo for gets their initials, and so does a photo that fails to load.
## Its settings, all per tile
| Where | What it holds |
| --- | --- |
| Loose, at the top | Columns (fit the tile, or one / two / three) and a switch per team |
| Top bar | A template, with people / team / confirmed counts as variables |
| Colors | Team headers, **Tint teams** (each team its own), tint the rows too, header fade, and the confirmed / unconfirmed / declined colours |
| Show | Top bar, team headers, team counts, avatars, positions, group by position, status, person notes, declined people, unconfirmed people, teams nobody is on |
Two Teams tiles on one dashboard can therefore show quite different things — one team with photos on one, a plain checklist of everybody on another.
The gear obeys rules 5 and 8: no `help` and no label over three words anywhere in it (the template's placeholder line is the documented exception), only hide-toggles inside **Show**, and everything else in a group of its own.
## Server
- `team_members?include=team,person` rides a **slow lane**: re-read when the plan changes, otherwise at most once a minute. It can never fail the plan read — a lost roster keeps the last good one and reports why.
- The service type's own team list is read as well, cached ten minutes. Planning Center only returns a team from `team_members` once somebody is scheduled on it, so that list is the only way to show a team nobody has signed up for — which is the one a booth most wants to see.
- `GET /teams` feeds the tile's team switches and always answers 200 with a list.
- Status letters (`C` / `U` / `D`) are matched on the first letter and anything unknown counts as unconfirmed. Photo and include handling are defensive in the same way the items read already is: an account that refuses `include` is read again without it.
## No shell changes
Picker entries carrying their own `instanceSchema`, the `color` field and `multiselect` with `allByDefault` all already exist. Nothing outside `modules/pco-plan/` and the mock changed.
## Verified
Against `tools/pco-mock.js`, which grew `team_members`, the service type's teams and stand-in avatar images — including a declined person, people with no photo and a team nobody is on:
- Four tiles side by side (three Teams with different settings, one Plan) each render independently; the Plan tile is unchanged.
- Team filtering, declined and unconfirmed filtering; group by position; one, two, three and auto columns; per-team tints; row tints.
- Avatars load through the proxy, fall back to initials, and are served from cache on later asks. An unknown person id is a 404.
- Planning Center killed mid-run: the tile goes red with a reason and **keeps the last good roster**; it recovers by itself when the mock returns. Admin re-init with tiles open, tile removal, and the existing 43 tests all pass.
- Endpoint use confirmed from the mock's log: the plan was read 8 times while the roster was read 3 and the team list twice.
**Not yet verified against the real API** — the Planning Center connector in this session answers 401, so the live shapes are checked on a booth after the update, as 1.6.0 was. The attributes used are the documented ones (`name`, `status`, `team_position_name`, `photo_thumbnail`, `notes`, `decline_reason`, plus the included `Team.name` / `Team.sequence` and `Person.avatar`), and every one of them has a fallback.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
The module now offers two tiles in the + picker, Plan and Teams, sharing
the one Planning Center connection and the one poll.
Teams draws the current plan's team and position assignments: each team as
a band of its people, with the person's photo, their position and a dot for
confirmed / unconfirmed / declined. Photos are proxied and cached by the
module (GET /team-avatar/<planPersonId>) so no browser ever talks to
Planning Center; a person with no photo gets their initials.
Everything shown is the tile's own choice, so two tiles can differ:
- Teams and Positions — a switch per team and per position, all on until
someone flips one (GET /teams, GET /positions feed the lists)
- Colours — a picker for the team headers, or Tint teams to give each its
own, optionally carried into the rows, plus the header fade and pickers
for the three statuses
- Show — twelve switches (top bar, team headers and counts, avatars,
positions, group by position, status, notes, declined and unconfirmed
people, teams nobody is on, columns)
Server: team_members?include=team,person rides a slow lane (re-read on a
plan change, else at most once a minute) and can never fail the plan read —
a lost roster keeps the last good one and says so. The service type's own
team list is read too, cached ten minutes: Planning Center only returns a
team once somebody is scheduled on it, so that list is the only way to show
a team nobody has signed up for.
No shell changes: picker entries carrying their own instanceSchema, the
colour field and multiselects all already exist.
tools/pco-mock.js grows team_members, the service type's teams and stand-in
avatar images, including a declined person, people with no photo and a team
nobody is on.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Colors and Status colors were two groups asking the same question, so they
are one: team header, the tints and the three status colours together.
The Positions switches go entirely — the team switches already decide what
a tile shows, and "Group by position" still arranges what is left. With
them go GET /positions and positionOptions().
Two rules the tile was breaking on the way past: a gear group may carry no
`help` (rule 5), and only hide-toggles belong in Show (rule 8) — so the
group blurbs are gone and the Columns picker sits loose at the top beside
the team switches.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
michael
merged commit 7a736b3db1 into main2026-09-24 15:28:05 -04:00
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
The module now offers two tiles in the + picker, Plan and Teams, sharing the one Planning Center connection and the one poll. Existing Plan tiles are untouched: they carry no variant, and the shell keeps handing those the module-level settings.
The Teams tile
The current plan's team and position assignments — each team as a band of its people, with the person's photo, their position and a dot for confirmed / unconfirmed / declined. Declined people are struck through and dimmed.
Photos are proxied and cached by the module (
GET /team-avatar/<planPersonId>), so no browser ever talks to Planning Center and the CDN address never reaches one. A person Planning Center has no photo for gets their initials, and so does a photo that fails to load.Its settings, all per tile
Two Teams tiles on one dashboard can therefore show quite different things — one team with photos on one, a plain checklist of everybody on another.
The gear obeys rules 5 and 8: no
helpand no label over three words anywhere in it (the template's placeholder line is the documented exception), only hide-toggles inside Show, and everything else in a group of its own.Server
team_members?include=team,personrides a slow lane: re-read when the plan changes, otherwise at most once a minute. It can never fail the plan read — a lost roster keeps the last good one and reports why.team_membersonce somebody is scheduled on it, so that list is the only way to show a team nobody has signed up for — which is the one a booth most wants to see.GET /teamsfeeds the tile's team switches and always answers 200 with a list.C/U/D) are matched on the first letter and anything unknown counts as unconfirmed. Photo and include handling are defensive in the same way the items read already is: an account that refusesincludeis read again without it.No shell changes
Picker entries carrying their own
instanceSchema, thecolorfield andmultiselectwithallByDefaultall already exist. Nothing outsidemodules/pco-plan/and the mock changed.Verified
Against
tools/pco-mock.js, which grewteam_members, the service type's teams and stand-in avatar images — including a declined person, people with no photo and a team nobody is on:Not yet verified against the real API — the Planning Center connector in this session answers 401, so the live shapes are checked on a booth after the update, as 1.6.0 was. The attributes used are the documented ones (
name,status,team_position_name,photo_thumbnail,notes,decline_reason, plus the includedTeam.name/Team.sequenceandPerson.avatar), and every one of them has a fallback.🤖 Generated with Claude Code