simplemdg-dev-cli 2.6.0 → 2.7.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/USER_GUIDE.md +1 -1
- package/dist/core/db/db-studio-client.d.ts +1 -1
- package/dist/core/db/db-studio-client.js +88 -22
- package/dist/core/db/db-studio-client.js.map +1 -1
- package/dist/core/db/db-studio-server.js +46 -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 +27 -0
- package/dist/core/db/db-studio-styles.js.map +1 -1
- package/dist/index.js +1 -1
- package/package.json +1 -1
- package/src/core/db/db-studio-client.ts +88 -22
- package/src/core/db/db-studio-server.ts +47 -0
- package/src/core/db/db-studio-styles.ts +27 -0
- package/src/index.ts +1 -1
|
@@ -26,10 +26,16 @@ var ICONS = {
|
|
|
26
26
|
gear:"M12 8a4 4 0 1 0 0 8 4 4 0 0 0 0-8z|M19.4 13a7.9 7.9 0 0 0 0-2l2-1.5-2-3.4-2.3 1a8 8 0 0 0-1.7-1l-.4-2.6h-4l-.4 2.6a8 8 0 0 0-1.7 1l-2.3-1-2 3.4L4.6 11a7.9 7.9 0 0 0 0 2l-2 1.5 2 3.4 2.3-1a8 8 0 0 0 1.7 1l.4 2.6h4l.4-2.6a8 8 0 0 0 1.7-1l2.3 1 2-3.4z",
|
|
27
27
|
home:"M3 11l9-8 9 8|M5 10v10h14V10",
|
|
28
28
|
table2:"M4 4h16v16H4z|M4 9h16|M9 4v16",
|
|
29
|
-
col:"M5 4v16|M12 4v16|M19 4v16"
|
|
29
|
+
col:"M5 4v16|M12 4v16|M19 4v16",
|
|
30
|
+
trash:"M4 7h16|M9 7V4h6v3|M6 7l1 13h10l1-13|M10 11v6|M14 11v6",
|
|
31
|
+
chevL:"M15 6l-6 6 6 6",
|
|
32
|
+
chevR:"M9 6l6 6-6 6",
|
|
33
|
+
filter:"M3 5h18l-7 8v6l-4 2v-8z",
|
|
34
|
+
undo:"M9 7L4 12l5 5|M4 12h11a5 5 0 0 1 0 10h-3"
|
|
30
35
|
};
|
|
31
36
|
function svgFor(name){var d=ICONS[name]||"";return '<svg class="ic" viewBox="0 0 24 24">'+d.split("|").map(function(p){return '<path d="'+p+'"></path>';}).join("")+'</svg>';}
|
|
32
37
|
function icEl(name,cls){var s=document.createElement("span");s.className="ticon "+(cls||"");s.innerHTML=svgFor(name);return s;}
|
|
38
|
+
function gbtn(icon,title,onClick,extra){var b=el("button",{class:"gbtn "+(extra||""),title:title,html:svgFor(icon)});b.addEventListener("click",function(e){onClick(e);});return b;}
|
|
33
39
|
|
|
34
40
|
/* ---------- dom helpers ---------- */
|
|
35
41
|
function $(id){return document.getElementById(id);}
|
|
@@ -300,37 +306,46 @@ function showFilterSql(tab,anchor){var g=tab.state.g;api("POST","/api/sql/genera
|
|
|
300
306
|
function pendingCount(g){return Object.keys(g.edits).length+Object.keys(g.deletes).length+g.inserts.length;}
|
|
301
307
|
function rowKeyOf(g,row){return g.pk.map(function(k){return String(row[k]);}).join("\\u0001");}
|
|
302
308
|
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,
|
|
304
|
-
var whereI=el("input",{
|
|
305
|
-
var
|
|
306
|
-
var
|
|
307
|
-
|
|
308
|
-
var
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
var
|
|
309
|
+
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,sel:{},iseq:0,undo:[],redo:[]};tab.state.g=g;
|
|
310
|
+
var whereI=el("input",{spellcheck:"false",placeholder:"WHERE clause, e.g. STATUS = 'A' AND CREATEDBY LIKE '%admin%'"});g.whereI=whereI;
|
|
311
|
+
var clr=el("span",{class:"clr",html:svgFor("x"),title:"Clear filter"});
|
|
312
|
+
var whereBox=el("div",{class:"wherebox"},[el("span",{html:svgFor("filter")}),whereI,clr]);
|
|
313
|
+
var apply=function(){g.where=whereI.value;g.offset=0;applyBtn.classList.remove("on");loadData(tab);};
|
|
314
|
+
var applyBtn=gbtn("run","Apply filter (Enter)",apply);g.applyBtn=applyBtn;
|
|
315
|
+
clr.addEventListener("click",function(){whereI.value="";whereBox.classList.remove("has");apply();});
|
|
316
|
+
whereI.addEventListener("input",function(){whereBox.classList.toggle("has",!!whereI.value);applyBtn.classList.toggle("on",whereI.value!==g.where);});
|
|
317
|
+
whereI.addEventListener("keydown",function(e){if(e.key==="Enter"){e.preventDefault();apply();if(e.ctrlKey||e.metaKey)showFilterSql(tab,applyBtn);}else if(e.key==="Escape"){e.preventDefault();whereI.value="";whereBox.classList.remove("has");apply();}});
|
|
318
|
+
var insBtn=gbtn("plus","Insert row",function(){addInsertRow(tab);});g.insBtn=insBtn;
|
|
319
|
+
var delBtn=gbtn("trash","Mark selected rows for delete",function(){toggleDeleteSelected(tab);},"danger");g.delBtn=delBtn;
|
|
320
|
+
var tb=el("div",{class:"gtoolbar"},[whereBox,applyBtn,gbtn("sql","Show generated SQL",function(e){showFilterSql(tab,e.currentTarget);}),gbtn("refresh","Refresh data",function(e){var b=e.currentTarget;b.classList.add("spinning");loadData(tab,function(){b.classList.remove("spinning");});}),el("span",{class:"gsep"}),insBtn,delBtn,gbtn("col","Open structure",function(){openStructureTab(schema,table);}),el("span",{class:"gsep"}),gbtn("imp","Export data",function(e){openExportMenu(tab,e.currentTarget);})]);
|
|
313
321
|
var changeBar=el("div",{class:"changebar hidden"});g.changeBar=changeBar;
|
|
314
|
-
|
|
322
|
+
var grid=el("div",{class:"gridwrap"});g.grid=grid;
|
|
323
|
+
var pageSel=el("select");["100","500","1000"].forEach(function(v){pageSel.appendChild(el("option",{value:v,text:v}));});g.pageSel=pageSel;
|
|
324
|
+
pageSel.addEventListener("change",function(){g.offset=0;loadData(tab);});
|
|
325
|
+
var rangeSpan=el("span",{class:"note"});g.rangeSpan=rangeSpan;var durSpan=el("span",{class:"note"});g.durSpan=durSpan;
|
|
326
|
+
var footer=el("div",{class:"gridfoot"},[rangeSpan,el("span",{style:"flex:1"}),el("span",{class:"pg"},[gbtn("chevL","Previous page",function(){g.offset=Math.max(0,g.offset-parseInt(pageSel.value,10));loadData(tab);}),el("span",{class:"note",text:"Rows"}),pageSel,gbtn("chevR","Next page",function(){g.offset+=parseInt(pageSel.value,10);loadData(tab);})]),durSpan]);
|
|
327
|
+
pane.appendChild(crumbs((activeConn()||{}).name,schema,table));pane.appendChild(tb);pane.appendChild(changeBar);pane.appendChild(grid);pane.appendChild(footer);
|
|
315
328
|
updateDirtyButtons(tab);
|
|
316
329
|
api("GET","/api/catalog/columns?"+qstr({connectionId:S.activeConnId,schema:schema,table:table})).then(function(r){g.columns=r.columns||[];}).catch(function(){});
|
|
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;
|
|
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;}}
|
|
330
|
+
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;insBtn.disabled=!g.editable;delBtn.disabled=!g.editable;insBtn.title=g.editable?"Insert row":"Read-only (no primary key)";renderGrid(tab);}).catch(function(){});
|
|
331
|
+
if(restore){g.where=restore.where||"";whereI.value=g.where;whereBox.classList.toggle("has",!!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;}}
|
|
319
332
|
loadData(tab);
|
|
320
333
|
loadCount(tab);
|
|
321
334
|
}
|
|
322
|
-
function
|
|
335
|
+
function selectedKeys(g){return Object.keys(g.sel);}
|
|
336
|
+
function loadData(tab,onDone){var g=tab.state.g;g.pageSize=parseInt(g.pageSel.value,10);clear(g.grid).appendChild(el("div",{class:"empty"},[el("span",{class:"spin"})," loading data..."]));$("stDuration").textContent="…";api("POST","/api/table/data",{connectionId:S.activeConnId,schema:g.schema,table:g.table,limit:g.pageSize,offset:g.offset,where:g.where,orderBy:g.orderBy,orderDirection:g.orderDir}).then(function(r){g.rows=r.result.rows;g.sel={};renderGrid(tab);var to=g.offset+r.result.rowCount;g.rangeSpan.textContent="Showing "+(r.result.rowCount?g.offset+1:0)+"-"+to+(g.total!=null?" of "+g.total.toLocaleString():"");g.durSpan.textContent="Duration: "+r.result.durationMs+"ms · Offset: "+g.offset;$("stDuration").textContent=r.result.durationMs+"ms";$("stRows").textContent=(g.total!=null?g.total+" total":r.result.rowCount+" rows");if(onDone)onDone();}).catch(function(e){clear(g.grid).appendChild(el("div",{class:"errbox",text:"Cannot load data.\\nReason: "+e.message+"\\nAction: test the connection or refresh from BTP app env."}));if(onDone)onDone();});}
|
|
323
337
|
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(){});}
|
|
324
338
|
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);}
|
|
325
339
|
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;}
|
|
326
340
|
var fields=g.columns.length?g.columns.map(function(c){return c.name;}):(g.rows[0]?Object.keys(g.rows[0]):[]);g.fields=fields;
|
|
327
341
|
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);
|
|
328
342
|
var tbody=el("tbody");
|
|
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.
|
|
343
|
+
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.sel[key]?"selrow ":"")+(deleted?"row-del ":"")+(err?"row-err ":""),"data-ri":ri});
|
|
344
|
+
tr.addEventListener("contextmenu",function(e){e.preventDefault();rowContextMenu(e,tab,row);});
|
|
330
345
|
var flag=edited?'<span class="rowflag d"></span>':(deleted?'<span class="rowflag del"></span>':"");
|
|
331
|
-
var num=el("td",{class:"rowhdr",html:flag+(g.offset+ri+1),title:err||""});num.addEventListener("click",function(){g.
|
|
346
|
+
var num=el("td",{class:"rowhdr",html:flag+(g.offset+ri+1),title:err||""});num.addEventListener("click",function(e){if(!(e.ctrlKey||e.metaKey||e.shiftKey))g.sel={};if(g.sel[key])delete g.sel[key];else g.sel[key]=true;renderGrid(tab);});tr.appendChild(num);
|
|
332
347
|
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);});
|
|
333
|
-
if(err){
|
|
348
|
+
if(err){tr.title=err;}
|
|
334
349
|
tbody.appendChild(tr);});
|
|
335
350
|
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);}}));
|
|
336
351
|
fields.forEach(function(f){var inp=el("input",{class:"cellinput",value:ins.values[f]!=null?ins.values[f]:""});inp.addEventListener("input",function(){if(inp.value==="")delete ins.values[f];else ins.values[f]=inp.value;});var td=el("td");td.appendChild(inp);tr.appendChild(td);});
|
|
@@ -342,11 +357,61 @@ function renderGrid(tab){var g=tab.state.g;var box=clear(g.grid);if(!g.rows.leng
|
|
|
342
357
|
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
358
|
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
359
|
input.addEventListener("blur",function(){if(!done){commit();renderGrid(tab);}});}
|
|
345
|
-
function
|
|
360
|
+
function toastAction(msg,actionLabel,onAction){var t=el("div",{class:"toast"});t.appendChild(el("span",{text:msg+" "}));t.appendChild(el("a",{class:"link",text:actionLabel,onclick:function(){onAction();t.remove();}}));$("toasts").appendChild(t);setTimeout(function(){t.style.opacity="0";setTimeout(function(){t.remove();},250);},6000);}
|
|
361
|
+
function toggleDeleteSelected(tab){var g=tab.state.g;if(!g.editable)return logMsg("Cannot delete: table has no primary key.","warn");var keys=selectedKeys(g);if(!keys.length)return logMsg("Select one or more rows (click the row number).","warn");
|
|
362
|
+
if(keys.every(function(k){return g.deletes[k];})){gridPushUndo(tab);keys.forEach(function(k){delete g.deletes[k];});renderGrid(tab);return;}
|
|
363
|
+
var mark=function(){gridPushUndo(tab);keys.forEach(function(k){g.deletes[k]=true;});g.sel={};renderGrid(tab);toastAction(keys.length+" row"+(keys.length>1?"s":"")+" marked for delete. They are removed only when you Save Changes.","Undo",function(){gridUndo(tab);});};
|
|
364
|
+
if(keys.length>1){if(confirm("Mark "+keys.length+" selected rows for deletion?\\nThey will not be deleted until you click Save Changes."))mark();}else mark();}
|
|
346
365
|
function addInsertRow(tab){var g=tab.state.g;gridPushUndo(tab);g.inserts.push({iseq:++g.iseq,values:{}});renderGrid(tab);}
|
|
347
366
|
function revertAll(tab){var g=tab.state.g;g.edits={};g.deletes={};g.inserts=[];g.errors={};renderGrid(tab);logMsg("Reverted pending changes.","ok");}
|
|
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",{
|
|
349
|
-
function
|
|
367
|
+
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;if(g.saveBtn)g.saveBtn.style.display=n>0?"":"none";if(g.revertBtn)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",{},["Pending: ",el("span",{class:"cnt-u",text:nu+" edit"+(nu===1?"":"s")})," · ",el("span",{class:"cnt-i",text:ni+" insert"+(ni===1?"":"s")})," · ",el("span",{class:"cnt-d",text:nd+" delete"+(nd===1?"":"s")})]));g.changeBar.appendChild(el("span",{style:"flex:1"}));g.changeBar.appendChild(el("button",{class:"btn sm",title:"Ctrl+S",text:"Save",onclick:function(){saveDataChanges(tab);}}));g.changeBar.appendChild(el("button",{class:"btn sm ghost",title:"Revert all (Ctrl+Z to undo)",text:"Revert",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");}}
|
|
368
|
+
function gridFields(g){return g.columns.length?g.columns.map(function(c){return c.name;}):(g.rows[0]?Object.keys(g.rows[0]):[]);}
|
|
369
|
+
function exportFilename(g,fmt,suffix){var conn=(activeConn()||{}).name||"db";var stamp=new Date().toISOString().replace(/[:.]/g,"-").slice(0,19);return (conn+"_"+g.schema+"_"+g.table+(suffix?"_"+suffix:"")+"_"+stamp+"."+fmt).replace(/[^a-z0-9._-]+/gi,"-");}
|
|
370
|
+
function exportRowsToFile(fields,rows,fmt,filename){return fetch(fmt==="csv"?"/api/export/csv":"/api/export/json",{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({fields:fields,rows:rows})}).then(function(r){return r.blob();}).then(function(b){var a=document.createElement("a");a.href=URL.createObjectURL(b);a.download=filename;a.click();});}
|
|
371
|
+
function exportCurrentPage(tab,fmt){var g=tab.state.g;if(!g.rows.length)return logMsg("No rows to export.","warn");logMsg("Preparing export…","ok");exportRowsToFile(gridFields(g),g.rows,fmt,exportFilename(g,fmt,"page")).then(function(){logMsg("Exported current page as "+fmt.toUpperCase(),"ok");});}
|
|
372
|
+
function exportSelected(tab,fmt){var g=tab.state.g;var rows=g.rows.filter(function(r){return g.sel[rowKeyOf(g,r)];});if(!rows.length)return logMsg("Select rows first (click row numbers).","warn");exportRowsToFile(gridFields(g),rows,fmt,exportFilename(g,fmt,"selected")).then(function(){logMsg("Exported "+rows.length+" selected row(s) as "+fmt.toUpperCase(),"ok");});}
|
|
373
|
+
function exportViaApi(tab,source,fmt,extra){var g=tab.state.g;logMsg("Preparing export…","ok");var body={connectionId:S.activeConnId,schema:g.schema,objectName:g.table,objectType:"table",source:source,format:fmt,whereClause:g.where,limit:g.pageSize,offset:g.offset,sort:g.orderBy?[{column:g.orderBy,direction:g.orderDir}]:[]};if(extra)for(var k in extra)body[k]=extra[k];return fetch("/api/export/data",{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify(body)}).then(function(r){if(!r.ok)return r.text().then(function(t){throw new Error(t||("HTTP "+r.status));});return r.blob();}).then(function(b){var a=document.createElement("a");a.href=URL.createObjectURL(b);a.download=exportFilename(g,fmt,source);a.click();logMsg("Export completed ("+fmt.toUpperCase()+")","ok");}).catch(function(e){logMsg("Export failed: "+e.message,"err");});}
|
|
374
|
+
function openExportMenu(tab,anchor){var r=anchor.getBoundingClientRect();showCtx(r.left,r.bottom+4,[
|
|
375
|
+
{label:"Current page · CSV",icon:"imp",onClick:function(){exportCurrentPage(tab,"csv");}},
|
|
376
|
+
{label:"Current page · JSON",icon:"imp",onClick:function(){exportCurrentPage(tab,"json");}},
|
|
377
|
+
{sep:true},
|
|
378
|
+
{label:"Current query/filter · CSV",icon:"imp",onClick:function(){exportViaApi(tab,"current-query","csv");}},
|
|
379
|
+
{label:"Current query/filter · JSON",icon:"imp",onClick:function(){exportViaApi(tab,"current-query","json");}},
|
|
380
|
+
{sep:true},
|
|
381
|
+
{label:"Selected rows · CSV",icon:"imp",onClick:function(){exportSelected(tab,"csv");}},
|
|
382
|
+
{label:"Selected rows · JSON",icon:"imp",onClick:function(){exportSelected(tab,"json");}},
|
|
383
|
+
{sep:true},
|
|
384
|
+
{label:"Export custom…",icon:"gear",onClick:function(){exportCustomModal(tab);}}
|
|
385
|
+
]);}
|
|
386
|
+
function exportCustomModal(tab){var g=tab.state.g;var cols=gridFields(g);
|
|
387
|
+
var src=el("select",{class:"select"});[["current-page","Current page"],["current-query","Current query/filter"],["selected-rows","Selected rows"],["whole-table","Whole table (can be large)"]].forEach(function(o){src.appendChild(el("option",{value:o[0],text:o[1]}));});
|
|
388
|
+
var fmt=el("select",{class:"select"});[["csv","CSV"],["json","JSON"]].forEach(function(f){fmt.appendChild(el("option",{value:f[0],text:f[1]}));});
|
|
389
|
+
var checks={};var list=el("div",{class:"fieldlist"});cols.forEach(function(c){var cb=el("input",{type:"checkbox"});cb.checked=true;checks[c]=cb;list.appendChild(el("label",{},[cb,c]));});
|
|
390
|
+
var warn=el("div",{class:"note"});src.addEventListener("change",function(){warn.textContent=src.value==="whole-table"?"Whole-table export can be large and may take a while.":"";});
|
|
391
|
+
var d=el("div",{class:"dialog"},[el("h3",{text:"Export data"}),
|
|
392
|
+
el("div",{class:"field"},[el("label",{text:"Source"}),src]),warn,
|
|
393
|
+
el("div",{class:"field"},[el("label",{text:"Columns"}),list]),
|
|
394
|
+
el("div",{class:"field"},[el("label",{text:"Format"}),fmt]),
|
|
395
|
+
el("div",{class:"row right"},[el("button",{class:"btn ghost",text:"Cancel",onclick:closeModal}),el("button",{class:"btn",text:"Export",onclick:function(){
|
|
396
|
+
var selectedColumns=cols.filter(function(c){return checks[c].checked;});if(!selectedColumns.length)return logMsg("Select at least one column.","warn");
|
|
397
|
+
var source=src.value,format=fmt.value;
|
|
398
|
+
if(source==="whole-table"&&!confirm("Export the whole table? This can be large."))return;
|
|
399
|
+
closeModal();
|
|
400
|
+
if(source==="current-page"){exportRowsToFile(selectedColumns,g.rows,format,exportFilename(g,format,"page")).then(function(){logMsg("Exported.","ok");});}
|
|
401
|
+
else if(source==="selected-rows"){var rows=g.rows.filter(function(r){return g.sel[rowKeyOf(g,r)];});if(!rows.length)return logMsg("No rows selected.","warn");exportRowsToFile(selectedColumns,rows,format,exportFilename(g,format,"selected")).then(function(){logMsg("Exported.","ok");});}
|
|
402
|
+
else{exportViaApi(tab,source,format,{selectedColumns:selectedColumns});}
|
|
403
|
+
}})])]);
|
|
404
|
+
openModal(d);}
|
|
405
|
+
function rowContextMenu(e,tab,row){var g=tab.state.g;showCtx(e.clientX,e.clientY,[
|
|
406
|
+
{label:"View row details",icon:"viw",onClick:function(){openCellViewer(row);}},
|
|
407
|
+
{label:"Copy row as JSON",icon:"col",onClick:function(){navigator.clipboard.writeText(JSON.stringify(row,null,2));logMsg("Copied row JSON","ok");}},
|
|
408
|
+
{label:"Copy INSERT statement",icon:"sql",onClick:function(){copyRowDml(g,row,"insert");}},
|
|
409
|
+
{label:"Copy UPDATE statement",icon:"sql",onClick:function(){copyRowDml(g,row,"update");}}
|
|
410
|
+
]);}
|
|
411
|
+
function copyRowDml(g,row,kind){var fields=gridFields(g);var qn='"'+g.schema+'"."'+g.table+'"';function lit(v){return v==null?"NULL":typeof v==="number"?String(v):"'"+String(v).replace(/'/g,"''")+"'";}
|
|
412
|
+
var sql;if(kind==="insert"){sql="INSERT INTO "+qn+" ("+fields.map(function(f){return '"'+f+'"';}).join(", ")+")\\nVALUES ("+fields.map(function(f){return lit(row[f]);}).join(", ")+");";}
|
|
413
|
+
else{var setp=fields.filter(function(f){return g.pk.indexOf(f)<0;}).map(function(f){return '"'+f+'" = '+lit(row[f]);}).join(",\\n ");var wherep=(g.pk.length?g.pk:fields).map(function(f){return '"'+f+'" = '+lit(row[f]);}).join("\\n AND ");sql="UPDATE "+qn+"\\nSET\\n "+setp+"\\nWHERE\\n "+wherep+";";}
|
|
414
|
+
navigator.clipboard.writeText(sql);logMsg("Copied "+kind.toUpperCase()+" statement","ok");}
|
|
350
415
|
function saveDataChanges(tab){var g=tab.state.g;if(S.readOnly)return logMsg("Read-only mode is on.","warn");
|
|
351
416
|
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]};});
|
|
352
417
|
var deletes=Object.keys(g.deletes).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,_k:key};});
|
|
@@ -466,7 +531,7 @@ var PALETTE=[
|
|
|
466
531
|
{label:"Focus Object Explorer",run:function(){var s=document.querySelector("#secTree .tsearch input");if(s)s.focus();else $("topSearch").focus();}},
|
|
467
532
|
{label:"Toggle Read-only",run:function(){toggleReadOnly();}},
|
|
468
533
|
{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")
|
|
534
|
+
{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")exportCurrentPage(t,"csv");}},
|
|
470
535
|
{label:"Close Active Tab",run:function(){if(S.activeTabId)closeTab(S.activeTabId);}},
|
|
471
536
|
{label:"Show Keyboard Shortcuts",run:function(){showShortcuts();}},
|
|
472
537
|
{label:"Open Settings",run:function(){openSettings();}}
|
|
@@ -517,6 +582,7 @@ window.addEventListener("load",function(){
|
|
|
517
582
|
$("querySearch").addEventListener("input",debounce(renderSavedQueries,200));wireSearch($("querySearch"),renderSavedQueries);
|
|
518
583
|
$("topSearch").addEventListener("input",debounce(function(){$("connSearch").value=$("topSearch").value;renderConnections();},200));
|
|
519
584
|
$("btnNewQuery").addEventListener("click",function(){if(!S.activeConnId)return logMsg("Select a connection first.","warn");openSqlTab();});
|
|
585
|
+
Array.prototype.forEach.call(document.querySelectorAll(".searchbox"),function(box){var inp=box.querySelector("input");if(!inp)return;var x=el("span",{class:"sbclr",html:svgFor("x"),title:"Clear (Esc)"});x.addEventListener("click",function(){inp.value="";inp.dispatchEvent(new Event("input"));inp.focus();});inp.addEventListener("input",function(){x.classList.toggle("show",!!inp.value);});box.appendChild(x);});
|
|
520
586
|
setConnStatus("Ready","ok");
|
|
521
587
|
openWelcome();
|
|
522
588
|
loadSettings().then(function(){return loadConnections();}).then(function(){return restoreWorkspace();});
|
|
@@ -695,6 +695,53 @@ export async function startStudioServer(options: TStudioServerOptions = {}): Pro
|
|
|
695
695
|
return;
|
|
696
696
|
}
|
|
697
697
|
|
|
698
|
+
if (pathname === "/api/export/data" && method === "POST") {
|
|
699
|
+
const body = await readJsonBody(req);
|
|
700
|
+
const source = getString(body, "source");
|
|
701
|
+
const format = getString(body, "format") === "json" ? "json" : "csv";
|
|
702
|
+
const schema = getString(body, "schema");
|
|
703
|
+
const table = getString(body, "objectName");
|
|
704
|
+
const selectedColumns = Array.isArray(body.selectedColumns) ? (body.selectedColumns as string[]) : undefined;
|
|
705
|
+
let rows: Array<Record<string, unknown>> = [];
|
|
706
|
+
let fields: string[] = [];
|
|
707
|
+
|
|
708
|
+
if (source === "selected-rows" && Array.isArray(body.selectedRows)) {
|
|
709
|
+
rows = body.selectedRows as Array<Record<string, unknown>>;
|
|
710
|
+
fields = selectedColumns ?? (rows[0] ? Object.keys(rows[0]) : []);
|
|
711
|
+
} else {
|
|
712
|
+
const adapter = await pool.getAdapter(getString(body, "connectionId"));
|
|
713
|
+
const sort = Array.isArray(body.sort) ? (body.sort as TGridSortState[]) : [];
|
|
714
|
+
const isPage = source === "current-page";
|
|
715
|
+
const result = await adapter.getTableData({
|
|
716
|
+
schema,
|
|
717
|
+
table,
|
|
718
|
+
limit: isPage ? getNumber(body, "limit", 100) : 100000,
|
|
719
|
+
offset: isPage ? getNumber(body, "offset", 0) : 0,
|
|
720
|
+
where: source === "whole-table" ? undefined : getString(body, "whereClause") || undefined,
|
|
721
|
+
orderBy: sort[0]?.column,
|
|
722
|
+
orderDirection: sort[0]?.direction === "desc" ? "desc" : "asc",
|
|
723
|
+
});
|
|
724
|
+
rows = result.rows;
|
|
725
|
+
fields = selectedColumns ?? result.fields;
|
|
726
|
+
}
|
|
727
|
+
|
|
728
|
+
if (selectedColumns) {
|
|
729
|
+
rows = rows.map((row) => {
|
|
730
|
+
const picked: Record<string, unknown> = {};
|
|
731
|
+
for (const column of selectedColumns) picked[column] = row[column];
|
|
732
|
+
return picked;
|
|
733
|
+
});
|
|
734
|
+
fields = selectedColumns;
|
|
735
|
+
}
|
|
736
|
+
|
|
737
|
+
if (format === "json") {
|
|
738
|
+
sendText(res, JSON.stringify(rows, null, 2), "application/json; charset=utf-8", `${table || "result"}.json`);
|
|
739
|
+
} else {
|
|
740
|
+
sendText(res, toCsv(fields, rows), "text/csv; charset=utf-8", `${table || "result"}.csv`);
|
|
741
|
+
}
|
|
742
|
+
return;
|
|
743
|
+
}
|
|
744
|
+
|
|
698
745
|
res.writeHead(404, { "content-type": "application/json; charset=utf-8" });
|
|
699
746
|
res.end(JSON.stringify({ error: "Not found" }));
|
|
700
747
|
};
|
|
@@ -61,6 +61,9 @@ svg.ic{width:15px;height:15px;vertical-align:-2px;fill:none;stroke:currentColor;
|
|
|
61
61
|
.searchbox svg{color:var(--faint)}
|
|
62
62
|
.searchbox input{flex:1;background:transparent;border:0;color:var(--text)}
|
|
63
63
|
.searchbox .sbtn{background:transparent;border:0;color:var(--muted);cursor:pointer}
|
|
64
|
+
.searchbox .sbclr{color:var(--faint);cursor:pointer;display:none;flex:0 0 auto}
|
|
65
|
+
.searchbox .sbclr.show{display:inline-flex}
|
|
66
|
+
.searchbox .sbclr:hover{color:var(--text)}
|
|
64
67
|
|
|
65
68
|
/* buttons + inputs */
|
|
66
69
|
.btn{background:var(--accent);border:1px solid var(--accent-2);color:#fff;border-radius:8px;padding:6px 11px;cursor:pointer}
|
|
@@ -254,4 +257,28 @@ mark.hl{background:#facc15;color:#10151f;border-radius:3px;padding:0 1px}
|
|
|
254
257
|
.ac .aci.sel,.ac .aci:hover{background:var(--accent);color:#fff}
|
|
255
258
|
.ac .aci .t{color:var(--faint);font-size:11px}
|
|
256
259
|
.toggle{display:flex;align-items:center;gap:8px;padding:6px 0}
|
|
260
|
+
/* compact data-grid toolbar */
|
|
261
|
+
.gtoolbar{display:flex;align-items:center;gap:6px;padding:7px 10px;border-bottom:1px solid var(--border);background:var(--bg-2);flex:0 0 auto}
|
|
262
|
+
.wherebox{display:flex;align-items:center;gap:6px;flex:1;min-width:120px;background:var(--bg-3);border:1px solid var(--border);border-radius:8px;padding:4px 9px}
|
|
263
|
+
.wherebox svg{color:var(--faint);flex:0 0 auto}
|
|
264
|
+
.wherebox input{flex:1;background:transparent;border:0;color:var(--text);font-family:Consolas,monospace}
|
|
265
|
+
.wherebox .clr{color:var(--faint);cursor:pointer;visibility:hidden;flex:0 0 auto}
|
|
266
|
+
.wherebox.has .clr{visibility:visible}
|
|
267
|
+
.wherebox .clr:hover{color:var(--text)}
|
|
268
|
+
.gbtn{width:32px;height:32px;display:inline-flex;align-items:center;justify-content:center;background:#22304a;border:1px solid var(--border);border-radius:8px;color:#cfe0ff;cursor:pointer;flex:0 0 auto}
|
|
269
|
+
.gbtn:hover{background:#2a3b5a}
|
|
270
|
+
.gbtn.on{border-color:var(--accent);color:#fff;box-shadow:0 0 0 1px var(--accent) inset}
|
|
271
|
+
.gbtn.danger{color:#fca5a5}
|
|
272
|
+
.gbtn.danger:hover{background:#7f1d1d;color:#fff}
|
|
273
|
+
.gbtn:disabled{opacity:.4;cursor:not-allowed}
|
|
274
|
+
.gbtn:disabled:hover{background:#22304a}
|
|
275
|
+
.gbtn.spinning svg{animation:sp .7s linear infinite}
|
|
276
|
+
.gsep{width:1px;height:20px;background:var(--border);margin:0 2px;flex:0 0 auto}
|
|
277
|
+
.gridfoot{display:flex;align-items:center;gap:12px;padding:6px 10px;border-top:1px solid var(--border);background:var(--bg-2);color:var(--muted);font-size:12px;flex:0 0 auto}
|
|
278
|
+
.gridfoot select{background:var(--bg-3);border:1px solid var(--border);border-radius:7px;color:var(--text);padding:3px 7px}
|
|
279
|
+
.gridfoot .pg{display:inline-flex;align-items:center;gap:7px}
|
|
280
|
+
.cnt-u{color:var(--amber)}.cnt-i{color:var(--green)}.cnt-d{color:var(--red)}
|
|
281
|
+
table.grid tr.selrow td{background:var(--sel)}
|
|
282
|
+
.fieldlist{max-height:200px;overflow:auto;border:1px solid var(--border);border-radius:8px;padding:6px}
|
|
283
|
+
.fieldlist label{display:flex;gap:7px;align-items:center;padding:3px 4px;font-size:12.5px}
|
|
257
284
|
`;
|
package/src/index.ts
CHANGED
|
@@ -320,7 +320,7 @@ async function runInstallCommand(options: TInstallCommandOptions): Promise<void>
|
|
|
320
320
|
process.exitCode = installResult.exitCode;
|
|
321
321
|
}
|
|
322
322
|
|
|
323
|
-
program.name("simplemdg").description("SimpleMDG local development helper").version("2.
|
|
323
|
+
program.name("simplemdg").description("SimpleMDG local development helper").version("2.7.0");
|
|
324
324
|
|
|
325
325
|
|
|
326
326
|
program
|