diff --git a/webui/src/Author.js b/webui/src/Author.tsx similarity index 72% rename from webui/src/Author.js rename to webui/src/Author.tsx index 7bb1bf3c..475244db 100644 --- a/webui/src/Author.js +++ b/webui/src/Author.tsx @@ -2,7 +2,10 @@ import Tooltip from '@material-ui/core/Tooltip/Tooltip'; import MAvatar from '@material-ui/core/Avatar'; import React from 'react'; -const Author = ({ author, ...props }) => { +import { AuthoredFragment } from './Author.generated'; + +type Props = AuthoredFragment; +const Author = ({ author, ...props }: Props) => { if (!author.email) { return {author.displayName}; } @@ -14,7 +17,7 @@ const Author = ({ author, ...props }) => { ); }; -export const Avatar = ({ author, ...props }) => { +export const Avatar = ({ author, ...props }: Props) => { if (author.avatarUrl) { return ; } diff --git a/webui/src/Content.js b/webui/src/Content.tsx similarity index 67% rename from webui/src/Content.js rename to webui/src/Content.tsx index 3a6900bc..9683f478 100644 --- a/webui/src/Content.js +++ b/webui/src/Content.tsx @@ -2,10 +2,12 @@ import unified from 'unified'; import parse from 'remark-parse'; import html from 'remark-html'; import remark2react from 'remark-react'; +import { ReactNode } from 'react'; import ImageTag from './tag/ImageTag'; import PreTag from './tag/PreTag'; -const Content = ({ markdown }) => { +type Props = { markdown: string }; +const Content = ({ markdown }: Props) => { const processor = unified() .use(parse) .use(html) @@ -16,7 +18,8 @@ const Content = ({ markdown }) => { }, }); - return processor.processSync(markdown).contents; + const contents: ReactNode = processor.processSync(markdown).contents; + return contents; }; export default Content; diff --git a/webui/src/CurrentIdentity.graphql b/webui/src/CurrentIdentity.graphql new file mode 100644 index 00000000..6c000a2e --- /dev/null +++ b/webui/src/CurrentIdentity.graphql @@ -0,0 +1,8 @@ +query CurrentIdentity { + defaultRepository { + userIdentity { + displayName + avatarUrl + } + } +} diff --git a/webui/src/CurrentIdentity.js b/webui/src/CurrentIdentity.js deleted file mode 100644 index 451979fb..00000000 --- a/webui/src/CurrentIdentity.js +++ /dev/null @@ -1,45 +0,0 @@ -import React from 'react'; -import gql from 'graphql-tag'; -import { Query } from 'react-apollo'; -import Avatar from '@material-ui/core/Avatar'; -import { makeStyles } from '@material-ui/styles'; - -const useStyles = makeStyles(theme => ({ - displayName: { - marginLeft: theme.spacing(2), - }, -})); - -const QUERY = gql` - { - defaultRepository { - userIdentity { - displayName - avatarUrl - } - } - } -`; - -const CurrentIdentity = () => { - const classes = useStyles(); - return ( - - {({ loading, error, data }) => { - if (error || loading || !data.defaultRepository.userIdentity) - return null; - const user = data.defaultRepository.userIdentity; - return ( - <> - - {user.displayName.charAt(0).toUpperCase()} - -
{user.displayName}
- - ); - }} -
- ); -}; - -export default CurrentIdentity; diff --git a/webui/src/CurrentIdentity.tsx b/webui/src/CurrentIdentity.tsx new file mode 100644 index 00000000..0a697cdd --- /dev/null +++ b/webui/src/CurrentIdentity.tsx @@ -0,0 +1,31 @@ +import React from 'react'; +import Avatar from '@material-ui/core/Avatar'; +import { makeStyles } from '@material-ui/core/styles'; + +import { useCurrentIdentityQuery } from './CurrentIdentity.generated'; + +const useStyles = makeStyles(theme => ({ + displayName: { + marginLeft: theme.spacing(2), + }, +})); + +const CurrentIdentity = () => { + const classes = useStyles(); + const { loading, error, data } = useCurrentIdentityQuery(); + + if (error || loading || !data?.defaultRepository?.userIdentity) + return null; + + const user = data.defaultRepository.userIdentity; + return ( + <> + + {user.displayName.charAt(0).toUpperCase()} + +
{user.displayName}
+ + ); +}; + +export default CurrentIdentity; diff --git a/webui/src/Date.js b/webui/src/Date.tsx similarity index 70% rename from webui/src/Date.js rename to webui/src/Date.tsx index 46741924..9380d2fc 100644 --- a/webui/src/Date.js +++ b/webui/src/Date.tsx @@ -1,8 +1,9 @@ import Tooltip from '@material-ui/core/Tooltip/Tooltip'; -import * as moment from 'moment'; +import moment from 'moment'; import React from 'react'; -const Date = ({ date }) => ( +type Props = { date: string }; +const Date = ({ date }: Props) => ( {moment(date).fromNow()} diff --git a/webui/src/Label.js b/webui/src/Label.tsx similarity index 73% rename from webui/src/Label.js rename to webui/src/Label.tsx index fdb8ed4d..e200f929 100644 --- a/webui/src/Label.js +++ b/webui/src/Label.tsx @@ -1,24 +1,27 @@ import React from 'react'; -import { makeStyles } from '@material-ui/styles'; +import { makeStyles } from '@material-ui/core/styles'; import { getContrastRatio, darken, } from '@material-ui/core/styles/colorManipulator'; import { common } from '@material-ui/core/colors'; +import { Color } from './gqlTypes'; +import { LabelFragment } from './Label.generated'; + // Minimum contrast between the background and the text color const contrastThreshold = 2.5; // Guess the text color based on the background color -const getTextColor = background => +const getTextColor = (background: string) => getContrastRatio(background, common.white) >= contrastThreshold ? common.white // White on dark backgrounds : common.black; // And black on light ones -const _rgb = color => 'rgb(' + color.R + ',' + color.G + ',' + color.B + ')'; +const _rgb = (color: Color) => 'rgb(' + color.R + ',' + color.G + ',' + color.B + ')'; // Create a style object from the label RGB colors -const createStyle = color => ({ +const createStyle = (color: Color) => ({ backgroundColor: _rgb(color), color: getTextColor(_rgb(color)), borderBottomColor: darken(_rgb(color), 0.2), @@ -29,7 +32,7 @@ const useStyles = makeStyles(theme => ({ ...theme.typography.body1, padding: '1px 6px 0.5px', fontSize: '0.9em', - fontWeight: '500', + fontWeight: 500, margin: '0.05em 1px calc(-1.5px + 0.05em)', borderRadius: '3px', display: 'inline-block', @@ -38,7 +41,8 @@ const useStyles = makeStyles(theme => ({ }, })); -function Label({ label }) { +type Props = { label: LabelFragment }; +function Label({ label }: Props) { const classes = useStyles(); return ( diff --git a/webui/tsconfig.json b/webui/tsconfig.json index f2850b71..705bae44 100644 --- a/webui/tsconfig.json +++ b/webui/tsconfig.json @@ -17,7 +17,11 @@ "resolveJsonModule": true, "isolatedModules": true, "noEmit": true, - "jsx": "react" + "jsx": "react", + "typeRoots": [ + "node_modules/@types/", + "types/" + ] }, "include": [ "src" diff --git a/webui/types/remark-html/index.d.ts b/webui/types/remark-html/index.d.ts new file mode 100644 index 00000000..6b6e7ef7 --- /dev/null +++ b/webui/types/remark-html/index.d.ts @@ -0,0 +1,6 @@ +declare module "remark-html" { + import { Plugin } from 'unified'; + + const plugin: Plugin; + export default plugin; +}; diff --git a/webui/types/remark-react/index.d.ts b/webui/types/remark-react/index.d.ts new file mode 100644 index 00000000..aa5e6bcb --- /dev/null +++ b/webui/types/remark-react/index.d.ts @@ -0,0 +1,6 @@ +declare module "remark-react" { + import { Plugin } from 'unified'; + + const plugin: Plugin; + export default plugin; +};