mushy 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -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>