Extracted breadcrumbs into a shared component, added it to project settings page
This commit is contained in:
@@ -1,4 +1,3 @@
|
|||||||
import faker from 'faker';
|
|
||||||
import { sample } from 'lodash';
|
import { sample } from 'lodash';
|
||||||
|
|
||||||
import { Comment, Issue, Project, User } from 'entities';
|
import { Comment, Issue, Project, User } from 'entities';
|
||||||
@@ -9,14 +8,19 @@ import { createEntity } from 'utils/typeorm';
|
|||||||
const seedUsers = (): Promise<User[]> => {
|
const seedUsers = (): Promise<User[]> => {
|
||||||
const users = [
|
const users = [
|
||||||
createEntity(User, {
|
createEntity(User, {
|
||||||
email: 'greg@jira.guest',
|
email: 'gaben@jira.guest',
|
||||||
name: 'Greg the Egg',
|
name: 'Lord Gaben',
|
||||||
avatarUrl: faker.image.avatar(),
|
avatarUrl: 'https://i.ibb.co/6RJ5hq6/gaben.jpg',
|
||||||
}),
|
}),
|
||||||
createEntity(User, {
|
createEntity(User, {
|
||||||
email: 'yoda@jira.guest',
|
email: 'yoda@jira.guest',
|
||||||
name: 'Baby Yoda',
|
name: 'Baby Yoda',
|
||||||
avatarUrl: faker.image.avatar(),
|
avatarUrl: 'https://i.ibb.co/6n0hLML/baby-yoda.jpg',
|
||||||
|
}),
|
||||||
|
createEntity(User, {
|
||||||
|
email: 'rick@jira.guest',
|
||||||
|
name: 'Pickle Rick',
|
||||||
|
avatarUrl: 'https://i.ibb.co/7JM1P2r/picke-rick.jpg',
|
||||||
}),
|
}),
|
||||||
];
|
];
|
||||||
return Promise.all(users);
|
return Promise.all(users);
|
||||||
|
|||||||
@@ -1,18 +1,6 @@
|
|||||||
import styled from 'styled-components';
|
import styled from 'styled-components';
|
||||||
|
|
||||||
import { color, font } from 'shared/utils/styles';
|
import { font } from 'shared/utils/styles';
|
||||||
|
|
||||||
export const Breadcrumbs = styled.div`
|
|
||||||
color: ${color.textMedium};
|
|
||||||
${font.size(15)};
|
|
||||||
`;
|
|
||||||
|
|
||||||
export const Divider = styled.span`
|
|
||||||
position: relative;
|
|
||||||
top: 2px;
|
|
||||||
margin: 0 10px;
|
|
||||||
${font.size(18)};
|
|
||||||
`;
|
|
||||||
|
|
||||||
export const Header = styled.div`
|
export const Header = styled.div`
|
||||||
margin-top: 6px;
|
margin-top: 6px;
|
||||||
|
|||||||
@@ -1,31 +1,14 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import PropTypes from 'prop-types';
|
|
||||||
|
|
||||||
import { CopyLinkButton } from 'shared/components';
|
import { CopyLinkButton } from 'shared/components';
|
||||||
|
|
||||||
import { Breadcrumbs, Divider, Header, BoardName } from './Styles';
|
import { Header, BoardName } from './Styles';
|
||||||
|
|
||||||
const propTypes = {
|
|
||||||
projectName: PropTypes.string.isRequired,
|
|
||||||
};
|
|
||||||
|
|
||||||
const ProjectBoardHeader = ({ projectName }) => (
|
|
||||||
<>
|
|
||||||
<Breadcrumbs>
|
|
||||||
Projects
|
|
||||||
<Divider>/</Divider>
|
|
||||||
{projectName}
|
|
||||||
<Divider>/</Divider>
|
|
||||||
Kanban Board
|
|
||||||
</Breadcrumbs>
|
|
||||||
|
|
||||||
|
const ProjectBoardHeader = () => (
|
||||||
<Header>
|
<Header>
|
||||||
<BoardName>Kanban board</BoardName>
|
<BoardName>Kanban board</BoardName>
|
||||||
<CopyLinkButton />
|
<CopyLinkButton />
|
||||||
</Header>
|
</Header>
|
||||||
</>
|
|
||||||
);
|
);
|
||||||
|
|
||||||
ProjectBoardHeader.propTypes = propTypes;
|
|
||||||
|
|
||||||
export default ProjectBoardHeader;
|
export default ProjectBoardHeader;
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ import React from 'react';
|
|||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
|
|
||||||
import useMergeState from 'shared/hooks/mergeState';
|
import useMergeState from 'shared/hooks/mergeState';
|
||||||
|
import { Breadcrumbs } from 'shared/components';
|
||||||
|
|
||||||
import Header from './Header';
|
import Header from './Header';
|
||||||
import Filters from './Filters';
|
import Filters from './Filters';
|
||||||
@@ -24,7 +25,8 @@ const ProjectBoard = ({ project, updateLocalProjectIssues }) => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Header projectName={project.name} />
|
<Breadcrumbs items={['Projects', project.name, 'Kanban Board']} />
|
||||||
|
<Header />
|
||||||
<Filters
|
<Filters
|
||||||
projectUsers={project.users}
|
projectUsers={project.users}
|
||||||
defaultFilters={defaultFilters}
|
defaultFilters={defaultFilters}
|
||||||
|
|||||||
@@ -10,11 +10,10 @@ export const FormCont = styled.div`
|
|||||||
|
|
||||||
export const FormElement = styled(Form.Element)`
|
export const FormElement = styled(Form.Element)`
|
||||||
max-width: 640px;
|
max-width: 640px;
|
||||||
padding: 20px 0;
|
|
||||||
`;
|
`;
|
||||||
|
|
||||||
export const FormHeading = styled.div`
|
export const FormHeading = styled.div`
|
||||||
padding-bottom: 15px;
|
padding: 6px 0 15px;
|
||||||
${font.size(24)}
|
${font.size(24)}
|
||||||
${font.medium}
|
${font.medium}
|
||||||
`;
|
`;
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import PropTypes from 'prop-types';
|
|||||||
import { ProjectCategory, ProjectCategoryCopy } from 'shared/constants/projects';
|
import { ProjectCategory, ProjectCategoryCopy } from 'shared/constants/projects';
|
||||||
import toast from 'shared/utils/toast';
|
import toast from 'shared/utils/toast';
|
||||||
import useApi from 'shared/hooks/api';
|
import useApi from 'shared/hooks/api';
|
||||||
import { Form } from 'shared/components';
|
import { Form, Breadcrumbs } from 'shared/components';
|
||||||
|
|
||||||
import { FormCont, FormHeading, FormElement, ActionButton } from './Styles';
|
import { FormCont, FormHeading, FormElement, ActionButton } from './Styles';
|
||||||
|
|
||||||
@@ -46,6 +46,7 @@ const ProjectSettings = ({ project, fetchProject }) => {
|
|||||||
>
|
>
|
||||||
<FormCont>
|
<FormCont>
|
||||||
<FormElement>
|
<FormElement>
|
||||||
|
<Breadcrumbs items={['Projects', project.name, 'Project Details']} />
|
||||||
<FormHeading>Project Details</FormHeading>
|
<FormHeading>Project Details</FormHeading>
|
||||||
<Form.Field.Input name="name" label="Name" />
|
<Form.Field.Input name="name" label="Name" />
|
||||||
<Form.Field.Input name="url" label="URL" />
|
<Form.Field.Input name="url" label="URL" />
|
||||||
|
|||||||
@@ -25,7 +25,9 @@ const ProjectSidebar = ({ project }) => {
|
|||||||
const match = useRouteMatch();
|
const match = useRouteMatch();
|
||||||
|
|
||||||
const renderLinkItem = (text, iconType, path) => {
|
const renderLinkItem = (text, iconType, path) => {
|
||||||
const linkItemProps = path
|
const isImplemented = !!path;
|
||||||
|
|
||||||
|
const linkItemProps = isImplemented
|
||||||
? { as: NavLink, exact: true, to: `${match.path}${path}` }
|
? { as: NavLink, exact: true, to: `${match.path}${path}` }
|
||||||
: { as: 'div' };
|
: { as: 'div' };
|
||||||
|
|
||||||
@@ -33,7 +35,7 @@ const ProjectSidebar = ({ project }) => {
|
|||||||
<LinkItem {...linkItemProps}>
|
<LinkItem {...linkItemProps}>
|
||||||
<Icon type={iconType} />
|
<Icon type={iconType} />
|
||||||
<LinkText>{text}</LinkText>
|
<LinkText>{text}</LinkText>
|
||||||
{!path && <NotImplemented>Not implemented</NotImplemented>}
|
{!isImplemented && <NotImplemented>Not implemented</NotImplemented>}
|
||||||
</LinkItem>
|
</LinkItem>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
15
client/src/shared/components/Breadcrumbs/Styles.js
Normal file
15
client/src/shared/components/Breadcrumbs/Styles.js
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
import styled from 'styled-components';
|
||||||
|
|
||||||
|
import { color, font } from 'shared/utils/styles';
|
||||||
|
|
||||||
|
export const Container = styled.div`
|
||||||
|
color: ${color.textMedium};
|
||||||
|
${font.size(15)};
|
||||||
|
`;
|
||||||
|
|
||||||
|
export const Divider = styled.span`
|
||||||
|
position: relative;
|
||||||
|
top: 2px;
|
||||||
|
margin: 0 10px;
|
||||||
|
${font.size(18)};
|
||||||
|
`;
|
||||||
23
client/src/shared/components/Breadcrumbs/index.jsx
Normal file
23
client/src/shared/components/Breadcrumbs/index.jsx
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
import React, { Fragment } from 'react';
|
||||||
|
import PropTypes from 'prop-types';
|
||||||
|
|
||||||
|
import { Container, Divider } from './Styles';
|
||||||
|
|
||||||
|
const propTypes = {
|
||||||
|
items: PropTypes.array.isRequired,
|
||||||
|
};
|
||||||
|
|
||||||
|
const Breadcrumbs = ({ items }) => (
|
||||||
|
<Container>
|
||||||
|
{items.map((item, index) => (
|
||||||
|
<Fragment key={item}>
|
||||||
|
{index !== 0 && <Divider>/</Divider>}
|
||||||
|
{item}
|
||||||
|
</Fragment>
|
||||||
|
))}
|
||||||
|
</Container>
|
||||||
|
);
|
||||||
|
|
||||||
|
Breadcrumbs.propTypes = propTypes;
|
||||||
|
|
||||||
|
export default Breadcrumbs;
|
||||||
@@ -1,6 +1,7 @@
|
|||||||
export { default as AboutTooltip } from './AboutTooltip';
|
export { default as AboutTooltip } from './AboutTooltip';
|
||||||
export { default as Avatar } from './Avatar';
|
export { default as Avatar } from './Avatar';
|
||||||
export { default as Button } from './Button';
|
export { default as Button } from './Button';
|
||||||
|
export { default as Breadcrumbs } from './Breadcrumbs';
|
||||||
export { default as ConfirmModal } from './ConfirmModal';
|
export { default as ConfirmModal } from './ConfirmModal';
|
||||||
export { default as CopyLinkButton } from './CopyLinkButton';
|
export { default as CopyLinkButton } from './CopyLinkButton';
|
||||||
export { default as DatePicker } from './DatePicker';
|
export { default as DatePicker } from './DatePicker';
|
||||||
|
|||||||
Reference in New Issue
Block a user