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