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 +4 -4
- data/app/components/satis/application_component.rb +27 -0
- data/app/components/satis/card/component.html.slim +15 -7
- data/app/components/satis/card/component.rb +9 -2
- data/app/components/satis/dropdown/component.rb +2 -2
- data/app/components/satis/dropdown/component.scss +11 -1
- data/app/components/satis/dropdown/component_controller.js +38 -5
- data/app/components/satis/input/component.rb +4 -4
- data/app/components/satis/input/component.scss +16 -0
- data/app/components/satis/menu/component.html.slim +2 -2
- data/app/components/satis/menu/component.rb +3 -2
- data/app/components/satis/menu_item/component.html.slim +5 -1
- data/app/components/satis/tab/component.rb +4 -1
- data/app/components/satis/tabs/component.html.slim +2 -2
- data/app/components/satis/tabs/component.rb +3 -2
- data/app/components/satis/tabs/component_controller.js +14 -50
- data/app/controllers/satis/user_data_controller.rb +30 -0
- data/app/models/satis/user_data.rb +11 -0
- data/app/views/shared/_fields_for.html.slim +3 -3
- data/config/routes.rb +1 -3
- data/db/migrate/20220929142147_create_satis_user_data.rb +13 -0
- data/db/migrate/20221212083110_change_satis_user_data.rb +10 -0
- data/lib/satis/active_record_helpers.rb +20 -0
- data/lib/satis/configuration.rb +8 -1
- data/lib/satis/engine.rb +8 -0
- data/lib/satis/menus/menu.rb +2 -2
- data/lib/satis/satisfied.rb +17 -0
- data/lib/satis/version.rb +1 -1
- data/lib/satis.rb +12 -0
- metadata +8 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 4d67068f1fbf018ab9c608056352d81b6dac55a162f7d81da49ea7053ae46fbc
|
4
|
+
data.tar.gz: 91f4663daf88672d435d705d6452316309fcb8bebc3f32f0560a41f9c372973f
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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.
|
37
|
-
|
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
|
-
=
|
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.
|
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 =
|
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)
|
@@ -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 (
|
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.
|
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 (
|
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 (
|
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 (
|
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 +=
|
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,
|
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) &&
|
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="
|
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
|
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
|
-
|
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
|
-
|
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
|
@@ -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.
|
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.
|
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.
|
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
@@ -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
|
data/lib/satis/configuration.rb
CHANGED
@@ -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
|
data/lib/satis/menus/menu.rb
CHANGED
@@ -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
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.
|
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
|
+
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
|