diff --git a/ApiTestManager/src/APITester.js b/ApiTestManager/src/APITester.js index a2b4a88..763ec9a 100644 --- a/ApiTestManager/src/APITester.js +++ b/ApiTestManager/src/APITester.js @@ -66,7 +66,7 @@ class APITester { return this.servers.filter(server => server.id == serverId)[0].basePath; // == : 타입 비교 없이 값만 비교 } - apiRequestTemplate(apiRequest, index) { + httpApiRequestTemplate(apiRequest, index) { return `
${apiRequest.collectionName} > ${apiRequest.name}
@@ -226,6 +226,106 @@ class APITester { `; } + tcpApiRequestTemplate(apiRequest, index) { + return ` +
+
${apiRequest.collectionName} > ${apiRequest.name}
+
+
+ ${this.renderServers(apiRequest.server)} + +
+ + +
+
+
+ +
+
+
+ +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Response + + + +
+ +
+
+
+
+
+
+
+
+
+
+
+ + `; + } + headerTemplate(header, index) { return ` @@ -555,53 +655,47 @@ class APITester { let apiRequestTabContent = $(this.apiTabContentTarget); let model = this.apiRequests[index]; - apiRequestTabContent.append(this.apiRequestTemplate(model, index)); - - let editableInput = new EditableInput({ - name: 'path', - value: model.path - }); - - let queryParamTable = new PropertyTable({ - propertyName: 'queryParams', - properties: model.queryParams - }); - - let headerTable = new PropertyTable({ - propertyName: 'headers', - properties: model.headers - }); - - queryParamTable.init(apiRequestTabContent.find(`#api_request_${model.id}`).find('.query_params')[0], (properties) => { - model.queryParams = properties; - console.log(model.queryParams); - this.buildPath(model); - editableInput.setValue(model.path); - $('span.variable').off('mouseover'); - $('span.variable').off('mouseout'); - document.querySelectorAll('span.variable').forEach(element => { - let text = element.innerText; - element.addEventListener('mouseover', () => me.showPopper(element, text)); - element.addEventListener('mouseout', () => me.hidePopper(element)); + if (model.type ==='HTTP'){ + apiRequestTabContent.append(this.httpApiRequestTemplate(model, index)); + let editableInput = new EditableInput({ + name: 'path', + value: model.path }); - }); - headerTable.init(apiRequestTabContent.find(`#api_request_${model.id}`).find('.request_headers')[0], (properties) => { - model.headers = properties; - $('span.variable').off('mouseover'); - $('span.variable').off('mouseout'); - document.querySelectorAll('span.variable').forEach(element => { - let text = element.innerText; - element.addEventListener('mouseover', () => me.showPopper(element, text)); - element.addEventListener('mouseout', () => me.hidePopper(element)); + let queryParamTable = new PropertyTable({ + propertyName: 'queryParams', + properties: model.queryParams }); - }); - apiRequestTabContent.find(`#api_request_${model.id}`).find('.api_request_info').find('.path').each(function() { - editableInput.init(this, (value) => { - model.path = value; - model.queryParams = me.parseParam(model.path); - queryParamTable.setProperties(model.queryParams); + let headerTable = new PropertyTable({ + propertyName: 'headers', + properties: model.headers + }); + + apiRequestTabContent.find(`#api_request_${model.id}`).find('.api_request_info').find('.path').each(function() { + editableInput.init(this, (value) => { + model.path = value; + model.queryParams = me.parseParam(model.path); + queryParamTable.setProperties(model.queryParams); + $('span.variable').off('mouseover'); + $('span.variable').off('mouseout'); + document.querySelectorAll('span.variable').forEach(element => { + let text = element.innerText; + element.addEventListener('mouseover', () => me.showPopper(element, text)); + element.addEventListener('mouseout', () => me.hidePopper(element)); + }); + }); + + $(this).append(``); + + $('span.variable').off('mouseover'); + $('span.variable').off('mouseout'); + }); + queryParamTable.init(apiRequestTabContent.find(`#api_request_${model.id}`).find('.query_params')[0], (properties) => { + model.queryParams = properties; + console.log(model.queryParams); + this.buildPath(model); + editableInput.setValue(model.path); $('span.variable').off('mouseover'); $('span.variable').off('mouseout'); document.querySelectorAll('span.variable').forEach(element => { @@ -611,14 +705,23 @@ class APITester { }); }); - $(this).append(``); + headerTable.init(apiRequestTabContent.find(`#api_request_${model.id}`).find('.request_headers')[0], (properties) => { + model.headers = properties; + $('span.variable').off('mouseover'); + $('span.variable').off('mouseout'); + document.querySelectorAll('span.variable').forEach(element => { + let text = element.innerText; + element.addEventListener('mouseover', () => me.showPopper(element, text)); + element.addEventListener('mouseout', () => me.hidePopper(element)); + }); + }); + } - $('span.variable').off('mouseover'); - $('span.variable').off('mouseout'); - }); + if (model.type ==='TCP'){ + apiRequestTabContent.append(this.tcpApiRequestTemplate(model, index)); + } document.querySelectorAll('.variable').forEach(element => { - let text = element.innerText; element.addEventListener('mouseover', () => me.showPopper(element, text)); element.addEventListener('mouseout', () => me.hidePopper(element)); @@ -626,10 +729,11 @@ class APITester { this.openTab(model.id); let target = $('#api_request_' + model.id); + let language = model.type ==='TCP'? 'text': 'json'; let requestBodyEditor = monaco.editor.create(target.find('.request_body')[0], { value: model.requestBody, - language: 'json', + language: language, automaticLayout: true }); @@ -665,7 +769,7 @@ class APITester { let responseBodyEditor = monaco.editor.create(target.find('.response_body')[0], { value: '', - language: 'json', + language: language, automaticLayout: true, quickSuggestions: false }); @@ -1076,6 +1180,10 @@ class APITester { if (newApiName === '') { newApiName = '새로운 API'; } + let newApiType = $('#new_api_type').val(); + if (newApiType === '') { + newApiType = 'HTTP'; + } const collection = this.collections.filter(function(collection) { return collection.id === collectionId; @@ -1087,6 +1195,7 @@ class APITester { method: 'GET', name: newApiName, path: '', + type : newApiType, headers: [], queryParams: [], requestBody: '', diff --git a/src/main/java/com/eactive/testmaster/client/controller/ApiClientController.java b/src/main/java/com/eactive/testmaster/client/controller/ApiClientController.java index 6503102..78e7cbc 100644 --- a/src/main/java/com/eactive/testmaster/client/controller/ApiClientController.java +++ b/src/main/java/com/eactive/testmaster/client/controller/ApiClientController.java @@ -2,23 +2,23 @@ package com.eactive.testmaster.client.controller; import com.eactive.testmaster.client.dto.ApiRequestDTO; import com.eactive.testmaster.client.dto.ApiResponse; -import com.eactive.testmaster.client.service.NettyApiClient; +import com.eactive.testmaster.client.service.ApiClient; +import com.eactive.testmaster.client.service.ApiClientFactory; +import java.util.concurrent.ExecutionException; import org.springframework.validation.BindingResult; import org.springframework.validation.Validator; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RestController; -import java.util.concurrent.ExecutionException; - @RestController public class ApiClientController { - private final NettyApiClient nettyApiClient; + private final ApiClientFactory apiClientFactory; private final Validator validator; - public ApiClientController(NettyApiClient nettyApiClient, Validator validator) { - this.nettyApiClient = nettyApiClient; + public ApiClientController(ApiClientFactory apiClientFactory, Validator validator) { + this.apiClientFactory = apiClientFactory; this.validator = validator; } @@ -31,6 +31,8 @@ public class ApiClientController { throw new IllegalArgumentException(bindingResult.getAllErrors().get(0).getDefaultMessage()); } - return nettyApiClient.handleRequest(request).get(); + ApiClient client = apiClientFactory.getClient(request); + return client.handleRequest(request).get(); } + } diff --git a/src/main/java/com/eactive/testmaster/client/dto/ApiRequestDTO.java b/src/main/java/com/eactive/testmaster/client/dto/ApiRequestDTO.java index 27d9978..a939a66 100644 --- a/src/main/java/com/eactive/testmaster/client/dto/ApiRequestDTO.java +++ b/src/main/java/com/eactive/testmaster/client/dto/ApiRequestDTO.java @@ -16,6 +16,8 @@ public class ApiRequestDTO implements Serializable { private String path; private String method; + private String type; + @NotNull(message = "서버를 선택해주세요.") private Long server; @@ -69,6 +71,14 @@ public class ApiRequestDTO implements Serializable { return method; } + public String getType() { + return type; + } + + public void setType(String type) { + this.type = type; + } + public void setMethod(String method) { this.method = method; } @@ -121,11 +131,11 @@ public class ApiRequestDTO implements Serializable { this.postRequestScript = postRequestScript; } - public long getSentBytes() { - return sentBytes; - } - - public void setSentBytes(long sentBytes) { - this.sentBytes = sentBytes; - } +// public long getSentBytes() { +// return sentBytes; +// } +// +// public void setSentBytes(long sentBytes) { +// this.sentBytes = sentBytes; +// } } diff --git a/src/main/java/com/eactive/testmaster/client/entity/ApiRequestInfo.java b/src/main/java/com/eactive/testmaster/client/entity/ApiRequestInfo.java index 9330589..7ff572d 100644 --- a/src/main/java/com/eactive/testmaster/client/entity/ApiRequestInfo.java +++ b/src/main/java/com/eactive/testmaster/client/entity/ApiRequestInfo.java @@ -28,6 +28,8 @@ public class ApiRequestInfo { private String path; + private String type; //API TYPE : HTTP, TCP + @Lob private String headers; @@ -143,6 +145,14 @@ public class ApiRequestInfo { this.postRequestScript = postRequestScript; } + public String getType() { + return type; + } + + public void setType(String type) { + this.type = type; + } + @Override public boolean equals(Object o) { if (this == o) return true; diff --git a/src/main/java/com/eactive/testmaster/client/service/ApiClient.java b/src/main/java/com/eactive/testmaster/client/service/ApiClient.java new file mode 100644 index 0000000..9223f1b --- /dev/null +++ b/src/main/java/com/eactive/testmaster/client/service/ApiClient.java @@ -0,0 +1,11 @@ +package com.eactive.testmaster.client.service; + + +import com.eactive.testmaster.client.dto.ApiRequestDTO; +import com.eactive.testmaster.client.dto.ApiResponse; +import java.util.concurrent.CompletableFuture; + +public interface ApiClient { + + CompletableFuture handleRequest(ApiRequestDTO apiRequest); +} diff --git a/src/main/java/com/eactive/testmaster/client/service/ApiClientFactory.java b/src/main/java/com/eactive/testmaster/client/service/ApiClientFactory.java new file mode 100644 index 0000000..886ee2a --- /dev/null +++ b/src/main/java/com/eactive/testmaster/client/service/ApiClientFactory.java @@ -0,0 +1,27 @@ +package com.eactive.testmaster.client.service; + +import com.eactive.testmaster.client.dto.ApiRequestDTO; +import org.springframework.stereotype.Service; + +@Service +public class ApiClientFactory { + + private final NettyHttpApiClient httpApiClient; + private final NettyTcpApiClient tcpApiClient; + + public ApiClientFactory(NettyHttpApiClient httpApiClient, NettyTcpApiClient tcpApiClient) { + this.httpApiClient = httpApiClient; + this.tcpApiClient = tcpApiClient; + } + + public ApiClient getClient(ApiRequestDTO request) { + switch (request.getType().toUpperCase()) { + case "HTTP": + return httpApiClient; + case "TCP": + return tcpApiClient; + default: + throw new IllegalArgumentException("Unsupported client type: " + request.getType()); + } + } +} diff --git a/src/main/java/com/eactive/testmaster/client/service/ApiRequestMigrationService.java b/src/main/java/com/eactive/testmaster/client/service/ApiRequestMigrationService.java index 294d2d4..d65a24e 100644 --- a/src/main/java/com/eactive/testmaster/client/service/ApiRequestMigrationService.java +++ b/src/main/java/com/eactive/testmaster/client/service/ApiRequestMigrationService.java @@ -46,10 +46,9 @@ public class ApiRequestMigrationService { } apiRequestRepository.findAll().forEach(apiRequest -> { - - apiRequest.setHeaders(apiRequest.getHeaders().replace("=", "::")); - apiRequest.setQueryParams(apiRequest.getQueryParams().replace("=", "::")); - + if(apiRequest.getType() == null){ + apiRequest.setType("HTTP"); + } apiRequestRepository.save(apiRequest); }); diff --git a/src/main/java/com/eactive/testmaster/client/service/NettyApiClient.java b/src/main/java/com/eactive/testmaster/client/service/NettyHttpApiClient.java similarity index 75% rename from src/main/java/com/eactive/testmaster/client/service/NettyApiClient.java rename to src/main/java/com/eactive/testmaster/client/service/NettyHttpApiClient.java index a320a69..c85d817 100644 --- a/src/main/java/com/eactive/testmaster/client/service/NettyApiClient.java +++ b/src/main/java/com/eactive/testmaster/client/service/NettyHttpApiClient.java @@ -30,8 +30,9 @@ import javax.net.ssl.SSLException; import java.util.concurrent.CompletableFuture; @Service -public class NettyApiClient { - private static final Logger logger = LoggerFactory.getLogger(NettyApiClient.class); +public class NettyHttpApiClient implements ApiClient { + + private static final Logger logger = LoggerFactory.getLogger(NettyHttpApiClient.class); @Autowired ServerRepository serverRepository; @@ -43,29 +44,30 @@ public class NettyApiClient { CompletableFuture responseFuture = new CompletableFuture<>(); EventLoopGroup group = new NioEventLoopGroup(); + try { Bootstrap b = new Bootstrap() - .group(group) - .channel(NioSocketChannel.class) - .option(ChannelOption.TCP_NODELAY, true) - .handler(new ChannelInitializer() { - @Override - public void initChannel(Channel ch) throws SSLException { - if (server.getScheme().equalsIgnoreCase("https")) { - final SslContext sslCtx = SslContextBuilder.forClient() - .trustManager(InsecureTrustManagerFactory.INSTANCE).build(); - ch.pipeline().addLast(sslCtx.newHandler(ch.alloc(), host, port));// Add SSL handler - } - - ch.pipeline().addLast(new HttpClientCodec()); - ch.pipeline().addLast(new HttpObjectAggregator(65536)); - ch.pipeline().addLast(new HttpContentDecompressor()); - ch.pipeline().addLast(new HttpHandler(responseFuture)); + .group(group) + .channel(NioSocketChannel.class) + .option(ChannelOption.TCP_NODELAY, true) + .handler(new ChannelInitializer() { + @Override + public void initChannel(Channel ch) throws SSLException { + if (server.getScheme().equalsIgnoreCase("https")) { + final SslContext sslCtx = SslContextBuilder.forClient() + .trustManager(InsecureTrustManagerFactory.INSTANCE).build(); + ch.pipeline().addLast(sslCtx.newHandler(ch.alloc(), host, port));// Add SSL handler } - }); + + ch.pipeline().addLast(new HttpClientCodec()); + ch.pipeline().addLast(new HttpObjectAggregator(65536)); + ch.pipeline().addLast(new HttpContentDecompressor()); + ch.pipeline().addLast(new HttpHandler(responseFuture)); + } + }); Channel ch = b.connect(host, port).sync().channel(); - ByteBuf content = null; + ByteBuf content; if (StringUtils.isNotEmpty(apiRequest.getRequestBody())) { content = Unpooled.copiedBuffer(apiRequest.getRequestBody(), CharsetUtil.UTF_8); } else { @@ -94,7 +96,7 @@ public class NettyApiClient { request.headers().add(customHeaders); } - apiRequest.setSentBytes(request.toString().length()); +// apiRequest.setSentBytes(request.toString().length()); ch.writeAndFlush(request); ch.closeFuture().sync(); diff --git a/src/main/java/com/eactive/testmaster/client/service/NettyTcpApiClient.java b/src/main/java/com/eactive/testmaster/client/service/NettyTcpApiClient.java new file mode 100644 index 0000000..0c0c09d --- /dev/null +++ b/src/main/java/com/eactive/testmaster/client/service/NettyTcpApiClient.java @@ -0,0 +1,106 @@ +package com.eactive.testmaster.client.service; + +import com.eactive.testmaster.client.dto.ApiRequestDTO; +import com.eactive.testmaster.client.dto.ApiResponse; +import com.eactive.testmaster.common.exception.ServerNotFoundException; +import com.eactive.testmaster.server.entity.Server; +import com.eactive.testmaster.server.entity.ServerRepository; +import io.netty.bootstrap.Bootstrap; +import io.netty.channel.ChannelFuture; +import io.netty.channel.ChannelHandlerContext; +import io.netty.channel.ChannelInitializer; +import io.netty.channel.EventLoopGroup; +import io.netty.channel.SimpleChannelInboundHandler; +import io.netty.channel.nio.NioEventLoopGroup; +import io.netty.channel.socket.SocketChannel; +import io.netty.channel.socket.nio.NioSocketChannel; +import io.netty.handler.codec.string.StringDecoder; +import io.netty.handler.codec.string.StringEncoder; +import java.util.concurrent.ArrayBlockingQueue; +import java.util.concurrent.BlockingQueue; +import java.util.concurrent.CompletableFuture; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.stereotype.Service; + +@Service +public class NettyTcpApiClient implements ApiClient { + + private static final Logger logger = LoggerFactory.getLogger(NettyTcpApiClient.class); + + private final ServerRepository serverRepository; + + public NettyTcpApiClient(ServerRepository serverRepository) { + this.serverRepository = serverRepository; + } + + public CompletableFuture handleRequest(ApiRequestDTO apiRequest) { + Server server = serverRepository.findById(apiRequest.getServer()).orElseThrow(() -> new ServerNotFoundException("Server not found")); + String host = server.getHostname(); + int port = server.getPort(); + + CompletableFuture responseFuture = new CompletableFuture<>(); + EventLoopGroup group = new NioEventLoopGroup(); + try { + String response = sendMessage(host, port, group, apiRequest.getRequestBody()); + ApiResponse apiResponse = new ApiResponse(); + apiResponse.setBody(response); + responseFuture.complete(apiResponse); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + ApiResponse response = new ApiResponse(); + response.setBody("An error occurred: " + e.getMessage()); + return CompletableFuture.completedFuture(response); + } finally { + group.shutdownGracefully(); + } + return responseFuture; + } + + public String sendMessage(String host, int port, EventLoopGroup group, final String message) throws InterruptedException { + final BlockingQueue answer = new ArrayBlockingQueue<>(1); + Bootstrap b = new Bootstrap(); + b.group(group) + .channel(NioSocketChannel.class) + .handler(new ChannelInitializer() { + @Override + protected void initChannel(SocketChannel ch) { + ch.pipeline().addLast(new StringDecoder(), new StringEncoder(), new SimpleChannelInboundHandler() { + @Override + protected void channelRead0(ChannelHandlerContext ctx, String msg) { + answer.offer(msg); + ctx.close(); + } + + @Override + public void channelActive(ChannelHandlerContext ctx) { + ctx.writeAndFlush(message); + // Send message on activation, consider thread safety + } + }); + } + }); + + // Connect to the server + ChannelFuture f = b.connect(host, port).sync(); + f.channel().closeFuture().sync(); + + // Wait for the response + return answer.take(); // This will block until a message is available + } + + +// public static void main(String[] args) { +// NettyTcpApiClient client = new NettyTcpApiClient(); +// try { +// String response = client.sendMessage("localhost", 30913, "00340000BASICTST010134567890ABCDEF"); +// System.out.println("Server replied: " + response); +// } catch (InterruptedException e) { +// Thread.currentThread().interrupt(); +// e.printStackTrace(); +// } finally { +// client.shutdown(); +// } +// } + +} diff --git a/src/main/java/com/eactive/testmaster/loadtest/service/LoadTestService.java b/src/main/java/com/eactive/testmaster/loadtest/service/LoadTestService.java index e3d0aea..148f468 100644 --- a/src/main/java/com/eactive/testmaster/loadtest/service/LoadTestService.java +++ b/src/main/java/com/eactive/testmaster/loadtest/service/LoadTestService.java @@ -6,7 +6,7 @@ import com.eactive.testmaster.client.entity.ApiRequestInfo; import com.eactive.testmaster.client.entity.ApiScenario; import com.eactive.testmaster.client.mapper.ApiRequestMapper; import com.eactive.testmaster.client.mapper.ApiScenarioMapper; -import com.eactive.testmaster.client.service.NettyApiClient; +import com.eactive.testmaster.client.service.ApiClientFactory; import com.eactive.testmaster.loadtest.dto.ApiRequestEvent; import com.eactive.testmaster.loadtest.dto.LoadTestDTO; import com.eactive.testmaster.loadtest.dto.LoadTestRequestAndResponse; @@ -42,20 +42,19 @@ public class LoadTestService extends TextWebSocketHandler { private LoadTestMonitorMap loadTestMonitorMap; - private NettyApiClient nettyApiClient; - + private ApiClientFactory apiClientFactory; private ApiScenarioMapper apiScenarioMapper; private ApiRequestMapper apiRequestMapper; private final RingBuffer ringBuffer; - public LoadTestService(SimpMessagingTemplate template, LoadTestMonitorMap loadTestMonitorMap, NettyApiClient nettyApiClient, ApiScenarioMapper apiScenarioMapper, ApiRequestMapper apiRequestMapper) { + public LoadTestService(SimpMessagingTemplate template, LoadTestMonitorMap loadTestMonitorMap,ApiClientFactory apiClientFactory, ApiScenarioMapper apiScenarioMapper, ApiRequestMapper apiRequestMapper) { this.template = template; this.loadTestMonitorMap = loadTestMonitorMap; - this.nettyApiClient = nettyApiClient; this.apiScenarioMapper = apiScenarioMapper; this.apiRequestMapper = apiRequestMapper; + this.apiClientFactory = apiClientFactory; Disruptor disruptor = new Disruptor<>(ApiRequestEvent::new, 1024, Executors.defaultThreadFactory()); disruptor.handleEventsWith(this::processApiRequestEvent); @@ -137,7 +136,7 @@ public class LoadTestService extends TextWebSocketHandler { List> scheduledFutures = new ArrayList<>(); List virtualUsers = new ArrayList<>(); for (int i = 0; i < numberOfUsers; i++) { - final VirtualUser virtualUser = new VirtualUser(loadTestDTO.getId(), maxCount, scenario, this, nettyApiClient, latch); + final VirtualUser virtualUser = new VirtualUser(loadTestDTO.getId(), maxCount, scenario, this, apiClientFactory, latch); virtualUsers.add(virtualUser); Instant startTime = Instant.now().plusMillis(i * rampUpTimeMillis); diff --git a/src/main/java/com/eactive/testmaster/loadtest/service/VirtualUser.java b/src/main/java/com/eactive/testmaster/loadtest/service/VirtualUser.java index 10ae072..6e9da31 100644 --- a/src/main/java/com/eactive/testmaster/loadtest/service/VirtualUser.java +++ b/src/main/java/com/eactive/testmaster/loadtest/service/VirtualUser.java @@ -4,7 +4,7 @@ import com.eactive.testmaster.client.dto.ApiRequestDTO; import com.eactive.testmaster.client.dto.ApiRequestKeyValueDTO; import com.eactive.testmaster.client.dto.ApiResponse; import com.eactive.testmaster.client.dto.internal.ScenarioNode; -import com.eactive.testmaster.client.service.NettyApiClient; +import com.eactive.testmaster.client.service.ApiClientFactory; import com.eactive.testmaster.loadtest.dto.LoadTestRequestAndResponse; import java.util.ArrayList; import java.util.HashMap; @@ -36,7 +36,7 @@ public class VirtualUser implements Runnable { private Thread runningThread; private final LoadTestService loadTestService; - private final NettyApiClient nettyApiClient; + private final ApiClientFactory apiClientFactory; private static Map globals = new ConcurrentHashMap<>(); private Map variables = new ConcurrentHashMap<>(); @@ -49,12 +49,12 @@ public class VirtualUser implements Runnable { private CountDownLatch latch; - public VirtualUser(String testId, int maxCount, ScenarioNode scenarioDTO, LoadTestService loadTestService, NettyApiClient nettyApiClient, CountDownLatch latch) { + public VirtualUser(String testId, int maxCount, ScenarioNode scenarioDTO, LoadTestService loadTestService, ApiClientFactory apiClientFactory, CountDownLatch latch) { this.testId = testId; this.scenario = scenarioDTO; this.loadTestService = loadTestService; - this.nettyApiClient = nettyApiClient; this.maxCount = maxCount; + this.apiClientFactory = apiClientFactory; this.latch = latch; } @@ -151,7 +151,7 @@ public class VirtualUser implements Runnable { ApiRequestDTO replaced = replacePlaceHoldersWithVariables(cloned); long startTime = System.currentTimeMillis(); - ApiResponse response = nettyApiClient.handleRequest(replaced).get(); + ApiResponse response = apiClientFactory.getClient(replaced).handleRequest(replaced).get(); long endTime = System.currentTimeMillis(); long responseTime = endTime - startTime; diff --git a/src/main/resources/static/plugins/apitestmanager/app.bundle.js b/src/main/resources/static/plugins/apitestmanager/app.bundle.js index 71a23d5..3abcb58 100644 --- a/src/main/resources/static/plugins/apitestmanager/app.bundle.js +++ b/src/main/resources/static/plugins/apitestmanager/app.bundle.js @@ -543,7 +543,7 @@ eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpac /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { "use strict"; -eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ \"default\": () => (__WEBPACK_DEFAULT_EXPORT__)\n/* harmony export */ });\n/* harmony import */ var monaco_editor__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! monaco-editor */ \"include-loader!./node_modules/monaco-editor/esm/vs/editor/editor.main.js\");\n/* harmony import */ var _APIClient__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./APIClient */ \"./src/APIClient.js\");\n/* harmony import */ var _components_EditableInput__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./components/EditableInput */ \"./src/components/EditableInput.js\");\n/* harmony import */ var _popperjs_core_lib_popper_lite__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! @popperjs/core/lib/popper-lite */ \"./node_modules/@popperjs/core/lib/popper-lite.js\");\n/* harmony import */ var _components_PropertyTable__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./components/PropertyTable */ \"./src/components/PropertyTable.js\");\n/* harmony import */ var _components_VariableSnippet__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ./components/VariableSnippet */ \"./src/components/VariableSnippet.js\");\nfunction ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }\nfunction _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }\nfunction _defineProperty(obj, key, value) { key = _toPropertyKey(key); if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }\nfunction _typeof(o) { \"@babel/helpers - typeof\"; return _typeof = \"function\" == typeof Symbol && \"symbol\" == typeof Symbol.iterator ? function (o) { return typeof o; } : function (o) { return o && \"function\" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? \"symbol\" : typeof o; }, _typeof(o); }\nfunction _slicedToArray(arr, i) { return _arrayWithHoles(arr) || _iterableToArrayLimit(arr, i) || _unsupportedIterableToArray(arr, i) || _nonIterableRest(); }\nfunction _nonIterableRest() { throw new TypeError(\"Invalid attempt to destructure non-iterable instance.\\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.\"); }\nfunction _unsupportedIterableToArray(o, minLen) { if (!o) return; if (typeof o === \"string\") return _arrayLikeToArray(o, minLen); var n = Object.prototype.toString.call(o).slice(8, -1); if (n === \"Object\" && o.constructor) n = o.constructor.name; if (n === \"Map\" || n === \"Set\") return Array.from(o); if (n === \"Arguments\" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); }\nfunction _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) arr2[i] = arr[i]; return arr2; }\nfunction _iterableToArrayLimit(r, l) { var t = null == r ? null : \"undefined\" != typeof Symbol && r[Symbol.iterator] || r[\"@@iterator\"]; if (null != t) { var e, n, i, u, a = [], f = !0, o = !1; try { if (i = (t = t.call(r)).next, 0 === l) { if (Object(t) !== t) return; f = !1; } else for (; !(f = (e = i.call(t)).done) && (a.push(e.value), a.length !== l); f = !0); } catch (r) { o = !0, n = r; } finally { try { if (!f && null != t[\"return\"] && (u = t[\"return\"](), Object(u) !== u)) return; } finally { if (o) throw n; } } return a; } }\nfunction _arrayWithHoles(arr) { if (Array.isArray(arr)) return arr; }\nfunction _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError(\"Cannot call a class as a function\"); } }\nfunction _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if (\"value\" in descriptor) descriptor.writable = true; Object.defineProperty(target, _toPropertyKey(descriptor.key), descriptor); } }\nfunction _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); Object.defineProperty(Constructor, \"prototype\", { writable: false }); return Constructor; }\nfunction _toPropertyKey(t) { var i = _toPrimitive(t, \"string\"); return \"symbol\" == _typeof(i) ? i : String(i); }\nfunction _toPrimitive(t, r) { if (\"object\" != _typeof(t) || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || \"default\"); if (\"object\" != _typeof(i)) return i; throw new TypeError(\"@@toPrimitive must return a primitive value.\"); } return (\"string\" === r ? String : Number)(t); }\n\n\n\n\n\n\nvar APITester = /*#__PURE__*/function () {\n function APITester(contextPath) {\n _classCallCheck(this, APITester);\n this.servers = [];\n this.apiTabTitleTarget = '#apiRequestTabTitle';\n this.apiTabContentTarget = '#apiRequestTabContent';\n this.collectionTarget = '#side_menubar';\n this.currentIndex = 0;\n this.apiRequests = []; //탭 열린 API\n this.collections = []; //API 컬렉션\n this.requestEditors = []; //API request body editor\n this.responseEditors = []; //API response body editor\n this.consoleEditors = []; //API console editor\n this.preRequestEditors = [];\n this.postRequestEditors = [];\n this.apiClient = new _APIClient__WEBPACK_IMPORTED_MODULE_1__[\"default\"]();\n this.popperContent = document.getElementById('popperContent');\n this.popperInstance = null;\n this.contextPath = contextPath || '/';\n }\n _createClass(APITester, [{\n key: \"getCollectionListURL\",\n value: function getCollectionListURL() {\n return this.contextPath + 'mgmt/collections/list.do';\n }\n }, {\n key: \"getCollectionCreateURL\",\n value: function getCollectionCreateURL() {\n return this.contextPath + 'mgmt/collections/create.do';\n }\n }, {\n key: \"getCollectionUpdateURL\",\n value: function getCollectionUpdateURL() {\n return this.contextPath + 'mgmt/collections/update.do';\n }\n }, {\n key: \"getCollectionDeleteURL\",\n value: function getCollectionDeleteURL() {\n return this.contextPath + 'mgmt/collections/delete.do';\n }\n }, {\n key: \"getAPISaveURL\",\n value: function getAPISaveURL(collectionId) {\n return this.contextPath + \"mgmt/collections/\".concat(collectionId, \"/apis/save.do\");\n }\n }, {\n key: \"getAPIDeleteURL\",\n value: function getAPIDeleteURL(collectionId) {\n return this.contextPath + \"mgmt/collections/\".concat(collectionId, \"/apis/delete.do\");\n }\n }, {\n key: \"renderServers\",\n value: function renderServers(selectedServer) {\n var optionsHtml = this.servers.map(function (server) {\n return \"\");\n }).join('');\n return \"\");\n }\n }, {\n key: \"basePath\",\n value: function basePath(serverId) {\n if (serverId === undefined || serverId === null || serverId === '') {\n return '';\n }\n return this.servers.filter(function (server) {\n return server.id == serverId;\n })[0].basePath; // == : 타입 비교 없이 값만 비교\n }\n }, {\n key: \"apiRequestTemplate\",\n value: function apiRequestTemplate(apiRequest, index) {\n return \"\\n
\\n
\").concat(apiRequest.collectionName, \" > \").concat(apiRequest.name, \"
\\n
\\n
\\n \\n \\n
\\n
\\n \").concat(this.renderServers(apiRequest.server), \"\\n \\n
\\n
\\n \\n \\n
\\n
\\n \\n
\\n \\n \\n
\\n
\\n
\\n
    \\n
  • \\n \\n
  • \\n
  • \\n \\n
  • \\n
  • \\n \\n
  • \\n
  • \\n \\n
  • \\n
  • \\n \\n
  • \\n
\\n
\\n
\\n
\\n
\\n
\\n
\\n
\\n
\\n
\\n
\\n
\\n \\n
\\n
\\n
\\n
\\n
\\n
\\n
\\n
\\n
\\n
\\n
\\n
\\n
\\n
\\n
\\n
\\n
\\n
\\n
\\n
\\n
\\n
\\n
\\n
\\n
\\n
\\n
\\n
\\n
\\n Response\\n \\n \\n \\n
\\n
    \\n
  • \\n \\n
  • \\n
  • \\n \\n
  • \\n
  • \\n \\n
  • \\n
\\n
\\n
\\n
\\n
\\n
\\n \\n \\n \\n \\n \\n \\n \\n \\n \\n
\\uC774\\uB984\\uAC12
\\n
\\n
\\n
\\n
\\n
\\n
\\n
\\n
\\n \\n \");\n }\n }, {\n key: \"headerTemplate\",\n value: function headerTemplate(header, index) {\n return \"\\n \\n \\n
\\n \\n
\\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \");\n }\n }, {\n key: \"responseHeaderTemplate\",\n value: function responseHeaderTemplate(key, value) {\n return \"\\n \\n \\n \\n \\n \\n \\n \\n \\n \");\n }\n }, {\n key: \"collectionTemplate\",\n value: function collectionTemplate(collection, index) {\n var _this = this;\n return \"\\n
  • \\n
    \\n \\n
    \\n \\n \\n
    \\n
    \\n
    \\n
      \\n \").concat(collection.apis.map(function (api, apiIndex) {\n return _this.collectionApiTemplate(api, apiIndex, collection.id);\n }).join(''), \"\\n
    \\n
    \\n
  • \\n \");\n }\n }, {\n key: \"collectionApiTemplate\",\n value: function collectionApiTemplate(api, apiIndex, collectionId) {\n return \"\\n
  • \\n \").concat(api.name, \"\\n
    \\n \\n \\n
    \\n
  • \\n \");\n }\n }, {\n key: \"init\",\n value: function init(servers) {\n if (servers) {\n this.servers = servers;\n if (this.servers.length === 0) {\n $('.toast-body').text('서버관리에서 서버를 등록해주세요.');\n $('.toast').toast('show');\n }\n }\n this.bindEvents();\n this.loadCollections();\n }\n }, {\n key: \"bindEvents\",\n value: function bindEvents() {\n var events = [{\n selector: '.btn_add_header',\n action: this.addHeader.bind(this)\n }, {\n selector: '.btn_remove_header',\n action: this.removeHeader.bind(this)\n }, {\n selector: '.send',\n action: this.handleSendAPIRequest.bind(this)\n }, {\n selector: '.save',\n action: this.saveAPIRequest.bind(this)\n }, {\n selector: '.save_collection',\n action: this.addCollection.bind(this)\n }, {\n selector: '#cancel-ajax',\n action: this.cancelAjaxRequest.bind(this)\n }, {\n selector: '#new_collection',\n action: this.showNewCollectionModal.bind(this)\n }, {\n selector: '#new_request',\n action: this.showNewApiRequestModal.bind(this)\n }, {\n selector: '.edit_collection',\n action: this.showCollectionEditModal.bind(this)\n }, {\n selector: '.delete_collection',\n action: this.showCollectionDeleteModal.bind(this)\n }, {\n selector: '.confirm_delete',\n action: this.removeCollection.bind(this)\n }, {\n selector: '.add_new_request',\n action: this.addAPIRequest.bind(this)\n }, {\n selector: '.edit_api_request',\n action: this.showEditNameModal.bind(this)\n }, {\n selector: '.delete_api_request',\n action: this.showDeleteApiRequestModal.bind(this)\n }, {\n selector: '.open_api_request',\n action: this.openApiRequest.bind(this)\n }, {\n selector: '.confirm_delete_api',\n action: this.deleteApiRequest.bind(this)\n }, {\n selector: '.close_tab',\n action: this.closeTab.bind(this)\n }];\n for (var _i = 0, _events = events; _i < _events.length; _i++) {\n var event = _events[_i];\n $(document).on('click', event.selector, event.action);\n }\n $(document).on('change', '.path', this.parseParam.bind(this));\n $(document).on('change', '.request_headers input', this.handleUIUpdate.bind(this));\n $(document).on('change', '.api_request_info select, .api_request_info input', this.handleUIUpdate.bind(this));\n $(document).on('change', '.api_request_info select', this.handleUpdateServer.bind(this));\n window.addEventListener('resize', this.resizeEditor.bind(this));\n }\n }, {\n key: \"resizeEditor\",\n value: function resizeEditor() {\n //FIXME: 창 크기 변경시 자동으로 editor 크기가 조정되지 않아서, 0으로 강제 변경후 다시 layout() 호출\n\n for (var i = 0; i < this.requestEditors.length; i++) {\n this.requestEditors[i].layout({\n width: 0\n });\n }\n for (var _i2 = 0; _i2 < this.responseEditors.length; _i2++) {\n this.responseEditors[_i2].layout({\n width: 0\n });\n }\n for (var _i3 = 0; _i3 < this.preRequestEditors.length; _i3++) {\n this.preRequestEditors[_i3].layout({\n width: 0\n });\n }\n for (var _i4 = 0; _i4 < this.postRequestEditors.length; _i4++) {\n this.postRequestEditors[_i4].layout({\n width: 0\n });\n }\n for (var _i5 = 0; _i5 < this.requestEditors.length; _i5++) {\n this.requestEditors[_i5].layout({});\n }\n for (var _i6 = 0; _i6 < this.responseEditors.length; _i6++) {\n this.responseEditors[_i6].layout({});\n }\n for (var _i7 = 0; _i7 < this.preRequestEditors.length; _i7++) {\n this.preRequestEditors[_i7].layout({});\n }\n for (var _i8 = 0; _i8 < this.postRequestEditors.length; _i8++) {\n this.postRequestEditors[_i8].layout({});\n }\n }\n }, {\n key: \"showCollectionDeleteModal\",\n value: function showCollectionDeleteModal(event) {\n var collectionId = $(event.currentTarget).closest('button').data('collection');\n $('#confirm_delete_modal').find('.confirm_delete').data('id', collectionId);\n $('#confirm_delete_modal').modal('show');\n }\n }, {\n key: \"getApiRequestModel\",\n value: function getApiRequestModel(apiId) {\n var foundApi = null;\n this.collections.forEach(function (collection) {\n collection.apis.forEach(function (api) {\n if (api.id === apiId) {\n foundApi = api;\n }\n });\n });\n return foundApi;\n }\n }, {\n key: \"showCollectionEditModal\",\n value: function showCollectionEditModal(event) {\n var me = this;\n var collectionId = $(event.currentTarget).closest('button').data('collection');\n var collection = this.collections.filter(function (collection) {\n return collection.id === collectionId;\n })[0];\n $('#edit_name_modal').find('input').val('');\n $('#edit_name_modal').modal('show');\n var saveBtn = $('#edit_name_modal').find('button.change_name');\n saveBtn.off('click');\n saveBtn.on('click', function () {\n collection.name = $('#edit_name_modal').find('input').val();\n me.saveCollection(collection.id, collection.name);\n me.renderCollections();\n $('#edit_name_modal').modal('hide');\n });\n }\n }, {\n key: \"showDeleteApiRequestModal\",\n value: function showDeleteApiRequestModal(event) {\n var collectionId = $(event.currentTarget).closest('li').data('collection');\n var apiId = $(event.currentTarget).closest('li').data('id');\n $('#confirm_delete_api_modal').find('.confirm_delete_api').data('id', apiId);\n $('#confirm_delete_api_modal').find('.confirm_delete_api').data('collection', collectionId);\n $('#confirm_delete_api_modal').modal('show');\n }\n }, {\n key: \"showNewApiRequestModal\",\n value: function showNewApiRequestModal(event) {\n if (this.collections.length == 0) {\n $('.toast-body').text('새로운 컬렉션을 추가해 주세요.');\n $('.toast').toast('show');\n return;\n }\n $('#new_api_request_modal').modal('show');\n }\n }, {\n key: \"showNewCollectionModal\",\n value: function showNewCollectionModal(event) {\n $('#new_collection_modal').find('input').val('');\n $('#new_collection_modal').modal('show');\n }\n }, {\n key: \"showEditNameModal\",\n value: function showEditNameModal(event) {\n var me = this;\n var apiId = $(event.currentTarget).closest('li').data('id');\n var collectionId = $(event.currentTarget).closest('li').data('collection');\n var collection = this.collections.filter(function (collection) {\n return collection.id === collectionId;\n })[0];\n var apiRequest = collection.apis.filter(function (api) {\n return api.id === apiId;\n })[0];\n apiRequest.collectionId = collectionId;\n var saveBtn = $('#edit_name_modal').find('button.change_name');\n saveBtn.off('click');\n saveBtn.on('click', function () {\n apiRequest.name = $('#edit_name_modal').find('input').val();\n me.changeAPIName(apiRequest);\n me.renderCollections();\n $('#edit_name_modal').modal('hide');\n\n //탭이 열려 있으면, 닫았다가 다시 열어야 함.\n me.renderTabHeader();\n me.renderTabContent(apiRequest.index);\n });\n $('#edit_name_modal').find('input').val('');\n $('#edit_name_modal').modal('show');\n }\n }, {\n key: \"getFieldValue\",\n value: function getFieldValue(element) {\n if ($(element).is('select') || $(element).is('input[type=\"text\"]')) {\n return $(element).val();\n }\n if ($(element).is('input[type=\"checkbox\"]')) {\n return $(element).is(':checked');\n }\n }\n }, {\n key: \"handleUIUpdate\",\n value: function handleUIUpdate(event) {\n if (event) {\n event.preventDefault();\n var element = event.currentTarget;\n var fieldName = $(element).attr('name');\n var newValue = this.getFieldValue(element);\n var tabIndex = $('#apiRequestTabContent').children().index($(event.currentTarget).closest('.api_request'));\n var model = this.apiRequests[tabIndex];\n if (fieldName !== '') {\n _.set(model, fieldName, newValue);\n }\n }\n }\n }, {\n key: \"handleUpdateServer\",\n value: function handleUpdateServer(event) {\n var tabIndex = $('#apiRequestTabContent').children().index($(event.currentTarget).closest('.api_request'));\n var model = this.apiRequests[tabIndex];\n var target = $('#api_request_' + model.id);\n target.find('input[name=\"basePath\"]').val(this.basePath(model.server));\n }\n }, {\n key: \"renderHeaders\",\n value: function renderHeaders(headers) {\n var _this2 = this;\n return headers.map(function (header, index) {\n return _this2.headerTemplate(header, index);\n }).join('');\n }\n }, {\n key: \"renderTabHeader\",\n value: function renderTabHeader() {\n var apiRequestTabTitle = $(this.apiTabTitleTarget);\n apiRequestTabTitle.empty();\n for (var idx = 0; idx < this.apiRequests.length; idx++) {\n var li = \"
  • \\n \\n
  • \");\n apiRequestTabTitle.append(li);\n }\n }\n }, {\n key: \"showPopper\",\n value: function showPopper(element, text) {\n var variable = text.replace(/{{|}}/g, '');\n this.popperContent.style.display = 'block';\n var innerDiv = this.popperContent.querySelector('.variable_popper');\n innerDiv.textContent = '{{' + variable + '}} = ' + (window.globals[variable] === undefined ? '' : window.globals[variable]);\n this.popperInstance = (0,_popperjs_core_lib_popper_lite__WEBPACK_IMPORTED_MODULE_5__.createPopper)(element, this.popperContent, {\n placement: 'bottom',\n // Popper below the element\n modifiers: [{\n name: 'offset',\n options: {\n offset: [0, 8] // Adjust the position if needed\n }\n }]\n });\n }\n }, {\n key: \"hidePopper\",\n value: function hidePopper(element) {\n if (this.popperInstance) {\n this.popperInstance.destroy();\n this.popperInstance = null;\n }\n this.popperContent.style.display = 'none';\n }\n }, {\n key: \"renderTabContent\",\n value: function renderTabContent(index) {\n var _this3 = this;\n var me = this;\n var apiRequestTabContent = $(this.apiTabContentTarget);\n var model = this.apiRequests[index];\n apiRequestTabContent.append(this.apiRequestTemplate(model, index));\n var editableInput = new _components_EditableInput__WEBPACK_IMPORTED_MODULE_2__[\"default\"]({\n name: 'path',\n value: model.path\n });\n var queryParamTable = new _components_PropertyTable__WEBPACK_IMPORTED_MODULE_3__[\"default\"]({\n propertyName: 'queryParams',\n properties: model.queryParams\n });\n var headerTable = new _components_PropertyTable__WEBPACK_IMPORTED_MODULE_3__[\"default\"]({\n propertyName: 'headers',\n properties: model.headers\n });\n queryParamTable.init(apiRequestTabContent.find(\"#api_request_\".concat(model.id)).find('.query_params')[0], function (properties) {\n model.queryParams = properties;\n console.log(model.queryParams);\n _this3.buildPath(model);\n editableInput.setValue(model.path);\n $('span.variable').off('mouseover');\n $('span.variable').off('mouseout');\n document.querySelectorAll('span.variable').forEach(function (element) {\n var text = element.innerText;\n element.addEventListener('mouseover', function () {\n return me.showPopper(element, text);\n });\n element.addEventListener('mouseout', function () {\n return me.hidePopper(element);\n });\n });\n });\n headerTable.init(apiRequestTabContent.find(\"#api_request_\".concat(model.id)).find('.request_headers')[0], function (properties) {\n model.headers = properties;\n $('span.variable').off('mouseover');\n $('span.variable').off('mouseout');\n document.querySelectorAll('span.variable').forEach(function (element) {\n var text = element.innerText;\n element.addEventListener('mouseover', function () {\n return me.showPopper(element, text);\n });\n element.addEventListener('mouseout', function () {\n return me.hidePopper(element);\n });\n });\n });\n apiRequestTabContent.find(\"#api_request_\".concat(model.id)).find('.api_request_info').find('.path').each(function () {\n editableInput.init(this, function (value) {\n model.path = value;\n model.queryParams = me.parseParam(model.path);\n queryParamTable.setProperties(model.queryParams);\n $('span.variable').off('mouseover');\n $('span.variable').off('mouseout');\n document.querySelectorAll('span.variable').forEach(function (element) {\n var text = element.innerText;\n element.addEventListener('mouseover', function () {\n return me.showPopper(element, text);\n });\n element.addEventListener('mouseout', function () {\n return me.hidePopper(element);\n });\n });\n });\n $(this).append(\"\");\n $('span.variable').off('mouseover');\n $('span.variable').off('mouseout');\n });\n document.querySelectorAll('.variable').forEach(function (element) {\n var text = element.innerText;\n element.addEventListener('mouseover', function () {\n return me.showPopper(element, text);\n });\n element.addEventListener('mouseout', function () {\n return me.hidePopper(element);\n });\n });\n this.openTab(model.id);\n var target = $('#api_request_' + model.id);\n var requestBodyEditor = monaco_editor__WEBPACK_IMPORTED_MODULE_0__.editor.create(target.find('.request_body')[0], {\n value: model.requestBody,\n language: 'json',\n automaticLayout: true\n });\n requestBodyEditor.onMouseMove(function (e) {\n var position = e.target.position;\n if (position) {\n var _model = requestBodyEditor.getModel();\n var word = _model.getWordAtPosition(position);\n var lineContent = _model.getLineContent(position.lineNumber);\n if (word) {\n if (lineContent.indexOf('{{' + word.word + '}}') > -1) {\n me.showPopper(e.target.element, word.word);\n }\n } else {\n me.hidePopper(e.target.element);\n }\n }\n });\n me.requestEditors.push(requestBodyEditor);\n target.find('.request_body')[0].addEventListener('shown.bs.tab', function () {\n me.requestEditors[index].layout();\n });\n me.requestEditors[index].onDidChangeModelContent(function (e) {\n model.requestBody = requestBodyEditor.getValue();\n });\n target.find('.request_body_type').on('change', function () {\n var model = requestBodyEditor.getModel();\n monaco_editor__WEBPACK_IMPORTED_MODULE_0__.editor.setModelLanguage(model, $(this).val());\n });\n var responseBodyEditor = monaco_editor__WEBPACK_IMPORTED_MODULE_0__.editor.create(target.find('.response_body')[0], {\n value: '',\n language: 'json',\n automaticLayout: true,\n quickSuggestions: false\n });\n me.responseEditors.push(responseBodyEditor);\n var consoleEditor = monaco_editor__WEBPACK_IMPORTED_MODULE_0__.editor.create(target.find('.console')[0], {\n value: '',\n automaticLayout: true,\n quickSuggestions: false\n });\n me.consoleEditors.push(consoleEditor);\n var preRequestEditor = monaco_editor__WEBPACK_IMPORTED_MODULE_0__.editor.create(target.find('.pre-request')[0], {\n value: model.preRequestScript,\n language: 'javascript',\n automaticLayout: true,\n quickSuggestions: false\n });\n var snippet1 = new _components_VariableSnippet__WEBPACK_IMPORTED_MODULE_4__[\"default\"]();\n snippet1.init(target.find('.pre-request-variable')[0], preRequestEditor);\n me.preRequestEditors.push(preRequestEditor);\n target.find('.pre-request')[0].addEventListener('shown.bs.tab', function () {\n me.preRequestEditors[index].layout();\n });\n me.preRequestEditors[index].onDidChangeModelContent(function (e) {\n model.preRequestScript = preRequestEditor.getValue();\n });\n var postRequestEditor = monaco_editor__WEBPACK_IMPORTED_MODULE_0__.editor.create(target.find('.post-request')[0], {\n value: model.postRequestScript,\n language: 'javascript',\n automaticLayout: true,\n quickSuggestions: false\n });\n var snippet2 = new _components_VariableSnippet__WEBPACK_IMPORTED_MODULE_4__[\"default\"]();\n snippet2.init(target.find('.post-request-variable')[0], postRequestEditor);\n me.postRequestEditors.push(postRequestEditor);\n target.find('.post-request')[0].addEventListener('shown.bs.tab', function () {\n me.postRequestEditors[index].layout();\n });\n me.postRequestEditors[index].onDidChangeModelContent(function (e) {\n model.postRequestScript = postRequestEditor.getValue();\n });\n }\n }, {\n key: \"renderResponse\",\n value: function renderResponse(tabIndex) {\n var _this4 = this;\n var model = this.apiRequests[tabIndex];\n var target = $('#api_request_' + model.id);\n target.find('.response_headers').empty();\n target.find('.response_status').empty();\n try {\n var parsedJson = JSON.parse(model.responseModel.body);\n var formattedJson = JSON.stringify(parsedJson, null, 2);\n this.responseEditors[tabIndex].setValue(formattedJson);\n } catch (e) {\n this.responseEditors[tabIndex].setValue(model.responseModel.body);\n }\n if (model.responseModel && model.responseModel.headers) {\n var headers = model.responseModel.headers;\n Object.entries(headers).forEach(function (_ref) {\n var _ref2 = _slicedToArray(_ref, 2),\n key = _ref2[0],\n value = _ref2[1];\n target.find('.response_headers').append(_this4.responseHeaderTemplate(key, value));\n });\n }\n target.find('.response_status').text('status: ' + model.responseModel.status);\n target.find('.response_time').text('time: ' + model.responseModel.time + 'ms');\n target.find('.response_size').text('size: ' + model.responseModel.size + 'bytes');\n }\n }, {\n key: \"customHelper\",\n value: function customHelper(event) {\n // Create and return the custom helper element\n var name = $(event.target).closest('.api_request_sortable').find('.open_api_request').text().trim();\n var apiId = $(event.target).closest('.api_request_sortable').data('id');\n return \"
    \\n
    \").concat(name, \"
    \\n
    \");\n }\n }, {\n key: \"renderCollections\",\n value: function renderCollections() {\n var select = $('#modal_collection');\n var sidemenu = $(this.collectionTarget);\n select.empty();\n sidemenu.empty();\n for (var i = 0; i < this.collections.length; i++) {\n sidemenu.append(this.renderCollection(this.collections[i], i));\n var option = $('\");\n }).join('');\n return \"\");\n }\n }, {\n key: \"basePath\",\n value: function basePath(serverId) {\n if (serverId === undefined || serverId === null || serverId === '') {\n return '';\n }\n return this.servers.filter(function (server) {\n return server.id == serverId;\n })[0].basePath; // == : 타입 비교 없이 값만 비교\n }\n }, {\n key: \"httpApiRequestTemplate\",\n value: function httpApiRequestTemplate(apiRequest, index) {\n return \"\\n
    \\n
    \").concat(apiRequest.collectionName, \" > \").concat(apiRequest.name, \"
    \\n
    \\n
    \\n \\n \\n
    \\n
    \\n \").concat(this.renderServers(apiRequest.server), \"\\n \\n
    \\n
    \\n \\n \\n
    \\n
    \\n \\n
    \\n \\n \\n
    \\n
    \\n
    \\n
      \\n
    • \\n \\n
    • \\n
    • \\n \\n
    • \\n
    • \\n \\n
    • \\n
    • \\n \\n
    • \\n
    • \\n \\n
    • \\n
    \\n
    \\n
    \\n
    \\n
    \\n
    \\n
    \\n
    \\n
    \\n
    \\n
    \\n
    \\n \\n
    \\n
    \\n
    \\n
    \\n
    \\n
    \\n
    \\n
    \\n
    \\n
    \\n
    \\n
    \\n
    \\n
    \\n
    \\n
    \\n
    \\n
    \\n
    \\n
    \\n
    \\n
    \\n
    \\n
    \\n
    \\n
    \\n
    \\n
    \\n
    \\n Response\\n \\n \\n \\n
    \\n
      \\n
    • \\n \\n
    • \\n
    • \\n \\n
    • \\n
    • \\n \\n
    • \\n
    \\n
    \\n
    \\n
    \\n
    \\n
    \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n
    \\uC774\\uB984\\uAC12
    \\n
    \\n
    \\n
    \\n
    \\n
    \\n
    \\n
    \\n
    \\n \\n \");\n }\n }, {\n key: \"tcpApiRequestTemplate\",\n value: function tcpApiRequestTemplate(apiRequest, index) {\n return \"\\n
    \\n
    \").concat(apiRequest.collectionName, \" > \").concat(apiRequest.name, \"
    \\n
    \\n
    \\n \").concat(this.renderServers(apiRequest.server), \"\\n \\n
    \\n \\n \\n
    \\n
    \\n
    \\n
      \\n
    • \\n \\n
    • \\n
    • \\n \\n
    • \\n
    • \\n \\n
    • \\n
    \\n
    \\n
    \\n
    \\n \\n
    \\n
    \\n
    \\n
    \\n
    \\n
    \\n
    \\n
    \\n
    \\n
    \\n
    \\n
    \\n
    \\n
    \\n
    \\n
    \\n
    \\n
    \\n
    \\n
    \\n
    \\n
    \\n
    \\n
    \\n
    \\n
    \\n
    \\n
    \\n
    \\n Response\\n \\n \\n \\n
    \\n
      \\n
    • \\n \\n
    • \\n
    • \\n \\n
    • \\n
    \\n
    \\n
    \\n
    \\n
    \\n
    \\n
    \\n
    \\n
    \\n
    \\n
    \\n
    \\n \\n \");\n }\n }, {\n key: \"headerTemplate\",\n value: function headerTemplate(header, index) {\n return \"\\n \\n \\n
    \\n \\n
    \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \");\n }\n }, {\n key: \"responseHeaderTemplate\",\n value: function responseHeaderTemplate(key, value) {\n return \"\\n \\n \\n \\n \\n \\n \\n \\n \\n \");\n }\n }, {\n key: \"collectionTemplate\",\n value: function collectionTemplate(collection, index) {\n var _this = this;\n return \"\\n
  • \\n
    \\n \\n
    \\n \\n \\n
    \\n
    \\n
    \\n
      \\n \").concat(collection.apis.map(function (api, apiIndex) {\n return _this.collectionApiTemplate(api, apiIndex, collection.id);\n }).join(''), \"\\n
    \\n
    \\n
  • \\n \");\n }\n }, {\n key: \"collectionApiTemplate\",\n value: function collectionApiTemplate(api, apiIndex, collectionId) {\n return \"\\n
  • \\n \").concat(api.name, \"\\n
    \\n \\n \\n
    \\n
  • \\n \");\n }\n }, {\n key: \"init\",\n value: function init(servers) {\n if (servers) {\n this.servers = servers;\n if (this.servers.length === 0) {\n $('.toast-body').text('서버관리에서 서버를 등록해주세요.');\n $('.toast').toast('show');\n }\n }\n this.bindEvents();\n this.loadCollections();\n }\n }, {\n key: \"bindEvents\",\n value: function bindEvents() {\n var events = [{\n selector: '.btn_add_header',\n action: this.addHeader.bind(this)\n }, {\n selector: '.btn_remove_header',\n action: this.removeHeader.bind(this)\n }, {\n selector: '.send',\n action: this.handleSendAPIRequest.bind(this)\n }, {\n selector: '.save',\n action: this.saveAPIRequest.bind(this)\n }, {\n selector: '.save_collection',\n action: this.addCollection.bind(this)\n }, {\n selector: '#cancel-ajax',\n action: this.cancelAjaxRequest.bind(this)\n }, {\n selector: '#new_collection',\n action: this.showNewCollectionModal.bind(this)\n }, {\n selector: '#new_request',\n action: this.showNewApiRequestModal.bind(this)\n }, {\n selector: '.edit_collection',\n action: this.showCollectionEditModal.bind(this)\n }, {\n selector: '.delete_collection',\n action: this.showCollectionDeleteModal.bind(this)\n }, {\n selector: '.confirm_delete',\n action: this.removeCollection.bind(this)\n }, {\n selector: '.add_new_request',\n action: this.addAPIRequest.bind(this)\n }, {\n selector: '.edit_api_request',\n action: this.showEditNameModal.bind(this)\n }, {\n selector: '.delete_api_request',\n action: this.showDeleteApiRequestModal.bind(this)\n }, {\n selector: '.open_api_request',\n action: this.openApiRequest.bind(this)\n }, {\n selector: '.confirm_delete_api',\n action: this.deleteApiRequest.bind(this)\n }, {\n selector: '.close_tab',\n action: this.closeTab.bind(this)\n }];\n for (var _i = 0, _events = events; _i < _events.length; _i++) {\n var event = _events[_i];\n $(document).on('click', event.selector, event.action);\n }\n $(document).on('change', '.path', this.parseParam.bind(this));\n $(document).on('change', '.request_headers input', this.handleUIUpdate.bind(this));\n $(document).on('change', '.api_request_info select, .api_request_info input', this.handleUIUpdate.bind(this));\n $(document).on('change', '.api_request_info select', this.handleUpdateServer.bind(this));\n window.addEventListener('resize', this.resizeEditor.bind(this));\n }\n }, {\n key: \"resizeEditor\",\n value: function resizeEditor() {\n //FIXME: 창 크기 변경시 자동으로 editor 크기가 조정되지 않아서, 0으로 강제 변경후 다시 layout() 호출\n\n for (var i = 0; i < this.requestEditors.length; i++) {\n this.requestEditors[i].layout({\n width: 0\n });\n }\n for (var _i2 = 0; _i2 < this.responseEditors.length; _i2++) {\n this.responseEditors[_i2].layout({\n width: 0\n });\n }\n for (var _i3 = 0; _i3 < this.preRequestEditors.length; _i3++) {\n this.preRequestEditors[_i3].layout({\n width: 0\n });\n }\n for (var _i4 = 0; _i4 < this.postRequestEditors.length; _i4++) {\n this.postRequestEditors[_i4].layout({\n width: 0\n });\n }\n for (var _i5 = 0; _i5 < this.requestEditors.length; _i5++) {\n this.requestEditors[_i5].layout({});\n }\n for (var _i6 = 0; _i6 < this.responseEditors.length; _i6++) {\n this.responseEditors[_i6].layout({});\n }\n for (var _i7 = 0; _i7 < this.preRequestEditors.length; _i7++) {\n this.preRequestEditors[_i7].layout({});\n }\n for (var _i8 = 0; _i8 < this.postRequestEditors.length; _i8++) {\n this.postRequestEditors[_i8].layout({});\n }\n }\n }, {\n key: \"showCollectionDeleteModal\",\n value: function showCollectionDeleteModal(event) {\n var collectionId = $(event.currentTarget).closest('button').data('collection');\n $('#confirm_delete_modal').find('.confirm_delete').data('id', collectionId);\n $('#confirm_delete_modal').modal('show');\n }\n }, {\n key: \"getApiRequestModel\",\n value: function getApiRequestModel(apiId) {\n var foundApi = null;\n this.collections.forEach(function (collection) {\n collection.apis.forEach(function (api) {\n if (api.id === apiId) {\n foundApi = api;\n }\n });\n });\n return foundApi;\n }\n }, {\n key: \"showCollectionEditModal\",\n value: function showCollectionEditModal(event) {\n var me = this;\n var collectionId = $(event.currentTarget).closest('button').data('collection');\n var collection = this.collections.filter(function (collection) {\n return collection.id === collectionId;\n })[0];\n $('#edit_name_modal').find('input').val('');\n $('#edit_name_modal').modal('show');\n var saveBtn = $('#edit_name_modal').find('button.change_name');\n saveBtn.off('click');\n saveBtn.on('click', function () {\n collection.name = $('#edit_name_modal').find('input').val();\n me.saveCollection(collection.id, collection.name);\n me.renderCollections();\n $('#edit_name_modal').modal('hide');\n });\n }\n }, {\n key: \"showDeleteApiRequestModal\",\n value: function showDeleteApiRequestModal(event) {\n var collectionId = $(event.currentTarget).closest('li').data('collection');\n var apiId = $(event.currentTarget).closest('li').data('id');\n $('#confirm_delete_api_modal').find('.confirm_delete_api').data('id', apiId);\n $('#confirm_delete_api_modal').find('.confirm_delete_api').data('collection', collectionId);\n $('#confirm_delete_api_modal').modal('show');\n }\n }, {\n key: \"showNewApiRequestModal\",\n value: function showNewApiRequestModal(event) {\n if (this.collections.length == 0) {\n $('.toast-body').text('새로운 컬렉션을 추가해 주세요.');\n $('.toast').toast('show');\n return;\n }\n $('#new_api_request_modal').modal('show');\n }\n }, {\n key: \"showNewCollectionModal\",\n value: function showNewCollectionModal(event) {\n $('#new_collection_modal').find('input').val('');\n $('#new_collection_modal').modal('show');\n }\n }, {\n key: \"showEditNameModal\",\n value: function showEditNameModal(event) {\n var me = this;\n var apiId = $(event.currentTarget).closest('li').data('id');\n var collectionId = $(event.currentTarget).closest('li').data('collection');\n var collection = this.collections.filter(function (collection) {\n return collection.id === collectionId;\n })[0];\n var apiRequest = collection.apis.filter(function (api) {\n return api.id === apiId;\n })[0];\n apiRequest.collectionId = collectionId;\n var saveBtn = $('#edit_name_modal').find('button.change_name');\n saveBtn.off('click');\n saveBtn.on('click', function () {\n apiRequest.name = $('#edit_name_modal').find('input').val();\n me.changeAPIName(apiRequest);\n me.renderCollections();\n $('#edit_name_modal').modal('hide');\n\n //탭이 열려 있으면, 닫았다가 다시 열어야 함.\n me.renderTabHeader();\n me.renderTabContent(apiRequest.index);\n });\n $('#edit_name_modal').find('input').val('');\n $('#edit_name_modal').modal('show');\n }\n }, {\n key: \"getFieldValue\",\n value: function getFieldValue(element) {\n if ($(element).is('select') || $(element).is('input[type=\"text\"]')) {\n return $(element).val();\n }\n if ($(element).is('input[type=\"checkbox\"]')) {\n return $(element).is(':checked');\n }\n }\n }, {\n key: \"handleUIUpdate\",\n value: function handleUIUpdate(event) {\n if (event) {\n event.preventDefault();\n var element = event.currentTarget;\n var fieldName = $(element).attr('name');\n var newValue = this.getFieldValue(element);\n var tabIndex = $('#apiRequestTabContent').children().index($(event.currentTarget).closest('.api_request'));\n var model = this.apiRequests[tabIndex];\n if (fieldName !== '') {\n _.set(model, fieldName, newValue);\n }\n }\n }\n }, {\n key: \"handleUpdateServer\",\n value: function handleUpdateServer(event) {\n var tabIndex = $('#apiRequestTabContent').children().index($(event.currentTarget).closest('.api_request'));\n var model = this.apiRequests[tabIndex];\n var target = $('#api_request_' + model.id);\n target.find('input[name=\"basePath\"]').val(this.basePath(model.server));\n }\n }, {\n key: \"renderHeaders\",\n value: function renderHeaders(headers) {\n var _this2 = this;\n return headers.map(function (header, index) {\n return _this2.headerTemplate(header, index);\n }).join('');\n }\n }, {\n key: \"renderTabHeader\",\n value: function renderTabHeader() {\n var apiRequestTabTitle = $(this.apiTabTitleTarget);\n apiRequestTabTitle.empty();\n for (var idx = 0; idx < this.apiRequests.length; idx++) {\n var li = \"
  • \\n \\n
  • \");\n apiRequestTabTitle.append(li);\n }\n }\n }, {\n key: \"showPopper\",\n value: function showPopper(element, text) {\n var variable = text.replace(/{{|}}/g, '');\n this.popperContent.style.display = 'block';\n var innerDiv = this.popperContent.querySelector('.variable_popper');\n innerDiv.textContent = '{{' + variable + '}} = ' + (window.globals[variable] === undefined ? '' : window.globals[variable]);\n this.popperInstance = (0,_popperjs_core_lib_popper_lite__WEBPACK_IMPORTED_MODULE_5__.createPopper)(element, this.popperContent, {\n placement: 'bottom',\n // Popper below the element\n modifiers: [{\n name: 'offset',\n options: {\n offset: [0, 8] // Adjust the position if needed\n }\n }]\n });\n }\n }, {\n key: \"hidePopper\",\n value: function hidePopper(element) {\n if (this.popperInstance) {\n this.popperInstance.destroy();\n this.popperInstance = null;\n }\n this.popperContent.style.display = 'none';\n }\n }, {\n key: \"renderTabContent\",\n value: function renderTabContent(index) {\n var _this3 = this;\n var me = this;\n var apiRequestTabContent = $(this.apiTabContentTarget);\n var model = this.apiRequests[index];\n if (model.type === 'HTTP') {\n apiRequestTabContent.append(this.httpApiRequestTemplate(model, index));\n var editableInput = new _components_EditableInput__WEBPACK_IMPORTED_MODULE_2__[\"default\"]({\n name: 'path',\n value: model.path\n });\n var queryParamTable = new _components_PropertyTable__WEBPACK_IMPORTED_MODULE_3__[\"default\"]({\n propertyName: 'queryParams',\n properties: model.queryParams\n });\n var headerTable = new _components_PropertyTable__WEBPACK_IMPORTED_MODULE_3__[\"default\"]({\n propertyName: 'headers',\n properties: model.headers\n });\n apiRequestTabContent.find(\"#api_request_\".concat(model.id)).find('.api_request_info').find('.path').each(function () {\n editableInput.init(this, function (value) {\n model.path = value;\n model.queryParams = me.parseParam(model.path);\n queryParamTable.setProperties(model.queryParams);\n $('span.variable').off('mouseover');\n $('span.variable').off('mouseout');\n document.querySelectorAll('span.variable').forEach(function (element) {\n var text = element.innerText;\n element.addEventListener('mouseover', function () {\n return me.showPopper(element, text);\n });\n element.addEventListener('mouseout', function () {\n return me.hidePopper(element);\n });\n });\n });\n $(this).append(\"\");\n $('span.variable').off('mouseover');\n $('span.variable').off('mouseout');\n });\n queryParamTable.init(apiRequestTabContent.find(\"#api_request_\".concat(model.id)).find('.query_params')[0], function (properties) {\n model.queryParams = properties;\n console.log(model.queryParams);\n _this3.buildPath(model);\n editableInput.setValue(model.path);\n $('span.variable').off('mouseover');\n $('span.variable').off('mouseout');\n document.querySelectorAll('span.variable').forEach(function (element) {\n var text = element.innerText;\n element.addEventListener('mouseover', function () {\n return me.showPopper(element, text);\n });\n element.addEventListener('mouseout', function () {\n return me.hidePopper(element);\n });\n });\n });\n headerTable.init(apiRequestTabContent.find(\"#api_request_\".concat(model.id)).find('.request_headers')[0], function (properties) {\n model.headers = properties;\n $('span.variable').off('mouseover');\n $('span.variable').off('mouseout');\n document.querySelectorAll('span.variable').forEach(function (element) {\n var text = element.innerText;\n element.addEventListener('mouseover', function () {\n return me.showPopper(element, text);\n });\n element.addEventListener('mouseout', function () {\n return me.hidePopper(element);\n });\n });\n });\n }\n if (model.type === 'TCP') {\n apiRequestTabContent.append(this.tcpApiRequestTemplate(model, index));\n }\n document.querySelectorAll('.variable').forEach(function (element) {\n var text = element.innerText;\n element.addEventListener('mouseover', function () {\n return me.showPopper(element, text);\n });\n element.addEventListener('mouseout', function () {\n return me.hidePopper(element);\n });\n });\n this.openTab(model.id);\n var target = $('#api_request_' + model.id);\n var language = model.type === 'TCP' ? 'text' : 'json';\n var requestBodyEditor = monaco_editor__WEBPACK_IMPORTED_MODULE_0__.editor.create(target.find('.request_body')[0], {\n value: model.requestBody,\n language: language,\n automaticLayout: true\n });\n requestBodyEditor.onMouseMove(function (e) {\n var position = e.target.position;\n if (position) {\n var _model = requestBodyEditor.getModel();\n var word = _model.getWordAtPosition(position);\n var lineContent = _model.getLineContent(position.lineNumber);\n if (word) {\n if (lineContent.indexOf('{{' + word.word + '}}') > -1) {\n me.showPopper(e.target.element, word.word);\n }\n } else {\n me.hidePopper(e.target.element);\n }\n }\n });\n me.requestEditors.push(requestBodyEditor);\n target.find('.request_body')[0].addEventListener('shown.bs.tab', function () {\n me.requestEditors[index].layout();\n });\n me.requestEditors[index].onDidChangeModelContent(function (e) {\n model.requestBody = requestBodyEditor.getValue();\n });\n target.find('.request_body_type').on('change', function () {\n var model = requestBodyEditor.getModel();\n monaco_editor__WEBPACK_IMPORTED_MODULE_0__.editor.setModelLanguage(model, $(this).val());\n });\n var responseBodyEditor = monaco_editor__WEBPACK_IMPORTED_MODULE_0__.editor.create(target.find('.response_body')[0], {\n value: '',\n language: language,\n automaticLayout: true,\n quickSuggestions: false\n });\n me.responseEditors.push(responseBodyEditor);\n var consoleEditor = monaco_editor__WEBPACK_IMPORTED_MODULE_0__.editor.create(target.find('.console')[0], {\n value: '',\n automaticLayout: true,\n quickSuggestions: false\n });\n me.consoleEditors.push(consoleEditor);\n var preRequestEditor = monaco_editor__WEBPACK_IMPORTED_MODULE_0__.editor.create(target.find('.pre-request')[0], {\n value: model.preRequestScript,\n language: 'javascript',\n automaticLayout: true,\n quickSuggestions: false\n });\n var snippet1 = new _components_VariableSnippet__WEBPACK_IMPORTED_MODULE_4__[\"default\"]();\n snippet1.init(target.find('.pre-request-variable')[0], preRequestEditor);\n me.preRequestEditors.push(preRequestEditor);\n target.find('.pre-request')[0].addEventListener('shown.bs.tab', function () {\n me.preRequestEditors[index].layout();\n });\n me.preRequestEditors[index].onDidChangeModelContent(function (e) {\n model.preRequestScript = preRequestEditor.getValue();\n });\n var postRequestEditor = monaco_editor__WEBPACK_IMPORTED_MODULE_0__.editor.create(target.find('.post-request')[0], {\n value: model.postRequestScript,\n language: 'javascript',\n automaticLayout: true,\n quickSuggestions: false\n });\n var snippet2 = new _components_VariableSnippet__WEBPACK_IMPORTED_MODULE_4__[\"default\"]();\n snippet2.init(target.find('.post-request-variable')[0], postRequestEditor);\n me.postRequestEditors.push(postRequestEditor);\n target.find('.post-request')[0].addEventListener('shown.bs.tab', function () {\n me.postRequestEditors[index].layout();\n });\n me.postRequestEditors[index].onDidChangeModelContent(function (e) {\n model.postRequestScript = postRequestEditor.getValue();\n });\n }\n }, {\n key: \"renderResponse\",\n value: function renderResponse(tabIndex) {\n var _this4 = this;\n var model = this.apiRequests[tabIndex];\n var target = $('#api_request_' + model.id);\n target.find('.response_headers').empty();\n target.find('.response_status').empty();\n try {\n var parsedJson = JSON.parse(model.responseModel.body);\n var formattedJson = JSON.stringify(parsedJson, null, 2);\n this.responseEditors[tabIndex].setValue(formattedJson);\n } catch (e) {\n this.responseEditors[tabIndex].setValue(model.responseModel.body);\n }\n if (model.responseModel && model.responseModel.headers) {\n var headers = model.responseModel.headers;\n Object.entries(headers).forEach(function (_ref) {\n var _ref2 = _slicedToArray(_ref, 2),\n key = _ref2[0],\n value = _ref2[1];\n target.find('.response_headers').append(_this4.responseHeaderTemplate(key, value));\n });\n }\n target.find('.response_status').text('status: ' + model.responseModel.status);\n target.find('.response_time').text('time: ' + model.responseModel.time + 'ms');\n target.find('.response_size').text('size: ' + model.responseModel.size + 'bytes');\n }\n }, {\n key: \"customHelper\",\n value: function customHelper(event) {\n // Create and return the custom helper element\n var name = $(event.target).closest('.api_request_sortable').find('.open_api_request').text().trim();\n var apiId = $(event.target).closest('.api_request_sortable').data('id');\n return \"
    \\n
    \").concat(name, \"
    \\n
    \");\n }\n }, {\n key: \"renderCollections\",\n value: function renderCollections() {\n var select = $('#modal_collection');\n var sidemenu = $(this.collectionTarget);\n select.empty();\n sidemenu.empty();\n for (var i = 0; i < this.collections.length; i++) {\n sidemenu.append(this.renderCollection(this.collections[i], i));\n var option = $('