feat: Zweck-Vokabular auf 12 Kategorien erweitert, Werkzeug-Formular im Enterprise-Look überarbeitet
Sechs neue Zweck-Kategorien (Datenanalyse, Video, Audio/Sprache, Kundenservice/Chatbot, Präsentation/Design, Automatisierung/Agenten) ergänzen die ursprünglichen sechs — deckt jetzt die tatsächliche Bandbreite an Einsatzgebieten ab statt nur klassischer Wissensarbeit. Werkzeug-Formular (Betreiber + Mandant, gleiche Vorlage) neu strukturiert: Karten-Layout mit thematischen Abschnitten, 2-Spalten-Grid für kurze Felder, Chip-Gruppen statt langer Checkbox-Listen, abgesetzte Gefahrenzone für den Löschen-Button. Dabei einen vorbestehenden Bug gefunden und behoben: das Lösch-Formular war fest auf die Betreiber-Route verdrahtet, obwohl dieselbe Vorlage auch vom Mandanten-Formular genutzt wird.
This commit is contained in:
68
CLAUDE.md
68
CLAUDE.md
@@ -39,8 +39,8 @@ Regelbasiert, nicht ML: die Ableitungsregeln (Datenklasse, KI-VO-
|
|||||||
Einstufung, Anforderungsprofil) liegen als versionierte YAML-Dateien
|
Einstufung, Anforderungsprofil) liegen als versionierte YAML-Dateien
|
||||||
vor, nicht im Code — ein fachlich Verantwortlicher soll sie anpassen
|
vor, nicht im Code — ein fachlich Verantwortlicher soll sie anpassen
|
||||||
können, ohne Go-Code anzufassen. Ein LLM ist v1 höchstens optional zur
|
können, ohne Go-Code anzufassen. Ein LLM ist v1 höchstens optional zur
|
||||||
Zweckerkennung aus dem Freitext vorgesehen (Textgenerierung/Übersetzung/
|
Zweckerkennung aus dem Freitext vorgesehen (die zwölf Zweck-Kategorien
|
||||||
Code/Bild/Transkription/Recherche erkennen), nie für die Einstufung
|
erkennen, siehe `gueltigeZwecke` weiter unten), nie für die Einstufung
|
||||||
selbst — und auch dort nur als Vorschlag, den der Mensch bestätigt.
|
selbst — und auch dort nur als Vorschlag, den der Mensch bestätigt.
|
||||||
|
|
||||||
---
|
---
|
||||||
@@ -269,13 +269,23 @@ aussahen — `formatAufbewahrung()` zeigt entsprechend "unbekannt" statt
|
|||||||
"0 Tage".
|
"0 Tage".
|
||||||
|
|
||||||
`geeignete_zwecke` ist seit derselben Migration ein kontrolliertes
|
`geeignete_zwecke` ist seit derselben Migration ein kontrolliertes
|
||||||
Vokabular statt Freitext: das Formular zeigt Checkboxen für genau die
|
Vokabular statt Freitext: das Formular zeigt Checkboxen statt eines
|
||||||
sechs Zweck-Kategorien aus dem Fragebogen (Textgenerierung,
|
Freitextfelds (`gueltigeZwecke` in `betreiber_werkzeug_handlers.go`,
|
||||||
Übersetzung, Code, Bild, Transkription, Recherche — `gueltigeZwecke` in
|
serverseitig validiert via `istGueltigerZweck`). Grund: ein künftiger
|
||||||
`betreiber_werkzeug_handlers.go`), serverseitig validiert
|
automatischer Zweckabgleich (Bewertungslogik Schritt 3, weiterhin nicht
|
||||||
(`istGueltigerZweck`). Grund: ein künftiger automatischer Zweckabgleich
|
gebaut) würde an inkonsistentem Freitext ("Text" statt
|
||||||
(Bewertungslogik Schritt 3, weiterhin nicht gebaut) würde an
|
"Textgenerierung") scheitern. Am 2026-08-31 von sechs auf zwölf
|
||||||
inkonsistentem Freitext ("Text" statt "Textgenerierung") scheitern.
|
Kategorien erweitert, nachdem der Nutzer zurecht einwandte, dass sechs
|
||||||
|
Kategorien die tatsächliche Bandbreite an Einsatzgebieten nicht
|
||||||
|
abdecken: Textgenerierung, Übersetzung, Code, Bild, Transkription,
|
||||||
|
Recherche, **Datenanalyse, Video, Audio/Sprache,
|
||||||
|
Kundenservice/Chatbot, Präsentation/Design, Automatisierung/Agenten**.
|
||||||
|
Es gibt keinen einheitlichen Branchenstandard für KI-Funktions-
|
||||||
|
kategorien (regulatorische Taxonomien wie die KI-VO selbst oder OECD/
|
||||||
|
NIST klassifizieren nach Risiko, nicht nach Funktion; Marktplatz-
|
||||||
|
Kategorien wie bei G2 sind Marketing, kein Standard) — diese zwölf
|
||||||
|
sind Deklarix' eigene, bewusst begrenzte Liste für den künftigen
|
||||||
|
Zweckabgleich, keine allgemeine KI-Taxonomie.
|
||||||
|
|
||||||
Neues Feld `subprozessoren` (TEXT[], Migration 0015) macht
|
Neues Feld `subprozessoren` (TEXT[], Migration 0015) macht
|
||||||
Unterauftragsverarbeiter (z. B. Anthropic bei Microsoft 365 Copilot,
|
Unterauftragsverarbeiter (z. B. Anthropic bei Microsoft 365 Copilot,
|
||||||
@@ -319,8 +329,8 @@ bleibt, mit welchem Katalogstand ein Vorschlag erzeugt wurde.
|
|||||||
nicht erfüllen — Grund je Werkzeug festhalten, auch aussortierte
|
nicht erfüllen — Grund je Werkzeug festhalten, auch aussortierte
|
||||||
Werkzeuge werden im Ergebnis mit Begründung gezeigt.
|
Werkzeuge werden im Ergebnis mit Begründung gezeigt.
|
||||||
3. **Zweckabgleich.** Aus `beschreibung`/`ergebnis` den Zweck ableiten
|
3. **Zweckabgleich.** Aus `beschreibung`/`ergebnis` den Zweck ableiten
|
||||||
(Textgenerierung, Übersetzung, Code, Bild, Transkription, Recherche)
|
(die zwölf Kategorien aus `gueltigeZwecke`, siehe Werkzeugkatalog
|
||||||
und gegen `geeignete_zwecke` filtern.
|
weiter unten) und gegen `geeignete_zwecke` filtern.
|
||||||
4. **Rangfolge.** Verbleibende Werkzeuge sortieren: EU-Verarbeitung,
|
4. **Rangfolge.** Verbleibende Werkzeuge sortieren: EU-Verarbeitung,
|
||||||
Training standardmäßig aus, kurze Aufbewahrung, Aktualität der
|
Training standardmäßig aus, kurze Aufbewahrung, Aktualität der
|
||||||
Prüfung.
|
Prüfung.
|
||||||
@@ -467,7 +477,41 @@ kein separates Desktop-Template.
|
|||||||
**Tabellen** (`table`/`th`/`td` in `app.css`) sind seit dieser Änderung
|
**Tabellen** (`table`/`th`/`td` in `app.css`) sind seit dieser Änderung
|
||||||
gestylt (vorher komplett ungestylt, betraf v. a. `register_liste.html`);
|
gestylt (vorher komplett ungestylt, betraf v. a. `register_liste.html`);
|
||||||
breite Tabellen stehen in einem `.table-scroll`-Wrapper (horizontales
|
breite Tabellen stehen in einem `.table-scroll`-Wrapper (horizontales
|
||||||
Scrollen auf dem Handy statt gequetschter Spalten).
|
Scrollen auf dem Handy statt gequetschter Spalten). Seit 2026-08-31 hat
|
||||||
|
`.table-scroll` zusätzlich einen rechten Fade-Rand (`mask-image`) —
|
||||||
|
ohne den sah eine am Fensterrand abgeschnittene breite Tabelle wie ein
|
||||||
|
Rendering-Fehler aus statt wie "hier geht's mit Scrollen weiter" (per
|
||||||
|
Screenshot am Werkzeugkatalog beobachtet: die letzten zwei Spalten
|
||||||
|
waren nur als einzelne Buchstaben sichtbar, ganz ohne Hinweis auf mehr
|
||||||
|
Inhalt).
|
||||||
|
|
||||||
|
**Formulare** (`.form-card`/`.form-section`/`.form-grid`/`.chip-group`
|
||||||
|
in `app.css`, seit 2026-08-31, erstmals angewendet auf
|
||||||
|
`betreiber_werkzeug_form.html`): vorher war jedes Formular eine flache
|
||||||
|
Spalte aus `<label>`+`<input>` ohne Gruppierung — bei einem Formular
|
||||||
|
mit über einem Dutzend Feldern (Werkzeug anlegen) wirkte das "klobig,
|
||||||
|
einfach nur untereinander" (O-Ton Nutzer). Jetzt: `.form-card` (weiße
|
||||||
|
Karte mit Rahmen/Schatten, Ant-Design-Tokens aus `design/enterprise.css`
|
||||||
|
übernommen) enthält mehrere `<fieldset class="form-section">`
|
||||||
|
(thematische Abschnitte mit Titel, per `border-top` getrennt), darin
|
||||||
|
`.form-grid` (2 Spalten ab 640px für kurze Felder wie Name/Anbieter
|
||||||
|
nebeneinander, `.form-full` erzwingt volle Breite für lange Felder).
|
||||||
|
Checkbox-/Radio-Gruppen mit vielen Optionen (Verarbeitungsort, die
|
||||||
|
zwölf Zwecke) sind `.chip-group` — abgerundete Pillen statt einer
|
||||||
|
langen Untereinander-Liste, ausgewählte Chips werden über
|
||||||
|
`:has(input:checked)` blau hervorgehoben (kein JavaScript). Ein
|
||||||
|
Löschen-Button steht nicht mehr einfach unter dem Formular, sondern in
|
||||||
|
einer abgesetzten `.form-gefahrenzone`-Fußzeile der Karte. Dieselben
|
||||||
|
Klassen sind bewusst generisch (nicht an ein Formular gebunden) — noch
|
||||||
|
nicht auf andere Formulare (Login/Registrierung, Fragebogen, übrige
|
||||||
|
Admin-Formulare) angewendet, das wäre der nächste Schritt, falls
|
||||||
|
gewünscht. Beim Umbau auffällig gewordener, vorbestehender Bug: das
|
||||||
|
Lösch-Formular in `betreiber_werkzeug_form.html` war fest auf
|
||||||
|
`/betreiber/werkzeuge/{id}/loeschen` verdrahtet, obwohl dieselbe
|
||||||
|
Vorlage auch vom Mandanten-Formular (`/verwaltung/werkzeuge/...`)
|
||||||
|
genutzt wird — ein Mandant hätte beim Löschen eines eigenen Werkzeugs
|
||||||
|
403 bekommen. Jetzt `{{.ActionBase}}/{{.ID}}/loeschen`, wie die
|
||||||
|
Formular-`action` selbst.
|
||||||
|
|
||||||
**Verifikationsmethode für CSS-Änderungen:** Live-Cookie-Auth per
|
**Verifikationsmethode für CSS-Änderungen:** Live-Cookie-Auth per
|
||||||
Chromium-Headless/CDP ist im Sandbox-Environment nicht möglich (kein
|
Chromium-Headless/CDP ist im Sandbox-Environment nicht möglich (kein
|
||||||
|
|||||||
@@ -26,12 +26,17 @@ func istGueltigerVerarbeitungsort(v string) bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// gueltigeZwecke ist das kontrollierte Vokabular für "geeignete Zwecke"
|
// gueltigeZwecke ist das kontrollierte Vokabular für "geeignete Zwecke"
|
||||||
// — exakt die sechs Zweck-Kategorien aus dem Fragebogen/der geplanten
|
// (siehe CLAUDE.md, Bewertungslogik Schritt 3). Vorher war das Feld
|
||||||
// Zweckabgleich-Stufe (siehe CLAUDE.md, Bewertungslogik Schritt 3).
|
// Freitext; ein Tippfehler ("Text" statt "Textgenerierung") hätte den
|
||||||
// Vorher war das Feld Freitext; ein Tippfehler ("Text" statt
|
// künftigen automatischen Zweckabgleich unbemerkt kaputt gemacht. Am
|
||||||
// "Textgenerierung") hätte den künftigen automatischen Zweckabgleich
|
// 2026-08-31 von sechs auf zwölf Kategorien erweitert (bewusste
|
||||||
// unbemerkt kaputt gemacht.
|
// v1-Scope-Entscheidung überarbeitet, nicht stillschweigend geändert)
|
||||||
var gueltigeZwecke = []string{"Textgenerierung", "Übersetzung", "Code", "Bild", "Transkription", "Recherche"}
|
// — die ursprünglichen sechs deckten nur klassische Wissensarbeit ab,
|
||||||
|
// nicht Datenanalyse/Video/Audio/Kundenservice/Design/Automatisierung.
|
||||||
|
var gueltigeZwecke = []string{
|
||||||
|
"Textgenerierung", "Übersetzung", "Code", "Bild", "Transkription", "Recherche",
|
||||||
|
"Datenanalyse", "Video", "Audio/Sprache", "Kundenservice/Chatbot", "Präsentation/Design", "Automatisierung/Agenten",
|
||||||
|
}
|
||||||
|
|
||||||
func istGueltigerZweck(v string) bool {
|
func istGueltigerZweck(v string) bool {
|
||||||
for _, z := range gueltigeZwecke {
|
for _, z := range gueltigeZwecke {
|
||||||
|
|||||||
@@ -555,6 +555,126 @@ button.entfernen {
|
|||||||
margin: 4px 12px 4px 0;
|
margin: 4px 12px 4px 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* ── Formular-Karten (Enterprise-Look, siehe design/enterprise.css
|
||||||
|
.ant-card/.ant-form-item) ─────────────────────────────────────────
|
||||||
|
Ersetzt "ein Formular = eine flache, ununterbrochene Spalte" durch
|
||||||
|
klar abgegrenzte Abschnitte mit Titel und ein Grid für kurze Felder
|
||||||
|
nebeneinander statt jedes Feld einzeln untereinander. */
|
||||||
|
.form-card {
|
||||||
|
background: #fff;
|
||||||
|
border: 1px solid var(--color-border);
|
||||||
|
border-radius: var(--radius-lg);
|
||||||
|
box-shadow: var(--shadow-sm);
|
||||||
|
margin-bottom: 24px;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-card form {
|
||||||
|
margin-bottom: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-section {
|
||||||
|
border: none;
|
||||||
|
margin: 0;
|
||||||
|
padding: 20px;
|
||||||
|
min-width: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-section + .form-section {
|
||||||
|
border-top: 1px solid var(--color-border);
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-section > legend {
|
||||||
|
padding: 0 0 12px;
|
||||||
|
font-size: 0.9375rem;
|
||||||
|
font-weight: 600;
|
||||||
|
color: var(--color-heading);
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-grid {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: 1fr;
|
||||||
|
gap: 0 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (min-width: 640px) {
|
||||||
|
.form-grid {
|
||||||
|
grid-template-columns: 1fr 1fr;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-grid .form-full {
|
||||||
|
grid-column: 1 / -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Checkbox-/Radio-Gruppen als Chips statt einer langen
|
||||||
|
Untereinander-Liste — v. a. bei den zwölf Zweck-Kategorien war das
|
||||||
|
vorher eine kaum überblickbare Spalte. */
|
||||||
|
.chip-group {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
gap: 8px;
|
||||||
|
margin-top: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.chip-group label {
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 6px;
|
||||||
|
margin-top: 0;
|
||||||
|
padding: 7px 14px;
|
||||||
|
border: 1px solid var(--color-border);
|
||||||
|
border-radius: 999px;
|
||||||
|
font-size: 0.8125rem;
|
||||||
|
font-weight: 500;
|
||||||
|
color: var(--color-text);
|
||||||
|
background: var(--color-bg);
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.chip-group input[type="checkbox"],
|
||||||
|
.chip-group input[type="radio"] {
|
||||||
|
width: auto;
|
||||||
|
min-height: 0;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.chip-group label:has(input:checked) {
|
||||||
|
border-color: var(--branding-primary);
|
||||||
|
background: rgba(22, 119, 255, 0.08);
|
||||||
|
color: var(--branding-primary);
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-actions {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
gap: 12px;
|
||||||
|
padding: 16px 20px;
|
||||||
|
background: var(--color-bg);
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-actions form,
|
||||||
|
.form-actions button {
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-gefahrenzone {
|
||||||
|
border-top: 1px solid var(--color-border);
|
||||||
|
padding: 16px 20px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
gap: 12px;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-gefahrenzone form {
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
.fragebogen fieldset input[type="radio"] {
|
.fragebogen fieldset input[type="radio"] {
|
||||||
width: auto;
|
width: auto;
|
||||||
min-height: 0;
|
min-height: 0;
|
||||||
|
|||||||
@@ -12,61 +12,107 @@
|
|||||||
Pflicht.
|
Pflicht.
|
||||||
</p>
|
</p>
|
||||||
{{if .Error}}<p class="fehler">{{.Error}}</p>{{end}}
|
{{if .Error}}<p class="fehler">{{.Error}}</p>{{end}}
|
||||||
|
<div class="form-card">
|
||||||
<form method="post" action="{{if .ID}}{{.ActionBase}}/{{.ID}}{{else}}{{.ActionBase}}{{end}}">
|
<form method="post" action="{{if .ID}}{{.ActionBase}}/{{.ID}}{{else}}{{.ActionBase}}{{end}}">
|
||||||
<label for="name">Name</label>
|
<fieldset class="form-section">
|
||||||
<input type="text" id="name" name="name" value="{{.Name}}" required>
|
<legend>Grunddaten</legend>
|
||||||
|
<div class="form-grid">
|
||||||
<label for="anbieter">Anbieter</label>
|
<div>
|
||||||
<input type="text" id="anbieter" name="anbieter" value="{{.Anbieter}}" required>
|
<label for="name">Name</label>
|
||||||
|
<input type="text" id="name" name="name" value="{{.Name}}" required>
|
||||||
<fieldset>
|
</div>
|
||||||
<legend>Verarbeitungsort</legend>
|
<div>
|
||||||
{{$gewaehlt := .Verarbeitungsort}}
|
<label for="anbieter">Anbieter</label>
|
||||||
{{range .Verarbeitungsorte}}
|
<input type="text" id="anbieter" name="anbieter" value="{{.Anbieter}}" required>
|
||||||
<label><input type="radio" name="verarbeitungsort" value="{{.}}" {{if eq . $gewaehlt}}checked{{end}} required> {{.}}</label>
|
</div>
|
||||||
{{end}}
|
<div class="form-full">
|
||||||
|
<label>Verarbeitungsort</label>
|
||||||
|
{{$gewaehlt := .Verarbeitungsort}}
|
||||||
|
<div class="chip-group">
|
||||||
|
{{range .Verarbeitungsorte}}
|
||||||
|
<label><input type="radio" name="verarbeitungsort" value="{{.}}" {{if eq . $gewaehlt}}checked{{end}} required> {{.}}</label>
|
||||||
|
{{end}}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</fieldset>
|
</fieldset>
|
||||||
|
|
||||||
<label><input type="checkbox" name="avv_verfuegbar" {{if .AVVVerfuegbar}}checked{{end}}> AVV verfügbar</label>
|
<fieldset class="form-section">
|
||||||
<label for="avv_url">AVV-URL</label>
|
<legend>Rechtliches & Datenschutz</legend>
|
||||||
<input type="text" id="avv_url" name="avv_url" value="{{.AVVURL}}">
|
<div class="form-grid">
|
||||||
|
<div class="form-full">
|
||||||
<label><input type="checkbox" name="training_opt_out" {{if .TrainingOptOut}}checked{{end}}> Training-Opt-out möglich</label>
|
<label>Zusicherungen</label>
|
||||||
<label><input type="checkbox" name="training_standard" {{if .TrainingStandard}}checked{{end}}> Training standardmäßig aus</label>
|
<div class="chip-group">
|
||||||
|
<label><input type="checkbox" name="avv_verfuegbar" {{if .AVVVerfuegbar}}checked{{end}}> AVV verfügbar</label>
|
||||||
<label for="aufbewahrung_tage">Aufbewahrung (Tage, leer lassen wenn vom Anbieter nicht beziffert)</label>
|
<label><input type="checkbox" name="training_opt_out" {{if .TrainingOptOut}}checked{{end}}> Training-Opt-out möglich</label>
|
||||||
<input type="number" id="aufbewahrung_tage" name="aufbewahrung_tage" min="0" value="{{.AufbewahrungTage}}">
|
<label><input type="checkbox" name="training_standard" {{if .TrainingStandard}}checked{{end}}> Training standardmäßig aus</label>
|
||||||
|
</div>
|
||||||
<label for="zertifizierungen">Zertifizierungen (kommagetrennt)</label>
|
</div>
|
||||||
<input type="text" id="zertifizierungen" name="zertifizierungen" value="{{.Zertifizierungen}}">
|
<div class="form-full">
|
||||||
|
<label for="avv_url">AVV-URL</label>
|
||||||
<label for="subprozessoren">Subprozessoren (kommagetrennt, z. B. Anthropic, AWS)</label>
|
<input type="text" id="avv_url" name="avv_url" value="{{.AVVURL}}">
|
||||||
<input type="text" id="subprozessoren" name="subprozessoren" value="{{.Subprozessoren}}">
|
</div>
|
||||||
|
<div>
|
||||||
<fieldset>
|
<label for="aufbewahrung_tage">Aufbewahrung (Tage, leer lassen wenn vom Anbieter nicht beziffert)</label>
|
||||||
<legend>Geeignete Zwecke</legend>
|
<input type="number" id="aufbewahrung_tage" name="aufbewahrung_tage" min="0" value="{{.AufbewahrungTage}}">
|
||||||
{{range .ZweckeOptionen}}
|
</div>
|
||||||
<label><input type="checkbox" name="geeignete_zwecke" value="{{.}}" {{if index $.ZweckeAusgewaehlt .}}checked{{end}}> {{.}}</label>
|
<div>
|
||||||
{{end}}
|
<label for="zertifizierungen">Zertifizierungen (kommagetrennt)</label>
|
||||||
|
<input type="text" id="zertifizierungen" name="zertifizierungen" value="{{.Zertifizierungen}}">
|
||||||
|
</div>
|
||||||
|
<div class="form-full">
|
||||||
|
<label for="subprozessoren">Subprozessoren (kommagetrennt, z. B. Anthropic, AWS)</label>
|
||||||
|
<input type="text" id="subprozessoren" name="subprozessoren" value="{{.Subprozessoren}}">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</fieldset>
|
</fieldset>
|
||||||
|
|
||||||
<label for="einschraenkungen">Einschränkungen (kommagetrennt)</label>
|
<fieldset class="form-section">
|
||||||
<input type="text" id="einschraenkungen" name="einschraenkungen" value="{{.Einschraenkungen}}">
|
<legend>Einsatzbereich</legend>
|
||||||
|
<div class="form-grid">
|
||||||
|
<div class="form-full">
|
||||||
|
<label>Geeignete Zwecke</label>
|
||||||
|
<div class="chip-group">
|
||||||
|
{{range .ZweckeOptionen}}
|
||||||
|
<label><input type="checkbox" name="geeignete_zwecke" value="{{.}}" {{if index $.ZweckeAusgewaehlt .}}checked{{end}}> {{.}}</label>
|
||||||
|
{{end}}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="form-full">
|
||||||
|
<label for="einschraenkungen">Einschränkungen (kommagetrennt)</label>
|
||||||
|
<input type="text" id="einschraenkungen" name="einschraenkungen" value="{{.Einschraenkungen}}">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</fieldset>
|
||||||
|
|
||||||
<label for="letzte_pruefung">Letzte Prüfung</label>
|
<fieldset class="form-section">
|
||||||
<input type="date" id="letzte_pruefung" name="letzte_pruefung" value="{{.LetztePruefung}}" required>
|
<legend>Beleg</legend>
|
||||||
|
<div class="form-grid">
|
||||||
|
<div>
|
||||||
|
<label for="letzte_pruefung">Letzte Prüfung</label>
|
||||||
|
<input type="date" id="letzte_pruefung" name="letzte_pruefung" value="{{.LetztePruefung}}" required>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<label for="quelle">Quelle (Beleg)</label>
|
||||||
|
<input type="text" id="quelle" name="quelle" value="{{.Quelle}}" required>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</fieldset>
|
||||||
|
|
||||||
<label for="quelle">Quelle (Beleg)</label>
|
<div class="form-actions">
|
||||||
<input type="text" id="quelle" name="quelle" value="{{.Quelle}}" required>
|
<button type="submit">Speichern</button>
|
||||||
|
</div>
|
||||||
<button type="submit">Speichern</button>
|
|
||||||
</form>
|
</form>
|
||||||
{{if .ID}}
|
{{if .ID}}
|
||||||
<form method="post" action="/betreiber/werkzeuge/{{.ID}}/loeschen" onsubmit="return confirm('Werkzeug wirklich löschen?')">
|
<div class="form-gefahrenzone">
|
||||||
<button type="submit" class="entfernen">Werkzeug löschen</button>
|
<span class="hinweis">Ein gelöschtes Werkzeug kann nicht wiederhergestellt werden.</span>
|
||||||
</form>
|
<form method="post" action="{{.ActionBase}}/{{.ID}}/loeschen" onsubmit="return confirm('Werkzeug wirklich löschen?')">
|
||||||
|
<button type="submit" class="entfernen">Werkzeug löschen</button>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
{{end}}
|
{{end}}
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
{{end}}
|
{{end}}
|
||||||
|
|||||||
Reference in New Issue
Block a user