Skip to content

Commit b148921

Browse files
committed
include audit section displaying audit messages
1 parent 99c30b6 commit b148921

File tree

7 files changed

+223
-0
lines changed

7 files changed

+223
-0
lines changed

src/Frontend/src/components/PageHeader.vue

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,13 +12,15 @@ import EventsMenuItem from "@/components/events/EventsMenuItem.vue";
1212
import DashboardMenuItem from "@/components/dashboard/DashboardMenuItem.vue";
1313
import FeedbackButton from "@/components/FeedbackButton.vue";
1414
import ThroughputMenuItem from "@/views/throughputreport/ThroughputMenuItem.vue";
15+
import AuditMenuItem from "./audit/AuditMenuItem.vue";
1516
1617
// prettier-ignore
1718
const menuItems = computed(
1819
() => [
1920
DashboardMenuItem,
2021
HeartbeatsMenuItem,
2122
...(useIsMonitoringEnabled() ? [MonitoringMenuItem] : []),
23+
AuditMenuItem,
2224
FailedMessagesMenuItem,
2325
CustomChecksMenuItem,
2426
EventsMenuItem,
Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
<script setup lang="ts">
2+
import routeLinks from "@/router/routeLinks";
3+
import { ColumnNames, useAuditStore } from "@/stores/AuditStore";
4+
import { storeToRefs } from "pinia";
5+
import { useRoute } from "vue-router";
6+
import DataView from "../DataView.vue";
7+
8+
const route = useRoute();
9+
const store = useAuditStore();
10+
const { messages, sortByInstances, itemsPerPage } = storeToRefs(store);
11+
</script>
12+
13+
<template>
14+
<section role="table" aria-label="endpoint-instances">
15+
<!--Table headings-->
16+
<div role="row" aria-label="column-headers" class="row table-head-row" :style="{ borderTop: 0 }">
17+
<div role="columnheader" :aria-label="ColumnNames.Status" class="status">
18+
<SortableColumn :sort-by="ColumnNames.Status" v-model="sortByInstances" :default-ascending="true">Status</SortableColumn>
19+
</div>
20+
<div role="columnheader" :aria-label="ColumnNames.MessageId" class="col-3">
21+
<SortableColumn :sort-by="ColumnNames.MessageId" v-model="sortByInstances" :default-ascending="true">Message Id</SortableColumn>
22+
</div>
23+
<div role="columnheader" :aria-label="ColumnNames.MessageType" class="col-3">
24+
<SortableColumn :sort-by="ColumnNames.MessageType" v-model="sortByInstances" :default-ascending="true">Type</SortableColumn>
25+
</div>
26+
<div role="columnheader" :aria-label="ColumnNames.TimeSent" class="col-2">
27+
<SortableColumn :sort-by="ColumnNames.TimeSent" v-model="sortByInstances">Time Sent</SortableColumn>
28+
</div>
29+
<div role="columnheader" :aria-label="ColumnNames.ProcessingTime" class="col-2">
30+
<SortableColumn :sort-by="ColumnNames.ProcessingTime" v-model="sortByInstances">Processing Time</SortableColumn>
31+
</div>
32+
</div>
33+
<!--Table rows-->
34+
<!--NOTE: currently the DataView pages on the client only: we need to make it server data aware (i.e. the total will be the count from the server, not the length of the data we have locally)-->
35+
<DataView :data="messages" :show-items-per-page="true" :items-per-page="itemsPerPage" @items-per-page-changed="store.setItemsPerPage">
36+
<template #data="{ pageData }">
37+
<div role="rowgroup" aria-label="endpoints">
38+
<div role="row" :aria-label="message.message_id" class="row grid-row" v-for="message in pageData" :key="message.id">
39+
<div role="cell" aria-label="instance-name" class="status">
40+
{{ "todo" }}
41+
</div>
42+
<div role="cell" aria-label="message-id" class="col-3 message-id">
43+
<div class="box-header">
44+
<tippy :aria-label="message.message_id" :delay="[700, 0]" class="no-side-padding lead righ-side-ellipsis endpoint-details-link">
45+
<template #content>
46+
<p :style="{ overflowWrap: 'break-word' }">{{ message.message_id }}</p>
47+
</template>
48+
<RouterLink class="hackToPreventSafariFromShowingTooltip" aria-label="details-link" :to="{ path: routeLinks.audit.message.link(message.id), query: { back: route.path } }">
49+
{{ message.id }}
50+
</RouterLink>
51+
</tippy>
52+
</div>
53+
</div>
54+
<div role="cell" aria-label="message-type" class="col-3 message-type">
55+
{{ message.message_type }}
56+
</div>
57+
<div role="cell" aria-label="time-sent" class="col-2 time-sent">
58+
{{ "todo" }}
59+
</div>
60+
<div role="cell" aria-label="processing-time" class="col-2 processing-time">
61+
{{ "todo" }}
62+
</div>
63+
</div>
64+
</div>
65+
</template>
66+
</DataView>
67+
</section>
68+
</template>
69+
70+
<style scoped>
71+
@import "../list.css";
72+
73+
.hackToPreventSafariFromShowingTooltip::after {
74+
content: "";
75+
display: block;
76+
}
77+
78+
.instances-muted {
79+
font-weight: bold;
80+
}
81+
82+
.status {
83+
width: 5em;
84+
text-align: center;
85+
}
86+
</style>
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
<script setup lang="ts">
2+
import { RouterLink } from "vue-router";
3+
import routeLinks from "@/router/routeLinks";
4+
</script>
5+
6+
<template>
7+
<RouterLink :to="routeLinks.audit.root">
8+
<i class="fa fa-envelope icon-white" title="Audit"></i>
9+
<span class="navbar-label">Audit</span>
10+
</RouterLink>
11+
</template>
12+
13+
<style scoped>
14+
@import "@/assets/navbar.css";
15+
@import "@/assets/header-menu-item.css";
16+
</style>

src/Frontend/src/router/config.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import routeLinks from "@/router/routeLinks";
88
import CustomChecksView from "@/views/CustomChecksView.vue";
99
import HeartbeatsView from "@/views/HeartbeatsView.vue";
1010
import ThroughputReportView from "@/views/ThroughputReportView.vue";
11+
import AuditView from "@/views/AuditView.vue";
1112

1213
export interface RouteItem {
1314
path: string;
@@ -52,6 +53,11 @@ const config: RouteItem[] = [
5253
},
5354
],
5455
},
56+
{
57+
path: routeLinks.audit.root,
58+
component: AuditView,
59+
title: "Messages",
60+
},
5561
{
5662
path: routeLinks.failedMessage.root,
5763
component: FailedMessagesView,

src/Frontend/src/router/routeLinks.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,17 @@ const heartbeatLinks = (root: string) => {
1212
};
1313
};
1414

15+
const auditLinks = (root: string) => {
16+
// function createLink(template: string) {
17+
// return { link: `${root}/${template}`, template: template };
18+
// }
19+
20+
return {
21+
root,
22+
message: { link: (id: string) => `${root}/message/${id}`, template: "message/:id" },
23+
};
24+
};
25+
1526
const failedMessagesLinks = (root: string) => {
1627
function createLink(template: string) {
1728
return { link: `${root}/${template}`, template: template };
@@ -93,6 +104,7 @@ const routeLinks = {
93104
dashboard: "/dashboard",
94105
heartbeats: heartbeatLinks("/heartbeats"),
95106
monitoring: monitoringLinks("/monitoring"),
107+
audit: auditLinks("/audit"),
96108
failedMessage: failedMessagesLinks("/failed-messages"),
97109
customChecks: "/custom-checks",
98110
events: "/events",
Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
import { useTypedFetchFromServiceControl } from "@/composables/serviceServiceControlUrls";
2+
import { acceptHMRUpdate, defineStore } from "pinia";
3+
import { ref, watch } from "vue";
4+
import useAutoRefresh from "@/composables/autoRefresh";
5+
//import { SortDirection, type GroupPropertyType } from "@/resources/SortOptions";
6+
import type { SortInfo } from "@/components/SortInfo";
7+
import Message from "@/resources/Message";
8+
9+
export enum ColumnNames {
10+
Status = "status",
11+
MessageId = "messageId",
12+
MessageType = "messageType",
13+
TimeSent = "timeSent",
14+
ProcessingTime = "processingTime",
15+
}
16+
17+
// const columnSortings = new Map<string, (endpoint: Message) => GroupPropertyType>([
18+
// // [ColumnNames.Name, (endpoint) => endpoint.name],
19+
// // [ColumnNames.InstancesDown, (endpoint) => endpoint.alive_count - endpoint.down_count],
20+
// // [ColumnNames.InstancesTotal, (endpoint) => endpoint.alive_count + endpoint.down_count],
21+
// // [ColumnNames.LastHeartbeat, (endpoint) => moment.utc(endpoint.heartbeat_information?.last_report_at ?? "1975-01-01T00:00:00")],
22+
// // [ColumnNames.Tracked, (endpoint) => endpoint.track_instances],
23+
// // [ColumnNames.TrackToggle, (endpoint) => endpoint.track_instances],
24+
// ]);
25+
26+
export const useAuditStore = defineStore("AuditStore", () => {
27+
const sortByInstances = ref<SortInfo>({
28+
property: ColumnNames.MessageId,
29+
isAscending: true,
30+
});
31+
32+
const messageFilterString = ref("");
33+
const itemsPerPage = ref(20);
34+
const messages = ref<Message[]>([]);
35+
// const sortedMessages = computed<Message[]>(() =>
36+
// [...messages.value].sort(getSortFunction(columnSortings.get(sortByInstances.value.property), sortByInstances.value.isAscending ? SortDirection.Ascending : SortDirection.Descending))
37+
// );
38+
// const filteredMessages = computed<Message[]>(() => sortedMessages.value.filter((message) => !messageFilterString.value || message.id.toLowerCase().includes(messageFilterString.value.toLowerCase())));
39+
watch(messageFilterString, (newValue) => {
40+
setMessageFilterString(newValue);
41+
});
42+
43+
const dataRetriever = useAutoRefresh(async () => {
44+
try {
45+
const [, data] = await useTypedFetchFromServiceControl<Message[]>("messages");
46+
messages.value = data;
47+
} catch (e) {
48+
messages.value = [];
49+
throw e;
50+
}
51+
}, 30000);
52+
53+
function setMessageFilterString(filter: string) {
54+
messageFilterString.value = filter;
55+
}
56+
57+
function setItemsPerPage(value: number) {
58+
itemsPerPage.value = value;
59+
}
60+
61+
const refresh = dataRetriever.executeAndResetTimer;
62+
63+
// eslint-disable-next-line promise/catch-or-return,promise/prefer-await-to-then,promise/valid-params
64+
refresh().then();
65+
66+
return {
67+
refresh,
68+
sortByInstances,
69+
messages,
70+
messageFilterString,
71+
itemsPerPage,
72+
setItemsPerPage,
73+
};
74+
});
75+
76+
if (import.meta.hot) {
77+
import.meta.hot.accept(acceptHMRUpdate(useAuditStore, import.meta.hot));
78+
}
79+
80+
export type AuditStore = ReturnType<typeof useAuditStore>;
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
<script setup lang="ts">
2+
import { licenseStatus } from "../composables/serviceLicense";
3+
import LicenseExpired from "../components/LicenseExpired.vue";
4+
import AuditList from "@/components/audit/AuditList.vue";
5+
</script>
6+
7+
<template>
8+
<LicenseExpired />
9+
<template v-if="!licenseStatus.isExpired">
10+
<div class="container">
11+
<div class="row">
12+
<div class="col-12">
13+
<h1>Audit Messages</h1>
14+
</div>
15+
</div>
16+
<div class="row">
17+
<AuditList />
18+
</div>
19+
</div>
20+
</template>
21+
</template>

0 commit comments

Comments
 (0)