web47core 0.1.10 → 0.1.11
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/assets/images/1x1.png +0 -0
- data/app/controllers/exceptions_controller.rb +18 -0
- data/app/controllers/notifications_controller.rb +17 -0
- data/config/locales/en.yml +23 -1
- data/config/routes.rb +1 -0
- data/lib/app/controllers/concerns/core_system_configuration_controller.rb +46 -0
- data/lib/app/controllers/concerns/restful_controller.rb +34 -0
- data/lib/app/helpers/core_form_helper.rb +266 -0
- data/lib/app/helpers/core_helper.rb +52 -0
- data/lib/app/helpers/core_link_helper.rb +273 -0
- data/lib/app/views/system_configurations/edit.html.haml +18 -0
- data/lib/app/views/system_configurations/show.html.haml +15 -0
- data/lib/web47core/config.rb +3 -1
- data/lib/web47core/version.rb +1 -1
- data/lib/web47core.rb +2 -0
- metadata +12 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: eb0a71b40f9e5d0067b00d477ad3ea6b666c7972ea7d8894f0535e74e7ccd846
|
4
|
+
data.tar.gz: 7585bf07cbb2ae2f6ada91905afebb19a11ca81ac78de3e1d6046c411d4db892
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 51df548129aab21318b9d01dc674cd8babdfdf990223821c35ba94c61ded799b27eb205cae2d634c9f2fba6c79f4cbc28f6c0ae81ab0b443a876f5ca2e4a89d9
|
7
|
+
data.tar.gz: 92f1f7602a1b12d2a6f204455c5e419a53d01016639052d5944010bdbbbd692eb7f127ebc7e53f008d8e63b6fac41ac2d789cf15aec6847606e0cf1121867526
|
Binary file
|
@@ -0,0 +1,18 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
#
|
4
|
+
# Capture the exception and give a nice screen to the user instead of a stack track looking one.
|
5
|
+
#
|
6
|
+
class ExceptionsController < ActionController::Base
|
7
|
+
include App47Logger
|
8
|
+
layout 'application'
|
9
|
+
respond_to :html
|
10
|
+
|
11
|
+
#
|
12
|
+
# Show
|
13
|
+
#
|
14
|
+
def show
|
15
|
+
log_controller_error request.env['action_dispatch.exception']
|
16
|
+
@xhr = request.headers['HTTP_X_REQUESTED_WITH'].present?
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
#
|
4
|
+
# Record the user opening the email
|
5
|
+
#
|
6
|
+
class NotificationsController < ApplicationController
|
7
|
+
#
|
8
|
+
# Notification was viewed
|
9
|
+
#
|
10
|
+
def show
|
11
|
+
Notification.find(params[:id]).viewed
|
12
|
+
rescue StandardError => error
|
13
|
+
log_controller_error error
|
14
|
+
ensure
|
15
|
+
redirect_to ActionController::Base.helpers.asset_path('1x1.png')
|
16
|
+
end
|
17
|
+
end
|
data/config/locales/en.yml
CHANGED
@@ -1,4 +1,6 @@
|
|
1
1
|
en:
|
2
|
+
update: Update
|
3
|
+
cancel: Cancel
|
2
4
|
time:
|
3
5
|
formats:
|
4
6
|
long: '%Y-%m-%d %H:%M:%ss (%Z)'
|
@@ -8,4 +10,24 @@ en:
|
|
8
10
|
formats:
|
9
11
|
long: '%B %d, %Y'
|
10
12
|
medium: '%b %d, %Y'
|
11
|
-
short: '%m/%d/%Y'
|
13
|
+
short: '%m/%d/%Y'
|
14
|
+
ui_form:
|
15
|
+
system_configuration:
|
16
|
+
placeholders:
|
17
|
+
switchboard_base_url: https://switchboard.app47.com
|
18
|
+
switchboard_stack_id: ab1a34afa231
|
19
|
+
hints:
|
20
|
+
switchboard_base_url: The base URL for the switchboard application
|
21
|
+
switchboard_stack_id: Stack ID to pull configuraiton from
|
22
|
+
switchboard_stack_api_token: API token to use for the stack ID
|
23
|
+
labels:
|
24
|
+
switchboard_base_url: Base URL
|
25
|
+
switchboard_stack_id: Stack ID
|
26
|
+
switchboard_stack_api_token: API Token
|
27
|
+
system_configurations:
|
28
|
+
show:
|
29
|
+
title: "%{name} System Configuration"
|
30
|
+
field_header: Field
|
31
|
+
value_header: Value
|
32
|
+
edit:
|
33
|
+
title: Edit %{name} System Configuration
|
data/config/routes.rb
CHANGED
@@ -0,0 +1,46 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
#
|
4
|
+
# Manage the system configuration page
|
5
|
+
#
|
6
|
+
module CoreSystemConfigurationsController
|
7
|
+
authorize_resource :system_configuration
|
8
|
+
|
9
|
+
#
|
10
|
+
# Edit the system configuration
|
11
|
+
#
|
12
|
+
def edit
|
13
|
+
load_configuration
|
14
|
+
end
|
15
|
+
|
16
|
+
#
|
17
|
+
# Update and log the system configuration changes
|
18
|
+
#
|
19
|
+
def update
|
20
|
+
# @system_configuration.update_attributes_and_log! @current_admin_user, system_configuration_params
|
21
|
+
SystemConfiguration.configuration.update! system_configuration_params
|
22
|
+
flash[:info] = 'System Configuration Updated, sync job running in the background'
|
23
|
+
Cron::SwitchboardSyncConfiguration.perform_later
|
24
|
+
redirect_to system_configuration_path
|
25
|
+
rescue StandardError => error
|
26
|
+
log_controller_error error
|
27
|
+
load_configuration
|
28
|
+
render :edit
|
29
|
+
end
|
30
|
+
|
31
|
+
private
|
32
|
+
|
33
|
+
#
|
34
|
+
# Get the system configuration properties from the request
|
35
|
+
#
|
36
|
+
def system_configuration_params
|
37
|
+
params.require(:system_configuration).permit(SystemConfiguration.allowed_param_names)
|
38
|
+
end
|
39
|
+
|
40
|
+
#
|
41
|
+
# Load the current system configuration
|
42
|
+
#
|
43
|
+
def load_configuration
|
44
|
+
@system_configuration = SystemConfiguration.configuration
|
45
|
+
end
|
46
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
#
|
4
|
+
# Reusable API methods
|
5
|
+
#
|
6
|
+
module RestfulController
|
7
|
+
#
|
8
|
+
# Render a JSON response with the results and status passed in. The payload will include
|
9
|
+
# an MD5 hash along with the response for validation.
|
10
|
+
#
|
11
|
+
def render_json_response(success = true, results = {}, status_code = :ok)
|
12
|
+
results[:success] = success
|
13
|
+
render status: status_code,
|
14
|
+
json: { results: results,
|
15
|
+
md5: hash(unescape_unicode(results.to_json)) }.to_json,
|
16
|
+
layout: false
|
17
|
+
end
|
18
|
+
|
19
|
+
#
|
20
|
+
# Convert UTF-8 unicode/escaped back to actual double byte character
|
21
|
+
#
|
22
|
+
def unescape_unicode(str)
|
23
|
+
str.gsub(/\\u([\da-fA-F]{4})/) do |_m|
|
24
|
+
[Regexp.last_match[1]].pack('H*').unpack('n*').pack('U*')
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
#
|
29
|
+
# Create a hash of the string contents
|
30
|
+
#
|
31
|
+
def hash(str)
|
32
|
+
Digest::MD5.hexdigest(str)
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,266 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
#
|
4
|
+
# helpers for creating forms
|
5
|
+
#
|
6
|
+
module CoreFormHelper
|
7
|
+
def materialize_form_for(options = {}, &block)
|
8
|
+
options[:form_authenticity_token] = form_authenticity_token
|
9
|
+
form = Materialize::Form.new(options)
|
10
|
+
form.render_form(&block)
|
11
|
+
end
|
12
|
+
|
13
|
+
#
|
14
|
+
# Text field
|
15
|
+
#
|
16
|
+
def form_text_field(model, field, options = {})
|
17
|
+
classes = options[:classes] || %w[s12 m6 l4 xl3]
|
18
|
+
value = model.send(field)
|
19
|
+
options[:type] = :text
|
20
|
+
options[:value] = value
|
21
|
+
tag_options = text_field_options(model, field, options)
|
22
|
+
content_tag(:div, class: (%w[input-field col] + classes).join(' ')) do
|
23
|
+
concat(tag(:input, tag_options))
|
24
|
+
concat(form_label_tag(model, field, value, options))
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def form_date_field(model, field, options = {})
|
29
|
+
classes = options[:classes] || %w[s12 m6 l4 xl3]
|
30
|
+
value = model.send(field)
|
31
|
+
options[:value] = value.strftime('%d %B, %Y') if value.present?
|
32
|
+
options[:type] = :text
|
33
|
+
tag_options = text_field_options(model, field, options)
|
34
|
+
tag_options[:class] = options[:date_picker_type] || 'simple-date-picker'
|
35
|
+
content_tag(:div, class: (%w[input-field col] + classes).join(' ')) do
|
36
|
+
concat(tag(:input, tag_options))
|
37
|
+
concat(form_label_tag(model, field, value, options))
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
#
|
42
|
+
# Password field
|
43
|
+
#
|
44
|
+
def form_password(model, field, options = {})
|
45
|
+
classes = options[:classes] || %w[s12 m6 l4 xl3]
|
46
|
+
value = model.send(field)
|
47
|
+
options[:type] = :password
|
48
|
+
options[:place_holder] = mask_value(value)
|
49
|
+
tag_options = text_field_options(model, field, options)
|
50
|
+
content_tag(:div, class: (%w[input-field col] + classes).join(' ')) do
|
51
|
+
concat(tag(:input, tag_options))
|
52
|
+
concat(form_label_tag(model, field, value, options))
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
#
|
57
|
+
# Select field
|
58
|
+
#
|
59
|
+
def form_select(model, field, options = {})
|
60
|
+
value = model.send(field)
|
61
|
+
raise 'Prompt needed' if value.blank? && options[:prompt].blank? && !options[:no_label]
|
62
|
+
|
63
|
+
hint_key = "ui_form.#{model.class.to_s.underscore}.hints.#{field}"
|
64
|
+
if I18n.exists?(hint_key)
|
65
|
+
base_classes = %w[input-field col tooltipped]
|
66
|
+
data = { tooltip: I18n.t(hint_key), position: :top }
|
67
|
+
else
|
68
|
+
base_classes = %w[input-field col]
|
69
|
+
data = {}
|
70
|
+
end
|
71
|
+
classes = (base_classes + (options[:classes] || %w[s12 m6 l4])).join(' ')
|
72
|
+
content_tag(:div, class: classes, data: data) do
|
73
|
+
concat(form_select_tag(model, field, options))
|
74
|
+
concat(form_label_tag(model, field, value, options))
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
#
|
79
|
+
# Create the select tag
|
80
|
+
#
|
81
|
+
def form_select_tag(model, field, options = {})
|
82
|
+
form_name = form_field_name(model, field, options)
|
83
|
+
content_tag(:select, id: form_name, name: form_name, class: options[:input_classes]) do
|
84
|
+
form_select_option_key_values(model.send(field), options).each do |value|
|
85
|
+
concat(content_tag(:option, value: value[:key], selected: value[:selected]) do
|
86
|
+
concat(value[:value])
|
87
|
+
end)
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
#
|
93
|
+
# Return an array of hashes for the selection to work easily
|
94
|
+
def form_select_option_key_values(value, options)
|
95
|
+
select_options = []
|
96
|
+
select_options << { key: '', value: options[:prompt], selected: false } if options[:prompt].present?
|
97
|
+
options[:options].each do |option_value|
|
98
|
+
option_value[:display_name] = option_value.display_name if option_value.respond_to?(:display_name)
|
99
|
+
select_options << case option_value
|
100
|
+
when String, Integer
|
101
|
+
{ key: option_value,
|
102
|
+
value: option_value,
|
103
|
+
selected: value.eql?(option_value) }
|
104
|
+
when Array
|
105
|
+
{ key: option_value.first,
|
106
|
+
value: option_value.last,
|
107
|
+
selected: value.to_s.eql?(option_value.first.to_s) }
|
108
|
+
when Hash
|
109
|
+
{ key: option_value[:key],
|
110
|
+
value: option_value[:value],
|
111
|
+
selected: value.eql?(option_value[:key]) }
|
112
|
+
else
|
113
|
+
{ key: option_value[:_id],
|
114
|
+
value: option_value[:display_name] || option_value[:name],
|
115
|
+
selected: value.eql?(option_value) }
|
116
|
+
end
|
117
|
+
end
|
118
|
+
select_options
|
119
|
+
end
|
120
|
+
|
121
|
+
#
|
122
|
+
# Checkbox field
|
123
|
+
#
|
124
|
+
def form_checkbox(model, field, classes = %w[s12 m6 l4 xl3], options = {})
|
125
|
+
form_name = form_field_name model, field
|
126
|
+
value = model.send(field)
|
127
|
+
options[:disabled] ||= false
|
128
|
+
properties = {
|
129
|
+
class: 'validate',
|
130
|
+
id: form_name,
|
131
|
+
name: form_name,
|
132
|
+
type: :checkbox,
|
133
|
+
disabled: options[:disabled]
|
134
|
+
}
|
135
|
+
properties[:checked] = true if model.send(field)
|
136
|
+
checkbox_tag = tag(:input, properties)
|
137
|
+
content_tag(:div, class: (%w[input-field col] + classes).join(' ')) do
|
138
|
+
concat(content_tag(:label) do
|
139
|
+
concat(checkbox_tag)
|
140
|
+
concat(form_checkbox_label_tag(model, field, value, input_classes: classes))
|
141
|
+
end)
|
142
|
+
end
|
143
|
+
end
|
144
|
+
|
145
|
+
#
|
146
|
+
# get the label for checkbox
|
147
|
+
#
|
148
|
+
def form_checkbox_label_tag(model, field, value, options = {})
|
149
|
+
# dont do a label if we are in default browser mode
|
150
|
+
return if options[:input_classes].present? && options[:input_classes].include?('browser-default')
|
151
|
+
|
152
|
+
# or if we have a prompt with now value
|
153
|
+
place_holder = field_place_holder(model, field)
|
154
|
+
return if place_holder.blank? && value.blank? && options[:prompt].present?
|
155
|
+
|
156
|
+
error = model.errors[field]
|
157
|
+
key = "ui_form.#{model.class.to_s.underscore}.labels.#{field}"
|
158
|
+
classes = value.nil? && place_holder.blank? ? '' : 'active'
|
159
|
+
classes += error.present? ? ' invalid red-text' : ' valid'
|
160
|
+
options[:class] = classes
|
161
|
+
options['data-error'] = error.join(', ') if error.present?
|
162
|
+
content_tag(:span, options) do
|
163
|
+
concat(I18n.exists?(key) ? I18n.t(key) : field.to_s.humanize)
|
164
|
+
end
|
165
|
+
end
|
166
|
+
|
167
|
+
#
|
168
|
+
# get the label for field
|
169
|
+
#
|
170
|
+
def form_label_tag(model, field, value, options = {})
|
171
|
+
# dont do a label if we are in default browser mode
|
172
|
+
return if options[:no_label]
|
173
|
+
return if options[:input_classes].present? && options[:input_classes].include?('browser-default')
|
174
|
+
|
175
|
+
# or if we have a prompt with now value
|
176
|
+
place_holder = options[:place_holder] || field_place_holder(model, field)
|
177
|
+
return if place_holder.blank? && value.blank? && options[:prompt].present?
|
178
|
+
|
179
|
+
error = model.errors[field]
|
180
|
+
key = "ui_form.#{model.class.to_s.underscore}.labels.#{field}"
|
181
|
+
classes = value.nil? && place_holder.blank? ? '' : 'active'
|
182
|
+
classes += error.present? ? ' invalid red-text' : ' valid'
|
183
|
+
options[:class] = classes
|
184
|
+
options[:for] = form_field_name(model, field, options)
|
185
|
+
options['data-error'] = error.join(', ') if error.present?
|
186
|
+
content_tag(:label, options) do
|
187
|
+
concat(I18n.exists?(key) ? I18n.t(key) : field.to_s.humanize)
|
188
|
+
concat(' ' + error.join(', ')) if error.present?
|
189
|
+
end
|
190
|
+
end
|
191
|
+
|
192
|
+
#
|
193
|
+
# Get the hint for the field and add it
|
194
|
+
#
|
195
|
+
def form_hint_tag(model, field)
|
196
|
+
key = "ui_form.#{model.class.to_s.underscore}.hints.#{field}"
|
197
|
+
return nil unless I18n.exists?(key)
|
198
|
+
|
199
|
+
content_tag(:p, class: 'form-hint', for: form_field_name(model, field)) do
|
200
|
+
concat(I18n.t(key))
|
201
|
+
end
|
202
|
+
end
|
203
|
+
|
204
|
+
#
|
205
|
+
# Add the placeholder option if found in the translations
|
206
|
+
#
|
207
|
+
def text_field_options(model, field, options)
|
208
|
+
form_name = form_field_name model, field, options
|
209
|
+
hint_key = "ui_form.#{model.class.to_s.underscore}.hints.#{field}"
|
210
|
+
if I18n.exists?(hint_key)
|
211
|
+
classes = %w[validate tooltipped]
|
212
|
+
options[:data] = { tooltip: I18n.t(hint_key), position: :top }
|
213
|
+
else
|
214
|
+
classes = %w[validate]
|
215
|
+
end
|
216
|
+
classes += options[:input_classes] if options[:input_classes].present?
|
217
|
+
options[:name] = form_name
|
218
|
+
options[:id] = form_name
|
219
|
+
place_holder = options[:place_holder] || field_place_holder(model, field)
|
220
|
+
if place_holder.present?
|
221
|
+
classes << 'active'
|
222
|
+
options[:placeholder] = place_holder
|
223
|
+
end
|
224
|
+
classes << 'active' if options[:value].present?
|
225
|
+
options[:class] = classes.uniq
|
226
|
+
options
|
227
|
+
end
|
228
|
+
|
229
|
+
def field_place_holder(model, field)
|
230
|
+
place_holder_key = "ui_form.#{model.class.to_s.underscore}.placeholders.#{field}"
|
231
|
+
I18n.exists?(place_holder_key) ? I18n.t(place_holder_key) : nil
|
232
|
+
end
|
233
|
+
|
234
|
+
#
|
235
|
+
# Return a consistent form field name
|
236
|
+
#
|
237
|
+
def form_field_name(model, field, options = {})
|
238
|
+
return options[:form_name] if options[:form_name].present?
|
239
|
+
|
240
|
+
# TODO: Need to handle the other side of the 1:M use case where
|
241
|
+
# the field name needs to end in _ids, not _id.
|
242
|
+
field = "#{field}_id" if model.class.reflect_on_association(field).present?
|
243
|
+
if options[:index].present?
|
244
|
+
if options[:array_name].present?
|
245
|
+
if options[:base_name].present?
|
246
|
+
"#{options[:base_name]}[#{options[:array_name]}[#{options[:index]}][#{field}]]"
|
247
|
+
else
|
248
|
+
"#{options[:array_name]}[#{options[:index]}][#{field}]"
|
249
|
+
end
|
250
|
+
else
|
251
|
+
"#{model.class.to_s.underscore}[#{options[:index]}][#{field}]"
|
252
|
+
end
|
253
|
+
else
|
254
|
+
"#{model.class.to_s.underscore}[#{field}]"
|
255
|
+
end
|
256
|
+
end
|
257
|
+
|
258
|
+
def form_radio_button(model, field, options = {})
|
259
|
+
value = model.send(field)
|
260
|
+
classes = (%w[input-field col] + options[:classes] || []).join(' ')
|
261
|
+
content_tag(:div, class: classes) do
|
262
|
+
concat(form_select_tag(model, field, options))
|
263
|
+
concat(form_label_tag(model, field, value))
|
264
|
+
end
|
265
|
+
end
|
266
|
+
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
#
|
4
|
+
# helpers for core views
|
5
|
+
#
|
6
|
+
module CoreHelper
|
7
|
+
#
|
8
|
+
# Set the title for the page
|
9
|
+
#
|
10
|
+
def title(page_title)
|
11
|
+
content_for(:title) { page_title }
|
12
|
+
end
|
13
|
+
|
14
|
+
def system_configuration_path
|
15
|
+
'/' + [Web47core.config.system_configuration_namespace, 'system_configuration'].join('/')
|
16
|
+
end
|
17
|
+
|
18
|
+
def edit_system_configuration_path
|
19
|
+
[system_configuration_path, 'edit'].join('/')
|
20
|
+
end
|
21
|
+
|
22
|
+
#
|
23
|
+
# Pull the value from system configuration and mask the ones that match the given strings
|
24
|
+
#
|
25
|
+
def mask_system_configuration(field)
|
26
|
+
should_mask = false
|
27
|
+
%w[password token secret access_key api_key].each do |mask|
|
28
|
+
should_mask |= field.include?(mask)
|
29
|
+
end
|
30
|
+
value = SystemConfiguration.send(field)
|
31
|
+
should_mask ? mask_value(value, default: 'No Set') : value
|
32
|
+
end
|
33
|
+
|
34
|
+
#
|
35
|
+
# Mask a value, i.e. password field
|
36
|
+
# 1. If blank or nil, return the default
|
37
|
+
# 2. Length of 1-4 only show the first character
|
38
|
+
# 3. Length 5-10 only show the first and last character
|
39
|
+
# 4. Otherwise show the first and last three characters
|
40
|
+
def mask_value(value, default: '************')
|
41
|
+
return default if value.blank?
|
42
|
+
|
43
|
+
case value.length
|
44
|
+
when 1..4
|
45
|
+
"#{value.first}***********"
|
46
|
+
when 5..10
|
47
|
+
"#{value.first}**********#{value.last}"
|
48
|
+
else
|
49
|
+
"#{value[0..2]}**********#{value[-3..-1]}"
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
@@ -0,0 +1,273 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
#
|
4
|
+
# common link generation helpers
|
5
|
+
#
|
6
|
+
module CoreLinkHelper
|
7
|
+
#
|
8
|
+
# Create a copy tag for data to be copied to the clipboard
|
9
|
+
#
|
10
|
+
def copy_tag(copy_text, options = {})
|
11
|
+
content_tag(:p, class: 'stack-tight') do
|
12
|
+
concat(copy_text)
|
13
|
+
concat(copy_text_tag(copy_text, options))
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
#
|
18
|
+
# Create a text element that is easy to copy
|
19
|
+
#
|
20
|
+
def copy_text_tag(copy_text, options = {})
|
21
|
+
options[:icon_name] ||= 'content_copy'
|
22
|
+
content_tag(:a, class: 'copy', href: '#', data: { 'clipboard-text' => copy_text }, onclick: 'return false;') do
|
23
|
+
concat(content_tag(:i, class: 'material-icons') do
|
24
|
+
options[:icon_name]
|
25
|
+
end)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
#
|
30
|
+
# Add the table action button and setup the drop down
|
31
|
+
#
|
32
|
+
def table_action_button(action_id, icon_name = 'more_horiz')
|
33
|
+
datum = { activates: action_id,
|
34
|
+
constrainWidth: false,
|
35
|
+
gutter: 28,
|
36
|
+
alignment: 'right' }
|
37
|
+
content_tag(:a, class: 'dropdown-button', data: datum) do
|
38
|
+
concat(materialize_icon(icon_name))
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
#
|
43
|
+
# Add a material icon by name
|
44
|
+
#
|
45
|
+
def materialize_icon(name, options = {})
|
46
|
+
classes = %w[material-icons]
|
47
|
+
classes += options[:classes] if options[:classes].present?
|
48
|
+
content_tag(:i, class: classes.join(' '), title: options[:title]) { name }
|
49
|
+
end
|
50
|
+
|
51
|
+
#
|
52
|
+
# Generic link tag
|
53
|
+
#
|
54
|
+
def link_tag(title, path, options = {})
|
55
|
+
content_tag(:a, href: path) do
|
56
|
+
concat(content_tag(:i, class: 'material-icons left') { options[:icon_name] }) if options[:icon_name].present?
|
57
|
+
concat(title)
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
#
|
62
|
+
# Edit a thingy in a pull down list
|
63
|
+
#
|
64
|
+
def edit_list_tag(obj, path, options = {})
|
65
|
+
return unless can? :edit, obj
|
66
|
+
|
67
|
+
options[:label] ||= I18n.t('ui_form.actions.edit')
|
68
|
+
content_tag(:li) do
|
69
|
+
edit_link_tag(obj, path, options)
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
#
|
74
|
+
# Edit an thingy
|
75
|
+
#
|
76
|
+
def edit_link_tag(obj, path, options = {})
|
77
|
+
return unless can? :edit, obj
|
78
|
+
|
79
|
+
content_tag(:a, href: path) do
|
80
|
+
concat(content_tag(:i, class: 'material-icons') do
|
81
|
+
'edit'
|
82
|
+
end)
|
83
|
+
concat(options[:label]) if options[:label].present?
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
def edit_modal_tag(obj, path, _options = {})
|
88
|
+
return unless can? :edit, obj
|
89
|
+
|
90
|
+
content_tag(:a, href: path, class: 'modal-action') do
|
91
|
+
concat(I18n.t('ui_form.actions.edit'))
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
#
|
96
|
+
# Restart a thingy
|
97
|
+
#
|
98
|
+
def replay_link_tag(obj, path, options = {})
|
99
|
+
return unless can? :edit, obj
|
100
|
+
|
101
|
+
icon_name = options[:icon_name] || 'replay'
|
102
|
+
content_tag(:a, href: path) do
|
103
|
+
concat(content_tag(:i, class: 'material-icons') do
|
104
|
+
icon_name
|
105
|
+
end)
|
106
|
+
concat(options[:label]) if options[:label].present?
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
#
|
111
|
+
# Restart a thingy
|
112
|
+
#
|
113
|
+
def replay_list_tag(obj, path, options = {})
|
114
|
+
return unless can? :edit, obj
|
115
|
+
|
116
|
+
options[:label] ||= I18n.t('ui_form.actions.replay')
|
117
|
+
content_tag(:li) do
|
118
|
+
replay_link_tag(obj, path, options)
|
119
|
+
end
|
120
|
+
end
|
121
|
+
|
122
|
+
#
|
123
|
+
# Details of a thingy in a pull down list
|
124
|
+
#
|
125
|
+
def info_list_tag(obj, path, options = {})
|
126
|
+
options[:label] ||= I18n.t('ui_form.actions.info')
|
127
|
+
content_tag(:li) do
|
128
|
+
info_link_tag(obj, path, options)
|
129
|
+
end
|
130
|
+
end
|
131
|
+
|
132
|
+
#
|
133
|
+
# Details of a thingy
|
134
|
+
#
|
135
|
+
def info_link_tag(obj, path, options = {})
|
136
|
+
return unless can? :read, obj
|
137
|
+
|
138
|
+
content_tag(:a, href: path) do
|
139
|
+
concat(content_tag(:i, class: 'material-icons') do
|
140
|
+
'info'
|
141
|
+
end)
|
142
|
+
concat(options[:label]) if options[:label].present?
|
143
|
+
end
|
144
|
+
end
|
145
|
+
|
146
|
+
#
|
147
|
+
# Show a list of things in a pull down list if the condition is true
|
148
|
+
#
|
149
|
+
def action_list_tag(condition, path, options = {})
|
150
|
+
return unless condition
|
151
|
+
raise('Label Required') if options[:label].blank?
|
152
|
+
|
153
|
+
content_tag(:li) do
|
154
|
+
action_link_tag(condition, path, options)
|
155
|
+
end
|
156
|
+
end
|
157
|
+
|
158
|
+
#
|
159
|
+
# Show a list of things if the condition is true.
|
160
|
+
#
|
161
|
+
def action_link_tag(condition, path, options = {})
|
162
|
+
return unless condition
|
163
|
+
|
164
|
+
content_tag(:a, href: path) do
|
165
|
+
concat(content_tag(:i, class: 'material-icons') do
|
166
|
+
options[:icon_name] || 'info'
|
167
|
+
end)
|
168
|
+
concat(options[:label]) if options[:label].present?
|
169
|
+
end
|
170
|
+
end
|
171
|
+
|
172
|
+
#
|
173
|
+
# Delete a thingy in a pull down list
|
174
|
+
#
|
175
|
+
def delete_list_tag(obj, path, options = {})
|
176
|
+
return unless can? :delete, obj
|
177
|
+
|
178
|
+
options[:label] ||= I18n.t('ui_form.actions.delete')
|
179
|
+
content_tag(:li) do
|
180
|
+
delete_link_tag(obj, path, options)
|
181
|
+
end
|
182
|
+
end
|
183
|
+
|
184
|
+
#
|
185
|
+
# Delete an thingy
|
186
|
+
#
|
187
|
+
def delete_link_tag(obj, path, options = {})
|
188
|
+
return unless can? :delete, obj
|
189
|
+
|
190
|
+
confirmation = options[:confirmation] || t('links.deletion_confirmation', name: obj.class.to_s.underscore.humanize)
|
191
|
+
content_tag(:a, href: path, data: { method: :delete, confirm: confirmation }) do
|
192
|
+
concat(content_tag(:i, class: 'material-icons') do
|
193
|
+
options[:icon_name] || 'delete'
|
194
|
+
end)
|
195
|
+
concat(options[:label]) if options[:label].present?
|
196
|
+
end
|
197
|
+
end
|
198
|
+
|
199
|
+
#
|
200
|
+
# Send notification in a pull down list
|
201
|
+
#
|
202
|
+
def notification_list_tag(obj, path, options = {})
|
203
|
+
return unless can? :manage, obj
|
204
|
+
|
205
|
+
options[:label] ||= I18n.t('customer_account_users.index.reset_password')
|
206
|
+
content_tag(:li) do
|
207
|
+
notification_link_tag(obj, path, options)
|
208
|
+
end
|
209
|
+
end
|
210
|
+
|
211
|
+
#
|
212
|
+
# Send notification
|
213
|
+
#
|
214
|
+
def notification_link_tag(obj, path, options = {})
|
215
|
+
return unless can? :manage, obj
|
216
|
+
|
217
|
+
content_tag(:a, href: path) do
|
218
|
+
concat(content_tag(:i, class: 'material-icons') do
|
219
|
+
options[:icon_name] || 'email'
|
220
|
+
end)
|
221
|
+
concat(options[:label]) if options[:label].present?
|
222
|
+
end
|
223
|
+
end
|
224
|
+
|
225
|
+
#
|
226
|
+
# Edit a page
|
227
|
+
#
|
228
|
+
def edit_class_link_tag(klass, path)
|
229
|
+
return unless can?(:edit, klass)
|
230
|
+
|
231
|
+
content_tag(:div, class: 'fixed-action-btn horizontal') do
|
232
|
+
concat(content_tag(:a, href: path, class: 'btn-floating btn-large right', style: 'padding: 0;margin: 0px 15px') do
|
233
|
+
concat(content_tag(:i, class: 'material-icons') { 'edit' })
|
234
|
+
end)
|
235
|
+
end
|
236
|
+
end
|
237
|
+
|
238
|
+
#
|
239
|
+
# Add a thingy
|
240
|
+
#
|
241
|
+
def add_link_tag(klass, path)
|
242
|
+
return unless can?(:manage, klass)
|
243
|
+
|
244
|
+
content_tag(:div, class: 'fixed-action-btn horizontal') do
|
245
|
+
concat(content_tag(:a, href: path, class: 'btn-floating btn-large right', style: 'padding: 0;margin: 0px 15px') do
|
246
|
+
concat(content_tag(:i, class: 'material-icons') { 'add' })
|
247
|
+
end)
|
248
|
+
end
|
249
|
+
end
|
250
|
+
|
251
|
+
#
|
252
|
+
# Form cancel button
|
253
|
+
#
|
254
|
+
def form_cancel_button_tag(path)
|
255
|
+
options = { class: 'btn-large waves-effect waves-light secondary', href: path }
|
256
|
+
content_tag(:a, options) do
|
257
|
+
concat(t('ui_form.actions.cancel'))
|
258
|
+
end
|
259
|
+
end
|
260
|
+
|
261
|
+
#
|
262
|
+
# Form submit button
|
263
|
+
#
|
264
|
+
def form_submit_button_tag(obj)
|
265
|
+
return unless can? :update, obj
|
266
|
+
|
267
|
+
options = { class: 'btn-large waves-effect waves-light', type: :submit }
|
268
|
+
content_tag(:button, options) do
|
269
|
+
concat(t('ui_form.actions.save'))
|
270
|
+
concat(content_tag(:i, class: 'material-icons right') { 'save' })
|
271
|
+
end
|
272
|
+
end
|
273
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
- title t('.title', name: SystemConfiguration.environment.titleize)
|
2
|
+
.container
|
3
|
+
%form{action: system_configuration_path, method: :post}
|
4
|
+
%input{type: :hidden, value: form_authenticity_token, name: 'authenticity_token'}
|
5
|
+
%input{type: :hidden, name: '_method', value: 'put'}
|
6
|
+
.row
|
7
|
+
= form_text_field(@system_configuration, :switchboard_base_url, classes: %w[s12 m4])
|
8
|
+
= form_text_field(@system_configuration, :switchboard_stack_id, classes: %w[s12 m4])
|
9
|
+
= form_password(@system_configuration, :switchboard_stack_api_token, classes: %w[s12 m4])
|
10
|
+
.row
|
11
|
+
.col.s6.center-align
|
12
|
+
%a.btn-large.waves-effect.waves-light{href: system_configuration_path}= t(':cancel')
|
13
|
+
%i.material-icons.right
|
14
|
+
cancel
|
15
|
+
.col.s6.center-align
|
16
|
+
%button.btn-large.waves-effect.waves-light{type: :submit}= t(':update')
|
17
|
+
%i.material-icons.right
|
18
|
+
save
|
@@ -0,0 +1,15 @@
|
|
1
|
+
- title t('.title', name: SystemConfiguration.environment.titleize)
|
2
|
+
= edit_class_link_tag(SystemConfiguration, edit_system_configuration_path)
|
3
|
+
.container
|
4
|
+
.row
|
5
|
+
.s12
|
6
|
+
%table.highlight.striped
|
7
|
+
%thead
|
8
|
+
%tr
|
9
|
+
%th.center-align=t('.field_header')
|
10
|
+
%th.center-align=t('.value_header')
|
11
|
+
%tbody
|
12
|
+
- SystemConfiguration.allowed_param_names.sort.each do |field|
|
13
|
+
%tr
|
14
|
+
%td.right-align=field
|
15
|
+
%td.left-align=mask_system_configuration(field)
|
data/lib/web47core/config.rb
CHANGED
@@ -6,7 +6,9 @@
|
|
6
6
|
module Web47core
|
7
7
|
class Config
|
8
8
|
include Singleton
|
9
|
-
attr_accessor :email_able_models,
|
9
|
+
attr_accessor :email_able_models,
|
10
|
+
:switchboard_able_models,
|
11
|
+
:system_configuration_namespace
|
10
12
|
|
11
13
|
def initialize
|
12
14
|
@email_able_models = []
|
data/lib/web47core/version.rb
CHANGED
data/lib/web47core.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: web47core
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.11
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Chris Schroeder
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2020-03-
|
11
|
+
date: 2020-03-29 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activesupport
|
@@ -541,12 +541,20 @@ extra_rdoc_files: []
|
|
541
541
|
files:
|
542
542
|
- LICENSE
|
543
543
|
- README.md
|
544
|
+
- app/assets/images/1x1.png
|
545
|
+
- app/controllers/exceptions_controller.rb
|
546
|
+
- app/controllers/notifications_controller.rb
|
544
547
|
- app/controllers/status_controller.rb
|
545
548
|
- app/views/status/index.html.haml
|
546
549
|
- bin/cron_server
|
547
550
|
- bin/delayed_job
|
548
551
|
- config/locales/en.yml
|
549
552
|
- config/routes.rb
|
553
|
+
- lib/app/controllers/concerns/core_system_configuration_controller.rb
|
554
|
+
- lib/app/controllers/concerns/restful_controller.rb
|
555
|
+
- lib/app/helpers/core_form_helper.rb
|
556
|
+
- lib/app/helpers/core_helper.rb
|
557
|
+
- lib/app/helpers/core_link_helper.rb
|
550
558
|
- lib/app/jobs/application_job.rb
|
551
559
|
- lib/app/jobs/cron/command.rb
|
552
560
|
- lib/app/jobs/cron/job.rb
|
@@ -578,6 +586,8 @@ files:
|
|
578
586
|
- lib/app/models/sms_notification.rb
|
579
587
|
- lib/app/models/smtp_configuration.rb
|
580
588
|
- lib/app/models/template.rb
|
589
|
+
- lib/app/views/system_configurations/edit.html.haml
|
590
|
+
- lib/app/views/system_configurations/show.html.haml
|
581
591
|
- lib/templates/email/notification_failure.liquid
|
582
592
|
- lib/templates/email/notification_failure.subject.liquid
|
583
593
|
- lib/templates/slack/error_message.liquid
|