diff --git a/ereuse_devicehub/static/js/main_inventory.js b/ereuse_devicehub/static/js/main_inventory.js index 86c25a82..11b0dc31 100644 --- a/ereuse_devicehub/static/js/main_inventory.js +++ b/ereuse_devicehub/static/js/main_inventory.js @@ -1,4 +1,4 @@ -$(document).ready(function() { +$(document).ready(function () { var show_allocate_form = $("#allocateModal").data('show-action-form'); var show_datawipe_form = $("#datawipeModal").data('show-action-form'); var show_trade_form = $("#tradeLotModal").data('show-action-form'); @@ -71,9 +71,9 @@ function removeLot() { function removeTag() { var devices = $(".deviceSelect").filter(':checked'); - var devices_id = $.map(devices, function(x) { return $(x).attr('data')}); + var devices_id = $.map(devices, function (x) { return $(x).attr('data') }); if (devices_id.length == 1) { - var url = "/inventory/tag/devices/"+devices_id[0]+"/del/"; + var url = "/inventory/tag/devices/" + devices_id[0] + "/del/"; window.location.href = url; } else { $("#unlinkTagAlertModal").click(); @@ -82,7 +82,7 @@ function removeTag() { function addTag() { var devices = $(".deviceSelect").filter(':checked'); - var devices_id = $.map(devices, function(x) { return $(x).attr('data')}); + var devices_id = $.map(devices, function (x) { return $(x).attr('data') }); if (devices_id.length == 1) { $("#addingTagModal .pol").hide(); $("#addingTagModal .btn-primary").show(); @@ -146,8 +146,8 @@ function get_device_list() { $("#actionModal .devices-count").html(devices_count); /* Insert the correct value in the input devicesList */ - var devices_id = $.map(devices, function(x) { return $(x).attr('data')}).join(","); - $.map($(".devicesList"), function(x) { + var devices_id = $.map(devices, function (x) { return $(x).attr('data') }).join(","); + $.map($(".devicesList"), function (x) { $(x).val(devices_id); }); @@ -166,17 +166,250 @@ function get_device_list() { return typ + " " + manuf + " " + dhid; }); - description = $.map(list_devices, function(x) { return x }).join(", "); + description = $.map(list_devices, function (x) { return x }).join(", "); $(".enumeration-devices").html(description); } function export_file(type_file) { var devices = $(".deviceSelect").filter(':checked'); - var devices_id = $.map(devices, function(x) { return $(x).attr('data-device-dhid')}).join(","); - if (devices_id){ - var url = "/inventory/export/"+type_file+"/?ids="+devices_id; + var devices_id = $.map(devices, function (x) { return $(x).attr('data-device-dhid') }).join(","); + if (devices_id) { + var url = "/inventory/export/" + type_file + "/?ids=" + devices_id; window.location.href = url; } else { $("#exportAlertModal").click(); } } + + + +/** + * Añade reactividad al botón de lotes + */ +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 () { + this.list = [] // list of petitions of requests @item --> {type: ["Remove" | "Add"], "LotID": string, "devices": number[]} + } + + /** + * Manage the actions that will be performed when applying the changes + * @param {*} ev event (Should be a checkbos type) + * @param {string} lotID lot id + * @param {number} deviceID device id + */ + manage(event, lotID, deviceListID) { + const checked = event.srcElement.checked + + var found = this.list.filter(list => list.lotID == lotID)[0] + + if (checked) { + if (found != undefined && found.type == "Remove") { + this.list = this.list.filter(list => list.lotID != lotID) + } else { + this.list.push({ type: "Add", lotID: lotID, devices: deviceListID }) + } + } else { + if (found != undefined && found.type == "Add") { + this.list = this.list.filter(list => list.lotID != lotID) + } else { + this.list.push({ type: "Remove", lotID: lotID, devices: deviceListID }) + } + } + + if (this.list.length > 0) { + document.getElementById("ApplyDeviceLots").classList.remove("disabled") + } else { + document.getElementById("ApplyDeviceLots").classList.add("disabled") + } + } + + /** + * Creates notification to give feedback to user + * @param {string} title notification title + * @param {string | null} toastText notification text + * @param {boolean} isError defines if a toast is a error + */ + notifyUser(title, toastText, isError) { + let toast = document.createElement("div") + toast.classList = "alert alert-dismissible fade show " + (isError ? "alert-danger" : "alert-success") + toast.attributes["data-autohide"] = !isError + toast.attributes["role"] = "alert" + toast.style = "margin-left: auto; width: fit-content;" + toast.innerHTML = `${title}` + if (toastText && toastText.length > 0) { + toast.innerHTML += `
${toastText}` + } + + document.getElementById("NotificationsContainer").appendChild(toast) + if (!isError) { + setTimeout(() => toast.classList.remove("show"), 3000) + setTimeout(() => toast.remove(), 3500) + } + } + + /** + * Get actions and execute call request to add or remove devices from lots + */ + doActions() { + this.list.forEach(async action => { + if (action.type == "Add") { + try { + await Api.devices_add(action.lotID, action.devices) + this.notifyUser("Devices sucefully aded to selected lot/s", "", false) + } catch (error) { + this.notifyUser("Failed to add devices to selected lot/s", error.responseJSON.message, true) + } + } else if (action.type == "Remove") { + try { + await Api.devices_remove(action.lotID, action.devices) + this.notifyUser("Devices sucefully removed from selected lot/s", "", false) + } catch (error) { + this.notifyUser("Fail to remove devices from selected lot/s", error.responseJSON.message, true) + } + } + }) + } + } + + var eventClickActions; + + /** + * Generates a list item with a correspondient checkbox state + * @param {String} lotID + * @param {String} lotName + * @param {Array} selectedDevicesIDs + * @param {HTMLElement} target + */ + function templateLot(lotID, lot, selectedDevicesIDs, elementTarget, actions) { + elementTarget.innerHTML = "" + + var htmlTemplate = ` + `; + + var existLotList = selectedDevicesIDs.map(selected => lot.devices.includes(selected)) + + var doc = document.createElement('li') + doc.innerHTML = htmlTemplate + + if (selectedDevicesIDs.length <= 0) { + doc.children[0].disabled = true + } else if (existLotList.every(value => value == true)) { + doc.children[0].checked = true + } else if (existLotList.every(value => value == false)) { + doc.children[0].checked = false + } else { + doc.children[0].indeterminate = true; + } + + doc.children[0].addEventListener('change', (ev) => actions.manage(ev, lotID, selectedDevicesIDs)) + elementTarget.append(doc) + } + + var listHTML = $("#LotsSelector") + + // Get selected devices + var selectedDevicesIDs = $.map($(".deviceSelect").filter(':checked'), function (x) { return parseInt($(x).attr('data')) }) + if (selectedDevicesIDs.length <= 0) { + listHTML.html('
  • No devices selected
  • ') + return + } + + // Initialize Actions list, and set checkbox triggers + var actions = new Actions() + if (eventClickActions) { + document.getElementById("ApplyDeviceLots").removeEventListener(eventClickActions) + } + eventClickActions = document.getElementById("ApplyDeviceLots").addEventListener("click", () => actions.doActions()) + document.getElementById("ApplyDeviceLots").classList.add("disabled") + + try { + listHTML.html('
  • ') + var devices = await Api.get_devices(selectedDevicesIDs) + var lots = await Api.get_lots() + + lots = lots.map(lot => { + lot.devices = devices + .filter(device => device.lots.filter(devicelot => devicelot.id == lot.id).length > 0) + .map(device => parseInt(device.id)) + return lot + }) + + listHTML.html('') + lots.forEach(lot => templateLot(lot.id, lot, selectedDevicesIDs, listHTML, actions)) + } catch (error) { + console.log(error) + listHTML.html('
  • Error feching devices and lots
    (see console for more details)
  • ') + } + + +} \ No newline at end of file diff --git a/ereuse_devicehub/templates/inventory/device_list.html b/ereuse_devicehub/templates/inventory/device_list.html index 157dda05..3168616e 100644 --- a/ereuse_devicehub/templates/inventory/device_list.html +++ b/ereuse_devicehub/templates/inventory/device_list.html @@ -71,25 +71,20 @@ {% endif %}
    -