Vollständiger Statusfilter, Beteiligte beim Anlegen, Knöpfe in den Listen
Vier Sachen aus der Durchsicht. **Der Statusfilter zeigte fünf von sieben Zuständen.** DRAFT und SEALED fehlten - ausgerechnet die beiden, die in der Liste am häufigsten standen; man konnte nach dem, was man sah, gerade nicht filtern. Das erklärt auch die Frage, was „In Prüfung" und „Ruhend" bedeuten: die Zustände standen nirgends in der Oberfläche. Jetzt alle sieben in der Reihenfolge des Lebenszyklus, mit einer Erklärung als title, und Versiegelt nur für den, der Versiegeltes lesen darf. Ein Test verlangt zu jedem Zustand einen Namen und eine Erklärung. **Beliebig viele Beteiligte beim Anlegen.** Das Formular kannte genau eine „betroffene Person", und die Rolle war auf SUBJECT festgelegt. Jetzt beliebig viele Zeilen mit je einer Rolle, Konten und Personalakten in einer Auswahl, wie auf der Aktenseite. Die Zerlegung steht als parseParticipantDrafts in lib/cases/terms.ts und nicht in der Server Action: seit die Rolle über den Zugriff entscheidet, darf eine erfundene Rolle nicht durchrutschen. **Die Filterleisten sind Knöpfe** wie überall sonst, mit gefülltem aktivem Filter. **Keine leere Kennungsspalte mehr.** In „Zuletzt geöffnet" stand bei einer Person nichts, wo sonst das Aktenzeichen steht - jetzt steht dort „Personalakte". Nebenbei zwei Stellen zurückgenommen, an denen die Spaltenklasse im Seitenkopf gelandet war statt in einer Zeile.
This commit is contained in:
@@ -50,6 +50,21 @@ export function grantsCaseAccess(role: string): boolean {
|
||||
return (WORKING_ROLES as readonly string[]).includes(role)
|
||||
}
|
||||
|
||||
/**
|
||||
* Die Zustände einer Fallakte in der Reihenfolge des Lebenszyklus aus
|
||||
* docs/05-akten-und-vorlagen.md. `SEALED` steht am Ende, weil es aus jedem
|
||||
* Zustand erreichbar ist und keine Stufe im Ablauf bildet.
|
||||
*/
|
||||
export const CASE_STATUSES = [
|
||||
'DRAFT',
|
||||
'OPEN',
|
||||
'REVIEW',
|
||||
'DORMANT',
|
||||
'CLOSED',
|
||||
'ARCHIVED',
|
||||
'SEALED',
|
||||
] as const
|
||||
|
||||
export const LINK_KINDS = ['RELATED', 'SUCCESSOR', 'MERGED_INTO'] as const
|
||||
|
||||
export type LinkKindName = (typeof LINK_KINDS)[number]
|
||||
@@ -57,3 +72,44 @@ export type LinkKindName = (typeof LINK_KINDS)[number]
|
||||
export function isLinkKind(value: string): value is LinkKindName {
|
||||
return (LINK_KINDS as readonly string[]).includes(value)
|
||||
}
|
||||
|
||||
/**
|
||||
* Ein Beteiligter, wie ihn das Formular „Neue Fallakte" mitschickt.
|
||||
*
|
||||
* Je Zeile ein verstecktes Feld der Form `user:<id>|ROLLE` oder
|
||||
* `file:<id>|ROLLE`. Die Zerlegung steht hier und nicht in der Server Action,
|
||||
* damit sie prüfbar ist: sie entscheidet, wer mit welcher Rolle in eine Akte
|
||||
* kommt, und eine unbekannte Rolle darf nicht durchrutschen.
|
||||
*/
|
||||
export type ParticipantDraft =
|
||||
| { kind: 'user'; id: string; role: ParticipantRoleName }
|
||||
| { kind: 'file'; id: string; role: ParticipantRoleName }
|
||||
|
||||
/** So viele Beteiligte nimmt das Formular höchstens an. */
|
||||
export const MAX_PARTICIPANT_DRAFTS = 50
|
||||
|
||||
export function parseParticipantDrafts(werte: readonly unknown[]): ParticipantDraft[] {
|
||||
const gesehen = new Set<string>()
|
||||
const ergebnis: ParticipantDraft[] = []
|
||||
|
||||
for (const wert of werte) {
|
||||
if (typeof wert !== 'string') continue
|
||||
const [ziel, rolle] = wert.split('|')
|
||||
const [art, id] = (ziel ?? '').split(':')
|
||||
|
||||
if (art !== 'user' && art !== 'file') continue
|
||||
if (!id) continue
|
||||
if (!rolle || !isParticipantRole(rolle)) continue
|
||||
|
||||
// Dieselbe Person in derselben Rolle nur einmal. In einer anderen Rolle
|
||||
// darf sie durchaus zweimal stehen: Zeuge und Betroffener zugleich kommt vor.
|
||||
const schluessel = `${art}:${id}|${rolle}`
|
||||
if (gesehen.has(schluessel)) continue
|
||||
gesehen.add(schluessel)
|
||||
|
||||
ergebnis.push({ kind: art, id, role: rolle })
|
||||
if (ergebnis.length >= MAX_PARTICIPANT_DRAFTS) break
|
||||
}
|
||||
|
||||
return ergebnis
|
||||
}
|
||||
|
||||
@@ -58,6 +58,20 @@ export const caseText = {
|
||||
ARCHIVED: 'Archiviert',
|
||||
SEALED: 'Versiegelt',
|
||||
} as Record<string, string>,
|
||||
/**
|
||||
* Was die Zustände bedeuten. Sie stehen im Lebenszyklus in
|
||||
* docs/05-akten-und-vorlagen.md, standen aber nirgends in der Oberfläche —
|
||||
* und ein Filter, dessen Bezeichnung man nicht versteht, ist keiner.
|
||||
*/
|
||||
statusHints: {
|
||||
DRAFT: 'Angelegt, noch nicht in Bearbeitung. Wird erst mit dem Öffnen zur laufenden Akte.',
|
||||
OPEN: 'In Bearbeitung.',
|
||||
REVIEW: 'Der Sachstand liegt der Leitung zur Prüfung vor. Zurück in Bearbeitung oder abgeschlossen.',
|
||||
DORMANT: 'Vorübergehend liegen gelassen, etwa weil eine Auskunft aussteht. Jederzeit wieder zu öffnen.',
|
||||
CLOSED: 'Abgeschlossen. Wiedereröffnen geht, verlangt aber eine Begründung im Verlauf.',
|
||||
ARCHIVED: 'Abgelegt. Bleibt lesbar, wird aber nicht mehr bearbeitet.',
|
||||
SEALED: 'Versiegelt. Nur mit Stufe 5 oder dem Recht „admin" lesbar, aus jedem Zustand erreichbar.',
|
||||
} as Record<string, string>,
|
||||
} as const
|
||||
|
||||
export const sectionText = {
|
||||
|
||||
Reference in New Issue
Block a user