Files
browser/platform_web/contracts/workspace.ts
T

200 lines
5.5 KiB
TypeScript

import type { JobResponse, 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;
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" | "runtime" | "config" | "plugins" | "llm" | "history";
export const serverDetailSections: Array<{ id: ServerDetailSection; label: string }> = [
{ id: "logs", label: "日志" },
{ id: "terminal", label: "管理终端" },
{ id: "runtime", label: "运行操作" },
{ id: "config", label: "配置" },
{ id: "plugins", label: "插件控制" },
{ id: "llm", label: "AI 助手" },
{ id: "history", label: "操作历史" }
];
export interface PluginControlDescriptor {
key: string;
label: string;
description: string;
capability: string;
lifecycleAction?: "start" | "stop" | "status";
dangerous: boolean;
}
export interface PluginControlGroupView {
pluginId: string;
pluginName: string;
version: string;
status: string;
controls: PluginControlDescriptor[];
}
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;
}