From a748c0f98776f8bc0dc3d9e4a9bc5611a0c60ac4 Mon Sep 17 00:00:00 2001 From: Tymoteusz Czech <2625371+Tymek@users.noreply.github.com> Date: Wed, 18 Oct 2023 14:18:30 +0200 Subject: [PATCH] refactor: split new feature switch into multiple files --- .../EnableEnvironmentDialog.tsx | 14 +- .../NewFeatureToggleSwitch.tsx | 327 +----------------- .../NewFeatureToggleSwitch.types.ts | 18 + .../createFeatureToggleCell.tsx | 79 +++++ .../useFeatureToggleSwitch.tsx | 237 +++++++++++++ .../ProjectFeatureToggles.tsx | 12 +- 6 files changed, 348 insertions(+), 339 deletions(-) create mode 100644 frontend/src/component/project/Project/ProjectFeatureToggles/FeatureToggleSwitch/NewFeatureToggleSwitch.types.ts create mode 100644 frontend/src/component/project/Project/ProjectFeatureToggles/FeatureToggleSwitch/createFeatureToggleCell.tsx create mode 100644 frontend/src/component/project/Project/ProjectFeatureToggles/FeatureToggleSwitch/useFeatureToggleSwitch.tsx diff --git a/frontend/src/component/project/Project/ProjectFeatureToggles/FeatureToggleSwitch/EnableEnvironmentDialog/EnableEnvironmentDialog.tsx b/frontend/src/component/project/Project/ProjectFeatureToggles/FeatureToggleSwitch/EnableEnvironmentDialog/EnableEnvironmentDialog.tsx index 7c34de17e4..a11623974c 100644 --- a/frontend/src/component/project/Project/ProjectFeatureToggles/FeatureToggleSwitch/EnableEnvironmentDialog/EnableEnvironmentDialog.tsx +++ b/frontend/src/component/project/Project/ProjectFeatureToggles/FeatureToggleSwitch/EnableEnvironmentDialog/EnableEnvironmentDialog.tsx @@ -64,9 +64,17 @@ export const EnableEnvironmentDialog: FC = ({ > The feature toggle has {disabledStrategiesCount} disabled - {disabledStrategiesCount === 1 ? ' strategy' : ' strategies'}.} - elseShow={"The feature toggle has disabled strategies."} + show={ + <> + The feature toggle has {disabledStrategiesCount}{' '} + disabled + {disabledStrategiesCount === 1 + ? ' strategy' + : ' strategies'} + . + + } + elseShow={'The feature toggle has disabled strategies.'} /> diff --git a/frontend/src/component/project/Project/ProjectFeatureToggles/FeatureToggleSwitch/NewFeatureToggleSwitch.tsx b/frontend/src/component/project/Project/ProjectFeatureToggles/FeatureToggleSwitch/NewFeatureToggleSwitch.tsx index c935ce12e3..edb7b1f24f 100644 --- a/frontend/src/component/project/Project/ProjectFeatureToggles/FeatureToggleSwitch/NewFeatureToggleSwitch.tsx +++ b/frontend/src/component/project/Project/ProjectFeatureToggles/FeatureToggleSwitch/NewFeatureToggleSwitch.tsx @@ -1,48 +1,15 @@ -import { - ComponentProps, - useCallback, - useMemo, - useState, - type VFC, -} from 'react'; +import { type VFC } from 'react'; import { Box, styled } from '@mui/material'; import PermissionSwitch from 'component/common/PermissionSwitch/PermissionSwitch'; import { UPDATE_FEATURE_ENVIRONMENT } from 'component/providers/AccessProvider/permissions'; import { useOptimisticUpdate } from './hooks/useOptimisticUpdate'; import { flexRow } from 'themes/themeStyles'; -import { formatUnknownError } from 'utils/formatUnknownError'; -import useFeatureApi from 'hooks/api/actions/useFeatureApi/useFeatureApi'; -import useToast from 'hooks/useToast'; -import { useChangeRequestToggle } from 'hooks/useChangeRequestToggle'; -import { UpdateEnabledMessage } from 'component/changeRequest/ChangeRequestConfirmDialog/ChangeRequestMessages/UpdateEnabledMessage'; -import { ChangeRequestDialogue } from 'component/changeRequest/ChangeRequestConfirmDialog/ChangeRequestConfirmDialog'; -import { - FeatureStrategyProdGuard, - isProdGuardEnabled, -} from 'component/feature/FeatureStrategy/FeatureStrategyProdGuard/FeatureStrategyProdGuard'; -import { EnableEnvironmentDialog } from './EnableEnvironmentDialog/EnableEnvironmentDialog'; -import { ListItemType } from '../ProjectFeatureToggles.types'; -import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender'; -import VariantsWarningTooltip from 'component/feature/FeatureView/FeatureVariants/VariantsTooltipWarning'; const StyledBoxContainer = styled(Box)<{ 'data-testid': string }>(() => ({ mx: 'auto', ...flexRow, })); -type OnFeatureToggleSwitchArgs = { - featureId: string; - projectId: string; - environmentName: string; - environmentType?: string; - hasStrategies?: boolean; - hasEnabledStrategies?: boolean; - isChangeRequestEnabled?: boolean; - changeRequestToggle?: ReturnType; - onRollback?: () => void; - onSuccess?: () => void; -}; - type FeatureToggleSwitchProps = { featureId: string; projectId: string; @@ -51,225 +18,6 @@ type FeatureToggleSwitchProps = { onToggle: (newState: boolean, onRollback: () => void) => void; }; -type Middleware = (next: () => void) => void; - -const composeAndRunMiddlewares = (middlewares: Middleware[]) => { - const runMiddleware = (currentIndex: number) => { - if (currentIndex < middlewares.length) { - middlewares[currentIndex](() => runMiddleware(currentIndex + 1)); - } - }; - - runMiddleware(0); -}; - -export const useFeatureToggleSwitch = (projectId: string) => { - const { loading, toggleFeatureEnvironmentOn, toggleFeatureEnvironmentOff } = - useFeatureApi(); - const { setToastData, setToastApiError } = useToast(); - const [prodGuardModalState, setProdGuardModalState] = useState< - ComponentProps - >({ - open: false, - label: '', - loading: false, - onClose: () => {}, - onClick: () => {}, - }); - const [enableEnvironmentDialogState, setEnableEnvironmentDialogState] = - useState>({ - isOpen: false, - environment: '', - onClose: () => {}, - onActivateDisabledStrategies: () => {}, - onAddDefaultStrategy: () => {}, - }); - const { - onChangeRequestToggle, - onChangeRequestToggleClose, - onChangeRequestToggleConfirm, - changeRequestDialogDetails, - } = useChangeRequestToggle(projectId); - const [changeRequestDialogCallback, setChangeRequestDialogCallback] = - useState<() => void>(); - - const onToggle = useCallback( - async (newState: boolean, config: OnFeatureToggleSwitchArgs) => { - let shouldActivateDisabledStrategies = false; - - const confirmProductionChanges: Middleware = (next) => { - if (config.isChangeRequestEnabled) { - // skip if change requests are enabled - return next(); - } - - if (isProdGuardEnabled(config.environmentType || '')) { - setProdGuardModalState({ - open: true, - label: `${ - !newState ? 'Disable' : 'Enable' - } Environment`, - loading: false, - onClose: () => { - setProdGuardModalState((prev) => ({ - ...prev, - open: false, - })); - config.onRollback?.(); - }, - onClick: () => { - setProdGuardModalState((prev) => ({ - ...prev, - open: false, - loading: true, - })); - next(); - }, - }); - } - - return next(); - }; - - const ensureActiveStrategies: Middleware = (next) => { - if (!config.hasStrategies || config.hasEnabledStrategies) { - 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(); - }, - onAddDefaultStrategy: () => { - setEnableEnvironmentDialogState((prev) => ({ - ...prev, - isOpen: false, - })); - next(); - }, - }); - }; - - const addToChangeRequest: Middleware = (next) => { - if (!config.isChangeRequestEnabled) { - return next(); - } - - 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) => { - if (newState !== true) { - return next(); - } - - try { - await toggleFeatureEnvironmentOn( - config.projectId, - config.featureId, - config.environmentName, - shouldActivateDisabledStrategies, - ); - setToastData({ - type: 'success', - title: `Available in ${config.environmentName}`, - text: `${config.featureId} is now available in ${config.environmentName} based on its defined strategies.`, - }); - config.onSuccess?.(); - } catch (error: unknown) { - setToastApiError(formatUnknownError(error)); - config.onRollback?.(); - } - }; - - const handleToggleEnvironmentOff: Middleware = async (next) => { - if (newState !== false) { - return next(); - } - - try { - await toggleFeatureEnvironmentOff( - config.projectId, - config.featureId, - config.environmentName, - ); - setToastData({ - type: 'success', - title: `Unavailable in ${config.environmentName}`, - text: `${config.featureId} is unavailable in ${config.environmentName} and its strategies will no longer have any effect.`, - }); - config.onSuccess?.(); - } catch (error: unknown) { - setToastApiError(formatUnknownError(error)); - config.onRollback?.(); - } - }; - - return composeAndRunMiddlewares([ - confirmProductionChanges, - ensureActiveStrategies, - addToChangeRequest, - handleToggleEnvironmentOff, - handleToggleEnvironmentOn, - ]); - }, - [setProdGuardModalState], - ); - - const modals = ( - <> - - - { - changeRequestDialogCallback?.(); - onChangeRequestToggleClose(); - }} - environment={changeRequestDialogDetails?.environment} - onConfirm={() => { - changeRequestDialogCallback?.(); - onChangeRequestToggleConfirm(); - }} - messageComponent={ - - } - /> - - ); - - return { onToggle, modals }; -}; - export const FeatureToggleSwitch: VFC = ({ projectId, featureId, @@ -315,76 +63,3 @@ export const FeatureToggleSwitch: VFC = ({ ); }; - -const StyledSwitchContainer = styled('div', { - shouldForwardProp: (prop) => prop !== 'hasWarning', -})<{ hasWarning?: boolean }>(({ theme, hasWarning }) => ({ - flexGrow: 0, - ...flexRow, - justifyContent: 'center', - ...(hasWarning && { - '::before': { - content: '""', - display: 'block', - width: theme.spacing(2), - }, - }), -})); - -export const createFeatureToggleCell = - ( - projectId: string, - environmentName: string, - isChangeRequestEnabled: boolean, - refetch: () => void, - onFeatureToggleSwitch: ReturnType< - typeof useFeatureToggleSwitch - >['onToggle'], - ) => - ({ - value, - row: { original: feature }, - }: { - value: boolean; - row: { original: ListItemType }; - }) => { - const environment = feature.environments[environmentName]; - - const hasWarning = useMemo( - () => - feature.someEnabledEnvironmentHasVariants && - environment.variantCount === 0 && - environment.enabled, - [feature, environment], - ); - - const onToggle = (newState: boolean, onRollback: () => void) => { - onFeatureToggleSwitch(newState, { - projectId, - featureId: feature.name, - environmentName, - environmentType: environment?.type, - hasStrategies: environment?.hasStrategies, - hasEnabledStrategies: environment?.hasEnabledStrategies, - isChangeRequestEnabled, - onRollback, - onSuccess: refetch, - }); - }; - - return ( - - - } - /> - - ); - }; diff --git a/frontend/src/component/project/Project/ProjectFeatureToggles/FeatureToggleSwitch/NewFeatureToggleSwitch.types.ts b/frontend/src/component/project/Project/ProjectFeatureToggles/FeatureToggleSwitch/NewFeatureToggleSwitch.types.ts new file mode 100644 index 0000000000..734746c2be --- /dev/null +++ b/frontend/src/component/project/Project/ProjectFeatureToggles/FeatureToggleSwitch/NewFeatureToggleSwitch.types.ts @@ -0,0 +1,18 @@ +import { ReactNode } from 'react'; + +export type OnFeatureToggleSwitchArgs = { + featureId: string; + projectId: string; + environmentName: string; + environmentType?: string; + hasStrategies?: boolean; + hasEnabledStrategies?: boolean; + isChangeRequestEnabled?: boolean; + onRollback?: () => void; + onSuccess?: () => void; +}; + +export type UseFeatureToggleSwitchType = (projectId: string) => { + modals: ReactNode; + onToggle: (newState: boolean, config: OnFeatureToggleSwitchArgs) => void; +}; diff --git a/frontend/src/component/project/Project/ProjectFeatureToggles/FeatureToggleSwitch/createFeatureToggleCell.tsx b/frontend/src/component/project/Project/ProjectFeatureToggles/FeatureToggleSwitch/createFeatureToggleCell.tsx new file mode 100644 index 0000000000..120c8e73dc --- /dev/null +++ b/frontend/src/component/project/Project/ProjectFeatureToggles/FeatureToggleSwitch/createFeatureToggleCell.tsx @@ -0,0 +1,79 @@ +import { useMemo } from 'react'; +import { styled } from '@mui/material'; +import { flexRow } from 'themes/themeStyles'; +import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender'; +import VariantsWarningTooltip from 'component/feature/FeatureView/FeatureVariants/VariantsTooltipWarning'; +import { FeatureToggleSwitch } from './NewFeatureToggleSwitch'; +import type { ListItemType } from '../ProjectFeatureToggles.types'; +import type { UseFeatureToggleSwitchType } from './NewFeatureToggleSwitch.types'; + +const StyledSwitchContainer = styled('div', { + shouldForwardProp: (prop) => prop !== 'hasWarning', +})<{ hasWarning?: boolean }>(({ theme, hasWarning }) => ({ + flexGrow: 0, + ...flexRow, + justifyContent: 'center', + ...(hasWarning && { + '::before': { + content: '""', + display: 'block', + width: theme.spacing(2), + }, + }), +})); + +export const createFeatureToggleCell = + ( + projectId: string, + environmentName: string, + isChangeRequestEnabled: boolean, + refetch: () => void, + onFeatureToggleSwitch: ReturnType['onToggle'], + ) => + ({ + value, + row: { original: feature }, + }: { + value: boolean; + row: { original: ListItemType }; + }) => { + const environment = feature.environments[environmentName]; + + const hasWarning = useMemo( + () => + feature.someEnabledEnvironmentHasVariants && + environment.variantCount === 0 && + environment.enabled, + [feature, environment], + ); + + const onToggle = (newState: boolean, onRollback: () => void) => { + onFeatureToggleSwitch(newState, { + projectId, + featureId: feature.name, + environmentName, + environmentType: environment?.type, + hasStrategies: environment?.hasStrategies, + hasEnabledStrategies: environment?.hasEnabledStrategies, + isChangeRequestEnabled, + onRollback, + onSuccess: refetch, + }); + }; + + return ( + + + } + /> + + ); + }; diff --git a/frontend/src/component/project/Project/ProjectFeatureToggles/FeatureToggleSwitch/useFeatureToggleSwitch.tsx b/frontend/src/component/project/Project/ProjectFeatureToggles/FeatureToggleSwitch/useFeatureToggleSwitch.tsx new file mode 100644 index 0000000000..a8cca49cd6 --- /dev/null +++ b/frontend/src/component/project/Project/ProjectFeatureToggles/FeatureToggleSwitch/useFeatureToggleSwitch.tsx @@ -0,0 +1,237 @@ +import { ComponentProps, useCallback, useState } from 'react'; +import { formatUnknownError } from 'utils/formatUnknownError'; +import useFeatureApi from 'hooks/api/actions/useFeatureApi/useFeatureApi'; +import useToast from 'hooks/useToast'; +import { useChangeRequestToggle } from 'hooks/useChangeRequestToggle'; +import { UpdateEnabledMessage } from 'component/changeRequest/ChangeRequestConfirmDialog/ChangeRequestMessages/UpdateEnabledMessage'; +import { ChangeRequestDialogue } from 'component/changeRequest/ChangeRequestConfirmDialog/ChangeRequestConfirmDialog'; +import { + FeatureStrategyProdGuard, + isProdGuardEnabled, +} from 'component/feature/FeatureStrategy/FeatureStrategyProdGuard/FeatureStrategyProdGuard'; +import { EnableEnvironmentDialog } from './EnableEnvironmentDialog/EnableEnvironmentDialog'; +import { + OnFeatureToggleSwitchArgs, + UseFeatureToggleSwitchType, +} from './NewFeatureToggleSwitch.types'; + +type Middleware = (next: () => void) => void; + +const composeAndRunMiddlewares = (middlewares: Middleware[]) => { + const runMiddleware = (currentIndex: number) => { + if (currentIndex < middlewares.length) { + middlewares[currentIndex](() => runMiddleware(currentIndex + 1)); + } + }; + + runMiddleware(0); +}; + +export const useFeatureToggleSwitch: UseFeatureToggleSwitchType = ( + projectId: string, +) => { + const { toggleFeatureEnvironmentOn, toggleFeatureEnvironmentOff } = + useFeatureApi(); + const { setToastData, setToastApiError } = useToast(); + const [prodGuardModalState, setProdGuardModalState] = useState< + ComponentProps + >({ + open: false, + label: '', + loading: false, + onClose: () => {}, + onClick: () => {}, + }); + const [enableEnvironmentDialogState, setEnableEnvironmentDialogState] = + useState>({ + isOpen: false, + environment: '', + onClose: () => {}, + onActivateDisabledStrategies: () => {}, + onAddDefaultStrategy: () => {}, + }); + const { + onChangeRequestToggle, + onChangeRequestToggleClose, + onChangeRequestToggleConfirm, + changeRequestDialogDetails, + } = useChangeRequestToggle(projectId); + const [changeRequestDialogCallback, setChangeRequestDialogCallback] = + useState<() => void>(); + + const onToggle = useCallback( + async (newState: boolean, config: OnFeatureToggleSwitchArgs) => { + let shouldActivateDisabledStrategies = false; + + const confirmProductionChanges: Middleware = (next) => { + if (config.isChangeRequestEnabled) { + // skip if change requests are enabled + return next(); + } + + if (isProdGuardEnabled(config.environmentType || '')) { + setProdGuardModalState({ + open: true, + label: `${ + !newState ? 'Disable' : 'Enable' + } Environment`, + loading: false, + onClose: () => { + setProdGuardModalState((prev) => ({ + ...prev, + open: false, + })); + config.onRollback?.(); + }, + onClick: () => { + setProdGuardModalState((prev) => ({ + ...prev, + open: false, + loading: true, + })); + next(); + }, + }); + } + + return next(); + }; + + const ensureActiveStrategies: Middleware = (next) => { + if (!config.hasStrategies || config.hasEnabledStrategies) { + 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(); + }, + onAddDefaultStrategy: () => { + setEnableEnvironmentDialogState((prev) => ({ + ...prev, + isOpen: false, + })); + next(); + }, + }); + }; + + const addToChangeRequest: Middleware = (next) => { + if (!config.isChangeRequestEnabled) { + return next(); + } + + 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) => { + if (newState !== true) { + return next(); + } + + try { + await toggleFeatureEnvironmentOn( + config.projectId, + config.featureId, + config.environmentName, + shouldActivateDisabledStrategies, + ); + setToastData({ + type: 'success', + title: `Enabled in ${config.environmentName}`, + text: `${config.featureId} is now available in ${config.environmentName} based on its defined strategies.`, + }); + config.onSuccess?.(); + } catch (error: unknown) { + setToastApiError(formatUnknownError(error)); + config.onRollback?.(); + } + }; + + const handleToggleEnvironmentOff: Middleware = async (next) => { + if (newState !== false) { + return next(); + } + + try { + await toggleFeatureEnvironmentOff( + config.projectId, + config.featureId, + config.environmentName, + ); + setToastData({ + type: 'success', + title: `Disabled in ${config.environmentName}`, + text: `${config.featureId} is unavailable in ${config.environmentName} and its strategies will no longer have any effect.`, + }); + config.onSuccess?.(); + } catch (error: unknown) { + setToastApiError(formatUnknownError(error)); + config.onRollback?.(); + } + }; + + return composeAndRunMiddlewares([ + confirmProductionChanges, + ensureActiveStrategies, + addToChangeRequest, + handleToggleEnvironmentOff, + handleToggleEnvironmentOn, + ]); + }, + [setProdGuardModalState], + ); + + const modals = ( + <> + + + { + changeRequestDialogCallback?.(); + onChangeRequestToggleClose(); + }} + environment={changeRequestDialogDetails?.environment} + onConfirm={() => { + changeRequestDialogCallback?.(); + onChangeRequestToggleConfirm(); + }} + messageComponent={ + + } + /> + + ); + + return { onToggle, modals }; +}; diff --git a/frontend/src/component/project/Project/ProjectFeatureToggles/ProjectFeatureToggles.tsx b/frontend/src/component/project/Project/ProjectFeatureToggles/ProjectFeatureToggles.tsx index a58e965ef8..708b0fa509 100644 --- a/frontend/src/component/project/Project/ProjectFeatureToggles/ProjectFeatureToggles.tsx +++ b/frontend/src/component/project/Project/ProjectFeatureToggles/ProjectFeatureToggles.tsx @@ -38,9 +38,6 @@ import { FeatureStaleDialog } from 'component/common/FeatureStaleDialog/FeatureS import { FeatureArchiveDialog } from 'component/common/FeatureArchiveDialog/FeatureArchiveDialog'; import { getColumnValues, includesFilter, useSearch } from 'hooks/useSearch'; import { Search } from 'component/common/Search/Search'; -import { useChangeRequestToggle } from 'hooks/useChangeRequestToggle'; -import { ChangeRequestDialogue } from 'component/changeRequest/ChangeRequestConfirmDialog/ChangeRequestConfirmDialog'; -import { UpdateEnabledMessage } from 'component/changeRequest/ChangeRequestConfirmDialog/ChangeRequestMessages/UpdateEnabledMessage'; import { IFeatureToggleListItem } from 'interfaces/featureToggle'; import { FavoriteIconHeader } from 'component/common/Table/FavoriteIconHeader/FavoriteIconHeader'; import { FavoriteIconCell } from 'component/common/Table/cells/FavoriteIconCell/FavoriteIconCell'; @@ -48,11 +45,6 @@ import { ProjectEnvironmentType, useEnvironmentsRef, } from './hooks/useEnvironmentsRef'; -import { - FeatureToggleSwitch, - createFeatureToggleCell, - useFeatureToggleSwitch, -} from './FeatureToggleSwitch/NewFeatureToggleSwitch'; import { ActionsCell } from './ActionsCell/ActionsCell'; import { ColumnsMenu } from './ColumnsMenu/ColumnsMenu'; import { useStyles } from './ProjectFeatureToggles.styles'; @@ -60,8 +52,6 @@ import { usePinnedFavorites } from 'hooks/usePinnedFavorites'; import { useFavoriteFeaturesApi } from 'hooks/api/actions/useFavoriteFeaturesApi/useFavoriteFeaturesApi'; import { FeatureTagCell } from 'component/common/Table/cells/FeatureTagCell/FeatureTagCell'; import { useGlobalLocalStorage } from 'hooks/useGlobalLocalStorage'; -import { flexRow } from 'themes/themeStyles'; -import VariantsWarningTooltip from 'component/feature/FeatureView/FeatureVariants/VariantsTooltipWarning'; import FileDownload from '@mui/icons-material/FileDownload'; import useUiConfig from 'hooks/api/getters/useUiConfig/useUiConfig'; import { ExportDialog } from 'component/feature/FeatureToggleList/ExportDialog'; @@ -71,6 +61,8 @@ import { ProjectFeaturesBatchActions } from './ProjectFeaturesBatchActions/Proje import { FeatureEnvironmentSeenCell } from '../../../common/Table/cells/FeatureSeenCell/FeatureEnvironmentSeenCell'; import { useChangeRequestsEnabled } from 'hooks/useChangeRequestsEnabled'; import { ListItemType } from './ProjectFeatureToggles.types'; +import { createFeatureToggleCell } from './FeatureToggleSwitch/createFeatureToggleCell'; +import { useFeatureToggleSwitch } from './FeatureToggleSwitch/useFeatureToggleSwitch'; const StyledResponsiveButton = styled(ResponsiveButton)(() => ({ whiteSpace: 'nowrap',