feat(editor): Taiga-Story und -Tasks aus dem Knoten-Fenster anlegen (D91, #trk.create)

Zwei Aktionen im Knoten-Fenster, nur wo GET /info das Feature meldet
(Lebendprobe-Muster, je Basis einmal gecacht) und nur an Knoten ohne
Ticket-Referenz — die Ref an der Zeile ist der Idempotenz-Marker.
Login-Dialog (type=password, kein window.prompt; nur das Token landet
im Browser, 401 fragt neu), Projekt-Dialog vorbelegt aus dem geerbten
&taiga.<slug>, Häkchen-Dialog nach der D91-Vorbelegung; Refs und ggf.
das Projekt-Schlagwort gehen undo-fähig als Tokens an die Zeilen
(appendToken: vor %% und vor der Fortsetzungsmarke). Regeln headless in
taiga.js (15 neue Tests); Deploy zieht TAIGA_API_URL aus der .env als
WERKBAUM_TAIGA_API_URL in die Server-Umgebung nach (Nutzerwunsch).

E2E im Browser gegen Backend + Taiga-Stub gemessen: Buttons nur ohne
Ref, Vorbelegung Kundenprojekt aus geerbtem Tag, Refs #US-/#T- an den
richtigen Zeilen, Erledigtes uebersprungen, abweichende Projektwahl
schreibt &taiga.mi-intern zurueck, Undo/Redo je Schreibzug, falsches
Passwort bleibt als Taiga-Fehlertext im Dialog.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
mhoennig
2026-08-27 16:51:10 +02:00
co-authored by Claude Fable 5
parent fd0e730656
commit d1de8758b1
9 changed files with 552 additions and 12 deletions
+4
View File
@@ -19,6 +19,10 @@ reverse.
## 2026-08-27
- Create a Taiga story from a diagram node: the node window offers "create story" and "create story + tasks" — log in once (the token stays in the browser), pick the project, and the ref lands in the line as `#US-123`, undoable
- Sub-packages become Taiga tasks via a checkbox dialog: required and optional children start checked, in `|`/`=` groups only realized alternatives, done children unchecked, discarded ones absent — each created task writes its `#T-…` ref to its line
- The project dialog is prefilled from the inherited `&taiga.slug` keyword, and a creation without or against the inherited assignment writes the keyword back to the node's line
- A node whose line already carries a `#US-…`/`#T-…` token offers no create action — the ref on the line is the idempotency marker
- The backend proxies Taiga through four named endpoints — login, projects, create story, create task; the Taiga API address is server configuration, the token stays in the browser, and `/api/v1/info` says whether the feature is on
- Free `&tag` keywords are part of the notation now: free-standing only, quoted mentions like `(&taiga.slug)` stay labels — and `&taiga.slug` names the Taiga project of a subtree, inherited downwards
- Plans spanning several Taiga projects: a `&taiga.slug` tag names the project per subtree, inherited downwards — the first consumer of the reserved free tags, recorded as planned
+10 -10
View File
@@ -12,9 +12,9 @@
- [^] #not.gates: And/or decomposition (S)
- [^] #not.opt: Optional nodes — neither required nor an alternative (S)
- [^] #not.id: Node IDs, (#auth:) before the title (S) %% often the ticket number, see SPEC §11
+ [~] #not.tag: Free tags, (&tag) (M) %% first consumer found: the Taiga project tag, D91
+ [/] #not.tag: Free tags, (&tag) (M) %% first consumer found: the Taiga project tag, D91
- [?] #not.tag.lens: A lens: highlight every node tagged (&x) (S)
- [~] #not.tag.project: (&taiga.slug) assigns the Taiga project, inherited (S)
- [x] #not.tag.project: (&taiga.slug) assigns the Taiga project, inherited (S)
- [^] #not.dep: Dependencies across the tree, (:#auth,#api) (M)
- [^] #not.dep.status: They constrain the status, not when work may start (S)
- [^] #not.dep.eff: Effective status: intrinsic, plus what it depends on (S)
@@ -199,19 +199,19 @@
- [!] < #idea.drift: A second parser that must not drift from the SPEC (M) %% exactly what D14 warns about
| [?] #idea.drift.fixtures: Both parsers test against the same fixtures (S)
| [?] #idea.drift.js: Run the one JS parser inside the IDE (M)
- [?] #trk: Tracker integration (XL) %% exactly one of these, hence =
= [?] #trk.taiga: Taiga (XL) https://taiga.io
- [~] #trk: Tracker integration (XL) %% exactly one of these, hence =
= [~] #trk.taiga: Taiga (XL) https://taiga.io
- [ ] #trk.resolve: Resolve "#US-123" over the REST API (M)
- [ ] #trk.resolve.read: Read title, link and status (S)
- [ ] #trk.resolve.map: Map the workflow onto the states (S)
- [?] #trk.write: Write the status back (M) :#trk.resolve
- [ ] #trk.create: Create tickets from nodes (XL)
- [/] #trk.create: Create tickets from nodes (XL)
- [x] #trk.create.proxy: Backend proxy with named endpoints (M)
- [ ] #trk.create.login: Log in to Taiga, token stays in the browser (S) :#trk.create.proxy
- [ ] #trk.create.project: The project comes from the inherited tag (S) :#not.tag.project
- [ ] #trk.create.story: A "create story" action in the node window (S) :#trk.create.login
- [ ] #trk.create.tasks: Sub-packages become tasks, picked in a dialog (M) :#trk.create.story
- [ ] #trk.create.ref: The ref lands in the line beside the id (S) :#trk.create.story
- [x] #trk.create.login: Log in to Taiga, token stays in the browser (S) :#trk.create.proxy
- [x] #trk.create.project: The project comes from the inherited tag (S) :#not.tag.project
- [x] #trk.create.story: A "create story" action in the node window (S) :#trk.create.login
- [x] #trk.create.tasks: Sub-packages become tasks, picked in a dialog (M) :#trk.create.story
- [x] #trk.create.ref: The ref lands in the line beside the id (S) :#trk.create.story
- [-] #trk.plugin: A plugin inside Taiga itself (L) %% legacy frontend, self-hosted only
= [?] #trk.tenzu: Tenzu, the successor (XXL) https://tenzu.net
= [ ] #trk.none: No tracker, plain text is enough (XS)