thecore_ui_rails_admin 3.4.2 → 3.5.1

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 2f2dbc04f7d702990f70e5e1283ae6ee123d230309a4f11e1eb4a9301ac42b3e
4
- data.tar.gz: 389eeb46854cb9d4d1d238631690a750975f1b11868540ebbe56fc4565749d70
3
+ metadata.gz: 4a25dd232dbfdfb24580adcb9171ea51ce2057cec2a4c8c1c688c517ffbc38ec
4
+ data.tar.gz: 8155fdf0de1aa96c27a859f6d4a8402d6bb1dc57a525996eb1510118677a1c96
5
5
  SHA512:
6
- metadata.gz: ef1fc5f9181a819872bbcf97f9592911ef8643339371c6df063cf0b101b97f9daef5b6f52289c1f927c3b6a4bc5063c363181934cd0214ddb2c216e2002c1547
7
- data.tar.gz: 0170a75ca864b1f7bb938128c32bdde3356f0a0625517e4431caa32dbf995e504aff2c8c146329be8a9bcdb56c9d68e03465e0372a7e8c4639d3ac10ba3ebaf6
6
+ metadata.gz: 674e7d39dc22303c919e82e9f0abd7139c043ef169769b21ee6d20b8a4c6ba47e9c29b6de5670e324be1f150760056ed1c0afba113ebc08d99ea5d9c2e487a88
7
+ data.tar.gz: 9bfbf1f7ec2a9baeddafe77f03d710d070275eed49859a7f407c6d76c51727154d5c41649e403c551aef5aa9d8403f975a89d0b5f2e9786f65ae9ce4ebdeede3
@@ -1,7 +1,6 @@
1
1
  //= require 'thecore_ui_commons'
2
2
  //= require 'rails_admin/custom/thecore/ui'
3
3
  //= require 'channels/index'
4
-
5
4
  const adjustIframe = function (obj) {
6
5
  console.log("Resizing");
7
6
  obj.style.height = obj.contentWindow.document.body.scrollHeight + 'px';
@@ -19,12 +18,22 @@ $(document).on('turbo:load', function (event) {
19
18
  console.log(" - Hostname:", currentURL.hostname);
20
19
  console.log(" - Port:", currentURL.port);
21
20
  console.log(" - Pathname:", currentURL.pathname);
21
+ // Get the current user ID from a meta tag
22
+ document.currentUserId = document.querySelector('meta[name="current-user-id"]').getAttribute('content');
23
+ // Get the current url pathname, is the first string between app/ and the first / encountered, i.e. /app/location/bulk/action, in this case is location
24
+ document.currentModelName = currentURL.pathname.split('/')[2];
25
+ console.log(" - Controller:", document.currentModelName);
22
26
  console.log(" - Search:", currentURL.search);
23
27
  currentURL.searchParams.forEach((v, k) => {
24
28
  console.log(` - ${k}: ${v}`);
25
29
  })
26
30
  console.log(" - Hash:", currentURL.hash);
27
31
 
32
+
33
+ // Remove any existing logo to avoid duplicates
34
+ $(".navbar-brand-logo").remove();
35
+ // Prepend the custom logo to the navbar
36
+
28
37
  // Add the app_logo before the Title
29
38
  const customer_logo_path = "<%= asset_path('app_logo.svg') %>";
30
39
  $(".navbar-brand").prepend(`<img class="navbar-brand-logo" alt="Customer Logo" src="${customer_logo_path}"/>`);
@@ -38,6 +47,109 @@ $(document).on('turbo:load', function (event) {
38
47
  link.href = link.href.split('?')[0] + currentQuery;
39
48
  }
40
49
  });
50
+
51
+ // If URL ends with /bulk_action, uncheck all checkboxes
52
+ if (currentURL.pathname.endsWith('/bulk_action')) {
53
+ const checkboxes = document.querySelectorAll('input[type="checkbox"][name^="schema"]');
54
+ checkboxes.forEach(checkbox => {
55
+ checkbox.checked = false;
56
+ });
57
+ // Also uncheck the main checkbox if it exists
58
+ const mainCheckbox = document.querySelector('input[type="checkbox"][name="all"]');
59
+ if (mainCheckbox) {
60
+ mainCheckbox.checked = false;
61
+ }
62
+
63
+ // Use the fetch to get all the already saved checkboxes:
64
+ fetch('/app/general_computation?' + new URLSearchParams({
65
+ verb: "load",
66
+ model: "UserPreference",
67
+ "finders[user_id]": document.currentUserId,
68
+ "finders[name]": `export_${document.currentModelName}`
69
+ }), {
70
+ headers: {
71
+ 'Content-Type': 'application/json',
72
+ 'Accept': 'application/json',
73
+ 'X-CSRF-Token': document.querySelector('meta[name="csrf-token"]').getAttribute('content')
74
+ }
75
+ })
76
+ .then(response => {
77
+ if (response.ok) {
78
+ return response.json()
79
+ // The value field in the response bears the ids of the input checkbox type to set at checked true
80
+ } else {
81
+ return {
82
+ message: {
83
+ value: []
84
+ }
85
+ }
86
+ }
87
+ })
88
+ .then(message => {
89
+ message.message.value.forEach(id => {
90
+ const selectedCheckbox = document.querySelector(`#${id}`);
91
+ if (selectedCheckbox) {
92
+ selectedCheckbox.checked = true;
93
+ }
94
+ })
95
+ })
96
+
97
+ // Add to the fieldset with id fields_to_export a button with class btn btn-info which, if clicked, gets the checked status of all checkboxes with name starting with schema and using the current session login, saves them to the ruby on rails controller User in order to be saved to the settings json field.
98
+ const fieldset = document.getElementById('fields_to_export');
99
+ if (fieldset) {
100
+ const saveButton = document.createElement('button');
101
+ saveButton.type = 'button';
102
+ saveButton.className = 'btn btn-info';
103
+ saveButton.textContent = 'Save Selected Fields as Default';
104
+ saveButton.style.marginLeft = '10px';
105
+ saveButton.onclick = function () {
106
+ const selectedFields = [];
107
+ const checkboxes = document.querySelectorAll('input[type="checkbox"][name^="schema"]');
108
+ checkboxes.forEach(checkbox => {
109
+ if (checkbox.checked) {
110
+ selectedFields.push(checkbox.id);
111
+ }
112
+ });
113
+ // Send the selected fields to the server using fetch API, emulating a POST request to /app/user of type form json
114
+ fetch('/app/general_computation', {
115
+ method: 'POST',
116
+ headers: {
117
+ 'Content-Type': 'application/json',
118
+ 'Accept': 'application/json',
119
+ 'X-CSRF-Token': document.querySelector('meta[name="csrf-token"]').getAttribute('content')
120
+ },
121
+ // The body will have the current_user id, a name which is created by concattenating export and the current model name, and the selected fields as an array
122
+ body: JSON.stringify({
123
+ verb: "upsert",
124
+ model: "UserPreference",
125
+ finders: {
126
+ user_id: document.currentUserId,
127
+ name: `export_${document.currentModelName}`
128
+ },
129
+ fields: {
130
+ value: selectedFields
131
+ }
132
+ })
133
+ })
134
+ .then(response => {
135
+ if (response.ok) {
136
+ alert('Default export fields saved successfully.');
137
+ } else {
138
+ alert('Error saving default export fields.');
139
+ }
140
+ })
141
+ .catch(error => {
142
+ console.error('Error:', error);
143
+ alert('Error saving default export fields.');
144
+ });
145
+ };
146
+ // add the button to a div with row class, then att the div to the fieldset
147
+ const buttonRow = document.createElement('div');
148
+ buttonRow.className = 'row mt-3';
149
+ buttonRow.appendChild(saveButton);
150
+ fieldset.append(buttonRow);
151
+ }
152
+ }
41
153
  });
42
154
 
43
155
  const sidepanel = "body > div.container-fluid > div > div.col-sm-3.col-md-2.flex-wrap.p-0"
@@ -72,4 +72,10 @@ body > div.container-fluid > div > div.col-sm-9.col-sm-offset-3.col-md-10.col-md
72
72
  height: 1.7em;
73
73
  }
74
74
 
75
+ // Hide and remove export for found objects, is safer to have the possibility to export only selected rows to avoid big CPU usage.
76
+ .export_collection_link,
77
+ #list form div div.row div.col-sm-6:nth-child(2) {
78
+ display: none;
79
+ }
80
+
75
81
  @import 'rails_admin/custom/thecore/theming';
@@ -0,0 +1,19 @@
1
+ module Api::UserPreference
2
+ extend ActiveSupport::Concern
3
+
4
+ included do
5
+ # Use self.json_attrs to drive json rendering for
6
+ # API model responses (index, show and update ones).
7
+ # For reference:
8
+ # https://api.rubyonrails.org/classes/ActiveModel/Serializers/JSON.html
9
+ # The object passed accepts only these keys:
10
+ # - only: list [] of model fields to be shown in JSON serialization
11
+ # - except: exclude these fields from the JSON serialization, is a list []
12
+ # - methods: include the result of some method defined in the model
13
+ # - include: include associated models, it's an object {} which also accepts the keys described here
14
+ cattr_accessor :json_attrs
15
+ self.json_attrs = ::ModelDrivenApi.smart_merge (json_attrs || {}), {}
16
+
17
+ # Custom action callable by the API must be defined in /app/models/concerns/endpoints/
18
+ end
19
+ end
@@ -0,0 +1,78 @@
1
+ class Endpoints::UserPreference < NonCrudEndpoints
2
+ # self.desc 'UserPreference', :test, {
3
+ # # Define the action name using openapi swagger format
4
+ # get: {
5
+ # summary: "Test API Custom Action",
6
+ # description: "This is a test API custom action",
7
+ # operationId: "test",
8
+ # tags: ["Test"],
9
+ # parameters: [
10
+ # {
11
+ # name: "explain",
12
+ # in: "query",
13
+ # description: "Explain the action by returning this openapi schema",
14
+ # required: true,
15
+ # schema: {
16
+ # type: "boolean"
17
+ # }
18
+ # }
19
+ # ],
20
+ # responses: {
21
+ # 200 => {
22
+ # description: "The openAPI json schema for this action",
23
+ # content: {
24
+ # "application/json": {
25
+ # schema: {
26
+ # type: "object",
27
+ # additionalProperties: true
28
+ # }
29
+ # }
30
+ # }
31
+ # },
32
+ # 501 => {
33
+ # error: :string,
34
+ # }
35
+ # }
36
+ # },
37
+ # post: {
38
+ # summary: "Test API Custom Action",
39
+ # description: "This is a test API custom action",
40
+ # operationId: "test",
41
+ # tags: ["Test"],
42
+ # requestBody: {
43
+ # required: true,
44
+ # content: {
45
+ # "application/json": {}
46
+ # }
47
+ # },
48
+ # responses: {
49
+ # 200 => {
50
+ # description: "The openAPI json schema for this action",
51
+ # # This will return the object with a message string and a params object
52
+ # content: {
53
+ # "application/json": {
54
+ # schema: {
55
+ # type: "object",
56
+ # properties: {
57
+ # message: {
58
+ # type: "string"
59
+ # },
60
+ # params: {
61
+ # type: "object",
62
+ # additionalProperties: true
63
+ # }
64
+ # }
65
+ # }
66
+ # }
67
+ # }
68
+ # },
69
+ # 501 => {
70
+ # error: :string,
71
+ # }
72
+ # }
73
+ # }
74
+ # }
75
+ # def test(params)
76
+ # return { message: "Hello World From Test API Custom Action called test", params: params }, 200
77
+ # end
78
+ end
@@ -0,0 +1,11 @@
1
+ module RailsAdmin::UserPreference
2
+ extend ActiveSupport::Concern
3
+
4
+ included do
5
+ rails_admin do
6
+ navigation_label I18n.t('admin.registries.label')
7
+ navigation_icon 'fa fa-file'
8
+ visible false
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,7 @@
1
+ class UserPreference < ApplicationRecord
2
+ include Api::UserPreference
3
+ include RailsAdmin::UserPreference
4
+ belongs_to :user, inverse_of: :user_preferences
5
+ validates :name, presence: true, uniqueness: { scope: :user_id }
6
+ validates :value, presence: true
7
+ end
@@ -4,6 +4,14 @@
4
4
  <head>
5
5
  <%= render "layouts/rails_admin/head" %>
6
6
  <%= render "layouts/rails_admin/controller_assets" %>
7
+
8
+ <!-- meta tags to get current user id and current model name which in rails_admin is not controller_name, since it's always main, but the abstract model one for use in custom javascript -->
9
+ <meta name="current-user-id" content="<%= current_user.id %>">
10
+ <%
11
+ =begin%>
12
+ <meta name="current-model-name" content="<%= @abstract_model.param_key %>">
13
+ <%
14
+ =end%>
7
15
  </head>
8
16
  <body class="rails_admin">
9
17
  <div data-i18n-options="<%= I18n.t("admin.js").to_json %>" id="admin-js"></div>
@@ -45,6 +45,7 @@ Rails.application.configure do
45
45
  Target.send :include, ThecoreUiRailsAdminTargetConcern
46
46
  ThecoreSettings::Setting.send :include, ThecoreUiRailsAdminSettingsConcern
47
47
 
48
+ require 'root_actions/general_computation'
48
49
  require 'root_actions/active_job_monitor'
49
50
  require 'member_actions/change_password'
50
51
  require 'member_actions/test_ldap_server'
@@ -1,3 +1,5 @@
1
1
  Rails.application.config.assets.precompile += %w(
2
2
  channels/index.js
3
3
  )
4
+
5
+ Rails.application.config.assets.precompile += %w( rails_admin/actions/general_computation.js rails_admin/actions/general_computation.css )
@@ -13,5 +13,8 @@ module ExportConcern
13
13
  # In index, instead, I show it only if there are records in the current view
14
14
  bindings[:controller].action_name == "index" ? (authorized? && !bindings[:controller].instance_variable_get("@objects").blank?) : true
15
15
  end
16
+ register_instance_option :bulkable? do
17
+ true
18
+ end
16
19
  end
17
20
  end
@@ -1,86 +1,91 @@
1
1
  puts "User Concern from ThecoreUiRailsAdmin"
2
- require 'active_support/concern'
2
+ require "active_support/concern"
3
3
 
4
4
  module ThecoreUiRailsAdminUserConcern
5
- extend ActiveSupport::Concern
6
-
7
- included do
8
- has_many :saved_filters, class_name: 'SavedFilter', foreign_key: :admin_user_id, dependent: :destroy
5
+ extend ActiveSupport::Concern
9
6
 
10
- # def admin_enum
11
- # [["",true],['✘',false]]
12
- # end
7
+ included do
8
+ has_many :saved_filters, class_name: "SavedFilter", foreign_key: :admin_user_id, dependent: :destroy
9
+ has_many :user_preferences, class_name: "UserPreference", foreign_key: :user_id, dependent: :destroy, inverse_of: :user
10
+ accepts_nested_attributes_for :user_preferences, allow_destroy: true
13
11
 
14
- # def locked_enum
15
- # [["✔",true],['✘',false]]
16
- # end
17
- #
18
-
19
- # locale field is a string which can be chosen from the list of available locales: it and en
20
- # The default locale is the one set in the I18n.default_locale
21
- # The locale is used to set the language of the user
22
- def locale_enum
23
- [['Italiano', 'it'], ['English', 'en']]
24
- end
25
-
26
- rails_admin do
27
- navigation_label Proc.new { I18n.t("admin.settings.label") }
28
- navigation_icon 'fa fa-user-circle'
29
- parent Role
30
- # desc Proc.new { I18n.t("activerecord.descriptions.user") }
31
-
32
- # Hide fields: :id, :remember_created_at, :sign_in_count, :current_sign_in_at, :last_sign_in_at, :current_sign_in_ip, :last_sign_in_ip, :lock_version, :role_users
33
- configure :id do
34
- hide
35
- end
36
- configure :remember_created_at do
37
- hide
38
- end
39
- configure :sign_in_count do
40
- hide
41
- end
42
- configure :current_sign_in_at do
43
- hide
44
- end
45
- configure :last_sign_in_at do
46
- hide
47
- end
48
- configure :current_sign_in_ip do
49
- hide
50
- end
51
- configure :last_sign_in_ip do
52
- hide
53
- end
54
- configure :lock_version do
55
- hide
56
- end
57
- configure :role_users do
58
- hide
59
- end
60
- configure :saved_filters do
61
- hide
62
- end
63
- configure :auth_source do
64
- read_only true
65
- end
12
+ # def admin_enum
13
+ # [["✔",true],['✘',false]]
14
+ # end
15
+
16
+ # def locked_enum
17
+ # [["✔",true],['✘',false]]
18
+ # end
19
+ #
20
+
21
+ # locale field is a string which can be chosen from the list of available locales: it and en
22
+ # The default locale is the one set in the I18n.default_locale
23
+ # The locale is used to set the language of the user
24
+ def locale_enum
25
+ [["Italiano", "it"], ["English", "en"]]
26
+ end
27
+
28
+ rails_admin do
29
+ navigation_label Proc.new { I18n.t("admin.settings.label") }
30
+ navigation_icon "fa fa-user-circle"
31
+ parent Role
32
+ # desc Proc.new { I18n.t("activerecord.descriptions.user") }
66
33
 
67
- update do
68
- configure :password do
69
- hide
70
- end
71
- configure :password_confirmation do
72
- hide
73
- end
74
- end
34
+ # Hide fields: :id, :remember_created_at, :sign_in_count, :current_sign_in_at, :last_sign_in_at, :current_sign_in_ip, :last_sign_in_ip, :lock_version, :role_users
35
+ configure :id do
36
+ hide
37
+ end
38
+ configure :remember_created_at do
39
+ hide
40
+ end
41
+ configure :sign_in_count do
42
+ hide
43
+ end
44
+ configure :current_sign_in_at do
45
+ hide
46
+ end
47
+ configure :last_sign_in_at do
48
+ hide
49
+ end
50
+ configure :current_sign_in_ip do
51
+ hide
52
+ end
53
+ configure :last_sign_in_ip do
54
+ hide
55
+ end
56
+ configure :lock_version do
57
+ hide
58
+ end
59
+ configure :role_users do
60
+ hide
61
+ end
62
+ configure :saved_filters do
63
+ hide
64
+ end
65
+ configure :user_preferences do
66
+ hide
67
+ end
68
+ configure :auth_source do
69
+ read_only true
70
+ end
75
71
 
76
- create do
77
- configure :password do
78
- required true
79
- end
80
- configure :password_confirmation do
81
- required true
82
- end
83
- end
72
+ update do
73
+ configure :password do
74
+ hide
75
+ end
76
+ configure :password_confirmation do
77
+ hide
78
+ end
79
+ end
80
+
81
+ create do
82
+ configure :password do
83
+ required true
84
+ end
85
+ configure :password_confirmation do
86
+ required true
84
87
  end
88
+ end
85
89
  end
86
- end
90
+ end
91
+ end
@@ -0,0 +1,12 @@
1
+ class CreateUserPreferences < ActiveRecord::Migration[7.2]
2
+ def change
3
+ create_table :user_preferences do |t|
4
+ t.references :user, null: false, foreign_key: true
5
+ t.string :name
6
+ t.jsonb :value
7
+
8
+ t.timestamps
9
+ end
10
+ add_index :user_preferences, :name
11
+ end
12
+ end
@@ -0,0 +1,59 @@
1
+ RailsAdmin::Config::Actions.add_action "general_computation", :base, :root do
2
+ show_in_sidebar false
3
+ show_in_navigation false
4
+ breadcrumb_parent [nil]
5
+ # This ensures the action only shows up for Users
6
+ # visible? authorized?
7
+ # Not a member action
8
+ member false
9
+ # Not a colleciton action
10
+ collection false
11
+ # Have a look at https://fontawesome.com/v5/search for available icons
12
+ link_icon 'fas fa-file'
13
+ # The controller which will be used to compute the action and the REST verbs it will respond to
14
+ http_methods [:get, :post, :put, :patch, :delete]
15
+ # Adding the controller which is needed to compute calls from the ui
16
+ controller do
17
+ proc do # This is needed because we need that this code is re-evaluated each time is called
18
+ if request.format.json?
19
+ # PArams sent by the new call are:
20
+ # {
21
+ # action: "upsert",
22
+ # model: "UserPreference",
23
+ # finders: {
24
+ # user_id: currentUserId,
25
+ # name: `export_${currentModelName}`
26
+ # },
27
+ # fields: {
28
+ # value: selectedFields
29
+ # }
30
+ # }
31
+ #
32
+ case params[:verb]
33
+ when "upsert"
34
+ params.permit!
35
+ result = params[:model].camelize.constantize.where(params[:finders]).first_or_initialize.update(params[:fields])
36
+ if result
37
+ status = 200
38
+ message = "User preference saved"
39
+ else
40
+ status = 422
41
+ message = "Error saving user preference: #{result.errors.full_messages.join(", ")}"
42
+ end
43
+ when "load"
44
+ params.permit!
45
+ result = params[:model].camelize.constantize.where(params[:finders]).first
46
+ message = result
47
+ status = result.nil? ? 404 : 200
48
+ end
49
+
50
+ # This is the code that is executed when the action is called
51
+ # It is executed in the context of the controller
52
+ # So you can access all the controller methods
53
+ # and instance variables
54
+ ActionCable.server.broadcast("messages", { topic: :general_computation, status: status, message: message})
55
+ render json: {message: message.presence || "No message"}.to_json, status: status.presence || 200
56
+ end
57
+ end
58
+ end
59
+ end
@@ -1,3 +1,3 @@
1
1
  module ThecoreUiRailsAdmin
2
- VERSION = "3.4.2".freeze
2
+ VERSION = "3.5.1".freeze
3
3
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: thecore_ui_rails_admin
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.4.2
4
+ version: 3.5.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Gabriele Tassoni
@@ -77,7 +77,11 @@ files:
77
77
  - app/assets/stylesheets/rails_admin/custom/thecore/variables.scss
78
78
  - app/assets/stylesheets/rails_admin/custom/theming.scss
79
79
  - app/assets/stylesheets/rails_admin/custom/variables.scss
80
+ - app/models/concerns/api/user_preference.rb
81
+ - app/models/concerns/endpoints/user_preference.rb
82
+ - app/models/concerns/rails_admin/user_preference.rb
80
83
  - app/models/saved_filter.rb
84
+ - app/models/user_preference.rb
81
85
  - app/views/layouts/rails_admin/_controller_assets.html.erb
82
86
  - app/views/layouts/rails_admin/application.html.erb
83
87
  - app/views/rails_admin/main/_dashboard_block.html.erb
@@ -85,6 +89,7 @@ files:
85
89
  - app/views/rails_admin/main/active_job_monitor.html.erb
86
90
  - app/views/rails_admin/main/change_password.html.erb
87
91
  - app/views/rails_admin/main/dashboard.html.erb
92
+ - app/views/rails_admin/main/general_computation.html.erb
88
93
  - app/views/rails_admin/main/import_users_from_ldap.html.erb
89
94
  - app/views/rails_admin/main/load_filters.html.erb
90
95
  - app/views/rails_admin/main/save_filter.html.erb
@@ -111,6 +116,7 @@ files:
111
116
  - db/migrate/20250206222412_add_locale_to_user.rb
112
117
  - db/migrate/20250429155934_create_saved_filters.rb
113
118
  - db/migrate/20250430081805_rename_model_name_to_abstract_model_name_in_saved_filter.rb
119
+ - db/migrate/20250916092441_create_user_preferences.rb
114
120
  - db/seeds.rb
115
121
  - lib/collection_actions/load_filters.rb
116
122
  - lib/collection_actions/save_filters.rb
@@ -120,6 +126,7 @@ files:
120
126
  - lib/rails_admin_abstract_controller.rb
121
127
  - lib/rails_admin_filter_controller_helper.rb
122
128
  - lib/root_actions/active_job_monitor.rb
129
+ - lib/root_actions/general_computation.rb
123
130
  - lib/tasks/thecore_ui_rails_admin_tasks.rake
124
131
  - lib/thecore_ui_rails_admin.rb
125
132
  - lib/thecore_ui_rails_admin/engine.rb
@@ -145,7 +152,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
145
152
  - !ruby/object:Gem::Version
146
153
  version: '0'
147
154
  requirements: []
148
- rubygems_version: 3.6.7
155
+ rubygems_version: 3.6.9
149
156
  specification_version: 4
150
157
  summary: Thecore Backend UI based on Rails Admin.
151
158
  test_files: []