1
0
mirror of https://github.com/Unleash/unleash.git synced 2025-07-26 13:48:33 +02:00

refactor: port ApiDetails to useSWR and TS (#653)

* refactor: add missing react-test-renderer types

* refactor: make IVersionInfo match backend type

* refactor: allow falsy conditions in ConditionallyRender

* refactor: port ApiDetails to useSWR and TS

* refactor: use arrow functions

* refactor: move useUiConfig to Footer

* refactor: add component name to props type

* refactor: move ApiDetails helpers to own file

* refactor: combine ApiDetails helper components

* refactor: move ApiDetails to the Footer dir

* Revert "refactor: allow falsy conditions in ConditionallyRender"

This reverts commit 70d75951eb4d0611e80b015a97243404618493ed.

* refactor: use booleans for ConditionallyRender

* refactor: use a subdir for ApiDetails

* refactor: fix ApiDetails helpers filename

* refactor: reformat using correct prettier settings
This commit is contained in:
olav 2022-02-02 12:32:30 +01:00 committed by GitHub
parent 23c6c0cd8f
commit 74733e5b44
13 changed files with 191 additions and 132 deletions

View File

@ -52,6 +52,7 @@
"@types/react": "17.0.38",
"@types/react-dom": "17.0.11",
"@types/react-router-dom": "5.3.3",
"@types/react-test-renderer": "^17.0.1",
"@types/react-timeago": "4.1.3",
"@welldone-software/why-did-you-render": "6.2.3",
"array-move": "3.0.1",

View File

@ -1,38 +0,0 @@
import React from 'react';
import ShowApiDetailsComponent from '../show-api-details-component';
import renderer from 'react-test-renderer';
test('renders correctly with empty version', () => {
const uiConfig = {
name: 'Unleash',
slogan: 'We are the best!',
environment: 'test',
version: '',
};
const tree = renderer.create(<ShowApiDetailsComponent uiConfig={uiConfig} />).toJSON();
expect(tree).toMatchSnapshot();
});
test('renders correctly with ui-config', () => {
const uiConfig = {
name: 'Unleash',
slogan: 'We are the best!',
environment: 'test',
version: '1.1.0',
};
const tree = renderer.create(<ShowApiDetailsComponent uiConfig={uiConfig} />).toJSON();
expect(tree).toMatchSnapshot();
});
test('renders correctly without uiConfig', () => {
const uiConfig = {
name: 'Unleash',
version: '1.1.0',
};
const tree = renderer.create(<ShowApiDetailsComponent uiConfig={uiConfig} />).toJSON();
expect(tree).toMatchSnapshot();
});

View File

@ -1,45 +0,0 @@
import React, { Component } from 'react';
import PropTypes from 'prop-types';
import ConditionallyRender from '../common/ConditionallyRender/ConditionallyRender';
class ShowApiDetailsComponent extends Component {
static propTypes = {
uiConfig: PropTypes.object.isRequired,
};
render() {
const { slogan, environment, version, versionInfo, name } = this.props.uiConfig;
let versionStr;
let updateNotification;
let instanceId;
if (versionInfo) {
if (versionInfo.current.enterprise) {
versionStr = `${name} ${versionInfo.current.enterprise}`;
if (Object.keys(versionInfo.latest).includes('enterprise') && !versionInfo.isLatest) {
updateNotification = `Upgrade available - Latest Enterprise release: ${versionInfo.latest.enterprise}`;
}
} else {
versionStr = `${name} ${versionInfo.current.oss}`;
if (Object.keys(versionInfo.latest).includes('oss') && !versionInfo.isLatest) {
updateNotification = `Upgrade available - Latest OSS release: ${versionInfo.latest.oss}`;
}
}
instanceId = versionInfo.instanceId;
} else {
versionStr = `${name} ${version}`;
}
return (
<section title="API details">
<h4>{`${versionStr}`} <ConditionallyRender condition={environment} show={<small>({environment})</small>} /></h4>
<ConditionallyRender condition={updateNotification} show={<small>{updateNotification}<br /></small>} />
<br />
<small>{slogan}</small>
<br />
<ConditionallyRender condition={instanceId} show={<small>{`${instanceId}`}</small>} />
</section>
);
}
}
export default ShowApiDetailsComponent;

View File

@ -1,10 +0,0 @@
import { connect } from 'react-redux';
import ShowApiDetailsComponent from './show-api-details-component';
const mapDispatchToProps = {};
const mapStateToProps = state => ({
uiConfig: state.uiConfig.toJS(),
});
export default connect(mapStateToProps, mapDispatchToProps)(ShowApiDetailsComponent);

View File

@ -0,0 +1,46 @@
import { ReactElement } from 'react';
import ConditionallyRender from '../../../common/ConditionallyRender';
import {
formatCurrentVersion,
formatUpdateNotification,
IPartialUiConfig,
} from './apidetails.helpers';
interface IApiDetailsProps {
uiConfig: IPartialUiConfig;
}
export const ApiDetails = (props: IApiDetailsProps): ReactElement => {
const instanceId = props.uiConfig.versionInfo?.instanceId;
const currentVersion = formatCurrentVersion(props.uiConfig);
const environment = props.uiConfig.environment;
const updateNotification = formatUpdateNotification(props.uiConfig);
return (
<section title="API details">
<h4>
{currentVersion}{' '}
<ConditionallyRender
condition={Boolean(environment)}
show={<small>({environment})</small>}
/>
</h4>
<ConditionallyRender
condition={Boolean(updateNotification)}
show={
<small>
{updateNotification}
<br />
</small>
}
/>
<br />
<small>{props.uiConfig.slogan}</small>
<br />
<ConditionallyRender
condition={Boolean(instanceId)}
show={<small>{`${instanceId}`}</small>}
/>
</section>
);
};

View File

@ -0,0 +1,38 @@
import { IVersionInfo } from '../../../../interfaces/uiConfig';
export interface IPartialUiConfig {
name: string;
version: string;
slogan?: string;
environment?: string;
versionInfo?: IVersionInfo;
}
export const formatCurrentVersion = (uiConfig: IPartialUiConfig): string => {
const current = uiConfig.versionInfo?.current;
if (current?.enterprise) {
return `${uiConfig.name} ${current.enterprise}`;
}
if (current?.oss) {
return `${uiConfig.name} ${current.oss}`;
}
return `${uiConfig.name} ${uiConfig.version}`;
};
export const formatUpdateNotification = (
uiConfig: IPartialUiConfig
): string | undefined => {
const latest = uiConfig.versionInfo?.latest;
const isLatest = uiConfig.versionInfo?.isLatest;
if (latest?.enterprise && !isLatest) {
return `Upgrade available - Latest Enterprise release: ${latest.enterprise}`;
}
if (latest?.oss && !isLatest) {
return `Upgrade available - Latest OSS release: ${latest.oss}`;
}
};

View File

@ -1,19 +1,19 @@
/* eslint-disable react/jsx-no-target-blank */
import { List, ListItem, ListItemText, Grid } from '@material-ui/core';
import ShowApiDetailsContainer from '../../api/show-api-details-container';
import useUiConfig from '../../../hooks/api/getters/useUiConfig/useUiConfig';
import { ApiDetails } from './ApiDetails/ApiDetails';
import { useStyles } from './Footer.styles';
export const Footer = () => {
const styles = useStyles();
const { uiConfig } = useUiConfig();
return (
<footer className={styles.footer}>
<Grid container justifyContent="center" spacing={10} style={{marginBottom: 0}}>
<Grid item md={4} xs={12}>
<ShowApiDetailsContainer />
<ApiDetails uiConfig={uiConfig} />
</Grid>
<Grid item xs={12} md="auto">
<Grid container spacing={7} direction="row">

View File

@ -42,6 +42,27 @@ exports[`renders correctly with ui-config 1`] = `
</section>
`;
exports[`renders correctly with versionInfo 1`] = `
<section
title="API details"
>
<h4>
Unleash 1.2.3
</h4>
<small>
Upgrade available - Latest Enterprise release: 1.2.4
<br />
</small>
<br />
<small />
<br />
<small>
1
</small>
</section>
`;
exports[`renders correctly without uiConfig 1`] = `
<section
title="API details"

View File

@ -19,11 +19,13 @@ exports[`should render DrawerMenu 1`] = `
title="API details"
>
<h4>
undefined undefined
Unleash 3.x
</h4>
<br />
<small />
<small>
The enterprise ready feature toggle service.
</small>
<br />
</section>
</div>
@ -445,11 +447,13 @@ exports[`should render DrawerMenu with "features" selected 1`] = `
title="API details"
>
<h4>
undefined undefined
Unleash 3.x
</h4>
<br />
<small />
<small>
The enterprise ready feature toggle service.
</small>
<br />
</section>
</div>

View File

@ -0,0 +1,53 @@
import React from 'react';
import renderer from 'react-test-renderer';
import { ApiDetails } from '../Footer/ApiDetails/ApiDetails';
test('renders correctly with empty version', () => {
const uiConfig = {
name: 'Unleash',
slogan: 'We are the best!',
environment: 'test',
version: '',
};
const tree = renderer.create(<ApiDetails uiConfig={uiConfig} />).toJSON();
expect(tree).toMatchSnapshot();
});
test('renders correctly with ui-config', () => {
const uiConfig = {
name: 'Unleash',
slogan: 'We are the best!',
environment: 'test',
version: '1.1.0',
};
const tree = renderer.create(<ApiDetails uiConfig={uiConfig} />).toJSON();
expect(tree).toMatchSnapshot();
});
test('renders correctly without uiConfig', () => {
const uiConfig = {
name: 'Unleash',
version: '1.1.0',
};
const tree = renderer.create(<ApiDetails uiConfig={uiConfig} />).toJSON();
expect(tree).toMatchSnapshot();
});
test('renders correctly with versionInfo', () => {
const uiConfig = {
name: 'Unleash',
version: '1.2.3',
versionInfo: {
instanceId: '1',
isLatest: false,
current: { enterprise: '1.2.3', oss: '1.2.3' },
latest: { enterprise: '1.2.4', oss: '1.2.4' },
},
};
const tree = renderer.create(<ApiDetails uiConfig={uiConfig} />).toJSON();
expect(tree).toMatchSnapshot();
});

View File

@ -2,33 +2,17 @@ import React from 'react';
import renderer from 'react-test-renderer';
import { MemoryRouter } from 'react-router-dom';
import { ThemeProvider } from '@material-ui/core';
import { Provider } from 'react-redux';
import { createStore } from 'redux';
import Footer from '../Footer/Footer';
import theme from '../../../themes/main-theme';
const mockStore = {
uiConfig: {
toJS: () => ({
flags: {
P: true,
},
}),
},
};
const mockReducer = state => state;
test('should render DrawerMenu', () => {
const tree = renderer.create(
<Provider store={createStore(mockReducer, mockStore)}>
<ThemeProvider theme={theme}>
<MemoryRouter>
<Footer />
</MemoryRouter>
</ThemeProvider>
</Provider>
<ThemeProvider theme={theme}>
<MemoryRouter>
<Footer />
</MemoryRouter>
</ThemeProvider>
);
expect(tree).toMatchSnapshot();
@ -36,13 +20,11 @@ test('should render DrawerMenu', () => {
test('should render DrawerMenu with "features" selected', () => {
const tree = renderer.create(
<Provider store={createStore(mockReducer, mockStore)}>
<ThemeProvider theme={theme}>
<MemoryRouter initialEntries={['/features']}>
<Footer />
</MemoryRouter>
</ThemeProvider>
</Provider>
<ThemeProvider theme={theme}>
<MemoryRouter initialEntries={['/features']}>
<Footer />
</MemoryRouter>
</ThemeProvider>
);
expect(tree).toMatchSnapshot();

View File

@ -19,11 +19,11 @@ export interface IFlags {
export interface IVersionInfo {
instanceId: string;
isLatest: boolean;
latest: Object;
current: ICurrent;
latest: Partial<IVersion>;
current: IVersion;
}
export interface ICurrent {
export interface IVersion {
oss: string;
enterprise: string;
}

View File

@ -2186,6 +2186,13 @@
"@types/history" "*"
"@types/react" "*"
"@types/react-test-renderer@^17.0.1":
version "17.0.1"
resolved "https://registry.yarnpkg.com/@types/react-test-renderer/-/react-test-renderer-17.0.1.tgz#3120f7d1c157fba9df0118dae20cb0297ee0e06b"
integrity sha512-3Fi2O6Zzq/f3QR9dRnlnHso9bMl7weKCviFmfF6B4LS1Uat6Hkm15k0ZAQuDz+UBq6B3+g+NM6IT2nr5QgPzCw==
dependencies:
"@types/react" "*"
"@types/react-timeago@4.1.3":
version "4.1.3"
resolved "https://registry.npmjs.org/@types/react-timeago/-/react-timeago-4.1.3.tgz"