Merge pull request #408 from eReuse/feature/3988-real-pagination
Feature/3988 real pagination
This commit is contained in:
commit
4ae9eeb4c7
42
docs/conf.py
42
docs/conf.py
|
@ -30,7 +30,6 @@ from teal.enums import Country, Currency, Layouts, Subdivision
|
|||
from teal.marshmallow import EnumField
|
||||
|
||||
from ereuse_devicehub.marshmallow import NestedOn
|
||||
from ereuse_devicehub.resources.schemas import Thing
|
||||
|
||||
project = 'Devicehub'
|
||||
copyright = '2020, eReuse.org team'
|
||||
|
@ -56,7 +55,7 @@ extensions = [
|
|||
'sphinx.ext.viewcode',
|
||||
'sphinxcontrib.plantuml',
|
||||
'sphinx.ext.autosectionlabel',
|
||||
'sphinx.ext.autodoc'
|
||||
'sphinx.ext.autodoc',
|
||||
]
|
||||
|
||||
# Add any paths that contain templates here, relative to this directory.
|
||||
|
@ -126,15 +125,12 @@ latex_elements = {
|
|||
# The paper size ('letterpaper' or 'a4paper').
|
||||
#
|
||||
# 'papersize': 'letterpaper',
|
||||
|
||||
# The font size ('10pt', '11pt' or '12pt').
|
||||
#
|
||||
# 'pointsize': '10pt',
|
||||
|
||||
# Additional stuff for the LaTeX preamble.
|
||||
#
|
||||
# 'preamble': '',
|
||||
|
||||
# Latex figure (float) alignment
|
||||
#
|
||||
# 'figure_align': 'htbp',
|
||||
|
@ -144,18 +140,20 @@ latex_elements = {
|
|||
# (source start file, target name, title,
|
||||
# author, documentclass [howto, manual, or own class]).
|
||||
latex_documents = [
|
||||
(master_doc, 'Devicehub.tex', 'Devicehub Documentation',
|
||||
'eReuse.org team', 'manual'),
|
||||
(
|
||||
master_doc,
|
||||
'Devicehub.tex',
|
||||
'Devicehub Documentation',
|
||||
'eReuse.org team',
|
||||
'manual',
|
||||
),
|
||||
]
|
||||
|
||||
# -- Options for manual page output ------------------------------------------
|
||||
|
||||
# One entry per manual page. List of tuples
|
||||
# (source start file, name, description, authors, manual section).
|
||||
man_pages = [
|
||||
(master_doc, 'devicehub', 'Devicehub Documentation',
|
||||
[author], 1)
|
||||
]
|
||||
man_pages = [(master_doc, 'devicehub', 'Devicehub Documentation', [author], 1)]
|
||||
|
||||
# -- Options for Texinfo output ----------------------------------------------
|
||||
|
||||
|
@ -163,9 +161,15 @@ man_pages = [
|
|||
# (source start file, target name, title, author,
|
||||
# dir menu entry, description, category)
|
||||
texinfo_documents = [
|
||||
(master_doc, 'Devicehub', 'Devicehub Documentation',
|
||||
author, 'Devicehub', 'One line description of project.',
|
||||
'Miscellaneous'),
|
||||
(
|
||||
master_doc,
|
||||
'Devicehub',
|
||||
'Devicehub Documentation',
|
||||
author,
|
||||
'Devicehub',
|
||||
'One line description of project.',
|
||||
'Miscellaneous',
|
||||
),
|
||||
]
|
||||
|
||||
# -- Extension configuration -------------------------------------------------
|
||||
|
@ -199,6 +203,7 @@ class DhlistDirective(Directive):
|
|||
This requires :py:class:`ereuse_devicehub.resources.schemas.SchemaMeta`.
|
||||
You will find in that module more information.
|
||||
"""
|
||||
|
||||
has_content = False
|
||||
|
||||
# Definition of passed-in options
|
||||
|
@ -216,7 +221,7 @@ class DhlistDirective(Directive):
|
|||
|
||||
sections = []
|
||||
sections.append(self.links(things)) # Make index
|
||||
for thng in things: # type: Thing
|
||||
for thng in things:
|
||||
# Generate a section for each class, with a title,
|
||||
# fields description and a paragraph
|
||||
section = n.section(ids=[self._id(thng)])
|
||||
|
@ -228,7 +233,9 @@ class DhlistDirective(Directive):
|
|||
for key, f in thng._own:
|
||||
name = n.field_name(text=f.data_key or key)
|
||||
body = [
|
||||
self.parse('{} {}'.format(self.type(f), f.metadata.get('description', '')))
|
||||
self.parse(
|
||||
'{} {}'.format(self.type(f), f.metadata.get('description', ''))
|
||||
)
|
||||
]
|
||||
if isinstance(f, EnumField):
|
||||
body.append(self._parse_enum_field(f))
|
||||
|
@ -244,6 +251,7 @@ class DhlistDirective(Directive):
|
|||
|
||||
def _parse_enum_field(self, f):
|
||||
from ereuse_devicehub.resources.device import states
|
||||
|
||||
if issubclass(f.enum, (Subdivision, Currency, Country, Layouts, states.State)):
|
||||
return self.parse(f.enum.__doc__)
|
||||
else:
|
||||
|
@ -298,7 +306,7 @@ class DhlistDirective(Directive):
|
|||
|
||||
def parse(self, text) -> n.container:
|
||||
"""Parses text possibly containing ReST stuff and adds it in
|
||||
a node."""
|
||||
a node."""
|
||||
p = n.container('')
|
||||
self.state.nested_parse(StringList(string2lines(inspect.cleandoc(text))), 0, p)
|
||||
return p
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
from distutils.version import StrictVersion
|
||||
from itertools import chain
|
||||
from typing import Set
|
||||
|
||||
from decouple import config
|
||||
from teal.auth import TokenAuth
|
||||
|
@ -44,7 +43,7 @@ class DevicehubConfig(Config):
|
|||
import_resource(metric_def),
|
||||
),
|
||||
)
|
||||
PASSWORD_SCHEMES = {'pbkdf2_sha256'} # type: Set[str]
|
||||
PASSWORD_SCHEMES = {'pbkdf2_sha256'}
|
||||
SECRET_KEY = config('SECRET_KEY')
|
||||
DB_USER = config('DB_USER', 'dhub')
|
||||
DB_PASSWORD = config('DB_PASSWORD', 'ereuse')
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
import itertools
|
||||
import json
|
||||
from pathlib import Path
|
||||
from typing import Set
|
||||
|
||||
import click
|
||||
import click_spinner
|
||||
|
@ -109,7 +108,7 @@ class Dummy:
|
|||
files = tuple(Path(__file__).parent.joinpath('files').iterdir())
|
||||
print('done.')
|
||||
sample_pc = None # We treat this one as a special sample for demonstrations
|
||||
pcs = set() # type: Set[int]
|
||||
pcs = set()
|
||||
with click.progressbar(files, label='Creating devices...'.ljust(28)) as bar:
|
||||
for path in bar:
|
||||
with path.open() as f:
|
||||
|
|
|
@ -118,16 +118,36 @@ class ErasureListView(DeviceListMixin):
|
|||
def dispatch_request(self, orphans=0):
|
||||
self.get_context()
|
||||
self.get_devices(orphans)
|
||||
if orphans:
|
||||
self.context['orphans'] = True
|
||||
return flask.render_template(self.template_name, **self.context)
|
||||
|
||||
def get_devices(self, orphans):
|
||||
page = int(request.args.get('page', 1))
|
||||
per_page = int(request.args.get('per_page', 5))
|
||||
|
||||
erasure = EraseBasic.query.filter_by(author=g.user).order_by(
|
||||
EraseBasic.created.desc()
|
||||
)
|
||||
if orphans:
|
||||
erasure = [e for e in erasure if e.device.orphan]
|
||||
schema = app.config.get('SCHEMA')
|
||||
sql = f"""
|
||||
select action.id from {schema}.action as action
|
||||
inner join {schema}.erase_basic as erase
|
||||
on action.id=erase.id
|
||||
inner join {schema}.device as device
|
||||
on device.id=action.parent_id
|
||||
inner join {schema}.placeholder as placeholder
|
||||
on placeholder.binding_id=device.id
|
||||
where action.parent_id is null or placeholder.kangaroo=true
|
||||
"""
|
||||
ids = (e[0] for e in db.session.execute(sql))
|
||||
erasure = EraseBasic.query.filter(EraseBasic.id.in_(ids)).order_by(
|
||||
EraseBasic.created.desc()
|
||||
)
|
||||
self.context['orphans'] = True
|
||||
|
||||
erasure = erasure.paginate(page=page, per_page=per_page)
|
||||
erasure.first = per_page * erasure.page - per_page + 1
|
||||
erasure.last = len(erasure.items) + erasure.first - 1
|
||||
self.context['erasure'] = erasure
|
||||
|
||||
|
||||
|
@ -138,8 +158,17 @@ class DeviceListView(DeviceListMixin):
|
|||
|
||||
|
||||
class AllDeviceListView(DeviceListMixin):
|
||||
template_name = 'inventory/all_device_list.html'
|
||||
|
||||
def dispatch_request(self):
|
||||
self.get_context(all_devices=True)
|
||||
# import pdb; pdb.set_trace()
|
||||
page = int(request.args.get('page', 1))
|
||||
per_page = int(request.args.get('per_page', 5))
|
||||
devices = self.context['devices'].paginate(page=page, per_page=per_page)
|
||||
devices.first = per_page * devices.page - per_page + 1
|
||||
devices.last = len(devices.items) + devices.first - 1
|
||||
self.context['devices'] = devices
|
||||
return flask.render_template(self.template_name, **self.context)
|
||||
|
||||
|
||||
|
|
|
@ -4,7 +4,7 @@ from contextlib import suppress
|
|||
from datetime import datetime
|
||||
from fractions import Fraction
|
||||
from math import hypot
|
||||
from typing import Iterator, List, Optional, Type, TypeVar
|
||||
from typing import Iterator, List, Optional, TypeVar
|
||||
|
||||
import dateutil.parser
|
||||
from ereuse_utils import getter, text
|
||||
|
@ -404,7 +404,7 @@ class Computer(Device):
|
|||
chassis value.
|
||||
"""
|
||||
|
||||
COMPONENTS = list(Component.__subclasses__()) # type: List[Type[Component]]
|
||||
COMPONENTS = list(Component.__subclasses__())
|
||||
COMPONENTS.remove(Motherboard)
|
||||
|
||||
def __init__(self, node: dict) -> None:
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
from datetime import datetime, timezone
|
||||
from typing import List
|
||||
|
||||
from ereuse_workbench.computer import Component, Computer, DataStorage
|
||||
from ereuse_workbench.computer import Computer, DataStorage
|
||||
from ereuse_workbench.utils import Dumpeable
|
||||
|
||||
|
||||
|
@ -24,8 +23,8 @@ class Snapshot(Dumpeable):
|
|||
self.endTime = datetime.now(timezone.utc)
|
||||
self.closed = False
|
||||
self.elapsed = None
|
||||
self.device = None # type: Computer
|
||||
self.components = None # type: List[Component]
|
||||
self.device = None
|
||||
self.components = None
|
||||
self._storages = None
|
||||
|
||||
def computer(self):
|
||||
|
|
671
ereuse_devicehub/templates/inventory/all_device_list.html
Normal file
671
ereuse_devicehub/templates/inventory/all_device_list.html
Normal file
|
@ -0,0 +1,671 @@
|
|||
{% extends "ereuse_devicehub/base_site.html" %}
|
||||
{% block main %}
|
||||
|
||||
<div class="pagetitle">
|
||||
<h1>Inventory</h1>
|
||||
<nav>
|
||||
<ol class="breadcrumb">
|
||||
<li class="breadcrumb-item"><a href="{{ url_for('inventory.alldevicelist')}}">Inventory</a></li>
|
||||
{% if not lot %}
|
||||
<li class="breadcrumb-item active">All devices</li>
|
||||
{% elif lot.is_temporary %}
|
||||
<li class="breadcrumb-item active">Temporary Lot</li>
|
||||
<li class="breadcrumb-item active">{{ lot.name }}</li>
|
||||
{% elif lot.is_incoming %}
|
||||
<li class="breadcrumb-item active">Incoming Lot</li>
|
||||
<li class="breadcrumb-item active">{{ lot.name }}</li>
|
||||
{% elif lot.is_outgoing %}
|
||||
<li class="breadcrumb-item active">Outgoing Lot</li>
|
||||
<li class="breadcrumb-item active">{{ lot.name }}</li>
|
||||
{% endif %}
|
||||
</ol>
|
||||
</nav>
|
||||
</div><!-- End Page Title -->
|
||||
|
||||
<section class="section profile">
|
||||
<div class="row">
|
||||
|
||||
<div class="col-xl-12">
|
||||
|
||||
<div class="card">
|
||||
{% if lot %}
|
||||
<div class="card-body pt-3">
|
||||
<!-- Bordered Tabs -->
|
||||
|
||||
<div class="d-flex align-items-center justify-content-between row">
|
||||
<div class="col-sm-12 col-md-5">
|
||||
<h3>
|
||||
<a href="{{ url_for('inventory.lot_edit', id=lot.id) }}">{{ lot.name }}</a>
|
||||
</h3>
|
||||
</div>
|
||||
|
||||
<div class="col-sm-12 col-md-7 d-md-flex justify-content-md-end"><!-- lot actions -->
|
||||
{% if lot.is_temporary or not lot.transfer.closed %}
|
||||
|
||||
{% if lot and lot.is_temporary %}
|
||||
<a type="button" href="{{ url_for('inventory.lot_new_transfer', lot_id=lot.id, type_id='outgoing') }}" class="btn btn-primary doTransfer" >
|
||||
Create Outgoing Lot
|
||||
</a>
|
||||
<a type="button" href="{{ url_for('inventory.lot_new_transfer', lot_id=lot.id, type_id='incoming') }}" class="btn btn-primary doTransfer">
|
||||
Create Incoming Lot
|
||||
</a>
|
||||
{% endif %}
|
||||
<a class="text-danger" href="javascript:removeLot()">
|
||||
<i class="bi bi-trash"></i> Delete Lot
|
||||
</a>
|
||||
<span class="d-none" id="activeRemoveLotModal" data-bs-toggle="modal" data-bs-target="#btnRemoveLots"></span>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
<div class="card-body pt-3" style="min-height: 650px;">
|
||||
<!-- Bordered Tabs -->
|
||||
{% if lot %}
|
||||
<ul class="nav nav-tabs nav-tabs-bordered">
|
||||
|
||||
<li class="nav-item">
|
||||
<button class="nav-link active" data-bs-toggle="tab" data-bs-target="#devices-list">Devices</button>
|
||||
</li>
|
||||
|
||||
{% if lot and not lot.is_temporary %}
|
||||
<li class="nav-item">
|
||||
<button class="nav-link" data-bs-toggle="tab" data-bs-target="#trade-documents-list">Documents</button>
|
||||
</li>
|
||||
|
||||
{% if lot.transfer %}
|
||||
<li class="nav-item">
|
||||
<button class="nav-link" data-bs-toggle="tab" data-bs-target="#edit-transfer">
|
||||
Transfer ({% if lot.transfer.closed %}<span class="text-danger">Closed</span>{% else %}<span class="text-success">Open</span>{% endif %})
|
||||
</button>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<button class="nav-link" data-bs-toggle="tab" data-bs-target="#edit-delivery-note">
|
||||
Delivery Note
|
||||
</button>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<button class="nav-link" data-bs-toggle="tab" data-bs-target="#edit-receiver-note">
|
||||
Receiver Note
|
||||
</button>
|
||||
</li>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
|
||||
</ul>
|
||||
{% endif %}
|
||||
<div class="tab-content pt-1">
|
||||
<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>
|
||||
<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>
|
||||
<div class="btn-group dropdown m-1" uib-dropdown="">
|
||||
<button id="btnActions" type="button" class="btn btn-primary dropdown-toggle" data-bs-toggle="dropdown" aria-expanded="false">
|
||||
<i class="bi bi-plus"></i>
|
||||
Actions
|
||||
</button>
|
||||
<span class="d-none" id="activeActionModal" data-bs-toggle="modal" data-bs-target="#actionModal"></span>
|
||||
<span class="d-none" id="activeAllocateModal" data-bs-toggle="modal" data-bs-target="#allocateModal"></span>
|
||||
<span class="d-none" id="activeDatawipeModal" data-bs-toggle="modal" data-bs-target="#datawipeModal"></span>
|
||||
<ul class="dropdown-menu" aria-labelledby="btnActions">
|
||||
<li>
|
||||
Status actions
|
||||
</li>
|
||||
<li>
|
||||
<a href="javascript:newAction('Recycling')" class="dropdown-item">
|
||||
<i class="bi bi-recycle"></i>
|
||||
Recycling
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="javascript:newAction('Use')" class="dropdown-item">
|
||||
<i class="bi bi-play-circle-fill"></i>
|
||||
Use
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="javascript:newAction('Refurbish')" class="dropdown-item">
|
||||
<i class="bi bi-tools"></i>
|
||||
Refurbish
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="javascript:newAction('Management')" class="dropdown-item">
|
||||
<i class="bi bi-mastodon"></i>
|
||||
Management
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
Allocation
|
||||
</li>
|
||||
<li>
|
||||
<a href="javascript:newAllocate('Allocate')" class="dropdown-item">
|
||||
<i class="bi bi-house-fill"></i>
|
||||
Allocate
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="javascript:newAllocate('Deallocate')" class="dropdown-item">
|
||||
<i class="bi bi-house"></i>
|
||||
Deallocate
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
Physical actions
|
||||
</li>
|
||||
<li>
|
||||
<a href="javascript:newAction('ToPrepare')" class="dropdown-item">
|
||||
<i class="bi bi-tools"></i>
|
||||
ToPrepare
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="javascript:newAction('Prepare')" class="dropdown-item">
|
||||
<i class="bi bi-egg"></i>
|
||||
Prepare
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="javascript:newDataWipe('DataWipe')" class="dropdown-item">
|
||||
<i class="bi bi-eraser-fill"></i>
|
||||
DataWipe
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="javascript:newAction('ToRepair')" class="dropdown-item">
|
||||
<i class="bi bi-screwdriver"></i>
|
||||
ToRepair
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="javascript:newAction('Ready')" class="dropdown-item">
|
||||
<i class="bi bi-check2-all"></i>
|
||||
Ready
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<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">
|
||||
<i class="bi bi-reply"></i>
|
||||
Exports
|
||||
</button>
|
||||
<span class="d-none" id="exportAlertModal" data-bs-toggle="modal" data-bs-target="#exportErrorModal"></span>
|
||||
<ul class="dropdown-menu" aria-labelledby="btnExport">
|
||||
<li>
|
||||
<a href="javascript:export_file('devices')" class="dropdown-item">
|
||||
<i class="bi bi-file-spreadsheet"></i>
|
||||
Devices Spreadsheet
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="javascript:export_file('devices_lots')" class="dropdown-item">
|
||||
<i class="bi bi-file-spreadsheet"></i>
|
||||
Devices Lots Spreadsheet
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="javascript:export_file('obada_standard')" class="dropdown-item">
|
||||
<i class="bi bi-file-spreadsheet"></i>
|
||||
Obada Standard Spreadsheet
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="javascript:export_file('certificates')" class="dropdown-item">
|
||||
<i class="bi bi-eraser-fill"></i>
|
||||
Erasure Certificate
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<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>
|
||||
|
||||
<div class="btn-group dropdown m-1" uib-dropdown="">
|
||||
<button id="btnSnapshot" type="button" class="btn btn-primary dropdown-toggle" data-bs-toggle="dropdown" aria-expanded="false">
|
||||
<i class="bi bi-laptop"></i>
|
||||
Placeholders
|
||||
</button>
|
||||
<ul class="dropdown-menu" aria-labelledby="btnSnapshot">
|
||||
<li>
|
||||
{% if lot %}
|
||||
<a href="{{ url_for('inventory.lot_upload_placeholder', lot_id=lot.id) }}" class="dropdown-item">
|
||||
{% else %}
|
||||
<a href="{{ url_for('inventory.upload_placeholder') }}" class="dropdown-item">
|
||||
{% endif %}
|
||||
<i class="bi bi-upload"></i>
|
||||
Upload Spreadsheet
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
{% if lot %}
|
||||
<a href="{{ url_for('inventory.lot_device_add', lot_id=lot.id) }}" class="dropdown-item">
|
||||
{% else %}
|
||||
<a href="{{ url_for('inventory.device_add') }}" class="dropdown-item">
|
||||
{% endif %}
|
||||
<i class="bi bi-plus"></i>
|
||||
Create a new
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div class="btn-group dropdown m-1" uib-dropdown="">
|
||||
<button id="btnSnapshot" type="button" class="btn btn-primary dropdown-toggle" data-bs-toggle="dropdown" aria-expanded="false">
|
||||
<i class="bi bi-laptop"></i>
|
||||
Snapshots
|
||||
</button>
|
||||
<ul class="dropdown-menu" aria-labelledby="btnSnapshot">
|
||||
<li>
|
||||
{% if lot %}
|
||||
<a href="{{ url_for('inventory.lot_upload_snapshot', lot_id=lot.id) }}" class="dropdown-item">
|
||||
{% else %}
|
||||
<a href="{{ url_for('inventory.upload_snapshot') }}" class="dropdown-item">
|
||||
{% endif %}
|
||||
<i class="bi bi-upload"></i>
|
||||
Upload files
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div id="select-devices-info" class="alert alert-info mb-0 mt-3 d-none" role="alert">
|
||||
If this text is showing is because there are an error
|
||||
</div>
|
||||
|
||||
<div class="tab-content pt-2">
|
||||
<form method="get">
|
||||
<div class="d-flex mt-4 mb-4">
|
||||
{% for f in form_filter %}
|
||||
{{ f }}
|
||||
{% endfor %}
|
||||
<input type="submit" class="ms-2 btn btn-primary" value="Filter" />
|
||||
</div>
|
||||
</form>
|
||||
|
||||
<p class="mt-3">
|
||||
Displaying devices of type
|
||||
<em>{{ form_filter.filter.data or "Computer" }}</em>
|
||||
</p>
|
||||
|
||||
<div class="dataTable-top" style="float: left;">
|
||||
<div class="dataTable-dropdown">
|
||||
<label>
|
||||
<select class="dataTable-selector">
|
||||
<option value="5"{% if devices.per_page == 5 %} selected="selected"{% endif %}>
|
||||
5
|
||||
</option>
|
||||
<option value="10"{% if devices.per_page == 10 %} selected="selected"{% endif %}>
|
||||
10
|
||||
</option>
|
||||
<option value="15"{% if devices.per_page == 15 %} selected="selected"{% endif %}>
|
||||
15
|
||||
</option>
|
||||
<option value="20"{% if devices.per_page == 20 %} selected="selected"{% endif %}>
|
||||
20
|
||||
</option>
|
||||
<option value="25"{% if devices.per_page == 25 %} selected="selected"{% endif %}>
|
||||
25
|
||||
</option>
|
||||
<option value="50"{% if devices.per_page == 50 %} selected="selected"{% endif %}>
|
||||
50
|
||||
</option>
|
||||
<option value="100"{% if devices.per_page == 100 %} selected="selected"{% endif %}>
|
||||
100
|
||||
</option>
|
||||
</select> entries per page
|
||||
</label>
|
||||
</div>
|
||||
<div class="dataTable-search">
|
||||
</div>
|
||||
</div>
|
||||
<div class="dataTable-container">
|
||||
<table class="table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th scope="col">Select</th>
|
||||
<th scope="col">Title</th>
|
||||
<th scope="col">DHID</th>
|
||||
<th scope="col">PHID</th>
|
||||
<th scope="col">Type</th>
|
||||
<th scope="col">Unique Identifiers</th>
|
||||
<th scope="col">Lifecycle Status</th>
|
||||
<th scope="col">Allocated Status</th>
|
||||
<th scope="col">Physical Status</th>
|
||||
<th scope="col" data-type="date" data-format="YYYY-MM-DD">Updated in</th>
|
||||
<th scope="col" data-type="date" data-format="YYYY-MM-DD hh:mm:ss">Registered in</th>
|
||||
<th scope="col"></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for dev in devices.items %}
|
||||
{% if dev.placeholder and (not dev.parent_id or dev.parent.placeholder.kangaroo) %}
|
||||
<tr>
|
||||
<td>
|
||||
<input type="checkbox" class="deviceSelect" data="{{ dev.id }}"
|
||||
data-device-type="{{ dev.type }}" data-device-manufacturer="{{ dev.manufacturer }}"
|
||||
data-device-dhid="{{ dev.devicehub_id }}" data-device-vname="{{ dev.verbose_name }}"
|
||||
{% if form_new_allocate.type.data and dev.id in list_devices %}
|
||||
checked="checked"
|
||||
{% endif %}
|
||||
/>
|
||||
</td>
|
||||
<td>
|
||||
<a href="{{ url_for('inventory.device_details', id=dev.devicehub_id)}}">
|
||||
{% if dev.get_type_logo() %}
|
||||
<i class="{{ dev.get_type_logo() }}" title="{{ dev.type }}"></i>
|
||||
{% endif %}
|
||||
{{ dev.verbose_name }}
|
||||
</a>
|
||||
{% if dev.lots | length > 0 %}
|
||||
<h6 class="d-inline">
|
||||
{% for lot in dev.get_lots_for_template() %}
|
||||
<span class="badge rounded-pill bg-light text-dark">{{ lot }}</span>
|
||||
{% endfor %}
|
||||
</h6>
|
||||
{% endif %}
|
||||
</td>
|
||||
<td>
|
||||
<a href="{{ url_for('inventory.device_details', id=dev.devicehub_id)}}">
|
||||
{{ dev.devicehub_id }}
|
||||
</a>
|
||||
</td>
|
||||
<td>
|
||||
{{ dev.binding and dev.binding.phid or dev.placeholder and dev.placeholder.phid or '' }}
|
||||
</td>
|
||||
<td>
|
||||
{{ dev.is_abstract() }}
|
||||
</td>
|
||||
<td>
|
||||
{% for t in dev.tags | sort(attribute="id") %}
|
||||
<a href="{{ url_for('labels.label_details', id=t.id)}}">{{ t.id }}</a>
|
||||
{% if not loop.last %},{% endif %}
|
||||
{% endfor %}
|
||||
</td>
|
||||
<td>{% if dev.status %}{{ dev.status.type }}{% endif %}</td>
|
||||
<td>{% if dev.allocated_status %}{{ dev.allocated_status.type }}{% endif %}</td>
|
||||
<td>{% if dev.physical_status %}{{ dev.physical_status.type }}{% endif %}</td>
|
||||
<td>{{ dev.get_updated.strftime('%Y-%m-%d %H:%M:%S')}}</td>
|
||||
<td>{{ dev.created.strftime('%Y-%m-%d %H:%M:%S')}}</td>
|
||||
<td>
|
||||
<a href="{{ dev.public_link }}" target="_blank">
|
||||
<i class="bi bi-box-arrow-up-right"></i>
|
||||
</a>
|
||||
</td>
|
||||
</tr>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
<div class="dataTable-bottom">
|
||||
<div class="dataTable-info">
|
||||
Showing {{ devices.first }} to {{ devices.last }} of {{ devices.total }} entries
|
||||
</div>
|
||||
<nav class="dataTable-pagination">
|
||||
<ul class="dataTable-pagination-list">
|
||||
{% if devices.has_prev %}
|
||||
<li class="pager">
|
||||
<a href="{{ url_for('inventory.alldevicelist', page=devices.prev_num, per_page=devices.per_page) }}">‹</a>
|
||||
</li>
|
||||
{% endif %}
|
||||
{% for page in devices.iter_pages() %}
|
||||
{% if page %}
|
||||
{% if page == devices.page %}
|
||||
<li class="active"><a href="javascript:void()">{{ page }}</a></li>
|
||||
{% else %}
|
||||
<li class="">
|
||||
<a href="{{ url_for('inventory.alldevicelist', page=page, per_page=devices.per_page) }}">
|
||||
{{ page }}
|
||||
</a>
|
||||
</li>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
{% if devices.has_next %}
|
||||
<li class="pager">
|
||||
<a href="{{ url_for('inventory.alldevicelist', page=devices.next_num, per_page=devices.per_page) }}">›</a>
|
||||
</li>
|
||||
{% endif %}
|
||||
</ul>
|
||||
</nav>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
{% if lot and not lot.is_temporary %}
|
||||
<div id="trade-documents-list" class="tab-pane fade trade-documents-list">
|
||||
<div class="btn-group dropdown ml-1 mt-1" uib-dropdown="">
|
||||
<a href="{{ url_for('inventory.trade_document_add', lot_id=lot.id)}}" class="btn btn-primary">
|
||||
<i class="bi bi-plus"></i>
|
||||
Add new document
|
||||
<span class="caret"></span>
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<h5 class="card-title">Documents</h5>
|
||||
<table class="table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th scope="col">File</th>
|
||||
<th scope="col" data-type="date" data-format="YYYY-MM-DD hh:mm">Uploaded on</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for doc in lot.documents %}
|
||||
<tr>
|
||||
<td>
|
||||
{% if doc.get_url() %}
|
||||
<a href="{{ doc.get_url() }}" target="_blank">{{ doc.file_name}}</a>
|
||||
{% else %}
|
||||
{{ doc.file_name}}
|
||||
{% endif %}
|
||||
</td>
|
||||
<td>
|
||||
{{ doc.created.strftime('%Y-%m-%d %H:%M')}}
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
{% for doc in lot.trade.documents %}
|
||||
<tr>
|
||||
<td>
|
||||
{% if doc.get_url() %}
|
||||
<a href="{{ doc.get_url() }}" target="_blank">{{ doc.file_name}}</a>
|
||||
{% else %}
|
||||
{{ doc.file_name}}
|
||||
{% endif %}
|
||||
</td>
|
||||
<td>
|
||||
{{ doc.created.strftime('%Y-%m-%d %H:%M')}}
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<div id="edit-transfer" class="tab-pane fade edit-transfer">
|
||||
<h5 class="card-title">Transfer</h5>
|
||||
<form method="post" action="{{ url_for('inventory.edit_transfer', lot_id=lot.id) }}" class="row g-3 needs-validation" novalidate>
|
||||
{{ form_transfer.csrf_token }}
|
||||
|
||||
{% for field in form_transfer %}
|
||||
{% if field != form_transfer.csrf_token %}
|
||||
<div class="col-12">
|
||||
{% if field != form_transfer.type %}
|
||||
{{ field.label(class_="form-label") }}
|
||||
{% if field == form_transfer.code %}
|
||||
<span class="text-danger">*</span>
|
||||
{% endif %}
|
||||
{{ field }}
|
||||
<small class="text-muted">{{ field.description }}</small>
|
||||
{% if field.errors %}
|
||||
<p class="text-danger">
|
||||
{% for error in field.errors %}
|
||||
{{ error }}<br/>
|
||||
{% endfor %}
|
||||
</p>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
|
||||
<div>
|
||||
<a href="{{ url_for('inventory.lotdevicelist', lot_id=lot.id) }}" class="btn btn-danger">Cancel</a>
|
||||
<button class="btn btn-primary" type="submit">Save</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
<div id="edit-delivery-note" class="tab-pane fade edit-delivery-note">
|
||||
<h5 class="card-title">Delivery Note</h5>
|
||||
<form method="post" action="{{ url_for('inventory.delivery_note', lot_id=lot.id) }}" class="row g-3 needs-validation" novalidate>
|
||||
{{ form_delivery.csrf_token }}
|
||||
|
||||
{% for field in form_delivery %}
|
||||
{% if field != form_delivery.csrf_token %}
|
||||
<div class="col-12">
|
||||
{% if field != form_delivery.type %}
|
||||
{{ field.label(class_="form-label") }}
|
||||
{{ field }}
|
||||
<small class="text-muted">{{ field.description }}</small>
|
||||
{% if field.errors %}
|
||||
<p class="text-danger">
|
||||
{% for error in field.errors %}
|
||||
{{ error }}<br/>
|
||||
{% endfor %}
|
||||
</p>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
|
||||
{% if lot.transfer and form_receiver.is_editable() %}
|
||||
<div>
|
||||
<a href="{{ url_for('inventory.lotdevicelist', lot_id=lot.id) }}" class="btn btn-danger">Cancel</a>
|
||||
<button class="btn btn-primary" type="submit">Save</button>
|
||||
</div>
|
||||
{% endif %}
|
||||
</form>
|
||||
</div>
|
||||
<div id="edit-receiver-note" class="tab-pane fade edit-receiver-note">
|
||||
<h5 class="card-title">Receiver Note</h5>
|
||||
<form method="post" action="{{ url_for('inventory.receiver_note', lot_id=lot.id) }}" class="row g-3 needs-validation" novalidate>
|
||||
{{ form_receiver.csrf_token }}
|
||||
|
||||
{% for field in form_receiver %}
|
||||
{% if field != form_receiver.csrf_token %}
|
||||
<div class="col-12">
|
||||
{% if field != form_receiver.type %}
|
||||
{{ field.label(class_="form-label") }}
|
||||
{{ field }}
|
||||
<small class="text-muted">{{ field.description }}</small>
|
||||
{% if field.errors %}
|
||||
<p class="text-danger">
|
||||
{% for error in field.errors %}
|
||||
{{ error }}<br/>
|
||||
{% endfor %}
|
||||
</p>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
|
||||
{% if lot.transfer and form_receiver.is_editable() %}
|
||||
<div>
|
||||
<a href="{{ url_for('inventory.lotdevicelist', lot_id=lot.id) }}" class="btn btn-danger">Cancel</a>
|
||||
<button class="btn btn-primary" type="submit">Save</button>
|
||||
</div>
|
||||
{% endif %}
|
||||
</form>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
</div><!-- End Bordered Tabs -->
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="NotificationsContainer" style="position: absolute; bottom: 0; right: 0; margin: 10px; margin-top: 70px; width: calc(100% - 310px);"></div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
{% include "inventory/lot_delete_modal.html" %}
|
||||
{% include "inventory/actions.html" %}
|
||||
{% include "inventory/allocate.html" %}
|
||||
{% include "inventory/data_wipe.html" %}
|
||||
{% include "inventory/trade.html" %}
|
||||
{% include "inventory/alert_export_error.html" %}
|
||||
{% include "inventory/alert_lots_changes.html" %}
|
||||
|
||||
<!-- Custom Code -->
|
||||
<script>
|
||||
$(document).ready(() => {
|
||||
$(".dataTable-selector").on("change", function() {
|
||||
const per_page = $('.dataTable-selector').val();
|
||||
window.location.href = "{{ url_for('inventory.alldevicelist', page=1) }}&per_page="+per_page;
|
||||
});
|
||||
});
|
||||
</script>
|
||||
<script>
|
||||
let table = new simpleDatatables.DataTable("table", {
|
||||
footer: false,
|
||||
paging: false,
|
||||
|
||||
})
|
||||
</script>
|
||||
{% if config['DEBUG'] %}
|
||||
<script src="{{ url_for('static', filename='js/main_inventory.js') }}"></script>
|
||||
{% else %}
|
||||
<script src="{{ url_for('static', filename='js/main_inventory.build.js') }}"></script>
|
||||
{% endif %}
|
||||
|
||||
|
||||
{% endblock main %}
|
|
@ -7,11 +7,7 @@
|
|||
<ol class="breadcrumb">
|
||||
<li class="breadcrumb-item"><a href="{{ url_for('inventory.devicelist')}}">Inventory</a></li>
|
||||
{% if not lot %}
|
||||
{% if all_devices %}
|
||||
<li class="breadcrumb-item active">All devices</li>
|
||||
{% else %}
|
||||
<li class="breadcrumb-item active">Unassigned</li>
|
||||
{% endif %}
|
||||
<li class="breadcrumb-item active">Unassigned</li>
|
||||
{% elif lot.is_temporary %}
|
||||
<li class="breadcrumb-item active">Temporary Lot</li>
|
||||
<li class="breadcrumb-item active">{{ lot.name }}</li>
|
||||
|
@ -230,17 +226,10 @@
|
|||
</a>
|
||||
</li>
|
||||
<li>
|
||||
{% if not all_devices %}
|
||||
<span class="dropdown-item" style="color: #999ea4;">
|
||||
<i class="bi bi-file-spreadsheet"></i>
|
||||
Devices Lots Spreadsheet
|
||||
</span>
|
||||
{% else %}
|
||||
<a href="javascript:export_file('devices_lots')" class="dropdown-item">
|
||||
<i class="bi bi-file-spreadsheet"></i>
|
||||
Devices Lots Spreadsheet
|
||||
</a>
|
||||
{% endif %}
|
||||
</li>
|
||||
<li>
|
||||
<a href="javascript:export_file('obada_standard')" class="dropdown-item">
|
||||
|
|
|
@ -109,7 +109,43 @@
|
|||
</div>
|
||||
{% endif %}
|
||||
|
||||
<div id="select-devices-info" class="alert alert-info mb-0 mt-3 d-none" role="alert">
|
||||
If this text is showing is because there are an error
|
||||
</div>
|
||||
|
||||
<div class="tab-content pt-2">
|
||||
<div class="dataTable-top" style="float: left;">
|
||||
<div class="dataTable-dropdown">
|
||||
<label>
|
||||
<select class="dataTable-selector">
|
||||
<option value="5"{% if erasure.per_page == 5 %} selected="selected"{% endif %}>
|
||||
5
|
||||
</option>
|
||||
<option value="10"{% if erasure.per_page == 10 %} selected="selected"{% endif %}>
|
||||
10
|
||||
</option>
|
||||
<option value="15"{% if erasure.per_page == 15 %} selected="selected"{% endif %}>
|
||||
15
|
||||
</option>
|
||||
<option value="20"{% if erasure.per_page == 20 %} selected="selected"{% endif %}>
|
||||
20
|
||||
</option>
|
||||
<option value="25"{% if erasure.per_page == 25 %} selected="selected"{% endif %}>
|
||||
25
|
||||
</option>
|
||||
<option value="50"{% if erasure.per_page == 50 %} selected="selected"{% endif %}>
|
||||
50
|
||||
</option>
|
||||
<option value="100"{% if erasure.per_page == 100 %} selected="selected"{% endif %}>
|
||||
100
|
||||
</option>
|
||||
</select> entries per page
|
||||
</label>
|
||||
</div>
|
||||
<div class="dataTable-search">
|
||||
</div>
|
||||
</div>
|
||||
<div class="dataTable-container">
|
||||
<table class="table">
|
||||
<thead>
|
||||
<tr>
|
||||
|
@ -125,7 +161,7 @@
|
|||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for ac in erasure %}
|
||||
{% for ac in erasure.items %}
|
||||
<tr>
|
||||
<td>
|
||||
<input type="checkbox" class="deviceSelect" data="{{ ac.device.my_partner.id }}"
|
||||
|
@ -170,7 +206,7 @@
|
|||
</td>
|
||||
<td>
|
||||
<a href="{{ url_for('inventory.export', export_id='snapshot') }}?id={{ ac.snapshot.uuid }}">
|
||||
{{ ac.snapshot.uuid }}
|
||||
{{ ac.snapshot.uuid }}
|
||||
</a>
|
||||
</td>
|
||||
<td>
|
||||
|
@ -194,135 +230,54 @@
|
|||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
</div>
|
||||
<div class="dataTable-bottom">
|
||||
<div class="dataTable-info">
|
||||
Showing {{ erasure.first }} to {{ erasure.last }} of {{ erasure.total }} entries
|
||||
</div>
|
||||
<nav class="dataTable-pagination">
|
||||
<ul class="dataTable-pagination-list">
|
||||
{% if erasure.has_prev %}
|
||||
<li class="pager">
|
||||
{% if orphans %}
|
||||
<a href="{{ url_for('inventory.device_erasure_list_orphans', orphans=1, page=erasure.prev_num, per_page=erasure.per_page) }}">‹</a>
|
||||
{% else %}
|
||||
<a href="{{ url_for('inventory.device_erasure_list', page=erasure.prev_num, per_page=erasure.per_page) }}">‹</a>
|
||||
{% endif %}
|
||||
</li>
|
||||
{% endif %}
|
||||
{% for page in erasure.iter_pages() %}
|
||||
{% if page %}
|
||||
{% if page == erasure.page %}
|
||||
<li class="active"><a href="javascript:void()">{{ page }}</a></li>
|
||||
{% else %}
|
||||
<li class="">
|
||||
{% if orphans %}
|
||||
<a href="{{ url_for('inventory.device_erasure_list_orphans', orphans=1, page=page, per_page=erasure.per_page) }}">
|
||||
{{ page }}
|
||||
</a>
|
||||
{% else %}
|
||||
<a href="{{ url_for('inventory.device_erasure_list', page=page, per_page=erasure.per_page) }}">
|
||||
{{ page }}
|
||||
</a>
|
||||
{% endif %}
|
||||
</li>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
{% if erasure.has_next %}
|
||||
<li class="pager">
|
||||
{% if orphans %}
|
||||
<a href="{{ url_for('inventory.device_erasure_list_orphans', orphans=1, page=erasure.next_num, per_page=erasure.per_page) }}">›</a>
|
||||
{% else %}
|
||||
<a href="{{ url_for('inventory.device_erasure_list', page=erasure.next_num, per_page=erasure.per_page) }}">›</a>
|
||||
{% endif %}
|
||||
</li>
|
||||
{% endif %}
|
||||
</ul>
|
||||
</nav>
|
||||
</div>
|
||||
</div>
|
||||
{% if lot and not lot.is_temporary %}
|
||||
<div id="trade-documents-list" class="tab-pane fade trade-documents-list">
|
||||
<h5 class="card-title">Documents</h5>
|
||||
<table class="table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th scope="col">File</th>
|
||||
<th scope="col" data-type="date" data-format="DD-MM-YYYY">Uploaded on</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for doc in lot.trade.documents %}
|
||||
<tr>
|
||||
<td>
|
||||
{% if doc.url %}
|
||||
<a href="{{ doc.url.to_text() }}" target="_blank">{{ doc.file_name}}</a>
|
||||
{% else %}
|
||||
{{ doc.file_name}}
|
||||
{% endif %}
|
||||
</td>
|
||||
<td>
|
||||
{{ doc.created.strftime('%H:%M %d-%m-%Y')}}
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<div id="edit-transfer" class="tab-pane fade edit-transfer">
|
||||
<h5 class="card-title">Transfer</h5>
|
||||
<form method="post" action="{{ url_for('inventory.edit_transfer', lot_id=lot.id) }}" class="row g-3 needs-validation" novalidate>
|
||||
{{ form_transfer.csrf_token }}
|
||||
|
||||
{% for field in form_transfer %}
|
||||
{% if field != form_transfer.csrf_token %}
|
||||
<div class="col-12">
|
||||
{% if field != form_transfer.type %}
|
||||
{{ field.label(class_="form-label") }}
|
||||
{% if field == form_transfer.code %}
|
||||
<span class="text-danger">*</span>
|
||||
{% endif %}
|
||||
{{ field }}
|
||||
<small class="text-muted">{{ field.description }}</small>
|
||||
{% if field.errors %}
|
||||
<p class="text-danger">
|
||||
{% for error in field.errors %}
|
||||
{{ error }}<br/>
|
||||
{% endfor %}
|
||||
</p>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
|
||||
<div>
|
||||
<a href="{{ url_for('inventory.lotdevicelist', lot_id=lot.id) }}" class="btn btn-danger">Cancel</a>
|
||||
<button class="btn btn-primary" type="submit">Save</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
<div id="edit-delivery-note" class="tab-pane fade edit-delivery-note">
|
||||
<h5 class="card-title">Delivery Note</h5>
|
||||
<form method="post" action="{{ url_for('inventory.delivery_note', lot_id=lot.id) }}" class="row g-3 needs-validation" novalidate>
|
||||
{{ form_delivery.csrf_token }}
|
||||
|
||||
{% for field in form_delivery %}
|
||||
{% if field != form_delivery.csrf_token %}
|
||||
<div class="col-12">
|
||||
{% if field != form_delivery.type %}
|
||||
{{ field.label(class_="form-label") }}
|
||||
{{ field }}
|
||||
<small class="text-muted">{{ field.description }}</small>
|
||||
{% if field.errors %}
|
||||
<p class="text-danger">
|
||||
{% for error in field.errors %}
|
||||
{{ error }}<br/>
|
||||
{% endfor %}
|
||||
</p>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
|
||||
{% if lot.transfer and form_receiver.is_editable() %}
|
||||
<div>
|
||||
<a href="{{ url_for('inventory.lotdevicelist', lot_id=lot.id) }}" class="btn btn-danger">Cancel</a>
|
||||
<button class="btn btn-primary" type="submit">Save</button>
|
||||
</div>
|
||||
{% endif %}
|
||||
</form>
|
||||
</div>
|
||||
<div id="edit-receiver-note" class="tab-pane fade edit-receiver-note">
|
||||
<h5 class="card-title">Receiver Note</h5>
|
||||
<form method="post" action="{{ url_for('inventory.receiver_note', lot_id=lot.id) }}" class="row g-3 needs-validation" novalidate>
|
||||
{{ form_receiver.csrf_token }}
|
||||
|
||||
{% for field in form_receiver %}
|
||||
{% if field != form_receiver.csrf_token %}
|
||||
<div class="col-12">
|
||||
{% if field != form_receiver.type %}
|
||||
{{ field.label(class_="form-label") }}
|
||||
{{ field }}
|
||||
<small class="text-muted">{{ field.description }}</small>
|
||||
{% if field.errors %}
|
||||
<p class="text-danger">
|
||||
{% for error in field.errors %}
|
||||
{{ error }}<br/>
|
||||
{% endfor %}
|
||||
</p>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
|
||||
{% if lot.transfer and form_receiver.is_editable() %}
|
||||
<div>
|
||||
<a href="{{ url_for('inventory.lotdevicelist', lot_id=lot.id) }}" class="btn btn-danger">Cancel</a>
|
||||
<button class="btn btn-primary" type="submit">Save</button>
|
||||
</div>
|
||||
{% endif %}
|
||||
</form>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
</div><!-- End Bordered Tabs -->
|
||||
</div>
|
||||
|
@ -334,21 +289,32 @@
|
|||
</div>
|
||||
</div>
|
||||
</section>
|
||||
{% include "inventory/lot_delete_modal.html" %}
|
||||
{% include "inventory/actions.html" %}
|
||||
{% include "inventory/allocate.html" %}
|
||||
{% include "inventory/data_wipe.html" %}
|
||||
{% include "inventory/trade.html" %}
|
||||
{% include "inventory/alert_export_error.html" %}
|
||||
{% include "inventory/alert_lots_changes.html" %}
|
||||
|
||||
<!-- Custom Code -->
|
||||
<script>
|
||||
$(document).ready(() => {
|
||||
$(".dataTable-selector").on("change", function() {
|
||||
const per_page = $('.dataTable-selector').val();
|
||||
{% if orphans %}
|
||||
window.location.href = "{{ url_for('inventory.device_erasure_list_orphans', orphans=1, page=1) }}&per_page="+per_page;
|
||||
{% else %}
|
||||
window.location.href = "{{ url_for('inventory.device_erasure_list', page=1) }}&per_page="+per_page;
|
||||
{% endif %}
|
||||
});
|
||||
});
|
||||
</script>
|
||||
<script>
|
||||
let table = new simpleDatatables.DataTable("table", {
|
||||
perPageSelect: [5, 10, 15, 20, 25, 50, 100],
|
||||
perPage: 20
|
||||
//perPageSelect: [5, 10, 15, 20, 25, 50, 100],
|
||||
//perPage: 20,
|
||||
footer: false,
|
||||
paging: false,
|
||||
|
||||
})
|
||||
</script>
|
||||
|
||||
{% if config['DEBUG'] %}
|
||||
<script src="{{ url_for('static', filename='js/main_inventory.js') }}"></script>
|
||||
{% else %}
|
||||
|
|
|
@ -2368,6 +2368,9 @@ def test_upload_snapshot_smartphone(user3: UserClientFlask):
|
|||
@pytest.mark.mvp
|
||||
@pytest.mark.usefixtures(conftest.app_context.__name__)
|
||||
def test_list_erasures(user3: UserClientFlask):
|
||||
from flask import current_app as app
|
||||
|
||||
app.config['SCHEMA'] = 'test'
|
||||
uri = '/inventory/upload-snapshot/'
|
||||
file_name = 'erase-sectors-2-hdd.snapshot.yaml'
|
||||
body, status = user3.get(uri)
|
||||
|
|
Reference in a new issue