mirror of
https://github.com/coder/coder.git
synced 2026-09-24 15:04:27 +08:00
feat: workspace filter query supported in backend (#2232)
* feat: add support for template in workspace filter * feat: Implement workspace search filter to support names * Use new query param parser for pagination fields * Remove excessive calls, use filters on a single query Co-authored-by: Garrett <garrett@coder.com>
This commit is contained in:
@@ -118,10 +118,10 @@ describe("api.ts", () => {
|
||||
it.each<[TypesGen.WorkspaceFilter | undefined, string]>([
|
||||
[undefined, "/api/v2/workspaces"],
|
||||
|
||||
[{ organization_id: "1", owner: "" }, "/api/v2/workspaces?organization_id=1"],
|
||||
[{ organization_id: "", owner: "1" }, "/api/v2/workspaces?owner=1"],
|
||||
[{ q: "" }, "/api/v2/workspaces"],
|
||||
[{ q: "owner:1" }, "/api/v2/workspaces?q=owner%3A1"],
|
||||
|
||||
[{ organization_id: "1", owner: "me" }, "/api/v2/workspaces?organization_id=1&owner=me"],
|
||||
[{ q: "owner:me" }, "/api/v2/workspaces?q=owner%3Ame"],
|
||||
])(`getWorkspacesURL(%p) returns %p`, (filter, expected) => {
|
||||
expect(getWorkspacesURL(filter)).toBe(expected)
|
||||
})
|
||||
|
||||
+2
-8
@@ -120,14 +120,8 @@ export const getWorkspacesURL = (filter?: TypesGen.WorkspaceFilter): string => {
|
||||
const basePath = "/api/v2/workspaces"
|
||||
const searchParams = new URLSearchParams()
|
||||
|
||||
if (filter?.organization_id) {
|
||||
searchParams.append("organization_id", filter.organization_id)
|
||||
}
|
||||
if (filter?.owner) {
|
||||
searchParams.append("owner", filter.owner)
|
||||
}
|
||||
if (filter?.name) {
|
||||
searchParams.append("name", filter.name)
|
||||
if (filter?.q && filter.q !== "") {
|
||||
searchParams.append("q", filter.q)
|
||||
}
|
||||
|
||||
const searchString = searchParams.toString()
|
||||
|
||||
@@ -90,7 +90,7 @@ export interface CreateUserRequest {
|
||||
readonly organization_id: string
|
||||
}
|
||||
|
||||
// From codersdk/workspaces.go:34:6
|
||||
// From codersdk/workspaces.go:35:6
|
||||
export interface CreateWorkspaceBuildRequest {
|
||||
readonly template_version_id?: string
|
||||
readonly transition: WorkspaceTransition
|
||||
@@ -223,7 +223,7 @@ export interface ProvisionerJobLog {
|
||||
readonly output: string
|
||||
}
|
||||
|
||||
// From codersdk/workspaces.go:201:6
|
||||
// From codersdk/workspaces.go:202:6
|
||||
export interface PutExtendWorkspaceRequest {
|
||||
readonly deadline: string
|
||||
}
|
||||
@@ -311,12 +311,12 @@ export interface UpdateUserProfileRequest {
|
||||
readonly username: string
|
||||
}
|
||||
|
||||
// From codersdk/workspaces.go:160:6
|
||||
// From codersdk/workspaces.go:161:6
|
||||
export interface UpdateWorkspaceAutostartRequest {
|
||||
readonly schedule?: string
|
||||
}
|
||||
|
||||
// From codersdk/workspaces.go:180:6
|
||||
// From codersdk/workspaces.go:181:6
|
||||
export interface UpdateWorkspaceTTLRequest {
|
||||
readonly ttl_ms?: number
|
||||
}
|
||||
@@ -371,7 +371,7 @@ export interface UsersRequest extends Pagination {
|
||||
readonly status?: string
|
||||
}
|
||||
|
||||
// From codersdk/workspaces.go:18:6
|
||||
// From codersdk/workspaces.go:19:6
|
||||
export interface Workspace {
|
||||
readonly id: string
|
||||
readonly created_at: string
|
||||
@@ -461,19 +461,17 @@ export interface WorkspaceBuild {
|
||||
readonly deadline: string
|
||||
}
|
||||
|
||||
// From codersdk/workspaces.go:83:6
|
||||
// From codersdk/workspaces.go:84:6
|
||||
export interface WorkspaceBuildsRequest extends Pagination {
|
||||
readonly WorkspaceID: string
|
||||
}
|
||||
|
||||
// From codersdk/workspaces.go:219:6
|
||||
// From codersdk/workspaces.go:220:6
|
||||
export interface WorkspaceFilter {
|
||||
readonly organization_id?: string
|
||||
readonly owner?: string
|
||||
readonly name?: string
|
||||
readonly q?: string
|
||||
}
|
||||
|
||||
// From codersdk/workspaces.go:41:6
|
||||
// From codersdk/workspaces.go:42:6
|
||||
export interface WorkspaceOptions {
|
||||
readonly include_deleted?: boolean
|
||||
}
|
||||
|
||||
@@ -104,13 +104,13 @@ describe("util > workspace", () => {
|
||||
describe("workspaceQueryToFilter", () => {
|
||||
it.each<[string | undefined, TypesGen.WorkspaceFilter]>([
|
||||
[undefined, {}],
|
||||
["", {}],
|
||||
["asdkfvjn", { name: "asdkfvjn" }],
|
||||
["owner:me", { owner: "me" }],
|
||||
["owner:me owner:me2", { owner: "me" }],
|
||||
["me/dev", { owner: "me", name: "dev" }],
|
||||
["me/", { owner: "me" }],
|
||||
[" key:val owner:me ", { owner: "me" }],
|
||||
["", { q: "" }],
|
||||
["asdkfvjn", { q: "asdkfvjn" }],
|
||||
["owner:me", { q: "owner:me" }],
|
||||
["owner:me owner:me2", { q: "owner:me owner:me2" }],
|
||||
["me/dev", { q: "me/dev" }],
|
||||
["me/", { q: "me/" }],
|
||||
[" key:val owner:me ", { q: "key:val owner:me" }],
|
||||
])(`query=%p, filter=%p`, (query, filter) => {
|
||||
expect(workspaceQueryToFilter(query)).toEqual(filter)
|
||||
})
|
||||
|
||||
@@ -263,42 +263,9 @@ export const defaultWorkspaceExtension = (__startDate?: dayjs.Dayjs): TypesGen.P
|
||||
}
|
||||
|
||||
export const workspaceQueryToFilter = (query?: string): TypesGen.WorkspaceFilter => {
|
||||
const defaultFilter: TypesGen.WorkspaceFilter = {}
|
||||
const preparedQuery = query?.trim().replace(/ +/g, " ")
|
||||
|
||||
if (!preparedQuery) {
|
||||
return defaultFilter
|
||||
} else {
|
||||
const parts = preparedQuery.split(" ")
|
||||
|
||||
for (const part of parts) {
|
||||
if (part.includes(":")) {
|
||||
const [key, val] = part.split(":")
|
||||
if (key && val) {
|
||||
if (key === "owner") {
|
||||
return {
|
||||
owner: val,
|
||||
}
|
||||
}
|
||||
// skip invalid key pairs
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
if (part.includes("/")) {
|
||||
const [username, name] = part.split("/")
|
||||
return {
|
||||
owner: username,
|
||||
name: name === "" ? undefined : name,
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
name: part,
|
||||
}
|
||||
}
|
||||
|
||||
return defaultFilter
|
||||
return {
|
||||
q: preparedQuery,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user