Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
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
166 changes: 2 additions & 164 deletions src/Frontend/src/components/audit/AuditList.vue
Original file line number Diff line number Diff line change
@@ -1,12 +1,10 @@
<script setup lang="ts">
import routeLinks from "@/router/routeLinks";
import { FieldNames, useAuditStore } from "@/stores/AuditStore";
import { storeToRefs } from "pinia";
import Message, { MessageStatus } from "@/resources/Message";
import { useRoute, useRouter } from "vue-router";
import ResultsCount from "@/components/ResultsCount.vue";
import { dotNetTimespanToMilliseconds, formatDotNetTimespan } from "@/composables/formatUtils";
import FiltersPanel from "@/components/audit/FiltersPanel.vue";
import AuditListItem from "@/components/audit/AuditListItem.vue";
import { onBeforeMount, onUnmounted, ref, watch } from "vue";
import RefreshConfig from "../RefreshConfig.vue";
import useAutoRefresh from "@/composables/autoRefresh";
Expand Down Expand Up @@ -36,58 +34,6 @@ onUnmounted(() => {
dataRetriever.updateTimeout(null);
});

function statusToName(messageStatus: MessageStatus) {
switch (messageStatus) {
case MessageStatus.Successful:
return "Successful";
case MessageStatus.ResolvedSuccessfully:
return "Successful after retries";
case MessageStatus.Failed:
return "Failed";
case MessageStatus.ArchivedFailure:
return "Failed message deleted";
case MessageStatus.RepeatedFailure:
return "Repeated Failures";
case MessageStatus.RetryIssued:
return "Retry requested";
}
}

function statusToIcon(messageStatus: MessageStatus) {
switch (messageStatus) {
case MessageStatus.Successful:
return "fa successful";
case MessageStatus.ResolvedSuccessfully:
return "fa resolved-successfully";
case MessageStatus.Failed:
return "fa failed";
case MessageStatus.ArchivedFailure:
return "fa archived";
case MessageStatus.RepeatedFailure:
return "fa repeated-failure";
case MessageStatus.RetryIssued:
return "fa retry-issued";
}
}

function hasWarning(message: Message) {
return (
message.status === MessageStatus.ResolvedSuccessfully || //
dotNetTimespanToMilliseconds(message.critical_time) < 0 ||
dotNetTimespanToMilliseconds(message.processing_time) < 0 ||
dotNetTimespanToMilliseconds(message.delivery_time) < 0
);
}

function navigateToMessage(message: Message) {
const query = router.currentRoute.value.query;

router.push({
path: message.status === MessageStatus.Successful || message.status === MessageStatus.ResolvedSuccessfully ? routeLinks.messages.successMessage.link(message.message_id, message.id) : routeLinks.messages.failedMessage.link(message.id),
query: { ...query, ...{ back: route.path } },
});
}

const firstLoad = ref(true);

onBeforeMount(() => {
Expand Down Expand Up @@ -167,20 +113,7 @@ watch(autoRefreshValue, (newValue) => dataRetriever.updateTimeout(newValue));
<div class="row results-table">
<LoadingSpinner v-if="firstLoad" />
<template v-for="message in messages" :key="message.id">
<div class="item" @click="navigateToMessage(message)">
<div class="status">
<div class="status-container" v-tippy="{ content: statusToName(message.status) }">
<div class="status-icon" :class="statusToIcon(message.status)"></div>
<div v-if="hasWarning(message)" class="warning"></div>
</div>
</div>
<div class="message-id">{{ message.message_id }}</div>
<div class="message-type">{{ message.message_type }}</div>
<div class="time-sent"><span class="label-name">Time Sent:</span>{{ new Date(message.time_sent).toLocaleString() }}</div>
<div class="critical-time"><span class="label-name">Critical Time:</span>{{ formatDotNetTimespan(message.critical_time) }}</div>
<div class="processing-time"><span class="label-name">Processing Time:</span>{{ formatDotNetTimespan(message.processing_time) }}</div>
<div class="delivery-time"><span class="label-name">Delivery Time:</span>{{ formatDotNetTimespan(message.delivery_time) }}</div>
</div>
<AuditListItem :message="message" />
</template>
</div>
</div>
Expand All @@ -204,99 +137,4 @@ watch(autoRefreshValue, (newValue) => dataRetriever.updateTimeout(newValue));
margin-bottom: 5rem;
background-color: #ffffff;
}
.item {
padding: 0.3rem 0.2rem;
border: 1px solid #ffffff;
border-bottom: 1px solid #eee;
display: grid;
grid-template-columns: 1.8em 1fr 1fr 1fr 1fr;
grid-template-rows: 1fr 1fr;
gap: 0.375rem;
grid-template-areas:
"status message-type message-type message-type time-sent"
"status message-id processing-time critical-time delivery-time";
}
.item:not(:first-child) {
border-top-color: #eee;
}
.item:hover {
border-color: #00a3c4;
background-color: #edf6f7;
cursor: pointer;
}
.label-name {
margin-right: 0.25rem;
color: #777f7f;
}
.status {
grid-area: status;
}
.message-id {
grid-area: message-id;
}
.time-sent {
grid-area: time-sent;
}
.message-type {
grid-area: message-type;
font-weight: bold;
overflow-wrap: break-word;
}
.processing-time {
grid-area: processing-time;
}
.critical-time {
grid-area: critical-time;
}
.delivery-time {
grid-area: delivery-time;
}
.status-container {
color: white;
width: 1.4em;
height: 1.4em;
position: relative;
}

.status-icon {
background-position: center;
background-repeat: no-repeat;
height: 1.4em;
width: 1.4em;
}

.warning {
background-image: url("@/assets/warning.svg");
background-position: bottom;
background-repeat: no-repeat;
height: 0.93em;
width: 0.93em;
position: absolute;
right: 0;
bottom: 0;
}

.successful {
background-image: url("@/assets/status_successful.svg");
}

.resolved-successfully {
background-image: url("@/assets/status_resolved.svg");
}

.failed {
background-image: url("@/assets/status_failed.svg");
}

.archived {
background-image: url("@/assets/status_archived.svg");
}

.repeated-failure {
background-image: url("@/assets/status_repeated_failed.svg");
}

.retry-issued {
background-image: url("@/assets/status_retry_issued.svg");
}
</style>
88 changes: 88 additions & 0 deletions src/Frontend/src/components/audit/AuditListItem.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
<script setup lang="ts">
import routeLinks from "@/router/routeLinks";
import Message, { MessageStatus } from "@/resources/Message";
import { defineProps } from "vue";
import { formatDotNetTimespan } from "@/composables/formatUtils";
import { useRoute, useRouter } from "vue-router";
import MessageStatusIcon from "@/components/audit/MessageStatusIcon.vue";
const route = useRoute();
const router = useRouter();
const props = defineProps<{
message: Message;
}>();
function navigateToMessage(message: Message) {
const query = router.currentRoute.value.query;
router.push({
path: message.status === MessageStatus.Successful || message.status === MessageStatus.ResolvedSuccessfully ? routeLinks.messages.successMessage.link(message.message_id, message.id) : routeLinks.messages.failedMessage.link(message.id),
query: { ...query, ...{ back: route.path } },
});
}
</script>

<template>
<div class="item" @click="navigateToMessage(props.message)">
<div class="status">
<MessageStatusIcon :message="props.message" />
</div>
<div class="message-id">{{ props.message.message_id }}</div>
<div class="message-type">{{ props.message.message_type }}</div>
<div class="time-sent"><span class="label-name">Time Sent:</span>{{ new Date(props.message.time_sent).toLocaleString() }}</div>
<div class="critical-time"><span class="label-name">Critical Time:</span>{{ formatDotNetTimespan(props.message.critical_time) }}</div>
<div class="processing-time"><span class="label-name">Processing Time:</span>{{ formatDotNetTimespan(props.message.processing_time) }}</div>
<div class="delivery-time"><span class="label-name">Delivery Time:</span>{{ formatDotNetTimespan(props.message.delivery_time) }}</div>
</div>
</template>

<style scoped>
.item {
padding: 0.3rem 0.2rem;
border: 1px solid #ffffff;
border-bottom: 1px solid #eee;
display: grid;
grid-template-columns: 1.8em 1fr 1fr 1fr 1fr;
grid-template-rows: 1fr 1fr;
gap: 0.375rem;
grid-template-areas:
"status message-type message-type message-type time-sent"
"status message-id processing-time critical-time delivery-time";
}
.item:not(:first-child) {
border-top-color: #eee;
}
.item:hover {
border-color: #00a3c4;
background-color: #edf6f7;
cursor: pointer;
}
.label-name {
margin-right: 0.25rem;
color: #777f7f;
}
.status {
grid-area: status;
}
.message-id {
grid-area: message-id;
}
.time-sent {
grid-area: time-sent;
}
.message-type {
grid-area: message-type;
font-weight: bold;
overflow-wrap: break-word;
}
.processing-time {
grid-area: processing-time;
}
.critical-time {
grid-area: critical-time;
}
.delivery-time {
grid-area: delivery-time;
}
</style>
95 changes: 95 additions & 0 deletions src/Frontend/src/components/audit/MessageStatusIcon.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
<script setup lang="ts">
import { dotNetTimespanToMilliseconds } from "@/composables/formatUtils";
import Message, { MessageStatus } from "@/resources/Message";
import { defineProps, computed } from "vue";

const props = defineProps<{
message: Message;
}>();

const hasWarning = computed(() => {
return (
props.message.status === MessageStatus.ResolvedSuccessfully ||
dotNetTimespanToMilliseconds(props.message.critical_time) < 0 ||
dotNetTimespanToMilliseconds(props.message.processing_time) < 0 ||
dotNetTimespanToMilliseconds(props.message.delivery_time) < 0
);
});

const statusInfo = computed(() => {
switch (props.message.status) {
case MessageStatus.Successful:
return { name: "Successful", icon: "fa successful" };
case MessageStatus.ResolvedSuccessfully:
return { name: "Successful after retries", icon: "fa resolved-successfully" };
case MessageStatus.Failed:
return { name: "Failed", icon: "fa failed" };
case MessageStatus.ArchivedFailure:
return { name: "Failed message deleted", icon: "fa archived" };
case MessageStatus.RepeatedFailure:
return { name: "Repeated failures", icon: "fa repeated-failure" };
case MessageStatus.RetryIssued:
return { name: "Retry requested", icon: "fa retry-issued" };
default:
return { name: "Unknown status", icon: "fa fa-question-circle" };
}
});
</script>

<template>
<div class="status-container" v-tippy="{ content: statusInfo.name }">
<div class="status-icon" :class="statusInfo.icon"></div>
<div v-if="hasWarning" class="warning"></div>
</div>
</template>

<style scoped>
.status-container {
color: white;
width: 1.4em;
height: 1.4em;
position: relative;
}

.status-icon {
background-position: center;
background-repeat: no-repeat;
height: 1.4em;
width: 1.4em;
}

.warning {
background-image: url("@/assets/warning.svg");
background-position: bottom;
background-repeat: no-repeat;
height: 0.93em;
width: 0.93em;
position: absolute;
right: 0;
bottom: 0;
}

.successful {
background-image: url("@/assets/status_successful.svg");
}

.resolved-successfully {
background-image: url("@/assets/status_resolved.svg");
}

.failed {
background-image: url("@/assets/status_failed.svg");
}

.archived {
background-image: url("@/assets/status_archived.svg");
}

.repeated-failure {
background-image: url("@/assets/status_repeated_failed.svg");
}

.retry-issued {
background-image: url("@/assets/status_retry_issued.svg");
}
</style>