Dashboard cards, backup last-seen
This commit is contained in:
@@ -934,3 +934,63 @@ def dashboard_summary():
|
||||
'shopfloor': shopfloor_count,
|
||||
'nonshopfloor': total - shopfloor_count
|
||||
})
|
||||
|
||||
|
||||
@computers_bp.route('/dashboard/quiet', methods=['GET'])
|
||||
@jwt_required()
|
||||
@require_permission('computers.view')
|
||||
def dashboard_quiet():
|
||||
"""PCs that have stopped reporting, and PCs that never started.
|
||||
|
||||
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.
|
||||
|
||||
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.
|
||||
"""
|
||||
from datetime import datetime, timedelta, timezone
|
||||
|
||||
hours = 24
|
||||
setting = Setting.query.filter_by(key='computers_quietreporthours').first()
|
||||
if setting and (setting.value or '').strip():
|
||||
try:
|
||||
hours = int(setting.value)
|
||||
except (TypeError, ValueError):
|
||||
pass
|
||||
cutoff = datetime.now(timezone.utc).replace(tzinfo=None) - timedelta(hours=hours)
|
||||
|
||||
query = (db.session.query(Computer, Asset)
|
||||
.join(Asset, Asset.assetid == Computer.assetid)
|
||||
.filter(Asset.isactive.is_(True)))
|
||||
|
||||
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,
|
||||
})
|
||||
|
||||
# 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])
|
||||
|
||||
@@ -163,6 +163,14 @@ class ComputersPlugin(BasePlugin):
|
||||
site that installed an earlier one.
|
||||
"""
|
||||
return [
|
||||
{
|
||||
'key': 'computers_quietreporthours',
|
||||
'value': '24',
|
||||
'valuetype': 'integer',
|
||||
'category': 'computers',
|
||||
'description': 'Hours without a collector report before a PC '
|
||||
'is listed as not reporting on the dashboard.',
|
||||
},
|
||||
{
|
||||
'key': 'computers_machinelink_alerts',
|
||||
'value': 'false',
|
||||
@@ -1247,14 +1255,30 @@ class ComputersPlugin(BasePlugin):
|
||||
return [computerscli]
|
||||
|
||||
def get_dashboard_widgets(self) -> List[Dict]:
|
||||
"""Return dashboard widget definitions."""
|
||||
"""Dashboard cards this plugin contributes.
|
||||
|
||||
REPLACES a declaration that named a Vue component which was never
|
||||
written - as did four other plugins - so nothing rendered and nobody
|
||||
noticed, because the frontend never called the widgets endpoint either.
|
||||
The contract now carries data and a renderer; core draws it.
|
||||
"""
|
||||
return [
|
||||
{
|
||||
'name': 'Computer Status',
|
||||
'component': 'ComputerStatusWidget',
|
||||
'endpoint': '/api/computers/dashboard/summary',
|
||||
'size': 'medium',
|
||||
'position': 6,
|
||||
'id': 'computers-quiet',
|
||||
'title': 'PCs not reporting',
|
||||
'endpoint': '/api/computers/dashboard/quiet',
|
||||
'render': 'exceptions',
|
||||
'severity': 'warning',
|
||||
'permission': 'computers.view',
|
||||
'empty': 'hide',
|
||||
'position': 20,
|
||||
'map': {
|
||||
'title': 'hostname',
|
||||
'detail': 'state',
|
||||
'meta': [{'key': 'quietdays', 'label': 'quiet for',
|
||||
'suffix': ' days'}],
|
||||
'link': '/pcs/{computerid}',
|
||||
},
|
||||
},
|
||||
]
|
||||
|
||||
|
||||
Reference in New Issue
Block a user