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()