Skip to content

Commit 6717d70

Browse files
committed
Merge branch 'monitoring_store' into john/refactor_stores
# Conflicts: # src/Frontend/src/components/failedmessages/DeletedMessages.vue # src/Frontend/src/components/failedmessages/FailedMessages.vue # src/Frontend/src/components/failedmessages/PendingRetries.vue # src/Frontend/src/stores/ServiceControlStore.ts
2 parents 0efe289 + 3032c5a commit 6717d70

File tree

11 files changed

+510
-785
lines changed

11 files changed

+510
-785
lines changed

src/Frontend/package-lock.json

Lines changed: 84 additions & 337 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/Frontend/package.json

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@
3333
"@vue-flow/controls": "1.1.3",
3434
"@vue-flow/core": "1.48.0",
3535
"@vuepic/vue-datepicker": "12.0.5",
36-
"@vueuse/core": "14.0.0",
36+
"@vueuse/core": "14.1.0",
3737
"bootstrap": "5.3.8",
3838
"codemirror": "6.0.2",
3939
"dayjs": "1.11.19",
@@ -69,13 +69,13 @@
6969
"eslint-config-prettier": "10.1.8",
7070
"eslint-plugin-prettier": "5.5.4",
7171
"eslint-plugin-promise": "7.2.1",
72-
"eslint-plugin-vue": "10.6.0",
72+
"eslint-plugin-vue": "10.6.1",
7373
"globals": "16.5.0",
7474
"jsdom": "26.1.0",
7575
"msw": "2.12.3",
76-
"prettier": "3.6.2",
76+
"prettier": "3.7.1",
7777
"typescript": "5.9.3",
78-
"typescript-eslint": "8.47.0",
78+
"typescript-eslint": "8.48.0",
7979
"vite": "7.2.4",
8080
"vite-plugin-checker": "0.11.0",
8181
"vite-plugin-vue-devtools": "8.0.5",

src/Frontend/src/components/failedmessages/DeletedMessages.vue

Lines changed: 39 additions & 164 deletions
Original file line numberDiff line numberDiff line change
@@ -1,133 +1,31 @@
11
<script setup lang="ts">
2-
import { onMounted, onUnmounted, ref, watch } from "vue";
2+
import { computed, onBeforeMount, ref, watch } from "vue";
33
import { useShowToast } from "../../composables/toast";
4-
import { onBeforeRouteLeave, useRoute } from "vue-router";
5-
import { useCookies } from "vue3-cookies";
4+
import { onBeforeRouteLeave } from "vue-router";
65
import LicenseNotExpired from "../../components/LicenseNotExpired.vue";
76
import ServiceControlAvailable from "../ServiceControlAvailable.vue";
87
import MessageList, { IMessageList } from "./MessageList.vue";
98
import ConfirmDialog from "../ConfirmDialog.vue";
109
import PaginationStrip from "../../components/PaginationStrip.vue";
11-
import dayjs from "@/utils/dayjs";
12-
import { ExtendedFailedMessage } from "@/resources/FailedMessage";
10+
import { FailedMessageStatus } from "@/resources/FailedMessage";
1311
import { TYPE } from "vue-toastification";
14-
import FailureGroup from "@/resources/FailureGroup";
1512
import FAIcon from "@/components/FAIcon.vue";
1613
import { faArrowRotateRight } from "@fortawesome/free-solid-svg-icons";
17-
import serviceControlClient from "@/components/serviceControlClient";
18-
import { useConfigurationStore } from "@/stores/ConfigurationStore";
1914
import { 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");
3427
const showConfirmRestore = ref(false);
3528
const 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
13230
function numberSelected() {
13331
return messageList.value?.getSelectedMessages()?.length ?? 0;
@@ -146,69 +44,45 @@ function isAnythingSelected() {
14644
}
14745
14846
async 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
19263
onBeforeRouteLeave(() => {
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

Comments
 (0)