diff --git a/frontend/src/component/common/BreadcrumbNav/BreadcrumbNav.tsx b/frontend/src/component/common/BreadcrumbNav/BreadcrumbNav.tsx index f022381f6c..937dd38814 100644 --- a/frontend/src/component/common/BreadcrumbNav/BreadcrumbNav.tsx +++ b/frontend/src/component/common/BreadcrumbNav/BreadcrumbNav.tsx @@ -46,8 +46,6 @@ const BreadcrumbNav = () => { item !== 'copy' && item !== 'features' && item !== 'features2' && - // TODO: this can be removed after new create flag flow goes live - item !== 'create-toggle' && item !== 'settings' && item !== 'profile' && item !== 'insights', diff --git a/frontend/src/component/feature/CreateFeature/CreateFeature.test.tsx b/frontend/src/component/feature/CreateFeature/CreateFeature.test.tsx deleted file mode 100644 index 6215809f4d..0000000000 --- a/frontend/src/component/feature/CreateFeature/CreateFeature.test.tsx +++ /dev/null @@ -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( - - } - /> - , - { - 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( - - } - /> - , - { - 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( - - } - /> - , - { - route: '/projects/default/create-toggle', - permissions: [{ permission: CREATE_FEATURE }], - }, - ); - - await screen.findByText('You are nearing the limit for feature flags'); - }); -}); diff --git a/frontend/src/component/feature/CreateFeature/CreateFeature.tsx b/frontend/src/component/feature/CreateFeature/CreateFeature.tsx deleted file mode 100644 index bb059bf26f..0000000000 --- a/frontend/src/component/feature/CreateFeature/CreateFeature.tsx +++ /dev/null @@ -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 ( - - - Feature flag project limit reached. To - be able to create more feature flags in this project - please increase the feature flag upper limit in the - project settings. - - } - /> - - - } - /> - } - > - - - - ); -}; - -export default CreateFeature; diff --git a/frontend/src/component/feature/EditFeature/EditFeature.tsx b/frontend/src/component/feature/EditFeature/EditFeature.tsx deleted file mode 100644 index 333f1d7e9f..0000000000 --- a/frontend/src/component/feature/EditFeature/EditFeature.tsx +++ /dev/null @@ -1,114 +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 * as jsonpatch from 'fast-json-patch'; -import { UpdateButton } from 'component/common/UpdateButton/UpdateButton'; -import { UPDATE_FEATURE } from 'component/providers/AccessProvider/permissions'; -import useFeatureApi from 'hooks/api/actions/useFeatureApi/useFeatureApi'; -import { useFeature } from 'hooks/api/getters/useFeature/useFeature'; -import useUiConfig from 'hooks/api/getters/useUiConfig/useUiConfig'; -import useToast from 'hooks/useToast'; -import { formatUnknownError } from 'utils/formatUnknownError'; -import { useRequiredPathParam } from 'hooks/useRequiredPathParam'; -import { GO_BACK } from 'constants/navigate'; - -const EditFeature = () => { - const projectId = useRequiredPathParam('projectId'); - const featureId = useRequiredPathParam('featureId'); - const { setToastData, setToastApiError } = useToast(); - const { uiConfig } = useUiConfig(); - const navigate = useNavigate(); - const { patchFeatureToggle: patchFeatureFlag, loading } = useFeatureApi(); - const { feature } = useFeature(projectId, featureId); - - const { - type, - setType, - name, - setName, - project, - setProject, - description, - setDescription, - impressionData, - setImpressionData, - clearErrors, - errors, - } = useFeatureForm( - feature?.name, - feature?.type, - feature?.project, - feature?.description, - feature?.impressionData, - ); - - const createPatch = () => { - const comparison = { ...feature, type, description, impressionData }; - const patch = jsonpatch.compare(feature, comparison); - return patch; - }; - - const handleSubmit = async (e: Event) => { - e.preventDefault(); - clearErrors(); - const patch = createPatch(); - try { - await patchFeatureFlag(project, featureId, patch); - navigate(`/projects/${project}/features/${name}`); - setToastData({ - title: 'Flag updated successfully', - type: 'success', - }); - } catch (error: unknown) { - setToastApiError(formatUnknownError(error)); - } - }; - - const formatApiCode = () => { - return `curl --location --request PATCH '${ - uiConfig.unleashUrl - }/api/admin/projects/${projectId}/features/${featureId}' \\ - --header 'Authorization: INSERT_API_KEY' \\ - --header 'Content-Type: application/json' \\ - --data-raw '${JSON.stringify(createPatch(), undefined, 2)}'`; - }; - - const handleCancel = () => { - navigate(GO_BACK); - }; - - return ( - - - - - - ); -}; - -export default EditFeature; diff --git a/frontend/src/component/feature/FeatureForm/FeatureForm.tsx b/frontend/src/component/feature/FeatureForm/FeatureForm.tsx deleted file mode 100644 index 57ae8124f7..0000000000 --- a/frontend/src/component/feature/FeatureForm/FeatureForm.tsx +++ /dev/null @@ -1,279 +0,0 @@ -import { - Button, - FormControl, - FormControlLabel, - styled, - Switch, - type Theme, - Typography, - Link, - Box, -} from '@mui/material'; -import FeatureTypeSelect from '../FeatureView/FeatureSettings/FeatureSettingsMetadata/FeatureTypeSelect/FeatureTypeSelect'; -import { CF_DESC_ID, CF_NAME_ID, CF_TYPE_ID } from 'utils/testIds'; -import useFeatureTypes from 'hooks/api/getters/useFeatureTypes/useFeatureTypes'; -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 { CREATE_FEATURE } from 'component/providers/AccessProvider/permissions'; -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'; - -interface IFeatureToggleForm { - type: CreateFeatureSchemaType; - name: string; - description: string; - project: string; - impressionData: boolean; - setType: React.Dispatch>; - setName: React.Dispatch>; - setDescription: React.Dispatch>; - setProject: React.Dispatch>; - setImpressionData: React.Dispatch>; - featureNaming?: FeatureNamingType; - validateToggleName?: () => void; - handleSubmit: (e: any) => void; - handleCancel: () => void; - errors: { [key: string]: string }; - mode: 'Create' | 'Edit'; - clearErrors: () => void; - children?: React.ReactNode; - Limit?: React.ReactNode; -} - -const StyledForm = styled('form')({ - height: '100%', -}); - -const StyledInputDescription = styled('p')(({ theme }) => ({ - marginBottom: theme.spacing(1), -})); - -const StyledInput = styled(Input)(({ theme }) => ({ - width: '100%', - marginBottom: theme.spacing(2), -})); - -const StyledFormControl = styled(FormControl)(({ theme }) => ({ - width: '100%', - marginBottom: theme.spacing(2), -})); - -const styledSelectInput = (theme: Theme) => ({ - marginBottom: theme.spacing(2), - minWidth: '400px', - [theme.breakpoints.down('sm')]: { - minWidth: '379px', - }, -}); - -const StyledTypeDescription = styled('p')(({ theme }) => ({ - fontSize: theme.fontSizes.smallBody, - color: theme.palette.text.secondary, - top: '-13px', - position: 'relative', -})); - -const StyledButtonContainer = styled('div')({ - display: 'flex', - justifyContent: 'flex-end', -}); - -const StyledRow = styled('div')(({ theme }) => ({ - display: 'flex', - alignItems: 'center', - marginTop: theme.spacing(1), -})); - -const StyledCancelButton = styled(Button)(({ theme }) => ({ - marginLeft: theme.spacing(3), -})); - -const styledTypography = (theme: Theme) => ({ - margin: theme.spacing(1, 0), -}); - -const LimitContainer = styled(Box)(({ theme }) => ({ - '&:has(*)': { - marginBottom: theme.spacing(2), - }, -})); - -const FeatureForm: React.FC = ({ - children, - type, - name, - description, - project, - setType, - setName, - setDescription, - setProject, - validateToggleName, - featureNaming, - setImpressionData, - impressionData, - handleSubmit, - handleCancel, - errors, - mode, - clearErrors, - Limit, -}) => { - const { featureTypes } = useFeatureTypes(); - const navigate = useNavigate(); - const { permissions } = useAuthPermissions(); - const editable = mode !== 'Edit'; - - const renderToggleDescription = () => { - 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 ( - - - What would you like to call your flag? - - - } - /> - clearErrors()} - value={name} - onChange={(e) => setName(trim(e.target.value))} - data-testid={CF_NAME_ID} - onBlur={validateToggleName} - /> - - What kind of feature flag do you want? - - - - {renderToggleDescription()} - - - In which project do you want to save the flag? - - } - /> - {/* TODO: this can be removed after new create flag flow goes live */} - { - setProject(projectId); - navigate(`/projects/${projectId}/create-toggle`, { - replace: true, - }); - }} - enabled={editable} - filter={projectFilterGenerator( - permissions || [], - CREATE_FEATURE, - )} - IconComponent={KeyboardArrowDownOutlined} - sx={styledSelectInput} - /> - - How would you describe your feature flag? - - setDescription(e.target.value)} - /> - - - Impression Data - - - When you enable impression data for a feature flag, your - client SDKs will emit events you can listen for every time - this flag gets triggered. Learn more in{' '} - - the impression data documentation - - - - - setImpressionData(!impressionData) - } - checked={impressionData} - /> - } - label='Enable impression data' - /> - - - {Limit} - - {children} - - Cancel - - - - ); -}; - -export default FeatureForm; diff --git a/frontend/src/component/menu/routes.ts b/frontend/src/component/menu/routes.ts index b7901e0157..024d5c159a 100644 --- a/frontend/src/component/menu/routes.ts +++ b/frontend/src/component/menu/routes.ts @@ -16,8 +16,6 @@ import EditEnvironment from 'component/environments/EditEnvironment/EditEnvironm import { EditContext } from 'component/context/EditContext/EditContext'; import EditTagType from 'component/tags/EditTagType/EditTagType'; import CreateTagType from 'component/tags/CreateTagType/CreateTagType'; -import CreateFeature from 'component/feature/CreateFeature/CreateFeature'; -import EditFeature from 'component/feature/EditFeature/EditFeature'; import ContextList from 'component/context/ContextList/ContextList/ContextList'; import { CreateIntegration } from 'component/integrations/CreateIntegration/CreateIntegration'; import { EditIntegration } from 'component/integrations/EditIntegration/EditIntegration'; @@ -86,14 +84,6 @@ export const routes: IRoute[] = [ type: 'protected', menu: {}, }, - { - path: '/projects/:projectId/features/:featureId/edit', - parent: '/projects', - title: 'Edit feature', - component: EditFeature, - type: 'protected', - menu: {}, - }, { path: '/projects/:projectId/features/:featureId/*', parent: '/projects', @@ -102,14 +92,6 @@ export const routes: IRoute[] = [ type: 'protected', menu: {}, }, - { - path: '/projects/:projectId/create-toggle', - parent: '/projects/:projectId/features', - title: 'Create feature flag', - component: CreateFeature, - type: 'protected', - menu: {}, - }, { path: '/projects/:projectId/*', parent: '/projects', diff --git a/frontend/src/component/project/Project/PaginatedProjectFeatureToggles/ProjectFeatureTogglesHeader/CreateFeatureDialog.tsx b/frontend/src/component/project/Project/PaginatedProjectFeatureToggles/ProjectFeatureTogglesHeader/CreateFeatureDialog.tsx index 616434619f..66dd34060d 100644 --- a/frontend/src/component/project/Project/PaginatedProjectFeatureToggles/ProjectFeatureTogglesHeader/CreateFeatureDialog.tsx +++ b/frontend/src/component/project/Project/PaginatedProjectFeatureToggles/ProjectFeatureTogglesHeader/CreateFeatureDialog.tsx @@ -21,7 +21,6 @@ import useFeatureForm from 'component/feature/hooks/useFeatureForm'; import useFeatureApi from 'hooks/api/actions/useFeatureApi/useFeatureApi'; import FlagIcon from '@mui/icons-material/Flag'; import ImpressionDataIcon from '@mui/icons-material/AltRoute'; -import { useFlagLimits } from 'component/feature/CreateFeature/CreateFeature'; import { useGlobalFeatureSearch } from 'component/feature/FeatureToggleList/useGlobalFeatureSearch'; import useProjectOverview, { featuresCount, @@ -37,6 +36,7 @@ import { ProjectIcon } from 'component/common/ProjectIcon/ProjectIcon'; import { MultiSelectConfigButton } from 'component/common/DialogFormTemplate/ConfigButtons/MultiSelectConfigButton'; import type { ITag } from 'interfaces/tags'; import { ToggleConfigButton } from 'component/common/DialogFormTemplate/ConfigButtons/ToggleConfigButton'; +import { useFlagLimits } from './useFlagLimits'; interface ICreateFeatureDialogProps { open: boolean; diff --git a/frontend/src/component/feature/CreateFeature/isProjectFeatureLimitReached.test.ts b/frontend/src/component/project/Project/PaginatedProjectFeatureToggles/ProjectFeatureTogglesHeader/isProjectFeatureLimitReached.test.ts similarity index 93% rename from frontend/src/component/feature/CreateFeature/isProjectFeatureLimitReached.test.ts rename to frontend/src/component/project/Project/PaginatedProjectFeatureToggles/ProjectFeatureTogglesHeader/isProjectFeatureLimitReached.test.ts index 77a520f979..d3d764f1fc 100644 --- a/frontend/src/component/feature/CreateFeature/isProjectFeatureLimitReached.test.ts +++ b/frontend/src/component/project/Project/PaginatedProjectFeatureToggles/ProjectFeatureTogglesHeader/isProjectFeatureLimitReached.test.ts @@ -1,4 +1,4 @@ -import { isProjectFeatureLimitReached } from './CreateFeature'; +import { isProjectFeatureLimitReached } from './useFlagLimits'; test('isFeatureLimitReached should return false when featureLimit is null', async () => { expect(isProjectFeatureLimitReached(null, 5)).toBe(false); diff --git a/frontend/src/component/feature/CreateFeature/useFlagLimits.test.ts b/frontend/src/component/project/Project/PaginatedProjectFeatureToggles/ProjectFeatureTogglesHeader/useFlagLimits.test.ts similarity index 97% rename from frontend/src/component/feature/CreateFeature/useFlagLimits.test.ts rename to frontend/src/component/project/Project/PaginatedProjectFeatureToggles/ProjectFeatureTogglesHeader/useFlagLimits.test.ts index b8abb2cf31..a785ec26e3 100644 --- a/frontend/src/component/feature/CreateFeature/useFlagLimits.test.ts +++ b/frontend/src/component/project/Project/PaginatedProjectFeatureToggles/ProjectFeatureTogglesHeader/useFlagLimits.test.ts @@ -1,6 +1,6 @@ import { renderHook } from '@testing-library/react'; -import { useFlagLimits } from './CreateFeature'; import { vi } from 'vitest'; +import { useFlagLimits } from './useFlagLimits'; vi.mock('hooks/useUiFlag', async (importOriginal) => { const actual = await importOriginal(); diff --git a/frontend/src/component/project/Project/PaginatedProjectFeatureToggles/ProjectFeatureTogglesHeader/useFlagLimits.tsx b/frontend/src/component/project/Project/PaginatedProjectFeatureToggles/ProjectFeatureTogglesHeader/useFlagLimits.tsx new file mode 100644 index 0000000000..c41d26a70b --- /dev/null +++ b/frontend/src/component/project/Project/PaginatedProjectFeatureToggles/ProjectFeatureTogglesHeader/useFlagLimits.tsx @@ -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 + ); +}; diff --git a/frontend/src/utils/routePathHelpers.ts b/frontend/src/utils/routePathHelpers.ts index bab9a6c391..177937ac91 100644 --- a/frontend/src/utils/routePathHelpers.ts +++ b/frontend/src/utils/routePathHelpers.ts @@ -6,7 +6,7 @@ export const getCreateTogglePath = ( projectId: string, query?: Record, ) => { - const path = `/projects/${projectId}/create-toggle`; + const path = `/projects/${projectId}?create=true`; let queryString: string | undefined; if (query) { @@ -16,12 +16,8 @@ export const getCreateTogglePath = ( } if (queryString) { - return `${path}?${queryString}`; + return `${path}&${queryString}`; } return path; }; - -export const getProjectEditPath = (projectId: string) => { - return `/projects/${projectId}/settings`; -};
- When you enable impression data for a feature flag, your - client SDKs will emit events you can listen for every time - this flag gets triggered. Learn more in{' '} - - the impression data documentation - -