USB external import, and filter chips on health-dot cards
This commit is contained in:
@@ -31,8 +31,25 @@
|
||||
|
||||
<!-- list: items each with a title, optional status badge, meta lines -->
|
||||
<div v-if="panel.render === 'list'" class="pap-list">
|
||||
<template v-if="rows(panel).length">
|
||||
<div v-for="(item, index) in rows(panel)" :key="index" class="pap-item">
|
||||
<!-- Filter chips for any list panel that shows a health dot. Client
|
||||
side over rows already fetched, so the counts cannot disagree with
|
||||
what is on screen. -->
|
||||
<div v-if="facets(panel).length > 1" class="pap-facets">
|
||||
<button
|
||||
v-for="facet in facets(panel)"
|
||||
:key="facet.value"
|
||||
type="button"
|
||||
class="pap-facet"
|
||||
:class="{ on: isFacetOn(panel, facet.value) }"
|
||||
@click="toggleFacet(panel, facet.value)"
|
||||
>{{ facet.label }} <span class="pap-facet-count">{{ facet.count }}</span></button>
|
||||
<button v-if="facetSelection[panel.id] && facetSelection[panel.id].length"
|
||||
type="button" class="pap-facet pap-facet-clear"
|
||||
@click="facetSelection[panel.id] = []">Clear</button>
|
||||
</div>
|
||||
|
||||
<template v-if="visibleRows(panel).length">
|
||||
<div v-for="(item, index) in visibleRows(panel)" :key="index" class="pap-item">
|
||||
<div class="pap-item-top">
|
||||
<span class="pap-title">{{ mapTitle(panel, item) }}</span>
|
||||
<span v-if="mapBadge(panel, item)" class="status-badge"
|
||||
@@ -59,6 +76,9 @@
|
||||
{{ actionError[panel.id] }}
|
||||
</div>
|
||||
</template>
|
||||
<div v-else-if="rows(panel).length" class="pap-empty">
|
||||
Nothing matches that filter. {{ rows(panel).length }} row(s) hidden.
|
||||
</div>
|
||||
<div v-else class="pap-empty">
|
||||
<span class="muted">{{ panel.empty || 'Nothing to show.' }}</span>
|
||||
<router-link v-if="panel.manage" :to="manageLink(panel, assetid)" class="pap-manage">
|
||||
@@ -135,9 +155,32 @@ import { colorStyle } from '@/utils/colorStyle'
|
||||
import {
|
||||
toApiPath, rows, panelVisible, mapTitle, mapBadge, mapMeta, manageLink,
|
||||
keyvalueFields, tableColumns, cell, badges, tabSections, rollupStatus,
|
||||
rowAction,
|
||||
rowAction, facets, facetedRows,
|
||||
} from './pluginAssetPanels'
|
||||
|
||||
// Which filter chips are active, per panel id. Deliberately NOT reset when the
|
||||
// data refreshes: a viewer who filtered to criticals and then hit refresh means
|
||||
// to still be looking at criticals.
|
||||
const facetSelection = ref({})
|
||||
|
||||
function isFacetOn(panel, value) {
|
||||
return (facetSelection.value[panel.id] || []).includes(value)
|
||||
}
|
||||
|
||||
function toggleFacet(panel, value) {
|
||||
const current = facetSelection.value[panel.id] || []
|
||||
facetSelection.value = {
|
||||
...facetSelection.value,
|
||||
[panel.id]: current.includes(value)
|
||||
? current.filter((v) => v !== value)
|
||||
: [...current, value],
|
||||
}
|
||||
}
|
||||
|
||||
function visibleRows(panel) {
|
||||
return facetedRows(panel, facetSelection.value[panel.id])
|
||||
}
|
||||
|
||||
const props = defineProps({
|
||||
assetid: { type: [Number, String], default: null },
|
||||
})
|
||||
@@ -302,6 +345,33 @@ defineExpose({ refresh: load })
|
||||
.status-badge { padding: 0.15rem 0.6rem; border-radius: 12px; font-size: 0.75rem; font-weight: 600; }
|
||||
.pap-meta { margin-top: 0.35rem; display: flex; flex-wrap: wrap; gap: 0.75rem; font-size: 0.82rem; color: var(--text-light); }
|
||||
.pap-empty { display: flex; align-items: center; gap: 0.6rem; }
|
||||
|
||||
.pap-facets {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 0.35rem;
|
||||
margin-bottom: 0.6rem;
|
||||
}
|
||||
|
||||
.pap-facet {
|
||||
font: inherit;
|
||||
font-size: 0.78rem;
|
||||
line-height: 1.6;
|
||||
padding: 0.05rem 0.5rem;
|
||||
border: 1px solid var(--border);
|
||||
border-radius: 10px;
|
||||
background: transparent;
|
||||
color: var(--text-light);
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.pap-facet:hover { border-color: var(--primary); }
|
||||
.pap-facet.on { border-color: var(--primary); color: var(--primary); }
|
||||
.pap-facet-clear { border-style: dashed; }
|
||||
|
||||
/* The count is the point: a red dot over a list of info rows is confusing
|
||||
until the chip says "Critical 2" and one click shows them. */
|
||||
.pap-facet-count { font-variant-numeric: tabular-nums; opacity: 0.75; }
|
||||
.pap-manage { font-size: 0.82rem; }
|
||||
/* Two aligned columns rather than space-between: a ragged right edge is hard
|
||||
to scan once a panel carries more than a handful of rows, and a long value
|
||||
|
||||
Reference in New Issue
Block a user