web47core 0.1.10 → 0.1.11

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 3b5aaf907f5f8e778ff9b3fac4d6d38db6f3c3314da02783a90d106ce06153e5
4
- data.tar.gz: 8dde405df315b3e1391c5e0f18fa8c495dd4f52ab0e7aaf36f4ebd538420125e
3
+ metadata.gz: eb0a71b40f9e5d0067b00d477ad3ea6b666c7972ea7d8894f0535e74e7ccd846
4
+ data.tar.gz: 7585bf07cbb2ae2f6ada91905afebb19a11ca81ac78de3e1d6046c411d4db892
5
5
  SHA512:
6
- metadata.gz: 881e3398e59b47a65f8fa840fe0e73fe98447cd67b58ff0e4a1cd38ac0205a19a3d676c1dc5c729d10f4c0e8c7406a7c743d98e0acc147119420c210ea271c25
7
- data.tar.gz: 75d4cb3c6120870f0eb97dd2599e4de9ae79e671557121570777a3ac263d17378de79f8fc7ed870e750b5d901288909134d5a282734afd33ccd15e9e314ec1f0
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
@@ -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
@@ -1,4 +1,5 @@
1
1
  # web47core/config/routes.rb
2
2
  Rails.application.routes.draw do
3
3
  get 'status' => 'status#index'
4
+ get '/notifications/:id', to: 'notifications#show'
4
5
  end
@@ -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)
@@ -6,7 +6,9 @@
6
6
  module Web47core
7
7
  class Config
8
8
  include Singleton
9
- attr_accessor :email_able_models, :switchboard_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 = []
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Web47core
4
- VERSION = '0.1.10'.freeze
4
+ VERSION = '0.1.11'
5
5
  end
data/lib/web47core.rb CHANGED
@@ -38,5 +38,7 @@ require 'app/jobs/cron/trim_failed_delayed_jobs'
38
38
  # Controllers
39
39
  #
40
40
  require 'web47core/engine'
41
+ require 'app/controllers/concerns/core_system_configuration_controller'
42
+ require 'app/controllers/concerns/restful_controller'
41
43
 
42
44
 
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.10
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-28 00:00:00.000000000 Z
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