Skip to content

Commit c35dbff

Browse files
authored
Merge pull request #6350 from brodyf42/6298_add_custom_per_org_navbar_links
[resolves 6298] Add Custom Admin-Defined Navbar Links
2 parents 3ed4ba2 + a1c76ff commit c35dbff

23 files changed

+547
-0
lines changed

.allow_skipping_tests

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ services/create_casa_admin_service.rb
4545
services/fdf_inputs_service.rb
4646
validators/casa_org_validator.rb
4747
validators/court_report_validator.rb
48+
validators/url_validator.rb
4849
validators/user_validator.rb
4950
values/all_casa_admin_parameters.rb
5051
values/casa_admin_parameters.rb

app/controllers/casa_org_controller.rb

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ class CasaOrgController < ApplicationController
77
before_action :set_learning_hour_topics, only: %i[edit update]
88
before_action :set_sent_emails, only: %i[edit update]
99
before_action :set_contact_topics, only: %i[edit update]
10+
before_action :set_custom_org_links, only: %i[edit update]
1011
before_action :require_organization!
1112
after_action :verify_authorized
1213
before_action :set_active_storage_url_options, only: %i[edit update]
@@ -90,6 +91,10 @@ def set_contact_topics
9091
@contact_topics = @casa_org.contact_topics.where(soft_delete: false)
9192
end
9293

94+
def set_custom_org_links
95+
@custom_org_links = @casa_org.custom_org_links
96+
end
97+
9398
def set_active_storage_url_options
9499
ActiveStorage::Current.url_options = {host: request.base_url}
95100
end
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
class CustomOrgLinksController < ApplicationController
2+
before_action :set_custom_org_link, only: %i[edit update destroy]
3+
after_action :verify_authorized
4+
5+
def new
6+
authorize CustomOrgLink
7+
@custom_org_link = CustomOrgLink.new
8+
end
9+
10+
def create
11+
authorize CustomOrgLink
12+
13+
@custom_org_link = current_organization.custom_org_links.new(custom_org_link_params)
14+
15+
if @custom_org_link.save
16+
redirect_to edit_casa_org_path(current_organization), notice: "Custom link was successfully created."
17+
else
18+
render :new, status: :unprocessable_entity
19+
end
20+
end
21+
22+
def edit
23+
authorize @custom_org_link
24+
end
25+
26+
def update
27+
authorize @custom_org_link
28+
if @custom_org_link.update(custom_org_link_params)
29+
redirect_to edit_casa_org_path(current_organization), notice: "Custom link was successfully updated."
30+
else
31+
render :edit, status: :unprocessable_entity
32+
end
33+
end
34+
35+
def destroy
36+
authorize @custom_org_link
37+
@custom_org_link.destroy
38+
redirect_to edit_casa_org_path(current_organization), notice: "Custom link was successfully deleted."
39+
end
40+
41+
private
42+
43+
def set_custom_org_link
44+
@custom_org_link = CustomOrgLink.find(params[:id])
45+
end
46+
47+
def custom_org_link_params
48+
params.require(:custom_org_link).permit(:text, :url, :active)
49+
end
50+
end

app/models/casa_org.rb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ class CasaOrg < ApplicationRecord
2727
has_many :learning_hour_topics, dependent: :destroy
2828
has_many :case_groups, dependent: :destroy
2929
has_many :contact_topics
30+
has_many :custom_org_links, dependent: :destroy
3031
has_one_attached :logo
3132
has_one_attached :court_report_template
3233
has_many :placement_types, dependent: :destroy

app/models/custom_org_link.rb

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
class CustomOrgLink < ApplicationRecord
2+
TEXT_MAX_LENGTH = 30
3+
4+
belongs_to :casa_org
5+
validates :text, :url, presence: true
6+
validates :text, length: {maximum: TEXT_MAX_LENGTH}
7+
validates :active, inclusion: {in: [true, false]}
8+
validates :url, url: true
9+
end
10+
11+
# == Schema Information
12+
#
13+
# Table name: custom_org_links
14+
#
15+
# id :bigint not null, primary key
16+
# active :boolean default(TRUE), not null
17+
# text :string not null
18+
# url :string not null
19+
# created_at :datetime not null
20+
# updated_at :datetime not null
21+
# casa_org_id :bigint not null
22+
#
23+
# Indexes
24+
#
25+
# index_custom_org_links_on_casa_org_id (casa_org_id)
26+
#
27+
# Foreign Keys
28+
#
29+
# fk_rails_... (casa_org_id => casa_orgs.id)
30+
#
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
class CustomOrgLinkPolicy < ApplicationPolicy
2+
class Scope < ApplicationPolicy::Scope
3+
def resolve
4+
case user
5+
when CasaAdmin
6+
scope.where(casa_org: @user.casa_org)
7+
else
8+
scope.none
9+
end
10+
end
11+
end
12+
end

app/validators/url_validator.rb

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
class UrlValidator < ActiveModel::EachValidator
2+
InvalidSchemeError = Class.new StandardError
3+
MissingHostError = Class.new StandardError
4+
5+
DEFAULT_SCHEMES = %w[http https].freeze
6+
7+
def validate_each(record, attribute, value)
8+
uri = URI.parse(value)
9+
validate_scheme uri
10+
validate_host uri
11+
rescue URI::InvalidURIError
12+
record.errors.add(attribute, "format is invalid")
13+
rescue InvalidSchemeError, MissingHostError => e
14+
record.errors.add(attribute, e.message)
15+
end
16+
17+
private
18+
19+
def validate_scheme(uri)
20+
accepted_schemes = Array.wrap(options[:scheme] || DEFAULT_SCHEMES)
21+
return if uri.scheme.in? accepted_schemes
22+
23+
raise InvalidSchemeError, "scheme invalid - only #{accepted_schemes.join(", ")} allowed"
24+
end
25+
26+
def validate_host(uri)
27+
raise MissingHostError, "host cannot be blank" if uri.host.blank?
28+
end
29+
end
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
<div class="row">
2+
<div class="col-lg-12">
3+
<div class="card-style mb-30">
4+
<div class="row align-items-center">
5+
<div class="col-md-6">
6+
<h3>Custom Links</h3>
7+
</div>
8+
<div class="col-md-6">
9+
<div class="breadcrumb-wrapper">
10+
<span class="ml-5">
11+
<%= link_to new_custom_org_link_path, class: "btn-sm main-btn primary-btn btn-hover" do %>
12+
<i class="lni lni-plus mr-10"></i> New Custom Link
13+
<% end %>
14+
</span>
15+
</div>
16+
</div>
17+
</div>
18+
<div class="table-wrapper table-responsive">
19+
<table class="table striped-table">
20+
<thead>
21+
<tr>
22+
<th>Display Text</th>
23+
<th>URL</th>
24+
<th>Active?</th>
25+
<th>Actions</th>
26+
</tr>
27+
</thead>
28+
<tbody>
29+
<% if @custom_org_links.blank? %>
30+
<tr>
31+
<td colspan="4">
32+
<span class="fw-light fst-italic text-center">No custom links have been added for this organization.</span>
33+
</td>
34+
</tr>
35+
<% else %>
36+
<% @custom_org_links.each do |custom_link| %>
37+
<tr>
38+
<td><%= custom_link.text %></td>
39+
<td><%= truncate(custom_link.url, length: 90) %></td>
40+
<td><%= custom_link.active ? "Yes" : "No" %></td>
41+
<td>
42+
<%= link_to edit_custom_org_link_path(custom_link) do %>
43+
<div class="action">
44+
<button class="text-danger">
45+
<i class="lni lni-pencil-alt"></i> Edit
46+
</button>
47+
</div>
48+
<% end %>
49+
<%= link_to custom_org_link_path(custom_link), method: :delete do %>
50+
<div class="action">
51+
<button class="text-danger">
52+
<i class="lni lni-trash-can"></i> Delete
53+
</button>
54+
</div>
55+
<% end %>
56+
</td>
57+
</tr>
58+
<% end %>
59+
<% end %>
60+
</tbody>
61+
</table>
62+
</div>
63+
</div>
64+
</div>
65+
</div>

app/views/casa_org/edit.html.erb

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,9 @@
9999
<div class="tables-wrapper">
100100
<%= render "languages", languages: current_organization.languages %>
101101
</div>
102+
<div class="tables-wrapper">
103+
<%= render "custom_org_links" %>
104+
</div>
102105
<!-- end -->
103106
<div class="title-wrapper pt-30">
104107
<div class="row align-items-center">
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
<div class="title-wrapper pt-30">
2+
<div class="row align-items-center">
3+
<div class="col-md-6">
4+
<div class="title mb-30">
5+
<h1>
6+
<%= title %>
7+
</h1>
8+
</div>
9+
</div>
10+
</div>
11+
</div><!-- ==== end title ==== -->
12+
13+
<!-- ========== card start ========== -->
14+
<div class="card-style mb-30">
15+
<%= form_with model: @custom_org_link, local: true do |form| %>
16+
<div class="alert-box danger-alert">
17+
<%= render "/shared/error_messages", resource: @custom_org_link %>
18+
</div>
19+
20+
<div class="input-style-1">
21+
<%= form.label :name, "Display Text" %>
22+
<%= form.text_field :text, class: "form-control", required: true %>
23+
</div>
24+
25+
<div class="input-style-1">
26+
<%= form.label :name, "URL" %>
27+
<%= form.text_field :url, class: "form-control", required: true %>
28+
</div>
29+
30+
<div class="form-check checkbox-style mb-20">
31+
<%= form.check_box :active, as: :boolean, class: 'form-check-input' %>
32+
<%= form.label :active, "Active?", class: 'form-check-label' %>
33+
</div>
34+
35+
<div class="actions mb-10">
36+
<%= button_tag type: "submit", class: "btn-sm main-btn primary-btn btn-hover" do %>
37+
<i class="lni lni-checkmark-circle mr-5"></i> <%= action %>
38+
<% end %>
39+
</div>
40+
<% end %>
41+
</div>
42+
<!-- card end -->

0 commit comments

Comments
 (0)