simplemdg-dev-cli 2.4.5 → 2.6.0
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.
- package/README.md +33 -0
- package/USER_GUIDE.md +57 -0
- package/dist/commands/cache.command.d.ts +2 -0
- package/dist/commands/cache.command.js +129 -0
- package/dist/commands/cache.command.js.map +1 -0
- package/dist/commands/cf.command.js +201 -122
- package/dist/commands/cf.command.js.map +1 -1
- package/dist/commands/gitlab.command.js +33 -23
- package/dist/commands/gitlab.command.js.map +1 -1
- package/dist/core/cache/smart-cache-events.d.ts +3 -0
- package/dist/core/cache/smart-cache-events.js +20 -0
- package/dist/core/cache/smart-cache-events.js.map +1 -0
- package/dist/core/cache/smart-cache-manager.d.ts +20 -0
- package/dist/core/cache/smart-cache-manager.js +148 -0
- package/dist/core/cache/smart-cache-manager.js.map +1 -0
- package/dist/core/cache/smart-cache-store.d.ts +8 -0
- package/dist/core/cache/smart-cache-store.js +74 -0
- package/dist/core/cache/smart-cache-store.js.map +1 -0
- package/dist/core/cache/smart-cache.d.ts +18 -0
- package/dist/core/cache/smart-cache.js +117 -0
- package/dist/core/cache/smart-cache.js.map +1 -0
- package/dist/core/cache/smart-cache.types.d.ts +62 -0
- package/dist/core/cache/smart-cache.types.js +17 -0
- package/dist/core/cache/smart-cache.types.js.map +1 -0
- package/dist/core/cf/cf-target-cache.d.ts +7 -0
- package/dist/core/cf/cf-target-cache.js +58 -0
- package/dist/core/cf/cf-target-cache.js.map +1 -0
- package/dist/core/cf/cf-target.types.d.ts +11 -0
- package/dist/core/cf/cf-target.types.js +11 -0
- package/dist/core/cf/cf-target.types.js.map +1 -0
- package/dist/core/db/db-studio-client.d.ts +1 -1
- package/dist/core/db/db-studio-client.js +173 -44
- package/dist/core/db/db-studio-client.js.map +1 -1
- package/dist/core/db/db-studio-server.js +125 -0
- package/dist/core/db/db-studio-server.js.map +1 -1
- package/dist/core/db/db-studio-styles.d.ts +1 -1
- package/dist/core/db/db-studio-styles.js +36 -0
- package/dist/core/db/db-studio-styles.js.map +1 -1
- package/dist/core/db/db-types.d.ts +54 -0
- package/dist/core/db/studio/sql-formatter.d.ts +25 -0
- package/dist/core/db/studio/sql-formatter.js +139 -0
- package/dist/core/db/studio/sql-formatter.js.map +1 -0
- package/dist/core/db/studio/studio-settings.d.ts +4 -0
- package/dist/core/db/studio/studio-settings.js +39 -0
- package/dist/core/db/studio/studio-settings.js.map +1 -0
- package/dist/core/db/studio/workspace-cache.d.ts +3 -0
- package/dist/core/db/studio/workspace-cache.js +51 -0
- package/dist/core/db/studio/workspace-cache.js.map +1 -0
- package/dist/index.js +3 -1
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/src/commands/cache.command.ts +159 -0
- package/src/commands/cf.command.ts +232 -129
- package/src/commands/gitlab.command.ts +37 -21
- package/src/core/cache/smart-cache-events.ts +20 -0
- package/src/core/cache/smart-cache-manager.ts +169 -0
- package/src/core/cache/smart-cache-store.ts +83 -0
- package/src/core/cache/smart-cache.ts +97 -0
- package/src/core/cache/smart-cache.types.ts +79 -0
- package/src/core/cf/cf-target-cache.ts +61 -0
- package/src/core/cf/cf-target.types.ts +17 -0
- package/src/core/db/db-studio-client.ts +173 -44
- package/src/core/db/db-studio-server.ts +109 -1
- package/src/core/db/db-studio-styles.ts +36 -0
- package/src/core/db/db-types.ts +61 -0
- package/src/core/db/studio/sql-formatter.ts +139 -0
- package/src/core/db/studio/studio-settings.ts +36 -0
- package/src/core/db/studio/workspace-cache.ts +51 -0
- package/src/index.ts +3 -1
|
@@ -36,6 +36,8 @@ function $(id){return document.getElementById(id);}
|
|
|
36
36
|
function el(tag,attrs,kids){var n=document.createElement(tag);if(attrs)for(var k in attrs){var v=attrs[k];if(v==null)continue;if(k==="class")n.className=v;else if(k==="text")n.textContent=v;else if(k==="html")n.innerHTML=v;else if(k.slice(0,2)==="on"&&typeof v==="function")n.addEventListener(k.slice(2),v);else n.setAttribute(k,v);}if(kids!=null){(Array.isArray(kids)?kids:[kids]).forEach(function(c){if(c==null)return;n.appendChild(typeof c==="string"||typeof c==="number"?document.createTextNode(String(c)):c);});}return n;}
|
|
37
37
|
function clear(n){while(n&&n.firstChild)n.removeChild(n.firstChild);return n;}
|
|
38
38
|
function esc(v){return String(v==null?"":v).replace(/[&<>"']/g,function(s){return {"&":"&","<":"<",">":">","\\"":""","'":"'"}[s];});}
|
|
39
|
+
function highlightMatch(text,search){var t=String(text==null?"":text);var s=String(search==null?"":search).trim();if(!s)return esc(t);var lt=t.toLowerCase(),ls=s.toLowerCase(),out="",i=0,idx;while((idx=lt.indexOf(ls,i))>=0){out+=esc(t.slice(i,idx))+'<mark class="hl">'+esc(t.slice(idx,idx+s.length))+'</mark>';i=idx+s.length;}out+=esc(t.slice(i));return out;}
|
|
40
|
+
function wireSearch(input,onRun,onClear){input.addEventListener("keydown",function(e){if(e.key==="Enter"){e.preventDefault();onRun();}else if(e.key==="Escape"){e.preventDefault();input.value="";if(onClear)onClear();else onRun();}});}
|
|
39
41
|
function debounce(fn,ms){var t;return function(){var a=arguments,c=this;clearTimeout(t);t=setTimeout(function(){fn.apply(c,a);},ms||220);};}
|
|
40
42
|
function topSpin(on){$("topSpin").className=on?"spin":"spin hidden";}
|
|
41
43
|
|
|
@@ -50,7 +52,7 @@ function setConnStatus(text,kind){$("stConn").innerHTML="";$("stConn").appendChi
|
|
|
50
52
|
function setRun(on){$("stConn").firstChild.className="st-dot "+(on?"run":"ok");}
|
|
51
53
|
|
|
52
54
|
/* ---------- global state ---------- */
|
|
53
|
-
var S = { connections:[], activeConnId:"", connType:"", activeSchema:"", readOnly:RO_DEFAULT, tabs:[], activeTabId:"", seq:0, savedQueries:[] };
|
|
55
|
+
var S = { connections:[], activeConnId:"", connType:"", activeSchema:"", readOnly:RO_DEFAULT, tabs:[], activeTabId:"", seq:0, savedQueries:[], settings:{ restoreWorkspace:true, defaultRowLimit:100, defaultSchema:"", readOnlyByDefault:RO_DEFAULT, queryTimeoutMs:30000, autoFormatGeneratedSql:true, autoSaveDelayMs:500, maxHistoryItems:300, showProductionWarning:true, theme:"dark" } };
|
|
54
56
|
function activeConn(){return S.connections.filter(function(c){return c.id===S.activeConnId;})[0];}
|
|
55
57
|
|
|
56
58
|
/* ====================================================================
|
|
@@ -71,10 +73,10 @@ function closeModal(){$("modalRoot").classList.add("hidden");clear($("modalRoot"
|
|
|
71
73
|
CONNECTIONS
|
|
72
74
|
==================================================================== */
|
|
73
75
|
function loadConnections(){var box=$("connList");box.innerHTML='<div class="skel"></div><div class="skel"></div>';return api("GET","/api/connections").then(function(r){S.connections=r.connections||[];renderConnections();}).catch(function(e){box.innerHTML='<div class="empty">'+esc(e.message)+'</div>';});}
|
|
74
|
-
function renderConnections(){var
|
|
75
|
-
function connCard(c){var color=c.color||ENV_COLORS[c.environment]||"#64748b";var card=el("div",{class:"conn-card"+(c.id===S.activeConnId?" active":""),style:"border-left-color:"+color,oncontextmenu:function(e){e.preventDefault();connMenu(e,c);}});card.addEventListener("click",function(){activateConnection(c.id);});
|
|
76
|
+
function renderConnections(){var raw=($("connSearch").value||"");var q=raw.toLowerCase();var box=clear($("connList"));var rows=S.connections.filter(function(c){return (c.name+" "+c.type+" "+(c.org||"")+" "+(c.app||"")+" "+(c.environment||"")).toLowerCase().indexOf(q)>=0;});rows.sort(function(a,b){return (b.isFavorite?1:0)-(a.isFavorite?1:0);});if(!rows.length){box.appendChild(el("div",{class:"empty",text:S.connections.length?"No results found":"No connections yet. Click + New or Import."}));return;}rows.forEach(function(c){box.appendChild(connCard(c,raw));});}
|
|
77
|
+
function connCard(c,q){var color=c.color||ENV_COLORS[c.environment]||"#64748b";var card=el("div",{class:"conn-card"+(c.id===S.activeConnId?" active":""),style:"border-left-color:"+color,oncontextmenu:function(e){e.preventDefault();connMenu(e,c);}});card.addEventListener("click",function(){activateConnection(c.id);});
|
|
76
78
|
var star=el("span",{class:"star"+(c.isFavorite?" on":""),title:"Favorite",onclick:function(e){e.stopPropagation();toggleFavorite(c);}});star.innerHTML=svgFor("star");
|
|
77
|
-
card.appendChild(el("div",{class:"conn-top"},[icEl("db","db"),el("span",{class:"conn-name",
|
|
79
|
+
card.appendChild(el("div",{class:"conn-top"},[icEl("db","db"),el("span",{class:"conn-name",html:highlightMatch(c.name,q),title:c.name}),star]));
|
|
78
80
|
var sub=[c.org,c.space].filter(Boolean).join(" / ")||c.host;
|
|
79
81
|
card.appendChild(el("div",{class:"conn-sub",text:sub,title:sub}));
|
|
80
82
|
var tags=el("div",{class:"conn-tags"});
|
|
@@ -110,7 +112,7 @@ function editConnModal(c){var sel={color:c.color||"",env:c.environment||""};var
|
|
|
110
112
|
==================================================================== */
|
|
111
113
|
function treeNode(opts){
|
|
112
114
|
var chev=el("span",{class:"tchev"+(opts.leaf?" leaf":""),html:"\\u203a"});
|
|
113
|
-
var label=el("span",{class:"tlabel",
|
|
115
|
+
var label=el("span",{class:"tlabel",title:opts.label});if(opts.labelHtml)label.innerHTML=opts.labelHtml;else label.textContent=opts.label;
|
|
114
116
|
var badge=el("span",{class:"tbadge"});
|
|
115
117
|
var spin=el("span",{class:"hidden"});
|
|
116
118
|
var row=el("div",{class:"trow"},[chev,icEl(opts.icon,opts.iconCls),label,badge,spin]);
|
|
@@ -150,11 +152,11 @@ function folderNode(schema,label,kind,iconCls){return treeNode({label:label,icon
|
|
|
150
152
|
var search=el("input",{class:"input",placeholder:"Search "+label.toLowerCase()+"..."});
|
|
151
153
|
var sb=el("div",{class:"searchbox tsearch"},[el("span",{html:svgFor("search")}),search]);
|
|
152
154
|
kids.appendChild(sb);kids.appendChild(listBox);
|
|
153
|
-
var run=function(){var sp=el("span",{class:"spin"});clear(listBox).appendChild(el("div",{class:"tnote"},[sp," loading..."]));api("GET","/api/catalog/objects?"+qstr({connectionId:S.activeConnId,schema:schema,kinds:kind,search:
|
|
154
|
-
search.addEventListener("input",debounce(run,250));
|
|
155
|
+
var run=function(){var sp=el("span",{class:"spin"});clear(listBox).appendChild(el("div",{class:"tnote"},[sp," loading..."]));var q=search.value||"";api("GET","/api/catalog/objects?"+qstr({connectionId:S.activeConnId,schema:schema,kinds:kind,search:q})).then(function(r){var objs=r.objects||[];setBadge(objs.length);clear(listBox);if(!objs.length){listBox.appendChild(el("div",{class:"tnote",text:q?"No results found":"None."}));return;}objs.forEach(function(o){listBox.appendChild(objectNode(schema,o,iconCls,q));});}).catch(function(e){clear(listBox).appendChild(el("div",{class:"tnote",text:e.message}));});};
|
|
156
|
+
search.addEventListener("input",debounce(run,250));wireSearch(search,run);
|
|
155
157
|
run();
|
|
156
158
|
}});}
|
|
157
|
-
function objectNode(schema,o,iconCls){var canData=o.kind==="table"||o.kind==="view"||o.kind==="column-view";return treeNode({label:o.name,icon:iconCls,iconCls:iconCls,leaf:true,
|
|
159
|
+
function objectNode(schema,o,iconCls,q){var canData=o.kind==="table"||o.kind==="view"||o.kind==="column-view";return treeNode({label:o.name,labelHtml:highlightMatch(o.name,q),icon:iconCls,iconCls:iconCls,leaf:true,
|
|
158
160
|
onClick:function(){selectTreeRow(this);},
|
|
159
161
|
onDblClick:canData?function(){openDataTab(schema,o.name);}:null,
|
|
160
162
|
onMenu:canData?function(e){objectMenu(e,schema,o);}:function(e){objectMenu(e,schema,o,true);}
|
|
@@ -163,19 +165,64 @@ var _selRow=null;
|
|
|
163
165
|
function selectTreeRow(node){if(_selRow)_selRow._row.classList.remove("sel");_selRow=node;node._row.classList.add("sel");}
|
|
164
166
|
function objectMenu(e,schema,o,limited){var qn='"'+schema+'"."'+o.name+'"';var items=[];if(!limited){items.push({label:"Open Data",icon:"table2",onClick:function(){openDataTab(schema,o.name);}});items.push({label:"Open Structure",icon:"col",onClick:function(){openStructureTab(schema,o.name);}});items.push({sep:true});items.push({label:"Generate SELECT",icon:"sql",onClick:function(){api("POST","/api/table/sql",{connectionId:S.activeConnId,schema:schema,table:o.name,limit:100}).then(function(r){openSqlTab(r.select,o.name);});}});items.push({label:"Generate COUNT",icon:"sql",onClick:function(){api("POST","/api/table/sql",{connectionId:S.activeConnId,schema:schema,table:o.name}).then(function(r){openSqlTab(r.count,o.name);});}});}
|
|
165
167
|
items.push({label:"Copy Full Name",icon:"col",onClick:function(){navigator.clipboard.writeText(qn);logMsg("Copied "+qn,"ok");}});
|
|
168
|
+
items.push({label:"Copy Name",icon:"col",onClick:function(){navigator.clipboard.writeText(o.name);logMsg("Copied "+o.name,"ok");}});
|
|
169
|
+
if(!limited){items.push({sep:true});
|
|
170
|
+
items.push({label:"Copy SELECT",icon:"sql",onClick:function(){api("POST","/api/table/generate-sql",{connectionId:S.activeConnId,schema:schema,table:o.name,limit:100}).then(function(r){navigator.clipboard.writeText(r.select);logMsg("Copied SELECT","ok");}).catch(function(er){logMsg(er.message,"err");});}});
|
|
171
|
+
items.push({label:"Copy INSERT template",icon:"sql",onClick:function(){api("POST","/api/table/generate-sql",{connectionId:S.activeConnId,schema:schema,table:o.name}).then(function(r){navigator.clipboard.writeText(r.insert);logMsg("Copied INSERT template","ok");}).catch(function(er){logMsg(er.message,"err");});}});
|
|
172
|
+
items.push({label:"Copy UPDATE template",icon:"sql",onClick:function(){api("POST","/api/table/generate-sql",{connectionId:S.activeConnId,schema:schema,table:o.name}).then(function(r){navigator.clipboard.writeText(r.update);logMsg("Copied UPDATE template","ok");}).catch(function(er){logMsg(er.message,"err");});}});
|
|
173
|
+
}
|
|
166
174
|
showCtx(e.clientX,e.clientY,items);}
|
|
167
175
|
|
|
168
176
|
/* ====================================================================
|
|
169
177
|
WORKSPACE TABS
|
|
170
178
|
==================================================================== */
|
|
171
|
-
|
|
172
|
-
function
|
|
173
|
-
function
|
|
179
|
+
var _dragTabId=null;
|
|
180
|
+
function orderedTabs(){return S.tabs.slice().sort(function(a,b){return (b.pinned?1:0)-(a.pinned?1:0);});}
|
|
181
|
+
function renderTabBar(){var bar=clear($("tabbar"));orderedTabs().forEach(function(tab){var chip=el("div",{class:"wtab"+(tab.id===S.activeTabId?" active":"")+(tab.pinned?" pinned":""),draggable:"true"});chip.addEventListener("click",function(){switchTab(tab.id);});chip.addEventListener("contextmenu",function(e){e.preventDefault();tabMenu(e,tab);});
|
|
182
|
+
chip.addEventListener("dragstart",function(e){_dragTabId=tab.id;chip.classList.add("dragging");if(e.dataTransfer)e.dataTransfer.effectAllowed="move";});
|
|
183
|
+
chip.addEventListener("dragend",function(){chip.classList.remove("dragging");Array.prototype.forEach.call(bar.children,function(x){x.classList.remove("dragover");});});
|
|
184
|
+
chip.addEventListener("dragover",function(e){e.preventDefault();chip.classList.add("dragover");});
|
|
185
|
+
chip.addEventListener("dragleave",function(){chip.classList.remove("dragover");});
|
|
186
|
+
chip.addEventListener("drop",function(e){e.preventDefault();chip.classList.remove("dragover");if(_dragTabId&&_dragTabId!==tab.id)reorderTab(_dragTabId,tab.id);});
|
|
187
|
+
chip.appendChild(el("span",{class:"t-ico"+(tab.pinned?" pin":""),html:svgFor(tab.pinned?"star":(tab.icon||"sql"))}));
|
|
188
|
+
chip.appendChild(el("span",{class:"t-title",text:tab.title,title:tab.title}));
|
|
189
|
+
if(tab.dirty)chip.appendChild(el("span",{class:"dot"}));
|
|
190
|
+
if(tab.closable!==false)chip.appendChild(el("span",{class:"x",html:svgFor("x"),onclick:function(e){e.stopPropagation();closeTab(tab.id);}}));
|
|
191
|
+
bar.appendChild(chip);});}
|
|
192
|
+
function reorderTab(srcId,targetId){var src=tabById(srcId);var ti=-1;for(var i=0;i<S.tabs.length;i++)if(S.tabs[i].id===targetId)ti=i;if(!src||ti<0)return;S.tabs=S.tabs.filter(function(t){return t.id!==srcId;});var idx=-1;for(var j=0;j<S.tabs.length;j++)if(S.tabs[j].id===targetId)idx=j;S.tabs.splice(idx,0,src);renderTabBar();scheduleWorkspaceSave();}
|
|
193
|
+
function tabMenu(e,tab){showCtx(e.clientX,e.clientY,[
|
|
194
|
+
{label:"Close",icon:"x",onClick:function(){closeTab(tab.id);}},
|
|
195
|
+
{label:"Close Others",icon:"x",onClick:function(){closeOtherTabs(tab.id);}},
|
|
196
|
+
{label:"Close Tabs to the Right",icon:"x",onClick:function(){closeTabsToRight(tab.id);}},
|
|
197
|
+
{sep:true},
|
|
198
|
+
{label:tab.pinned?"Unpin Tab":"Pin Tab",icon:"star",onClick:function(){tab.pinned=!tab.pinned;renderTabBar();scheduleWorkspaceSave();}},
|
|
199
|
+
{label:"Rename Tab",icon:"gear",onClick:function(){var n=prompt("Tab name",tab.title);if(n){tab.title=n;renderTabBar();scheduleWorkspaceSave();}}},
|
|
200
|
+
{label:"Duplicate Tab",icon:"plus",onClick:function(){duplicateTab(tab);}}
|
|
201
|
+
]);}
|
|
202
|
+
function duplicateTab(tab){if(tab.kind==="sql"&&tab.state.editor)openSqlTab(tab.state.editor.value,tab.title);else if(tab.kind==="data"&&tab.meta)openDataTab(tab.meta.schema,tab.meta.table);else if(tab.kind==="structure"&&tab.meta)openStructureTab(tab.meta.schema,tab.meta.table);}
|
|
203
|
+
function closeOtherTabs(keepId){var others=S.tabs.filter(function(t){return t.id!==keepId&&t.closable!==false;});if(others.some(function(t){return t.dirty;})&&!confirm("Close other tabs? Unsaved changes will be lost."))return;others.forEach(function(t){t.el.remove();});S.tabs=S.tabs.filter(function(t){return t.id===keepId||t.closable===false;});switchTab(keepId);renderTabBar();scheduleWorkspaceSave();}
|
|
204
|
+
function closeTabsToRight(fromId){var ord=orderedTabs();var i=0;for(var k=0;k<ord.length;k++)if(ord[k].id===fromId)i=k;var toClose=ord.slice(i+1).filter(function(t){return t.closable!==false;});if(toClose.some(function(t){return t.dirty;})&&!confirm("Close tabs to the right? Unsaved changes will be lost."))return;var ids={};toClose.forEach(function(t){ids[t.id]=1;t.el.remove();});S.tabs=S.tabs.filter(function(t){return !ids[t.id];});if(ids[S.activeTabId])switchTab(fromId);renderTabBar();scheduleWorkspaceSave();}
|
|
205
|
+
function nextTab(dir){var ord=orderedTabs();if(ord.length<2)return;var i=0;for(var k=0;k<ord.length;k++)if(ord[k].id===S.activeTabId)i=k;var ni=(i+dir+ord.length)%ord.length;switchTab(ord[ni].id);}
|
|
206
|
+
function openTab(spec){var ex=S.tabs.filter(function(t){return t.key===spec.key;})[0];if(ex){switchTab(ex.id);return ex;}var id=spec.restoreId||("wt"+(++S.seq));var pane=el("div",{class:"tabpane hidden"});$("tabcontent").appendChild(pane);var now=new Date().toISOString();var tab={id:id,key:spec.key,kind:spec.kind,title:spec.title,icon:spec.icon,dirty:false,closable:spec.closable!==false,el:pane,state:{},connectionId:spec.connectionId||"",meta:spec.meta||null,pinned:!!spec.pinned,openedAt:now};S.tabs.push(tab);spec.build(pane,tab);renderTabBar();switchTab(id);scheduleWorkspaceSave();return tab;}
|
|
207
|
+
function switchTab(id){S.activeTabId=id;S.tabs.forEach(function(t){t.el.classList.toggle("hidden",t.id!==id);});renderTabBar();var tab=tabById(id);if(tab&&tab.onShow)tab.onShow();updatePendingStatus();scheduleWorkspaceSave();}
|
|
174
208
|
function tabById(id){return S.tabs.filter(function(t){return t.id===id;})[0];}
|
|
175
209
|
function setDirty(tab,on){tab.dirty=on;renderTabBar();updatePendingStatus();}
|
|
176
|
-
function closeTab(id){var tab=tabById(id);if(!tab)return;if(tab.dirty&&!confirm("'"+tab.title+"' has unsaved changes. Close anyway?"))return;tab.el.remove();var idx=S.tabs.indexOf(tab);S.tabs=S.tabs.filter(function(t){return t.id!==id;});if(S.activeTabId===id){var next=S.tabs[Math.max(0,idx-1)];if(next)switchTab(next.id);else openWelcome();}renderTabBar();}
|
|
210
|
+
function closeTab(id){var tab=tabById(id);if(!tab)return;if(tab.dirty&&!confirm("'"+tab.title+"' has unsaved changes. Close anyway?"))return;tab.el.remove();var idx=S.tabs.indexOf(tab);S.tabs=S.tabs.filter(function(t){return t.id!==id;});if(S.activeTabId===id){var next=S.tabs[Math.max(0,idx-1)];if(next)switchTab(next.id);else openWelcome();}renderTabBar();scheduleWorkspaceSave();}
|
|
177
211
|
function updatePendingStatus(){var tab=tabById(S.activeTabId);var n=tab&&tab.state&&tab.state.g?pendingCount(tab.state.g):0;$("stPending").textContent=n>0?(n+" pending change"+(n>1?"s":"")):"";$("stPending").className=n>0?"st-item st-pending":"st-item";}
|
|
178
212
|
|
|
213
|
+
/* ---- workspace persistence ---- */
|
|
214
|
+
function kindToType(k){return k==="data"?"data-grid":k==="structure"?"metadata":k;}
|
|
215
|
+
function serializeWorkspace(){var tabs=S.tabs.filter(function(t){return t.kind!=="welcome";}).map(function(t){var st={id:t.id,type:kindToType(t.kind),title:t.title,pinned:!!t.pinned,dirty:!!t.dirty,connectionId:t.connectionId||undefined,openedAt:t.openedAt||new Date().toISOString(),updatedAt:new Date().toISOString()};if(t.meta){st.schema=t.meta.schema;st.objectName=t.meta.table;st.objectType=t.meta.objectType;}if(t.kind==="sql"&&t.state.editor)st.sql=t.state.editor.value;if(t.kind==="data"&&t.state.g){var g=t.state.g;st.filter=g.whereI.value;st.pageSize=parseInt(g.pageSel.value,10);st.pageIndex=g.offset;st.sort=g.orderBy?[{column:g.orderBy,direction:g.orderDir}]:[];}return st;});return {version:1,activeTabId:S.activeTabId,tabs:tabs,tabGroups:[],layout:{readOnly:S.readOnly,sidebarWidth:$("sidebar").offsetWidth},updatedAt:new Date().toISOString()};}
|
|
216
|
+
var _wsTimer=null;
|
|
217
|
+
function scheduleWorkspaceSave(){if(_wsTimer)clearTimeout(_wsTimer);_wsTimer=setTimeout(function(){api("PUT","/api/studio/workspace",serializeWorkspace()).catch(function(){});},Math.max(400,S.settings.autoSaveDelayMs||500));}
|
|
218
|
+
function loadSettings(){return api("GET","/api/studio/settings").then(function(r){if(r.settings)S.settings=r.settings;}).catch(function(){});}
|
|
219
|
+
function restoreWorkspace(){if(!S.settings.restoreWorkspace)return Promise.resolve();return api("GET","/api/studio/workspace").then(function(r){var ws=r.workspace;if(!ws||!ws.tabs||!ws.tabs.length)return;var active=null;ws.tabs.forEach(function(st){try{
|
|
220
|
+
if(st.type==="sql"){if(st.connectionId){var c=byId(st.connectionId);if(c){S.activeConnId=c.id;S.connType=c.type;}}var t=openSqlTab(st.sql||"",null);t.title=st.title;t.pinned=!!st.pinned;if(st.id===ws.activeTabId)active=t.id;}
|
|
221
|
+
else if(st.type==="data-grid"){var cd=byId(st.connectionId);if(!cd){logMsg("Tab '"+st.title+"' not restored: connection removed.","warn");return;}S.activeConnId=cd.id;S.connType=cd.type;var dt=openDataTab(st.schema,st.objectName,{where:st.filter,pageSize:st.pageSize,sort:st.sort,offset:st.pageIndex});dt.pinned=!!st.pinned;if(st.id===ws.activeTabId)active=dt.id;}
|
|
222
|
+
else if(st.type==="metadata"){var cm=byId(st.connectionId);if(!cm)return;S.activeConnId=cm.id;S.connType=cm.type;var mt=openStructureTab(st.schema,st.objectName);mt.pinned=!!st.pinned;if(st.id===ws.activeTabId)active=mt.id;}
|
|
223
|
+
}catch(e){}});updateTopBadges();renderTabBar();if(active)switchTab(active);logMsg("Workspace restored ("+ws.tabs.length+" tab"+(ws.tabs.length>1?"s":"")+").","ok");}).catch(function(){});}
|
|
224
|
+
function byId(id){return S.connections.filter(function(c){return c.id===id;})[0];}
|
|
225
|
+
|
|
179
226
|
/* ====================================================================
|
|
180
227
|
WELCOME
|
|
181
228
|
==================================================================== */
|
|
@@ -199,20 +246,29 @@ function wcard(icon,title,desc,onClick){return el("div",{class:"wcard",onclick:o
|
|
|
199
246
|
SQL CONSOLE TAB
|
|
200
247
|
==================================================================== */
|
|
201
248
|
var DANGER=/\\b(drop|truncate|alter|grant|revoke)\\b/i;
|
|
202
|
-
function openSqlTab(sql,nameHint){var title="SQL"+(nameHint?": "+nameHint:" Console");openTab({key:"sql:"+(++S.seq),kind:"sql",title:title,icon:"sql",build:function(pane,tab){buildSqlPane(pane,tab,sql
|
|
249
|
+
function openSqlTab(sql,nameHint,queryId){var title="SQL"+(nameHint?": "+nameHint:" Console");return openTab({key:"sql:"+(++S.seq),kind:"sql",title:title,icon:"sql",connectionId:S.activeConnId,meta:{queryId:queryId||null},build:function(pane,tab){tab.connectionId=S.activeConnId;buildSqlPane(pane,tab,sql!=null?sql:"select * from DUMMY");}});}
|
|
203
250
|
function buildSqlPane(pane,tab,initialSql){
|
|
204
251
|
var editor=el("textarea",{class:"editor",spellcheck:"false"});editor.value=initialSql;tab.state.editor=editor;
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
252
|
+
var gutter=el("div",{class:"gutter",text:"1"});
|
|
253
|
+
function syncGutter(){var lines=editor.value.split("\\n").length;var s="";for(var i=1;i<=lines;i++)s+=i+"\\n";gutter.textContent=s;gutter.scrollTop=editor.scrollTop;}
|
|
254
|
+
tab.state.syncGutter=syncGutter;
|
|
255
|
+
editor.addEventListener("input",function(){setDirty(tab,true);syncGutter();scheduleWorkspaceSave();});
|
|
256
|
+
editor.addEventListener("scroll",function(){gutter.scrollTop=editor.scrollTop;});
|
|
257
|
+
editor.addEventListener("keydown",function(e){if((e.ctrlKey||e.metaKey)&&e.key==="Enter"){e.preventDefault();runMode(tab,"selected");}else if(e.key==="F5"){e.preventDefault();runMode(tab,"all");}else if((e.ctrlKey||e.metaKey)&&(e.key==="s"||e.key==="S")){e.preventDefault();saveQueryTab(tab);}});
|
|
258
|
+
var editwrap=el("div",{class:"editwrap"},[gutter,editor]);
|
|
259
|
+
var limitSel=el("select",{class:"select",style:"width:auto"});["100","500","1000","5000","0"].forEach(function(v){limitSel.appendChild(el("option",{value:v,text:v==="0"?"No limit":v}));});limitSel.value=String(S.settings.defaultRowLimit||100);tab.state.limit=limitSel;
|
|
260
|
+
var runBtn=el("button",{class:"btn",onclick:function(){runMode(tab,"selected");}},[el("span",{html:svgFor("run")})," Run"]);tab.state.runBtn=runBtn;
|
|
261
|
+
var runMenu=el("button",{class:"btn",style:"padding:6px 7px",html:"\\u25be",title:"Run options",onclick:function(e){showCtx(e.clientX,e.clientY,[{label:"Run Selected (Ctrl+Enter)",icon:"run",onClick:function(){runMode(tab,"selected");}},{label:"Run Current Statement",icon:"run",onClick:function(){runMode(tab,"current");}},{label:"Run All (F5)",icon:"run",onClick:function(){runMode(tab,"all");}},{label:"Explain",icon:"sql",onClick:function(){runMode(tab,"explain");}}]);}});
|
|
262
|
+
var tb=el("div",{class:"toolbar"},[runBtn,runMenu,el("button",{class:"btn sec",text:"Format",onclick:function(){api("POST","/api/sql/format",{sql:editor.value}).then(function(r){setEditorValue(tab,r.sql);}).catch(function(){setEditorValue(tab,formatSql(editor.value));});}}),el("span",{class:"note",text:"Limit"}),limitSel,el("button",{class:"btn ghost",text:"Save",title:"Ctrl+S",onclick:function(){saveQueryTab(tab);}}),el("button",{class:"btn ghost",text:"CSV",onclick:function(){exportResult(tab,"csv");}}),el("button",{class:"btn ghost",text:"JSON",onclick:function(){exportResult(tab,"json");}}),el("span",{class:"grow"}),el("span",{class:"note",id:"sqlmeta_"+tab.id})]);
|
|
210
263
|
var body=el("div",{class:"pane-body"});var errBox=el("div",{class:"errbox hidden"});var grid=el("div",{class:"gridwrap"});tab.state.err=errBox;tab.state.grid=grid;
|
|
211
|
-
body.appendChild(
|
|
212
|
-
pane.appendChild(tb);pane.appendChild(body);
|
|
264
|
+
body.appendChild(editwrap);body.appendChild(errBox);body.appendChild(el("div",{class:"note",text:"Result"}));body.appendChild(grid);
|
|
265
|
+
pane.appendChild(tb);pane.appendChild(body);syncGutter();
|
|
213
266
|
}
|
|
214
|
-
function
|
|
215
|
-
function
|
|
267
|
+
function setEditorValue(tab,v){tab.state.editor.value=v;if(tab.state.syncGutter)tab.state.syncGutter();setDirty(tab,true);scheduleWorkspaceSave();}
|
|
268
|
+
function splitRangesClient(sql){var ranges=[],buf="",start=-1,inStr=false,q="",inLine=false,inBlock=false;function push(e){if(buf.trim())ranges.push({sql:buf.trim(),start:start,end:e});buf="";start=-1;}for(var i=0;i<sql.length;i++){var ch=sql[i],nx=sql[i+1];if(start===-1&&!/\\s/.test(ch))start=i;if(inLine){buf+=ch;if(ch==="\\n")inLine=false;continue;}if(inBlock){buf+=ch;if(ch==="*"&&nx==="/"){buf+=nx;i++;inBlock=false;}continue;}if(inStr){buf+=ch;if(ch===q)inStr=false;continue;}if(ch==="-"&&nx==="-"){inLine=true;buf+=ch;continue;}if(ch==="/"&&nx==="*"){inBlock=true;buf+=ch;continue;}if(ch==="'"||ch==='"'){inStr=true;q=ch;buf+=ch;continue;}if(ch===";"){push(i);continue;}buf+=ch;}push(sql.length);return ranges;}
|
|
269
|
+
function statementAtCursor(sql,off){var r=splitRangesClient(sql);for(var i=0;i<r.length;i++)if(off>=r[i].start&&off<=r[i].end+1)return r[i].sql;return (r[r.length-1]||{}).sql||sql.trim();}
|
|
270
|
+
function runMode(tab,mode){var ed=tab.state.editor;var hasSel=ed.selectionStart!=ed.selectionEnd;var sel=hasSel?ed.value.substring(ed.selectionStart,ed.selectionEnd).trim():"";var sql;if(mode==="all")sql=ed.value.trim();else if(mode==="current")sql=statementAtCursor(ed.value,ed.selectionStart);else if(mode==="explain"){if(S.connType!=="postgresql")return logMsg("Explain currently supports PostgreSQL.","warn");sql="EXPLAIN "+(sel||statementAtCursor(ed.value,ed.selectionStart));}else sql=sel||statementAtCursor(ed.value,ed.selectionStart);if(!sql)return logMsg("Nothing to run.","warn");execSql(tab,sql);}
|
|
271
|
+
function execSql(tab,sql,confirmed){if(!S.activeConnId)return logMsg("Select a connection first.","warn");
|
|
216
272
|
if(!confirmed&&DANGER.test(sql)){if(!confirm("This statement may modify or drop data:\\n\\n"+sql.slice(0,160)+"\\n\\nRun anyway?"))return;}
|
|
217
273
|
tab.state.err.classList.add("hidden");tab.state.runBtn.disabled=true;tab.state.runBtn.innerHTML="";tab.state.runBtn.appendChild(el("span",{class:"spin"}));tab.state.runBtn.appendChild(document.createTextNode(" Running..."));setRun(true);setConnStatus("Running query...","run");
|
|
218
274
|
var limit=parseInt(tab.state.limit.value,10);
|
|
@@ -225,34 +281,41 @@ function runSqlTab(tab,confirmed){var sql=currentSqlText(tab);if(!sql)return log
|
|
|
225
281
|
$("stDuration").textContent=r.result.durationMs+"ms";$("stRows").textContent=r.result.rowCount+" rows";
|
|
226
282
|
}).catch(function(e){tab.state.runBtn.innerHTML=svgFor("run")+" Run";tab.state.runBtn.disabled=false;setConnStatus("Connected","ok");tab.state.err.textContent=e.message;tab.state.err.classList.remove("hidden");});
|
|
227
283
|
}
|
|
228
|
-
function
|
|
229
|
-
function saveQueryTab(tab){var sql=tab.state.editor.value.trim();if(!sql)return logMsg("Nothing to save.","warn");var name=prompt("Query name","Query "+new Date().toLocaleString());if(!name)return;api("POST","/api/queries",{name:name,sql:sql,connectionId:S.activeConnId,connectionType:S.connType}).then(function(){setDirty(tab,false);loadSavedQueries();logMsg("Query saved.","ok");}).catch(function(e){logMsg(e.message,"err");});}
|
|
284
|
+
function saveQueryTab(tab){var sql=tab.state.editor.value.trim();if(!sql)return logMsg("Nothing to save.","warn");var qid=tab.meta&&tab.meta.queryId;if(qid){api("PUT","/api/queries/"+encodeURIComponent(qid),{name:tab.title.replace(/^SQL: ?/,""),sql:sql}).then(function(){setDirty(tab,false);loadSavedQueries();logMsg("Query updated.","ok");}).catch(function(e){logMsg(e.message,"err");});return;}var name=prompt("Save query as","Query "+new Date().toLocaleString());if(!name)return;api("POST","/api/queries",{name:name,sql:sql,connectionId:S.activeConnId,connectionType:S.connType}).then(function(r){if(tab.meta)tab.meta.queryId=r.query.id;tab.title="SQL: "+name;setDirty(tab,false);renderTabBar();loadSavedQueries();logMsg("Query saved.","ok");}).catch(function(e){logMsg(e.message,"err");});}
|
|
230
285
|
function exportResult(tab,fmt){var res=tab.state.lastResult;if(!res||!res.rows.length)return logMsg("No result to export.","warn");var fields=res.fields&&res.fields.length?res.fields:Object.keys(res.rows[0]);fetch(fmt==="csv"?"/api/export/csv":"/api/export/json",{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({fields:fields,rows:res.rows})}).then(function(r){return r.blob();}).then(function(b){var a=document.createElement("a");a.href=URL.createObjectURL(b);a.download=fmt==="csv"?"result.csv":"result.json";a.click();logMsg("Exported "+fmt.toUpperCase(),"ok");});}
|
|
231
286
|
function formatSql(sql){return sql.replace(/\\s+/g," ").replace(/\\b(select|from|where|and|or|order by|group by|having|limit|offset|inner join|left join|right join|join|on|union|values|set|insert into|update|delete from|create table|alter table)\\b/gi,function(m){return "\\n"+m.toUpperCase();}).trim();}
|
|
232
287
|
|
|
233
288
|
/* generic read-only result grid (sql console) */
|
|
234
|
-
function renderResultGrid(box,result,onSort){clear(box);if(!result||!result.rows||!result.rows.length){box.appendChild(el("div",{class:"empty",text:result&&result.affectedRows!=null?("Affected rows: "+result.affectedRows):"No rows."}));return;}var fields=result.fields&&result.fields.length?result.fields:Object.keys(result.rows[0]);var table=el("table",{class:"grid"});var thead=el("thead");var htr=el("tr");htr.appendChild(el("th",{class:"rowhdr",text:"#"}));fields.forEach(function(f){htr.appendChild(el("th",{text:f,title:f}));});thead.appendChild(htr);table.appendChild(thead);var tb=el("tbody");result.rows.forEach(function(row,ri){var tr=el("tr");tr.appendChild(el("td",{class:"rowhdr",text:ri+1}));fields.forEach(function(f){var v=row[f];var disp=v==null?"":typeof v==="object"?JSON.stringify(v):String(v);var td=el("td",{class:typeof v==="number"?"num":"",title:disp,text:disp.length>400?disp.slice(0,400)+"\\u2026":disp});td.addEventListener("dblclick",function(){
|
|
289
|
+
function renderResultGrid(box,result,onSort){clear(box);if(!result||!result.rows||!result.rows.length){box.appendChild(el("div",{class:"empty",text:result&&result.affectedRows!=null?("Affected rows: "+result.affectedRows):"No rows."}));return;}var fields=result.fields&&result.fields.length?result.fields:Object.keys(result.rows[0]);var table=el("table",{class:"grid"});var thead=el("thead");var htr=el("tr");htr.appendChild(el("th",{class:"rowhdr",text:"#"}));fields.forEach(function(f){htr.appendChild(el("th",{text:f,title:f}));});thead.appendChild(htr);table.appendChild(thead);var tb=el("tbody");result.rows.forEach(function(row,ri){var tr=el("tr");tr.appendChild(el("td",{class:"rowhdr",text:ri+1}));fields.forEach(function(f){var v=row[f];var disp=v==null?"":typeof v==="object"?JSON.stringify(v):String(v);var td=el("td",{class:typeof v==="number"?"num":"",title:disp,text:disp.length>400?disp.slice(0,400)+"\\u2026":disp});td.addEventListener("dblclick",function(){openCellViewer(v);});tr.appendChild(td);});tb.appendChild(tr);});table.appendChild(tb);box.appendChild(table);}
|
|
235
290
|
|
|
236
291
|
/* ====================================================================
|
|
237
292
|
DATA GRID TAB (editable, pending changes)
|
|
238
293
|
==================================================================== */
|
|
239
|
-
function openDataTab(schema,table){openTab({key:"data:"+S.activeConnId+":"+schema+"."+table,kind:"data",title:table,icon:"table2",build:function(pane,tab){buildDataPane(pane,tab,schema,table);}});}
|
|
294
|
+
function openDataTab(schema,table,restore){return openTab({key:"data:"+S.activeConnId+":"+schema+"."+table,kind:"data",title:table,icon:"table2",connectionId:S.activeConnId,meta:{schema:schema,table:table,objectType:"table"},build:function(pane,tab){tab.connectionId=S.activeConnId;buildDataPane(pane,tab,schema,table,restore);}});}
|
|
295
|
+
var _pop=null;
|
|
296
|
+
function showPopover(node,anchor){closePop();_pop=node;node.style.position="fixed";document.body.appendChild(node);var r=anchor.getBoundingClientRect();node.style.left=Math.min(r.left,window.innerWidth-node.offsetWidth-10)+"px";node.style.top=(r.bottom+6)+"px";setTimeout(function(){document.addEventListener("mousedown",popOutside,true);},0);}
|
|
297
|
+
function popOutside(e){if(_pop&&!_pop.contains(e.target))closePop();}
|
|
298
|
+
function closePop(){if(_pop){_pop.remove();_pop=null;document.removeEventListener("mousedown",popOutside,true);}}
|
|
299
|
+
function showFilterSql(tab,anchor){var g=tab.state.g;api("POST","/api/sql/generate-table-query",{connectionId:S.activeConnId,schema:g.schema,table:g.table,where:g.whereI.value||"",sort:g.orderBy?[{column:g.orderBy,direction:g.orderDir}]:[],limit:parseInt(g.pageSel.value,10),offset:g.offset}).then(function(r){var pre=el("pre",{text:r.sql});var pop=el("div",{class:"popover"},[el("div",{class:"row",style:"margin-bottom:8px"},[el("b",{text:"Generated SQL"}),el("span",{style:"flex:1"}),el("button",{class:"btn sm sec",text:"Copy",onclick:function(){navigator.clipboard.writeText(r.sql);logMsg("Copied SQL","ok");}}),el("button",{class:"btn sm",text:"Open in Console",onclick:function(){closePop();openSqlTab(r.sql,g.table);}}),el("button",{class:"btn sm ghost",text:"Close",onclick:closePop})]),pre]);showPopover(pop,anchor);}).catch(function(e){logMsg(e.message,"err");});}
|
|
240
300
|
function pendingCount(g){return Object.keys(g.edits).length+Object.keys(g.deletes).length+g.inserts.length;}
|
|
241
301
|
function rowKeyOf(g,row){return g.pk.map(function(k){return String(row[k]);}).join("\\u0001");}
|
|
242
|
-
function buildDataPane(pane,tab,schema,table){
|
|
243
|
-
var g={schema:schema,table:table,pk:[],columns:[],rows:[],offset:0,pageSize:100,where:"",orderBy:"",orderDir:"asc",total:null,edits:{},deletes:{},inserts:[],errors:{},editable:false,selRow:null,iseq:0};tab.state.g=g;
|
|
302
|
+
function buildDataPane(pane,tab,schema,table,restore){
|
|
303
|
+
var g={schema:schema,table:table,pk:[],columns:[],rows:[],offset:0,pageSize:100,where:"",orderBy:"",orderDir:"asc",total:null,edits:{},deletes:{},inserts:[],errors:{},editable:false,selRow:null,iseq:0,undo:[],redo:[]};tab.state.g=g;
|
|
244
304
|
var whereI=el("input",{class:"input",style:"flex:1",placeholder:"WHERE clause, e.g. STATUS = 'A'"});g.whereI=whereI;
|
|
245
305
|
var pageSel=el("select",{class:"select",style:"width:auto"});["100","500","1000"].forEach(function(v){pageSel.appendChild(el("option",{value:v,text:v}));});g.pageSel=pageSel;
|
|
246
306
|
var pageInfo=el("span",{class:"note"});g.pageInfo=pageInfo;
|
|
247
|
-
|
|
307
|
+
wireSearch(whereI,function(){g.where=whereI.value;g.offset=0;loadData(tab);});
|
|
308
|
+
var tb1=el("div",{class:"toolbar"},[whereI,el("button",{class:"btn",text:"Apply",onclick:function(){g.where=whereI.value;g.offset=0;loadData(tab);}}),el("button",{class:"btn ghost",text:"Show SQL",onclick:function(e){showFilterSql(tab,e.currentTarget);}}),el("button",{class:"btn sec",text:"Refresh",onclick:function(){loadData(tab);}}),el("span",{class:"note",text:"Page"}),pageSel,el("button",{class:"btn sec",text:"Prev",onclick:function(){g.offset=Math.max(0,g.offset-parseInt(pageSel.value,10));loadData(tab);}}),el("button",{class:"btn sec",text:"Next",onclick:function(){g.offset+=parseInt(pageSel.value,10);loadData(tab);}}),pageInfo,el("span",{class:"grow"}),el("button",{class:"btn ghost",text:"CSV",onclick:function(){exportData(tab,"csv");}}),el("button",{class:"btn ghost",text:"JSON",onclick:function(){exportData(tab,"json");}})]);
|
|
248
309
|
var saveBtn=el("button",{class:"btn",text:"Save changes",onclick:function(){saveDataChanges(tab);}});var revertBtn=el("button",{class:"btn ghost",text:"Revert all",onclick:function(){revertAll(tab);}});g.saveBtn=saveBtn;g.revertBtn=revertBtn;
|
|
249
310
|
var editHint=el("span",{class:"note"});g.editHint=editHint;
|
|
250
311
|
var tb2=el("div",{class:"toolbar"},[el("button",{class:"btn sec",text:"+ Insert row",onclick:function(){addInsertRow(tab);}}),el("button",{class:"btn ghost",text:"Delete selected",onclick:function(){toggleDeleteSelected(tab);}}),el("button",{class:"btn ghost",text:"Structure",onclick:function(){openStructureTab(schema,table);}}),saveBtn,revertBtn,editHint]);
|
|
251
312
|
var grid=el("div",{class:"gridwrap"});g.grid=grid;
|
|
252
|
-
|
|
313
|
+
var changeBar=el("div",{class:"changebar hidden"});g.changeBar=changeBar;
|
|
314
|
+
pane.appendChild(crumbs((activeConn()||{}).name,schema,table));pane.appendChild(tb1);pane.appendChild(tb2);pane.appendChild(changeBar);pane.appendChild(grid);
|
|
253
315
|
updateDirtyButtons(tab);
|
|
254
316
|
api("GET","/api/catalog/columns?"+qstr({connectionId:S.activeConnId,schema:schema,table:table})).then(function(r){g.columns=r.columns||[];}).catch(function(){});
|
|
255
317
|
api("GET","/api/catalog/primary-key?"+qstr({connectionId:S.activeConnId,schema:schema,table:table})).then(function(r){g.pk=(r.primaryKey&&r.primaryKey.columns)||[];g.editable=g.pk.length>0;editHint.textContent=g.editable?("Editable \\u00b7 double-click a cell \\u00b7 key: "+g.pk.join(", ")):"Read-only (no primary key detected)";renderGrid(tab);}).catch(function(){editHint.textContent="";});
|
|
318
|
+
if(restore){g.where=restore.where||"";whereI.value=g.where;g.offset=restore.offset||0;if(restore.pageSize)pageSel.value=String(restore.pageSize);if(restore.sort&&restore.sort[0]){g.orderBy=restore.sort[0].column;g.orderDir=restore.sort[0].direction;}}
|
|
256
319
|
loadData(tab);
|
|
257
320
|
loadCount(tab);
|
|
258
321
|
}
|
|
@@ -260,13 +323,13 @@ function loadData(tab){var g=tab.state.g;g.pageSize=parseInt(g.pageSel.value,10)
|
|
|
260
323
|
function loadCount(tab){var g=tab.state.g;api("POST","/api/table/count",{connectionId:S.activeConnId,schema:g.schema,table:g.table}).then(function(r){g.total=r.count;$("stRows").textContent=r.count+" total";}).catch(function(){});}
|
|
261
324
|
function dataSortToggle(tab,field){var g=tab.state.g;if(g.orderBy===field)g.orderDir=g.orderDir==="asc"?"desc":"asc";else{g.orderBy=field;g.orderDir="asc";}g.offset=0;loadData(tab);}
|
|
262
325
|
function renderGrid(tab){var g=tab.state.g;var box=clear(g.grid);if(!g.rows.length&&!g.inserts.length){box.appendChild(el("div",{class:"empty",text:"No rows."}));return;}
|
|
263
|
-
var fields=g.columns.length?g.columns.map(function(c){return c.name;}):(g.rows[0]?Object.keys(g.rows[0]):[]);
|
|
326
|
+
var fields=g.columns.length?g.columns.map(function(c){return c.name;}):(g.rows[0]?Object.keys(g.rows[0]):[]);g.fields=fields;
|
|
264
327
|
var table=el("table",{class:"grid"});var thead=el("thead");var htr=el("tr");htr.appendChild(el("th",{class:"rowhdr",text:"#"}));fields.forEach(function(f){var arrow=g.orderBy===f?(g.orderDir==="desc"?" \\u25BC":" \\u25B2"):"";var th=el("th",{title:"Click to sort",text:f+arrow});th.addEventListener("click",function(){dataSortToggle(tab,f);});htr.appendChild(th);});thead.appendChild(htr);table.appendChild(thead);
|
|
265
328
|
var tbody=el("tbody");
|
|
266
|
-
g.rows.forEach(function(row,ri){var key=rowKeyOf(g,row);var deleted=!!g.deletes[key];var edited=g.edits[key];var err=g.errors[key];var tr=el("tr",{class:(g.selRow===ri?"selrow ":"")+(deleted?"row-del ":"")+(err?"row-err ":"")});
|
|
329
|
+
g.rows.forEach(function(row,ri){var key=rowKeyOf(g,row);var deleted=!!g.deletes[key];var edited=g.edits[key];var err=g.errors[key];var tr=el("tr",{class:(g.selRow===ri?"selrow ":"")+(deleted?"row-del ":"")+(err?"row-err ":""),"data-ri":ri});
|
|
267
330
|
var flag=edited?'<span class="rowflag d"></span>':(deleted?'<span class="rowflag del"></span>':"");
|
|
268
|
-
var num=el("td",{class:"rowhdr",html:flag+(g.offset+ri+1)});num.addEventListener("click",function(){g.selRow=(g.selRow===ri?null:ri);renderGrid(tab);});tr.appendChild(num);
|
|
269
|
-
fields.forEach(function(f){var hasEdit=edited&&Object.prototype.hasOwnProperty.call(edited,f);var v=hasEdit?edited[f]:row[f];var disp=v==null?"":typeof v==="object"?JSON.stringify(v):String(v);var td=el("td",{class:(typeof v==="number"?"num ":"")+(hasEdit?"edited":""),title:disp,text:disp.length>400?disp.slice(0,400)+"\\u2026":disp});if(g.editable&&!deleted){td.addEventListener("dblclick",function(){startEdit(tab,td,ri,f,row);});}else{td.addEventListener("dblclick",function(){
|
|
331
|
+
var num=el("td",{class:"rowhdr",html:flag+(g.offset+ri+1),title:err||""});num.addEventListener("click",function(){g.selRow=(g.selRow===ri?null:ri);renderGrid(tab);});tr.appendChild(num);
|
|
332
|
+
fields.forEach(function(f){var hasEdit=edited&&Object.prototype.hasOwnProperty.call(edited,f);var v=hasEdit?edited[f]:row[f];var disp=v==null?"":typeof v==="object"?JSON.stringify(v):String(v);var td=el("td",{class:(typeof v==="number"?"num ":"")+(hasEdit?"edited":""),title:disp,text:disp.length>400?disp.slice(0,400)+"\\u2026":disp});if(g.editable&&!deleted){td.addEventListener("dblclick",function(){startEdit(tab,td,ri,f,row);});}else{td.addEventListener("dblclick",function(){openCellViewer(v);});}tr.appendChild(td);});
|
|
270
333
|
if(err){var etr=tr;etr.title=err;}
|
|
271
334
|
tbody.appendChild(tr);});
|
|
272
335
|
g.inserts.forEach(function(ins){var tr=el("tr",{class:"row-ins"});tr.appendChild(el("td",{class:"rowhdr",html:'<span class="rowflag ins"></span>'+"new",onclick:function(){g.inserts=g.inserts.filter(function(x){return x!==ins;});updateDirtyButtons(tab);renderGrid(tab);}}));
|
|
@@ -276,11 +339,13 @@ function renderGrid(tab){var g=tab.state.g;var box=clear(g.grid);if(!g.rows.leng
|
|
|
276
339
|
table.appendChild(tbody);box.appendChild(table);
|
|
277
340
|
updateDirtyButtons(tab);
|
|
278
341
|
}
|
|
279
|
-
function startEdit(tab,td,ri,field,row){if(td.querySelector("input"))return;var g=tab.state.g;var key=rowKeyOf(g,row);var cur=g.edits[key]&&Object.prototype.hasOwnProperty.call(g.edits[key],field)?g.edits[key][field]:row[field];var input=el("input",{class:"cellinput"});input.value=cur==null?"":typeof cur==="object"?JSON.stringify(cur):String(cur);clear(td).appendChild(input);input.focus();input.select();var done=false;function commit(){if(done)return;done=true;var origStr=row[field]==null?"":String(row[field]);if(input.value
|
|
280
|
-
function
|
|
281
|
-
function
|
|
342
|
+
function startEdit(tab,td,ri,field,row){if(td.querySelector("input"))return;var g=tab.state.g;var colIdx=g.fields?g.fields.indexOf(field):-1;var key=rowKeyOf(g,row);var cur=g.edits[key]&&Object.prototype.hasOwnProperty.call(g.edits[key],field)?g.edits[key][field]:row[field];var input=el("input",{class:"cellinput"});input.value=cur==null?"":typeof cur==="object"?JSON.stringify(cur):String(cur);clear(td).appendChild(input);input.focus();input.select();var done=false;function commit(){if(done)return true;done=true;var origStr=row[field]==null?"":String(row[field]);if(input.value!==origStr){gridPushUndo(tab);g.edits[key]=g.edits[key]||{};g.edits[key][field]=input.value;}else if(g.edits[key]){delete g.edits[key][field];if(!Object.keys(g.edits[key]).length)delete g.edits[key];}return true;}
|
|
343
|
+
input.addEventListener("keydown",function(e){if(e.key==="Enter"){e.preventDefault();commit();renderGrid(tab);editAt(tab,ri+1,colIdx);}else if(e.key==="Tab"){e.preventDefault();commit();renderGrid(tab);editAt(tab,ri,colIdx+1);}else if(e.key==="Escape"){e.preventDefault();done=true;renderGrid(tab);}});
|
|
344
|
+
input.addEventListener("blur",function(){if(!done){commit();renderGrid(tab);}});}
|
|
345
|
+
function toggleDeleteSelected(tab){var g=tab.state.g;if(g.selRow==null)return logMsg("Click a row number to select it first.","warn");if(!g.editable)return logMsg("Cannot delete: no primary key.","warn");gridPushUndo(tab);var key=rowKeyOf(g,g.rows[g.selRow]);if(g.deletes[key])delete g.deletes[key];else g.deletes[key]=true;renderGrid(tab);}
|
|
346
|
+
function addInsertRow(tab){var g=tab.state.g;gridPushUndo(tab);g.inserts.push({iseq:++g.iseq,values:{}});renderGrid(tab);}
|
|
282
347
|
function revertAll(tab){var g=tab.state.g;g.edits={};g.deletes={};g.inserts=[];g.errors={};renderGrid(tab);logMsg("Reverted pending changes.","ok");}
|
|
283
|
-
function updateDirtyButtons(tab){var g=tab.state.g;var
|
|
348
|
+
function updateDirtyButtons(tab){var g=tab.state.g;var nu=Object.keys(g.edits).length,nd=Object.keys(g.deletes).length,ni=g.inserts.length;var n=nu+nd+ni;g.saveBtn.style.display=n>0?"":"none";g.revertBtn.style.display=n>0?"":"none";setDirty(tab,n>0);if(g.changeBar){if(n>0){g.changeBar.classList.remove("hidden");clear(g.changeBar);g.changeBar.appendChild(el("span",{text:"Pending changes: "+nu+" update(s), "+ni+" insert(s), "+nd+" delete(s)"}));g.changeBar.appendChild(el("span",{class:"grow"}));g.changeBar.appendChild(el("button",{class:"btn sm",text:"Save Changes",onclick:function(){saveDataChanges(tab);}}));g.changeBar.appendChild(el("button",{class:"btn sm ghost",text:"Revert All",onclick:function(){revertAll(tab);}}));g.changeBar.appendChild(el("button",{class:"btn sm ghost",text:"Show Changes",onclick:function(){showChanges(tab);}}));}else g.changeBar.classList.add("hidden");}}
|
|
284
349
|
function exportData(tab,fmt){var g=tab.state.g;if(!g.rows.length)return logMsg("No rows.","warn");var fields=g.columns.length?g.columns.map(function(c){return c.name;}):Object.keys(g.rows[0]);fetch(fmt==="csv"?"/api/export/csv":"/api/export/json",{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({fields:fields,rows:g.rows})}).then(function(r){return r.blob();}).then(function(b){var a=document.createElement("a");a.href=URL.createObjectURL(b);a.download=fmt==="csv"?g.table+".csv":g.table+".json";a.click();});}
|
|
285
350
|
function saveDataChanges(tab){var g=tab.state.g;if(S.readOnly)return logMsg("Read-only mode is on.","warn");
|
|
286
351
|
var updates=Object.keys(g.edits).map(function(key){var row=g.rows.filter(function(r){return rowKeyOf(g,r)===key;})[0];var keyObj={};g.pk.forEach(function(k){keyObj[k]=row[k];});return {key:keyObj,changes:g.edits[key]};});
|
|
@@ -309,13 +374,14 @@ function rowKeyFromKeyObj(g,keyObj){return g.pk.map(function(k){return String(ke
|
|
|
309
374
|
/* ====================================================================
|
|
310
375
|
STRUCTURE / METADATA TAB
|
|
311
376
|
==================================================================== */
|
|
312
|
-
function openStructureTab(schema,table){openTab({key:"struct:"+S.activeConnId+":"+schema+"."+table,kind:"structure",title:"Structure: "+table,icon:"col",build:function(pane,tab){buildStructure(pane,tab,schema,table);}});}
|
|
377
|
+
function openStructureTab(schema,table){return openTab({key:"struct:"+S.activeConnId+":"+schema+"."+table,kind:"structure",title:"Structure: "+table,icon:"col",connectionId:S.activeConnId,meta:{schema:schema,table:table,objectType:"table"},build:function(pane,tab){tab.connectionId=S.activeConnId;buildStructure(pane,tab,schema,table);}});}
|
|
313
378
|
function buildStructure(pane,tab,schema,table){
|
|
314
379
|
var subtabs=el("div",{class:"meta-tabs"});var body=el("div",{class:"pane-body"});
|
|
315
380
|
var defs=[["columns","Columns"],["indexes","Indexes"],["ddl","DDL"],["info","Info"]];
|
|
316
381
|
var active="columns";var data={};
|
|
317
382
|
function render(){clear(body);if(active==="columns")renderCols();else if(active==="indexes")renderIdx();else if(active==="ddl")renderDdl();else renderInfo();Array.prototype.forEach.call(subtabs.children,function(ch,i){ch.classList.toggle("active",defs[i][0]===active);});}
|
|
318
383
|
defs.forEach(function(d){subtabs.appendChild(el("div",{class:"meta-tab",text:d[1],onclick:function(){active=d[0];render();}}));});
|
|
384
|
+
pane.appendChild(crumbs((activeConn()||{}).name,schema,table));
|
|
319
385
|
pane.appendChild(el("div",{class:"toolbar"},[el("b",{text:'"'+schema+'"."'+table+'"'}),el("span",{class:"grow"}),el("button",{class:"btn sec",text:"Open Data",onclick:function(){openDataTab(schema,table);}})]));
|
|
320
386
|
pane.appendChild(subtabs);pane.appendChild(body);
|
|
321
387
|
function renderCols(){body.appendChild(el("div",{class:"empty"},[el("span",{class:"spin"})," loading..."]));api("GET","/api/catalog/columns?"+qstr({connectionId:S.activeConnId,schema:schema,table:table})).then(function(r){data.columns=r.columns||[];if(active!=="columns")return;clear(body);var t=el("table",{class:"grid"});t.appendChild(el("thead",{html:"<tr><th>Name</th><th>Type</th><th>Length</th><th>Scale</th><th>Nullable</th><th>Key</th><th>Default</th><th>Comment</th></tr>"}));var tb=el("tbody");data.columns.forEach(function(c){tb.appendChild(el("tr",{html:"<td>"+esc(c.name)+"</td><td>"+esc(c.dataType)+'</td><td class="num">'+esc(c.length==null?"":c.length)+'</td><td class="num">'+esc(c.scale==null?"":c.scale)+"</td><td>"+(c.nullable?"YES":"NO")+"</td><td>"+(c.isPrimaryKey?'<span class="pill pk">PK</span>':"")+"</td><td>"+esc(c.defaultValue==null?"":c.defaultValue)+"</td><td>"+esc(c.comment==null?"":c.comment)+"</td>"}));});t.appendChild(tb);clear(body).appendChild(t);}).catch(function(e){clear(body).appendChild(el("div",{class:"errbox",text:e.message}));});}
|
|
@@ -329,7 +395,7 @@ function buildStructure(pane,tab,schema,table){
|
|
|
329
395
|
SAVED QUERIES
|
|
330
396
|
==================================================================== */
|
|
331
397
|
function loadSavedQueries(){return api("GET","/api/queries").then(function(r){S.savedQueries=r.queries||[];renderSavedQueries();}).catch(function(){});}
|
|
332
|
-
function renderSavedQueries(){var
|
|
398
|
+
function renderSavedQueries(){var raw=($("querySearch").value||"");var q=raw.toLowerCase();var box=clear($("queryList"));var rows=S.savedQueries.filter(function(x){return (x.name+" "+(x.tags||[]).join(" ")).toLowerCase().indexOf(q)>=0;});if(!rows.length){box.appendChild(el("div",{class:"empty",text:S.savedQueries.length?"No results found":"No saved queries."}));return;}rows.forEach(function(x){var item=el("div",{class:"wli",onclick:function(){openSqlTab(x.sql,x.name,x.id);},oncontextmenu:function(e){e.preventDefault();queryMenu(e,x);}});item.appendChild(el("b",{html:highlightMatch(x.name,raw)}));item.appendChild(el("div",{class:"note",text:(x.connectionType||"")+" \\u00b7 "+new Date(x.updatedAt).toLocaleDateString()}));box.appendChild(item);});}
|
|
333
399
|
function queryMenu(e,x){showCtx(e.clientX,e.clientY,[{label:"Open",icon:"sql",onClick:function(){openSqlTab(x.sql,x.name);}},{label:"Rename",icon:"gear",onClick:function(){var n=prompt("New name",x.name);if(n)api("PUT","/api/queries/"+encodeURIComponent(x.id),{name:n}).then(loadSavedQueries);}},{label:"Delete",icon:"x",danger:true,onClick:function(){if(confirm("Delete '"+x.name+"'?"))api("DELETE","/api/queries/"+encodeURIComponent(x.id)).then(loadSavedQueries);}}]);}
|
|
334
400
|
|
|
335
401
|
/* ====================================================================
|
|
@@ -369,6 +435,68 @@ function openBtpWizard(){var stState={apps:[],services:[],app:"",svc:null,color:
|
|
|
369
435
|
/* ====================================================================
|
|
370
436
|
READ-ONLY + INIT
|
|
371
437
|
==================================================================== */
|
|
438
|
+
/* ====================================================================
|
|
439
|
+
KEYBOARD + COMMAND PALETTE + SETTINGS
|
|
440
|
+
==================================================================== */
|
|
441
|
+
function isTyping(t){return t&&(t.tagName==="INPUT"||t.tagName==="TEXTAREA"||t.isContentEditable);}
|
|
442
|
+
function saveActive(){var t=tabById(S.activeTabId);if(!t)return;if(t.kind==="sql")saveQueryTab(t);else if(t.kind==="data")saveDataChanges(t);else logMsg("Nothing to save in this tab.","warn");}
|
|
443
|
+
function onGlobalKey(e){var k=e.key;var ctrl=e.ctrlKey||e.metaKey;
|
|
444
|
+
if(ctrl&&e.shiftKey&&(k==="P"||k==="p")){e.preventDefault();openCommandPalette();return;}
|
|
445
|
+
if(k==="Escape"){hideCtx();closePop();if(_palette){closePalette();return;}return;}
|
|
446
|
+
if(ctrl&&k==="Tab"){e.preventDefault();nextTab(e.shiftKey?-1:1);return;}
|
|
447
|
+
if(ctrl&&(k==="w"||k==="W")){e.preventDefault();if(S.activeTabId)closeTab(S.activeTabId);return;}
|
|
448
|
+
if(ctrl&&!e.shiftKey&&(k==="f"||k==="F")&&!isTyping(e.target)){e.preventDefault();$("topSearch").focus();return;}
|
|
449
|
+
if(k==="F5"&&!isTyping(e.target)){var ft=tabById(S.activeTabId);if(ft&&ft.kind==="sql"){e.preventDefault();runMode(ft,"all");}return;}
|
|
450
|
+
if(ctrl&&(k==="s"||k==="S")&&!isTyping(e.target)){e.preventDefault();saveActive();return;}
|
|
451
|
+
var at=tabById(S.activeTabId);
|
|
452
|
+
if(at&&at.kind==="data"&&at.state.g&&!isTyping(e.target)){var g=at.state.g;
|
|
453
|
+
if(ctrl&&(k==="s"||k==="S")){e.preventDefault();saveDataChanges(at);return;}
|
|
454
|
+
if(ctrl&&(k==="z"||k==="Z")){e.preventDefault();gridUndo(at);return;}
|
|
455
|
+
if(ctrl&&(k==="y"||k==="Y")){e.preventDefault();gridRedo(at);return;}
|
|
456
|
+
if(k==="Delete"){e.preventDefault();toggleDeleteSelected(at);return;}
|
|
457
|
+
}
|
|
458
|
+
}
|
|
459
|
+
var PALETTE=[
|
|
460
|
+
{label:"New SQL Console",run:function(){if(!S.activeConnId)logMsg("Select a connection first.","warn");else openSqlTab();}},
|
|
461
|
+
{label:"Run SQL (current tab)",run:function(){var t=tabById(S.activeTabId);if(t&&t.kind==="sql")runMode(t,"selected");}},
|
|
462
|
+
{label:"Save Query / Grid Changes",run:saveActive},
|
|
463
|
+
{label:"Import from BTP App",run:function(){openBtpWizard();}},
|
|
464
|
+
{label:"New direct connection",run:function(){newConnModal();}},
|
|
465
|
+
{label:"Focus Connections",run:function(){$("connSearch").focus();}},
|
|
466
|
+
{label:"Focus Object Explorer",run:function(){var s=document.querySelector("#secTree .tsearch input");if(s)s.focus();else $("topSearch").focus();}},
|
|
467
|
+
{label:"Toggle Read-only",run:function(){toggleReadOnly();}},
|
|
468
|
+
{label:"Open Active Table Structure",run:function(){var t=tabById(S.activeTabId);if(t&&t.meta&&t.meta.table)openStructureTab(t.meta.schema,t.meta.table);else logMsg("No active table.","warn");}},
|
|
469
|
+
{label:"Export Result CSV",run:function(){var t=tabById(S.activeTabId);if(t&&t.kind==="sql")exportResult(t,"csv");else if(t&&t.kind==="data")exportData(t,"csv");}},
|
|
470
|
+
{label:"Close Active Tab",run:function(){if(S.activeTabId)closeTab(S.activeTabId);}},
|
|
471
|
+
{label:"Show Keyboard Shortcuts",run:function(){showShortcuts();}},
|
|
472
|
+
{label:"Open Settings",run:function(){openSettings();}}
|
|
473
|
+
];
|
|
474
|
+
var _palette=null;
|
|
475
|
+
function openCommandPalette(){closePalette();var input=el("input",{placeholder:"Type a command..."});var list=el("div",{class:"pitems"});var sel=0;var filtered=PALETTE.slice();
|
|
476
|
+
function draw(){clear(list);var q=input.value.toLowerCase();filtered=PALETTE.filter(function(c){return c.label.toLowerCase().indexOf(q)>=0;});filtered.forEach(function(c,i){list.appendChild(el("div",{class:"pitem"+(i===sel?" sel":""),onclick:function(){closePalette();c.run();}},[el("span",{html:highlightMatch(c.label,input.value)})]));});}
|
|
477
|
+
input.addEventListener("input",function(){sel=0;draw();});
|
|
478
|
+
input.addEventListener("keydown",function(e){if(e.key==="ArrowDown"){e.preventDefault();sel=Math.min(filtered.length-1,sel+1);draw();}else if(e.key==="ArrowUp"){e.preventDefault();sel=Math.max(0,sel-1);draw();}else if(e.key==="Enter"){e.preventDefault();if(filtered[sel]){closePalette();filtered[sel].run();}}else if(e.key==="Escape"){e.preventDefault();closePalette();}});
|
|
479
|
+
var ov=el("div",{class:"modal",onclick:function(e){if(e.target===ov)closePalette();}},[el("div",{class:"palette"},[input,list])]);document.body.appendChild(ov);_palette=ov;draw();input.focus();}
|
|
480
|
+
function closePalette(){if(_palette){_palette.remove();_palette=null;}}
|
|
481
|
+
function showShortcuts(){var rows=[["Ctrl+Shift+P","Command palette"],["Ctrl+Tab","Next tab"],["Ctrl+Shift+Tab","Previous tab"],["Ctrl+W","Close active tab"],["Ctrl+S","Save query / grid changes"],["Ctrl+F","Focus search"],["Escape","Close popup / clear search"],["Ctrl+Enter","Run selected / current SQL"],["F5","Run all SQL"],["Ctrl+Z / Ctrl+Y","Undo / redo (editor & grid)"],["Delete","Mark grid row for delete"],["Enter / Tab","Confirm cell edit & move"],["Esc","Cancel cell edit"]];
|
|
482
|
+
var grid=el("div",{class:"shorts"});rows.forEach(function(r){grid.appendChild(el("div",{class:"srow"},[el("span",{text:r[1]}),el("span",{class:"kbd",text:r[0]})]));});
|
|
483
|
+
openModal(el("div",{class:"dialog"},[el("h3",{text:"Keyboard shortcuts"}),grid,el("div",{class:"row right",style:"margin-top:14px"},[el("button",{class:"btn",text:"Close",onclick:closeModal})])]));}
|
|
484
|
+
function openSettings(){var s=S.settings;var restore=el("input",{type:"checkbox"});restore.checked=s.restoreWorkspace;var ro=el("input",{type:"checkbox"});ro.checked=s.readOnlyByDefault;var prod=el("input",{type:"checkbox"});prod.checked=s.showProductionWarning;var fmt=el("input",{type:"checkbox"});fmt.checked=s.autoFormatGeneratedSql;var limit=el("input",{class:"input",value:String(s.defaultRowLimit)});var schema=el("input",{class:"input",value:s.defaultSchema||""});var timeout=el("input",{class:"input",value:String(s.queryTimeoutMs)});var maxh=el("input",{class:"input",value:String(s.maxHistoryItems)});var delay=el("input",{class:"input",value:String(s.autoSaveDelayMs)});
|
|
485
|
+
var d=el("div",{class:"dialog"},[el("h3",{text:"Studio settings"}),el("label",{class:"toggle"},[restore," Restore workspace on startup"]),el("label",{class:"toggle"},[ro," Read-only by default"]),el("label",{class:"toggle"},[prod," Show production warning"]),el("label",{class:"toggle"},[fmt," Auto-format generated SQL"]),el("div",{class:"field"},[el("label",{text:"Default row limit"}),limit]),el("div",{class:"field"},[el("label",{text:"Default schema"}),schema]),el("div",{class:"field"},[el("label",{text:"Query timeout (ms)"}),timeout]),el("div",{class:"field"},[el("label",{text:"Max history items"}),maxh]),el("div",{class:"field"},[el("label",{text:"Auto-save delay (ms)"}),delay]),el("div",{class:"row right"},[el("button",{class:"btn ghost",text:"Cancel",onclick:closeModal}),el("button",{class:"btn",text:"Save",onclick:function(){api("PUT","/api/studio/settings",{restoreWorkspace:restore.checked,readOnlyByDefault:ro.checked,showProductionWarning:prod.checked,autoFormatGeneratedSql:fmt.checked,defaultRowLimit:parseInt(limit.value,10)||100,defaultSchema:schema.value.trim(),queryTimeoutMs:parseInt(timeout.value,10)||30000,maxHistoryItems:parseInt(maxh.value,10)||300,autoSaveDelayMs:parseInt(delay.value,10)||500}).then(function(r){S.settings=r.settings;closeModal();logMsg("Settings saved.","ok");}).catch(function(e){logMsg(e.message,"err");});}})])]);openModal(d);}
|
|
486
|
+
function openCellViewer(value){var raw=value==null?"":typeof value==="object"?JSON.stringify(value):String(value);var pretty=raw;try{pretty=JSON.stringify(JSON.parse(raw),null,2);}catch(e){}var ta=el("textarea",{class:"editor",style:"min-height:300px"});ta.value=pretty;openModal(el("div",{class:"dialog",style:"width:700px"},[el("h3",{text:"Cell value"}),ta,el("div",{class:"row right",style:"margin-top:10px"},[el("button",{class:"btn ghost",text:"Copy",onclick:function(){navigator.clipboard.writeText(raw);logMsg("Copied value","ok");}}),el("button",{class:"btn",text:"Close",onclick:closeModal})])]));}
|
|
487
|
+
function crumbs(connName,schema,table){var c=el("div",{class:"crumbs"});c.appendChild(el("a",{text:connName||"Connection",onclick:function(){if(S.activeConnId)activateConnection(S.activeConnId);}}));c.appendChild(el("span",{class:"sep",text:"\\u203a"}));c.appendChild(el("a",{text:schema,onclick:function(){S.activeSchema=schema;updateTopBadges();}}));c.appendChild(el("span",{class:"sep",text:"\\u203a"}));c.appendChild(el("span",{text:table}));return c;}
|
|
488
|
+
|
|
489
|
+
/* ---- grid undo/redo + change review ---- */
|
|
490
|
+
function gridSnapshot(g){return JSON.stringify({edits:g.edits,deletes:g.deletes,inserts:g.inserts});}
|
|
491
|
+
function gridApplySnap(g,s){var o=JSON.parse(s);g.edits=o.edits;g.deletes=o.deletes;g.inserts=o.inserts;}
|
|
492
|
+
function gridPushUndo(tab){var g=tab.state.g;g.undo.push(gridSnapshot(g));if(g.undo.length>60)g.undo.shift();g.redo=[];}
|
|
493
|
+
function gridUndo(tab){var g=tab.state.g;if(!g.undo.length)return logMsg("Nothing to undo.","warn");g.redo.push(gridSnapshot(g));gridApplySnap(g,g.undo.pop());renderGrid(tab);}
|
|
494
|
+
function gridRedo(tab){var g=tab.state.g;if(!g.redo.length)return logMsg("Nothing to redo.","warn");g.undo.push(gridSnapshot(g));gridApplySnap(g,g.redo.pop());renderGrid(tab);}
|
|
495
|
+
function showChanges(tab){var g=tab.state.g;var out=[];Object.keys(g.edits).forEach(function(key){var row=g.rows.filter(function(r){return rowKeyOf(g,r)===key;})[0]||{};Object.keys(g.edits[key]).forEach(function(col){out.push(["update",key,col,String(row[col]==null?"":row[col]),String(g.edits[key][col])]);});});Object.keys(g.deletes).forEach(function(key){out.push(["delete",key,"","",""]);});g.inserts.forEach(function(ins){out.push(["insert","(new)",Object.keys(ins.values).join(","),"",JSON.stringify(ins.values)]);});
|
|
496
|
+
var t=el("table",{class:"grid"});t.appendChild(el("thead",{html:"<tr><th>Type</th><th>Row key</th><th>Column</th><th>Old</th><th>New</th></tr>"}));var tb=el("tbody");if(!out.length)tb.appendChild(el("tr",{html:'<td colspan="5">No pending changes.</td>'}));out.forEach(function(r){tb.appendChild(el("tr",{html:r.map(function(c){return "<td>"+esc(c)+"</td>";}).join("")}));});t.appendChild(tb);
|
|
497
|
+
openModal(el("div",{class:"dialog",style:"width:780px"},[el("h3",{text:"Pending changes"}),el("div",{class:"gridwrap",style:"max-height:52vh"},[t]),el("div",{class:"row right",style:"margin-top:12px"},[el("button",{class:"btn",text:"Close",onclick:closeModal})])]));}
|
|
498
|
+
function editAt(tab,ri,colIdx){var g=tab.state.g;if(ri<0||ri>=g.rows.length||colIdx<0||!g.fields||colIdx>=g.fields.length)return;var tr=g.grid.querySelector('tr[data-ri="'+ri+'"]');if(!tr)return;var tds=tr.querySelectorAll("td");var td=tds[colIdx+1];if(td)startEdit(tab,td,ri,g.fields[colIdx],g.rows[ri]);}
|
|
499
|
+
|
|
372
500
|
function applyReadOnly(){var b=$("roBadge");b.className="badge ro"+(S.readOnly?" active":"");b.textContent=S.readOnly?"Read-only":"Read/Write";}
|
|
373
501
|
function toggleReadOnly(){S.readOnly=!S.readOnly;applyReadOnly();logMsg("Read-only mode: "+(S.readOnly?"ON":"OFF"),"ok");}
|
|
374
502
|
|
|
@@ -382,15 +510,16 @@ window.addEventListener("load",function(){
|
|
|
382
510
|
$("btnImport").addEventListener("click",openBtpWizard);
|
|
383
511
|
$("btnImport2").addEventListener("click",openBtpWizard);
|
|
384
512
|
$("btnNewConn").addEventListener("click",newConnModal);
|
|
385
|
-
$("btnSettings").addEventListener("click",
|
|
513
|
+
$("btnSettings").addEventListener("click",openSettings);
|
|
386
514
|
$("btnHome").addEventListener("click",openWelcome);
|
|
387
|
-
|
|
388
|
-
$("
|
|
515
|
+
window.addEventListener("keydown",onGlobalKey);
|
|
516
|
+
$("connSearch").addEventListener("input",debounce(renderConnections,200));wireSearch($("connSearch"),renderConnections);
|
|
517
|
+
$("querySearch").addEventListener("input",debounce(renderSavedQueries,200));wireSearch($("querySearch"),renderSavedQueries);
|
|
389
518
|
$("topSearch").addEventListener("input",debounce(function(){$("connSearch").value=$("topSearch").value;renderConnections();},200));
|
|
390
519
|
$("btnNewQuery").addEventListener("click",function(){if(!S.activeConnId)return logMsg("Select a connection first.","warn");openSqlTab();});
|
|
391
520
|
setConnStatus("Ready","ok");
|
|
392
521
|
openWelcome();
|
|
393
|
-
loadConnections();
|
|
522
|
+
loadSettings().then(function(){return loadConnections();}).then(function(){return restoreWorkspace();});
|
|
394
523
|
loadSavedQueries();
|
|
395
524
|
});
|
|
396
525
|
})();
|