Die restlichen zwei Änderungswünsche. **Protokoll.** „Wer was wo macht" stand seit dem ersten Tag in AuditLog - harte Regel 3 sorgt dafür. Was fehlte, war die Ansicht darauf. /admin/protokoll ist genau das und keine zweite Aufzeichnung: filterbar nach Person, Aktion, Art und Zeitraum, rückwärts blätternd. Nur für die Leitung. Eine Zeile nennt Aktenzeichen und Namen, und schon die Existenz einer Zeile verrät, dass es einen Vorgang gibt; ein gefiltertes Protokoll für alle wäre ein Weg, die Sichtbarkeitsregeln von hinten aufzurollen. Aus demselben Grund werden Kennungen ohne Sichtbarkeitsfilter zu Aktenzeichen aufgelöst - ein Protokoll aus UUIDs liest niemand, und eines, das niemand liest, ist keine Kontrolle. **Speichern.** Jedes Feld trug seinen eigenen Knopf: ein Arbeitsvertrag mit zwölf Feldern hiess zwölfmal speichern. Der Knopf steht jetzt am Blatt. Geschrieben wird trotzdem je Feld und nicht als Transaktion, und das folgt aus dem Datenmodell: Abschnitte sind einzeln versioniert, weil mehrere Leute gleichzeitig an einer Akte arbeiten. Als Transaktion blockierte ein einziges zwischenzeitlich geändertes Feld das ganze Blatt - elf gute Änderungen verloren, weil jemand das zwölfte angefasst hat. So geht durch, was durchgeht, und die Rückmeldung sagt, was offen blieb und wo. Lichtbilder bleiben ausgenommen: ein Upload mit Prüfkette ist keine Feldänderung. lib/audit.ts liegt jetzt als lib/audit/write.ts neben lib/audit/query.ts.
90 lines
3.2 KiB
TypeScript
90 lines
3.2 KiB
TypeScript
/**
|
||
* Dokumente und Anhänge.
|
||
*
|
||
* Nach Bereichen getrennt, weil eine **Client-Komponente die ganze Datei ins
|
||
* Bündel zieht**, in der ihr Text steht. Lägen alle Texte in einer, trüge jede
|
||
* Ansicht die der ganzen Anwendung mit sich herum — das Budget aus
|
||
* docs/09-performance-und-ux.md wäre nach wenigen Phasen aufgebraucht.
|
||
*
|
||
* Serverkomponenten nehmen weiter `de` aus `lib/i18n/de.ts`: was dorthin
|
||
* gezogen wird, verlässt den Server nicht.
|
||
*/
|
||
|
||
export const documentText = {
|
||
saveAll: 'Dokument speichern',
|
||
one: 'Dokument',
|
||
many: 'Dokumente',
|
||
number: 'Dokumentnummer',
|
||
title: 'Titel',
|
||
kind: 'Dokumentart',
|
||
heading: 'Dokumente',
|
||
empty: 'Noch kein Dokument.',
|
||
create: 'Dokument anlegen',
|
||
createTitle: 'Neues Dokument',
|
||
createHint: 'Die Vorlage bestimmt Aufbau und Aussehen. Der Titel lässt sich später ändern.',
|
||
open: 'Öffnen',
|
||
finalize: 'Ausfertigen',
|
||
finalizeHint: 'Danach sind Änderungen nur noch mit eigenem Recht möglich.',
|
||
retract: 'Zurückziehen',
|
||
retractReason: 'Begründung der Zurücknahme',
|
||
reclassify: 'Klassifizierung ändern',
|
||
retracted: (date: string, person: string, reason: string) =>
|
||
`Dokument zurückgezogen am ${date} durch ${person} · Begründung: ${reason}`,
|
||
finalized: (date: string, person: string) => `Ausgefertigt am ${date} durch ${person}`,
|
||
sheet: 'Aktenblatt',
|
||
edit: 'Bearbeiten',
|
||
print: 'Drucken',
|
||
issuedAt: 'Ausgestellt',
|
||
signedOn: 'Datum',
|
||
unclassified: 'Ohne Klassifikation',
|
||
photoEmpty: 'Lichtbild 3×4 cm',
|
||
photoLater: 'Lichtbilder kommen mit der Dateiprüfung.',
|
||
footerNote: 'Dieses Dokument ist klassifiziert. Nur für autorisiertes Personal.',
|
||
ownerCase: 'Zur Fallakte',
|
||
ownerPersonnel: 'Zur Personalakte',
|
||
ownerNone: 'Ohne Besitzer',
|
||
statusNames: {
|
||
DRAFT: 'Entwurf',
|
||
FINAL: 'Ausgefertigt',
|
||
RETRACTED: 'Zurückgezogen',
|
||
} as Record<string, string>,
|
||
layoutNames: {
|
||
FORM: 'Formular',
|
||
PROSE: 'Vertragstext',
|
||
NOTE: 'Vermerk',
|
||
DOSSIER: 'Aktenblatt',
|
||
} as Record<string, string>,
|
||
} as const
|
||
|
||
export const attachmentText = {
|
||
one: 'Anhang',
|
||
many: 'Anhänge',
|
||
heading: 'Anhänge',
|
||
empty: 'Keine Anhänge.',
|
||
add: 'Datei anhängen',
|
||
choose: 'Datei wählen',
|
||
dropHint: 'Datei hierher ziehen oder auswählen',
|
||
allowed: 'PNG, JPEG, WebP, PDF oder Text, bis 25 MB',
|
||
uploading: 'Wird übertragen',
|
||
checking: 'Wird geprüft',
|
||
download: 'Herunterladen',
|
||
release: 'Trotzdem freigeben',
|
||
releaseHint:
|
||
'Die Datei wurde nicht auf Schadsoftware geprüft. Sie wird beim Freigeben neu kodiert, soweit das geht.',
|
||
quotaUsed: (used: string, total: string) => `${used} von ${total} belegt`,
|
||
statusNames: {
|
||
PENDING: 'Wird geprüft',
|
||
CLEAN: 'Geprüft',
|
||
BLOCKED: 'Abgelehnt',
|
||
FAILED: 'Prüfung unvollständig',
|
||
} as Record<string, string>,
|
||
errors: {
|
||
'file-empty': 'Die Datei ist leer.',
|
||
'file-too-large': 'Die Datei ist größer als 25 MB.',
|
||
'quota-exceeded': 'Dein Kontingent von 500 MB ist ausgeschöpft.',
|
||
'rate-limited': 'Zu viele Uploads. In einer Minute erneut versuchen.',
|
||
'release-not-possible': 'Nur eine unvollständige Prüfung lässt sich freigeben.',
|
||
transfer: 'Übertragung fehlgeschlagen. Erneut versuchen.',
|
||
} as Record<string, string>,
|
||
} as const
|