1
0
mirror of https://github.com/Unleash/unleash.git synced 2025-09-24 17:51:14 +02:00

Merge branch 'main' into 1-4036

This commit is contained in:
Thomas Heartman 2025-09-01 09:15:14 +02:00 committed by GitHub
commit 9474e6ebbe
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
11 changed files with 91 additions and 29 deletions

View File

@ -9,7 +9,7 @@
[![Build and Tests](https://img.shields.io/github/actions/workflow/status/Unleash/unleash/build.yaml?branch=main)](https://github.com/Unleash/unleash/actions/workflows/build.yaml) [![Coverage Report](https://img.shields.io/badge/coverage-vitest-green)](https://github.com/Unleash/unleash/actions/workflows/build_coverage.yaml) [![Docker Pulls](https://img.shields.io/docker/pulls/unleashorg/unleash-server)](https://hub.docker.com/r/unleashorg/unleash-server) [![Apache-2.0 license](https://img.shields.io/github/license/unleash/unleash)](https://github.com/Unleash/unleash/blob/main/LICENSE) [![Join Unleash on Slack](https://img.shields.io/badge/slack-join-635dc5?logo=slack)](https://slack.unleash.run)
[Experience Unleash Live Demo →](https://www.getunleash.io/interactive-demo)
[Try Unleash Cloud for free →](https://www.getunleash.io/plans/enterprise-payg?utm_source=readme&utm_medium=oss&utm_content=top-cta)
</div>
@ -93,9 +93,9 @@ The above sections show you how to get up and running quickly and easily. When y
## Online demo
Try out [the Unleash online demo](https://www.getunleash.io/interactive-demo).
Try out [the Unleash online demo](https://www.getunleash.io/interactive-demo?utm_source=readme&utm_medium=oss&utm_content=demo-section-cta).
[![The Unleash online demo](./.github/github_online_demo.svg)](https://www.getunleash.io/interactive-demo)
[![The Unleash online demo](./.github/github_online_demo.svg)](https://www.getunleash.io/interactive-demo?utm_source=readme&utm_medium=oss&utm_content=demo-section-cta)
<br/>

View File

@ -1,17 +1,17 @@
import { calculateRatio } from './calculate-ratio.ts';
test('A ratio of anything to 0 is 100', () => {
expect(calculateRatio(0, 0)).toBe(100);
expect(calculateRatio(5, 0)).toBe(100);
test('A ratio of anything to 0 is N/A', () => {
expect(calculateRatio(0, 0)).toBe('N/A');
expect(calculateRatio(5, 0)).toBe('N/A');
});
test('Normal ratios work as expected', () => {
expect(calculateRatio(0, 1)).toBe(0);
expect(calculateRatio(1, 1)).toBe(100);
expect(calculateRatio(1, 2)).toBe(50);
expect(calculateRatio(5, 2)).toBe(250);
expect(calculateRatio(0, 1)).toBe('0%');
expect(calculateRatio(1, 1)).toBe('100%');
expect(calculateRatio(1, 2)).toBe('50%');
expect(calculateRatio(5, 2)).toBe('250%');
});
test('Numbers are rounded to the nearest integer', () => {
expect(calculateRatio(5, 9)).toBe(56);
expect(calculateRatio(5, 9)).toBe('56%');
});

View File

@ -1,12 +1,11 @@
export const calculateRatio = (
antecedent: number,
consequent: number,
): number => {
const rawRatio = Math.round((antecedent / consequent) * 100);
if (Number.isNaN(rawRatio) || rawRatio === Number.POSITIVE_INFINITY) {
return 100;
): string => {
if (consequent === 0) {
return 'N/A';
}
const ratio = Math.round((antecedent / consequent) * 100);
return rawRatio;
return `${ratio}%`;
};

View File

@ -65,7 +65,7 @@ export const CreationArchiveRatioTooltip: FC<
<ChartTooltipContainer tooltip={tooltip}>
<StyledTooltipItemContainer elevation={3}>
<Typography variant='body2' component='span' fontWeight='bold'>
Ratio {ratio}%
Ratio {ratio}
</Typography>
<DataList>

View File

@ -90,7 +90,7 @@ export const CreationArchiveStats: FC<CreationArchiveStatsProps> = ({
<StyledRatioContainer>
<StyledPercentageRow>
<StyledRatioTypography>
{isLoading ? '...' : `${currentRatio}%`}
{isLoading ? '...' : currentRatio}
</StyledRatioTypography>
<HelpIcon tooltip='Ratio of archived flags to created flags'>
<StyledInfoIcon />

View File

@ -113,7 +113,7 @@ export const PerformanceInsights: FC = () => {
{isLifecycleGraphsEnabled && isEnterprise() ? (
<StyledWidget>
<StyledWidgetStats width={275}>
<WidgetTitle title='Flags created vs archived' />
<WidgetTitle title='Flags archived vs flags created' />
<CreationArchiveStats
groupedCreationArchiveData={
groupedCreationArchiveData

View File

@ -0,0 +1,54 @@
import Add from '@mui/icons-material/Add';
import { Box, styled } from '@mui/material';
import PermissionIconButton from 'component/common/PermissionIconButton/PermissionIconButton';
import { CREATE_FEATURE } from 'component/providers/AccessProvider/permissions';
import type { UnknownFlag } from './hooks/useUnknownFlags.js';
import { Link } from 'react-router-dom';
import useProjects from 'hooks/api/getters/useProjects/useProjects.js';
import { DEFAULT_PROJECT_ID } from 'hooks/api/getters/useDefaultProject/useDefaultProjectId.js';
import AccessContext from 'contexts/AccessContext.js';
import { useContext } from 'react';
const StyledBox = styled(Box)(() => ({
display: 'flex',
justifyContent: 'center',
}));
interface IUnknownFlagsActionsCellProps {
unknownFlag: UnknownFlag;
}
export const UnknownFlagsActionsCell = ({
unknownFlag,
}: IUnknownFlagsActionsCellProps) => {
const { projects } = useProjects();
const { hasAccess } = useContext(AccessContext);
let project =
projects.find(({ id }) => id === DEFAULT_PROJECT_ID) || projects[0];
if (!hasAccess(CREATE_FEATURE, project?.id)) {
for (const proj of projects) {
if (hasAccess(CREATE_FEATURE, proj.id)) {
project = proj;
break;
}
}
}
return (
<StyledBox>
<PermissionIconButton
component={Link}
data-loading
to={`/projects/${project?.id}?create=true&name=${unknownFlag.name}`}
permission={CREATE_FEATURE}
projectId={project?.id}
tooltipProps={{
title: 'Create feature flag',
}}
>
<Add />
</PermissionIconButton>
</StyledBox>
);
};

View File

@ -18,6 +18,7 @@ import { useUiFlag } from 'hooks/useUiFlag.js';
import NotFound from 'component/common/NotFound/NotFound.js';
import { UnknownFlagsSeenInUnleashCell } from './UnknownFlagsSeenInUnleashCell.js';
import { HelpIcon } from 'component/common/HelpIcon/HelpIcon.js';
import { UnknownFlagsActionsCell } from './UnknownFlagsActionsCell.js';
const StyledAlert = styled(Alert)(({ theme }) => ({
marginBottom: theme.spacing(3),
@ -104,6 +105,17 @@ export const UnknownFlagsTable = () => {
),
width: 150,
},
{
Header: 'Actions',
align: 'center',
Cell: ({
row: { original: unknownFlag },
}: {
row: { original: UnknownFlag };
}) => <UnknownFlagsActionsCell unknownFlag={unknownFlag} />,
width: 100,
disableSortBy: true,
},
],
[],
);

View File

@ -221,10 +221,9 @@ const theme = {
*/
charts: {
A1: '#6C65E5',
A2: '#8C87EB',
A3: '#ADA9F1',
A4: '#CECCF6',
A5: '#F1F0FC',
A2: '#9D98EE',
A3: '#CECCF6',
A4: '#F1F0FC',
B1: '#1791AE',
C1: '#DF416E',
D1: '#D76500',

View File

@ -277,10 +277,9 @@ const theme = {
*/
charts: {
A1: '#6C65E5',
A2: '#8C87EB',
A3: '#ADA9F1',
A4: '#CECCF6',
A5: '#F1F0FC',
A2: '#9D98EE',
A3: '#CECCF6',
A4: '#F1F0FC',
B1: '#1791AE',
C1: '#DF416E',
D1: '#D76500',

View File

@ -142,7 +142,6 @@ declare module '@mui/material/styles' {
A2: string;
A3: string;
A4: string;
A5: string;
B1: string;
C1: string;
D1: string;