[CORL-51] show comment revisions (#2590)

* add comment revisions

* reverse history order

* add strings

* update fixtures

* fix fixtures
This commit is contained in:
Tessa Thornton
2019-09-30 09:18:34 -04:00
committed by GitHub
parent e61e62a238
commit 941a385d53
13 changed files with 222 additions and 8 deletions
@@ -0,0 +1,67 @@
import React, { FunctionComponent } from "react";
import { CommentRevisionContainer_comment as CommentData } from "coral-admin/__generated__/CommentRevisionContainer_comment.graphql";
import { CommentRevisionContainer_settings as SettingsData } from "coral-admin/__generated__/CommentRevisionContainer_settings.graphql";
import { graphql, withFragmentContainer } from "coral-framework/lib/relay";
import { HorizontalGutter, Timestamp } from "coral-ui/components";
import CommentContent from "./CommentContent";
interface Props {
comment: CommentData;
settings: SettingsData;
}
const CommentRevisionContainer: FunctionComponent<Props> = ({
settings,
comment,
}) => {
return (
<HorizontalGutter>
{comment.revisionHistory
.concat()
.reverse()
.filter(c =>
comment && comment.revision && comment.revision.id
? comment.revision.id !== c.id
: true
)
.map(c => (
<div key={c.id}>
<Timestamp>{c.createdAt}</Timestamp>
<CommentContent
suspectWords={settings.wordList.suspect}
bannedWords={settings.wordList.banned}
>
{c.body ? c.body : ""}
</CommentContent>
</div>
))}
</HorizontalGutter>
);
};
const enhanced = withFragmentContainer<Props>({
comment: graphql`
fragment CommentRevisionContainer_comment on Comment {
revision {
id
}
revisionHistory {
id
body
createdAt
}
}
`,
settings: graphql`
fragment CommentRevisionContainer_settings on Settings {
wordList {
banned
suspect
}
}
`,
})(CommentRevisionContainer);
export default enhanced;
@@ -16,5 +16,5 @@
}
.detailsDivider {
border: 1px solid var(--palette-grey-lightest);
border-color: var(--palette-grey-lightest);
}
@@ -13,6 +13,9 @@ it("renders all markers", () => {
const props: PropTypesOf<typeof MarkersContainerN> = {
comment: {
status: "PREMOD",
editing: {
edited: false,
},
revision: {
actionCounts: {
flag: {
@@ -53,6 +56,9 @@ it("renders some markers", () => {
const props: PropTypesOf<typeof MarkersContainerN> = {
comment: {
status: "PREMOD",
editing: {
edited: false,
},
revision: {
actionCounts: {
flag: {
@@ -6,8 +6,8 @@ import { MarkersContainer_comment } from "coral-admin/__generated__/MarkersConta
import { MarkersContainer_settings } from "coral-admin/__generated__/MarkersContainer_settings.graphql";
import { withFragmentContainer } from "coral-framework/lib/relay";
import { Marker, MarkerCount } from "coral-ui/components";
import FlagDetailsContainer from "./FlagDetailsContainer";
import Markers from "./Markers";
import ModerateCardDetailsContainer from "./ModerateCardDetailsContainer";
interface MarkersContainerProps {
comment: MarkersContainer_comment;
@@ -123,8 +123,10 @@ export class MarkersContainer extends React.Component<MarkersContainerProps> {
return (
<Markers
details={
doesHaveDetails ? (
<FlagDetailsContainer
doesHaveDetails || this.props.comment.editing.edited ? (
<ModerateCardDetailsContainer
hasDetails={!!doesHaveDetails}
hasRevisions={this.props.comment.editing.edited}
onUsernameClick={this.props.onUsernameClick}
comment={this.props.comment}
settings={this.props.settings}
@@ -141,8 +143,11 @@ export class MarkersContainer extends React.Component<MarkersContainerProps> {
const enhanced = withFragmentContainer<MarkersContainerProps>({
comment: graphql`
fragment MarkersContainer_comment on Comment {
...FlagDetailsContainer_comment
...ModerateCardDetailsContainer_comment
status
editing {
edited
}
revision {
actionCounts {
flag {
@@ -168,7 +173,7 @@ const enhanced = withFragmentContainer<MarkersContainerProps>({
`,
settings: graphql`
fragment MarkersContainer_settings on Settings {
...FlagDetailsContainer_settings
...ModerateCardDetailsContainer_settings
}
`,
})(MarkersContainer);
@@ -159,4 +159,9 @@
.timestamp {
color: var(--palette-grey-lighter);
}
.edited {
color: var(--palette-grey-lighter);
padding-left: var(--spacing-2)
}
@@ -14,6 +14,7 @@ const baseProps: PropTypesOf<typeof ModerateCardN> = {
username: "Theon",
createdAt: "2018-11-29T16:01:51.897Z",
body: "content",
edited: false,
inReplyTo: null,
comment: {},
settings: {},
@@ -57,6 +57,7 @@ interface Props {
*/
dangling?: boolean;
deleted?: boolean;
edited: boolean;
}
const ModerateCard: FunctionComponent<Props> = ({
@@ -85,6 +86,7 @@ const ModerateCard: FunctionComponent<Props> = ({
mini = false,
hideUsername = false,
deleted = false,
edited,
}) => {
const commentBody = deleted ? (
<Localized id="moderate-comment-deleted-body">
@@ -131,6 +133,13 @@ const ModerateCard: FunctionComponent<Props> = ({
</BaseButton>
)}
<Timestamp className={styles.timestamp}>{createdAt}</Timestamp>
{edited && (
<Localized id="moderate-comment-edited">
<Typography variant="timestamp" className={styles.edited}>
(edited)
</Typography>
</Localized>
)}
<FeatureButton
featured={featured}
onClick={onFeature}
@@ -189,6 +189,7 @@ const ModerateCardContainer: FunctionComponent<Props> = ({
mini={mini}
hideUsername={hideUsername}
deleted={comment.deleted ? comment.deleted : false}
edited={comment.editing.edited}
/>
</FadeInTransition>
</>
@@ -213,6 +214,9 @@ const enhanced = withFragmentContainer<Props>({
revision {
id
}
editing {
edited
}
parent {
author {
id
@@ -0,0 +1,4 @@
.button {
text-transform: uppercase;
font-size: 14px;
}
@@ -0,0 +1,90 @@
import { Localized } from "fluent-react/compat";
import React, { FunctionComponent, useState } from "react";
import { graphql } from "react-relay";
import { ModerateCardDetailsContainer_comment as CommentData } from "coral-admin/__generated__/ModerateCardDetailsContainer_comment.graphql";
import { ModerateCardDetailsContainer_settings as SettingsData } from "coral-admin/__generated__/ModerateCardDetailsContainer_settings.graphql";
import { withFragmentContainer } from "coral-framework/lib/relay";
import { Flex, HorizontalGutter, Icon, Tab, TabBar } from "coral-ui/components";
import CommentRevisionContainer from "./CommentRevisionContainer";
import FlagDetailsContainer from "./FlagDetailsContainer";
import styles from "./ModerateCardDetailsContainer.css";
interface Props {
comment: CommentData;
settings: SettingsData;
onUsernameClick: (id?: string) => void;
hasDetails: boolean;
hasRevisions: boolean;
}
const ModerateCardDetailsContainer: FunctionComponent<Props> = ({
comment,
onUsernameClick,
settings,
hasDetails,
hasRevisions,
}) => {
const [activeTab, setActiveTab] = useState<"DETAILS" | "HISTORY">(
hasDetails ? "DETAILS" : "HISTORY"
);
return (
<HorizontalGutter>
<TabBar
variant="secondary"
activeTab={activeTab}
onTabClick={id => setActiveTab(id as "DETAILS" | "HISTORY")}
>
{hasDetails && (
<Tab tabID="DETAILS" classes={styles}>
<Flex alignItems="center" itemGutter>
<Icon size="md">list</Icon>
<Localized id="moderateCardDetails-tab-details">
<span>Details</span>
</Localized>
</Flex>
</Tab>
)}
{hasRevisions && (
<Tab tabID="HISTORY" classes={styles}>
<Flex alignItems="center" itemGutter>
<Icon>edit</Icon>
<Localized id="moderateCardDetails-tab-edits">
<span>Edit history</span>
</Localized>
</Flex>
</Tab>
)}
</TabBar>
{activeTab === "DETAILS" && (
<FlagDetailsContainer
comment={comment}
settings={settings}
onUsernameClick={onUsernameClick}
/>
)}
{activeTab === "HISTORY" && (
<CommentRevisionContainer comment={comment} settings={settings} />
)}
</HorizontalGutter>
);
};
const enhanced = withFragmentContainer<Props>({
comment: graphql`
fragment ModerateCardDetailsContainer_comment on Comment {
...FlagDetailsContainer_comment
...CommentRevisionContainer_comment
}
`,
settings: graphql`
fragment ModerateCardDetailsContainer_settings on Settings {
...FlagDetailsContainer_settings
...CommentRevisionContainer_settings
}
`,
})(ModerateCardDetailsContainer);
export default enhanced;
@@ -3,9 +3,12 @@
exports[`renders all markers 1`] = `
<Markers
details={
<Relay(FlagDetailsContainer)
<Relay(ModerateCardDetailsContainer)
comment={
Object {
"editing": Object {
"edited": false,
},
"revision": Object {
"actionCounts": Object {
"flag": Object {
@@ -30,6 +33,8 @@ exports[`renders all markers 1`] = `
"status": "PREMOD",
}
}
hasDetails={true}
hasRevisions={false}
onUsernameClick={[Function]}
settings={
Object {
@@ -143,9 +148,12 @@ exports[`renders all markers 1`] = `
exports[`renders some markers 1`] = `
<Markers
details={
<Relay(FlagDetailsContainer)
<Relay(ModerateCardDetailsContainer)
comment={
Object {
"editing": Object {
"edited": false,
},
"revision": Object {
"actionCounts": Object {
"flag": Object {
@@ -170,6 +178,8 @@ exports[`renders some markers 1`] = `
"status": "PREMOD",
}
}
hasDetails={true}
hasRevisions={false}
onUsernameClick={[Function]}
settings={
Object {
+10
View File
@@ -501,6 +501,16 @@ export const baseComment = createFixture<GQLComment>({
edges: [],
pageInfo: { endCursor: null, hasNextPage: false },
},
editing: {
edited: false,
},
revisionHistory: [
{
id: "revision",
body: "Comment body",
createdAt: "2018-07-06T18:24:00.000Z",
},
],
revision: {
actionCounts: {
flag: {
+3
View File
@@ -412,6 +412,7 @@ moderate-emptyQueue-reported = Nicely done! There are no more reported comments
moderate-emptyQueue-unmoderated = Nicely done! All comments have been moderated.
moderate-emptyQueue-rejected = There are no rejected comments.
moderate-comment-edited = (edited)
moderate-comment-inReplyTo = Reply to <Username></Username>
moderate-comment-viewContext = View Context
moderate-comment-rejectButton =
@@ -460,6 +461,8 @@ moderate-searchBar-comboBoxTextField =
moderate-searchBar-goTo = Go to
moderate-searchBar-seeAllResults = See all results
moderateCardDetails-tab-details = Details
moderateCardDetails-tab-edits = Edit history
### Moderate User History Drawer
moderate-user-drawer-email =