mirror of
https://github.com/Unleash/unleash.git
synced 2025-05-12 01:17:04 +02:00
feat: add creation buttons to application features and strategies (#6387)

This commit is contained in:
parent
68095916e8
commit
a958797a8a
@ -1,12 +1,20 @@
|
|||||||
import { Box, styled } from '@mui/material';
|
import { Box, styled } from '@mui/material';
|
||||||
import { ConditionallyRender } from '../../common/ConditionallyRender/ConditionallyRender';
|
import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender';
|
||||||
import { WarningAmberRounded } from '@mui/icons-material';
|
import { WarningAmberRounded } from '@mui/icons-material';
|
||||||
import { ApplicationOverviewIssuesSchema } from 'openapi';
|
import { ApplicationOverviewIssuesSchema } from 'openapi';
|
||||||
|
import { Link } from 'react-router-dom';
|
||||||
|
import {
|
||||||
|
CREATE_FEATURE,
|
||||||
|
CREATE_STRATEGY,
|
||||||
|
} from 'component/providers/AccessProvider/permissions';
|
||||||
|
import { useContext } from 'react';
|
||||||
|
import AccessContext from 'contexts/AccessContext';
|
||||||
|
|
||||||
const WarningContainer = styled(Box)(({ theme }) => ({
|
const WarningContainer = styled(Box)(({ theme }) => ({
|
||||||
display: 'flex',
|
display: 'flex',
|
||||||
flexDirection: 'column',
|
flexDirection: 'column',
|
||||||
alignSelf: 'stretch',
|
alignSelf: 'stretch',
|
||||||
|
fontSize: theme.fontSizes.smallBody,
|
||||||
}));
|
}));
|
||||||
|
|
||||||
const WarningHeader = styled(Box)(({ theme }) => ({
|
const WarningHeader = styled(Box)(({ theme }) => ({
|
||||||
@ -21,11 +29,7 @@ const WarningHeader = styled(Box)(({ theme }) => ({
|
|||||||
color: theme.palette.warning.main,
|
color: theme.palette.warning.main,
|
||||||
}));
|
}));
|
||||||
|
|
||||||
const SmallText = styled(Box)(({ theme }) => ({
|
const WarningHeaderText = styled(Box)(({ theme }) => ({
|
||||||
fontSize: theme.fontSizes.smallBody,
|
|
||||||
}));
|
|
||||||
|
|
||||||
const WarningHeaderText = styled(SmallText)(({ theme }) => ({
|
|
||||||
color: theme.palette.warning.dark,
|
color: theme.palette.warning.dark,
|
||||||
fontWeight: theme.fontWeight.bold,
|
fontWeight: theme.fontWeight.bold,
|
||||||
}));
|
}));
|
||||||
@ -36,7 +40,6 @@ const StyledList = styled('ul')(({ theme }) => ({
|
|||||||
|
|
||||||
const StyledListElement = styled('li')(({ theme }) => ({
|
const StyledListElement = styled('li')(({ theme }) => ({
|
||||||
fontWeight: theme.fontWeight.bold,
|
fontWeight: theme.fontWeight.bold,
|
||||||
fontSize: theme.fontSizes.smallBody,
|
|
||||||
}));
|
}));
|
||||||
|
|
||||||
const IssueContainer = styled(Box)(({ theme }) => ({
|
const IssueContainer = styled(Box)(({ theme }) => ({
|
||||||
@ -62,6 +65,20 @@ const IssueTextContainer = styled(Box)(({ theme }) => ({
|
|||||||
border: `1px solid ${theme.palette.divider}`,
|
border: `1px solid ${theme.palette.divider}`,
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
const IssueRowContainer = styled(Box)(({ theme }) => ({
|
||||||
|
display: 'flex',
|
||||||
|
flexDirection: 'row',
|
||||||
|
gap: theme.spacing(1.5),
|
||||||
|
alignItems: 'center',
|
||||||
|
}));
|
||||||
|
|
||||||
|
const StyledLink = styled(Link)(() => ({
|
||||||
|
overflow: 'hidden',
|
||||||
|
textOverflow: 'ellipsis',
|
||||||
|
whiteSpace: 'nowrap',
|
||||||
|
textDecoration: 'underline',
|
||||||
|
}));
|
||||||
|
|
||||||
export interface IApplicationIssuesProps {
|
export interface IApplicationIssuesProps {
|
||||||
issues: ApplicationOverviewIssuesSchema[];
|
issues: ApplicationOverviewIssuesSchema[];
|
||||||
}
|
}
|
||||||
@ -85,6 +102,7 @@ const resolveIssueText = (issue: ApplicationOverviewIssuesSchema) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export const ApplicationIssues = ({ issues }: IApplicationIssuesProps) => {
|
export const ApplicationIssues = ({ issues }: IApplicationIssuesProps) => {
|
||||||
|
const { hasAccess } = useContext(AccessContext);
|
||||||
return (
|
return (
|
||||||
<ConditionallyRender
|
<ConditionallyRender
|
||||||
condition={issues.length > 0}
|
condition={issues.length > 0}
|
||||||
@ -100,12 +118,44 @@ export const ApplicationIssues = ({ issues }: IApplicationIssuesProps) => {
|
|||||||
<IssueContainer>
|
<IssueContainer>
|
||||||
{issues.map((issue) => (
|
{issues.map((issue) => (
|
||||||
<IssueTextContainer key={issue.type}>
|
<IssueTextContainer key={issue.type}>
|
||||||
<SmallText>{resolveIssueText(issue)}</SmallText>
|
{resolveIssueText(issue)}
|
||||||
<StyledList>
|
<StyledList>
|
||||||
{issue.items.map((item) => (
|
{issue.items.map((item) => (
|
||||||
<StyledListElement key={item}>
|
<IssueRowContainer key={item}>
|
||||||
{item}
|
<StyledListElement>
|
||||||
</StyledListElement>
|
{item}
|
||||||
|
</StyledListElement>
|
||||||
|
<ConditionallyRender
|
||||||
|
condition={
|
||||||
|
issue.type ===
|
||||||
|
'missingFeatures' &&
|
||||||
|
hasAccess(CREATE_FEATURE)
|
||||||
|
}
|
||||||
|
show={
|
||||||
|
<StyledLink
|
||||||
|
key={item}
|
||||||
|
to={`/projects/default/create-toggle?name=${item}`}
|
||||||
|
>
|
||||||
|
Create feature flag
|
||||||
|
</StyledLink>
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
<ConditionallyRender
|
||||||
|
condition={
|
||||||
|
issue.type ===
|
||||||
|
'missingStrategies' &&
|
||||||
|
hasAccess(CREATE_STRATEGY)
|
||||||
|
}
|
||||||
|
show={
|
||||||
|
<StyledLink
|
||||||
|
key={item}
|
||||||
|
to={`/strategies/create`}
|
||||||
|
>
|
||||||
|
Create strategy type
|
||||||
|
</StyledLink>
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
</IssueRowContainer>
|
||||||
))}
|
))}
|
||||||
</StyledList>
|
</StyledList>
|
||||||
</IssueTextContainer>
|
</IssueTextContainer>
|
||||||
|
@ -72,3 +72,48 @@ test('Display application overview without environments', async () => {
|
|||||||
await screen.findByText('my-app');
|
await screen.findByText('my-app');
|
||||||
await screen.findByText('No data available.');
|
await screen.findByText('No data available.');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('Display application with issues', async () => {
|
||||||
|
setupApi({
|
||||||
|
environments: [
|
||||||
|
{
|
||||||
|
name: 'development',
|
||||||
|
instanceCount: 999,
|
||||||
|
lastSeen: new Date().toISOString(),
|
||||||
|
sdks: ['unleash-client-node:5.5.0-beta.0'],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
issues: [
|
||||||
|
{
|
||||||
|
type: 'missingFeatures',
|
||||||
|
items: ['feature1'],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'missingStrategies',
|
||||||
|
items: ['strategy1'],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
featureCount: 1,
|
||||||
|
projects: ['default'],
|
||||||
|
});
|
||||||
|
render(
|
||||||
|
<Routes>
|
||||||
|
<Route
|
||||||
|
path={'/applications/:name'}
|
||||||
|
element={<ApplicationOverview />}
|
||||||
|
/>
|
||||||
|
</Routes>,
|
||||||
|
{
|
||||||
|
route: '/applications/my-app',
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
await screen.findByText(
|
||||||
|
'We detected 1 feature flag defined in the SDK that does not exist in Unleash',
|
||||||
|
);
|
||||||
|
await screen.findByText(
|
||||||
|
'We detected 1 strategy type defined in the SDK that does not exist in Unleash',
|
||||||
|
);
|
||||||
|
await screen.findByText('feature1');
|
||||||
|
await screen.findByText('strategy1');
|
||||||
|
});
|
||||||
|
Loading…
Reference in New Issue
Block a user