diff --git a/packages/mermaid/src/diagrams/kanban/kanbanDb.ts b/packages/mermaid/src/diagrams/kanban/kanbanDb.ts index 260b1d32a..478c37803 100644 --- a/packages/mermaid/src/diagrams/kanban/kanbanDb.ts +++ b/packages/mermaid/src/diagrams/kanban/kanbanDb.ts @@ -130,7 +130,8 @@ const addNode = (level: number, id: string, descr: string, type: number, shapeDa throw new Error(`No such shape: ${doc.shape}. Shape names should be lowercase.`); } - if (doc?.shape) { + // if shape is defined in the yaml data, use it if it is a valid shape kanbanItem + if (doc?.shape && doc.shape === 'kanbanItem') { node.shape = doc?.shape; } if (doc?.label) { diff --git a/packages/mermaid/src/rendering-util/rendering-elements/shapes/kanbanItem.ts b/packages/mermaid/src/rendering-util/rendering-elements/shapes/kanbanItem.ts index 4dc6324a7..34ba7873d 100644 --- a/packages/mermaid/src/rendering-util/rendering-elements/shapes/kanbanItem.ts +++ b/packages/mermaid/src/rendering-util/rendering-elements/shapes/kanbanItem.ts @@ -6,25 +6,26 @@ import { userNodeOverrides, styles2String } from './handDrawnShapeStyles.js'; import rough from 'roughjs'; import type { D3Selection } from '../../../types.js'; -const colorFromPriority = (priority: KanbanNode['priority']) => { +const colorFromPriority = (priority: NonNullable) => { switch (priority) { case 'Very High': return 'red'; case 'High': return 'orange'; + case 'Medium': + return null; // no stroke case 'Low': return 'blue'; case 'Very Low': return 'lightblue'; } }; -export const kanbanItem = async ( +export async function kanbanItem( parent: D3Selection, - node: Node, + // Omit the 'shape' prop since otherwise, it causes a TypeScript circular dependency error + kanbanNode: Omit | Omit, { config }: ShapeRenderOptions -) => { - const unknownNode = node as unknown; - const kanbanNode = unknownNode as KanbanNode; +) { const { labelStyles, nodeStyles } = styles2String(kanbanNode); kanbanNode.labelStyle = labelStyles; @@ -42,7 +43,7 @@ export const kanbanItem = async ( let ticketUrl = ''; let link; - if (kanbanNode.ticket && config?.kanban?.ticketBaseUrl) { + if ('ticket' in kanbanNode && kanbanNode.ticket && config?.kanban?.ticketBaseUrl) { ticketUrl = config?.kanban?.ticketBaseUrl.replace('#TICKET#', kanbanNode.ticket); link = shapeSvg .insert('svg:a', ':first-child') @@ -62,17 +63,21 @@ export const kanbanItem = async ( }; let labelEl, bbox2; if (link) { - ({ label: labelEl, bbox: bbox2 } = await insertLabel(link, kanbanNode.ticket || '', options)); + ({ label: labelEl, bbox: bbox2 } = await insertLabel( + link, + ('ticket' in kanbanNode && kanbanNode.ticket) || '', + options + )); } else { ({ label: labelEl, bbox: bbox2 } = await insertLabel( shapeSvg, - kanbanNode.ticket || '', + ('ticket' in kanbanNode && kanbanNode.ticket) || '', options )); } const { label: labelElAssigned, bbox: bboxAssigned } = await insertLabel( shapeSvg, - kanbanNode.assigned || '', + ('assigned' in kanbanNode && kanbanNode.assigned) || '', options ); kanbanNode.width = orgWidth; @@ -129,7 +134,9 @@ export const kanbanItem = async ( .attr('y', y) .attr('width', totalWidth) .attr('height', totalHeight); - if (kanbanNode.priority) { + + const priority = 'priority' in kanbanNode && kanbanNode.priority; + if (priority) { const line = shapeSvg.append('line', ':first-child'); const lineX = x + 2; @@ -142,7 +149,7 @@ export const kanbanItem = async ( .attr('y2', y2) .attr('stroke-width', '4') - .attr('stroke', colorFromPriority(kanbanNode.priority)); + .attr('stroke', colorFromPriority(priority)); } } @@ -154,4 +161,4 @@ export const kanbanItem = async ( }; return shapeSvg; -}; +}