mirror of
https://github.com/Unleash/unleash.git
synced 2025-06-27 01:19:00 +02:00
feat: use Unleash React SDK in Admin UI (#9723)
In this PR I integrate the Unleash React SDK with the Admin UI. We also take advantage of Unleash Hosted Edge behind the scenes with multiple regions to get the evaluations close to the end user.
This commit is contained in:
parent
09c3f1ab40
commit
e63b28c1b8
@ -7,6 +7,7 @@
|
|||||||
<meta name="baseUriPath" content="::baseUriPath::" />
|
<meta name="baseUriPath" content="::baseUriPath::" />
|
||||||
<meta name="cdnPrefix" content="::cdnPrefix::" />
|
<meta name="cdnPrefix" content="::cdnPrefix::" />
|
||||||
<meta name="uiFlags" content="::uiFlags::" />
|
<meta name="uiFlags" content="::uiFlags::" />
|
||||||
|
<meta name="unleashToken" content="::unleashToken::" />
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||||
<meta name="description" content="unleash" />
|
<meta name="description" content="unleash" />
|
||||||
<title>Unleash</title>
|
<title>Unleash</title>
|
||||||
|
@ -69,6 +69,7 @@
|
|||||||
"@types/uuid": "^9.0.0",
|
"@types/uuid": "^9.0.0",
|
||||||
"@uiw/codemirror-theme-duotone": "4.23.10",
|
"@uiw/codemirror-theme-duotone": "4.23.10",
|
||||||
"@uiw/react-codemirror": "4.23.10",
|
"@uiw/react-codemirror": "4.23.10",
|
||||||
|
"@unleash/proxy-client-react": "^5.0.0",
|
||||||
"@vitejs/plugin-react": "4.3.4",
|
"@vitejs/plugin-react": "4.3.4",
|
||||||
"cartesian": "^1.0.1",
|
"cartesian": "^1.0.1",
|
||||||
"chart.js": "3.9.1",
|
"chart.js": "3.9.1",
|
||||||
@ -118,6 +119,7 @@
|
|||||||
"swr": "2.3.3",
|
"swr": "2.3.3",
|
||||||
"tss-react": "4.9.15",
|
"tss-react": "4.9.15",
|
||||||
"typescript": "5.4.5",
|
"typescript": "5.4.5",
|
||||||
|
"unleash-proxy-client": "^3.7.3",
|
||||||
"use-query-params": "^2.2.1",
|
"use-query-params": "^2.2.1",
|
||||||
"vanilla-jsoneditor": "^0.23.0",
|
"vanilla-jsoneditor": "^0.23.0",
|
||||||
"vite": "5.4.16",
|
"vite": "5.4.16",
|
||||||
|
@ -28,8 +28,9 @@ import { ReactComponent as CelebatoryUnleashLogo } from 'assets/img/unleashHolid
|
|||||||
import { ReactComponent as CelebatoryUnleashLogoWhite } from 'assets/img/unleashHolidayDark.svg';
|
import { ReactComponent as CelebatoryUnleashLogoWhite } from 'assets/img/unleashHolidayDark.svg';
|
||||||
import { ReactComponent as LogoOnlyWhite } from 'assets/img/logo.svg';
|
import { ReactComponent as LogoOnlyWhite } from 'assets/img/logo.svg';
|
||||||
import { ReactComponent as LogoOnly } from 'assets/img/logoDark.svg';
|
import { ReactComponent as LogoOnly } from 'assets/img/logoDark.svg';
|
||||||
import { useUiFlag } from 'hooks/useUiFlag';
|
|
||||||
import { Link } from 'react-router-dom';
|
import { Link } from 'react-router-dom';
|
||||||
|
import { useFlag } from '@unleash/proxy-client-react';
|
||||||
|
import { useUiFlag } from 'hooks/useUiFlag';
|
||||||
|
|
||||||
export const MobileNavigationSidebar: FC<{
|
export const MobileNavigationSidebar: FC<{
|
||||||
onClick: () => void;
|
onClick: () => void;
|
||||||
@ -110,7 +111,7 @@ export const NavigationSidebar: FC<{ NewInUnleash?: typeof NewInUnleash }> = ({
|
|||||||
NewInUnleash,
|
NewInUnleash,
|
||||||
}) => {
|
}) => {
|
||||||
const { routes } = useRoutes();
|
const { routes } = useRoutes();
|
||||||
const celebatoryUnleash = useUiFlag('celebrateUnleash');
|
const celebrateUnleashFrontend = useFlag('celebrateUnleashFrontend');
|
||||||
|
|
||||||
const [mode, setMode] = useNavigationMode();
|
const [mode, setMode] = useNavigationMode();
|
||||||
const [expanded, changeExpanded] = useExpanded<'configure' | 'admin'>();
|
const [expanded, changeExpanded] = useExpanded<'configure' | 'admin'>();
|
||||||
@ -138,7 +139,7 @@ export const NavigationSidebar: FC<{ NewInUnleash?: typeof NewInUnleash }> = ({
|
|||||||
<ThemeMode
|
<ThemeMode
|
||||||
darkmode={
|
darkmode={
|
||||||
<ConditionallyRender
|
<ConditionallyRender
|
||||||
condition={celebatoryUnleash}
|
condition={celebrateUnleashFrontend}
|
||||||
show={<CelebatoryUnleashLogoWhite />}
|
show={<CelebatoryUnleashLogoWhite />}
|
||||||
elseShow={
|
elseShow={
|
||||||
<StyledUnleashLogoWhite aria-label='Unleash logo' />
|
<StyledUnleashLogoWhite aria-label='Unleash logo' />
|
||||||
@ -147,7 +148,7 @@ export const NavigationSidebar: FC<{ NewInUnleash?: typeof NewInUnleash }> = ({
|
|||||||
}
|
}
|
||||||
lightmode={
|
lightmode={
|
||||||
<ConditionallyRender
|
<ConditionallyRender
|
||||||
condition={celebatoryUnleash}
|
condition={celebrateUnleashFrontend}
|
||||||
show={<StyledCelebatoryLogo />}
|
show={<StyledCelebatoryLogo />}
|
||||||
elseShow={
|
elseShow={
|
||||||
<StyledUnleashLogo aria-label='Unleash logo' />
|
<StyledUnleashLogo aria-label='Unleash logo' />
|
||||||
|
@ -0,0 +1,56 @@
|
|||||||
|
import type React from 'react';
|
||||||
|
import { type FC, useEffect } from 'react';
|
||||||
|
import useUiConfig from 'hooks/api/getters/useUiConfig/useUiConfig';
|
||||||
|
import FlagProvider, { UnleashClient } from '@unleash/proxy-client-react';
|
||||||
|
|
||||||
|
const UNLEASH_API = 'https://hosted.edge.getunleash.io/api/frontend';
|
||||||
|
const DEV_TOKEN = '';
|
||||||
|
|
||||||
|
let client: UnleashClient;
|
||||||
|
let token: string;
|
||||||
|
let started: boolean = false;
|
||||||
|
|
||||||
|
export const UnleashFlagProvider: FC<{ children?: React.ReactNode }> = ({
|
||||||
|
children,
|
||||||
|
}) => {
|
||||||
|
const getUnleashFrontendToken = (): string => {
|
||||||
|
const el = document.querySelector<HTMLMetaElement>(
|
||||||
|
'meta[name="unleashToken"]',
|
||||||
|
);
|
||||||
|
|
||||||
|
const content = el?.content ?? '::unleashToken::';
|
||||||
|
return content === '::unleashToken::' ? DEV_TOKEN : content;
|
||||||
|
};
|
||||||
|
|
||||||
|
// We only want to create a single client.
|
||||||
|
if (!client) {
|
||||||
|
token = getUnleashFrontendToken();
|
||||||
|
|
||||||
|
client = new UnleashClient({
|
||||||
|
url: UNLEASH_API,
|
||||||
|
clientKey: token || 'offline',
|
||||||
|
refreshInterval: 1,
|
||||||
|
appName: 'Unleash Cloud UI',
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const { uiConfig } = useUiConfig();
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (uiConfig.unleashContext && token) {
|
||||||
|
client.updateContext(uiConfig.unleashContext);
|
||||||
|
if (!started) {
|
||||||
|
started = true;
|
||||||
|
client.start();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// nothing
|
||||||
|
}
|
||||||
|
}, [uiConfig.unleashContext]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<FlagProvider unleashClient={client} startClient={false}>
|
||||||
|
{children}
|
||||||
|
</FlagProvider>
|
||||||
|
);
|
||||||
|
};
|
@ -22,6 +22,7 @@ import { Error as LayoutError } from './component/layout/Error/Error';
|
|||||||
import { ErrorBoundary } from 'react-error-boundary';
|
import { ErrorBoundary } from 'react-error-boundary';
|
||||||
import { useRecordUIErrorApi } from 'hooks/api/actions/useRecordUIErrorApi/useRecordUiErrorApi';
|
import { useRecordUIErrorApi } from 'hooks/api/actions/useRecordUIErrorApi/useRecordUiErrorApi';
|
||||||
import { HighlightProvider } from 'component/common/Highlight/HighlightProvider';
|
import { HighlightProvider } from 'component/common/Highlight/HighlightProvider';
|
||||||
|
import { UnleashFlagProvider } from 'component/providers/UnleashFlagProvider/UnleashFlagProvider';
|
||||||
|
|
||||||
window.global ||= window;
|
window.global ||= window;
|
||||||
|
|
||||||
@ -50,6 +51,7 @@ const ApplicationRoot = () => {
|
|||||||
<ThemeProvider>
|
<ThemeProvider>
|
||||||
<AnnouncerProvider>
|
<AnnouncerProvider>
|
||||||
<PlausibleProvider>
|
<PlausibleProvider>
|
||||||
|
<UnleashFlagProvider>
|
||||||
<ErrorBoundary
|
<ErrorBoundary
|
||||||
FallbackComponent={LayoutError}
|
FallbackComponent={LayoutError}
|
||||||
onError={sendErrorToApi}
|
onError={sendErrorToApi}
|
||||||
@ -67,6 +69,7 @@ const ApplicationRoot = () => {
|
|||||||
</FeedbackCESProvider>
|
</FeedbackCESProvider>
|
||||||
</FeedbackProvider>
|
</FeedbackProvider>
|
||||||
</ErrorBoundary>
|
</ErrorBoundary>
|
||||||
|
</UnleashFlagProvider>
|
||||||
</PlausibleProvider>
|
</PlausibleProvider>
|
||||||
</AnnouncerProvider>
|
</AnnouncerProvider>
|
||||||
</ThemeProvider>
|
</ThemeProvider>
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
import type { ReactNode } from 'react';
|
import type { ReactNode } from 'react';
|
||||||
import type { Variant } from 'utils/variants';
|
import type { Variant } from 'utils/variants';
|
||||||
import type { ResourceLimitsSchema } from '../openapi';
|
import type { ResourceLimitsSchema } from '../openapi';
|
||||||
|
import {} from '@unleash/proxy-client-react/dist/FlagContext';
|
||||||
|
import type { IMutableContext } from 'unleash-proxy-client';
|
||||||
|
|
||||||
export interface IUiConfig {
|
export interface IUiConfig {
|
||||||
authenticationType?: string;
|
authenticationType?: string;
|
||||||
@ -34,6 +36,7 @@ export interface IUiConfig {
|
|||||||
oidcConfiguredThroughEnv?: boolean;
|
oidcConfiguredThroughEnv?: boolean;
|
||||||
samlConfiguredThroughEnv?: boolean;
|
samlConfiguredThroughEnv?: boolean;
|
||||||
maxSessionsCount?: number;
|
maxSessionsCount?: number;
|
||||||
|
unleashContext?: IMutableContext;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IProclamationToast {
|
export interface IProclamationToast {
|
||||||
|
@ -3371,6 +3371,15 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
|
"@unleash/proxy-client-react@npm:^5.0.0":
|
||||||
|
version: 5.0.0
|
||||||
|
resolution: "@unleash/proxy-client-react@npm:5.0.0"
|
||||||
|
peerDependencies:
|
||||||
|
unleash-proxy-client: ^3.7.3
|
||||||
|
checksum: 10c0/cf8d227a2db06c5ca09be4be45885306b71733540ace3980ff3794bfaa22c6b38a15446e46ca8880478c018d8ecd0f14e14cb203a6c3ba9b901853db0a9890ba
|
||||||
|
languageName: node
|
||||||
|
linkType: hard
|
||||||
|
|
||||||
"@vitejs/plugin-react@npm:4.3.4":
|
"@vitejs/plugin-react@npm:4.3.4":
|
||||||
version: 4.3.4
|
version: 4.3.4
|
||||||
resolution: "@vitejs/plugin-react@npm:4.3.4"
|
resolution: "@vitejs/plugin-react@npm:4.3.4"
|
||||||
@ -9609,6 +9618,13 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
|
"tiny-emitter@npm:^2.1.0":
|
||||||
|
version: 2.1.0
|
||||||
|
resolution: "tiny-emitter@npm:2.1.0"
|
||||||
|
checksum: 10c0/459c0bd6e636e80909898220eb390e1cba2b15c430b7b06cec6ac29d87acd29ef618b9b32532283af749f5d37af3534d0e3bde29fdf6bcefbf122784333c953d
|
||||||
|
languageName: node
|
||||||
|
linkType: hard
|
||||||
|
|
||||||
"tinybench@npm:^2.9.0":
|
"tinybench@npm:^2.9.0":
|
||||||
version: 2.9.0
|
version: 2.9.0
|
||||||
resolution: "tinybench@npm:2.9.0"
|
resolution: "tinybench@npm:2.9.0"
|
||||||
@ -10123,6 +10139,7 @@ __metadata:
|
|||||||
"@types/uuid": "npm:^9.0.0"
|
"@types/uuid": "npm:^9.0.0"
|
||||||
"@uiw/codemirror-theme-duotone": "npm:4.23.10"
|
"@uiw/codemirror-theme-duotone": "npm:4.23.10"
|
||||||
"@uiw/react-codemirror": "npm:4.23.10"
|
"@uiw/react-codemirror": "npm:4.23.10"
|
||||||
|
"@unleash/proxy-client-react": "npm:^5.0.0"
|
||||||
"@vitejs/plugin-react": "npm:4.3.4"
|
"@vitejs/plugin-react": "npm:4.3.4"
|
||||||
cartesian: "npm:^1.0.1"
|
cartesian: "npm:^1.0.1"
|
||||||
chart.js: "npm:3.9.1"
|
chart.js: "npm:3.9.1"
|
||||||
@ -10173,6 +10190,7 @@ __metadata:
|
|||||||
swr: "npm:2.3.3"
|
swr: "npm:2.3.3"
|
||||||
tss-react: "npm:4.9.15"
|
tss-react: "npm:4.9.15"
|
||||||
typescript: "npm:5.4.5"
|
typescript: "npm:5.4.5"
|
||||||
|
unleash-proxy-client: "npm:^3.7.3"
|
||||||
use-query-params: "npm:^2.2.1"
|
use-query-params: "npm:^2.2.1"
|
||||||
vanilla-jsoneditor: "npm:^0.23.0"
|
vanilla-jsoneditor: "npm:^0.23.0"
|
||||||
vite: "npm:5.4.16"
|
vite: "npm:5.4.16"
|
||||||
@ -10184,6 +10202,16 @@ __metadata:
|
|||||||
languageName: unknown
|
languageName: unknown
|
||||||
linkType: soft
|
linkType: soft
|
||||||
|
|
||||||
|
"unleash-proxy-client@npm:^3.7.3":
|
||||||
|
version: 3.7.3
|
||||||
|
resolution: "unleash-proxy-client@npm:3.7.3"
|
||||||
|
dependencies:
|
||||||
|
tiny-emitter: "npm:^2.1.0"
|
||||||
|
uuid: "npm:^9.0.1"
|
||||||
|
checksum: 10c0/3a061d4e3587325046fea0133fe405fef143dbcfdd6ed20c54200b46a22bf49acdccb6dcc0b250400a9ace2350b0065f856731a5712598d27c1e9266a141f559
|
||||||
|
languageName: node
|
||||||
|
linkType: hard
|
||||||
|
|
||||||
"untildify@npm:^4.0.0":
|
"untildify@npm:^4.0.0":
|
||||||
version: 4.0.0
|
version: 4.0.0
|
||||||
resolution: "untildify@npm:4.0.0"
|
resolution: "untildify@npm:4.0.0"
|
||||||
@ -10298,6 +10326,15 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
|
"uuid@npm:^9.0.1":
|
||||||
|
version: 9.0.1
|
||||||
|
resolution: "uuid@npm:9.0.1"
|
||||||
|
bin:
|
||||||
|
uuid: dist/bin/uuid
|
||||||
|
checksum: 10c0/1607dd32ac7fc22f2d8f77051e6a64845c9bce5cd3dd8aa0070c074ec73e666a1f63c7b4e0f4bf2bc8b9d59dc85a15e17807446d9d2b17c8485fbc2147b27f9b
|
||||||
|
languageName: node
|
||||||
|
linkType: hard
|
||||||
|
|
||||||
"uvu@npm:^0.5.0":
|
"uvu@npm:^0.5.0":
|
||||||
version: 0.5.6
|
version: 0.5.6
|
||||||
resolution: "uvu@npm:0.5.6"
|
resolution: "uvu@npm:0.5.6"
|
||||||
|
@ -158,6 +158,7 @@ exports[`should create default config 1`] = `
|
|||||||
"ui": {
|
"ui": {
|
||||||
"environment": "Open Source",
|
"environment": "Open Source",
|
||||||
},
|
},
|
||||||
|
"unleashFrontendToken": undefined,
|
||||||
"userInactivityThresholdInDays": 180,
|
"userInactivityThresholdInDays": 180,
|
||||||
"versionCheck": {
|
"versionCheck": {
|
||||||
"enable": true,
|
"enable": true,
|
||||||
|
@ -751,6 +751,9 @@ export function createConfig(options: IUnleashOptions): IUnleashConfig {
|
|||||||
|
|
||||||
const openAIAPIKey = process.env.OPENAI_API_KEY;
|
const openAIAPIKey = process.env.OPENAI_API_KEY;
|
||||||
|
|
||||||
|
const unleashFrontendToken =
|
||||||
|
options.unleashFrontendToken || process.env.UNLEASH_FRONTEND_TOKEN;
|
||||||
|
|
||||||
const defaultDaysToBeConsideredInactive = 180;
|
const defaultDaysToBeConsideredInactive = 180;
|
||||||
const userInactivityThresholdInDays =
|
const userInactivityThresholdInDays =
|
||||||
options.userInactivityThresholdInDays ??
|
options.userInactivityThresholdInDays ??
|
||||||
@ -801,6 +804,7 @@ export function createConfig(options: IUnleashOptions): IUnleashConfig {
|
|||||||
openAIAPIKey,
|
openAIAPIKey,
|
||||||
userInactivityThresholdInDays,
|
userInactivityThresholdInDays,
|
||||||
buildDate: process.env.BUILD_DATE,
|
buildDate: process.env.BUILD_DATE,
|
||||||
|
unleashFrontendToken,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -31,6 +31,7 @@ const flagResolver = {
|
|||||||
isEnabled: jest.fn(),
|
isEnabled: jest.fn(),
|
||||||
getAll: jest.fn(),
|
getAll: jest.fn(),
|
||||||
getVariant: jest.fn(),
|
getVariant: jest.fn(),
|
||||||
|
getStaticContext: jest.fn(),
|
||||||
};
|
};
|
||||||
|
|
||||||
// Make sure it's always cleaned up
|
// Make sure it's always cleaned up
|
||||||
|
@ -191,6 +191,11 @@ export const uiConfigSchema = {
|
|||||||
description: 'The maximum number of sessions that a user has.',
|
description: 'The maximum number of sessions that a user has.',
|
||||||
example: 10,
|
example: 10,
|
||||||
},
|
},
|
||||||
|
unleashContext: {
|
||||||
|
type: 'object',
|
||||||
|
description:
|
||||||
|
'The context object used to configure the Unleash instance.',
|
||||||
|
},
|
||||||
},
|
},
|
||||||
components: {
|
components: {
|
||||||
schemas: {
|
schemas: {
|
||||||
|
@ -174,6 +174,12 @@ class ConfigController extends Controller {
|
|||||||
...expFlags,
|
...expFlags,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const unleashContext = {
|
||||||
|
...this.flagResolver.getStaticContext(), //clientId etc.
|
||||||
|
email: req.user.email,
|
||||||
|
userId: req.user.id,
|
||||||
|
};
|
||||||
|
|
||||||
const response: UiConfigSchema = {
|
const response: UiConfigSchema = {
|
||||||
...this.config.ui,
|
...this.config.ui,
|
||||||
flags,
|
flags,
|
||||||
@ -192,6 +198,7 @@ class ConfigController extends Controller {
|
|||||||
maintenanceMode,
|
maintenanceMode,
|
||||||
feedbackUriPath: this.config.feedbackUriPath,
|
feedbackUriPath: this.config.feedbackUriPath,
|
||||||
maxSessionsCount,
|
maxSessionsCount,
|
||||||
|
unleashContext: unleashContext,
|
||||||
};
|
};
|
||||||
|
|
||||||
this.openApiService.respondWithValidation(
|
this.openApiService.respondWithValidation(
|
||||||
|
@ -352,6 +352,7 @@ export interface IFlagResolver {
|
|||||||
getAll: (context?: IFlagContext) => IFlags;
|
getAll: (context?: IFlagContext) => IFlags;
|
||||||
isEnabled: (expName: IFlagKey, context?: IFlagContext) => boolean;
|
isEnabled: (expName: IFlagKey, context?: IFlagContext) => boolean;
|
||||||
getVariant: (expName: IFlagKey, context?: IFlagContext) => Variant;
|
getVariant: (expName: IFlagKey, context?: IFlagContext) => Variant;
|
||||||
|
getStaticContext: () => IFlagContext;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IExternalFlagResolver {
|
export interface IExternalFlagResolver {
|
||||||
|
@ -4,6 +4,7 @@ import type { LogLevel, LogProvider } from '../logger';
|
|||||||
import type { ILegacyApiTokenCreate } from './models/api-token';
|
import type { ILegacyApiTokenCreate } from './models/api-token';
|
||||||
import type {
|
import type {
|
||||||
IExperimentalOptions,
|
IExperimentalOptions,
|
||||||
|
IFlagContext,
|
||||||
IFlagResolver,
|
IFlagResolver,
|
||||||
IFlags,
|
IFlags,
|
||||||
} from './experimental';
|
} from './experimental';
|
||||||
@ -165,6 +166,7 @@ export interface IUnleashOptions {
|
|||||||
>
|
>
|
||||||
>;
|
>;
|
||||||
userInactivityThresholdInDays?: number;
|
userInactivityThresholdInDays?: number;
|
||||||
|
unleashFrontendToken?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IEmailOption {
|
export interface IEmailOption {
|
||||||
@ -198,6 +200,8 @@ export interface IUIConfig {
|
|||||||
title: string;
|
title: string;
|
||||||
}[];
|
}[];
|
||||||
flags?: IFlags;
|
flags?: IFlags;
|
||||||
|
unleashToken?: string;
|
||||||
|
unleashContext?: IFlagContext;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ICspDomainOptions {
|
export interface ICspDomainOptions {
|
||||||
@ -287,4 +291,5 @@ export interface IUnleashConfig {
|
|||||||
openAIAPIKey?: string;
|
openAIAPIKey?: string;
|
||||||
userInactivityThresholdInDays: number;
|
userInactivityThresholdInDays: number;
|
||||||
buildDate?: string;
|
buildDate?: string;
|
||||||
|
unleashFrontendToken?: string;
|
||||||
}
|
}
|
||||||
|
@ -61,6 +61,10 @@ export default class FlagResolver implements IFlagResolver {
|
|||||||
}
|
}
|
||||||
return this.externalResolver.getVariant(expName, context);
|
return this.externalResolver.getVariant(expName, context);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getStaticContext(): IFlagContext {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export const getVariantValue = <T = string>(
|
export const getVariantValue = <T = string>(
|
||||||
|
@ -10,6 +10,7 @@ export async function loadIndexHTML(
|
|||||||
): Promise<string> {
|
): Promise<string> {
|
||||||
const { cdnPrefix, baseUriPath = '' } = config.server;
|
const { cdnPrefix, baseUriPath = '' } = config.server;
|
||||||
const uiFlags = encodeURI(JSON.stringify(config.ui.flags || '{}'));
|
const uiFlags = encodeURI(JSON.stringify(config.ui.flags || '{}'));
|
||||||
|
const unleashToken = config.unleashFrontendToken;
|
||||||
|
|
||||||
let indexHTML: string;
|
let indexHTML: string;
|
||||||
if (cdnPrefix) {
|
if (cdnPrefix) {
|
||||||
@ -23,5 +24,11 @@ export async function loadIndexHTML(
|
|||||||
.toString();
|
.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
return rewriteHTML(indexHTML, baseUriPath, cdnPrefix, uiFlags);
|
return rewriteHTML(
|
||||||
|
indexHTML,
|
||||||
|
baseUriPath,
|
||||||
|
cdnPrefix,
|
||||||
|
uiFlags,
|
||||||
|
unleashToken,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
@ -3,6 +3,7 @@ export const rewriteHTML = (
|
|||||||
rewriteValue: string,
|
rewriteValue: string,
|
||||||
cdnPrefix?: string,
|
cdnPrefix?: string,
|
||||||
uiFlags?: string,
|
uiFlags?: string,
|
||||||
|
unleashToken?: string,
|
||||||
): string => {
|
): string => {
|
||||||
let result = input;
|
let result = input;
|
||||||
result = result.replace(/::baseUriPath::/gi, rewriteValue);
|
result = result.replace(/::baseUriPath::/gi, rewriteValue);
|
||||||
@ -13,6 +14,8 @@ export const rewriteHTML = (
|
|||||||
|
|
||||||
result = result.replace(/::uiFlags::/gi, uiFlags || '{}');
|
result = result.replace(/::uiFlags::/gi, uiFlags || '{}');
|
||||||
|
|
||||||
|
result = result.replace(/::unleashToken::/gi, unleashToken || '');
|
||||||
|
|
||||||
result = result.replace(
|
result = result.replace(
|
||||||
/\/static/gi,
|
/\/static/gi,
|
||||||
`${cdnPrefix || rewriteValue}/static`,
|
`${cdnPrefix || rewriteValue}/static`,
|
||||||
|
Loading…
Reference in New Issue
Block a user