feat: complete node pool api, sdk and ui

Signed-off-by: allanice001 <allanice001@gmail.com>
This commit is contained in:
allanice001
2025-11-08 10:22:45 +00:00
parent c478a8d10f
commit 334df457ce
130 changed files with 19675 additions and 187 deletions

91
ui/src/api/node_pools.ts Normal file
View File

@@ -0,0 +1,91 @@
import { withRefresh } from "@/api/with-refresh.ts"
import type {
DtoAttachAnnotationsRequest,
DtoAttachLabelsRequest,
DtoAttachServersRequest,
DtoAttachTaintsRequest,
DtoCreateNodePoolRequest,
DtoUpdateNodePoolRequest,
} from "@/sdk"
import { makeNodePoolApi } from "@/sdkClient.ts"
const nodePools = makeNodePoolApi()
export const canAttachToPool = (poolRole: string | undefined, serverRole: string | undefined) => {
if (!poolRole) return true
return poolRole === serverRole
}
export const nodePoolsApi = {
listNodePools: () =>
withRefresh(async () => {
return await nodePools.listNodePools({})
}),
createNodePool: (body: DtoCreateNodePoolRequest) =>
withRefresh(async () => {
return await nodePools.createNodePool({ body })
}),
getNodePool: (id: string) =>
withRefresh(async () => {
return await nodePools.getNodePool({ id })
}),
deleteNodePool: (id: string) =>
withRefresh(async () => {
await nodePools.deleteNodePool({ id })
}),
updateNodePool: (id: string, body: DtoUpdateNodePoolRequest) =>
withRefresh(async () => {
return await nodePools.updateNodePool({ id, body })
}),
// Servers
listNodePoolServers: (id: string) =>
withRefresh(async () => {
return await nodePools.listNodePoolServers({ id })
}),
attachNodePoolServer: (id: string, body: DtoAttachServersRequest) =>
withRefresh(async () => {
return await nodePools.attachNodePoolServers({ id, body })
}),
detachNodePoolServers: (id: string, serverId: string) =>
withRefresh(async () => {
return await nodePools.detachNodePoolServer({ id, serverId })
}),
// Taints
listNodePoolTaints: (id: string) =>
withRefresh(async () => {
return await nodePools.listNodePoolTaints({ id })
}),
attachNodePoolTaints: (id: string, body: DtoAttachTaintsRequest) =>
withRefresh(async () => {
return await nodePools.attachNodePoolTaints({ id, body })
}),
detachNodePoolTaints: (id: string, taintId: string) =>
withRefresh(async () => {
return await nodePools.detachNodePoolTaint({ id, taintId })
}),
// Labels
listNodePoolLabels: (id: string) =>
withRefresh(async () => {
return await nodePools.listNodePoolLabels({ id })
}),
attachNodePoolLabels: (id: string, body: DtoAttachLabelsRequest) =>
withRefresh(async () => {
return await nodePools.attachNodePoolLabels({ id, body })
}),
detachNodePoolLabels: (id: string, labelId: string) =>
withRefresh(async () => {
return await nodePools.detachNodePoolLabel({ id, labelId })
}),
// Annotations
listNodePoolAnnotations: (id: string) =>
withRefresh(async () => {
return await nodePools.listNodePoolAnnotations({ id })
}),
attachNodePoolAnnotations: (id: string, body: DtoAttachAnnotationsRequest) =>
withRefresh(async () => {
return await nodePools.attachNodePoolAnnotations({ id, body })
}),
detachNodePoolAnnotations: (id: string, annotationId: string) =>
withRefresh(async () => {
return await nodePools.detachNodePoolAnnotation({ id, annotationId })
}),
}

View File

@@ -1,10 +1,29 @@
import { withRefresh } from "@/api/with-refresh.ts"
import { orgStore } from "@/auth/org.ts"
import { authStore } from "@/auth/store.ts"
import type { DtoCreateSSHRequest, DtoSshResponse, DtoSshRevealResponse } from "@/sdk"
import { makeSshApi } from "@/sdkClient.ts"
const ssh = makeSshApi()
export type SshDownloadPart = "public" | "private" | "both"
function authHeaders() {
const token = authStore.getAccessToken()
const orgId = orgStore.get()
return {
...(token ? { Authorization: `Bearer ${token}` } : {}),
...(orgId ? { "X-Org-ID": orgId } : {}),
}
}
async function authedFetch(input: RequestInfo | URL, init: RequestInit = {}) {
return fetch(input, {
...init,
headers: { ...(init.headers as any), ...authHeaders() },
credentials: "include", // keep if you rely on cookies/HttpOnly sessions
})
}
export const sshApi = {
listSshKeys: () =>
withRefresh(async (): Promise<DtoSshResponse[]> => {
@@ -42,7 +61,7 @@ export const sshApi = {
url.searchParams.set("part", part)
url.searchParams.set("mode", "json")
const res = await fetch(url.toString())
const res = await authedFetch(url.toString())
if (!res.ok) throw new Error(`Download failed: ${res.statusText}`)
return (await res.json()) as {
id: string
@@ -61,7 +80,7 @@ export const sshApi = {
const url = new URL(`/api/v1/ssh/${id}/download`, window.location.origin)
url.searchParams.set("part", part)
const res = await fetch(url.toString())
const res = await authedFetch(url.toString())
if (!res.ok) throw new Error(`Download failed: ${res.statusText}`)
// Parse filename from Content-Disposition