mirror of
https://github.com/Unleash/unleash.git
synced 2025-08-27 13:49:10 +02:00
chore(AI): lifecycleMetrics flag cleanup (#10511)
This PR cleans up the lifecycleMetrics flag. These changes were automatically generated by AI and should be reviewed carefully. Fixes #10505 --------- Co-authored-by: unleash-bot <194219037+unleash-bot[bot]@users.noreply.github.com> Co-authored-by: Thomas Heartman <thomas@getunleash.io>
This commit is contained in:
parent
a9b1d7c11b
commit
170ed87fcb
@ -1,63 +0,0 @@
|
||||
import { render } from 'utils/testRenderer';
|
||||
import { fireEvent, screen } from '@testing-library/react';
|
||||
import { Insights } from './Insights.tsx';
|
||||
import { testServerRoute, testServerSetup } from 'utils/testServer';
|
||||
import { vi } from 'vitest';
|
||||
|
||||
const server = testServerSetup();
|
||||
|
||||
const setupApi = () => {
|
||||
testServerRoute(server, '/api/admin/insights', {
|
||||
users: { total: 0, active: 0, inactive: 0 },
|
||||
userTrends: [],
|
||||
projectFlagTrends: [],
|
||||
metricsSummaryTrends: [],
|
||||
flags: { total: 0 },
|
||||
flagTrends: [],
|
||||
environmentTypeTrends: [],
|
||||
lifecycleTrends: [],
|
||||
creationArchiveTrends: [],
|
||||
});
|
||||
|
||||
testServerRoute(server, '/api/admin/projects', {
|
||||
projects: [
|
||||
{ name: 'Project A Name', id: 'projectA' },
|
||||
{ name: 'Project B Name', id: 'projectB' },
|
||||
],
|
||||
});
|
||||
};
|
||||
|
||||
const currentTime = '2024-04-25T08:05:00.000Z';
|
||||
|
||||
// todo(lifecycleMetrics): this test won't be relevant anymore because the
|
||||
// filters are on each section instead of the top-level component. Consider
|
||||
// rewriting this for the individual section components instead.
|
||||
test('Filter insights by project and date', async () => {
|
||||
vi.setSystemTime(currentTime);
|
||||
setupApi();
|
||||
render(<Insights withCharts={false} />);
|
||||
const addFilter = await screen.findByText('Filter');
|
||||
fireEvent.click(addFilter);
|
||||
const projectFilter = await screen.findByText('Project');
|
||||
|
||||
// filter by project
|
||||
fireEvent.click(projectFilter);
|
||||
await screen.findByText('Project A Name');
|
||||
const projectName = await screen.findByText('Project B Name');
|
||||
await fireEvent.click(projectName);
|
||||
expect(window.location.href).toContain('project=IS%3AprojectB');
|
||||
|
||||
// last month moving window by default
|
||||
const fromDate = await screen.findByText('03/25/2024');
|
||||
await screen.findByText('04/25/2024');
|
||||
|
||||
// change dates by preset range
|
||||
fireEvent.click(fromDate);
|
||||
const previousMonth = await screen.findByText('Previous month');
|
||||
fireEvent.click(previousMonth);
|
||||
await screen.findByText('03/01/2024');
|
||||
await screen.findByText('03/31/2024');
|
||||
expect(window.location.href).toContain(
|
||||
'?project=IS%3AprojectB&from=IS%3A2024-03-01&to=IS%3A2024-03-31',
|
||||
);
|
||||
});
|
@ -1,8 +1,6 @@
|
||||
import type { FC } from 'react';
|
||||
import { styled } from '@mui/material';
|
||||
import { InsightsHeader } from './components/InsightsHeader/InsightsHeader.tsx';
|
||||
import { useUiFlag } from 'hooks/useUiFlag.ts';
|
||||
import { LegacyInsights } from './LegacyInsights.tsx';
|
||||
import { StyledContainer } from './InsightsCharts.styles.ts';
|
||||
import { LifecycleInsights } from './sections/LifecycleInsights.tsx';
|
||||
import { PerformanceInsights } from './sections/PerformanceInsights.tsx';
|
||||
@ -12,21 +10,13 @@ const StyledWrapper = styled('div')(({ theme }) => ({
|
||||
paddingTop: theme.spacing(2),
|
||||
}));
|
||||
|
||||
const NewInsights: FC = () => {
|
||||
return (
|
||||
<StyledWrapper>
|
||||
<InsightsHeader />
|
||||
<StyledContainer>
|
||||
<LifecycleInsights />
|
||||
<PerformanceInsights />
|
||||
<UserInsights />
|
||||
</StyledContainer>
|
||||
</StyledWrapper>
|
||||
);
|
||||
};
|
||||
|
||||
export const Insights: FC<{ withCharts?: boolean }> = (props) => {
|
||||
const useNewInsights = useUiFlag('lifecycleMetrics');
|
||||
|
||||
return useNewInsights ? <NewInsights /> : <LegacyInsights {...props} />;
|
||||
};
|
||||
export const Insights: FC = () => (
|
||||
<StyledWrapper>
|
||||
<InsightsHeader />
|
||||
<StyledContainer>
|
||||
<LifecycleInsights />
|
||||
<PerformanceInsights />
|
||||
<UserInsights />
|
||||
</StyledContainer>
|
||||
</StyledWrapper>
|
||||
);
|
||||
|
@ -127,55 +127,51 @@ export const InsightsCharts: FC<IChartsProps> = ({
|
||||
<ConditionallyRender
|
||||
condition={showAllProjects}
|
||||
show={
|
||||
<>
|
||||
<StyledWidget>
|
||||
<StyledWidgetStats>
|
||||
<WidgetTitle title='Total users' />
|
||||
<UserStats
|
||||
count={usersTotal}
|
||||
active={usersActive}
|
||||
inactive={usersInactive}
|
||||
isLoading={loading}
|
||||
/>
|
||||
</StyledWidgetStats>
|
||||
<StyledChartContainer>
|
||||
<UsersChart
|
||||
userTrends={userTrends}
|
||||
isLoading={loading}
|
||||
/>
|
||||
</StyledChartContainer>
|
||||
</StyledWidget>
|
||||
</>
|
||||
<StyledWidget>
|
||||
<StyledWidgetStats>
|
||||
<WidgetTitle title='Total users' />
|
||||
<UserStats
|
||||
count={usersTotal}
|
||||
active={usersActive}
|
||||
inactive={usersInactive}
|
||||
isLoading={loading}
|
||||
/>
|
||||
</StyledWidgetStats>
|
||||
<StyledChartContainer>
|
||||
<UsersChart
|
||||
userTrends={userTrends}
|
||||
isLoading={loading}
|
||||
/>
|
||||
</StyledChartContainer>
|
||||
</StyledWidget>
|
||||
}
|
||||
elseShow={
|
||||
<>
|
||||
<StyledWidget>
|
||||
<StyledWidgetStats>
|
||||
<WidgetTitle
|
||||
title={
|
||||
isOneProjectSelected
|
||||
? 'Users in project'
|
||||
: 'Users per project on average'
|
||||
}
|
||||
tooltip={
|
||||
isOneProjectSelected
|
||||
? 'Number of users in selected projects.'
|
||||
: 'Average number of users for selected projects.'
|
||||
}
|
||||
/>
|
||||
<UserStats
|
||||
count={summary.averageUsers}
|
||||
isLoading={loading}
|
||||
/>
|
||||
</StyledWidgetStats>
|
||||
<StyledChartContainer>
|
||||
<UsersPerProjectChart
|
||||
projectFlagTrends={groupedProjectsData}
|
||||
isLoading={loading}
|
||||
/>
|
||||
</StyledChartContainer>
|
||||
</StyledWidget>
|
||||
</>
|
||||
<StyledWidget>
|
||||
<StyledWidgetStats>
|
||||
<WidgetTitle
|
||||
title={
|
||||
isOneProjectSelected
|
||||
? 'Users in project'
|
||||
: 'Users per project on average'
|
||||
}
|
||||
tooltip={
|
||||
isOneProjectSelected
|
||||
? 'Number of users in selected projects.'
|
||||
: 'Average number of users for selected projects.'
|
||||
}
|
||||
/>
|
||||
<UserStats
|
||||
count={summary.averageUsers}
|
||||
isLoading={loading}
|
||||
/>
|
||||
</StyledWidgetStats>
|
||||
<StyledChartContainer>
|
||||
<UsersPerProjectChart
|
||||
projectFlagTrends={groupedProjectsData}
|
||||
isLoading={loading}
|
||||
/>
|
||||
</StyledChartContainer>
|
||||
</StyledWidget>
|
||||
}
|
||||
/>
|
||||
<ConditionallyRender
|
||||
@ -234,47 +230,35 @@ export const InsightsCharts: FC<IChartsProps> = ({
|
||||
<ConditionallyRender
|
||||
condition={showAllProjects}
|
||||
show={
|
||||
<>
|
||||
<StyledWidget>
|
||||
<StyledWidgetStats width={275}>
|
||||
<WidgetTitle title='Flags' />
|
||||
<FlagStats
|
||||
count={flagsTotal}
|
||||
flagsPerUser={getFlagsPerUser(
|
||||
flagsTotal,
|
||||
usersTotal,
|
||||
)}
|
||||
isLoading={loading}
|
||||
/>
|
||||
</StyledWidgetStats>
|
||||
<StyledChartContainer>
|
||||
<FlagsChart
|
||||
flagTrends={flagTrends}
|
||||
isLoading={loading}
|
||||
/>
|
||||
</StyledChartContainer>
|
||||
</StyledWidget>
|
||||
</>
|
||||
<StyledWidget>
|
||||
<StyledWidgetStats width={275}>
|
||||
<WidgetTitle title='Flags' />
|
||||
<FlagStats count={flagsTotal} isLoading={loading} />
|
||||
</StyledWidgetStats>
|
||||
<StyledChartContainer>
|
||||
<FlagsChart
|
||||
flagTrends={flagTrends}
|
||||
isLoading={loading}
|
||||
/>
|
||||
</StyledChartContainer>
|
||||
</StyledWidget>
|
||||
}
|
||||
elseShow={
|
||||
<>
|
||||
<StyledWidget>
|
||||
<StyledWidgetStats width={275}>
|
||||
<WidgetTitle title='Flags' />
|
||||
<FlagStats
|
||||
count={summary.total}
|
||||
flagsPerUser={''}
|
||||
isLoading={loading}
|
||||
/>
|
||||
</StyledWidgetStats>
|
||||
<StyledChartContainer>
|
||||
<FlagsProjectChart
|
||||
projectFlagTrends={groupedProjectsData}
|
||||
isLoading={loading}
|
||||
/>
|
||||
</StyledChartContainer>
|
||||
</StyledWidget>
|
||||
</>
|
||||
<StyledWidget>
|
||||
<StyledWidgetStats width={275}>
|
||||
<WidgetTitle title='Flags' />
|
||||
<FlagStats
|
||||
count={summary.total}
|
||||
isLoading={loading}
|
||||
/>
|
||||
</StyledWidgetStats>
|
||||
<StyledChartContainer>
|
||||
<FlagsProjectChart
|
||||
projectFlagTrends={groupedProjectsData}
|
||||
isLoading={loading}
|
||||
/>
|
||||
</StyledChartContainer>
|
||||
</StyledWidget>
|
||||
}
|
||||
/>
|
||||
<ConditionallyRender
|
||||
|
@ -7,7 +7,6 @@ import {
|
||||
type IFilterItem,
|
||||
} from 'component/filter/Filters/Filters';
|
||||
import { styled } from '@mui/material';
|
||||
import { useUiFlag } from 'hooks/useUiFlag';
|
||||
|
||||
interface IFeatureToggleFiltersProps {
|
||||
state: FilterItemParamHolder;
|
||||
@ -26,9 +25,6 @@ export const InsightsFilters: FC<IFeatureToggleFiltersProps> = ({
|
||||
...filterProps
|
||||
}) => {
|
||||
const { projects } = useProjects();
|
||||
const FilterComponent = useUiFlag('lifecycleMetrics')
|
||||
? FiltersNoPadding
|
||||
: Filters;
|
||||
|
||||
const [availableFilters, setAvailableFilters] = useState<IFilterItem[]>([]);
|
||||
|
||||
@ -81,7 +77,7 @@ export const InsightsFilters: FC<IFeatureToggleFiltersProps> = ({
|
||||
}, [JSON.stringify(projects)]);
|
||||
|
||||
return (
|
||||
<FilterComponent
|
||||
<FiltersNoPadding
|
||||
{...filterProps}
|
||||
state={state}
|
||||
availableFilters={availableFilters}
|
||||
|
@ -1,76 +0,0 @@
|
||||
import type { FC } from 'react';
|
||||
import { styled } from '@mui/material';
|
||||
import { usePersistentTableState } from 'hooks/usePersistentTableState';
|
||||
import { allOption } from 'component/common/ProjectSelect/ProjectSelect';
|
||||
import { useInsights } from 'hooks/api/getters/useInsights/useInsights';
|
||||
import { InsightsHeader } from './components/InsightsHeader/InsightsHeader.tsx';
|
||||
import { useInsightsData } from './hooks/useInsightsData.ts';
|
||||
import { Sticky } from 'component/common/Sticky/Sticky';
|
||||
import { InsightsFilters } from './InsightsFilters.tsx';
|
||||
import { FilterItemParam } from '../../utils/serializeQueryParams.ts';
|
||||
import { format, subMonths } from 'date-fns';
|
||||
import { withDefault } from 'use-query-params';
|
||||
import { InsightsCharts } from './InsightsCharts.tsx';
|
||||
|
||||
const StyledWrapper = styled('div')(({ theme }) => ({
|
||||
paddingTop: theme.spacing(2),
|
||||
}));
|
||||
|
||||
const StickyContainer = styled(Sticky)(({ theme }) => ({
|
||||
position: 'sticky',
|
||||
top: 0,
|
||||
zIndex: theme.zIndex.sticky,
|
||||
padding: theme.spacing(2, 0),
|
||||
background: theme.palette.background.application,
|
||||
transition: 'padding 0.3s ease',
|
||||
}));
|
||||
|
||||
interface InsightsProps {
|
||||
withCharts?: boolean;
|
||||
}
|
||||
|
||||
export const LegacyInsights: FC<InsightsProps> = ({ withCharts = true }) => {
|
||||
const stateConfig = {
|
||||
project: FilterItemParam,
|
||||
from: withDefault(FilterItemParam, {
|
||||
values: [format(subMonths(new Date(), 1), 'yyyy-MM-dd')],
|
||||
operator: 'IS',
|
||||
}),
|
||||
to: withDefault(FilterItemParam, {
|
||||
values: [format(new Date(), 'yyyy-MM-dd')],
|
||||
operator: 'IS',
|
||||
}),
|
||||
};
|
||||
const [state, setState] = usePersistentTableState('insights', stateConfig, [
|
||||
'from',
|
||||
'to',
|
||||
]);
|
||||
|
||||
const { insights, loading } = useInsights(
|
||||
state.from?.values[0],
|
||||
state.to?.values[0],
|
||||
);
|
||||
|
||||
const projects = state.project?.values ?? [allOption.id];
|
||||
|
||||
const insightsData = useInsightsData(insights, projects);
|
||||
|
||||
return (
|
||||
<StyledWrapper>
|
||||
<StickyContainer>
|
||||
<InsightsHeader
|
||||
actions={
|
||||
<InsightsFilters state={state} onChange={setState} />
|
||||
}
|
||||
/>
|
||||
</StickyContainer>
|
||||
{withCharts && (
|
||||
<InsightsCharts
|
||||
loading={loading}
|
||||
projects={projects}
|
||||
{...insightsData}
|
||||
/>
|
||||
)}
|
||||
</StyledWrapper>
|
||||
);
|
||||
};
|
@ -1,7 +1,5 @@
|
||||
import Icon from '@mui/material/Icon';
|
||||
import { Box, Typography, styled } from '@mui/material';
|
||||
import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender';
|
||||
import { useUiFlag } from 'hooks/useUiFlag';
|
||||
import { useId } from 'hooks/useId';
|
||||
import { ScreenReaderOnly } from 'component/common/ScreenReaderOnly/ScreenReaderOnly';
|
||||
import { HelpIcon } from 'component/common/HelpIcon/HelpIcon';
|
||||
@ -79,27 +77,19 @@ const LabelContainer = styled('div')({
|
||||
|
||||
interface IFlagStatsProps {
|
||||
count: number;
|
||||
flagsPerUser?: string; // todo: remove this prop with the lifecycleMetrics flag
|
||||
isLoading?: boolean;
|
||||
}
|
||||
|
||||
export const FlagStats: React.FC<IFlagStatsProps> = ({
|
||||
count,
|
||||
flagsPerUser,
|
||||
isLoading,
|
||||
}) => {
|
||||
const hideFlagsPerUser = useUiFlag('lifecycleMetrics');
|
||||
const labelId = hideFlagsPerUser ? useId() : '';
|
||||
const descriptionId = hideFlagsPerUser ? useId() : '';
|
||||
export const FlagStats: React.FC<IFlagStatsProps> = ({ count, isLoading }) => {
|
||||
const labelId = useId();
|
||||
const descriptionId = useId();
|
||||
return (
|
||||
<>
|
||||
<StyledRingContainer>
|
||||
<StyledRing>
|
||||
<StyledRingContent
|
||||
{...(hideFlagsPerUser && {
|
||||
'aria-labelledby': labelId,
|
||||
'aria-describedby': descriptionId,
|
||||
})}
|
||||
aria-labelledby={labelId}
|
||||
aria-describedby={descriptionId}
|
||||
>
|
||||
{isLoading ? (
|
||||
<ScreenReaderOnly>
|
||||
@ -112,50 +102,20 @@ export const FlagStats: React.FC<IFlagStatsProps> = ({
|
||||
</StyledRing>
|
||||
</StyledRingContainer>
|
||||
|
||||
{hideFlagsPerUser ? (
|
||||
<LabelContainer>
|
||||
<Typography id={labelId} variant='body2'>
|
||||
Total number of flags
|
||||
</Typography>
|
||||
<HelpIcon
|
||||
htmlTooltip
|
||||
tooltipId={descriptionId}
|
||||
tooltip={
|
||||
'This includes the four lifecycle stages define, develop, production, and cleanup'
|
||||
}
|
||||
>
|
||||
<InfoOutlined />
|
||||
</HelpIcon>
|
||||
</LabelContainer>
|
||||
) : (
|
||||
<ConditionallyRender
|
||||
condition={
|
||||
flagsPerUser !== undefined && flagsPerUser !== ''
|
||||
<LabelContainer>
|
||||
<Typography id={labelId} variant='body2'>
|
||||
Total number of flags
|
||||
</Typography>
|
||||
<HelpIcon
|
||||
htmlTooltip
|
||||
tooltipId={descriptionId}
|
||||
tooltip={
|
||||
'This includes the four lifecycle stages define, develop, production, and cleanup'
|
||||
}
|
||||
show={
|
||||
<StyledInsightsContainer>
|
||||
<StyledTextContainer>
|
||||
<StyledHeaderContainer>
|
||||
<StyledIcon>award_star</StyledIcon>
|
||||
<Typography
|
||||
fontWeight='bold'
|
||||
variant='body2'
|
||||
color='primary'
|
||||
>
|
||||
Insights
|
||||
</Typography>
|
||||
</StyledHeaderContainer>
|
||||
<Typography variant='body2'>
|
||||
Flags per user
|
||||
</Typography>
|
||||
</StyledTextContainer>
|
||||
<StyledFlagCountPerUser>
|
||||
{flagsPerUser}
|
||||
</StyledFlagCountPerUser>
|
||||
</StyledInsightsContainer>
|
||||
}
|
||||
/>
|
||||
)}
|
||||
>
|
||||
<InfoOutlined />
|
||||
</HelpIcon>
|
||||
</LabelContainer>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
@ -61,7 +61,6 @@ export const PerformanceInsights: FC = () => {
|
||||
summary,
|
||||
groupedProjectsData,
|
||||
groupedLifecycleData,
|
||||
userTrends,
|
||||
groupedMetricsData,
|
||||
allMetricsDatapoints,
|
||||
environmentTypeTrends,
|
||||
@ -69,8 +68,6 @@ export const PerformanceInsights: FC = () => {
|
||||
} = useInsightsData(insights, projects);
|
||||
|
||||
const { isEnterprise } = useUiConfig();
|
||||
const lastUserTrend = userTrends[userTrends.length - 1];
|
||||
const usersTotal = lastUserTrend?.total ?? 0;
|
||||
const lastFlagTrend = flagTrends[flagTrends.length - 1];
|
||||
const flagsTotal = lastFlagTrend?.total ?? 0;
|
||||
|
||||
@ -137,14 +134,7 @@ export const PerformanceInsights: FC = () => {
|
||||
<StyledWidget>
|
||||
<StyledWidgetStats width={275}>
|
||||
<WidgetTitle title='Flags' />
|
||||
<FlagStats
|
||||
count={flagsTotal}
|
||||
flagsPerUser={getFlagsPerUser(
|
||||
flagsTotal,
|
||||
usersTotal,
|
||||
)}
|
||||
isLoading={loading}
|
||||
/>
|
||||
<FlagStats count={flagsTotal} isLoading={loading} />
|
||||
</StyledWidgetStats>
|
||||
<StyledChartContainer>
|
||||
<FlagsChart
|
||||
@ -157,11 +147,7 @@ export const PerformanceInsights: FC = () => {
|
||||
<StyledWidget>
|
||||
<StyledWidgetStats width={275}>
|
||||
<WidgetTitle title='Flags' />
|
||||
<FlagStats
|
||||
count={summary.total}
|
||||
flagsPerUser={''}
|
||||
isLoading={loading}
|
||||
/>
|
||||
<FlagStats count={summary.total} isLoading={loading} />
|
||||
</StyledWidgetStats>
|
||||
<StyledChartContainer>
|
||||
<FlagsProjectChart
|
||||
|
@ -86,7 +86,6 @@ export type UiFlags = {
|
||||
consumptionModelUI?: boolean;
|
||||
edgeObservability?: boolean;
|
||||
customMetrics?: boolean;
|
||||
lifecycleMetrics?: boolean;
|
||||
createFlagDialogCache?: boolean;
|
||||
impactMetrics?: boolean;
|
||||
changeRequestApproverEmails?: boolean;
|
||||
|
@ -54,7 +54,6 @@ export type IFlagKey =
|
||||
| 'consumptionModelUI'
|
||||
| 'edgeObservability'
|
||||
| 'reportUnknownFlags'
|
||||
| 'lifecycleMetrics'
|
||||
| 'customMetrics'
|
||||
| 'impactMetrics'
|
||||
| 'createFlagDialogCache'
|
||||
@ -261,10 +260,6 @@ const flags: IFlags = {
|
||||
process.env.UNLEASH_EXPERIMENTAL_REPORT_UNKNOWN_FLAGS,
|
||||
false,
|
||||
),
|
||||
lifecycleMetrics: parseEnvVarBoolean(
|
||||
process.env.UNLEASH_EXPERIMENTAL_LIFECYCLE_METRICS,
|
||||
false,
|
||||
),
|
||||
createFlagDialogCache: parseEnvVarBoolean(
|
||||
process.env.UNLEASH_EXPERIMENTAL_CREATE_FLAG_DIALOG_CACHE,
|
||||
false,
|
||||
|
@ -53,7 +53,6 @@ process.nextTick(async () => {
|
||||
strictSchemaValidation: true,
|
||||
reportUnknownFlags: true,
|
||||
customMetrics: true,
|
||||
lifecycleMetrics: true,
|
||||
impactMetrics: true,
|
||||
paygTrialEvents: true,
|
||||
lifecycleGraphs: true,
|
||||
|
Loading…
Reference in New Issue
Block a user