From 524005b3b73d4eb7074b4d266ba454bfadfeae2b Mon Sep 17 00:00:00 2001 From: McKayla Washburn Date: Thu, 13 Feb 2025 22:54:59 +0000 Subject: [PATCH 01/20] nom --- .../migrations/000293_user_configs.down.sql | 57 +++++++++++++++++ .../migrations/000293_user_configs.up.sql | 62 +++++++++++++++++++ 2 files changed, 119 insertions(+) create mode 100644 coderd/database/migrations/000293_user_configs.down.sql create mode 100644 coderd/database/migrations/000293_user_configs.up.sql diff --git a/coderd/database/migrations/000293_user_configs.down.sql b/coderd/database/migrations/000293_user_configs.down.sql new file mode 100644 index 0000000000000..e3fb8d9403cc7 --- /dev/null +++ b/coderd/database/migrations/000293_user_configs.down.sql @@ -0,0 +1,57 @@ +-- Put back "theme_preference" column +ALTER TABLE users ADD COLUMN IF NOT EXISTS + theme_preference text DEFAULT ''::text NOT NULL; + +-- Copy "theme_preference" back to "users" +UPDATE users (theme_preference) + SELECT value + FROM user_configs + WHERE users.id = user_configs.user_id + AND user_configs.key = 'theme_preference'; + +-- Drop the "user_configs" table. +DROP TABLE user_configs; + +-- Replace "group_members_expanded", and bring back with "theme_preference" +DROP VIEW group_members_expanded; +-- Taken from 000242_group_members_view.up.sql +CREATE VIEW + group_members_expanded +AS +-- If the group is a user made group, then we need to check the group_members table. +-- If it is the "Everyone" group, then we need to check the organization_members table. +WITH all_members AS ( + SELECT user_id, group_id FROM group_members + UNION + SELECT user_id, organization_id AS group_id FROM organization_members +) +SELECT + users.id AS user_id, + users.email AS user_email, + users.username AS user_username, + users.hashed_password AS user_hashed_password, + users.created_at AS user_created_at, + users.updated_at AS user_updated_at, + users.status AS user_status, + users.rbac_roles AS user_rbac_roles, + users.login_type AS user_login_type, + users.avatar_url AS user_avatar_url, + users.deleted AS user_deleted, + users.last_seen_at AS user_last_seen_at, + users.quiet_hours_schedule AS user_quiet_hours_schedule, + users.theme_preference AS user_theme_preference, + users.name AS user_name, + users.github_com_user_id AS user_github_com_user_id, + groups.organization_id AS organization_id, + groups.name AS group_name, + all_members.group_id AS group_id +FROM + all_members +JOIN + users ON users.id = all_members.user_id +JOIN + groups ON groups.id = all_members.group_id +WHERE + users.deleted = 'false'; + +COMMENT ON VIEW group_members_expanded IS 'Joins group members with user information, organization ID, group name. Includes both regular group members and organization members (as part of the "Everyone" group).'; diff --git a/coderd/database/migrations/000293_user_configs.up.sql b/coderd/database/migrations/000293_user_configs.up.sql new file mode 100644 index 0000000000000..931033f419236 --- /dev/null +++ b/coderd/database/migrations/000293_user_configs.up.sql @@ -0,0 +1,62 @@ +CREATE TABLE IF NOT EXISTS user_configs ( + user_id uuid NOT NULL, + key varchar(256) NOT NULL, + value text NOT NULL +); + +ALTER TABLE ONLY user_configs + ADD CONSTRAINT unique_key_per_user UNIQUE (user_id, key); + + +-- +INSERT INTO user_configs (user_id, key, value) + SELECT id, 'theme_preference', theme_preference + FROM users + WHERE users.theme_preference IS NOT NULL; + + +-- Replace "group_members_expanded" without "theme_preference" +DROP VIEW group_members_expanded; +-- Taken from 000242_group_members_view.up.sql +CREATE VIEW + group_members_expanded +AS +-- If the group is a user made group, then we need to check the group_members table. +-- If it is the "Everyone" group, then we need to check the organization_members table. +WITH all_members AS ( + SELECT user_id, group_id FROM group_members + UNION + SELECT user_id, organization_id AS group_id FROM organization_members +) +SELECT + users.id AS user_id, + users.email AS user_email, + users.username AS user_username, + users.hashed_password AS user_hashed_password, + users.created_at AS user_created_at, + users.updated_at AS user_updated_at, + users.status AS user_status, + users.rbac_roles AS user_rbac_roles, + users.login_type AS user_login_type, + users.avatar_url AS user_avatar_url, + users.deleted AS user_deleted, + users.last_seen_at AS user_last_seen_at, + users.quiet_hours_schedule AS user_quiet_hours_schedule, + users.name AS user_name, + users.github_com_user_id AS user_github_com_user_id, + groups.organization_id AS organization_id, + groups.name AS group_name, + all_members.group_id AS group_id +FROM + all_members +JOIN + users ON users.id = all_members.user_id +JOIN + groups ON groups.id = all_members.group_id +WHERE + users.deleted = 'false'; + +COMMENT ON VIEW group_members_expanded IS 'Joins group members with user information, organization ID, group name. Includes both regular group members and organization members (as part of the "Everyone" group).'; + +-- Drop the "theme_preference" column now that the view no longer depends on it. +ALTER TABLE users DROP COLUMN theme_preference; From eadd8508f32fe894779c04a9c8417e19e31b4c27 Mon Sep 17 00:00:00 2001 From: McKayla Washburn Date: Thu, 13 Feb 2025 23:58:33 +0000 Subject: [PATCH 02/20] =?UTF-8?q?=F0=9F=A7=AA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- coderd/audit.go | 1 - coderd/database/db2sdk/db2sdk.go | 16 ++-- coderd/database/dbauthz/dbauthz.go | 8 +- coderd/database/dbauthz/dbauthz_test.go | 12 ++- coderd/database/dbgen/dbgen.go | 1 - coderd/database/dbmem/dbmem.go | 63 ++++++++------- coderd/database/dbmetrics/querymetrics.go | 2 +- coderd/database/dbmock/dbmock.go | 4 +- coderd/database/dump.sql | 13 +++- coderd/database/modelmethods.go | 27 ++++--- coderd/database/modelqueries.go | 2 - coderd/database/models.go | 9 ++- coderd/database/querier.go | 2 +- coderd/database/queries.sql.go | 93 ++++++++--------------- coderd/database/queries/auditlogs.sql | 1 - coderd/database/queries/users.sql | 16 ++-- coderd/database/unique_constraint.go | 1 + coderd/users.go | 3 +- codersdk/users.go | 5 +- site/src/api/typesGenerated.ts | 1 - 20 files changed, 130 insertions(+), 150 deletions(-) diff --git a/coderd/audit.go b/coderd/audit.go index f764094782a2f..8e7e1717f3955 100644 --- a/coderd/audit.go +++ b/coderd/audit.go @@ -204,7 +204,6 @@ func (api *API) convertAuditLog(ctx context.Context, dblog database.GetAuditLogs Deleted: dblog.UserDeleted.Bool, LastSeenAt: dblog.UserLastSeenAt.Time, QuietHoursSchedule: dblog.UserQuietHoursSchedule.String, - ThemePreference: dblog.UserThemePreference.String, Name: dblog.UserName.String, }, []uuid.UUID{}) user = &sdkUser diff --git a/coderd/database/db2sdk/db2sdk.go b/coderd/database/db2sdk/db2sdk.go index 8d2a75960bd0e..ddd5089fcf0d6 100644 --- a/coderd/database/db2sdk/db2sdk.go +++ b/coderd/database/db2sdk/db2sdk.go @@ -149,14 +149,13 @@ func ReducedUser(user database.User) codersdk.ReducedUser { Username: user.Username, AvatarURL: user.AvatarURL, }, - Email: user.Email, - Name: user.Name, - CreatedAt: user.CreatedAt, - UpdatedAt: user.UpdatedAt, - LastSeenAt: user.LastSeenAt, - Status: codersdk.UserStatus(user.Status), - LoginType: codersdk.LoginType(user.LoginType), - ThemePreference: user.ThemePreference, + Email: user.Email, + Name: user.Name, + CreatedAt: user.CreatedAt, + UpdatedAt: user.UpdatedAt, + LastSeenAt: user.LastSeenAt, + Status: codersdk.UserStatus(user.Status), + LoginType: codersdk.LoginType(user.LoginType), } } @@ -175,7 +174,6 @@ func UserFromGroupMember(member database.GroupMember) database.User { Deleted: member.UserDeleted, LastSeenAt: member.UserLastSeenAt, QuietHoursSchedule: member.UserQuietHoursSchedule, - ThemePreference: member.UserThemePreference, Name: member.UserName, GithubComUserID: member.UserGithubComUserID, } diff --git a/coderd/database/dbauthz/dbauthz.go b/coderd/database/dbauthz/dbauthz.go index 545a94b0f678e..0701e2cd972bb 100644 --- a/coderd/database/dbauthz/dbauthz.go +++ b/coderd/database/dbauthz/dbauthz.go @@ -3911,13 +3911,13 @@ 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.User, error) { - u, err := q.db.GetUserByID(ctx, arg.ID) +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.User{}, err + return database.UserConfig{}, err } if err := q.authorizeContext(ctx, policy.ActionUpdatePersonal, u); err != nil { - return database.User{}, err + return database.UserConfig{}, err } return q.db.UpdateUserAppearanceSettings(ctx, arg) } diff --git a/coderd/database/dbauthz/dbauthz_test.go b/coderd/database/dbauthz/dbauthz_test.go index 46aa96bf1f7a9..afb87b2d8a8ca 100644 --- a/coderd/database/dbauthz/dbauthz_test.go +++ b/coderd/database/dbauthz/dbauthz_test.go @@ -1523,11 +1523,15 @@ func (s *MethodTestSuite) TestUser() { })) s.Run("UpdateUserAppearanceSettings", 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{ - ID: u.ID, - ThemePreference: u.ThemePreference, - UpdatedAt: u.UpdatedAt, - }).Asserts(u, policy.ActionUpdatePersonal).Returns(u) + UserID: u.ID, + ThemePreference: 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{}) diff --git a/coderd/database/dbgen/dbgen.go b/coderd/database/dbgen/dbgen.go index cfd360f740183..1f9eb841b6930 100644 --- a/coderd/database/dbgen/dbgen.go +++ b/coderd/database/dbgen/dbgen.go @@ -512,7 +512,6 @@ func GroupMember(t testing.TB, db database.Store, member database.GroupMemberTab UserDeleted: user.Deleted, UserLastSeenAt: user.LastSeenAt, UserQuietHoursSchedule: user.QuietHoursSchedule, - UserThemePreference: user.ThemePreference, UserName: user.Name, UserGithubComUserID: user.GithubComUserID, OrganizationID: group.OrganizationID, diff --git a/coderd/database/dbmem/dbmem.go b/coderd/database/dbmem/dbmem.go index 780a180f1ff35..2365617240453 100644 --- a/coderd/database/dbmem/dbmem.go +++ b/coderd/database/dbmem/dbmem.go @@ -55,43 +55,44 @@ func New() database.Store { mutex: &sync.RWMutex{}, data: &data{ apiKeys: make([]database.APIKey, 0), - organizationMembers: make([]database.OrganizationMember, 0), - organizations: make([]database.Organization, 0), - users: make([]database.User, 0), + auditLogs: make([]database.AuditLog, 0), + customRoles: make([]database.CustomRole, 0), dbcryptKeys: make([]database.DBCryptKey, 0), externalAuthLinks: make([]database.ExternalAuthLink, 0), - groups: make([]database.Group, 0), - groupMembers: make([]database.GroupMemberTable, 0), - auditLogs: make([]database.AuditLog, 0), files: make([]database.File, 0), gitSSHKey: make([]database.GitSSHKey, 0), + groups: make([]database.Group, 0), + groupMembers: make([]database.GroupMemberTable, 0), + licenses: make([]database.License, 0), + locks: map[int64]struct{}{}, notificationMessages: make([]database.NotificationMessage, 0), notificationPreferences: make([]database.NotificationPreference, 0), + organizationMembers: make([]database.OrganizationMember, 0), + organizations: make([]database.Organization, 0), parameterSchemas: make([]database.ParameterSchema, 0), + presets: make([]database.TemplateVersionPreset, 0), + presetParameters: make([]database.TemplateVersionPresetParameter, 0), provisionerDaemons: make([]database.ProvisionerDaemon, 0), + provisionerJobs: make([]database.ProvisionerJob, 0), + provisionerJobLogs: make([]database.ProvisionerJobLog, 0), provisionerKeys: make([]database.ProvisionerKey, 0), + runtimeConfig: map[string]string{}, + telemetryItems: make([]database.TelemetryItem, 0), + templateVersions: make([]database.TemplateVersionTable, 0), + templates: make([]database.TemplateTable, 0), + users: make([]database.User, 0), + userConfigs: make([]database.UserConfig, 0), + userStatusChanges: make([]database.UserStatusChange, 0), workspaceAgents: make([]database.WorkspaceAgent, 0), - provisionerJobLogs: make([]database.ProvisionerJobLog, 0), workspaceResources: make([]database.WorkspaceResource, 0), workspaceModules: make([]database.WorkspaceModule, 0), workspaceResourceMetadata: make([]database.WorkspaceResourceMetadatum, 0), - provisionerJobs: make([]database.ProvisionerJob, 0), - templateVersions: make([]database.TemplateVersionTable, 0), - templates: make([]database.TemplateTable, 0), workspaceAgentStats: make([]database.WorkspaceAgentStat, 0), workspaceAgentLogs: make([]database.WorkspaceAgentLog, 0), workspaceBuilds: make([]database.WorkspaceBuild, 0), workspaceApps: make([]database.WorkspaceApp, 0), workspaces: make([]database.WorkspaceTable, 0), - licenses: make([]database.License, 0), workspaceProxies: make([]database.WorkspaceProxy, 0), - customRoles: make([]database.CustomRole, 0), - locks: map[int64]struct{}{}, - runtimeConfig: map[string]string{}, - userStatusChanges: make([]database.UserStatusChange, 0), - telemetryItems: make([]database.TelemetryItem, 0), - presets: make([]database.TemplateVersionPreset, 0), - presetParameters: make([]database.TemplateVersionPresetParameter, 0), }, } // Always start with a default org. Matching migration 198. @@ -222,6 +223,7 @@ type data struct { templateVersionWorkspaceTags []database.TemplateVersionWorkspaceTag templates []database.TemplateTable templateUsageStats []database.TemplateUsageStat + userConfigs []database.UserConfig workspaceAgents []database.WorkspaceAgent workspaceAgentMetadata []database.WorkspaceAgentMetadatum workspaceAgentLogs []database.WorkspaceAgentLog @@ -888,7 +890,6 @@ func (q *FakeQuerier) getGroupMemberNoLock(ctx context.Context, userID, groupID UserDeleted: user.Deleted, UserLastSeenAt: user.LastSeenAt, UserQuietHoursSchedule: user.QuietHoursSchedule, - UserThemePreference: user.ThemePreference, UserName: user.Name, UserGithubComUserID: user.GithubComUserID, OrganizationID: orgID, @@ -10064,24 +10065,31 @@ func (q *FakeQuerier) UpdateTemplateWorkspacesLastUsedAt(_ context.Context, arg return nil } -func (q *FakeQuerier) UpdateUserAppearanceSettings(_ context.Context, arg database.UpdateUserAppearanceSettingsParams) (database.User, error) { +func (q *FakeQuerier) UpdateUserAppearanceSettings(_ context.Context, arg database.UpdateUserAppearanceSettingsParams) (database.UserConfig, error) { err := validateDatabaseType(arg) if err != nil { - return database.User{}, err + return database.UserConfig{}, err } q.mutex.Lock() defer q.mutex.Unlock() - for index, user := range q.users { - if user.ID != arg.ID { + for i, uc := range q.userConfigs { + if uc.UserID != arg.UserID || uc.Key != "theme_preference" { continue } - user.ThemePreference = arg.ThemePreference - q.users[index] = user - return user, nil + uc.Value = arg.ThemePreference + q.userConfigs[i] = uc + return uc, nil } - return database.User{}, sql.ErrNoRows + + 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 { @@ -12437,7 +12445,6 @@ func (q *FakeQuerier) GetAuthorizedAuditLogsOffset(ctx context.Context, arg data UserLastSeenAt: sql.NullTime{Time: user.LastSeenAt, Valid: userValid}, UserLoginType: database.NullLoginType{LoginType: user.LoginType, Valid: userValid}, UserDeleted: sql.NullBool{Bool: user.Deleted, Valid: userValid}, - UserThemePreference: sql.NullString{String: user.ThemePreference, Valid: userValid}, UserQuietHoursSchedule: sql.NullString{String: user.QuietHoursSchedule, Valid: userValid}, UserStatus: database.NullUserStatus{UserStatus: user.Status, Valid: userValid}, UserRoles: user.RBACRoles, diff --git a/coderd/database/dbmetrics/querymetrics.go b/coderd/database/dbmetrics/querymetrics.go index fc84f556aabfb..7d65310ad28d9 100644 --- a/coderd/database/dbmetrics/querymetrics.go +++ b/coderd/database/dbmetrics/querymetrics.go @@ -2471,7 +2471,7 @@ func (m queryMetricsStore) UpdateTemplateWorkspacesLastUsedAt(ctx context.Contex return r0 } -func (m queryMetricsStore) UpdateUserAppearanceSettings(ctx context.Context, arg database.UpdateUserAppearanceSettingsParams) (database.User, error) { +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()) diff --git a/coderd/database/dbmock/dbmock.go b/coderd/database/dbmock/dbmock.go index d51631316a3cd..44e6b0f48f257 100644 --- a/coderd/database/dbmock/dbmock.go +++ b/coderd/database/dbmock/dbmock.go @@ -5251,10 +5251,10 @@ func (mr *MockStoreMockRecorder) UpdateTemplateWorkspacesLastUsedAt(ctx, arg any } // UpdateUserAppearanceSettings mocks base method. -func (m *MockStore) UpdateUserAppearanceSettings(ctx context.Context, arg database.UpdateUserAppearanceSettingsParams) (database.User, error) { +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.User) + ret0, _ := ret[0].(database.UserConfig) ret1, _ := ret[1].(error) return ret0, ret1 } diff --git a/coderd/database/dump.sql b/coderd/database/dump.sql index 20e7d14b57d01..f080df4f10ad7 100644 --- a/coderd/database/dump.sql +++ b/coderd/database/dump.sql @@ -764,7 +764,6 @@ CREATE TABLE users ( deleted boolean DEFAULT false NOT NULL, last_seen_at timestamp without time zone DEFAULT '0001-01-01 00:00:00'::timestamp without time zone NOT NULL, quiet_hours_schedule text DEFAULT ''::text NOT NULL, - theme_preference text DEFAULT ''::text NOT NULL, name text DEFAULT ''::text NOT NULL, github_com_user_id bigint, hashed_one_time_passcode bytea, @@ -774,8 +773,6 @@ CREATE TABLE users ( COMMENT ON COLUMN users.quiet_hours_schedule IS 'Daily (!) cron schedule (with optional CRON_TZ) signifying the start of the user''s quiet hours. If empty, the default quiet hours on the instance is used instead.'; -COMMENT ON COLUMN users.theme_preference IS '"" can be interpreted as "the user does not care", falling back to the default theme'; - COMMENT ON COLUMN users.name IS 'Name of the Coder user'; COMMENT ON COLUMN users.github_com_user_id IS 'The GitHub.com numerical user ID. At time of implementation, this is used to check if the user has starred the Coder repository.'; @@ -807,7 +804,6 @@ CREATE VIEW group_members_expanded AS users.deleted AS user_deleted, users.last_seen_at AS user_last_seen_at, users.quiet_hours_schedule AS user_quiet_hours_schedule, - users.theme_preference AS user_theme_preference, users.name AS user_name, users.github_com_user_id AS user_github_com_user_id, groups.organization_id, @@ -1448,6 +1444,12 @@ CREATE VIEW template_with_names AS COMMENT ON VIEW template_with_names IS 'Joins in the display name information such as username, avatar, and organization name.'; +CREATE TABLE user_configs ( + user_id uuid NOT NULL, + key character varying(256) NOT NULL, + value text NOT NULL +); + CREATE TABLE user_deleted ( id uuid DEFAULT gen_random_uuid() NOT NULL, user_id uuid NOT NULL, @@ -2094,6 +2096,9 @@ ALTER TABLE ONLY template_versions ALTER TABLE ONLY templates ADD CONSTRAINT templates_pkey PRIMARY KEY (id); +ALTER TABLE ONLY user_configs + ADD CONSTRAINT unique_key_per_user UNIQUE (user_id, key); + ALTER TABLE ONLY user_deleted ADD CONSTRAINT user_deleted_pkey PRIMARY KEY (id); diff --git a/coderd/database/modelmethods.go b/coderd/database/modelmethods.go index 63e03ccb27f40..025469316cdb8 100644 --- a/coderd/database/modelmethods.go +++ b/coderd/database/modelmethods.go @@ -398,20 +398,19 @@ func ConvertUserRows(rows []GetUsersRow) []User { users := make([]User, len(rows)) for i, r := range rows { users[i] = User{ - ID: r.ID, - Email: r.Email, - Username: r.Username, - Name: r.Name, - HashedPassword: r.HashedPassword, - CreatedAt: r.CreatedAt, - UpdatedAt: r.UpdatedAt, - Status: r.Status, - RBACRoles: r.RBACRoles, - LoginType: r.LoginType, - AvatarURL: r.AvatarURL, - Deleted: r.Deleted, - LastSeenAt: r.LastSeenAt, - ThemePreference: r.ThemePreference, + ID: r.ID, + Email: r.Email, + Username: r.Username, + Name: r.Name, + HashedPassword: r.HashedPassword, + CreatedAt: r.CreatedAt, + UpdatedAt: r.UpdatedAt, + Status: r.Status, + RBACRoles: r.RBACRoles, + LoginType: r.LoginType, + AvatarURL: r.AvatarURL, + Deleted: r.Deleted, + LastSeenAt: r.LastSeenAt, } } diff --git a/coderd/database/modelqueries.go b/coderd/database/modelqueries.go index 78f6285e3c11a..c5646ea61394d 100644 --- a/coderd/database/modelqueries.go +++ b/coderd/database/modelqueries.go @@ -417,7 +417,6 @@ func (q *sqlQuerier) GetAuthorizedUsers(ctx context.Context, arg GetUsersParams, &i.Deleted, &i.LastSeenAt, &i.QuietHoursSchedule, - &i.ThemePreference, &i.Name, &i.GithubComUserID, &i.HashedOneTimePasscode, @@ -504,7 +503,6 @@ func (q *sqlQuerier) GetAuthorizedAuditLogsOffset(ctx context.Context, arg GetAu &i.UserRoles, &i.UserAvatarUrl, &i.UserDeleted, - &i.UserThemePreference, &i.UserQuietHoursSchedule, &i.OrganizationName, &i.OrganizationDisplayName, diff --git a/coderd/database/models.go b/coderd/database/models.go index fc11e1f4f5ebe..1d07d8637d1b0 100644 --- a/coderd/database/models.go +++ b/coderd/database/models.go @@ -2468,7 +2468,6 @@ type GroupMember struct { UserDeleted bool `db:"user_deleted" json:"user_deleted"` UserLastSeenAt time.Time `db:"user_last_seen_at" json:"user_last_seen_at"` UserQuietHoursSchedule string `db:"user_quiet_hours_schedule" json:"user_quiet_hours_schedule"` - UserThemePreference string `db:"user_theme_preference" json:"user_theme_preference"` UserName string `db:"user_name" json:"user_name"` UserGithubComUserID sql.NullInt64 `db:"user_github_com_user_id" json:"user_github_com_user_id"` OrganizationID uuid.UUID `db:"organization_id" json:"organization_id"` @@ -3025,8 +3024,6 @@ type User struct { LastSeenAt time.Time `db:"last_seen_at" json:"last_seen_at"` // Daily (!) cron schedule (with optional CRON_TZ) signifying the start of the user's quiet hours. If empty, the default quiet hours on the instance is used instead. QuietHoursSchedule string `db:"quiet_hours_schedule" json:"quiet_hours_schedule"` - // "" can be interpreted as "the user does not care", falling back to the default theme - ThemePreference string `db:"theme_preference" json:"theme_preference"` // Name of the Coder user Name string `db:"name" json:"name"` // The GitHub.com numerical user ID. At time of implementation, this is used to check if the user has starred the Coder repository. @@ -3037,6 +3034,12 @@ type User struct { OneTimePasscodeExpiresAt sql.NullTime `db:"one_time_passcode_expires_at" json:"one_time_passcode_expires_at"` } +type UserConfig struct { + UserID uuid.UUID `db:"user_id" json:"user_id"` + Key string `db:"key" json:"key"` + Value string `db:"value" json:"value"` +} + // Tracks when users were deleted type UserDeleted struct { ID uuid.UUID `db:"id" json:"id"` diff --git a/coderd/database/querier.go b/coderd/database/querier.go index 5f9856028b985..8ad30a5304169 100644 --- a/coderd/database/querier.go +++ b/coderd/database/querier.go @@ -498,7 +498,7 @@ 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) (User, 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 diff --git a/coderd/database/queries.sql.go b/coderd/database/queries.sql.go index d8c2b3a77dacf..70f3d65486af1 100644 --- a/coderd/database/queries.sql.go +++ b/coderd/database/queries.sql.go @@ -457,7 +457,6 @@ SELECT users.rbac_roles AS user_roles, users.avatar_url AS user_avatar_url, users.deleted AS user_deleted, - users.theme_preference AS user_theme_preference, users.quiet_hours_schedule AS user_quiet_hours_schedule, COALESCE(organizations.name, '') AS organization_name, COALESCE(organizations.display_name, '') AS organization_display_name, @@ -601,7 +600,6 @@ type GetAuditLogsOffsetRow struct { UserRoles pq.StringArray `db:"user_roles" json:"user_roles"` UserAvatarUrl sql.NullString `db:"user_avatar_url" json:"user_avatar_url"` UserDeleted sql.NullBool `db:"user_deleted" json:"user_deleted"` - UserThemePreference sql.NullString `db:"user_theme_preference" json:"user_theme_preference"` UserQuietHoursSchedule sql.NullString `db:"user_quiet_hours_schedule" json:"user_quiet_hours_schedule"` OrganizationName string `db:"organization_name" json:"organization_name"` OrganizationDisplayName string `db:"organization_display_name" json:"organization_display_name"` @@ -661,7 +659,6 @@ func (q *sqlQuerier) GetAuditLogsOffset(ctx context.Context, arg GetAuditLogsOff &i.UserRoles, &i.UserAvatarUrl, &i.UserDeleted, - &i.UserThemePreference, &i.UserQuietHoursSchedule, &i.OrganizationName, &i.OrganizationDisplayName, @@ -1574,7 +1571,7 @@ func (q *sqlQuerier) DeleteGroupMemberFromGroup(ctx context.Context, arg DeleteG } const getGroupMembers = `-- name: GetGroupMembers :many -SELECT user_id, user_email, user_username, user_hashed_password, user_created_at, user_updated_at, user_status, user_rbac_roles, user_login_type, user_avatar_url, user_deleted, user_last_seen_at, user_quiet_hours_schedule, user_theme_preference, user_name, user_github_com_user_id, organization_id, group_name, group_id FROM group_members_expanded +SELECT user_id, user_email, user_username, user_hashed_password, user_created_at, user_updated_at, user_status, user_rbac_roles, user_login_type, user_avatar_url, user_deleted, user_last_seen_at, user_quiet_hours_schedule, user_name, user_github_com_user_id, organization_id, group_name, group_id FROM group_members_expanded ` func (q *sqlQuerier) GetGroupMembers(ctx context.Context) ([]GroupMember, error) { @@ -1600,7 +1597,6 @@ func (q *sqlQuerier) GetGroupMembers(ctx context.Context) ([]GroupMember, error) &i.UserDeleted, &i.UserLastSeenAt, &i.UserQuietHoursSchedule, - &i.UserThemePreference, &i.UserName, &i.UserGithubComUserID, &i.OrganizationID, @@ -1621,7 +1617,7 @@ func (q *sqlQuerier) GetGroupMembers(ctx context.Context) ([]GroupMember, error) } const getGroupMembersByGroupID = `-- name: GetGroupMembersByGroupID :many -SELECT user_id, user_email, user_username, user_hashed_password, user_created_at, user_updated_at, user_status, user_rbac_roles, user_login_type, user_avatar_url, user_deleted, user_last_seen_at, user_quiet_hours_schedule, user_theme_preference, user_name, user_github_com_user_id, organization_id, group_name, group_id FROM group_members_expanded WHERE group_id = $1 +SELECT user_id, user_email, user_username, user_hashed_password, user_created_at, user_updated_at, user_status, user_rbac_roles, user_login_type, user_avatar_url, user_deleted, user_last_seen_at, user_quiet_hours_schedule, user_name, user_github_com_user_id, organization_id, group_name, group_id FROM group_members_expanded WHERE group_id = $1 ` func (q *sqlQuerier) GetGroupMembersByGroupID(ctx context.Context, groupID uuid.UUID) ([]GroupMember, error) { @@ -1647,7 +1643,6 @@ func (q *sqlQuerier) GetGroupMembersByGroupID(ctx context.Context, groupID uuid. &i.UserDeleted, &i.UserLastSeenAt, &i.UserQuietHoursSchedule, - &i.UserThemePreference, &i.UserName, &i.UserGithubComUserID, &i.OrganizationID, @@ -7427,7 +7422,7 @@ FROM ( -- Select all groups this user is a member of. This will also include -- the "Everyone" group for organizations the user is a member of. - SELECT user_id, user_email, user_username, user_hashed_password, user_created_at, user_updated_at, user_status, user_rbac_roles, user_login_type, user_avatar_url, user_deleted, user_last_seen_at, user_quiet_hours_schedule, user_theme_preference, user_name, user_github_com_user_id, organization_id, group_name, group_id FROM group_members_expanded + SELECT user_id, user_email, user_username, user_hashed_password, user_created_at, user_updated_at, user_status, user_rbac_roles, user_login_type, user_avatar_url, user_deleted, user_last_seen_at, user_quiet_hours_schedule, user_name, user_github_com_user_id, organization_id, group_name, group_id FROM group_members_expanded WHERE $1 = user_id AND $2 = group_members_expanded.organization_id @@ -10972,7 +10967,7 @@ func (q *sqlQuerier) GetAuthorizationUserRoles(ctx context.Context, userID uuid. 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, theme_preference, name, github_com_user_id, hashed_one_time_passcode, one_time_passcode_expires_at + 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 FROM users WHERE @@ -11004,7 +10999,6 @@ func (q *sqlQuerier) GetUserByEmailOrUsername(ctx context.Context, arg GetUserBy &i.Deleted, &i.LastSeenAt, &i.QuietHoursSchedule, - &i.ThemePreference, &i.Name, &i.GithubComUserID, &i.HashedOneTimePasscode, @@ -11015,7 +11009,7 @@ func (q *sqlQuerier) GetUserByEmailOrUsername(ctx context.Context, arg GetUserBy const getUserByID = `-- name: GetUserByID :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, theme_preference, name, github_com_user_id, hashed_one_time_passcode, one_time_passcode_expires_at + 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 FROM users WHERE @@ -11041,7 +11035,6 @@ func (q *sqlQuerier) GetUserByID(ctx context.Context, id uuid.UUID) (User, error &i.Deleted, &i.LastSeenAt, &i.QuietHoursSchedule, - &i.ThemePreference, &i.Name, &i.GithubComUserID, &i.HashedOneTimePasscode, @@ -11068,7 +11061,7 @@ func (q *sqlQuerier) GetUserCount(ctx context.Context) (int64, error) { 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, theme_preference, name, github_com_user_id, hashed_one_time_passcode, one_time_passcode_expires_at, COUNT(*) OVER() AS count + 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, COUNT(*) OVER() AS count FROM users WHERE @@ -11178,7 +11171,6 @@ type GetUsersRow struct { Deleted bool `db:"deleted" json:"deleted"` LastSeenAt time.Time `db:"last_seen_at" json:"last_seen_at"` QuietHoursSchedule string `db:"quiet_hours_schedule" json:"quiet_hours_schedule"` - ThemePreference string `db:"theme_preference" json:"theme_preference"` Name string `db:"name" json:"name"` GithubComUserID sql.NullInt64 `db:"github_com_user_id" json:"github_com_user_id"` HashedOneTimePasscode []byte `db:"hashed_one_time_passcode" json:"hashed_one_time_passcode"` @@ -11221,7 +11213,6 @@ func (q *sqlQuerier) GetUsers(ctx context.Context, arg GetUsersParams) ([]GetUse &i.Deleted, &i.LastSeenAt, &i.QuietHoursSchedule, - &i.ThemePreference, &i.Name, &i.GithubComUserID, &i.HashedOneTimePasscode, @@ -11242,7 +11233,7 @@ func (q *sqlQuerier) GetUsers(ctx context.Context, arg GetUsersParams) ([]GetUse } const getUsersByIDs = `-- name: GetUsersByIDs :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, theme_preference, name, github_com_user_id, hashed_one_time_passcode, one_time_passcode_expires_at FROM users WHERE id = ANY($1 :: uuid [ ]) +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 FROM users WHERE id = ANY($1 :: uuid [ ]) ` // This shouldn't check for deleted, because it's frequently used @@ -11271,7 +11262,6 @@ func (q *sqlQuerier) GetUsersByIDs(ctx context.Context, ids []uuid.UUID) ([]User &i.Deleted, &i.LastSeenAt, &i.QuietHoursSchedule, - &i.ThemePreference, &i.Name, &i.GithubComUserID, &i.HashedOneTimePasscode, @@ -11309,7 +11299,7 @@ VALUES -- if the status passed in is empty, fallback to dormant, which is what -- we were doing before. COALESCE(NULLIF($10::text, '')::user_status, 'dormant'::user_status) - ) RETURNING id, email, username, hashed_password, created_at, updated_at, status, rbac_roles, login_type, avatar_url, deleted, last_seen_at, quiet_hours_schedule, theme_preference, name, github_com_user_id, hashed_one_time_passcode, one_time_passcode_expires_at + ) RETURNING 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 ` type InsertUserParams struct { @@ -11353,7 +11343,6 @@ func (q *sqlQuerier) InsertUser(ctx context.Context, arg InsertUserParams) (User &i.Deleted, &i.LastSeenAt, &i.QuietHoursSchedule, - &i.ThemePreference, &i.Name, &i.GithubComUserID, &i.HashedOneTimePasscode, @@ -11415,45 +11404,29 @@ func (q *sqlQuerier) UpdateInactiveUsersToDormant(ctx context.Context, arg Updat } const updateUserAppearanceSettings = `-- name: UpdateUserAppearanceSettings :one -UPDATE - users +INSERT INTO + user_configs (user_id, key, value) +VALUES + ($1, 'theme_preference', $2) +ON CONFLICT + ON CONSTRAINT unique_key_per_user +DO UPDATE SET - theme_preference = $2, - updated_at = $3 -WHERE - id = $1 -RETURNING id, email, username, hashed_password, created_at, updated_at, status, rbac_roles, login_type, avatar_url, deleted, last_seen_at, quiet_hours_schedule, theme_preference, name, github_com_user_id, hashed_one_time_passcode, one_time_passcode_expires_at + value = $2 +WHERE user_configs.user_id = $1 + AND user_configs.key = 'theme_preference' +RETURNING user_id, key, value ` type UpdateUserAppearanceSettingsParams struct { - ID uuid.UUID `db:"id" json:"id"` + UserID uuid.UUID `db:"user_id" json:"user_id"` ThemePreference string `db:"theme_preference" json:"theme_preference"` - UpdatedAt time.Time `db:"updated_at" json:"updated_at"` } -func (q *sqlQuerier) UpdateUserAppearanceSettings(ctx context.Context, arg UpdateUserAppearanceSettingsParams) (User, error) { - row := q.db.QueryRowContext(ctx, updateUserAppearanceSettings, arg.ID, arg.ThemePreference, arg.UpdatedAt) - var i User - err := row.Scan( - &i.ID, - &i.Email, - &i.Username, - &i.HashedPassword, - &i.CreatedAt, - &i.UpdatedAt, - &i.Status, - &i.RBACRoles, - &i.LoginType, - &i.AvatarURL, - &i.Deleted, - &i.LastSeenAt, - &i.QuietHoursSchedule, - &i.ThemePreference, - &i.Name, - &i.GithubComUserID, - &i.HashedOneTimePasscode, - &i.OneTimePasscodeExpiresAt, - ) +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 } @@ -11539,7 +11512,7 @@ SET last_seen_at = $2, updated_at = $3 WHERE - id = $1 RETURNING id, email, username, hashed_password, created_at, updated_at, status, rbac_roles, login_type, avatar_url, deleted, last_seen_at, quiet_hours_schedule, theme_preference, name, github_com_user_id, hashed_one_time_passcode, one_time_passcode_expires_at + id = $1 RETURNING 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 ` type UpdateUserLastSeenAtParams struct { @@ -11565,7 +11538,6 @@ func (q *sqlQuerier) UpdateUserLastSeenAt(ctx context.Context, arg UpdateUserLas &i.Deleted, &i.LastSeenAt, &i.QuietHoursSchedule, - &i.ThemePreference, &i.Name, &i.GithubComUserID, &i.HashedOneTimePasscode, @@ -11587,7 +11559,7 @@ SET '':: bytea END WHERE - id = $2 RETURNING id, email, username, hashed_password, created_at, updated_at, status, rbac_roles, login_type, avatar_url, deleted, last_seen_at, quiet_hours_schedule, theme_preference, name, github_com_user_id, hashed_one_time_passcode, one_time_passcode_expires_at + id = $2 RETURNING 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 ` type UpdateUserLoginTypeParams struct { @@ -11612,7 +11584,6 @@ func (q *sqlQuerier) UpdateUserLoginType(ctx context.Context, arg UpdateUserLogi &i.Deleted, &i.LastSeenAt, &i.QuietHoursSchedule, - &i.ThemePreference, &i.Name, &i.GithubComUserID, &i.HashedOneTimePasscode, @@ -11632,7 +11603,7 @@ SET name = $6 WHERE id = $1 -RETURNING id, email, username, hashed_password, created_at, updated_at, status, rbac_roles, login_type, avatar_url, deleted, last_seen_at, quiet_hours_schedule, theme_preference, name, github_com_user_id, hashed_one_time_passcode, one_time_passcode_expires_at +RETURNING 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 ` type UpdateUserProfileParams struct { @@ -11668,7 +11639,6 @@ func (q *sqlQuerier) UpdateUserProfile(ctx context.Context, arg UpdateUserProfil &i.Deleted, &i.LastSeenAt, &i.QuietHoursSchedule, - &i.ThemePreference, &i.Name, &i.GithubComUserID, &i.HashedOneTimePasscode, @@ -11684,7 +11654,7 @@ SET quiet_hours_schedule = $2 WHERE id = $1 -RETURNING id, email, username, hashed_password, created_at, updated_at, status, rbac_roles, login_type, avatar_url, deleted, last_seen_at, quiet_hours_schedule, theme_preference, name, github_com_user_id, hashed_one_time_passcode, one_time_passcode_expires_at +RETURNING 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 ` type UpdateUserQuietHoursScheduleParams struct { @@ -11709,7 +11679,6 @@ func (q *sqlQuerier) UpdateUserQuietHoursSchedule(ctx context.Context, arg Updat &i.Deleted, &i.LastSeenAt, &i.QuietHoursSchedule, - &i.ThemePreference, &i.Name, &i.GithubComUserID, &i.HashedOneTimePasscode, @@ -11726,7 +11695,7 @@ SET rbac_roles = ARRAY(SELECT DISTINCT UNNEST($1 :: text[])) WHERE id = $2 -RETURNING id, email, username, hashed_password, created_at, updated_at, status, rbac_roles, login_type, avatar_url, deleted, last_seen_at, quiet_hours_schedule, theme_preference, name, github_com_user_id, hashed_one_time_passcode, one_time_passcode_expires_at +RETURNING 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 ` type UpdateUserRolesParams struct { @@ -11751,7 +11720,6 @@ func (q *sqlQuerier) UpdateUserRoles(ctx context.Context, arg UpdateUserRolesPar &i.Deleted, &i.LastSeenAt, &i.QuietHoursSchedule, - &i.ThemePreference, &i.Name, &i.GithubComUserID, &i.HashedOneTimePasscode, @@ -11767,7 +11735,7 @@ SET status = $2, updated_at = $3 WHERE - id = $1 RETURNING id, email, username, hashed_password, created_at, updated_at, status, rbac_roles, login_type, avatar_url, deleted, last_seen_at, quiet_hours_schedule, theme_preference, name, github_com_user_id, hashed_one_time_passcode, one_time_passcode_expires_at + id = $1 RETURNING 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 ` type UpdateUserStatusParams struct { @@ -11793,7 +11761,6 @@ func (q *sqlQuerier) UpdateUserStatus(ctx context.Context, arg UpdateUserStatusP &i.Deleted, &i.LastSeenAt, &i.QuietHoursSchedule, - &i.ThemePreference, &i.Name, &i.GithubComUserID, &i.HashedOneTimePasscode, diff --git a/coderd/database/queries/auditlogs.sql b/coderd/database/queries/auditlogs.sql index 115bdcd4c8f6f..d23c90d7ce878 100644 --- a/coderd/database/queries/auditlogs.sql +++ b/coderd/database/queries/auditlogs.sql @@ -16,7 +16,6 @@ SELECT users.rbac_roles AS user_roles, users.avatar_url AS user_avatar_url, users.deleted AS user_deleted, - users.theme_preference AS user_theme_preference, users.quiet_hours_schedule AS user_quiet_hours_schedule, COALESCE(organizations.name, '') AS organization_name, COALESCE(organizations.display_name, '') AS organization_display_name, diff --git a/coderd/database/queries/users.sql b/coderd/database/queries/users.sql index 1f30a2c2c1d24..3caef9e70945a 100644 --- a/coderd/database/queries/users.sql +++ b/coderd/database/queries/users.sql @@ -99,13 +99,17 @@ WHERE id = $1; -- name: UpdateUserAppearanceSettings :one -UPDATE - users +INSERT INTO + user_configs (user_id, key, value) +VALUES + (@user_id, 'theme_preference', @theme_preference) +ON CONFLICT + ON CONSTRAINT unique_key_per_user +DO UPDATE SET - theme_preference = $2, - updated_at = $3 -WHERE - id = $1 + value = @theme_preference +WHERE user_configs.user_id = @user_id + AND user_configs.key = 'theme_preference' RETURNING *; -- name: UpdateUserRoles :one diff --git a/coderd/database/unique_constraint.go b/coderd/database/unique_constraint.go index ce427cf97c3bc..2132068aefe03 100644 --- a/coderd/database/unique_constraint.go +++ b/coderd/database/unique_constraint.go @@ -65,6 +65,7 @@ const ( UniqueTemplateVersionsPkey UniqueConstraint = "template_versions_pkey" // ALTER TABLE ONLY template_versions ADD CONSTRAINT template_versions_pkey PRIMARY KEY (id); UniqueTemplateVersionsTemplateIDNameKey UniqueConstraint = "template_versions_template_id_name_key" // ALTER TABLE ONLY template_versions ADD CONSTRAINT template_versions_template_id_name_key UNIQUE (template_id, name); UniqueTemplatesPkey UniqueConstraint = "templates_pkey" // ALTER TABLE ONLY templates ADD CONSTRAINT templates_pkey PRIMARY KEY (id); + UniqueUniqueKeyPerUser UniqueConstraint = "unique_key_per_user" // ALTER TABLE ONLY user_configs ADD CONSTRAINT unique_key_per_user UNIQUE (user_id, key); UniqueUserDeletedPkey UniqueConstraint = "user_deleted_pkey" // ALTER TABLE ONLY user_deleted ADD CONSTRAINT user_deleted_pkey PRIMARY KEY (id); UniqueUserLinksPkey UniqueConstraint = "user_links_pkey" // ALTER TABLE ONLY user_links ADD CONSTRAINT user_links_pkey PRIMARY KEY (user_id, login_type); UniqueUserStatusChangesPkey UniqueConstraint = "user_status_changes_pkey" // ALTER TABLE ONLY user_status_changes ADD CONSTRAINT user_status_changes_pkey PRIMARY KEY (id); diff --git a/coderd/users.go b/coderd/users.go index 964f18724449a..b379f5fbbbc2e 100644 --- a/coderd/users.go +++ b/coderd/users.go @@ -995,9 +995,8 @@ func (api *API) putUserAppearanceSettings(rw http.ResponseWriter, r *http.Reques } updatedUser, err := api.Database.UpdateUserAppearanceSettings(ctx, database.UpdateUserAppearanceSettingsParams{ - ID: user.ID, + UserID: user.ID, ThemePreference: params.ThemePreference, - UpdatedAt: dbtime.Now(), }) if err != nil { httpapi.Write(ctx, rw, http.StatusInternalServerError, codersdk.Response{ diff --git a/codersdk/users.go b/codersdk/users.go index 4dbdc0d4e4f91..db8f6e7f6d6de 100644 --- a/codersdk/users.go +++ b/codersdk/users.go @@ -54,9 +54,8 @@ type ReducedUser struct { UpdatedAt time.Time `json:"updated_at" table:"updated at" format:"date-time"` LastSeenAt time.Time `json:"last_seen_at" format:"date-time"` - Status UserStatus `json:"status" table:"status" enums:"active,suspended"` - LoginType LoginType `json:"login_type"` - ThemePreference string `json:"theme_preference"` + Status UserStatus `json:"status" table:"status" enums:"active,suspended"` + LoginType LoginType `json:"login_type"` } // User represents a user in Coder. diff --git a/site/src/api/typesGenerated.ts b/site/src/api/typesGenerated.ts index 50b45ccd4d22f..d6f8c44c7e967 100644 --- a/site/src/api/typesGenerated.ts +++ b/site/src/api/typesGenerated.ts @@ -1934,7 +1934,6 @@ export interface ReducedUser extends MinimalUser { readonly last_seen_at: string; readonly status: UserStatus; readonly login_type: LoginType; - readonly theme_preference: string; } // From codersdk/workspaceproxy.go From 4467aec2a83368a2a26a1e86e9399a3cf605ca16 Mon Sep 17 00:00:00 2001 From: McKayla Washburn Date: Fri, 14 Feb 2025 00:11:16 +0000 Subject: [PATCH 03/20] :) --- coderd/apidoc/docs.go | 19 ++++++------ coderd/apidoc/swagger.json | 19 ++++++------ coderd/users.go | 17 ++++------- codersdk/users.go | 4 +++ docs/admin/security/audit-logs.md | 2 +- docs/reference/api/audit.md | 1 - docs/reference/api/enterprise.md | 16 ---------- docs/reference/api/schemas.md | 50 ++++++++++++++++--------------- docs/reference/api/users.md | 36 +++------------------- enterprise/audit/table.go | 1 - site/src/api/typesGenerated.ts | 5 ++++ 11 files changed, 63 insertions(+), 107 deletions(-) diff --git a/coderd/apidoc/docs.go b/coderd/apidoc/docs.go index 6f09a0482dbd1..70803d6313c3d 100644 --- a/coderd/apidoc/docs.go +++ b/coderd/apidoc/docs.go @@ -6353,7 +6353,7 @@ const docTemplate = `{ "200": { "description": "OK", "schema": { - "$ref": "#/definitions/codersdk.User" + "$ref": "#/definitions/codersdk.UserAppearanceSettings" } } } @@ -13738,9 +13738,6 @@ const docTemplate = `{ } ] }, - "theme_preference": { - "type": "string" - }, "updated_at": { "type": "string", "format": "date-time" @@ -14601,9 +14598,6 @@ const docTemplate = `{ } ] }, - "theme_preference": { - "type": "string" - }, "updated_at": { "type": "string", "format": "date-time" @@ -15211,9 +15205,6 @@ const docTemplate = `{ } ] }, - "theme_preference": { - "type": "string" - }, "updated_at": { "type": "string", "format": "date-time" @@ -15284,6 +15275,14 @@ const docTemplate = `{ } } }, + "codersdk.UserAppearanceSettings": { + "type": "object", + "properties": { + "theme_preference": { + "type": "string" + } + } + }, "codersdk.UserLatency": { "type": "object", "properties": { diff --git a/coderd/apidoc/swagger.json b/coderd/apidoc/swagger.json index db682394ca04a..a31b69a8524bc 100644 --- a/coderd/apidoc/swagger.json +++ b/coderd/apidoc/swagger.json @@ -5605,7 +5605,7 @@ "200": { "description": "OK", "schema": { - "$ref": "#/definitions/codersdk.User" + "$ref": "#/definitions/codersdk.UserAppearanceSettings" } } } @@ -12425,9 +12425,6 @@ } ] }, - "theme_preference": { - "type": "string" - }, "updated_at": { "type": "string", "format": "date-time" @@ -13263,9 +13260,6 @@ } ] }, - "theme_preference": { - "type": "string" - }, "updated_at": { "type": "string", "format": "date-time" @@ -13825,9 +13819,6 @@ } ] }, - "theme_preference": { - "type": "string" - }, "updated_at": { "type": "string", "format": "date-time" @@ -13898,6 +13889,14 @@ } } }, + "codersdk.UserAppearanceSettings": { + "type": "object", + "properties": { + "theme_preference": { + "type": "string" + } + } + }, "codersdk.UserLatency": { "type": "object", "properties": { diff --git a/coderd/users.go b/coderd/users.go index b379f5fbbbc2e..fef791203d32d 100644 --- a/coderd/users.go +++ b/coderd/users.go @@ -981,7 +981,7 @@ func (api *API) notifyUserStatusChanged(ctx context.Context, actingUserName stri // @Tags Users // @Param user path string true "User ID, name, or me" // @Param request body codersdk.UpdateUserAppearanceSettingsRequest true "New appearance settings" -// @Success 200 {object} codersdk.User +// @Success 200 {object} codersdk.UserAppearanceSettings // @Router /users/{user}/appearance [put] func (api *API) putUserAppearanceSettings(rw http.ResponseWriter, r *http.Request) { var ( @@ -994,7 +994,7 @@ func (api *API) putUserAppearanceSettings(rw http.ResponseWriter, r *http.Reques return } - updatedUser, err := api.Database.UpdateUserAppearanceSettings(ctx, database.UpdateUserAppearanceSettingsParams{ + updatedSettings, err := api.Database.UpdateUserAppearanceSettings(ctx, database.UpdateUserAppearanceSettingsParams{ UserID: user.ID, ThemePreference: params.ThemePreference, }) @@ -1006,16 +1006,9 @@ func (api *API) putUserAppearanceSettings(rw http.ResponseWriter, r *http.Reques return } - organizationIDs, err := userOrganizationIDs(ctx, api, user) - if err != nil { - httpapi.Write(ctx, rw, http.StatusInternalServerError, codersdk.Response{ - Message: "Internal error fetching user's organizations.", - Detail: err.Error(), - }) - return - } - - httpapi.Write(ctx, rw, http.StatusOK, db2sdk.User(updatedUser, organizationIDs)) + httpapi.Write(ctx, rw, http.StatusOK, codersdk.UserAppearanceSettings{ + ThemePreference: updatedSettings.Value, + }) } // @Summary Update user password diff --git a/codersdk/users.go b/codersdk/users.go index db8f6e7f6d6de..933a43460836a 100644 --- a/codersdk/users.go +++ b/codersdk/users.go @@ -186,6 +186,10 @@ type ValidateUserPasswordResponse struct { Details string `json:"details"` } +type UserAppearanceSettings struct { + ThemePreference string `json:"theme_preference"` +} + type UpdateUserAppearanceSettingsRequest struct { ThemePreference string `json:"theme_preference" validate:"required"` } diff --git a/docs/admin/security/audit-logs.md b/docs/admin/security/audit-logs.md index 2131e7746d2d6..852c8e86b2809 100644 --- a/docs/admin/security/audit-logs.md +++ b/docs/admin/security/audit-logs.md @@ -28,7 +28,7 @@ We track the following resources: | RoleSyncSettings
| |
FieldTracked
fieldtrue
mappingtrue
| | Template
write, delete | |
FieldTracked
active_version_idtrue
activity_bumptrue
allow_user_autostarttrue
allow_user_autostoptrue
allow_user_cancel_workspace_jobstrue
autostart_block_days_of_weektrue
autostop_requirement_days_of_weektrue
autostop_requirement_weekstrue
created_atfalse
created_bytrue
created_by_avatar_urlfalse
created_by_usernamefalse
default_ttltrue
deletedfalse
deprecatedtrue
descriptiontrue
display_nametrue
failure_ttltrue
group_acltrue
icontrue
idtrue
max_port_sharing_leveltrue
nametrue
organization_display_namefalse
organization_iconfalse
organization_idfalse
organization_namefalse
provisionertrue
require_active_versiontrue
time_til_dormanttrue
time_til_dormant_autodeletetrue
updated_atfalse
user_acltrue
| | TemplateVersion
create, write | |
FieldTracked
archivedtrue
created_atfalse
created_bytrue
created_by_avatar_urlfalse
created_by_usernamefalse
external_auth_providersfalse
idtrue
job_idfalse
messagefalse
nametrue
organization_idfalse
readmetrue
source_example_idfalse
template_idtrue
updated_atfalse
| -| User
create, write, delete | |
FieldTracked
avatar_urlfalse
created_atfalse
deletedtrue
emailtrue
github_com_user_idfalse
hashed_one_time_passcodefalse
hashed_passwordtrue
idtrue
last_seen_atfalse
login_typetrue
nametrue
one_time_passcode_expires_attrue
quiet_hours_scheduletrue
rbac_rolestrue
statustrue
theme_preferencefalse
updated_atfalse
usernametrue
| +| User
create, write, delete | |
FieldTracked
avatar_urlfalse
created_atfalse
deletedtrue
emailtrue
github_com_user_idfalse
hashed_one_time_passcodefalse
hashed_passwordtrue
idtrue
last_seen_atfalse
login_typetrue
nametrue
one_time_passcode_expires_attrue
quiet_hours_scheduletrue
rbac_rolestrue
statustrue
updated_atfalse
usernametrue
| | WorkspaceBuild
start, stop | |
FieldTracked
build_numberfalse
created_atfalse
daily_costfalse
deadlinefalse
idfalse
initiator_by_avatar_urlfalse
initiator_by_usernamefalse
initiator_idfalse
job_idfalse
max_deadlinefalse
provisioner_statefalse
reasonfalse
template_version_idtrue
template_version_preset_idfalse
transitionfalse
updated_atfalse
workspace_idfalse
| | WorkspaceProxy
| |
FieldTracked
created_attrue
deletedfalse
derp_enabledtrue
derp_onlytrue
display_nametrue
icontrue
idtrue
nametrue
region_idtrue
token_hashed_secrettrue
updated_atfalse
urltrue
versiontrue
wildcard_hostnametrue
| | WorkspaceTable
| |
FieldTracked
automatic_updatestrue
autostart_scheduletrue
created_atfalse
deletedfalse
deleting_attrue
dormant_attrue
favoritetrue
idtrue
last_used_atfalse
nametrue
next_start_attrue
organization_idfalse
owner_idtrue
template_idtrue
ttltrue
updated_atfalse
| diff --git a/docs/reference/api/audit.md b/docs/reference/api/audit.md index 3fc6e746f17c8..af13e9049d0b4 100644 --- a/docs/reference/api/audit.md +++ b/docs/reference/api/audit.md @@ -83,7 +83,6 @@ curl -X GET http://coder-server:8080/api/v2/audit?limit=0 \ } ], "status": "active", - "theme_preference": "string", "updated_at": "2019-08-24T14:15:22Z", "username": "string" }, diff --git a/docs/reference/api/enterprise.md b/docs/reference/api/enterprise.md index 282cf20ab252d..c18b0d5478b5e 100644 --- a/docs/reference/api/enterprise.md +++ b/docs/reference/api/enterprise.md @@ -219,7 +219,6 @@ curl -X GET http://coder-server:8080/api/v2/groups?organization=string&has_membe "login_type": "", "name": "string", "status": "active", - "theme_preference": "string", "updated_at": "2019-08-24T14:15:22Z", "username": "string" } @@ -260,7 +259,6 @@ Status Code **200** | `»» login_type` | [codersdk.LoginType](schemas.md#codersdklogintype) | false | | | | `»» name` | string | false | | | | `»» status` | [codersdk.UserStatus](schemas.md#codersdkuserstatus) | false | | | -| `»» theme_preference` | string | false | | | | `»» updated_at` | string(date-time) | false | | | | `»» username` | string | true | | | | `» name` | string | false | | | @@ -326,7 +324,6 @@ curl -X GET http://coder-server:8080/api/v2/groups/{group} \ "login_type": "", "name": "string", "status": "active", - "theme_preference": "string", "updated_at": "2019-08-24T14:15:22Z", "username": "string" } @@ -387,7 +384,6 @@ curl -X DELETE http://coder-server:8080/api/v2/groups/{group} \ "login_type": "", "name": "string", "status": "active", - "theme_preference": "string", "updated_at": "2019-08-24T14:15:22Z", "username": "string" } @@ -467,7 +463,6 @@ curl -X PATCH http://coder-server:8080/api/v2/groups/{group} \ "login_type": "", "name": "string", "status": "active", - "theme_preference": "string", "updated_at": "2019-08-24T14:15:22Z", "username": "string" } @@ -1230,7 +1225,6 @@ curl -X GET http://coder-server:8080/api/v2/organizations/{organization}/groups "login_type": "", "name": "string", "status": "active", - "theme_preference": "string", "updated_at": "2019-08-24T14:15:22Z", "username": "string" } @@ -1271,7 +1265,6 @@ Status Code **200** | `»» login_type` | [codersdk.LoginType](schemas.md#codersdklogintype) | false | | | | `»» name` | string | false | | | | `»» status` | [codersdk.UserStatus](schemas.md#codersdkuserstatus) | false | | | -| `»» theme_preference` | string | false | | | | `»» updated_at` | string(date-time) | false | | | | `»» username` | string | true | | | | `» name` | string | false | | | @@ -1350,7 +1343,6 @@ curl -X POST http://coder-server:8080/api/v2/organizations/{organization}/groups "login_type": "", "name": "string", "status": "active", - "theme_preference": "string", "updated_at": "2019-08-24T14:15:22Z", "username": "string" } @@ -1412,7 +1404,6 @@ curl -X GET http://coder-server:8080/api/v2/organizations/{organization}/groups/ "login_type": "", "name": "string", "status": "active", - "theme_preference": "string", "updated_at": "2019-08-24T14:15:22Z", "username": "string" } @@ -2655,7 +2646,6 @@ curl -X PUT http://coder-server:8080/api/v2/scim/v2/Users/{id} \ } ], "status": "active", - "theme_preference": "string", "updated_at": "2019-08-24T14:15:22Z", "username": "string" } @@ -2745,7 +2735,6 @@ curl -X PATCH http://coder-server:8080/api/v2/scim/v2/Users/{id} \ } ], "status": "active", - "theme_preference": "string", "updated_at": "2019-08-24T14:15:22Z", "username": "string" } @@ -3109,7 +3098,6 @@ curl -X GET http://coder-server:8080/api/v2/templates/{template}/acl \ } ], "status": "active", - "theme_preference": "string", "updated_at": "2019-08-24T14:15:22Z", "username": "string" } @@ -3143,7 +3131,6 @@ Status Code **200** | `»» name` | string | false | | | | `»» organization_id` | string | false | | | | `» status` | [codersdk.UserStatus](schemas.md#codersdkuserstatus) | false | | | -| `» theme_preference` | string | false | | | | `» updated_at` | string(date-time) | false | | | | `» username` | string | true | | | @@ -3266,7 +3253,6 @@ curl -X GET http://coder-server:8080/api/v2/templates/{template}/acl/available \ "login_type": "", "name": "string", "status": "active", - "theme_preference": "string", "updated_at": "2019-08-24T14:15:22Z", "username": "string" } @@ -3290,7 +3276,6 @@ curl -X GET http://coder-server:8080/api/v2/templates/{template}/acl/available \ "login_type": "", "name": "string", "status": "active", - "theme_preference": "string", "updated_at": "2019-08-24T14:15:22Z", "username": "string" } @@ -3325,7 +3310,6 @@ Status Code **200** | `»»» login_type` | [codersdk.LoginType](schemas.md#codersdklogintype) | false | | | | `»»» name` | string | false | | | | `»»» status` | [codersdk.UserStatus](schemas.md#codersdkuserstatus) | false | | | -| `»»» theme_preference` | string | false | | | | `»»» updated_at` | string(date-time) | false | | | | `»»» username` | string | true | | | | `»» name` | string | false | | | diff --git a/docs/reference/api/schemas.md b/docs/reference/api/schemas.md index 7b2759e281f8e..2f6633744b897 100644 --- a/docs/reference/api/schemas.md +++ b/docs/reference/api/schemas.md @@ -242,7 +242,6 @@ "login_type": "", "name": "string", "status": "active", - "theme_preference": "string", "updated_at": "2019-08-24T14:15:22Z", "username": "string" } @@ -266,7 +265,6 @@ "login_type": "", "name": "string", "status": "active", - "theme_preference": "string", "updated_at": "2019-08-24T14:15:22Z", "username": "string" } @@ -654,7 +652,6 @@ } ], "status": "active", - "theme_preference": "string", "updated_at": "2019-08-24T14:15:22Z", "username": "string" }, @@ -746,7 +743,6 @@ } ], "status": "active", - "theme_preference": "string", "updated_at": "2019-08-24T14:15:22Z", "username": "string" }, @@ -3056,7 +3052,6 @@ Git clone makes use of this by parsing the URL from: 'Username for "https://gith } ], "status": "active", - "theme_preference": "string", "updated_at": "2019-08-24T14:15:22Z", "username": "string" } @@ -3108,7 +3103,6 @@ Git clone makes use of this by parsing the URL from: 'Username for "https://gith "login_type": "", "name": "string", "status": "active", - "theme_preference": "string", "updated_at": "2019-08-24T14:15:22Z", "username": "string" } @@ -5149,7 +5143,6 @@ Git clone makes use of this by parsing the URL from: 'Username for "https://gith "login_type": "", "name": "string", "status": "active", - "theme_preference": "string", "updated_at": "2019-08-24T14:15:22Z", "username": "string" } @@ -5157,19 +5150,18 @@ Git clone makes use of this by parsing the URL from: 'Username for "https://gith ### Properties -| Name | Type | Required | Restrictions | Description | -|--------------------|--------------------------------------------|----------|--------------|-------------| -| `avatar_url` | string | false | | | -| `created_at` | string | true | | | -| `email` | string | true | | | -| `id` | string | true | | | -| `last_seen_at` | string | false | | | -| `login_type` | [codersdk.LoginType](#codersdklogintype) | false | | | -| `name` | string | false | | | -| `status` | [codersdk.UserStatus](#codersdkuserstatus) | false | | | -| `theme_preference` | string | false | | | -| `updated_at` | string | false | | | -| `username` | string | true | | | +| Name | Type | Required | Restrictions | Description | +|----------------|--------------------------------------------|----------|--------------|-------------| +| `avatar_url` | string | false | | | +| `created_at` | string | true | | | +| `email` | string | true | | | +| `id` | string | true | | | +| `last_seen_at` | string | false | | | +| `login_type` | [codersdk.LoginType](#codersdklogintype) | false | | | +| `name` | string | false | | | +| `status` | [codersdk.UserStatus](#codersdkuserstatus) | false | | | +| `updated_at` | string | false | | | +| `username` | string | true | | | #### Enumerated Values @@ -6132,7 +6124,6 @@ Restarts will only happen on weekdays in this list on weeks which line up with W } ], "status": "active", - "theme_preference": "string", "updated_at": "2019-08-24T14:15:22Z", "username": "string" } @@ -6153,7 +6144,6 @@ Restarts will only happen on weekdays in this list on weeks which line up with W | `role` | [codersdk.TemplateRole](#codersdktemplaterole) | false | | | | `roles` | array of [codersdk.SlimRole](#codersdkslimrole) | false | | | | `status` | [codersdk.UserStatus](#codersdkuserstatus) | false | | | -| `theme_preference` | string | false | | | | `updated_at` | string | false | | | | `username` | string | true | | | @@ -6832,7 +6822,6 @@ If the schedule is empty, the user will be updated to use the default schedule.| } ], "status": "active", - "theme_preference": "string", "updated_at": "2019-08-24T14:15:22Z", "username": "string" } @@ -6852,7 +6841,6 @@ If the schedule is empty, the user will be updated to use the default schedule.| | `organization_ids` | array of string | false | | | | `roles` | array of [codersdk.SlimRole](#codersdkslimrole) | false | | | | `status` | [codersdk.UserStatus](#codersdkuserstatus) | false | | | -| `theme_preference` | string | false | | | | `updated_at` | string | false | | | | `username` | string | true | | | @@ -6950,6 +6938,20 @@ If the schedule is empty, the user will be updated to use the default schedule.| |----------|----------------------------------------------------------------------------|----------|--------------|-------------| | `report` | [codersdk.UserActivityInsightsReport](#codersdkuseractivityinsightsreport) | false | | | +## codersdk.UserAppearanceSettings + +```json +{ + "theme_preference": "string" +} +``` + +### Properties + +| Name | Type | Required | Restrictions | Description | +|--------------------|--------|----------|--------------|-------------| +| `theme_preference` | string | false | | | + ## codersdk.UserLatency ```json diff --git a/docs/reference/api/users.md b/docs/reference/api/users.md index d8aac77cfa83b..67fe73b57c6f8 100644 --- a/docs/reference/api/users.md +++ b/docs/reference/api/users.md @@ -49,7 +49,6 @@ curl -X GET http://coder-server:8080/api/v2/users \ } ], "status": "active", - "theme_preference": "string", "updated_at": "2019-08-24T14:15:22Z", "username": "string" } @@ -125,7 +124,6 @@ curl -X POST http://coder-server:8080/api/v2/users \ } ], "status": "active", - "theme_preference": "string", "updated_at": "2019-08-24T14:15:22Z", "username": "string" } @@ -400,7 +398,6 @@ curl -X GET http://coder-server:8080/api/v2/users/{user} \ } ], "status": "active", - "theme_preference": "string", "updated_at": "2019-08-24T14:15:22Z", "username": "string" } @@ -475,35 +472,15 @@ curl -X PUT http://coder-server:8080/api/v2/users/{user}/appearance \ ```json { - "avatar_url": "http://example.com", - "created_at": "2019-08-24T14:15:22Z", - "email": "user@example.com", - "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08", - "last_seen_at": "2019-08-24T14:15:22Z", - "login_type": "", - "name": "string", - "organization_ids": [ - "497f6eca-6276-4993-bfeb-53cbbbba6f08" - ], - "roles": [ - { - "display_name": "string", - "name": "string", - "organization_id": "string" - } - ], - "status": "active", - "theme_preference": "string", - "updated_at": "2019-08-24T14:15:22Z", - "username": "string" + "theme_preference": "string" } ``` ### Responses -| Status | Meaning | Description | Schema | -|--------|---------------------------------------------------------|-------------|------------------------------------------| -| 200 | [OK](https://tools.ietf.org/html/rfc7231#section-6.3.1) | OK | [codersdk.User](schemas.md#codersdkuser) | +| Status | Meaning | Description | Schema | +|--------|---------------------------------------------------------|-------------|------------------------------------------------------------------------------| +| 200 | [OK](https://tools.ietf.org/html/rfc7231#section-6.3.1) | OK | [codersdk.UserAppearanceSettings](schemas.md#codersdkuserappearancesettings) | To perform this operation, you must be authenticated. [Learn more](authentication.md). @@ -1157,7 +1134,6 @@ curl -X PUT http://coder-server:8080/api/v2/users/{user}/profile \ } ], "status": "active", - "theme_preference": "string", "updated_at": "2019-08-24T14:15:22Z", "username": "string" } @@ -1214,7 +1190,6 @@ curl -X GET http://coder-server:8080/api/v2/users/{user}/roles \ } ], "status": "active", - "theme_preference": "string", "updated_at": "2019-08-24T14:15:22Z", "username": "string" } @@ -1283,7 +1258,6 @@ curl -X PUT http://coder-server:8080/api/v2/users/{user}/roles \ } ], "status": "active", - "theme_preference": "string", "updated_at": "2019-08-24T14:15:22Z", "username": "string" } @@ -1340,7 +1314,6 @@ curl -X PUT http://coder-server:8080/api/v2/users/{user}/status/activate \ } ], "status": "active", - "theme_preference": "string", "updated_at": "2019-08-24T14:15:22Z", "username": "string" } @@ -1397,7 +1370,6 @@ curl -X PUT http://coder-server:8080/api/v2/users/{user}/status/suspend \ } ], "status": "active", - "theme_preference": "string", "updated_at": "2019-08-24T14:15:22Z", "username": "string" } diff --git a/enterprise/audit/table.go b/enterprise/audit/table.go index d43b2e224e374..0c50f308d73b4 100644 --- a/enterprise/audit/table.go +++ b/enterprise/audit/table.go @@ -145,7 +145,6 @@ var auditableResourcesTypes = map[any]map[string]Action{ "last_seen_at": ActionIgnore, "deleted": ActionTrack, "quiet_hours_schedule": ActionTrack, - "theme_preference": ActionIgnore, "name": ActionTrack, "github_com_user_id": ActionIgnore, "hashed_one_time_passcode": ActionIgnore, diff --git a/site/src/api/typesGenerated.ts b/site/src/api/typesGenerated.ts index d6f8c44c7e967..dc3bd15731a2a 100644 --- a/site/src/api/typesGenerated.ts +++ b/site/src/api/typesGenerated.ts @@ -2760,6 +2760,11 @@ export interface UserActivityInsightsResponse { readonly report: UserActivityInsightsReport; } +// From codersdk/users.go +export interface UserAppearanceSettings { + readonly theme_preference: string; +} + // From codersdk/insights.go export interface UserLatency { readonly template_ids: readonly string[]; From c4d60a32f67d40148c2fe276803e44e436715fc2 Mon Sep 17 00:00:00 2001 From: McKayla Washburn Date: Fri, 14 Feb 2025 18:34:56 +0000 Subject: [PATCH 04/20] ah yes --- coderd/apidoc/docs.go | 35 +++++++ coderd/apidoc/swagger.json | 29 ++++++ coderd/coderd.go | 1 + coderd/database/dbauthz/dbauthz.go | 7 ++ coderd/database/dbmem/dbmem.go | 14 +++ coderd/database/dbmetrics/querymetrics.go | 7 ++ coderd/database/dbmock/dbmock.go | 15 +++ coderd/database/querier.go | 1 + coderd/database/queries.sql.go | 17 ++++ coderd/database/queries/users.sql | 9 ++ coderd/users.go | 29 ++++++ site/index.html | 93 ++++++++++--------- site/site.go | 32 +++++-- site/src/api/api.ts | 14 +-- site/src/api/queries/users.ts | 36 +++---- site/src/contexts/ThemeProvider.tsx | 16 ++-- site/src/hooks/useEmbeddedMetadata.test.ts | 10 ++ site/src/hooks/useEmbeddedMetadata.ts | 4 + .../AppearancePage/AppearancePage.tsx | 30 +++++- site/src/testHelpers/entities.ts | 7 +- 20 files changed, 316 insertions(+), 90 deletions(-) diff --git a/coderd/apidoc/docs.go b/coderd/apidoc/docs.go index 70803d6313c3d..70a0c8016f110 100644 --- a/coderd/apidoc/docs.go +++ b/coderd/apidoc/docs.go @@ -6314,6 +6314,41 @@ const docTemplate = `{ } }, "/users/{user}/appearance": { + "get": { + "security": [ + { + "CoderSessionToken": [] + } + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "Users" + ], + "summary": "Update user appearance settings", + "operationId": "update-user-appearance-settings", + "parameters": [ + { + "type": "string", + "description": "User ID, name, or me", + "name": "user", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/codersdk.UserAppearanceSettings" + } + } + } + }, "put": { "security": [ { diff --git a/coderd/apidoc/swagger.json b/coderd/apidoc/swagger.json index a31b69a8524bc..30c2ed28e067c 100644 --- a/coderd/apidoc/swagger.json +++ b/coderd/apidoc/swagger.json @@ -5572,6 +5572,35 @@ } }, "/users/{user}/appearance": { + "get": { + "security": [ + { + "CoderSessionToken": [] + } + ], + "consumes": ["application/json"], + "produces": ["application/json"], + "tags": ["Users"], + "summary": "Update user appearance settings", + "operationId": "update-user-appearance-settings", + "parameters": [ + { + "type": "string", + "description": "User ID, name, or me", + "name": "user", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/codersdk.UserAppearanceSettings" + } + } + } + }, "put": { "security": [ { diff --git a/coderd/coderd.go b/coderd/coderd.go index 8ff8c05ee75b2..a2b2c5c31bfe9 100644 --- a/coderd/coderd.go +++ b/coderd/coderd.go @@ -1124,6 +1124,7 @@ func New(options *Options) *API { r.Put("/suspend", api.putSuspendUserAccount()) r.Put("/activate", api.putActivateUserAccount()) }) + r.Get("/appearance", api.getUserAppearanceSettings) r.Put("/appearance", api.putUserAppearanceSettings) r.Route("/password", func(r chi.Router) { r.Use(httpmw.RateLimit(options.LoginRateLimit, time.Minute)) diff --git a/coderd/database/dbauthz/dbauthz.go b/coderd/database/dbauthz/dbauthz.go index 0701e2cd972bb..9cf14fc85a52a 100644 --- a/coderd/database/dbauthz/dbauthz.go +++ b/coderd/database/dbauthz/dbauthz.go @@ -2424,6 +2424,13 @@ 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) { + if err := q.authorizeContext(ctx, policy.ActionReadPersonal, rbac.ResourceUser); 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) } diff --git a/coderd/database/dbmem/dbmem.go b/coderd/database/dbmem/dbmem.go index 2365617240453..22eb1d2076f0b 100644 --- a/coderd/database/dbmem/dbmem.go +++ b/coderd/database/dbmem/dbmem.go @@ -5871,6 +5871,20 @@ 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 diff --git a/coderd/database/dbmetrics/querymetrics.go b/coderd/database/dbmetrics/querymetrics.go index 7d65310ad28d9..40088556c6f71 100644 --- a/coderd/database/dbmetrics/querymetrics.go +++ b/coderd/database/dbmetrics/querymetrics.go @@ -1351,6 +1351,13 @@ 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) diff --git a/coderd/database/dbmock/dbmock.go b/coderd/database/dbmock/dbmock.go index 44e6b0f48f257..cbb98e45109b9 100644 --- a/coderd/database/dbmock/dbmock.go +++ b/coderd/database/dbmock/dbmock.go @@ -2841,6 +2841,21 @@ 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() diff --git a/coderd/database/querier.go b/coderd/database/querier.go index 8ad30a5304169..ecf52d196b767 100644 --- a/coderd/database/querier.go +++ b/coderd/database/querier.go @@ -286,6 +286,7 @@ 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) (int64, error) diff --git a/coderd/database/queries.sql.go b/coderd/database/queries.sql.go index 70f3d65486af1..ef5f87b69fa1a 100644 --- a/coderd/database/queries.sql.go +++ b/coderd/database/queries.sql.go @@ -10965,6 +10965,23 @@ 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 diff --git a/coderd/database/queries/users.sql b/coderd/database/queries/users.sql index 3caef9e70945a..c45aa83bd46e6 100644 --- a/coderd/database/queries/users.sql +++ b/coderd/database/queries/users.sql @@ -98,6 +98,15 @@ SET WHERE id = $1; +-- name: GetUserAppearanceSettings :one +SELECT + value as theme_preference +FROM + user_configs +WHERE + user_id = @user_id + AND key = 'theme_preference'; + -- name: UpdateUserAppearanceSettings :one INSERT INTO user_configs (user_id, key, value) diff --git a/coderd/users.go b/coderd/users.go index fef791203d32d..539e0dfe9f3af 100644 --- a/coderd/users.go +++ b/coderd/users.go @@ -973,6 +973,35 @@ func (api *API) notifyUserStatusChanged(ctx context.Context, actingUserName stri return nil } +// @Summary Update user appearance settings +// @ID update-user-appearance-settings +// @Security CoderSessionToken +// @Accept json +// @Produce json +// @Tags Users +// @Param user path string true "User ID, name, or me" +// @Success 200 {object} codersdk.UserAppearanceSettings +// @Router /users/{user}/appearance [get] +func (api *API) getUserAppearanceSettings(rw http.ResponseWriter, r *http.Request) { + var ( + ctx = r.Context() + user = httpmw.UserParam(r) + ) + + themePreference, err := api.Database.GetUserAppearanceSettings(ctx, user.ID) + if err != nil { + httpapi.Write(ctx, rw, http.StatusInternalServerError, codersdk.Response{ + Message: "Internal error updating user.", + Detail: err.Error(), + }) + return + } + + httpapi.Write(ctx, rw, http.StatusOK, codersdk.UserAppearanceSettings{ + ThemePreference: themePreference, + }) +} + // @Summary Update user appearance settings // @ID update-user-appearance-settings // @Security CoderSessionToken diff --git a/site/index.html b/site/index.html index fff26338b21aa..b953abe052923 100644 --- a/site/index.html +++ b/site/index.html @@ -9,53 +9,54 @@ --> - - Coder - - - - - - - - - - - - - - - - - - + + Coder + + + + + + + + + + + + + + + + + + + -
- +
+ diff --git a/site/site.go b/site/site.go index 3a85f7b3963ad..3b42cf30aab9a 100644 --- a/site/site.go +++ b/site/site.go @@ -292,13 +292,14 @@ type htmlState struct { ApplicationName string LogoURL string - BuildInfo string - User string - Entitlements string - Appearance string - Experiments string - Regions string - DocsURL string + BuildInfo string + User string + Entitlements string + Appearance string + UserAppearance string + Experiments string + Regions string + DocsURL string } type csrfState struct { @@ -426,12 +427,18 @@ func (h *Handler) renderHTMLWithState(r *http.Request, filePath string, state ht var eg errgroup.Group var user database.User + var themePreference string orgIDs := []uuid.UUID{} eg.Go(func() error { var err error user, err = h.opts.Database.GetUserByID(ctx, apiKey.UserID) return err }) + eg.Go(func() error { + var err error + themePreference, err = h.opts.Database.GetUserAppearanceSettings(ctx, apiKey.UserID) + 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 { @@ -455,6 +462,17 @@ func (h *Handler) renderHTMLWithState(r *http.Request, filePath string, state ht } }() + wg.Add(1) + go func() { + defer wg.Done() + userAppearance, err := json.Marshal(codersdk.UserAppearanceSettings{ + ThemePreference: themePreference, + }) + if err == nil { + state.UserAppearance = html.EscapeString(string(userAppearance)) + } + }() + if h.Entitlements != nil { wg.Add(1) go func() { diff --git a/site/src/api/api.ts b/site/src/api/api.ts index 43051961fa7e7..7db51cd23c43f 100644 --- a/site/src/api/api.ts +++ b/site/src/api/api.ts @@ -1320,14 +1320,16 @@ class ApiMethods { return response.data; }; + getAppearanceSettings = + async (): Promise => { + const response = await this.axios.get("/api/v2/users/me/appearance"); + return response.data; + }; + updateAppearanceSettings = async ( - userId: string, data: TypesGen.UpdateUserAppearanceSettingsRequest, - ): Promise => { - const response = await this.axios.put( - `/api/v2/users/${userId}/appearance`, - data, - ); + ): Promise => { + const response = await this.axios.put("/api/v2/users/me/appearance", data); return response.data; }; diff --git a/site/src/api/queries/users.ts b/site/src/api/queries/users.ts index 77d879abe3258..5de828b6eac22 100644 --- a/site/src/api/queries/users.ts +++ b/site/src/api/queries/users.ts @@ -8,8 +8,8 @@ import type { UpdateUserPasswordRequest, UpdateUserProfileRequest, User, + UserAppearanceSettings, UsersRequest, - ValidateUserPasswordRequest, } from "api/typesGenerated"; import { type MetadataState, @@ -224,35 +224,39 @@ export const updateProfile = (userId: string) => { }; }; +const myAppearanceKey = ["me", "appearance"]; + +export const appearanceSettings = ( + metadata: MetadataState, +) => { + return cachedQuery({ + metadata, + queryKey: myAppearanceKey, + queryFn: API.getAppearanceSettings, + }); +}; + export const updateAppearanceSettings = ( - userId: string, queryClient: QueryClient, ): UseMutationOptions< - User, + UserAppearanceSettings, unknown, UpdateUserAppearanceSettingsRequest, unknown > => { return { - mutationFn: (req) => API.updateAppearanceSettings(userId, req), + mutationFn: (req) => API.updateAppearanceSettings(req), onMutate: async (patch) => { // Mutate the `queryClient` optimistically to make the theme switcher // more responsive. - const me: User | undefined = queryClient.getQueryData(meKey); - if (userId === "me" && me) { - queryClient.setQueryData(meKey, { - ...me, - theme_preference: patch.theme_preference, - }); - } + queryClient.setQueryData(myAppearanceKey, { + theme_preference: patch.theme_preference, + }); }, - onSuccess: async () => { + onSuccess: async () => // Could technically invalidate more, but we only ever care about the // `theme_preference` for the `me` query. - if (userId === "me") { - await queryClient.invalidateQueries(meKey); - } - }, + await queryClient.invalidateQueries(myAppearanceKey), }; }; diff --git a/site/src/contexts/ThemeProvider.tsx b/site/src/contexts/ThemeProvider.tsx index 8367e96e3cc64..4521ab71d7a74 100644 --- a/site/src/contexts/ThemeProvider.tsx +++ b/site/src/contexts/ThemeProvider.tsx @@ -7,26 +7,27 @@ import { StyledEngineProvider, // biome-ignore lint/nursery/noRestrictedImports: we extend the MUI theme } from "@mui/material/styles"; +import { appearanceSettings } from "api/queries/users"; +import { useEmbeddedMetadata } from "hooks/useEmbeddedMetadata"; import { type FC, type PropsWithChildren, type ReactNode, - useContext, useEffect, useMemo, useState, } from "react"; +import { useQuery } from "react-query"; import themes, { DEFAULT_THEME, type Theme } from "theme"; -import { AuthContext } from "./auth/AuthProvider"; /** * */ export const ThemeProvider: FC = ({ children }) => { - // We need to use the `AuthContext` directly, rather than the `useAuth` hook, - // because Storybook and many tests depend on this component, but do not provide - // an `AuthProvider`, and `useAuth` will throw in that case. - const user = useContext(AuthContext)?.user; + const { metadata } = useEmbeddedMetadata(); + const appearanceSettingsQuery = useQuery( + appearanceSettings(metadata.userAppearance), + ); const themeQuery = useMemo( () => window.matchMedia?.("(prefers-color-scheme: light)"), [], @@ -53,7 +54,8 @@ export const ThemeProvider: FC = ({ children }) => { }, [themeQuery]); // We might not be logged in yet, or the `theme_preference` could be an empty string. - const themePreference = user?.theme_preference || DEFAULT_THEME; + const themePreference = + appearanceSettingsQuery.data?.theme_preference || DEFAULT_THEME; // The janky casting here is find because of the much more type safe fallback // We need to support `themePreference` being wrong anyway because the database // value could be anything, like an empty string. diff --git a/site/src/hooks/useEmbeddedMetadata.test.ts b/site/src/hooks/useEmbeddedMetadata.test.ts index 75dd4eed8f235..aacb635ada3bf 100644 --- a/site/src/hooks/useEmbeddedMetadata.test.ts +++ b/site/src/hooks/useEmbeddedMetadata.test.ts @@ -6,6 +6,7 @@ import { MockEntitlements, MockExperiments, MockUser, + MockUserAppearanceSettings, } from "testHelpers/entities"; import { DEFAULT_METADATA_KEY, @@ -38,6 +39,7 @@ const mockDataForTags = { entitlements: MockEntitlements, experiments: MockExperiments, user: MockUser, + userAppearance: MockUserAppearanceSettings, regions: MockRegions, } as const satisfies Record; @@ -66,6 +68,10 @@ const emptyMetadata: RuntimeHtmlMetadata = { available: false, value: undefined, }, + userAppearance: { + available: false, + value: undefined, + }, }; const populatedMetadata: RuntimeHtmlMetadata = { @@ -93,6 +99,10 @@ const populatedMetadata: RuntimeHtmlMetadata = { available: true, value: MockUser, }, + userAppearance: { + available: true, + value: MockUserAppearanceSettings, + }, }; function seedInitialMetadata(metadataKey: string): () => void { diff --git a/site/src/hooks/useEmbeddedMetadata.ts b/site/src/hooks/useEmbeddedMetadata.ts index ac4fd50037ed3..35cd8614f408e 100644 --- a/site/src/hooks/useEmbeddedMetadata.ts +++ b/site/src/hooks/useEmbeddedMetadata.ts @@ -5,6 +5,7 @@ import type { Experiments, Region, User, + UserAppearanceSettings, } from "api/typesGenerated"; import { useMemo, useSyncExternalStore } from "react"; @@ -25,6 +26,7 @@ type AvailableMetadata = Readonly<{ user: User; experiments: Experiments; appearance: AppearanceConfig; + userAppearance: UserAppearanceSettings; entitlements: Entitlements; regions: readonly Region[]; "build-info": BuildInfoResponse; @@ -83,6 +85,8 @@ export class MetadataManager implements MetadataManagerApi { this.metadata = { user: this.registerValue("user"), appearance: this.registerValue("appearance"), + userAppearance: + this.registerValue("userAppearance"), entitlements: this.registerValue("entitlements"), experiments: this.registerValue("experiments"), "build-info": this.registerValue("build-info"), diff --git a/site/src/pages/UserSettingsPage/AppearancePage/AppearancePage.tsx b/site/src/pages/UserSettingsPage/AppearancePage/AppearancePage.tsx index dfa4519ab2d58..796a0d2ad0be6 100644 --- a/site/src/pages/UserSettingsPage/AppearancePage/AppearancePage.tsx +++ b/site/src/pages/UserSettingsPage/AppearancePage/AppearancePage.tsx @@ -1,19 +1,37 @@ 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 { useAuthenticated } from "contexts/auth/RequireAuth"; +import { useEmbeddedMetadata } from "hooks/useEmbeddedMetadata"; import type { FC } from "react"; -import { useMutation, useQueryClient } from "react-query"; +import { useMutation, useQuery, useQueryClient } from "react-query"; import { Section } from "../Section"; import { AppearanceForm } from "./AppearanceForm"; export const AppearancePage: FC = () => { - const { user: me } = useAuthenticated(); const queryClient = useQueryClient(); const updateAppearanceSettingsMutation = useMutation( - updateAppearanceSettings("me", queryClient), + updateAppearanceSettings(queryClient), ); + const { metadata } = useEmbeddedMetadata(); + const appearanceSettingsQuery = useQuery( + appearanceSettings(metadata.userAppearance), + ); + + console.log(metadata.userAppearance); + console.log(appearanceSettingsQuery.data); + + if (appearanceSettingsQuery.isLoading) { + return ; + } + + if (!appearanceSettingsQuery.data) { + return ; + } + return ( <>
{
diff --git a/site/src/testHelpers/entities.ts b/site/src/testHelpers/entities.ts index a607df6bb87c9..b70195cc6879a 100644 --- a/site/src/testHelpers/entities.ts +++ b/site/src/testHelpers/entities.ts @@ -475,7 +475,6 @@ export const MockUser: TypesGen.User = { avatar_url: "https://avatars.githubusercontent.com/u/95932066?s=200&v=4", last_seen_at: "", login_type: "password", - theme_preference: "", name: "", }; @@ -496,7 +495,6 @@ export const MockUser2: TypesGen.User = { avatar_url: "", last_seen_at: "2022-09-14T19:12:21Z", login_type: "oidc", - theme_preference: "", name: "Mock User The Second", }; @@ -512,10 +510,13 @@ export const SuspendedMockUser: TypesGen.User = { avatar_url: "", last_seen_at: "", login_type: "password", - theme_preference: "", name: "", }; +export const MockUserAppearanceSettings: TypesGen.UserAppearanceSettings = { + theme_preference: "dark", +}; + export const MockOrganizationMember: TypesGen.OrganizationMemberWithUserData = { organization_id: MockOrganization.id, user_id: MockUser.id, From 2c3a3f36c372f87ef3b31195402b572559fd1c8b Mon Sep 17 00:00:00 2001 From: McKayla Washburn Date: Fri, 14 Feb 2025 18:36:08 +0000 Subject: [PATCH 05/20] =?UTF-8?q?=F0=9F=A7=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../pages/UserSettingsPage/AppearancePage/AppearancePage.tsx | 3 --- 1 file changed, 3 deletions(-) diff --git a/site/src/pages/UserSettingsPage/AppearancePage/AppearancePage.tsx b/site/src/pages/UserSettingsPage/AppearancePage/AppearancePage.tsx index 796a0d2ad0be6..1379e42d0e909 100644 --- a/site/src/pages/UserSettingsPage/AppearancePage/AppearancePage.tsx +++ b/site/src/pages/UserSettingsPage/AppearancePage/AppearancePage.tsx @@ -21,9 +21,6 @@ export const AppearancePage: FC = () => { appearanceSettings(metadata.userAppearance), ); - console.log(metadata.userAppearance); - console.log(appearanceSettingsQuery.data); - if (appearanceSettingsQuery.isLoading) { return ; } From 1c6f7fee3fc8c152e312f65dfcf57927fb5e9729 Mon Sep 17 00:00:00 2001 From: McKayla Washburn Date: Fri, 14 Feb 2025 19:05:53 +0000 Subject: [PATCH 06/20] foreign key --- coderd/database/migrations/000293_user_configs.up.sql | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/coderd/database/migrations/000293_user_configs.up.sql b/coderd/database/migrations/000293_user_configs.up.sql index 931033f419236..e52654563f75d 100644 --- a/coderd/database/migrations/000293_user_configs.up.sql +++ b/coderd/database/migrations/000293_user_configs.up.sql @@ -1,7 +1,10 @@ CREATE TABLE IF NOT EXISTS user_configs ( - user_id uuid NOT NULL, - key varchar(256) NOT NULL, - value text NOT NULL + user_id uuid NOT NULL, + key varchar(256) NOT NULL, + value text NOT NULL, + + PRIMARY KEY (user_id, key), + FOREIGN KEY (user_id) REFERENCES users (id) ON DELETE CASCADE ); ALTER TABLE ONLY user_configs From 76804ad4ed373823ca9729646e8e15531ea81363 Mon Sep 17 00:00:00 2001 From: McKayla Washburn Date: Fri, 14 Feb 2025 19:12:20 +0000 Subject: [PATCH 07/20] =?UTF-8?q?=F0=9F=A7=B9=F0=9F=A7=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- coderd/coderd.go | 2 +- coderd/database/dump.sql | 5 ++++- coderd/database/foreign_key_constraint.go | 1 + coderd/database/migrations/000293_user_configs.up.sql | 5 +---- coderd/database/queries.sql.go | 2 +- coderd/database/queries/users.sql | 2 +- coderd/database/unique_constraint.go | 2 +- coderd/users.go | 2 +- 8 files changed, 11 insertions(+), 10 deletions(-) diff --git a/coderd/coderd.go b/coderd/coderd.go index a2b2c5c31bfe9..083d158d8682e 100644 --- a/coderd/coderd.go +++ b/coderd/coderd.go @@ -1124,7 +1124,7 @@ func New(options *Options) *API { r.Put("/suspend", api.putSuspendUserAccount()) r.Put("/activate", api.putActivateUserAccount()) }) - r.Get("/appearance", api.getUserAppearanceSettings) + r.Get("/appearance", api.userAppearanceSettings) r.Put("/appearance", api.putUserAppearanceSettings) r.Route("/password", func(r chi.Router) { r.Use(httpmw.RateLimit(options.LoginRateLimit, time.Minute)) diff --git a/coderd/database/dump.sql b/coderd/database/dump.sql index f080df4f10ad7..9401c8381b1db 100644 --- a/coderd/database/dump.sql +++ b/coderd/database/dump.sql @@ -2097,7 +2097,7 @@ ALTER TABLE ONLY templates ADD CONSTRAINT templates_pkey PRIMARY KEY (id); ALTER TABLE ONLY user_configs - ADD CONSTRAINT unique_key_per_user UNIQUE (user_id, key); + ADD CONSTRAINT user_configs_pkey PRIMARY KEY (user_id, key); ALTER TABLE ONLY user_deleted ADD CONSTRAINT user_deleted_pkey PRIMARY KEY (id); @@ -2501,6 +2501,9 @@ ALTER TABLE ONLY templates ALTER TABLE ONLY templates ADD CONSTRAINT templates_organization_id_fkey FOREIGN KEY (organization_id) REFERENCES organizations(id) ON DELETE CASCADE; +ALTER TABLE ONLY user_configs + ADD CONSTRAINT user_configs_user_id_fkey FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE; + ALTER TABLE ONLY user_deleted ADD CONSTRAINT user_deleted_user_id_fkey FOREIGN KEY (user_id) REFERENCES users(id); diff --git a/coderd/database/foreign_key_constraint.go b/coderd/database/foreign_key_constraint.go index 66c379a749e01..cd58a6aa2e831 100644 --- a/coderd/database/foreign_key_constraint.go +++ b/coderd/database/foreign_key_constraint.go @@ -49,6 +49,7 @@ const ( ForeignKeyTemplateVersionsTemplateID ForeignKeyConstraint = "template_versions_template_id_fkey" // ALTER TABLE ONLY template_versions ADD CONSTRAINT template_versions_template_id_fkey FOREIGN KEY (template_id) REFERENCES templates(id) ON DELETE CASCADE; ForeignKeyTemplatesCreatedBy ForeignKeyConstraint = "templates_created_by_fkey" // ALTER TABLE ONLY templates ADD CONSTRAINT templates_created_by_fkey FOREIGN KEY (created_by) REFERENCES users(id) ON DELETE RESTRICT; ForeignKeyTemplatesOrganizationID ForeignKeyConstraint = "templates_organization_id_fkey" // ALTER TABLE ONLY templates ADD CONSTRAINT templates_organization_id_fkey FOREIGN KEY (organization_id) REFERENCES organizations(id) ON DELETE CASCADE; + ForeignKeyUserConfigsUserID ForeignKeyConstraint = "user_configs_user_id_fkey" // ALTER TABLE ONLY user_configs ADD CONSTRAINT user_configs_user_id_fkey FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE; ForeignKeyUserDeletedUserID ForeignKeyConstraint = "user_deleted_user_id_fkey" // ALTER TABLE ONLY user_deleted ADD CONSTRAINT user_deleted_user_id_fkey FOREIGN KEY (user_id) REFERENCES users(id); ForeignKeyUserLinksOauthAccessTokenKeyID ForeignKeyConstraint = "user_links_oauth_access_token_key_id_fkey" // ALTER TABLE ONLY user_links ADD CONSTRAINT user_links_oauth_access_token_key_id_fkey FOREIGN KEY (oauth_access_token_key_id) REFERENCES dbcrypt_keys(active_key_digest); ForeignKeyUserLinksOauthRefreshTokenKeyID ForeignKeyConstraint = "user_links_oauth_refresh_token_key_id_fkey" // ALTER TABLE ONLY user_links ADD CONSTRAINT user_links_oauth_refresh_token_key_id_fkey FOREIGN KEY (oauth_refresh_token_key_id) REFERENCES dbcrypt_keys(active_key_digest); diff --git a/coderd/database/migrations/000293_user_configs.up.sql b/coderd/database/migrations/000293_user_configs.up.sql index e52654563f75d..fb5db1d8e5f6e 100644 --- a/coderd/database/migrations/000293_user_configs.up.sql +++ b/coderd/database/migrations/000293_user_configs.up.sql @@ -7,11 +7,8 @@ CREATE TABLE IF NOT EXISTS user_configs ( FOREIGN KEY (user_id) REFERENCES users (id) ON DELETE CASCADE ); -ALTER TABLE ONLY user_configs - ADD CONSTRAINT unique_key_per_user UNIQUE (user_id, key); - --- +-- Copy "theme_preference" from "users" table INSERT INTO user_configs (user_id, key, value) SELECT id, 'theme_preference', theme_preference FROM users diff --git a/coderd/database/queries.sql.go b/coderd/database/queries.sql.go index ef5f87b69fa1a..73b6435ee4e2a 100644 --- a/coderd/database/queries.sql.go +++ b/coderd/database/queries.sql.go @@ -11426,7 +11426,7 @@ INSERT INTO VALUES ($1, 'theme_preference', $2) ON CONFLICT - ON CONSTRAINT unique_key_per_user + ON CONSTRAINT user_configs_pkey DO UPDATE SET value = $2 diff --git a/coderd/database/queries/users.sql b/coderd/database/queries/users.sql index c45aa83bd46e6..79f19c1784155 100644 --- a/coderd/database/queries/users.sql +++ b/coderd/database/queries/users.sql @@ -113,7 +113,7 @@ INSERT INTO VALUES (@user_id, 'theme_preference', @theme_preference) ON CONFLICT - ON CONSTRAINT unique_key_per_user + ON CONSTRAINT user_configs_pkey DO UPDATE SET value = @theme_preference diff --git a/coderd/database/unique_constraint.go b/coderd/database/unique_constraint.go index 2132068aefe03..c86daa9aa167d 100644 --- a/coderd/database/unique_constraint.go +++ b/coderd/database/unique_constraint.go @@ -65,7 +65,7 @@ const ( UniqueTemplateVersionsPkey UniqueConstraint = "template_versions_pkey" // ALTER TABLE ONLY template_versions ADD CONSTRAINT template_versions_pkey PRIMARY KEY (id); UniqueTemplateVersionsTemplateIDNameKey UniqueConstraint = "template_versions_template_id_name_key" // ALTER TABLE ONLY template_versions ADD CONSTRAINT template_versions_template_id_name_key UNIQUE (template_id, name); UniqueTemplatesPkey UniqueConstraint = "templates_pkey" // ALTER TABLE ONLY templates ADD CONSTRAINT templates_pkey PRIMARY KEY (id); - UniqueUniqueKeyPerUser UniqueConstraint = "unique_key_per_user" // ALTER TABLE ONLY user_configs ADD CONSTRAINT unique_key_per_user UNIQUE (user_id, key); + UniqueUserConfigsPkey UniqueConstraint = "user_configs_pkey" // ALTER TABLE ONLY user_configs ADD CONSTRAINT user_configs_pkey PRIMARY KEY (user_id, key); UniqueUserDeletedPkey UniqueConstraint = "user_deleted_pkey" // ALTER TABLE ONLY user_deleted ADD CONSTRAINT user_deleted_pkey PRIMARY KEY (id); UniqueUserLinksPkey UniqueConstraint = "user_links_pkey" // ALTER TABLE ONLY user_links ADD CONSTRAINT user_links_pkey PRIMARY KEY (user_id, login_type); UniqueUserStatusChangesPkey UniqueConstraint = "user_status_changes_pkey" // ALTER TABLE ONLY user_status_changes ADD CONSTRAINT user_status_changes_pkey PRIMARY KEY (id); diff --git a/coderd/users.go b/coderd/users.go index 539e0dfe9f3af..482de59c94a25 100644 --- a/coderd/users.go +++ b/coderd/users.go @@ -982,7 +982,7 @@ func (api *API) notifyUserStatusChanged(ctx context.Context, actingUserName stri // @Param user path string true "User ID, name, or me" // @Success 200 {object} codersdk.UserAppearanceSettings // @Router /users/{user}/appearance [get] -func (api *API) getUserAppearanceSettings(rw http.ResponseWriter, r *http.Request) { +func (api *API) userAppearanceSettings(rw http.ResponseWriter, r *http.Request) { var ( ctx = r.Context() user = httpmw.UserParam(r) From d30d1ec9a06d21789e4c5fdbef7ceb7af9d9a1b1 Mon Sep 17 00:00:00 2001 From: McKayla Washburn Date: Fri, 14 Feb 2025 19:38:12 +0000 Subject: [PATCH 08/20] =?UTF-8?q?=F0=9F=8F=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- cli/testdata/coder_users_list_--output_json.golden | 2 -- 1 file changed, 2 deletions(-) diff --git a/cli/testdata/coder_users_list_--output_json.golden b/cli/testdata/coder_users_list_--output_json.golden index fa82286acebbf..61b17e026d290 100644 --- a/cli/testdata/coder_users_list_--output_json.golden +++ b/cli/testdata/coder_users_list_--output_json.golden @@ -10,7 +10,6 @@ "last_seen_at": "====[timestamp]=====", "status": "active", "login_type": "password", - "theme_preference": "", "organization_ids": [ "===========[first org ID]===========" ], @@ -32,7 +31,6 @@ "last_seen_at": "====[timestamp]=====", "status": "dormant", "login_type": "password", - "theme_preference": "", "organization_ids": [ "===========[first org ID]===========" ], From 24d1ae02771ce7031a171bdfecbfcf398a195401 Mon Sep 17 00:00:00 2001 From: McKayla Washburn Date: Fri, 14 Feb 2025 19:46:56 +0000 Subject: [PATCH 09/20] mock new /appearance route --- site/src/testHelpers/handlers.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/site/src/testHelpers/handlers.ts b/site/src/testHelpers/handlers.ts index b458956b17a1d..e8dc9e2dedd3c 100644 --- a/site/src/testHelpers/handlers.ts +++ b/site/src/testHelpers/handlers.ts @@ -162,6 +162,9 @@ export const handlers = [ http.get("/api/v2/users/me", () => { return HttpResponse.json(M.MockUser); }), + http.get("/api/v2/users/me/appearance", () => { + return HttpResponse.json(M.MockUserAppearanceSettings); + }), http.get("/api/v2/users/me/keys", () => { return HttpResponse.json(M.MockAPIKey); }), From 929d70b93c1d1c4696a04a4d649f42626f47d06e Mon Sep 17 00:00:00 2001 From: McKayla Washburn Date: Fri, 14 Feb 2025 21:34:57 +0000 Subject: [PATCH 10/20] fixies --- coderd/apidoc/docs.go | 4 ++-- coderd/apidoc/swagger.json | 4 ++-- coderd/database/dbauthz/dbauthz.go | 6 ++++- coderd/users.go | 6 ++--- docs/reference/api/users.md | 37 ++++++++++++++++++++++++++++++ 5 files changed, 49 insertions(+), 8 deletions(-) diff --git a/coderd/apidoc/docs.go b/coderd/apidoc/docs.go index 70a0c8016f110..a1f6a90a73b95 100644 --- a/coderd/apidoc/docs.go +++ b/coderd/apidoc/docs.go @@ -6329,8 +6329,8 @@ const docTemplate = `{ "tags": [ "Users" ], - "summary": "Update user appearance settings", - "operationId": "update-user-appearance-settings", + "summary": "Get user appearance settings", + "operationId": "get-user-appearance-settings", "parameters": [ { "type": "string", diff --git a/coderd/apidoc/swagger.json b/coderd/apidoc/swagger.json index 30c2ed28e067c..fc5d23934bee8 100644 --- a/coderd/apidoc/swagger.json +++ b/coderd/apidoc/swagger.json @@ -5581,8 +5581,8 @@ "consumes": ["application/json"], "produces": ["application/json"], "tags": ["Users"], - "summary": "Update user appearance settings", - "operationId": "update-user-appearance-settings", + "summary": "Get user appearance settings", + "operationId": "get-user-appearance-settings", "parameters": [ { "type": "string", diff --git a/coderd/database/dbauthz/dbauthz.go b/coderd/database/dbauthz/dbauthz.go index 9cf14fc85a52a..46ef898e8148b 100644 --- a/coderd/database/dbauthz/dbauthz.go +++ b/coderd/database/dbauthz/dbauthz.go @@ -2425,7 +2425,11 @@ func (q *querier) GetUserActivityInsights(ctx context.Context, arg database.GetU } func (q *querier) GetUserAppearanceSettings(ctx context.Context, userID uuid.UUID) (string, error) { - if err := q.authorizeContext(ctx, policy.ActionReadPersonal, rbac.ResourceUser); err != nil { + 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) diff --git a/coderd/users.go b/coderd/users.go index 482de59c94a25..2507a313c1288 100644 --- a/coderd/users.go +++ b/coderd/users.go @@ -973,8 +973,8 @@ func (api *API) notifyUserStatusChanged(ctx context.Context, actingUserName stri return nil } -// @Summary Update user appearance settings -// @ID update-user-appearance-settings +// @Summary Get user appearance settings +// @ID get-user-appearance-settings // @Security CoderSessionToken // @Accept json // @Produce json @@ -1003,7 +1003,7 @@ func (api *API) userAppearanceSettings(rw http.ResponseWriter, r *http.Request) } // @Summary Update user appearance settings -// @ID update-user-appearance-settings +// @ID update-user-appearance-setting // @Security CoderSessionToken // @Accept json // @Produce json diff --git a/docs/reference/api/users.md b/docs/reference/api/users.md index 67fe73b57c6f8..60689ac012dc1 100644 --- a/docs/reference/api/users.md +++ b/docs/reference/api/users.md @@ -437,6 +437,43 @@ curl -X DELETE http://coder-server:8080/api/v2/users/{user} \ To perform this operation, you must be authenticated. [Learn more](authentication.md). +## Get user appearance settings + +### Code samples + +```shell +# Example request using curl +curl -X GET http://coder-server:8080/api/v2/users/{user}/appearance \ + -H 'Accept: application/json' \ + -H 'Coder-Session-Token: API_KEY' +``` + +`GET /users/{user}/appearance` + +### Parameters + +| Name | In | Type | Required | Description | +|--------|------|--------|----------|----------------------| +| `user` | path | string | true | User ID, name, or me | + +### Example responses + +> 200 Response + +```json +{ + "theme_preference": "string" +} +``` + +### Responses + +| Status | Meaning | Description | Schema | +|--------|---------------------------------------------------------|-------------|------------------------------------------------------------------------------| +| 200 | [OK](https://tools.ietf.org/html/rfc7231#section-6.3.1) | OK | [codersdk.UserAppearanceSettings](schemas.md#codersdkuserappearancesettings) | + +To perform this operation, you must be authenticated. [Learn more](authentication.md). + ## Update user appearance settings ### Code samples From 766d0306baa78bb2e2913afc97e153b11ebb1524 Mon Sep 17 00:00:00 2001 From: McKayla Washburn Date: Fri, 14 Feb 2025 22:06:12 +0000 Subject: [PATCH 11/20] :^) --- .../components/FileUpload/FileUpload.test.tsx | 22 +++++++++---------- site/src/hooks/useClipboard.test.tsx | 7 +++--- .../AppearancePage/AppearancePage.test.tsx | 2 +- .../WorkspaceScheduleControls.test.tsx | 19 ++++------------ site/src/testHelpers/renderHelpers.tsx | 7 ++++-- 5 files changed, 24 insertions(+), 33 deletions(-) diff --git a/site/src/components/FileUpload/FileUpload.test.tsx b/site/src/components/FileUpload/FileUpload.test.tsx index 2ff94f355bcfe..e4e40a477cd26 100644 --- a/site/src/components/FileUpload/FileUpload.test.tsx +++ b/site/src/components/FileUpload/FileUpload.test.tsx @@ -1,20 +1,18 @@ -import { fireEvent, render, screen } from "@testing-library/react"; -import { ThemeProvider } from "contexts/ThemeProvider"; +import { fireEvent, screen } from "@testing-library/react"; import { FileUpload } from "./FileUpload"; +import { renderComponent } from "testHelpers/renderHelpers"; test("accepts files with the correct extension", async () => { const onUpload = jest.fn(); - render( - - - , + renderComponent( + , ); const dropZone = screen.getByTestId("drop-zone"); diff --git a/site/src/hooks/useClipboard.test.tsx b/site/src/hooks/useClipboard.test.tsx index f98c1d1154b86..316fa391f5a74 100644 --- a/site/src/hooks/useClipboard.test.tsx +++ b/site/src/hooks/useClipboard.test.tsx @@ -11,7 +11,7 @@ */ import { act, renderHook, screen } from "@testing-library/react"; import { GlobalSnackbar } from "components/GlobalSnackbar/GlobalSnackbar"; -import { ThemeProvider } from "contexts/ThemeProvider"; +import { ThemeOverride } from "contexts/ThemeProvider"; import { COPY_FAILED_MESSAGE, HTTP_FALLBACK_DATA_ID, @@ -19,6 +19,7 @@ import { type UseClipboardResult, useClipboard, } from "./useClipboard"; +import themes, { DEFAULT_THEME } from "theme"; // Need to mock console.error because we deliberately need to trigger errors in // the code to assert that it can recover from them, but we also don't want them @@ -121,10 +122,10 @@ function renderUseClipboard(inputs: TInput) { initialProps: inputs, wrapper: ({ children }) => ( // Need ThemeProvider because GlobalSnackbar uses theme - + {children} - + ), }, ); diff --git a/site/src/pages/UserSettingsPage/AppearancePage/AppearancePage.test.tsx b/site/src/pages/UserSettingsPage/AppearancePage/AppearancePage.test.tsx index e3eb0d9c12367..c48c265460a4e 100644 --- a/site/src/pages/UserSettingsPage/AppearancePage/AppearancePage.test.tsx +++ b/site/src/pages/UserSettingsPage/AppearancePage/AppearancePage.test.tsx @@ -34,7 +34,7 @@ describe("appearance page", () => { // Check if the API was called correctly expect(API.updateAppearanceSettings).toBeCalledTimes(1); - expect(API.updateAppearanceSettings).toHaveBeenCalledWith("me", { + expect(API.updateAppearanceSettings).toHaveBeenCalledWith({ theme_preference: "light", }); }); diff --git a/site/src/pages/WorkspacePage/WorkspaceScheduleControls.test.tsx b/site/src/pages/WorkspacePage/WorkspaceScheduleControls.test.tsx index 3d2f44602bd31..827d06cf1b96a 100644 --- a/site/src/pages/WorkspacePage/WorkspaceScheduleControls.test.tsx +++ b/site/src/pages/WorkspacePage/WorkspaceScheduleControls.test.tsx @@ -1,17 +1,15 @@ -import { render, screen } from "@testing-library/react"; +import { screen } from "@testing-library/react"; import userEvent from "@testing-library/user-event"; import { API } from "api/api"; import { workspaceByOwnerAndName } from "api/queries/workspaces"; -import { GlobalSnackbar } from "components/GlobalSnackbar/GlobalSnackbar"; -import { ThemeProvider } from "contexts/ThemeProvider"; import dayjs from "dayjs"; import { http, HttpResponse } from "msw"; import type { FC } from "react"; -import { QueryClient, QueryClientProvider, useQuery } from "react-query"; -import { RouterProvider, createMemoryRouter } from "react-router-dom"; +import { useQuery } from "react-query"; import { MockTemplate, MockWorkspace } from "testHelpers/entities"; import { server } from "testHelpers/server"; import { WorkspaceScheduleControls } from "./WorkspaceScheduleControls"; +import { render } from "testHelpers/renderHelpers"; const Wrapper: FC = () => { const { data: workspace } = useQuery( @@ -45,16 +43,7 @@ const renderScheduleControls = async () => { }); }), ); - render( - - - }])} - /> - - - , - ); + render(); await screen.findByTestId("schedule-controls"); expect(screen.getByText("Stop in 3 hours")).toBeInTheDocument(); }; diff --git a/site/src/testHelpers/renderHelpers.tsx b/site/src/testHelpers/renderHelpers.tsx index 330919c7ef7f6..854fe0a94475b 100644 --- a/site/src/testHelpers/renderHelpers.tsx +++ b/site/src/testHelpers/renderHelpers.tsx @@ -5,7 +5,7 @@ import { } from "@testing-library/react"; import { AppProviders } from "App"; import type { ProxyProvider } from "contexts/ProxyContext"; -import { ThemeProvider } from "contexts/ThemeProvider"; +import { ThemeOverride } from "contexts/ThemeProvider"; import { RequireAuth } from "contexts/auth/RequireAuth"; import { DashboardLayout } from "modules/dashboard/DashboardLayout"; import type { DashboardProvider } from "modules/dashboard/DashboardProvider"; @@ -20,6 +20,7 @@ import { createMemoryRouter, } from "react-router-dom"; import { MockUser } from "./entities"; +import themes, { DEFAULT_THEME } from "theme"; export function createTestQueryClient() { // Helps create one query client for each test case, to make sure that tests @@ -245,6 +246,8 @@ export const waitForLoaderToBeRemoved = async (): Promise => { export const renderComponent = (component: React.ReactElement) => { return testingLibraryRender(component, { - wrapper: ({ children }) => {children}, + wrapper: ({ children }) => ( + {children} + ), }); }; From 57b6a489609929e6838ea8f22fb1dfee355916fa Mon Sep 17 00:00:00 2001 From: McKayla Washburn Date: Fri, 14 Feb 2025 22:10:08 +0000 Subject: [PATCH 12/20] would you pls --- coderd/users.go | 2 +- site/src/components/FileUpload/FileUpload.test.tsx | 2 +- site/src/hooks/useClipboard.test.tsx | 2 +- site/src/pages/WorkspacePage/WorkspaceScheduleControls.test.tsx | 2 +- site/src/testHelpers/renderHelpers.tsx | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/coderd/users.go b/coderd/users.go index 2507a313c1288..2fc88d466be90 100644 --- a/coderd/users.go +++ b/coderd/users.go @@ -1003,7 +1003,7 @@ func (api *API) userAppearanceSettings(rw http.ResponseWriter, r *http.Request) } // @Summary Update user appearance settings -// @ID update-user-appearance-setting +// @ID update-user-appearance-settings // @Security CoderSessionToken // @Accept json // @Produce json diff --git a/site/src/components/FileUpload/FileUpload.test.tsx b/site/src/components/FileUpload/FileUpload.test.tsx index e4e40a477cd26..6292bc200a517 100644 --- a/site/src/components/FileUpload/FileUpload.test.tsx +++ b/site/src/components/FileUpload/FileUpload.test.tsx @@ -1,6 +1,6 @@ import { fireEvent, screen } from "@testing-library/react"; -import { FileUpload } from "./FileUpload"; import { renderComponent } from "testHelpers/renderHelpers"; +import { FileUpload } from "./FileUpload"; test("accepts files with the correct extension", async () => { const onUpload = jest.fn(); diff --git a/site/src/hooks/useClipboard.test.tsx b/site/src/hooks/useClipboard.test.tsx index 316fa391f5a74..1d4d2eb702a81 100644 --- a/site/src/hooks/useClipboard.test.tsx +++ b/site/src/hooks/useClipboard.test.tsx @@ -12,6 +12,7 @@ import { act, renderHook, screen } from "@testing-library/react"; import { GlobalSnackbar } from "components/GlobalSnackbar/GlobalSnackbar"; import { ThemeOverride } from "contexts/ThemeProvider"; +import themes, { DEFAULT_THEME } from "theme"; import { COPY_FAILED_MESSAGE, HTTP_FALLBACK_DATA_ID, @@ -19,7 +20,6 @@ import { type UseClipboardResult, useClipboard, } from "./useClipboard"; -import themes, { DEFAULT_THEME } from "theme"; // Need to mock console.error because we deliberately need to trigger errors in // the code to assert that it can recover from them, but we also don't want them diff --git a/site/src/pages/WorkspacePage/WorkspaceScheduleControls.test.tsx b/site/src/pages/WorkspacePage/WorkspaceScheduleControls.test.tsx index 827d06cf1b96a..225db7c8a44c0 100644 --- a/site/src/pages/WorkspacePage/WorkspaceScheduleControls.test.tsx +++ b/site/src/pages/WorkspacePage/WorkspaceScheduleControls.test.tsx @@ -7,9 +7,9 @@ import { http, HttpResponse } from "msw"; import type { FC } from "react"; import { useQuery } from "react-query"; import { MockTemplate, MockWorkspace } from "testHelpers/entities"; +import { render } from "testHelpers/renderHelpers"; import { server } from "testHelpers/server"; import { WorkspaceScheduleControls } from "./WorkspaceScheduleControls"; -import { render } from "testHelpers/renderHelpers"; const Wrapper: FC = () => { const { data: workspace } = useQuery( diff --git a/site/src/testHelpers/renderHelpers.tsx b/site/src/testHelpers/renderHelpers.tsx index 854fe0a94475b..eb76b481783da 100644 --- a/site/src/testHelpers/renderHelpers.tsx +++ b/site/src/testHelpers/renderHelpers.tsx @@ -19,8 +19,8 @@ import { RouterProvider, createMemoryRouter, } from "react-router-dom"; -import { MockUser } from "./entities"; import themes, { DEFAULT_THEME } from "theme"; +import { MockUser } from "./entities"; export function createTestQueryClient() { // Helps create one query client for each test case, to make sure that tests From 18447a3985bf29471485758f1cbdf1e1bf51e7ed Mon Sep 17 00:00:00 2001 From: McKayla Washburn Date: Fri, 14 Feb 2025 22:25:20 +0000 Subject: [PATCH 13/20] take your test --- coderd/database/dbauthz/dbauthz_test.go | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/coderd/database/dbauthz/dbauthz_test.go b/coderd/database/dbauthz/dbauthz_test.go index afb87b2d8a8ca..2815a1700e364 100644 --- a/coderd/database/dbauthz/dbauthz_test.go +++ b/coderd/database/dbauthz/dbauthz_test.go @@ -1521,6 +1521,15 @@ func (s *MethodTestSuite) TestUser() { []database.GetUserWorkspaceBuildParametersRow{}, ) })) + s.Run("GetUserAppearanceSettings", s.Subtest(func(db database.Store, check *expects) { + ctx := context.Background() + u := dbgen.User(s.T(), db, database.User{}) + db.UpdateUserAppearanceSettings(ctx, database.UpdateUserAppearanceSettingsParams{ + 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) { u := dbgen.User(s.T(), db, database.User{}) uc := database.UserConfig{ From 04c298c31466945593d7dc5aa869a4278e587ace Mon Sep 17 00:00:00 2001 From: McKayla Washburn Date: Fri, 14 Feb 2025 22:41:35 +0000 Subject: [PATCH 14/20] :| --- coderd/apidoc/docs.go | 3 --- coderd/apidoc/swagger.json | 1 - coderd/users.go | 1 - 3 files changed, 5 deletions(-) diff --git a/coderd/apidoc/docs.go b/coderd/apidoc/docs.go index a1f6a90a73b95..e4d348aa295e8 100644 --- a/coderd/apidoc/docs.go +++ b/coderd/apidoc/docs.go @@ -6320,9 +6320,6 @@ const docTemplate = `{ "CoderSessionToken": [] } ], - "consumes": [ - "application/json" - ], "produces": [ "application/json" ], diff --git a/coderd/apidoc/swagger.json b/coderd/apidoc/swagger.json index fc5d23934bee8..d3e062ca6a285 100644 --- a/coderd/apidoc/swagger.json +++ b/coderd/apidoc/swagger.json @@ -5578,7 +5578,6 @@ "CoderSessionToken": [] } ], - "consumes": ["application/json"], "produces": ["application/json"], "tags": ["Users"], "summary": "Get user appearance settings", diff --git a/coderd/users.go b/coderd/users.go index 2fc88d466be90..4e6f2be52729d 100644 --- a/coderd/users.go +++ b/coderd/users.go @@ -976,7 +976,6 @@ func (api *API) notifyUserStatusChanged(ctx context.Context, actingUserName stri // @Summary Get user appearance settings // @ID get-user-appearance-settings // @Security CoderSessionToken -// @Accept json // @Produce json // @Tags Users // @Param user path string true "User ID, name, or me" From bb1ac6e704a24d94e448996da485b47899246930 Mon Sep 17 00:00:00 2001 From: McKayla Washburn Date: Fri, 14 Feb 2025 22:53:28 +0000 Subject: [PATCH 15/20] ok --- coderd/users.go | 14 +++++++++----- site/site.go | 4 ++++ site/site_test.go | 3 +++ 3 files changed, 16 insertions(+), 5 deletions(-) diff --git a/coderd/users.go b/coderd/users.go index 4e6f2be52729d..97babd0ae7836 100644 --- a/coderd/users.go +++ b/coderd/users.go @@ -989,11 +989,15 @@ func (api *API) userAppearanceSettings(rw http.ResponseWriter, r *http.Request) themePreference, err := api.Database.GetUserAppearanceSettings(ctx, user.ID) if err != nil { - httpapi.Write(ctx, rw, http.StatusInternalServerError, codersdk.Response{ - Message: "Internal error updating user.", - Detail: err.Error(), - }) - return + if !errors.Is(err, sql.ErrNoRows) { + httpapi.Write(ctx, rw, http.StatusInternalServerError, codersdk.Response{ + Message: "Error reading user settings.", + Detail: err.Error(), + }) + return + } + + themePreference = "" } httpapi.Write(ctx, rw, http.StatusOK, codersdk.UserAppearanceSettings{ diff --git a/site/site.go b/site/site.go index 3b42cf30aab9a..eea4794c6c216 100644 --- a/site/site.go +++ b/site/site.go @@ -437,6 +437,10 @@ 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) + if errors.Is(err, sql.ErrNoRows) { + themePreference = "" + return nil + } return err }) eg.Go(func() error { diff --git a/site/site_test.go b/site/site_test.go index 63f3f9aa17226..ae03536981e82 100644 --- a/site/site_test.go +++ b/site/site_test.go @@ -65,6 +65,9 @@ func TestInjection(t *testing.T) { handler.ServeHTTP(rw, r) require.Equal(t, http.StatusOK, rw.Code) + fmt.Println("oh boy oh boy oh boy") + fmt.Println(rw.Body.String()) + fmt.Println("oh boy oh boy oh boy") var got codersdk.User err := json.Unmarshal([]byte(html.UnescapeString(rw.Body.String())), &got) require.NoError(t, err) From 8036b87e878fe810189bc4155bffbbca47ce391e Mon Sep 17 00:00:00 2001 From: McKayla Washburn Date: Fri, 14 Feb 2025 22:56:28 +0000 Subject: [PATCH 16/20] - --- site/site_test.go | 3 --- 1 file changed, 3 deletions(-) diff --git a/site/site_test.go b/site/site_test.go index ae03536981e82..63f3f9aa17226 100644 --- a/site/site_test.go +++ b/site/site_test.go @@ -65,9 +65,6 @@ func TestInjection(t *testing.T) { handler.ServeHTTP(rw, r) require.Equal(t, http.StatusOK, rw.Code) - fmt.Println("oh boy oh boy oh boy") - fmt.Println(rw.Body.String()) - fmt.Println("oh boy oh boy oh boy") var got codersdk.User err := json.Unmarshal([]byte(html.UnescapeString(rw.Body.String())), &got) require.NoError(t, err) From f694cfccbca895fee23e1c6d1d04efe512668c2d Mon Sep 17 00:00:00 2001 From: McKayla Washburn Date: Fri, 14 Feb 2025 23:26:36 +0000 Subject: [PATCH 17/20] down --- coderd/database/migrations/000293_user_configs.down.sql | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/coderd/database/migrations/000293_user_configs.down.sql b/coderd/database/migrations/000293_user_configs.down.sql index e3fb8d9403cc7..c3ca42798ef98 100644 --- a/coderd/database/migrations/000293_user_configs.down.sql +++ b/coderd/database/migrations/000293_user_configs.down.sql @@ -3,11 +3,11 @@ ALTER TABLE users ADD COLUMN IF NOT EXISTS theme_preference text DEFAULT ''::text NOT NULL; -- Copy "theme_preference" back to "users" -UPDATE users (theme_preference) - SELECT value +UPDATE users + SET theme_preference = (SELECT value FROM user_configs - WHERE users.id = user_configs.user_id - AND user_configs.key = 'theme_preference'; + WHERE user_configs.user_id = users.id + AND user_configs.key = 'theme_preference'); -- Drop the "user_configs" table. DROP TABLE user_configs; From 67fb8acd1405d25b8aa2fcee1b4c51aa1364cdb9 Mon Sep 17 00:00:00 2001 From: McKayla Washburn Date: Wed, 19 Feb 2025 00:05:47 +0000 Subject: [PATCH 18/20] oops --- .../calling-module/calling-module.tfplan.json | 4 +-- .../calling-module.tfstate.json | 10 +++---- .../chaining-resources.tfplan.json | 4 +-- .../chaining-resources.tfstate.json | 10 +++---- .../conflicting-resources.tfplan.json | 4 +-- .../conflicting-resources.tfstate.json | 10 +++---- .../display-apps-disabled.tfplan.json | 4 +-- .../display-apps-disabled.tfstate.json | 8 +++--- .../display-apps/display-apps.tfplan.json | 4 +-- .../display-apps/display-apps.tfstate.json | 8 +++--- .../external-auth-providers.tfplan.json | 6 ++-- .../external-auth-providers.tfstate.json | 8 +++--- .../instance-id/instance-id.tfplan.json | 4 +-- .../instance-id/instance-id.tfstate.json | 12 ++++---- .../mapped-apps/mapped-apps.tfplan.json | 4 +-- .../mapped-apps/mapped-apps.tfstate.json | 16 +++++------ .../multiple-agents-multiple-apps.tfplan.json | 4 +-- ...multiple-agents-multiple-apps.tfstate.json | 26 ++++++++--------- .../multiple-agents-multiple-envs.tfplan.json | 4 +-- ...multiple-agents-multiple-envs.tfstate.json | 26 ++++++++--------- ...tiple-agents-multiple-monitors.tfplan.json | 4 +-- ...iple-agents-multiple-monitors.tfstate.json | 20 ++++++------- ...ltiple-agents-multiple-scripts.tfplan.json | 4 +-- ...tiple-agents-multiple-scripts.tfstate.json | 26 ++++++++--------- .../multiple-agents.tfplan.json | 4 +-- .../multiple-agents.tfstate.json | 20 ++++++------- .../multiple-apps/multiple-apps.tfplan.json | 4 +-- .../multiple-apps/multiple-apps.tfstate.json | 20 ++++++------- .../resource-metadata-duplicate.tfplan.json | 4 +-- .../resource-metadata-duplicate.tfstate.json | 16 +++++------ .../resource-metadata.tfplan.json | 4 +-- .../resource-metadata.tfstate.json | 12 ++++---- .../rich-parameters-order.tfplan.json | 10 +++---- .../rich-parameters-order.tfstate.json | 12 ++++---- .../rich-parameters-validation.tfplan.json | 18 ++++++------ .../rich-parameters-validation.tfstate.json | 20 ++++++------- .../rich-parameters.tfplan.json | 26 ++++++++--------- .../rich-parameters.tfstate.json | 28 +++++++++---------- 38 files changed, 214 insertions(+), 214 deletions(-) diff --git a/provisioner/terraform/testdata/calling-module/calling-module.tfplan.json b/provisioner/terraform/testdata/calling-module/calling-module.tfplan.json index d3c8d6bbd4792..8759627e35398 100644 --- a/provisioner/terraform/testdata/calling-module/calling-module.tfplan.json +++ b/provisioner/terraform/testdata/calling-module/calling-module.tfplan.json @@ -1,6 +1,6 @@ { "format_version": "1.2", - "terraform_version": "1.9.8", + "terraform_version": "1.10.5", "planned_values": { "root_module": { "resources": [ @@ -254,7 +254,7 @@ ] } ], - "timestamp": "2025-02-18T18:21:16Z", + "timestamp": "2025-02-18T10:58:12Z", "applyable": true, "complete": true, "errored": false diff --git a/provisioner/terraform/testdata/calling-module/calling-module.tfstate.json b/provisioner/terraform/testdata/calling-module/calling-module.tfstate.json index aab85b9b862e6..0286c44e0412b 100644 --- a/provisioner/terraform/testdata/calling-module/calling-module.tfstate.json +++ b/provisioner/terraform/testdata/calling-module/calling-module.tfstate.json @@ -1,6 +1,6 @@ { "format_version": "1.0", - "terraform_version": "1.9.8", + "terraform_version": "1.10.5", "values": { "root_module": { "resources": [ @@ -26,7 +26,7 @@ } ], "env": null, - "id": "99813be0-d7b7-4a73-a751-73f98a1819fd", + "id": "6b8c1681-8d24-454f-9674-75aa10a78a66", "init_script": "", "metadata": [], "motd_file": null, @@ -35,7 +35,7 @@ "shutdown_script": null, "startup_script": null, "startup_script_behavior": "non-blocking", - "token": "e00cfe7e-1e10-4ed5-8bd7-e5df9ce50e76", + "token": "b10f2c9a-2936-4d64-9d3c-3705fa094272", "troubleshooting_url": null }, "sensitive_values": { @@ -66,7 +66,7 @@ "outputs": { "script": "" }, - "random": "6991323013163911812" + "random": "2818431725852233027" }, "sensitive_values": { "inputs": {}, @@ -81,7 +81,7 @@ "provider_name": "registry.terraform.io/hashicorp/null", "schema_version": 0, "values": { - "id": "7450673059056179011", + "id": "2514800225855033412", "triggers": null }, "sensitive_values": {}, diff --git a/provisioner/terraform/testdata/chaining-resources/chaining-resources.tfplan.json b/provisioner/terraform/testdata/chaining-resources/chaining-resources.tfplan.json index a7b0020fdbd5f..4f478962e7b97 100644 --- a/provisioner/terraform/testdata/chaining-resources/chaining-resources.tfplan.json +++ b/provisioner/terraform/testdata/chaining-resources/chaining-resources.tfplan.json @@ -1,6 +1,6 @@ { "format_version": "1.2", - "terraform_version": "1.9.8", + "terraform_version": "1.10.5", "planned_values": { "root_module": { "resources": [ @@ -199,7 +199,7 @@ ] } }, - "timestamp": "2025-02-18T18:21:16Z", + "timestamp": "2025-02-18T10:58:12Z", "applyable": true, "complete": true, "errored": false diff --git a/provisioner/terraform/testdata/chaining-resources/chaining-resources.tfstate.json b/provisioner/terraform/testdata/chaining-resources/chaining-resources.tfstate.json index abbe48b1adaef..d51e2ecb81c71 100644 --- a/provisioner/terraform/testdata/chaining-resources/chaining-resources.tfstate.json +++ b/provisioner/terraform/testdata/chaining-resources/chaining-resources.tfstate.json @@ -1,6 +1,6 @@ { "format_version": "1.0", - "terraform_version": "1.9.8", + "terraform_version": "1.10.5", "values": { "root_module": { "resources": [ @@ -26,7 +26,7 @@ } ], "env": null, - "id": "abb9ab2c-a59b-4d45-92ce-4883a42a25a0", + "id": "a4c46a8c-dd2a-4913-8897-e77b24fdd7f1", "init_script": "", "metadata": [], "motd_file": null, @@ -35,7 +35,7 @@ "shutdown_script": null, "startup_script": null, "startup_script_behavior": "non-blocking", - "token": "925aef90-3801-4158-bf9b-95ee2739d24b", + "token": "c263f7b6-c0e7-4106-b3fc-aefbe373ee7a", "troubleshooting_url": null }, "sensitive_values": { @@ -54,7 +54,7 @@ "provider_name": "registry.terraform.io/hashicorp/null", "schema_version": 0, "values": { - "id": "1077607069181053633", + "id": "4299141049988455758", "triggers": null }, "sensitive_values": {}, @@ -71,7 +71,7 @@ "provider_name": "registry.terraform.io/hashicorp/null", "schema_version": 0, "values": { - "id": "7753018043075213587", + "id": "8248139888152642631", "triggers": null }, "sensitive_values": {}, diff --git a/provisioner/terraform/testdata/conflicting-resources/conflicting-resources.tfplan.json b/provisioner/terraform/testdata/conflicting-resources/conflicting-resources.tfplan.json index b85b1f4e03a0a..57af82397bd20 100644 --- a/provisioner/terraform/testdata/conflicting-resources/conflicting-resources.tfplan.json +++ b/provisioner/terraform/testdata/conflicting-resources/conflicting-resources.tfplan.json @@ -1,6 +1,6 @@ { "format_version": "1.2", - "terraform_version": "1.9.8", + "terraform_version": "1.10.5", "planned_values": { "root_module": { "resources": [ @@ -199,7 +199,7 @@ ] } }, - "timestamp": "2025-02-18T18:21:16Z", + "timestamp": "2025-02-18T10:58:12Z", "applyable": true, "complete": true, "errored": false diff --git a/provisioner/terraform/testdata/conflicting-resources/conflicting-resources.tfstate.json b/provisioner/terraform/testdata/conflicting-resources/conflicting-resources.tfstate.json index d364ad7e22bdd..f1e9760fcdac1 100644 --- a/provisioner/terraform/testdata/conflicting-resources/conflicting-resources.tfstate.json +++ b/provisioner/terraform/testdata/conflicting-resources/conflicting-resources.tfstate.json @@ -1,6 +1,6 @@ { "format_version": "1.0", - "terraform_version": "1.9.8", + "terraform_version": "1.10.5", "values": { "root_module": { "resources": [ @@ -26,7 +26,7 @@ } ], "env": null, - "id": "a2967190-27de-4110-9800-8365b54c1f2b", + "id": "c5972861-13a8-4c3d-9e7b-c32aab3c5105", "init_script": "", "metadata": [], "motd_file": null, @@ -35,7 +35,7 @@ "shutdown_script": null, "startup_script": null, "startup_script_behavior": "non-blocking", - "token": "ad2bfe66-fab4-4166-9829-138575dca918", + "token": "9c2883aa-0c0e-470f-a40c-588b47e663be", "troubleshooting_url": null }, "sensitive_values": { @@ -54,7 +54,7 @@ "provider_name": "registry.terraform.io/hashicorp/null", "schema_version": 0, "values": { - "id": "4824924933868648791", + "id": "4167500156989566756", "triggers": null }, "sensitive_values": {}, @@ -70,7 +70,7 @@ "provider_name": "registry.terraform.io/hashicorp/null", "schema_version": 0, "values": { - "id": "6383295970090695836", + "id": "2831408390006359178", "triggers": null }, "sensitive_values": {}, diff --git a/provisioner/terraform/testdata/display-apps-disabled/display-apps-disabled.tfplan.json b/provisioner/terraform/testdata/display-apps-disabled/display-apps-disabled.tfplan.json index 9513f7c9dafdd..f715d1e5b36ef 100644 --- a/provisioner/terraform/testdata/display-apps-disabled/display-apps-disabled.tfplan.json +++ b/provisioner/terraform/testdata/display-apps-disabled/display-apps-disabled.tfplan.json @@ -1,6 +1,6 @@ { "format_version": "1.2", - "terraform_version": "1.9.8", + "terraform_version": "1.10.5", "planned_values": { "root_module": { "resources": [ @@ -198,7 +198,7 @@ ] } }, - "timestamp": "2025-02-18T18:21:16Z", + "timestamp": "2025-02-18T10:58:12Z", "applyable": true, "complete": true, "errored": false diff --git a/provisioner/terraform/testdata/display-apps-disabled/display-apps-disabled.tfstate.json b/provisioner/terraform/testdata/display-apps-disabled/display-apps-disabled.tfstate.json index 8d27f240a7fba..8127adf08deb5 100644 --- a/provisioner/terraform/testdata/display-apps-disabled/display-apps-disabled.tfstate.json +++ b/provisioner/terraform/testdata/display-apps-disabled/display-apps-disabled.tfstate.json @@ -1,6 +1,6 @@ { "format_version": "1.0", - "terraform_version": "1.9.8", + "terraform_version": "1.10.5", "values": { "root_module": { "resources": [ @@ -26,7 +26,7 @@ } ], "env": null, - "id": "69a948fe-0f7a-4a2f-a298-69af05f51e5e", + "id": "f145f4f8-1d6c-4a66-ba80-abbc077dfe1e", "init_script": "", "metadata": [], "motd_file": null, @@ -35,7 +35,7 @@ "shutdown_script": null, "startup_script": null, "startup_script_behavior": "non-blocking", - "token": "9b8143bb-8bde-4d38-a7f4-0f6bd977a8e9", + "token": "612a69b3-4b07-4752-b930-ed7dd36dc926", "troubleshooting_url": null }, "sensitive_values": { @@ -54,7 +54,7 @@ "provider_name": "registry.terraform.io/hashicorp/null", "schema_version": 0, "values": { - "id": "7433336070111935217", + "id": "3571714162665255692", "triggers": null }, "sensitive_values": {}, diff --git a/provisioner/terraform/testdata/display-apps/display-apps.tfplan.json b/provisioner/terraform/testdata/display-apps/display-apps.tfplan.json index 6531f7bd68560..b4b3e8d72cb07 100644 --- a/provisioner/terraform/testdata/display-apps/display-apps.tfplan.json +++ b/provisioner/terraform/testdata/display-apps/display-apps.tfplan.json @@ -1,6 +1,6 @@ { "format_version": "1.2", - "terraform_version": "1.9.8", + "terraform_version": "1.10.5", "planned_values": { "root_module": { "resources": [ @@ -198,7 +198,7 @@ ] } }, - "timestamp": "2025-02-18T18:21:16Z", + "timestamp": "2025-02-18T10:58:12Z", "applyable": true, "complete": true, "errored": false diff --git a/provisioner/terraform/testdata/display-apps/display-apps.tfstate.json b/provisioner/terraform/testdata/display-apps/display-apps.tfstate.json index b77b4f29d2c7c..53be3e3041729 100644 --- a/provisioner/terraform/testdata/display-apps/display-apps.tfstate.json +++ b/provisioner/terraform/testdata/display-apps/display-apps.tfstate.json @@ -1,6 +1,6 @@ { "format_version": "1.0", - "terraform_version": "1.9.8", + "terraform_version": "1.10.5", "values": { "root_module": { "resources": [ @@ -26,7 +26,7 @@ } ], "env": null, - "id": "636f2be0-1b27-41ac-a956-21492da0dc39", + "id": "df983aa4-ad0a-458a-acd2-1d5c93e4e4d8", "init_script": "", "metadata": [], "motd_file": null, @@ -35,7 +35,7 @@ "shutdown_script": null, "startup_script": null, "startup_script_behavior": "non-blocking", - "token": "0c53590c-daa7-4f8e-b880-fbd61b8de2e3", + "token": "c2ccd3c2-5ac3-46f5-9620-f1d4c633169f", "troubleshooting_url": null }, "sensitive_values": { @@ -54,7 +54,7 @@ "provider_name": "registry.terraform.io/hashicorp/null", "schema_version": 0, "values": { - "id": "2200476559043400784", + "id": "4058093101918806466", "triggers": null }, "sensitive_values": {}, diff --git a/provisioner/terraform/testdata/external-auth-providers/external-auth-providers.tfplan.json b/provisioner/terraform/testdata/external-auth-providers/external-auth-providers.tfplan.json index 1e49b9d9d34a4..fbd2636bfb68d 100644 --- a/provisioner/terraform/testdata/external-auth-providers/external-auth-providers.tfplan.json +++ b/provisioner/terraform/testdata/external-auth-providers/external-auth-providers.tfplan.json @@ -1,6 +1,6 @@ { "format_version": "1.2", - "terraform_version": "1.9.8", + "terraform_version": "1.10.5", "planned_values": { "root_module": { "resources": [ @@ -113,7 +113,7 @@ ], "prior_state": { "format_version": "1.0", - "terraform_version": "1.9.8", + "terraform_version": "1.10.5", "values": { "root_module": { "resources": [ @@ -222,7 +222,7 @@ ] } }, - "timestamp": "2025-02-18T18:21:16Z", + "timestamp": "2025-02-18T10:58:12Z", "applyable": true, "complete": true, "errored": false diff --git a/provisioner/terraform/testdata/external-auth-providers/external-auth-providers.tfstate.json b/provisioner/terraform/testdata/external-auth-providers/external-auth-providers.tfstate.json index 5a5ce2e321741..e439476cc9b52 100644 --- a/provisioner/terraform/testdata/external-auth-providers/external-auth-providers.tfstate.json +++ b/provisioner/terraform/testdata/external-auth-providers/external-auth-providers.tfstate.json @@ -1,6 +1,6 @@ { "format_version": "1.0", - "terraform_version": "1.9.8", + "terraform_version": "1.10.5", "values": { "root_module": { "resources": [ @@ -54,7 +54,7 @@ } ], "env": null, - "id": "9e757383-d864-4d62-a0f6-c97e84796094", + "id": "048746d5-8a05-4615-bdf3-5e0ecda12ba0", "init_script": "", "metadata": [], "motd_file": null, @@ -63,7 +63,7 @@ "shutdown_script": null, "startup_script": null, "startup_script_behavior": "non-blocking", - "token": "310d28cf-0eb2-4a7c-859c-762bb505f5c4", + "token": "d2a64629-1d18-4704-a3b1-eae300a362d1", "troubleshooting_url": null }, "sensitive_values": { @@ -82,7 +82,7 @@ "provider_name": "registry.terraform.io/hashicorp/null", "schema_version": 0, "values": { - "id": "1250995009519083999", + "id": "5369997016721085167", "triggers": null }, "sensitive_values": {}, diff --git a/provisioner/terraform/testdata/instance-id/instance-id.tfplan.json b/provisioner/terraform/testdata/instance-id/instance-id.tfplan.json index 200e924224b0d..7c929b496d8fd 100644 --- a/provisioner/terraform/testdata/instance-id/instance-id.tfplan.json +++ b/provisioner/terraform/testdata/instance-id/instance-id.tfplan.json @@ -1,6 +1,6 @@ { "format_version": "1.2", - "terraform_version": "1.9.8", + "terraform_version": "1.10.5", "planned_values": { "root_module": { "resources": [ @@ -219,7 +219,7 @@ ] } ], - "timestamp": "2025-02-18T18:21:16Z", + "timestamp": "2025-02-18T10:58:12Z", "applyable": true, "complete": true, "errored": false diff --git a/provisioner/terraform/testdata/instance-id/instance-id.tfstate.json b/provisioner/terraform/testdata/instance-id/instance-id.tfstate.json index df1ce2a76526e..7f7cdfa6a5055 100644 --- a/provisioner/terraform/testdata/instance-id/instance-id.tfstate.json +++ b/provisioner/terraform/testdata/instance-id/instance-id.tfstate.json @@ -1,6 +1,6 @@ { "format_version": "1.0", - "terraform_version": "1.9.8", + "terraform_version": "1.10.5", "values": { "root_module": { "resources": [ @@ -26,7 +26,7 @@ } ], "env": null, - "id": "26597111-8ebc-4949-90b7-2722007692c7", + "id": "0b84fffb-d2ca-4048-bdab-7b84229bffba", "init_script": "", "metadata": [], "motd_file": null, @@ -35,7 +35,7 @@ "shutdown_script": null, "startup_script": null, "startup_script_behavior": "non-blocking", - "token": "6c4915dd-1d22-42c7-b14c-f0369d570096", + "token": "05f05235-a62b-4634-841b-da7fe3763e2e", "troubleshooting_url": null }, "sensitive_values": { @@ -54,8 +54,8 @@ "provider_name": "registry.terraform.io/coder/coder", "schema_version": 0, "values": { - "agent_id": "26597111-8ebc-4949-90b7-2722007692c7", - "id": "119683f2-fe7d-4823-aced-0044dafb96f0", + "agent_id": "0b84fffb-d2ca-4048-bdab-7b84229bffba", + "id": "7d6e9d00-4cf9-4a38-9b4b-1eb6ba98b50c", "instance_id": "example" }, "sensitive_values": {}, @@ -71,7 +71,7 @@ "provider_name": "registry.terraform.io/hashicorp/null", "schema_version": 0, "values": { - "id": "4260132288485152121", + "id": "446414716532401482", "triggers": null }, "sensitive_values": {}, diff --git a/provisioner/terraform/testdata/mapped-apps/mapped-apps.tfplan.json b/provisioner/terraform/testdata/mapped-apps/mapped-apps.tfplan.json index b7ea8fafc508c..dfcf3ccc7b52f 100644 --- a/provisioner/terraform/testdata/mapped-apps/mapped-apps.tfplan.json +++ b/provisioner/terraform/testdata/mapped-apps/mapped-apps.tfplan.json @@ -1,6 +1,6 @@ { "format_version": "1.2", - "terraform_version": "1.9.8", + "terraform_version": "1.10.5", "planned_values": { "root_module": { "resources": [ @@ -321,7 +321,7 @@ ] } ], - "timestamp": "2025-02-18T18:21:16Z", + "timestamp": "2025-02-18T10:58:12Z", "applyable": true, "complete": true, "errored": false diff --git a/provisioner/terraform/testdata/mapped-apps/mapped-apps.tfstate.json b/provisioner/terraform/testdata/mapped-apps/mapped-apps.tfstate.json index bf794aa4b7fab..ae0acf1650825 100644 --- a/provisioner/terraform/testdata/mapped-apps/mapped-apps.tfstate.json +++ b/provisioner/terraform/testdata/mapped-apps/mapped-apps.tfstate.json @@ -1,6 +1,6 @@ { "format_version": "1.0", - "terraform_version": "1.9.8", + "terraform_version": "1.10.5", "values": { "root_module": { "resources": [ @@ -26,7 +26,7 @@ } ], "env": null, - "id": "23443da2-bde9-4591-839f-456da45f8189", + "id": "4b66f4b5-d235-4c57-8b50-7db3643f8070", "init_script": "", "metadata": [], "motd_file": null, @@ -35,7 +35,7 @@ "shutdown_script": null, "startup_script": null, "startup_script_behavior": "non-blocking", - "token": "d4b3676c-fa3c-4f4f-88cf-fe93f72383ab", + "token": "a39963f7-3429-453f-b23f-961aa3590f06", "troubleshooting_url": null }, "sensitive_values": { @@ -55,14 +55,14 @@ "provider_name": "registry.terraform.io/coder/coder", "schema_version": 1, "values": { - "agent_id": "23443da2-bde9-4591-839f-456da45f8189", + "agent_id": "4b66f4b5-d235-4c57-8b50-7db3643f8070", "command": null, "display_name": "app1", "external": false, "healthcheck": [], "hidden": false, "icon": null, - "id": "474ac80e-7675-4055-9598-b1295acb7c12", + "id": "e67b9091-a454-42ce-85ee-df929f716c4f", "open_in": "slim-window", "order": null, "share": "owner", @@ -86,14 +86,14 @@ "provider_name": "registry.terraform.io/coder/coder", "schema_version": 1, "values": { - "agent_id": "23443da2-bde9-4591-839f-456da45f8189", + "agent_id": "4b66f4b5-d235-4c57-8b50-7db3643f8070", "command": null, "display_name": "app2", "external": false, "healthcheck": [], "hidden": false, "icon": null, - "id": "1290cc75-0ef0-4740-a29c-d96e170e647d", + "id": "84db109a-484c-42cc-b428-866458a99964", "open_in": "slim-window", "order": null, "share": "owner", @@ -116,7 +116,7 @@ "provider_name": "registry.terraform.io/hashicorp/null", "schema_version": 0, "values": { - "id": "5053475313220856922", + "id": "800496923164467286", "triggers": null }, "sensitive_values": {}, diff --git a/provisioner/terraform/testdata/multiple-agents-multiple-apps/multiple-agents-multiple-apps.tfplan.json b/provisioner/terraform/testdata/multiple-agents-multiple-apps/multiple-agents-multiple-apps.tfplan.json index 9b659107549d6..4ba8c29b7fa77 100644 --- a/provisioner/terraform/testdata/multiple-agents-multiple-apps/multiple-agents-multiple-apps.tfplan.json +++ b/provisioner/terraform/testdata/multiple-agents-multiple-apps/multiple-agents-multiple-apps.tfplan.json @@ -1,6 +1,6 @@ { "format_version": "1.2", - "terraform_version": "1.9.8", + "terraform_version": "1.10.5", "planned_values": { "root_module": { "resources": [ @@ -575,7 +575,7 @@ ] } ], - "timestamp": "2025-02-18T18:21:16Z", + "timestamp": "2025-02-18T10:58:12Z", "applyable": true, "complete": true, "errored": false diff --git a/provisioner/terraform/testdata/multiple-agents-multiple-apps/multiple-agents-multiple-apps.tfstate.json b/provisioner/terraform/testdata/multiple-agents-multiple-apps/multiple-agents-multiple-apps.tfstate.json index a016997dd9bf8..7ffb9866b4c48 100644 --- a/provisioner/terraform/testdata/multiple-agents-multiple-apps/multiple-agents-multiple-apps.tfstate.json +++ b/provisioner/terraform/testdata/multiple-agents-multiple-apps/multiple-agents-multiple-apps.tfstate.json @@ -1,6 +1,6 @@ { "format_version": "1.0", - "terraform_version": "1.9.8", + "terraform_version": "1.10.5", "values": { "root_module": { "resources": [ @@ -26,7 +26,7 @@ } ], "env": null, - "id": "b228504c-ad73-4c53-933c-c232043849b3", + "id": "9ba3ef14-bb43-4470-b019-129bf16eb0b2", "init_script": "", "metadata": [], "motd_file": null, @@ -35,7 +35,7 @@ "shutdown_script": null, "startup_script": null, "startup_script_behavior": "non-blocking", - "token": "bc9f8c02-f208-48de-9114-93f58e1ebc58", + "token": "b40bdbf8-bf41-4822-a71e-03016079ddbe", "troubleshooting_url": null }, "sensitive_values": { @@ -68,7 +68,7 @@ } ], "env": null, - "id": "46fa750a-1796-4db4-a242-06e9cd95f0e2", + "id": "959048f4-3f1d-4cb0-93da-1dfacdbb7976", "init_script": "", "metadata": [], "motd_file": null, @@ -77,7 +77,7 @@ "shutdown_script": null, "startup_script": null, "startup_script_behavior": "non-blocking", - "token": "91722f85-db71-4d9c-9e24-fd04ab44e4fb", + "token": "71ef9752-9257-478c-bf5e-c6713a9f5073", "troubleshooting_url": null }, "sensitive_values": { @@ -96,14 +96,14 @@ "provider_name": "registry.terraform.io/coder/coder", "schema_version": 1, "values": { - "agent_id": "b228504c-ad73-4c53-933c-c232043849b3", + "agent_id": "9ba3ef14-bb43-4470-b019-129bf16eb0b2", "command": null, "display_name": null, "external": false, "healthcheck": [], "hidden": false, "icon": null, - "id": "ad43457a-d53e-4858-af1c-8ac6b1f7e68e", + "id": "f125297a-130c-4c29-a1bf-905f95841fff", "open_in": "slim-window", "order": null, "share": "owner", @@ -126,7 +126,7 @@ "provider_name": "registry.terraform.io/coder/coder", "schema_version": 1, "values": { - "agent_id": "b228504c-ad73-4c53-933c-c232043849b3", + "agent_id": "9ba3ef14-bb43-4470-b019-129bf16eb0b2", "command": null, "display_name": null, "external": false, @@ -139,7 +139,7 @@ ], "hidden": false, "icon": null, - "id": "0d7a6598-0402-41c7-9e3a-934633f37e43", + "id": "687e66e5-4888-417d-8fbd-263764dc5011", "open_in": "slim-window", "order": null, "share": "owner", @@ -164,14 +164,14 @@ "provider_name": "registry.terraform.io/coder/coder", "schema_version": 1, "values": { - "agent_id": "46fa750a-1796-4db4-a242-06e9cd95f0e2", + "agent_id": "959048f4-3f1d-4cb0-93da-1dfacdbb7976", "command": null, "display_name": null, "external": false, "healthcheck": [], "hidden": false, "icon": null, - "id": "2e9fab10-5707-4150-811d-76debaca9cc2", + "id": "70f10886-fa90-4089-b290-c2d44c5073ae", "open_in": "slim-window", "order": null, "share": "owner", @@ -194,7 +194,7 @@ "provider_name": "registry.terraform.io/hashicorp/null", "schema_version": 0, "values": { - "id": "5260983662585355730", + "id": "1056762545519872704", "triggers": null }, "sensitive_values": {}, @@ -210,7 +210,7 @@ "provider_name": "registry.terraform.io/hashicorp/null", "schema_version": 0, "values": { - "id": "9030448048834232915", + "id": "784993046206959042", "triggers": null }, "sensitive_values": {}, diff --git a/provisioner/terraform/testdata/multiple-agents-multiple-envs/multiple-agents-multiple-envs.tfplan.json b/provisioner/terraform/testdata/multiple-agents-multiple-envs/multiple-agents-multiple-envs.tfplan.json index 22cf85bab1640..7fe81435861e4 100644 --- a/provisioner/terraform/testdata/multiple-agents-multiple-envs/multiple-agents-multiple-envs.tfplan.json +++ b/provisioner/terraform/testdata/multiple-agents-multiple-envs/multiple-agents-multiple-envs.tfplan.json @@ -1,6 +1,6 @@ { "format_version": "1.2", - "terraform_version": "1.9.8", + "terraform_version": "1.10.5", "planned_values": { "root_module": { "resources": [ @@ -472,7 +472,7 @@ ] } ], - "timestamp": "2025-02-18T18:21:16Z", + "timestamp": "2025-02-18T10:58:12Z", "applyable": true, "complete": true, "errored": false diff --git a/provisioner/terraform/testdata/multiple-agents-multiple-envs/multiple-agents-multiple-envs.tfstate.json b/provisioner/terraform/testdata/multiple-agents-multiple-envs/multiple-agents-multiple-envs.tfstate.json index 7dd7fc0036665..f7801ad37220c 100644 --- a/provisioner/terraform/testdata/multiple-agents-multiple-envs/multiple-agents-multiple-envs.tfstate.json +++ b/provisioner/terraform/testdata/multiple-agents-multiple-envs/multiple-agents-multiple-envs.tfstate.json @@ -1,6 +1,6 @@ { "format_version": "1.0", - "terraform_version": "1.9.8", + "terraform_version": "1.10.5", "values": { "root_module": { "resources": [ @@ -26,7 +26,7 @@ } ], "env": null, - "id": "b2eb9a49-7e85-46b3-883b-cad8032817b9", + "id": "5494b9d3-a230-41a4-8f50-be69397ab4cf", "init_script": "", "metadata": [], "motd_file": null, @@ -35,7 +35,7 @@ "shutdown_script": null, "startup_script": null, "startup_script_behavior": "non-blocking", - "token": "c076688b-1d3b-49e1-bc6a-e141373a18c1", + "token": "84f93622-75a4-4bf1-b806-b981066d4870", "troubleshooting_url": null }, "sensitive_values": { @@ -68,7 +68,7 @@ } ], "env": null, - "id": "0d10329b-746e-44e2-bd67-8b2328347f06", + "id": "a4cb672c-020b-4729-b451-c7fabba4669c", "init_script": "", "metadata": [], "motd_file": null, @@ -77,7 +77,7 @@ "shutdown_script": null, "startup_script": null, "startup_script_behavior": "non-blocking", - "token": "68db82bf-2be6-4309-8b59-25df9a89a806", + "token": "2861b097-2ea6-4c3a-a64c-5a726b9e3700", "troubleshooting_url": null }, "sensitive_values": { @@ -96,8 +96,8 @@ "provider_name": "registry.terraform.io/coder/coder", "schema_version": 1, "values": { - "agent_id": "b2eb9a49-7e85-46b3-883b-cad8032817b9", - "id": "1488081e-64f1-4b99-9490-4311b9d6cb88", + "agent_id": "5494b9d3-a230-41a4-8f50-be69397ab4cf", + "id": "4ec31abd-b84a-45b6-80bd-c78eecf387f1", "name": "ENV_1", "value": "Env 1" }, @@ -114,8 +114,8 @@ "provider_name": "registry.terraform.io/coder/coder", "schema_version": 1, "values": { - "agent_id": "b2eb9a49-7e85-46b3-883b-cad8032817b9", - "id": "1479b961-3e81-4bb4-9f84-b03ea79631ac", + "agent_id": "5494b9d3-a230-41a4-8f50-be69397ab4cf", + "id": "c0f4dac3-2b1a-4903-a0f1-2743f2000f1b", "name": "ENV_2", "value": "Env 2" }, @@ -132,8 +132,8 @@ "provider_name": "registry.terraform.io/coder/coder", "schema_version": 1, "values": { - "agent_id": "0d10329b-746e-44e2-bd67-8b2328347f06", - "id": "85aeb657-7581-4f70-9849-bec5d8b8f396", + "agent_id": "a4cb672c-020b-4729-b451-c7fabba4669c", + "id": "e0ccf967-d767-4077-b521-20132af3217a", "name": "ENV_3", "value": "Env 3" }, @@ -150,7 +150,7 @@ "provider_name": "registry.terraform.io/hashicorp/null", "schema_version": 0, "values": { - "id": "4160244480026169609", + "id": "7748417950448815454", "triggers": null }, "sensitive_values": {}, @@ -166,7 +166,7 @@ "provider_name": "registry.terraform.io/hashicorp/null", "schema_version": 0, "values": { - "id": "9212471919710672321", + "id": "1466092153882814278", "triggers": null }, "sensitive_values": {}, diff --git a/provisioner/terraform/testdata/multiple-agents-multiple-monitors/multiple-agents-multiple-monitors.tfplan.json b/provisioner/terraform/testdata/multiple-agents-multiple-monitors/multiple-agents-multiple-monitors.tfplan.json index 6252194bfeb0a..b5481b4c89463 100644 --- a/provisioner/terraform/testdata/multiple-agents-multiple-monitors/multiple-agents-multiple-monitors.tfplan.json +++ b/provisioner/terraform/testdata/multiple-agents-multiple-monitors/multiple-agents-multiple-monitors.tfplan.json @@ -1,6 +1,6 @@ { "format_version": "1.2", - "terraform_version": "1.9.8", + "terraform_version": "1.10.5", "planned_values": { "root_module": { "resources": [ @@ -618,7 +618,7 @@ ] } ], - "timestamp": "2025-02-18T18:21:17Z", + "timestamp": "2025-02-18T10:58:12Z", "applyable": true, "complete": true, "errored": false diff --git a/provisioner/terraform/testdata/multiple-agents-multiple-monitors/multiple-agents-multiple-monitors.tfstate.json b/provisioner/terraform/testdata/multiple-agents-multiple-monitors/multiple-agents-multiple-monitors.tfstate.json index e78fba716b9c3..85ef0a7ccddad 100644 --- a/provisioner/terraform/testdata/multiple-agents-multiple-monitors/multiple-agents-multiple-monitors.tfstate.json +++ b/provisioner/terraform/testdata/multiple-agents-multiple-monitors/multiple-agents-multiple-monitors.tfstate.json @@ -1,6 +1,6 @@ { "format_version": "1.0", - "terraform_version": "1.9.8", + "terraform_version": "1.10.5", "values": { "root_module": { "resources": [ @@ -26,7 +26,7 @@ } ], "env": null, - "id": "1e66fd1b-d220-4f86-b30c-32a9866c33d0", + "id": "9c36f8be-874a-40f6-a395-f37d6d910a83", "init_script": "", "metadata": [], "motd_file": null, @@ -46,7 +46,7 @@ "shutdown_script": null, "startup_script": null, "startup_script_behavior": "non-blocking", - "token": "9f0bba2e-9c55-49f0-88cb-5a2a79d96540", + "token": "1bed5f78-a309-4049-9805-b5f52a17306d", "troubleshooting_url": null }, "sensitive_values": { @@ -87,7 +87,7 @@ } ], "env": null, - "id": "8e35ccdd-d7ba-4a51-8466-32eda77d9283", + "id": "23009046-30ce-40d4-81f4-f8e7726335a5", "init_script": "", "metadata": [], "motd_file": null, @@ -118,7 +118,7 @@ "shutdown_script": null, "startup_script": null, "startup_script_behavior": "non-blocking", - "token": "ea281836-1a0e-4eca-a599-236c08a333b4", + "token": "3d40e367-25e5-43a3-8b7a-8528b31edbbd", "troubleshooting_url": null }, "sensitive_values": { @@ -148,14 +148,14 @@ "provider_name": "registry.terraform.io/coder/coder", "schema_version": 1, "values": { - "agent_id": "1e66fd1b-d220-4f86-b30c-32a9866c33d0", + "agent_id": "9c36f8be-874a-40f6-a395-f37d6d910a83", "command": null, "display_name": null, "external": false, "healthcheck": [], "hidden": false, "icon": null, - "id": "32b7f2f8-ca27-4ddd-94dd-6d8ef8f6cfba", + "id": "c8ff409a-d30d-4e62-a5a1-771f90d712ca", "open_in": "slim-window", "order": null, "share": "owner", @@ -178,7 +178,7 @@ "provider_name": "registry.terraform.io/coder/coder", "schema_version": 1, "values": { - "agent_id": "1e66fd1b-d220-4f86-b30c-32a9866c33d0", + "agent_id": "9c36f8be-874a-40f6-a395-f37d6d910a83", "command": null, "display_name": null, "external": false, @@ -191,7 +191,7 @@ ], "hidden": false, "icon": null, - "id": "3ef9f58a-8a2f-4be7-8134-c1ad6089f9e2", + "id": "23c1f02f-cc1a-4e64-b64f-dc2294781c14", "open_in": "slim-window", "order": null, "share": "owner", @@ -216,7 +216,7 @@ "provider_name": "registry.terraform.io/hashicorp/null", "schema_version": 0, "values": { - "id": "3176283506982774871", + "id": "4679211063326469519", "triggers": null }, "sensitive_values": {}, diff --git a/provisioner/terraform/testdata/multiple-agents-multiple-scripts/multiple-agents-multiple-scripts.tfplan.json b/provisioner/terraform/testdata/multiple-agents-multiple-scripts/multiple-agents-multiple-scripts.tfplan.json index dd9ed0d4e6e39..628c97c8563ff 100644 --- a/provisioner/terraform/testdata/multiple-agents-multiple-scripts/multiple-agents-multiple-scripts.tfplan.json +++ b/provisioner/terraform/testdata/multiple-agents-multiple-scripts/multiple-agents-multiple-scripts.tfplan.json @@ -1,6 +1,6 @@ { "format_version": "1.2", - "terraform_version": "1.9.8", + "terraform_version": "1.10.5", "planned_values": { "root_module": { "resources": [ @@ -523,7 +523,7 @@ ] } ], - "timestamp": "2025-02-18T18:21:16Z", + "timestamp": "2025-02-18T10:58:12Z", "applyable": true, "complete": true, "errored": false diff --git a/provisioner/terraform/testdata/multiple-agents-multiple-scripts/multiple-agents-multiple-scripts.tfstate.json b/provisioner/terraform/testdata/multiple-agents-multiple-scripts/multiple-agents-multiple-scripts.tfstate.json index b228b10384554..918dccb57bd11 100644 --- a/provisioner/terraform/testdata/multiple-agents-multiple-scripts/multiple-agents-multiple-scripts.tfstate.json +++ b/provisioner/terraform/testdata/multiple-agents-multiple-scripts/multiple-agents-multiple-scripts.tfstate.json @@ -1,6 +1,6 @@ { "format_version": "1.0", - "terraform_version": "1.9.8", + "terraform_version": "1.10.5", "values": { "root_module": { "resources": [ @@ -26,7 +26,7 @@ } ], "env": null, - "id": "08227630-d8d8-44a6-8d1a-c6b4e56220e6", + "id": "56eebdd7-8348-439a-8ee9-3cd9a4967479", "init_script": "", "metadata": [], "motd_file": null, @@ -35,7 +35,7 @@ "shutdown_script": null, "startup_script": null, "startup_script_behavior": "non-blocking", - "token": "9e5b296e-3ce0-4cd8-af7d-8d702c96516e", + "token": "bc6f97e3-265d-49e9-b08b-e2bc38736da0", "troubleshooting_url": null }, "sensitive_values": { @@ -68,7 +68,7 @@ } ], "env": null, - "id": "2b0d2ea6-b448-4c31-a95d-163475818d8e", + "id": "36b8da5b-7a03-4da7-a081-f4ae599d7302", "init_script": "", "metadata": [], "motd_file": null, @@ -77,7 +77,7 @@ "shutdown_script": null, "startup_script": null, "startup_script_behavior": "non-blocking", - "token": "81c60ec1-67f0-44d3-82af-41599fad84e1", + "token": "fa30098e-d8d2-4dad-87ad-3e0a328d2084", "troubleshooting_url": null }, "sensitive_values": { @@ -96,11 +96,11 @@ "provider_name": "registry.terraform.io/coder/coder", "schema_version": 1, "values": { - "agent_id": "08227630-d8d8-44a6-8d1a-c6b4e56220e6", + "agent_id": "56eebdd7-8348-439a-8ee9-3cd9a4967479", "cron": null, "display_name": "Foobar Script 1", "icon": null, - "id": "4350804c-b8b5-45c8-994e-8f7020b41b1c", + "id": "29d2f25b-f774-4bb8-9ef4-9aa03a4b3765", "log_path": null, "run_on_start": true, "run_on_stop": false, @@ -121,11 +121,11 @@ "provider_name": "registry.terraform.io/coder/coder", "schema_version": 1, "values": { - "agent_id": "08227630-d8d8-44a6-8d1a-c6b4e56220e6", + "agent_id": "56eebdd7-8348-439a-8ee9-3cd9a4967479", "cron": null, "display_name": "Foobar Script 2", "icon": null, - "id": "3b449c9e-48ab-4e7b-aa46-dd488ce1284c", + "id": "7e7a2376-3028-493c-8ce1-665efd6c5d9c", "log_path": null, "run_on_start": true, "run_on_stop": false, @@ -146,11 +146,11 @@ "provider_name": "registry.terraform.io/coder/coder", "schema_version": 1, "values": { - "agent_id": "2b0d2ea6-b448-4c31-a95d-163475818d8e", + "agent_id": "36b8da5b-7a03-4da7-a081-f4ae599d7302", "cron": null, "display_name": "Foobar Script 3", "icon": null, - "id": "2132fa1c-d2e9-4229-983f-2dfca88da420", + "id": "c6c46bde-7eff-462b-805b-82597a8095d2", "log_path": null, "run_on_start": true, "run_on_stop": false, @@ -171,7 +171,7 @@ "provider_name": "registry.terraform.io/hashicorp/null", "schema_version": 0, "values": { - "id": "6203386614814118800", + "id": "3047178084751259009", "triggers": null }, "sensitive_values": {}, @@ -187,7 +187,7 @@ "provider_name": "registry.terraform.io/hashicorp/null", "schema_version": 0, "values": { - "id": "3432231377698621412", + "id": "6983265822377125070", "triggers": null }, "sensitive_values": {}, diff --git a/provisioner/terraform/testdata/multiple-agents/multiple-agents.tfplan.json b/provisioner/terraform/testdata/multiple-agents/multiple-agents.tfplan.json index bfbdabe595cc8..bf0bd8b21d340 100644 --- a/provisioner/terraform/testdata/multiple-agents/multiple-agents.tfplan.json +++ b/provisioner/terraform/testdata/multiple-agents/multiple-agents.tfplan.json @@ -1,6 +1,6 @@ { "format_version": "1.2", - "terraform_version": "1.9.8", + "terraform_version": "1.10.5", "planned_values": { "root_module": { "resources": [ @@ -431,7 +431,7 @@ ] } }, - "timestamp": "2025-02-18T18:21:16Z", + "timestamp": "2025-02-18T10:58:12Z", "applyable": true, "complete": true, "errored": false diff --git a/provisioner/terraform/testdata/multiple-agents/multiple-agents.tfstate.json b/provisioner/terraform/testdata/multiple-agents/multiple-agents.tfstate.json index 92835a1ab8f2c..71987deb178cc 100644 --- a/provisioner/terraform/testdata/multiple-agents/multiple-agents.tfstate.json +++ b/provisioner/terraform/testdata/multiple-agents/multiple-agents.tfstate.json @@ -1,6 +1,6 @@ { "format_version": "1.0", - "terraform_version": "1.9.8", + "terraform_version": "1.10.5", "values": { "root_module": { "resources": [ @@ -26,7 +26,7 @@ } ], "env": null, - "id": "a8594294-4a4c-4e78-95b2-569e9c050b60", + "id": "f65fcb62-ef69-44e8-b8eb-56224c9e9d6f", "init_script": "", "metadata": [], "motd_file": null, @@ -35,7 +35,7 @@ "shutdown_script": null, "startup_script": null, "startup_script_behavior": "non-blocking", - "token": "4d6a9b4d-52f1-4243-b2b9-4d5a4f96f4bf", + "token": "57047ef7-1433-4938-a604-4dd2812b1039", "troubleshooting_url": null }, "sensitive_values": { @@ -68,7 +68,7 @@ } ], "env": null, - "id": "4724838a-a88e-45ea-a7ac-ee70a653cbfb", + "id": "d366a56f-2899-4e96-b0a1-3e97ac9bd834", "init_script": "", "metadata": [], "motd_file": "/etc/motd", @@ -77,7 +77,7 @@ "shutdown_script": "echo bye bye", "startup_script": null, "startup_script_behavior": "non-blocking", - "token": "d579f2f2-db06-4fbc-9a8f-6d075d01e645", + "token": "59a6c328-d6ac-450d-a507-de6c14cb16d0", "troubleshooting_url": null }, "sensitive_values": { @@ -110,7 +110,7 @@ } ], "env": null, - "id": "349ebae6-324b-404a-a3b7-1a81c727a490", + "id": "907bbf6b-fa77-4138-a348-ef5d0fb98b15", "init_script": "", "metadata": [], "motd_file": null, @@ -119,7 +119,7 @@ "shutdown_script": null, "startup_script": null, "startup_script_behavior": "blocking", - "token": "0647e08f-8661-4d3b-8789-cccdcf3263e3", + "token": "7f0bb618-c82a-491b-891a-6d9f3abeeca0", "troubleshooting_url": "https://coder.com/troubleshoot" }, "sensitive_values": { @@ -152,7 +152,7 @@ } ], "env": null, - "id": "2309f077-2c30-497b-813b-bd0bba5c1bc3", + "id": "e9b11e47-0238-4915-9539-ac06617f3398", "init_script": "", "metadata": [], "motd_file": null, @@ -161,7 +161,7 @@ "shutdown_script": null, "startup_script": null, "startup_script_behavior": "non-blocking", - "token": "b29e6471-68b5-41e8-a3c8-3192baab26c7", + "token": "102a2043-9a42-4490-b0b4-c4fb215552e0", "troubleshooting_url": null }, "sensitive_values": { @@ -180,7 +180,7 @@ "provider_name": "registry.terraform.io/hashicorp/null", "schema_version": 0, "values": { - "id": "1888190210657376001", + "id": "2948336473894256689", "triggers": null }, "sensitive_values": {}, diff --git a/provisioner/terraform/testdata/multiple-apps/multiple-apps.tfplan.json b/provisioner/terraform/testdata/multiple-apps/multiple-apps.tfplan.json index d6005bbc52040..3f18f84cf30ec 100644 --- a/provisioner/terraform/testdata/multiple-apps/multiple-apps.tfplan.json +++ b/provisioner/terraform/testdata/multiple-apps/multiple-apps.tfplan.json @@ -1,6 +1,6 @@ { "format_version": "1.2", - "terraform_version": "1.9.8", + "terraform_version": "1.10.5", "planned_values": { "root_module": { "resources": [ @@ -440,7 +440,7 @@ ] } ], - "timestamp": "2025-02-18T18:21:16Z", + "timestamp": "2025-02-18T10:58:12Z", "applyable": true, "complete": true, "errored": false diff --git a/provisioner/terraform/testdata/multiple-apps/multiple-apps.tfstate.json b/provisioner/terraform/testdata/multiple-apps/multiple-apps.tfstate.json index 63056d3ef93e8..9a21887d3ed4b 100644 --- a/provisioner/terraform/testdata/multiple-apps/multiple-apps.tfstate.json +++ b/provisioner/terraform/testdata/multiple-apps/multiple-apps.tfstate.json @@ -1,6 +1,6 @@ { "format_version": "1.0", - "terraform_version": "1.9.8", + "terraform_version": "1.10.5", "values": { "root_module": { "resources": [ @@ -26,7 +26,7 @@ } ], "env": null, - "id": "623b33e1-6c61-4daf-b6b7-ac953454047f", + "id": "e7f1e434-ad52-4175-b8d1-4fab9fbe7891", "init_script": "", "metadata": [], "motd_file": null, @@ -35,7 +35,7 @@ "shutdown_script": null, "startup_script": null, "startup_script_behavior": "non-blocking", - "token": "fc01cd68-f043-4530-a889-561b47f3ad98", + "token": "da1c4966-5bb7-459e-8b7e-ce1cf189e49d", "troubleshooting_url": null }, "sensitive_values": { @@ -54,14 +54,14 @@ "provider_name": "registry.terraform.io/coder/coder", "schema_version": 1, "values": { - "agent_id": "623b33e1-6c61-4daf-b6b7-ac953454047f", + "agent_id": "e7f1e434-ad52-4175-b8d1-4fab9fbe7891", "command": null, "display_name": null, "external": false, "healthcheck": [], "hidden": false, "icon": null, - "id": "3f23d7ed-6677-4eec-b9dc-d7fdb7c64dee", + "id": "41882acb-ad8c-4436-a756-e55160e2eba7", "open_in": "slim-window", "order": null, "share": "owner", @@ -84,7 +84,7 @@ "provider_name": "registry.terraform.io/coder/coder", "schema_version": 1, "values": { - "agent_id": "623b33e1-6c61-4daf-b6b7-ac953454047f", + "agent_id": "e7f1e434-ad52-4175-b8d1-4fab9fbe7891", "command": null, "display_name": null, "external": false, @@ -97,7 +97,7 @@ ], "hidden": false, "icon": null, - "id": "182cbdc1-246b-4b71-aa0b-4b5918e56d87", + "id": "28fb460e-746b-47b9-8c88-fc546f2ca6c4", "open_in": "slim-window", "order": null, "share": "owner", @@ -122,14 +122,14 @@ "provider_name": "registry.terraform.io/coder/coder", "schema_version": 1, "values": { - "agent_id": "623b33e1-6c61-4daf-b6b7-ac953454047f", + "agent_id": "e7f1e434-ad52-4175-b8d1-4fab9fbe7891", "command": null, "display_name": null, "external": false, "healthcheck": [], "hidden": false, "icon": null, - "id": "8862fa5e-846b-4fba-a5d9-892060809c1c", + "id": "2751d89f-6c41-4b50-9982-9270ba0660b0", "open_in": "slim-window", "order": null, "share": "owner", @@ -152,7 +152,7 @@ "provider_name": "registry.terraform.io/hashicorp/null", "schema_version": 0, "values": { - "id": "6057067911545137976", + "id": "1493563047742372481", "triggers": null }, "sensitive_values": {}, diff --git a/provisioner/terraform/testdata/resource-metadata-duplicate/resource-metadata-duplicate.tfplan.json b/provisioner/terraform/testdata/resource-metadata-duplicate/resource-metadata-duplicate.tfplan.json index a5138f9c49f24..078f6a63738f8 100644 --- a/provisioner/terraform/testdata/resource-metadata-duplicate/resource-metadata-duplicate.tfplan.json +++ b/provisioner/terraform/testdata/resource-metadata-duplicate/resource-metadata-duplicate.tfplan.json @@ -1,6 +1,6 @@ { "format_version": "1.2", - "terraform_version": "1.9.8", + "terraform_version": "1.10.5", "planned_values": { "root_module": { "resources": [ @@ -426,7 +426,7 @@ ] } ], - "timestamp": "2025-02-18T18:21:16Z", + "timestamp": "2025-02-18T10:58:12Z", "applyable": true, "complete": true, "errored": false diff --git a/provisioner/terraform/testdata/resource-metadata-duplicate/resource-metadata-duplicate.tfstate.json b/provisioner/terraform/testdata/resource-metadata-duplicate/resource-metadata-duplicate.tfstate.json index f5b3827ee4b4e..79b8ec551eb4d 100644 --- a/provisioner/terraform/testdata/resource-metadata-duplicate/resource-metadata-duplicate.tfstate.json +++ b/provisioner/terraform/testdata/resource-metadata-duplicate/resource-metadata-duplicate.tfstate.json @@ -1,6 +1,6 @@ { "format_version": "1.0", - "terraform_version": "1.9.8", + "terraform_version": "1.10.5", "values": { "root_module": { "resources": [ @@ -26,7 +26,7 @@ } ], "env": null, - "id": "dabcdac4-9d40-4ed3-8331-9f5b29c88b5a", + "id": "febc1e16-503f-42c3-b1ab-b067d172a860", "init_script": "", "metadata": [ { @@ -44,7 +44,7 @@ "shutdown_script": null, "startup_script": null, "startup_script_behavior": "non-blocking", - "token": "7df37d19-71f4-4b8d-8ebb-9665787aff28", + "token": "2b609454-ea6a-4ec8-ba03-d305712894d1", "troubleshooting_url": null }, "sensitive_values": { @@ -68,7 +68,7 @@ "daily_cost": 29, "hide": true, "icon": "/icon/server.svg", - "id": "ed62b95e-6be8-4f94-a490-ea01e39c5a21", + "id": "0ea63fbe-3e81-4c34-9edc-c2b1ddc62c46", "item": [ { "is_null": false, @@ -83,7 +83,7 @@ "value": "" } ], - "resource_id": "1655456926645556376" + "resource_id": "856574543079218847" }, "sensitive_values": { "item": [ @@ -107,7 +107,7 @@ "daily_cost": 20, "hide": true, "icon": "/icon/server.svg", - "id": "1dc3e361-d9f8-44a1-8b95-1f8eb43147b6", + "id": "2a367f6b-b055-425c-bdc0-7c63cafdc146", "item": [ { "is_null": false, @@ -116,7 +116,7 @@ "value": "world" } ], - "resource_id": "1655456926645556376" + "resource_id": "856574543079218847" }, "sensitive_values": { "item": [ @@ -136,7 +136,7 @@ "provider_name": "registry.terraform.io/hashicorp/null", "schema_version": 0, "values": { - "id": "1655456926645556376", + "id": "856574543079218847", "triggers": null }, "sensitive_values": {}, diff --git a/provisioner/terraform/testdata/resource-metadata/resource-metadata.tfplan.json b/provisioner/terraform/testdata/resource-metadata/resource-metadata.tfplan.json index fd10694fb7599..f3f97e8b96897 100644 --- a/provisioner/terraform/testdata/resource-metadata/resource-metadata.tfplan.json +++ b/provisioner/terraform/testdata/resource-metadata/resource-metadata.tfplan.json @@ -1,6 +1,6 @@ { "format_version": "1.2", - "terraform_version": "1.9.8", + "terraform_version": "1.10.5", "planned_values": { "root_module": { "resources": [ @@ -378,7 +378,7 @@ ] } ], - "timestamp": "2025-02-18T18:21:16Z", + "timestamp": "2025-02-18T10:58:12Z", "applyable": true, "complete": true, "errored": false diff --git a/provisioner/terraform/testdata/resource-metadata/resource-metadata.tfstate.json b/provisioner/terraform/testdata/resource-metadata/resource-metadata.tfstate.json index 4b09a3d909406..5089c0b42e3e7 100644 --- a/provisioner/terraform/testdata/resource-metadata/resource-metadata.tfstate.json +++ b/provisioner/terraform/testdata/resource-metadata/resource-metadata.tfstate.json @@ -1,6 +1,6 @@ { "format_version": "1.0", - "terraform_version": "1.9.8", + "terraform_version": "1.10.5", "values": { "root_module": { "resources": [ @@ -26,7 +26,7 @@ } ], "env": null, - "id": "1f393aa3-fcce-4347-bcc1-8f0f832176fd", + "id": "bf7c9d15-6b61-4012-9cd8-10ba7ca9a4d8", "init_script": "", "metadata": [ { @@ -44,7 +44,7 @@ "shutdown_script": null, "startup_script": null, "startup_script_behavior": "non-blocking", - "token": "ab5174ea-1047-4476-be51-57e81ffdd8ca", + "token": "91d4aa20-db80-4404-a68c-a19abeb4a5b9", "troubleshooting_url": null }, "sensitive_values": { @@ -68,7 +68,7 @@ "daily_cost": 29, "hide": true, "icon": "/icon/server.svg", - "id": "83beec7e-d68b-4712-96f3-0825092425b1", + "id": "b96f5efa-fe45-4a6a-9bd2-70e2063b7b2a", "item": [ { "is_null": false, @@ -95,7 +95,7 @@ "value": "squirrel" } ], - "resource_id": "4369933318739720708" + "resource_id": "978725577783936679" }, "sensitive_values": { "item": [ @@ -118,7 +118,7 @@ "provider_name": "registry.terraform.io/hashicorp/null", "schema_version": 0, "values": { - "id": "4369933318739720708", + "id": "978725577783936679", "triggers": null }, "sensitive_values": {}, diff --git a/provisioner/terraform/testdata/rich-parameters-order/rich-parameters-order.tfplan.json b/provisioner/terraform/testdata/rich-parameters-order/rich-parameters-order.tfplan.json index 901fd71ae6d5f..46ac62ce6f09e 100644 --- a/provisioner/terraform/testdata/rich-parameters-order/rich-parameters-order.tfplan.json +++ b/provisioner/terraform/testdata/rich-parameters-order/rich-parameters-order.tfplan.json @@ -1,6 +1,6 @@ { "format_version": "1.2", - "terraform_version": "1.9.8", + "terraform_version": "1.10.5", "planned_values": { "root_module": { "resources": [ @@ -113,7 +113,7 @@ ], "prior_state": { "format_version": "1.0", - "terraform_version": "1.9.8", + "terraform_version": "1.10.5", "values": { "root_module": { "resources": [ @@ -130,7 +130,7 @@ "display_name": null, "ephemeral": false, "icon": null, - "id": "b1e652cd-eb2c-4c6d-bc9c-3add380ffbe1", + "id": "b106fb5a-0ab1-4530-8cc0-9ff9a515dff4", "mutable": false, "name": "Example", "option": null, @@ -157,7 +157,7 @@ "display_name": null, "ephemeral": false, "icon": null, - "id": "af5ae8c5-fc90-4a04-9014-1708984a7b27", + "id": "5b1c2605-c7a4-4248-bf92-b761e36e0111", "mutable": false, "name": "Sample", "option": null, @@ -263,7 +263,7 @@ ] } }, - "timestamp": "2025-02-18T18:21:16Z", + "timestamp": "2025-02-18T10:58:12Z", "applyable": true, "complete": true, "errored": false diff --git a/provisioner/terraform/testdata/rich-parameters-order/rich-parameters-order.tfstate.json b/provisioner/terraform/testdata/rich-parameters-order/rich-parameters-order.tfstate.json index 1f5505dbaa0ac..bade7edb803c5 100644 --- a/provisioner/terraform/testdata/rich-parameters-order/rich-parameters-order.tfstate.json +++ b/provisioner/terraform/testdata/rich-parameters-order/rich-parameters-order.tfstate.json @@ -1,6 +1,6 @@ { "format_version": "1.0", - "terraform_version": "1.9.8", + "terraform_version": "1.10.5", "values": { "root_module": { "resources": [ @@ -17,7 +17,7 @@ "display_name": null, "ephemeral": false, "icon": null, - "id": "5aeb4a3f-99e0-4e07-b8c5-b20a2ad82b80", + "id": "3f56c659-fe68-47c3-9765-cd09abe69de7", "mutable": false, "name": "Example", "option": null, @@ -44,7 +44,7 @@ "display_name": null, "ephemeral": false, "icon": null, - "id": "cd792a6d-6456-46b2-afed-4893930efcb6", + "id": "2ecde94b-399a-43c7-b50a-3603895aff83", "mutable": false, "name": "Sample", "option": null, @@ -80,7 +80,7 @@ } ], "env": null, - "id": "0a162a13-6c04-402b-b568-d18ca061b63c", + "id": "a2171da1-5f68-446f-97e3-1c2755552840", "init_script": "", "metadata": [], "motd_file": null, @@ -89,7 +89,7 @@ "shutdown_script": null, "startup_script": null, "startup_script_behavior": "non-blocking", - "token": "f15d5bd3-e9a3-40a0-8265-c2d7e46f841c", + "token": "a986f085-2697-4d95-a431-6545716ca36b", "troubleshooting_url": null }, "sensitive_values": { @@ -108,7 +108,7 @@ "provider_name": "registry.terraform.io/hashicorp/null", "schema_version": 0, "values": { - "id": "4854678966366130580", + "id": "5482122353677678043", "triggers": null }, "sensitive_values": {}, diff --git a/provisioner/terraform/testdata/rich-parameters-validation/rich-parameters-validation.tfplan.json b/provisioner/terraform/testdata/rich-parameters-validation/rich-parameters-validation.tfplan.json index 14b4604dd5574..1f7a216dc7a3f 100644 --- a/provisioner/terraform/testdata/rich-parameters-validation/rich-parameters-validation.tfplan.json +++ b/provisioner/terraform/testdata/rich-parameters-validation/rich-parameters-validation.tfplan.json @@ -1,6 +1,6 @@ { "format_version": "1.2", - "terraform_version": "1.9.8", + "terraform_version": "1.10.5", "planned_values": { "root_module": { "resources": [ @@ -113,7 +113,7 @@ ], "prior_state": { "format_version": "1.0", - "terraform_version": "1.9.8", + "terraform_version": "1.10.5", "values": { "root_module": { "resources": [ @@ -130,7 +130,7 @@ "display_name": null, "ephemeral": true, "icon": null, - "id": "5bb41b73-1b57-4054-82d6-a24e37f0e489", + "id": "65767637-5ffa-400f-be3f-f03868bd7070", "mutable": true, "name": "number_example", "option": null, @@ -157,7 +157,7 @@ "display_name": null, "ephemeral": false, "icon": null, - "id": "0906e50c-dae7-4a5f-b312-cc9acc58068b", + "id": "d8ee017a-1a92-43f2-aaa8-483573c08485", "mutable": false, "name": "number_example_max", "option": null, @@ -196,7 +196,7 @@ "display_name": null, "ephemeral": false, "icon": null, - "id": "86b42229-3aca-45f7-a815-986a42f75515", + "id": "1516f72d-71aa-4ae8-95b5-4dbcf999e173", "mutable": false, "name": "number_example_max_zero", "option": null, @@ -235,7 +235,7 @@ "display_name": null, "ephemeral": false, "icon": null, - "id": "9f920ec3-6c51-4264-bd95-ac6cdc2fce6b", + "id": "720ff4a2-4f26-42d5-a0f8-4e5c92b3133e", "mutable": false, "name": "number_example_min", "option": null, @@ -274,7 +274,7 @@ "display_name": null, "ephemeral": false, "icon": null, - "id": "9e89b197-3df0-46a8-925a-c523be8b38f7", + "id": "395bcef8-1f59-4a4f-b104-f0c4b6686193", "mutable": false, "name": "number_example_min_max", "option": null, @@ -313,7 +313,7 @@ "display_name": null, "ephemeral": false, "icon": null, - "id": "678a411a-91af-409e-b2aa-68e0cab28483", + "id": "29b2943d-e736-4635-a553-097ebe51e7ec", "mutable": false, "name": "number_example_min_zero", "option": null, @@ -545,7 +545,7 @@ ] } }, - "timestamp": "2025-02-18T18:21:16Z", + "timestamp": "2025-02-18T10:58:12Z", "applyable": true, "complete": true, "errored": false diff --git a/provisioner/terraform/testdata/rich-parameters-validation/rich-parameters-validation.tfstate.json b/provisioner/terraform/testdata/rich-parameters-validation/rich-parameters-validation.tfstate.json index fa86d8b2633a6..1580f18bb97d8 100644 --- a/provisioner/terraform/testdata/rich-parameters-validation/rich-parameters-validation.tfstate.json +++ b/provisioner/terraform/testdata/rich-parameters-validation/rich-parameters-validation.tfstate.json @@ -1,6 +1,6 @@ { "format_version": "1.0", - "terraform_version": "1.9.8", + "terraform_version": "1.10.5", "values": { "root_module": { "resources": [ @@ -17,7 +17,7 @@ "display_name": null, "ephemeral": true, "icon": null, - "id": "964932eb-2be8-4822-a0d4-38cc1259e01b", + "id": "35958620-8fa6-479e-b2aa-19202d594b03", "mutable": true, "name": "number_example", "option": null, @@ -44,7 +44,7 @@ "display_name": null, "ephemeral": false, "icon": null, - "id": "537335ac-ab4e-4a55-b5d9-48b005ec79e8", + "id": "518c5dad-6069-4c24-8e0b-1ee75a52da3b", "mutable": false, "name": "number_example_max", "option": null, @@ -83,7 +83,7 @@ "display_name": null, "ephemeral": false, "icon": null, - "id": "e127a1c4-3f28-4099-9fc1-ce3c5dd692b4", + "id": "050653a6-301b-4916-a871-32d007e1294d", "mutable": false, "name": "number_example_max_zero", "option": null, @@ -122,7 +122,7 @@ "display_name": null, "ephemeral": false, "icon": null, - "id": "51ab82c4-c8f7-4340-95bd-daf185c2943f", + "id": "4704cc0b-6c9d-422d-ba21-c488d780619e", "mutable": false, "name": "number_example_min", "option": null, @@ -161,7 +161,7 @@ "display_name": null, "ephemeral": false, "icon": null, - "id": "79d01b03-b0cf-4681-a73b-daf5ac609d4e", + "id": "a8575ac7-8cf3-4deb-a716-ab5a31467e0b", "mutable": false, "name": "number_example_min_max", "option": null, @@ -200,7 +200,7 @@ "display_name": null, "ephemeral": false, "icon": null, - "id": "c84de2b5-e02e-4a95-81bf-056f7b3ac9e4", + "id": "1efc1290-5939-401c-8287-7b8d6724cdb6", "mutable": false, "name": "number_example_min_zero", "option": null, @@ -248,7 +248,7 @@ } ], "env": null, - "id": "e1a0b1d6-c022-47df-8266-a1f825c95630", + "id": "356b8996-c71d-479a-b161-ac3828a1831e", "init_script": "", "metadata": [], "motd_file": null, @@ -257,7 +257,7 @@ "shutdown_script": null, "startup_script": null, "startup_script_behavior": "non-blocking", - "token": "40aa41d9-9b4d-4627-95cf-b0812ab7197a", + "token": "27611e1a-9de5-433b-81e4-cbd9f92dfe06", "troubleshooting_url": null }, "sensitive_values": { @@ -276,7 +276,7 @@ "provider_name": "registry.terraform.io/hashicorp/null", "schema_version": 0, "values": { - "id": "387589351868049923", + "id": "7456139785400247293", "triggers": null }, "sensitive_values": {}, diff --git a/provisioner/terraform/testdata/rich-parameters/rich-parameters.tfplan.json b/provisioner/terraform/testdata/rich-parameters/rich-parameters.tfplan.json index f810ee9e7abd8..e6b5b1cab49dd 100644 --- a/provisioner/terraform/testdata/rich-parameters/rich-parameters.tfplan.json +++ b/provisioner/terraform/testdata/rich-parameters/rich-parameters.tfplan.json @@ -1,6 +1,6 @@ { "format_version": "1.2", - "terraform_version": "1.9.8", + "terraform_version": "1.10.5", "planned_values": { "root_module": { "resources": [ @@ -113,7 +113,7 @@ ], "prior_state": { "format_version": "1.0", - "terraform_version": "1.9.8", + "terraform_version": "1.10.5", "values": { "root_module": { "resources": [ @@ -130,7 +130,7 @@ "display_name": null, "ephemeral": false, "icon": null, - "id": "52b500fb-d625-4ed7-a621-2d601dcef852", + "id": "14d20380-9100-4218-afca-15d066dec134", "mutable": false, "name": "Example", "option": [ @@ -174,7 +174,7 @@ "display_name": null, "ephemeral": false, "icon": null, - "id": "d9a89304-4ca4-48ab-aa1d-dd862a79f615", + "id": "fec66abe-d831-4095-8520-8a654ccf309a", "mutable": false, "name": "number_example", "option": null, @@ -201,7 +201,7 @@ "display_name": null, "ephemeral": false, "icon": null, - "id": "17ea5d4a-248f-4b9f-a645-afef54a4f5a0", + "id": "9e6cbf84-b49c-4c24-ad71-91195269ec84", "mutable": false, "name": "number_example_max_zero", "option": null, @@ -240,7 +240,7 @@ "display_name": null, "ephemeral": false, "icon": null, - "id": "eb1a6901-fb90-43f1-b573-509fde663d32", + "id": "5fbb470c-3814-4706-8fa6-c8c7e0f04c19", "mutable": false, "name": "number_example_min_max", "option": null, @@ -279,7 +279,7 @@ "display_name": null, "ephemeral": false, "icon": null, - "id": "7be51b9c-dc6e-4066-a57f-c169895080aa", + "id": "3790d994-f401-4e98-ad73-70b6f4e577d2", "mutable": false, "name": "number_example_min_zero", "option": null, @@ -318,7 +318,7 @@ "display_name": null, "ephemeral": false, "icon": null, - "id": "e8fb9b8b-9d14-4b87-9ec1-d5796a6c7d36", + "id": "26b3faa6-2eda-45f0-abbe-f4aba303f7cc", "mutable": false, "name": "Sample", "option": null, @@ -349,7 +349,7 @@ "display_name": null, "ephemeral": false, "icon": null, - "id": "9f121174-a611-47b6-9b1e-a03bd5c023d5", + "id": "6027c1aa-dae9-48d9-90f2-b66151bf3129", "mutable": true, "name": "First parameter from module", "option": null, @@ -376,7 +376,7 @@ "display_name": null, "ephemeral": false, "icon": null, - "id": "c41b68b8-f8b8-4d82-b259-6cab2a62f5ae", + "id": "62262115-184d-4e14-a756-bedb553405a9", "mutable": true, "name": "Second parameter from module", "option": null, @@ -408,7 +408,7 @@ "display_name": null, "ephemeral": false, "icon": null, - "id": "6bf5db78-d787-46c4-a36f-f1c1b479206f", + "id": "9ced5a2a-0e83-44fe-8088-6db4df59c15e", "mutable": true, "name": "First parameter from child module", "option": null, @@ -435,7 +435,7 @@ "display_name": null, "ephemeral": false, "icon": null, - "id": "30db357f-b819-4db0-ba3a-fe7bd3ed2b1a", + "id": "f9564821-9614-4931-b760-2b942d59214a", "mutable": true, "name": "Second parameter from child module", "option": null, @@ -788,7 +788,7 @@ } } }, - "timestamp": "2025-02-18T18:21:17Z", + "timestamp": "2025-02-18T10:58:12Z", "applyable": true, "complete": true, "errored": false diff --git a/provisioner/terraform/testdata/rich-parameters/rich-parameters.tfstate.json b/provisioner/terraform/testdata/rich-parameters/rich-parameters.tfstate.json index be9477bae7fdb..e83a026c81717 100644 --- a/provisioner/terraform/testdata/rich-parameters/rich-parameters.tfstate.json +++ b/provisioner/terraform/testdata/rich-parameters/rich-parameters.tfstate.json @@ -1,6 +1,6 @@ { "format_version": "1.0", - "terraform_version": "1.9.8", + "terraform_version": "1.10.5", "values": { "root_module": { "resources": [ @@ -17,7 +17,7 @@ "display_name": null, "ephemeral": false, "icon": null, - "id": "bf439468-4a7b-44f2-a3c9-1f5ce22d5395", + "id": "bfd26633-f683-494b-8f71-1697c81488c3", "mutable": false, "name": "Example", "option": [ @@ -61,7 +61,7 @@ "display_name": null, "ephemeral": false, "icon": null, - "id": "a5b904c7-4304-4f53-b602-037e6c97d321", + "id": "53a78857-abc2-4447-8329-cc12e160aaba", "mutable": false, "name": "number_example", "option": null, @@ -88,7 +88,7 @@ "display_name": null, "ephemeral": false, "icon": null, - "id": "8af7500b-da86-4242-a351-a6cdeccdf174", + "id": "2ac0c3b2-f97f-47ad-beda-54264ba69422", "mutable": false, "name": "number_example_max_zero", "option": null, @@ -127,7 +127,7 @@ "display_name": null, "ephemeral": false, "icon": null, - "id": "af3488a7-2242-42e4-abec-e4e333523df5", + "id": "3b06ad67-0ab3-434c-b934-81e409e21565", "mutable": false, "name": "number_example_min_max", "option": null, @@ -166,7 +166,7 @@ "display_name": null, "ephemeral": false, "icon": null, - "id": "d9d7e087-99db-4a3d-88d6-07a7e80eebff", + "id": "6f7c9117-36e4-47d5-8f23-a4e495a62895", "mutable": false, "name": "number_example_min_zero", "option": null, @@ -205,7 +205,7 @@ "display_name": null, "ephemeral": false, "icon": null, - "id": "c000a6c6-4a97-41ef-b281-2fc6045f47c4", + "id": "5311db13-4521-4566-aac1-c70db8976ba5", "mutable": false, "name": "Sample", "option": null, @@ -241,7 +241,7 @@ } ], "env": null, - "id": "d408fac5-09cf-4435-bd19-395f98c1522e", + "id": "2d891d31-82ac-4fdd-b922-25c1dfac956c", "init_script": "", "metadata": [], "motd_file": null, @@ -250,7 +250,7 @@ "shutdown_script": null, "startup_script": null, "startup_script_behavior": "non-blocking", - "token": "1d0062ec-43ca-4c73-b9d9-01faa18c888f", + "token": "6942a4c6-24f6-42b5-bcc7-d3e26d00d950", "troubleshooting_url": null }, "sensitive_values": { @@ -269,7 +269,7 @@ "provider_name": "registry.terraform.io/hashicorp/null", "schema_version": 0, "values": { - "id": "1399596486368633070", + "id": "6111468857109842799", "triggers": null }, "sensitive_values": {}, @@ -294,7 +294,7 @@ "display_name": null, "ephemeral": false, "icon": null, - "id": "193c4367-c1d3-45ff-903d-773980e7f930", + "id": "1adeea93-ddc4-4dd8-b328-e167161bbe84", "mutable": true, "name": "First parameter from module", "option": null, @@ -321,7 +321,7 @@ "display_name": null, "ephemeral": false, "icon": null, - "id": "d86af8d9-8d91-4161-9e29-02acb7a98c5e", + "id": "4bb326d9-cf43-4947-b26c-bb668a9f7a80", "mutable": true, "name": "Second parameter from module", "option": null, @@ -353,7 +353,7 @@ "display_name": null, "ephemeral": false, "icon": null, - "id": "bcf8f382-6ed3-4304-8ad0-b6fde8e0ae29", + "id": "a2b6d1e4-2e77-4eff-a81b-0fe285750824", "mutable": true, "name": "First parameter from child module", "option": null, @@ -380,7 +380,7 @@ "display_name": null, "ephemeral": false, "icon": null, - "id": "1db63f83-4d25-4ebb-9f20-ae34db766b2f", + "id": "9dac8aaa-ccf6-4c94-90d2-2009bfbbd596", "mutable": true, "name": "Second parameter from child module", "option": null, From 0590d77cb1514c383debbc49cc856c3bb95b886c Mon Sep 17 00:00:00 2001 From: McKayla Washburn Date: Thu, 27 Feb 2025 18:01:03 +0000 Subject: [PATCH 19/20] fix migration numbers --- ...{000295_user_configs.down.sql => 000297_user_configs.down.sql} | 0 .../{000295_user_configs.up.sql => 000297_user_configs.up.sql} | 0 2 files changed, 0 insertions(+), 0 deletions(-) rename coderd/database/migrations/{000295_user_configs.down.sql => 000297_user_configs.down.sql} (100%) rename coderd/database/migrations/{000295_user_configs.up.sql => 000297_user_configs.up.sql} (100%) diff --git a/coderd/database/migrations/000295_user_configs.down.sql b/coderd/database/migrations/000297_user_configs.down.sql similarity index 100% rename from coderd/database/migrations/000295_user_configs.down.sql rename to coderd/database/migrations/000297_user_configs.down.sql diff --git a/coderd/database/migrations/000295_user_configs.up.sql b/coderd/database/migrations/000297_user_configs.up.sql similarity index 100% rename from coderd/database/migrations/000295_user_configs.up.sql rename to coderd/database/migrations/000297_user_configs.up.sql From 9360f54104a41738a7ab8d2ace097b7e2162ca10 Mon Sep 17 00:00:00 2001 From: McKayla Washburn Date: Wed, 5 Mar 2025 17:35:20 +0000 Subject: [PATCH 20/20] =?UTF-8?q?=F0=9F=A7=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- coderd/apidoc/docs.go | 12 +++ coderd/apidoc/swagger.json | 12 +++ ....down.sql => 000299_user_configs.down.sql} | 0 ...figs.up.sql => 000299_user_configs.up.sql} | 0 codersdk/users.go | 3 + docs/reference/api/audit.md | 1 + docs/reference/api/enterprise.md | 54 +++++++---- docs/reference/api/schemas.md | 94 +++++++++++-------- docs/reference/api/users.md | 8 ++ site/src/api/typesGenerated.ts | 1 + 10 files changed, 125 insertions(+), 60 deletions(-) rename coderd/database/migrations/{000297_user_configs.down.sql => 000299_user_configs.down.sql} (100%) rename coderd/database/migrations/{000297_user_configs.up.sql => 000299_user_configs.up.sql} (100%) diff --git a/coderd/apidoc/docs.go b/coderd/apidoc/docs.go index 820d10d6bb776..8f90cd5c205a2 100644 --- a/coderd/apidoc/docs.go +++ b/coderd/apidoc/docs.go @@ -13888,6 +13888,10 @@ const docTemplate = `{ } ] }, + "theme_preference": { + "description": "Deprecated: this value should be retrieved from\n` + "`" + `codersdk.UserPreferenceSettings` + "`" + ` instead.", + "type": "string" + }, "updated_at": { "type": "string", "format": "date-time" @@ -14752,6 +14756,10 @@ const docTemplate = `{ } ] }, + "theme_preference": { + "description": "Deprecated: this value should be retrieved from\n` + "`" + `codersdk.UserPreferenceSettings` + "`" + ` instead.", + "type": "string" + }, "updated_at": { "type": "string", "format": "date-time" @@ -15359,6 +15367,10 @@ const docTemplate = `{ } ] }, + "theme_preference": { + "description": "Deprecated: this value should be retrieved from\n` + "`" + `codersdk.UserPreferenceSettings` + "`" + ` instead.", + "type": "string" + }, "updated_at": { "type": "string", "format": "date-time" diff --git a/coderd/apidoc/swagger.json b/coderd/apidoc/swagger.json index cbb69b16306a9..fcfe56d3fc4aa 100644 --- a/coderd/apidoc/swagger.json +++ b/coderd/apidoc/swagger.json @@ -12565,6 +12565,10 @@ } ] }, + "theme_preference": { + "description": "Deprecated: this value should be retrieved from\n`codersdk.UserPreferenceSettings` instead.", + "type": "string" + }, "updated_at": { "type": "string", "format": "date-time" @@ -13404,6 +13408,10 @@ } ] }, + "theme_preference": { + "description": "Deprecated: this value should be retrieved from\n`codersdk.UserPreferenceSettings` instead.", + "type": "string" + }, "updated_at": { "type": "string", "format": "date-time" @@ -13963,6 +13971,10 @@ } ] }, + "theme_preference": { + "description": "Deprecated: this value should be retrieved from\n`codersdk.UserPreferenceSettings` instead.", + "type": "string" + }, "updated_at": { "type": "string", "format": "date-time" diff --git a/coderd/database/migrations/000297_user_configs.down.sql b/coderd/database/migrations/000299_user_configs.down.sql similarity index 100% rename from coderd/database/migrations/000297_user_configs.down.sql rename to coderd/database/migrations/000299_user_configs.down.sql diff --git a/coderd/database/migrations/000297_user_configs.up.sql b/coderd/database/migrations/000299_user_configs.up.sql similarity index 100% rename from coderd/database/migrations/000297_user_configs.up.sql rename to coderd/database/migrations/000299_user_configs.up.sql diff --git a/codersdk/users.go b/codersdk/users.go index b49b1afef318a..31854731a0ae1 100644 --- a/codersdk/users.go +++ b/codersdk/users.go @@ -56,6 +56,9 @@ type ReducedUser struct { Status UserStatus `json:"status" table:"status" enums:"active,suspended"` LoginType LoginType `json:"login_type"` + // Deprecated: this value should be retrieved from + // `codersdk.UserPreferenceSettings` instead. + ThemePreference string `json:"theme_preference,omitempty"` } // User represents a user in Coder. diff --git a/docs/reference/api/audit.md b/docs/reference/api/audit.md index af13e9049d0b4..3fc6e746f17c8 100644 --- a/docs/reference/api/audit.md +++ b/docs/reference/api/audit.md @@ -83,6 +83,7 @@ curl -X GET http://coder-server:8080/api/v2/audit?limit=0 \ } ], "status": "active", + "theme_preference": "string", "updated_at": "2019-08-24T14:15:22Z", "username": "string" }, diff --git a/docs/reference/api/enterprise.md b/docs/reference/api/enterprise.md index c18b0d5478b5e..152f331fc81d5 100644 --- a/docs/reference/api/enterprise.md +++ b/docs/reference/api/enterprise.md @@ -219,6 +219,7 @@ curl -X GET http://coder-server:8080/api/v2/groups?organization=string&has_membe "login_type": "", "name": "string", "status": "active", + "theme_preference": "string", "updated_at": "2019-08-24T14:15:22Z", "username": "string" } @@ -259,6 +260,7 @@ Status Code **200** | `»» login_type` | [codersdk.LoginType](schemas.md#codersdklogintype) | false | | | | `»» name` | string | false | | | | `»» status` | [codersdk.UserStatus](schemas.md#codersdkuserstatus) | false | | | +| `»» theme_preference` | string | false | | Deprecated: this value should be retrieved from `codersdk.UserPreferenceSettings` instead. | | `»» updated_at` | string(date-time) | false | | | | `»» username` | string | true | | | | `» name` | string | false | | | @@ -324,6 +326,7 @@ curl -X GET http://coder-server:8080/api/v2/groups/{group} \ "login_type": "", "name": "string", "status": "active", + "theme_preference": "string", "updated_at": "2019-08-24T14:15:22Z", "username": "string" } @@ -384,6 +387,7 @@ curl -X DELETE http://coder-server:8080/api/v2/groups/{group} \ "login_type": "", "name": "string", "status": "active", + "theme_preference": "string", "updated_at": "2019-08-24T14:15:22Z", "username": "string" } @@ -463,6 +467,7 @@ curl -X PATCH http://coder-server:8080/api/v2/groups/{group} \ "login_type": "", "name": "string", "status": "active", + "theme_preference": "string", "updated_at": "2019-08-24T14:15:22Z", "username": "string" } @@ -1225,6 +1230,7 @@ curl -X GET http://coder-server:8080/api/v2/organizations/{organization}/groups "login_type": "", "name": "string", "status": "active", + "theme_preference": "string", "updated_at": "2019-08-24T14:15:22Z", "username": "string" } @@ -1265,6 +1271,7 @@ Status Code **200** | `»» login_type` | [codersdk.LoginType](schemas.md#codersdklogintype) | false | | | | `»» name` | string | false | | | | `»» status` | [codersdk.UserStatus](schemas.md#codersdkuserstatus) | false | | | +| `»» theme_preference` | string | false | | Deprecated: this value should be retrieved from `codersdk.UserPreferenceSettings` instead. | | `»» updated_at` | string(date-time) | false | | | | `»» username` | string | true | | | | `» name` | string | false | | | @@ -1343,6 +1350,7 @@ curl -X POST http://coder-server:8080/api/v2/organizations/{organization}/groups "login_type": "", "name": "string", "status": "active", + "theme_preference": "string", "updated_at": "2019-08-24T14:15:22Z", "username": "string" } @@ -1404,6 +1412,7 @@ curl -X GET http://coder-server:8080/api/v2/organizations/{organization}/groups/ "login_type": "", "name": "string", "status": "active", + "theme_preference": "string", "updated_at": "2019-08-24T14:15:22Z", "username": "string" } @@ -2646,6 +2655,7 @@ curl -X PUT http://coder-server:8080/api/v2/scim/v2/Users/{id} \ } ], "status": "active", + "theme_preference": "string", "updated_at": "2019-08-24T14:15:22Z", "username": "string" } @@ -2735,6 +2745,7 @@ curl -X PATCH http://coder-server:8080/api/v2/scim/v2/Users/{id} \ } ], "status": "active", + "theme_preference": "string", "updated_at": "2019-08-24T14:15:22Z", "username": "string" } @@ -3098,6 +3109,7 @@ curl -X GET http://coder-server:8080/api/v2/templates/{template}/acl \ } ], "status": "active", + "theme_preference": "string", "updated_at": "2019-08-24T14:15:22Z", "username": "string" } @@ -3114,25 +3126,26 @@ curl -X GET http://coder-server:8080/api/v2/templates/{template}/acl \ Status Code **200** -| Name | Type | Required | Restrictions | Description | -|----------------------|----------------------------------------------------------|----------|--------------|-------------| -| `[array item]` | array | false | | | -| `» avatar_url` | string(uri) | false | | | -| `» created_at` | string(date-time) | true | | | -| `» email` | string(email) | true | | | -| `» id` | string(uuid) | true | | | -| `» last_seen_at` | string(date-time) | false | | | -| `» login_type` | [codersdk.LoginType](schemas.md#codersdklogintype) | false | | | -| `» name` | string | false | | | -| `» organization_ids` | array | false | | | -| `» role` | [codersdk.TemplateRole](schemas.md#codersdktemplaterole) | false | | | -| `» roles` | array | false | | | -| `»» display_name` | string | false | | | -| `»» name` | string | false | | | -| `»» organization_id` | string | false | | | -| `» status` | [codersdk.UserStatus](schemas.md#codersdkuserstatus) | false | | | -| `» updated_at` | string(date-time) | false | | | -| `» username` | string | true | | | +| Name | Type | Required | Restrictions | Description | +|----------------------|----------------------------------------------------------|----------|--------------|--------------------------------------------------------------------------------------------| +| `[array item]` | array | false | | | +| `» avatar_url` | string(uri) | false | | | +| `» created_at` | string(date-time) | true | | | +| `» email` | string(email) | true | | | +| `» id` | string(uuid) | true | | | +| `» last_seen_at` | string(date-time) | false | | | +| `» login_type` | [codersdk.LoginType](schemas.md#codersdklogintype) | false | | | +| `» name` | string | false | | | +| `» organization_ids` | array | false | | | +| `» role` | [codersdk.TemplateRole](schemas.md#codersdktemplaterole) | false | | | +| `» roles` | array | false | | | +| `»» display_name` | string | false | | | +| `»» name` | string | false | | | +| `»» organization_id` | string | false | | | +| `» status` | [codersdk.UserStatus](schemas.md#codersdkuserstatus) | false | | | +| `» theme_preference` | string | false | | Deprecated: this value should be retrieved from `codersdk.UserPreferenceSettings` instead. | +| `» updated_at` | string(date-time) | false | | | +| `» username` | string | true | | | #### Enumerated Values @@ -3253,6 +3266,7 @@ curl -X GET http://coder-server:8080/api/v2/templates/{template}/acl/available \ "login_type": "", "name": "string", "status": "active", + "theme_preference": "string", "updated_at": "2019-08-24T14:15:22Z", "username": "string" } @@ -3276,6 +3290,7 @@ curl -X GET http://coder-server:8080/api/v2/templates/{template}/acl/available \ "login_type": "", "name": "string", "status": "active", + "theme_preference": "string", "updated_at": "2019-08-24T14:15:22Z", "username": "string" } @@ -3310,6 +3325,7 @@ Status Code **200** | `»»» login_type` | [codersdk.LoginType](schemas.md#codersdklogintype) | false | | | | `»»» name` | string | false | | | | `»»» status` | [codersdk.UserStatus](schemas.md#codersdkuserstatus) | false | | | +| `»»» theme_preference` | string | false | | Deprecated: this value should be retrieved from `codersdk.UserPreferenceSettings` instead. | | `»»» updated_at` | string(date-time) | false | | | | `»»» username` | string | true | | | | `»» name` | string | false | | | diff --git a/docs/reference/api/schemas.md b/docs/reference/api/schemas.md index baf55a0fa48ac..9fa22af7356ae 100644 --- a/docs/reference/api/schemas.md +++ b/docs/reference/api/schemas.md @@ -242,6 +242,7 @@ "login_type": "", "name": "string", "status": "active", + "theme_preference": "string", "updated_at": "2019-08-24T14:15:22Z", "username": "string" } @@ -265,6 +266,7 @@ "login_type": "", "name": "string", "status": "active", + "theme_preference": "string", "updated_at": "2019-08-24T14:15:22Z", "username": "string" } @@ -656,6 +658,7 @@ } ], "status": "active", + "theme_preference": "string", "updated_at": "2019-08-24T14:15:22Z", "username": "string" }, @@ -747,6 +750,7 @@ } ], "status": "active", + "theme_preference": "string", "updated_at": "2019-08-24T14:15:22Z", "username": "string" }, @@ -3065,6 +3069,7 @@ Git clone makes use of this by parsing the URL from: 'Username for "https://gith } ], "status": "active", + "theme_preference": "string", "updated_at": "2019-08-24T14:15:22Z", "username": "string" } @@ -3132,6 +3137,7 @@ Git clone makes use of this by parsing the URL from: 'Username for "https://gith "login_type": "", "name": "string", "status": "active", + "theme_preference": "string", "updated_at": "2019-08-24T14:15:22Z", "username": "string" } @@ -5181,6 +5187,7 @@ Git clone makes use of this by parsing the URL from: 'Username for "https://gith "login_type": "", "name": "string", "status": "active", + "theme_preference": "string", "updated_at": "2019-08-24T14:15:22Z", "username": "string" } @@ -5188,18 +5195,19 @@ Git clone makes use of this by parsing the URL from: 'Username for "https://gith ### Properties -| Name | Type | Required | Restrictions | Description | -|----------------|--------------------------------------------|----------|--------------|-------------| -| `avatar_url` | string | false | | | -| `created_at` | string | true | | | -| `email` | string | true | | | -| `id` | string | true | | | -| `last_seen_at` | string | false | | | -| `login_type` | [codersdk.LoginType](#codersdklogintype) | false | | | -| `name` | string | false | | | -| `status` | [codersdk.UserStatus](#codersdkuserstatus) | false | | | -| `updated_at` | string | false | | | -| `username` | string | true | | | +| Name | Type | Required | Restrictions | Description | +|--------------------|--------------------------------------------|----------|--------------|--------------------------------------------------------------------------------------------| +| `avatar_url` | string | false | | | +| `created_at` | string | true | | | +| `email` | string | true | | | +| `id` | string | true | | | +| `last_seen_at` | string | false | | | +| `login_type` | [codersdk.LoginType](#codersdklogintype) | false | | | +| `name` | string | false | | | +| `status` | [codersdk.UserStatus](#codersdkuserstatus) | false | | | +| `theme_preference` | string | false | | Deprecated: this value should be retrieved from `codersdk.UserPreferenceSettings` instead. | +| `updated_at` | string | false | | | +| `username` | string | true | | | #### Enumerated Values @@ -6164,6 +6172,7 @@ Restarts will only happen on weekdays in this list on weeks which line up with W } ], "status": "active", + "theme_preference": "string", "updated_at": "2019-08-24T14:15:22Z", "username": "string" } @@ -6171,21 +6180,22 @@ Restarts will only happen on weekdays in this list on weeks which line up with W ### Properties -| Name | Type | Required | Restrictions | Description | -|--------------------|-------------------------------------------------|----------|--------------|-------------| -| `avatar_url` | string | false | | | -| `created_at` | string | true | | | -| `email` | string | true | | | -| `id` | string | true | | | -| `last_seen_at` | string | false | | | -| `login_type` | [codersdk.LoginType](#codersdklogintype) | false | | | -| `name` | string | false | | | -| `organization_ids` | array of string | false | | | -| `role` | [codersdk.TemplateRole](#codersdktemplaterole) | false | | | -| `roles` | array of [codersdk.SlimRole](#codersdkslimrole) | false | | | -| `status` | [codersdk.UserStatus](#codersdkuserstatus) | false | | | -| `updated_at` | string | false | | | -| `username` | string | true | | | +| Name | Type | Required | Restrictions | Description | +|--------------------|-------------------------------------------------|----------|--------------|--------------------------------------------------------------------------------------------| +| `avatar_url` | string | false | | | +| `created_at` | string | true | | | +| `email` | string | true | | | +| `id` | string | true | | | +| `last_seen_at` | string | false | | | +| `login_type` | [codersdk.LoginType](#codersdklogintype) | false | | | +| `name` | string | false | | | +| `organization_ids` | array of string | false | | | +| `role` | [codersdk.TemplateRole](#codersdktemplaterole) | false | | | +| `roles` | array of [codersdk.SlimRole](#codersdkslimrole) | false | | | +| `status` | [codersdk.UserStatus](#codersdkuserstatus) | false | | | +| `theme_preference` | string | false | | Deprecated: this value should be retrieved from `codersdk.UserPreferenceSettings` instead. | +| `updated_at` | string | false | | | +| `username` | string | true | | | #### Enumerated Values @@ -6862,6 +6872,7 @@ If the schedule is empty, the user will be updated to use the default schedule.| } ], "status": "active", + "theme_preference": "string", "updated_at": "2019-08-24T14:15:22Z", "username": "string" } @@ -6869,20 +6880,21 @@ If the schedule is empty, the user will be updated to use the default schedule.| ### Properties -| Name | Type | Required | Restrictions | Description | -|--------------------|-------------------------------------------------|----------|--------------|-------------| -| `avatar_url` | string | false | | | -| `created_at` | string | true | | | -| `email` | string | true | | | -| `id` | string | true | | | -| `last_seen_at` | string | false | | | -| `login_type` | [codersdk.LoginType](#codersdklogintype) | false | | | -| `name` | string | false | | | -| `organization_ids` | array of string | false | | | -| `roles` | array of [codersdk.SlimRole](#codersdkslimrole) | false | | | -| `status` | [codersdk.UserStatus](#codersdkuserstatus) | false | | | -| `updated_at` | string | false | | | -| `username` | string | true | | | +| Name | Type | Required | Restrictions | Description | +|--------------------|-------------------------------------------------|----------|--------------|--------------------------------------------------------------------------------------------| +| `avatar_url` | string | false | | | +| `created_at` | string | true | | | +| `email` | string | true | | | +| `id` | string | true | | | +| `last_seen_at` | string | false | | | +| `login_type` | [codersdk.LoginType](#codersdklogintype) | false | | | +| `name` | string | false | | | +| `organization_ids` | array of string | false | | | +| `roles` | array of [codersdk.SlimRole](#codersdkslimrole) | false | | | +| `status` | [codersdk.UserStatus](#codersdkuserstatus) | false | | | +| `theme_preference` | string | false | | Deprecated: this value should be retrieved from `codersdk.UserPreferenceSettings` instead. | +| `updated_at` | string | false | | | +| `username` | string | true | | | #### Enumerated Values diff --git a/docs/reference/api/users.md b/docs/reference/api/users.md index 275bad5ffc556..3f0c38571f7c4 100644 --- a/docs/reference/api/users.md +++ b/docs/reference/api/users.md @@ -49,6 +49,7 @@ curl -X GET http://coder-server:8080/api/v2/users \ } ], "status": "active", + "theme_preference": "string", "updated_at": "2019-08-24T14:15:22Z", "username": "string" } @@ -124,6 +125,7 @@ curl -X POST http://coder-server:8080/api/v2/users \ } ], "status": "active", + "theme_preference": "string", "updated_at": "2019-08-24T14:15:22Z", "username": "string" } @@ -434,6 +436,7 @@ curl -X GET http://coder-server:8080/api/v2/users/{user} \ } ], "status": "active", + "theme_preference": "string", "updated_at": "2019-08-24T14:15:22Z", "username": "string" } @@ -1207,6 +1210,7 @@ curl -X PUT http://coder-server:8080/api/v2/users/{user}/profile \ } ], "status": "active", + "theme_preference": "string", "updated_at": "2019-08-24T14:15:22Z", "username": "string" } @@ -1263,6 +1267,7 @@ curl -X GET http://coder-server:8080/api/v2/users/{user}/roles \ } ], "status": "active", + "theme_preference": "string", "updated_at": "2019-08-24T14:15:22Z", "username": "string" } @@ -1331,6 +1336,7 @@ curl -X PUT http://coder-server:8080/api/v2/users/{user}/roles \ } ], "status": "active", + "theme_preference": "string", "updated_at": "2019-08-24T14:15:22Z", "username": "string" } @@ -1387,6 +1393,7 @@ curl -X PUT http://coder-server:8080/api/v2/users/{user}/status/activate \ } ], "status": "active", + "theme_preference": "string", "updated_at": "2019-08-24T14:15:22Z", "username": "string" } @@ -1443,6 +1450,7 @@ curl -X PUT http://coder-server:8080/api/v2/users/{user}/status/suspend \ } ], "status": "active", + "theme_preference": "string", "updated_at": "2019-08-24T14:15:22Z", "username": "string" } diff --git a/site/src/api/typesGenerated.ts b/site/src/api/typesGenerated.ts index d2f5cd073b085..222c07575b969 100644 --- a/site/src/api/typesGenerated.ts +++ b/site/src/api/typesGenerated.ts @@ -1970,6 +1970,7 @@ export interface ReducedUser extends MinimalUser { readonly last_seen_at: string; readonly status: UserStatus; readonly login_type: LoginType; + readonly theme_preference?: string; } // From codersdk/workspaceproxy.go