var gojs = (function () { "use strict"; var myDiagram; let isLinkDeletion = false; let armsStateArray; function init() { // Since 2.2 you can also author concise templates with method chaining instead of GraphObject.make // For details, see https://gojs.net/latest/intro/buildingObjects.html const $ = go.GraphObject.make; // for conciseness in defining templates myDiagram = new go.Diagram('myDiagramDiv', { allowCopy: false, layout: $(go.LayeredDigraphLayout, { setsPortSpots: false, // Links already know their fromSpot and toSpot columnSpacing: 5, isInitial: false, isOngoing: false, }), validCycle: go.CycleMode.NotDirected, 'undoManager.isEnabled': true, "maxSelectionCount": 1, // �ㅼ쨷 �좏깮 鍮꾪솢�� }); // when the document is modified, add a "*" to the title and enable the "Save" button myDiagram.addDiagramListener('Modified', (e) => { const button = document.getElementById('mapping_save_button'); if (button) button.disabled = !myDiagram.isModified; const idx = document.title.indexOf('*'); if (myDiagram.isModified) { if (idx < 0) document.title += '*'; } else { if (idx >= 0) document.title = document.title.slice(0, idx); } }); // const graygrad = $(go.Brush, 'Linear', { 0: 'white', 0.1: 'whitesmoke', 0.9: 'whitesmoke', 1: 'lightgray' }); // �몃뱶 諛뺤뒪 諛곌꼍�� const graygrad = $(go.Brush, 'Linear', { 0: 'rgba(51, 51, 51, 0)', 0.1: 'rgba(51, 51, 51, 0.1)', 0.9: 'rgba(51, 51, 51, 0.9)', 1: 'rgba(51, 51, 51, 1)' }); // �몃뱶 諛뺤뒪 �뚮몢由� const lightGray = 'rgba(128, 128, 128, 0.5)'; // �먮┛ �뚯깋 (�щ챸�� 50%) myDiagram.nodeTemplate = // the default node template $(go.Node, { movable: false }, 'Spot', { selectionAdorned: false, textEditable: false, locationObjectName: 'BODY' }, new go.Binding('location', 'loc', go.Point.parse).makeTwoWay(go.Point.stringify), // { // doubleClick: (e, node) => { // // �붾툝 �대┃ �� �ㅽ뻾�� 硫붿냼�� �몄텧 // console.log(node.data.c_id); // popup_modal('update_popup', node.data.c_id); // } // }, $(go.Panel, 'Auto', { name: 'BODY' }, $(go.Shape, 'RoundedRectangle', { fill: graygrad, stroke: lightGray, minSize: new go.Size(100, 30) }, new go.Binding('fill', 'isSelected', (s) => (s ? 'dodgerblue' : graygrad)).ofObject() ), $(go.Panel, 'Horizontal', { alignment: go.Spot.Left, margin: 3 }, $(go.Picture, { source: "/arms/img/arms.png", // �꾩씠肄� �대�吏� 寃쎈줈 width: 20, height: 20, margin: new go.Margin(0, 0, 0, 4) }), $(go.TextBlock, { stroke: 'white', font: '12px sans-serif', margin: new go.Margin(3, 4, 3, 4), // �곸젅�� 留덉쭊 �ㅼ젙 alignment: go.Spot.Left, editable: true, textEdited: function(textBlock, oldText, newText) { // 以꾨컮轅� 臾몄옄瑜� �쒓굅 textBlock.text = newText.replace(/\r?\n|\r/g, ''); if (textBlock.text.trim() === "") { jNotify("鍮� 媛믪쑝濡쒕뒗 �곹깭紐낆쓣 蹂�寃쏀븷 �� �놁뒿�덈떎."); textBlock.text = oldText; } }, }, new go.Binding('text').makeTwoWay() ), $(go.Shape, "Rectangle", // �ㅽ럹�댁꽌 ��븷�� �� �щ챸�� �꾪삎 異붽� { stroke: null, fill: "transparent", stretch: go.GraphObject.Horizontal, // �⑤꼸�� �섎㉧吏� 怨듦컙�� 梨꾩썙�� 諛��대깂 width: 1, height: 1 } ), // $(go.Shape, // { // figure: "XLine", // width: 8, // height: 8, // stroke: "rgba(255, 255, 255, 0.45)", // strokeWidth: 2, // �먭퍡 // margin: new go.Margin(0, 0, 0, 0), // cursor: "pointer", // alignment: go.Spot.Right, // click: function(e, obj) { // // �곹깭 ��젣 �뺤씤 �앹뾽 �몄텧 // const node = obj.part; // const state_name = node.data.text; // const state_c_id = node.data.c_id; // popup_modal('delete_popup', state_c_id, state_name); // } // } // ) /* $(go.TextBlock, { stroke: 'white', font: '12px sans-serif', editable: true, margin: new go.Margin(3, 4, 3, 4), // �곸젅�� 留덉쭊 �ㅼ젙 alignment: go.Spot.Left, }, new go.Binding('text').makeTwoWay() )*/ ) ), // output port $(go.Panel, 'Auto', { alignment: go.Spot.Right, portId: 'from', fromLinkable: true, cursor: 'pointer', click: (e, obj) => { if (obj.part.data.category !== 'NoAdd') { addNodeAndLink(e, obj); } }}, $(go.Shape, 'Diamond', { width: 11, height: 11, fill: 'white', stroke: graygrad, strokeWidth: 3 }), // $(go.Shape, 'PlusLine', new go.Binding('visible', '', (data) => data.category !== 'NoAdd').ofObject(), { width: 11, height: 11, fill: null, stroke: 'dodgerblue', strokeWidth: 3 }) ), // input port $(go.Panel, 'Auto', { alignment: go.Spot.Left, portId: 'to', toLinkable: true }, $(go.Shape, 'Ellipse', { width: 9, height: 9, fill: 'white', stroke: graygrad, strokeWidth: 3 }), $(go.Shape, 'Ellipse', { width: 6, height: 6, fill: 'white', stroke: null }) ) ); // �고겢由� �대깽�� 由ъ뒪�� myDiagram.addDiagramListener("ObjectContextClicked", function (e) { let element = e.subject.part; if (element) { let data = element.data; // �좏깮�� �붿냼�� �곗씠�� // �붿뒪 �곹깭留� 泥섎━ if (data.type === "arms-state") { let stateId = data.c_id; // armsStateArray�먯꽌 �대떦 stateId媛� �덈뒗吏� �뺤씤 let foundState = armsStateArray.find(item => item.c_id == stateId); if (foundState) { console.log("State found in armsStateArray:", foundState); let contextMenu = element.part.contextMenu; let deleteNodeButton = contextMenu ? contextMenu.findObject("deleteNodeButton") : null; let buttonShape = deleteNodeButton ? deleteNodeButton.findObject("buttonShape") : null; if (!deleteNodeButton || !buttonShape) return; // 踰꾪듉�� �놁쑝硫� 醫낅즺 // ��젣 踰꾪듉 鍮꾪솢�깊솕 �먮뒗 �쒖꽦�� if (foundState.c_check === "true") { disableButton(deleteNodeButton, "deleteText"); } else { enableButton(deleteNodeButton, deleteNode, "deleteText"); } } } else if (element instanceof go.Link) { let data = element.data; let contextMenu = element.part.contextMenu; let deleteLinkButton = contextMenu ? contextMenu.findObject("deleteLinkButton") : null; if (!deleteLinkButton) return; // 踰꾪듉�� �놁쑝硫� 醫낅즺 const isDisableButton = data.toNode.type === "arms-state" && data.toNode.c_check === "true"; if (isDisableButton) { disableButton(deleteLinkButton, "deleteLinkText"); } else { enableButton(deleteLinkButton, deleteLinkClick, "deleteLinkText"); } } } }); // 踰꾪듉 鍮꾪솢�깊솕 function disableButton(button, textObjectName) { button.click = null; // �대┃ 鍮꾪솢�깊솕 let textBlock = button.findObject(textObjectName); if (textBlock) { textBlock.stroke = "gray"; // �띿뒪�� 鍮꾪솢�깊솕 �됱긽 } button.mouseEnter = null; button.mouseLeave = null; } // 踰꾪듉 �쒖꽦�� function enableButton(button, clickHandler, textObjectName) { button.click = clickHandler; // �대┃ �쒖꽦�� let textBlock = button.findObject(textObjectName); if (textBlock) { textBlock.stroke = "white"; // �쒖꽦�붾맂 �띿뒪�� �됱긽 } button.mouseEnter = (e, obj) => { let shape = obj.findObject("buttonShape"); if (shape) shape.fill = "dodgerblue"; // 留덉슦�� �몃쾭 �� �됱긽 }; button.mouseLeave = (e, obj) => { let shape = obj.findObject("buttonShape"); if (shape) shape.fill = "rgba(51, 51, 51, 0.8)"; // 湲곕낯 諛곌꼍 �됱긽 }; } myDiagram.nodeTemplate.contextMenu = $(go.Adornment, "Auto", $(go.Panel, "Vertical", $("ContextMenuButton", $(go.Shape, "Rectangle", { fill: "rgba(51, 51, 51, 0.8)", stroke: null, name: "buttonShape", width: 50, height: 20, }), $(go.TextBlock, "�섏젙", { font: "12px", stroke: "white", margin: new go.Margin(0, 3, 0, 3), } ), { click: renameNode, "ButtonBorder.stroke": null, "ButtonBorder.fill": "rgba(51, 51, 51, 0.8)", mouseEnter: (e, obj) => { let shape = obj.findObject("buttonShape"); if (shape) shape.fill = "dodgerblue"; }, mouseLeave: (e, obj) => { let shape = obj.findObject("buttonShape"); if (shape) shape.fill = "rgba(51, 51, 51, 0.8)"; } } ), $("ContextMenuButton", $(go.Shape, "Rectangle", { fill: "rgba(51, 51, 51, 0.8)", stroke: null, name: "buttonShape", width: 50, height: 20 }), $(go.TextBlock, "��젣", { name: "deleteText", font: "12px", stroke: "white", margin: new go.Margin(0, 3, 0, 3), } ), { name: "deleteNodeButton", click: deleteNode, "ButtonBorder.stroke": null, "ButtonBorder.fill": "rgba(51, 51, 51, 0.8)", mouseEnter: (e, obj) => { let shape = obj.findObject("buttonShape"); if (shape) shape.fill = "dodgerblue"; }, mouseLeave: (e, obj) => { let shape = obj.findObject("buttonShape"); if (shape) shape.fill = "rgba(51, 51, 51, 0.8)"; } } ) ) ); function renameNode(e, obj) { const node = obj.part.adornedPart; if (node) { console.log(node.data.c_id); let state_c_id = node.data.c_id; popup_modal("update_popup", state_c_id); } } function deleteNode(e, obj) { const node = obj.part.adornedPart; if (node) { let state_c_id = node.data.c_id; let state_name = node.data.text; console.log(state_name); popup_modal("delete_popup", state_c_id, state_name); } } // ARMS 移댄뀒怨좊━ �몃뱶 �ㅼ젙 myDiagram.nodeTemplateMap.add( 'Loading', $(go.Node, { movable: false }, 'Spot', { selectionAdorned: false, textEditable: true, locationObjectName: 'BODY' }, new go.Binding('location', 'loc', go.Point.parse).makeTwoWay(go.Point.stringify), // the main body consists of a Rectangle surrounding the text $(go.Panel, 'Auto', { name: 'BODY' }, $(go.Shape, 'RoundedRectangle', { fill: graygrad, stroke: lightGray, minSize: new go.Size(100, 30) }, new go.Binding('fill', 'isSelected', (s) => (s ? 'dodgerblue' : graygrad)).ofObject() ), $(go.Panel, 'Horizontal', { alignment: go.Spot.Left, margin: 3 }, /*$(go.Picture, { source: "/arms/img/arms.png", // �꾩씠肄� �대�吏� 寃쎈줈 width: 20, height: 20, margin: new go.Margin(0, 0, 0, 0) }), $(go.TextBlock, { stroke: 'white', font: '12px sans-serif', editable: false, margin: new go.Margin(3, 4, 3, 4), // �곸젅�� 留덉쭊 �ㅼ젙 alignment: go.Spot.Left, }, new go.Binding('text').makeTwoWay() )*/ $(go.TextBlock, // 移댄뀒怨좊━ 蹂� �꾩씠肄� �ㅼ젙(�섎뱶肄붾뵫) { font: "12px FontAwesome, sans-serif", // �꾩씠肄섏뿉 FontAwesome �ъ슜 margin: new go.Margin(0, 8, 0, 8), // �꾩씠肄섍낵 �띿뒪�� �ъ씠�� 媛꾧꺽 �ㅼ젙 }, new go.Binding("text", "", function(data) { let icon = ""; if (data.c_id === "3") { icon = "��"; } else if (data.c_id === "4") { icon = "��"; } else if (data.c_id === "5") { icon = "��"; } else if (data.c_id === "6") { icon = "��"; } return " " + icon; }), // 移댄뀒怨좊━ 蹂� �됱긽 �ㅼ젙 new go.Binding("stroke", "", function(data) { let color = "white"; if (data.c_id === "3") { color = "#DB2A34"; } else if (data.c_id === "4") { color = "#E49400"; } else if (data.c_id === "5") { color = "#2D8515"; } else if (data.c_id === "6") { color = "#2477FF"; } return color; }) ), // 移댄뀒怨좊━紐� $(go.TextBlock, { stroke: "white", // �띿뒪�� �됱긽 font: "12px sans-serif" }, new go.Binding("text", "", function(data) { return " " + data.text; }) ) ) ), // output port $(go.Panel, 'Auto', { alignment: go.Spot.Right, portId: 'from', fromLinkable: true, cursor: 'pointer', click: (e, obj) => { if (obj.part.data.category !== 'NoAdd') { addNodeAndLink(e, obj); } }}, $(go.Shape, 'Diamond', { width: 11, height: 11, fill: 'white', stroke: graygrad, strokeWidth: 3 }), // $(go.Shape, 'PlusLine', new go.Binding('visible', '', (data) => data.category !== 'Loading').ofObject(), { width: 11, height: 11, fill: null, stroke: 'dodgerblue', strokeWidth: 3 }) ), ) ); myDiagram.nodeTemplateMap.add( 'End', $(go.Node, { movable: false }, 'Spot', { selectionAdorned: false, textEditable: true, locationObjectName: 'BODY' }, new go.Binding('location', 'loc', go.Point.parse).makeTwoWay(go.Point.stringify), // the main body consists of a Rectangle surrounding the text $(go.Panel, 'Auto', { name: 'BODY' }, $(go.Shape, 'RoundedRectangle', { fill: graygrad, stroke: lightGray, minSize: new go.Size(100, 30) }, new go.Binding('fill', 'isSelected', (s) => (s ? 'dodgerblue' : graygrad)).ofObject() ), $(go.Panel, 'Horizontal', { alignment: go.Spot.Left, margin: 3 }, $(go.Picture, { width: 20, height: 20, margin: new go.Margin(0, 0, 0, 4) }, new go.Binding('source', 'server_type', function(type) { console.log(type); switch(type) { case '�대씪�곕뱶': return '/arms/img/commonIconPack/jira/mark-gradient-white-jira.svg'; case '�⑦봽�덈���': return '/arms/img/commonIconPack/jira/mark-gradient-blue-jira.svg'; case '�덈뱶留덉씤_�⑦봽�덈���': return '/arms/img/community_devtool/redmine_logo.png'; default: return ''; } }) ), $(go.TextBlock, { stroke: 'white', font: '12px sans-serif', editable: false, margin: new go.Margin(3, 3 + 11, 3, 3 + 4), alignment: go.Spot.Left, }, new go.Binding('text', 'text') ) ) ), // input port $(go.Panel, 'Auto', { alignment: go.Spot.Left, portId: 'to', toLinkable: true }, $(go.Shape, 'Ellipse', { width: 9, height: 9, fill: 'white', stroke: graygrad, strokeWidth: 3 }), $(go.Shape, 'Ellipse', { width: 6, height: 6, fill: 'white', stroke: null }) ) ) ); // �몃뱶 �곕젅湲고넻 �곸뿭 二쇱꽍 /*myDiagram.nodeTemplateMap.add( 'Recycle', $(go.Node, 'Auto', { portId: 'to', toLinkable: true, deletable: false, layerName: 'Background', locationSpot: go.Spot.Center, }, new go.Binding('location', 'loc', go.Point.parse).makeTwoWay(go.Point.stringify), { dragComputation: (node, pt, gridpt) => pt, mouseDrop: (e, obj) => e.diagram.commandHandler.deleteSelection(), }, $(go.Shape, { fill: 'lightgray', stroke: 'gray' }), $(go.TextBlock, 'Drop Here\nTo Delete', { margin: 5, textAlign: 'center' }) ) );*/ function addNodeAndLink(e, obj) { const fromNode = obj.part; const diagram = fromNode.diagram; diagram.startTransaction('Add State'); // get the node data for which the user clicked the button const fromData = fromNode.data; const category = fromData.category; const c_id = fromData.c_id; const type = fromData.type; if (category === "NoAdd" || category === "Loading") { // NoAdd, Loading 移댄뀒怨좊━ �몃뱶�� 寃쎌슦 Node�� �앹꽦 紐삵븯�꾨줉 泥섎━ diagram.commitTransaction('Add Node'); return; } // else { // if (!confirm(fromData.text + " 移댄뀒怨좊━ �곹깭瑜� 異붽��섏떆寃좎뒿�덇퉴?")) { // return; // } // } // create a new "State" data object, positioned off to the right of the fromNode const p = fromNode.location.copy(); p.x += diagram.toolManager.draggingTool.gridSnapCellSize.width; /* const toData = { text: 'new', loc: go.Point.stringify(p), };*/ let toData; if (type === 'arms-category') { toData = { key: 'arms-state-' + (diagram.model.nodeDataArray.length + 1), text: '�좉퇋 �곹깭', isNew: true, type: 'arms-state', mapping_id: fromData.c_id, category: 'NoAdd', loc: go.Point.stringify(p), }; } else { toData = { text: '�좉퇋 �곹깭', isNew: true, loc: go.Point.stringify(p), }; } // add the new node data to the model const model = diagram.model; model.addNodeData(toData); // create a link data from the old node data to the new node data const linkdata = { from: model.getKeyForNodeData(fromData), to: model.getKeyForNodeData(toData), isNew: true, }; // and add the link data to the model model.addLinkData(linkdata); // select the new Node const newnode = diagram.findNodeForData(toData); diagram.select(newnode); // snap the new node to a valid location newnode.location = diagram.toolManager.draggingTool.computeMove(newnode, p); // then account for any overlap shiftNodesToEmptySpaces(); diagram.commitTransaction('Add State'); } // Highlight ports when they are targets for linking or relinking. let OldTarget = null; // remember the last highlit port function highlight(port) { if (OldTarget !== port) { lowlight(); // remove highlight from any old port OldTarget = port; port.scale = 1.3; // highlight by enlarging } } function lowlight() { // remove any highlight if (OldTarget) { OldTarget.scale = 1.0; OldTarget = null; } } // ARMS �곹깭 �몃뱶 �띿뒪�� �몄쭛 �대깽�� 由ъ뒪�� 異붽� myDiagram.addDiagramListener('TextEdited', (e) => { const text_block = e.subject; // �몄쭛�� �띿뒪�� 釉붾줉 const node = text_block.part; // �띿뒪�� 釉붾줉�� �ы븿�� �몃뱶 if (node !== null) { const edited_text = text_block.text; const state_c_id = node.data.c_id; const state_category_mapping_id = node.data.mapping_id; console.log(node.data.c_id); console.log('Edited text: ', edited_text); // �곹깭紐� 蹂�寃� �몄텧 update_arms_state(state_c_id, state_category_mapping_id, edited_text, null) .then((result) => { // API �몄텧 寃곌낵瑜� 泥섎━�⑸땲��. jSuccess("�곹깭紐� 蹂�寃쎌씠 �꾨즺�섏뿀�듬땲��."); console.log(result); }) .catch((error) => { console.error('Error fetching data:', error); return; }); } }); // �곌껐�� Point to Point �곌껐 �대깽�� 泥섎━ myDiagram.addDiagramListener('LinkDrawn', (e) => { const link = e.subject; const from_node = link.fromNode; const to_node = link.toNode; link.data.fromNode = from_node.data; link.data.toNode = to_node.data; link.data.oldFromNode = from_node.data; link.data.oldToNode = to_node.data; // ARMS �곹깭 �몃뱶�먯꽌 ALM �곹깭濡� �대� �곌껐�� �덈뒗 寃쎌슦 if (from_node.category === "NoAdd" && from_node.findLinksOutOf().count > 1) { const existing_link = from_node.findLinksOutOf().first(); // jNotify(from_node.data.text + "�� �대� �곌껐�� ALM �곹깭媛� �덉뒿�덈떎. �곌껐 ��젣 �� �곌껐 �댁<�몄슂."); isLinkDeletion = false; myDiagram.remove(link); return; } // ALM �곹깭 �몃뱶媛� �대� �곌껐�� ARMS �곹깭媛� �덈뒗 寃쎌슦 if (to_node.category === 'End' && to_node.findLinksInto().count > 1) { const existing_link = to_node.findLinksInto().first(); jNotify("ALM �곹깭(" + to_node.data.text + ")�� �대� "+ existing_link.data.fromNode.text +" �곹깭�� �곌껐�섏뼱�덉뒿�덈떎."); isLinkDeletion = false; myDiagram.remove(link); return; } // ARMS �곹깭 - ARMS �곹깭 �곌껐 留됯린 if (from_node.category === 'NoAdd' && to_node.category === "NoAdd") { jNotify("ARMS �곹깭�쇰━�� �곌껐�� �� �놁뒿�덈떎."); isLinkDeletion = false; myDiagram.remove(link); return; } // ARMS �곹깭�� �곹깭 移댄뀒怨좊━ 1媛쒖뿉留� �곌껐 媛��� if (to_node.category === "NoAdd" && to_node.findLinksInto().count > 1) { const existing_link = to_node.findLinksInto().first(); jNotify(to_node.data.text + " �곹깭�� " + existing_link.data.fromNode.text +" 移댄뀒怨좊━媛� 吏��� �섏뼱�덉뒿�덈떎."); isLinkDeletion = false; myDiagram.remove(link); return; } // 移댄뀒怨좊━ - ALM �곹깭 �곌껐 留됯린 if (from_node.category === 'Loading' && to_node.category === "End") { jNotify("移댄뀒怨좊━�� ARMS �곹깭�먮쭔 �곌껐�� �� �덉뒿�덈떎."); isLinkDeletion = false; myDiagram.remove(link); return; } let update_c_id = to_node.data.c_id; let update_mapping_id = from_node.data.c_id; if (to_node.data.type === "arms-state") { update_arms_state(update_c_id, update_mapping_id, null, null) .then((result) => { console.log(result); jSuccess(to_node.data.text + " �곹깭媛� " + from_node.data.text + " 移댄뀒怨좊━�� �곌껐�섏뿀�듬땲��."); }) .catch((error) => { console.error('Error fetching data:', error) myDiagram.remove(link); return; }); } else if (to_node.data.type === "alm-status") { update_alm_status(update_c_id, update_mapping_id) .then((result) => { console.log(result); jSuccess("ALM �곹깭(" + to_node.data.text + ")媛� " + from_node.data.text + " �곹깭�� �곌껐�섏뿀�듬땲��."); }) .catch((error) => { console.error('Error fetching data:', error); myDiagram.remove(link); return; }); } lowlight(); }); // �곌껐 �쒕옒洹몃줈 �곌껐�� 洹몃━�� �대깽�� 泥섎━ myDiagram.addDiagramListener('LinkRelinked', (e) => { console.log(e); const link = e.subject; const from_node = link.fromNode; const to_node = link.toNode; // �쒕옒洹� �� 留곹겕 �곗씠�� 異붽� const old_from_node = link.data.oldFromNode; const old_to_node = link.data.oldToNode; // �좏슚�� 寃��ъ뿉 �ㅽ뙣�� 寃쎌슦 留곹겕瑜� �쒓굅�섍퀬 湲곗〈 �곹깭濡� 蹂듭썝 const remove_new_link_and_restore = () => { isLinkDeletion = false; myDiagram.remove(link); if (old_from_node && old_to_node) { const newLinkData = { from: old_from_node.key, to: old_to_node.key, fromNode: old_from_node, toNode: old_to_node, oldFromNode: old_from_node, oldToNode: old_to_node, }; myDiagram.model.addLinkData(newLinkData); } }; // ARMS �곹깭 �몃뱶�먯꽌 ALM �곹깭濡� �대� �곌껐�� �덈뒗 寃쎌슦 if (from_node.category === "NoAdd" && from_node.findLinksOutOf().count > 1) { const existing_link = from_node.findLinksOutOf().first(); // jNotify(from_node.data.text + "�� �대� �곌껐�� ALM �곹깭媛� �덉뒿�덈떎. �곌껐 ��젣 �� �곌껐 �댁<�몄슂."); remove_new_link_and_restore(); return; } // ALM �곹깭 �몃뱶媛� �대� �곌껐�� ARMS �곹깭媛� �덈뒗 寃쎌슦 if (to_node.category === 'End' && to_node.findLinksInto().count > 1) { const existing_link = to_node.findLinksInto().first(); jNotify("ALM �곹깭(" + to_node.data.text + ")�� �대� "+ existing_link.data.fromNode.text +" �곹깭�� �곌껐�섏뼱�덉뒿�덈떎."); remove_new_link_and_restore(); return; } // ARMS �곹깭 - ARMS �곹깭 �곌껐 留됯린 if (from_node.category === 'NoAdd' && to_node.category === "NoAdd") { jNotify("ARMS �곹깭�쇰━�� �곌껐�� �� �놁뒿�덈떎."); isLinkDeletion = false; myDiagram.remove(link); return; } // ARMS �곹깭�� �곹깭 移댄뀒怨좊━ 1媛쒖뿉留� �곌껐 媛��� if (to_node.category === "NoAdd" && to_node.findLinksInto().count > 1) { const existing_link = to_node.findLinksInto().first(); jNotify(to_node.data.text + " �곹깭�� " + existing_link.data.fromNode.text +" 移댄뀒怨좊━媛� 吏��� �섏뼱�덉뒿�덈떎."); remove_new_link_and_restore(); return; } // 移댄뀒怨좊━ - ALM �곹깭 �곌껐 留됯린 if (from_node.category === 'Loading' && to_node.category === "End") { jNotify("移댄뀒怨좊━�� ARMS �곹깭�먮쭔 �곌껐�� �� �덉뒿�덈떎."); remove_new_link_and_restore(); return; } // �쒕옒洹� �� �쒕∼�쇰줈 �곌껐�� 蹂�寃� 泥섎━�� 寃쎌슦 湲곗〈 �곌껐 ��젣 update 泥섎━ let old_c_id = old_to_node.c_id; let old_mapping_id = null; // let old_mapping_id = old_from_node.c_id; if (old_to_node.type === "arms-state") { // 湲곗〈 ARMS �곹깭 珥덇린�� update_arms_state(old_c_id, old_mapping_id, null, null) .then((result) => { // API �몄텧 寃곌낵瑜� 泥섎━�⑸땲��. console.log(result); }) .catch((error) => { console.error('Error fetching data:', error); remove_new_link_and_restore(); return; }); } else if (old_to_node.type === "alm-status") { // 湲곗〈 ALM �곹깭 珥덇린�� update_alm_status(old_c_id, old_mapping_id) .then((result) => { console.log(result); }) .catch((error) => { console.error('Error fetching data:', error); remove_new_link_and_restore(); return; }); } // �쒕옒洹� �� �쒕∼�쇰줈 �곌껐�� 蹂�寃� 泥섎━�� 寃쎌슦 �덈줈�� �곌껐 link update 泥섎━ let c_id = to_node.data.c_id; let mapping_id = from_node.data.c_id; if (to_node.data.type === "arms-state") { update_arms_state(c_id, mapping_id, null, null) .then((result) => { // API �몄텧 寃곌낵瑜� 泥섎━�⑸땲��. jSuccess(to_node.data.text + " �곹깭媛� " + from_node.data.text + "移댄뀒怨좊━�� �곌껐�섏뿀�듬땲��."); console.log(result); }) .catch((error) => { console.error('Error fetching data:', error); remove_new_link_and_restore(); return; }); } else if (to_node.data.type === "alm-status") { console.log("ALM �곹깭 留ㅽ븨 蹂�寃�"); update_alm_status(c_id, mapping_id) .then((result) => { jSuccess("ALM �곹깭(" + to_node.data.text + ")媛� " + from_node.data.text + " �곹깭�� �곌껐�섏뿀�듬땲��."); console.log(result); }) .catch((error) => { console.error('Error fetching data:', error); remove_new_link_and_restore(); return; }); } // old data 理쒖떊�� link.data.oldFromNode = from_node.data; link.data.oldToNode = to_node.data; }); myDiagram.commandHandler.canDeleteSelection = function() { // �좏깮�� �곗씠�� (�ㅼ쨷 �좏깮�� 鍮꾪솢�깊솕�섏뼱 �덉뼱 ��긽 �섎굹留� �좏깮��) const selectedNode = myDiagram.selection.first(); // �좏깮�� �곗씠�곌� Node ���낆씪 �� if (selectedNode instanceof go.Node) { isLinkDeletion = false; // Link ��젣媛� �꾨땶 Node ��젣濡� 泥섎━ // 移댄뀒怨좊━ �닿굅��, ALM �곹깭�� 寃쎌슦 if (selectedNode && (selectedNode.data.type === "arms-category" || selectedNode.data.type === 'alm-status')) { // ��젣 紐삵븯�꾨줉 泥섎━ let node_type = selectedNode.data.type === "arms-category" ? "移댄뀒怨좊━" : "ALM �곹깭"; alert(`${node_type} �좏삎�� �몃뱶�� ��젣�� �� �놁뒿�덈떎.`); return false; } // ARMS�� �곹깭�� 寃쎌슦 else if (selectedNode && (selectedNode.data.type === "arms-state")) { // ��젣�좎� �щ��� ���� �뚮┝ 李� 異붽� const state_name = selectedNode.data.text; const state_c_id = selectedNode.data.c_id; let foundState = armsStateArray.find(item => item.c_id === selectedNode.data.c_id); if (!(foundState && foundState.c_check === "true")) { popup_modal('delete_popup', state_c_id, state_name); return; } alert('湲곕낯 �곹깭�� ��젣�� �� �놁뒿�덈떎.'); return false; /*if (!confirm( state_name + " �곹깭瑜� ��젣�섏떆寃좎뒿�덇퉴?")) { return false; } else { remove_arms_state(state_c_id, state_name) .then((result) => { console.log(result); }) .catch((error) => { console.error('Error fetching data:', error); return false; }); }*/ } } // 湲곕낯 ��젣 �숈옉 �섑뻾 return go.CommandHandler.prototype.canDeleteSelection.call(this); }; myDiagram.addDiagramListener("SelectionDeleting", function(e) { const selectedNode = e.diagram.selection.first(); // �곌껐 �좏깮 �� ��젣 �뺤씤 �뚮┝ 李� �⑤룄濡� 泥섎━瑜� �꾪븳 �뚮옒洹� if (selectedNode instanceof go.Node) { isLinkDeletion = false; } else if (selectedNode instanceof go.Link) { isLinkDeletion = true; } }); // �곗씠�� 蹂�寃� �대깽�� 由ъ뒪�� myDiagram.addModelChangedListener(function(e) { // ��젣 �대깽�� 泥섎━(Remove) if (e.change === go.ChangedEvent.Remove) { // �곌껐(留곹겕)留� ��젣 - �몃뱶�� ��젣�� 寃쎌슦�� �곌껐�� �먮룞��젣 if (e.propertyName === 'linkDataArray' && isLinkDeletion) { const removedLinkData = e.oldValue; // 湲곗〈 �곌껐 if (removedLinkData.toNode.type === "arms-state" && removedLinkData.toNode.c_check === "true") { alert("湲곕낯 �곹깭 �곌껐�� ��젣�� �� �놁뒿�덈떎."); myDiagram.model.addLinkData(removedLinkData); return; } if (!confirm("�대떦 �곌껐�� ��젣�섏떆寃좎뒿�덇퉴?")) { // ��젣 痍⑥냼 �� 湲곗〈 �곌껐 �щ벑濡� myDiagram.model.addLinkData(removedLinkData); return; } let c_id = removedLinkData.toNode.c_id; if (removedLinkData.toNode.type === "arms-state") { // amrs �곹깭 c_id�� ���� 留ㅽ븨 媛� null 泥섎━ let state_category_mapping_id = null; update_arms_state(c_id, state_category_mapping_id, null, null) .then((result) => { // API �몄텧 寃곌낵瑜� 泥섎━�⑸땲��. console.log(result); }) .catch((error) => { // �ㅻ쪟媛� 諛쒖깮�� 寃쎌슦 泥섎━�⑸땲��. console.error('Error fetching data:', error); myDiagram.model.addLinkData(removedLinkData); return; }); } else if (removedLinkData.toNode.type === "alm-status") { console.log("alm �곹깭 留곹겕 ��젣"); update_alm_status(c_id, null) .then((result) => { // API �몄텧 寃곌낵瑜� 泥섎━�⑸땲��. console.log(result); }) .catch((error) => { // �ㅻ쪟媛� 諛쒖깮�� 寃쎌슦 泥섎━�⑸땲��. console.error('Error fetching data:', error); myDiagram.model.addLinkData(removedLinkData); return; }); } } } }); myDiagram.linkTemplate = $(go.Link, { selectionAdorned: false, fromPortId: 'from', toPortId: 'to', relinkableTo: true, contextMenu: // �곌껐 ��젣 �고겢由� 硫붾돱 異붽� $(go.Adornment, "Auto", $(go.Panel, "Vertical", $("ContextMenuButton", $(go.Shape, "Rectangle", { fill: "rgba(51, 51, 51, 0.8)", stroke: null, name: "buttonShape", width: 50, height: 20 }), $(go.TextBlock, "��젣", { name: "deleteLinkText", font: "12px", stroke: "white", margin: new go.Margin(0, 0, 0, 0), } ), { name: "deleteLinkButton", click: deleteLinkClick, "ButtonBorder.stroke": null, "ButtonBorder.fill": "rgba(51, 51, 51, 0.8)", mouseEnter: (e, obj) => { let shape = obj.findObject("buttonShape"); if (shape) shape.fill = "dodgerblue"; }, mouseLeave: (e, obj) => { let shape = obj.findObject("buttonShape"); if (shape) shape.fill = "rgba(51, 51, 51, 0.8)"; } } ) ) ) }, $(go.Shape, { stroke: 'lightgray', strokeWidth: 3 }, { mouseEnter: (e, obj) => { obj.strokeWidth = 5; obj.stroke = 'dodgerblue'; }, mouseLeave: (e, obj) => { obj.strokeWidth = 3; obj.stroke = 'lightgray'; }, } ) ); function deleteLinkClick(e, obj) { e.diagram.commandHandler.deleteSelection(); } function commonLinkingToolInit(tool) { // the temporary link drawn during a link drawing operation (LinkingTool) is thick and blue tool.temporaryLink = $(go.Link, { layerName: 'Tool' }, $(go.Shape, { stroke: 'dodgerblue', strokeWidth: 5 })); // change the standard proposed ports feedback from blue rectangles to transparent circles tool.temporaryFromPort.figure = 'Circle'; tool.temporaryFromPort.stroke = null; tool.temporaryFromPort.strokeWidth = 0; tool.temporaryToPort.figure = 'Circle'; tool.temporaryToPort.stroke = null; tool.temporaryToPort.strokeWidth = 0; // provide customized visual feedback as ports are targeted or not tool.portTargeted = (realnode, realport, tempnode, tempport, toend) => { if (realport === null) { // no valid port nearby lowlight(); } else if (toend) { highlight(realport); } }; } const ltool = myDiagram.toolManager.linkingTool; commonLinkingToolInit(ltool); // do not allow links to be drawn starting at the "to" port ltool.direction = go.LinkingDirection.ForwardsOnly; const rtool = myDiagram.toolManager.relinkingTool; commonLinkingToolInit(rtool); // change the standard relink handle to be a shape that takes the shape of the link rtool.toHandleArchetype = $(go.Shape, { isPanelMain: true, fill: null, stroke: 'dodgerblue', strokeWidth: 5 }); // use a special DraggingTool to cause the dragging of a Link to start relinking it myDiagram.toolManager.draggingTool = new DragLinkingTool(); // detect when dropped onto an occupied cell myDiagram.addDiagramListener('SelectionMoved', shiftNodesToEmptySpaces); function shiftNodesToEmptySpaces() { myDiagram.selection.each((node) => { if (!(node instanceof go.Node)) return; // look for Parts overlapping the node while (true) { const exist = myDiagram .findObjectsIn( node.actualBounds, // only consider Parts (obj) => obj.part, // ignore Links and the dropped node itself (part) => part instanceof go.Node && part !== node, // check for any overlap, not complete containment true ) .first(); if (exist === null) break; // try shifting down beyond the existing node to see if there's empty space node.moveTo(node.actualBounds.x, exist.actualBounds.bottom + 10); } }); } // prevent nodes from being dragged to the left of where the layout placed them myDiagram.addDiagramListener('LayoutCompleted', (e) => { myDiagram.nodes.each((node) => { if (node.category === 'Recycle') return; node.minLocation = new go.Point(node.location.x, -Infinity); }); }); } function isEncoded(str) { try { return str !== decodeURIComponent(str); } catch (e) { return false; } } // 媛앹껜�� 紐⑤뱺 臾몄옄�댁쓣 �붿퐫�⑺븯�� �ш� �⑥닔 function decodeObject(obj) { for (let key in obj) { if (typeof obj[key] === 'string' && isEncoded(obj[key])) { obj[key] = decodeURIComponent(obj[key]); } else if (typeof obj[key] === 'object') { decodeObject(obj[key]); } } } function load(data) { // let data = document.getElementById('mySavedModel').value; console.log(data); armsStateArray = data.nodeDataArray.filter(item => item.type === "arms-state"); myDiagram.model = go.Model.fromJson(data); // if any nodes don't have a real location, explicitly do a layout if (myDiagram.nodes.any((n) => !n.location.isReal())) layout(); } function layout() { myDiagram.layoutDiagram(true); } // Define a custom tool that changes a drag operation on a Link to a relinking operation, // but that operates like a normal DraggingTool otherwise. class DragLinkingTool extends go.DraggingTool { constructor() { super(); this.isGridSnapEnabled = true; this.isGridSnapRealtime = false; this.gridSnapCellSize = new go.Size(182, 1); this.gridSnapOrigin = new go.Point(5.5, 0); } // Handle dragging a link specially -- by starting the RelinkingTool on that Link doActivate() { const diagram = this.diagram; if (diagram === null) return; this.standardMouseSelect(); const main = this.currentPart; // this is set by the standardMouseSelect if (main instanceof go.Link) { // maybe start relinking instead of dragging const relinkingtool = diagram.toolManager.relinkingTool; // tell the RelinkingTool to work on this Link, not what is under the mouse relinkingtool.originalLink = main; // start the RelinkingTool diagram.currentTool = relinkingtool; // can activate it right now, because it already has the originalLink to reconnect relinkingtool.doActivate(); relinkingtool.doMouseMove(); } else { super.doActivate(); } } } // end DragLinkingTool function save() { let data = myDiagram.model.toJson(); console.log(data); let jsonData = JSON.parse(data); decodeObject(jsonData); console.log(jsonData); document.getElementById('mySavedModel').value = JSON.stringify(jsonData, null, 2); myDiagram.isModified = false; } return { init, save, load, layout } })(); //利됱떆�ㅽ뻾 �⑥닔