From 07170fb1177231e498abec6f2f1ee132068c1ecb Mon Sep 17 00:00:00 2001 From: Toofan Mohammadi Date: Thu, 12 Nov 2026 01:38:26 +0330 Subject: [PATCH 1/2] fix(roadmap): open task preview items correctly --- .../src/lib/features/collections/RoadmapItemPreview.svelte | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/frontend/src/lib/features/collections/RoadmapItemPreview.svelte b/frontend/src/lib/features/collections/RoadmapItemPreview.svelte index 141a51b23..ea136769b 100644 --- a/frontend/src/lib/features/collections/RoadmapItemPreview.svelte +++ b/frontend/src/lib/features/collections/RoadmapItemPreview.svelte @@ -33,10 +33,10 @@ portal: 'body', }); - function openItem(event) { - event.stopPropagation(); + function openItem(itemId, event) { + event?.stopPropagation(); $open = false; - onopen?.(item.id); + onopen?.(itemId); } From f3c346b8196f9bd4b60a77a81a7370a0423b1d85 Mon Sep 17 00:00:00 2001 From: Toofan Mohammadi Date: Thu, 12 Nov 2026 01:38:31 +0330 Subject: [PATCH 2/2] fix(roadmap): render dependency arrows reliably --- .../collections/CollectionRoadmap.svelte | 42 +++++++++++-------- 1 file changed, 24 insertions(+), 18 deletions(-) diff --git a/frontend/src/lib/features/collections/CollectionRoadmap.svelte b/frontend/src/lib/features/collections/CollectionRoadmap.svelte index a1f29b0b7..fa693e6b5 100644 --- a/frontend/src/lib/features/collections/CollectionRoadmap.svelte +++ b/frontend/src/lib/features/collections/CollectionRoadmap.svelte @@ -593,7 +593,8 @@ const source = itemMap.get(link.source_id); const target = itemMap.get(link.target_id); if (source && target) { - arrows.push({ source, target }); + // "Depends On" links run from the dependent (source) to its blocker (target). + arrows.push({ blocker: target, dependent: source }); } } } @@ -648,9 +649,10 @@ // Sync collection name and load links when items change $effect(() => { + const dependencyLinkTypeId = roadmapConfig.dependency_link_type_id; if (!collectionStore.loading) { currentCollectionName = collectionStore.collectionName; - untrack(() => loadLinksForItems(allItemsSorted)); + if (dependencyLinkTypeId) untrack(() => loadLinksForItems(allItemsSorted)); } }); @@ -914,15 +916,20 @@ return { startOffset: 0, endOffset: 0 }; } - // SVG arrow path between two items (using treeData indices) - function getArrowPath(source, target, sourceIndex, targetIndex) { - const x1 = (source.barEnd + gridOffset) * colWidth; - const y1 = sourceIndex * ROW_HEIGHT + ROW_HEIGHT / 2; - const x2 = (target.barStart + gridOffset) * colWidth; - const y2 = targetIndex * ROW_HEIGHT + ROW_HEIGHT / 2; - + // Connect the facing bar ends, with direction from blocker to dependent. + function getArrowGeometry(blocker, dependent, blockerIndex, dependentIndex) { + const forward = blocker.barStart + blocker.barEnd <= dependent.barStart + dependent.barEnd; + const x1 = ((forward ? blocker.barEnd : blocker.barStart) + gridOffset) * colWidth; + const y1 = blockerIndex * ROW_HEIGHT + ROW_HEIGHT / 2; + const x2 = ((forward ? dependent.barStart : dependent.barEnd) + gridOffset) * colWidth; + const y2 = dependentIndex * ROW_HEIGHT + ROW_HEIGHT / 2; const midX = (x1 + x2) / 2; - return `M ${x1} ${y1} C ${midX} ${y1}, ${midX} ${y2}, ${x2} ${y2}`; + return { + path: `M ${x1} ${y1} C ${midX} ${y1}, ${midX} ${y2}, ${x2} ${y2}`, + head: forward + ? `${x2},${y2} ${x2 - 6},${y2 - 4} ${x2 - 6},${y2 + 4}` + : `${x2},${y2} ${x2 + 6},${y2 - 4} ${x2 + 6},${y2 + 4}`, + }; } // --- Panel resize handlers --- @@ -1505,7 +1512,7 @@ {@const visibleColor = getVisibleColor(roadmapItem.statusColor)} {#if roadmapItem.isMilestone && !roadmapConfig.end_field_id} - + {#each dependencyArrows as arrow} - {@const sourceIdx = treeData.findIndex(i => i.id === arrow.source.id)} - {@const targetIdx = treeData.findIndex(i => i.id === arrow.target.id)} - {#if sourceIdx !== -1 && targetIdx !== -1} + {@const blockerIdx = treeData.findIndex(i => i.id === arrow.blocker.id)} + {@const dependentIdx = treeData.findIndex(i => i.id === arrow.dependent.id)} + {@const geometry = getArrowGeometry(arrow.blocker, arrow.dependent, blockerIdx, dependentIdx)} + {#if blockerIdx !== -1 && dependentIdx !== -1} - {@const tx = (arrow.target.barStart + gridOffset) * colWidth} - {@const ty = targetIdx * ROW_HEIGHT + ROW_HEIGHT / 2}