Multi-select party picker on the dedicated submission draft editor —
lawyer picks which of the project's parties to mention in this
specific submission. Adds the t-paliad-277 variable-bag multi-party
shape ({{parties.claimants}}, {{parties.claimant.0.name}}) while
keeping the legacy flat aliases ({{parties.claimant.name}}) for every
existing .docx template authored before the rename.
Surfaces an explicit "Aus Projekt importieren" button + last-imported
timestamp at the top of the variable sidebar so the lawyer can re-pull
project-derived variables (project.*, parties.*, deadline.*,
procedural_event.*, rule.*) when the project data drifts away from the
saved draft overrides. firm.*, today.*, user.* overrides survive the
import — those values aren't sourced from the project record.
Schema: mig 131 adds two columns to paliad.submission_drafts:
- selected_parties uuid[] DEFAULT '{}'::uuid[]
Empty = include every party (legacy default).
Non-empty = restrict to the subset, grouped by role at substitution.
- last_imported_at timestamptz NULL
Bumped each "Aus Projekt importieren" click; surfaced in UI.
Backend:
- SubmissionVarsContext gains SelectedParties — filterPartiesBySelection
restricts the resolved bag before role bucketing.
- addPartyVars emits THREE coexisting forms per role: comma-joined
(parties.claimants), indexed (parties.claimant.0.name), and flat
legacy (parties.claimant.name → first selected claimant). Flat
aliases are kept forever per the issue's backward-compat contract.
- SubmissionDraftService.ImportFromProject strips overrides for
project-derived prefixes and bumps last_imported_at; rejects
project-less drafts (nothing to import from).
- New endpoint POST /api/submission-drafts/{id}/import-from-project.
- DraftPatch + PATCH handlers accept selected_parties.
- submissionDraftView now ships available_parties so the editor can
render the picker without an extra round-trip.
Frontend:
- submission-draft.tsx: new import-row + parties block in the sidebar.
- client/submission-draft.ts: paintImportRow / paintPartyPicker /
onPartySelectionChange / onImportFromProject; group parties by
role bucket (claimant / defendant / other) with DE+EN role-string
matching to mirror the backend bucketing.
- 3 new i18n keys (DE+EN): import.button, parties.title, parties.hint.
- CSS for the picker + import row in global.css.
Tests: 6 new unit tests in submission_vars_parties_test.go covering
the multi-party bag emission, German role-string bucketing, flat-alias
first-of-role resolution, empty-selection-means-all default, non-empty
restriction, and the isProjectDerivedKey policy that powers the
import path.
Build hygiene: go build/vet clean; go test -short ./internal/... pass;
bun run build clean (2876 i18n keys, scan clean).
188 lines
8.2 KiB
TypeScript
188 lines
8.2 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";
|
|
|
|
// t-paliad-238 Slice A — dedicated Submissions/Schriftsätze editor page.
|
|
//
|
|
// Lawyer picks (or creates) a draft for one (project, submission_code),
|
|
// edits placeholder variables in a sticky sidebar, sees a read-only
|
|
// HTML preview of the merged document, and exports the result as
|
|
// .docx. Drafts persist server-side per paliad.submission_drafts.
|
|
//
|
|
// Pure shell: client/submission-draft.ts hydrates draft list + variable
|
|
// form + preview pane after page load. The same dist/submission-draft.html
|
|
// serves every (project_id, submission_code, [draft_id]) URL.
|
|
//
|
|
// Design ref: docs/design-submission-page-2026-05-22.md §6.
|
|
|
|
export function renderSubmissionDraft(): 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="submissions.draft.title">Schriftsatz bearbeiten — Paliad</title>
|
|
<link rel="stylesheet" href="/assets/global.css" />
|
|
</head>
|
|
<body className="has-sidebar page-submission-draft">
|
|
<Sidebar currentPath="/projects" />
|
|
<BottomNav currentPath="/projects" />
|
|
|
|
<main>
|
|
<section className="tool-page submission-draft-page">
|
|
<div className="container">
|
|
<a
|
|
id="submission-draft-back-link"
|
|
href="/projects"
|
|
className="back-link"
|
|
data-i18n="submissions.draft.back">
|
|
← Zurück zum Projekt
|
|
</a>
|
|
|
|
<div id="submission-draft-loading" className="entity-loading">
|
|
<p data-i18n="submissions.draft.loading">Lädt…</p>
|
|
</div>
|
|
|
|
<div id="submission-draft-notfound" className="entity-empty" style="display:none">
|
|
<p data-i18n="submissions.draft.notfound">
|
|
Schriftsatz nicht gefunden oder keine Berechtigung.
|
|
</p>
|
|
</div>
|
|
|
|
<div id="submission-draft-error" className="entity-empty" style="display:none" />
|
|
|
|
<div id="submission-draft-body" style="display:none">
|
|
<header className="submission-draft-header">
|
|
<div className="submission-draft-header-text">
|
|
<h1 id="submission-draft-title" />
|
|
<p id="submission-draft-subtitle" className="tool-subtitle" />
|
|
</div>
|
|
<div className="submission-draft-header-actions">
|
|
<button
|
|
id="submission-draft-export-btn"
|
|
type="button"
|
|
className="btn-primary btn-cta-lime"
|
|
data-i18n="submissions.draft.action.export">
|
|
Als .docx exportieren
|
|
</button>
|
|
</div>
|
|
</header>
|
|
|
|
<div className="submission-draft-grid">
|
|
{/* Sidebar — draft switcher + variable groups. */}
|
|
<aside className="submission-draft-sidebar" id="submission-draft-sidebar">
|
|
<div className="submission-draft-switcher">
|
|
<label htmlFor="submission-draft-pick" data-i18n="submissions.draft.switcher.label">
|
|
Entwurf
|
|
</label>
|
|
<select id="submission-draft-pick" />
|
|
<button
|
|
type="button"
|
|
id="submission-draft-new-btn"
|
|
className="btn-small btn-secondary"
|
|
data-i18n="submissions.draft.action.new">
|
|
+ Neuer Entwurf
|
|
</button>
|
|
</div>
|
|
|
|
<div className="submission-draft-name-row">
|
|
<input
|
|
type="text"
|
|
id="submission-draft-name"
|
|
className="entity-form-input"
|
|
data-i18n-placeholder="submissions.draft.name.placeholder"
|
|
placeholder="Name dieses Entwurfs"
|
|
/>
|
|
<button
|
|
type="button"
|
|
id="submission-draft-delete-btn"
|
|
className="btn-small btn-link-danger"
|
|
data-i18n="submissions.draft.action.delete">
|
|
Löschen
|
|
</button>
|
|
</div>
|
|
|
|
<p className="submission-draft-savestatus" id="submission-draft-savestatus" />
|
|
|
|
{/* t-paliad-277: "Aus Projekt importieren" + last-
|
|
imported-at timestamp. Only visible when the
|
|
draft has a project_id attached. */}
|
|
<div
|
|
id="submission-draft-import-row"
|
|
className="submission-draft-import-row"
|
|
style="display:none">
|
|
<button
|
|
type="button"
|
|
id="submission-draft-import-btn"
|
|
className="btn-small btn-secondary"
|
|
data-i18n="submissions.draft.import.button">
|
|
Aus Projekt importieren
|
|
</button>
|
|
<span
|
|
id="submission-draft-import-stamp"
|
|
className="submission-draft-import-stamp"
|
|
/>
|
|
</div>
|
|
|
|
{/* t-paliad-277: multi-select party picker.
|
|
Populated from view.available_parties; checkbox
|
|
per party, grouped by role. Hidden when no
|
|
project or no parties on the project. */}
|
|
<div
|
|
id="submission-draft-parties"
|
|
className="submission-draft-parties"
|
|
style="display:none">
|
|
<h3
|
|
className="submission-draft-var-group-title"
|
|
data-i18n="submissions.draft.parties.title">
|
|
Parteien
|
|
</h3>
|
|
<p
|
|
className="submission-draft-parties-hint"
|
|
data-i18n="submissions.draft.parties.hint">
|
|
Wählen Sie aus, welche Parteien im Schriftsatz genannt werden sollen.
|
|
</p>
|
|
<div
|
|
id="submission-draft-parties-list"
|
|
className="submission-draft-parties-list"
|
|
/>
|
|
</div>
|
|
|
|
<div className="submission-draft-variables" id="submission-draft-variables" />
|
|
</aside>
|
|
|
|
{/* Preview pane — read-only HTML render of the merged
|
|
document body. Re-renders on autosave round-trip. */}
|
|
<section className="submission-draft-preview-wrap">
|
|
<header className="submission-draft-preview-header">
|
|
<h2 data-i18n="submissions.draft.preview.title">Vorschau</h2>
|
|
<span
|
|
className="submission-draft-preview-hint"
|
|
data-i18n="submissions.draft.preview.hint">
|
|
Read-only Vorschau — finale Bearbeitung in Word.
|
|
</span>
|
|
</header>
|
|
<div className="submission-draft-preview" id="submission-draft-preview" />
|
|
</section>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</section>
|
|
</main>
|
|
|
|
<Footer />
|
|
<PaliadinWidget />
|
|
|
|
<script src="/assets/submission-draft.js"></script>
|
|
</body>
|
|
</html>
|
|
);
|
|
}
|