|
5 | 5 | * @see specs/016-entity-relationship-viz/data-model.md |
6 | 6 | */ |
7 | 7 |
|
8 | | -import { Anchor, Group, Stack, Text } from '@mantine/core'; |
| 8 | +import { Anchor, Badge, Group, Stack, Text, Tooltip } from '@mantine/core'; |
| 9 | +import { IconArrowDownLeft, IconArrowRight } from '@tabler/icons-react'; |
9 | 10 | import { useNavigate } from '@tanstack/react-router'; |
10 | 11 | import React from 'react'; |
11 | 12 |
|
| 13 | +import { ICON_SIZE } from '@/config/style-constants'; |
12 | 14 | import type { RelationshipItem as RelationshipItemType } from '@/types/relationship'; |
13 | 15 | import { decodeHtmlEntities } from '@/utils/decode-html-entities'; |
14 | 16 | import { formatMetadata } from '@/utils/formatMetadata'; |
@@ -72,25 +74,61 @@ export const RelationshipItem: React.FC<RelationshipItemProps> = ({ item }) => { |
72 | 74 | // Otherwise, let the browser handle it (opens in new tab, etc.) |
73 | 75 | }; |
74 | 76 |
|
| 77 | + // Direction indicator configuration |
| 78 | + const getDirectionBadge = () => { |
| 79 | + const isOutbound = item.direction === 'outbound'; |
| 80 | + |
| 81 | + return ( |
| 82 | + <Tooltip |
| 83 | + label={isOutbound ? 'This entity references the related entity' : 'The related entity references this one'} |
| 84 | + position="top" |
| 85 | + > |
| 86 | + <Badge |
| 87 | + size="xs" |
| 88 | + variant="light" |
| 89 | + color={isOutbound ? 'blue' : 'green'} |
| 90 | + leftSection={ |
| 91 | + isOutbound ? ( |
| 92 | + <IconArrowRight size={ICON_SIZE.XS} /> |
| 93 | + ) : ( |
| 94 | + <IconArrowDownLeft size={ICON_SIZE.XS} /> |
| 95 | + ) |
| 96 | + } |
| 97 | + > |
| 98 | + {isOutbound ? 'Outgoing' : 'Incoming'} |
| 99 | + </Badge> |
| 100 | + </Tooltip> |
| 101 | + ); |
| 102 | + }; |
| 103 | + |
75 | 104 | return ( |
76 | 105 | <Stack gap="xs" data-testid={`relationship-item-${item.id}`}> |
77 | | - <Group gap="xs"> |
78 | | - <Anchor href={entityUrl} onClick={handleClick} size="sm"> |
79 | | - {decodeHtmlEntities(item.displayName || cleanEntityId)} |
80 | | - </Anchor> |
81 | | - {item.isSelfReference && ( |
82 | | - <Text size="xs" c="dimmed"> |
83 | | - (self-reference) |
84 | | - </Text> |
85 | | - )} |
| 106 | + <Group gap="sm" justify="space-between" align="start" wrap="nowrap"> |
| 107 | + <Group gap="xs" style={{ flex: 1, minWidth: 0 }}> |
| 108 | + {getDirectionBadge()} |
| 109 | + <Anchor |
| 110 | + href={entityUrl} |
| 111 | + onClick={handleClick} |
| 112 | + size="sm" |
| 113 | + fw={500} |
| 114 | + style={{ wordBreak: 'break-word' }} |
| 115 | + > |
| 116 | + {decodeHtmlEntities(item.displayName || cleanEntityId)} |
| 117 | + </Anchor> |
| 118 | + {item.isSelfReference && ( |
| 119 | + <Badge size="xs" variant="outline" color="gray"> |
| 120 | + Self |
| 121 | + </Badge> |
| 122 | + )} |
| 123 | + </Group> |
86 | 124 | </Group> |
87 | 125 | {item.subtitle && ( |
88 | | - <Text size="xs" c="dimmed" data-testid="relationship-subtitle"> |
| 126 | + <Text size="xs" c="dimmed" data-testid="relationship-subtitle" ml={4}> |
89 | 127 | {decodeHtmlEntities(item.subtitle)} |
90 | 128 | </Text> |
91 | 129 | )} |
92 | 130 | {item.metadata && ( |
93 | | - <Text size="xs" c="dimmed" data-testid="relationship-metadata"> |
| 131 | + <Text size="xs" c="dimmed" data-testid="relationship-metadata" ml={4}> |
94 | 132 | {formatMetadata(item.metadata)} |
95 | 133 | </Text> |
96 | 134 | )} |
|
0 commit comments