Files
Agent-System/web/src/lib/docGovActionVisibility.ts
T
weichenandCursor aed7f3f9b5 fix(web): gate docgov actions by duty id, not folded role
author_only A/A/A users were stuck as author-only under resolveCurrentDocRole priority.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-17 13:48:59 +00:00

80 lines
2.1 KiB
TypeScript

import type { UserRole } from '../types/docgov';
export type DocGovApprovalAction = 'submit' | 'review' | 'approve';
export type DocDutyIds = {
authorId?: number;
reviewerId?: number;
approverId?: number;
};
export type DocDutyRole = 'author' | 'reviewer' | 'approver';
export function isUnmanagedDocDuties(duties: DocDutyIds): boolean {
return !(
(duties.authorId ?? 0) > 0 ||
(duties.reviewerId ?? 0) > 0 ||
(duties.approverId ?? 0) > 0
);
}
/** 直接比对用户 ID 与职责槽位,不经过折叠后的单角色 currentRole。 */
export function holdsDocDuty(
userId: number | undefined,
role: DocDutyRole,
duties: DocDutyIds,
): boolean {
if (!userId || userId <= 0) return false;
switch (role) {
case 'author':
return (duties.authorId ?? 0) === userId;
case 'reviewer':
return (duties.reviewerId ?? 0) === userId;
case 'approver':
return (duties.approverId ?? 0) === userId;
default: {
const _exhaustive: never = role;
return _exhaustive;
}
}
}
export function canShowDocGovApprovalAction(
action: DocGovApprovalAction,
currentUserId: number | undefined,
duties: DocDutyIds,
): boolean {
if (isUnmanagedDocDuties(duties)) return false;
switch (action) {
case 'submit':
return holdsDocDuty(currentUserId, 'author', duties);
case 'review':
return holdsDocDuty(currentUserId, 'reviewer', duties);
case 'approve':
return holdsDocDuty(currentUserId, 'approver', duties);
default: {
const _exhaustive: never = action;
return _exhaustive;
}
}
}
/** @deprecated Prefer holdsDocDuty; kept for callers that still pass a folded role label. */
export function canShowDocGovApprovalActionByRole(
action: DocGovApprovalAction,
currentRole: UserRole,
duties: DocDutyIds,
): boolean {
if (isUnmanagedDocDuties(duties)) return false;
switch (action) {
case 'submit':
return currentRole === 'author';
case 'review':
return currentRole === 'reviewer';
case 'approve':
return currentRole === 'approver';
default:
return false;
}
}