Skip to content

Commit 7f4a8b0

Browse files
authored
Align look and feel for all tabs (#2377)
1 parent 85abf90 commit 7f4a8b0

File tree

6 files changed

+140
-110
lines changed

6 files changed

+140
-110
lines changed

src/Frontend/src/components/CodeEditor.vue

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -59,15 +59,19 @@ const extensions = computed(() => {
5959

6060
<style scoped>
6161
.wrapper {
62+
margin-top: 5px;
6263
border-radius: 0.5rem;
6364
padding: 0.5rem;
6465
border: 1px solid #ccc;
66+
background: white;
6567
display: flex;
6668
flex-direction: column;
6769
}
6870
.toolbar {
69-
border-bottom: 1px solid #ccc;
70-
padding-bottom: 0.5rem;
71+
background-color: #f3f3f3;
72+
border: #8c8c8c 1px solid;
73+
border-radius: 3px;
74+
padding: 5px;
7175
margin-bottom: 0.5rem;
7276
display: flex;
7377
flex-direction: row;

src/Frontend/src/components/messages2/BodyView.vue

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -21,11 +21,17 @@ const body = computed(() => bodyState.value.data.value);
2121
</script>
2222

2323
<template>
24-
<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>
25-
<div v-else-if="bodyState.failed_to_load" class="alert alert-info">Message body unavailable.</div>
26-
<LoadingSpinner v-else-if="bodyState.loading" />
27-
<CodeEditor v-else-if="body !== undefined && contentType.isSupported" :model-value="body" :language="contentType.language" :read-only="true" :show-gutter="true"></CodeEditor>
28-
<div v-else class="alert alert-warning">Message body cannot be displayed because content type "{{ bodyState.data.content_type }}" is not supported.</div>
24+
<div class="gap">
25+
<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>
26+
<div v-else-if="bodyState.failed_to_load" class="alert alert-info">Message body unavailable.</div>
27+
<LoadingSpinner v-else-if="bodyState.loading" />
28+
<CodeEditor v-else-if="body !== undefined && contentType.isSupported" :model-value="body" :language="contentType.language" :read-only="true" :show-gutter="true"></CodeEditor>
29+
<div v-else class="alert alert-warning">Message body cannot be displayed because content type "{{ bodyState.data.content_type }}" is not supported.</div>
30+
</div>
2931
</template>
3032

31-
<style scoped></style>
33+
<style scoped>
34+
.gap {
35+
margin-top: 5px;
36+
}
37+
</style>

src/Frontend/src/components/messages2/FlowDiagram/FlowDiagram.vue

Lines changed: 44 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -218,44 +218,46 @@ const selectedErrorColor = hexToCSSFilter("#e8e6e8").filter;
218218
</script>
219219

220220
<template>
221-
<div v-if="store.conversationData.failed_to_load" class="alert alert-info">FlowDiagram data is unavailable.</div>
222-
<LoadingSpinner v-else-if="store.conversationData.loading" />
223-
<div v-else id="tree-container">
224-
<VueFlow :nodes="nodes" :edges="edges" :min-zoom="0.1" :max-zoom="1.2" :only-render-visible-elements="true" @nodes-initialized="layoutGraph">
225-
<Controls :show-interactive="false" position="top-left" class="controls" />
226-
<template #node-message="{ id, data }: { id: string; data: NodeData }">
227-
<TextEllipses class="address" :text="`${data.sendingEndpoint.name}@${data.sendingEndpoint.host}`" />
228-
<div class="node" :class="{ error: data.isError, 'current-message': id === store.state.data.id }">
229-
<div class="node-text">
230-
<i
231-
class="fa"
232-
:style="data.isError && id === store.state.data.id ? { filter: selectedErrorColor } : {}"
233-
:class="{ 'pa-flow-timeout': data.isTimeout, 'pa-flow-command': data.isCommand, 'pa-flow-event': data.isEvent }"
234-
v-tippy="data.type"
235-
/>
236-
<div class="typeName">
237-
<RouterLink v-if="data.isError" :to="{ path: routeLinks.messages.failedMessage.link(id), query: { back: backLink } }"><TextEllipses style="width: 204px" :text="data.label" ellipses-style="LeftSide" /></RouterLink>
238-
<RouterLink v-else :to="{ path: routeLinks.messages.successMessage.link(data.messageId, id), query: { back: backLink } }"><TextEllipses style="width: 204px" :text="data.label" ellipses-style="LeftSide" /></RouterLink>
239-
</div>
240-
<i v-if="data.isError" class="fa pa-flow-failed" :style="id !== store.state.data.id ? { filter: errorColor } : { filter: selectedErrorColor }" />
241-
<div class="time-sent">
242-
<time-since class="time-since" :date-utc="data.timeSent" />
243-
</div>
244-
<div class="sagas" v-if="data.sagaInvocations.length > 0">
245-
<div class="saga" v-for="saga in data.sagaInvocations" :key="saga.id">
246-
<i
247-
class="fa"
248-
v-tippy="saga.isSagaInitiated ? 'Message originated from Saga' : !saga.isSagaInitiated && saga.isSagaCompleted ? 'Saga Completed' : 'Saga Initiated / Updated'"
249-
:class="{ 'pa-flow-saga-initiated': saga.isSagaInitiated, 'pa-flow-saga-completed': !saga.isSagaInitiated && saga.isSagaCompleted, 'pa-flow-saga-trigger': !saga.isSagaInitiated && !saga.isSagaCompleted }"
250-
/>
251-
<div class="sagaName"><TextEllipses style="width: 182px" :text="saga.sagaType" ellipses-style="LeftSide" /></div>
221+
<div class="gap">
222+
<div v-if="store.conversationData.failed_to_load" class="alert alert-info">FlowDiagram data is unavailable.</div>
223+
<LoadingSpinner v-else-if="store.conversationData.loading" />
224+
<div v-else id="tree-container">
225+
<VueFlow :nodes="nodes" :edges="edges" :min-zoom="0.1" :max-zoom="1.2" :only-render-visible-elements="true" @nodes-initialized="layoutGraph">
226+
<Controls :show-interactive="false" position="top-left" class="controls" />
227+
<template #node-message="{ id, data }: { id: string; data: NodeData }">
228+
<TextEllipses class="address" :text="`${data.sendingEndpoint.name}@${data.sendingEndpoint.host}`" />
229+
<div class="node" :class="{ error: data.isError, 'current-message': id === store.state.data.id }">
230+
<div class="node-text">
231+
<i
232+
class="fa"
233+
:style="data.isError && id === store.state.data.id ? { filter: selectedErrorColor } : {}"
234+
:class="{ 'pa-flow-timeout': data.isTimeout, 'pa-flow-command': data.isCommand, 'pa-flow-event': data.isEvent }"
235+
v-tippy="data.type"
236+
/>
237+
<div class="typeName">
238+
<RouterLink v-if="data.isError" :to="{ path: routeLinks.messages.failedMessage.link(id), query: { back: backLink } }"><TextEllipses style="width: 204px" :text="data.label" ellipses-style="LeftSide" /></RouterLink>
239+
<RouterLink v-else :to="{ path: routeLinks.messages.successMessage.link(data.messageId, id), query: { back: backLink } }"><TextEllipses style="width: 204px" :text="data.label" ellipses-style="LeftSide" /></RouterLink>
240+
</div>
241+
<i v-if="data.isError" class="fa pa-flow-failed" :style="id !== store.state.data.id ? { filter: errorColor } : { filter: selectedErrorColor }" />
242+
<div class="time-sent">
243+
<time-since class="time-since" :date-utc="data.timeSent" />
244+
</div>
245+
<div class="sagas" v-if="data.sagaInvocations.length > 0">
246+
<div class="saga" v-for="saga in data.sagaInvocations" :key="saga.id">
247+
<i
248+
class="fa"
249+
v-tippy="saga.isSagaInitiated ? 'Message originated from Saga' : !saga.isSagaInitiated && saga.isSagaCompleted ? 'Saga Completed' : 'Saga Initiated / Updated'"
250+
:class="{ 'pa-flow-saga-initiated': saga.isSagaInitiated, 'pa-flow-saga-completed': !saga.isSagaInitiated && saga.isSagaCompleted, 'pa-flow-saga-trigger': !saga.isSagaInitiated && !saga.isSagaCompleted }"
251+
/>
252+
<div class="sagaName"><TextEllipses style="width: 182px" :text="saga.sagaType" ellipses-style="LeftSide" /></div>
253+
</div>
252254
</div>
253255
</div>
254256
</div>
255-
</div>
256-
<TextEllipses class="address" :text="`${data.receivingEndpoint.name}@${data.receivingEndpoint.host}`" />
257-
</template>
258-
</VueFlow>
257+
<TextEllipses class="address" :text="`${data.receivingEndpoint.name}@${data.receivingEndpoint.host}`" />
258+
</template>
259+
</VueFlow>
260+
</div>
259261
</div>
260262
</template>
261263

@@ -268,6 +270,13 @@ const selectedErrorColor = hexToCSSFilter("#e8e6e8").filter;
268270
<style scoped>
269271
@import "../../list.css";
270272
273+
.gap {
274+
margin-top: 5px;
275+
border-radius: 0.5rem;
276+
padding: 0.5rem;
277+
border: 1px solid #ccc;
278+
background: white;
279+
}
271280
.controls {
272281
display: flex;
273282
flex-wrap: wrap;

src/Frontend/src/components/messages2/HeadersView.vue

Lines changed: 30 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -22,35 +22,44 @@ const filteredHeaders = computed(() => {
2222
</script>
2323

2424
<template>
25-
<div>
26-
<div class="row filters">
27-
<div class="col">
28-
<div class="text-search-container">
29-
<div class="text-search">
30-
<div>
31-
<FilterInput v-model="searchTerm" :aria-label="`Search for a header key or value`" :placeholder="'Search for a header key or value...'" />
25+
<div class="gap">
26+
<div>
27+
<div class="row filters">
28+
<div class="col">
29+
<div class="text-search-container">
30+
<div class="text-search">
31+
<div>
32+
<FilterInput v-model="searchTerm" :aria-label="`Search for a header key or value`" :placeholder="'Search for a header key or value...'" />
33+
</div>
3234
</div>
3335
</div>
3436
</div>
3537
</div>
3638
</div>
37-
</div>
38-
<div class="header-list" v-if="filteredHeaders.length > 0 && !headers.not_found">
39-
<template v-for="(header, index) in filteredHeaders" :key="index">
40-
<div class="header-key">{{ header.key }}</div>
41-
<div class="header-value" @mouseover="toggleHover(index, true)" @mouseleave="toggleHover(index, false)">
42-
<pre class="removeBootStrap">{{ header.value }}</pre>
43-
<div class="clippy-button"><CopyToClipboard v-if="header.value && hoverStates[index]" :value="header.value" :isIconOnly="true" /></div>
44-
</div>
45-
</template>
46-
</div>
39+
<div class="header-list" v-if="filteredHeaders.length > 0 && !headers.not_found">
40+
<template v-for="(header, index) in filteredHeaders" :key="index">
41+
<div class="header-key">{{ header.key }}</div>
42+
<div class="header-value" @mouseover="toggleHover(index, true)" @mouseleave="toggleHover(index, false)">
43+
<pre class="removeBootStrap">{{ header.value }}</pre>
44+
<div class="clippy-button"><CopyToClipboard v-if="header.value && hoverStates[index]" :value="header.value" :isIconOnly="true" /></div>
45+
</div>
46+
</template>
47+
</div>
4748

48-
<!-- Message if filtered list is empty -->
49-
<div v-if="filteredHeaders.length <= 0 && !headers.not_found" class="alert alert-warning">No headers found matching the search term.</div>
50-
<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>
49+
<!-- Message if filtered list is empty -->
50+
<div v-if="filteredHeaders.length <= 0 && !headers.not_found" class="alert alert-warning">No headers found matching the search term.</div>
51+
<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>
52+
</div>
5153
</template>
5254

5355
<style scoped>
56+
.gap {
57+
margin-top: 5px;
58+
border-radius: 0.5rem;
59+
padding: 0.5rem;
60+
border: 1px solid #ccc;
61+
background: white;
62+
}
5463
.removeBootStrap {
5564
background: initial;
5665
border: none;
@@ -78,7 +87,6 @@ const filteredHeaders = computed(() => {
7887
}
7988
.filters {
8089
background-color: #f3f3f3;
81-
margin-top: 5px;
8290
border: #8c8c8c 1px solid;
8391
border-radius: 3px;
8492
padding: 5px;
@@ -92,6 +100,7 @@ const filteredHeaders = computed(() => {
92100
align-items: flex-start;
93101
justify-content: center;
94102
row-gap: 2px;
103+
background-color: #f3f3f3;
95104
}
96105
97106
.header-value,

src/Frontend/src/components/messages2/SagaDiagram.vue

Lines changed: 16 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@ import routeLinks from "@/router/routeLinks";
44
import { useSagaDiagramStore } from "@/stores/SagaDiagramStore";
55
import { useMessageStore } from "@/stores/MessageStore";
66
import { storeToRefs } from "pinia";
7-
import ToolbarEndpointIcon from "@/assets/Shell_ToolbarEndpoint.svg";
87
import { SagaViewModel, parseSagaUpdates } from "./SagaDiagram/SagaDiagramParser";
98
import { typeToName } from "@/composables/typeHumanizer";
109
import LoadingSpinner from "@/components/LoadingSpinner.vue";
@@ -71,11 +70,8 @@ const vm = computed<SagaViewModel>(() => {
7170
<template>
7271
<div class="saga-container">
7372
<!-- Toolbar header -->
74-
<div v-if="vm.HasSagaData" class="header">
75-
<button :class="['saga-button', { 'saga-button--active': vm.ShowMessageData }]" aria-label="show-message-data-button" @click="sagaDiagramStore.toggleMessageData">
76-
<img class="saga-button-icon" :src="ToolbarEndpointIcon" alt="" />
77-
{{ vm.ShowMessageData ? "Hide Message Data" : "Show Message Data" }}
78-
</button>
73+
<div v-if="vm.HasSagaData" class="toolbar">
74+
<button type="button" class="btn btn-secondary btn-sm" aria-label="show-message-data-button" @click="sagaDiagramStore.toggleMessageData"><i class="fa fa-list-ul"></i> {{ vm.ShowMessageData ? "Hide Message Data" : "Show Message Data" }}</button>
7975
</div>
8076

8177
<!-- Loading Spinner -->
@@ -111,16 +107,24 @@ const vm = computed<SagaViewModel>(() => {
111107
.saga-container {
112108
display: flex;
113109
flex-direction: column;
114-
/* Must validate parent height in order to set this element min-height value */
115-
min-height: 500px;
116-
background-color: #ffffff;
110+
margin-top: 5px;
111+
border-radius: 0.5rem;
112+
padding: 0.5rem;
113+
border: 1px solid #ccc;
114+
background: white;
117115
}
118116
119117
/* Main containers */
120118
121-
.header {
122-
padding: 0.5rem;
123-
border-bottom: solid 2px #ddd;
119+
.toolbar {
120+
background-color: #f3f3f3;
121+
border: #8c8c8c 1px solid;
122+
border-radius: 3px;
123+
padding: 5px;
124+
margin-bottom: 0.5rem;
125+
display: flex;
126+
flex-direction: row;
127+
min-height: 40px;
124128
}
125129
.body {
126130
display: flex;
@@ -140,30 +144,4 @@ const vm = computed<SagaViewModel>(() => {
140144
align-items: center;
141145
min-height: 200px;
142146
}
143-
144-
/* Button styles */
145-
146-
.saga-button {
147-
display: block;
148-
padding: 0.2rem 0.7rem 0.1rem;
149-
color: #555555;
150-
font-size: 0.75rem;
151-
border: solid 2px #00a3c4;
152-
background-color: #e3e4e5;
153-
}
154-
.saga-button:focus,
155-
.saga-button:hover {
156-
background-color: #daebfc;
157-
}
158-
159-
.saga-button:active,
160-
.saga-button--active {
161-
background-color: #c3dffc;
162-
}
163-
.saga-button-icon {
164-
width: 0.75rem;
165-
height: 0.75rem;
166-
margin-top: -0.2rem;
167-
margin-right: 0.25rem;
168-
}
169147
</style>

src/Frontend/src/components/messages2/SequenceDiagram.vue

Lines changed: 32 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -18,18 +18,42 @@ onMounted(() => store.refreshConversation());
1818
</script>
1919

2020
<template>
21-
<a class="help-link" target="_blank" href="https://docs.particular.net/servicepulse/sequence-diagram"><i class="fa fa-info-circle" /> Sequence Diagram Help</a>
22-
<div class="outer" @scroll="(ev) => (endpointYOffset = (ev.target as Element).scrollTop)">
23-
<svg class="sequence-diagram" :style="{ width: `max(100%, ${isNaN(maxWidth) ? 0 : maxWidth}px)` }" :height="maxHeight + 20">
24-
<Timeline />
25-
<Handlers />
26-
<Routes />
27-
<Endpoints :yOffset="endpointYOffset" />
28-
</svg>
21+
<div class="wrapper">
22+
<div class="toolbar">
23+
<a class="help-link" target="_blank" href="https://docs.particular.net/servicepulse/sequence-diagram"><i class="fa fa-info-circle" /> Sequence Diagram Help</a>
24+
</div>
25+
<div class="outer" @scroll="(ev) => (endpointYOffset = (ev.target as Element).scrollTop)">
26+
<svg class="sequence-diagram" :style="{ width: `max(100%, ${isNaN(maxWidth) ? 0 : maxWidth}px)` }" :height="maxHeight + 20">
27+
<Timeline />
28+
<Handlers />
29+
<Routes />
30+
<Endpoints :yOffset="endpointYOffset" />
31+
</svg>
32+
</div>
2933
</div>
3034
</template>
3135

3236
<style scoped>
37+
.wrapper {
38+
margin-top: 5px;
39+
border-radius: 0.5rem;
40+
padding: 0.5rem;
41+
border: 1px solid #ccc;
42+
background: white;
43+
display: flex;
44+
flex-direction: column;
45+
}
46+
.toolbar {
47+
background-color: #f3f3f3;
48+
border: #8c8c8c 1px solid;
49+
border-radius: 3px;
50+
padding: 5px;
51+
margin-bottom: 0.5rem;
52+
display: flex;
53+
flex-direction: row;
54+
justify-content: end;
55+
min-height: 40px;
56+
}
3357
.outer {
3458
max-width: 100%;
3559
max-height: calc(100vh - 27em);

0 commit comments

Comments
 (0)