diff --git a/src/simple-flowchart/components/FlowchartNode.vue b/src/simple-flowchart/components/FlowchartNode.vue index 88f0833..09a7778 100644 --- a/src/simple-flowchart/components/FlowchartNode.vue +++ b/src/simple-flowchart/components/FlowchartNode.vue @@ -6,13 +6,24 @@
-
+
- + + + + + + + +
+
+ + Press APPLY first, to generate your connection details! +
@@ -36,7 +47,7 @@
- + @@ -52,8 +63,8 @@ - Discard - Save + {{ discardButtonLabel }} + Save @@ -73,18 +84,39 @@
-
-
- - - - - -
{{ k }}{{ v }}
+
{{ capitalizedType }}*
+
+ + Apply first! + URL: {{this.url}}
+
+ + + + + + + + + + + + + + + + +
width{{ this.data.width }}px
height{{ this.data.height }}px
bitrate{{ this.data.bitrate }}kbps
+
+
+ Target: {{ this.data.url }} +
+
+
{ } }, + apiId: { + type: String, + default: null + }, options: { type: Object, default() { @@ -155,6 +191,9 @@ export default { } }, mounted() { + if (this.apiId === null && this.type !== 'ingest') { + this.$nextTick(() => this.show.editor = true); + } }, computed: { nodeStyle() { @@ -172,8 +211,16 @@ export default { }, capitalizedType() { return capitalize(this.type); + }, + discardButtonLabel() { + if (this.type === 'ingest') { + return "CLOSE"; + } else { + return "DISCARD"; + } } }, + methods: { handleMousedown(e) { const target = e.target || e.srcElement; @@ -240,12 +287,18 @@ $portSize: 14; .node-content { font-size: 13px; + padding: 0.5em; th { width: 50%; } } + + .node-content-long { + word-break: break-all; + } + } .node-port { diff --git a/src/simple-flowchart/components/SimpleFlowchart.vue b/src/simple-flowchart/components/SimpleFlowchart.vue index f6c7283..6236f4f 100644 --- a/src/simple-flowchart/components/SimpleFlowchart.vue +++ b/src/simple-flowchart/components/SimpleFlowchart.vue @@ -152,7 +152,11 @@ export default { const existed = this.scene.links.find((link) => { return link.from === this.draggingLink.from && link.to === index; }) - if (!existed) { + // check for conflicting + const conflicting = this.scene.links.find((link) => { // This makes sure that only one link can go towards a node + return link.to === index; + }) + if (!existed && !conflicting) { let maxID = Math.max(0, ...this.scene.links.map((link) => { return link.id })) @@ -223,10 +227,16 @@ export default { if (typeof target.className === 'string' && target.className.indexOf('node-delete') > -1) { // console.log('delete2', this.action.dragging); this.nodeDelete(this.action.dragging); + this.action.dragging = null; } } + + if (this.action.dragging) { + this.$emit("nodeMoved", this.action.dragging); + this.action.dragging = null; + } + this.action.linking = false; - this.action.dragging = null; this.action.scrolling = false; }, handleDown(e) { diff --git a/src/views/Dashboard.vue b/src/views/Dashboard.vue index 45a2cfb..adb5f74 100644 --- a/src/views/Dashboard.vue +++ b/src/views/Dashboard.vue @@ -2,7 +2,8 @@
- + @@ -11,7 +12,14 @@ - + @@ -24,7 +32,8 @@ import SimpleFlowchart from '@/simple-flowchart'; import ElementAdder from "@/components/ElementAdder"; import WorkspaceDrawerContent from "@/components/WorkspaceDrawerContent"; import Toolbar from "@/components/Toolbar"; -import {maxBy} from 'lodash'; + +import {some} from 'lodash'; export default { name: 'Dashboard', @@ -36,7 +45,13 @@ export default { }, data: () => ({ showDrawer: false, - diagram: { + idGenerator: 1, + pendingChanges: { + created: [], + updated: [], + deleted: [] + }, + model: { centerX: 0, centerY: 0, scale: 1, @@ -51,40 +66,95 @@ export default { let newNode = { x: 10, y: 10, - type + type, + apiId: null } switch (type) { case "ingest": newNode.data = { - "url": "https://videon.test.kmlabz.com/live" + url: "", + streamkey: "demokey" } break; case "encoder": newNode.data = { - "bitrate": 8000, - "width": 600, - "height": 800 + bitrate: 0, + width: 0, + height: 0 } break; case "restreamer": newNode.data = { - "url": "https://youtube.com/live", - "streamkey": "testkey" + url: "", + streamkey: "" } break; } - if (this.diagram.nodes.length > 0) { - const max_id = maxBy(this.diagram.nodes, 'id').id + newNode.id = this.idGenerator; + this.idGenerator++; - newNode.id = max_id + 1; + this.model.nodes.push(newNode); + //this.pendingChanges.created.add(newNode.id); + this.enqueuePendingNodeCreation(newNode.id); + + }, + // Vuejs can not track changes of a set, so we do this magic hack to fix it + enqueuePendingNodeDeletion(id) { + let pending_deletes = new Set(this.pendingChanges.deleted); + let pending_updates = new Set(this.pendingChanges.updated); + let pending_creations = new Set(this.pendingChanges.created); + + // This stuff is here to prevent the creation and deletion of an object in the same transaction + if (pending_creations.has(id)) { + pending_creations.delete(id); } else { - newNode.id = 1; + pending_deletes.add(id); } - this.diagram.nodes.push(newNode) + pending_updates.delete(id); + this.pendingChanges.deleted = Array.from(pending_deletes); + this.pendingChanges.updated = Array.from(pending_updates); + this.pendingChanges.created = Array.from(pending_creations); + }, + enqueuePendingNodeUpdate(id) { + let pending_updates = new Set(this.pendingChanges.updated); + pending_updates.add(id); + this.pendingChanges.updated = Array.from(pending_updates); + }, + enqueuePendingNodeCreation(id) { + let pending_creations = new Set(this.pendingChanges.created); + pending_creations.add(id); + this.pendingChanges.created = Array.from(pending_creations); + }, + // --- end of magic hack + handleNodeMove() { + // TODO + }, + handleLinkBreak({from,to}) { + this.enqueuePendingNodeUpdate(from); + this.enqueuePendingNodeUpdate(to); + }, + handleLinkAdd({from, to}) { + this.enqueuePendingNodeUpdate(from); + this.enqueuePendingNodeUpdate(to); + }, + performApply() { + this.pendingChanges.created.forEach((id) => { + this.model.nodes.find((n) => n.id === id).apiId = 'a'; + }); + this.pendingChanges = { + deleted: [], + created: [], + updated: [] + } + } + }, + computed: { + modelChanged() { + return some(this.pendingChanges, (o) => o.length > 0); } }