mushy 0.15.3 → 0.19.0

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.
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.',