Skip to content

console: recolor the console's accent per instance - #38720

Draft
djahandarie wants to merge 2 commits into
MaterializeInc:mainfrom
djahandarie:console-instance-accent
Draft

console: recolor the console's accent per instance#38720
djahandarie wants to merge 2 commits into
MaterializeInc:mainfrom
djahandarie:console-instance-accent

Conversation

@djahandarie

@djahandarie djahandarie commented Sep 9, 2026

Copy link
Copy Markdown
Contributor

Stacked on #38691, which adds spec.consoleAppearance.displayName. This is
the other half of that change, split out per review so the palette question can
be settled on its own. Draft until we have design direction on the palette
(see the open question below).

GitHub diffs this against main, so the file view below includes #38691's
commit as well. The accent change on its own is the second commit:
04f8b6a

What

Adds accentColor to spec.consoleAppearance, which recolors what the console
accents in Materialize purple: the active navigation item, primary buttons,
links, focus rings, and selection highlights.

spec:
  consoleAppearance:
    displayName: prod
    accentColor: orange

Colors that carry meaning are left alone, so an error stays red and a healthy
object stays green. The default is unchanged: an instance that configures
nothing renders exactly as it does today, which a test pins.

Red and green are not offered, per review: the console already spends both on
meaning, and an error is hard to find on a red page. That leaves blue,
orange, and purple, where purple lets an operator pin the default
explicitly.

Open question: the palette

The palette's hues do not run parallel. A shade that is vivid in one hue is
muted or washed out in another, so reading purple's shade positions for every
hue would drop some link text below 4.5:1 against the page and would paint the
primary button in a muted brick rather than a vivid one. theme/accent.ts
therefore names the shades each hue accents with, and a test holds every hue to
4.5:1 for accented text and surfaces.

That table is the weakest part of this change, and it is a symptom rather than
a fix: theme/colors.ts was drawn for a purple product with semantic
accents, not as a set of interchangeable skins. An even scale designed for the
purpose, along the lines of the colorbrewer sequential or qualitative sets
raised in review, would let this be a single rule instead of a per-hue table,
and would give a wider set of hues than three. That needs design input, which
is why this is a draft. A TODO in accent.ts records the same thing.

How

Both palettes read their accent tokens from theme/accent.ts, so every
consumer of accent.purple, accent.brightPurple and background.accent
follows automatically, including the theme's own Button, Radio and Tabs
overrides.

Accent values the themes had hardcoded become palette tokens so that they
follow the accent as well: the active navigation item's wash (an inline
rgba(90, 52, 203, 0.2) in NavItem, whose comment already wished it were a
token), both themes' input focus rings, and three components that read raw
colors.purple[…] shades. The light focus ring moves from
hsla(257, 100%, 65%, 0.24) to purple[400] at the same opacity, which the
hsla was approximating to within one unit of green.

accentColor names a hue rather than carrying a CSS color, so no arbitrary
value can reach the DOM, and an orchestratord newer than the console it serves
falls back to purple rather than rendering an unresolvable color.

Also here: enum values in the generated field reference

crd-writer only listed an enum's values when its variants carried doc
comments, because schemars describes those with oneOf and a bare enum with a
plain array of values. It now reads both. So accentColor documents its own
values instead of repeating them in prose, which is what review asked for, and
privateKeyAlgorithm picks up the RSA/ECDSA/Ed25519 list it was missing.
That second change is visible in the regenerated reference and is the only
behavior change outside this feature.

Tests

  • Console unit tests cover the accent color's app-config parsing (including a
    value the build does not know), the default palette reproducing the shades
    the themes hardcoded, and the contrast floor every hue's shades hold.
  • The orchestratord modification and the rollout-hash test grow to cover the
    new field.

Notes for reviewers

  • accent.purple and accent.brightPurple now carry whatever hue is
    configured, which their names no longer describe. Renaming them to role names
    touches 112 call sites, so it is not in this change; the contract is
    documented on BasePalette instead. Happy to do the rename first if
    preferred.

🤖 Generated with Claude Code

djahandarie and others added 2 commits September 9, 2026 12:20
Consoles are otherwise identical, so an operator running several
Materialize instances cannot tell from a browser tab which instance a
console is pointed at, and a change meant for dev is one tab away from
landing on prod.

Adds `spec.consoleAppearance` to the Materialize CRD:

    spec:
      consoleAppearance:
        displayName: prod

Orchestratord copies it onto the Console resource and into the
`app-config.json` it already writes for the console, so no new
configuration channel and no console rollout are needed to pick it up.
The console appends the name to its browser tab title. It sets the title
from the app config before authenticating, so the name is there on the
login screen too.

`consoleAppearance` is a struct rather than a flat `consoleDisplayName`
so that further per-instance appearance settings can join it without
another top-level field.

The field is optional and has no effect in Cloud, which serves one
console for all of an organization's regions. It is excluded from the
rollout hash and skipped when unset, so setting it does not roll
environmentd, and adopting a version of the operator that knows about it
does not roll instances that leave it unset.

Tests: adds `console_appearance_does_not_affect_the_rollout_hash` in
`mz-cloud-resources` and a `ConsoleAppearance` modification in
`test/orchestratord/mzcompose.py` covering the passthrough into
`app-config.json`, plus console unit tests for the tab title and the
app-config parsing.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Follows the display name in MaterializeInc#38691, which named an instance in its
browser tab title. This lets an instance also recolor what the console
accents in Materialize purple: the active navigation item, primary
buttons, links, focus rings and selection highlights.

    spec:
      consoleAppearance:
        displayName: prod
        accentColor: orange

Red and green are deliberately not offered. The console already spends
both on meaning, and an error is hard to find on a red page.

The palette's hues don't run parallel, so a hue that is vivid at one
shade is muted at the same shade of another. `theme/accent.ts` names the
shades each hue accents with, holds accented text and surfaces to 4.5:1
against what they sit against, and reproduces purple's shades exactly
when nothing is configured. Accent values the themes had hardcoded, the
active navigation item's wash and both focus rings, become palette
tokens so they follow the accent too.

`crd-writer` only listed an enum's values in the generated field
reference when its variants carried doc comments, because schemars
describes those with `oneOf` and a bare enum with a plain array of
values. It now reads both, so `accentColor` documents its own values
rather than repeating them in prose, and `privateKeyAlgorithm` picks up
the values it was missing.

Tests: extends the console unit tests with the accent color's
app-config parsing, the default palette reproducing the hardcoded purple
shades, and the contrast each hue's shades hold. The orchestratord
modification and the rollout-hash test grow to cover the new field.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
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