feat: add theme_mode, theme_light, theme_dark to UserAppearanceSettings (#25076)

Part 1: Backend portion of a change broken into 2 PRs.
Part 2: #25077 

Adds three new UserAppearanceSettings fields (theme_mode, theme_light,
theme_dark) on top of the existing theme_preference and terminal_font.
Replaces GetUserThemePreference and GetUserTerminalFont with a single
GetUserAppearanceSettings aggregate query. The PUT handler is wrapped in
db.InTx so sync-mode's mode + slot writes can never half-apply.
This commit is contained in:
Jaayden Halko
2026-05-14 11:44:05 +07:00
committed by GitHub
parent d147dd3bdd
commit 024132e8a4
23 changed files with 1209 additions and 223 deletions
+42 -8
View File
@@ -12518,6 +12518,20 @@ Restarts will only happen on weekdays in this list on weeks which line up with W
|-------------------------------------------------------------------------------------|
| ``, `fira-code`, `geist-mono`, `ibm-plex-mono`, `jetbrains-mono`, `source-code-pro` |
## codersdk.ThemeMode
```json
""
```
### Properties
#### Enumerated Values
| Value(s) |
|----------------------|
| ``, `single`, `sync` |
## codersdk.ThinkingDisplayMode
```json
@@ -12846,16 +12860,30 @@ Restarts will only happen on weekdays in this list on weeks which line up with W
```json
{
"terminal_font": "",
"theme_dark": "light",
"theme_light": "light",
"theme_mode": "sync",
"theme_preference": "string"
}
```
### Properties
| Name | Type | Required | Restrictions | Description |
|--------------------|--------------------------------------------------------|----------|--------------|-------------|
| `terminal_font` | [codersdk.TerminalFontName](#codersdkterminalfontname) | true | | |
| `theme_preference` | string | true | | |
| Name | Type | Required | Restrictions | Description |
|--------------------|--------------------------------------------------------|----------|--------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| `terminal_font` | [codersdk.TerminalFontName](#codersdkterminalfontname) | true | | |
| `theme_dark` | string | false | | Theme dark is required when ThemeMode is "sync". In "single" mode an empty value means "preserve the previously persisted slot" rather than "clear the slot", so partial updates that send only one slot keep the other intact. |
| `theme_light` | string | false | | Theme light is required when ThemeMode is "sync". In "single" mode an empty value means "preserve the previously persisted slot" rather than "clear the slot", so partial updates that send only one slot keep the other intact. |
| `theme_mode` | [codersdk.ThemeMode](#codersdkthememode) | false | | Theme mode is optional for backward compatibility. When empty, the server leaves theme_mode, theme_light, and theme_dark unchanged so older CLI clients do not erase sync-mode settings. Legacy auto preferences are the exception: they clear theme_mode so clients can migrate the old sync-with-system setting. |
| `theme_preference` | string | true | | |
#### Enumerated Values
| Property | Value(s) |
|---------------|---------------------------------------------------------------------------------------------|
| `theme_dark` | `dark`, `dark-protan-deuter`, `dark-tritan`, `light`, `light-protan-deuter`, `light-tritan` |
| `theme_light` | `dark`, `dark-protan-deuter`, `dark-tritan`, `light`, `light-protan-deuter`, `light-tritan` |
| `theme_mode` | `single`, `sync` |
## codersdk.UpdateUserNotificationPreferences
@@ -13344,16 +13372,22 @@ If the schedule is empty, the user will be updated to use the default schedule.|
```json
{
"terminal_font": "",
"theme_dark": "string",
"theme_light": "string",
"theme_mode": "",
"theme_preference": "string"
}
```
### Properties
| Name | Type | Required | Restrictions | Description |
|--------------------|--------------------------------------------------------|----------|--------------|-------------|
| `terminal_font` | [codersdk.TerminalFontName](#codersdkterminalfontname) | false | | |
| `theme_preference` | string | false | | |
| Name | Type | Required | Restrictions | Description |
|--------------------|--------------------------------------------------------|----------|--------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| `terminal_font` | [codersdk.TerminalFontName](#codersdkterminalfontname) | false | | |
| `theme_dark` | string | false | | Ignored when ThemeMode is "single" |
| `theme_light` | string | false | | Ignored when ThemeMode is "single" |
| `theme_mode` | [codersdk.ThemeMode](#codersdkthememode) | false | | |
| `theme_preference` | string | false | | Theme preference is the legacy single-field appearance setting. In "single" mode it mirrors the active theme. In "sync" mode modern clients normally mirror the active OS slot, but older clients can update only this field, so it may diverge from ThemeLight or ThemeDark until a modern client saves the full appearance state again. |
## codersdk.UserLatency
+9
View File
@@ -547,6 +547,9 @@ curl -X GET http://coder-server:8080/api/v2/users/{user}/appearance \
```json
{
"terminal_font": "",
"theme_dark": "string",
"theme_light": "string",
"theme_mode": "",
"theme_preference": "string"
}
```
@@ -578,6 +581,9 @@ curl -X PUT http://coder-server:8080/api/v2/users/{user}/appearance \
```json
{
"terminal_font": "",
"theme_dark": "light",
"theme_light": "light",
"theme_mode": "sync",
"theme_preference": "string"
}
```
@@ -596,6 +602,9 @@ curl -X PUT http://coder-server:8080/api/v2/users/{user}/appearance \
```json
{
"terminal_font": "",
"theme_dark": "string",
"theme_light": "string",
"theme_mode": "",
"theme_preference": "string"
}
```