Major overhaul to the Notes/Issues. Minor tweaks to the UI. Added Profile photos
This commit is contained in:
@@ -485,37 +485,13 @@ export default function DeviceDetail() {
|
||||
<section className="rounded-lg border p-6" style={{ backgroundColor: "var(--bg-card)", borderColor: "var(--border-primary)" }}>
|
||||
<h2 className="text-lg font-semibold mb-4" style={{ color: "var(--text-heading)" }}>Device Information</h2>
|
||||
<div style={{ display: "grid", gridTemplateColumns: "1fr 1fr 1fr", gap: "1rem", alignItems: "start" }}>
|
||||
{/* Col 1: Status on top, device image below */}
|
||||
<div style={{ display: "flex", flexDirection: "column", gap: "0.75rem", height: "100%" }}>
|
||||
<div style={{ display: "flex", alignItems: "center", gap: "0.75rem" }}>
|
||||
<div
|
||||
className="w-10 h-10 rounded-full flex items-center justify-center shrink-0"
|
||||
style={{ backgroundColor: isOnline ? "var(--success-bg)" : "var(--bg-card-hover)" }}
|
||||
>
|
||||
<span
|
||||
className="w-3 h-3 rounded-full inline-block"
|
||||
style={{ backgroundColor: isOnline ? "var(--success-text)" : "var(--text-muted)" }}
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<div className="text-xs font-medium uppercase tracking-wide" style={{ color: "var(--text-muted)" }}>Status</div>
|
||||
<div className="text-sm font-semibold" style={{ color: isOnline ? "var(--success-text)" : "var(--text-muted)" }}>
|
||||
{isOnline ? "Online" : "Offline"}
|
||||
{mqttStatus && (
|
||||
<span className="ml-2 text-xs font-normal" style={{ color: "var(--text-muted)" }}>
|
||||
{mqttStatus.seconds_since_heartbeat}s ago
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div style={{ flex: 1, display: "flex", alignItems: "center", justifyContent: "center" }}>
|
||||
<img
|
||||
src={hwImage}
|
||||
alt={hwVariant}
|
||||
style={{ maxHeight: 80, maxWidth: "100%", objectFit: "contain", opacity: 0.85 }}
|
||||
/>
|
||||
</div>
|
||||
{/* Col 1: Device image */}
|
||||
<div style={{ display: "flex", alignItems: "center", height: "100%" }}>
|
||||
<img
|
||||
src={hwImage}
|
||||
alt={hwVariant}
|
||||
style={{ maxHeight: 120, maxWidth: "100%", objectFit: "contain", opacity: 0.85 }}
|
||||
/>
|
||||
</div>
|
||||
|
||||
{/* Col 2: Serial Number, Hardware Variant, Document ID */}
|
||||
@@ -785,23 +761,35 @@ export default function DeviceDetail() {
|
||||
{attr.bellOutputs.map((output, i) => (
|
||||
<div
|
||||
key={i}
|
||||
className="relative rounded-md border px-4 py-3 text-center overflow-hidden"
|
||||
style={{ borderColor: "var(--border-primary)", backgroundColor: "var(--bg-primary)", minWidth: 90 }}
|
||||
className="rounded-md border overflow-hidden"
|
||||
style={{ borderColor: "var(--border-primary)", backgroundColor: "var(--bg-primary)", minWidth: 120 }}
|
||||
>
|
||||
<span
|
||||
className="absolute inset-0 flex items-center justify-center font-bold pointer-events-none select-none"
|
||||
style={{ fontSize: "3rem", color: "var(--text-heading)", opacity: 0.06 }}
|
||||
>
|
||||
{i + 1}
|
||||
</span>
|
||||
<div className="relative">
|
||||
<div className="text-xs" style={{ color: "var(--text-muted)" }}>
|
||||
Output <span style={{ color: "var(--text-primary)" }}>{output}</span>
|
||||
<div style={{ display: "flex", alignItems: "stretch" }}>
|
||||
<div
|
||||
style={{
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
justifyContent: "center",
|
||||
width: 44,
|
||||
fontSize: "1.5rem",
|
||||
fontWeight: 700,
|
||||
color: "var(--text-heading)",
|
||||
opacity: 0.15,
|
||||
borderRight: "1px solid var(--border-primary)",
|
||||
flexShrink: 0,
|
||||
}}
|
||||
>
|
||||
{i + 1}
|
||||
</div>
|
||||
<div className="text-xs mt-1" style={{ color: "var(--text-muted)" }}>
|
||||
{attr.hammerTimings?.[i] != null ? (
|
||||
<><span style={{ color: "var(--text-primary)" }}>{attr.hammerTimings[i]}</span> ms</>
|
||||
) : "-"}
|
||||
<div style={{ padding: "0.5rem 0.75rem" }}>
|
||||
<div className="text-xs" style={{ color: "var(--text-muted)" }}>
|
||||
Output <span style={{ color: "var(--text-primary)" }}>{output}</span>
|
||||
</div>
|
||||
<div className="text-xs mt-1" style={{ color: "var(--text-muted)" }}>
|
||||
{attr.hammerTimings?.[i] != null ? (
|
||||
<>Timing <span style={{ color: "var(--text-primary)" }}>{attr.hammerTimings[i]}</span> ms</>
|
||||
) : "Timing -"}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -920,17 +908,28 @@ export default function DeviceDetail() {
|
||||
style={{ backgroundColor: "var(--bg-primary)", borderColor: "var(--border-primary)" }}
|
||||
onClick={() => user.user_id && navigate(`/users/${user.user_id}`)}
|
||||
>
|
||||
<div className="flex items-center justify-between">
|
||||
<div className="min-w-0">
|
||||
<p className="text-sm font-medium truncate" style={{ color: "var(--text-heading)" }}>
|
||||
{user.display_name || user.email || "Unknown User"}
|
||||
</p>
|
||||
{user.email && user.display_name && (
|
||||
<p className="text-xs truncate" style={{ color: "var(--text-muted)" }}>{user.email}</p>
|
||||
)}
|
||||
{user.user_id && (
|
||||
<p className="text-xs font-mono" style={{ color: "var(--text-muted)" }}>{user.user_id}</p>
|
||||
)}
|
||||
<div className="flex items-center justify-between gap-3">
|
||||
<div className="flex items-center gap-3 min-w-0">
|
||||
<div
|
||||
className="w-8 h-8 rounded-full overflow-hidden shrink-0"
|
||||
style={{ backgroundColor: "var(--bg-card-hover)" }}
|
||||
>
|
||||
{user.photo_url ? (
|
||||
<img src={user.photo_url} alt="" style={{ width: "100%", height: "100%", objectFit: "cover" }} />
|
||||
) : (
|
||||
<div className="w-full h-full flex items-center justify-center text-xs font-bold" style={{ color: "var(--text-muted)" }}>
|
||||
{(user.display_name || user.email || "?").charAt(0).toUpperCase()}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
<div className="min-w-0">
|
||||
<p className="text-sm font-medium truncate" style={{ color: "var(--text-heading)" }}>
|
||||
{user.display_name || user.email || "Unknown User"}
|
||||
</p>
|
||||
{user.email && user.display_name && (
|
||||
<p className="text-xs truncate" style={{ color: "var(--text-muted)", opacity: 0.7 }}>{user.email}</p>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
{user.role && (
|
||||
<span className="px-2 py-0.5 text-xs rounded-full capitalize shrink-0 ml-2" style={{ backgroundColor: "var(--badge-blue-bg)", color: "var(--badge-blue-text)" }}>
|
||||
@@ -1026,11 +1025,20 @@ export default function DeviceDetail() {
|
||||
<h1 className="text-2xl font-bold" style={{ color: "var(--text-heading)" }}>
|
||||
{device.device_name || "Unnamed Device"}
|
||||
</h1>
|
||||
<span
|
||||
className={`inline-block w-3 h-3 rounded-full ${isOnline ? "bg-green-500" : ""}`}
|
||||
style={!isOnline ? { backgroundColor: "var(--border-primary)" } : undefined}
|
||||
title={isOnline ? "Online" : "Offline"}
|
||||
/>
|
||||
<div style={{ display: "flex", alignItems: "center", gap: "0.5rem" }}>
|
||||
<span
|
||||
className="w-3 h-3 rounded-full inline-block"
|
||||
style={{ backgroundColor: isOnline ? "var(--success-text)" : "var(--text-muted)" }}
|
||||
/>
|
||||
<span className="text-sm font-semibold" style={{ color: isOnline ? "var(--success-text)" : "var(--text-muted)" }}>
|
||||
{isOnline ? "Online" : "Offline"}
|
||||
{mqttStatus && (
|
||||
<span className="ml-2 text-xs font-normal" style={{ color: "var(--text-muted)" }}>
|
||||
{mqttStatus.seconds_since_heartbeat}s ago
|
||||
</span>
|
||||
)}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{canEdit && (
|
||||
|
||||
Reference in New Issue
Block a user