// Clasificación primaria / secundaria de acciones — puro (sin React), lo usan
// el menú de fila, la cabecera/pie del documento y resolveActions del
// DocumentPage. Ver record-actions.ts para las acciones aportadas por addons.
import type { ActionPriority } from '@asteby/metacore-sdk'
import type { InstalledAddonsValue } from './installed-addons-context'
export type { ActionPriority }
/** Lo mínimo que se lee de una acción de metadata para clasificarla. */
export interface PrioritizableAction {
key: string
priority?: string
trigger?: { type?: string; capability?: string } | null
}
// Segmentos de la clave (separados por _ . -) que marcan una acción de
// compartir/salida. Por segmento: `create_mailbox` no es «mail», `send` solo
// (enviar una cotización) sigue siendo flujo principal.
const SECONDARY_SEGMENTS = new Set([
'print',
'reprint',
'share',
'email',
'mail',
'whatsapp',
'chat',
'download',
'pdf',
'xml',
'acuse',
])
const CRUD_KEYS = new Set(['view', 'edit', 'delete'])
/** "primary" | "secondary" | undefined (= acción normal del menú). */
export function classifyActionPriority(action: PrioritizableAction): ActionPriority | undefined {
if (action.priority === 'primary' || action.priority === 'secondary') return action.priority
if (CRUD_KEYS.has(action.key)) return undefined
return action.key
.toLowerCase()
.split(/[_.-]+/)
.some((seg) => SECONDARY_SEGMENTS.has(seg))
? 'secondary'
: undefined
}
export interface SplitActions {
/** La única destacada (la primera que se declara `primary`). */
primary?: A
/** El resto de acciones principales, en orden. */
main: A[]
/** Compartir / imprimir / correo / chat… */
secondary: A[]
}
/**
* Separa primaria, principales y secundarias conservando el orden. Si varias
* reclaman `primary`, sólo la primera lo es; las demás quedan como principales.
*/
export function splitActionsByPriority(actions: readonly A[]): SplitActions {
let primary: A | undefined
const main: A[] = []
const secondary: A[] = []
for (const a of actions) {
const p = classifyActionPriority(a)
if (p === 'secondary') secondary.push(a)
else if (p === 'primary' && !primary) primary = a
else main.push(a)
}
return { primary, main, secondary }
}
/**
* Una acción que despacha por capacidad (`trigger.type: "capability"`) sólo se
* ofrece si algún addon instalado la provee. Sin provider = desconocido → se
* muestra (el servidor revalida igual).
*/
export function isActionProviderActive(action: PrioritizableAction, installed: InstalledAddonsValue | null): boolean {
const t = action.trigger
if (!installed || !t || t.type !== 'capability' || !t.capability) return true
return installed.capabilities.has(t.capability)
}