feat(product): Plan-Arbeit fuer Direct-AP-Pfad (ADP P1)
All checks were successful
Deploy Development / deploy (push) Successful in 49s
Test Suite / pytest-backend (push) Successful in 3m45s
Test Suite / lint-backend (push) Successful in 2s
Test Suite / compose-smoke (push) Has been skipped
Test Suite / k6 /api/health Baseline (push) Successful in 19s
Test Suite / playwright-smoke (push) Successful in 12s
All checks were successful
Deploy Development / deploy (push) Successful in 49s
Test Suite / pytest-backend (push) Successful in 3m45s
Test Suite / lint-backend (push) Successful in 2s
Test Suite / compose-smoke (push) Has been skipped
Test Suite / k6 /api/health Baseline (push) Successful in 19s
Test Suite / playwright-smoke (push) Successful in 12s
Product-Outline enthaelt work; planOutlineKeys-Reihenfolge steuert Sidebar; Product-spezifischer Lead auf Plan-Arbeit.
This commit is contained in:
parent
f7d65dde01
commit
dc6f25b673
|
|
@ -83,7 +83,7 @@ INITIATIVE_UI_PROFILES: dict[str, dict[str, Any]] = {
|
||||||
"workDefaultRoute": "/work/sprint",
|
"workDefaultRoute": "/work/sprint",
|
||||||
"workDefaultRouteWithoutActiveWorkCycle": "/work/today",
|
"workDefaultRouteWithoutActiveWorkCycle": "/work/today",
|
||||||
"controlDefaultRoute": "/control/status",
|
"controlDefaultRoute": "/control/status",
|
||||||
"planOutlineKeys": ["profile", "inbox", "sprint", "gates"],
|
"planOutlineKeys": ["profile", "inbox", "work", "sprint", "gates"],
|
||||||
"workNavKeys": ["sprint", "today", "mine"],
|
"workNavKeys": ["sprint", "today", "mine"],
|
||||||
"dataSlices": [
|
"dataSlices": [
|
||||||
"backlog",
|
"backlog",
|
||||||
|
|
|
||||||
|
|
@ -54,7 +54,7 @@ const ARCHETYPE_UI = {
|
||||||
planDefaultRoute: '/plan/inbox',
|
planDefaultRoute: '/plan/inbox',
|
||||||
workDefaultRoute: '/work/sprint',
|
workDefaultRoute: '/work/sprint',
|
||||||
controlDefaultRoute: '/control/status',
|
controlDefaultRoute: '/control/status',
|
||||||
planOutlineKeys: ['profile', 'inbox', 'sprint', 'gates'],
|
planOutlineKeys: ['profile', 'inbox', 'work', 'sprint', 'gates'],
|
||||||
workNavKeys: ['sprint', 'today', 'mine'],
|
workNavKeys: ['sprint', 'today', 'mine'],
|
||||||
},
|
},
|
||||||
'initiative.linear_project': {
|
'initiative.linear_project': {
|
||||||
|
|
@ -130,8 +130,10 @@ export function resolveProcessSteps(input = {}) {
|
||||||
export function resolvePlanOutlineNodes(input = {}) {
|
export function resolvePlanOutlineNodes(input = {}) {
|
||||||
const { planOutlineKeys } = resolveMethodUiDefaults(input)
|
const { planOutlineKeys } = resolveMethodUiDefaults(input)
|
||||||
if (!planOutlineKeys) return PLAN_OUTLINE_NODES
|
if (!planOutlineKeys) return PLAN_OUTLINE_NODES
|
||||||
const allowed = new Set(planOutlineKeys)
|
const order = new Map(planOutlineKeys.map((key, index) => [key, index]))
|
||||||
return PLAN_OUTLINE_NODES.filter((node) => allowed.has(node.key))
|
return PLAN_OUTLINE_NODES.filter((node) => order.has(node.key)).sort(
|
||||||
|
(a, b) => (order.get(a.key) ?? 0) - (order.get(b.key) ?? 0),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
||||||
|
|
@ -15,7 +15,7 @@ describe('methodUiDefaults', () => {
|
||||||
})
|
})
|
||||||
expect(ui.planDefaultRoute).toBe('/plan/inbox')
|
expect(ui.planDefaultRoute).toBe('/plan/inbox')
|
||||||
expect(ui.workDefaultRoute).toBe('/work/sprint')
|
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([
|
expect(resolveWorkNavItems({ archetypeKey: 'initiative.product' }).map((i) => i.key)).toEqual([
|
||||||
'sprint',
|
'sprint',
|
||||||
'today',
|
'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', () => {
|
it('linear archetype defaults to gates and filters plan outline', () => {
|
||||||
const ui = resolveMethodUiDefaults({ archetypeKey: 'initiative.linear_project' })
|
const ui = resolveMethodUiDefaults({ archetypeKey: 'initiative.linear_project' })
|
||||||
expect(ui.planDefaultRoute).toBe('/plan/gates')
|
expect(ui.planDefaultRoute).toBe('/plan/gates')
|
||||||
|
|
|
||||||
|
|
@ -13,6 +13,7 @@ function PlanWorkInner() {
|
||||||
const { initiativeId, projectId: scopeProjectId, hrefWithScope } = useProgramScope()
|
const { initiativeId, projectId: scopeProjectId, hrefWithScope } = useProgramScope()
|
||||||
const [executionGraph, setExecutionGraph] = useState(null)
|
const [executionGraph, setExecutionGraph] = useState(null)
|
||||||
const {
|
const {
|
||||||
|
initiative,
|
||||||
actions,
|
actions,
|
||||||
projects,
|
projects,
|
||||||
roadmapItems,
|
roadmapItems,
|
||||||
|
|
@ -52,6 +53,11 @@ function PlanWorkInner() {
|
||||||
return <LoadingState message="Lade Arbeitspakete …" />
|
return <LoadingState message="Lade Arbeitspakete …" />
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const isProduct = initiative?.archetype_key === 'initiative.product'
|
||||||
|
const sectionLead = isProduct
|
||||||
|
? 'Arbeitspakete direkt anlegen (Pfad B) oder committetes Ist — ohne Eingang-Umweg. Sprint-fokussiert unter Ausführen → Sprint.'
|
||||||
|
: 'Gesamt-Ist am Vorhaben — Sprint-fokussierte Arbeit unter Ausführen → Sprint.'
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
{error && <p className="error">{error}</p>}
|
{error && <p className="error">{error}</p>}
|
||||||
|
|
@ -76,7 +82,7 @@ function PlanWorkInner() {
|
||||||
busy={formBusy}
|
busy={formBusy}
|
||||||
executionGraph={executionGraph}
|
executionGraph={executionGraph}
|
||||||
sectionTitle="Alle Arbeitspakete"
|
sectionTitle="Alle Arbeitspakete"
|
||||||
sectionLead="Gesamt-Ist am Vorhaben — Sprint-fokussierte Arbeit unter Ausführen → Sprint."
|
sectionLead={sectionLead}
|
||||||
/>
|
/>
|
||||||
</>
|
</>
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -145,8 +145,10 @@ export function resolveOperatingProfileFromInput(input = {}) {
|
||||||
export function resolvePlanOutlineNodesFromProfile(input = {}) {
|
export function resolvePlanOutlineNodesFromProfile(input = {}) {
|
||||||
const { planOutlineKeys } = resolveOperatingProfileFromInput(input)
|
const { planOutlineKeys } = resolveOperatingProfileFromInput(input)
|
||||||
if (!planOutlineKeys) return PLAN_OUTLINE_NODES
|
if (!planOutlineKeys) return PLAN_OUTLINE_NODES
|
||||||
const allowed = new Set(planOutlineKeys)
|
const order = new Map(planOutlineKeys.map((key, index) => [key, index]))
|
||||||
return PLAN_OUTLINE_NODES.filter((node) => allowed.has(node.key))
|
return PLAN_OUTLINE_NODES.filter((node) => order.has(node.key)).sort(
|
||||||
|
(a, b) => (order.get(a.key) ?? 0) - (order.get(b.key) ?? 0),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
||||||
|
|
@ -21,7 +21,7 @@ const PRODUCT_CONTEXT = {
|
||||||
workDefaultRoute: '/work/sprint',
|
workDefaultRoute: '/work/sprint',
|
||||||
workDefaultRouteWithoutActiveWorkCycle: '/work/today',
|
workDefaultRouteWithoutActiveWorkCycle: '/work/today',
|
||||||
controlDefaultRoute: '/control/status',
|
controlDefaultRoute: '/control/status',
|
||||||
planOutlineKeys: ['profile', 'inbox', 'sprint', 'gates'],
|
planOutlineKeys: ['profile', 'inbox', 'work', 'sprint', 'gates'],
|
||||||
workNavKeys: ['sprint', 'today', 'mine'],
|
workNavKeys: ['sprint', 'today', 'mine'],
|
||||||
},
|
},
|
||||||
data_slices: ['backlog', 'actions', 'roadmap', 'work_cycles', 'projects'],
|
data_slices: ['backlog', 'actions', 'roadmap', 'work_cycles', 'projects'],
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user