feat(taiga): Ticket verknüpfen — URL/Ref-Feld mit Betreff-Bestätigung (D91-Nachtrag 11)

Ein Knopf im Knoten-Fenster bindet ein bestehendes Taiga-Ticket an den
Knoten: Die eingefügte Ticket-URL trägt Slug, Typ und Nummer selbst; eine
nackte Nummer wird per Probe Story-dann-Task aufgelöst. Verknüpft wird erst
nach Anzeige des Betreffs; geschrieben werden Ref-Token und ggf.
&taiga.<slug> in einem Undo-Schritt, der geholte Stand füllt den
Ticket-Cache. Eine URL einer fremden Instanz wird benannt statt verknüpft.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
mhoennig
2026-08-28 12:48:32 +02:00
co-authored by Claude Opus 5
parent ce657e74c1
commit 1a33ebdac8
8 changed files with 313 additions and 13 deletions
+4
View File
@@ -19,6 +19,10 @@ reverse.
## 2026-08-28
- "Link ticket" in the node window binds an existing Taiga story or task to a node: paste the ticket's URL — it carries project, type and number by itself — or enter a ref or bare number
- A bare number is resolved by probing story then task, and the ticket's subject is shown before anything is written — you link what you saw
- Linking appends the ref and, where needed, the `&taiga.slug` tag in one undo step, and pre-fills the ticket cache so window and divergence mark agree at once
- A ticket URL from a different Taiga instance is named as such instead of silently linking a same-numbered ticket on yours
- One bulk request reads the status of all referenced tickets: the proxy fans the refs out right next to the Taiga instance, so the cost scales with the refs in the plan — not with a project that holds thousands of tickets
- With a Taiga login, diverging tickets show up in the diagram: a ref whose ticket status no longer matches the node's box turns amber — as its own little badge where the ref is the node id and thus not part of the title
- The bulk result pre-fills the node window's ticket cache, so hovering a ticket node usually needs no request of its own any more
+62
View File
@@ -8471,3 +8471,65 @@ lebenden Seite umschreibt, bekommt beim Reload deren Gedächtnis zurück;
wiederhergestellt wird ein Dokument als gewöhnliche Änderung über das
Textfeld. Und der Debug-Reset hängt am `confirm`, das die isolierte Welt
des Prüf-Panes nicht stubben kann (Nachtrag 9) — er ist dort wirkungslos.
**Nachtrag 11 — „Ticket verknüpfen": ein bestehendes Ticket an den Knoten
binden (2026-08-28).** Nutzerwunsch: Wer eine Story oder Task schon in Taiga
hat, soll sie im Werkbaum eintragen können — „klar, kann man einfach
`#US-1234` schreiben, aber der User braucht ja ggf. auch die Taiga
Projekt-ID". Die Antwort auf genau dieses Problem liegt in Taiga selbst:
**Die URL des Tickets trägt alles** — `…/project/<slug>/us/123` bzw.
`…/task/45` enthalten Slug, Typ und Nummer (dieselbe Form, die `ticketUrl`
seit Nachtrag 5 vorwärts baut). Wer auf dem Ticket steht, kopiert die
Adresszeile; die Projekt-Frage stellt sich nicht. Die Entscheidungen
(Multiple-Choice: URL/Ref-Feld, die Such-Ausbaustufe zurückgestellt):
- **Ein Knopf „Taiga: Ticket verknüpfen"** im Knoten-Fenster, neben den
Anlege-Knöpfen und wie sie nur an Knoten ohne Ref (die Ref ist der
Idempotenz-Marker). **Ein Eingabefeld, drei Formen** (`parseTicketInput`,
headless): die Taiga-URL (Slug/Typ/Nummer aus dem Pfad, die
Projekt-Auswahl tritt zurück), eine Ref (`US-123`/`T-45`, `#` und
Kleinschreibung erlaubt, normalisiert) oder eine **nackte Nummer** — so
zeigt Taiga sie. Die ist eindeutig auflösbar: Taigas Zähler läuft je
Projekt über beide Typen gemeinsam (Nachtrag 2), probiert wird Story,
dann Task über die vorhandenen Lese-Endpunkte — genau einer trifft, kein
neuer Backend-Endpunkt.
- **Verknüpft wird, was man gesehen hat:** Aufgelöst wird schon beim Tippen
(400 ms Ruhe, überholte Antworten verwirft ein Zähler), und der
**Betreff steht im Dialog**, bevor der Verknüpfen-Knopf freigibt — eine
blind eingetragene Nummer ist der Fehler, den der Dialog verhindern soll.
Tipp-Zwischenstände sind still (kein Fehler beim halben Token); „kein
Ticket" und Taiga-Fehler stehen im Dialog.
- **Eine URL von einer fremden Taiga-Instanz wird benannt, nicht
verknüpft** (`foreignTaigaUrl` gegen die konfigurierte Web-Basis): Slug
und Nummer würden gegen UNSERE Instanz aufgelöst und träfen dort
womöglich ein fremdes Ticket gleicher Nummer. Ohne Web-Basis ist nichts
zu prüfen — dann wacht die Betreff-Bestätigung allein.
- **Geschrieben wird wie bei der Anlage:** Ref-Token an die Zeile, dazu
`&taiga.<slug>`, wenn der Teilbaum keine oder eine andere Zuordnung hat
(dieselbe Regel wie Nachtrag 3/4), ein Undo-Schritt. Der beim Auflösen
geholte Stand füllt den **Ticket-Cache** gleich mit — Fenster und
Abweichungs-Marke (Nachtrag 10) stimmen ohne weiteren Abruf.
- **Zurückgestellt: die durchsuchbare Ticket-Liste** (Taigas
`/search`-Endpunkt hinter einem neuen Proxy-Weg) — mehr Komfort, ein
eigener Bau; das URL-Feld deckt den Arbeitsfluss ab, in dem man das
Ticket ohnehin vor sich hat.
Der Plan-Knoten `#trk.link` (S) kippte prompt die Größenprüfung des eigenen
Plans (`#trk.taiga` XL mit nun 30+2 ≥ 32, D62) — ehrlich nachgezogen auf
XXL, danach wieder 0 Warnungen (dieselbe Kaskade wie bei D64).
**Nachgemessen** Ende-zu-Ende im Browser gegen das lokale Backend mit
Taiga-Stub (dessen `by_ref` dafür ref-bewusst wurde — 404 auf Unbekanntes,
sonst wäre die Nummer-Probe nicht prüfbar): Die eingefügte Story-URL zeigt
`#US-123 · Login bauen (Taiga-Fassung)` und sperrt die Projekt-Auswahl;
Verknüpfen schreibt `#US-123` an die Zeile OHNE redundantes Schlagwort
(geerbter Slug = gewählter). Die nackte `1234` läuft über US-404 auf
`#T-1234 · API-Teil`. Die fremde Instanz und die fehlende `999` stehen als
Meldung im Dialog, der Knopf bleibt gesperrt. Eine Ref mit abweichender
Projektwahl schreibt `&taiga.mi-intern #US-123`. Das Fenster des
verknüpften Knotens zeigt den Stand aus dem Cache (0 weitere
`by_ref`-Abfragen im Stub-Mitschnitt) samt der Abweichungs-Knöpfe; zwei
Undos nehmen die beiden Verknüpfungen je in einem Schritt zurück. 628
Frontend-Tests (11 neue); Gegenproben per Mutation: Kleinschreibung aus dem
Ref-Muster → genau der Normalisierungs-Test fällt, URL-Wächter aus
`foreignTaigaUrl` → genau der danach benannte.
+6
View File
@@ -1416,6 +1416,12 @@ wird sie von selbst die ID. Erstreckt sich ein Plan über **mehrere**
Taiga-Projekte, benennt das Schlagwort `&taiga.<slug>` (unten) das Projekt
je Teilbaum — eine Ref wird gegen das Projekt des nächsten Vorfahren mit so
einem Tag aufgelöst. Siehe D91-Nachträge 2 und 3.
An die Zeile kommt die Ref beim **Anlegen** eines Tickets aus dem Knoten
ebenso wie beim **Verknüpfen** mit einem bestehenden — dort genügt als
Eingabe die Taiga-URL des Tickets, die Projekt, Typ und Nummer selbst trägt;
eine nackte Nummer wird per Probe aufgelöst (Story, dann Task — Taigas
Zähler ist je Projekt gemeinsam). Verknüpft wird erst nach Anzeige des
Betreffs (D91-Nachtrag 11).
Der **Stand** eines so bezeichneten Tickets (Betreff, Status, Zuständiger)
wird im Knoten-Fenster gezeigt (§9); weicht er von der Statusbox ab, sind
dort beide Richtungen als ausdrückliche Aktionen zu haben — von selbst
+10 -1
View File
@@ -200,7 +200,7 @@
| [?] #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.taiga: Taiga (XXL) 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)
@@ -216,6 +216,7 @@
- [^] #trk.create.tasks: Sub-packages become tasks, picked in a dialog (M) :#trk.create.story
- [^] #trk.create.task: A dialog-free "create task" under a story ancestor (S) :#trk.create.tasks,#trk.resolve.read
- [^] #trk.create.ref: The ref lands in the line beside the id (S) :#trk.create.story
- [x] #trk.link: Link an existing ticket to a node (S) :#trk.resolve.read
- [^] #trk.open: Open a ticket ref in Taiga (S) :#trk.create.ref,#not.tag.project
- [-] #trk.plugin: A plugin inside Taiga itself (L) %% legacy frontend, self-hosted only
= [?] #trk.tenzu: Tenzu, the successor (XXL) https://tenzu.net
@@ -1199,6 +1200,14 @@
on touch. Needs the instance's web address (server configuration,
reported by /info) and the inherited &taiga.slug project (D91-Nachtrag 5).
#trk.link
"Link ticket" in the node window binds an EXISTING Taiga ticket to a
node: paste the ticket's URL — it carries project, type and number by
itself — or enter a ref or bare number, resolved by probing story then
task. The subject is shown before anything is written; linking appends
the ref token and, where needed, the &taiga.slug tag, one undo step
(D91-Nachtrag 11).
#trk.create.proxy
A few named endpoints in the Werkbaum backend (auth, projects, user
stories, tasks) relay to the Taiga instance configured server-side. No