feat: filter for running workspaces (#4157)

* Refactor workspaces xservice

* Remove layout comment

* Format

* Add comments

* Add running workspaces filter to frontend

* Start on backend - add status to filter

* Update sql and add test - wip

* Attempt to unconvert status for easier querying

* Fix syntax

* Join jobs table, untested

* sql

* Add Status to GetAuthorizedWorkspaces

* Update job tests to have canceled time

* fmt

* add status filter to database fake

Co-authored-by: Colin Adler <colin1adler@gmail.com>
This commit is contained in:
Presley Pizzo
2022-10-11 13:50:41 -04:00
committed by GitHub
parent aefb477e21
commit 62357084ba
15 changed files with 434 additions and 99 deletions

View File

@ -5431,48 +5431,133 @@ func (q *sqlQuerier) GetWorkspaceOwnerCountsByTemplateIDs(ctx context.Context, i
const getWorkspaces = `-- name: GetWorkspaces :many
SELECT
id, created_at, updated_at, owner_id, organization_id, template_id, deleted, name, autostart_schedule, ttl, last_used_at
workspaces.id, workspaces.created_at, workspaces.updated_at, workspaces.owner_id, workspaces.organization_id, workspaces.template_id, workspaces.deleted, workspaces.name, workspaces.autostart_schedule, workspaces.ttl, workspaces.last_used_at
FROM
workspaces
workspaces
LEFT JOIN LATERAL (
SELECT
workspace_builds.transition,
provisioner_jobs.started_at,
provisioner_jobs.updated_at,
provisioner_jobs.canceled_at,
provisioner_jobs.completed_at,
provisioner_jobs.error
FROM
workspace_builds
LEFT JOIN
provisioner_jobs
ON
provisioner_jobs.id = workspace_builds.job_id
WHERE
workspace_builds.workspace_id = workspaces.id
ORDER BY
build_number DESC
LIMIT
1
) latest_build ON TRUE
WHERE
-- Optionally include deleted workspaces
-- Optionally include deleted workspaces
workspaces.deleted = $1
-- Filter by owner_id
AND CASE
WHEN $2 :: uuid != '00000000-00000000-00000000-00000000' THEN
owner_id = $2
WHEN $2 :: text != '' THEN
CASE
WHEN $2 = 'pending' THEN
latest_build.started_at IS NULL
WHEN $2 = 'starting' THEN
latest_build.started_at IS NOT NULL AND
latest_build.canceled_at IS NULL AND
latest_build.completed_at IS NULL AND
latest_build.updated_at - INTERVAL '30 seconds' < NOW() AND
latest_build.transition = 'start'::workspace_transition
WHEN $2 = 'running' THEN
latest_build.completed_at IS NOT NULL AND
latest_build.canceled_at IS NULL AND
latest_build.error IS NULL AND
latest_build.transition = 'start'::workspace_transition
WHEN $2 = 'stopping' THEN
latest_build.started_at IS NOT NULL AND
latest_build.canceled_at IS NULL AND
latest_build.completed_at IS NULL AND
latest_build.updated_at - INTERVAL '30 seconds' < NOW() AND
latest_build.transition = 'stop'::workspace_transition
WHEN $2 = 'stopped' THEN
latest_build.completed_at IS NOT NULL AND
latest_build.canceled_at IS NULL AND
latest_build.error IS NULL AND
latest_build.transition = 'stop'::workspace_transition
WHEN $2 = 'failed' THEN
(latest_build.canceled_at IS NOT NULL AND
latest_build.error IS NOT NULL) OR
(latest_build.completed_at IS NOT NULL AND
latest_build.error IS NOT NULL)
WHEN $2 = 'canceling' THEN
latest_build.canceled_at IS NOT NULL AND
latest_build.completed_at IS NULL
WHEN $2 = 'canceled' THEN
latest_build.canceled_at IS NOT NULL AND
latest_build.completed_at IS NOT NULL
WHEN $2 = 'deleted' THEN
latest_build.started_at IS NOT NULL AND
latest_build.canceled_at IS NULL AND
latest_build.completed_at IS NOT NULL AND
latest_build.updated_at - INTERVAL '30 seconds' < NOW() AND
latest_build.transition = 'delete'::workspace_transition
WHEN $2 = 'deleting' THEN
latest_build.completed_at IS NOT NULL AND
latest_build.canceled_at IS NULL AND
latest_build.error IS NULL AND
latest_build.transition = 'delete'::workspace_transition
ELSE
true
END
ELSE true
END
-- Filter by owner_name
-- Filter by owner_id
AND CASE
WHEN $3 :: text != '' THEN
owner_id = (SELECT id FROM users WHERE lower(username) = lower($3))
WHEN $3 :: uuid != '00000000-00000000-00000000-00000000' THEN
owner_id = $3
ELSE true
END
-- Filter by owner_name
AND CASE
WHEN $4 :: text != '' THEN
owner_id = (SELECT id FROM users WHERE lower(username) = lower($4))
ELSE true
END
-- Filter by template_name
-- There can be more than 1 template with the same name across organizations.
-- Use the organization filter to restrict to 1 org if needed.
-- Use the organization filter to restrict to 1 org if needed.
AND CASE
WHEN $4 :: text != '' THEN
template_id = ANY(SELECT id FROM templates WHERE lower(name) = lower($4))
WHEN $5 :: text != '' THEN
template_id = ANY(SELECT id FROM templates WHERE lower(name) = lower($5))
ELSE true
END
-- Filter by template_ids
AND CASE
WHEN array_length($5 :: uuid[], 1) > 0 THEN
template_id = ANY($5)
WHEN array_length($6 :: uuid[], 1) > 0 THEN
template_id = ANY($6)
ELSE true
END
-- Filter by name, matching on substring
AND CASE
WHEN $6 :: text != '' THEN
name ILIKE '%' || $6 || '%'
WHEN $7 :: text != '' THEN
name ILIKE '%' || $7 || '%'
ELSE true
END
`
type GetWorkspacesParams struct {
Deleted bool `db:"deleted" json:"deleted"`
Status string `db:"status" json:"status"`
OwnerID uuid.UUID `db:"owner_id" json:"owner_id"`
OwnerUsername string `db:"owner_username" json:"owner_username"`
TemplateName string `db:"template_name" json:"template_name"`
@ -5483,6 +5568,7 @@ type GetWorkspacesParams struct {
func (q *sqlQuerier) GetWorkspaces(ctx context.Context, arg GetWorkspacesParams) ([]Workspace, error) {
rows, err := q.db.QueryContext(ctx, getWorkspaces,
arg.Deleted,
arg.Status,
arg.OwnerID,
arg.OwnerUsername,
arg.TemplateName,