/** * AP1.9d — Methoden-Default-UI (DEPRECATED AP2.3b — Fallback bis Resolver live). * Bevorzugt: GET /api/initiatives/:id/operating-context + resolveOperatingProfile.js * * @typedef {{ key: string, to: string, label: string, mode: 'plan'|'work'|'control' }} ProcessStep * @typedef {{ * archetypeKey: string | null, * methodKey: string | null, * hasActiveSprint: boolean, * }} MethodUiInput * @typedef {{ * processSteps: ProcessStep[], * planDefaultRoute: string, * workDefaultRoute: string, * controlDefaultRoute: string, * planOutlineKeys: string[] | null, * workNavKeys: string[] | null, * }} MethodUiDefaults */ import { PLAN_OUTLINE_NODES } from '../plan/planOutlineNodes.js' import { WORK_NAV_ITEMS } from './workNav.js' const PRODUCT_PROCESS = [ { key: 'inbox', to: '/plan/inbox', label: 'Eingang', mode: 'plan' }, { key: 'sprint-plan', to: '/plan/sprint', label: 'Sprint planen', mode: 'plan' }, { key: 'sprint-work', to: '/work/sprint', label: 'Ausführen', mode: 'work' }, { key: 'control', to: '/control/status', label: 'Kontrolle', mode: 'control' }, ] const LINEAR_PROCESS = [ { key: 'gates', to: '/plan/gates', label: 'Zielzustände', mode: 'plan' }, { key: 'work', to: '/work/today', label: 'Ausführen', mode: 'work' }, { key: 'control', to: '/control/status', label: 'Kontrolle', mode: 'control' }, ] const MATURITY_PROCESS = [ { key: 'gates', to: '/plan/gates', label: 'Stufen', mode: 'plan' }, { key: 'journey', to: '/control/journey', label: 'Rhythmen', mode: 'control' }, { key: 'work', to: '/work/today', label: 'Ausführen', mode: 'work' }, { key: 'control', to: '/control/status', label: 'Kontrolle', mode: 'control' }, ] const PROGRAM_PROCESS = [ { key: 'gates', to: '/plan/gates', label: 'Phasen', mode: 'plan' }, { key: 'inbox', to: '/plan/inbox', label: 'Eingang', mode: 'plan' }, { key: 'work', to: '/work/today', label: 'Ausführen', mode: 'work' }, { key: 'control', to: '/control/status', label: 'Kontrolle', mode: 'control' }, ] const ARCHETYPE_UI = { 'initiative.product': { processSteps: PRODUCT_PROCESS, planDefaultRoute: '/plan/inbox', workDefaultRoute: '/work/sprint', controlDefaultRoute: '/control/status', planOutlineKeys: ['profile', 'inbox', 'work', 'sprint', 'gates'], workNavKeys: ['sprint', 'today', 'mine'], }, 'initiative.linear_project': { processSteps: LINEAR_PROCESS, planDefaultRoute: '/plan/gates', workDefaultRoute: '/work/today', controlDefaultRoute: '/control/status', planOutlineKeys: ['profile', 'structure', 'gates', 'inbox', 'work'], workNavKeys: ['today', 'mine', 'sprint'], }, 'initiative.maturity_journey': { processSteps: MATURITY_PROCESS, planDefaultRoute: '/plan/gates', workDefaultRoute: '/work/today', controlDefaultRoute: '/control/status', planOutlineKeys: ['profile', 'gates', 'work'], workNavKeys: ['today', 'mine', 'sprint'], }, 'initiative.program': { processSteps: PROGRAM_PROCESS, planDefaultRoute: '/plan/gates', workDefaultRoute: '/work/today', controlDefaultRoute: '/control/status', planOutlineKeys: ['profile', 'structure', 'gates', 'inbox', 'sprint', 'work'], workNavKeys: ['today', 'mine', 'sprint'], }, } const FALLBACK_DEFAULTS = { processSteps: [], planDefaultRoute: '/plan/profile', workDefaultRoute: '/work/today', controlDefaultRoute: '/control/status', planOutlineKeys: null, workNavKeys: null, } /** * @param {MethodUiInput} input * @returns {MethodUiDefaults} */ export function resolveMethodUiDefaults(input = {}) { const archetypeKey = input.archetypeKey || null const base = ARCHETYPE_UI[archetypeKey] || FALLBACK_DEFAULTS let workDefaultRoute = base.workDefaultRoute if (archetypeKey === 'initiative.product' && !input.hasActiveSprint) { workDefaultRoute = '/work/today' } return { processSteps: base.processSteps, planDefaultRoute: base.planDefaultRoute, workDefaultRoute, controlDefaultRoute: base.controlDefaultRoute, planOutlineKeys: base.planOutlineKeys, workNavKeys: base.workNavKeys, } } /** * @param {MethodUiInput} input * @returns {ProcessStep[]} */ export function resolveProcessSteps(input = {}) { return resolveMethodUiDefaults(input).processSteps } /** * @param {MethodUiInput} input * @returns {typeof PLAN_OUTLINE_NODES} */ export function resolvePlanOutlineNodes(input = {}) { const { planOutlineKeys } = resolveMethodUiDefaults(input) if (!planOutlineKeys) return PLAN_OUTLINE_NODES const order = new Map(planOutlineKeys.map((key, index) => [key, index])) return PLAN_OUTLINE_NODES.filter((node) => order.has(node.key)).sort( (a, b) => (order.get(a.key) ?? 0) - (order.get(b.key) ?? 0), ) } /** * @param {MethodUiInput} input * @returns {typeof WORK_NAV_ITEMS} */ export function resolveWorkNavItems(input = {}) { const { workNavKeys } = resolveMethodUiDefaults(input) if (!workNavKeys) return WORK_NAV_ITEMS const order = new Map(workNavKeys.map((key, index) => [key, index])) return WORK_NAV_ITEMS.filter((item) => order.has(item.key)).sort( (a, b) => (order.get(a.key) ?? 0) - (order.get(b.key) ?? 0), ) } /** * Aktiven Prozessschritt aus Modus + Pfad ableiten. * @param {string} pathname * @param {ProcessStep[]} steps */ export function resolveActiveProcessStepKey(pathname, steps) { const path = (pathname || '').replace(/\/$/, '') || pathname if (!steps.length) return null if (path.startsWith('/control/')) { const journey = steps.find((s) => s.key === 'journey') if (journey && path.startsWith('/control/journey')) return 'journey' return steps.find((s) => s.mode === 'control')?.key ?? null } if (path.startsWith('/work/')) { if (path.startsWith('/work/sprint')) { return steps.find((s) => s.key === 'sprint-work')?.key ?? null } return steps.find((s) => s.key === 'work')?.key ?? null } if (path.startsWith('/plan/')) { if (path.startsWith('/plan/inbox')) return 'inbox' if (path.startsWith('/plan/sprint')) return 'sprint-plan' if (path.startsWith('/plan/gates')) return 'gates' } if (path.startsWith('/actions/')) { return steps.find((s) => s.mode === 'work')?.key ?? null } return null }