diff --git a/CHANGELOG.md b/CHANGELOG.md index bf4a03f1..806a01b4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,10 +8,33 @@ ml). ## master ## testing + +## [2.1.0] - 2022-05-11 - [added] #219 Add functionality to searchbar (Lots and devices). +- [added] #222 Allow user to update its password. +- [added] #233 Filter in out trades from lots selector. +- [added] #236 Allow select multiple devices in multiple pages. +- [added] #237 Confirmation dialog on apply lots changes. +- [added] #238 Customize labels. +- [added] #242 Add icons in list of devices. +- [added] #244 Select full devices. +- [added] #257 Add functionality to search generic categories like all components. +- [added] #252 new tabs lots and public link in details of one device. - [changed] #211 Print DHID-QR label for selected devices. - [changed] #218 Add reactivity to device lots. +- [changed] #220 Add reactive lots list. +- [changed] #232 Set max lots list to 20. +- [changed] #235 Hide trade buttons. +- [changed] #239 Change Tags for Unique Identifier. +- [changed] #247 Change colors. +- [changed] #253 Drop download public links. - [fixed] #214 Login workflow +- [fixed] #221 Fix responsive issues on frontend. +- [fixed] #223 fix trade lots modal. +- [fixed] #224 fix clickable lots selector not working when click in text. +- [fixed] #254 Fix minor types in frontend. +- [fixed] #255 Fix status column on device list. + ## [2.0.0] - 2022-03-15 First server render HTML version. Completely rewrites views of angular JS client on flask. diff --git a/ereuse_devicehub/__init__.py b/ereuse_devicehub/__init__.py index 4bf535c4..28c957cd 100644 --- a/ereuse_devicehub/__init__.py +++ b/ereuse_devicehub/__init__.py @@ -1 +1 @@ -__version__ = "2.1.0.dev" +__version__ = "2.2.0.alpha0" diff --git a/ereuse_devicehub/inventory/forms.py b/ereuse_devicehub/inventory/forms.py index d58fcaf9..062d185c 100644 --- a/ereuse_devicehub/inventory/forms.py +++ b/ereuse_devicehub/inventory/forms.py @@ -52,16 +52,30 @@ from ereuse_devicehub.resources.user.exceptions import InsufficientPermission from ereuse_devicehub.resources.user.models import User DEVICES = { - "All": ["All"], + "All": ["All Devices", "All Components"], "Computer": [ + "All Computers", "Desktop", "Laptop", "Server", ], - "Monitor": ["ComputerMonitor", "Monitor", "TelevisionSet", "Projector"], - "Mobile, tablet & smartphone": ["Mobile", "Tablet", "Smartphone", "Cellphone"], - "DataStorage": ["HardDrive", "SolidStateDrive"], + "Monitor": [ + "All Monitors", + "ComputerMonitor", + "Monitor", + "TelevisionSet", + "Projector", + ], + "Mobile, tablet & smartphone": [ + "All Mobile", + "Mobile", + "Tablet", + "Smartphone", + "Cellphone", + ], + "DataStorage": ["All DataStorage", "HardDrive", "SolidStateDrive"], "Accessories & Peripherals": [ + "All Peripherals", "GraphicCard", "Motherboard", "NetworkAdapter", @@ -75,26 +89,104 @@ DEVICES = { ], } +COMPUTERS = ['Desktop', 'Laptop', 'Server'] + +COMPONENTS = [ + 'GraphicCard', + 'DataStorage', + 'HardDrive', + 'DataStorage', + 'SolidStateDrive', + 'Motherboard', + 'NetworkAdapter', + 'Processor', + 'RamModule', + 'SoundCard', + 'Display', + 'Battery', + 'Camera', +] + +MONITORS = ["ComputerMonitor", "Monitor", "TelevisionSet", "Projector"] +MOBILE = ["Mobile", "Tablet", "Smartphone", "Cellphone"] +DATASTORAGE = ["HardDrive", "SolidStateDrive"] +PERIPHERALS = [ + "GraphicCard", + "Motherboard", + "NetworkAdapter", + "Processor", + "RamModule", + "SoundCard", + "Battery", + "Keyboard", + "Mouse", + "MemoryCardReader", +] + class FilterForm(FlaskForm): filter = SelectField( - '', choices=DEVICES, default="Computer", render_kw={'class': "form-select"} + '', choices=DEVICES, default="All Computers", render_kw={'class': "form-select"} ) - def __init__(self, *args, **kwargs): + def __init__(self, lots, lot_id, *args, **kwargs): super().__init__(*args, **kwargs) + self.lots = lots + self.lot_id = lot_id + self._get_types() + + def _get_types(self): types_of_devices = [item for sublist in DEVICES.values() for item in sublist] dev = request.args.get('filter') - self.device = dev if dev in types_of_devices else None - if self.device: - self.filter.data = self.device + self.device_type = dev if dev in types_of_devices else None + if self.device_type: + self.filter.data = self.device_type + + def filter_from_lots(self): + if self.lot_id: + self.lot = self.lots.filter(Lot.id == self.lot_id).one() + device_ids = (d.id for d in self.lot.devices) + self.devices = Device.query.filter(Device.id.in_(device_ids)) + else: + self.devices = Device.query.filter(Device.owner_id == g.user.id).filter_by( + lots=None + ) def search(self): + self.filter_from_lots() + filter_type = None + if self.device_type: + filter_type = [self.device_type] + else: + # Case without Filter + filter_type = COMPUTERS - if self.device: - return [self.device] + # Generic Filters + if "All Devices" == self.device_type: + filter_type = COMPUTERS + ["Monitor"] + MOBILE - return ['Desktop', 'Laptop', 'Server'] + elif "All Components" == self.device_type: + filter_type = COMPONENTS + + elif "All Computers" == self.device_type: + filter_type = COMPUTERS + + elif "All Monitors" == self.device_type: + filter_type = MONITORS + + elif "All Mobile" == self.device_type: + filter_type = MOBILE + + elif "All DataStorage" == self.device_type: + filter_type = DATASTORAGE + + elif "All Peripherals" == self.device_type: + filter_type = PERIPHERALS + + if filter_type: + self.devices = self.devices.filter(Device.type.in_(filter_type)) + + return self.devices.order_by(Device.updated.desc()) class LotForm(FlaskForm): diff --git a/ereuse_devicehub/inventory/views.py b/ereuse_devicehub/inventory/views.py index 2df8fd69..a09f4f5b 100644 --- a/ereuse_devicehub/inventory/views.py +++ b/ereuse_devicehub/inventory/views.py @@ -43,8 +43,8 @@ class DeviceListMix(GenericMixView): def get_context(self, lot_id): super().get_context() lots = self.context['lots'] - form_filter = FilterForm() - filter_types = form_filter.search() + form_filter = FilterForm(lots, lot_id) + devices = form_filter.search() lot = None tags = ( Tag.query.filter(Tag.owner_id == current_user.id) @@ -54,10 +54,6 @@ class DeviceListMix(GenericMixView): if lot_id: lot = lots.filter(Lot.id == lot_id).one() - devices = lot.devices - if "All" not in filter_types: - devices = [dev for dev in lot.devices if dev.type in filter_types] - devices = sorted(devices, key=lambda x: x.updated, reverse=True) form_new_action = NewActionForm(lot=lot.id) form_new_allocate = AllocateForm(lot=lot.id) form_new_datawipe = DataWipeForm(lot=lot.id) @@ -67,20 +63,6 @@ class DeviceListMix(GenericMixView): user_from=g.user.email, ) else: - if "All" in filter_types: - devices = ( - Device.query.filter(Device.owner_id == current_user.id) - .filter_by(lots=None) - .order_by(Device.updated.desc()) - ) - else: - devices = ( - Device.query.filter(Device.owner_id == current_user.id) - .filter_by(lots=None) - .filter(Device.type.in_(filter_types)) - .order_by(Device.updated.desc()) - ) - form_new_action = NewActionForm() form_new_allocate = AllocateForm() form_new_datawipe = DataWipeForm() diff --git a/ereuse_devicehub/static/js/main_inventory.js b/ereuse_devicehub/static/js/main_inventory.js index c8159c83..5db11bdd 100644 --- a/ereuse_devicehub/static/js/main_inventory.js +++ b/ereuse_devicehub/static/js/main_inventory.js @@ -83,25 +83,33 @@ window.addEventListener("DOMContentLoaded", () => { const alertInfoDevices = document.getElementById("select-devices-info"); function itemListCheckChanged() { - const listDevices = TableController.getAllDevicesInCurrentPage() - const isAllChecked = listDevices.map(itm => itm.checked); - - if (isAllChecked.every(bool => bool == true)) { - btnSelectAll.checked = true; - btnSelectAll.indeterminate = false; - alertInfoDevices.innerHTML = `Selected devices: ${TableController.getSelectedDevices().length} + alertInfoDevices.innerHTML = `Selected devices: ${TableController.getSelectedDevices().length} ${TableController.getAllDevices().length != TableController.getSelectedDevices().length ? `Select all devices (${TableController.getAllDevices().length})` : "Cancel selection" }`; - alertInfoDevices.classList.remove("d-none"); - } else if (isAllChecked.every(bool => bool == false)) { - btnSelectAll.checked = false; - btnSelectAll.indeterminate = false; + + if (TableController.getSelectedDevices().length <= 0) { alertInfoDevices.classList.add("d-none") } else { + alertInfoDevices.classList.remove("d-none"); + } + + if (TableController.getAllDevices().length == TableController.getSelectedDevices().length) { + btnSelectAll.checked = true; + btnSelectAll.indeterminate = false; + } else if(TableController.getAllSelectedDevicesInCurrentPage().length > 0) { btnSelectAll.indeterminate = true; - alertInfoDevices.classList.add("d-none") + } else { + btnSelectAll.checked = false; + btnSelectAll.indeterminate = false; + } + + if (TableController.getAllDevices().length == 0) { + btnSelectAll.checked = false; + btnSelectAll.disabled = true; + } else { + btnSelectAll.disabled = false; } } @@ -125,6 +133,8 @@ window.addEventListener("DOMContentLoaded", () => { table.on("datatable.page", () => itemListCheckChanged()); table.on("datatable.perpage", () => itemListCheckChanged()); table.on("datatable.update", () => itemListCheckChanged()); + + itemListCheckChanged(); }) function deviceSelect() { diff --git a/ereuse_devicehub/templates/ereuse_devicehub/user_login.html b/ereuse_devicehub/templates/ereuse_devicehub/user_login.html index f010e3d7..f6423759 100644 --- a/ereuse_devicehub/templates/ereuse_devicehub/user_login.html +++ b/ereuse_devicehub/templates/ereuse_devicehub/user_login.html @@ -60,7 +60,7 @@
-

Don't have account? Create an account

+

Don't have account? Create an account

@@ -83,4 +83,18 @@ + + + {% endblock body %} diff --git a/ereuse_devicehub/templates/inventory/device_list.html b/ereuse_devicehub/templates/inventory/device_list.html index ef8f7aef..2b1d5cec 100644 --- a/ereuse_devicehub/templates/inventory/device_list.html +++ b/ereuse_devicehub/templates/inventory/device_list.html @@ -84,7 +84,7 @@