Reformat inventory view

This should all deserve flex
..or move to off the shelf inventory sofwtare
This commit is contained in:
2025-05-26 01:49:09 +03:00
parent 35dc28a8f5
commit 971920f94c
5 changed files with 125 additions and 243 deletions

View File

@@ -129,7 +129,7 @@ class InventoryForm(Form):
owner = FormField(MemberForm, label="Owner")
user = FormField(MemberForm, label="Current User")
usable = BooleanField("Usable")
visibility = SelectField("Visibility", choices=['public', 'unlisted', 'secret'], default='unlisted')
visibility = SelectField("Visibility", choices=['public', 'unlisted', 'secret', 'archived'], default='unlisted')
class HardwareForm(Form):
serial = StringField("Serial Number")
@@ -143,7 +143,6 @@ class ShortenerForm(Form):
class InventoryItemForm(CustomForm):
type = SelectField("Type", choices=fetch_type_select())
name = StringField('Name')
external_link = StringField('External link')
comment = StringField('Comment')
inventory = FormField(InventoryForm)
hardware = FormField(HardwareForm)

View File

@@ -27,9 +27,9 @@ body {
.csstransforms & th.rotate {
height: 140px;
white-space: nowrap;
// Firefox needs the extra DIV for some reason, otherwise the text disappears if you rotate
// Firefox needs the extra DIV for some reason, otherwise the text disappears if you rotate
> div {
transform:
transform:
// Magic Numbers
translate(25px, 51px)
// 45 is really 360-45
@@ -68,8 +68,14 @@ span.tooltipped {
text-decoration-line: underline;
text-decoration-style: dotted;
}
</style>
.horizontalRow {
display: flex;
justify-content: flex-start;
gap: 20px;
padding: 10px;
}
</style>
</head>
<body>
<script
@@ -98,24 +104,43 @@ span.tooltipped {
<script src="https://cdnjs.cloudflare.com/ajax/libs/materialize/1.0.0/js/materialize.min.js" integrity="sha384-ZOED+d9HxogEQwD+jFvux96iGQR9TxfJO+mPF2ZS0TuKH6eWrmvPsDpO6I0OWdiX" crossorigin="anonymous"></script>
<script type="text/javascript">
document.addEventListener('DOMContentLoaded', function() {
document.addEventListener("DOMContentLoaded", function () {
$("time.timeago").timeago();
var elems = document.querySelectorAll('.tooltipped');
var elems = document.querySelectorAll(".tooltipped");
var instances = M.Tooltip.init(elems, {});
var elems = document.querySelectorAll('.sidenav');
var elems = document.querySelectorAll(".sidenav");
var instances = M.Sidenav.init(elems, {});
var elems = document.querySelectorAll('select');
var elems = document.querySelectorAll("select");
var instances = M.FormSelect.init(elems, {});
var elems = document.querySelectorAll('.materialboxed');
var elems = document.querySelectorAll(".materialboxed");
var instances = M.Materialbox.init(elems, {});
var elems = document.querySelectorAll('.collapsible.expandable');
var instances = M.Collapsible.init(elems, {accordion: false});
var elems = document.querySelectorAll(".collapsible.expandable");
var instances = M.Collapsible.init(elems, { accordion: false });
});
$("button.audit-button").on("click", function () {
let button = $(this);
$.ajax({
method: "POST",
url: "/m/inventory/" + button.data("itemId") + "/audit",
data: { noRedirect: true },
success: function () {
button.unbind("click");
button.removeClass([
"orange",
"red",
"waves-effect",
"waves-light",
]);
button.addClass(["unclickable", "green"]);
button.text("Just now");
},
});
});
</script>
</body>
</html>

View File

@@ -40,10 +40,10 @@
</td>
<td>{{ item.inventory.visibility }}</td>
<td>{{ item.type }}</td>
<td><a href="/m/inventory/{{ item._id }}/view">{{ item | format_name }} {{ item.comment }}</a></td>
<td><a href="/m/inventory/{{ item._id }}/view">{{ item | format_name }}</a> {{ item.comment }}</td>
<td>{{ item.location }}</td>
<td>{{ item | owner_link}}</td>
<td>{{ item | user_link}}</td>
<td>{{ item | owner_link }}</td>
<td>{{ item | user_link }}</td>
{% if can_audit %}
<td>
<form onsubmit="return false;">
@@ -63,20 +63,4 @@
</table>
{{ add_item_button() }}
</div>
<script>
$('button.audit-button').on('click', function() {
let button = $(this);
$.ajax({
method: 'POST',
url: "/m/inventory/" + button.data('itemId') + "/audit",
data: { noRedirect: true },
success: function() {
button.unbind('click');
button.removeClass(['orange', 'red', 'waves-effect', 'waves-light']);
button.addClass(['unclickable', 'green']);
button.text('Just now');
}
})
});
</script>
{% endblock %}

View File

@@ -3,15 +3,14 @@
<div class="container">
<form method="POST" autocomplete="off">
{{ form.csrf_token }}
<p>Inventory item.</p>
<div id="errors" style="background-color: red;">
{% for field, errors in form.errors.items() %}
<div>
{{ form[field].label.text }} :
{{ form[field].label.text }} :
{% if errors.items %}
{% for error, msg in errors.items() %}
{{ form[field][error].label.text }} :
{{ form[field][error].label.text }} :
{{ ", ".join(msg) }}
{% endfor %}
{% else %}
@@ -33,15 +32,36 @@
</tr>
</thead>
<tbody>
<tr>
<td>Location</td>
<td>{{ form.location }}</td>
<td></td>
<td><button class="btn waves-effect waves-light" type="submit" name="action">Submit
<i class="material-icons right">send</i>
</button>
</td>
</tr>
<tr>
<td>k6.ee/</td>
<td>{{ form.shortener.slug }}</td>
</tr>
<tr>
<td>Type</td>
<td>{{ form["type"] }}</td>
<td>Visibility</td>
<td>{{ form.inventory.visibility }}</td>
</tr>
<tr>
<td>Vendor</td>
<td>{{ form.hardware.vendor }}</td>
<td>Serial number</td>
<td>{{ form.hardware.serial }}</td>
</tr>
<tr>
@@ -49,11 +69,6 @@
<td>{{ form.hardware.product }}</td>
</tr>
<tr>
<td>Serial number</td>
<td>{{ form.hardware.serial }}</td>
</tr>
<tr>
<td>Name</td>
<td>{{ form.name }}</td>
@@ -75,33 +90,10 @@
<span>
</td>
<td>{{ form.inventory.owner.username }}</td>
</tr>
<tr>
<td>Current user</td>
<td>{{ form.inventory.user.username }}</td>
</tr>
<tr>
<td>External link</td>
<td>{{ form.external_link }}</td>
</tr>
<tr>
<td>URL slug</td>
<td>{{ form.shortener.slug }}</td>
</tr>
<tr>
<td>Location</td>
<td>{{ form.location }}</td>
</tr>
<tr>
<td>Visibility</td>
<td>{{ form.inventory.visibility }}</td>
</tr>
</tbody>
</table>
@@ -196,4 +188,3 @@ $(function() {
});
</script>
{% endblock %}

View File

@@ -1,25 +1,69 @@
{% extends 'base.html' %}
{% block content %}
<div class="container">
<p>Inventory item.</p>
<title>{% if item.get("shortener").slug %}/{{ item.get("shortener").slug }}{% else %}k6{% endif %}: {{ item.name }}</title>
<div class="horizontalRow">
<div class="col s12"><a {% if not can_edit %} disabled="" {% endif %} href="/m/inventory/{{ item._id }}/edit" class="waves-effect waves-light btn">Edit</a></div>
<div class="col s12"><a href="/m/inventory/{{ item._id }}/clone" class="waves-effect waves-light btn">Clone</a></div>
</div>
<table>
<thead>
<tr>
<th>Key</th>
<th>Value</th>
<th>Key</th>
<th>Value</th>
</tr>
</thead>
<tbody>
<tr>
<td>Location</td>
<td>{{ item.location }}</td>
<td>Last audited</td>
<td><div>
<form onsubmit="return false;">
<button
data-item-id="{{ item._id }}"
class="audit-button {{ item.inventory | audit_color }} waves-effect waves-light btn"
{% if not can_audit %}disabled=""{% endif %}
>
{{item.inventory | audit_text}}
</button>
</form>{% if item.inventory.get("audit") %} by {{ item.inventory.audit.username }}{% endif %}
</div>
</tr>
<tr>
<td>URL slug</td>
<td>
{% if item.get("shortener").slug %}
{{ item.get("shortener", {}).get("slug") | qr_code }}
<a href="http://k6.ee/{{ item.get("shortener").slug }}">
k6.ee/{{ item.get("shortener").slug }}
</a>
{% endif %}
</td>
</tr>
<tr>
<td>Type</td>
<td>{{ item["type"] }}</td>
<td class="tooltip" data-tooltip="Who can see the item">Visibility</td>
<td>{{ item.inventory.visibility }}</td>
</tr>
<tr>
<td>Vendor</td>
<td>{{ item.get("hardware").vendor }}</td>
<td>Serial number</td>
<td>{{ item.get("hardware").serial }}</td>
</tr>
<tr>
@@ -27,11 +71,6 @@
<td>{{ item.get("hardware").product }}</td>
</tr>
<tr>
<td>Serial number</td>
<td>{{ item.get("hardware").serial }}</td>
</tr>
{% if item.mac %}
<tr>
<td>MAC address</td>
@@ -54,98 +93,27 @@
<td>Comment</td>
<td>{{ item.comment }}</td>
</tr>
<tr>
<td>Owner</td>
<td>{{ item.inventory.get("owner").username | display_name }}</td>
</tr>
<tr>
<td>Current user</td>
<td>{{ item.inventory.get("user").username | display_name }}</td>
<td>{{ item | owner_link }}</td>
<td>User</td>
<td>{{ item | user_link }}</td>
</tr>
{% macro auditLine(timestamp, user) -%}
{{ timestamp | timeago }}
by
{{ user | display_name }}
{%- endmacro %}
<tr>
<td>Last audited</td>
<td>
{% if item.inventory.get("audit") %}
{% if item.inventory.get("audit", {}).get("log") %}
<details>
<summary>
{{ auditLine(item.inventory.audit.timestamp, item.inventory.audit.username) }}
</summary>
<ul class="browser-default">
{% for audit in item.inventory.audit.log | reverse %}
<li>{{ auditLine(audit.timestamp, audit.username) }}</li>
{% endfor %}
</ul>
</details>
{% else %}
{{ auditLine(item.inventory.audit.timestamp, item.inventory.audit.username) }}
{% endif %}
{% else %}
Never
{% endif %}
</td>
</tr>
<tr>
<td>URL slug</td>
<td>
{% if item.get("shortener").slug %}
<a href="http://k6.ee/{{ item.get("shortener").slug }}">
k6.ee/{{ item.get("shortener").slug }}
</a>
{% endif %}
</td>
</tr>
<tr>
<td>QR Code (WIP)</td>
<td>
{% if item.get("shortener").slug %}
{{ item.get("shortener", {}).get("slug") | qr_code }}
{% endif %}
</td>
</tr>
<tr>
<td>External link</td>
<td><a href="{{ item.external_link }}">External link</a></td>
</tr>
<tr>
<td>Location</td>
<td>{{ item.location }}</td>
</tr>
<tr>
<td class="tooltip" data-tooltip="Who can see the item">Visibility</td>
<td>{{ item.inventory.visibility }}</td>
</tr>
<tr>
<td class="tooltip" data-tooltip="Other members can make use of this inventory item">Usable</td>
<td>{% if item.inventory.usable %}<i class="material-icons">check_circle</i>{% endif %}</td>
</tr>
<tr>
<td>Tags</td>
{% for tag in item.tags %}
<div class="chip"> {{ tag }} </div>
{% endfor %}
</tr>
</tbody>
</table>
<h3>Tags</h3>
{% for tag in item.tags %}
<div class="chip"> {{ tag }} </div>
{% endfor %}
<div>
<h3>Photo</h3>
{% if item.has_photo %}
<img src="{{ photo_url }}" alt="" style="max-width: 800px; width: 100%;">
{% endif %}
<form id="photo-form" action="/inventory/{{ item._id }}/upload-photo" method="post" enctype="multipart/form-data">
<div class="row placeholder-dark">
<div class="file-field input-field col s6">
@@ -165,97 +133,13 @@
</div>
</div>
</form>
<h3>Actions</h3>
{% if not item.inventory.user and item.inventory.usable %}
<div class="row">
<div class="col s12">
<form action="/m/inventory/{{ item._id }}/use" method="post" style="display: inline;">
<button class="waves-effect waves-light btn" type="submit">Use</button>
</form>
</div>
</div>
{% if item.has_photo %}
<img src="{{ photo_url }}" alt="" style="max-width: 800px; width: 100%;">
{% endif %}
{% if is_using %}
<div class="row">
<div class="col s12">
<form action="/m/inventory/{{ item._id }}/vacate" method="post" style="display: inline;">
<button class="waves-effect waves-light btn" type="submit">Vacate</button>
</form>
</div>
</div>
{% endif %}
<div class="row">
<div class="col s12">
<a {% if not can_edit %} disabled="" {% endif %} href="/m/inventory/{{ item._id }}/edit" class="waves-effect waves-light btn">
Edit
</a>
</div>
</div>
<div class="row">
<div class="col s12">
<a href="/m/inventory/{{ item._id }}/clone" class="waves-effect waves-light btn">Clone</a>
</div>
</div>
<div class="row">
<div class="col s12">
<button {% if can_audit %} data-target="audit-modal" {% else %} disabled="" {% endif %} class="modal-trigger orange waves-effect waves-light btn">
<i class="material-icons left">done</i>Audit
</button>
</div>
</div>
<div class="row">
<div class="col s12">
<form action="/m/inventory/{{ item._id }}/archive" method="post" style="display: inline;">
<button {% if not can_edit %} disabled="" {% endif %} class="red lighten-1 waves-effect waves-light btn" type="submit">
<i class="material-icons left">archive</i>Archive
</button>
</form>
</div>
</div>
{% if can_audit %}
<div id="audit-modal" class="modal">
<div class="modal-content">
<h4>Check that:</h4>
<p>
<label>
<input class="audit-check" type="checkbox"/>
<span>Object is present at the space</span>
</label>
</p>
<p>
<label>
<input class="audit-check" type="checkbox"/>
<span>There is no obvious issues and it does not present danger</span>
</label>
</p>
<p>
<label>
<input class="audit-check" type="checkbox"/>
<span>Object has QR code attached to it and it's up to date</span>
</label>
</p>
<p>
<label>
<input class="audit-check" type="checkbox"/>
<span>Picture is up to date</span>
</label>
</p>
</div>
<div class="modal-footer">
<form action="/m/inventory/{{ item._id }}/audit" method="post" style="display: inline;">
<button id="audit-modal-send" disabled="" type="submit" class="orange waves-effect waves-light btn"><i class="material-icons left">done</i>Confirm</button>
</form>
</div>
</div>
{% endif %}
</div>
<script>
$(function() {
var photoInput = $("#photo-form input[type=file]");
@@ -291,4 +175,3 @@ $(function() {
});
</script>
{% endblock %}