Add setting to set logo URL (#410)

This commit is contained in:
Riccardo Graziosi
2024-09-16 18:48:18 +02:00
committed by GitHub
parent 5780d8494e
commit 63b3b4050a
16 changed files with 156 additions and 33 deletions

View File

@@ -34,6 +34,10 @@
}
}
.brandDisabled {
pointer-events: none;
}
.navbarToggler {
@extend .navbar-toggler;

View File

@@ -56,6 +56,18 @@
.anonymousFeedbackLink {
@extend .my-2;
}
/* style lists */
ul {
width: fit-content;
margin: 0 auto;
margin-bottom: 1rem;
li {
text-align: left;
position: relative;
left: -8px;
}
}
}
.sidebarFilters {

View File

@@ -2,6 +2,7 @@ require 'uri'
class ApplicationController < ActionController::Base
include ApplicationHelper
include HeaderHelper
include Pundit::Authorization
rescue_from Pundit::NotAuthorizedError, with: :user_not_authorized

View File

@@ -0,0 +1,11 @@
module HeaderHelper
def get_url_for_logo
if Current.tenant.tenant_setting.logo_links_to == "root_page"
@header_full_urls ? get_url_for(method(:root_url)) : root_path
elsif Current.tenant.tenant_setting.logo_links_to == "custom_url"
Current.tenant.tenant_setting.logo_custom_url
else
nil
end
end
end

View File

@@ -13,6 +13,9 @@ import {
TENANT_SETTING_BRAND_DISPLAY_NONE,
TENANT_SETTING_COLLAPSE_BOARDS_IN_HEADER_NO_COLLAPSE,
TENANT_SETTING_COLLAPSE_BOARDS_IN_HEADER_ALWAYS_COLLAPSE,
TENANT_SETTING_LOGO_LINKS_TO_ROOT_PAGE,
TENANT_SETTING_LOGO_LINKS_TO_CUSTOM_URL,
TENANT_SETTING_LOGO_LINKS_TO_NOTHING,
} from '../../../interfaces/ITenantSetting';
import { DangerText, SmallMutedText } from '../../common/CustomTexts';
import { getLabel, getValidationMessage } from '../../../helpers/formUtils';
@@ -31,6 +34,8 @@ export interface ISiteSettingsGeneralForm {
isPrivate: boolean;
allowAnonymousFeedback: boolean;
feedbackApprovalPolicy: string;
logoLinksTo: string;
logoCustomUrl?: string;
showRoadmapInHeader: boolean;
collapseBoardsInHeader: string;
showVoteCount: boolean;
@@ -58,6 +63,8 @@ interface Props {
isPrivate: boolean,
allowAnonymousFeedback: boolean,
feedbackApprovalPolicy: string,
logoLinksTo: string,
logoCustomUrl: string,
showRoadmapInHeader: boolean,
collapseBoardsInHeader: string,
showVoteCount: boolean,
@@ -94,6 +101,8 @@ const GeneralSiteSettingsP = ({
isPrivate: originForm.isPrivate,
allowAnonymousFeedback: originForm.allowAnonymousFeedback,
feedbackApprovalPolicy: originForm.feedbackApprovalPolicy,
logoLinksTo: originForm.logoLinksTo,
logoCustomUrl: originForm.logoCustomUrl,
showRoadmapInHeader: originForm.showRoadmapInHeader,
collapseBoardsInHeader: originForm.collapseBoardsInHeader,
showVoteCount: originForm.showVoteCount,
@@ -114,6 +123,8 @@ const GeneralSiteSettingsP = ({
data.isPrivate,
data.allowAnonymousFeedback,
data.feedbackApprovalPolicy,
data.logoLinksTo,
data.logoCustomUrl,
data.showRoadmapInHeader,
data.collapseBoardsInHeader,
data.showVoteCount,
@@ -301,29 +312,59 @@ const GeneralSiteSettingsP = ({
<div className="formGroup">
<label htmlFor="feedbackApprovalPolicy">{ getLabel('tenant_setting', 'feedback_approval_policy') }</label>
<select
{...register('feedbackApprovalPolicy')}
id="feedbackApprovalPolicy"
className="selectPicker"
>
<option value="anonymous_require_approval">
{ I18n.t('site_settings.general.feedback_approval_policy_anonymous_require_approval') }
</option>
<option value="never_require_approval">
{ I18n.t('site_settings.general.feedback_approval_policy_never_require_approval') }
</option>
<option value="always_require_approval">
{ I18n.t('site_settings.general.feedback_approval_policy_always_require_approval') }
</option>
</select>
<SmallMutedText>
{ I18n.t('site_settings.general.feedback_approval_policy_help') }
</SmallMutedText>
<select
{...register('feedbackApprovalPolicy')}
id="feedbackApprovalPolicy"
className="selectPicker"
>
<option value="anonymous_require_approval">
{ I18n.t('site_settings.general.feedback_approval_policy_anonymous_require_approval') }
</option>
<option value="never_require_approval">
{ I18n.t('site_settings.general.feedback_approval_policy_never_require_approval') }
</option>
<option value="always_require_approval">
{ I18n.t('site_settings.general.feedback_approval_policy_always_require_approval') }
</option>
</select>
<SmallMutedText>
{ I18n.t('site_settings.general.feedback_approval_policy_help') }
</SmallMutedText>
</div>
</div>
<div id="header" className="settingsGroup">
<h4>{ I18n.t('site_settings.general.subtitle_header') }</h4>
<div className="formGroup">
<label htmlFor="logoLinksTo">{ getLabel('tenant_setting', 'logo_links_to') }</label>
<select
{...register('logoLinksTo')}
id="logoLinksTo"
className="selectPicker"
>
<option value={TENANT_SETTING_LOGO_LINKS_TO_ROOT_PAGE}>
{ I18n.t('site_settings.general.logo_links_to_root_page') }
</option>
<option value={TENANT_SETTING_LOGO_LINKS_TO_CUSTOM_URL}>
{ I18n.t('site_settings.general.logo_links_to_custom_url') }
</option>
<option value={TENANT_SETTING_LOGO_LINKS_TO_NOTHING}>
{ I18n.t('site_settings.general.logo_links_to_nothing') }
</option>
</select>
</div>
{ watch('logoLinksTo') === TENANT_SETTING_LOGO_LINKS_TO_CUSTOM_URL &&
<div className="formGroup">
<label htmlFor="logoCustomUrl">{ getLabel('tenant_setting', 'logo_custom_url') }</label>
<input
{...register('logoCustomUrl')}
id="logoCustomUrl"
className="formControl"
/>
</div>
}
<div className="formGroup">
<div className="checkboxSwitch">
@@ -334,18 +375,18 @@ const GeneralSiteSettingsP = ({
<div className="formGroup">
<label htmlFor="collapseBoardsInHeader">{ getLabel('tenant_setting', 'collapse_boards_in_header') }</label>
<select
{...register('collapseBoardsInHeader')}
id="collapseBoardsInHeader"
className="selectPicker"
>
<option value={TENANT_SETTING_COLLAPSE_BOARDS_IN_HEADER_NO_COLLAPSE}>
{ I18n.t('site_settings.general.collapse_boards_in_header_no_collapse') }
</option>
<option value={TENANT_SETTING_COLLAPSE_BOARDS_IN_HEADER_ALWAYS_COLLAPSE}>
{ I18n.t('site_settings.general.collapse_boards_in_header_always_collapse') }
</option>
</select>
<select
{...register('collapseBoardsInHeader')}
id="collapseBoardsInHeader"
className="selectPicker"
>
<option value={TENANT_SETTING_COLLAPSE_BOARDS_IN_HEADER_NO_COLLAPSE}>
{ I18n.t('site_settings.general.collapse_boards_in_header_no_collapse') }
</option>
<option value={TENANT_SETTING_COLLAPSE_BOARDS_IN_HEADER_ALWAYS_COLLAPSE}>
{ I18n.t('site_settings.general.collapse_boards_in_header_always_collapse') }
</option>
</select>
</div>
</div>

View File

@@ -3,7 +3,12 @@ import { connect } from "react-redux";
import GeneralSiteSettingsP from "../components/SiteSettings/General/GeneralSiteSettingsP";
import { updateTenant } from "../actions/Tenant/updateTenant";
import { State } from "../reducers/rootReducer";
import { TenantSettingBrandDisplay, TenantSettingCollapseBoardsInHeader, TenantSettingFeedbackApprovalPolicy } from "../interfaces/ITenantSetting";
import {
TenantSettingBrandDisplay,
TenantSettingCollapseBoardsInHeader,
TenantSettingFeedbackApprovalPolicy,
TenantSettingLogoLinksTo,
} from "../interfaces/ITenantSetting";
const mapStateToProps = (state: State) => ({
areUpdating: state.siteSettings.general.areUpdating,
@@ -22,6 +27,8 @@ const mapDispatchToProps = (dispatch: any) => ({
isPrivate: boolean,
allowAnonymousFeedback: boolean,
feedbackApprovalPolicy: TenantSettingFeedbackApprovalPolicy,
logoLinksTo: TenantSettingLogoLinksTo,
logoCustomUrl: string,
showRoadmapInHeader: boolean,
collapseBoardsInHeader: TenantSettingCollapseBoardsInHeader,
showVoteCount: boolean,
@@ -39,6 +46,8 @@ const mapDispatchToProps = (dispatch: any) => ({
is_private: isPrivate,
allow_anonymous_feedback: allowAnonymousFeedback,
feedback_approval_policy: feedbackApprovalPolicy,
logo_links_to: logoLinksTo,
logo_custom_url: logoCustomUrl,
show_roadmap_in_header: showRoadmapInHeader,
collapse_boards_in_header: collapseBoardsInHeader,
show_vote_count: showVoteCount,

View File

@@ -30,6 +30,16 @@ export type TenantSettingFeedbackApprovalPolicy =
typeof TENANT_SETTING_FEEDBACK_APPROVAL_POLICY_NEVER_REQUIRE_APPROVAL |
typeof TENANT_SETTING_FEEDBACK_APPROVAL_POLICY_ALWAYS_REQUIRE_APPROVAL;
// Logo links to
export const TENANT_SETTING_LOGO_LINKS_TO_ROOT_PAGE = 'root_page';
export const TENANT_SETTING_LOGO_LINKS_TO_CUSTOM_URL = 'custom_url';
export const TENANT_SETTING_LOGO_LINKS_TO_NOTHING = 'nothing';
export type TenantSettingLogoLinksTo =
typeof TENANT_SETTING_LOGO_LINKS_TO_ROOT_PAGE |
typeof TENANT_SETTING_LOGO_LINKS_TO_CUSTOM_URL |
typeof TENANT_SETTING_LOGO_LINKS_TO_NOTHING;
// Collapse boards in header
export const TENANT_SETTING_COLLAPSE_BOARDS_IN_HEADER_NO_COLLAPSE = 'no_collapse';
export const TENANT_SETTING_COLLAPSE_BOARDS_IN_HEADER_ALWAYS_COLLAPSE = 'always_collapse';
@@ -53,6 +63,8 @@ interface ITenantSetting {
show_roadmap_in_header?: boolean;
show_powered_by?: boolean;
collapse_boards_in_header?: TenantSettingCollapseBoardsInHeader;
logo_links_to?: TenantSettingLogoLinksTo;
logo_custom_url?: string;
custom_css?: string;
}

View File

@@ -12,6 +12,12 @@ class TenantSetting < ApplicationRecord
:no_name_no_logo
]
enum logo_links_to: [
:root_page,
:custom_url,
:nothing
]
enum collapse_boards_in_header: [
:no_collapse,
:always_collapse

View File

@@ -13,6 +13,8 @@ class TenantSettingPolicy < ApplicationPolicy
:show_vote_count,
:show_vote_button_in_board,
:show_powered_by,
:logo_links_to,
:logo_custom_url,
:show_roadmap_in_header,
:collapse_boards_in_header,
:custom_css

View File

@@ -1,7 +1,7 @@
<nav class="header">
<div class="container">
<%=
link_to @header_full_urls ? get_url_for(method(:root_url)) : root_path, class: 'brand' do
link_to get_url_for_logo, class: "brand#{@tenant_setting.logo_links_to == 'nothing' ? ' brandDisabled' : ''}", tabindex: @tenant_setting.logo_links_to == 'nothing' ? -1 : 0 do
app_name = content_tag :span, @tenant.site_name
logo = image_tag(@tenant.site_logo ? @tenant.site_logo : "", class: 'logo', skip_pipeline: true)

View File

@@ -17,6 +17,8 @@
isPrivate: @tenant_setting.is_private,
allowAnonymousFeedback: @tenant_setting.allow_anonymous_feedback,
feedbackApprovalPolicy: @tenant_setting.feedback_approval_policy,
logoLinksTo: @tenant_setting.logo_links_to,
logoCustomUrl: @tenant_setting.logo_custom_url,
showRoadmapInHeader: @tenant_setting.show_roadmap_in_header,
collapseBoardsInHeader: @tenant_setting.collapse_boards_in_header,
locale: @tenant.locale,

View File

@@ -135,6 +135,8 @@ en:
show_vote_button_in_board: 'Show vote buttons in board page'
show_powered_by: 'Show "Powered by Astuto"'
root_board_id: 'Root page'
logo_links_to: 'Logo links to'
logo_custom_url: 'Logo custom URL'
show_roadmap_in_header: 'Show roadmap link in header'
collapse_boards_in_header: 'Collapse boards in header'
custom_css: 'Custom CSS'

View File

@@ -196,6 +196,9 @@ en:
feedback_approval_policy_always_require_approval: 'Always require approval'
feedback_approval_policy_help: 'If you require approval, submitted feedback will remain hidden from the public until a moderator or administrator approves it. Feedback submitted by moderators and administrators is always approved automatically.'
subtitle_header: 'Header'
logo_links_to_root_page: 'Root page'
logo_links_to_custom_url: 'Custom URL'
logo_links_to_nothing: 'Nothing'
collapse_boards_in_header_no_collapse: 'Never'
collapse_boards_in_header_always_collapse: 'Always'
subtitle_visibility: 'Visibility'

View File

@@ -0,0 +1,6 @@
class AddLogoLinksToToTenantSettings < ActiveRecord::Migration[6.1]
def change
add_column :tenant_settings, :logo_links_to, :integer, default: 0, null: false
add_column :tenant_settings, :logo_custom_url, :string
end
end

View File

@@ -10,7 +10,7 @@
#
# It's strongly recommended that you check this file into your version control system.
ActiveRecord::Schema.define(version: 2024_09_08_121603) do
ActiveRecord::Schema.define(version: 2024_09_16_140807) do
# These are extensions that must be enabled in order to support this database
enable_extension "plpgsql"
@@ -183,6 +183,8 @@ ActiveRecord::Schema.define(version: 2024_09_08_121603) do
t.integer "email_registration_policy", default: 0, null: false
t.string "allowed_email_domains"
t.boolean "use_browser_locale", default: false, null: false
t.integer "logo_links_to", default: 0, null: false
t.string "logo_custom_url"
t.index ["tenant_id"], name: "index_tenant_settings_on_tenant_id"
end

View File

@@ -80,4 +80,14 @@ RSpec.describe TenantSetting, type: :model do
tenant_setting.email_registration_policy = 'custom_domains_allowed'
expect(tenant_setting).to be_valid
end
it 'has a setting for logo links to' do
expect(tenant_setting.logo_links_to).to eq('root_page')
tenant_setting.logo_links_to = 'custom_url'
expect(tenant_setting).to be_valid
tenant_setting.logo_links_to = 'nothing'
expect(tenant_setting).to be_valid
end
end