-
-
Notifications
You must be signed in to change notification settings - Fork 281
feature: add bulk update #3695
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
feature: add bulk update #3695
Changes from 11 commits
0185150
633f97d
83e2247
0f85794
fa8c558
7a67ccd
7d35c46
ade1422
a2be7fb
0278fca
750dd25
ec17628
3d3b87d
669edce
154b062
fd56fe0
182c522
c8f635a
b7f529b
aaa324e
095bacd
4166a5f
859296e
d8213a8
9a74b8a
0fa296b
94bfe9a
8321f59
40af2d8
1764142
9ae1366
f40706d
2146fbd
b0ea750
c675317
04fae6b
4739bec
19eb3fb
d6faf95
6710069
8686622
589cf6d
a9fd0e7
fb8ec92
69fda6a
017946a
385552c
657c5ca
9553272
42f5da7
f9d828e
d203f7b
88fa6ed
d4a0715
8c9a874
58e9b38
977d046
9d7ef48
495b762
e6f1feb
65a1524
c87da90
6deb60d
39070f8
d09bbb7
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -9,6 +9,14 @@ class Avo::Views::ResourceEditComponent < Avo::ResourceComponent | |
prop :view, default: Avo::ViewInquirer.new(:edit).freeze | ||
prop :display_breadcrumbs, default: true, reader: :public | ||
|
||
attr_reader :query | ||
|
||
def initialize(resource:, query: nil, prefilled_fields: nil, **args) | ||
@query = query | ||
@prefilled_fields = prefilled_fields | ||
super(resource: resource, **args) | ||
end | ||
Nevelito marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
def after_initialize | ||
@display_breadcrumbs = @reflection.blank? && display_breadcrumbs | ||
end | ||
|
@@ -18,6 +26,8 @@ def title | |
end | ||
|
||
def back_path | ||
return helpers.resources_path(resource: @resource) if params[:controller] == "avo/bulk_update" | ||
|
||
# The `return_to` param takes precedence over anything else. | ||
return params[:return_to] if params[:return_to].present? | ||
|
||
|
@@ -76,13 +86,19 @@ def is_edit? | |
end | ||
|
||
def form_method | ||
return :put if is_edit? | ||
return :put if is_edit? && params[:controller] != "avo/bulk_update" | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think we should use the put as well for bulk updates, any argument why we should use post? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. you can test it, when it is using put there are problems and records will not update. the case is that it have to update min. two records There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I tested and works well, committed here let me know if you see any limitation and if we should revert this commit |
||
|
||
:post | ||
end | ||
|
||
def model | ||
@resource.record | ||
end | ||
|
||
def form_url | ||
if is_edit? | ||
if params[:controller] == "avo/bulk_update" | ||
helpers.handle_bulk_update_path(resource_name: @resource.name, query: @query) | ||
elsif is_edit? | ||
helpers.resource_path( | ||
record: @resource.record, | ||
resource: @resource | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -3,6 +3,7 @@ | |
class Avo::Views::ResourceIndexComponent < Avo::ResourceComponent | ||
include Avo::ResourcesHelper | ||
include Avo::ApplicationHelper | ||
include Avo::Concerns::ChecksShowAuthorization | ||
|
||
prop :resource | ||
prop :resources | ||
|
@@ -33,6 +34,20 @@ def view_type | |
@index_params[:view_type] | ||
end | ||
|
||
def bulk_edit_path | ||
# Add the `view` param to let Avo know where to redirect back when the user clicks the `Cancel` button. | ||
args = {via_view: "index"} | ||
|
||
if @parent_record.present? | ||
args = { | ||
via_resource_class: parent_resource.class.to_s, | ||
Paul-Bob marked this conversation as resolved.
Show resolved
Hide resolved
|
||
via_record_id: @parent_record.to_param | ||
} | ||
end | ||
|
||
helpers.edit_bulk_update_path(resource: @resource, **args) | ||
end | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This method appears to be unused, shouldn't we incorporate it within There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. you right, fixed |
||
|
||
def available_view_types | ||
@index_params[:available_view_types] | ||
end | ||
|
@@ -154,6 +169,16 @@ def render_dynamic_filters_button | |
end | ||
end | ||
|
||
def render_bulk_update_button | ||
a_link helpers.edit_bulk_update_path(resource_name: @resource.name, id: 4), | ||
style: :primary, | ||
color: :primary, | ||
icon: "avo/edit", | ||
form_class: "flex flex-col sm:flex-row sm:inline-flex" do | ||
"Bulk update" | ||
end | ||
end | ||
|
||
def scopes_list | ||
Avo::Advanced::Scopes::ListComponent.new( | ||
scopes: @scopes, | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,152 @@ | ||
module Avo | ||
class BulkUpdateController < ResourcesController | ||
before_action :set_query, only: [:edit, :handle] | ||
before_action :set_fields, only: [:edit, :handle] | ||
|
||
def edit | ||
@prefilled_fields = prefill_fields(@query, @fields) | ||
@record = @resource.model_class.new(@prefilled_fields.transform_values { |v| v.nil? ? nil : v }) | ||
|
||
@resource.record = @record | ||
render Avo::Views::ResourceEditComponent.new( | ||
resource: @resource, | ||
query: @query, | ||
prefilled_fields: @prefilled_fields | ||
) | ||
end | ||
|
||
def handle | ||
if params_to_apply.blank? | ||
flash[:warning] = t("avo.no_changes_made") | ||
redirect_to after_bulk_update_path | ||
return | ||
end | ||
|
||
updated_count, failed_records = update_records | ||
|
||
if failed_records.empty? | ||
flash[:notice] = t("avo.bulk_update_success", count: updated_count) | ||
else | ||
error_messages = failed_records.flat_map { |fr| fr[:errors] }.uniq | ||
flash[:error] = t("avo.bulk_update_failure", count: failed_records.count, errors: error_messages.join(", ")) | ||
end | ||
|
||
redirect_to after_bulk_update_path | ||
end | ||
|
||
private | ||
|
||
def params_to_apply | ||
Nevelito marked this conversation as resolved.
Show resolved
Hide resolved
|
||
prefilled_params = params[:prefilled] || {} | ||
current_params = current_resource_params | ||
progress_fields = progress_bar_fields | ||
|
||
current_params.reject do |key, value| | ||
key_sym = key.to_sym | ||
prefilled_value = prefilled_params[key_sym] | ||
|
||
progress_field_with_default?(progress_fields, key_sym, prefilled_value, value) || | ||
prefilled_value.to_s == value.to_s | ||
end | ||
end | ||
|
||
def current_resource_params | ||
resource_key = @resource_name.downcase.to_sym | ||
params[resource_key] || {} | ||
end | ||
|
||
def progress_bar_fields | ||
@resource.get_field_definitions | ||
.select { |field| field.is_a?(Avo::Fields::ProgressBarField) } | ||
Check failure on line 60 in app/controllers/avo/bulk_update_controller.rb
|
||
.map(&:id) | ||
Check failure on line 61 in app/controllers/avo/bulk_update_controller.rb
|
||
.map(&:to_sym) | ||
Check failure on line 62 in app/controllers/avo/bulk_update_controller.rb
|
||
end | ||
|
||
def progress_field_with_default?(progress_fields, key_sym, prefilled_value, value) | ||
progress_fields.include?(key_sym) && prefilled_value == "" && value.to_s == "50" | ||
end | ||
|
||
def update_records | ||
Nevelito marked this conversation as resolved.
Show resolved
Hide resolved
Nevelito marked this conversation as resolved.
Show resolved
Hide resolved
Nevelito marked this conversation as resolved.
Show resolved
Hide resolved
|
||
updated_count = 0 | ||
failed_records = [] | ||
|
||
@query.each do |record| | ||
update_record(record, params_to_apply) | ||
if record.save | ||
updated_count += 1 | ||
else | ||
add_failed_record(failed_records, record) | ||
end | ||
rescue => e | ||
add_failed_record(failed_records, record, e.message) | ||
end | ||
|
||
[updated_count, failed_records] | ||
end | ||
|
||
def update_record(record, params_to_apply) | ||
params_to_apply.each do |key, value| | ||
record.public_send(:"#{key}=", value) | ||
rescue => e | ||
log_field_assignment_error(key, e.message) | ||
end | ||
|
||
@resource.fill_record(record, params) | ||
end | ||
|
||
def log_field_assignment_error(key, error_message) | ||
puts "Błąd przypisywania pola #{key}: #{error_message}" | ||
end | ||
|
||
def add_failed_record(failed_records, record, error_message = nil) | ||
errors = error_message ? [error_message] : record.errors.full_messages | ||
failed_records << { record: record, errors: errors } | ||
Check failure on line 103 in app/controllers/avo/bulk_update_controller.rb
|
||
end | ||
|
||
def after_bulk_update_path | ||
resources_path(resource: @resource) | ||
end | ||
|
||
def prefill_fields(records, fields) | ||
fields.each_key.with_object({}) do |field_name, prefilled| | ||
values = records.map { |record| record.public_send(field_name) } | ||
values.uniq! | ||
prefilled[field_name] = (values.size == 1 ? values.first : nil) | ||
Check failure on line 114 in app/controllers/avo/bulk_update_controller.rb
|
||
end | ||
end | ||
|
||
def set_query | ||
Nevelito marked this conversation as resolved.
Show resolved
Hide resolved
|
||
@query = if params[:query].present? | ||
@resource.find_record(params[:query], params: params) | ||
Check failure on line 120 in app/controllers/avo/bulk_update_controller.rb
|
||
else | ||
Check failure on line 121 in app/controllers/avo/bulk_update_controller.rb
|
||
find_records_by_resource_ids | ||
Check failure on line 122 in app/controllers/avo/bulk_update_controller.rb
|
||
end | ||
end | ||
|
||
def find_records_by_resource_ids | ||
resource_ids = action_params[:fields]&.dig(:avo_resource_ids)&.split(",") || [] | ||
decrypted_query || (resource_ids.any? ? @resource.find_record(resource_ids, params: params) : []) | ||
end | ||
|
||
def set_fields | ||
if @query.blank? | ||
flash[:error] = I18n.t("avo.bulk_update_no_records") | ||
redirect_to after_bulk_update_path | ||
else | ||
@fields = @query.first.attributes.keys.index_with { nil } | ||
end | ||
end | ||
|
||
def action_params | ||
@action_params ||= params.permit(:authenticity_token, fields: {}) | ||
end | ||
|
||
def decrypted_query | ||
encrypted_query = action_params[:fields]&.dig(:avo_selected_query) || params[:query] | ||
|
||
return if encrypted_query.blank? | ||
|
||
Avo::Services::EncryptionService.decrypt(message: encrypted_query, purpose: :select_all, serializer: Marshal) | ||
end | ||
end | ||
end |
Uh oh!
There was an error while loading. Please reload this page.