Files
chatwoot/app/controllers/dashboard_controller.rb
T
f9cc702030 fix(help-center): documentation layout on custom domain root, locale (#14850)
Help centers using the documentation layout now render correctly in two
cases that previously fell back to the wrong output. Opening a portal at
its custom-domain root (e.g. docs.example.com/ ) now shows the full
documentation home
in place instead of the classic layout, and portals whose locale is a
region variant that Chatwoot doesn't ship a
translation for (e.g. th_TH , fr_ML ) now show their categories in the
sidebar on article pages.

Closes
https://linear.app/chatwoot/issue/CW-7437/portal-layout-is-not-properly-working-in-custom-domain

## How to test

1. Create a portal with the documentation layout and a custom domain
(e.g. example.chat.test ), with at least one
category containing a published article.
2. Visit the custom-domain root ( http://example.chat.test:3000/ ) → it
should show the full documentation home
(sidebar, topbar), not the classic layout, with no redirect.
3. Set the portal's locale to a region variant Chatwoot doesn't
translate, e.g. th_TH , with categories/articles
under that locale.
4. Open an article → the sidebar should list the article's category and
sibling articles. Before the fix the sidebar
was empty for these locales.

---------

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-24 16:12:55 -07:00

124 lines
3.9 KiB
Ruby

class DashboardController < ActionController::Base
include SwitchLocale
include PortalHomeData
GLOBAL_CONFIG_KEYS = %w[
LOGO
LOGO_DARK
LOGO_THUMBNAIL
INSTALLATION_NAME
WIDGET_BRAND_URL
TERMS_URL
BRAND_URL
BRAND_NAME
PRIVACY_URL
DISPLAY_MANIFEST
CREATE_NEW_ACCOUNT_FROM_DASHBOARD
CHATWOOT_INBOX_TOKEN
API_CHANNEL_NAME
API_CHANNEL_THUMBNAIL
CLOUD_ANALYTICS_TOKEN
DIRECT_UPLOADS_ENABLED
MAXIMUM_FILE_UPLOAD_SIZE
HCAPTCHA_SITE_KEY
LOGOUT_REDIRECT_LINK
DISABLE_USER_PROFILE_UPDATE
DEPLOYMENT_ENV
INSTALLATION_PRICING_PLAN
].freeze
before_action :set_application_pack
before_action :set_global_config
before_action :set_dashboard_scripts
around_action :switch_locale
before_action :ensure_installation_onboarding, only: [:index]
before_action :render_hc_if_custom_domain, only: [:index]
before_action :ensure_html_format
layout 'vueapp'
def index; end
private
def ensure_html_format
render json: { error: 'Please use API routes instead of dashboard routes for JSON requests' }, status: :not_acceptable if request.format.json?
end
def set_global_config
@global_config = GlobalConfig.get(*GLOBAL_CONFIG_KEYS).merge(app_config)
end
def set_dashboard_scripts
@dashboard_scripts = sensitive_path? ? nil : GlobalConfig.get_value('DASHBOARD_SCRIPTS')
end
def ensure_installation_onboarding
redirect_to '/installation/onboarding' if ::Redis::Alfred.get(::Redis::Alfred::CHATWOOT_INSTALLATION_ONBOARDING)
end
def render_hc_if_custom_domain
domain = request.host
return if domain == URI.parse(ENV.fetch('FRONTEND_URL', '')).host
@portal = Portal.find_by(custom_domain: domain)
return unless @portal
@locale = @portal.default_locale
if @portal.layout == 'documentation'
request.variant = :documentation
load_home_data
end
render 'public/api/v1/portals/show', layout: 'portal', portal: @portal and return
end
def app_config
{
APP_VERSION: Chatwoot.config[:version],
VAPID_PUBLIC_KEY: VapidService.public_key,
ENABLE_ACCOUNT_SIGNUP: GlobalConfigService.load('ENABLE_ACCOUNT_SIGNUP', 'false'),
FB_APP_ID: GlobalConfigService.load('FB_APP_ID', ''),
INSTAGRAM_APP_ID: GlobalConfigService.load('INSTAGRAM_APP_ID', ''),
TIKTOK_APP_ID: GlobalConfigService.load('TIKTOK_APP_ID', ''),
FACEBOOK_API_VERSION: GlobalConfigService.load('FACEBOOK_API_VERSION', 'v18.0'),
WHATSAPP_APP_ID: GlobalConfigService.load('WHATSAPP_APP_ID', ''),
WHATSAPP_CONFIGURATION_ID: GlobalConfigService.load('WHATSAPP_CONFIGURATION_ID', ''),
IS_ENTERPRISE: ChatwootApp.enterprise?,
AZURE_APP_ID: GlobalConfigService.load('AZURE_APP_ID', ''),
GIT_SHA: GIT_HASH,
ALLOWED_LOGIN_METHODS: allowed_login_methods,
ACTIVE_PLATFORM_BANNERS: active_platform_banners
}
end
def active_platform_banners
return [] unless ChatwootApp.chatwoot_cloud?
PlatformBanner.active.order(created_at: :desc).as_json(only: %i[id banner_message banner_type updated_at])
end
def allowed_login_methods
methods = ['email']
methods << 'google_oauth' if GlobalConfigService.load('ENABLE_GOOGLE_OAUTH_LOGIN', 'true').to_s != 'false'
methods << 'saml' if ChatwootHub.pricing_plan != 'community' && GlobalConfigService.load('ENABLE_SAML_SSO_LOGIN', 'true').to_s != 'false'
methods
end
def set_application_pack
@application_pack = if request.path.include?('/auth') || request.path.include?('/login')
'v3app'
else
'dashboard'
end
end
def sensitive_path?
# dont load dashboard scripts on sensitive paths like password reset
sensitive_paths = [edit_user_password_path].freeze
# remove app prefix
current_path = request.path.gsub(%r{^/app}, '')
sensitive_paths.include?(current_path)
end
end