Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ecfcdd1fea | ||
|
|
312a8e281e |
+1
-1
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@govoplan/records",
|
||||
"version": "0.1.20",
|
||||
"version": "0.1.22",
|
||||
"private": true,
|
||||
"description": "GovOPlaN eAkte and institutional records module.",
|
||||
"type": "module",
|
||||
|
||||
+1
-1
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
||||
|
||||
[project]
|
||||
name = "govoplan-records"
|
||||
version = "0.1.20"
|
||||
version = "0.1.22"
|
||||
description = "GovOPlaN eAkte and institutional records module."
|
||||
readme = "README.md"
|
||||
requires-python = ">=3.12"
|
||||
|
||||
@@ -16,6 +16,7 @@ from govoplan_core.core.module_guards import (
|
||||
)
|
||||
from govoplan_core.core.modules import (
|
||||
CapabilityDocumentation,
|
||||
DocumentationCondition,
|
||||
DocumentationLink,
|
||||
DocumentationTopic,
|
||||
FrontendModule,
|
||||
@@ -52,7 +53,7 @@ from govoplan_records.backend.archive import (
|
||||
|
||||
MODULE_ID = "records"
|
||||
MODULE_NAME = "Records"
|
||||
MODULE_VERSION = "0.1.20"
|
||||
MODULE_VERSION = "0.1.22"
|
||||
READ_SCOPE = "records:workspace:read"
|
||||
WRITE_SCOPE = "records:workspace:write"
|
||||
ADMIN_SCOPE = "records:workspace:admin"
|
||||
@@ -222,11 +223,31 @@ DOCUMENTATION = (
|
||||
),
|
||||
),
|
||||
metadata={
|
||||
"kind": "reference",
|
||||
"help_contexts": [
|
||||
"records.data-subject-requests",
|
||||
"records.lifecycle",
|
||||
],
|
||||
},
|
||||
translations={
|
||||
"de": {
|
||||
"title": "Datenschutzanfragen zur eAkte",
|
||||
"summary": (
|
||||
"Minimierte Aktenmetadaten ausgeben und dabei Aufbewahrungs-, Sperr-, Aussonderungs- und Archivnachweise bewahren."
|
||||
),
|
||||
"body": (
|
||||
"Records gleicht innerhalb eines Mandanten exakte Verweise auf Akte, Revision, Eintrag, Band, Chronologie, "
|
||||
"Sperre, Aussonderung, Übergabepaket und anbietergeführte Quellen ab. Konto-, Identitäts- und "
|
||||
"Mitgliedschaftsselektoren zeigen Verantwortungszuordnungen von Beschäftigten, bedeuten aber niemals, dass die "
|
||||
"beschäftigte Person Gegenstand einer Akte ist. Eine Auskunft zur aktenbetroffenen Person erfordert deshalb eine "
|
||||
"führende Akten- oder Quellverknüpfung. Die Ausgabe enthält begrenzte Metadaten zu Akte, Veraktung, Chronologie, "
|
||||
"Sperre, Aussonderung und Übergabe. Quellinhalt, Schnappschüsse, Suchtext, undurchsichtige Kontexte und Nutzdaten, "
|
||||
"Prüfsummen, Wiederholungsschlüssel, Start-URLs, Archivmanifeste und -belege, Genehmigungskennungen und fremde "
|
||||
"Akten bleiben ausgeschlossen. Unveränderliche Nachweise werden aufbewahrt. Der aktuelle Aktenfakt erhält eine "
|
||||
"nicht ausführbare manuelle Prüfung und kann nur über den gesteuerten eAkte-Lebenszyklus verändert werden."
|
||||
),
|
||||
}
|
||||
},
|
||||
),
|
||||
DocumentationTopic(
|
||||
id="records.workspace",
|
||||
@@ -243,6 +264,7 @@ DOCUMENTATION = (
|
||||
layer="configured",
|
||||
documentation_types=("admin", "user"),
|
||||
audience=("user", "records_manager", "operator", "module_admin", "auditor"),
|
||||
conditions=(DocumentationCondition(required_scopes=(READ_SCOPE,)),),
|
||||
order=100,
|
||||
related_modules=OPTIONAL_DEPENDENCIES,
|
||||
links=(
|
||||
@@ -267,6 +289,7 @@ DOCUMENTATION = (
|
||||
}
|
||||
},
|
||||
metadata={
|
||||
"kind": "workflow",
|
||||
"help_contexts": [
|
||||
"records.workspace",
|
||||
"records.file-plan",
|
||||
@@ -329,6 +352,7 @@ DOCUMENTATION = (
|
||||
}
|
||||
},
|
||||
metadata={
|
||||
"kind": "reference",
|
||||
"help_contexts": [
|
||||
"records.action.file",
|
||||
"records.field.source-module",
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from govoplan_records.backend.manifest import manifest
|
||||
|
||||
|
||||
def test_records_german_workflow_and_reference_are_complete() -> None:
|
||||
topics = {topic.id: topic for topic in manifest.documentation}
|
||||
assert len(topics) == 5
|
||||
for topic in topics.values():
|
||||
assert all(topic.translations["de"].get(key) for key in ("title", "summary", "body"))
|
||||
workflow = topics["records.workspace"]
|
||||
assert workflow.metadata["kind"] == "workflow"
|
||||
assert workflow.conditions
|
||||
assert topics["records.filing"].metadata["kind"] == "reference"
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@govoplan/records-webui",
|
||||
"version": "0.1.20",
|
||||
"version": "0.1.22",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"main": "src/index.ts",
|
||||
|
||||
@@ -162,7 +162,7 @@ export function RecordCatalogDialog({
|
||||
<FormField label={kind === "file-plan" ? "Node ID" : "Class ID"}><input value={identifier} onChange={(event) => setIdentifier(event.target.value)} disabled={Boolean(selectedId)} required /></FormField>
|
||||
<FormField label={kind === "file-plan" ? "Code" : "Key"}><input value={code} onChange={(event) => setCode(event.target.value)} required /></FormField>
|
||||
<FormField label="Label"><input value={label} onChange={(event) => setLabel(event.target.value)} required /></FormField>
|
||||
{kind === "file-plan" ? <FormField label="Parent node"><select value={parentId} onChange={(event) => setParentId(event.target.value)}><option value="">Top level</option>{catalog.file_plan.filter((item) => item.node_id !== identifier).map((item) => <option key={item.node_id} value={item.node_id}>{item.code} · {item.label}</option>)}</select></FormField> : <><FormField label="File-plan node"><select value={filePlanNodeId} onChange={(event) => setFilePlanNodeId(event.target.value)} required>{catalog.file_plan.map((item) => <option key={item.node_id} value={item.node_id}>{item.code} · {item.label}</option>)}</select></FormField><FormField label="Retention period (days)"><input type="number" min="0" value={retentionDays} onChange={(event) => setRetentionDays(event.target.value)} /></FormField><FormField label="Retention trigger"><select value={closureTrigger} onChange={(event) => setClosureTrigger(event.target.value)}><option value="record_closed">Record closure</option><option value="calendar_month_end">End of closure month</option><option value="calendar_year_end">End of closure year</option><option value="explicit">Explicit date at closure</option></select></FormField></>}
|
||||
{kind === "file-plan" ? <FormField label="Parent node"><select value={parentId} onChange={(event) => setParentId(event.target.value)}><option value="">Top level</option>{catalog.file_plan.filter((item) => item.node_id !== identifier).map((item) => <option key={item.node_id} value={item.node_id}>{item.code} · {item.label}</option>)}</select></FormField> : <><FormField label="File-plan node"><select value={filePlanNodeId} onChange={(event) => setFilePlanNodeId(event.target.value)} required>{catalog.file_plan.map((item) => <option key={item.node_id} value={item.node_id}>{item.code} · {item.label}</option>)}</select></FormField><FormField label="Retention period (days)" helpContextId="records.field.retention-trigger" helpModuleId="records"><input type="number" min="0" value={retentionDays} onChange={(event) => setRetentionDays(event.target.value)} /></FormField><FormField label="Retention trigger" helpContextId="records.field.retention-trigger" helpModuleId="records"><select value={closureTrigger} onChange={(event) => setClosureTrigger(event.target.value)}><option value="record_closed">Record closure</option><option value="calendar_month_end">End of closure month</option><option value="calendar_year_end">End of closure year</option><option value="explicit">Explicit date at closure</option></select></FormField></>}
|
||||
<FormField label="Description"><textarea rows={4} value={description} onChange={(event) => setDescription(event.target.value)} /></FormField>
|
||||
</DialogForm>
|
||||
</Dialog>
|
||||
|
||||
@@ -258,10 +258,10 @@ export function RecordLifecyclePanel({
|
||||
{availableActions.canReopen && <Button type="button" variant="ghost" onClick={() => openAction("reopen")}><RotateCcw size={16} aria-hidden="true" /> Reopen</Button>}
|
||||
{availableActions.canAppraise && <Button type="button" variant="ghost" onClick={() => openAction("appraise")}><CheckCheck size={16} aria-hidden="true" /> Appraise</Button>}
|
||||
<Button type="button" variant="ghost" onClick={() => openAction("hold")} disabledReason={!canWrite ? "Your account may not apply a hold." : undefined}><LockKeyhole size={16} aria-hidden="true" /> Apply hold</Button>
|
||||
{availableActions.canPropose && <Button type="button" variant="primary" onClick={() => openAction("disposition")} disabledReason={activeHolds.length ? "Release all active holds first." : undefined}><ArchiveRestore size={16} aria-hidden="true" /> Propose disposition</Button>}
|
||||
{availableActions.canFinalize && <Button type="button" variant="primary" onClick={() => openAction("finalize")} disabledReason={activeHolds.length ? "Release all active holds first." : undefined}><CheckCheck size={16} aria-hidden="true" /> Finalize approved disposition</Button>}
|
||||
{currentDisposition && ["review_pending", "review_unavailable"].includes(currentDisposition.status) && <Button type="button" variant="ghost" onClick={() => openAction("withdraw")}><Ban size={16} aria-hidden="true" /> Withdraw proposal</Button>}
|
||||
{availableActions.canPrepare && <Button type="button" variant="primary" onClick={() => openAction("prepare-transfer")} disabledReason={healthyProviders.length === 0 ? "No healthy archive profile is available." : activeHolds.length ? "Release all active holds first." : undefined}><Box size={16} aria-hidden="true" /> Prepare transfer</Button>}
|
||||
{availableActions.canPropose && <Button type="button" variant="primary" helpContextId="records.lifecycle.disposition" helpModuleId="records" onClick={() => openAction("disposition")} disabledReason={activeHolds.length ? "Release all active holds first." : undefined}><ArchiveRestore size={16} aria-hidden="true" /> Propose disposition</Button>}
|
||||
{availableActions.canFinalize && <Button type="button" variant="primary" helpContextId="records.lifecycle.finalize" helpModuleId="records" onClick={() => openAction("finalize")} disabledReason={activeHolds.length ? "Release all active holds first." : undefined}><CheckCheck size={16} aria-hidden="true" /> Finalize approved disposition</Button>}
|
||||
{currentDisposition && ["review_pending", "review_unavailable"].includes(currentDisposition.status) && <Button type="button" variant="ghost" helpContextId="records.lifecycle.disposition" helpModuleId="records" onClick={() => openAction("withdraw")}><Ban size={16} aria-hidden="true" /> Withdraw proposal</Button>}
|
||||
{availableActions.canPrepare && <Button type="button" variant="primary" helpContextId="records.lifecycle.prepare-transfer" helpModuleId="records" onClick={() => openAction("prepare-transfer")} disabledReason={healthyProviders.length === 0 ? "No healthy archive profile is available." : activeHolds.length ? "Release all active holds first." : undefined}><Box size={16} aria-hidden="true" /> Prepare transfer</Button>}
|
||||
{availableActions.canDispatch && <Button type="button" variant="primary" onClick={() => openAction("dispatch-transfer")} disabledReason={!currentPackage?.simulated ? "Real archive dispatch needs a target-specific recovery profile." : activeHolds.length ? "Release all active holds first." : undefined}><Play size={16} aria-hidden="true" /> Run simulation</Button>}
|
||||
{canAdmin && <Button type="button" variant="ghost" onClick={openRecovery}><ArchiveRestore size={16} aria-hidden="true" /> Recovery evidence</Button>}
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user