mushy 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,73 @@
1
+ module Mushy
2
+
3
+ class Collection < Flux
4
+
5
+ attr_accessor :collection
6
+
7
+ def self.details
8
+ {
9
+ name: 'Collection',
10
+ description: 'Collects events.',
11
+ config: {
12
+ id: {
13
+ description: 'The path to the unique id in the body of the element.',
14
+ type: 'id',
15
+ value: { url: 'a|@href' },
16
+ },
17
+ operation: {
18
+ description: 'Perform this operation.',
19
+ type: 'select',
20
+ options: ['all', 'delete', 'upsert', 'update', 'insert'],
21
+ value: 'upsert',
22
+ },
23
+ },
24
+ }
25
+ end
26
+
27
+ def initialize
28
+ self.collection = {}
29
+ super
30
+ end
31
+
32
+ def process event, config
33
+ self.send(config[:operation].to_sym, event, config)
34
+ end
35
+
36
+ def get_the_id event, config
37
+ event[config[:id]]
38
+ end
39
+
40
+ def all event, config
41
+ self.collection.values
42
+ end
43
+
44
+ def delete event, config
45
+ self.collection.delete get_the_id(event, config)
46
+ event[config[:operation_performed]] = 'deleted' if config[:operation_performed]
47
+ event
48
+ end
49
+
50
+ def upsert event, config
51
+ if self.collection[get_the_id(event, config)]
52
+ update event, config
53
+ else
54
+ insert event, config
55
+ end
56
+ end
57
+
58
+ def update event, config
59
+ item = self.collection[get_the_id(event, config)]
60
+ event.each { |k, v| item[k] = v } if item
61
+ event[config[:operation_performed]] = (item ? 'updated' : 'not exist') if config[:operation_performed]
62
+ event
63
+ end
64
+
65
+ def insert event, config
66
+ self.collection[get_the_id(event, config)] = event
67
+ event[config[:operation_performed]] = 'inserted' if config[:operation_performed]
68
+ event
69
+ end
70
+
71
+ end
72
+
73
+ end
@@ -0,0 +1,37 @@
1
+ module Mushy
2
+
3
+ class Filter < Flux
4
+
5
+ def process event, config
6
+
7
+ differences = [:equal, :notequal]
8
+ .select { |x| config[x].is_a? Hash }
9
+ .map { |x| config[x].map { |k, v| { m: x, k: k, v1: v } } }
10
+ .flatten
11
+ .map { |x| x[:v2] = event[x[:k]] ; x }
12
+ .map { |x| [x[:m], x[:v1], x[:v2]] }
13
+ .reject { |x| self.send x[0], x[1], x[2] }
14
+
15
+ differences.count == 0 ? event : nil
16
+
17
+ end
18
+
19
+ def equal a, b
20
+ [a, b]
21
+ .map { |x| numeric?(x) ? x.to_f : x }
22
+ .map { |x| x.to_s.strip.downcase }
23
+ .group_by { |x| x }
24
+ .count == 1
25
+ end
26
+
27
+ def notequal a, b
28
+ equal(a, b) == false
29
+ end
30
+
31
+ def numeric? value
32
+ Float(value) != nil rescue false
33
+ end
34
+
35
+ end
36
+
37
+ end
@@ -0,0 +1,30 @@
1
+ require 'faraday'
2
+
3
+ module Mushy
4
+
5
+ class Get < Flux
6
+
7
+ def process event, config
8
+
9
+ faraday = Faraday.new do |connection|
10
+ connection.adapter Faraday.default_adapter
11
+ end
12
+
13
+ headers = config[:headers] || {}
14
+ data = {}
15
+ url = config[:url]
16
+
17
+ response = faraday.get config[:url], data, headers
18
+
19
+ {
20
+ status: response.status,
21
+ url: url,
22
+ reason_phrase: response.reason_phrase,
23
+ headers: response.headers,
24
+ body: response.body,
25
+ }
26
+ end
27
+
28
+ end
29
+
30
+ end
@@ -0,0 +1,38 @@
1
+ module Mushy
2
+
3
+ class Ls < Bash
4
+
5
+ def self.details
6
+ {
7
+ name: 'Ls',
8
+ description: 'Run the "ls" command.',
9
+ config: {
10
+ directory: {
11
+ description: 'The working directory in which the command will be run.',
12
+ type: 'text',
13
+ value: '',
14
+ },
15
+ },
16
+ }
17
+ end
18
+
19
+ def process event, config
20
+
21
+ config[:command] = 'ls'
22
+
23
+ result = super event, config
24
+
25
+ return result unless result[:success]
26
+
27
+ result[:text].split("\n").map do |x|
28
+ {
29
+ name: x,
30
+ }
31
+ end
32
+
33
+ end
34
+
35
+ end
36
+
37
+ end
38
+
@@ -0,0 +1,52 @@
1
+ require 'nokogiri'
2
+
3
+ module Mushy
4
+
5
+ class ParseHtml < Flux
6
+
7
+ def self.details
8
+ {
9
+ name: 'ParseHtml',
10
+ description: 'Parses HTML.',
11
+ config: {
12
+ path: {
13
+ description: 'The path to the HTML in the incoming event.',
14
+ type: 'text',
15
+ value: 'body',
16
+ },
17
+ extract: {
18
+ description: 'The form of the event that is meant to be pulled from this event.',
19
+ type: 'keyvalue',
20
+ value: { url: 'a|@href' },
21
+ }
22
+ },
23
+ }
24
+ end
25
+
26
+ def process event, config
27
+
28
+ doc = Nokogiri::HTML event[config[:path]]
29
+
30
+ matches = config[:extract].keys.reduce( { } ) do |matches, key|
31
+ css, value = config[:extract][key].split('|')
32
+ value = value || './node()'
33
+
34
+ matches[key] = doc.css(css).map { |x| x.xpath(value).to_s }
35
+ matches
36
+ end
37
+
38
+ matches[matches.keys.first]
39
+ .each_with_index
40
+ .map { |_, i| i }
41
+ .map do |i|
42
+ matches.keys.reduce(SymbolizedHash.new( { } )) do |record, key|
43
+ record[key] = matches[key][i]
44
+ record[key] = record[key].strip if record[key]
45
+ record
46
+ end
47
+ end
48
+ end
49
+
50
+ end
51
+
52
+ end
@@ -0,0 +1,27 @@
1
+ require 'csv'
2
+
3
+ module Mushy
4
+
5
+ class ReadCsv < Flux
6
+
7
+ def process event, config
8
+ data = event[config[:key]]
9
+
10
+ headers = config[:headers].to_s.strip.downcase == 'true' ? true : false
11
+
12
+ rows = CSV.new data, headers: headers
13
+
14
+ rows.map do |row|
15
+ if headers
16
+ row.to_hash
17
+ else
18
+ record = {}
19
+ row.each_with_index { |r, i| record[("a".ord + i).chr] = r }
20
+ record
21
+ end
22
+ end
23
+ end
24
+
25
+ end
26
+
27
+ end
@@ -0,0 +1,39 @@
1
+ module Mushy
2
+
3
+ class WriteFile < Flux
4
+
5
+ def self.details
6
+ {
7
+ name: 'WriteFile',
8
+ description: 'Write a file.',
9
+ config: {
10
+ name: {
11
+ description: 'The name of the file.',
12
+ type: 'text',
13
+ value: 'records',
14
+ },
15
+ directory: {
16
+ description: 'The directory in which to write the file. Leave blank for the current directory.',
17
+ type: 'text',
18
+ value: 'records',
19
+ },
20
+ path: {
21
+ description: 'The path to the data to write.',
22
+ type: 'text',
23
+ value: 'records',
24
+ },
25
+ },
26
+ }
27
+ end
28
+
29
+ def process event, config
30
+ data = event[config[:path].to_sym] || event[config[:path].to_s]
31
+
32
+ File.open(config[:name], 'w') { |f| f.write data }
33
+
34
+ {}
35
+ end
36
+
37
+ end
38
+
39
+ end
@@ -0,0 +1,56 @@
1
+ module Mushy
2
+
3
+ class Masher
4
+
5
+ attr_accessor :mash_methods
6
+
7
+ def initialize
8
+ self.mash_methods =
9
+ {
10
+ String => ->(x, d) do
11
+ x.match('{{\s?(\w*)\s?}}') do |m|
12
+ if (m.captures.count == 1)
13
+ match_on_key = d.keys.select { |x| x.to_s == m.captures[0].to_s }.first
14
+ if match_on_key
15
+ value = dig match_on_key.to_s, d
16
+ return value unless value.is_a?(String) || value.is_a?(Numeric)
17
+ end
18
+ end
19
+ end
20
+ Liquid::Template.parse(x).render SymbolizedHash.new(d)
21
+ end,
22
+ Hash => ->(x, d) do
23
+ h = SymbolizedHash.new(x)
24
+ h.each { |k, v| h[k] = mash v, d }
25
+ h
26
+ end,
27
+ Array => ->(x, d) { x.map { |x| mash x, d } }
28
+ }
29
+ end
30
+
31
+ def mash value, data
32
+ method_for(value).call value, data
33
+ end
34
+
35
+ def method_for value
36
+ mash_methods
37
+ .select { |k, _| value.is_a? k }
38
+ .map { |_, v| v }
39
+ .first || ->(x, _) { x }
40
+ end
41
+
42
+ def dig key, data
43
+ return nil unless key
44
+
45
+ segments = key.split '.'
46
+
47
+ segments.each do |segment|
48
+ data = data.is_a?(Hash) ? (data[segment] || data[segment.to_sym]) : (data ? data.send(segment.to_sym) : nil)
49
+ end
50
+
51
+ data
52
+ end
53
+
54
+ end
55
+
56
+ end
@@ -0,0 +1,8 @@
1
+ module Mushy
2
+
3
+ class Run
4
+ attr_accessor :id
5
+ attr_accessor :flow_id
6
+ end
7
+
8
+ end
@@ -0,0 +1,56 @@
1
+ module Mushy
2
+
3
+ class Runner
4
+
5
+ attr_accessor :runner
6
+
7
+ def initialize runner = nil
8
+ self.runner = runner || self
9
+ end
10
+
11
+ def start event_data, flux, flow
12
+ run = find_run flux, flow
13
+ starting_event = build_event event_data, flow.id, run.id, flux.id
14
+
15
+ events = run_event_with_flux starting_event, flux
16
+
17
+ while events.any?
18
+ events = events.map { |e| runner.run_event_in_flow e, flow }.flatten
19
+ end
20
+
21
+ run
22
+ end
23
+
24
+ def run_event_in_flow event, flow
25
+ flow.fluxs_for(event)
26
+ .map { |s| runner.run_event_with_flux event, s }
27
+ .flatten
28
+ end
29
+
30
+ def run_event_with_flux event, flux
31
+ [flux.execute(event.data)]
32
+ .flatten
33
+ .reject { |x| x.nil? }
34
+ .map { |x| x.is_a?(Hash) ? build_event(x, event.flow_id, event.run_id, flux.id) : x }
35
+ end
36
+
37
+ def find_run flux, flow
38
+ run = Mushy::Run.new
39
+ run.id = SecureRandom.uuid
40
+ run.flow_id = flow.id
41
+ run
42
+ end
43
+
44
+ def build_event event_data, flow_id, run_id, flux_id
45
+ event = Mushy::Event.new
46
+ event.id = SecureRandom.uuid
47
+ event.run_id = run_id
48
+ event.flow_id = flow_id
49
+ event.flux_id = flux_id
50
+ event.data = event_data
51
+ event
52
+ end
53
+
54
+ end
55
+
56
+ end
@@ -0,0 +1,3 @@
1
+ module Mushy
2
+ VERSION = '0.0.1'
3
+ end
@@ -0,0 +1,256 @@
1
+ <html>
2
+ <head>
3
+ <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/water.css@2/out/dark.css">
4
+ <script src="https://cdn.jsdelivr.net/npm/vue@2.6.12/dist/vue.js"></script>
5
+ <script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>
6
+ </head>
7
+ <body>
8
+ <div id="app">
9
+ <table>
10
+ <tr v-for="flux in flow.fluxs">
11
+ <td>{{flux.name}}</td>
12
+ </tr>
13
+ </table>
14
+ <mip-heavy :data="setup"></mip-heavy>
15
+ <mip-heavy v-for="(data, id) in configs" v-show="setup.flux.value === id" :data="data"></mip-heavy>
16
+ <div v-if="results.loading">Loading...</div>
17
+ <div v-else>{{results.length}} result{{results.length == 1 ? "" : "s"}}</div>
18
+ <mip-heavy v-for="data in results" :data="data"></mip-heavy>
19
+ </div>
20
+ </body>
21
+ </html>
22
+
23
+ <script type="text/javascript">
24
+
25
+ var fancyName = function(id) { return '(' + id + '.split(/[ _]/).map(function(x){return x[0].toUpperCase() + x.substring(1)}).join(\' \'))' };
26
+ var thingToData = function(thing) {
27
+ var record = {};
28
+ for (var key in thing)
29
+ if (thing[key].value)
30
+ if (thing[key].type == 'json')
31
+ record[key] = JSON.parse(thing[key].value);
32
+ else
33
+ record[key] = thing[key].value;
34
+ return record;
35
+ };
36
+
37
+ var components = {
38
+ label: {
39
+ props: ['label', 'description'],
40
+ template: '<label :for="id" v-if="label != \'\'">{{label || ' + fancyName('id') + '}} <i v-show="description">({{description}})</i></label>'
41
+ },
42
+ text: {
43
+ props: ['label', 'placeholder', 'disabled', 'readonly', 'value', 'description'],
44
+ template: '<div><mip-label :id="id" :label="label" :description="description"></mip-label><input type="text" :name="id" :placeholder="placeholder" v-bind:value="value" v-on:input="$emit(\'update:value\', $event.target.value);" :disabled="disabled == \'true\'" :readonly="readonly == \'true\'"></div>'
45
+ },
46
+ integer: {
47
+ props: ['label', 'placeholder', 'disabled', 'readonly', 'value', 'description'],
48
+ template: '<div><mip-label :id="id" :label="label" :description="description"></mip-label><input type="text" :name="id" :placeholder="placeholder" v-bind:value="value" v-on:input="$emit(\'update:value\', $event.target.value);" :disabled="disabled == \'true\'" :readonly="readonly == \'true\'"></div>'
49
+ },
50
+ email: {
51
+ props: ['label', 'placeholder', 'disabled', 'readonly', 'value', 'description'],
52
+ template: '<div><mip-label :id="id" :label="label" :description="description"></mip-label><input type="email" :name="id" :placeholder="placeholder" v-bind:value="value" v-on:input="$emit(\'update:value\', $event.target.value)" :disabled="disabled == \'true\'" :readonly="readonly == \'true\'"></div>'
53
+ },
54
+ textarea: {
55
+ props: ['label', 'placeholder', 'disabled', 'readonly', 'value', 'description'],
56
+ template: '<div><mip-label :id="id" :label="label" :description="description"></mip-label><textarea :name="id" :placeholder="placeholder" v-bind:value="value" v-on:input="$emit(\'update:value\', $event.target.value)" :disabled="disabled == \'true\'" :readonly="readonly == \'true\'"></textarea></div>'
57
+ },
58
+ json: {
59
+ props: ['label', 'placeholder', 'disabled', 'readonly', 'value', 'description'],
60
+ template: '<div><mip-label :id="id" :label="label" :description="description"></mip-label><pre><code>{{value}}</code></pre><textarea :name="id" :placeholder="placeholder" v-bind:value="value" v-on:input="$emit(\'update:value\', $event.target.value)" :disabled="disabled == \'true\'" :readonly="readonly == \'true\'"></textarea></div>'
61
+ },
62
+ jsonview: {
63
+ data: function() {
64
+ return {
65
+ toggle: function(view) { return view == 'beautiful' ? 'thin' : 'beautiful'; },
66
+ copy: function(view, json) { console.log(view); return navigator.clipboard.writeText((view == 'beautiful' ? JSON.stringify(json, null, " ") : JSON.stringify(json))); },
67
+ show: function(view, json) { return view == 'beautiful' ? JSON.stringify(json, null, " ") : JSON.stringify(json); },
68
+ };
69
+ },
70
+ props: ['label', 'placeholder', 'disabled', 'readonly', 'value', 'description', 'view'],
71
+ template: '<div><mip-label :id="id" :label="label" :description="description"></mip-label> <a href="#" v-on:click.prevent.stop="view=toggle(view)">{{(view == \'beautiful\' ? \'>\' : \'^\')}}</a><a href="#" v-on:click.prevent.stop="copy(view, value)">copy</a><pre><code>{{show(view, value)}}</code></pre></div>'
72
+ },
73
+ radio: {
74
+ props: ['label', 'value', 'options', 'description'],
75
+ template: '<div><mip-label :id="id" :label="label" :description="description"></mip-label><div v-for="option in options"><input type="radio" :name="id" v-bind:value="option" v-on:input="$emit(\'update:value\', $event.target.value)" :checked="value == option"> <label for="option">{{option}}</label></div></div>'
76
+ },
77
+ select: {
78
+ props: ['label', 'value', 'options', 'description'],
79
+ template: '<div><mip-label :id="id" :label="label" :description="description"></mip-label><select :name="id" v-on:input="$emit(\'update:value\', $event.target.value)"><option v-for="option in options" v-bind:value="option" :selected="value == option">{{option}}</option></select></div>'
80
+ },
81
+ boolean: {
82
+ props: ['label', 'value', 'options', 'description'],
83
+ template: '<div><mip-label :id="id" :label="label" :description="description"></mip-label><select :name="id" v-on:input="$emit(\'update:value\', $event.target.value)"><option v-for="option in [true, false]" v-bind:value="option" :selected="value == option">{{option}}</option></select></div>'
84
+ },
85
+ table: {
86
+ props: ['value', 'description'],
87
+ template: '<table><tr><th v-for="(d, i) in value[0]">{{' + fancyName('i') + '}}</th></tr><tr v-for="v in value"><td v-for="(d, i) in v">{{d}}</td></tr></table>'
88
+ },
89
+ editgrid: {
90
+ data: function() {
91
+ return {
92
+ removeRecord: function(record, records, index) { records.splice(index, 1); },
93
+ addRecord: function(editors, records) {
94
+ var record = {};
95
+ for (var i = 0; i < editors.length; i++)
96
+ {
97
+ record[editors[i].target] = editors[i].field.value;
98
+ editors[i].field.value = editors[i].field.default ? editors[i].field.default : '';
99
+ }
100
+ records.push(record);
101
+ }
102
+ };
103
+ },
104
+ props: ['value', 'editors', 'label', 'description'],
105
+ template: '<div><mip-label :id="id" :label="label" :description="description"></mip-label><table><tr><th v-for="(d, i) in value[0]">{{' + fancyName('i') + '}}</th></tr><tr v-for="(v, z) in value"><td v-for="(d, i) in v">{{d}}</td><td><a href="#" v-on:click.prevent.stop="removeRecord(v, value, z)">[x]</a></td></tr><tr><td v-for="editor in editors"><mip-thing :data="editor.field" :id="editor.id"></mip-thing></td><td><a href="#" v-on:click.prevent.stop="addRecord(editors, value)">[Add]</a></td></tr></table></div>'
106
+ },
107
+ keyvalue: {
108
+ data: function() {
109
+ return {
110
+ removeRecord: function(data, key) { Vue.delete(data, key) },
111
+ addRecord: function(editors, data) {
112
+ Vue.set(data, editors[0].field.value, editors[1].field.value)
113
+ editors[0].field.value = editors[0].field.default;
114
+ editors[1].field.value = editors[1].field.default;
115
+ }
116
+ };
117
+ },
118
+ props: ['value', 'label', 'editors', 'description'],
119
+ template: '<div><mip-label :id="id" :label="label" :description="description"></mip-label><table><tr v-for="(v, k) in value"><td>{{k}}</td><td>{{v}}</td><td><a href="#" v-on:click.prevent.stop="removeRecord(value, k)">[x]</a></td></tr><tr><td v-for="editor in editors"><mip-thing :data="editor.field" :id="editor.id"></mip-thing></td><td><a href="#" v-on:click.prevent.stop="addRecord(editors, value)" v-show="editors[0].field.value">[Add]</a></td></tr></table></div>'
120
+ },
121
+ button: {
122
+ props: ['click', 'description'],
123
+ template: '<button v-on:click.prevent.stop="click(pull(this))">{{id}}</button>'
124
+ }
125
+ };
126
+
127
+ for(var property in components)
128
+ {
129
+ var props = JSON.parse(JSON.stringify(components[property].props));
130
+ props.push('id');
131
+ Vue.component('mip-' + property, {
132
+ data: components[property].data ?? function () {
133
+ var foundIt = this.$parent;
134
+ var counter = 0;
135
+ while (foundIt.$parent.constructor.name == "VueComponent" && counter < 10)
136
+ {
137
+ foundIt = foundIt.$parent;
138
+ counter += 1;
139
+ }
140
+ return {
141
+ console: console,
142
+ pull: function(x) { return thingToData(foundIt.data); },
143
+ }
144
+ },
145
+ props: props,
146
+ template: components[property].template
147
+ });
148
+ }
149
+
150
+ var thingTemplate = '<div>';
151
+ for (var property in components)
152
+ thingTemplate = thingTemplate + '<mip-' + property + ' v-if="data.type == \'' + property + '\'" :id="id" ' + components[property].props.map(function(x){ return ':' + x + '.sync="data.' + x + '"';}).join(' ') + '></mip-' + property + '>'
153
+ thingTemplate = thingTemplate + '</div>';
154
+
155
+ Vue.component('mip-thing', {
156
+ data: function () {
157
+ return {
158
+ console: console,
159
+ }
160
+ },
161
+ props: ['data', 'value', 'id', 'model'],
162
+ template: thingTemplate
163
+ });
164
+
165
+ Vue.component('mip-heavy', {
166
+ data: function () {
167
+ return {
168
+ console: console,
169
+ }
170
+ },
171
+ props: ['data'],
172
+ template: '<div><mip-thing v-for="(d, id) in data" :data="d" :id="id"></mip-thing></div>',
173
+ });
174
+
175
+ var sample = {
176
+ email: { type: 'email', value: 'darren@cauthon.com' },
177
+ first_name: { type: 'text', value: 'Darren' },
178
+ description: { type: 'textarea', value: 'more data' },
179
+ size: { type: 'select', value: 'medium', options: ['small', 'medium', 'large']},
180
+ heynow: { type: 'keyvalue',
181
+ value: {
182
+ first_name: 'John',
183
+ last_name: 'Doe',
184
+ },
185
+ editors: [
186
+ { id: 'new_key', target: 'key', field: { type: 'text', value: '', default: '' } },
187
+ { id: 'new_value', target: 'value', field: { type: 'text', value: '', default: '' } }
188
+ ] },
189
+ past: { type: 'editgrid',
190
+ value: [
191
+ { name: 'Godzilla', quantity: 1 },
192
+ { name: 'Mothra', quantity: 2 },
193
+ ],
194
+ editors: [
195
+ { id: 'new_name', target: 'name', field: { type: 'text', value: '', default: '' } },
196
+ { id: 'new_quantity', target: 'quantity', field: { type: 'select', value: '1', options: [1, 2, 3], default: 1 } }
197
+ ] },
198
+ super_action: { type: 'button', click: function(x) { console.log(x) } },
199
+ };
200
+
201
+ var app = null;
202
+
203
+ axios.get('/fluxs')
204
+ .then(function(data){
205
+
206
+ var configs = {};
207
+ data.data.fluxs.map(function(x){
208
+ configs[x.name] = x.config;
209
+ });
210
+
211
+ var setup = {
212
+ event: { type: 'json', value: '{}' },
213
+ id: { type: 'text', value: '' },
214
+ name: { type: 'text', value: '' },
215
+ flux: { type: 'select', value: data.data.fluxs[0].name, options: data.data.fluxs.map(function(x){ return x.name })},
216
+ };
217
+
218
+ for (var key in configs)
219
+ {
220
+ configs[key].go = { type: 'button', click: function(c) {
221
+ app.results = [];
222
+ Vue.set(app.results, 'loading', true);
223
+ axios.post('/run', { config: c, setup: thingToData(app.setup) })
224
+ .then(function(r){
225
+ Vue.set(app.results, 'loading', false);
226
+ for (var key in r.data.result)
227
+ app.results.push({darren: { type:'jsonview', value: r.data.result[key], view: 'thin' }});
228
+ });
229
+ } };
230
+
231
+ configs[key].save = { type: 'button', click: function(config) {
232
+ var setup = thingToData(app.setup);
233
+ var flux = {
234
+ id: setup.id,
235
+ name: setup.name,
236
+ config: config,
237
+ };
238
+ app.flow.fluxs.push(flux);
239
+ console.log(flux);
240
+ }
241
+ };
242
+ }
243
+
244
+ app = new Vue({
245
+ el: '#app',
246
+ data: {
247
+ flow: {
248
+ fluxs: [],
249
+ },
250
+ configs: configs,
251
+ setup: setup,
252
+ results: [],
253
+ }
254
+ });
255
+ });
256
+ </script>