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.
This commit is contained in:
Hugo Dutka
2025-06-18 18:32:34 +02:00
committed by GitHub
parent 591f5db5f6
commit 8f6a5afa4f
24 changed files with 145 additions and 0 deletions
+5
View File
@@ -3451,6 +3451,11 @@ func (q *querier) GetWorkspacesEligibleForTransition(ctx context.Context, now ti
return q.db.GetWorkspacesEligibleForTransition(ctx, now)
}
func (q *querier) HasTemplateVersionsWithAITask(ctx context.Context) (bool, error) {
// Anyone can call HasTemplateVersionsWithAITask.
return q.db.HasTemplateVersionsWithAITask(ctx)
}
func (q *querier) InsertAPIKey(ctx context.Context, arg database.InsertAPIKeyParams) (database.APIKey, error) {
return insert(q.log, q.auth,
rbac.ResourceApiKey.WithOwner(arg.UserID.String()),
+3
View File
@@ -4566,6 +4566,9 @@ func (s *MethodTestSuite) TestSystemFunctions() {
s.Run("GetProvisionerJobByIDForUpdate", s.Subtest(func(db database.Store, check *expects) {
check.Args(uuid.New()).Asserts(rbac.ResourceProvisionerJobs, policy.ActionRead).Errors(sql.ErrNoRows)
}))
s.Run("HasTemplateVersionsWithAITask", s.Subtest(func(db database.Store, check *expects) {
check.Args().Asserts()
}))
}
func (s *MethodTestSuite) TestNotifications() {
+13
View File
@@ -8495,6 +8495,19 @@ func (q *FakeQuerier) GetWorkspacesEligibleForTransition(ctx context.Context, no
return workspaces, nil
}
func (q *FakeQuerier) HasTemplateVersionsWithAITask(_ context.Context) (bool, error) {
q.mutex.RLock()
defer q.mutex.RUnlock()
for _, templateVersion := range q.templateVersions {
if templateVersion.HasAITask {
return true, nil
}
}
return false, nil
}
func (q *FakeQuerier) InsertAPIKey(_ context.Context, arg database.InsertAPIKeyParams) (database.APIKey, error) {
if err := validateDatabaseType(arg); err != nil {
return database.APIKey{}, err
@@ -2041,6 +2041,13 @@ func (m queryMetricsStore) GetWorkspacesEligibleForTransition(ctx context.Contex
return workspaces, err
}
func (m queryMetricsStore) HasTemplateVersionsWithAITask(ctx context.Context) (bool, error) {
start := time.Now()
r0, r1 := m.s.HasTemplateVersionsWithAITask(ctx)
m.queryLatencies.WithLabelValues("HasTemplateVersionsWithAITask").Observe(time.Since(start).Seconds())
return r0, r1
}
func (m queryMetricsStore) InsertAPIKey(ctx context.Context, arg database.InsertAPIKeyParams) (database.APIKey, error) {
start := time.Now()
key, err := m.s.InsertAPIKey(ctx, arg)
+15
View File
@@ -4292,6 +4292,21 @@ func (mr *MockStoreMockRecorder) GetWorkspacesEligibleForTransition(ctx, now any
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetWorkspacesEligibleForTransition", reflect.TypeOf((*MockStore)(nil).GetWorkspacesEligibleForTransition), ctx, now)
}
// HasTemplateVersionsWithAITask mocks base method.
func (m *MockStore) HasTemplateVersionsWithAITask(ctx context.Context) (bool, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "HasTemplateVersionsWithAITask", ctx)
ret0, _ := ret[0].(bool)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// HasTemplateVersionsWithAITask indicates an expected call of HasTemplateVersionsWithAITask.
func (mr *MockStoreMockRecorder) HasTemplateVersionsWithAITask(ctx any) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "HasTemplateVersionsWithAITask", reflect.TypeOf((*MockStore)(nil).HasTemplateVersionsWithAITask), ctx)
}
// InTx mocks base method.
func (m *MockStore) InTx(arg0 func(database.Store) error, arg1 *database.TxOptions) error {
m.ctrl.T.Helper()
+2
View File
@@ -462,6 +462,8 @@ type sqlcQuerier interface {
GetWorkspacesAndAgentsByOwnerID(ctx context.Context, ownerID uuid.UUID) ([]GetWorkspacesAndAgentsByOwnerIDRow, error)
GetWorkspacesByTemplateID(ctx context.Context, templateID uuid.UUID) ([]WorkspaceTable, error)
GetWorkspacesEligibleForTransition(ctx context.Context, now time.Time) ([]GetWorkspacesEligibleForTransitionRow, error)
// Determines if the template versions table has any rows with has_ai_task = TRUE.
HasTemplateVersionsWithAITask(ctx context.Context) (bool, error)
InsertAPIKey(ctx context.Context, arg InsertAPIKeyParams) (APIKey, error)
// We use the organization_id as the id
// for simplicity since all users is
+12
View File
@@ -11806,6 +11806,18 @@ func (q *sqlQuerier) GetTemplateVersionsCreatedAfter(ctx context.Context, create
return items, nil
}
const hasTemplateVersionsWithAITask = `-- name: HasTemplateVersionsWithAITask :one
SELECT EXISTS (SELECT 1 FROM template_versions WHERE has_ai_task = TRUE)
`
// Determines if the template versions table has any rows with has_ai_task = TRUE.
func (q *sqlQuerier) HasTemplateVersionsWithAITask(ctx context.Context) (bool, error) {
row := q.db.QueryRowContext(ctx, hasTemplateVersionsWithAITask)
var exists bool
err := row.Scan(&exists)
return exists, err
}
const insertTemplateVersion = `-- name: InsertTemplateVersion :exec
INSERT INTO
template_versions (
@@ -226,3 +226,7 @@ FROM
WHERE
template_versions.id IN (archived_versions.id)
RETURNING template_versions.id;
-- name: HasTemplateVersionsWithAITask :one
-- Determines if the template versions table has any rows with has_ai_task = TRUE.
SELECT EXISTS (SELECT 1 FROM template_versions WHERE has_ai_task = TRUE);