diff --git a/admin/app/components/solidus_admin/roles/edit/component.html.erb b/admin/app/components/solidus_admin/roles/edit/component.html.erb
new file mode 100644
index 0000000000..541df92c40
--- /dev/null
+++ b/admin/app/components/solidus_admin/roles/edit/component.html.erb
@@ -0,0 +1,16 @@
+<%= turbo_frame_tag :edit_role_modal do %>
+ <%= render component("ui/modal").new(title: t(".title")) do |modal| %>
+ <%= form_for @role, url: solidus_admin.role_path(@role), html: { id: form_id } do |f| %>
+
+ <%= render component("ui/forms/field").text_field(f, :name, class: "required") %>
+
+ <% modal.with_actions do %>
+
+ <%= render component("ui/button").new(form: form_id, type: :submit, text: t('.submit')) %>
+ <% end %>
+ <% end %>
+ <% end %>
+<% end %>
+<%= render component("roles/index").new(page: @page) %>
diff --git a/admin/app/components/solidus_admin/roles/edit/component.rb b/admin/app/components/solidus_admin/roles/edit/component.rb
new file mode 100644
index 0000000000..3d2e06dc2f
--- /dev/null
+++ b/admin/app/components/solidus_admin/roles/edit/component.rb
@@ -0,0 +1,12 @@
+# frozen_string_literal: true
+
+class SolidusAdmin::Roles::Edit::Component < SolidusAdmin::BaseComponent
+ def initialize(page:, role:)
+ @page = page
+ @role = role
+ end
+
+ def form_id
+ dom_id(@role, "#{stimulus_id}_edit_role_form")
+ end
+end
diff --git a/admin/app/components/solidus_admin/roles/edit/component.yml b/admin/app/components/solidus_admin/roles/edit/component.yml
new file mode 100644
index 0000000000..22945513da
--- /dev/null
+++ b/admin/app/components/solidus_admin/roles/edit/component.yml
@@ -0,0 +1,6 @@
+# Add your component translations here.
+# Use the translation in the example in your template with `t(".hello")`.
+en:
+ title: "Edit Role"
+ cancel: "Cancel"
+ submit: "Update Role"
diff --git a/admin/app/components/solidus_admin/roles/index/component.rb b/admin/app/components/solidus_admin/roles/index/component.rb
index 6d2063e0fc..63ac5c1592 100644
--- a/admin/app/components/solidus_admin/roles/index/component.rb
+++ b/admin/app/components/solidus_admin/roles/index/component.rb
@@ -14,7 +14,7 @@ def search_url
end
def row_url(role)
- solidus_admin.roles_path(role)
+ solidus_admin.edit_role_path(role, _turbo_frame: :edit_role_modal)
end
def page_actions
@@ -29,6 +29,7 @@ def page_actions
def turbo_frames
%w[
new_role_modal
+ edit_role_modal
]
end
diff --git a/admin/app/controllers/solidus_admin/roles_controller.rb b/admin/app/controllers/solidus_admin/roles_controller.rb
index f01cf30cb2..1d601ce7c6 100644
--- a/admin/app/controllers/solidus_admin/roles_controller.rb
+++ b/admin/app/controllers/solidus_admin/roles_controller.rb
@@ -4,6 +4,8 @@ module SolidusAdmin
class RolesController < SolidusAdmin::BaseController
include SolidusAdmin::ControllerHelpers::Search
+ before_action :find_role, only: %i[edit update]
+
search_scope(:all)
search_scope(:admin) { _1.where(name: "admin") }
@@ -52,6 +54,39 @@ def create
end
end
+ def edit
+ set_index_page
+
+ respond_to do |format|
+ format.html { render component('roles/edit').new(page: @page, role: @role) }
+ end
+ end
+
+ def update
+ if @role.update(role_params)
+ respond_to do |format|
+ flash[:notice] = t('.success')
+
+ format.html do
+ redirect_to solidus_admin.roles_path, status: :see_other
+ end
+
+ format.turbo_stream do
+ render turbo_stream: ''
+ end
+ end
+ else
+ set_index_page
+
+ respond_to do |format|
+ format.html do
+ page_component = component('roles/edit').new(page: @page, role: @role)
+ render page_component, status: :unprocessable_entity
+ end
+ end
+ end
+ end
+
def destroy
@roles = Spree::Role.where(id: params[:id])
@@ -63,6 +98,10 @@ def destroy
private
+ def find_role
+ @role = Spree::Role.find(params[:id])
+ end
+
def set_index_page
roles = apply_search_to(
Spree::Role.unscoped.order(id: :desc),
diff --git a/admin/config/locales/roles.en.yml b/admin/config/locales/roles.en.yml
index 3017e99ac9..abf6936513 100644
--- a/admin/config/locales/roles.en.yml
+++ b/admin/config/locales/roles.en.yml
@@ -6,3 +6,5 @@ en:
success: "Roles were successfully removed."
create:
success: "Role was successfully created."
+ update:
+ success: "Role was successfully updated."
diff --git a/admin/config/routes.rb b/admin/config/routes.rb
index e2c6e716a0..61f5a72979 100644
--- a/admin/config/routes.rb
+++ b/admin/config/routes.rb
@@ -63,7 +63,7 @@
admin_resources :refund_reasons, except: [:show]
admin_resources :reimbursement_types, only: [:index]
admin_resources :return_reasons, except: [:show]
- admin_resources :roles, only: [:index, :new, :create, :destroy]
+ admin_resources :roles, except: [:show]
admin_resources :adjustment_reasons, except: [:show]
admin_resources :store_credit_reasons, except: [:show]
end
diff --git a/admin/spec/features/roles_spec.rb b/admin/spec/features/roles_spec.rb
index a05e4f88c4..2b08dab450 100644
--- a/admin/spec/features/roles_spec.rb
+++ b/admin/spec/features/roles_spec.rb
@@ -74,4 +74,34 @@
end
end
end
+
+ context "when editing an existing role" do
+ let(:query) { "?page=1&q%5Bname_cont%5D=er" }
+
+ before do
+ Spree::Role.create(name: "Reviewer")
+ visit "/admin/roles#{query}"
+ find_row("Reviewer").click
+ expect(page).to have_content("Edit Role")
+ expect(page).to be_axe_clean
+ end
+
+ it "opens a modal" do
+ expect(page).to have_selector("dialog")
+ within("dialog") { click_on "Cancel" }
+ expect(page).not_to have_selector("dialog")
+ expect(page.current_url).to include(query)
+ end
+
+ it "successfully updates the existing role" do
+ fill_in "Name", with: "Publisher"
+
+ click_on "Update Role"
+ expect(page).to have_content("Role was successfully updated.")
+ expect(page).to have_content("Publisher")
+ expect(page).not_to have_content("Reviewer")
+ expect(Spree::Role.find_by(name: "Publisher")).to be_present
+ expect(page.current_url).to include(query)
+ end
+ end
end
diff --git a/admin/spec/requests/solidus_admin/roles_spec.rb b/admin/spec/requests/solidus_admin/roles_spec.rb
index fea41daabf..95e57c6cb6 100644
--- a/admin/spec/requests/solidus_admin/roles_spec.rb
+++ b/admin/spec/requests/solidus_admin/roles_spec.rb
@@ -64,6 +64,53 @@
end
end
+ describe "GET /edit" do
+ it "renders the edit template with a 200 OK status" do
+ get solidus_admin.edit_role_path(role)
+ expect(response).to have_http_status(:ok)
+ end
+ end
+
+ describe "PATCH /update" do
+ context "with valid parameters" do
+ let(:valid_attributes) { { name: "Publisher" } }
+
+ it "updates the role" do
+ patch solidus_admin.role_path(role), params: { role: valid_attributes }
+ role.reload
+ expect(role.name).to eq("Publisher")
+ end
+
+ it "redirects to the index page with a 303 See Other status" do
+ patch solidus_admin.role_path(role), params: { role: valid_attributes }
+ expect(response).to redirect_to(solidus_admin.roles_path)
+ expect(response).to have_http_status(:see_other)
+ end
+
+ it "displays a success flash message" do
+ patch solidus_admin.role_path(role), params: { role: valid_attributes }
+ follow_redirect!
+ expect(response.body).to include("Role was successfully updated.")
+ end
+ end
+
+ context "with invalid parameters" do
+ let(:invalid_attributes) { { name: "admin" } }
+
+ it "does not update the role" do
+ original_name = role.name
+ patch solidus_admin.role_path(role), params: { role: invalid_attributes }
+ role.reload
+ expect(role.name).to eq(original_name)
+ end
+
+ it "renders the edit template with unprocessable_entity status" do
+ patch solidus_admin.role_path(role), params: { role: invalid_attributes }
+ expect(response).to have_http_status(:unprocessable_entity)
+ end
+ end
+ end
+
describe "DELETE /destroy" do
let!(:role_to_delete) { create(:role) }