fix: hide "Create Workspace" button for deleted templates (#22092)

**Background**

Reported in #17417, there is a `deleted` query parameter supported by
/api/v2/templates, but we do not respect this field on the client,
showing the "Create Workspace" button for deleted templates.

**Expected Behavior**

Don't show the "Create Workspace" button for deleted templates.

**Notes**

This PR adds a new `deleted` field to the templates API response.

Co-authored-by: Danielle Maywood <danielle@themaywoods.com>
This commit is contained in:
Jeremy Ruppel
2026-02-13 19:44:50 -05:00
committed by GitHub
co-authored by Danielle Maywood
parent ebd7ab11cb
commit 0df864fb88
11 changed files with 118 additions and 19 deletions
+3
View File
@@ -18919,6 +18919,9 @@ const docTemplate = `{
"default_ttl_ms": {
"type": "integer"
},
"deleted": {
"type": "boolean"
},
"deprecated": {
"type": "boolean"
},
+3
View File
@@ -17306,6 +17306,9 @@
"default_ttl_ms": {
"type": "integer"
},
"deleted": {
"type": "boolean"
},
"deprecated": {
"type": "boolean"
},
+1
View File
@@ -1131,6 +1131,7 @@ func (api *API) convertTemplate(
RequireActiveVersion: templateAccessControl.RequireActiveVersion,
Deprecated: templateAccessControl.IsDeprecated(),
DeprecationMessage: templateAccessControl.Deprecated,
Deleted: template.Deleted,
MaxPortShareLevel: maxPortShareLevel,
UseClassicParameterFlow: template.UseClassicParameterFlow,
CORSBehavior: codersdk.CORSBehavior(template.CorsBehavior),
+43
View File
@@ -1801,6 +1801,49 @@ func TestDeleteTemplate(t *testing.T) {
require.ErrorAs(t, err, &apiErr)
require.Equal(t, http.StatusForbidden, apiErr.StatusCode())
})
t.Run("DeletedIsSet", func(t *testing.T) {
t.Parallel()
client := coderdtest.New(t, &coderdtest.Options{IncludeProvisionerDaemon: true})
user := coderdtest.CreateFirstUser(t, client)
version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, nil)
template := coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID)
coderdtest.AwaitTemplateVersionJobCompleted(t, client, version.ID)
ctx := testutil.Context(t, testutil.WaitLong)
// Verify the deleted field is exposed in the SDK and set to false for active templates
got, err := client.Template(ctx, template.ID)
require.NoError(t, err)
require.False(t, got.Deleted)
})
t.Run("DeletedIsTrue", func(t *testing.T) {
t.Parallel()
client := coderdtest.New(t, &coderdtest.Options{IncludeProvisionerDaemon: true})
user := coderdtest.CreateFirstUser(t, client)
version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, nil)
template := coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID)
coderdtest.AwaitTemplateVersionJobCompleted(t, client, version.ID)
ctx := testutil.Context(t, testutil.WaitLong)
err := client.DeleteTemplate(ctx, template.ID)
require.NoError(t, err)
// Verify the deleted field is set to true by listing templates with
// deleted:true filter.
templates, err := client.Templates(ctx, codersdk.TemplateFilter{
OrganizationID: user.OrganizationID,
SearchQuery: "deleted:true",
})
require.NoError(t, err)
require.Len(t, templates, 1)
require.Equal(t, template.ID, templates[0].ID)
require.True(t, templates[0].Deleted)
})
}
func TestTemplateMetrics(t *testing.T) {