console: let self-managed instances set a display name - #38691
console: let self-managed instances set a display name#38691djahandarie wants to merge 1 commit into
Conversation
Alphadelta14
left a comment
There was a problem hiding this comment.
I'd feel most comfortable if we made the displayName (okay with) and accents as discrete changes (need coordinated direction on this one)
| * is the default, and names the shades the rest of the palette was designed | ||
| * around. | ||
| */ | ||
| const ACCENT_SHADES: Record< |
There was a problem hiding this comment.
feels like this is built from scratch more than taken from our theme/colors.ts.
And if we were to be looking at alternative skinning, I'd normally recommend using a slightly more even palette.
Like a single hue sequential
https://colorbrewer2.org/#type=sequential&scheme=Purples&n=9
or a multi-hue sequential
https://colorbrewer2.org/#type=sequential&scheme=BuPu&n=9
Or for a Paired set
https://colorbrewer2.org/#type=qualitative&scheme=Paired&n=12
(You'd remove the ones that don't make sense)
but we'd probably need proper design input on this.
There was a problem hiding this comment.
Moved to #38720 along with the rest of the accent work, so this can be settled there.
You're right that it's built rather than taken. The table exists because theme/colors.ts wasn't drawn as a set of interchangeable accents: the hues don't run parallel, so reading purple's positions for every hue puts green[500] link text at 3.3:1 on white and paints the primary button in red[600], which is a muted brick next to that ramp's crimson. Picking shades per hue was the smallest way to keep contrast honest, not a claim that it's the right palette.
An even scale designed for the purpose is the better fix, and it would collapse the table back to a single rule and give more than three hues to choose from. I've noted the colorbrewer sequential/qualitative sets in #38720 and left a TODO at the table pointing at the same question, so it's blocked on design input rather than merged on my judgment.
| /// appends it to its browser tab title. | ||
| #[serde(skip_serializing_if = "Option::is_none")] | ||
| pub display_name: Option<String>, | ||
| /// The hue the console accents its interface with: `blue`, `green`, |
There was a problem hiding this comment.
I don't like having all of the distinct values in our comment. but I guess we don't show our enum values in our docs... 😒
There was a problem hiding this comment.
Fixed the underlying cause instead, in #38720: 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 the field documents its own values and the prose list is gone.
Side effect worth knowing about: privateKeyAlgorithm picks up the RSA/ECDSA/Ed25519 list it was also missing, so that entry in the generated reference changes too.
This PR no longer has an enum in it at all, so the comment you were looking at is gone from here either way.
| > = { | ||
| purple: { light: { primary: 600, bright: 500 }, dark: { primary: 400 } }, | ||
| // Red is muted rather than vivid at 600, so it accents a shade lighter. | ||
| red: { light: { primary: 500, bright: 500 }, dark: { primary: 400 } }, |
There was a problem hiding this comment.
accents should exclude red and green options to not be too conflicting with errors in the console (hard to find errors on a red page).
There was a problem hiding this comment.
Done in #38720: red and green are no longer offered, leaving blue, orange, and purple (purple so an operator can pin the default explicitly). The enum's doc comment records why they're absent, so it doesn't get "helpfully" re-added later.
Worth flagging the cost, since red for production is the case operators reach for first: with three hues, one of which is the default, there are two real choices for telling instances apart. That's another reason the palette question in the other thread matters, since a wider even scale would give non-conflicting hues to spend.
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>
d3b9dee to
150f13d
Compare
|
Split as asked. This PR is now #38720 carries the accent work, stacked on this branch and left as a draft pending design direction on the palette. It also picks up your other two comments: red and green are gone, and Rebased onto current main while I was in there. The screenshots above are from the combined version, so the accent ones belong to #38720 now. |
|
(Asked Claude to do one pass to handle the comments, sorry for the Claude-speak responses on here) |





What
Adds an optional
spec.consoleAppearanceto the Materialize CRD so that eachself-managed instance's console can name itself:
The console appends the name to its browser tab title, e.g.
Materialize Console · prod. The field is optional, and has no effect in Materialize Cloud,which serves a single console for all of an organization's regions.
Recoloring the console's accent was originally part of this change and has
moved to #38720 per review, so that it can be discussed on its own.
Why
Every console looks identical, so an operator running more than one Materialize
instance cannot tell from a browser tab which instance a console is pointed at.
The only distinguishing signal today is the URL, which is easy to miss, so a
change intended for a dev instance is one tab away from landing on production.
The workarounds are per-instance browser profiles or a patched console image,
and neither survives an upgrade.
How
The console already fetches an
app-config.jsonthat orchestratord rendersfrom the Console resource, so this reuses that channel instead of adding one:
Materialize.spec.consoleAppearance→Console.spec.appearance→app-config.json→appConfig.appearancein the console.The title is set from that config before the console authenticates, so the name
is on the login screen too.
consoleAppearanceis a struct rather than a flatconsoleDisplayNameso thatfurther per-instance appearance settings can join it without another top-level
field.
consoleAppearanceis excluded from the rollout hash and is skipped duringserialization when unset. Setting or changing it therefore reconciles only the
console's ConfigMap, which the console picks up on its next page load with no
pod restart, and adopting an operator version that knows the field does not
roll instances that leave it unset.
The CRD field reference under
doc/user/data/self_managed/is regenerated withthe
crd-writerstep thatbin/bump-versionruns.Tests
console_appearance_does_not_affect_the_rollout_hashinmz-cloud-resourcescovers both rollout-hash properties above.
ConsoleAppearancemodification intest/orchestratord/mzcompose.pycovers the passthrough from the Materialize CR to the console's
app-config.json.The subjective part: where this configuration belongs
The field sits on the Materialize CR and is exempt from the rollout hash. That
is the choice in this change I would most like a second opinion on, so here is
the reasoning and what it costs.
Why the CR. It is where every other per-instance console setting already
lives (
consoleReplicas,consoleResourceRequirements,consoleExternalCertificateSpec), so it is where an operator already looks.It is declarative and versioned alongside the rest of the instance, and it
reaches the browser through the
app-config.jsonthe operator already writes,so no new delivery mechanism has to be built or watched.
What that costs. A field on a versioned CRD is close to permanent: it has
to be carried through both CRD versions and the conversion webhook, which is
the bulk of the Rust in this diff, and withdrawing it later is a breaking API
change. It also puts presentation into an API whose every other field describes
infrastructure, which invites the follow-on requests (a logo, a favicon,
arbitrary CSS) that this deliberately does not open the door to.
The rollout-hash exemption is a smaller but real burden. Exclusion is enforced
by a hand-maintained struct literal in
generate_rollout_hashplus askip_serializing_if, neither of which is visible from the field's type, andgetting it wrong means a cosmetic edit rolls production. Exempting it is not
optional though: a retitle that costs an environmentd rollout is a feature
nobody would use. The precedent is already set by
consoleReplicasand bothservices' resource requirements, so this follows an existing pattern rather
than inventing an exemption. If the pattern deserves a stronger mechanism than
prose plus a struct literal, that is worth its own change.
Alternatives, and why I did not take them.
systemParameterConfigmapName). Wrongconsumer, and too late in the boot sequence. Those are database settings that
environmentd applies and
SHOW ALLreports, and nothing in environmentdneeds to know what the console calls itself. More decisively, the console
fetches
app-config.jsonbefore it authenticates, so the name is on thelogin screen. Anything sourced over SQL cannot be, because it would need a
session first.
alternative if we would rather keep the CRD strictly about infrastructure.
It keeps cosmetics out of a permanent API and cannot touch a
rollout-relevant field by construction. It costs a second object to create
and own, RBAC and orphan handling, no schema validation, and drift from the
manifest that describes the rest of the instance. It is more machinery than
a CRD field, not less.
light and dark switcher does. It is per browser, so it protects whoever sets
it and nobody else, which is the exact failure this feature exists to
prevent. Worth having as a complement, wrong as the primary.
files behind nginx with no server of its own, so persistence would mean the
catalog, which lands back on the first bullet and adds a write path and
privileges to design.
the workarounds this replaces. The operator owns the Deployment and
overwrites the env var, and a patched image has to be rebuilt on every
upgrade.
instances, and this is per instance.
Notes for reviewers
displayNamecould default tometadata.namerather than being configuredat all, which would give every instance a useful tab title with no
configuration. I kept it explicit because that name is often neither short
nor human: the install docs name the CR
12345678-1234-1234-1234-123456789012. But if we would rather have thezero-config version, this feature needs no new field at all.
🤖 Generated with Claude Code