From d79ed0af4827c7cedb435404076fbc0490e1e0b8 Mon Sep 17 00:00:00 2001 From: Andres Hermosilla Date: Thu, 25 Feb 2021 14:47:26 -0800 Subject: [PATCH] #244 Progressively enhance alerts table with filter controls --- site/layouts/alert/list.html | 39 +++++++++------- src/index.js | 91 ++++++++++++++++++++++++++++++++++++ 2 files changed, 112 insertions(+), 18 deletions(-) diff --git a/site/layouts/alert/list.html b/site/layouts/alert/list.html index e2578da45..ea9e5e6dc 100644 --- a/site/layouts/alert/list.html +++ b/site/layouts/alert/list.html @@ -7,24 +7,27 @@

{{ .Title }}

{{ .Content }}
- - - - - - - - - {{ range (.Pages.ByParam "alertindex") }} - - - - - - - - - {{ end }} +
IdAlertStatusRiskType
{{ .Params.alertid }}{{ .Title }}{{ .Params.status }}{{ .Params.risk }}{{ .Params.alerttype }}
+ + + + + + + + + + + {{ range (.Pages.ByParam "alertindex") }} + + + + + + + + {{ end }} +
IdAlertStatusRiskType
{{ .Params.alertid }}{{ .Title }}{{ .Params.status }}{{ .Params.risk }}{{ .Params.alerttype }}
diff --git a/src/index.js b/src/index.js index 05d685340..fe68aad0b 100644 --- a/src/index.js +++ b/src/index.js @@ -8,6 +8,12 @@ new BadgerAccordion(".js-badger-accordion", { openHeadersOnLoad: [0] }); +function removeAllChildNodes(parent) { + while (parent.firstChild) { + parent.removeChild(parent.firstChild); + } +} + document.addEventListener("DOMContentLoaded", function() { // Basic attempt to obfuscate emails Array.from(document.querySelectorAll("[data-mail]")).map(function(el) { @@ -18,6 +24,91 @@ document.addEventListener("DOMContentLoaded", function() { }, {once: true}); }); + // Make tables filterable + Array.from(document.querySelectorAll("[data-sort-filter]")).map(function(el) { + const widget = { + options: {}, + filters: {} + }; + + // Checks if row matches against filter + function isFilterMatch(row) { + for (let index in widget.filters) { + const filter = widget.filters[index].toLowerCase(); + const rowValue = row.columns[index].toLowerCase(); + if (rowValue.indexOf(filter) === -1) { + return false; + } + } + return true; + } + + // Create datalist that input can use for suggetions + function setupDatalist(el, label) { + widget.options[idx] = document.createElement('datalist'); + widget.options[idx].setAttribute('id', 'opts_for_' + label); + widget.options[idx]._options = [] + el.appendChild(widget.options[idx]); + } + + // Add input for filtering + function addInput(el, label) { + const input = document.createElement('input'); + input.addEventListener("change", function(e) { + widget.filters[idx] = e.target.value; + removeAllChildNodes(tbody); + rows.filter(isFilterMatch).map(r => { + tbody.appendChild(r.el) + }); + }); + input.setAttribute('style', 'width:100%;display:block') + input.setAttribute('type', 'text'); + input.setAttribute('name', 'filter_' + label); + input.setAttribute('list', 'opts_for_' + label); + el.appendChild(input); + } + const tbody = el.querySelector('tbody'); + const headings = Array.from(el.querySelectorAll('thead th')).map((el, idx) => { + const isSuggested = el.getAttribute("data-suggest") !== null; + const label = el.innerText.toLowerCase(); + el.appendChild(document.createElement('br')); + addInput(el, label); + + if (isSuggested) { + setupDatalist(el, label); + } + return {idx, isSuggested, label}; + }) + + const rows = Array.from(el.querySelectorAll('tbody tr')).map(tr => { + const columns = Array.from(tr.querySelectorAll('td')).map((c, idx) => { + // For columns that match the index of the `data-suggest` headers + // ... add the text value to options + if (widget.options[idx]) { + widget.options[idx]._options.push(c.innerText) + } + return c.innerText; + }); + return { + el: tr, // Needed for writing to dom + columns, // Needed for filtered + }; + }); + + // Go through options elements and populate lists with column aggregates + // gathered in previous loop + Object.entries(widget.options).map(pair => { + const [idx, el] = pair; + const opts = [...new Set(el._options)]; + opts.sort(); + opts.map(o => { + const ol = document.createElement('option'); + ol.innerText = o; + return ol; + }).map(ol => el.appendChild(ol)); + }); + }); + function clearFilter(menu) { menu.classList.remove("is-filtering"); Array.from(menu.getElementsByTagName('li')).map(function(el) {