diff --git a/server/pruef-bewerbung.mjs b/server/pruef-bewerbung.mjs index 5613d888..bfdcba10 100644 --- a/server/pruef-bewerbung.mjs +++ b/server/pruef-bewerbung.mjs @@ -437,6 +437,92 @@ melde("=== 8. Wie man hinkommt ==="); /* ======================================================================= 9. DIE OBERFLÄCHE ======================================================================= */ +melde(""); +/* ======================================================================= + 8b. WER SICH KUEMMERT (17.09.2026) + + Filipe wollte die Arbeit mit der rechten Hand teilen. Gemessen: Es + gab dafuer nichts -- beide sehen jede Anfrage, niemand ist benannt. + Bei einer Anfrage ist das teurer als anderswo: Dort wartet ein + Mensch auf eine Antwort. + + DREI DINGE WERDEN GEPRUEFT, und das dritte ist das eigentliche: + 1. Uebernehmen und abgeben mit demselben Knopf. + 2. Der Zustaendige steht in der Liste. + 3. Eine FREMDE Uebernahme wird abgewiesen -- sonst nimmt einer dem + anderen die Anfrage aus der Hand, ohne dass es jemand merkt. + + Und der Riegel: Wer den Eingang nicht sehen darf, darf sich auch + nicht zustaendig erklaeren. Diese Zeile hat beim Schreiben GEFEHLT + (der Router setzt `angemeldet` fuer den ganzen Pfad, `nurLeitung` + aber je Route) -- gefunden beim Nachsehen der Nachbarzeilen, nicht + beim Schreiben. + ======================================================================= */ +melde(""); +melde("=== 8b. Wer sich kuemmert ==="); +{ + let liste = alsJson(await holen("/workspace/api/bewerbungen", kDogi)); + const offen = (liste.bewerbungen || []).find((b) => b.zustand === "neu") + || (liste.bewerbungen || [])[0]; + ok(!!offen, `eine Anfrage zum Uebernehmen (${offen?.nenn_name})`); + /* DIE ANZAHL GEHOERT IN DIE BEDINGUNG. Beim ersten Lauf war die + Liste leer, und diese Zeile war trotzdem gruen -- `undefined` ist + nun einmal kein Zustaendiger. Eine Pruefung, die ohne Daten + bestaetigt, bestaetigt nichts. */ + ok(!!offen && !offen.zustaendig_id, "um die sich noch niemand kuemmert"); + + { + const r = await schicken(`/workspace/api/bewerbung/${offen.id}/kuemmern`, kDogi, null, "PUT"); + ok(r.code === 200 && alsJson(r).zustaendig === true, `uebernehmen geht (${r.code})`); + liste = alsJson(await holen("/workspace/api/bewerbungen", kDogi)); + const b = (liste.bewerbungen || []).find((x) => x.id === offen.id); + ok(b?.zustaendig_name === "Filipe", + `und es steht in der Liste (${b?.zustaendig_name})`); + ok(!!b?.zustaendig_seit, `mit dem Zeitpunkt (${b?.zustaendig_seit?.slice(0, 10)})`); + } + + /* DER FALL, AUF DEN ES ANKOMMT */ + { + const r = await schicken(`/workspace/api/bewerbung/${offen.id}/kuemmern`, kHand, null, "PUT"); + ok(r.code === 409, `die rechte Hand nimmt sie ihm nicht aus der Hand (${r.code})`); + ok((alsJson(r).fehler || "").includes("Filipe"), + `und erfaehrt, wer sich kuemmert ("${alsJson(r).fehler}")`); + liste = alsJson(await holen("/workspace/api/bewerbungen", kDogi)); + const b = (liste.bewerbungen || []).find((x) => x.id === offen.id); + ok(b?.zustaendig_name === "Filipe", "der Zustaendige bleibt unveraendert"); + } + + /* Abgeben -- und dann kann der andere */ + { + await schicken(`/workspace/api/bewerbung/${offen.id}/kuemmern`, kDogi, null, "PUT"); + liste = alsJson(await holen("/workspace/api/bewerbungen", kDogi)); + let b = (liste.bewerbungen || []).find((x) => x.id === offen.id); + ok(!b?.zustaendig_id, "derselbe Knopf gibt wieder ab"); + const r = await schicken(`/workspace/api/bewerbung/${offen.id}/kuemmern`, kHand, null, "PUT"); + ok(r.code === 200, `jetzt kann die rechte Hand (${r.code})`); + liste = alsJson(await holen("/workspace/api/bewerbungen", kDogi)); + b = (liste.bewerbungen || []).find((x) => x.id === offen.id); + ok(b?.zustaendig_name === "Rieke", `und steht dort (${b?.zustaendig_name})`); + /* Zurueck auf Anfang, damit Abschnitt 9 die Karten unveraendert + vorfindet -- eine Pruefung, die der naechsten den Zustand + verstellt, macht deren Ergebnis unlesbar. */ + await schicken(`/workspace/api/bewerbung/${offen.id}/kuemmern`, kHand, null, "PUT"); + } + + /* DER RIEGEL. Wer den Eingang nicht sehen darf, darf sich auch nicht + zustaendig erklaeren -- sonst haengt ein Name an einer Anfrage, der + dort nichts zu suchen hat, und sie gilt als betreut, waehrend sich + niemand kuemmert. */ + for (const [wer, keks] of [["ein Modi", kModi], ["ein Zugang aus der Community", kKessi]]) { + const r = await schicken(`/workspace/api/bewerbung/${offen.id}/kuemmern`, keks, null, "PUT"); + ok(r.code === 404, `${wer} kann sich nicht zustaendig erklaeren (${r.code})`); + } + { + const r = await schicken("/workspace/api/bewerbung/999999/kuemmern", kDogi, null, "PUT"); + ok(r.code === 404, `eine erfundene Nummer wird abgewiesen (${r.code})`); + } +} + melde(""); melde("=== 9. Im echten Browser ==="); { diff --git a/server/pruef-nachruesten.mjs b/server/pruef-nachruesten.mjs index 87d18645..bb74da1d 100644 --- a/server/pruef-nachruesten.mjs +++ b/server/pruef-nachruesten.mjs @@ -75,7 +75,8 @@ const ALT = ["eintrag_id", "stufe", "seit", "von_id", "notiz", "buddy_id", "erst Talentkarte und angelegtem Zugang) und wird hier mitgefuehrt: Jede neue Spalte gehoert in diese Liste, sonst prueft die Datei den Weg von gestern. */ -const NEU = ["beendet_am", "beendet_grund", "beendet_von", "person_id"]; +const NEU = ["beendet_am", "beendet_grund", "beendet_von", "person_id", + "zustaendig_id", "zustaendig_seit"]; { const d = new DatabaseSync(process.env.WORKSPACE_DB); diff --git a/server/pruef-nachwuchs.mjs b/server/pruef-nachwuchs.mjs index 4b1a8b88..9e164354 100644 --- a/server/pruef-nachwuchs.mjs +++ b/server/pruef-nachwuchs.mjs @@ -1586,6 +1586,86 @@ melde("=== 17. Der Anschluss im Browser ==="); } } +/* ======================================================================= + 19. WER SICH KUEMMERT (17.09.2026) + + Filipe wollte die Arbeit mit der rechten Hand teilen. Gemessen: Es + gab dafuer nichts -- beide sehen jeden Kandidaten, niemand ist + benannt. Das ist nicht „geteilt", das ist „jeder dachte, der andere + macht es". Bei einem Kandidaten heisst das: Er bleibt auf seiner + Stufe liegen, die Standzeit waechst, und die Karte sagt zwar DASS + etwas liegt, aber nicht, wer es aufheben sollte. + + DER WICHTIGSTE FALL IST DER DRITTE: Eine fremde Uebernahme wird + ABGEWIESEN, nicht stillschweigend ueberschrieben. Sonst nimmt einer + dem anderen den Kandidaten aus der Hand, ohne dass es jemand merkt + -- und beide glauben, es sei erledigt. + ======================================================================= */ +melde(""); +melde("=== 19. Wer sich kuemmert ==="); +{ + const neuer = await roh("/workspace/api/bereich/talente", HAUS, { cookie: kDogi }, + { art: "ruhig", titel: "Sami aus dem Chat", text: "Faellt auf." }); + ok(neuer.code === 201 || neuer.code === 200, `ein Kandidat dafuer (${neuer.code})`); + + const finde = async (keks, haus) => (json(await roh("/workspace/api/talente/lage", + haus, { cookie: keks })).kandidaten || []).find((k) => k.titel === "Sami aus dem Chat"); + + let k = await finde(kDogi, HAUS); + ok(k?.zustaendig === null, + `am Anfang kuemmert sich niemand (${JSON.stringify(k?.zustaendig)})`); + + /* ---- Uebernehmen ---- */ + { + const r = await roh(`/workspace/api/talente/${k.id}/kuemmern`, HAUS, + { cookie: kDogi }, null, "PUT"); + ok(r.code === 200 && json(r).zustaendig === true, `uebernehmen geht (${r.code})`); + k = await finde(kDogi, HAUS); + ok(k.zustaendig?.name === "Filipe", `und es steht dabei, wer (${k.zustaendig?.name})`); + ok(k.zustaendig?.tage === 0, `seit wann (${k.zustaendig?.tage} Tage)`); + } + + /* ---- DER FALL, AUF DEN ES ANKOMMT ---- */ + { + const r = await roh(`/workspace/api/talente/${k.id}/kuemmern`, CREW, + { cookie: kHand }, null, "PUT"); + ok(r.code === 409, + `die rechte Hand kann ihn nicht aus der Hand nehmen (${r.code})`); + ok((json(r).fehler || "").includes("Filipe"), + `und erfaehrt, wer sich kuemmert ("${json(r).fehler}")`); + /* GEGENPROBE ZUR WIRKUNG: nichts halb passiert. */ + k = await finde(kDogi, HAUS); + ok(k.zustaendig?.name === "Filipe", "der Zustaendige bleibt unveraendert"); + } + + /* ---- Abgeben, dann kann der andere ---- */ + { + const r = await roh(`/workspace/api/talente/${k.id}/kuemmern`, HAUS, + { cookie: kDogi }, null, "PUT"); + ok(r.code === 200 && json(r).zustaendig === false, `derselbe Knopf gibt ab (${r.code})`); + k = await finde(kDogi, HAUS); + ok(k.zustaendig === null, "danach kuemmert sich wieder niemand"); + + const r2 = await roh(`/workspace/api/talente/${k.id}/kuemmern`, CREW, + { cookie: kHand }, null, "PUT"); + ok(r2.code === 200, `jetzt kann die rechte Hand uebernehmen (${r2.code})`); + const kh = await finde(kHand, CREW); + ok(kh?.zustaendig?.name === "Rieke", `und steht dort (${kh?.zustaendig?.name})`); + } + + /* ---- Die Community kommt nicht heran ---- */ + { + const r = await roh(`/workspace/api/talente/${k.id}/kuemmern`, CREW, + { cookie: kModi }, null, "PUT"); + ok(r.code === 404, `ein Modi kann sich nicht zustaendig erklaeren (${r.code})`); + } + { + const r = await roh("/workspace/api/talente/999999/kuemmern", HAUS, + { cookie: kDogi }, null, "PUT"); + ok(r.code === 404, `eine erfundene Nummer wird abgewiesen (${r.code})`); + } +} + /* ------------------------------------------------------------------- */ melde(""); melde(`${geprueft} Pruefungen, ${fehler} Fehler` diff --git a/server/workspace-bewerbung.js b/server/workspace-bewerbung.js index d812fe54..de854fad 100644 --- a/server/workspace-bewerbung.js +++ b/server/workspace-bewerbung.js @@ -123,6 +123,40 @@ export function tabellen() { Kommt eine Frage dazu, braucht es keine Schemaänderung -- und eine entfernte Frage lässt die alten Antworten stehen, statt sie unlesbar zu machen. */ + /* ===================================================================== + WER SICH KUEMMERT (17.09.2026) + + Filipe wollte die Arbeit mit der rechten Hand teilen. Bis heute + gab es dafuer nichts: Beide sehen jede Anfrage, niemand ist + benannt. Das ist nicht „geteilt", das ist „jeder dachte, der + andere macht es" -- und bei einer Anfrage wartet ein Mensch + darauf. + + MAN NIMMT SELBST, MAN BEKOMMT NICHT ZUGETEILT. Ein „DogFather + weist zu" waere eine Rangordnung, und die gehoert hier nicht hin + (Filipe, 18.08.2026: „mich bitte nie wie da hoeher stellen wie + andere"). Wer Zeit hat, uebernimmt; wer keine mehr hat, gibt ab. + + ALS SPALTE UND NICHT ALS EIGENE TABELLE: Es ist genau eine Zahl je + Anfrage. Eine Tabelle dafuer waere ein Verbund mehr bei jeder + Abfrage und keine einzige zusaetzliche Antwort. + + `ON DELETE SET NULL`: Geht jemand, faellt seine Anfrage zurueck in + „kuemmert sich niemand" -- sichtbar, statt an einen Namen gebunden + zu bleiben, den es nicht mehr gibt. */ + for (const [spalte, typ] of [ + ["zustaendig_id", "INTEGER"], + ["zustaendig_seit", "TEXT"], + ]) { + try { + const da = db().prepare("PRAGMA table_info(bewerbungen)").all().map((z) => z.name); + if (!da.includes(spalte)) { + db().exec(`ALTER TABLE bewerbungen ADD COLUMN ${spalte} ${typ}`); + console.log(`[anfragen] Spalte '${spalte}' ergaenzt.`); + } + } catch (f) { console.error(`[anfragen] Spalte '${spalte}':`, f?.message); } + } + db().exec("CREATE INDEX IF NOT EXISTS idx_bewerbung_zustand ON bewerbungen (zustand, id DESC)"); db().exec("CREATE INDEX IF NOT EXISTS idx_bewerbung_person ON bewerbungen (person_id, id DESC)"); entwicklungTabellen(); @@ -312,6 +346,69 @@ bewerbungRouter.post("/workspace/api/bewerbung", express.json({ limit: "64kb" }) und im Zwischenspeicher des Browsers landet er trotzdem. ===================================================================== */ bewerbungRouter.use("/workspace/api/bewerbungen-zahl", angemeldet); +/* ===================================================================== + ICH KUEMMERE MICH (17.09.2026) + + EIN KNOPF, ZWEI RICHTUNGEN -- wie bei den Merkmalen und den + Probeschritten. Wer schon zustaendig ist, gibt mit demselben Knopf + wieder ab. Zwei getrennte Wege waeren zwei Knoepfe, von denen immer + einer nichts tut. + + MAN NIMMT SELBST, MAN BEKOMMT NICHT ZUGETEILT. Ein „DogFather weist + zu" waere eine Rangordnung, und die gehoert hier nicht hin. Wer Zeit + hat, uebernimmt; wer keine mehr hat, gibt ab. + + EINE FREMDE UEBERNAHME WIRD ABGEWIESEN, nicht stillschweigend + ueberschrieben: Sonst nimmt einer dem anderen die Anfrage aus der + Hand, ohne dass es jemand merkt -- und beide glauben, sie sei + erledigt. Wer wirklich uebernehmen will, laesst erst abgeben. + ===================================================================== */ +bewerbungRouter.put("/workspace/api/bewerbung/:id/kuemmern", gleicheHerkunft, + /* `nurLeitung` GEHOERT HIERHIN und ist beim Schreiben gefehlt. + + Der Router setzt oben `angemeldet` fuer den ganzen Pfad, aber NICHT + `nurLeitung` -- das haengt an jeder einzelnen Route (siehe die + beiden darunter). Ohne diese Zeile haette sich jeder Angemeldete + fuer eine fremde Anfrage zustaendig erklaeren koennen: kein + Datenabfluss, aber ein Name an einer Anfrage, der dort nichts zu + suchen hat -- und die Anfrage gilt als betreut, waehrend sich + niemand kuemmert. Gefunden beim Nachsehen der Nachbarzeilen. */ + nurLeitung, (req, res) => { + try { + /* `Number` und eine eigene Pruefung -- diese Datei hat keinen + `nummer`-Helfer, und ein Aufruf darauf waere ein Absturz zur + Laufzeit gewesen (node --check sieht das nicht). Gefunden beim + Nachsehen, nicht beim Schreiben. */ + const id = Number(req.params.id); + if (!Number.isInteger(id) || id <= 0) { + return res.status(404).json({ fehler: "nicht_gefunden" }); + } + const b = id && db().prepare( + "SELECT id, zustaendig_id FROM bewerbungen WHERE id = ?").get(id); + if (!b) return res.status(404).json({ fehler: "nicht_gefunden" }); + + if (b.zustaendig_id && b.zustaendig_id !== req.person.id) { + const wer = db().prepare("SELECT name FROM personen WHERE id = ?") + .get(b.zustaendig_id); + return res.status(409).json({ + fehler: `Darum kümmert sich schon ${wer?.name || "jemand"}.`, + }); + } + + const nehmen = !b.zustaendig_id; + db().prepare("UPDATE bewerbungen SET zustaendig_id = ?, zustaendig_seit = ? WHERE id = ?") + .run(nehmen ? req.person.id : null, nehmen ? jetzt() : null, id); + protokolliere(nehmen ? "anfrage_uebernommen" : "anfrage_abgegeben", { + personId: req.person.id, rolle: req.person.rolle, ip: echteIp(req), + detail: `#${id}`, + }); + res.json({ ok: true, zustaendig: nehmen }); + } catch (f) { + console.error("[anfragen] Kuemmern:", f?.message); + res.status(503).json({ fehler: "nicht_verfuegbar" }); + } + }); + bewerbungRouter.get("/workspace/api/bewerbungen-zahl", nurLeitung, (req, res) => { try { const z = db().prepare( @@ -335,11 +432,16 @@ bewerbungRouter.get("/workspace/api/bewerbungen", nurLeitung, (req, res) => { const zeilen = db().prepare(` SELECT b.id, b.person_id, b.nenn_name, b.zustand, b.erstellt, b.grund, b.entschieden_am, b.eintrag_id, + /* WER SICH KUEMMERT -- oder niemand. Die zweite Antwort ist + die wichtigere: Eine Anfrage, um die sich niemand + kuemmert, soll das sagen. */ + b.zustaendig_id, b.zustaendig_seit, z.name AS zustaendig_name, p.name AS konto_name, p.rolle AS konto_rolle, e.name AS von_name FROM bewerbungen b LEFT JOIN personen p ON p.id = b.person_id LEFT JOIN personen e ON e.id = b.entschieden_von + LEFT JOIN personen z ON z.id = b.zustaendig_id ORDER BY /* NEUE ZUERST, DANN WAS LIEGT. Die Reihenfolge ist die Arbeitsanweisung dieser Seite -- wie bei den Talenten. */ diff --git a/server/workspace-entwicklung.js b/server/workspace-entwicklung.js index 3108a30a..6aa2ad86 100644 --- a/server/workspace-entwicklung.js +++ b/server/workspace-entwicklung.js @@ -285,6 +285,19 @@ export function tabellen() { gekommen ist, und das bleibt wahr, auch wenn er wieder geht. Ein CASCADE haette genau diesen Verlauf mitgeloescht. */ ["person_id", "INTEGER"], + + /* WER SICH UM DIESEN KANDIDATEN KUEMMERT (17.09.2026). + + Dieselbe Luecke wie bei den Anfragen, nur teurer: Ein Kandidat, + fuer den sich niemand zustaendig fuehlt, bleibt auf seiner Stufe + liegen -- und die Standzeit an der Karte sagt zwar, DASS etwas + liegt, aber nicht, wer es aufheben sollte. + + `zustaendig_seit` kommt mit: „seit gestern uebernommen" und „seit + drei Wochen uebernommen" sind zwei verschiedene Auskuenfte, und + die zweite ist die, die man sehen will. */ + ["zustaendig_id", "INTEGER"], + ["zustaendig_seit", "TEXT"], ]) { try { const da = db().prepare("PRAGMA table_info(talent_stufe)").all().map((s) => s.name); @@ -983,10 +996,12 @@ function talentKarte(e, merkmale) { const stand = db().prepare( `SELECT s.stufe, s.seit, s.notiz, s.buddy_id, s.erste_schicht, s.beendet_am, s.beendet_grund, p.name AS beendet_von_name, - s.person_id, w.name AS person_name, w.aktiv AS person_aktiv + s.person_id, w.name AS person_name, w.aktiv AS person_aktiv, + s.zustaendig_id, s.zustaendig_seit, z.name AS zustaendig_name FROM talent_stufe s LEFT JOIN personen p ON p.id = s.beendet_von LEFT JOIN personen w ON w.id = s.person_id + LEFT JOIN personen z ON z.id = s.zustaendig_id WHERE s.eintrag_id = ?`) .get(e.id); const stufe = talentStufe(stand?.stufe) || TALENT_STUFEN[0]; @@ -1053,6 +1068,15 @@ function talentKarte(e, merkmale) { der Karte nicht aussehen wie einer, der laeuft. Die Karte bleibt trotzdem stehen -- sie erzaehlt, wie jemand gekommen ist, und das bleibt wahr, auch wenn er wieder geht. */ + /* WER SICH KUEMMERT -- oder niemand. `null` ist hier die wichtigere + Antwort von beiden: Eine Karte, um die sich niemand kuemmert, + soll das sagen. */ + zustaendig: stand?.zustaendig_id && stand?.zustaendig_name ? { + id: stand.zustaendig_id, + name: stand.zustaendig_name, + seit: stand.zustaendig_seit, + tage: tageSeit(stand.zustaendig_seit), + } : null, person: stand?.person_id && stand?.person_name ? { id: stand.person_id, name: stand.person_name, @@ -1381,6 +1405,63 @@ entwicklungRouter.put("/workspace/api/talente/:id/beenden", gleicheHerkunft, } }); +/* ===================================================================== + ICH KUEMMERE MICH (17.09.2026) + + Dieselbe Frage wie bei den Anfragen, nur teurer: Ein Kandidat, fuer + den sich niemand zustaendig fuehlt, bleibt auf seiner Stufe liegen. + Die Standzeit sagt, DASS etwas liegt -- nicht, wer es aufheben + sollte. + + EIN KNOPF, ZWEI RICHTUNGEN. Und eine fremde Uebernahme wird + abgewiesen statt ueberschrieben: Sonst nimmt einer dem anderen den + Kandidaten aus der Hand, ohne dass es jemand merkt. + ===================================================================== */ +entwicklungRouter.put("/workspace/api/talente/:id/kuemmern", gleicheHerkunft, + (req, res) => { + try { + const id = nummer(req.params.id); + const e = id && db().prepare( + "SELECT id, bereich FROM eintraege WHERE id = ?").get(id); + if (!e || e.bereich !== "talente") return res.status(404).json({ fehler: "nicht_gefunden" }); + + const stand = db().prepare( + "SELECT zustaendig_id FROM talent_stufe WHERE eintrag_id = ?").get(id); + if (stand?.zustaendig_id && stand.zustaendig_id !== req.person.id) { + const wer = db().prepare("SELECT name FROM personen WHERE id = ?") + .get(stand.zustaendig_id); + return res.status(409).json({ + fehler: `Darum kümmert sich schon ${wer?.name || "jemand"}.`, + }); + } + + const nehmen = !stand?.zustaendig_id; + const nun = jetzt(); + if (stand) { + db().prepare(`UPDATE talent_stufe SET zustaendig_id = ?, zustaendig_seit = ? + WHERE eintrag_id = ?`) + .run(nehmen ? req.person.id : null, nehmen ? nun : null, id); + } else { + /* Noch keine Stufenzeile -- die entsteht erst beim ersten + Schritt. Wer sich vorher kuemmern will, soll das koennen: + „Ich sehe ihn mir an" ist der haeufigste erste Schritt + ueberhaupt, und er faellt sonst durch. */ + db().prepare(`INSERT INTO talent_stufe + (eintrag_id, stufe, seit, von_id, zustaendig_id, zustaendig_seit) + VALUES (?, 'aufgefallen', ?, ?, ?, ?)`) + .run(id, nun, req.person.id, req.person.id, nun); + } + protokolliere(nehmen ? "talent_uebernommen" : "talent_abgegeben", { + personId: req.person.id, rolle: req.person.rolle, ip: echteIp(req), + detail: `#${id}`, + }); + res.json({ ok: true, zustaendig: nehmen }); + } catch (f) { + console.error("[talente] Kuemmern:", f?.message); + res.status(503).json({ fehler: "nicht_verfuegbar" }); + } + }); + /* WIEDER AUFNEHMEN -- und der alte Grund bleibt stehen. Menschen aendern sich; ein "damals zu wenig Zeit" ist in einem Jahr diff --git a/workspace/app.webmanifest b/workspace/app.webmanifest index 31c02c43..7a6d065e 100644 --- a/workspace/app.webmanifest +++ b/workspace/app.webmanifest @@ -22,25 +22,25 @@ }, "icons": [ { - "src": "/assets/img/app-symbole/workspace-192.png?v=202609180100", + "src": "/assets/img/app-symbole/workspace-192.png?v=202609180146", "sizes": "192x192", "type": "image/png", "purpose": "any" }, { - "src": "/assets/img/app-symbole/workspace-512.png?v=202609180100", + "src": "/assets/img/app-symbole/workspace-512.png?v=202609180146", "sizes": "512x512", "type": "image/png", "purpose": "any" }, { - "src": "/assets/img/app-symbole/workspace-192-maskable.png?v=202609180100", + "src": "/assets/img/app-symbole/workspace-192-maskable.png?v=202609180146", "sizes": "192x192", "type": "image/png", "purpose": "maskable" }, { - "src": "/assets/img/app-symbole/workspace-512-maskable.png?v=202609180100", + "src": "/assets/img/app-symbole/workspace-512-maskable.png?v=202609180146", "sizes": "512x512", "type": "image/png", "purpose": "maskable" diff --git a/workspace/assets/css/bewerbung.css b/workspace/assets/css/bewerbung.css index a9caf7e7..fa75f607 100644 --- a/workspace/assets/css/bewerbung.css +++ b/workspace/assets/css/bewerbung.css @@ -272,3 +272,51 @@ background: color-mix(in srgb, var(--akzent) 10%, transparent); } .bw-tor__wort { margin: 0; font-size: .95rem; } + +/* ===================================================================== + WER SICH KÜMMERT (17.09.2026) + + Bis heute sahen DogFather und die rechte Hand jede Anfrage, und + niemand war benannt. Das ist nicht „geteilt", das ist „jeder dachte, + der andere macht es" -- und hier wartet ein Mensch darauf. + + DER UNBESETZTE ZUSTAND IST DER AUFFÄLLIGE. „Ich kümmere mich" steht + als Knopf da; wer schon übernommen hat, sieht eine ruhige Zeile. + Andersherum wäre die Liste ein Feld aus Namen, in dem die Lücke + nicht auffällt -- und genau die Lücke ist die Auskunft. + ===================================================================== */ +.bw-kuemmern { + display: flex; flex-wrap: wrap; align-items: center; gap: 8px 12px; + margin-top: 10px; +} + +.bw-kuemmern__knopf { + min-height: 38px; + padding: 7px 15px; + border: 1px solid color-mix(in srgb, var(--akzent) 45%, var(--rand)); + border-radius: 999px; + background: color-mix(in srgb, var(--tinte) 90%, #ffffff 10%); + color: color-mix(in srgb, var(--akzent) 30%, #ffffff); + font: inherit; font-size: .84rem; font-weight: 600; + cursor: pointer; + transition: border-color .16s ease, color .16s ease; +} +.bw-kuemmern__knopf:hover { border-color: var(--akzent); color: #ffffff; } +.bw-kuemmern__knopf:focus-visible { outline: 2px solid var(--akzent); outline-offset: 2px; } + +/* Schon übernommen: ruhiger. Es ist eine Auskunft, keine Aufforderung. */ +.bw-kuemmern[data-wer="ich"] .bw-kuemmern__knopf { + border-color: color-mix(in srgb, var(--gut, #79d1a2) 45%, var(--rand)); + color: color-mix(in srgb, var(--gut, #79d1a2) 30%, #ffffff); +} +/* Fremd: kein Ziel mehr, also sieht es auch nicht danach aus. Ein + Knopf, der aussieht wie einer und nichts tut, ist eine Falle. */ +.bw-kuemmern[data-wer="anderer"] .bw-kuemmern__knopf { + border-style: dashed; + border-color: var(--rand); + background: none; + color: var(--text-still); + cursor: default; +} +.bw-kuemmern__seit { font-size: .78rem; color: var(--text-still); } + diff --git a/workspace/assets/css/entwicklung.css b/workspace/assets/css/entwicklung.css index b7703246..d19ba407 100644 --- a/workspace/assets/css/entwicklung.css +++ b/workspace/assets/css/entwicklung.css @@ -1398,3 +1398,44 @@ .e-herkunft__weg:focus-visible { outline: 2px solid var(--akzent); outline-offset: 3px; } .e-herkunft__buddy { color: var(--text-still); } +/* ===================================================================== + WER SICH UM DIESEN KANDIDATEN KÜMMERT (17.09.2026) + + Die Standzeit oben sagt, DASS etwas liegt -- nicht, wer es aufheben + sollte. Diese Zeile beantwortet die zweite Hälfte. + + Sie steht weit oben an der Karte, direkt unter dem Kopf: Wer die + Liste überfliegt, sucht genau danach. + ===================================================================== */ +.t-kuemmern { + display: flex; flex-wrap: wrap; align-items: center; gap: 8px 12px; + margin: 10px 0 2px; +} + +.t-kuemmern__knopf { + min-height: 38px; + padding: 7px 15px; + border: 1px solid color-mix(in srgb, var(--akzent) 45%, var(--rand)); + border-radius: 999px; + background: color-mix(in srgb, var(--tinte) 90%, #ffffff 10%); + color: color-mix(in srgb, var(--akzent) 30%, #ffffff); + font: inherit; font-size: .84rem; font-weight: 600; + cursor: pointer; + transition: border-color .16s ease, color .16s ease; +} +.t-kuemmern__knopf:hover { border-color: var(--akzent); color: #ffffff; } +.t-kuemmern__knopf:focus-visible { outline: 2px solid var(--akzent); outline-offset: 2px; } + +.t-kuemmern[data-wer="ich"] .t-kuemmern__knopf { + border-color: color-mix(in srgb, var(--gut, #79d1a2) 45%, var(--rand)); + color: color-mix(in srgb, var(--gut, #79d1a2) 30%, #ffffff); +} +.t-kuemmern[data-wer="anderer"] .t-kuemmern__knopf { + border-style: dashed; + border-color: var(--rand); + background: none; + color: var(--text-still); + cursor: default; +} +.t-kuemmern__seit { font-size: .78rem; color: var(--text-still); } + diff --git a/workspace/assets/js/bewerbungen.js b/workspace/assets/js/bewerbungen.js index 3615c4e2..7e808884 100644 --- a/workspace/assets/js/bewerbungen.js +++ b/workspace/assets/js/bewerbungen.js @@ -52,6 +52,11 @@ }; let daten = null; + /* WER BIN ICH? Nötig, um „Du kümmerst dich" von „jemand anderes + kümmert sich" zu unterscheiden. Ein Vergleich über den NAMEN wäre + der naheliegende Fehler: Zwei Leute dürfen gleich heißen, und dann + gibt der eine dem anderen die Anfrage aus der Hand. */ + let ich = null; const zeichnen = () => { /* ---------- Die Zahlen oben ---------- */ @@ -109,6 +114,60 @@ kopf.append(el('span', 'bw-marke', ZUSTAND_WORT[b.zustand] || b.zustand)); karte.append(kopf); + /* ---- WER SICH KÜMMERT (17.09.2026) ------------------------------ + + Bis heute sahen DogFather und die rechte Hand jede Anfrage, und + niemand war benannt. Das ist nicht „geteilt", das ist „jeder + dachte, der andere macht es" -- und hier wartet ein Mensch + darauf. + + MAN NIMMT SELBST. Kein „zuweisen": Das wäre eine Rangordnung, + und die gehört hier nicht hin. Wer Zeit hat, übernimmt. + + DER UNBESETZTE ZUSTAND IST DER AUFFÄLLIGE. „Kümmert sich + niemand" steht als Knopf da, „Du kümmerst dich" als ruhige + Zeile. Andersherum wäre die Liste ein Feld aus Namen, in dem + die Lücke nicht auffällt -- und genau die Lücke ist die + Auskunft. */ + if (b.zustand !== 'angenommen' && b.zustand !== 'abgelehnt') { + const kum = el('div', 'bw-kuemmern'); + const meins = b.zustaendig_id === ich?.id; + if (b.zustaendig_id) kum.dataset.wer = meins ? 'ich' : 'anderer'; + + const knopf = el('button', 'bw-kuemmern__knopf'); + knopf.type = 'button'; + knopf.textContent = b.zustaendig_id + ? (meins ? 'Du kümmerst dich · abgeben' : `${b.zustaendig_name} kümmert sich`) + : 'Ich kümmere mich'; + /* Fremdes bleibt stehen -- wer es trotzdem will, lässt erst + abgeben. Ein Knopf, der fremdes Zuständigsein still + überschreibt, nimmt dem anderen die Anfrage aus der Hand. */ + knopf.disabled = !!b.zustaendig_id && !meins; + knopf.addEventListener('click', async () => { + knopf.disabled = true; + melde(''); + try { + const a2 = await fetch(`/workspace/api/bewerbung/${b.id}/kuemmern`, { + method: 'PUT', credentials: 'same-origin', + }); + if (!a2.ok) { + const d = await a2.json().catch(() => ({})); + melde(d.fehler || 'Ging nicht.'); + knopf.disabled = false; + return; + } + await laden(); + } catch { melde('Ging nicht.'); knopf.disabled = false; } + }); + kum.append(knopf); + if (b.zustaendig_seit) { + kum.append(el('span', 'bw-kuemmern__seit', 'seit ' + liegtSeit( + Math.max(0, Math.floor( + (Date.now() - Date.parse(b.zustaendig_seit)) / 86400000))))); + } + karte.append(kum); + } + /* ---- Was schon entschieden wurde ---- */ if (b.zustand !== 'neu' && (b.grund || b.von_name)) { const alt = el('div', 'bw-karte__frueher'); @@ -241,6 +300,12 @@ }; const laden = async () => { + if (!ich) { + try { + const i = await fetch('/workspace/api/ich', { credentials: 'same-origin' }); + if (i.ok) { ich = await i.json(); window.werZeigen?.(ich); } + } catch { /* dann bleibt der Vergleich aus -- kein Absturz */ } + } let a; try { a = await fetch('/workspace/api/bewerbungen', { credentials: 'same-origin' }); diff --git a/workspace/assets/js/talente.js b/workspace/assets/js/talente.js index e336e12f..d5068dc1 100644 --- a/workspace/assets/js/talente.js +++ b/workspace/assets/js/talente.js @@ -61,6 +61,11 @@ Ein Wert, der zu frueh gerechnet wird, ist dauerhaft falsch -- der Knopf waere nie erschienen. */ let darfListe = null; + /* WER BIN ICH? Für die Unterscheidung „Du kümmerst dich" gegen + „jemand anderes kümmert sich". Verglichen wird über die NUMMER, + nicht über den Namen: Zwei Leute dürfen gleich heißen, und dann + nimmt der eine dem anderen den Kandidaten aus der Hand. */ + let ich = null; const darfAnlegen = () => Array.isArray(darfListe) && !!lage?.zugang?.rolle && darfListe.includes(lage.zugang.rolle); const offen = new Set(); // welche Karten aufgeklappt sind @@ -105,6 +110,53 @@ } a.append(kopf); + /* ---- WER SICH KÜMMERT (17.09.2026) -------------------------------- + + Dieselbe Lücke wie bei den Anfragen, nur teurer: Ein Kandidat, + für den sich niemand zuständig fühlt, bleibt auf seiner Stufe + liegen. Die Standzeit oben sagt, DASS etwas liegt -- nicht, wer + es aufheben sollte. + + MAN NIMMT SELBST, MAN BEKOMMT NICHT ZUGETEILT. Ein „DogFather + weist zu" wäre eine Rangordnung, und die gehört hier nicht hin. + + AN JEDER STUFE, AUCH IM TEAM. Gerade in den ersten Wochen nach + der Aufnahme ist die Frage „wer schaut nach ihm?" die wichtigste + -- und sie ist etwas anderes als der Buddy, der die Schicht + begleitet. */ + if (!k.beendet) { + const kum = el('div', 't-kuemmern'); + const meins = k.zustaendig?.id === ich?.id; + if (k.zustaendig) kum.dataset.wer = meins ? 'ich' : 'anderer'; + + const knopf = el('button', 't-kuemmern__knopf'); + knopf.type = 'button'; + knopf.textContent = k.zustaendig + ? (meins ? 'Du kümmerst dich · abgeben' : `${k.zustaendig.name} kümmert sich`) + : 'Ich kümmere mich'; + knopf.disabled = !!k.zustaendig && !meins; + knopf.addEventListener('click', async () => { + knopf.disabled = true; + melde(''); + try { + const r = await hole(`/workspace/api/talente/${k.id}/kuemmern`, { method: 'PUT' }); + if (!r.ok) { + melde(absage(await r.json().catch(() => ({})))); + knopf.disabled = false; + return; + } + await laden(); + } catch { melde('Ging nicht.'); knopf.disabled = false; } + }); + kum.append(knopf); + if (k.zustaendig?.tage !== null && k.zustaendig?.tage !== undefined) { + kum.append(el('span', 't-kuemmern__seit', + k.zustaendig.tage === 0 ? 'seit heute' + : `seit ${k.zustaendig.tage} ${k.zustaendig.tage === 1 ? 'Tag' : 'Tagen'}`)); + } + a.append(kum); + } + if (k.einsatz) a.append(el('p', 't-karte__wo', k.einsatz)); if (k.text) a.append(el('p', 't-karte__text', k.text)); @@ -1147,7 +1199,7 @@ try { const a = await hole('/workspace/api/ich'); if (!a.ok) return; - const ich = await a.json(); + ich = await a.json(); window.werZeigen?.(ich); darfListe = ich?.darf_anlegen; } catch { /* umgeleitet */ } diff --git a/workspace/aufgaben.html b/workspace/aufgaben.html index ccec8bdf..6c922bfc 100644 --- a/workspace/aufgaben.html +++ b/workspace/aufgaben.html @@ -12,19 +12,19 @@ Ton wie die Kopfleiste darunter (#06090f), damit Leiste und Seite eine Flaeche sind statt zweier. --> - - - - - - + + + + + + - + @@ -291,10 +291,10 @@ - - - - - + + + + + diff --git a/workspace/automation.html b/workspace/automation.html index ddb35285..41f93e37 100644 --- a/workspace/automation.html +++ b/workspace/automation.html @@ -12,20 +12,20 @@ Ton wie die Kopfleiste darunter (#06090f), damit Leiste und Seite eine Flaeche sind statt zweier. --> - - - - - - - + + + + + + + - + @@ -168,10 +168,10 @@ - - - - - + + + + + diff --git a/workspace/befinden.html b/workspace/befinden.html index ab62f204..f815200e 100644 --- a/workspace/befinden.html +++ b/workspace/befinden.html @@ -7,14 +7,14 @@ - - - - - - - - + + + + + + + + @@ -105,9 +105,9 @@ - - - - + + + + diff --git a/workspace/bereich.html b/workspace/bereich.html index 38ef0bfe..d858bf71 100644 --- a/workspace/bereich.html +++ b/workspace/bereich.html @@ -12,24 +12,24 @@ Ton wie die Kopfleiste darunter (#06090f), damit Leiste und Seite eine Flaeche sind statt zweier. --> - - - - - - + + + + + + - - + + - + @@ -243,14 +243,14 @@ - - - - - - - - - + + + + + + + + + diff --git a/workspace/bewerben.html b/workspace/bewerben.html index 0db38efc..390cb350 100644 --- a/workspace/bewerben.html +++ b/workspace/bewerben.html @@ -7,17 +7,17 @@ - - - - - - - - - + + + + + + + + + - + @@ -107,10 +107,10 @@ - - - - - + + + + + diff --git a/workspace/bewerbungen.html b/workspace/bewerbungen.html index 9c5e7afc..fe19a1ef 100644 --- a/workspace/bewerbungen.html +++ b/workspace/bewerbungen.html @@ -7,16 +7,16 @@ - - - - - - - - + + + + + + + + - + @@ -80,10 +80,10 @@ - - - - - + + + + + diff --git a/workspace/calls.html b/workspace/calls.html index c4f7b5ef..92fec800 100644 --- a/workspace/calls.html +++ b/workspace/calls.html @@ -12,20 +12,20 @@ Ton wie die Kopfleiste darunter (#06090f), damit Leiste und Seite eine Flaeche sind statt zweier. --> - - - - - - - + + + + + + + - + @@ -89,11 +89,11 @@ - - - - - - + + + + + + diff --git a/workspace/chat.html b/workspace/chat.html index 9013bf7d..ced5105c 100644 --- a/workspace/chat.html +++ b/workspace/chat.html @@ -12,26 +12,26 @@ Ton wie die Kopfleiste darunter (#06090f), damit Leiste und Seite eine Flaeche sind statt zweier. --> - - - - + + + + - - - + + + - + @@ -341,10 +341,10 @@ - - - - - + + + + + diff --git a/workspace/content.html b/workspace/content.html index ffcd0a34..c3669d95 100644 --- a/workspace/content.html +++ b/workspace/content.html @@ -12,20 +12,20 @@ Ton wie die Kopfleiste darunter (#06090f), damit Leiste und Seite eine Flaeche sind statt zweier. --> - - - - - - - + + + + + + + - + @@ -179,12 +179,12 @@ - - - - - - - + + + + + + + diff --git a/workspace/crew-index.html b/workspace/crew-index.html index 365f5b9d..2978719a 100644 --- a/workspace/crew-index.html +++ b/workspace/crew-index.html @@ -36,15 +36,15 @@ - - - + + + - + @@ -339,6 +339,6 @@ - + diff --git a/workspace/crew.webmanifest b/workspace/crew.webmanifest index a83e8c0f..375f9777 100644 --- a/workspace/crew.webmanifest +++ b/workspace/crew.webmanifest @@ -22,25 +22,25 @@ }, "icons": [ { - "src": "/assets/img/app-symbole/crew-192.png?v=202609180100", + "src": "/assets/img/app-symbole/crew-192.png?v=202609180146", "sizes": "192x192", "type": "image/png", "purpose": "any" }, { - "src": "/assets/img/app-symbole/crew-512.png?v=202609180100", + "src": "/assets/img/app-symbole/crew-512.png?v=202609180146", "sizes": "512x512", "type": "image/png", "purpose": "any" }, { - "src": "/assets/img/app-symbole/crew-192-maskable.png?v=202609180100", + "src": "/assets/img/app-symbole/crew-192-maskable.png?v=202609180146", "sizes": "192x192", "type": "image/png", "purpose": "maskable" }, { - "src": "/assets/img/app-symbole/crew-512-maskable.png?v=202609180100", + "src": "/assets/img/app-symbole/crew-512-maskable.png?v=202609180146", "sizes": "512x512", "type": "image/png", "purpose": "maskable" diff --git a/workspace/dateien.html b/workspace/dateien.html index 70aeeaca..9a2c393c 100644 --- a/workspace/dateien.html +++ b/workspace/dateien.html @@ -12,20 +12,20 @@ Ton wie die Kopfleiste darunter (#06090f), damit Leiste und Seite eine Flaeche sind statt zweier. --> - - - - - - - + + + + + + + - + @@ -108,10 +108,10 @@ - - - - - + + + + + diff --git a/workspace/entwicklung.html b/workspace/entwicklung.html index c2d876fe..b255719b 100644 --- a/workspace/entwicklung.html +++ b/workspace/entwicklung.html @@ -7,14 +7,14 @@ - - - - - - - - + + + + + + + + @@ -102,9 +102,9 @@ - - - - + + + + diff --git a/workspace/index.html b/workspace/index.html index 95e53d72..6c4461ff 100644 --- a/workspace/index.html +++ b/workspace/index.html @@ -30,9 +30,9 @@ - - - + + + @@ -401,6 +401,6 @@ - + diff --git a/workspace/kalender.html b/workspace/kalender.html index b53d96ae..f632d823 100644 --- a/workspace/kalender.html +++ b/workspace/kalender.html @@ -12,20 +12,20 @@ Ton wie die Kopfleiste darunter (#06090f), damit Leiste und Seite eine Flaeche sind statt zweier. --> - - - - - - - + + + + + + + - + @@ -377,11 +377,11 @@ - - - - - - + + + + + + diff --git a/workspace/leistung.html b/workspace/leistung.html index 70593a43..c05da9e8 100644 --- a/workspace/leistung.html +++ b/workspace/leistung.html @@ -12,20 +12,20 @@ Ton wie die Kopfleiste darunter (#06090f), damit Leiste und Seite eine Flaeche sind statt zweier. --> - - - - - - - + + + + + + + - + @@ -444,10 +444,10 @@ - - - - - + + + + + diff --git a/workspace/personen.html b/workspace/personen.html index bd434794..44d14b41 100644 --- a/workspace/personen.html +++ b/workspace/personen.html @@ -12,20 +12,20 @@ Ton wie die Kopfleiste darunter (#06090f), damit Leiste und Seite eine Flaeche sind statt zweier. --> - - - - - - - + + + + + + + - + @@ -423,10 +423,10 @@ - - - - - + + + + + diff --git a/workspace/profil.html b/workspace/profil.html index b1f9beef..a2b4bca8 100644 --- a/workspace/profil.html +++ b/workspace/profil.html @@ -12,20 +12,20 @@ Ton wie die Kopfleiste darunter (#06090f), damit Leiste und Seite eine Flaeche sind statt zweier. --> - - - - - - - + + + + + + + - + @@ -214,11 +214,11 @@ - - - - - - + + + + + + diff --git a/workspace/rechte.html b/workspace/rechte.html index f894f616..e1ab0a47 100644 --- a/workspace/rechte.html +++ b/workspace/rechte.html @@ -7,14 +7,14 @@ - - - - - - - - + + + + + + + + @@ -134,9 +134,9 @@ Beim ersten Anlauf fehlte die Zeile auf genau diesen beiden neuen Seiten. Gefunden hat das nicht das Auge, sondern pruef-css-klassen, die seit dem 07.09. jede Seite danach absucht. --> - - - - + + + + diff --git a/workspace/report.html b/workspace/report.html index 46a9eb01..b015a5da 100644 --- a/workspace/report.html +++ b/workspace/report.html @@ -12,20 +12,20 @@ Ton wie die Kopfleiste darunter (#06090f), damit Leiste und Seite eine Flaeche sind statt zweier. --> - - - - - - - + + + + + + + - + @@ -106,11 +106,11 @@ - - - - - - + + + + + + diff --git a/workspace/scouting.html b/workspace/scouting.html index 35fd5658..1e36911b 100644 --- a/workspace/scouting.html +++ b/workspace/scouting.html @@ -12,20 +12,20 @@ Ton wie die Kopfleiste darunter (#06090f), damit Leiste und Seite eine Flaeche sind statt zweier. --> - - - - - - - + + + + + + + - + @@ -173,10 +173,10 @@ - - - - - + + + + + diff --git a/workspace/start.html b/workspace/start.html index 5efea766..1b0e2a46 100644 --- a/workspace/start.html +++ b/workspace/start.html @@ -12,21 +12,21 @@ Ton wie die Kopfleiste darunter (#06090f), damit Leiste und Seite eine Flaeche sind statt zweier. --> - - - - + + + + - - + + - + @@ -674,10 +674,10 @@

- - - - - + + + + + diff --git a/workspace/startcheck.html b/workspace/startcheck.html index 70da5438..844985c2 100644 --- a/workspace/startcheck.html +++ b/workspace/startcheck.html @@ -12,20 +12,20 @@ Ton wie die Kopfleiste darunter (#06090f), damit Leiste und Seite eine Flaeche sind statt zweier. --> - - - - - - - + + + + + + + - + @@ -85,11 +85,11 @@ - - - - - - + + + + + + diff --git a/workspace/steckbrief.html b/workspace/steckbrief.html index 9cdcc8fb..1577bad2 100644 --- a/workspace/steckbrief.html +++ b/workspace/steckbrief.html @@ -12,20 +12,20 @@ Ton wie die Kopfleiste darunter (#06090f), damit Leiste und Seite eine Flaeche sind statt zweier. --> - - - - - - - + + + + + + + - + @@ -146,11 +146,11 @@ - - - - - - + + + + + + diff --git a/workspace/talente.html b/workspace/talente.html index b3647f69..1e2d48ea 100644 --- a/workspace/talente.html +++ b/workspace/talente.html @@ -7,18 +7,18 @@ - - - - - - + + + + + + - - - + + + @@ -111,9 +111,9 @@ - - - - + + + + diff --git a/workspace/team.html b/workspace/team.html index 342615c8..cfedaf63 100644 --- a/workspace/team.html +++ b/workspace/team.html @@ -7,20 +7,20 @@ - - - - - - - + + + + + + + - + @@ -110,10 +110,10 @@ - - - - - + + + + + diff --git a/workspace/teamlage.html b/workspace/teamlage.html index 094382ad..4c626ed7 100644 --- a/workspace/teamlage.html +++ b/workspace/teamlage.html @@ -7,20 +7,20 @@ - - - - - - - + + + + + + + - + - - - - + + + + diff --git a/workspace/teilen.html b/workspace/teilen.html index a0e404f7..db95a177 100644 --- a/workspace/teilen.html +++ b/workspace/teilen.html @@ -7,13 +7,13 @@ - - - - - - - + + + + + + + @@ -112,9 +112,9 @@ - - - - + + + + diff --git a/workspace/treff-moderation.html b/workspace/treff-moderation.html index d871d13e..8f4e1d28 100644 --- a/workspace/treff-moderation.html +++ b/workspace/treff-moderation.html @@ -7,14 +7,14 @@ - - - - - - - - + + + + + + + + @@ -126,9 +126,9 @@ - - - - + + + + diff --git a/workspace/treff-regeln.html b/workspace/treff-regeln.html index 42c0b1cb..a914916c 100644 --- a/workspace/treff-regeln.html +++ b/workspace/treff-regeln.html @@ -7,18 +7,18 @@ - - - - - - - + + + + + + + - + @@ -211,10 +211,10 @@ Beim ersten Anlauf fehlte die Zeile auf genau diesen beiden neuen Seiten. Gefunden hat das nicht das Auge, sondern pruef-css-klassen, die seit dem 07.09. jede Seite danach absucht. --> - - - - - + + + + + diff --git a/workspace/uebersicht.html b/workspace/uebersicht.html index ccff5833..42ae2038 100644 --- a/workspace/uebersicht.html +++ b/workspace/uebersicht.html @@ -12,22 +12,22 @@ Ton wie die Kopfleiste darunter (#06090f), damit Leiste und Seite eine Flaeche sind statt zweier. --> - - - - + + + + - - - + + + - + @@ -149,11 +149,11 @@ - + - - - - + + + + diff --git a/workspace/wissen.html b/workspace/wissen.html index 5a09971b..958abf3f 100644 --- a/workspace/wissen.html +++ b/workspace/wissen.html @@ -12,20 +12,20 @@ Ton wie die Kopfleiste darunter (#06090f), damit Leiste und Seite eine Flaeche sind statt zweier. --> - - - - - - - + + + + + + + - + @@ -190,10 +190,10 @@ - - - - - + + + + +