Merge pull request #406 from eReuse/feature/4092-erasure-tabs
Feature/4092 erasure tabs
This commit is contained in:
commit
5d8c26ade6
|
@ -12,6 +12,7 @@ ml).
|
||||||
- [added] #387 add template settings for Secure Erasure.
|
- [added] #387 add template settings for Secure Erasure.
|
||||||
- [added] #397 add obada standard export.
|
- [added] #397 add obada standard export.
|
||||||
- [added] #402 add reset password module.
|
- [added] #402 add reset password module.
|
||||||
|
- [added] #406 add orphans disks page.
|
||||||
- [changed] #391 add dhid in table and export of Erasure section.
|
- [changed] #391 add dhid in table and export of Erasure section.
|
||||||
- [changed] #395 change response for the new api to workbench.
|
- [changed] #395 change response for the new api to workbench.
|
||||||
- [changed] #396 modularize commands.
|
- [changed] #396 modularize commands.
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
__version__ = "2.4.2"
|
__version__ = "2.4.3"
|
||||||
|
|
|
@ -115,15 +115,19 @@ class DeviceListMixin(GenericMixin):
|
||||||
class ErasureListView(DeviceListMixin):
|
class ErasureListView(DeviceListMixin):
|
||||||
template_name = 'inventory/erasure_list.html'
|
template_name = 'inventory/erasure_list.html'
|
||||||
|
|
||||||
def dispatch_request(self):
|
def dispatch_request(self, orphans=0):
|
||||||
self.get_context()
|
self.get_context()
|
||||||
self.get_devices()
|
self.get_devices(orphans)
|
||||||
|
if orphans:
|
||||||
|
self.context['orphans'] = True
|
||||||
return flask.render_template(self.template_name, **self.context)
|
return flask.render_template(self.template_name, **self.context)
|
||||||
|
|
||||||
def get_devices(self):
|
def get_devices(self, orphans):
|
||||||
erasure = EraseBasic.query.filter_by(author=g.user).order_by(
|
erasure = EraseBasic.query.filter_by(author=g.user).order_by(
|
||||||
EraseBasic.created.desc()
|
EraseBasic.created.desc()
|
||||||
)
|
)
|
||||||
|
if orphans:
|
||||||
|
erasure = [e for e in erasure if e.device.orphan]
|
||||||
self.context['erasure'] = erasure
|
self.context['erasure'] = erasure
|
||||||
|
|
||||||
|
|
||||||
|
@ -1452,3 +1456,7 @@ devices.add_url_rule(
|
||||||
devices.add_url_rule(
|
devices.add_url_rule(
|
||||||
'/device/erasure/', view_func=ErasureListView.as_view('device_erasure_list')
|
'/device/erasure/', view_func=ErasureListView.as_view('device_erasure_list')
|
||||||
)
|
)
|
||||||
|
devices.add_url_rule(
|
||||||
|
'/device/erasure/<int:orphans>/',
|
||||||
|
view_func=ErasureListView.as_view('device_erasure_list_orphans'),
|
||||||
|
)
|
||||||
|
|
|
@ -1326,6 +1326,19 @@ class DataStorage(JoinedComponentTableMixin, Component):
|
||||||
except LookupError:
|
except LookupError:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
@property
|
||||||
|
def orphan(self):
|
||||||
|
if not self.parent:
|
||||||
|
return True
|
||||||
|
|
||||||
|
if self.parent.placeholder and self.parent.placeholder.kangaroo:
|
||||||
|
return True
|
||||||
|
|
||||||
|
if self.parent.binding and self.parent.binding.kangaroo:
|
||||||
|
return True
|
||||||
|
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
class HardDrive(DataStorage):
|
class HardDrive(DataStorage):
|
||||||
pass
|
pass
|
||||||
|
|
|
@ -306,7 +306,7 @@ class LotDeviceView(LotBaseChildrenView):
|
||||||
dev_qry = Device.query.filter(Device.id.in_(ids)).filter(Device.owner == g.user)
|
dev_qry = Device.query.filter(Device.id.in_(ids)).filter(Device.owner == g.user)
|
||||||
|
|
||||||
for dev in dev_qry:
|
for dev in dev_qry:
|
||||||
if isinstance(dev, DataStorage) and dev.parent:
|
if isinstance(dev, DataStorage) and not dev.orphan:
|
||||||
continue
|
continue
|
||||||
devices.add(dev)
|
devices.add(dev)
|
||||||
|
|
||||||
|
|
|
@ -18,9 +18,54 @@
|
||||||
|
|
||||||
<div class="card">
|
<div class="card">
|
||||||
<div class="card-body pt-3" style="min-height: 650px;">
|
<div class="card-body pt-3" style="min-height: 650px;">
|
||||||
<div class="tab-content pt-1">
|
<ul class="nav nav-tabs nav-tabs-bordered">
|
||||||
|
|
||||||
|
<li class="nav-item">
|
||||||
|
<a href="{{ url_for('inventory.device_erasure_list') }}" class="nav-link{% if not orphans %} active{% endif %}">
|
||||||
|
All hard drivers
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
|
||||||
|
<li class="nav-item">
|
||||||
|
<a href="{{ url_for('inventory.device_erasure_list_orphans', orphans=1) }}" class="nav-link{% if orphans %} active{% endif %}">
|
||||||
|
Hard drives without device
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
|
||||||
|
</ul>
|
||||||
|
<div class="tab-content pt-2">
|
||||||
<div id="devices-list" class="tab-pane fade devices-list active show">
|
<div id="devices-list" class="tab-pane fade devices-list active show">
|
||||||
<label class="btn btn-primary " for="SelectAllBTN"><input type="checkbox" id="SelectAllBTN" autocomplete="off"></label>
|
<label class="btn btn-primary " for="SelectAllBTN"><input type="checkbox" id="SelectAllBTN" autocomplete="off"></label>
|
||||||
|
{% if orphans %}
|
||||||
|
<div class="btn-group dropdown ml-1">
|
||||||
|
<button id="btnLots" type="button" onclick="processSelectedDevices()" class="btn btn-primary dropdown-toggle" data-bs-toggle="dropdown" aria-expanded="false">
|
||||||
|
<i class="bi bi-folder2"></i>
|
||||||
|
Lots
|
||||||
|
<span class="caret"></span>
|
||||||
|
</button>
|
||||||
|
<span class="d-none" id="activeTradeModal" data-bs-toggle="modal" data-bs-target="#tradeLotModal"></span>
|
||||||
|
|
||||||
|
<ul class="dropdown-menu" aria-labelledby="btnLots" id="dropDownLotsSelector">
|
||||||
|
<div class="row w-100">
|
||||||
|
<div class="input-group mb-3 mx-2">
|
||||||
|
<div class="input-group-prepend">
|
||||||
|
<span class="input-group-text" id="basic-addon1"><i class="bi bi-search"></i></span>
|
||||||
|
</div>
|
||||||
|
<input type="text" class="form-control" id="lots-search" placeholder="search" aria-label="search" aria-describedby="basic-addon1">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<h6 class="dropdown-header">Select lots where to store the selected devices</h6>
|
||||||
|
<ul class="mx-3" id="LotsSelector"></ul>
|
||||||
|
<li><hr /></li>
|
||||||
|
<li>
|
||||||
|
<a href="#" class="dropdown-item" id="ApplyDeviceLots">
|
||||||
|
<i class="bi bi-check"></i>
|
||||||
|
Apply
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
<div class="btn-group dropdown m-1" uib-dropdown="">
|
<div class="btn-group dropdown m-1" uib-dropdown="">
|
||||||
<button id="btnExport" type="button" class="btn btn-primary dropdown-toggle" data-bs-toggle="dropdown" aria-expanded="false">
|
<button id="btnExport" type="button" class="btn btn-primary dropdown-toggle" data-bs-toggle="dropdown" aria-expanded="false">
|
||||||
<i class="bi bi-reply"></i>
|
<i class="bi bi-reply"></i>
|
||||||
|
@ -42,6 +87,27 @@
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
|
{% if orphans %}
|
||||||
|
<div class="btn-group dropdown m-1" uib-dropdown="">
|
||||||
|
<button id="btnTags" type="button" class="btn btn-primary dropdown-toggle" data-bs-toggle="dropdown" aria-expanded="false">
|
||||||
|
<i class="bi bi-tag"></i>
|
||||||
|
Labels
|
||||||
|
</button>
|
||||||
|
<ul class="dropdown-menu" aria-labelledby="btnTags">
|
||||||
|
<li>
|
||||||
|
<form id="print_labels" method="post" action="{{ url_for('labels.print_labels') }}">
|
||||||
|
{% for f in form_print_labels %}
|
||||||
|
{{ f }}
|
||||||
|
{% endfor %}
|
||||||
|
<a href="javascript:$('#print_labels').submit()" class="dropdown-item">
|
||||||
|
<i class="bi bi-printer"></i>
|
||||||
|
Print labels
|
||||||
|
</a>
|
||||||
|
</form>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
<div class="tab-content pt-2">
|
<div class="tab-content pt-2">
|
||||||
<table class="table">
|
<table class="table">
|
||||||
|
@ -74,11 +140,24 @@
|
||||||
<td>
|
<td>
|
||||||
{% if ac.device.phid() %}
|
{% if ac.device.phid() %}
|
||||||
<a href="{{ url_for('inventory.device_details', id=ac.device.dhid)}}">
|
<a href="{{ url_for('inventory.device_details', id=ac.device.dhid)}}">
|
||||||
|
{% if ac.device.get_type_logo() %}
|
||||||
|
<i class="{{ ac.device.get_type_logo() }}" title="{{ ac.device.type }}"></i>
|
||||||
|
{% endif %}
|
||||||
{{ ac.device.serial_number.upper() }}
|
{{ ac.device.serial_number.upper() }}
|
||||||
</a>
|
</a>
|
||||||
{% else %}
|
{% else %}
|
||||||
|
{% if ac.device.get_type_logo() %}
|
||||||
|
<i class="{{ ac.device.get_type_logo() }}" title="{{ ac.device.type }}"></i>
|
||||||
|
{% endif %}
|
||||||
{{ ac.device.serial_number.upper() }}
|
{{ ac.device.serial_number.upper() }}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
{% if ac.device.lots | length > 0 %}
|
||||||
|
<h6 class="d-inline">
|
||||||
|
{% for lot in ac.device.get_lots_for_template() %}
|
||||||
|
<span class="badge rounded-pill bg-light text-dark">{{ lot }}</span>
|
||||||
|
{% endfor %}
|
||||||
|
</h6>
|
||||||
|
{% endif %}
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
{% if ac.device.phid() %}
|
{% if ac.device.phid() %}
|
||||||
|
|
|
@ -32,7 +32,7 @@
|
||||||
</div>
|
</div>
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col qr">
|
<div class="col qr">
|
||||||
<div id="{{ dev.devicehub_id }}"></div>
|
<div id="{{ dev.dhid }}"></div>
|
||||||
</div>
|
</div>
|
||||||
<div class="col dhid">
|
<div class="col dhid">
|
||||||
<div style="padding-top: 55px">
|
<div style="padding-top: 55px">
|
||||||
|
@ -41,7 +41,7 @@
|
||||||
data-model="{{ dev.model or '' }}"
|
data-model="{{ dev.model or '' }}"
|
||||||
data-tags="{{ dev.list_tags() }}"
|
data-tags="{{ dev.list_tags() }}"
|
||||||
data-phid="{{ dev.phid() }}"
|
data-phid="{{ dev.phid() }}"
|
||||||
data-sid="{{ dev.sid or '' }}">{{ dev.devicehub_id }}</b>
|
data-sid="{{ dev.sid or '' }}">{{ dev.dhid }}</b>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -192,7 +192,7 @@
|
||||||
<script src="{{ url_for('static', filename='js/print.pdf.js') }}"></script>
|
<script src="{{ url_for('static', filename='js/print.pdf.js') }}"></script>
|
||||||
<script type="text/javascript">
|
<script type="text/javascript">
|
||||||
{% for dev in devices %}
|
{% for dev in devices %}
|
||||||
qr_draw("{{ dev.public_link }}", "#{{ dev.devicehub_id }}")
|
qr_draw("{{ dev.public_link }}", "#{{ dev.dhid }}")
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</script>
|
</script>
|
||||||
{% endblock main %}
|
{% endblock main %}
|
||||||
|
|
|
@ -56,6 +56,7 @@ def test_api_docs(client: Client):
|
||||||
'/inventory/device/{id}/',
|
'/inventory/device/{id}/',
|
||||||
'/inventory/device/{dhid}/binding/',
|
'/inventory/device/{dhid}/binding/',
|
||||||
'/inventory/device/erasure/',
|
'/inventory/device/erasure/',
|
||||||
|
'/inventory/device/erasure/{orphans}/',
|
||||||
'/inventory/all/device/',
|
'/inventory/all/device/',
|
||||||
'/inventory/export/{export_id}/',
|
'/inventory/export/{export_id}/',
|
||||||
'/inventory/lot/add/',
|
'/inventory/lot/add/',
|
||||||
|
|
|
@ -2393,6 +2393,19 @@ def test_list_erasures(user3: UserClientFlask):
|
||||||
assert status == '200 OK'
|
assert status == '200 OK'
|
||||||
assert txt in body
|
assert txt in body
|
||||||
|
|
||||||
|
uri = '/inventory/device/erasure/1/'
|
||||||
|
body, status = user3.get(uri)
|
||||||
|
assert status == '200 OK'
|
||||||
|
assert txt not in body
|
||||||
|
|
||||||
|
dev = Device.query.first()
|
||||||
|
dev.binding.kangaroo = True
|
||||||
|
db.session.commit()
|
||||||
|
|
||||||
|
body, status = user3.get(uri)
|
||||||
|
assert status == '200 OK'
|
||||||
|
assert txt in body
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.mvp
|
@pytest.mark.mvp
|
||||||
@pytest.mark.usefixtures(conftest.app_context.__name__)
|
@pytest.mark.usefixtures(conftest.app_context.__name__)
|
||||||
|
|
Reference in a new issue