Wider details dialog, Card fields dialog like device details, no sideways chip scroll
- Details dialog is wider so the device name is never cut off. - Overview list rows use the USMT Status colors (row color, ping color). - Workbench on phones: the stack header no longer sits over the device list. - Card fields uses the device-details dialog frame; bolder arrows; x to remove. - Filter chips wrap onto more lines instead of scrolling sideways.
This commit is contained in:
1 parent
9c21567f6d
commit
7242f8f8af
4 files changed
+54
-24
No files matched your search
+19
-13
@@ -657,8 +657,10 @@
|
||||
document.addEventListener('mousedown', e => {
|
||||
if (menu && !menu.contains(e.target) && !(e.target.closest && e.target.closest('.xf-btn, .xf-chip, .col-filter-btn'))) closeMenu();
|
||||
}, true);
|
||||
window.addEventListener('scroll', () => { if (menu && !menu.classList.contains('xf-sheet')) closeMenu(); }, { passive: true });
|
||||
window.addEventListener('resize', closeMenu);
|
||||
// the card-field dialog stays open through scrolling and the phone keyboard resizing the page
|
||||
const keepOpen = () => menuCtx && menuCtx.fields;
|
||||
window.addEventListener('scroll', () => { if (menu && !keepOpen() && !menu.classList.contains('xf-sheet')) closeMenu(); }, { passive: true });
|
||||
window.addEventListener('resize', () => { if (!keepOpen()) closeMenu(); });
|
||||
|
||||
// ------------------------------------------------------------------------------------
|
||||
// Custom View card fields (phones/tablets): choose and order what each card shows
|
||||
@@ -666,11 +668,14 @@
|
||||
function openFieldEditor() {
|
||||
closeMenu();
|
||||
if (typeof customColumns === 'undefined') return;
|
||||
backdrop = el('div', 'xf-backdrop'); backdrop.onclick = closeMenu;
|
||||
menu = el('div', 'xf-menu xf-sheet xf-fields-sheet');
|
||||
// Same frame as the device details dialog: under the nav, full width on phones
|
||||
backdrop = el('div', 'modal-overlay xf-fields-overlay');
|
||||
backdrop.style.display = 'block';
|
||||
backdrop.onclick = e => { if (e.target === backdrop) closeMenu(); };
|
||||
menu = el('div', 'modal-content xf-fields-sheet');
|
||||
menuCtx = { fields: true };
|
||||
backdrop.appendChild(menu);
|
||||
document.body.appendChild(backdrop);
|
||||
document.body.appendChild(menu);
|
||||
document.addEventListener('keydown', onMenuKey, true);
|
||||
renderFieldEditor();
|
||||
}
|
||||
@@ -679,10 +684,10 @@
|
||||
if (!menu) return;
|
||||
const label = id => { try { return getCustomColDef(id).label; } catch (e) { return id; } };
|
||||
menu.innerHTML = '';
|
||||
const head = el('div', 'xf-head');
|
||||
head.appendChild(el('span', 'xf-title', 'Card fields'));
|
||||
const x = el('button', 'xf-x', '×'); x.type = 'button'; x.onclick = closeMenu;
|
||||
const head = el('div', 'modal-header');
|
||||
const x = el('span', 'close-modal', '\u00d7'); x.title = 'Close'; x.onclick = closeMenu;
|
||||
head.appendChild(x);
|
||||
head.appendChild(el('h2', 'xf-fields-title', 'Card fields'));
|
||||
menu.appendChild(head);
|
||||
menu.appendChild(el('div', 'xf-hint', 'Choose what each card shows and in what order. The first field is the card title.'));
|
||||
|
||||
@@ -691,14 +696,15 @@
|
||||
const row = el('div', 'xf-field');
|
||||
row.appendChild(el('span', 'xf-field-name', label(id)));
|
||||
if (i === 0) row.appendChild(el('span', 'xf-badge', 'Title'));
|
||||
const btn = (txt, title, fn, disabled) => {
|
||||
const b = el('button', 'xf-mini', txt); b.type = 'button'; b.title = title; b.disabled = !!disabled;
|
||||
const btn = (svg, title, fn, disabled, cls) => {
|
||||
const b = el('button', 'xf-mini' + (cls ? ' ' + cls : '')); b.type = 'button'; b.title = title; b.disabled = !!disabled;
|
||||
b.innerHTML = svg; b.setAttribute('aria-label', title);
|
||||
b.onclick = () => { fn(); renderFieldEditor(); };
|
||||
row.appendChild(b);
|
||||
};
|
||||
btn('↑', 'Move up', () => moveCustomColumn(i, i - 1), i === 0);
|
||||
btn('↓', 'Move down', () => moveCustomColumn(i, i + 1), i === customColumns.length - 1);
|
||||
btn('−', 'Remove from cards', () => toggleCustomColumn(id), customColumns.length <= 1);
|
||||
btn('<svg viewBox="0 0 16 16" aria-hidden="true"><path d="M8 13V3M3.5 7.5 8 3l4.5 4.5" fill="none" stroke="currentColor" stroke-width="2.4" stroke-linecap="round" stroke-linejoin="round"/></svg>', 'Move up', () => moveCustomColumn(i, i - 1), i === 0);
|
||||
btn('<svg viewBox="0 0 16 16" aria-hidden="true"><path d="M8 3v10M3.5 8.5 8 13l4.5-4.5" fill="none" stroke="currentColor" stroke-width="2.4" stroke-linecap="round" stroke-linejoin="round"/></svg>', 'Move down', () => moveCustomColumn(i, i + 1), i === customColumns.length - 1);
|
||||
btn('<svg viewBox="0 0 16 16" aria-hidden="true"><path d="M4 4l8 8M12 4l-8 8" fill="none" stroke="currentColor" stroke-width="2.4" stroke-linecap="round"/></svg>', 'Remove from cards', () => toggleCustomColumn(id), customColumns.length <= 1, 'xf-mini-x');
|
||||
shown.appendChild(row);
|
||||
});
|
||||
menu.appendChild(shown);
|
||||
|
||||
+1
-1
@@ -2877,7 +2877,7 @@
|
||||
detailsBody.style.minHeight = '0';
|
||||
detailsBody.style.padding = '0';
|
||||
} else {
|
||||
modalContent.style.maxWidth = '550px';
|
||||
modalContent.style.maxWidth = '680px';
|
||||
modalContent.style.width = '85%';
|
||||
modalContent.style.height = 'auto';
|
||||
modalContent.style.maxHeight = 'calc(100vh - 100px)';
|
||||
|
||||
+26
-7
@@ -23,6 +23,10 @@ table.xf-table thead tr.filter-row { display: none !important; }
|
||||
|
||||
.master-table:not(#table-custom) thead { position: sticky; top: var(--sticky-top, 112px); z-index: 20; }
|
||||
|
||||
/* A Workbench stack never needs to scroll sideways, and a sideways-scrolling box captures its
|
||||
sticky header (which then sits over the device list on phones) */
|
||||
.stack-box.table-wrapper { overflow: visible !important; }
|
||||
|
||||
@media (min-width: 1101px) {
|
||||
/* An overflowing wrapper would capture the sticky header; these tables never need to
|
||||
scroll sideways at desktop widths (they're fixed-layout, 100% wide) */
|
||||
@@ -223,9 +227,6 @@ body { padding-bottom: var(--dock-h, 40px) !important; }
|
||||
.modal-header { padding: 14px 14px 8px; }
|
||||
.modal-header h2 { font-size: 1.2em; word-break: break-all; }
|
||||
|
||||
/* Details title: the Advanced/Simple View button gets its own line under the device
|
||||
name instead of floating over the content */
|
||||
#detailsTitle button { float: none !important; display: block; margin: 10px 0 0 !important; font-size: 0.65em !important; }
|
||||
|
||||
/* Device details: Advanced View's source / overview / destination columns stack,
|
||||
and the whole dialog scrolls instead of each column scrolling separately */
|
||||
@@ -332,7 +333,7 @@ table.xf-table thead th:has(> .xf-btn):not(.sortable-th) { position: relative; p
|
||||
.xf-bar { display: none; }
|
||||
@media (max-width: 1100px) {
|
||||
.xf-bar {
|
||||
display: flex; gap: 6px; padding: 8px 10px; overflow-x: auto; scrollbar-width: none;
|
||||
display: flex; flex-wrap: wrap; gap: 6px; padding: 8px 10px; overflow: visible; /* chips wrap: no sideways scrolling */
|
||||
position: sticky; top: var(--sticky-top, 112px); z-index: 25;
|
||||
background: linear-gradient(rgba(0,0,0,0.15), rgba(0,0,0,0.15)), var(--bg-card);
|
||||
border-bottom: 1px solid var(--border-color); box-shadow: 0 4px 8px rgba(0,0,0,0.25);
|
||||
@@ -360,6 +361,23 @@ table.xf-table thead th:has(> .xf-btn):not(.sortable-th) { position: relative; p
|
||||
background: transparent; color: inherit; border: 1px solid var(--border-color); border-radius: 6px;
|
||||
}
|
||||
.xf-mini:disabled { opacity: 0.3; cursor: default; }
|
||||
.xf-mini { display: inline-flex; align-items: center; justify-content: center; padding: 0; }
|
||||
.xf-mini svg { width: 17px; height: 17px; }
|
||||
.xf-mini:hover:not(:disabled) { border-color: #3498db; color: #3498db; }
|
||||
.xf-mini.xf-mini-x:hover:not(:disabled) { border-color: #e74c3c; color: #e74c3c; }
|
||||
|
||||
/* Card fields: the same dialog frame as the device details */
|
||||
.xf-fields-overlay .modal-content.xf-fields-sheet {
|
||||
width: 85%; max-width: 550px; margin: 80px auto 20px; max-height: calc(100vh - 100px); max-height: calc(100dvh - 100px);
|
||||
display: flex; flex-direction: column; overflow: hidden; font-size: 15px;
|
||||
}
|
||||
.xf-fields-sheet .modal-header { flex: none; }
|
||||
.xf-fields-sheet .xf-fields-title { margin: 0; }
|
||||
.xf-fields-sheet .xf-hint { padding: 12px 20px 8px; }
|
||||
.xf-fields-sheet .xf-fields { padding: 0 20px; }
|
||||
.xf-fields-sheet .xf-add { padding: 0 20px; }
|
||||
.xf-fields-sheet .xf-actions { padding: 12px 20px 16px; }
|
||||
.xf-fields-sheet .xf-actions button { flex: 1; padding: 11px; }
|
||||
.xf-add { display: flex; flex-direction: column; flex: 1 1 auto; min-height: 0; margin-top: 8px; }
|
||||
.xf-fields-sheet .xf-list { flex: 1 1 auto; min-height: 110px; }
|
||||
.xf-fields-sheet .xf-add .xf-search { flex: none; }
|
||||
@@ -476,9 +494,10 @@ a.nav-brand:hover h2 { color: #d6eaf8; }
|
||||
a.nav-brand:focus-visible { outline: 2px solid #3498db; outline-offset: 3px; }
|
||||
|
||||
/* Device details title: name on the left, Simple / Advanced View toggle on the right, one line */
|
||||
#detailsTitle { display: flex; align-items: center; gap: 12px; flex-wrap: nowrap; padding-right: 10px; min-width: 0; }
|
||||
/* the name gives way (ellipsis) so the toggle never drops to a second line */
|
||||
#detailsTitle .dt-name { flex: 1 1 auto; min-width: 0; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
|
||||
/* The dialog is wide enough for name + toggle on one line; on a phone that can't fit both,
|
||||
the toggle moves under the name rather than cutting the name off */
|
||||
#detailsTitle { display: flex; align-items: center; gap: 12px; flex-wrap: wrap; padding-right: 10px; min-width: 0; }
|
||||
#detailsTitle .dt-name { flex: 0 1 auto; min-width: 0; white-space: nowrap; }
|
||||
#detailsTitle .dt-name .copy-row-btn { vertical-align: middle; }
|
||||
#detailsTitle .dt-toggle { flex: 0 0 auto; }
|
||||
#detailsTitle .dt-toggle {
|
||||
|
||||
+8
-3
@@ -568,9 +568,14 @@
|
||||
const td = (t, bold) => { const c = el('td'); if (bold) c.appendChild(el('b', null, t)); else c.textContent = t; c.title = t; return c; };
|
||||
row.appendChild(td(r['Source Device'], true));
|
||||
row.appendChild(td(r['Destination Device'] || 'N/A'));
|
||||
row.appendChild(td(statusOf(r)));
|
||||
row.appendChild(td(String(detail || '')));
|
||||
row.appendChild(td(statusOf(r), true));
|
||||
const dc = td(String(detail || ''));
|
||||
// ping values colored like the USMT Status page
|
||||
if (/^(Online|Timed Out|Not Found|DNS Issue)$/.test(String(detail || '')) && typeof getPingColor === 'function') { dc.style.color = getPingColor(detail); dc.style.fontWeight = 'bold'; }
|
||||
row.appendChild(dc);
|
||||
row.appendChild(td(r.Tags || 'None'));
|
||||
// same row colors as the USMT Status page
|
||||
try { const bg = themes[currentTheme].groupColors[r['Backup Status']]; if (bg) row.style.backgroundColor = bg; } catch (e) {}
|
||||
row.onclick = () => showDeviceDetails(r['Source Device']);
|
||||
tb.appendChild(row);
|
||||
});
|
||||
@@ -641,7 +646,7 @@
|
||||
function signature() {
|
||||
const a = g('apiData'), sc = g('softwareCache') || {}, docs = g('availableDocs') || [];
|
||||
return [Array.isArray(a) ? a.length : 0, JSON.stringify(a || []).length, Object.keys(g('advancedDataCache') || {}).length,
|
||||
Object.keys(sc).length, docs.length, g('globalDataLastUpdated'), Math.floor(Date.now() / 300000)].join('|');
|
||||
Object.keys(sc).length, docs.length, g('globalDataLastUpdated'), g('currentTheme'), Math.floor(Date.now() / 300000)].join('|');
|
||||
}
|
||||
function maybeRender(force) {
|
||||
if (!visible()) return;
|
||||
|
||||
Reference in new issue
Block a user