Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion src/Frontend/src/components/BackendChecksNotifications.vue
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import useConnectionsAndStatsAutoRefresh from "@/composables/useConnectionsAndSt
import useEnvironmentAndVersionsAutoRefresh from "@/composables/useEnvironmentAndVersionsAutoRefresh";
import { useServiceControlStore } from "@/stores/ServiceControlStore";
import { storeToRefs } from "pinia";
import { useMonitoringStore } from "@/stores/MonitoringStore";

const router = useRouter();

Expand All @@ -18,7 +19,9 @@ const monitoringConnectionState = connectionStore.monitoringConnectionState;
const { store: environmentStore } = useEnvironmentAndVersionsAutoRefresh();
const environment = environmentStore.environment;
const serviceControlStore = useServiceControlStore();
const { monitoringUrl, serviceControlUrl, isMonitoringDisabled } = storeToRefs(serviceControlStore);
const monitoringStore = useMonitoringStore();
const { serviceControlUrl } = storeToRefs(serviceControlStore);
const { monitoringUrl, isMonitoringDisabled } = storeToRefs(monitoringStore);

const primaryConnectionFailure = computed(() => connectionState.unableToConnect);
const monitoringConnectionFailure = computed(() => monitoringConnectionState.unableToConnect);
Expand Down
5 changes: 4 additions & 1 deletion src/Frontend/src/components/PageFooter.vue
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import { useServiceControlStore } from "@/stores/ServiceControlStore";
import { storeToRefs } from "pinia";
import { useConfigurationStore } from "@/stores/ConfigurationStore";
import { useLicenseStore } from "@/stores/LicenseStore";
import { useMonitoringStore } from "@/stores/MonitoringStore";

const { store: connectionStore } = useConnectionsAndStatsAutoRefresh();
const connectionState = connectionStore.connectionState;
Expand All @@ -18,7 +19,9 @@ const { store: environmentAndVersionsStore } = useEnvironmentAndVersionsAutoRefr
const newVersions = environmentAndVersionsStore.newVersions;
const environment = environmentAndVersionsStore.environment;
const serviceControlStore = useServiceControlStore();
const { serviceControlUrl, monitoringUrl } = storeToRefs(serviceControlStore);
const monitoringStore = useMonitoringStore();
const { serviceControlUrl } = storeToRefs(serviceControlStore);
const { monitoringUrl } = storeToRefs(monitoringStore);
const licenseStore = useLicenseStore();
const { licenseStatus, license } = licenseStore;

Expand Down
6 changes: 3 additions & 3 deletions src/Frontend/src/components/PageHeader.vue
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,11 @@ import DashboardMenuItem from "@/components/dashboard/DashboardMenuItem.vue";
import FeedbackButton from "@/components/FeedbackButton.vue";
import ThroughputMenuItem from "@/views/throughputreport/ThroughputMenuItem.vue";
import AuditMenuItem from "./audit/AuditMenuItem.vue";
import { useServiceControlStore } from "@/stores/ServiceControlStore";
import { useMonitoringStore } from "@/stores/MonitoringStore";
import { storeToRefs } from "pinia";

const serviceControlStore = useServiceControlStore();
const { isMonitoringEnabled } = storeToRefs(serviceControlStore);
const monitoringStore = useMonitoringStore();
const { isMonitoringEnabled } = storeToRefs(monitoringStore);
// prettier-ignore
const menuItems = computed(
() => [
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import CodeEditor from "@/components/CodeEditor.vue";
import { useServiceControlStore } from "@/stores/ServiceControlStore";
import { storeToRefs } from "pinia";
import LoadingSpinner from "../LoadingSpinner.vue";
import { useMonitoringStore } from "@/stores/MonitoringStore";

interface ServiceControlInstanceConnection {
settings: { [key: string]: object };
Expand All @@ -19,7 +20,9 @@ interface MetricsConnectionDetails {
}

const serviceControlStore = useServiceControlStore();
const { serviceControlUrl, monitoringUrl } = storeToRefs(serviceControlStore);
const monitoringStore = useMonitoringStore();
const { serviceControlUrl } = storeToRefs(serviceControlStore);
const { monitoringUrl } = storeToRefs(monitoringStore);

const loading = ref(true);
const showCodeOnlyTab = ref(true);
Expand Down Expand Up @@ -102,7 +105,7 @@ async function getServiceControlConnection() {

async function getMonitoringConnection() {
try {
const [, data] = await serviceControlStore.fetchTypedFromMonitoring<{ Metrics: MetricsConnectionDetails }>("connection");
const [, data] = await monitoringStore.fetchTypedFromMonitoring<{ Metrics: MetricsConnectionDetails }>("connection");
return { ...data, errors: [] };
} catch {
return { Metrics: null, errors: [`Error SC Monitoring instance at ${monitoringUrl.value}connection`] };
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,16 +5,19 @@ import FAIcon from "@/components/FAIcon.vue";
import useConnectionsAndStatsAutoRefresh from "@/composables/useConnectionsAndStatsAutoRefresh";
import { useServiceControlStore } from "@/stores/ServiceControlStore";
import { storeToRefs } from "pinia";
import { useMonitoringStore } from "@/stores/MonitoringStore";

const { store: connectionStore } = useConnectionsAndStatsAutoRefresh();
const connectionState = connectionStore.connectionState;
const monitoringConnectionState = connectionStore.monitoringConnectionState;

const serviceControlStore = useServiceControlStore();
const monitoringStore = useMonitoringStore();
serviceControlStore.refresh();
monitoringStore.refresh();
const localServiceControlUrl = ref(serviceControlStore.serviceControlUrl);
const localMonitoringUrl = ref(serviceControlStore.monitoringUrl);
const { isMonitoringDisabled } = storeToRefs(serviceControlStore);
const localMonitoringUrl = ref(monitoringStore.monitoringUrl);
const { isMonitoringDisabled } = storeToRefs(monitoringStore);

const testingServiceControl = ref(false);
const serviceControlValid = ref<boolean | null>(null);
Expand Down
12 changes: 6 additions & 6 deletions src/Frontend/src/components/monitoring/EndpointDetails.vue
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ import { useMonitoringHistoryPeriodStore } from "@/stores/MonitoringHistoryPerio
import routeLinks from "@/router/routeLinks";
import FAIcon from "@/components/FAIcon.vue";
import { faEnvelope } from "@fortawesome/free-solid-svg-icons";
import { useServiceControlStore } from "@/stores/ServiceControlStore";
import { useMonitoringStore } from "@/stores/MonitoringStore";

const { store: connectionStore } = useConnectionsAndStatsAutoRefresh();
const monitoringConnectionState = connectionStore.monitoringConnectionState;
Expand All @@ -30,13 +30,13 @@ const router = useRouter();
const endpointName = route.params.endpointName.toString();
let refreshInterval: number;

const monitoringStore = useMonitoringEndpointDetailsStore();
const monitoringEndpointDetailsStore = useMonitoringEndpointDetailsStore();
const monitoringHistoryPeriodStore = useMonitoringHistoryPeriodStore();
const serviceControlStore = useServiceControlStore();
const { isMonitoringDisabled } = storeToRefs(serviceControlStore);
const monitoringStore = useMonitoringStore();
const { isMonitoringDisabled } = storeToRefs(monitoringStore);

const { historyPeriod } = storeToRefs(monitoringHistoryPeriodStore);
const { negativeCriticalTimeIsPresent, endpointDetails: endpoint } = storeToRefs(monitoringStore);
const { negativeCriticalTimeIsPresent, endpointDetails: endpoint } = storeToRefs(monitoringEndpointDetailsStore);

watch(historyPeriod, (newValue) => {
changeRefreshInterval(newValue.refreshIntervalVal);
Expand All @@ -57,7 +57,7 @@ const activeTab = computed({
});

async function getEndpointDetails() {
await monitoringStore.getEndpointDetails(endpointName);
await monitoringEndpointDetailsStore.getEndpointDetails(endpointName);
}

function changeRefreshInterval(milliseconds: number) {
Expand Down
12 changes: 6 additions & 6 deletions src/Frontend/src/components/monitoring/EndpointInstances.vue
Original file line number Diff line number Diff line change
Expand Up @@ -12,19 +12,19 @@ import ColumnHeader from "@/components/ColumnHeader.vue";
import { CriticalTime, InstanceName, ProcessingTime, ScheduledRetries, Throughput } from "@/resources/MonitoringResources";
import FAIcon from "@/components/FAIcon.vue";
import { faEnvelope, faTrash } from "@fortawesome/free-solid-svg-icons";
import { useServiceControlStore } from "@/stores/ServiceControlStore";
import { useMonitoringStore } from "@/stores/MonitoringStore";

const isRemovingEndpointEnabled = ref<boolean>(false);
const router = useRouter();

const monitoringStore = useMonitoringEndpointDetailsStore();
const { endpointDetails: endpoint, endpointName } = storeToRefs(monitoringStore);
const monitoringEndpointDetailsStore = useMonitoringEndpointDetailsStore();
const { endpointDetails: endpoint, endpointName } = storeToRefs(monitoringEndpointDetailsStore);

const serviceControlStore = useServiceControlStore();
const monitoringStore = useMonitoringStore();

async function removeEndpoint(endpointName: string, instance: ExtendedEndpointInstance) {
try {
await serviceControlStore.deleteFromMonitoring("monitored-instance/" + endpointName + "/" + instance.id);
await monitoringStore.deleteFromMonitoring("monitored-instance/" + endpointName + "/" + instance.id);
endpoint.value.instances.splice(endpoint.value.instances.indexOf(instance), 1);
if (endpoint.value.instances.length === 0) {
router.push(routeLinks.monitoring.root);
Expand All @@ -37,7 +37,7 @@ async function removeEndpoint(endpointName: string, instance: ExtendedEndpointIn

async function getIsRemovingEndpointEnabled() {
try {
const response = await serviceControlStore.optionsFromMonitoring();
const response = await monitoringStore.optionsFromMonitoring();
if (response) {
const headers = response.headers;
const allow = headers.get("Allow");
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
<script setup lang="ts">
import routeLinks from "@/router/routeLinks";
import { useServiceControlStore } from "@/stores/ServiceControlStore";
import { useMonitoringStore } from "@/stores/MonitoringStore";
import { storeToRefs } from "pinia";

const store = useServiceControlStore();
const store = useMonitoringStore();
const { monitoringUrl } = storeToRefs(store);
</script>

Expand Down
6 changes: 4 additions & 2 deletions src/Frontend/src/stores/ConnectionsAndStatsStore.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,12 @@ import { FailedMessage, FailedMessageStatus } from "@/resources/FailedMessage";
import { ConnectionState } from "@/resources/ConnectionState";
import { useCounter } from "@vueuse/core";
import { useServiceControlStore } from "./ServiceControlStore";
import { useMonitoringStore } from "./MonitoringStore";

export const useConnectionsAndStatsStore = defineStore("ConnectionsAndStatsStore", () => {
const serviceControlStore = useServiceControlStore();
const { isMonitoringEnabled } = storeToRefs(serviceControlStore);
const monitoringStore = useMonitoringStore();
const { isMonitoringEnabled } = storeToRefs(monitoringStore);

const failedMessageCount = ref(0);
const archivedMessageCount = ref(0);
Expand Down Expand Up @@ -61,7 +63,7 @@ export const useConnectionsAndStatsStore = defineStore("ConnectionsAndStatsStore

function getDisconnectedEndpointsCount() {
return fetchAndSetConnectionState(
() => serviceControlStore.fetchTypedFromMonitoring<number>("monitored-endpoints/disconnected"),
() => monitoringStore.fetchTypedFromMonitoring<number>("monitored-endpoints/disconnected"),
monitoringConnectionState,
(_, data) => {
return data;
Expand Down
4 changes: 3 additions & 1 deletion src/Frontend/src/stores/EnvironmentAndVersionsStore.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,11 @@ import { useMemoize } from "@vueuse/core";
import { acceptHMRUpdate, defineStore } from "pinia";
import { computed, reactive } from "vue";
import { useServiceControlStore } from "./ServiceControlStore";
import { useMonitoringStore } from "./MonitoringStore";

export const useEnvironmentAndVersionsStore = defineStore("EnvironmentAndVersionsStore", () => {
const serviceControlStore = useServiceControlStore();
const monitoringStore = useMonitoringStore();

const environment = reactive({
monitoring_version: "",
Expand Down Expand Up @@ -95,7 +97,7 @@ export const useEnvironmentAndVersionsStore = defineStore("EnvironmentAndVersion

async function setMonitoringVersion() {
try {
const [response] = await serviceControlStore.fetchTypedFromMonitoring("");
const [response] = await monitoringStore.fetchTypedFromMonitoring("");
if (response) {
environment.monitoring_version = response.headers.get("X-Particular-Version") ?? "";
}
Expand Down
8 changes: 4 additions & 4 deletions src/Frontend/src/stores/MonitoringEndpointDetailsStore.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,22 +9,22 @@ import type GroupOperation from "@/resources/GroupOperation";
import { emptyEndpointDetails } from "@/components/monitoring/endpoints";
import { useMemoize } from "@vueuse/core";
import useConnectionsAndStatsAutoRefresh from "@/composables/useConnectionsAndStatsAutoRefresh";
import { useServiceControlStore } from "./ServiceControlStore";
import { useMonitoringStore } from "./MonitoringStore";

export const useMonitoringEndpointDetailsStore = defineStore("MonitoringEndpointDetailsStore", () => {
const historyPeriodStore = useMonitoringHistoryPeriodStore();
const { store: connectionStore } = useConnectionsAndStatsAutoRefresh();
const serviceControlStore = useServiceControlStore();
const monitoringStore = useMonitoringStore();
const messageGroupClient = createMessageGroupClient();

const getMemoisedEndpointDetails = useMemoize((endpointName: string, historyPeriod = 1) => {
const data = ref<EndpointDetails | EndpointDetailsError | null>(null);
return {
data,
refresh: async () => {
if (serviceControlStore.isMonitoringEnabled) {
if (monitoringStore.isMonitoringEnabled) {
try {
const [, details] = await serviceControlStore.fetchTypedFromMonitoring<EndpointDetails>(`${`monitored-endpoints`}/${endpointName}?history=${historyPeriod}`);
const [, details] = await monitoringStore.fetchTypedFromMonitoring<EndpointDetails>(`${`monitored-endpoints`}/${endpointName}?history=${historyPeriod}`);
data.value = details!;
} catch (error) {
console.error(error);
Expand Down
72 changes: 69 additions & 3 deletions src/Frontend/src/stores/MonitoringStore.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,18 +5,21 @@ import { useMonitoringHistoryPeriodStore } from "./MonitoringHistoryPeriodStore"
import type { EndpointGroup, Endpoint, GroupedEndpoint } from "@/resources/MonitoringEndpoint";
import type { SortInfo } from "@/components/SortInfo";
import useConnectionsAndStatsAutoRefresh from "@/composables/useConnectionsAndStatsAutoRefresh";
import { useServiceControlStore } from "./ServiceControlStore";
import GroupOperation from "@/resources/GroupOperation";
import { getParameter, getParams } from "./environment";
import { useServiceControlStore } from "./ServiceControlStore";

export const useMonitoringStore = defineStore("MonitoringStore", () => {
const historyPeriodStore = useMonitoringHistoryPeriodStore();

const route = useRoute();
const router = useRouter();
const { store: connectionStore } = useConnectionsAndStatsAutoRefresh();
//TODO: if/when a recoverabilityStore is created, replace this
const serviceControlStore = useServiceControlStore();

//STORE STATE CONSTANTS
const monitoringUrl = ref<string | null>();
const grouping = ref({
groupedEndpoints: [] as EndpointGroup[],
groupSegments: 0,
Expand All @@ -36,12 +39,39 @@ export const useMonitoringStore = defineStore("MonitoringStore", () => {
const endpointListIsGrouped = computed<boolean>(() => grouping.value.selectedGrouping !== 0);
const getEndpointList = computed<Endpoint[]>(() => (filterString.value ? endpointList.value.filter((endpoint) => endpoint.name.toLowerCase().includes(filterString.value.toLowerCase())) : endpointList.value));

const isMonitoringDisabled = computed(() => monitoringUrl.value == null || monitoringUrl.value === "" || monitoringUrl.value === "!");
const isMonitoringEnabled = computed(() => !isMonitoringDisabled.value);

watch(sortBy, async () => await updateEndpointList(), { deep: true });
watch(filterString, async (newValue) => {
await updateFilterString(newValue);
});

//STORE ACTIONS
function getMonitoringUrl() {
if (!monitoringUrl.value) refresh();
return monitoringUrl.value;
}

function refresh() {
const params = getParams();
const mu = getParameter(params, "mu");

if (mu) {
monitoringUrl.value = mu.value;
window.localStorage.setItem("mu", monitoringUrl.value);
console.debug(`Monitoring Url found in QS and stored in local storage: ${monitoringUrl.value}`);
} else if (window.localStorage.getItem("mu")) {
monitoringUrl.value = window.localStorage.getItem("mu");
console.debug(`Monitoring Url, not in QS, found in local storage: ${monitoringUrl.value}`);
} else if (window.defaultConfig && window.defaultConfig.monitoring_urls && window.defaultConfig.monitoring_urls.length) {
monitoringUrl.value = window.defaultConfig.monitoring_urls[0];
console.debug(`setting Monitoring Url to its default value: ${window.defaultConfig.monitoring_urls[0]}`);
} else {
console.warn("Monitoring Url is not defined.");
}
}

async function updateFilterString(filter: string | null = null) {
filterString.value = filter ?? route.query.filter?.toString() ?? "";

Expand Down Expand Up @@ -73,9 +103,9 @@ export const useMonitoringStore = defineStore("MonitoringStore", () => {

async function getAllMonitoredEndpoints() {
let endpoints: Endpoint[] = [];
if (serviceControlStore.isMonitoringEnabled) {
if (isMonitoringEnabled.value) {
try {
const [, data] = await serviceControlStore.fetchTypedFromMonitoring<Endpoint[]>(`monitored-endpoints?history=${historyPeriodStore.historyPeriod.pVal}`);
const [, data] = await fetchTypedFromMonitoring<Endpoint[]>(`monitored-endpoints?history=${historyPeriodStore.historyPeriod.pVal}`);
endpoints = data ?? [];
const [, exceptionGroups] = await serviceControlStore.fetchTypedFromServiceControl<GroupOperation[]>(`recoverability/groups/Endpoint Name`);

Expand Down Expand Up @@ -200,24 +230,60 @@ export const useMonitoringStore = defineStore("MonitoringStore", () => {
}
}

async function fetchTypedFromMonitoring<T>(suffix: string): Promise<[Response?, T?]> {
if (isMonitoringDisabled.value) {
return [];
}

const response = await fetch(`${getMonitoringUrl()}${suffix}`);
const data = await response.json();

return [response, data];
}

async function deleteFromMonitoring(suffix: string) {
const requestOptions = {
method: "DELETE",
};
return await fetch(`${getMonitoringUrl()}${suffix}`, requestOptions);
}

async function optionsFromMonitoring() {
if (isMonitoringDisabled.value) {
return Promise.resolve(null);
}

const requestOptions = {
method: "OPTIONS",
};
return await fetch(getMonitoringUrl() ?? "", requestOptions);
}

return {
//state
monitoringUrl,
grouping,
endpointList,
disconnectedEndpointCount,
filterString,
sortBy,

//getters
isMonitoringDisabled,
isMonitoringEnabled,
Comment on lines +274 to +275
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we really need two?

Copy link
Contributor Author

@PhilBastian PhilBastian Oct 28, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

¯_(ツ)_/¯. I guess it makes it more readable in the usage sites if it's a positive or negative based usage

endpointListCount,
endpointListIsEmpty,
endpointListIsGrouped,
getEndpointList,

//actions
refresh,
updateSelectedGrouping,
updateEndpointList,
updateFilterString,
fetchTypedFromMonitoring,
deleteFromMonitoring,
optionsFromMonitoring,
Comment on lines +286 to +288
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should these be typed?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't understand what you're referring to

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Example, instead of await monitoringStore.fetchTypedFromMonitoring<EndpointDetails>(${monitored-endpoints}/${endpointName}?history=${historyPeriod}); we would call monitoringStore.getHistory(endpointName, historyPeriod)
Or instead of monitoringStore.fetchTypedFromMonitoring<number>("monitored-endpoints/disconnected"), we would call monitoringStore.disconnected()

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if we applied the same logic to the servicecontrolstore, we'd have ~100 different functions exposed from the store.
It's an idea worth exploring, but not as part of this refactor IMO

};
});

Expand Down
Loading
Loading