-
-
Notifications
You must be signed in to change notification settings - Fork 315
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add Alchemy::Admin::ToolbarButton ViewComponent
- Loading branch information
Showing
5 changed files
with
285 additions
and
114 deletions.
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 |
---|---|---|
@@ -0,0 +1,111 @@ | ||
module Alchemy | ||
module Admin | ||
# Renders a toolbar button for the Alchemy toolbar | ||
# | ||
# == Example | ||
# | ||
# <%= render Alchemy::Admin::ToolbarButton.new( | ||
# url: new_resource_path, | ||
# icon: :plus, | ||
# label: 'Create Resource', | ||
# hotkey: 'alt+n', | ||
# dialog_options: { | ||
# title: 'Create Resource', | ||
# size: "430x400" | ||
# }, | ||
# if_permitted_to: [:create, resource_model] | ||
# ) %> | ||
# | ||
# @param [String] :url | ||
# Url for link. | ||
# @param [String] :icon | ||
# Icon name. See https://remixicon.com for available icons. | ||
# @param [String] :label | ||
# Text for button tooltip. | ||
# @param [String] :hotkey | ||
# Keyboard shortcut for this button. I.E +alt-n+ | ||
# @param [Hash] :dialog_options | ||
# Overlay options. See link_to_dialog helper. | ||
# @param [Array] :if_permitted_to ([:action, :controller]) | ||
# Check permission for button. Exactly how you defined the permission in your +authorization_rules.rb+. Defaults to controller and action from button url. | ||
# @param [Boolean] :skip_permission_check (false) | ||
# Skip the permission check. NOT RECOMMENDED! | ||
# | ||
class ToolbarButton < ViewComponent::Base | ||
erb_template <<-ERB | ||
<div class="toolbar_button"> | ||
<sl-tooltip content="<%= label %>" placement="<%= tooltip_placement %>"> | ||
<%= link_to(render_icon(icon, style: icon_style), url, { | ||
class: css_classes, | ||
"data-dialog-options" => dialog ? dialog_options.to_json : nil, | ||
"data-alchemy-hotkey" => hotkey, | ||
:is => dialog ? "alchemy-dialog-link" : nil | ||
}.merge(link_options)) %> | ||
</sl-tooltip> | ||
</div> | ||
ERB | ||
|
||
delegate :can?, :link_to, :link_to_dialog, :render_icon, to: :helpers | ||
|
||
attr_reader :url, | ||
:icon, | ||
:label, | ||
:hotkey, | ||
:dialog, | ||
:dialog_options, | ||
:skip_permission_check, | ||
:if_permitted_to, | ||
:active, | ||
:link_options, | ||
:icon_style, | ||
:tooltip_placement | ||
|
||
def initialize( | ||
url:, | ||
icon:, | ||
label:, | ||
hotkey: nil, | ||
title: nil, | ||
dialog: true, | ||
dialog_options: {}, | ||
skip_permission_check: false, | ||
if_permitted_to: [], | ||
active: false, | ||
link_options: {}, | ||
icon_style: "line", | ||
tooltip_placement: "top-start" | ||
) | ||
@url = url | ||
@icon = icon | ||
@label = label | ||
@hotkey = hotkey | ||
@dialog = dialog | ||
@dialog_options = dialog_options | ||
@skip_permission_check = skip_permission_check | ||
@if_permitted_to = if_permitted_to | ||
@active = active | ||
@link_options = link_options | ||
@icon_style = icon_style | ||
@tooltip_placement = tooltip_placement | ||
end | ||
|
||
def render? | ||
skip_permission_check || can?(*permission_options) | ||
end | ||
|
||
private | ||
|
||
def css_classes = ["icon_button", active && "active"].compact | ||
|
||
def permission_options = if_permitted_to.presence || permissions_from_url | ||
|
||
def permissions_from_url | ||
action_controller = url.gsub(/\A\//, "").split("/") | ||
[ | ||
action_controller.last.to_sym, | ||
action_controller[0..action_controller.length - 2].join("_").to_sym | ||
] | ||
end | ||
end | ||
end | ||
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
This file was deleted.
Oops, something went wrong.
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 |
---|---|---|
@@ -0,0 +1,168 @@ | ||
require "rails_helper" | ||
|
||
RSpec.describe Alchemy::Admin::ToolbarButton, type: :component do | ||
before do | ||
allow_any_instance_of(described_class).to receive(:render_icon) do |component| | ||
Alchemy::Admin::Icon.new(component.icon, style: component.icon_style).call | ||
end | ||
end | ||
|
||
let(:component) do | ||
described_class.new(url: admin_dashboard_path, icon: "info", label: "Show Info") | ||
end | ||
|
||
context "with permission" do | ||
before { expect(component).to receive(:can?) { true } } | ||
|
||
it "renders a toolbar button" do | ||
render_inline component | ||
expect(page).to have_css %(sl-tooltip a.icon_button[href="#{admin_dashboard_path}"]) | ||
end | ||
|
||
context "with dialog option set to false" do | ||
let(:component) do | ||
described_class.new( | ||
url: admin_dashboard_path, | ||
icon: "info", | ||
label: "Show Info", | ||
dialog: false | ||
) | ||
end | ||
|
||
it "renders a normal link" do | ||
render_inline component | ||
expect(page).to have_css(%(a[href="#{admin_dashboard_path}"])) | ||
expect(page).not_to have_css("[data-dialog-options]") | ||
end | ||
end | ||
|
||
context "with dialog_options set" do | ||
let(:component) do | ||
described_class.new( | ||
url: admin_dashboard_path, | ||
icon: "info", | ||
label: "Show Info", | ||
dialog_options: { | ||
title: "Info", | ||
size: "300x200" | ||
} | ||
) | ||
end | ||
|
||
it "passes them to the link" do | ||
render_inline component | ||
expect(page).to have_css(%(a[data-dialog-options='{"title":"Info","size":"300x200"}'])) | ||
end | ||
end | ||
|
||
context "with hotkey set" do | ||
let(:component) do | ||
described_class.new( | ||
url: admin_dashboard_path, | ||
icon: "info", | ||
label: "Show Info", | ||
hotkey: "alt+i" | ||
) | ||
end | ||
|
||
it "passes it to the link" do | ||
render_inline component | ||
expect(page).to have_css('a[data-alchemy-hotkey="alt+i"]') | ||
end | ||
end | ||
|
||
context "with icon_style set" do | ||
let(:component) do | ||
described_class.new( | ||
url: admin_dashboard_path, | ||
icon: "info", | ||
label: "Show Info", | ||
icon_style: "fill" | ||
) | ||
end | ||
|
||
it "passes it to the icon" do | ||
render_inline component | ||
expect(page).to have_css('alchemy-icon[icon-style="fill"]') | ||
end | ||
end | ||
|
||
context "with tooltip_placement set" do | ||
let(:component) do | ||
described_class.new( | ||
url: admin_dashboard_path, | ||
icon: "info", | ||
label: "Show Info", | ||
tooltip_placement: "bottom-center" | ||
) | ||
end | ||
|
||
it "passes it to the icon" do | ||
render_inline component | ||
expect(page).to have_css('sl-tooltip[placement="bottom-center"]') | ||
end | ||
end | ||
|
||
context "with active set to true" do | ||
let(:component) do | ||
described_class.new( | ||
url: admin_dashboard_path, | ||
icon: "info", | ||
label: "Show Info", | ||
active: true | ||
) | ||
end | ||
|
||
it "button has active class" do | ||
render_inline component | ||
expect(page).to have_css("a.active") | ||
end | ||
end | ||
end | ||
|
||
context "without permission" do | ||
before { expect(component).to receive(:can?) { false } } | ||
|
||
it "returns empty string" do | ||
render_inline component | ||
expect(page.native.inner_html).to be_empty | ||
end | ||
end | ||
|
||
context "with disabled permission check" do | ||
before { expect(component).not_to receive(:can?) { false } } | ||
|
||
let(:component) do | ||
described_class.new( | ||
url: admin_dashboard_path, | ||
icon: "info", | ||
label: "Show Info", | ||
skip_permission_check: true | ||
) | ||
end | ||
|
||
it "renders a toolbar button" do | ||
render_inline component | ||
expect(page).to have_css %(sl-tooltip .icon_button[href="#{admin_dashboard_path}"]) | ||
end | ||
end | ||
|
||
context "with empty permission option" do | ||
before { expect(component).to receive(:can?) { true } } | ||
|
||
let(:component) do | ||
described_class.new( | ||
url: admin_dashboard_path, | ||
icon: "info", | ||
label: "Show Info", | ||
if_permitted_to: "" | ||
) | ||
end | ||
|
||
it "returns reads the permission from url" do | ||
expect(component).to receive(:permissions_from_url) | ||
render_inline component | ||
expect(page).to have_css %(sl-tooltip .icon_button[href="#{admin_dashboard_path}"]) | ||
end | ||
end | ||
end |
Oops, something went wrong.