mirror of
				https://github.com/Unleash/unleash.git
				synced 2025-10-27 11:02:16 +01:00 
			
		
		
		
	chore: remove create feature component (#7959)
After we implemented new feature flag creation flow, this are not used anymore. Creation is now handled by **CreateFeatureDialog**. Also edit component can be minified, because it does not need so many fields anymore.
This commit is contained in:
		
							parent
							
								
									e5cca661d9
								
							
						
					
					
						commit
						4a4dafcc3f
					
				@ -46,8 +46,6 @@ const BreadcrumbNav = () => {
 | 
				
			|||||||
                item !== 'copy' &&
 | 
					                item !== 'copy' &&
 | 
				
			||||||
                item !== 'features' &&
 | 
					                item !== 'features' &&
 | 
				
			||||||
                item !== 'features2' &&
 | 
					                item !== 'features2' &&
 | 
				
			||||||
                // TODO: this can be removed after new create flag flow goes live
 | 
					 | 
				
			||||||
                item !== 'create-toggle' &&
 | 
					 | 
				
			||||||
                item !== 'settings' &&
 | 
					                item !== 'settings' &&
 | 
				
			||||||
                item !== 'profile' &&
 | 
					                item !== 'profile' &&
 | 
				
			||||||
                item !== 'insights',
 | 
					                item !== 'insights',
 | 
				
			||||||
 | 
				
			|||||||
@ -1,93 +0,0 @@
 | 
				
			|||||||
import { screen, waitFor } from '@testing-library/react';
 | 
					 | 
				
			||||||
import { render } from 'utils/testRenderer';
 | 
					 | 
				
			||||||
import { testServerRoute, testServerSetup } from 'utils/testServer';
 | 
					 | 
				
			||||||
import CreateFeature from './CreateFeature';
 | 
					 | 
				
			||||||
import { CREATE_FEATURE } from 'component/providers/AccessProvider/permissions';
 | 
					 | 
				
			||||||
import { Route, Routes } from 'react-router-dom';
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
const server = testServerSetup();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
const setupApi = ({
 | 
					 | 
				
			||||||
    flagCount,
 | 
					 | 
				
			||||||
    flagLimit,
 | 
					 | 
				
			||||||
}: { flagCount: number; flagLimit: number }) => {
 | 
					 | 
				
			||||||
    testServerRoute(server, '/api/admin/ui-config', {
 | 
					 | 
				
			||||||
        flags: {
 | 
					 | 
				
			||||||
            resourceLimits: true,
 | 
					 | 
				
			||||||
        },
 | 
					 | 
				
			||||||
        resourceLimits: {
 | 
					 | 
				
			||||||
            featureFlags: flagLimit,
 | 
					 | 
				
			||||||
        },
 | 
					 | 
				
			||||||
    });
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    testServerRoute(server, '/api/admin/search/features', {
 | 
					 | 
				
			||||||
        total: flagCount,
 | 
					 | 
				
			||||||
        features: Array.from({ length: flagCount }).map((_, i) => ({
 | 
					 | 
				
			||||||
            name: `flag-${i}`,
 | 
					 | 
				
			||||||
        })),
 | 
					 | 
				
			||||||
    });
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
describe('button states', () => {
 | 
					 | 
				
			||||||
    test("should allow you to create feature flags when you're below the global limit", async () => {
 | 
					 | 
				
			||||||
        setupApi({ flagLimit: 3, flagCount: 2 });
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        render(
 | 
					 | 
				
			||||||
            <Routes>
 | 
					 | 
				
			||||||
                <Route
 | 
					 | 
				
			||||||
                    path='/projects/:projectId/create-toggle'
 | 
					 | 
				
			||||||
                    element={<CreateFeature />}
 | 
					 | 
				
			||||||
                />
 | 
					 | 
				
			||||||
            </Routes>,
 | 
					 | 
				
			||||||
            {
 | 
					 | 
				
			||||||
                route: '/projects/default/create-toggle',
 | 
					 | 
				
			||||||
                permissions: [{ permission: CREATE_FEATURE }],
 | 
					 | 
				
			||||||
            },
 | 
					 | 
				
			||||||
        );
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        const button = await screen.findByRole('button', {
 | 
					 | 
				
			||||||
            name: /create feature flag/i,
 | 
					 | 
				
			||||||
        });
 | 
					 | 
				
			||||||
        await waitFor(() => {
 | 
					 | 
				
			||||||
            expect(button).not.toBeDisabled();
 | 
					 | 
				
			||||||
        });
 | 
					 | 
				
			||||||
    });
 | 
					 | 
				
			||||||
});
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
describe('limit component', () => {
 | 
					 | 
				
			||||||
    test('should show limit reached info', async () => {
 | 
					 | 
				
			||||||
        setupApi({ flagLimit: 1, flagCount: 1 });
 | 
					 | 
				
			||||||
        render(
 | 
					 | 
				
			||||||
            <Routes>
 | 
					 | 
				
			||||||
                <Route
 | 
					 | 
				
			||||||
                    path='/projects/:projectId/create-toggle'
 | 
					 | 
				
			||||||
                    element={<CreateFeature />}
 | 
					 | 
				
			||||||
                />
 | 
					 | 
				
			||||||
            </Routes>,
 | 
					 | 
				
			||||||
            {
 | 
					 | 
				
			||||||
                route: '/projects/default/create-toggle',
 | 
					 | 
				
			||||||
                permissions: [{ permission: CREATE_FEATURE }],
 | 
					 | 
				
			||||||
            },
 | 
					 | 
				
			||||||
        );
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        await screen.findByText('You have reached the limit for feature flags');
 | 
					 | 
				
			||||||
    });
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    test('should show approaching limit info', async () => {
 | 
					 | 
				
			||||||
        setupApi({ flagLimit: 10, flagCount: 9 });
 | 
					 | 
				
			||||||
        render(
 | 
					 | 
				
			||||||
            <Routes>
 | 
					 | 
				
			||||||
                <Route
 | 
					 | 
				
			||||||
                    path='/projects/:projectId/create-toggle'
 | 
					 | 
				
			||||||
                    element={<CreateFeature />}
 | 
					 | 
				
			||||||
                />
 | 
					 | 
				
			||||||
            </Routes>,
 | 
					 | 
				
			||||||
            {
 | 
					 | 
				
			||||||
                route: '/projects/default/create-toggle',
 | 
					 | 
				
			||||||
                permissions: [{ permission: CREATE_FEATURE }],
 | 
					 | 
				
			||||||
            },
 | 
					 | 
				
			||||||
        );
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        await screen.findByText('You are nearing the limit for feature flags');
 | 
					 | 
				
			||||||
    });
 | 
					 | 
				
			||||||
});
 | 
					 | 
				
			||||||
@ -1,235 +0,0 @@
 | 
				
			|||||||
import FormTemplate from 'component/common/FormTemplate/FormTemplate';
 | 
					 | 
				
			||||||
import { useNavigate } from 'react-router-dom';
 | 
					 | 
				
			||||||
import FeatureForm from '../FeatureForm/FeatureForm';
 | 
					 | 
				
			||||||
import useFeatureForm from '../hooks/useFeatureForm';
 | 
					 | 
				
			||||||
import useUiConfig from 'hooks/api/getters/useUiConfig/useUiConfig';
 | 
					 | 
				
			||||||
import useToast from 'hooks/useToast';
 | 
					 | 
				
			||||||
import useFeatureApi from 'hooks/api/actions/useFeatureApi/useFeatureApi';
 | 
					 | 
				
			||||||
import { CREATE_FEATURE } from 'component/providers/AccessProvider/permissions';
 | 
					 | 
				
			||||||
import { useContext } from 'react';
 | 
					 | 
				
			||||||
import { CreateButton } from 'component/common/CreateButton/CreateButton';
 | 
					 | 
				
			||||||
import UIContext from 'contexts/UIContext';
 | 
					 | 
				
			||||||
import { CF_CREATE_BTN_ID } from 'utils/testIds';
 | 
					 | 
				
			||||||
import { formatUnknownError } from 'utils/formatUnknownError';
 | 
					 | 
				
			||||||
import { GO_BACK } from 'constants/navigate';
 | 
					 | 
				
			||||||
import { Alert, styled } from '@mui/material';
 | 
					 | 
				
			||||||
import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender';
 | 
					 | 
				
			||||||
import useProjectOverview, {
 | 
					 | 
				
			||||||
    featuresCount,
 | 
					 | 
				
			||||||
} from 'hooks/api/getters/useProjectOverview/useProjectOverview';
 | 
					 | 
				
			||||||
import { useUiFlag } from 'hooks/useUiFlag';
 | 
					 | 
				
			||||||
import { useGlobalFeatureSearch } from '../FeatureToggleList/useGlobalFeatureSearch';
 | 
					 | 
				
			||||||
import { Limit } from 'component/common/Limit/Limit';
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
const StyledAlert = styled(Alert)(({ theme }) => ({
 | 
					 | 
				
			||||||
    marginBottom: theme.spacing(2),
 | 
					 | 
				
			||||||
}));
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
export const isProjectFeatureLimitReached = (
 | 
					 | 
				
			||||||
    featureLimit: number | null | undefined,
 | 
					 | 
				
			||||||
    currentFeatureCount: number,
 | 
					 | 
				
			||||||
): boolean => {
 | 
					 | 
				
			||||||
    return (
 | 
					 | 
				
			||||||
        featureLimit !== null &&
 | 
					 | 
				
			||||||
        featureLimit !== undefined &&
 | 
					 | 
				
			||||||
        featureLimit <= currentFeatureCount
 | 
					 | 
				
			||||||
    );
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
const useGlobalFlagLimit = (flagLimit: number, flagCount: number) => {
 | 
					 | 
				
			||||||
    const resourceLimitsEnabled = useUiFlag('resourceLimits');
 | 
					 | 
				
			||||||
    const limitReached = resourceLimitsEnabled && flagCount >= flagLimit;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    return {
 | 
					 | 
				
			||||||
        limitReached,
 | 
					 | 
				
			||||||
        limitMessage: limitReached
 | 
					 | 
				
			||||||
            ? `You have reached the instance-wide limit of ${flagLimit} feature flags.`
 | 
					 | 
				
			||||||
            : undefined,
 | 
					 | 
				
			||||||
    };
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
type FlagLimitsProps = {
 | 
					 | 
				
			||||||
    global: { limit: number; count: number };
 | 
					 | 
				
			||||||
    project: { limit?: number; count: number };
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
export const useFlagLimits = ({ global, project }: FlagLimitsProps) => {
 | 
					 | 
				
			||||||
    const {
 | 
					 | 
				
			||||||
        limitReached: globalFlagLimitReached,
 | 
					 | 
				
			||||||
        limitMessage: globalLimitMessage,
 | 
					 | 
				
			||||||
    } = useGlobalFlagLimit(global.limit, global.count);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    const projectFlagLimitReached = isProjectFeatureLimitReached(
 | 
					 | 
				
			||||||
        project.limit,
 | 
					 | 
				
			||||||
        project.count,
 | 
					 | 
				
			||||||
    );
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    const limitMessage = globalFlagLimitReached
 | 
					 | 
				
			||||||
        ? globalLimitMessage
 | 
					 | 
				
			||||||
        : projectFlagLimitReached
 | 
					 | 
				
			||||||
          ? `You have reached the project limit of ${project.limit} feature flags.`
 | 
					 | 
				
			||||||
          : undefined;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    return {
 | 
					 | 
				
			||||||
        limitMessage,
 | 
					 | 
				
			||||||
        globalFlagLimitReached,
 | 
					 | 
				
			||||||
        projectFlagLimitReached,
 | 
					 | 
				
			||||||
    };
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
const CreateFeature = () => {
 | 
					 | 
				
			||||||
    const { setToastData, setToastApiError } = useToast();
 | 
					 | 
				
			||||||
    const { setShowFeedback } = useContext(UIContext);
 | 
					 | 
				
			||||||
    const { uiConfig } = useUiConfig();
 | 
					 | 
				
			||||||
    const navigate = useNavigate();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    const {
 | 
					 | 
				
			||||||
        type,
 | 
					 | 
				
			||||||
        setType,
 | 
					 | 
				
			||||||
        name,
 | 
					 | 
				
			||||||
        setName,
 | 
					 | 
				
			||||||
        project,
 | 
					 | 
				
			||||||
        setProject,
 | 
					 | 
				
			||||||
        description,
 | 
					 | 
				
			||||||
        setDescription,
 | 
					 | 
				
			||||||
        validateToggleName,
 | 
					 | 
				
			||||||
        impressionData,
 | 
					 | 
				
			||||||
        setImpressionData,
 | 
					 | 
				
			||||||
        getTogglePayload,
 | 
					 | 
				
			||||||
        clearErrors,
 | 
					 | 
				
			||||||
        errors,
 | 
					 | 
				
			||||||
    } = useFeatureForm();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    const { project: projectInfo } = useProjectOverview(project);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    const { createFeatureToggle, loading } = useFeatureApi();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    const { total: totalFlags, loading: loadingTotalFlagCount } =
 | 
					 | 
				
			||||||
        useGlobalFeatureSearch();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    const resourceLimitsEnabled = useUiFlag('resourceLimits');
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    const { globalFlagLimitReached, projectFlagLimitReached, limitMessage } =
 | 
					 | 
				
			||||||
        useFlagLimits({
 | 
					 | 
				
			||||||
            global: {
 | 
					 | 
				
			||||||
                limit: uiConfig.resourceLimits.featureFlags,
 | 
					 | 
				
			||||||
                count: totalFlags ?? 0,
 | 
					 | 
				
			||||||
            },
 | 
					 | 
				
			||||||
            project: {
 | 
					 | 
				
			||||||
                limit: projectInfo.featureLimit,
 | 
					 | 
				
			||||||
                count: featuresCount(projectInfo),
 | 
					 | 
				
			||||||
            },
 | 
					 | 
				
			||||||
        });
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    const handleSubmit = async (e: Event) => {
 | 
					 | 
				
			||||||
        e.preventDefault();
 | 
					 | 
				
			||||||
        clearErrors();
 | 
					 | 
				
			||||||
        const validToggleName = await validateToggleName();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        if (validToggleName) {
 | 
					 | 
				
			||||||
            const payload = getTogglePayload();
 | 
					 | 
				
			||||||
            try {
 | 
					 | 
				
			||||||
                await createFeatureToggle(project, payload);
 | 
					 | 
				
			||||||
                navigate(`/projects/${project}/features/${name}`, {
 | 
					 | 
				
			||||||
                    replace: true,
 | 
					 | 
				
			||||||
                });
 | 
					 | 
				
			||||||
                setToastData({
 | 
					 | 
				
			||||||
                    title: 'Flag created successfully',
 | 
					 | 
				
			||||||
                    text: 'Now you can start using your flag.',
 | 
					 | 
				
			||||||
                    confetti: true,
 | 
					 | 
				
			||||||
                    type: 'success',
 | 
					 | 
				
			||||||
                });
 | 
					 | 
				
			||||||
                setShowFeedback(true);
 | 
					 | 
				
			||||||
            } catch (error: unknown) {
 | 
					 | 
				
			||||||
                setToastApiError(formatUnknownError(error));
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    };
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    const formatApiCode = () => {
 | 
					 | 
				
			||||||
        return `curl --location --request POST '${
 | 
					 | 
				
			||||||
            uiConfig.unleashUrl
 | 
					 | 
				
			||||||
        }/api/admin/projects/${project}/features' \\
 | 
					 | 
				
			||||||
    --header 'Authorization: INSERT_API_KEY' \\
 | 
					 | 
				
			||||||
    --header 'Content-Type: application/json' \\
 | 
					 | 
				
			||||||
    --data-raw '${JSON.stringify(getTogglePayload(), undefined, 2)}'`;
 | 
					 | 
				
			||||||
    };
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    const handleCancel = () => {
 | 
					 | 
				
			||||||
        navigate(GO_BACK);
 | 
					 | 
				
			||||||
    };
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    return (
 | 
					 | 
				
			||||||
        <FormTemplate
 | 
					 | 
				
			||||||
            loading={loading}
 | 
					 | 
				
			||||||
            title='Create feature flag'
 | 
					 | 
				
			||||||
            description='Feature flags support different use cases, each with their own specific needs such as simple static routing or more complex routing.
 | 
					 | 
				
			||||||
            The feature flag is disabled when created and you decide when to enable'
 | 
					 | 
				
			||||||
            documentationLink='https://docs.getunleash.io/reference/feature-toggle-types'
 | 
					 | 
				
			||||||
            documentationLinkLabel='Feature flag types documentation'
 | 
					 | 
				
			||||||
            formatApiCode={formatApiCode}
 | 
					 | 
				
			||||||
        >
 | 
					 | 
				
			||||||
            <ConditionallyRender
 | 
					 | 
				
			||||||
                condition={projectFlagLimitReached}
 | 
					 | 
				
			||||||
                show={
 | 
					 | 
				
			||||||
                    <StyledAlert severity='error'>
 | 
					 | 
				
			||||||
                        <strong>Feature flag project limit reached. </strong> To
 | 
					 | 
				
			||||||
                        be able to create more feature flags in this project
 | 
					 | 
				
			||||||
                        please increase the feature flag upper limit in the
 | 
					 | 
				
			||||||
                        project settings.
 | 
					 | 
				
			||||||
                    </StyledAlert>
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
            />
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            <FeatureForm
 | 
					 | 
				
			||||||
                type={type}
 | 
					 | 
				
			||||||
                name={name}
 | 
					 | 
				
			||||||
                project={project}
 | 
					 | 
				
			||||||
                description={description}
 | 
					 | 
				
			||||||
                setType={setType}
 | 
					 | 
				
			||||||
                setName={setName}
 | 
					 | 
				
			||||||
                setProject={setProject}
 | 
					 | 
				
			||||||
                setDescription={setDescription}
 | 
					 | 
				
			||||||
                validateToggleName={validateToggleName}
 | 
					 | 
				
			||||||
                setImpressionData={setImpressionData}
 | 
					 | 
				
			||||||
                impressionData={impressionData}
 | 
					 | 
				
			||||||
                errors={errors}
 | 
					 | 
				
			||||||
                handleSubmit={handleSubmit}
 | 
					 | 
				
			||||||
                handleCancel={handleCancel}
 | 
					 | 
				
			||||||
                mode='Create'
 | 
					 | 
				
			||||||
                clearErrors={clearErrors}
 | 
					 | 
				
			||||||
                featureNaming={projectInfo.featureNaming}
 | 
					 | 
				
			||||||
                Limit={
 | 
					 | 
				
			||||||
                    <ConditionallyRender
 | 
					 | 
				
			||||||
                        condition={resourceLimitsEnabled}
 | 
					 | 
				
			||||||
                        show={
 | 
					 | 
				
			||||||
                            <Limit
 | 
					 | 
				
			||||||
                                name='feature flags'
 | 
					 | 
				
			||||||
                                limit={uiConfig.resourceLimits.featureFlags}
 | 
					 | 
				
			||||||
                                currentValue={totalFlags ?? 0}
 | 
					 | 
				
			||||||
                            />
 | 
					 | 
				
			||||||
                        }
 | 
					 | 
				
			||||||
                    />
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
            >
 | 
					 | 
				
			||||||
                <CreateButton
 | 
					 | 
				
			||||||
                    name='feature flag'
 | 
					 | 
				
			||||||
                    disabled={
 | 
					 | 
				
			||||||
                        loadingTotalFlagCount ||
 | 
					 | 
				
			||||||
                        globalFlagLimitReached ||
 | 
					 | 
				
			||||||
                        projectFlagLimitReached
 | 
					 | 
				
			||||||
                    }
 | 
					 | 
				
			||||||
                    permission={CREATE_FEATURE}
 | 
					 | 
				
			||||||
                    projectId={project}
 | 
					 | 
				
			||||||
                    data-testid={CF_CREATE_BTN_ID}
 | 
					 | 
				
			||||||
                    tooltipProps={{
 | 
					 | 
				
			||||||
                        title: limitMessage,
 | 
					 | 
				
			||||||
                        arrow: true,
 | 
					 | 
				
			||||||
                    }}
 | 
					 | 
				
			||||||
                />
 | 
					 | 
				
			||||||
            </FeatureForm>
 | 
					 | 
				
			||||||
        </FormTemplate>
 | 
					 | 
				
			||||||
    );
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
export default CreateFeature;
 | 
					 | 
				
			||||||
@ -1,6 +1,6 @@
 | 
				
			|||||||
import FormTemplate from 'component/common/FormTemplate/FormTemplate';
 | 
					import FormTemplate from 'component/common/FormTemplate/FormTemplate';
 | 
				
			||||||
import { useNavigate } from 'react-router-dom';
 | 
					import { useNavigate } from 'react-router-dom';
 | 
				
			||||||
import FeatureForm from '../FeatureForm/FeatureForm';
 | 
					import EditFeatureForm from '../FeatureForm/EditFeatureForm';
 | 
				
			||||||
import useFeatureForm from '../hooks/useFeatureForm';
 | 
					import useFeatureForm from '../hooks/useFeatureForm';
 | 
				
			||||||
import * as jsonpatch from 'fast-json-patch';
 | 
					import * as jsonpatch from 'fast-json-patch';
 | 
				
			||||||
import { UpdateButton } from 'component/common/UpdateButton/UpdateButton';
 | 
					import { UpdateButton } from 'component/common/UpdateButton/UpdateButton';
 | 
				
			||||||
@ -26,15 +26,12 @@ const EditFeature = () => {
 | 
				
			|||||||
        type,
 | 
					        type,
 | 
				
			||||||
        setType,
 | 
					        setType,
 | 
				
			||||||
        name,
 | 
					        name,
 | 
				
			||||||
        setName,
 | 
					 | 
				
			||||||
        project,
 | 
					        project,
 | 
				
			||||||
        setProject,
 | 
					 | 
				
			||||||
        description,
 | 
					        description,
 | 
				
			||||||
        setDescription,
 | 
					        setDescription,
 | 
				
			||||||
        impressionData,
 | 
					        impressionData,
 | 
				
			||||||
        setImpressionData,
 | 
					        setImpressionData,
 | 
				
			||||||
        clearErrors,
 | 
					        clearErrors,
 | 
				
			||||||
        errors,
 | 
					 | 
				
			||||||
    } = useFeatureForm(
 | 
					    } = useFeatureForm(
 | 
				
			||||||
        feature?.name,
 | 
					        feature?.name,
 | 
				
			||||||
        feature?.type,
 | 
					        feature?.type,
 | 
				
			||||||
@ -88,25 +85,19 @@ const EditFeature = () => {
 | 
				
			|||||||
            documentationLinkLabel='Feature flag types documentation'
 | 
					            documentationLinkLabel='Feature flag types documentation'
 | 
				
			||||||
            formatApiCode={formatApiCode}
 | 
					            formatApiCode={formatApiCode}
 | 
				
			||||||
        >
 | 
					        >
 | 
				
			||||||
            <FeatureForm
 | 
					            <EditFeatureForm
 | 
				
			||||||
                type={type}
 | 
					                type={type}
 | 
				
			||||||
                name={name}
 | 
					                name={name}
 | 
				
			||||||
                project={project}
 | 
					 | 
				
			||||||
                description={description}
 | 
					                description={description}
 | 
				
			||||||
                setType={setType}
 | 
					                setType={setType}
 | 
				
			||||||
                setName={setName}
 | 
					 | 
				
			||||||
                setProject={setProject}
 | 
					 | 
				
			||||||
                setDescription={setDescription}
 | 
					                setDescription={setDescription}
 | 
				
			||||||
                errors={errors}
 | 
					 | 
				
			||||||
                handleSubmit={handleSubmit}
 | 
					                handleSubmit={handleSubmit}
 | 
				
			||||||
                handleCancel={handleCancel}
 | 
					                handleCancel={handleCancel}
 | 
				
			||||||
                impressionData={impressionData}
 | 
					                impressionData={impressionData}
 | 
				
			||||||
                setImpressionData={setImpressionData}
 | 
					                setImpressionData={setImpressionData}
 | 
				
			||||||
                mode='Edit'
 | 
					 | 
				
			||||||
                clearErrors={clearErrors}
 | 
					 | 
				
			||||||
            >
 | 
					            >
 | 
				
			||||||
                <UpdateButton permission={UPDATE_FEATURE} projectId={project} />
 | 
					                <UpdateButton permission={UPDATE_FEATURE} projectId={project} />
 | 
				
			||||||
            </FeatureForm>
 | 
					            </EditFeatureForm>
 | 
				
			||||||
        </FormTemplate>
 | 
					        </FormTemplate>
 | 
				
			||||||
    );
 | 
					    );
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
				
			|||||||
@ -10,40 +10,23 @@ import {
 | 
				
			|||||||
    Box,
 | 
					    Box,
 | 
				
			||||||
} from '@mui/material';
 | 
					} from '@mui/material';
 | 
				
			||||||
import FeatureTypeSelect from '../FeatureView/FeatureSettings/FeatureSettingsMetadata/FeatureTypeSelect/FeatureTypeSelect';
 | 
					import FeatureTypeSelect from '../FeatureView/FeatureSettings/FeatureSettingsMetadata/FeatureTypeSelect/FeatureTypeSelect';
 | 
				
			||||||
import { CF_DESC_ID, CF_NAME_ID, CF_TYPE_ID } from 'utils/testIds';
 | 
					import { CF_DESC_ID, CF_TYPE_ID } from 'utils/testIds';
 | 
				
			||||||
import useFeatureTypes from 'hooks/api/getters/useFeatureTypes/useFeatureTypes';
 | 
					import useFeatureTypes from 'hooks/api/getters/useFeatureTypes/useFeatureTypes';
 | 
				
			||||||
import KeyboardArrowDownOutlined from '@mui/icons-material/KeyboardArrowDownOutlined';
 | 
					import KeyboardArrowDownOutlined from '@mui/icons-material/KeyboardArrowDownOutlined';
 | 
				
			||||||
import { projectFilterGenerator } from 'utils/projectFilterGenerator';
 | 
					 | 
				
			||||||
import FeatureProjectSelect from '../FeatureView/FeatureSettings/FeatureSettingsProject/FeatureProjectSelect/FeatureProjectSelect';
 | 
					 | 
				
			||||||
import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender';
 | 
					 | 
				
			||||||
import { trim } from 'component/common/util';
 | 
					 | 
				
			||||||
import Input from 'component/common/Input/Input';
 | 
					import Input from 'component/common/Input/Input';
 | 
				
			||||||
import { CREATE_FEATURE } from 'component/providers/AccessProvider/permissions';
 | 
					import type React from 'react';
 | 
				
			||||||
import { useNavigate } from 'react-router-dom';
 | 
					 | 
				
			||||||
import React from 'react';
 | 
					 | 
				
			||||||
import { useAuthPermissions } from 'hooks/api/getters/useAuth/useAuthPermissions';
 | 
					 | 
				
			||||||
import type { FeatureNamingType } from 'interfaces/project';
 | 
					 | 
				
			||||||
import { FeatureNamingPatternInfo } from '../FeatureNamingPatternInfo/FeatureNamingPatternInfo';
 | 
					 | 
				
			||||||
import type { CreateFeatureSchemaType } from 'openapi';
 | 
					import type { CreateFeatureSchemaType } from 'openapi';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
interface IFeatureToggleForm {
 | 
					interface IFeatureToggleForm {
 | 
				
			||||||
    type: CreateFeatureSchemaType;
 | 
					    type: CreateFeatureSchemaType;
 | 
				
			||||||
    name: string;
 | 
					    name: string;
 | 
				
			||||||
    description: string;
 | 
					    description: string;
 | 
				
			||||||
    project: string;
 | 
					 | 
				
			||||||
    impressionData: boolean;
 | 
					    impressionData: boolean;
 | 
				
			||||||
    setType: React.Dispatch<React.SetStateAction<CreateFeatureSchemaType>>;
 | 
					    setType: React.Dispatch<React.SetStateAction<CreateFeatureSchemaType>>;
 | 
				
			||||||
    setName: React.Dispatch<React.SetStateAction<string>>;
 | 
					 | 
				
			||||||
    setDescription: React.Dispatch<React.SetStateAction<string>>;
 | 
					    setDescription: React.Dispatch<React.SetStateAction<string>>;
 | 
				
			||||||
    setProject: React.Dispatch<React.SetStateAction<string>>;
 | 
					 | 
				
			||||||
    setImpressionData: React.Dispatch<React.SetStateAction<boolean>>;
 | 
					    setImpressionData: React.Dispatch<React.SetStateAction<boolean>>;
 | 
				
			||||||
    featureNaming?: FeatureNamingType;
 | 
					 | 
				
			||||||
    validateToggleName?: () => void;
 | 
					 | 
				
			||||||
    handleSubmit: (e: any) => void;
 | 
					    handleSubmit: (e: any) => void;
 | 
				
			||||||
    handleCancel: () => void;
 | 
					    handleCancel: () => void;
 | 
				
			||||||
    errors: { [key: string]: string };
 | 
					 | 
				
			||||||
    mode: 'Create' | 'Edit';
 | 
					 | 
				
			||||||
    clearErrors: () => void;
 | 
					 | 
				
			||||||
    children?: React.ReactNode;
 | 
					    children?: React.ReactNode;
 | 
				
			||||||
    Limit?: React.ReactNode;
 | 
					    Limit?: React.ReactNode;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@ -106,73 +89,37 @@ const LimitContainer = styled(Box)(({ theme }) => ({
 | 
				
			|||||||
    },
 | 
					    },
 | 
				
			||||||
}));
 | 
					}));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const FeatureForm: React.FC<IFeatureToggleForm> = ({
 | 
					const EditFeatureForm: React.FC<IFeatureToggleForm> = ({
 | 
				
			||||||
    children,
 | 
					    children,
 | 
				
			||||||
    type,
 | 
					    type,
 | 
				
			||||||
    name,
 | 
					    name,
 | 
				
			||||||
    description,
 | 
					    description,
 | 
				
			||||||
    project,
 | 
					 | 
				
			||||||
    setType,
 | 
					    setType,
 | 
				
			||||||
    setName,
 | 
					 | 
				
			||||||
    setDescription,
 | 
					    setDescription,
 | 
				
			||||||
    setProject,
 | 
					 | 
				
			||||||
    validateToggleName,
 | 
					 | 
				
			||||||
    featureNaming,
 | 
					 | 
				
			||||||
    setImpressionData,
 | 
					    setImpressionData,
 | 
				
			||||||
    impressionData,
 | 
					    impressionData,
 | 
				
			||||||
    handleSubmit,
 | 
					    handleSubmit,
 | 
				
			||||||
    handleCancel,
 | 
					    handleCancel,
 | 
				
			||||||
    errors,
 | 
					 | 
				
			||||||
    mode,
 | 
					 | 
				
			||||||
    clearErrors,
 | 
					 | 
				
			||||||
    Limit,
 | 
					    Limit,
 | 
				
			||||||
}) => {
 | 
					}) => {
 | 
				
			||||||
    const { featureTypes } = useFeatureTypes();
 | 
					    const { featureTypes } = useFeatureTypes();
 | 
				
			||||||
    const navigate = useNavigate();
 | 
					 | 
				
			||||||
    const { permissions } = useAuthPermissions();
 | 
					 | 
				
			||||||
    const editable = mode !== 'Edit';
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    const renderToggleDescription = () => {
 | 
					    const renderToggleDescription = () => {
 | 
				
			||||||
        return featureTypes.find((flag) => flag.id === type)?.description;
 | 
					        return featureTypes.find((flag) => flag.id === type)?.description;
 | 
				
			||||||
    };
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    const displayFeatureNamingInfo = Boolean(featureNaming?.pattern);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    React.useEffect(() => {
 | 
					 | 
				
			||||||
        if (featureNaming?.pattern && validateToggleName && name) {
 | 
					 | 
				
			||||||
            clearErrors();
 | 
					 | 
				
			||||||
            validateToggleName();
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }, [featureNaming?.pattern]);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    return (
 | 
					    return (
 | 
				
			||||||
        <StyledForm onSubmit={handleSubmit}>
 | 
					        <StyledForm onSubmit={handleSubmit}>
 | 
				
			||||||
            <StyledInputDescription>
 | 
					            <StyledInputDescription>
 | 
				
			||||||
                What would you like to call your flag?
 | 
					                What would you like to call your flag?
 | 
				
			||||||
            </StyledInputDescription>
 | 
					            </StyledInputDescription>
 | 
				
			||||||
            <ConditionallyRender
 | 
					 | 
				
			||||||
                condition={displayFeatureNamingInfo}
 | 
					 | 
				
			||||||
                show={
 | 
					 | 
				
			||||||
                    <FeatureNamingPatternInfo featureNaming={featureNaming!} />
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
            />
 | 
					 | 
				
			||||||
            <StyledInput
 | 
					            <StyledInput
 | 
				
			||||||
                autoFocus
 | 
					                autoFocus
 | 
				
			||||||
                disabled={mode === 'Edit'}
 | 
					                disabled={true}
 | 
				
			||||||
                label='Name'
 | 
					                label='Name'
 | 
				
			||||||
                aria-details={
 | 
					 | 
				
			||||||
                    displayFeatureNamingInfo
 | 
					 | 
				
			||||||
                        ? 'feature-naming-pattern-info'
 | 
					 | 
				
			||||||
                        : undefined
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
                id='feature-flag-name'
 | 
					                id='feature-flag-name'
 | 
				
			||||||
                error={Boolean(errors.name)}
 | 
					 | 
				
			||||||
                errorText={errors.name}
 | 
					 | 
				
			||||||
                onFocus={() => clearErrors()}
 | 
					 | 
				
			||||||
                value={name}
 | 
					                value={name}
 | 
				
			||||||
                onChange={(e) => setName(trim(e.target.value))}
 | 
					                onChange={() => {}}
 | 
				
			||||||
                data-testid={CF_NAME_ID}
 | 
					 | 
				
			||||||
                onBlur={validateToggleName}
 | 
					 | 
				
			||||||
            />
 | 
					            />
 | 
				
			||||||
            <StyledInputDescription>
 | 
					            <StyledInputDescription>
 | 
				
			||||||
                What kind of feature flag do you want?
 | 
					                What kind of feature flag do you want?
 | 
				
			||||||
@ -190,31 +137,6 @@ const FeatureForm: React.FC<IFeatureToggleForm> = ({
 | 
				
			|||||||
            <StyledTypeDescription>
 | 
					            <StyledTypeDescription>
 | 
				
			||||||
                {renderToggleDescription()}
 | 
					                {renderToggleDescription()}
 | 
				
			||||||
            </StyledTypeDescription>
 | 
					            </StyledTypeDescription>
 | 
				
			||||||
            <ConditionallyRender
 | 
					 | 
				
			||||||
                condition={editable}
 | 
					 | 
				
			||||||
                show={
 | 
					 | 
				
			||||||
                    <StyledInputDescription>
 | 
					 | 
				
			||||||
                        In which project do you want to save the flag?
 | 
					 | 
				
			||||||
                    </StyledInputDescription>
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
            />
 | 
					 | 
				
			||||||
            {/* TODO: this can be removed after new create flag flow goes live */}
 | 
					 | 
				
			||||||
            <FeatureProjectSelect
 | 
					 | 
				
			||||||
                value={project}
 | 
					 | 
				
			||||||
                onChange={(projectId) => {
 | 
					 | 
				
			||||||
                    setProject(projectId);
 | 
					 | 
				
			||||||
                    navigate(`/projects/${projectId}/create-toggle`, {
 | 
					 | 
				
			||||||
                        replace: true,
 | 
					 | 
				
			||||||
                    });
 | 
					 | 
				
			||||||
                }}
 | 
					 | 
				
			||||||
                enabled={editable}
 | 
					 | 
				
			||||||
                filter={projectFilterGenerator(
 | 
					 | 
				
			||||||
                    permissions || [],
 | 
					 | 
				
			||||||
                    CREATE_FEATURE,
 | 
					 | 
				
			||||||
                )}
 | 
					 | 
				
			||||||
                IconComponent={KeyboardArrowDownOutlined}
 | 
					 | 
				
			||||||
                sx={styledSelectInput}
 | 
					 | 
				
			||||||
            />
 | 
					 | 
				
			||||||
            <StyledInputDescription>
 | 
					            <StyledInputDescription>
 | 
				
			||||||
                How would you describe your feature flag?
 | 
					                How would you describe your feature flag?
 | 
				
			||||||
            </StyledInputDescription>
 | 
					            </StyledInputDescription>
 | 
				
			||||||
@ -276,4 +198,4 @@ const FeatureForm: React.FC<IFeatureToggleForm> = ({
 | 
				
			|||||||
    );
 | 
					    );
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export default FeatureForm;
 | 
					export default EditFeatureForm;
 | 
				
			||||||
@ -65,14 +65,6 @@ exports[`returns all baseRoutes 1`] = `
 | 
				
			|||||||
    "title": "FeatureView",
 | 
					    "title": "FeatureView",
 | 
				
			||||||
    "type": "protected",
 | 
					    "type": "protected",
 | 
				
			||||||
  },
 | 
					  },
 | 
				
			||||||
  {
 | 
					 | 
				
			||||||
    "component": [Function],
 | 
					 | 
				
			||||||
    "menu": {},
 | 
					 | 
				
			||||||
    "parent": "/projects/:projectId/features",
 | 
					 | 
				
			||||||
    "path": "/projects/:projectId/create-toggle",
 | 
					 | 
				
			||||||
    "title": "Create feature flag",
 | 
					 | 
				
			||||||
    "type": "protected",
 | 
					 | 
				
			||||||
  },
 | 
					 | 
				
			||||||
  {
 | 
					  {
 | 
				
			||||||
    "component": {
 | 
					    "component": {
 | 
				
			||||||
      "$$typeof": Symbol(react.lazy),
 | 
					      "$$typeof": Symbol(react.lazy),
 | 
				
			||||||
 | 
				
			|||||||
@ -16,7 +16,6 @@ import EditEnvironment from 'component/environments/EditEnvironment/EditEnvironm
 | 
				
			|||||||
import { EditContext } from 'component/context/EditContext/EditContext';
 | 
					import { EditContext } from 'component/context/EditContext/EditContext';
 | 
				
			||||||
import EditTagType from 'component/tags/EditTagType/EditTagType';
 | 
					import EditTagType from 'component/tags/EditTagType/EditTagType';
 | 
				
			||||||
import CreateTagType from 'component/tags/CreateTagType/CreateTagType';
 | 
					import CreateTagType from 'component/tags/CreateTagType/CreateTagType';
 | 
				
			||||||
import CreateFeature from 'component/feature/CreateFeature/CreateFeature';
 | 
					 | 
				
			||||||
import EditFeature from 'component/feature/EditFeature/EditFeature';
 | 
					import EditFeature from 'component/feature/EditFeature/EditFeature';
 | 
				
			||||||
import ContextList from 'component/context/ContextList/ContextList/ContextList';
 | 
					import ContextList from 'component/context/ContextList/ContextList/ContextList';
 | 
				
			||||||
import { CreateIntegration } from 'component/integrations/CreateIntegration/CreateIntegration';
 | 
					import { CreateIntegration } from 'component/integrations/CreateIntegration/CreateIntegration';
 | 
				
			||||||
@ -102,14 +101,6 @@ export const routes: IRoute[] = [
 | 
				
			|||||||
        type: 'protected',
 | 
					        type: 'protected',
 | 
				
			||||||
        menu: {},
 | 
					        menu: {},
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        path: '/projects/:projectId/create-toggle',
 | 
					 | 
				
			||||||
        parent: '/projects/:projectId/features',
 | 
					 | 
				
			||||||
        title: 'Create feature flag',
 | 
					 | 
				
			||||||
        component: CreateFeature,
 | 
					 | 
				
			||||||
        type: 'protected',
 | 
					 | 
				
			||||||
        menu: {},
 | 
					 | 
				
			||||||
    },
 | 
					 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        path: '/projects/:projectId/*',
 | 
					        path: '/projects/:projectId/*',
 | 
				
			||||||
        parent: '/projects',
 | 
					        parent: '/projects',
 | 
				
			||||||
 | 
				
			|||||||
@ -21,7 +21,6 @@ import useFeatureForm from 'component/feature/hooks/useFeatureForm';
 | 
				
			|||||||
import useFeatureApi from 'hooks/api/actions/useFeatureApi/useFeatureApi';
 | 
					import useFeatureApi from 'hooks/api/actions/useFeatureApi/useFeatureApi';
 | 
				
			||||||
import FlagIcon from '@mui/icons-material/Flag';
 | 
					import FlagIcon from '@mui/icons-material/Flag';
 | 
				
			||||||
import ImpressionDataIcon from '@mui/icons-material/AltRoute';
 | 
					import ImpressionDataIcon from '@mui/icons-material/AltRoute';
 | 
				
			||||||
import { useFlagLimits } from 'component/feature/CreateFeature/CreateFeature';
 | 
					 | 
				
			||||||
import { useGlobalFeatureSearch } from 'component/feature/FeatureToggleList/useGlobalFeatureSearch';
 | 
					import { useGlobalFeatureSearch } from 'component/feature/FeatureToggleList/useGlobalFeatureSearch';
 | 
				
			||||||
import useProjectOverview, {
 | 
					import useProjectOverview, {
 | 
				
			||||||
    featuresCount,
 | 
					    featuresCount,
 | 
				
			||||||
@ -37,6 +36,7 @@ import { ProjectIcon } from 'component/common/ProjectIcon/ProjectIcon';
 | 
				
			|||||||
import { MultiSelectConfigButton } from 'component/common/DialogFormTemplate/ConfigButtons/MultiSelectConfigButton';
 | 
					import { MultiSelectConfigButton } from 'component/common/DialogFormTemplate/ConfigButtons/MultiSelectConfigButton';
 | 
				
			||||||
import type { ITag } from 'interfaces/tags';
 | 
					import type { ITag } from 'interfaces/tags';
 | 
				
			||||||
import { ToggleConfigButton } from 'component/common/DialogFormTemplate/ConfigButtons/ToggleConfigButton';
 | 
					import { ToggleConfigButton } from 'component/common/DialogFormTemplate/ConfigButtons/ToggleConfigButton';
 | 
				
			||||||
 | 
					import { useFlagLimits } from './useFlagLimits';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
interface ICreateFeatureDialogProps {
 | 
					interface ICreateFeatureDialogProps {
 | 
				
			||||||
    open: boolean;
 | 
					    open: boolean;
 | 
				
			||||||
 | 
				
			|||||||
@ -1,4 +1,4 @@
 | 
				
			|||||||
import { isProjectFeatureLimitReached } from './CreateFeature';
 | 
					import { isProjectFeatureLimitReached } from './useFlagLimits';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
test('isFeatureLimitReached  should return false when featureLimit is null', async () => {
 | 
					test('isFeatureLimitReached  should return false when featureLimit is null', async () => {
 | 
				
			||||||
    expect(isProjectFeatureLimitReached(null, 5)).toBe(false);
 | 
					    expect(isProjectFeatureLimitReached(null, 5)).toBe(false);
 | 
				
			||||||
@ -1,6 +1,6 @@
 | 
				
			|||||||
import { renderHook } from '@testing-library/react';
 | 
					import { renderHook } from '@testing-library/react';
 | 
				
			||||||
import { useFlagLimits } from './CreateFeature';
 | 
					 | 
				
			||||||
import { vi } from 'vitest';
 | 
					import { vi } from 'vitest';
 | 
				
			||||||
 | 
					import { useFlagLimits } from './useFlagLimits';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
vi.mock('hooks/useUiFlag', async (importOriginal) => {
 | 
					vi.mock('hooks/useUiFlag', async (importOriginal) => {
 | 
				
			||||||
    const actual = await importOriginal();
 | 
					    const actual = await importOriginal();
 | 
				
			||||||
@ -0,0 +1,53 @@
 | 
				
			|||||||
 | 
					import { useUiFlag } from 'hooks/useUiFlag';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type FlagLimitsProps = {
 | 
				
			||||||
 | 
					    global: { limit: number; count: number };
 | 
				
			||||||
 | 
					    project: { limit?: number; count: number };
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export const useFlagLimits = ({ global, project }: FlagLimitsProps) => {
 | 
				
			||||||
 | 
					    const {
 | 
				
			||||||
 | 
					        limitReached: globalFlagLimitReached,
 | 
				
			||||||
 | 
					        limitMessage: globalLimitMessage,
 | 
				
			||||||
 | 
					    } = useGlobalFlagLimit(global.limit, global.count);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const projectFlagLimitReached = isProjectFeatureLimitReached(
 | 
				
			||||||
 | 
					        project.limit,
 | 
				
			||||||
 | 
					        project.count,
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const limitMessage = globalFlagLimitReached
 | 
				
			||||||
 | 
					        ? globalLimitMessage
 | 
				
			||||||
 | 
					        : projectFlagLimitReached
 | 
				
			||||||
 | 
					          ? `You have reached the project limit of ${project.limit} feature flags.`
 | 
				
			||||||
 | 
					          : undefined;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return {
 | 
				
			||||||
 | 
					        limitMessage,
 | 
				
			||||||
 | 
					        globalFlagLimitReached,
 | 
				
			||||||
 | 
					        projectFlagLimitReached,
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const useGlobalFlagLimit = (flagLimit: number, flagCount: number) => {
 | 
				
			||||||
 | 
					    const resourceLimitsEnabled = useUiFlag('resourceLimits');
 | 
				
			||||||
 | 
					    const limitReached = resourceLimitsEnabled && flagCount >= flagLimit;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return {
 | 
				
			||||||
 | 
					        limitReached,
 | 
				
			||||||
 | 
					        limitMessage: limitReached
 | 
				
			||||||
 | 
					            ? `You have reached the instance-wide limit of ${flagLimit} feature flags.`
 | 
				
			||||||
 | 
					            : undefined,
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export const isProjectFeatureLimitReached = (
 | 
				
			||||||
 | 
					    featureLimit: number | null | undefined,
 | 
				
			||||||
 | 
					    currentFeatureCount: number,
 | 
				
			||||||
 | 
					): boolean => {
 | 
				
			||||||
 | 
					    return (
 | 
				
			||||||
 | 
					        featureLimit !== null &&
 | 
				
			||||||
 | 
					        featureLimit !== undefined &&
 | 
				
			||||||
 | 
					        featureLimit <= currentFeatureCount
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
@ -6,7 +6,7 @@ export const getCreateTogglePath = (
 | 
				
			|||||||
    projectId: string,
 | 
					    projectId: string,
 | 
				
			||||||
    query?: Record<string, string>,
 | 
					    query?: Record<string, string>,
 | 
				
			||||||
) => {
 | 
					) => {
 | 
				
			||||||
    const path = `/projects/${projectId}/create-toggle`;
 | 
					    const path = `/projects/${projectId}?create=true`;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    let queryString: string | undefined;
 | 
					    let queryString: string | undefined;
 | 
				
			||||||
    if (query) {
 | 
					    if (query) {
 | 
				
			||||||
@ -16,12 +16,8 @@ export const getCreateTogglePath = (
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (queryString) {
 | 
					    if (queryString) {
 | 
				
			||||||
        return `${path}?${queryString}`;
 | 
					        return `${path}&${queryString}`;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    return path;
 | 
					    return path;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					 | 
				
			||||||
export const getProjectEditPath = (projectId: string) => {
 | 
					 | 
				
			||||||
    return `/projects/${projectId}/settings`;
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
		Reference in New Issue
	
	Block a user