diff options
Diffstat (limited to 'webui/src')
-rw-r--r-- | webui/src/App.tsx | 2 | ||||
-rw-r--r-- | webui/src/components/BackToListButton.tsx | 36 | ||||
-rw-r--r-- | webui/src/components/BugTitleForm/BugTitleForm.tsx | 2 | ||||
-rw-r--r-- | webui/src/components/Content/PreTag.tsx | 2 | ||||
-rw-r--r-- | webui/src/components/Header/Header.tsx | 73 | ||||
-rw-r--r-- | webui/src/pages/bug/Bug.tsx | 19 | ||||
-rw-r--r-- | webui/src/pages/bug/BugQuery.tsx | 4 | ||||
-rw-r--r-- | webui/src/pages/bug/CommentForm.tsx | 1 | ||||
-rw-r--r-- | webui/src/pages/list/BugRow.graphql | 3 | ||||
-rw-r--r-- | webui/src/pages/list/BugRow.tsx | 16 | ||||
-rw-r--r-- | webui/src/pages/list/FilterToolbar.tsx | 2 | ||||
-rw-r--r-- | webui/src/pages/new/NewBugPage.tsx | 11 | ||||
-rw-r--r-- | webui/src/pages/notfound/NotFoundPage.tsx | 52 | ||||
-rw-r--r-- | webui/src/themes/DefaultDark.ts | 3 | ||||
-rw-r--r-- | webui/src/themes/DefaultLight.ts | 4 |
15 files changed, 208 insertions, 22 deletions
diff --git a/webui/src/App.tsx b/webui/src/App.tsx index b9ade974..4c81913c 100644 --- a/webui/src/App.tsx +++ b/webui/src/App.tsx @@ -5,6 +5,7 @@ import Layout from './components/Header'; import BugPage from './pages/bug'; import ListPage from './pages/list'; import NewBugPage from './pages/new/NewBugPage'; +import NotFoundPage from './pages/notfound/NotFoundPage'; export default function App() { return ( @@ -13,6 +14,7 @@ export default function App() { <Route path="/" exact component={ListPage} /> <Route path="/new" exact component={NewBugPage} /> <Route path="/bug/:id" exact component={BugPage} /> + <Route component={NotFoundPage} /> </Switch> </Layout> ); diff --git a/webui/src/components/BackToListButton.tsx b/webui/src/components/BackToListButton.tsx new file mode 100644 index 00000000..7ca53ad0 --- /dev/null +++ b/webui/src/components/BackToListButton.tsx @@ -0,0 +1,36 @@ +import React from 'react'; + +import Button from '@material-ui/core/Button'; +import { makeStyles } from '@material-ui/core/styles'; +import ArrowBackIcon from '@material-ui/icons/ArrowBack'; + +const useStyles = makeStyles((theme) => ({ + backButton: { + position: 'sticky', + top: '80px', + backgroundColor: theme.palette.primary.dark, + color: theme.palette.primary.contrastText, + '&:hover': { + backgroundColor: theme.palette.primary.main, + color: theme.palette.primary.contrastText, + }, + }, +})); + +function BackToListButton() { + const classes = useStyles(); + + return ( + <Button + variant="contained" + className={classes.backButton} + aria-label="back to issue list" + href="/" + > + <ArrowBackIcon /> + Back to List + </Button> + ); +} + +export default BackToListButton; diff --git a/webui/src/components/BugTitleForm/BugTitleForm.tsx b/webui/src/components/BugTitleForm/BugTitleForm.tsx index cc9f5267..a7d5a820 100644 --- a/webui/src/components/BugTitleForm/BugTitleForm.tsx +++ b/webui/src/components/BugTitleForm/BugTitleForm.tsx @@ -70,7 +70,7 @@ function BugTitleForm({ bug }: Props) { function isFormValid() { if (issueTitleInput) { - return issueTitleInput.value.length > 0 ? true : false; + return issueTitleInput.value.length > 0; } else { return false; } diff --git a/webui/src/components/Content/PreTag.tsx b/webui/src/components/Content/PreTag.tsx index 5256ab12..8e352153 100644 --- a/webui/src/components/Content/PreTag.tsx +++ b/webui/src/components/Content/PreTag.tsx @@ -11,7 +11,7 @@ const useStyles = makeStyles({ const PreTag = (props: React.HTMLProps<HTMLPreElement>) => { const classes = useStyles(); - return <pre className={classes.tag} {...props}></pre>; + return <pre className={classes.tag} {...props} />; }; export default PreTag; diff --git a/webui/src/components/Header/Header.tsx b/webui/src/components/Header/Header.tsx index 3bdb252f..3064f6e4 100644 --- a/webui/src/components/Header/Header.tsx +++ b/webui/src/components/Header/Header.tsx @@ -1,12 +1,15 @@ import React from 'react'; -import { Link } from 'react-router-dom'; +import { Link, useLocation } from 'react-router-dom'; import AppBar from '@material-ui/core/AppBar'; +import Tab, { TabProps } from '@material-ui/core/Tab'; +import Tabs from '@material-ui/core/Tabs'; import Toolbar from '@material-ui/core/Toolbar'; +import Tooltip from '@material-ui/core/Tooltip/Tooltip'; import { makeStyles } from '@material-ui/core/styles'; -import { LightSwitch } from '../../components/Themer'; import CurrentIdentity from '../CurrentIdentity/CurrentIdentity'; +import { LightSwitch } from '../Themer'; const useStyles = makeStyles((theme) => ({ offset: { @@ -15,9 +18,13 @@ const useStyles = makeStyles((theme) => ({ filler: { flexGrow: 1, }, + appBar: { + backgroundColor: theme.palette.primary.dark, + color: theme.palette.primary.contrastText, + }, appTitle: { ...theme.typography.h6, - color: 'white', + color: theme.palette.primary.contrastText, textDecoration: 'none', display: 'flex', alignItems: 'center', @@ -31,18 +38,53 @@ const useStyles = makeStyles((theme) => ({ }, })); +function a11yProps(index: any) { + return { + id: `nav-tab-${index}`, + 'aria-controls': `nav-tabpanel-${index}`, + }; +} + +const DisabledTabWithTooltip = (props: TabProps) => { + /*The span elements around disabled tabs are needed, as the tooltip + * won't be triggered by disabled elements. + * See: https://material-ui.com/components/tooltips/#disabled-elements + * This must be done in a wrapper component, otherwise the TabS component + * cannot pass it styles down to the Tab component. Resulting in (console) + * warnings. This wrapper acceps the passed down TabProps and pass it around + * the span element to the Tab component. + */ + const msg = `This feature doesn't exist yet. Come help us build it.`; + return ( + <Tooltip title={msg}> + <span> + <Tab disabled {...props} /> + </span> + </Tooltip> + ); +}; + function Header() { const classes = useStyles(); + const location = useLocation(); + const [selectedTab, setTab] = React.useState(location.pathname); + + const handleTabClick = ( + event: React.ChangeEvent<{}>, + newTabValue: string + ) => { + setTab(newTabValue); + }; return ( <> - <AppBar position="fixed" color="primary"> + <AppBar position="fixed" className={classes.appBar}> <Toolbar> <Link to="/" className={classes.appTitle}> - <img src="/logo.svg" className={classes.logo} alt="git-bug" /> + <img src="/logo.svg" className={classes.logo} alt="git-bug logo" /> git-bug </Link> - <div className={classes.filler}></div> + <div className={classes.filler} /> <div className={classes.lightSwitch}> <LightSwitch /> </div> @@ -50,6 +92,25 @@ function Header() { </Toolbar> </AppBar> <div className={classes.offset} /> + <Tabs + centered + value={selectedTab} + onChange={handleTabClick} + aria-label="nav tabs" + > + <DisabledTabWithTooltip label="Code" value="/code" {...a11yProps(1)} /> + <Tab label="Bugs" value="/" component={Link} to="/" {...a11yProps(2)} /> + <DisabledTabWithTooltip + label="Pull Requests" + value="/pulls" + {...a11yProps(3)} + /> + <DisabledTabWithTooltip + label="Settings" + value="/settings" + {...a11yProps(4)} + /> + </Tabs> </> ); } diff --git a/webui/src/pages/bug/Bug.tsx b/webui/src/pages/bug/Bug.tsx index 83785a37..25281f96 100644 --- a/webui/src/pages/bug/Bug.tsx +++ b/webui/src/pages/bug/Bug.tsx @@ -18,11 +18,17 @@ const useStyles = makeStyles((theme) => ({ maxWidth: 1000, margin: 'auto', marginTop: theme.spacing(4), - overflow: 'hidden', }, header: { - marginLeft: theme.spacing(3) + 40, marginRight: theme.spacing(2), + marginLeft: theme.spacing(3) + 40, + }, + title: { + ...theme.typography.h5, + }, + id: { + ...theme.typography.subtitle1, + marginLeft: theme.spacing(1), }, container: { display: 'flex', @@ -36,11 +42,11 @@ const useStyles = makeStyles((theme) => ({ marginRight: theme.spacing(2), minWidth: 400, }, - sidebar: { + rightSidebar: { marginTop: theme.spacing(2), flex: '0 0 200px', }, - sidebarTitle: { + rightSidebarTitle: { fontWeight: 'bold', }, labelList: { @@ -76,7 +82,6 @@ function Bug({ bug }: Props) { <div className={classes.header}> <BugTitleForm bug={bug} /> </div> - <div className={classes.container}> <div className={classes.timeline}> <TimelineQuery bug={bug} /> @@ -88,8 +93,8 @@ function Bug({ bug }: Props) { )} </IfLoggedIn> </div> - <div className={classes.sidebar}> - <span className={classes.sidebarTitle}>Labels</span> + <div className={classes.rightSidebar}> + <span className={classes.rightSidebarTitle}>Labels</span> <ul className={classes.labelList}> {bug.labels.length === 0 && ( <span className={classes.noLabel}>None yet</span> diff --git a/webui/src/pages/bug/BugQuery.tsx b/webui/src/pages/bug/BugQuery.tsx index 2a70a2f8..5d459c42 100644 --- a/webui/src/pages/bug/BugQuery.tsx +++ b/webui/src/pages/bug/BugQuery.tsx @@ -3,6 +3,8 @@ import { RouteComponentProps } from 'react-router-dom'; import CircularProgress from '@material-ui/core/CircularProgress'; +import NotFoundPage from '../notfound/NotFoundPage'; + import Bug from './Bug'; import { useGetBugQuery } from './BugQuery.generated'; @@ -15,8 +17,8 @@ const BugQuery: React.FC<Props> = ({ match }: Props) => { variables: { id: match.params.id }, }); if (loading) return <CircularProgress />; + if (!data?.repository?.bug) return <NotFoundPage />; if (error) return <p>Error: {error}</p>; - if (!data?.repository?.bug) return <p>404.</p>; return <Bug bug={data.repository.bug} />; }; diff --git a/webui/src/pages/bug/CommentForm.tsx b/webui/src/pages/bug/CommentForm.tsx index fe9536ac..e70348a6 100644 --- a/webui/src/pages/bug/CommentForm.tsx +++ b/webui/src/pages/bug/CommentForm.tsx @@ -27,6 +27,7 @@ const useStyles = makeStyles<Theme, StyleProps>((theme) => ({ }, actions: { display: 'flex', + gap: '1em', justifyContent: 'flex-end', }, greenButton: { diff --git a/webui/src/pages/list/BugRow.graphql b/webui/src/pages/list/BugRow.graphql index 547c09d8..e4e2760c 100644 --- a/webui/src/pages/list/BugRow.graphql +++ b/webui/src/pages/list/BugRow.graphql @@ -9,5 +9,8 @@ fragment BugRow on Bug { labels { ...Label } + comments { + totalCount + } ...authored } diff --git a/webui/src/pages/list/BugRow.tsx b/webui/src/pages/list/BugRow.tsx index 8d8fb5cb..1f5d22aa 100644 --- a/webui/src/pages/list/BugRow.tsx +++ b/webui/src/pages/list/BugRow.tsx @@ -6,6 +6,7 @@ import TableRow from '@material-ui/core/TableRow/TableRow'; import Tooltip from '@material-ui/core/Tooltip/Tooltip'; import { makeStyles } from '@material-ui/core/styles'; import CheckCircleOutline from '@material-ui/icons/CheckCircleOutline'; +import CommentOutlinedIcon from '@material-ui/icons/CommentOutlined'; import ErrorOutline from '@material-ui/icons/ErrorOutline'; import Date from 'src/components/Date'; @@ -74,6 +75,13 @@ const useStyles = makeStyles((theme) => ({ display: 'inline-block', }, }, + commentCount: { + fontSize: '1rem', + marginLeft: theme.spacing(0.5), + }, + commentCountCell: { + display: 'inline-flex', + }, })); type Props = { @@ -82,6 +90,8 @@ type Props = { function BugRow({ bug }: Props) { const classes = useStyles(); + // Subtract 1 from totalCount as 1 comment is the bug description + const commentCount = bug.comments.totalCount - 1; return ( <TableRow hover> <TableCell className={classes.cell}> @@ -105,6 +115,12 @@ function BugRow({ bug }: Props) { by {bug.author.displayName} </div> </div> + {commentCount > 0 && ( + <span className={classes.commentCountCell}> + <CommentOutlinedIcon aria-label="Comment count" /> + <span className={classes.commentCount}>{commentCount}</span> + </span> + )} </TableCell> </TableRow> ); diff --git a/webui/src/pages/list/FilterToolbar.tsx b/webui/src/pages/list/FilterToolbar.tsx index e4cd8e6a..74eefe4c 100644 --- a/webui/src/pages/list/FilterToolbar.tsx +++ b/webui/src/pages/list/FilterToolbar.tsx @@ -40,7 +40,7 @@ function CountingFilter({ query, children, ...props }: CountingFilterProps) { variables: { query }, }); - var prefix; + let prefix; if (loading) prefix = '...'; else if (error || !data?.repository) prefix = '???'; // TODO: better prefixes & error handling diff --git a/webui/src/pages/new/NewBugPage.tsx b/webui/src/pages/new/NewBugPage.tsx index 96afb56a..4dc60e3c 100644 --- a/webui/src/pages/new/NewBugPage.tsx +++ b/webui/src/pages/new/NewBugPage.tsx @@ -1,7 +1,7 @@ import React, { FormEvent, useState } from 'react'; +import { useHistory } from 'react-router-dom'; -import { Button } from '@material-ui/core'; -import Paper from '@material-ui/core/Paper'; +import { Button, Paper } from '@material-ui/core'; import { makeStyles, Theme } from '@material-ui/core/styles'; import BugTitleInput from '../../components/BugTitleForm/BugTitleInput'; @@ -47,7 +47,9 @@ function NewBugPage() { const [issueTitle, setIssueTitle] = useState(''); const [issueComment, setIssueComment] = useState(''); const classes = useStyles(); + let issueTitleInput: any; + let history = useHistory(); function submitNewIssue(e: FormEvent) { e.preventDefault(); @@ -59,12 +61,15 @@ function NewBugPage() { message: issueComment, }, }, + }).then(function (data) { + const id = data.data?.newBug.bug.humanId; + history.push('/bug/' + id); }); issueTitleInput.value = ''; } function isFormValid() { - return issueTitle.length > 0 && issueComment.length > 0 ? true : false; + return issueTitle.length > 0; } if (loading) return <div>Loading...</div>; diff --git a/webui/src/pages/notfound/NotFoundPage.tsx b/webui/src/pages/notfound/NotFoundPage.tsx new file mode 100644 index 00000000..2c6f6854 --- /dev/null +++ b/webui/src/pages/notfound/NotFoundPage.tsx @@ -0,0 +1,52 @@ +import React from 'react'; + +import { makeStyles } from '@material-ui/core/styles'; + +import BackToListButton from '../../components/BackToListButton'; + +const useStyles = makeStyles((theme) => ({ + main: { + maxWidth: 1000, + margin: 'auto', + marginTop: theme.spacing(10), + }, + logo: { + height: '350px', + display: 'block', + marginLeft: 'auto', + marginRight: 'auto', + }, + icon: { + display: 'block', + marginLeft: 'auto', + marginRight: 'auto', + fontSize: '80px', + }, + backLink: { + marginTop: theme.spacing(1), + textAlign: 'center', + }, + header: { + fontSize: '30px', + textAlign: 'center', + }, +})); + +function NotFoundPage() { + const classes = useStyles(); + return ( + <main className={classes.main}> + <h1 className={classes.header}>404 – Page not found</h1> + <img + src="/logo-alpha-flat-outline.svg" + className={classes.logo} + alt="git-bug Logo" + /> + <div className={classes.backLink}> + <BackToListButton /> + </div> + </main> + ); +} + +export default NotFoundPage; diff --git a/webui/src/themes/DefaultDark.ts b/webui/src/themes/DefaultDark.ts index 6a92ec49..65dd6329 100644 --- a/webui/src/themes/DefaultDark.ts +++ b/webui/src/themes/DefaultDark.ts @@ -4,7 +4,8 @@ const defaultDarkTheme = createMuiTheme({ palette: { type: 'dark', primary: { - main: '#263238', + dark: '#263238', + main: '#2a393e', light: '#525252', }, error: { diff --git a/webui/src/themes/DefaultLight.ts b/webui/src/themes/DefaultLight.ts index bc788a98..9c57ebe5 100644 --- a/webui/src/themes/DefaultLight.ts +++ b/webui/src/themes/DefaultLight.ts @@ -4,8 +4,10 @@ const defaultLightTheme = createMuiTheme({ palette: { type: 'light', primary: { - main: '#263238', + dark: '#263238', + main: '#5a6b73', light: '#f5f5f5', + contrastText: '#fff', }, info: { main: '#e2f1ff', |