Skip to content

Land the dataops-family redesign on main - #31

Merged
alexeygrigorev merged 40 commits into
mainfrom
family/land-1002
Oct 2, 2026
Merged

alexeygrigorev merged 40 commits into
mainfrom
family/land-1002

Conversation

@alexeygrigorev

Copy link
Copy Markdown
Member

Lands the dataops-family redesign onto current main by merging origin/redesign/dataops-family (tip 5912faf) into origin/main (tip cdf3a9a).

What it does

  • Brings the full dataops-family UI redesign (family shell with sidebar navigation, banded panels, count meta and empty-state pills on list pages, campaign page with banded panels and segmented stage control, wrapped detail pages/forms/API docs, operator template test alignment) into main.
  • Preserves all of main's newer functionality: the inbound-mailbox feature (PR feat(mailbox): file inbound mail, and block the senders you mark as spam #27), separate admin API + staff-managed API keys (bc5768e), and the admin-nav link to admin API key management (cdf3a9a).

Conflict resolution (templates/base.html)

The only conflict. Resolution: the redesign's restructured shell wins (sidebar nav with icon links, {% with current_url_name=request.resolver_match.url_name %}, "Administer" nav group); main's functional change from cdf3a9a was re-applied inside the new shell — the Admin link now points to {% url 'mailing:admin_api_keys' %} with aria-current="page" on the admin_api_keys route, using the shell's current_url_name variable.

Verification

  • uv run pytest: 754 passed.
  • uv run ruff check .: all checks passed.

Vendor the dakit bundle (tokens + base + components, self-hosted fonts)
into static/dakit/ via scripts/sync_dakit.sh, which records the dakit
commit in static/dakit/PROVENANCE; relay has no Node build, so the
generated CSS is checked in like any other vendored dependency.

Load dakit before app.css in base.html, switch the theme boot script and
toggle to the shared dakit-theme storage key (migrating the old
datamailer.theme value once), and cover the wiring in the operator UI
test.
Replace the raw --dm-* color/type/space definitions with a compat shim
aliasing dakit's semantic tokens (dakit docs/adoption.md alias strategy),
so both themes resolve through dakit's contrast-verified palette — the
dark remap replaces relay's private dark values, which is the point of
the shared system. dakit gained the danger.hover role for relay's solid
danger buttons, so the last raw color goes too.

app.css keeps no token source of its own: base.html already links the
vendored bundle (static/dakit/dakit.css) first, so drop the duplicate
tokens copy, the local @font-face rules, and static/mailing/fonts — the
bundle serves the same self-hosted files from static/dakit/fonts. Also
drop the unused --border/--ink/--surface legacy aliases.
Mechanical rename of every call site through the shim mapping and delete
the shim — app.css now defines no tokens of its own. Radius follow dakit
canon: inputs, nav items and inset surfaces take the 4px step, buttons
and panels the 6px step. docs/design-system.md now describes the dakit
foundation, the vendored bundle, and the --dk-* roles.
The bundle's @font-face rules use ../fonts/ relative URLs, so dakit.css
must sit one level above the fonts directory — mirror dakit's dist/ +
fonts/ layout in static/dakit/ instead of flattening it. Fonts now load
instead of falling back to system faces.
Dakit's base layer now draws its own chevron on every non-multiple
select, 12px off the edge instead of the native arrow hugging it
(circled in the Active client screenshot). The synced bundle carries
it; the client-switcher's padding keeps its label clear of the glyph.

Note: this commit also carries the operator-UX additions another
session appended to app.css (skip link, sidebar current-client,
local nav) — staged together by accident; content is theirs, left
intact here rather than rewritten under a concurrent writer.
…eme)

Carries the shared dropdown chevron and the theme-pinned color-scheme
from dakit's base layer; PROVENANCE records the source commit.
Making .secondary-section a card kept the section-header's and the
heading's own page-flow margin-tops, which stacked on the card's
padding-top into an empty band that read as a phantom bordered box
above Recent History / Recent Events.
The sidebar moves onto the page background with the product mark, an
icon-plus-text nav (16x16 stroke icons, the dakit icon language), and
the active-client select directly under the mark. Global links become
a slim toolbar over the canvas only, right-aligned like dataops.
Phones get a 64px top bar whose menu opens the nav as a drawer with a
scrim, Escape, and focus handling; collapsing still leaves a visible
restore control (icon rail).
Demote repeated and per-row actions to the quiet secondary (Use client,
filters, contact toolbar updates, API docs links, test-email apply), keep
the filled accent for the one primary action per view, alias it as
.button.primary, and restate destructive actions as dakit's outlined
danger instead of a filled red button. Button weight follows dakit's
medium.
Stats render as one segmented strip (hairline-divided cells in a single
bordered container) instead of loose cards, everywhere stats-grid is
used. Tables take dakit's uppercase quiet headers, badges take the
dk-badge geometry (small radius, 11px), timelines become divided rows
in one container, empty states are plain copy instead of boxes, and
focus rings unify on dakit's 2px focus-ring. The dashboard attention
queue becomes a banded panel like dataops' 'Needs your attention'.
The badge-tone change carried two forms (test send, cancel) whose views
live only in the uncommitted campaign-UI work, so every campaign detail
render crashed on reverse(). Drop the forms here until that work lands,
and re-point the detail and base-template assertions at the copy and
shell this branch actually ships.
The 1px-gap trick painted the container's border color across empty
grid tracks once eight worker cells wrapped. Give each cell its own
right/bottom hairline pulled 1px past its track instead; overflow
hidden clips the outer edges.
At 390px the toolbar clipped the theme toggle and wrapped the API Docs
label; global controls go icon-only at phone widths. The clients table
becomes labelled rows (the family spec's mobile table conversion) and
every narrow table-wrap gains a right-edge fade hinting sideways scroll.
The sidebar plane moves to --dk-bg-muted, nav rows take the family's
36px/10px geometry, the drawer scrim uses --dk-bg-backdrop instead of a
raw overlay color, and controls settle on --dk-radius-md with the
dataops focus ring. A toolbar account chip (avatar + sign-out) completes
the family toolbar, and an sr-only utility backs the visually-hidden
table headers.
Every stacked form now exits through one footer row above a top border
with the primary action first and Cancel after it, per the family spec.
The receiving-address form moves its submit out of the field grid into
that footer, and its count strip uses the shared stat cells instead of
margined sections inside the bordered container.
Campaigns, audiences, and clients carry data-labels and join the
stack-table pattern, so phone widths read one labelled row per record
instead of a clipped grid. The campaign table drops its fixed layout so
the six-column comparison fits the 1440 canvas without cutting off the
delivery column.
Lands origin/redesign/dataops-family (5912faf) on top of main (cdf3a9a).

Conflict: templates/base.html — main's admin-nav change (cdf3a9a) met the
redesign's full shell restructure. Resolution: the redesign's shell wins
(toolbar + account menu + icon sidebar with dakit bundle); main's functional
change is re-applied inside the new shell — the sidebar Administer 'Admin'
entry now links to {% url 'mailing:admin_api_keys' %} with aria-current on
admin_api_keys instead of the old /admin/ Django admin link. Django admin
remains reachable via the link on the Admin API Keys page (added by cdf3a9a).

Tests: uv run pytest — 754 passed; ruff clean.
@alexeygrigorev
alexeygrigorev merged commit 1e27605 into main Oct 2, 2026
1 check passed
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