1- import { computed , type Ref , watchEffect } from "vue" ;
1+ import { computed , watchEffect } from "vue" ;
22import { CapabilityStatus , StatusIndicator } from "@/components/platformcapabilities/types" ;
3- import { faCheck , faInfoCircle , faTimes , type IconDefinition } from "@fortawesome/free-solid-svg-icons" ;
4- import type ConnectionTestResults from "@/resources/ConnectionTestResults" ;
5- import useIsAllMessagesSupported from "@/components/audit/isAllMessagesSupported" ;
3+ import useIsAllMessagesSupported , { minimumSCVersionForAllMessages } from "@/components/audit/isAllMessagesSupported" ;
64import { storeToRefs } from "pinia" ;
75import { useAuditStore } from "@/stores/AuditStore" ;
8- import { AuditingCardDescription , AuditingIndicatorTooltip } from "@/components/platformcapabilities/constants" ;
96import { MessageStatus } from "@/resources/Message" ;
7+ import { type CapabilityComposable , useCapabilityBase } from "./BaseCapability" ;
8+ import { useRemoteInstancesStore } from "@/stores/RemoteInstancesStore" ;
9+ import { RemoteInstanceStatus , type RemoteInstance } from "@/resources/RemoteInstance" ;
10+
11+ enum AuditingCardDescription {
12+ NotConfigured = "Auditing instance is connected but no successful messages have been processed yet or you don't have auditing enabled for any endpoints." ,
13+ Unavailable = "All Auditing instances are configured but not responding." ,
14+ PartiallyUnavailable = "Some Auditing instances are not responding. Check individual instance status below." ,
15+ NotSupported = `Auditing instance is connected but the "All Messages" feature requires ServiceControl ${ minimumSCVersionForAllMessages } or higher.` ,
16+ Available = "Auditing is available and processing successful messages." ,
17+ }
18+
19+ enum AuditingIndicatorTooltip {
20+ InstanceAvailable = "Auditing instance is configured and available" ,
21+ InstanceUnavailable = "The Auditing instance is configured but not responding" ,
22+ MessagesAvailable = "Successful messages are being processed" ,
23+ MessagesUnavailable = "No successful messages have been processed yet or auditing is not enabled for any endpoints" ,
24+ AllMessagesNotSupported = `The 'All Messages' feature requires ServiceControl ${ minimumSCVersionForAllMessages } or higher` ,
25+ }
1026
11- // http://localhost:33333/api/configuration/remotes
1227/**
13- [
14- {
15- "api_uri": "http://servicecontrol-audit:44444",
16- "version": "6.7.6",
17- "status": "online",
18- "configuration": {
19- "host": {
20- "instance_name": "Particular.ServiceControl.Audit",
21- "logging": {
22- "log_path": "/app/.logs",
23- "logging_level": "information"
24- }
25- },
26- "data_retention": {
27- "audit_retention_period": "7.00:00:00"
28- },
29- "performance_tunning": {
30- "max_body_size_to_store": 102400
31- },
32- "transport": {
33- "transport_type": "RabbitMQ.QuorumConventionalRouting",
34- "audit_log_queue": "audit.log",
35- "audit_queue": "audit",
36- "forward_audit_messages": false
37- },
38- "peristence": {
39- "persistence_type": "RavenDB"
40- },
41- "plugins": {
28+ * Checks if all audit remote instances are unavailable
29+ */
30+ function allAuditInstancesUnavailable ( instances : RemoteInstance [ ] | null | undefined ) : boolean {
31+ if ( ! instances || instances . length === 0 ) {
32+ return false ;
33+ }
34+ return instances . every ( ( instance ) => instance . status !== RemoteInstanceStatus . Online ) ;
35+ }
4236
43- }
44- }
37+ /**
38+ * Checks if any audit remote instances are unavailable (but not all)
39+ */
40+ function hasUnavailableAuditInstances ( instances : RemoteInstance [ ] | null | undefined ) : boolean {
41+ if ( ! instances || instances . length === 0 ) {
42+ return false ;
4543 }
46- ]
44+ return instances . some ( ( instance ) => instance . status !== RemoteInstanceStatus . Online ) ;
45+ }
46+
47+ /**
48+ * Checks if any audit remote instances are available
4749 */
50+ function hasAvailableAuditInstances ( instances : RemoteInstance [ ] | null | undefined ) : boolean {
51+ if ( ! instances || instances . length === 0 ) {
52+ return false ;
53+ }
54+ return instances . some ( ( instance ) => instance . status === RemoteInstanceStatus . Online ) ;
55+ }
4856
49- export function useAuditingCapability ( testResults : Ref < ConnectionTestResults | null > ) {
57+ /**
58+ * Checks if some but not all audit instances are unavailable
59+ */
60+ function hasPartiallyUnavailableAuditInstances ( instances : RemoteInstance [ ] | null | undefined ) : boolean {
61+ if ( ! instances || instances . length === 0 ) {
62+ return false ;
63+ }
64+ return hasUnavailableAuditInstances ( instances ) && hasAvailableAuditInstances ( instances ) ;
65+ }
66+
67+ export function useAuditingCapability ( ) : CapabilityComposable {
68+ const { getIconForStatus, createIndicator } = useCapabilityBase ( ) ;
69+
70+ // This gives us the list of remote instances configured in ServiceControl.
71+ const remoteInstancesStore = useRemoteInstancesStore ( ) ;
72+ const { remoteInstances } = storeToRefs ( remoteInstancesStore ) ;
73+
74+ // This gives us the messages array which includes all messages (successful and failed).
5075 const auditStore = useAuditStore ( ) ;
51- // this gives us the messages array which includes all messages (successful and failed)
5276 const { messages } = storeToRefs ( auditStore ) ;
53- const isAllMessagesSupported = useIsAllMessagesSupported ( ) ;
54-
55- // Count only successful audit messages
5677 const successfulMessageCount = computed ( ( ) => {
5778 return messages . value . filter ( ( msg ) => msg . status === MessageStatus . Successful || msg . status === MessageStatus . ResolvedSuccessfully ) . length ;
5879 } ) ;
5980
60- // this tells us if the audit instance is configured and responding
61- const auditingConfiguredAndResponding = computed ( ( ) => {
62- return testResults . value ?. audit_connection_result ?. connection_successful ?? false ;
63- } ) ;
81+ const isAllMessagesSupported = useIsAllMessagesSupported ( ) ;
6482
6583 watchEffect ( ( ) => {
6684 // Trigger initial load of audit messages if audit is configured
67- if ( auditingConfiguredAndResponding . value && messages . value . length === 0 ) {
85+ if ( hasAvailableAuditInstances ( remoteInstances . value ) ) {
6886 // TODO: This is not auto refreshed. User will need to manually refresh the page to get updated data. Ideally this would auto refresh periodically.
6987 auditStore . refresh ( ) ;
7088 }
7189 } ) ;
7290
91+ // Determine overall auditing status
7392 const auditStatus = computed ( ( ) => {
74- // If audit instance is not configured or not responding
75- if ( ! auditingConfiguredAndResponding . value ) {
93+ // 1. Check if there are any audit instances configured.
94+ if ( ! remoteInstances . value || remoteInstances . value . length === 0 ) {
95+ return CapabilityStatus . NotConfigured ;
96+ }
97+
98+ // 2. Check if all audit instances are unavailable
99+ if ( allAuditInstancesUnavailable ( remoteInstances . value ) ) {
76100 return CapabilityStatus . Unavailable ;
77101 }
78102
79- // If audit instance is available but 'All Messages' feature is not supported or there are no successful audit messages
103+ // 3. Check if some but not all audit instances are unavailable
104+ if ( hasPartiallyUnavailableAuditInstances ( remoteInstances . value ) ) {
105+ return CapabilityStatus . PartiallyUnavailable ;
106+ }
107+
108+ // 4. Check if all messages feature is supported and there are successful messages
80109 if ( ! isAllMessagesSupported . value || successfulMessageCount . value === 0 ) {
81110 return CapabilityStatus . NotConfigured ;
82111 }
83112
84- // Audit instance is available and there are successful audit messages
113+ // 5. Audit instance is available and there are successful audit messages
85114 return CapabilityStatus . Available ;
86115 } ) ;
87116
88- const auditIcon = computed < IconDefinition > ( ( ) => {
89- if ( auditStatus . value === CapabilityStatus . NotConfigured ) {
90- return faInfoCircle ;
91- }
92-
93- if ( auditStatus . value === CapabilityStatus . Available ) {
94- return faCheck ;
95- }
96-
97- // Uavailable
98- return faTimes ;
99- } ) ;
117+ // Determine icon based on status
118+ const auditIcon = computed ( ( ) => getIconForStatus ( auditStatus . value ) ) ;
100119
120+ // Determine description based on status
101121 const auditDescription = computed ( ( ) => {
102122 if ( auditStatus . value === CapabilityStatus . NotConfigured ) {
103123 return AuditingCardDescription . NotConfigured ;
@@ -107,21 +127,31 @@ export function useAuditingCapability(testResults: Ref<ConnectionTestResults | n
107127 return AuditingCardDescription . Available ;
108128 }
109129
110- // Uavailable
130+ if ( auditStatus . value === CapabilityStatus . PartiallyUnavailable ) {
131+ return AuditingCardDescription . PartiallyUnavailable ;
132+ }
133+
134+ // Unavailable
111135 return AuditingCardDescription . Unavailable ;
112136 } ) ;
113137
114- const auditIndicators = computed < StatusIndicator [ ] > ( ( ) => {
138+ // Determine indicators
139+ const auditIndicators = computed ( ( ) => {
115140 const indicators : StatusIndicator [ ] = [ ] ;
116141
117- indicators . push ( {
118- label : "Instance" ,
119- status : auditingConfiguredAndResponding . value ? CapabilityStatus . Available : CapabilityStatus . Unavailable ,
120- tooltip : auditingConfiguredAndResponding . value ? AuditingIndicatorTooltip . InstanceAvailable : AuditingIndicatorTooltip . InstanceUnavailable ,
121- } ) ;
142+ // Add an indicator for each remote audit instance
143+ if ( remoteInstances . value && remoteInstances . value . length > 0 ) {
144+ remoteInstances . value . forEach ( ( instance , index ) => {
145+ const isAvailable = instance . status === RemoteInstanceStatus . Online ;
146+ const label = remoteInstances . value ! . length > 1 ? `Instance ${ index + 1 } ` : "Instance" ;
147+ const tooltip = isAvailable ? AuditingIndicatorTooltip . InstanceAvailable : AuditingIndicatorTooltip . InstanceUnavailable ;
122148
123- // Messages available indicator
124- if ( auditingConfiguredAndResponding . value ) {
149+ indicators . push ( createIndicator ( label , isAvailable ? CapabilityStatus . Available : CapabilityStatus . Unavailable , tooltip , instance . api_uri , instance . version ) ) ;
150+ } ) ;
151+ }
152+
153+ // Messages available indicator - show if at least one instance is available
154+ if ( hasAvailableAuditInstances ( remoteInstances . value ) ) {
125155 const messagesAvailable = isAllMessagesSupported . value && successfulMessageCount . value > 0 ;
126156
127157 let messageTooltip = "" ;
@@ -133,20 +163,20 @@ export function useAuditingCapability(testResults: Ref<ConnectionTestResults | n
133163 messageTooltip = AuditingIndicatorTooltip . MessagesUnavailable ;
134164 }
135165
136- indicators . push ( {
137- label : "Messages" ,
138- status : messagesAvailable ? CapabilityStatus . Available : CapabilityStatus . NotConfigured ,
139- tooltip : messageTooltip ,
140- } ) ;
166+ indicators . push ( createIndicator ( "Messages" , messagesAvailable ? CapabilityStatus . Available : CapabilityStatus . NotConfigured , messageTooltip ) ) ;
141167 }
142168
143169 return indicators ;
144170 } ) ;
145171
172+ // Loading state - true if remote instances haven't been loaded yet
173+ const isLoading = computed ( ( ) => remoteInstances . value === null || remoteInstances . value === undefined ) ;
174+
146175 return {
147176 status : auditStatus ,
148177 icon : auditIcon ,
149178 description : auditDescription ,
150179 indicators : auditIndicators ,
180+ isLoading,
151181 } ;
152182}
0 commit comments