mirror of
https://github.com/fosrl/pangolin.git
synced 2026-08-06 04:31:22 +02:00
add basic ui for private inference resource
This commit is contained in:
@@ -42,6 +42,7 @@ export type PrivateResourceFormValues = {
|
||||
roles?: PrivateResourceAccessTag[];
|
||||
users?: PrivateResourceAccessTag[];
|
||||
clients?: PrivateResourceClient[];
|
||||
providerIds?: number[];
|
||||
};
|
||||
|
||||
export type SiteResourceAccess = {
|
||||
@@ -220,7 +221,11 @@ export function buildCreateSiteResourcePayload(
|
||||
typeof data.alias === "string" &&
|
||||
data.alias.trim()
|
||||
? data.alias
|
||||
: undefined
|
||||
: undefined,
|
||||
aiProviders: (data.providerIds ?? []).map((providerId) => ({
|
||||
providerId,
|
||||
modelAccessMode: "catalog" as const
|
||||
}))
|
||||
}),
|
||||
...((data.mode === "host" || data.mode === "cidr") && {
|
||||
tcpPortRangeString: data.tcpPortRangeString,
|
||||
@@ -353,19 +358,33 @@ export function siteResourceToFormValues(
|
||||
};
|
||||
}
|
||||
|
||||
export function createGeneralFormSchema(t: TranslateFn) {
|
||||
return z.object({
|
||||
name: z
|
||||
.string()
|
||||
.min(1, t("editInternalResourceDialogNameRequired"))
|
||||
.max(255, t("editInternalResourceDialogNameMaxLength")),
|
||||
niceId: z
|
||||
.string()
|
||||
.min(1)
|
||||
.max(255)
|
||||
.regex(/^[a-zA-Z0-9-]+$/),
|
||||
enabled: z.boolean()
|
||||
});
|
||||
export function createGeneralFormSchema(
|
||||
t: TranslateFn,
|
||||
options?: { requireAlias?: boolean }
|
||||
) {
|
||||
return z
|
||||
.object({
|
||||
name: z
|
||||
.string()
|
||||
.min(1, t("editInternalResourceDialogNameRequired"))
|
||||
.max(255, t("editInternalResourceDialogNameMaxLength")),
|
||||
niceId: z
|
||||
.string()
|
||||
.min(1)
|
||||
.max(255)
|
||||
.regex(/^[a-zA-Z0-9-]+$/),
|
||||
enabled: z.boolean(),
|
||||
alias: z.string().nullish()
|
||||
})
|
||||
.superRefine((data, ctx) => {
|
||||
if (options?.requireAlias && !data.alias?.trim()) {
|
||||
ctx.addIssue({
|
||||
code: z.ZodIssueCode.custom,
|
||||
message: t("aiResourceAliasRequired"),
|
||||
path: ["alias"]
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
export function createAccessFormSchema() {
|
||||
@@ -422,7 +441,8 @@ export function createCreateFormSchema(t: TranslateFn) {
|
||||
pamMode: z.enum(["passthrough", "push"]).optional().nullable(),
|
||||
tcpPortRangeString: createPortRangeStringSchema(t),
|
||||
udpPortRangeString: createPortRangeStringSchema(t),
|
||||
disableIcmp: z.boolean().optional()
|
||||
disableIcmp: z.boolean().optional(),
|
||||
providerIds: z.array(z.number().int().positive()).optional()
|
||||
})
|
||||
.superRefine((data, ctx) => {
|
||||
const isNativeSsh =
|
||||
@@ -434,12 +454,27 @@ export function createCreateFormSchema(t: TranslateFn) {
|
||||
) {
|
||||
ctx.addIssue({
|
||||
code: z.ZodIssueCode.custom,
|
||||
message: t(
|
||||
"createInternalResourceDialogPleaseSelectSite"
|
||||
),
|
||||
message: t("createInternalResourceDialogPleaseSelectSite"),
|
||||
path: ["siteIds"]
|
||||
});
|
||||
}
|
||||
if (data.mode === "inference") {
|
||||
const trimmedAlias = data.alias?.trim();
|
||||
if (!trimmedAlias) {
|
||||
ctx.addIssue({
|
||||
code: z.ZodIssueCode.custom,
|
||||
message: t("aiResourceAliasRequired"),
|
||||
path: ["alias"]
|
||||
});
|
||||
}
|
||||
if (!data.providerIds || data.providerIds.length < 1) {
|
||||
ctx.addIssue({
|
||||
code: z.ZodIssueCode.custom,
|
||||
message: t("aiResourceProvidersRequired"),
|
||||
path: ["providerIds"]
|
||||
});
|
||||
}
|
||||
}
|
||||
if (
|
||||
data.mode !== "ssh" &&
|
||||
data.mode !== "inference" &&
|
||||
@@ -592,9 +627,26 @@ export function createInferenceFormSchema(t: TranslateFn) {
|
||||
return z
|
||||
.object({
|
||||
mode: z.literal("inference"),
|
||||
alias: z.string().nullish()
|
||||
alias: z.string().nullish(),
|
||||
providerIds: z.array(z.number().int().positive()).optional()
|
||||
})
|
||||
.superRefine((data, ctx) => destinationRefine(data, ctx, t));
|
||||
.superRefine((data, ctx) => {
|
||||
const trimmedAlias = data.alias?.trim();
|
||||
if (!trimmedAlias) {
|
||||
ctx.addIssue({
|
||||
code: z.ZodIssueCode.custom,
|
||||
message: t("aiResourceAliasRequired"),
|
||||
path: ["alias"]
|
||||
});
|
||||
}
|
||||
if (!data.providerIds || data.providerIds.length < 1) {
|
||||
ctx.addIssue({
|
||||
code: z.ZodIssueCode.custom,
|
||||
message: t("aiResourceProvidersRequired"),
|
||||
path: ["providerIds"]
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
export function createCidrFormSchema(t: TranslateFn) {
|
||||
|
||||
@@ -57,6 +57,10 @@ import type {
|
||||
} from "@server/routers/siteResource";
|
||||
import type { GetSiteResourceResponse } from "@server/routers/siteResource/getSiteResource";
|
||||
import type { ListTargetsResponse } from "@server/routers/target";
|
||||
import type {
|
||||
ListAiModelsResponse,
|
||||
ListAiProvidersResponse
|
||||
} from "@server/routers/aiProvider/types";
|
||||
import type { ListUsersResponse } from "@server/routers/user";
|
||||
import type ResponseT from "@server/types/Response";
|
||||
import {
|
||||
@@ -1174,6 +1178,36 @@ export const aiProviderQueries = {
|
||||
|
||||
return res.data.data.targets;
|
||||
}
|
||||
}),
|
||||
providerModels: ({ providerId }: { providerId: number }) =>
|
||||
queryOptions({
|
||||
queryKey: ["AI_PROVIDERS", providerId, "MODELS"] as const,
|
||||
queryFn: async ({ signal, meta }) => {
|
||||
const res = await meta!.api.get<
|
||||
AxiosResponse<ListAiModelsResponse>
|
||||
>(`/ai-provider/${providerId}/models`, {
|
||||
params: { page: 1, pageSize: 1000 },
|
||||
signal
|
||||
});
|
||||
return res.data.data.models;
|
||||
}
|
||||
}),
|
||||
orgProviders: ({ orgId, query }: { orgId: string; query?: string }) =>
|
||||
queryOptions({
|
||||
queryKey: ["AI_PROVIDERS", orgId, "LIST", query ?? ""] as const,
|
||||
queryFn: async ({ signal, meta }) => {
|
||||
const res = await meta!.api.get<
|
||||
AxiosResponse<ListAiProvidersResponse>
|
||||
>(`/org/${orgId}/ai-providers`, {
|
||||
params: {
|
||||
page: 1,
|
||||
pageSize: 100,
|
||||
...(query ? { query } : {})
|
||||
},
|
||||
signal
|
||||
});
|
||||
return res.data.data.providers;
|
||||
}
|
||||
})
|
||||
};
|
||||
|
||||
@@ -1242,6 +1276,30 @@ export const resourceQueries = {
|
||||
return res.data.data.clients;
|
||||
}
|
||||
}),
|
||||
siteResourceAiProviders: ({ siteResourceId }: { siteResourceId: number }) =>
|
||||
queryOptions({
|
||||
queryKey: [
|
||||
"SITE_RESOURCES",
|
||||
siteResourceId,
|
||||
"AI_PROVIDERS"
|
||||
] as const,
|
||||
queryFn: async ({ signal, meta }) => {
|
||||
const res = await meta!.api.get<
|
||||
AxiosResponse<{
|
||||
providers: Array<{
|
||||
providerId: number;
|
||||
modelAccessMode: "catalog" | "allowlist";
|
||||
name: string;
|
||||
type: string;
|
||||
enabled: boolean;
|
||||
}>;
|
||||
}>
|
||||
>(`/site-resource/${siteResourceId}/ai-providers`, {
|
||||
signal
|
||||
});
|
||||
return res.data.data.providers;
|
||||
}
|
||||
}),
|
||||
resourceTargets: ({ resourceId }: { resourceId: number }) =>
|
||||
queryOptions({
|
||||
queryKey: ["RESOURCES", resourceId, "TARGETS"] as const,
|
||||
|
||||
Reference in New Issue
Block a user