diff --git a/backend/entity_archetypes/ui_profiles.py b/backend/entity_archetypes/ui_profiles.py
index b807145..9d5d606 100644
--- a/backend/entity_archetypes/ui_profiles.py
+++ b/backend/entity_archetypes/ui_profiles.py
@@ -83,7 +83,7 @@ INITIATIVE_UI_PROFILES: dict[str, dict[str, Any]] = {
"workDefaultRoute": "/work/sprint",
"workDefaultRouteWithoutActiveWorkCycle": "/work/today",
"controlDefaultRoute": "/control/status",
- "planOutlineKeys": ["profile", "inbox", "sprint", "gates"],
+ "planOutlineKeys": ["profile", "inbox", "work", "sprint", "gates"],
"workNavKeys": ["sprint", "today", "mine"],
"dataSlices": [
"backlog",
diff --git a/frontend/src/config/methodUiDefaults.js b/frontend/src/config/methodUiDefaults.js
index 88928ab..2b3ab78 100644
--- a/frontend/src/config/methodUiDefaults.js
+++ b/frontend/src/config/methodUiDefaults.js
@@ -54,7 +54,7 @@ const ARCHETYPE_UI = {
planDefaultRoute: '/plan/inbox',
workDefaultRoute: '/work/sprint',
controlDefaultRoute: '/control/status',
- planOutlineKeys: ['profile', 'inbox', 'sprint', 'gates'],
+ planOutlineKeys: ['profile', 'inbox', 'work', 'sprint', 'gates'],
workNavKeys: ['sprint', 'today', 'mine'],
},
'initiative.linear_project': {
@@ -130,8 +130,10 @@ export function resolveProcessSteps(input = {}) {
export function resolvePlanOutlineNodes(input = {}) {
const { planOutlineKeys } = resolveMethodUiDefaults(input)
if (!planOutlineKeys) return PLAN_OUTLINE_NODES
- const allowed = new Set(planOutlineKeys)
- return PLAN_OUTLINE_NODES.filter((node) => allowed.has(node.key))
+ 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),
+ )
}
/**
diff --git a/frontend/src/config/methodUiDefaults.test.js b/frontend/src/config/methodUiDefaults.test.js
index cf26d43..1ddfe0d 100644
--- a/frontend/src/config/methodUiDefaults.test.js
+++ b/frontend/src/config/methodUiDefaults.test.js
@@ -15,7 +15,7 @@ describe('methodUiDefaults', () => {
})
expect(ui.planDefaultRoute).toBe('/plan/inbox')
expect(ui.workDefaultRoute).toBe('/work/sprint')
- expect(ui.planOutlineKeys).toEqual(['profile', 'inbox', 'sprint', 'gates'])
+ expect(ui.planOutlineKeys).toEqual(['profile', 'inbox', 'work', 'sprint', 'gates'])
expect(resolveWorkNavItems({ archetypeKey: 'initiative.product' }).map((i) => i.key)).toEqual([
'sprint',
'today',
@@ -41,6 +41,12 @@ describe('methodUiDefaults', () => {
])
})
+ it('product plan outline includes work for direct AP path', () => {
+ expect(
+ resolvePlanOutlineNodes({ archetypeKey: 'initiative.product' }).map((n) => n.key),
+ ).toEqual(['profile', 'inbox', 'work', 'sprint', 'gates'])
+ })
+
it('linear archetype defaults to gates and filters plan outline', () => {
const ui = resolveMethodUiDefaults({ archetypeKey: 'initiative.linear_project' })
expect(ui.planDefaultRoute).toBe('/plan/gates')
diff --git a/frontend/src/pages/modes/PlanWorkPage.jsx b/frontend/src/pages/modes/PlanWorkPage.jsx
index 67e5cbd..a2ac3c9 100644
--- a/frontend/src/pages/modes/PlanWorkPage.jsx
+++ b/frontend/src/pages/modes/PlanWorkPage.jsx
@@ -13,6 +13,7 @@ function PlanWorkInner() {
const { initiativeId, projectId: scopeProjectId, hrefWithScope } = useProgramScope()
const [executionGraph, setExecutionGraph] = useState(null)
const {
+ initiative,
actions,
projects,
roadmapItems,
@@ -52,6 +53,11 @@ function PlanWorkInner() {
return
{error}
} @@ -76,7 +82,7 @@ function PlanWorkInner() { busy={formBusy} executionGraph={executionGraph} sectionTitle="Alle Arbeitspakete" - sectionLead="Gesamt-Ist am Vorhaben — Sprint-fokussierte Arbeit unter Ausführen → Sprint." + sectionLead={sectionLead} /> > ) diff --git a/frontend/src/registry/resolveOperatingProfile.js b/frontend/src/registry/resolveOperatingProfile.js index 671d40b..a2f5ffe 100644 --- a/frontend/src/registry/resolveOperatingProfile.js +++ b/frontend/src/registry/resolveOperatingProfile.js @@ -145,8 +145,10 @@ export function resolveOperatingProfileFromInput(input = {}) { export function resolvePlanOutlineNodesFromProfile(input = {}) { const { planOutlineKeys } = resolveOperatingProfileFromInput(input) if (!planOutlineKeys) return PLAN_OUTLINE_NODES - const allowed = new Set(planOutlineKeys) - return PLAN_OUTLINE_NODES.filter((node) => allowed.has(node.key)) + 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), + ) } /** diff --git a/frontend/src/registry/resolveOperatingProfile.test.js b/frontend/src/registry/resolveOperatingProfile.test.js index 805f07f..58fb77e 100644 --- a/frontend/src/registry/resolveOperatingProfile.test.js +++ b/frontend/src/registry/resolveOperatingProfile.test.js @@ -21,7 +21,7 @@ const PRODUCT_CONTEXT = { workDefaultRoute: '/work/sprint', workDefaultRouteWithoutActiveWorkCycle: '/work/today', controlDefaultRoute: '/control/status', - planOutlineKeys: ['profile', 'inbox', 'sprint', 'gates'], + planOutlineKeys: ['profile', 'inbox', 'work', 'sprint', 'gates'], workNavKeys: ['sprint', 'today', 'mine'], }, data_slices: ['backlog', 'actions', 'roadmap', 'work_cycles', 'projects'],