11<script setup lang="ts">
2- import { onMounted , onUnmounted , ref , watch } from " vue" ;
2+ import { computed , onBeforeMount , ref , watch } from " vue" ;
33import { useShowToast } from " ../../composables/toast" ;
4- import { onBeforeRouteLeave , useRoute } from " vue-router" ;
5- import { useCookies } from " vue3-cookies" ;
4+ import { onBeforeRouteLeave } from " vue-router" ;
65import LicenseNotExpired from " ../../components/LicenseNotExpired.vue" ;
76import ServiceControlAvailable from " ../ServiceControlAvailable.vue" ;
87import MessageList , { IMessageList } from " ./MessageList.vue" ;
98import ConfirmDialog from " ../ConfirmDialog.vue" ;
109import PaginationStrip from " ../../components/PaginationStrip.vue" ;
11- import dayjs from " @/utils/dayjs" ;
12- import { ExtendedFailedMessage } from " @/resources/FailedMessage" ;
10+ import { FailedMessageStatus } from " @/resources/FailedMessage" ;
1311import { TYPE } from " vue-toastification" ;
14- import FailureGroup from " @/resources/FailureGroup" ;
1512import FAIcon from " @/components/FAIcon.vue" ;
1613import { faArrowRotateRight } from " @fortawesome/free-solid-svg-icons" ;
17- import serviceControlClient from " @/components/serviceControlClient" ;
18- import { useConfigurationStore } from " @/stores/ConfigurationStore" ;
1914import { storeToRefs } from " pinia" ;
15+ import { useStoreAutoRefresh } from " @/composables/useAutoRefresh" ;
16+ import { DeletedPeriodOption , useRecoverabilityStore } from " @/stores/RecoverabilityStore" ;
17+ import LoadingSpinner from " ../LoadingSpinner.vue" ;
2018
21- let pollingFaster = false ;
22- let refreshInterval: number | undefined ;
23- const perPage = 50 ;
19+ const POLLING_INTERVAL_NORMAL = 5000 ;
20+ const POLLING_INTERVAL_FAST = 1000 ;
21+
22+ const loading = ref (false );
23+ const { autoRefresh, isRefreshing, updateInterval } = useStoreAutoRefresh (" messagesStore" , useRecoverabilityStore , POLLING_INTERVAL_NORMAL );
24+ const { store } = autoRefresh ();
25+ const { messages, groupId, groupName, totalCount, pageNumber, selectedPeriod } = storeToRefs (store );
2426
25- const route = useRoute ();
26- const groupId = ref <string >(route .params .groupId as string );
27- const groupName = ref (" " );
28- const pageNumber = ref (1 );
29- const totalCount = ref (0 );
30- const cookies = useCookies ().cookies ;
31- const periodOptions = [" All Deleted" , " Deleted in the last 2 Hours" , " Deleted in the last 1 Day" , " Deleted in the last 7 days" ] as const ;
32- type PeriodOption = (typeof periodOptions )[number ];
33- const selectedPeriod = ref <PeriodOption >(" Deleted in the last 7 days" );
3427const showConfirmRestore = ref (false );
3528const messageList = ref <IMessageList | undefined >();
36- const messages = ref <ExtendedFailedMessage []>([]);
37-
38- watch (pageNumber , () => loadMessages ());
39-
40- const configurationStore = useConfigurationStore ();
41- const { configuration } = storeToRefs (configurationStore );
42-
43- function loadMessages() {
44- let startDate = new Date (0 );
45- const endDate = new Date ();
46-
47- switch (selectedPeriod .value ) {
48- case " All Deleted" :
49- startDate = new Date ();
50- startDate .setHours (startDate .getHours () - 24 * 365 );
51- break ;
52- case " Deleted in the last 2 Hours" :
53- startDate = new Date ();
54- startDate .setHours (startDate .getHours () - 2 );
55- break ;
56- case " Deleted in the last 1 Day" :
57- startDate = new Date ();
58- startDate .setHours (startDate .getHours () - 24 );
59- break ;
60- case " Deleted in the last 7 days" :
61- startDate = new Date ();
62- startDate .setHours (startDate .getHours () - 24 * 7 );
63- break ;
64- }
65- return loadPagedMessages (groupId .value , pageNumber .value , " " , " " , startDate .toISOString (), endDate .toISOString ());
66- }
67-
68- async function loadGroupDetails(groupId : string ) {
69- const [, data] = await serviceControlClient .fetchTypedFromServiceControl <FailureGroup >(` archive/groups/id/${groupId } ` );
70- groupName .value = data .title ;
71- }
72-
73- function loadPagedMessages(groupId ? : string , page : number = 1 , sortBy : string = " modified" , direction : string = " desc" , startDate : string = new Date (0 ).toISOString (), endDate : string = new Date ().toISOString ()) {
74- const dateRange = startDate + " ..." + endDate ;
75- let loadGroupDetailsPromise;
76- if (groupId && ! groupName .value ) {
77- loadGroupDetailsPromise = loadGroupDetails (groupId );
78- }
79-
80- async function loadDelMessages() {
81- try {
82- const [response, data] = await serviceControlClient .fetchTypedFromServiceControl <ExtendedFailedMessage []>(
83- ` ${groupId ? ` recoverability/groups/${groupId }/ ` : " " }errors?status=archived&page=${page }&per_page=${perPage }&sort=${sortBy }&direction=${direction }&modified=${dateRange } `
84- );
85-
86- totalCount .value = parseInt (response .headers .get (" Total-Count" ) ?? " 0" );
87-
88- if (messages .value .length && data .length ) {
89- // merge the previously selected messages into the new list so we can replace them
90- messages .value .forEach ((previousMessage ) => {
91- const receivedMessage = data .find ((m ) => m .id === previousMessage .id );
92- if (receivedMessage ) {
93- if (previousMessage .last_modified === receivedMessage .last_modified ) {
94- receivedMessage .retryInProgress = previousMessage .retryInProgress ;
95- receivedMessage .deleteInProgress = previousMessage .deleteInProgress ;
96- }
97-
98- receivedMessage .selected = previousMessage .selected ;
99- }
100- });
101- }
102- messages .value = updateMessagesScheduledDeletionDate (data );
103- } catch (err ) {
104- console .log (err );
105- const result = {
106- message: " error" ,
107- };
108- return result ;
109- }
110- }
111-
112- const loadDelMessagesPromise = loadDelMessages ();
113-
114- if (loadGroupDetailsPromise ) {
115- return Promise .all ([loadGroupDetailsPromise , loadDelMessagesPromise ]);
116- }
117-
118- return loadDelMessagesPromise ;
119- }
120-
121- function updateMessagesScheduledDeletionDate(messages : ExtendedFailedMessage []) {
122- // check deletion time
123- messages .forEach ((message ) => {
124- message .error_retention_period = dayjs .duration (configuration .value ?.data_retention .error_retention_period ?? " PT0S" ).asHours ();
125- const countdown = dayjs (message .last_modified ).add (message .error_retention_period , " hours" );
126- message .delete_soon = countdown < dayjs ();
127- message .deleted_in = countdown .format ();
128- });
129- return messages ;
130- }
13129
13230function numberSelected() {
13331 return messageList .value ?.getSelectedMessages ()?.length ?? 0 ;
@@ -146,69 +44,45 @@ function isAnythingSelected() {
14644}
14745
14846async function restoreSelectedMessages() {
149- changeRefreshInterval (1000 );
47+ // We're starting a restore, poll more frequently
48+ updateInterval (POLLING_INTERVAL_FAST );
15049 const selectedMessages = messageList .value ?.getSelectedMessages () ?? [];
15150 selectedMessages .forEach ((m ) => (m .restoreInProgress = true ));
15251 useShowToast (TYPE .INFO , " Info" , ` restoring ${selectedMessages .length } messages... ` );
15352
154- await serviceControlClient .patchToServiceControl (
155- " errors/unarchive" ,
156- selectedMessages .map ((m ) => m .id )
157- );
53+ await store .restoreById (selectedMessages .map ((m ) => m .id ));
15854 messageList .value ?.deselectAll ();
15955}
16056
161- function periodChanged(period : PeriodOption ) {
162- selectedPeriod .value = period ;
163- cookies .set (" all_deleted_messages_period" , period );
164-
165- loadMessages ();
166- }
167-
168- function isRestoreInProgress() {
169- return messages .value .some ((message ) => message .restoreInProgress );
170- }
171-
172- function changeRefreshInterval(milliseconds : number ) {
173- if (refreshInterval != null ) {
174- window .clearInterval (refreshInterval );
175- }
176-
177- refreshInterval = window .setInterval (() => {
178- // If we're currently polling at 5 seconds and there is a restore in progress, then change the polling interval to poll every 1 second
179- if (! pollingFaster && isRestoreInProgress ()) {
180- changeRefreshInterval (1000 );
181- pollingFaster = true ;
182- } else if (pollingFaster && ! isRestoreInProgress ()) {
183- // if we're currently polling every 1 second but all restores are done, change polling frequency back to every 5 seconds
184- changeRefreshInterval (5000 );
185- pollingFaster = false ;
186- }
187-
188- loadMessages ();
189- }, milliseconds );
57+ async function periodChanged(period : DeletedPeriodOption ) {
58+ loading .value = true ;
59+ await store .setPeriod (period );
60+ loading .value = false ;
19061}
19162
19263onBeforeRouteLeave (() => {
19364 groupId .value = " " ;
19465 groupName .value = " " ;
19566});
19667
197- onUnmounted (() => {
198- if (refreshInterval != null ) {
199- window .clearInterval (refreshInterval );
68+ const isRestoreInProgress = computed (() => messages .value .some ((message ) => message .restoreInProgress ));
69+ watch (isRestoreInProgress , (restoreInProgress ) => {
70+ if (restoreInProgress ) {
71+ // If there is a restore in progress, poll every 1 second
72+ updateInterval (POLLING_INTERVAL_FAST );
73+ } else {
74+ // If all restores are done, change polling frequency back to every 5 seconds
75+ updateInterval (POLLING_INTERVAL_NORMAL );
20076 }
20177});
20278
203- onMounted (() => {
204- let cookiePeriod = cookies .get (" all_deleted_messages_period" ) as PeriodOption ;
205- if (! cookiePeriod ) {
206- cookiePeriod = periodOptions [periodOptions .length - 1 ]; // default is last 7 days
207- }
208- selectedPeriod .value = cookiePeriod ;
209- loadMessages ();
210-
211- changeRefreshInterval (5000 );
79+ onBeforeMount (async () => {
80+ loading .value = true ;
81+ // set status before mount to ensure no other controls/processes can cause extra refreshes during mount
82+ await store .setMessageStatus (FailedMessageStatus .Archived );
83+ });
84+ watch (isRefreshing , () => {
85+ if (! isRefreshing .value && loading .value ) loading .value = false ;
21286});
21387 </script >
21488
@@ -240,7 +114,7 @@ onMounted(() => {
240114 <span class =" caret" ></span >
241115 </button >
242116 <ul class =" dropdown-menu" >
243- <li v-for =" (period, index) in periodOptions " :key =" index" >
117+ <li v-for =" (period, index) in store.deletedPeriodOptions " :key =" index" >
244118 <a @click.prevent =" periodChanged(period)" >{{ period }}</a >
245119 </li >
246120 </ul >
@@ -249,11 +123,12 @@ onMounted(() => {
249123 </div >
250124 <div class =" row" >
251125 <div class =" col-12" >
252- <MessageList :messages =" messages" ref =" messageList" ></MessageList >
126+ <LoadingSpinner v-if =" messages.length === 0 && (loading || isRefreshing)" />
127+ <MessageList v-else :messages =" messages" ref =" messageList" ></MessageList >
253128 </div >
254129 </div >
255130 <div class =" row" v-if =" messages.length > 0" >
256- <PaginationStrip v-model =" pageNumber" :total-count =" totalCount" :items-per-page =" perPage" />
131+ <PaginationStrip v-model =" pageNumber" :total-count =" totalCount" :items-per-page =" store. perPage" />
257132 </div >
258133 <Teleport to =" #modalDisplay" >
259134 <ConfirmDialog
0 commit comments