summaryrefslogtreecommitdiffstatshomepage
path: root/webui/src
diff options
context:
space:
mode:
Diffstat (limited to 'webui/src')
-rw-r--r--webui/src/App.tsx2
-rw-r--r--webui/src/components/Author.tsx2
-rw-r--r--webui/src/components/BackToListButton.tsx2
-rw-r--r--webui/src/components/BugTitleForm/BugTitleForm.tsx4
-rw-r--r--webui/src/components/CommentInput/CommentInput.tsx2
-rw-r--r--webui/src/components/Content/AnchorTag.tsx2
-rw-r--r--webui/src/components/Date.tsx3
-rw-r--r--webui/src/components/Header/Header.tsx61
-rw-r--r--webui/src/components/Identity/CurrentIdentity.tsx2
-rw-r--r--webui/src/components/Identity/CurrentRepository.tsx19
-rw-r--r--webui/src/components/Moment.tsx28
-rw-r--r--webui/src/index.tsx11
-rw-r--r--webui/src/pages/bug/BugQuery.tsx5
-rw-r--r--webui/src/pages/bug/MessageHistoryDialog.tsx4
-rw-r--r--webui/src/pages/bug/TimelineQuery.tsx2
-rw-r--r--webui/src/pages/identity/BugList.tsx2
-rw-r--r--webui/src/pages/identity/Identity.tsx4
-rw-r--r--webui/src/pages/identity/IdentityQuery.tsx4
-rw-r--r--webui/src/pages/list/BugRow.tsx2
-rw-r--r--webui/src/pages/list/Filter.tsx2
-rw-r--r--webui/src/pages/list/FilterToolbar.tsx6
-rw-r--r--webui/src/pages/list/ListQuery.tsx2
-rw-r--r--webui/src/pages/new/NewBugPage.tsx2
-rw-r--r--webui/src/setupTests.js6
24 files changed, 92 insertions, 87 deletions
diff --git a/webui/src/App.tsx b/webui/src/App.tsx
index 4bf09606..173f35ff 100644
--- a/webui/src/App.tsx
+++ b/webui/src/App.tsx
@@ -1,4 +1,4 @@
-import { Route, Routes } from 'react-router-dom';
+import { Route, Routes } from 'react-router';
import Layout from './components/Header';
import BugPage from './pages/bug';
diff --git a/webui/src/components/Author.tsx b/webui/src/components/Author.tsx
index 92e14d40..51ed336a 100644
--- a/webui/src/components/Author.tsx
+++ b/webui/src/components/Author.tsx
@@ -1,7 +1,7 @@
import MAvatar from '@mui/material/Avatar';
import Link from '@mui/material/Link';
import Tooltip from '@mui/material/Tooltip/Tooltip';
-import { Link as RouterLink } from 'react-router-dom';
+import { Link as RouterLink } from 'react-router';
import { AuthoredFragment } from '../graphql/fragments.generated';
diff --git a/webui/src/components/BackToListButton.tsx b/webui/src/components/BackToListButton.tsx
index a4e4ea9c..234d1458 100644
--- a/webui/src/components/BackToListButton.tsx
+++ b/webui/src/components/BackToListButton.tsx
@@ -1,7 +1,7 @@
import ArrowBackIcon from '@mui/icons-material/ArrowBack';
import Button from '@mui/material/Button';
import makeStyles from '@mui/styles/makeStyles';
-import { Link } from 'react-router-dom';
+import { Link } from 'react-router';
const useStyles = makeStyles((theme) => ({
backButton: {
diff --git a/webui/src/components/BugTitleForm/BugTitleForm.tsx b/webui/src/components/BugTitleForm/BugTitleForm.tsx
index 78b9e901..82185d4f 100644
--- a/webui/src/components/BugTitleForm/BugTitleForm.tsx
+++ b/webui/src/components/BugTitleForm/BugTitleForm.tsx
@@ -1,7 +1,7 @@
import { Button, Typography } from '@mui/material';
import makeStyles from '@mui/styles/makeStyles';
import { useRef, useState } from 'react';
-import { Link } from 'react-router-dom';
+import { Link } from 'react-router';
import { TimelineDocument } from '../../pages/bug/TimelineQuery.generated';
import IfLoggedIn from '../IfLoggedIn/IfLoggedIn';
@@ -71,7 +71,7 @@ function BugTitleForm({ bug }: Props) {
const [setTitle, { loading, error }] = useSetTitleMutation();
const [issueTitle, setIssueTitle] = useState(bug.title);
const classes = useStyles();
- const issueTitleInput = useRef<HTMLInputElement>();
+ const issueTitleInput = useRef<HTMLInputElement>(null);
function isFormValid() {
if (issueTitleInput.current) {
diff --git a/webui/src/components/CommentInput/CommentInput.tsx b/webui/src/components/CommentInput/CommentInput.tsx
index 0fde1d95..4d4c3b63 100644
--- a/webui/src/components/CommentInput/CommentInput.tsx
+++ b/webui/src/components/CommentInput/CommentInput.tsx
@@ -102,7 +102,7 @@ function CommentInput({ inputProps, inputText, loading, onChange }: Props) {
multiline
value={input}
variant="filled"
- rows="4" // TODO: rowsMin support
+ minRows={4}
onChange={(e: any) => setInput(e.target.value)}
disabled={loading}
/>
diff --git a/webui/src/components/Content/AnchorTag.tsx b/webui/src/components/Content/AnchorTag.tsx
index e9edef95..da861bc2 100644
--- a/webui/src/components/Content/AnchorTag.tsx
+++ b/webui/src/components/Content/AnchorTag.tsx
@@ -1,6 +1,6 @@
import makeStyles from '@mui/styles/makeStyles';
import * as React from 'react';
-import { Link } from 'react-router-dom';
+import { Link } from 'react-router';
const useStyles = makeStyles((theme) => ({
tag: {
diff --git a/webui/src/components/Date.tsx b/webui/src/components/Date.tsx
index 1454fac7..19efc081 100644
--- a/webui/src/components/Date.tsx
+++ b/webui/src/components/Date.tsx
@@ -1,6 +1,7 @@
import Tooltip from '@mui/material/Tooltip/Tooltip';
import moment from 'moment';
-import Moment from 'react-moment';
+
+import Moment from './Moment';
const HOUR = 1000 * 3600;
const DAY = 24 * HOUR;
diff --git a/webui/src/components/Header/Header.tsx b/webui/src/components/Header/Header.tsx
index 5c03a5ec..69b3fdfb 100644
--- a/webui/src/components/Header/Header.tsx
+++ b/webui/src/components/Header/Header.tsx
@@ -1,13 +1,11 @@
import AppBar from '@mui/material/AppBar';
-import Tab, { TabProps } from '@mui/material/Tab';
-import Tabs from '@mui/material/Tabs';
import Toolbar from '@mui/material/Toolbar';
-import Tooltip from '@mui/material/Tooltip/Tooltip';
import { alpha } from '@mui/material/styles';
import makeStyles from '@mui/styles/makeStyles';
-import { Link, useLocation } from 'react-router-dom';
+import { Link } from 'react-router';
import CurrentIdentity from '../Identity/CurrentIdentity';
+import CurrentRepository from '../Identity/CurrentRepository';
import { LightSwitch } from '../Themer';
const useStyles = makeStyles((theme) => ({
@@ -29,7 +27,7 @@ const useStyles = makeStyles((theme) => ({
alignItems: 'center',
},
lightSwitch: {
- marginRight: '20px',
+ marginRight: theme.spacing(2),
color: alpha(theme.palette.primary.contrastText, 0.5),
},
logo: {
@@ -38,43 +36,8 @@ 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 accepts 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();
-
- // Prevents error of invalid tab selection in <Tabs>
- // Will return a valid tab path or false if path is unknown.
- function highlightTab() {
- const validTabs = ['/', '/code', '/pulls', '/settings'];
- const tab = validTabs.find((tabPath) => tabPath === location.pathname);
- return tab === undefined ? false : tab;
- }
return (
<>
@@ -82,28 +45,14 @@ function Header() {
<Toolbar>
<Link to="/" className={classes.appTitle}>
<img src="/logo.svg" className={classes.logo} alt="git-bug logo" />
- git-bug
+ <CurrentRepository default="git-bug" />
</Link>
<div className={classes.filler} />
<LightSwitch className={classes.lightSwitch} />
<CurrentIdentity />
</Toolbar>
</AppBar>
- <div className={classes.offset} />
- <Tabs centered value={highlightTab()} 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>
+ <div className={classes.offset}></div>
</>
);
}
diff --git a/webui/src/components/Identity/CurrentIdentity.tsx b/webui/src/components/Identity/CurrentIdentity.tsx
index e6a396a8..fb06898e 100644
--- a/webui/src/components/Identity/CurrentIdentity.tsx
+++ b/webui/src/components/Identity/CurrentIdentity.tsx
@@ -12,7 +12,7 @@ import {
import Avatar from '@mui/material/Avatar';
import makeStyles from '@mui/styles/makeStyles';
import { useState, useRef } from 'react';
-import { Link as RouterLink } from 'react-router-dom';
+import { Link as RouterLink } from 'react-router';
import { useCurrentIdentityQuery } from './CurrentIdentity.generated';
diff --git a/webui/src/components/Identity/CurrentRepository.tsx b/webui/src/components/Identity/CurrentRepository.tsx
new file mode 100644
index 00000000..77aa6839
--- /dev/null
+++ b/webui/src/components/Identity/CurrentRepository.tsx
@@ -0,0 +1,19 @@
+import { useCurrentIdentityQuery } from './CurrentIdentity.generated';
+
+// same as in multi_repo_cache.go
+const defaultRepoName = '__default';
+
+const CurrentRepository = (props: { default: string }) => {
+ const { loading, error, data } = useCurrentIdentityQuery();
+
+ if (error || loading || !data?.repository?.name) return null;
+
+ let name = data.repository.name;
+ if (name === defaultRepoName) {
+ name = props.default;
+ }
+
+ return <>{name}</>;
+};
+
+export default CurrentRepository;
diff --git a/webui/src/components/Moment.tsx b/webui/src/components/Moment.tsx
new file mode 100644
index 00000000..4bffbd31
--- /dev/null
+++ b/webui/src/components/Moment.tsx
@@ -0,0 +1,28 @@
+import moment from 'moment';
+
+type Props = {
+ date: moment.MomentInput;
+ format: string;
+ fromNowDuring?: number;
+};
+
+const Moment = ({ date, format, fromNowDuring }: Props) => {
+ let dateString: string | undefined;
+ const dateMoment = moment(date);
+
+ if (fromNowDuring) {
+ const diff = moment().diff(dateMoment, 'ms');
+ if (diff < fromNowDuring) {
+ dateString = dateMoment.fromNow();
+ }
+ }
+
+ // we either are out of range or didn't get asked for fromNow
+ if (dateString === undefined) {
+ dateString = dateMoment.format(format);
+ }
+
+ return <span>{dateString}</span>;
+};
+
+export default Moment;
diff --git a/webui/src/index.tsx b/webui/src/index.tsx
index d203eb19..a7cbe559 100644
--- a/webui/src/index.tsx
+++ b/webui/src/index.tsx
@@ -1,19 +1,20 @@
import { ApolloProvider } from '@apollo/client';
-import ReactDOM from 'react-dom';
-import { BrowserRouter } from 'react-router-dom';
+import React from 'react';
+import { createRoot } from 'react-dom/client';
+import { BrowserRouter } from 'react-router';
import App from './App';
import apolloClient from './apollo';
import Themer from './components/Themer';
import { defaultLightTheme, defaultDarkTheme } from './themes/index';
-ReactDOM.render(
+const root = createRoot(document.getElementById('root') as HTMLElement);
+root.render(
<ApolloProvider client={apolloClient}>
<BrowserRouter>
<Themer lightTheme={defaultLightTheme} darkTheme={defaultDarkTheme}>
<App />
</Themer>
</BrowserRouter>
- </ApolloProvider>,
- document.getElementById('root')
+ </ApolloProvider>
);
diff --git a/webui/src/pages/bug/BugQuery.tsx b/webui/src/pages/bug/BugQuery.tsx
index 244b0836..704dd037 100644
--- a/webui/src/pages/bug/BugQuery.tsx
+++ b/webui/src/pages/bug/BugQuery.tsx
@@ -1,6 +1,6 @@
import CircularProgress from '@mui/material/CircularProgress';
import * as React from 'react';
-import { useParams } from 'react-router-dom';
+import { useParams } from 'react-router';
import NotFoundPage from '../notfound/NotFoundPage';
@@ -16,7 +16,8 @@ const BugQuery: React.FC = () => {
});
if (loading) return <CircularProgress />;
if (!data?.repository?.bug) return <NotFoundPage />;
- if (error) return <p>Error: {error}</p>;
+ if (error) return <p>Error: {error.message}</p>;
+
return <Bug bug={data.repository.bug} />;
};
diff --git a/webui/src/pages/bug/MessageHistoryDialog.tsx b/webui/src/pages/bug/MessageHistoryDialog.tsx
index 77f82d86..7523d5c0 100644
--- a/webui/src/pages/bug/MessageHistoryDialog.tsx
+++ b/webui/src/pages/bug/MessageHistoryDialog.tsx
@@ -17,9 +17,9 @@ import createStyles from '@mui/styles/createStyles';
import withStyles from '@mui/styles/withStyles';
import moment from 'moment';
import * as React from 'react';
-import Moment from 'react-moment';
import Content from '../../components/Content';
+import Moment from '../../components/Moment';
import { AddCommentFragment } from './MessageCommentFragment.generated';
import { CreateFragment } from './MessageCreateFragment.generated';
@@ -159,7 +159,7 @@ function MessageHistoryDialog({ bugId, commentId, open, onClose }: Props) {
Something went wrong...
</DialogTitle>
<DialogContent dividers>
- <p>Error: {error}</p>
+ <p>Error: {error.message}</p>
</DialogContent>
</Dialog>
);
diff --git a/webui/src/pages/bug/TimelineQuery.tsx b/webui/src/pages/bug/TimelineQuery.tsx
index ab9e4cd6..3b55270c 100644
--- a/webui/src/pages/bug/TimelineQuery.tsx
+++ b/webui/src/pages/bug/TimelineQuery.tsx
@@ -17,7 +17,7 @@ const TimelineQuery = ({ bug }: Props) => {
});
if (loading) return <CircularProgress />;
- if (error) return <p>Error: {error}</p>;
+ if (error) return <p>Error: {error.message}</p>;
const nodes = data?.repository?.bug?.timeline.nodes;
if (!nodes) {
diff --git a/webui/src/pages/identity/BugList.tsx b/webui/src/pages/identity/BugList.tsx
index a7c37a32..7c661dc2 100644
--- a/webui/src/pages/identity/BugList.tsx
+++ b/webui/src/pages/identity/BugList.tsx
@@ -34,7 +34,7 @@ function BugList({ id }: Props) {
});
if (loading) return <CircularProgress />;
- if (error) return <p>Error: {error}</p>;
+ if (error) return <p>Error: {error.message}</p>;
const bugs = data?.repository?.allBugs.nodes;
return (
diff --git a/webui/src/pages/identity/Identity.tsx b/webui/src/pages/identity/Identity.tsx
index 19b80b1c..beced10d 100644
--- a/webui/src/pages/identity/Identity.tsx
+++ b/webui/src/pages/identity/Identity.tsx
@@ -5,7 +5,7 @@ import Avatar from '@mui/material/Avatar';
import CircularProgress from '@mui/material/CircularProgress';
import Grid from '@mui/material/Grid';
import makeStyles from '@mui/styles/makeStyles';
-import { Link as RouterLink } from 'react-router-dom';
+import { Link as RouterLink } from 'react-router';
import { IdentityFragment } from '../../components/Identity/IdentityFragment.generated';
@@ -56,7 +56,7 @@ const Identity = ({ identity }: Props) => {
});
if (loading) return <CircularProgress />;
- if (error) return <p>Error: {error}</p>;
+ if (error) return <p>Error: {error.message}</p>;
const statistic = data?.repository;
const authoredCount = statistic?.authored?.totalCount;
const participatedCount = statistic?.participated?.totalCount;
diff --git a/webui/src/pages/identity/IdentityQuery.tsx b/webui/src/pages/identity/IdentityQuery.tsx
index 382116ca..faa192f6 100644
--- a/webui/src/pages/identity/IdentityQuery.tsx
+++ b/webui/src/pages/identity/IdentityQuery.tsx
@@ -1,6 +1,6 @@
import CircularProgress from '@mui/material/CircularProgress';
import * as React from 'react';
-import { useParams } from 'react-router-dom';
+import { useParams } from 'react-router';
import { useGetUserByIdQuery } from '../../components/Identity/UserIdentity.generated';
@@ -14,7 +14,7 @@ const UserQuery: React.FC = () => {
variables: { userId: params.id },
});
if (loading) return <CircularProgress />;
- if (error) return <p>Error: {error}</p>;
+ if (error) return <p>Error: {error.message}</p>;
if (!data?.repository?.identity) return <p>404.</p>;
return <Identity identity={data.repository.identity} />;
};
diff --git a/webui/src/pages/list/BugRow.tsx b/webui/src/pages/list/BugRow.tsx
index 82582dbe..40f43613 100644
--- a/webui/src/pages/list/BugRow.tsx
+++ b/webui/src/pages/list/BugRow.tsx
@@ -6,7 +6,7 @@ import TableRow from '@mui/material/TableRow/TableRow';
import Tooltip from '@mui/material/Tooltip/Tooltip';
import makeStyles from '@mui/styles/makeStyles';
import * as React from 'react';
-import { Link } from 'react-router-dom';
+import { Link } from 'react-router';
import Author from 'src/components/Author';
import Date from 'src/components/Date';
diff --git a/webui/src/pages/list/Filter.tsx b/webui/src/pages/list/Filter.tsx
index 6b3422be..0ba5e71d 100644
--- a/webui/src/pages/list/Filter.tsx
+++ b/webui/src/pages/list/Filter.tsx
@@ -10,7 +10,7 @@ import withStyles from '@mui/styles/withStyles';
import clsx from 'clsx';
import * as React from 'react';
import { useRef, useState, useEffect } from 'react';
-import { Location, Link } from 'react-router-dom';
+import { Location, Link } from 'react-router';
import { Color } from '../../gqlTypes';
diff --git a/webui/src/pages/list/FilterToolbar.tsx b/webui/src/pages/list/FilterToolbar.tsx
index 5e774734..9b467e20 100644
--- a/webui/src/pages/list/FilterToolbar.tsx
+++ b/webui/src/pages/list/FilterToolbar.tsx
@@ -4,7 +4,7 @@ import ErrorOutline from '@mui/icons-material/ErrorOutline';
import Toolbar from '@mui/material/Toolbar';
import makeStyles from '@mui/styles/makeStyles';
import * as React from 'react';
-import { Location } from 'react-router-dom';
+import { Location } from 'react-router';
import {
Filter,
@@ -131,8 +131,8 @@ function FilterToolbar({ query, queryLocation }: Props) {
params[key] && params[key].includes(value)
? values.filter((v) => v !== value)
: values
- ? [...values, value]
- : [value],
+ ? [...values, value]
+ : [value],
};
};
const clearParam =
diff --git a/webui/src/pages/list/ListQuery.tsx b/webui/src/pages/list/ListQuery.tsx
index 6b508e90..98a7df42 100644
--- a/webui/src/pages/list/ListQuery.tsx
+++ b/webui/src/pages/list/ListQuery.tsx
@@ -13,7 +13,7 @@ import { Theme } from '@mui/material/styles';
import makeStyles from '@mui/styles/makeStyles';
import * as React from 'react';
import { useState, useEffect, useRef } from 'react';
-import { useLocation, useNavigate, Link } from 'react-router-dom';
+import { useLocation, useNavigate, Link } from 'react-router';
import { useCurrentIdentityQuery } from '../../components/Identity/CurrentIdentity.generated';
import IfLoggedIn from 'src/components/IfLoggedIn/IfLoggedIn';
diff --git a/webui/src/pages/new/NewBugPage.tsx b/webui/src/pages/new/NewBugPage.tsx
index 91e4905a..c0aa6b3f 100644
--- a/webui/src/pages/new/NewBugPage.tsx
+++ b/webui/src/pages/new/NewBugPage.tsx
@@ -2,7 +2,7 @@ import { Button, Paper } from '@mui/material';
import { Theme } from '@mui/material/styles';
import makeStyles from '@mui/styles/makeStyles';
import { FormEvent, useRef, useState } from 'react';
-import { useNavigate } from 'react-router-dom';
+import { useNavigate } from 'react-router';
import BugTitleInput from '../../components/BugTitleForm/BugTitleInput';
import CommentInput from '../../components/CommentInput/CommentInput';
diff --git a/webui/src/setupTests.js b/webui/src/setupTests.js
new file mode 100644
index 00000000..012e25a1
--- /dev/null
+++ b/webui/src/setupTests.js
@@ -0,0 +1,6 @@
+import { TextEncoder } from 'util';
+
+// jsdom, used to run tests, doesn't support text-encoder
+// https://github.com/remix-run/react-router/issues/12363
+
+global.TextEncoder = TextEncoder;