fix(panel): mark platform system services read-only in the fleet table
login/lobby carry reserved names, so every per-server route rejects them — yet the cockpit offered claim/stop/wake and a console link on their rows, each answering 400 bad_name. The fleet view now marks them (system:true, shared naming.IsSystemServer) and the panel renders a plain label instead of dead actions.
This commit is contained in:
9 files changed
+99
-4
No files matched your search
@@ -51,6 +51,8 @@
|
||||
"backups_link_desc": "View and restore world backups for this server.",
|
||||
"files_link_title": "Server files",
|
||||
"files_link_desc": "Browse and repair files in the world volume.",
|
||||
"system_service": "System service",
|
||||
"system_service_hint": "Provisioned and managed by the platform (felis systemservers); it accepts no user operations.",
|
||||
"players_back_to_console": "Back to console",
|
||||
"players_not_yours_title": "Not your server",
|
||||
"players_not_yours_body": "Only the owner or an admin can manage this server's players.",
|
||||
|
||||
@@ -51,6 +51,8 @@
|
||||
"backups_link_desc": "查看并恢复该服务器的世界备份。",
|
||||
"files_link_title": "服务器文件",
|
||||
"files_link_desc": "浏览并修复世界卷中的文件。",
|
||||
"system_service": "系统服务",
|
||||
"system_service_hint": "由平台预置并管理(felis systemservers),不接受用户操作。",
|
||||
"players_back_to_console": "返回控制台",
|
||||
"players_not_yours_title": "这不是你的服务器",
|
||||
"players_not_yours_body": "只有所有者或管理员才能管理此服务器的玩家。",
|
||||
|
||||
@@ -119,6 +119,10 @@ export interface FleetServer {
|
||||
* Empty/absent for an unclaimed server or when the best-effort owner lookup
|
||||
* failed — the cockpit renders that as "unclaimed". */
|
||||
owner?: string;
|
||||
/** True for a platform-provisioned system service (the login gate, the lobby).
|
||||
* Their reserved names are rejected by every per-server route, so the cockpit
|
||||
* renders them read-only instead of offering actions that would 400. */
|
||||
system?: boolean;
|
||||
}
|
||||
|
||||
/** BackupView is one row of GET /api/v1/backups (spec §7 backups). A backup is
|
||||
|
||||
@@ -82,6 +82,7 @@ interface UnifiedServer {
|
||||
endpointAddress?: string | null;
|
||||
claimable?: boolean;
|
||||
owned?: boolean;
|
||||
system?: boolean;
|
||||
}
|
||||
|
||||
export function ServersPage() {
|
||||
@@ -126,6 +127,7 @@ export function ServersPage() {
|
||||
endpointAddress: s.endpointAddress,
|
||||
claimable: !s.owner,
|
||||
owned: s.owner === identity?.email,
|
||||
system: s.system,
|
||||
}));
|
||||
} else {
|
||||
return (data as ServerInfo[]).map((s) => ({
|
||||
@@ -443,7 +445,11 @@ function ServerRow({
|
||||
</td>
|
||||
{isAdmin && (
|
||||
<td className="px-4 py-3 align-middle text-left">
|
||||
{server.owner ? (
|
||||
{server.system ? (
|
||||
<span className="text-xs text-muted-foreground/70" title={ts("system_service_hint")}>
|
||||
{ts("system_service")}
|
||||
</span>
|
||||
) : server.owner ? (
|
||||
<span className="inline-flex max-w-[16rem] items-center gap-1.5 truncate">
|
||||
<UserRound className="h-3.5 w-3.5 shrink-0 text-muted-foreground" />
|
||||
<span className="truncate" title={server.owner}>
|
||||
@@ -486,7 +492,13 @@ function ServerRow({
|
||||
</td>
|
||||
<td className="px-4 py-3 align-middle">
|
||||
<div className="flex items-center justify-end gap-2">
|
||||
{server.claimable && !server.owned ? (
|
||||
{server.system ? (
|
||||
// A system service carries a reserved name that every per-server route
|
||||
// rejects, so offer no actions — just the honest label.
|
||||
<span className="text-xs text-muted-foreground/70" title={ts("system_service_hint")}>
|
||||
{ts("system_service")}
|
||||
</span>
|
||||
) : server.claimable && !server.owned ? (
|
||||
<>
|
||||
<Button
|
||||
size="sm"
|
||||
|
||||
Reference in new issue
Block a user