diff --git a/docs/CHANGELOG.md b/docs/CHANGELOG.md index acdb6d1..ff2c80c 100644 --- a/docs/CHANGELOG.md +++ b/docs/CHANGELOG.md @@ -19,6 +19,8 @@ reverse. ## 2026-08-28 +- The Taiga buttons in the node window sit side by side in one row now — the window grows a little wider for them, and they wrap only when space truly runs out +- The open button moved into the ticket box's action row, next to write and take, and its label shrank to "Open #US-123" — the neighbours say where - "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 diff --git a/docs/DECISIONS.md b/docs/DECISIONS.md index bd526da..14587d8 100644 --- a/docs/DECISIONS.md +++ b/docs/DECISIONS.md @@ -8533,3 +8533,38 @@ 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. + +**Nachtrag 12 — die Taiga-Knöpfe stehen in einer Zeile (2026-08-28).** +Nutzerwunsch: nebeneinander, „mehrzeilig nur, wenn der Platz nicht +ausreicht". Genau das ist flex-wrap — und trotzdem stapelten die Knöpfe +praktisch immer, aus zwei Gründen, beide gemessen statt geraten: + +- **Zwei getrennte Container:** Schreiben/Übernehmen saßen in der + `tk-act`-Zeile der Ticket-Box, der ↗-Öffnen-Knopf in einem eigenen + `.nodetip-taiga` darunter — immer zwei Zeilen, unabhängig vom Platz. + Jetzt gibt es EINE Aktions-Zeile: `paintTicket` baut sie, `paintDiff` + füllt seine Knöpfe hinein, der Öffnen-Knopf kommt dazu (und steht damit + auch im Idle-/Fehler-Fall neben „Stand holen" bzw. ↻). Nebengewinn: Weil + der Knopf jetzt IN der Ticket-Box lebt, ist „in Taiga" in seinem Label + redundant geworden — `taigaOpenBtn` heißt in allen neun Sprachen nur noch + „{ref} öffnen"; den Kontext sagen die Nachbarknöpfe. +- **Das Fenster war zu schmal:** 21rem (336px) sind das Maß für + Text-Fenster; schon zwei deutsche Knöpfe brauchten mehr. Mit Taiga-Knöpfen + trägt das Fenster die Klasse `tipwide` (max. 31rem, weiter durch + `100vw − 24px` geklemmt) — die Zahl ist gemessen, nicht geschätzt: Die + drei deutschen Anlege-Knöpfe brauchen 425px, die Abweichungs-Zeile mit + gekürztem Öffnen-Knopf 440px, beide passen in die 454px Innenbreite; + bei 30rem fehlten der zweiten Zeile genau 4px. Die Klasse wird beim + Fenster-Aufbau auch wieder HERUNTERGENOMMEN — das Element wird + wiederverwendet, sonst bliebe ein Text-Fenster breit. + +Umbrochen wird weiterhin, wo der Platz wirklich fehlt (Telefon: die Klemme +auf `100vw − 24px` greift, gemessen 351px bei 375px Breite; sehr lange Refs +ebenso) — genau die Ausnahme, die der Wunsch benennt. + +**Nachgemessen** im Browser gegen Backend + Stub, deutsche Oberfläche (die +längsten Labels): drei Anlege-Knöpfe eine Zeile, „→ nach Taiga schreiben · +← aus Taiga übernehmen · ↗ #US-123 öffnen" eine Zeile (Fenster 484px); ein +Ref-Knoten ohne Projekt-Slug (keine Knöpfe) fällt auf 336px zurück — +`tipwide` ist weg. 628 Tests unverändert (reine UI-Verdrahtung, +Browser-geprüft — die D54-Nachtrag-3-Grenze). diff --git a/frontend/src/app.js b/frontend/src/app.js index 1a57c5d..9434dac 100644 --- a/frontend/src/app.js +++ b/frontend/src/app.js @@ -1823,6 +1823,11 @@ function taigaTicketUrl(lineNo){ } function appendTaigaActions(el){ + /* Mit Taiga-Knöpfen darf das Fenster breiter werden (`tipwide`), damit die + Aktionen NEBENEINANDER stehen; umgebrochen wird erst, wenn der Platz + wirklich nicht reicht (flex-wrap). Die Klasse muss hier auch wieder + heruntergenommen werden — das Fenster-Element wird wiederverwendet. */ + nodeTip.classList.remove('tipwide'); if(!taigaOn) return; const line = +el.dataset.line; if(!line) return; @@ -1833,22 +1838,14 @@ function appendTaigaActions(el){ const ref = ticketRefOf(node); if(ref){ /* Der Knoten IST schon angelegt (Idempotenz-Marker) — statt der - Anlage-Knöpfe gibt es den Stand des Tickets und den Weg dorthin. Der - Slug (SPEC §1) trägt das Lesen, die Web-Basis das Öffnen: Fehlt eines, - entfällt nur dessen Hälfte. */ + Anlage-Knöpfe gibt es den Stand des Tickets, und in dessen + Aktions-Zeile sitzt auch der ↗-Öffnen-Knopf (paintTicket): eine + Zeile für alle Taiga-Knöpfe. Der Slug (SPEC §1) trägt das Lesen, + die Web-Basis das Öffnen — fehlt eines, entfällt nur dessen Hälfte. */ const slug = taigaSlugs(roots).get(node); - const url = ticketUrl(taigaWeb, slug, ref); - if(slug) nodeTipBody.appendChild(ticketBox(el, slug, ref, line)); - /* Als Knopf im Fenster ist der Link auch auf Touch erreichbar (dort gibt - es kein Strg) und macht die Strg+Klick-Geste nebenbei auffindbar - (D25-Lehre). */ - if(url){ - const b = document.createElement('button'); - b.type = 'button'; b.className = 'nodetip-taigabtn'; b.tabIndex = -1; - b.textContent = '↗ ' + t('taigaOpenBtn', {ref: '#' + ref}); - b.addEventListener('click', () => { closeNodeTip(); window.open(url, '_blank', 'noopener'); }); - wrap.appendChild(b); - nodeTipBody.appendChild(wrap); + if(slug){ + nodeTipBody.appendChild(ticketBox(el, slug, ref, line)); + nodeTip.classList.add('tipwide'); } return; } @@ -1870,6 +1867,7 @@ function appendTaigaActions(el){ wrap.appendChild(mk(t('taigaTaskBtn'), taigaTask)); wrap.appendChild(mk(t('taigaLinkBtn'), taigaLink)); nodeTipBody.appendChild(wrap); + nodeTip.classList.add('tipwide'); } /* ---------- Ticket-Stand im Knoten-Fenster (D91-Nachtrag 6) ---------- @@ -1938,11 +1936,32 @@ function paintTicket(box, key, slug, ref, lineNo){ box.appendChild(head); if(st.data.subject) line('tk-line', st.data.subject); if(st.data.assignee) line('tk-line', t('taigaTicketAssignee', {name: st.data.assignee})); - paintDiff(box, line, st, key, slug, ref, lineNo); + /* EINE Aktions-Zeile für alle Knöpfe — Schreiben/Übernehmen (paintDiff) + und der ↗-Öffnen-Knopf nebeneinander; flex-wrap bricht erst um, wenn + der Platz nicht reicht. Der Öffnen-Knopf ist auf Touch der einzige + Weg zum Ticket (kein Strg) und macht die Strg+Klick-Geste + auffindbar (D25-Lehre). */ + const act = document.createElement('div'); + act.className = 'tk-act'; + paintDiff(box, line, st, key, slug, ref, lineNo, act); + const u = ticketUrl(taigaWeb, slug, ref); + if(u) act.appendChild(openBtn(u, ref)); + if(act.childNodes.length) box.appendChild(act); return; } if(st.kind === 'err') line('tk-err', st.msg); - box.appendChild(reloadBtn(key, slug, ref, st.kind === 'err')); + const act = document.createElement('div'); + act.className = 'tk-act'; + act.appendChild(reloadBtn(key, slug, ref, st.kind === 'err')); + const u = ticketUrl(taigaWeb, slug, ref); + if(u) act.appendChild(openBtn(u, ref)); + box.appendChild(act); +} + +/* Der ↗-Knopf zum Ticket im Taiga-Frontend (D91-Nachtrag 5). */ +function openBtn(url, ref){ + return mkBtn('↗ ' + t('taigaOpenBtn', {ref: '#' + ref}), + () => { closeNodeTip(); window.open(url, '_blank', 'noopener'); }); } /* Die Abweichung und ihre zwei Knöpfe (D91-Nachtrag 7): Sagen Ticket und @@ -1950,7 +1969,7 @@ function paintTicket(box, key, slug, ref, lineNo){ ausdrücklich angeboten — von selbst geschieht nichts, in keine Richtung. Verglichen wird nur, was abbildbar ist: Ein unbekannter Spaltenname (oben unabgebildet) sagt nichts über den Plan. */ -function paintDiff(box, line, st, key, slug, ref, lineNo){ +function paintDiff(box, line, st, key, slug, ref, lineNo, act){ const ticket = mapTaigaStatus(st.data.status); if(!ticket) return; const eigen = ownStatusOfLine(lineNo); @@ -1969,12 +1988,11 @@ function paintDiff(box, line, st, key, slug, ref, lineNo){ } box.appendChild(d); - const act = document.createElement('div'); - act.className = 'tk-act'; /* Schreiben geht nur für die fünf abgebildeten Zustände (D91-Nachtrag 7); `[?]`, `[!]`, `[-]` und der neutrale Knoten lassen das Ticket unangetastet — und das Fenster sagt, warum. Ohne gelesene `version` - fehlt Taigas Sperre; dann wird nicht angeboten. */ + fehlt Taigas Sperre; dann wird nicht angeboten. Die Knöpfe gehen in + die GEMEINSAME Aktions-Zeile des Aufrufers (`act`). */ const ziel = eigen ? taigaStatusName(eigen.code) : null; if(ziel && st.data.version != null){ act.appendChild(mkBtn('→ ' + t('taigaTicketPush'), @@ -1982,7 +2000,6 @@ function paintDiff(box, line, st, key, slug, ref, lineNo){ } act.appendChild(mkBtn('← ' + t('taigaTicketPull'), () => pullStatus(lineNo, ticket.code))); - box.appendChild(act); if(!ziel) line('tk-line', t('taigaTicketNoMap')); } @@ -3267,7 +3284,7 @@ const I18N = { acHint:"{n} ID-Vorschläge – ↑/↓ wählt, Enter übernimmt", tipClose:"Schließen", tipOpenLink:"Link öffnen", - taigaStoryBtn:"Taiga: Story anlegen", taigaTaskBtn:"Taiga: Task anlegen", taigaTaskNoProject:"Kein Zugriff auf das Projekt „{slug}“.", taigaLoginTitle:"Bei Taiga anmelden", taigaUser:"Benutzername", taigaPass:"Passwort", taigaLoginDo:"Anmelden", taigaCancel:"Abbrechen", taigaProjectTitle:"Taiga-Ticket anlegen", taigaProject:"Projekt", taigaTasksPick:"Teilpakete als Tasks anlegen:", taigaCreateDo:"Anlegen", taigaError:"Fehlgeschlagen: {error}", taigaOpenBtn:"{ref} in Taiga öffnen", taigaLinkBtn:"Taiga: Ticket verknüpfen", taigaLinkTitle:"Taiga-Ticket verknüpfen", taigaLinkDo:"Verknüpfen", taigaLinkHint:"Taiga-URL oder Ref (US-123, T-45, 123)", taigaLinkNotFound:"Kein Ticket {ref} im Projekt „{slug}“.", taigaLinkForeign:"Die Adresse gehört zu einer anderen Taiga-Instanz.",taigaTicketDiff:"weicht vom Plan ab:", taigaTicketNoBox:"ohne Statusbox", taigaTicketPush:"nach Taiga schreiben", taigaTicketPull:"aus Taiga übernehmen", taigaTicketWriting:"wird geschrieben …", taigaTicketNoMap:"Dieser Zustand hat in Taiga keine Entsprechung — geschrieben wird nichts.", taigaTicketNoColumn:"Die Spalte „{name}“ gibt es in diesem Projekt nicht.", taigaTicketFetch:"Stand holen", taigaTicketReload:"Stand neu holen", taigaTicketLoading:"Stand wird geholt …", taigaTicketAssignee:"Zuständig: {name}", + taigaStoryBtn:"Taiga: Story anlegen", taigaTaskBtn:"Taiga: Task anlegen", taigaTaskNoProject:"Kein Zugriff auf das Projekt „{slug}“.", taigaLoginTitle:"Bei Taiga anmelden", taigaUser:"Benutzername", taigaPass:"Passwort", taigaLoginDo:"Anmelden", taigaCancel:"Abbrechen", taigaProjectTitle:"Taiga-Ticket anlegen", taigaProject:"Projekt", taigaTasksPick:"Teilpakete als Tasks anlegen:", taigaCreateDo:"Anlegen", taigaError:"Fehlgeschlagen: {error}", taigaOpenBtn:"{ref} öffnen", taigaLinkBtn:"Taiga: Ticket verknüpfen", taigaLinkTitle:"Taiga-Ticket verknüpfen", taigaLinkDo:"Verknüpfen", taigaLinkHint:"Taiga-URL oder Ref (US-123, T-45, 123)", taigaLinkNotFound:"Kein Ticket {ref} im Projekt „{slug}“.", taigaLinkForeign:"Die Adresse gehört zu einer anderen Taiga-Instanz.",taigaTicketDiff:"weicht vom Plan ab:", taigaTicketNoBox:"ohne Statusbox", taigaTicketPush:"nach Taiga schreiben", taigaTicketPull:"aus Taiga übernehmen", taigaTicketWriting:"wird geschrieben …", taigaTicketNoMap:"Dieser Zustand hat in Taiga keine Entsprechung — geschrieben wird nichts.", taigaTicketNoColumn:"Die Spalte „{name}“ gibt es in diesem Projekt nicht.", taigaTicketFetch:"Stand holen", taigaTicketReload:"Stand neu holen", taigaTicketLoading:"Stand wird geholt …", taigaTicketAssignee:"Zuständig: {name}", liveLoadWarn:"Server-Dokument nicht geladen: {url} ({error}). Läuft das Backend, und ist die Adresse eine Dokument-Adresse (…/documents/<uuid>)?", liveStaleWarn:"Deine Änderung war nicht mehr anwendbar ({error}) — der Stand wurde einmal frisch geholt.", liveConflictText:"Jemand hat dieselben Zeilen geändert. Wessen Fassung soll gelten?", @@ -3404,7 +3421,7 @@ const I18N = { acHint:"{n} id suggestions – ↑/↓ to choose, Enter to insert", tipClose:"Close", tipOpenLink:"Open link", - taigaStoryBtn:"Taiga: create story", taigaTaskBtn:"Taiga: create task", taigaTaskNoProject:"No access to project “{slug}”.", taigaLoginTitle:"Log in to Taiga", taigaUser:"Username", taigaPass:"Password", taigaLoginDo:"Log in", taigaCancel:"Cancel", taigaProjectTitle:"Create Taiga ticket", taigaProject:"Project", taigaTasksPick:"Create sub-packages as tasks:", taigaCreateDo:"Create", taigaError:"Failed: {error}", taigaOpenBtn:"Open {ref} in Taiga", taigaLinkBtn:"Taiga: link ticket", taigaLinkTitle:"Link Taiga ticket", taigaLinkDo:"Link", taigaLinkHint:"Taiga URL or ref (US-123, T-45, 123)", taigaLinkNotFound:"No ticket {ref} in project “{slug}”.", taigaLinkForeign:"That address belongs to a different Taiga instance.",taigaTicketDiff:"differs from the plan:", taigaTicketNoBox:"no status box", taigaTicketPush:"write to Taiga", taigaTicketPull:"take from Taiga", taigaTicketWriting:"writing …", taigaTicketNoMap:"This state has no counterpart in Taiga — nothing is written.", taigaTicketNoColumn:"There is no column “{name}” in this project.", taigaTicketFetch:"Fetch state", taigaTicketReload:"Fetch again", taigaTicketLoading:"Fetching state …", taigaTicketAssignee:"Assigned to: {name}", + taigaStoryBtn:"Taiga: create story", taigaTaskBtn:"Taiga: create task", taigaTaskNoProject:"No access to project “{slug}”.", taigaLoginTitle:"Log in to Taiga", taigaUser:"Username", taigaPass:"Password", taigaLoginDo:"Log in", taigaCancel:"Cancel", taigaProjectTitle:"Create Taiga ticket", taigaProject:"Project", taigaTasksPick:"Create sub-packages as tasks:", taigaCreateDo:"Create", taigaError:"Failed: {error}", taigaOpenBtn:"Open {ref}", taigaLinkBtn:"Taiga: link ticket", taigaLinkTitle:"Link Taiga ticket", taigaLinkDo:"Link", taigaLinkHint:"Taiga URL or ref (US-123, T-45, 123)", taigaLinkNotFound:"No ticket {ref} in project “{slug}”.", taigaLinkForeign:"That address belongs to a different Taiga instance.",taigaTicketDiff:"differs from the plan:", taigaTicketNoBox:"no status box", taigaTicketPush:"write to Taiga", taigaTicketPull:"take from Taiga", taigaTicketWriting:"writing …", taigaTicketNoMap:"This state has no counterpart in Taiga — nothing is written.", taigaTicketNoColumn:"There is no column “{name}” in this project.", taigaTicketFetch:"Fetch state", taigaTicketReload:"Fetch again", taigaTicketLoading:"Fetching state …", taigaTicketAssignee:"Assigned to: {name}", liveLoadWarn:"Server document not loaded: {url} ({error}). Is the backend running, and is the address a document address (…/documents/<uuid>)?", liveStaleWarn:"Your change no longer applied ({error}) — the document was fetched afresh once.", liveConflictText:"Someone changed the same lines. Whose version should win?", @@ -3540,7 +3557,7 @@ const I18N = { acHint:"{n} sugerencias de ID – ↑/↓ elige, Intro inserta", tipClose:"Cerrar", tipOpenLink:"Abrir enlace", - taigaStoryBtn:"Taiga: crear historia", taigaTaskBtn:"Taiga: crear tarea", taigaTaskNoProject:"Sin acceso al proyecto «{slug}».", taigaLoginTitle:"Iniciar sesión en Taiga", taigaUser:"Usuario", taigaPass:"Contraseña", taigaLoginDo:"Iniciar sesión", taigaCancel:"Cancelar", taigaProjectTitle:"Crear ticket de Taiga", taigaProject:"Proyecto", taigaTasksPick:"Crear subpaquetes como tareas:", taigaCreateDo:"Crear", taigaError:"Error: {error}", taigaOpenBtn:"Abrir {ref} en Taiga", taigaLinkBtn:"Taiga: vincular ticket", taigaLinkTitle:"Vincular ticket de Taiga", taigaLinkDo:"Vincular", taigaLinkHint:"URL de Taiga o ref (US-123, T-45, 123)", taigaLinkNotFound:"No hay ticket {ref} en el proyecto «{slug}».", taigaLinkForeign:"La dirección pertenece a otra instancia de Taiga.",taigaTicketDiff:"difiere del plan:", taigaTicketNoBox:"sin casilla de estado", taigaTicketPush:"escribir en Taiga", taigaTicketPull:"tomar de Taiga", taigaTicketWriting:"escribiendo …", taigaTicketNoMap:"Este estado no tiene equivalente en Taiga: no se escribe nada.", taigaTicketNoColumn:"En este proyecto no existe la columna «{name}».", taigaTicketFetch:"Consultar estado", taigaTicketReload:"Volver a consultar", taigaTicketLoading:"Consultando estado …", taigaTicketAssignee:"Asignado a: {name}", + taigaStoryBtn:"Taiga: crear historia", taigaTaskBtn:"Taiga: crear tarea", taigaTaskNoProject:"Sin acceso al proyecto «{slug}».", taigaLoginTitle:"Iniciar sesión en Taiga", taigaUser:"Usuario", taigaPass:"Contraseña", taigaLoginDo:"Iniciar sesión", taigaCancel:"Cancelar", taigaProjectTitle:"Crear ticket de Taiga", taigaProject:"Proyecto", taigaTasksPick:"Crear subpaquetes como tareas:", taigaCreateDo:"Crear", taigaError:"Error: {error}", taigaOpenBtn:"Abrir {ref}", taigaLinkBtn:"Taiga: vincular ticket", taigaLinkTitle:"Vincular ticket de Taiga", taigaLinkDo:"Vincular", taigaLinkHint:"URL de Taiga o ref (US-123, T-45, 123)", taigaLinkNotFound:"No hay ticket {ref} en el proyecto «{slug}».", taigaLinkForeign:"La dirección pertenece a otra instancia de Taiga.",taigaTicketDiff:"difiere del plan:", taigaTicketNoBox:"sin casilla de estado", taigaTicketPush:"escribir en Taiga", taigaTicketPull:"tomar de Taiga", taigaTicketWriting:"escribiendo …", taigaTicketNoMap:"Este estado no tiene equivalente en Taiga: no se escribe nada.", taigaTicketNoColumn:"En este proyecto no existe la columna «{name}».", taigaTicketFetch:"Consultar estado", taigaTicketReload:"Volver a consultar", taigaTicketLoading:"Consultando estado …", taigaTicketAssignee:"Asignado a: {name}", liveLoadWarn:"Documento del servidor no cargado: {url} ({error}). ¿Está el backend en marcha y es la dirección la de un documento (…/documents/<uuid>)?", liveStaleWarn:"Tu cambio ya no era aplicable ({error}): se volvió a cargar el estado una vez.", liveConflictText:"Alguien cambió las mismas líneas. ¿Qué versión debe prevalecer?", @@ -3676,7 +3693,7 @@ const I18N = { acHint:"{n} suggestions d'ID – ↑/↓ pour choisir, Entrée pour insérer", tipClose:"Fermer", tipOpenLink:"Ouvrir le lien", - taigaStoryBtn:"Taiga : créer la story", taigaTaskBtn:"Taiga : créer une tâche", taigaTaskNoProject:"Pas d'accès au projet « {slug} ».", taigaLoginTitle:"Se connecter à Taiga", taigaUser:"Nom d'utilisateur", taigaPass:"Mot de passe", taigaLoginDo:"Se connecter", taigaCancel:"Annuler", taigaProjectTitle:"Créer un ticket Taiga", taigaProject:"Projet", taigaTasksPick:"Créer les sous-lots comme tâches :", taigaCreateDo:"Créer", taigaError:"Échec : {error}", taigaOpenBtn:"Ouvrir {ref} dans Taiga", taigaLinkBtn:"Taiga : lier un ticket", taigaLinkTitle:"Lier un ticket Taiga", taigaLinkDo:"Lier", taigaLinkHint:"URL Taiga ou réf (US-123, T-45, 123)", taigaLinkNotFound:"Pas de ticket {ref} dans le projet « {slug} ».", taigaLinkForeign:"L'adresse appartient à une autre instance Taiga.",taigaTicketDiff:"diffère du plan :", taigaTicketNoBox:"sans case d'état", taigaTicketPush:"écrire dans Taiga", taigaTicketPull:"reprendre de Taiga", taigaTicketWriting:"écriture …", taigaTicketNoMap:"Cet état n'a pas d'équivalent dans Taiga — rien n'est écrit.", taigaTicketNoColumn:"La colonne « {name} » n'existe pas dans ce projet.", taigaTicketFetch:"Relever l'état", taigaTicketReload:"Relever à nouveau", taigaTicketLoading:"Relevé de l'état …", taigaTicketAssignee:"Assigné à : {name}", + taigaStoryBtn:"Taiga : créer la story", taigaTaskBtn:"Taiga : créer une tâche", taigaTaskNoProject:"Pas d'accès au projet « {slug} ».", taigaLoginTitle:"Se connecter à Taiga", taigaUser:"Nom d'utilisateur", taigaPass:"Mot de passe", taigaLoginDo:"Se connecter", taigaCancel:"Annuler", taigaProjectTitle:"Créer un ticket Taiga", taigaProject:"Projet", taigaTasksPick:"Créer les sous-lots comme tâches :", taigaCreateDo:"Créer", taigaError:"Échec : {error}", taigaOpenBtn:"Ouvrir {ref}", taigaLinkBtn:"Taiga : lier un ticket", taigaLinkTitle:"Lier un ticket Taiga", taigaLinkDo:"Lier", taigaLinkHint:"URL Taiga ou réf (US-123, T-45, 123)", taigaLinkNotFound:"Pas de ticket {ref} dans le projet « {slug} ».", taigaLinkForeign:"L'adresse appartient à une autre instance Taiga.",taigaTicketDiff:"diffère du plan :", taigaTicketNoBox:"sans case d'état", taigaTicketPush:"écrire dans Taiga", taigaTicketPull:"reprendre de Taiga", taigaTicketWriting:"écriture …", taigaTicketNoMap:"Cet état n'a pas d'équivalent dans Taiga — rien n'est écrit.", taigaTicketNoColumn:"La colonne « {name} » n'existe pas dans ce projet.", taigaTicketFetch:"Relever l'état", taigaTicketReload:"Relever à nouveau", taigaTicketLoading:"Relevé de l'état …", taigaTicketAssignee:"Assigné à : {name}", liveLoadWarn:"Document du serveur non chargé : {url} ({error}). Le backend tourne-t-il, et l'adresse est-elle celle d'un document (…/documents/<uuid>) ?", liveStaleWarn:"Ta modification n'était plus applicable ({error}) — l'état a été rechargé une fois.", liveConflictText:"Quelqu'un a modifié les mêmes lignes. Quelle version doit l'emporter ?", @@ -3812,7 +3829,7 @@ const I18N = { acHint:"{n} podpowiedzi ID – ↑/↓ wybiera, Enter wstawia", tipClose:"Zamknij", tipOpenLink:"Otwórz link", - taigaStoryBtn:"Taiga: utwórz historyjkę", taigaTaskBtn:"Taiga: utwórz zadanie", taigaTaskNoProject:"Brak dostępu do projektu „{slug}”.", taigaLoginTitle:"Zaloguj się do Taigi", taigaUser:"Nazwa użytkownika", taigaPass:"Hasło", taigaLoginDo:"Zaloguj", taigaCancel:"Anuluj", taigaProjectTitle:"Utwórz zgłoszenie w Taidze", taigaProject:"Projekt", taigaTasksPick:"Utwórz podpakiety jako zadania:", taigaCreateDo:"Utwórz", taigaError:"Niepowodzenie: {error}", taigaOpenBtn:"Otwórz {ref} w Taidze", taigaLinkBtn:"Taiga: powiąż zgłoszenie", taigaLinkTitle:"Powiąż zgłoszenie Taigi", taigaLinkDo:"Powiąż", taigaLinkHint:"URL Taigi lub ref (US-123, T-45, 123)", taigaLinkNotFound:"Brak zgłoszenia {ref} w projekcie „{slug}”.", taigaLinkForeign:"Adres należy do innej instancji Taigi.",taigaTicketDiff:"różni się od planu:", taigaTicketNoBox:"bez pola statusu", taigaTicketPush:"zapisz w Taidze", taigaTicketPull:"pobierz z Taigi", taigaTicketWriting:"zapisywanie …", taigaTicketNoMap:"Ten stan nie ma odpowiednika w Taidze — nic nie zostanie zapisane.", taigaTicketNoColumn:"W tym projekcie nie ma kolumny „{name}”.", taigaTicketFetch:"Pobierz stan", taigaTicketReload:"Pobierz ponownie", taigaTicketLoading:"Pobieranie stanu …", taigaTicketAssignee:"Przypisane do: {name}", + taigaStoryBtn:"Taiga: utwórz historyjkę", taigaTaskBtn:"Taiga: utwórz zadanie", taigaTaskNoProject:"Brak dostępu do projektu „{slug}”.", taigaLoginTitle:"Zaloguj się do Taigi", taigaUser:"Nazwa użytkownika", taigaPass:"Hasło", taigaLoginDo:"Zaloguj", taigaCancel:"Anuluj", taigaProjectTitle:"Utwórz zgłoszenie w Taidze", taigaProject:"Projekt", taigaTasksPick:"Utwórz podpakiety jako zadania:", taigaCreateDo:"Utwórz", taigaError:"Niepowodzenie: {error}", taigaOpenBtn:"Otwórz {ref}", taigaLinkBtn:"Taiga: powiąż zgłoszenie", taigaLinkTitle:"Powiąż zgłoszenie Taigi", taigaLinkDo:"Powiąż", taigaLinkHint:"URL Taigi lub ref (US-123, T-45, 123)", taigaLinkNotFound:"Brak zgłoszenia {ref} w projekcie „{slug}”.", taigaLinkForeign:"Adres należy do innej instancji Taigi.",taigaTicketDiff:"różni się od planu:", taigaTicketNoBox:"bez pola statusu", taigaTicketPush:"zapisz w Taidze", taigaTicketPull:"pobierz z Taigi", taigaTicketWriting:"zapisywanie …", taigaTicketNoMap:"Ten stan nie ma odpowiednika w Taidze — nic nie zostanie zapisane.", taigaTicketNoColumn:"W tym projekcie nie ma kolumny „{name}”.", taigaTicketFetch:"Pobierz stan", taigaTicketReload:"Pobierz ponownie", taigaTicketLoading:"Pobieranie stanu …", taigaTicketAssignee:"Przypisane do: {name}", liveLoadWarn:"Nie wczytano dokumentu z serwera: {url} ({error}). Czy backend działa i czy adres wskazuje dokument (…/documents/<uuid>)?", liveStaleWarn:"Twoja zmiana nie dała się już zastosować ({error}) — stan pobrano raz od nowa.", liveConflictText:"Ktoś zmienił te same wiersze. Która wersja ma obowiązywać?", @@ -3948,7 +3965,7 @@ const I18N = { acHint:"{n} подсказок ID – ↑/↓ выбирает, Enter вставляет", tipClose:"Закрыть", tipOpenLink:"Открыть ссылку", - taigaStoryBtn:"Taiga: создать историю", taigaTaskBtn:"Taiga: создать задачу", taigaTaskNoProject:"Нет доступа к проекту «{slug}».", taigaLoginTitle:"Вход в Taiga", taigaUser:"Имя пользователя", taigaPass:"Пароль", taigaLoginDo:"Войти", taigaCancel:"Отмена", taigaProjectTitle:"Создать тикет в Taiga", taigaProject:"Проект", taigaTasksPick:"Создать подпакеты как задачи:", taigaCreateDo:"Создать", taigaError:"Не удалось: {error}", taigaOpenBtn:"Открыть {ref} в Taiga", taigaLinkBtn:"Taiga: связать тикет", taigaLinkTitle:"Связать тикет Taiga", taigaLinkDo:"Связать", taigaLinkHint:"URL Taiga или реф (US-123, T-45, 123)", taigaLinkNotFound:"Тикета {ref} нет в проекте «{slug}».", taigaLinkForeign:"Адрес относится к другой инстанции Taiga.",taigaTicketDiff:"расходится с планом:", taigaTicketNoBox:"без статуса", taigaTicketPush:"записать в Taiga", taigaTicketPull:"взять из Taiga", taigaTicketWriting:"запись …", taigaTicketNoMap:"У этого состояния нет соответствия в Taiga — ничего не записано.", taigaTicketNoColumn:"В этом проекте нет колонки «{name}».", taigaTicketFetch:"Получить статус", taigaTicketReload:"Обновить статус", taigaTicketLoading:"Получение статуса …", taigaTicketAssignee:"Назначено: {name}", + taigaStoryBtn:"Taiga: создать историю", taigaTaskBtn:"Taiga: создать задачу", taigaTaskNoProject:"Нет доступа к проекту «{slug}».", taigaLoginTitle:"Вход в Taiga", taigaUser:"Имя пользователя", taigaPass:"Пароль", taigaLoginDo:"Войти", taigaCancel:"Отмена", taigaProjectTitle:"Создать тикет в Taiga", taigaProject:"Проект", taigaTasksPick:"Создать подпакеты как задачи:", taigaCreateDo:"Создать", taigaError:"Не удалось: {error}", taigaOpenBtn:"Открыть {ref}", taigaLinkBtn:"Taiga: связать тикет", taigaLinkTitle:"Связать тикет Taiga", taigaLinkDo:"Связать", taigaLinkHint:"URL Taiga или реф (US-123, T-45, 123)", taigaLinkNotFound:"Тикета {ref} нет в проекте «{slug}».", taigaLinkForeign:"Адрес относится к другой инстанции Taiga.",taigaTicketDiff:"расходится с планом:", taigaTicketNoBox:"без статуса", taigaTicketPush:"записать в Taiga", taigaTicketPull:"взять из Taiga", taigaTicketWriting:"запись …", taigaTicketNoMap:"У этого состояния нет соответствия в Taiga — ничего не записано.", taigaTicketNoColumn:"В этом проекте нет колонки «{name}».", taigaTicketFetch:"Получить статус", taigaTicketReload:"Обновить статус", taigaTicketLoading:"Получение статуса …", taigaTicketAssignee:"Назначено: {name}", liveLoadWarn:"Документ с сервера не загружен: {url} ({error}). Запущен ли бэкенд и является ли адрес адресом документа (…/documents/<uuid>)?", liveStaleWarn:"Ваше изменение больше не применялось ({error}) — состояние загружено заново.", liveConflictText:"Кто-то изменил те же строки. Чья версия должна остаться?", @@ -4084,7 +4101,7 @@ const I18N = { acHint:"{n} आईडी सुझाव – ↑/↓ से चुनें, Enter से डालें", tipClose:"बंद करें", tipOpenLink:"लिंक खोलें", - taigaStoryBtn:"Taiga: स्टोरी बनाएँ", taigaTaskBtn:"Taiga: टास्क बनाएँ", taigaTaskNoProject:"प्रोजेक्ट “{slug}” तक पहुँच नहीं है।", taigaLoginTitle:"Taiga में साइन इन करें", taigaUser:"उपयोगकर्ता नाम", taigaPass:"पासवर्ड", taigaLoginDo:"साइन इन", taigaCancel:"रद्द करें", taigaProjectTitle:"Taiga टिकट बनाएँ", taigaProject:"प्रोजेक्ट", taigaTasksPick:"उप-पैकेज टास्क के रूप में बनाएँ:", taigaCreateDo:"बनाएँ", taigaError:"विफल: {error}", taigaOpenBtn:"Taiga में {ref} खोलें", taigaLinkBtn:"Taiga: टिकट लिंक करें", taigaLinkTitle:"Taiga टिकट लिंक करें", taigaLinkDo:"लिंक करें", taigaLinkHint:"Taiga URL या रेफ़ (US-123, T-45, 123)", taigaLinkNotFound:"प्रोजेक्ट “{slug}” में टिकट {ref} नहीं है।", taigaLinkForeign:"यह पता किसी और Taiga इंस्टेंस का है।",taigaTicketDiff:"योजना से भिन्न:", taigaTicketNoBox:"स्थिति-बॉक्स नहीं", taigaTicketPush:"Taiga में लिखें", taigaTicketPull:"Taiga से लें", taigaTicketWriting:"लिखा जा रहा है …", taigaTicketNoMap:"इस स्थिति का Taiga में कोई समकक्ष नहीं है — कुछ नहीं लिखा जाता।", taigaTicketNoColumn:"इस प्रोजेक्ट में “{name}” कॉलम नहीं है।", taigaTicketFetch:"स्थिति लाएँ", taigaTicketReload:"फिर से लाएँ", taigaTicketLoading:"स्थिति लाई जा रही है …", taigaTicketAssignee:"ज़िम्मेदार: {name}", + taigaStoryBtn:"Taiga: स्टोरी बनाएँ", taigaTaskBtn:"Taiga: टास्क बनाएँ", taigaTaskNoProject:"प्रोजेक्ट “{slug}” तक पहुँच नहीं है।", taigaLoginTitle:"Taiga में साइन इन करें", taigaUser:"उपयोगकर्ता नाम", taigaPass:"पासवर्ड", taigaLoginDo:"साइन इन", taigaCancel:"रद्द करें", taigaProjectTitle:"Taiga टिकट बनाएँ", taigaProject:"प्रोजेक्ट", taigaTasksPick:"उप-पैकेज टास्क के रूप में बनाएँ:", taigaCreateDo:"बनाएँ", taigaError:"विफल: {error}", taigaOpenBtn:"{ref} खोलें", taigaLinkBtn:"Taiga: टिकट लिंक करें", taigaLinkTitle:"Taiga टिकट लिंक करें", taigaLinkDo:"लिंक करें", taigaLinkHint:"Taiga URL या रेफ़ (US-123, T-45, 123)", taigaLinkNotFound:"प्रोजेक्ट “{slug}” में टिकट {ref} नहीं है।", taigaLinkForeign:"यह पता किसी और Taiga इंस्टेंस का है।",taigaTicketDiff:"योजना से भिन्न:", taigaTicketNoBox:"स्थिति-बॉक्स नहीं", taigaTicketPush:"Taiga में लिखें", taigaTicketPull:"Taiga से लें", taigaTicketWriting:"लिखा जा रहा है …", taigaTicketNoMap:"इस स्थिति का Taiga में कोई समकक्ष नहीं है — कुछ नहीं लिखा जाता।", taigaTicketNoColumn:"इस प्रोजेक्ट में “{name}” कॉलम नहीं है।", taigaTicketFetch:"स्थिति लाएँ", taigaTicketReload:"फिर से लाएँ", taigaTicketLoading:"स्थिति लाई जा रही है …", taigaTicketAssignee:"ज़िम्मेदार: {name}", liveLoadWarn:"सर्वर दस्तावेज़ लोड नहीं हुआ: {url} ({error})। क्या बैकएंड चल रहा है और क्या पता दस्तावेज़ का पता है (…/documents/<uuid>)?", liveStaleWarn:"आपका बदलाव अब लागू नहीं हो सका ({error}) — स्थिति एक बार नए सिरे से ली गई।", liveConflictText:"किसी और ने वही पंक्तियाँ बदली हैं। किसका संस्करण रहे?", @@ -4231,7 +4248,7 @@ const I18N = { acHint:"{n} 个 ID 建议 – ↑/↓ 选择,Enter 插入", tipClose:"关闭", tipOpenLink:"打开链接", - taigaStoryBtn:"Taiga:创建故事", taigaTaskBtn:"Taiga:创建任务", taigaTaskNoProject:"无法访问项目「{slug}」。", taigaLoginTitle:"登录 Taiga", taigaUser:"用户名", taigaPass:"密码", taigaLoginDo:"登录", taigaCancel:"取消", taigaProjectTitle:"创建 Taiga 工单", taigaProject:"项目", taigaTasksPick:"将子包创建为任务:", taigaCreateDo:"创建", taigaError:"失败:{error}", taigaOpenBtn:"在 Taiga 中打开 {ref}", taigaLinkBtn:"Taiga:关联工单", taigaLinkTitle:"关联 Taiga 工单", taigaLinkDo:"关联", taigaLinkHint:"Taiga 网址或编号(US-123、T-45、123)", taigaLinkNotFound:"项目「{slug}」中没有工单 {ref}。", taigaLinkForeign:"该地址属于另一个 Taiga 实例。",taigaTicketDiff:"与计划不一致:", taigaTicketNoBox:"没有状态框", taigaTicketPush:"写入 Taiga", taigaTicketPull:"从 Taiga 取用", taigaTicketWriting:"正在写入 …", taigaTicketNoMap:"该状态在 Taiga 中没有对应项 — 不会写入任何内容。", taigaTicketNoColumn:"本项目中没有「{name}」这一列。", taigaTicketFetch:"获取状态", taigaTicketReload:"重新获取", taigaTicketLoading:"正在获取状态 …", taigaTicketAssignee:"负责人:{name}", + taigaStoryBtn:"Taiga:创建故事", taigaTaskBtn:"Taiga:创建任务", taigaTaskNoProject:"无法访问项目「{slug}」。", taigaLoginTitle:"登录 Taiga", taigaUser:"用户名", taigaPass:"密码", taigaLoginDo:"登录", taigaCancel:"取消", taigaProjectTitle:"创建 Taiga 工单", taigaProject:"项目", taigaTasksPick:"将子包创建为任务:", taigaCreateDo:"创建", taigaError:"失败:{error}", taigaOpenBtn:"打开 {ref}", taigaLinkBtn:"Taiga:关联工单", taigaLinkTitle:"关联 Taiga 工单", taigaLinkDo:"关联", taigaLinkHint:"Taiga 网址或编号(US-123、T-45、123)", taigaLinkNotFound:"项目「{slug}」中没有工单 {ref}。", taigaLinkForeign:"该地址属于另一个 Taiga 实例。",taigaTicketDiff:"与计划不一致:", taigaTicketNoBox:"没有状态框", taigaTicketPush:"写入 Taiga", taigaTicketPull:"从 Taiga 取用", taigaTicketWriting:"正在写入 …", taigaTicketNoMap:"该状态在 Taiga 中没有对应项 — 不会写入任何内容。", taigaTicketNoColumn:"本项目中没有「{name}」这一列。", taigaTicketFetch:"获取状态", taigaTicketReload:"重新获取", taigaTicketLoading:"正在获取状态 …", taigaTicketAssignee:"负责人:{name}", liveLoadWarn:"未能加载服务器文档:{url}({error})。后端在运行吗?该地址是文档地址(…/documents/<uuid>)吗?", liveStaleWarn:"你的更改已无法应用({error})——已重新获取一次当前状态。", liveConflictText:"有人改动了同样的行。以谁的版本为准?", @@ -4367,7 +4384,7 @@ const I18N = { acHint:"ID候補 {n} 件 – ↑/↓で選択、Enterで挿入", tipClose:"閉じる", tipOpenLink:"リンクを開く", - taigaStoryBtn:"Taiga: ストーリーを作成", taigaTaskBtn:"Taiga: タスクを作成", taigaTaskNoProject:"プロジェクト「{slug}」にアクセスできません。", taigaLoginTitle:"Taiga にログイン", taigaUser:"ユーザー名", taigaPass:"パスワード", taigaLoginDo:"ログイン", taigaCancel:"キャンセル", taigaProjectTitle:"Taiga チケットを作成", taigaProject:"プロジェクト", taigaTasksPick:"サブパッケージをタスクとして作成:", taigaCreateDo:"作成", taigaError:"失敗: {error}", taigaOpenBtn:"Taiga で {ref} を開く", taigaLinkBtn:"Taiga: チケットを紐付け", taigaLinkTitle:"Taiga チケットを紐付け", taigaLinkDo:"紐付ける", taigaLinkHint:"Taiga の URL または参照番号 (US-123, T-45, 123)", taigaLinkNotFound:"プロジェクト「{slug}」にチケット {ref} はありません。", taigaLinkForeign:"このアドレスは別の Taiga インスタンスのものです。",taigaTicketDiff:"計画と食い違い:", taigaTicketNoBox:"ステータス欄なし", taigaTicketPush:"Taiga に書く", taigaTicketPull:"Taiga から取る", taigaTicketWriting:"書き込み中 …", taigaTicketNoMap:"この状態に対応する列が Taiga にありません — 何も書き込みません。", taigaTicketNoColumn:"このプロジェクトに「{name}」列はありません。", taigaTicketFetch:"状態を取得", taigaTicketReload:"再取得", taigaTicketLoading:"状態を取得中 …", taigaTicketAssignee:"担当: {name}", + taigaStoryBtn:"Taiga: ストーリーを作成", taigaTaskBtn:"Taiga: タスクを作成", taigaTaskNoProject:"プロジェクト「{slug}」にアクセスできません。", taigaLoginTitle:"Taiga にログイン", taigaUser:"ユーザー名", taigaPass:"パスワード", taigaLoginDo:"ログイン", taigaCancel:"キャンセル", taigaProjectTitle:"Taiga チケットを作成", taigaProject:"プロジェクト", taigaTasksPick:"サブパッケージをタスクとして作成:", taigaCreateDo:"作成", taigaError:"失敗: {error}", taigaOpenBtn:"{ref} を開く", taigaLinkBtn:"Taiga: チケットを紐付け", taigaLinkTitle:"Taiga チケットを紐付け", taigaLinkDo:"紐付ける", taigaLinkHint:"Taiga の URL または参照番号 (US-123, T-45, 123)", taigaLinkNotFound:"プロジェクト「{slug}」にチケット {ref} はありません。", taigaLinkForeign:"このアドレスは別の Taiga インスタンスのものです。",taigaTicketDiff:"計画と食い違い:", taigaTicketNoBox:"ステータス欄なし", taigaTicketPush:"Taiga に書く", taigaTicketPull:"Taiga から取る", taigaTicketWriting:"書き込み中 …", taigaTicketNoMap:"この状態に対応する列が Taiga にありません — 何も書き込みません。", taigaTicketNoColumn:"このプロジェクトに「{name}」列はありません。", taigaTicketFetch:"状態を取得", taigaTicketReload:"再取得", taigaTicketLoading:"状態を取得中 …", taigaTicketAssignee:"担当: {name}", liveLoadWarn:"サーバー文書を読み込めませんでした: {url}({error})。バックエンドは動いていますか。アドレスは文書のアドレス(…/documents/<uuid>)ですか。", liveStaleWarn:"あなたの変更はもう適用できませんでした({error})。状態を一度取り直しました。", liveConflictText:"同じ行が他の人にも変更されました。どちらの版を採りますか。", diff --git a/frontend/src/style.css b/frontend/src/style.css index 8bb20fc..2e10dc5 100644 --- a/frontend/src/style.css +++ b/frontend/src/style.css @@ -1060,6 +1060,10 @@ box-shadow:0 8px 24px rgba(36,52,71,.3); padding:10px 30px 10px 12px;font-size:.78rem;line-height:1.45; } + /* Mit Taiga-Knöpfen darf das Fenster breiter werden, damit die Aktionen + nebeneinander stehen (D91-Nachtrag 11); die 21rem bleiben das Maß für + reine Text-Fenster. */ + .nodetip.tipwide{max-width:min(31rem, calc(100vw - 24px))} .nodetip[hidden]{display:none} .nodetip-x{ position:absolute;top:2px;right:2px;width:26px;height:26px;