factory_bot_instrumentation 2.9.0 → 3.0.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.
- checksums.yaml +4 -4
- data/.gitignore +1 -0
- data/.rubocop.yml +4 -0
- data/CHANGELOG.md +13 -0
- data/Makefile +7 -1
- data/Rakefile +19 -0
- data/app/assets/javascripts/factory_bot_instrumentation/application.js +454 -12
- data/app/assets/stylesheets/factory_bot_instrumentation/application.css +31 -33
- data/factory_bot_instrumentation.gemspec +8 -1
- data/lib/factory_bot/instrumentation/asset_bundler.rb +194 -0
- data/lib/factory_bot/instrumentation/engine.rb +24 -0
- data/lib/factory_bot/instrumentation/version.rb +1 -1
- data/lib/factory_bot/instrumentation.rb +3 -0
- metadata +2 -6
- data/app/assets/config/factory_bot_instrumentation_manifest.js +0 -2
- data/app/assets/javascripts/factory_bot_instrumentation/create.js +0 -134
- data/app/assets/javascripts/factory_bot_instrumentation/hooks.js +0 -123
- data/app/assets/javascripts/factory_bot_instrumentation/lib/form.js +0 -66
- data/app/assets/javascripts/factory_bot_instrumentation/lib/utils.js +0 -116
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 3a38fbf7fbe98fed861a4fc524a10e5798e8e1abc918c742272365b11c476e81
|
|
4
|
+
data.tar.gz: a9b886fd2f52d856c264b34d8b2d4297df8ea12d1bb6bf1f84b1bbb6480b54ce
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 0bbbb1aaad25753d40cd97dfdd968c9935cfc9d6aded00ceb39aded62067707ebde83364a6b688700bf2cef4c3b43778a3c67c6f54940224a2d6be237aec48bb
|
|
7
|
+
data.tar.gz: 412673861a682f7506c9b56e2be255f56ac66eb604596348de122e29e6aacd6cc54dcbbc6f51ec3eee1dd4c35b30dc2494f96e6b995678245c0d8ac54b275ec1
|
data/.gitignore
CHANGED
data/.rubocop.yml
CHANGED
data/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,19 @@
|
|
|
2
2
|
|
|
3
3
|
* TODO: Replace this bullet point with an actual description of a change.
|
|
4
4
|
|
|
5
|
+
### 3.0.0 (13 May 2026)
|
|
6
|
+
|
|
7
|
+
* Added automatic asset registering with Sprockets ([#46](https://github.com/hausgold/factory_bot_instrumentation/pull/46))
|
|
8
|
+
|
|
9
|
+
So you can remove the following lines from your `app/assets/config/manifest.js`:
|
|
10
|
+
|
|
11
|
+
```js
|
|
12
|
+
//= link factory_bot_instrumentation/application.css
|
|
13
|
+
//= link factory_bot_instrumentation/application.js
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
* Added automatic asset bundling to support Propshaft ([#46](https://github.com/hausgold/factory_bot_instrumentation/pull/46))
|
|
17
|
+
|
|
5
18
|
### 2.9.0 (4 May 2026)
|
|
6
19
|
|
|
7
20
|
* Dropped Ruby 3.x and Rails <8.1 support ([#45](https://github.com/hausgold/factory_bot_instrumentation/pull/45))
|
data/Makefile
CHANGED
|
@@ -28,6 +28,7 @@ HEAD ?= head
|
|
|
28
28
|
ID ?= id
|
|
29
29
|
MKDIR ?= mkdir
|
|
30
30
|
RM ?= rm
|
|
31
|
+
SED ?= sed
|
|
31
32
|
SORT ?= sort
|
|
32
33
|
TEST ?= test
|
|
33
34
|
XARGS ?= xargs
|
|
@@ -174,6 +175,11 @@ stats:
|
|
|
174
175
|
# Print all the notes from the code
|
|
175
176
|
@$(call run-shell,$(BUNDLE) exec $(RAKE) stats)
|
|
176
177
|
|
|
177
|
-
|
|
178
|
+
build:
|
|
179
|
+
# Build and prepare the gem for releasing
|
|
180
|
+
@$(call run-shell,$(BUNDLE) exec $(RAKE) bundle_assets)
|
|
181
|
+
@$(SED) -i '/spec.extensions/d' factory_bot_instrumentation.gemspec
|
|
182
|
+
|
|
183
|
+
release: build
|
|
178
184
|
# Release a new gem version
|
|
179
185
|
@$(BUNDLE) exec $(RAKE) release
|
data/Rakefile
CHANGED
|
@@ -11,6 +11,17 @@ require 'countless/rake_tasks'
|
|
|
11
11
|
APP_RAKEFILE = File.expand_path('spec/dummy/Rakefile', __dir__)
|
|
12
12
|
load 'rails/tasks/engine.rake'
|
|
13
13
|
|
|
14
|
+
desc 'Bundle the engine JavaScript and CSS sources into application.{js,css}'
|
|
15
|
+
task :bundle_assets do
|
|
16
|
+
require 'factory_bot/instrumentation/asset_bundler'
|
|
17
|
+
FactoryBot::Instrumentation::AssetBundler.bundle_all!.each do |kind, files|
|
|
18
|
+
conf = FactoryBot::Instrumentation::AssetBundler.config(kind)
|
|
19
|
+
rel = files.map { |f| f.sub("#{conf[:source_dir]}/", '') }
|
|
20
|
+
puts "Bundled #{files.size} #{kind.upcase} source(s) into " \
|
|
21
|
+
"#{conf[:output_name]}: #{rel.join(', ')}"
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
|
|
14
25
|
desc 'Run all specs in spec directory (excluding plugin specs)'
|
|
15
26
|
RSpec::Core::RakeTask.new(spec: [
|
|
16
27
|
'db:drop', 'db:create', 'db:migrate', 'db:setup'
|
|
@@ -18,6 +29,14 @@ RSpec::Core::RakeTask.new(spec: [
|
|
|
18
29
|
|
|
19
30
|
task default: :spec
|
|
20
31
|
|
|
32
|
+
# Neuter Bundler's `release:guard_clean` check. The `make build` step prunes
|
|
33
|
+
# the unbundled JS/CSS sources from `app/assets/**/factory_bot_instrumentation/`
|
|
34
|
+
# after bundling them into `application.{js,css}`, which leaves the working
|
|
35
|
+
# tree dirty by design. The commit + tag are already in place before release,
|
|
36
|
+
# so the clean-tree guard would only block pushing the artefact we just built.
|
|
37
|
+
Rake::Task['release:guard_clean'].clear
|
|
38
|
+
task 'release:guard_clean'
|
|
39
|
+
|
|
21
40
|
# Configure all code statistics directories
|
|
22
41
|
Countless.configure do |config|
|
|
23
42
|
config.stats_base_directories = [
|
|
@@ -1,16 +1,458 @@
|
|
|
1
|
-
//
|
|
2
|
-
// include all the files listed below.
|
|
1
|
+
// !!! AUTO-GENERATED FILE - DO NOT EDIT !!!
|
|
3
2
|
//
|
|
4
|
-
//
|
|
5
|
-
//
|
|
6
|
-
//
|
|
3
|
+
// This file bundles every JS source under
|
|
4
|
+
// +app/assets/javascripts/factory_bot_instrumentation/+ into a single asset. It is regenerated:
|
|
5
|
+
// * on `gem install` / `bundle install` (via a RubyGems extension
|
|
6
|
+
// hook), and
|
|
7
|
+
// * during gem release (via the `bundle_assets` Rake task).
|
|
7
8
|
//
|
|
8
|
-
//
|
|
9
|
-
// the bottom of the compiled file. JavaScript code in this file should be
|
|
10
|
-
// added after the last require_* statement.
|
|
9
|
+
// To rebuild it manually, run:
|
|
11
10
|
//
|
|
12
|
-
//
|
|
13
|
-
|
|
14
|
-
//
|
|
11
|
+
// $ bundle exec rake bundle_assets
|
|
12
|
+
|
|
13
|
+
// >>> create.js
|
|
14
|
+
window.CreateForm = CreateForm = function()
|
|
15
|
+
{
|
|
16
|
+
this.scope = '#generate';
|
|
17
|
+
this.form = new Form(this.scope);
|
|
18
|
+
this.scenarios = window.scenarios;
|
|
19
|
+
this.select = $(`${this.scope} .scenario`);
|
|
20
|
+
this.desc = $(`${this.scope} .description`);
|
|
21
|
+
|
|
22
|
+
let self = this;
|
|
23
|
+
|
|
24
|
+
this.form.errorContent = function(payload, output, cb)
|
|
25
|
+
{
|
|
26
|
+
window.utils.waterfallWithHooks({
|
|
27
|
+
data: {
|
|
28
|
+
alert: `An unexpected error occurred. Looks like something went wrong
|
|
29
|
+
while generating your new entity. This might be a bug, or an
|
|
30
|
+
unexpected feature. It could be a temporary issue. When this
|
|
31
|
+
is persistent contact your friendly API Instrumentation
|
|
32
|
+
administrator.`,
|
|
33
|
+
output: output,
|
|
34
|
+
payload: payload,
|
|
35
|
+
pre: '',
|
|
36
|
+
post: ''
|
|
37
|
+
},
|
|
38
|
+
pre: window.hooks.preCreateError,
|
|
39
|
+
post: window.hooks.postCreateError,
|
|
40
|
+
action: (payload, innerCb) => {
|
|
41
|
+
cb(null, `
|
|
42
|
+
${payload.pre}
|
|
43
|
+
<div class="alert alert-danger" role="alert">${payload.alert}</div>
|
|
44
|
+
<pre id="data">${payload.output}</pre>
|
|
45
|
+
${window.utils.clipboardButton()}
|
|
46
|
+
${payload.post}
|
|
47
|
+
`);
|
|
48
|
+
innerCb(null, payload);
|
|
49
|
+
}
|
|
50
|
+
});
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
this.form.resultContent = function(payload, output, cb)
|
|
54
|
+
{
|
|
55
|
+
let card = window.utils.card({
|
|
56
|
+
body: `
|
|
57
|
+
<pre id="data">${output}</pre>
|
|
58
|
+
${window.utils.clipboardButton()}
|
|
59
|
+
`
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
window.utils.waterfallWithHooks({
|
|
63
|
+
data: {
|
|
64
|
+
alert: `A new ${self.scenario().name.toLowerCase()} was created.`,
|
|
65
|
+
output: output,
|
|
66
|
+
payload: payload,
|
|
67
|
+
cards: [card],
|
|
68
|
+
pre: '',
|
|
69
|
+
post: '',
|
|
70
|
+
openCard: '#details'
|
|
71
|
+
},
|
|
72
|
+
pre: window.hooks.preCreateResult,
|
|
73
|
+
post: window.hooks.postCreateResult,
|
|
74
|
+
action: (payload, innerCb) => {
|
|
75
|
+
cb(null, `
|
|
76
|
+
${payload.pre}
|
|
77
|
+
<div class="alert alert-success" role="alert">${payload.alert}</div>
|
|
78
|
+
<div class="accordion" id="response">
|
|
79
|
+
${payload.cards.join(' ')}
|
|
80
|
+
</div>
|
|
81
|
+
${payload.post}
|
|
82
|
+
`);
|
|
83
|
+
innerCb(null, payload);
|
|
84
|
+
if (payload.openCard) {
|
|
85
|
+
$(
|
|
86
|
+
`.accordion#response button[data-target="${payload.openCard}"]`
|
|
87
|
+
).click();
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
});
|
|
91
|
+
};
|
|
92
|
+
};
|
|
93
|
+
|
|
94
|
+
CreateForm.prototype.updateDesc = function()
|
|
95
|
+
{
|
|
96
|
+
this.desc.html(this.scenario().desc);
|
|
97
|
+
};
|
|
98
|
+
|
|
99
|
+
CreateForm.prototype.activeScenario = function()
|
|
100
|
+
{
|
|
101
|
+
raw = this.select.find(':selected').val().split('/');
|
|
102
|
+
return { group: raw[0], index: raw[1] };
|
|
103
|
+
};
|
|
104
|
+
|
|
105
|
+
CreateForm.prototype.scenario = function()
|
|
106
|
+
{
|
|
107
|
+
scenario = this.activeScenario();
|
|
108
|
+
return this.scenarios[scenario.group][scenario.index];
|
|
109
|
+
};
|
|
110
|
+
|
|
111
|
+
CreateForm.prototype.bind = function()
|
|
112
|
+
{
|
|
113
|
+
this.form.bind((event) => {
|
|
114
|
+
this.submit();
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
this.select.on('change', this.updateDesc.bind(this));
|
|
118
|
+
this.updateDesc();
|
|
119
|
+
};
|
|
120
|
+
|
|
121
|
+
CreateForm.prototype.submit = function()
|
|
122
|
+
{
|
|
123
|
+
let form = this.form;
|
|
124
|
+
let conf = this.scenario();
|
|
125
|
+
|
|
126
|
+
window.utils.waterfallWithHooks({
|
|
127
|
+
data: {
|
|
128
|
+
factory: conf.factory,
|
|
129
|
+
traits: conf.traits,
|
|
130
|
+
overwrite: conf.overwrite
|
|
131
|
+
},
|
|
132
|
+
pre: window.hooks.preCreate,
|
|
133
|
+
post: window.hooks.postCreate,
|
|
134
|
+
action: (payload, cb) => {
|
|
135
|
+
window.utils.request({
|
|
136
|
+
url: window.createUrl,
|
|
137
|
+
data: JSON.stringify(payload)
|
|
138
|
+
}, (err, result) => {
|
|
139
|
+
if (err) { return cb && cb(err); }
|
|
140
|
+
cb(null, { request: payload, response: result });
|
|
141
|
+
});
|
|
142
|
+
}
|
|
143
|
+
}, function(err, result) {
|
|
144
|
+
if (err) { return form.showError(err, err.responseText); }
|
|
145
|
+
form.showResult(result, result.response);
|
|
146
|
+
});
|
|
147
|
+
};
|
|
148
|
+
|
|
149
|
+
// >>> hooks.js
|
|
150
|
+
// You can define some custom hooks to enhance the functionality. With the help
|
|
151
|
+
// of the following hooks you are able to customize the outputs, perform
|
|
152
|
+
// additional HTTP requests or anything you like.
|
|
15
153
|
//
|
|
16
|
-
|
|
154
|
+
// All the hooks are designed to passthrough a payload. They receive this
|
|
155
|
+
// payload as the first argument, and a callback function to signal the end of
|
|
156
|
+
// the hook. You MUST pass the payload as second parameter to the callback, or
|
|
157
|
+
// pass an error object as first argument. You can modify the payload as you
|
|
158
|
+
// wish, eg. adding some data from subsequent requests.
|
|
159
|
+
//
|
|
160
|
+
// Example hooks:
|
|
161
|
+
//
|
|
162
|
+
// // Error case
|
|
163
|
+
// window.hooks.postCreate.push((payload, cb) => {
|
|
164
|
+
// cb({ error: true});
|
|
165
|
+
// });
|
|
166
|
+
//
|
|
167
|
+
// // Happy case
|
|
168
|
+
// window.hooks.postCreate.push((payload, cb) => {
|
|
169
|
+
// cb(null, Object.assign(payload, { additional: { data: true } }));
|
|
170
|
+
// });
|
|
171
|
+
//
|
|
172
|
+
// Mind the fact that you can define multiple custom functions per hook type.
|
|
173
|
+
// They are executed after each other in a waterfall like flow. The order of
|
|
174
|
+
// the hooks array is therefore essential.
|
|
175
|
+
window.hooks = {
|
|
176
|
+
// With the help of the +perCreate+ hooks you can manipulate the create
|
|
177
|
+
// request parameters. Think of an additional handling which reads an
|
|
178
|
+
// overwrite form or a kind of trait checkboxes to customize the factory
|
|
179
|
+
// call. The +payload+ looks like this:
|
|
180
|
+
//
|
|
181
|
+
// {
|
|
182
|
+
// factory: 'user',
|
|
183
|
+
// traits: ['confirmed'],
|
|
184
|
+
// overwrite: { password: 'secret' }
|
|
185
|
+
// }
|
|
186
|
+
preCreate: [],
|
|
187
|
+
|
|
188
|
+
// The +postCreate+ hook allows you to perform subsequent requests to fetch
|
|
189
|
+
// additional data. Think of a user instrumentation where you want to request
|
|
190
|
+
// a one time token for this user. This token can be added to the payload and
|
|
191
|
+
// can be shown with the help of the +preCreateResult+ hook. The payload
|
|
192
|
+
// contains the request parameters and the response body from the
|
|
193
|
+
// instrumentation request. Here comes an example +payload+:
|
|
194
|
+
//
|
|
195
|
+
// {
|
|
196
|
+
// request: { factory: 'user', /* [..] */ },
|
|
197
|
+
// response: { /* [..] */ }
|
|
198
|
+
// }
|
|
199
|
+
postCreate: [],
|
|
200
|
+
|
|
201
|
+
// With the help of the +preCreateResult+ hook you can customize the output
|
|
202
|
+
// of the result. You could also perform some subsequent requests or some UI
|
|
203
|
+
// preparations. You can access the output options and the runtime payload
|
|
204
|
+
// with all its data and make modifications to them. This hook is triggered
|
|
205
|
+
// before the result is rendered. A sample payload comes here:
|
|
206
|
+
//
|
|
207
|
+
// {
|
|
208
|
+
// alert: 'Your alert text.',
|
|
209
|
+
// output: 'Formatted response',
|
|
210
|
+
// payload: { request: { /* [..] */ }, response: { /* [..] */ } },
|
|
211
|
+
// cards: [
|
|
212
|
+
// `The details accordion card,
|
|
213
|
+
// you can add more, remove the details card
|
|
214
|
+
// or reorder them`
|
|
215
|
+
// ],
|
|
216
|
+
// openCard: '#details', // Open a custom card, or none
|
|
217
|
+
// pre: 'Additinal HTML content before the alert.',
|
|
218
|
+
// post: 'Additinal HTML content after the formatted response output.'
|
|
219
|
+
// }
|
|
220
|
+
preCreateResult: [],
|
|
221
|
+
|
|
222
|
+
// In case you want to perform some logic after the result is rendered, you
|
|
223
|
+
// can use the +postCreateResult+ hook. You can access the output options and
|
|
224
|
+
// the runtime payload with all its data, but changes to them won't take
|
|
225
|
+
// effect. The +payload+ looks like this:
|
|
226
|
+
//
|
|
227
|
+
// {
|
|
228
|
+
// alert: 'Your alert text.',
|
|
229
|
+
// output: 'Formatted response',
|
|
230
|
+
// payload: { request: { /* [..] */ }, response: { /* [..] */ } },
|
|
231
|
+
// cards: [
|
|
232
|
+
// `The details accordion card,
|
|
233
|
+
// you can add more, remove the details card
|
|
234
|
+
// or reorder them`
|
|
235
|
+
// ],
|
|
236
|
+
// openCard: '#details', // Open a custom card, or none
|
|
237
|
+
// pre: 'Additinal HTML content before the alert.',
|
|
238
|
+
// post: 'Additinal HTML content after the formatted response output.'
|
|
239
|
+
// }
|
|
240
|
+
postCreateResult: [],
|
|
241
|
+
|
|
242
|
+
// With the help of the +preCreateError+ hook you can customize the output of
|
|
243
|
+
// the error. Furthermore you can perform some subsequent requests or
|
|
244
|
+
// whatever comes to your mind. You can access the output options and the
|
|
245
|
+
// runtime payload with all its data and make modifications to them. This
|
|
246
|
+
// hook is triggered before the error is rendered. A sample payload comes
|
|
247
|
+
// here:
|
|
248
|
+
//
|
|
249
|
+
// {
|
|
250
|
+
// alert: 'Your alert text.',
|
|
251
|
+
// output: 'Formatted response',
|
|
252
|
+
// payload: { request: { /* [..] */ }, response: { /* [..] */ } },
|
|
253
|
+
// pre: 'Additinal HTML content before the alert.',
|
|
254
|
+
// post: 'Additinal HTML content after the formatted response output.'
|
|
255
|
+
// }
|
|
256
|
+
preCreateError: [],
|
|
257
|
+
|
|
258
|
+
// In case you want to perform some magic after an error occurred, you can use
|
|
259
|
+
// the +postCreateError+ hook. You can access the output options and the
|
|
260
|
+
// runtime payload with all its data, but changes to them won't take effect
|
|
261
|
+
// because this hook is triggered after the error is rendered. The +payload+
|
|
262
|
+
// looks like this:
|
|
263
|
+
//
|
|
264
|
+
// {
|
|
265
|
+
// alert: 'Your alert text.',
|
|
266
|
+
// output: 'Formatted response',
|
|
267
|
+
// payload: { request: { /* [..] */ }, response: { /* [..] */ } },
|
|
268
|
+
// pre: 'Additinal HTML content before the alert.',
|
|
269
|
+
// post: 'Additinal HTML content after the formatted response output.'
|
|
270
|
+
// }
|
|
271
|
+
postCreateError: []
|
|
272
|
+
};
|
|
273
|
+
|
|
274
|
+
// >>> lib/form.js
|
|
275
|
+
window.Form = Form = function(scope)
|
|
276
|
+
{
|
|
277
|
+
this.button = $(scope).find('button');
|
|
278
|
+
this.result = $('#result');
|
|
279
|
+
this.spinner = $('#spinner');
|
|
280
|
+
};
|
|
281
|
+
|
|
282
|
+
Form.prototype.bind = function(action)
|
|
283
|
+
{
|
|
284
|
+
this.button.on('click', (event) => {
|
|
285
|
+
event.preventDefault();
|
|
286
|
+
this.hideResult();
|
|
287
|
+
action(event);
|
|
288
|
+
return false;
|
|
289
|
+
});
|
|
290
|
+
};
|
|
291
|
+
|
|
292
|
+
Form.prototype.hideResult = function()
|
|
293
|
+
{
|
|
294
|
+
this.result.hide();
|
|
295
|
+
this.button.prop('disabled', true);
|
|
296
|
+
this.spinner.show();
|
|
297
|
+
};
|
|
298
|
+
|
|
299
|
+
Form.prototype.showResultContainer = function(html)
|
|
300
|
+
{
|
|
301
|
+
this.result.html(html);
|
|
302
|
+
$('pre').each((i, block) => hljs.highlightBlock(block));
|
|
303
|
+
new ClipboardJS('.cb-copy');
|
|
304
|
+
this.result.show();
|
|
305
|
+
this.button.prop('disabled', false);
|
|
306
|
+
};
|
|
307
|
+
|
|
308
|
+
Form.prototype.showError = function(payload, output)
|
|
309
|
+
{
|
|
310
|
+
this.spinner.hide();
|
|
311
|
+
output = window.utils.prepareOutput(output);
|
|
312
|
+
this.errorContent(payload, output, (err, html) => {
|
|
313
|
+
this.showResultContainer(html);
|
|
314
|
+
});
|
|
315
|
+
};
|
|
316
|
+
|
|
317
|
+
Form.prototype.errorContent = function(payload, output, cb)
|
|
318
|
+
{
|
|
319
|
+
cb(null, `
|
|
320
|
+
<pre id="data">${output}</pre>
|
|
321
|
+
${window.utils.clipboardButton()}
|
|
322
|
+
`);
|
|
323
|
+
};
|
|
324
|
+
|
|
325
|
+
Form.prototype.showResult = function(payload, output)
|
|
326
|
+
{
|
|
327
|
+
this.spinner.hide();
|
|
328
|
+
output = window.utils.prepareOutput(output);
|
|
329
|
+
this.resultContent(payload, output, (err, html) => {
|
|
330
|
+
this.showResultContainer(html);
|
|
331
|
+
});
|
|
332
|
+
};
|
|
333
|
+
|
|
334
|
+
Form.prototype.resultContent = function(payload, output, cb)
|
|
335
|
+
{
|
|
336
|
+
cb(null, `
|
|
337
|
+
<pre id="data">${output}</pre>
|
|
338
|
+
${window.utils.clipboardButton()}
|
|
339
|
+
`);
|
|
340
|
+
};
|
|
341
|
+
|
|
342
|
+
// >>> lib/utils.js
|
|
343
|
+
window.utils = Utils = {};
|
|
344
|
+
|
|
345
|
+
Utils.pushWaterfallPayload = function(data)
|
|
346
|
+
{
|
|
347
|
+
return (cb) => cb(null, data);
|
|
348
|
+
};
|
|
349
|
+
|
|
350
|
+
Utils.waterfallWithHooks = function(opts, cb)
|
|
351
|
+
{
|
|
352
|
+
cb = cb || function(){};
|
|
353
|
+
opts = Object.assign({
|
|
354
|
+
pre: [],
|
|
355
|
+
post: [],
|
|
356
|
+
data: {},
|
|
357
|
+
action: (payload, cb) => cb(null, payload)
|
|
358
|
+
}, opts);
|
|
359
|
+
|
|
360
|
+
async.waterfall([
|
|
361
|
+
// Yield the data to pre hooks
|
|
362
|
+
Utils.pushWaterfallPayload(opts.data),
|
|
363
|
+
// Perform pre hooks
|
|
364
|
+
...opts.pre,
|
|
365
|
+
// Perform the create request
|
|
366
|
+
opts.action,
|
|
367
|
+
// Perform post hooks
|
|
368
|
+
...opts.post
|
|
369
|
+
], cb);
|
|
370
|
+
};
|
|
371
|
+
|
|
372
|
+
Utils.request = function(opts, cb)
|
|
373
|
+
{
|
|
374
|
+
opts = Object.assign({
|
|
375
|
+
url: '/',
|
|
376
|
+
type: 'POST',
|
|
377
|
+
data: '{}',
|
|
378
|
+
dataType: 'json',
|
|
379
|
+
contentType: 'application/json; charset=utf-8',
|
|
380
|
+
ignoreErrors: false
|
|
381
|
+
}, opts || {}, {
|
|
382
|
+
success: (result) => cb(null, result)
|
|
383
|
+
});
|
|
384
|
+
|
|
385
|
+
errCb = (err) => cb(err);
|
|
386
|
+
if (opts.ignoreErrors) {
|
|
387
|
+
errCb = (err) => cb(null, err);
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
$.ajax(opts).fail(errCb);
|
|
391
|
+
};
|
|
392
|
+
|
|
393
|
+
Utils.escape = function(str)
|
|
394
|
+
{
|
|
395
|
+
return str.replace(/&/g, "&")
|
|
396
|
+
.replace(/</g, "<")
|
|
397
|
+
.replace(/>/g, ">");
|
|
398
|
+
};
|
|
399
|
+
|
|
400
|
+
Utils.prepareOutput = function(output)
|
|
401
|
+
{
|
|
402
|
+
try {
|
|
403
|
+
if (typeof output !== 'object') { output = JSON.parse(output); }
|
|
404
|
+
output = JSON.stringify(output, null, 2);
|
|
405
|
+
} catch { }
|
|
406
|
+
|
|
407
|
+
return window.utils.escape(output);
|
|
408
|
+
};
|
|
409
|
+
|
|
410
|
+
Utils.clipboardButton = function(id)
|
|
411
|
+
{
|
|
412
|
+
id = id || 'data';
|
|
413
|
+
return `
|
|
414
|
+
<span class="btn btn-primary cb-copy"
|
|
415
|
+
data-clipboard-target="#${id}">
|
|
416
|
+
<i class="fas fa-paste"></i> Copy result to clipboard
|
|
417
|
+
</span>
|
|
418
|
+
`;
|
|
419
|
+
};
|
|
420
|
+
|
|
421
|
+
Utils.clipboardBadge = function(id)
|
|
422
|
+
{
|
|
423
|
+
id = id || 'data';
|
|
424
|
+
return `
|
|
425
|
+
<span class="badge badge-dark cb-copy" title="Copy result to clipboard"
|
|
426
|
+
data-clipboard-target="#${id}"><i class="fas fa-paste"></i>
|
|
427
|
+
</span>
|
|
428
|
+
`;
|
|
429
|
+
};
|
|
430
|
+
|
|
431
|
+
Utils.card = function(opts)
|
|
432
|
+
{
|
|
433
|
+
opts = Object.assign({
|
|
434
|
+
id: 'details',
|
|
435
|
+
icon: 'fa-asterisk',
|
|
436
|
+
title: 'Details',
|
|
437
|
+
body: ''
|
|
438
|
+
}, opts || {});
|
|
439
|
+
|
|
440
|
+
return `
|
|
441
|
+
<div class="card">
|
|
442
|
+
<div class="card-header">
|
|
443
|
+
<h5 class="mb-0">
|
|
444
|
+
<button class="btn btn-link collapsed" type="button"
|
|
445
|
+
data-toggle="collapse" data-target="#${opts.id}"
|
|
446
|
+
aria-expanded="false">
|
|
447
|
+
<i class="fas ${opts.icon}"></i> ${opts.title}</h5>
|
|
448
|
+
</button>
|
|
449
|
+
</h5>
|
|
450
|
+
</div>
|
|
451
|
+
<div id="${opts.id}" class="collapse" data-parent="#response">
|
|
452
|
+
<div class="card-body">
|
|
453
|
+
${opts.body}
|
|
454
|
+
</div>
|
|
455
|
+
</div>
|
|
456
|
+
</div>
|
|
457
|
+
`;
|
|
458
|
+
};
|
|
@@ -1,42 +1,18 @@
|
|
|
1
1
|
/*
|
|
2
|
-
*
|
|
3
|
-
* include all the files listed below.
|
|
2
|
+
* !!! AUTO-GENERATED FILE - DO NOT EDIT !!!
|
|
4
3
|
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
4
|
+
* This file bundles every CSS source under
|
|
5
|
+
* +app/assets/stylesheets/factory_bot_instrumentation/+ into a single asset. It is regenerated:
|
|
6
|
+
* * on `gem install` / `bundle install` (via a RubyGems extension
|
|
7
|
+
* hook), and
|
|
8
|
+
* * during gem release (via the `bundle_assets` Rake task).
|
|
8
9
|
*
|
|
9
|
-
*
|
|
10
|
-
* at the bottom of the compiled file so the styles you add here take
|
|
11
|
-
* precedence over styles defined in any other CSS/SCSS files in this
|
|
12
|
-
* directory. Styles in this file should be added after the last require_*
|
|
13
|
-
* statement. It is generally better to create a new file per style scope.
|
|
10
|
+
* To rebuild it manually, run:
|
|
14
11
|
*
|
|
15
|
-
|
|
16
|
-
*= require_self
|
|
12
|
+
* $ bundle exec rake bundle_assets
|
|
17
13
|
*/
|
|
18
14
|
|
|
19
|
-
|
|
20
|
-
.result-container { background-color: #f8f8f8 }
|
|
21
|
-
.hljs { background-color: #fff; }
|
|
22
|
-
.jumbotron { padding: 1rem }
|
|
23
|
-
.jumbotron .row { margin-top: 0 }
|
|
24
|
-
.badge { cursor: pointer }
|
|
25
|
-
.btn-link:hover, .btn-link:active, .btn-link:focus { text-decoration: none }
|
|
26
|
-
|
|
27
|
-
pre {
|
|
28
|
-
margin-bottom: 0;
|
|
29
|
-
white-space: pre-wrap;
|
|
30
|
-
white-space: -moz-pre-wrap;
|
|
31
|
-
white-space: -pre-wrap;
|
|
32
|
-
white-space: -o-pre-wrap;
|
|
33
|
-
word-wrap: break-word;
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
pre + .btn {
|
|
37
|
-
margin-top: 1rem;
|
|
38
|
-
}
|
|
39
|
-
|
|
15
|
+
/* >>> spinner.css */
|
|
40
16
|
.spinner {
|
|
41
17
|
margin: 100px auto;
|
|
42
18
|
width: 50px;
|
|
@@ -89,3 +65,25 @@ pre + .btn {
|
|
|
89
65
|
-webkit-transform: scaleY(1.0);
|
|
90
66
|
}
|
|
91
67
|
}
|
|
68
|
+
|
|
69
|
+
/* >>> utils.css */
|
|
70
|
+
.row { margin-top: 5em }
|
|
71
|
+
.result-container { background-color: #f8f8f8 }
|
|
72
|
+
.hljs { background-color: #fff; }
|
|
73
|
+
.jumbotron { padding: 1rem }
|
|
74
|
+
.jumbotron .row { margin-top: 0 }
|
|
75
|
+
.badge { cursor: pointer }
|
|
76
|
+
.btn-link:hover, .btn-link:active, .btn-link:focus { text-decoration: none }
|
|
77
|
+
|
|
78
|
+
pre {
|
|
79
|
+
margin-bottom: 0;
|
|
80
|
+
white-space: pre-wrap;
|
|
81
|
+
white-space: -moz-pre-wrap;
|
|
82
|
+
white-space: -pre-wrap;
|
|
83
|
+
white-space: -o-pre-wrap;
|
|
84
|
+
word-wrap: break-word;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
pre + .btn {
|
|
88
|
+
margin-top: 1rem;
|
|
89
|
+
}
|
|
@@ -24,13 +24,20 @@ Gem::Specification.new do |spec|
|
|
|
24
24
|
}
|
|
25
25
|
|
|
26
26
|
spec.files = `git ls-files -z`.split("\x0").reject do |f|
|
|
27
|
-
f.match(
|
|
27
|
+
next false if f.match?(/application\.(js|css)/)
|
|
28
|
+
|
|
29
|
+
f.match(%r{^(test|spec|features|ext)/}) || f.match(/\.(js|css)$/)
|
|
28
30
|
end
|
|
29
31
|
|
|
30
32
|
spec.bindir = 'exe'
|
|
31
33
|
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
|
32
34
|
spec.require_paths = ['lib']
|
|
33
35
|
|
|
36
|
+
# Regenerate the bundled JavaScript asset whenever the gem is
|
|
37
|
+
# installed. This is the standard RubyGems / Bundler hook and fires
|
|
38
|
+
# for plain +gem install+ as well as for Git-source +bundle install+
|
|
39
|
+
# in third-party applications.
|
|
40
|
+
|
|
34
41
|
spec.required_ruby_version = '>= 4.0'
|
|
35
42
|
|
|
36
43
|
spec.add_dependency 'factory_bot', '~> 6.2'
|