mirror of
https://github.com/Unleash/unleash.git
synced 2025-09-10 17:53:36 +02:00
cr support in new feature toggle switch
This commit is contained in:
parent
948374d55b
commit
d73912669f
@ -1,10 +1,7 @@
|
|||||||
import {
|
import {
|
||||||
ComponentProps,
|
ComponentProps,
|
||||||
FC,
|
|
||||||
ReactNode,
|
|
||||||
useCallback,
|
useCallback,
|
||||||
useMemo,
|
useMemo,
|
||||||
useReducer,
|
|
||||||
useState,
|
useState,
|
||||||
type VFC,
|
type VFC,
|
||||||
} from 'react';
|
} from 'react';
|
||||||
@ -13,18 +10,15 @@ import PermissionSwitch from 'component/common/PermissionSwitch/PermissionSwitch
|
|||||||
import { UPDATE_FEATURE_ENVIRONMENT } from 'component/providers/AccessProvider/permissions';
|
import { UPDATE_FEATURE_ENVIRONMENT } from 'component/providers/AccessProvider/permissions';
|
||||||
import { useOptimisticUpdate } from './hooks/useOptimisticUpdate';
|
import { useOptimisticUpdate } from './hooks/useOptimisticUpdate';
|
||||||
import { flexRow } from 'themes/themeStyles';
|
import { flexRow } from 'themes/themeStyles';
|
||||||
import { ENVIRONMENT_STRATEGY_ERROR } from 'constants/apiErrors';
|
|
||||||
import { formatUnknownError } from 'utils/formatUnknownError';
|
import { formatUnknownError } from 'utils/formatUnknownError';
|
||||||
import useFeatureApi from 'hooks/api/actions/useFeatureApi/useFeatureApi';
|
import useFeatureApi from 'hooks/api/actions/useFeatureApi/useFeatureApi';
|
||||||
import useToast from 'hooks/useToast';
|
import useToast from 'hooks/useToast';
|
||||||
import { useChangeRequestsEnabled } from 'hooks/useChangeRequestsEnabled';
|
|
||||||
import { useChangeRequestToggle } from 'hooks/useChangeRequestToggle';
|
import { useChangeRequestToggle } from 'hooks/useChangeRequestToggle';
|
||||||
import { UpdateEnabledMessage } from 'component/changeRequest/ChangeRequestConfirmDialog/ChangeRequestMessages/UpdateEnabledMessage';
|
import { UpdateEnabledMessage } from 'component/changeRequest/ChangeRequestConfirmDialog/ChangeRequestMessages/UpdateEnabledMessage';
|
||||||
import { ChangeRequestDialogue } from 'component/changeRequest/ChangeRequestConfirmDialog/ChangeRequestConfirmDialog';
|
import { ChangeRequestDialogue } from 'component/changeRequest/ChangeRequestConfirmDialog/ChangeRequestConfirmDialog';
|
||||||
import {
|
import {
|
||||||
FeatureStrategyProdGuard,
|
FeatureStrategyProdGuard,
|
||||||
isProdGuardEnabled,
|
isProdGuardEnabled,
|
||||||
useFeatureStrategyProdGuard,
|
|
||||||
} from 'component/feature/FeatureStrategy/FeatureStrategyProdGuard/FeatureStrategyProdGuard';
|
} from 'component/feature/FeatureStrategy/FeatureStrategyProdGuard/FeatureStrategyProdGuard';
|
||||||
import { EnableEnvironmentDialog } from './EnableEnvironmentDialog/EnableEnvironmentDialog';
|
import { EnableEnvironmentDialog } from './EnableEnvironmentDialog/EnableEnvironmentDialog';
|
||||||
import { ListItemType } from '../ProjectFeatureToggles.types';
|
import { ListItemType } from '../ProjectFeatureToggles.types';
|
||||||
@ -44,7 +38,8 @@ type OnFeatureToggleSwitchArgs = {
|
|||||||
hasStrategies?: boolean;
|
hasStrategies?: boolean;
|
||||||
hasEnabledStrategies?: boolean;
|
hasEnabledStrategies?: boolean;
|
||||||
isChangeRequestEnabled?: boolean;
|
isChangeRequestEnabled?: boolean;
|
||||||
onError?: () => void;
|
changeRequestToggle?: ReturnType<typeof useChangeRequestToggle>;
|
||||||
|
onRollback?: () => void;
|
||||||
onSuccess?: () => void;
|
onSuccess?: () => void;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -68,11 +63,10 @@ const composeAndRunMiddlewares = (middlewares: Middleware[]) => {
|
|||||||
runMiddleware(0);
|
runMiddleware(0);
|
||||||
};
|
};
|
||||||
|
|
||||||
export const useFeatureToggleSwitch = () => {
|
export const useFeatureToggleSwitch = (projectId: string) => {
|
||||||
const { loading, toggleFeatureEnvironmentOn, toggleFeatureEnvironmentOff } =
|
const { loading, toggleFeatureEnvironmentOn, toggleFeatureEnvironmentOff } =
|
||||||
useFeatureApi();
|
useFeatureApi();
|
||||||
const { setToastData, setToastApiError } = useToast();
|
const { setToastData, setToastApiError } = useToast();
|
||||||
// FIXME: change modals approach
|
|
||||||
const [prodGuardModalState, setProdGuardModalState] = useState<
|
const [prodGuardModalState, setProdGuardModalState] = useState<
|
||||||
ComponentProps<typeof FeatureStrategyProdGuard>
|
ComponentProps<typeof FeatureStrategyProdGuard>
|
||||||
>({
|
>({
|
||||||
@ -82,10 +76,26 @@ export const useFeatureToggleSwitch = () => {
|
|||||||
onClose: () => {},
|
onClose: () => {},
|
||||||
onClick: () => {},
|
onClick: () => {},
|
||||||
});
|
});
|
||||||
|
const [enableEnvironmentDialogState, setEnableEnvironmentDialogState] =
|
||||||
|
useState<ComponentProps<typeof EnableEnvironmentDialog>>({
|
||||||
|
isOpen: false,
|
||||||
|
environment: '',
|
||||||
|
onClose: () => {},
|
||||||
|
onActivateDisabledStrategies: () => {},
|
||||||
|
onAddDefaultStrategy: () => {},
|
||||||
|
});
|
||||||
|
const {
|
||||||
|
onChangeRequestToggle,
|
||||||
|
onChangeRequestToggleClose,
|
||||||
|
onChangeRequestToggleConfirm,
|
||||||
|
changeRequestDialogDetails,
|
||||||
|
} = useChangeRequestToggle(projectId);
|
||||||
|
const [changeRequestDialogCallback, setChangeRequestDialogCallback] =
|
||||||
|
useState<() => void>();
|
||||||
|
|
||||||
const onToggle = useCallback(
|
const onToggle = useCallback(
|
||||||
async (newState: boolean, config: OnFeatureToggleSwitchArgs) => {
|
async (newState: boolean, config: OnFeatureToggleSwitchArgs) => {
|
||||||
let shouldActivateDisabled = false;
|
let shouldActivateDisabledStrategies = false;
|
||||||
|
|
||||||
const confirmProductionChanges: Middleware = (next) => {
|
const confirmProductionChanges: Middleware = (next) => {
|
||||||
if (config.isChangeRequestEnabled) {
|
if (config.isChangeRequestEnabled) {
|
||||||
@ -105,7 +115,7 @@ export const useFeatureToggleSwitch = () => {
|
|||||||
...prev,
|
...prev,
|
||||||
open: false,
|
open: false,
|
||||||
}));
|
}));
|
||||||
config.onError?.();
|
config.onRollback?.();
|
||||||
},
|
},
|
||||||
onClick: () => {
|
onClick: () => {
|
||||||
setProdGuardModalState((prev) => ({
|
setProdGuardModalState((prev) => ({
|
||||||
@ -122,16 +132,55 @@ export const useFeatureToggleSwitch = () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const ensureActiveStrategies: Middleware = (next) => {
|
const ensureActiveStrategies: Middleware = (next) => {
|
||||||
shouldActivateDisabled = false;
|
if (!config.hasStrategies || config.hasEnabledStrategies) {
|
||||||
// TODO: implementation
|
return next();
|
||||||
|
}
|
||||||
|
|
||||||
|
setEnableEnvironmentDialogState({
|
||||||
|
isOpen: true,
|
||||||
|
environment: config.environmentName,
|
||||||
|
onClose: () => {
|
||||||
|
setEnableEnvironmentDialogState((prev) => ({
|
||||||
|
...prev,
|
||||||
|
isOpen: false,
|
||||||
|
}));
|
||||||
|
config.onRollback?.();
|
||||||
|
},
|
||||||
|
onActivateDisabledStrategies: () => {
|
||||||
|
setEnableEnvironmentDialogState((prev) => ({
|
||||||
|
...prev,
|
||||||
|
isOpen: false,
|
||||||
|
}));
|
||||||
|
shouldActivateDisabledStrategies = true;
|
||||||
next();
|
next();
|
||||||
|
},
|
||||||
|
onAddDefaultStrategy: () => {
|
||||||
|
setEnableEnvironmentDialogState((prev) => ({
|
||||||
|
...prev,
|
||||||
|
isOpen: false,
|
||||||
|
}));
|
||||||
|
next();
|
||||||
|
},
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
const addToChangeRequest: Middleware = (next) => {
|
const addToChangeRequest: Middleware = (next) => {
|
||||||
if (!config.isChangeRequestEnabled) {
|
if (!config.isChangeRequestEnabled) {
|
||||||
next();
|
return next();
|
||||||
}
|
}
|
||||||
// TODO: implementation
|
|
||||||
|
setChangeRequestDialogCallback(() => {
|
||||||
|
setChangeRequestDialogCallback(undefined);
|
||||||
|
// always reset to previous state when using change requests
|
||||||
|
config.onRollback?.();
|
||||||
|
});
|
||||||
|
|
||||||
|
onChangeRequestToggle(
|
||||||
|
config.featureId,
|
||||||
|
config.environmentName,
|
||||||
|
newState,
|
||||||
|
shouldActivateDisabledStrategies,
|
||||||
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleToggleEnvironmentOn: Middleware = async (next) => {
|
const handleToggleEnvironmentOn: Middleware = async (next) => {
|
||||||
@ -144,7 +193,7 @@ export const useFeatureToggleSwitch = () => {
|
|||||||
config.projectId,
|
config.projectId,
|
||||||
config.featureId,
|
config.featureId,
|
||||||
config.environmentName,
|
config.environmentName,
|
||||||
shouldActivateDisabled,
|
shouldActivateDisabledStrategies,
|
||||||
);
|
);
|
||||||
setToastData({
|
setToastData({
|
||||||
type: 'success',
|
type: 'success',
|
||||||
@ -154,7 +203,7 @@ export const useFeatureToggleSwitch = () => {
|
|||||||
config.onSuccess?.();
|
config.onSuccess?.();
|
||||||
} catch (error: unknown) {
|
} catch (error: unknown) {
|
||||||
setToastApiError(formatUnknownError(error));
|
setToastApiError(formatUnknownError(error));
|
||||||
config.onError?.();
|
config.onRollback?.();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -177,32 +226,45 @@ export const useFeatureToggleSwitch = () => {
|
|||||||
config.onSuccess?.();
|
config.onSuccess?.();
|
||||||
} catch (error: unknown) {
|
} catch (error: unknown) {
|
||||||
setToastApiError(formatUnknownError(error));
|
setToastApiError(formatUnknownError(error));
|
||||||
config.onError?.();
|
config.onRollback?.();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
return composeAndRunMiddlewares([
|
return composeAndRunMiddlewares([
|
||||||
confirmProductionChanges,
|
confirmProductionChanges,
|
||||||
addToChangeRequest,
|
|
||||||
ensureActiveStrategies,
|
ensureActiveStrategies,
|
||||||
|
addToChangeRequest,
|
||||||
handleToggleEnvironmentOff,
|
handleToggleEnvironmentOff,
|
||||||
handleToggleEnvironmentOn,
|
handleToggleEnvironmentOn,
|
||||||
() => {
|
|
||||||
console.log('done', { newState, config }); // FIXME: remove
|
|
||||||
config.onSuccess?.();
|
|
||||||
},
|
|
||||||
]);
|
]);
|
||||||
},
|
},
|
||||||
[setProdGuardModalState],
|
[setProdGuardModalState],
|
||||||
);
|
);
|
||||||
|
|
||||||
const modals = useMemo(
|
const modals = (
|
||||||
() => (
|
|
||||||
<>
|
<>
|
||||||
<FeatureStrategyProdGuard {...prodGuardModalState} />
|
<FeatureStrategyProdGuard {...prodGuardModalState} />
|
||||||
|
<EnableEnvironmentDialog {...enableEnvironmentDialogState} />
|
||||||
|
<ChangeRequestDialogue
|
||||||
|
isOpen={changeRequestDialogDetails.isOpen}
|
||||||
|
onClose={() => {
|
||||||
|
changeRequestDialogCallback?.();
|
||||||
|
onChangeRequestToggleClose();
|
||||||
|
}}
|
||||||
|
environment={changeRequestDialogDetails?.environment}
|
||||||
|
onConfirm={() => {
|
||||||
|
changeRequestDialogCallback?.();
|
||||||
|
onChangeRequestToggleConfirm();
|
||||||
|
}}
|
||||||
|
messageComponent={
|
||||||
|
<UpdateEnabledMessage
|
||||||
|
enabled={changeRequestDialogDetails?.enabled!}
|
||||||
|
featureName={changeRequestDialogDetails?.featureName!}
|
||||||
|
environment={changeRequestDialogDetails.environment!}
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
/>
|
||||||
</>
|
</>
|
||||||
),
|
|
||||||
[prodGuardModalState],
|
|
||||||
);
|
);
|
||||||
|
|
||||||
return { onToggle, modals };
|
return { onToggle, modals };
|
||||||
@ -305,7 +367,7 @@ export const createFeatureToggleCell =
|
|||||||
hasStrategies: environment?.hasStrategies,
|
hasStrategies: environment?.hasStrategies,
|
||||||
hasEnabledStrategies: environment?.hasEnabledStrategies,
|
hasEnabledStrategies: environment?.hasEnabledStrategies,
|
||||||
isChangeRequestEnabled,
|
isChangeRequestEnabled,
|
||||||
onError: onRollback,
|
onRollback,
|
||||||
onSuccess: refetch,
|
onSuccess: refetch,
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
@ -110,7 +110,7 @@ export const ProjectFeatureToggles = ({
|
|||||||
>();
|
>();
|
||||||
const projectId = useRequiredPathParam('projectId');
|
const projectId = useRequiredPathParam('projectId');
|
||||||
const { onToggle: onFeatureToggle, modals: featureToggleModals } =
|
const { onToggle: onFeatureToggle, modals: featureToggleModals } =
|
||||||
useFeatureToggleSwitch();
|
useFeatureToggleSwitch(projectId);
|
||||||
|
|
||||||
const { value: storedParams, setValue: setStoredParams } =
|
const { value: storedParams, setValue: setStoredParams } =
|
||||||
createLocalStorage(
|
createLocalStorage(
|
||||||
@ -134,11 +134,6 @@ export const ProjectFeatureToggles = ({
|
|||||||
: globalStore.favorites,
|
: globalStore.favorites,
|
||||||
);
|
);
|
||||||
const { favorite, unfavorite } = useFavoriteFeaturesApi();
|
const { favorite, unfavorite } = useFavoriteFeaturesApi();
|
||||||
const {
|
|
||||||
onChangeRequestToggleClose,
|
|
||||||
onChangeRequestToggleConfirm,
|
|
||||||
changeRequestDialogDetails,
|
|
||||||
} = useChangeRequestToggle(projectId);
|
|
||||||
const { isChangeRequestConfigured } = useChangeRequestsEnabled(projectId);
|
const { isChangeRequestConfigured } = useChangeRequestsEnabled(projectId);
|
||||||
const [showExportDialog, setShowExportDialog] = useState(false);
|
const [showExportDialog, setShowExportDialog] = useState(false);
|
||||||
const { uiConfig } = useUiConfig();
|
const { uiConfig } = useUiConfig();
|
||||||
@ -645,23 +640,6 @@ export const ProjectFeatureToggles = ({
|
|||||||
}}
|
}}
|
||||||
featureIds={[featureArchiveState || '']}
|
featureIds={[featureArchiveState || '']}
|
||||||
projectId={projectId}
|
projectId={projectId}
|
||||||
/>{' '}
|
|
||||||
<ChangeRequestDialogue
|
|
||||||
isOpen={changeRequestDialogDetails.isOpen}
|
|
||||||
onClose={onChangeRequestToggleClose}
|
|
||||||
environment={changeRequestDialogDetails?.environment}
|
|
||||||
onConfirm={onChangeRequestToggleConfirm}
|
|
||||||
messageComponent={
|
|
||||||
<UpdateEnabledMessage
|
|
||||||
featureName={
|
|
||||||
changeRequestDialogDetails.featureName!
|
|
||||||
}
|
|
||||||
enabled={changeRequestDialogDetails.enabled!}
|
|
||||||
environment={
|
|
||||||
changeRequestDialogDetails?.environment!
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
}
|
|
||||||
/>
|
/>
|
||||||
<ConditionallyRender
|
<ConditionallyRender
|
||||||
condition={
|
condition={
|
||||||
|
Loading…
Reference in New Issue
Block a user