122 lines
3.3 KiB
JavaScript
122 lines
3.3 KiB
JavaScript
import { defineStore } from 'pinia'
|
|
import { ref, computed } from 'vue'
|
|
import * as alertsApi from '@/api/alerts'
|
|
import { detectNewCriticalAlerts } from '@/composables/criticalAlertDetect'
|
|
|
|
export const useAlertStore = defineStore('alerts', () => {
|
|
const alerts = ref([])
|
|
const loading = ref(false)
|
|
const statusFilter = ref(null)
|
|
const lastSeenAlertIds = ref([])
|
|
const bannerAlerts = ref([])
|
|
const pollSeeded = ref(false)
|
|
|
|
const openAlerts = computed(() => alerts.value.filter(a => a.status === 'OPEN'))
|
|
const criticalAlerts = computed(() => alerts.value.filter(a => a.severity === 'CRITICAL'))
|
|
|
|
function mergeBannerAlerts(newAlerts) {
|
|
const existingIds = new Set(bannerAlerts.value.map(alert => alert.id))
|
|
const merged = [...bannerAlerts.value]
|
|
for (const alert of newAlerts) {
|
|
if (!existingIds.has(alert.id)) merged.push(alert)
|
|
}
|
|
bannerAlerts.value = merged
|
|
}
|
|
|
|
function applyPollResults(items) {
|
|
const { newAlerts, nextSeenIds, seeded } = detectNewCriticalAlerts(
|
|
items,
|
|
lastSeenAlertIds.value,
|
|
pollSeeded.value,
|
|
)
|
|
lastSeenAlertIds.value = nextSeenIds
|
|
pollSeeded.value = seeded
|
|
if (newAlerts.length > 0) {
|
|
mergeBannerAlerts(newAlerts)
|
|
}
|
|
return newAlerts
|
|
}
|
|
|
|
async function loadAlerts(encounterId, status) {
|
|
loading.value = true
|
|
try {
|
|
const filter = status ?? statusFilter.value
|
|
const data = await alertsApi.fetchAlerts(encounterId, filter)
|
|
alerts.value = data.items
|
|
} catch (e) {
|
|
console.error('Failed to load alerts', e)
|
|
} finally {
|
|
loading.value = false
|
|
}
|
|
}
|
|
|
|
async function loadGlobalAlerts(status = 'OPEN') {
|
|
loading.value = true
|
|
try {
|
|
const data = await alertsApi.fetchAllAlerts(status)
|
|
alerts.value = data.items
|
|
} catch (e) {
|
|
console.error('Failed to load alerts', e)
|
|
} finally {
|
|
loading.value = false
|
|
}
|
|
}
|
|
|
|
async function pollOpenAlerts() {
|
|
try {
|
|
const items = await alertsApi.fetchAllOpenAlerts()
|
|
alerts.value = items
|
|
return applyPollResults(items)
|
|
} catch (e) {
|
|
console.error('Failed to poll alerts', e)
|
|
return []
|
|
}
|
|
}
|
|
|
|
function dismissBannerAlert(alertId) {
|
|
bannerAlerts.value = bannerAlerts.value.filter(alert => alert.id !== alertId)
|
|
}
|
|
|
|
function dismissAllBannerAlerts() {
|
|
bannerAlerts.value = []
|
|
}
|
|
|
|
async function acknowledge(alertId, note) {
|
|
const updated = await alertsApi.acknowledgeAlert(alertId, note || undefined)
|
|
const alert = alerts.value.find(a => a.id === alertId)
|
|
if (alert) {
|
|
alert.status = updated.status ?? 'ACKNOWLEDGED'
|
|
alert.acknowledgedBy = updated.acknowledgedBy ?? alert.acknowledgedBy
|
|
alert.acknowledgedAt = updated.acknowledgedAt ?? alert.acknowledgedAt
|
|
}
|
|
dismissBannerAlert(alertId)
|
|
return updated
|
|
}
|
|
|
|
async function resolve(alertId) {
|
|
await alertsApi.resolveAlert(alertId)
|
|
const alert = alerts.value.find(a => a.id === alertId)
|
|
if (alert) alert.status = 'RESOLVED'
|
|
dismissBannerAlert(alertId)
|
|
}
|
|
|
|
return {
|
|
alerts,
|
|
loading,
|
|
statusFilter,
|
|
lastSeenAlertIds,
|
|
bannerAlerts,
|
|
pollSeeded,
|
|
openAlerts,
|
|
criticalAlerts,
|
|
loadAlerts,
|
|
loadGlobalAlerts,
|
|
pollOpenAlerts,
|
|
dismissBannerAlert,
|
|
dismissAllBannerAlerts,
|
|
acknowledge,
|
|
resolve,
|
|
applyPollResults,
|
|
}
|
|
})
|