-
Notifications
You must be signed in to change notification settings - Fork 26
Add all messages list to ServicePulse #2275
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 22 commits
b148921
105cc68
337fdef
dd2cd69
36d7815
b281cf3
f706a7f
db87e15
ef84c78
2616724
0065abb
6933c0f
10ae9af
0a510d0
ba62324
60e4bfa
322f801
9cf0ac4
338d370
3b206eb
9e77b04
be36fd2
2fd84ca
7d3e2a7
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
@@ -0,0 +1,86 @@ | ||||||
<script setup lang="ts"> | ||||||
import { ref } from "vue"; | ||||||
import OnOffSwitch from "./OnOffSwitch.vue"; | ||||||
const props = defineProps<{ | ||||||
id: string; | ||||||
initialTimeout?: number; | ||||||
onManualRefresh: () => void; | ||||||
}>(); | ||||||
const emit = defineEmits<{ change: [newValue: number | null]; manualRefresh: [] }>(); | ||||||
const autoRefresh = ref(props.initialTimeout != null); | ||||||
const refreshTimeout = ref(props.initialTimeout ?? 5); | ||||||
function toggleRefresh() { | ||||||
autoRefresh.value = !autoRefresh.value; | ||||||
updateTimeout(); | ||||||
} | ||||||
function updateTimeout() { | ||||||
validateTimeout(); | ||||||
emit("change", autoRefresh.value ? refreshTimeout.value * 1000 : null); | ||||||
} | ||||||
function validateTimeout() { | ||||||
refreshTimeout.value = Math.max(1, Math.min(600, refreshTimeout.value)); | ||||||
} | ||||||
</script> | ||||||
|
||||||
<template> | ||||||
<div class="refresh-config"> | ||||||
<button class="fa" title="refresh" @click="() => emit('manualRefresh')"> | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. why? I don't want this to look like other buttons in the system There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why should this button be different? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. because of the layout |
||||||
<i class="fa fa-lg fa-refresh" /> | ||||||
</button> | ||||||
<span>|</span> | ||||||
<label>Auto-Refresh:</label> | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It would be nice to have some kind of visual indication that we are fetching new data - https://fontawesome.com/icons/spinner?f=classic&s=solid There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. added as idea |
||||||
<div> | ||||||
<OnOffSwitch :id="id" @toggle="toggleRefresh" :value="autoRefresh" /> | ||||||
</div> | ||||||
<input type="number" v-model="refreshTimeout" min="1" max="600" v-on:change="updateTimeout" /> | ||||||
<span class="unit">s</span> | ||||||
Comment on lines
+38
to
+42
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Could a dropdown with pre-set refresh ratings including zero be better option? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. this works, and looks fine... |
||||||
</div> | ||||||
</template> | ||||||
|
||||||
<style scoped> | ||||||
.refresh-config { | ||||||
display: flex; | ||||||
align-items: center; | ||||||
gap: 0.5em; | ||||||
} | ||||||
.refresh-config .unit { | ||||||
margin-left: -0.45em; | ||||||
} | ||||||
.refresh-config label { | ||||||
margin: 0; | ||||||
} | ||||||
.refresh-config input { | ||||||
width: 3.5em; | ||||||
} | ||||||
.refresh-config button { | ||||||
background: none; | ||||||
border: none; | ||||||
width: 2em; | ||||||
} | ||||||
.refresh-config button .fa { | ||||||
transition: all 0.15s ease-in-out; | ||||||
transition: rotate 0.05s ease-in-out; | ||||||
transform-origin: center; | ||||||
} | ||||||
.refresh-config button:hover .fa { | ||||||
color: #00a3c4; | ||||||
transform: scale(1.1); | ||||||
} | ||||||
.refresh-config button:active .fa { | ||||||
transform: rotate(25deg); | ||||||
text-shadow: #929e9e 0.25px 0.25px; | ||||||
} | ||||||
</style> |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,224 @@ | ||
<script setup lang="ts"> | ||
import routeLinks from "@/router/routeLinks"; | ||
import { ColumnNames, useAuditStore } from "@/stores/AuditStore"; | ||
import { storeToRefs } from "pinia"; | ||
import { useRoute } from "vue-router"; | ||
import SortableColumn from "../SortableColumn.vue"; | ||
import { MessageStatus } from "@/resources/Message"; | ||
import moment from "moment"; | ||
import { useFormatTime } from "@/composables/formatter"; | ||
import RefreshConfig from "../RefreshConfig.vue"; | ||
import ItemsPerPage from "../ItemsPerPage.vue"; | ||
import PaginationStrip from "../PaginationStrip.vue"; | ||
const route = useRoute(); | ||
const store = useAuditStore(); | ||
const { messages, sortByInstances, itemsPerPage, selectedPage, totalCount } = storeToRefs(store); | ||
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 friendlyTypeName(messageType: string) { | ||
if (messageType == null) return null; | ||
const typeClass = messageType.split(",")[0]; | ||
const typeName = typeClass.split(".").reverse()[0]; | ||
return typeName.replace(/\+/g, "."); | ||
} | ||
Comment on lines
+52
to
+58
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This can be problematic, it may be worth adding a card to the board. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. In other places, we show the whole type name There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. added card |
||
function formatDotNetTimespan(timespan: string) { | ||
//assuming if we have days in the timespan then something is very, very wrong | ||
const [hh, mm, ss] = timespan.split(":"); | ||
const time = useFormatTime(((parseInt(hh) * 60 + parseInt(mm)) * 60 + parseFloat(ss)) * 1000); | ||
return `${time.value} ${time.unit}`; | ||
} | ||
PhilBastian marked this conversation as resolved.
Show resolved
Hide resolved
|
||
</script> | ||
|
||
<template> | ||
<section class="section-table" role="table" aria-label="endpoint-instances"> | ||
<div class="header"> | ||
<RefreshConfig id="auditListRefresh" @change="store.updateRefreshTimer" @manual-refresh="store.refresh" /> | ||
<!--Table headings--> | ||
<div role="row" aria-label="column-headers" class="row table-head-row" :style="{ borderTop: 0 }"> | ||
<div role="columnheader" :aria-label="ColumnNames.Status" class="status"> | ||
<SortableColumn :sort-by="ColumnNames.Status" v-model="sortByInstances" :default-ascending="true">Status</SortableColumn> | ||
</div> | ||
<div role="columnheader" :aria-label="ColumnNames.MessageId" class="col-3"> | ||
<SortableColumn :sort-by="ColumnNames.MessageId" v-model="sortByInstances" :default-ascending="true">Message Id</SortableColumn> | ||
</div> | ||
<div role="columnheader" :aria-label="ColumnNames.MessageType" class="col-3"> | ||
<SortableColumn :sort-by="ColumnNames.MessageType" v-model="sortByInstances" :default-ascending="true">Type</SortableColumn> | ||
</div> | ||
<div role="columnheader" :aria-label="ColumnNames.TimeSent" class="col-2"> | ||
<SortableColumn :sort-by="ColumnNames.TimeSent" v-model="sortByInstances">Time Sent</SortableColumn> | ||
</div> | ||
<div role="columnheader" :aria-label="ColumnNames.ProcessingTime" class="col-2"> | ||
<SortableColumn :sort-by="ColumnNames.ProcessingTime" v-model="sortByInstances">Processing Time</SortableColumn> | ||
</div> | ||
</div> | ||
</div> | ||
<!--Table rows--> | ||
<!--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)--> | ||
<div class="messages" role="rowgroup" aria-label="messages"> | ||
<div role="row" :aria-label="message.message_id" class="row grid-row" v-for="message in messages" :key="message.id"> | ||
<div role="cell" aria-label="status" class="status" :title="statusToName(message.status)"> | ||
<div class="status-icon" :class="statusToIcon(message.status)"></div> | ||
</div> | ||
<div role="cell" aria-label="message-id" class="col-3 message-id"> | ||
<div class="box-header"> | ||
<tippy :aria-label="message.message_id" :delay="[700, 0]" class="no-side-padding lead righ-side-ellipsis endpoint-details-link"> | ||
<template #content> | ||
<p :style="{ overflowWrap: 'break-word' }">{{ message.message_id }}</p> | ||
</template> | ||
<RouterLink class="hackToPreventSafariFromShowingTooltip" aria-label="details-link" :to="{ path: routeLinks.messages.message.link(message.id), query: { back: route.path } }"> | ||
{{ message.message_id }} | ||
</RouterLink> | ||
</tippy> | ||
</div> | ||
</div> | ||
<div role="cell" aria-label="message-type" class="col-3 message-type"> | ||
{{ friendlyTypeName(message.message_type) }} | ||
</div> | ||
<div role="cell" aria-label="time-sent" class="col-2 time-sent"> | ||
{{ moment(message.time_sent).local().format("LLLL") }} | ||
</div> | ||
<div role="cell" aria-label="processing-time" class="col-2 processing-time"> | ||
{{ formatDotNetTimespan(message.processing_time) }} | ||
</div> | ||
</div> | ||
</div> | ||
<div class="row"> | ||
<ItemsPerPage v-model="itemsPerPage" /> | ||
<PaginationStrip v-model="selectedPage" :totalCount="totalCount" :itemsPerPage="itemsPerPage" /> | ||
</div> | ||
</section> | ||
</template> | ||
|
||
<style scoped> | ||
@import "../list.css"; | ||
.hackToPreventSafariFromShowingTooltip::after { | ||
content: ""; | ||
display: block; | ||
} | ||
.section-table { | ||
overflow: auto; | ||
flex: 1; | ||
display: flex; | ||
flex-direction: column; | ||
} | ||
.messages { | ||
flex: 1; | ||
overflow: auto; | ||
} | ||
.status { | ||
width: 5em; | ||
text-align: center; | ||
} | ||
.status-icon { | ||
color: white; | ||
border-radius: 0.75em; | ||
width: 1.2em; | ||
height: 1.2em; | ||
} | ||
.status-icon::before { | ||
vertical-align: middle; | ||
font-size: 0.85em; | ||
} | ||
.successful { | ||
background: #6cc63f; | ||
} | ||
.successful::before { | ||
content: "\f00c"; | ||
} | ||
.resolved-successfully { | ||
background: #3f881b; | ||
} | ||
.resolved-successfully::before { | ||
content: "\f01e"; | ||
} | ||
.failed { | ||
background: #c63f3f; | ||
} | ||
.failed::before { | ||
content: "\f00d"; | ||
} | ||
.archived { | ||
background: #000000; | ||
} | ||
.archived::before { | ||
content: "\f187"; | ||
font-size: 0.85em; | ||
} | ||
.repeated-failure { | ||
background: #c63f3f; | ||
} | ||
.repeated-failure::before { | ||
content: "\f00d\f00d"; | ||
font-size: 0.6em; | ||
} | ||
.retry-issued { | ||
background: #cccccc; | ||
color: #000000; | ||
} | ||
.retry-issued::before { | ||
content: "\f01e"; | ||
} | ||
.grid-row { | ||
display: flex; | ||
position: relative; | ||
border-top: 1px solid #eee; | ||
border-right: 1px solid #fff; | ||
border-bottom: 1px solid #eee; | ||
border-left: 1px solid #fff; | ||
background-color: #fff; | ||
margin: 0; | ||
} | ||
.grid-row:nth-child(even) { | ||
background-color: #eee; | ||
} | ||
</style> |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
<script setup lang="ts"> | ||
import { RouterLink } from "vue-router"; | ||
import routeLinks from "@/router/routeLinks"; | ||
</script> | ||
|
||
<template> | ||
<RouterLink :to="routeLinks.messages.root"> | ||
<i class="fa fa-envelope icon-white" title="All Messages"></i> | ||
<span class="navbar-label">All Messages</span> | ||
</RouterLink> | ||
</template> | ||
|
||
<style scoped> | ||
@import "@/assets/navbar.css"; | ||
@import "@/assets/header-menu-item.css"; | ||
</style> |
This file was deleted.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I was thinking that it may also make sense to save in local storage the current setting, so it won't reset
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
added as idea