fix: remove stale backend capability gating
This commit is contained in:
@@ -1714,10 +1714,6 @@ async function loadKnowledgeDocuments(knowledgeBases) {
|
||||
}
|
||||
|
||||
async function loadStorageStatus(projectId = "") {
|
||||
if (!backendSupports("/v2/storage/status")) {
|
||||
appState.storageStatus = null;
|
||||
return null;
|
||||
}
|
||||
const suffix = projectId ? `?project_id=${encodeURIComponent(projectId)}` : "";
|
||||
const payload = await storyforgeFetch(`/v2/storage/status${suffix}`).catch(() => null);
|
||||
appState.storageStatus = payload;
|
||||
@@ -1884,9 +1880,6 @@ async function loadOneLinerMessages(sessionId) {
|
||||
async function ensureOneLinerSession() {
|
||||
const projectId = getOneLinerProjectId();
|
||||
if (!projectId) throw new Error("当前还没有项目,OneLiner 需要先绑定项目上下文。");
|
||||
if (!backendSupports("/v2/oneliner/sessions")) {
|
||||
throw new Error("当前后端还没有接入 OneLiner 会话接口。");
|
||||
}
|
||||
let session = getCurrentOneLinerSession();
|
||||
if (!session) {
|
||||
session = await storyforgeFetch("/v2/oneliner/sessions", {
|
||||
@@ -1895,6 +1888,11 @@ async function ensureOneLinerSession() {
|
||||
project_id: projectId,
|
||||
preferred_platform: getPreferredPlatform()
|
||||
}
|
||||
}).catch((error) => {
|
||||
if (isMissingBackendCapability(error)) {
|
||||
throw new Error("当前实例还没有开放 OneLiner 会话接口。");
|
||||
}
|
||||
throw error;
|
||||
});
|
||||
appState.onelinerSessions = [session, ...safeArray(appState.onelinerSessions)];
|
||||
appState.selectedOnelinerSessionId = session.id;
|
||||
@@ -1931,9 +1929,6 @@ async function submitOneLinerMessage(content) {
|
||||
}
|
||||
|
||||
async function createOneLinerRun(runRequest) {
|
||||
if (!backendSupports("/v2/oneliner/runs")) {
|
||||
throw new Error("当前后端还没有接入主 Agent 运行层。");
|
||||
}
|
||||
const projectId = getOneLinerProjectId();
|
||||
const payload = await storyforgeFetch("/v2/oneliner/runs", {
|
||||
method: "POST",
|
||||
@@ -1945,6 +1940,11 @@ async function createOneLinerRun(runRequest) {
|
||||
scheduling_mode: "queued",
|
||||
...runRequest
|
||||
}
|
||||
}).catch((error) => {
|
||||
if (isMissingBackendCapability(error)) {
|
||||
throw new Error("当前实例还没有开放主 Agent 运行层。");
|
||||
}
|
||||
throw error;
|
||||
});
|
||||
await loadAgentControlSurfaces(projectId);
|
||||
appState.selectedOnelinerRunId = payload?.id || choosePreferredOneLinerRunId(appState.onelinerRuns, "");
|
||||
@@ -2229,9 +2229,6 @@ function collectOneLinerActionPayload(action) {
|
||||
}
|
||||
|
||||
async function executeOneLinerAction(executorKey, options = {}) {
|
||||
if (!backendSupports("/v2/oneliner/actions/execute")) {
|
||||
throw new Error("当前后端还没有接入 OneLiner 动作执行器。");
|
||||
}
|
||||
const projectId = getOneLinerProjectId();
|
||||
const session = getCurrentOneLinerSession() || await ensureOneLinerSession();
|
||||
const payload = await storyforgeFetch("/v2/oneliner/actions/execute", {
|
||||
@@ -2243,6 +2240,11 @@ async function executeOneLinerAction(executorKey, options = {}) {
|
||||
session_id: options.sessionId || session?.id || "",
|
||||
payload: options.payload || {}
|
||||
}
|
||||
}).catch((error) => {
|
||||
if (isMissingBackendCapability(error)) {
|
||||
throw new Error("当前实例还没有开放 OneLiner 动作执行器。");
|
||||
}
|
||||
throw error;
|
||||
});
|
||||
await loadAgentControlSurfaces(projectId);
|
||||
if (appState.selectedOnelinerSessionId) {
|
||||
@@ -2500,10 +2502,8 @@ async function bootstrap() {
|
||||
const runtimePlatforms = getRuntimePlatformValues();
|
||||
const preferredPlatform = getCurrentPlatformValue();
|
||||
setCurrentPlatform(preferredPlatform);
|
||||
const supportsReviews = backendSupports("/v2/reviews");
|
||||
const supportsIntegrationHealth = backendSupports("/v2/integrations/health");
|
||||
const supportsLocalModels = backendSupports("/v2/integrations/local-models");
|
||||
const supportsStorageStatus = backendSupports("/v2/storage/status");
|
||||
const supportsLiveRecorderSources = backendSupports("/v2/live-recorder/sources");
|
||||
const supportsLiveRecorderStatus = backendSupports("/v2/live-recorder/status");
|
||||
const supportsLiveRecorderFiles = backendSupports("/v2/live-recorder/files");
|
||||
@@ -2545,7 +2545,7 @@ async function bootstrap() {
|
||||
trackingDigest
|
||||
};
|
||||
})),
|
||||
supportsReviews ? storyforgeFetch("/v2/reviews").catch(() => []) : Promise.resolve([]),
|
||||
storyforgeFetch("/v2/reviews").catch(() => []),
|
||||
supportsIntegrationHealth ? storyforgeFetch("/v2/integrations/health").catch(() => null) : Promise.resolve(null),
|
||||
supportsLocalModels ? storyforgeFetch("/v2/integrations/local-models").catch(() => null) : Promise.resolve(null),
|
||||
supportsLiveRecorderSources ? storyforgeFetch("/v2/live-recorder/sources").catch(() => ({ items: [] })) : Promise.resolve({ items: [] })
|
||||
@@ -2605,11 +2605,7 @@ async function bootstrap() {
|
||||
appState.liveRecorderHealth = liveRecorderHealth;
|
||||
appState.documents = await loadKnowledgeDocuments(dashboard.knowledge_bases);
|
||||
appState.selectedProjectId = appState.selectedProjectId || dashboard.projects?.[0]?.id || "";
|
||||
if (supportsStorageStatus) {
|
||||
await loadStorageStatus(appState.selectedProjectId || "");
|
||||
} else {
|
||||
appState.storageStatus = null;
|
||||
}
|
||||
await loadStorageStatus(appState.selectedProjectId || "");
|
||||
await loadAgentControlSurfaces(appState.selectedProjectId || "");
|
||||
if (appState.selectedOnelinerSessionId) {
|
||||
await loadOneLinerMessages(appState.selectedOnelinerSessionId);
|
||||
@@ -3220,11 +3216,7 @@ async function applySelectedProject(projectId = "") {
|
||||
appState.selectedProjectId = projectId || "";
|
||||
setBusy(true, "正在切换项目视图...");
|
||||
try {
|
||||
if (backendSupports("/v2/storage/status")) {
|
||||
await loadStorageStatus(appState.selectedProjectId || "");
|
||||
} else {
|
||||
appState.storageStatus = null;
|
||||
}
|
||||
await loadStorageStatus(appState.selectedProjectId || "");
|
||||
await loadAgentControlSurfaces(appState.selectedProjectId || "");
|
||||
if (appState.selectedOnelinerSessionId) {
|
||||
await loadOneLinerMessages(appState.selectedOnelinerSessionId);
|
||||
@@ -3824,13 +3816,13 @@ function renderStorageStatusPanel() {
|
||||
<div class="panel-head">
|
||||
<div>
|
||||
<h3>存储状态</h3>
|
||||
<div class="panel-subtitle">后端暂未提供 /v2/storage/status,先用任务和录像文件做本地观察</div>
|
||||
<div class="panel-subtitle">当前实例没有返回存储策略时,先用任务和录像文件做本地观察</div>
|
||||
</div>
|
||||
<span class="tag blue">降级视图</span>
|
||||
</div>
|
||||
<div class="task-item">
|
||||
<h4>未拉取到 NAS 策略</h4>
|
||||
<p>后端补上 storage/status 后,这里会自动显示账号 / 项目 / 任务分层、容量和最近写入路径。</p>
|
||||
<p>当 storage/status 暂时拿不到时,这里会自动退回到任务和录像文件的降级视图。</p>
|
||||
<div class="task-meta">
|
||||
<span class="tag">最近任务 ${escapeHtml(formatNumber(projectJobCount))}</span>
|
||||
<span class="tag">录制源 ${escapeHtml(formatNumber(liveRecorderSources.length))}</span>
|
||||
@@ -6896,14 +6888,6 @@ function renderReviewScreen() {
|
||||
}
|
||||
return screenShell("发布与复盘", "先自动连接工作区。", `${button("自动连接", "open-auth", "primary")}`, renderEmptyState("复盘未加载", "自动连接成功后,这里会先用最近任务生成一版复盘入口。"));
|
||||
}
|
||||
if (!backendSupports("/v2/reviews")) {
|
||||
return screenShell(
|
||||
"发布与复盘",
|
||||
"当前 live collector 还没有接入复盘读写接口。",
|
||||
`${button("去生产", "goto-production", "primary")}`,
|
||||
renderEmptyState("复盘能力暂未接入", "这套后端还缺 /v2/reviews,当前可以继续跑生产任务,等 live collector 同步后这里会自动切成真实复盘工作台。")
|
||||
);
|
||||
}
|
||||
const project = getSelectedProject();
|
||||
const completed = safeArray(appState.dashboard.recent_jobs).filter((item) => item.status === "completed").slice(0, 4);
|
||||
const reviews = getProjectReviews(project?.id || "").slice(0, 8);
|
||||
@@ -11314,11 +11298,7 @@ document.addEventListener("click", async (event) => {
|
||||
appState.selectedProjectId = action.dataset.projectId || "";
|
||||
setBusy(true, "正在切换项目视图...");
|
||||
try {
|
||||
if (backendSupports("/v2/storage/status")) {
|
||||
await loadStorageStatus(appState.selectedProjectId || "");
|
||||
} else {
|
||||
appState.storageStatus = null;
|
||||
}
|
||||
await loadStorageStatus(appState.selectedProjectId || "");
|
||||
await loadAgentControlSurfaces(appState.selectedProjectId || "");
|
||||
if (appState.selectedOnelinerSessionId) {
|
||||
await loadOneLinerMessages(appState.selectedOnelinerSessionId);
|
||||
|
||||
@@ -274,21 +274,28 @@ test("governance and quota panels use real empty-state language instead of backe
|
||||
test("quota and review screens foreground live next-step guidance", () => {
|
||||
const tenantQuota = extractBetween(APP, "function renderTenantQuotaPanel()", "function policyScopeTagLabel(");
|
||||
const review = extractBetween(APP, "function renderReviewScreen()", "function renderStrategyScreen()");
|
||||
const storage = extractBetween(APP, "function renderStorageStatusPanel()", "function renderAutomationScreen()");
|
||||
|
||||
assert.match(tenantQuota, /先处理存储超限|先恢复额度保护|先补项目额度策略|先检查本周期消耗|先跑出第一条计量/);
|
||||
assert.match(tenantQuota, /主要消耗/);
|
||||
assert.match(tenantQuota, /周期 /);
|
||||
assert.match(tenantQuota, /计量 /);
|
||||
|
||||
assert.doesNotMatch(review, /复盘能力暂未接入|还缺 \/v2\/reviews/);
|
||||
assert.match(review, /先把最近完成任务写成复盘|先回看高频结论|先跑出第一条可复盘任务/);
|
||||
assert.match(review, /高频结论/);
|
||||
assert.match(review, /已发布/);
|
||||
assert.doesNotMatch(storage, /后端暂未提供 \/v2\/storage\/status/);
|
||||
assert.match(storage, /当前实例没有返回存储策略时/);
|
||||
});
|
||||
|
||||
test("tracking refresh and top-video analysis flows expose async feedback inside the workbench", () => {
|
||||
const tracking = extractBetween(APP, "function renderTrackingScreen()", "function renderAutomationScreen()");
|
||||
const discovery = extractBetween(APP, "function renderDiscoveryOverviewSection(", "function renderDiscoveryRelationsSection(");
|
||||
const trackingActions = extractBetween(APP, "async function markTrackingDigestRead()", "function createEmptyTrackingDigest(");
|
||||
const oneLinerSession = extractBetween(APP, "async function ensureOneLinerSession()", "async function submitOneLinerMessage(");
|
||||
const oneLinerRun = extractBetween(APP, "async function createOneLinerRun(", "async function confirmOneLinerRun(");
|
||||
const oneLinerAction = extractBetween(APP, "async function executeOneLinerAction(", "function openCurrentOneLinerRunResultAction(");
|
||||
const skillReview = extractBetween(APP, "function openPlatformSkillReviewAction(", "function openPlatformSkillRollbackAction(");
|
||||
const topVideoAction = extractBetween(APP, "function openAnalyzeTopVideosAction()", "function openSimilaritySearchAction()");
|
||||
|
||||
@@ -302,6 +309,9 @@ test("tracking refresh and top-video analysis flows expose async feedback inside
|
||||
assert.match(discovery, /最近高分拆解/);
|
||||
assert.match(discovery, /这批结果已经回流到当前账号页/);
|
||||
assert.doesNotMatch(trackingActions, /当前后端暂不支持.*跟踪已读游标|当前后端暂不支持.*批量跟踪同步|当前后端暂不支持.*单账号跟踪同步/s);
|
||||
assert.doesNotMatch(oneLinerSession, /当前后端还没有接入 OneLiner 会话接口/);
|
||||
assert.doesNotMatch(oneLinerRun, /当前后端还没有接入主 Agent 运行层/);
|
||||
assert.doesNotMatch(oneLinerAction, /当前后端还没有接入 OneLiner 动作执行器/);
|
||||
assert.doesNotMatch(skillReview, /当前后端还没有接入平台技能验收接口/);
|
||||
assert.doesNotMatch(topVideoAction, /当前后端暂不支持.*高分作品批量分析/s);
|
||||
assert.match(topVideoAction, /当前实例未提供/);
|
||||
|
||||
Reference in New Issue
Block a user