-
-
Notifications
You must be signed in to change notification settings - Fork 256
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
Create a belongs_to
record from the associated record screen
#1876
Merged
adrianthedev
merged 20 commits into
avo-hq:main
from
sdcoffey:feature/create_via_belongs_to_field
Oct 20, 2023
Merged
Changes from 9 commits
Commits
Show all changes
20 commits
Select commit
Hold shift + click to select a range
26126ad
wip
sdcoffey d292661
move keep_modal_open view to shared partial
sdcoffey b9c7b9e
update base controller to show modal when creating via a belongs_to r…
sdcoffey b7754fd
WIP add create button to belongs_to edit field with return-handling c…
sdcoffey afc20c3
hook up panel back button from modal
sdcoffey c3a958b
pass params[:via_belongs_to_resource_class] through #create
sdcoffey c913b65
add WIP system spec for belongs_to cases
sdcoffey 6b3effb
update specs to cover polymorphic and searchable polymorphic belongs_to
sdcoffey 6336054
style and cleanup
sdcoffey f68c175
decompose long method in reload_belongs_to_controller
sdcoffey 368533b
fixup! decompose long method in reload_belongs_to_controller
sdcoffey 0454a34
remove change to .gitignore
sdcoffey 25f91b6
remove usage of class_names
sdcoffey 1e44d70
rename _keep_modal_open -> _flash_alerts
sdcoffey 642136a
ensure validation errors are still shown after create failure
sdcoffey 540a92b
add in_modal param to PanelComponent to allow better form display ins…
sdcoffey c94dc00
fixup! add in_modal param to PanelComponent to allow better form disp…
sdcoffey 21042ec
use to_param/find_record instead of bare id
sdcoffey 528432c
optionally render heading and content in modal
sdcoffey 8427405
tweaks
adrianthedev File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -73,3 +73,4 @@ app/assets/builds | |
|
||
TAGS | ||
brakeman_results.html | ||
.idea/* |
214 changes: 118 additions & 96 deletions
214
app/components/avo/fields/belongs_to_field/edit_component.html.erb
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,115 +1,137 @@ | ||
<% if is_polymorphic? %> | ||
<% | ||
# Set the model keys so we can pass them over | ||
model_keys = @field.types.map do |type| | ||
resource = Avo::App.get_resource_by_model_name(type.to_s) | ||
[type.to_s, resource.model_key] | ||
end.to_h | ||
%> | ||
<div class="divide-y" | ||
data-controller="belongs-to-field" | ||
data-searchable="<%= @field.searchable %>" | ||
data-association="<%= @field.id %>" | ||
data-association-class="<%= @field&.target_resource&.model_class || nil %>" | ||
> | ||
<%= field_wrapper **field_wrapper_args, help: @field.polymorphic_help || '' do %> | ||
<%= @form.select @field.type_input_foreign_key, @field.types.map { |type| [::Avo::App.get_resource_by_model_name(type.to_s).name, type.to_s] }, | ||
{ | ||
value: @field.value, | ||
include_blank: @field.placeholder, | ||
}, | ||
{ | ||
class: classes("w-full"), | ||
data: { | ||
**@field.get_html(:data, view: view, element: :input), | ||
action: "change->belongs-to-field#changeType #{field_html_action}", | ||
'belongs-to-field-target': "select", | ||
}, | ||
disabled: disabled | ||
} | ||
<div data-controller="reload-belongs-to-field" | ||
data-action="turbo:before-stream-render@document->reload-belongs-to-field#beforeStreamRender" | ||
data-reload-belongs-to-field-polymorphic-value="<%= is_polymorphic? %>" | ||
data-reload-belongs-to-field-searchable-value="<%= @field.searchable %>" | ||
data-reload-belongs-to-field-relation-name-value="<%= @field.id %>" | ||
data-reload-belongs-to-field-target-name-value="<%= form.object_name %>[<%= @field.id_input_foreign_key %>]" | ||
> | ||
<% if is_polymorphic? %> | ||
<% | ||
# Set the model keys so we can pass them over | ||
model_keys = @field.types.map do |type| | ||
resource = Avo::App.get_resource_by_model_name(type.to_s) | ||
[type.to_s, resource.model_key] | ||
end.to_h | ||
%> | ||
<% | ||
# If the select field is disabled, no value will be sent. It's how HTML works. | ||
# Thus the extra hidden field to actually send the related id to the server. | ||
if disabled %> | ||
<%= @form.hidden_field @field.type_input_foreign_key %> | ||
<div class="divide-y" | ||
data-controller="belongs-to-field" | ||
data-searchable="<%= @field.searchable %>" | ||
data-association="<%= @field.id %>" | ||
data-association-class="<%= @field&.target_resource&.model_class || nil %>" | ||
> | ||
<%= field_wrapper **field_wrapper_args, help: @field.polymorphic_help || '' do %> | ||
<%= @form.select @field.type_input_foreign_key, @field.types.map { |type| [::Avo::App.get_resource_by_model_name(type.to_s).name, type.to_s] }, | ||
{ | ||
value: @field.value, | ||
include_blank: @field.placeholder, | ||
}, | ||
{ | ||
class: classes("w-full"), | ||
data: { | ||
**@field.get_html(:data, view: view, element: :input), | ||
action: "change->belongs-to-field#changeType #{field_html_action}", | ||
'belongs-to-field-target': "select", | ||
}, | ||
disabled: disabled | ||
} | ||
%> | ||
<% | ||
# If the select field is disabled, no value will be sent. It's how HTML works. | ||
# Thus the extra hidden field to actually send the related id to the server. | ||
if disabled %> | ||
<%= @form.hidden_field @field.type_input_foreign_key %> | ||
<% end %> | ||
<% end %> | ||
<% end %> | ||
<% @field.types.each do |type| %> | ||
<div class="hidden" | ||
data-belongs-to-field-target="type" | ||
data-type="<%= type %>" | ||
> | ||
<%= field_wrapper **field_wrapper_args, label: ::Avo::App.get_resource_by_model_name(type.to_s).name do %> | ||
<% if @field.searchable %> | ||
<%= render Avo::Fields::BelongsToField::AutocompleteComponent.new form: @form, | ||
disabled: disabled, | ||
field: @field, | ||
foreign_key: @field.id_input_foreign_key, | ||
model_key: model_keys[type.to_s], | ||
polymorphic_record: polymorphic_record, | ||
resource: @resource, | ||
style: @field.get_html(:style, view: view, element: :input), | ||
type: type, | ||
classes: classes("w-full"), | ||
view: view | ||
<% @field.types.each do |type| %> | ||
<div class="hidden" | ||
data-belongs-to-field-target="type" | ||
data-type="<%= type %>" | ||
> | ||
<%= field_wrapper **field_wrapper_args, label: ::Avo::App.get_resource_by_model_name(type.to_s).name do %> | ||
<div class="flex flex-col gap-1"> | ||
<% if @field.searchable %> | ||
<%= render Avo::Fields::BelongsToField::AutocompleteComponent.new form: @form, | ||
disabled: disabled, | ||
field: @field, | ||
foreign_key: @field.id_input_foreign_key, | ||
model_key: model_keys[type.to_s], | ||
polymorphic_record: polymorphic_record, | ||
resource: @resource, | ||
style: @field.get_html(:style, view: view, element: :input), | ||
type: type, | ||
classes: classes("w-full"), | ||
view: view | ||
%> | ||
<% else %> | ||
<%= @form.select @field.id_input_foreign_key, | ||
options_for_select(@field.values_for_type(type), @resource.present? && @resource.model.present? ? @resource.model[@field.id_input_foreign_key] : nil), | ||
{ | ||
value: @resource.model[@field.id_input_foreign_key].to_s, | ||
include_blank: @field.placeholder, | ||
}, | ||
{ | ||
class: classes("w-full"), | ||
data: @field.get_html(:data, view: view, element: :input), | ||
disabled: disabled | ||
} | ||
%> | ||
<% | ||
# If the select field is disabled, no value will be sent. It's how HTML works. | ||
# Thus the extra hidden field to actually send the related id to the server. | ||
if disabled %> | ||
<%= @form.hidden_field @field.id_input_foreign_key %> | ||
<% end %> | ||
<% end %> | ||
<% create_href = create_path(::Avo::App.get_resource_by_model_name(type.to_s)) %> | ||
<% if !disabled && create_href.present? %> | ||
<%= link_to t("avo.create_new_item", item: type.to_s.downcase), | ||
create_href, | ||
class: "text-sm" | ||
%> | ||
<% end %> | ||
</div> | ||
<% end %> | ||
</div> | ||
<% end %> | ||
</div> | ||
<% else %> | ||
<%= field_wrapper **field_wrapper_args do %> | ||
<div class="flex flex-col gap-1"> | ||
<% if @field.searchable %> | ||
<%= render Avo::Fields::BelongsToField::AutocompleteComponent.new form: @form, | ||
field: @field, | ||
model_key: @field.target_resource&.model_key, | ||
foreign_key: @field.id_input_foreign_key, | ||
resource: @resource, | ||
disabled: disabled, | ||
classes: classes("w-full"), | ||
view: view, | ||
style: @field.get_html(:style, view: view, element: :input) | ||
%> | ||
<% else %> | ||
<%= @form.select @field.id_input_foreign_key, | ||
options_for_select(@field.values_for_type(type), @resource.present? && @resource.model.present? ? @resource.model[@field.id_input_foreign_key] : nil), | ||
<% else %> | ||
<%= @form.select @field.id_input_foreign_key, @field.options, | ||
{ | ||
value: @resource.model[@field.id_input_foreign_key].to_s, | ||
include_blank: @field.placeholder, | ||
value: @field.value | ||
}, | ||
{ | ||
class: classes("w-full"), | ||
data: @field.get_html(:data, view: view, element: :input), | ||
disabled: disabled | ||
disabled: disabled, | ||
style: @field.get_html(:style, view: view, element: :input) | ||
} | ||
%> | ||
<% | ||
<% | ||
# If the select field is disabled, no value will be sent. It's how HTML works. | ||
# Thus the extra hidden field to actually send the related id to the server. | ||
if disabled %> | ||
<%= @form.hidden_field @field.id_input_foreign_key %> | ||
<% end %> | ||
<%= @form.hidden_field @field.id_input_foreign_key %> | ||
<% end %> | ||
<% end %> | ||
<% if !disabled && create_path.present? %> | ||
<%= link_to t("avo.create_new_item", item: @field.name.downcase), create_path, class: "text-sm" %> | ||
<% end %> | ||
</div> | ||
<% end %> | ||
</div> | ||
<% else %> | ||
<%= field_wrapper **field_wrapper_args do %> | ||
<% if @field.searchable %> | ||
<%= render Avo::Fields::BelongsToField::AutocompleteComponent.new form: @form, | ||
field: @field, | ||
model_key: @field.target_resource&.model_key, | ||
foreign_key: @field.id_input_foreign_key, | ||
resource: @resource, | ||
disabled: disabled, | ||
classes: classes("w-full"), | ||
view: view, | ||
style: @field.get_html(:style, view: view, element: :input) | ||
%> | ||
<% else %> | ||
<%= @form.select @field.id_input_foreign_key, @field.options, | ||
{ | ||
include_blank: @field.placeholder, | ||
value: @field.value | ||
}, | ||
{ | ||
class: classes("w-full"), | ||
data: @field.get_html(:data, view: view, element: :input), | ||
disabled: disabled, | ||
style: @field.get_html(:style, view: view, element: :input) | ||
} | ||
%> | ||
<% | ||
# If the select field is disabled, no value will be sent. It's how HTML works. | ||
# Thus the extra hidden field to actually send the related id to the server. | ||
if disabled %> | ||
<%= @form.hidden_field @field.id_input_foreign_key %> | ||
<% end %> | ||
<% end %> | ||
<% end %> | ||
<% end %> | ||
</div> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -4,18 +4,20 @@ class Avo::Views::ResourceEditComponent < Avo::ResourceComponent | |
include Avo::ResourcesHelper | ||
include Avo::ApplicationHelper | ||
|
||
def initialize(resource: nil, model: nil, actions: [], view: :edit) | ||
def initialize(resource: nil, model: nil, actions: [], view: :edit, display_breadcrumbs: true) | ||
@resource = resource | ||
@model = model | ||
@actions = actions | ||
@view = view | ||
@display_breadcrumbs = display_breadcrumbs | ||
end | ||
|
||
def title | ||
@resource.default_panel_name | ||
end | ||
|
||
def back_path | ||
return resource_edit_or_new_path if via_belongs_to? | ||
return resource_view_path if via_resource? | ||
return resources_path if via_index? | ||
|
||
|
@@ -34,6 +36,23 @@ def resource_view_path | |
helpers.resource_view_path(model: association_resource.model, resource: association_resource) | ||
end | ||
|
||
def resource_edit_or_new_path | ||
modal_id = "new_via_belongs_to" | ||
|
||
if params[:via_resource_id].present? | ||
# Back to edit path with param indicating turbo stream should simply close modal | ||
related_resource = params[:via_belongs_to_resource_class].constantize.new | ||
related_record = related_resource.model_class.find(params[:via_resource_id]) | ||
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. If we start using |
||
helpers.edit_resource_path(resource: related_resource, | ||
model: related_record, | ||
close_modal: modal_id) | ||
else | ||
# Back to new path with param indicating turbo stream should close modal | ||
helpers.new_resource_path(resource: @resource, | ||
close_modal: modal_id) | ||
end | ||
end | ||
|
||
def can_see_the_destroy_button? | ||
return super if is_edit? && Avo.configuration.resource_default_view == :edit | ||
|
||
|
@@ -46,12 +65,20 @@ def can_see_the_save_button? | |
@resource.authorization.authorize_action @view, raise_exception: false | ||
end | ||
|
||
def display_breadcrumbs? | ||
@reflection.blank? && @display_breadcrumbs | ||
end | ||
|
||
private | ||
|
||
def via_index? | ||
params[:via_view] == "index" | ||
end | ||
|
||
def via_belongs_to? | ||
params[:via_belongs_to_resource_class].present? | ||
end | ||
|
||
def is_edit? | ||
view.in?([:edit, :update]) | ||
end | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should we use
resource.model.to_param
instead?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good catch! Looks like that's also happening here:
avo/app/components/avo/fields/belongs_to_field/show_component.rb
Lines 8 to 9 in c94dc00