mirror of
https://github.com/Unleash/unleash.git
synced 2025-07-31 13:47:02 +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:
parent
23c6c0cd8f
commit
74733e5b44
@ -52,6 +52,7 @@
|
|||||||
"@types/react": "17.0.38",
|
"@types/react": "17.0.38",
|
||||||
"@types/react-dom": "17.0.11",
|
"@types/react-dom": "17.0.11",
|
||||||
"@types/react-router-dom": "5.3.3",
|
"@types/react-router-dom": "5.3.3",
|
||||||
|
"@types/react-test-renderer": "^17.0.1",
|
||||||
"@types/react-timeago": "4.1.3",
|
"@types/react-timeago": "4.1.3",
|
||||||
"@welldone-software/why-did-you-render": "6.2.3",
|
"@welldone-software/why-did-you-render": "6.2.3",
|
||||||
"array-move": "3.0.1",
|
"array-move": "3.0.1",
|
||||||
|
@ -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();
|
|
||||||
});
|
|
@ -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;
|
|
@ -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);
|
|
46
frontend/src/component/menu/Footer/ApiDetails/ApiDetails.tsx
Normal file
46
frontend/src/component/menu/Footer/ApiDetails/ApiDetails.tsx
Normal 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>
|
||||||
|
);
|
||||||
|
};
|
@ -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}`;
|
||||||
|
}
|
||||||
|
};
|
@ -1,19 +1,19 @@
|
|||||||
/* eslint-disable react/jsx-no-target-blank */
|
/* eslint-disable react/jsx-no-target-blank */
|
||||||
|
|
||||||
import { List, ListItem, ListItemText, Grid } from '@material-ui/core';
|
import { List, ListItem, ListItemText, Grid } from '@material-ui/core';
|
||||||
|
import useUiConfig from '../../../hooks/api/getters/useUiConfig/useUiConfig';
|
||||||
import ShowApiDetailsContainer from '../../api/show-api-details-container';
|
import { ApiDetails } from './ApiDetails/ApiDetails';
|
||||||
|
|
||||||
import { useStyles } from './Footer.styles';
|
import { useStyles } from './Footer.styles';
|
||||||
|
|
||||||
export const Footer = () => {
|
export const Footer = () => {
|
||||||
const styles = useStyles();
|
const styles = useStyles();
|
||||||
|
const { uiConfig } = useUiConfig();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<footer className={styles.footer}>
|
<footer className={styles.footer}>
|
||||||
<Grid container justifyContent="center" spacing={10} style={{marginBottom: 0}}>
|
<Grid container justifyContent="center" spacing={10} style={{marginBottom: 0}}>
|
||||||
<Grid item md={4} xs={12}>
|
<Grid item md={4} xs={12}>
|
||||||
<ShowApiDetailsContainer />
|
<ApiDetails uiConfig={uiConfig} />
|
||||||
</Grid>
|
</Grid>
|
||||||
<Grid item xs={12} md="auto">
|
<Grid item xs={12} md="auto">
|
||||||
<Grid container spacing={7} direction="row">
|
<Grid container spacing={7} direction="row">
|
||||||
|
@ -42,6 +42,27 @@ exports[`renders correctly with ui-config 1`] = `
|
|||||||
</section>
|
</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`] = `
|
exports[`renders correctly without uiConfig 1`] = `
|
||||||
<section
|
<section
|
||||||
title="API details"
|
title="API details"
|
@ -19,11 +19,13 @@ exports[`should render DrawerMenu 1`] = `
|
|||||||
title="API details"
|
title="API details"
|
||||||
>
|
>
|
||||||
<h4>
|
<h4>
|
||||||
undefined undefined
|
Unleash 3.x
|
||||||
|
|
||||||
</h4>
|
</h4>
|
||||||
<br />
|
<br />
|
||||||
<small />
|
<small>
|
||||||
|
The enterprise ready feature toggle service.
|
||||||
|
</small>
|
||||||
<br />
|
<br />
|
||||||
</section>
|
</section>
|
||||||
</div>
|
</div>
|
||||||
@ -445,11 +447,13 @@ exports[`should render DrawerMenu with "features" selected 1`] = `
|
|||||||
title="API details"
|
title="API details"
|
||||||
>
|
>
|
||||||
<h4>
|
<h4>
|
||||||
undefined undefined
|
Unleash 3.x
|
||||||
|
|
||||||
</h4>
|
</h4>
|
||||||
<br />
|
<br />
|
||||||
<small />
|
<small>
|
||||||
|
The enterprise ready feature toggle service.
|
||||||
|
</small>
|
||||||
<br />
|
<br />
|
||||||
</section>
|
</section>
|
||||||
</div>
|
</div>
|
||||||
|
53
frontend/src/component/menu/__tests__/apidetails.test.tsx
Normal file
53
frontend/src/component/menu/__tests__/apidetails.test.tsx
Normal 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();
|
||||||
|
});
|
@ -2,33 +2,17 @@ import React from 'react';
|
|||||||
import renderer from 'react-test-renderer';
|
import renderer from 'react-test-renderer';
|
||||||
import { MemoryRouter } from 'react-router-dom';
|
import { MemoryRouter } from 'react-router-dom';
|
||||||
import { ThemeProvider } from '@material-ui/core';
|
import { ThemeProvider } from '@material-ui/core';
|
||||||
import { Provider } from 'react-redux';
|
|
||||||
import { createStore } from 'redux';
|
|
||||||
|
|
||||||
import Footer from '../Footer/Footer';
|
import Footer from '../Footer/Footer';
|
||||||
import theme from '../../../themes/main-theme';
|
import theme from '../../../themes/main-theme';
|
||||||
|
|
||||||
const mockStore = {
|
|
||||||
uiConfig: {
|
|
||||||
toJS: () => ({
|
|
||||||
flags: {
|
|
||||||
P: true,
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
const mockReducer = state => state;
|
|
||||||
|
|
||||||
test('should render DrawerMenu', () => {
|
test('should render DrawerMenu', () => {
|
||||||
const tree = renderer.create(
|
const tree = renderer.create(
|
||||||
<Provider store={createStore(mockReducer, mockStore)}>
|
<ThemeProvider theme={theme}>
|
||||||
<ThemeProvider theme={theme}>
|
<MemoryRouter>
|
||||||
<MemoryRouter>
|
<Footer />
|
||||||
<Footer />
|
</MemoryRouter>
|
||||||
</MemoryRouter>
|
</ThemeProvider>
|
||||||
</ThemeProvider>
|
|
||||||
</Provider>
|
|
||||||
);
|
);
|
||||||
|
|
||||||
expect(tree).toMatchSnapshot();
|
expect(tree).toMatchSnapshot();
|
||||||
@ -36,13 +20,11 @@ test('should render DrawerMenu', () => {
|
|||||||
|
|
||||||
test('should render DrawerMenu with "features" selected', () => {
|
test('should render DrawerMenu with "features" selected', () => {
|
||||||
const tree = renderer.create(
|
const tree = renderer.create(
|
||||||
<Provider store={createStore(mockReducer, mockStore)}>
|
<ThemeProvider theme={theme}>
|
||||||
<ThemeProvider theme={theme}>
|
<MemoryRouter initialEntries={['/features']}>
|
||||||
<MemoryRouter initialEntries={['/features']}>
|
<Footer />
|
||||||
<Footer />
|
</MemoryRouter>
|
||||||
</MemoryRouter>
|
</ThemeProvider>
|
||||||
</ThemeProvider>
|
|
||||||
</Provider>
|
|
||||||
);
|
);
|
||||||
|
|
||||||
expect(tree).toMatchSnapshot();
|
expect(tree).toMatchSnapshot();
|
||||||
|
@ -19,11 +19,11 @@ export interface IFlags {
|
|||||||
export interface IVersionInfo {
|
export interface IVersionInfo {
|
||||||
instanceId: string;
|
instanceId: string;
|
||||||
isLatest: boolean;
|
isLatest: boolean;
|
||||||
latest: Object;
|
latest: Partial<IVersion>;
|
||||||
current: ICurrent;
|
current: IVersion;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ICurrent {
|
export interface IVersion {
|
||||||
oss: string;
|
oss: string;
|
||||||
enterprise: string;
|
enterprise: string;
|
||||||
}
|
}
|
||||||
|
@ -2186,6 +2186,13 @@
|
|||||||
"@types/history" "*"
|
"@types/history" "*"
|
||||||
"@types/react" "*"
|
"@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":
|
"@types/react-timeago@4.1.3":
|
||||||
version "4.1.3"
|
version "4.1.3"
|
||||||
resolved "https://registry.npmjs.org/@types/react-timeago/-/react-timeago-4.1.3.tgz"
|
resolved "https://registry.npmjs.org/@types/react-timeago/-/react-timeago-4.1.3.tgz"
|
||||||
|
Loading…
Reference in New Issue
Block a user