feat: preserve full-page launch context
This commit is contained in:
@@ -37,5 +37,10 @@ owner module.
|
|||||||
|
|
||||||
Quick Access is not an authorization boundary. Every contribution keeps its
|
Quick Access is not an authorization boundary. Every contribution keeps its
|
||||||
own permission requirements and View surface. Full-page routes remain the
|
own permission requirements and View surface. Full-page routes remain the
|
||||||
canonical fallback. Disabling this module removes the rail without making any
|
canonical fallback. Launch context version 1 contains only the tenant/account
|
||||||
domain state unavailable through its owning module.
|
identity, safe active-object reference, acting-assignment identifiers,
|
||||||
|
temporal selection, exact View identity, and return route. Cross-tenant object
|
||||||
|
references are discarded and unknown context versions are ignored. The
|
||||||
|
destination reauthorizes every read and effect. Disabling this module removes
|
||||||
|
the rail without making any domain state unavailable through its owning
|
||||||
|
module.
|
||||||
|
|||||||
@@ -121,6 +121,9 @@ DOCUMENTATION = (
|
|||||||
"Messages combines enabled Mail, Postbox, and future chat contributions in one overlay. "
|
"Messages combines enabled Mail, Postbox, and future chat contributions in one overlay. "
|
||||||
"Personal settings can reorder or hide items that remain available under system, tenant, "
|
"Personal settings can reorder or hide items that remain available under system, tenant, "
|
||||||
"permission, and View policy. Every item retains a link to its complete owning page. "
|
"permission, and View policy. Every item retains a link to its complete owning page. "
|
||||||
|
"That launch carries a versioned, bounded reference to the current object, acting assignment, "
|
||||||
|
"temporal selection, View revision, and return location. The destination rechecks access, and "
|
||||||
|
"the breadcrumb return action restores the originating route without copying protected content."
|
||||||
),
|
),
|
||||||
layer="configured",
|
layer="configured",
|
||||||
documentation_types=("user",),
|
documentation_types=("user",),
|
||||||
@@ -140,6 +143,8 @@ DOCUMENTATION = (
|
|||||||
"Eine Kategorie in der rechten Leiste oeffnet kompakte Werkzeuge, ohne die aktuelle Aufgabe zu verlassen. "
|
"Eine Kategorie in der rechten Leiste oeffnet kompakte Werkzeuge, ohne die aktuelle Aufgabe zu verlassen. "
|
||||||
"Nachrichten fuehrt Beitraege aus Mail, Postfach und kuenftigen Chat-Modulen in einer Einblendung zusammen. "
|
"Nachrichten fuehrt Beitraege aus Mail, Postfach und kuenftigen Chat-Modulen in einer Einblendung zusammen. "
|
||||||
"Persoenliche Einstellungen koennen alle durch System, Mandant, Berechtigungen und Ansicht zugelassenen Eintraege ordnen oder ausblenden. "
|
"Persoenliche Einstellungen koennen alle durch System, Mandant, Berechtigungen und Ansicht zugelassenen Eintraege ordnen oder ausblenden. "
|
||||||
|
"Beim Oeffnen der vollstaendigen Seite werden nur versionierte, begrenzte Verweise auf Objekt, handelnde Zuordnung, "
|
||||||
|
"Zeitbezug, Ansichtsversion und Ruecksprungort uebergeben. Das Ziel prueft den Zugriff erneut."
|
||||||
),
|
),
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -159,6 +164,7 @@ DOCUMENTATION = (
|
|||||||
"The catalogue follows installed module registrations. System settings constrain tenants; "
|
"The catalogue follows installed module registrations. System settings constrain tenants; "
|
||||||
"tenant settings constrain users. An item may remain available, be blocked, or be forced. "
|
"tenant settings constrain users. An item may remain available, be blocked, or be forced. "
|
||||||
"Views and permissions form additional ceilings and Quick Access never grants access to domain data. "
|
"Views and permissions form additional ceilings and Quick Access never grants access to domain data. "
|
||||||
|
"Launch context version 1 rejects cross-tenant active-object references and unknown context versions fail closed."
|
||||||
),
|
),
|
||||||
layer="configured",
|
layer="configured",
|
||||||
documentation_types=("admin",),
|
documentation_types=("admin",),
|
||||||
@@ -171,6 +177,7 @@ DOCUMENTATION = (
|
|||||||
"Der Katalog folgt den Registrierungen installierter Module. Systemeinstellungen begrenzen Mandanten, "
|
"Der Katalog folgt den Registrierungen installierter Module. Systemeinstellungen begrenzen Mandanten, "
|
||||||
"Mandanteneinstellungen begrenzen Benutzer. Ein Eintrag kann verfuegbar, gesperrt oder erzwungen sein. "
|
"Mandanteneinstellungen begrenzen Benutzer. Ein Eintrag kann verfuegbar, gesperrt oder erzwungen sein. "
|
||||||
"Ansichten und Berechtigungen bilden weitere Grenzen; Schnellzugriff erteilt selbst keinen Datenzugriff. "
|
"Ansichten und Berechtigungen bilden weitere Grenzen; Schnellzugriff erteilt selbst keinen Datenzugriff. "
|
||||||
|
"Startkontext Version 1 verwirft mandantenfremde Objektverweise; unbekannte Versionen werden abgelehnt."
|
||||||
),
|
),
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -13,6 +13,9 @@ import {
|
|||||||
DismissibleAlert,
|
DismissibleAlert,
|
||||||
IconButton,
|
IconButton,
|
||||||
LoadingFrame,
|
LoadingFrame,
|
||||||
|
dispatchQuickAccessResult,
|
||||||
|
quickAccessLaunchState,
|
||||||
|
useGuardedNavigate,
|
||||||
usePlatformLanguage,
|
usePlatformLanguage,
|
||||||
usePlatformUiCapabilities,
|
usePlatformUiCapabilities,
|
||||||
type QuickAccessRailProps,
|
type QuickAccessRailProps,
|
||||||
@@ -32,7 +35,7 @@ const iconByCategory: Record<string, LucideIcon> = {
|
|||||||
files: Files
|
files: Files
|
||||||
};
|
};
|
||||||
|
|
||||||
export default function QuickAccessRail({ settings, auth, tools }: QuickAccessRailProps) {
|
export default function QuickAccessRail({ settings, auth, tools, launchContext }: QuickAccessRailProps) {
|
||||||
const [effective, setEffective] = useState<EffectiveQuickAccess | null>(null);
|
const [effective, setEffective] = useState<EffectiveQuickAccess | null>(null);
|
||||||
const [activeCategoryId, setActiveCategoryId] = useState<string | null>(null);
|
const [activeCategoryId, setActiveCategoryId] = useState<string | null>(null);
|
||||||
const [loading, setLoading] = useState(true);
|
const [loading, setLoading] = useState(true);
|
||||||
@@ -40,6 +43,7 @@ export default function QuickAccessRail({ settings, auth, tools }: QuickAccessRa
|
|||||||
const drawerRef = useRef<HTMLDivElement>(null);
|
const drawerRef = useRef<HTMLDivElement>(null);
|
||||||
const triggerRef = useRef<HTMLButtonElement | null>(null);
|
const triggerRef = useRef<HTMLButtonElement | null>(null);
|
||||||
const location = useLocation();
|
const location = useLocation();
|
||||||
|
const navigate = useGuardedNavigate();
|
||||||
const contributions = usePlatformUiCapabilities<QuickAccessToolsUiCapability>("quickAccess.tools");
|
const contributions = usePlatformUiCapabilities<QuickAccessToolsUiCapability>("quickAccess.tools");
|
||||||
const { translateText } = usePlatformLanguage();
|
const { translateText } = usePlatformLanguage();
|
||||||
const renderers = useMemo(
|
const renderers = useMemo(
|
||||||
@@ -125,6 +129,11 @@ export default function QuickAccessRail({ settings, auth, tools }: QuickAccessRa
|
|||||||
setActiveCategoryId(category.id);
|
setActiveCategoryId(category.id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function openFullPage(path: string) {
|
||||||
|
closeDrawer(false);
|
||||||
|
navigate(path, { state: quickAccessLaunchState(launchContext) });
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<aside className="quick-access-rail" aria-label="i18n:govoplan-quick-access.quick_access">
|
<aside className="quick-access-rail" aria-label="i18n:govoplan-quick-access.quick_access">
|
||||||
@@ -187,10 +196,28 @@ export default function QuickAccessRail({ settings, auth, tools }: QuickAccessRa
|
|||||||
<strong>{translateText(tool.label)}</strong>
|
<strong>{translateText(tool.label)}</strong>
|
||||||
{tool.description ? <small>{translateText(tool.description)}</small> : null}
|
{tool.description ? <small>{translateText(tool.description)}</small> : null}
|
||||||
</div>
|
</div>
|
||||||
{tool.full_page_path ? <Link to={tool.full_page_path} onClick={() => closeDrawer(false)}>i18n:govoplan-quick-access.open_full_page</Link> : null}
|
{tool.full_page_path ? (
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
className="quick-access-full-page-link"
|
||||||
|
onClick={() => openFullPage(tool.full_page_path!)}
|
||||||
|
>
|
||||||
|
i18n:govoplan-quick-access.open_full_page
|
||||||
|
</button>
|
||||||
|
) : null}
|
||||||
</div>
|
</div>
|
||||||
{renderer
|
{renderer
|
||||||
? renderer.render({ settings, auth, close: () => closeDrawer(), active: true })
|
? renderer.render({
|
||||||
|
settings,
|
||||||
|
auth,
|
||||||
|
close: () => closeDrawer(),
|
||||||
|
active: true,
|
||||||
|
launchContext,
|
||||||
|
complete: (result) => {
|
||||||
|
dispatchQuickAccessResult(tool.id, launchContext, result);
|
||||||
|
closeDrawer();
|
||||||
|
}
|
||||||
|
})
|
||||||
: <p className="quick-access-tool-unavailable">i18n:govoplan-quick-access.compact_view_unavailable</p>}
|
: <p className="quick-access-tool-unavailable">i18n:govoplan-quick-access.compact_view_unavailable</p>}
|
||||||
</section>
|
</section>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -34,7 +34,7 @@
|
|||||||
display: grid;
|
display: grid;
|
||||||
place-items: center;
|
place-items: center;
|
||||||
border: 0;
|
border: 0;
|
||||||
border-radius: 4px;
|
border-radius: var(--radius-sm);
|
||||||
color: var(--muted);
|
color: var(--muted);
|
||||||
background: transparent;
|
background: transparent;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
@@ -61,7 +61,7 @@
|
|||||||
margin: 11px auto;
|
margin: 11px auto;
|
||||||
border: 2px solid var(--border);
|
border: 2px solid var(--border);
|
||||||
border-top-color: var(--accent);
|
border-top-color: var(--accent);
|
||||||
border-radius: 50%;
|
border-radius: var(--radius-round);
|
||||||
animation: quick-access-spin 0.8s linear infinite;
|
animation: quick-access-spin 0.8s linear infinite;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -76,7 +76,7 @@
|
|||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
border-left: var(--border-line);
|
border-left: var(--border-line);
|
||||||
box-shadow: -12px 0 30px rgb(0 0 0 / 18%);
|
box-shadow: var(--shadow-drawer-side);
|
||||||
background: var(--panel);
|
background: var(--panel);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -141,12 +141,25 @@
|
|||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
}
|
}
|
||||||
|
|
||||||
.quick-access-tool-heading > a {
|
.quick-access-tool-heading > a,
|
||||||
|
.quick-access-full-page-link {
|
||||||
flex: 0 0 auto;
|
flex: 0 0 auto;
|
||||||
color: var(--accent);
|
color: var(--accent);
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.quick-access-full-page-link {
|
||||||
|
border: 0;
|
||||||
|
background: transparent;
|
||||||
|
font-family: inherit;
|
||||||
|
font-weight: 700;
|
||||||
|
padding: 0;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.quick-access-full-page-link:hover,
|
||||||
|
.quick-access-full-page-link:focus-visible { text-decoration: underline; }
|
||||||
|
|
||||||
.quick-access-settings {
|
.quick-access-settings {
|
||||||
min-width: 0;
|
min-width: 0;
|
||||||
display: grid;
|
display: grid;
|
||||||
@@ -250,7 +263,7 @@
|
|||||||
height: min(70vh, 680px);
|
height: min(70vh, 680px);
|
||||||
border-top: var(--border-line);
|
border-top: var(--border-line);
|
||||||
border-left: 0;
|
border-left: 0;
|
||||||
box-shadow: 0 -12px 30px rgb(0 0 0 / 18%);
|
box-shadow: var(--shadow-drawer-bottom);
|
||||||
}
|
}
|
||||||
|
|
||||||
.quick-access-preference-row {
|
.quick-access-preference-row {
|
||||||
|
|||||||
Reference in New Issue
Block a user