From b956a6466c5798c8b9f17d9d7703d33bcfe851b5 Mon Sep 17 00:00:00 2001 From: Abhineet Jain Date: Wed, 8 Jun 2022 15:21:39 +0000 Subject: [PATCH 1/7] design commit --- site/src/components/TemplateStats/TemplateStats.tsx | 6 ++++++ site/src/pages/TemplatesPage/TemplatesPageView.tsx | 3 +++ 2 files changed, 9 insertions(+) diff --git a/site/src/components/TemplateStats/TemplateStats.tsx b/site/src/components/TemplateStats/TemplateStats.tsx index 24da983939975..458d2d58c2119 100644 --- a/site/src/components/TemplateStats/TemplateStats.tsx +++ b/site/src/components/TemplateStats/TemplateStats.tsx @@ -13,6 +13,7 @@ const Language = { lastUpdateLabel: "Last updated", userPlural: "users", userSingular: "user", + createdByLabel: "Created by" } export interface TemplateStatsProps { @@ -45,6 +46,11 @@ export const TemplateStats: FC = ({ template, activeVersion {dayjs().to(dayjs(template.updated_at))} +
+
+ {Language.createdByLabel} + admin +
) } diff --git a/site/src/pages/TemplatesPage/TemplatesPageView.tsx b/site/src/pages/TemplatesPage/TemplatesPageView.tsx index a27cf2cacf5c1..023f934ef2a30 100644 --- a/site/src/pages/TemplatesPage/TemplatesPageView.tsx +++ b/site/src/pages/TemplatesPage/TemplatesPageView.tsx @@ -49,6 +49,7 @@ export const Language = { templateTooltipTitle: "What is template?", templateTooltipText: "With templates you can create a common configuration for your workspaces using Terraform.", templateTooltipLink: "Manage templates", + createdByLabel: "Created by", } const TemplateHelpTooltip: React.FC = () => { @@ -95,6 +96,7 @@ export const TemplatesPageView: FC = (props) => { {Language.nameLabel} {Language.usedByLabel} {Language.lastUpdatedLabel} + {Language.createdByLabel} @@ -137,6 +139,7 @@ export const TemplatesPageView: FC = (props) => { {Language.developerCount(template.workspace_owner_count)} {dayjs().to(dayjs(template.updated_at))} + admin
From c2880130f0e7bbd5e3736c0b76d2e36995021abf Mon Sep 17 00:00:00 2001 From: Abhineet Jain Date: Thu, 9 Jun 2022 15:14:50 +0000 Subject: [PATCH 2/7] add owner_id to templates table --- coderd/database/dump.sql | 6 ++++- .../migrations/000022_template_owner.down.sql | 1 + .../migrations/000022_template_owner.up.sql | 1 + coderd/database/models.go | 1 + coderd/database/queries.sql.go | 22 +++++++++++++------ coderd/database/queries/templates.sql | 5 +++-- 6 files changed, 26 insertions(+), 10 deletions(-) create mode 100644 coderd/database/migrations/000022_template_owner.down.sql create mode 100644 coderd/database/migrations/000022_template_owner.up.sql diff --git a/coderd/database/dump.sql b/coderd/database/dump.sql index eff1e9ea6350c..6d83b3cc0f4a0 100644 --- a/coderd/database/dump.sql +++ b/coderd/database/dump.sql @@ -248,7 +248,8 @@ CREATE TABLE templates ( active_version_id uuid NOT NULL, description character varying(128) DEFAULT ''::character varying NOT NULL, max_ttl bigint DEFAULT '604800000000000'::bigint NOT NULL, - min_autostart_interval bigint DEFAULT '3600000000000'::bigint NOT NULL + min_autostart_interval bigint DEFAULT '3600000000000'::bigint NOT NULL, + owner_id uuid ); CREATE TABLE users ( @@ -479,6 +480,9 @@ ALTER TABLE ONLY template_versions ALTER TABLE ONLY templates ADD CONSTRAINT templates_organization_id_fkey FOREIGN KEY (organization_id) REFERENCES organizations(id) ON DELETE CASCADE; +ALTER TABLE ONLY templates + ADD CONSTRAINT templates_owner_id_fkey FOREIGN KEY (owner_id) REFERENCES users(id) ON DELETE RESTRICT; + ALTER TABLE ONLY workspace_agents ADD CONSTRAINT workspace_agents_resource_id_fkey FOREIGN KEY (resource_id) REFERENCES workspace_resources(id) ON DELETE CASCADE; diff --git a/coderd/database/migrations/000022_template_owner.down.sql b/coderd/database/migrations/000022_template_owner.down.sql new file mode 100644 index 0000000000000..ec6a5ee949da8 --- /dev/null +++ b/coderd/database/migrations/000022_template_owner.down.sql @@ -0,0 +1 @@ +ALTER TABLE ONLY templates DROP COLUMN IF EXISTS owner_id; diff --git a/coderd/database/migrations/000022_template_owner.up.sql b/coderd/database/migrations/000022_template_owner.up.sql new file mode 100644 index 0000000000000..800a7c590696d --- /dev/null +++ b/coderd/database/migrations/000022_template_owner.up.sql @@ -0,0 +1 @@ +ALTER TABLE ONLY templates ADD COLUMN IF NOT EXISTS owner_id uuid REFERENCES users (id) ON DELETE RESTRICT; diff --git a/coderd/database/models.go b/coderd/database/models.go index 22f47053c3955..944e11fa8187a 100644 --- a/coderd/database/models.go +++ b/coderd/database/models.go @@ -438,6 +438,7 @@ type Template struct { Description string `db:"description" json:"description"` MaxTtl int64 `db:"max_ttl" json:"max_ttl"` MinAutostartInterval int64 `db:"min_autostart_interval" json:"min_autostart_interval"` + OwnerID uuid.NullUUID `db:"owner_id" json:"owner_id"` } type TemplateVersion struct { diff --git a/coderd/database/queries.sql.go b/coderd/database/queries.sql.go index 06e5f61105269..bcf4358002c73 100644 --- a/coderd/database/queries.sql.go +++ b/coderd/database/queries.sql.go @@ -1603,7 +1603,7 @@ func (q *sqlQuerier) UpdateProvisionerJobWithCompleteByID(ctx context.Context, a const getTemplateByID = `-- name: GetTemplateByID :one SELECT - id, created_at, updated_at, organization_id, deleted, name, provisioner, active_version_id, description, max_ttl, min_autostart_interval + id, created_at, updated_at, organization_id, deleted, name, provisioner, active_version_id, description, max_ttl, min_autostart_interval, owner_id FROM templates WHERE @@ -1627,13 +1627,14 @@ func (q *sqlQuerier) GetTemplateByID(ctx context.Context, id uuid.UUID) (Templat &i.Description, &i.MaxTtl, &i.MinAutostartInterval, + &i.OwnerID, ) return i, err } const getTemplateByOrganizationAndName = `-- name: GetTemplateByOrganizationAndName :one SELECT - id, created_at, updated_at, organization_id, deleted, name, provisioner, active_version_id, description, max_ttl, min_autostart_interval + id, created_at, updated_at, organization_id, deleted, name, provisioner, active_version_id, description, max_ttl, min_autostart_interval, owner_id FROM templates WHERE @@ -1665,13 +1666,14 @@ func (q *sqlQuerier) GetTemplateByOrganizationAndName(ctx context.Context, arg G &i.Description, &i.MaxTtl, &i.MinAutostartInterval, + &i.OwnerID, ) return i, err } const getTemplatesByIDs = `-- name: GetTemplatesByIDs :many SELECT - id, created_at, updated_at, organization_id, deleted, name, provisioner, active_version_id, description, max_ttl, min_autostart_interval + id, created_at, updated_at, organization_id, deleted, name, provisioner, active_version_id, description, max_ttl, min_autostart_interval, owner_id FROM templates WHERE @@ -1699,6 +1701,7 @@ func (q *sqlQuerier) GetTemplatesByIDs(ctx context.Context, ids []uuid.UUID) ([] &i.Description, &i.MaxTtl, &i.MinAutostartInterval, + &i.OwnerID, ); err != nil { return nil, err } @@ -1715,7 +1718,7 @@ func (q *sqlQuerier) GetTemplatesByIDs(ctx context.Context, ids []uuid.UUID) ([] const getTemplatesByOrganization = `-- name: GetTemplatesByOrganization :many SELECT - id, created_at, updated_at, organization_id, deleted, name, provisioner, active_version_id, description, max_ttl, min_autostart_interval + id, created_at, updated_at, organization_id, deleted, name, provisioner, active_version_id, description, max_ttl, min_autostart_interval, owner_id FROM templates WHERE @@ -1749,6 +1752,7 @@ func (q *sqlQuerier) GetTemplatesByOrganization(ctx context.Context, arg GetTemp &i.Description, &i.MaxTtl, &i.MinAutostartInterval, + &i.OwnerID, ); err != nil { return nil, err } @@ -1775,10 +1779,11 @@ INSERT INTO active_version_id, description, max_ttl, - min_autostart_interval + min_autostart_interval, + owner_id ) VALUES - ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10) RETURNING id, created_at, updated_at, organization_id, deleted, name, provisioner, active_version_id, description, max_ttl, min_autostart_interval + ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11) RETURNING id, created_at, updated_at, organization_id, deleted, name, provisioner, active_version_id, description, max_ttl, min_autostart_interval, owner_id ` type InsertTemplateParams struct { @@ -1792,6 +1797,7 @@ type InsertTemplateParams struct { Description string `db:"description" json:"description"` MaxTtl int64 `db:"max_ttl" json:"max_ttl"` MinAutostartInterval int64 `db:"min_autostart_interval" json:"min_autostart_interval"` + OwnerID uuid.NullUUID `db:"owner_id" json:"owner_id"` } func (q *sqlQuerier) InsertTemplate(ctx context.Context, arg InsertTemplateParams) (Template, error) { @@ -1806,6 +1812,7 @@ func (q *sqlQuerier) InsertTemplate(ctx context.Context, arg InsertTemplateParam arg.Description, arg.MaxTtl, arg.MinAutostartInterval, + arg.OwnerID, ) var i Template err := row.Scan( @@ -1820,6 +1827,7 @@ func (q *sqlQuerier) InsertTemplate(ctx context.Context, arg InsertTemplateParam &i.Description, &i.MaxTtl, &i.MinAutostartInterval, + &i.OwnerID, ) return i, err } @@ -1873,7 +1881,7 @@ SET WHERE id = $1 RETURNING - id, created_at, updated_at, organization_id, deleted, name, provisioner, active_version_id, description, max_ttl, min_autostart_interval + id, created_at, updated_at, organization_id, deleted, name, provisioner, active_version_id, description, max_ttl, min_autostart_interval, owner_id ` type UpdateTemplateMetaByIDParams struct { diff --git a/coderd/database/queries/templates.sql b/coderd/database/queries/templates.sql index ffc0b9dabfb38..2ac81781d1188 100644 --- a/coderd/database/queries/templates.sql +++ b/coderd/database/queries/templates.sql @@ -49,10 +49,11 @@ INSERT INTO active_version_id, description, max_ttl, - min_autostart_interval + min_autostart_interval, + owner_id ) VALUES - ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10) RETURNING *; + ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11) RETURNING *; -- name: UpdateTemplateActiveVersionByID :exec UPDATE From 02cb2930ce57d244c3d34fe12687e41d86451369 Mon Sep 17 00:00:00 2001 From: Abhineet Jain Date: Fri, 10 Jun 2022 03:02:36 +0000 Subject: [PATCH 3/7] add owner information in apis and ui --- coderd/audit/diff_test.go | 2 ++ coderd/audit/table.go | 1 + coderd/database/databasefake/databasefake.go | 1 + coderd/templates.go | 33 ++++++++++++++----- codersdk/templates.go | 2 ++ site/src/api/typesGenerated.ts | 8 +++-- .../TemplateStats/TemplateStats.stories.tsx | 9 +++++ .../TemplateStats/TemplateStats.tsx | 5 +-- .../pages/TemplatesPage/TemplatesPageView.tsx | 3 +- site/src/testHelpers/entities.ts | 2 ++ 10 files changed, 51 insertions(+), 15 deletions(-) diff --git a/coderd/audit/diff_test.go b/coderd/audit/diff_test.go index 53f2110f07c26..912ed7d791944 100644 --- a/coderd/audit/diff_test.go +++ b/coderd/audit/diff_test.go @@ -88,6 +88,7 @@ func TestDiff(t *testing.T) { ActiveVersionID: uuid.UUID{3}, MaxTtl: int64(time.Hour), MinAutostartInterval: int64(time.Minute), + OwnerID: uuid.NullUUID{UUID: uuid.UUID{4}, Valid: true}, }, exp: audit.Map{ "id": uuid.UUID{1}.String(), @@ -97,6 +98,7 @@ func TestDiff(t *testing.T) { "active_version_id": uuid.UUID{3}.String(), "max_ttl": int64(3600000000000), "min_autostart_interval": int64(60000000000), + "owner_id": uuid.UUID{4}.String(), }, }, }) diff --git a/coderd/audit/table.go b/coderd/audit/table.go index efdf0de1d6431..09a33facd0b81 100644 --- a/coderd/audit/table.go +++ b/coderd/audit/table.go @@ -72,6 +72,7 @@ var AuditableResources = auditMap(map[any]map[string]Action{ "description": ActionTrack, "max_ttl": ActionTrack, "min_autostart_interval": ActionTrack, + "owner_id": ActionTrack, }, &database.TemplateVersion{}: { "id": ActionTrack, diff --git a/coderd/database/databasefake/databasefake.go b/coderd/database/databasefake/databasefake.go index 78f85e71c597c..87ad44a83a71c 100644 --- a/coderd/database/databasefake/databasefake.go +++ b/coderd/database/databasefake/databasefake.go @@ -1316,6 +1316,7 @@ func (q *fakeQuerier) InsertTemplate(_ context.Context, arg database.InsertTempl Description: arg.Description, MaxTtl: arg.MaxTtl, MinAutostartInterval: arg.MinAutostartInterval, + OwnerID: arg.OwnerID, } q.templates = append(q.templates, template) return template, nil diff --git a/coderd/templates.go b/coderd/templates.go index 386a360111960..88c30c953efd8 100644 --- a/coderd/templates.go +++ b/coderd/templates.go @@ -1,6 +1,7 @@ package coderd import ( + "context" "database/sql" "errors" "fmt" @@ -49,7 +50,7 @@ func (api *API) template(rw http.ResponseWriter, r *http.Request) { count = uint32(workspaceCounts[0].Count) } - httpapi.Write(rw, http.StatusOK, convertTemplate(template, count)) + httpapi.Write(rw, http.StatusOK, convertTemplate(r.Context(), api.Database, template, count)) } func (api *API) deleteTemplate(rw http.ResponseWriter, r *http.Request) { @@ -97,6 +98,7 @@ func (api *API) deleteTemplate(rw http.ResponseWriter, r *http.Request) { func (api *API) postTemplateByOrganization(rw http.ResponseWriter, r *http.Request) { var createTemplate codersdk.CreateTemplateRequest organization := httpmw.OrganizationParam(r) + apiKey := httpmw.APIKey(r) if !api.Authorize(rw, r, rbac.ActionCreate, rbac.ResourceTemplate.InOrg(organization.ID)) { return } @@ -175,6 +177,10 @@ func (api *API) postTemplateByOrganization(rw http.ResponseWriter, r *http.Reque Description: createTemplate.Description, MaxTtl: int64(maxTTL), MinAutostartInterval: int64(minAutostartInterval), + OwnerID: uuid.NullUUID{ + UUID: apiKey.UserID, + Valid: true, + }, }) if err != nil { return xerrors.Errorf("insert template: %s", err) @@ -208,7 +214,7 @@ func (api *API) postTemplateByOrganization(rw http.ResponseWriter, r *http.Reque } } - template = convertTemplate(dbTemplate, 0) + template = convertTemplate(r.Context(), db, dbTemplate, 0) return nil }) if err != nil { @@ -258,7 +264,7 @@ func (api *API) templatesByOrganization(rw http.ResponseWriter, r *http.Request) return } - httpapi.Write(rw, http.StatusOK, convertTemplates(templates, workspaceCounts)) + httpapi.Write(rw, http.StatusOK, convertTemplates(r.Context(), api.Database, templates, workspaceCounts)) } func (api *API) templateByOrganizationAndName(rw http.ResponseWriter, r *http.Request) { @@ -304,7 +310,7 @@ func (api *API) templateByOrganizationAndName(rw http.ResponseWriter, r *http.Re count = uint32(workspaceCounts[0].Count) } - httpapi.Write(rw, http.StatusOK, convertTemplate(template, count)) + httpapi.Write(rw, http.StatusOK, convertTemplate(r.Context(), api.Database, template, count)) } func (api *API) patchTemplateMeta(rw http.ResponseWriter, r *http.Request) { @@ -400,10 +406,10 @@ func (api *API) patchTemplateMeta(rw http.ResponseWriter, r *http.Request) { return } - httpapi.Write(rw, http.StatusOK, convertTemplate(updated, count)) + httpapi.Write(rw, http.StatusOK, convertTemplate(r.Context(), api.Database, updated, count)) } -func convertTemplates(templates []database.Template, workspaceCounts []database.GetWorkspaceOwnerCountsByTemplateIDsRow) []codersdk.Template { +func convertTemplates(ctx context.Context, db database.Store, templates []database.Template, workspaceCounts []database.GetWorkspaceOwnerCountsByTemplateIDsRow) []codersdk.Template { apiTemplates := make([]codersdk.Template, 0, len(templates)) for _, template := range templates { found := false @@ -411,18 +417,25 @@ func convertTemplates(templates []database.Template, workspaceCounts []database. if workspaceCount.TemplateID.String() != template.ID.String() { continue } - apiTemplates = append(apiTemplates, convertTemplate(template, uint32(workspaceCount.Count))) + apiTemplates = append(apiTemplates, convertTemplate(ctx, db, template, uint32(workspaceCount.Count))) found = true break } if !found { - apiTemplates = append(apiTemplates, convertTemplate(template, uint32(0))) + apiTemplates = append(apiTemplates, convertTemplate(ctx, db, template, uint32(0))) } } return apiTemplates } -func convertTemplate(template database.Template, workspaceOwnerCount uint32) codersdk.Template { +func convertTemplate(ctx context.Context, db database.Store, template database.Template, workspaceOwnerCount uint32) codersdk.Template { + var ownerName string + if template.OwnerID.Valid { + owner, err := db.GetUserByID(ctx, template.OwnerID.UUID) + if err == nil { + ownerName = owner.Username + } + } return codersdk.Template{ ID: template.ID, CreatedAt: template.CreatedAt, @@ -435,5 +448,7 @@ func convertTemplate(template database.Template, workspaceOwnerCount uint32) cod Description: template.Description, MaxTTLMillis: time.Duration(template.MaxTtl).Milliseconds(), MinAutostartIntervalMillis: time.Duration(template.MinAutostartInterval).Milliseconds(), + OwnerID: template.OwnerID, + OwnerName: ownerName, } } diff --git a/codersdk/templates.go b/codersdk/templates.go index e137c3fca05b3..97a4507916438 100644 --- a/codersdk/templates.go +++ b/codersdk/templates.go @@ -25,6 +25,8 @@ type Template struct { Description string `json:"description"` MaxTTLMillis int64 `json:"max_ttl_ms"` MinAutostartIntervalMillis int64 `json:"min_autostart_interval_ms"` + OwnerID uuid.NullUUID `json:"owner_id"` + OwnerName string `json:"owner_name"` } type UpdateActiveTemplateVersion struct { diff --git a/site/src/api/typesGenerated.ts b/site/src/api/typesGenerated.ts index 90c651c61cd9a..40d133b4d550a 100644 --- a/site/src/api/typesGenerated.ts +++ b/site/src/api/typesGenerated.ts @@ -247,6 +247,8 @@ export interface Template { readonly description: string readonly max_ttl_ms: number readonly min_autostart_interval_ms: number + readonly owner_id?: string + readonly owner_name: string } // From codersdk/templateversions.go:14:6 @@ -276,12 +278,12 @@ export interface TemplateVersionParameter { readonly default_source_value: boolean } -// From codersdk/templates.go:98:6 +// From codersdk/templates.go:100:6 export interface TemplateVersionsByTemplateRequest extends Pagination { readonly template_id: string } -// From codersdk/templates.go:30:6 +// From codersdk/templates.go:32:6 export interface UpdateActiveTemplateVersion { readonly id: string } @@ -291,7 +293,7 @@ export interface UpdateRoles { readonly roles: string[] } -// From codersdk/templates.go:34:6 +// From codersdk/templates.go:36:6 export interface UpdateTemplateMeta { readonly description?: string readonly max_ttl_ms?: number diff --git a/site/src/components/TemplateStats/TemplateStats.stories.tsx b/site/src/components/TemplateStats/TemplateStats.stories.tsx index 3056187d110d4..c8e3a912a6f8f 100644 --- a/site/src/components/TemplateStats/TemplateStats.stories.tsx +++ b/site/src/components/TemplateStats/TemplateStats.stories.tsx @@ -23,3 +23,12 @@ UsedByMany.args = { }, activeVersion: Mocks.MockTemplateVersion, } + +export const UnknownOwner = Template.bind({}) +UnknownOwner.args = { + template: { + ...Mocks.MockTemplate, + owner_name: "", + }, + activeVersion: Mocks.MockTemplateVersion, +} diff --git a/site/src/components/TemplateStats/TemplateStats.tsx b/site/src/components/TemplateStats/TemplateStats.tsx index 458d2d58c2119..d38176cefea14 100644 --- a/site/src/components/TemplateStats/TemplateStats.tsx +++ b/site/src/components/TemplateStats/TemplateStats.tsx @@ -13,7 +13,8 @@ const Language = { lastUpdateLabel: "Last updated", userPlural: "users", userSingular: "user", - createdByLabel: "Created by" + createdByLabel: "Created by", + defaultTemplateCreator: "", } export interface TemplateStatsProps { @@ -49,7 +50,7 @@ export const TemplateStats: FC = ({ template, activeVersion
{Language.createdByLabel} - admin + {template.owner_name || Language.defaultTemplateCreator}
) diff --git a/site/src/pages/TemplatesPage/TemplatesPageView.tsx b/site/src/pages/TemplatesPage/TemplatesPageView.tsx index 023f934ef2a30..4801e6a619fb0 100644 --- a/site/src/pages/TemplatesPage/TemplatesPageView.tsx +++ b/site/src/pages/TemplatesPage/TemplatesPageView.tsx @@ -50,6 +50,7 @@ export const Language = { templateTooltipText: "With templates you can create a common configuration for your workspaces using Terraform.", templateTooltipLink: "Manage templates", createdByLabel: "Created by", + defaultTemplateOwner: "", } const TemplateHelpTooltip: React.FC = () => { @@ -139,7 +140,7 @@ export const TemplatesPageView: FC = (props) => { {Language.developerCount(template.workspace_owner_count)} {dayjs().to(dayjs(template.updated_at))} - admin + {template.owner_name || Language.defaultTemplateOwner}
diff --git a/site/src/testHelpers/entities.ts b/site/src/testHelpers/entities.ts index 53414283e4cc9..6db3b5f04e628 100644 --- a/site/src/testHelpers/entities.ts +++ b/site/src/testHelpers/entities.ts @@ -114,6 +114,8 @@ export const MockTemplate: TypesGen.Template = { description: "This is a test description.", max_ttl_ms: 604800000, min_autostart_interval_ms: 3600000, + owner_id: "test-owner-id", + owner_name: "test_owner", } export const MockWorkspaceAutostartDisabled: TypesGen.UpdateWorkspaceAutostartRequest = { From 460a8189bfed4bee5dc2151e5f987518e7dad5a0 Mon Sep 17 00:00:00 2001 From: Abhineet Jain Date: Fri, 10 Jun 2022 15:35:43 +0000 Subject: [PATCH 4/7] update minWidth for statItem --- site/src/components/TemplateStats/TemplateStats.tsx | 2 +- site/src/components/WorkspaceBuildStats/WorkspaceBuildStats.tsx | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/site/src/components/TemplateStats/TemplateStats.tsx b/site/src/components/TemplateStats/TemplateStats.tsx index d38176cefea14..ad6f619d10027 100644 --- a/site/src/components/TemplateStats/TemplateStats.tsx +++ b/site/src/components/TemplateStats/TemplateStats.tsx @@ -70,7 +70,7 @@ const useStyles = makeStyles((theme) => ({ }, statItem: { - minWidth: theme.spacing(20), + minWidth: "20%", padding: theme.spacing(2), paddingTop: theme.spacing(1.75), }, diff --git a/site/src/components/WorkspaceBuildStats/WorkspaceBuildStats.tsx b/site/src/components/WorkspaceBuildStats/WorkspaceBuildStats.tsx index 0db8dfc143362..4b00dd0584f55 100644 --- a/site/src/components/WorkspaceBuildStats/WorkspaceBuildStats.tsx +++ b/site/src/components/WorkspaceBuildStats/WorkspaceBuildStats.tsx @@ -69,7 +69,7 @@ const useStyles = makeStyles((theme) => ({ }, statItem: { - minWidth: theme.spacing(20), + minWidth: "16%", padding: theme.spacing(2), paddingTop: theme.spacing(1.75), }, From 6760cf968761ba7dce47e13cb54846c061f11676 Mon Sep 17 00:00:00 2001 From: Abhineet Jain Date: Fri, 10 Jun 2022 17:25:54 +0000 Subject: [PATCH 5/7] rename owner to created_by --- coderd/audit/diff_test.go | 4 +-- coderd/audit/table.go | 2 +- coderd/database/databasefake/databasefake.go | 2 +- coderd/database/dump.sql | 6 ++-- .../migrations/000022_template_owner.down.sql | 2 +- .../migrations/000022_template_owner.up.sql | 2 +- coderd/database/models.go | 2 +- coderd/database/queries.sql.go | 28 +++++++++---------- coderd/database/queries/templates.sql | 2 +- coderd/templates.go | 14 +++++----- codersdk/templates.go | 4 +-- site/src/api/typesGenerated.ts | 4 +-- .../TemplateStats/TemplateStats.stories.tsx | 6 ++-- .../TemplateStats/TemplateStats.tsx | 2 +- .../pages/TemplatesPage/TemplatesPageView.tsx | 2 +- site/src/testHelpers/entities.ts | 4 +-- 16 files changed, 43 insertions(+), 43 deletions(-) diff --git a/coderd/audit/diff_test.go b/coderd/audit/diff_test.go index 912ed7d791944..ba91692a0734f 100644 --- a/coderd/audit/diff_test.go +++ b/coderd/audit/diff_test.go @@ -88,7 +88,7 @@ func TestDiff(t *testing.T) { ActiveVersionID: uuid.UUID{3}, MaxTtl: int64(time.Hour), MinAutostartInterval: int64(time.Minute), - OwnerID: uuid.NullUUID{UUID: uuid.UUID{4}, Valid: true}, + CreatedBy: uuid.NullUUID{UUID: uuid.UUID{4}, Valid: true}, }, exp: audit.Map{ "id": uuid.UUID{1}.String(), @@ -98,7 +98,7 @@ func TestDiff(t *testing.T) { "active_version_id": uuid.UUID{3}.String(), "max_ttl": int64(3600000000000), "min_autostart_interval": int64(60000000000), - "owner_id": uuid.UUID{4}.String(), + "created_by": uuid.UUID{4}.String(), }, }, }) diff --git a/coderd/audit/table.go b/coderd/audit/table.go index 09a33facd0b81..7562472f3c583 100644 --- a/coderd/audit/table.go +++ b/coderd/audit/table.go @@ -72,7 +72,7 @@ var AuditableResources = auditMap(map[any]map[string]Action{ "description": ActionTrack, "max_ttl": ActionTrack, "min_autostart_interval": ActionTrack, - "owner_id": ActionTrack, + "created_by": ActionTrack, }, &database.TemplateVersion{}: { "id": ActionTrack, diff --git a/coderd/database/databasefake/databasefake.go b/coderd/database/databasefake/databasefake.go index 87ad44a83a71c..4374a502c3dcc 100644 --- a/coderd/database/databasefake/databasefake.go +++ b/coderd/database/databasefake/databasefake.go @@ -1316,7 +1316,7 @@ func (q *fakeQuerier) InsertTemplate(_ context.Context, arg database.InsertTempl Description: arg.Description, MaxTtl: arg.MaxTtl, MinAutostartInterval: arg.MinAutostartInterval, - OwnerID: arg.OwnerID, + CreatedBy: arg.CreatedBy, } q.templates = append(q.templates, template) return template, nil diff --git a/coderd/database/dump.sql b/coderd/database/dump.sql index 6d83b3cc0f4a0..95ef9ff0df3d6 100644 --- a/coderd/database/dump.sql +++ b/coderd/database/dump.sql @@ -249,7 +249,7 @@ CREATE TABLE templates ( description character varying(128) DEFAULT ''::character varying NOT NULL, max_ttl bigint DEFAULT '604800000000000'::bigint NOT NULL, min_autostart_interval bigint DEFAULT '3600000000000'::bigint NOT NULL, - owner_id uuid + created_by uuid ); CREATE TABLE users ( @@ -478,10 +478,10 @@ ALTER TABLE ONLY template_versions ADD CONSTRAINT template_versions_template_id_fkey FOREIGN KEY (template_id) REFERENCES templates(id) ON DELETE CASCADE; ALTER TABLE ONLY templates - ADD CONSTRAINT templates_organization_id_fkey FOREIGN KEY (organization_id) REFERENCES organizations(id) ON DELETE CASCADE; + ADD CONSTRAINT templates_created_by_fkey FOREIGN KEY (created_by) REFERENCES users(id) ON DELETE RESTRICT; ALTER TABLE ONLY templates - ADD CONSTRAINT templates_owner_id_fkey FOREIGN KEY (owner_id) REFERENCES users(id) ON DELETE RESTRICT; + ADD CONSTRAINT templates_organization_id_fkey FOREIGN KEY (organization_id) REFERENCES organizations(id) ON DELETE CASCADE; ALTER TABLE ONLY workspace_agents ADD CONSTRAINT workspace_agents_resource_id_fkey FOREIGN KEY (resource_id) REFERENCES workspace_resources(id) ON DELETE CASCADE; diff --git a/coderd/database/migrations/000022_template_owner.down.sql b/coderd/database/migrations/000022_template_owner.down.sql index ec6a5ee949da8..435291e5ccb10 100644 --- a/coderd/database/migrations/000022_template_owner.down.sql +++ b/coderd/database/migrations/000022_template_owner.down.sql @@ -1 +1 @@ -ALTER TABLE ONLY templates DROP COLUMN IF EXISTS owner_id; +ALTER TABLE ONLY templates DROP COLUMN IF EXISTS created_by; diff --git a/coderd/database/migrations/000022_template_owner.up.sql b/coderd/database/migrations/000022_template_owner.up.sql index 800a7c590696d..7ca6f235591bc 100644 --- a/coderd/database/migrations/000022_template_owner.up.sql +++ b/coderd/database/migrations/000022_template_owner.up.sql @@ -1 +1 @@ -ALTER TABLE ONLY templates ADD COLUMN IF NOT EXISTS owner_id uuid REFERENCES users (id) ON DELETE RESTRICT; +ALTER TABLE ONLY templates ADD COLUMN IF NOT EXISTS created_by uuid REFERENCES users (id) ON DELETE RESTRICT; diff --git a/coderd/database/models.go b/coderd/database/models.go index 944e11fa8187a..2454049da0ac0 100644 --- a/coderd/database/models.go +++ b/coderd/database/models.go @@ -438,7 +438,7 @@ type Template struct { Description string `db:"description" json:"description"` MaxTtl int64 `db:"max_ttl" json:"max_ttl"` MinAutostartInterval int64 `db:"min_autostart_interval" json:"min_autostart_interval"` - OwnerID uuid.NullUUID `db:"owner_id" json:"owner_id"` + CreatedBy uuid.NullUUID `db:"created_by" json:"created_by"` } type TemplateVersion struct { diff --git a/coderd/database/queries.sql.go b/coderd/database/queries.sql.go index bcf4358002c73..9091bd57b6caa 100644 --- a/coderd/database/queries.sql.go +++ b/coderd/database/queries.sql.go @@ -1603,7 +1603,7 @@ func (q *sqlQuerier) UpdateProvisionerJobWithCompleteByID(ctx context.Context, a const getTemplateByID = `-- name: GetTemplateByID :one SELECT - id, created_at, updated_at, organization_id, deleted, name, provisioner, active_version_id, description, max_ttl, min_autostart_interval, owner_id + id, created_at, updated_at, organization_id, deleted, name, provisioner, active_version_id, description, max_ttl, min_autostart_interval, created_by FROM templates WHERE @@ -1627,14 +1627,14 @@ func (q *sqlQuerier) GetTemplateByID(ctx context.Context, id uuid.UUID) (Templat &i.Description, &i.MaxTtl, &i.MinAutostartInterval, - &i.OwnerID, + &i.CreatedBy, ) return i, err } const getTemplateByOrganizationAndName = `-- name: GetTemplateByOrganizationAndName :one SELECT - id, created_at, updated_at, organization_id, deleted, name, provisioner, active_version_id, description, max_ttl, min_autostart_interval, owner_id + id, created_at, updated_at, organization_id, deleted, name, provisioner, active_version_id, description, max_ttl, min_autostart_interval, created_by FROM templates WHERE @@ -1666,14 +1666,14 @@ func (q *sqlQuerier) GetTemplateByOrganizationAndName(ctx context.Context, arg G &i.Description, &i.MaxTtl, &i.MinAutostartInterval, - &i.OwnerID, + &i.CreatedBy, ) return i, err } const getTemplatesByIDs = `-- name: GetTemplatesByIDs :many SELECT - id, created_at, updated_at, organization_id, deleted, name, provisioner, active_version_id, description, max_ttl, min_autostart_interval, owner_id + id, created_at, updated_at, organization_id, deleted, name, provisioner, active_version_id, description, max_ttl, min_autostart_interval, created_by FROM templates WHERE @@ -1701,7 +1701,7 @@ func (q *sqlQuerier) GetTemplatesByIDs(ctx context.Context, ids []uuid.UUID) ([] &i.Description, &i.MaxTtl, &i.MinAutostartInterval, - &i.OwnerID, + &i.CreatedBy, ); err != nil { return nil, err } @@ -1718,7 +1718,7 @@ func (q *sqlQuerier) GetTemplatesByIDs(ctx context.Context, ids []uuid.UUID) ([] const getTemplatesByOrganization = `-- name: GetTemplatesByOrganization :many SELECT - id, created_at, updated_at, organization_id, deleted, name, provisioner, active_version_id, description, max_ttl, min_autostart_interval, owner_id + id, created_at, updated_at, organization_id, deleted, name, provisioner, active_version_id, description, max_ttl, min_autostart_interval, created_by FROM templates WHERE @@ -1752,7 +1752,7 @@ func (q *sqlQuerier) GetTemplatesByOrganization(ctx context.Context, arg GetTemp &i.Description, &i.MaxTtl, &i.MinAutostartInterval, - &i.OwnerID, + &i.CreatedBy, ); err != nil { return nil, err } @@ -1780,10 +1780,10 @@ INSERT INTO description, max_ttl, min_autostart_interval, - owner_id + created_by ) VALUES - ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11) RETURNING id, created_at, updated_at, organization_id, deleted, name, provisioner, active_version_id, description, max_ttl, min_autostart_interval, owner_id + ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11) RETURNING id, created_at, updated_at, organization_id, deleted, name, provisioner, active_version_id, description, max_ttl, min_autostart_interval, created_by ` type InsertTemplateParams struct { @@ -1797,7 +1797,7 @@ type InsertTemplateParams struct { Description string `db:"description" json:"description"` MaxTtl int64 `db:"max_ttl" json:"max_ttl"` MinAutostartInterval int64 `db:"min_autostart_interval" json:"min_autostart_interval"` - OwnerID uuid.NullUUID `db:"owner_id" json:"owner_id"` + CreatedBy uuid.NullUUID `db:"created_by" json:"created_by"` } func (q *sqlQuerier) InsertTemplate(ctx context.Context, arg InsertTemplateParams) (Template, error) { @@ -1812,7 +1812,7 @@ func (q *sqlQuerier) InsertTemplate(ctx context.Context, arg InsertTemplateParam arg.Description, arg.MaxTtl, arg.MinAutostartInterval, - arg.OwnerID, + arg.CreatedBy, ) var i Template err := row.Scan( @@ -1827,7 +1827,7 @@ func (q *sqlQuerier) InsertTemplate(ctx context.Context, arg InsertTemplateParam &i.Description, &i.MaxTtl, &i.MinAutostartInterval, - &i.OwnerID, + &i.CreatedBy, ) return i, err } @@ -1881,7 +1881,7 @@ SET WHERE id = $1 RETURNING - id, created_at, updated_at, organization_id, deleted, name, provisioner, active_version_id, description, max_ttl, min_autostart_interval, owner_id + id, created_at, updated_at, organization_id, deleted, name, provisioner, active_version_id, description, max_ttl, min_autostart_interval, created_by ` type UpdateTemplateMetaByIDParams struct { diff --git a/coderd/database/queries/templates.sql b/coderd/database/queries/templates.sql index 2ac81781d1188..c3b3753083351 100644 --- a/coderd/database/queries/templates.sql +++ b/coderd/database/queries/templates.sql @@ -50,7 +50,7 @@ INSERT INTO description, max_ttl, min_autostart_interval, - owner_id + created_by ) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11) RETURNING *; diff --git a/coderd/templates.go b/coderd/templates.go index 88c30c953efd8..05f5227c9cafc 100644 --- a/coderd/templates.go +++ b/coderd/templates.go @@ -177,7 +177,7 @@ func (api *API) postTemplateByOrganization(rw http.ResponseWriter, r *http.Reque Description: createTemplate.Description, MaxTtl: int64(maxTTL), MinAutostartInterval: int64(minAutostartInterval), - OwnerID: uuid.NullUUID{ + CreatedBy: uuid.NullUUID{ UUID: apiKey.UserID, Valid: true, }, @@ -429,11 +429,11 @@ func convertTemplates(ctx context.Context, db database.Store, templates []databa } func convertTemplate(ctx context.Context, db database.Store, template database.Template, workspaceOwnerCount uint32) codersdk.Template { - var ownerName string - if template.OwnerID.Valid { - owner, err := db.GetUserByID(ctx, template.OwnerID.UUID) + var createdByName string + if template.CreatedBy.Valid { + creator, err := db.GetUserByID(ctx, template.CreatedBy.UUID) if err == nil { - ownerName = owner.Username + createdByName = creator.Username } } return codersdk.Template{ @@ -448,7 +448,7 @@ func convertTemplate(ctx context.Context, db database.Store, template database.T Description: template.Description, MaxTTLMillis: time.Duration(template.MaxTtl).Milliseconds(), MinAutostartIntervalMillis: time.Duration(template.MinAutostartInterval).Milliseconds(), - OwnerID: template.OwnerID, - OwnerName: ownerName, + CreatedByID: template.CreatedBy, + CreatedByName: createdByName, } } diff --git a/codersdk/templates.go b/codersdk/templates.go index 97a4507916438..31f1ea97d9b59 100644 --- a/codersdk/templates.go +++ b/codersdk/templates.go @@ -25,8 +25,8 @@ type Template struct { Description string `json:"description"` MaxTTLMillis int64 `json:"max_ttl_ms"` MinAutostartIntervalMillis int64 `json:"min_autostart_interval_ms"` - OwnerID uuid.NullUUID `json:"owner_id"` - OwnerName string `json:"owner_name"` + CreatedByID uuid.NullUUID `json:"created_by_id"` + CreatedByName string `json:"created_by_name"` } type UpdateActiveTemplateVersion struct { diff --git a/site/src/api/typesGenerated.ts b/site/src/api/typesGenerated.ts index 40d133b4d550a..9922816060317 100644 --- a/site/src/api/typesGenerated.ts +++ b/site/src/api/typesGenerated.ts @@ -247,8 +247,8 @@ export interface Template { readonly description: string readonly max_ttl_ms: number readonly min_autostart_interval_ms: number - readonly owner_id?: string - readonly owner_name: string + readonly created_by_id?: string + readonly created_by_name: string } // From codersdk/templateversions.go:14:6 diff --git a/site/src/components/TemplateStats/TemplateStats.stories.tsx b/site/src/components/TemplateStats/TemplateStats.stories.tsx index c8e3a912a6f8f..fb7f36d894652 100644 --- a/site/src/components/TemplateStats/TemplateStats.stories.tsx +++ b/site/src/components/TemplateStats/TemplateStats.stories.tsx @@ -24,11 +24,11 @@ UsedByMany.args = { activeVersion: Mocks.MockTemplateVersion, } -export const UnknownOwner = Template.bind({}) -UnknownOwner.args = { +export const UnknownCreator = Template.bind({}) +UnknownCreator.args = { template: { ...Mocks.MockTemplate, - owner_name: "", + created_by_name: "", }, activeVersion: Mocks.MockTemplateVersion, } diff --git a/site/src/components/TemplateStats/TemplateStats.tsx b/site/src/components/TemplateStats/TemplateStats.tsx index ad6f619d10027..fed612f45f019 100644 --- a/site/src/components/TemplateStats/TemplateStats.tsx +++ b/site/src/components/TemplateStats/TemplateStats.tsx @@ -50,7 +50,7 @@ export const TemplateStats: FC = ({ template, activeVersion
{Language.createdByLabel} - {template.owner_name || Language.defaultTemplateCreator} + {template.created_by_name || Language.defaultTemplateCreator}
) diff --git a/site/src/pages/TemplatesPage/TemplatesPageView.tsx b/site/src/pages/TemplatesPage/TemplatesPageView.tsx index 4801e6a619fb0..9ce4a9d67b090 100644 --- a/site/src/pages/TemplatesPage/TemplatesPageView.tsx +++ b/site/src/pages/TemplatesPage/TemplatesPageView.tsx @@ -140,7 +140,7 @@ export const TemplatesPageView: FC = (props) => { {Language.developerCount(template.workspace_owner_count)} {dayjs().to(dayjs(template.updated_at))} - {template.owner_name || Language.defaultTemplateOwner} + {template.created_by_name || Language.defaultTemplateOwner}
diff --git a/site/src/testHelpers/entities.ts b/site/src/testHelpers/entities.ts index 6db3b5f04e628..c96e35dc116ff 100644 --- a/site/src/testHelpers/entities.ts +++ b/site/src/testHelpers/entities.ts @@ -114,8 +114,8 @@ export const MockTemplate: TypesGen.Template = { description: "This is a test description.", max_ttl_ms: 604800000, min_autostart_interval_ms: 3600000, - owner_id: "test-owner-id", - owner_name: "test_owner", + created_by_id: "test-owner-id", + created_by_name: "test_owner", } export const MockWorkspaceAutostartDisabled: TypesGen.UpdateWorkspaceAutostartRequest = { From 5eaf8ad5268f8e0a8ee76987f648158f5565e3eb Mon Sep 17 00:00:00 2001 From: Abhineet Jain Date: Fri, 10 Jun 2022 17:33:53 +0000 Subject: [PATCH 6/7] missing refactor to created_by --- ...ate_owner.down.sql => 000022_template_created_by.down.sql} | 0 ...emplate_owner.up.sql => 000022_template_created_by.up.sql} | 0 site/src/pages/TemplatesPage/TemplatesPageView.tsx | 4 ++-- site/src/testHelpers/entities.ts | 4 ++-- 4 files changed, 4 insertions(+), 4 deletions(-) rename coderd/database/migrations/{000022_template_owner.down.sql => 000022_template_created_by.down.sql} (100%) rename coderd/database/migrations/{000022_template_owner.up.sql => 000022_template_created_by.up.sql} (100%) diff --git a/coderd/database/migrations/000022_template_owner.down.sql b/coderd/database/migrations/000022_template_created_by.down.sql similarity index 100% rename from coderd/database/migrations/000022_template_owner.down.sql rename to coderd/database/migrations/000022_template_created_by.down.sql diff --git a/coderd/database/migrations/000022_template_owner.up.sql b/coderd/database/migrations/000022_template_created_by.up.sql similarity index 100% rename from coderd/database/migrations/000022_template_owner.up.sql rename to coderd/database/migrations/000022_template_created_by.up.sql diff --git a/site/src/pages/TemplatesPage/TemplatesPageView.tsx b/site/src/pages/TemplatesPage/TemplatesPageView.tsx index 9ce4a9d67b090..deda1cad6cdcc 100644 --- a/site/src/pages/TemplatesPage/TemplatesPageView.tsx +++ b/site/src/pages/TemplatesPage/TemplatesPageView.tsx @@ -50,7 +50,7 @@ export const Language = { templateTooltipText: "With templates you can create a common configuration for your workspaces using Terraform.", templateTooltipLink: "Manage templates", createdByLabel: "Created by", - defaultTemplateOwner: "", + defaultTemplateCreator: "", } const TemplateHelpTooltip: React.FC = () => { @@ -140,7 +140,7 @@ export const TemplatesPageView: FC = (props) => { {Language.developerCount(template.workspace_owner_count)} {dayjs().to(dayjs(template.updated_at))} - {template.created_by_name || Language.defaultTemplateOwner} + {template.created_by_name || Language.defaultTemplateCreator}
diff --git a/site/src/testHelpers/entities.ts b/site/src/testHelpers/entities.ts index c96e35dc116ff..b37e038529dbc 100644 --- a/site/src/testHelpers/entities.ts +++ b/site/src/testHelpers/entities.ts @@ -114,8 +114,8 @@ export const MockTemplate: TypesGen.Template = { description: "This is a test description.", max_ttl_ms: 604800000, min_autostart_interval_ms: 3600000, - created_by_id: "test-owner-id", - created_by_name: "test_owner", + created_by_id: "test-creator-id", + created_by_name: "test_creator", } export const MockWorkspaceAutostartDisabled: TypesGen.UpdateWorkspaceAutostartRequest = { From 3f73dfd2447dbe60b22d537d205bc827f09b3ebb Mon Sep 17 00:00:00 2001 From: Abhineet Jain Date: Fri, 10 Jun 2022 19:02:41 +0000 Subject: [PATCH 7/7] handle errors in fetching created_by names --- coderd/templates.go | 82 ++++++++++++++++++++++++++++++++++++--------- 1 file changed, 66 insertions(+), 16 deletions(-) diff --git a/coderd/templates.go b/coderd/templates.go index 05f5227c9cafc..d79bd19f70fa2 100644 --- a/coderd/templates.go +++ b/coderd/templates.go @@ -50,7 +50,16 @@ func (api *API) template(rw http.ResponseWriter, r *http.Request) { count = uint32(workspaceCounts[0].Count) } - httpapi.Write(rw, http.StatusOK, convertTemplate(r.Context(), api.Database, template, count)) + createdByNameMap, err := getCreatedByNamesByTemplateIDs(r.Context(), api.Database, []database.Template{template}) + if err != nil { + httpapi.Write(rw, http.StatusInternalServerError, httpapi.Response{ + Message: "Internal error fetching creator name.", + Detail: err.Error(), + }) + return + } + + httpapi.Write(rw, http.StatusOK, convertTemplate(template, count, createdByNameMap[template.ID.String()])) } func (api *API) deleteTemplate(rw http.ResponseWriter, r *http.Request) { @@ -214,7 +223,12 @@ func (api *API) postTemplateByOrganization(rw http.ResponseWriter, r *http.Reque } } - template = convertTemplate(r.Context(), db, dbTemplate, 0) + createdByNameMap, err := getCreatedByNamesByTemplateIDs(r.Context(), db, []database.Template{dbTemplate}) + if err != nil { + return xerrors.Errorf("get creator name: %w", err) + } + + template = convertTemplate(dbTemplate, 0, createdByNameMap[dbTemplate.ID.String()]) return nil }) if err != nil { @@ -264,7 +278,16 @@ func (api *API) templatesByOrganization(rw http.ResponseWriter, r *http.Request) return } - httpapi.Write(rw, http.StatusOK, convertTemplates(r.Context(), api.Database, templates, workspaceCounts)) + createdByNameMap, err := getCreatedByNamesByTemplateIDs(r.Context(), api.Database, templates) + if err != nil { + httpapi.Write(rw, http.StatusInternalServerError, httpapi.Response{ + Message: "Internal error fetching creator names.", + Detail: err.Error(), + }) + return + } + + httpapi.Write(rw, http.StatusOK, convertTemplates(templates, workspaceCounts, createdByNameMap)) } func (api *API) templateByOrganizationAndName(rw http.ResponseWriter, r *http.Request) { @@ -310,7 +333,16 @@ func (api *API) templateByOrganizationAndName(rw http.ResponseWriter, r *http.Re count = uint32(workspaceCounts[0].Count) } - httpapi.Write(rw, http.StatusOK, convertTemplate(r.Context(), api.Database, template, count)) + createdByNameMap, err := getCreatedByNamesByTemplateIDs(r.Context(), api.Database, []database.Template{template}) + if err != nil { + httpapi.Write(rw, http.StatusInternalServerError, httpapi.Response{ + Message: "Internal error fetching creator name.", + Detail: err.Error(), + }) + return + } + + httpapi.Write(rw, http.StatusOK, convertTemplate(template, count, createdByNameMap[template.ID.String()])) } func (api *API) patchTemplateMeta(rw http.ResponseWriter, r *http.Request) { @@ -406,10 +438,35 @@ func (api *API) patchTemplateMeta(rw http.ResponseWriter, r *http.Request) { return } - httpapi.Write(rw, http.StatusOK, convertTemplate(r.Context(), api.Database, updated, count)) + createdByNameMap, err := getCreatedByNamesByTemplateIDs(r.Context(), api.Database, []database.Template{updated}) + if err != nil { + httpapi.Write(rw, http.StatusInternalServerError, httpapi.Response{ + Message: "Internal error fetching creator name.", + Detail: err.Error(), + }) + return + } + + httpapi.Write(rw, http.StatusOK, convertTemplate(updated, count, createdByNameMap[updated.ID.String()])) +} + +func getCreatedByNamesByTemplateIDs(ctx context.Context, db database.Store, templates []database.Template) (map[string]string, error) { + creators := make(map[string]string, len(templates)) + for _, template := range templates { + if template.CreatedBy.Valid { + creator, err := db.GetUserByID(ctx, template.CreatedBy.UUID) + if err != nil { + return map[string]string{}, err + } + creators[template.ID.String()] = creator.Username + } else { + creators[template.ID.String()] = "" + } + } + return creators, nil } -func convertTemplates(ctx context.Context, db database.Store, templates []database.Template, workspaceCounts []database.GetWorkspaceOwnerCountsByTemplateIDsRow) []codersdk.Template { +func convertTemplates(templates []database.Template, workspaceCounts []database.GetWorkspaceOwnerCountsByTemplateIDsRow, createdByNameMap map[string]string) []codersdk.Template { apiTemplates := make([]codersdk.Template, 0, len(templates)) for _, template := range templates { found := false @@ -417,25 +474,18 @@ func convertTemplates(ctx context.Context, db database.Store, templates []databa if workspaceCount.TemplateID.String() != template.ID.String() { continue } - apiTemplates = append(apiTemplates, convertTemplate(ctx, db, template, uint32(workspaceCount.Count))) + apiTemplates = append(apiTemplates, convertTemplate(template, uint32(workspaceCount.Count), createdByNameMap[template.ID.String()])) found = true break } if !found { - apiTemplates = append(apiTemplates, convertTemplate(ctx, db, template, uint32(0))) + apiTemplates = append(apiTemplates, convertTemplate(template, uint32(0), createdByNameMap[template.ID.String()])) } } return apiTemplates } -func convertTemplate(ctx context.Context, db database.Store, template database.Template, workspaceOwnerCount uint32) codersdk.Template { - var createdByName string - if template.CreatedBy.Valid { - creator, err := db.GetUserByID(ctx, template.CreatedBy.UUID) - if err == nil { - createdByName = creator.Username - } - } +func convertTemplate(template database.Template, workspaceOwnerCount uint32, createdByName string) codersdk.Template { return codersdk.Template{ ID: template.ID, CreatedAt: template.CreatedAt,