t-paliad-251. Four bundled concerns from m's 2026-05-25 reports, one
worker, one branch.
Part 1 — Event-type browse modal (search + filters)
- Modal already had a search input; added court-type filter chips
(UPC / EPA / DPMA / DE / Allgemein) under the search.
- Chips render only the jurisdictions actually present in the data;
any future flavour lands at the end of the row.
- Active chip uses the lime-tint chip palette already established by
the .event-type-collapsed* family (t-paliad-165).
- Search input keeps autofocus; chip + search filters intersect.
Part 2 — Type → Rule auto-fill + sort options
- Inverted the existing rule.concept_default_event_type_id mapping
client-side: given a chosen event_type X, candidate rules are
those with concept_default_event_type_id === X.
- Resolution picks (1) exact match on the project's
proceeding_type_id, (2) jurisdiction match on the rule's
proceeding (EPA→EPO canonicalised), (3) first candidate.
- Sort dropdown next to the Rule label: by proceeding sequence,
by court (jurisdiction grouping with optgroup), alphabetical.
Defaults to "by court"; localStorage-persisted per browser.
- All sorts are client-side over the existing /api/deadline-rules
payload — no new endpoint.
Part 3 — Auto rule mode + clearer override warning
- Auto badge (.form-hint--auto, lime-tint pill + " — <rule name>")
surfaces whenever the Rule was derived from the chosen Type.
Disappears the moment the user manually picks a different rule.
- Override warning names BOTH sides + the actually-applied rule:
"Typ ergibt Regel: X. Gewählte Regel: Y. Es wird Y angewendet."
- Symmetric `lastAutoFilledRuleID` sticky-replace flag mirrors the
existing `lastAutoFilledEventTypeID` (t-paliad-165) so the auto-
fill only replaces its own previous suggestion, never a manual
pick.
- Collapsed Typ view (t-paliad-165) is suppressed when the rule was
auto-derived from the type — the "vorgegeben durch Regel" copy
reads backwards in that case; show picker + Auto badge instead.
Part 4 — Standardtitel button (create + edit)
- Button rendered next to the Title field on both /deadlines/new
and /deadlines/{id} (edit mode only).
- Recipe (recipe-docs-here-so-future-templates-can-mirror-it):
head =
1. event_type label (if exactly one Typ chip is set)
2. rule code+name (when a Rule is set — "RoP.023 — Klageerwiderung")
3. proceeding type name from project (create form only)
4. fallback: t("deadlines.field.title.default_fallback")
suffix = " — <project.reference>" when ref is set and not
already in head.
Examples:
Klageerwiderung — C-UPC-0042 (type known)
RoP.023 — Klageerwiderung — REF (rule known, no type)
UPC — Verletzungsverfahren — REF (only proceeding type)
Neue Frist — REF (fallback)
- Click REPLACES current title; no destructive confirmation
because the user invoked it explicitly. Focus moves into the
title input afterwards so the user can fine-tune.
Build hygiene:
- go build + go vet + go test ./internal/... clean.
- frontend/build.ts clean (2786 keys, +10 new DE+EN, scan clean).
- All changes client-side / CSS / i18n + 2 small TSX edits; no
schema, no service, no migration.
Files touched:
- frontend/src/client/event-types.ts (browse-modal chips)
- frontend/src/client/deadlines-new.ts (rewrite — Type→Rule, sort,
Auto badge, override warn, Standardtitel)
- frontend/src/client/deadlines-detail.ts (edit-mode Standardtitel
+ show/hide on enter/exit edit)
- frontend/src/deadlines-new.tsx (label-row + sort dropdown + Auto
badge slot + override-warn slot + Standardtitel button)
- frontend/src/deadlines-detail.tsx (Standardtitel button)
- frontend/src/styles/global.css (.event-type-browse-chip*,
.form-hint--auto, .form-hint-badge, .form-field-label-row,
.btn-link-action, .rule-sort-select)
- frontend/src/client/i18n.ts (+10 keys DE+EN)
201 lines
10 KiB
TypeScript
201 lines
10 KiB
TypeScript
import { h } from "./jsx";
|
|
import { Sidebar } from "./components/Sidebar";
|
|
import { PaliadinWidget } from "./components/PaliadinWidget";
|
|
import { BottomNav } from "./components/BottomNav";
|
|
import { Footer } from "./components/Footer";
|
|
import { PWAHead } from "./components/PWAHead";
|
|
|
|
export function renderDeadlinesNew(): string {
|
|
return "<!DOCTYPE html>" + (
|
|
<html lang="de">
|
|
<head>
|
|
<meta charset="UTF-8" />
|
|
<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover" />
|
|
<meta name="theme-color" content="#BFF355" />
|
|
<meta name="apple-mobile-web-app-capable" content="yes" />
|
|
<meta name="apple-mobile-web-app-status-bar-style" content="default" />
|
|
<PWAHead />
|
|
<title data-i18n="deadlines.neu.title">Neue Frist — Paliad</title>
|
|
<link rel="stylesheet" href="/assets/global.css" />
|
|
</head>
|
|
<body className="has-sidebar">
|
|
<Sidebar currentPath="/events?type=deadline" />
|
|
<BottomNav currentPath="/events?type=deadline" />
|
|
|
|
<main>
|
|
<section className="tool-page">
|
|
<div className="container container-narrow">
|
|
<div className="tool-header">
|
|
<a href="/events?type=deadline" className="back-link" id="deadline-new-back" data-i18n="deadlines.neu.back">← Zurück zur Übersicht</a>
|
|
<h1 data-i18n="deadlines.neu.heading">Neue Frist anlegen</h1>
|
|
<p className="tool-subtitle" data-i18n="deadlines.neu.subtitle">
|
|
Eine persistente Frist an einer Akte. Sichtbar für alle Personen, die die Akte sehen können.
|
|
</p>
|
|
</div>
|
|
|
|
<form id="deadline-new-form" className="entity-form" autocomplete="off">
|
|
<div className="form-field">
|
|
<label htmlFor="deadline-project" data-i18n="deadlines.field.akte">Akte</label>
|
|
<select id="deadline-project" required>
|
|
<option value="" disabled selected data-i18n="deadlines.field.akte.choose">Bitte wählen…</option>
|
|
</select>
|
|
<p className="form-hint" id="deadline-project-empty-hint" style="display:none" data-i18n="deadlines.field.akte.empty">
|
|
Sie haben noch keine Akte. Bitte zuerst eine Akte anlegen.
|
|
</p>
|
|
</div>
|
|
|
|
<div className="form-field">
|
|
<div className="form-field-label-row">
|
|
<label htmlFor="deadline-title" data-i18n="deadlines.field.title">Titel</label>
|
|
{/* t-paliad-251 Part 4 — derive a Standardtitel from the
|
|
currently-known context (event type → rule → proceeding
|
|
type → fallback) with the project reference as suffix.
|
|
Always replaces the title; no destructive confirmation
|
|
because the user invoked it explicitly. */}
|
|
<button
|
|
type="button"
|
|
id="deadline-title-default-btn"
|
|
className="btn-link-action"
|
|
data-i18n="deadlines.field.title.default_btn"
|
|
>
|
|
Standardtitel
|
|
</button>
|
|
</div>
|
|
<input
|
|
type="text"
|
|
id="deadline-title"
|
|
required
|
|
placeholder="z.B. Klageerwiderung einreichen"
|
|
data-i18n-placeholder="deadlines.field.title.placeholder"
|
|
/>
|
|
</div>
|
|
|
|
<div className="form-field" id="deadline-event-type-field">
|
|
<label data-i18n="deadlines.field.event_type">Typ (optional)</label>
|
|
{/* t-paliad-165 follow-up — collapsed view: when a Regel
|
|
is selected and a default event_type is known, the
|
|
Typ chip is hidden and the type is rendered inline
|
|
as a single read-only summary with an "Anderen Typ
|
|
wählen" link that re-expands the picker. */}
|
|
<div
|
|
className="event-type-collapsed"
|
|
id="deadline-event-type-collapsed"
|
|
style="display:none"
|
|
>
|
|
<span
|
|
className="event-type-collapsed-label"
|
|
id="deadline-event-type-collapsed-label"
|
|
/>
|
|
<span
|
|
className="event-type-collapsed-source"
|
|
data-i18n="deadlines.field.rule.autofill_inline"
|
|
>
|
|
(vorgegeben durch Regel)
|
|
</span>
|
|
<button
|
|
type="button"
|
|
className="event-type-collapsed-override"
|
|
id="deadline-event-type-override-btn"
|
|
data-i18n="deadlines.field.rule.override"
|
|
>
|
|
Anderen Typ wählen
|
|
</button>
|
|
</div>
|
|
<div id="deadline-event-types" className="event-type-picker-host" />
|
|
{/* Soft warning when the user is in expanded mode AND
|
|
has picked an event_type that doesn't include the
|
|
rule's canonical default. Reuses the existing
|
|
yellow form-hint--warning style; never blocking. */}
|
|
<p
|
|
className="form-hint form-hint--warning"
|
|
id="deadline-event-type-rule-mismatch"
|
|
style="display:none"
|
|
data-i18n="deadlines.field.rule.mismatch"
|
|
>
|
|
Hinweis: Typ widerspricht Regel — Sie haben den Typ überschrieben.
|
|
</p>
|
|
</div>
|
|
|
|
{/* m/paliad#56 — Regel sits directly beneath the Typ
|
|
picker so the parent/child relationship reads at a
|
|
glance. Due date is its own row below. */}
|
|
<div className="form-field">
|
|
<div className="form-field-label-row">
|
|
<label htmlFor="deadline-rule" data-i18n="deadlines.field.rule">Regel (optional)</label>
|
|
{/* t-paliad-251 Part 2 — sort options for the Rule
|
|
select. Defaults to "by_court" so users in the
|
|
UPC bucket find UPC rules quickly. */}
|
|
<select id="deadline-rule-sort" className="rule-sort-select" aria-label="Sortierung">
|
|
<option value="by_proceeding" data-i18n="deadlines.field.rule.sort.by_proceeding">Nach Verfahrensablauf</option>
|
|
<option value="by_court" data-i18n="deadlines.field.rule.sort.by_court" selected>Nach Gerichtsart</option>
|
|
<option value="alpha" data-i18n="deadlines.field.rule.sort.alpha">Alphabetisch</option>
|
|
</select>
|
|
</div>
|
|
<select id="deadline-rule">
|
|
<option value="" data-i18n="deadlines.field.rule.none">Keine Regel</option>
|
|
</select>
|
|
{/* t-paliad-251 Part 3 — explicit Auto badge surfaces
|
|
whenever the Rule was auto-derived from the Typ.
|
|
Hidden when the user has manually picked a rule. */}
|
|
<p
|
|
className="form-hint form-hint--auto"
|
|
id="deadline-rule-auto-hint"
|
|
style="display:none"
|
|
>
|
|
<span
|
|
className="form-hint-badge"
|
|
data-i18n="deadlines.field.rule.auto_badge"
|
|
>Auto</span>
|
|
<span id="deadline-rule-auto-hint-text" />
|
|
</p>
|
|
{/* t-paliad-251 Part 3 — clearer override warning that
|
|
names BOTH the type-derived rule and the actually-
|
|
applied rule. Replaces the older Regel→Typ-only
|
|
mismatch warning when the contradiction goes the
|
|
other direction. */}
|
|
<p
|
|
className="form-hint form-hint--warning"
|
|
id="deadline-rule-override-warn"
|
|
style="display:none"
|
|
/>
|
|
</div>
|
|
|
|
<div className="form-field">
|
|
<label htmlFor="deadline-due" data-i18n="deadlines.field.due">Fälligkeitsdatum</label>
|
|
<input type="date" id="deadline-due" required />
|
|
</div>
|
|
|
|
<div className="form-field">
|
|
<label htmlFor="deadline-notes" data-i18n="deadlines.field.notes">Notizen (optional)</label>
|
|
<textarea id="deadline-notes" rows={3} placeholder="Hinweise, Verweise, nächste Schritte…" data-i18n-placeholder="deadlines.field.notes.placeholder" />
|
|
</div>
|
|
|
|
<p className="form-msg" id="deadline-new-msg" />
|
|
|
|
{/* t-paliad-154 — form-time 4-eye hint. Hidden by default;
|
|
revealed by client TS when an effective policy applies
|
|
to the chosen project. */}
|
|
<div className="approval-hint" id="deadline-approval-hint" style="display:none">
|
|
<span className="approval-hint-icon" dangerouslySetInnerHTML={{
|
|
__html: '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M12 22s8-4 8-10V5l-8-3-8 3v7c0 6 8 10 8 10z"/></svg>'
|
|
}} />
|
|
<span id="deadline-approval-hint-text" />
|
|
</div>
|
|
|
|
<div className="form-actions">
|
|
<a href="/events?type=deadline" id="deadline-new-cancel" className="btn-cancel" data-i18n="deadlines.neu.cancel">Abbrechen</a>
|
|
<button type="submit" className="btn-primary btn-cta-lime" data-i18n="deadlines.neu.submit">Frist anlegen</button>
|
|
</div>
|
|
</form>
|
|
</div>
|
|
</section>
|
|
</main>
|
|
|
|
<Footer />
|
|
<PaliadinWidget />
|
|
<script src="/assets/deadlines-new.js"></script>
|
|
</body>
|
|
</html>
|
|
);
|
|
}
|