Skip to content

Commit 562aebc

Browse files
committed
[resolves 6298] Add Custom Admin-Defined Navbar Links
1 parent 4274abb commit 562aebc

19 files changed

+303
-1
lines changed

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: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
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+
if current_organization.custom_org_links.count >= CustomOrgLink::MAX_RECORDS_PER_ORG
14+
return redirect_to edit_casa_org_path(current_organization), alert: "Custom Link was not created - limit has been reached."
15+
end
16+
17+
@custom_org_link = current_organization.custom_org_links.new(custom_org_link_params)
18+
19+
if @custom_org_link.save
20+
redirect_to edit_casa_org_path(current_organization), notice: "Custom link was successfully created."
21+
else
22+
render :new, status: :unprocessable_entity
23+
end
24+
end
25+
26+
def edit
27+
authorize @custom_org_link
28+
end
29+
30+
def update
31+
authorize @custom_org_link
32+
if @custom_org_link.update(custom_org_link_params)
33+
redirect_to edit_casa_org_path(current_organization), notice: "Custom link was successfully updated."
34+
else
35+
render :edit, status: :unprocessable_entity
36+
end
37+
end
38+
39+
def destroy
40+
authorize @custom_org_link
41+
@custom_org_link.destroy
42+
redirect_to edit_casa_org_path(current_organization), notice: "Custom link was successfully deleted."
43+
end
44+
45+
private
46+
47+
def set_custom_org_link
48+
@custom_org_link = CustomOrgLink.find(params[:id])
49+
end
50+
51+
def custom_org_link_params
52+
params.require(:custom_org_link).permit(:text, :url, :active)
53+
end
54+
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: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
class CustomOrgLink < ApplicationRecord
2+
MAX_RECORDS_PER_ORG = 3
3+
TEXT_MAX_LENGTH = 30
4+
5+
belongs_to :casa_org
6+
validates :text, :url, presence: true
7+
validates :text, length: {maximum: TEXT_MAX_LENGTH}
8+
validates :active, inclusion: {in: [true, false]}
9+
validates :url, url: true
10+
end
11+
12+
# == Schema Information
13+
#
14+
# Table name: custom_org_links
15+
#
16+
# id :bigint not null, primary key
17+
# active :boolean default(TRUE), not null
18+
# text :string not null
19+
# url :string not null
20+
# created_at :datetime not null
21+
# updated_at :datetime not null
22+
# casa_org_id :bigint not null
23+
#
24+
# Indexes
25+
#
26+
# index_custom_org_links_on_casa_org_id (casa_org_id)
27+
#
28+
# Foreign Keys
29+
#
30+
# fk_rails_... (casa_org_id => casa_orgs.id)
31+
#
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: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
class UrlValidator < ActiveModel::EachValidator
2+
DEFAULT_SCHEMES = %w[http https].freeze
3+
4+
def validate_each(record, attribute, value)
5+
uri = URI.parse(value)
6+
accepted_schemes = Array.wrap(options[:scheme] || DEFAULT_SCHEMES)
7+
record.errors.add(attribute, "scheme invalid - only #{accepted_schemes.join(", ")} allowed") unless uri.scheme.in? accepted_schemes
8+
record.errors.add(attribute) if uri.host.blank?
9+
rescue URI::InvalidURIError
10+
record.errors.add(attribute)
11+
end
12+
end
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
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+
<% if @custom_org_links.count < CustomOrgLink::MAX_RECORDS_PER_ORG %>
12+
<%= link_to new_custom_org_link_path, class: "btn-sm main-btn primary-btn btn-hover" do %>
13+
<i class="lni lni-plus mr-10"></i> New Custom Link
14+
<% end %>
15+
<% else %>
16+
<button type="button" class="btn-sm main-btn light-btn" disabled>
17+
<i class="lni lni-circle-minus mr-10"></i> Link Limit Reached
18+
</button>
19+
<% end %>
20+
</span>
21+
</div>
22+
</div>
23+
</div>
24+
<div class="table-wrapper table-responsive">
25+
<table class="table striped-table">
26+
<thead>
27+
<tr>
28+
<th>Display Text</th>
29+
<th>URL</th>
30+
<th>Active?</th>
31+
<th>Actions</th>
32+
</tr>
33+
</thead>
34+
<tbody>
35+
<% @custom_org_links.each do |custom_link| %>
36+
<tr>
37+
<td><%= custom_link.text %></td>
38+
<td><%= truncate(custom_link.url, length: 90) %></td>
39+
<td><%= custom_link.active ? "Yes" : "No" %></td>
40+
<td>
41+
<%= link_to edit_custom_org_link_path(custom_link) do %>
42+
<div class="action">
43+
<button class="text-danger">
44+
<i class="lni lni-pencil-alt"></i> Edit
45+
</button>
46+
</div>
47+
<% end %>
48+
<%= link_to custom_org_link_path(custom_link), method: :delete do %>
49+
<div class="action">
50+
<button class="text-danger">
51+
<i class="lni lni-trash-can"></i> Delete
52+
</button>
53+
</div>
54+
<% end %>
55+
</td>
56+
</tr>
57+
<% end %>
58+
</tbody>
59+
</table>
60+
</div>
61+
</div>
62+
</div>
63+
</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 -->
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
<%= render partial: "form", locals: { title: "Edit Custom Link", action: 'Update' } %>

0 commit comments

Comments
 (0)