mirror of
https://github.com/wassname/talk.git
synced 2026-07-05 08:32:10 +08:00
[CORL-51] show comment revisions (#2590)
* add comment revisions * reverse history order * add strings * update fixtures * fix fixtures
This commit is contained in:
@@ -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;
|
||||
+12
-2
@@ -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 {
|
||||
|
||||
@@ -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: {
|
||||
|
||||
@@ -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 =
|
||||
|
||||
Reference in New Issue
Block a user