Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions webui/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion webui/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@
"eslint-config-prettier": "^6.12.0",
"eslint-plugin-graphql": "^4.0.0",
"eslint-plugin-prettier": "^3.1.4",
"prettier": "^2.1.2"
"prettier": "^2.2.1"
},
"scripts": {
"start": "npm run generate && react-scripts start",
Expand Down
2 changes: 2 additions & 0 deletions webui/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,14 @@ import { Route, Switch } from 'react-router';
import Layout from './layout';
import BugPage from './pages/bug';
import ListPage from './pages/list';
import NewBugPage from './pages/new/NewBugPage';

export default function App() {
return (
<Layout>
<Switch>
<Route path="/" exact component={ListPage} />
<Route path="/new" exact component={NewBugPage} />
<Route path="/bug/:id" exact component={BugPage} />
</Switch>
</Layout>
Expand Down
96 changes: 96 additions & 0 deletions webui/src/pages/bug/CommentInput.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
import React, { useState, useEffect } from 'react';

import Tab from '@material-ui/core/Tab';
import Tabs from '@material-ui/core/Tabs';
import TextField from '@material-ui/core/TextField';
import { makeStyles } from '@material-ui/core/styles';

import Content from 'src/components/Content';

const useStyles = makeStyles((theme) => ({
container: {
margin: theme.spacing(2, 0),
padding: theme.spacing(0, 2, 2, 2),
},
textarea: {},
tabContent: {
margin: theme.spacing(2, 0),
},
preview: {
borderBottom: `solid 3px ${theme.palette.grey['200']}`,
minHeight: '5rem',
},
actions: {
display: 'flex',
justifyContent: 'flex-end',
},
}));

type TabPanelProps = {
children: React.ReactNode;
value: number;
index: number;
} & React.HTMLProps<HTMLDivElement>;
function TabPanel({ children, value, index, ...props }: TabPanelProps) {
return (
<div
role="tabpanel"
hidden={value !== index}
id={`editor-tabpanel-${index}`}
aria-labelledby={`editor-tab-${index}`}
{...props}
>
{value === index && children}
</div>
);
}

const a11yProps = (index: number) => ({
id: `editor-tab-${index}`,
'aria-controls': `editor-tabpanel-${index}`,
});

type Props = {
loading: boolean;
onChange: (comment: string) => void;
};

function CommentInput({ loading, onChange }: Props) {
const [input, setInput] = useState<string>('');
const [tab, setTab] = useState(0);
const classes = useStyles();

useEffect(() => {
onChange(input);
}, [input, onChange]);

return (
<div>
<Tabs value={tab} onChange={(_, t) => setTab(t)}>
<Tab label="Write" {...a11yProps(0)} />
<Tab label="Preview" {...a11yProps(1)} />
</Tabs>
<div className={classes.tabContent}>
<TabPanel value={tab} index={0}>
<TextField
fullWidth
label="Comment"
placeholder="Leave a comment"
className={classes.textarea}
multiline
value={input}
variant="filled"
rows="4" // TODO: rowsMin support
onChange={(e: any) => setInput(e.target.value)}
disabled={loading}
/>
</TabPanel>
<TabPanel value={tab} index={1} className={classes.preview}>
<Content markdown={input} />
</TabPanel>
</div>
</div>
);
}

export default CommentInput;
57 changes: 42 additions & 15 deletions webui/src/pages/list/ListQuery.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { ApolloError } from '@apollo/client';
import React, { useState, useEffect, useRef } from 'react';
import { useLocation, useHistory, Link } from 'react-router-dom';

import { Button } from '@material-ui/core';
import IconButton from '@material-ui/core/IconButton';
import InputBase from '@material-ui/core/InputBase';
import Paper from '@material-ui/core/Paper';
Expand Down Expand Up @@ -40,6 +41,17 @@ const useStyles = makeStyles<Theme, StylesProps>((theme) => ({
alignItems: 'center',
justifyContent: 'space-between',
},
filterissueLabel: {
fontSize: '14px',
fontWeight: 'bold',
paddingRight: '12px',
},
filterissueContainer: {
display: 'flex',
flexDirection: 'row',
alignItems: 'flex-start',
justifyContents: 'left',
},
search: {
borderRadius: theme.shape.borderRadius,
borderColor: fade(theme.palette.primary.main, 0.2),
Expand Down Expand Up @@ -95,6 +107,13 @@ const useStyles = makeStyles<Theme, StylesProps>((theme) => ({
padding: theme.spacing(2, 3),
},
},
greenButton: {
backgroundColor: '#2ea44fd9',
color: '#fff',
'&:hover': {
backgroundColor: '#2ea44f',
},
},
}));

function editParams(
Expand Down Expand Up @@ -271,21 +290,29 @@ function ListQuery() {
return (
<Paper className={classes.main}>
<header className={classes.header}>
<h1>Issues</h1>
<form onSubmit={formSubmit}>
<InputBase
placeholder="Filter"
value={input}
onInput={(e: any) => setInput(e.target.value)}
classes={{
root: classes.search,
focused: classes.searchFocused,
}}
/>
<button type="submit" hidden>
Search
</button>
</form>
<div className="filterissueContainer">
<form onSubmit={formSubmit}>
<label className={classes.filterissueLabel} htmlFor="issuefilter">
Filter
</label>
<InputBase
id="issuefilter"
placeholder="Filter"
value={input}
onInput={(e: any) => setInput(e.target.value)}
classes={{
root: classes.search,
focused: classes.searchFocused,
}}
/>
<button type="submit" hidden>
Search
</button>
</form>
</div>
<Button className={classes.greenButton} variant="contained" href="/new">
New issue
</Button>
</header>
<FilterToolbar query={query} queryLocation={queryLocation} />
{content}
Expand Down
7 changes: 7 additions & 0 deletions webui/src/pages/new/NewBug.graphql
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
mutation newBug($input: NewBugInput!) {
newBug(input: $input) {
bug {
humanId
}
}
}
121 changes: 121 additions & 0 deletions webui/src/pages/new/NewBugPage.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
import React, { FormEvent, useState } from 'react';

import { Button } from '@material-ui/core';
import Paper from '@material-ui/core/Paper';
import TextField from '@material-ui/core/TextField/TextField';
import { fade, makeStyles, Theme } from '@material-ui/core/styles';

import CommentInput from '../bug/CommentInput';

import { useNewBugMutation } from './NewBug.generated';

/**
* Css in JS styles
*/
const useStyles = makeStyles((theme: Theme) => ({
main: {
maxWidth: 800,
margin: 'auto',
marginTop: theme.spacing(4),
marginBottom: theme.spacing(4),
padding: theme.spacing(2),
overflow: 'hidden',
},
titleInput: {
borderRadius: theme.shape.borderRadius,
borderColor: fade(theme.palette.primary.main, 0.2),
borderStyle: 'solid',
borderWidth: '1px',
backgroundColor: fade(theme.palette.primary.main, 0.05),
padding: theme.spacing(0, 0),
transition: theme.transitions.create([
'width',
'borderColor',
'backgroundColor',
]),
},
form: {
display: 'flex',
flexDirection: 'column',
},
actions: {
display: 'flex',
justifyContent: 'flex-end',
},
gitbugButton: {
backgroundColor: '#2ea44fd9',
color: '#fff',
'&:hover': {
backgroundColor: '#2ea44f',
},
},
}));

/**
* Form to create a new issue
*/
function NewBugPage() {
const [newBug, { loading, error }] = useNewBugMutation();
const [issueTitle, setIssueTitle] = useState('');
const [issueComment, setIssueComment] = useState('');
const classes = useStyles();
let issueTitleInput: any;

function submitNewIssue(e: FormEvent) {
e.preventDefault();
if (!isFormValid()) return;
console.log('submitNewISsue');
console.log('title: ', issueTitle);
console.log('comment: ', issueComment);
newBug({
variables: {
input: {
title: issueTitle,
message: issueComment,
},
},
});
issueTitleInput.value = '';
}

function isFormValid() {
return issueTitle.length > 0 && issueComment.length > 0 ? true : false;
}

if (loading) return <div>Loading</div>;
if (error) return <div>Error</div>;

return (
<Paper className={classes.main}>
<form className={classes.form} onSubmit={submitNewIssue}>
<TextField
inputRef={(node) => {
issueTitleInput = node;
}}
label="Title"
className={classes.titleInput}
variant="outlined"
fullWidth
margin="dense"
onChange={(event: any) => setIssueTitle(event.target.value)}
/>
<CommentInput
loading={false}
onChange={(comment: string) => setIssueComment(comment)}
/>
<div className={classes.actions}>
<Button
className={classes.gitbugButton}
variant="contained"
type="submit"
disabled={isFormValid() ? false : true}
>
Submit new issue
</Button>
</div>
</form>
</Paper>
);
}

export default NewBugPage;