activeadmin_dynamic_fields 0.4.0 → 0.6.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: bf72bdd2f498f04dd656b044b1b711cd1e4962ad98d9190807ac9b4bfa423ba0
4
- data.tar.gz: 036c3c43e6b00ed99b900f21216b824b00dccbf3a3d871cdfa331080f30eceb3
3
+ metadata.gz: 04dad08d3de4d4cfd25de86ec9a07e3010e081afc8481b513e85103026863869
4
+ data.tar.gz: 193871cc16015051ae231a3894c6dbf3fa71f043156fcfac7162bc830380e92c
5
5
  SHA512:
6
- metadata.gz: 94007fc44295a8e251f011ef78884c31a03904e53d264bc9b5aa716645c268a0c3a7343f75b0831f790a36b14f1dcdb03ea6a87fb8e819accb36b871c5617f14
7
- data.tar.gz: bc6beec26ce12eb2f40c70cc8b9fd12f3cdd416ecf735380fd77343d395e7e7b3f2665cfc2fed8a8339651dcbc12db1eaaae3ce7c6019b5cf6bdf133c4390e31
6
+ metadata.gz: ed3de892e2f3e225bfc875c37906dfca703c1769413c631f20caf8a1fcded149c9560cf523c50f3e56ff60cca02622061c5fe8185a09d8bd081963d3674ee9ed
7
+ data.tar.gz: 70e75c688f0b2c8448e23f747752202288c89abf9ab7b4c5b11a1c4de1d92c3c18ff1e029e2e7728f5333bf76c2cc4ad54c0ca5b76402b33e698a83e448b410a
data/README.md CHANGED
@@ -1,8 +1,9 @@
1
- # ActiveAdmin Dynamic Fields [![Gem Version](https://badge.fury.io/rb/activeadmin_dynamic_fields.svg)](https://badge.fury.io/rb/activeadmin_dynamic_fields) [![CircleCI](https://circleci.com/gh/blocknotes/activeadmin_dynamic_fields.svg?style=svg)](https://circleci.com/gh/blocknotes/activeadmin_dynamic_fields)
1
+ # ActiveAdmin Dynamic Fields [![Gem Version](https://badge.fury.io/rb/activeadmin_dynamic_fields.svg)](https://badge.fury.io/rb/activeadmin_dynamic_fields) [![Gem downloads](https://badgen.net/rubygems/dt/activeadmin_dynamic_fields)](https://rubygems.org/gems/activeadmin_dynamic_fields) [![Specs](https://github.com/blocknotes/activeadmin_dynamic_fields/actions/workflows/specs.yml/badge.svg)](https://github.com/blocknotes/activeadmin_dynamic_fields/actions/workflows/specs.yml)
2
2
 
3
3
  An Active Admin plugin to add dynamic behaviors to some fields.
4
4
 
5
5
  Features:
6
+
6
7
  - set conditional checks on fields
7
8
  - trigger actions on target elements
8
9
  - inline field editing
@@ -10,41 +11,67 @@ Features:
10
11
 
11
12
  The easiest way to show how this plugin works is looking the examples [below](#examples).
12
13
 
14
+ Please :star: if you like it.
15
+
13
16
  ## Install
14
- - Add to your Gemfile: `gem 'activeadmin_dynamic_fields'`
15
- - Execute bundle
16
- - Add at the end of your ActiveAdmin javascripts (_app/assets/javascripts/active_admin.js_):
17
+
18
+ First, add the gem to your ActiveAdmin project: `gem 'activeadmin_dynamic_fields'` (and execute `bundle`)
19
+
20
+ If you installed Active Admin **without Webpacker** support:
21
+ - add at the end of your ActiveAdmin javascripts (_app/assets/javascripts/active_admin.js_):
17
22
 
18
23
  ```js
19
24
  //= require activeadmin/dynamic_fields
20
25
  ```
21
26
 
27
+ Otherwise **with Webpacker**:
28
+
29
+ - Execute in your project root:
30
+
31
+ ```sh
32
+ yarn add blocknotes/activeadmin_dynamic_fields
33
+ ```
34
+
35
+ - Add to your *app/javascript/packs/active_admin.js*:
36
+
37
+ ```js
38
+ require('activeadmin_dynamic_fields')
39
+ ```
40
+
22
41
  ## Options
42
+
23
43
  Options are passed to fields using *input_html* parameter as *data* attributes.
24
44
 
25
45
  Conditions:
46
+
26
47
  - **data-if**: check a condition, values:
27
- + **checked**: check if a checkbox is checked
48
+ + **checked**: check if a checkbox is checked (ex. `"data-if": "checked"`)
28
49
  + **not_checked**: check if a checkbox is not checked
29
50
  + **blank**: check if a field is blank
30
51
  + **not_blank**: check if a field is not blank
31
52
  + **changed**: check if the value of an input is changed (dirty)
32
- - **data-eq**: check if a field has a specific value
33
- - **data-not**: check if a field hasn't a specific value
34
- - **data-function**: check the return value of a custom function
53
+ - **data-eq**: check if a field has a specific value (ex. `"data-eq": "42"`)
54
+ - **data-not**: check if a field has not a specific value
55
+ - **data-match**: check if a field match a regexp
56
+ - **data-mismatch**: check if a field doesn't match a regexp (ex. `"data-mismatch": "^\d+$"`)
57
+ - **data-function**: check the return value of a custom function (ex. `"data-function": "my_check"`)
35
58
 
36
59
  Actions:
60
+
37
61
  - **data-then**: action to trigger (alias **data-action**), values:
38
- + **hide**: hides elements
62
+ + **hide**: hides elements (ex. `"data-then": "hide", "data-target": ".errors"`)
39
63
  + **slide**: hides elements (using sliding)
40
64
  + **fade**: hides elements (using fading)
41
- + **addClass**: adds classes
42
- + **setValue**: set a value
43
- + **callback**: call a function (with arguments: **data-args**)
65
+ + **addClass**: adds classes (ex. `"data-then": "addClass red"`)
66
+ + **addStyle**: adds some styles (ex. `"data-then": "addStyle color: #fb1; font-size: 12px"`)
67
+ + **setText**: set the text of an element (ex. `"data-then": "setText A sample text"`)
68
+ + **setValue**: set the value of an input element (ex. `"data-then": "setValue A sample value"`)
69
+ + **callback**: call a function (with arguments: **data-args**) (ex. `"data-then": "callback a_fun"`)
44
70
  - **data-else**: action to trigger when the condition check is not true
45
71
  - **data-args**: arguments passed to the callback function
46
72
 
47
73
  Targets:
74
+
48
75
  - **data-target**: target css selector (from parent fieldset, look for the closest match)
49
76
  - **data-gtarget**: target css selector globally
50
77
 
@@ -53,6 +80,7 @@ A check condition or a custom check function are required. A trigger action is r
53
80
  ## Examples
54
81
 
55
82
  ### Dynamic fields examples
83
+
56
84
  - A checkbox that hides other fields if is checked (ex. model *Article*):
57
85
 
58
86
  ```rb
@@ -124,6 +152,7 @@ function on_change_category(el) {
124
152
  ```
125
153
 
126
154
  ### Inline editing examples
155
+
127
156
  - Prepare a custom member action to save data, an *update* helper function is available (third parameter is optional, allow to filter using strong parameters):
128
157
 
129
158
  ```rb
@@ -161,6 +190,7 @@ end
161
190
  ```
162
191
 
163
192
  ### Dialog example
193
+
164
194
  Example with 2 models: *Author* and *Article*
165
195
 
166
196
  Prepare the content dialog - in Active Admin Author config:
@@ -204,13 +234,16 @@ end
204
234
  The link url is loaded via AJAX before opening the dialog.
205
235
 
206
236
  ## Do you like it? Star it!
207
- If you use this component just star it. A developer is more motivated to improve a project when there is some interest.
208
237
 
209
- Take a look at [other ActiveAdmin components](https://github.com/blocknotes?utf8=✓&tab=repositories&q=activeadmin&type=source) that I made if you are curious.
238
+ If you use this component just star it. A developer is more motivated to improve a project when there is some interest. My other [Active Admin components](https://github.com/blocknotes?utf8=✓&tab=repositories&q=activeadmin&type=source).
239
+
240
+ Or consider offering me a coffee, it's a small thing but it is greatly appreciated: [about me](https://www.blocknot.es/about-me).
210
241
 
211
242
  ## Contributors
243
+
212
244
  - [Mattia Roccoberton](http://blocknot.es): author
213
245
  - The good guys that opened issues and pull requests from time to time
214
246
 
215
247
  ## License
248
+
216
249
  The gem is available as open-source under the terms of the [MIT](LICENSE.txt).
data/Rakefile CHANGED
@@ -1,3 +1,16 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "bundler/gem_tasks"
3
+ require 'bundler/gem_tasks'
4
+
5
+ begin
6
+ require 'rspec/core/rake_task'
7
+
8
+ RSpec::Core::RakeTask.new(:spec) do |t|
9
+ # t.ruby_opts = %w[-w]
10
+ t.rspec_opts = ['--color', '--format documentation']
11
+ end
12
+
13
+ task default: :spec
14
+ rescue LoadError
15
+ puts '! LoadError: no RSpec available'
16
+ end
@@ -1,10 +1,19 @@
1
1
  (function () {
2
2
  'use strict'
3
3
 
4
+ // noinspection JSUnusedGlobalSymbols
4
5
  const ACTIONS = {
5
6
  addClass: (el, name) => el.addClass(name),
7
+ addStyle: (el, extra_style) => {
8
+ let style = (el.attr('style') || '').trim()
9
+ if (!style.includes(extra_style)) {
10
+ if (style) style = style.replace(/;$/, '') + '; ' // ensure style ends with ;
11
+ el.attr('style', `${style}${extra_style}`)
12
+ }
13
+ },
6
14
  callback: (el, name) => {
7
- if (window[name]) window[name](el.data('args'))
15
+ const cb_function = window.hasOwnProperty(name) ? window[name] : null
16
+ if (typeof cb_function === 'function') cb_function(el.data('args'))
8
17
  else {
9
18
  el.attr('data-df-errors', 'callback function not found')
10
19
  console.warn(`activeadmin_dynamic_fields callback function not found: ${name}`)
@@ -12,19 +21,23 @@
12
21
  },
13
22
  fade: el => el.fadeOut(),
14
23
  hide: el => el.hide(),
24
+ setText: (el, text) => el.text(text),
15
25
  setValue: (el, value) => {
16
- if (el.attr('type') == 'checkbox') el.prop('checked', value == '1')
26
+ if (el.attr('type') === 'checkbox') el.prop('checked', value === '1')
17
27
  else el.val(value)
18
28
  el.trigger('change')
19
29
  },
20
30
  slide: el => el.slideUp()
21
31
  }
22
32
 
33
+ // noinspection EqualityComparisonWithCoercionJS, JSUnusedGlobalSymbols
23
34
  const CONDITIONS = {
24
35
  blank: el => el.val().length === 0 || !el.val().trim(),
25
36
  changed: _el => true,
26
37
  checked: el => el.is(':checked'),
27
38
  eq: (el, value) => el.val() == value,
39
+ match: (el, regexp) => regexp.test(el.val()),
40
+ mismatch: (el, regexp) => !regexp.test(el.val()),
28
41
  not: (el, value) => el.val() != value,
29
42
  not_blank: el => el.val().trim(),
30
43
  not_checked: el => !el.is(':checked')
@@ -32,6 +45,9 @@
32
45
 
33
46
  const REVERSE_ACTIONS = {
34
47
  addClass: (el, name) => el.removeClass(name),
48
+ addStyle: (el, extra_style) => {
49
+ if(el.attr('style')) el.attr('style', el.attr('style').replace(extra_style, ''))
50
+ },
35
51
  fade: el => el.fadeIn(),
36
52
  hide: el => el.show(),
37
53
  slide: el => el.slideDown()
@@ -39,74 +55,98 @@
39
55
 
40
56
  class Field {
41
57
  constructor(el) {
42
- const action = el.data('then') || el.data('action') || ''
58
+ this.el = el
59
+ const action_name = this.evaluateAction()
60
+ const result = this.evaluateCondition()
61
+ this.condition = result.condition
62
+ this.condition_arg = result.condition_arg
63
+ this.evaluateTarget(action_name)
64
+ }
65
+
66
+ apply() {
67
+ if (this.condition(this.el, this.condition_arg)) {
68
+ if (this.else_reverse_action) this.else_reverse_action(this.target, this.else_action_arg)
69
+ this.action(this.target, this.action_arg)
70
+ }
71
+ else {
72
+ if (this.reverse_action) this.reverse_action(this.target, this.action_arg)
73
+ if (this.else_action) this.else_action(this.target, this.else_action_arg)
74
+ }
75
+ }
76
+
77
+ evaluateAction() {
78
+ const action = this.el.data('then') || this.el.data('action') || ''
43
79
  const action_name = action.split(' ', 1)[0]
44
- const else_action = el.data('else') || ''
80
+ const else_action = this.el.data('else') || ''
45
81
  const else_action_name = else_action.split(' ', 1)[0]
46
82
 
47
- this.el = el
48
83
  this.action = ACTIONS[action_name]
49
84
  this.action_arg = action.substring(action.indexOf(' ') + 1)
50
85
  this.reverse_action = REVERSE_ACTIONS[action_name]
51
86
  this.else_action = ACTIONS[else_action_name]
52
87
  this.else_action_arg = else_action.substring(else_action.indexOf(' ') + 1)
53
88
  this.else_reverse_action = REVERSE_ACTIONS[else_action_name]
54
- this.condition = CONDITIONS[el.data('if')]
55
- if (!this.condition && el.data('eq')) {
56
- [this.condition, this.condition_arg] = [CONDITIONS['eq'], el.data('eq')]
57
- }
58
- if (!this.condition && el.data('not')) {
59
- [this.condition, this.condition_arg] = [CONDITIONS['not'], el.data('not')]
60
- }
61
- this.custom_function = el.data('function')
62
- if (!this.condition && this.custom_function) {
63
- this.condition = window[this.custom_function]
64
- if (!this.condition) {
65
- el.attr('data-df-errors', 'custom function not found')
89
+
90
+ return action_name
91
+ }
92
+
93
+ evaluateCondition() {
94
+ let value = CONDITIONS[this.el.data('if')?.trim()]
95
+ if (value) return { condition: value }
96
+
97
+ value = this.el.data('eq')
98
+ if (value) return { condition: CONDITIONS['eq'], condition_arg: value }
99
+
100
+ value = this.el.data('not')
101
+ if (value) return { condition: CONDITIONS['not'], condition_arg: value }
102
+
103
+ value = this.el.data('match')
104
+ if (value) return { condition: CONDITIONS['match'], condition_arg: new RegExp(value) }
105
+
106
+ value = this.el.data('mismatch')
107
+ if (value) return { condition: CONDITIONS['mismatch'], condition_arg: new RegExp(value) }
108
+
109
+ this.custom_function = this.el.data('function')
110
+ if (this.custom_function) {
111
+ value = window[this.custom_function]
112
+ if (value) return { condition: value }
113
+ else {
114
+ this.el.attr('data-df-errors', 'custom function not found')
66
115
  console.warn(`activeadmin_dynamic_fields custom function not found: ${this.custom_function}`)
67
116
  }
68
117
  }
69
118
 
70
- // closest find for has many associations
71
- if (el.data('target')) this.target = el.closest('fieldset').find(el.data('target'))
72
- else if (el.data('gtarget')) this.target = $(el.data('gtarget'))
73
- if (action_name == 'callback') this.target = el
119
+ return {}
74
120
  }
75
121
 
76
- apply(el) {
77
- if (this.condition(el, this.condition_arg)) {
78
- if (this.else_reverse_action) this.else_reverse_action(this.target, this.else_action_arg)
79
- this.action(this.target, this.action_arg)
80
- }
81
- else {
82
- if (this.reverse_action) this.reverse_action(this.target, this.action_arg)
83
- if (this.else_action) this.else_action(this.target, this.else_action_arg)
84
- }
122
+ evaluateTarget(action_name) {
123
+ // closest find for has many associations
124
+ if (this.el.data('target')) this.target = this.el.closest('fieldset').find(this.el.data('target'))
125
+ else if (this.el.data('gtarget')) this.target = $(this.el.data('gtarget'))
126
+ if (action_name === 'callback') this.target = this.el
85
127
  }
86
128
 
87
- is_valid() {
129
+ isValid() {
88
130
  if (!this.condition) return false
89
- if (!this.action && !this.custom_function) return false
90
-
91
- return true
131
+ return (this.action || this.custom_function)
92
132
  }
93
133
 
94
134
  setup() {
95
- if (!this.is_valid()) return
96
- if (this.el.data('if') != 'changed') this.apply(this.el)
97
- this.el.on('change', () => this.apply(this.el))
135
+ if (!this.isValid()) return
136
+ if (this.el.data('if') !== 'changed') this.apply()
137
+ this.el.on('change', () => this.apply())
98
138
  }
99
139
  }
100
140
 
101
- // Inline update - must be called binded on the editing element
141
+ // Inline update - must be called bound on the editing element
102
142
  function dfUpdateField() {
103
- if ($(this).data('loading') != '1') {
143
+ if ($(this).data('loading') !== '1') {
104
144
  $(this).data('loading', '1');
105
145
  let _this = $(this);
106
146
  let type = $(this).data('field-type');
107
147
  let new_value;
108
- if (type == 'boolean') new_value = !$(this).data('field-value');
109
- else if (type == 'select') new_value = $(this).val();
148
+ if (type === 'boolean') new_value = !$(this).data('field-value');
149
+ else if (type === 'select') new_value = $(this).val();
110
150
  else new_value = $(this).text();
111
151
  let data = {};
112
152
  data[$(this).data('field')] = new_value;
@@ -115,16 +155,16 @@
115
155
  data: { data: data },
116
156
  method: 'POST',
117
157
  url: $(this).data('save-url'),
118
- complete: function (req, status) {
158
+ complete: function (_req, _status) {
119
159
  $(this).data('loading', '0');
120
160
  },
121
- success: function (data, status, req) {
122
- if (data.status == 'error') {
161
+ success: function (data, _status, _req) {
162
+ if (data.status === 'error') {
123
163
  if ($(this).data('show-errors')) {
124
164
  let result = '';
125
165
  let message = data.message;
126
166
  for (let key in message) {
127
- if (typeof (message[key]) === 'object') {
167
+ if (message.hasOwnProperty(key) && typeof (message[key]) === 'object') {
128
168
  if (result) result += ' - ';
129
169
  result += key + ': ' + message[key].join('; ');
130
170
  }
@@ -150,10 +190,9 @@
150
190
  }
151
191
  }
152
192
 
153
- // Init
154
- $(document).ready(function () {
193
+ function dfInit() {
155
194
  // Setup dynamic fields
156
- const selectors = '.active_admin .input [data-if], .active_admin .input [data-eq], .active_admin .input [data-not], .active_admin .input [data-function]'
195
+ const selectors = '.active_admin .input [data-if], .active_admin .input [data-eq], .active_admin .input [data-not], .active_admin .input [data-match], .active_admin .input [data-mismatch], .active_admin .input [data-function]'
157
196
  $(selectors).each(function () {
158
197
  new Field($(this)).setup()
159
198
  })
@@ -174,20 +213,23 @@
174
213
  $('.active_admin [data-df-dialog]').on('click', function (event) {
175
214
  event.preventDefault()
176
215
  $(this).blur()
177
- if ($('#df-dialog').data('loading') != '1') {
178
- $('#df-dialog').data('loading', '1')
179
- if ($('#df-dialog').length == 0) $('body').append('<div id="df-dialog"></div>')
216
+ const df_dialog = $('#df-dialog')
217
+
218
+ if (df_dialog.data('loading') !== '1') {
219
+ df_dialog.data('loading', '1')
220
+ if (df_dialog.length === 0) $('body').append('<div id="df-dialog"></div>')
180
221
  let title = $(this).attr('title')
181
222
  $.ajax({
182
223
  url: $(this).attr('href'),
183
- complete: function (req, status) {
224
+ complete: function (_req, _status) {
184
225
  $('#df-dialog').data('loading', '0')
185
226
  },
186
- success: function (data, status, req) {
187
- if (title) $('#df-dialog').attr('title', title)
188
- $('#df-dialog').html(data)
189
- $('#df-dialog').dialog({ modal: true })
190
- },
227
+ success: function (data, _status, _req) {
228
+ const dialog = $('#df-dialog')
229
+ if (title) dialog.attr('title', title)
230
+ dialog.html(data)
231
+ dialog.dialog({ modal: true })
232
+ }
191
233
  })
192
234
  }
193
235
  })
@@ -200,11 +242,14 @@
200
242
  $(this).data('field-value', $(this).text())
201
243
  let fnUpdate = $.proxy(dfUpdateField, $(this))
202
244
  $(this).on('blur', function () {
203
- if ($(this).data('field-value') != $(this).text()) fnUpdate()
245
+ if ($(this).data('field-value') !== $(this).text()) fnUpdate()
204
246
  })
205
247
  })
206
248
  $('[data-field][data-field-type="select"][data-save-url]').each(function () {
207
249
  $(this).on('change', $.proxy(dfUpdateField, $(this)))
208
250
  })
209
- })
251
+ }
252
+
253
+ $(document).ready(dfInit)
254
+ $(document).on('turbolinks:load', dfInit)
210
255
  })()
@@ -2,6 +2,6 @@
2
2
 
3
3
  module ActiveAdmin
4
4
  module DynamicFields
5
- VERSION = '0.4.0'
5
+ VERSION = '0.6.0'
6
6
  end
7
7
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: activeadmin_dynamic_fields
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.0
4
+ version: 0.6.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Mattia Roccoberton
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2020-09-22 00:00:00.000000000 Z
11
+ date: 2021-05-24 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activeadmin
@@ -24,132 +24,6 @@ dependencies:
24
24
  - - "~>"
25
25
  - !ruby/object:Gem::Version
26
26
  version: '2.0'
27
- - !ruby/object:Gem::Dependency
28
- name: activestorage
29
- requirement: !ruby/object:Gem::Requirement
30
- requirements:
31
- - - "~>"
32
- - !ruby/object:Gem::Version
33
- version: 6.0.3.2
34
- type: :development
35
- prerelease: false
36
- version_requirements: !ruby/object:Gem::Requirement
37
- requirements:
38
- - - "~>"
39
- - !ruby/object:Gem::Version
40
- version: 6.0.3.2
41
- - !ruby/object:Gem::Dependency
42
- name: capybara
43
- requirement: !ruby/object:Gem::Requirement
44
- requirements:
45
- - - "~>"
46
- - !ruby/object:Gem::Version
47
- version: 3.33.0
48
- type: :development
49
- prerelease: false
50
- version_requirements: !ruby/object:Gem::Requirement
51
- requirements:
52
- - - "~>"
53
- - !ruby/object:Gem::Version
54
- version: 3.33.0
55
- - !ruby/object:Gem::Dependency
56
- name: pry
57
- requirement: !ruby/object:Gem::Requirement
58
- requirements:
59
- - - "~>"
60
- - !ruby/object:Gem::Version
61
- version: 0.13.1
62
- type: :development
63
- prerelease: false
64
- version_requirements: !ruby/object:Gem::Requirement
65
- requirements:
66
- - - "~>"
67
- - !ruby/object:Gem::Version
68
- version: 0.13.1
69
- - !ruby/object:Gem::Dependency
70
- name: puma
71
- requirement: !ruby/object:Gem::Requirement
72
- requirements:
73
- - - "~>"
74
- - !ruby/object:Gem::Version
75
- version: 4.3.5
76
- type: :development
77
- prerelease: false
78
- version_requirements: !ruby/object:Gem::Requirement
79
- requirements:
80
- - - "~>"
81
- - !ruby/object:Gem::Version
82
- version: 4.3.5
83
- - !ruby/object:Gem::Dependency
84
- name: rspec_junit_formatter
85
- requirement: !ruby/object:Gem::Requirement
86
- requirements:
87
- - - "~>"
88
- - !ruby/object:Gem::Version
89
- version: 0.4.1
90
- type: :development
91
- prerelease: false
92
- version_requirements: !ruby/object:Gem::Requirement
93
- requirements:
94
- - - "~>"
95
- - !ruby/object:Gem::Version
96
- version: 0.4.1
97
- - !ruby/object:Gem::Dependency
98
- name: rspec-rails
99
- requirement: !ruby/object:Gem::Requirement
100
- requirements:
101
- - - "~>"
102
- - !ruby/object:Gem::Version
103
- version: 4.0.1
104
- type: :development
105
- prerelease: false
106
- version_requirements: !ruby/object:Gem::Requirement
107
- requirements:
108
- - - "~>"
109
- - !ruby/object:Gem::Version
110
- version: 4.0.1
111
- - !ruby/object:Gem::Dependency
112
- name: rubocop
113
- requirement: !ruby/object:Gem::Requirement
114
- requirements:
115
- - - "~>"
116
- - !ruby/object:Gem::Version
117
- version: 0.90.0
118
- type: :development
119
- prerelease: false
120
- version_requirements: !ruby/object:Gem::Requirement
121
- requirements:
122
- - - "~>"
123
- - !ruby/object:Gem::Version
124
- version: 0.90.0
125
- - !ruby/object:Gem::Dependency
126
- name: selenium-webdriver
127
- requirement: !ruby/object:Gem::Requirement
128
- requirements:
129
- - - "~>"
130
- - !ruby/object:Gem::Version
131
- version: 3.142.7
132
- type: :development
133
- prerelease: false
134
- version_requirements: !ruby/object:Gem::Requirement
135
- requirements:
136
- - - "~>"
137
- - !ruby/object:Gem::Version
138
- version: 3.142.7
139
- - !ruby/object:Gem::Dependency
140
- name: sqlite3
141
- requirement: !ruby/object:Gem::Requirement
142
- requirements:
143
- - - "~>"
144
- - !ruby/object:Gem::Version
145
- version: 1.4.2
146
- type: :development
147
- prerelease: false
148
- version_requirements: !ruby/object:Gem::Requirement
149
- requirements:
150
- - - "~>"
151
- - !ruby/object:Gem::Version
152
- version: 1.4.2
153
27
  description: An Active Admin plugin to add dynamic behaviors to fields
154
28
  email: mat@blocknot.es
155
29
  executables: []
@@ -183,7 +57,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
183
57
  - !ruby/object:Gem::Version
184
58
  version: '0'
185
59
  requirements: []
186
- rubygems_version: 3.0.3
60
+ rubygems_version: 3.1.4
187
61
  signing_key:
188
62
  specification_version: 4
189
63
  summary: Dynamic fields for ActiveAdmin