forked from sombochea/verdaccio-ui
feat: version Component - Replaced classes by func. comp (#129)
* refactor: replaced classes by func comp * fix: fixed space margin * refactor: changed display logic * fix: fixed types * fix: fixed Version test * fix: fixed version style
This commit is contained in:
parent
1a74c08b5d
commit
1d705da38c
@ -1,48 +1,39 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { mount } from 'enzyme';
|
import { mount } from 'enzyme';
|
||||||
import { MemoryRouter } from 'react-router';
|
import { MemoryRouter } from 'react-router';
|
||||||
|
import { DetailContext, DetailContextProps } from '../../pages/Version';
|
||||||
|
|
||||||
import Versions, { LABEL_CURRENT_TAGS, LABEL_VERSION_HISTORY } from './Versions';
|
import Versions, { LABEL_CURRENT_TAGS, LABEL_VERSION_HISTORY } from './Versions';
|
||||||
import data from './__partials__/data.json';
|
import data from './__partials__/data.json';
|
||||||
|
|
||||||
import { render, cleanup } from '@testing-library/react';
|
import { render, cleanup } from '@testing-library/react';
|
||||||
|
|
||||||
const mockPackageMeta = jest.fn(() => ({
|
const detailContextValue: Partial<DetailContextProps> = {
|
||||||
packageName: 'foo',
|
packageName: 'foo',
|
||||||
packageMeta: data,
|
packageMeta: data,
|
||||||
}));
|
};
|
||||||
|
|
||||||
jest.mock('../../pages/Version', () => ({
|
const ComponentToBeRendered: React.FC<{ contextValue: Partial<DetailContextProps> }> = ({ contextValue }) => (
|
||||||
DetailContextConsumer: component => {
|
<MemoryRouter>
|
||||||
return component.children({ ...mockPackageMeta() });
|
<DetailContext.Provider value={contextValue}>
|
||||||
},
|
<Versions />
|
||||||
}));
|
</DetailContext.Provider>
|
||||||
|
</MemoryRouter>
|
||||||
|
);
|
||||||
|
|
||||||
describe('<Version /> component', () => {
|
describe('<Version /> component', () => {
|
||||||
beforeEach(() => {
|
|
||||||
jest.resetModules();
|
|
||||||
});
|
|
||||||
|
|
||||||
afterEach(() => {
|
afterEach(() => {
|
||||||
cleanup();
|
cleanup();
|
||||||
});
|
});
|
||||||
|
|
||||||
// FIXME: this test is not deterministic (writes `N days ago` in the snapshot, where N is random number)
|
// FIXME: this test is not deterministic (writes `N days ago` in the snapshot, where N is random number)
|
||||||
test.skip('should render the component in default state', () => {
|
test.skip('should render the component in default state', () => {
|
||||||
const wrapper = mount(
|
const wrapper = mount(<ComponentToBeRendered contextValue={detailContextValue} />);
|
||||||
<MemoryRouter>
|
|
||||||
<Versions />
|
|
||||||
</MemoryRouter>
|
|
||||||
);
|
|
||||||
expect(wrapper.html()).toMatchSnapshot();
|
expect(wrapper.html()).toMatchSnapshot();
|
||||||
});
|
});
|
||||||
|
|
||||||
test('should render versions', () => {
|
test('should render versions', () => {
|
||||||
const { getByText } = render(
|
const { getByText } = render(<ComponentToBeRendered contextValue={detailContextValue} />);
|
||||||
<MemoryRouter>
|
|
||||||
<Versions />
|
|
||||||
</MemoryRouter>
|
|
||||||
);
|
|
||||||
|
|
||||||
expect(getByText(LABEL_VERSION_HISTORY)).toBeTruthy();
|
expect(getByText(LABEL_VERSION_HISTORY)).toBeTruthy();
|
||||||
expect(getByText(LABEL_CURRENT_TAGS)).toBeTruthy();
|
expect(getByText(LABEL_CURRENT_TAGS)).toBeTruthy();
|
||||||
@ -53,18 +44,7 @@ describe('<Version /> component', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
test('should not render versions', () => {
|
test('should not render versions', () => {
|
||||||
const request = {
|
const { queryByText } = render(<ComponentToBeRendered contextValue={{ packageName: detailContextValue.packageName }} />);
|
||||||
packageName: 'foo',
|
|
||||||
};
|
|
||||||
|
|
||||||
// @ts-ignore
|
|
||||||
mockPackageMeta.mockImplementation(() => request);
|
|
||||||
|
|
||||||
const { queryByText } = render(
|
|
||||||
<MemoryRouter>
|
|
||||||
<Versions />
|
|
||||||
</MemoryRouter>
|
|
||||||
);
|
|
||||||
|
|
||||||
expect(queryByText(LABEL_VERSION_HISTORY)).toBeFalsy();
|
expect(queryByText(LABEL_VERSION_HISTORY)).toBeFalsy();
|
||||||
expect(queryByText(LABEL_CURRENT_TAGS)).toBeFalsy();
|
expect(queryByText(LABEL_CURRENT_TAGS)).toBeFalsy();
|
||||||
|
@ -1,90 +1,46 @@
|
|||||||
import React, { ReactElement } from 'react';
|
import React, { useContext } from 'react';
|
||||||
import List from '@material-ui/core/List';
|
|
||||||
import { Link as RouterLink } from 'react-router-dom';
|
import { DetailContext } from '../../pages/Version';
|
||||||
import Link from '@material-ui/core/Link';
|
|
||||||
import ListItem from '@material-ui/core/ListItem';
|
import { Heading } from './styles';
|
||||||
|
|
||||||
|
import VersionsTagList from './VersionsTagList';
|
||||||
|
import VersionsHistoryList from './VersionsHistoryList';
|
||||||
|
|
||||||
import { DetailContextConsumer } from '../../pages/Version';
|
|
||||||
import { formatDateDistance } from '../../utils/package';
|
|
||||||
import { DIST_TAGS } from '../../../lib/constants';
|
import { DIST_TAGS } from '../../../lib/constants';
|
||||||
|
|
||||||
import { Heading, Spacer, ListItemText } from './styles';
|
|
||||||
|
|
||||||
export const NOT_AVAILABLE = 'Not available';
|
export const NOT_AVAILABLE = 'Not available';
|
||||||
export const LABEL_CURRENT_TAGS = 'Current Tags';
|
export const LABEL_CURRENT_TAGS = 'Current Tags';
|
||||||
export const LABEL_VERSION_HISTORY = 'Version History';
|
export const LABEL_VERSION_HISTORY = 'Version History';
|
||||||
|
|
||||||
class Versions extends React.PureComponent {
|
const Versions: React.FC = () => {
|
||||||
public render(): ReactElement<HTMLDivElement> {
|
const detailContext = useContext(DetailContext);
|
||||||
return (
|
|
||||||
<DetailContextConsumer>
|
const { packageMeta, packageName } = detailContext;
|
||||||
{context => {
|
|
||||||
const { packageMeta, packageName } = context;
|
|
||||||
|
|
||||||
if (!packageMeta) {
|
if (!packageMeta) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
return this.renderContent(packageMeta, packageName);
|
// @ts-ignore - Property 'dist-tags' does not exist on type 'PackageMetaInterface'
|
||||||
}}
|
const { versions = {}, time = {}, [DIST_TAGS]: distTags = {} } = packageMeta;
|
||||||
</DetailContextConsumer>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
public renderPackageList = (packages: {}, timeMap: Record<string, {}>, packageName): ReactElement<HTMLDivElement> => {
|
|
||||||
return (
|
|
||||||
<List dense={true}>
|
|
||||||
{Object.keys(packages)
|
|
||||||
.reverse()
|
|
||||||
.map(version => (
|
|
||||||
<ListItem className="version-item" key={version}>
|
|
||||||
<Link component={RouterLink} to={`/-/web/detail/${packageName}/v/${version}`}>
|
|
||||||
<ListItemText>{version}</ListItemText>
|
|
||||||
</Link>
|
|
||||||
<Spacer />
|
|
||||||
<ListItemText>{timeMap[version] ? `${formatDateDistance(timeMap[version])} ago` : NOT_AVAILABLE}</ListItemText>
|
|
||||||
</ListItem>
|
|
||||||
))}
|
|
||||||
</List>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
public renderTagList = (packages: {}): ReactElement<HTMLDivElement> => {
|
|
||||||
return (
|
|
||||||
<List dense={true}>
|
|
||||||
{Object.keys(packages)
|
|
||||||
.reverse()
|
|
||||||
.map(tag => (
|
|
||||||
<ListItem className="version-item" key={tag}>
|
|
||||||
<ListItemText>{tag}</ListItemText>
|
|
||||||
<Spacer />
|
|
||||||
<ListItemText>{packages[tag]}</ListItemText>
|
|
||||||
</ListItem>
|
|
||||||
))}
|
|
||||||
</List>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
public renderContent(packageMeta, packageName): ReactElement<HTMLDivElement> {
|
|
||||||
const { versions = {}, time: timeMap = {}, [DIST_TAGS]: distTags = {} } = packageMeta;
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
{distTags && (
|
{distTags && Object.keys(distTags).length > 0 && (
|
||||||
<>
|
<>
|
||||||
<Heading variant="subtitle1">{LABEL_CURRENT_TAGS}</Heading>
|
<Heading variant="subtitle1">{LABEL_CURRENT_TAGS}</Heading>
|
||||||
{this.renderTagList(distTags)}
|
<VersionsTagList tags={distTags} />
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
{versions && (
|
{versions && Object.keys(versions).length > 0 && packageName && (
|
||||||
<>
|
<>
|
||||||
<Heading variant="subtitle1">{LABEL_VERSION_HISTORY}</Heading>
|
<Heading variant="subtitle1">{LABEL_VERSION_HISTORY}</Heading>
|
||||||
{this.renderPackageList(versions, timeMap, packageName)}
|
<VersionsHistoryList packageName={packageName} time={time} versions={versions} />
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
}
|
};
|
||||||
}
|
|
||||||
|
|
||||||
export default Versions;
|
export default Versions;
|
||||||
|
35
src/components/Versions/VersionsHistoryList.tsx
Normal file
35
src/components/Versions/VersionsHistoryList.tsx
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import List from '@material-ui/core/List';
|
||||||
|
import Link from '@material-ui/core/Link';
|
||||||
|
import ListItem from '@material-ui/core/ListItem';
|
||||||
|
import { Link as RouterLink } from 'react-router-dom';
|
||||||
|
import { Spacer, ListItemText } from './styles';
|
||||||
|
|
||||||
|
import { Versions, Time } from '../../../types/packageMeta';
|
||||||
|
import { formatDateDistance } from '../../utils/package';
|
||||||
|
|
||||||
|
export const NOT_AVAILABLE = 'Not available';
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
versions: Versions;
|
||||||
|
packageName: string;
|
||||||
|
time: Time;
|
||||||
|
}
|
||||||
|
|
||||||
|
const VersionsHistoryList: React.FC<Props> = ({ versions, packageName, time }) => (
|
||||||
|
<List dense={true}>
|
||||||
|
{Object.keys(versions)
|
||||||
|
.reverse()
|
||||||
|
.map(version => (
|
||||||
|
<ListItem className="version-item" key={version}>
|
||||||
|
<Link component={RouterLink} to={`/-/web/detail/${packageName}/v/${version}`}>
|
||||||
|
<ListItemText>{version}</ListItemText>
|
||||||
|
</Link>
|
||||||
|
<Spacer />
|
||||||
|
<ListItemText>{time[version] ? `${formatDateDistance(time[version])} ago` : NOT_AVAILABLE}</ListItemText>
|
||||||
|
</ListItem>
|
||||||
|
))}
|
||||||
|
</List>
|
||||||
|
);
|
||||||
|
|
||||||
|
export default VersionsHistoryList;
|
26
src/components/Versions/VersionsTagList.tsx
Normal file
26
src/components/Versions/VersionsTagList.tsx
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import List from '@material-ui/core/List';
|
||||||
|
import ListItem from '@material-ui/core/ListItem';
|
||||||
|
import { Spacer, ListItemText } from './styles';
|
||||||
|
|
||||||
|
import { DistTags } from '../../../types/packageMeta';
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
tags: DistTags;
|
||||||
|
}
|
||||||
|
|
||||||
|
const VersionsTagList: React.FC<Props> = ({ tags }) => (
|
||||||
|
<List dense={true}>
|
||||||
|
{Object.keys(tags)
|
||||||
|
.reverse()
|
||||||
|
.map(tag => (
|
||||||
|
<ListItem className="version-item" key={tag}>
|
||||||
|
<ListItemText>{tag}</ListItemText>
|
||||||
|
<Spacer />
|
||||||
|
<ListItemText>{tags[tag]}</ListItemText>
|
||||||
|
</ListItem>
|
||||||
|
))}
|
||||||
|
</List>
|
||||||
|
);
|
||||||
|
|
||||||
|
export default VersionsTagList;
|
File diff suppressed because one or more lines are too long
@ -14,6 +14,7 @@ export const Spacer = styled('div')({
|
|||||||
borderBottom: '1px dotted rgba(0, 0, 0, 0.2)',
|
borderBottom: '1px dotted rgba(0, 0, 0, 0.2)',
|
||||||
whiteSpace: 'nowrap',
|
whiteSpace: 'nowrap',
|
||||||
height: '0.5em',
|
height: '0.5em',
|
||||||
|
margin: '0 16px',
|
||||||
});
|
});
|
||||||
|
|
||||||
export const ListItemText = styled(MuiListItemText)({
|
export const ListItemText = styled(MuiListItemText)({
|
||||||
|
@ -1,4 +1,7 @@
|
|||||||
export interface PackageMetaInterface {
|
export interface PackageMetaInterface {
|
||||||
|
versions?: Versions;
|
||||||
|
distTags?: DistTags;
|
||||||
|
time?: Time;
|
||||||
latest: {
|
latest: {
|
||||||
name: string;
|
name: string;
|
||||||
dist: {
|
dist: {
|
||||||
@ -14,3 +17,37 @@ interface LicenseInterface {
|
|||||||
type: string;
|
type: string;
|
||||||
url: string;
|
url: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface DistTags {
|
||||||
|
[key: string]: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface Time {
|
||||||
|
[key: string]: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface Versions {
|
||||||
|
[key: string]: Version;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface Version {
|
||||||
|
name: string;
|
||||||
|
version: string;
|
||||||
|
author?: string | Author;
|
||||||
|
maintainers?: Maintainer[];
|
||||||
|
description?: string;
|
||||||
|
license?: string;
|
||||||
|
main?: string;
|
||||||
|
keywords?: string[];
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Author {
|
||||||
|
name?: string;
|
||||||
|
email?: string;
|
||||||
|
url?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Maintainer {
|
||||||
|
email?: string;
|
||||||
|
name?: string;
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user