1
0
mirror of https://github.com/Unleash/unleash.git synced 2025-11-24 20:06:55 +01:00

chore: configure the 'maintenanceMode' flag to accept variants (#10956)

Configure the `maintenanceMode` flag type to be `boolean | Variant` and
update the env parsing to allow passing strings from the env.

The [first
impl](3bbfc9e681)
required you to set a full, variant -- stringified as json -- in the
env, but this is both error-prone and not very user friendly.
Additionally, the name of the variant isn't really important, and if
you're passing a string, you probably want it to be true.

As such, the [second
impl](c38357baa4)
updates the env parsing to read the full string value into a
pre-formatted variant if it's not parseable as a boolean.

As such, to set a custom message, you can now do:

```sh
UNLEASH_EXPERIMENTAL_MAINTENANCE_MODE='Custom message from plain env var string' yarn dev
```

With the [updates to the
UI](https://github.com/Unleash/unleash/pull/10961), it'll look a little
something like this:

<img width="388" height="64" alt="image"
src="https://github.com/user-attachments/assets/6b8a174b-d75f-4748-8f1a-1ad4ebce2073"
/>

## Rationale

This allows locking down Unleash instances with a custom message.
Previously, you'd have to use both maintenance mode and a custom banner
for this, but that requires more work to set properly and it shows two
banners, when you really only want the one.
This commit is contained in:
Thomas Heartman 2025-11-11 12:52:49 +01:00 committed by GitHub
parent 6f02edce2d
commit b33abf036b
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 65 additions and 4 deletions

View File

@ -52,7 +52,7 @@ export type UiFlags = {
T?: boolean; T?: boolean;
UNLEASH_CLOUD?: boolean; UNLEASH_CLOUD?: boolean;
UG?: boolean; UG?: boolean;
maintenanceMode?: boolean; maintenanceMode?: boolean | Variant;
messageBanner?: Variant; messageBanner?: Variant;
banner?: Variant; banner?: Variant;
notifications?: boolean; notifications?: boolean;

View File

@ -1,6 +1,9 @@
import { PayloadType, type Variant } from 'unleash-client'; import { PayloadType, type Variant } from 'unleash-client';
import { parseEnvVarBoolean } from '../util/index.js';
import { defaultVariant } from 'unleash-client/lib/variant.js'; import { defaultVariant } from 'unleash-client/lib/variant.js';
import {
parseEnvVarBoolean,
parseEnvVarBooleanOrStringVariant,
} from '../util/index.js';
import type { MetricFlagContext } from 'unleash-client/lib/impact-metrics/metric-types.js'; import type { MetricFlagContext } from 'unleash-client/lib/impact-metrics/metric-types.js';
import type { Context } from '../features/playground/feature-evaluator/index.js'; import type { Context } from '../features/playground/feature-evaluator/index.js';
@ -72,7 +75,7 @@ const flags: IFlags = {
process.env.UNLEASH_RESPONSE_TIME_WITH_APP_NAME_KILL_SWITCH, process.env.UNLEASH_RESPONSE_TIME_WITH_APP_NAME_KILL_SWITCH,
false, false,
), ),
maintenanceMode: parseEnvVarBoolean( maintenanceMode: parseEnvVarBooleanOrStringVariant(
process.env.UNLEASH_EXPERIMENTAL_MAINTENANCE_MODE, process.env.UNLEASH_EXPERIMENTAL_MAINTENANCE_MODE,
false, false,
), ),

View File

@ -108,7 +108,6 @@ export class UiConfigService {
email: user.email, email: user.email,
userId: user.id, userId: user.id,
}; };
const uiConfig: UiConfigSchema = { const uiConfig: UiConfigSchema = {
...this.config.ui, ...this.config.ui,
flags, flags,

View File

@ -1,5 +1,7 @@
import { PayloadType } from 'unleash-client';
import { import {
parseEnvVarBoolean, parseEnvVarBoolean,
parseEnvVarBooleanOrStringVariant,
parseEnvVarNumber, parseEnvVarNumber,
parseEnvVarStrings, parseEnvVarStrings,
} from './parseEnvVar.js'; } from './parseEnvVar.js';
@ -39,3 +41,32 @@ test('parseEnvVarStringList', () => {
expect(parseEnvVarStrings('a,b,c', [])).toEqual(['a', 'b', 'c']); expect(parseEnvVarStrings('a,b,c', [])).toEqual(['a', 'b', 'c']);
expect(parseEnvVarStrings(' a,,,b, c , ,', [])).toEqual(['a', 'b', 'c']); expect(parseEnvVarStrings(' a,,,b, c , ,', [])).toEqual(['a', 'b', 'c']);
}); });
test('parseEnvVarBooleanOrStringVariant', () => {
expect(parseEnvVarBooleanOrStringVariant(undefined, true)).toEqual(true);
expect(parseEnvVarBooleanOrStringVariant(undefined, false)).toEqual(false);
for (const truthy of ['true', 't', '1']) {
expect(parseEnvVarBooleanOrStringVariant(truthy, false)).toEqual(true);
}
for (const falsy of ['false', 'f', '0']) {
expect(parseEnvVarBooleanOrStringVariant(falsy, true)).toEqual(false);
}
expect(
parseEnvVarBooleanOrStringVariant(undefined, {
name: 'default-variant',
enabled: false,
}),
).toEqual({ name: 'default-variant', enabled: false });
expect(
parseEnvVarBooleanOrStringVariant('custom string', true),
).toMatchObject({
name: expect.any(String),
enabled: true,
payload: {
value: 'custom string',
type: PayloadType.STRING,
},
});
});

View File

@ -1,3 +1,5 @@
import { PayloadType, type Variant } from 'unleash-client';
export function parseEnvVarNumber( export function parseEnvVarNumber(
envVar: string | undefined, envVar: string | undefined,
defaultVal: number, defaultVal: number,
@ -53,3 +55,29 @@ export function parseEnvVarJSON(
return defaultVal; return defaultVal;
} }
export function parseEnvVarBooleanOrStringVariant(
envVar: string | undefined,
defaultVal: boolean | Variant,
): boolean | Variant {
if (!envVar) {
return defaultVal;
}
if (envVar === '1' || envVar === 't' || envVar === 'true') {
return true;
}
if (envVar === '0' || envVar === 'f' || envVar === 'false') {
return false;
}
return {
name: 'Variant',
enabled: true,
payload: {
type: PayloadType.STRING,
value: envVar,
},
};
}