fix: expose active import workflows as source sync status

This commit is contained in:
FFXN 2026-09-04 11:52:41 +08:00
parent 7ca5eaab97
commit 448fd92f6d
5 changed files with 46 additions and 7 deletions

View File

@ -1,6 +1,6 @@
{
"schemaVersion": 5,
"subtreeTree": "7f8c4b3b5f6bc8ade3d87bf3100b81c58e254de4",
"subtreeTree": "7475a7b293fa321bc728243a7ba62284bf469883",
"openapiSha256": "5f9bee6a3593d8bd05308c7a57ab3d02ef451133cde9347a40543fae934a9a59",
"capabilityV2AuthManifestSha256": "e322a2fa779d1f40b95c54c1021cffecaec77abbd7b34899573dcdf4ff353109",
"capabilityV2AuthTestVectorSha256": "ae0de37b1ff05c40f905cf17a7b410d8971acacf64db07d5ee3d6fecfa559ce3",

View File

@ -1996,13 +1996,25 @@ describe("database source-product workflow repository edge coverage", () => {
expect(calls[0]).toMatchObject({
maxRows: 2,
operation: "select",
params: [tenantId, knowledgeSpaceId, '["team:reader"]', "sync", sourceId, "source-b"],
params: [
tenantId,
knowledgeSpaceId,
'["team:reader"]',
"sync",
"crawl-import",
"online-document-import",
"online-drive-import",
sourceId,
"source-b",
],
tableName: "source_workflow_runs",
});
expect(calls[0]?.sql).toContain("ROW_NUMBER() OVER");
expect(calls[0]?.sql).toContain('CASE WHEN "active_slot" = 1 THEN 1 ELSE 0 END DESC');
expect(calls[0]?.sql).toContain('"source_run_rank" = 1');
expect(calls[0]?.sql).toContain('"source_id" IN ($5, $6)');
expect(calls[0]?.sql).toContain('"source_id" IN ($8, $9)');
expect(calls[0]?.sql).toContain('"kind" IN ($5, $6, $7)');
expect(calls[0]?.sql).toContain('"active_slot" = 1');
expect(calls[0]?.sql).toContain('"required_permission_scope"');
expect(calls[0]?.sql).toContain('"capability_grants"');
await expect(
@ -2040,6 +2052,9 @@ describe("database source-product workflow repository edge coverage", () => {
'["team:reader"]',
'["team:reader"]',
"sync",
"crawl-import",
"online-document-import",
"online-drive-import",
sourceId,
]);
const call = calls[0];

View File

@ -1195,8 +1195,13 @@ export function createDatabaseSourceProductWorkflowRepository(input: {
params,
candidateGrants,
);
params.push("sync");
const kindPlaceholder = p(database, params.length);
params.push("sync", "crawl-import", "online-document-import", "online-drive-import");
const syncKindPlaceholder = p(database, params.length - 3);
const importKindPlaceholders = [
p(database, params.length - 2),
p(database, params.length - 1),
p(database, params.length),
].join(", ");
const placeholders = ids
.map((id) => {
params.push(id);
@ -1209,7 +1214,7 @@ export function createDatabaseSourceProductWorkflowRepository(input: {
maxRows: ids.length,
operation: "select",
params,
sql: `SELECT * FROM (SELECT ${q(database, runTable)}.*, ROW_NUMBER() OVER (PARTITION BY ${q(database, "source_id")} ORDER BY CASE WHEN ${q(database, "active_slot")} = 1 THEN 1 ELSE 0 END DESC, ${q(database, "created_at")} DESC, ${q(database, "updated_at")} DESC, ${q(database, "id")} DESC) AS ${q(database, rankColumn)} FROM ${q(database, runTable)} WHERE ${q(database, "tenant_id")} = ${p(database, 1)} AND ${q(database, "knowledge_space_id")} = ${p(database, 2)} AND ${permissionScopePredicate} AND ${q(database, "kind")} = ${kindPlaceholder} AND ${q(database, "source_id")} IN (${placeholders})) ${q(database, rankedRuns)} WHERE ${q(database, rankColumn)} = 1;`,
sql: `SELECT * FROM (SELECT ${q(database, runTable)}.*, ROW_NUMBER() OVER (PARTITION BY ${q(database, "source_id")} ORDER BY CASE WHEN ${q(database, "active_slot")} = 1 THEN 1 ELSE 0 END DESC, ${q(database, "created_at")} DESC, ${q(database, "updated_at")} DESC, ${q(database, "id")} DESC) AS ${q(database, rankColumn)} FROM ${q(database, runTable)} WHERE ${q(database, "tenant_id")} = ${p(database, 1)} AND ${q(database, "knowledge_space_id")} = ${p(database, 2)} AND ${permissionScopePredicate} AND (${q(database, "kind")} = ${syncKindPlaceholder} OR (${q(database, "kind")} IN (${importKindPlaceholders}) AND ${q(database, "active_slot")} = 1)) AND ${q(database, "source_id")} IN (${placeholders})) ${q(database, rankedRuns)} WHERE ${q(database, rankColumn)} = 1;`,
tableName: runTable,
});
return result.rows.map(mapRun);

View File

@ -1225,6 +1225,16 @@ describe("in-memory source product workflow repository", () => {
: null,
});
await repository.start(runRecord("active-sync"));
await repository.start(
runRecord("active-import", {
kind: "crawl-import",
sourceId: "source-import",
}),
);
await terminalRun(repository, "completed-import", "completed", {
kind: "online-document-import",
sourceId: "source-completed-import",
});
await repository.start(
runRecord("other-source", {
sourceId: "source-other",
@ -1256,6 +1266,8 @@ describe("in-memory source product workflow repository", () => {
sourceIds: [
"source-memory",
"source-other",
"source-import",
"source-completed-import",
"source-private",
"source-capability-private",
"source-memory",
@ -1264,6 +1276,7 @@ describe("in-memory source product workflow repository", () => {
}),
).resolves.toEqual([
expect.objectContaining({ id: "active-sync", sourceId: "source-memory" }),
expect.objectContaining({ id: "active-import", sourceId: "source-import" }),
expect.objectContaining({ id: "other-source", sourceId: "source-other" }),
]);
await expect(

View File

@ -694,7 +694,13 @@ export function createInMemorySourceProductWorkflowRepository(input?: {
run.tenantId !== tenantId ||
run.knowledgeSpaceId !== knowledgeSpaceId ||
!runPermissionScopeAllows(run, candidateGrants) ||
run.kind !== "sync" ||
(run.kind !== "sync" &&
!(
run.activeSlot === 1 &&
(run.kind === "crawl-import" ||
run.kind === "online-document-import" ||
run.kind === "online-drive-import")
)) ||
!run.sourceId ||
!requestedSourceIds.has(run.sourceId)
) {