drixio 1.1.7 → 1.1.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,497 +0,0 @@
1
- (function(){let e=document.createElement(`link`).relList;if(e&&e.supports&&e.supports(`modulepreload`))return;for(let e of document.querySelectorAll(`link[rel="modulepreload"]`))n(e);new MutationObserver(e=>{for(let t of e)if(t.type===`childList`)for(let e of t.addedNodes)e.tagName===`LINK`&&e.rel===`modulepreload`&&n(e)}).observe(document,{childList:!0,subtree:!0});function t(e){let t={};return e.integrity&&(t.integrity=e.integrity),e.referrerPolicy&&(t.referrerPolicy=e.referrerPolicy),e.crossOrigin===`use-credentials`?t.credentials=`include`:e.crossOrigin===`anonymous`?t.credentials=`omit`:t.credentials=`same-origin`,t}function n(e){if(e.ep)return;e.ep=!0;let n=t(e);fetch(e.href,n)}})();var e=`
2
- <header>
3
- <div id="current-path">
4
- <span id="db-name">database</span>
5
- <span id="slash">/</span>
6
- <div id="current-table">
7
- <span class="material-symbols-outlined" id="table-icon"> table </span>
8
- <span id="table-name">users</span>
9
- </div>
10
- </div>
11
-
12
-
13
- <div class="header-actions" style="position: relative;">
14
- <button id="import-btn" class="secondary" title="Import">
15
- <span id="import-icon" class="material-symbols-outlined">upload</span>
16
- Import
17
- </button>
18
- <button id="export-btn" class="primary" title="Export">
19
- <span id="export-icon" class="material-symbols-outlined">download</span>
20
- Export
21
- <span id="export-arrow-icon" class="material-symbols-outlined">arrow_drop_down</span>
22
- </button>
23
- <ul id="export-dropdown" class="dropdown-menu hidden">
24
- <li class="dropdown-submenu">
25
- <a class="dropdown-item">
26
- <span class="material-symbols-outlined">table</span> Data
27
- <span class="caret material-symbols-outlined">chevron_right</span>
28
- </a>
29
- <ul class="dropdown-menu sub-menu">
30
- <li><button id="export-data-csv-btn" class="dropdown-item">Export as CSV</button></li>
31
- <li><button id="export-data-json-btn" class="dropdown-item">Export as JSON</button></li>
32
- <li class="data-tab-only" style="display: none;"><button id="export-data-filtered-csv-btn" class="dropdown-item" style="color: var(--color-primary);">Export as CSV with Queries</button></li>
33
- <li class="data-tab-only" style="display: none;"><button id="export-data-filtered-json-btn" class="dropdown-item" style="color: var(--color-primary);">Export as JSON with Queries</button></li>
34
- </ul>
35
- </li>
36
-
37
- <li class="dropdown-submenu">
38
- <a class="dropdown-item">
39
- <span class="material-symbols-outlined">schema</span> Schema
40
- <span class="caret material-symbols-outlined">chevron_right</span>
41
- </a>
42
- <ul class="dropdown-menu sub-menu">
43
- <li><button id="export-schema-dict-btn" class="dropdown-item">Data Dictionary (.md)</button></li>
44
- <li><button id="export-schema-sql-btn" class="dropdown-item">Schema Only (.sql)</button></li>
45
- </ul>
46
- </li>
47
-
48
- <li class="dropdown-submenu console-tab-only" style="display: none;">
49
- <a class="dropdown-item">
50
- <span class="material-symbols-outlined">terminal</span> SQL Console
51
- <span class="caret material-symbols-outlined">chevron_right</span>
52
- </a>
53
- <ul class="dropdown-menu sub-menu">
54
- <li><button id="export-console-csv-btn" class="dropdown-item">Export Result (CSV)</button></li>
55
- <li><button id="export-console-json-btn" class="dropdown-item">Export Result (JSON)</button></li>
56
- </ul>
57
- </li>
58
-
59
- <li class="dropdown-submenu">
60
- <a class="dropdown-item">
61
- <span class="material-symbols-outlined">account_tree</span> ERD
62
- <span class="caret material-symbols-outlined">chevron_right</span>
63
- </a>
64
- <ul class="dropdown-menu sub-menu">
65
- <li><button id="export-erd-json-btn" class="dropdown-item">Export Layout (JSON)</button></li>
66
- </ul>
67
- </li>
68
-
69
- <li class="dropdown-divider"></li>
70
-
71
- <li>
72
- <button id="export-db-sql-btn" class="dropdown-item">
73
- <span class="material-symbols-outlined">database</span>
74
- Database (.sql)
75
- </button>
76
- </li>
77
- </ul>
78
- </div>
79
- </header>
80
- `,t=`
81
- <aside>
82
- <div id="sidebar-header">
83
- <span class="material-symbols-outlined" id="database-icon"> database </span>
84
- <h1 id="brand-title">
85
- DRIXIO
86
- <p id="brand-subtitle">STUDIO</p>
87
- </h1>
88
- </div>
89
-
90
- <div id="sidebar-content">
91
- <div id="search-bar">
92
- <span class="material-symbols-outlined" id="search-icon"> search </span>
93
- <input type="text" placeholder="Search" id="search-input" />
94
- </div>
95
-
96
- <nav id="table-nav">
97
- <!-- Display All Table -->
98
- </nav>
99
- </div>
100
-
101
- <div id="sidebar-footer">
102
- <button id="theme-toggle" title="Toggle Dark Mode">
103
- <span class="material-symbols-outlined" id="theme-icon">dark_mode</span>
104
- Theme
105
- </button>
106
- </div>
107
- </aside>
108
- `,n=`
109
- <nav id="tab-nav">
110
- <button
111
- type="button"
112
- class="tab-btn"
113
- onclick="handleSwitchTab('data-btn')"
114
- id="data-btn"
115
- >
116
- <span class="material-symbols-outlined" id="data-icon"> table_rows </span>
117
- Data
118
- </button>
119
- <button
120
- class="tab-btn"
121
- onclick="handleSwitchTab('schema-btn')"
122
- id="schema-btn"
123
- >
124
- <span class="material-symbols-outlined" id="schema-icon">
125
- grid_layout_side
126
- </span>
127
- Schema (Table)
128
- </button>
129
-
130
- <div class="flex-1"></div>
131
-
132
- <button class="tab-btn" onclick="handleSwitchTab('status-btn')" id="status-btn">
133
- <span class="material-symbols-outlined" id="status-icon"> database </span>
134
- Database Status
135
- </button>
136
- <button class="tab-btn" onclick="handleSwitchTab('erd-btn')" id="erd-btn">
137
- <span class="material-symbols-outlined" id="erd-icon"> schema </span>
138
- ERD Visualization
139
- </button>
140
- <button class="tab-btn" onclick="handleSwitchTab('sql-btn')" id="sql-btn">
141
- <span class="material-symbols-outlined" id="sql-icon"> code </span>
142
- SQL Console
143
- </button>
144
- </nav>
145
- `;async function r(){return await(await fetch(`/api/tables`)).json()}async function i(){return await(await fetch(`/api/config`)).json()}async function a(){return await(await fetch(`/api/tables/stats`)).json()}async function o(e,t={}){let{where:n=``,limit:r=50,offset:i=0,orderCol:a,orderAsc:o}=t,s=new URLSearchParams;n&&s.append(`where`,n),s.append(`limit`,r.toString()),s.append(`offset`,i.toString()),a&&(s.append(`orderCol`,a),s.append(`orderAsc`,o===!1?`false`:`true`));let c=`/api/tables/${e}/data?${s.toString()}`;return await(await fetch(c)).json()}async function s(e){return await(await fetch(`/api/tables/${e}/schema`)).json()}async function c(e){return await(await fetch(`/api/tables/${e}/indexes`)).json()}async function l(e){return await(await fetch(`/api/query`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({sql:e})})).json()}async function u(){try{let e=await r(),t=document.getElementById(`table-nav`),n=document.getElementById(`not-found-msg`);n&&n.remove(),e.success&&e.data&&e.data.length>0?(e.data.forEach(e=>{let n=document.createElement(`button`);n.type=`button`,n.className=`table-btn`,n.dataset.table=e,n.innerHTML=`<span>${e}</span><span class="table-btn-badge" id="badge-${e}" class="hidden"></span>`,n.onclick=()=>{window.AppState.currentTable=e,window.AppState.currentTableBtnElement=n,window.AppState.currentTab===`erd-btn`||window.AppState.currentTab===`sql-btn`||window.AppState.currentTab===`status-btn`?window.handleSwitchTab(`data-btn`):window.renderCurrentView()},t.appendChild(n)}),window.handleSwitchTab(`data-btn`),a().then(e=>{e.success&&e.data&&Object.entries(e.data).forEach(([e,t])=>{let n=document.getElementById(`badge-${e}`);n&&(n.textContent=Number(t).toLocaleString(),n.style.display=`inline-flex`)})}).catch(e=>console.error(`Failed to load table stats:`,e))):(t.innerHTML=`<div id="not-found-msg">No Tables Found.</div>`,window.handleSwitchTab(`data-btn`))}catch(e){console.error(`Failed to fetch tables:`,e)}}function d(e,t){document.querySelectorAll(`#${e} .cell-in-range, #${e} .cell-selected, #${e} .range-top, #${e} .range-bottom, #${e} .range-left, #${e} .range-right, #${e} .row-header-selected`).forEach(e=>{e.classList.remove(`cell-in-range`,`cell-selected`,`range-top`,`range-bottom`,`range-left`,`range-right`,`row-header-selected`)});let n=t.selection;if(n.startRow===-1)return;let r=Math.min(n.startRow,n.endRow),i=Math.max(n.startRow,n.endRow),a=Math.min(n.startCol,n.endCol),o=Math.max(n.startCol,n.endCol);document.querySelectorAll(`#${e} td.data-cell`).forEach(e=>{let s=parseInt(e.dataset.rowIdx),c=parseInt(e.dataset.colIdx);s>=r&&s<=i&&c>=a&&c<=o&&(e.classList.add(`cell-in-range`),s===r&&e.classList.add(`range-top`),s===i&&e.classList.add(`range-bottom`),c===a&&e.classList.add(`range-left`),c===o&&e.classList.add(`range-right`),s===n.startRow&&c===n.startCol&&(e.classList.add(`cell-selected`),t.selectedCell=e))}),n.isDraggingRow&&document.querySelectorAll(`#${e} td.row-header`).forEach(e=>{let t=parseInt(e.dataset.rowIdx);t>=r&&t<=i&&e.classList.add(`row-header-selected`)})}function f(e,t,n,r){e.addEventListener(`mousedown`,e=>{if(e.target.tagName===`INPUT`||e.target.tagName===`SELECT`)return;let i=e.target.closest(`td.row-header`);if(i&&e.button!==2){let e=parseInt(i.dataset.rowIdx);n.selection={isDragging:!1,isDraggingRow:!0,startRow:e,endRow:e,startCol:0,endCol:r-1},d(t,n);return}let a=e.target.closest(`td.data-cell`);if(!a)return;let o=parseInt(a.dataset.rowIdx),s=parseInt(a.dataset.colIdx);n.selection={isDragging:!0,startRow:o,startCol:s,endRow:o,endCol:s},d(t,n)}),e.addEventListener(`mouseover`,e=>{if(n.selection.isDraggingRow){let r=e.target.closest(`td.row-header`);if(!r)return;n.selection.endRow=parseInt(r.dataset.rowIdx),d(t,n);return}if(!n.selection.isDragging)return;let r=e.target.closest(`td.data-cell`);r&&(n.selection.endRow=parseInt(r.dataset.rowIdx),n.selection.endCol=parseInt(r.dataset.colIdx),d(t,n))}),e.addEventListener(`mouseup`,()=>{n.selection&&(n.selection.isDragging=!1,n.selection.isDraggingRow=!1)})}function p(e,t){let n=document.createElement(`div`);n.className=`resizer`,e.appendChild(n),n.addEventListener(`click`,e=>e.stopPropagation()),n.addEventListener(`mousedown`,n=>{n.preventDefault(),n.stopPropagation();let r=n.pageX,i=e.offsetWidth,a=!1,o=n=>{a=!0,t&&(t.isResizing=!0);let o=i+(n.pageX-r);e.style.width=o+`px`,e.style.minWidth=o+`px`,e.style.maxWidth=o+`px`},s=()=>{document.removeEventListener(`mousemove`,o),document.removeEventListener(`mouseup`,s),document.body.style.cursor=``,a&&setTimeout(()=>{t&&(t.isResizing=!1)},100)};document.body.style.cursor=`col-resize`,document.addEventListener(`mousemove`,o),document.addEventListener(`mouseup`,s)})}async function m(){if(!window.DataGrid)return;let{pendingEdits:e,pendingInserts:t,pkColumn:n}=window.DataGrid,r=window.AppState.currentTable;if(!r||!n){alert(`Cannot save: No Primary Key detected for this table.`);return}let i=[];for(let[t,a]of Object.entries(e)){if(Object.keys(a).length===0)continue;let e=Object.entries(a).map(([e,t])=>t===``?`"${e}" = NULL`:`"${e}" = '${t.replace(/'/g,`''`)}'`).join(`, `);i.push(`UPDATE "${r}" SET ${e} WHERE "${n}" = '${t.replace(/'/g,`''`)}';`)}for(let e=0;e<t.length;e++){let n=t[e];if(Object.keys(n).length===0||!Object.values(n).some(e=>e!==``))continue;let a=Object.keys(n),o=a.map(e=>{let t=n[e];return t===``?`NULL`:`'${t.replace(/'/g,`''`)}'`});i.push(`INSERT INTO "${r}" ("${a.join(`", "`)}") VALUES (${o.join(`, `)});`)}if(window.DataGrid.pendingDeletes)for(let e of window.DataGrid.pendingDeletes)i.push(`DELETE FROM "${r}" WHERE "${n}" = '${e.replace(/'/g,`''`)}';`);if(i.length===0)return;let a=!0,o=``;for(let e of i)try{let t=await l(e);if(!t.success){a=!1,o=t.error;break}}catch(e){a=!1,o=e.message;break}a?(window.DataGrid&&(window.DataGrid.pendingEdits={},window.DataGrid.pendingInserts=[{}],window.DataGrid.pendingDeletes=new Set,window.DataGrid.history=[],window.DataGrid.currentTransaction=null,window.DataGrid.refreshData?window.DataGrid.refreshData():window.renderCurrentView()),window.showToast&&window.showToast(`Data saved successfully!`)):(window.showToast?window.showToast(`Save failed: `+o,`error`):alert(`Save failed:
146
- `+o),document.querySelectorAll(`.cell-edited`).forEach(e=>{e.classList.remove(`cell-edited`),e.classList.add(`cell-error`)})),window.updateSidebarDirtyState?.()}function h(e,t,n,r=!0){if(r&&window.DataGrid.currentTransaction){let n=e.textContent;(n===`null`||e.classList.contains(`ghost-row`))&&(n=``),n!==t&&window.DataGrid.currentTransaction.push({td:e,oldVal:n,newVal:t})}let i=e.dataset.col;if(e.innerHTML=t||(e.dataset.insertIndex===void 0?`<em>null</em>`:`+ New`),e.dataset.insertIndex!==void 0){let r=parseInt(e.dataset.insertIndex);if(window.DataGrid.pendingInserts[r]||(window.DataGrid.pendingInserts[r]={}),t){if(window.DataGrid.pendingInserts[r][i]=t,e.classList.add(`cell-edited`),e.classList.remove(`ghost-row`),r===window.DataGrid.pendingInserts.length-1){e.closest(`tr`).classList.remove(`ghost-row-tr`),window.DataGrid.pendingInserts.push({});let t=document.querySelector(`#data-grid-table-${window.AppState.currentTable} tbody`),i=document.createElement(`tr`);i.className=`ghost-row-tr`;let a=parseInt(e.dataset.rowIdx)+1;i.innerHTML+=`<td class="row-header" data-row-idx="${a}">*</td>`,n.forEach((e,t)=>{i.innerHTML+=`<td class="data-cell ghost-row" data-row-idx="${a}" data-col-idx="${t}" data-insert-index="${r+1}" data-col="${e}">+ New</td>`}),t.appendChild(i)}}else window.DataGrid.pendingInserts[r]&&delete window.DataGrid.pendingInserts[r][i],e.classList.remove(`cell-edited`),e.classList.add(`ghost-row`)}else{let n=e.dataset.pk;t===e.dataset.original?(e.classList.remove(`cell-edited`),e.classList.remove(`cell-error`),window.DataGrid.pendingEdits[n]&&(delete window.DataGrid.pendingEdits[n][i],Object.keys(window.DataGrid.pendingEdits[n]).length===0&&delete window.DataGrid.pendingEdits[n])):(window.DataGrid.pendingEdits[n]||(window.DataGrid.pendingEdits[n]={}),window.DataGrid.pendingEdits[n][i]=t,e.classList.add(`cell-edited`),e.classList.remove(`cell-error`))}window.updateSidebarDirtyState?.()}function g(e,t=!0){let n=document.querySelector(`#data-grid-table-${window.AppState.currentTable} td.data-cell[data-row-idx="${e}"]`)?.closest(`tr`);if(!n||n.classList.contains(`ghost-row-tr`)||n.classList.contains(`row-deleted`))return;let r=n.querySelector(`td.data-cell`)?.dataset.pk;r!==void 0&&(t&&window.DataGrid.currentTransaction&&window.DataGrid.currentTransaction.push({type:`delete`,rowIdx:e,pk:r}),window.DataGrid.pendingDeletes.add(r),n.classList.add(`row-deleted`)),window.updateSidebarDirtyState?.()}function _(e,t){let n=document.querySelector(`#data-grid-table-${window.AppState.currentTable} td.data-cell[data-row-idx="${e}"]`)?.closest(`tr`);n&&n.classList.remove(`row-deleted`),window.DataGrid.pendingDeletes.delete(t),window.updateSidebarDirtyState?.()}function v(e,t){e.forEach(e=>{let n=window.AppState.currentTable,r=document.querySelector(`#data-grid-table-${n} td.data-cell[data-row-idx="${e}"]`)?.closest(`tr`);if(!r||r.classList.contains(`ghost-row-tr`))return;let i=document.querySelector(`#data-grid-table-${n} .ghost-row-tr`);i&&t.forEach((e,n)=>{let a=r.querySelector(`td.data-cell[data-col-idx="${n}"]`),o=i.querySelector(`td.data-cell[data-col-idx="${n}"]`);if(a&&o){let n=a.dataset.insertIndex===void 0?a.classList.contains(`cell-edited`)?window.DataGrid.pendingEdits[a.dataset.pk]?.[e]:a.dataset.original:window.DataGrid.pendingInserts[a.dataset.insertIndex][e];n!=null&&n!==`null`&&h(o,n,t,!0)}})})}function y(e,t,n){e.addEventListener(`dblclick`,e=>{let r=e.target.closest(`td.data-cell`);if(!r||r.querySelector(`input, select`))return;let i=r.dataset.col,a=t.find(e=>e.name===i),o=a?.type?.toUpperCase()||``,s=o.includes(`ENUM`),c=o===`DATE`,u=o.includes(`DATETIME`)||o.includes(`TIMESTAMP`),d=o.includes(`BOOL`)||o===`TINYINT(1)`,f=r.textContent===`null`||r.textContent===`+ New`?``:r.textContent,p;if(a&&a.fkTarget){p=document.createElement(`select`);let e=document.createElement(`option`);e.value=f,e.textContent=`Loading...`,p.appendChild(e);let{table:t,column:n}=a.fkTarget;l(`SELECT * FROM "${t}" LIMIT 100`).then(e=>{if(e.success&&e.data&&e.data.rows){if(p.innerHTML=``,a.nullable){let e=document.createElement(`option`);e.value=``,e.textContent=`-- None --`,p.appendChild(e)}let t=n;if(e.data.columns){let n=[`name`,`title`,`label`,`description`],r=e.data.columns.find(e=>n.includes(e.toLowerCase()));r&&(t=r)}if(e.data.rows.forEach(e=>{let r=String(e[n]),i=t===n?r:`${r} - ${e[t]}`,a=document.createElement(`option`);a.value=r,a.textContent=i,r===f&&(a.selected=!0),p.appendChild(a)}),f&&!e.data.rows.find(e=>String(e[n])===f)){let e=document.createElement(`option`);e.value=f,e.textContent=`${f} (Not in limit)`,e.selected=!0,p.appendChild(e)}}}).catch(t=>{e.textContent=`Error loading options`})}else if(s){let e=a.type.match(/enum\((.*?)\)/i),t=[];e&&(t=e[1].split(`,`).map(e=>e.trim().replace(/^'|'$/g,``))),p=document.createElement(`select`),t.forEach(e=>{let t=document.createElement(`option`);t.value=e,t.textContent=e,e===f&&(t.selected=!0),p.appendChild(t)})}else if(c)p=document.createElement(`input`),p.type=`date`,p.value=f;else if(u){p=document.createElement(`input`),p.type=`datetime-local`;let e=f.replace(` `,`T`).slice(0,16);p.value=e}else d?(p=document.createElement(`input`),p.type=`checkbox`,p.checked=f===`1`||f.toLowerCase()===`true`):(p=document.createElement(`input`),p.type=`text`,p.value=f);let m=!1,g=()=>{m=!0;let e=document.getElementById(`modal-editor-overlay`),t=document.getElementById(`modal-textarea`),n=document.getElementById(`modal-cancel-btn`),r=document.getElementById(`modal-save-btn`),a=document.getElementById(`modal-title`);a.textContent=`Edit ${i}`,t.value=p.value,e.style.display=`flex`,t.focus();let o=()=>{e.style.display=`none`,r.onclick=null,n.onclick=null,m=!1,p.focus()};n.onclick=o,r.onclick=()=>{p.value=t.value,o(),_()}};if(r.innerHTML=``,r.appendChild(p),o===``||!s&&!c&&!u&&!d&&!(a&&a.fkTarget)){let e=document.createElement(`span`);e.className=`material-symbols-outlined cell-expand-btn`,e.textContent=`open_in_full`,e.onmousedown=e=>e.preventDefault(),e.onclick=()=>g(),r.appendChild(e),p.style.width=`100%`,p.style.paddingRight=`32px`,p.addEventListener(`keydown`,e=>{e.key===`Enter`&&e.shiftKey?(e.preventDefault(),g()):e.key===`Enter`&&p.blur(),e.key===`Tab`&&(e.preventDefault(),p.blur(),document.body.dispatchEvent(new KeyboardEvent(`keydown`,{key:`Tab`,shiftKey:e.shiftKey,bubbles:!0})))})}else p.addEventListener(`keydown`,e=>{e.key===`Enter`&&p.blur(),e.key===`Tab`&&(e.preventDefault(),p.blur(),document.body.dispatchEvent(new KeyboardEvent(`keydown`,{key:`Tab`,shiftKey:e.shiftKey,bubbles:!0})))});p.focus();let _=()=>{if(m)return;let e=d?p.checked?`1`:`0`:p.value;u&&e&&(e=e.replace(`T`,` `)+`:00`),window.DataGrid.currentTransaction=[],h(r,e,n),window.DataGrid.currentTransaction.length>0&&window.DataGrid.history.push(window.DataGrid.currentTransaction),window.DataGrid.currentTransaction=null};p.addEventListener(`blur`,()=>{setTimeout(()=>{m||_()},100)})})}function b(){let e=window.AppState?.currentTable;if(!e)return``;let t=document.getElementById(`filter-val-${e}`)?.value.trim(),n=document.getElementById(`filter-op-${e}`)?.value,r=document.getElementById(`filter-col-${e}`)?.value,i=``;if(t||n===`IS NULL`){let e=t;e&&!e.startsWith(`'`)&&!e.endsWith(`'`)&&isNaN(Number(e))&&(e.toUpperCase().includes(` AND `)||e.toUpperCase().includes(` OR `)||(e=`'${e.replace(/'/g,`''`)}'`)),i=`"${r}" ${n} ${e}`}return i}function x(e,t,n,r){let i=`<td class="row-header" data-row-idx="${t}">${t+1}</td>`,a=n?e[n]:t;return r.forEach((n,r)=>{let o=e[n]===null?`null`:String(e[n]),s=o.replace(/"/g,`&quot;`),c=o===`null`?`<em>null</em>`:o.replace(/</g,`&lt;`);i+=`<td class="data-cell" data-row-idx="${t}" data-col-idx="${r}" data-pk="${a}" data-col="${n}" data-original="${s}">${c}</td>`}),i}async function S(e,t,n=``,r=!1,i=null){document.querySelectorAll(`.table-btn`).forEach(e=>e.classList.remove(`active`)),t&&t.classList.add(`active`);let a=document.getElementById(`table-name`);a&&(a.textContent=e);let c=i||document.getElementById(`main-content`);r||(c.innerHTML=`<div class='p-6'>Loading...</div>`);try{let i=await s(e);if(!i.success)throw Error(i.error);let a=i.data,l=a.find(e=>e.isPk)?.name;(!r||!window.DataGrid)&&(window.DataGrid={schema:a,pkColumn:l,pendingEdits:{},pendingInserts:[{}],pendingDeletes:new Set,selectedCell:null,history:[],currentTransaction:null,sortState:{col:l||a[0].name,asc:!0},pagination:{limit:50,offset:0,isLoading:!1,hasMore:!0},selection:{isDragging:!1,isDraggingRow:!1,startRow:-1,startCol:-1,endRow:-1,endCol:-1}}),window.TableStates&&window.TableStates[e]&&(window.TableStates[e].dataGrid=window.DataGrid);let u=await o(e,{where:n,limit:window.DataGrid.pagination.limit,offset:window.DataGrid.pagination.offset,orderCol:window.DataGrid.sortState.col,orderAsc:window.DataGrid.sortState.asc});if(u.success&&u.data){let n=u.data.rows,i=u.data.columns;window.DataGrid.pagination.hasMore=n.length===window.DataGrid.pagination.limit;let s=i.map(e=>`<option value="${e}">${e}</option>`).join(``);r||(c.innerHTML=`
147
- <div class="toolbar">
148
- <div class="filter-group">
149
- <div class="filter-icon-container">
150
- <span class="material-symbols-outlined" id="filter-icon">filter_list</span>
151
- <span>Filter</span>
152
- </div>
153
- <select id="filter-col-${e}" class="filter-select">${s}</select>
154
- <select id="filter-op-${e}" class="filter-select">
155
- <option value="=">=</option>
156
- <option value=">">></option>
157
- <option value="<"><</option>
158
- <option value=">=">>=</option>
159
- <option value="<="><=</option>
160
- <option value="LIKE">LIKE</option>
161
- <option value="!=">!=</option>
162
- </select>
163
- <input type="text" id="filter-val-${e}" class="filter-input" placeholder="Enter value..." />
164
- </div>
165
- <div class="flex-1"></div>
166
- <button id="btn-refresh-data-${e}" class="refresh-btn" title="Refresh Data (F5)"><span class="material-symbols-outlined">refresh</span></button>
167
- </div>
168
- <div class="table-container" id="data-grid-container-${e}"></div>
169
- `);let d=`<table class="data-table" id="data-grid-table-${e}"><thead><tr>`;d+=`<th class="row-header">#</th>`,i.forEach(e=>{let t=a.find(t=>t.name===e),n=``,r=``;t&&(t.isPk&&(n=` <span class="opacity-50 text-10">(PK)</span>`),t.name.toLowerCase().includes(`id`)&&!t.isPk&&(n=` <span class="opacity-50 text-10">(FK)</span>`),r=`<br><span class="font-normal opacity-70 text-10 font-mono">${t.type}</span>`);let i=``;window.DataGrid.sortState.col===e&&(i=window.DataGrid.sortState.asc?`▲`:`▼`),d+=`<th class="sortable" data-col="${e}" class="cursor-pointer select-none">
170
- <div class="flex justify-between items-center" style="min-width: 128px;">
171
- <div>${e}${n}${r}</div>
172
- <div class="sort-arrow" class="opacity-80 ml-2 text-right" style="font-size: 8px; margin-left: 32px;">${i}</div>
173
- </div>
174
- </th>`}),d+=`</tr></thead><tbody>`,n&&n.length>0&&n.forEach((e,t)=>{d+=`<tr>${x(e,t,l,i)}</tr>`}),d+=`<tr class="ghost-row-tr">`;let m=n?n.length:0;d+=`<td class="row-header" data-row-idx="${m}">*</td>`,i.forEach((e,t)=>{d+=`<td class="data-cell ghost-row" data-row-idx="${m}" data-col-idx="${t}" data-insert-index="0" data-col="${e}">+ New</td>`}),d+=`</tr></tbody></table>`;let h=document.getElementById(`data-grid-container-${e}`);if(!h)return;if(h.innerHTML=d,document.querySelectorAll(`th.sortable`).forEach(n=>{n.onclick=r=>{if(window.DataGrid&&window.DataGrid.isResizing)return;if(Object.keys(window.DataGrid.pendingEdits).length>0||window.DataGrid.pendingInserts.length>1||window.DataGrid.pendingDeletes.size>0){alert(`You have unsaved changes. Please save changes before sorting.`);return}let i=n.dataset.col;window.DataGrid.sortState.col===i?window.DataGrid.sortState.asc=!window.DataGrid.sortState.asc:(window.DataGrid.sortState.col=i,window.DataGrid.sortState.asc=!0),window.DataGrid.pagination.offset=0,S(e,t,b(),!0)},p(n,window.DataGrid)}),f(h,`data-grid-table-${e}`,window.DataGrid,i.length),y(h,a,i),!r){let n=document.getElementById(`filter-val-${e}`),r=(n=!0)=>{n&&window.DataGrid&&(window.DataGrid.pagination.offset=0),S(e,t,b(),!0)},a;n&&n.addEventListener(`input`,()=>{clearTimeout(a),a=setTimeout(()=>r(!0),400)});let s=document.getElementById(`filter-col-${e}`),c=document.getElementById(`filter-op-${e}`);s&&s.addEventListener(`change`,()=>r(!0)),c&&c.addEventListener(`change`,()=>r(!0));let u=()=>{(Object.keys(window.DataGrid.pendingEdits).length>0||window.DataGrid.pendingInserts.length>1||window.DataGrid.pendingDeletes.size>0)&&!confirm(`You have unsaved changes. Are you sure you want to refresh and discard them?`)||(window.DataGrid.pendingEdits={},window.DataGrid.pendingInserts=[{}],window.DataGrid.pendingDeletes=new Set,window.DataGrid.history=[],window.DataGrid.currentTransaction=null,window.updateSidebarDirtyState?.(),r(!1))},d=document.getElementById(`btn-refresh-data-${e}`);d&&(d.onclick=u),window.DataGrid.refreshData=u;let f=async()=>{if(window.DataGrid.pagination.isLoading||!window.DataGrid.pagination.hasMore)return;window.DataGrid.pagination.isLoading=!0,window.DataGrid.pagination.offset+=window.DataGrid.pagination.limit;let t={where:b(),limit:window.DataGrid.pagination.limit,offset:window.DataGrid.pagination.offset,orderCol:window.DataGrid.sortState.col,orderAsc:window.DataGrid.sortState.asc};try{let n=await o(e,t);if(window.DataGrid.pagination.isLoading=!1,n.success&&n.data){let t=n.data.rows;window.DataGrid.pagination.hasMore=t.length===window.DataGrid.pagination.limit;let r=document.querySelector(`#data-grid-table-${e} tbody`);if(!r)return;let a=r.querySelector(`td[data-insert-index]`)?.closest(`tr`),o=window.DataGrid.pagination.offset;t.forEach((e,t)=>{let n=document.createElement(`tr`);n.innerHTML=x(e,o+t,l,i),a?r.insertBefore(n,a):r.appendChild(n)});let s=o+t.length,c=r.querySelectorAll(`td[data-insert-index]`),u=new Set;c.forEach(e=>{let t=e.closest(`tr`);if(u.has(t))return;u.add(t);let n=t.querySelector(`.row-header`);n&&(n.dataset.rowIdx=s),t.querySelectorAll(`td.data-cell`).forEach(e=>e.dataset.rowIdx=s),s++})}}catch{window.DataGrid.pagination.isLoading=!1}};setTimeout(()=>{let t=document.getElementById(`data-grid-container-${e}`);t&&t.addEventListener(`scroll`,e=>{let{scrollTop:t,scrollHeight:n,clientHeight:r}=e.target;t+r>=n-50&&f()})},50)}}else c.innerHTML=`<div class="p-6 text-error">Error: ${u.error}</div>`}catch(e){c.innerHTML=`<div class="p-6 text-error">Failed to load data: ${e.message}</div>`}}async function ee(){if(!window.SchemaGrid)return;let{pendingEdits:e,pendingInserts:t,pendingDeletes:n}=window.SchemaGrid,r=window.AppState.currentTable;if(!r)return;let i=[];if(n)for(let e of n)i.push(`ALTER TABLE "${r}" DROP COLUMN "${e}";`);for(let[t,n]of Object.entries(e)){let e=t;if(n.name&&n.name!==t&&(i.push(`ALTER TABLE "${r}" RENAME COLUMN "${t}" TO "${n.name}";`),e=n.name),Object.keys(n).filter(e=>e!==`name`).length>0){let a=window.SchemaGrid.schema?.find(e=>e.name===t)||{},o=n.type===void 0?a.type:n.type,s=[],c=n.isPk===void 0?a.isPk:n.isPk,l=String(c).toUpperCase();if((l===`1`||l===`TRUE`||l===`YES`||l.includes(`PK`)||l===`KEY`)&&s.push(`PRIMARY KEY`),l.includes(`FK:`)){let e=l.match(/FK:\s*([^\s,]+)/i);if(e&&e[1]){let t=e[1].split(`.`);t.length===2&&s.push(`REFERENCES "${t[0]}"("${t[1]}")`)}}let u=n.nullable===void 0?a.nullable:n.nullable;(u===`0`||u===`No`||u===!1)&&s.push(`NOT NULL`);let d=n.defaultValue===void 0?a.defaultValue:n.defaultValue;if(d&&s.push(`DEFAULT '${String(d).replace(/'/g,`''`)}'`),window.AppState.dbType===`sqlite`){alert(`SQLite does not support altering column types directly. Please recreate the table or use Raw SQL.`);return}else window.AppState.dbType===`postgres`?(i.push(`ALTER TABLE "${r}" ALTER COLUMN "${e}" TYPE ${o};`),s.includes(`NOT NULL`)&&i.push(`ALTER TABLE "${r}" ALTER COLUMN "${e}" SET NOT NULL;`),d&&i.push(`ALTER TABLE "${r}" ALTER COLUMN "${e}" SET DEFAULT '${String(d).replace(/'/g,`''`)}';`)):i.push(`ALTER TABLE "${r}" MODIFY COLUMN "${e}" ${o} ${s.join(` `)};`)}}for(let e=0;e<t.length;e++){let n=t[e];if(Object.keys(n).length===0||!n.name||n.name.trim()===``)continue;let a=n.name.trim(),o=n.type||`TEXT`,s=[],c=String(n.isPk||``).toUpperCase();if((c===`1`||c===`TRUE`||c===`YES`||c.includes(`PK`)||c===`KEY`)&&s.push(`PRIMARY KEY`),c.includes(`FK:`)){let e=c.match(/FK:\s*([^\s,]+)/i);if(e&&e[1]){let t=e[1].split(`.`);t.length===2&&s.push(`REFERENCES "${t[0]}"("${t[1]}")`)}}(n.nullable===`0`||n.nullable===`false`||n.nullable===`No`)&&s.push(`NOT NULL`),n.defaultValue&&s.push(`DEFAULT '${n.defaultValue.replace(/'/g,`''`)}'`),i.push(`ALTER TABLE "${r}" ADD COLUMN "${a}" ${o} ${s.join(` `)};`)}if(window.SchemaGrid.pendingIndexEdits){for(let e of window.SchemaGrid.pendingIndexEdits.dropped)e&&e.trim()!==``&&i.push(`DROP INDEX "${e}";`);for(let e of window.SchemaGrid.pendingIndexEdits.added){let t=``;t=e.name&&e.name.trim()!==``?`"${e.name}"`:`"idx_${r}_${e.columns.join(`_`)}_${Date.now()}"`;let n=e.isUnique?`UNIQUE`:``,a=e.columns.map(e=>`"${e}"`).join(`, `);i.push(`CREATE ${n} INDEX IF NOT EXISTS ${t} ON "${r}" (${a});`)}}if(i.length===0)return;let a=!0,o=``;for(let e of i)try{let t=await l(e);if(!t.success){a=!1,o=t.error;break}}catch(e){a=!1,o=e.message;break}if(a){window.SchemaGrid&&(window.SchemaGrid.pendingEdits={},window.SchemaGrid.pendingInserts=[{}],window.SchemaGrid.pendingDeletes=new Set,window.SchemaGrid.pendingIndexEdits={added:[],dropped:[]},window.SchemaGrid.history=[],window.SchemaGrid.currentTransaction=null);let e=document.getElementById(`btn-refresh-schema-${r}`);e?e.click():window.renderCurrentView(),window.showToast&&window.showToast(`Schema saved successfully!`)}else o.includes(`near "MODIFY": syntax error`)?o=`SQLite: Currently does not support modifying existing column types or constraints directly. You can only Rename columns or Add new columns.`:o.includes(`syntax error`)&&(o=`SQLite: `+o),window.showToast?window.showToast(`Save failed: `+o,`error`):alert(`Save failed:
175
- `+o),document.querySelectorAll(`.cell-edited`).forEach(e=>{e.classList.remove(`cell-edited`),e.classList.add(`cell-error`)});window.updateSidebarDirtyState?.()}function C(e,t,n,r=!0){if(r&&window.SchemaGrid.currentTransaction){let n=e.textContent;(n===`null`||e.classList.contains(`ghost-row`))&&(n=``),n!==t&&window.SchemaGrid.currentTransaction.push({td:e,oldVal:n,newVal:t})}let i=e.dataset.colKey;if(e.innerHTML=t||(e.dataset.insertIndex===void 0?`<span class="text-soft">-</span>`:`+ New`),e.dataset.insertIndex!==void 0){let r=parseInt(e.dataset.insertIndex);if(window.SchemaGrid.pendingInserts[r]||(window.SchemaGrid.pendingInserts[r]={}),t){if(window.SchemaGrid.pendingInserts[r][i]=t,e.classList.add(`cell-edited`),e.classList.remove(`ghost-row`),r===window.SchemaGrid.pendingInserts.length-1){e.closest(`tr`).classList.remove(`ghost-row-tr`),window.SchemaGrid.pendingInserts.push({});let t=document.querySelector(`#schema-grid-table-${window.AppState.currentTable} tbody`),i=document.createElement(`tr`);i.className=`ghost-row-tr`;let a=parseInt(e.dataset.rowIdx)+1;i.innerHTML+=`<td class="row-header" data-row-idx="${a}">*</td>`,n.forEach((e,t)=>{i.innerHTML+=`<td class="data-cell ghost-row" data-row-idx="${a}" data-col-idx="${t}" data-insert-index="${r+1}" data-col-key="${e}">+ New</td>`}),t.appendChild(i)}}else window.SchemaGrid.pendingInserts[r]&&delete window.SchemaGrid.pendingInserts[r][i],e.classList.remove(`cell-edited`),e.classList.add(`ghost-row`)}else{let n=e.dataset.pk,r=e.dataset.original;r===`-`&&(r=``),t===r?(e.classList.remove(`cell-edited`),e.classList.remove(`cell-error`),window.SchemaGrid.pendingEdits[n]&&(delete window.SchemaGrid.pendingEdits[n][i],Object.keys(window.SchemaGrid.pendingEdits[n]).length===0&&delete window.SchemaGrid.pendingEdits[n])):(window.SchemaGrid.pendingEdits[n]||(window.SchemaGrid.pendingEdits[n]={}),window.SchemaGrid.pendingEdits[n][i]=t,e.classList.add(`cell-edited`),e.classList.remove(`cell-error`))}window.updateSidebarDirtyState?.()}function w(e,t=!0){let n=document.querySelector(`#schema-grid-table-${window.AppState.currentTable} td.data-cell[data-row-idx="${e}"]`)?.closest(`tr`);if(!n||n.classList.contains(`ghost-row-tr`)||n.classList.contains(`row-deleted`))return;let r=n.querySelector(`td.data-cell`)?.dataset.pk;r!==void 0&&(t&&window.SchemaGrid.currentTransaction&&window.SchemaGrid.currentTransaction.push({type:`delete`,rowIdx:e,pk:r}),window.SchemaGrid.pendingDeletes.add(r),n.classList.add(`row-deleted`)),window.updateSidebarDirtyState?.()}function te(e,t){let n=document.querySelector(`#schema-grid-table-${window.AppState.currentTable} td.data-cell[data-row-idx="${e}"]`)?.closest(`tr`);n&&n.classList.remove(`row-deleted`),window.SchemaGrid.pendingDeletes.delete(t),window.updateSidebarDirtyState?.()}function ne(e,t){e.forEach(e=>{let n=window.AppState.currentTable,r=document.querySelector(`#schema-grid-table-${n} td.data-cell[data-row-idx="${e}"]`)?.closest(`tr`);if(!r||r.classList.contains(`ghost-row-tr`))return;let i=document.querySelector(`#schema-grid-table-${n} .ghost-row-tr`);i&&t.forEach((e,n)=>{let a=r.querySelector(`td.data-cell[data-col-idx="${n}"]`),o=i.querySelector(`td.data-cell[data-col-idx="${n}"]`);if(a&&o){let n=a.dataset.insertIndex===void 0?a.classList.contains(`cell-edited`)?window.SchemaGrid.pendingEdits[a.dataset.pk]?.[e]:a.dataset.original:window.SchemaGrid.pendingInserts[a.dataset.insertIndex][e];n!=null&&n!==`null`&&(e===`name`&&(n+=`_copy`),C(o,n,t,!0))}})})}function re(){let e=window.SchemaGrid;if(!e)return;let t=document.getElementById(`index-modal`);t&&t.remove();let n=[...e.indexes],r=[...e.pendingIndexEdits.added],i=new Set(e.pendingIndexEdits.dropped),a=n.filter(e=>!i.has(e.name)).concat(r),o=e.schema.map(e=>e.name);e.pendingInserts.forEach(e=>{e.name&&e.name.trim()!==``&&o.push(e.name.trim())});let s=o.map(e=>`<option value="${e}">${e}</option>`).join(``);t=document.createElement(`div`),t.id=`index-modal`,t.style.cssText=`
176
- position: fixed; top:0; left:0; width:100vw; height:100vh; background:rgba(0,0,0,0.5);
177
- display:flex; justify-content:center; align-items:center; z-index:9999;
178
- `,t.innerHTML=`
179
- <div class="modal-container" class="w-500">
180
- <div class="modal-header">
181
- <h3 class="m-0">Manage Indexes</h3>
182
- <button id="close-idx-modal" class="modal-close-btn"><span class="material-symbols-outlined">close</span></button>
183
- </div>
184
- <div class="modal-body-scroll" id="idx-list-container">
185
- </div>
186
- <div class="modal-section-bg">
187
- <div class="font-semibold mb-2">Add New Index</div>
188
- <div class="flex-col gap-2">
189
- <input type="text" id="new-idx-name" placeholder="Index Name (Optional)" class="modal-input" />
190
- <select id="new-idx-cols" multiple class="modal-input" class="h-80">
191
- ${s}
192
- </select>
193
- <div class="text-12 text-soft">Hold Ctrl/Cmd to select multiple columns</div>
194
- <label class="items-center gap-6px cursor-pointer">
195
- <input type="checkbox" id="new-idx-unique" /> Unique Index
196
- </label>
197
- <button id="add-idx-btn" class="primary" class="btn-primary">Add</button>
198
- </div>
199
- </div>
200
- <div class="modal-footer">
201
- <button id="cancel-idx-btn" class="secondary" class="btn-secondary">Cancel</button>
202
- <button id="save-idx-btn" class="primary" class="btn-primary">Save Changes</button>
203
- </div>
204
- </div>
205
- `,document.body.appendChild(t);let c=()=>t.remove();document.getElementById(`close-idx-modal`).onclick=c,document.getElementById(`cancel-idx-btn`).onclick=c;let l=()=>{let e=a.map((e,t)=>`
206
- <div class="index-row" class="index-row-container">
207
- <div class="flex-1"><strong>${e.name||`-`}</strong></div>
208
- <div class="flex-2 text-12 text-secondary">${e.columns.join(`, `)}</div>
209
- <div class="w-60 text-12 text-center">${e.isUnique?`UNIQUE`:``}</div>
210
- <button class="icon-btn delete-idx-btn" data-idx="${t}" class="text-error btn-icon"><span class="material-symbols-outlined" class="icon-18">delete</span></button>
211
- </div>
212
- `).join(``);a.length===0&&(e=`<div class="p-4 text-center text-secondary">No indexes yet.</div>`),document.getElementById(`idx-list-container`).innerHTML=e,document.querySelectorAll(`.delete-idx-btn`).forEach(e=>{e.onclick=e=>{let t=parseInt(e.currentTarget.dataset.idx,10);a.splice(t,1),l()}})};l(),document.getElementById(`add-idx-btn`).onclick=()=>{let e=document.getElementById(`new-idx-name`).value.trim(),t=document.getElementById(`new-idx-cols`),n=Array.from(t.selectedOptions).map(e=>e.value),r=document.getElementById(`new-idx-unique`).checked;if(n.length===0){alert(`Please select at least one column for the index.`);return}a.push({name:e,columns:n,isUnique:r}),document.getElementById(`new-idx-name`).value=``,document.getElementById(`new-idx-unique`).checked=!1,t.selectedIndex=-1,l()},document.getElementById(`save-idx-btn`).onclick=()=>{let t=[],r=new Set;n.forEach(e=>{a.find(t=>t.name===e.name&&JSON.stringify(t.columns)===JSON.stringify(e.columns))||r.add(e.name)}),a.forEach(e=>{n.find(t=>t.name===e.name&&JSON.stringify(t.columns)===JSON.stringify(e.columns))||t.push(e)}),e.pendingIndexEdits.added=t,e.pendingIndexEdits.dropped=Array.from(r),window.updateSidebarDirtyState?.(),window.renderSchemaGrid(),c()}}async function ie(e,t){if(!window.SchemaGrid)return;let n=document.getElementById(`pkfk-modal`);n&&n.remove();let r=e.dataset.insertIndex!==void 0,i=t.includes(`PK`),a=t.includes(`FK`),o=``,s=``;if(a){let e=t.match(/FK \((.*?)\)/);if(e&&e[1]){let t=e[1].split(`.`);t.length===2&&(o=t[0],s=t[1])}else{let e=t.match(/FK:\s*([^\s,]+)/i);if(e&&e[1]){let t=e[1].split(`.`);t.length===2&&(o=t[0],s=t[1])}}}n=document.createElement(`div`),n.id=`pkfk-modal`,n.style.cssText=`
213
- position: fixed; top:0; left:0; width:100vw; height:100vh; background:rgba(0,0,0,0.5);
214
- display:flex; justify-content:center; align-items:center; z-index:9999;
215
- `,n.innerHTML=`
216
- <div class="modal-container" class="w-400">
217
- <div class="modal-header">
218
- <h3 class="m-0">Manage Keys</h3>
219
- <button id="close-pkfk-modal" class="modal-close-btn"><span class="material-symbols-outlined">close</span></button>
220
- </div>
221
- <div class="modal-body">
222
- <label class="items-center gap-2 cursor-pointer">
223
- <input type="checkbox" id="modal-is-pk" ${i?`checked`:``} />
224
- <strong>Primary Key (PK)</strong>
225
- </label>
226
-
227
- <div class="divider-y"></div>
228
-
229
- <label class="flex items-center gap-2 ${r?`cursor-pointer opacity-100`:`cursor-not-allowed opacity-60`}">
230
- <input type="checkbox" id="modal-is-fk" ${a?`checked`:``} ${r?``:`disabled`} />
231
- <strong>Foreign Key (FK)</strong>
232
- </label>
233
-
234
- ${r?``:`<div class="text-11 text-soft mt-n12 ml-24">Note: FKs can only be added when creating new columns.</div>`}
235
-
236
- <div id="fk-settings-container" class="flex-col gap-2 pl-6 ${a?`flex`:`hidden`}">
237
- <div>
238
- <div class="text-12 text-secondary mb-1">Target Table</div>
239
- <select id="modal-fk-table" class="modal-input w-full">
240
- <option value="">Loading tables...</option>
241
- </select>
242
- </div>
243
- <div>
244
- <div class="text-12 text-secondary mb-1">Target Column</div>
245
- <select id="modal-fk-col" class="modal-input w-full" ${o?``:`disabled`}>
246
- <option value="">Select a table first</option>
247
- </select>
248
- </div>
249
- </div>
250
- </div>
251
- <div class="modal-footer">
252
- <button id="cancel-pkfk-btn" class="secondary" class="btn-secondary">Cancel</button>
253
- <button id="save-pkfk-btn" class="primary" class="btn-primary">Save</button>
254
- </div>
255
- </div>
256
- `,document.body.appendChild(n);let c=()=>n.remove();document.getElementById(`close-pkfk-modal`).onclick=c,document.getElementById(`cancel-pkfk-btn`).onclick=c;let l=document.getElementById(`modal-is-fk`),u=document.getElementById(`fk-settings-container`),d=document.getElementById(`modal-fk-table`),f=document.getElementById(`modal-fk-col`);l.addEventListener(`change`,e=>{u.style.display=e.target.checked?`flex`:`none`});try{let e=await(await fetch(`/api/tables`)).json();e.success&&e.data&&(d.innerHTML=`<option value="">-- Select Table --</option>`+e.data.map(e=>`<option value="${e}" ${e===o?`selected`:``}>${e}</option>`).join(``),o&&p(o,s))}catch{d.innerHTML=`<option value="">Error loading tables</option>`}async function p(e,t=``){f.disabled=!0,f.innerHTML=`<option value="">Loading columns...</option>`;try{let n=await(await fetch(`/api/tables/${e}/schema`)).json();n.success&&n.data&&(f.innerHTML=`<option value="">-- Select Column --</option>`+n.data.map(e=>`<option value="${e.name}" ${e.name===t?`selected`:``}>${e.name}</option>`).join(``),f.disabled=!1)}catch{f.innerHTML=`<option value="">Error loading columns</option>`}}d.addEventListener(`change`,e=>{let t=e.target.value;t?p(t):(f.innerHTML=`<option value="">Select a table first</option>`,f.disabled=!0)}),document.getElementById(`save-pkfk-btn`).onclick=()=>{let t=document.getElementById(`modal-is-pk`).checked,n=document.getElementById(`modal-is-fk`).checked,r=d.value,l=f.value;if(t===i&&n===a&&r===o&&l===s){c();return}let u=``;if(t&&n){if(!r||!l){alert(`Please select both Target Table and Target Column for the Foreign Key.`);return}u=`PK, FK: ${r}.${l}`}else if(t)u=`PK`;else if(n){if(!r||!l){alert(`Please select both Target Table and Target Column for the Foreign Key.`);return}u=`FK: ${r}.${l}`}window.SchemaGrid.currentTransaction=[],C(e,u,[`name`,`type`,`isPk`,`nullable`,`defaultValue`,`indexing`]),window.SchemaGrid.currentTransaction.length>0&&window.SchemaGrid.history.push(window.SchemaGrid.currentTransaction),window.SchemaGrid.currentTransaction=null,c()}}function ae(e,t){e.addEventListener(`click`,e=>{e.target.closest(`.manage-indexes-cell`)&&re()}),e.addEventListener(`dblclick`,e=>{let n=e.target.closest(`td.data-cell`);if(!n||n.querySelector(`input, select`))return;let r=n.dataset.colKey;n.dataset.insertIndex;let i=n.textContent===`-`||n.textContent===`+ New`||n.textContent===`No`||n.textContent===`null`?``:n.textContent===`Yes`?`1`:n.textContent,a;if(r===`isPk`){ie(n,n.textContent);return}else if(r===`nullable`)a=document.createElement(`select`),[`No`,`Yes`].forEach(e=>{let t=document.createElement(`option`);t.value=e,t.textContent=e,(e===`Yes`&&i===`1`||e===`No`&&i===``)&&(t.selected=!0),a.appendChild(t)});else if(r===`type`){a=document.createElement(`select`);let e=[`INTEGER`,`TEXT`,`REAL`,`BLOB`,`NUMERIC`,`BOOLEAN`,`DATE`,`DATETIME`,`JSON`,`VARCHAR(255)`,`DECIMAL(10,2)`,`UUID`];i&&!e.some(e=>e.toUpperCase()===i.toUpperCase())&&e.unshift(i),e.forEach(e=>{let t=document.createElement(`option`);t.value=e,t.textContent=e,e.toUpperCase()===i.toUpperCase()&&(t.selected=!0),a.appendChild(t)})}else a=document.createElement(`input`),a.type=`text`,a.value=i;n.innerHTML=``,n.appendChild(a),a.style.width=`100%`,a.addEventListener(`keydown`,e=>{e.key===`Enter`&&a.blur(),e.key===`Tab`&&(e.preventDefault(),a.blur(),document.body.dispatchEvent(new KeyboardEvent(`keydown`,{key:`Tab`,shiftKey:e.shiftKey,bubbles:!0})))}),a.focus();let o=()=>{let e=a.value;window.SchemaGrid.currentTransaction=[],C(n,e,t),window.SchemaGrid.currentTransaction.length>0&&window.SchemaGrid.history.push(window.SchemaGrid.currentTransaction),window.SchemaGrid.currentTransaction=null};a.addEventListener(`blur`,()=>{o()})})}async function T(e,t,n=null){document.querySelectorAll(`.table-btn`).forEach(e=>e.classList.remove(`active`)),t&&t.classList.add(`active`);let r=document.getElementById(`table-name`);r&&(r.textContent=e+` (Schema)`);let i=n||document.getElementById(`main-content`);i.innerHTML=`<div class='p-6'>Loading Schema...</div>`;try{let[n,r]=await Promise.all([s(e),c(e)]);if(n.success&&n.data){let a=n.data,o=r.success&&r.data?r.data:[];window.SchemaGrid={schema:a,indexes:o,pendingEdits:{},pendingIndexEdits:{added:[],dropped:[]},pendingInserts:[{}],pendingDeletes:new Set,selectedCell:null,history:[],currentTransaction:null,sortState:{colKey:null,asc:!0},filterText:``,isResizing:!1,selection:{startRow:-1,startCol:-1,endRow:-1,endCol:-1,isDragging:!1}},window.TableStates&&window.TableStates[e]&&(window.TableStates[e].schemaGrid=window.SchemaGrid),i.innerHTML=`
257
- <div class="toolbar">
258
- <div class="filter-group">
259
- <div class="filter-icon-container">
260
- <span class="material-symbols-outlined">search</span>
261
- <span>Search</span>
262
- </div>
263
- <input type="text" id="schema-search-val-${e}" class="filter-input" placeholder="Search name or type..." class="w-250" value="${window.SchemaGrid.filterText}" />
264
- </div>
265
- <div class="flex-1"></div>
266
- <button id="btn-refresh-schema-${e}" class="refresh-btn" title="Refresh Schema (F5)"><span class="material-symbols-outlined">refresh</span></button>
267
- </div>
268
- <div id="schema-grid-container-${e}" class="table-container"></div>
269
- `,window.renderSchemaGrid=()=>{let t=document.getElementById(`schema-grid-container-${e}`);if(!t)return;let n=[...window.SchemaGrid.schema];if(window.SchemaGrid.filterText){let e=window.SchemaGrid.filterText.toLowerCase();n=n.filter(t=>t.name&&t.name.toLowerCase().includes(e)||t.type&&t.type.toLowerCase().includes(e))}window.SchemaGrid.sortState.colKey&&n.sort((e,t)=>{let n=window.SchemaGrid.sortState.colKey,r=e[n],i=t[n];return r??=``,i??=``,r<i?window.SchemaGrid.sortState.asc?-1:1:r>i?window.SchemaGrid.sortState.asc?1:-1:0});let r=[`name`,`type`,`isPk`,`nullable`,`defaultValue`,`indexing`],i=[`Name`,`Type`,`PK/FK`,`Nullable`,`Default Value`,`Indexing`],a=`<table class="data-table" id="schema-grid-table-${e}"><thead><tr><th class="row-header">#</th>`;r.forEach((e,t)=>{let n=``;window.SchemaGrid.sortState.colKey===e&&(n=window.SchemaGrid.sortState.asc?`▲`:`▼`),a+=`<th class="sortable" data-col-key="${e}">
270
- <div class="flex justify-between items-center">
271
- <div>${i[t]}</div>
272
- <div class="sort-arrow" class="text-10 opacity-80 ml-2 w-12 text-right">${n}</div>
273
- </div>
274
- </th>`}),a+=`</tr></thead><tbody>`,n&&n.length>0&&n.forEach((e,t)=>{a+=`<tr><td class="row-header" data-row-idx="${t}">${t+1}</td>`,r.forEach((r,i)=>{if(r===`indexing`){if(t===0){let e=(n?n.length:0)+1,t=window.SchemaGrid.indexes.length,r=window.SchemaGrid.pendingIndexEdits.added.length,i=window.SchemaGrid.pendingIndexEdits.dropped.length,o=t+r-i;a+=`<td class="data-cell manage-indexes-cell" rowspan="${e}" class="text-center align-middle cursor-pointer font-medium border-l text-brand">
275
- Manage Indexes (${o})
276
- </td>`}return}let o=e[r];if(r===`isPk`){let t=o,n=!!e.fkTarget;o=t&&n?`PK, FK (${e.fkTarget.table}.${e.fkTarget.column})`:t?`PK`:n?`FK (${e.fkTarget.table}.${e.fkTarget.column})`:`-`}else r===`nullable`?o=o?`Yes`:`No`:o??=``;let s=String(o).replace(/"/g,`&quot;`),c=o===``?`<span class="text-soft">-</span>`:String(o).replace(/</g,`&lt;`);a+=`<td class="data-cell" data-row-idx="${t}" data-col-idx="${i}" data-pk="${e.name}" data-col-key="${r}" data-original="${s}">${c}</td>`}),a+=`</tr>`}),a+=`<tr class="ghost-row-tr">`;let o=n?n.length:0;a+=`<td class="row-header" data-row-idx="${o}">*</td>`,r.forEach((e,t)=>{e!==`indexing`&&(a+=`<td class="data-cell ghost-row" data-row-idx="${o}" data-col-idx="${t}" data-insert-index="0" data-col-key="${e}">+ New</td>`)}),a+=`</tr></tbody></table>`,t.innerHTML=a,document.querySelectorAll(`#schema-grid-table-${e} th.sortable`).forEach(e=>{e.onclick=t=>{if(window.SchemaGrid.isResizing)return;if(Object.keys(window.SchemaGrid.pendingEdits).length>0||window.SchemaGrid.pendingInserts.length>1||window.SchemaGrid.pendingDeletes.size>0||window.SchemaGrid.pendingIndexEdits.added.length>0||window.SchemaGrid.pendingIndexEdits.dropped.length>0){alert(`You have unsaved changes! Please press Ctrl+S to save them before sorting.`);return}let n=e.dataset.colKey;window.SchemaGrid.sortState.colKey===n?window.SchemaGrid.sortState.asc=!window.SchemaGrid.sortState.asc:(window.SchemaGrid.sortState.colKey=n,window.SchemaGrid.sortState.asc=!0),window.SchemaGrid.selection={startRow:-1,startCol:-1,endRow:-1,endCol:-1,isDragging:!1},window.renderSchemaGrid()},p(e,window.SchemaGrid)}),f(t,`schema-grid-table-${e}`,window.SchemaGrid,r.length),ae(t,r)},window.renderSchemaGrid();let s=document.getElementById(`schema-search-val-${e}`);s&&s.addEventListener(`input`,e=>{window.SchemaGrid.filterText=e.target.value,window.SchemaGrid.selection={startRow:-1,startCol:-1,endRow:-1,endCol:-1,isDragging:!1},window.renderSchemaGrid()});let c=document.getElementById(`btn-refresh-schema-${e}`);c&&(c.onclick=()=>{(Object.keys(window.SchemaGrid.pendingEdits).length>0||window.SchemaGrid.pendingInserts.length>1||window.SchemaGrid.pendingDeletes.size>0||window.SchemaGrid.pendingIndexEdits.added.length>0||window.SchemaGrid.pendingIndexEdits.dropped.length>0)&&!confirm(`You have unsaved changes. Are you sure you want to refresh and discard them?`)||(window.SchemaGrid.pendingEdits={},window.SchemaGrid.pendingInserts=[{}],window.SchemaGrid.pendingDeletes.clear(),window.SchemaGrid.pendingIndexEdits={added:[],dropped:[]},window.SchemaGrid.history=[],window.SchemaGrid.currentTransaction=null,window.updateSidebarDirtyState?.(),T(e,t,document.getElementById(`view-schema-btn-${e}`)))})}else i.innerHTML=`<div class="p-6 text-error">Error: ${n.error}</div>`}catch(e){i.innerHTML=`<div class="p-6 text-error">Failed to load schema: ${e.message}</div>`}}var E=0,oe=(e,t,n)=>{let r=[e.map(e=>`"${String(e).replace(/"/g,`""`)}"`).join(`,`),...t.map(t=>e.map(e=>`"${(t[e]===null?``:String(t[e])).replace(/"/g,`""`)}"`).join(`,`))].join(`\\n`),i=new Blob([r],{type:`text/csv;charset=utf-8;`}),a=URL.createObjectURL(i),o=document.createElement(`a`);o.setAttribute(`href`,a),o.setAttribute(`download`,n),o.style.visibility=`hidden`,document.body.appendChild(o),o.click(),document.body.removeChild(o)},D=async(e,t,n)=>{let r=e||t.value.substring(t.selectionStart,t.selectionEnd).trim();if(r||=t.value.trim(),!r)return;if(r.toLowerCase()===`clear`||r.toLowerCase()===`clear;`){n.innerHTML=``,e||(t.selectionStart=t.selectionEnd,t.value=``);return}window.AppState.lastQuery=t.value,window.AppState.queryHistory||(window.AppState.queryHistory=[]);let i=window.AppState.queryHistory;i.includes(r)||(i.unshift(r),i.length>10&&i.pop(),window.dispatchEvent(new Event(`query-history-updated`))),E++;let a=`history-block-${E}`,o=document.getElementById(`console-welcome-msg`);o&&(o.style.display=`none`);let s=document.createElement(`div`);s.className=`console-history-block`,s.innerHTML=`
277
- <div class="console-history-header">
278
- <div class="console-history-sql">${r.replace(/</g,`&lt;`).replace(/>/g,`&gt;`)}</div>
279
- <div class="console-history-actions">
280
- <button class="icon-btn copy-btn" title="Copy SQL"><span class="material-symbols-outlined" class="icon-16">content_copy</span></button>
281
- <button class="icon-btn rerun-btn" title="Re-run"><span class="material-symbols-outlined" class="icon-16">refresh</span></button>
282
- </div>
283
- </div>
284
- <div id="${a}-results" class="console-history-results">
285
- <div class="console-msg-executing">
286
- <span class="material-symbols-outlined" class="animate-spin">sync</span> Executing...
287
- </div>
288
- </div>
289
- `,n.appendChild(s),s.querySelector(`.copy-btn`).onclick=()=>{navigator.clipboard.writeText(r),window.showToast?window.showToast(`SQL copied to clipboard`):alert(`Copied`)},s.querySelector(`.rerun-btn`).onclick=()=>D(r,t,n),n.scrollTop=n.scrollHeight,e||(t.selectionStart=t.selectionEnd,t.value=``);try{let e=performance.now(),t=await l(r),i=(performance.now()-e).toFixed(1),o=document.getElementById(`${a}-results`);if(!t.success){o.innerHTML=`<div class="console-msg-error"><span class="material-symbols-outlined" class="icon-16 mt-2px">error</span><span>Error: ${t.error}</span></div>`,n.scrollTop=n.scrollHeight;return}let s=t.data.rows||[],c=s.length;if(c===0){o.innerHTML=`<div class="console-msg-success"><span class="material-symbols-outlined" class="icon-16">check_circle</span> Query executed successfully in ${i}ms. 0 rows returned.</div>`,n.scrollTop=n.scrollHeight;return}let u=Object.keys(s[0]),d=document.createElement(`div`);d.className=`console-stats-header`;let f=s.slice(0,1e3);d.innerHTML=`
290
- <div class="console-stats-info">
291
- <span class="material-symbols-outlined" class="text-success icon-14">check_circle</span>
292
- <span>${c} rows${c>1e3?` (Showing first 1000)`:``} &middot; ${i}ms</span>
293
- </div>
294
- <button class="console-export-btn export-btn">
295
- <span class="material-symbols-outlined" class="icon-14">download</span> CSV
296
- </button>
297
- `,o.innerHTML=``,o.appendChild(d),d.querySelector(`.export-btn`).onclick=()=>{oe(u,s,`drixio_export_${new Date().getTime()}.csv`)};let p=document.createElement(`div`);p.className=`table-container`,p.style.border=`1px solid var(--color-border)`,p.style.borderRadius=`6px`,p.style.overflow=`auto`,p.style.maxHeight=`320px`;let m=document.createElement(`table`);m.className=`data-table`;let h=document.createElement(`thead`);h.style.position=`sticky`,h.style.top=`0`,h.style.zIndex=`10`;let g=document.createElement(`tr`),_=document.createElement(`th`);_.className=`row-header`,_.textContent=`#`,g.appendChild(_),u.forEach(e=>{let t=document.createElement(`th`);t.textContent=e,g.appendChild(t)}),h.appendChild(g),m.appendChild(h);let v=document.createElement(`tbody`);f.forEach((e,t)=>{let n=document.createElement(`tr`),r=document.createElement(`td`);r.className=`row-header`,r.textContent=t+1,n.appendChild(r),u.forEach(t=>{let r=document.createElement(`td`);r.className=`data-cell data-cell-truncate`;let i=e[t];if(i===null){let e=document.createElement(`span`);e.textContent=`NULL`,e.classList.add(`text-soft`,`italic`),r.appendChild(e)}else{let e=String(i);r.textContent=e,e.length>40&&(r.title=e)}n.appendChild(r)}),v.appendChild(n)}),m.appendChild(v),p.appendChild(m),o.appendChild(p),setTimeout(()=>n.scrollTop=n.scrollHeight,10)}catch(e){let t=document.getElementById(`${a}-results`);t&&(t.innerHTML=`<div class="console-msg-error"><span class="material-symbols-outlined" class="icon-16 mt-2px">error</span><span>Error: ${e.message}</span></div>`,n.scrollTop=n.scrollHeight)}},se=(e,t)=>{let n=-1,r=``,i=()=>{D(null,e,t),n=-1,r=``,s()},a=document.getElementById(`run-sql-btn`);a&&(a.onclick=()=>i());let o=document.getElementById(`sql-highlight-layer`),s=()=>{let t=e.value;if(t===``){o&&(o.innerHTML=`<span class="hl-placeholder">SELECT * FROM sqlite_master;</span>`);return}t=t.replace(/&/g,`&amp;`).replace(/</g,`&lt;`).replace(/>/g,`&gt;`);let n=RegExp(`('.*?'|".*?")|\\b(\\d+)\\b|\\b(${`SELECT.FROM.WHERE.AND.OR.IN.NOT.NULL.IS.ORDER.BY.GROUP.ASC.DESC.LIMIT.OFFSET.JOIN.INNER.LEFT.RIGHT.ON.AS.CREATE.TABLE.DROP.ALTER.INSERT.INTO.VALUES.UPDATE.SET.DELETE.PRAGMA.EXPLAIN.QUERY.PLAN.WITH.UNION.ALL.HAVING.LIKE.BETWEEN.EXISTS.CASE.WHEN.THEN.ELSE.END.CAST.DEFAULT.PRIMARY.KEY.FOREIGN.UNIQUE.CHECK.REFERENCES.AUTOINCREMENT.COUNT.SUM.AVG.MIN.MAX.COALESCE.BEGIN.COMMIT.ROLLBACK.INDEX.VIEW.TRIGGER.REPLACE.CROSS.FULL.OUTER`.split(`.`).join(`|`)})\\b`,`gi`);t=t.replace(n,(e,t,n,r)=>t?`<span class="hl-string">${t}</span>`:n?`<span class="hl-number">${n}</span>`:r?`<span class="hl-keyword">${r.toUpperCase()}</span>`:e),t.endsWith(`\\n`)&&(t+=` `),o&&(o.innerHTML=t)};e.addEventListener(`input`,s),e.addEventListener(`scroll`,()=>{o&&(o.scrollTop=e.scrollTop,o.scrollLeft=e.scrollLeft)}),s(),e.addEventListener(`keydown`,t=>{let a=window.AppState.queryHistory||[];t.key===`ArrowUp`?e.selectionStart===0&&e.selectionEnd===0&&n<a.length-1&&(t.preventDefault(),n===-1&&(r=e.value),n++,e.value=a[n],s(),setTimeout(()=>{e.selectionStart=e.value.length,e.selectionEnd=e.value.length},0)):t.key===`ArrowDown`?e.selectionStart===e.value.length&&e.selectionEnd===e.value.length&&n>-1&&(t.preventDefault(),n--,n===-1?e.value=r:e.value=a[n],s(),setTimeout(()=>{e.selectionStart=e.value.length,e.selectionEnd=e.value.length},0)):((t.ctrlKey||t.metaKey)&&t.key===`Enter`||t.key===`Enter`&&!t.shiftKey&&e.value.trim().endsWith(`;`))&&(t.preventDefault(),i())})};function ce(e,t,n){document.querySelectorAll(`.table-btn`).forEach(e=>e.classList.remove(`active`)),t&&t.classList.add(`active`);let r=document.getElementById(`table-name`);r&&(r.textContent=`SQL Console`),n.innerHTML=`
298
- <div class="sql-console-wrapper">
299
- <div id="console-history-pane">
300
- <div id="console-welcome-msg">
301
- <div id="console-welcome-title">
302
- <div id="icon-container">
303
- <span class="material-symbols-outlined" class="icon-36">database_search</span>
304
- </div>
305
- <span>Welcome to Drixio SQL Terminal.</span>
306
- </div>
307
- <span id="console-welcome-description">Type your query below and press <b>Ctrl+Enter</b> or end with <b>;</b> and press <b>Enter</b> to execute.</span>
308
- <span id="console-welcome-hint"><b>Hint:</b> Highlight specific lines to only run the selection.</span>
309
- </div>
310
- </div>
311
- <div id="console-input-pane">
312
- <div class="sql-editor-wrapper">
313
- <span class="sql-prompt">sql &gt;</span>
314
- <div class="sql-editor-layer-container">
315
- <!-- Syntax Highlight Layer (Background) -->
316
- <div id="sql-highlight-layer" class="sql-editor"></div>
317
- <!-- Real Textarea (Foreground) -->
318
- <textarea id="sql-editor" class="sql-editor"></textarea>
319
- </div>
320
- </div>
321
- <div class="hidden justify-end mt-2">
322
- <button id="run-sql-btn" class="primary" class="btn-primary flex items-center gap-6px text-13 transition-opacity">
323
- <span class="material-symbols-outlined" class="icon-16">play_arrow</span> Run (Ctrl+Enter)
324
- </button>
325
- </div>
326
- </div>
327
- </div>
328
- `;let i=document.getElementById(`sql-editor`),a=document.getElementById(`console-history-pane`);window.AppState.lastQuery&&(i.value=window.AppState.lastQuery),i.focus(),se(i,a)}var O={erdData:[],undoStack:[],selectedTables:new Set,clipboard:[],draggingNode:null,draggingColInfo:null,draggedNodesStart:[],dragStartMouse:{x:0,y:0},targetColForDelete:null,zoom:1,isPanning:!1,panStart:{x:0,y:0},scrollStart:{left:0,top:0},drawingFkStartCol:null,drawingFkStartCoords:null,contextMenuPos:{x:0,y:0},snapToGrid:!0,pushUndoState(){this.undoStack.push(JSON.parse(JSON.stringify(this.erdData))),this.undoStack.length>50&&this.undoStack.shift()},undo(){return this.undoStack.length>0?(this.erdData=this.undoStack.pop(),!0):!1},clearSelection(){this.selectedTables.clear()},toggleSelection(e){this.selectedTables.has(e)?this.selectedTables.delete(e):this.selectedTables.add(e)},setSelection(e){this.selectedTables.clear(),this.selectedTables.add(e)}};async function le(){let e=await r();if(!e||!e.success||!e.data)return[];let t=e.data,n=[],i=t.map(async e=>{let t=await s(e);t&&t.success&&n.push({table:e,columns:t.data})});return await Promise.all(i),n}function k(){try{let e=localStorage.getItem(`drixio-erd-positions`);return e?JSON.parse(e):{}}catch{return{}}}function A(e){localStorage.setItem(`drixio-erd-positions`,JSON.stringify(e))}async function ue(e){let t=[];if(e.forEach(e=>{if(e.isDraft){let n=e.columns.map(e=>{let t=`${e.name} ${e.type}`;return e.isPk&&(e.type.toUpperCase()===`INTEGER`?t+=` PRIMARY KEY AUTOINCREMENT`:t+=` PRIMARY KEY`),!e.nullable&&!e.isPk&&(t+=` NOT NULL DEFAULT ''`),e.fkTarget&&(t+=` REFERENCES ${e.fkTarget.table}(${e.fkTarget.column})`),t}).join(`, `);t.push(`CREATE TABLE ${e.table} (${n});`)}else e.columns.forEach(n=>{if(n.isDraft){let r=`ALTER TABLE ${e.table} ADD COLUMN ${n.name} ${n.type}`;n.fkTarget&&(r+=` REFERENCES ${n.fkTarget.table}(${n.fkTarget.column})`),t.push(r+`;`)}})}),t.length===0)return!0;try{for(let e of t){let t=await l(e);if(!t.success)throw Error(t.error||`Query failed`)}return!0}catch(e){return window.showToast(`Failed to save: `+e.message,`error`),!1}}function de(e){if(!e||e.length===0)return;let t={};e.forEach(e=>t[e.table]=new Set),e.forEach(e=>{e.columns.forEach(n=>{n.fkTarget&&n.fkTarget.table&&t[e.table]&&n.fkTarget.table!==e.table&&t[e.table].add(n.fkTarget.table)})});let n={};e.forEach(e=>n[e.table]=0);let r=!0,i=0;for(;r&&i<e.length+5;){r=!1,i++;for(let i of e){let e=n[i.table];for(let a of t[i.table])n[a]!==void 0&&n[a]>=e&&(n[i.table]=n[a]+1,r=!0)}}let a={};for(let t of e){let e=n[t.table]||0;a[e]||(a[e]=[]),a[e].push(t.table)}let o=k()||{};return Object.keys(a).forEach(e=>{let t=parseInt(e);a[e].forEach((e,n)=>{o[e]={x:50+t*350,y:50+n*250}})}),A(o),o}var j=null;function fe(){j||(j=document.createElement(`div`),j.className=`drixio-context-menu`,document.body.appendChild(j),document.addEventListener(`click`,e=>{j.classList.contains(`visible`)&&!j.contains(e.target)&&N()}),window.addEventListener(`scroll`,e=>{j.classList.contains(`visible`)&&(j.contains(e.target)||N())},!0))}function M(e,t){e.preventDefault&&e.preventDefault(),e.stopPropagation&&e.stopPropagation(),fe(),j.innerHTML=``,t.forEach(e=>{if(e.type===`divider`||e===`divider`){let e=document.createElement(`div`);e.className=`drixio-context-menu-divider`,j.appendChild(e);return}let t=document.createElement(`div`);t.className=`drixio-context-menu-item`,e.danger&&t.classList.add(`danger`),t.innerHTML=`
329
- ${e.icon?`<span class="material-symbols-outlined">${e.icon}</span>`:``}
330
- <span class="drixio-menu-label">${e.label}</span>
331
- ${e.shortcut?`<span class="drixio-menu-shortcut">${e.shortcut}</span>`:``}
332
- `,t.addEventListener(`click`,t=>{t.stopPropagation(),N(),e.action&&e.action()}),j.appendChild(t)}),j.style.visibility=`hidden`,j.classList.add(`visible`),requestAnimationFrame(()=>{let t=j.getBoundingClientRect(),n=e.clientX,r=e.clientY;n+t.width>window.innerWidth&&(n=window.innerWidth-t.width-8),r+t.height>window.innerHeight&&(r=window.innerHeight-t.height-8),j.style.left=`${n}px`,j.style.top=`${r}px`,j.style.visibility=`visible`})}function N(){j&&j.classList.remove(`visible`)}function P(){if(O.selectedTables.size===0)return;let e=[];O.selectedTables.forEach(t=>{let n=O.erdData.find(e=>e.table===t);if(n){let t=JSON.parse(JSON.stringify(n));t.columns.forEach(e=>{e.fkTarget&&delete e.fkTarget}),e.push(t)}}),O.clipboard=e,window.showToast(`Copied ${e.length} table(s)`,`success`)}function F(){O.selectedTables.size!==0&&(O.pushUndoState(),O.erdData.forEach(e=>{e.columns.forEach(e=>{e.fkTarget&&O.selectedTables.has(e.fkTarget.table)&&delete e.fkTarget})}),O.erdData=O.erdData.filter(e=>!O.selectedTables.has(e.table)),O.clearSelection(),H(),window.showToast(`Deleted selected table(s)`,`success`))}function I(){if(!O.clipboard||O.clipboard.length===0)return;O.pushUndoState(),O.clearSelection();let e=k();O.clipboard.forEach((t,n)=>{let r=JSON.parse(JSON.stringify(t)),i=`_copy`,a=r.table+i,o=1;for(;O.erdData.some(e=>e.table===a);)o++,a=r.table+i+o;r.table=a,r.isDraft=!0,r.columns.forEach(e=>e.isDraft=!0),e[t.table]?e[a]={x:e[t.table].x+40+n*20,y:e[t.table].y+40+n*20}:e[a]={x:100+n*20,y:100+n*20},O.erdData.push(r),O.selectedTables.add(a)}),A(e),H(),window.showToast(`Pasted ${O.clipboard.length} table(s)`,`success`)}function pe(){document.addEventListener(`keydown`,async e=>{window.AppState&&window.AppState.currentTab!==`erd-btn`||e.target.tagName===`INPUT`||e.target.tagName===`SELECT`||e.target.tagName===`TEXTAREA`||((e.ctrlKey||e.metaKey)&&e.key===`s`&&(e.preventDefault(),await ue(O.erdData)&&(window.showToast(`ERD Schema saved successfully!`,`success`),G(document.getElementById(`main-content`)))),(e.ctrlKey||e.metaKey)&&e.key===`z`&&(e.preventDefault(),O.undo()?(H(),window.showToast(`Undid last action`,`success`)):window.showToast(`Nothing to undo`,`info`)),e.ctrlKey&&e.key===`c`&&(e.preventDefault(),P()),e.ctrlKey&&e.key===`v`&&(e.preventDefault(),I()),e.key===`Delete`&&(e.preventDefault(),F()))})}function me(){let e=document.getElementById(`erd-workspace`);document.querySelectorAll(`.erd-node`).forEach(t=>{let n=O.erdData.find(e=>e.table===t.dataset.table);if(!n)return;let r=t.querySelector(`.erd-node-header`);if(r.addEventListener(`mousedown`,r=>{if(r.button===1||r.target.tagName===`INPUT`)return;if(!O.selectedTables.has(n.table))!r.ctrlKey&&!r.metaKey&&O.clearSelection(),O.selectedTables.add(n.table),document.querySelectorAll(`.erd-node`).forEach(e=>{O.selectedTables.has(e.dataset.table)?e.classList.add(`is-selected`):e.classList.remove(`is-selected`)});else if(r.ctrlKey||r.metaKey){O.selectedTables.delete(n.table),t.classList.remove(`is-selected`);return}O.draggingNode=t;let i=e.getBoundingClientRect();O.dragStartMouse={x:r.clientX,y:r.clientY},O.draggedNodesStart=[],O.selectedTables.forEach(e=>{let t=document.querySelector(`.erd-node[data-table="${e}"]`);if(t){let e=t.getBoundingClientRect();O.draggedNodesStart.push({node:t,startX:(e.left-i.left)/O.zoom,startY:(e.top-i.top)/O.zoom}),t.style.zIndex=`10`}}),document.body.style.cursor=`grabbing`}),t.addEventListener(`contextmenu`,e=>{e.preventDefault(),e.stopPropagation(),O.selectedTables.has(n.table)||(O.setSelection(n.table),document.querySelectorAll(`.erd-node`).forEach(e=>{O.selectedTables.has(e.dataset.table)?e.classList.add(`is-selected`):e.classList.remove(`is-selected`)})),M(e,[{label:`Copy`,icon:`content_copy`,action:P},{label:`Cut`,icon:`content_cut`,action:()=>{P(),F()}},`divider`,{label:`Delete`,icon:`delete`,danger:!0,action:F}])}),t.querySelector(`.erd-add-col-btn`).addEventListener(`click`,()=>{O.pushUndoState(),n.columns.push({name:`new_col_${n.columns.length}`,type:`TEXT`,isDraft:!0,nullable:!0}),H()}),n.isDraft){let e=r.querySelector(`.erd-node-name`);r.addEventListener(`dblclick`,t=>{if(t.target.tagName===`INPUT`)return;t.stopPropagation();let r=document.createElement(`input`);r.value=n.table,r.className=`erd-inline-input`,e.replaceWith(r),r.focus(),r.addEventListener(`blur`,()=>{let e=n.table,t=r.value.trim()||e;if(e!==t){O.pushUndoState(),n.table=t;let r=k();r[e]&&(r[t]=r[e],delete r[e],A(r)),O.erdData.forEach(n=>{n.columns.forEach(n=>{n.fkTarget&&n.fkTarget.table===e&&(n.fkTarget.table=t)})}),O.selectedTables.has(e)&&(O.selectedTables.delete(e),O.selectedTables.add(t))}H()}),r.addEventListener(`keydown`,e=>{e.key===`Enter`&&r.blur()})})}else r.addEventListener(`dblclick`,e=>{e.stopPropagation(),window.AppState.currentTable=t.dataset.table;let n=document.querySelector(`.table-btn[data-table="${t.dataset.table}"]`);n&&(window.AppState.currentTableBtnElement=n,document.querySelectorAll(`.table-btn`).forEach(e=>e.classList.remove(`active`)),n.classList.add(`active`)),window.handleSwitchTab?window.handleSwitchTab(`schema-btn`):window.renderCurrentView&&(window.AppState.currentTab=`schema-btn`,window.renderCurrentView())});let i=t.querySelectorAll(`.erd-column`);i.forEach(t=>{let r=parseInt(t.dataset.index),i=n.columns[r];if(t.addEventListener(`contextmenu`,e=>{i.isPk||!i.isDraft&&!n.isDraft||(e.preventDefault(),e.stopPropagation(),M(e,[{label:`Delete Column`,icon:`delete`,danger:!0,action:()=>{O.pushUndoState(),O.erdData.forEach(e=>{e.columns.forEach(e=>{e.fkTarget&&e.fkTarget.table===n.table&&e.fkTarget.column===i.name&&delete e.fkTarget})}),n.columns.splice(r,1),H()}}]))}),!i.isDraft&&!n.isDraft)return;t.querySelectorAll(`.editable-field`).forEach(e=>{e.addEventListener(`dblclick`,t=>{if(t.target.tagName===`INPUT`||t.target.tagName===`SELECT`)return;t.stopPropagation();let r=e.dataset.field,a;if(r===`type`){a=document.createElement(`select`),a.className=`erd-inline-input`;let e=[`INTEGER`,`TEXT`,`REAL`,`BLOB`,`BOOLEAN`,`DATE`,`DATETIME`];if(e.forEach(e=>{let t=document.createElement(`option`);t.value=e,t.textContent=e,i.type.toUpperCase()===e&&(t.selected=!0),a.appendChild(t)}),!e.includes(i.type.toUpperCase())){let e=document.createElement(`option`);e.value=i.type,e.textContent=i.type,e.selected=!0,a.appendChild(e)}a.addEventListener(`change`,()=>{a.blur()})}else a=document.createElement(`input`),a.value=r===`name`&&i.nullable?i.name+` ?`:i[r],a.className=`erd-inline-input`;e.replaceWith(a),a.focus(),a.addEventListener(`blur`,()=>{let e=i[r],t=r===`type`?a.value.toUpperCase():a.value;if(t=t.trim()||e,e===t&&!t.endsWith(`?`)&&!t.endsWith(`!`)){H();return}O.pushUndoState(),r===`name`&&(t.endsWith(`?`)?(i.nullable=!0,t=t.slice(0,-1).trim()):(i.nullable=!1,t.endsWith(`!`)&&(t=t.slice(0,-1).trim()))),r===`name`&&i.isPk&&e!==t&&O.erdData.forEach(r=>{r.columns.forEach(r=>{r.fkTarget&&r.fkTarget.table===n.table&&r.fkTarget.column===e&&(r.fkTarget.column=t)})}),i[r]=t,H()}),a.addEventListener(`keydown`,e=>{e.key===`Enter`&&a.blur()})})});let a=t.querySelector(`.erd-drag-handle`);a&&a.addEventListener(`mousedown`,t=>{t.stopPropagation(),O.drawingFkStartCol={table:n.table,col:i.name,colIndex:r};let o=a.getBoundingClientRect(),s=e.getBoundingClientRect();O.drawingFkStartCoords={x:(o.right-s.left)/O.zoom,y:(o.top+o.height/2-s.top)/O.zoom}})}),t.querySelectorAll(`.erd-reorder-handle`).forEach(e=>{e.addEventListener(`dragstart`,t=>{let r=e.closest(`.erd-column`);O.draggingColInfo={table:n.table,colIndex:parseInt(r.dataset.index)},t.dataTransfer.effectAllowed=`move`,t.dataTransfer.setData(`text/plain`,n.table)})}),i.forEach(e=>{e.addEventListener(`dragover`,e=>{!O.draggingColInfo||O.draggingColInfo.table!==n.table||(e.preventDefault(),e.dataTransfer.dropEffect=`move`)}),e.addEventListener(`drop`,t=>{if(t.preventDefault(),!O.draggingColInfo||O.draggingColInfo.table!==n.table)return;let r=O.draggingColInfo.colIndex,i=parseInt(e.dataset.index);if(r!==i){O.pushUndoState();let[e]=n.columns.splice(r,1);n.columns.splice(i,0,e),H()}O.draggingColInfo=null})})})}var L=!1;function he(){L||(L=!0,document.addEventListener(`mousemove`,e=>{if(O.drawingFkStartCol){let t=document.getElementById(`erd-workspace`);if(!t)return;let n=t.getBoundingClientRect(),r=(e.clientX-n.left)/O.zoom,i=(e.clientY-n.top)/O.zoom,a=document.getElementById(`erd-temp-path`),o=document.getElementById(`erd-svg-layer`);a||(a=document.createElementNS(`http://www.w3.org/2000/svg`,`path`),a.id=`erd-temp-path`,a.setAttribute(`fill`,`none`),a.setAttribute(`stroke`,`var(--color-primary)`),a.setAttribute(`stroke-width`,`2`),a.setAttribute(`stroke-dasharray`,`5,5`),o&&o.appendChild(a)),a&&a.setAttribute(`d`,`M ${O.drawingFkStartCoords.x} ${O.drawingFkStartCoords.y} L ${r} ${i}`);return}if(!O.draggingNode)return;let t=(e.clientX-O.dragStartMouse.x)/O.zoom,n=(e.clientY-O.dragStartMouse.y)/O.zoom;O.draggedNodesStart.forEach(e=>{let r=e.startX+t,i=e.startY+n;r<0&&(r=0),i<0&&(i=0),O.snapToGrid&&(r=Math.round(r/20)*20,i=Math.round(i/20)*20),e.node.style.left=`${r}px`,e.node.style.top=`${i}px`}),U()}),document.addEventListener(`mouseup`,e=>{if(O.drawingFkStartCol){let t=document.elementFromPoint(e.clientX,e.clientY),n=t?t.closest(`.erd-node`):null;if(n){let e=n.dataset.table;if(e!==O.drawingFkStartCol.table){let t=O.erdData.find(t=>t.table===e).columns.find(e=>e.isPk);if(t){let n=confirm(`Create Foreign Key to ${e}?\n\nClick OK for Nullable (0..N)\nClick Cancel for Not Nullable (1..N)`);O.pushUndoState();let r=O.erdData.find(e=>e.table===O.drawingFkStartCol.table),i=r.columns[O.drawingFkStartCol.colIndex];i.fkTarget={table:e,column:t.name},i.nullable=n,r.columns.splice(O.drawingFkStartCol.colIndex,1),r.columns.push(i),H()}else window.showToast(`Target table has no Primary Key!`,`error`)}}else{let e=O.erdData.find(e=>e.table===O.drawingFkStartCol.table).columns[O.drawingFkStartCol.colIndex];e.fkTarget&&(O.pushUndoState(),delete e.fkTarget,H())}let r=document.getElementById(`erd-temp-path`);r&&r.remove(),O.drawingFkStartCol=null}if(O.draggingNode){document.body.style.cursor=``;let e=k();O.draggedNodesStart.forEach(t=>{t.node.style.zIndex=``,e[t.node.dataset.table]={x:parseFloat(t.node.style.left),y:parseFloat(t.node.style.top)}}),A(e),W(),O.draggingNode=null,O.draggedNodesStart=[]}}))}var R=!1,z={x:0,y:0},B=null;function ge(e){e.addEventListener(`scroll`,()=>{W()}),e.addEventListener(`mousedown`,t=>{t.button===1||t.button===0&&t.altKey?(t.preventDefault(),O.isPanning=!0,O.panStart.x=t.clientX,O.panStart.y=t.clientY,O.scrollStart.left=e.scrollLeft,O.scrollStart.top=e.scrollTop,document.body.style.cursor=`grabbing`):t.button===0&&(t.target.id===`erd-workspace`||t.target.id===`erd-svg-layer`||t.target.id===`erd-nodes-layer`)&&(R=!0,z={x:t.clientX,y:t.clientY},!t.ctrlKey&&!t.metaKey&&(O.clearSelection(),H()),B=document.createElement(`div`),B.style.position=`fixed`,B.style.border=`1px solid #3b82f6`,B.style.backgroundColor=`rgba(59, 130, 246, 0.1)`,B.style.zIndex=`1000`,B.style.pointerEvents=`none`,document.body.appendChild(B))});let t=()=>{let e=document.getElementById(`btn-erd-zoom-reset`);e&&(e.textContent=Math.round(O.zoom*100)+`%`)},n=e=>{O.zoom=Math.max(.2,Math.min(e,3));let n=document.getElementById(`erd-workspace`);n&&(n.style.transform=`scale(${O.zoom})`,U(),W(),t())},r=document.getElementById(`btn-erd-zoom-in`);r&&r.addEventListener(`click`,()=>n(O.zoom+.1));let i=document.getElementById(`btn-erd-zoom-out`);i&&i.addEventListener(`click`,()=>n(O.zoom-.1));let a=document.getElementById(`btn-erd-zoom-reset`);a&&a.addEventListener(`click`,()=>n(1)),e.addEventListener(`wheel`,e=>{(e.ctrlKey||e.metaKey)&&(e.preventDefault(),n(O.zoom-e.deltaY*.001))},{passive:!1}),document.addEventListener(`mousemove`,t=>{if(R&&B){let e=Math.min(t.clientX,z.x),n=Math.min(t.clientY,z.y),r=Math.abs(t.clientX-z.x),i=Math.abs(t.clientY-z.y);B.style.left=e+`px`,B.style.top=n+`px`,B.style.width=r+`px`,B.style.height=i+`px`;return}if(O.isPanning){if(e){let n=t.clientX-O.panStart.x,r=t.clientY-O.panStart.y;e.scrollLeft=O.scrollStart.left-n,e.scrollTop=O.scrollStart.top-r}return}}),document.addEventListener(`mouseup`,e=>{if(R&&(R=!1,B)){let e=B.getBoundingClientRect();B.remove(),B=null;let t=document.querySelectorAll(`.erd-node`),n=!1;t.forEach(t=>{let r=t.getBoundingClientRect();e.right<r.left||e.left>r.right||e.bottom<r.top||e.top>r.bottom||(O.selectedTables.add(t.dataset.table),n=!0)}),n&&H()}O.isPanning&&(O.isPanning=!1,document.body.style.cursor=``)}),e.addEventListener(`contextmenu`,e=>{(e.target.id===`erd-workspace`||e.target.id===`erd-svg-layer`||e.target.id===`erd-nodes-layer`||e.target.id===`erd-wrapper`)&&(e.preventDefault(),e.stopPropagation(),M(e,[{label:`Add Table`,icon:`add_box`,action:()=>{let e=document.getElementById(`btn-add-table`);e&&e.click()}},`divider`,{label:`Auto Layout`,icon:`account_tree`,action:()=>{O.pushUndoState(),de(O.erdData),H(),window.showToast(`Auto Layout Applied`,`success`)}}]))});let o=document.getElementById(`erd-search-input`),s=document.getElementById(`erd-search-results`);o&&s&&(o.addEventListener(`input`,t=>{let n=t.target.value.toLowerCase();if(s.innerHTML=``,!n){s.style.display=`none`;return}let r=O.erdData.filter(e=>e.table.toLowerCase().includes(n));if(r.length===0){s.innerHTML=`<div class="erd-search-item" class="text-soft">No results</div>`,s.style.display=`block`;return}r.forEach(t=>{let n=document.createElement(`div`);n.className=`erd-search-item`,n.textContent=t.table,n.onclick=()=>{O.setSelection(t.table);let n=document.querySelector(`.erd-node[data-table="${t.table}"]`);if(n){let t=n.getBoundingClientRect(),r=e.getBoundingClientRect(),i=parseFloat(n.style.left),a=parseFloat(n.style.top);e.scrollLeft=i*O.zoom-r.width/2+t.width/2,e.scrollTop=a*O.zoom-r.height/2+t.height/2}H(),s.style.display=`none`,o.value=``},s.appendChild(n)}),s.style.display=`block`}),document.addEventListener(`click`,e=>{!o.contains(e.target)&&!s.contains(e.target)&&(s.style.display=`none`)}))}function _e(e){let t=document.getElementById(`erd-minimap`);if(!t)return;let n=!1;t.addEventListener(`mousedown`,r=>{if(r.stopPropagation(),r.button!==0)return;n=!0;let i=t.getBoundingClientRect(),a=.0325,o=t=>{let n=t.clientX-i.left,r=t.clientY-i.top,o=(n-25)/a,s=(r-0)/a,c=e.clientWidth/O.zoom,l=e.clientHeight/O.zoom;e.scrollLeft=(o-c/2)*O.zoom,e.scrollTop=(s-l/2)*O.zoom};o(r);let s=e=>{n&&o(e)},c=()=>{n=!1,document.removeEventListener(`mousemove`,s),document.removeEventListener(`mouseup`,c)};document.addEventListener(`mousemove`,s),document.addEventListener(`mouseup`,c)})}var V=!1;function ve(){if(V)return;let e=document.getElementById(`erd-wrapper`);e&&(ge(e),_e(e),pe(),he(),V=!0)}function H(){let e=document.getElementById(`erd-nodes-layer`);if(!e)return;if(e.innerHTML=``,!O.erdData||O.erdData.length===0){e.innerHTML=`
333
- <div class="p-6 text-soft">No tables found. Right click to add one.</div>
334
- `;return}let t=k(),n=50,r=50,i=0;O.erdData.forEach(a=>{let o,s;t[a.table]?(o=t[a.table].x,s=t[a.table].y):(o=n,s=r,n+=320,n>1200&&(n=50,r+=i+50,i=0));let c=ye(a,o,s);O.selectedTables.has(a.table)&&c.classList.add(`is-selected`),e.appendChild(c);let l=40+a.columns.length*40+40;l>i&&(i=l)}),me(),setTimeout(()=>{U(),W()},10)}function ye(e,t,n){let r=document.createElement(`div`);r.className=`erd-node ${e.isDraft?`is-draft`:``}`,r.dataset.table=e.table,r.style.left=`${t}px`,r.style.top=`${n}px`;let i=e.columns.map((t,n)=>{let r=`web_asset`,i=`var(--color-text-soft)`;t.isPk?(r=`key`,i=`#f59e0b`):t.fkTarget&&(r=`link`,i=`#3b82f6`);let a=t.fkTarget?`is-fk`:``,o=t.isDraft?`is-draft`:``,s=t.type.toUpperCase();return`
335
- <div class="erd-column ${a} ${o}" data-col="${t.name}" data-index="${n}">
336
- <div class="erd-col-left" class="flex-1 items-center gap-2">
337
- <span class="material-symbols-outlined erd-reorder-handle icon-16 cursor-grab" draggable="true" style="--dynamic-icon-color: ${i}; color: var(--dynamic-icon-color);">${r}</span>
338
- <span class="erd-col-name editable-field" data-field="name">${t.name}${t.nullable?` ?`:``}</span>
339
- </div>
340
- <div class="erd-col-right items-center gap-6px">
341
- <span class="erd-col-type editable-field" data-field="type">${s}</span>
342
- ${(t.isDraft||e.isDraft)&&!t.isPk?`<div class="erd-drag-handle" title="Drag to create Foreign Key"></div>`:``}
343
- </div>
344
- </div>
345
- `}).join(``);return r.innerHTML=`
346
- <div class="erd-node-header" title="${e.isDraft?`Double click to rename`:``}">
347
- <span class="material-symbols-outlined" class="icon-16">table_chart</span>
348
- <span class="font-semibold" class="erd-node-name">${e.table}</span>
349
- </div>
350
- <div class="erd-node-body">
351
- ${i}
352
- </div>
353
- <div class="erd-add-col-btn">
354
- <span class="material-symbols-outlined" class="icon-16">add</span> Add Column
355
- </div>
356
- `,r}function U(){let e=document.getElementById(`erd-svg-layer`);if(!e)return;let t=``;O.erdData.forEach(e=>{let n=e.table,r=document.querySelector(`.erd-node[data-table="${n}"]`);r&&e.columns.forEach(e=>{if(e.fkTarget){let n=e.fkTarget.table,i=e.fkTarget.column,a=document.querySelector(`.erd-node[data-table="${n}"]`);if(!a)return;let o=r.querySelector(`.erd-column[data-col="${e.name}"]`),s=a.querySelector(`.erd-column[data-col="${i}"]`);if(!o||!s)return;let c=o.getBoundingClientRect(),l=s.getBoundingClientRect(),u=document.getElementById(`erd-workspace`).getBoundingClientRect(),d,f,p,m;c.right<l.left+20?(d=(c.right-u.left)/O.zoom,p=(l.left-u.left)/O.zoom):(d=(c.left-u.left)/O.zoom,p=(l.right-u.left)/O.zoom),f=(c.top+c.height/2-u.top)/O.zoom,m=(l.top+l.height/2-u.top)/O.zoom;let h=Math.abs(p-d),g=Math.max(h*.5,50),_=d<p?d+g:d-g,v=f,y=d<p?p-g:p+g,b=m,x=e.nullable?`url(#zero-or-one)`:`url(#one-and-only-one)`;t+=`
357
- <path
358
- d="M ${d} ${f} C ${_} ${v}, ${y} ${b}, ${p} ${m}"
359
- fill="none"
360
- stroke="var(--color-text)"
361
- stroke-width="1.5"
362
- opacity="0.8"
363
- marker-start="url(#crows-foot-zero-many)"
364
- marker-end="${x}"
365
- />
366
- `}})}),e.innerHTML=`
367
- <defs>
368
- <!-- FK side: Zero or Many (0<) -->
369
- <marker id="crows-foot-zero-many" viewBox="0 0 16 10" refX="16" refY="5" markerWidth="10" markerHeight="10" orient="auto-start-reverse">
370
- <path d="M 16 0 L 8 5 M 16 10 L 8 5 M 16 5 L 8 5 M 4 5 L 0 5" fill="none" stroke="var(--color-text)" stroke-width="1.5" opacity="0.9" />
371
- <circle cx="5" cy="5" r="3" fill="var(--color-bg-primary)" stroke="var(--color-text)" stroke-width="1.5" opacity="0.9" />
372
- </marker>
373
-
374
- <!-- PK side: One and Only One (||) -->
375
- <marker id="one-and-only-one" viewBox="0 0 16 10" refX="13" refY="5" markerWidth="10" markerHeight="10" orient="auto">
376
- <path d="M 10 0 L 10 10 M 6 0 L 6 10" fill="none" stroke="var(--color-text)" stroke-width="1.5" opacity="0.9" />
377
- </marker>
378
-
379
- <!-- PK side: Zero or One (0|) -->
380
- <marker id="zero-or-one" viewBox="0 0 16 10" refX="13" refY="5" markerWidth="10" markerHeight="10" orient="auto">
381
- <path d="M 10 0 L 10 10" fill="none" stroke="var(--color-text)" stroke-width="1.5" opacity="0.9" />
382
- <circle cx="5" cy="5" r="3" fill="var(--color-bg-primary)" stroke="var(--color-text)" stroke-width="1.5" opacity="0.9" />
383
- </marker>
384
- </defs>
385
- ${t}
386
- `}function W(){let e=document.getElementById(`erd-minimap-content`);if(!e)return;e.innerHTML=``;let t=k(),n=document.getElementById(`erd-nodes-layer`);if(!n)return;let r=Array.from(n.querySelectorAll(`.erd-node`)),i=.0325;r.forEach(n=>{let r=n.dataset.table,a=t[r]||{x:0,y:0},o=n.getBoundingClientRect(),s=o.width/O.zoom,c=o.height/O.zoom,l=document.createElement(`div`);l.style.position=`absolute`,l.style.left=`${25+a.x*i}px`,l.style.top=`${0+a.y*i}px`,l.style.width=`${s*i}px`,l.style.height=`${c*i}px`,l.style.backgroundColor=`var(--color-primary)`,l.style.opacity=O.selectedTables.has(r)?`1`:`0.5`,l.style.borderRadius=`2px`,e.appendChild(l)});let a=document.getElementById(`erd-minimap-viewport`);if(a){let e=document.getElementById(`erd-wrapper`),t=e.clientWidth/O.zoom,n=e.clientHeight/O.zoom,r=e.scrollLeft/O.zoom,o=e.scrollTop/O.zoom;a.style.left=`${25+r*i}px`,a.style.top=`${0+o*i}px`,a.style.width=`${t*i}px`,a.style.height=`${n*i}px`}}async function G(e){if(!document.getElementById(`erd-wrapper`)){e.innerHTML=`
387
- <div id="erd-wrapper" class="erd-grid-bg erd-workspace-container">
388
- <div id="erd-workspace" class="erd-workspace-canvas">
389
- <svg id="erd-svg-layer" class="erd-svg-layer"></svg>
390
- <div id="erd-nodes-layer" class="erd-nodes-layer"></div>
391
- </div>
392
- <div class="erd-controls-container">
393
- <!-- Search -->
394
- <div class="erd-search-container" class="pointer-events-auto">
395
- <span class="material-symbols-outlined search-icon">search</span>
396
- <input type="text" id="erd-search-input" placeholder="Search tables..." autocomplete="off">
397
- <div id="erd-search-results" class="erd-search-results hidden"></div>
398
- </div>
399
-
400
- <!-- Zoom Controls -->
401
- <div class="erd-controls-group">
402
- <button id="btn-erd-zoom-out" class="drixio-btn drixio-btn-secondary erd-zoom-btn" title="Zoom Out"><span class="material-symbols-outlined" class="icon-20">remove</span></button>
403
- <button id="btn-erd-zoom-reset" class="drixio-btn drixio-btn-secondary erd-zoom-text-btn" title="Reset Zoom">100%</button>
404
- <button id="btn-erd-zoom-in" class="drixio-btn drixio-btn-secondary erd-zoom-btn" title="Zoom In"><span class="material-symbols-outlined" class="icon-20">add</span></button>
405
- </div>
406
-
407
- <!-- Minimap -->
408
- <div id="erd-minimap" class="erd-minimap">
409
- <div id="erd-minimap-content" class="erd-minimap-content"></div>
410
- <div id="erd-minimap-viewport" class="erd-minimap-viewport"></div>
411
- </div>
412
- </div>
413
- </div>
414
- `;let t={x:0,y:0};document.getElementById(`erd-wrapper`).addEventListener(`contextmenu`,e=>{if(e.preventDefault(),e.target.closest(`.erd-node`))return;let n=document.getElementById(`erd-workspace`).getBoundingClientRect();t.x=(e.clientX-n.left)/O.zoom,t.y=(e.clientY-n.top)/O.zoom,M(e,[{label:`Add Table`,icon:`table_chart`,action:()=>{let e=`new_table_${Math.floor(Math.random()*1e3)}`,n={table:e,isDraft:!0,columns:[{name:`id`,type:`INTEGER`,isPk:!0,isDraft:!0,nullable:!1}]},r=k();r[e]={x:t.x,y:t.y},A(r),O.pushUndoState(),O.erdData.push(n),H()}},{label:`Paste`,icon:`content_paste`,action:I}])}),ve()}let t=document.getElementById(`erd-nodes-layer`);t&&(t.innerHTML=`<div class="p-6 text-soft">Loading ERD Data...</div>`),O.erdData=await le()||[],O.erdData.forEach(e=>{e.columns.sort((e,t)=>e.isPk&&!t.isPk?-1:!e.isPk&&t.isPk||e.fkTarget&&!t.fkTarget?1:!e.fkTarget&&t.fkTarget?-1:0),e.columns.forEach(e=>{e.isPk&&(e.nullable=!1)})}),O.undoStack=[],O.clearSelection(),H()}function be(e){if(!e||e<=0)return`N/A`;let t=Math.floor(e/(3600*24)),n=Math.floor(e%(3600*24)/3600),r=Math.floor(e%3600/60),i=``;return t>0&&(i+=`${t}d `),n>0&&(i+=`${n}h `),i+=`${r}m`,i||`< 1m`}function K(e){if(e===0||!e)return`0 B`;let t=1024,n=[`B`,`KB`,`MB`,`GB`,`TB`],r=Math.floor(Math.log(e)/Math.log(t));return parseFloat((e/t**r).toFixed(2))+` `+n[r]}var q=null,J=null;function Y(e,t,n,r,i=``){return`
415
- <div class="status-card ${r}">
416
- <div class="status-card-header">
417
- <span>${t}</span>
418
- <div class="status-card-icon">
419
- <span class="material-symbols-outlined">${e}</span>
420
- </div>
421
- </div>
422
- <div class="status-card-value">${n}</div>
423
- ${i?`<div class="status-card-subtext">${i}</div>`:``}
424
- </div>
425
- `}function xe(e){let t=document.getElementById(`status-cards-container`);if(!t)return;let n=``,r=Date.now();if(n+=Y(`table`,`Total Tables`,e.totalTables||`0`,`card-purple`),n+=Y(`hard_drive`,`Storage Used`,K(e.sizeBytes),`card-warning`),n+=Y(`dns`,`Active Connections`,e.activeConnections||`0`,`card-success`),e.uptime&&(n+=Y(`schedule`,`Server Uptime`,be(e.uptime),`card-purple`)),e.dbType===`mysql`){let t=0;if(q&&J&&e.queries){let n=(r-J)/1e3,i=e.queries-q.queries;t=Math.max(0,i/n)}n+=Y(`speed`,`Queries Per Second`,t.toFixed(1),`card-primary`,`QPS (Estimated)`)}else if(e.dbType===`postgres`){let t=0;if(q&&J&&e.transactions){let n=(r-J)/1e3,i=e.transactions-q.transactions;t=Math.max(0,i/n)}n+=Y(`receipt_long`,`Transactions Per Sec`,t.toFixed(1),`card-primary`,`TPS (Estimated)`)}else if(e.dbType===`sqlite`){let t=(e.osMemUsed/e.osMemTotal*100).toFixed(1);n+=Y(`memory`,`Host Memory Usage`,`${t}%`,`card-primary`,K(e.osMemUsed)),n+=Y(`memory_alt`,`Host CPU Load`,(e.osCpuUsage||0).toFixed(2),`card-purple`,`1 min avg`)}t.innerHTML=n,q=e,J=r}window.navigateToTableData=function(e){let t=document.querySelector(`.table-btn[data-table="${e}"]`);t&&(window.AppState.currentTable=e,window.AppState.currentTableBtnElement=t,window.handleSwitchTab(`data-btn`))};function Se(e){let t=document.getElementById(`status-distribution-container`),n=document.getElementById(`status-toptables-container`);if(!t||!n)return;let r=Object.entries(e).sort((e,t)=>t[1]-e[1]);if(r.length===0)return;let i=r.slice(0,5),a=r.reduce((e,[t,n])=>e+n,0),o=[`#3b82f6`,`#10b981`,`#f59e0b`,`#8b5cf6`,`#ec4899`],s=`<h3 class="top-tables-title">Top Largest Tables</h3><div class="top-tables-list">`;i.forEach(([e,t],n)=>{s+=`
426
- <div class="top-table-item hover-clickable" onclick="window.navigateToTableData('${e}')">
427
- <span class="top-table-name" style="border-left: 4px solid ${o[n]}; padding-left: 8px;">${e}</span>
428
- <span class="top-table-rows">${t.toLocaleString()} rows</span>
429
- </div>
430
- `}),s+=`</div>`,n.innerHTML=s,n.classList.remove(`hidden`),n.classList.add(`block`);let c=`<h3 class="distribution-title">Row Count Distribution</h3><div class="distribution-content" style="display: flex; gap: 48px; align-items: center; justify-content: space-between; margin-top: 24px;">`,l=`<div class="distribution-legend" style="flex: 1; margin-top: 0;">`,u=[],d=0;if(a>0){let e=0;i.forEach(([t,n],r)=>{let i=n/a*100;e+=n;let s=d,c=d+i;u.push(`${o[r]} ${s.toFixed(2)}% ${c.toFixed(2)}%`),d=c,l+=`
431
- <div class="legend-item">
432
- <div class="legend-color" style="background: ${o[r]}"></div>
433
- <span>${t} (${i.toFixed(1)}%)</span>
434
- </div>
435
- `});let t=a-e;if(t>0&&r.length>5){let e=t/a*100,n=d,r=d+e;u.push(`#94a3b8 ${n.toFixed(2)}% ${r.toFixed(2)}%`),d=r,l+=`
436
- <div class="legend-item">
437
- <div class="legend-color" style="background: #94a3b8"></div>
438
- <span>Others (${e.toFixed(1)}%)</span>
439
- </div>
440
- `}c+=`<div class="distribution-pie" style="background: conic-gradient(${u.join(`, `)});"></div>`}else c+=`<div class="distribution-pie" style="background: var(--color-border);"></div>`,l+=`<div class="text-soft text-sm">No rows found</div>`;l+=`</div>`,c+=l+`</div>`,t.innerHTML=c,t.classList.remove(`hidden`),t.classList.add(`block`)}function Ce(){X()}async function we(e){e.innerHTML=`
441
- <div class="status-dashboard">
442
- <div class="hero-overview-panel">
443
- <div class="status-db-icon-container">
444
- <span class="material-symbols-outlined status-db-icon" id="status-db-icon">database_search</span>
445
- <span id="connection-dot" class="connection-dot yellow"></span>
446
- </div>
447
- <div class="hero-info">
448
- <h1 id="header-db-name" class="hero-db-name">-</h1>
449
- <div class="hero-subinfo">
450
- <span id="header-db-type" class="hero-db-type">-</span>
451
- <span class="hero-dot-separator">•</span>
452
- <span id="header-db-version" class="hero-db-version">-</span>
453
- </div>
454
- </div>
455
- <div class="hero-actions" style="margin-left: auto; margin-bottom: auto;">
456
- <button id="status-refresh-btn" class="icon-btn primary" title="Refresh Metrics" style="display: flex; align-items: center; margin-bottom: auto; gap: 8px; padding: 8px 12px; border-radius: 8px; background: rgba(255,255,255,0.1); border: 1px solid rgba(255,255,255,0.1); color: var(--color-text); cursor: pointer; font-size: 12px; font-weight: 500; transition: all 0.2s;">
457
- <span class="material-symbols-outlined" style="font-size: 16px;">refresh</span>
458
- Refresh
459
- </button>
460
- </div>
461
- </div>
462
-
463
- <div class="status-grid" id="status-cards-container">
464
- <!-- Cards will be injected here -->
465
- </div>
466
-
467
- <div class="analytics-split-view">
468
- <div id="status-toptables-container" class="top-tables-container hidden">
469
- <!-- Top tables injected here -->
470
- </div>
471
- <div id="status-distribution-container" class="distribution-container hidden">
472
- <!-- Distribution Bar injected here -->
473
- </div>
474
- </div>
475
-
476
- <div id="feature-prompts-container" class="flex-col gap-4 mt-4 hidden">
477
- <!-- Feature prompts will be injected here -->
478
- </div>
479
- </div>
480
- `,await X();let t=document.getElementById(`status-refresh-btn`);t&&t.addEventListener(`click`,()=>{let e=t.querySelector(`.material-symbols-outlined`);e&&(e.style.transition=`transform 0.5s ease`,e.style.transform=`rotate(${(e.dataset.rot||0)*1+360}deg)`,e.dataset.rot=(e.dataset.rot||0)*1+360),X()}),window.statusPollingInterval&&clearInterval(window.statusPollingInterval),window.statusPollingInterval=setInterval(()=>{window.AppState.currentTab===`status-btn`&&X()},3e3)}async function X(){try{let[e,t]=await Promise.all([fetch(`/api/status`),fetch(`/api/tables/stats`)]),n=await e.json(),r=await t.json();n.success?Te(n.data,r.data):Z(n.error)}catch(e){Z(e.message)}}function Te(e,t={}){let n=document.getElementById(`status-db-icon`),r=document.getElementById(`connection-dot`);if(!n||!r)return;if(e.status===`connected`)n.textContent=`database`,r.className=`connection-dot green`;else{n.textContent=`database_off`,r.className=`connection-dot red`;return}let i=document.getElementById(`header-db-name`),a=document.getElementById(`header-db-type`),o=document.getElementById(`header-db-version`);i&&(i.textContent=e.dbName||`Unknown`),a&&(a.textContent=e.dbType||`Unknown`),o&&(o.textContent=e.version?`v${e.version}`:`N/A`),xe(e);let s=document.getElementById(`feature-prompts-container`);s&&(s.innerHTML=`
481
- <div class="feature-prompt">
482
- <span class="material-symbols-outlined icon">info</span>
483
- <div>
484
- <div class="prompt-title">Avg Query Latency & Slow Queries</div>
485
- <div>This metric requires specific database plugins to be enabled on your server (e.g. <code>pg_stat_statements</code> for PostgreSQL, or <code>Performance Schema</code> for MySQL).</div>
486
- </div>
487
- </div>
488
- `,s.classList.remove(`hidden`),s.classList.add(`flex`)),Se(t)}function Z(e){let t=document.getElementById(`status-db-icon`),n=document.getElementById(`connection-dot`);t&&n&&(t.textContent=`database_off`,n.className=`connection-dot red`);let r=document.getElementById(`status-cards-container`);r&&(r.innerHTML=`<div class="text-red-500">Failed to load database status: ${e}</div>`)}var Ee=()=>{let e=localStorage.getItem(`drixio-theme`),t=window.matchMedia&&window.matchMedia(`(prefers-color-scheme: dark)`).matches;if(e===`dark`||!e&&t){document.documentElement.setAttribute(`data-theme`,`dark`);let e=document.getElementById(`theme-icon`);e&&(e.textContent=`light_mode`)}let n=document.getElementById(`theme-toggle`);n&&n.addEventListener(`click`,()=>{let e=document.documentElement.getAttribute(`data-theme`)===`dark`,t=e?`light`:`dark`;document.documentElement.setAttribute(`data-theme`,t),localStorage.setItem(`drixio-theme`,t),document.getElementById(`theme-icon`).textContent=e?`dark_mode`:`light_mode`})},De=()=>{window.showToast=function(e,t=`success`){let n=document.getElementById(`toast-container`);if(!n)return;let r=document.createElement(`div`);r.className=`toast ${t}`,r.innerHTML=`<span class="material-symbols-outlined">${t===`success`?`check_circle`:`error`}</span> <span>${e}</span>`,n.appendChild(r),setTimeout(()=>{r.parentNode&&r.parentNode.removeChild(r)},3e3)}},Oe=()=>{document.addEventListener(`mouseup`,()=>{window.DataGrid&&window.DataGrid.selection&&(window.DataGrid.selection.isDragging=!1),window.SchemaGrid&&window.SchemaGrid.selection&&(window.SchemaGrid.selection.isDragging=!1)}),document.addEventListener(`contextmenu`,e=>{let t=window.AppState?.currentTab===`data-btn`,n=window.AppState?.currentTab===`schema-btn`;if(!t&&!n||t&&!window.DataGrid||n&&!window.SchemaGrid)return;let r=e.target.closest(`td.row-header`);if(!r)return;e.preventDefault();let i=parseInt(r.dataset.rowIdx),a=e=>{let r=[i],a=t?window.DataGrid:window.SchemaGrid;if(a&&a.selection&&a.selection.startRow!==-1){let e=a.selection,t=Math.min(e.startRow,e.endRow),n=Math.max(e.startRow,e.endRow);if(i>=t&&i<=n){r=[];for(let e=t;e<=n;e++)r.push(e)}}t?(window.DataGrid.currentTransaction=[],e===`delete`?r.forEach(e=>g(e)):e===`duplicate`&&(v(r,window.DataGrid.schema.map(e=>e.name)),setTimeout(()=>{let e=document.getElementById(`data-grid-container-${window.AppState.currentTable}`);e&&(e.scrollTop=e.scrollHeight)},50)),window.DataGrid.currentTransaction.length>0&&window.DataGrid.history.push(window.DataGrid.currentTransaction),window.DataGrid.currentTransaction=null):n&&(window.SchemaGrid.currentTransaction=[],e===`delete`?r.forEach(e=>w(e)):e===`duplicate`&&(ne(r,[`name`,`type`,`isPk`,`nullable`,`defaultValue`,`Index`]),setTimeout(()=>{let e=document.getElementById(`schema-grid-container-${window.AppState.currentTable}`);e&&(e.scrollTop=e.scrollHeight)},50)),window.SchemaGrid.currentTransaction.length>0&&window.SchemaGrid.history.push(window.SchemaGrid.currentTransaction),window.SchemaGrid.currentTransaction=null)};M(e,[{label:`Duplicate Row(s)`,icon:`content_copy`,action:()=>a(`duplicate`)},`divider`,{label:`Delete Row(s)`,icon:`delete`,danger:!0,action:()=>a(`delete`)}])}),document.addEventListener(`keydown`,e=>{let t=window.AppState?.currentTab===`data-btn`,n=window.AppState?.currentTab===`schema-btn`;if(e.key===`F5`){t&&window.DataGrid?.refreshData?(e.preventDefault(),window.DataGrid.refreshData()):n&&document.getElementById(`btn-refresh-schema`)&&(e.preventDefault(),document.getElementById(`btn-refresh-schema`).click());return}if(!(!t&&!n)&&!(e.target.tagName===`INPUT`||e.target.tagName===`SELECT`||e.target.tagName===`TEXTAREA`)){if([`ArrowUp`,`ArrowDown`,`ArrowLeft`,`ArrowRight`].includes(e.key)){let n=t?window.DataGrid:window.SchemaGrid;if(!n||!n.selection)return;e.preventDefault();let r=n.selection;if(r.startRow===-1)return;let i=t?n.schema.length:5,a=window.AppState?.currentTable,o=document.querySelectorAll(t?`#data-grid-table-${a} tbody tr`:`#schema-grid-table-${a} tbody tr`),s=o.length>0?o.length-1:0,c=e.shiftKey?r.endRow:r.startRow,l=e.shiftKey?r.endCol:r.startCol;e.key===`ArrowUp`&&(c=Math.max(0,c-1)),e.key===`ArrowDown`&&(c=Math.min(s,c+1)),e.key===`ArrowLeft`&&(l=Math.max(0,l-1)),e.key===`ArrowRight`&&(l=Math.min(i-1,l+1)),e.shiftKey?(r.endRow=c,r.endCol=l):(r.startRow=c,r.endRow=c,r.startCol=l,r.endCol=l),d(t?`data-grid-table-${a}`:`schema-grid-table-${a}`,n),setTimeout(()=>{let e=document.querySelector(t?`#data-grid-table-${a} td.data-cell[data-row-idx="${c}"][data-col-idx="${l}"]`:`#schema-grid-table-${a} td.data-cell[data-row-idx="${c}"][data-col-idx="${l}"]`);if(e){let n=document.getElementById(t?`data-grid-container-${a}`:`schema-grid-container-${a}`);if(n){let t=e.getBoundingClientRect(),r=n.getBoundingClientRect();t.bottom>r.bottom?n.scrollTop+=t.bottom-r.bottom+5:t.top<r.top+30&&(n.scrollTop-=r.top+30-t.top),t.right>r.right?n.scrollLeft+=t.right-r.right+5:t.left<r.left+50&&(n.scrollLeft-=r.left+50-t.left)}}},5);return}if(e.key===`Enter`||e.key===`Tab`){let n=t?window.DataGrid:window.SchemaGrid;if(!n||!n.selection||n.selection.startRow===-1)return;e.preventDefault();let r=window.AppState?.currentTable,i=Math.min(n.selection.startRow,n.selection.endRow),a=Math.min(n.selection.startCol,n.selection.endCol);if(e.key===`Enter`){let e=document.querySelector(t?`#data-grid-table-${r} td.data-cell[data-row-idx="${i}"][data-col-idx="${a}"]`:`#schema-grid-table-${r} td.data-cell[data-row-idx="${i}"][data-col-idx="${a}"]`);if(e){let t=new MouseEvent(`dblclick`,{bubbles:!0,cancelable:!0,view:window});e.dispatchEvent(t)}return}if(e.key===`Tab`){let o=t?n.schema.length:5,s=document.querySelectorAll(t?`#data-grid-table-${r} tbody tr`:`#schema-grid-table-${r} tbody tr`),c=s.length>0?s.length-1:0;e.shiftKey?(--a,a<0&&(a=o-1,i=Math.max(0,i-1))):(a+=1,a>=o&&(a=0,i=Math.min(c,i+1))),n.selection.startRow=i,n.selection.endRow=i,n.selection.startCol=a,n.selection.endCol=a,d(t?`data-grid-table-${r}`:`schema-grid-table-${r}`,n),setTimeout(()=>{let e=document.querySelector(t?`#data-grid-table-${r} td.data-cell[data-row-idx="${i}"][data-col-idx="${a}"]`:`#schema-grid-table-${r} td.data-cell[data-row-idx="${i}"][data-col-idx="${a}"]`);if(e){let n=document.getElementById(t?`data-grid-container-${r}`:`schema-grid-container-${r}`);if(n){let t=e.getBoundingClientRect(),r=n.getBoundingClientRect();t.bottom>r.bottom?n.scrollTop+=t.bottom-r.bottom+5:t.top<r.top+30&&(n.scrollTop-=r.top+30-t.top),t.right>r.right?n.scrollLeft+=t.right-r.right+5:t.left<r.left+50&&(n.scrollLeft-=r.left+50-t.left)}}},5);return}}if(e.key===`Delete`||e.key===`Backspace`){if(t)window.DataGrid.currentTransaction=[],document.querySelectorAll(`#data-grid-table-${window.AppState.currentTable} .cell-in-range`).forEach(e=>h(e,``,window.DataGrid.schema.map(e=>e.name))),window.DataGrid.currentTransaction.length>0&&window.DataGrid.history.push(window.DataGrid.currentTransaction),window.DataGrid.currentTransaction=null;else if(n){window.SchemaGrid.currentTransaction=[];let e=[`name`,`type`,`isPk`,`nullable`,`defaultValue`];document.querySelectorAll(`#schema-grid-table-${window.AppState.currentTable} .cell-in-range`).forEach(t=>{(t.dataset.insertIndex!==void 0||t.dataset.colKey===`name`)&&C(t,``,e)}),window.SchemaGrid.currentTransaction.length>0&&window.SchemaGrid.history.push(window.SchemaGrid.currentTransaction),window.SchemaGrid.currentTransaction=null}}if(e.key.toLowerCase()===`s`&&(e.ctrlKey||e.metaKey)&&(e.preventDefault(),t&&window.saveDataGridEdits(),n&&window.saveSchemaEdits()),e.key.toLowerCase()===`c`&&(e.ctrlKey||e.metaKey)){let e=(t?window.DataGrid:window.SchemaGrid).selection;if(e.startRow===-1)return;let n=Math.min(e.startRow,e.endRow),r=Math.max(e.startRow,e.endRow),i=Math.min(e.startCol,e.endCol),a=Math.max(e.startCol,e.endCol),o=``;for(let e=n;e<=r;e++){let n=[];for(let r=i;r<=a;r++){let i=document.querySelector(t?`#data-grid-table-${window.AppState.currentTable} td.data-cell[data-row-idx="${e}"][data-col-idx="${r}"]`:`#schema-grid-table-${window.AppState.currentTable} td.data-cell[data-row-idx="${e}"][data-col-idx="${r}"]`);if(i){let e=i.textContent.replace(/^null$|^\+ New$/,``);n.push(e)}}o+=n.join(` `)+`
489
- `}navigator.clipboard.writeText(o.trimEnd()),document.querySelectorAll(`.cell-in-range`).forEach(e=>{e.style.backgroundColor=`var(--color-copy-flash)`,setTimeout(()=>e.style.backgroundColor=``,150)})}if(e.key===`-`&&(e.ctrlKey||e.metaKey)){e.preventDefault();let r=t?window.DataGrid:window.SchemaGrid,i=r.selection;if(i.startRow===-1)return;let a=Math.min(i.startRow,i.endRow),o=Math.max(i.startRow,i.endRow);if(t){r.currentTransaction=[];for(let e=a;e<=o;e++)g(e);r.currentTransaction.length>0&&r.history.push(r.currentTransaction),r.currentTransaction=null}else if(n){r.currentTransaction=[];for(let e=a;e<=o;e++)w(e);r.currentTransaction.length>0&&r.history.push(r.currentTransaction),r.currentTransaction=null}}if(e.key.toLowerCase()===`z`&&(e.ctrlKey||e.metaKey)){if(e.preventDefault(),t){let e=window.DataGrid.history?.pop();if(e){let t=window.DataGrid.schema.map(e=>e.name);for(let n=e.length-1;n>=0;n--){let r=e[n];r.type===`delete`?_(r.rowIdx,r.pk):h(r.td,r.oldVal,t,!1)}}}else if(n){let e=window.SchemaGrid.history?.pop();if(e){let t=[`name`,`type`,`isPk`,`nullable`,`defaultValue`];for(let n=e.length-1;n>=0;n--){let r=e[n];r.type===`delete`?te(r.rowIdx,r.pk):C(r.td,r.oldVal,t,!1)}}}}}}),document.addEventListener(`paste`,e=>{let t=window.AppState?.currentTab===`data-btn`,n=window.AppState?.currentTab===`schema-btn`;if(!t&&!n)return;let r=t?window.DataGrid:window.SchemaGrid;if(!r||e.target.tagName===`INPUT`||e.target.tagName===`SELECT`||e.target.tagName===`TEXTAREA`)return;let i=r.selection;if(i.startRow===-1)return;let a=e.clipboardData.getData(`text`);if(!a)return;e.preventDefault();let o=a.split(/\r?\n/).map(e=>e.split(` `)),s=Math.min(i.startRow,i.endRow),c=Math.min(i.startCol,i.endCol);if(r.currentTransaction=[],t){let e=r.schema.map(e=>e.name);o.forEach(t=>{t.forEach((t,n)=>{let r=c+n,i=document.querySelector(`#data-grid-table-${window.AppState.currentTable} td.data-cell[data-row-idx="${s}"][data-col-idx="${r}"]`);i&&h(i,t,e)}),s++}),r.currentTransaction.length>0&&r.history.push(r.currentTransaction),r.currentTransaction=null}else if(n){let e=[`name`,`type`,`isPk`,`nullable`,`defaultValue`];o.forEach(t=>{t.forEach((t,n)=>{let r=c+n,i=document.querySelector(`#schema-grid-table-${window.AppState.currentTable} td.data-cell[data-row-idx="${s}"][data-col-idx="${r}"]`);i&&(i.dataset.insertIndex!==void 0||i.dataset.colKey===`name`)&&C(i,t,e)}),s++}),r.currentTransaction.length>0&&r.history.push(r.currentTransaction),r.currentTransaction=null}})},ke=document.getElementById(`header-container`),Ae=document.getElementById(`sidebar-container`),je=document.getElementById(`tab-container`);ke.innerHTML=e,Ae.innerHTML=t,je.innerHTML=n;var Q=document.getElementById(`export-btn`),$=document.getElementById(`export-dropdown`);if(Q&&$){Q.addEventListener(`click`,e=>{e.stopPropagation(),$.classList.toggle(`hidden`);let t=window.AppState.currentTab===`data-btn`,n=window.AppState.currentTab===`console-btn`;document.querySelectorAll(`.data-tab-only`).forEach(e=>{e.style.display=t?`list-item`:`none`}),document.querySelectorAll(`.console-tab-only`).forEach(e=>{e.style.display=n?`list-item`:`none`})}),document.addEventListener(`click`,e=>{!Q.contains(e.target)&&!$.contains(e.target)&&$.classList.add(`hidden`)});let e=(e,t,n=!1)=>{if($.classList.add(`hidden`),e===`/query/export`){let e=document.querySelector(`#sql-editor textarea`)||document.querySelector(`#sql-editor`),n=``;if(e&&e.value&&(n=e.value),!n&&window.ViewCache&&window.ViewCache.lastQuery&&(n=window.ViewCache.lastQuery),!n){alert(`No SQL query found to export.`);return}fetch(`/api/query/export?format=${t}`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({sql:n})}).then(e=>e.blob()).then(e=>{let n=URL.createObjectURL(e),r=document.createElement(`a`);r.href=n,r.download=`query_result_${new Date().getTime()}.${t}`,document.body.appendChild(r),r.click(),r.remove()}).catch(e=>alert(`Failed to export query: `+e));return}let r=`${e}?format=${t}`;if(n&&window.DataGrid){let e=b?b():``,t=window.DataGrid.sortState?.col||``,n=window.DataGrid.sortState?.asc??!0;r+=`&where=${encodeURIComponent(e)}&orderCol=${t}&orderAsc=${n}`}window.open(r,`_blank`)};document.getElementById(`export-data-csv-btn`)?.addEventListener(`click`,()=>{window.AppState.currentTable&&e(`/api/tables/${window.AppState.currentTable}/export`,`csv`)}),document.getElementById(`export-data-json-btn`)?.addEventListener(`click`,()=>{window.AppState.currentTable&&e(`/api/tables/${window.AppState.currentTable}/export`,`json`)}),document.getElementById(`export-data-filtered-csv-btn`)?.addEventListener(`click`,()=>{window.AppState.currentTable&&e(`/api/tables/${window.AppState.currentTable}/export`,`csv`,!0)}),document.getElementById(`export-data-filtered-json-btn`)?.addEventListener(`click`,()=>{window.AppState.currentTable&&e(`/api/tables/${window.AppState.currentTable}/export`,`json`,!0)}),document.getElementById(`export-schema-dict-btn`)?.addEventListener(`click`,()=>{window.open(`/api/database/dictionary`,`_blank`),$.classList.add(`hidden`)}),document.getElementById(`export-schema-sql-btn`)?.addEventListener(`click`,()=>{window.open(`/api/database/schema-only`,`_blank`),$.classList.add(`hidden`)}),document.getElementById(`export-console-csv-btn`)?.addEventListener(`click`,()=>{e(`/api/query/export`,`csv`)}),document.getElementById(`export-console-json-btn`)?.addEventListener(`click`,()=>{e(`/api/query/export`,`json`)}),document.getElementById(`export-erd-json-btn`)?.addEventListener(`click`,()=>{let e=localStorage.getItem(`drixio_erd_drafts`);if(!e){alert(`No ERD layout found to export.`);return}let t=new Blob([e],{type:`application/json`}),n=URL.createObjectURL(t),r=document.createElement(`a`);r.href=n,r.download=`erd_layout_${new Date().getTime()}.json`,r.click(),$.classList.add(`hidden`)}),document.getElementById(`export-db-sql-btn`)?.addEventListener(`click`,()=>{window.open(`/api/database/export`,`_blank`),$.classList.add(`hidden`)})}window.AppState={currentTable:null,currentTab:`data-btn`,currentTableBtnElement:null,dbType:null},i().then(e=>{if(e&&e.success&&e.data&&(window.AppState.dbType=e.data.dbType,e.data.dbName)){let t=document.getElementById(`db-name`);t&&(t.textContent=e.data.dbName)}}),window.TableStates={},window.ViewCache={},window.updateSidebarDirtyState=function(){document.querySelectorAll(`.table-btn`).forEach(e=>{let t=e.dataset.table,n=e.querySelector(`span`).textContent,r=t||n.replace(/\s*\*$/,``),i=window.TableStates[r],a=!1;if(i){if(i.dataGrid){let e=i.dataGrid;(Object.keys(e.pendingEdits||{}).length>0||e.pendingInserts&&e.pendingInserts.some(e=>Object.keys(e).length>0)||e.pendingDeletes&&e.pendingDeletes.size>0)&&(a=!0)}if(i.schemaGrid){let e=i.schemaGrid,t=e.pendingIndexEdits&&(e.pendingIndexEdits.added.length>0||e.pendingIndexEdits.dropped.length>0);(Object.keys(e.pendingEdits||{}).length>0||e.pendingInserts&&e.pendingInserts.some(e=>Object.keys(e).length>0)||e.pendingDeletes&&e.pendingDeletes.size>0||t)&&(a=!0)}}let o=e.querySelector(`span`),s=o.textContent.replace(/\s*\*$/,``);a?(o.textContent=s+` *`,o.style.fontWeight=`bold`):(o.textContent=s,o.style.fontWeight=`normal`)})},window.handleSwitchTab=function(e){document.querySelectorAll(`.tab-btn`).forEach(e=>e.classList.remove(`isCurrentTab`));let t=document.getElementById(e);if(t&&t.classList.add(`isCurrentTab`),window.AppState.currentTab=e,e===`erd-btn`||e===`sql-btn`||e===`status-btn`)window.AppState.currentTable=null,window.AppState.currentTableBtnElement=null,document.querySelectorAll(`.table-btn`).forEach(e=>e.classList.remove(`active`));else if((e===`data-btn`||e===`schema-btn`)&&!window.AppState.currentTable){let e=document.querySelector(`.table-btn`);e&&(window.AppState.currentTable=e.dataset.table||e.querySelector(`span`).textContent.replace(/\s*\*$/,``),window.AppState.currentTableBtnElement=e,e.classList.add(`active`))}window.renderCurrentView()},window.renderEmptyState=function(e){e.innerHTML=`
490
- <div class="empty-state">
491
- <div class="icon-container">
492
- <span class="material-symbols-outlined">database</span>
493
- </div>
494
- <h2>No Table Selected</h2>
495
- <p>Select a table from the sidebar to view its data, schema, or run SQL queries.</p>
496
- </div>
497
- `},window.renderCurrentView=function(e=``,t=!1){let n=[`erd-btn`,`sql-btn`,`status-btn`].includes(window.AppState.currentTab),r=document.getElementById(`main-content`);document.querySelectorAll(`.view-container`).forEach(e=>e.style.display=`none`);let i=n?`view-${window.AppState.currentTab}`:`view-${window.AppState.currentTab}-${window.AppState.currentTable}`,a=document.getElementById(i);if(a||(a=document.createElement(`div`),a.id=i,a.className=`view-container`,a.style.width=`100%`,a.style.flex=`1`,a.style.display=`flex`,a.style.flexDirection=`column`,a.style.overflow=`hidden`,r.appendChild(a)),a.style.display=`flex`,!window.AppState.currentTable&&!n){window.renderEmptyState(a);return}let o=window.AppState.currentTable;o&&!window.TableStates[o]&&(window.TableStates[o]={dataGrid:null,schemaGrid:null}),window.AppState.currentTab===`data-btn`?(window.TableStates[o].dataGrid&&(window.DataGrid=window.TableStates[o].dataGrid),(!window.TableStates[o].dataGrid||!a.hasChildNodes())&&S(o,window.AppState.currentTableBtnElement,e,t,a)):window.AppState.currentTab===`schema-btn`?(window.TableStates[o].schemaGrid&&(window.SchemaGrid=window.TableStates[o].schemaGrid),(!window.TableStates[o].schemaGrid||!a.hasChildNodes())&&T(o,window.AppState.currentTableBtnElement,a)):window.AppState.currentTab===`sql-btn`?a.hasChildNodes()||ce(o,window.AppState.currentTableBtnElement,a):window.AppState.currentTab===`erd-btn`?a.hasChildNodes()||G(a):window.AppState.currentTab===`status-btn`&&(a.hasChildNodes()?Ce():we(a)),document.querySelectorAll(`.table-btn`).forEach(e=>e.classList.remove(`active`)),window.AppState.currentTableBtnElement&&window.AppState.currentTableBtnElement.classList.add(`active`)},window.saveDataGridEdits=m,window.saveSchemaEdits=ee,document.addEventListener(`DOMContentLoaded`,()=>{u(),Ee(),De(),Oe()});