import * as monaco from 'monaco-editor'; import APIScenarioExecutor from './APIScenarioExecutor'; import Drawflow from 'drawflow'; class APIScenario { constructor(apiTester, contextPath) { this.scenarioList = []; this.currentScenario = null; this.apiTester = apiTester; this.contextPath = contextPath || '/'; } getAPIScenarioListURL() { return this.contextPath + 'mgmt/api_scenario/list.do'; } getAPIScenarioCreateURL() { return this.contextPath + 'mgmt/api_scenario/create.do'; } getAPIScenarioUpdateURL() { return this.contextPath + 'mgmt/api_scenario/update.do'; } getAPIScenarioDeleteURL() { return this.contextPath + 'mgmt/api_scenario/delete.do'; } init() { this.loadScenarioList(); this.outputEditor = monaco.editor.create(document.getElementById('output'), { value: '', automaticLayout: true }); this.bindEvents(); let id = document.getElementById('drawflow'); this.editor = new Drawflow(id); this.editor.reroute = true; this.editor.reroute_fix_curvature = true; this.editor.force_first_input = true; this.editor.start(); // this.editor.on('contextmenu', (event) => { // let node = this.editor.getNodeFromId(event.target.id); // }) this.showOutput = true; } loadScenarioList(callback) { const me = this; this.currentAjaxRequest = $.ajax({ url: this.getAPIScenarioListURL(), type: 'GET', contentType: 'application/json', success: function(data) { me.scenarioList = data; let drawflowData = {drawflow: {Home: {data: {}}}}; data.forEach((scenario) => { let scenarioData = null; try { scenarioData = JSON.parse(scenario.scenario); } catch (e) { scenarioData = {}; } drawflowData.drawflow[scenario.id] = {data: scenarioData}; }); me.editor.import(drawflowData); me.editor.changeModule('Home'); }, error: function(response, textStatus, errorThrown) { me.hideLoadingOverlay(); $('.toast-body').text(response.responseJSON.error); $('.toast').toast('show'); }, complete: function() { me.renderScenarioList(); if (callback) { callback(); } me.hideLoadingOverlay(); } }); } getScenarioList() { return this.scenarioList; } openScenario(event) { event.preventDefault(); let scenarioId = $(event.target).closest('li').data('id'); this.stopScenario(); this.openScenarioById(scenarioId); } openScenarioById(scenarioId) { document.querySelectorAll('.api-scenario-list li').forEach((node) => { node.classList.remove('selected'); }); //find li by data-id and add class selected document.querySelector(`.api-scenario-list li[data-id="${scenarioId}"]`).classList.add('selected'); this.editor.changeModule(scenarioId); this.currentScenario = scenarioId; } getScenario(scenarioId) { return this.getScenarioList().find((scenario) => scenario.id === scenarioId); } showLoadingOverlay() { $('#loading-overlay').show(); } hideLoadingOverlay() { $('#loading-overlay').hide(); } showNewScenarioModal() { $('#new_scenario_modal').find('input').val(''); $('#new_scenario_modal').modal('show'); } createScenario() { const name = $('#new_scenario_name').val(); const me = this; me.showLoadingOverlay(); this.currentAjaxRequest = $.ajax({ url: this.getAPIScenarioCreateURL(), type: 'POST', contentType: 'application/json', data: JSON.stringify({name: name, scenario: '{}', description: ''}), success: function(data) { me.loadScenarioList(() => { me.openScenarioById(data.id); let start = `
Start
`; me.editor.addNode('Start', 0, 1, 100, 100, 'start', {}, start); me.saveScenario(); }); }, error: function(response, textStatus, errorThrown) { me.hideLoadingOverlay(); $('.toast-body').text(response.responseJSON.error); $('.toast').toast('show'); }, complete: function() { me.hideLoadingOverlay(); $('#new_scenario_modal').modal('hide'); } }); } saveScenario() { if (this.currentScenario !== null) { let data = this.editor.export(); console.log(data.drawflow[this.currentScenario].data); let updatedScenario = this.getScenario(this.currentScenario); updatedScenario.scenario = JSON.stringify(data.drawflow[this.currentScenario].data); const me = this; me.showLoadingOverlay(); this.currentAjaxRequest = $.ajax({ url: this.getAPIScenarioUpdateURL(), type: 'POST', contentType: 'application/json', data: JSON.stringify(updatedScenario), error: function(response, textStatus, errorThrown) { me.hideLoadingOverlay(); $('.toast-body').text(response.responseJSON.error); $('.toast').toast('show'); }, complete: function() { me.hideLoadingOverlay(); $('.toast-body').text('저장되었습니다.'); $('.toast').toast('show'); } }); } } showDeleteModal(event) { const id = $(event.currentTarget).closest('li').data('id'); $('#confirm_delete_scenario_modal').find('.confirm_delete_scenario').data('id', id); $('#confirm_delete_scenario_modal').modal('show'); } removeScenario(event) { const id = $(event.currentTarget).data('id'); const me = this; me.showLoadingOverlay(); this.currentAjaxRequest = $.ajax({ url: this.getAPIScenarioDeleteURL(), type: 'POST', contentType: 'application/json', data: JSON.stringify({id: id}), error: function(response, textStatus, errorThrown) { me.hideLoadingOverlay(); $('.toast-body').text(response.responseJSON.error); $('.toast').toast('show'); }, complete: function() { me.hideLoadingOverlay(); $('#confirm_delete_scenario_modal').modal('hide'); $('.toast-body').text('삭제되었습니다.'); $('.toast').toast('show'); me.editor.changeModule('Home'); me.loadScenarioList(() => { if (me.getScenarioList().length > 0) { me.openScenarioById(me.getScenarioList()[0].id); } }); } }); } toggleOutput() { // Define your selectors as constants for easy changes and better readability const scenarioContentSelector = '.api-scenario-content'; const scenarioOutputSelector = '.api-scenario-output'; const scenarioOutputBodySelector = '.api-scenario-output-body'; const drawflowSelector = '#drawflow'; const scenarioEditorSelector = '.scenario_editor'; // Ensure parentHeight is a number let parentHeight = parseInt($(scenarioContentSelector).css('height'), 10); // Toggle the showOutput state this.showOutput = !this.showOutput; if (!this.showOutput) { $(scenarioOutputSelector).css('flex', '0'); $(scenarioOutputBodySelector).hide(); let editorHeight = $(scenarioEditorSelector).css('height'); $(drawflowSelector).css('height', editorHeight); $(scenarioOutputSelector).removeClass('halfHeight'); $(drawflowSelector).removeClass('halfHeight'); } else { $(scenarioOutputSelector).css('flex', '1'); $(scenarioOutputSelector).addClass('halfHeight'); $(scenarioOutputBodySelector).show(); $(drawflowSelector).addClass('halfHeight'); $(drawflowSelector).css('height', parentHeight / 2); } // Adjustments for when parentHeight isn't a valid number if (isNaN(parentHeight)) { console.error('parentHeight is not a number. Check the height of the api-scenario-content element.'); // Fallback or additional error handling can be placed here } } resizeEditor() { //FIXME: 창 크기 변경시 자동으로 editor 크기가 조정되지 않아서, 0으로 강제 변경후 다시 layout() 호출 this.outputEditor.layout({ width: 0 }); this.outputEditor.layout({}); } runScript() { console.log(this.editor.export().drawflow); let graph = APIScenarioExecutor.extractGraphFromStart(this.editor.export().drawflow[this.currentScenario].data); this.executor = new APIScenarioExecutor(graph, this.apiTester, this.outputEditor); } runScenarioAll() { if (!this.executor) { this.runScript(); } if (!this.executor.isDone) { this.executor.executeAll(); } else { this.executor.reset(); } } runScenarioStep() { if (!this.executor) { this.runScript(); } if (!this.executor.isDone) { this.executor.executeCurrentNode(); this.executor.moveToNextNode(); } else { this.executor.reset(); } } resetScenario() { } pauseScenario() { } stopScenario() { if (this.executor) { this.executor.reset(); this.executor = null; } this.outputEditor.setValue(''); } addStart() { let start = `
Start
`; this.editor.addNode('Start', 0, 1, 100, 100, 'start', {}, start); } bindEvents() { const events = [ {type: 'click', selector: '.open_scenario', action: this.openScenario.bind(this)}, {type: 'click', selector: '.export', action: this.runScript.bind(this)}, {type: 'click', selector: '.toggle_output', action: this.toggleOutput.bind(this)}, {type: 'click', selector: '.run_scenario_step', action: this.runScenarioStep.bind(this)}, {type: 'click', selector: '.run_scenario_all', action: this.runScenarioAll.bind(this)}, {type: 'click', selector: '.reset_scenario', action: this.resetScenario.bind(this)}, {type: 'click', selector: '.pause_scenario', action: this.pauseScenario.bind(this)}, {type: 'click', selector: '.stop_scenario', action: this.stopScenario.bind(this)}, {type: 'click', selector: '#new_scenario', action: this.showNewScenarioModal.bind(this)}, {type: 'click', selector: '.create_scenario', action: this.createScenario.bind(this)}, {type: 'click', selector: '.save_scenario', action: this.saveScenario.bind(this)}, // {type: 'click', selector: '.add_start', action: this.addStart.bind(this)}, {type: 'click', selector: '.delete_scenario', action: this.showDeleteModal.bind(this)}, {type: 'click', selector: '.confirm_delete_scenario', action: this.removeScenario.bind(this)}, {type: 'click', selector: '.stop_scenario', action: this.stopScenario.bind(this)} ]; for (let event of events) { $(document).on(event.type, event.selector, event.action); } window.addEventListener('resize', this.resizeEditor.bind(this)); var me = this; $('#drawflow').droppable({ drop: function(event, ui) { const x = ui.offset.left - $(this).offset().left; const y = ui.offset.top - $(this).offset().top; const dataset = ui.draggable[0].dataset; console.log(dataset); var node = `
API
${dataset.name}
`; me.editor.addNode(dataset.name, 1, 1, x, y, dataset.nodeType, dataset, node); } }); } scenarioListTemplate(scenario) { return `
  • ${scenario.name}
  • `; } renderScenarioList() { let scenarioList = this.getScenarioList(); let scenarioListHtml = scenarioList.map((scenario) => this.scenarioListTemplate(scenario)).join(''); $('.api-scenario-list').html(scenarioListHtml); let nodes = document.querySelectorAll('.api-scenario-list li'); nodes.forEach((node) => { if ($(node).data('id') === this.currentScenario) { node.classList.add('selected'); } }); } } export default APIScenario;