From 0af5bbad38dfef7e4894b44c0094176e04695d1a Mon Sep 17 00:00:00 2001 From: Thomas Heartman Date: Mon, 24 Jun 2024 12:53:55 +0200 Subject: [PATCH] chore: remove createProjectWithEnvironmentConfig and newCreateProjectUI flags (#7429) This PR removes the last two flags related to the project managament improvements project, making the new project creation form GA. In doing so, we can also delete the old project creation form (or at least the page, the form is still in use in the project settings). --- .../Project/CreateProject/CreateProject.tsx | 138 +----------------- .../project/ProjectList/ProjectList.tsx | 34 ++--- frontend/src/interfaces/uiConfig.ts | 2 - .../__snapshots__/create-config.test.ts.snap | 2 - .../project/project-service.e2e.test.ts | 25 +--- src/lib/features/project/project-service.ts | 33 ++--- src/lib/types/experimental.ts | 10 -- src/server-dev.ts | 1 - 8 files changed, 23 insertions(+), 222 deletions(-) diff --git a/frontend/src/component/project/Project/CreateProject/CreateProject.tsx b/frontend/src/component/project/Project/CreateProject/CreateProject.tsx index 520b9cf23e..8e865b476a 100644 --- a/frontend/src/component/project/Project/CreateProject/CreateProject.tsx +++ b/frontend/src/component/project/Project/CreateProject/CreateProject.tsx @@ -1,141 +1,7 @@ -import { Navigate, useNavigate } from 'react-router-dom'; -import ProjectForm from '../ProjectForm/ProjectForm'; -import useProjectForm, { - DEFAULT_PROJECT_STICKINESS, -} from '../hooks/useProjectForm'; -import { CreateButton } from 'component/common/CreateButton/CreateButton'; -import FormTemplate from 'component/common/FormTemplate/FormTemplate'; -import { CREATE_PROJECT } from 'component/providers/AccessProvider/permissions'; -import useProjectApi from 'hooks/api/actions/useProjectApi/useProjectApi'; -import { useAuthUser } from 'hooks/api/getters/useAuth/useAuthUser'; -import useUiConfig from 'hooks/api/getters/useUiConfig/useUiConfig'; -import useToast from 'hooks/useToast'; -import { formatUnknownError } from 'utils/formatUnknownError'; -import { GO_BACK } from 'constants/navigate'; -import { usePlausibleTracker } from 'hooks/usePlausibleTracker'; -import { Button, styled } from '@mui/material'; -import { useUiFlag } from 'hooks/useUiFlag'; - -const CREATE_PROJECT_BTN = 'CREATE_PROJECT_BTN'; - -const StyledButton = styled(Button)(({ theme }) => ({ - marginLeft: theme.spacing(3), -})); +import { Navigate } from 'react-router-dom'; const CreateProject = () => { - const { setToastData, setToastApiError } = useToast(); - const { refetchUser } = useAuthUser(); - const { uiConfig } = useUiConfig(); - const useNewProjectForm = useUiFlag('newCreateProjectUI'); - const navigate = useNavigate(); - const { trackEvent } = usePlausibleTracker(); - const { - projectId, - projectName, - projectDesc, - projectMode, - setProjectMode, - setProjectId, - setProjectName, - setProjectDesc, - getCreateProjectPayload, - clearErrors, - validateProjectId, - validateName, - setProjectStickiness, - projectStickiness, - errors, - } = useProjectForm(); - - if (useNewProjectForm) { - return ; - } - - const { createProject, loading } = useProjectApi(); - - const handleSubmit = async (e: Event) => { - e.preventDefault(); - clearErrors(); - const validName = validateName(); - const validId = useNewProjectForm || (await validateProjectId()); - - if (validName && validId) { - const payload = getCreateProjectPayload({ - omitId: useNewProjectForm, - }); - try { - const createdProject = await createProject(payload); - refetchUser(); - navigate(`/projects/${createdProject.id}`, { replace: true }); - setToastData({ - title: 'Project created', - text: 'Now you can add flags to this project', - confetti: true, - type: 'success', - }); - - if (projectStickiness !== DEFAULT_PROJECT_STICKINESS) { - trackEvent('project_stickiness_set'); - } - trackEvent('project-mode', { - props: { mode: projectMode, action: 'added' }, - }); - } catch (error: unknown) { - setToastApiError(formatUnknownError(error)); - } - } - }; - - const formatApiCode = () => { - return `curl --location --request POST '${uiConfig.unleashUrl}/api/admin/projects' \\ ---header 'Authorization: INSERT_API_KEY' \\ ---header 'Content-Type: application/json' \\ ---data-raw '${JSON.stringify( - getCreateProjectPayload({ omitId: useNewProjectForm }), - undefined, - 2, - )}'`; - }; - - const handleCancel = () => { - navigate(GO_BACK); - }; - - return ( - - - - Cancel - - - ); + return ; }; export default CreateProject; diff --git a/frontend/src/component/project/ProjectList/ProjectList.tsx b/frontend/src/component/project/ProjectList/ProjectList.tsx index bff5dc8cff..4010f25299 100644 --- a/frontend/src/component/project/ProjectList/ProjectList.tsx +++ b/frontend/src/component/project/ProjectList/ProjectList.tsx @@ -1,5 +1,5 @@ import { useContext, useEffect, useMemo, useState } from 'react'; -import { useNavigate, useSearchParams } from 'react-router-dom'; +import { useSearchParams } from 'react-router-dom'; import useProjects from 'hooks/api/getters/useProjects/useProjects'; import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender'; import type { IProjectCard } from 'interfaces/project'; @@ -20,7 +20,6 @@ import { ReactComponent as ProPlanIcon } from 'assets/icons/pro-enterprise-featu import { ReactComponent as ProPlanIconLight } from 'assets/icons/pro-enterprise-feature-badge-light.svg'; import { safeRegExp } from '@server/util/escape-regex'; import { ThemeMode } from 'component/common/ThemeMode/ThemeMode'; -import { useUiFlag } from 'hooks/useUiFlag'; import { useProfile } from 'hooks/api/getters/useProfile/useProfile'; import { groupProjects } from './group-projects'; import { ProjectGroup } from './ProjectGroup'; @@ -92,7 +91,6 @@ const ProjectCreationButton = () => { const showCreateDialog = Boolean(searchParams.get('create')); const [openCreateDialog, setOpenCreateDialog] = useState(showCreateDialog); const { hasAccess } = useContext(AccessContext); - const navigate = useNavigate(); const { isOss } = useUiConfig(); const createButtonData = resolveCreateButtonData( @@ -100,14 +98,12 @@ const ProjectCreationButton = () => { hasAccess(CREATE_PROJECT), ); - const useNewProjectForm = useUiFlag('newCreateProjectUI'); - - const CreateButton: React.FC<{ onClick: () => void }> = ({ onClick }) => { - return ( + return ( + <> setOpenCreateDialog(true)} maxWidth='700px' permission={CREATE_PROJECT} disabled={createButtonData.disabled} @@ -116,22 +112,12 @@ const ProjectCreationButton = () => { > New project - ); - }; - - if (useNewProjectForm) { - return ( - <> - setOpenCreateDialog(true)} /> - setOpenCreateDialog(false)} - /> - - ); - } else { - return navigate('/projects/create')} />; - } + setOpenCreateDialog(false)} + /> + + ); }; export const ProjectListNew = () => { diff --git a/frontend/src/interfaces/uiConfig.ts b/frontend/src/interfaces/uiConfig.ts index 47a70528a9..d6dd7ea4ff 100644 --- a/frontend/src/interfaces/uiConfig.ts +++ b/frontend/src/interfaces/uiConfig.ts @@ -81,8 +81,6 @@ export type UiFlags = { projectOverviewRefactorFeedback?: boolean; featureLifecycle?: boolean; scimApi?: boolean; - createProjectWithEnvironmentConfig?: boolean; - newCreateProjectUI?: boolean; manyStrategiesPagination?: boolean; enableLegacyVariants?: boolean; navigationSidebar?: boolean; diff --git a/src/lib/__snapshots__/create-config.test.ts.snap b/src/lib/__snapshots__/create-config.test.ts.snap index 177ab87032..f2bf6f3842 100644 --- a/src/lib/__snapshots__/create-config.test.ts.snap +++ b/src/lib/__snapshots__/create-config.test.ts.snap @@ -83,7 +83,6 @@ exports[`should create default config 1`] = ` "celebrateUnleash": false, "collectTrafficDataUsage": false, "commandBarUI": false, - "createProjectWithEnvironmentConfig": false, "demo": false, "disableBulkToggle": false, "disableMetrics": false, @@ -138,7 +137,6 @@ exports[`should create default config 1`] = ` }, "migrationLock": true, "navigationSidebar": true, - "newCreateProjectUI": false, "outdatedSdksBanner": false, "parseProjectFromSession": false, "personalAccessTokensKillSwitch": false, diff --git a/src/lib/features/project/project-service.e2e.test.ts b/src/lib/features/project/project-service.e2e.test.ts index b9e6c704ff..fd01f57380 100644 --- a/src/lib/features/project/project-service.e2e.test.ts +++ b/src/lib/features/project/project-service.e2e.test.ts @@ -79,9 +79,7 @@ beforeAll(async () => { const config = createTestConfig({ getLogger, experimental: { - flags: { - createProjectWithEnvironmentConfig: true, - }, + flags: {}, }, }); eventService = new EventService(stores, config); @@ -2715,26 +2713,5 @@ describe('automatic ID generation for create project', () => { expect(project.id).toBe(id); }, ); - - test.each(['', undefined, ' '])( - 'if the flag to enable auto ID generation is off, not providing a valid ID (testing `%s`) throws an error', - async (id) => { - // @ts-expect-error - projectService.flagResolver.isEnabled = () => { - return false; - }; - - const createProject = () => - projectService.createProject( - { - name: randomId(), - id, - }, - user, - auditUser, - ); - expect(createProject).rejects.toThrow(); - }, - ); }); }); diff --git a/src/lib/features/project/project-service.ts b/src/lib/features/project/project-service.ts index d1233afc73..ef40dc258e 100644 --- a/src/lib/features/project/project-service.ts +++ b/src/lib/features/project/project-service.ts @@ -294,10 +294,7 @@ export default class ProjectService { } async validateProjectEnvironments(environments: string[] | undefined) { - if ( - this.flagResolver.isEnabled('createProjectWithEnvironmentConfig') && - environments - ) { + if (environments) { if (environments.length === 0) { throw new BadDataError( 'A project must always have at least one environment.', @@ -339,12 +336,7 @@ export default class ProjectService { const validateData = async () => { await this.validateProjectEnvironments(newProject.environments); - if ( - !newProject.id?.trim() && - this.flagResolver.isEnabled( - 'createProjectWithEnvironmentConfig', - ) - ) { + if (!newProject.id?.trim()) { newProject.id = await this.generateUniqueProjectId( newProject.name, ); @@ -362,15 +354,13 @@ export default class ProjectService { await this.projectStore.create(data); - const envsToEnable = - this.flagResolver.isEnabled('createProjectWithEnvironmentConfig') && - newProject.environments?.length - ? newProject.environments - : ( - await this.environmentStore.getAll({ - enabled: true, - }) - ).map((env) => env.name); + const envsToEnable = newProject.environments?.length + ? newProject.environments + : ( + await this.environmentStore.getAll({ + enabled: true, + }) + ).map((env) => env.name); await Promise.all( envsToEnable.map(async (env) => { @@ -378,10 +368,7 @@ export default class ProjectService { }), ); - if ( - this.isEnterprise && - this.flagResolver.isEnabled('createProjectWithEnvironmentConfig') - ) { + if (this.isEnterprise) { if (newProject.changeRequestEnvironments) { await this.validateEnvironmentsExist( newProject.changeRequestEnvironments.map((env) => env.name), diff --git a/src/lib/types/experimental.ts b/src/lib/types/experimental.ts index bd577be748..c8652ed05e 100644 --- a/src/lib/types/experimental.ts +++ b/src/lib/types/experimental.ts @@ -56,9 +56,7 @@ export type IFlagKey = | 'featureLifecycle' | 'featureLifecycleMetrics' | 'parseProjectFromSession' - | 'createProjectWithEnvironmentConfig' | 'manyStrategiesPagination' - | 'newCreateProjectUI' | 'enableLegacyVariants' | 'navigationSidebar' | 'commandBarUI' @@ -272,14 +270,6 @@ const flags: IFlags = { process.env.UNLEASH_EXPERIMENTAL_PARSE_PROJECT_FROM_SESSION, false, ), - createProjectWithEnvironmentConfig: parseEnvVarBoolean( - process.env.UNLEASH_EXPERIMENTAL_CREATE_PROJECT_WITH_ENVIRONMENT_CONFIG, - false, - ), - newCreateProjectUI: parseEnvVarBoolean( - process.env.UNLEASH_EXPERIMENTAL_NEW_CREATE_PROJECT_UI, - false, - ), manyStrategiesPagination: parseEnvVarBoolean( process.env.UNLEASH_EXPERIMENTAL_MANY_STRATEGIES_PAGINATION, false, diff --git a/src/server-dev.ts b/src/server-dev.ts index 3fc317203b..7c91d90e49 100644 --- a/src/server-dev.ts +++ b/src/server-dev.ts @@ -50,7 +50,6 @@ process.nextTick(async () => { projectOverviewRefactorFeedback: true, featureLifecycle: true, parseProjectFromSession: true, - createProjectWithEnvironmentConfig: true, manyStrategiesPagination: true, enableLegacyVariants: false, commandBarUI: true,