m flagged 2026-05-27 20:26: archived rules (e.g. the 5 mig 152 Mängelbeseitigung clones) clutter the /admin/procedural-events default view. They were correctly archived by mig 152 but visually noisy alongside active rules. Fix: default activeLifecycle = 'published'. The 'Alle' chip still exists for when the user wants to see drafts + archived; 'Archived' chip surfaces them on demand. Initial view shows only the active corpus.
185 lines
9.9 KiB
TypeScript
185 lines
9.9 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";
|
|
|
|
// /admin/procedural-events — Slice 11b (t-paliad-192). Filterable rule table + an
|
|
// Orphans tab that surfaces the Slice 10 fuzzy-match staging rows so an
|
|
// admin can hand-bind each legacy deadline to one of the candidate
|
|
// rule_ids. Both surfaces share the same page shell to keep navigation
|
|
// shallow — the count badge on the Orphans tab is loaded eagerly on
|
|
// first paint so the editor sees the legal-review backlog every visit.
|
|
export function renderAdminRulesList(): 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="admin.procedural_events.list.title">Regeln verwalten — Paliad</title>
|
|
<link rel="stylesheet" href="/assets/global.css" />
|
|
</head>
|
|
<body className="has-sidebar">
|
|
<Sidebar currentPath="/admin/procedural-events" />
|
|
<BottomNav currentPath="/admin/procedural-events" />
|
|
|
|
<main>
|
|
<section className="tool-page">
|
|
<div className="container">
|
|
<div className="tool-header">
|
|
<div>
|
|
<h1 data-i18n="admin.procedural_events.list.heading">Regeln verwalten</h1>
|
|
<p className="tool-subtitle" data-i18n="admin.rules.list.subtitle">
|
|
Fristen-Regeln anlegen, bearbeiten und freigeben. Lifecycle: draft → published → archived.
|
|
</p>
|
|
</div>
|
|
<div className="admin-rules-header-actions">
|
|
<button type="button" id="rules-new-btn" className="btn-primary" data-i18n="admin.procedural_events.list.new">
|
|
+ Neue Regel
|
|
</button>
|
|
</div>
|
|
</div>
|
|
|
|
<div className="admin-rules-tabs">
|
|
<button type="button" className="admin-rules-tab active" id="rules-tab-rules" data-tab="rules" data-i18n="admin.rules.tab.rules">
|
|
Regeln
|
|
</button>
|
|
<button type="button" className="admin-rules-tab" id="rules-tab-orphans" data-tab="orphans">
|
|
<span data-i18n="admin.rules.tab.orphans">Orphans</span>
|
|
<span className="admin-rules-tab-badge" id="rules-orphans-badge" style="display:none">0</span>
|
|
</button>
|
|
</div>
|
|
|
|
<div id="rules-feedback" className="form-msg" style="display:none" />
|
|
|
|
{/* Rules tab */}
|
|
<div id="rules-pane-rules" className="admin-rules-pane">
|
|
<div className="admin-rules-filters">
|
|
<div className="admin-rules-filter">
|
|
<label htmlFor="rules-filter-proceeding" data-i18n="admin.rules.filter.proceeding">Verfahrenstyp</label>
|
|
<select id="rules-filter-proceeding" className="admin-rules-select">
|
|
<option value="" data-i18n="admin.rules.filter.proceeding.any">Alle</option>
|
|
</select>
|
|
</div>
|
|
|
|
<div className="admin-rules-filter">
|
|
<label htmlFor="rules-filter-trigger" data-i18n="admin.rules.filter.trigger">Trigger-Ereignis</label>
|
|
<select id="rules-filter-trigger" className="admin-rules-select">
|
|
<option value="" data-i18n="admin.rules.filter.trigger.any">Alle</option>
|
|
</select>
|
|
</div>
|
|
|
|
<div className="admin-rules-filter admin-rules-filter-chips">
|
|
<span className="admin-rules-filter-label" data-i18n="admin.rules.filter.lifecycle">Lifecycle</span>
|
|
<div className="admin-rules-chips" id="rules-filter-lifecycle">
|
|
<button type="button" className="admin-rules-chip" data-state="" data-i18n="admin.rules.filter.lifecycle.any">Alle</button>
|
|
<button type="button" className="admin-rules-chip" data-state="draft" data-i18n="admin.rules.lifecycle.draft">Draft</button>
|
|
<button type="button" className="admin-rules-chip active" data-state="published" data-i18n="admin.rules.lifecycle.published">Published</button>
|
|
<button type="button" className="admin-rules-chip" data-state="archived" data-i18n="admin.rules.lifecycle.archived">Archived</button>
|
|
</div>
|
|
</div>
|
|
|
|
<div className="admin-rules-filter admin-rules-filter-search">
|
|
<label htmlFor="rules-filter-search" data-i18n="admin.rules.filter.search">Suche</label>
|
|
<input
|
|
type="text"
|
|
id="rules-filter-search"
|
|
className="admin-rules-input"
|
|
placeholder="Name, Submission Code, Rechtsgrundlage..."
|
|
data-i18n-placeholder="admin.rules.filter.search.placeholder"
|
|
autocomplete="off"
|
|
/>
|
|
</div>
|
|
</div>
|
|
|
|
<div className="entity-table-wrap admin-rules-table-wrap">
|
|
<table className="entity-table admin-rules-table">
|
|
<thead>
|
|
<tr>
|
|
<th data-i18n="admin.procedural_events.col.code">Submission Code</th>
|
|
<th data-i18n="admin.procedural_events.col.proceeding">Verfahren</th>
|
|
<th data-i18n="admin.rules.col.legal_citation">Rechtsgrundlage</th>
|
|
<th data-i18n="admin.rules.col.name">Name</th>
|
|
<th data-i18n="admin.rules.col.priority">Priorität</th>
|
|
<th data-i18n="admin.rules.col.lifecycle">Lifecycle</th>
|
|
<th data-i18n="admin.rules.col.modified">Zuletzt geändert</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody id="rules-tbody">
|
|
<tr><td colspan={7} className="admin-rules-loading" data-i18n="admin.rules.loading">Lade...</td></tr>
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
|
|
<div className="entity-empty" id="rules-empty" style="display:none">
|
|
<p data-i18n="admin.rules.empty">Keine Regeln für die gewählten Filter.</p>
|
|
</div>
|
|
</div>
|
|
|
|
{/* Orphans tab */}
|
|
<div id="rules-pane-orphans" className="admin-rules-pane" style="display:none">
|
|
<p className="tool-subtitle" data-i18n="admin.rules.orphans.subtitle">
|
|
Legacy-Deadlines aus dem fuzzy-match Backfill (Slice 10), die nicht eindeutig einer Regel zugeordnet werden konnten. Bitte die richtige Kandidaten-Regel auswählen.
|
|
</p>
|
|
<div id="rules-orphans-list" className="admin-rules-orphans">
|
|
<p className="admin-rules-loading" data-i18n="admin.rules.orphans.loading">Lade...</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</section>
|
|
</main>
|
|
|
|
{/* Reason modal — reused for "+ Neue Regel" (creates a draft) and for
|
|
the orphan resolve flow. Both writes go through audit-reason
|
|
session config server-side, so the modal enforces the 10-char
|
|
minimum client-side per Slice 11a edge case #4. */}
|
|
<div className="modal-overlay" id="rules-reason-modal" style="display:none">
|
|
<div className="modal-card">
|
|
<div className="modal-header">
|
|
<h2 id="rules-reason-title" data-i18n="admin.rules.modal.new.title">Neue Regel anlegen</h2>
|
|
<button className="modal-close" id="rules-reason-close" type="button" aria-label="Close">×</button>
|
|
</div>
|
|
<p id="rules-reason-body" className="invite-modal-body" data-i18n="admin.rules.modal.new.body">
|
|
Eine neue Regel wird als Draft angelegt. Bitte einen Grund (mind. 10 Zeichen) angeben — dieser wandert ins Audit-Log und beim Export in die Migration.
|
|
</p>
|
|
<form id="rules-reason-form" className="entity-form" autocomplete="off">
|
|
<div id="rules-reason-extra" />
|
|
<div className="form-field">
|
|
<label htmlFor="rules-reason-text" data-i18n="admin.rules.modal.reason">Grund</label>
|
|
<textarea
|
|
id="rules-reason-text"
|
|
className="admin-rules-input"
|
|
rows={3}
|
|
required
|
|
minlength={10}
|
|
placeholder="z. B. „Neue Regel für RoP.198 nach UPC-Reform 2026..."
|
|
data-i18n-placeholder="admin.rules.modal.reason.placeholder"
|
|
/>
|
|
<p className="admin-rules-hint" data-i18n="admin.rules.modal.reason.hint">
|
|
Mindestens 10 Zeichen.
|
|
</p>
|
|
</div>
|
|
<p className="form-msg" id="rules-reason-msg" style="display:none" />
|
|
<div className="form-actions">
|
|
<button type="button" className="btn-cancel" id="rules-reason-cancel" data-i18n="common.cancel">Abbrechen</button>
|
|
<button type="submit" className="btn-primary" id="rules-reason-submit" data-i18n="admin.rules.modal.confirm">
|
|
Bestätigen
|
|
</button>
|
|
</div>
|
|
</form>
|
|
</div>
|
|
</div>
|
|
|
|
<Footer />
|
|
<PaliadinWidget />
|
|
<script src="/assets/admin-rules-list.js"></script>
|
|
</body>
|
|
</html>
|
|
);
|
|
}
|