Skip to content

Commit 8f6a5af

Browse files
authored
feat: add backend logic for determining tasks tab visibility (#18401)
This PR implements the backend logic for determining if the Tasks tab should be visible in the web UI as described in [the RFC](https://www.notion.so/coderhq/Coder-Tasks-207d579be5928053ab68c8d9a4b59eaa?source=copy_link#210d579be5928013ab5acbe69a2f548b). The frontend component will be added in a follow-up PR once the entire Tasks backend is implemented so as not to break the dogfood environment until then.
1 parent 591f5db commit 8f6a5af

File tree

24 files changed

+145
-0
lines changed

24 files changed

+145
-0
lines changed

cli/testdata/coder_server_--help.golden

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,9 @@ Clients include the Coder CLI, Coder Desktop, IDE extensions, and the web UI.
8585
is detected. By default it instructs users to update using 'curl -L
8686
https://coder.com/install.sh | sh'.
8787

88+
--hide-ai-tasks bool, $CODER_HIDE_AI_TASKS (default: false)
89+
Hide AI tasks from the dashboard.
90+
8891
--ssh-config-options string-array, $CODER_SSH_CONFIG_OPTIONS
8992
These SSH config options will override the default SSH config options.
9093
Provide options in "key=value" or "key value" format separated by

cli/testdata/server-config.yaml.golden

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -520,6 +520,9 @@ client:
520520
# 'webgl', or 'dom'.
521521
# (default: canvas, type: string)
522522
webTerminalRenderer: canvas
523+
# Hide AI tasks from the dashboard.
524+
# (default: false, type: bool)
525+
hideAITasks: false
523526
# Support links to display in the top right drop down menu.
524527
# (default: <unset>, type: struct[[]codersdk.LinkConfig])
525528
supportLinks: []

coderd/apidoc/docs.go

Lines changed: 3 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

coderd/apidoc/swagger.json

Lines changed: 3 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

coderd/coderd.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -628,6 +628,7 @@ func New(options *Options) *API {
628628
Entitlements: options.Entitlements,
629629
Telemetry: options.Telemetry,
630630
Logger: options.Logger.Named("site"),
631+
HideAITasks: options.DeploymentValues.HideAITasks.Value(),
631632
})
632633
api.SiteHandler.Experiments.Store(&experiments)
633634

coderd/database/dbauthz/dbauthz.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3451,6 +3451,11 @@ func (q *querier) GetWorkspacesEligibleForTransition(ctx context.Context, now ti
34513451
return q.db.GetWorkspacesEligibleForTransition(ctx, now)
34523452
}
34533453

3454+
func (q *querier) HasTemplateVersionsWithAITask(ctx context.Context) (bool, error) {
3455+
// Anyone can call HasTemplateVersionsWithAITask.
3456+
return q.db.HasTemplateVersionsWithAITask(ctx)
3457+
}
3458+
34543459
func (q *querier) InsertAPIKey(ctx context.Context, arg database.InsertAPIKeyParams) (database.APIKey, error) {
34553460
return insert(q.log, q.auth,
34563461
rbac.ResourceApiKey.WithOwner(arg.UserID.String()),

coderd/database/dbauthz/dbauthz_test.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4566,6 +4566,9 @@ func (s *MethodTestSuite) TestSystemFunctions() {
45664566
s.Run("GetProvisionerJobByIDForUpdate", s.Subtest(func(db database.Store, check *expects) {
45674567
check.Args(uuid.New()).Asserts(rbac.ResourceProvisionerJobs, policy.ActionRead).Errors(sql.ErrNoRows)
45684568
}))
4569+
s.Run("HasTemplateVersionsWithAITask", s.Subtest(func(db database.Store, check *expects) {
4570+
check.Args().Asserts()
4571+
}))
45694572
}
45704573

45714574
func (s *MethodTestSuite) TestNotifications() {

coderd/database/dbmem/dbmem.go

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8495,6 +8495,19 @@ func (q *FakeQuerier) GetWorkspacesEligibleForTransition(ctx context.Context, no
84958495
return workspaces, nil
84968496
}
84978497

8498+
func (q *FakeQuerier) HasTemplateVersionsWithAITask(_ context.Context) (bool, error) {
8499+
q.mutex.RLock()
8500+
defer q.mutex.RUnlock()
8501+
8502+
for _, templateVersion := range q.templateVersions {
8503+
if templateVersion.HasAITask {
8504+
return true, nil
8505+
}
8506+
}
8507+
8508+
return false, nil
8509+
}
8510+
84988511
func (q *FakeQuerier) InsertAPIKey(_ context.Context, arg database.InsertAPIKeyParams) (database.APIKey, error) {
84998512
if err := validateDatabaseType(arg); err != nil {
85008513
return database.APIKey{}, err

coderd/database/dbmetrics/querymetrics.go

Lines changed: 7 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

coderd/database/dbmock/dbmock.go

Lines changed: 15 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

coderd/database/querier.go

Lines changed: 2 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

coderd/database/queries.sql.go

Lines changed: 12 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

coderd/database/queries/templateversions.sql

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -226,3 +226,7 @@ FROM
226226
WHERE
227227
template_versions.id IN (archived_versions.id)
228228
RETURNING template_versions.id;
229+
230+
-- name: HasTemplateVersionsWithAITask :one
231+
-- Determines if the template versions table has any rows with has_ai_task = TRUE.
232+
SELECT EXISTS (SELECT 1 FROM template_versions WHERE has_ai_task = TRUE);

codersdk/deployment.go

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -399,6 +399,7 @@ type DeploymentValues struct {
399399
AdditionalCSPPolicy serpent.StringArray `json:"additional_csp_policy,omitempty" typescript:",notnull"`
400400
WorkspaceHostnameSuffix serpent.String `json:"workspace_hostname_suffix,omitempty" typescript:",notnull"`
401401
Prebuilds PrebuildsConfig `json:"workspace_prebuilds,omitempty" typescript:",notnull"`
402+
HideAITasks serpent.Bool `json:"hide_ai_tasks,omitempty" typescript:",notnull"`
402403

403404
Config serpent.YAMLConfigPath `json:"config,omitempty" typescript:",notnull"`
404405
WriteConfig serpent.Bool `json:"write_config,omitempty" typescript:",notnull"`
@@ -3116,6 +3117,16 @@ Write out the current server config as YAML to stdout.`,
31163117
YAML: "failure_hard_limit",
31173118
Hidden: true,
31183119
},
3120+
{
3121+
Name: "Hide AI Tasks",
3122+
Description: "Hide AI tasks from the dashboard.",
3123+
Flag: "hide-ai-tasks",
3124+
Env: "CODER_HIDE_AI_TASKS",
3125+
Default: "false",
3126+
Value: &c.HideAITasks,
3127+
Group: &deploymentGroupClient,
3128+
YAML: "hideAITasks",
3129+
},
31193130
}
31203131

31213132
return opts

docs/reference/api/general.md

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

docs/reference/api/schemas.md

Lines changed: 3 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

docs/reference/cli/server.md

Lines changed: 11 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

enterprise/cli/testdata/coder_server_--help.golden

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,9 @@ Clients include the Coder CLI, Coder Desktop, IDE extensions, and the web UI.
8686
is detected. By default it instructs users to update using 'curl -L
8787
https://coder.com/install.sh | sh'.
8888

89+
--hide-ai-tasks bool, $CODER_HIDE_AI_TASKS (default: false)
90+
Hide AI tasks from the dashboard.
91+
8992
--ssh-config-options string-array, $CODER_SSH_CONFIG_OPTIONS
9093
These SSH config options will override the default SSH config options.
9194
Provide options in "key=value" or "key value" format separated by

site/index.html

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
<meta property="regions" content="{{ .Regions }}" />
2626
<meta property="docs-url" content="{{ .DocsURL }}" />
2727
<meta property="logo-url" content="{{ .LogoURL }}" />
28+
<meta property="tasks-tab-visible" content="{{ .TasksTabVisible }}" />
2829
<!-- We need to set data-react-helmet to be able to override it in the workspace page -->
2930
<link
3031
rel="alternate icon"

site/site.go

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,7 @@ type Options struct {
8585
Entitlements *entitlements.Set
8686
Telemetry telemetry.Reporter
8787
Logger slog.Logger
88+
HideAITasks bool
8889
}
8990

9091
func New(opts *Options) *Handler {
@@ -316,6 +317,8 @@ type htmlState struct {
316317
Experiments string
317318
Regions string
318319
DocsURL string
320+
321+
TasksTabVisible string
319322
}
320323

321324
type csrfState struct {
@@ -445,6 +448,7 @@ func (h *Handler) renderHTMLWithState(r *http.Request, filePath string, state ht
445448
var user database.User
446449
var themePreference string
447450
var terminalFont string
451+
var tasksTabVisible bool
448452
orgIDs := []uuid.UUID{}
449453
eg.Go(func() error {
450454
var err error
@@ -480,6 +484,20 @@ func (h *Handler) renderHTMLWithState(r *http.Request, filePath string, state ht
480484
orgIDs = memberIDs[0].OrganizationIDs
481485
return err
482486
})
487+
eg.Go(func() error {
488+
// If HideAITasks is true, force hide the tasks tab
489+
if h.opts.HideAITasks {
490+
tasksTabVisible = false
491+
return nil
492+
}
493+
494+
hasAITask, err := h.opts.Database.HasTemplateVersionsWithAITask(ctx)
495+
if err != nil {
496+
return err
497+
}
498+
tasksTabVisible = hasAITask
499+
return nil
500+
})
483501
err := eg.Wait()
484502
if err == nil {
485503
var wg sync.WaitGroup
@@ -550,6 +568,14 @@ func (h *Handler) renderHTMLWithState(r *http.Request, filePath string, state ht
550568
}
551569
}()
552570
}
571+
wg.Add(1)
572+
go func() {
573+
defer wg.Done()
574+
tasksTabVisible, err := json.Marshal(tasksTabVisible)
575+
if err == nil {
576+
state.TasksTabVisible = html.EscapeString(string(tasksTabVisible))
577+
}
578+
}()
553579
wg.Wait()
554580
}
555581

site/src/api/typesGenerated.ts

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

site/src/hooks/useEmbeddedMetadata.test.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import {
55
MockBuildInfo,
66
MockEntitlements,
77
MockExperiments,
8+
MockTasksTabVisible,
89
MockUserAppearanceSettings,
910
MockUserOwner,
1011
} from "testHelpers/entities";
@@ -41,6 +42,7 @@ const mockDataForTags = {
4142
user: MockUserOwner,
4243
userAppearance: MockUserAppearanceSettings,
4344
regions: MockRegions,
45+
tasksTabVisible: MockTasksTabVisible,
4446
} as const satisfies Record<MetadataKey, MetadataValue>;
4547

4648
const emptyMetadata: RuntimeHtmlMetadata = {
@@ -72,6 +74,10 @@ const emptyMetadata: RuntimeHtmlMetadata = {
7274
available: false,
7375
value: undefined,
7476
},
77+
tasksTabVisible: {
78+
available: false,
79+
value: undefined,
80+
},
7581
};
7682

7783
const populatedMetadata: RuntimeHtmlMetadata = {
@@ -103,6 +109,10 @@ const populatedMetadata: RuntimeHtmlMetadata = {
103109
available: true,
104110
value: MockUserAppearanceSettings,
105111
},
112+
tasksTabVisible: {
113+
available: true,
114+
value: MockTasksTabVisible,
115+
},
106116
};
107117

108118
function seedInitialMetadata(metadataKey: string): () => void {

site/src/hooks/useEmbeddedMetadata.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ type AvailableMetadata = Readonly<{
3030
entitlements: Entitlements;
3131
regions: readonly Region[];
3232
"build-info": BuildInfoResponse;
33+
tasksTabVisible: boolean;
3334
}>;
3435

3536
export type MetadataKey = keyof AvailableMetadata;
@@ -91,6 +92,7 @@ export class MetadataManager implements MetadataManagerApi {
9192
experiments: this.registerValue<Experiments>("experiments"),
9293
"build-info": this.registerValue<BuildInfoResponse>("build-info"),
9394
regions: this.registerRegionValue(),
95+
tasksTabVisible: this.registerValue<boolean>("tasksTabVisible"),
9496
};
9597
}
9698

site/src/testHelpers/entities.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -534,6 +534,8 @@ export const MockUserAppearanceSettings: TypesGen.UserAppearanceSettings = {
534534
terminal_font: "",
535535
};
536536

537+
export const MockTasksTabVisible: boolean = false;
538+
537539
export const MockOrganizationMember: TypesGen.OrganizationMemberWithUserData = {
538540
organization_id: MockOrganization.id,
539541
user_id: MockUserOwner.id,

0 commit comments

Comments
 (0)