182 lines
5.1 KiB
TypeScript
182 lines
5.1 KiB
TypeScript
import type { JobResponse, RunEndpointResponse, ServerInstanceResponse, ServerMetricsResponse, UserContactProfile, UserStatus, UserThemePreferenceResponse } from "../api/types";
|
|
|
|
export type WorkspaceRole = "platformAdmin" | "serverOwner" | "serverAdmin";
|
|
|
|
export type WorkspaceCapability =
|
|
| "profile.settings.manage"
|
|
| "platform.overview.read"
|
|
| "servers.read"
|
|
| "servers.manage"
|
|
| "plugins.market.read"
|
|
| "users.manage"
|
|
| "aiProviders.manage"
|
|
| "system.maintenance";
|
|
|
|
export interface CurrentUserView {
|
|
id: string;
|
|
displayName: string;
|
|
email?: string;
|
|
status: UserStatus;
|
|
roles: WorkspaceRole[];
|
|
capabilities: WorkspaceCapability[];
|
|
profile: UserContactProfile;
|
|
themePreference?: UserThemePreferenceResponse;
|
|
source: "api" | "local";
|
|
}
|
|
|
|
const roleCapabilities: Record<WorkspaceRole, WorkspaceCapability[]> = {
|
|
platformAdmin: [
|
|
"profile.settings.manage",
|
|
"platform.overview.read",
|
|
"servers.read",
|
|
"servers.manage",
|
|
"plugins.market.read",
|
|
"users.manage",
|
|
"aiProviders.manage",
|
|
"system.maintenance"
|
|
],
|
|
serverOwner: ["profile.settings.manage", "servers.read", "servers.manage"],
|
|
serverAdmin: ["profile.settings.manage", "servers.read", "servers.manage"]
|
|
};
|
|
|
|
export function capabilitiesForRoles(roles: WorkspaceRole[]): WorkspaceCapability[] {
|
|
const set = new Set<WorkspaceCapability>();
|
|
for (const role of roles) {
|
|
for (const capability of roleCapabilities[role] ?? []) {
|
|
set.add(capability);
|
|
}
|
|
}
|
|
return [...set];
|
|
}
|
|
|
|
export function isPlatformAdmin(user: CurrentUserView): boolean {
|
|
return user.roles.includes("platformAdmin");
|
|
}
|
|
|
|
export function rolesFromBackendRoles(roles: string[]): WorkspaceRole[] {
|
|
const mapped = new Set<WorkspaceRole>();
|
|
for (const role of roles) {
|
|
const normalized = role.toLowerCase();
|
|
if (normalized === "admin" || normalized === "platform-admin" || normalized === "platformadmin") {
|
|
mapped.add("platformAdmin");
|
|
}
|
|
if (normalized === "server-owner" || normalized === "owner") {
|
|
mapped.add("serverOwner");
|
|
}
|
|
if (normalized === "server-admin" || normalized === "operator") {
|
|
mapped.add("serverAdmin");
|
|
}
|
|
}
|
|
return mapped.size > 0 ? [...mapped] : ["serverAdmin"];
|
|
}
|
|
|
|
export type OperationStatus = "pending" | "succeeded" | "failed";
|
|
|
|
export interface OperationRecord {
|
|
id: string;
|
|
intent: string;
|
|
targetKind: "server" | "plugin" | "config" | "llm" | "platform";
|
|
targetId: string;
|
|
requester: string;
|
|
status: OperationStatus;
|
|
jobId?: string;
|
|
jobState?: JobResponse["state"];
|
|
message?: string;
|
|
errorReason?: string;
|
|
diagnosticId?: string;
|
|
createdAt: string;
|
|
updatedAt: string;
|
|
}
|
|
|
|
export interface ServerCardView {
|
|
instance: ServerInstanceResponse;
|
|
endpoint?: RunEndpointResponse;
|
|
metrics?: ServerMetricsResponse;
|
|
pendingJobs: number;
|
|
activeJobs?: number;
|
|
failedJobs?: number;
|
|
latestJob?: JobResponse;
|
|
}
|
|
|
|
export type ServerStatusFilter = "all" | "online" | "offline" | "attention";
|
|
|
|
export function serverIsOnline(state: ServerInstanceResponse["state"]): boolean {
|
|
return state === "running";
|
|
}
|
|
|
|
export function serverNeedsAttention(state: ServerInstanceResponse["state"]): boolean {
|
|
return state === "failed" || state === "installing";
|
|
}
|
|
|
|
export function filterServerCards(cards: ServerCardView[], keyword: string, status: ServerStatusFilter): ServerCardView[] {
|
|
const query = keyword.trim().toLowerCase();
|
|
return cards.filter((card) => {
|
|
if (query && !`${card.instance.name} ${card.instance.id} ${card.instance.pluginId}`.toLowerCase().includes(query)) {
|
|
return false;
|
|
}
|
|
if (status === "online") {
|
|
return serverIsOnline(card.instance.state);
|
|
}
|
|
if (status === "offline") {
|
|
return !serverIsOnline(card.instance.state);
|
|
}
|
|
if (status === "attention") {
|
|
return serverNeedsAttention(card.instance.state);
|
|
}
|
|
return true;
|
|
});
|
|
}
|
|
|
|
export interface GameTypeDistributionEntry {
|
|
serverType: string;
|
|
label: string;
|
|
count: number;
|
|
}
|
|
|
|
export interface PlatformOverviewSignal {
|
|
id: string;
|
|
kind: "log" | "fault" | "plugin" | "aiProvider" | "job";
|
|
summary: string;
|
|
detail: string;
|
|
targetPage: "servers" | "plugins" | "aiProviders" | "maintenance";
|
|
targetId?: string;
|
|
tone: "info" | "warning" | "error";
|
|
at: string;
|
|
}
|
|
|
|
export type ServerDetailSection = "logs" | "terminal" | "config" | "llm" | "history" | `plugin:${string}`;
|
|
|
|
export const serverDetailSections: Array<{ id: ServerDetailSection; label: string }> = [
|
|
{ id: "logs", label: "日志" },
|
|
{ id: "terminal", label: "管理终端" },
|
|
{ id: "config", label: "配置" },
|
|
{ id: "llm", label: "AI 助手" },
|
|
{ id: "history", label: "操作历史" }
|
|
];
|
|
|
|
export interface DiffLine {
|
|
kind: "same" | "added" | "removed";
|
|
text: string;
|
|
}
|
|
|
|
export interface ConfigDiffView {
|
|
serverInstanceId: string;
|
|
configVersion?: number;
|
|
checksum?: string;
|
|
key?: string;
|
|
source?: string;
|
|
summary: string;
|
|
lines: DiffLine[];
|
|
nextContent: string;
|
|
proposedContentInputRef?: string;
|
|
}
|
|
|
|
export interface LlmSuggestionView {
|
|
serverInstanceId: string;
|
|
source: "api";
|
|
recommendation: string;
|
|
diffId?: string;
|
|
expiresAt?: string;
|
|
diff?: ConfigDiffView;
|
|
}
|