Skip to content
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

fix: boolean group field broken with setters #2985

Merged
merged 10 commits into from
Jul 19, 2024
8 changes: 4 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,13 +38,13 @@ Avo is a very custom Admin Panel Framework, Content Management System, and Inter
<br>
🎸 **Demo app**: [Avodemo](https://main.avodemo.com/)
<br>
🐤 **Twitter**: [avo_hq](https://twitter.com/avo_hq)
🐤 **Twitter**: [`avo_hq`](https://twitter.com/avo_hq)
<br>
💬 **Community chat**: [discord](https://discord.gg/pkTF6y8)
💬 **Community chat**: [Discord](https://discord.gg/pkTF6y8)
<br>
🔧 **Issue tracker**: [GitHub issues](http://github.com/avo-hq/avo/issues)
🔧 **Issue tracker**: [GitHub Issues](http://github.com/avo-hq/avo/issues)
<br>
🎙 **Discussions and feature requests**: [GitHub issues](http://github.com/avo-hq/avo/discussions)
🎙 **Discussions and feature requests**: [GitHub Discussions](http://github.com/avo-hq/avo/discussions)

## Features

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ def checked?(id)
if params[@form_scope].present? && params[@form_scope][@field.id.to_s].present?
params[@form_scope][@field.id.to_s].include?(id.to_s)
elsif @field.value.present?
@field.value[id.to_s]
@field.value.with_indifferent_access[id]
end
end
end
Original file line number Diff line number Diff line change
@@ -1,13 +1,10 @@
<div data-controller="tippy">
<%= link_to t('avo.view').humanize, 'javascript:void(0);', data: { 'tippy-target': 'source' } %>
<%= link_to t("avo.view").humanize, "javascript:void(0);", data: {"tippy-target": :source} %>
<div class="hidden" data-tippy-target="content">
<div class="p-2 space-y-2">
<%
@options.each do |id, label|
checked = @value.present? && @value[id.to_s].present?
%>
<% @options.each do |id, label| %>
<div class="flex flex-nowrap">
<%= render Avo::Fields::Common::BooleanCheckComponent.new checked: checked %>
<%= render Avo::Fields::Common::BooleanCheckComponent.new checked: @value.present? && @value&.with_indifferent_access[id].present? %>
<div class="ml-px text-left py-px"><%= label %></div>
</div>
<% end %>
Expand Down
2 changes: 1 addition & 1 deletion lib/avo/fields/boolean_group_field.rb
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ def fill_field(record, _, values, _)
end

# Don't override existing values unless specified in options
record[id] = (record[id] || {}).merge(new_value)
record.send(:"#{id}=", (record.send(id) || {}).merge(new_value))

record
end
Expand Down
4 changes: 3 additions & 1 deletion lib/avo/licensing/request.rb
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
require "net/http"

module Avo
module Licensing
class Request
Expand All @@ -8,7 +10,7 @@ def post(endpoint, body:, timeout:)
http.use_ssl = (uri.scheme == "https")
http.read_timeout = timeout
http.open_timeout = timeout
request = Net::HTTP::Post.new(uri.request_uri, {'Content-Type' => 'application/json'})
request = Net::HTTP::Post.new(uri.request_uri, {"Content-Type" => "application/json"})
request.body = body
http.request(request)
end
Expand Down
Binary file modified public/avo-assets/logo-on-white.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions spec/dummy/app/avo/resources/user.rb
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,7 @@ def main_panel_fields
field :cv, as: :file, name: "CV"
field :is_admin?, as: :boolean, name: "Is admin", only_on: :index
field :roles, as: :boolean_group, options: {admin: "Administrator", manager: "Manager", writer: "Writer"}
field :permissions, as: :boolean_group, options: {create: "Create", read: "Read", update: "Update", delete: "Delete"}
field :birthday,
as: :date,
first_day_of_week: 1,
Expand Down
11 changes: 11 additions & 0 deletions spec/dummy/app/models/user.rb
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,8 @@ class User < ApplicationRecord
scope :admins, -> { where "(roles->>'admin')::boolean is true" }
scope :non_admins, -> { where "(roles->>'admin')::boolean != true" }

attr_writer :permissions

def is_admin?
roles.present? && roles["admin"].present?
end
Expand Down Expand Up @@ -88,4 +90,13 @@ def accounts
def is_developer?
true
end

def permissions
{
create: true,
update: false,
read: true,
delete: true,
Paul-Bob marked this conversation as resolved.
Show resolved Hide resolved
}
end
end
154 changes: 109 additions & 45 deletions spec/system/avo/boolean_group_field_spec.rb
Original file line number Diff line number Diff line change
@@ -1,49 +1,121 @@
require "rails_helper"

RSpec.describe "BooleanGroupField", type: :system do
describe "with regular input" do
let!(:user) { create :user, roles: {} }
context "database backed BooleanGroupField" do
describe "with regular input" do
let!(:user) { create :user, roles: {} }

context "index" do
it "displays the users name" do
visit "/admin/resources/users"

expect(page).to have_text "ROLES"
expect(page).to have_text "View"
find("tr[data-resource-id='#{user.to_param}'] [data-field-id='roles']").find("a", text: "View").hover
sleep 0.1
wait_for_loaded

assert_popup_texts %w[Administrator Manager Writer]
end
end

context "show" do
it "displays the users roles" do
visit "/admin/resources/users/#{user.id}"

show_popup_for("roles")
sleep 0.1

assert_popup_texts %w[ROLES Administrator Manager Writer]
assert_svg_classes %w[text-red-500 text-red-500 text-red-500]
end
end

context "edit" do
it "changes the users roles" do
visit "/admin/resources/users/#{user.id}/edit"

expect(page).to_not have_checked_field "user_roles_administrator"
expect(page).to_not have_checked_field "user_roles_manager"
expect(page).to_not have_checked_field "user_roles_writer"

check "user_roles_admin"
uncheck "user_roles_manager"
uncheck "user_roles_writer"

save

user_id = page.find('[data-field-id="id"] [data-slot="value"]').text
user_slug = User.find(user_id).slug
expect(current_path).to eql "/admin/resources/users/#{user_slug}"

visit "/admin/resources/users/#{user_slug}"
show_popup_for("roles")
sleep 0.1

assert_popup_texts %w[ROLES Administrator Manager Writer]
assert_svg_classes %w[text-green-600 text-red-500 text-red-500]
end

it "doesn't affect unspecified options" do
user.update(roles: user.roles.merge({publisher: true}))

visit "/admin/resources/users/#{user.id}/edit"

uncheck "user_roles_admin"
uncheck "user_roles_manager"
uncheck "user_roles_writer"

save

user.reload
expect(user.roles).to eql({admin: false, manager: false, publisher: true,
writer: false}.with_indifferent_access)
end
end
end
end

context "non database backed BooleanGroupField" do
let!(:user) { create :user }

context "index" do
it "displays the users name" do
it "displays the users permissions" do
visit "/admin/resources/users"

expect(page).to have_text "ROLES"
expect(page).to have_text "PERMISSIONS"
expect(page).to have_text "View"
find("tr[data-resource-id='#{user.to_param}'] [data-field-id='roles']").find("a", text: "View").hover
find("tr[data-resource-id='#{user.to_param}'] [data-field-id='permissions']").find("a", text: "View").hover
sleep 0.1
wait_for_loaded

expect(page).to have_text "Administrator"
expect(page).to have_text "Manager"
expect(page).to have_text "Writer"
assert_popup_texts %w[PERMISSIONS Create Read Update Delete]
end
end

context "show" do
it "displays the users roles" do
it "displays the users permissions" do
visit "/admin/resources/users/#{user.id}"

show_roles_popup
show_popup_for("permissions")
sleep 0.1

expect(page).to have_text "ROLES"
expect(page).to have_text "Administrator"
expect(page).to have_text "Manager"
expect(page).to have_text "Writer"
expect(page.all(".tippy-content svg")[0][:class]).to have_text "text-red-500"
expect(page.all(".tippy-content svg")[1][:class]).to have_text "text-red-500"
expect(page.all(".tippy-content svg")[2][:class]).to have_text "text-red-500"
assert_popup_texts %w[PERMISSIONS Create Read Update Delete]
assert_svg_classes %w[text-green-600 text-green-600 text-red-500 text-green-600]
end
end

context "edit" do
it "changes the users roles" do
it "does not change the user permissions" do
visit "/admin/resources/users/#{user.id}/edit"

check "user_roles_admin"
uncheck "user_roles_manager"
uncheck "user_roles_writer"
expect(page).to have_checked_field "user_permissions_create"
expect(page).to have_checked_field "user_permissions_read"
expect(page).to_not have_checked_field "user_permissions_update"
expect(page).to have_checked_field "user_permissions_delete"

uncheck "user_permissions_create"
check "user_permissions_update"

save

Expand All @@ -52,36 +124,28 @@
expect(current_path).to eql "/admin/resources/users/#{user_slug}"

visit "/admin/resources/users/#{user_slug}"
show_roles_popup
show_popup_for("permissions")
sleep 0.1

expect(page).to have_text "ROLES"
expect(page).to have_text "Administrator"
expect(page).to have_text "Manager"
expect(page).to have_text "Writer"
expect(page.all(".tippy-content svg")[0][:class]).to have_text "text-green-600"
expect(page.all(".tippy-content svg")[1][:class]).to have_text "text-red-500"
expect(page.all(".tippy-content svg")[2][:class]).to have_text "text-red-500"
assert_popup_texts %w[PERMISSIONS Create Read Update Delete]
assert_svg_classes %w[text-green-600 text-green-600 text-red-500 text-green-600]
end
end
end
end

it "doesn't affect unspecified options" do
user.update(roles: user.roles.merge({publisher: true}))

visit "/admin/resources/users/#{user.id}/edit"

uncheck "user_roles_admin"
uncheck "user_roles_manager"
uncheck "user_roles_writer"

save
def show_popup_for(group)
find("[data-field-id=#{group}]").find("a", text: "View").hover
end

user.reload
expect(user.roles).to eql({admin: false, manager: false, publisher: true, writer: false}.with_indifferent_access)
end
end
def assert_popup_texts(texts)
texts.each do |text|
expect(page).to have_text text
end
end

def show_roles_popup
find("[data-field-id='roles']").find("a", text: "View").hover
def assert_svg_classes(classes)
classes.each_with_index do |klass, index|
expect(page.all(".tippy-content svg")[index][:class]).to have_text klass
end
end
Loading