ez-resources 0.1.0
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 +7 -0
- data/MIT-LICENSE +20 -0
- data/README.md +106 -0
- data/Rakefile +34 -0
- data/app/cells/ez/resources/application_cell.rb +40 -0
- data/app/cells/ez/resources/collection/table.slim +42 -0
- data/app/cells/ez/resources/collection_cell.rb +115 -0
- data/app/cells/ez/resources/field/show.slim +2 -0
- data/app/cells/ez/resources/field_cell.rb +41 -0
- data/app/cells/ez/resources/form/show.slim +16 -0
- data/app/cells/ez/resources/form_cell.rb +33 -0
- data/app/cells/ez/resources/search/show.slim +20 -0
- data/app/cells/ez/resources/search_cell.rb +43 -0
- data/lib/ez/resources.rb +21 -0
- data/lib/ez/resources/engine.rb +14 -0
- data/lib/ez/resources/manager.rb +114 -0
- data/lib/ez/resources/manager/action.rb +17 -0
- data/lib/ez/resources/manager/config.rb +150 -0
- data/lib/ez/resources/manager/config_store.rb +48 -0
- data/lib/ez/resources/manager/dsl.rb +22 -0
- data/lib/ez/resources/manager/field.rb +46 -0
- data/lib/ez/resources/manager/fields.rb +31 -0
- data/lib/ez/resources/manager/hook.rb +16 -0
- data/lib/ez/resources/manager/hooks.rb +38 -0
- data/lib/ez/resources/railtie.rb +8 -0
- data/lib/ez/resources/version.rb +7 -0
- data/lib/tasks/ez/resources_tasks.rake +5 -0
- metadata +327 -0
@@ -0,0 +1,20 @@
|
|
1
|
+
= div_for 'collection-search-container'
|
2
|
+
= div_for 'collection-search-panel'
|
3
|
+
h4 = t('phrases.search_and_filter')
|
4
|
+
|
5
|
+
= div_for 'collection-search-panel-form'
|
6
|
+
= simple_form_for model.search, url: model.path_for(action: :index), method: :get do |f|
|
7
|
+
- model.collection_columns.each do |field|
|
8
|
+
- if field.searchable && SEARCHABLE_FIELDS.include?(field.type)
|
9
|
+
= div_for 'collection-search-panel-field'
|
10
|
+
= f.input field_name(field),
|
11
|
+
label: field_label(field),
|
12
|
+
required: false,
|
13
|
+
as: cast_field_type(field.type),
|
14
|
+
collection: field.collection,
|
15
|
+
include_blank: true
|
16
|
+
|
17
|
+
= f.submit t('actions.apply'), class: css_for('collection-search-panel-submit-button')
|
18
|
+
|
19
|
+
- if model.params[:q]
|
20
|
+
= link_to t('actions.reset'), model.path_for(action: :index), class: css_for('collection-search-panel-reset-link')
|
@@ -0,0 +1,43 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Ez
|
4
|
+
module Resources
|
5
|
+
class SearchCell < ApplicationCell
|
6
|
+
SEARCHABLE_FIELDS = %i[string association select link boolean].freeze
|
7
|
+
|
8
|
+
form
|
9
|
+
|
10
|
+
def cast_field_type(type)
|
11
|
+
case type
|
12
|
+
when :link then :string
|
13
|
+
when :boolean then :select
|
14
|
+
when :association then :string
|
15
|
+
else
|
16
|
+
type
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def field_name(field)
|
21
|
+
if association?(field)
|
22
|
+
search_key(field.name, field.search_suffix, field.options.fetch(:association))
|
23
|
+
else
|
24
|
+
search_key(field.name, field.search_suffix)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def field_label(field)
|
29
|
+
"#{field.title} (#{t "search.suffix.#{field.search_suffix}"})"
|
30
|
+
end
|
31
|
+
|
32
|
+
private
|
33
|
+
|
34
|
+
def search_key(name, search_suffix, association_prefix = nil)
|
35
|
+
[association_prefix, name, search_suffix].compact.join('_').to_sym
|
36
|
+
end
|
37
|
+
|
38
|
+
def association?(field)
|
39
|
+
field.type == :association && field.options[:association].present?
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
data/lib/ez/resources.rb
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'ez/resources/engine'
|
4
|
+
require 'ez/resources/manager'
|
5
|
+
|
6
|
+
require 'ez/configurator'
|
7
|
+
module Ez
|
8
|
+
module Resources
|
9
|
+
include Ez::Configurator
|
10
|
+
|
11
|
+
configure do |config|
|
12
|
+
config.ignore_fields = %w[id created_at updated_at]
|
13
|
+
config.i18n_scope = 'ez_resources'
|
14
|
+
end
|
15
|
+
|
16
|
+
BaseError = Class.new(StandardError)
|
17
|
+
GuessingError = Class.new(BaseError)
|
18
|
+
ConfigurationError = Class.new(BaseError)
|
19
|
+
UnavailableError = Class.new(BaseError)
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,114 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'ez/resources/manager/dsl'
|
4
|
+
require 'ez/resources/manager/config'
|
5
|
+
|
6
|
+
module Ez
|
7
|
+
module Resources
|
8
|
+
module Manager
|
9
|
+
include ::Cell::RailsExtensions::ActionController
|
10
|
+
|
11
|
+
def self.included(base)
|
12
|
+
base.extend(DSL)
|
13
|
+
|
14
|
+
base.rescue_from UnavailableError do
|
15
|
+
if Ez::Resources.config.ui_failed_hook
|
16
|
+
instance_exec(&Ez::Resources.config.ui_failed_hook)
|
17
|
+
else
|
18
|
+
flash[:alert] = t('messages.unavailable', scope: Ez::Resources.config.i18n_scope)
|
19
|
+
redirect_to '/'
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def index
|
25
|
+
Manager::Hooks.can!(:can_list?, ez_resource_config)
|
26
|
+
|
27
|
+
ez_resource_view :collection, ez_resource_config
|
28
|
+
end
|
29
|
+
|
30
|
+
def show
|
31
|
+
Manager::Hooks.can!(:can_read?, ez_resource_config)
|
32
|
+
|
33
|
+
if ez_resource_config.show_action_renders_form?
|
34
|
+
ez_resource_view :form, ez_resource_config
|
35
|
+
else
|
36
|
+
# TODO: render show cell
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
def new
|
41
|
+
Manager::Hooks.can!(:can_create?, ez_resource_config)
|
42
|
+
|
43
|
+
ez_resource_view :form, ez_resource_config
|
44
|
+
end
|
45
|
+
|
46
|
+
def create
|
47
|
+
Manager::Hooks.can!(:can_create?, ez_resource_config)
|
48
|
+
|
49
|
+
@ez_resource = ez_resource_config.model.new(ez_resource_params)
|
50
|
+
|
51
|
+
if @ez_resource.save
|
52
|
+
flash[:notice] = t('messages.created',
|
53
|
+
resource_name: ez_resource_config.resource_name,
|
54
|
+
scope: Ez::Resources.config.i18n_scope)
|
55
|
+
|
56
|
+
redirect_to ez_resource_config.path_for(action: :index)
|
57
|
+
else
|
58
|
+
flash[:alert] = t('messages.invalid',
|
59
|
+
resource_name: ez_resource_config.resource_name,
|
60
|
+
scope: Ez::Resources.config.i18n_scope)
|
61
|
+
|
62
|
+
ez_resource_view :form, ez_resource_config
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
def edit
|
67
|
+
Manager::Hooks.can!(:can_update?, ez_resource_config, ez_resource_config.data)
|
68
|
+
|
69
|
+
ez_resource_view :form, ez_resource_config
|
70
|
+
end
|
71
|
+
|
72
|
+
def update
|
73
|
+
Manager::Hooks.can!(:can_update?, ez_resource_config, ez_resource_config.data)
|
74
|
+
|
75
|
+
@ez_resource = ez_resource_config.data
|
76
|
+
|
77
|
+
if @ez_resource.update(ez_resource_params)
|
78
|
+
flash[:notice] = t('messages.updated',
|
79
|
+
resource_name: ez_resource_config.resource_name,
|
80
|
+
scope: Ez::Resources.config.i18n_scope)
|
81
|
+
|
82
|
+
redirect_to ez_resource_config.path_for(action: :index)
|
83
|
+
else
|
84
|
+
flash[:alert] = t('messages.invalid',
|
85
|
+
resource_name: ez_resource_config.resource_name,
|
86
|
+
scope: Ez::Resources.config.i18n_scope)
|
87
|
+
|
88
|
+
ez_resource_view :form, ez_resource_config
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
# TODO: Later
|
93
|
+
def destroy; end
|
94
|
+
|
95
|
+
private
|
96
|
+
|
97
|
+
def ez_resource_view(cell_name, *args)
|
98
|
+
render html: cell("ez/resources/#{cell_name}", *args), layout: true
|
99
|
+
end
|
100
|
+
|
101
|
+
def ez_resource_params
|
102
|
+
params.require(:ez_resource).permit(ez_resource_config.form_fields.map(&:name))
|
103
|
+
end
|
104
|
+
|
105
|
+
def ez_resource_config
|
106
|
+
Config.new(
|
107
|
+
controller: self,
|
108
|
+
dsl_config: self.class.ez_resource_config_store,
|
109
|
+
data: @ez_resource
|
110
|
+
)
|
111
|
+
end
|
112
|
+
end
|
113
|
+
end
|
114
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Ez
|
4
|
+
module Resources
|
5
|
+
module Manager
|
6
|
+
class Action
|
7
|
+
attr_reader :name, :builder, :options
|
8
|
+
|
9
|
+
def initialize(name, builder, options = {})
|
10
|
+
@name = name
|
11
|
+
@builder = builder
|
12
|
+
@options = options
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,150 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Ez
|
4
|
+
module Resources
|
5
|
+
module Manager
|
6
|
+
class Config
|
7
|
+
include Pagy::Backend
|
8
|
+
|
9
|
+
DEFAULT_ACTIONS = %i[index show new create edit update destroy].freeze
|
10
|
+
|
11
|
+
attr_reader :paginator, :search, :controller
|
12
|
+
|
13
|
+
def initialize(controller:, dsl_config:, data: nil)
|
14
|
+
@controller = controller
|
15
|
+
@dsl_config = dsl_config
|
16
|
+
@data = data
|
17
|
+
end
|
18
|
+
|
19
|
+
def data
|
20
|
+
@data ||= case controller.action_name
|
21
|
+
when 'index' then collection
|
22
|
+
when 'new' then new_resource
|
23
|
+
when 'show' then resource
|
24
|
+
when 'edit' then resource
|
25
|
+
when 'update' then resource
|
26
|
+
else
|
27
|
+
raise ConfigurationError, "Invalid action #{controller.action_name}"
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def total_count
|
32
|
+
@total_count ||= model.count
|
33
|
+
end
|
34
|
+
|
35
|
+
def model
|
36
|
+
@model ||= dsl_config.model || controller_name.classify.constantize
|
37
|
+
rescue NameError
|
38
|
+
raise GuessingError, "Ez::Resources tried to guess model name as #{controller_name.classify} but constant is missing. You can define model class explicitly with :model options"
|
39
|
+
end
|
40
|
+
|
41
|
+
def actions
|
42
|
+
@actions ||= dsl_config.actions || DEFAULT_ACTIONS
|
43
|
+
end
|
44
|
+
|
45
|
+
def show_action_renders_form?
|
46
|
+
@show_action_renders_form ||= dsl_config.show_action_renders_form
|
47
|
+
end
|
48
|
+
|
49
|
+
def hooks
|
50
|
+
@hooks ||= dsl_config.hooks || []
|
51
|
+
end
|
52
|
+
|
53
|
+
def resource_label
|
54
|
+
@resource_label ||= dsl_config.resource_label || :id
|
55
|
+
end
|
56
|
+
|
57
|
+
def resource_name
|
58
|
+
@resource_name ||= controller_name.classify
|
59
|
+
end
|
60
|
+
|
61
|
+
def resources_name
|
62
|
+
@resources_name ||= dsl_config.resources_name || resource_name.pluralize
|
63
|
+
end
|
64
|
+
|
65
|
+
def paginate_collection?
|
66
|
+
@paginate_collection ||= dsl_config.paginate_collection != false
|
67
|
+
end
|
68
|
+
|
69
|
+
def collection_search?
|
70
|
+
@collection_search ||= dsl_config.collection_search != false
|
71
|
+
end
|
72
|
+
|
73
|
+
def collection_views
|
74
|
+
@collection_views ||= dsl_config.collection_views || []
|
75
|
+
end
|
76
|
+
|
77
|
+
def collection_columns
|
78
|
+
@collection_columns ||= dsl_config.collection_columns || model.columns.map do |column|
|
79
|
+
Ez::Resources::Manager::Field.new(
|
80
|
+
name: column.name,
|
81
|
+
title: column.name.to_s.humanize,
|
82
|
+
type: column.sql_type_metadata.type
|
83
|
+
)
|
84
|
+
end.reject { |col| Ez::Resources.config.ignore_fields.include?(col.name) }
|
85
|
+
end
|
86
|
+
|
87
|
+
def collection_actions
|
88
|
+
@colleciton_actions ||= dsl_config.collection_actions || []
|
89
|
+
end
|
90
|
+
|
91
|
+
def form_fields
|
92
|
+
@form_fields ||= dsl_config.form_fields || collection_columns || []
|
93
|
+
end
|
94
|
+
|
95
|
+
def path_for(action:, id: nil, params: nil)
|
96
|
+
if id
|
97
|
+
controller.url_for(action: action, id: id, only_path: true)
|
98
|
+
elsif params
|
99
|
+
controller.url_for(action: action, **params, only_path: true)
|
100
|
+
else
|
101
|
+
controller.url_for(action: action, only_path: true)
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
def params
|
106
|
+
@params ||= controller.params
|
107
|
+
end
|
108
|
+
|
109
|
+
private
|
110
|
+
|
111
|
+
attr_reader :dsl_config
|
112
|
+
|
113
|
+
def collection
|
114
|
+
return paginated_collection if paginate_collection?
|
115
|
+
|
116
|
+
@collection ||= if dsl_config.collection_query
|
117
|
+
dsl_config.collection_query.call(model, controller)
|
118
|
+
else
|
119
|
+
model.all
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
123
|
+
def paginated_collection
|
124
|
+
@search = model.ransack(params[:q])
|
125
|
+
|
126
|
+
@paginated_collection ||= if dsl_config.collection_query
|
127
|
+
pagy, paginated_collection = pagy dsl_config.collection_query.call(search.result, controller)
|
128
|
+
else
|
129
|
+
pagy, paginated_collection = pagy search.result.includes(dsl_config.includes)
|
130
|
+
end
|
131
|
+
|
132
|
+
@paginator = pagy
|
133
|
+
paginated_collection
|
134
|
+
end
|
135
|
+
|
136
|
+
def new_resource
|
137
|
+
@new_resource ||= model.new
|
138
|
+
end
|
139
|
+
|
140
|
+
def resource
|
141
|
+
@resource ||= model.find(controller.params[:id])
|
142
|
+
end
|
143
|
+
|
144
|
+
def controller_name
|
145
|
+
@controller_name ||= controller.controller_name
|
146
|
+
end
|
147
|
+
end
|
148
|
+
end
|
149
|
+
end
|
150
|
+
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'ez/resources/manager/fields'
|
4
|
+
require 'ez/resources/manager/hooks'
|
5
|
+
|
6
|
+
module Ez
|
7
|
+
module Resources
|
8
|
+
module Manager
|
9
|
+
class ConfigStore
|
10
|
+
attr_accessor :actions, :model, :paginate_collection, :resource_name, :resource_label, :resources_name,
|
11
|
+
:collection_columns, :collection_query, :collection_search, :show_action_renders_form, :includes,
|
12
|
+
:collection_views
|
13
|
+
|
14
|
+
def collection_columns(&block)
|
15
|
+
if block_given?
|
16
|
+
@collection_columns = Fields.new(&block).fields
|
17
|
+
else
|
18
|
+
@collection_columns
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
def collection_actions(&block)
|
23
|
+
if block_given?
|
24
|
+
@collection_actions = Fields.new(&block).actions
|
25
|
+
else
|
26
|
+
@collection_actions
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def form_fields(&block)
|
31
|
+
if block_given?
|
32
|
+
@form_fields = Fields.new(&block).fields
|
33
|
+
else
|
34
|
+
@form_fields
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
def hooks(&block)
|
39
|
+
if block_given?
|
40
|
+
@hooks = Hooks.new(&block).hooks
|
41
|
+
else
|
42
|
+
@hooks
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'ez/resources/manager/config_store'
|
4
|
+
|
5
|
+
module Ez
|
6
|
+
module Resources
|
7
|
+
module Manager
|
8
|
+
module DSL
|
9
|
+
def ez_resource_config_store
|
10
|
+
@ez_resource_config_store || Ez::Resources::Manager::ConfigStore.new
|
11
|
+
end
|
12
|
+
|
13
|
+
def ez_resource(&block)
|
14
|
+
config = Ez::Resources::Manager::ConfigStore.new
|
15
|
+
block.call(config)
|
16
|
+
|
17
|
+
@ez_resource_config_store = config
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|