Simplify server file toolbar
This commit is contained in:
@@ -98,6 +98,8 @@ describe("ServerDetailPage config write approval", () => {
|
|||||||
expect(serverDetailPageSource).not.toContain("entry.editable");
|
expect(serverDetailPageSource).not.toContain("entry.editable");
|
||||||
expect(serverDetailPageSource).not.toContain("entry.downloadable");
|
expect(serverDetailPageSource).not.toContain("entry.downloadable");
|
||||||
expect(serverDetailPageSource).not.toContain("当前目录暂无缓存结果;点击刷新目录读取实时文件。");
|
expect(serverDetailPageSource).not.toContain("当前目录暂无缓存结果;点击刷新目录读取实时文件。");
|
||||||
|
expect(serverDetailPageSource).not.toContain("独立通道");
|
||||||
|
expect(serverDetailPageSource).not.toContain("目录已更新");
|
||||||
});
|
});
|
||||||
|
|
||||||
it("keeps run distribution and client-manager workflows out of server detail tabs", () => {
|
it("keeps run distribution and client-manager workflows out of server detail tabs", () => {
|
||||||
|
|||||||
@@ -596,7 +596,7 @@ function ServerFilesSection({ instance, session, operations }: ServerFilesSectio
|
|||||||
try {
|
try {
|
||||||
const response = await platformApiClient.listServerFiles(instance.id, { directoryKey, path: relativePath || undefined, query: searchQuery || undefined, recursive });
|
const response = await platformApiClient.listServerFiles(instance.id, { directoryKey, path: relativePath || undefined, query: searchQuery || undefined, recursive });
|
||||||
setList({ status: "ready", data: response });
|
setList({ status: "ready", data: response });
|
||||||
if (options.silent && response.state === "ready") setPanelResult({ status: "succeeded", label: `目录已更新:${response.entries.length} 项` });
|
if (options.silent && response.state === "ready") setPanelResult(null);
|
||||||
if (options.silent && response.state === "pending") setPanelResult({ status: "pending", label: serverFileListPendingLabel(response) });
|
if (options.silent && response.state === "pending") setPanelResult({ status: "pending", label: serverFileListPendingLabel(response) });
|
||||||
if (options.silent && response.state === "failed") setPanelResult({ status: "failed", label: response.reason ?? "目录刷新失败" });
|
if (options.silent && response.state === "failed") setPanelResult({ status: "failed", label: response.reason ?? "目录刷新失败" });
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
@@ -616,7 +616,8 @@ function ServerFilesSection({ instance, session, operations }: ServerFilesSectio
|
|||||||
const response = await platformApiClient.refreshServerFiles(instance.id, { directoryKey, path: relativePath || undefined, query: searchQuery || undefined, recursive, idempotencyKey: serverFileIdempotency("list", instance.id, directoryKey) });
|
const response = await platformApiClient.refreshServerFiles(instance.id, { directoryKey, path: relativePath || undefined, query: searchQuery || undefined, recursive, idempotencyKey: serverFileIdempotency("list", instance.id, directoryKey) });
|
||||||
setList({ status: "ready", data: response });
|
setList({ status: "ready", data: response });
|
||||||
if (operationId) operations.succeed(operationId, `目录刷新任务 ${response.job?.id ?? "已派发"}`, response.job);
|
if (operationId) operations.succeed(operationId, `目录刷新任务 ${response.job?.id ?? "已派发"}`, response.job);
|
||||||
setPanelResult({ status: serverFileListResultStatus(response), label: serverFileListResultLabel(response) });
|
if (response.state === "ready") setPanelResult(null);
|
||||||
|
else setPanelResult({ status: serverFileListResultStatus(response), label: serverFileListResultLabel(response) });
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
const reason = error instanceof Error ? error.message : "目录刷新失败";
|
const reason = error instanceof Error ? error.message : "目录刷新失败";
|
||||||
if (operationId) operations.fail(operationId, reason, operationId);
|
if (operationId) operations.fail(operationId, reason, operationId);
|
||||||
@@ -761,14 +762,13 @@ function ServerFilesSection({ instance, session, operations }: ServerFilesSectio
|
|||||||
<article className="console-panel server-file-manager" aria-label="server file manager">
|
<article className="console-panel server-file-manager" aria-label="server file manager">
|
||||||
<div className="panel-header">
|
<div className="panel-header">
|
||||||
<h2><Folder size={16} style={{ verticalAlign: "-2px" }} /> 服务器文件</h2>
|
<h2><Folder size={16} style={{ verticalAlign: "-2px" }} /> 服务器文件</h2>
|
||||||
<span className="page-status">独立通道 {workspace.data.transfer.channel} · 内联编辑 {formatBytes(workspace.data.transfer.maxInlineEditBytes)}</span>
|
|
||||||
</div>
|
</div>
|
||||||
|
<div className="server-file-toolbar">
|
||||||
<div className="server-file-pathbar" aria-label="当前文件路径">
|
<div className="server-file-pathbar" aria-label="当前文件路径">
|
||||||
<button type="button" className="icon-command" onClick={goUp} disabled={!relativePath && directoryKey === workspace.data.defaultDirectoryKey}><ChevronRight size={14} className="server-file-back-icon" /><span>上级</span></button>
|
<button type="button" className="icon-command" onClick={goUp} disabled={!relativePath && directoryKey === workspace.data.defaultDirectoryKey}><ChevronRight size={14} className="server-file-back-icon" /><span>上级</span></button>
|
||||||
<span className="server-file-path-chip">{activeDirectory?.label ?? (directoryKey || "服务器根目录")}</span>
|
<span className="server-file-path-chip">{activeDirectory?.label ?? (directoryKey || "服务器根目录")}</span>
|
||||||
{relativePath.split("/").filter(Boolean).map((part) => <span key={part} className="server-file-path-chip server-file-path-child"><ChevronRight size={12} />{part}</span>)}
|
{relativePath.split("/").filter(Boolean).map((part) => <span key={part} className="server-file-path-chip server-file-path-child"><ChevronRight size={12} />{part}</span>)}
|
||||||
</div>
|
</div>
|
||||||
<div className={cx("server-file-toolbar", workspace.data.directories.length > 1 && "server-file-toolbar-has-tabs")}>
|
|
||||||
{workspace.data.directories.length > 1 && <div className="server-file-directory-tabs" role="tablist" aria-label="文件目录">
|
{workspace.data.directories.length > 1 && <div className="server-file-directory-tabs" role="tablist" aria-label="文件目录">
|
||||||
{workspace.data.directories.map((directory) => (
|
{workspace.data.directories.map((directory) => (
|
||||||
<button key={directory.key} type="button" className={cx("segmented-button", directory.key === directoryKey && "segmented-button-active")} onClick={() => { setDirectoryKey(directory.key); setRelativePath(""); }}>
|
<button key={directory.key} type="button" className={cx("segmented-button", directory.key === directoryKey && "segmented-button-active")} onClick={() => { setDirectoryKey(directory.key); setRelativePath(""); }}>
|
||||||
@@ -861,7 +861,6 @@ function serverFileListResultStatus(response: ServerFileListResponse): "pending"
|
|||||||
}
|
}
|
||||||
|
|
||||||
function serverFileListResultLabel(response: ServerFileListResponse): string {
|
function serverFileListResultLabel(response: ServerFileListResponse): string {
|
||||||
if (response.state === "ready") return `目录已更新:${response.entries.length} 项`;
|
|
||||||
if (response.state === "failed") return response.reason ?? "目录刷新失败";
|
if (response.state === "failed") return response.reason ?? "目录刷新失败";
|
||||||
return serverFileListPendingLabel(response);
|
return serverFileListPendingLabel(response);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -455,9 +455,10 @@ to{transform:translate(-50%,-50%) rotate(calc(var(--construct-drift) + 360deg))}
|
|||||||
.server-file-back-icon{transform:rotate(180deg)}
|
.server-file-back-icon{transform:rotate(180deg)}
|
||||||
.server-file-path-chip{display:inline-flex;align-items:center;gap:4px;min-height:30px;padding:0;border:0;border-radius:0;background:transparent;color:var(--ink-soft);font-size:12px;font-weight:800;white-space:nowrap}
|
.server-file-path-chip{display:inline-flex;align-items:center;gap:4px;min-height:30px;padding:0;border:0;border-radius:0;background:transparent;color:var(--ink-soft);font-size:12px;font-weight:800;white-space:nowrap}
|
||||||
.server-file-path-child{color:var(--ink-faint)}
|
.server-file-path-child{color:var(--ink-faint)}
|
||||||
.server-file-toolbar{display:grid;grid-template-columns:minmax(320px,1fr) auto;gap:8px;align-items:center;min-width:0}.server-file-toolbar-has-tabs{grid-template-columns:minmax(160px,.8fr) minmax(320px,1.2fr) auto}
|
.server-file-toolbar{display:flex;align-items:center;gap:8px;flex-wrap:wrap;min-width:0}
|
||||||
|
.server-file-toolbar .server-file-pathbar{flex:0 0 auto}
|
||||||
.server-file-directory-tabs{display:flex;gap:6px;overflow:auto;min-width:0;padding-bottom:2px}
|
.server-file-directory-tabs{display:flex;gap:6px;overflow:auto;min-width:0;padding-bottom:2px}
|
||||||
.server-file-search{display:flex;align-items:center;gap:7px;min-width:0;min-height:36px;padding:0 8px;border:1px solid var(--line);border-radius:4px;background:var(--control-surface);box-shadow:none}
|
.server-file-search{display:flex;align-items:center;gap:7px;flex:1 1 320px;min-width:240px;min-height:36px;padding:0 8px;border:1px solid var(--line);border-radius:4px;background:var(--control-surface);box-shadow:none}
|
||||||
.server-file-search input[type=search]{min-width:120px;flex:1 1 auto;border:0;background:transparent;color:var(--ink);font:inherit;outline:0}
|
.server-file-search input[type=search]{min-width:120px;flex:1 1 auto;border:0;background:transparent;color:var(--ink);font:inherit;outline:0}
|
||||||
.server-file-search label{display:inline-flex;align-items:center;gap:5px;color:var(--ink-faint);font-size:12px;font-weight:800;white-space:nowrap}
|
.server-file-search label{display:inline-flex;align-items:center;gap:5px;color:var(--ink-faint);font-size:12px;font-weight:800;white-space:nowrap}
|
||||||
.server-file-actions{justify-content:flex-end;flex-wrap:nowrap}
|
.server-file-actions{justify-content:flex-end;flex-wrap:nowrap}
|
||||||
@@ -726,7 +727,7 @@ to{transform:translate(-50%,-50%) rotate(calc(var(--construct-drift) + 360deg))}
|
|||||||
.section-tabs{overflow-x:auto;flex-wrap:nowrap;padding-bottom:4px}
|
.section-tabs{overflow-x:auto;flex-wrap:nowrap;padding-bottom:4px}
|
||||||
.server-toolbar{align-items:stretch}
|
.server-toolbar{align-items:stretch}
|
||||||
.server-toolbar input[type=search],.server-toolbar select{flex:1 1 100%;min-width:0}
|
.server-toolbar input[type=search],.server-toolbar select{flex:1 1 100%;min-width:0}
|
||||||
.server-file-toolbar{grid-template-columns:1fr}.server-file-search,.server-file-actions,.server-file-pathbar{align-items:stretch;flex-wrap:wrap}.server-file-search input[type=search]{min-width:0}.server-file-actions{justify-content:stretch}.server-file-actions>*{flex:1 1 auto}
|
.server-file-toolbar{align-items:stretch}.server-file-search,.server-file-actions,.server-file-pathbar{align-items:stretch;flex-wrap:wrap}.server-file-search input[type=search]{min-width:0}.server-file-actions{justify-content:stretch}.server-file-actions>*{flex:1 1 auto}
|
||||||
.plugin-control-row,.server-card-head,.server-detail-title-row{grid-template-columns:1fr;align-items:stretch}
|
.plugin-control-row,.server-card-head,.server-detail-title-row{grid-template-columns:1fr;align-items:stretch}
|
||||||
.server-card-head,.server-detail-title-row{display:grid}
|
.server-card-head,.server-detail-title-row{display:grid}
|
||||||
.server-detail-title-row .action-strip{align-items:stretch}
|
.server-detail-title-row .action-strip{align-items:stretch}
|
||||||
|
|||||||
Reference in New Issue
Block a user