mushy 0.15.3 → 0.19.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (39) hide show
  1. checksums.yaml +4 -4
  2. data/hey.mushy +29 -0
  3. data/lib/mushy/builder/api.rb +15 -3
  4. data/lib/mushy/builder/documentation.rb +37 -0
  5. data/lib/mushy/builder/index.rb +88 -15
  6. data/lib/mushy/flux.rb +5 -1
  7. data/lib/mushy/fluxs/bash.rb +24 -0
  8. data/lib/mushy/fluxs/browser.rb +120 -0
  9. data/lib/mushy/fluxs/build_csv.rb +23 -0
  10. data/lib/mushy/fluxs/cli.rb +12 -0
  11. data/lib/mushy/fluxs/collection.rb +3 -1
  12. data/lib/mushy/fluxs/document.rb +16 -0
  13. data/lib/mushy/fluxs/environment.rb +13 -0
  14. data/lib/mushy/fluxs/file_watch.rb +30 -1
  15. data/lib/mushy/fluxs/filter.rb +28 -0
  16. data/lib/mushy/fluxs/format.rb +42 -1
  17. data/lib/mushy/fluxs/git_log.rb +2 -0
  18. data/lib/mushy/fluxs/global_variables.rb +17 -1
  19. data/lib/mushy/fluxs/interval.rb +2 -0
  20. data/lib/mushy/fluxs/ls.rb +112 -0
  21. data/lib/mushy/fluxs/parse_html.rb +37 -1
  22. data/lib/mushy/fluxs/pdf.rb +72 -1
  23. data/lib/mushy/fluxs/pwd.rb +42 -1
  24. data/lib/mushy/fluxs/read_csv.rb +27 -0
  25. data/lib/mushy/fluxs/read_file.rb +24 -9
  26. data/lib/mushy/fluxs/read_json.rb +21 -7
  27. data/lib/mushy/fluxs/screenshot.rb +72 -2
  28. data/lib/mushy/fluxs/sense_hat_environmental_sensors.rb +2 -0
  29. data/lib/mushy/fluxs/sense_hat_led_matrix.rb +2 -0
  30. data/lib/mushy/fluxs/simple_python_program.rb +1 -0
  31. data/lib/mushy/fluxs/smtp.rb +2 -1
  32. data/lib/mushy/fluxs/stdout.rb +2 -0
  33. data/lib/mushy/fluxs/times.rb +9 -0
  34. data/lib/mushy/fluxs/twilio_message.rb +113 -0
  35. data/lib/mushy/fluxs/write_file.rb +48 -0
  36. data/lib/mushy/fluxs/write_json.rb +16 -0
  37. data/mushy.gemspec +1 -1
  38. metadata +8 -7
  39. data/lib/mushy/fluxs/print.rb +0 -26
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 4b743e14b0d41b727255550df74d33edc0c5eb33b4426e31d4eea41830aa167e
4
- data.tar.gz: 26e61eb0310e6a512deca465c0bb375c94b28ce58a3ee296e677b60a4fea5fc3
3
+ metadata.gz: d783dd461abacb6686c2e131fc228d2640f1dda9836d1c49c1073f7e37054739
4
+ data.tar.gz: 950f0fd45cb88001fe62d3f1541374c2df5a1f3ff931b19d3a40f4a6fd187fb3
5
5
  SHA512:
6
- metadata.gz: 9bcfe3677a5ca79b2e0249e1b03dec50bc2a019a06f8c61dcb0b4d6e76fc7f11f28f86f32c908d666ba163427a020630f43f73d0ad2c429a35a6f66bf047eab9
7
- data.tar.gz: 421e40fea84d8ed8e18f0f60584d55b21bb540139c6e9c28cfcf5ce8770a3102e6a92d17efe4b44fae4706bc36b9e2d080b036ba9208162ac5efe60e3c04a657
6
+ metadata.gz: 15b49ebac4c571ab8f2c34450516f0325b70a3e85e7bd909bdd800c29a74ee7377297fa5128f8d7b5458ec278768e92cafbd8af552321f372d26a9a743d8ebb1
7
+ data.tar.gz: 8041bbd1b4f89af13edc858be699bc3903e4bea680ac68b0b2f26a744adc0b7230572034ade0367851b7f5201e3c51ca9a48095d7afd9300f5185ce2f2c0bd3f
data/hey.mushy ADDED
@@ -0,0 +1,29 @@
1
+ {
2
+ "fluxs": [
3
+ {
4
+ "id": "0294b0c4-296f-44cd-9891-95fe75ebe4d2",
5
+ "name": "Start it up",
6
+ "flux": "Cli",
7
+ "parents": [
8
+
9
+ ],
10
+ "config": {
11
+ "model": {
12
+ }
13
+ }
14
+ },
15
+ {
16
+ "id": "7779dce1-1ce8-4241-8e94-ddcd5cb4f8df",
17
+ "name": "Output something",
18
+ "flux": "Stdout",
19
+ "parents": [
20
+ "0294b0c4-296f-44cd-9891-95fe75ebe4d2"
21
+ ],
22
+ "config": {
23
+ "message": "Hello.",
24
+ "model": {
25
+ }
26
+ }
27
+ }
28
+ ]
29
+ }
@@ -31,7 +31,17 @@ module Mushy
31
31
  end
32
32
 
33
33
  def self.start file, event
34
- file = "#{file}.mushy" unless file.downcase.end_with?('.mushy')
34
+ original_file = file
35
+ file = [file, "#{Dir.home}/.mushy/#{file}"]
36
+ .map { |x| (x.downcase.end_with?('.mushy') ? x : "#{x}.mushy") }
37
+ .select { |x| File.exist?(x) }
38
+ .first
39
+
40
+ unless file
41
+ puts "#{original_file} does not exist."
42
+ return
43
+ end
44
+
35
45
  flow = File.open(file).read
36
46
  flow = Mushy::Flow.parse flow
37
47
 
@@ -77,7 +87,6 @@ module Mushy
77
87
  end
78
88
 
79
89
  def self.get_flow file
80
- puts "trying to get: #{file}"
81
90
  file = "#{file}.mushy" unless file.downcase.end_with?('.mushy')
82
91
  data = JSON.parse File.open(file).read
83
92
 
@@ -129,10 +138,13 @@ module Mushy
129
138
  {
130
139
  fluxs: Mushy::Flux.all.select { |x| x.respond_to? :details }.select { |x| x.details }.map do |flux|
131
140
  details = flux.details
141
+
142
+ details[:documentation] = Documentation.build_from details
143
+
132
144
  details[:config][:incoming_split] = { type: 'text', shrink: true, description: 'Split an incoming event into multiple events by this key, an each event will be processed independently.', default: '' }
133
145
  details[:config][:outgoing_split] = { type: 'text', shrink: true, description: 'Split an outgoing event into multiple events by this key.', default: '' }
134
146
  details[:config][:merge] = { type: 'text', shrink: true, description: 'A comma-delimited list of fields from the event to carry through. Use * to merge all fields.', default: '' }
135
- details[:config][:group] = { type: 'text', shrink: true, description: 'Group events by a field, which is stored in a key. The format is group_by|group_key.', default: '' }
147
+ details[:config][:group] = { type: 'text', shrink: true, description: 'Group events by this key, with the value as the key. If a group key is provided like group_by|group_key, then multiple events with the results under group_key will be returned.', default: '' }
136
148
  details[:config][:limit] = { type: 'integer', shrink: true, description: 'Limit the number of events to this number.', default: '' }
137
149
  details[:config][:join] = { type: 'text', shrink: true, description: 'Join all of the events from this flux into one event, under this name.', default: '' }
138
150
  details[:config][:sort] = { type: 'text', shrink: true, description: 'Sort by this key.', default: '' }
@@ -0,0 +1,37 @@
1
+ module Mushy
2
+ module Builder
3
+ module Documentation
4
+
5
+ def self.build_from config
6
+ basic_usage = "#{config[:description]}"
7
+ if config[:config]&.any?
8
+ rows = config[:config]
9
+ .map { |x| [x[0], x[1][:description], (x[1][:shrink] ? '(optional) ' : '')] }
10
+ .reduce("") { |t, i| "#{t}<tr><td>#{i[0]}</td><td>#{i[2]}#{i[1]}</td></tr>" }
11
+ basic_usage += '<table class="table is-bordered"><thead><tr><td>Field</td><td>Description</td></tr></thead>' + rows + "</table>"
12
+ end
13
+
14
+ {
15
+ "Basic Usage" => basic_usage,
16
+ }.tap do |documentation|
17
+ if config[:examples]
18
+ config[:examples].each do |item|
19
+ documentation[item[0]] = [
20
+ item[1][:description],
21
+ code_sample('Input', item[1][:input]),
22
+ code_sample('Config', item[1][:config]),
23
+ code_sample('Result', item[1][:result]),
24
+ ].select { |x| x }.reduce('') { |t, i| t + i }
25
+ end
26
+ end
27
+ end
28
+ end
29
+
30
+ def self.code_sample title, value
31
+ return nil unless value
32
+ "<div><b>#{title}</b></div><pre><code>#{JSON.pretty_generate(value)}</code></pre>"
33
+ end
34
+
35
+ end
36
+ end
37
+ end
@@ -52,6 +52,52 @@ module Mushy
52
52
  <button v-on:click.prevent.stop="startNew({ setup: setup, configs: configs })" class="button is-link">Add a New Flux To This Flow</button>
53
53
  </div>
54
54
  </div>
55
+
56
+ <div v-bind:class="setup.fluxTypeSelect">
57
+ <div class="modal-background"></div>
58
+ <div class="modal-card">
59
+ <header class="modal-card-head">
60
+ <p class="modal-card-title">Flux Types</p>
61
+ <button class="delete" aria-label="close" v-on:click.prevent.stop="setup.fluxTypeSelect['is-active'] = false"></button>
62
+ </header>
63
+ <section class="modal-card-body">
64
+ <div class="content">
65
+ <div v-for="(fluxGroup) in fluxGroups">
66
+ <h2 style="font-style:italic">{{fluxGroup.name}}</h2>
67
+ <div v-for="(fluxType, id) in fluxGroup.fluxs">
68
+ <div class="level">
69
+ <div class="level-left"><h2>{{fluxType.title || fluxType.name}}</h2></div>
70
+ <div class="level-right">
71
+ <button class="button is-primary level-item" v-on:click.prevent.stop="setup.flux.value = fluxType.name;setup.fluxTypeSelect['is-active'] = false">
72
+ Select
73
+ </button>
74
+ <button class="button level-item" v-on:click.prevent.stop="fluxType.showDetails = true" v-if="fluxType['showDetails'] == false">
75
+ Open
76
+ </button>
77
+ <button class="button level-item" v-on:click.prevent.stop="fluxType.showDetails = false" v-if="fluxType['showDetails']">
78
+ Close
79
+ </button>
80
+ </div>
81
+ </div>
82
+
83
+ <div v-if="fluxType['showDetails']">
84
+ <div class="tabs">
85
+ <ul>
86
+ <li v-for="(a, b) in fluxType.documentation"><a v-on:click.prevent.stop="fluxType.detailsTab = b">{{b}}</a></li>
87
+ </ul>
88
+ </div>
89
+ <div v-for="(a, b) in fluxType.documentation" v-if="fluxType['detailsTab'] == b" v-html="a"></div>
90
+ </div>
91
+ </div>
92
+ </div>
93
+ </div>
94
+ </section>
95
+ <footer class="modal-card-foot">
96
+ <button class="button is-primary" v-on:click.prevent.stop="setup.fluxTypeSelect['is-active'] = false">Done</button>
97
+ </footer>
98
+ </div>
99
+ </div>
100
+
55
101
  <div class="column" v-if="setup.showFlux">
56
102
  <div class="columns">
57
103
  <div class="column is-half">
@@ -124,7 +170,7 @@ module Mushy
124
170
  },
125
171
  text: {
126
172
  props: ['label', 'placeholder', 'disabled', 'readonly', 'value', 'description', 'shrink'],
127
- template: '<div><mip-label :id="id" :label="label" :description="description" :hide_description="shrink && !value"></mip-label> <a href="#" v-on:click.prevent.stop="shrink=false" v-show="shrink && !value">[^]</a><div class="control"><input type="text" :name="id" v-if="value || !shrink" :placeholder="placeholder" v-bind:value="value" v-on:input="$emit(\\'update:value\\', $event.target.value);" :disabled="disabled == \\'true\\'" :readonly="readonly == \\'true\\'" class="input"></div></div>'
173
+ template: '<div><div class="level"><div class="level-left"><div class="level-item"><mip-label :id="id" :label="label" :description="description" :hide_description="shrink && !value"></mip-label></div><div class="level-item"> <a href="#" v-on:click.prevent.stop="shrink=false" v-show="shrink && !value">[^]</a></div></div></div> <div class="control"><input type="text" :name="id" v-if="value || !shrink" :placeholder="placeholder" v-bind:value="value" v-on:input="$emit(\\'update:value\\', $event.target.value);" :disabled="disabled == \\'true\\'" :readonly="readonly == \\'true\\'" class="input"></div></div>'
128
174
  },
129
175
  hide: {
130
176
  props: ['label', 'description'],
@@ -132,19 +178,19 @@ module Mushy
132
178
  },
133
179
  integer: {
134
180
  props: ['label', 'placeholder', 'disabled', 'readonly', 'value', 'description', 'shrink'],
135
- template: '<div><mip-label :id="id" :label="label" :description="description" :hide_description="shrink && !value"></mip-label> <a href="#" v-on:click.prevent.stop="shrink=false" v-show="shrink && !value">[^]</a><div class="control"><input type="text" :name="id" v-if="value || !shrink" :placeholder="placeholder" v-bind:value="value" v-on:input="$emit(\\'update:value\\', $event.target.value);" :disabled="disabled == \\'true\\'" :readonly="readonly == \\'true\\'" class="input"></div></div>'
181
+ template: '<div><div class="level"><div class="level-left"><div class="level-item"><mip-label :id="id" :label="label" :description="description" :hide_description="shrink && !value"></mip-label></div><div class="level-item"> <a href="#" v-on:click.prevent.stop="shrink=false" v-show="shrink && !value">[^]</a></div></div></div> <div class="control"><input type="text" :name="id" v-if="value || !shrink" :placeholder="placeholder" v-bind:value="value" v-on:input="$emit(\\'update:value\\', $event.target.value);" :disabled="disabled == \\'true\\'" :readonly="readonly == \\'true\\'" class="input"></div></div>'
136
182
  },
137
183
  email: {
138
184
  props: ['label', 'placeholder', 'disabled', 'readonly', 'value', 'description', 'shrink'],
139
- template: '<div><mip-label :id="id" :label="label" :description="description" :hide_description="shrink && !value"></mip-label> <a href="#" v-on:click.prevent.stop="shrink=false" v-show="shrink && !value">[^]</a><div class="control"><input type="email" :name="id" v-if="value || !shrink" :placeholder="placeholder" v-bind:value="value" v-on:input="$emit(\\'update:value\\', $event.target.value)" :disabled="disabled == \\'true\\'" :readonly="readonly == \\'true\\'" class="input"></div></div>'
185
+ template: '<div><div class="level"><div class="level-left"><div class="level-item"><mip-label :id="id" :label="label" :description="description" :hide_description="shrink && !value"></mip-label></div><div class="level-item"> <a href="#" v-on:click.prevent.stop="shrink=false" v-show="shrink && !value">[^]</a></div></div></div> <div class="control"><input type="email" :name="id" v-if="value || !shrink" :placeholder="placeholder" v-bind:value="value" v-on:input="$emit(\\'update:value\\', $event.target.value)" :disabled="disabled == \\'true\\'" :readonly="readonly == \\'true\\'" class="input"></div></div>'
140
186
  },
141
187
  textarea: {
142
188
  props: ['label', 'placeholder', 'disabled', 'readonly', 'value', 'description', 'shrink'],
143
- template: '<div><mip-label :id="id" :label="label" :description="description" :hide_description="shrink && !value"></mip-label> <a href="#" v-on:click.prevent.stop="shrink=false" v-show="shrink && !value">[^]</a><div class="control"><textarea :name="id" v-if="value || !shrink" :placeholder="placeholder" v-bind:value="value" v-on:input="$emit(\\'update:value\\', $event.target.value)" :disabled="disabled == \\'true\\'" :readonly="readonly == \\'true\\'" class="textarea"></textarea></div></div>'
189
+ template: '<div><div class="level"><div class="level-left"><div class="level-item"><mip-label :id="id" :label="label" :description="description" :hide_description="shrink && !value"></mip-label></div><div class="level-item"> <a href="#" v-on:click.prevent.stop="shrink=false" v-show="shrink && !value">[^]</a></div></div></div> <div class="control"><textarea :name="id" v-if="value || !shrink" :placeholder="placeholder" v-bind:value="value" v-on:input="$emit(\\'update:value\\', $event.target.value)" :disabled="disabled == \\'true\\'" :readonly="readonly == \\'true\\'" class="textarea"></textarea></div></div>'
144
190
  },
145
191
  json: {
146
192
  props: ['label', 'placeholder', 'disabled', 'readonly', 'value', 'description', 'shrink'],
147
- template: '<div><mip-label :id="id" :label="label" :description="description" :hide_description="shrink && !value"></mip-label> <a href="#" v-on:click.prevent.stop="shrink=false" v-show="shrink && !value">[^]</a><textarea :name="id" v-if="value || !shrink" :placeholder="placeholder" v-bind:value="value" v-on:input="$emit(\\'update:value\\', $event.target.value)" :disabled="disabled == \\'true\\'" :readonly="readonly == \\'true\\'" class="textarea"></textarea></div>'
193
+ template: '<div><div class="level"><div class="level-left"><div class="level-item"><mip-label :id="id" :label="label" :description="description" :hide_description="shrink && !value"></mip-label></div><div class="level-item"> <a href="#" v-on:click.prevent.stop="shrink=false" v-show="shrink && !value">[^]</a></div></div></div> <textarea :name="id" v-if="value || !shrink" :placeholder="placeholder" v-bind:value="value" v-on:input="$emit(\\'update:value\\', $event.target.value)" :disabled="disabled == \\'true\\'" :readonly="readonly == \\'true\\'" class="textarea"></textarea></div>'
148
194
  },
149
195
  jsonview: {
150
196
  data: function() {
@@ -159,15 +205,15 @@ module Mushy
159
205
  },
160
206
  radio: {
161
207
  props: ['label', 'value', 'options', 'description', 'shrink'],
162
- template: '<div><mip-label :id="id" :label="label" :description="description" :hide_description="shrink && !value"></mip-label> <a href="#" v-on:click.prevent.stop="shrink=false" v-show="shrink && !value">[^]</a><div v-for="option in options"><input type="radio" :name="id" v-bind:value="option" v-if="value || !shrink" v-on:input="$emit(\\'update:value\\', $event.target.value)" :checked="value == option"> <label for="option">{{option}}</label></div></div>'
208
+ template: '<div><div class="level"><div class="level-left"><div class="level-item"><mip-label :id="id" :label="label" :description="description" :hide_description="shrink && !value"></mip-label></div><div class="level-item"> <a href="#" v-on:click.prevent.stop="shrink=false" v-show="shrink && !value">[^]</a></div></div></div> <div v-for="option in options"><input type="radio" :name="id" v-bind:value="option" v-if="value || !shrink" v-on:input="$emit(\\'update:value\\', $event.target.value)" :checked="value == option"> <label for="option">{{option}}</label></div></div>'
163
209
  },
164
210
  select: {
165
211
  props: ['label', 'value', 'options', 'description', 'shrink'],
166
- template: '<div><mip-label :id="id" :label="label" :description="description" :hide_description="shrink && !value"></mip-label> <a href="#" v-on:click.prevent.stop="shrink=false" v-show="shrink && !value">[^]</a><div class="control"><select :name="id" v-if="value || !shrink" v-on:input="$emit(\\'update:value\\', $event.target.value)" class="select"><option v-for="option in options" v-bind:value="option" :selected="value == option">{{option}}</option></select></div></div>'
212
+ template: '<div><div class="level"><div class="level-left"><div class="level-item"><mip-label :id="id" :label="label" :description="description" :hide_description="shrink && !value"></mip-label></div><div class="level-item"> <a href="#" v-on:click.prevent.stop="shrink=false" v-show="shrink && !value">[^]</a></div></div></div> <div class="control"><select :name="id" v-if="value || !shrink" v-on:input="$emit(\\'update:value\\', $event.target.value)" class="select"><option v-for="option in options" v-bind:value="option" :selected="value == option">{{option}}</option></select></div></div>'
167
213
  },
168
214
  selectrecord: {
169
215
  props: ['label', 'value', 'options', 'description', 'shrink'],
170
- template: '<div><mip-label :id="id" :label="label" :description="description" :hide_description="shrink && !value"></mip-label> <a href="#" v-on:click.prevent.stop="shrink=false" v-show="shrink && !value">[^]</a><div class="control"><select :name="id" v-if="value || !shrink" v-on:input="$emit(\\'update:value\\', $event.target.value)" class="select"><option v-for="option in options" v-bind:value="option.id" :selected="value == option.id">{{option.name}}</option></select></div></div>'
216
+ template: '<div><div class="level"><div class="level-left"><div class="level-item"><mip-label :id="id" :label="label" :description="description" :hide_description="shrink && !value"></mip-label></div><div class="level-item"> <a href="#" v-on:click.prevent.stop="shrink=false" v-show="shrink && !value">[^]</a></div></div></div> <div class="control"><select :name="id" v-if="value || !shrink" v-on:input="$emit(\\'update:value\\', $event.target.value)" class="select"><option v-for="option in options" v-bind:value="option.id" :selected="value == option.id">{{option.name}}</option></select></div></div>'
171
217
  },
172
218
  selectmanyrecords: {
173
219
  data: function() {
@@ -193,11 +239,11 @@ module Mushy
193
239
  };
194
240
  },
195
241
  props: ['label', 'value', 'options', 'description', 'shrink'],
196
- template: '<div><mip-label :id="id" :label="label" :description="description" :hide_description="shrink && !value"></mip-label> <a href="#" v-on:click.prevent.stop="shrink=false" v-show="shrink && !value">[^]</a> <span v-for="option in options" v-if="value && value.includes(option.id)">{{option.name}} <a href="#" v-on:click.prevent.stop="remove(option.id, value);$emit(\\'update:value\\', value)">[X]</a> </span> <a href="#" v-on:click.prevent.stop="doit(selectedValue, value);$emit(\\'update:value\\', value)">ADD</a> <div class="control"><select :name="id" v-if="value || !shrink" v-on:input="selectedValue=$event.target.value;" class="select"><option v-for="option in options" v-bind:value="option.id">{{option.name}}</option></select></div></div>'
242
+ template: '<div><div class="level"><div class="level-left"><div class="level-item"><mip-label :id="id" :label="label" :description="description" :hide_description="shrink && !value"></mip-label></div><div class="level-item"> <a href="#" v-on:click.prevent.stop="shrink=false" v-show="shrink && !value">[^]</a></div></div></div> <span v-for="option in options" v-if="value && value.includes(option.id)">{{option.name}} <a href="#" v-on:click.prevent.stop="remove(option.id, value);$emit(\\'update:value\\', value)">[X]</a> </span> <div class="control"><select :name="id" v-if="value || !shrink" v-on:input="selectedValue=$event.target.value;" class="select" v-on:change.prevent.stop="doit(selectedValue, value);$emit(\\'update:value\\', value);$event.target.value=\\'\\';"><option v-for="option in options" v-bind:value="option.id">{{option.name}}</option></select></div></div>'
197
243
  },
198
244
  boolean: {
199
245
  props: ['label', 'value', 'options', 'description', 'shrink'],
200
- template: '<div><mip-label :id="id" :label="label" :description="description" :hide_description="shrink && !value"></mip-label> <a href="#" v-on:click.prevent.stop="shrink=false" v-show="shrink && !value">[^]</a><div class="control"><select :name="id" v-if="(value != undefined && value != null && value != \\'\\') || !shrink" v-on:input="$emit(\\'update:value\\', $event.target.value)" class="select"><option v-for="option in [true, false]" v-bind:value="option" :selected="value == option">{{option}}</option></select></div></div>'
246
+ template: '<div><div class="level"><div class="level-left"><div class="level-item"><mip-label :id="id" :label="label" :description="description" :hide_description="shrink && !value"></mip-label></div><div class="level-item"> <a href="#" v-on:click.prevent.stop="shrink=false" v-show="shrink && !value">[^]</a></div></div></div> <div class="control"><select :name="id" v-if="(value != undefined && value != null && value != \\'\\') || !shrink" v-on:input="$emit(\\'update:value\\', $event.target.value)" class="select"><option v-for="option in [true, false]" v-bind:value="option" :selected="value == option">{{option}}</option></select></div></div>'
201
247
  },
202
248
  table: {
203
249
  props: ['value', 'description'],
@@ -219,7 +265,7 @@ module Mushy
219
265
  };
220
266
  },
221
267
  props: ['value', 'editors', 'label', 'description', 'shrink'],
222
- template: '<div><mip-label :id="id" :label="label" :description="description" :hide_description="shrink && !value"></mip-label> <a href="#" v-on:click.prevent.stop="shrink=false" v-show="shrink && value.length == 0">[^]</a><table v-if="value.length > 0 || !shrink" class="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>'
268
+ template: '<div><div class="level"><div class="level-left"><div class="level-item"><mip-label :id="id" :label="label" :description="description" :hide_description="shrink && !value"></mip-label></div><div class="level-item"> <a href="#" v-on:click.prevent.stop="shrink=false" v-show="shrink && value.length == 0">[^]</a></div></div></div> <table v-if="value.length > 0 || !shrink" class="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>'
223
269
  },
224
270
  keyvalue: {
225
271
  data: function() {
@@ -234,7 +280,7 @@ module Mushy
234
280
  };
235
281
  },
236
282
  props: ['value', 'label', 'editors', 'description', 'shrink'],
237
- template: '<div><mip-label :id="id" :label="label" :description="description" :hide_description="shrink && !value"></mip-label> <a href="#" v-on:click.prevent.stop="shrink=false" v-show="shrink">[^]</a><table v-if="JSON.stringify(value) != \\'{}\\' || !shrink" class="table"><tr v-for="(v, k) in value"><td>{{k}}</td><td>{{v}}</td><td><button v-on:click.prevent.stop="removeRecord(value, k)" class="button">Remove {{k}}</button></td></tr><tr><td v-for="editor in editors"><mip-thing :data="editor.field" :id="editor.id"></mip-thing></td><td><button v-on:click.prevent.stop="addRecord(editors, value)" v-show="editors[0].field.value" class="button">{{actionText(editors[0].field.value, value)}} {{editors[0].field.value}}</button></td></tr></table></div>'
283
+ template: '<div><div class="level"><div class="level-left"><div class="level-item"><mip-label :id="id" :label="label" :description="description" :hide_description="shrink && !value"></mip-label></div><div class="level-item"> <a href="#" v-on:click.prevent.stop="shrink=false" v-show="shrink">[^]</a></div></div></div> <table v-if="JSON.stringify(value) != \\'{}\\' || !shrink" class="table"><tr v-for="(v, k) in value"><td>{{k}}</td><td>{{v}}</td><td><button v-on:click.prevent.stop="removeRecord(value, k)" class="button">Remove {{k}}</button></td></tr><tr><td v-for="editor in editors"><mip-thing :data="editor.field" :id="editor.id"></mip-thing></td><td><button v-on:click.prevent.stop="addRecord(editors, value)" v-show="editors[0].field.value" class="button">{{actionText(editors[0].field.value, value)}} {{editors[0].field.value}}</button></td></tr></table></div>'
238
284
  },
239
285
  button: {
240
286
  data: function() {
@@ -281,7 +327,7 @@ module Mushy
281
327
  });
282
328
  }
283
329
 
284
- var thingTemplate = '<div v-bind:class="{ \\\'ml-3\\\': data.foghat==\\\'free\\\', \\\'column\\\': data.foghat!=\\\'free\\\', \\\'is-full\\\': data.foghat!=\\\'half\\\' && data.foghat!=\\\'free\\\', \\\'is-half\\\': data.foghat==\\\'half\\\' }">';
330
+ var thingTemplate = '<div v-show="data.hide != true" v-bind:class="{ \\\'ml-3\\\': data.foghat==\\\'free\\\', \\\'column\\\': data.foghat!=\\\'free\\\', \\\'is-full\\\': data.foghat!=\\\'half\\\' && data.foghat!=\\\'free\\\', \\\'is-half\\\': data.foghat==\\\'half\\\' }">';
285
331
  for (var property in components)
286
332
  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 + '>'
287
333
  thingTemplate = thingTemplate + '</div>';
@@ -292,7 +338,7 @@ module Mushy
292
338
  console: console,
293
339
  }
294
340
  },
295
- props: ['data', 'value', 'id', 'model', 'foghat'],
341
+ props: ['data', 'value', 'id', 'model', 'foghat', 'hide'],
296
342
  template: thingTemplate
297
343
  });
298
344
 
@@ -337,12 +383,28 @@ module Mushy
337
383
  fluxdata = fluxdata.data;
338
384
  flowdata = flowdata.data;
339
385
 
386
+ fluxdata.fluxs.map(function(x) {
387
+ x['showDetails'] = false;
388
+ x['detailsTab'] = Object.getOwnPropertyNames(x.documentation)[0];
389
+ } );
390
+
391
+ fluxGroups = []
392
+ fluxdata.fluxs.map(function(x) {
393
+ if (x.fluxGroup) {} else { x.fluxGroup = { name: 'Others', position: 999999 } };
394
+ rowboat = fluxGroups.filter(function(y) { return y.name == x.fluxGroup.name })[0];
395
+ if (rowboat) {} else { fluxGroups.push(x.fluxGroup); x.fluxGroup.fluxs = [] }
396
+ rowboat = fluxGroups.filter(function(y) { return y.name == x.fluxGroup.name })[0];
397
+ rowboat.fluxs.push(x);
398
+ } );
399
+ fluxGroups = fluxGroups.sort(function(x, y) { return (x.position || 1000) - (y.position || 1000); })
400
+
340
401
  var configs = {};
341
402
  fluxdata.fluxs.map(function(x){
342
403
  configs[x.name] = x.config;
343
404
  });
344
405
 
345
406
  var options = [''];
407
+ fluxTypesWithDetails = fluxdata.fluxs;
346
408
  fluxTypes = fluxdata.fluxs.map(function(x){ return x.name });
347
409
  for(var type in fluxTypes)
348
410
  options.push(fluxTypes[type]);
@@ -391,9 +453,18 @@ module Mushy
391
453
  "modal": true,
392
454
  "is-active": false,
393
455
  },
456
+ fluxTypeSelect: {
457
+ "modal": true,
458
+ "is-active": false,
459
+ },
394
460
  id: { type: 'hide', value: '' },
395
461
  name: { type: 'text', value: '' },
396
- flux: { type: 'select', value: fluxdata.fluxs[0].name, options: options},
462
+ flux: { type: 'select', value: fluxdata.fluxs[0].name, options: options, hide: true },
463
+ open_flux: { type: 'button', name: 'Select a Flux', foghat: 'free', medium: 'hey', color: 'is-primary',
464
+ click: function() {
465
+ Vue.set(app.setup.fluxTypeSelect, 'is-active', true);
466
+ }
467
+ },
397
468
  parents: { type: 'selectmanyrecords', label: 'Receive Events From', value: '', options: flowdata.fluxs },
398
469
  };
399
470
 
@@ -507,6 +578,8 @@ module Mushy
507
578
  });
508
579
  },
509
580
  configs: configs,
581
+ fluxTypes: fluxTypesWithDetails,
582
+ fluxGroups: fluxGroups,
510
583
  setup: setup,
511
584
  flux_name_for: function(ids, fluxes) {
512
585
  var fluxs = fluxes.filter(function(x){ return ids.includes(x.id) });
data/lib/mushy/flux.rb CHANGED
@@ -119,7 +119,11 @@ module Mushy
119
119
  def group_these_results results, event, by
120
120
  group_by = by.split('|')[0]
121
121
  result_key = by.split('|')[1]
122
- results.group_by { |x| x[group_by] }.map { |k, v| SymbolizedHash.new( { result_key => v } ) }
122
+ grouped_results = results.group_by { |x| x[group_by] }
123
+
124
+ return grouped_results unless result_key
125
+
126
+ grouped_results.map { |k, v| SymbolizedHash.new( { result_key => v } ) }
123
127
  end
124
128
 
125
129
  def outgoing_split_these_results results, event, by
@@ -5,7 +5,9 @@ module Mushy
5
5
  def self.details
6
6
  {
7
7
  name: 'Bash',
8
+ title: 'Execute a command via bash',
8
9
  description: 'Run a bash command.',
10
+ fluxGroup: { name: 'Execute' },
9
11
  config: {
10
12
  command: {
11
13
  description: 'The command to run in bash.',
@@ -19,6 +21,28 @@ module Mushy
19
21
  value: '',
20
22
  },
21
23
  },
24
+ examples: {
25
+ "Successful Call" => {
26
+ description: 'This will run the ls command and return the full bash result.',
27
+ input: {
28
+ command: "ls",
29
+ },
30
+ result: {
31
+ "text": "bin\nblue_heart.png\nthe_output.txt\n",
32
+ "success": true,
33
+ "exit_code": 0
34
+ }
35
+ },
36
+ "Failed Call" => {
37
+ description: 'This is an example of what happens when the command fails.',
38
+ input: { command: 'rm file_that_does_not_exist.txt' },
39
+ result: {
40
+ "text": "",
41
+ "success": false,
42
+ "exit_code": 256
43
+ }
44
+ },
45
+ }
22
46
  }
23
47
  end
24
48
 
@@ -7,6 +7,8 @@ module Mushy
7
7
  def self.details
8
8
  {
9
9
  name: 'Browser',
10
+ title: 'Use a browser',
11
+ fluxGroup: { name: 'Web' },
10
12
  description: 'Visit a page in a browser.',
11
13
  config: {
12
14
  url: {
@@ -75,6 +77,124 @@ module Mushy
75
77
  value: '',
76
78
  },
77
79
  },
80
+ examples: {
81
+ "Successful Call" => {
82
+ description: 'This will open https://www.google.com and return the result.',
83
+ config: {
84
+ url: "https://www.google.com",
85
+ },
86
+ result: {
87
+ "url": "https://www.google.com/",
88
+ "status": 200,
89
+ "title": "Google",
90
+ "cookies": [
91
+ {
92
+ "name": "1P_JAR",
93
+ "value": "2021-10-06-12",
94
+ "domain": ".google.com",
95
+ "path": "/",
96
+ "expires": 1636117150.583117,
97
+ "size": 19,
98
+ "httpOnly": false,
99
+ "secure": true,
100
+ "session": false,
101
+ "sameSite": "None",
102
+ "priority": "Medium"
103
+ },
104
+ ],
105
+ "headers": {},
106
+ "time": 1.486214604,
107
+ "body": "<html itemscope=\"\" itemtype=\"http://schema.org/WebPage\" lang=\"en\">...</html>"
108
+ }
109
+ },
110
+ "Login To a Site" => {
111
+ description: 'This will open https://www.yoursitepleasethankyou.com, login using javascript, and then return the state of the browser after logging in.',
112
+ input: {
113
+ url: "https://www.yoursitepleasethankyou.com",
114
+ username: "MYUSERNAME",
115
+ password: "MYPASSWORD",
116
+ },
117
+ config: {
118
+ url: "{{url}}",
119
+ timeout: 10,
120
+ execute: "$('#username').val('{{username}}');
121
+ $('#next').click();
122
+ $('#password').val('{{password}}');
123
+ $('#login').click();"
124
+ },
125
+ result: {
126
+ "url": "https://yoursitepleasethankyou/",
127
+ "status": 200,
128
+ "title": "",
129
+ "cookies": [
130
+ {
131
+ "name": "session_id",
132
+ "value": "1jfujsx5xbnuxmsjmgjhzfpi",
133
+ "domain": ".yoursitepleasethankyou",
134
+ "path": "/",
135
+ "expires": -1,
136
+ "size": 41,
137
+ "httpOnly": true,
138
+ "secure": true,
139
+ "session": true,
140
+ "sameSite": "Lax",
141
+ "priority": "Medium"
142
+ }
143
+ ],
144
+ "headers": {},
145
+ "time": 4.633920809,
146
+ "body": "<html xmlns=\"http://www.w3.org/1999/xhtml\"><head></head>...</html>"
147
+ }
148
+ },
149
+ "Access a Page After Logging In" => {
150
+ description: 'This will open a page using cookies from the previous request. Note that the cookies came from another browser flux event.',
151
+ input: {
152
+ "url": "https://yoursitepleasethankyou/",
153
+ "cookies": [
154
+ {
155
+ "name": "session_id",
156
+ "value": "1jfujsx5xbnuxmsjmgjhzfpi",
157
+ "domain": ".yoursitepleasethankyou",
158
+ "path": "/",
159
+ "expires": -1,
160
+ "size": 41,
161
+ "httpOnly": true,
162
+ "secure": true,
163
+ "session": true,
164
+ "sameSite": "Lax",
165
+ "priority": "Medium"
166
+ }
167
+ ],
168
+ },
169
+ config: {
170
+ url: "https://www.yoursitepleasethankyou.com/myaccount",
171
+ carry_cookies_from: "{{cookies}}"
172
+ },
173
+ result: {
174
+ "url": "https://yoursitepleasethankyou/",
175
+ "status": 200,
176
+ "title": "",
177
+ "cookies": [
178
+ {
179
+ "name": "session_id",
180
+ "value": "1jfujsx5xbnuxmsjmgjhzfpi",
181
+ "domain": ".yoursitepleasethankyou",
182
+ "path": "/",
183
+ "expires": -1,
184
+ "size": 41,
185
+ "httpOnly": true,
186
+ "secure": true,
187
+ "session": true,
188
+ "sameSite": "Lax",
189
+ "priority": "Medium"
190
+ }
191
+ ],
192
+ "headers": {},
193
+ "time": 4.633920809,
194
+ "body": "<html><head></head>Your name is John Doe...</html>"
195
+ }
196
+ }
197
+ }
78
198
  }
79
199
  end
80
200
 
@@ -7,7 +7,9 @@ module Mushy
7
7
  def self.details
8
8
  {
9
9
  name: 'BuildCsv',
10
+ title: "Build CSV",
10
11
  description: 'Build a CSV.',
12
+ fluxGroup: { name: 'CSV' },
11
13
  config: {
12
14
  input_path: {
13
15
  description: 'The path to the set of records to include in the CSV.',
@@ -30,6 +32,27 @@ module Mushy
30
32
  value: true,
31
33
  },
32
34
  },
35
+ examples: {
36
+ "Build a Simple CSV" => {
37
+ description: 'Converts a set of records to a CSV.',
38
+ input: {
39
+ things: [
40
+ { name: "Apple", color:"Red" },
41
+ { name: "Banana", color: "Yellow" },
42
+ { name: "Pear", color: "Green" }
43
+ ]
44
+ },
45
+ config: {
46
+ input_path: "things",
47
+ output_path: "records",
48
+ headers: { name: "Name", color: "Color" },
49
+ header_row: true
50
+ },
51
+ result: {
52
+ records: "Name,Color\nApple,Red\nBanana,Yellow\nPear,Green\n"
53
+ }
54
+ },
55
+ }
33
56
  }
34
57
  end
35
58
 
@@ -5,9 +5,21 @@ module Mushy
5
5
  def self.details
6
6
  {
7
7
  name: 'Cli',
8
+ title: 'Start a flow via command line',
9
+ fluxGroup: { name: 'Starters', position: 0 },
8
10
  description: 'Accept CLI arguments from the run command.',
9
11
  config: {
10
12
  },
13
+ examples: {
14
+ "Calling From The Command Line" => {
15
+ description: 'Calling the CLI with command-line arguments.',
16
+ input: "mushy start file first:John last:Doe",
17
+ result: {
18
+ "first": "John",
19
+ "last": "Doe"
20
+ }
21
+ },
22
+ }
11
23
  }
12
24
  end
13
25
 
@@ -5,7 +5,9 @@ module Mushy
5
5
  def self.details
6
6
  {
7
7
  name: 'Collection',
8
- description: 'Collects events.',
8
+ title: 'Collect and retrieve events',
9
+ description: 'Collect and retrieve events for the flow.',
10
+ fluxGroup: { name: 'Flows' },
9
11
  config: {
10
12
  id: {
11
13
  description: 'The path to the unique id in the body of the element.',