Merge pull request #205 from eReuse/feature/server-side-render-UX-improvements

Feature/server side render ux improvements
This commit is contained in:
Santiago L 2022-03-07 18:34:42 +01:00 committed by GitHub
commit 7000b58c6e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
21 changed files with 167 additions and 98 deletions

View File

@ -1,8 +1,8 @@
import os import os
import click.testing import click.testing
import ereuse_utils
import flask.cli import flask.cli
import ereuse_utils
from ereuse_devicehub.config import DevicehubConfig from ereuse_devicehub.config import DevicehubConfig
from ereuse_devicehub.devicehub import Devicehub from ereuse_devicehub.devicehub import Devicehub

View File

@ -1,7 +1,6 @@
import copy import copy
import json import json
from json.decoder import JSONDecodeError from json.decoder import JSONDecodeError
from boltons.urlutils import URL from boltons.urlutils import URL
from flask import g, request from flask import g, request
from flask_wtf import FlaskForm from flask_wtf import FlaskForm
@ -63,7 +62,7 @@ class LotDeviceForm(FlaskForm):
return bool(self._devices) return bool(self._devices)
def save(self): def save(self, commit=True):
trade = self._lot.trade trade = self._lot.trade
if trade: if trade:
for dev in self._devices: for dev in self._devices:
@ -73,12 +72,16 @@ class LotDeviceForm(FlaskForm):
if self._devices: if self._devices:
self._lot.devices.update(self._devices) self._lot.devices.update(self._devices)
db.session.add(self._lot) db.session.add(self._lot)
if commit:
db.session.commit() db.session.commit()
def remove(self): def remove(self, commit=True):
if self._devices: if self._devices:
self._lot.devices.difference_update(self._devices) self._lot.devices.difference_update(self._devices)
db.session.add(self._lot) db.session.add(self._lot)
if commit:
db.session.commit() db.session.commit()
@ -114,7 +117,7 @@ class LotForm(FlaskForm):
return self.id return self.id
def remove(self): def remove(self):
if self.instance and not self.instance.devices: if self.instance and not self.instance.trade:
self.instance.delete() self.instance.delete()
db.session.commit() db.session.commit()
return self.instance return self.instance
@ -465,9 +468,9 @@ class TagDeviceForm(FlaskForm):
if self.delete: if self.delete:
tags = Tag.query.filter(Tag.owner_id == g.user.id).filter_by( tags = Tag.query.filter(Tag.owner_id == g.user.id).filter_by(
device_id=self.device_id device_id=self.device_id
) ).order_by(Tag.id)
else: else:
tags = Tag.query.filter(Tag.owner_id == g.user.id).filter_by(device_id=None) tags = Tag.query.filter(Tag.owner_id == g.user.id).filter_by(device_id=None).order_by(Tag.id)
self.tag.choices = [(tag.id, tag.id) for tag in tags] self.tag.choices = [(tag.id, tag.id) for tag in tags]

View File

@ -1,13 +1,15 @@
import csv import csv
import logging
from io import StringIO from io import StringIO
import flask import flask
import flask_weasyprint import flask_weasyprint
from flask import Blueprint, g, make_response, request, url_for from flask import Blueprint, g, make_response, request, url_for, app
from flask.views import View from flask.views import View
from flask_login import current_user, login_required from flask_login import current_user, login_required
from werkzeug.exceptions import NotFound from werkzeug.exceptions import NotFound
from sqlalchemy import or_ from sqlalchemy import or_
from requests.exceptions import ConnectionError
from ereuse_devicehub import messages from ereuse_devicehub import messages
from ereuse_devicehub.inventory.forms import ( from ereuse_devicehub.inventory.forms import (
@ -30,10 +32,13 @@ from ereuse_devicehub.resources.documents.device_row import ActionRow, DeviceRow
from ereuse_devicehub.resources.hash_reports import insert_hash from ereuse_devicehub.resources.hash_reports import insert_hash
from ereuse_devicehub.resources.lot.models import Lot from ereuse_devicehub.resources.lot.models import Lot
from ereuse_devicehub.resources.tag.model import Tag from ereuse_devicehub.resources.tag.model import Tag
from ereuse_devicehub.db import db
# TODO(@slamora): rename base 'inventory.devices' --> 'inventory' # TODO(@slamora): rename base 'inventory.devices' --> 'inventory'
devices = Blueprint('inventory.devices', __name__, url_prefix='/inventory') devices = Blueprint('inventory.devices', __name__, url_prefix='/inventory')
logger = logging.getLogger(__name__)
class DeviceListMix(View): class DeviceListMix(View):
decorators = [login_required] decorators = [login_required]
@ -51,7 +56,7 @@ class DeviceListMix(View):
tags = ( tags = (
Tag.query.filter(Tag.owner_id == current_user.id) Tag.query.filter(Tag.owner_id == current_user.id)
.filter(Tag.device_id.is_(None)) .filter(Tag.device_id.is_(None))
.order_by(Tag.created.desc()) .order_by(Tag.id.asc())
) )
if lot_id: if lot_id:
@ -134,10 +139,11 @@ class LotDeviceAddView(View):
def dispatch_request(self): def dispatch_request(self):
form = LotDeviceForm() form = LotDeviceForm()
if form.validate_on_submit(): if form.validate_on_submit():
form.save() form.save(commit=False)
messages.success( messages.success(
'Add devices to lot "{}" successfully!'.format(form._lot.name) 'Add devices to lot "{}" successfully!'.format(form._lot.name)
) )
db.session.commit()
else: else:
messages.error('Error adding devices to lot!') messages.error('Error adding devices to lot!')
@ -153,10 +159,11 @@ class LotDeviceDeleteView(View):
def dispatch_request(self): def dispatch_request(self):
form = LotDeviceForm() form = LotDeviceForm()
if form.validate_on_submit(): if form.validate_on_submit():
form.remove() form.remove(commit=False)
messages.success( messages.success(
'Remove devices from lot "{}" successfully!'.format(form._lot.name) 'Remove devices from lot "{}" successfully!'.format(form._lot.name)
) )
db.session.commit()
else: else:
messages.error('Error removing devices from lot!') messages.error('Error removing devices from lot!')
@ -207,6 +214,12 @@ class LotDeleteView(View):
def dispatch_request(self, id): def dispatch_request(self, id):
form = LotForm(id=id) form = LotForm(id=id)
if form.instance.trade:
msg = "Sorry, the lot cannot be deleted because have a trade action "
messages.error(msg)
next_url = url_for('inventory.devices.lotdevicelist', lot_id=id)
return flask.redirect(next_url)
form.remove() form.remove()
next_url = url_for('inventory.devices.devicelist') next_url = url_for('inventory.devices.devicelist')
return flask.redirect(next_url) return flask.redirect(next_url)
@ -251,7 +264,7 @@ class TagListView(View):
def dispatch_request(self): def dispatch_request(self):
lots = Lot.query.filter(Lot.owner_id == current_user.id) lots = Lot.query.filter(Lot.owner_id == current_user.id)
tags = Tag.query.filter(Tag.owner_id == current_user.id) tags = Tag.query.filter(Tag.owner_id == current_user.id).order_by(Tag.id)
context = { context = {
'lots': lots, 'lots': lots,
'tags': tags, 'tags': tags,
@ -287,7 +300,14 @@ class TagAddUnnamedView(View):
context = {'page_title': 'New Unnamed Tag', 'lots': lots} context = {'page_title': 'New Unnamed Tag', 'lots': lots}
form = TagUnnamedForm() form = TagUnnamedForm()
if form.validate_on_submit(): if form.validate_on_submit():
try:
form.save() form.save()
except ConnectionError as e:
logger.error("Error while trying to connect to tag server: {}".format(e))
msg = ("Sorry, we cannot create the unnamed tags requested because "
"some error happens while connecting to the tag server!")
messages.error(msg)
next_url = url_for('inventory.devices.taglist') next_url = url_for('inventory.devices.taglist')
return flask.redirect(next_url) return flask.redirect(next_url)

View File

@ -474,6 +474,13 @@ class Device(Thing):
key=attrgetter('type')) # last test of each type key=attrgetter('type')) # last test of each type
return self._warning_actions(current_tests) return self._warning_actions(current_tests)
@property
def verbose_name(self):
type = self.type or ''
manufacturer = self.manufacturer or ''
model = self.model or ''
return f'{type} {manufacturer} {model}'
@declared_attr @declared_attr
def __mapper_args__(cls): def __mapper_args__(cls):
"""Defines inheritance. """Defines inheritance.

View File

@ -59,18 +59,39 @@ function deviceSelect() {
} }
} }
function removeLot() {
var devices = $(".deviceSelect");
if (devices.length > 0) {
$("#btnRemoveLots .text-danger").show();
} else {
$("#btnRemoveLots .text-danger").hide();
}
$("#activeRemoveLotModal").click();
}
function removeTag() { function removeTag() {
var devices = $(".deviceSelect").filter(':checked'); 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 > 0) { 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; window.location.href = url;
} else {
$("#unlinkTagAlertModal").click();
} }
} }
function addTag() { function addTag() {
deviceSelect(); var devices = $(".deviceSelect").filter(':checked');
$("#addingTagModal").click(); var devices_id = $.map(devices, function(x) { return $(x).attr('data')});
if (devices_id.length == 1) {
$("#addingTagModal .pol").hide();
$("#addingTagModal .btn-primary").show();
} else {
$("#addingTagModal .pol").show();
$("#addingTagModal .btn-primary").hide();
}
$("#addTagAlertModal").click();
} }
function newTrade(action) { function newTrade(action) {

View File

@ -65,5 +65,5 @@ function printpdf() {
min_tag_side = (Math.min(height, width)/2) + border; min_tag_side = (Math.min(height, width)/2) + border;
pdf.addImage(imgData, 'PNG', border, border, img_side, img_side); pdf.addImage(imgData, 'PNG', border, border, img_side, img_side);
pdf.text(tag, max_tag_side, min_tag_side); pdf.text(tag, max_tag_side, min_tag_side);
pdf.save('Tags.pdf'); pdf.save('Tag_'+tag+'.pdf');
} }

View File

@ -17,9 +17,14 @@
<link href="https://fonts.gstatic.com" rel="preconnect"> <link href="https://fonts.gstatic.com" rel="preconnect">
<link href="https://fonts.googleapis.com/css?family=Open+Sans:300,300i,400,400i,600,600i,700,700i|Nunito:300,300i,400,400i,600,600i,700,700i|Poppins:300,300i,400,400i,500,500i,600,600i,700,700i" rel="stylesheet"> <link href="https://fonts.googleapis.com/css?family=Open+Sans:300,300i,400,400i,600,600i,700,700i|Nunito:300,300i,400,400i,600,600i,700,700i|Poppins:300,300i,400,400i,500,500i,600,600i,700,700i" rel="stylesheet">
<!-- JS Files -->
<script src="{{ url_for('static', filename='js/jquery-3.6.0.min.js') }}"></script>
<script src="https://cdn.jsdelivr.net/npm/simple-datatables@latest"></script>
<!-- Vendor CSS Files --> <!-- Vendor CSS Files -->
<link href="{{ url_for('static', filename='vendor/bootstrap/css/bootstrap.min.css') }}" rel="stylesheet"> <link href="{{ url_for('static', filename='vendor/bootstrap/css/bootstrap.min.css') }}" rel="stylesheet">
<link href="{{ url_for('static', filename='vendor/bootstrap-icons/bootstrap-icons.css') }}" rel="stylesheet"> <link href="{{ url_for('static', filename='vendor/bootstrap-icons/bootstrap-icons.css') }}" rel="stylesheet">
<link href="https://cdn.jsdelivr.net/npm/simple-datatables@latest/dist/style.css" rel="stylesheet" type="text/css">
<!-- Template Main CSS File --> <!-- Template Main CSS File -->

View File

@ -18,7 +18,7 @@
</select> </select>
<input class="devicesList" type="hidden" name="device" /> <input class="devicesList" type="hidden" name="device" />
<p class="text-danger pol"> <p class="text-danger pol">
You need select first some device for adding this in a tag You need select first one device and only one for add this in a tag
</p> </p>
</div> </div>

View File

@ -0,0 +1,21 @@
<div class="modal fade" id="unlinkTagErrorModal" tabindex="-1" style="display: none;" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">Error Unlink Tag</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div class="modal-body">
<p class="text-danger pol">
You need select first one device and only one for Unlink one Tag
</p>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Close</button>
</div>
</div>
</div>
</div>

View File

@ -31,7 +31,7 @@
<form method="post" class="row g-3 needs-validation" novalidate> <form method="post" class="row g-3 needs-validation" novalidate>
{{ form.csrf_token }} {{ form.csrf_token }}
<div class="col-12"> <div>
<div class="form-group has-validation mb-2"> <div class="form-group has-validation mb-2">
<label for="name" class="form-label">Type *</label> <label for="name" class="form-label">Type *</label>
<select id="type" class="form-control" name="type" required=""> <select id="type" class="form-control" name="type" required="">
@ -369,7 +369,7 @@
</div> </div>
<div class="col-12"> <div>
<a href="{{ url_for('inventory.devices.devicelist') }}" class="btn btn-danger">Cancel</a> <a href="{{ url_for('inventory.devices.devicelist') }}" class="btn btn-danger">Cancel</a>
<button class="btn btn-primary" type="submit">Save</button> <button class="btn btn-primary" type="submit">Save</button>
</div> </div>
@ -385,6 +385,5 @@
</div> </div>
</div> </div>
</section> </section>
<script src="{{ url_for('static', filename='js/jquery-3.6.0.min.js') }}"></script>
<script src="{{ url_for('static', filename='js/create_device.js') }}"></script> <script src="{{ url_for('static', filename='js/create_device.js') }}"></script>
{% endblock main %} {% endblock main %}

View File

@ -1,6 +1,5 @@
{% extends "ereuse_devicehub/base_site.html" %} {% extends "ereuse_devicehub/base_site.html" %}
{% block main %} {% block main %}
<link href="https://cdn.jsdelivr.net/npm/simple-datatables@latest/dist/style.css" rel="stylesheet" type="text/css">
<div class="pagetitle"> <div class="pagetitle">
<h1>Inventory</h1> <h1>Inventory</h1>

View File

@ -1,6 +1,5 @@
{% extends "ereuse_devicehub/base_site.html" %} {% extends "ereuse_devicehub/base_site.html" %}
{% block main %} {% block main %}
<link href="https://cdn.jsdelivr.net/npm/simple-datatables@latest/dist/style.css" rel="stylesheet" type="text/css">
<div class="pagetitle"> <div class="pagetitle">
<h1>Inventory</h1> <h1>Inventory</h1>
@ -33,8 +32,23 @@
<div class="card-body pt-3"> <div class="card-body pt-3">
<!-- Bordered Tabs --> <!-- Bordered Tabs -->
<div class="col-12"> <div class="d-flex align-items-center justify-content-between">
<h3><a href="{{ url_for('inventory.devices.lot_edit', id=lot.id) }}">{{ lot.name }}</a></h3> <h3><a href="{{ url_for('inventory.devices.lot_edit', id=lot.id) }}">{{ lot.name }}</a></h3>
<div><!-- lot actions -->
{% if lot.is_temporary %}
<span class="d-none" id="activeRemoveLotModal" data-bs-toggle="modal" data-bs-target="#btnRemoveLots"></span>
<a class="me-2" href="javascript:removeLot()">
<i class="bi bi-trash"></i> Remove Lot
</a>
<a class="me-2" href="javascript:newTrade('user_from')">
<i class="bi bi-arrow-down-right"></i> Add supplier
</a>
<a href="javascript:newTrade('user_to')">
<i class="bi bi-arrow-up-right"></i> Add receiver
</a>
{% endif %}
</div>
</div> </div>
</div> </div>
</div> </div>
@ -66,16 +80,6 @@
</button> </button>
<span class="d-none" id="activeTradeModal" data-bs-toggle="modal" data-bs-target="#tradeLotModal"></span> <span class="d-none" id="activeTradeModal" data-bs-toggle="modal" data-bs-target="#tradeLotModal"></span>
<ul class="dropdown-menu" aria-labelledby="btnLots"> <ul class="dropdown-menu" aria-labelledby="btnLots">
{% if lot and lot.is_temporary and not lot.devices %}
<li>
<a href="javascript:newAction('Use')" class="dropdown-item"
data-bs-toggle="modal" data-bs-target="#btnRemoveLots">
<i class="bi bi-trash"></i>
Remove Lot
<span class="caret"></span>
</a>
</li>
{% endif %}
<li> <li>
<a href="javascript:void()" class="dropdown-item" data-bs-toggle="modal" data-bs-target="#addingLotModal"> <a href="javascript:void()" class="dropdown-item" data-bs-toggle="modal" data-bs-target="#addingLotModal">
<i class="bi bi-plus"></i> <i class="bi bi-plus"></i>
@ -88,29 +92,6 @@
Remove selected devices from a lot Remove selected devices from a lot
</a> </a>
</li> </li>
{% if lot.is_temporary %}
<li>
<a href="javascript:newTrade('user_from')" class="dropdown-item">
<i class="bi bi-plus"></i>
Add supplier
</a>
</li>
<li>
<a href="javascript:newTrade('user_to')" class="dropdown-item">
<i class="bi bi-plus"></i>
Add receiver
</a>
</li>
{% endif %}
{% if lot and not lot.is_temporary %}
<li>
<a href="{{ url_for('inventory.devices.trade_document_add', lot_id=lot.id)}}" class="dropdown-item">
<i class="bi bi-plus"></i>
Add new document
<span class="caret"></span>
</a>
</li>
{% endif %}
</ul> </ul>
</div> </div>
<div class="btn-group dropdown ml-1" uib-dropdown=""> <div class="btn-group dropdown ml-1" uib-dropdown="">
@ -239,17 +220,19 @@
<i class="bi bi-tag"></i> <i class="bi bi-tag"></i>
Tags Tags
</button> </button>
<span class="d-none" id="unlinkTagAlertModal" data-bs-toggle="modal" data-bs-target="#unlinkTagErrorModal"></span>
<span class="d-none" id="addTagAlertModal" data-bs-toggle="modal" data-bs-target="#addingTagModal"></span>
<ul class="dropdown-menu" aria-labelledby="btnTags"> <ul class="dropdown-menu" aria-labelledby="btnTags">
<li> <li>
<a href="javascript:addTag()" class="dropdown-item" data-bs-toggle="modal" data-bs-target="#addingTagModal"> <a href="javascript:addTag()" class="dropdown-item">
<i class="bi bi-plus"></i> <i class="bi bi-plus"></i>
Add Tag to selected Devices Add Tag to selected Device
</a> </a>
</li> </li>
<li> <li>
<a href="javascript:removeTag()" class="dropdown-item"> <a href="javascript:removeTag()" class="dropdown-item">
<i class="bi bi-x"></i> <i class="bi bi-x"></i>
Remove Tag from selected Devices Remove Tag from selected Device
</a> </a>
</li> </li>
</ul> </ul>
@ -257,7 +240,7 @@
<div class="btn-group dropdown ml-1" uib-dropdown=""> <div class="btn-group dropdown ml-1" uib-dropdown="">
<button id="btnSnapshot" type="button" class="btn btn-primary dropdown-toggle" data-bs-toggle="dropdown" aria-expanded="false"> <button id="btnSnapshot" type="button" class="btn btn-primary dropdown-toggle" data-bs-toggle="dropdown" aria-expanded="false">
<i class="bi bi-tag"></i> <i class="bi bi-laptop"></i>
New Device New Device
</button> </button>
<ul class="dropdown-menu" aria-labelledby="btnSnapshot"> <ul class="dropdown-menu" aria-labelledby="btnSnapshot">
@ -276,6 +259,24 @@
</ul> </ul>
</div> </div>
{% if lot and not lot.is_temporary %}
<div class="btn-group dropdown ml-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-book"></i>
Documents
</button>
<ul class="dropdown-menu" aria-labelledby="btnSnapshot">
<li>
<a href="{{ url_for('inventory.devices.trade_document_add', lot_id=lot.id)}}" class="dropdown-item">
<i class="bi bi-plus"></i>
Add new document
<span class="caret"></span>
</a>
</li>
</ul>
</div>
{% endif %}
<div class="tab-content pt-2"> <div class="tab-content pt-2">
<h5 class="card-title">Computers</h5> <h5 class="card-title">Computers</h5>
@ -304,7 +305,7 @@
</td> </td>
<td> <td>
<a href="{{ url_for('inventory.devices.device_details', id=dev.devicehub_id)}}"> <a href="{{ url_for('inventory.devices.device_details', id=dev.devicehub_id)}}">
{{ dev.type }} {{ dev.manufacturer }} {{ dev.model }} {{ dev.verbose_name }}
</a> </a>
</td> </td>
<td> <td>
@ -374,16 +375,11 @@
{% include "inventory/data_wipe.html" %} {% include "inventory/data_wipe.html" %}
{% include "inventory/trade.html" %} {% include "inventory/trade.html" %}
{% include "inventory/alert_export_error.html" %} {% include "inventory/alert_export_error.html" %}
{% include "inventory/alert_unlink_tag_error.html" %}
<!-- CDN -->
<script src="https://cdn.jsdelivr.net/npm/simple-datatables@latest"></script>
<!-- Custom Code --> <!-- Custom Code -->
<script> <script>
const table = new simpleDatatables.DataTable("table") const table = new simpleDatatables.DataTable("table")
</script> </script>
<script>
</script>
<script src="{{ url_for('static', filename='js/jquery-3.6.0.min.js') }}"></script>
<script src="{{ url_for('static', filename='js/main_inventory.js') }}"></script> <script src="{{ url_for('static', filename='js/main_inventory.js') }}"></script>
{% endblock main %} {% endblock main %}

View File

@ -34,7 +34,7 @@
<form method="post" class="row g-3 needs-validation" novalidate> <form method="post" class="row g-3 needs-validation" novalidate>
{{ form.csrf_token }} {{ form.csrf_token }}
<div class="col-12"> <div>
<label for="name" class="form-label">Name</label> <label for="name" class="form-label">Name</label>
<div class="input-group has-validation"> <div class="input-group has-validation">
<input type="text" name="name" class="form-control" required value="{{ form.name.data|default('', true) }}"> <input type="text" name="name" class="form-control" required value="{{ form.name.data|default('', true) }}">
@ -42,8 +42,12 @@
</div> </div>
</div> </div>
<div class="col-12"> <div>
{% if form.id %}
<a href="{{ url_for('inventory.devices.lotdevicelist', lot_id=form.id) }}" class="btn btn-danger">Cancel</a>
{% else %}
<a href="{{ url_for('inventory.devices.devicelist') }}" class="btn btn-danger">Cancel</a> <a href="{{ url_for('inventory.devices.devicelist') }}" class="btn btn-danger">Cancel</a>
{% endif %}
<button class="btn btn-primary" type="submit">Save</button> <button class="btn btn-primary" type="submit">Save</button>
</div> </div>
</form> </form>

View File

@ -9,12 +9,15 @@
<div class="modal-body"> <div class="modal-body">
Are you sure that you want to remove lot <strong>{{ lot.name }}</strong>? Are you sure that you want to remove lot <strong>{{ lot.name }}</strong>?
<p class="text-danger">
There are devices in this lot, are you sure you want to delete it?
</p>
</div> </div>
<div class="modal-footer"> <div class="modal-footer">
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Close</button> <button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Close</button>
<a href="{{ url_for('inventory.devices.lot_del', id=lot.id)}}" type="button" class="btn btn-primary"> <a href="{{ url_for('inventory.devices.lot_del', id=lot.id)}}" type="button" class="btn btn-primary">
Save changes Confirm
</a> </a>
</div> </div>

View File

@ -33,7 +33,7 @@
<form method="post" class="row g-3 needs-validation" novalidate> <form method="post" class="row g-3 needs-validation" novalidate>
{{ form.csrf_token }} {{ form.csrf_token }}
<div class="col-12"> <div>
<label for="code" class="form-label">code</label> <label for="code" class="form-label">code</label>
<div class="input-group has-validation"> <div class="input-group has-validation">
<input type="text" name="code" class="form-control" required value="{{ form.code.data|default('', true) }}"> <input type="text" name="code" class="form-control" required value="{{ form.code.data|default('', true) }}">
@ -48,7 +48,7 @@
{% endif %} {% endif %}
</div> </div>
<div class="col-12"> <div>
<a href="{{ url_for('inventory.devices.taglist') }}" class="btn btn-danger">Cancel</a> <a href="{{ url_for('inventory.devices.taglist') }}" class="btn btn-danger">Cancel</a>
<button class="btn btn-primary" type="submit">Save</button> <button class="btn btn-primary" type="submit">Save</button>
</div> </div>

View File

@ -33,7 +33,7 @@
<form method="post" class="row g-3 needs-validation" novalidate> <form method="post" class="row g-3 needs-validation" novalidate>
{{ form.csrf_token }} {{ form.csrf_token }}
<div class="col-12"> <div>
<label for="code" class="form-label">Amount</label> <label for="code" class="form-label">Amount</label>
<div class="input-group has-validation"> <div class="input-group has-validation">
{{ form.amount(class_="form-control") }} {{ form.amount(class_="form-control") }}
@ -48,7 +48,7 @@
{% endif %} {% endif %}
</div> </div>
<div class="col-12"> <div>
<a href="{{ url_for('inventory.devices.taglist') }}" class="btn btn-danger">Cancel</a> <a href="{{ url_for('inventory.devices.taglist') }}" class="btn btn-danger">Cancel</a>
<button class="btn btn-primary" type="submit">Save</button> <button class="btn btn-primary" type="submit">Save</button>
</div> </div>

View File

@ -1,6 +1,5 @@
{% extends "ereuse_devicehub/base_site.html" %} {% extends "ereuse_devicehub/base_site.html" %}
{% block main %} {% block main %}
<link href="https://cdn.jsdelivr.net/npm/simple-datatables@latest/dist/style.css" rel="stylesheet" type="text/css">
<div class="pagetitle"> <div class="pagetitle">
<h1>Inventory</h1> <h1>Inventory</h1>
@ -35,7 +34,7 @@
<div class="col-lg-9 col-md-8"> <div class="col-lg-9 col-md-8">
{% if tag.device %} {% if tag.device %}
<a href="{{url_for('inventory.devices.device_details', id=tag.device.devicehub_id)}}"> <a href="{{url_for('inventory.devices.device_details', id=tag.device.devicehub_id)}}">
{{ tag.device.manufacturer }} {{ tag.device.model }} {{ tag.device.verbose_name }}
</a> </a>
{% endif %} {% endif %}
</div> </div>
@ -106,7 +105,6 @@
</div> </div>
</div> </div>
</section> </section>
<script src="{{ url_for('static', filename='js/jquery-3.6.0.min.js') }}"></script>
<script src="{{ url_for('static', filename='js/qrcode.js') }}"></script> <script src="{{ url_for('static', filename='js/qrcode.js') }}"></script>
<script src="{{ url_for('static', filename='js/jspdf.min.js') }}"></script> <script src="{{ url_for('static', filename='js/jspdf.min.js') }}"></script>
<script src="{{ url_for('static', filename='js/print.pdf.js') }}"></script> <script src="{{ url_for('static', filename='js/print.pdf.js') }}"></script>

View File

@ -1,6 +1,5 @@
{% extends "ereuse_devicehub/base_site.html" %} {% extends "ereuse_devicehub/base_site.html" %}
{% block main %} {% block main %}
<link href="https://cdn.jsdelivr.net/npm/simple-datatables@latest/dist/style.css" rel="stylesheet" type="text/css">
<div class="pagetitle"> <div class="pagetitle">
<h1>Inventory</h1> <h1>Inventory</h1>
@ -59,7 +58,7 @@
<td> <td>
{% if tag.device %} {% if tag.device %}
<a href={{ url_for('inventory.devices.device_details', id=tag.device.devicehub_id)}}> <a href={{ url_for('inventory.devices.device_details', id=tag.device.devicehub_id)}}>
{{ tag.device.type }} {{ tag.device.manufacturer }} {{ tag.device.model }} {{ tag.device.verbose_name }}
</a> </a>
{% endif %} {% endif %}
</td> </td>
@ -77,14 +76,8 @@
</div> </div>
</section> </section>
<!-- CDN -->
<script src="https://cdn.jsdelivr.net/npm/simple-datatables@latest"></script>
<!-- Custom Code --> <!-- Custom Code -->
<script> <script>
const table = new simpleDatatables.DataTable("table") const table = new simpleDatatables.DataTable("table")
</script> </script>
<script>
</script>
<script src="{{ url_for('static', filename='js/jquery-3.6.0.min.js') }}"></script>
{% endblock main %} {% endblock main %}

View File

@ -32,7 +32,7 @@
<form method="post" class="row g-3 needs-validation" novalidate> <form method="post" class="row g-3 needs-validation" novalidate>
{{ form.csrf_token }} {{ form.csrf_token }}
<div class="col-12"> <div>
<label for="tag" class="form-label">Tag</label> <label for="tag" class="form-label">Tag</label>
<div class="input-group has-validation"> <div class="input-group has-validation">
{{ form.tag(class_="form-control") }} {{ form.tag(class_="form-control") }}
@ -48,9 +48,9 @@
</div> </div>
<input class="devicesList" type="hidden" name="device" /> <input class="devicesList" type="hidden" name="device" />
<div class="col-12"> <div>
<a href="{{ referrer }}" class="btn btn-danger">Cancel</a> <a href="{{ referrer }}" class="btn btn-danger">Cancel</a>
<button class="btn btn-primary" type="submit">Save</button> <button class="btn btn-primary" type="submit">Unlink</button>
</div> </div>
</form> </form>

View File

@ -35,11 +35,10 @@
{{ form.csrf_token }} {{ form.csrf_token }}
{% for field in form %} {% for field in form %}
{% if field != form.csrf_token %} {% if field != form.csrf_token %}
<div class="col-12"> <div>
{{ field.label(class_="form-label") }} {{ field.label(class_="form-label") }}
{{ field }} {{ field }}
<small class="text-muted">{{ field.description }}</small> <small class="text-muted">{{ field.description }}</small>
{% endif %}
{% if field.errors %} {% if field.errors %}
<p class="text-danger"> <p class="text-danger">
{% for error in field.errors %} {% for error in field.errors %}
@ -48,9 +47,10 @@
</p> </p>
{% endif %} {% endif %}
</div> </div>
{% endif %}
{% endfor %} {% endfor %}
<div class="col-12"> <div>
<a href="{{ url_for('inventory.devices.lotdevicelist', lot_id=form._lot.id) }}" class="btn btn-danger">Cancel</a> <a href="{{ url_for('inventory.devices.lotdevicelist', lot_id=form._lot.id) }}" class="btn btn-danger">Cancel</a>
<button class="btn btn-primary" type="submit">Save</button> <button class="btn btn-primary" type="submit">Save</button>
</div> </div>

View File

@ -33,7 +33,7 @@
<form method="post" enctype="multipart/form-data" class="row g-3 needs-validation" novalidate> <form method="post" enctype="multipart/form-data" class="row g-3 needs-validation" novalidate>
{{ form.csrf_token }} {{ form.csrf_token }}
<div class="col-12"> <div>
<label for="name" class="form-label">Select a Snapshot file</label> <label for="name" class="form-label">Select a Snapshot file</label>
<div class="input-group has-validation"> <div class="input-group has-validation">
{{ form.snapshot }} {{ form.snapshot }}
@ -54,7 +54,7 @@
{% endif %} {% endif %}
</div> </div>
<div class="col-12"> <div>
<a href="{{ url_for('inventory.devices.devicelist') }}" class="btn btn-danger">Cancel</a> <a href="{{ url_for('inventory.devices.devicelist') }}" class="btn btn-danger">Cancel</a>
<button class="btn btn-primary" type="submit">Send</button> <button class="btn btn-primary" type="submit">Send</button>
</div> </div>