Show unavailable Fleet history explicitly
This commit is contained in:
@@ -125,6 +125,7 @@
|
||||
:node="fleet.selectedNode.value"
|
||||
:node-id="fleet.selectedNodeId.value"
|
||||
:history-loading="fleet.nodeHistoryLoading.value"
|
||||
:history-message="fleet.nodeHistoryMessage.value"
|
||||
:history-labels="fleet.nodeHistoryLabels.value"
|
||||
:cpu-datasets="fleet.nodeHistoryCpuDatasets.value"
|
||||
:mem-datasets="fleet.nodeHistoryMemDatasets.value"
|
||||
|
||||
@@ -32,6 +32,7 @@
|
||||
</div>
|
||||
|
||||
<!-- History Charts -->
|
||||
<p v-if="historyMessage" role="status" class="text-sm text-amber-200 mb-4">{{ historyMessage }}</p>
|
||||
<div v-if="historyLoading && !historyLabels.length" class="text-white/40 text-sm py-4 text-center mb-4">
|
||||
Loading history...
|
||||
</div>
|
||||
@@ -129,6 +130,7 @@ defineProps<{
|
||||
node: FleetNode | null
|
||||
nodeId: string
|
||||
historyLoading: boolean
|
||||
historyMessage?: string
|
||||
historyLabels: string[]
|
||||
cpuDatasets: ChartDataset[]
|
||||
memDatasets: ChartDataset[]
|
||||
|
||||
@@ -2,8 +2,9 @@ import { afterEach, expect, it, vi } from 'vitest'
|
||||
import { defineComponent } from 'vue'
|
||||
import { flushPromises, mount } from '@vue/test-utils'
|
||||
import { rpcClient } from '@/api/rpc-client'
|
||||
import { useFleetData } from '../useFleetData'
|
||||
import { useFleetData, normalizeFleetNode } from '../useFleetData'
|
||||
import FleetAlerts from '../FleetAlerts.vue'
|
||||
import FleetNodeDetail from '../FleetNodeDetail.vue'
|
||||
|
||||
vi.mock('@/api/rpc-client', () => ({ rpcClient: { call: vi.fn() } }))
|
||||
afterEach(() => { sessionStorage.clear(); vi.clearAllMocks() })
|
||||
@@ -82,3 +83,31 @@ it('ignores an older alerts failure after a newer successful refresh', async ()
|
||||
expect(fleet.alertsLoading.value).toBe(false)
|
||||
} finally { wrapper.unmount() }
|
||||
})
|
||||
|
||||
it('reports explicitly unavailable history and clears the message when changing nodes', async () => {
|
||||
vi.mocked(rpcClient.call).mockImplementation(({ method, params }) => {
|
||||
if (method !== 'telemetry.fleet-node-history') return Promise.resolve({ nodes: [], alerts: [] }) as never
|
||||
return Promise.resolve((params as { node_id: string }).node_id === 'trusted'
|
||||
? { history_available: false, entries: [{ timestamp: 'must-not-render', cpu_pct: 99 }] }
|
||||
: { entries: [{ timestamp: 'legacy-available', cpu_pct: 12 }] }) as never
|
||||
})
|
||||
let fleet!: ReturnType<typeof useFleetData>
|
||||
const wrapper = mount(defineComponent({ setup() { fleet = useFleetData(); return () => null } }))
|
||||
try {
|
||||
await flushPromises()
|
||||
fleet.selectNode('trusted'); await flushPromises()
|
||||
expect(fleet.nodeHistoryMessage.value).toContain('unavailable')
|
||||
expect(fleet.nodeHistory.value).toEqual([])
|
||||
const detail = mount(FleetNodeDetail, { props: {
|
||||
node: normalizeFleetNode({ node_id: 'trusted' }), nodeId: 'trusted',
|
||||
historyLoading: false, historyMessage: fleet.nodeHistoryMessage.value,
|
||||
historyLabels: [], cpuDatasets: [], memDatasets: [], diskDatasets: [], chartWidth: 300,
|
||||
}, global: { mocks: { $ver: (v: string) => v }, stubs: { LineChart: true } } })
|
||||
expect(detail.get('[role="status"]').text()).toContain('History is unavailable')
|
||||
expect(detail.text()).not.toContain('CPU History')
|
||||
detail.unmount()
|
||||
fleet.selectNode('legacy'); await flushPromises()
|
||||
expect(fleet.nodeHistoryMessage.value).toBe('')
|
||||
expect(fleet.nodeHistory.value[0]?.timestamp).toBe('legacy-available')
|
||||
} finally { wrapper.unmount() }
|
||||
})
|
||||
|
||||
@@ -281,6 +281,7 @@ export function useFleetData() {
|
||||
const selectedNodeId = ref<string | null>(cached.selectedNodeId ?? null)
|
||||
const nodeHistory = ref<NodeHistoryEntry[]>([])
|
||||
const nodeHistoryLoading = ref(false)
|
||||
const nodeHistoryMessage = ref('')
|
||||
const autoRefresh = ref(true)
|
||||
const lastRefreshed = ref(cached.lastRefreshed ?? '')
|
||||
const sortBy = ref<SortOption>(cached.sortBy ?? 'status')
|
||||
@@ -423,15 +424,25 @@ export function useFleetData() {
|
||||
const request = ++historyRequest
|
||||
nodeHistoryLoading.value = true
|
||||
try {
|
||||
const data = await rpcClient.call<{ history?: NodeHistoryEntry[]; entries?: NodeHistoryEntry[] }>({
|
||||
const data = await rpcClient.call<{ history?: NodeHistoryEntry[]; entries?: NodeHistoryEntry[]; history_available?: boolean }>({
|
||||
method: 'telemetry.fleet-node-history',
|
||||
params: { node_id: nodeId },
|
||||
})
|
||||
if (request === historyRequest && selectedNodeId.value === nodeId) {
|
||||
nodeHistory.value = normalizeNodeHistoryResponse(data)
|
||||
if (data.history_available === false) {
|
||||
nodeHistory.value = []
|
||||
nodeHistoryMessage.value = 'History is unavailable for this node.'
|
||||
} else {
|
||||
nodeHistory.value = normalizeNodeHistoryResponse(data)
|
||||
nodeHistoryMessage.value = ''
|
||||
}
|
||||
}
|
||||
} catch {
|
||||
// Non-critical
|
||||
if (request === historyRequest && selectedNodeId.value === nodeId) {
|
||||
nodeHistoryMessage.value = nodeHistory.value.length
|
||||
? 'History refresh failed. Showing the last received history.'
|
||||
: 'History is unavailable for this node.'
|
||||
}
|
||||
} finally {
|
||||
if (request === historyRequest) nodeHistoryLoading.value = false
|
||||
}
|
||||
@@ -521,6 +532,7 @@ export function useFleetData() {
|
||||
historyRequest++
|
||||
nodeHistory.value = []
|
||||
nodeHistoryLoading.value = false
|
||||
nodeHistoryMessage.value = ''
|
||||
if (newId) {
|
||||
fetchNodeHistory(newId)
|
||||
} else {
|
||||
@@ -599,7 +611,7 @@ export function useFleetData() {
|
||||
|
||||
return {
|
||||
loading, refreshing, errorMessage, nodes, fleetAlerts, alertsLoading, alertsErrorMessage,
|
||||
selectedNodeId, selectedNode, nodeHistory, nodeHistoryLoading,
|
||||
selectedNodeId, selectedNode, nodeHistory, nodeHistoryLoading, nodeHistoryMessage,
|
||||
autoRefresh, lastRefreshed, sortBy, chartWidth, now,
|
||||
onlineCount, offlineCount, unknownCount, healthyCount, fleetHealthPct,
|
||||
avgCpu, avgMem, avgDisk, sortedNodes, allAppIds,
|
||||
|
||||
Reference in New Issue
Block a user