diff --git a/CHANGELOG.md b/CHANGELOG.md index d78eac3f..533d8fef 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,7 @@ ml). ## testing - [changed] #218 add reactivit to device lots +- [added] #219 add functionality to searchbar (Lots and devices) - [changed] #211 Print DHID-QR label for selected devices. - [fixed] #214 Login workflow diff --git a/ereuse_devicehub/static/js/api.js b/ereuse_devicehub/static/js/api.js new file mode 100644 index 00000000..ee98a08f --- /dev/null +++ b/ereuse_devicehub/static/js/api.js @@ -0,0 +1,76 @@ +const Api = { + /** + * get lots id + * @returns get lots + */ + async get_lots() { + var request = await this.doRequest(API_URLS.lots, "GET", null); + if (request != undefined) return request.items; + throw request; + }, + + /** + * Get filtered devices info + * @param {number[]} ids devices ids + * @returns full detailed device list + */ + async get_devices(ids) { + var request = await this.doRequest(API_URLS.devices + '?filter={"id": [' + ids.toString() + ']}', "GET", null); + if (request != undefined) return request.items; + throw request; + }, + + /** + * Get filtered devices info + * @param {number[]} ids devices ids + * @returns full detailed device list + */ + async search_device(id) { + var request = await this.doRequest(API_URLS.devices + '?filter={"devicehub_id": ["' + id + '"]}', "GET", null) + if (request != undefined) return request.items + throw request + }, + + /** + * Add devices to lot + * @param {number} lotID lot id + * @param {number[]} listDevices list devices id + */ + async devices_add(lotID, listDevices) { + var queryURL = API_URLS.devices_modify.replace("UUID", lotID) + "?" + listDevices.map(deviceID => "id=" + deviceID).join("&"); + return await Api.doRequest(queryURL, "POST", null); + }, + + /** + * Remove devices from a lot + * @param {number} lotID lot id + * @param {number[]} listDevices list devices id + */ + async devices_remove(lotID, listDevices) { + var queryURL = API_URLS.devices_modify.replace("UUID", lotID) + "?" + listDevices.map(deviceID => "id=" + deviceID).join("&"); + return await Api.doRequest(queryURL, "DELETE", null); + }, + + /** + * + * @param {string} url URL to be requested + * @param {String} type Action type + * @param {String | Object} body body content + * @returns + */ + async doRequest(url, type, body) { + var result; + try { + result = await $.ajax({ + url: url, + type: type, + headers: { "Authorization": API_URLS.Auth_Token }, + body: body + }); + return result; + } catch (error) { + console.error(error); + throw error; + } + } +} \ No newline at end of file diff --git a/ereuse_devicehub/static/js/main.js b/ereuse_devicehub/static/js/main.js index 13646f28..d47c80a9 100644 --- a/ereuse_devicehub/static/js/main.js +++ b/ereuse_devicehub/static/js/main.js @@ -40,7 +40,7 @@ /** * Sidebar toggle */ - if (select('.toggle-sidebar-btn')) { + if (select('.toggle-sidebar-btn')) { on('click', '.toggle-sidebar-btn', function(e) { select('body').classList.toggle('toggle-sidebar') }) @@ -110,10 +110,10 @@ /** * Initiate tooltips */ - var tooltipTriggerList = [].slice.call(document.querySelectorAll('[data-bs-toggle="tooltip"]')) - var tooltipList = tooltipTriggerList.map(function(tooltipTriggerEl) { - return new bootstrap.Tooltip(tooltipTriggerEl) - }) + var tooltipTriggerList = [].slice.call(document.querySelectorAll('[data-bs-toggle="tooltip"]')) + var tooltipList = tooltipTriggerList.map(function(tooltipTriggerEl) { + return new bootstrap.Tooltip(tooltipTriggerEl) + }) /** * Initiate quill editors @@ -141,31 +141,31 @@ }], ["bold", "italic", "underline", "strike"], [{ - color: [] - }, - { - background: [] - } + color: [] + }, + { + background: [] + } ], [{ - script: "super" - }, - { - script: "sub" - } + script: "super" + }, + { + script: "sub" + } ], [{ - list: "ordered" - }, - { - list: "bullet" - }, - { - indent: "-1" - }, - { - indent: "+1" - } + list: "ordered" + }, + { + list: "bullet" + }, + { + indent: "-1" + }, + { + indent: "+1" + } ], ["direction", { align: [] @@ -206,44 +206,44 @@ /** * Autoresize echart charts */ - const mainContainer = select('#main'); - if (mainContainer) { - setTimeout(() => { - new ResizeObserver(function() { - select('.echart', true).forEach(getEchart => { - echarts.getInstanceByDom(getEchart).resize(); - }) - }).observe(mainContainer); - }, 200); - } + const mainContainer = select('#main'); + if (mainContainer) { + setTimeout(() => { + new ResizeObserver(function() { + select('.echart', true).forEach(getEchart => { + echarts.getInstanceByDom(getEchart).resize(); + }) + }).observe(mainContainer); + }, 200); + } /** * Select all functionality */ - var btnSelectAll = document.getElementById("SelectAllBTN"); - var tableListCheckboxes = document.querySelectorAll(".deviceSelect"); + var btnSelectAll = document.getElementById("SelectAllBTN"); + var tableListCheckboxes = document.querySelectorAll(".deviceSelect"); - function itemListCheckChanged(event) { - let isAllChecked = Array.from(tableListCheckboxes).map(itm => itm.checked); - if (isAllChecked.every(bool => bool == true)) { - btnSelectAll.checked = true; - btnSelectAll.indeterminate = false; - } else if (isAllChecked.every(bool => bool == false)) { - btnSelectAll.checked = false; - btnSelectAll.indeterminate = false; - } else { - btnSelectAll.indeterminate = true; - } - } - - tableListCheckboxes.forEach(item => { - item.addEventListener("click", itemListCheckChanged); - }) + function itemListCheckChanged(event) { + let isAllChecked = Array.from(tableListCheckboxes).map(itm => itm.checked); + if (isAllChecked.every(bool => bool == true)) { + btnSelectAll.checked = true; + btnSelectAll.indeterminate = false; + } else if (isAllChecked.every(bool => bool == false)) { + btnSelectAll.checked = false; + btnSelectAll.indeterminate = false; + } else { + btnSelectAll.indeterminate = true; + } + } - btnSelectAll.addEventListener("click", event => { - let checkedState = event.target.checked; - tableListCheckboxes.forEach(ckeckbox => ckeckbox.checked = checkedState); - }) + tableListCheckboxes.forEach(item => { + item.addEventListener("click", itemListCheckChanged); + }) + + btnSelectAll.addEventListener("click", event => { + let checkedState = event.target.checked; + tableListCheckboxes.forEach(ckeckbox => ckeckbox.checked = checkedState); + }) /** * Avoid hide dropdown when user clicked inside @@ -252,4 +252,132 @@ event.stopPropagation(); }) + /** + * Search form functionality + */ + window.addEventListener("DOMContentLoaded", () => { + var searchForm = document.getElementById("SearchForm") + var inputSearch = document.querySelector("#SearchForm > input") + var doSearch = true + + searchForm.addEventListener("submit", (event) => { + event.preventDefault(); + }) + + let timeoutHandler = setTimeout(() => { }, 1) + let dropdownList = document.getElementById("dropdown-search-list") + let defaultEmptySearch = document.getElementById("dropdown-search-list").innerHTML + + + inputSearch.addEventListener("input", (e) => { + clearTimeout(timeoutHandler) + let searchText = e.target.value + if (searchText == '') { + document.getElementById("dropdown-search-list").innerHTML = defaultEmptySearch; + return + } + + let resultCount = 0; + function searchCompleted() { + resultCount++; + if (resultCount < 2 && document.getElementById("dropdown-search-list").children.length > 0) { + setTimeout(() => { + document.getElementById("dropdown-search-list").innerHTML = ` + ` + }, 100) + } + } + + timeoutHandler = setTimeout(async () => { + dropdownList.innerHTML = ` + + `; + + + try { + Api.search_device(searchText.toUpperCase()).then(devices => { + dropdownList.querySelector("#deviceSearchLoader").style = "display: none" + + for (let i = 0; i < devices.length; i++) { + const device = devices[i]; + + // See: ereuse_devicehub/resources/device/models.py + var verboseName = `${device.type} ${device.manufacturer} ${device.model}` + + const templateString = ` +
  • + + + ${verboseName} + ${device.devicehubID} + +
  • `; + dropdownList.innerHTML += templateString + if (i == 4) { // Limit to 4 resullts + break; + } + } + + searchCompleted(); + }) + } catch (error) { + dropdownList.innerHTML += ` + `; + console.log(error); + } + + try { + Api.get_lots().then(lots => { + dropdownList.querySelector("#lotSearchLoader").style = "display: none" + for (let i = 0; i < lots.length; i++) { + const lot = lots[i]; + if (lot.name.toUpperCase().includes(searchText.toUpperCase())) { + const templateString = ` +
  • + + + ${lot.name} + +
  • `; + dropdownList.innerHTML += templateString + if (i == 4) { // Limit to 4 resullts + break; + } + } + } + searchCompleted(); + }) + + } catch (error) { + dropdownList.innerHTML += ` + `; + console.log(error); + } + }, 1000) + }) + }) + })(); diff --git a/ereuse_devicehub/static/js/main_inventory.js b/ereuse_devicehub/static/js/main_inventory.js index 26c68544..75006a2f 100644 --- a/ereuse_devicehub/static/js/main_inventory.js +++ b/ereuse_devicehub/static/js/main_inventory.js @@ -182,77 +182,10 @@ function export_file(type_file) { } - /** * Reactive lots button */ async function processSelectedDevices() { - const Api = { - /** - * get lots id - * @returns get lots - */ - async get_lots() { - var request = await this.doRequest(API_URLS.lots, "GET", null); - if (request != undefined) return request.items; - throw request; - }, - - /** - * Get filtered devices info - * @param {number[]} ids devices ids - * @returns full detailed device list - */ - async get_devices(ids) { - var request = await this.doRequest(API_URLS.devices + '?filter={"id": [' + ids.toString() + ']}', "GET", null); - if (request != undefined) return request.items; - throw request; - }, - - /** - * Add devices to lot - * @param {number} lotID lot id - * @param {number[]} listDevices list devices id - */ - async devices_add(lotID, listDevices) { - var queryURL = API_URLS.devices_modify.replace("UUID", lotID) + "?" + listDevices.map(deviceID => "id=" + deviceID).join("&"); - return await Api.doRequest(queryURL, "POST", null); - }, - - /** - * Remove devices from a lot - * @param {number} lotID lot id - * @param {number[]} listDevices list devices id - */ - async devices_remove(lotID, listDevices) { - var queryURL = API_URLS.devices_modify.replace("UUID", lotID) + "?" + listDevices.map(deviceID => "id=" + deviceID).join("&"); - return await Api.doRequest(queryURL, "DELETE", null); - }, - - /** - * - * @param {string} url URL to be requested - * @param {String} type Action type - * @param {String | Object} body body content - * @returns - */ - async doRequest(url, type, body) { - var result; - try { - result = await $.ajax({ - url: url, - type: type, - headers: { "Authorization": API_URLS.Auth_Token }, - body: body - }); - return result; - } catch (error) { - console.error(error); - throw error; - } - } - } - class Actions { constructor() { diff --git a/ereuse_devicehub/templates/ereuse_devicehub/base.html b/ereuse_devicehub/templates/ereuse_devicehub/base.html index 7b56a1ec..8e147828 100644 --- a/ereuse_devicehub/templates/ereuse_devicehub/base.html +++ b/ereuse_devicehub/templates/ereuse_devicehub/base.html @@ -50,6 +50,20 @@ + + + + diff --git a/ereuse_devicehub/templates/ereuse_devicehub/base_site.html b/ereuse_devicehub/templates/ereuse_devicehub/base_site.html index 900f6f8b..4e721730 100644 --- a/ereuse_devicehub/templates/ereuse_devicehub/base_site.html +++ b/ereuse_devicehub/templates/ereuse_devicehub/base_site.html @@ -12,9 +12,21 @@ @@ -101,81 +113,82 @@