Excel-style column filters, full-page Custom View, card field editor
Filters (web/excel-filter.js), modeled on Excel's AutoFilter: - Every column header gets a dropdown: Sort A to Z / Z to A, Clear Filter From "<column>", Search, a checkbox list of the column's values with (Select All) and (Blanks), OK / Cancel. Values come from rows passing the other columns' filters; filters on several columns combine. Tags and software lists are split into individual items. - The button shows a funnel when filtered and an arrow when sorted, and a "Clear filters (n)" button appears beside the group's copy buttons - Replaces the old per-column filter row (which also removes the gap between header and filter rows); hooks the existing filter passes so global search, counts and worker re-renders keep working - Menus are fixed-position on <body>, so sticky headers and neighbouring tables can't cover them; on phones they open as a bottom sheet - Workbench stacks get the same menus (sorting done client-side) - Custom View's filter icon opens the same menu Layout: - Sticky headers use separated borders so no hairline gap opens - Phones/tablets: a sticky bar of column chips (with active counts and "Clear all") opens the filter menus - Custom View fills the page like the other views on desktop; it still scrolls sideways when wide, with its header pinned under the group header - Custom View on phones/tablets: a "Card fields" sheet to choose, order and remove the fields shown on each card Demo: first visit puts 6 PCs (one per migration stage) on the Workbench.
This commit is contained in:
1 parent
d24be4a2d6
commit
b216ce43f2
5 files changed
+788
-99
No files matched your search
@@ -937,6 +937,35 @@
|
||||
let seen = false;
|
||||
try { seen = localStorage.getItem('usmt_demo_seen') === '1'; } catch (e) {}
|
||||
if (!seen) this.about(true);
|
||||
this.seedWorkbench();
|
||||
},
|
||||
|
||||
// First visit: put 6 PCs on the Workbench (one per migration stage) so it isn't empty.
|
||||
// Only when the visitor has no saved stacks; "Reset my changes" clears them again.
|
||||
async seedWorkbench() {
|
||||
try { if (localStorage.getItem('usmt_workbench_stacks')) return; } catch (e) { return; }
|
||||
for (let i = 0; i < 60; i++) {
|
||||
if (typeof apiData !== 'undefined' && apiData.filter(r => r["Backup Status"] && r["Backup Status"] !== "No Data").length > 20) break;
|
||||
await sleep(500);
|
||||
}
|
||||
if (typeof apiData === 'undefined' || typeof myStacks === 'undefined') return;
|
||||
try { if (localStorage.getItem('usmt_workbench_stacks')) return; } catch (e) { return; } // created meanwhile
|
||||
|
||||
const wanted = ["Backup In Progress", "Restore In Progress", "Backup Completed", "Completed", "Not Started", "Not Associated"];
|
||||
const picks = [];
|
||||
for (const status of wanted) {
|
||||
const row = apiData.find(r => r["Backup Status"] === status && !picks.includes(r["Source Device"])
|
||||
&& (status === "Completed" || r["Source Online"] === "Online"));
|
||||
if (row) picks.push(row["Source Device"]);
|
||||
}
|
||||
for (const r of apiData) { // top up to 6 if a stage is empty
|
||||
if (picks.length >= 6) break;
|
||||
if (!["Skipped", "No Data"].includes(r["Backup Status"]) && !picks.includes(r["Source Device"])) picks.push(r["Source Device"]);
|
||||
}
|
||||
if (!picks.length) return;
|
||||
myStacks = [{ id: 1, name: "Stack 1", list: picks.slice(0, 6).join('\n') }];
|
||||
saveAndRender();
|
||||
myStacks.forEach(st => refreshStackTable(st.id));
|
||||
},
|
||||
about(show) {
|
||||
this.modal.classList.toggle('show', show);
|
||||
|
||||
Reference in new issue
Block a user