mirror of
https://github.com/verdaccio/verdaccio.git
synced 2025-01-06 22:40:26 -05:00
refactor: package list [WIP]
This commit is contained in:
parent
c518b94978
commit
aec337719e
11 changed files with 158 additions and 50 deletions
|
@ -7,6 +7,8 @@ import _ from 'lodash';
|
|||
import { addScope, addGravatarSupport, deleteProperties, sortByName, parseReadme } from '../../../lib/utils';
|
||||
import { allow } from '../../middleware';
|
||||
import { DIST_TAGS, HEADER_TYPE, HEADERS, HTTP_STATUS } from '../../../lib/constants';
|
||||
import { generateGravatarUrl } from '../../../utils/user';
|
||||
import { formatAuthor } from '../../../webui/utils/package';
|
||||
import logger from '../../../lib/logger';
|
||||
import type { Router } from 'express';
|
||||
import type { IAuth, $ResponseExtend, $RequestExtend, $NextFunctionVer, IStorageHandler, $SidebarPackage } from '../../../../types';
|
||||
|
@ -41,12 +43,18 @@ function addPackageWebApi(route: Router, storage: IStorageHandler, auth: IAuth,
|
|||
throw err;
|
||||
}
|
||||
|
||||
async function processPermissionsPackages(packages) {
|
||||
async function processPermissionsPackages(packages = []) {
|
||||
const permissions = [];
|
||||
for (const pkg of packages) {
|
||||
const packgesCopy = packages.slice();
|
||||
for (const pkg of packgesCopy) {
|
||||
const pkgCopy = { ...pkg };
|
||||
pkgCopy.author = formatAuthor(pkg.author);
|
||||
try {
|
||||
if (await checkAllow(pkg.name, req.remote_user)) {
|
||||
permissions.push(pkg);
|
||||
if (config.web) {
|
||||
pkgCopy.author.avatar = generateGravatarUrl(pkgCopy.author.email, config.web.gravatar);
|
||||
}
|
||||
permissions.push(pkgCopy);
|
||||
}
|
||||
} catch (err) {
|
||||
logger.logger.error({ name: pkg.name, error: err }, 'permission process for @{name} has failed: @{error}');
|
||||
|
|
3
src/webui/components/Icon/img/filebinary.svg
Normal file
3
src/webui/components/Icon/img/filebinary.svg
Normal file
|
@ -0,0 +1,3 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" id="filebinary">
|
||||
<path d="M8.5 1H1c-.55 0-1 .45-1 1v12c0 .55.45 1 1 1h10c.55 0 1-.45 1-1V4.5L8.5 1zM11 14H1V2h7l3 3v9zM5 6.98L3.5 8.5 5 10l-.5 1L2 8.5 4.5 6l.5.98zM7.5 6L10 8.5 7.5 11l-.5-.98L8.5 8.5 7 7l.5-1z"></path>
|
||||
</svg>
|
After Width: | Height: | Size: 265 B |
3
src/webui/components/Icon/img/law.svg
Normal file
3
src/webui/components/Icon/img/law.svg
Normal file
|
@ -0,0 +1,3 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" id="law">
|
||||
<path fill-rule="evenodd" d="M7 4c-.83 0-1.5-.67-1.5-1.5S6.17 1 7 1s1.5.67 1.5 1.5S7.83 4 7 4zm7 6c0 1.11-.89 2-2 2h-1c-1.11 0-2-.89-2-2l2-4h-1c-.55 0-1-.45-1-1H8v8c.42 0 1 .45 1 1h1c.42 0 1 .45 1 1H3c0-.55.58-1 1-1h1c0-.55.58-1 1-1h.03L6 5H5c0 .55-.45 1-1 1H3l2 4c0 1.11-.89 2-2 2H2c-1.11 0-2-.89-2-2l2-4H1V5h3c0-.55.45-1 1-1h4c.55 0 1 .45 1 1h3v1h-1l2 4zM2.5 7L1 10h3L2.5 7zM13 10l-1.5-3-1.5 3h3z"></path>
|
||||
</svg>
|
After Width: | Height: | Size: 464 B |
6
src/webui/components/Icon/img/version.svg
Normal file
6
src/webui/components/Icon/img/version.svg
Normal file
|
@ -0,0 +1,6 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 14 16" height="16" width="14" id="version">
|
||||
<path fill-rule="evenodd" d="M13 3H7c-.55 0-1 .45-1 1v8c0 .55.45 1 1 1h6c.55 0 1-.45 1-1V4c0-.55-.45-1-1-1zm-1 8H8V5h4v6zM4 4h1v1H4v6h1v1H4c-.55 0-1-.45-1-1V5c0-.55.45-1 1-1zM1 5h1v1H1v4h1v1H1c-.55 0-1-.45-1-1V6c0-.55.45-1 1-1z"></path>
|
||||
|
||||
</svg>
|
||||
|
||||
|
After Width: | Height: | Size: 344 B |
|
@ -20,7 +20,10 @@ import spain from './img/spain.svg';
|
|||
import earth from './img/earth.svg';
|
||||
import verdaccio from './img/verdaccio.svg';
|
||||
import license from './img/license.svg';
|
||||
import law from './img/law.svg';
|
||||
import time from './img/time.svg';
|
||||
import version from './img/version.svg';
|
||||
import filebinary from './img/filebinary.svg';
|
||||
|
||||
export const Icons: $Shape<IIconsMap> = {
|
||||
// flags
|
||||
|
@ -35,6 +38,9 @@ export const Icons: $Shape<IIconsMap> = {
|
|||
verdaccio,
|
||||
license,
|
||||
time,
|
||||
law,
|
||||
version,
|
||||
filebinary,
|
||||
};
|
||||
|
||||
const Icon = ({ className, name, size = 'sm', img = false, pointer = false, ...props }: IProps): Node => {
|
||||
|
|
|
@ -21,7 +21,7 @@ const getSize = (size: string) => {
|
|||
default:
|
||||
return `
|
||||
width: 14px;
|
||||
height: 14px;
|
||||
height: 16px;
|
||||
`;
|
||||
}
|
||||
};
|
||||
|
|
|
@ -9,15 +9,21 @@ import React from 'react';
|
|||
import type { Element } from 'react';
|
||||
import { spacing } from '../../utils/styles/mixings';
|
||||
|
||||
import Grid from '@material-ui/core/Grid';
|
||||
import List from '@material-ui/core/List';
|
||||
import ListItem from '@material-ui/core/ListItem';
|
||||
import ListItemText from '@material-ui/core/ListItemText';
|
||||
import ListItemAvatar from '@material-ui/core/ListItemAvatar';
|
||||
import Avatar2 from '@material-ui/core/Avatar';
|
||||
import Typography from '@material-ui/core/Typography';
|
||||
import Divider from '@material-ui/core/Divider';
|
||||
import IconButton from '@material-ui/core/IconButton';
|
||||
import BugReport from '@material-ui/icons/BugReport';
|
||||
import Tooltip from '@material-ui/core/Tooltip';
|
||||
import HomeIcon from '@material-ui/icons/Home';
|
||||
import BookmarkBorder from '@material-ui/icons/BookmarkBorder';
|
||||
|
||||
import Tag from '../Tag';
|
||||
import fileSizeSI from '../../utils/file-size';
|
||||
import { formatDate, formatDateDistance } from '../../utils/package';
|
||||
|
||||
import { IProps } from './types';
|
||||
|
@ -39,7 +45,9 @@ import {
|
|||
Field,
|
||||
Content,
|
||||
Footer,
|
||||
PackageName,
|
||||
} from './styles';
|
||||
import { fontWeight } from '../../utils/styles/sizes';
|
||||
|
||||
const getInitialsName = (name: string) =>
|
||||
name
|
||||
|
@ -47,36 +55,48 @@ const getInitialsName = (name: string) =>
|
|||
.reduce((accumulator, currentValue) => accumulator.charAt(0) + currentValue.charAt(0), '')
|
||||
.toUpperCase();
|
||||
|
||||
const Package = ({ name: label, version, time, author: { name, avatar }, description, license, keywords = [] }: IProps): Element<WrapperLink> => {
|
||||
const renderMainInfo = () => (
|
||||
<MainInfo>
|
||||
<Name>{label}</Name>
|
||||
<Version>{`v${version}`}</Version>
|
||||
</MainInfo>
|
||||
);
|
||||
|
||||
const renderAuthorInfo = () => (
|
||||
<Author>
|
||||
<Avatar alt={name} src={avatar}>
|
||||
{!avatar && getInitialsName(name)}
|
||||
</Avatar>
|
||||
<Details>
|
||||
<Text text={name} weight={'bold'} />
|
||||
</Details>
|
||||
</Author>
|
||||
const Package = ({ name: label, version, dist: { unpackedSize } = {}, time, author: { name, avatar }, description, license, keywords = [] }: IProps): Element<WrapperLink> => {
|
||||
console.log(unpackedSize);
|
||||
const renderVersionInfo = () => version && (
|
||||
<OverviewItem>
|
||||
<Icon name={'version'} />
|
||||
{`v${version}`}
|
||||
</OverviewItem>
|
||||
);
|
||||
|
||||
const renderAuthorInfo = () => {
|
||||
return (
|
||||
<Author>
|
||||
<Avatar alt={name} src={avatar} style={{ width: '20px', height: '20px' }} />
|
||||
<Details>
|
||||
<Text text={name} />
|
||||
</Details>
|
||||
</Author>
|
||||
);
|
||||
<<<<<<< HEAD
|
||||
};
|
||||
=======
|
||||
}
|
||||
|
||||
const renderFileSize = () => unpackedSize && (
|
||||
<OverviewItem>
|
||||
<Icon name={'filebinary'} />
|
||||
{fileSizeSI(unpackedSize)}
|
||||
</OverviewItem>
|
||||
);
|
||||
|
||||
>>>>>>> b4b8d6b0... wip
|
||||
const renderLicenseInfo = () =>
|
||||
license && (
|
||||
<OverviewItem>
|
||||
<Icon modifiers={spacing('margin', '4px', '5px', '0px', '0px')} name={'license'} pointer={true} />
|
||||
<Icon name={'law'} />
|
||||
{license}
|
||||
</OverviewItem>
|
||||
);
|
||||
|
||||
const renderPublishedInfo = () => (
|
||||
<OverviewItem>
|
||||
<Icon name={'time'} pointer={true} />
|
||||
<Icon name={'time'} />
|
||||
<Published modifiers={spacing('margin', '0px', '5px', '0px', '0px')}>{`Published on ${formatDate(time)} •`}</Published>
|
||||
{`${formatDateDistance(time)} ago`}
|
||||
</OverviewItem>
|
||||
|
@ -111,26 +131,62 @@ const Package = ({ name: label, version, time, author: { name, avatar }, descrip
|
|||
// )}
|
||||
// </WrapperLink>
|
||||
// );
|
||||
const tags = keywords.sort().map((keyword, index) => (
|
||||
<Tag style={{ color: '#485A3E' }} key={index}>
|
||||
{keyword}
|
||||
</Tag>
|
||||
));
|
||||
|
||||
return (
|
||||
<List>
|
||||
<List style={{ padding: '12px 0 12px 0'}}>
|
||||
<ListItem alignItems="flex-start">
|
||||
<ListItemAvatar>
|
||||
{/* <ListItemAvatar>
|
||||
<Avatar2 alt="Remy Sharp" src="/static/images/avatar/1.jpg" />
|
||||
</ListItemAvatar>
|
||||
<ListItemText
|
||||
primary={label}
|
||||
</ListItemAvatar> */}
|
||||
<ListItemText component="div" style={{ paddingRight: 0}}
|
||||
primary={
|
||||
<Grid item xs={12} container>
|
||||
<Grid item xs>
|
||||
<PackageName>{label}</PackageName>
|
||||
</Grid>
|
||||
<Grid item xs style={{ textAlign: "right" }}>
|
||||
<Tooltip title="Visit homepage" aria-label="Add">
|
||||
<IconButton aria-label="Report" style={{ padding: '6px' }}>
|
||||
<HomeIcon fontSize="small" style={{ fontSize: '16px' }} />
|
||||
</IconButton>
|
||||
</Tooltip>
|
||||
<Tooltip title="Open an issue" aria-label="Add">
|
||||
<IconButton aria-label="Report" style={{ padding: '6px' }}>
|
||||
<BugReport fontSize="small" style={{ fontSize: '16px' }} />
|
||||
</IconButton>
|
||||
</Tooltip>
|
||||
<Tooltip title="Pin it" aria-label="Add">
|
||||
<IconButton aria-label="Report" style={{ padding: '6px' }}>
|
||||
<BookmarkBorder fontSize="small" style={{ fontSize: '16px' }} />
|
||||
</IconButton>
|
||||
</Tooltip>
|
||||
</Grid>
|
||||
</Grid>
|
||||
}
|
||||
secondary={
|
||||
<React.Fragment>
|
||||
<Typography component="span" color="textPrimary">
|
||||
{name}
|
||||
<Typography component="span" style={{ color: '#586069', fontSize: '14px', paddingRight: 0 }}>
|
||||
{description}
|
||||
</Typography>
|
||||
{description}
|
||||
{tags.length > 0 && <span style={{ marginTop: '8px', display: 'block' }}>
|
||||
{tags}
|
||||
</span>}
|
||||
</React.Fragment>
|
||||
}
|
||||
/>
|
||||
</ListItem>
|
||||
<Divider></Divider>
|
||||
<ListItem alignItems="flex-start">
|
||||
{renderAuthorInfo()}
|
||||
{renderVersionInfo()}
|
||||
{renderPublishedInfo()}
|
||||
{renderFileSize()}
|
||||
{renderLicenseInfo()}
|
||||
</ListItem>
|
||||
</List>
|
||||
);
|
||||
};
|
||||
|
|
|
@ -52,8 +52,9 @@ export const OverviewItem = styled.span`
|
|||
&& {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin: 0 0 5px 0;
|
||||
color: ${colors.greyLight};
|
||||
margin: 0 0 0 16px;
|
||||
color: #908ba1;
|
||||
font-size: 16px;
|
||||
}
|
||||
`;
|
||||
|
||||
|
@ -83,15 +84,14 @@ export const Version = styled.span`
|
|||
|
||||
export const Icon = styled(Ico)`
|
||||
&& {
|
||||
margin: 1px 5px 0 0;
|
||||
fill: ${colors.greyLight};
|
||||
margin: 0px 10px 0px 0;
|
||||
fill: #908ba1;
|
||||
}
|
||||
`;
|
||||
|
||||
export const Published = styled.span`
|
||||
&& {
|
||||
display: none;
|
||||
color: ${colors.greyLight};
|
||||
color: #908ba1;
|
||||
${({ modifiers }) => modifiers};
|
||||
}
|
||||
`;
|
||||
|
@ -178,7 +178,7 @@ export const WrapperLink = styled(Link)`
|
|||
align-items: center;
|
||||
}
|
||||
${OverviewItem} {
|
||||
margin: 0 0 0 10px;
|
||||
margin: 0 0 0 0;
|
||||
}
|
||||
${Overview} {
|
||||
flex-direction: row;
|
||||
|
@ -197,3 +197,22 @@ export const WrapperLink = styled(Link)`
|
|||
`)};
|
||||
}
|
||||
`;
|
||||
|
||||
/**
|
||||
* Ayush's style
|
||||
*/
|
||||
|
||||
export const PackageName = styled.span`
|
||||
&& {
|
||||
font-weight: 600;
|
||||
font-size: 20px;
|
||||
display: block;
|
||||
margin-bottom: 12px;
|
||||
color: #414141;
|
||||
cursor: pointer;
|
||||
|
||||
&:hover {
|
||||
color: black;
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
|
|
@ -1,9 +1,10 @@
|
|||
import React, { Fragment } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
import Divider from '@material-ui/core/Divider';
|
||||
import Package from '../Package';
|
||||
import Help from '../Help';
|
||||
import { formatAuthor, formatLicense } from '../../utils/package';
|
||||
import { formatLicense } from '../../utils/package';
|
||||
|
||||
import classes from './packageList.scss';
|
||||
|
||||
|
@ -24,11 +25,14 @@ export default class PackageList extends React.Component {
|
|||
const { packages } = this.props;
|
||||
return (
|
||||
packages.map((pkg, i) => {
|
||||
const { name, version, description, time, keywords } = pkg;
|
||||
const author = formatAuthor(pkg.author);
|
||||
const { name, version, description, time, keywords, dist } = pkg;
|
||||
const author = pkg.author;
|
||||
const license = formatLicense(pkg.license);
|
||||
return (
|
||||
<Package key={i} {...{ name, version, author, description, license, time, keywords }} />
|
||||
<React.Fragment key={i}>
|
||||
{i !== 0 && <Divider style={{ margin: 0 }}></Divider>}
|
||||
<Package {...{ name, dist, version, author, description, license, time, keywords }} />
|
||||
</React.Fragment>
|
||||
);
|
||||
})
|
||||
);
|
||||
|
|
|
@ -11,10 +11,10 @@ export const Wrapper = styled.span`
|
|||
vertical-align: middle;
|
||||
line-height: 22px;
|
||||
border-radius: 2px;
|
||||
color: #9f9f9f;
|
||||
background-color: hsla(0, 0%, 51%, 0.1);
|
||||
color: #485a3e;
|
||||
background-color: #f3f4f2;
|
||||
padding: 0.22rem 0.4rem;
|
||||
margin: 5px 10px 0 0;
|
||||
margin: 8px 8px 0 0;
|
||||
${ellipsis('300px')};
|
||||
}
|
||||
`;
|
||||
|
|
|
@ -47,13 +47,17 @@ export function formatAuthor(author) {
|
|||
let authorDetails = {
|
||||
name: DEFAULT_USER,
|
||||
email: '',
|
||||
avatar: '',
|
||||
};
|
||||
|
||||
if (!author) {
|
||||
return authorDetails;
|
||||
}
|
||||
|
||||
if (isString(author)) {
|
||||
authorDetails = {
|
||||
...authorDetails,
|
||||
name: author ? author : authorDetails.name,
|
||||
email: author.email ? author.email : authorDetails.email,
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -61,8 +65,7 @@ export function formatAuthor(author) {
|
|||
authorDetails = {
|
||||
...authorDetails,
|
||||
name: author.name ? author.name : authorDetails.name,
|
||||
email: author.email ? author.email : authorDetails.email,
|
||||
avatar: author.avatar ? author.avatar : authorDetails.avatar,
|
||||
email: author.email ? author.email: authorDetails.email,
|
||||
};
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue