diff --git a/frontend/src/pages/InitiativeDetailPage.jsx b/frontend/src/pages/InitiativeDetailPage.jsx index b07f1ca..acab978 100644 --- a/frontend/src/pages/InitiativeDetailPage.jsx +++ b/frontend/src/pages/InitiativeDetailPage.jsx @@ -41,7 +41,7 @@ import { useSession } from '../context/SessionContext.jsx' export function InitiativeDetailPage() { const { id } = useParams() - const { context } = useSession() + const { context, loading: sessionLoading } = useSession() const { capabilities } = useCapabilities() const { actors, @@ -64,6 +64,7 @@ export function InitiativeDetailPage() { const [hideDone, setHideDone] = useState(true) const load = useCallback(async () => { + if (sessionLoading) return setLoading(true) setError(null) try { @@ -75,13 +76,12 @@ export function InitiativeDetailPage() { setActions(actionData) const loads = [] - if (capabilities.has('kairo.blocker.read')) { + const canReadOm = + capabilities.has('kairo.initiative.read') || + capabilities.has('kairo.blocker.read') + if (canReadOm) { loads.push(listInitiativeBlockers(id).then(setBlockers).catch(() => setBlockers([]))) - } - if (capabilities.has('kairo.backlog.read')) { loads.push(listInitiativeBacklog(id).then(setBacklogItems).catch(() => setBacklogItems([]))) - } - if (capabilities.has('kairo.milestone.read')) { loads.push(listInitiativeMilestones(id).then(setMilestones).catch(() => setMilestones([]))) } await Promise.all(loads) @@ -90,7 +90,7 @@ export function InitiativeDetailPage() { } finally { setLoading(false) } - }, [id, capabilities]) + }, [id, capabilities, sessionLoading]) useEffect(() => { load() @@ -405,7 +405,7 @@ export function InitiativeDetailPage() { - {capabilities.has('kairo.milestone.read') && ( + {capabilities.has('kairo.initiative.read') && ( )} - {capabilities.has('kairo.backlog.read') && ( + {capabilities.has('kairo.initiative.read') && ( )} - {capabilities.has('kairo.blocker.read') && ( + {capabilities.has('kairo.initiative.read') && ( { 'kairo.action.read', 'kairo.initiative.read', 'kairo.workspace.read', - 'kairo.attention.read', ]) expect(all.length).toBe(6) const readOnly = getWidgetsForArea('workspace', ['kairo.initiative.read']) expect(readOnly.some((w) => w.key === 'kairo.my_open_actions')).toBe(false) expect(readOnly.some((w) => w.key === 'kairo.active_initiatives')).toBe(true) + expect(readOnly.some((w) => w.key === 'kairo.attention')).toBe(false) }) }) diff --git a/frontend/src/registry/widgetRegistry.js b/frontend/src/registry/widgetRegistry.js index fabfc07..0f36a98 100644 --- a/frontend/src/registry/widgetRegistry.js +++ b/frontend/src/registry/widgetRegistry.js @@ -42,7 +42,7 @@ export const WIDGETS = [ title: 'Aufmerksamkeit', description: 'Regelbasierte Attention-Items', area: 'workspace', - requiredCapability: 'kairo.attention.read', + requiredCapability: 'kairo.workspace.read', defaultOrder: 8, component: AttentionWidget, }, diff --git a/frontend/src/widgets/TenantContextWidget.jsx b/frontend/src/widgets/TenantContextWidget.jsx index a8a0c9d..cb600ed 100644 --- a/frontend/src/widgets/TenantContextWidget.jsx +++ b/frontend/src/widgets/TenantContextWidget.jsx @@ -1,8 +1,17 @@ +import { useEffect, useState } from 'react' import { useSession } from '../context/SessionContext.jsx' import { WidgetCard } from '../components/WidgetCard.jsx' export function TenantContextWidget() { const { context, me } = useSession() + const [version, setVersion] = useState(null) + + useEffect(() => { + fetch('/api/version') + .then((r) => r.json()) + .then((data) => setVersion(data)) + .catch(() => setVersion(null)) + }, []) return ( @@ -28,6 +37,14 @@ export function TenantContextWidget() { {context.actor.type} )} + {version && ( + + App-Version + + {version.version} ยท Schema {version.schema} + + + )} )}