Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9f5569ae54 | ||
|
|
705255f378 | ||
|
|
b9b9e9431a |
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@govoplan/wiki-webui",
|
"name": "@govoplan/wiki-webui",
|
||||||
"version": "0.1.20",
|
"version": "0.1.22",
|
||||||
"private": true,
|
"private": true,
|
||||||
"description": "GovOPlaN governed collaborative Wiki module.",
|
"description": "GovOPlaN governed collaborative Wiki module.",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
|
|||||||
+1
-1
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|||||||
|
|
||||||
[project]
|
[project]
|
||||||
name = "govoplan-wiki"
|
name = "govoplan-wiki"
|
||||||
version = "0.1.20"
|
version = "0.1.22"
|
||||||
description = "GovOPlaN governed collaborative Wiki module."
|
description = "GovOPlaN governed collaborative Wiki module."
|
||||||
readme = "README.md"
|
readme = "README.md"
|
||||||
requires-python = ">=3.12"
|
requires-python = ">=3.12"
|
||||||
|
|||||||
@@ -0,0 +1,79 @@
|
|||||||
|
"""German translations for public structured documentation metadata."""
|
||||||
|
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
from typing import Any
|
||||||
|
|
||||||
|
|
||||||
|
GERMAN_STRUCTURED_TRANSLATIONS: dict[str, dict[str, Any]] = {'wiki.admin.access-publishing': {'consequence_classes': {'publisher_mode': 'Die Verlagsautorität '
|
||||||
|
'wird an der '
|
||||||
|
'Aktionsgrenze erneut '
|
||||||
|
'bewertet.',
|
||||||
|
'restricted_without_acl': 'Die '
|
||||||
|
'Konfiguration '
|
||||||
|
'wird '
|
||||||
|
'abgelehnt, um '
|
||||||
|
'eine nicht '
|
||||||
|
'erreichbare '
|
||||||
|
'oder '
|
||||||
|
'versehentlich '
|
||||||
|
'ausgesetzte '
|
||||||
|
'Ressource zu '
|
||||||
|
'verhindern.'}},
|
||||||
|
'wiki.admin.data-subject-requests': {'consequence_classes': {'erasure': 'Der Anbieter erstellt '
|
||||||
|
'nicht ausführbare '
|
||||||
|
'manuelle '
|
||||||
|
'Überprüfungsaktionen und '
|
||||||
|
'ändert automatisch keine '
|
||||||
|
'Wissensnachweise.',
|
||||||
|
'uninstall': 'Anhaltende Wiki-Zeilen '
|
||||||
|
'blockieren die '
|
||||||
|
'Deinstallation, bis '
|
||||||
|
'die Migration, '
|
||||||
|
'Aufbewahrung oder '
|
||||||
|
'explizite '
|
||||||
|
'Pensionierung '
|
||||||
|
'abgeschlossen ist.'}},
|
||||||
|
'wiki.integrations.references-search': {'consequence_classes': {'connector_absent': 'Externe '
|
||||||
|
'Referenzen '
|
||||||
|
'können '
|
||||||
|
'aufgezeichnet '
|
||||||
|
'werden, '
|
||||||
|
'Synchronisation '
|
||||||
|
'oder '
|
||||||
|
'Migration '
|
||||||
|
'können '
|
||||||
|
'jedoch nicht '
|
||||||
|
'ausgeführt '
|
||||||
|
'werden.',
|
||||||
|
'files_absent': 'Referenzen '
|
||||||
|
'bleiben nur '
|
||||||
|
'Metadaten und es '
|
||||||
|
'wird keine '
|
||||||
|
'binäre Operation '
|
||||||
|
'angeboten.',
|
||||||
|
'search_absent': 'Veröffentlichte '
|
||||||
|
'Seiten sind '
|
||||||
|
'durch globale '
|
||||||
|
'Suche nicht '
|
||||||
|
'auffindbar.'}},
|
||||||
|
'wiki.module-boundary': {'consequence_classes': {'ownership': 'Wiki-Shops regulierten Text und '
|
||||||
|
'Referenzen, niemals binäre Inhalte '
|
||||||
|
'oder externe '
|
||||||
|
'Transportinformationen.'}},
|
||||||
|
'wiki.workflow.author-publish': {'consequence_classes': {'draft_after_publish': 'Die zuletzt '
|
||||||
|
'veröffentlichte '
|
||||||
|
'Revision bleibt '
|
||||||
|
'leserlich '
|
||||||
|
'sichtbar, bis '
|
||||||
|
'der neue Entwurf '
|
||||||
|
'explizit '
|
||||||
|
'veröffentlicht '
|
||||||
|
'wird.',
|
||||||
|
'stale_revision': 'Das Schreiben gibt '
|
||||||
|
'einen Konflikt zurück '
|
||||||
|
'und bewahrt sowohl '
|
||||||
|
'die gespeicherte '
|
||||||
|
'Revision als auch den '
|
||||||
|
'Entwurf des '
|
||||||
|
'Anrufers.'}}}
|
||||||
@@ -1,5 +1,8 @@
|
|||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
|
from govoplan_core.core.modules import with_documentation_structured_translations
|
||||||
|
from govoplan_wiki.backend.german_structured_documentation import GERMAN_STRUCTURED_TRANSLATIONS
|
||||||
|
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
||||||
from sqlalchemy import func
|
from sqlalchemy import func
|
||||||
@@ -52,7 +55,7 @@ from govoplan_wiki.backend.service import (
|
|||||||
|
|
||||||
MODULE_ID = "wiki"
|
MODULE_ID = "wiki"
|
||||||
MODULE_NAME = "Wiki"
|
MODULE_NAME = "Wiki"
|
||||||
MODULE_VERSION = "0.1.20"
|
MODULE_VERSION = "0.1.22"
|
||||||
OPTIONAL_DEPENDENCIES = (
|
OPTIONAL_DEPENDENCIES = (
|
||||||
"files",
|
"files",
|
||||||
"dms",
|
"dms",
|
||||||
@@ -187,7 +190,9 @@ DOCUMENTATION = (
|
|||||||
id="wiki.module-boundary",
|
id="wiki.module-boundary",
|
||||||
title="Wiki module boundary",
|
title="Wiki module boundary",
|
||||||
summary="Governed collaborative knowledge spaces, hierarchical pages, immutable revisions, links, labels, comments, access, and publishing.",
|
summary="Governed collaborative knowledge spaces, hierarchical pages, immutable revisions, links, labels, comments, access, and publishing.",
|
||||||
body="Wiki owns native knowledge-space and page identity, hierarchy, drafts, immutable revisions, comments, labels, typed references, redirects, and publication state. Files or DMS owns binary content, Records owns formal record disposition, Docs owns product and configured-system guidance, and Connectors owns MediaWiki or BlueSpice transport.",
|
body="Documentation books sit immediately beside the visible heading or contextual label for Wiki, "
|
||||||
|
"not among operational action buttons. Field help remains beside its label. "
|
||||||
|
"Wiki owns native knowledge-space and page identity, hierarchy, drafts, immutable revisions, comments, labels, typed references, redirects, and publication state. Files or DMS owns binary content, Records owns formal record disposition, Docs owns product and configured-system guidance, and Connectors owns MediaWiki or BlueSpice transport.",
|
||||||
layer="available",
|
layer="available",
|
||||||
documentation_types=("admin", "user"),
|
documentation_types=("admin", "user"),
|
||||||
audience=("user", "operator", "module_admin", "product_owner"),
|
audience=("user", "operator", "module_admin", "product_owner"),
|
||||||
@@ -196,7 +201,10 @@ DOCUMENTATION = (
|
|||||||
"de": {
|
"de": {
|
||||||
"title": "Modulgrenze von Wiki",
|
"title": "Modulgrenze von Wiki",
|
||||||
"summary": "Gesteuerte Wissensbereiche mit hierarchischen Seiten, unveränderlichen Revisionen, Verweisen, Schlagwörtern, Kommentaren, Zugriff und Veröffentlichung.",
|
"summary": "Gesteuerte Wissensbereiche mit hierarchischen Seiten, unveränderlichen Revisionen, Verweisen, Schlagwörtern, Kommentaren, Zugriff und Veröffentlichung.",
|
||||||
"body": "Wiki verwaltet die Identität nativer Wissensbereiche und Seiten, Hierarchie, Entwürfe, unveränderliche Revisionen, Kommentare, Schlagwörter, typisierte Verweise, Weiterleitungen und Veröffentlichungsstatus. Files beziehungsweise DMS verwaltet Binärinhalte, Records die formale Aufbewahrung, Docs die Produkt- und Konfigurationsdokumentation und Connectors den Transport zu MediaWiki oder BlueSpice.",
|
"body": "Dokumentationsbücher stehen unmittelbar neben der sichtbaren Überschrift oder "
|
||||||
|
"Kontextbezeichnung für Wiki, nicht zwischen ausführbaren Aktionsschaltflächen. Feldhilfe "
|
||||||
|
"bleibt neben der Feldbezeichnung. "
|
||||||
|
"Wiki verwaltet die Identität nativer Wissensbereiche und Seiten, Hierarchie, Entwürfe, unveränderliche Revisionen, Kommentare, Schlagwörter, typisierte Verweise, Weiterleitungen und Veröffentlichungsstatus. Files beziehungsweise DMS verwaltet Binärinhalte, Records die formale Aufbewahrung, Docs die Produkt- und Konfigurationsdokumentation und Connectors den Transport zu MediaWiki oder BlueSpice.",
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
links=(
|
links=(
|
||||||
@@ -574,5 +582,10 @@ manifest = ModuleManifest(
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
manifest = with_documentation_structured_translations(
|
||||||
|
manifest, locale="de", translations=GERMAN_STRUCTURED_TRANSLATIONS
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
def get_manifest() -> ModuleManifest:
|
def get_manifest() -> ModuleManifest:
|
||||||
return manifest
|
return manifest
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ class WikiManifestTests(unittest.TestCase):
|
|||||||
def test_manifest_registers_complete_vertical_slice(self) -> None:
|
def test_manifest_registers_complete_vertical_slice(self) -> None:
|
||||||
manifest = get_manifest()
|
manifest = get_manifest()
|
||||||
self.assertEqual("wiki", manifest.id)
|
self.assertEqual("wiki", manifest.id)
|
||||||
self.assertEqual("0.1.20", manifest.version)
|
self.assertEqual("0.1.22", manifest.version)
|
||||||
self.assertEqual(("access",), manifest.dependencies)
|
self.assertEqual(("access",), manifest.dependencies)
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
{READ_SCOPE, WRITE_SCOPE, COMMENT_SCOPE, PUBLISH_SCOPE, ADMIN_SCOPE},
|
{READ_SCOPE, WRITE_SCOPE, COMMENT_SCOPE, PUBLISH_SCOPE, ADMIN_SCOPE},
|
||||||
|
|||||||
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@govoplan/wiki-webui",
|
"name": "@govoplan/wiki-webui",
|
||||||
"version": "0.1.20",
|
"version": "0.1.22",
|
||||||
"private": true,
|
"private": true,
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"main": "src/index.ts",
|
"main": "src/index.ts",
|
||||||
|
|||||||
@@ -146,7 +146,7 @@ export default function WikiPage({ settings, auth }: PlatformRouteContext) {
|
|||||||
<FilterBar as="form" surface="control" wrap="never" width="default" className="wiki-search" onSubmit={submitSearch}><Search size={17} aria-hidden="true" /><input value={query} onChange={(event) => setQuery(event.target.value)} aria-label="Search Wiki pages" placeholder="Search pages in this space" /><Button type="submit" variant="primary">Search</Button></FilterBar>
|
<FilterBar as="form" surface="control" wrap="never" width="default" className="wiki-search" onSubmit={submitSearch}><Search size={17} aria-hidden="true" /><input value={query} onChange={(event) => setQuery(event.target.value)} aria-label="Search Wiki pages" placeholder="Search pages in this space" /><Button type="submit" variant="primary">Search</Button></FilterBar>
|
||||||
<label className="wiki-space-picker"><span>Space</span><select value={selectedSpaceId} onChange={(event) => setSelectedSpaceId(event.target.value)}>{spaces.map((space) => <option key={space.space_id} value={space.space_id}>{space.title}</option>)}</select></label>
|
<label className="wiki-space-picker"><span>Space</span><select value={selectedSpaceId} onChange={(event) => setSelectedSpaceId(event.target.value)}>{spaces.map((space) => <option key={space.space_id} value={space.space_id}>{space.title}</option>)}</select></label>
|
||||||
<span className="wiki-count">{pages.length} pages</span>
|
<span className="wiki-count">{pages.length} pages</span>
|
||||||
</>} helpAction={<DocumentationHelpLink reference={{ topicId: "wiki.workflow.author-publish", documentationType: "user" }} label="Open Wiki documentation" />} createAction={<div className="wiki-create-actions">
|
</>} title="Wiki" titleLevel={1} titleHelp={<DocumentationHelpLink reference={{ topicId: "wiki.workflow.author-publish", documentationType: "user" }} label="Open Wiki documentation" />} createAction={<div className="wiki-create-actions">
|
||||||
{canAdmin && <Button type="button" onClick={() => { setDialogError(""); setSpaceDialog("new"); }} interfaceId="wiki.action.create-space"><Plus size={16} /> New space</Button>}
|
{canAdmin && <Button type="button" onClick={() => { setDialogError(""); setSpaceDialog("new"); }} interfaceId="wiki.action.create-space"><Plus size={16} /> New space</Button>}
|
||||||
{canWrite && selectedSpace && <Button type="button" variant="primary" onClick={() => { setDialogError(""); setPageDialog("new"); }} interfaceId="wiki.action.create-page"><FilePlus2 size={16} /> New page</Button>}
|
{canWrite && selectedSpace && <Button type="button" variant="primary" onClick={() => { setDialogError(""); setPageDialog("new"); }} interfaceId="wiki.action.create-page"><FilePlus2 size={16} /> New page</Button>}
|
||||||
</div>} />
|
</div>} />
|
||||||
@@ -181,12 +181,12 @@ export default function WikiPage({ settings, auth }: PlatformRouteContext) {
|
|||||||
function WikiDetail({ record, revisions, comments, canWrite, canPublish, canComment, saving, onEdit, onPublish, onAddLink, onRemoveLink, onHistory, onComment, onArchive }: { record: WikiPageRecord; revisions: WikiRevision[]; comments: WikiComment[]; canWrite: boolean; canPublish: boolean; canComment: boolean; saving: boolean; onEdit: () => void; onPublish: () => void; onAddLink: () => void; onRemoveLink: (id: string) => Promise<void>; onHistory: () => void; onComment: (body: string) => Promise<void>; onArchive: () => void }) {
|
function WikiDetail({ record, revisions, comments, canWrite, canPublish, canComment, saving, onEdit, onPublish, onAddLink, onRemoveLink, onHistory, onComment, onArchive }: { record: WikiPageRecord; revisions: WikiRevision[]; comments: WikiComment[]; canWrite: boolean; canPublish: boolean; canComment: boolean; saving: boolean; onEdit: () => void; onPublish: () => void; onAddLink: () => void; onRemoveLink: (id: string) => Promise<void>; onHistory: () => void; onComment: (body: string) => Promise<void>; onArchive: () => void }) {
|
||||||
const [comment, setComment] = useState("");
|
const [comment, setComment] = useState("");
|
||||||
return <article className="wiki-detail" data-interface-id="wiki.section.page">
|
return <article className="wiki-detail" data-interface-id="wiki.section.page">
|
||||||
<header className="wiki-detail-header"><div><span className="wiki-eyebrow">{record.path} · revision {record.revision}</span><h1>{record.title}</h1><p>{record.summary}</p></div><div className="wiki-badges"><StatusBadge status={stateTone(record.state)} label={humanize(record.state)} /><StatusBadge status={record.effective_visibility === "restricted" ? "attention" : "neutral"} label={humanize(record.effective_visibility)} /></div></header>
|
<header className="wiki-detail-header"><div><span className="wiki-eyebrow">{record.path} · revision {record.revision}</span><h2>{record.title}</h2><p>{record.summary}</p></div><div className="wiki-badges"><StatusBadge status={stateTone(record.state)} label={humanize(record.state)} /><StatusBadge status={record.effective_visibility === "restricted" ? "attention" : "neutral"} label={humanize(record.effective_visibility)} /></div></header>
|
||||||
<div className="wiki-detail-actions" aria-label="Wiki page actions">
|
<div className="wiki-detail-actions" aria-label="Wiki page actions">
|
||||||
{canWrite && record.state !== "archived" && <Button type="button" onClick={onEdit} interfaceId="wiki.action.edit"><Pencil size={16} /> Edit</Button>}
|
{canWrite && record.state !== "archived" && <Button type="button" onClick={onEdit} interfaceId="wiki.action.edit"><Pencil size={16} /> Edit</Button>}
|
||||||
{canWrite && record.state !== "archived" && <Button type="button" onClick={onAddLink}><Link2 size={16} /> Add reference</Button>}
|
{canWrite && record.state !== "archived" && <Button type="button" onClick={onAddLink}><Link2 size={16} /> Add reference</Button>}
|
||||||
{(canWrite || canPublish) && <Button type="button" onClick={onHistory} interfaceId="wiki.section.revisions"><History size={16} /> Revisions ({revisions.length})</Button>}
|
{(canWrite || canPublish) && <Button type="button" onClick={onHistory} interfaceId="wiki.section.revisions"><History size={16} /> Revisions ({revisions.length})</Button>}
|
||||||
{canPublish && record.state === "draft" && <Button type="button" variant="primary" disabled={saving} onClick={onPublish} interfaceId="wiki.action.publish"><Upload size={16} /> Publish</Button>}
|
{canPublish && record.state === "draft" && <Button type="button" variant="primary" helpContextId="wiki.editor" helpModuleId="wiki" disabled={saving} onClick={onPublish} interfaceId="wiki.action.publish"><Upload size={16} /> Publish</Button>}
|
||||||
</div>
|
</div>
|
||||||
{record.published_revision && record.state === "draft" && <div className="wiki-publication-note" role="status">Readers and Search still receive published revision {record.published_revision} until this draft is published.</div>}
|
{record.published_revision && record.state === "draft" && <div className="wiki-publication-note" role="status">Readers and Search still receive published revision {record.published_revision} until this draft is published.</div>}
|
||||||
<div className="wiki-body">{record.body || <span className="wiki-muted">This page has no body text yet.</span>}</div>
|
<div className="wiki-body">{record.body || <span className="wiki-muted">This page has no body text yet.</span>}</div>
|
||||||
|
|||||||
Executable
+12
@@ -0,0 +1,12 @@
|
|||||||
|
import type { PlatformTranslations } from "@govoplan/core-webui";
|
||||||
|
|
||||||
|
/** Module-owned translations for contextual headings. */
|
||||||
|
export const generatedTranslations: PlatformTranslations = {
|
||||||
|
en: {
|
||||||
|
"Wiki": "Wiki",
|
||||||
|
},
|
||||||
|
de: {
|
||||||
|
"Wiki": "Wiki",
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
@@ -1,11 +1,13 @@
|
|||||||
import { createElement, lazy } from "react";
|
import { createElement, lazy } from "react";
|
||||||
import type { PlatformWebModule } from "@govoplan/core-webui";
|
import type { PlatformWebModule } from "@govoplan/core-webui";
|
||||||
|
import { generatedTranslations } from "./i18n/generatedTranslations";
|
||||||
import "./styles/wiki.css";
|
import "./styles/wiki.css";
|
||||||
|
|
||||||
|
|
||||||
const WikiPage = lazy(() => import("./features/wiki/WikiPage"));
|
const WikiPage = lazy(() => import("./features/wiki/WikiPage"));
|
||||||
|
|
||||||
export const wikiModule: PlatformWebModule = {
|
export const wikiModule: PlatformWebModule = {
|
||||||
|
translations: generatedTranslations,
|
||||||
id: "wiki",
|
id: "wiki",
|
||||||
label: "Wiki",
|
label: "Wiki",
|
||||||
version: "0.1.20",
|
version: "0.1.20",
|
||||||
|
|||||||
@@ -89,7 +89,7 @@
|
|||||||
|
|
||||||
.wiki-space-header h2,
|
.wiki-space-header h2,
|
||||||
.wiki-space-header p,
|
.wiki-space-header p,
|
||||||
.wiki-detail-header h1,
|
.wiki-detail-header h2,
|
||||||
.wiki-detail-header p,
|
.wiki-detail-header p,
|
||||||
.wiki-section h2,
|
.wiki-section h2,
|
||||||
.wiki-section p,
|
.wiki-section p,
|
||||||
@@ -125,7 +125,7 @@
|
|||||||
border-block-end: 1px solid var(--border-subtle);
|
border-block-end: 1px solid var(--border-subtle);
|
||||||
}
|
}
|
||||||
|
|
||||||
.wiki-detail-header h1 {
|
.wiki-detail-header h2 {
|
||||||
margin-block-start: var(--space-1);
|
margin-block-start: var(--space-1);
|
||||||
font-size: var(--font-size-2xl);
|
font-size: var(--font-size-2xl);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user