From f1aac2ada998bce4398d6964666895886d80ae08 Mon Sep 17 00:00:00 2001 From: Claude Date: Tue, 6 Oct 2026 10:21:54 +0000 Subject: [PATCH] Projekte: Projektabschnitt am Ticket als Abschnitt, Art-Frage als Dialog Der Abschnitt nutzt Card, Button und Dialog statt Altklassen und Icons. TicketProjects laedt nur noch bei einer anderen Ticket-ID neu (load haengt an ticket.$id, der neueste Ticketstand kommt ueber ein ref), damit "Suche neue Repos ..." bei Status-, Zustaendig- oder Dringend-Aenderung nicht erneut blinkt. Co-Authored-By: Claude Sonnet 5.5 --- src/components/TicketProjects.jsx | 82 ++++++++++++++++--------------- 1 file changed, 43 insertions(+), 39 deletions(-) diff --git a/src/components/TicketProjects.jsx b/src/components/TicketProjects.jsx index e1c395e..d3838bb 100644 --- a/src/components/TicketProjects.jsx +++ b/src/components/TicketProjects.jsx @@ -1,5 +1,4 @@ -import { useState, useEffect, useCallback } from 'react' -import { FaPlus, FaLink } from 'react-icons/fa6' +import { Fragment, useState, useEffect, useCallback, useRef } from 'react' import { useWebsiteProjects } from '../hooks/useWebsiteProjects' import { createProjectFromTemplate, importNewReposThrottled } from '../lib/projectAdminApi' import { isOutsideOrg, assignSummary, assignableProjects } from '../lib/projectAssign' @@ -7,6 +6,7 @@ import { slugify } from '../lib/subdomain' import AssignedProjectCard from './AssignedProjectCard' import { fetchServices, completeAssignment } from '../lib/projectKindsApi' import { kindLabelFor } from '../lib/assignFlow' +import { Card, Button, Dialog } from './ui' // Projekte am Ticket: Liste, Zuweisen, Loesen und neues Projekt an einer Stelle. // Loesen nimmt das Projekt nur vom Ticket; die Kundenzuordnung (Sichtbarkeit im Portal) bleibt. @@ -29,12 +29,18 @@ export default function TicketProjects({ ticket }) { fetchServices().then((s) => setKinds(s.kinds || [])).catch(() => {}) }, []) + // Neu laden (samt "Suche neue Repos ...") nur bei einem anderen Ticket, nicht bei Status, Zustaendig oder Dringend: + // load haengt an der Ticket-ID, den jeweils neuesten Ticketstand (Kunde) liest es ueber ticketRef + const ticketRef = useRef(ticket) + ticketRef.current = ticket + const ticketId = ticket?.$id + const load = useCallback(async () => { - if (!ticket?.$id) return - const [all, mine] = await Promise.all([fetchAllProjects(), fetchByTicketId(ticket.$id)]) + if (!ticketId) return + const [all, mine] = await Promise.all([fetchAllProjects(), fetchByTicketId(ticketId)]) setAssigned(mine) - setAvailable(assignableProjects(all, ticket, new Set(mine.map((p) => p.$id)))) - }, [ticket, fetchAllProjects, fetchByTicketId]) + setAvailable(assignableProjects(all, ticketRef.current, new Set(mine.map((p) => p.$id)))) + }, [ticketId, fetchAllProjects, fetchByTicketId]) useEffect(() => { let cancelled = false @@ -156,16 +162,15 @@ export default function TicketProjects({ ticket }) { } return ( -
-
Projekte ({assigned.length})
- {importing &&

Suche neue Repos …

} - {importHint &&
{importHint}
} - {error &&
{error}
} + + {importing &&

Suche neue Repos …

} + {importHint &&

{importHint}

} + {error &&

{error}

} {assigned.length === 0 - ?

Noch kein Projekt an diesem Ticket.

+ ?

Noch kein Projekt an diesem Ticket.

: assigned.map((p) => (
- {kindLabelFor(kinds, p.kind)} + {kindLabelFor(kinds, p.kind)} - setSelected(e.target.value)}> {available.map((p) => ( ))} - - + +
{assignResult && ( -
-
{assignResult.text}
+

+ {assignResult.text} {assignResult.warnings.map((w, i) => ( -

{w}
+ +
+ {w} +
))} -
+

)} {showCreate && ( -
- setCreateForm((f) => ({ ...f, displayName: e.target.value }))} required /> - setCreateForm((f) => ({ ...f, subdomain: e.target.value }))} required /> - + + setCreateForm((f) => ({ ...f, displayName: e.target.value }))} required /> + setCreateForm((f) => ({ ...f, subdomain: e.target.value }))} required /> +
)} {kindDialog && ( -
- setKindDialog(false)}>× -
-

Was ist das?

-

Bitte wähle die Art des Projekts, bevor es zugewiesen wird.

- {kinds.length === 0 && ( -
Arten konnten nicht geladen werden – bitte neu laden.
- )} -
- {kinds.map((k) => ( - - ))} -
+ setKindDialog(false)}> +

Bitte wähle die Art des Projekts, bevor es zugewiesen wird.

+ {kinds.length === 0 && ( +

Arten konnten nicht geladen werden – bitte neu laden.

+ )} +
+ {kinds.map((k) => ( + + ))}
-
+ )} -
+
) }