Skip to content
Closed
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
3 changes: 0 additions & 3 deletions src/Frontend/src/assets/footer.css
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,10 @@ footer {
color: #bcc6c2;
font-size: 14px;
font-weight: normal;
margin-top: 100px;
text-align: left;
text-align: center;
width: 100%;
background-color: #fff;
position: fixed;
bottom: 0;
border-top: 1px solid #ddd;
box-shadow: 0px -10px 16px #f2f6f7;
padding-top: 7px;
Expand Down
4 changes: 3 additions & 1 deletion src/Frontend/src/assets/main.css
Original file line number Diff line number Diff line change
Expand Up @@ -76,9 +76,11 @@ body {

#main-content {
padding-top: 40px;
padding-bottom: 40px;
overflow: auto;
flex: 1;
display: flex;
flex-direction: column;
--main-background: #f2f6f7;
}

h1 {
Expand Down
20 changes: 12 additions & 8 deletions src/Frontend/src/components/CodeEditor.vue
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ const props = withDefaults(
showCopyToClipboard?: boolean;
ariaLabel?: string;
css?: string;
toolbarStickyHeight?: string;
}>(),
{ readOnly: true, showGutter: true, showCopyToClipboard: true }
);
Expand Down Expand Up @@ -50,21 +51,20 @@ const extensions = computed(() => {
</script>

<template>
<div class="wrapper" :aria-label="ariaLabel" :class="css">
<div v-if="props.showCopyToClipboard || $slots.toolbarLeft || $slots.toolbarRight" class="toolbar">
<div><slot name="toolbarLeft"></slot></div>
<div>
<slot name="toolbarRight"></slot>
<CopyToClipboard class="clipboard" v-if="props.showCopyToClipboard" :value="code" />
</div>
<div v-if="props.showCopyToClipboard || $slots.toolbarLeft || $slots.toolbarRight" :class="{ toolbar: true, sticky: props.toolbarStickyHeight != null }" :style="{ top: props.toolbarStickyHeight }">
<div><slot name="toolbarLeft"></slot></div>
<div>
<slot name="toolbarRight"></slot>
<CopyToClipboard class="clipboard" v-if="props.showCopyToClipboard" :value="code" />
</div>
</div>
<div class="wrapper" :aria-label="ariaLabel" :class="css">
<CodeMirror v-model="code" :extensions="extensions" :basic="props.showGutter" :minimal="!props.showGutter" :readonly="props.readOnly" :gutter="!props.readOnly" :wrap="true"></CodeMirror>
</div>
</template>

<style scoped>
.wrapper {
margin-top: 5px;
border-radius: 0.5rem;
padding: 0.5rem;
border: 1px solid #ccc;
Expand All @@ -83,6 +83,10 @@ const extensions = computed(() => {
justify-content: space-between;
align-items: center;
}
.toolbar.sticky {
position: sticky;
z-index: 1;
}
.clipboard {
margin-left: 0.5rem;
}
Expand Down
10 changes: 9 additions & 1 deletion src/Frontend/src/components/TabsLayout.vue
Original file line number Diff line number Diff line change
Expand Up @@ -37,4 +37,12 @@ watch(
</keep-alive>
</template>

<style scoped></style>
<style scoped>
.tabs {
position: sticky;
top: 7.7rem;
z-index: 1;
margin-bottom: 1px;
background-color: var(--main-background);
}
</style>
18 changes: 5 additions & 13 deletions src/Frontend/src/components/messages2/BodyView.vue
Original file line number Diff line number Diff line change
Expand Up @@ -21,17 +21,9 @@ const body = computed(() => bodyState.value.data.value);
</script>

<template>
<div class="gap">
<div v-if="bodyState.not_found" class="alert alert-info">Could not find the message body. This could be because the message URL is invalid or the corresponding message was processed and is no longer tracked by ServiceControl.</div>
<div v-else-if="bodyState.failed_to_load" class="alert alert-info">Message body unavailable.</div>
<LoadingSpinner v-else-if="bodyState.loading" />
<CodeEditor v-else-if="body !== undefined && contentType.isSupported" :model-value="body" :language="contentType.language" :read-only="true" :show-gutter="true"></CodeEditor>
<div v-else class="alert alert-warning">Message body cannot be displayed because content type "{{ bodyState.data.content_type }}" is not supported.</div>
</div>
<div v-if="bodyState.not_found" class="alert alert-info">Could not find the message body. This could be because the message URL is invalid or the corresponding message was processed and is no longer tracked by ServiceControl.</div>
<div v-else-if="bodyState.failed_to_load" class="alert alert-info">Message body unavailable.</div>
<LoadingSpinner v-else-if="bodyState.loading" />
<CodeEditor v-else-if="body !== undefined && contentType.isSupported" :model-value="body" :language="contentType.language" :read-only="true" :show-gutter="true" toolbar-sticky-height="9.7rem"></CodeEditor>
<div v-else class="alert alert-warning">Message body cannot be displayed because content type "{{ bodyState.data.content_type }}" is not supported.</div>
</template>

<style scoped>
.gap {
margin-top: 5px;
}
</style>
Original file line number Diff line number Diff line change
Expand Up @@ -271,21 +271,22 @@ const selectedErrorColor = hexToCSSFilter("#e8e6e8").filter;
@import "../../list.css";

.gap {
margin-top: 5px;
border-radius: 0.5rem;
padding: 0.5rem;
border: 1px solid #ccc;
background: white;
flex: 1;
}

.controls {
display: flex;
flex-wrap: wrap;
justify-content: center;
}

#tree-container {
width: 92vw;
height: 70vh;
width: 100%;
height: 100%;
}

.sagas {
Expand Down
56 changes: 24 additions & 32 deletions src/Frontend/src/components/messages2/HeadersView.vue
Original file line number Diff line number Diff line change
Expand Up @@ -22,44 +22,33 @@ const filteredHeaders = computed(() => {
</script>

<template>
<div class="gap">
<div>
<div class="row filters">
<div class="col">
<div class="text-search-container">
<div class="text-search">
<div>
<FilterInput v-model="searchTerm" :aria-label="`Search for a header key or value`" :placeholder="'Search for a header key or value...'" />
</div>
</div>
<div class="row filters">
<div class="col">
<div class="text-search-container">
<div class="text-search">
<div>
<FilterInput v-model="searchTerm" :aria-label="`Search for a header key or value`" :placeholder="'Search for a header key or value...'" />
</div>
</div>
</div>
</div>
<div class="header-list" v-if="filteredHeaders.length > 0 && !headers.not_found">
<template v-for="(header, index) in filteredHeaders" :key="index">
<div class="header-key">{{ header.key }}</div>
<div class="header-value" @mouseover="toggleHover(index, true)" @mouseleave="toggleHover(index, false)">
<pre class="removeBootStrap">{{ header.value }}</pre>
<div class="clippy-button"><CopyToClipboard v-if="header.value && hoverStates[index]" :value="header.value" :isIconOnly="true" /></div>
</div>
</template>
</div>

<!-- Message if filtered list is empty -->
<div v-if="filteredHeaders.length <= 0 && !headers.not_found" class="alert alert-warning">No headers found matching the search term.</div>
<div v-if="headers.not_found" class="alert alert-info">Could not find message headers. This could be because the message URL is invalid or the corresponding message was processed and is no longer tracked by ServiceControl.</div>
</div>
<div class="header-list" v-if="filteredHeaders.length > 0 && !headers.not_found">
<template v-for="(header, index) in filteredHeaders" :key="index">
<div class="header-key">{{ header.key }}</div>
<div class="header-value" @mouseover="toggleHover(index, true)" @mouseleave="toggleHover(index, false)">
<pre class="removeBootStrap">{{ header.value }}</pre>
<div class="clippy-button"><CopyToClipboard v-if="header.value && hoverStates[index]" :value="header.value" :isIconOnly="true" /></div>
</div>
</template>
</div>

<!-- Message if filtered list is empty -->
<div v-if="filteredHeaders.length <= 0 && !headers.not_found" class="alert alert-warning">No headers found matching the search term.</div>
<div v-if="headers.not_found" class="alert alert-info">Could not find message headers. This could be because the message URL is invalid or the corresponding message was processed and is no longer tracked by ServiceControl.</div>
</template>

<style scoped>
.gap {
margin-top: 5px;
border-radius: 0.5rem;
padding: 0.5rem;
border: 1px solid #ccc;
background: white;
}
.removeBootStrap {
background: initial;
border: none;
Expand All @@ -86,10 +75,13 @@ const filteredHeaders = computed(() => {
max-width: 40rem;
}
.filters {
background-color: #f3f3f3;
background-color: var(--main-background);
border: #8c8c8c 1px solid;
border-radius: 3px;
padding: 5px;
position: sticky;
top: 9.7rem;
z-index: 1;
}

.header-list {
Expand All @@ -100,7 +92,7 @@ const filteredHeaders = computed(() => {
align-items: flex-start;
justify-content: center;
row-gap: 2px;
background-color: #f3f3f3;
background-color: var(--main-background);
}

.header-value,
Expand Down
130 changes: 81 additions & 49 deletions src/Frontend/src/components/messages2/MessageView.vue
Original file line number Diff line number Diff line change
Expand Up @@ -100,62 +100,64 @@ onMounted(() => {
<no-data v-else-if="state.failed_to_load" title="message failures" message="An error occurred while trying to load the message. Please check the ServiceControl logs to learn what the issue is."></no-data>
<template v-else>
<LoadingOverlay v-if="state.loading ?? false" />
<div class="row">
<div class="col-sm-12 no-side-padding">
<RouterLink :to="backLink"><i class="fa fa-chevron-left"></i> Back</RouterLink>
<div class="active break group-title">
<h1 class="message-type-title">{{ state.data.message_type }}</h1>
<div class="header-and-metadata">
<div class="row">
<div class="col-sm-12 no-side-padding">
<RouterLink :to="backLink"><i class="fa fa-chevron-left"></i> Back</RouterLink>
<div class="active break group-title">
<h1 class="message-type-title">{{ state.data.message_type }}</h1>
</div>
</div>
</div>
</div>
<div class="row">
<div class="col-sm-12 no-side-padding">
<div class="metadata group-message-count message-metadata">
<MetadataLabel v-if="state.data.failure_status.retry_in_progress" tooltip="Message is being added to the retries queue" type="info" text="Requesting retry..." />
<MetadataLabel v-if="state.data.failure_status.retried" tooltip="Message is enqueued to be retried" type="info" text="Waiting for retry" />
<MetadataLabel v-if="state.data.failure_status.restoring" tooltip="Message is being restored" type="info" text="Restoring..." />
<MetadataLabel v-if="state.data.failure_status.archiving" tooltip="Message is being deleted" type="info" text="Deleting..." />
<MetadataLabel v-if="state.data.failure_status.archived" tooltip="Message is deleted" type="warning" text="Deleted" />
<MetadataLabel v-if="state.data.failure_status.resolved" tooltip="Message was processed successfully" type="warning" text="Processed" />
<MetadataLabel
v-if="state.data.failure_metadata.number_of_processing_attempts !== undefined && state.data.failure_metadata.number_of_processing_attempts > 1"
:tooltip="`This message has already failed ${state.data.failure_metadata.number_of_processing_attempts} times`"
type="important"
:text="`${(state.data.failure_metadata.number_of_processing_attempts ?? 0) - 1} Retry Failures`"
/>
<template v-if="state.data.failure_metadata.edited">
<MetadataLabel tooltip="Message was edited" type="info" text="Edited" />
<span v-if="state.data.failure_metadata.edit_of" class="metadata metadata-link">
<i class="fa fa-history"></i> <RouterLink :to="{ path: routeLinks.messages.failedMessage.link(state.data.failure_metadata.edit_of), query: route.query }">View previous version</RouterLink>
</span>
</template>
<span v-if="state.data.failure_metadata.time_of_failure" class="metadata"><i class="fa fa-clock-o"></i> Failed: <time-since :date-utc="state.data.failure_metadata.time_of_failure"></time-since></span>
<span v-else class="metadata"><i class="fa fa-clock-o"></i> Processed at: <time-since :date-utc="state.data.processed_at"></time-since></span>
<template v-if="state.data.receiving_endpoint">
<span class="metadata"><i class="fa pa-endpoint" :style="{ filter: endpointColor }"></i> Endpoint: {{ state.data.receiving_endpoint.name }}</span>
<span class="metadata"><i class="fa fa-laptop"></i> Machine: {{ state.data.receiving_endpoint.host }}</span>
</template>
<span v-if="state.data.failure_metadata.redirect" class="metadata"><i class="fa pa-redirect-source pa-redirect-small"></i> Redirect: {{ state.data.failure_metadata.redirect }}</span>
<template v-if="state.data.failure_status.archived">
<span class="metadata"><i class="fa fa-clock-o"></i> Deleted: <time-since :date-utc="state.data.failure_metadata.last_modified"></time-since></span>
<span class="metadata danger" v-if="state.data.failure_status.delete_soon"><i class="fa fa-trash-o danger"></i> Scheduled for permanent deletion: immediately</span>
<span class="metadata danger" v-else><i class="fa fa-trash-o danger"></i> Scheduled for permanent deletion: <time-since :date-utc="state.data.failure_metadata.deleted_in"></time-since></span>
</template>
<div class="row">
<div class="col-sm-12 no-side-padding">
<div class="metadata group-message-count message-metadata">
<MetadataLabel v-if="state.data.failure_status.retry_in_progress" tooltip="Message is being added to the retries queue" type="info" text="Requesting retry..." />
<MetadataLabel v-if="state.data.failure_status.retried" tooltip="Message is enqueued to be retried" type="info" text="Waiting for retry" />
<MetadataLabel v-if="state.data.failure_status.restoring" tooltip="Message is being restored" type="info" text="Restoring..." />
<MetadataLabel v-if="state.data.failure_status.archiving" tooltip="Message is being deleted" type="info" text="Deleting..." />
<MetadataLabel v-if="state.data.failure_status.archived" tooltip="Message is deleted" type="warning" text="Deleted" />
<MetadataLabel v-if="state.data.failure_status.resolved" tooltip="Message was processed successfully" type="warning" text="Processed" />
<MetadataLabel
v-if="state.data.failure_metadata.number_of_processing_attempts !== undefined && state.data.failure_metadata.number_of_processing_attempts > 1"
:tooltip="`This message has already failed ${state.data.failure_metadata.number_of_processing_attempts} times`"
type="important"
:text="`${(state.data.failure_metadata.number_of_processing_attempts ?? 0) - 1} Retry Failures`"
/>
<template v-if="state.data.failure_metadata.edited">
<MetadataLabel tooltip="Message was edited" type="info" text="Edited" />
<span v-if="state.data.failure_metadata.edit_of" class="metadata metadata-link">
<i class="fa fa-history"></i> <RouterLink :to="{ path: routeLinks.messages.failedMessage.link(state.data.failure_metadata.edit_of), query: route.query }">View previous version</RouterLink>
</span>
</template>
<span v-if="state.data.failure_metadata.time_of_failure" class="metadata"><i class="fa fa-clock-o"></i> Failed: <time-since :date-utc="state.data.failure_metadata.time_of_failure"></time-since></span>
<span v-else class="metadata"><i class="fa fa-clock-o"></i> Processed at: <time-since :date-utc="state.data.processed_at"></time-since></span>
<template v-if="state.data.receiving_endpoint">
<span class="metadata"><i class="fa pa-endpoint" :style="{ filter: endpointColor }"></i> Endpoint: {{ state.data.receiving_endpoint.name }}</span>
<span class="metadata"><i class="fa fa-laptop"></i> Machine: {{ state.data.receiving_endpoint.host }}</span>
</template>
<span v-if="state.data.failure_metadata.redirect" class="metadata"><i class="fa pa-redirect-source pa-redirect-small"></i> Redirect: {{ state.data.failure_metadata.redirect }}</span>
<template v-if="state.data.failure_status.archived">
<span class="metadata"><i class="fa fa-clock-o"></i> Deleted: <time-since :date-utc="state.data.failure_metadata.last_modified"></time-since></span>
<span class="metadata danger" v-if="state.data.failure_status.delete_soon"><i class="fa fa-trash-o danger"></i> Scheduled for permanent deletion: immediately</span>
<span class="metadata danger" v-else><i class="fa fa-trash-o danger"></i> Scheduled for permanent deletion: <time-since :date-utc="state.data.failure_metadata.deleted_in"></time-since></span>
</template>
</div>
</div>
</div>
</div>
<div class="row">
<div class="col-sm-12 no-side-padding">
<div class="btn-toolbar message-toolbar">
<DeleteMessageButton />
<RestoreMessageButton />
<RetryMessageButton />
<EditAndRetryButton />
<ExportMessageButton />
<div class="row">
<div class="col-sm-12 no-side-padding">
<div class="btn-toolbar message-toolbar">
<DeleteMessageButton />
<RestoreMessageButton />
<RetryMessageButton />
<EditAndRetryButton />
<ExportMessageButton />
</div>
</div>
</div>
</div>
<div class="row">
<div class="row tab-contents">
<div class="col-sm-12 no-side-padding">
<TabsLayout :tabs="tabs" />
</div>
Expand All @@ -168,6 +170,36 @@ onMounted(() => {
<style scoped>
@import "../list.css";

.container,
section,
.tab-contents,
.tab-contents > div {
display: flex;
flex-direction: column;
flex: 1;
}

.container {
height: auto;
}

section,
.tab-contents,
.tab-contents > div {
max-height: 100%;
display: flex;
flex-direction: column;
min-height: 0;
flex: 1;
}

.header-and-metadata {
position: sticky;
top: -2.5rem;
z-index: 1;
background-color: var(--main-background);
}

h1.message-type-title {
margin: 0 0 8px;
font-size: 24px;
Expand Down
Loading