cm-admin 1.5.39 → 1.5.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/.github/workflows/deploy-yard-docs.yml +45 -0
- data/CNAME +1 -0
- data/Gemfile.lock +1 -1
- data/README.md +8 -2
- data/app/assets/javascripts/cm_admin/application.js +11 -11
- data/app/assets/javascripts/cm_admin/custom_action.js +30 -0
- data/app/assets/stylesheets/cm_admin/components/_input.scss +12 -0
- data/app/controllers/cm_admin/resource_controller.rb +13 -2
- data/app/javascript/packs/cm_admin/application.js +25 -28
- data/app/views/cm_admin/main/_actions_dropdown.html.slim +2 -2
- data/app/views/layouts/_custom_action_modal.html.slim +1 -1
- data/app/views/layouts/_custom_action_modals.html.slim +8 -7
- data/config/routes.rb +1 -1
- data/lib/cm_admin/constants.rb +4 -0
- data/lib/cm_admin/models/dsl_method.rb +203 -30
- data/lib/cm_admin/models/row.rb +6 -0
- data/lib/cm_admin/version.rb +1 -1
- data/lib/cm_admin/view_helpers/field_display_helper.rb +1 -0
- data/lib/cm_admin/view_helpers/form_field_helper.rb +24 -14
- data/lib/cm_admin/view_helpers/form_helper.rb +5 -1
- metadata +5 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: c64d865b82c2abfd0975930a349a1ba2f63ee85d5ecbf0a4e627d3cbc1629bb1
|
4
|
+
data.tar.gz: 5ce41edd98628d3b20315a5ca44c5be95daf578bbdd53c97192f114f58110545
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 7327d73ee5028535163d62e4f3dbc7197389132178331c9bf76e4e0bb463166a06fb74186c4c32c0a50871c37ead0895e7f4b43157646bb3a5ff59b3e5e7e207
|
7
|
+
data.tar.gz: fefcc76ae24e4cc066c9dc70831fa5f1974bfe03563c49863e319180adec9577eb0dcb6acae9a4d35d4b587a7a2b602d3a09e0cab4c4b03ae8eac1e12eddd286
|
@@ -0,0 +1,45 @@
|
|
1
|
+
name: Deploy Yard Docs
|
2
|
+
|
3
|
+
on:
|
4
|
+
workflow_dispatch:
|
5
|
+
|
6
|
+
jobs:
|
7
|
+
build:
|
8
|
+
runs-on: ubuntu-latest
|
9
|
+
steps:
|
10
|
+
- uses: actions/checkout@v4
|
11
|
+
- name: Set up Ruby
|
12
|
+
uses: ruby/setup-ruby@v1
|
13
|
+
with:
|
14
|
+
ruby-version: "3.3"
|
15
|
+
- name: Install Yard gem
|
16
|
+
run: gem install yard
|
17
|
+
- name: Build Yard Docs
|
18
|
+
run: yardoc lib/cm_admin/models/dsl_method.rb
|
19
|
+
- name: Upload artifact
|
20
|
+
uses: actions/upload-pages-artifact@v1
|
21
|
+
with:
|
22
|
+
name: github-pages # name of the artifact
|
23
|
+
path: ./doc
|
24
|
+
if-no-files-found: error
|
25
|
+
|
26
|
+
deploy:
|
27
|
+
# Add a dependency to the build job
|
28
|
+
needs: build
|
29
|
+
|
30
|
+
# Grant GITHUB_TOKEN the permissions required to make a Pages deployment
|
31
|
+
permissions:
|
32
|
+
pages: write # to deploy to Pages
|
33
|
+
id-token: write # to verify the deployment originates from an appropriate source
|
34
|
+
|
35
|
+
# Deploy to the github-pages environment
|
36
|
+
environment:
|
37
|
+
name: github-pages # artifact name
|
38
|
+
url: ${{ steps.deployment.outputs.page_url }}
|
39
|
+
|
40
|
+
# Specify runner + deployment step
|
41
|
+
runs-on: ubuntu-latest
|
42
|
+
steps:
|
43
|
+
- name: Deploy to GitHub Pages
|
44
|
+
id: deployment
|
45
|
+
uses: actions/deploy-pages@v2
|
data/CNAME
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
docs.cm-admin.commutatus.com
|
data/Gemfile.lock
CHANGED
data/README.md
CHANGED
@@ -37,13 +37,19 @@ For demo repo check [here](https://github.com/commutatus/cm-admin-panel-demo)
|
|
37
37
|
|
38
38
|
After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
|
39
39
|
|
40
|
-
To install this gem onto your local machine, run `bundle exec rake install`.
|
40
|
+
To install this gem onto your local machine, run `bundle exec rake install`.
|
41
|
+
|
42
|
+
## Deployment
|
43
|
+
|
44
|
+
To release a new version of the Gem you can use Github Actions.
|
45
|
+
|
46
|
+
Go to Actions tab in your repository and click on `Bump Gem` workflow.
|
47
|
+
You will see `Run workflow` button click on it and choose `Bump Type`, then click `Run Workflow` and it will bump the version of the gem and push the changes to the repository.
|
41
48
|
|
42
49
|
## Contributing
|
43
50
|
|
44
51
|
Bug reports and pull requests are welcome on [GitHub](https://github.com/commutatus/cm-admin).
|
45
52
|
|
46
|
-
|
47
53
|
## License
|
48
54
|
|
49
55
|
The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
|
@@ -1,12 +1,12 @@
|
|
1
|
-
import
|
2
|
-
import
|
3
|
-
|
4
|
-
import './bulk_actions.js'
|
5
|
-
import './cocoon.js'
|
6
|
-
import './exports.js'
|
7
|
-
import './filters.js'
|
8
|
-
import './form_validation.js'
|
9
|
-
import './quick_search.js'
|
10
|
-
import './custom.js'
|
11
|
-
import './kanban.js'
|
1
|
+
import "./scaffolds.js";
|
2
|
+
import "./shared_scaffolds.js";
|
12
3
|
|
4
|
+
import "./bulk_actions.js";
|
5
|
+
import "./cocoon.js";
|
6
|
+
import "./exports.js";
|
7
|
+
import "./filters.js";
|
8
|
+
import "./form_validation.js";
|
9
|
+
import "./quick_search.js";
|
10
|
+
import "./custom.js";
|
11
|
+
import "./kanban.js";
|
12
|
+
import "./custom_action";
|
@@ -0,0 +1,30 @@
|
|
1
|
+
import * as bootstrap from "bootstrap";
|
2
|
+
window.bootstrap = bootstrap;
|
3
|
+
|
4
|
+
document.addEventListener("turbo:load", function () {
|
5
|
+
$('[data-action="fetch-modal"]').on("click", function (e) {
|
6
|
+
const actionName = $(this).attr("data-action_name");
|
7
|
+
const modelName = $(this).attr("data-model_name");
|
8
|
+
const recordId = $(this).attr("data-record_id");
|
9
|
+
const modalContainer = $(
|
10
|
+
"[data-behaviour='custom-action-modal-container']"
|
11
|
+
);
|
12
|
+
const routeMount = document.location.href.split("/")[3];
|
13
|
+
|
14
|
+
if (!actionName || !modelName || !recordId || !modalContainer) return;
|
15
|
+
$.ajax({
|
16
|
+
url: `/${routeMount}/${modelName}/${recordId}/custom_action_modal/${actionName}`,
|
17
|
+
method: "GET",
|
18
|
+
success: function (response) {
|
19
|
+
modalContainer.html(response);
|
20
|
+
const actionModal = new bootstrap.Modal(
|
21
|
+
modalContainer.children().first()
|
22
|
+
);
|
23
|
+
actionModal.show();
|
24
|
+
},
|
25
|
+
error: function (error) {
|
26
|
+
console.error("Error:", error);
|
27
|
+
},
|
28
|
+
});
|
29
|
+
});
|
30
|
+
});
|
@@ -109,6 +109,18 @@
|
|
109
109
|
}
|
110
110
|
|
111
111
|
//checkbox-style
|
112
|
+
|
113
|
+
.cm-checkbox-section {
|
114
|
+
width: 100%;
|
115
|
+
float: left;
|
116
|
+
.cm-checkbox-label {
|
117
|
+
float: left;
|
118
|
+
padding-left: 10px;
|
119
|
+
}
|
120
|
+
.cm-checkbox-tag {
|
121
|
+
float: left;
|
122
|
+
}
|
123
|
+
}
|
112
124
|
input.cm-checkbox[type="checkbox"] {
|
113
125
|
position: relative;
|
114
126
|
// display: block;
|
@@ -89,7 +89,7 @@ module CmAdmin
|
|
89
89
|
end
|
90
90
|
|
91
91
|
def import
|
92
|
-
@model = Model.find_by({name: controller_name.
|
92
|
+
@model = Model.find_by({name: controller_name.classify})
|
93
93
|
allowed_params = params.permit(file_import: [:associated_model_name, :import_file]).to_h
|
94
94
|
file_import = ::FileImport.new(allowed_params[:file_import])
|
95
95
|
file_import.added_by = Current.user
|
@@ -101,7 +101,7 @@ module CmAdmin
|
|
101
101
|
end
|
102
102
|
|
103
103
|
def import_form
|
104
|
-
@model = Model.find_by({name: controller_name.
|
104
|
+
@model = Model.find_by({name: controller_name.classify})
|
105
105
|
respond_to do |format|
|
106
106
|
format.html { render '/cm_admin/main/import_form' }
|
107
107
|
end
|
@@ -172,6 +172,17 @@ module CmAdmin
|
|
172
172
|
end
|
173
173
|
end
|
174
174
|
|
175
|
+
def cm_custom_action_modal(params)
|
176
|
+
scoped_model = "CmAdmin::#{@model.name}Policy::Scope".constantize.new(Current.user, @model.name.constantize).resolve
|
177
|
+
@ar_object = fetch_ar_object(scoped_model, params[:id])
|
178
|
+
if params[:action_name] == 'destroy'
|
179
|
+
render partial: '/layouts/destroy_action_modal', locals: { ar_object: @ar_object }
|
180
|
+
else
|
181
|
+
custom_action = @model.available_actions.select { |x| x.name == params[:action_name].to_s }.first
|
182
|
+
render partial: '/layouts/custom_action_modal', locals: { custom_action:, ar_object: @ar_object }
|
183
|
+
end
|
184
|
+
end
|
185
|
+
|
175
186
|
def get_nested_table_fields(fields)
|
176
187
|
nested_table_fields = []
|
177
188
|
fields.each do |field|
|
@@ -1,30 +1,27 @@
|
|
1
|
-
require("@rails/ujs").start()
|
2
|
-
require("turbolinks").start()
|
3
|
-
require("@rails/activestorage").start()
|
4
|
-
require("stylesheets/cm_admin/application")
|
5
|
-
require("jquery")
|
6
|
-
require("moment")
|
7
|
-
require("bootstrap")
|
8
|
-
require(
|
9
|
-
require("jgrowl")
|
10
|
-
require("trix")
|
11
|
-
require(
|
12
|
-
require(
|
13
|
-
require(
|
14
|
-
require(
|
15
|
-
require(
|
16
|
-
require(
|
17
|
-
require(
|
18
|
-
|
19
|
-
import jQuery from 'jquery'
|
20
|
-
import LocalTime from "local-time"
|
21
|
-
window.$ = jQuery
|
22
|
-
window.jQuery = jQuery
|
23
|
-
|
24
|
-
LocalTime.start()
|
25
|
-
require("@nathanvda/cocoon")
|
26
|
-
import "@fortawesome/fontawesome-free/css/all"
|
27
|
-
import "daterangepicker"
|
28
|
-
|
1
|
+
require("@rails/ujs").start();
|
2
|
+
require("turbolinks").start();
|
3
|
+
require("@rails/activestorage").start();
|
4
|
+
require("stylesheets/cm_admin/application");
|
5
|
+
require("jquery");
|
6
|
+
require("moment");
|
7
|
+
require("bootstrap");
|
8
|
+
require("flatpickr");
|
9
|
+
require("jgrowl");
|
10
|
+
require("trix");
|
11
|
+
require("./scaffolds.js");
|
12
|
+
require("/app/assets/javascripts/cm_admin/shared_scaffolds.js");
|
13
|
+
require("/app/assets/javascripts/cm_admin/form_validation.js");
|
14
|
+
require("/app/assets/javascripts/cm_admin/quick_search.js");
|
15
|
+
require("/app/assets/javascripts/cm_admin/filters.js");
|
16
|
+
require("/app/assets/javascripts/cm_admin/exports.js");
|
17
|
+
require("/app/assets/javascripts/cm_admin/bulk_actions.js");
|
29
18
|
|
19
|
+
import jQuery from "jquery";
|
20
|
+
import LocalTime from "local-time";
|
21
|
+
window.$ = jQuery;
|
22
|
+
window.jQuery = jQuery;
|
30
23
|
|
24
|
+
LocalTime.start();
|
25
|
+
require("@nathanvda/cocoon");
|
26
|
+
import "@fortawesome/fontawesome-free/css/all";
|
27
|
+
import "daterangepicker";
|
@@ -27,7 +27,7 @@
|
|
27
27
|
i.fa.fa-trash
|
28
28
|
| Destroy
|
29
29
|
- else
|
30
|
-
|
30
|
+
div data={action: 'fetch-modal', model_name: "#{cm_model.name.underscore.pluralize}", action_name: "destroy", record_id: "#{ar_object.id.to_s}"}
|
31
31
|
.popup-option
|
32
32
|
span
|
33
33
|
i.fa.fa-trash
|
@@ -42,7 +42,7 @@
|
|
42
42
|
i class="#{custom_action.icon_name}"
|
43
43
|
= custom_action_title(custom_action)
|
44
44
|
- when :modal
|
45
|
-
=
|
45
|
+
div data={action: 'fetch-modal', model_name: "#{cm_model.name.underscore.pluralize}", action_name: "#{custom_action.name}", record_id: "#{ar_object.id.to_s}"}
|
46
46
|
.popup-option
|
47
47
|
span
|
48
48
|
i class="#{custom_action.icon_name}"
|
@@ -8,4 +8,4 @@
|
|
8
8
|
- if custom_action.partial
|
9
9
|
= render partial: custom_action.partial, locals: { custom_action: custom_action, ar_object: ar_object }
|
10
10
|
- else
|
11
|
-
= render partial: 'cm_admin/main/custom_action_modal_form', locals: { custom_action: custom_action, ar_object: ar_object }
|
11
|
+
= render partial: 'cm_admin/main/custom_action_modal_form', locals: { custom_action: custom_action, ar_object: ar_object }
|
@@ -1,24 +1,25 @@
|
|
1
1
|
- custom_action_with_modals = @model.available_actions.select{ |act| act if act.display_type == :modal && act.action_type == :custom }
|
2
2
|
- bulk_action_with_modals = @model.available_actions.select{ |act| act if act.display_type == :modal && act.action_type == :bulk_action }
|
3
3
|
- destroy_action = @ar_object ? available_actions(@model, @ar_object, 'destroy') : nil
|
4
|
+
|
5
|
+
div[data-behaviour="custom-action-modal-container"]
|
6
|
+
|
4
7
|
- if @associated_model
|
5
8
|
- custom_action_with_modals += @associated_model.available_actions.select{ |act| act if act.display_type == :modal }
|
9
|
+
|
6
10
|
- if @current_action&.name == 'index'
|
7
11
|
- bulk_action_with_modals.each do |bulk_action|
|
8
12
|
= render partial: '/layouts/custom_action_modal', locals: { custom_action: bulk_action, ar_object: nil }
|
9
|
-
|
10
|
-
- custom_action_with_modals.each do |custom_action|
|
11
|
-
= render partial: '/layouts/custom_action_modal', locals: { custom_action: custom_action, ar_object: ar_object }
|
12
|
-
- if destroy_action
|
13
|
-
= render partial: '/layouts/destroy_action_modal', locals: { ar_object: ar_object }
|
13
|
+
|
14
14
|
- elsif @current_action&.name == 'show'
|
15
15
|
- custom_action_with_modals.each do |custom_action|
|
16
|
-
= render partial: '/layouts/custom_action_modal', locals: { custom_action: custom_action, ar_object: @ar_object
|
16
|
+
= render partial: '/layouts/custom_action_modal', locals: { custom_action: custom_action, ar_object: @ar_object }
|
17
17
|
- if destroy_action
|
18
18
|
= render partial: '/layouts/destroy_action_modal', locals: { ar_object: @ar_object }
|
19
|
+
|
19
20
|
- elsif @current_action&.action_type == :custom && @associated_ar_object&.data.present?
|
20
21
|
- @associated_ar_object.data.each do |ar_object|
|
21
22
|
- custom_action_with_modals.select{|custom_action| custom_action.model_name == @current_action.child_records.to_s.classify}.each do |custom_action|
|
22
23
|
= render partial: '/layouts/custom_action_modal', locals: { custom_action: custom_action, ar_object: ar_object }
|
23
24
|
- if destroy_action
|
24
|
-
= render partial: '/layouts/destroy_action_modal', locals: { ar_object: ar_object }
|
25
|
+
= render partial: '/layouts/destroy_action_modal', locals: { ar_object: ar_object }
|
data/config/routes.rb
CHANGED
@@ -16,7 +16,7 @@ CmAdmin::Engine.routes.draw do
|
|
16
16
|
send(:post, 'import', to: "#{model.name.underscore}#import", as: "#{model.name.underscore}_import")
|
17
17
|
end
|
18
18
|
end
|
19
|
-
|
19
|
+
|
20
20
|
model.available_actions.sort_by {|act| act.name}.each do |act|
|
21
21
|
scope model.name.tableize do
|
22
22
|
# Define route only when action trail related field is present
|
data/lib/cm_admin/constants.rb
CHANGED
@@ -3,42 +3,109 @@ module CmAdmin
|
|
3
3
|
module DslMethod
|
4
4
|
extend ActiveSupport::Concern
|
5
5
|
|
6
|
-
|
6
|
+
# Create a table for index page with pagination.
|
7
|
+
#
|
8
|
+
# @param page_title [String] the title of page
|
9
|
+
# @param page_description [String] the description of page
|
10
|
+
# @param partial [String] the partial path of page
|
11
|
+
# @param view_type [Symbol] view type of page +:table+, +:card+ or +:kanban+
|
12
|
+
# @example Index page
|
13
|
+
# cm_index do
|
14
|
+
# page_title 'Post'
|
15
|
+
# column :title
|
16
|
+
# column :created_at, field_type: :date, format: '%d %b, %Y'
|
17
|
+
# column :updated_at, field_type: :date, format: '%d %b, %Y', header: 'Last Updated At'
|
18
|
+
# end
|
19
|
+
# rdoc-image:/public/examples/cm_index.png
|
20
|
+
def cm_index(page_title: nil, page_description: nil, partial: nil, view_type: :table)
|
7
21
|
@current_action = CmAdmin::Models::Action.find_by(self, name: 'index')
|
8
22
|
@current_action.set_values(page_title, page_description, partial, view_type)
|
9
23
|
yield
|
10
24
|
end
|
11
25
|
|
12
|
-
|
26
|
+
# Create a view for show page
|
27
|
+
#
|
28
|
+
# @param page_title [String | Symbol] the title of page, if symbol passed, it will be a method name on model
|
29
|
+
# @param page_description [String] the description of page
|
30
|
+
# @param partial [String] the partial path of page
|
31
|
+
#
|
32
|
+
# @example Showing page
|
33
|
+
# cm_show page_title: :title do
|
34
|
+
# tab :profile, '' do
|
35
|
+
# cm_section 'Post Details' do
|
36
|
+
# field :title
|
37
|
+
# field :body, field_type: :rich_text
|
38
|
+
# field :is_featured
|
39
|
+
# field :status, field_type: :tag, tag_class: STATUS_TAG_COLOR
|
40
|
+
# end
|
41
|
+
# end
|
42
|
+
# end
|
43
|
+
def cm_show(page_title: nil, page_description: nil, partial: nil)
|
13
44
|
@current_action = CmAdmin::Models::Action.find_by(self, name: 'show')
|
14
45
|
@current_action.set_values(page_title, page_description, partial)
|
15
46
|
yield
|
16
47
|
end
|
17
48
|
|
18
|
-
|
49
|
+
# Create a form for edit action
|
50
|
+
#
|
51
|
+
# @param page_title [String] or [Symbol] the title of page, if symbol passed, it will be a method name on model
|
52
|
+
# @param page_description [String] the description of page
|
53
|
+
# @param partial [String] the partial path of page
|
54
|
+
# @param redirect_to [Proc, nil] A lambda that takes the current object and redirect to path after update
|
55
|
+
#
|
56
|
+
# @example Editing page with a redirect
|
57
|
+
# cm_edit(page_title: "Edit Post", page_description: 'Enter all details to edit Post', redirect_to: ->(current_object) { "/pages/#{current_object.id}" }) do
|
58
|
+
# cm_section 'Details' do
|
59
|
+
# form_field :title, input_type: :string
|
60
|
+
# form_field :body, input_type: :rich_text
|
61
|
+
# end
|
62
|
+
# end
|
63
|
+
def cm_edit(page_title: nil, page_description: nil, partial: nil, redirect_to: nil)
|
19
64
|
@current_action = CmAdmin::Models::Action.find_by(self, name: 'edit')
|
20
65
|
@current_action.set_values(page_title, page_description, partial, redirect_to)
|
21
66
|
yield
|
22
67
|
end
|
23
68
|
|
24
|
-
|
69
|
+
# Create a form for new action
|
70
|
+
#
|
71
|
+
# @param page_title [String] the title of page
|
72
|
+
# @param page_description [String] the description of page
|
73
|
+
# @param partial [String] the partial path of page
|
74
|
+
# @param redirect_to [Proc, nil] A lambda that takes the current object and redirect to path after create
|
75
|
+
#
|
76
|
+
# @example Creating a new page with a redirect
|
77
|
+
# cm_new(page_title: "Add Post", page_description: 'Enter all details to add Post', redirect_to: ->(current_object) { "/pages/#{current_object.id}" }) do
|
78
|
+
# cm_section 'Details' do
|
79
|
+
# form_field :title, input_type: :string
|
80
|
+
# form_field :body, input_type: :rich_text
|
81
|
+
# end
|
82
|
+
# end
|
83
|
+
def cm_new(page_title: nil, page_description: nil, partial: nil, redirect_to: nil)
|
25
84
|
@current_action = CmAdmin::Models::Action.find_by(self, name: 'new')
|
26
85
|
@current_action.set_values(page_title, page_description, partial, redirect_to)
|
27
86
|
yield
|
28
87
|
end
|
29
88
|
|
89
|
+
# Set page title for current action
|
90
|
+
# @param title [String] the title of page
|
30
91
|
def page_title(title)
|
31
92
|
return unless @current_action
|
32
93
|
|
33
94
|
@current_action.page_title = title
|
34
95
|
end
|
35
96
|
|
97
|
+
# Set page description for current action
|
98
|
+
# @param description [String] the description of page
|
36
99
|
def page_description(description)
|
37
100
|
return unless @current_action
|
38
101
|
|
39
102
|
@current_action.page_description = description
|
40
103
|
end
|
41
104
|
|
105
|
+
# Set kanban view for current action
|
106
|
+
# @param column_name [String] the name of column
|
107
|
+
# @param exclude [Array] the array of fields to exclude
|
108
|
+
# @param only [Array] the array of fields to include
|
42
109
|
def kanban_view(column_name, exclude: [], only: [])
|
43
110
|
return unless @current_action
|
44
111
|
|
@@ -47,19 +114,35 @@ module CmAdmin
|
|
47
114
|
@current_action.kanban_attr[:only] = only
|
48
115
|
end
|
49
116
|
|
117
|
+
# Set scopes for current action
|
118
|
+
# @param scopes [Array] the array of scopes
|
50
119
|
def scope_list(scopes = [])
|
51
120
|
return unless @current_action
|
52
121
|
|
53
122
|
@current_action.scopes = scopes
|
54
123
|
end
|
55
124
|
|
125
|
+
# Create a new tab on show page.
|
126
|
+
#
|
127
|
+
# @param tab_name [String] or [Symbol] the name of tab
|
128
|
+
# @param custom_action [String] the name of custom action
|
129
|
+
# @param associated_model [String] the name of associated model
|
130
|
+
# @param layout_type [String] the layout type of tab, +cm_association_index+, +cm_association_show+
|
131
|
+
# @param layout [String] the layout of tab
|
132
|
+
# @param partial [String] the partial path of tab
|
133
|
+
# @param display_if [Proc] A lambda that takes the current object and return true or false
|
134
|
+
#
|
135
|
+
# @example Creating a tab
|
136
|
+
# tab :comments, 'comment', associated_model: 'comments', layout_type: 'cm_association_index' do
|
137
|
+
# column :message
|
138
|
+
# end
|
56
139
|
def tab(tab_name, custom_action, associated_model: nil, layout_type: nil, layout: nil, partial: nil, display_if: nil, &block)
|
57
140
|
if custom_action.to_s == ''
|
58
141
|
@current_action = CmAdmin::Models::Action.find_by(self, name: 'show')
|
59
142
|
@available_tabs << CmAdmin::Models::Tab.new(tab_name, '', display_if, &block)
|
60
143
|
else
|
61
144
|
action = CmAdmin::Models::Action.new(name: custom_action.to_s, verb: :get, path: ':id/' + custom_action,
|
62
|
-
layout_type
|
145
|
+
layout_type:, layout:, partial:, child_records: associated_model,
|
63
146
|
action_type: :custom, display_type: :page, model_name: name)
|
64
147
|
@available_actions << action
|
65
148
|
@current_action = action
|
@@ -68,21 +151,53 @@ module CmAdmin
|
|
68
151
|
yield if block
|
69
152
|
end
|
70
153
|
|
154
|
+
# Create a new row on page or form.
|
155
|
+
# @param display_if [Proc] A lambda that takes the current object and return true or false
|
156
|
+
# @param html_attrs [Hash] A hash that contains html attributes
|
157
|
+
# @example Creating a row
|
158
|
+
# row(display_if: ->(current_object) { current_object.name == 'John' }, html_attrs: { class: 'row-class' }) do
|
159
|
+
# cm_section 'Details' do
|
160
|
+
# form_field :title, input_type: :string
|
161
|
+
# end
|
162
|
+
# end
|
71
163
|
def row(display_if: nil, html_attrs: nil, &block)
|
72
164
|
@available_fields[@current_action.name.to_sym] ||= []
|
73
165
|
@available_fields[@current_action.name.to_sym] << CmAdmin::Models::Row.new(@current_action, @model, display_if, html_attrs, &block)
|
74
166
|
end
|
75
167
|
|
168
|
+
# Create a new section on page or form.
|
169
|
+
# @param section_name [String] the name of section
|
170
|
+
# @param display_if [Proc] A lambda that takes the current object and return true or false
|
171
|
+
# @param col_size [Integer] the size of column according to grid view
|
172
|
+
# @param html_attrs [Hash] A hash that contains html attributes
|
173
|
+
|
174
|
+
# @example Creating a section
|
175
|
+
# cm_section('Basic Information', display_if: ->(current_object) { current_object.name == 'John' }, col_size: 6, html_attrs: { class: 'section-class' }) do
|
176
|
+
# field :title, input_type: :string
|
177
|
+
# end
|
76
178
|
def cm_section(section_name, display_if: nil, col_size: nil, html_attrs: nil, &block)
|
77
179
|
@available_fields[@current_action.name.to_sym] ||= []
|
78
180
|
@available_fields[@current_action.name.to_sym] << CmAdmin::Models::Section.new(section_name, @current_action, @model, display_if, html_attrs, col_size, &block)
|
79
181
|
end
|
80
182
|
|
81
|
-
#
|
183
|
+
# @deprecated Use {#cm_section} instead of this method
|
82
184
|
def cm_show_section(section_name, display_if: nil, html_attrs: nil, &block)
|
83
|
-
cm_section(section_name, display_if
|
185
|
+
cm_section(section_name, display_if:, html_attrs:, &block)
|
84
186
|
end
|
85
187
|
|
188
|
+
# Create a new column on index layout.
|
189
|
+
# @param field_name [String] the name of field
|
190
|
+
# @param field_type [Symbol] the type of field, +:string+, +:text+, +:image+, +:date+, +:rich_text+, +:time+, +:integer+, +:decimal+, +:custom+, +:datetime+, +:money+, +:money_with_symbol+, +:link+, +:association+, +:enum+, +:tag+, +:attachment+, +:drawer+
|
191
|
+
# @param header [String] the header of field
|
192
|
+
# @param format [String] the format of field for date field
|
193
|
+
# @param helper_method [Symbol] the helper method for field, should be defined in custom_helper.rb file, will take two arguments, +record+ and +field_name+
|
194
|
+
# @param height [Integer] the height of field for image field
|
195
|
+
# @param width [Integer] the width of field for image field
|
196
|
+
# @params custom_link [String] the custom link for field
|
197
|
+
# @params tag_class [Hash] the tag class for field, example: { approved: 'completed', draft: 'active-two', rejected: 'danger' }, this will add css class to tag
|
198
|
+
# @params display_if [Proc] A lambda that takes the current object and return true or false
|
199
|
+
# @example Creating a column
|
200
|
+
# column('name', field_type: :string)
|
86
201
|
def column(field_name, options = {})
|
87
202
|
@available_fields[@current_action.name.to_sym] ||= []
|
88
203
|
raise 'Only one column can be locked in a table.' if @available_fields[@current_action.name.to_sym].select { |x| x.lockable }.size > 0 && options[:lockable]
|
@@ -105,6 +220,10 @@ module CmAdmin
|
|
105
220
|
@available_fields[@current_action.name.to_sym] << CmAdmin::Models::Column.new(field_name, options)
|
106
221
|
end
|
107
222
|
|
223
|
+
# Get all columns for a model for index layout.
|
224
|
+
# @param exclude [Array] the array of fields to exclude
|
225
|
+
# @example Getting all columns
|
226
|
+
# all_db_columns(exclude: ['id'])
|
108
227
|
def all_db_columns(options = {})
|
109
228
|
field_names = instance_variable_get(:@ar_model)&.columns&.map { |x| x.name.to_sym }
|
110
229
|
if options.include?(:exclude) && field_names
|
@@ -116,49 +235,103 @@ module CmAdmin
|
|
116
235
|
end
|
117
236
|
end
|
118
237
|
|
119
|
-
#
|
120
|
-
#
|
121
|
-
#
|
122
|
-
#
|
123
|
-
#
|
124
|
-
#
|
125
|
-
#
|
126
|
-
#
|
127
|
-
#
|
238
|
+
# Create a new custom action for model
|
239
|
+
# @param name [String] the name of action
|
240
|
+
# @param page_title [String] the title of page
|
241
|
+
# @param page_description [String] the description of page
|
242
|
+
# @param display_name [String] the display name of action
|
243
|
+
# @param verb [String] the verb of action, +get+, +post+, +put+, +patch+ or +delete+
|
244
|
+
# @param layout [String] the layout of action
|
245
|
+
# @param layout_type [String] the layout type of action, +cm_association_index+, +cm_association_show+
|
246
|
+
# @param partial [String] the partial path of action
|
247
|
+
# @param path [String] the path of action
|
248
|
+
# @param display_type [Symbol] the display type of action, +:button+, +:modal+
|
249
|
+
# @param modal_configuration [Hash] the configuration of modal
|
250
|
+
# @param url_params [Hash] the url params of action
|
251
|
+
# @param display_if [Proc] A lambda that takes the current object and return true or false
|
252
|
+
# @param route_type [String] the route type of action, +member+, +collection+
|
253
|
+
# @param icon_name [String] the icon name of action, follow font-awesome icon name
|
254
|
+
# @example Creating a custom action with modal
|
255
|
+
# custom_action name: 'approve', route_type: 'member', verb: 'patch', icon_name: 'fa-regular fa-circle-check', path: ':id/approve', display_type: :modal, display_if: lambda(&:draft?), modal_configuration: { title: 'Approve Post', description: 'Are you sure you want approve this post', confirmation_text: 'Approve' } do
|
256
|
+
# post = ::Post.find(params[:id])
|
257
|
+
# post.approved!
|
258
|
+
# post
|
259
|
+
# end
|
260
|
+
# @example Creating a custom action with button
|
261
|
+
# custom_action name: 'approve', route_type: 'member', verb: 'patch', icon_name: 'fa-regular fa-circle-check', path: ':id/approve', display_type: :button, display_if: lambda(&:draft?) do
|
262
|
+
# post = ::Post.find(params[:id])
|
263
|
+
# post.approved!
|
264
|
+
# post
|
128
265
|
# end
|
129
|
-
|
130
|
-
def custom_action(name: nil, page_title: nil, page_description: nil, display_name: nil, verb: nil, layout: nil, layout_type: nil, partial: nil, path: nil, display_type: nil, modal_configuration: {}, url_params: {}, display_if: ->(arg) { true }, route_type: nil, icon_name: 'fa fa-th-large', &block)
|
266
|
+
def custom_action(name: nil, page_title: nil, page_description: nil, display_name: nil, verb: nil, layout: nil, layout_type: nil, partial: nil, path: nil, display_type: nil, modal_configuration: {}, url_params: {}, display_if: ->(_arg) { true }, route_type: nil, icon_name: 'fa fa-th-large', &block)
|
131
267
|
action = CmAdmin::Models::CustomAction.new(
|
132
|
-
page_title
|
133
|
-
name
|
134
|
-
layout_type
|
135
|
-
parent: current_action.name, display_type
|
136
|
-
action_type: :custom, route_type
|
137
|
-
model_name: self.name, url_params
|
268
|
+
page_title:, page_description:,
|
269
|
+
name:, display_name:, verb:, layout:,
|
270
|
+
layout_type:, partial:, path:,
|
271
|
+
parent: current_action.name, display_type:, display_if:,
|
272
|
+
action_type: :custom, route_type:, icon_name:, modal_configuration:,
|
273
|
+
model_name: self.name, url_params:, &block
|
138
274
|
)
|
139
275
|
@available_actions << action
|
140
|
-
# self.class.class_eval(&block)
|
141
276
|
end
|
142
277
|
|
143
|
-
|
278
|
+
# Create a new bulk action for model
|
279
|
+
# @param name [String] the name of action
|
280
|
+
# @param display_name [String] the display name of action
|
281
|
+
# @param display_if [Proc] A lambda that takes the current object and return true or false
|
282
|
+
# @param redirection_url [String] the redirection url of action
|
283
|
+
# @param icon_name [String] the icon name of action, follow font-awesome icon name
|
284
|
+
# @param verb [String] the verb of action, +get+, +post+, +put+, +patch+ or +delete+
|
285
|
+
# @param display_type [Symbol] the display type of action, +:page+, +:modal+
|
286
|
+
# @param modal_configuration [Hash] the configuration of modal
|
287
|
+
# @param route_type [String] the route type of action, +member+, +collection+
|
288
|
+
# @param partial [String] the partial path of action
|
289
|
+
# @example Creating a bulk action
|
290
|
+
# bulk_action name: 'approve', display_name: 'Approve', display_if: lambda { |arg| arg.draft? }, redirection_url: '/posts', icon_name: 'fa-regular fa-circle-check', verb: :patch, display_type: :modal, modal_configuration: { title: 'Approve Post', description: 'Are you sure you want approve this post', confirmation_text: 'Approve' } do
|
291
|
+
# posts = ::Post.where(id: params[:ids])
|
292
|
+
# posts.each(&:approved!)
|
293
|
+
# posts
|
294
|
+
# end
|
295
|
+
def bulk_action(name: nil, display_name: nil, display_if: ->(_arg) { true }, redirection_url: nil, icon_name: nil, verb: nil, display_type: nil, modal_configuration: {}, route_type: nil, partial: nil, &block)
|
144
296
|
bulk_action = CmAdmin::Models::BulkAction.new(
|
145
|
-
name
|
146
|
-
redirection_url
|
147
|
-
verb
|
297
|
+
name:, display_name:, display_if:, modal_configuration:,
|
298
|
+
redirection_url:, icon_name:, action_type: :bulk_action,
|
299
|
+
verb:, display_type:, route_type:, partial:, &block
|
148
300
|
)
|
149
301
|
@available_actions << bulk_action
|
150
302
|
end
|
151
303
|
|
304
|
+
# Create a new filter for model
|
305
|
+
# @param db_column_name [String] the name of column
|
306
|
+
# @param filter_type [String] the type of filter, +:date+, +:multi_select+, +:range+, +:search+, +:single_select+
|
307
|
+
# @param placeholder [String] the placeholder of filter
|
308
|
+
# @param helper_method [String] the helper method for filter, should be defined in custom_helper.rb file
|
309
|
+
# @param filter_with [Symbol] filter with scope name on model
|
310
|
+
# @param collection [Array] the collection of filter, use with single_select or multi_select
|
311
|
+
# @example Creating a filter
|
312
|
+
# filter('name', :search)
|
313
|
+
# filter('created_at', :date)
|
314
|
+
# filter('status', :single_select, collection: ['draft', 'published'])
|
315
|
+
# filter('status', :multi_select, helper_method: 'status_collection')
|
316
|
+
# filter('age', :range)
|
152
317
|
def filter(db_column_name, filter_type, options = {})
|
153
|
-
@filters << CmAdmin::Models::Filter.new(db_column_name
|
318
|
+
@filters << CmAdmin::Models::Filter.new(db_column_name:, filter_type:, options:)
|
154
319
|
end
|
155
320
|
|
321
|
+
# Set sort direction for filters
|
322
|
+
# @param direction [Symbol] the direction of sort, +:asc+, +:desc+
|
323
|
+
# @example Setting sort direction
|
324
|
+
# sort_direction(:asc)
|
156
325
|
def sort_direction(direction = :desc)
|
157
326
|
raise ArgumentError, "Select a valid sort direction like #{CmAdmin::Models::Action::VALID_SORT_DIRECTION.join(' or ')} instead of #{direction}" unless CmAdmin::Models::Action::VALID_SORT_DIRECTION.include?(direction.to_sym.downcase)
|
158
327
|
|
159
328
|
@current_action.sort_direction = direction.to_sym if @current_action
|
160
329
|
end
|
161
330
|
|
331
|
+
# Set sort column for filters
|
332
|
+
# @param column [Symbol] the column name
|
333
|
+
# @example Setting sort column
|
334
|
+
# sort_column(:created_at)
|
162
335
|
def sort_column(column = :created_at)
|
163
336
|
@current_action.sort_column = column.to_sym if @current_action
|
164
337
|
end
|
data/lib/cm_admin/models/row.rb
CHANGED
@@ -43,6 +43,12 @@ module CmAdmin
|
|
43
43
|
def cm_show_section(section_name, col_size: nil, display_if: nil, html_attrs: nil, &block)
|
44
44
|
cm_section(section_name, col_size: col_size, display_if: display_if, html_attrs: html_attrs, &block)
|
45
45
|
end
|
46
|
+
|
47
|
+
def nested_form_section(section_name, display_if: nil, col_size: nil, html_attrs: nil, &block)
|
48
|
+
nested_section = CmAdmin::Models::Section.new(section_name, @current_action, @cm_model, display_if, html_attrs, col_size, &block)
|
49
|
+
nested_section.parent_section = self
|
50
|
+
@row_fields << nested_section
|
51
|
+
end
|
46
52
|
end
|
47
53
|
end
|
48
54
|
end
|
data/lib/cm_admin/version.rb
CHANGED
@@ -87,6 +87,7 @@ module CmAdmin
|
|
87
87
|
ar_object.send(field.field_name).to_s.titleize
|
88
88
|
when :tag
|
89
89
|
tag_class = field.tag_class.dig("#{ar_object.send(field.field_name.to_s)}".to_sym).to_s
|
90
|
+
tag_class = 'neutral' if tag_class.blank?
|
90
91
|
content_tag :span, class: "status-tag #{tag_class}" do
|
91
92
|
ar_object.send(field.field_name).to_s.titleize.upcase
|
92
93
|
end
|
@@ -56,7 +56,7 @@ module CmAdmin
|
|
56
56
|
|
57
57
|
def cm_switch_field(form_obj, cm_field, value, required_class, _target_action, _ajax_url)\
|
58
58
|
content_tag :div, class: 'form-check form-switch' do
|
59
|
-
form_obj.check_box cm_field.field_name,
|
59
|
+
concat form_obj.check_box cm_field.field_name,
|
60
60
|
merge_wrapper_options(
|
61
61
|
{
|
62
62
|
class: "field-control form-check-input #{required_class}",
|
@@ -65,6 +65,7 @@ module CmAdmin
|
|
65
65
|
role: 'switch'
|
66
66
|
}, cm_field.html_attrs
|
67
67
|
)
|
68
|
+
concat content_tag(:div, cm_field.field_name.to_s.titleize, class: 'cm-switch-label')
|
68
69
|
end
|
69
70
|
end
|
70
71
|
|
@@ -272,18 +273,10 @@ module CmAdmin
|
|
272
273
|
if value.instance_of?(Array)
|
273
274
|
format_check_box_array(value, form_obj, cm_field, required_class, target_action)
|
274
275
|
else
|
275
|
-
|
276
|
-
|
277
|
-
|
278
|
-
|
279
|
-
disabled: cm_field.disabled.call(form_obj.object),
|
280
|
-
data: {
|
281
|
-
field_name: cm_field.field_name,
|
282
|
-
target_action: target_action&.name,
|
283
|
-
target_url: target_action&.name ? cm_admin.send("#{@model.name.underscore}_#{target_action&.name}_path") : ''
|
284
|
-
}
|
285
|
-
}, cm_field.html_attrs
|
286
|
-
)
|
276
|
+
content_tag :div, class: 'cm-checkbox-section' do
|
277
|
+
concat single_checkbox_tag(value, form_obj, cm_field, required_class, target_action)
|
278
|
+
concat content_tag(:div, cm_field.field_name.to_s.titleize, class: 'cm-checkbox-label')
|
279
|
+
end
|
287
280
|
end
|
288
281
|
end
|
289
282
|
|
@@ -302,8 +295,25 @@ module CmAdmin
|
|
302
295
|
end
|
303
296
|
end
|
304
297
|
|
298
|
+
def single_checkbox_tag(value, form_obj, cm_field, required_class, target_action)
|
299
|
+
content_tag :div, class: 'cm-checkbox-tag' do
|
300
|
+
concat form_obj.check_box cm_field.field_name,
|
301
|
+
merge_wrapper_options(
|
302
|
+
{
|
303
|
+
class: "cm-checkbox #{required_class} #{target_action.present? ? 'linked-field-request' : ''}",
|
304
|
+
disabled: cm_field.disabled.call(form_obj.object),
|
305
|
+
data: {
|
306
|
+
field_name: cm_field.field_name,
|
307
|
+
target_action: target_action&.name,
|
308
|
+
target_url: target_action&.name ? cm_admin.send("#{@model.name.underscore}_#{target_action&.name}_path") : ''
|
309
|
+
}
|
310
|
+
}, cm_field.html_attrs
|
311
|
+
)
|
312
|
+
end
|
313
|
+
end
|
314
|
+
|
305
315
|
def format_check_box_tag(val, form_obj, cm_field, required_class, target_action)
|
306
|
-
content_tag :div, class: 'cm-
|
316
|
+
content_tag :div, class: 'cm-checkbox-tag' do
|
307
317
|
if val.present?
|
308
318
|
concat form_obj.text_field cm_field.field_name, name: "#{@model.name.underscore}[#{cm_field.field_name}][]", value: '0', hidden: true, disabled: 'disabled'
|
309
319
|
else
|
@@ -74,7 +74,11 @@ module CmAdmin
|
|
74
74
|
rows.each do |row|
|
75
75
|
concat(content_tag(:div, class: 'row') do
|
76
76
|
row.row_fields.each do |field|
|
77
|
-
|
77
|
+
if field.is_a?(CmAdmin::Models::Section)
|
78
|
+
concat set_nested_section_form_fields(resource, form_obj, Array(field))
|
79
|
+
else
|
80
|
+
concat set_form_field(resource, form_obj, field)
|
81
|
+
end
|
78
82
|
end
|
79
83
|
end)
|
80
84
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: cm-admin
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.5.
|
4
|
+
version: 1.5.41
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Michael
|
@@ -14,7 +14,7 @@ authors:
|
|
14
14
|
autorequire:
|
15
15
|
bindir: exe
|
16
16
|
cert_chain: []
|
17
|
-
date: 2024-
|
17
|
+
date: 2024-08-01 00:00:00.000000000 Z
|
18
18
|
dependencies:
|
19
19
|
- !ruby/object:Gem::Dependency
|
20
20
|
name: caxlsx_rails
|
@@ -175,6 +175,7 @@ files:
|
|
175
175
|
- ".github/ISSUE_TEMPLATE/bug_report.md"
|
176
176
|
- ".github/ISSUE_TEMPLATE/config.yml"
|
177
177
|
- ".github/ISSUE_TEMPLATE/feature_request.md"
|
178
|
+
- ".github/workflows/deploy-yard-docs.yml"
|
178
179
|
- ".github/workflows/linters.yml"
|
179
180
|
- ".github/workflows/release-gem.yml"
|
180
181
|
- ".gitignore"
|
@@ -184,6 +185,7 @@ files:
|
|
184
185
|
- ".stylelintrc.json"
|
185
186
|
- ".travis.yml"
|
186
187
|
- ".vscode/settings.json"
|
188
|
+
- CNAME
|
187
189
|
- CODE_OF_CONDUCT.md
|
188
190
|
- Gemfile
|
189
191
|
- Gemfile.lock
|
@@ -205,6 +207,7 @@ files:
|
|
205
207
|
- app/assets/javascripts/cm_admin/bulk_actions.js
|
206
208
|
- app/assets/javascripts/cm_admin/cocoon.js
|
207
209
|
- app/assets/javascripts/cm_admin/custom.js
|
210
|
+
- app/assets/javascripts/cm_admin/custom_action.js
|
208
211
|
- app/assets/javascripts/cm_admin/exports.js
|
209
212
|
- app/assets/javascripts/cm_admin/filters.js
|
210
213
|
- app/assets/javascripts/cm_admin/form_validation.js
|