Call the inventory panel Assets, not Estate
All checks were successful
CI / naming (push) Successful in 3s
CI / frontend (push) Successful in 13s
CI / migrations-mysql (push) Successful in 40s
CI / backend (push) Successful in 4m11s

The panel had no group label before it was one panel, so grouping it needed a
heading and it got 'Estate' - RMM idiom, and the word the leadership documents
already used for the whole of what a site owns.

Wrong register for this surface. The sidebar already groups exactly these things
under a section named assets, so the dashboard had invented a second word for a
group the app already names, and the panel's own total row says 'All assets' -
the heading and the total disagreed inside one panel. 'Estate' is also
enterprise-IT and largely British idiom; it earns its place in an executive
summary and not on a screen read at 6am.

The scoped classes follow the label, so the markup does not keep a word the UI
stopped using. The documents keep 'estate', where it is doing real work for a
leadership reader.

Scope: product
This commit is contained in:
cproudlock
2026-08-30 12:57:05 -04:00
parent 58b53b50f6
commit 4c8291628f

View File

@@ -18,13 +18,13 @@
<template #rail>
<!-- Only when the totals actually loaded. /api/dashboard/summary
needs assets.view, and a caller without it got an empty object
that rendered as a tidy column of zeros - an estate of nothing,
stated with total confidence. Same fault as reporting Low
that rendered as a tidy column of zeros - a site with nothing
in it, stated with total confidence. Same fault as reporting Low
Supplies 0 while the monitoring is down. -->
<section v-if="summaryloaded" class="dc-panel estate">
<header class="estate-head">
<h3>Estate</h3>
<router-link to="/reports" class="estate-link">Reports</router-link>
<section v-if="summaryloaded" class="dc-panel assets">
<header class="assets-head">
<h3>Assets</h3>
<router-link to="/reports" class="assets-link">Reports</router-link>
</header>
<!-- One line per asset type, then the total under a rule.
@@ -37,21 +37,21 @@
EVERY counted type must appear here. The endpoint's grand total
is machines + PCs + network + printers + measuring tools, and
omitting one leaves a total nothing on screen explains. -->
<div class="estate-row">
<router-link to="/machines" class="estate-k">Machines</router-link>
<span class="estate-v">{{ stats.totalmachines || 0 }}</span>
<div class="assets-row">
<router-link to="/machines" class="assets-k">Machines</router-link>
<span class="assets-v">{{ stats.totalmachines || 0 }}</span>
</div>
<div class="estate-row">
<router-link to="/pcs" class="estate-k">PCs</router-link>
<span class="estate-v">{{ stats.totalpc || 0 }}</span>
<div class="assets-row">
<router-link to="/pcs" class="assets-k">PCs</router-link>
<span class="assets-v">{{ stats.totalpc || 0 }}</span>
</div>
<div class="estate-row">
<router-link to="/printers" class="estate-k">Printers</router-link>
<span class="estate-v">{{ stats.totalprinter || 0 }}</span>
<div class="assets-row">
<router-link to="/printers" class="assets-k">Printers</router-link>
<span class="assets-v">{{ stats.totalprinter || 0 }}</span>
</div>
<div class="estate-row">
<router-link to="/network" class="estate-k">Network devices</router-link>
<span class="estate-v">{{ stats.totalnetwork || 0 }}</span>
<div class="assets-row">
<router-link to="/network" class="assets-k">Network devices</router-link>
<span class="assets-v">{{ stats.totalnetwork || 0 }}</span>
</div>
<!-- Measuring tools are IN the grand total the endpoint returns, so
they have to be visible here. Left out, the total silently
@@ -59,23 +59,23 @@
729 on an instance with gages - which is the exact fault this
panel was built to remove. Dev has none, so it looked correct
here and was wrong everywhere the import had run. -->
<div class="estate-row">
<router-link to="/measuringtools" class="estate-k">Measuring tools</router-link>
<span class="estate-v">{{ stats.totalmeasuringtool || 0 }}</span>
<div class="assets-row">
<router-link to="/measuringtools" class="assets-k">Measuring tools</router-link>
<span class="assets-v">{{ stats.totalmeasuringtool || 0 }}</span>
</div>
<div class="estate-row estate-total">
<span class="estate-k">All assets</span>
<span class="estate-v">{{ stats.totalassets || 0 }}</span>
<div class="assets-row assets-total">
<span class="assets-k">All assets</span>
<span class="assets-v">{{ stats.totalassets || 0 }}</span>
</div>
<!-- Status, on one line, and explicitly labelled as status. In
repair is muted at zero rather than given a card of its own to
announce that nothing is wrong. -->
<p class="estate-status">
<span class="estate-inuse">{{ stats.activeassets || 0 }}</span> in use
<p class="assets-status">
<span class="assets-inuse">{{ stats.activeassets || 0 }}</span> in use
<span aria-hidden="true"> / </span>
<span :class="{ 'estate-zero': !stats.inrepair }">
<span :class="{ 'assets-zero': !stats.inrepair }">
{{ stats.inrepair || 0 }} in repair
</span>
</p>
@@ -89,12 +89,12 @@
uses - server-filtered for a signed-out visitor - so it can never
offer a link that dead-ends at the router guard, and it names no
plugin this page had to know about. -->
<section v-else-if="openable.length" class="dc-panel estate">
<header class="estate-head">
<section v-else-if="openable.length" class="dc-panel assets">
<header class="assets-head">
<h3>Where you can go</h3>
</header>
<div v-for="item in openable" :key="item.route" class="estate-row">
<router-link :to="item.route" class="estate-k">{{ item.name }}</router-link>
<div v-for="item in openable" :key="item.route" class="assets-row">
<router-link :to="item.route" class="assets-k">{{ item.name }}</router-link>
</div>
</section>
</template>
@@ -165,7 +165,7 @@ onMounted(async () => {
<style scoped>
/* Matches the panels in DashboardCards; the rail reads as one column rather
than as a page card that happens to sit beside them. */
.estate {
.assets {
background: var(--bg-card);
border: 1px solid var(--border);
border-radius: 8px;
@@ -173,13 +173,13 @@ onMounted(async () => {
min-width: 0;
}
.estate-head {
.assets-head {
display: flex;
align-items: baseline;
gap: 0.5rem;
margin-bottom: 0.35rem;
}
.estate-head h3 {
.assets-head h3 {
margin: 0;
font-size: 0.78rem;
font-weight: 700;
@@ -188,14 +188,14 @@ onMounted(async () => {
color: var(--text-light);
flex: 1 1 auto;
}
.estate-link {
.assets-link {
font-size: 0.78rem;
color: var(--link);
text-decoration: none;
}
.estate-link:hover { text-decoration: underline; }
.assets-link:hover { text-decoration: underline; }
.estate-row {
.assets-row {
display: flex;
align-items: baseline;
justify-content: space-between;
@@ -203,32 +203,32 @@ onMounted(async () => {
padding: 0.35rem 0;
border-bottom: 1px solid var(--border);
}
.estate-row:last-of-type { border-bottom: none; }
.assets-row:last-of-type { border-bottom: none; }
.estate-k {
.assets-k {
color: var(--link);
text-decoration: none;
font-size: 0.9rem;
}
a.estate-k:hover { text-decoration: underline; }
span.estate-k { color: var(--text); font-weight: 600; }
a.assets-k:hover { text-decoration: underline; }
span.assets-k { color: var(--text); font-weight: 600; }
.estate-v {
.assets-v {
font-weight: 600;
font-variant-numeric: tabular-nums;
}
.estate-total {
.assets-total {
margin-top: 0.35rem;
border-top: 2px solid var(--border);
border-bottom: none;
}
.estate-status {
.assets-status {
margin: 0.5rem 0 0;
font-size: 0.85rem;
color: var(--text-light);
}
.estate-inuse { color: var(--success); font-weight: 600; font-variant-numeric: tabular-nums; }
.estate-zero { color: var(--text-light); }
.assets-inuse { color: var(--success); font-weight: 600; font-variant-numeric: tabular-nums; }
.assets-zero { color: var(--text-light); }
</style>