mirror of
https://github.com/Unleash/unleash.git
synced 2025-05-22 01:16:07 +02:00
refactor: get segment limits from uiConfig (#1047)
* refactor: improve useUiConfig return type * refactor: get segment limits from uiConfig
This commit is contained in:
parent
682921d5bf
commit
006b853f6c
@ -8,7 +8,7 @@ import {
|
||||
import { FeatureStrategySegmentList } from 'component/feature/FeatureStrategy/FeatureStrategySegment/FeatureStrategySegmentList';
|
||||
import { useStyles } from 'component/feature/FeatureStrategy/FeatureStrategySegment/FeatureStrategySegment.styles';
|
||||
import { SegmentDocsStrategyWarning } from 'component/segments/SegmentDocs/SegmentDocs';
|
||||
import { STRATEGY_SEGMENTS_LIMIT } from 'utils/segmentLimits';
|
||||
import { useSegmentLimits } from 'hooks/api/getters/useSegmentLimits/useSegmentLimits';
|
||||
|
||||
interface IFeatureStrategySegmentProps {
|
||||
segments: ISegment[];
|
||||
@ -19,9 +19,14 @@ export const FeatureStrategySegment = ({
|
||||
segments: selectedSegments,
|
||||
setSegments: setSelectedSegments,
|
||||
}: IFeatureStrategySegmentProps) => {
|
||||
const atSegmentsLimit = selectedSegments.length >= STRATEGY_SEGMENTS_LIMIT;
|
||||
const { segments: allSegments } = useSegments();
|
||||
const { classes: styles } = useStyles();
|
||||
const { strategySegmentsLimit } = useSegmentLimits();
|
||||
|
||||
const atStrategySegmentsLimit: boolean = Boolean(
|
||||
strategySegmentsLimit &&
|
||||
selectedSegments.length >= strategySegmentsLimit
|
||||
);
|
||||
|
||||
if (!allSegments || allSegments.length === 0) {
|
||||
return null;
|
||||
@ -48,13 +53,13 @@ export const FeatureStrategySegment = ({
|
||||
return (
|
||||
<>
|
||||
<h3 className={styles.title}>Segmentation</h3>
|
||||
{atSegmentsLimit && <SegmentDocsStrategyWarning />}
|
||||
{atStrategySegmentsLimit && <SegmentDocsStrategyWarning />}
|
||||
<p>Add a predefined segment to constrain this feature toggle:</p>
|
||||
<AutocompleteBox
|
||||
label="Select segments"
|
||||
options={autocompleteOptions}
|
||||
onChange={onChange}
|
||||
disabled={atSegmentsLimit}
|
||||
disabled={atStrategySegmentsLimit}
|
||||
/>
|
||||
<FeatureStrategySegmentList
|
||||
segments={selectedSegments}
|
||||
|
@ -19,7 +19,7 @@ interface IDrawerMenuProps {
|
||||
admin?: boolean;
|
||||
links: Array<{
|
||||
value: string;
|
||||
icon: string | ReactNode;
|
||||
icon: ReactNode;
|
||||
href: string;
|
||||
title: string;
|
||||
}>;
|
||||
|
@ -14,8 +14,8 @@ import { SegmentForm } from '../SegmentForm/SegmentForm';
|
||||
import { feedbackCESContext } from 'component/feedback/FeedbackCESContext/FeedbackCESContext';
|
||||
import { segmentsDocsLink } from 'component/segments/SegmentDocs/SegmentDocs';
|
||||
import { useSegmentValuesCount } from 'component/segments/hooks/useSegmentValuesCount';
|
||||
import { SEGMENT_VALUES_LIMIT } from 'utils/segmentLimits';
|
||||
import { SEGMENT_CREATE_BTN_ID } from 'utils/testIds';
|
||||
import { useSegmentLimits } from 'hooks/api/getters/useSegmentLimits/useSegmentLimits';
|
||||
|
||||
export const CreateSegment = () => {
|
||||
const { uiConfig } = useUiConfig();
|
||||
@ -38,8 +38,12 @@ export const CreateSegment = () => {
|
||||
} = useSegmentForm();
|
||||
|
||||
const hasValidConstraints = useConstraintsValidation(constraints);
|
||||
const { segmentValuesLimit } = useSegmentLimits();
|
||||
const segmentValuesCount = useSegmentValuesCount(constraints);
|
||||
const atSegmentValuesLimit = segmentValuesCount >= SEGMENT_VALUES_LIMIT;
|
||||
|
||||
const overSegmentValuesLimit: boolean = Boolean(
|
||||
segmentValuesLimit && segmentValuesCount > segmentValuesLimit
|
||||
);
|
||||
|
||||
const formatApiCode = () => {
|
||||
return `curl --location --request POST '${
|
||||
@ -96,7 +100,7 @@ export const CreateSegment = () => {
|
||||
<CreateButton
|
||||
name="segment"
|
||||
permission={CREATE_SEGMENT}
|
||||
disabled={!hasValidConstraints || atSegmentValuesLimit}
|
||||
disabled={!hasValidConstraints || overSegmentValuesLimit}
|
||||
data-testid={SEGMENT_CREATE_BTN_ID}
|
||||
/>
|
||||
</SegmentForm>
|
||||
|
@ -16,8 +16,8 @@ import { segmentsFormDescription } from 'component/segments/CreateSegment/Create
|
||||
import { UpdateButton } from 'component/common/UpdateButton/UpdateButton';
|
||||
import { segmentsDocsLink } from 'component/segments/SegmentDocs/SegmentDocs';
|
||||
import { useSegmentValuesCount } from 'component/segments/hooks/useSegmentValuesCount';
|
||||
import { SEGMENT_VALUES_LIMIT } from 'utils/segmentLimits';
|
||||
import { SEGMENT_SAVE_BTN_ID } from 'utils/testIds';
|
||||
import { useSegmentLimits } from 'hooks/api/getters/useSegmentLimits/useSegmentLimits';
|
||||
|
||||
export const EditSegment = () => {
|
||||
const segmentId = useRequiredPathParam('segmentId');
|
||||
@ -46,7 +46,11 @@ export const EditSegment = () => {
|
||||
|
||||
const hasValidConstraints = useConstraintsValidation(constraints);
|
||||
const segmentValuesCount = useSegmentValuesCount(constraints);
|
||||
const atSegmentValuesLimit = segmentValuesCount >= SEGMENT_VALUES_LIMIT;
|
||||
const { segmentValuesLimit } = useSegmentLimits();
|
||||
|
||||
const overSegmentValuesLimit: boolean = Boolean(
|
||||
segmentValuesLimit && segmentValuesCount > segmentValuesLimit
|
||||
);
|
||||
|
||||
const formatApiCode = () => {
|
||||
return `curl --location --request PUT '${
|
||||
@ -98,7 +102,7 @@ export const EditSegment = () => {
|
||||
>
|
||||
<UpdateButton
|
||||
permission={UPDATE_SEGMENT}
|
||||
disabled={!hasValidConstraints || atSegmentValuesLimit}
|
||||
disabled={!hasValidConstraints || overSegmentValuesLimit}
|
||||
data-testid={SEGMENT_SAVE_BTN_ID}
|
||||
/>
|
||||
</SegmentForm>
|
||||
|
@ -1,9 +1,6 @@
|
||||
import { Alert } from '@mui/material';
|
||||
import { useStyles } from 'component/segments/SegmentDocs/SegmentDocs.styles';
|
||||
import {
|
||||
STRATEGY_SEGMENTS_LIMIT,
|
||||
SEGMENT_VALUES_LIMIT,
|
||||
} from 'utils/segmentLimits';
|
||||
import { useSegmentLimits } from 'hooks/api/getters/useSegmentLimits/useSegmentLimits';
|
||||
|
||||
export const SegmentDocsWarning = () => {
|
||||
const { classes: styles } = useStyles();
|
||||
@ -25,19 +22,31 @@ export const SegmentDocsWarning = () => {
|
||||
};
|
||||
|
||||
export const SegmentDocsValuesWarning = () => {
|
||||
const { segmentValuesLimit } = useSegmentLimits();
|
||||
|
||||
if (typeof segmentValuesLimit === 'undefined') {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<Alert severity="warning">
|
||||
Segments is an experimental feature available to select users.
|
||||
Currently, segments are limited to at most {SEGMENT_VALUES_LIMIT}{' '}
|
||||
Currently, segments are limited to at most {segmentValuesLimit}{' '}
|
||||
values. <SegmentLimitsLink />
|
||||
</Alert>
|
||||
);
|
||||
};
|
||||
|
||||
export const SegmentDocsValuesError = (props: { values: number }) => {
|
||||
const { segmentValuesLimit } = useSegmentLimits();
|
||||
|
||||
if (typeof segmentValuesLimit === 'undefined') {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<Alert severity="error">
|
||||
Segments are limited to at most {SEGMENT_VALUES_LIMIT} values. This
|
||||
Segments are limited to at most {segmentValuesLimit} values. This
|
||||
segment currently has {props.values}{' '}
|
||||
{props.values === 1 ? 'value' : 'values'}.
|
||||
</Alert>
|
||||
@ -45,9 +54,15 @@ export const SegmentDocsValuesError = (props: { values: number }) => {
|
||||
};
|
||||
|
||||
export const SegmentDocsStrategyWarning = () => {
|
||||
const { strategySegmentsLimit } = useSegmentLimits();
|
||||
|
||||
if (typeof strategySegmentsLimit === 'undefined') {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<Alert severity="warning">
|
||||
Strategies are limited to {STRATEGY_SEGMENTS_LIMIT} segments.{' '}
|
||||
Strategies are limited to {strategySegmentsLimit} segments.{' '}
|
||||
<SegmentLimitsLink />
|
||||
</Alert>
|
||||
);
|
||||
|
@ -28,8 +28,8 @@ import {
|
||||
SegmentDocsValuesError,
|
||||
} from 'component/segments/SegmentDocs/SegmentDocs';
|
||||
import { useSegmentValuesCount } from 'component/segments/hooks/useSegmentValuesCount';
|
||||
import { SEGMENT_VALUES_LIMIT } from 'utils/segmentLimits';
|
||||
import AccessContext from 'contexts/AccessContext';
|
||||
import { useSegmentLimits } from 'hooks/api/getters/useSegmentLimits/useSegmentLimits';
|
||||
|
||||
interface ISegmentFormPartTwoProps {
|
||||
constraints: IConstraint[];
|
||||
@ -52,8 +52,12 @@ export const SegmentFormStepTwo: React.FC<ISegmentFormPartTwoProps> = ({
|
||||
const { context = [] } = useUnleashContext();
|
||||
const [open, setOpen] = useState(false);
|
||||
const segmentValuesCount = useSegmentValuesCount(constraints);
|
||||
const overSegmentValuesLimit = segmentValuesCount > SEGMENT_VALUES_LIMIT;
|
||||
const modePermission = mode === 'create' ? CREATE_SEGMENT : UPDATE_SEGMENT;
|
||||
const { segmentValuesLimit } = useSegmentLimits();
|
||||
|
||||
const overSegmentValuesLimit: boolean = Boolean(
|
||||
segmentValuesLimit && segmentValuesCount > segmentValuesLimit
|
||||
);
|
||||
|
||||
const autocompleteOptions = context.map(c => ({
|
||||
value: c.name,
|
||||
|
@ -0,0 +1,16 @@
|
||||
import useUiConfig from 'hooks/api/getters/useUiConfig/useUiConfig';
|
||||
import { IUiConfig } from 'interfaces/uiConfig';
|
||||
|
||||
type IUseSegmentLimits = Pick<
|
||||
IUiConfig,
|
||||
'segmentValuesLimit' | 'strategySegmentsLimit'
|
||||
>;
|
||||
|
||||
export const useSegmentLimits = (): IUseSegmentLimits => {
|
||||
const { uiConfig } = useUiConfig();
|
||||
|
||||
return {
|
||||
segmentValuesLimit: uiConfig.segmentValuesLimit,
|
||||
strategySegmentsLimit: uiConfig.strategySegmentsLimit,
|
||||
};
|
||||
};
|
@ -1,9 +1,9 @@
|
||||
import { LibraryBooks } from '@mui/icons-material';
|
||||
import { IUiConfig } from 'interfaces/uiConfig';
|
||||
|
||||
export const defaultValue = {
|
||||
export const defaultValue: IUiConfig = {
|
||||
name: 'Unleash',
|
||||
version: '3.x',
|
||||
environment: '',
|
||||
slogan: 'The enterprise ready feature toggle service.',
|
||||
flags: {
|
||||
P: false,
|
||||
|
@ -1,40 +1,27 @@
|
||||
import useSWR, { mutate, SWRConfiguration } from 'swr';
|
||||
import useSWR from 'swr';
|
||||
import { formatApiPath } from 'utils/formatPath';
|
||||
import { defaultValue } from './defaultValue';
|
||||
import { IUiConfig } from 'interfaces/uiConfig';
|
||||
import handleErrorResponses from '../httpErrorResponseHandler';
|
||||
import { useMemo } from 'react';
|
||||
import { useMemo, useCallback } from 'react';
|
||||
|
||||
const REQUEST_KEY = 'api/admin/ui-config';
|
||||
|
||||
const useUiConfig = (options: SWRConfiguration = {}) => {
|
||||
const fetcher = () => {
|
||||
const path = formatApiPath(`api/admin/ui-config`);
|
||||
|
||||
return fetch(path, {
|
||||
method: 'GET',
|
||||
credentials: 'include',
|
||||
})
|
||||
.then(handleErrorResponses('configuration'))
|
||||
.then(res => res.json());
|
||||
};
|
||||
|
||||
const { data, error } = useSWR<IUiConfig>(REQUEST_KEY, fetcher, options);
|
||||
|
||||
const refetch = () => {
|
||||
mutate(REQUEST_KEY);
|
||||
};
|
||||
|
||||
const isOss = () => {
|
||||
if (data?.versionInfo?.current?.enterprise) {
|
||||
return false;
|
||||
} else if (!data || !data.versionInfo) {
|
||||
return false;
|
||||
interface IUseUIConfigOutput {
|
||||
uiConfig: IUiConfig;
|
||||
loading: boolean;
|
||||
error?: Error;
|
||||
refetch: () => void;
|
||||
isOss: () => boolean;
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
||||
const uiConfig = useMemo(() => {
|
||||
const useUiConfig = (): IUseUIConfigOutput => {
|
||||
const path = formatApiPath(`api/admin/ui-config`);
|
||||
const { data, error, mutate } = useSWR<IUiConfig>(path, fetcher);
|
||||
|
||||
const isOss = useCallback(() => {
|
||||
return !data?.versionInfo?.current?.enterprise;
|
||||
}, [data]);
|
||||
|
||||
const uiConfig: IUiConfig = useMemo(() => {
|
||||
return { ...defaultValue, ...data };
|
||||
}, [data]);
|
||||
|
||||
@ -42,9 +29,15 @@ const useUiConfig = (options: SWRConfiguration = {}) => {
|
||||
uiConfig,
|
||||
loading: !error && !data,
|
||||
error,
|
||||
refetch,
|
||||
refetch: mutate,
|
||||
isOss,
|
||||
};
|
||||
};
|
||||
|
||||
const fetcher = (path: string) => {
|
||||
return fetch(path)
|
||||
.then(handleErrorResponses('configuration'))
|
||||
.then(res => res.json());
|
||||
};
|
||||
|
||||
export default useUiConfig;
|
||||
|
@ -1,15 +1,20 @@
|
||||
import { ReactNode } from 'react';
|
||||
|
||||
export interface IUiConfig {
|
||||
authenticationType: string;
|
||||
baseUriPath: string;
|
||||
authenticationType?: string;
|
||||
baseUriPath?: string;
|
||||
flags: IFlags;
|
||||
name: string;
|
||||
slogan: string;
|
||||
unleashUrl: string;
|
||||
environment?: string;
|
||||
unleashUrl?: string;
|
||||
version: string;
|
||||
versionInfo: IVersionInfo;
|
||||
versionInfo?: IVersionInfo;
|
||||
links: ILinks[];
|
||||
disablePasswordAuth?: boolean;
|
||||
toast?: IProclamationToast;
|
||||
segmentValuesLimit?: number;
|
||||
strategySegmentsLimit?: number;
|
||||
}
|
||||
|
||||
export interface IProclamationToast {
|
||||
@ -46,7 +51,7 @@ export interface IVersion {
|
||||
|
||||
export interface ILinks {
|
||||
value: string;
|
||||
icon: string;
|
||||
icon: ReactNode;
|
||||
href: string;
|
||||
title: string;
|
||||
}
|
||||
|
@ -1,2 +0,0 @@
|
||||
export const SEGMENT_VALUES_LIMIT = 100;
|
||||
export const STRATEGY_SEGMENTS_LIMIT = 5;
|
Loading…
Reference in New Issue
Block a user