mirror of
https://github.com/datahub-project/datahub.git
synced 2025-12-24 08:28:12 +00:00
feat(React Incubation): User Profile (#2083)
* feat(react incubation): user profile w/ mock data * removing spurious build-and-test change * fixing CI issues
This commit is contained in:
parent
b0801de7ad
commit
dcefd96b4a
@ -26,8 +26,10 @@ module.exports = {
|
||||
'no-debugger': 'warn',
|
||||
'require-await': 'warn',
|
||||
'import/prefer-default-export': 'off', // TODO: remove this lint rule
|
||||
'import/extensions': 'off',
|
||||
'react/jsx-props-no-spreading': 'off',
|
||||
'no-plusplus': 'off',
|
||||
'no-prototype-builtins': 'off',
|
||||
'react/require-default-props': 'off',
|
||||
'@typescript-eslint/no-unused-vars': [
|
||||
'error',
|
||||
|
||||
53383
datahub-web-react/package-lock.json
generated
Normal file
53383
datahub-web-react/package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
@ -18,6 +18,7 @@
|
||||
"@types/react-router-dom": "^5.1.6",
|
||||
"antd": "^4.9.4",
|
||||
"graphql": "^15.4.0",
|
||||
"history": "^5.0.0",
|
||||
"js-cookie": "^2.2.1",
|
||||
"query-string": "^6.13.8",
|
||||
"react": "^17.0.0",
|
||||
@ -25,6 +26,7 @@
|
||||
"react-router": "^5.2.0",
|
||||
"react-router-dom": "^5.1.6",
|
||||
"react-scripts": "4.0.1",
|
||||
"styled-components": "^5.2.1",
|
||||
"typescript": "^4.1.3",
|
||||
"web-vitals": "^0.2.4"
|
||||
},
|
||||
@ -70,6 +72,7 @@
|
||||
"@storybook/preset-create-react-app": "^3.1.5",
|
||||
"@types/graphql": "^14.5.0",
|
||||
"@types/query-string": "^6.3.0",
|
||||
"@types/styled-components": "^5.1.7",
|
||||
"@typescript-eslint/eslint-plugin": "^4.11.0",
|
||||
"@typescript-eslint/parser": "^4.11.0",
|
||||
"babel-loader": "8.1.0",
|
||||
|
||||
@ -38,6 +38,7 @@ export const Routes = (): JSX.Element => {
|
||||
|
||||
{entityRegistry.getEntities().map((entity) => (
|
||||
<ProtectedRoute
|
||||
key={entity.getPathName()}
|
||||
isLoggedIn={isLoggedIn}
|
||||
path={`/${entity.getPathName()}/:urn`}
|
||||
render={() => <EntityPage entityType={entity.type} />}
|
||||
|
||||
3
datahub-web-react/src/components/entity/user/Subview.ts
Normal file
3
datahub-web-react/src/components/entity/user/Subview.ts
Normal file
@ -0,0 +1,3 @@
|
||||
export enum Subview {
|
||||
Ownership = 'ownership',
|
||||
}
|
||||
@ -1,7 +1,7 @@
|
||||
import * as React from 'react';
|
||||
import { CorpUser, EntityType } from '../../../types.generated';
|
||||
import { Entity, PreviewType } from '../Entity';
|
||||
import { UserPage } from './UserPage';
|
||||
import UserProfile from './UserProfile';
|
||||
|
||||
/**
|
||||
* Definition of the DataHub Dataset entity.
|
||||
@ -19,7 +19,7 @@ export class UserEntity implements Entity<CorpUser> {
|
||||
|
||||
getCollectionName: () => string = () => 'Users';
|
||||
|
||||
renderProfile: (urn: string) => JSX.Element = (_) => <UserPage />;
|
||||
renderProfile: (urn: string) => JSX.Element = (_) => <UserProfile />;
|
||||
|
||||
renderPreview = (_: PreviewType, _1: CorpUser) => <p>Hello</p>;
|
||||
}
|
||||
|
||||
82
datahub-web-react/src/components/entity/user/UserDetails.tsx
Normal file
82
datahub-web-react/src/components/entity/user/UserDetails.tsx
Normal file
@ -0,0 +1,82 @@
|
||||
import { Menu } from 'antd';
|
||||
import { MenuProps } from 'antd/lib/menu';
|
||||
import React from 'react';
|
||||
import { useHistory } from 'react-router-dom';
|
||||
import styled from 'styled-components';
|
||||
|
||||
import { EntityType } from '../../../types.generated';
|
||||
import { useEntityRegistry } from '../../useEntityRegistry';
|
||||
import { navigateToUserUrl } from './routingUtils/navigateToUserUrl';
|
||||
import { Subview } from './Subview';
|
||||
import UserOwnership from './UserOwnership';
|
||||
|
||||
const MENU_KEY_DELIMETER = '__';
|
||||
|
||||
const toMenuKey = (subview?: Subview, item?: string) => `${subview}${MENU_KEY_DELIMETER}${item}`;
|
||||
|
||||
const fromMenuKey = (key: string): { subview: string; item: string } => {
|
||||
const parts = key.split(MENU_KEY_DELIMETER);
|
||||
return { subview: parts[0], item: parts[1] };
|
||||
};
|
||||
|
||||
const MenuWrapper = styled.div`
|
||||
border: 2px solid #f5f5f5;
|
||||
`;
|
||||
|
||||
const Content = styled.div`
|
||||
margin-left: 32px;
|
||||
flex-grow: 1;
|
||||
`;
|
||||
|
||||
const DetailWrapper = styled.div`
|
||||
display: inline-flex;
|
||||
width: 100%;
|
||||
`;
|
||||
|
||||
type Props = {
|
||||
urn: string;
|
||||
ownerships: { [key in EntityType]?: any[] };
|
||||
subview?: Subview;
|
||||
item?: string;
|
||||
};
|
||||
|
||||
export default function UserDetails({ ownerships, subview, item, urn }: Props) {
|
||||
const entityRegistry = useEntityRegistry();
|
||||
const ownershipMenuOptions: Array<EntityType> = Object.keys(ownerships) as Array<EntityType>;
|
||||
const history = useHistory();
|
||||
|
||||
const onMenuClick: MenuProps['onClick'] = ({ key }) => {
|
||||
const { subview: nextSubview, item: nextItem } = fromMenuKey(String(key));
|
||||
navigateToUserUrl({ urn, subview: nextSubview, item: nextItem, history, entityRegistry });
|
||||
};
|
||||
|
||||
const subviews = Object.values(Subview);
|
||||
|
||||
const selectedKey = toMenuKey(subview, item);
|
||||
|
||||
return (
|
||||
<DetailWrapper>
|
||||
<MenuWrapper>
|
||||
<Menu
|
||||
selectable={false}
|
||||
mode="inline"
|
||||
style={{ width: 256 }}
|
||||
openKeys={subviews}
|
||||
selectedKeys={[selectedKey]}
|
||||
onClick={onMenuClick}
|
||||
>
|
||||
<Menu.SubMenu key={Subview.Ownership} title="Ownership">
|
||||
{ownershipMenuOptions.map((option) => (
|
||||
<Menu.Item key={toMenuKey(Subview.Ownership, entityRegistry.getPathName(option))}>
|
||||
{entityRegistry.getCollectionName(option)}
|
||||
</Menu.Item>
|
||||
))}
|
||||
</Menu.SubMenu>
|
||||
</Menu>
|
||||
</MenuWrapper>
|
||||
<Content>
|
||||
{subview === Subview.Ownership && <UserOwnership ownerships={ownerships} entityPath={item} />}
|
||||
</Content>
|
||||
</DetailWrapper>
|
||||
);
|
||||
}
|
||||
69
datahub-web-react/src/components/entity/user/UserHeader.tsx
Normal file
69
datahub-web-react/src/components/entity/user/UserHeader.tsx
Normal file
@ -0,0 +1,69 @@
|
||||
import { UserOutlined } from '@ant-design/icons';
|
||||
import styled from 'styled-components';
|
||||
import React from 'react';
|
||||
import { Space, Badge, Typography, Avatar } from 'antd';
|
||||
|
||||
type Props = {
|
||||
profileSrc?: string;
|
||||
name: string;
|
||||
title: string;
|
||||
skills: string[];
|
||||
teams: string[];
|
||||
email: string;
|
||||
};
|
||||
|
||||
const Row = styled.div`
|
||||
display: inline-flex;
|
||||
`;
|
||||
|
||||
const AvatarWrapper = styled.div`
|
||||
margin-right: 32px;
|
||||
`;
|
||||
|
||||
const Traits = styled.div`
|
||||
display: inline-flex;
|
||||
margin-top: 32px;
|
||||
`;
|
||||
|
||||
const Skills = styled.div`
|
||||
margin-right: 32px;
|
||||
`;
|
||||
|
||||
export default function UserHeader({ profileSrc, name, title, skills, teams, email }: Props) {
|
||||
return (
|
||||
<Row>
|
||||
<AvatarWrapper>
|
||||
<Avatar icon={<UserOutlined />} src={profileSrc} size={100} />
|
||||
</AvatarWrapper>
|
||||
<div>
|
||||
<Typography.Title level={3}>{name}</Typography.Title>
|
||||
<Space split="|" size="middle">
|
||||
<Typography.Text>{title}</Typography.Text>
|
||||
<a href={`mailto:${email}`}>
|
||||
<Typography.Text strong>{email}</Typography.Text>
|
||||
</a>
|
||||
</Space>
|
||||
<div>
|
||||
<Traits>
|
||||
<Skills>
|
||||
<Typography.Title level={5}>Ask me about</Typography.Title>
|
||||
<Space>
|
||||
{skills.map((skill) => (
|
||||
<Badge style={{ backgroundColor: '#108ee9' }} count={skill} key={skill} />
|
||||
))}
|
||||
</Space>
|
||||
</Skills>
|
||||
<div>
|
||||
<Typography.Title level={5}>Teams</Typography.Title>
|
||||
<Space>
|
||||
{teams.map((team) => (
|
||||
<Badge style={{ backgroundColor: '#87d068' }} count={team} key={team} />
|
||||
))}
|
||||
</Space>
|
||||
</div>
|
||||
</Traits>
|
||||
</div>
|
||||
</div>
|
||||
</Row>
|
||||
);
|
||||
}
|
||||
@ -0,0 +1,43 @@
|
||||
import React from 'react';
|
||||
import { List, Typography } from 'antd';
|
||||
import styled from 'styled-components';
|
||||
|
||||
import { EntityType } from '../../../types.generated';
|
||||
import { useEntityRegistry } from '../../useEntityRegistry';
|
||||
import { PreviewType } from '../Entity';
|
||||
|
||||
type Props = {
|
||||
ownerships: { [key in EntityType]?: any[] };
|
||||
entityPath?: string;
|
||||
};
|
||||
|
||||
const ListContainer = styled.div`
|
||||
display: default;
|
||||
flex-grow: default;
|
||||
`;
|
||||
|
||||
export default ({ ownerships, entityPath }: Props) => {
|
||||
const entityRegistry = useEntityRegistry();
|
||||
|
||||
const entityType = entityRegistry.getTypeFromPathName(entityPath || '');
|
||||
|
||||
if (!entityType) return null;
|
||||
|
||||
const entitiesToShow = ownerships[entityType] || [];
|
||||
|
||||
return (
|
||||
<ListContainer>
|
||||
<List
|
||||
dataSource={entitiesToShow}
|
||||
header={
|
||||
<Typography.Title level={3}>
|
||||
{entityRegistry.getCollectionName(entityType)} they own
|
||||
</Typography.Title>
|
||||
}
|
||||
renderItem={(item) => {
|
||||
return entityRegistry.renderPreview(entityType, PreviewType.PREVIEW, item);
|
||||
}}
|
||||
/>
|
||||
</ListContainer>
|
||||
);
|
||||
};
|
||||
@ -1,8 +0,0 @@
|
||||
import * as React from 'react';
|
||||
|
||||
/**
|
||||
* Responsible for reading & writing users.
|
||||
*/
|
||||
export const UserPage: React.VFC = () => {
|
||||
return <div>Needs Implemented</div>;
|
||||
};
|
||||
54
datahub-web-react/src/components/entity/user/UserProfile.tsx
Normal file
54
datahub-web-react/src/components/entity/user/UserProfile.tsx
Normal file
@ -0,0 +1,54 @@
|
||||
import { Divider } from 'antd';
|
||||
import React from 'react';
|
||||
import styled from 'styled-components';
|
||||
|
||||
import { EntityType, PlatformNativeType } from '../../../types.generated';
|
||||
import UserHeader from './UserHeader';
|
||||
import UserDetails from './UserDetails';
|
||||
import useUserParams from './routingUtils/useUserParams';
|
||||
|
||||
const PageContainer = styled.div`
|
||||
background-color: white;
|
||||
padding: 32px 100px;
|
||||
`;
|
||||
|
||||
/**
|
||||
* Responsible for reading & writing users.
|
||||
*/
|
||||
export default function UserProfile() {
|
||||
const { urn, subview, item } = useUserParams();
|
||||
|
||||
return (
|
||||
<PageContainer>
|
||||
<UserHeader
|
||||
name="Jane Doe"
|
||||
title="Software Engineer"
|
||||
skills={['Pandas', 'Multivariate Calculus', 'Juggling']}
|
||||
teams={['Product', 'Data Science']}
|
||||
email="jane@datahub.ui"
|
||||
/>
|
||||
<Divider />
|
||||
<UserDetails
|
||||
urn={urn}
|
||||
subview={subview}
|
||||
item={item}
|
||||
ownerships={{
|
||||
[EntityType.Dataset]: [
|
||||
{
|
||||
name: 'HiveDataset',
|
||||
origin: 'PROD',
|
||||
description: 'this is a dataset',
|
||||
platformNativeType: PlatformNativeType.Table,
|
||||
},
|
||||
{
|
||||
name: 'KafkaDataset',
|
||||
origin: 'PROD',
|
||||
description: 'this is also a dataset',
|
||||
platformNativeType: PlatformNativeType.Table,
|
||||
},
|
||||
],
|
||||
}}
|
||||
/>
|
||||
</PageContainer>
|
||||
);
|
||||
}
|
||||
@ -0,0 +1,53 @@
|
||||
import React from 'react';
|
||||
import { render } from '@testing-library/react';
|
||||
import UserDetails from '../UserDetails';
|
||||
import { EntityType, PlatformNativeType } from '../../../../types.generated';
|
||||
import TestPageContainer from '../../../../utils/test-utils/TestPageContainer';
|
||||
import { Subview } from '../Subview';
|
||||
|
||||
const ownerships = {
|
||||
[EntityType.Dataset]: [
|
||||
{
|
||||
name: 'HiveDataset',
|
||||
origin: 'PROD',
|
||||
description: 'this is a dataset',
|
||||
platformNativeType: PlatformNativeType.Table,
|
||||
},
|
||||
{
|
||||
name: 'KafkaDataset',
|
||||
origin: 'PROD',
|
||||
description: 'this is also a dataset',
|
||||
platformNativeType: PlatformNativeType.Table,
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
describe('UserDetails', () => {
|
||||
it('renders a menu with the ownership submenu and datasets option', () => {
|
||||
const { getByText } = render(
|
||||
<TestPageContainer>
|
||||
<UserDetails urn="some:urn" ownerships={ownerships} />;
|
||||
</TestPageContainer>,
|
||||
);
|
||||
expect(getByText('Ownership')).toBeInTheDocument();
|
||||
expect(getByText('Datasets')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('will not the show the ownership details by default', () => {
|
||||
const { queryByText } = render(
|
||||
<TestPageContainer>
|
||||
<UserDetails urn="some:urn" ownerships={ownerships} />;
|
||||
</TestPageContainer>,
|
||||
);
|
||||
expect(queryByText('Datasets they own')).not.toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('will the show the ownership details when selected', () => {
|
||||
const { getByText } = render(
|
||||
<TestPageContainer>
|
||||
<UserDetails urn="some:urn" ownerships={ownerships} subview={Subview.Ownership} item="dataset" />;
|
||||
</TestPageContainer>,
|
||||
);
|
||||
expect(getByText('Datasets they own')).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
@ -0,0 +1,35 @@
|
||||
import React from 'react';
|
||||
import { render } from '@testing-library/react';
|
||||
import UserHeader from '../UserHeader';
|
||||
|
||||
describe('UserHeader', () => {
|
||||
it('renders', () => {
|
||||
render(
|
||||
<UserHeader
|
||||
name="Jane Doe"
|
||||
title="Software Engineer"
|
||||
skills={['Pandas', 'Multivariate Calculus', 'Juggling']}
|
||||
teams={['Product', 'Data Science']}
|
||||
email="jane@datahub.ui"
|
||||
/>,
|
||||
);
|
||||
});
|
||||
it('renders name, title, skills, teams and email', () => {
|
||||
const { getByText } = render(
|
||||
<UserHeader
|
||||
name="Jane Doe"
|
||||
title="Software Engineer"
|
||||
skills={['Pandas', 'Multivariate Calculus', 'Juggling']}
|
||||
teams={['Product', 'Data Science']}
|
||||
email="jane@datahub.ui"
|
||||
/>,
|
||||
);
|
||||
expect(getByText('Jane Doe')).toBeInTheDocument();
|
||||
expect(getByText('Software Engineer')).toBeInTheDocument();
|
||||
expect(getByText('Pandas')).toBeInTheDocument();
|
||||
expect(getByText('Juggling')).toBeInTheDocument();
|
||||
expect(getByText('Product')).toBeInTheDocument();
|
||||
expect(getByText('Data Science')).toBeInTheDocument();
|
||||
expect(getByText('jane@datahub.ui')).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
@ -0,0 +1,43 @@
|
||||
import React from 'react';
|
||||
import { render } from '@testing-library/react';
|
||||
import UserOwnership from '../UserOwnership';
|
||||
import { EntityType, PlatformNativeType } from '../../../../types.generated';
|
||||
import TestPageContainer from '../../../../utils/test-utils/TestPageContainer';
|
||||
|
||||
const ownerships = {
|
||||
[EntityType.Dataset]: [
|
||||
{
|
||||
name: 'HiveDataset',
|
||||
origin: 'PROD',
|
||||
description: 'this is a dataset',
|
||||
platformNativeType: PlatformNativeType.Table,
|
||||
},
|
||||
{
|
||||
name: 'KafkaDataset',
|
||||
origin: 'PROD',
|
||||
description: 'this is also a dataset',
|
||||
platformNativeType: PlatformNativeType.Table,
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
describe('UserOwnership', () => {
|
||||
it('renders a list container', () => {
|
||||
const { getByText } = render(
|
||||
<TestPageContainer>
|
||||
<UserOwnership ownerships={ownerships} entityPath="dataset" />
|
||||
</TestPageContainer>,
|
||||
);
|
||||
expect(getByText('Datasets they own')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('renders the entity rows', () => {
|
||||
const { getByText } = render(
|
||||
<TestPageContainer>
|
||||
<UserOwnership ownerships={ownerships} entityPath="dataset" />
|
||||
</TestPageContainer>,
|
||||
);
|
||||
expect(getByText('this is a dataset')).toBeInTheDocument();
|
||||
expect(getByText('this is also a dataset')).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
@ -0,0 +1,35 @@
|
||||
import { createBrowserHistory } from 'history';
|
||||
|
||||
import { getTestEntityRegistry } from '../../../../../utils/test-utils/TestPageContainer';
|
||||
import { Subview } from '../../Subview';
|
||||
import { navigateToUserUrl } from '../navigateToUserUrl';
|
||||
|
||||
const history = createBrowserHistory();
|
||||
|
||||
const entityRegistry = getTestEntityRegistry();
|
||||
|
||||
describe('navigateToUserUrl', () => {
|
||||
beforeEach(() => {
|
||||
jest.spyOn(history, 'push');
|
||||
});
|
||||
|
||||
it('navigates to the correct url without subviews', () => {
|
||||
navigateToUserUrl({
|
||||
urn: 'test:urn',
|
||||
history,
|
||||
entityRegistry,
|
||||
});
|
||||
expect(history.push).toHaveBeenCalledWith({ pathname: '/user/test:urn' });
|
||||
});
|
||||
|
||||
it('navigates to the correct url with subviews', () => {
|
||||
navigateToUserUrl({
|
||||
urn: 'test:urn',
|
||||
subview: Subview.Ownership,
|
||||
item: 'dataset',
|
||||
history,
|
||||
entityRegistry,
|
||||
});
|
||||
expect(history.push).toHaveBeenCalledWith({ pathname: '/user/test:urn/ownership/dataset' });
|
||||
});
|
||||
});
|
||||
@ -0,0 +1,23 @@
|
||||
import { RouteComponentProps } from 'react-router-dom';
|
||||
import { EntityType } from '../../../../types.generated';
|
||||
import EntityRegistry from '../../EntityRegistry';
|
||||
|
||||
export const navigateToUserUrl = ({
|
||||
urn,
|
||||
subview,
|
||||
item,
|
||||
history,
|
||||
entityRegistry,
|
||||
}: {
|
||||
urn: string;
|
||||
subview?: string;
|
||||
item?: string;
|
||||
history: RouteComponentProps['history'];
|
||||
entityRegistry: EntityRegistry;
|
||||
}) => {
|
||||
history.push({
|
||||
pathname: `/${entityRegistry.getPathName(EntityType.User)}/${urn}${subview ? `/${subview}` : ''}${
|
||||
item && subview ? `/${item}` : ''
|
||||
}`,
|
||||
});
|
||||
};
|
||||
@ -0,0 +1,27 @@
|
||||
import { useMemo } from 'react';
|
||||
|
||||
import { useLocation, useParams } from 'react-router';
|
||||
import { Subview } from '../Subview';
|
||||
|
||||
type UserPageParams = {
|
||||
urn: string;
|
||||
};
|
||||
|
||||
const SUBVIEW_PATH_INDEX = 3;
|
||||
const ITEM_PATH_INDEX = 4;
|
||||
|
||||
export default function useUserParams(): { subview?: Subview; item?: string; urn: string } {
|
||||
const location = useLocation();
|
||||
const { urn } = useParams<UserPageParams>();
|
||||
return useMemo(() => {
|
||||
const parts = location.pathname.split('/');
|
||||
const subview = parts[SUBVIEW_PATH_INDEX];
|
||||
|
||||
return {
|
||||
urn,
|
||||
subview:
|
||||
subview && Object.values(Subview).indexOf(subview as Subview) >= 0 ? (subview as Subview) : undefined,
|
||||
item: parts[ITEM_PATH_INDEX],
|
||||
};
|
||||
}, [location.pathname, urn]);
|
||||
}
|
||||
@ -14,5 +14,4 @@ export enum PageRoutes {
|
||||
BROWSE = '/browse',
|
||||
BROWSE_RESULTS = '/browse/:type',
|
||||
DATASETS = '/datasets',
|
||||
USERS = '/users',
|
||||
}
|
||||
|
||||
28
datahub-web-react/src/utils/test-utils/TestPageContainer.tsx
Normal file
28
datahub-web-react/src/utils/test-utils/TestPageContainer.tsx
Normal file
@ -0,0 +1,28 @@
|
||||
import React, { useMemo } from 'react';
|
||||
import { MemoryRouter } from 'react-router';
|
||||
|
||||
import { DatasetEntity } from '../../components/entity/dataset/DatasetEntity';
|
||||
import { UserEntity } from '../../components/entity/user/User';
|
||||
import EntityRegistry from '../../components/entity/EntityRegistry';
|
||||
import { EntityRegistryContext } from '../../entityRegistryContext';
|
||||
|
||||
type Props = {
|
||||
children: React.ReactNode;
|
||||
};
|
||||
|
||||
export function getTestEntityRegistry() {
|
||||
const entityRegistry = new EntityRegistry();
|
||||
entityRegistry.register(new DatasetEntity());
|
||||
entityRegistry.register(new UserEntity());
|
||||
return entityRegistry;
|
||||
}
|
||||
|
||||
export default ({ children }: Props) => {
|
||||
const entityRegistry = useMemo(() => getTestEntityRegistry(), []);
|
||||
|
||||
return (
|
||||
<MemoryRouter>
|
||||
<EntityRegistryContext.Provider value={entityRegistry}>{children}</EntityRegistryContext.Provider>;
|
||||
</MemoryRouter>
|
||||
);
|
||||
};
|
||||
@ -163,7 +163,7 @@
|
||||
jsesc "^2.5.1"
|
||||
source-map "^0.5.0"
|
||||
|
||||
"@babel/helper-annotate-as-pure@^7.10.4", "@babel/helper-annotate-as-pure@^7.12.10":
|
||||
"@babel/helper-annotate-as-pure@^7.0.0", "@babel/helper-annotate-as-pure@^7.10.4", "@babel/helper-annotate-as-pure@^7.12.10":
|
||||
version "7.12.10"
|
||||
resolved "https://registry.yarnpkg.com/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.12.10.tgz"
|
||||
integrity sha512-XplmVbC1n+KY6jL8/fgLVXXUauDIB+lD5+GsQEh6F6GBF1dq1qy4DP4yXWzDKcoqXB3X58t61e85Fitoww4JVQ==
|
||||
@ -1257,7 +1257,7 @@
|
||||
globals "^11.1.0"
|
||||
lodash "^4.17.19"
|
||||
|
||||
"@babel/traverse@^7.0.0", "@babel/traverse@^7.1.0", "@babel/traverse@^7.10.4", "@babel/traverse@^7.12.1", "@babel/traverse@^7.12.10", "@babel/traverse@^7.12.5", "@babel/traverse@^7.12.9", "@babel/traverse@^7.7.0":
|
||||
"@babel/traverse@^7.0.0", "@babel/traverse@^7.1.0", "@babel/traverse@^7.10.4", "@babel/traverse@^7.12.1", "@babel/traverse@^7.12.10", "@babel/traverse@^7.12.5", "@babel/traverse@^7.12.9", "@babel/traverse@^7.4.5", "@babel/traverse@^7.7.0":
|
||||
version "7.12.12"
|
||||
resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.12.12.tgz"
|
||||
integrity sha512-s88i0X0lPy45RrLM8b9mz8RPH5FqO9G9p7ti59cToE44xFm1Q+Pjh5Gq4SXBbtb88X7Uy7pexeqRIQDDMNkL0w==
|
||||
@ -1359,7 +1359,7 @@
|
||||
resolved "https://registry.yarnpkg.com/@emotion/hash/-/hash-0.8.0.tgz"
|
||||
integrity sha512-kBJtf7PH6aWwZ6fka3zQ0p6SBYzx4fl1LoZXE2RrnYST9Xljm7WfKJrU4g/Xr3Beg72MLrp1AWNUmuYJTL7Cow==
|
||||
|
||||
"@emotion/is-prop-valid@0.8.8", "@emotion/is-prop-valid@^0.8.6":
|
||||
"@emotion/is-prop-valid@0.8.8", "@emotion/is-prop-valid@^0.8.6", "@emotion/is-prop-valid@^0.8.8":
|
||||
version "0.8.8"
|
||||
resolved "https://registry.yarnpkg.com/@emotion/is-prop-valid/-/is-prop-valid-0.8.8.tgz"
|
||||
integrity sha512-u5WtneEAr5IDG2Wv65yhunPSMLIpuKsbuOktRojfrEiEvRyC85LgPMZI63cr7NUqT8ZIGdSVg8ZKGxIug4lXcA==
|
||||
@ -1405,12 +1405,12 @@
|
||||
"@emotion/styled-base" "^10.0.27"
|
||||
babel-plugin-emotion "^10.0.27"
|
||||
|
||||
"@emotion/stylis@0.8.5":
|
||||
"@emotion/stylis@0.8.5", "@emotion/stylis@^0.8.4":
|
||||
version "0.8.5"
|
||||
resolved "https://registry.yarnpkg.com/@emotion/stylis/-/stylis-0.8.5.tgz"
|
||||
integrity sha512-h6KtPihKFn3T9fuIrwvXXUOwlx3rfUvfZIcP5a6rh8Y7zjE3O06hT5Ss4S/YI1AYhuZ1kjaE/5EaOOI2NqSylQ==
|
||||
|
||||
"@emotion/unitless@0.7.5":
|
||||
"@emotion/unitless@0.7.5", "@emotion/unitless@^0.7.4":
|
||||
version "0.7.5"
|
||||
resolved "https://registry.yarnpkg.com/@emotion/unitless/-/unitless-0.7.5.tgz"
|
||||
integrity sha512-OWORNpfjMsSSUBVrRBVGECkhWcULOAJz9ZW8uK9qgxD+87M7jHRcvh/A96XXNhXTLmKcoYSQtBEX7lHMO7YRwg==
|
||||
@ -3071,6 +3071,14 @@
|
||||
resolved "https://registry.yarnpkg.com/@types/history/-/history-4.7.8.tgz"
|
||||
integrity sha512-S78QIYirQcUoo6UJZx9CSP0O2ix9IaeAXwQi26Rhr/+mg7qqPy8TzaxHSUut7eGjL8WmLccT7/MXf304WjqHcA==
|
||||
|
||||
"@types/hoist-non-react-statics@*":
|
||||
version "3.3.1"
|
||||
resolved "https://registry.npmjs.org/@types/hoist-non-react-statics/-/hoist-non-react-statics-3.3.1.tgz"
|
||||
integrity sha512-iMIqiko6ooLrTh1joXodJK5X9xeEALT1kM5G3ZLhD3hszxBdIEd5C75U834D9mLcINgD4OyZf5uQXjkuYydWvA==
|
||||
dependencies:
|
||||
"@types/react" "*"
|
||||
hoist-non-react-statics "^3.3.0"
|
||||
|
||||
"@types/html-minifier-terser@^5.0.0":
|
||||
version "5.1.1"
|
||||
resolved "https://registry.yarnpkg.com/@types/html-minifier-terser/-/html-minifier-terser-5.1.1.tgz"
|
||||
@ -3322,6 +3330,15 @@
|
||||
resolved "https://registry.yarnpkg.com/@types/stack-utils/-/stack-utils-2.0.0.tgz"
|
||||
integrity sha512-RJJrrySY7A8havqpGObOB4W92QXKJo63/jFLLgpvOtsGUqbQZ9Sbgl35KMm1DjC6j7AvmmU2bIno+3IyEaemaw==
|
||||
|
||||
"@types/styled-components@^5.1.7":
|
||||
version "5.1.7"
|
||||
resolved "https://registry.npmjs.org/@types/styled-components/-/styled-components-5.1.7.tgz"
|
||||
integrity sha512-BJzPhFygYspyefAGFZTZ/8lCEY4Tk+Iqktvnko3xmJf9LrLqs3+grxPeU3O0zLl6yjbYBopD0/VikbHgXDbJtA==
|
||||
dependencies:
|
||||
"@types/hoist-non-react-statics" "*"
|
||||
"@types/react" "*"
|
||||
csstype "^3.0.2"
|
||||
|
||||
"@types/tapable@*", "@types/tapable@^1.0.5":
|
||||
version "1.0.6"
|
||||
resolved "https://registry.yarnpkg.com/@types/tapable/-/tapable-1.0.6.tgz"
|
||||
@ -4537,6 +4554,16 @@ babel-plugin-react-docgen@^4.1.0, babel-plugin-react-docgen@^4.2.1:
|
||||
lodash "^4.17.15"
|
||||
react-docgen "^5.0.0"
|
||||
|
||||
"babel-plugin-styled-components@>= 1":
|
||||
version "1.12.0"
|
||||
resolved "https://registry.npmjs.org/babel-plugin-styled-components/-/babel-plugin-styled-components-1.12.0.tgz"
|
||||
integrity sha512-FEiD7l5ZABdJPpLssKXjBUJMYqzbcNzBowfXDCdJhOpbhWiewapUaY+LZGT8R4Jg2TwOjGjG4RKeyrO5p9sBkA==
|
||||
dependencies:
|
||||
"@babel/helper-annotate-as-pure" "^7.0.0"
|
||||
"@babel/helper-module-imports" "^7.0.0"
|
||||
babel-plugin-syntax-jsx "^6.18.0"
|
||||
lodash "^4.17.11"
|
||||
|
||||
babel-plugin-syntax-jsx@^6.18.0:
|
||||
version "6.18.0"
|
||||
resolved "https://registry.yarnpkg.com/babel-plugin-syntax-jsx/-/babel-plugin-syntax-jsx-6.18.0.tgz"
|
||||
@ -5236,6 +5263,11 @@ camelcase@^6.0.0, camelcase@^6.1.0, camelcase@^6.2.0:
|
||||
resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-6.2.0.tgz"
|
||||
integrity sha512-c7wVvbw3f37nuobQNtgsgG9POC9qMbNuMQmTCqZv23b6MIz0fcYpBiOlv9gEN/hdLdnZTDQhg6e9Dq5M1vKvfg==
|
||||
|
||||
camelize@^1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.npmjs.org/camelize/-/camelize-1.0.0.tgz"
|
||||
integrity sha1-FkpUg+Yw+kMh5a8HAg5TGDGyYJs=
|
||||
|
||||
caniuse-api@^3.0.0:
|
||||
version "3.0.0"
|
||||
resolved "https://registry.yarnpkg.com/caniuse-api/-/caniuse-api-3.0.0.tgz"
|
||||
@ -6017,6 +6049,11 @@ css-blank-pseudo@^0.1.4:
|
||||
dependencies:
|
||||
postcss "^7.0.5"
|
||||
|
||||
css-color-keywords@^1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.npmjs.org/css-color-keywords/-/css-color-keywords-1.0.0.tgz"
|
||||
integrity sha1-/qJhbcZ2spYmhrOvjb2+GAskTgU=
|
||||
|
||||
css-color-names@0.0.4, css-color-names@^0.0.4:
|
||||
version "0.0.4"
|
||||
resolved "https://registry.yarnpkg.com/css-color-names/-/css-color-names-0.0.4.tgz"
|
||||
@ -6107,6 +6144,15 @@ css-select@^2.0.0:
|
||||
domutils "^1.7.0"
|
||||
nth-check "^1.0.2"
|
||||
|
||||
css-to-react-native@^3.0.0:
|
||||
version "3.0.0"
|
||||
resolved "https://registry.npmjs.org/css-to-react-native/-/css-to-react-native-3.0.0.tgz"
|
||||
integrity sha512-Ro1yETZA813eoyUp2GDBhG2j+YggidUmzO1/v9eYBKR2EHVEniE2MI/NqpTQ954BMpTPZFsGNPm46qFB9dpaPQ==
|
||||
dependencies:
|
||||
camelize "^1.0.0"
|
||||
css-color-keywords "^1.0.0"
|
||||
postcss-value-parser "^4.0.2"
|
||||
|
||||
css-tree@1.0.0-alpha.37:
|
||||
version "1.0.0-alpha.37"
|
||||
resolved "https://registry.yarnpkg.com/css-tree/-/css-tree-1.0.0-alpha.37.tgz"
|
||||
@ -8610,6 +8656,13 @@ history@^4.9.0:
|
||||
tiny-warning "^1.0.0"
|
||||
value-equal "^1.0.1"
|
||||
|
||||
history@^5.0.0:
|
||||
version "5.0.0"
|
||||
resolved "https://registry.yarnpkg.com/history/-/history-5.0.0.tgz#0cabbb6c4bbf835addb874f8259f6d25101efd08"
|
||||
integrity sha512-3NyRMKIiFSJmIPdq7FxkNMJkQ7ZEtVblOQ38VtKaA0zZMW1Eo6Q6W8oDKEflr1kNNTItSnk4JMCO1deeSgbLLg==
|
||||
dependencies:
|
||||
"@babel/runtime" "^7.7.6"
|
||||
|
||||
hmac-drbg@^1.0.0:
|
||||
version "1.0.1"
|
||||
resolved "https://registry.yarnpkg.com/hmac-drbg/-/hmac-drbg-1.0.1.tgz"
|
||||
@ -8619,7 +8672,7 @@ hmac-drbg@^1.0.0:
|
||||
minimalistic-assert "^1.0.0"
|
||||
minimalistic-crypto-utils "^1.0.1"
|
||||
|
||||
hoist-non-react-statics@^3.1.0, hoist-non-react-statics@^3.3.0, hoist-non-react-statics@^3.3.2:
|
||||
hoist-non-react-statics@^3.0.0, hoist-non-react-statics@^3.1.0, hoist-non-react-statics@^3.3.0, hoist-non-react-statics@^3.3.2:
|
||||
version "3.3.2"
|
||||
resolved "https://registry.yarnpkg.com/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz"
|
||||
integrity sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==
|
||||
@ -13067,7 +13120,7 @@ query-string@*, query-string@^4.1.0:
|
||||
|
||||
query-string@^6.13.8:
|
||||
version "6.13.8"
|
||||
resolved "https://registry.yarnpkg.com/query-string/-/query-string-6.13.8.tgz#8cf231759c85484da3cf05a851810d8e825c1159"
|
||||
resolved "https://registry.yarnpkg.com/query-string/-/query-string-6.13.8.tgz"
|
||||
integrity sha512-jxJzQI2edQPE/NPUOusNjO/ZOGqr1o2OBa/3M00fU76FsLXDVbJDv/p7ng5OdQyorKrkRz1oqfwmbe5MAMePQg==
|
||||
dependencies:
|
||||
decode-uri-component "^0.2.0"
|
||||
@ -15037,7 +15090,7 @@ spdy@^4.0.2:
|
||||
|
||||
split-on-first@^1.0.0:
|
||||
version "1.1.0"
|
||||
resolved "https://registry.yarnpkg.com/split-on-first/-/split-on-first-1.1.0.tgz#f610afeee3b12bce1d0c30425e76398b78249a5f"
|
||||
resolved "https://registry.yarnpkg.com/split-on-first/-/split-on-first-1.1.0.tgz"
|
||||
integrity sha512-43ZssAJaMusuKWL8sKUBQXHWOpq8d6CfN/u1p4gUzfJkM05C8rxTmYrkIPTXapZpORA6LkkzcUulJ8FqA7Uudw==
|
||||
|
||||
split-string@^3.0.1, split-string@^3.0.2:
|
||||
@ -15175,7 +15228,7 @@ strict-uri-encode@^1.0.0:
|
||||
|
||||
strict-uri-encode@^2.0.0:
|
||||
version "2.0.0"
|
||||
resolved "https://registry.yarnpkg.com/strict-uri-encode/-/strict-uri-encode-2.0.0.tgz#b9c7330c7042862f6b142dc274bbcc5866ce3546"
|
||||
resolved "https://registry.yarnpkg.com/strict-uri-encode/-/strict-uri-encode-2.0.0.tgz"
|
||||
integrity sha1-ucczDHBChi9rFC3CdLvMWGbONUY=
|
||||
|
||||
string-convert@^0.2.0:
|
||||
@ -15394,6 +15447,22 @@ style-to-object@0.3.0, style-to-object@^0.3.0:
|
||||
dependencies:
|
||||
inline-style-parser "0.1.1"
|
||||
|
||||
styled-components@^5.2.1:
|
||||
version "5.2.1"
|
||||
resolved "https://registry.npmjs.org/styled-components/-/styled-components-5.2.1.tgz"
|
||||
integrity sha512-sBdgLWrCFTKtmZm/9x7jkIabjFNVzCUeKfoQsM6R3saImkUnjx0QYdLwJHBjY9ifEcmjDamJDVfknWm1yxZPxQ==
|
||||
dependencies:
|
||||
"@babel/helper-module-imports" "^7.0.0"
|
||||
"@babel/traverse" "^7.4.5"
|
||||
"@emotion/is-prop-valid" "^0.8.8"
|
||||
"@emotion/stylis" "^0.8.4"
|
||||
"@emotion/unitless" "^0.7.4"
|
||||
babel-plugin-styled-components ">= 1"
|
||||
css-to-react-native "^3.0.0"
|
||||
hoist-non-react-statics "^3.0.0"
|
||||
shallowequal "^1.1.0"
|
||||
supports-color "^5.5.0"
|
||||
|
||||
stylehacks@^4.0.0:
|
||||
version "4.0.3"
|
||||
resolved "https://registry.yarnpkg.com/stylehacks/-/stylehacks-4.0.3.tgz"
|
||||
@ -15408,7 +15477,7 @@ supports-color@^2.0.0:
|
||||
resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-2.0.0.tgz"
|
||||
integrity sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=
|
||||
|
||||
supports-color@^5.3.0:
|
||||
supports-color@^5.3.0, supports-color@^5.5.0:
|
||||
version "5.5.0"
|
||||
resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz"
|
||||
integrity sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user