mirror of
https://github.com/coder/coder.git
synced 2026-09-24 15:04:27 +08:00
fix(site): display tasks link when no templates contain an AI task (#19184)
Fixes https://github.com/coder/coder/issues/19059 This change ensures we always show the "Tasks" link, even when a deployment doesn't yet have a tasks template set up.
This commit is contained in:
@@ -3617,11 +3617,6 @@ 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()),
|
||||
|
||||
@@ -4826,9 +4826,6 @@ func (s *MethodTestSuite) TestSystemFunctions() {
|
||||
})
|
||||
check.Args(j.ID).Asserts(v.RBACObject(tpl), policy.ActionRead).Returns(j)
|
||||
}))
|
||||
s.Run("HasTemplateVersionsWithAITask", s.Subtest(func(db database.Store, check *expects) {
|
||||
check.Args().Asserts()
|
||||
}))
|
||||
}
|
||||
|
||||
func (s *MethodTestSuite) TestNotifications() {
|
||||
|
||||
@@ -2098,13 +2098,6 @@ 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)
|
||||
|
||||
@@ -4472,21 +4472,6 @@ 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()
|
||||
|
||||
@@ -473,8 +473,6 @@ 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
|
||||
|
||||
@@ -13014,18 +13014,6 @@ 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 (
|
||||
|
||||
@@ -234,7 +234,3 @@ 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);
|
||||
|
||||
+1
-16
@@ -448,7 +448,6 @@ func (h *Handler) renderHTMLWithState(r *http.Request, filePath string, state ht
|
||||
var user database.User
|
||||
var themePreference string
|
||||
var terminalFont string
|
||||
var tasksTabVisible bool
|
||||
orgIDs := []uuid.UUID{}
|
||||
eg.Go(func() error {
|
||||
var err error
|
||||
@@ -484,20 +483,6 @@ func (h *Handler) renderHTMLWithState(r *http.Request, filePath string, state ht
|
||||
orgIDs = memberIDs[0].OrganizationIDs
|
||||
return err
|
||||
})
|
||||
eg.Go(func() error {
|
||||
// If HideAITasks is true, force hide the tasks tab
|
||||
if h.opts.HideAITasks {
|
||||
tasksTabVisible = false
|
||||
return nil
|
||||
}
|
||||
|
||||
hasAITask, err := h.opts.Database.HasTemplateVersionsWithAITask(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
tasksTabVisible = hasAITask
|
||||
return nil
|
||||
})
|
||||
err := eg.Wait()
|
||||
if err == nil {
|
||||
var wg sync.WaitGroup
|
||||
@@ -571,7 +556,7 @@ func (h *Handler) renderHTMLWithState(r *http.Request, filePath string, state ht
|
||||
wg.Add(1)
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
tasksTabVisible, err := json.Marshal(tasksTabVisible)
|
||||
tasksTabVisible, err := json.Marshal(!h.opts.HideAITasks)
|
||||
if err == nil {
|
||||
state.TasksTabVisible = html.EscapeString(string(tasksTabVisible))
|
||||
}
|
||||
|
||||
@@ -13,6 +13,7 @@ import { AvatarData } from "components/Avatar/AvatarData";
|
||||
import { AvatarDataSkeleton } from "components/Avatar/AvatarDataSkeleton";
|
||||
import { Button } from "components/Button/Button";
|
||||
import { displayError } from "components/GlobalSnackbar/utils";
|
||||
import { Link } from "components/Link/Link";
|
||||
import { Margins } from "components/Margins/Margins";
|
||||
import {
|
||||
PageHeader,
|
||||
@@ -60,6 +61,7 @@ import { Helmet } from "react-helmet-async";
|
||||
import { useMutation, useQuery, useQueryClient } from "react-query";
|
||||
import { Link as RouterLink, useNavigate } from "react-router-dom";
|
||||
import TextareaAutosize from "react-textarea-autosize";
|
||||
import { docs } from "utils/docs";
|
||||
import { pageTitle } from "utils/page";
|
||||
import { relativeTime } from "utils/time";
|
||||
import { type UserOption, UsersCombobox } from "./UsersCombobox";
|
||||
@@ -139,7 +141,10 @@ const NoTemplatesPlaceholder: FC = () => {
|
||||
No Task templates found
|
||||
</h3>
|
||||
<span className="text-content-secondary text-sm">
|
||||
Create a Task template to get started
|
||||
<Link href={docs("/ai-coder/tasks")} target="_blank" rel="noreferrer">
|
||||
Learn about Tasks
|
||||
</Link>{" "}
|
||||
to get started.
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user