Add per-server notes field and show hardware info on dashboard
All checks were successful
Build-Publish / build (linux/amd64) (push) Successful in 4s
Build-Publish / build (linux/arm64) (push) Successful in 12s
Build-Publish / create-manifest (push) Successful in 1s
Build-Publish / publish-template (push) Successful in 8s

This commit is contained in:
j
2026-03-08 13:27:35 +13:00
parent 8747209181
commit 5052d4604f
3 changed files with 82 additions and 0 deletions

View File

@@ -39,6 +39,7 @@ class Server(db.Model):
is_online = db.Column(db.Boolean, default=False)
last_collected = db.Column(db.DateTime, nullable=True)
details = db.Column(db.JSON, nullable=True)
notes = db.Column(db.Text, default='')
__table_args__ = (db.UniqueConstraint('username', 'hostname', name='uq_user_host'),)
@@ -282,11 +283,22 @@ def api_servers():
'url': s.url,
'is_online': s.is_online,
'last_collected': s.last_collected.isoformat() if s.last_collected else None,
'notes': s.notes,
'details': s.details,
})
return jsonify(result)
@app.route('/api/servers/<int:server_id>/notes', methods=['PUT'])
def api_update_notes(server_id):
from flask import request
server = Server.query.get_or_404(server_id)
data = request.get_json()
server.notes = data.get('notes', '')
db.session.commit()
return jsonify({'ok': True})
def _ip_sort_key(ip_str):
if not ip_str:
return [999, 999, 999, 999]

View File

@@ -288,6 +288,36 @@ main {
text-align: right;
}
/* --- Notes --- */
.notes-section {
margin-bottom: 12px;
}
.notes-input {
width: 100%;
min-height: 32px;
background: #0f172a;
border: 1px solid #1e3a5f;
border-radius: 6px;
color: #cbd5e1;
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;
font-size: 0.8rem;
padding: 8px 10px;
resize: none;
overflow: hidden;
line-height: 1.4;
}
.notes-input:focus {
outline: none;
border-color: #3b82f6;
}
.notes-input::placeholder {
color: #475569;
}
/* --- Container / VM Sub-cards --- */
.container-grid {

View File

@@ -55,6 +55,13 @@
</div>
<div class="server-ip">{{ server.primary_ip or 'No IP' }}</div>
<div class="server-os">{{ sys.get('os_pretty', '') }}</div>
{% if server.is_online and (cpu.get('model') or mem.get('total_mb')) %}
<div class="server-hw">
{%- if cpu.get('model') %}{{ cpu.get('model') }}{% endif %}
{%- if cpu.get('cores') %} ({{ cpu.get('cores') }}c){% endif %}
{%- if mem.get('total_mb') %} / {{ mem.get('total_mb', '')|format_mb }}{% endif -%}
</div>
{% endif %}
{% if server.is_online %}
<div class="usage-bars">
@@ -96,6 +103,13 @@
<!-- Expanded Details -->
<div class="card-details" style="display: none;">
<div class="notes-section">
<textarea class="notes-input"
data-server-id="{{ server.id }}"
placeholder="Add notes..."
onclick="event.stopPropagation();"
oninput="autoResizeNotes(this); debounceSaveNotes(this);">{{ server.notes or '' }}</textarea>
</div>
<div class="details-grid">
<!-- System Info -->
<div class="detail-section">
@@ -170,6 +184,7 @@
<tr class="table-header"><td>Interface</td><td>IPv4</td><td>IPv6</td><td>MAC</td><td>State</td><td>Speed</td><td>Driver</td></tr>
{% set nets = d.get('net', []) if d.get('net') else [] %}
{% for iface in nets %}
{% if iface.get('ipv4') or iface.get('ipv6') %}
<tr>
<td>{{ iface.get('name', iface.get('_name', '-')) }}</td>
<td>{{ iface.get('ipv4', '-') or '-' }}</td>
@@ -179,6 +194,7 @@
<td>{% if iface.get('speed_mbps') %}{{ iface.get('speed_mbps') }} Mbps{% else %}-{% endif %}</td>
<td>{{ iface.get('driver', '-') or '-' }}</td>
</tr>
{% endif %}
{% endfor %}
</table>
@@ -322,8 +338,32 @@
if (!isOpen) {
details.style.display = 'block';
card.classList.add('expanded');
// Auto-resize notes textarea
const ta = details.querySelector('.notes-input');
if (ta) autoResizeNotes(ta);
}
}
function autoResizeNotes(ta) {
ta.style.height = 'auto';
ta.style.height = ta.scrollHeight + 'px';
}
let _notesTimers = {};
function debounceSaveNotes(ta) {
const id = ta.dataset.serverId;
clearTimeout(_notesTimers[id]);
_notesTimers[id] = setTimeout(() => saveNotes(ta), 800);
}
function saveNotes(ta) {
const id = ta.dataset.serverId;
fetch('/api/servers/' + id + '/notes', {
method: 'PUT',
headers: {'Content-Type': 'application/json'},
body: JSON.stringify({notes: ta.value})
});
}
</script>
</body>
</html>