Tab the PC detail page and add panel groups to the ADR-010 contract

This commit is contained in:
2026-08-31 14:25:53 -04:00
parent 73a91ef916
commit 0d49341a2a
8 changed files with 315 additions and 20 deletions

View File

@@ -2,7 +2,7 @@
<!-- Generic renderer for ADR-010 get_asset_panels (Path A). A plugin declares
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 panels" :key="panel.id">
<template v-for="panel in groupedPanels" :key="panel.id">
<div v-if="panelVisible(panel)" class="section-card">
<!-- 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
@@ -149,7 +149,7 @@
</template>
<script setup>
import { ref, watch } from 'vue'
import { ref, computed, watch } from 'vue'
import api from '../api'
import { colorStyle } from '@/utils/colorStyle'
import {
@@ -183,10 +183,29 @@ function visibleRows(panel) {
const props = defineProps({
assetid: { type: [Number, String], default: null },
// Which detail-page tab to render. Null renders every panel, which is what
// the detail pages that have not adopted tabs still do - so this stays
// additive and no existing page changes behaviour.
group: { type: String, default: null },
})
const panels = ref([])
// The server resolves every panel's group before we see it, so an unknown or
// absent one is already 'details' by the time it arrives here. Filtering can
// therefore be a plain equality check and nothing falls through the gap.
const groupedPanels = computed(() =>
props.group ? panels.value.filter((p) => p.group === props.group) : panels.value
)
// Which groups actually have a panel with data, so a parent can hide a tab
// rather than offering an empty one.
const populatedGroups = computed(() => {
const seen = new Set()
panels.value.forEach((p) => { if (panelVisible(p)) seen.add(p.group || 'details') })
return seen
})
// Which tab each 'tabs' panel is showing, keyed by panel id. Kept here rather
// than on the panel object because panels are replaced wholesale on refetch.
const tabs = ref({})
@@ -334,7 +353,7 @@ watch(() => props.assetid, load, { immediate: true })
// Let a parent detail page (for example PCDetail's header Refresh button)
// trigger a panel reload without duplicating the fetch plumbing.
defineExpose({ refresh: load })
defineExpose({ refresh: load, populatedGroups })
</script>
<style scoped>