diff --git a/frontend/src/component/insights/Insights.test.tsx b/frontend/src/component/insights/Insights.test.tsx index 6f40943b560d..b8ad1cb0c6ba 100644 --- a/frontend/src/component/insights/Insights.test.tsx +++ b/frontend/src/component/insights/Insights.test.tsx @@ -1,6 +1,6 @@ import { render } from '../../utils/testRenderer'; import { fireEvent, screen } from '@testing-library/react'; -import { NewInsights } from './Insights'; +import { Insights } from './Insights'; import { testServerRoute, testServerSetup } from '../../utils/testServer'; import { vi } from 'vitest'; @@ -30,7 +30,7 @@ const currentTime = '2024-04-25T08:05:00.000Z'; test('Filter insights by project and date', async () => { vi.setSystemTime(currentTime); setupApi(); - render(); + render(); const addFilter = await screen.findByText('Add Filter'); fireEvent.click(addFilter); diff --git a/frontend/src/component/insights/Insights.tsx b/frontend/src/component/insights/Insights.tsx index a543ab1a9bee..5d4987396525 100644 --- a/frontend/src/component/insights/Insights.tsx +++ b/frontend/src/component/insights/Insights.tsx @@ -1,17 +1,11 @@ import { useState, type FC } from 'react'; -import { Box, styled } from '@mui/material'; -import { ArrayParam, withDefault } from 'use-query-params'; +import { styled } from '@mui/material'; import { usePersistentTableState } from 'hooks/usePersistentTableState'; -import { - allOption, - ProjectSelect, -} from 'component/common/ProjectSelect/ProjectSelect'; +import { allOption } from 'component/common/ProjectSelect/ProjectSelect'; import { useInsights } from 'hooks/api/getters/useInsights/useInsights'; import { InsightsHeader } from './components/InsightsHeader/InsightsHeader'; import { useInsightsData } from './hooks/useInsightsData'; -import { type IChartsProps, InsightsCharts } from './InsightsCharts'; -import { LegacyInsightsCharts } from './LegacyInsightsCharts'; -import { useUiFlag } from 'hooks/useUiFlag'; +import { InsightsCharts } from './InsightsCharts'; import { Sticky } from 'component/common/Sticky/Sticky'; import { InsightsFilters } from './InsightsFilters'; import { FilterItemParam } from '../../utils/serializeQueryParams'; @@ -29,87 +23,11 @@ const StickyContainer = styled(Sticky)(({ theme }) => ({ transition: 'padding 0.3s ease', })); -/** - * @deprecated remove with insightsV2 flag - */ -const StickyWrapper = styled(Box, { - shouldForwardProp: (prop) => prop !== 'scrolled', -})<{ scrolled?: boolean }>(({ theme, scrolled }) => ({ - position: 'sticky', - top: 0, - zIndex: theme.zIndex.sticky, - padding: scrolled ? theme.spacing(2, 0) : theme.spacing(2, 0, 2), - background: theme.palette.background.application, - transition: 'padding 0.3s ease', -})); - -const StyledProjectSelect = styled(ProjectSelect)(({ theme }) => ({ - flex: 1, - width: '300px', - [theme.breakpoints.down('sm')]: { - width: '100%', - }, -})); - -/** - * @deprecated remove with insightsV2 flag - */ -const LegacyInsights: FC = () => { - const [scrolled, setScrolled] = useState(false); - const { insights, loading, error } = useInsights(); - const stateConfig = { - projects: withDefault(ArrayParam, [allOption.id]), - }; - const [state, setState] = usePersistentTableState('insights', stateConfig); - const setProjects = (projects: string[]) => { - setState({ projects }); - }; - const projects = state.projects - ? (state.projects.filter(Boolean) as string[]) - : []; - - const insightsData = useInsightsData(insights, projects); - - const handleScroll = () => { - if (!scrolled && window.scrollY > 0) { - setScrolled(true); - } else if (scrolled && window.scrollY === 0) { - setScrolled(false); - } - }; - - if (typeof window !== 'undefined') { - window.addEventListener('scroll', handleScroll); - } - - return ( - - - - } - /> - - - - ); -}; - interface InsightsProps { - ChartComponent?: FC; + withCharts?: boolean; } -export const NewInsights: FC = ({ ChartComponent }) => { +export const Insights: FC = ({ withCharts = true }) => { const [scrolled, setScrolled] = useState(false); const stateConfig = { @@ -118,7 +36,7 @@ export const NewInsights: FC = ({ ChartComponent }) => { to: FilterItemParam, }; const [state, setState] = usePersistentTableState('insights', stateConfig); - const { insights, loading, error } = useInsights( + const { insights, loading } = useInsights( state.from?.values[0], state.to?.values[0], ); @@ -148,8 +66,8 @@ export const NewInsights: FC = ({ ChartComponent }) => { } /> - {ChartComponent && ( - = ({ ChartComponent }) => { ); }; - -export const Insights: FC = () => { - const isInsightsV2Enabled = useUiFlag('insightsV2'); - - if (isInsightsV2Enabled) - return ; - - return ; -}; diff --git a/frontend/src/component/insights/LegacyInsightsCharts.tsx b/frontend/src/component/insights/LegacyInsightsCharts.tsx deleted file mode 100644 index c83d3a82997d..000000000000 --- a/frontend/src/component/insights/LegacyInsightsCharts.tsx +++ /dev/null @@ -1,254 +0,0 @@ -import type { VFC } from 'react'; -import { Box, styled } from '@mui/material'; -import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender'; -import { Widget } from './components/Widget/Widget'; -import { UserStats } from './componentsStat/UserStats/UserStats'; -import { UsersChart } from './componentsChart/UsersChart/UsersChart'; -import { UsersPerProjectChart } from './componentsChart/UsersPerProjectChart/UsersPerProjectChart'; -import { FlagStats } from './componentsStat/FlagStats/FlagStats'; -import { FlagsChart } from './componentsChart/FlagsChart/FlagsChart'; -import { FlagsProjectChart } from './componentsChart/FlagsProjectChart/FlagsProjectChart'; -import { LegacyHealthStats } from './componentsStat/HealthStats/LegacyHealthStats'; -import { ProjectHealthChart } from './componentsChart/ProjectHealthChart/ProjectHealthChart'; -import { TimeToProduction } from './componentsStat/TimeToProduction/TimeToProduction'; -import { TimeToProductionChart } from './componentsChart/TimeToProductionChart/TimeToProductionChart'; -import { MetricsSummaryChart } from './componentsChart/MetricsSummaryChart/MetricsSummaryChart'; -import { UpdatesPerEnvironmentTypeChart } from './componentsChart/UpdatesPerEnvironmentTypeChart/UpdatesPerEnvironmentTypeChart'; -import type { - InstanceInsightsSchema, - InstanceInsightsSchemaFlags, - InstanceInsightsSchemaUsers, -} from 'openapi'; -import type { GroupedDataByProject } from './hooks/useGroupedProjectTrends'; -import { allOption } from 'component/common/ProjectSelect/ProjectSelect'; -import { chartInfo } from './chart-info'; -import useUiConfig from 'hooks/api/getters/useUiConfig/useUiConfig'; - -interface IChartsProps { - flags: InstanceInsightsSchema['flags']; - flagTrends: InstanceInsightsSchema['flagTrends']; - projectsData: InstanceInsightsSchema['projectFlagTrends']; - groupedProjectsData: GroupedDataByProject< - InstanceInsightsSchema['projectFlagTrends'] - >; - metricsData: InstanceInsightsSchema['metricsSummaryTrends']; - groupedMetricsData: GroupedDataByProject< - InstanceInsightsSchema['metricsSummaryTrends'] - >; - users: InstanceInsightsSchema['users']; - userTrends: InstanceInsightsSchema['userTrends']; - environmentTypeTrends: InstanceInsightsSchema['environmentTypeTrends']; - summary: { - total: number; - active: number; - stale: number; - potentiallyStale: number; - averageUsers: number; - averageHealth?: string; - flagsPerUser?: string; - medianTimeToProduction?: number; - }; - loading: boolean; - projects: string[]; - allMetricsDatapoints: string[]; -} - -const StyledGrid = styled(Box)(({ theme }) => ({ - display: 'grid', - gridTemplateColumns: `repeat(2, 1fr)`, - gridAutoRows: 'auto', - gap: theme.spacing(2), - paddingBottom: theme.spacing(2), - [theme.breakpoints.up('md')]: { - gridTemplateColumns: `300px 1fr`, - }, -})); - -const ChartWidget = styled(Widget)(({ theme }) => ({ - [theme.breakpoints.down('md')]: { - gridColumnStart: 'span 2', - order: 2, - }, -})); - -/** - * @deprecated remove with insightsV2 flag - */ -export const LegacyInsightsCharts: VFC = ({ - projects, - flags, - users, - summary, - userTrends, - groupedProjectsData, - flagTrends, - groupedMetricsData, - environmentTypeTrends, - allMetricsDatapoints, - loading, -}) => { - const { isEnterprise } = useUiConfig(); - const showAllProjects = projects[0] === allOption.id; - const isOneProjectSelected = projects.length === 1; - - function getFlagsPerUser( - flags: InstanceInsightsSchemaFlags, - users: InstanceInsightsSchemaUsers, - ) { - const flagsPerUserCalculation = flags.total / users.total; - return Number.isNaN(flagsPerUserCalculation) - ? 'N/A' - : flagsPerUserCalculation.toFixed(2); - } - - return ( - <> - - - - - } - elseShow={ - - - - } - /> - - - - } - elseShow={ - - - - } - /> - - - - - - - } - elseShow={ - - - - } - /> - - - - - - - - - - - - - - - } - /> - - - - - - theme.spacing(2) }} - > - - - - } - /> - - ); -}; diff --git a/frontend/src/component/insights/chart-info.ts b/frontend/src/component/insights/chart-info.ts deleted file mode 100644 index dcd517ab0e9e..000000000000 --- a/frontend/src/component/insights/chart-info.ts +++ /dev/null @@ -1,85 +0,0 @@ -/** - * @deprecated remove with insightsV2 flag - */ -export const chartInfo = { - totalUsers: { - title: 'Total users', - tooltip: 'Total number of current users.', - }, - usersInProject: { - title: 'Users in project', - tooltip: 'Average number of users for selected projects.', - }, - avgUsersPerProject: { - title: 'Users per project on average', - tooltip: 'Number of users in selected projects.', - }, - users: { - title: 'Users', - tooltip: 'How the number of users changes over time.', - }, - usersPerProject: { - title: 'Users per project', - tooltip: - 'How the number of users changes over time for the selected projects.', - }, - totalFlags: { - title: 'Total flags', - tooltip: - 'Active flags (not archived) that currently exist across the selected projects.', - }, - flags: { - title: 'Number of flags', - tooltip: - 'How the number of flags has changed over time across all projects.', - }, - flagsPerProject: { - title: 'Flags per project', - tooltip: - 'How the number of flags changes over time for the selected projects.', - }, - averageHealth: { - title: 'Average health', - tooltip: - 'Average health is the current percentage of flags in the selected projects that are not stale or potentially stale.', - }, - overallHealth: { - title: 'Overall Health', - tooltip: - 'How the overall health changes over time across all projects.', - }, - healthPerProject: { - title: 'Health per project', - tooltip: - 'How the overall health changes over time for the selected projects.', - }, - medianTimeToProduction: { - title: 'Median time to production', - tooltip: - 'How long does it currently take on average from when a feature flag was created until it was enabled in a "production" type environment. This is calculated only from feature flags of the type "release" and is the median across the selected projects.', - }, - timeToProduction: { - title: 'Time to production', - tooltip: - 'How the median time to production changes over time across all projects.', - }, - timeToProductionPerProject: { - title: 'Time to production per project', - tooltip: - 'How the average time to production changes over time for the selected projects.', - }, - metrics: { - title: 'Flag evaluation metrics', - tooltip: - 'Summary of all flag evaluations reported by SDKs across all projects.', - }, - metricsPerProject: { - title: 'Flag evaluation metrics per project', - tooltip: - 'Summary of all flag evaluations reported by SDKs for the selected projects.', - }, - updates: { - title: 'Updates per environment type', - tooltip: 'Summary of all configuration updates per environment type.', - }, -}; diff --git a/frontend/src/component/insights/components/Widget/Widget.tsx b/frontend/src/component/insights/components/Widget/Widget.tsx deleted file mode 100644 index 202b3f70b070..000000000000 --- a/frontend/src/component/insights/components/Widget/Widget.tsx +++ /dev/null @@ -1,47 +0,0 @@ -import type React from 'react'; -import type { FC, ReactNode } from 'react'; -import { Paper, Typography, styled, type SxProps } from '@mui/material'; -import { HelpIcon } from 'component/common/HelpIcon/HelpIcon'; -import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender'; -import type { Theme } from '@mui/material/styles/createTheme'; -import InfoOutlined from '@mui/icons-material/InfoOutlined'; - -const StyledPaper = styled(Paper)(({ theme }) => ({ - padding: theme.spacing(3), - borderRadius: `${theme.shape.borderRadiusLarge}px`, - minWidth: 0, // bugfix, see: https://github.com/chartjs/Chart.js/issues/4156#issuecomment-295180128 - position: 'relative', -})); - -/** - * @deprecated remove with insightsV2 flag - */ -export const Widget: FC<{ - title: ReactNode; - tooltip?: ReactNode; - sx?: SxProps; - children?: React.ReactNode; -}> = ({ title, children, tooltip, ...rest }) => ( - - ({ - marginBottom: theme.spacing(3), - display: 'flex', - alignItems: 'center', - gap: theme.spacing(0.5), - })} - > - {title} - - - - } - /> - - {children} - -); diff --git a/frontend/src/component/insights/componentsStat/HealthStats/LegacyHealthStats.tsx b/frontend/src/component/insights/componentsStat/HealthStats/LegacyHealthStats.tsx deleted file mode 100644 index 962057d52e43..000000000000 --- a/frontend/src/component/insights/componentsStat/HealthStats/LegacyHealthStats.tsx +++ /dev/null @@ -1,320 +0,0 @@ -import type { FC } from 'react'; -import { useThemeMode } from 'hooks/useThemeMode'; -import { styled, useTheme } from '@mui/material'; - -interface IHealthStatsProps { - value?: string | number; - healthy: number; - stale: number; - potentiallyStale: number; -} - -const StyledSvg = styled('svg')(() => ({ - maxWidth: '250px', - margin: '0 auto', -})); - -/** - * @deprecated remove with insightsV2 flag - */ -export const LegacyHealthStats: FC = ({ - value, - healthy, - stale, - potentiallyStale, -}) => { - const { themeMode } = useThemeMode(); - const isDark = themeMode === 'dark'; - const theme = useTheme(); - - return ( - - Health Stats - - - - - - {value !== undefined ? `${value}%` : 'N/A'} - - - - - - {healthy || 0} - - - Healthy - - - - - - {stale || 0} - - - Stale - - - - - - {potentiallyStale || 0} - - - - Potentially - - - stale - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ); -}; diff --git a/frontend/src/interfaces/uiConfig.ts b/frontend/src/interfaces/uiConfig.ts index c00a70a7cab6..ad82100c9d50 100644 --- a/frontend/src/interfaces/uiConfig.ts +++ b/frontend/src/interfaces/uiConfig.ts @@ -89,7 +89,6 @@ export type UiFlags = { navigationSidebar?: boolean; flagCreator?: boolean; resourceLimits?: boolean; - insightsV2?: boolean; integrationEvents?: boolean; newEventSearch?: boolean; archiveProjects?: boolean; diff --git a/src/lib/__snapshots__/create-config.test.ts.snap b/src/lib/__snapshots__/create-config.test.ts.snap index d5f1617b9b68..1ef0c6659232 100644 --- a/src/lib/__snapshots__/create-config.test.ts.snap +++ b/src/lib/__snapshots__/create-config.test.ts.snap @@ -120,7 +120,6 @@ exports[`should create default config 1`] = ` }, "filterInvalidClientMetrics": false, "googleAuthEnabled": false, - "insightsV2": false, "integrationEvents": false, "killInsightsUI": false, "killScheduledChangeRequestCache": false, diff --git a/src/lib/types/experimental.ts b/src/lib/types/experimental.ts index e6df34fecd5a..b8a925218016 100644 --- a/src/lib/types/experimental.ts +++ b/src/lib/types/experimental.ts @@ -59,7 +59,6 @@ export type IFlagKey = | 'resourceLimits' | 'extendedMetrics' | 'removeUnsafeInlineStyleSrc' - | 'insightsV2' | 'integrationEvents' | 'originMiddleware' | 'newEventSearch' @@ -292,10 +291,6 @@ const flags: IFlags = { process.env.UNLEASH_EXPERIMENTAL_REMOVE_UNSAFE_INLINE_STYLE_SRC, false, ), - insightsV2: parseEnvVarBoolean( - process.env.UNLEASH_EXPERIMENTAL_INSIGHTS_V2, - false, - ), integrationEvents: parseEnvVarBoolean( process.env.UNLEASH_EXPERIMENTAL_INTEGRATION_EVENTS, false, diff --git a/src/server-dev.ts b/src/server-dev.ts index 33037fd15747..31ad0c5ecd4a 100644 --- a/src/server-dev.ts +++ b/src/server-dev.ts @@ -52,7 +52,6 @@ process.nextTick(async () => { enableLegacyVariants: false, resourceLimits: true, extendedMetrics: true, - insightsV2: true, integrationEvents: true, originMiddleware: true, newEventSearch: true,