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:
Steven Masley
2022-06-14 08:46:33 -05:00
committed by GitHub
co-authored by Garrett
parent 5be52de593
commit dc1de58857
20 changed files with 1068 additions and 464 deletions
+3 -3
View File
@@ -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
View File
@@ -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()
+9 -11
View File
@@ -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
}
+7 -7
View File
@@ -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)
})
+2 -35
View File
@@ -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,
}
}