Skip to content

Embed router migration#7

Merged
altrup merged 82 commits into
mainfrom
embed-router-migration
Jul 19, 2026
Merged

Embed router migration#7
altrup merged 82 commits into
mainfrom
embed-router-migration

Conversation

@altrup

@altrup altrup commented Jul 12, 2026

Copy link
Copy Markdown
Owner

use embeds to replace complicated commands

altrup and others added 9 commits July 12, 2026 16:08
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…o client

All 15 command names survive; subcommand trees on filter, mode,
default_ring_recipients, and ring collapse into their panels.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@altrup altrup self-assigned this Jul 12, 2026
altrup and others added 20 commits July 12, 2026 19:05
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…on's custom_id)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Both destructive buttons share the label Reset and open a confirmation
modal (shared helper, also adopted by delete-data).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Handlers live at their route's path ([param] folders, get/post/modal.ts
files) and index.ts is a plain routing table importing each one directly.
Per-panel helpers sit in _shared.ts files.

Also unifies the reset naming (recipients /clear and clearDefaultRingees
become /reset and resetDefaultRingees) and moves the delete-data
confirmation modal onto /delete-data itself instead of a /confirm subpath.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
node 22's bundled npm 10 computes a different ideal tree for vite's
optional esbuild peer, so a lockfile written by npm 11 fails npm ci
under npm 10 (and vice versa). Upgrade npm in CI and normalize the
lockfile with npm 11.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Apply the embed redesign handoff across all panels: harmonized accent
colors, unicode-emoji titles, `Label · value` status lines, and a
consistent final nav row (Home last, on its own row) via a new navRow
helper. Render the flash notice as a bolded-lead markdown blockquote.

Rework role signups from the two-step add into a scoped panel like
filter: pick a scope (by-channel or by-role, as path segments), view its
links, and edit them inline with one diffed multi-select. The /signuprole
and /unsignuprole commands drive the same edit routes via add/remove
query params, mirroring the filter members pattern.

Batch (multi-scope) editing is intentionally left out: panel state lives
entirely in the customId and Discord caps it at 100 chars, which a
multi-id scope path blows past at ~4 ids.

Add branded ringvc/vc emoji on Home, guarded on client availability so an
unresolvable emoji falls back to none.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Reserve router.route for paths that serve multiple methods.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Replace the per-panel back/home nav row with a shared section bar
(Home, Signups, Filters, Ringees, Mode), the current section rendered
as an inert Primary tab. The Signups tab carries the branded voice-chat
app emoji, fetched at startup, with a unicode-bell fallback.

Fold Home's old section-button row into the bar, rename Filter to
Filters and ring recipients to Ringees, and restyle the catalog page
onto grouped description lines.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Split the eight sections across two pages of four tabs, with a pager
(back on the left, forward on the right) in each row's fifth slot. The
bar opens on the page holding the active section, and its nav param lets
the pager peek at the other page without leaving the panel. The active
tab is inert only on its own root, staying a live link back on sub-pages
and other scopes.

Move the Github and Support links onto a dedicated About page, leaving
Home as the branded welcome plus the bar. Colour the Delete data tab its
destructive red when selected, and drop its now-redundant Cancel button.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
A dedicated fast path for ringing your saved defaults into your current
voice channel, dispatching to the existing /ring/default route so it
inherits the same in-VC / not-in-VC handling.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Add a reusable subNav row (the old role-signups switch, generalized)
that sits just above the section bar wherever a section has sibling
views. Signups shows My signups / Role signups (the latter only with
Manage Roles), and role signups moves its By channel / By role switch
below its selects.

Split Ring into Quick ring (the immediate action) and Default ringees
(the saved list plus auto-ring). The bar's Ring tab is voice-aware,
opening Quick ring in a voice channel and Default ringees otherwise, so
it never lands on the "not in a voice channel" notice by default.
Default ringees inlines prev/next into its action row, keeping the dense
panel within Discord's five-row limit.

A channel auto-ring override now drops when set back to the global
value, so the manual "Remove override" button, route, and handler are
gone. Rename ring recipients to ringees throughout, link /ring_defaults
from the Default ringees panel, and key the subNav buttons so they never
collide with the bar's customIds.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Move the action acknowledgement below the panel body instead of between
the title and the body.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Switching the filter type now reinterprets the existing list (blocked
users become allowed users, and vice versa) instead of clearing it.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- paginate: an exactly-full list (a multiple of PAGE_SIZE) now gets a
  trailing empty page, so a 26th member can still be added at 25 entries
- flashLine: bold only the first line's lead so the ** markers don't span
  blockquote lines and render literally on multi-line flashes
- extract resolveSelectionEdit so the filter/recipients/signups member
  editors share the select-vs-query-param diff logic; recipients now
  honors add/remove query params like the others
- signups: run the add/remove mutations with Promise.all instead of
  sequentially awaiting each
- vitest: inject dummy env so the suite is self-contained and no longer
  depends on a developer's .env

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The eight sections no longer fit a five-button row, forcing a two-page
split with a pager. A string select holds all of them in one row: the
active section is the menu's default option (so it shows as the current
value), and the paging plus the nav override query param are gone.

navBar no longer needs the current path or query params, so its callers
pass only the active section.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
altrup and others added 28 commits July 14, 2026 22:31
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The router strips the key during decode, so the POST handlers no longer
receive a ts param they never read; base36 keeps the encoding short.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- pageCountOf: only append a trailing empty add-page when a full page
  fills the whole edit select (PAGE_SIZE >= SELECT_MAX_VALUES); an
  exactly-full list now spans exactly its full pages, so the count line
  and pager no longer advertise a phantom page
- page-jump: reject partly-numeric input ("2abc", "1e2") instead of
  honoring parseInt's prefix
- ring: restore the server-only guard so /ring from a DM says so rather
  than the misleading "join a voice channel" hint
- unsignuprole with no channel routes through the by-role reset
  confirmation modal instead of silently clearing every channel

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- role edit handlers call the existing resolveSelectionEdit instead of
  hand-rolling the select/diff-or-query-param resolution
- extract the guild + Manage-Roles + pick-a-scope guard the four role
  edit/reset handlers repeated into roleEditGuard, returning the resolved
  guild and scope or the flash to redirect with
- move mentionChannel beside mentionUser/mentionRole in @main/ring so the
  mention family lives in one place

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The four member panels built the same add/remove select by hand, varying
only the entity type, its default entries, and the noun. editSelectRow
takes the caller's entity-specific builder plus that noun and applies the
shared min/max, "Edit <noun>: select to add, deselect to remove"
placeholder, reset key, and pattern wiring.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Modal dispatches no longer accept reply flags; the confirm modal carries
Ephemeral on its setTo instead, applied when a command-launched
submission creates its reply.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
pageCountOf appends a trailing empty page for adding entries when the
last page fills the edit select; the count line derives its page count
from the total instead so that navigation-only page never inflates it.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Switching a filter's type keeps its entries and reverses what they mean:
a blacklist's blocked users become the only people a whitelist lets
through. The notice now spells that out and warns instead of confirming
when there are entries to reinterpret.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The section bar showed the active section as a selected value, reading
like a value picker. Make the active section the placeholder ("Section:
…") instead, so the bar reads as a location label; selecting any option
routes there.

Move the Ring defaults action from the Quick ring panel onto the Default
ringees panel it rings, left of ⚙ Options via a new pagedControls
leading slot, and redirect its POST back to that panel.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The section bar's "Section:" placeholder now has a sibling: the active
sub-nav button is prefixed "View:" to name the current view, so the two
nav levels announce themselves the same way and the sub-view switch reads
as navigation rather than a pair of actions.

That labeling also distinguishes the Default ringees *view* from the Ring
defaults *action*, which is what made them feel jumbled — so Ring defaults
stays on the Quick ring panel where a ring-now action belongs, and
pagedControls drops the leading-action slot it no longer needs.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The section bar showed the active section as its placeholder ("Section:
X"), restating what the panel title already says and reading as a stored
value. Make it an action prompt ("Switch sections") so the bar reads as
navigation, and drop the now-unused active argument from every call site.

The sub-nav keeps its "Viewing:" prefix: its buttons are all visible, so
marking the current one helps, whereas the collapsed bar is better spent
inviting the open.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Hiding every panel's options behind a ⚙ toggle buried controls like the
filter type switch even when the row was free. Show the option buttons
directly whenever there's no pager competing for the row (the common
single-page case); the toggle now appears only when pagination needs the
row too. Destructive actions stay safe through their own confirm modal,
not the toggle.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Every panel's Reset was Danger-red, pulling the eye to a rare action and
away from the content. Reset is already modal-guarded (type-to-confirm),
so the red wasn't the safeguard. Make the five Resets Secondary and keep
red only for the Delete-data section's "Delete everything", so red means
the one point-of-no-return action.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Modals can't be colored, so signal danger through text instead: prefix
every confirm title with ⚠️ and add a "This can't be undone." line under
the input. Raise the delete-everything confirmation word from DELETE to
DELETE EVERYTHING so the nuclear action takes a deliberate phrase, and
have its test reference the constant instead of the literal.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The toggle switched between green (enable) and grey (disable), so its
color flip read as a state change on its own. Use Primary for both and
let the label carry enable vs disable.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Its one caller passes only (router, path); the label always defaults
to "Back".

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Mirror signup/unsignup/signuprole: resolve the current voice channel
when no channel option is given, and open the by-role panel when there
is no channel context instead of jumping to the reset-all modal. Bulk
reset stays available behind the panel's Reset button.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Compress paragraph-length comments across the new route layer to one or
two lines, keeping only the load-bearing rationale (per-render customId
reset, the add-page rule, off-page alreadyPresent semantics, the
blacklist/whitelist guard) and cutting restatement.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@altrup
altrup merged commit 3cced94 into main Jul 19, 2026
6 checks passed
@altrup
altrup deleted the embed-router-migration branch July 19, 2026 22:35
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant