feat(campaign): add durable operator queue controls

This commit is contained in:
2026-07-22 08:39:44 +02:00
parent 62a68792a4
commit 21f3014ac5
10 changed files with 420 additions and 29 deletions

View File

@@ -0,0 +1,78 @@
export type OperatorQueueAction =
| "details"
| "pause"
| "resume"
| "retry"
| "queue-unsent"
| "reconcile"
| "cancel";
export type OperatorQueuePermissions = {
canRead: boolean;
canControl: boolean;
canRetry: boolean;
canQueue: boolean;
canReconcile: boolean;
};
export type OperatorQueueFacts = {
retryable: number;
outcomeUnknown: number;
queueableUnattempted: number;
queued: number;
paused: number;
cancellable: number;
};
export const OPERATOR_QUEUE_REASON = {
permission: "i18n:govoplan-campaign.you_do_not_have_permission_for_this_action.dfcfbad6",
noQueued: "i18n:govoplan-campaign.no_queued_jobs_can_be_paused.acaa0b4e",
noPaused: "i18n:govoplan-campaign.no_paused_jobs_can_be_resumed.869b6275",
noFailed: "i18n:govoplan-campaign.no_failed_jobs_are_eligible_for_retry.e65a69f9",
noUnsent: "i18n:govoplan-campaign.no_unsent_jobs_are_available_to_queue.585bfe87",
noUnknown: "i18n:govoplan-campaign.no_uncertain_outcomes_require_reconciliation.933bc53c",
noCancellable: "i18n:govoplan-campaign.no_cancellable_queued_work_remains.80e31d49"
} as const;
/**
* Return the reason each fixed queue action is unavailable. A null result means
* the action is permitted and meaningful for the current queue projection.
*/
export function operatorQueueActionBlocks(
facts: OperatorQueueFacts,
permissions: OperatorQueuePermissions
): Record<OperatorQueueAction, string | null> {
return {
details: permissions.canRead ? null : OPERATOR_QUEUE_REASON.permission,
pause: !permissions.canControl
? OPERATOR_QUEUE_REASON.permission
: facts.queued > 0
? null
: OPERATOR_QUEUE_REASON.noQueued,
resume: !permissions.canControl
? OPERATOR_QUEUE_REASON.permission
: facts.paused > 0
? null
: OPERATOR_QUEUE_REASON.noPaused,
retry: !permissions.canRetry
? OPERATOR_QUEUE_REASON.permission
: facts.retryable > 0
? null
: OPERATOR_QUEUE_REASON.noFailed,
"queue-unsent": !permissions.canQueue
? OPERATOR_QUEUE_REASON.permission
: facts.queueableUnattempted > 0
? null
: OPERATOR_QUEUE_REASON.noUnsent,
reconcile: !permissions.canReconcile
? OPERATOR_QUEUE_REASON.permission
: facts.outcomeUnknown > 0
? null
: OPERATOR_QUEUE_REASON.noUnknown,
cancel: !permissions.canControl
? OPERATOR_QUEUE_REASON.permission
: facts.cancellable > 0
? null
: OPERATOR_QUEUE_REASON.noCancellable
};
}