Implemented REST Mock tool
Co-authored-by: widlam <mikolaj.widla@gmail.com> Co-authored-by: Adam Bem <adam.bem@zoho.eu> Reviewed-on: #231 Reviewed-by: Adam Bem <bema@noreply.example.com> Co-authored-by: Mikolaj Widla <widlam@noreply.example.com> Co-committed-by: Mikolaj Widla <widlam@noreply.example.com>
This commit is contained in:
		| @@ -36,14 +36,12 @@ public class MockController { | |||||||
|  |  | ||||||
|     /** |     /** | ||||||
|      * Updates queried message with given set of data |      * Updates queried message with given set of data | ||||||
|      * @param body {@link MockedMessageDto} json representation |      * @param message {@link MockedMessageDto} json representation | ||||||
|      * @return confirmation and 200 OK |      * @return confirmation and 200 OK | ||||||
|      */ |      */ | ||||||
|     @SneakyThrows |     @SneakyThrows | ||||||
|     @PutMapping |     @PutMapping | ||||||
|     public ResponseEntity<String> updateMessage(@RequestBody String body){ |     public ResponseEntity<String> updateMessage(@RequestBody MockedMessageDto message){ | ||||||
|         ObjectMapper mapper = new ObjectMapper(); |  | ||||||
|         MockedMessageDto message = mapper.readValue(body, MockedMessageDto.class); |  | ||||||
|         return klausService.setMockedResponse(message); |         return klausService.setMockedResponse(message); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -18,3 +18,13 @@ COPY ./nginx.conf /etc/nginx/conf.d/default.conf | |||||||
|  |  | ||||||
| EXPOSE 80 | EXPOSE 80 | ||||||
| EXPOSE 443 | EXPOSE 443 | ||||||
|  |  | ||||||
|  |  | ||||||
|  | FROM node:latest as dev | ||||||
|  | WORKDIR /app | ||||||
|  | COPY package*.json ./ | ||||||
|  | RUN npm install | ||||||
|  | ENV HOST=0.0.0.0 | ||||||
|  | COPY . . | ||||||
|  | EXPOSE 8080 | ||||||
|  | CMD ["npm", "run", "dev"] | ||||||
|   | |||||||
| @@ -18,6 +18,11 @@ server { | |||||||
|         proxy_set_header Host $host; |         proxy_set_header Host $host; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     location /api/mock { | ||||||
|  |         proxy_pass http://xmltools-mocked-services:8097/api/mock; | ||||||
|  |         proxy_set_header Host $host; | ||||||
|  |     } | ||||||
|  |  | ||||||
|     location /libxml/ { |     location /libxml/ { | ||||||
|         proxy_pass http://xmltools-libxml-backend/; |         proxy_pass http://xmltools-libxml-backend/; | ||||||
|         proxy_set_header Host $host; |         proxy_set_header Host $host; | ||||||
|   | |||||||
| @@ -3,7 +3,7 @@ | |||||||
|   "version": "0.0.0", |   "version": "0.0.0", | ||||||
|   "private": true, |   "private": true, | ||||||
|   "scripts": { |   "scripts": { | ||||||
|     "dev": "vite", |     "dev": "vite --host", | ||||||
|     "build": "run-p type-check build-only", |     "build": "run-p type-check build-only", | ||||||
|     "preview": "vite preview", |     "preview": "vite preview", | ||||||
|     "build-only": "vite build", |     "build-only": "vite build", | ||||||
|   | |||||||
| @@ -8,7 +8,7 @@ import SidebarComponent from '@components/sidebar/SidebarComponent.vue'; | |||||||
| <template> | <template> | ||||||
|   <div id="layout" class="flex h-screen bg-gradient-to-r from-white to-sky-200 dark:from-slate-800 dark:to-indigo-950"> |   <div id="layout" class="flex h-screen bg-gradient-to-r from-white to-sky-200 dark:from-slate-800 dark:to-indigo-950"> | ||||||
|     <SidebarComponent /> |     <SidebarComponent /> | ||||||
|     <div class="relative p-6 w-full m-4 bg-blue-50 dark:bg-gray-700 rounded-2xl shadow-lg"> |     <div class="relative p-6 w-full m-4 bg-blue-50 dark:bg-gray-700 rounded-2xl overflow-hidden shadow-lg"> | ||||||
|       <RouterView></RouterView> |       <RouterView></RouterView> | ||||||
|     </div> |     </div> | ||||||
|   </div> |   </div> | ||||||
|   | |||||||
							
								
								
									
										15
									
								
								Frontend/src/components/mock/BodyDetailComponent.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										15
									
								
								Frontend/src/components/mock/BodyDetailComponent.vue
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,15 @@ | |||||||
|  | <script setup lang="ts"> | ||||||
|  |  | ||||||
|  | const props = defineProps( | ||||||
|  |     { | ||||||
|  |         data: {required: true, type: String} | ||||||
|  |     } | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | </script> | ||||||
|  |  | ||||||
|  | <template> | ||||||
|  |     <span class="text-white text-center h-screen overflow-x-scroll "> | ||||||
|  |         {{ props.data.replace(/\\n/g,"") }} | ||||||
|  |     </span> | ||||||
|  | </template> | ||||||
							
								
								
									
										62
									
								
								Frontend/src/components/mock/HeadersComponent.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										62
									
								
								Frontend/src/components/mock/HeadersComponent.vue
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,62 @@ | |||||||
|  | <script setup lang="ts"> | ||||||
|  | import { ref} from 'vue'; | ||||||
|  |  | ||||||
|  | const props = defineProps( | ||||||
|  |     { | ||||||
|  |         headersObject : Object | ||||||
|  |     }  | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | const emit = defineEmits([ | ||||||
|  |     'update:httpHeaders' | ||||||
|  | ]) | ||||||
|  |  | ||||||
|  | const headerData  = ref(props.headersObject) | ||||||
|  | const newHeaderName = ref(''); | ||||||
|  | const newHeaderValue = ref(''); | ||||||
|  |  | ||||||
|  | function isHeaderEssential(headerName : string){ | ||||||
|  |     return headerName == "Keep-Alive" || headerName == "Connection" || headerName == "Date" | ||||||
|  | } | ||||||
|  |  | ||||||
|  | function setEssentialHeaderStyle(headerName : string){ | ||||||
|  |     return isHeaderEssential(headerName) ? "text-gray-400" : "tool-button text-red-400"; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | function deleteHeader(index : string){ | ||||||
|  |     if(!isHeaderEssential(index) && headerData.value != undefined){ | ||||||
|  |         delete headerData.value[index] | ||||||
|  |         emit('update:httpHeaders',headerData.value) | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | function addNewHeader(name : string, value : string){ | ||||||
|  |     if (headerData.value != undefined){ | ||||||
|  |         headerData.value[name] = value; | ||||||
|  |         newHeaderName.value = ""; | ||||||
|  |         newHeaderValue.value = ""; | ||||||
|  |         emit('update:httpHeaders',headerData.value) | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | </script> | ||||||
|  |  | ||||||
|  | <template> | ||||||
|  |     <div class="w-full gap-4 flex"> | ||||||
|  |         <div class="w-full">Header name</div> | ||||||
|  |         <div class="w-full">Header value</div> | ||||||
|  |         <div class="w-1/5"></div> | ||||||
|  |     </div> | ||||||
|  |     <div class="flex flex-col gap-4"> | ||||||
|  |         <div class="flex gap-9 flex-row" v-for="(item, index) in headerData" :key="index"> | ||||||
|  |             <input type="text" :value="index" class="text-field" /> | ||||||
|  |             <input type="text" :value="item" class="text-field" /> | ||||||
|  |             <button @click="deleteHeader(index)" class="tool-button w-1/5" :class="setEssentialHeaderStyle(index)">Remove</button> | ||||||
|  |         </div> | ||||||
|  |         <div class="flex gap-9 flex-row"> | ||||||
|  |             <input type="text" v-model="newHeaderName" class="text-field"  /> | ||||||
|  |             <input type="text" v-model="newHeaderValue" class="text-field"  /> | ||||||
|  |             <button class="tool-button w-1/5" @click="addNewHeader(newHeaderName, newHeaderValue)" >Add</button> | ||||||
|  |         </div> | ||||||
|  |     </div> | ||||||
|  | </template> | ||||||
							
								
								
									
										23
									
								
								Frontend/src/components/mock/HeadersDetailComponent.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										23
									
								
								Frontend/src/components/mock/HeadersDetailComponent.vue
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,23 @@ | |||||||
|  | <script setup lang="ts"> | ||||||
|  |  | ||||||
|  | const props = defineProps( | ||||||
|  |     { | ||||||
|  |         data: {type:String, required:true} | ||||||
|  |     } | ||||||
|  | ) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | </script> | ||||||
|  |  | ||||||
|  | <template> | ||||||
|  |     <div class="w-full text-center text-white mt-2 flex flex-col gap-4 "> | ||||||
|  |         <div class="flex flex-row gap-4">  | ||||||
|  |             <div class="w-full font-bold">Name</div>  | ||||||
|  |             <div class="w-full font-bold">Value</div>  | ||||||
|  |         </div > | ||||||
|  |         <div class="flex flex-row gap-4" v-for="(value,name) in JSON.parse(data)" :key="name"> | ||||||
|  |             <div class="w-full overflow-hidden">{{ name }}</div> | ||||||
|  |             <div class="w-full overflow-hidden">{{ value }}</div> | ||||||
|  |         </div> | ||||||
|  |     </div> | ||||||
|  | </template> | ||||||
							
								
								
									
										40
									
								
								Frontend/src/components/mock/HistoryComponent.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										40
									
								
								Frontend/src/components/mock/HistoryComponent.vue
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,40 @@ | |||||||
|  | <script setup lang="ts"> | ||||||
|  | import { ref } from 'vue'; | ||||||
|  | import HistoryRecords from './HistoryRecords.vue'; | ||||||
|  | import BodyDetailComponent from './BodyDetailComponent.vue'; | ||||||
|  | import HeadersDetailComponent from './HeadersDetailComponent.vue'; | ||||||
|  |  | ||||||
|  | const shownDetail = ref('none'); | ||||||
|  | const currentShownData = ref(''); | ||||||
|  | const currentIndex = ref(-1); | ||||||
|  |  | ||||||
|  | function showBody(body : string, index: number){ | ||||||
|  |     if( currentIndex.value == index && shownDetail.value == "body" ){ | ||||||
|  |         shownDetail.value = "none"; | ||||||
|  |     } else { | ||||||
|  |         currentIndex.value = index; | ||||||
|  |         shownDetail.value = "body"; | ||||||
|  |         currentShownData.value = body; | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | function showHeaders(headers: object, index: number){ | ||||||
|  |     if(currentIndex.value == index && shownDetail.value == "headers" ){ | ||||||
|  |         shownDetail.value = "none"; | ||||||
|  |     } else { | ||||||
|  |         currentIndex.value = index; | ||||||
|  |         shownDetail.value = "headers"; | ||||||
|  |         currentShownData.value = JSON.stringify(headers); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | </script> | ||||||
|  |  | ||||||
|  |  | ||||||
|  | <template> | ||||||
|  |     <div class="w-full xl:w-5/12 flex flex-col gap-y-4"> | ||||||
|  |     <HistoryRecords class="h-1/3 overflow-y-scroll" @click:show-headers="showHeaders" @click:show-body="showBody"></HistoryRecords> | ||||||
|  |     <BodyDetailComponent :data="currentShownData" v-if="shownDetail == 'body' "></BodyDetailComponent> | ||||||
|  |     <HeadersDetailComponent :data="currentShownData"  v-if="shownDetail == 'headers' "></HeadersDetailComponent> | ||||||
|  |     </div> | ||||||
|  | </template> | ||||||
							
								
								
									
										63
									
								
								Frontend/src/components/mock/HistoryRecords.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										63
									
								
								Frontend/src/components/mock/HistoryRecords.vue
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,63 @@ | |||||||
|  | <script setup lang="ts"> | ||||||
|  | import {ref, type Ref } from 'vue'; | ||||||
|  |  | ||||||
|  | interface historyRecord { | ||||||
|  |     clientUUID : String, | ||||||
|  |     dateTimeStamp: String, | ||||||
|  |     headers : Object, | ||||||
|  |     httpMethod: String, | ||||||
|  |     requestBody: String | ||||||
|  | } | ||||||
|  |  | ||||||
|  | const emit = defineEmits([ | ||||||
|  |     'click:showHeaders', | ||||||
|  |     'click:showBody', | ||||||
|  | ]) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | const clientUUID = localStorage.getItem("clientUUID") | ||||||
|  | const fetchLink = window.location.protocol + "//" + window.location.hostname + "/mock/api/event"; | ||||||
|  | const historyRecords : Ref<Array<historyRecord>> = ref([]) | ||||||
|  | fetch(fetchLink+"/"+clientUUID).then(response => response.json()).then(data => { historyRecords.value = data }); | ||||||
|  |  | ||||||
|  | function parseTimeStamp(timestamp : String){ | ||||||
|  |     return timestamp.substring(10,19).replace("T"," "); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | function showHeaders(headers: Object, index : number){ | ||||||
|  |     emit('click:showHeaders',headers, index) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | function showBody(body: String , index : number){ | ||||||
|  |     console.log(body) | ||||||
|  |     emit('click:showBody',body, index) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | function refreshHistory(){ | ||||||
|  |     fetch(fetchLink+"/"+clientUUID).then(response => response.json()).then(data => { historyRecords.value = data }); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | </script> | ||||||
|  |  | ||||||
|  | <template> | ||||||
|  |     <div> | ||||||
|  |         <table class="text-white h-28 w-full text-center"> | ||||||
|  |             <tr> | ||||||
|  |                 <th>Time</th> | ||||||
|  |                 <th>HTTP Method</th> | ||||||
|  |                 <th>HTTP Headers</th> | ||||||
|  |                 <th>Request Body</th> | ||||||
|  |                 <th class="text-2xl"><button @click="refreshHistory()">⟳</button></th> | ||||||
|  |             </tr> | ||||||
|  |             <tr v-for="(item , index) in historyRecords" :key="index"> | ||||||
|  |                 <td> {{ parseTimeStamp(item.dateTimeStamp) }} </td> | ||||||
|  |                 <td> {{ item.httpMethod }} </td> | ||||||
|  |                 <td> <button @click="showHeaders(item.headers, index)">Show Headers</button> </td> | ||||||
|  |                 <td>  | ||||||
|  |                     <button v-if="item.requestBody.length != 0" @click="showBody(item.requestBody, index)">Show Body</button>  | ||||||
|  |                     <span v-else>Empty Body</span> | ||||||
|  |                 </td> | ||||||
|  |             </tr> | ||||||
|  |         </table> | ||||||
|  |     </div> | ||||||
|  | </template> | ||||||
							
								
								
									
										36
									
								
								Frontend/src/components/mock/MockedMessageToastComponent.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										36
									
								
								Frontend/src/components/mock/MockedMessageToastComponent.vue
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,36 @@ | |||||||
|  | <script setup lang="ts"> | ||||||
|  | import { ref } from 'vue'; | ||||||
|  |  | ||||||
|  | const emit = defineEmits([ | ||||||
|  |     'closed:toast_closed', | ||||||
|  | ]) | ||||||
|  |  | ||||||
|  | const props = defineProps( | ||||||
|  |     { | ||||||
|  |         message: {type: String, required: true}, | ||||||
|  |         visible: {type: String, required: true}, | ||||||
|  |     } | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | function hideToast(){ | ||||||
|  |     emit('closed:toast_closed',"hidden") | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  | </script> | ||||||
|  |  | ||||||
|  |  | ||||||
|  | <template> | ||||||
|  |     <div id="toast-success" class="transition-opacity duration-1000 flex items-center w-full max-w-xs p-4 mb-4 text-gray-500 bg-white rounded-lg shadow dark:text-gray-400 dark:bg-gray-800 " :class="visible" role="alert"> | ||||||
|  |     <div class="inline-flex items-center justify-center flex-shrink-0 w-8 h-8 text-green-500 bg-green-100 rounded-lg dark:bg-green-800 dark:text-green-200"> | ||||||
|  |         <svg aria-hidden="true" class="w-5 h-5" fill="currentColor" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M16.707 5.293a1 1 0 010 1.414l-8 8a1 1 0 01-1.414 0l-4-4a1 1 0 011.414-1.414L8 12.586l7.293-7.293a1 1 0 011.414 0z" clip-rule="evenodd"></path></svg> | ||||||
|  |         <span class="sr-only">Check icon</span> | ||||||
|  |     </div> | ||||||
|  |     <div class="ml-3 text-sm font-normal">{{ props.message }}</div> | ||||||
|  |     <button @click="hideToast"  type="button" class="ml-auto -mx-1.5 -my-1.5 bg-white text-gray-400 hover:text-gray-900 rounded-lg focus:ring-2 focus:ring-gray-300 p-1.5 hover:bg-gray-100 inline-flex h-8 w-8 dark:text-gray-500 dark:hover:text-white dark:bg-gray-800 dark:hover:bg-gray-700"> | ||||||
|  |         <span class="sr-only">Close</span> | ||||||
|  |         <svg aria-hidden="true" class="w-5 h-5" fill="currentColor" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M4.293 4.293a1 1 0 011.414 0L10 8.586l4.293-4.293a1 1 0 111.414 1.414L11.414 10l4.293 4.293a1 1 0 01-1.414 1.414L10 11.414l-4.293 4.293a1 1 0 01-1.414-1.414L8.586 10 4.293 5.707a1 1 0 010-1.414z" clip-rule="evenodd"></path></svg> | ||||||
|  |     </button> | ||||||
|  |     </div> | ||||||
|  | </template> | ||||||
| @@ -1,10 +0,0 @@ | |||||||
| <script setup lang="ts"> |  | ||||||
|  |  | ||||||
|  |  | ||||||
| </script> |  | ||||||
|  |  | ||||||
| <template> |  | ||||||
|   <h1>RestMock</h1> |  | ||||||
| </template> |  | ||||||
|  |  | ||||||
| <style scoped></style> |  | ||||||
							
								
								
									
										72
									
								
								Frontend/src/components/mock/RestMockMessageComponent.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										72
									
								
								Frontend/src/components/mock/RestMockMessageComponent.vue
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,72 @@ | |||||||
|  | <script setup lang="ts"> | ||||||
|  | import {ref, type Ref} from 'vue'; | ||||||
|  | import HeadersComponent from './HeadersComponent.vue'; | ||||||
|  | import SaveComponent from './SaveComponent.vue'; | ||||||
|  |  | ||||||
|  | const clientUUID = ref(''); | ||||||
|  | const host = window.location.protocol + "//" + window.location.hostname + "/mock"; | ||||||
|  | const mockMessageLink = ref("www.google.com"); | ||||||
|  |  | ||||||
|  | interface mockedMessageData { | ||||||
|  |   clientUUID: string; | ||||||
|  |   contentType: string; | ||||||
|  |   messageBody: string; | ||||||
|  |   httpHeaders: object; | ||||||
|  |   httpStatus: number; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | const exampleData : mockedMessageData = { | ||||||
|  |   clientUUID : "exampleUUID", | ||||||
|  |   contentType: "application/json", | ||||||
|  |   messageBody: "hello", | ||||||
|  |   httpHeaders: {Connection:"keep-alive"}, | ||||||
|  |   httpStatus: 200, | ||||||
|  | } | ||||||
|  |  | ||||||
|  | let messageData : Ref<mockedMessageData> = ref(exampleData); | ||||||
|  | if ( localStorage.clientUUID != undefined ){ | ||||||
|  |     clientUUID.value = localStorage.clientUUID; | ||||||
|  | } | ||||||
|  | fetch(host + '/api/mock/' + clientUUID.value).then( response => response.json() ).then(data => {putDataInFields(data);  }); | ||||||
|  |  | ||||||
|  | function putDataInFields(data: mockedMessageData){ | ||||||
|  |   clientUUID.value = data.clientUUID; | ||||||
|  |   localStorage.clientUUID = clientUUID.value | ||||||
|  |   mockMessageLink.value = host.replace("/mock","/api/mock")+"/r/"+clientUUID.value | ||||||
|  |   messageData = ref( data ) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | </script> | ||||||
|  |  | ||||||
|  | <template> | ||||||
|  |   <div class="flex flex-col w-full xl:w-3/5 text-center dark:text-white gap-6"> | ||||||
|  |     <div> | ||||||
|  |       <label for="link">Link</label><br/> | ||||||
|  |       <div class="flex gap-4"> | ||||||
|  |         <div class="p-2 w-full border-slate-400 border-2 rounded-lg"> | ||||||
|  |           <a class="underline" :href="mockMessageLink">{{ mockMessageLink }}</a> | ||||||
|  |         </div> | ||||||
|  |         <SaveComponent v-bind:message-data="messageData"></SaveComponent> | ||||||
|  |       </div> | ||||||
|  |     </div> | ||||||
|  |     <div class="flex flex-row w-full gap-64"> | ||||||
|  |       <div class="w-full"> | ||||||
|  |         <label for="contentType">Content Type</label><br/> | ||||||
|  |         <input  class="text-field" id="contentType" type="text" v-model="messageData.contentType"/> | ||||||
|  |       </div> | ||||||
|  |        | ||||||
|  |       <div class="w-full"> | ||||||
|  |         <label for="httpStatus">HttpStatus</label><br/> | ||||||
|  |         <input class="text-field" id="httpStatus" type="text" v-model="messageData.httpStatus"/> | ||||||
|  |       </div> | ||||||
|  |        | ||||||
|  |     </div> | ||||||
|  |     <div class="flex flex-col"> | ||||||
|  |       <label for="messageBody">Body</label> | ||||||
|  |       <textarea class="text-field h-64" id="messageBody" v-model="messageData.messageBody"></textarea> | ||||||
|  |     </div> | ||||||
|  |     <HeadersComponent @update:httpHeaders="(newHeaders: object) => {messageData.httpHeaders = newHeaders }" :key="JSON.stringify(messageData.httpHeaders)" :headers-object="messageData.httpHeaders"></HeadersComponent> | ||||||
|  |   </div> | ||||||
|  | </template> | ||||||
|  |  | ||||||
|  | <style scoped></style> | ||||||
							
								
								
									
										46
									
								
								Frontend/src/components/mock/SaveComponent.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										46
									
								
								Frontend/src/components/mock/SaveComponent.vue
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,46 @@ | |||||||
|  | <script setup lang="ts"> | ||||||
|  | import { ref } from 'vue'; | ||||||
|  | import MockedMessageToastComponent from './MockedMessageToastComponent.vue'; | ||||||
|  |  | ||||||
|  |  | ||||||
|  | const props = defineProps( | ||||||
|  |     { | ||||||
|  |     messageData : {type: Object, required:true} | ||||||
|  |     } | ||||||
|  | ) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | const message = ref(''); | ||||||
|  | const visible = ref('hidden'); | ||||||
|  | const fetchLink = window.location.protocol + "//" + window.location.hostname + "/mock/api/mock" | ||||||
|  |  | ||||||
|  | function prepareAndSendData(){ | ||||||
|  |     if (props.messageData != null|| props.messageData != undefined ){ | ||||||
|  |         fetch(fetchLink, { method: "put", body:JSON.stringify(props.messageData), headers: { "Content-Type" : "application/json" }}) | ||||||
|  |         .then( response => response.text() ) | ||||||
|  |         .then( data =>  {message.value = data} ) | ||||||
|  |         .catch(exception => {message.value = exception}) | ||||||
|  |  | ||||||
|  |         showToast(); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | function showToast(){ | ||||||
|  |     visible.value = "visible"; | ||||||
|  |     setTimeout( () => { visible.value = "opacity-0" } , 1500 ) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | function hideToast(){ | ||||||
|  |     visible.value = "hidden"; | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | </script> | ||||||
|  |  | ||||||
|  | <template> | ||||||
|  |     <button @click="prepareAndSendData()" class="w-2/12 tool-button">Save</button> | ||||||
|  |  | ||||||
|  |     <div class="fixed bottom-5 right-12"> | ||||||
|  |         <MockedMessageToastComponent @closed:toast_closed="hideToast()" v-bind:visible="visible" v-bind:message="message"/> | ||||||
|  |     </div> | ||||||
|  | </template> | ||||||
| @@ -44,6 +44,6 @@ function canBeFormatted() { | |||||||
|                 <button class="tool-button" @click="clear">Clear</button> |                 <button class="tool-button" @click="clear">Clear</button> | ||||||
|             </div> |             </div> | ||||||
|         </div> |         </div> | ||||||
|         <textarea id="xmlField" v-model="data" @input="sendValue()" class="text-field"></textarea> |         <textarea id="xmlField" v-model="data" @input="sendValue()" class="text-field h-full"></textarea> | ||||||
|     </div> |     </div> | ||||||
| </template> | </template> | ||||||
| @@ -47,6 +47,11 @@ const routes = [ | |||||||
|     name: 'xslt', |     name: 'xslt', | ||||||
|     component: () => xsltTool |     component: () => xsltTool | ||||||
|   }, |   }, | ||||||
|  |   { | ||||||
|  |     path: '/rest/mock', | ||||||
|  |     name: 'restmock', | ||||||
|  |     component: () => restMock | ||||||
|  |   } | ||||||
| ] | ] | ||||||
|  |  | ||||||
|  |  | ||||||
|   | |||||||
| @@ -3,9 +3,9 @@ | |||||||
| @tailwind utilities; | @tailwind utilities; | ||||||
|  |  | ||||||
| .tool-button { | .tool-button { | ||||||
|     @apply py-1 px-4 rounded-full w-fit bg-gradient-to-r from-blue-400 to-blue-300 dark:text-white dark:from-sky-600 dark:to-sky-800 hover:bg-blue-400 |     @apply py-1 px-4 rounded-full bg-gradient-to-r from-blue-300 to-sky-200  dark:text-white dark:from-sky-600 dark:to-sky-800 hover:bg-blue-400 | ||||||
| } | } | ||||||
|  |  | ||||||
| .text-field { | .text-field { | ||||||
|     @apply w-full h-full resize-none font-mono bg-white dark:text-slate-100 dark:bg-gray-600 border border-slate-400 p-2 rounded-md |     @apply w-full font-mono dark:text-slate-100 dark:bg-gray-600 border border-slate-400 p-2 rounded-lg | ||||||
| } | } | ||||||
| @@ -31,6 +31,6 @@ function clear() { | |||||||
|                 <JsonButtonFormatterComponent :json="json" @update:result="(data: any) => format(data)"></JsonButtonFormatterComponent> |                 <JsonButtonFormatterComponent :json="json" @update:result="(data: any) => format(data)"></JsonButtonFormatterComponent> | ||||||
|             </div> |             </div> | ||||||
|         </div> |         </div> | ||||||
|         <textarea name="data" id="data" :value="json" class="text-field"></textarea> |         <textarea name="data" id="data" :value="json" class="text-field h-full"></textarea> | ||||||
|     </div> |     </div> | ||||||
| </template> | </template> | ||||||
| @@ -1,14 +1,14 @@ | |||||||
| <script lang="ts"> | <script setup lang="ts"> | ||||||
| import RestMockComponent from '@components/mock/RestMockComponent.vue' | import RestMockMessageComponent from '@components/mock/RestMockMessageComponent.vue' | ||||||
|  | import HistoryComponent from '@components/mock/HistoryComponent.vue' | ||||||
|  |  | ||||||
| export default { |  | ||||||
|     name:"RestMockView", |  | ||||||
|     components: {RestMockComponent} |  | ||||||
| } |  | ||||||
| </script> | </script> | ||||||
|  |  | ||||||
|  |  | ||||||
| <template> | <template> | ||||||
|     <RestMockComponent></RestMockComponent> |     <div class="flex flex-col xl:flex-row gap-6 w-full overflow-hidden h-full"> | ||||||
|  |         <RestMockMessageComponent></RestMockMessageComponent> | ||||||
|  |         <HistoryComponent></HistoryComponent> | ||||||
|  |     </div> | ||||||
| </template> | </template> | ||||||
|  |  | ||||||
|   | |||||||
| @@ -31,6 +31,6 @@ function clear() { | |||||||
|                 <XMLButtonFormatterComponent :xml="xml" @update:result="(data: any) => format(data)"></XMLButtonFormatterComponent> |                 <XMLButtonFormatterComponent :xml="xml" @update:result="(data: any) => format(data)"></XMLButtonFormatterComponent> | ||||||
|             </div> |             </div> | ||||||
|         </div> |         </div> | ||||||
|         <textarea name="data" id="data" :value="xml" class="text-field"></textarea> |         <textarea name="data" id="data" :value="xml" class="text-field h-full"></textarea> | ||||||
|     </div> |     </div> | ||||||
| </template> | </template> | ||||||
| @@ -8,6 +8,27 @@ export default defineConfig({ | |||||||
|   plugins: [ |   plugins: [ | ||||||
|     vue(), |     vue(), | ||||||
|   ], |   ], | ||||||
|  |   server:{ | ||||||
|  |     port: 80, | ||||||
|  |     host: '0.0.0.0', | ||||||
|  |     proxy : { | ||||||
|  |       '/java': { | ||||||
|  |         target:'http://xmltools-backend:8081/', | ||||||
|  |         rewrite: (path) => path.replace(/^\/java/, ''), | ||||||
|  |       }, | ||||||
|  |       '/libxml': { | ||||||
|  |         target:'http://xmltools-libxml-backend/', | ||||||
|  |         rewrite: (path) => path.replace(/^\/libxml/, ''),  | ||||||
|  |       }, | ||||||
|  |       '/mock': { | ||||||
|  |         target:'http://xmltools-mocked-services:8097/', | ||||||
|  |         rewrite: (path) => path.replace(/^\/mock/, ''), | ||||||
|  |       }, | ||||||
|  |       '/api/mock': { | ||||||
|  |         target: 'http://xmltools-mocked-services:8097/' | ||||||
|  |       } | ||||||
|  |     }, | ||||||
|  |   }, | ||||||
|   resolve: { |   resolve: { | ||||||
|     alias: { |     alias: { | ||||||
|       '@': fileURLToPath(new URL('./src', import.meta.url)), |       '@': fileURLToPath(new URL('./src', import.meta.url)), | ||||||
|   | |||||||
							
								
								
									
										1
									
								
								dev.sh
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										1
									
								
								dev.sh
									
									
									
									
									
										Executable file
									
								
							| @@ -0,0 +1 @@ | |||||||
|  | docker-compose -f docker-compose.dev.yml  up --build | ||||||
							
								
								
									
										75
									
								
								docker-compose.dev.yml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										75
									
								
								docker-compose.dev.yml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,75 @@ | |||||||
|  | version: "3" | ||||||
|  |  | ||||||
|  | services: | ||||||
|  |     redis: | ||||||
|  |         container_name: xmltools-redis | ||||||
|  |         build: ./Redis | ||||||
|  |         restart: "no" | ||||||
|  |  | ||||||
|  |     xmltools-frontend: | ||||||
|  |         build:  | ||||||
|  |           context: ./Frontend | ||||||
|  |           target: dev | ||||||
|  |         container_name: xmltools-frontend | ||||||
|  |         image: xmltools-frontend | ||||||
|  |         ports: | ||||||
|  |             - 80:80 | ||||||
|  |         volumes: | ||||||
|  |             - ./Frontend:/app | ||||||
|  |             - /app/node_modules | ||||||
|  |     xmltools-backend: | ||||||
|  |         build: ./Backend/tools-services | ||||||
|  |         container_name: xmltools-backend | ||||||
|  |         image: xmltools-backend | ||||||
|  |         ports: | ||||||
|  |             - 8081:8081 | ||||||
|  |  | ||||||
|  |     xmltools-libxml-backend: | ||||||
|  |         build: ./Backend-libXML | ||||||
|  |         container_name: xmltools-libxml-backend | ||||||
|  |         image: xmltools-libxml-backend | ||||||
|  |         ports: | ||||||
|  |             - 8082:80 | ||||||
|  |  | ||||||
|  |     xmltools-mocked-services: | ||||||
|  |         build: | ||||||
|  |             context: ./Backend/mocked-services | ||||||
|  |             dockerfile: Dockerfile | ||||||
|  |         container_name: xmltools-mocked-services | ||||||
|  |         restart: "no" | ||||||
|  |         ports: | ||||||
|  |             - "8097:8097" | ||||||
|  |         depends_on: | ||||||
|  |             - redis | ||||||
|  |         environment: | ||||||
|  |             SPRING_PROFILES_ACTIVE: DEV | ||||||
|  |             TZ: Europe/Warsaw | ||||||
|  |  | ||||||
|  |     swagger: | ||||||
|  |         image: "swaggerapi/swagger-ui:latest" | ||||||
|  |         container_name: xmltools-swagger | ||||||
|  |         ports: | ||||||
|  |             - "8000:8080" | ||||||
|  |         environment: | ||||||
|  |             - BASE_URL=/swagger | ||||||
|  |             - SWAGGER_JSON=/Swagger/swagger.json | ||||||
|  |         volumes: | ||||||
|  |             - ./Swagger:/Swagger | ||||||
|  |  | ||||||
|  |     filebeat: | ||||||
|  |         build: ./Filebeat | ||||||
|  |         container_name: xmltools-filebeat | ||||||
|  |         user: root | ||||||
|  |         volumes: | ||||||
|  |             - "./Filebeat/filebeat.docker.yml:/usr/share/filebeat/filebeat.yml:ro" | ||||||
|  |             - "/var/lib/docker/containers:/var/lib/docker/containers:ro" | ||||||
|  |             - "/var/run/docker.sock:/var/run/docker.sock:ro" | ||||||
|  |         environment: | ||||||
|  |             - ENV_TYPE | ||||||
|  |         command: | ||||||
|  |             - "-e" | ||||||
|  |             - "--strict.perms=false" | ||||||
|  |  | ||||||
|  | networks: | ||||||
|  |     default: | ||||||
|  |         name: tools_network | ||||||
| @@ -7,7 +7,9 @@ services: | |||||||
|         restart: "no" |         restart: "no" | ||||||
|  |  | ||||||
|     xmltools-frontend: |     xmltools-frontend: | ||||||
|         build: ./Frontend |         build: | ||||||
|  |             context: ./Frontend | ||||||
|  |             target: production-stage | ||||||
|         container_name: xmltools-frontend |         container_name: xmltools-frontend | ||||||
|         image: xmltools-frontend |         image: xmltools-frontend | ||||||
|         ports: |         ports: | ||||||
|   | |||||||
| @@ -41,6 +41,9 @@ within created container. | |||||||
|  |  | ||||||
| ## How to run | ## How to run | ||||||
|  |  | ||||||
|  | Dev server(with hot-reload frontend): docker-compose -f docker-compose.dev.yml  up --build | ||||||
|  | Prod: docker-compose up --build | ||||||
|  |  | ||||||
| ### Localy | ### Localy | ||||||
| In order to run application use | In order to run application use | ||||||
| ```aidl | ```aidl | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user