feat: machine pages Порты, Статус, Изменить as dialogs over the current page; Действие column in the ports table
This commit is contained in:
1 parent
2009796421
commit
d92696226e
11 files changed
+141
-5
No files matched your search
@@ -0,0 +1,88 @@
|
||||
// Порты, Статус and Изменить of a machine in a dialog over the current page:
|
||||
// the server's pages as fragments, so nothing behind is lost. They open from
|
||||
// the buttons of a machine's row, and from a menu on a tab's title or a
|
||||
// pane's title bar (a right click, or a long press on a phone). Closing the
|
||||
// dialog unmounts the fragment's module: its charts and polling stop.
|
||||
(function () {
|
||||
'use strict';
|
||||
const TITLES = {forwards: 'Порты', status: 'Статус', edit: 'Изменить'};
|
||||
const dlg = document.getElementById('machinedlg');
|
||||
const area = dlg.querySelector('.frag-area');
|
||||
const page = /^\/agents\/([^/]+)\/(forwards|status|edit)$/;
|
||||
let changed = false;
|
||||
|
||||
function open(id, what, name) {
|
||||
dlg.querySelector('.md-title').textContent = (name || id) + ' · ' + TITLES[what];
|
||||
App.put(area, '<p class="muted" style="padding:16px 18px">загрузка…</p>');
|
||||
if (!dlg.open) (window.FileViews ? FileViews.openModal(dlg) : dlg.showModal());
|
||||
App.load(area, '/agents/' + encodeURIComponent(id) + '/' + what);
|
||||
}
|
||||
dlg.addEventListener('close', () => {
|
||||
App.put(area, '');
|
||||
// A form sent in the dialog (a new name, say) shows in the list behind.
|
||||
if (changed && document.querySelector('main#app').dataset.view === 'machines') App.go('/', false);
|
||||
changed = false;
|
||||
});
|
||||
dlg.querySelector('.md-close').onclick = () => dlg.close();
|
||||
// «Изменить» drawn again after a new name: the title follows it.
|
||||
new MutationObserver(() => {
|
||||
const h = area.querySelector('[data-module="edit"] .wrap > h1');
|
||||
if (h) dlg.querySelector('.md-title').textContent = h.textContent.trim() + ' · ' + TITLES.edit;
|
||||
}).observe(area, {childList: true});
|
||||
dlg.addEventListener('submit', () => { changed = true; });
|
||||
// The fragment's own links: another page of a machine stays in the dialog,
|
||||
// anything else closes it and goes on as usual.
|
||||
area.addEventListener('click', ev => {
|
||||
const a = ev.target.closest('a[href]');
|
||||
if (!a || ev.button !== 0 || ev.metaKey || ev.ctrlKey || ev.shiftKey || a.target || a.hasAttribute('download')) return;
|
||||
const u = new URL(a.href, location.href), m = page.exec(u.pathname);
|
||||
if (u.origin !== location.origin) return;
|
||||
if (m) { ev.preventDefault(); ev.stopPropagation(); App.load(area, u.pathname + u.search); return; }
|
||||
dlg.close();
|
||||
}, true);
|
||||
document.addEventListener('click', ev => {
|
||||
const b = ev.target.closest('[data-dialog]');
|
||||
if (!b || ev.button !== 0 || ev.metaKey || ev.ctrlKey || ev.shiftKey) return;
|
||||
ev.preventDefault();
|
||||
open(b.dataset.id, b.dataset.dialog, b.dataset.name);
|
||||
});
|
||||
|
||||
// menu: Порты, Статус, Изменить of agent, by the pointer.
|
||||
const menu = document.createElement('div');
|
||||
menu.className = 'addmenu mdmenu';
|
||||
menu.hidden = true;
|
||||
document.body.appendChild(menu);
|
||||
function closeMenu() { menu.hidden = true; document.removeEventListener('pointerdown', outside, true); }
|
||||
function outside(ev) { if (!menu.contains(ev.target)) closeMenu(); }
|
||||
function showMenu(ev, agent) {
|
||||
ev.preventDefault();
|
||||
menu.innerHTML = '';
|
||||
const head = document.createElement('div');
|
||||
head.className = 'muted md-head';
|
||||
head.textContent = agent.name;
|
||||
menu.appendChild(head);
|
||||
Object.keys(TITLES).forEach(k => {
|
||||
const b = document.createElement('button');
|
||||
b.type = 'button'; b.className = 'item';
|
||||
b.innerHTML = '<span><b></b></span>';
|
||||
b.querySelector('b').textContent = TITLES[k];
|
||||
b.onclick = () => { closeMenu(); open(agent.id, k, agent.name); };
|
||||
menu.appendChild(b);
|
||||
});
|
||||
menu.hidden = false;
|
||||
const m = menu.getBoundingClientRect();
|
||||
menu.style.left = Math.max(8, Math.min(innerWidth - m.width - 8, ev.clientX)) + 'px';
|
||||
menu.style.top = Math.max(8, Math.min(innerHeight - m.height - 8, ev.clientY)) + 'px';
|
||||
setTimeout(() => document.addEventListener('pointerdown', outside, true), 0);
|
||||
}
|
||||
document.addEventListener('keydown', ev => { if (ev.key === 'Escape' && !menu.hidden) closeMenu(); });
|
||||
|
||||
// A machine page asked for by its address: the machines view with it open.
|
||||
const m = window.APP && window.APP.dialog && page.exec(window.APP.dialog);
|
||||
if (m) {
|
||||
const row = document.querySelector('[data-open][data-id="' + CSS.escape(m[1]) + '"]');
|
||||
history.replaceState({}, '', '/');
|
||||
open(m[1], m[2], row ? row.dataset.name : m[1]);
|
||||
}
|
||||
window.MachineDialog = {open, menu: showMenu};
|
||||
})();
|
||||
Reference in new issue
Block a user