From 0e6d06246817812f9601d5f98753b8ff34dcd656 Mon Sep 17 00:00:00 2001 From: Gitar Date: Fri, 20 Sep 2024 11:58:09 +0000 Subject: [PATCH 1/4] [Gitar] Updating TypeScript files --- frontend/src/interfaces/uiConfig.ts | 1 - .../feature-toggle/feature-toggle-service.ts | 21 ++++-------- .../tests/feature-toggle-service.e2e.test.ts | 16 ++------- .../features/project/project-read-model.ts | 28 ++++++---------- .../project/project-service.e2e.test.ts | 2 +- src/lib/features/project/project-service.ts | 18 ++++------ .../project/project-store.e2e.test.ts | 2 +- src/lib/features/project/project-store.ts | 33 ++++++------------- src/lib/types/experimental.ts | 5 --- 9 files changed, 38 insertions(+), 88 deletions(-) diff --git a/frontend/src/interfaces/uiConfig.ts b/frontend/src/interfaces/uiConfig.ts index 7fcb3fb32722..784192cf63a6 100644 --- a/frontend/src/interfaces/uiConfig.ts +++ b/frontend/src/interfaces/uiConfig.ts @@ -86,7 +86,6 @@ export type UiFlags = { enableLegacyVariants?: boolean; navigationSidebar?: boolean; flagCreator?: boolean; - archiveProjects?: boolean; projectListImprovements?: boolean; onboardingUI?: boolean; eventTimeline?: boolean; diff --git a/src/lib/features/feature-toggle/feature-toggle-service.ts b/src/lib/features/feature-toggle/feature-toggle-service.ts index 99c06a39ac99..a41e34854c51 100644 --- a/src/lib/features/feature-toggle/feature-toggle-service.ts +++ b/src/lib/features/feature-toggle/feature-toggle-service.ts @@ -1230,14 +1230,12 @@ class FeatureToggleService { } private async validateActiveProject(projectId: string) { - if (this.flagResolver.isEnabled('archiveProjects')) { - const hasActiveProject = - await this.projectStore.hasActiveProject(projectId); - if (!hasActiveProject) { - throw new NotFoundError( - `Active project with id ${projectId} does not exist`, - ); - } + const hasActiveProject = + await this.projectStore.hasActiveProject(projectId); + if (!hasActiveProject) { + throw new NotFoundError( + `Active project with id ${projectId} does not exist`, + ); } } @@ -1253,12 +1251,7 @@ class FeatureToggleService { await this.validateName(value.name); await this.validateFeatureFlagNameAgainstPattern(value.name, projectId); - let projectExists: boolean; - if (this.flagResolver.isEnabled('archiveProjects')) { - projectExists = await this.projectStore.hasActiveProject(projectId); - } else { - projectExists = await this.projectStore.hasProject(projectId); - } + let projectExists = await this.projectStore.hasActiveProject(projectId); if (await this.projectStore.isFeatureLimitReached(projectId)) { throw new InvalidOperationError( diff --git a/src/lib/features/feature-toggle/tests/feature-toggle-service.e2e.test.ts b/src/lib/features/feature-toggle/tests/feature-toggle-service.e2e.test.ts index 5fd0b835b2a0..fb93c96dab4b 100644 --- a/src/lib/features/feature-toggle/tests/feature-toggle-service.e2e.test.ts +++ b/src/lib/features/feature-toggle/tests/feature-toggle-service.e2e.test.ts @@ -38,7 +38,6 @@ let segmentService: ISegmentService; let eventService: EventService; let environmentService: EnvironmentService; let unleashConfig: IUnleashConfig; -const TEST_USER_ID = -9999; const mockConstraints = (): IConstraint[] => { return Array.from({ length: 5 }).map(() => ({ values: ['x', 'y', 'z'], @@ -51,7 +50,7 @@ const irrelevantDate = new Date(); beforeAll(async () => { const config = createTestConfig({ - experimental: { flags: { archiveProjects: true } }, + experimental: { flags: {} }, }); db = await dbInit( 'feature_toggle_service_v2_service_serial', @@ -77,7 +76,6 @@ beforeEach(async () => { }); test('Should create feature flag strategy configuration', async () => { const projectId = 'default'; - const username = 'feature-flag'; const config: Omit = { name: 'default', constraints: [], @@ -104,7 +102,6 @@ test('Should create feature flag strategy configuration', async () => { test('Should be able to update existing strategy configuration', async () => { const projectId = 'default'; - const username = 'existing-strategy'; const featureName = 'update-existing-strategy'; const config: Omit = { name: 'default', @@ -139,8 +136,6 @@ test('Should be able to update existing strategy configuration', async () => { test('Should be able to get strategy by id', async () => { const featureName = 'get-strategy-by-id'; const projectId = 'default'; - - const userName = 'strategy'; const config: Omit = { name: 'default', constraints: [], @@ -168,8 +163,6 @@ test('Should be able to get strategy by id', async () => { test('should ignore name in the body when updating feature flag', async () => { const featureName = 'body-name-update'; const projectId = 'default'; - - const userName = 'strategy'; const secondFeatureName = 'body-name-update2'; await service.createFeatureToggle( @@ -213,8 +206,6 @@ test('should ignore name in the body when updating feature flag', async () => { test('should not get empty rows as features', async () => { const projectId = 'default'; - const userName = 'strategy'; - await service.createFeatureToggle( projectId, { @@ -505,7 +496,6 @@ test('If change requests are enabled, cannot change variants without going via C }); test('If CRs are protected for any environment in the project stops bulk update of variants', async () => { - const user = { email: 'test@example.com', username: 'test-user' } as User; const project = await stores.projectStore.create({ id: 'crOnVariantsProject', name: 'crOnVariantsProject', @@ -599,7 +589,6 @@ test('getPlaygroundFeatures should return ids and titles (if they exist) on clie const projectId = 'default'; const title = 'custom strategy title'; - const userName = 'strategy'; const config: Omit = { name: 'default', constraints: [], @@ -819,7 +808,6 @@ test('Should enable disabled strategies on feature environment enabled', async ( const flagName = 'enableThisFlag'; const project = 'default'; const environment = 'default'; - const shouldActivateDisabledStrategies = true; await service.createFeatureToggle( project, { @@ -856,7 +844,7 @@ test('Should enable disabled strategies on feature environment enabled', async ( true, TEST_AUDIT_USER, { email: 'test@example.com' } as User, - shouldActivateDisabledStrategies, + true, ); const strategy = await service.getStrategy(createdConfig.id); diff --git a/src/lib/features/project/project-read-model.ts b/src/lib/features/project/project-read-model.ts index c793543d81ba..011299a19dfc 100644 --- a/src/lib/features/project/project-read-model.ts +++ b/src/lib/features/project/project-read-model.ts @@ -104,12 +104,10 @@ export class ProjectReadModel implements IProjectReadModel { }) .orderBy('projects.name', 'asc'); - if (this.flagResolver.isEnabled('archiveProjects')) { - if (query?.archived === true) { - projects = projects.whereNot(`${TABLE}.archived_at`, null); - } else { - projects = projects.where(`${TABLE}.archived_at`, null); - } + if (query?.archived === true) { + projects = projects.whereNot(`${TABLE}.archived_at`, null); + } else { + projects = projects.where(`${TABLE}.archived_at`, null); } if (query?.id) { @@ -126,9 +124,7 @@ export class ProjectReadModel implements IProjectReadModel { 'project_settings.project_mode', ] as (string | Raw)[]; - if (this.flagResolver.isEnabled('archiveProjects')) { - selectColumns.push(`${TABLE}.archived_at`); - } + selectColumns.push(`${TABLE}.archived_at`); let groupByColumns = ['projects.id', 'project_settings.project_mode']; @@ -179,12 +175,10 @@ export class ProjectReadModel implements IProjectReadModel { .leftJoin('project_stats', 'project_stats.project', 'projects.id') .orderBy('projects.name', 'asc'); - if (this.flagResolver.isEnabled('archiveProjects')) { - if (query?.archived === true) { - projects = projects.whereNot(`${TABLE}.archived_at`, null); - } else { - projects = projects.where(`${TABLE}.archived_at`, null); - } + if (query?.archived === true) { + projects = projects.whereNot(`${TABLE}.archived_at`, null); + } else { + projects = projects.where(`${TABLE}.archived_at`, null); } if (query?.id) { @@ -201,9 +195,7 @@ export class ProjectReadModel implements IProjectReadModel { 'project_stats.avg_time_to_prod_current_window', ] as (string | Raw)[]; - if (this.flagResolver.isEnabled('archiveProjects')) { - selectColumns.push(`${TABLE}.archived_at`); - } + selectColumns.push(`${TABLE}.archived_at`); const groupByColumns = [ 'projects.id', diff --git a/src/lib/features/project/project-service.e2e.test.ts b/src/lib/features/project/project-service.e2e.test.ts index eeebf1f5580d..bdd3cda35f37 100644 --- a/src/lib/features/project/project-service.e2e.test.ts +++ b/src/lib/features/project/project-service.e2e.test.ts @@ -83,7 +83,7 @@ beforeAll(async () => { const config = createTestConfig({ getLogger, experimental: { - flags: { archiveProjects: true, useProjectReadModel: true }, + flags: { useProjectReadModel: true }, }, }); eventService = createEventsService(db.rawDatabase, config); diff --git a/src/lib/features/project/project-service.ts b/src/lib/features/project/project-service.ts index 41280746351f..c476c28647d9 100644 --- a/src/lib/features/project/project-service.ts +++ b/src/lib/features/project/project-service.ts @@ -500,14 +500,12 @@ export default class ProjectService { } private async validateActiveProject(projectId: string) { - if (this.flagResolver.isEnabled('archiveProjects')) { - const hasActiveProject = - await this.projectStore.hasActiveProject(projectId); - if (!hasActiveProject) { - throw new NotFoundError( - `Active project with id ${projectId} does not exist`, - ); - } + const hasActiveProject = + await this.projectStore.hasActiveProject(projectId); + if (!hasActiveProject) { + throw new NotFoundError( + `Active project with id ${projectId} does not exist`, + ); } } @@ -1552,9 +1550,7 @@ export default class ProjectService { health: project.health || 0, favorite: favorite, updatedAt: project.updatedAt, - ...(this.flagResolver.isEnabled('archiveProjects') - ? { archivedAt: project.archivedAt } - : {}), + archivedAt: project.archivedAt, createdAt: project.createdAt, onboardingStatus, environments, diff --git a/src/lib/features/project/project-store.e2e.test.ts b/src/lib/features/project/project-store.e2e.test.ts index 4f5c9cbdae22..a338c10f821c 100644 --- a/src/lib/features/project/project-store.e2e.test.ts +++ b/src/lib/features/project/project-store.e2e.test.ts @@ -12,7 +12,7 @@ let environmentStore: IEnvironmentStore; beforeAll(async () => { db = await dbInit('project_store_serial', getLogger, { - experimental: { flags: { archiveProjects: true } }, + experimental: { flags: {} }, }); stores = db.stores; projectStore = stores.projectStore; diff --git a/src/lib/features/project/project-store.ts b/src/lib/features/project/project-store.ts index 1a1bf0e174ee..4f3028d0e657 100644 --- a/src/lib/features/project/project-store.ts +++ b/src/lib/features/project/project-store.ts @@ -132,12 +132,10 @@ class ProjectStore implements IProjectStore { .leftJoin('project_stats', 'project_stats.project', 'projects.id') .orderBy('projects.name', 'asc'); - if (this.flagResolver.isEnabled('archiveProjects')) { - if (query?.archived === true) { - projects = projects.whereNot(`${TABLE}.archived_at`, null); - } else { - projects = projects.where(`${TABLE}.archived_at`, null); - } + if (query?.archived === true) { + projects = projects.whereNot(`${TABLE}.archived_at`, null); + } else { + projects = projects.where(`${TABLE}.archived_at`, null); } if (query?.id) { @@ -156,9 +154,7 @@ class ProjectStore implements IProjectStore { 'project_stats.avg_time_to_prod_current_window', ] as (string | Raw)[]; - if (this.flagResolver.isEnabled('archiveProjects')) { - selectColumns.push(`${TABLE}.archived_at`); - } + selectColumns.push(`${TABLE}.archived_at`); let groupByColumns = [ 'projects.id', @@ -237,9 +233,7 @@ class ProjectStore implements IProjectStore { .where(query) .orderBy('name', 'asc'); - if (this.flagResolver.isEnabled('archiveProjects')) { - projects = projects.where(`${TABLE}.archived_at`, null); - } + projects = projects.where(`${TABLE}.archived_at`, null); const rows = await projects; @@ -248,9 +242,7 @@ class ProjectStore implements IProjectStore { async get(id: string): Promise { let extraColumns: string[] = []; - if (this.flagResolver.isEnabled('archiveProjects')) { - extraColumns = ['archived_at']; - } + extraColumns = ['archived_at']; return this.db .first([...COLUMNS, ...SETTINGS_COLUMNS, ...extraColumns]) @@ -634,8 +626,7 @@ class ProjectStore implements IProjectStore { async getApplicationsByProject( params: IProjectApplicationsSearchParams, ): Promise { - const { project, limit, sortOrder, sortBy, searchParams, offset } = - params; + const { project, limit, sortOrder, searchParams, offset } = params; const validatedSortOrder = sortOrder === 'asc' || sortOrder === 'desc' ? sortOrder : 'asc'; const query = this.db @@ -741,9 +732,7 @@ class ProjectStore implements IProjectStore { async count(): Promise { let count = this.db.from(TABLE).count('*'); - if (this.flagResolver.isEnabled('archiveProjects')) { - count = count.where(`${TABLE}.archived_at`, null); - } + count = count.where(`${TABLE}.archived_at`, null); return count.then((res) => Number(res[0].count)); } @@ -766,9 +755,7 @@ class ProjectStore implements IProjectStore { this.db.raw(`COALESCE(${SETTINGS_TABLE}.project_mode, 'open')`), ); - if (this.flagResolver.isEnabled('archiveProjects')) { - query = query.where(`${TABLE}.archived_at`, null); - } + query = query.where(`${TABLE}.archived_at`, null); const result: ProjectModeCount[] = await query; diff --git a/src/lib/types/experimental.ts b/src/lib/types/experimental.ts index 58512f22615d..fb75b941a6e0 100644 --- a/src/lib/types/experimental.ts +++ b/src/lib/types/experimental.ts @@ -56,7 +56,6 @@ export type IFlagKey = | 'extendedMetrics' | 'removeUnsafeInlineStyleSrc' | 'originMiddleware' - | 'archiveProjects' | 'projectListImprovements' | 'useProjectReadModel' | 'addonUsageMetrics' @@ -281,10 +280,6 @@ const flags: IFlags = { process.env.UNLEASH_EXPERIMENTAL_ORIGIN_MIDDLEWARE, false, ), - archiveProjects: parseEnvVarBoolean( - process.env.UNLEASH_EXPERIMENTAL_ARCHIVE_PROJECTS, - false, - ), projectListImprovements: parseEnvVarBoolean( process.env.UNLEASH_EXPERIMENTAL_PROJECT_LIST_IMPROVEMENTS, false, From 24ac541e58cc303d30a678e61adbc50c5bb28c7c Mon Sep 17 00:00:00 2001 From: Gitar Date: Fri, 20 Sep 2024 11:58:09 +0000 Subject: [PATCH 2/4] [Gitar] Updating TSX files --- .../src/component/project/Project/Project.tsx | 4 +-- .../Settings/EditProject/EditProject.tsx | 17 +------------ .../project/ProjectList/LegacyProjectList.tsx | 25 +++++++------------ .../project/ProjectList/ProjectList.tsx | 6 +---- 4 files changed, 12 insertions(+), 40 deletions(-) diff --git a/frontend/src/component/project/Project/Project.tsx b/frontend/src/component/project/Project/Project.tsx index e7b8084b1eb5..2db8712c5fe6 100644 --- a/frontend/src/component/project/Project/Project.tsx +++ b/frontend/src/component/project/Project/Project.tsx @@ -44,7 +44,6 @@ import { ProjectApplications } from '../ProjectApplications/ProjectApplications' import { ProjectInsights } from './ProjectInsights/ProjectInsights'; import useProjectOverview from 'hooks/api/getters/useProjectOverview/useProjectOverview'; import { ProjectArchived } from './ArchiveProject/ProjectArchived'; -import { useUiFlag } from 'hooks/useUiFlag'; const StyledBadge = styled(Badge)(({ theme }) => ({ position: 'absolute', @@ -77,7 +76,6 @@ export const Project = () => { const basePath = `/projects/${projectId}`; const projectName = project?.name || projectId; const { favorite, unfavorite } = useFavoriteProjectsApi(); - const archiveProjectsEnabled = useUiFlag('archiveProjects'); const [showDelDialog, setShowDelDialog] = useState(false); @@ -192,7 +190,7 @@ export const Project = () => { ); - if (archiveProjectsEnabled && Boolean(project.archivedAt)) { + if (project.archivedAt) { return ; } diff --git a/frontend/src/component/project/Project/ProjectSettings/Settings/EditProject/EditProject.tsx b/frontend/src/component/project/Project/ProjectSettings/Settings/EditProject/EditProject.tsx index 01a277b16db7..56d13e2b3615 100644 --- a/frontend/src/component/project/Project/ProjectSettings/Settings/EditProject/EditProject.tsx +++ b/frontend/src/component/project/Project/ProjectSettings/Settings/EditProject/EditProject.tsx @@ -10,12 +10,10 @@ import { Alert, styled } from '@mui/material'; import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender'; import { UpdateEnterpriseSettings } from './UpdateEnterpriseSettings'; import { UpdateProject } from './UpdateProject'; -import { DeleteProjectForm } from './DeleteProjectForm'; import useProjectOverview, { featuresCount, } from 'hooks/api/getters/useProjectOverview/useProjectOverview'; import { ArchiveProjectForm } from './ArchiveProjectForm'; -import { useUiFlag } from 'hooks/useUiFlag'; const StyledFormContainer = styled('div')(({ theme }) => ({ display: 'flex', @@ -28,7 +26,6 @@ const EditProject = () => { const { hasAccess } = useContext(AccessContext); const id = useRequiredPathParam('projectId'); const { project } = useProjectOverview(id); - const archiveProjectsEnabled = useUiFlag('archiveProjects'); if (!project.name) { return null; @@ -52,19 +49,7 @@ const EditProject = () => { condition={isEnterprise()} show={} /> - - } - elseShow={ - - } - /> + ); diff --git a/frontend/src/component/project/ProjectList/LegacyProjectList.tsx b/frontend/src/component/project/ProjectList/LegacyProjectList.tsx index deb87431fcbe..68f34b485769 100644 --- a/frontend/src/component/project/ProjectList/LegacyProjectList.tsx +++ b/frontend/src/component/project/ProjectList/LegacyProjectList.tsx @@ -25,7 +25,6 @@ import { useProfile } from 'hooks/api/getters/useProfile/useProfile'; import { groupProjects } from './group-projects'; import { ProjectGroup } from './ProjectGroup'; import { CreateProjectDialog } from '../Project/CreateProject/NewCreateProjectForm/CreateProjectDialog'; -import { useUiFlag } from 'hooks/useUiFlag'; const StyledApiError = styled(ApiError)(({ theme }) => ({ maxWidth: '500px', @@ -126,7 +125,6 @@ export const ProjectList = () => { const [searchValue, setSearchValue] = useState( searchParams.get('search') || '', ); - const archiveProjectsEnabled = useUiFlag('archiveProjects'); const myProjects = new Set(useProfile().profile?.projects || []); @@ -200,20 +198,15 @@ export const ProjectList = () => { } /> - - - Archived projects - - - - } - /> + <> + + Archived projects + + + diff --git a/frontend/src/component/project/ProjectList/ProjectList.tsx b/frontend/src/component/project/ProjectList/ProjectList.tsx index 4c3acbb40fb3..801f59039f03 100644 --- a/frontend/src/component/project/ProjectList/ProjectList.tsx +++ b/frontend/src/component/project/ProjectList/ProjectList.tsx @@ -36,7 +36,6 @@ const NewProjectList = () => { const isSmallScreen = useMediaQuery(theme.breakpoints.down('md')); const [state, setState] = useProjectsListState(); - const archiveProjectsEnabled = useUiFlag('archiveProjects'); const myProjects = new Set(useProfile().profile?.projects || []); @@ -78,10 +77,7 @@ const NewProjectList = () => { } /> - } - /> + From 70aab3aa73283c22e91edc086f0d702136910f36 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Fri, 20 Sep 2024 12:05:10 +0000 Subject: [PATCH 3/4] Gitar Duet for #8201 --- src/lib/features/feature-toggle/feature-toggle-service.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/lib/features/feature-toggle/feature-toggle-service.ts b/src/lib/features/feature-toggle/feature-toggle-service.ts index a41e34854c51..d34a4b3f6f16 100644 --- a/src/lib/features/feature-toggle/feature-toggle-service.ts +++ b/src/lib/features/feature-toggle/feature-toggle-service.ts @@ -1251,7 +1251,8 @@ class FeatureToggleService { await this.validateName(value.name); await this.validateFeatureFlagNameAgainstPattern(value.name, projectId); - let projectExists = await this.projectStore.hasActiveProject(projectId); + const projectExists = + await this.projectStore.hasActiveProject(projectId); if (await this.projectStore.isFeatureLimitReached(projectId)) { throw new InvalidOperationError( From c17cb8f33c120b27d6d001228f0d4354465a828c Mon Sep 17 00:00:00 2001 From: kwasniew Date: Mon, 23 Sep 2024 11:45:58 +0200 Subject: [PATCH 4/4] refactor: inline push column --- src/lib/features/project/project-read-model.ts | 6 ++---- src/lib/features/project/project-store.ts | 6 ++---- 2 files changed, 4 insertions(+), 8 deletions(-) diff --git a/src/lib/features/project/project-read-model.ts b/src/lib/features/project/project-read-model.ts index 011299a19dfc..b8b12d60cf87 100644 --- a/src/lib/features/project/project-read-model.ts +++ b/src/lib/features/project/project-read-model.ts @@ -122,10 +122,9 @@ export class ProjectReadModel implements IProjectReadModel { 'MAX(events.created_at) AS last_updated', ), 'project_settings.project_mode', + 'projects.archived_at', ] as (string | Raw)[]; - selectColumns.push(`${TABLE}.archived_at`); - let groupByColumns = ['projects.id', 'project_settings.project_mode']; if (userId) { @@ -193,10 +192,9 @@ export class ProjectReadModel implements IProjectReadModel { 'count(features.name) FILTER (WHERE features.archived_at is null and features.potentially_stale IS TRUE) AS potentially_stale_feature_count', ), 'project_stats.avg_time_to_prod_current_window', + 'projects.archived_at', ] as (string | Raw)[]; - selectColumns.push(`${TABLE}.archived_at`); - const groupByColumns = [ 'projects.id', 'project_stats.avg_time_to_prod_current_window', diff --git a/src/lib/features/project/project-store.ts b/src/lib/features/project/project-store.ts index 4f3028d0e657..d9f7162c6560 100644 --- a/src/lib/features/project/project-store.ts +++ b/src/lib/features/project/project-store.ts @@ -152,10 +152,9 @@ class ProjectStore implements IProjectStore { 'project_settings.default_stickiness', 'project_settings.project_mode', 'project_stats.avg_time_to_prod_current_window', + 'projects.archived_at', ] as (string | Raw)[]; - selectColumns.push(`${TABLE}.archived_at`); - let groupByColumns = [ 'projects.id', 'project_settings.default_stickiness', @@ -241,8 +240,7 @@ class ProjectStore implements IProjectStore { } async get(id: string): Promise { - let extraColumns: string[] = []; - extraColumns = ['archived_at']; + const extraColumns: string[] = ['archived_at']; return this.db .first([...COLUMNS, ...SETTINGS_COLUMNS, ...extraColumns])