diff --git a/react/features/base/config/extraInterfaceConfigWhitelist.ts b/react/features/base/config/extraInterfaceConfigWhitelist.ts new file mode 100644 index 000000000000..8b221d1d9126 --- /dev/null +++ b/react/features/base/config/extraInterfaceConfigWhitelist.ts @@ -0,0 +1,4 @@ +/** + * Deploy-specific interface_config whitelists. + */ +export default []; diff --git a/react/features/base/config/interfaceConfigWhitelist.ts b/react/features/base/config/interfaceConfigWhitelist.ts index d8fe2194b28d..3d402c6041ed 100644 --- a/react/features/base/config/interfaceConfigWhitelist.ts +++ b/react/features/base/config/interfaceConfigWhitelist.ts @@ -1,3 +1,5 @@ +import extraInterfaceConfigWhitelistCopy from './extraInterfaceConfigWhitelist'; + /** * The interface config keys to whitelist, the keys that can be overridden. * @@ -45,7 +47,6 @@ export default [ 'SHARING_FEATURES', 'SHOW_CHROME_EXTENSION_BANNER', 'SHOW_POWERED_BY', - 'SUPPORT_URL', 'TILE_VIEW_MAX_COLUMNS', 'TOOLBAR_ALWAYS_VISIBLE', 'TOOLBAR_BUTTONS', @@ -54,4 +55,4 @@ export default [ 'VERTICAL_FILMSTRIP', 'VIDEO_LAYOUT_FIT', 'VIDEO_QUALITY_LABEL_DISABLED' -]; +].concat(extraInterfaceConfigWhitelistCopy); diff --git a/react/features/base/react/components/web/InlineDialogFailure.tsx b/react/features/base/react/components/web/InlineDialogFailure.tsx index ac802c2082ba..9e7150aa3d70 100644 --- a/react/features/base/react/components/web/InlineDialogFailure.tsx +++ b/react/features/base/react/components/web/InlineDialogFailure.tsx @@ -1,9 +1,11 @@ import React from 'react'; import { useTranslation } from 'react-i18next'; +import { useSelector } from 'react-redux'; import { makeStyles } from 'tss-react/mui'; import { withPixelLineHeight } from '../../../styles/functions.web'; import Button from '../../../ui/components/web/Button'; +import { getSupportUrl } from '../../functions'; const useStyles = makeStyles()(theme => { return { @@ -50,7 +52,7 @@ const InlineDialogFailure = ({ const { t } = useTranslation(); const { classes } = useStyles(); - const supportLink = interfaceConfig.SUPPORT_URL; + const supportLink = useSelector(getSupportUrl); const supportString = t('inlineDialogFailure.supportMsg'); const supportLinkElem = supportLink && showSupportLink ? ( diff --git a/react/features/base/react/functions.ts b/react/features/base/react/functions.ts index 3339f582229c..0664cc01d2e5 100644 --- a/react/features/base/react/functions.ts +++ b/react/features/base/react/functions.ts @@ -1,5 +1,8 @@ import punycode from 'punycode'; +import { IStateful } from '../app/types'; +import { toState } from '../redux/functions'; + /** * Returns the field value in a platform generic way. * @@ -47,3 +50,16 @@ export function formatURLText(text = '') { return result; } + +/** + * Returns the configured support URL. + * + * @param {IStateful} stateful - The redux state. + * @returns {string|undefined} - The configured support link. + */ +export function getSupportUrl(stateful: IStateful) { + + // TODO: Once overwriting trough interface config is completelly gone we should think of a way to be able to set + // the value in the branding and not return the default value from interface config. + return toState(stateful)['features/dynamic-branding'].supportUrl || interfaceConfig?.SUPPORT_URL; +} diff --git a/react/features/dynamic-branding/middleware.native.ts b/react/features/dynamic-branding/middleware.native.ts index adf80b244f21..c19dcff24577 100644 --- a/react/features/dynamic-branding/middleware.native.ts +++ b/react/features/dynamic-branding/middleware.native.ts @@ -25,7 +25,8 @@ MiddlewareRegistry.register(store => next => action => { didPageUrl, inviteDomain, labels, - sharedVideoAllowedURLDomains + sharedVideoAllowedURLDomains, + supportUrl } = action.value; action.value = { @@ -36,7 +37,8 @@ MiddlewareRegistry.register(store => next => action => { didPageUrl, inviteDomain, labels, - sharedVideoAllowedURLDomains + sharedVideoAllowedURLDomains, + supportUrl }; // The backend may send an empty string, make sure we skip that. diff --git a/react/features/dynamic-branding/reducer.ts b/react/features/dynamic-branding/reducer.ts index 77e8feb2db22..89c849668078 100644 --- a/react/features/dynamic-branding/reducer.ts +++ b/react/features/dynamic-branding/reducer.ts @@ -159,6 +159,7 @@ export interface IDynamicBrandingState { premeetingBackground: string; sharedVideoAllowedURLDomains?: Array; showGiphyIntegration?: boolean; + supportUrl?: string; useDynamicBrandingData: boolean; virtualBackgrounds: Array; } @@ -184,6 +185,7 @@ ReducerRegistry.register(STORE_NAME, (state = DEFAULT_STA premeetingBackground, sharedVideoAllowedURLDomains, showGiphyIntegration, + supportUrl, virtualBackgrounds } = action.value; @@ -202,6 +204,7 @@ ReducerRegistry.register(STORE_NAME, (state = DEFAULT_STA premeetingBackground, sharedVideoAllowedURLDomains, showGiphyIntegration, + supportUrl, customizationFailed: false, customizationReady: true, useDynamicBrandingData: true, diff --git a/react/features/notifications/components/web/Notification.tsx b/react/features/notifications/components/web/Notification.tsx index cb6177a5dad1..a33fdff6b3dd 100644 --- a/react/features/notifications/components/web/Notification.tsx +++ b/react/features/notifications/components/web/Notification.tsx @@ -1,6 +1,7 @@ import { Theme } from '@mui/material'; import React, { isValidElement, useCallback, useContext } from 'react'; import { useTranslation } from 'react-i18next'; +import { useSelector } from 'react-redux'; import { keyframes } from 'tss-react'; import { makeStyles } from 'tss-react/mui'; @@ -15,6 +16,7 @@ import { IconWarningCircle } from '../../../base/icons/svg'; import Message from '../../../base/react/components/web/Message'; +import { getSupportUrl } from '../../../base/react/functions'; import { withPixelLineHeight } from '../../../base/styles/functions.web'; import { NOTIFICATION_ICON, NOTIFICATION_TYPE } from '../../constants'; import { INotificationProps } from '../../types'; @@ -190,6 +192,7 @@ const Notification = ({ const { classes, cx, theme } = useStyles(); const { t } = useTranslation(); const { unmounting } = useContext(NotificationsTransitionContext); + const supportUrl = useSelector(getSupportUrl); const ICON_COLOR = { error: theme.palette.iconError, @@ -229,9 +232,9 @@ const Notification = ({ ); }, [ description, descriptionArguments, descriptionKey, classes ]); - const _onOpenSupportLink = () => { - window.open(interfaceConfig.SUPPORT_URL, '_blank', 'noopener'); - }; + const _onOpenSupportLink = useCallback(() => { + window.open(supportUrl, '_blank', 'noopener'); + }, [ supportUrl ]); const mapAppearanceToButtons = useCallback((): { content: string; onClick: () => void; testId?: string; type?: string; }[] => { @@ -244,7 +247,7 @@ const Notification = ({ } ]; - if (!hideErrorSupportLink && interfaceConfig.SUPPORT_URL) { + if (!hideErrorSupportLink && supportUrl) { buttons.push({ content: t('dialog.contactSupport'), onClick: _onOpenSupportLink @@ -279,7 +282,7 @@ const Notification = ({ return []; } - }, [ appearance, onDismiss, customActionHandler, customActionNameKey, hideErrorSupportLink ]); + }, [ appearance, onDismiss, customActionHandler, customActionNameKey, hideErrorSupportLink, supportUrl ]); const getIcon = useCallback(() => { let iconToDisplay; @@ -313,7 +316,7 @@ const Notification = ({