diff --git a/elements/noflo-ui.html b/elements/noflo-ui.html index 8562531b2..8b22a0109 100644 --- a/elements/noflo-ui.html +++ b/elements/noflo-ui.html @@ -124,7 +124,10 @@ this.fire('project:save:runtime', event.detail); }.bind(this)); this.$.grapheditor.addEventListener('edges', function (event) { - this.fire('context:edges', event.detail); + this.fire('context:edges', { + graph: this.$.grapheditor.graph.name || this.$.grapheditor.graph.properties.id, + edges: event.detail + }); }.bind(this)); this.$.grapheditor.addEventListener('nodes', function (event) { this.fire('context:nodes', event.detail); @@ -306,7 +309,7 @@ this.$.search.graphResults(this.ctx.searchGraphResult); } if (this.ctx.edges !== undefined) { - this.$.packets.edges = this.ctx.edges; + this.$.packets.edges = this.ctx.edges.edges; } if (this.ctx.error) { this.$.packets.processError(this.ctx.error); diff --git a/graphs/ContextStorage.fbp b/graphs/ContextStorage.fbp index 0a6aa3084..4f0d77d7a 100644 --- a/graphs/ContextStorage.fbp +++ b/graphs/ContextStorage.fbp @@ -9,7 +9,6 @@ Dispatch OUT[0] -> IN SplitEdges(core/Split) OUT -> START CreateEdgeCtx(objects/ CreateEdgeCtx OUT -> CONTEXT SetEdges(ui/SetToContext) 'edges' -> KEY SetEdges SplitEdges OUT -> VALUE SetEdges CONTEXT -> IN MergeContext(core/Merge) -# TODO: Send to runtime # Selected nodes Dispatch OUT[1] -> IN SplitNodes(core/Split) OUT -> START CreateNodeCtx(objects/CreateObject) diff --git a/graphs/RuntimeMiddleware.fbp b/graphs/RuntimeMiddleware.fbp new file mode 100644 index 000000000..4116ea547 --- /dev/null +++ b/graphs/RuntimeMiddleware.fbp @@ -0,0 +1,16 @@ +INPORT=Dispatch.IN:IN +OUTPORT=Passed.OUT:PASS +OUTPORT=NewActions.OUT:NEW + +'runtime:connected,context:edges' -> ROUTES Dispatch(ui/DispatchAction) + +# Pass connected runtime to all handlers and also outside +Dispatch HANDLE[0] -> IN Runtimes(core/Merge) +Runtimes OUT -> IN Passed(core/Merge) +Dispatch PASS -> IN Passed + +# Send selected edges to runtime +Dispatch HANDLE[1] -> EDGES SendEdges(runtime/SendEdges) +Runtimes OUT -> RUNTIME SendEdges OUT -> IN Passed + +NewActions(core/Merge) diff --git a/graphs/main.fbp b/graphs/main.fbp index e2c932a2e..b5f2de59f 100644 --- a/graphs/main.fbp +++ b/graphs/main.fbp @@ -12,8 +12,10 @@ Logger PASS -> IN UrlMiddleware(ui/UrlMiddleware) UrlMiddleware NEW -> IN Actions UrlMiddleware PASS -> IN UserMiddleware(ui/UserMiddleware) UserMiddleware NEW -> IN Actions +UserMiddleware PASS -> IN RuntimeMiddleware(ui/RuntimeMiddleware) +RuntimeMiddleware NEW -> IN Actions # Once middlewares have processed event, pass to stores -UserMiddleware PASS -> IN Dispatch(routers/GroupRouter) +RuntimeMiddleware PASS -> IN Dispatch(routers/GroupRouter) 'user,main,project,github,runtime,context' -> ROUTES Dispatch Dispatch OUT[0] -> IN UserReducer(ui/UserReducer) Dispatch OUT[1] -> START MainContext(ui/CreateContext) diff --git a/spec/RuntimeMiddleware.coffee b/spec/RuntimeMiddleware.coffee index b8577ca84..14012217a 100644 --- a/spec/RuntimeMiddleware.coffee +++ b/spec/RuntimeMiddleware.coffee @@ -8,19 +8,90 @@ else baseDir = 'noflo-ui' describe 'Runtime Middleware', -> + c = null + actionIn = null + passAction = null + newAction = null runtime = null before (done) -> + @timeout 4000 fixtures = document.getElementById 'fixtures' transport = require('fbp-protocol-client').getTransport 'iframe' runtime = new transport address: 'mockruntime.html' runtime.setParentElement fixtures window.runtime = runtime - done() + loader = new noflo.ComponentLoader baseDir + loader.load 'ui/RuntimeMiddleware', (err, instance) -> + return done err if err + c = instance + actionIn = noflo.internalSocket.createSocket() + c.inPorts.in.attach actionIn + actionIn.port = 'in' + ### + c.network.on 'begingroup', (data) -> + console.log " < #{data.id}" + c.network.on 'data', (data) -> + console.log "DATA #{data.id}" + c.network.on 'endgroup', (data) -> + console.log " > #{data.id}" + ### + c.start() + c.network.once 'start', -> + done() + beforeEach -> + passAction = noflo.internalSocket.createSocket() + c.outPorts.pass.attach passAction + passAction.port = 'pass' + newAction = noflo.internalSocket.createSocket() + c.outPorts.new.attach newAction + newAction.port = 'new' afterEach -> + c.outPorts.pass.detach passAction + c.outPorts.new.detach newAction runtime.iframe.contentWindow.clearMessages() + send = (socket, action, payload) -> + actionParts = action.split ':' + socket.beginGroup part for part in actionParts + socket.send payload + socket.endGroup part for part in actionParts + + receive = (socket, expected, check, done) -> + received = [] + onBeginGroup = (group) -> + received.push "< #{group}" + onData = (data) -> + received.push 'DATA' + check data + onEndGroup = (group) -> + received.push "> #{group}" + return unless received.length >= expected.length + socket.removeListener 'begingroup', onBeginGroup + socket.removeListener 'data', onData + socket.removeListener 'endgroup', onEndGroup + chai.expect(received).to.eql expected + done() + socket.on 'begingroup', onBeginGroup + socket.on 'data', onData + socket.on 'endgroup', onEndGroup + + receiveAction = (socket, action, check, done) -> + expected = [] + actionParts = action.split ':' + expected.push "< #{part}" for part in actionParts + expected.push 'DATA' + actionParts.reverse() + expected.push "> #{part}" for part in actionParts + receive socket, expected, check, done + + receivePass = (socket, action, payload, done) -> + check = (data) -> + # Strict equality check for passed packets + chai.expect(data).to.equal payload + receiveAction socket, action, check, done + # Set up a fake runtime connection and test that we can play both ends it 'should be able to connect', (done) -> capabilities = [ @@ -41,3 +112,28 @@ describe 'Runtime Middleware', -> send 'runtime', 'runtime', capabilities: capabilities , 100 + + describe 'receiving a runtime:connected action', -> + it 'should pass it out as-is', (done) -> + action = 'runtime:connected' + payload = runtime + receivePass passAction, action, payload, done + send actionIn, action, payload + describe 'receiving a context:edges action', -> + it 'should send selected edges to the runtime', (done) -> + expectedEdges = [ + from: + node: 'Foo' + port: 'out' + to: + node: 'Bar' + port: 'in' + ] + send actionIn, 'context:edges', + graph: 'foo' + edges: expectedEdges + runtime.iframe.contentWindow.handleProtocolMessage (msg) -> + chai.expect(msg.protocol).to.equal 'network' + chai.expect(msg.command).to.equal 'edges' + chai.expect(msg.payload.edges).to.eql expectedEdges + done()