128 lines
3.6 KiB
HTML
128 lines
3.6 KiB
HTML
|
|
<style>
|
|
#erd svg { width: 100%; height: auto; }
|
|
#erd svg.erDiagram .divider path { stroke-opacity: 0.4; }
|
|
#erd svg.erDiagram .row-rect-odd path,
|
|
#erd svg.erDiagram .row-rect-odd rect,
|
|
#erd svg.erDiagram .row-rect-even path,
|
|
#erd svg.erDiagram .row-rect-even rect { stroke: none !important; }
|
|
</style>
|
|
<div id="erd" style="padding: 1rem 0;"></div>
|
|
<script type="module">
|
|
import mermaid from 'https://esm.sh/mermaid@11/dist/mermaid.esm.min.mjs';
|
|
const dark = matchMedia('(prefers-color-scheme: dark)').matches;
|
|
await document.fonts.ready;
|
|
mermaid.initialize({
|
|
startOnLoad: false,
|
|
theme: 'base',
|
|
fontFamily: '"Anthropic Sans", sans-serif',
|
|
themeVariables: {
|
|
darkMode: dark,
|
|
fontSize: '13px',
|
|
fontFamily: '"Anthropic Sans", sans-serif',
|
|
lineColor: dark ? '#9c9a92' : '#73726c',
|
|
textColor: dark ? '#c2c0b6' : '#3d3d3a',
|
|
primaryColor: dark ? '#3C3489' : '#EEEDFE',
|
|
primaryTextColor: dark ? '#CECBF6' : '#3C3489',
|
|
primaryBorderColor: dark ? '#7F77DD' : '#534AB7',
|
|
secondaryColor: dark ? '#085041' : '#E1F5EE',
|
|
tertiaryColor: dark ? '#712B13' : '#FAECE7',
|
|
},
|
|
});
|
|
const diagram = `erDiagram
|
|
staff_users {
|
|
uuid id PK
|
|
string name
|
|
string email
|
|
string role
|
|
}
|
|
devices {
|
|
uuid id PK
|
|
string serial_number
|
|
string firmware_version
|
|
string firestore_doc_id
|
|
}
|
|
app_users {
|
|
uuid id PK
|
|
string email
|
|
string display_name
|
|
string firestore_uid
|
|
}
|
|
customers {
|
|
uuid id PK
|
|
string full_name
|
|
string email
|
|
string phone
|
|
timestamp created_at
|
|
}
|
|
entries {
|
|
uuid id PK
|
|
uuid author_id FK
|
|
varchar type
|
|
varchar status
|
|
varchar severity
|
|
string title
|
|
text body
|
|
timestamp created_at
|
|
timestamp updated_at
|
|
}
|
|
entry_links {
|
|
uuid id PK
|
|
uuid entry_id FK
|
|
varchar entity_type
|
|
uuid entity_id
|
|
}
|
|
support_tickets {
|
|
uuid id PK
|
|
uuid customer_id FK
|
|
uuid device_id FK
|
|
uuid linked_entry_id FK
|
|
varchar status
|
|
varchar priority
|
|
varchar opened_via
|
|
timestamp created_at
|
|
timestamp updated_at
|
|
}
|
|
ticket_messages {
|
|
uuid id PK
|
|
uuid ticket_id FK
|
|
uuid sender_id
|
|
varchar sender_type
|
|
text body
|
|
timestamp created_at
|
|
}
|
|
|
|
staff_users ||--o{ entries : "authors"
|
|
entries ||--o{ entry_links : "has links"
|
|
support_tickets ||--o{ ticket_messages : "has messages"
|
|
customers ||--o{ support_tickets : "opens"
|
|
devices ||--o{ support_tickets : "subject of"
|
|
entries ||--o| support_tickets : "escalated to"
|
|
`;
|
|
const { svg } = await mermaid.render('erd-svg', diagram);
|
|
document.getElementById('erd').innerHTML = svg;
|
|
|
|
document.querySelectorAll('#erd svg.erDiagram .node').forEach(node => {
|
|
const firstPath = node.querySelector('path[d]');
|
|
if (!firstPath) return;
|
|
const d = firstPath.getAttribute('d');
|
|
const nums = d.match(/-?[\d.]+/g)?.map(Number);
|
|
if (!nums || nums.length < 8) return;
|
|
const xs = [nums[0], nums[2], nums[4], nums[6]];
|
|
const ys = [nums[1], nums[3], nums[5], nums[7]];
|
|
const x = Math.min(...xs), y = Math.min(...ys);
|
|
const w = Math.max(...xs) - x, h = Math.max(...ys) - y;
|
|
const rect = document.createElementNS('http://www.w3.org/2000/svg', 'rect');
|
|
rect.setAttribute('x', x); rect.setAttribute('y', y);
|
|
rect.setAttribute('width', w); rect.setAttribute('height', h);
|
|
rect.setAttribute('rx', '8');
|
|
for (const a of ['fill', 'stroke', 'stroke-width', 'class', 'style']) {
|
|
if (firstPath.hasAttribute(a)) rect.setAttribute(a, firstPath.getAttribute(a));
|
|
}
|
|
firstPath.replaceWith(rect);
|
|
});
|
|
document.querySelectorAll('#erd svg.erDiagram .row-rect-odd path, #erd svg.erDiagram .row-rect-even path').forEach(p => {
|
|
p.setAttribute('stroke', 'none');
|
|
});
|
|
</script>
|