From c309664a3dab292131c4222cd4ebe38c579a84a4 Mon Sep 17 00:00:00 2001 From: Marcin Tojek Date: Fri, 4 Apr 2025 10:12:57 +0200 Subject: [PATCH 01/22] feat: switch terminal fonts --- site/package.json | 1 + site/pnpm-lock.yaml | 8 ++++++++ site/src/pages/TerminalPage/TerminalPage.tsx | 4 ++-- site/src/theme/constants.ts | 5 +++++ site/src/theme/globalFonts.ts | 3 +++ 5 files changed, 19 insertions(+), 2 deletions(-) diff --git a/site/package.json b/site/package.json index d9fd1fbec2b05..bc40e094df28c 100644 --- a/site/package.json +++ b/site/package.json @@ -42,6 +42,7 @@ "@emotion/styled": "11.14.0", "@fastly/performance-observer-polyfill": "2.0.0", "@fontsource-variable/inter": "5.1.1", + "@fontsource/fira-code": "5.2.5", "@fontsource/ibm-plex-mono": "5.1.1", "@monaco-editor/react": "4.6.0", "@mui/icons-material": "5.16.14", diff --git a/site/pnpm-lock.yaml b/site/pnpm-lock.yaml index 55c4c955da4d9..3b7ff150e36ef 100644 --- a/site/pnpm-lock.yaml +++ b/site/pnpm-lock.yaml @@ -40,6 +40,9 @@ importers: '@fontsource-variable/inter': specifier: 5.1.1 version: 5.1.1 + '@fontsource/fira-code': + specifier: 5.2.5 + version: 5.2.5 '@fontsource/ibm-plex-mono': specifier: 5.1.1 version: 5.1.1 @@ -1034,6 +1037,9 @@ packages: '@fontsource-variable/inter@5.1.1': resolution: {integrity: sha512-OpXFTmiH6tHkYijMvQTycFKBLK4X+SRV6tet1m4YOUH7SzIIlMqDja+ocDtiCA72UthBH/vF+3ZtlMr2rN/wIw==, tarball: https://registry.npmjs.org/@fontsource-variable/inter/-/inter-5.1.1.tgz} + '@fontsource/fira-code@5.2.5': + resolution: {integrity: sha512-Rn9PJoyfRr5D6ukEhZpzhpD+rbX2rtoz9QjkOuGxqFxrL69fQvhadMUBxQIOuTF4sTTkPRSKlAEpPjTKaI12QA==, tarball: https://registry.npmjs.org/@fontsource/fira-code/-/fira-code-5.2.5.tgz} + '@fontsource/ibm-plex-mono@5.1.1': resolution: {integrity: sha512-1aayqPe/ZkD3MlvqpmOHecfA3f2B8g+fAEkgvcCd3lkPP0pS1T0xG5Zmn2EsJQqr1JURtugPUH+5NqvKyfFZMQ==, tarball: https://registry.npmjs.org/@fontsource/ibm-plex-mono/-/ibm-plex-mono-5.1.1.tgz} @@ -6954,6 +6960,8 @@ snapshots: '@fontsource-variable/inter@5.1.1': {} + '@fontsource/fira-code@5.2.5': {} + '@fontsource/ibm-plex-mono@5.1.1': {} '@humanwhocodes/config-array@0.11.14': diff --git a/site/src/pages/TerminalPage/TerminalPage.tsx b/site/src/pages/TerminalPage/TerminalPage.tsx index c86a3f9ed5396..d1ad415fb48e0 100644 --- a/site/src/pages/TerminalPage/TerminalPage.tsx +++ b/site/src/pages/TerminalPage/TerminalPage.tsx @@ -18,7 +18,7 @@ import { Helmet } from "react-helmet-async"; import { useQuery } from "react-query"; import { useNavigate, useParams, useSearchParams } from "react-router-dom"; import themes from "theme"; -import { MONOSPACE_FONT_FAMILY } from "theme/constants"; +import { MONOSPACE_FONT_FAMILY, TERMINAL_FONT_FAMILY_2 } from "theme/constants"; import { pageTitle } from "utils/page"; import { openMaybePortForwardedURL } from "utils/portForward"; import { terminalWebsocketUrl } from "utils/terminal"; @@ -110,7 +110,7 @@ const TerminalPage: FC = () => { allowProposedApi: true, allowTransparency: true, disableStdin: false, - fontFamily: MONOSPACE_FONT_FAMILY, + fontFamily: TERMINAL_FONT_FAMILY_2, fontSize: 16, theme: { background: theme.palette.background.default, diff --git a/site/src/theme/constants.ts b/site/src/theme/constants.ts index b95998640efde..63092b0f99650 100644 --- a/site/src/theme/constants.ts +++ b/site/src/theme/constants.ts @@ -1,6 +1,11 @@ export const borderRadius = 8; export const MONOSPACE_FONT_FAMILY = "'IBM Plex Mono', 'Lucida Console', 'Lucida Sans Typewriter', 'Liberation Mono', 'Monaco', 'Courier New', Courier, monospace"; +export const TERMINAL_FONT_FAMILY_1 = MONOSPACE_FONT_FAMILY; +export const TERMINAL_FONT_FAMILY_2 = MONOSPACE_FONT_FAMILY.replace( + "IBM Plex Mono", + "Fira Code", +); export const BODY_FONT_FAMILY = `"Inter Variable", system-ui, sans-serif`; export const navHeight = 62; export const containerWidth = 1380; diff --git a/site/src/theme/globalFonts.ts b/site/src/theme/globalFonts.ts index 24371dd57568e..db8089f9db266 100644 --- a/site/src/theme/globalFonts.ts +++ b/site/src/theme/globalFonts.ts @@ -3,3 +3,6 @@ import "@fontsource/ibm-plex-mono/400.css"; import "@fontsource/ibm-plex-mono/600.css"; // Main body copy font import "@fontsource-variable/inter"; +// Alternative font for Terminal +import "@fontsource/fira-code/400.css"; +import "@fontsource/fira-code/600.css"; From d9e9627e7d038bf6dd176939f30465e6b6cbc3fa Mon Sep 17 00:00:00 2001 From: Marcin Tojek Date: Fri, 4 Apr 2025 10:46:11 +0200 Subject: [PATCH 02/22] Rename GetAppearanceSettings to GetUserThemePreferences --- .../TestProvisioners_Golden/list.golden | 2 +- cli/testdata/coder_provisioner_list.golden | 2 +- coderd/apidoc/docs.go | 36 ++++++++ coderd/apidoc/swagger.json | 27 +++++- coderd/database/dbauthz/dbauthz.go | 44 +++++----- coderd/database/dbauthz/dbauthz_test.go | 8 +- coderd/database/dbmem/dbmem.go | 82 ++++++++--------- coderd/database/dbmetrics/querymetrics.go | 28 +++--- coderd/database/dbmock/dbmock.go | 60 ++++++------- coderd/database/querier.go | 4 +- coderd/database/queries.sql.go | 88 +++++++++---------- coderd/database/queries/users.sql | 4 +- coderd/users.go | 4 +- codersdk/users.go | 15 +++- docs/reference/api/schemas.md | 46 ++++++++-- docs/reference/api/users.md | 3 + .../terraform/testdata/resources/version.txt | 2 +- site/site.go | 2 +- site/src/api/typesGenerated.ts | 11 +++ 19 files changed, 294 insertions(+), 174 deletions(-) diff --git a/cli/testdata/TestProvisioners_Golden/list.golden b/cli/testdata/TestProvisioners_Golden/list.golden index 3f50f90746744..35844d8b9c50e 100644 --- a/cli/testdata/TestProvisioners_Golden/list.golden +++ b/cli/testdata/TestProvisioners_Golden/list.golden @@ -1,4 +1,4 @@ -ID CREATED AT LAST SEEN AT NAME VERSION TAGS KEY NAME STATUS CURRENT JOB ID CURRENT JOB STATUS PREVIOUS JOB ID PREVIOUS JOB STATUS ORGANIZATION +ID CREATED AT LAST SEEN AT NAME VERSION TAGS KEY NAME STATUS CURRENT JOB ID CURRENT JOB STATUS PREVIOUS JOB ID PREVIOUS JOB STATUS ORGANIZATION 00000000-0000-0000-aaaa-000000000000 ====[timestamp]===== ====[timestamp]===== default-provisioner v0.0.0-devel map[owner: scope:organization] built-in idle 00000000-0000-0000-bbbb-000000000001 succeeded Coder 00000000-0000-0000-aaaa-000000000001 ====[timestamp]===== ====[timestamp]===== provisioner-1 v0.0.0 map[foo:bar owner: scope:organization] built-in busy 00000000-0000-0000-bbbb-000000000002 running Coder 00000000-0000-0000-aaaa-000000000002 ====[timestamp]===== ====[timestamp]===== provisioner-2 v0.0.0 map[owner: scope:organization] built-in offline 00000000-0000-0000-bbbb-000000000003 succeeded Coder diff --git a/cli/testdata/coder_provisioner_list.golden b/cli/testdata/coder_provisioner_list.golden index 64941eebf5b89..e34db5605fd81 100644 --- a/cli/testdata/coder_provisioner_list.golden +++ b/cli/testdata/coder_provisioner_list.golden @@ -1,2 +1,2 @@ -CREATED AT LAST SEEN AT KEY NAME NAME VERSION STATUS TAGS +CREATED AT LAST SEEN AT KEY NAME NAME VERSION STATUS TAGS ====[timestamp]===== ====[timestamp]===== built-in test v0.0.0-devel idle map[owner: scope:organization] diff --git a/coderd/apidoc/docs.go b/coderd/apidoc/docs.go index c93af6a64a41c..bc11caf62facf 100644 --- a/coderd/apidoc/docs.go +++ b/coderd/apidoc/docs.go @@ -15595,6 +15595,19 @@ const docTemplate = `{ "TemplateVersionWarningUnsupportedWorkspaces" ] }, + "codersdk.TerminalFontName": { + "type": "string", + "enum": [ + "", + "ibm-mono-plex", + "fira-code" + ], + "x-enum-varnames": [ + "TerminalFontUnknown", + "TerminalFontIbmMonoPlex", + "TerminalFontFiraCode" + ] + }, "codersdk.TimingStage": { "type": "string", "enum": [ @@ -15768,9 +15781,21 @@ const docTemplate = `{ "codersdk.UpdateUserAppearanceSettingsRequest": { "type": "object", "required": [ + "terminal_font", "theme_preference" ], "properties": { + "terminal_font": { + "enum": [ + "ibm-mono-plex", + "fira-code" + ], + "allOf": [ + { + "$ref": "#/definitions/codersdk.TerminalFontName" + } + ] + }, "theme_preference": { "type": "string" } @@ -16062,6 +16087,17 @@ const docTemplate = `{ "codersdk.UserAppearanceSettings": { "type": "object", "properties": { + "terminal_font": { + "enum": [ + "ibm-mono-plex", + "fira-code" + ], + "allOf": [ + { + "$ref": "#/definitions/codersdk.TerminalFontName" + } + ] + }, "theme_preference": { "type": "string" } diff --git a/coderd/apidoc/swagger.json b/coderd/apidoc/swagger.json index da4d7a4fcf41c..a9cdae584b627 100644 --- a/coderd/apidoc/swagger.json +++ b/coderd/apidoc/swagger.json @@ -14180,6 +14180,15 @@ "enum": ["UNSUPPORTED_WORKSPACES"], "x-enum-varnames": ["TemplateVersionWarningUnsupportedWorkspaces"] }, + "codersdk.TerminalFontName": { + "type": "string", + "enum": ["", "ibm-mono-plex", "fira-code"], + "x-enum-varnames": [ + "TerminalFontUnknown", + "TerminalFontIbmMonoPlex", + "TerminalFontFiraCode" + ] + }, "codersdk.TimingStage": { "type": "string", "enum": [ @@ -14350,8 +14359,16 @@ }, "codersdk.UpdateUserAppearanceSettingsRequest": { "type": "object", - "required": ["theme_preference"], + "required": ["terminal_font", "theme_preference"], "properties": { + "terminal_font": { + "enum": ["ibm-mono-plex", "fira-code"], + "allOf": [ + { + "$ref": "#/definitions/codersdk.TerminalFontName" + } + ] + }, "theme_preference": { "type": "string" } @@ -14617,6 +14634,14 @@ "codersdk.UserAppearanceSettings": { "type": "object", "properties": { + "terminal_font": { + "enum": ["ibm-mono-plex", "fira-code"], + "allOf": [ + { + "$ref": "#/definitions/codersdk.TerminalFontName" + } + ] + }, "theme_preference": { "type": "string" } diff --git a/coderd/database/dbauthz/dbauthz.go b/coderd/database/dbauthz/dbauthz.go index 3815f713c0f4e..e496eda90ea54 100644 --- a/coderd/database/dbauthz/dbauthz.go +++ b/coderd/database/dbauthz/dbauthz.go @@ -1061,6 +1061,28 @@ func (q *querier) customRoleCheck(ctx context.Context, role database.CustomRole) return nil } +func (q *querier) GetUserThemePreference(ctx context.Context, userID uuid.UUID) (string, error) { + u, err := q.db.GetUserByID(ctx, userID) + if err != nil { + return "", err + } + if err := q.authorizeContext(ctx, policy.ActionReadPersonal, u); err != nil { + return "", err + } + return q.db.GetUserThemePreference(ctx, userID) +} + +func (q *querier) UpdateUserThemePreference(ctx context.Context, arg database.UpdateUserThemePreferenceParams) (database.UserConfig, error) { + u, err := q.db.GetUserByID(ctx, arg.UserID) + if err != nil { + return database.UserConfig{}, err + } + if err := q.authorizeContext(ctx, policy.ActionUpdatePersonal, u); err != nil { + return database.UserConfig{}, err + } + return q.db.UpdateUserThemePreference(ctx, arg) +} + func (q *querier) AcquireLock(ctx context.Context, id int64) error { return q.db.AcquireLock(ctx, id) } @@ -2711,17 +2733,6 @@ func (q *querier) GetUserActivityInsights(ctx context.Context, arg database.GetU return q.db.GetUserActivityInsights(ctx, arg) } -func (q *querier) GetUserAppearanceSettings(ctx context.Context, userID uuid.UUID) (string, error) { - u, err := q.db.GetUserByID(ctx, userID) - if err != nil { - return "", err - } - if err := q.authorizeContext(ctx, policy.ActionReadPersonal, u); err != nil { - return "", err - } - return q.db.GetUserAppearanceSettings(ctx, userID) -} - func (q *querier) GetUserByEmailOrUsername(ctx context.Context, arg database.GetUserByEmailOrUsernameParams) (database.User, error) { return fetch(q.log, q.auth, q.db.GetUserByEmailOrUsername)(ctx, arg) } @@ -4311,17 +4322,6 @@ func (q *querier) UpdateTemplateWorkspacesLastUsedAt(ctx context.Context, arg da return fetchAndExec(q.log, q.auth, policy.ActionUpdate, fetch, q.db.UpdateTemplateWorkspacesLastUsedAt)(ctx, arg) } -func (q *querier) UpdateUserAppearanceSettings(ctx context.Context, arg database.UpdateUserAppearanceSettingsParams) (database.UserConfig, error) { - u, err := q.db.GetUserByID(ctx, arg.UserID) - if err != nil { - return database.UserConfig{}, err - } - if err := q.authorizeContext(ctx, policy.ActionUpdatePersonal, u); err != nil { - return database.UserConfig{}, err - } - return q.db.UpdateUserAppearanceSettings(ctx, arg) -} - func (q *querier) UpdateUserDeletedByID(ctx context.Context, id uuid.UUID) error { return deleteQ(q.log, q.auth, q.db.GetUserByID, q.db.UpdateUserDeletedByID)(ctx, id) } diff --git a/coderd/database/dbauthz/dbauthz_test.go b/coderd/database/dbauthz/dbauthz_test.go index 0fe17f886b1b2..b110c1b17b327 100644 --- a/coderd/database/dbauthz/dbauthz_test.go +++ b/coderd/database/dbauthz/dbauthz_test.go @@ -1630,23 +1630,23 @@ func (s *MethodTestSuite) TestUser() { []database.GetUserWorkspaceBuildParametersRow{}, ) })) - s.Run("GetUserAppearanceSettings", s.Subtest(func(db database.Store, check *expects) { + s.Run("GetUserThemePreference", s.Subtest(func(db database.Store, check *expects) { ctx := context.Background() u := dbgen.User(s.T(), db, database.User{}) - db.UpdateUserAppearanceSettings(ctx, database.UpdateUserAppearanceSettingsParams{ + db.UpdateUserThemePreference(ctx, database.UpdateUserThemePreferenceParams{ UserID: u.ID, ThemePreference: "light", }) check.Args(u.ID).Asserts(u, policy.ActionReadPersonal).Returns("light") })) - s.Run("UpdateUserAppearanceSettings", s.Subtest(func(db database.Store, check *expects) { + s.Run("UpdateUserThemePreference", s.Subtest(func(db database.Store, check *expects) { u := dbgen.User(s.T(), db, database.User{}) uc := database.UserConfig{ UserID: u.ID, Key: "theme_preference", Value: "dark", } - check.Args(database.UpdateUserAppearanceSettingsParams{ + check.Args(database.UpdateUserThemePreferenceParams{ UserID: u.ID, ThemePreference: uc.Value, }).Asserts(u, policy.ActionUpdatePersonal).Returns(uc) diff --git a/coderd/database/dbmem/dbmem.go b/coderd/database/dbmem/dbmem.go index bfae69fa68b98..d76a6d0b7aacd 100644 --- a/coderd/database/dbmem/dbmem.go +++ b/coderd/database/dbmem/dbmem.go @@ -1379,6 +1379,47 @@ func (q *FakeQuerier) getProvisionerJobsByIDsWithQueuePositionLockedGlobalQueue( return jobs, nil } +func (q *FakeQuerier) GetUserThemePreference(_ context.Context, userID uuid.UUID) (string, error) { + q.mutex.RLock() + defer q.mutex.RUnlock() + + for _, uc := range q.userConfigs { + if uc.UserID != userID || uc.Key != "theme_preference" { + continue + } + return uc.Value, nil + } + + return "", sql.ErrNoRows +} + +func (q *FakeQuerier) UpdateUserThemePreference(_ context.Context, arg database.UpdateUserThemePreferenceParams) (database.UserConfig, error) { + err := validateDatabaseType(arg) + if err != nil { + return database.UserConfig{}, err + } + + q.mutex.Lock() + defer q.mutex.Unlock() + + for i, uc := range q.userConfigs { + if uc.UserID != arg.UserID || uc.Key != "theme_preference" { + continue + } + uc.Value = arg.ThemePreference + q.userConfigs[i] = uc + return uc, nil + } + + uc := database.UserConfig{ + UserID: arg.UserID, + Key: "theme_preference", + Value: arg.ThemePreference, + } + q.userConfigs = append(q.userConfigs, uc) + return uc, nil +} + func (*FakeQuerier) AcquireLock(_ context.Context, _ int64) error { return xerrors.New("AcquireLock must only be called within a transaction") } @@ -6434,20 +6475,6 @@ func (q *FakeQuerier) GetUserActivityInsights(_ context.Context, arg database.Ge return rows, nil } -func (q *FakeQuerier) GetUserAppearanceSettings(_ context.Context, userID uuid.UUID) (string, error) { - q.mutex.RLock() - defer q.mutex.RUnlock() - - for _, uc := range q.userConfigs { - if uc.UserID != userID || uc.Key != "theme_preference" { - continue - } - return uc.Value, nil - } - - return "", sql.ErrNoRows -} - func (q *FakeQuerier) GetUserByEmailOrUsername(_ context.Context, arg database.GetUserByEmailOrUsernameParams) (database.User, error) { if err := validateDatabaseType(arg); err != nil { return database.User{}, err @@ -10996,33 +11023,6 @@ func (q *FakeQuerier) UpdateTemplateWorkspacesLastUsedAt(_ context.Context, arg return nil } -func (q *FakeQuerier) UpdateUserAppearanceSettings(_ context.Context, arg database.UpdateUserAppearanceSettingsParams) (database.UserConfig, error) { - err := validateDatabaseType(arg) - if err != nil { - return database.UserConfig{}, err - } - - q.mutex.Lock() - defer q.mutex.Unlock() - - for i, uc := range q.userConfigs { - if uc.UserID != arg.UserID || uc.Key != "theme_preference" { - continue - } - uc.Value = arg.ThemePreference - q.userConfigs[i] = uc - return uc, nil - } - - uc := database.UserConfig{ - UserID: arg.UserID, - Key: "theme_preference", - Value: arg.ThemePreference, - } - q.userConfigs = append(q.userConfigs, uc) - return uc, nil -} - func (q *FakeQuerier) UpdateUserDeletedByID(_ context.Context, id uuid.UUID) error { q.mutex.Lock() defer q.mutex.Unlock() diff --git a/coderd/database/dbmetrics/querymetrics.go b/coderd/database/dbmetrics/querymetrics.go index b29d95752d195..b8abb638c6484 100644 --- a/coderd/database/dbmetrics/querymetrics.go +++ b/coderd/database/dbmetrics/querymetrics.go @@ -88,6 +88,20 @@ func (m queryMetricsStore) DeleteOrganization(ctx context.Context, id uuid.UUID) return r0 } +func (m queryMetricsStore) GetUserThemePreference(ctx context.Context, userID uuid.UUID) (string, error) { + start := time.Now() + r0, r1 := m.s.GetUserThemePreference(ctx, userID) + m.queryLatencies.WithLabelValues("GetUserThemePreference").Observe(time.Since(start).Seconds()) + return r0, r1 +} + +func (m queryMetricsStore) UpdateUserThemePreference(ctx context.Context, arg database.UpdateUserThemePreferenceParams) (database.UserConfig, error) { + start := time.Now() + r0, r1 := m.s.UpdateUserThemePreference(ctx, arg) + m.queryLatencies.WithLabelValues("UpdateUserThemePreference").Observe(time.Since(start).Seconds()) + return r0, r1 +} + func (m queryMetricsStore) AcquireLock(ctx context.Context, pgAdvisoryXactLock int64) error { start := time.Now() err := m.s.AcquireLock(ctx, pgAdvisoryXactLock) @@ -1502,13 +1516,6 @@ func (m queryMetricsStore) GetUserActivityInsights(ctx context.Context, arg data return r0, r1 } -func (m queryMetricsStore) GetUserAppearanceSettings(ctx context.Context, userID uuid.UUID) (string, error) { - start := time.Now() - r0, r1 := m.s.GetUserAppearanceSettings(ctx, userID) - m.queryLatencies.WithLabelValues("GetUserAppearanceSettings").Observe(time.Since(start).Seconds()) - return r0, r1 -} - func (m queryMetricsStore) GetUserByEmailOrUsername(ctx context.Context, arg database.GetUserByEmailOrUsernameParams) (database.User, error) { start := time.Now() user, err := m.s.GetUserByEmailOrUsername(ctx, arg) @@ -2727,13 +2734,6 @@ func (m queryMetricsStore) UpdateTemplateWorkspacesLastUsedAt(ctx context.Contex return r0 } -func (m queryMetricsStore) UpdateUserAppearanceSettings(ctx context.Context, arg database.UpdateUserAppearanceSettingsParams) (database.UserConfig, error) { - start := time.Now() - r0, r1 := m.s.UpdateUserAppearanceSettings(ctx, arg) - m.queryLatencies.WithLabelValues("UpdateUserAppearanceSettings").Observe(time.Since(start).Seconds()) - return r0, r1 -} - func (m queryMetricsStore) UpdateUserDeletedByID(ctx context.Context, id uuid.UUID) error { start := time.Now() r0 := m.s.UpdateUserDeletedByID(ctx, id) diff --git a/coderd/database/dbmock/dbmock.go b/coderd/database/dbmock/dbmock.go index e30759c6bba42..d00649c4e0cad 100644 --- a/coderd/database/dbmock/dbmock.go +++ b/coderd/database/dbmock/dbmock.go @@ -3139,21 +3139,6 @@ func (mr *MockStoreMockRecorder) GetUserActivityInsights(ctx, arg any) *gomock.C return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetUserActivityInsights", reflect.TypeOf((*MockStore)(nil).GetUserActivityInsights), ctx, arg) } -// GetUserAppearanceSettings mocks base method. -func (m *MockStore) GetUserAppearanceSettings(ctx context.Context, userID uuid.UUID) (string, error) { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "GetUserAppearanceSettings", ctx, userID) - ret0, _ := ret[0].(string) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// GetUserAppearanceSettings indicates an expected call of GetUserAppearanceSettings. -func (mr *MockStoreMockRecorder) GetUserAppearanceSettings(ctx, userID any) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetUserAppearanceSettings", reflect.TypeOf((*MockStore)(nil).GetUserAppearanceSettings), ctx, userID) -} - // GetUserByEmailOrUsername mocks base method. func (m *MockStore) GetUserByEmailOrUsername(ctx context.Context, arg database.GetUserByEmailOrUsernameParams) (database.User, error) { m.ctrl.T.Helper() @@ -3289,6 +3274,21 @@ func (mr *MockStoreMockRecorder) GetUserStatusCounts(ctx, arg any) *gomock.Call return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetUserStatusCounts", reflect.TypeOf((*MockStore)(nil).GetUserStatusCounts), ctx, arg) } +// GetUserThemePreference mocks base method. +func (m *MockStore) GetUserThemePreference(ctx context.Context, userID uuid.UUID) (string, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetUserThemePreference", ctx, userID) + ret0, _ := ret[0].(string) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetUserThemePreference indicates an expected call of GetUserThemePreference. +func (mr *MockStoreMockRecorder) GetUserThemePreference(ctx, userID any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetUserThemePreference", reflect.TypeOf((*MockStore)(nil).GetUserThemePreference), ctx, userID) +} + // GetUserWorkspaceBuildParameters mocks base method. func (m *MockStore) GetUserWorkspaceBuildParameters(ctx context.Context, arg database.GetUserWorkspaceBuildParametersParams) ([]database.GetUserWorkspaceBuildParametersRow, error) { m.ctrl.T.Helper() @@ -5768,21 +5768,6 @@ func (mr *MockStoreMockRecorder) UpdateTemplateWorkspacesLastUsedAt(ctx, arg any return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UpdateTemplateWorkspacesLastUsedAt", reflect.TypeOf((*MockStore)(nil).UpdateTemplateWorkspacesLastUsedAt), ctx, arg) } -// UpdateUserAppearanceSettings mocks base method. -func (m *MockStore) UpdateUserAppearanceSettings(ctx context.Context, arg database.UpdateUserAppearanceSettingsParams) (database.UserConfig, error) { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "UpdateUserAppearanceSettings", ctx, arg) - ret0, _ := ret[0].(database.UserConfig) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// UpdateUserAppearanceSettings indicates an expected call of UpdateUserAppearanceSettings. -func (mr *MockStoreMockRecorder) UpdateUserAppearanceSettings(ctx, arg any) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UpdateUserAppearanceSettings", reflect.TypeOf((*MockStore)(nil).UpdateUserAppearanceSettings), ctx, arg) -} - // UpdateUserDeletedByID mocks base method. func (m *MockStore) UpdateUserDeletedByID(ctx context.Context, id uuid.UUID) error { m.ctrl.T.Helper() @@ -5974,6 +5959,21 @@ func (mr *MockStoreMockRecorder) UpdateUserStatus(ctx, arg any) *gomock.Call { return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UpdateUserStatus", reflect.TypeOf((*MockStore)(nil).UpdateUserStatus), ctx, arg) } +// UpdateUserThemePreference mocks base method. +func (m *MockStore) UpdateUserThemePreference(ctx context.Context, arg database.UpdateUserThemePreferenceParams) (database.UserConfig, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "UpdateUserThemePreference", ctx, arg) + ret0, _ := ret[0].(database.UserConfig) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// UpdateUserThemePreference indicates an expected call of UpdateUserThemePreference. +func (mr *MockStoreMockRecorder) UpdateUserThemePreference(ctx, arg any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UpdateUserThemePreference", reflect.TypeOf((*MockStore)(nil).UpdateUserThemePreference), ctx, arg) +} + // UpdateVolumeResourceMonitor mocks base method. func (m *MockStore) UpdateVolumeResourceMonitor(ctx context.Context, arg database.UpdateVolumeResourceMonitorParams) error { m.ctrl.T.Helper() diff --git a/coderd/database/querier.go b/coderd/database/querier.go index 54483c2176f4e..d0aba4d376b3d 100644 --- a/coderd/database/querier.go +++ b/coderd/database/querier.go @@ -343,7 +343,6 @@ type sqlcQuerier interface { // produces a bloated value if a user has used multiple templates // simultaneously. GetUserActivityInsights(ctx context.Context, arg GetUserActivityInsightsParams) ([]GetUserActivityInsightsRow, error) - GetUserAppearanceSettings(ctx context.Context, userID uuid.UUID) (string, error) GetUserByEmailOrUsername(ctx context.Context, arg GetUserByEmailOrUsernameParams) (User, error) GetUserByID(ctx context.Context, id uuid.UUID) (User, error) GetUserCount(ctx context.Context, includeSystem bool) (int64, error) @@ -369,6 +368,7 @@ type sqlcQuerier interface { // We do not start counting from 0 at the start_time. We check the last status change before the start_time for each user. As such, // the result shows the total number of users in each status on any particular day. GetUserStatusCounts(ctx context.Context, arg GetUserStatusCountsParams) ([]GetUserStatusCountsRow, error) + GetUserThemePreference(ctx context.Context, userID uuid.UUID) (string, error) GetUserWorkspaceBuildParameters(ctx context.Context, arg GetUserWorkspaceBuildParametersParams) ([]GetUserWorkspaceBuildParametersRow, error) // This will never return deleted users. GetUsers(ctx context.Context, arg GetUsersParams) ([]GetUsersRow, error) @@ -570,7 +570,6 @@ type sqlcQuerier interface { UpdateTemplateVersionDescriptionByJobID(ctx context.Context, arg UpdateTemplateVersionDescriptionByJobIDParams) error UpdateTemplateVersionExternalAuthProvidersByJobID(ctx context.Context, arg UpdateTemplateVersionExternalAuthProvidersByJobIDParams) error UpdateTemplateWorkspacesLastUsedAt(ctx context.Context, arg UpdateTemplateWorkspacesLastUsedAtParams) error - UpdateUserAppearanceSettings(ctx context.Context, arg UpdateUserAppearanceSettingsParams) (UserConfig, error) UpdateUserDeletedByID(ctx context.Context, id uuid.UUID) error UpdateUserGithubComUserID(ctx context.Context, arg UpdateUserGithubComUserIDParams) error UpdateUserHashedOneTimePasscode(ctx context.Context, arg UpdateUserHashedOneTimePasscodeParams) error @@ -584,6 +583,7 @@ type sqlcQuerier interface { UpdateUserQuietHoursSchedule(ctx context.Context, arg UpdateUserQuietHoursScheduleParams) (User, error) UpdateUserRoles(ctx context.Context, arg UpdateUserRolesParams) (User, error) UpdateUserStatus(ctx context.Context, arg UpdateUserStatusParams) (User, error) + UpdateUserThemePreference(ctx context.Context, arg UpdateUserThemePreferenceParams) (UserConfig, error) UpdateVolumeResourceMonitor(ctx context.Context, arg UpdateVolumeResourceMonitorParams) error UpdateWorkspace(ctx context.Context, arg UpdateWorkspaceParams) (WorkspaceTable, error) UpdateWorkspaceAgentConnectionByID(ctx context.Context, arg UpdateWorkspaceAgentConnectionByIDParams) error diff --git a/coderd/database/queries.sql.go b/coderd/database/queries.sql.go index e1c7c3e65ab92..6e0246c534efd 100644 --- a/coderd/database/queries.sql.go +++ b/coderd/database/queries.sql.go @@ -12159,23 +12159,6 @@ func (q *sqlQuerier) GetAuthorizationUserRoles(ctx context.Context, userID uuid. return i, err } -const getUserAppearanceSettings = `-- name: GetUserAppearanceSettings :one -SELECT - value as theme_preference -FROM - user_configs -WHERE - user_id = $1 - AND key = 'theme_preference' -` - -func (q *sqlQuerier) GetUserAppearanceSettings(ctx context.Context, userID uuid.UUID) (string, error) { - row := q.db.QueryRowContext(ctx, getUserAppearanceSettings, userID) - var theme_preference string - err := row.Scan(&theme_preference) - return theme_preference, err -} - const getUserByEmailOrUsername = `-- name: GetUserByEmailOrUsername :one SELECT id, email, username, hashed_password, created_at, updated_at, status, rbac_roles, login_type, avatar_url, deleted, last_seen_at, quiet_hours_schedule, name, github_com_user_id, hashed_one_time_passcode, one_time_passcode_expires_at, is_system @@ -12273,6 +12256,23 @@ func (q *sqlQuerier) GetUserCount(ctx context.Context, includeSystem bool) (int6 return count, err } +const getUserThemePreference = `-- name: GetUserThemePreference :one +SELECT + value as theme_preference +FROM + user_configs +WHERE + user_id = $1 + AND key = 'theme_preference' +` + +func (q *sqlQuerier) GetUserThemePreference(ctx context.Context, userID uuid.UUID) (string, error) { + row := q.db.QueryRowContext(ctx, getUserThemePreference, userID) + var theme_preference string + err := row.Scan(&theme_preference) + return theme_preference, err +} + const getUsers = `-- name: GetUsers :many SELECT id, email, username, hashed_password, created_at, updated_at, status, rbac_roles, login_type, avatar_url, deleted, last_seen_at, quiet_hours_schedule, name, github_com_user_id, hashed_one_time_passcode, one_time_passcode_expires_at, is_system, COUNT(*) OVER() AS count @@ -12636,33 +12636,6 @@ func (q *sqlQuerier) UpdateInactiveUsersToDormant(ctx context.Context, arg Updat return items, nil } -const updateUserAppearanceSettings = `-- name: UpdateUserAppearanceSettings :one -INSERT INTO - user_configs (user_id, key, value) -VALUES - ($1, 'theme_preference', $2) -ON CONFLICT - ON CONSTRAINT user_configs_pkey -DO UPDATE -SET - value = $2 -WHERE user_configs.user_id = $1 - AND user_configs.key = 'theme_preference' -RETURNING user_id, key, value -` - -type UpdateUserAppearanceSettingsParams struct { - UserID uuid.UUID `db:"user_id" json:"user_id"` - ThemePreference string `db:"theme_preference" json:"theme_preference"` -} - -func (q *sqlQuerier) UpdateUserAppearanceSettings(ctx context.Context, arg UpdateUserAppearanceSettingsParams) (UserConfig, error) { - row := q.db.QueryRowContext(ctx, updateUserAppearanceSettings, arg.UserID, arg.ThemePreference) - var i UserConfig - err := row.Scan(&i.UserID, &i.Key, &i.Value) - return i, err -} - const updateUserDeletedByID = `-- name: UpdateUserDeletedByID :exec UPDATE users @@ -13010,6 +12983,33 @@ func (q *sqlQuerier) UpdateUserStatus(ctx context.Context, arg UpdateUserStatusP return i, err } +const updateUserThemePreference = `-- name: UpdateUserThemePreference :one +INSERT INTO + user_configs (user_id, key, value) +VALUES + ($1, 'theme_preference', $2) +ON CONFLICT + ON CONSTRAINT user_configs_pkey +DO UPDATE +SET + value = $2 +WHERE user_configs.user_id = $1 + AND user_configs.key = 'theme_preference' +RETURNING user_id, key, value +` + +type UpdateUserThemePreferenceParams struct { + UserID uuid.UUID `db:"user_id" json:"user_id"` + ThemePreference string `db:"theme_preference" json:"theme_preference"` +} + +func (q *sqlQuerier) UpdateUserThemePreference(ctx context.Context, arg UpdateUserThemePreferenceParams) (UserConfig, error) { + row := q.db.QueryRowContext(ctx, updateUserThemePreference, arg.UserID, arg.ThemePreference) + var i UserConfig + err := row.Scan(&i.UserID, &i.Key, &i.Value) + return i, err +} + const getWorkspaceAgentDevcontainersByAgentID = `-- name: GetWorkspaceAgentDevcontainersByAgentID :many SELECT id, workspace_agent_id, created_at, workspace_folder, config_path, name diff --git a/coderd/database/queries/users.sql b/coderd/database/queries/users.sql index c4304cfc3e60e..fe3bd3a414631 100644 --- a/coderd/database/queries/users.sql +++ b/coderd/database/queries/users.sql @@ -102,7 +102,7 @@ SET WHERE id = $1; --- name: GetUserAppearanceSettings :one +-- name: GetUserThemePreference :one SELECT value as theme_preference FROM @@ -111,7 +111,7 @@ WHERE user_id = @user_id AND key = 'theme_preference'; --- name: UpdateUserAppearanceSettings :one +-- name: UpdateUserThemePreference :one INSERT INTO user_configs (user_id, key, value) VALUES diff --git a/coderd/users.go b/coderd/users.go index 069e1fc240302..934b0b9486111 100644 --- a/coderd/users.go +++ b/coderd/users.go @@ -976,7 +976,7 @@ func (api *API) userAppearanceSettings(rw http.ResponseWriter, r *http.Request) user = httpmw.UserParam(r) ) - themePreference, err := api.Database.GetUserAppearanceSettings(ctx, user.ID) + themePreference, err := api.Database.GetUserThemePreference(ctx, user.ID) if err != nil { if !errors.Is(err, sql.ErrNoRows) { httpapi.Write(ctx, rw, http.StatusInternalServerError, codersdk.Response{ @@ -1015,7 +1015,7 @@ func (api *API) putUserAppearanceSettings(rw http.ResponseWriter, r *http.Reques return } - updatedSettings, err := api.Database.UpdateUserAppearanceSettings(ctx, database.UpdateUserAppearanceSettingsParams{ + updatedSettings, err := api.Database.UpdateUserThemePreference(ctx, database.UpdateUserThemePreferenceParams{ UserID: user.ID, ThemePreference: params.ThemePreference, }) diff --git a/codersdk/users.go b/codersdk/users.go index 31854731a0ae1..3be661a9d22ff 100644 --- a/codersdk/users.go +++ b/codersdk/users.go @@ -189,12 +189,23 @@ type ValidateUserPasswordResponse struct { Details string `json:"details"` } +// TerminalFontName is the name of supported terminal font +type TerminalFontName string + +const ( + TerminalFontUnknown TerminalFontName = "" + TerminalFontIbmMonoPlex TerminalFontName = "ibm-mono-plex" + TerminalFontFiraCode TerminalFontName = "fira-code" +) + type UserAppearanceSettings struct { - ThemePreference string `json:"theme_preference"` + ThemePreference string `json:"theme_preference"` + TerminalFont TerminalFontName `json:"terminal_font" enums:"ibm-mono-plex,fira-code"` } type UpdateUserAppearanceSettingsRequest struct { - ThemePreference string `json:"theme_preference" validate:"required"` + ThemePreference string `json:"theme_preference" validate:"required"` + TerminalFont TerminalFontName `json:"terminal_font" validate:"required" enums:"ibm-mono-plex,fira-code"` } type UpdateUserPasswordRequest struct { diff --git a/docs/reference/api/schemas.md b/docs/reference/api/schemas.md index 4791967b53c9e..08c211c06d9cc 100644 --- a/docs/reference/api/schemas.md +++ b/docs/reference/api/schemas.md @@ -6712,6 +6712,22 @@ Restarts will only happen on weekdays in this list on weeks which line up with W |--------------------------| | `UNSUPPORTED_WORKSPACES` | +## codersdk.TerminalFontName + +```json +"" +``` + +### Properties + +#### Enumerated Values + +| Value | +|-----------------| +| `` | +| `ibm-mono-plex` | +| `fira-code` | + ## codersdk.TimingStage ```json @@ -6909,15 +6925,24 @@ Restarts will only happen on weekdays in this list on weeks which line up with W ```json { + "terminal_font": "ibm-mono-plex", "theme_preference": "string" } ``` ### Properties -| Name | Type | Required | Restrictions | Description | -|--------------------|--------|----------|--------------|-------------| -| `theme_preference` | string | true | | | +| Name | Type | Required | Restrictions | Description | +|--------------------|--------------------------------------------------------|----------|--------------|-------------| +| `terminal_font` | [codersdk.TerminalFontName](#codersdkterminalfontname) | true | | | +| `theme_preference` | string | true | | | + +#### Enumerated Values + +| Property | Value | +|-----------------|-----------------| +| `terminal_font` | `ibm-mono-plex` | +| `terminal_font` | `fira-code` | ## codersdk.UpdateUserNotificationPreferences @@ -7260,15 +7285,24 @@ If the schedule is empty, the user will be updated to use the default schedule.| ```json { + "terminal_font": "ibm-mono-plex", "theme_preference": "string" } ``` ### Properties -| Name | Type | Required | Restrictions | Description | -|--------------------|--------|----------|--------------|-------------| -| `theme_preference` | string | false | | | +| Name | Type | Required | Restrictions | Description | +|--------------------|--------------------------------------------------------|----------|--------------|-------------| +| `terminal_font` | [codersdk.TerminalFontName](#codersdkterminalfontname) | false | | | +| `theme_preference` | string | false | | | + +#### Enumerated Values + +| Property | Value | +|-----------------|-----------------| +| `terminal_font` | `ibm-mono-plex` | +| `terminal_font` | `fira-code` | ## codersdk.UserLatency diff --git a/docs/reference/api/users.md b/docs/reference/api/users.md index 3f0c38571f7c4..09358064b2118 100644 --- a/docs/reference/api/users.md +++ b/docs/reference/api/users.md @@ -501,6 +501,7 @@ curl -X GET http://coder-server:8080/api/v2/users/{user}/appearance \ ```json { + "terminal_font": "ibm-mono-plex", "theme_preference": "string" } ``` @@ -531,6 +532,7 @@ curl -X PUT http://coder-server:8080/api/v2/users/{user}/appearance \ ```json { + "terminal_font": "ibm-mono-plex", "theme_preference": "string" } ``` @@ -548,6 +550,7 @@ curl -X PUT http://coder-server:8080/api/v2/users/{user}/appearance \ ```json { + "terminal_font": "ibm-mono-plex", "theme_preference": "string" } ``` diff --git a/provisioner/terraform/testdata/resources/version.txt b/provisioner/terraform/testdata/resources/version.txt index ca7176690dd6f..720c7384c6195 100644 --- a/provisioner/terraform/testdata/resources/version.txt +++ b/provisioner/terraform/testdata/resources/version.txt @@ -1 +1 @@ -1.11.2 +1.11.1 diff --git a/site/site.go b/site/site.go index f4d5509479db5..710ad6174fbae 100644 --- a/site/site.go +++ b/site/site.go @@ -436,7 +436,7 @@ func (h *Handler) renderHTMLWithState(r *http.Request, filePath string, state ht }) eg.Go(func() error { var err error - themePreference, err = h.opts.Database.GetUserAppearanceSettings(ctx, apiKey.UserID) + themePreference, err = h.opts.Database.GetUserThemePreference(ctx, apiKey.UserID) if errors.Is(err, sql.ErrNoRows) { themePreference = "" return nil diff --git a/site/src/api/typesGenerated.ts b/site/src/api/typesGenerated.ts index 2df1c351d9db1..05e7c807ed614 100644 --- a/site/src/api/typesGenerated.ts +++ b/site/src/api/typesGenerated.ts @@ -2655,6 +2655,15 @@ export interface TemplateVersionsByTemplateRequest extends Pagination { readonly include_archived: boolean; } +// From codersdk/users.go +export type TerminalFontName = "fira-code" | "ibm-mono-plex" | ""; + +export const TerminalFontNames: TerminalFontName[] = [ + "fira-code", + "ibm-mono-plex", + "", +]; + // From codersdk/workspacebuilds.go export type TimingStage = | "apply" @@ -2788,6 +2797,7 @@ export interface UpdateTemplateMeta { // From codersdk/users.go export interface UpdateUserAppearanceSettingsRequest { readonly theme_preference: string; + readonly terminal_font: TerminalFontName; } // From codersdk/notifications.go @@ -2904,6 +2914,7 @@ export interface UserActivityInsightsResponse { // From codersdk/users.go export interface UserAppearanceSettings { readonly theme_preference: string; + readonly terminal_font: TerminalFontName; } // From codersdk/insights.go From fd6c9e427512cacfa2d7c98dee451348574a2678 Mon Sep 17 00:00:00 2001 From: Marcin Tojek Date: Fri, 4 Apr 2025 11:05:10 +0200 Subject: [PATCH 03/22] GetUserTerminalFont --- coderd/database/dbauthz/dbauthz.go | 66 ++++++++---- coderd/database/dbmem/dbmem.go | 123 ++++++++++++++-------- coderd/database/dbmetrics/querymetrics.go | 42 +++++--- coderd/database/dbmock/dbmock.go | 30 ++++++ coderd/database/querier.go | 2 + coderd/database/queries.sql.go | 44 ++++++++ coderd/database/queries/users.sql | 23 ++++ 7 files changed, 253 insertions(+), 77 deletions(-) diff --git a/coderd/database/dbauthz/dbauthz.go b/coderd/database/dbauthz/dbauthz.go index e496eda90ea54..042e97f6569f6 100644 --- a/coderd/database/dbauthz/dbauthz.go +++ b/coderd/database/dbauthz/dbauthz.go @@ -1061,28 +1061,6 @@ func (q *querier) customRoleCheck(ctx context.Context, role database.CustomRole) return nil } -func (q *querier) GetUserThemePreference(ctx context.Context, userID uuid.UUID) (string, error) { - u, err := q.db.GetUserByID(ctx, userID) - if err != nil { - return "", err - } - if err := q.authorizeContext(ctx, policy.ActionReadPersonal, u); err != nil { - return "", err - } - return q.db.GetUserThemePreference(ctx, userID) -} - -func (q *querier) UpdateUserThemePreference(ctx context.Context, arg database.UpdateUserThemePreferenceParams) (database.UserConfig, error) { - u, err := q.db.GetUserByID(ctx, arg.UserID) - if err != nil { - return database.UserConfig{}, err - } - if err := q.authorizeContext(ctx, policy.ActionUpdatePersonal, u); err != nil { - return database.UserConfig{}, err - } - return q.db.UpdateUserThemePreference(ctx, arg) -} - func (q *querier) AcquireLock(ctx context.Context, id int64) error { return q.db.AcquireLock(ctx, id) } @@ -2805,6 +2783,28 @@ func (q *querier) GetUserStatusCounts(ctx context.Context, arg database.GetUserS return q.db.GetUserStatusCounts(ctx, arg) } +func (q *querier) GetUserTerminalFont(ctx context.Context, userID uuid.UUID) (string, error) { + u, err := q.db.GetUserByID(ctx, userID) + if err != nil { + return "", err + } + if err := q.authorizeContext(ctx, policy.ActionReadPersonal, u); err != nil { + return "", err + } + return q.db.GetUserTerminalFont(ctx, userID) +} + +func (q *querier) GetUserThemePreference(ctx context.Context, userID uuid.UUID) (string, error) { + u, err := q.db.GetUserByID(ctx, userID) + if err != nil { + return "", err + } + if err := q.authorizeContext(ctx, policy.ActionReadPersonal, u); err != nil { + return "", err + } + return q.db.GetUserThemePreference(ctx, userID) +} + func (q *querier) GetUserWorkspaceBuildParameters(ctx context.Context, params database.GetUserWorkspaceBuildParametersParams) ([]database.GetUserWorkspaceBuildParametersRow, error) { u, err := q.db.GetUserByID(ctx, params.OwnerID) if err != nil { @@ -4459,6 +4459,28 @@ func (q *querier) UpdateUserStatus(ctx context.Context, arg database.UpdateUserS return updateWithReturn(q.log, q.auth, fetch, q.db.UpdateUserStatus)(ctx, arg) } +func (q *querier) UpdateUserTerminalFont(ctx context.Context, arg database.UpdateUserTerminalFontParams) (database.UserConfig, error) { + u, err := q.db.GetUserByID(ctx, arg.UserID) + if err != nil { + return database.UserConfig{}, err + } + if err := q.authorizeContext(ctx, policy.ActionUpdatePersonal, u); err != nil { + return database.UserConfig{}, err + } + return q.db.UpdateUserTerminalFont(ctx, arg) +} + +func (q *querier) UpdateUserThemePreference(ctx context.Context, arg database.UpdateUserThemePreferenceParams) (database.UserConfig, error) { + u, err := q.db.GetUserByID(ctx, arg.UserID) + if err != nil { + return database.UserConfig{}, err + } + if err := q.authorizeContext(ctx, policy.ActionUpdatePersonal, u); err != nil { + return database.UserConfig{}, err + } + return q.db.UpdateUserThemePreference(ctx, arg) +} + func (q *querier) UpdateVolumeResourceMonitor(ctx context.Context, arg database.UpdateVolumeResourceMonitorParams) error { if err := q.authorizeContext(ctx, policy.ActionUpdate, rbac.ResourceWorkspaceAgentResourceMonitor); err != nil { return err diff --git a/coderd/database/dbmem/dbmem.go b/coderd/database/dbmem/dbmem.go index d76a6d0b7aacd..a8351cbb8ca16 100644 --- a/coderd/database/dbmem/dbmem.go +++ b/coderd/database/dbmem/dbmem.go @@ -1379,47 +1379,6 @@ func (q *FakeQuerier) getProvisionerJobsByIDsWithQueuePositionLockedGlobalQueue( return jobs, nil } -func (q *FakeQuerier) GetUserThemePreference(_ context.Context, userID uuid.UUID) (string, error) { - q.mutex.RLock() - defer q.mutex.RUnlock() - - for _, uc := range q.userConfigs { - if uc.UserID != userID || uc.Key != "theme_preference" { - continue - } - return uc.Value, nil - } - - return "", sql.ErrNoRows -} - -func (q *FakeQuerier) UpdateUserThemePreference(_ context.Context, arg database.UpdateUserThemePreferenceParams) (database.UserConfig, error) { - err := validateDatabaseType(arg) - if err != nil { - return database.UserConfig{}, err - } - - q.mutex.Lock() - defer q.mutex.Unlock() - - for i, uc := range q.userConfigs { - if uc.UserID != arg.UserID || uc.Key != "theme_preference" { - continue - } - uc.Value = arg.ThemePreference - q.userConfigs[i] = uc - return uc, nil - } - - uc := database.UserConfig{ - UserID: arg.UserID, - Key: "theme_preference", - Value: arg.ThemePreference, - } - q.userConfigs = append(q.userConfigs, uc) - return uc, nil -} - func (*FakeQuerier) AcquireLock(_ context.Context, _ int64) error { return xerrors.New("AcquireLock must only be called within a transaction") } @@ -6687,6 +6646,34 @@ func (q *FakeQuerier) GetUserStatusCounts(_ context.Context, arg database.GetUse return result, nil } +func (q *FakeQuerier) GetUserTerminalFont(ctx context.Context, userID uuid.UUID) (string, error) { + q.mutex.RLock() + defer q.mutex.RUnlock() + + for _, uc := range q.userConfigs { + if uc.UserID != userID || uc.Key != "terminal_font" { + continue + } + return uc.Value, nil + } + + return "", sql.ErrNoRows +} + +func (q *FakeQuerier) GetUserThemePreference(_ context.Context, userID uuid.UUID) (string, error) { + q.mutex.RLock() + defer q.mutex.RUnlock() + + for _, uc := range q.userConfigs { + if uc.UserID != userID || uc.Key != "theme_preference" { + continue + } + return uc.Value, nil + } + + return "", sql.ErrNoRows +} + func (q *FakeQuerier) GetUserWorkspaceBuildParameters(_ context.Context, params database.GetUserWorkspaceBuildParametersParams) ([]database.GetUserWorkspaceBuildParametersRow, error) { q.mutex.RLock() defer q.mutex.RUnlock() @@ -11348,6 +11335,60 @@ func (q *FakeQuerier) UpdateUserStatus(_ context.Context, arg database.UpdateUse return database.User{}, sql.ErrNoRows } +func (q *FakeQuerier) UpdateUserTerminalFont(ctx context.Context, arg database.UpdateUserTerminalFontParams) (database.UserConfig, error) { + err := validateDatabaseType(arg) + if err != nil { + return database.UserConfig{}, err + } + + q.mutex.Lock() + defer q.mutex.Unlock() + + for i, uc := range q.userConfigs { + if uc.UserID != arg.UserID || uc.Key != "terminal_font" { + continue + } + uc.Value = arg.TerminalFont + q.userConfigs[i] = uc + return uc, nil + } + + uc := database.UserConfig{ + UserID: arg.UserID, + Key: "terminal_font", + Value: arg.TerminalFont, + } + q.userConfigs = append(q.userConfigs, uc) + return uc, nil +} + +func (q *FakeQuerier) UpdateUserThemePreference(_ context.Context, arg database.UpdateUserThemePreferenceParams) (database.UserConfig, error) { + err := validateDatabaseType(arg) + if err != nil { + return database.UserConfig{}, err + } + + q.mutex.Lock() + defer q.mutex.Unlock() + + for i, uc := range q.userConfigs { + if uc.UserID != arg.UserID || uc.Key != "theme_preference" { + continue + } + uc.Value = arg.ThemePreference + q.userConfigs[i] = uc + return uc, nil + } + + uc := database.UserConfig{ + UserID: arg.UserID, + Key: "theme_preference", + Value: arg.ThemePreference, + } + q.userConfigs = append(q.userConfigs, uc) + return uc, nil +} + func (q *FakeQuerier) UpdateVolumeResourceMonitor(_ context.Context, arg database.UpdateVolumeResourceMonitorParams) error { err := validateDatabaseType(arg) if err != nil { diff --git a/coderd/database/dbmetrics/querymetrics.go b/coderd/database/dbmetrics/querymetrics.go index b8abb638c6484..31ce37e096f1f 100644 --- a/coderd/database/dbmetrics/querymetrics.go +++ b/coderd/database/dbmetrics/querymetrics.go @@ -88,20 +88,6 @@ func (m queryMetricsStore) DeleteOrganization(ctx context.Context, id uuid.UUID) return r0 } -func (m queryMetricsStore) GetUserThemePreference(ctx context.Context, userID uuid.UUID) (string, error) { - start := time.Now() - r0, r1 := m.s.GetUserThemePreference(ctx, userID) - m.queryLatencies.WithLabelValues("GetUserThemePreference").Observe(time.Since(start).Seconds()) - return r0, r1 -} - -func (m queryMetricsStore) UpdateUserThemePreference(ctx context.Context, arg database.UpdateUserThemePreferenceParams) (database.UserConfig, error) { - start := time.Now() - r0, r1 := m.s.UpdateUserThemePreference(ctx, arg) - m.queryLatencies.WithLabelValues("UpdateUserThemePreference").Observe(time.Since(start).Seconds()) - return r0, r1 -} - func (m queryMetricsStore) AcquireLock(ctx context.Context, pgAdvisoryXactLock int64) error { start := time.Now() err := m.s.AcquireLock(ctx, pgAdvisoryXactLock) @@ -1579,6 +1565,20 @@ func (m queryMetricsStore) GetUserStatusCounts(ctx context.Context, arg database return r0, r1 } +func (m queryMetricsStore) GetUserTerminalFont(ctx context.Context, userID uuid.UUID) (string, error) { + start := time.Now() + r0, r1 := m.s.GetUserTerminalFont(ctx, userID) + m.queryLatencies.WithLabelValues("GetUserTerminalFont").Observe(time.Since(start).Seconds()) + return r0, r1 +} + +func (m queryMetricsStore) GetUserThemePreference(ctx context.Context, userID uuid.UUID) (string, error) { + start := time.Now() + r0, r1 := m.s.GetUserThemePreference(ctx, userID) + m.queryLatencies.WithLabelValues("GetUserThemePreference").Observe(time.Since(start).Seconds()) + return r0, r1 +} + func (m queryMetricsStore) GetUserWorkspaceBuildParameters(ctx context.Context, ownerID database.GetUserWorkspaceBuildParametersParams) ([]database.GetUserWorkspaceBuildParametersRow, error) { start := time.Now() r0, r1 := m.s.GetUserWorkspaceBuildParameters(ctx, ownerID) @@ -2825,6 +2825,20 @@ func (m queryMetricsStore) UpdateUserStatus(ctx context.Context, arg database.Up return user, err } +func (m queryMetricsStore) UpdateUserTerminalFont(ctx context.Context, arg database.UpdateUserTerminalFontParams) (database.UserConfig, error) { + start := time.Now() + r0, r1 := m.s.UpdateUserTerminalFont(ctx, arg) + m.queryLatencies.WithLabelValues("UpdateUserTerminalFont").Observe(time.Since(start).Seconds()) + return r0, r1 +} + +func (m queryMetricsStore) UpdateUserThemePreference(ctx context.Context, arg database.UpdateUserThemePreferenceParams) (database.UserConfig, error) { + start := time.Now() + r0, r1 := m.s.UpdateUserThemePreference(ctx, arg) + m.queryLatencies.WithLabelValues("UpdateUserThemePreference").Observe(time.Since(start).Seconds()) + return r0, r1 +} + func (m queryMetricsStore) UpdateVolumeResourceMonitor(ctx context.Context, arg database.UpdateVolumeResourceMonitorParams) error { start := time.Now() r0 := m.s.UpdateVolumeResourceMonitor(ctx, arg) diff --git a/coderd/database/dbmock/dbmock.go b/coderd/database/dbmock/dbmock.go index d00649c4e0cad..4117cb71074be 100644 --- a/coderd/database/dbmock/dbmock.go +++ b/coderd/database/dbmock/dbmock.go @@ -3274,6 +3274,21 @@ func (mr *MockStoreMockRecorder) GetUserStatusCounts(ctx, arg any) *gomock.Call return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetUserStatusCounts", reflect.TypeOf((*MockStore)(nil).GetUserStatusCounts), ctx, arg) } +// GetUserTerminalFont mocks base method. +func (m *MockStore) GetUserTerminalFont(ctx context.Context, userID uuid.UUID) (string, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetUserTerminalFont", ctx, userID) + ret0, _ := ret[0].(string) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetUserTerminalFont indicates an expected call of GetUserTerminalFont. +func (mr *MockStoreMockRecorder) GetUserTerminalFont(ctx, userID any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetUserTerminalFont", reflect.TypeOf((*MockStore)(nil).GetUserTerminalFont), ctx, userID) +} + // GetUserThemePreference mocks base method. func (m *MockStore) GetUserThemePreference(ctx context.Context, userID uuid.UUID) (string, error) { m.ctrl.T.Helper() @@ -5959,6 +5974,21 @@ func (mr *MockStoreMockRecorder) UpdateUserStatus(ctx, arg any) *gomock.Call { return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UpdateUserStatus", reflect.TypeOf((*MockStore)(nil).UpdateUserStatus), ctx, arg) } +// UpdateUserTerminalFont mocks base method. +func (m *MockStore) UpdateUserTerminalFont(ctx context.Context, arg database.UpdateUserTerminalFontParams) (database.UserConfig, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "UpdateUserTerminalFont", ctx, arg) + ret0, _ := ret[0].(database.UserConfig) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// UpdateUserTerminalFont indicates an expected call of UpdateUserTerminalFont. +func (mr *MockStoreMockRecorder) UpdateUserTerminalFont(ctx, arg any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UpdateUserTerminalFont", reflect.TypeOf((*MockStore)(nil).UpdateUserTerminalFont), ctx, arg) +} + // UpdateUserThemePreference mocks base method. func (m *MockStore) UpdateUserThemePreference(ctx context.Context, arg database.UpdateUserThemePreferenceParams) (database.UserConfig, error) { m.ctrl.T.Helper() diff --git a/coderd/database/querier.go b/coderd/database/querier.go index d0aba4d376b3d..028c025dde921 100644 --- a/coderd/database/querier.go +++ b/coderd/database/querier.go @@ -368,6 +368,7 @@ type sqlcQuerier interface { // We do not start counting from 0 at the start_time. We check the last status change before the start_time for each user. As such, // the result shows the total number of users in each status on any particular day. GetUserStatusCounts(ctx context.Context, arg GetUserStatusCountsParams) ([]GetUserStatusCountsRow, error) + GetUserTerminalFont(ctx context.Context, userID uuid.UUID) (string, error) GetUserThemePreference(ctx context.Context, userID uuid.UUID) (string, error) GetUserWorkspaceBuildParameters(ctx context.Context, arg GetUserWorkspaceBuildParametersParams) ([]GetUserWorkspaceBuildParametersRow, error) // This will never return deleted users. @@ -583,6 +584,7 @@ type sqlcQuerier interface { UpdateUserQuietHoursSchedule(ctx context.Context, arg UpdateUserQuietHoursScheduleParams) (User, error) UpdateUserRoles(ctx context.Context, arg UpdateUserRolesParams) (User, error) UpdateUserStatus(ctx context.Context, arg UpdateUserStatusParams) (User, error) + UpdateUserTerminalFont(ctx context.Context, arg UpdateUserTerminalFontParams) (UserConfig, error) UpdateUserThemePreference(ctx context.Context, arg UpdateUserThemePreferenceParams) (UserConfig, error) UpdateVolumeResourceMonitor(ctx context.Context, arg UpdateVolumeResourceMonitorParams) error UpdateWorkspace(ctx context.Context, arg UpdateWorkspaceParams) (WorkspaceTable, error) diff --git a/coderd/database/queries.sql.go b/coderd/database/queries.sql.go index 6e0246c534efd..e9acf4bb5462b 100644 --- a/coderd/database/queries.sql.go +++ b/coderd/database/queries.sql.go @@ -12256,6 +12256,23 @@ func (q *sqlQuerier) GetUserCount(ctx context.Context, includeSystem bool) (int6 return count, err } +const getUserTerminalFont = `-- name: GetUserTerminalFont :one +SELECT + value as terminal_font +FROM + user_configs +WHERE + user_id = $1 + AND key = 'terminal_font' +` + +func (q *sqlQuerier) GetUserTerminalFont(ctx context.Context, userID uuid.UUID) (string, error) { + row := q.db.QueryRowContext(ctx, getUserTerminalFont, userID) + var terminal_font string + err := row.Scan(&terminal_font) + return terminal_font, err +} + const getUserThemePreference = `-- name: GetUserThemePreference :one SELECT value as theme_preference @@ -12983,6 +13000,33 @@ func (q *sqlQuerier) UpdateUserStatus(ctx context.Context, arg UpdateUserStatusP return i, err } +const updateUserTerminalFont = `-- name: UpdateUserTerminalFont :one +INSERT INTO + user_configs (user_id, key, value) +VALUES + ($1, 'terminal_font', $2) +ON CONFLICT + ON CONSTRAINT user_configs_pkey +DO UPDATE +SET + value = $2 +WHERE user_configs.user_id = $1 + AND user_configs.key = 'terminal_font' +RETURNING user_id, key, value +` + +type UpdateUserTerminalFontParams struct { + UserID uuid.UUID `db:"user_id" json:"user_id"` + TerminalFont string `db:"terminal_font" json:"terminal_font"` +} + +func (q *sqlQuerier) UpdateUserTerminalFont(ctx context.Context, arg UpdateUserTerminalFontParams) (UserConfig, error) { + row := q.db.QueryRowContext(ctx, updateUserTerminalFont, arg.UserID, arg.TerminalFont) + var i UserConfig + err := row.Scan(&i.UserID, &i.Key, &i.Value) + return i, err +} + const updateUserThemePreference = `-- name: UpdateUserThemePreference :one INSERT INTO user_configs (user_id, key, value) diff --git a/coderd/database/queries/users.sql b/coderd/database/queries/users.sql index fe3bd3a414631..0bac76c8df14a 100644 --- a/coderd/database/queries/users.sql +++ b/coderd/database/queries/users.sql @@ -125,6 +125,29 @@ WHERE user_configs.user_id = @user_id AND user_configs.key = 'theme_preference' RETURNING *; +-- name: GetUserTerminalFont :one +SELECT + value as terminal_font +FROM + user_configs +WHERE + user_id = @user_id + AND key = 'terminal_font'; + +-- name: UpdateUserTerminalFont :one +INSERT INTO + user_configs (user_id, key, value) +VALUES + (@user_id, 'terminal_font', @terminal_font) +ON CONFLICT + ON CONSTRAINT user_configs_pkey +DO UPDATE +SET + value = @terminal_font +WHERE user_configs.user_id = @user_id + AND user_configs.key = 'terminal_font' +RETURNING *; + -- name: UpdateUserRoles :one UPDATE users From 40ee863bebb94016278700a9e3c28c73b405003d Mon Sep 17 00:00:00 2001 From: Marcin Tojek Date: Fri, 4 Apr 2025 11:35:20 +0200 Subject: [PATCH 04/22] ibm-plex-mono --- coderd/apidoc/docs.go | 8 ++--- coderd/apidoc/swagger.json | 8 ++--- coderd/users.go | 33 +++++++++++++++++-- codersdk/users.go | 6 ++-- docs/reference/api/schemas.md | 10 +++--- docs/reference/api/users.md | 6 ++-- site/src/api/typesGenerated.ts | 4 +-- .../AppearancePage/AppearanceForm.stories.tsx | 2 +- .../AppearancePage/AppearanceForm.tsx | 5 +-- .../AppearancePage/AppearancePage.test.tsx | 2 ++ .../AppearancePage/AppearancePage.tsx | 1 + site/src/testHelpers/entities.ts | 1 + site/src/theme/index.ts | 2 ++ 13 files changed, 61 insertions(+), 27 deletions(-) diff --git a/coderd/apidoc/docs.go b/coderd/apidoc/docs.go index bc11caf62facf..350486f25c8e0 100644 --- a/coderd/apidoc/docs.go +++ b/coderd/apidoc/docs.go @@ -15599,12 +15599,12 @@ const docTemplate = `{ "type": "string", "enum": [ "", - "ibm-mono-plex", + "ibm-plex-mono", "fira-code" ], "x-enum-varnames": [ "TerminalFontUnknown", - "TerminalFontIbmMonoPlex", + "TerminalFontIbmPlexMono", "TerminalFontFiraCode" ] }, @@ -15787,7 +15787,7 @@ const docTemplate = `{ "properties": { "terminal_font": { "enum": [ - "ibm-mono-plex", + "ibm-plex-mono", "fira-code" ], "allOf": [ @@ -16089,7 +16089,7 @@ const docTemplate = `{ "properties": { "terminal_font": { "enum": [ - "ibm-mono-plex", + "ibm-plex-mono", "fira-code" ], "allOf": [ diff --git a/coderd/apidoc/swagger.json b/coderd/apidoc/swagger.json index a9cdae584b627..4f89e11c53582 100644 --- a/coderd/apidoc/swagger.json +++ b/coderd/apidoc/swagger.json @@ -14182,10 +14182,10 @@ }, "codersdk.TerminalFontName": { "type": "string", - "enum": ["", "ibm-mono-plex", "fira-code"], + "enum": ["", "ibm-plex-mono", "fira-code"], "x-enum-varnames": [ "TerminalFontUnknown", - "TerminalFontIbmMonoPlex", + "TerminalFontIbmPlexMono", "TerminalFontFiraCode" ] }, @@ -14362,7 +14362,7 @@ "required": ["terminal_font", "theme_preference"], "properties": { "terminal_font": { - "enum": ["ibm-mono-plex", "fira-code"], + "enum": ["ibm-plex-mono", "fira-code"], "allOf": [ { "$ref": "#/definitions/codersdk.TerminalFontName" @@ -14635,7 +14635,7 @@ "type": "object", "properties": { "terminal_font": { - "enum": ["ibm-mono-plex", "fira-code"], + "enum": ["ibm-plex-mono", "fira-code"], "allOf": [ { "$ref": "#/definitions/codersdk.TerminalFontName" diff --git a/coderd/users.go b/coderd/users.go index 934b0b9486111..d0ed0223362df 100644 --- a/coderd/users.go +++ b/coderd/users.go @@ -989,8 +989,22 @@ func (api *API) userAppearanceSettings(rw http.ResponseWriter, r *http.Request) themePreference = "" } + terminalFont, err := api.Database.GetUserTerminalFont(ctx, user.ID) + if err != nil { + if !errors.Is(err, sql.ErrNoRows) { + httpapi.Write(ctx, rw, http.StatusInternalServerError, codersdk.Response{ + Message: "Error reading user settings.", + Detail: err.Error(), + }) + return + } + + terminalFont = "" + } + httpapi.Write(ctx, rw, http.StatusOK, codersdk.UserAppearanceSettings{ ThemePreference: themePreference, + TerminalFont: codersdk.TerminalFontName(terminalFont), }) } @@ -1015,20 +1029,33 @@ func (api *API) putUserAppearanceSettings(rw http.ResponseWriter, r *http.Reques return } - updatedSettings, err := api.Database.UpdateUserThemePreference(ctx, database.UpdateUserThemePreferenceParams{ + updatedThemePreference, err := api.Database.UpdateUserThemePreference(ctx, database.UpdateUserThemePreferenceParams{ UserID: user.ID, ThemePreference: params.ThemePreference, }) if err != nil { httpapi.Write(ctx, rw, http.StatusInternalServerError, codersdk.Response{ - Message: "Internal error updating user.", + Message: "Internal error updating user theme prefence.", + Detail: err.Error(), + }) + return + } + + updatedTerminalFont, err := api.Database.UpdateUserTerminalFont(ctx, database.UpdateUserTerminalFontParams{ + UserID: user.ID, + TerminalFont: string(params.ThemePreference), + }) + if err != nil { + httpapi.Write(ctx, rw, http.StatusInternalServerError, codersdk.Response{ + Message: "Internal error updating user terminal font.", Detail: err.Error(), }) return } httpapi.Write(ctx, rw, http.StatusOK, codersdk.UserAppearanceSettings{ - ThemePreference: updatedSettings.Value, + ThemePreference: updatedThemePreference.Value, + TerminalFont: codersdk.TerminalFontName(updatedTerminalFont.Value), }) } diff --git a/codersdk/users.go b/codersdk/users.go index 3be661a9d22ff..9f136f00235db 100644 --- a/codersdk/users.go +++ b/codersdk/users.go @@ -194,18 +194,18 @@ type TerminalFontName string const ( TerminalFontUnknown TerminalFontName = "" - TerminalFontIbmMonoPlex TerminalFontName = "ibm-mono-plex" + TerminalFontIbmPlexMono TerminalFontName = "ibm-plex-mono" TerminalFontFiraCode TerminalFontName = "fira-code" ) type UserAppearanceSettings struct { ThemePreference string `json:"theme_preference"` - TerminalFont TerminalFontName `json:"terminal_font" enums:"ibm-mono-plex,fira-code"` + TerminalFont TerminalFontName `json:"terminal_font" enums:"ibm-plex-mono,fira-code"` } type UpdateUserAppearanceSettingsRequest struct { ThemePreference string `json:"theme_preference" validate:"required"` - TerminalFont TerminalFontName `json:"terminal_font" validate:"required" enums:"ibm-mono-plex,fira-code"` + TerminalFont TerminalFontName `json:"terminal_font" validate:"required" enums:"ibm-plex-mono,fira-code"` } type UpdateUserPasswordRequest struct { diff --git a/docs/reference/api/schemas.md b/docs/reference/api/schemas.md index 08c211c06d9cc..5b3b132b6546c 100644 --- a/docs/reference/api/schemas.md +++ b/docs/reference/api/schemas.md @@ -6725,7 +6725,7 @@ Restarts will only happen on weekdays in this list on weeks which line up with W | Value | |-----------------| | `` | -| `ibm-mono-plex` | +| `ibm-plex-mono` | | `fira-code` | ## codersdk.TimingStage @@ -6925,7 +6925,7 @@ Restarts will only happen on weekdays in this list on weeks which line up with W ```json { - "terminal_font": "ibm-mono-plex", + "terminal_font": "ibm-plex-mono", "theme_preference": "string" } ``` @@ -6941,7 +6941,7 @@ Restarts will only happen on weekdays in this list on weeks which line up with W | Property | Value | |-----------------|-----------------| -| `terminal_font` | `ibm-mono-plex` | +| `terminal_font` | `ibm-plex-mono` | | `terminal_font` | `fira-code` | ## codersdk.UpdateUserNotificationPreferences @@ -7285,7 +7285,7 @@ If the schedule is empty, the user will be updated to use the default schedule.| ```json { - "terminal_font": "ibm-mono-plex", + "terminal_font": "ibm-plex-mono", "theme_preference": "string" } ``` @@ -7301,7 +7301,7 @@ If the schedule is empty, the user will be updated to use the default schedule.| | Property | Value | |-----------------|-----------------| -| `terminal_font` | `ibm-mono-plex` | +| `terminal_font` | `ibm-plex-mono` | | `terminal_font` | `fira-code` | ## codersdk.UserLatency diff --git a/docs/reference/api/users.md b/docs/reference/api/users.md index 09358064b2118..61f4d390fccd4 100644 --- a/docs/reference/api/users.md +++ b/docs/reference/api/users.md @@ -501,7 +501,7 @@ curl -X GET http://coder-server:8080/api/v2/users/{user}/appearance \ ```json { - "terminal_font": "ibm-mono-plex", + "terminal_font": "ibm-plex-mono", "theme_preference": "string" } ``` @@ -532,7 +532,7 @@ curl -X PUT http://coder-server:8080/api/v2/users/{user}/appearance \ ```json { - "terminal_font": "ibm-mono-plex", + "terminal_font": "ibm-plex-mono", "theme_preference": "string" } ``` @@ -550,7 +550,7 @@ curl -X PUT http://coder-server:8080/api/v2/users/{user}/appearance \ ```json { - "terminal_font": "ibm-mono-plex", + "terminal_font": "ibm-plex-mono", "theme_preference": "string" } ``` diff --git a/site/src/api/typesGenerated.ts b/site/src/api/typesGenerated.ts index 05e7c807ed614..e205e8938e999 100644 --- a/site/src/api/typesGenerated.ts +++ b/site/src/api/typesGenerated.ts @@ -2656,11 +2656,11 @@ export interface TemplateVersionsByTemplateRequest extends Pagination { } // From codersdk/users.go -export type TerminalFontName = "fira-code" | "ibm-mono-plex" | ""; +export type TerminalFontName = "fira-code" | "ibm-plex-mono" | ""; export const TerminalFontNames: TerminalFontName[] = [ "fira-code", - "ibm-mono-plex", + "ibm-plex-mono", "", ]; diff --git a/site/src/pages/UserSettingsPage/AppearancePage/AppearanceForm.stories.tsx b/site/src/pages/UserSettingsPage/AppearancePage/AppearanceForm.stories.tsx index 4f2c5965dc957..436e2e7e38c2d 100644 --- a/site/src/pages/UserSettingsPage/AppearancePage/AppearanceForm.stories.tsx +++ b/site/src/pages/UserSettingsPage/AppearancePage/AppearanceForm.stories.tsx @@ -18,6 +18,6 @@ type Story = StoryObj; export const Example: Story = { args: { - initialValues: { theme_preference: "" }, + initialValues: { theme_preference: "", terminal_font: "" }, }, }; diff --git a/site/src/pages/UserSettingsPage/AppearancePage/AppearanceForm.tsx b/site/src/pages/UserSettingsPage/AppearancePage/AppearanceForm.tsx index 3468685a246cb..cda4ae198c444 100644 --- a/site/src/pages/UserSettingsPage/AppearancePage/AppearanceForm.tsx +++ b/site/src/pages/UserSettingsPage/AppearancePage/AppearanceForm.tsx @@ -6,7 +6,7 @@ import { PreviewBadge } from "components/Badges/Badges"; import { Stack } from "components/Stack/Stack"; import { ThemeOverride } from "contexts/ThemeProvider"; import type { FC } from "react"; -import themes, { DEFAULT_THEME, type Theme } from "theme"; +import themes, { DEFAULT_TERMINAL_FONT, DEFAULT_THEME, type Theme } from "theme"; export interface AppearanceFormProps { isUpdating?: boolean; @@ -22,13 +22,14 @@ export const AppearanceForm: FC = ({ initialValues, }) => { const currentTheme = initialValues.theme_preference || DEFAULT_THEME; + const currentTerminalFont = initialValues.terminal_font || DEFAULT_TERMINAL_FONT; const onChangeTheme = async (theme: string) => { if (isUpdating) { return; } - await onSubmit({ theme_preference: theme }); + await onSubmit({ theme_preference: theme, terminal_font: currentTerminalFont }); }; return ( diff --git a/site/src/pages/UserSettingsPage/AppearancePage/AppearancePage.test.tsx b/site/src/pages/UserSettingsPage/AppearancePage/AppearancePage.test.tsx index c48c265460a4e..5b8db73dd95ab 100644 --- a/site/src/pages/UserSettingsPage/AppearancePage/AppearancePage.test.tsx +++ b/site/src/pages/UserSettingsPage/AppearancePage/AppearancePage.test.tsx @@ -12,6 +12,7 @@ describe("appearance page", () => { jest.spyOn(API, "updateAppearanceSettings").mockResolvedValueOnce({ ...MockUser, theme_preference: "dark", + terminal_font: "", }); const dark = await screen.findByText("Dark"); @@ -27,6 +28,7 @@ describe("appearance page", () => { jest.spyOn(API, "updateAppearanceSettings").mockResolvedValueOnce({ ...MockUser, theme_preference: "light", + terminal_font: "", }); const light = await screen.findByText("Light"); diff --git a/site/src/pages/UserSettingsPage/AppearancePage/AppearancePage.tsx b/site/src/pages/UserSettingsPage/AppearancePage/AppearancePage.tsx index 1379e42d0e909..68621751da553 100644 --- a/site/src/pages/UserSettingsPage/AppearancePage/AppearancePage.tsx +++ b/site/src/pages/UserSettingsPage/AppearancePage/AppearancePage.tsx @@ -47,6 +47,7 @@ export const AppearancePage: FC = () => { error={updateAppearanceSettingsMutation.error} initialValues={{ theme_preference: appearanceSettingsQuery.data.theme_preference, + terminal_font: appearanceSettingsQuery.data.terminal_font, }} onSubmit={updateAppearanceSettingsMutation.mutateAsync} /> diff --git a/site/src/testHelpers/entities.ts b/site/src/testHelpers/entities.ts index a298dea4ffd9d..02b08f03c5376 100644 --- a/site/src/testHelpers/entities.ts +++ b/site/src/testHelpers/entities.ts @@ -536,6 +536,7 @@ export const SuspendedMockUser: TypesGen.User = { export const MockUserAppearanceSettings: TypesGen.UserAppearanceSettings = { theme_preference: "dark", + terminal_font: "", }; export const MockOrganizationMember: TypesGen.OrganizationMemberWithUserData = { diff --git a/site/src/theme/index.ts b/site/src/theme/index.ts index a36bd9b223e8d..504241c8f8e0f 100644 --- a/site/src/theme/index.ts +++ b/site/src/theme/index.ts @@ -36,3 +36,5 @@ const theme = { } satisfies Record; export default theme; + +export const DEFAULT_TERMINAL_FONT = "ibm-plex-mono"; From 6a6272b24d362a7ca68ec6ae18b70f55ca6b4b51 Mon Sep 17 00:00:00 2001 From: Marcin Tojek Date: Fri, 4 Apr 2025 12:48:31 +0200 Subject: [PATCH 05/22] form --- coderd/users.go | 2 +- site/site.go | 11 ++ site/src/api/queries/users.ts | 1 + .../AppearancePage/AppearanceForm.tsx | 125 ++++++++++++++---- .../AppearancePage/AppearancePage.tsx | 33 ++--- 5 files changed, 123 insertions(+), 49 deletions(-) diff --git a/coderd/users.go b/coderd/users.go index d0ed0223362df..030935871ce56 100644 --- a/coderd/users.go +++ b/coderd/users.go @@ -1043,7 +1043,7 @@ func (api *API) putUserAppearanceSettings(rw http.ResponseWriter, r *http.Reques updatedTerminalFont, err := api.Database.UpdateUserTerminalFont(ctx, database.UpdateUserTerminalFontParams{ UserID: user.ID, - TerminalFont: string(params.ThemePreference), + TerminalFont: string(params.TerminalFont), }) if err != nil { httpapi.Write(ctx, rw, http.StatusInternalServerError, codersdk.Response{ diff --git a/site/site.go b/site/site.go index 710ad6174fbae..e47e15848cda0 100644 --- a/site/site.go +++ b/site/site.go @@ -428,6 +428,7 @@ func (h *Handler) renderHTMLWithState(r *http.Request, filePath string, state ht var eg errgroup.Group var user database.User var themePreference string + var terminalFont string orgIDs := []uuid.UUID{} eg.Go(func() error { var err error @@ -443,6 +444,15 @@ func (h *Handler) renderHTMLWithState(r *http.Request, filePath string, state ht } return err }) + eg.Go(func() error { + var err error + terminalFont, err = h.opts.Database.GetUserTerminalFont(ctx, apiKey.UserID) + if errors.Is(err, sql.ErrNoRows) { + terminalFont = "" + return nil + } + return err + }) eg.Go(func() error { memberIDs, err := h.opts.Database.GetOrganizationIDsByMemberIDs(ctx, []uuid.UUID{apiKey.UserID}) if errors.Is(err, sql.ErrNoRows) || len(memberIDs) == 0 { @@ -471,6 +481,7 @@ func (h *Handler) renderHTMLWithState(r *http.Request, filePath string, state ht defer wg.Done() userAppearance, err := json.Marshal(codersdk.UserAppearanceSettings{ ThemePreference: themePreference, + TerminalFont: codersdk.TerminalFontName(terminalFont), }) if err == nil { state.UserAppearance = html.EscapeString(string(userAppearance)) diff --git a/site/src/api/queries/users.ts b/site/src/api/queries/users.ts index 5de828b6eac22..82b10213b4409 100644 --- a/site/src/api/queries/users.ts +++ b/site/src/api/queries/users.ts @@ -251,6 +251,7 @@ export const updateAppearanceSettings = ( // more responsive. queryClient.setQueryData(myAppearanceKey, { theme_preference: patch.theme_preference, + terminal_font: patch.terminal_font, }); }, onSuccess: async () => diff --git a/site/src/pages/UserSettingsPage/AppearancePage/AppearanceForm.tsx b/site/src/pages/UserSettingsPage/AppearancePage/AppearanceForm.tsx index cda4ae198c444..219c3df892e6d 100644 --- a/site/src/pages/UserSettingsPage/AppearancePage/AppearanceForm.tsx +++ b/site/src/pages/UserSettingsPage/AppearancePage/AppearanceForm.tsx @@ -1,12 +1,26 @@ import type { Interpolation } from "@emotion/react"; +import CircularProgress from "@mui/material/CircularProgress"; +import FormControl from "@mui/material/FormControl"; +import FormControlLabel from "@mui/material/FormControlLabel"; +import Radio from "@mui/material/Radio"; +import RadioGroup from "@mui/material/RadioGroup"; import { visuallyHidden } from "@mui/utils"; -import type { UpdateUserAppearanceSettingsRequest } from "api/typesGenerated"; +import { + type TerminalFontName, + TerminalFontNames, + type UpdateUserAppearanceSettingsRequest, +} from "api/typesGenerated"; import { ErrorAlert } from "components/Alert/ErrorAlert"; import { PreviewBadge } from "components/Badges/Badges"; import { Stack } from "components/Stack/Stack"; import { ThemeOverride } from "contexts/ThemeProvider"; import type { FC } from "react"; -import themes, { DEFAULT_TERMINAL_FONT, DEFAULT_THEME, type Theme } from "theme"; +import themes, { + DEFAULT_TERMINAL_FONT, + DEFAULT_THEME, + type Theme, +} from "theme"; +import { Section } from "../Section"; export interface AppearanceFormProps { isUpdating?: boolean; @@ -22,44 +36,107 @@ export const AppearanceForm: FC = ({ initialValues, }) => { const currentTheme = initialValues.theme_preference || DEFAULT_THEME; - const currentTerminalFont = initialValues.terminal_font || DEFAULT_TERMINAL_FONT; + const currentTerminalFont = + initialValues.terminal_font || DEFAULT_TERMINAL_FONT; const onChangeTheme = async (theme: string) => { if (isUpdating) { return; } + await onSubmit({ + theme_preference: theme, + terminal_font: currentTerminalFont, + }); + }; - await onSubmit({ theme_preference: theme, terminal_font: currentTerminalFont }); + const onChangeTerminalFont = async (terminalFont: TerminalFontName) => { + if (isUpdating) { + return; + } + await onSubmit({ + theme_preference: currentTheme, + terminal_font: terminalFont, + }); }; return (
{Boolean(error) && } - - onChangeTheme("auto")} - /> - onChangeTheme("dark")} - /> - onChangeTheme("light")} - /> - +
+ Theme + {isUpdating && } + + } + layout="fluid" + > + + onChangeTheme("auto")} + /> + onChangeTheme("dark")} + /> + onChangeTheme("light")} + /> + +
+
+
+ Terminal Font + {isUpdating && } + + } + layout="fluid" + > + + + onChangeTerminalFont(toTerminalFontName(value)) + } + > + } + label={ +
IBM Plex Mono
+ } + /> + } + label={
Fira Code
} + /> +
+
+
); }; +export function toTerminalFontName(value: string): TerminalFontName { + return TerminalFontNames.includes(value as TerminalFontName) + ? (value as TerminalFontName) + : ""; +} + interface AutoThemePreviewButtonProps extends Omit { themes: [Theme, Theme]; onSelect?: () => void; diff --git a/site/src/pages/UserSettingsPage/AppearancePage/AppearancePage.tsx b/site/src/pages/UserSettingsPage/AppearancePage/AppearancePage.tsx index 68621751da553..679ad6aeef3bd 100644 --- a/site/src/pages/UserSettingsPage/AppearancePage/AppearancePage.tsx +++ b/site/src/pages/UserSettingsPage/AppearancePage/AppearancePage.tsx @@ -1,13 +1,10 @@ -import CircularProgress from "@mui/material/CircularProgress"; import { updateAppearanceSettings } from "api/queries/users"; import { appearanceSettings } from "api/queries/users"; import { ErrorAlert } from "components/Alert/ErrorAlert"; import { Loader } from "components/Loader/Loader"; -import { Stack } from "components/Stack/Stack"; import { useEmbeddedMetadata } from "hooks/useEmbeddedMetadata"; import type { FC } from "react"; import { useMutation, useQuery, useQueryClient } from "react-query"; -import { Section } from "../Section"; import { AppearanceForm } from "./AppearanceForm"; export const AppearancePage: FC = () => { @@ -31,27 +28,15 @@ export const AppearancePage: FC = () => { return ( <> -
- Theme - {updateAppearanceSettingsMutation.isLoading && ( - - )} - - } - layout="fluid" - > - -
+ ); }; From 40ee7976eb2e1fa13e6cda648f395038654bb1bd Mon Sep 17 00:00:00 2001 From: Marcin Tojek Date: Fri, 4 Apr 2025 13:55:32 +0200 Subject: [PATCH 06/22] Terminal uses font --- site/src/pages/TerminalPage/TerminalPage.tsx | 22 ++++++++++++++++---- site/src/theme/constants.ts | 14 ++++++++----- 2 files changed, 27 insertions(+), 9 deletions(-) diff --git a/site/src/pages/TerminalPage/TerminalPage.tsx b/site/src/pages/TerminalPage/TerminalPage.tsx index d1ad415fb48e0..a6d6b712de497 100644 --- a/site/src/pages/TerminalPage/TerminalPage.tsx +++ b/site/src/pages/TerminalPage/TerminalPage.tsx @@ -7,18 +7,20 @@ import { WebLinksAddon } from "@xterm/addon-web-links"; import { WebglAddon } from "@xterm/addon-webgl"; import { Terminal } from "@xterm/xterm"; import { deploymentConfig } from "api/queries/deployment"; +import { appearanceSettings } from "api/queries/users"; import { workspaceByOwnerAndName, workspaceUsage, } from "api/queries/workspaces"; import { useProxy } from "contexts/ProxyContext"; import { ThemeOverride } from "contexts/ThemeProvider"; +import { useEmbeddedMetadata } from "hooks/useEmbeddedMetadata"; import { type FC, useCallback, useEffect, useRef, useState } from "react"; import { Helmet } from "react-helmet-async"; import { useQuery } from "react-query"; import { useNavigate, useParams, useSearchParams } from "react-router-dom"; -import themes from "theme"; -import { MONOSPACE_FONT_FAMILY, TERMINAL_FONT_FAMILY_2 } from "theme/constants"; +import themes, { DEFAULT_TERMINAL_FONT } from "theme"; +import { terminalFonts } from "theme/constants"; import { pageTitle } from "utils/page"; import { openMaybePortForwardedURL } from "utils/portForward"; import { terminalWebsocketUrl } from "utils/terminal"; @@ -100,6 +102,13 @@ const TerminalPage: FC = () => { handleWebLinkRef.current = handleWebLink; }, [handleWebLink]); + const { metadata } = useEmbeddedMetadata(); + const appearanceSettingsQuery = useQuery( + appearanceSettings(metadata.userAppearance), + ); + const currentTerminalFont = + appearanceSettingsQuery.data?.terminal_font || DEFAULT_TERMINAL_FONT; + // Create the terminal! const fitAddonRef = useRef(); useEffect(() => { @@ -110,7 +119,7 @@ const TerminalPage: FC = () => { allowProposedApi: true, allowTransparency: true, disableStdin: false, - fontFamily: TERMINAL_FONT_FAMILY_2, + fontFamily: terminalFonts[currentTerminalFont], fontSize: 16, theme: { background: theme.palette.background.default, @@ -150,7 +159,12 @@ const TerminalPage: FC = () => { window.removeEventListener("resize", listener); terminal.dispose(); }; - }, [config.isLoading, renderer, theme.palette.background.default]); + }, [ + config.isLoading, + renderer, + theme.palette.background.default, + currentTerminalFont, + ]); // Updates the reconnection token into the URL if necessary. useEffect(() => { diff --git a/site/src/theme/constants.ts b/site/src/theme/constants.ts index 63092b0f99650..e2d5a07a5026c 100644 --- a/site/src/theme/constants.ts +++ b/site/src/theme/constants.ts @@ -1,11 +1,15 @@ +import type { TerminalFontName } from "api/typesGenerated"; + export const borderRadius = 8; export const MONOSPACE_FONT_FAMILY = "'IBM Plex Mono', 'Lucida Console', 'Lucida Sans Typewriter', 'Liberation Mono', 'Monaco', 'Courier New', Courier, monospace"; -export const TERMINAL_FONT_FAMILY_1 = MONOSPACE_FONT_FAMILY; -export const TERMINAL_FONT_FAMILY_2 = MONOSPACE_FONT_FAMILY.replace( - "IBM Plex Mono", - "Fira Code", -); +export const terminalFonts: Record = { + "fira-code": MONOSPACE_FONT_FAMILY.replace("IBM Plex Mono", "Fira Code"), + "ibm-plex-mono": MONOSPACE_FONT_FAMILY, + + "": MONOSPACE_FONT_FAMILY, +}; + export const BODY_FONT_FAMILY = `"Inter Variable", system-ui, sans-serif`; export const navHeight = 62; export const containerWidth = 1380; From ae1cb128e31fa0e0cdd6a021fd4a859ba00935a5 Mon Sep 17 00:00:00 2001 From: Marcin Tojek Date: Fri, 4 Apr 2025 11:59:43 +0000 Subject: [PATCH 07/22] Fix golden --- cli/testdata/TestProvisioners_Golden/list.golden | 2 +- cli/testdata/coder_provisioner_list.golden | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/cli/testdata/TestProvisioners_Golden/list.golden b/cli/testdata/TestProvisioners_Golden/list.golden index 35844d8b9c50e..3f50f90746744 100644 --- a/cli/testdata/TestProvisioners_Golden/list.golden +++ b/cli/testdata/TestProvisioners_Golden/list.golden @@ -1,4 +1,4 @@ -ID CREATED AT LAST SEEN AT NAME VERSION TAGS KEY NAME STATUS CURRENT JOB ID CURRENT JOB STATUS PREVIOUS JOB ID PREVIOUS JOB STATUS ORGANIZATION +ID CREATED AT LAST SEEN AT NAME VERSION TAGS KEY NAME STATUS CURRENT JOB ID CURRENT JOB STATUS PREVIOUS JOB ID PREVIOUS JOB STATUS ORGANIZATION 00000000-0000-0000-aaaa-000000000000 ====[timestamp]===== ====[timestamp]===== default-provisioner v0.0.0-devel map[owner: scope:organization] built-in idle 00000000-0000-0000-bbbb-000000000001 succeeded Coder 00000000-0000-0000-aaaa-000000000001 ====[timestamp]===== ====[timestamp]===== provisioner-1 v0.0.0 map[foo:bar owner: scope:organization] built-in busy 00000000-0000-0000-bbbb-000000000002 running Coder 00000000-0000-0000-aaaa-000000000002 ====[timestamp]===== ====[timestamp]===== provisioner-2 v0.0.0 map[owner: scope:organization] built-in offline 00000000-0000-0000-bbbb-000000000003 succeeded Coder diff --git a/cli/testdata/coder_provisioner_list.golden b/cli/testdata/coder_provisioner_list.golden index e34db5605fd81..64941eebf5b89 100644 --- a/cli/testdata/coder_provisioner_list.golden +++ b/cli/testdata/coder_provisioner_list.golden @@ -1,2 +1,2 @@ -CREATED AT LAST SEEN AT KEY NAME NAME VERSION STATUS TAGS +CREATED AT LAST SEEN AT KEY NAME NAME VERSION STATUS TAGS ====[timestamp]===== ====[timestamp]===== built-in test v0.0.0-devel idle map[owner: scope:organization] From 8f9e313e89be20603f6551114d7ae1869a64c116 Mon Sep 17 00:00:00 2001 From: Marcin Tojek Date: Fri, 4 Apr 2025 14:03:37 +0200 Subject: [PATCH 08/22] fix version --- provisioner/terraform/testdata/resources/version.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/provisioner/terraform/testdata/resources/version.txt b/provisioner/terraform/testdata/resources/version.txt index 720c7384c6195..ca7176690dd6f 100644 --- a/provisioner/terraform/testdata/resources/version.txt +++ b/provisioner/terraform/testdata/resources/version.txt @@ -1 +1 @@ -1.11.1 +1.11.2 From 94a358798b411017dd57e51b37b4a259bdeda376 Mon Sep 17 00:00:00 2001 From: Marcin Tojek Date: Fri, 4 Apr 2025 14:23:21 +0200 Subject: [PATCH 09/22] WIP --- coderd/users.go | 2 +- .../TerminalPage/TerminalPage.stories.tsx | 34 +++++++++++++++++++ 2 files changed, 35 insertions(+), 1 deletion(-) diff --git a/coderd/users.go b/coderd/users.go index 030935871ce56..7af8fb6508d76 100644 --- a/coderd/users.go +++ b/coderd/users.go @@ -1035,7 +1035,7 @@ func (api *API) putUserAppearanceSettings(rw http.ResponseWriter, r *http.Reques }) if err != nil { httpapi.Write(ctx, rw, http.StatusInternalServerError, codersdk.Response{ - Message: "Internal error updating user theme prefence.", + Message: "Internal error updating user theme preference.", Detail: err.Error(), }) return diff --git a/site/src/pages/TerminalPage/TerminalPage.stories.tsx b/site/src/pages/TerminalPage/TerminalPage.stories.tsx index 4cf052668bb06..aa24485353894 100644 --- a/site/src/pages/TerminalPage/TerminalPage.stories.tsx +++ b/site/src/pages/TerminalPage/TerminalPage.stories.tsx @@ -17,6 +17,7 @@ import { MockEntitlements, MockExperiments, MockUser, + MockUserAppearanceSettings, MockWorkspace, MockWorkspaceAgent, } from "testHelpers/entities"; @@ -76,6 +77,7 @@ const meta = { key: getAuthorizationKey({ checks: permissionChecks }), data: { editWorkspaceProxies: true }, }, + { key: ["me", "appearance"], data: MockUserAppearanceSettings }, ], chromatic: { delay: 300 }, }, @@ -106,6 +108,38 @@ export const Starting: Story = { }, }; +export const FontFiraCode: Story = { + decorators: [withWebSocket], + parameters: { + ...meta.parameters, + webSocket: [ + { + event: "message", + // Copied and pasted this from browser + data: "➜ codergit:(bq/refactor-web-term-notifications) ✗", + }, + ], + queries: [ + ...meta.parameters.queries.filter( + (q) => + !( + Array.isArray(q.key) && + q.key[0] === "me" && + q.key[1] === "appearance" + ), + ), + { + key: ["me", "appearance"], + data: { + ...MockUserAppearanceSettings, + terminal_font: "fira-code", + }, + }, + createWorkspaceWithAgent("ready"), + ], + }, +}; + export const Ready: Story = { decorators: [withWebSocket], parameters: { From bdbae61d457906f2c32d199f23c284fafc9b8387 Mon Sep 17 00:00:00 2001 From: Marcin Tojek Date: Fri, 4 Apr 2025 14:34:27 +0200 Subject: [PATCH 10/22] jest --- .../AppearancePage/AppearancePage.test.tsx | 29 ++++++++++++++++--- 1 file changed, 25 insertions(+), 4 deletions(-) diff --git a/site/src/pages/UserSettingsPage/AppearancePage/AppearancePage.test.tsx b/site/src/pages/UserSettingsPage/AppearancePage/AppearancePage.test.tsx index 5b8db73dd95ab..59dc62980b9f0 100644 --- a/site/src/pages/UserSettingsPage/AppearancePage/AppearancePage.test.tsx +++ b/site/src/pages/UserSettingsPage/AppearancePage/AppearancePage.test.tsx @@ -12,14 +12,14 @@ describe("appearance page", () => { jest.spyOn(API, "updateAppearanceSettings").mockResolvedValueOnce({ ...MockUser, theme_preference: "dark", - terminal_font: "", + terminal_font: "fira-code", }); const dark = await screen.findByText("Dark"); await userEvent.click(dark); // Check if the API was called correctly - expect(API.updateAppearanceSettings).toBeCalledTimes(0); + expect(API.updateAppearanceSettings).toHaveBeenCalledTimes(0); }); it("changes theme to light", async () => { @@ -27,17 +27,38 @@ describe("appearance page", () => { jest.spyOn(API, "updateAppearanceSettings").mockResolvedValueOnce({ ...MockUser, + terminal_font: "ibm-plex-mono", theme_preference: "light", - terminal_font: "", }); const light = await screen.findByText("Light"); await userEvent.click(light); // Check if the API was called correctly - expect(API.updateAppearanceSettings).toBeCalledTimes(1); + expect(API.updateAppearanceSettings).toHaveBeenCalledTimes(1); expect(API.updateAppearanceSettings).toHaveBeenCalledWith({ + terminal_font: "ibm-plex-mono", theme_preference: "light", }); }); + + it("changes font to fira code", async () => { + renderWithAuth(); + + jest.spyOn(API, "updateAppearanceSettings").mockResolvedValueOnce({ + ...MockUser, + terminal_font: "fira-code", + theme_preference: "dark", + }); + + const ibmPlex = await screen.findByText("Fira Code"); + await userEvent.click(ibmPlex); + + // Check if the API was called correctly + expect(API.updateAppearanceSettings).toHaveBeenCalledTimes(1); + expect(API.updateAppearanceSettings).toHaveBeenCalledWith({ + terminal_font: "fira-code", + theme_preference: "dark", + }); + }); }); From 33a6177e8206b6f8f1c2817cb79500fdffb61b31 Mon Sep 17 00:00:00 2001 From: Marcin Tojek Date: Fri, 4 Apr 2025 14:39:45 +0200 Subject: [PATCH 11/22] dbauthz_test.g --- coderd/database/dbauthz/dbauthz_test.go | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/coderd/database/dbauthz/dbauthz_test.go b/coderd/database/dbauthz/dbauthz_test.go index b110c1b17b327..8525ffa1095f2 100644 --- a/coderd/database/dbauthz/dbauthz_test.go +++ b/coderd/database/dbauthz/dbauthz_test.go @@ -1651,6 +1651,27 @@ func (s *MethodTestSuite) TestUser() { ThemePreference: uc.Value, }).Asserts(u, policy.ActionUpdatePersonal).Returns(uc) })) + s.Run("GetUserTerminalFont", s.Subtest(func(db database.Store, check *expects) { + ctx := context.Background() + u := dbgen.User(s.T(), db, database.User{}) + db.UpdateUserTerminalFont(ctx, database.UpdateUserTerminalFontParams{ + UserID: u.ID, + TerminalFont: "ibm-plex-mono", + }) + check.Args(u.ID).Asserts(u, policy.ActionReadPersonal).Returns("ibm-plex-mono") + })) + s.Run("UpdateUserTerminalFont", s.Subtest(func(db database.Store, check *expects) { + u := dbgen.User(s.T(), db, database.User{}) + uc := database.UserConfig{ + UserID: u.ID, + Key: "terminal-font", + Value: "ibm-plex-mono", + } + check.Args(database.UpdateUserTerminalFontParams{ + UserID: u.ID, + TerminalFont: uc.Value, + }).Asserts(u, policy.ActionUpdatePersonal).Returns(uc) + })) s.Run("UpdateUserStatus", s.Subtest(func(db database.Store, check *expects) { u := dbgen.User(s.T(), db, database.User{}) check.Args(database.UpdateUserStatusParams{ From 23a0768802fd74833352de9d73a0c77b827f2085 Mon Sep 17 00:00:00 2001 From: Marcin Tojek Date: Fri, 4 Apr 2025 15:15:13 +0200 Subject: [PATCH 12/22] check --- coderd/database/dbauthz/dbauthz_test.go | 2 +- coderd/users.go | 16 ++++++ coderd/users_test.go | 72 +++++++++++++++++++++++++ codersdk/users.go | 22 ++++++-- 4 files changed, 107 insertions(+), 5 deletions(-) diff --git a/coderd/database/dbauthz/dbauthz_test.go b/coderd/database/dbauthz/dbauthz_test.go index 8525ffa1095f2..bd6ef69528335 100644 --- a/coderd/database/dbauthz/dbauthz_test.go +++ b/coderd/database/dbauthz/dbauthz_test.go @@ -1664,7 +1664,7 @@ func (s *MethodTestSuite) TestUser() { u := dbgen.User(s.T(), db, database.User{}) uc := database.UserConfig{ UserID: u.ID, - Key: "terminal-font", + Key: "terminal_font", Value: "ibm-plex-mono", } check.Args(database.UpdateUserTerminalFontParams{ diff --git a/coderd/users.go b/coderd/users.go index 7af8fb6508d76..9abc761e3d6eb 100644 --- a/coderd/users.go +++ b/coderd/users.go @@ -1029,6 +1029,13 @@ func (api *API) putUserAppearanceSettings(rw http.ResponseWriter, r *http.Reques return } + if !isValidFontName(params.TerminalFont) { + httpapi.Write(ctx, rw, http.StatusBadRequest, codersdk.Response{ + Message: "Unsupported font family.", + }) + return + } + updatedThemePreference, err := api.Database.UpdateUserThemePreference(ctx, database.UpdateUserThemePreferenceParams{ UserID: user.ID, ThemePreference: params.ThemePreference, @@ -1059,6 +1066,15 @@ func (api *API) putUserAppearanceSettings(rw http.ResponseWriter, r *http.Reques }) } +func isValidFontName(font codersdk.TerminalFontName) bool { + switch font { + case codersdk.TerminalFontIbmPlexMono, codersdk.TerminalFontFiraCode, "": + return true + default: + return false + } +} + // @Summary Update user password // @ID update-user-password // @Security CoderSessionToken diff --git a/coderd/users_test.go b/coderd/users_test.go index c21eca85a5ee7..2d6f773ecc167 100644 --- a/coderd/users_test.go +++ b/coderd/users_test.go @@ -1972,6 +1972,78 @@ func TestPostTokens(t *testing.T) { require.NoError(t, err) } +func TestUserTerminalFont(t *testing.T) { + t.Parallel() + + t.Run("valid font", func(t *testing.T) { + adminClient := coderdtest.New(t, nil) + firstUser := coderdtest.CreateFirstUser(t, adminClient) + client, _ := coderdtest.CreateAnotherUser(t, adminClient, firstUser.OrganizationID) + + ctx, cancel := context.WithTimeout(context.Background(), testutil.WaitLong) + defer cancel() + + // given + initial, err := client.GetUserAppearanceSettings(ctx, "me") + require.Equal(t, codersdk.TerminalFontName(""), initial.TerminalFont) + + // when + updated, err := client.UpdateUserAppearanceSettings(ctx, "me", codersdk.UpdateUserAppearanceSettingsRequest{ + ThemePreference: "light", + TerminalFont: "fira-code", + }) + require.NoError(t, err) + + // then + require.Equal(t, codersdk.TerminalFontFiraCode, updated.TerminalFont) + }) + + t.Run("unsupported font", func(t *testing.T) { + adminClient := coderdtest.New(t, nil) + firstUser := coderdtest.CreateFirstUser(t, adminClient) + client, _ := coderdtest.CreateAnotherUser(t, adminClient, firstUser.OrganizationID) + + ctx, cancel := context.WithTimeout(context.Background(), testutil.WaitLong) + defer cancel() + + // given + initial, err := client.GetUserAppearanceSettings(ctx, "me") + require.Equal(t, codersdk.TerminalFontName(""), initial.TerminalFont) + + // when + _, err = client.UpdateUserAppearanceSettings(ctx, "me", codersdk.UpdateUserAppearanceSettingsRequest{ + ThemePreference: "light", + TerminalFont: "foobar", + }) + + // then + require.Error(t, err) + }) + + t.Run("empty font is ok", func(t *testing.T) { + adminClient := coderdtest.New(t, nil) + firstUser := coderdtest.CreateFirstUser(t, adminClient) + client, _ := coderdtest.CreateAnotherUser(t, adminClient, firstUser.OrganizationID) + + ctx, cancel := context.WithTimeout(context.Background(), testutil.WaitLong) + defer cancel() + + // given + initial, err := client.GetUserAppearanceSettings(ctx, "me") + require.Equal(t, codersdk.TerminalFontName(""), initial.TerminalFont) + + // when + updated, err := client.UpdateUserAppearanceSettings(ctx, "me", codersdk.UpdateUserAppearanceSettingsRequest{ + ThemePreference: "light", + TerminalFont: "", + }) + + // then + require.NoError(t, err) + require.Equal(t, codersdk.TerminalFontName(""), updated.TerminalFont) + }) +} + func TestWorkspacesByUser(t *testing.T) { t.Parallel() t.Run("Empty", func(t *testing.T) { diff --git a/codersdk/users.go b/codersdk/users.go index 9f136f00235db..a4c2eea1f7012 100644 --- a/codersdk/users.go +++ b/codersdk/users.go @@ -477,17 +477,31 @@ func (c *Client) UpdateUserStatus(ctx context.Context, user string, status UserS return resp, json.NewDecoder(res.Body).Decode(&resp) } +// GetUserAppearanceSettings fetches the appearance settings for a user. +func (c *Client) GetUserAppearanceSettings(ctx context.Context, user string) (UserAppearanceSettings, error) { + res, err := c.Request(ctx, http.MethodGet, fmt.Sprintf("/api/v2/users/%s/appearance", user), nil) + if err != nil { + return UserAppearanceSettings{}, err + } + defer res.Body.Close() + if res.StatusCode != http.StatusOK { + return UserAppearanceSettings{}, ReadBodyAsError(res) + } + var resp UserAppearanceSettings + return resp, json.NewDecoder(res.Body).Decode(&resp) +} + // UpdateUserAppearanceSettings updates the appearance settings for a user. -func (c *Client) UpdateUserAppearanceSettings(ctx context.Context, user string, req UpdateUserAppearanceSettingsRequest) (User, error) { +func (c *Client) UpdateUserAppearanceSettings(ctx context.Context, user string, req UpdateUserAppearanceSettingsRequest) (UserAppearanceSettings, error) { res, err := c.Request(ctx, http.MethodPut, fmt.Sprintf("/api/v2/users/%s/appearance", user), req) if err != nil { - return User{}, err + return UserAppearanceSettings{}, err } defer res.Body.Close() if res.StatusCode != http.StatusOK { - return User{}, ReadBodyAsError(res) + return UserAppearanceSettings{}, ReadBodyAsError(res) } - var resp User + var resp UserAppearanceSettings return resp, json.NewDecoder(res.Body).Decode(&resp) } From 9bed6bc668f208f966778a2bab19314d037d0ff3 Mon Sep 17 00:00:00 2001 From: Marcin Tojek Date: Fri, 4 Apr 2025 15:35:21 +0200 Subject: [PATCH 13/22] go tests --- coderd/users_test.go | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/coderd/users_test.go b/coderd/users_test.go index 2d6f773ecc167..cbba319d1c0ce 100644 --- a/coderd/users_test.go +++ b/coderd/users_test.go @@ -2020,7 +2020,7 @@ func TestUserTerminalFont(t *testing.T) { require.Error(t, err) }) - t.Run("empty font is ok", func(t *testing.T) { + t.Run("undefined font is not ok", func(t *testing.T) { adminClient := coderdtest.New(t, nil) firstUser := coderdtest.CreateFirstUser(t, adminClient) client, _ := coderdtest.CreateAnotherUser(t, adminClient, firstUser.OrganizationID) @@ -2033,14 +2033,13 @@ func TestUserTerminalFont(t *testing.T) { require.Equal(t, codersdk.TerminalFontName(""), initial.TerminalFont) // when - updated, err := client.UpdateUserAppearanceSettings(ctx, "me", codersdk.UpdateUserAppearanceSettingsRequest{ + _, err = client.UpdateUserAppearanceSettings(ctx, "me", codersdk.UpdateUserAppearanceSettingsRequest{ ThemePreference: "light", TerminalFont: "", }) // then - require.NoError(t, err) - require.Equal(t, codersdk.TerminalFontName(""), updated.TerminalFont) + require.Error(t, err) }) } From f4c24efe2b06fe328ced15dc4a881791a0e03bf0 Mon Sep 17 00:00:00 2001 From: Marcin Tojek Date: Fri, 4 Apr 2025 15:41:54 +0200 Subject: [PATCH 14/22] fix --- coderd/users_test.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/coderd/users_test.go b/coderd/users_test.go index cbba319d1c0ce..ce084500a0c25 100644 --- a/coderd/users_test.go +++ b/coderd/users_test.go @@ -2008,6 +2008,7 @@ func TestUserTerminalFont(t *testing.T) { // given initial, err := client.GetUserAppearanceSettings(ctx, "me") + require.NoError(t, err) require.Equal(t, codersdk.TerminalFontName(""), initial.TerminalFont) // when @@ -2030,6 +2031,7 @@ func TestUserTerminalFont(t *testing.T) { // given initial, err := client.GetUserAppearanceSettings(ctx, "me") + require.NoError(t, err) require.Equal(t, codersdk.TerminalFontName(""), initial.TerminalFont) // when From 449e079867fbde93247e8731eed3f4804e61c790 Mon Sep 17 00:00:00 2001 From: Marcin Tojek Date: Fri, 4 Apr 2025 15:47:32 +0200 Subject: [PATCH 15/22] t.Parallel --- coderd/users_test.go | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/coderd/users_test.go b/coderd/users_test.go index ce084500a0c25..fdaad21a826a9 100644 --- a/coderd/users_test.go +++ b/coderd/users_test.go @@ -1976,6 +1976,8 @@ func TestUserTerminalFont(t *testing.T) { t.Parallel() t.Run("valid font", func(t *testing.T) { + t.Parallel() + adminClient := coderdtest.New(t, nil) firstUser := coderdtest.CreateFirstUser(t, adminClient) client, _ := coderdtest.CreateAnotherUser(t, adminClient, firstUser.OrganizationID) @@ -1985,6 +1987,7 @@ func TestUserTerminalFont(t *testing.T) { // given initial, err := client.GetUserAppearanceSettings(ctx, "me") + require.NoError(t, err) require.Equal(t, codersdk.TerminalFontName(""), initial.TerminalFont) // when @@ -1999,6 +2002,8 @@ func TestUserTerminalFont(t *testing.T) { }) t.Run("unsupported font", func(t *testing.T) { + t.Parallel() + adminClient := coderdtest.New(t, nil) firstUser := coderdtest.CreateFirstUser(t, adminClient) client, _ := coderdtest.CreateAnotherUser(t, adminClient, firstUser.OrganizationID) @@ -2022,6 +2027,8 @@ func TestUserTerminalFont(t *testing.T) { }) t.Run("undefined font is not ok", func(t *testing.T) { + t.Parallel() + adminClient := coderdtest.New(t, nil) firstUser := coderdtest.CreateFirstUser(t, adminClient) client, _ := coderdtest.CreateAnotherUser(t, adminClient, firstUser.OrganizationID) From 2a68eebf9fa0d0e0029d563e60c051afa6c0a864 Mon Sep 17 00:00:00 2001 From: Marcin Tojek Date: Mon, 7 Apr 2025 13:05:38 +0200 Subject: [PATCH 16/22] Review fixes --- .../TestProvisioners_Golden/list.golden | 2 +- cli/testdata/coder_provisioner_list.golden | 2 +- coderd/apidoc/docs.go | 22 +++------------- coderd/apidoc/swagger.json | 16 +++--------- coderd/users.go | 8 ++---- codersdk/users.go | 8 +++--- docs/reference/api/schemas.md | 18 ++----------- docs/reference/api/users.md | 6 ++--- .../terraform/testdata/resources/version.txt | 2 +- .../AppearancePage/AppearanceForm.tsx | 25 ++++++++++--------- site/src/theme/index.ts | 9 +++++++ 11 files changed, 43 insertions(+), 75 deletions(-) diff --git a/cli/testdata/TestProvisioners_Golden/list.golden b/cli/testdata/TestProvisioners_Golden/list.golden index 3f50f90746744..35844d8b9c50e 100644 --- a/cli/testdata/TestProvisioners_Golden/list.golden +++ b/cli/testdata/TestProvisioners_Golden/list.golden @@ -1,4 +1,4 @@ -ID CREATED AT LAST SEEN AT NAME VERSION TAGS KEY NAME STATUS CURRENT JOB ID CURRENT JOB STATUS PREVIOUS JOB ID PREVIOUS JOB STATUS ORGANIZATION +ID CREATED AT LAST SEEN AT NAME VERSION TAGS KEY NAME STATUS CURRENT JOB ID CURRENT JOB STATUS PREVIOUS JOB ID PREVIOUS JOB STATUS ORGANIZATION 00000000-0000-0000-aaaa-000000000000 ====[timestamp]===== ====[timestamp]===== default-provisioner v0.0.0-devel map[owner: scope:organization] built-in idle 00000000-0000-0000-bbbb-000000000001 succeeded Coder 00000000-0000-0000-aaaa-000000000001 ====[timestamp]===== ====[timestamp]===== provisioner-1 v0.0.0 map[foo:bar owner: scope:organization] built-in busy 00000000-0000-0000-bbbb-000000000002 running Coder 00000000-0000-0000-aaaa-000000000002 ====[timestamp]===== ====[timestamp]===== provisioner-2 v0.0.0 map[owner: scope:organization] built-in offline 00000000-0000-0000-bbbb-000000000003 succeeded Coder diff --git a/cli/testdata/coder_provisioner_list.golden b/cli/testdata/coder_provisioner_list.golden index 64941eebf5b89..e34db5605fd81 100644 --- a/cli/testdata/coder_provisioner_list.golden +++ b/cli/testdata/coder_provisioner_list.golden @@ -1,2 +1,2 @@ -CREATED AT LAST SEEN AT KEY NAME NAME VERSION STATUS TAGS +CREATED AT LAST SEEN AT KEY NAME NAME VERSION STATUS TAGS ====[timestamp]===== ====[timestamp]===== built-in test v0.0.0-devel idle map[owner: scope:organization] diff --git a/coderd/apidoc/docs.go b/coderd/apidoc/docs.go index 350486f25c8e0..61deac3008a8b 100644 --- a/coderd/apidoc/docs.go +++ b/coderd/apidoc/docs.go @@ -15604,7 +15604,7 @@ const docTemplate = `{ ], "x-enum-varnames": [ "TerminalFontUnknown", - "TerminalFontIbmPlexMono", + "TerminalFontIBMPlexMono", "TerminalFontFiraCode" ] }, @@ -15786,15 +15786,7 @@ const docTemplate = `{ ], "properties": { "terminal_font": { - "enum": [ - "ibm-plex-mono", - "fira-code" - ], - "allOf": [ - { - "$ref": "#/definitions/codersdk.TerminalFontName" - } - ] + "$ref": "#/definitions/codersdk.TerminalFontName" }, "theme_preference": { "type": "string" @@ -16088,15 +16080,7 @@ const docTemplate = `{ "type": "object", "properties": { "terminal_font": { - "enum": [ - "ibm-plex-mono", - "fira-code" - ], - "allOf": [ - { - "$ref": "#/definitions/codersdk.TerminalFontName" - } - ] + "$ref": "#/definitions/codersdk.TerminalFontName" }, "theme_preference": { "type": "string" diff --git a/coderd/apidoc/swagger.json b/coderd/apidoc/swagger.json index 4f89e11c53582..0d2b63ef3131a 100644 --- a/coderd/apidoc/swagger.json +++ b/coderd/apidoc/swagger.json @@ -14185,7 +14185,7 @@ "enum": ["", "ibm-plex-mono", "fira-code"], "x-enum-varnames": [ "TerminalFontUnknown", - "TerminalFontIbmPlexMono", + "TerminalFontIBMPlexMono", "TerminalFontFiraCode" ] }, @@ -14362,12 +14362,7 @@ "required": ["terminal_font", "theme_preference"], "properties": { "terminal_font": { - "enum": ["ibm-plex-mono", "fira-code"], - "allOf": [ - { - "$ref": "#/definitions/codersdk.TerminalFontName" - } - ] + "$ref": "#/definitions/codersdk.TerminalFontName" }, "theme_preference": { "type": "string" @@ -14635,12 +14630,7 @@ "type": "object", "properties": { "terminal_font": { - "enum": ["ibm-plex-mono", "fira-code"], - "allOf": [ - { - "$ref": "#/definitions/codersdk.TerminalFontName" - } - ] + "$ref": "#/definitions/codersdk.TerminalFontName" }, "theme_preference": { "type": "string" diff --git a/coderd/users.go b/coderd/users.go index 9abc761e3d6eb..03f900c01ddeb 100644 --- a/coderd/users.go +++ b/coderd/users.go @@ -6,6 +6,7 @@ import ( "errors" "fmt" "net/http" + "slices" "github.com/go-chi/chi/v5" "github.com/go-chi/render" @@ -1067,12 +1068,7 @@ func (api *API) putUserAppearanceSettings(rw http.ResponseWriter, r *http.Reques } func isValidFontName(font codersdk.TerminalFontName) bool { - switch font { - case codersdk.TerminalFontIbmPlexMono, codersdk.TerminalFontFiraCode, "": - return true - default: - return false - } + return slices.Contains(codersdk.TerminalFontNames, font) } // @Summary Update user password diff --git a/codersdk/users.go b/codersdk/users.go index a4c2eea1f7012..bdc9b521367f0 100644 --- a/codersdk/users.go +++ b/codersdk/users.go @@ -192,20 +192,22 @@ type ValidateUserPasswordResponse struct { // TerminalFontName is the name of supported terminal font type TerminalFontName string +var TerminalFontNames = []TerminalFontName{TerminalFontUnknown, TerminalFontIBMPlexMono, TerminalFontFiraCode} + const ( TerminalFontUnknown TerminalFontName = "" - TerminalFontIbmPlexMono TerminalFontName = "ibm-plex-mono" + TerminalFontIBMPlexMono TerminalFontName = "ibm-plex-mono" TerminalFontFiraCode TerminalFontName = "fira-code" ) type UserAppearanceSettings struct { ThemePreference string `json:"theme_preference"` - TerminalFont TerminalFontName `json:"terminal_font" enums:"ibm-plex-mono,fira-code"` + TerminalFont TerminalFontName `json:"terminal_font"` } type UpdateUserAppearanceSettingsRequest struct { ThemePreference string `json:"theme_preference" validate:"required"` - TerminalFont TerminalFontName `json:"terminal_font" validate:"required" enums:"ibm-plex-mono,fira-code"` + TerminalFont TerminalFontName `json:"terminal_font" validate:"required"` } type UpdateUserPasswordRequest struct { diff --git a/docs/reference/api/schemas.md b/docs/reference/api/schemas.md index 5b3b132b6546c..1359c2feec9fb 100644 --- a/docs/reference/api/schemas.md +++ b/docs/reference/api/schemas.md @@ -6925,7 +6925,7 @@ Restarts will only happen on weekdays in this list on weeks which line up with W ```json { - "terminal_font": "ibm-plex-mono", + "terminal_font": "", "theme_preference": "string" } ``` @@ -6937,13 +6937,6 @@ Restarts will only happen on weekdays in this list on weeks which line up with W | `terminal_font` | [codersdk.TerminalFontName](#codersdkterminalfontname) | true | | | | `theme_preference` | string | true | | | -#### Enumerated Values - -| Property | Value | -|-----------------|-----------------| -| `terminal_font` | `ibm-plex-mono` | -| `terminal_font` | `fira-code` | - ## codersdk.UpdateUserNotificationPreferences ```json @@ -7285,7 +7278,7 @@ If the schedule is empty, the user will be updated to use the default schedule.| ```json { - "terminal_font": "ibm-plex-mono", + "terminal_font": "", "theme_preference": "string" } ``` @@ -7297,13 +7290,6 @@ If the schedule is empty, the user will be updated to use the default schedule.| | `terminal_font` | [codersdk.TerminalFontName](#codersdkterminalfontname) | false | | | | `theme_preference` | string | false | | | -#### Enumerated Values - -| Property | Value | -|-----------------|-----------------| -| `terminal_font` | `ibm-plex-mono` | -| `terminal_font` | `fira-code` | - ## codersdk.UserLatency ```json diff --git a/docs/reference/api/users.md b/docs/reference/api/users.md index 61f4d390fccd4..43842fde6539b 100644 --- a/docs/reference/api/users.md +++ b/docs/reference/api/users.md @@ -501,7 +501,7 @@ curl -X GET http://coder-server:8080/api/v2/users/{user}/appearance \ ```json { - "terminal_font": "ibm-plex-mono", + "terminal_font": "", "theme_preference": "string" } ``` @@ -532,7 +532,7 @@ curl -X PUT http://coder-server:8080/api/v2/users/{user}/appearance \ ```json { - "terminal_font": "ibm-plex-mono", + "terminal_font": "", "theme_preference": "string" } ``` @@ -550,7 +550,7 @@ curl -X PUT http://coder-server:8080/api/v2/users/{user}/appearance \ ```json { - "terminal_font": "ibm-plex-mono", + "terminal_font": "", "theme_preference": "string" } ``` diff --git a/provisioner/terraform/testdata/resources/version.txt b/provisioner/terraform/testdata/resources/version.txt index ca7176690dd6f..720c7384c6195 100644 --- a/provisioner/terraform/testdata/resources/version.txt +++ b/provisioner/terraform/testdata/resources/version.txt @@ -1 +1 @@ -1.11.2 +1.11.1 diff --git a/site/src/pages/UserSettingsPage/AppearancePage/AppearanceForm.tsx b/site/src/pages/UserSettingsPage/AppearancePage/AppearanceForm.tsx index 219c3df892e6d..9d8761305583e 100644 --- a/site/src/pages/UserSettingsPage/AppearancePage/AppearanceForm.tsx +++ b/site/src/pages/UserSettingsPage/AppearancePage/AppearanceForm.tsx @@ -18,6 +18,7 @@ import type { FC } from "react"; import themes, { DEFAULT_TERMINAL_FONT, DEFAULT_THEME, + fontLabels, type Theme, } from "theme"; import { Section } from "../Section"; @@ -112,18 +113,18 @@ export const AppearanceForm: FC = ({ onChangeTerminalFont(toTerminalFontName(value)) } > - } - label={ -
IBM Plex Mono
- } - /> - } - label={
Fira Code
} - /> + {TerminalFontNames.filter((name) => name !== "").map((name) => ( + } + label={ +
+ IBM Plex Mono +
+ } + /> + ))} diff --git a/site/src/theme/index.ts b/site/src/theme/index.ts index 504241c8f8e0f..f9ca4cc82f134 100644 --- a/site/src/theme/index.ts +++ b/site/src/theme/index.ts @@ -1,7 +1,10 @@ // biome-ignore lint/nursery/noRestrictedImports: We still use `Theme` as a basis for our actual theme, for now. import type { Theme as MuiTheme } from "@mui/material/styles"; +import type { TerminalFontName } from "api/typesGenerated"; import type * as monaco from "monaco-editor"; +import { of } from "rxjs"; import type { Branding } from "./branding"; +import { terminalFonts } from "./constants"; import dark from "./dark"; import type { NewTheme } from "./experimental"; import type { ExternalImageModeStyles } from "./externalImages"; @@ -37,4 +40,10 @@ const theme = { export default theme; +export const fontLabels: Record = { + "fira-code": "Fira Code", + "ibm-plex-mono": "IBM Plex Mono", + "": "", // needed for enum completeness, otherwise fails the build +}; + export const DEFAULT_TERMINAL_FONT = "ibm-plex-mono"; From b9fa3fef31ab09578a5a447124be554b16b0ac55 Mon Sep 17 00:00:00 2001 From: Marcin Tojek Date: Mon, 7 Apr 2025 11:10:46 +0000 Subject: [PATCH 17/22] make gen --- cli/testdata/TestProvisioners_Golden/list.golden | 2 +- cli/testdata/coder_provisioner_list.golden | 2 +- provisioner/terraform/testdata/resources/version.txt | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/cli/testdata/TestProvisioners_Golden/list.golden b/cli/testdata/TestProvisioners_Golden/list.golden index 35844d8b9c50e..3f50f90746744 100644 --- a/cli/testdata/TestProvisioners_Golden/list.golden +++ b/cli/testdata/TestProvisioners_Golden/list.golden @@ -1,4 +1,4 @@ -ID CREATED AT LAST SEEN AT NAME VERSION TAGS KEY NAME STATUS CURRENT JOB ID CURRENT JOB STATUS PREVIOUS JOB ID PREVIOUS JOB STATUS ORGANIZATION +ID CREATED AT LAST SEEN AT NAME VERSION TAGS KEY NAME STATUS CURRENT JOB ID CURRENT JOB STATUS PREVIOUS JOB ID PREVIOUS JOB STATUS ORGANIZATION 00000000-0000-0000-aaaa-000000000000 ====[timestamp]===== ====[timestamp]===== default-provisioner v0.0.0-devel map[owner: scope:organization] built-in idle 00000000-0000-0000-bbbb-000000000001 succeeded Coder 00000000-0000-0000-aaaa-000000000001 ====[timestamp]===== ====[timestamp]===== provisioner-1 v0.0.0 map[foo:bar owner: scope:organization] built-in busy 00000000-0000-0000-bbbb-000000000002 running Coder 00000000-0000-0000-aaaa-000000000002 ====[timestamp]===== ====[timestamp]===== provisioner-2 v0.0.0 map[owner: scope:organization] built-in offline 00000000-0000-0000-bbbb-000000000003 succeeded Coder diff --git a/cli/testdata/coder_provisioner_list.golden b/cli/testdata/coder_provisioner_list.golden index e34db5605fd81..64941eebf5b89 100644 --- a/cli/testdata/coder_provisioner_list.golden +++ b/cli/testdata/coder_provisioner_list.golden @@ -1,2 +1,2 @@ -CREATED AT LAST SEEN AT KEY NAME NAME VERSION STATUS TAGS +CREATED AT LAST SEEN AT KEY NAME NAME VERSION STATUS TAGS ====[timestamp]===== ====[timestamp]===== built-in test v0.0.0-devel idle map[owner: scope:organization] diff --git a/provisioner/terraform/testdata/resources/version.txt b/provisioner/terraform/testdata/resources/version.txt index 720c7384c6195..0a5af26df3fdb 100644 --- a/provisioner/terraform/testdata/resources/version.txt +++ b/provisioner/terraform/testdata/resources/version.txt @@ -1 +1 @@ -1.11.1 +1.11.3 From 45245fc6808e0f4d661aa0f4b0c861104865ba27 Mon Sep 17 00:00:00 2001 From: Marcin Tojek Date: Mon, 7 Apr 2025 14:06:57 +0200 Subject: [PATCH 18/22] fixes --- .../UserSettingsPage/AppearancePage/AppearanceForm.tsx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/site/src/pages/UserSettingsPage/AppearancePage/AppearanceForm.tsx b/site/src/pages/UserSettingsPage/AppearancePage/AppearanceForm.tsx index 9d8761305583e..079ed3c523ddb 100644 --- a/site/src/pages/UserSettingsPage/AppearancePage/AppearanceForm.tsx +++ b/site/src/pages/UserSettingsPage/AppearancePage/AppearanceForm.tsx @@ -106,9 +106,9 @@ export const AppearanceForm: FC = ({ > onChangeTerminalFont(toTerminalFontName(value)) } @@ -120,7 +120,7 @@ export const AppearanceForm: FC = ({ control={} label={
- IBM Plex Mono + {fontLabels[name]}
} /> From 922bac233ea41427f4ddcc562150640a9b82534a Mon Sep 17 00:00:00 2001 From: Marcin Tojek Date: Mon, 7 Apr 2025 14:07:30 +0200 Subject: [PATCH 19/22] fix --- provisioner/terraform/testdata/resources/version.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/provisioner/terraform/testdata/resources/version.txt b/provisioner/terraform/testdata/resources/version.txt index 0a5af26df3fdb..ca7176690dd6f 100644 --- a/provisioner/terraform/testdata/resources/version.txt +++ b/provisioner/terraform/testdata/resources/version.txt @@ -1 +1 @@ -1.11.3 +1.11.2 From 59854a66eb24902ed673490b1340249498edfd86 Mon Sep 17 00:00:00 2001 From: Marcin Tojek Date: Mon, 7 Apr 2025 14:11:05 +0200 Subject: [PATCH 20/22] Fix --- .../AppearancePage/AppearanceForm.tsx | 12 ++++-------- site/src/theme/constants.ts | 9 ++++++++- site/src/theme/index.ts | 10 ---------- 3 files changed, 12 insertions(+), 19 deletions(-) diff --git a/site/src/pages/UserSettingsPage/AppearancePage/AppearanceForm.tsx b/site/src/pages/UserSettingsPage/AppearancePage/AppearanceForm.tsx index 079ed3c523ddb..9ecee2dfac83a 100644 --- a/site/src/pages/UserSettingsPage/AppearancePage/AppearanceForm.tsx +++ b/site/src/pages/UserSettingsPage/AppearancePage/AppearanceForm.tsx @@ -15,12 +15,8 @@ import { PreviewBadge } from "components/Badges/Badges"; import { Stack } from "components/Stack/Stack"; import { ThemeOverride } from "contexts/ThemeProvider"; import type { FC } from "react"; -import themes, { - DEFAULT_TERMINAL_FONT, - DEFAULT_THEME, - fontLabels, - type Theme, -} from "theme"; +import themes, { DEFAULT_THEME, type Theme } from "theme"; +import { DEFAULT_TERMINAL_FONT, terminalFontLabels } from "theme/constants"; import { Section } from "../Section"; export interface AppearanceFormProps { @@ -119,8 +115,8 @@ export const AppearanceForm: FC = ({ value={name} control={} label={ -
- {fontLabels[name]} +
+ {terminalFontLabels[name]}
} /> diff --git a/site/src/theme/constants.ts b/site/src/theme/constants.ts index e2d5a07a5026c..162e67310749c 100644 --- a/site/src/theme/constants.ts +++ b/site/src/theme/constants.ts @@ -3,14 +3,21 @@ import type { TerminalFontName } from "api/typesGenerated"; export const borderRadius = 8; export const MONOSPACE_FONT_FAMILY = "'IBM Plex Mono', 'Lucida Console', 'Lucida Sans Typewriter', 'Liberation Mono', 'Monaco', 'Courier New', Courier, monospace"; +export const BODY_FONT_FAMILY = `"Inter Variable", system-ui, sans-serif`; + export const terminalFonts: Record = { "fira-code": MONOSPACE_FONT_FAMILY.replace("IBM Plex Mono", "Fira Code"), "ibm-plex-mono": MONOSPACE_FONT_FAMILY, "": MONOSPACE_FONT_FAMILY, }; +export const terminalFontLabels: Record = { + "fira-code": "Fira Code", + "ibm-plex-mono": "IBM Plex Mono", + "": "", // needed for enum completeness, otherwise fails the build +}; +export const DEFAULT_TERMINAL_FONT = "ibm-plex-mono"; -export const BODY_FONT_FAMILY = `"Inter Variable", system-ui, sans-serif`; export const navHeight = 62; export const containerWidth = 1380; export const containerWidthMedium = 1080; diff --git a/site/src/theme/index.ts b/site/src/theme/index.ts index f9ca4cc82f134..15dc4349dc238 100644 --- a/site/src/theme/index.ts +++ b/site/src/theme/index.ts @@ -2,9 +2,7 @@ import type { Theme as MuiTheme } from "@mui/material/styles"; import type { TerminalFontName } from "api/typesGenerated"; import type * as monaco from "monaco-editor"; -import { of } from "rxjs"; import type { Branding } from "./branding"; -import { terminalFonts } from "./constants"; import dark from "./dark"; import type { NewTheme } from "./experimental"; import type { ExternalImageModeStyles } from "./externalImages"; @@ -39,11 +37,3 @@ const theme = { } satisfies Record; export default theme; - -export const fontLabels: Record = { - "fira-code": "Fira Code", - "ibm-plex-mono": "IBM Plex Mono", - "": "", // needed for enum completeness, otherwise fails the build -}; - -export const DEFAULT_TERMINAL_FONT = "ibm-plex-mono"; From 61fca63a6491162ac15fd13dfe372eecd33349ba Mon Sep 17 00:00:00 2001 From: Marcin Tojek Date: Mon, 7 Apr 2025 14:12:21 +0200 Subject: [PATCH 21/22] Fix --- site/src/pages/TerminalPage/TerminalPage.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/site/src/pages/TerminalPage/TerminalPage.tsx b/site/src/pages/TerminalPage/TerminalPage.tsx index a6d6b712de497..9740e239233a4 100644 --- a/site/src/pages/TerminalPage/TerminalPage.tsx +++ b/site/src/pages/TerminalPage/TerminalPage.tsx @@ -19,8 +19,8 @@ import { type FC, useCallback, useEffect, useRef, useState } from "react"; import { Helmet } from "react-helmet-async"; import { useQuery } from "react-query"; import { useNavigate, useParams, useSearchParams } from "react-router-dom"; -import themes, { DEFAULT_TERMINAL_FONT } from "theme"; -import { terminalFonts } from "theme/constants"; +import themes from "theme"; +import { DEFAULT_TERMINAL_FONT, terminalFonts } from "theme/constants"; import { pageTitle } from "utils/page"; import { openMaybePortForwardedURL } from "utils/portForward"; import { terminalWebsocketUrl } from "utils/terminal"; From b22e626500e8d9942717b92b74bf9781fa7614d3 Mon Sep 17 00:00:00 2001 From: Marcin Tojek Date: Mon, 7 Apr 2025 14:15:31 +0200 Subject: [PATCH 22/22] cleanup --- site/src/theme/index.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/site/src/theme/index.ts b/site/src/theme/index.ts index 15dc4349dc238..a36bd9b223e8d 100644 --- a/site/src/theme/index.ts +++ b/site/src/theme/index.ts @@ -1,6 +1,5 @@ // biome-ignore lint/nursery/noRestrictedImports: We still use `Theme` as a basis for our actual theme, for now. import type { Theme as MuiTheme } from "@mui/material/styles"; -import type { TerminalFontName } from "api/typesGenerated"; import type * as monaco from "monaco-editor"; import type { Branding } from "./branding"; import dark from "./dark"; pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy