remove grid:local and grid:host targets
This commit is contained in:
parent
09a30911e8
commit
6afa649f20
6 changed files with 2 additions and 310 deletions
|
|
@ -9,7 +9,7 @@ import { client as work } from './client.js';
|
||||||
import { consts, COLOR as color, LISTS as lists } from './consts.js';
|
import { consts, COLOR as color, LISTS as lists } from './consts.js';
|
||||||
import { device, devices } from './devices.js';
|
import { device, devices } from './devices.js';
|
||||||
import { catalog, dialog, event, group, help, hide, image } from './main.js';
|
import { catalog, dialog, event, group, help, hide, image } from './main.js';
|
||||||
import { modal, mode, probe, process, show, space, util, view } from './main.js';
|
import { modal, mode, process, show, space, util, view } from './main.js';
|
||||||
import { local as dataLocal } from '../../data/local.js';
|
import { local as dataLocal } from '../../data/local.js';
|
||||||
import { noop, ajax, o2js, js2o } from './utils.js';
|
import { noop, ajax, o2js, js2o } from './utils.js';
|
||||||
import { functions } from './function.js';
|
import { functions } from './function.js';
|
||||||
|
|
@ -162,7 +162,6 @@ export const api = {
|
||||||
o2js,
|
o2js,
|
||||||
onkey,
|
onkey,
|
||||||
platform,
|
platform,
|
||||||
probe,
|
|
||||||
process,
|
process,
|
||||||
sdb: dataLocal,
|
sdb: dataLocal,
|
||||||
selection,
|
selection,
|
||||||
|
|
|
||||||
|
|
@ -927,8 +927,6 @@ export const conf = {
|
||||||
devel: false,
|
devel: false,
|
||||||
drawer: false,
|
drawer: false,
|
||||||
edgeangle: 20,
|
edgeangle: 20,
|
||||||
exportGhost: false,
|
|
||||||
exportLocal: false,
|
|
||||||
exportOcto: false,
|
exportOcto: false,
|
||||||
exportPreview: false,
|
exportPreview: false,
|
||||||
exportThumb: false,
|
exportThumb: false,
|
||||||
|
|
|
||||||
|
|
@ -218,207 +218,6 @@ function exportGCodeDialog(gcode, sections, info, names) {
|
||||||
ajax.send(form);
|
ajax.send(form);
|
||||||
}
|
}
|
||||||
|
|
||||||
function gridhost_tracker(host,key) {
|
|
||||||
ajax(host+"/api/check?key="+key, function(data) {
|
|
||||||
data = js2o(data);
|
|
||||||
console.log(data);
|
|
||||||
if (!(data.done || data.error)) {
|
|
||||||
setTimeout(function() { gridhost_tracker(host,key) }, 1000);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function gridlocal_probe(ev, devs) {
|
|
||||||
if (ev && ev.code !== 'Enter') return;
|
|
||||||
|
|
||||||
if (!devs && api.probe.local(gridlocal_probe)) return;
|
|
||||||
|
|
||||||
grid_local = devs;
|
|
||||||
|
|
||||||
let gdev = localGet('grid-local');
|
|
||||||
let gloc = $('grid-local');
|
|
||||||
let html = [];
|
|
||||||
for (let uuid in devs) {
|
|
||||||
gdev = gdev || uuid;
|
|
||||||
let dev = devs[uuid];
|
|
||||||
let sel = uuid === gdev ? ' selected' : '';
|
|
||||||
html.push(`<option id="gl-${uuid}" value="${uuid}" ${sel}>${dev.stat.device.name}</option>`);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (html.length) {
|
|
||||||
gloc.innerHTML = html.join('\n');
|
|
||||||
gloc.onchange = (ev) => {
|
|
||||||
localSet('grid-local', gloc.options[gloc.selectedIndex].value);
|
|
||||||
};
|
|
||||||
$('send-to-gridhead').style.display = 'flex';
|
|
||||||
$('send-to-gridspool').style.display = 'flex';
|
|
||||||
} else {
|
|
||||||
$('send-to-gridhead').style.display = '';
|
|
||||||
$('send-to-gridspool').style.display = '';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function sendto_gridlocal() {
|
|
||||||
let uuid = $('grid-local').value;
|
|
||||||
let dev = grid_local[uuid];
|
|
||||||
if (dev) {
|
|
||||||
let file = $('print-filename').value;
|
|
||||||
fetch(
|
|
||||||
`${api.probe.live}/api/grid_send?uuid=${uuid}&file=${encodeURIComponent(file + "." + fileext)}`,
|
|
||||||
{method: "POST", body: gcode}
|
|
||||||
)
|
|
||||||
.then(t => t.text())
|
|
||||||
.then(t => {
|
|
||||||
api.stats.add(`ua_${api.mode.get_lower()}_print_local_ok`);
|
|
||||||
console.log({grid_spool_said: t});
|
|
||||||
})
|
|
||||||
.catch(e => {
|
|
||||||
api.stats.add(`ua_${api.mode.get_lower()}_print_local_err`);
|
|
||||||
console.log({grid_local_spool_error: e});
|
|
||||||
})
|
|
||||||
.finally(() => {
|
|
||||||
api.modal.hide();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function admin_gridlocal() {
|
|
||||||
let dev = grid_local[$('grid-local').value];
|
|
||||||
if (dev && dev.stat && dev.stat.device) {
|
|
||||||
let dsd = dev.stat.device;
|
|
||||||
window.open(`http://${dsd.addr[0]}:${dsd.port || 4080}`, "_grid_admin");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function gridhost_probe(ev, set_host) {
|
|
||||||
if (ev && ev.code !== 'Enter') return;
|
|
||||||
if (!(grid_host && grid_apik)) return;
|
|
||||||
|
|
||||||
if (set_host) grid_host.value = set_host;
|
|
||||||
|
|
||||||
let xhtr = new XMLHttpRequest(),
|
|
||||||
host = grid_host.value,
|
|
||||||
apik = grid_apik.value,
|
|
||||||
target = grid_target.value;
|
|
||||||
|
|
||||||
if (!apik) $('gpapik').style.display = 'none';
|
|
||||||
|
|
||||||
if (!host && api.probe.grid(gridhost_probe)) return;
|
|
||||||
|
|
||||||
if (!host) return;
|
|
||||||
|
|
||||||
xhtr.onreadystatechange = function() {
|
|
||||||
if (xhtr.readyState === 4) {
|
|
||||||
if (xhtr.status >= 200 && xhtr.status < 300) {
|
|
||||||
localSet('grid-host', host);
|
|
||||||
localSet('grid-apik', apik);
|
|
||||||
let res = JSON.parse(xhtr.responseText);
|
|
||||||
let sel = false;
|
|
||||||
let match = false;
|
|
||||||
let first = null;
|
|
||||||
let html = [];
|
|
||||||
grid_targets = {};
|
|
||||||
for (let key in res) {
|
|
||||||
first = first || key;
|
|
||||||
if (!localGet('grid-target')) {
|
|
||||||
localSet('grid-target', key);
|
|
||||||
sel = true;
|
|
||||||
} else {
|
|
||||||
sel = localGet('grid-target') === key;
|
|
||||||
}
|
|
||||||
match = match || sel;
|
|
||||||
grid_targets[html.length] = key;
|
|
||||||
html.push(
|
|
||||||
"<option id='gpo-'" + key + " value='" +key + "'" +
|
|
||||||
(sel ? " selected" : "") +
|
|
||||||
">" +
|
|
||||||
(res[key].comment || key) +
|
|
||||||
"</option>"
|
|
||||||
);
|
|
||||||
}
|
|
||||||
if (!match) {
|
|
||||||
localSet('grid-target', first);
|
|
||||||
}
|
|
||||||
grid_target.innerHTML = html.join('\n');
|
|
||||||
} else if (xhtr.status === 401) {
|
|
||||||
$('gpapik').style.display = '';
|
|
||||||
} else {
|
|
||||||
local.removeItem('grid-host');
|
|
||||||
local.removeItem('grid-apik');
|
|
||||||
console.log("invalid grid:host url");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
xhtr.open("GET", host + "/api/active?key=" + apik);
|
|
||||||
xhtr.send();
|
|
||||||
}
|
|
||||||
|
|
||||||
function sendto_gridhost() {
|
|
||||||
if (!(grid_host && grid_apik)) return;
|
|
||||||
|
|
||||||
let xhtr = new XMLHttpRequest(),
|
|
||||||
host = grid_host.value,
|
|
||||||
apik = grid_apik.value,
|
|
||||||
target = localGet('grid-target') || '';
|
|
||||||
|
|
||||||
if (target === '') {
|
|
||||||
api.show.alert('invalid or missing target');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (host.indexOf("http") !== 0) {
|
|
||||||
api.show.alert("host missing protocol (http:// or https://)");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (host.indexOf("://") < 0) {
|
|
||||||
api.show.alert("host:port malformed");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (api.const.SECURE && !api.util.isSecure(host)) {
|
|
||||||
api.show.alert("host must begin with 'https' on a secure site");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
localSet('grid-host', host.trim());
|
|
||||||
localSet('grid-apik', apik.trim());
|
|
||||||
|
|
||||||
xhtr.onreadystatechange = function() {
|
|
||||||
if (xhtr.readyState === 4) {
|
|
||||||
let status = xhtr.status;
|
|
||||||
api.stats.add(`ua_${api.mode.get_lower()}_print_grid_${status}`);
|
|
||||||
if (status >= 200 && status < 300) {
|
|
||||||
let json = js2o(xhtr.responseText);
|
|
||||||
gridhost_tracker(host,json.key);
|
|
||||||
api.ajax(host+"/api/wait?key="+json.key, function(data) {
|
|
||||||
data = js2o(data);
|
|
||||||
console.log(data);
|
|
||||||
api.show.alert("print to "+target+": "+data.status, 600);
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
api.show.alert("grid:host error\nstatus: "+status+"\nmessage: "+xhtr.responseText, 10000);
|
|
||||||
}
|
|
||||||
api.show.progress(0);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
xhtr.upload.addEventListener('progress', function(evt) {
|
|
||||||
api.show.progress(evt.loaded/evt.total, "sending");
|
|
||||||
});
|
|
||||||
filename = $('print-filename').value;
|
|
||||||
xhtr.open("POST",
|
|
||||||
host + "/api/print?" +
|
|
||||||
"filename=" + filename +
|
|
||||||
"&target=" + target +
|
|
||||||
"&key=" + apik +
|
|
||||||
"&time=" + Math.round(info.time) +
|
|
||||||
"&length=" + Math.round(info.distance) +
|
|
||||||
"&image=" + filename
|
|
||||||
);
|
|
||||||
xhtr.setRequestHeader("Content-Type", "text/plain");
|
|
||||||
let snapshot = api.view.snapshot;
|
|
||||||
xhtr.send(snapshot ? [gcode,snapshot].join("\0") : gcode);
|
|
||||||
api.modal.hide();
|
|
||||||
}
|
|
||||||
|
|
||||||
function download() {
|
function download() {
|
||||||
filename = $('print-filename').value;
|
filename = $('print-filename').value;
|
||||||
api.util.download(gcode, filename + "." + fileext);
|
api.util.download(gcode, filename + "." + fileext);
|
||||||
|
|
@ -463,8 +262,6 @@ function exportGCodeDialog(gcode, sections, info, names) {
|
||||||
let set = api.conf.get();
|
let set = api.conf.get();
|
||||||
let fdm = MODE === MODES.FDM;
|
let fdm = MODE === MODES.FDM;
|
||||||
let octo = set.controller.exportOcto && MODE !== MODES.CAM;
|
let octo = set.controller.exportOcto && MODE !== MODES.CAM;
|
||||||
let ghost = set.controller.exportGhost;
|
|
||||||
let local = set.controller.exportLocal;
|
|
||||||
let preview = set.controller.exportPreview;
|
let preview = set.controller.exportPreview;
|
||||||
$('code-preview-head').style.display = preview ? '' : 'none';
|
$('code-preview-head').style.display = preview ? '' : 'none';
|
||||||
$('code-preview').style.display = preview ? '' : 'none';
|
$('code-preview').style.display = preview ? '' : 'none';
|
||||||
|
|
@ -484,8 +281,6 @@ function exportGCodeDialog(gcode, sections, info, names) {
|
||||||
// persist fields when changed
|
// persist fields when changed
|
||||||
bindField('octo-host', 'octo-host');
|
bindField('octo-host', 'octo-host');
|
||||||
bindField('octo-apik', 'octo-apik');
|
bindField('octo-apik', 'octo-apik');
|
||||||
bindField('grid-host', 'grid-host');
|
|
||||||
bindField('grid-apik', 'grid-apik');
|
|
||||||
|
|
||||||
// in cam mode, show zip file option
|
// in cam mode, show zip file option
|
||||||
let downloadZip = $('print-zip');
|
let downloadZip = $('print-zip');
|
||||||
|
|
@ -699,37 +494,11 @@ function exportGCodeDialog(gcode, sections, info, names) {
|
||||||
$('ophost').style.display = 'none';
|
$('ophost').style.display = 'none';
|
||||||
$('opapik').style.display = 'none';
|
$('opapik').style.display = 'none';
|
||||||
$('oph1nt').style.display = 'none';
|
$('oph1nt').style.display = 'none';
|
||||||
$('send-to-gridhost').style.display = 'none';
|
|
||||||
}
|
}
|
||||||
octo_host.value = localGet('octo-host') || '';
|
octo_host.value = localGet('octo-host') || '';
|
||||||
octo_apik.value = localGet('octo-apik') || '';
|
octo_apik.value = localGet('octo-apik') || '';
|
||||||
} catch (e) { console.log(e) }
|
} catch (e) { console.log(e) }
|
||||||
|
|
||||||
// grid:host setup
|
|
||||||
$('send-to-hosthead').style.display = ghost ? '' : 'none';
|
|
||||||
$('send-to-gridhost').style.display = ghost ? '' : 'none';
|
|
||||||
if (ghost) try {
|
|
||||||
$('print-gridhost').onclick = sendto_gridhost;
|
|
||||||
$('grid-host').onkeyup = gridhost_probe;
|
|
||||||
$('grid-apik').onkeyup = gridhost_probe;
|
|
||||||
grid_host = $('grid-host');
|
|
||||||
grid_apik = $('grid-apik');
|
|
||||||
grid_target = $('grid-target');
|
|
||||||
grid_target.onchange = function(ev) {
|
|
||||||
localSet('grid-target', grid_targets[grid_target.selectedIndex]);
|
|
||||||
};
|
|
||||||
grid_host.value = localGet('grid-host') || '';
|
|
||||||
grid_apik.value = localGet('grid-apik') || '';
|
|
||||||
gridhost_probe();
|
|
||||||
} catch (e) { console.log(e) }
|
|
||||||
|
|
||||||
// grid:local setup
|
|
||||||
if (local) try {
|
|
||||||
gridlocal_probe();
|
|
||||||
$('print-gridlocal').onclick = sendto_gridlocal;
|
|
||||||
$('admin-gridlocal').onclick = admin_gridlocal;
|
|
||||||
} catch (e) { console.log(e) }
|
|
||||||
|
|
||||||
// preview of the generated GCODE (first 64k max)
|
// preview of the generated GCODE (first 64k max)
|
||||||
if (preview && gcode) $('code-preview-textarea').value = gcode.substring(0,65535);
|
if (preview && gcode) $('code-preview-textarea').value = gcode.substring(0,65535);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -155,8 +155,6 @@ function booleanSave() {
|
||||||
control.reverseZoom = ui.reverseZoom.checked;
|
control.reverseZoom = ui.reverseZoom.checked;
|
||||||
control.dark = ui.dark.checked;
|
control.dark = ui.dark.checked;
|
||||||
control.exportOcto = ui.exportOcto.checked;
|
control.exportOcto = ui.exportOcto.checked;
|
||||||
control.exportGhost = ui.exportGhost.checked;
|
|
||||||
control.exportLocal = ui.exportLocal.checked;
|
|
||||||
control.exportThumb = ui.exportThumb.checked;
|
control.exportThumb = ui.exportThumb.checked;
|
||||||
control.exportPreview = ui.exportPreview.checked;
|
control.exportPreview = ui.exportPreview.checked;
|
||||||
control.healMesh = ui.healMesh.checked;
|
control.healMesh = ui.healMesh.checked;
|
||||||
|
|
@ -904,7 +902,6 @@ function init_one() {
|
||||||
xany: $('mod-x-any'),
|
xany: $('mod-x-any'),
|
||||||
xsla: $('mod-x-sla'),
|
xsla: $('mod-x-sla'),
|
||||||
xlaser: $('mod-x-laser'),
|
xlaser: $('mod-x-laser'),
|
||||||
local: $('mod-local'),
|
|
||||||
don8: $('mod-don8'),
|
don8: $('mod-don8'),
|
||||||
any: $('mod-any'),
|
any: $('mod-any'),
|
||||||
},
|
},
|
||||||
|
|
@ -1058,8 +1055,6 @@ function init_one() {
|
||||||
spaceRandoX: newBoolean(LANG.op_spcx_s, booleanSave, {title:LANG.op_spcx_l, show:isBelt}),
|
spaceRandoX: newBoolean(LANG.op_spcx_s, booleanSave, {title:LANG.op_spcx_l, show:isBelt}),
|
||||||
spaceLayout: newInput(LANG.op_spcr_s, {title:LANG.op_spcr_l, convert:toFloat, size:3, units}),
|
spaceLayout: newInput(LANG.op_spcr_s, {title:LANG.op_spcr_l, convert:toFloat, size:3, units}),
|
||||||
_____: newGroup(LANG.xp_menu, $('prefs-xpo'), {inline: true}),
|
_____: newGroup(LANG.xp_menu, $('prefs-xpo'), {inline: true}),
|
||||||
exportLocal: newBoolean(`Grid:Local`, booleanSave, {title:LANG.op_exgl_l}),
|
|
||||||
exportGhost: newBoolean(`Grid:Host`, booleanSave, {title:LANG.op_exgh_l}),
|
|
||||||
exportOcto: newBoolean(`OctoPrint`, booleanSave, {title:LANG.op_exop_l}),
|
exportOcto: newBoolean(`OctoPrint`, booleanSave, {title:LANG.op_exop_l}),
|
||||||
exportThumb: newBoolean(`Thumbnail`, booleanSave, {modes:FDM}),
|
exportThumb: newBoolean(`Thumbnail`, booleanSave, {modes:FDM}),
|
||||||
exportPreview: newBoolean(`Code Preview`, booleanSave),
|
exportPreview: newBoolean(`Code Preview`, booleanSave),
|
||||||
|
|
|
||||||
|
|
@ -114,12 +114,6 @@ export const mode = {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
export const probe = {
|
|
||||||
live: "https://live.grid.space",
|
|
||||||
grid: noop,
|
|
||||||
local: noop
|
|
||||||
};
|
|
||||||
|
|
||||||
export const process = {
|
export const process = {
|
||||||
code: currentProcessCode,
|
code: currentProcessCode,
|
||||||
get: currentProcessName
|
get: currentProcessName
|
||||||
|
|
@ -784,43 +778,7 @@ function showHelpFile(local,then) {
|
||||||
}
|
}
|
||||||
|
|
||||||
function showLocal() {
|
function showLocal() {
|
||||||
showModal('local');
|
// deprecated
|
||||||
api.probe.local((err,data) => {
|
|
||||||
let devc = 0;
|
|
||||||
let bind = [];
|
|
||||||
let html = ['<table>'];
|
|
||||||
html.push(`<thead><tr><th>device</th><th>type</th><th>status</th><th></th></tr></thead>`);
|
|
||||||
html.push(`<tbody>`);
|
|
||||||
let recs = [];
|
|
||||||
for (let k in data) {
|
|
||||||
recs.push(data[k].stat);
|
|
||||||
}
|
|
||||||
recs.sort((a,b) => {
|
|
||||||
return a.device.name < b.device.name ? -1 : 1;
|
|
||||||
});
|
|
||||||
for (let r of recs) {
|
|
||||||
bind.push({uuid: r.device.uuid, host: r.device.addr[0], port: r.device.port});
|
|
||||||
html.push(`<tr>`);
|
|
||||||
html.push(`<td>${r.device.name}</td>`);
|
|
||||||
html.push(`<td>${r.device.mode}</td>`);
|
|
||||||
html.push(`<td>${r.state}</td>`);
|
|
||||||
html.push(`<td><button id="${r.device.uuid}">admin</button></td>`);
|
|
||||||
html.push(`</tr>`);
|
|
||||||
devc++;
|
|
||||||
}
|
|
||||||
html.push(`</tbody>`);
|
|
||||||
html.push(`</table>`);
|
|
||||||
if (devc) {
|
|
||||||
$('mod-local').innerHTML = html.join('');
|
|
||||||
} else {
|
|
||||||
$('mod-local').innerHTML = `<br><b>no local devices</b>`;
|
|
||||||
}
|
|
||||||
bind.forEach(rec => {
|
|
||||||
$(rec.uuid).onclick = () => {
|
|
||||||
window.open(`http://${rec.host}:${rec.port||4080}/`);
|
|
||||||
};
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function setViewMode(mode) {
|
function setViewMode(mode) {
|
||||||
|
|
|
||||||
|
|
@ -612,8 +612,6 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- grid local list -->
|
|
||||||
<div id="mod-local" class="mdialog f-col"></div>
|
|
||||||
<!-- export dialogs -->
|
<!-- export dialogs -->
|
||||||
<div id="mod-x-any" class="mod-print mdialog f-col">
|
<div id="mod-x-any" class="mod-print mdialog f-col">
|
||||||
<div class="f-row gap4">
|
<div class="f-row gap4">
|
||||||
|
|
@ -667,31 +665,6 @@
|
||||||
</div>
|
</div>
|
||||||
<div id="oph1nt"><label class="hint"><a href="http://docs.octoprint.org/en/master/api/general.html?highlight=cors#cross-origin-requests" target="_help">CORS support</a> must be enabled in API settings</label></div>
|
<div id="oph1nt"><label class="hint"><a href="http://docs.octoprint.org/en/master/api/general.html?highlight=cors#cross-origin-requests" target="_help">CORS support</a> must be enabled in API settings</label></div>
|
||||||
</div>
|
</div>
|
||||||
<div id="send-to-hosthead" class="header"><label>grid:host</label></div>
|
|
||||||
<div id="send-to-gridhost" class="f-col box">
|
|
||||||
<div class="grow f-row">
|
|
||||||
<div class="f-col grow">
|
|
||||||
<div><label>host</label><input id="grid-host" size="20" placeholder="http(s)://host:port" /></div>
|
|
||||||
<div id="gpapik"><label>api key</label><input id="grid-apik" size="20" /></div>
|
|
||||||
<div><label>target</label><select id="grid-target"></select></div>
|
|
||||||
</div>
|
|
||||||
<button id="print-gridhost">send</button>
|
|
||||||
</div>
|
|
||||||
<div><label class="hint">setup <a href="https://github.com/GridSpace/grid-host" target="_help">grid:host</a> for your network</label></div>
|
|
||||||
</div>
|
|
||||||
<div id="send-to-gridhead" class="header noshow"><label>grid:local</label></div>
|
|
||||||
<div id="send-to-gridspool" class="f-row box noshow">
|
|
||||||
<div class="grow f-row">
|
|
||||||
<div class="grow a-center j-center">
|
|
||||||
<label>target</label>
|
|
||||||
<select id="grid-local"></select>
|
|
||||||
</div>
|
|
||||||
<div class="f-col">
|
|
||||||
<button id="print-gridlocal">send</button>
|
|
||||||
<button id="admin-gridlocal">admin</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
<div id="mod-x-sla" class="mod-print mdialog f-col">
|
<div id="mod-x-sla" class="mod-print mdialog f-col">
|
||||||
<div class="header"><label>export</label></div>
|
<div class="header"><label>export</label></div>
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue