Drop the Actions tab and give wide panels the full width
This commit is contained in:
@@ -3,7 +3,7 @@
|
||||
a panel as JSON (title, endpoint, render mode, field map); this renders it
|
||||
on any asset detail page, so a plugin adds detail-page UI with no Vue. -->
|
||||
<template v-for="panel in groupedPanels" :key="panel.id">
|
||||
<div v-if="panelVisible(panel)" class="section-card">
|
||||
<div v-if="panelVisible(panel)" class="section-card" :class="{ 'pap-span': panel.render === 'table' }">
|
||||
<!-- collapsible panels get a clickable header with a caret and, when the
|
||||
panel declares a status rollup, a green/yellow/red dot for the worst
|
||||
row (a stopped service or a warning/critical event). --><h3
|
||||
@@ -430,7 +430,18 @@ defineExpose({ refresh: load, populatedGroups })
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.pap-table-wrap { overflow-x: auto; }
|
||||
/* A table panel SPANS BOTH COLUMNS rather than scrolling inside one.
|
||||
Network interfaces is the case that forced this: adapter, address, MAC,
|
||||
speed and state at half page width either squeezed every cell to three
|
||||
lines or handed the reader a horizontal scrollbar, and a scrollbar for
|
||||
data that simply needs room is a layout failure, not a feature. column-span
|
||||
is the multi-column layout's own answer, so the short fact cards stay two-up
|
||||
around it.
|
||||
|
||||
The wrapper keeps overflow-x as a floor for the genuinely too-wide case on
|
||||
a narrow viewport, where nothing else can help. */
|
||||
.pap-span { column-span: all; }
|
||||
.pap-table-wrap { overflow-x: auto; max-width: 100%; }
|
||||
.pap-table { width: 100%; border-collapse: collapse; font-size: 0.85rem; }
|
||||
.pap-table th, .pap-table td { text-align: left; padding: 0.4rem 0.6rem; border-bottom: 1px solid var(--border); }
|
||||
.pap-badges { display: flex; flex-wrap: wrap; gap: 0.5rem; }
|
||||
|
||||
@@ -272,11 +272,14 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Software. The core installed-applications list plus anything a plugin
|
||||
declared for this group. -->
|
||||
<div v-show="activegroup === 'software'" class="content-grid">
|
||||
<!-- Software and Activity run FULL WIDTH, not in the two-column flow the
|
||||
Details tab uses. Both are long lists rather than short fact cards:
|
||||
an application inventory or an event feed split into balanced columns
|
||||
reads as two unrelated lists, and the eye has to find where the first
|
||||
one ended. -->
|
||||
<div v-show="activegroup === 'software'" class="detail-full">
|
||||
<PluginAssetPanels :assetid="computer.assetid" group="software" />
|
||||
<div class="content-column">
|
||||
<div>
|
||||
<div class="section-card" v-if="installedApps.length > 0">
|
||||
<h3 class="section-title">Installed Applications</h3>
|
||||
<div class="app-list">
|
||||
@@ -299,16 +302,15 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Metrics, Actions and Activity are entirely plugin-contributed: the
|
||||
telemetry, the service controls and the event feed all belong to the
|
||||
endpoints plugin, and core knows nothing about them. -->
|
||||
<!-- Metrics and Activity are entirely plugin-contributed: the telemetry,
|
||||
the service state and its controls, and the event feed all belong to
|
||||
the endpoints plugin, and core knows nothing about them.
|
||||
|
||||
Metrics keeps the two-column flow because it is short cards. -->
|
||||
<div v-show="activegroup === 'metrics'" class="content-grid">
|
||||
<PluginAssetPanels :assetid="computer.assetid" group="metrics" />
|
||||
</div>
|
||||
<div v-show="activegroup === 'actions'" class="content-grid">
|
||||
<PluginAssetPanels :assetid="computer.assetid" group="actions" />
|
||||
</div>
|
||||
<div v-show="activegroup === 'activity'" class="content-grid">
|
||||
<div v-show="activegroup === 'activity'" class="detail-full">
|
||||
<PluginAssetPanels :assetid="computer.assetid" group="activity" />
|
||||
</div>
|
||||
|
||||
@@ -386,7 +388,6 @@ const detailtabs = computed(() => {
|
||||
tabs.push({ key: 'software', label: 'Software', count: installedApps.value.length || null })
|
||||
}
|
||||
if (has('metrics')) tabs.push({ key: 'metrics', label: 'Metrics' })
|
||||
if (has('actions')) tabs.push({ key: 'actions', label: 'Actions' })
|
||||
if (has('activity')) tabs.push({ key: 'activity', label: 'Activity' })
|
||||
return tabs
|
||||
})
|
||||
@@ -602,6 +603,12 @@ async function confirmRetire() {
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
/* Software and Activity are single long lists, so they use the full page width
|
||||
rather than .content-grid's two balanced columns. Cards inside still need
|
||||
their own vertical rhythm, which the column flow was providing. */
|
||||
.detail-full { display: flex; flex-direction: column; gap: 1rem; }
|
||||
.detail-full > * { min-width: 0; }
|
||||
|
||||
/* PC-specific styles - shared styles are in global style.css */
|
||||
|
||||
/* Remote-access protocol links */
|
||||
|
||||
@@ -351,8 +351,9 @@ class EndpointsPlugin(BasePlugin):
|
||||
'permission': 'endpoints.command',
|
||||
'empty': 'No monitored services reported.',
|
||||
'position': 12,
|
||||
# Start/Stop act on the machine, so this is a control surface
|
||||
'group': 'actions',
|
||||
# Service state is telemetry first; the Start/Stop controls
|
||||
# belong beside it rather than in a tab of their own.
|
||||
'group': 'metrics',
|
||||
},
|
||||
{
|
||||
'id': 'endpoints-tracked-processes',
|
||||
|
||||
@@ -25,7 +25,7 @@ pluginui_bp = Blueprint('pluginui', __name__)
|
||||
#
|
||||
# 'details' is first and is the fallback: it holds what an asset IS, which is
|
||||
# what a panel declaring nothing almost always contributes.
|
||||
ASSET_PANEL_GROUPS = ('details', 'software', 'metrics', 'actions', 'activity')
|
||||
ASSET_PANEL_GROUPS = ('details', 'software', 'metrics', 'activity')
|
||||
|
||||
|
||||
def _collect(hookname):
|
||||
|
||||
@@ -372,8 +372,7 @@ class BasePlugin(ABC):
|
||||
'position': int, # order among panels
|
||||
'group': str, # OPTIONAL. Which tab on the detail page:
|
||||
# 'details' | 'software' | 'metrics'
|
||||
# | 'actions' | 'activity'. Omitted means
|
||||
# 'details'.
|
||||
# | 'activity'. Omitted means 'details'.
|
||||
}
|
||||
|
||||
ON 'group'. The detail pages are tabbed, and a panel says which tab it
|
||||
@@ -384,8 +383,14 @@ class BasePlugin(ABC):
|
||||
existing plugin working untouched: an unknown or absent group resolves
|
||||
to 'details', which is the tab that holds what an asset IS. Reach for
|
||||
another group only when the panel is the thing that tab exists for -
|
||||
an inventory listing, live telemetry, controls that act on the machine,
|
||||
or a history feed.
|
||||
an inventory listing, live telemetry, or a history feed.
|
||||
|
||||
There is deliberately no group for controls. A panel that acts on the
|
||||
machine belongs beside the state it acts on: tracked services read as
|
||||
telemetry first and a Start/Stop second, so they live in 'metrics' with
|
||||
the rest of what the endpoint reports. Splitting the buttons away from
|
||||
the state they change made a tab that held one card and answered no
|
||||
question on its own.
|
||||
|
||||
Consumed by GET /api/pluginui/asset-panels?assetid=<id>, which returns
|
||||
the panels matching that asset's type. Disabled plugins
|
||||
|
||||
Reference in New Issue
Block a user