fix(t-paliad-061): rename residue + small i18n cleanups (PR-D)
Per docs/audit-polish-2026-04-27.md PR-D batch:
- F-11 office labels on /projects/{id}/team — use t("office."+key) so
"duesseldorf"/"munich" render as "Düsseldorf"/"München"
- F-17 "Lead" → "Leitung" in DE on the Rolle column and /projects/new
subtitle (EN keeps "Lead")
- F-18 admin.team.permission.global_admin → "Globaler Admin" (DE) plus
matching "globaler Admin" in last_admin error
- F-19 rename DOM IDs: projekt-type → project-type, projekt-view →
project-view, akten-status → project-status (markup + all
getElementById/$ callsites in client modules)
- F-26 Akte filter dropdown on /deadlines + /appointments → "Projekt"
/ "Alle Projekte" in DE (column headers stay for PR-A/F-12)
- F-44 admin card "Departments / Dezernate" → "Dezernate"
- F-45 "Dezernat / Partner" → "Dezernat oder Partner" on settings +
onboarding profile fields
go build/vet/test clean; frontend bun run build clean.
This commit is contained in:
@@ -23,7 +23,7 @@ const PLANNED: PlannedCard[] = [
|
||||
icon: ICON_BUILDING,
|
||||
i18nTitle: "admin.card.departments.title",
|
||||
i18nDesc: "admin.card.departments.desc",
|
||||
fallbackTitle: "Departments / Dezernate",
|
||||
fallbackTitle: "Dezernate",
|
||||
fallbackDesc: "Dezernate anlegen und Mitglieder verwalten.",
|
||||
},
|
||||
{
|
||||
|
||||
@@ -72,9 +72,9 @@ export function renderAppointments(): string {
|
||||
<option value="deadline_hearing" data-i18n="termine.type.deadline_hearing">Fristverhandlung</option>
|
||||
</select>
|
||||
|
||||
<label className="akten-filter-label" htmlFor="appointment-filter-project" data-i18n="termine.filter.akte">Akte</label>
|
||||
<label className="akten-filter-label" htmlFor="appointment-filter-project" data-i18n="termine.filter.akte">Projekt</label>
|
||||
<select id="appointment-filter-project" className="akten-select">
|
||||
<option value="" data-i18n="termine.filter.akte.all">Alle Akten & persönlich</option>
|
||||
<option value="" data-i18n="termine.filter.akte.all">Alle Projekte & persönlich</option>
|
||||
<option value="__personal__" data-i18n="termine.filter.akte.personal">Nur persönliche</option>
|
||||
</select>
|
||||
|
||||
|
||||
@@ -526,14 +526,14 @@ const translations: Record<Lang, Record<string, string>> = {
|
||||
"fristen.summary.upcoming": "Sp\u00e4ter",
|
||||
"fristen.summary.completed": "Erledigt",
|
||||
"fristen.filter.status": "Status",
|
||||
"fristen.filter.akte": "Akte",
|
||||
"fristen.filter.akte": "Projekt",
|
||||
"fristen.filter.all": "Alle (offen & erledigt)",
|
||||
"fristen.filter.pending": "Alle offenen",
|
||||
"fristen.filter.overdue": "\u00dcberf\u00e4llig",
|
||||
"fristen.filter.thisweek": "Diese Woche",
|
||||
"fristen.filter.upcoming": "Sp\u00e4ter",
|
||||
"fristen.filter.completed": "Erledigt",
|
||||
"fristen.filter.akte.all": "Alle Akten",
|
||||
"fristen.filter.akte.all": "Alle Projekte",
|
||||
"fristen.col.due": "F\u00e4llig",
|
||||
"fristen.col.title": "Titel",
|
||||
"fristen.col.akte": "Akte",
|
||||
@@ -743,7 +743,7 @@ const translations: Record<Lang, Record<string, string>> = {
|
||||
"onboarding.office.placeholder": "Bitte ausw\u00e4hlen",
|
||||
"onboarding.job_title": "Berufsbezeichnung",
|
||||
"onboarding.job_title.placeholder": "z.B. Associate, Partner, PA",
|
||||
"onboarding.dezernat": "Dezernat / Partner",
|
||||
"onboarding.dezernat": "Dezernat oder Partner",
|
||||
"onboarding.dezernat.placeholder": "z.B. Dr. M\u00fcller, Team Schmidt",
|
||||
"onboarding.optional": "(optional)",
|
||||
"onboarding.submit": "Profil anlegen",
|
||||
@@ -866,7 +866,7 @@ const translations: Record<Lang, Record<string, string>> = {
|
||||
"projekte.submit": "Projekt anlegen",
|
||||
"projekte.neu.title": "Neues Projekt \u2014 Paliad",
|
||||
"projekte.neu.heading": "Neues Projekt anlegen",
|
||||
"projekte.neu.subtitle": "Mandant, Streitsache, Patent, Verfahren oder generisches Projekt \u2014 hierarchisch einordnen. Sichtbarkeit folgt dem Team (Sie werden als \u201eLead\u201c automatisch hinzugef\u00fcgt).",
|
||||
"projekte.neu.subtitle": "Mandant, Streitsache, Patent, Verfahren oder generisches Projekt \u2014 hierarchisch einordnen. Sichtbarkeit folgt dem Team (Sie werden als \u201eLeitung\u201c automatisch hinzugef\u00fcgt).",
|
||||
"projekte.field.type": "Typ",
|
||||
"projekte.field.parent": "\u00dcbergeordnetes Projekt",
|
||||
"projekte.field.parent.placeholder": "Titel eingeben, um ein \u00dcberprojekt zu suchen...",
|
||||
@@ -955,7 +955,7 @@ const translations: Record<Lang, Record<string, string>> = {
|
||||
"projekte.type.patent": "Patent",
|
||||
"projekte.type.case": "Verfahren",
|
||||
"projekte.type.project": "Projekt",
|
||||
"projekte.team.role.lead": "Lead",
|
||||
"projekte.team.role.lead": "Leitung",
|
||||
"projekte.team.role.associate": "Associate",
|
||||
"projekte.team.role.pa": "PA",
|
||||
"projekte.team.role.of_counsel": "Of Counsel",
|
||||
@@ -983,7 +983,7 @@ const translations: Record<Lang, Record<string, string>> = {
|
||||
"einstellungen.profil.office": "B\u00fcro",
|
||||
"einstellungen.profil.job_title": "Berufsbezeichnung",
|
||||
"einstellungen.profil.job_title.placeholder": "z.B. Associate, Partner, PA",
|
||||
"einstellungen.profil.dezernat": "Dezernat / Partner",
|
||||
"einstellungen.profil.dezernat": "Dezernat oder Partner",
|
||||
"einstellungen.profil.dezernat.placeholder": "z.B. Dr. M\u00fcller, Team Schmidt",
|
||||
"einstellungen.profil.lang": "Sprache",
|
||||
"einstellungen.profil.lang.de": "Deutsch",
|
||||
@@ -1029,8 +1029,8 @@ const translations: Record<Lang, Record<string, string>> = {
|
||||
"termine.summary.later": "Sp\u00e4ter",
|
||||
"termine.filter.type": "Typ",
|
||||
"termine.filter.type.all": "Alle Typen",
|
||||
"termine.filter.akte": "Akte",
|
||||
"termine.filter.akte.all": "Alle Akten & pers\u00f6nlich",
|
||||
"termine.filter.akte": "Projekt",
|
||||
"termine.filter.akte.all": "Alle Projekte & pers\u00f6nlich",
|
||||
"termine.filter.akte.personal": "Nur pers\u00f6nliche",
|
||||
"termine.filter.from": "Von",
|
||||
"termine.filter.to": "Bis",
|
||||
@@ -1196,7 +1196,7 @@ const translations: Record<Lang, Record<string, string>> = {
|
||||
"admin.coming_soon": "Kommt bald",
|
||||
"admin.card.team.title": "Team-Verwaltung",
|
||||
"admin.card.team.desc": "Benutzer:innen anlegen, bearbeiten, löschen.",
|
||||
"admin.card.departments.title": "Departments / Dezernate",
|
||||
"admin.card.departments.title": "Dezernate",
|
||||
"admin.card.departments.desc": "Dezernate anlegen und Mitglieder verwalten.",
|
||||
"admin.card.audit.title": "Audit-Log",
|
||||
"admin.card.audit.desc": "Wer hat wann was geändert? Nachvollziehbarkeit für sicherheitsrelevante Aktionen.",
|
||||
@@ -1241,8 +1241,8 @@ const translations: Record<Lang, Record<string, string>> = {
|
||||
"admin.team.direct_add.job_title": "Berufsbezeichnung",
|
||||
"admin.team.direct_add.dezernat": "Dezernat (optional)",
|
||||
"admin.team.permission.standard": "Standard",
|
||||
"admin.team.permission.global_admin": "Global Admin",
|
||||
"admin.team.permission.last_admin": "Der letzte Global Admin kann nicht degradiert werden.",
|
||||
"admin.team.permission.global_admin": "Globaler Admin",
|
||||
"admin.team.permission.last_admin": "Der letzte globale Admin kann nicht degradiert werden.",
|
||||
"admin.team.direct_add.cancel": "Abbrechen",
|
||||
"admin.team.direct_add.submit": "Anlegen",
|
||||
|
||||
@@ -2435,7 +2435,7 @@ const translations: Record<Lang, Record<string, string>> = {
|
||||
"admin.coming_soon": "Coming soon",
|
||||
"admin.card.team.title": "Team Management",
|
||||
"admin.card.team.desc": "Create, edit and delete user accounts.",
|
||||
"admin.card.departments.title": "Departments / Dezernate",
|
||||
"admin.card.departments.title": "Dezernate",
|
||||
"admin.card.departments.desc": "Create departments and manage their members.",
|
||||
"admin.card.audit.title": "Audit Log",
|
||||
"admin.card.audit.desc": "Who changed what, and when. Traceability for security-relevant actions.",
|
||||
|
||||
@@ -110,10 +110,10 @@ export function initParentPicker() {
|
||||
});
|
||||
}
|
||||
|
||||
// wireTypeChange wires the <select id="projekt-type"> change handler and runs
|
||||
// wireTypeChange wires the <select id="project-type"> change handler and runs
|
||||
// the visibility pass once with the current value.
|
||||
export function wireTypeChange() {
|
||||
const typeSel = $("projekt-type") as HTMLSelectElement;
|
||||
const typeSel = $("project-type") as HTMLSelectElement;
|
||||
showFieldsForType(typeSel.value);
|
||||
typeSel.addEventListener("change", () => showFieldsForType(typeSel.value));
|
||||
}
|
||||
@@ -131,7 +131,7 @@ export function readPayload(
|
||||
msg: HTMLElement,
|
||||
opts: { omitEmpty: boolean; mode: "create" | "edit" },
|
||||
): Record<string, unknown> | null {
|
||||
const type = ($("projekt-type") as HTMLSelectElement).value;
|
||||
const type = ($("project-type") as HTMLSelectElement).value;
|
||||
const title = ($("project-title") as HTMLInputElement).value.trim();
|
||||
if (!title) {
|
||||
msg.textContent = t("projekte.error.title_required") || "Title required";
|
||||
@@ -198,7 +198,7 @@ export function prefillForm(p: Record<string, unknown>) {
|
||||
const getTA = (id: string) => $(id) as HTMLTextAreaElement;
|
||||
|
||||
const type = String(p.type ?? "project");
|
||||
getSel("projekt-type").value = type;
|
||||
getSel("project-type").value = type;
|
||||
showFieldsForType(type);
|
||||
|
||||
get("project-title").value = String(p.title ?? "");
|
||||
|
||||
@@ -774,7 +774,7 @@ function openEditModal() {
|
||||
// Type changes are allowed (t-paliad-056). Wire the warning that lists
|
||||
// which fields will be NULL'd server-side when the user picks a new
|
||||
// type.
|
||||
const typeSel = document.getElementById("projekt-type") as HTMLSelectElement | null;
|
||||
const typeSel = document.getElementById("project-type") as HTMLSelectElement | null;
|
||||
if (typeSel) {
|
||||
typeSel.disabled = false;
|
||||
typeSel.onchange = () => {
|
||||
@@ -817,7 +817,7 @@ const TYPE_SPECIFIC_FIELDS: Record<string, { key: string; i18n: string }[]> = {
|
||||
function renderTypeChangeWarning() {
|
||||
const wrap = document.getElementById("project-edit-type-warning") as HTMLDivElement | null;
|
||||
const fieldsSpan = document.getElementById("project-edit-type-warning-fields") as HTMLSpanElement | null;
|
||||
const typeSel = document.getElementById("projekt-type") as HTMLSelectElement | null;
|
||||
const typeSel = document.getElementById("project-type") as HTMLSelectElement | null;
|
||||
if (!wrap || !fieldsSpan || !typeSel || !project) return;
|
||||
|
||||
const newType = typeSel.value;
|
||||
@@ -1238,9 +1238,10 @@ function renderTeam() {
|
||||
!m.inherited && canRemoveTeamMember(m)
|
||||
? `<button type="button" class="btn-ghost btn-small team-remove-btn" data-user-id="${esc(m.user_id)}">${esc(t("projekte.detail.team.remove") || "Entfernen")}</button>`
|
||||
: "";
|
||||
const officeLabel = m.user_office ? t("office." + m.user_office) || m.user_office : "";
|
||||
return `<tr>
|
||||
<td><strong>${esc(m.user_display_name || m.user_email)}</strong>
|
||||
<span class="form-hint">· ${esc(m.user_email)}${m.user_office ? " · " + esc(m.user_office) : ""}</span></td>
|
||||
<span class="form-hint">· ${esc(m.user_email)}${officeLabel ? " · " + esc(officeLabel) : ""}</span></td>
|
||||
<td><span class="projekt-team-role">${esc(roleLabel)}</span></td>
|
||||
<td>${source}</td>
|
||||
<td>${removeBtn}</td>
|
||||
|
||||
@@ -60,7 +60,7 @@ async function applyParentFromQueryString() {
|
||||
($("projekt-parent-id") as HTMLInputElement).value = p.id;
|
||||
($("projekt-parent-input") as HTMLInputElement).value = p.title;
|
||||
// Default to 'case' under a non-root parent; user can override.
|
||||
const typeSel = $("projekt-type") as HTMLSelectElement;
|
||||
const typeSel = $("project-type") as HTMLSelectElement;
|
||||
if (typeSel.value === "client") {
|
||||
typeSel.value = "case";
|
||||
showFieldsForType(typeSel.value);
|
||||
|
||||
@@ -176,9 +176,9 @@ function initSearch() {
|
||||
}
|
||||
|
||||
function initFilters() {
|
||||
const typeSel = document.getElementById("projekt-type") as HTMLSelectElement;
|
||||
const status = document.getElementById("akten-status") as HTMLSelectElement;
|
||||
const view = document.getElementById("projekt-view") as HTMLSelectElement;
|
||||
const typeSel = document.getElementById("project-type") as HTMLSelectElement;
|
||||
const status = document.getElementById("project-status") as HTMLSelectElement;
|
||||
const view = document.getElementById("project-view") as HTMLSelectElement;
|
||||
typeSel.addEventListener("change", () => {
|
||||
typeFilter = typeSel.value;
|
||||
render();
|
||||
|
||||
@@ -13,8 +13,8 @@ export function ProjectFormFields(): string {
|
||||
return (
|
||||
<div className="project-form-fields">
|
||||
<div className="form-field">
|
||||
<label htmlFor="projekt-type" data-i18n="projekte.field.type">Typ</label>
|
||||
<select id="projekt-type" required>
|
||||
<label htmlFor="project-type" data-i18n="projekte.field.type">Typ</label>
|
||||
<select id="project-type" required>
|
||||
<option value="client" data-i18n="projekte.type.client">Mandant (Wurzel)</option>
|
||||
<option value="litigation" data-i18n="projekte.type.litigation">Streitsache</option>
|
||||
<option value="patent" data-i18n="projekte.type.patent">Patent</option>
|
||||
|
||||
@@ -78,9 +78,9 @@ export function renderDeadlines(): string {
|
||||
<option value="completed" data-i18n="fristen.filter.completed">Erledigt</option>
|
||||
</select>
|
||||
|
||||
<label className="akten-filter-label" htmlFor="deadline-filter-project" data-i18n="fristen.filter.akte">Akte</label>
|
||||
<label className="akten-filter-label" htmlFor="deadline-filter-project" data-i18n="fristen.filter.akte">Projekt</label>
|
||||
<select id="deadline-filter-project" className="akten-select">
|
||||
<option value="" data-i18n="fristen.filter.akte.all">Alle Akten</option>
|
||||
<option value="" data-i18n="fristen.filter.akte.all">Alle Projekte</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -58,8 +58,8 @@ export function renderProjects(): string {
|
||||
</div>
|
||||
|
||||
<div className="akten-filter-row">
|
||||
<label className="akten-filter-label" htmlFor="projekt-type" data-i18n="projekte.filter.type">Typ</label>
|
||||
<select id="projekt-type" className="akten-select">
|
||||
<label className="akten-filter-label" htmlFor="project-type" data-i18n="projekte.filter.type">Typ</label>
|
||||
<select id="project-type" className="akten-select">
|
||||
<option value="" data-i18n="projekte.filter.type.all">Alle Typen</option>
|
||||
<option value="client" data-i18n="projekte.type.client">Mandant</option>
|
||||
<option value="litigation" data-i18n="projekte.type.litigation">Streitsache</option>
|
||||
@@ -68,16 +68,16 @@ export function renderProjects(): string {
|
||||
<option value="project" data-i18n="projekte.type.project">Projekt</option>
|
||||
</select>
|
||||
|
||||
<label className="akten-filter-label" htmlFor="akten-status" data-i18n="projekte.filter.status">Status</label>
|
||||
<select id="akten-status" className="akten-select">
|
||||
<label className="akten-filter-label" htmlFor="project-status" data-i18n="projekte.filter.status">Status</label>
|
||||
<select id="project-status" className="akten-select">
|
||||
<option value="" data-i18n="projekte.filter.status.all">Alle Status</option>
|
||||
<option value="active" data-i18n="projekte.filter.status.active">Aktiv</option>
|
||||
<option value="archived" data-i18n="projekte.filter.status.archived">Archiviert</option>
|
||||
<option value="closed" data-i18n="projekte.filter.status.closed">Abgeschlossen</option>
|
||||
</select>
|
||||
|
||||
<label className="akten-filter-label" htmlFor="projekt-view" data-i18n="projekte.filter.view">Ansicht</label>
|
||||
<select id="projekt-view" className="akten-select">
|
||||
<label className="akten-filter-label" htmlFor="project-view" data-i18n="projekte.filter.view">Ansicht</label>
|
||||
<select id="project-view" className="akten-select">
|
||||
<option value="flat" data-i18n="projekte.view.flat">Flache Liste</option>
|
||||
<option value="tree" data-i18n="projekte.view.tree">Baumansicht</option>
|
||||
<option value="roots" data-i18n="projekte.view.roots">Nur Wurzeln</option>
|
||||
|
||||
@@ -102,7 +102,7 @@ export function renderSettings(): string {
|
||||
|
||||
<div className="form-field">
|
||||
<label htmlFor="profil-dezernat" data-i18n="einstellungen.profil.dezernat">
|
||||
Dezernat / Partner <span className="login-label-optional" data-i18n="einstellungen.optional">(optional)</span>
|
||||
Dezernat oder Partner <span className="login-label-optional" data-i18n="einstellungen.optional">(optional)</span>
|
||||
</label>
|
||||
<input
|
||||
type="text"
|
||||
|
||||
Reference in New Issue
Block a user