[CORL-423] Rearrange client files and folder (#2352)

* chore: reorganize account

* chore: reorganize install

* chore: reorganize auth files

* chore: reorganize admin files

* fix: graphql naming

* chore: adapt account routing
This commit is contained in:
Vinh
2019-06-11 15:33:46 +00:00
committed by Wyatt Johnson
parent 05c8f06ed8
commit 3947b143cb
559 changed files with 1691 additions and 1755 deletions
+36
View File
@@ -0,0 +1,36 @@
import TransitionControl from "coral-framework/testHelpers/TransitionControl";
import { BrowserProtocol, queryMiddleware } from "farce";
import { createFarceRouter, ElementsRenderer } from "found";
import { Resolver } from "found-relay";
import React, { FunctionComponent } from "react";
import { CoralContextConsumer } from "coral-framework/lib/bootstrap/CoralContext";
import routeConfig from "../routeConfig";
import NotFound from "../routes/NotFound";
const Router = createFarceRouter({
historyProtocol: new BrowserProtocol(),
historyMiddlewares: [queryMiddleware],
routeConfig,
renderReady: ({ elements }) => (
<>
<ElementsRenderer elements={elements} />
{// this enables router transition control when writing tests.
process.env.NODE_ENV === "test" && <TransitionControl />}
</>
),
renderError: ({ error }) => (
<div>{error.status === 404 ? <NotFound /> : "Error"}</div>
),
});
const App: FunctionComponent = () => (
<CoralContextConsumer>
{({ relayEnvironment }) => (
<Router resolver={new Resolver(relayEnvironment)} />
)}
</CoralContextConsumer>
);
export default App;
@@ -0,0 +1,19 @@
import { noop } from "lodash";
import React from "react";
import { createRenderer } from "react-test-renderer/shallow";
import { PropTypesOf } from "coral-framework/types";
import ApprovedComment from "./ApprovedComment";
it("renders correctly", () => {
const props: PropTypesOf<typeof ApprovedComment> = {
href: "#",
username: "InTheExpensiveSeats",
date: "2018-07-06T18:24:00.000Z",
onGotoComment: noop,
};
const renderer = createRenderer();
renderer.render(<ApprovedComment {...props} />);
expect(renderer.getRenderOutput()).toMatchSnapshot();
});
@@ -0,0 +1,43 @@
import { Localized } from "fluent-react/compat";
import React, { FunctionComponent } from "react";
import ApprovedIcon from "./ApprovedIcon";
import DecisionItem from "./DecisionItem";
import DotDivider from "./DotDivider";
import Footer from "./Footer";
import GoToCommentLink from "./GoToCommentLink";
import Info from "./Info";
import Timestamp from "./Timestamp";
import { Typography } from "coral-ui/components";
interface Props {
href: string;
username: string;
date: string;
onGotoComment?: React.EventHandler<React.MouseEvent>;
}
const Username: FunctionComponent<{ username: string }> = ({ username }) => (
<strong>{username}</strong>
);
const ApprovedComment: FunctionComponent<Props> = props => (
<DecisionItem icon={<ApprovedIcon />}>
<Localized
id="decisionHistory-approvedCommentBy"
Username={<Username username={props.username} />}
>
<Info>{"Approved comment by <Username></Username>"}</Info>
</Localized>
<Footer>
<Typography variant="timestamp">
<Timestamp>{props.date}</Timestamp>
</Typography>
<DotDivider />
<GoToCommentLink href={props.href} onClick={props.onGotoComment} />
</Footer>
</DecisionItem>
);
export default ApprovedComment;
@@ -0,0 +1,3 @@
.root {
color: var(--palette-success-main);
}
@@ -0,0 +1,10 @@
import React from "react";
import { createRenderer } from "react-test-renderer/shallow";
import ApprovedIcon from "./ApprovedIcon";
it("renders correctly", () => {
const renderer = createRenderer();
renderer.render(<ApprovedIcon />);
expect(renderer.getRenderOutput()).toMatchSnapshot();
});
@@ -0,0 +1,11 @@
import React, { FunctionComponent } from "react";
import { Icon } from "coral-ui/components";
import styles from "./ApprovedIcon.css";
const ApprovedIcon: FunctionComponent = () => (
<Icon className={styles.root}>check</Icon>
);
export default ApprovedIcon;
@@ -0,0 +1,60 @@
import { noop } from "lodash";
import React from "react";
import { createRenderer } from "react-test-renderer/shallow";
import { removeFragmentRefs } from "coral-framework/testHelpers";
import { PropTypesOf } from "coral-framework/types";
import DecisionHistory from "./DecisionHistory";
const DecisionHistoryN = removeFragmentRefs(DecisionHistory);
const baseProps: PropTypesOf<typeof DecisionHistoryN> = {
actions: [],
onLoadMore: noop,
hasMore: false,
disableLoadMore: false,
onClosePopover: noop,
};
it("renders correctly", () => {
const props: PropTypesOf<typeof DecisionHistoryN> = {
...baseProps,
actions: [{ id: "1" }, { id: "2" }, { id: "3" }],
};
const renderer = createRenderer();
renderer.render(<DecisionHistoryN {...props} />);
expect(renderer.getRenderOutput()).toMatchSnapshot();
});
it("renders empty state", () => {
const props: PropTypesOf<typeof DecisionHistoryN> = {
...baseProps,
};
const renderer = createRenderer();
renderer.render(<DecisionHistoryN {...props} />);
expect(renderer.getRenderOutput()).toMatchSnapshot();
});
it("renders hasMore", () => {
const props: PropTypesOf<typeof DecisionHistoryN> = {
...baseProps,
actions: [{ id: "1" }, { id: "2" }, { id: "3" }],
hasMore: true,
};
const renderer = createRenderer();
renderer.render(<DecisionHistoryN {...props} />);
expect(renderer.getRenderOutput()).toMatchSnapshot();
});
it("renders disable load more", () => {
const props: PropTypesOf<typeof DecisionHistoryN> = {
...baseProps,
actions: [{ id: "1" }, { id: "2" }, { id: "3" }],
hasMore: true,
disableLoadMore: true,
};
const renderer = createRenderer();
renderer.render(<DecisionHistoryN {...props} />);
expect(renderer.getRenderOutput()).toMatchSnapshot();
});
@@ -0,0 +1,46 @@
import React, { FunctionComponent } from "react";
import { PropTypesOf } from "coral-framework/types";
import DecisionHistoryItemContainer from "./DecisionHistoryItemContainer";
import DecisionList from "./DecisionList";
import Empty from "./Empty";
import Main from "./Main";
import ShowMoreButton from "./ShowMoreButton";
import Title from "./Title";
interface Props {
actions: Array<
{ id: string } & PropTypesOf<typeof DecisionHistoryItemContainer>["action"]
>;
onLoadMore?: () => void;
hasMore?: boolean;
disableLoadMore?: boolean;
onClosePopover: () => void;
}
const DecisionHistory: FunctionComponent<Props> = props => (
<div data-testid="decisionHistory-container">
<Title />
<Main>
<DecisionList>
{props.actions.length === 0 && <Empty />}
{props.actions.map(action => (
<DecisionHistoryItemContainer
key={action.id}
action={action}
onClosePopover={props.onClosePopover}
/>
))}
</DecisionList>
{props.hasMore && (
<ShowMoreButton
onClick={props.onLoadMore}
disabled={props.disableLoadMore}
/>
)}
</Main>
</div>
);
export default DecisionHistory;
@@ -0,0 +1,8 @@
.popover {
width: 350px;
}
.historyIcon {
color: var(--palette-text-secondary);
margin-right: calc(1.5 * var(--mini-unit));
}
@@ -0,0 +1,44 @@
import { Localized } from "fluent-react/compat";
import React, { FunctionComponent } from "react";
import { BaseButton, ClickOutside, Icon, Popover } from "coral-ui/components";
import DecisionHistoryQuery from "./DecisionHistoryQuery";
import styles from "./DecisionHistoryButton.css";
const popoverID = "decision-history-popover";
const DecisionHistoryButton: FunctionComponent = () => (
<Localized id="decisionHistory-popover" attrs={{ description: true }}>
<Popover
data-testid="decisionHistory-popover"
id={popoverID}
placement="bottom-end"
description="A dialog showing the decision history"
classes={{ popover: styles.popover }}
modifiers={{ arrow: { enabled: false } }}
body={({ toggleVisibility }) => (
<ClickOutside onClickOutside={toggleVisibility}>
<div>
<DecisionHistoryQuery onClosePopover={toggleVisibility} />
</div>
</ClickOutside>
)}
>
{({ toggleVisibility, ref, visible }) => (
<BaseButton
onClick={toggleVisibility}
aria-controls={popoverID}
ref={ref}
className={styles.historyIcon}
data-testid="decisionHistory-toggle"
>
<Icon size="lg">history</Icon>
</BaseButton>
)}
</Popover>
</Localized>
);
export default DecisionHistoryButton;
@@ -0,0 +1,117 @@
import React from "react";
import { graphql, RelayPaginationProp } from "react-relay";
import { DecisionHistoryContainer_viewer as ViewerData } from "coral-admin/__generated__/DecisionHistoryContainer_viewer.graphql";
import { DecisionHistoryContainerPaginationQueryVariables } from "coral-admin/__generated__/DecisionHistoryContainerPaginationQuery.graphql";
import { withPaginationContainer } from "coral-framework/lib/relay";
import DecisionHistory from "./DecisionHistory";
interface DecisionHistoryContainerProps {
viewer: ViewerData;
relay: RelayPaginationProp;
onClosePopover: () => void;
}
export class DecisionHistoryContainer extends React.Component<
DecisionHistoryContainerProps
> {
public state = {
disableLoadMore: false,
};
public render() {
const actions = this.props.viewer.commentModerationActionHistory.edges.map(
edge => edge.node
);
return (
<DecisionHistory
actions={actions}
onLoadMore={this.loadMore}
hasMore={this.props.relay.hasMore()}
disableLoadMore={this.state.disableLoadMore}
onClosePopover={this.props.onClosePopover}
/>
);
}
private loadMore = () => {
if (!this.props.relay.hasMore() || this.props.relay.isLoading()) {
return;
}
this.setState({ disableLoadMore: true });
this.props.relay.loadMore(
10, // Fetch the next 10 feed items
error => {
this.setState({ disableLoadMore: false });
if (error) {
// tslint:disable-next-line:no-console
console.error(error);
}
}
);
};
}
// TODO: (cvle) If this could be autogenerated.
type FragmentVariables = DecisionHistoryContainerPaginationQueryVariables;
const enhanced = withPaginationContainer<
DecisionHistoryContainerProps,
DecisionHistoryContainerPaginationQueryVariables,
FragmentVariables
>(
{
viewer: graphql`
fragment DecisionHistoryContainer_viewer on User
@argumentDefinitions(
count: { type: "Int!", defaultValue: 5 }
cursor: { type: "Cursor" }
) {
commentModerationActionHistory(first: $count, after: $cursor)
@connection(key: "DecisionHistory_commentModerationActionHistory") {
edges {
node {
id
...DecisionHistoryItemContainer_action
}
}
}
}
`,
},
{
direction: "forward",
getConnectionFromProps(props) {
return props.viewer && props.viewer.commentModerationActionHistory;
},
// This is also the default implementation of `getFragmentVariables` if it isn't provided.
getFragmentVariables(prevVars, totalCount) {
return {
...prevVars,
count: totalCount,
};
},
getVariables(props, { count, cursor }, fragmentVariables) {
return {
count,
cursor,
};
},
query: graphql`
# Pagination query to be fetched upon calling 'loadMore'.
# Notice that we re-use our fragment, and the shape of this query matches our fragment spec.
query DecisionHistoryContainerPaginationQuery(
$count: Int!
$cursor: Cursor
) {
viewer {
...DecisionHistoryContainer_viewer
@arguments(count: $count, cursor: $cursor)
}
}
`,
}
)(DecisionHistoryContainer);
export default enhanced;
@@ -0,0 +1,68 @@
import React from "react";
import { graphql } from "react-relay";
import { DecisionHistoryItemContainer_action as ActionData } from "coral-admin/__generated__/DecisionHistoryItemContainer_action.graphql";
import { withFragmentContainer } from "coral-framework/lib/relay";
import ApprovedComment from "./ApprovedComment";
import RejectedComment from "./RejectedComment";
interface DecisionHistoryItemContainerProps {
action: ActionData;
onClosePopover: () => void;
}
class DecisionHistoryItemContainer extends React.Component<
DecisionHistoryItemContainerProps
> {
public render() {
const href = `/admin/moderate/comment/${
this.props.action.revision.comment.id
}`;
const username =
(this.props.action.revision.comment.author &&
this.props.action.revision.comment.author.username) ||
"Unknown"; // TODO: (cvle) Figure out what to display, when username is not available.
if (this.props.action.status === "APPROVED") {
return (
<ApprovedComment
href={href}
username={username}
date={this.props.action.createdAt}
onGotoComment={this.props.onClosePopover}
/>
);
} else if (this.props.action.status === "REJECTED") {
return (
<RejectedComment
href={href}
username={username}
date={this.props.action.createdAt}
onGotoComment={this.props.onClosePopover}
/>
);
}
return null;
}
}
const enhanced = withFragmentContainer<DecisionHistoryItemContainerProps>({
action: graphql`
fragment DecisionHistoryItemContainer_action on CommentModerationAction {
id
revision {
id
comment {
id
author {
username
}
}
}
createdAt
status
}
`,
})(DecisionHistoryItemContainer);
export default enhanced;
@@ -0,0 +1,4 @@
.container {
padding: var(--mini-unit);
min-height: 30px;
}
@@ -0,0 +1,10 @@
import React from "react";
import { createRenderer } from "react-test-renderer/shallow";
import DecisionHistoryLoading from "./DecisionHistoryLoading";
it("renders correctly", () => {
const renderer = createRenderer();
renderer.render(<DecisionHistoryLoading />);
expect(renderer.getRenderOutput()).toMatchSnapshot();
});
@@ -0,0 +1,27 @@
import React, { FunctionComponent } from "react";
import { Delay, Flex, Spinner } from "coral-ui/components";
import Main from "./Main";
import Title from "./Title";
import styles from "./DecisionHistoryLoading.css";
const DecisionHistoryLoading: FunctionComponent = () => (
<div data-testid="decisionHistory-loading-container">
<Title />
<Main>
<Flex
justifyContent="center"
alignItems="center"
className={styles.container}
>
<Delay>
<Spinner size="sm" />
</Delay>
</Flex>
</Main>
</div>
);
export default DecisionHistoryLoading;
@@ -0,0 +1,45 @@
import { graphql, QueryRenderer } from "coral-framework/lib/relay";
import React, { Component } from "react";
import { DecisionHistoryQuery as QueryTypes } from "coral-admin/__generated__/DecisionHistoryQuery.graphql";
import DecisionHistoryContainer from "./DecisionHistoryContainer";
import DecisionHistoryLoading from "./DecisionHistoryLoading";
interface Props {
onClosePopover: () => void;
}
class DecisionHistoryQuery extends Component<Props> {
public render() {
return (
<QueryRenderer<QueryTypes>
query={graphql`
query DecisionHistoryQuery {
viewer {
...DecisionHistoryContainer_viewer
}
}
`}
variables={{}}
render={({ error, props }) => {
if (error) {
return <div>{error.message}</div>;
}
if (!props || !props.viewer) {
return <DecisionHistoryLoading />;
}
return (
<DecisionHistoryContainer
viewer={props.viewer}
onClosePopover={this.props.onClosePopover}
/>
);
}}
/>
);
}
}
export default DecisionHistoryQuery;
@@ -0,0 +1,13 @@
.root {
padding: calc(0.5 * var(--mini-unit)) calc(0.5 * var(--mini-unit))
calc(0.5 * var(--mini-unit)) 0;
}
.leftCol {
display: flex;
justify-content: center;
flex-grow: 0;
flex-shrink: 0;
width: calc(3 * var(--mini-unit));
padding-top: 3px;
}
@@ -0,0 +1,16 @@
import React from "react";
import { createRenderer } from "react-test-renderer/shallow";
import { PropTypesOf } from "coral-framework/types";
import DecisionItem from "./DecisionItem";
it("renders correctly", () => {
const props: PropTypesOf<typeof DecisionItem> = {
icon: "icon",
children: "children",
};
const renderer = createRenderer();
renderer.render(<DecisionItem {...props} />);
expect(renderer.getRenderOutput()).toMatchSnapshot();
});
@@ -0,0 +1,21 @@
import React, { FunctionComponent } from "react";
import { Flex } from "coral-ui/components";
import styles from "./DecisionItem.css";
interface Props {
icon: React.ReactNode;
children: React.ReactNode;
}
const DecisionItem: FunctionComponent<Props> = props => (
<li className={styles.root}>
<Flex>
<div className={styles.leftCol}>{props.icon}</div>
<div>{props.children}</div>
</Flex>
</li>
);
export default DecisionItem;
@@ -0,0 +1,12 @@
.root {
margin: 0;
padding: 0;
list-style-type: none;
& > * {
border-bottom: 1px solid var(--palette-divider);
}
& > *:last-child {
border-bottom: 0;
}
}
@@ -0,0 +1,15 @@
import React from "react";
import { createRenderer } from "react-test-renderer/shallow";
import { PropTypesOf } from "coral-framework/types";
import DecisionList from "./DecisionList";
it("renders correctly", () => {
const props: PropTypesOf<typeof DecisionList> = {
children: "children",
};
const renderer = createRenderer();
renderer.render(<DecisionList {...props} />);
expect(renderer.getRenderOutput()).toMatchSnapshot();
});
@@ -0,0 +1,9 @@
import React, { FunctionComponent } from "react";
import styles from "./DecisionList.css";
const DecisionList: FunctionComponent = props => (
<ul className={styles.root}>{props.children}</ul>
);
export default DecisionList;
@@ -0,0 +1,7 @@
.root {
height: 100%;
font-size: calc(12rem / var(--rem-base));
line-height: calc(12em / 12);
color: var(--palette-divider);
padding: 0 calc(0.5 * var(--mini-unit));
}
@@ -0,0 +1,10 @@
import React from "react";
import { createRenderer } from "react-test-renderer/shallow";
import DotDivider from "./DotDivider";
it("renders correctly", () => {
const renderer = createRenderer();
renderer.render(<DotDivider />);
expect(renderer.getRenderOutput()).toMatchSnapshot();
});
@@ -0,0 +1,9 @@
import React, { FunctionComponent } from "react";
import styles from "./DotDivider.css";
const Footer: FunctionComponent<{}> = () => (
<div className={styles.root}></div>
);
export default Footer;
@@ -0,0 +1,3 @@
.root {
padding: calc(1.5 * var(--mini-unit)) calc(2 * var(--mini-unit));
}
@@ -0,0 +1,10 @@
import React from "react";
import { createRenderer } from "react-test-renderer/shallow";
import Empty from "./Empty";
it("renders correctly", () => {
const renderer = createRenderer();
renderer.render(<Empty />);
expect(renderer.getRenderOutput()).toMatchSnapshot();
});
@@ -0,0 +1,18 @@
import { Localized } from "fluent-react/compat";
import React, { FunctionComponent } from "react";
import { Flex, Typography } from "coral-ui/components";
import styles from "./Empty.css";
const Empty: FunctionComponent<{}> = () => (
<Flex justifyContent="center" alignItems="center" className={styles.root}>
<Localized id="decisionHistory-youWillSeeAList">
<Typography>
You will see a list of your post moderation actions here.
</Typography>
</Localized>
</Flex>
);
export default Empty;
@@ -0,0 +1,2 @@
.root {
}
@@ -0,0 +1,15 @@
import React from "react";
import { createRenderer } from "react-test-renderer/shallow";
import { PropTypesOf } from "coral-framework/types";
import Footer from "./Footer";
it("renders correctly", () => {
const props: PropTypesOf<typeof Footer> = {
children: "children",
};
const renderer = createRenderer();
renderer.render(<Footer {...props} />);
expect(renderer.getRenderOutput()).toMatchSnapshot();
});
@@ -0,0 +1,17 @@
import React, { FunctionComponent } from "react";
import { Flex } from "coral-ui/components";
import styles from "./Footer.css";
interface Props {
children: React.ReactNode;
}
const Footer: FunctionComponent<Props> = props => (
<Flex className={styles.root} alignItems="baseline">
{props.children}
</Flex>
);
export default Footer;
@@ -0,0 +1,9 @@
.root {
font-size: calc(12rem / var(--rem-base));
font-weight: var(--font-weight-regular);
font-family: var(--font-family-sans-serif);
line-height: calc(14em / 12);
letter-spacing: calc(0.2em / 12);
color: var(--palette-primary-main);
text-decoration: none;
}
@@ -0,0 +1,17 @@
import { noop } from "lodash";
import React from "react";
import { createRenderer } from "react-test-renderer/shallow";
import { PropTypesOf } from "coral-framework/types";
import GoToCommentLink from "./GoToCommentLink";
it("renders correctly", () => {
const props: PropTypesOf<typeof GoToCommentLink> = {
href: "#",
onClick: noop,
};
const renderer = createRenderer();
renderer.render(<GoToCommentLink {...props} />);
expect(renderer.getRenderOutput()).toMatchSnapshot();
});
@@ -0,0 +1,30 @@
import { Localized } from "fluent-react/compat";
import { Link } from "found";
import React, { FunctionComponent } from "react";
import { Icon, TextLink } from "coral-ui/components";
import styles from "./GoToCommentLink.css";
interface Props {
href: string;
onClick?: React.EventHandler<React.MouseEvent>;
}
const GoToCommentLink: FunctionComponent<Props> = props => {
return (
<Link
as={TextLink}
className={styles.root}
to={props.href}
onClick={props.onClick}
>
<Localized id="decisionHistory-goToComment">
<span>Go to comment</span>
</Localized>{" "}
<Icon>chevron_right</Icon>
</Link>
);
};
export default GoToCommentLink;
@@ -0,0 +1,13 @@
.root {
font-size: calc(14rem / var(--rem-base));
line-height: calc(16em / 12);
/*
Fallback begin
Unfortunately Firefox / IE does not support
`word-break: break-word` yet.
*/
word-break: break-all;
/* Fallback end */
word-break: break-word;
}
@@ -0,0 +1,15 @@
import React from "react";
import { createRenderer } from "react-test-renderer/shallow";
import { PropTypesOf } from "coral-framework/types";
import Info from "./Info";
it("renders correctly", () => {
const props: PropTypesOf<typeof Info> = {
children: "children",
};
const renderer = createRenderer();
renderer.render(<Info {...props} />);
expect(renderer.getRenderOutput()).toMatchSnapshot();
});
@@ -0,0 +1,15 @@
import React, { FunctionComponent } from "react";
import { Typography } from "coral-ui/components";
import styles from "./Info.css";
interface Props {
children: React.ReactNode;
}
const Info: FunctionComponent<Props> = props => (
<Typography className={styles.root}>{props.children}</Typography>
);
export default Info;
@@ -0,0 +1,5 @@
.root {
max-height: calc(26 * var(--mini-unit));
overflow: hidden;
overflow-y: scroll;
}
@@ -0,0 +1,15 @@
import React from "react";
import { createRenderer } from "react-test-renderer/shallow";
import { PropTypesOf } from "coral-framework/types";
import Main from "./Main";
it("renders correctly", () => {
const props: PropTypesOf<typeof Main> = {
children: "children",
};
const renderer = createRenderer();
renderer.render(<Main {...props} />);
expect(renderer.getRenderOutput()).toMatchSnapshot();
});
@@ -0,0 +1,9 @@
import React, { FunctionComponent } from "react";
import styles from "./Main.css";
const Main: FunctionComponent = props => (
<div className={styles.root}>{props.children}</div>
);
export default Main;
@@ -0,0 +1,19 @@
import { noop } from "lodash";
import React from "react";
import { createRenderer } from "react-test-renderer/shallow";
import { PropTypesOf } from "coral-framework/types";
import RejectedComment from "./RejectedComment";
it("renders correctly", () => {
const props: PropTypesOf<typeof RejectedComment> = {
href: "#",
username: "InTheExpensiveSeats",
date: "2018-07-06T18:24:00.000Z",
onGotoComment: noop,
};
const renderer = createRenderer();
renderer.render(<RejectedComment {...props} />);
expect(renderer.getRenderOutput()).toMatchSnapshot();
});
@@ -0,0 +1,43 @@
import { Localized } from "fluent-react/compat";
import React, { FunctionComponent } from "react";
import DecisionItem from "./DecisionItem";
import DotDivider from "./DotDivider";
import Footer from "./Footer";
import GoToCommentLink from "./GoToCommentLink";
import Info from "./Info";
import RejectedIcon from "./RejectedIcon";
import Timestamp from "./Timestamp";
import { Typography } from "coral-ui/components";
interface Props {
href: string;
username: string;
date: string;
onGotoComment?: React.EventHandler<React.MouseEvent>;
}
const Username: FunctionComponent<{ username: string }> = ({ username }) => (
<strong>{username}</strong>
);
const RejectedComment: FunctionComponent<Props> = props => (
<DecisionItem icon={<RejectedIcon />}>
<Localized
id="decisionHistory-rejectedCommentBy"
Username={<Username username={props.username} />}
>
<Info>{"Rejected comment by <Username></Username>"}</Info>
</Localized>
<Footer>
<Typography variant="timestamp">
<Timestamp>{props.date}</Timestamp>
</Typography>
<DotDivider />
<GoToCommentLink href={props.href} onClick={props.onGotoComment} />
</Footer>
</DecisionItem>
);
export default RejectedComment;
@@ -0,0 +1,3 @@
.root {
color: var(--palette-error-main);
}
@@ -0,0 +1,10 @@
import React from "react";
import { createRenderer } from "react-test-renderer/shallow";
import RejectedIcon from "./RejectedIcon";
it("renders correctly", () => {
const renderer = createRenderer();
renderer.render(<RejectedIcon />);
expect(renderer.getRenderOutput()).toMatchSnapshot();
});
@@ -0,0 +1,11 @@
import React, { FunctionComponent } from "react";
import { Icon } from "coral-ui/components";
import styles from "./RejectedIcon.css";
const RejectedIcon: FunctionComponent = () => (
<Icon className={styles.root}>cancel</Icon>
);
export default RejectedIcon;
@@ -0,0 +1,16 @@
.root {
text-transform: uppercase;
font-size: calc(12rem / var(--rem-base));
font-weight: var(--font-weight-medium);
font-family: var(--font-family-sans-serif);
line-height: calc(2 * var(--mini-unit));
letter-spacing: calc(0.2em / 12);
color: var(--palette-grey-main);
width: 100%;
border-top: 1px solid var(--palette-divider);
text-align: center;
&:disabled {
color: var(--palette-grey-lighter);
}
}
@@ -0,0 +1,17 @@
import { noop } from "lodash";
import React from "react";
import { createRenderer } from "react-test-renderer/shallow";
import { PropTypesOf } from "coral-framework/types";
import ShowMoreButton from "./ShowMoreButton";
it("renders correctly", () => {
const props: PropTypesOf<typeof ShowMoreButton> = {
disabled: false,
onClick: noop,
};
const renderer = createRenderer();
renderer.render(<ShowMoreButton {...props} />);
expect(renderer.getRenderOutput()).toMatchSnapshot();
});
@@ -0,0 +1,25 @@
import { Localized } from "fluent-react/compat";
import React, { FunctionComponent } from "react";
import { BaseButton } from "coral-ui/components";
import styles from "./ShowMoreButton.css";
interface Props {
disabled?: boolean;
onClick?: () => void;
}
const ShowMoreButton: FunctionComponent<Props> = props => (
<Localized id="decisionHistory-showMoreButton">
<BaseButton
className={styles.root}
onClick={props.onClick}
disabled={props.disabled}
>
Show More
</BaseButton>
</Localized>
);
export default ShowMoreButton;
@@ -0,0 +1,8 @@
.root {
color: var(--palette-text-secondary);
font-family: var(--font-family-sans-serif);
font-weight: var(--font-weight-medium);
font-size: calc(12rem / var(--rem-base));
line-height: calc(14em / 12);
letter-spacing: 0;
}
@@ -0,0 +1,15 @@
import React from "react";
import { createRenderer } from "react-test-renderer/shallow";
import { PropTypesOf } from "coral-framework/types";
import Timestamp from "./Timestamp";
it("renders correctly", () => {
const props: PropTypesOf<typeof Timestamp> = {
children: "2018-07-06T18:24:00.000Z",
};
const renderer = createRenderer();
renderer.render(<Timestamp {...props} />);
expect(renderer.getRenderOutput()).toMatchSnapshot();
});
@@ -0,0 +1,15 @@
import React, { FunctionComponent } from "react";
import { RelativeTime } from "coral-ui/components";
import styles from "./Timestamp.css";
interface Props {
children: string;
}
const DecisionHistory: FunctionComponent<Props> = props => (
<RelativeTime className={styles.root} date={props.children} />
);
export default DecisionHistory;
@@ -0,0 +1,16 @@
.root {
padding: 0 calc(0.5 * var(--mini-unit));
background-color: #f2f2f2;
color: var(--palette-text-primary);
border-bottom: 1px solid var(--palette-grey-lighter);
}
.text {
text-transform: uppercase;
font-size: calc(12rem / var(--rem-base));
font-weight: var(--font-weight-medium);
font-family: var(--font-family-sans-serif);
line-height: calc(12em / 12);
letter-spacing: calc(0.2em / 12);
color: var(--palette-text-primary);
}
@@ -0,0 +1,10 @@
import React from "react";
import { createRenderer } from "react-test-renderer/shallow";
import Title from "./Title";
it("renders correctly", () => {
const renderer = createRenderer();
renderer.render(<Title />);
expect(renderer.getRenderOutput()).toMatchSnapshot();
});
@@ -0,0 +1,19 @@
import { Localized } from "fluent-react/compat";
import React, { FunctionComponent } from "react";
import { Flex, Icon, Typography } from "coral-ui/components";
import styles from "./Title.css";
const Title: FunctionComponent = () => (
<Flex className={styles.root} alignItems="center">
<Icon>history</Icon>{" "}
<Localized id="decisionHistory-yourDecisionHistory">
<Typography container="span" className={styles.text}>
Your Decision History
</Typography>
</Localized>
</Flex>
);
export default Title;
@@ -0,0 +1,34 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`renders correctly 1`] = `
<DecisionItem
icon={<ApprovedIcon />}
>
<Localized
Username={
<Username
username="InTheExpensiveSeats"
/>
}
id="decisionHistory-approvedCommentBy"
>
<Info>
Approved comment by &lt;Username&gt;&lt;/Username&gt;
</Info>
</Localized>
<Footer>
<ForwardRef(forwardRef)
variant="timestamp"
>
<DecisionHistory>
2018-07-06T18:24:00.000Z
</DecisionHistory>
</ForwardRef(forwardRef)>
<Footer />
<GoToCommentLink
href="#"
onClick={[Function]}
/>
</Footer>
</DecisionItem>
`;
@@ -0,0 +1,9 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`renders correctly 1`] = `
<ForwardRef(forwardRef)
className="ApprovedIcon-root"
>
check
</ForwardRef(forwardRef)>
`;
@@ -0,0 +1,130 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`renders correctly 1`] = `
<div
data-testid="decisionHistory-container"
>
<Title />
<Main>
<DecisionList>
<Relay(DecisionHistoryItemContainer)
action={
Object {
"id": "1",
}
}
onClosePopover={[Function]}
/>
<Relay(DecisionHistoryItemContainer)
action={
Object {
"id": "2",
}
}
onClosePopover={[Function]}
/>
<Relay(DecisionHistoryItemContainer)
action={
Object {
"id": "3",
}
}
onClosePopover={[Function]}
/>
</DecisionList>
</Main>
</div>
`;
exports[`renders disable load more 1`] = `
<div
data-testid="decisionHistory-container"
>
<Title />
<Main>
<DecisionList>
<Relay(DecisionHistoryItemContainer)
action={
Object {
"id": "1",
}
}
onClosePopover={[Function]}
/>
<Relay(DecisionHistoryItemContainer)
action={
Object {
"id": "2",
}
}
onClosePopover={[Function]}
/>
<Relay(DecisionHistoryItemContainer)
action={
Object {
"id": "3",
}
}
onClosePopover={[Function]}
/>
</DecisionList>
<ShowMoreButton
disabled={true}
onClick={[Function]}
/>
</Main>
</div>
`;
exports[`renders empty state 1`] = `
<div
data-testid="decisionHistory-container"
>
<Title />
<Main>
<DecisionList>
<Empty />
</DecisionList>
</Main>
</div>
`;
exports[`renders hasMore 1`] = `
<div
data-testid="decisionHistory-container"
>
<Title />
<Main>
<DecisionList>
<Relay(DecisionHistoryItemContainer)
action={
Object {
"id": "1",
}
}
onClosePopover={[Function]}
/>
<Relay(DecisionHistoryItemContainer)
action={
Object {
"id": "2",
}
}
onClosePopover={[Function]}
/>
<Relay(DecisionHistoryItemContainer)
action={
Object {
"id": "3",
}
}
onClosePopover={[Function]}
/>
</DecisionList>
<ShowMoreButton
disabled={false}
onClick={[Function]}
/>
</Main>
</div>
`;
@@ -0,0 +1,24 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`renders correctly 1`] = `
<div
data-testid="decisionHistory-loading-container"
>
<Title />
<Main>
<ForwardRef(forwardRef)
alignItems="center"
className="DecisionHistoryLoading-container"
justifyContent="center"
>
<Delay
ms={500}
>
<withPropsOnChange(Spinner)
size="sm"
/>
</Delay>
</ForwardRef(forwardRef)>
</Main>
</div>
`;
@@ -0,0 +1,18 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`renders correctly 1`] = `
<li
className="DecisionItem-root"
>
<ForwardRef(forwardRef)>
<div
className="DecisionItem-leftCol"
>
icon
</div>
<div>
children
</div>
</ForwardRef(forwardRef)>
</li>
`;
@@ -0,0 +1,9 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`renders correctly 1`] = `
<ul
className="DecisionList-root"
>
children
</ul>
`;
@@ -0,0 +1,9 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`renders correctly 1`] = `
<div
className="DotDivider-root"
>
</div>
`;
@@ -0,0 +1,17 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`renders correctly 1`] = `
<ForwardRef(forwardRef)
alignItems="center"
className="Empty-root"
justifyContent="center"
>
<Localized
id="decisionHistory-youWillSeeAList"
>
<ForwardRef(forwardRef)>
You will see a list of your post moderation actions here.
</ForwardRef(forwardRef)>
</Localized>
</ForwardRef(forwardRef)>
`;
@@ -0,0 +1,10 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`renders correctly 1`] = `
<ForwardRef(forwardRef)
alignItems="baseline"
className="Footer-root"
>
children
</ForwardRef(forwardRef)>
`;
@@ -0,0 +1,22 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`renders correctly 1`] = `
<ForwardRef(render)
as={[Function]}
className="GoToCommentLink-root"
onClick={[Function]}
to="#"
>
<Localized
id="decisionHistory-goToComment"
>
<span>
Go to comment
</span>
</Localized>
<ForwardRef(forwardRef)>
chevron_right
</ForwardRef(forwardRef)>
</ForwardRef(render)>
`;
@@ -0,0 +1,9 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`renders correctly 1`] = `
<ForwardRef(forwardRef)
className="Info-root"
>
children
</ForwardRef(forwardRef)>
`;
@@ -0,0 +1,9 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`renders correctly 1`] = `
<div
className="Main-root"
>
children
</div>
`;
@@ -0,0 +1,34 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`renders correctly 1`] = `
<DecisionItem
icon={<RejectedIcon />}
>
<Localized
Username={
<Username
username="InTheExpensiveSeats"
/>
}
id="decisionHistory-rejectedCommentBy"
>
<Info>
Rejected comment by &lt;Username&gt;&lt;/Username&gt;
</Info>
</Localized>
<Footer>
<ForwardRef(forwardRef)
variant="timestamp"
>
<DecisionHistory>
2018-07-06T18:24:00.000Z
</DecisionHistory>
</ForwardRef(forwardRef)>
<Footer />
<GoToCommentLink
href="#"
onClick={[Function]}
/>
</Footer>
</DecisionItem>
`;
@@ -0,0 +1,9 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`renders correctly 1`] = `
<ForwardRef(forwardRef)
className="RejectedIcon-root"
>
cancel
</ForwardRef(forwardRef)>
`;
@@ -0,0 +1,15 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`renders correctly 1`] = `
<Localized
id="decisionHistory-showMoreButton"
>
<ForwardRef(forwardRef)
className="ShowMoreButton-root"
disabled={false}
onClick={[Function]}
>
Show More
</ForwardRef(forwardRef)>
</Localized>
`;
@@ -0,0 +1,8 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`renders correctly 1`] = `
<ForwardRef(forwardRef)
className="Timestamp-root"
date="2018-07-06T18:24:00.000Z"
/>
`;
@@ -0,0 +1,23 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`renders correctly 1`] = `
<ForwardRef(forwardRef)
alignItems="center"
className="Title-root"
>
<ForwardRef(forwardRef)>
history
</ForwardRef(forwardRef)>
<Localized
id="decisionHistory-yourDecisionHistory"
>
<ForwardRef(forwardRef)
className="Title-text"
container="span"
>
Your Decision History
</ForwardRef(forwardRef)>
</Localized>
</ForwardRef(forwardRef)>
`;
@@ -0,0 +1,4 @@
export {
default,
default as DecisionHistoryButton,
} from "./DecisionHistoryButton";
+13
View File
@@ -0,0 +1,13 @@
:global {
body {
padding: 0;
margin: 0;
}
}
.root {
}
.logoContainer {
position: relative;
}
+20
View File
@@ -0,0 +1,20 @@
import { removeFragmentRefs } from "coral-framework/testHelpers";
import React from "react";
import { createRenderer } from "react-test-renderer/shallow";
import { PropTypesOf } from "coral-framework/types";
import Main from "./Main";
const MainN = removeFragmentRefs(Main);
it("renders correctly", () => {
const props: PropTypesOf<typeof MainN> = {
viewer: {},
children: "child",
};
const renderer = createRenderer();
renderer.render(<MainN {...props} />);
expect(renderer.getRenderOutput()).toMatchSnapshot();
});
+40
View File
@@ -0,0 +1,40 @@
import React, { FunctionComponent } from "react";
import { PropTypesOf } from "coral-framework/types";
import { Logo } from "coral-ui/components";
import { AppBar, Begin, Divider, End } from "coral-ui/components/AppBar";
import { DecisionHistoryButton } from "./DecisionHistory";
import NavigationContainer from "./Navigation";
import UserMenuContainer from "./UserMenu";
import Version from "./Version";
import styles from "./Main.css";
interface Props {
viewer: PropTypesOf<typeof UserMenuContainer>["viewer"] &
PropTypesOf<typeof NavigationContainer>["viewer"];
children: React.ReactNode;
}
const Main: FunctionComponent<Props> = ({ children, viewer }) => (
<div className={styles.root}>
<AppBar gutterBegin gutterEnd>
<Begin itemGutter="double">
<div className={styles.logoContainer}>
<Logo />
<Version />
</div>
<NavigationContainer viewer={viewer} />
</Begin>
<End>
<DecisionHistoryButton />
<Divider />
<UserMenuContainer viewer={viewer} />
</End>
</AppBar>
{children}
</div>
);
export default Main;
+35
View File
@@ -0,0 +1,35 @@
import React from "react";
import { MainRouteQueryResponse } from "coral-admin/__generated__/MainRouteQuery.graphql";
import { graphql } from "coral-framework/lib/relay";
import { withRouteConfig } from "coral-framework/lib/router";
import Main from "./Main";
interface Props {
data: MainRouteQueryResponse | null;
}
class MainRoute extends React.Component<Props> {
public render() {
return (
<Main viewer={this.props.data && this.props.data.viewer}>
{this.props.children}
</Main>
);
}
}
const enhanced = withRouteConfig<Props>({
query: graphql`
query MainRouteQuery {
viewer {
...UserMenuContainer_viewer
...NavigationContainer_viewer
}
}
`,
})(MainRoute);
export default enhanced;
@@ -0,0 +1,10 @@
import React from "react";
import { createRenderer } from "react-test-renderer/shallow";
import Navigation from "./Navigation";
it("renders correctly", () => {
const renderer = createRenderer();
renderer.render(<Navigation showConfigure />);
expect(renderer.getRenderOutput()).toMatchSnapshot();
});
@@ -0,0 +1,31 @@
import { Localized } from "fluent-react/compat";
import React, { FunctionComponent } from "react";
import { AppBarNavigation } from "coral-ui/components";
import NavigationLink from "./NavigationLink";
interface Props {
showConfigure: boolean;
}
const Navigation: FunctionComponent<Props> = props => (
<AppBarNavigation>
<Localized id="navigation-moderate">
<NavigationLink to="/admin/moderate">Moderate</NavigationLink>
</Localized>
<Localized id="navigation-stories">
<NavigationLink to="/admin/stories">Stories</NavigationLink>
</Localized>
<Localized id="navigation-community">
<NavigationLink to="/admin/community">Community</NavigationLink>
</Localized>
{props.showConfigure && (
<Localized id="navigation-configure">
<NavigationLink to="/admin/configure">Configure</NavigationLink>
</Localized>
)}
</AppBarNavigation>
);
export default Navigation;
@@ -0,0 +1,41 @@
import React from "react";
import { NavigationContainer_viewer as ViewerData } from "coral-admin/__generated__/NavigationContainer_viewer.graphql";
import { Ability, can } from "coral-admin/permissions";
import { graphql, withFragmentContainer } from "coral-framework/lib/relay";
import {
SignOutMutation,
withSignOutMutation,
} from "coral-framework/mutations";
import Navigation from "./Navigation";
interface Props {
signOut: SignOutMutation;
viewer: ViewerData | null;
}
class NavigationContainer extends React.Component<Props> {
public render() {
return (
<Navigation
showConfigure={
!!this.props.viewer &&
can(this.props.viewer, Ability.CHANGE_CONFIGURATION)
}
/>
);
}
}
const enhanced = withSignOutMutation(
withFragmentContainer<Props>({
viewer: graphql`
fragment NavigationContainer_viewer on User {
role
}
`,
})(NavigationContainer)
);
export default enhanced;
@@ -0,0 +1,16 @@
import React from "react";
import { createRenderer } from "react-test-renderer/shallow";
import { PropTypesOf } from "coral-framework/types";
import NavigationLink from "./NavigationLink";
it("renders correctly", () => {
const props: PropTypesOf<typeof NavigationLink> = {
to: "/moderate",
children: "link",
};
const renderer = createRenderer();
renderer.render(<NavigationLink {...props} />);
expect(renderer.getRenderOutput()).toMatchSnapshot();
});
@@ -0,0 +1,17 @@
import { Link, LocationDescriptor } from "found";
import React, { FunctionComponent } from "react";
import { AppBarNavigationItem } from "coral-ui/components";
interface Props {
children: React.ReactNode;
to: string | LocationDescriptor;
}
const NavigationLink: FunctionComponent<Props> = props => (
<Link to={props.to} as={AppBarNavigationItem} activePropName="active">
{props.children}
</Link>
);
export default NavigationLink;
@@ -0,0 +1,42 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`renders correctly 1`] = `
<withPropsOnChange(Navigation)>
<Localized
id="navigation-moderate"
>
<NavigationLink
to="/admin/moderate"
>
Moderate
</NavigationLink>
</Localized>
<Localized
id="navigation-stories"
>
<NavigationLink
to="/admin/stories"
>
Stories
</NavigationLink>
</Localized>
<Localized
id="navigation-community"
>
<NavigationLink
to="/admin/community"
>
Community
</NavigationLink>
</Localized>
<Localized
id="navigation-configure"
>
<NavigationLink
to="/admin/configure"
>
Configure
</NavigationLink>
</Localized>
</withPropsOnChange(Navigation)>
`;
@@ -0,0 +1,11 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`renders correctly 1`] = `
<ForwardRef(render)
activePropName="active"
as={[Function]}
to="/moderate"
>
link
</ForwardRef(render)>
`;
@@ -0,0 +1 @@
export { default, default as NavigationContainer } from "./NavigationContainer";
@@ -0,0 +1,11 @@
.button {
padding-top: 0;
padding-bottom: 0;
margin-left: 5px;
}
.buttonText {
font-size: calc(18rem / var(--rem-base));
letter-spacing: calc(-0.2em / 18);
margin-left: 2px;
margin-right: 1px;
}
@@ -0,0 +1,17 @@
import { noop } from "lodash";
import React from "react";
import { createRenderer } from "react-test-renderer/shallow";
import { PropTypesOf } from "coral-framework/types";
import UserMenu from "./UserMenu";
it("renders correctly", () => {
const props: PropTypesOf<typeof UserMenu> = {
username: "Admin",
onSignOut: noop as any,
};
const renderer = createRenderer();
renderer.render(<UserMenu {...props} />);
expect(renderer.getRenderOutput()).toMatchSnapshot();
});
@@ -0,0 +1,79 @@
import { Localized } from "fluent-react/compat";
import React, { FunctionComponent } from "react";
import {
Button,
ButtonIcon,
ClickOutside,
Dropdown,
DropdownButton,
DropdownDivider,
Popover,
} from "coral-ui/components";
import styles from "./UserMenu.css";
interface Props {
username: string;
onSignOut: React.EventHandler<React.MouseEvent>;
}
const UserMenu: FunctionComponent<Props> = props => (
<Localized id="userMenu-popover" attrs={{ description: true }}>
<Popover
id="userMenu"
placement="bottom-end"
description="A dialog of the user menu with related links and actions"
body={({ toggleVisibility }) => (
<ClickOutside onClickOutside={toggleVisibility}>
<Dropdown>
<Localized id="userMenu-viewLatestRelease">
<DropdownButton
href="https://github.com/coralproject/talk/releases/latest"
target="_blank"
rel="noopener"
>
View Latest Release
</DropdownButton>
</Localized>
<Localized id="userMenu-reportBug">
<DropdownButton
href="https://github.com/coralproject/talk/issues/new"
target="_blank"
rel="noopener"
>
Report a Bug or Give Feedback
</DropdownButton>
</Localized>
<DropdownDivider />
<Localized id="userMenu-signOut">
<DropdownButton onClick={props.onSignOut} blankAdornment>
Sign Out
</DropdownButton>
</Localized>
</Dropdown>
</ClickOutside>
)}
>
{({ toggleVisibility, ref, visible }) => (
<Button
className={styles.button}
onClick={toggleVisibility}
ref={ref}
variant="regular"
size="small"
>
<ButtonIcon size="lg">account_circle</ButtonIcon>
<span className={styles.buttonText}>{props.username}</span>
{
<ButtonIcon size="lg">
{visible ? "arrow_drop_up" : "arrow_drop_down"}
</ButtonIcon>
}
</Button>
)}
</Popover>
</Localized>
);
export default UserMenu;
@@ -0,0 +1,39 @@
import React from "react";
import { UserMenuContainer_viewer as ViewerData } from "coral-admin/__generated__/UserMenuContainer_viewer.graphql";
import { graphql, withFragmentContainer } from "coral-framework/lib/relay";
import {
SignOutMutation,
withSignOutMutation,
} from "coral-framework/mutations";
import UserMenu from "./UserMenu";
interface Props {
signOut: SignOutMutation;
viewer: ViewerData | null;
}
class UserMenuContainer extends React.Component<Props> {
private handleSignOut = () => this.props.signOut();
public render() {
return (
<UserMenu
onSignOut={this.handleSignOut}
username={(this.props.viewer && this.props.viewer.username) || ""}
/>
);
}
}
const enhanced = withSignOutMutation(
withFragmentContainer<Props>({
viewer: graphql`
fragment UserMenuContainer_viewer on User {
username
}
`,
})(UserMenuContainer)
);
export default enhanced;
@@ -0,0 +1,21 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`renders correctly 1`] = `
<Localized
attrs={
Object {
"description": true,
}
}
id="userMenu-popover"
>
<withPropsOnChange(Popover)
body={[Function]}
description="A dialog of the user menu with related links and actions"
id="userMenu"
placement="bottom-end"
>
[Function]
</withPropsOnChange(Popover)>
</Localized>
`;
@@ -0,0 +1 @@
export { default, default as UserMenuContainer } from "./UserMenuContainer";
+6
View File
@@ -0,0 +1,6 @@
.version {
position: absolute;
right: 0;
top: 23px;
font-size: calc(10rem / var(--rem-base));
}
+15
View File
@@ -0,0 +1,15 @@
import React, { FunctionComponent } from "react";
import { Typography } from "coral-ui/components";
import styles from "./Version.css";
const Version: FunctionComponent = () => {
return (
<Typography className={styles.version} variant="detail">
{process.env.TALK_VERSION ? `v${process.env.TALK_VERSION}` : "Unknown"}
</Typography>
);
};
export default Version;
@@ -0,0 +1,34 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`renders correctly 1`] = `
<div
className="Main-root"
>
<withPropsOnChange(AppBar)
gutterBegin={true}
gutterEnd={true}
>
<withPropsOnChange(Begin)
itemGutter="double"
>
<div
className="Main-logoContainer"
>
<withPropsOnChange(Logo) />
<Version />
</div>
<withContext(createMutationContainer(Relay(NavigationContainer)))
viewer={Object {}}
/>
</withPropsOnChange(Begin)>
<withPropsOnChange(End)>
<DecisionHistoryButton />
<withPropsOnChange(Divider) />
<withContext(createMutationContainer(Relay(UserMenuContainer)))
viewer={Object {}}
/>
</withPropsOnChange(End)>
</withPropsOnChange(AppBar)>
child
</div>
`;
+1
View File
@@ -0,0 +1 @@
export { default, default as App } from "./App";