Skip to content

mermaid_node

mermaid_node

MermaidNode — represents a node in a Mermaid diagram.

MermaidNode dataclass

MermaidNode(
    id: str,
    name: str,
    type: str,
    subtitle: str | None = None,
    domo_instance: str | None = None,
    alias: str | None = None,
    css_class: str | None = None,
    shape: str | None = None,
    url: str | None = None,
)

Represents a node in a Mermaid diagram.

Structured label (rendered at to_string time): Line 1: name (entity title) Line 2: subtitle (chart_type, data_provider_type, or class name) Line 3: domo_instance (if show_instance=True) Line 4: id (if show_entity_id=True)

Attributes:

Name Type Description
id str

Unique identifier for the node

name str

Display name for the entity (title only — no metadata baked in)

type str

Entity type (e.g., PAGE, CARD, DATA_SOURCE)

subtitle str | None

Second line — chart_type, data_provider_type, or class name

domo_instance str | None

Domo instance name (for federated/multi-instance diagrams)

alias str | None

Short alias for the node (e.g., "A", "B", "C") - auto-generated

css_class str | None

Optional CSS class for styling (e.g., "FederatedDataset")

shape str | None

Mermaid shape name (e.g., "cyl", "notch-rect", "fr-rect")

url str | None

Optional URL for click directive linking to the entity in Domo

mermaid_id property

mermaid_id: str

Generate a Mermaid-safe node ID.

from_domo_entity classmethod

from_domo_entity(entity: Any) -> MermaidNode

Create a MermaidNode from a Domo entity (DomoPage, DomoDataset, etc.).

Source code in src/crew_dcs/integrations/graphs/mermaid/mermaid_node.py
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
@classmethod
def from_domo_entity(cls, entity: Any) -> MermaidNode:
    """Create a MermaidNode from a Domo entity (DomoPage, DomoDataset, etc.)."""
    name = _resolve_entity_name(entity)
    url = getattr(entity, "display_url", None)
    subtitle = _resolve_subtitle(entity)
    domo_instance = _resolve_domo_instance(entity)

    return cls(
        id=str(entity.id),
        name=name,
        type=entity.entity_type,
        subtitle=subtitle,
        domo_instance=domo_instance,
        url=url,
    )
from_lineage_link(lineage_link: Any) -> MermaidNode

Create a MermaidNode from a lineage link item.

Structured label: - Line 1: entity name - Line 2: chart_type / data_provider_type / class name - Line 3: domo_instance (stored but only shown if flag is set)

Source code in src/crew_dcs/integrations/graphs/mermaid/mermaid_node.py
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
@classmethod
def from_lineage_link(cls, lineage_link: Any) -> MermaidNode:
    """Create a MermaidNode from a lineage link item.

    Structured label:
    - Line 1: entity name
    - Line 2: chart_type / data_provider_type / class name
    - Line 3: domo_instance (stored but only shown if flag is set)
    """
    if lineage_link.entity:
        entity = lineage_link.entity
        name = _resolve_entity_name(entity)
        url = getattr(entity, "display_url", None)
        subtitle = _resolve_subtitle(entity)
        domo_instance = _resolve_domo_instance(entity)

        return cls(
            id=str(entity.id),
            name=name,
            type=entity.entity_type,
            subtitle=subtitle,
            domo_instance=domo_instance,
            url=url,
        )

    return cls(
        id=str(lineage_link.id),
        name=str(lineage_link.id),
        type=lineage_link.type,
    )

from_lineage_node classmethod

from_lineage_node(node: LineageNode) -> MermaidNode

Create a MermaidNode from a LineageNode with formatted display.

Source code in src/crew_dcs/integrations/graphs/mermaid/mermaid_node.py
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
@classmethod
def from_lineage_node(
    cls,
    node: LineageNode,
) -> MermaidNode:
    """Create a MermaidNode from a LineageNode with formatted display."""
    entity_name = node.name or str(node.id)

    subtitle = None
    domo_instance = None

    if node.entity:
        domo_instance = _resolve_domo_instance(node.entity)
        subtitle = _resolve_subtitle(node.entity)

    if not subtitle:
        # Fallback: entity_type as title case
        subtitle = node.entity_type.replace("_", " ").title()

    css_class = None
    if node.entity and getattr(node.entity, "is_federated", False):
        clean_type = node.entity_type.replace("_", "").title()
        css_class = f"Federated{clean_type}"
    elif node.entity_type in ("SUBSCRIPTION", "PUBLICATION"):
        css_class = node.entity_type.title()

    return cls(
        id=str(node.id),
        name=entity_name,
        type=node.entity_type,
        subtitle=subtitle,
        domo_instance=domo_instance,
        css_class=css_class,
    )

to_string

to_string(
    use_alias: bool = False,
    indentation: int = 4,
    *,
    show_instance: bool = False,
    show_entity_id: bool = False
) -> str

Render the node as a Mermaid node definition.

Uses the v11.3.0+ @{ shape: <name> } syntax when a shape is set, falling back to the bracket syntax (["name"]) otherwise.

Parameters:

Name Type Description Default
use_alias bool

If True, use the alias instead of full ID

False
indentation int

Number of spaces to indent

4
show_instance bool

If True, include domo_instance on line 3

False
show_entity_id bool

If True, include entity ID on line 4

False
Source code in src/crew_dcs/integrations/graphs/mermaid/mermaid_node.py
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
def to_string(
    self,
    use_alias: bool = False,
    indentation: int = 4,
    *,
    show_instance: bool = False,
    show_entity_id: bool = False,
) -> str:
    """Render the node as a Mermaid node definition.

    Uses the v11.3.0+ ``@{ shape: <name> }`` syntax when a shape is set,
    falling back to the bracket syntax (``["name"]``) otherwise.

    Args:
        use_alias: If True, use the alias instead of full ID
        indentation: Number of spaces to indent
        show_instance: If True, include domo_instance on line 3
        show_entity_id: If True, include entity ID on line 4
    """
    label = self._build_label(
        show_instance=show_instance,
        show_entity_id=show_entity_id,
    )
    safe_label = label.replace('"', "'").replace("\n", " ")

    if use_alias and self.alias:
        node_id = self.alias
    else:
        node_id = f"{self.type}_{self.id}".replace("-", "_").replace(" ", "_")[:50]

    # Resolve shape: explicit > entity-type mapping > default (rect)
    shape = self.shape or self.ENTITY_TYPE_SHAPES.get(self.type)

    if shape:
        return f'{" " * indentation}{node_id}@{{ shape: {shape}, label: "{safe_label}" }}'

    return f'{" " * indentation}{node_id}["{safe_label}"]'