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.
- checksums.yaml +7 -0
- data/bin/mushy +3 -0
- data/lib/mushy.rb +15 -0
- data/lib/mushy/event.rb +15 -0
- data/lib/mushy/flow.rb +47 -0
- data/lib/mushy/flux.rb +165 -0
- data/lib/mushy/fluxs/bash.rb +41 -0
- data/lib/mushy/fluxs/browser.rb +106 -0
- data/lib/mushy/fluxs/build_csv.rb +53 -0
- data/lib/mushy/fluxs/collection.rb +73 -0
- data/lib/mushy/fluxs/filter.rb +37 -0
- data/lib/mushy/fluxs/get.rb +30 -0
- data/lib/mushy/fluxs/ls.rb +38 -0
- data/lib/mushy/fluxs/parse_html.rb +52 -0
- data/lib/mushy/fluxs/read_csv.rb +27 -0
- data/lib/mushy/fluxs/write_file.rb +39 -0
- data/lib/mushy/masher.rb +56 -0
- data/lib/mushy/run.rb +8 -0
- data/lib/mushy/runner.rb +56 -0
- data/lib/mushy/version.rb +3 -0
- data/lib/public/index.html +256 -0
- data/lib/site.rb +54 -0
- data/mushy.gemspec +24 -0
- data/note.txt +2 -0
- metadata +137 -0
@@ -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
|
data/lib/mushy/masher.rb
ADDED
@@ -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
|
data/lib/mushy/run.rb
ADDED
data/lib/mushy/runner.rb
ADDED
@@ -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,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>
|