diff --git a/.gitignore b/.gitignore index 0c71b2055..e4b14d2f5 100644 --- a/.gitignore +++ b/.gitignore @@ -60,3 +60,6 @@ package-lock.json # cypress test/cypress/videos/* + +/config/master.key +/config/*.enc \ No newline at end of file diff --git a/app/controllers/super_admin/installation_configs_controller.rb b/app/controllers/super_admin/installation_configs_controller.rb new file mode 100644 index 000000000..36a45f707 --- /dev/null +++ b/app/controllers/super_admin/installation_configs_controller.rb @@ -0,0 +1,46 @@ +class SuperAdmin::InstallationConfigsController < SuperAdmin::ApplicationController + # Overwrite any of the RESTful controller actions to implement custom behavior + # For example, you may want to send an email after a foo is updated. + # + # def update + # super + # send_foo_updated_email(requested_resource) + # end + + # Override this method to specify custom lookup behavior. + # This will be used to set the resource for the `show`, `edit`, and `update` + # actions. + # + # def find_resource(param) + # Foo.find_by!(slug: param) + # end + + # The result of this lookup will be available as `requested_resource` + + # Override this if you have certain roles that require a subset + # this will be used to set the records shown on the `index` action. + # + def scoped_resource + resource_class.editable + end + + # Override `resource_params` if you want to transform the submitted + # data before it's persisted. For example, the following would turn all + # empty values into nil values. It uses other APIs such as `resource_class` + # and `dashboard`: + # + # def resource_params + # params.require(resource_class.model_name.param_key). + # permit(dashboard.permitted_attributes). + # transform_values { |value| value == "" ? nil : value } + # end + + def resource_params + params.require(:installation_config) + .permit(:name, :value) + .transform_values { |value| value == '' ? nil : value }.merge(locked: false) + end + + # See https://administrate-prototype.herokuapp.com/customizing_controller_actions + # for more information +end diff --git a/app/dashboards/installation_config_dashboard.rb b/app/dashboards/installation_config_dashboard.rb new file mode 100644 index 000000000..8a60c0dba --- /dev/null +++ b/app/dashboards/installation_config_dashboard.rb @@ -0,0 +1,66 @@ +require 'administrate/base_dashboard' + +class InstallationConfigDashboard < Administrate::BaseDashboard + # ATTRIBUTE_TYPES + # a hash that describes the type of each of the model's fields. + # + # Each different type represents an Administrate::Field object, + # which determines how the attribute is displayed + # on pages throughout the dashboard. + ATTRIBUTE_TYPES = { + id: Field::Number, + name: Field::String, + value: SerializedField, + created_at: Field::DateTime, + updated_at: Field::DateTime + }.freeze + + # COLLECTION_ATTRIBUTES + # an array of attributes that will be displayed on the model's index page. + # + # By default, it's limited to four items to reduce clutter on index pages. + # Feel free to add, remove, or rearrange items. + COLLECTION_ATTRIBUTES = %i[ + id + name + value + created_at + ].freeze + + # SHOW_PAGE_ATTRIBUTES + # an array of attributes that will be displayed on the model's show page. + SHOW_PAGE_ATTRIBUTES = %i[ + id + name + value + created_at + updated_at + ].freeze + + # FORM_ATTRIBUTES + # an array of attributes that will be displayed + # on the model's form (`new` and `edit`) pages. + FORM_ATTRIBUTES = %i[ + name + value + ].freeze + + # COLLECTION_FILTERS + # a hash that defines filters that can be used while searching via the search + # field of the dashboard. + # + # For example to add an option to search for open resources by typing "open:" + # in the search field: + # + # COLLECTION_FILTERS = { + # open: ->(resources) { resources.where(open: true) } + # }.freeze + COLLECTION_FILTERS = {}.freeze + + # Overwrite this method to customize how installation configs are displayed + # across all pages of the admin dashboard. + # + # def display_resource(installation_config) + # "InstallationConfig ##{installation_config.id}" + # end +end diff --git a/app/fields/serialized_field.rb b/app/fields/serialized_field.rb new file mode 100644 index 000000000..5c1069c42 --- /dev/null +++ b/app/fields/serialized_field.rb @@ -0,0 +1,15 @@ +require 'administrate/field/base' + +class SerializedField < Administrate::Field::Base + def to_s + hash? ? data.as_json : data.to_s + end + + def hash? + data.is_a? Hash + end + + def array? + data.is_a? Array + end +end diff --git a/app/models/installation_config.rb b/app/models/installation_config.rb index 589ab3a36..ce65eb678 100644 --- a/app/models/installation_config.rb +++ b/app/models/installation_config.rb @@ -3,6 +3,7 @@ # Table name: installation_configs # # id :bigint not null, primary key +# locked :boolean default(TRUE), not null # name :string not null # serialized_value :jsonb not null # created_at :datetime not null @@ -10,14 +11,17 @@ # # Indexes # +# index_installation_configs_on_name (name) UNIQUE # index_installation_configs_on_name_and_created_at (name,created_at) UNIQUE # class InstallationConfig < ApplicationRecord serialize :serialized_value, HashWithIndifferentAccess + before_validation :set_lock validates :name, presence: true default_scope { order(created_at: :desc) } + scope :editable, -> { where(locked: false) } def value serialized_value[:value] @@ -28,4 +32,10 @@ class InstallationConfig < ApplicationRecord value: value_to_assigned }.with_indifferent_access end + + private + + def set_lock + self.locked = true if locked.nil? + end end diff --git a/app/views/fields/serialized_field/_form.html.erb b/app/views/fields/serialized_field/_form.html.erb new file mode 100644 index 000000000..946eb0187 --- /dev/null +++ b/app/views/fields/serialized_field/_form.html.erb @@ -0,0 +1,19 @@ +
+ <%= f.label field.attribute, class: "field-unit__label" %> +
+ <% if field.array? %> + <% field.data.each do |sub_field| %> + <%= f.fields_for "#{field.attribute}[]", field.resource do |values_form| %> +
+ <% sub_field.each do |sf_key, sf_value| %> + <%= values_form.label sf_key %> + <%= values_form.text_field sf_key, value: sf_value, disabled: true %> + <% end %> +
+ <% end %> + <% end %> + <% else %> + <%= f.text_field field.attribute %> + <% end %> +
+
diff --git a/app/views/fields/serialized_field/_index.html.erb b/app/views/fields/serialized_field/_index.html.erb new file mode 100644 index 000000000..a3e1ce420 --- /dev/null +++ b/app/views/fields/serialized_field/_index.html.erb @@ -0,0 +1,9 @@ +<% if field.array? %> + <% field.data.each do |sub_field| %> +
+ <%= sub_field.to_s %> +
+ <% end %> +<% else %> + <%= field.to_s %> +<% end %> diff --git a/app/views/fields/serialized_field/_show.html.erb b/app/views/fields/serialized_field/_show.html.erb new file mode 100644 index 000000000..a3e1ce420 --- /dev/null +++ b/app/views/fields/serialized_field/_show.html.erb @@ -0,0 +1,9 @@ +<% if field.array? %> + <% field.data.each do |sub_field| %> +
+ <%= sub_field.to_s %> +
+ <% end %> +<% else %> + <%= field.to_s %> +<% end %> diff --git a/app/views/super_admin/application/_navigation.html.erb b/app/views/super_admin/application/_navigation.html.erb index 54c2ecc1b..09810f053 100644 --- a/app/views/super_admin/application/_navigation.html.erb +++ b/app/views/super_admin/application/_navigation.html.erb @@ -15,7 +15,8 @@ as defined by the routes in the `admin/` namespace accounts: 'ion ion-briefcase', users: 'ion ion-person-stalker', super_admins: 'ion ion-unlocked', - access_tokens: 'ion-key' + access_tokens: 'ion-key', + installation_configs: 'ion ion-settings' } %> @@ -43,7 +44,7 @@ as defined by the routes in the `admin/` namespace