22import { computed , onMounted , ref , watch } from " vue" ;
33import { useRetryEditedMessage } from " @/composables/serviceFailedMessage" ;
44import MessageHeader from " ./EditMessageHeader.vue" ;
5- import { EditAndRetryConfig } from " @/resources/Configuration" ;
65import type Header from " @/resources/Header" ;
7- import { ExtendedFailedMessage } from " @/resources/FailedMessage" ;
86import parseContentType from " @/composables/contentTypeParser" ;
97import { CodeLanguage } from " @/components/codeEditorTypes" ;
108import CodeEditor from " @/components/CodeEditor.vue" ;
9+ import { useMessageStore } from " @/stores/MessageStore" ;
10+ import { storeToRefs } from " pinia" ;
11+ import LoadingSpinner from " @/components/LoadingSpinner.vue" ;
12+ import debounce from " lodash/debounce" ;
1113
1214interface HeaderWithEditing extends Header {
1315 isLocked: boolean ;
@@ -18,13 +20,7 @@ interface HeaderWithEditing extends Header {
1820
1921const emit = defineEmits <{
2022 cancel: [];
21- retried: [];
22- }>();
23-
24- const props = defineProps <{
25- id: string ;
26- message: ExtendedFailedMessage ;
27- configuration: EditAndRetryConfig ;
23+ confirm: [];
2824}>();
2925
3026interface LocalMessageState {
@@ -46,27 +42,32 @@ const localMessage = ref<LocalMessageState>({
4642 isBodyEmpty: false ,
4743 isContentTypeSupported: false ,
4844 bodyContentType: undefined ,
49- bodyUnavailable: true ,
45+ bodyUnavailable: false ,
5046 isEvent: false ,
5147 retried: false ,
5248 headers: [],
5349 messageBody: " " ,
5450});
55- let origMessageBody: string ;
56-
5751const showEditAndRetryConfirmation = ref (false );
5852const showCancelConfirmation = ref (false );
5953const showEditRetryGenericError = ref (false );
54+ const store = useMessageStore ();
55+ const { state, headers, body, edit_and_retry_config } = storeToRefs (store );
56+ const id = computed (() => state .value .data .id ?? " " );
57+ const uneditedMessageBody = computed (() => body .value .data .value ?? " " );
58+ const regExToPruneLineEndings = new RegExp (/ [\n\r ] * / , " g" );
59+ const debounceBodyUpdate = debounce ((value : string ) => {
60+ const newValue = value .replaceAll (regExToPruneLineEndings , " " );
61+ localMessage .value .isBodyChanged = newValue !== uneditedMessageBody .value .replaceAll (regExToPruneLineEndings , " " );
62+ localMessage .value .isBodyEmpty = newValue === " " ;
63+ }, 100 );
6064
61- const id = computed (() => props .id );
62- const messageBody = computed (() => props .message .messageBody );
63-
64- watch (messageBody , (newValue ) => {
65- if (newValue !== origMessageBody ) {
66- localMessage .value .isBodyChanged = true ;
65+ watch (
66+ () => localMessage .value .messageBody ,
67+ (newValue ) => {
68+ debounceBodyUpdate (newValue );
6769 }
68- localMessage .value .isBodyEmpty = newValue === " " ;
69- });
70+ );
7071
7172function close() {
7273 emit (" cancel" );
@@ -91,24 +92,10 @@ function confirmCancel() {
9192}
9293
9394function resetBodyChanges() {
94- localMessage .value .messageBody = origMessageBody ;
95+ localMessage .value .messageBody = uneditedMessageBody . value ;
9596 localMessage .value .isBodyChanged = false ;
9697}
9798
98- function findHeadersByKey(key : string ) {
99- return localMessage .value .headers .find ((header : HeaderWithEditing ) => header .key === key );
100- }
101-
102- function getContentType() {
103- const header = findHeadersByKey (" NServiceBus.ContentType" );
104- return header ?.value ;
105- }
106-
107- function getMessageIntent() {
108- const intent = findHeadersByKey (" NServiceBus.MessageIntent" );
109- return intent ?.value ;
110- }
111-
11299function removeHeadersMarkedAsRemoved() {
113100 localMessage .value .headers = localMessage .value .headers .filter ((header : HeaderWithEditing ) => ! header .isMarkedAsRemoved );
114101}
@@ -118,59 +105,62 @@ async function retryEditedMessage() {
118105 try {
119106 await useRetryEditedMessage (id .value , localMessage );
120107 localMessage .value .retried = true ;
121- return emit (" retried " );
108+ return emit (" confirm " );
122109 } catch {
123110 showEditAndRetryConfirmation .value = false ;
124111 showEditRetryGenericError .value = true ;
125112 }
126113}
127114
128115function initializeMessageBodyAndHeaders() {
129- origMessageBody = props .message .messageBody ;
130- localMessage .value = {
116+ function getHeaderValue(key : string ) {
117+ const header = local .headers .find ((header : HeaderWithEditing ) => header .key === key );
118+ return header ?.value ;
119+ }
120+
121+ const local = <LocalMessageState >{
131122 isBodyChanged: false ,
132123 isBodyEmpty: false ,
133124 isContentTypeSupported: false ,
134125 bodyContentType: undefined ,
135- bodyUnavailable: props . message . bodyUnavailable ,
126+ bodyUnavailable: body . value . not_found ?? false ,
136127 isEvent: false ,
137- retried: props . message . retried ,
138- headers: props . message . headers .map ((header : Header ) => ({ ... header })) as HeaderWithEditing [],
139- messageBody: props . message . messageBody ,
128+ retried: state . value . data . failure_status . retried ?? false ,
129+ headers: headers . value . data .map ((header : Header ) => ({ ... header })) as HeaderWithEditing [],
130+ messageBody: body . value . data . value ?? " " ,
140131 };
141- localMessage .value .isBodyEmpty = false ;
142- localMessage .value .isBodyChanged = false ;
143132
144- const contentType = getContentType ( );
145- localMessage . value .bodyContentType = contentType ;
133+ const contentType = getHeaderValue ( " NServiceBus.ContentType " );
134+ local .bodyContentType = contentType ;
146135 const parsedContentType = parseContentType (contentType );
147- localMessage . value .isContentTypeSupported = parsedContentType .isSupported ;
148- localMessage . value .language = parsedContentType .language ;
136+ local .isContentTypeSupported = parsedContentType .isSupported ;
137+ local .language = parsedContentType .language ;
149138
150- const messageIntent = getMessageIntent ( );
151- localMessage . value .isEvent = messageIntent === " Publish" ;
139+ const messageIntent = getHeaderValue ( " NServiceBus.MessageIntent " );
140+ local .isEvent = messageIntent === " Publish" ;
152141
153- for (let index = 0 ; index < props . message . headers .length ; index ++ ) {
154- const header: HeaderWithEditing = props . message . headers [index ] as HeaderWithEditing ;
142+ for (let index = 0 ; index < headers . value . data .length ; index ++ ) {
143+ const header: HeaderWithEditing = headers . value . data [index ] as HeaderWithEditing ;
155144
156145 header .isLocked = false ;
157146 header .isSensitive = false ;
158147 header .isMarkedAsRemoved = false ;
159148 header .isChanged = false ;
160149
161- if (props . configuration .locked_headers .includes (header .key )) {
150+ if (edit_and_retry_config . value .locked_headers .includes (header .key )) {
162151 header .isLocked = true ;
163- } else if (props . configuration .sensitive_headers .includes (header .key )) {
152+ } else if (edit_and_retry_config . value .sensitive_headers .includes (header .key )) {
164153 header .isSensitive = true ;
165154 }
166155
167- localMessage . value .headers [index ] = header ;
156+ local .headers [index ] = header ;
168157 }
158+
159+ localMessage .value = local ;
169160}
170161
171162function togglePanel(panelNum : number ) {
172163 panel .value = panelNum ;
173- return false ;
174164}
175165
176166onMounted (() => {
@@ -225,14 +215,22 @@ onMounted(() => {
225215 </tr >
226216 </tbody >
227217 </table >
228- <div role =" tabpanel" v-if =" panel === 2 && !localMessage.bodyUnavailable" style =" height : calc (100% - 260px )" >
229- <div style =" margin-top : 1.25rem " >
230- <CodeEditor aria-label =" message body" :read-only =" !localMessage.isContentTypeSupported" v-model =" localMessage.messageBody" :language =" localMessage.language" :show-gutter =" true" ></CodeEditor >
218+ <template v-if =" panel === 2 " >
219+ <div role =" tabpanel" v-if =" !localMessage.bodyUnavailable" >
220+ <div style =" margin-top : 1.25rem " >
221+ <LoadingSpinner v-if =" body.loading" />
222+ <CodeEditor v-else aria-label =" message body" :read-only =" !localMessage.isContentTypeSupported" v-model =" localMessage.messageBody" :language =" localMessage.language" :show-gutter =" true" >
223+ <template #toolbarLeft >
224+ <span class =" empty-error" v-if =" localMessage.isBodyEmpty" ><i class =" fa fa-exclamation-triangle" ></i > Message body cannot be empty</span >
225+ </template >
226+ <template #toolbarRight >
227+ <button v-if =" localMessage.isBodyChanged" type =" button" class =" btn btn-secondary btn-sm" @click =" resetBodyChanges" ><i class =" fa fa-undo" ></i > Reset changes</button >
228+ </template >
229+ </CodeEditor >
230+ </div >
231231 </div >
232- <span class =" empty-error" v-if =" localMessage.isBodyEmpty" ><i class =" fa fa-exclamation-triangle" ></i > Message body cannot be empty</span >
233- <span class =" reset-body" v-if =" localMessage.isBodyChanged" ><i class =" fa fa-undo" v-tippy =" `Reset changes`" ></i > <a @click =" resetBodyChanges()" href =" javascript:void(0)" >Reset changes</a ></span >
234- <div class =" alert alert-info" v-if =" panel === 2 && localMessage.bodyUnavailable" >{{ localMessage.bodyUnavailable }}</div >
235- </div >
232+ <div role =" tabpanel" class =" alert alert-info" v-else >{{ localMessage.bodyUnavailable }}</div >
233+ </template >
236234 </div >
237235 </div >
238236 </div >
@@ -280,14 +278,6 @@ onMounted(() => {
280278 margin-right : 20px ;
281279}
282280
283- .modal-msg-editor .reset-body {
284- color : #00a3c4 ;
285- font-weight : bold ;
286- text-align : left ;
287- margin-top : 15px ;
288- display : inline-block ;
289- }
290-
291281.modal-msg-editor .reset-body a :hover {
292282 cursor : pointer ;
293283}
@@ -297,8 +287,6 @@ onMounted(() => {
297287}
298288
299289.modal-msg-editor .empty-error {
300- float : right ;
301- margin-top : 15px ;
302290 color : #ce4844 ;
303291 font-weight : bold ;
304292}
0 commit comments