Skip to content

Commit

Permalink
feature: format_using and update_using field options (#1797)
Browse files Browse the repository at this point in the history
  • Loading branch information
adrianthedev committed Jun 28, 2023
1 parent a45a460 commit af82381
Show file tree
Hide file tree
Showing 30 changed files with 112 additions and 27 deletions.
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
<%= field_wrapper **field_wrapper_args do %>
<%= @form.text_field @field.id,
value: @field.value,
class: classes("w-full"),
value: field.value.to_s,
placeholder: @field.placeholder,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
<%= field_wrapper **field_wrapper_args, dash_if_blank: false do %>
<div class="h-8 flex items-center">
<%= @form.check_box @field.id,
value: @field.value,
checked: @field.value,
class: "text-lg h-4 w-4 checked:bg-primary-400 focus:checked:!bg-primary-400 #{@field.get_html(:classes, view: view, element: :input)}",
data: @field.get_html(:data, view: view, element: :input),
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
<%= field_wrapper **field_wrapper_args, full_width: true do %>
<div data-controller="code-field">
<%= @form.text_area @field.id,
value: @field.value,
class: classes("w-full"),
data: {
'code-field-target': 'element',
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
<%= field_wrapper **field_wrapper_args do %>
<%= @form.select @field.id, @field.select_options, {
value: @field.value,
selected: @field.value,
include_blank: @field.include_blank
},
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
<%= field_wrapper **field_wrapper_args, full_width: true do %>
<div data-controller="easy-mde">
<%= @form.text_area @field.id,
value: @field.value,
class: classes("w-full js-has-easy-mde-editor"),
data: {
view: view,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
<%= field_wrapper **field_wrapper_args do %>
<%= @form.number_field @field.id,
value: @field.value,
class: classes("w-full"),
data: @field.get_html(:data, view: view, element: :input),
disabled: disabled?,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
<%= field_wrapper **field_wrapper_args do %>
<%= @form.password_field @field.id,
value: @field.value,
class: classes("w-full"),
data: @field.get_html(:data, view: view, element: :input),
disabled: disabled?,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
</div>
<% end %>
<%= @form.range_field @field.id,
value: @field.value,
class: "w-full #{@field.get_html(:classes, view: view, element: :input)}",
data: {
action: "input->progress-bar-field#update",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,6 @@
disabled: disabled?,
placeholder: @field.placeholder,
style: @field.get_html(:style, view: view, element: :input),
value: @resource.model.present? ? @resource.model[@field.id] : @field.value
value: @field.value
%>
<% end %>
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
<%= field_wrapper **field_wrapper_args do %>
<%= form.text_field @field.id,
value: @field.value,
class: classes("w-full"),
data: @field.get_html(:data, view: view, element: :input),
disabled: disabled?,
placeholder: @field.placeholder,
style: @field.get_html(:style, view: view, element: :input),
# value: @field.value,
multiple: multiple,
autocomplete: @field.autocomplete
%>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
<%= field_wrapper **field_wrapper_args do %>
<%= @form.text_area @field.id,
value: @field.value,
class: classes("w-full"),
data: @field.get_html(:data, view: view, element: :input),
disabled: disabled?,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
<%= sanitize @field.value.to_s %>
<% end %>
<%= @form.text_area @field.id,
value: @field.value,
class: classes("w-full hidden"),
data: @field.get_html(:data, view: view, element: :input),
disabled: disabled?,
Expand Down
2 changes: 1 addition & 1 deletion app/components/avo/views/resource_edit_component.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
selected_resources: [@resource.model.id],
**@resource.stimulus_data_attributes
} do %>
<%= form_with model: @resource.model,
<%= form_with model: @resource.record,
scope: @resource.form_scope,
url: form_url,
method: form_method,
Expand Down
11 changes: 7 additions & 4 deletions lib/avo/base_resource.rb
Original file line number Diff line number Diff line change
Expand Up @@ -151,7 +151,8 @@ def initialize
def record
@model
end
alias :model :record
alias_method :model, :record


def hydrate(model: nil, view: nil, user: nil, params: nil)
@view = view if view.present?
Expand Down Expand Up @@ -307,17 +308,19 @@ def attachment_fields
end
end

def fill_model(model, params, extra_params: [])
# Map the received params to their actual fields
fields_by_database_id = get_field_definitions
# Map the received params to their actual fields.
def fields_by_database_id
get_field_definitions
.reject do |field|
field.computed
end
.map do |field|
[field.database_id.to_s, field]
end
.to_h
end

def fill_model(model, params, extra_params: [])
# Write the field values
params.each do |key, value|
field = fields_by_database_id[key]
Expand Down
43 changes: 43 additions & 0 deletions lib/avo/execution_context.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
module Avo
class ExecutionContext
attr_accessor :target, :context, :params, :view_context, :current_user, :request, :include, :main_app, :avo

def initialize(**args)
# Extend the class with custom modules if required.
if args[:include].present?
args[:include].each do |mod|
self.class.send(:include, mod)
end
end

# If you want this block to behave like a view you can delegate the missing methods to the view_context
#
# Ex: Avo::ExecutionContext.new(target: ..., delegate_missing_to: :view_context).handle
if args[:delegate_missing_to].present?
self.class.send(:delegate_missing_to, args[:delegate_missing_to])
end

# If target doesn't respond to call, we don't need to initialize the others attr_accessors.
return unless (@target = args[:target]).respond_to? :call

args.except(:target).each do |key, value|
singleton_class.class_eval { attr_accessor key }
instance_variable_set("@#{key}", value)
end

# Set defaults on not initialized accessors
@context ||= Avo::App.context
@params ||= Avo::App.params
@view_context ||= Avo::App.view_context
@current_user ||= Avo::App.current_user
@request ||= view_context.request
@main_app ||= view_context.main_app
@avo ||= view_context.avo
end

# Return target if target is not callable, otherwise, execute target on this instance context
def handle
target.respond_to?(:call) ? instance_exec(&target) : target
end
end
end
22 changes: 17 additions & 5 deletions lib/avo/fields/base_field.rb
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ def initialize(id, **args, &block)
@nullable = args[:nullable] || false
@null_values = args[:null_values] || [nil, ""]
@format_using = args[:format_using] || nil
@update_using = args[:update_using] || nil
@placeholder = args[:placeholder]
@autocomplete = args[:autocomplete] || nil
@help = args[:help] || nil
Expand Down Expand Up @@ -183,20 +184,31 @@ def value(property = nil)
final_value = instance_exec(@model, @resource, @view, self, &block)
end

# Run the value through resolver if present
final_value = instance_exec(final_value, &@format_using) if @format_using.present?

final_value
if @format_using.present?
# Apply the changes in the
Avo::ExecutionContext.new(target: @format_using, model: model, key: property, value: final_value, resource: resource, view: view, field: self, delegate_missing_to: :view_context).handle
else
final_value
end
end

# Fills the model with the received value on create and update actions.
def fill_field(model, key, value, params)
return model unless model.methods.include? key.to_sym

model.send("#{key}=", value)
if @update_using.present?
value = update_using(model, key, value, params)
end

model.public_send("#{key}=", value)

model
end

def update_using(model, key, value, params)
Avo::ExecutionContext.new(target: @update_using, model: model, key: key, value: value, resource: resource, field: self).handle
end

# Try to see if the field has a different database ID than it's name
def database_id
foreign_key
Expand Down
15 changes: 13 additions & 2 deletions spec/dummy/app/avo/resources/city_resource.rb
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ class CityResource < Avo::BaseResource
self.search_result_path = -> {
avo.resources_city_path record, custom: "yup"
}
self.extra_params = [:fish_type, :something_else, properties: [], information: [:name, :history]]
self.extra_params = [city: [:name, :metadata, :coordinates, :city_center_area, :description, :population, :is_capital, :image_url, :tiny_description, :status, features: {}, metadata: {}]]
self.default_view_type = :map
self.map_view = {
mapkick_options: {
Expand Down Expand Up @@ -43,12 +43,23 @@ class CityResource < Avo::BaseResource
color: "#009099"
}
field :description, as: :trix, attachment_key: :description_file, visible: ->(resource:) { resource.params[:show_native_fields].blank? }
field :metadata,
as: :code,
format_using: -> {
if view == :edit
JSON.generate(value)
else
value
end
},
update_using: -> do
ActiveSupport::JSON.decode(value)
end
with_options hide_on: :forms do
field :name, as: :text, help: "The name of your city"
field :population, as: :number
field :is_capital, as: :boolean
field :features, as: :key_value
field :metadata, as: :code
field :image_url, as: :external_image
field :tiny_description, as: :markdown
field :status, as: :badge, enum: ::City.statuses
Expand Down
2 changes: 1 addition & 1 deletion spec/dummy/app/avo/resources/comment_resource.rb
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ class CommentResource < Avo::BaseResource
self.after_update_path = :index

field :id, as: :id
field :body, as: :textarea, format_using: ->(value) do
field :body, as: :textarea, format_using: -> do
if view == :show
content_tag(:div, style: "white-space: pre-line") { value }
else
Expand Down
2 changes: 1 addition & 1 deletion spec/dummy/app/avo/resources/photo_comment_resource.rb
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ class PhotoCommentResource < Avo::BaseResource
end

field :id, as: :id
field :body, as: :textarea, format_using: ->(value) do
field :body, as: :textarea, format_using: -> do
if view == :show
content_tag(:div, style: "white-space: pre-line") { value }
else
Expand Down
2 changes: 1 addition & 1 deletion spec/dummy/app/avo/resources/post_resource.rb
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ class PostResource < Avo::BaseResource
enforce_suggestions: true,
help: "The only allowed values here are `one`, `two`, and `three`"
field :cover_photo, as: :file, is_image: true, as_avatar: :rounded, full_width: true, hide_on: [], accept: "image/*", display_filename: false
field :cover_photo, as: :external_image, name: "Cover photo", required: true, hide_on: :all, link_to_resource: true, as_avatar: :rounded, format_using: ->(value) { value.present? ? value&.url : nil }
field :cover_photo, as: :external_image, name: "Cover photo", required: true, hide_on: :all, link_to_resource: true, as_avatar: :rounded, format_using: -> { value.present? ? value&.url : nil }
field :audio, as: :file, is_audio: true, accept: "audio/*"
field :excerpt, as: :text, hide_on: :all, as_description: true do |model|
extract_excerpt model.body
Expand Down
2 changes: 1 addition & 1 deletion spec/dummy/app/avo/resources/product_resource.rb
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ class ProductResource < Avo::BaseResource
}
}
title :title, as: :text
body :description, as: :textarea, format_using: ->(value) {
body :description, as: :textarea, format_using: -> {
simple_format value
}
end
Expand Down
2 changes: 1 addition & 1 deletion spec/dummy/app/avo/resources/team_resource.rb
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ class TeamResource < Avo::BaseResource
rows: 5,
readonly: false,
hide_on: :index,
format_using: ->(value) { value.to_s.truncate 30 },
format_using: -> { value.to_s.truncate 30 },
default: "This is a wonderful team!",
nullable: true,
null_values: ["0", "", "null", "nil"]
Expand Down
2 changes: 1 addition & 1 deletion spec/dummy/app/avo/resources/user_resource.rb
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ class UserResource < Avo::BaseResource
hide_on: :edit do |model, resource, view, field|
model.posts.to_a.size > 0 ? "yes" : "no"
end
field :outside_link, as: :text, only_on: [:show], format_using: ->(url) { link_to("hey", url, target: "_blank") } do |model, *args|
field :outside_link, as: :text, only_on: [:show], format_using: -> { link_to("hey", value, target: "_blank") } do |model, *args|
main_app.hey_url
end
end
Expand Down
2 changes: 1 addition & 1 deletion spec/dummy/app/avo/resources/z_post_resource.rb
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ class ZPostResource < Avo::BaseResource
enforce_suggestions: true,
help: "The only allowed values here are `one`, `two`, and `three`"
field :cover_photo, as: :file, is_image: true, as_avatar: :rounded, full_width: true, hide_on: [], accept: "image/*"
field :cover_photo, as: :external_image, name: "Cover photo", required: true, hide_on: :all, link_to_resource: true, as_avatar: :rounded, format_using: ->(value) { value.present? ? value&.url : nil }
field :cover_photo, as: :external_image, name: "Cover photo", required: true, hide_on: :all, link_to_resource: true, as_avatar: :rounded, format_using: -> { value.present? ? value&.url : nil }
field :audio, as: :file, is_audio: true, accept: "audio/*"
field :excerpt, as: :text, hide_on: :all, as_description: true do |model|
ActionView::Base.full_sanitizer.sanitize(model.body).truncate 130
Expand Down
9 changes: 9 additions & 0 deletions spec/dummy/app/models/city.rb
Original file line number Diff line number Diff line change
Expand Up @@ -38,4 +38,13 @@ def coordinates=(value)
self.latitude = value.first
self.longitude = value.last
end

# alternative to format_using and update_using
# def json_metadata
# ActiveSupport::JSON.encode(metadata)
# end

# def json_metadata=(value)
# self.metadata = ActiveSupport::JSON.decode(value)
# end
end
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@
<%= avo_edit_field(:number, :population, form: form, help: "The population of the city.") %>
<%= avo_edit_field(:is_capital, as: :boolean, form: form) %>
<%= avo_edit_field(:features, as: :key_value, form: form) %>
<%= avo_show_field(:metadata, as: :code, form: form) %>
<%= avo_show_field(:image_url, as: :external_image, form: form) do |model|
'https://images.unsplash.com/photo-1660061993776-098c0ee403ac?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=MnwxfDB8MXxyYW5kb218MHx8fHx8fHx8MTY2MDMxMzc4NA&ixlib=rb-1.2.1&q=80&w=1080'
end %>
Expand Down
2 changes: 0 additions & 2 deletions spec/features/avo/native_fields_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@
expect(find_field('Population').value).to eq city.population.to_s
expect(find_field('Is capital').value).to eq "1"
expect(find_field('Features').value).to eq "\"#{city.features}\""
expect(find_field('metadata', visible: false, disabled: true).value).to eq city.metadata

expect(page).to have_css 'img[src="https://images.unsplash.com/photo-1660061993776-098c0ee403ac?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=MnwxfDB8MXxyYW5kb218MHx8fHx8fHx8MTY2MDMxMzc4NA&ixlib=rb-1.2.1&q=80&w=1080"]'
expect(find_field('Image url').value).to eq city.image_url
Expand All @@ -31,7 +30,6 @@
fill_in 'city[population]', with: 101
find('[name="city[is_capital]"]').set(false)
fill_in 'city[features]', with: "{\"hey\": \"features\"}"
find_field('metadata', visible: false, disabled: true).set("{\"hey\": \"metadata\"}")

click_on "Save"

Expand Down
2 changes: 1 addition & 1 deletion spec/system/avo/date_time_fields/date_time_eastern_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
subject(:text_input) { find '[data-field-id="posted_at"] [data-controller="date-field"] input[type="text"]' }
before do
CommentResource.with_temporary_items do
field :body, as: :textarea, format_using: ->(value) do
field :body, as: :textarea, format_using: -> do
if view == :show
content_tag(:div, style: "white-space: pre-line") { value }
else
Expand Down
2 changes: 1 addition & 1 deletion spec/system/avo/date_time_fields/date_time_utc_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@

before do
CommentResource.with_temporary_items do
field :body, as: :textarea, format_using: ->(value) do
field :body, as: :textarea, format_using: -> do
if view == :show
content_tag(:div, style: "white-space: pre-line") { value }
else
Expand Down
2 changes: 1 addition & 1 deletion spec/system/avo/date_time_fields/date_time_western_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@

before do
CommentResource.with_temporary_items do
field :body, as: :textarea, format_using: ->(value) do
field :body, as: :textarea, format_using: -> do
if view == :show
content_tag(:div, style: "white-space: pre-line") { value }
else
Expand Down

0 comments on commit af82381

Please sign in to comment.