hazelcast 추가

This commit is contained in:
현성필
2024-12-31 15:12:51 +09:00
parent 79a264aa69
commit 895c0d5762
6 changed files with 410 additions and 29 deletions
+11 -5
View File
@@ -5,6 +5,7 @@ import VariableSnippet from './components/VariableSnippet';
import HTTPClientView from './components/HTTPClientView';
import TCPClientView from './components/TCPClientView';
import ServerManager from './components/ServerManager';
import HTTPFlatClientView from './components/HTTPFlatClientView';
class APITester {
@@ -398,9 +399,15 @@ class APITester {
requestBodyEditor = monaco.editor.create(target.find('.request_body')[0], {
value: model.requestBody, language: 'json', automaticLayout: true
});
}
if (model.type === 'TCP') {
} else if (model.type === 'HTTPFlat') {
let httpFlatClientView = new HTTPFlatClientView(me, this.serverManager, apiRequestTabContent, model);
httpFlatClientView.init();
target = this.openTab(model.id);
requestBodyEditor = monaco.editor.create(target.find('.request_body')[0], {
value: model.requestBody, language: 'json', automaticLayout: true
});
httpFlatClientView.requestBodyEditor = requestBodyEditor;
} else if (model.type === 'TCP') {
const tcpClientView = new TCPClientView(me, this.serverManager, apiRequestTabContent, model);
tcpClientView.init();
target = this.openTab(model.id);
@@ -408,7 +415,6 @@ class APITester {
requestBodyEditor = monaco.editor.create(target.find('.request_body')[0], {
value: model.requestBody, language: 'text', automaticLayout: true
});
tcpClientView.requestBodyEditor = requestBodyEditor;
}
@@ -832,7 +838,7 @@ class APITester {
};
newApi.collectionName = collection.name;
if (newApiType === 'TCP') {
if (newApiType === 'TCP' || newApiType === 'HTTPFlat') {
newApi.layout = { layoutItems : []};
}
@@ -54,22 +54,6 @@ class EditableInputView {
this.controller.additionalCallback(this.model.getValue());
}
});
// this.editableDiv.addEventListener('paste', (event) => {
// event.preventDefault();
// if (navigator.clipboard && navigator.clipboard.readText) {
// navigator.clipboard.readText().then(text => {
// this.insertTextAtCursor(text);
// }).catch(err => {
// console.error('Failed to read clipboard contents: ', err);
// // Fallback to using clipboardData from the paste event
// const text = (event.clipboardData || window.clipboardData).getData('text');
// this.insertTextAtCursor(text);
// });
// } else {
// const text = (event.clipboardData || window.clipboardData).getData('text');
// this.insertTextAtCursor(text);
// }
// });
this.editableDiv.addEventListener('paste', (event) => {
event.preventDefault();
let text = (event.clipboardData || window.clipboardData).getData('text/plain'); // Using 'text/plain' for compatibility
@@ -13,7 +13,7 @@ class HTTPClientView {
init() {
let me = this;
this.apiRequestTabContent.append(this.httpApiRequestTemplate(this.model, this.index));
let editableInput = new EditableInput({
let pathInput = new EditableInput({
name: 'path',
value: this.model.path
});
@@ -28,7 +28,7 @@ class HTTPClientView {
});
this.apiRequestTabContent.find(`#api_request_${this.model.id}`).find('.api_request_info').find('.path').each(function() {
editableInput.init(this, (value) => {
pathInput.init(this, (value) => {
me.model.path = value;
me.model.queryParams = me.parent.parseParam(me.model.path);
queryParamTable.setProperties(me.model.queryParams);
@@ -36,8 +36,8 @@ class HTTPClientView {
$('span.variable').off('mouseout');
document.querySelectorAll('span.variable').forEach(element => {
let text = element.innerText;
element.addEventListener('mouseover', () => this.parent.showPopper(element, text));
element.addEventListener('mouseout', () => this.parent.hidePopper(element));
element.addEventListener('mouseover', () => me.parent.showPopper(element, text));
element.addEventListener('mouseout', () => me.parent.hidePopper(element));
});
});
@@ -51,7 +51,7 @@ class HTTPClientView {
this.model.queryParams = properties;
console.log(this.model.queryParams);
this.buildPath(this.model);
editableInput.setValue(this.model.path);
pathInput.setValue(this.model.path);
$('span.variable').off('mouseover');
$('span.variable').off('mouseout');
document.querySelectorAll('span.variable').forEach(element => {
@@ -0,0 +1,390 @@
import LayoutGrid from './LayoutGrid';
import LayoutTreeGrid from './LayoutTreeGrid';
import LayoutTreeDataGrid from './LayoutTreeDataGrid';
import * as monaco from 'monaco-editor';
import ApiLayoutItemTreeBuilder from './ApiLayoutItemTreeBuilder';
import ApiLayoutItemTreeDataBuilder from './ApiLayoutItemTreeDataBuilder';
import EditableInput from './EditableInput';
import PropertyTable from './PropertyTable';
class HTTPFlatClientView {
constructor(parent, serverManager, apiRequestTabContent, model, index) {
this.parent = parent;
this.serverManager = serverManager;
this.apiRequestTabContent = apiRequestTabContent;
this.model = model;
this.index = index;
this.server = this.serverManager.getServer(this.model.server);
}
init() {
console.log('HTTPFlatClientView init');
this.apiRequestTabContent.append(this.httpFlatRequestTemplate(this.model, this.index));
let pathInput = new EditableInput({
name: 'path',
value: this.model.path
});
let queryParamTable = new PropertyTable({
propertyName: 'queryParams',
properties: this.model.queryParams
});
let headerTable = new PropertyTable({
propertyName: 'headers',
properties: this.model.headers
});
let me = this;
this.apiRequestTabContent.find(`#api_request_${this.model.id}`).find('.api_request_info').find('.path').each(function() {
pathInput.init(this, (value) => {
me.model.path = value;
me.model.queryParams = me.parent.parseParam(me.model.path);
queryParamTable.setProperties(me.model.queryParams);
$('span.variable').off('mouseover');
$('span.variable').off('mouseout');
document.querySelectorAll('span.variable').forEach(element => {
let text = element.innerText;
element.addEventListener('mouseover', () => me.parent.showPopper(element, text));
element.addEventListener('mouseout', () => me.parent.hidePopper(element));
});
});
$(this).append(`<label>Path</label>`);
$('span.variable').off('mouseover');
$('span.variable').off('mouseout');
});
queryParamTable.init(this.apiRequestTabContent.find(`#api_request_${this.model.id}`).find('.query_params')[0], (properties) => {
this.model.queryParams = properties;
console.log(this.model.queryParams);
this.buildPath(this.model);
pathInput.setValue(this.model.path);
$('span.variable').off('mouseover');
$('span.variable').off('mouseout');
document.querySelectorAll('span.variable').forEach(element => {
let text = element.innerText;
element.addEventListener('mouseover', () => this.parent.showPopper(element, text));
element.addEventListener('mouseout', () => this.parent.hidePopper(element));
});
});
headerTable.init(this.apiRequestTabContent.find(`#api_request_${this.model.id}`).find('.request_headers')[0], (properties) => {
this.model.headers = properties;
$('span.variable').off('mouseover');
$('span.variable').off('mouseout');
document.querySelectorAll('span.variable').forEach(element => {
let text = element.innerText;
element.addEventListener('mouseover', () => this.parent.showPopper(element, text));
element.addEventListener('mouseout', () => this.parent.hidePopper(element));
});
});
if (this.server && this.server.headers === undefined) {
this.server.headers = [];
}
let layoutJson = JSON.stringify(this.model.layout, null, 2);
this.layoutJsonEditor = monaco.editor.create(this.apiRequestTabContent.find(`#api_request_${this.model.id}`).find('.layout-json')[0], {
value: layoutJson, language: 'json', automaticLayout: true, quickSuggestions: false
});
const layoutDataTreeOptions = [
{name: 'loutItemSerno', width: 100, isFirst: true, label: '#'},
{name: 'loutItemName', width: 100, align: 'left', label: '항목명(영문)'},
{name: 'loutItemDesc', width: 100, align: 'left', label: '항목설명'},
{name: 'loutItemDepth', width: 60, align: 'center', label: '깊이'},
{name: 'loutItemType', width: 100, align: 'center', label: '아이템 유형'},
{name: 'loutItemOccCnt', width: 100, align: 'center', label: '반복 횟수'},
{name: 'loutItemOccRef', width: 120, align: 'center', label: '반복 참조 필드'},
{name: 'loutItemLength', width: 100, align: 'center', label: '데이터 길이'},
{name: 'value', width: 200, align: 'left', label: '값', type: 'textfield'}
];
let layoutRoot = ApiLayoutItemTreeBuilder.createTree(this.model.layout.layoutItems);
let replicator = new ApiLayoutItemTreeDataBuilder(10000);
let layoutDataRoot = replicator.createReplicatedTree(layoutRoot);
let layoutTreeDataGrid = new LayoutTreeDataGrid(this.apiRequestTabContent.find(`#api_request_${this.model.id}`).find('.request_layout_data_tree'), layoutDataRoot, this.model, layoutDataTreeOptions, this.apiRequestTabContent.find(`#api_request_${this.model.id}`).find('.total_message_length'));
layoutTreeDataGrid.init( async (finalMessage, layoutDataTree) => {
const prefix = (this.server && this.server.serverOptions) ? await this.serverManager.renderServerPrefix(this.server.serverOptions, this.model) : '';
this.requestBodyEditor.setValue(prefix + finalMessage);
this.model.layout.computedLayoutItemRoot = layoutDataTree;
$('span.variable').off('mouseover');
$('span.variable').off('mouseout');
document.querySelectorAll('span.variable').forEach(element => {
let text = element.innerText;
element.addEventListener('mouseover', () => this.parent.showPopper(element, text));
element.addEventListener('mouseout', () => this.parent.hidePopper(element));
});
});
let layoutTreeGrid = new LayoutTreeGrid(this.apiRequestTabContent.find(`#api_request_${this.model.id}`).find('.request_layout_tree'), layoutRoot, layoutDataTreeOptions, (root) => {
let replicator = new ApiLayoutItemTreeDataBuilder(10000);
let layoutDataRoot = replicator.createReplicatedTree(root);
layoutTreeDataGrid.rebuild(layoutDataRoot);
$('span.variable').off('mouseover');
$('span.variable').off('mouseout');
document.querySelectorAll('span.variable').forEach(element => {
let text = element.innerText;
element.addEventListener('mouseover', () => this.parent.showPopper(element, text));
element.addEventListener('mouseout', () => this.parent.hidePopper(element));
});
});
let layoutGrid = new LayoutGrid(this.apiRequestTabContent.find(`#api_request_${this.model.id}`).find('.request_layout'), this.model.layout, (model) => {
model.items.forEach((item) => {
item.children = [];
});
let updatedRoot = ApiLayoutItemTreeBuilder.createTree(model.items);
layoutTreeGrid.rebuild(updatedRoot, (root) => {
let replicator = new ApiLayoutItemTreeDataBuilder(10000);
let layoutDataRoot = replicator.createReplicatedTree(root);
layoutTreeDataGrid.rebuild(layoutDataRoot);
});
this.layoutJsonEditor.setValue(JSON.stringify(this.model.layout, null, 2));
$('span.variable').off('mouseover');
$('span.variable').off('mouseout');
document.querySelectorAll('span.variable').forEach(element => {
let text = element.innerText;
element.addEventListener('mouseover', () => this.parent.showPopper(element, text));
element.addEventListener('mouseout', () => this.parent.hidePopper(element));
});
});
this.apiRequestTabContent.find(`#api_request_${this.model.id}`).find('.load_layout').on('click', () => {
try {
this.model.layout = JSON.parse(this.layoutJsonEditor.getValue());
this.model.layout.layoutItems.forEach((item) => {
if (item.value === undefined){
item.value = '';
}
});
console.log(this.model);
layoutGrid.rebuild(this.model.layout);
} catch (e) {
console.error(e);
alert(e);
}
});
window.addEventListener('resize', this.resizeEditor.bind(this));
}
buildPath(model) {
let queryString = model.path.split('?')[0];
if (model.queryParams.length > 0) {
queryString += '?';
}
for (let i = 0; i < model.queryParams.length; i++) {
if (!model.queryParams[i].enabled) {
continue;
}
queryString += model.queryParams[i].key + '=' + model.queryParams[i].value;
if (i < model.queryParams.length - 1) {
queryString += '&';
}
}
model.path = queryString;
}
resizeEditor() {
this.requestBodyEditor.layout({
width: 0
});
this.requestBodyEditor.layout({});
this.layoutJsonEditor.layout({
width: 0
});
this.layoutJsonEditor.layout({});
}
httpFlatRequestTemplate(apiRequest, index) {
return `
<div class="tab-pane fade mt-1 api_request" id="api_request_${apiRequest.id}" style="height: 100%;">
<div><span class="collection_name">${apiRequest.collectionName}</span> &gt; <span class="api_name">${apiRequest.name}</span></div>
<div class="d-flex api_request_info">
<div class="form-floating">
<select name="method" class="form-select method" style="width: 90px; border-bottom-right-radius: 0;border-top-right-radius: 0;">
<option value="POST" ${apiRequest.method === 'POST' ? 'selected' : ''}>POST</option>
<option value="GET" ${apiRequest.method === 'GET' ? 'selected' : ''}>GET</option>
<option value="PUT" ${apiRequest.method === 'PUT' ? 'selected' : ''}>PUT</option>
<option value="DELETE" ${apiRequest.method === 'DELETE' ? 'selected' : ''}>DELETE</option>
<option value="CONNECT" ${apiRequest.method === 'CONNECT' ? 'selected' : ''}>CONNECT</option>
<option value="HEAD" ${apiRequest.method === 'HEAD' ? 'selected' : ''}>HEAD</option>
<option value="OPTIONS" ${apiRequest.method === 'OPTIONS' ? 'selected' : ''}>OPTIONS</option>
<option value="TRACE" ${apiRequest.method === 'TRACE' ? 'selected' : ''}>TRACE</option>
<option value="PATCH" ${apiRequest.method === 'PATCH' ? 'selected' : ''}>PATCH</option>
</select>
<label class="form-label must">Method</label>
</div>
<div class="form-floating">
${this.serverManager.renderHttpServers(apiRequest.server)}
<label class="form-label must">Server</label>
</div>
<div class="form-floating">
<input type="text" name="basePath" class="form-control" style="width: 180px; border-radius: 0" value="${this.serverManager.basePath(apiRequest.server)}" readonly>
<label class="must">기본 경로</label>
</div>
<div class="form-floating editableInput me-1 path" data-name="path" data-label="Path">
<label>Path</label>
</div>
<button class="btn btn-primary send me-1">Send</button>
<button class="btn btn-primary save" data-index="${index}" style="height: 58px;">저장</button>
</div>
<div class="api_request d-flex flex-column" style="height:100%;">
<div class="api_request_body">
<ul class="nav nav-tabs mt-1" role="tablist">
<li class="nav-item" role="presentation">
<button class="nav-link btn_request_body_tab" data-bs-toggle="tab"
type="button" role="tab" aria-controls="requestBody" data-bs-target="#requestBodyTab_${apiRequest.id}"
aria-selected="false">Layout
</button>
</li>
<li class="nav-item" role="presentation">
<button class="nav-link btn_layout_json_tab" data-bs-toggle="tab"
type="button" role="tab" aria-controls="layoutJson" data-bs-target="#requestLayoutJson_${apiRequest.id}"
aria-selected="false">Layout JSON
</button>
</li>
<li class="nav-item" role="presentation">
<button class="nav-link btn_layout_tree_tab" data-bs-toggle="tab"
type="button" role="tab" aria-controls="layoutTree" data-bs-target="#requestLayoutTreeTab_${apiRequest.id}"
aria-selected="false">Layout Tree
</button>
</li>
<li class="nav-item" role="presentation">
<button class="nav-link btn_request_body_data_tab" data-bs-toggle="tab"
type="button" role="tab" aria-controls="requestBodyData" data-bs-target="#requestBodyDataTab_${apiRequest.id}"
aria-selected="false">Layout Data
</button>
</li>
<li class="nav-item" role="presentation">
<button class="nav-link btn_request_param_tab" data-bs-toggle="tab"
type="button" role="tab" aria-controls="paramTab" data-bs-target="#requestParamTab_${apiRequest.id}"
aria-selected="true">Param
</button>
</li>
<li class="nav-item" role="presentation">
<button class="nav-link btn_request_header_tab" data-bs-toggle="tab"
type="button" role="tab" aria-controls="requestHeader" data-bs-target="#requestHeaderTab_${apiRequest.id}"
aria-selected="false">Header
</button>
</li>
<li class="nav-item" role="presentation">
<button class="nav-link btn_prerequest_tab" data-bs-toggle="tab"
type="button" role="tab" aria-controls="preScript" data-bs-target="#preRequestTab_${apiRequest.id}"
aria-selected="false">Pre-Request
</button>
</li>
<li class="nav-item" role="presentation">
<button class="nav-link btn_postrequest_tab" data-bs-toggle="tab"
type="button" role="tab" aria-controls="postScript" data-bs-target="#postRequestTab_${apiRequest.id}"
aria-selected="false">Post-Request
</button>
</li>
</ul>
<div class="tab-content" style="height: 100%;">
<div class="tab-pane fade request_layout_json_tab" role="tabpanel" id="requestLayoutJson_${apiRequest.id}" aria-labelledby="requestLayoutJson-tab">
<div class="d-flex flex-column">
<div style="width:calc(100%);">
<div class="layout-json mt-1" style="height:300px;border:1px solid grey;"></div>
</div>
<button class="btn btn-primary mt-1 load_layout">레이아웃 불러오기</button>
</div>
</div>
<div class="tab-pane show fade request_body_tab" role="tabpanel" id="requestBodyTab_${apiRequest.id}" aria-labelledby="requestBody-tab">
<div class="d-flex flex-column">
<div class="request_layout" style="border:1px solid grey; overflow: scroll"></div>
</div>
</div>
<div class="tab-pane show fade request_layout_tree_tab" role="tabpanel" id="requestLayoutTreeTab_${apiRequest.id}" aria-labelledby="requestLayoutTree-tab">
<div class="d-flex flex-column">
<div class="request_layout_tree" style="border:1px solid grey; overflow: scroll"></div>
</div>
</div>
<div class="tab-pane show fade request_body_data_tab" role="tabpanel" id="requestBodyDataTab_${apiRequest.id}" aria-labelledby="requestBodyData-tab">
<div class="d-flex flex-column">
<div class="request_layout_data_tree" style="border:1px solid grey; overflow: scroll"></div>
</div>
</div>
<div class="tab-pane fade show request_param_tab" role="tabpanel" id="requestParamTab_${apiRequest.id}" aria-labelledby="requestParams-tab">
<div class="query_params">
</div>
</div>
<div class="tab-pane fade request_header_tab" role="tabpanel" id="requestHeaderTab_${apiRequest.id}"
aria-labelledby="requestHeader-tab">
<div class="request_headers">
</div>
</div>
<div class="tab-pane fade pre_script_tab" role="tabpanel" id="preRequestTab_${apiRequest.id}" aria-labelledby="preScript-tab">
<div class="d-flex flex-row">
<div style="width:calc(100% - 200px);">
<div class="pre-request mt-1" style="height:300px;border:1px solid grey;"></div>
</div>
<div style="width: 200px;">
<div class="pre-request-variable">
</div>
</div>
</div>
</div>
<div class="tab-pane fade post_script_tab" role="tabpanel" id="postRequestTab_${apiRequest.id}"
aria-labelledby="postScrit-tab">
<div class="d-flex flex-row">
<div style="width:calc(100% - 200px);">
<div class="post-request mt-1" style="height:300px;border:1px solid grey;"></div>
</div>
<div style="width: 200px;">
<div class="post-request-variable">
</div>
</div>
</div>
</div>
</div>
</div>
<div class="request_body mt-1" style="height: 150px; border:1px solid grey;"></div>
<div class="api_request_info" >
<span>전체 메시지 길이: </span>
<span class="total_message_length"></span>
</div>
<div class="api_request_info">
</div>
<div class="api_response" style="flex: 1">
<div class="mt-1">
<span>Response</span>
<span class="response_time"></span>
<span class="response_size"></span>
</div>
<ul class="nav nav-tabs mt-1" role="tablist">
<li class="nav-item" role="presentation">
<button class="nav-link active" data-bs-toggle="tab" data-bs-target="#responseBodyTab_${apiRequest.id}" type="button" role="tab" aria-controls="responseBody" aria-selected="false">Body</button>
</li>
<li class="nav-item" role="presentation">
<button class="nav-link" data-bs-toggle="tab" data-bs-target="#consoleTab_${apiRequest.id}" type="button" role="tab" aria-controls="consoleTab" aria-selected="false">Console</button>
</li>
</ul>
<div class="tab-content border-bottom" style="min-height: 250px;">
<div class="tab-pane fade show active" id="responseBodyTab_${apiRequest.id}" role="tabpanel"
aria-labelledby="responseParams-tab">
<div class="response_body mt-1" style="width:100%;height:250px;border:1px solid grey;"></div>
</div>
<div class="tab-pane fade" id="consoleTab_${apiRequest.id}" role="tabpanel"
aria-labelledby="console-tab">
<div class="console mt-1" style="width:100%;height:250px;border:1px solid grey;"></div>
</div>
</div>
</div>
</div>
</div>
`;
}
}
export default HTTPFlatClientView;
@@ -23,7 +23,7 @@ class TCPClientView {
if (this.server && this.server.headers === undefined) {
this.server.headers = [];
}
if (this.server) {
if (this.server && this.server.serverOptions) {
this.serverManager.renderTcpServerOptions('.server_options', this.server.serverOptions, this.model.headers, this.parent);
}
@@ -50,7 +50,7 @@ class TCPClientView {
let layoutTreeDataGrid = new LayoutTreeDataGrid(this.apiRequestTabContent.find(`#api_request_${this.model.id}`).find('.request_layout_data_tree'), layoutDataRoot, this.model, layoutDataTreeOptions, this.apiRequestTabContent.find(`#api_request_${this.model.id}`).find('.total_message_length'));
layoutTreeDataGrid.init( async (finalMessage, layoutDataTree) => {
const prefix = this.server.serverOptions ? await this.serverManager.renderServerPrefix(this.server.serverOptions, this.model) : '';
const prefix = (this.server && this.server.serverOptions) ? await this.serverManager.renderServerPrefix(this.server.serverOptions, this.model) : '';
this.requestBodyEditor.setValue(prefix + finalMessage);
this.model.layout.computedLayoutItemRoot = layoutDataTree;
+2 -1
View File
@@ -48,7 +48,8 @@ dependencies {
// implementation 'io.springfox:springfox-boot-starter:3.0.0'
implementation 'org.apache.httpcomponents:httpclient:4.5.14'
implementation 'com.hazelcast:hazelcast:4.2.8'
implementation 'com.hazelcast:hazelcast-spring:4.2.8'
// implementation("org.graalvm.polyglot:polyglot:24.1.0")
// implementation("org.graalvm.polyglot:js:24.1.0")