m/paliad#76. The export button no longer pokes out of the tabs nav with a non-tab styling — instead it lives inside a new "Verwaltung" tab (last in the project tab list) as a normal section with heading, description, and a plain btn-secondary trigger. Same gate as before (canExportProject). Archive co-locates in the same tab as a pointer to the Edit-modal danger zone: click "Bearbeiten öffnen" → modal opens scrolled to the archive button. Single source of truth for the destructive action stays in the modal; the Verwaltung pointer just gives it discoverability. If neither sub-section is visible to the caller (no export entitlement, not global_admin), the Verwaltung tab hides itself — an empty tab is worse UX than no tab.
779 lines
48 KiB
TypeScript
779 lines
48 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";
|
|
import { ProjectFormFields } from "./components/ProjectFormFields";
|
|
|
|
// Project detail shell (v2). DOM IDs use the English `project-*` /
|
|
// `parties-*` / `deadlines-*` / `appointments-*` / `notes-*` / `checklists-*`
|
|
// naming. The client TS in client/projects-detail.ts queries these IDs in
|
|
// lockstep — keep names in sync.
|
|
export function renderProjectsDetail(): 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="projects.detail.title">Projekt — Paliad</title>
|
|
<link rel="stylesheet" href="/assets/global.css" />
|
|
</head>
|
|
<body className="has-sidebar">
|
|
<Sidebar currentPath="/projects" />
|
|
<BottomNav currentPath="/projects" />
|
|
|
|
<main>
|
|
<section className="tool-page">
|
|
<div className="container">
|
|
<a href="/projects" className="back-link" data-i18n="projects.detail.back">← Zurück zur Übersicht</a>
|
|
|
|
<nav className="projekt-breadcrumb" id="project-breadcrumb" aria-label="Breadcrumb" />
|
|
|
|
<div id="project-detail-loading" className="entity-loading">
|
|
<p data-i18n="projects.detail.loading">Lädt…</p>
|
|
</div>
|
|
|
|
<div id="project-detail-notfound" className="entity-empty" style="display:none">
|
|
<p data-i18n="projects.detail.notfound">Projekt nicht gefunden oder keine Berechtigung.</p>
|
|
</div>
|
|
|
|
<div id="project-detail-body" style="display:none">
|
|
<header className="entity-detail-header">
|
|
<div className="entity-detail-title-row">
|
|
<div className="entity-detail-title-col">
|
|
<h1 id="project-title-display" />
|
|
<div className="entity-detail-meta">
|
|
<span id="project-type-chip" className="entity-type-chip" />
|
|
<span className="entity-ref" id="project-ref-display" />
|
|
{/* Auto-derived project code (t-paliad-222 / m/paliad#50).
|
|
Rendered as a separate badge so the user can still
|
|
distinguish a custom reference (left badge) from a
|
|
tree-derived code (right badge); when reference is
|
|
blank, the derived code IS reference and only this
|
|
badge shows. Hidden via inline style until the
|
|
client populates it. */}
|
|
<span className="entity-ref entity-ref-code" id="project-code-display" style="display:none" title="Auto-derived project code" />
|
|
<span id="project-clientmatter" className="entity-ref" />
|
|
<span id="project-status-chip" className="entity-status-chip" />
|
|
<a id="project-netdocs" className="netdocs-link" target="_blank" rel="noopener" style="display:none">netDocuments ↗</a>
|
|
</div>
|
|
</div>
|
|
<div className="entity-detail-actions">
|
|
<button id="project-edit-btn" className="btn-icon" type="button" aria-label="Bearbeiten" data-i18n-title="projects.detail.edit" title="Bearbeiten">
|
|
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
|
<path d="M11 4H4a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2v-7" />
|
|
<path d="M18.5 2.5a2.121 2.121 0 0 1 3 3L12 15l-4 1 1-4 9.5-9.5z" />
|
|
</svg>
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</header>
|
|
|
|
<div className="entity-detail-description" id="project-description-wrap">
|
|
<h3 data-i18n="projects.detail.description.heading">Notizen</h3>
|
|
<p id="project-description-display" className="entity-detail-description-text" />
|
|
</div>
|
|
|
|
<nav className="entity-tabs" id="project-tabs">
|
|
<a className="entity-tab" data-tab="history" href="#" data-i18n="projects.detail.tab.verlauf">Verlauf</a>
|
|
<a className="entity-tab" data-tab="team" href="#" data-i18n="projects.detail.tab.team">Team</a>
|
|
<a className="entity-tab" data-tab="children" href="#" data-i18n="projects.detail.tab.kinder">Projektbaum</a>
|
|
<a className="entity-tab" data-tab="parties" href="#" data-i18n="projects.detail.tab.parteien">Parteien</a>
|
|
<a className="entity-tab" data-tab="deadlines" href="#" data-i18n="projects.detail.tab.fristen">Fristen</a>
|
|
<a className="entity-tab" data-tab="appointments" href="#" data-i18n="projects.detail.tab.termine">Termine</a>
|
|
<a className="entity-tab" data-tab="notes" href="#" data-i18n="projects.detail.tab.notizen">Notizen</a>
|
|
<a className="entity-tab" data-tab="checklists" href="#" data-i18n="projects.detail.tab.checklisten">Checklisten</a>
|
|
<a className="entity-tab" data-tab="submissions" href="#" data-i18n="projects.detail.tab.submissions">Schriftsätze</a>
|
|
{/* Verwaltung — rare admin actions (export, archive). Sits
|
|
last in the tab list per t-paliad-245. */}
|
|
<a className="entity-tab" data-tab="settings" href="#" data-i18n="projects.detail.tab.settings">Verwaltung</a>
|
|
</nav>
|
|
|
|
{/* History (Verlauf) — t-paliad-171 SmartTimeline Slice 1.
|
|
The legacy <ul.entity-events> + Mehr-laden controls are
|
|
replaced by the vertical timeline (rendered by
|
|
client/views/shape-timeline.ts). The bar from t-paliad-170
|
|
keeps driving filter state via its customRunner. */}
|
|
<section className="entity-tab-panel" id="tab-history">
|
|
<div className="smart-timeline-controls">
|
|
<button type="button" className="btn-secondary btn-small subtree-toggle" aria-pressed="false">
|
|
Inkl. Unterprojekte
|
|
</button>
|
|
<button type="button" className="btn-secondary btn-small" id="smart-timeline-audit-toggle" aria-pressed="false" data-i18n="projects.detail.smarttimeline.audit.toggle.show">
|
|
Audit-Log anzeigen
|
|
</button>
|
|
{/* Slice 4 — Client-level Timeline-Ansicht toggle.
|
|
Hidden by default (display:none); the client TS
|
|
flips it visible only when project.type === 'client'. */}
|
|
<button type="button" className="btn-secondary btn-small" id="smart-timeline-client-toggle" aria-pressed="false" style="display:none" data-i18n="projects.detail.smarttimeline.client.toggle.lanes">
|
|
Timeline-Ansicht
|
|
</button>
|
|
<button type="button" className="btn-primary btn-cta-lime btn-small" id="smart-timeline-add-btn" data-i18n="projects.detail.smarttimeline.add.cta">
|
|
+ Eintrag
|
|
</button>
|
|
{/* t-paliad-177 — link to the standalone /chart page.
|
|
Opens in a new tab per design §8.1; the Verlauf
|
|
embed itself stays vertical-DOM-only. */}
|
|
<a
|
|
id="smart-timeline-open-chart"
|
|
className="btn-secondary btn-small"
|
|
href="#"
|
|
target="_blank"
|
|
rel="noopener"
|
|
data-i18n="projects.detail.smarttimeline.open_chart"
|
|
>
|
|
Als Chart anzeigen ↗
|
|
</a>
|
|
</div>
|
|
<div id="project-events-filter-bar" />
|
|
<div id="project-smart-timeline" className="smart-timeline" />
|
|
|
|
{/* "Eigener Meilenstein" modal. Hidden by default; opened
|
|
by the "+ Eintrag" CTA above. The other modal options
|
|
route to existing flows (see client wiring). */}
|
|
<div id="smart-timeline-add-modal" className="smart-timeline-modal" style="display:none" role="dialog" aria-modal="true">
|
|
<div className="smart-timeline-modal-card">
|
|
<h3 data-i18n="projects.detail.smarttimeline.add.modal.title">
|
|
Neuer Eintrag im SmartTimeline
|
|
</h3>
|
|
|
|
<div className="smart-timeline-add-choices">
|
|
<a id="smart-timeline-add-deadline" className="smart-timeline-add-choice" href="#" data-i18n="projects.detail.smarttimeline.add.choice.deadline">
|
|
Frist anlegen
|
|
</a>
|
|
<a id="smart-timeline-add-appointment" className="smart-timeline-add-choice" href="#" data-i18n="projects.detail.smarttimeline.add.choice.appointment">
|
|
Termin anlegen
|
|
</a>
|
|
<button type="button" id="smart-timeline-add-counterclaim" className="smart-timeline-add-choice" data-i18n="projects.detail.smarttimeline.add.choice.counterclaim">
|
|
Widerklage (CCR)
|
|
</button>
|
|
<button type="button" className="smart-timeline-add-choice smart-timeline-add-choice--disabled" disabled title="Slice 3" data-i18n="projects.detail.smarttimeline.add.choice.amend">
|
|
Antrag auf Änderung (R.30)
|
|
</button>
|
|
<button type="button" id="smart-timeline-add-milestone" className="smart-timeline-add-choice smart-timeline-add-choice--primary" data-i18n="projects.detail.smarttimeline.add.choice.milestone">
|
|
Eigener Meilenstein
|
|
</button>
|
|
</div>
|
|
|
|
<form id="smart-timeline-milestone-form" className="entity-form" style="display:none" autocomplete="off">
|
|
<div className="form-field">
|
|
<label htmlFor="smart-timeline-milestone-title" data-i18n="projects.detail.smarttimeline.milestone.title">Titel</label>
|
|
<input type="text" id="smart-timeline-milestone-title" required maxLength={200} />
|
|
</div>
|
|
<div className="form-field">
|
|
<label htmlFor="smart-timeline-milestone-date" data-i18n="projects.detail.smarttimeline.milestone.date">Datum (optional)</label>
|
|
<input type="date" id="smart-timeline-milestone-date" />
|
|
</div>
|
|
<div className="form-field">
|
|
<label htmlFor="smart-timeline-milestone-desc" data-i18n="projects.detail.smarttimeline.milestone.description">Beschreibung (optional)</label>
|
|
<textarea id="smart-timeline-milestone-desc" rows={3} />
|
|
</div>
|
|
{/* Slice 4 — bubble-up override (t-paliad-175 §7.2 Q5). */}
|
|
<div className="form-field form-field--checkbox">
|
|
<label className="form-checkbox">
|
|
<input type="checkbox" id="smart-timeline-milestone-bubble-up" />
|
|
<span data-i18n="projects.detail.smarttimeline.milestone.bubble_up">In übergeordneten Akten anzeigen</span>
|
|
</label>
|
|
<small className="form-field-hint" data-i18n="projects.detail.smarttimeline.milestone.bubble_up_hint">
|
|
Beim Aktivieren erscheint dieser Meilenstein auf Patent-, Verfahrens- und Mandantsicht.
|
|
</small>
|
|
</div>
|
|
<div id="smart-timeline-milestone-msg" className="form-msg" />
|
|
<div className="form-field-row">
|
|
<button type="button" className="btn-secondary" id="smart-timeline-milestone-cancel" data-i18n="projects.detail.smarttimeline.add.cancel">Abbrechen</button>
|
|
<button type="submit" className="btn-primary btn-cta-lime" data-i18n="projects.detail.smarttimeline.add.submit">Speichern</button>
|
|
</div>
|
|
</form>
|
|
|
|
{/* CCR sub-project create form (Slice 3, t-paliad-174). The
|
|
proceeding-type select is populated by the client at
|
|
runtime; our_side defaults to inverted with a
|
|
"Stimmt nicht?" override toggle for the R.49.2.b
|
|
edge case. Title is auto-suggested server-side and
|
|
can be overridden inline. */}
|
|
<form id="smart-timeline-counterclaim-form" className="entity-form" style="display:none" autocomplete="off">
|
|
<div className="form-field">
|
|
<label htmlFor="smart-timeline-counterclaim-procedure" data-i18n="projects.detail.smarttimeline.counterclaim.procedure">Verfahrenstyp</label>
|
|
<select id="smart-timeline-counterclaim-procedure">
|
|
{/* Options injected from client; defaults to upc.rev.cfi */}
|
|
</select>
|
|
</div>
|
|
<div className="form-field">
|
|
<label htmlFor="smart-timeline-counterclaim-title" data-i18n="projects.detail.smarttimeline.counterclaim.title">Titel (optional)</label>
|
|
<input type="text" id="smart-timeline-counterclaim-title" maxLength={200} placeholder="Auto-Vorschlag aus Patentnummer" />
|
|
</div>
|
|
<div className="form-field">
|
|
<label htmlFor="smart-timeline-counterclaim-case-number" data-i18n="projects.detail.smarttimeline.counterclaim.case_number">CCR-Aktenzeichen (optional)</label>
|
|
<input type="text" id="smart-timeline-counterclaim-case-number" maxLength={200} placeholder="ACT_xxx_2026" />
|
|
</div>
|
|
<div className="form-field form-field--checkbox">
|
|
<label className="form-checkbox">
|
|
<input type="checkbox" id="smart-timeline-counterclaim-flip-toggle" />
|
|
<span data-i18n="projects.detail.smarttimeline.counterclaim.flip_override">Unsere Seite NICHT umkehren (Stimmt nicht?)</span>
|
|
</label>
|
|
<small className="form-field-hint" data-i18n="projects.detail.smarttimeline.counterclaim.flip_hint">
|
|
Im Standardfall (CCR-Nichtigkeit) kehrt sich unsere Seite um (Kläger ↔ Beklagter). Aktivieren bei R.49.2.b CCI.
|
|
</small>
|
|
</div>
|
|
<div id="smart-timeline-counterclaim-msg" className="form-msg" />
|
|
<div className="form-field-row">
|
|
<button type="button" className="btn-secondary" id="smart-timeline-counterclaim-cancel" data-i18n="projects.detail.smarttimeline.add.cancel">Abbrechen</button>
|
|
<button type="submit" className="btn-primary btn-cta-lime" data-i18n="projects.detail.smarttimeline.counterclaim.submit">Widerklage anlegen</button>
|
|
</div>
|
|
</form>
|
|
|
|
<div className="smart-timeline-modal-close-row">
|
|
<button type="button" className="btn-secondary btn-small" id="smart-timeline-modal-close" data-i18n="projects.detail.smarttimeline.add.cancel">
|
|
Abbrechen
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</section>
|
|
|
|
{/* Team */}
|
|
<section className="entity-tab-panel" id="tab-team" style="display:none">
|
|
<div className="party-controls">
|
|
<button id="team-add-btn" className="btn-primary btn-cta-lime btn-small" type="button" data-i18n="projects.detail.team.add">
|
|
Mitglied hinzufügen
|
|
</button>
|
|
</div>
|
|
|
|
<form id="team-form" className="entity-form party-form" style="display:none" autocomplete="off">
|
|
<div className="form-field-row">
|
|
<div className="form-field">
|
|
<label htmlFor="team-user-input" data-i18n="projects.detail.team.form.user">Benutzer</label>
|
|
<input type="text" id="team-user-input" placeholder="Name oder E-Mail..." autocomplete="off" />
|
|
<input type="hidden" id="team-user-id" />
|
|
<div id="team-user-suggestions" className="collab-suggestions" />
|
|
<div id="team-user-invite-hint" className="collab-invite-hint" style="display:none">
|
|
<span id="team-user-invite-hint-text" data-i18n="projects.detail.team.invite.hint">Benutzer nicht gefunden?</span>
|
|
<button type="button" className="btn-secondary btn-small" id="team-user-invite-btn" data-i18n="projects.detail.team.invite.cta">Einladen</button>
|
|
</div>
|
|
</div>
|
|
<div className="form-field">
|
|
<label htmlFor="team-responsibility" data-i18n="projects.detail.team.form.responsibility">Rolle im Projekt</label>
|
|
<select id="team-responsibility">
|
|
<option value="admin" data-i18n="projects.team.responsibility.admin">Admin</option>
|
|
<option value="lead" data-i18n="projects.team.responsibility.lead">Lead</option>
|
|
<option value="member" selected data-i18n="projects.team.responsibility.member">Mitglied</option>
|
|
<option value="observer" data-i18n="projects.team.responsibility.observer">Beobachter</option>
|
|
<option value="external" data-i18n="projects.team.responsibility.external">Extern</option>
|
|
</select>
|
|
<p id="team-profession-hint" className="form-hint" style="display:none" />
|
|
</div>
|
|
</div>
|
|
<div className="form-actions">
|
|
<button type="button" className="btn-cancel" id="team-cancel" data-i18n="projects.detail.team.form.cancel">Abbrechen</button>
|
|
<button type="submit" className="btn-primary btn-cta-lime" data-i18n="projects.detail.team.form.submit">Hinzufügen</button>
|
|
</div>
|
|
<p className="form-msg" id="team-msg" />
|
|
</form>
|
|
|
|
{/* t-paliad-231 — pure-client mailto: for non-admins.
|
|
Button stays disabled until at least one row is
|
|
selected; click opens a mailto: with every selected
|
|
member in the To: line. No server call. */}
|
|
<div className="party-controls team-mailto-controls" id="team-mailto-controls" style="display:none">
|
|
<button
|
|
type="button"
|
|
id="team-mailto-btn"
|
|
className="btn-secondary btn-small"
|
|
disabled
|
|
data-i18n-title="projects.team.mailto.empty"
|
|
title="Mindestens ein Mitglied auswählen"
|
|
>
|
|
<span id="team-mailto-label" data-i18n="projects.team.mailto.label">Mail an Auswahl</span>
|
|
</button>
|
|
</div>
|
|
|
|
<table className="party-table">
|
|
<thead>
|
|
<tr>
|
|
<th className="team-col-select">
|
|
<input
|
|
type="checkbox"
|
|
id="team-select-master"
|
|
aria-label="Alle sichtbaren auswählen"
|
|
/>
|
|
</th>
|
|
<th data-i18n="projects.detail.team.col.name">Name</th>
|
|
<th data-i18n="projects.detail.team.col.profession">Profession</th>
|
|
<th data-i18n="projects.detail.team.col.responsibility">Rolle</th>
|
|
<th data-i18n="projects.detail.team.col.source">Herkunft</th>
|
|
<th />
|
|
</tr>
|
|
</thead>
|
|
<tbody id="team-body" />
|
|
</table>
|
|
|
|
<p className="entity-events-empty" id="team-empty" style="display:none" data-i18n="projects.detail.team.empty">
|
|
Noch keine Teammitglieder.
|
|
</p>
|
|
|
|
{/* t-paliad-139 — Aus Unterprojekten subsection. */}
|
|
<div id="team-section-descendants" style="display:none">
|
|
<h3 className="entity-section-heading" data-i18n="projects.team.section.from_descendants">
|
|
Aus Unterprojekten
|
|
</h3>
|
|
<p className="form-hint" data-i18n="projects.team.section.from_descendants.hint">
|
|
Personen, die direkt auf einem Unterprojekt eingetragen sind und nicht auf diesem oder einem Übergeordneten.
|
|
</p>
|
|
<table className="party-table">
|
|
<thead>
|
|
<tr>
|
|
<th data-i18n="projects.detail.team.col.name">Name</th>
|
|
<th data-i18n="projects.detail.team.col.role">Rolle</th>
|
|
<th data-i18n="projects.detail.team.col.source">Herkunft</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody id="team-descendants-body" />
|
|
</table>
|
|
</div>
|
|
|
|
{/* t-paliad-139 — Abgeleitet (Partner Unit) subsection. */}
|
|
<div id="team-section-derived" style="display:none">
|
|
<h3 className="entity-section-heading" data-i18n="projects.team.section.derived">
|
|
Abgeleitet (Partner Unit)
|
|
</h3>
|
|
<p className="form-hint" data-i18n="projects.team.section.derived.hint">
|
|
Mitglieder, die über eine zugeordnete Partner Unit auf diesem Projekt aktiv sind.
|
|
</p>
|
|
<table className="party-table">
|
|
<thead>
|
|
<tr>
|
|
<th data-i18n="projects.detail.team.col.name">Name</th>
|
|
<th data-i18n="projects.detail.team.col.role">Rolle</th>
|
|
<th data-i18n="projects.detail.team.col.source">Herkunft</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody id="team-derived-body" />
|
|
</table>
|
|
</div>
|
|
|
|
{/* t-paliad-139 — Partner Units management. */}
|
|
<div id="team-section-units" style="display:none">
|
|
<h3 className="entity-section-heading" data-i18n="projects.team.section.units">
|
|
Partner Units
|
|
</h3>
|
|
<p className="form-hint" data-i18n="projects.team.section.units.hint">
|
|
Partner Units, die auf diesem Projekt eingebunden sind. Mitglieder mit passenden Unit-Rollen werden automatisch abgeleitet.
|
|
</p>
|
|
<div className="party-controls">
|
|
<button type="button" id="unit-attach-show" className="btn-primary btn-cta-lime btn-small" data-i18n="projects.team.units.attach">
|
|
Partner Unit zuordnen
|
|
</button>
|
|
</div>
|
|
<div id="unit-attach-form-wrap" style="display:none">
|
|
<form id="unit-attach-form" className="entity-form party-form" autocomplete="off">
|
|
<div className="form-field-row">
|
|
<div className="form-field">
|
|
<label htmlFor="unit-attach-select" data-i18n="projects.team.units.select">Unit</label>
|
|
<select id="unit-attach-select" required />
|
|
</div>
|
|
</div>
|
|
<fieldset className="form-field">
|
|
<legend data-i18n="projects.team.units.derive_roles">Welche Unit-Rollen ableiten?</legend>
|
|
<label className="form-checkbox">
|
|
<input type="checkbox" id="unit-attach-role-pa" checked /> <span data-i18n="unit_role.pa">PA</span>
|
|
</label>
|
|
<label className="form-checkbox">
|
|
<input type="checkbox" id="unit-attach-role-senior_pa" checked /> <span data-i18n="unit_role.senior_pa">Senior PA</span>
|
|
</label>
|
|
<label className="form-checkbox">
|
|
<input type="checkbox" id="unit-attach-role-attorney" /> <span data-i18n="unit_role.attorney">Attorney</span>
|
|
</label>
|
|
</fieldset>
|
|
<label className="form-checkbox">
|
|
<input type="checkbox" id="unit-attach-authority" /> <span data-i18n="projects.team.units.grants_authority">Stimmrecht abgeben (4-Augen)</span>
|
|
</label>
|
|
<div className="form-actions">
|
|
<button type="button" className="btn-cancel" id="unit-attach-cancel" data-i18n="projects.detail.team.form.cancel">Abbrechen</button>
|
|
<button type="submit" className="btn-primary btn-cta-lime" data-i18n="projects.team.units.attach">Zuordnen</button>
|
|
</div>
|
|
</form>
|
|
</div>
|
|
<table className="party-table">
|
|
<thead>
|
|
<tr>
|
|
<th data-i18n="projects.team.units.col.name">Unit</th>
|
|
<th data-i18n="projects.team.units.col.derive_roles">Abgeleitete Rollen</th>
|
|
<th data-i18n="projects.team.units.col.authority">Authority</th>
|
|
<th />
|
|
</tr>
|
|
</thead>
|
|
<tbody id="team-units-body" />
|
|
</table>
|
|
</div>
|
|
</section>
|
|
|
|
{/* Project Tree (Projektbaum) — full visible hierarchy with current node highlighted */}
|
|
<section className="entity-tab-panel" id="tab-children" style="display:none">
|
|
<div className="party-controls">
|
|
<a id="child-add-link" className="btn-primary btn-cta-lime btn-small" href="/projects/new" data-i18n="projects.detail.kinder.add">
|
|
Untervorhaben anlegen
|
|
</a>
|
|
</div>
|
|
<div id="project-tree" className="projekt-tree" />
|
|
<p className="entity-events-empty" id="children-empty" style="display:none" data-i18n="projects.detail.kinder.empty">
|
|
Keine untergeordneten Projekte.
|
|
</p>
|
|
</section>
|
|
|
|
{/* Parties (Parteien) */}
|
|
<section className="entity-tab-panel" id="tab-parties" style="display:none">
|
|
<div className="party-controls">
|
|
<button id="party-add-btn" className="btn-primary btn-cta-lime btn-small" type="button" data-i18n="projects.detail.parteien.add">
|
|
Partei hinzufügen
|
|
</button>
|
|
</div>
|
|
|
|
<form id="party-form" className="entity-form party-form" style="display:none" autocomplete="off">
|
|
<div className="form-field-row">
|
|
<div className="form-field">
|
|
<label htmlFor="party-name" data-i18n="projects.detail.parteien.form.name">Name</label>
|
|
<input type="text" id="party-name" required />
|
|
</div>
|
|
<div className="form-field">
|
|
<label htmlFor="party-role" data-i18n="projects.detail.parteien.form.role">Rolle</label>
|
|
<select id="party-role">
|
|
<option value="claimant" data-i18n="projects.detail.parteien.role.claimant">Kläger</option>
|
|
<option value="defendant" data-i18n="projects.detail.parteien.role.defendant">Beklagter</option>
|
|
<option value="thirdparty" data-i18n="projects.detail.parteien.role.thirdparty">Streitverkündeter / Drittpartei</option>
|
|
</select>
|
|
</div>
|
|
</div>
|
|
<div className="form-field">
|
|
<label htmlFor="party-rep" data-i18n="projects.detail.parteien.form.rep">Vertreter (optional)</label>
|
|
<input type="text" id="party-rep" />
|
|
</div>
|
|
<div className="form-actions">
|
|
<button type="button" className="btn-cancel" id="party-cancel" data-i18n="projects.detail.parteien.form.cancel">Abbrechen</button>
|
|
<button type="submit" className="btn-primary btn-cta-lime" data-i18n="projects.detail.parteien.form.submit">Hinzufügen</button>
|
|
</div>
|
|
<p className="form-msg" id="party-msg" />
|
|
</form>
|
|
|
|
<table className="party-table">
|
|
<thead>
|
|
<tr>
|
|
<th data-i18n="projects.detail.parteien.col.name">Name</th>
|
|
<th data-i18n="projects.detail.parteien.col.role">Rolle</th>
|
|
<th data-i18n="projects.detail.parteien.col.rep">Vertreter</th>
|
|
<th />
|
|
</tr>
|
|
</thead>
|
|
<tbody id="parties-body" />
|
|
</table>
|
|
|
|
<div className="entity-empty-card" id="parties-empty" style="display:none">
|
|
<p data-i18n="projects.detail.parteien.empty">
|
|
Noch keine Parteien eingetragen.
|
|
</p>
|
|
<button id="parties-empty-cta" className="btn-primary btn-cta-lime" type="button" data-i18n="projects.detail.parteien.add">
|
|
Partei hinzufügen
|
|
</button>
|
|
</div>
|
|
</section>
|
|
|
|
{/* Deadlines (Fristen) */}
|
|
<section className="entity-tab-panel" id="tab-deadlines" style="display:none">
|
|
<div className="party-controls">
|
|
<a id="deadline-add-link" className="btn-primary btn-cta-lime btn-small" data-i18n="projects.detail.deadlines.add" href="#">
|
|
Frist hinzufügen
|
|
</a>
|
|
<button type="button" className="btn-secondary btn-small subtree-toggle" aria-pressed="false">
|
|
Inkl. Unterprojekte
|
|
</button>
|
|
</div>
|
|
<div className="entity-table-wrap" id="project-deadlines-tablewrap">
|
|
<table className="entity-table fristen-table">
|
|
<thead>
|
|
<tr>
|
|
<th />
|
|
<th data-i18n="deadlines.col.due">Fällig</th>
|
|
<th data-i18n="deadlines.col.title">Titel</th>
|
|
<th data-i18n="deadlines.col.rule">Regel</th>
|
|
<th data-i18n="deadlines.col.status">Status</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody id="project-deadlines-body" />
|
|
</table>
|
|
</div>
|
|
<p className="entity-events-empty" id="project-deadlines-empty" style="display:none" data-i18n="projects.detail.deadlines.empty">
|
|
Für dieses Projekt sind noch keine Fristen erfasst.
|
|
</p>
|
|
</section>
|
|
|
|
{/* Appointments (Termine) */}
|
|
<section className="entity-tab-panel" id="tab-appointments" style="display:none">
|
|
<div className="party-controls">
|
|
<button type="button" id="appointment-add-btn" className="btn-primary btn-cta-lime btn-small" data-i18n="projects.detail.appointments.add">
|
|
Termin hinzufügen
|
|
</button>
|
|
<button type="button" className="btn-secondary btn-small subtree-toggle" aria-pressed="false">
|
|
Inkl. Unterprojekte
|
|
</button>
|
|
</div>
|
|
|
|
<form id="project-appointment-form" className="party-form" style="display:none">
|
|
<div className="form-field-row">
|
|
<div className="form-field">
|
|
<label htmlFor="project-appointment-title" data-i18n="appointments.field.title">Titel</label>
|
|
<input type="text" id="project-appointment-title" required />
|
|
</div>
|
|
<div className="form-field">
|
|
<label htmlFor="project-appointment-type" data-i18n="appointments.field.type">Typ</label>
|
|
<select id="project-appointment-type">
|
|
<option value="" data-i18n="appointments.field.type.none">Kein Typ</option>
|
|
<option value="hearing" data-i18n="appointments.type.hearing">Verhandlung</option>
|
|
<option value="meeting" data-i18n="appointments.type.meeting">Besprechung</option>
|
|
<option value="consultation" data-i18n="appointments.type.consultation">Beratung</option>
|
|
<option value="deadline_hearing" data-i18n="appointments.type.deadline_hearing">Fristverhandlung</option>
|
|
</select>
|
|
</div>
|
|
</div>
|
|
<div className="form-field-row">
|
|
<div className="form-field">
|
|
<label htmlFor="project-appointment-start" data-i18n="appointments.field.start">Beginn</label>
|
|
<input type="datetime-local" id="project-appointment-start" required />
|
|
</div>
|
|
<div className="form-field">
|
|
<label htmlFor="project-appointment-end" data-i18n="appointments.field.end">Ende (optional)</label>
|
|
<input type="datetime-local" id="project-appointment-end" />
|
|
</div>
|
|
</div>
|
|
<div className="form-field">
|
|
<label htmlFor="project-appointment-location" data-i18n="appointments.field.location">Ort</label>
|
|
<input type="text" id="project-appointment-location" />
|
|
</div>
|
|
<div className="form-actions">
|
|
<button type="button" className="btn-cancel" id="project-appointment-cancel" data-i18n="projects.detail.appointments.form.cancel">Abbrechen</button>
|
|
<button type="submit" className="btn-primary btn-cta-lime" data-i18n="projects.detail.appointments.form.submit">Hinzufügen</button>
|
|
</div>
|
|
<p className="form-msg" id="project-appointment-msg" />
|
|
</form>
|
|
|
|
<div className="entity-table-wrap" id="project-appointments-tablewrap">
|
|
<table className="entity-table fristen-table">
|
|
<thead>
|
|
<tr>
|
|
<th />
|
|
<th data-i18n="appointments.col.start">Beginn</th>
|
|
<th data-i18n="appointments.col.title">Titel</th>
|
|
<th data-i18n="appointments.col.location">Ort</th>
|
|
<th data-i18n="appointments.col.type">Typ</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody id="project-appointments-body" />
|
|
</table>
|
|
</div>
|
|
<p className="entity-events-empty" id="project-appointments-empty" style="display:none" data-i18n="projects.detail.appointments.empty">
|
|
Für dieses Projekt sind noch keine Termine erfasst.
|
|
</p>
|
|
</section>
|
|
|
|
{/* Notes (Notizen) */}
|
|
<section className="entity-tab-panel" id="tab-notes" style="display:none">
|
|
<div id="notes-container" className="notiz-container" data-parent-type="project" />
|
|
</section>
|
|
|
|
{/* Checklists (Checklisten) */}
|
|
<section className="entity-tab-panel" id="tab-checklists" style="display:none">
|
|
<div className="party-controls">
|
|
<button id="checklist-add-btn" className="btn-primary btn-cta-lime btn-small" type="button" data-i18n="projects.detail.checklisten.add">
|
|
Checkliste hinzufügen
|
|
</button>
|
|
</div>
|
|
<p className="form-msg" id="project-checklists-msg" />
|
|
<p id="project-checklists-empty" className="entity-events-empty" style="display:none" data-i18n="projects.detail.checklisten.empty">
|
|
Für dieses Projekt sind noch keine Checklisten-Instanzen erfasst.
|
|
</p>
|
|
<div className="entity-table-wrap" id="project-checklists-tablewrap" style="display:none">
|
|
<table className="entity-table">
|
|
<thead>
|
|
<tr>
|
|
<th data-i18n="projects.detail.checklisten.col.template">Vorlage</th>
|
|
<th data-i18n="projects.detail.checklisten.col.name">Name</th>
|
|
<th data-i18n="projects.detail.checklisten.col.progress">Fortschritt</th>
|
|
<th data-i18n="projects.detail.checklisten.col.created">Angelegt</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody id="project-checklists-body" />
|
|
</table>
|
|
</div>
|
|
<p className="tool-subtitle checklists-hint">
|
|
<span data-i18n="projects.detail.checklisten.hint.prefix">Vorlagen werden auf der </span>
|
|
<a href="/checklists" data-i18n="projects.detail.checklisten.hint.link">Checklisten</a>
|
|
<span data-i18n="projects.detail.checklisten.hint.suffix">-Seite angelegt und bearbeitet.</span>
|
|
</p>
|
|
</section>
|
|
|
|
{/* Submissions (Schriftsätze) — t-paliad-242 broadened
|
|
the original t-paliad-215 list to the full
|
|
cross-proceeding catalog. The table shows every
|
|
active filing rule across every proceeding, grouped
|
|
by proceeding; the project's own proceeding is
|
|
pinned to the top. The no-proceeding hint stays as
|
|
a soft nudge above the catalog (the table renders
|
|
regardless). */}
|
|
<section className="entity-tab-panel" id="tab-submissions" style="display:none">
|
|
<div id="project-submissions-no-proceeding" className="entity-events-empty" style="display:none">
|
|
<p data-i18n="projects.detail.submissions.empty.no_proceeding">
|
|
Für dieses Projekt ist noch kein Verfahrenstyp gesetzt — der Katalog unten zeigt trotzdem alle Vorlagen.
|
|
</p>
|
|
<button
|
|
type="button"
|
|
id="project-submissions-edit-cta"
|
|
className="btn-primary btn-small"
|
|
data-i18n="projects.detail.submissions.empty.no_proceeding.cta">
|
|
Projekt bearbeiten
|
|
</button>
|
|
</div>
|
|
<p id="project-submissions-empty" className="entity-events-empty" style="display:none" data-i18n="projects.detail.submissions.empty">
|
|
Es sind aktuell keine Schriftsatzvorlagen hinterlegt.
|
|
</p>
|
|
<div className="entity-table-wrap" id="project-submissions-tablewrap" style="display:none">
|
|
<table className="entity-table entity-table--readonly">
|
|
<thead>
|
|
<tr>
|
|
<th data-i18n="projects.detail.submissions.col.name">Schriftsatz</th>
|
|
<th data-i18n="projects.detail.submissions.col.party">Partei</th>
|
|
<th data-i18n="projects.detail.submissions.col.source">Rechtsgrundlage</th>
|
|
<th data-i18n="projects.detail.submissions.col.action" />
|
|
</tr>
|
|
</thead>
|
|
<tbody id="project-submissions-body" />
|
|
</table>
|
|
</div>
|
|
<p className="tool-subtitle submissions-hint" data-i18n="projects.detail.submissions.hint">
|
|
Schriftsätze werden direkt aus dem Projekt heraus als .docx generiert. Anpassen, drucken, einreichen.
|
|
</p>
|
|
</section>
|
|
|
|
{/* Verwaltung — rare admin actions (export, archive). Each
|
|
sub-section hides itself if the caller is not entitled
|
|
(export: §4 gate; archive: global_admin). */}
|
|
<section className="entity-tab-panel" id="tab-settings" style="display:none">
|
|
<div className="settings-section" id="project-settings-export" style="display:none">
|
|
<h3 className="entity-section-heading" data-i18n="projects.detail.settings.export.heading">Daten exportieren</h3>
|
|
<p className="tool-subtitle" data-i18n="projects.detail.settings.export.description">
|
|
Lade alle Daten dieses Projekts (inkl. Unter-Projekten) als Excel + JSON + CSV-Archiv herunter.
|
|
</p>
|
|
<button
|
|
type="button"
|
|
id="project-export-btn"
|
|
className="btn-secondary"
|
|
data-i18n="projects.detail.export.button">
|
|
Daten exportieren
|
|
</button>
|
|
</div>
|
|
|
|
<div className="settings-section" id="project-settings-archive" style="display:none">
|
|
<h3 className="entity-section-heading" data-i18n="projects.detail.settings.archive.heading">Projekt archivieren</h3>
|
|
<p className="tool-subtitle" data-i18n="projects.detail.settings.archive.description">
|
|
Archivieren erfolgt aus dem Bearbeiten-Dialog (Gefahrenbereich).
|
|
</p>
|
|
<button
|
|
type="button"
|
|
id="project-settings-archive-link"
|
|
className="btn-secondary"
|
|
data-i18n="projects.detail.settings.archive.cta">
|
|
Bearbeiten öffnen
|
|
</button>
|
|
</div>
|
|
</section>
|
|
</div>
|
|
|
|
{/* Full edit modal — same form as /projects/new, pre-filled. */}
|
|
<div className="modal-overlay" id="project-edit-modal" style="display:none">
|
|
<div className="modal-card modal-card-wide">
|
|
<div className="modal-header">
|
|
<h2 data-i18n="projects.detail.edit.modal.title">Projekt bearbeiten</h2>
|
|
<button className="modal-close" id="project-edit-modal-close" type="button" aria-label="Schließen">×</button>
|
|
</div>
|
|
<form id="project-edit-form" className="entity-form" autocomplete="off">
|
|
<ProjectFormFields />
|
|
|
|
<div
|
|
className="form-warn"
|
|
id="project-edit-type-warning"
|
|
role="alert"
|
|
style="display:none"
|
|
>
|
|
<strong data-i18n="projects.detail.edit.type_change_warning.title">
|
|
Diese Felder werden geleert:
|
|
</strong>
|
|
<span id="project-edit-type-warning-fields" />
|
|
</div>
|
|
|
|
<p className="form-msg" id="project-edit-msg" />
|
|
|
|
<div className="form-actions">
|
|
<button type="button" className="btn-cancel" id="project-edit-cancel" data-i18n="projects.cancel">Abbrechen</button>
|
|
<button type="submit" className="btn-primary btn-cta-lime" data-i18n="projects.detail.save">Speichern</button>
|
|
</div>
|
|
</form>
|
|
{/* Danger zone — destructive action, visually separated from Save/Cancel. */}
|
|
<div className="modal-danger-zone" id="project-delete-wrap" style="display:none">
|
|
<button id="project-delete-btn" className="btn-link-danger" type="button" data-i18n="projects.detail.delete">
|
|
Projekt archivieren
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
{/* Add-checklist-instance modal (t-paliad-239) — picks a
|
|
template and POSTs to /api/checklists/{slug}/instances
|
|
with the current project_id; the row appears in the
|
|
Checklists tab list on success. */}
|
|
<div className="modal-overlay" id="add-checklist-modal" style="display:none">
|
|
<div className="modal-card modal-card-wide">
|
|
<div className="modal-header">
|
|
<h2 data-i18n="projects.detail.checklisten.add">Checkliste hinzufügen</h2>
|
|
<button className="modal-close" id="add-checklist-close" type="button">×</button>
|
|
</div>
|
|
<div className="form-field">
|
|
<input type="text" id="add-checklist-search" autocomplete="off" data-i18n-placeholder="projects.detail.checklisten.add.search" placeholder="Vorlage suchen…" />
|
|
</div>
|
|
<div className="add-checklist-list" id="add-checklist-list" />
|
|
<p className="entity-events-empty" id="add-checklist-empty" style="display:none" data-i18n="projects.detail.checklisten.add.empty_pick">
|
|
Keine passenden Vorlagen gefunden.
|
|
</p>
|
|
<p className="form-msg" id="add-checklist-msg" />
|
|
</div>
|
|
</div>
|
|
|
|
{/* Delete confirmation modal */}
|
|
<div className="modal-overlay" id="delete-modal" style="display:none">
|
|
<div className="modal-card">
|
|
<div className="modal-header">
|
|
<h2 data-i18n="projects.detail.delete.confirm.title">Projekt wirklich archivieren?</h2>
|
|
<button className="modal-close" id="delete-modal-close" type="button">×</button>
|
|
</div>
|
|
<p data-i18n="projects.detail.delete.confirm.body">
|
|
Das Projekt wird archiviert. Es kann nicht direkt wiederhergestellt werden.
|
|
</p>
|
|
<div className="form-actions">
|
|
<button type="button" className="btn-cancel" id="delete-modal-cancel" data-i18n="projects.detail.delete.confirm.cancel">Abbrechen</button>
|
|
<button type="button" className="btn-danger" id="delete-modal-confirm" data-i18n="projects.detail.delete.confirm.ok">Archivieren</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</section>
|
|
</main>
|
|
|
|
<Footer />
|
|
<PaliadinWidget />
|
|
<script src="/assets/projects-detail.js"></script>
|
|
</body>
|
|
</html>
|
|
);
|
|
}
|