mirror of
https://github.com/coder/coder.git
synced 2026-06-02 20:48:20 +00:00
feat(coderd): add owner-related fields to tasks_with_status view (#20471)
Relates to https://github.com/coder/coder/pull/20431/files#diff-9cfc826a6ce7e77d977b2025482474dd263d12965b2a94479a74c7f1d872b782 If the workspace relating to a task was deleted, most of the workspace-related fields in `taskFromDBTaskAndWorkspace` will be zero-valued. However, we can still get information relating to the owner so that "created by" shows up correctly in the UI. Updates the `tasks_with_status` view with a join on `visible_users` to get owner-related info.
This commit is contained in:
+2
-2
@@ -339,8 +339,8 @@ func taskFromDBTaskAndWorkspace(dbTask database.Task, ws codersdk.Workspace) cod
|
||||
ID: dbTask.ID,
|
||||
OrganizationID: dbTask.OrganizationID,
|
||||
OwnerID: dbTask.OwnerID,
|
||||
OwnerName: ws.OwnerName,
|
||||
OwnerAvatarURL: ws.OwnerAvatarURL,
|
||||
OwnerName: dbTask.OwnerUsername,
|
||||
OwnerAvatarURL: dbTask.OwnerAvatarUrl,
|
||||
Name: dbTask.Name,
|
||||
TemplateID: ws.TemplateID,
|
||||
TemplateVersionID: dbTask.TemplateVersionID,
|
||||
|
||||
Generated
+19
-11
@@ -1828,6 +1828,15 @@ CREATE TABLE tasks (
|
||||
deleted_at timestamp with time zone
|
||||
);
|
||||
|
||||
CREATE VIEW visible_users AS
|
||||
SELECT users.id,
|
||||
users.username,
|
||||
users.name,
|
||||
users.avatar_url
|
||||
FROM users;
|
||||
|
||||
COMMENT ON VIEW visible_users IS 'Visible fields of users are allowed to be joined with other tables for including context of other resources.';
|
||||
|
||||
CREATE TABLE workspace_agents (
|
||||
id uuid NOT NULL,
|
||||
created_at timestamp with time zone NOT NULL,
|
||||
@@ -1978,8 +1987,16 @@ CREATE VIEW tasks_with_status AS
|
||||
END AS status,
|
||||
task_app.workspace_build_number,
|
||||
task_app.workspace_agent_id,
|
||||
task_app.workspace_app_id
|
||||
FROM ((((tasks
|
||||
task_app.workspace_app_id,
|
||||
task_owner.owner_username,
|
||||
task_owner.owner_name,
|
||||
task_owner.owner_avatar_url
|
||||
FROM (((((tasks
|
||||
CROSS JOIN LATERAL ( SELECT vu.username AS owner_username,
|
||||
vu.name AS owner_name,
|
||||
vu.avatar_url AS owner_avatar_url
|
||||
FROM visible_users vu
|
||||
WHERE (vu.id = tasks.owner_id)) task_owner)
|
||||
LEFT JOIN LATERAL ( SELECT task_app_1.workspace_build_number,
|
||||
task_app_1.workspace_agent_id,
|
||||
task_app_1.workspace_app_id
|
||||
@@ -2210,15 +2227,6 @@ COMMENT ON COLUMN template_versions.external_auth_providers IS 'IDs of External
|
||||
|
||||
COMMENT ON COLUMN template_versions.message IS 'Message describing the changes in this version of the template, similar to a Git commit message. Like a commit message, this should be a short, high-level description of the changes in this version of the template. This message is immutable and should not be updated after the fact.';
|
||||
|
||||
CREATE VIEW visible_users AS
|
||||
SELECT users.id,
|
||||
users.username,
|
||||
users.name,
|
||||
users.avatar_url
|
||||
FROM users;
|
||||
|
||||
COMMENT ON VIEW visible_users IS 'Visible fields of users are allowed to be joined with other tables for including context of other resources.';
|
||||
|
||||
CREATE VIEW template_version_with_user AS
|
||||
SELECT template_versions.id,
|
||||
template_versions.template_id,
|
||||
|
||||
@@ -0,0 +1,74 @@
|
||||
-- Drop view from 000390_tasks_with_status_user_fields.up.sql.
|
||||
DROP VIEW IF EXISTS tasks_with_status;
|
||||
|
||||
-- Restore from 000382_add_columns_to_tasks_with_status.up.sql.
|
||||
CREATE VIEW
|
||||
tasks_with_status
|
||||
AS
|
||||
SELECT
|
||||
tasks.*,
|
||||
CASE
|
||||
WHEN tasks.workspace_id IS NULL OR latest_build.job_status IS NULL THEN 'pending'::task_status
|
||||
|
||||
WHEN latest_build.job_status = 'failed' THEN 'error'::task_status
|
||||
|
||||
WHEN latest_build.transition IN ('stop', 'delete')
|
||||
AND latest_build.job_status = 'succeeded' THEN 'paused'::task_status
|
||||
|
||||
WHEN latest_build.transition = 'start'
|
||||
AND latest_build.job_status = 'pending' THEN 'initializing'::task_status
|
||||
|
||||
WHEN latest_build.transition = 'start' AND latest_build.job_status IN ('running', 'succeeded') THEN
|
||||
CASE
|
||||
WHEN agent_status.none THEN 'initializing'::task_status
|
||||
WHEN agent_status.connecting THEN 'initializing'::task_status
|
||||
WHEN agent_status.connected THEN
|
||||
CASE
|
||||
WHEN app_status.any_unhealthy THEN 'error'::task_status
|
||||
WHEN app_status.any_initializing THEN 'initializing'::task_status
|
||||
WHEN app_status.all_healthy_or_disabled THEN 'active'::task_status
|
||||
ELSE 'unknown'::task_status
|
||||
END
|
||||
ELSE 'unknown'::task_status
|
||||
END
|
||||
|
||||
ELSE 'unknown'::task_status
|
||||
END AS status,
|
||||
task_app.*
|
||||
FROM
|
||||
tasks
|
||||
LEFT JOIN LATERAL (
|
||||
SELECT workspace_build_number, workspace_agent_id, workspace_app_id
|
||||
FROM task_workspace_apps task_app
|
||||
WHERE task_id = tasks.id
|
||||
ORDER BY workspace_build_number DESC
|
||||
LIMIT 1
|
||||
) task_app ON TRUE
|
||||
LEFT JOIN LATERAL (
|
||||
SELECT
|
||||
workspace_build.transition,
|
||||
provisioner_job.job_status,
|
||||
workspace_build.job_id
|
||||
FROM workspace_builds workspace_build
|
||||
JOIN provisioner_jobs provisioner_job ON provisioner_job.id = workspace_build.job_id
|
||||
WHERE workspace_build.workspace_id = tasks.workspace_id
|
||||
AND workspace_build.build_number = task_app.workspace_build_number
|
||||
) latest_build ON TRUE
|
||||
CROSS JOIN LATERAL (
|
||||
SELECT
|
||||
COUNT(*) = 0 AS none,
|
||||
bool_or(workspace_agent.lifecycle_state IN ('created', 'starting')) AS connecting,
|
||||
bool_and(workspace_agent.lifecycle_state = 'ready') AS connected
|
||||
FROM workspace_agents workspace_agent
|
||||
WHERE workspace_agent.id = task_app.workspace_agent_id
|
||||
) agent_status
|
||||
CROSS JOIN LATERAL (
|
||||
SELECT
|
||||
bool_or(workspace_app.health = 'unhealthy') AS any_unhealthy,
|
||||
bool_or(workspace_app.health = 'initializing') AS any_initializing,
|
||||
bool_and(workspace_app.health IN ('healthy', 'disabled')) AS all_healthy_or_disabled
|
||||
FROM workspace_apps workspace_app
|
||||
WHERE workspace_app.id = task_app.workspace_app_id
|
||||
) app_status
|
||||
WHERE
|
||||
tasks.deleted_at IS NULL;
|
||||
@@ -0,0 +1,84 @@
|
||||
-- Drop view from 00037_add_columns_to_tasks_with_status.up.sql.
|
||||
DROP VIEW IF EXISTS tasks_with_status;
|
||||
|
||||
-- Add owner_name, owner_avatar_url columns.
|
||||
CREATE VIEW
|
||||
tasks_with_status
|
||||
AS
|
||||
SELECT
|
||||
tasks.*,
|
||||
CASE
|
||||
WHEN tasks.workspace_id IS NULL OR latest_build.job_status IS NULL THEN 'pending'::task_status
|
||||
|
||||
WHEN latest_build.job_status = 'failed' THEN 'error'::task_status
|
||||
|
||||
WHEN latest_build.transition IN ('stop', 'delete')
|
||||
AND latest_build.job_status = 'succeeded' THEN 'paused'::task_status
|
||||
|
||||
WHEN latest_build.transition = 'start'
|
||||
AND latest_build.job_status = 'pending' THEN 'initializing'::task_status
|
||||
|
||||
WHEN latest_build.transition = 'start' AND latest_build.job_status IN ('running', 'succeeded') THEN
|
||||
CASE
|
||||
WHEN agent_status.none THEN 'initializing'::task_status
|
||||
WHEN agent_status.connecting THEN 'initializing'::task_status
|
||||
WHEN agent_status.connected THEN
|
||||
CASE
|
||||
WHEN app_status.any_unhealthy THEN 'error'::task_status
|
||||
WHEN app_status.any_initializing THEN 'initializing'::task_status
|
||||
WHEN app_status.all_healthy_or_disabled THEN 'active'::task_status
|
||||
ELSE 'unknown'::task_status
|
||||
END
|
||||
ELSE 'unknown'::task_status
|
||||
END
|
||||
|
||||
ELSE 'unknown'::task_status
|
||||
END AS status,
|
||||
task_app.*,
|
||||
task_owner.*
|
||||
FROM
|
||||
tasks
|
||||
CROSS JOIN LATERAL (
|
||||
SELECT
|
||||
vu.username AS owner_username,
|
||||
vu.name AS owner_name,
|
||||
vu.avatar_url AS owner_avatar_url
|
||||
FROM visible_users vu
|
||||
WHERE vu.id = tasks.owner_id
|
||||
) task_owner
|
||||
LEFT JOIN LATERAL (
|
||||
SELECT workspace_build_number, workspace_agent_id, workspace_app_id
|
||||
FROM task_workspace_apps task_app
|
||||
WHERE task_id = tasks.id
|
||||
ORDER BY workspace_build_number DESC
|
||||
LIMIT 1
|
||||
) task_app ON TRUE
|
||||
LEFT JOIN LATERAL (
|
||||
SELECT
|
||||
workspace_build.transition,
|
||||
provisioner_job.job_status,
|
||||
workspace_build.job_id
|
||||
FROM workspace_builds workspace_build
|
||||
JOIN provisioner_jobs provisioner_job ON provisioner_job.id = workspace_build.job_id
|
||||
WHERE workspace_build.workspace_id = tasks.workspace_id
|
||||
AND workspace_build.build_number = task_app.workspace_build_number
|
||||
) latest_build ON TRUE
|
||||
CROSS JOIN LATERAL (
|
||||
SELECT
|
||||
COUNT(*) = 0 AS none,
|
||||
bool_or(workspace_agent.lifecycle_state IN ('created', 'starting')) AS connecting,
|
||||
bool_and(workspace_agent.lifecycle_state = 'ready') AS connected
|
||||
FROM workspace_agents workspace_agent
|
||||
WHERE workspace_agent.id = task_app.workspace_agent_id
|
||||
) agent_status
|
||||
CROSS JOIN LATERAL (
|
||||
SELECT
|
||||
bool_or(workspace_app.health = 'unhealthy') AS any_unhealthy,
|
||||
bool_or(workspace_app.health = 'initializing') AS any_initializing,
|
||||
bool_and(workspace_app.health IN ('healthy', 'disabled')) AS all_healthy_or_disabled
|
||||
FROM workspace_apps workspace_app
|
||||
WHERE workspace_app.id = task_app.workspace_app_id
|
||||
) app_status
|
||||
WHERE
|
||||
tasks.deleted_at IS NULL;
|
||||
|
||||
@@ -4221,6 +4221,9 @@ type Task struct {
|
||||
WorkspaceBuildNumber sql.NullInt32 `db:"workspace_build_number" json:"workspace_build_number"`
|
||||
WorkspaceAgentID uuid.NullUUID `db:"workspace_agent_id" json:"workspace_agent_id"`
|
||||
WorkspaceAppID uuid.NullUUID `db:"workspace_app_id" json:"workspace_app_id"`
|
||||
OwnerUsername string `db:"owner_username" json:"owner_username"`
|
||||
OwnerName string `db:"owner_name" json:"owner_name"`
|
||||
OwnerAvatarUrl string `db:"owner_avatar_url" json:"owner_avatar_url"`
|
||||
}
|
||||
|
||||
type TaskTable struct {
|
||||
|
||||
@@ -12964,7 +12964,7 @@ func (q *sqlQuerier) DeleteTask(ctx context.Context, arg DeleteTaskParams) (Task
|
||||
}
|
||||
|
||||
const getTaskByID = `-- name: GetTaskByID :one
|
||||
SELECT id, organization_id, owner_id, name, workspace_id, template_version_id, template_parameters, prompt, created_at, deleted_at, status, workspace_build_number, workspace_agent_id, workspace_app_id FROM tasks_with_status WHERE id = $1::uuid
|
||||
SELECT id, organization_id, owner_id, name, workspace_id, template_version_id, template_parameters, prompt, created_at, deleted_at, status, workspace_build_number, workspace_agent_id, workspace_app_id, owner_username, owner_name, owner_avatar_url FROM tasks_with_status WHERE id = $1::uuid
|
||||
`
|
||||
|
||||
func (q *sqlQuerier) GetTaskByID(ctx context.Context, id uuid.UUID) (Task, error) {
|
||||
@@ -12985,12 +12985,15 @@ func (q *sqlQuerier) GetTaskByID(ctx context.Context, id uuid.UUID) (Task, error
|
||||
&i.WorkspaceBuildNumber,
|
||||
&i.WorkspaceAgentID,
|
||||
&i.WorkspaceAppID,
|
||||
&i.OwnerUsername,
|
||||
&i.OwnerName,
|
||||
&i.OwnerAvatarUrl,
|
||||
)
|
||||
return i, err
|
||||
}
|
||||
|
||||
const getTaskByWorkspaceID = `-- name: GetTaskByWorkspaceID :one
|
||||
SELECT id, organization_id, owner_id, name, workspace_id, template_version_id, template_parameters, prompt, created_at, deleted_at, status, workspace_build_number, workspace_agent_id, workspace_app_id FROM tasks_with_status WHERE workspace_id = $1::uuid
|
||||
SELECT id, organization_id, owner_id, name, workspace_id, template_version_id, template_parameters, prompt, created_at, deleted_at, status, workspace_build_number, workspace_agent_id, workspace_app_id, owner_username, owner_name, owner_avatar_url FROM tasks_with_status WHERE workspace_id = $1::uuid
|
||||
`
|
||||
|
||||
func (q *sqlQuerier) GetTaskByWorkspaceID(ctx context.Context, workspaceID uuid.UUID) (Task, error) {
|
||||
@@ -13011,6 +13014,9 @@ func (q *sqlQuerier) GetTaskByWorkspaceID(ctx context.Context, workspaceID uuid.
|
||||
&i.WorkspaceBuildNumber,
|
||||
&i.WorkspaceAgentID,
|
||||
&i.WorkspaceAppID,
|
||||
&i.OwnerUsername,
|
||||
&i.OwnerName,
|
||||
&i.OwnerAvatarUrl,
|
||||
)
|
||||
return i, err
|
||||
}
|
||||
@@ -13064,7 +13070,7 @@ func (q *sqlQuerier) InsertTask(ctx context.Context, arg InsertTaskParams) (Task
|
||||
}
|
||||
|
||||
const listTasks = `-- name: ListTasks :many
|
||||
SELECT id, organization_id, owner_id, name, workspace_id, template_version_id, template_parameters, prompt, created_at, deleted_at, status, workspace_build_number, workspace_agent_id, workspace_app_id FROM tasks_with_status tws
|
||||
SELECT id, organization_id, owner_id, name, workspace_id, template_version_id, template_parameters, prompt, created_at, deleted_at, status, workspace_build_number, workspace_agent_id, workspace_app_id, owner_username, owner_name, owner_avatar_url FROM tasks_with_status tws
|
||||
WHERE tws.deleted_at IS NULL
|
||||
AND CASE WHEN $1::UUID != '00000000-0000-0000-0000-000000000000' THEN tws.owner_id = $1::UUID ELSE TRUE END
|
||||
AND CASE WHEN $2::UUID != '00000000-0000-0000-0000-000000000000' THEN tws.organization_id = $2::UUID ELSE TRUE END
|
||||
@@ -13102,6 +13108,9 @@ func (q *sqlQuerier) ListTasks(ctx context.Context, arg ListTasksParams) ([]Task
|
||||
&i.WorkspaceBuildNumber,
|
||||
&i.WorkspaceAgentID,
|
||||
&i.WorkspaceAppID,
|
||||
&i.OwnerUsername,
|
||||
&i.OwnerName,
|
||||
&i.OwnerAvatarUrl,
|
||||
); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user