fix(docs): secure adaptive handbook projections
This commit is contained in:
@@ -110,11 +110,12 @@ export type DocsDocumentationTopic = {
|
||||
|
||||
export type DocsContext = {
|
||||
actor: {
|
||||
tenant_id: string;
|
||||
user_id: string;
|
||||
scope_count: number;
|
||||
tenant_id?: string;
|
||||
user_id?: string;
|
||||
scope_count?: number;
|
||||
documentation_type: "admin" | "user";
|
||||
locale: string;
|
||||
available_documentation_types: Array<"admin" | "user">;
|
||||
};
|
||||
summary: {
|
||||
module_count: number;
|
||||
|
||||
@@ -123,7 +123,11 @@ export default function DocsPage({ settings }: { settings: ApiSettings }) {
|
||||
<aside className="section-sidebar docs-outline" aria-label="i18n:govoplan-docs.documentation_outline.6f836b99">
|
||||
<div className="docs-sidebar-header">
|
||||
<div className="section-title">i18n:govoplan-docs.help_center.f3f3a34b</div>
|
||||
<AudienceToggle selected={documentationType} onSelect={selectDocumentationType} />
|
||||
<AudienceToggle
|
||||
selected={documentationType}
|
||||
onSelect={selectDocumentationType}
|
||||
canViewAdmin={context?.actor.available_documentation_types.includes("admin") ?? documentationType === "admin"}
|
||||
/>
|
||||
</div>
|
||||
<nav className="docs-tree" aria-label="i18n:govoplan-docs.documentation_outline.6f836b99">
|
||||
<ExplorerTree
|
||||
@@ -211,7 +215,13 @@ export default function DocsPage({ settings }: { settings: ApiSettings }) {
|
||||
}
|
||||
}
|
||||
|
||||
function AudienceToggle({ selected, onSelect }: { selected: DocumentationType; onSelect: (type: DocumentationType) => void }) {
|
||||
function AudienceToggle({ selected, onSelect, canViewAdmin }: { selected: DocumentationType; onSelect: (type: DocumentationType) => void; canViewAdmin: boolean }) {
|
||||
const options: Array<{ id: DocumentationType; label: string }> = [
|
||||
{ id: "user", label: "i18n:govoplan-docs.user_docs.1e38e8d3" }
|
||||
];
|
||||
if (canViewAdmin) {
|
||||
options.unshift({ id: "admin", label: "i18n:govoplan-docs.admin_docs.bf504a56" });
|
||||
}
|
||||
return (
|
||||
<SegmentedControl
|
||||
className="docs-audience-toggle"
|
||||
@@ -221,10 +231,7 @@ function AudienceToggle({ selected, onSelect }: { selected: DocumentationType; o
|
||||
ariaLabel="i18n:govoplan-docs.documentation_type.5a66690c"
|
||||
value={selected}
|
||||
onChange={onSelect}
|
||||
options={[
|
||||
{ id: "admin", label: "i18n:govoplan-docs.admin_docs.bf504a56" },
|
||||
{ id: "user", label: "i18n:govoplan-docs.user_docs.1e38e8d3" }
|
||||
]}
|
||||
options={options}
|
||||
/>
|
||||
);
|
||||
}
|
||||
@@ -365,10 +372,16 @@ function WorkflowDetails({ topic, documentationType, topicById }: { topic: DocsD
|
||||
const outcome = metadataString(topic.metadata, "outcome");
|
||||
const result = metadataString(topic.metadata, "result");
|
||||
const verification = metadataString(topic.metadata, "verification");
|
||||
const currentConfiguration = metadataList(topic.metadata, "current_configuration");
|
||||
const limitations = metadataList(topic.metadata, "limitations");
|
||||
const constraints = metadataRecords(topic.metadata, "constraints");
|
||||
const prefix = topicAnchorId(topic);
|
||||
return (
|
||||
<div className="docs-topic-details">
|
||||
{outcome && <DetailBlock id={`${prefix}-outcome`} title="i18n:govoplan-docs.outcome.10172bd3" value={outcome} />}
|
||||
{!!currentConfiguration.length && <DetailList id={`${prefix}-current-configuration`} title="i18n:govoplan-docs.this_system.b13a51ad" items={currentConfiguration} />}
|
||||
{!!constraints.length && <ConstraintDetails id={`${prefix}-constraints`} constraints={constraints} />}
|
||||
{!!limitations.length && <DetailList id={`${prefix}-limitations`} title="i18n:govoplan-docs.details.a6b3c45f" items={limitations} />}
|
||||
{!!prerequisites.length && <DetailList id={`${prefix}-prerequisites`} title="i18n:govoplan-docs.prerequisites.fdf2407f" items={prerequisites} />}
|
||||
{!!steps.length &&
|
||||
<div className="docs-detail-block" id={`${prefix}-steps`}>
|
||||
@@ -385,6 +398,30 @@ function WorkflowDetails({ topic, documentationType, topicById }: { topic: DocsD
|
||||
);
|
||||
}
|
||||
|
||||
function ConstraintDetails({ id, constraints }: { id: string; constraints: Record<string, unknown>[] }) {
|
||||
return (
|
||||
<div className="docs-detail-block" id={id}>
|
||||
<h4>i18n:govoplan-docs.requirements.09a428f9</h4>
|
||||
<dl className="detail-list compact">
|
||||
{constraints.map((constraint, index) => {
|
||||
const label = metadataString(constraint, "label");
|
||||
const description = metadataString(constraint, "description");
|
||||
const values = metadataList(constraint, "values");
|
||||
return (
|
||||
<div key={metadataString(constraint, "id") || `${label}-${index}`}>
|
||||
<dt>{label}</dt>
|
||||
<dd>
|
||||
{description}
|
||||
{!!values.length && <span className="muted block">{values.join(", ")}</span>}
|
||||
</dd>
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</dl>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
function ReferenceDetails({ topic, showTechnical, documentationType, topicById }: { topic: DocsDocumentationTopic; showTechnical: boolean; documentationType: DocumentationType; topicById: Map<string, DocsDocumentationTopic> }) {
|
||||
const route = metadataString(topic.metadata, "route");
|
||||
const screen = metadataString(topic.metadata, "screen");
|
||||
@@ -783,6 +820,9 @@ function outlineForPage(page: DocsPageNode | null, showTechnical: boolean): Outl
|
||||
if (topic.summary) items.push({ id: `${prefix}-summary`, label: "i18n:govoplan-docs.summary.d6b9936d" });
|
||||
if (topic.kind === "workflow") {
|
||||
if (metadataString(topic.metadata, "outcome")) items.push({ id: `${prefix}-outcome`, label: "i18n:govoplan-docs.outcome.10172bd3" });
|
||||
if (metadataList(topic.metadata, "current_configuration").length) items.push({ id: `${prefix}-current-configuration`, label: "i18n:govoplan-docs.this_system.b13a51ad" });
|
||||
if (metadataRecords(topic.metadata, "constraints").length) items.push({ id: `${prefix}-constraints`, label: "i18n:govoplan-docs.requirements.09a428f9" });
|
||||
if (metadataList(topic.metadata, "limitations").length) items.push({ id: `${prefix}-limitations`, label: "i18n:govoplan-docs.details.a6b3c45f" });
|
||||
if (metadataList(topic.metadata, "prerequisites").length) items.push({ id: `${prefix}-prerequisites`, label: "i18n:govoplan-docs.prerequisites.fdf2407f" });
|
||||
if (metadataList(topic.metadata, "steps").length) items.push({ id: `${prefix}-steps`, label: "i18n:govoplan-docs.steps.6041435e" });
|
||||
if (metadataString(topic.metadata, "result")) items.push({ id: `${prefix}-result`, label: "i18n:govoplan-docs.result.1f4fbf43" });
|
||||
@@ -800,7 +840,7 @@ function outlineForPage(page: DocsPageNode | null, showTechnical: boolean): Outl
|
||||
}
|
||||
|
||||
function documentationTypeFromSearch(search: string): DocumentationType {
|
||||
return new URLSearchParams(search).get("type") === "user" ? "user" : "admin";
|
||||
return new URLSearchParams(search).get("type") === "admin" ? "admin" : "user";
|
||||
}
|
||||
|
||||
function localeFromSearch(search: string): string | null {
|
||||
|
||||
@@ -4,7 +4,7 @@ import { generatedTranslations } from "./i18n/generatedTranslations";
|
||||
|
||||
const DocsPage = lazy(() => import("./features/docs/DocsPage"));
|
||||
|
||||
const docsReadScopes = ["docs:documentation:read", "system:settings:read", "admin:settings:read"];
|
||||
const docsReadScopes = ["docs:documentation:read", "docs:documentation:admin", "system:settings:read", "admin:settings:read"];
|
||||
|
||||
const translations = {
|
||||
en: generatedTranslations.en,
|
||||
@@ -14,7 +14,7 @@ const translations = {
|
||||
export const docsModule: PlatformWebModule = {
|
||||
id: "docs",
|
||||
label: "i18n:govoplan-docs.docs.68a41942",
|
||||
version: "1.0.0",
|
||||
version: "0.1.9",
|
||||
dependencies: ["access"],
|
||||
optionalDependencies: ["policy", "audit", "ops", "workflow", "search"],
|
||||
translations,
|
||||
@@ -24,4 +24,4 @@ export const docsModule: PlatformWebModule = {
|
||||
|
||||
};
|
||||
|
||||
export default docsModule;
|
||||
export default docsModule;
|
||||
|
||||
Reference in New Issue
Block a user