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