Dashboard polish

This commit is contained in:
2026-08-11 15:28:29 -04:00
parent f1d46e7ab8
commit 34cb9a5e3e
11 changed files with 150 additions and 76 deletions

View File

@@ -940,21 +940,25 @@ def dashboard_summary():
@jwt_required()
@require_permission('computers.view')
def dashboard_quiet():
"""PCs that have stopped reporting, and PCs that never started.
"""PCs that WERE reporting, have stopped, and are still meant to be in use.
Two populations, deliberately distinguished rather than merged into one
count. A PC that reported and went quiet is probably switched off, moved or
broken. A PC that has NEVER reported is worse: it is either not enrolled, or
enrolled against the wrong pc-type, so nothing enforces anything on it and
no backup of it exists. That one hides indefinitely because nothing about it
is failing loudly - and it is exactly the shape of the bay that carried a
wrong machine number for weeks.
Three filters, and each removes a population that would otherwise be noise:
Silence is the only signal available here. There is no heartbeat separate
from the report, so 'stopped reporting' is measured against the collector's
own last write.
Never reported at all is EXCLUDED. Those are usually records created by
hand or imported, not bays that broke - listing them buries the PCs that
actually changed state behind rows nobody is going to act on.
Not In Use is EXCLUDED. A PC in Repair, Inventory or Retired is silent on
purpose; that is the status doing its job, not a fault.
Soft-deleted is excluded for the same reason.
What is left is the real signal: a machine that was working, is not now, and
nobody has marked as anything else. Silence is the only evidence available -
there is no heartbeat separate from the report.
"""
from datetime import datetime, timedelta, timezone
from shopdb.api import AssetStatus
hours = 24
setting = Setting.query.filter_by(key='computers_quietreporthours').first()
@@ -964,36 +968,26 @@ def dashboard_quiet():
except (TypeError, ValueError):
pass
cutoff = datetime.now(timezone.utc).replace(tzinfo=None) - timedelta(hours=hours)
now = datetime.now(timezone.utc).replace(tzinfo=None)
query = (db.session.query(Computer, Asset)
.join(Asset, Asset.assetid == Computer.assetid)
.filter(Asset.isactive.is_(True)))
rows = (db.session.query(Computer, Asset)
.join(Asset, Asset.assetid == Computer.assetid)
.join(AssetStatus, AssetStatus.statusid == Asset.statusid)
.filter(Asset.isactive.is_(True),
AssetStatus.status == 'In Use',
Computer.lastreporteddate.isnot(None),
Computer.lastreporteddate < cutoff)
.all())
rows = []
for comp, asset in query.all():
last = comp.lastreporteddate
if last is None:
rows.append({
'computerid': comp.computerid,
'hostname': comp.hostname,
'state': 'never reported',
'lastreported': None,
'quietdays': None,
})
elif last < cutoff:
rows.append({
'computerid': comp.computerid,
'hostname': comp.hostname,
'state': 'stopped reporting',
'lastreported': last.isoformat() + 'Z',
'quietdays': (datetime.now(timezone.utc).replace(tzinfo=None)
- last).days,
})
out = [{
'computerid': comp.computerid,
'hostname': comp.hostname,
'lastreported': comp.lastreporteddate.isoformat() + 'Z',
'quietdays': (now - comp.lastreporteddate).days,
} for comp, _asset in rows]
# Never-reported first, then longest silence: the order someone should work
# down the list, not the order the rows came out of the table.
rows.sort(key=lambda r: (r['quietdays'] is not None, -(r['quietdays'] or 0)))
return success_response(rows[:50])
out.sort(key=lambda r: -r['quietdays'])
return success_response(out[:50])
@computers_bp.route('/dashboard/sharedmachines', methods=['GET'])

View File

@@ -1265,7 +1265,8 @@ class ComputersPlugin(BasePlugin):
return [
{
'id': 'computers-quiet',
'title': 'PCs not reporting',
'viewall': '/pcs',
'title': 'PCs gone silent',
'endpoint': '/api/computers/dashboard/quiet',
'render': 'exceptions',
'severity': 'warning',
@@ -1274,14 +1275,15 @@ class ComputersPlugin(BasePlugin):
'position': 20,
'map': {
'title': 'hostname',
'detail': 'state',
'meta': [{'key': 'quietdays', 'label': 'quiet for',
'detail': '',
'meta': [{'key': 'quietdays', 'label': 'silent',
'suffix': ' days'}],
'link': '/pcs/{computerid}',
},
},
{
'id': 'computers-sharedmachines',
'viewall': '/machines',
'title': 'Machine numbers on two PCs',
'endpoint': '/api/computers/dashboard/sharedmachines',
'render': 'exceptions',