satis 1.0.67 → 1.0.69

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 3e05287afa653b87170ae0c2ebccac7548323106ff6fb631a6126ada2b84a554
4
- data.tar.gz: 9e6c4450b2d7b7e0cca1ef42e2076eec116be0b871e0697c8fcf544c9adcb8a9
3
+ metadata.gz: 4d67068f1fbf018ab9c608056352d81b6dac55a162f7d81da49ea7053ae46fbc
4
+ data.tar.gz: 91f4663daf88672d435d705d6452316309fcb8bebc3f32f0560a41f9c372973f
5
5
  SHA512:
6
- metadata.gz: 4a3d17b84eb5dd0fdc1b84bcc316a771355041a3d6de1463ce420bb4b757e0bc8b97c2f476fa416aff09d999e1a73fc0d4eda12c200b0a4905dc2a5b40dba9d9
7
- data.tar.gz: d67f4cafd6e6b07c92cb626c3c95d843c1e02f8b4af4136c1cf462a1a3ff3fd15bb54340caa060750ff47ca2351c4cb64443b18cac61cd17e9cde5183de77b89
6
+ metadata.gz: 1e5a801b78f3494ac01c060ddb06f1abeb99c1c3facd288e04fb39f13e56f34126182778bd0fc91d986bbd7ea90a6a7e565cd3a584395928641cf8769ba49c8d
7
+ data.tar.gz: db160debfab9a8036df9b6522abbe047c61a48a1e57dbc3fc139d96c539786d5e293f21cab71311bdc90f0022db1c4b46f561d04ec8a0e26169ca16ba4cb5eca
@@ -7,6 +7,9 @@ module Satis
7
7
 
8
8
  attr_accessor :original_view_context
9
9
 
10
+ delegate :add_helper, to: :class
11
+
12
+
10
13
  #
11
14
  # This provides us with a translation helper which scopes into the original view
12
15
  # and thereby conveniently scopes the translations.
@@ -46,5 +49,29 @@ module Satis
46
49
  def i18n_scope
47
50
  self.class.name.split('::').second.underscore.to_sym
48
51
  end
52
+
53
+ def component_name
54
+ self.class.name.sub(/::Component$/, "").sub(/^Satis::/, "").underscore
55
+ end
56
+
57
+ def self.add_helper(name, component)
58
+ if respond_to?(name)
59
+ Satis.config.logger.warn("Helper #{name} already defined, skipping.")
60
+ return
61
+ end
62
+ define_method(name) do |*args, **kwargs, &block|
63
+ original_args = args.dup
64
+ options = args.extract_options!
65
+ instance = if options.key? :variant
66
+ variant_component = component.to_s.sub(/::Component$/, "::#{options[:variant].to_s.camelize}::Component").safe_constantize
67
+ (variant_component || component).new(*original_args, **kwargs)
68
+ else
69
+ kwargs[component_name.to_sym] = self
70
+ component.new(*original_args, **kwargs)
71
+ end
72
+ original_view_context.render(instance, &block)
73
+ end
74
+ end
75
+
49
76
  end
50
77
  end
@@ -1,4 +1,4 @@
1
- .sts-card.sts-tabs data-controller="satis-tabs" data-satis-tabs-persist-value="false"
1
+ .sts-card.sts-tabs data-controller="satis-tabs" data-satis-tabs-persist-value="false" data-satis-tabs-key-value="#{key}"
2
2
  - if header?
3
3
  .sts-card__header class="#{tabs? ? '' : 'border-b border-gray-200'} #{header_background_color[:light]} dark:#{header_background_color[:dark]}"
4
4
  .-ml-4.-mt-4.flex.justify-between.items-center.flex-wrap.sm:flex-nowrap
@@ -33,19 +33,27 @@
33
33
  option selected=tab.selected? = t(tab.name, scope: [:tabs])
34
34
  .hidden.sm:block
35
35
  nav.-mb-px.flex.space-x-8.overflow-x-auto aria-label="Tabs"
36
- - tabs.each do |tab|
37
- a.tab id="#{tab.name}" href="#" aria-current="#{tab.selected? ? "page" : ''}" data-satis-tabs-target="tab" data-action="click->satis-tabs#select"
36
+ - tabs.each_with_index do |tab, index|
37
+ - id = tab.id.present? ? tab.id : tab.name
38
+ .flex
39
+ a.tab id="#{id}" class="#{index == (tab.selected_tab_index) ? 'selected' : ''}" href="#" aria-current="#{tab.selected? ? "page" : ''}" data-satis-tabs-target="tab" data-action="click->satis-tabs#select"
38
40
  - if tab.icon
39
41
  i.mr-2 class=tab.icon
40
- = t(tab.name, scope: [:tabs], default: tab.title || tab.name)
42
+ span id="tab_label_#{tab.id}"
43
+ = t(tab.name, scope: [:tabs], default: tab.title || tab.name)
41
44
  i.fal.fa-triangle-exclamation.ml-2.hidden
42
45
  - if tab.badge
43
- span.badge
46
+ span.badge id="tab_badge_#{tab.id}"
44
47
  = tab.badge
48
+ - if tab.tab_menu
49
+ = render(Satis::Menu::Component.new(tab.tab_menu, icon: 'fa-thin fa-square-chevron-down'))
50
+ - if custom_tabs_link_html.present?
51
+ = custom_tabs_link_html
45
52
 
46
- - tabs.each do |tab|
47
- div id="#{tab.name}-content" class="tab-content #{tab.options[:padding] == true ? 'px-6 py-6' : ''}" data-satis-tabs-target="content"
53
+ - tabs.each_with_index do |tab, index|
54
+ div id="#{tab.name}-content" class="tab-content #{tab.options[:padding] == true ? 'px-6 py-6' : ''} #{index == (tab.selected_tab_index) ? 'selected' : ''}" data-satis-tabs-target="content"
48
55
  = tab.to_s
56
+
49
57
  - else
50
58
  div class="#{content_padding ? 'px-6 py-6' : ''}"
51
59
  = content
@@ -7,7 +7,7 @@ module Satis
7
7
  renders_many :tabs, Tab::Component
8
8
  renders_one :footer
9
9
 
10
- attr_reader :icon, :title, :description, :menu, :content_padding, :header_background_color, :initial_actions
10
+ attr_reader :icon, :title, :description, :menu, :content_padding, :header_background_color, :initial_actions, :key, :custom_tabs_link_html
11
11
 
12
12
  def initialize(icon: nil,
13
13
  title: nil,
@@ -17,7 +17,8 @@ module Satis
17
17
  header_background_color: {
18
18
  dark: 'bg-gray-800', light: 'bg-white'
19
19
  },
20
- actions: [])
20
+ actions: [],
21
+ key: nil)
21
22
  super
22
23
  @title = title
23
24
  @title = @title.reject(&:blank?).compact.join(' ') if @title.is_a?(Array)
@@ -27,6 +28,12 @@ module Satis
27
28
  @content_padding = content_padding
28
29
  @header_background_color = header_background_color
29
30
  @initial_actions = actions
31
+ @key = key
32
+ end
33
+
34
+ def custom_tabs_link(&block)
35
+ return unless block_given?
36
+ @custom_tabs_link_html = block.call.html_safe
30
37
  end
31
38
 
32
39
  def tabs?
@@ -27,8 +27,8 @@ module Satis
27
27
  options[:input_html].delete(:autofocus)
28
28
  end
29
29
 
30
- actions = [options[:input_html]['data-action'], 'change->satis-dropdown#display',
31
- 'focus->satis-dropdown#focus'].join(' ')
30
+ actions = [options[:input_html]['data-action'], 'change->satis-dropdown#display',
31
+ 'focus->satis-dropdown#focus'].join(' ') unless options[:input_html]['data-reflex']
32
32
 
33
33
  options[:input_html].merge!('data-satis-dropdown-target' => 'hiddenInput',
34
34
  'data-action' => actions)
@@ -5,6 +5,16 @@
5
5
  }
6
6
 
7
7
  input {
8
- @apply dark:text-gray-300
8
+ @apply dark:text-gray-300;
9
+
10
+ }
11
+
12
+ .warning
13
+ {
14
+ @apply border-orange-500;
15
+ input {
16
+ @apply text-gray-400;
17
+
18
+ }
9
19
  }
10
20
  }
@@ -184,6 +184,12 @@ export default class extends ApplicationController {
184
184
  } else {
185
185
  this.debouncedLocalResults(event)
186
186
  }
187
+
188
+ if (this.searchInputTarget.value) {
189
+ this.searchInputTarget.closest(".bg-white").classList.add("warning")
190
+ } else {
191
+ this.searchInputTarget.closest(".bg-white").classList.remove("warning")
192
+ }
187
193
  }
188
194
 
189
195
  // User presses reset button
@@ -211,6 +217,10 @@ export default class extends ApplicationController {
211
217
  event.preventDefault()
212
218
  }
213
219
 
220
+ if (this.searchInputTarget.closest(".bg-white").classList.contains("warning")) {
221
+ this.searchInputTarget.closest(".bg-white").classList.remove("warning")
222
+ }
223
+
214
224
  return false
215
225
  }
216
226
 
@@ -245,6 +255,10 @@ export default class extends ApplicationController {
245
255
  this.lastSearch = this.searchInputTarget.value
246
256
 
247
257
  this.hiddenInputTarget.dispatchEvent(new Event("change"))
258
+
259
+ if (this.searchInputTarget.closest(".bg-white").classList.contains("warning")) {
260
+ this.searchInputTarget.closest(".bg-white").classList.remove("warning")
261
+ }
248
262
  }
249
263
 
250
264
  // --- Helpers
@@ -257,11 +271,17 @@ export default class extends ApplicationController {
257
271
  this.searchInputTarget.value = currentItem.getAttribute("data-satis-dropdown-item-text")
258
272
 
259
273
  Array.prototype.slice.call(currentItem.attributes).forEach((attr) => {
260
- if (attr.name.startsWith("data") && !attr.name.startsWith("data-satis") && !attr.name.startsWith("data-action")) {
274
+ if (
275
+ attr.name.startsWith("data") &&
276
+ !attr.name.startsWith("data-satis") &&
277
+ !attr.name.startsWith("data-action")
278
+ ) {
261
279
  this.hiddenInputTarget.setAttribute(attr.name, attr.value)
262
280
  }
263
281
  })
264
- this.hiddenInputTarget.dispatchEvent(new CustomEvent("change", { detail: { src: "satis-dropdown" } }))
282
+ if (!this.hiddenInputTarget.getAttribute("data-reflex")) {
283
+ this.hiddenInputTarget.dispatchEvent(new CustomEvent("change", { detail: { src: "satis-dropdown" } }))
284
+ }
265
285
  }
266
286
  }
267
287
 
@@ -362,7 +382,10 @@ export default class extends ApplicationController {
362
382
  this.hiddenInputTarget.value = this.lastSearch
363
383
  }
364
384
 
365
- if (matches.length == 1 && matches[0].getAttribute("data-satis-dropdown-item-text").toLowerCase().indexOf(this.lastSearch.toLowerCase()) >= 0) {
385
+ if (
386
+ matches.length == 1 &&
387
+ matches[0].getAttribute("data-satis-dropdown-item-text").toLowerCase().indexOf(this.lastSearch.toLowerCase()) >= 0
388
+ ) {
366
389
  this.selectItem(matches[0].closest('[data-satis-dropdown-target="item"]'))
367
390
  } else if (matches.length > 1) {
368
391
  this.showResultsList(event)
@@ -372,7 +395,11 @@ export default class extends ApplicationController {
372
395
  // Remote search
373
396
  fetchResults(event) {
374
397
  const promise = new Promise((resolve, reject) => {
375
- if ((this.searchInputTarget.value == this.lastSearch && (this.currentPage == this.lastPage || this.currentPage == this.endPage)) || !this.hasUrlValue) {
398
+ if (
399
+ (this.searchInputTarget.value == this.lastSearch &&
400
+ (this.currentPage == this.lastPage || this.currentPage == this.endPage)) ||
401
+ !this.hasUrlValue
402
+ ) {
376
403
  return
377
404
  }
378
405
 
@@ -401,7 +428,13 @@ export default class extends ApplicationController {
401
428
  this.highLightSelected()
402
429
  this.showResultsList()
403
430
 
404
- if (this.nrOfItems == 1 && this.itemTargets[0].getAttribute("data-satis-dropdown-item-text").toLowerCase().indexOf(this.searchInputTarget.value.toLowerCase()) >= 0) {
431
+ if (
432
+ this.nrOfItems == 1 &&
433
+ this.itemTargets[0]
434
+ .getAttribute("data-satis-dropdown-item-text")
435
+ .toLowerCase()
436
+ .indexOf(this.searchInputTarget.value.toLowerCase()) >= 0
437
+ ) {
405
438
  this.selectItem(this.itemTargets[0].closest('[data-satis-dropdown-target="item"]'))
406
439
  } else if (this.nrOfItems == 1) {
407
440
  this.moveDown()
@@ -6,8 +6,8 @@ module Satis
6
6
  attr_reader :classes
7
7
 
8
8
  def initialize(classes: nil, colored: true)
9
- @classes = classes || ''
10
- @classes += ' colored' if colored
9
+ @classes = classes || ""
10
+ @classes += " colored" if colored
11
11
  end
12
12
  end
13
13
 
@@ -27,11 +27,11 @@ module Satis
27
27
  end
28
28
 
29
29
  def input_class
30
- [@options.fetch(:input_html, {}).fetch(:class, ''), 'sts-input__input', form.has_error?(attribute) && 'is-invalid'].join(' ')
30
+ [@options.fetch(:input_html, {}).fetch(:class, ""), "sts-input__input", form.has_error?(attribute) ? "is-invalid" : ""].join(" ")
31
31
  end
32
32
 
33
33
  def input_container_class
34
- form.has_error?(attribute) && 'is-invalid'
34
+ form.has_error?(attribute) && "is-invalid"
35
35
  end
36
36
  end
37
37
  end
@@ -20,6 +20,14 @@
20
20
  &:focus {
21
21
  box-shadow: none;
22
22
  }
23
+
24
+ &.white {
25
+ background: rgb(255, 255, 255);
26
+
27
+ .dark & {
28
+ background: rgba(255, 255, 255, 0.1);
29
+ }
30
+ }
23
31
  }
24
32
 
25
33
  &__element {
@@ -33,6 +41,14 @@
33
41
  }
34
42
  }
35
43
 
44
+ &.white {
45
+ background: rgb(255, 255, 255);
46
+
47
+ .dark & {
48
+ background: rgba(255, 255, 255, 0.1);
49
+ }
50
+ }
51
+
36
52
  input {
37
53
  @apply -ml-3 -mr-3 -mt-2 -mb-2 w-full;
38
54
 
@@ -1,9 +1,9 @@
1
- div data-controller="satis-menu" data-action="mouseover->satis-menu#show mouseleave->satis-menu#hide"
1
+ div data-controller="satis-menu" data-action="#{menu.event}->satis-menu#show mouseleave->satis-menu#hide"
2
2
  - if content
3
3
  = content
4
4
  - else
5
5
  button.inline-flex.items-center.justify-center.h-8.w-8.rounded-full.focus:outline-none.focus:ring-2.focus:ring-offset-2.focus:ring-primary-500.dark:text-gray-500 aria-expanded="false" aria-haspopup="true" type="button"
6
- span.font-semibold.flex-1 class="#{menu.items.present? ? '' : 'text-gray-200'}"
6
+ span.font-semibold.flex-1 id="#{icon_id}" class="#{menu.items.present? ? '' : 'text-gray-200'}"
7
7
  i class=icon
8
8
 
9
9
  - if menu.items.present?
@@ -4,12 +4,13 @@ module Satis
4
4
  module Menu
5
5
  class Component < Satis::ApplicationComponent
6
6
  # renders_many :tabs, Tab::Component
7
- attr_reader :menu, :icon
7
+ attr_reader :menu, :icon, :icon_id
8
8
 
9
- def initialize(menu, icon: nil)
9
+ def initialize(menu, icon: nil, icon_id: nil)
10
10
  super
11
11
  @menu = menu
12
12
  @icon = icon || 'fa-solid fa-ellipsis-vertical'
13
+ @icon_id = icon_id
13
14
  end
14
15
  end
15
16
  end
@@ -1,9 +1,13 @@
1
1
  li.rounded-sm.px-3.py-1.hover:bg-gray-100.dark:hover:bg-gray-200.flex.items-center data-controller="satis-menu" data-action="mouseover->satis-menu#show mouseleave->satis-menu#hide"
2
2
  a.cursor-pointer.py-1.w-full.text-left.flex.items-center.outline-none.focus:outline-none href=item.link *item.link_attributes
3
+ - if item.type == :custom
4
+ = render(partial: item.link_attributes[:data][:path], locals: item.link_attributes[:data][:parameters])
3
5
  span.pr-1.flex-shrink-0.w-6
4
6
  - if item.icon.present?
5
7
  i class=item.icon
6
- span.pr-1.flex-1 = item.label
8
+ span.pr-1.flex-1
9
+ - unless item.type == :custom
10
+ = item.label
7
11
  span.pr-1.flex-shrink-0.w-6
8
12
  - if item.type == :toggle
9
13
  i.fal.fa-check.hidden data-satis-menu-target="toggle" id="#{item.id}"
@@ -3,7 +3,7 @@
3
3
  module Satis
4
4
  module Tab
5
5
  class Component < Satis::ApplicationComponent
6
- attr_reader :options, :name, :icon, :badge
6
+ attr_reader :options, :name, :icon, :badge, :id, :tab_menu, :selected_tab_index
7
7
 
8
8
  def initialize(name, *args, &block)
9
9
  super
@@ -11,8 +11,11 @@ module Satis
11
11
  @options = args.extract_options!
12
12
  @args = args
13
13
  @icon = options[:icon]
14
+ @id = options[:id]
14
15
  @badge = options[:badge]
16
+ @tab_menu = options[:tab_menu]
15
17
  @block = block
18
+ @selected_tab_index = options[:selected_tab_index]
16
19
  end
17
20
 
18
21
  def responsive?
@@ -1,4 +1,4 @@
1
- .sts-tabs id="#{group}" data-controller="satis-tabs" data-satis-tabs-persist-value="#{persist}"
1
+ .sts-tabs id="#{group}" data-controller="satis-tabs" data-satis-tabs-persist-value="#{persist}" data-satis-tabs-key-value="#{key}"
2
2
  .sm:hidden
3
3
  label.sr-only for="tabs" Select a tab
4
4
  select#tabs.block.w-full.pl-3.pr-10.py-2.text-base.border-gray-300.focus:outline-none.focus:ring-primary-500.focus:border-primary-500.sm:text-sm.rounded-md name="tabs" data-action="change->satis-tabs#select" data-satis-tabs-target="select"
@@ -20,4 +20,4 @@
20
20
  div
21
21
  - tabs.each do |tab|
22
22
  div id="#{tab.name}-content" class="tab-content #{tab.options[:padding] == false ? '' : 'mt-4'}" data-satis-tabs-target="content"
23
- = tab.to_s
23
+ = tab.to_s
@@ -4,12 +4,13 @@ module Satis
4
4
  module Tabs
5
5
  class Component < Satis::ApplicationComponent
6
6
  renders_many :tabs, Tab::Component
7
- attr_reader :group, :persist
7
+ attr_reader :group, :persist, :key
8
8
 
9
- def initialize(group: :main, persist: false)
9
+ def initialize(group: :main, persist: false, key: nil)
10
10
  super
11
11
  @group = group
12
12
  @persist = persist
13
+ @key = key
13
14
  end
14
15
  end
15
16
  end
@@ -5,7 +5,7 @@ import ApplicationController from "../../../../frontend/controllers/application_
5
5
  */
6
6
  export default class extends ApplicationController {
7
7
  static targets = ["tab", "content", "select"]
8
- static values = { persist: Boolean }
8
+ static values = { persist: Boolean, key: String }
9
9
 
10
10
  static keyBindings = [
11
11
  {
@@ -23,9 +23,6 @@ export default class extends ApplicationController {
23
23
  connect() {
24
24
  super.connect()
25
25
 
26
- const ourUrl = new URL(window.location.href)
27
- this.keyBase = ourUrl.pathname.substring(1, ourUrl.pathname.length).replace(/\//, "_") + "_tabs_" + this.context.scope.element.id
28
-
29
26
  let firstErrorIndex
30
27
  this.tabTargets.forEach((tab, index) => {
31
28
  let hasErrors = this.contentTargets[index].querySelectorAll(".is-invalid")
@@ -37,7 +34,13 @@ export default class extends ApplicationController {
37
34
  }
38
35
  })
39
36
 
40
- this.open(firstErrorIndex || this.tabToOpen())
37
+ if (this.keyValue) {
38
+ this.getUserData(this.keyValue).then((data) => {
39
+ this.open(firstErrorIndex || data?.tab_index || 0)
40
+ })
41
+ } else {
42
+ this.open(firstErrorIndex || 0)
43
+ }
41
44
  }
42
45
 
43
46
  select(event) {
@@ -51,7 +54,12 @@ export default class extends ApplicationController {
51
54
  })
52
55
  }
53
56
  this.open(index)
54
- this.storeValue("openTab", index)
57
+
58
+ if (this.keyValue) {
59
+ this.setUserData(this.keyValue, { tab_index: index }).then((data) => {
60
+ //console.log(data)
61
+ })
62
+ }
55
63
 
56
64
  // Cancel the this event (dont show the browser context menu)
57
65
  event.preventDefault()
@@ -75,49 +83,5 @@ export default class extends ApplicationController {
75
83
  this.selectTarget.selectedIndex = index
76
84
  }
77
85
 
78
- storeValue(key, value) {
79
- if (!this.persistValue) {
80
- return
81
- }
82
-
83
- if (typeof Storage !== "undefined") {
84
- sessionStorage.setItem(this.keyBase + "_" + key, value)
85
- }
86
- }
87
-
88
- getValue(key) {
89
- if (!this.persistValue) {
90
- return
91
- }
92
-
93
- if (typeof Storage !== "undefined") {
94
- return sessionStorage.getItem(this.keyBase + "_" + key)
95
- }
96
- }
97
-
98
86
  disconnect() {}
99
-
100
- tabToOpen() {
101
- let urlValue = this.getUrlVar(this.context.scope.element.id + "Tab")
102
-
103
- if (typeof urlValue !== "undefined") {
104
- return urlValue
105
- }
106
-
107
- return this.getValue("openTab") || 0
108
- }
109
-
110
- getUrlVar(name) {
111
- return this.getUrlVars()[name]
112
- }
113
-
114
- getUrlVars() {
115
- let vars = {}
116
-
117
- window.location.href.replace(/[?&]+([^=&]+)=([^&]*)/gi, function (m, key, value) {
118
- vars[key] = value
119
- })
120
-
121
- return vars
122
- }
123
87
  }
@@ -0,0 +1,30 @@
1
+ module Satis
2
+ class UserDataController < ApplicationController
3
+ def show
4
+ key = request.url.split('/user_data/').last
5
+ data = Satis.config.current_user.user_data.keyed(key)
6
+
7
+ if data.id.present?
8
+ render json: data.data, status: 200
9
+ else
10
+ render json: {}, status: 404
11
+ end
12
+ end
13
+
14
+ def update
15
+ key = request.url.split('/user_data/').last
16
+ data = Satis.config.current_user.user_data.keyed(key)
17
+
18
+ data.data = user_data_update_params.as_json
19
+ data.save!
20
+
21
+ render json: data.data, status: 200
22
+ end
23
+
24
+ private
25
+
26
+ def user_data_update_params
27
+ params.require(:user_datum)
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,11 @@
1
+ module Satis
2
+ class UserData < ApplicationRecord
3
+ belongs_to :user, optional: true
4
+
5
+ validates :key, presence: true, uniqueness: { scope: :user_id, allow_nil: true }
6
+
7
+ def self.keyed(key)
8
+ find_or_create_by(key: key)
9
+ end
10
+ end
11
+ end
@@ -13,11 +13,11 @@
13
13
  = yield(nested_form)
14
14
  .col-span-1.flex.justify-center.items-center.association
15
15
  .h-full.w-1.border-r.border-dashed
16
- a.text-primary-600.bg-white.dark:bg-gray-800 href="#" data-action='click->satis-fields-for#addAssociation' style="margin-left: -7px;"
16
+ a.text-primary-600.nested-fields_action href="#" data-action='click->satis-fields-for#addAssociation'
17
17
  i.fal.fa-plus
18
18
  .hidden.col-span-1.flex.justify-center.items-center.association
19
19
  .h-full.w-1.border-r.border-dashed
20
- a.text-primary-600.bg-white.dark:bg-gray-800 href="#" data-action='click->satis-fields-for#removeAssociation' style="margin-left: -7px;"
20
+ a.text-primary-600.nested-fields_action href="#" data-action='click->satis-fields-for#removeAssociation'
21
21
  i.fal.fa-trash
22
22
 
23
23
  = form.rails_fields_for collection do |nested_form|
@@ -29,7 +29,7 @@
29
29
  = yield(nested_form)
30
30
  .col-span-1.flex.justify-center.items-center
31
31
  .h-full.w-1.border-r.border-dashed
32
- a.text-primary-600.bg-white.dark:bg-gray-800 href="#" data-action='click->satis-fields-for#removeAssociation' style="margin-left: -7px;"
32
+ a.text-primary-600.nested-fields_action href="#" data-action='click->satis-fields-for#removeAssociation'
33
33
  i.fal.fa-trash
34
34
 
35
35
  span data-satis-fields-for-target='insertionPoint'
data/config/routes.rb CHANGED
@@ -1,5 +1,3 @@
1
1
  Satis::Engine.routes.draw do
2
- resources :tables, param: :table_name do
3
- get 'filter_collection', on: :collection
4
- end
2
+ resources :user_data, only: %i[show update]
5
3
  end
@@ -0,0 +1,13 @@
1
+ class CreateSatisUserData < ActiveRecord::Migration[6.1]
2
+ def change
3
+ create_table :satis_user_data, id: :uuid do |t|
4
+ t.string :key, null: false
5
+ t.jsonb :data, null: false, default: {}
6
+ t.belongs_to :user, null: false, foreign_key: true, type: :uuid
7
+
8
+ t.timestamps
9
+ end
10
+ add_index :satis_user_data, :key, unique: true
11
+ add_index :satis_user_data, :data, using: :gin
12
+ end
13
+ end
@@ -0,0 +1,10 @@
1
+ class ChangeSatisUserData < ActiveRecord::Migration[7.0]
2
+ disable_ddl_transaction!
3
+ def change
4
+ safety_assured { change_column :satis_user_data, :data, :jsonb, null: true, default: {} }
5
+ safety_assured { change_column :satis_user_data, :user_id, :uuid, null: true, foreign_key: true }
6
+
7
+ remove_index :satis_user_data, [:key]
8
+ add_index :satis_user_data, [:user_id, :key], unique: true, algorithm: :concurrently
9
+ end
10
+ end
@@ -0,0 +1,20 @@
1
+ require_relative 'satisfied'
2
+
3
+ module Satis::ActiveRecordHelpers
4
+ extend ActiveSupport::Concern
5
+
6
+ included do
7
+ delegate :satisfied?, to: :class
8
+ end
9
+
10
+ class_methods do
11
+ def satisfied(options = {})
12
+ @_satis_satisfied_options = options
13
+ include Satis::Satisfied
14
+ end
15
+
16
+ def satisfied?
17
+ included_modules.include?(Satis::Satisfied)
18
+ end
19
+ end
20
+ end
@@ -3,13 +3,14 @@
3
3
  module Satis
4
4
  class Configuration
5
5
  attr_accessor :submit_on_enter, :confirm_before_leave
6
- attr_writer :default_help_text
6
+ attr_writer :default_help_text, :current_user
7
7
  attr_writer :logger
8
8
 
9
9
  def initialize
10
10
  @logger = Logger.new(STDOUT)
11
11
  @submit_on_enter = true
12
12
  @confirm_before_leave = false
13
+ @current_user = -> {}
13
14
 
14
15
  @default_help_text = lambda do |_template, _object, key, _additional_scope|
15
16
  scope = help_scope(template, object, additional_scope)
@@ -57,5 +58,11 @@ module Satis
57
58
 
58
59
  actions.map { |action| help_scope(template, object, additional_scope, action: action) }
59
60
  end
61
+
62
+ def current_user
63
+ raise 'current_user should be a Proc' unless @current_user.is_a? Proc
64
+
65
+ instance_exec(&@current_user)
66
+ end
60
67
  end
61
68
  end
data/lib/satis/engine.rb CHANGED
@@ -23,5 +23,13 @@ module Satis
23
23
  end
24
24
  end
25
25
  end
26
+
27
+ initializer :append_migrations do |app|
28
+ unless app.root.to_s.match? root.to_s
29
+ config.paths['db/migrate'].expanded.each do |expanded_path|
30
+ app.config.paths['db/migrate'] << expanded_path
31
+ end
32
+ end
33
+ end
26
34
  end
27
35
  end
@@ -3,13 +3,13 @@
3
3
  module Satis
4
4
  module Menus
5
5
  class Menu
6
- attr_reader :items, :level
7
-
6
+ attr_reader :items, :level, :event
8
7
  def initialize(*args, **kwargs)
9
8
  @options = args.extract_options!
10
9
  @items = []
11
10
  @scope = Array.wrap(args.first)
12
11
  @level = kwargs[:level] || 0
12
+ @event = kwargs[:event] || 'mouseover'
13
13
  yield self if block_given?
14
14
  end
15
15
 
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Satis
4
+ module Satisfied
5
+ extend ActiveSupport::Concern
6
+
7
+ class_methods do
8
+ def satisfied_options
9
+ @_satis_satisfied_options || {}
10
+ end
11
+ end
12
+
13
+ included do
14
+ has_many :user_data, class_name: 'Satis::UserData'
15
+ end
16
+ end
17
+ end
data/lib/satis/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Satis
2
- VERSION = "1.0.67"
2
+ VERSION = "1.0.69"
3
3
  end
data/lib/satis.rb CHANGED
@@ -1,6 +1,7 @@
1
1
  require 'satis/version'
2
2
  require 'satis/engine'
3
3
  require 'satis/configuration'
4
+ require 'satis/active_record_helpers'
4
5
 
5
6
  require 'view_component'
6
7
  require 'browser'
@@ -32,5 +33,16 @@ module Satis
32
33
  def add_helper(name, component)
33
34
  Satis::Helpers::Container.add_helper(name, component)
34
35
  end
36
+
37
+ def add_component_helper(component_name, name, component)
38
+ klass = "Satis::#{component_name.to_s.classify}::Component".safe_constantize
39
+ return if klass.blank?
40
+ klass.add_helper name, component
41
+ end
42
+ end
43
+
44
+ # Include helpers
45
+ ActiveSupport.on_load(:active_record) do
46
+ include Satis::ActiveRecordHelpers
35
47
  end
36
48
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: satis
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.67
4
+ version: 1.0.69
5
5
  platform: ruby
6
6
  authors:
7
7
  - Tom de Grunt
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2022-11-10 00:00:00.000000000 Z
11
+ date: 2022-12-22 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: browser
@@ -164,14 +164,19 @@ files:
164
164
  - app/components/satis/tabs/component.scss
165
165
  - app/components/satis/tabs/component_controller.js
166
166
  - app/controllers/satis/application_controller.rb
167
+ - app/controllers/satis/user_data_controller.rb
167
168
  - app/helpers/satis/application_helper.rb
168
169
  - app/jobs/satis/application_job.rb
169
170
  - app/mailers/satis/application_mailer.rb
170
171
  - app/models/satis/application_record.rb
172
+ - app/models/satis/user_data.rb
171
173
  - app/views/shared/_fields_for.html.slim
172
174
  - config/routes.rb
175
+ - db/migrate/20220929142147_create_satis_user_data.rb
176
+ - db/migrate/20221212083110_change_satis_user_data.rb
173
177
  - lib/satis.rb
174
178
  - lib/satis/action_controller_helpers.rb
179
+ - lib/satis/active_record_helpers.rb
175
180
  - lib/satis/configuration.rb
176
181
  - lib/satis/engine.rb
177
182
  - lib/satis/forms/builder.rb
@@ -184,6 +189,7 @@ files:
184
189
  - lib/satis/menus/builder.rb
185
190
  - lib/satis/menus/item.rb
186
191
  - lib/satis/menus/menu.rb
192
+ - lib/satis/satisfied.rb
187
193
  - lib/satis/version.rb
188
194
  - lib/tasks/satis_tasks.rake
189
195
  homepage: https://github.com/entdec/satis