From 4e602164368132a47d867852f1e6243c1866bbbd Mon Sep 17 00:00:00 2001 From: Sanjeev Lakhwani Date: Mon, 28 Sep 2026 13:39:00 -0400 Subject: [PATCH] feat: add dev settings float button with PCGL mode toggle Shown only when BENTO_PUBLIC_SHOW_DEV_SETTINGS is true, so it can be enabled on staging without the dev flag. Overrides are stored in localStorage and ignored when the flag is off. --- src/app/public/config.js/route.ts | 1 + src/js/App.tsx | 11 +++++- .../Util/DevSettingsFloatButton.tsx | 35 +++++++++++++++++++ src/js/config.ts | 25 ++++++++++++- src/js/constants/ui.ts | 1 + src/styles.css | 7 ++++ 6 files changed, 78 insertions(+), 2 deletions(-) create mode 100644 src/js/components/Util/DevSettingsFloatButton.tsx diff --git a/src/app/public/config.js/route.ts b/src/app/public/config.js/route.ts index 258821ecd..d26a963e5 100644 --- a/src/app/public/config.js/route.ts +++ b/src/app/public/config.js/route.ts @@ -26,6 +26,7 @@ export function GET() { SHOW_SIGN_IN: parseBoolean(process.env.BENTO_PUBLIC_SHOW_SIGN_IN), FORCE_CATALOGUE: parseBoolean(process.env.BENTO_PUBLIC_FORCE_CATALOGUE), // Show data catalogue even with 1 project PCGL_MODE: parseBoolean(process.env.BENTO_PUBLIC_PCGL_MODE), + SHOW_DEV_SETTINGS: parseBoolean(process.env.BENTO_PUBLIC_SHOW_DEV_SETTINGS), // Dev/staging testing only // Theme variables CATALOGUE_HEADER_BACKGROUND: process.env.BENTO_PUBLIC_CATALOGUE_HEADER_BACKGROUND, diff --git a/src/js/App.tsx b/src/js/App.tsx index 9c91a5961..19f68f1ba 100644 --- a/src/js/App.tsx +++ b/src/js/App.tsx @@ -24,6 +24,7 @@ import BentoAppRouter from '@/components/BentoAppRouter'; import LanguageHandler from '@/components/Util/LanguageHandler'; import AuthOutlet from '@/components/Util/AuthOutlet'; import ResponsiveProvider from '@/components/Util/ResponsiveProvider'; +import DevSettingsFloatButton from '@/components/Util/DevSettingsFloatButton'; // Hooks and utilities imports import { BentoAuthContext } from 'bento-auth-js'; @@ -32,7 +33,14 @@ import { useSmallScreen } from '@/hooks/useResponsiveContext'; // Store and configuration imports import { store } from './store'; -import { AUTH_CALLBACK_URL, CLIENT_ID, OPENID_CONFIG_URL, PCGL_MODE, PUBLIC_URL_NO_TRAILING_SLASH } from './config'; +import { + AUTH_CALLBACK_URL, + CLIENT_ID, + OPENID_CONFIG_URL, + PCGL_MODE, + PUBLIC_URL_NO_TRAILING_SLASH, + SHOW_DEV_SETTINGS, +} from './config'; // Styles imports import 'antd/dist/reset.css'; @@ -86,6 +94,7 @@ const InnerRootApp = () => { > + {SHOW_DEV_SETTINGS && } diff --git a/src/js/components/Util/DevSettingsFloatButton.tsx b/src/js/components/Util/DevSettingsFloatButton.tsx new file mode 100644 index 000000000..916780a28 --- /dev/null +++ b/src/js/components/Util/DevSettingsFloatButton.tsx @@ -0,0 +1,35 @@ +import { FloatButton } from 'antd'; +import { SettingOutlined } from '@ant-design/icons'; + +import { CONFIGURED_PCGL_MODE, DEV_SETTINGS, type DevSettings, PCGL_MODE } from '@/config'; +import { LOCALSTORAGE_DEV_SETTINGS_KEY } from '@/constants/ui'; +import { saveValue } from '@/utils/localStorage'; + +// Config values are read once at module load (i18n namespaces, facet registry, etc.), so any change requires a reload. +const updateDevSettings = (update: DevSettings) => { + saveValue(LOCALSTORAGE_DEV_SETTINGS_KEY, { ...DEV_SETTINGS, ...update }); + window.location.reload(); +}; + +/** Floating settings menu for dev/staging testing; only rendered when BENTO_PUBLIC_SHOW_DEV_SETTINGS is true. */ +const DevSettingsFloatButton = () => ( + } + tooltip={{ title: 'Dev settings', placement: 'right' }} + > + updateDevSettings({ PCGL_MODE: !PCGL_MODE })} + /> + +); + +export default DevSettingsFloatButton; diff --git a/src/js/config.ts b/src/js/config.ts index 8824d6071..86398b19e 100644 --- a/src/js/config.ts +++ b/src/js/config.ts @@ -1,4 +1,5 @@ import { stringToBoolean } from '@/utils/strings'; +import { LOCALSTORAGE_DEV_SETTINGS_KEY } from '@/constants/ui'; export interface PublicConfig { // General @@ -15,6 +16,7 @@ export interface PublicConfig { SHOW_SIGN_IN: boolean; FORCE_CATALOGUE: boolean; // Show data catalogue even with 1 project PCGL_MODE: boolean; // Puts Bento Public in "PCGL mode", turning it into the PCGL research portal + SHOW_DEV_SETTINGS: boolean; // Show a floating dev settings button for overriding config at runtime (testing only) // Theme variables CATALOGUE_HEADER_BACKGROUND: string | undefined; CATALOGUE_HEADER_TEXT_COLOR: string | undefined; @@ -54,7 +56,28 @@ export const SHOW_ADMIN_LINK = export const SHOW_SIGN_IN = BENTO_PUBLIC_CONFIG.SHOW_SIGN_IN ?? stringToBoolean(process.env.BENTO_PUBLIC_SHOW_SIGN_IN); export const FORCE_CATALOGUE = BENTO_PUBLIC_CONFIG.FORCE_CATALOGUE ?? stringToBoolean(process.env.BENTO_PUBLIC_FORCE_CATALOGUE); -export const PCGL_MODE = BENTO_PUBLIC_CONFIG.PCGL_MODE ?? stringToBoolean(process.env.BENTO_PUBLIC_PCGL_MODE); +export const SHOW_DEV_SETTINGS = + BENTO_PUBLIC_CONFIG.SHOW_DEV_SETTINGS ?? stringToBoolean(process.env.BENTO_PUBLIC_SHOW_DEV_SETTINGS); + +// Runtime overrides set via the dev settings float button; only honoured when dev settings are enabled, so stale +// localStorage values can't affect deployments without the flag. +export interface DevSettings { + PCGL_MODE?: boolean; +} +const readDevSettings = (): DevSettings => { + if (!SHOW_DEV_SETTINGS) return {}; + try { + const parsed = JSON.parse(localStorage.getItem(LOCALSTORAGE_DEV_SETTINGS_KEY) ?? '{}'); + return parsed && typeof parsed === 'object' ? parsed : {}; + } catch { + return {}; + } +}; +export const DEV_SETTINGS = readDevSettings(); + +export const CONFIGURED_PCGL_MODE = + BENTO_PUBLIC_CONFIG.PCGL_MODE ?? stringToBoolean(process.env.BENTO_PUBLIC_PCGL_MODE); +export const PCGL_MODE = DEV_SETTINGS.PCGL_MODE ?? CONFIGURED_PCGL_MODE; // Beacon configuration and flags export const BEACON_URL = BENTO_PUBLIC_CONFIG.BEACON_URL ?? process.env.BEACON_URL; diff --git a/src/js/constants/ui.ts b/src/js/constants/ui.ts index f00887fd4..e7cf16c20 100644 --- a/src/js/constants/ui.ts +++ b/src/js/constants/ui.ts @@ -1 +1,2 @@ export const LOCALSTORAGE_UI_SETTINGS_KEY = 'BENTO_UI_SETTINGS'; +export const LOCALSTORAGE_DEV_SETTINGS_KEY = 'BENTO_DEV_SETTINGS'; diff --git a/src/styles.css b/src/styles.css index bc164a466..ade08408e 100644 --- a/src/styles.css +++ b/src/styles.css @@ -1986,3 +1986,10 @@ button.pm-sec-head { cursor: pointer; } .pm-body { grid-template-columns: 1fr; } .pm-body::before { display: none; } } + +.dev-settings-float-btn { + /* Sit above the Next.js dev indicator, which is also pinned bottom-left */ + bottom: 6em; + left: 2em; + inset-inline-end: auto; +}