UI-13a stayed on private after upload, so the doc menu had no doc_proj* entries. Always use the category trigger first, then exact id. Co-authored-by: Cursor <cursoragent@cursor.com>
58 lines
2.0 KiB
TypeScript
58 lines
2.0 KiB
TypeScript
export type DeliverableCategory = 'workflow' | 'shared' | 'private';
|
|
|
|
export const CATEGORY_TRIGGER_LABEL: Record<DeliverableCategory, string> = {
|
|
workflow: '流程受控',
|
|
shared: '项目共享',
|
|
private: '我的私密',
|
|
};
|
|
|
|
export type DocOpenIntent =
|
|
| { kind: 'exact-id'; docId: string }
|
|
| { kind: 'controlled-task-key'; taskKey: string }
|
|
| { kind: 'workflow-label' };
|
|
|
|
export type DocSelectorStep =
|
|
| { action: 'ensure_category'; category: DeliverableCategory }
|
|
| { action: 'select_exact'; docId: string }
|
|
| { action: 'fail'; reason: string };
|
|
|
|
const CONTROLLED_DOC_ID = /^doc_proj\d+_[a-z][a-z0-9_]*$/;
|
|
|
|
export function requiredCategoryForDocOpen(intent: DocOpenIntent): DeliverableCategory {
|
|
if (intent.kind === 'workflow-label' || intent.kind === 'controlled-task-key') {
|
|
return 'workflow';
|
|
}
|
|
const docId = intent.docId.trim();
|
|
if (CONTROLLED_DOC_ID.test(docId)) {
|
|
return 'workflow';
|
|
}
|
|
if (docId.startsWith('doc-free-')) {
|
|
return 'private';
|
|
}
|
|
throw new Error(`cannot infer deliverable category for ${JSON.stringify(docId)}`);
|
|
}
|
|
|
|
/**
|
|
* Plan the real UI sequence: always ensure the target category via the category
|
|
* trigger, then select by exact data-doc-id from that category's menu.
|
|
* A private (or other) menu missing doc_proj* is not a failure until after switch.
|
|
*/
|
|
export function planExactDocOpen(input: {
|
|
currentCategory: DeliverableCategory;
|
|
visibleMenuDocIds: string[];
|
|
targetDocId: string;
|
|
}): DocSelectorStep[] {
|
|
const category = requiredCategoryForDocOpen({ kind: 'exact-id', docId: input.targetDocId });
|
|
const ensure: DocSelectorStep = { action: 'ensure_category', category };
|
|
if (input.currentCategory !== category) {
|
|
return [ensure];
|
|
}
|
|
if (!input.visibleMenuDocIds.includes(input.targetDocId)) {
|
|
return [
|
|
ensure,
|
|
{ action: 'fail', reason: `doc-selector menu missing data-doc-id=${input.targetDocId}` },
|
|
];
|
|
}
|
|
return [ensure, { action: 'select_exact', docId: input.targetDocId }];
|
|
}
|