Compare commits

..
4 Commits
Author SHA1 Message Date
zemion 11b9b7c4c6 fix(webui): bind file credentials and deletion to help
Module Package Release / publish-packages (push) Successful in 13s
2026-08-24 11:36:40 +02:00
zemion ab08c73777 docs: complete German structured documentation
Module Package Release / publish-packages (push) Successful in 11s
2026-08-24 01:15:33 +02:00
zemion 74c26090d7 docs(files): complete German reference coverage
Module Package Release / publish-packages (push) Successful in 11s
2026-08-23 21:09:37 +02:00
zemion 62047e7a20 docs(files): document pinned SMB validation 2026-08-21 23:20:15 +02:00
12 changed files with 659 additions and 27 deletions
+14 -6
View File
@@ -139,12 +139,20 @@ cd /mnt/DATA/git/govoplan-files/dev/connectors
```
The script reads `.env` from this directory when present and seeds tiny WebDAV,
Nextcloud, SMB, and MinIO fixtures. WebDAV and Nextcloud are browsed and imported
through the pinned connector transport. SMB and S3 product access deliberately
fails closed until their SDK transports support peer pinning, so their fixtures
are retained for transport development and reported as expected optional skips.
The `--require-smb` and `--require-s3` switches are useful only while developing
that transport support and currently make the smoke check fail by design.
Nextcloud, SMB, and MinIO fixtures. WebDAV and Nextcloud use the pinned HTTP
transport. SMB uses the Files-owned `smbprotocol` connection cache so initial
connections, reconnects, aliases, and DFS referral targets are pinned. S3 uses
pinned botocore pools for retries, redirects, discovery, and aliases. Every
socket destination is revalidated when it opens, including when private-network
access is enabled for these local fixtures.
SMB and S3 are optional by default: a missing provider dependency or unavailable
target is reported as `SKIP`. Use `--require-smb` and `--require-s3` to turn such
provider failures into a non-zero smoke result during deployment validation. The
bundled Samba service is a deterministic single-share target, not a DFS
topology. Referral and reconnect behavior is covered by the transport contract
tests; deployments using DFS must additionally run the required SMB smoke check
against their actual referral topology and record the resolved peers.
SMB smoke checks need the optional Python dependency in the environment running
the script:
+10
View File
@@ -1034,6 +1034,16 @@ attempt. Botocore retries, redirects, endpoint discovery, and aliases, plus SMB
reconnects and DFS referrals, must pass through the pinned factories. A changed
or unsupported SDK seam must fail before a usable client/session is returned.
SMB deployments use `smbprotocol>=1.13`; signing is required by default and SMB
encryption can be required per connector profile. Private targets additionally
require the governed private-network setting, but that setting never bypasses
per-connection address validation. The bundled development Samba target checks
live initial browse/import behavior with `smoke.py --require-smb`. It is a
single-share fixture rather than a DFS topology: reconnect and referral handling
is enforced by the transport contract suite, while operators using DFS must run
the same required smoke check against their institutional referral topology and
record the initial and referred peers as deployment evidence.
### Imported evidence and sync
Given a permitted WebDAV file is imported, its managed response and audit event
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@govoplan/files-webui",
"version": "0.1.20",
"version": "0.1.23",
"private": true,
"type": "module",
"main": "webui/src/index.ts",
+1 -1
View File
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
[project]
name = "govoplan-files"
version = "0.1.20"
version = "0.1.23"
description = "GovOPlaN files module with backend and WebUI integration."
readme = "README.md"
requires-python = ">=3.12"
@@ -0,0 +1,132 @@
from __future__ import annotations
from dataclasses import replace
from typing import Iterable
from govoplan_core.core.modules import DocumentationTopic
_TRANSLATIONS = {
"files.tabular-content": {
"title": "Verwaltete CSV- und XLSX-Versionen als gesteuerte Datenquellen verwenden",
"summary": "Exakte autorisierte Dateiversionen für Connectors bereitstellen, ohne Files-Kontrollen zu umgehen.",
"body": (
"Files listet nur CSV- und XLSX-Dateien auf, die für die aktuelle Person im Mandanten sichtbar sind. Das Öffnen erfordert zusätzlich die Download-Berechtigung und eine exakte unveränderliche Versionsreferenz. Größenobergrenzen werden vor dem Speicherzugriff geprüft; Prüfsumme, Quarantäne, Verschlüsselungshülle, Löschung, Eigentum und Freigaben bleiben in Files maßgeblich. Connectors erhält Metadaten und verifizierte Bytes über die Core-Fähigkeit und importiert weder Files-Modelle noch Speicherschlüssel oder Verschlüsselungsinterna. Eine neuere aktuelle Version ersetzt eine gebundene Quellversion nie still; Connectors meldet die Änderung zur ausdrücklichen Prüfung."
),
},
"files.records.exact-version-source": {
"title": "Eine exakte Dateiversion in einer eAkte ablegen",
"summary": "Records nach aktueller Zugriffs- und Integritätsprüfung eine unveränderliche Files-Versionsreferenz übergeben.",
"body": (
"Wenn Records aktiv ist, stellt Files exakte Identitäten verwalteter FileVersion-Objekte über den anbieterneutralen Aktenquellenvertrag bereit. Die Ablage prüft aktiven Mandanten, aktuelle Files-Berechtigung, Eigentums- oder Freigabezugriff, unveränderliche Versionsidentität und Integrität des verwalteten Blobs. Records erhält Dateiname, Pfad, Version, Digest, Medientyp, Größe, Schutzstatus und Aufruflink; Files bleibt Eigentümer der Bytes."
),
},
"files.search.managed-content": {
"title": "Verwaltete Dateien und Ordner durchsuchen",
"summary": "Dateinamen, logische Pfade und Beschreibungen für die berechtigungsbewusste Plattformsuche bereitstellen.",
"body": (
"Wenn Search installiert ist, trägt Files verwaltete Dateien und Ordner zu dessen abgeleitetem Index bei. Jedes Ergebnis ist auf den Mandanten begrenzt und prüft vor der Ausgabe aktuelles Eigentum, Gruppenmitgliedschaft, direkte Freigaben, Ablauf, Widerruf, Löschung und Files-Berechtigungen erneut. Bestätigte Datei- und Freigabeänderungen werden über die Plattform-Event-Outbox übertragen; eine Administration kann den abgeleiteten Index neu aufbauen, ohne führende Files-Daten zu verändern."
),
},
"files.forms-runtime.managed-evidence": {
"title": "Formularanhänge als verwaltete Nachweise erfassen",
"summary": "Kurzlebige Upload-Freigaben ausstellen und verwaltete Dateiversionen an genau eine Formulareinreichung binden.",
"body": (
"Fordert Forms Runtime einen Dokumentnachweis an, stellt Files einer aktiven, mandantengleichen verwahrenden Person eine zweckgebundene Freigabe aus. Das Bearer-Token wird einmal angezeigt, nur als SHA-256-Digest gespeichert, läuft spätestens nach 15 Minuten ab und kann genau eine verwaltete Dateiversion erzeugen. Bei der endgültigen Einreichung werden exaktes Formular, Freigabe, Asset, Version, Prüfsumme, Löschstatus und Files-Integritätsgrenze erneut geprüft. Öffentliche Erfassung erhält dadurch keine allgemeinen Files-Berechtigungen; ein Dokument für eine Einreichung kann nicht still für eine andere wiederverwendet werden."
),
},
"files.workflow.organize-managed-files": {
"title": "Verwaltete Dateien und Ordner organisieren",
"summary": "Ordner anlegen und zugängliche Inhalte mit ausdrücklicher Konfliktbehandlung umbenennen, verschieben oder kopieren.",
"body": (
"Die Organisation bleibt in gesteuerten persönlichen oder Gruppenbereichen. Verschieben erhält die Asset-Identität; Kopieren erzeugt neue Assets und Versionen, die unveränderliche Blob-Bytes wiederverwenden. Jeder Zielkonflikt muss ausdrücklich abgelehnt, durch Umbenennen gelöst, überschrieben oder übersprungen werden."
),
},
"files.workflow.find-and-download-files": {
"title": "Verwaltete Dateien finden und herunterladen",
"summary": "Zugängliche Inhalte suchen und eine aktuelle Dateiversion oder ein ZIP einer Auswahl herunterladen.",
"body": (
"Files kann nach logischem Pfad oder Namensmuster sortiert und durchsucht werden. Ein Download verwendet immer die zugängliche aktuelle Version; aus einer Mehrfachauswahl kann ein temporäres ZIP-Archiv erzeugt werden. Einen eigenen Dienst zur Inhaltsvorschau gibt es derzeit nicht."
),
},
"files.workflow.share-managed-files": {
"title": "Zugriff auf verwaltete Dateien steuern",
"summary": "Direkte Lese-, Schreib- und Verwaltungsfreigaben auflisten, vergeben, ändern, befristen oder widerrufen, ohne das Eigentum zu ändern.",
"body": (
"Dateieigentümer und Files-Administrationen verwalten direkte Freigaben für Personen, Gruppen, den Mandanten und Campaign. Abgelaufene oder widerrufene Freigaben berechtigen sofort nicht mehr; unabhängige aktive Freigaben bleiben wirksam. Der Freigabedialog zeigt aktive und historische Einträge, und ein Widerruf ist idempotent. Die Zugriffserklärung prüft standardmäßig die angemeldete Person. Erlaubt Policy ausgewählte Fremdprüfungen, kann derselbe zentrale Dialog eine andere aktive Person im Mandanten bewerten; diese Diagnose wird im Audit protokolliert und gewährt keinen Zugriff."
),
},
"files.workflow.delete-managed-files": {
"title": "Verwaltete Dateien und Ordner löschen",
"summary": "Zugängliche Dateien oder einen Ordnerbaum nach aktueller Richtlinie weich löschen.",
"body": (
"Löschen blendet ausgewählte verwaltete Assets aus, statt gespeicherte Nachweise physisch zu vernichten. Ordner werden standardmäßig einschließlich ihrer Unterordner und Dateien rekursiv gelöscht; eine nicht rekursive Anforderung scheitert bei einem nicht leeren Ordner. Eine autorisierte Wiederherstellung aktiviert dasselbe Asset mit Versionen, Provenienz, Ordnerbaum oder Connector-Bereich erneut, sofern Pfad oder Bezeichnung frei ist. Die unwiderrufliche Vernichtung ist ein eigener Administrationsablauf mit Aufbewahrungs- und Legal-Hold-Prüfungen."
),
},
"files.workflow.restore-retain-and-purge": {
"title": "Verwaltete Dateien wiederherstellen, aufbewahren und vernichten",
"summary": "Weich gelöschte Ressourcen wiederherstellen und irreversible Löschung mit Aufbewahrung, Legal Hold, Vorschau, Freigabe und Recovery-Nachweis steuern.",
"body": (
"Wiederherstellen erhält ursprüngliche Asset-Identität, Versionen, Blob-Referenzen und Connector-Provenienz. Eine Aufbewahrungsadministration kann mit Begründung und Revisionsprüfung ein Aufbewahrungsdatum oder Legal Hold setzen. Eine physische Vernichtung benötigt eigene Berechtigung, aktuellen unveränderlichen Vorschau-Hash, Idempotenzschlüssel, die wörtliche Bestätigung PURGE und eine Freigabereferenz. Aktive Aufbewahrung, Legal Hold, Freigaben sowie Campaign- und Form-Nachweise blockieren sie. Zuerst werden berechtigte Datenbankeinträge entfernt und Blobs freigegeben; eine getrennte begrenzte Garbage Collection prüft unter derselben verteilten Blob-Sperre wie Uploads alle FileVersion-Referenzen erneut, bevor Bytes und Metadaten gelöscht werden. Jede irreversible Aktion erscheint im Core-Recovery-Ledger und Audit-Nachweis."
),
},
"files.privacy.data-subject-requests": {
"title": "Files-Daten in einer Datenschutzanfrage prüfen",
"summary": "Sichere Files-Metadaten ermitteln und Entscheidungen über Aufbewahrung, Nachweise und Byte-Löschung ausdrücklich behandeln.",
"body": (
"Der Files-DSAR-Anbieter sucht nur im wirksamen Mandanten und verlangt eine direkte Mitgliedschaft oder namensraumbezogene Files-Benutzerreferenz. Er exportiert begrenzte Datei-, Versions-, Ordner-, Freigabe-, Nachweis-, Connector-Konfigurations- und Integritätsmetadaten ohne Dateibytes, Speicherorte, Tokens, Passwörter, Geheimnisreferenzen oder verschlüsselte Zugangsdaten. Pläne dürfen eine aktive Freigabe für die betroffene Person widerrufen oder eine veränderbare Akteursreferenz lösen. Legal Hold, aktive Aufbewahrung, Form- und Campaign-Nachweise, Konfigurationshistorie und Integritätsnachweise bleiben mit Begründung erhalten. Dateiinhalte, Eigentum, Namen und Pfade benötigen manuelle Prüfung. Freigegebene physische Löschung muss den getrennt autorisierten Files-Vernichtungs- und Blob-Garbage-Collection-Ablauf nutzen, damit DSAR keine Nachweisblocker, Freigabe, Audit- oder Recovery-Kontrollen umgeht."
),
},
"files.reference.integrity-recovery-and-fail-closed-transports": {
"title": "Files-Integrität, Recovery und ausfallsichere Connector-Transporte betreiben",
"summary": "Datenbanknachweise, Blob-Chiffretexte und Encryption-Verwahrung als eine Recovery-Einheit sichern und jeden SDK-verwalteten Gegenpunkt binden.",
"body": (
"Dauerhafter lokaler Speicher ist die betriebliche Basis. Files wird aus einem abgestimmten Datenbank-/Blob-Snapshot mit passenden Encryption-Tabellen und ursprünglichem Deployment-Hauptschlüssel wiederhergestellt; anschließend ist der begrenzte fortsetzbare Integritätsscan auszuführen und geschützter sowie ungeschützter Zugriff stichprobenartig zu prüfen. Scan- und Befundaktionen benötigen die angezeigte Revision. Geschützte Scans prüfen erst den Chiffretext, dann nach Entschlüsselung den semantischen Klartextnachweis. Unter PostgreSQL sichern lease-gebundene Core-Recovery-Absichten Objektauswirkungen ab; Abweichungen werden quarantänisiert und bleiben in Ops sichtbar. SQLite verwendet für Entwicklung eine prozesslokale Sperre und ist kein Produktions-Recovery-Profil; nach hartem Prozessverlust ist ein Integritätsscan erforderlich. Fehlende oder abweichende Blobs werden quarantänisiert, verwaiste Objekte vor einer ausdrücklich autorisierten Bereinigung zunächst nur gemeldet. Physische Vernichtung und Blob-Garbage-Collection prüfen ihre irreversiblen Wirkungen getrennt. S3-Schreibvorgänge nutzen bedingte Effekte und digestbasierte Vorwärts-Recovery; S3- und SMB-Transporte binden Wiederholungen, Umleitungen, Aliasse und erkannte Endpunkte und wenden die Richtlinie für private Netze vor jeder Verbindung erneut an. Fehlt eine verifizierbare Transportnaht, wird geschlossen abgebrochen. Destruktive Modulstilllegung entfernt Datenbanktabellen, nicht jedoch Blob-Objekte im Backend."
),
},
"files.reference.snapshot-provenance-and-capabilities": {
"title": "Snapshot-Provenienz und Files-Fähigkeiten integrieren",
"summary": "Stabile Files-Fähigkeiten oder HTTP-Verträge verwenden und exakte Versionsnachweise bewahren, statt Files-Interna zu importieren.",
"body": (
"files.access erklärt Ressourcenzugriff; files.campaign_attachments friert Campaign-Eingaben auf exaktes Asset, Version, Blob, Prüfsumme und Quellrevision ein. Externe Inhalte müssen vor einer gesteuerten Nutzung importiert und ihre Provenienz auf abgeleiteten Snapshots erhalten werden. Zusammenarbeit, Provider-Synchronisierung, OAuth, externe Änderungen und fachlicher Workflow-Zustand bleiben in den jeweils verantwortlichen Modulen."
),
},
"files.assurance.process-and-release-readiness": {
"title": "Files-gestützte Prozesse und Releases absichern",
"summary": "Einen Prozess gegen die implementierte Files-Grenze prüfen, erlaubte und abgelehnte Pfade erproben und vor Freigabe Nachweise bewahren.",
"body": (
"Prozessverantwortliche müssen implementierte Kontrollen von geplanten Fähigkeiten unterscheiden. Ein Release ist erst bereit, wenn Paket- und Manifestversionen übereinstimmen und repräsentative Pfade für Autorisierung, Upload-Grenzen, Konflikte, Download, Löschung, Connectoren und Recovery erprobt wurden. Wiederherstellung, Aufbewahrung, Legal Hold, gesteuerte Vernichtung, Blob-Garbage-Collection, Freigabelebenszyklus und ausdrückliches S3-Zurückschreiben erzeugen eigene Policy-, Recovery- oder Audit-Nachweise. Gewöhnliche Organisationsänderungen stützen sich weiterhin vor allem auf die Files-Änderungssequenz statt auf ein eigenes kanonisches Audit-Ereignis. Verbleibende Grenzen sind in der Prozessbewertung zu dokumentieren und Nachweisarten dürfen nicht gleichgesetzt werden."
),
},
"files.reference.shared-storage-profile": {
"title": "Files mit einem gemeinsamen Speicherprofil betreiben",
"summary": "Lokalen, hostweit gemeinsamen oder S3-basierten Speicher passend zur Laufzeittopologie wählen.",
"body": (
"Core stellt das gemeinsame lokale/S3-Objektspeicher-Backend bereit; Files verantwortet Dateimetadaten und Objektschlüssel. Lokaler Speicher eignet sich für einen Laufzeitprozess, ein gemeinsames Host-Volume für Replikate auf demselben Host. Unabhängige Hosts benötigen einen ausdrücklich vertrauenswürdigen HTTPS-S3-kompatiblen Endpunkt. PostgreSQL, Objekte und Hauptschlüssel müssen auf denselben abgestimmten Recovery-Zeitpunkt wiederhergestellt werden."
),
},
"files.reference.generated-artifact-store": {
"title": "Erzeugte Modulausgaben speichern",
"summary": "Optionalen Erzeugermodulen erlauben, Ausgaben über die Autoritätsgrenze von Files dauerhaft abzulegen.",
"body": (
"Die Fähigkeit files.artifact_store nimmt erzeugte Bytes mit begrenzter, nicht geheimer Provenienz entgegen, wendet Upload-Autorisierung, Eigentums-, Pfad-, Versions- und Blob-Speicherregeln von Files an und liefert anbieterneutrale Datei-/Versionsreferenzen. Idempotenz beruht auf der Quellprovenienz. Die Annahme eines Artefakts beweist weder Druck, Versand noch eine andere externe Wirkung."
),
},
}
def localize_documentation_topics(
topics: Iterable[DocumentationTopic],
) -> tuple[DocumentationTopic, ...]:
localized: list[DocumentationTopic] = []
for topic in topics:
german = _TRANSLATIONS.get(topic.id)
if german is None:
localized.append(topic)
continue
translations = {
locale: dict(value) for locale, value in topic.translations.items()
}
translations["de"] = {**translations.get("de", {}), **german}
localized.append(replace(topic, translations=translations))
return tuple(localized)
@@ -0,0 +1,458 @@
"""German translations for public structured documentation metadata."""
from __future__ import annotations
from typing import Any
GERMAN_STRUCTURED_TRANSLATIONS: dict[str, dict[str, Any]] = {'files.assurance.process-and-release-readiness': {'outcome': 'Der Prozess oder die '
'Veröffentlichung hat eine explizite '
'Genehmigungsaufzeichnung, die an '
'abgestimmte Versionen, '
'repräsentative Nachweise, bekannte '
'Einschränkungen und eigene '
'Restrisiken gebunden ist.',
'prerequisites': ['Ein benannter '
'Prozessbesitzer hat die '
'beabsichtigten Benutzer, '
'Datenklassifizierung, '
'Aufbewahrungserwartungen und '
'Integrationen definiert.',
'Ein Kandidaten-Release wird '
'in einer sauberen Datenbank '
'und einer Upgrade-Kopie mit '
'ausgerichteten Python-, '
'Root-Paket-, WebUI-Paket- '
'und Modulmanifestversionen '
'installiert.',
'Repräsentative zugelassene '
'und verweigerte Konten, '
'begrenzte Testdateien und '
'ein koordiniertes '
'Datenbank-/Blob-/Key-Wiederherstellungsset '
'sind verfügbar.'],
'steps': ['Vergleichen Sie die '
'Prozessanforderungen mit der '
'implementierten / geplanten Grenze '
'des Handbuchs und notieren Sie jede '
'nicht unterstützte Anforderung oder '
'Kompensationskontrolle.',
'Bestätigen Sie die '
'Versionsausrichtung, wenden Sie '
'Migrationen auf bereinigte und '
'aktualisierte Datenbanken an und '
'führen Sie das Repository sowie '
'Meta-Repository-Sicherheits- und '
'Statikanalyse-Gates aus.',
'Übung erlaubt und verweigert '
'persönlichen, Gruppen und teilen Sie '
'den Zugriff mit repräsentativen '
'Konten.',
'Übung begrenzte Archivvorschau und '
'Bestätigung, jede erforderliche '
'Konfliktstrategie, Organisation, '
'Download und weiche Löschung.',
'Wenn Konnektoren konfiguriert sind, '
'überprüfen Sie die '
'Richtlinienerklärung und einen '
'angehängten HTTP-Provider; '
'überprüfen Sie die '
'Installateur-eigene Garage, wenn Sie '
'ausgewählt sind, und üben Sie dann '
'konfigurierte S3-Retries/Aliases und '
'SMB-Reconnect/Referral-Ziele unter '
'der Bereitstellungsrichtlinie für '
'das private Netzwerk aus, um zu '
'bestätigen, dass eine inkompatible '
'SDK-Transportnaht nicht geschlossen '
'ist.',
'Stellen Sie ein koordiniertes '
'Datenbank-/Blob-/Key-Backup wieder '
'her und vergleichen Sie '
'repräsentative heruntergeladene '
'Bytes mit den aufgezeichneten '
'SHA-256-Prüfsummen.',
'Notieren Sie die getesteten '
'Versionen, Ergebnisse, bekannte '
'Einschränkungen, Evidenzorte, '
'Restrisiken, Eigentümer und '
'Genehmigungsentscheidung.'],
'verification': 'Ein Überprüfer kann die '
'aufgezeichneten '
'Berechtigungs-/Verweigerungs-, '
'Integritäts-, Konnektor- und '
'Wiederherstellungsüberprüfungen '
'reproduzieren und jede nicht '
'erfüllte Anforderung auf eine '
'dokumentierte Einschränkung '
'oder akzeptierte '
'Kompensationskontrolle '
'zurückführen.'},
'files.forms-runtime.managed-evidence': {'limitations': ['Das erste Signaturprofil ist eine '
'authentifizierte Bestätigung; '
'fortgeschrittene und qualifizierte '
'elektronische Signaturen erfordern '
'einen separaten Anbieter.'],
'outcome': 'Der Entwurf verweist auf eine '
'unveränderliche verwaltete Dateiversion mit '
'genauen Prüfsummennachweisen.',
'prerequisites': ['Formulare Laufzeit und Dateien sind '
'aktiviert, und das Aufnahmeprofil hat '
'eine aktive Benutzerdepotbank für den '
'gleichen Mandant.'],
'steps': ['Fordern Sie eine Beweisbewilligung für '
'Dateien von der editierbaren Formularinstanz '
'an, laden Sie sie über die zurückgegebene '
'einmalige Trägerroute hoch und fügen Sie dann '
'die zurückgegebene Beweisreferenz zum Entwurf '
'hinzu.'],
'verification': 'Reichen Sie das Formular ein und '
'vergewissern Sie sich, dass geänderte, '
'gelöschte, unter Quarantäne gestellte, '
'mieterübergreifende und '
'gebührenübergreifende Referenzen '
'abgelehnt werden.'},
'files.governed-connectors-and-provenance': {'limitations': ['Die manuelle '
'Ordner-Synchronisierung plant keine '
'zukünftigen Runs oder mutiert, '
'löscht, umbenennt, verschiebt oder '
'ändert ACLs für entfernte Inhalte.',
'Ein erfolgreicher Teildurchlauf ist '
'keine vollständige Abdeckung, wenn '
'die Antwort verkürzt wird oder '
'Überprüfungsergebnisse enthält.'],
'outcome': 'Zulässige Konnektordateien werden zu '
'verwalteten Assets oder Versionen, '
'während jede Ausnahme explizit und '
'überprüfbar bleibt.',
'prerequisites': ['Ein sichtbarer aktiver '
'Verbindungsraum verwendet '
'manuelle Synchronisierung und '
'Links zu einem zugänglichen '
'verwalteten Benutzer- oder '
'Gruppenraum.',
'Der Betreiber hat '
'file:file:upload und die '
'effektive Konnektorrichtlinie '
'erlaubt die angeforderten Root- '
'und Source-Pfade.'],
'steps': ['Öffnen Sie den Ordner des verknüpften '
'Verbinders, wählen Sie den Ordner Sync '
'und überprüfen Sie das verwaltete Ziel.',
'Halten Sie den sicheren Sprung '
'standardmäßig oder wählen Sie explizit '
'umbenennen, ablehnen oder überschreiben '
'für nicht verwandte Zielkollisionen.',
'Legen Sie die Auswahl der begrenzten '
'Dateianzahl und des Unterordners fest, '
'führen Sie die Synchronisierung aus und '
'überprüfen Sie jedes eingegebene '
'Elementergebnis und jede '
'Abkürzungswarnung.',
'Setzen Sie einen verkürzten Lauf aus '
'einem schmaleren entfernten Ordner fort; '
'konfigurieren Sie die Planung separat, '
'wenn eine Hintergrundoperation '
'erforderlich ist.'],
'verification': 'Vergleichen Sie die '
'Antwortzusammenfassung und die '
'Ergebnisse pro Element mit dem '
'Auditereignis '
'files.connector.folder synced und '
'prüfen Sie dann die Herkunft der '
'erstellten, aktualisierten und '
'unveränderten repräsentativen '
'Assets.'},
'files.privacy.data-subject-requests': {'limitations': ['E-Mail-, Konto- oder '
'Identitätsselektoren allein können nicht '
'von Dateien aufgelöst werden, da Dateien '
'nicht im Besitz des '
'Access-Verzeichnisses sind; geben Sie '
'die bestätigte Mitgliedschaftsreferenz '
'an.',
'Der Anbieter bettet keine rohen '
'Dateiinhalte in den JSON-Export ein und '
'führt niemals eine physische '
'Blob-Löschung als DSAR-Nebenwirkung '
'durch.'],
'outcome': 'Dateieigene Betreffreferenzen werden '
'überprüft oder entfernt, ohne den '
'zurückgehaltenen Inhalt oder Nachweise '
'stillschweigend zu zerstören.',
'prerequisites': ['Die Anfrage wurde autorisiert und '
'enthält eine direkte '
'Mandantenmitgliedschaft oder eine '
'Betreffreferenz Dateien.',
'Der Datenschutzprüfer kann den '
'Zugriffsexport von der Löschbehörde '
'und der Löschbehörde für Dateien '
'unterscheiden.'],
'steps': ['Führen Sie die Anbietersuche aus und '
'bestätigen Sie die vollständige Abdeckung der '
'Dateiberichte anstelle eines ausgefallenen '
'oder abwesenden Anbieters.',
'Überprüfen Sie Datei-/Versionsmetadaten, '
'Gründe für die Aufbewahrung von Nachweisen und '
'den Quellpfad für die manuelle '
'Inhaltsüberprüfung.',
'Generieren Sie den Löschplan und führen Sie '
'nur die genehmigten reversiblen '
'Aktienrücknahme- oder Subjektreferenzaktionen '
'aus.',
'Für die genehmigte Byte-Löschung lösen Sie '
'jeden Lifecycle-Blocker auf und verwenden Sie '
'Files Purge Preview, Execution und Blob '
'Garbage Collection separat.'],
'verification': 'Bestätigen Sie, dass jeder '
'Dateidatensatz eine Aufbewahrungs-, '
'Überprüfungs-, Widerrufs- oder '
'Loslösungsdisposition hat und prüfen Sie '
'jede separate Bereinigung durch seine '
'Audit- und Wiederherstellungsnachweise.'},
'files.records.exact-version-source': {'outcome': 'Records behält eine exakt geregelte Referenz, '
'während Files Byte Authority bleibt.',
'prerequisites': ['Die genaue Dateiversion existiert und '
'übergibt das aktuelle Files Integrity '
'Gate.',
'Sie haben derzeit die Datei Lesezugriff '
'und Records Einreichung Behörde.'],
'steps': ['Wählen Sie die genaue verwaltete Dateiversion '
'aus, die zum institutionellen Datensatz gehört.',
'Wählen Sie den Zieldatensatz und geben Sie den '
'Zugangszweck und den Anmeldegrund an.',
'Bestätigen Sie die Einreichung; Dateien '
'überprüft den aktuellen Zugriff erneut und löst '
'die genaue Version auf.',
'Öffnen Sie die Datensatzchronologie und '
'überprüfen Sie die Versionsidentität und den '
'SHA-256 Digest.']},
'files.reference.integrity-recovery-and-fail-closed-transports': {'verification': 'Führen Sie '
'nach der '
'Wiederherstellung '
'einen '
'Checksummen-fähigen '
'Integritätsscan '
'aus, lösen Sie '
'jedes fehlende '
'/ korrupte '
'Finden, '
'genehmigen '
'oder behalten '
'Sie jedes '
'gemeldete '
'Waisenkind, '
'inspizieren '
'Sie die '
'Wiederherstellungsvorgänge '
'von Dateien in '
'Ops, '
'überprüfen Sie '
'den '
'autorisierten '
'und '
'verweigerten '
'Zugriff und '
'testen Sie '
'konfigurierte '
'HTTP-, S3- und '
'SMB-Verbindungen '
'mit ihrer '
'aufgezeichneten '
'Zieltopologie.'},
'files.reference.shared-storage-profile': {'limitations': ['Installer-verwaltete Garage ist '
'Single-Node, es sei denn, ein '
'externer Multi-Node-Cluster wird '
'separat betrieben.',
'Die Anwendung erstellt oder '
'verifiziert keine '
'PostgreSQL/Objekt/Schlüssel-Backups.'],
'verification': 'Führen Sie die '
'Dateispeicher-Round-Trip-Prüfung und '
'eine koordinierte '
'Wiederherstellungsübung gegen die '
'genaue Bereitstellungstopologie aus.'},
'files.tabular-content': {'consequence_classes': {'fail_closed': 'Nicht verfügbare, '
'überdimensionierte, unter '
'Quarantäne gestellte oder nicht '
'autorisierte Inhalte werden '
'nicht analysiert oder in der '
'Vorschau angezeigt.',
'pin_exact_version': 'Eine Quelle behält ihre '
'überprüfte '
'unveränderliche '
'Dateiversion, bis sie '
'explizit aktualisiert '
'wird.',
'preserve_file_controls': 'Zugriff auf Dateien, '
'Integrität, '
'Verschlüsselung, '
'Aufbewahrung und '
'rechtliche Kontrolle '
'bleiben '
'autoritativ.'}},
'files.workflow.delete-managed-files': {'limitations': ['Löschung ist eine weiche Löschung, keine '
'harte Säuberung.',
'Die Wiederherstellung schlägt fehl, wenn '
'eine aktive Datei, ein Ordner oder ein '
'Verbindungsraum bereits den Pfad oder '
'das Label verwendet.'],
'outcome': 'Der ausgewählte Inhalt wird aus aktiven '
'Dateiansichten unter dem aktuellen '
'Soft-Löschmodell ausgeblendet.',
'prerequisites': ['Sie können die ausgewählten '
'verwalteten Inhalte anzeigen und '
'löschen und haben Schreib- oder '
'Eigentümerzugriff auf jedes betroffene '
'Asset oder jeden Ordner.',
'Sie haben den gesamten Ordnerbaum beim '
'rekursiven Löschen überprüft.'],
'steps': ['Öffnen Sie Dateien und wählen Sie die Dateien '
'oder den Ordner zum Löschen aus.',
'Überprüfen Sie die Auswahl und, für einen '
'Ordner, alle Inhalte darunter.',
'Bestätigen Sie die Löschaktion.',
'Erfrischen oder öffnen Sie den Raum und '
'überprüfen Sie, ob die ausgewählten Pfade '
'nicht mehr aktiv sind.'],
'verification': 'Bestätigen Sie, dass die gelöschten '
'Pfade nicht mehr im aktiven Raum '
'erscheinen; behandeln Sie die Aktion '
'nicht als physisches Löschen.'},
'files.workflow.find-and-download-files': {'outcome': 'Die autorisierten aktuellen Dateibytes '
'oder das generierte Archiv werden auf das '
'lokale Gerät heruntergeladen.',
'prerequisites': ['Sie können verwaltete Dateien im '
'entsprechenden Bereich anzeigen und '
'herunterladen.'],
'steps': ['Öffnen Sie Dateien und wählen Sie den '
'entsprechenden Personen- oder Gruppenraum '
'aus.',
'Navigieren Sie in Ordnern, sortieren Sie '
'die Liste oder verwenden Sie ein Pfad- / '
'Namensmuster, um den beabsichtigten Inhalt '
'zu finden.',
'Überprüfen Sie den angezeigten Besitzer, '
'Pfad, Größe, Prüfsumme und Versionsdetails.',
'Laden Sie eine aktuelle Dateiversion '
'herunter oder wählen Sie mehrere Dateien '
'aus und wählen Sie ZIP herunterladen.'],
'verification': 'Bestätigen Sie die heruntergeladenen '
'Namen und vergleichen Sie, wo '
'Integrität wichtig ist, die '
'Dateibytes mit der angezeigten '
'Prüfsumme.'},
'files.workflow.organize-managed-files': {'outcome': 'Der ausgewählte Inhalt hat den '
'beabsichtigten verwalteten Eigentümer und '
'logischen Pfad.',
'prerequisites': ['Sie können verwaltete Dateien '
'anzeigen und organisieren.',
'Sie haben Schreib- oder '
'Eigentümerzugriff auf alle von der '
'Operation verwendeten Quellelemente '
'und Zielbereiche; die globale '
'Organisationsberechtigung allein '
'gewährt keinen Ressourcenzugriff.'],
'steps': ['Öffnen Sie Dateien und wählen Sie den '
'persönlichen oder Gruppenraum zum '
'Organisieren aus.',
'Erstellen Sie die erforderlichen Zielordner '
'oder wählen Sie die Dateien und Ordner aus, '
'um sie umzubenennen, zu verschieben oder zu '
'kopieren.',
'Wählen Sie das Ziel aus und lösen Sie jeden '
'Zielkonflikt explizit.',
'Wenden Sie die Operation an und öffnen Sie '
'den Zielordner erneut.'],
'verification': 'Bestätigen Sie jeden resultierenden '
'Pfad und Besitzer; für eine Bewegung '
'bestätigen Sie auch, dass der alte '
'Pfad verschwunden ist, und für eine '
'Kopie bestätigen Sie, dass die Quelle '
'verbleibt.'},
'files.workflow.restore-retain-and-purge': {'limitations': ['Automatische zeitbasierte '
'Bereinigungsplanung ist nicht '
'enthalten; ein autorisierter '
'handelnde Person startet Vorschau, '
'Ausführung und Blob-Sammlung.',
'Der Verschlüsselungsumschlag eines '
'geschützten Blobs folgt der eigenen '
'Aufbewahrungs- und '
'Schlüssel-Verwahrungsrichtlinie des '
'Verschlüsselungsmoduls.'],
'outcome': 'Berechtigte Metadaten und nicht '
'referenzierte Bytes werden mit separat '
'überprüfbaren Richtlinien-, Audit- und '
'Wiederherstellungsnachweisen gelöscht.',
'prerequisites': ['Die handelnde Person hat die '
'eindeutige Wiederherstellungs-, '
'Aufbewahrungs- oder '
'Bereinigungsberechtigung, die für '
'die beabsichtigte Aktion '
'erforderlich ist.',
'Ein Bereinigungsziel ist bereits '
'sanft gelöscht und alle abhängigen '
'Nachweise oder Aktien wurden '
'rechtmäßig gelöst.'],
'steps': ['Festlegen oder Überprüfen von '
'Aufbewahrungs- und Haltezustand unter '
'Verwendung der angezeigten '
'Lifecycle-Revision.',
'Überprüfen Sie zum Wiederherstellen, ob '
'der ursprüngliche Pfad oder das '
'ursprüngliche Label frei ist, und stellen '
'Sie die gleiche Ressource wieder her.',
'Erstellen Sie zum Löschen eine begrenzte '
'Purge-Vorschau und lösen Sie jeden '
'benannten Blocker auf.',
'Führen Sie die passende Vorschau mit einem '
'idempotency-Schlüssel, PURGE-Bestätigung '
'und Genehmigungsreferenz aus.',
'Führen Sie eine begrenzte '
'Blob-Garbage-Sammlung aus und prüfen Sie '
'alle Wiederherstellungs- oder '
'Ergebnis-unbekannten Operationen in Ops.'],
'verification': 'Überprüfen Sie, ob die '
'Asset-/Versionszeilen fehlen, der '
'Blob bleibt referenziert, nicht '
'referenzierte Bytes fehlen nach GC '
'und jede Operation hat eine gültige '
'Wiederherstellungsnachweiskette.'},
'files.workflow.share-managed-files': {'limitations': ['Kampagnenziel-Zuschüsse werden '
'normalerweise durch die '
'Kampagnenintegration erstellt und nicht '
'manuell im Dateidialog ausgewählt.',
'Ein Benutzer kann den Zugriff über einen '
'anderen aktiven direkten Zuschuss oder '
'Besitzpfad behalten, nachdem eine Aktie '
'widerrufen wurde.',
'Ausgewählte benutzererklärungen erfordern '
'die richtlinienberechtigung und sind nur '
'diagnosen; sie geben sich nicht als '
'benutzer aus oder gewähren dateizugriff.'],
'outcome': 'Direkter Zugriff hat die angeforderte '
'Berechtigung und Lebensdauer, während das '
'verwaltete Asset seinen Eigentümer behält.',
'prerequisites': ['Sie haben die Freigabeberechtigung für '
'Dateien und besitzen die Datei oder '
'verwalten Dateiräume für den aktiven '
'Mandanten.',
'Das beabsichtigte Benutzer-, Gruppen-, '
'Mandant- oder Kampagnenziel existiert '
'und ist aktiv.'],
'steps': ['Wählen Sie eine verwaltete Datei aus, wählen '
'Sie Shares verwalten und überprüfen Sie die '
'effektiven und historischen direkten Zuschüsse.',
'Wählen Sie den beabsichtigten Benutzer, die '
'Gruppe oder den Mandanten aus und wählen Sie '
'den Zugriff lesen, schreiben oder verwalten '
'sowie einen optionalen Ablauf.',
'Geben oder aktualisieren Sie die Freigabe, ohne '
'den Dateibesitz zu ändern.',
'Widerrufen Sie einen Zuschuss, wenn er nicht '
'mehr benötigt wird; wiederholter Widerruf ist '
'ein No-Op.'],
'verification': 'Testen Sie einen beabsichtigten und einen '
'verweigerten Pfad, verfallen oder '
'widerrufen Sie die Gewährung und stellen '
'Sie sicher, dass nur noch unabhängige '
'Zugangspfade verbleiben.'}}
+14 -3
View File
@@ -1,5 +1,8 @@
from __future__ import annotations
from govoplan_core.core.modules import with_documentation_structured_translations
from govoplan_files.backend.german_structured_documentation import GERMAN_STRUCTURED_TRANSLATIONS
from dataclasses import replace
from pathlib import Path
@@ -55,6 +58,9 @@ from govoplan_files.backend.configuration_provider import (
)
from govoplan_files.backend.db import models as file_models # noqa: F401 - populate Files ORM metadata
from govoplan_files.backend.documentation import documentation_topics
from govoplan_files.backend.german_documentation import (
localize_documentation_topics,
)
from govoplan_files.backend.dsar_provider import FILES_DSAR_CAPABILITY
from govoplan_files.backend.form_evidence import (
CAPABILITY_FORM_EVIDENCE_FILES,
@@ -452,7 +458,7 @@ def _dsar_provider(context: ModuleContext) -> object:
manifest = ModuleManifest(
id="files",
name="Files",
version="0.1.20",
version="0.1.23",
required_capabilities=(
CAPABILITY_AUTH_PRINCIPAL_RESOLVER,
CAPABILITY_AUTH_PERMISSION_EVALUATOR,
@@ -617,7 +623,7 @@ manifest = ModuleManifest(
),
),
),
documentation=(
documentation=localize_documentation_topics((
DocumentationTopic(
id="files.tabular-content",
title="Use managed CSV and XLSX versions as governed data sources",
@@ -1750,7 +1756,7 @@ manifest = ModuleManifest(
related_modules=("templates", "campaigns", "reporting"),
metadata={"kind": "reference", "route": "/files"},
),
),
)),
documentation_providers=(documentation_topics,),
migration_spec=MigrationSpec(
module_id="files",
@@ -1876,5 +1882,10 @@ manifest = ModuleManifest(
)
manifest = with_documentation_structured_translations(
manifest, locale="de", translations=GERMAN_STRUCTURED_TRANSLATIONS
)
def get_manifest() -> ModuleManifest:
return manifest
+7
View File
@@ -0,0 +1,7 @@
from govoplan_files.backend.manifest import get_manifest
def test_static_documentation_has_complete_german_reference_copy() -> None:
for topic in get_manifest().documentation:
german = topic.translations.get("de", {})
assert all(german.get(field, "").strip() for field in ("title", "summary", "body")), topic.id
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@govoplan/files-webui",
"version": "0.1.20",
"version": "0.1.23",
"private": true,
"type": "module",
"main": "src/index.ts",
@@ -1061,7 +1061,7 @@ export default function FileConnectorSettingsPanel({
)}
<div className="file-connector-settings-section file-connector-policy-locks">
<ToggleSwitch label="i18n:govoplan-files.lower_connection_limits.4f9838bc" checked={policyDraft.allowLowerConnectionLimits} disabled={saving || !canWrite} onChange={(allowLowerConnectionLimits) => patchPolicyDraft({ allowLowerConnectionLimits })} />
<ToggleSwitch label="i18n:govoplan-files.lower_credential_limits.ec2b72bc" checked={policyDraft.allowLowerCredentialLimits} disabled={saving || !canWrite} onChange={(allowLowerCredentialLimits) => patchPolicyDraft({ allowLowerCredentialLimits })} />
<ToggleSwitch label="i18n:govoplan-files.lower_credential_limits.ec2b72bc" helpContextId="files.connector.policy" helpModuleId="files" checked={policyDraft.allowLowerCredentialLimits} disabled={saving || !canWrite} onChange={(allowLowerCredentialLimits) => patchPolicyDraft({ allowLowerCredentialLimits })} />
<ToggleSwitch label="i18n:govoplan-files.lower_provider_limits.5816270a" checked={policyDraft.allowLowerProviderLimits} disabled={saving || !canWrite} onChange={(allowLowerProviderLimits) => patchPolicyDraft({ allowLowerProviderLimits })} />
<ToggleSwitch label="i18n:govoplan-files.lower_path_limits.1abcccb1" checked={policyDraft.allowLowerPathLimits} disabled={saving || !canWrite} onChange={(allowLowerPathLimits) => patchPolicyDraft({ allowLowerPathLimits })} />
<ToggleSwitch label="i18n:govoplan-files.lower_endpoint_limits.3fd781d5" checked={policyDraft.allowLowerUrlLimits} disabled={saving || !canWrite} onChange={(allowLowerUrlLimits) => patchPolicyDraft({ allowLowerUrlLimits })} />
@@ -1101,14 +1101,14 @@ export default function FileConnectorSettingsPanel({
<p>Choose where this credential can be used and how it signs in.</p>
</header>
<FormGrid columns={2} collapseAt="standard" className="">
<FormField label="i18n:govoplan-files.credential_id.9432a6e1">
<FormField label="i18n:govoplan-files.credential_id.9432a6e1" helpContextId="files.connector.credentials" helpModuleId="files">
<input className={!editingCredentialId && !credentialDraft.id.trim() ? "field-input-missing" : undefined} aria-invalid={!editingCredentialId && !credentialDraft.id.trim() || undefined} value={credentialDraft.id} disabled={Boolean(editingCredentialId) || saving} onChange={(event) => patchCredentialDraft({ id: event.target.value })} placeholder={`${scopeType}-webdav-credentials`} />
</FormField>
<FormField label="i18n:govoplan-files.label.74341e3c">
<input className={!credentialDraft.label.trim() ? "field-input-missing" : undefined} aria-invalid={!credentialDraft.label.trim() || undefined} value={credentialDraft.label} disabled={saving} onChange={(event) => patchCredentialDraft({ label: event.target.value })} placeholder="i18n:govoplan-files.govoplan_webdav_credentials.bc696d69" />
</FormField>
{credentialAttachProfileId &&
<FormField label="i18n:govoplan-files.connection_credential.178babe0">
<FormField label="i18n:govoplan-files.connection_credential.178babe0" helpContextId="files.connector.credentials" helpModuleId="files">
<input value={credentialAttachedProfile ? `${credentialAttachedProfile.label} (${credentialAttachedProfile.id})` : credentialAttachProfileId} disabled readOnly />
</FormField>
}
@@ -1130,8 +1130,8 @@ export default function FileConnectorSettingsPanel({
/>
</FormField>
</div>
<FormField label="i18n:govoplan-files.credential_mode.23fdd899" documentation={CONNECTOR_DOCUMENTATION}>
<select value={credentialDraft.credentialMode} disabled={saving} onChange={(event) => patchCredentialDraft({ credentialMode: event.target.value as CredentialMode })}>
<FormField label="i18n:govoplan-files.credential_mode.23fdd899" documentation={CONNECTOR_DOCUMENTATION} helpContextId="files.connector.credentials" helpModuleId="files">
<select data-help-context-id="files.connector.credentials" data-help-module-id="files" value={credentialDraft.credentialMode} disabled={saving} onChange={(event) => patchCredentialDraft({ credentialMode: event.target.value as CredentialMode })}>
<option value="none">i18n:govoplan-files.none.6eef6648</option>
<option value="anonymous">i18n:govoplan-files.anonymous.9bed5104</option>
<option value="basic">i18n:govoplan-files.username_password.e8ba8896</option>
@@ -1142,8 +1142,8 @@ export default function FileConnectorSettingsPanel({
</FormGrid>
<div className="file-connector-settings-section">
<ToggleSwitch label="i18n:govoplan-files.enabled.df174a3f" checked={credentialDraft.enabled} disabled={saving} onChange={(enabled) => patchCredentialDraft({ enabled })} />
{editingCredentialId && <ToggleSwitch label="i18n:govoplan-files.clear_saved_password.7442260d" checked={credentialDraft.clearPassword} disabled={saving} onChange={(clearPassword) => patchCredentialDraft({ clearPassword })} />}
{editingCredentialId && <ToggleSwitch label="i18n:govoplan-files.clear_saved_token.a9c670aa" checked={credentialDraft.clearToken} disabled={saving} onChange={(clearToken) => patchCredentialDraft({ clearToken })} />}
{editingCredentialId && <ToggleSwitch label="i18n:govoplan-files.clear_saved_password.7442260d" helpContextId="files.connector.credentials" helpModuleId="files" checked={credentialDraft.clearPassword} disabled={saving} onChange={(clearPassword) => patchCredentialDraft({ clearPassword })} />}
{editingCredentialId && <ToggleSwitch label="i18n:govoplan-files.clear_saved_token.a9c670aa" helpContextId="files.connector.credentials" helpModuleId="files" checked={credentialDraft.clearToken} disabled={saving} onChange={(clearToken) => patchCredentialDraft({ clearToken })} />}
</div>
</section>
@@ -1179,8 +1179,8 @@ export default function FileConnectorSettingsPanel({
disabled={saving}
showPassword={false} />
<FormGrid columns={2} collapseAt="standard" className="">
<FormField label="i18n:govoplan-files.secret_reference.04ed2221">
<input value={credentialDraft.secretRef} disabled={saving} onChange={(event) => patchCredentialDraft({ secretRef: event.target.value })} />
<FormField label="i18n:govoplan-files.secret_reference.04ed2221" helpContextId="files.connector.credentials" helpModuleId="files">
<input data-help-context-id="files.connector.credentials" data-help-module-id="files" value={credentialDraft.secretRef} disabled={saving} onChange={(event) => patchCredentialDraft({ secretRef: event.target.value })} />
</FormField>
</FormGrid>
</>
@@ -1304,8 +1304,8 @@ export default function FileConnectorSettingsPanel({
<FormField label="i18n:govoplan-files.base_path.6a4867ca">
<input value={draft.basePath} disabled={saving} onChange={(event) => patchDraft({ basePath: event.target.value })} placeholder="GovOPlaN" />
</FormField>
<FormField label="i18n:govoplan-files.credential_mode.23fdd899" documentation={CONNECTOR_DOCUMENTATION}>
<select value={draft.credentialMode} disabled={saving} onChange={(event) => patchDraft({ credentialMode: event.target.value as CredentialMode })}>
<FormField label="i18n:govoplan-files.credential_mode.23fdd899" documentation={CONNECTOR_DOCUMENTATION} helpContextId="files.connector.credentials" helpModuleId="files">
<select data-help-context-id="files.connector.credentials" data-help-module-id="files" value={draft.credentialMode} disabled={saving} onChange={(event) => patchDraft({ credentialMode: event.target.value as CredentialMode })}>
<option value="none">i18n:govoplan-files.none.6eef6648</option>
<option value="anonymous">i18n:govoplan-files.anonymous.9bed5104</option>
<option value="basic">i18n:govoplan-files.username_password.e8ba8896</option>
@@ -1313,8 +1313,8 @@ export default function FileConnectorSettingsPanel({
<option value="secret_ref">i18n:govoplan-files.secret_reference.04ed2221</option>
</select>
</FormField>
<FormField label="i18n:govoplan-files.credential.8bede3ea">
<select value={profileCredentialSelectValue} disabled={saving || profileCredentialOptions.length === 0} onChange={(event) => patchDraft({ credentialProfileId: event.target.value })}>
<FormField label="i18n:govoplan-files.credential.8bede3ea" helpContextId="files.connector.credentials" helpModuleId="files">
<select data-help-context-id="files.connector.credentials" data-help-module-id="files" value={profileCredentialSelectValue} disabled={saving || profileCredentialOptions.length === 0} onChange={(event) => patchDraft({ credentialProfileId: event.target.value })}>
{profileCredentialOptions.length === 0 && <option value="">i18n:govoplan-files.no_saved_credential.30a5a951</option>}
{profileCredentialOptions.map((credential) => <option key={credential.id} value={credential.id}>{credential.label}</option>)}
</select>
+7 -1
View File
@@ -2293,7 +2293,7 @@ export default function FilesPage({ settings, auth }: {settings: ApiSettings;aut
<Button onClick={() => openTransferDialog("copy")} disabled={Boolean(organizeBlocker || selectionBlocker)} disabledReason={organizeBlocker || selectionBlocker}><Copy size={16} aria-hidden="true" /> i18n:govoplan-files.copy.af74f7c5</Button>
{hasSelection && <Button onClick={openRenameDialog} disabled={Boolean(organizeBlocker)} disabledReason={organizeBlocker}>{selectedEntryCount === 1 ? "i18n:govoplan-files.rename.d3f4cb89" : "i18n:govoplan-files.bulk_rename.7dcaa624"}</Button>}
<Button onClick={() => accessExplainableTarget && void openAccessExplanation(accessExplainableTarget)} disabled={Boolean(accessExplanationBlocker)} disabledReason={accessExplanationBlocker}><KeyRound size={16} aria-hidden="true" /> i18n:govoplan-files.explain_access.4d5fac37</Button>
<Button variant="danger" onClick={() => void deleteSelected()} disabled={Boolean(deleteBlocker)} disabledReason={deleteBlocker}><Trash2 size={16} aria-hidden="true" /> i18n:govoplan-files.delete.f6fdbe48</Button>
<Button variant="danger" helpContextId="files.list" helpModuleId="files" onClick={() => void deleteSelected()} disabled={Boolean(deleteBlocker)} disabledReason={deleteBlocker}><Trash2 size={16} aria-hidden="true" /> i18n:govoplan-files.delete.f6fdbe48</Button>
{activeSpaceIsConnector &&
<Button
variant="danger"
@@ -2793,8 +2793,12 @@ export default function FilesPage({ settings, auth }: {settings: ApiSettings;aut
{archivePreview.requires_password &&
<FormField
label="Archive password"
helpContextId="files.list"
helpModuleId="files"
help="The password stays in this dialog and is sent only while inspecting or importing this archive.">
<PasswordField
helpContextId="files.list"
helpModuleId="files"
value={archivePassword}
onValueChange={setArchivePassword}
disabled={busy}
@@ -2857,6 +2861,8 @@ export default function FilesPage({ settings, auth }: {settings: ApiSettings;aut
</Button>
{archivePreview.requires_password &&
<Button
helpContextId="files.list"
helpModuleId="files"
onClick={() => activeDialogTarget && void loadArchivePreview(archiveFile, activeDialogTarget, { preserveSelection: true })}
disabled={busy || !archivePassword}>
<RefreshCw size={15} aria-hidden="true" /> Verify password
@@ -264,7 +264,7 @@ export function FileContextMenu({
<button type="button" role="menuitem" onClick={onMove} disabled={!hasSelection || !canOrganize}><MoveRight size={15} aria-hidden="true" /> i18n:govoplan-files.move.8a74a26e</button>
<button type="button" role="menuitem" onClick={onCopy} disabled={!hasSelection || !canOrganize}><Copy size={15} aria-hidden="true" /> i18n:govoplan-files.copy.92556c6d</button>
<button type="button" role="menuitem" onClick={onExplainAccess} disabled={!canExplainAccess}><KeyRound size={15} aria-hidden="true" /> i18n:govoplan-files.explain_access.4d5fac37</button>
{showDelete && <button type="button" role="menuitem" className="danger" onClick={onDelete} disabled={!canDelete}><Trash2 size={15} aria-hidden="true" /> i18n:govoplan-files.delete.f6fdbe48</button>}
{showDelete && <button type="button" role="menuitem" className="danger" data-help-context-id="files.list" data-help-module-id="files" onClick={onDelete} disabled={!canDelete}><Trash2 size={15} aria-hidden="true" /> i18n:govoplan-files.delete.f6fdbe48</button>}
</div>);
}