Ticket-Details: Repo und klickbare Ticket-Nummer in der Ueberschrift, Beschreibung auf 10 Zeilen gekuerzt
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
parent
32e405252b
commit
5a00a668ec
4 changed files with 72 additions and 9 deletions
|
|
@ -741,7 +741,17 @@ header.office-header h1 {
|
||||||
font-size: 0.9rem;
|
font-size: 0.9rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.office-modal-item .office-modal-description {
|
||||||
|
white-space: pre-line;
|
||||||
|
}
|
||||||
|
|
||||||
|
.office-modal-repo {
|
||||||
|
color: #64748b;
|
||||||
|
font-size: 0.85rem;
|
||||||
|
}
|
||||||
|
|
||||||
.office-modal-item-heading {
|
.office-modal-item-heading {
|
||||||
|
flex-wrap: wrap;
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
gap: 8px;
|
gap: 8px;
|
||||||
|
|
|
||||||
|
|
@ -1419,6 +1419,23 @@ function renderTicketModalBody(body, content) {
|
||||||
|
|
||||||
const heading = document.createElement("div");
|
const heading = document.createElement("div");
|
||||||
heading.className = "office-modal-item-heading";
|
heading.className = "office-modal-item-heading";
|
||||||
|
if (item.repo) {
|
||||||
|
const repoEl = document.createElement("span");
|
||||||
|
repoEl.className = "office-modal-repo";
|
||||||
|
repoEl.textContent = item.repo;
|
||||||
|
heading.appendChild(repoEl);
|
||||||
|
}
|
||||||
|
if (item.number) {
|
||||||
|
const numEl = item.link ? document.createElement("a") : document.createElement("span");
|
||||||
|
numEl.className = "office-modal-ticket-number";
|
||||||
|
numEl.textContent = `#${item.number}`;
|
||||||
|
if (item.link) {
|
||||||
|
numEl.href = item.link;
|
||||||
|
numEl.target = "_blank";
|
||||||
|
numEl.rel = "noopener noreferrer";
|
||||||
|
}
|
||||||
|
heading.appendChild(numEl);
|
||||||
|
}
|
||||||
const titleEl = document.createElement("strong");
|
const titleEl = document.createElement("strong");
|
||||||
titleEl.textContent = item.title;
|
titleEl.textContent = item.title;
|
||||||
heading.appendChild(titleEl);
|
heading.appendChild(titleEl);
|
||||||
|
|
@ -1433,17 +1450,10 @@ function renderTicketModalBody(body, content) {
|
||||||
|
|
||||||
if (item.description) {
|
if (item.description) {
|
||||||
const desc = document.createElement("p");
|
const desc = document.createElement("p");
|
||||||
|
desc.className = "office-modal-description";
|
||||||
desc.textContent = item.description;
|
desc.textContent = item.description;
|
||||||
li.appendChild(desc);
|
li.appendChild(desc);
|
||||||
}
|
}
|
||||||
if (item.link) {
|
|
||||||
const a = document.createElement("a");
|
|
||||||
a.href = item.link;
|
|
||||||
a.target = "_blank";
|
|
||||||
a.rel = "noopener noreferrer";
|
|
||||||
a.textContent = "Auf Codeberg öffnen";
|
|
||||||
li.appendChild(a);
|
|
||||||
}
|
|
||||||
list.appendChild(li);
|
list.appendChild(li);
|
||||||
}
|
}
|
||||||
body.appendChild(list);
|
body.appendChild(list);
|
||||||
|
|
|
||||||
|
|
@ -190,6 +190,22 @@ export function groupTicketsByColumn(tickets = []) {
|
||||||
return groups;
|
return groups;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Issue #88: Beschreibungen im Ticket-Modal werden auf diese Zeilenzahl gekuerzt.
|
||||||
|
export const TICKET_DESCRIPTION_MAX_LINES = 10;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Kuerzt einen Text auf maxLines Zeilen; ist er laenger, ersetzt "..." den Rest.
|
||||||
|
*
|
||||||
|
* @param {string} text
|
||||||
|
* @param {number} [maxLines]
|
||||||
|
* @returns {string}
|
||||||
|
*/
|
||||||
|
export function truncateDescriptionLines(text, maxLines = TICKET_DESCRIPTION_MAX_LINES) {
|
||||||
|
const lines = String(text || "").replace(/\s+$/, "").split(/\r?\n/);
|
||||||
|
if (lines.length <= maxLines) return lines.join("\n");
|
||||||
|
return `${lines.slice(0, maxLines).join("\n")}\n...`;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Baut das Inhaltsmodell fuer das Board-Spalten-Modal (Visualization.md 4.2/4.5): echter
|
* Baut das Inhaltsmodell fuer das Board-Spalten-Modal (Visualization.md 4.2/4.5): echter
|
||||||
* Titel/Beschreibung je Ticket, plus Link auf die Codeberg-Quelle sofern das Ticket per
|
* Titel/Beschreibung je Ticket, plus Link auf die Codeberg-Quelle sofern das Ticket per
|
||||||
|
|
@ -210,9 +226,15 @@ export function buildTicketModalContent(columnKey, tickets = [], opts = {}) {
|
||||||
items: tickets.map((ticket) => ({
|
items: tickets.map((ticket) => ({
|
||||||
id: ticket.id,
|
id: ticket.id,
|
||||||
title: ticket.title,
|
title: ticket.title,
|
||||||
description: ticket.description || "",
|
description: truncateDescriptionLines(ticket.description),
|
||||||
type: ticket.type || null,
|
type: ticket.type || null,
|
||||||
color: ticket.color || null,
|
color: ticket.color || null,
|
||||||
|
// Issue #88: Repo und Ticket-Nummer stehen in der Ueberschrift, die Nummer ist der Link.
|
||||||
|
repo:
|
||||||
|
ticket.source === "codeberg" && ticket.external_ref
|
||||||
|
? ticket.repo || `${codebergOwner}/${codebergRepo}`
|
||||||
|
: null,
|
||||||
|
number: ticket.source === "codeberg" && ticket.external_ref ? String(ticket.external_ref) : null,
|
||||||
link:
|
link:
|
||||||
ticket.source === "codeberg" && ticket.external_ref
|
ticket.source === "codeberg" && ticket.external_ref
|
||||||
? `https://codeberg.org/${ticket.repo || `${codebergOwner}/${codebergRepo}`}/issues/${ticket.external_ref}`
|
? `https://codeberg.org/${ticket.repo || `${codebergOwner}/${codebergRepo}`}/issues/${ticket.external_ref}`
|
||||||
|
|
|
||||||
|
|
@ -904,3 +904,24 @@ test("systemsWithoutHostConfig kommt ohne Hosts und ohne system_ids zurecht", ()
|
||||||
assert.deepEqual(systemsWithoutHostConfig([{ id: "a" }], [{ hostname: "a" }]), [{ id: "a" }]);
|
assert.deepEqual(systemsWithoutHostConfig([{ id: "a" }], [{ hostname: "a" }]), [{ id: "a" }]);
|
||||||
assert.deepEqual(systemsWithoutHostConfig(), []);
|
assert.deepEqual(systemsWithoutHostConfig(), []);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test("buildTicketModalContent liefert Repo und Ticket-Nummer fuer die Ueberschrift (Issue #88)", () => {
|
||||||
|
const content = buildTicketModalContent("backlog", [
|
||||||
|
{ id: 1, title: "A", source: "codeberg", external_ref: "3", repo: "fds2610/Steuerkram" },
|
||||||
|
{ id: 2, title: "B", source: "api", external_ref: null },
|
||||||
|
]);
|
||||||
|
assert.equal(content.items[0].repo, "fds2610/Steuerkram");
|
||||||
|
assert.equal(content.items[0].number, "3");
|
||||||
|
assert.equal(content.items[1].repo, null);
|
||||||
|
assert.equal(content.items[1].number, null);
|
||||||
|
});
|
||||||
|
|
||||||
|
test("buildTicketModalContent kuerzt Beschreibungen auf 10 Zeilen mit '...' (Issue #88)", () => {
|
||||||
|
const lines = Array.from({ length: 12 }, (_, i) => `Zeile ${i + 1}`);
|
||||||
|
const [long, exact] = buildTicketModalContent("backlog", [
|
||||||
|
{ id: 1, title: "A", description: lines.join("\n") },
|
||||||
|
{ id: 2, title: "B", description: lines.slice(0, 10).join("\n") },
|
||||||
|
]).items;
|
||||||
|
assert.equal(long.description, `${lines.slice(0, 10).join("\n")}\n...`);
|
||||||
|
assert.equal(exact.description, lines.slice(0, 10).join("\n"));
|
||||||
|
});
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue