satis 2.1.39 → 2.1.41
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 -1
- data/Rakefile +0 -4
- data/app/assets/stylesheets/satis/application.css +2 -0
- data/app/components/satis/call_to_action/component.css +11 -0
- data/app/components/satis/call_to_action/component.html.slim +25 -0
- data/app/components/satis/call_to_action/component.rb +24 -0
- data/app/components/satis/card/component.rb +1 -1
- data/app/components/satis/link_button/component.css +11 -0
- data/app/components/satis/link_button/component.html.slim +11 -0
- data/app/components/satis/link_button/component.rb +17 -0
- data/app/components/satis/tab/component.rb +2 -2
- data/app/javascript/satis/controllers/fields_for_controller.js +79 -7
- data/app/views/shared/_fields_for.html.slim +16 -2
- data/lib/satis/helpers/container.rb +11 -10
- data/lib/satis/version.rb +1 -1
- data/lib/satis.rb +6 -5
- 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: 3eec0a994c04e1229ba122c0c5b8443e24405834a7fa461a4606edd1d21fcc46
|
4
|
+
data.tar.gz: 38216df0a8fbaa32b085a04386b0cb50703ff191f4e25a20ec92f09505756256
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 9de946bcc30083902717763eaa4be4ddad6cd2103486c3fa94680ceff2ff07d4a0a0be3e913c5060d6c16f25e82b856749d46c9f659164010075ed95f28f44f1
|
7
|
+
data.tar.gz: 395f70551a7b09aa4f9eaadcebcba2e2fcdd11eb4a586142cfb4e51c8ac153637fe012c6558f6dc49aecc246a0e053724ea87a166e6c36e0630ffd0f4310fc62
|
data/.gitignore
CHANGED
data/Rakefile
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
@import '../../../components/satis/appearance_switcher/component.css';
|
2
2
|
@import '../../../components/satis/breadcrumbs/component.css';
|
3
3
|
@import '../../../components/satis/card/component.css';
|
4
|
+
@import '../../../components/satis/call_to_action/component.css';
|
4
5
|
@import '../../../components/satis/color_picker/component.css';
|
5
6
|
@import '../../../components/satis/date_time_picker/component.css';
|
6
7
|
@import '../../../components/satis/dialog/component.css';
|
@@ -9,6 +10,7 @@
|
|
9
10
|
@import '../../../components/satis/flash_messages/component.css';
|
10
11
|
@import '../../../components/satis/input/component.css';
|
11
12
|
@import '../../../components/satis/input_array/component.css';
|
13
|
+
@import '../../../components/satis/link_button/component.css';
|
12
14
|
@import '../../../components/satis/map/component.css';
|
13
15
|
@import '../../../components/satis/menu/component.css';
|
14
16
|
@import '../../../components/satis/page/component.css';
|
@@ -0,0 +1,25 @@
|
|
1
|
+
.sts-call-to-action class=style
|
2
|
+
.px-6.py-12.sm:px-6.sm:py-16.lg:px-8
|
3
|
+
.mx-auto.max-w-2xl.text-center
|
4
|
+
h2.text-balance.text-4xl.font-semibold.tracking-tight.text-gray-900.sm:text-5xl.dark:text-white
|
5
|
+
= title
|
6
|
+
p.mx-auto.mt-6.max-w-xl.text-pretty.text-lg/8.text-gray-600
|
7
|
+
= description
|
8
|
+
.mt-10.flex.items-center.justify-center.gap-x-6
|
9
|
+
- actions.each do |action|
|
10
|
+
= action
|
11
|
+
|
12
|
+
/.bg-primary-600.rounded-md
|
13
|
+
.px-6.py-24.sm:px-6.sm:py-32.lg:px-8
|
14
|
+
.mx-auto.max-w-2xl.text-center
|
15
|
+
h2.text-balance.text-4xl.font-semibold.tracking-tight.text-white.sm:text-5xl
|
16
|
+
| Boost your productivity. Start using our app today.
|
17
|
+
p.mx-auto.mt-6.max-w-xl.text-pretty.text-lg/8.text-primary-200
|
18
|
+
| Incididunt sint fugiat pariatur cupidatat consectetur sit cillum anim id veniam aliqua proident excepteur commodo do ea.
|
19
|
+
.mt-10.flex.items-center.justify-center.gap-x-6
|
20
|
+
a.rounded-md.bg-white.px-3.5.py-2.5.text-sm.font-semibold.text-primary-600.shadow-sm.hover:bg-primary-50.focus-visible:outline.focus-visible:outline-2.focus-visible:outline-offset-2.focus-visible:outline-white[href="#"]
|
21
|
+
| Get started
|
22
|
+
a.text-sm.font-semibold.leading-6.text-white[href="#"]
|
23
|
+
| Learn more
|
24
|
+
span[aria-hidden="true"]
|
25
|
+
| →
|
@@ -0,0 +1,24 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Satis
|
4
|
+
module CallToAction
|
5
|
+
class Component < Satis::ApplicationComponent
|
6
|
+
renders_many :actions, LinkButton::Component
|
7
|
+
|
8
|
+
attr_reader :identifier, :title, :description, :style
|
9
|
+
|
10
|
+
def initialize(identifier = nil,
|
11
|
+
icon: nil,
|
12
|
+
title: nil,
|
13
|
+
description: nil,
|
14
|
+
style: :regular)
|
15
|
+
super
|
16
|
+
|
17
|
+
@identifier = identifier
|
18
|
+
@title = title
|
19
|
+
@description = description
|
20
|
+
@style = style
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -27,7 +27,7 @@ module Satis
|
|
27
27
|
super
|
28
28
|
|
29
29
|
if identifier.blank?
|
30
|
-
|
30
|
+
Satis::Deprecation.warn('Calling sts.card with the id parameter will become mandatory')
|
31
31
|
end
|
32
32
|
|
33
33
|
@identifier = identifier
|
@@ -0,0 +1,11 @@
|
|
1
|
+
a.sts-link-button.button {
|
2
|
+
@apply rounded-md px-3.5 py-2.5 text-sm font-semibold text-white shadow-sm focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-primary-600;
|
3
|
+
}
|
4
|
+
|
5
|
+
a.sts-link-button.primary {
|
6
|
+
@apply bg-primary-600 hover:bg-primary-500 dark:bg-white dark:text-primary-600;
|
7
|
+
}
|
8
|
+
|
9
|
+
a.sts-link-button.link {
|
10
|
+
@apply mt-1 text-sm font-semibold leading-6 text-gray-600;
|
11
|
+
}
|
@@ -0,0 +1,11 @@
|
|
1
|
+
- if type == :primary
|
2
|
+
a.sts-link-button.button.primary href=url
|
3
|
+
= title
|
4
|
+
- if type == :button
|
5
|
+
a.sts-link-button.button href=url
|
6
|
+
= title
|
7
|
+
- if type == :link
|
8
|
+
a.sts-link-button.link href=url
|
9
|
+
= title
|
10
|
+
- if icon
|
11
|
+
i.ml-2 aria-hidden="true" class=icon
|
@@ -0,0 +1,17 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Satis
|
4
|
+
module LinkButton
|
5
|
+
class Component < Satis::ApplicationComponent
|
6
|
+
attr_reader :title, :url, :icon, :type, :class_names
|
7
|
+
# renders_many :items
|
8
|
+
def initialize(type, title: nil, icon: nil, url: nil)
|
9
|
+
@type = type.to_sym
|
10
|
+
@title = title
|
11
|
+
@icon = icon
|
12
|
+
@url = url
|
13
|
+
@class_names = class_names
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -36,12 +36,12 @@ module Satis
|
|
36
36
|
# FIXME: Obsolete these
|
37
37
|
if tab_menu.present?
|
38
38
|
@menu ||= tab_menu
|
39
|
-
|
39
|
+
Satis::Deprecation.warn('Calling tab with the tab_menu parameter, use menu instead')
|
40
40
|
end
|
41
41
|
|
42
42
|
if selected_tab_index.present?
|
43
43
|
@selected_tab_index = selected_tab_index # use selected
|
44
|
-
|
44
|
+
Satis::Deprecation.warn('Calling tab with the selected_tab_index parameter, use selected instead')
|
45
45
|
end
|
46
46
|
|
47
47
|
@block = block
|
@@ -7,6 +7,7 @@ export default class FieldsForController extends ApplicationController {
|
|
7
7
|
super.connect()
|
8
8
|
|
9
9
|
this.boundMonitorChanges = this.monitorChanges.bind(this)
|
10
|
+
this.boundMouseMove = this.mouseMove.bind(this)
|
10
11
|
this.addNewLine()
|
11
12
|
}
|
12
13
|
|
@@ -20,30 +21,81 @@ export default class FieldsForController extends ApplicationController {
|
|
20
21
|
})
|
21
22
|
|
22
23
|
let tmpNode = event.target.closest(".nested-fields")
|
24
|
+
this.setupNewChild(tmpNode)
|
25
|
+
|
26
|
+
this.addNewLine()
|
27
|
+
|
28
|
+
window.scrollBy(0, this.element.querySelector(".nested-fields").clientHeight)
|
29
|
+
}
|
30
|
+
|
31
|
+
setupNewChild(tmpNode) {
|
23
32
|
tmpNode.classList.remove("template")
|
24
33
|
tmpNode.querySelectorAll(".association").forEach((item) => {
|
25
34
|
if (item.classList.contains("hidden")) {
|
26
|
-
item.
|
35
|
+
if (!item.querySelector("a[data-action='click->satis-fields-for#cloneAssociation']")) {
|
36
|
+
item.classList.remove("hidden")
|
37
|
+
}
|
27
38
|
} else {
|
28
|
-
item.
|
39
|
+
if (!item.querySelector("a[data-action='click->satis-fields-for#cloneAssociation']")) {
|
40
|
+
item.remove()
|
41
|
+
} else {
|
42
|
+
item.classList.add("hidden")
|
43
|
+
}
|
29
44
|
}
|
30
45
|
})
|
31
46
|
|
32
47
|
// Simply replace every child node's attributes value, replacing TEMPLATE
|
33
|
-
let
|
48
|
+
let templateId = new Date().valueOf()
|
49
|
+
let templateName = tmpNode.querySelector("span.temp-name").getAttribute("temp_name")
|
50
|
+
tmpNode.querySelector("span.temp-id").setAttribute("temp_id", templateId)
|
34
51
|
tmpNode.querySelectorAll("*").forEach((node) => {
|
35
52
|
for (let attribute of node.attributes) {
|
36
|
-
attribute.value = attribute.value.replace(/TEMPLATE/g,
|
53
|
+
attribute.value = attribute.value.replace(/TEMPLATE-NAME/g, `[${templateName}][${templateId}]`)
|
54
|
+
attribute.value = attribute.value.replace(/TEMPLATE-ID/g, `${templateName}_${templateId}`)
|
55
|
+
|
56
|
+
attribute.value = attribute.value.replace(/TEMPLATE/g, templateId)
|
37
57
|
}
|
38
58
|
})
|
39
59
|
|
40
60
|
tmpNode.querySelectorAll("template").forEach((node) => {
|
41
|
-
node.innerHTML = node.innerHTML.replace(/TEMPLATE/g,
|
61
|
+
node.innerHTML = node.innerHTML.replace(/TEMPLATE-NANE/g, `[${templateName}][${templateId}]`)
|
62
|
+
node.innerHTML = node.innerHTML.replace(/TEMPLATE-ID/g, `${templateName}_${templateId}`)
|
63
|
+
|
64
|
+
node.innerHTML = node.innerHTML.replace(/TEMPLATE/g, templateId)
|
42
65
|
})
|
43
66
|
|
44
|
-
this.
|
67
|
+
tmpNode.addEventListener("mousemove", this.boundMouseMove)
|
68
|
+
}
|
45
69
|
|
46
|
-
|
70
|
+
cloneAssociation(event) {
|
71
|
+
event.preventDefault()
|
72
|
+
|
73
|
+
let item = event.target.closest(".nested-fields")
|
74
|
+
let templateId = item.querySelector("span.temp-id").getAttribute("temp_id")
|
75
|
+
let templateName = item.querySelector("span.temp-name").getAttribute("temp_name")
|
76
|
+
|
77
|
+
let clonedItem = item.cloneNode(true)
|
78
|
+
|
79
|
+
clonedItem.querySelectorAll("*").forEach((node) => {
|
80
|
+
for (let attribute of node.attributes) {
|
81
|
+
attribute.value = attribute.value.replaceAll(`[${templateName}][${templateId}]`, "TEMPLATE-NAME")
|
82
|
+
attribute.value = attribute.value.replaceAll(`${templateName}_${templateId}`, "TEMPLATE-ID")
|
83
|
+
}
|
84
|
+
})
|
85
|
+
|
86
|
+
//this.insertionPointTarget.appendChild(clonedItem)
|
87
|
+
this.insertionPointTarget.insertBefore(
|
88
|
+
clonedItem,
|
89
|
+
this.insertionPointTarget.childNodes[this.insertionPointTarget.childNodes.length - 1]
|
90
|
+
)
|
91
|
+
|
92
|
+
clonedItem
|
93
|
+
.querySelector("a[data-action='click->satis-fields-for#removeAssociation']")
|
94
|
+
?.parentElement.classList.remove("hidden")
|
95
|
+
clonedItem
|
96
|
+
.querySelector("a[data-action='click->satis-fields-for#cloneAssociation']")
|
97
|
+
?.parentElement.classList.add("hidden")
|
98
|
+
this.setupNewChild(clonedItem)
|
47
99
|
}
|
48
100
|
|
49
101
|
addNewLine() {
|
@@ -59,6 +111,26 @@ export default class FieldsForController extends ApplicationController {
|
|
59
111
|
}, 500)
|
60
112
|
}
|
61
113
|
|
114
|
+
mouseMove(event) {
|
115
|
+
let item = event.target.closest(".nested-fields")
|
116
|
+
|
117
|
+
if (event.altKey) {
|
118
|
+
item
|
119
|
+
.querySelector("a[data-action='click->satis-fields-for#removeAssociation']")
|
120
|
+
?.parentElement.classList.add("hidden")
|
121
|
+
item
|
122
|
+
.querySelector("a[data-action='click->satis-fields-for#cloneAssociation']")
|
123
|
+
?.parentElement.classList.remove("hidden")
|
124
|
+
} else {
|
125
|
+
item
|
126
|
+
.querySelector("a[data-action='click->satis-fields-for#removeAssociation']")
|
127
|
+
?.parentElement.classList.remove("hidden")
|
128
|
+
item
|
129
|
+
.querySelector("a[data-action='click->satis-fields-for#cloneAssociation']")
|
130
|
+
?.parentElement.classList.add("hidden")
|
131
|
+
}
|
132
|
+
}
|
133
|
+
|
62
134
|
monitorChanges(event) {
|
63
135
|
if (event?.detail?.src == "satis-dropdown") {
|
64
136
|
// Skip events caused by the initial load of a satis-dropdown
|
@@ -5,9 +5,12 @@
|
|
5
5
|
- if template_object
|
6
6
|
template data-satis-fields-for-target='template'
|
7
7
|
= form.rails_fields_for collection, template_object, child_index: 'TEMPLATE' do |nested_form|
|
8
|
+
- items_name_parts = nested_form.object_name.split(']').map{|x| x.gsub('[', '')}
|
8
9
|
.nested-fields.template.py-2.field-for-bg
|
9
10
|
= nested_form.input :id, as: :hidden
|
10
11
|
= nested_form.input :_destroy, as: :hidden
|
12
|
+
span.hidden.temp-id temp_id=items_name_parts[-1]
|
13
|
+
span.hidden.temp-name temp_name=items_name_parts[-2]
|
11
14
|
.grid.grid-cols-12.gap-4
|
12
15
|
.col-span-11.fields
|
13
16
|
= yield(nested_form)
|
@@ -15,18 +18,29 @@
|
|
15
18
|
.h-full.w-1.border-r.border-dashed.dark:border-gray-700
|
16
19
|
a.text-primary-600.nested-fields_action href="#" data-action='click->satis-fields-for#addAssociation'
|
17
20
|
i.fal.fa-plus
|
21
|
+
.hidden.col-span-1.flex.justify-center.items-center.association
|
22
|
+
.h-full.w-1.border-r.border-dashed
|
23
|
+
a.text-primary-600.nested-fields_action href="#" data-action='click->satis-fields-for#cloneAssociation'
|
24
|
+
i.fa-light.fa-copy
|
18
25
|
.hidden.col-span-1.flex.justify-center.items-center.association
|
19
26
|
.h-full.w-1.border-r.border-dashed.dark:border-gray-700
|
20
27
|
a.text-primary-600.nested-fields_action href="#" data-action='click->satis-fields-for#removeAssociation'
|
21
28
|
i.fal.fa-trash
|
22
29
|
|
23
|
-
= form.
|
24
|
-
|
30
|
+
= form.fields_for collection do |nested_form|
|
31
|
+
- items_name_parts = nested_form.object_name.split(']').map{|x| x.gsub('[', '')}
|
32
|
+
.nested-fields.field-for-bg.py-2 data-action='mousemove->satis-fields-for#mouseMove'
|
25
33
|
= nested_form.input :id, as: :hidden
|
26
34
|
= nested_form.input :_destroy, as: :hidden
|
35
|
+
span.hidden.temp-id temp_id=items_name_parts[-1]
|
36
|
+
span.hidden.temp-name temp_name=items_name_parts[-2]
|
27
37
|
.grid.grid-cols-12.gap-4
|
28
38
|
.col-span-11
|
29
39
|
= yield(nested_form)
|
40
|
+
.hidden.col-span-1.flex.justify-center.items-center.association
|
41
|
+
.h-full.w-1.border-r.border-dashed
|
42
|
+
a.text-primary-600.nested-fields_action href="#" data-action='click->satis-fields-for#cloneAssociation'
|
43
|
+
i.fa-light.fa-copy
|
30
44
|
.col-span-1.flex.justify-center.items-center
|
31
45
|
.h-full.w-1.border-r.border-dashed.dark:border-gray-700
|
32
46
|
a.text-primary-600.nested-fields_action href="#" data-action='click->satis-fields-for#removeAssociation'
|
@@ -12,6 +12,7 @@ module Satis
|
|
12
12
|
add_helper :avatar, Satis::Avatar::Component
|
13
13
|
add_helper :breadcrumbs, Satis::Breadcrumbs::Component
|
14
14
|
add_helper :card, Satis::Card::Component
|
15
|
+
add_helper :call_to_action, Satis::CallToAction::Component
|
15
16
|
add_helper :editor, Satis::Editor::Component
|
16
17
|
add_helper :flash_messages, Satis::FlashMessages::Component
|
17
18
|
add_helper :info, Satis::Info::Component
|
@@ -35,19 +36,19 @@ module Satis
|
|
35
36
|
@browser ||= Browser.new(action_view.request.user_agent)
|
36
37
|
end
|
37
38
|
|
38
|
-
def form_for(name, *args, &
|
39
|
-
options = args.extract_options!.deep_merge!(html: {
|
39
|
+
def form_for(name, *args, &)
|
40
|
+
options = args.extract_options!.deep_merge!(html: {data: {}})
|
40
41
|
form_options_defaults!(options)
|
41
42
|
update_form_data_options!(options[:html][:data], options)
|
42
43
|
args << options.merge(builder: Satis::Forms::Builder)
|
43
|
-
action_view.form_for(name, *args, &
|
44
|
+
action_view.form_for(name, *args, &)
|
44
45
|
end
|
45
46
|
|
46
|
-
def form_with(model: nil, scope: nil, url: nil, format: nil, **options, &
|
47
|
+
def form_with(model: nil, scope: nil, url: nil, format: nil, **options, &)
|
47
48
|
options = options.reverse_merge(builder: Satis::Forms::Builder, class: "").deep_merge!(data: {})
|
48
49
|
form_options_defaults!(options)
|
49
50
|
update_form_data_options!(options[:data], options)
|
50
|
-
action_view.form_with(model: model, scope: scope, url: url, format: format, **options, &
|
51
|
+
action_view.form_with(model: model, scope: scope, url: url, format: format, **options, &)
|
51
52
|
end
|
52
53
|
|
53
54
|
def form_options_defaults!(options)
|
@@ -71,11 +72,11 @@ module Satis
|
|
71
72
|
original_args = args.dup
|
72
73
|
options = args.extract_options!
|
73
74
|
instance = if options.key? :variant
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
75
|
+
variant_component = component.to_s.sub(/::Component$/, "::#{options[:variant].to_s.camelize}::Component").safe_constantize
|
76
|
+
(variant_component || component).new(*original_args, **kwargs)
|
77
|
+
else
|
78
|
+
component.new(*original_args, **kwargs)
|
79
|
+
end
|
79
80
|
instance.original_view_context = action_view
|
80
81
|
action_view.render(instance, &block)
|
81
82
|
end
|
data/lib/satis/version.rb
CHANGED
data/lib/satis.rb
CHANGED
@@ -1,15 +1,16 @@
|
|
1
|
-
require
|
2
|
-
require
|
3
|
-
require
|
4
|
-
require
|
1
|
+
require "satis/version"
|
2
|
+
require "satis/engine"
|
3
|
+
require "satis/configuration"
|
4
|
+
require "satis/active_record_helpers"
|
5
5
|
|
6
6
|
Browser::Base.include(Browser::Aliases)
|
7
7
|
|
8
8
|
module Satis
|
9
9
|
extend Configurable
|
10
10
|
|
11
|
-
|
11
|
+
Deprecation = ActiveSupport::Deprecation.new("2.2", "Satis")
|
12
12
|
|
13
|
+
class << self
|
13
14
|
def confirm_before_leave?
|
14
15
|
return false if config.nil?
|
15
16
|
|
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: 2.1.
|
4
|
+
version: 2.1.41
|
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: 2024-
|
11
|
+
date: 2024-11-14 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: browser
|
@@ -759,6 +759,9 @@ files:
|
|
759
759
|
- app/components/satis/breadcrumbs/crumb.slim
|
760
760
|
- app/components/satis/calendar_month/component.html.slim
|
761
761
|
- app/components/satis/calendar_month/component.rb
|
762
|
+
- app/components/satis/call_to_action/component.css
|
763
|
+
- app/components/satis/call_to_action/component.html.slim
|
764
|
+
- app/components/satis/call_to_action/component.rb
|
762
765
|
- app/components/satis/card/component.css
|
763
766
|
- app/components/satis/card/component.html.slim
|
764
767
|
- app/components/satis/card/component.rb
|
@@ -804,6 +807,9 @@ files:
|
|
804
807
|
- app/components/satis/input_array/component.html.slim
|
805
808
|
- app/components/satis/input_array/component.rb
|
806
809
|
- app/components/satis/input_array/component_controller.js
|
810
|
+
- app/components/satis/link_button/component.css
|
811
|
+
- app/components/satis/link_button/component.html.slim
|
812
|
+
- app/components/satis/link_button/component.rb
|
807
813
|
- app/components/satis/map/component.css
|
808
814
|
- app/components/satis/map/component.html.slim
|
809
815
|
- app/components/satis/map/component.rb
|