dashboard: tighten the printer, warranty and notification cards
PRINTER CARD is now supplies at or below 5 percent, a new printers_dashboardpercent setting. The report and the card want different scopes: the report lists anything the thresholds call low, which is right for planning an order, while the dashboard is asking what to walk out and change today - and a cartridge at 18 percent is not that. Lowest first. PRINTER LOCATION WAS ALWAYS EMPTY. The lookup went through db.session.get on locationid and produced nothing even where a location is set; the printers list has always read it through the asset relationship, so the card does too now. WARRANTY ROWS are identified the way the floor identifies them: the PC's hostname and the MACHINE it drives, reusing the same lookup behind the warranty page's machine column so the board and the report cannot disagree about which bay a PC belongs to. No dates - expired or expiring is the whole decision when scanning a board, and the exact day belongs on the report you order from. NOTIFICATIONS are stacked: the type in full on one line, the message beneath, trimmed to 100 characters with the rest on hover. Inline, the type was truncated to make room for prose that was then truncated anyway, and neither read. A tooltip is omitted when the text was not trimmed, because one repeating what is already on screen is noise. Two general additions: layout: 'stacked' on a card, and map.detailtooltip.
This commit is contained in:
@@ -17,14 +17,16 @@
|
||||
|
||||
<!-- exceptions / list: one line per thing, each linking to itself -->
|
||||
<ul v-else class="dc-rows">
|
||||
<li v-for="(row, index) in visibleRows(card)" :key="index" class="dc-row">
|
||||
<li v-for="(row, index) in visibleRows(card)" :key="index" class="dc-row"
|
||||
:class="{ 'dc-row-stacked': card.layout === 'stacked' }">
|
||||
<router-link v-if="row.link" :to="row.link" class="dc-row-title"
|
||||
:title="row.titletip || undefined">
|
||||
{{ row.title }}
|
||||
</router-link>
|
||||
<span v-else class="dc-row-title dc-row-nolink"
|
||||
:title="row.titletip || undefined">{{ row.title }}</span>
|
||||
<span v-if="row.detail" class="dc-row-detail">{{ row.detail }}</span>
|
||||
<span v-if="row.detail" class="dc-row-detail"
|
||||
:title="row.detailtip || undefined">{{ row.detail }}</span>
|
||||
<span v-for="(chip, c) in row.chips" :key="c" class="dc-chip"
|
||||
:class="'dc-chip-' + (chip.level || 'low')" :title="chip.title">
|
||||
{{ chip.text }}
|
||||
@@ -173,6 +175,12 @@ defineExpose({ load })
|
||||
min-width: 0;
|
||||
}
|
||||
.dc-row:last-child { border-bottom: none; }
|
||||
/* Stacked: a label on one line, prose beneath. Inline, the label is truncated
|
||||
to make room for text that is then truncated anyway, and neither reads. */
|
||||
.dc-row-stacked { flex-direction: column; align-items: stretch; gap: 0.15rem; }
|
||||
.dc-row-stacked .dc-row-title { max-width: 100%; }
|
||||
.dc-row-stacked .dc-row-detail { white-space: normal; color: var(--text-light); }
|
||||
.dc-row-stacked .dc-row-meta { margin-left: 0; padding-left: 0; }
|
||||
.dc-row-title {
|
||||
font-weight: 600;
|
||||
color: var(--link);
|
||||
|
||||
@@ -43,6 +43,14 @@ export function mapDetail(card, item) {
|
||||
return key ? item[key] : ''
|
||||
}
|
||||
|
||||
// The untruncated text behind a shortened detail. Same rule as elsewhere: the
|
||||
// tooltip explains, it never carries the only copy of something essential.
|
||||
export function mapDetailTip(card, item) {
|
||||
const key = card.map && card.map.detailtooltip
|
||||
const full = key ? (item[key] || '') : ''
|
||||
return full && full !== mapDetail(card, item) ? full : ''
|
||||
}
|
||||
|
||||
export function mapMeta(card, item) {
|
||||
const meta = (card.map && card.map.meta) || []
|
||||
return meta
|
||||
@@ -115,6 +123,7 @@ export function cardRows(card) {
|
||||
title: mapTitle(card, item),
|
||||
titletip: mapTitleTip(card, item),
|
||||
detail: mapDetail(card, item),
|
||||
detailtip: mapDetailTip(card, item),
|
||||
meta: mapMeta(card, item),
|
||||
chips: mapChips(card, item),
|
||||
link: mapLink(card, item),
|
||||
|
||||
@@ -202,3 +202,27 @@ describe('chips and tooltips', () => {
|
||||
.toEqual([])
|
||||
})
|
||||
})
|
||||
|
||||
describe('stacked rows', () => {
|
||||
const card = {
|
||||
render: 'list',
|
||||
layout: 'stacked',
|
||||
map: { title: 'typename', detail: 'message', detailtooltip: 'fullmessage' },
|
||||
_data: [{ typename: 'Recertification', message: 'Short text', fullmessage: 'Short text' }],
|
||||
}
|
||||
|
||||
it('offers no tooltip when the detail is already whole', () => {
|
||||
// A tooltip repeating what is on screen is noise, and it makes the cursor
|
||||
// change for no reason.
|
||||
expect(cardRows(card)[0].detailtip).toBe('')
|
||||
})
|
||||
|
||||
it('offers the full text when the detail was trimmed', () => {
|
||||
const trimmed = { ...card, _data: [{
|
||||
typename: 'General', message: 'Start of a long message...',
|
||||
fullmessage: 'Start of a long message that continues well past the card',
|
||||
}] }
|
||||
expect(cardRows(trimmed)[0].detailtip)
|
||||
.toBe('Start of a long message that continues well past the card')
|
||||
})
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user