mirror of
https://github.com/wassname/talk.git
synced 2026-07-06 05:17:19 +08:00
[next] Comment Reply Revisions (#2072)
* feat: added revision id support for replies * feat: use createCommentReply
This commit is contained in:
@@ -0,0 +1,17 @@
|
||||
import { RecordSourceSelectorProxy } from "relay-runtime";
|
||||
|
||||
export default function incrementStoryCommentCounts(
|
||||
store: RecordSourceSelectorProxy,
|
||||
storyID: string
|
||||
) {
|
||||
// Updating Comment Count
|
||||
const story = store.get(storyID);
|
||||
if (story) {
|
||||
const record = story.getLinkedRecord("commentCounts");
|
||||
if (record) {
|
||||
// TODO: when we have moderation, we'll need to be careful here.
|
||||
const currentCount = record.getValue("totalVisible");
|
||||
record.setValue(currentCount + 1, "totalVisible");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
export {
|
||||
default as incrementStoryCommentCounts,
|
||||
} from "./incrementStoryCommentCounts";
|
||||
export {
|
||||
default as prependCommentEdgeToProfile,
|
||||
} from "./prependCommentEdgeToProfile";
|
||||
@@ -0,0 +1,25 @@
|
||||
import {
|
||||
ConnectionHandler,
|
||||
Environment,
|
||||
RecordProxy,
|
||||
RecordSourceSelectorProxy,
|
||||
} from "relay-runtime";
|
||||
|
||||
import { getMeSourceID } from "talk-framework/helpers";
|
||||
|
||||
export default function prependCommentEdgeToProfile(
|
||||
environment: Environment,
|
||||
store: RecordSourceSelectorProxy,
|
||||
commentEdge: RecordProxy
|
||||
) {
|
||||
const meProxy = store.get(getMeSourceID(environment)!);
|
||||
const con = ConnectionHandler.getConnection(
|
||||
meProxy,
|
||||
"CommentHistory_comments"
|
||||
);
|
||||
// Note: Currently this is always null, until Relay comes
|
||||
// with better data retaintion and data from store support.
|
||||
if (con) {
|
||||
ConnectionHandler.insertEdgeBefore(con, commentEdge);
|
||||
}
|
||||
}
|
||||
@@ -5,144 +5,69 @@ import {
|
||||
RecordSourceSelectorProxy,
|
||||
} from "relay-runtime";
|
||||
|
||||
import { getMe, getMeSourceID } from "talk-framework/helpers";
|
||||
import { getMe } from "talk-framework/helpers";
|
||||
import { TalkContext } from "talk-framework/lib/bootstrap";
|
||||
import {
|
||||
commitMutationPromiseNormalized,
|
||||
createMutationContainer,
|
||||
} from "talk-framework/lib/relay";
|
||||
import { Omit } from "talk-framework/types";
|
||||
|
||||
import { CreateCommentMutation as MutationTypes } from "talk-stream/__generated__/CreateCommentMutation.graphql";
|
||||
|
||||
import {
|
||||
incrementStoryCommentCounts,
|
||||
prependCommentEdgeToProfile,
|
||||
} from "../helpers";
|
||||
|
||||
export type CreateCommentInput = Omit<
|
||||
MutationTypes["variables"]["input"],
|
||||
"clientMutationId"
|
||||
> & { local?: boolean };
|
||||
>;
|
||||
|
||||
function sharedUpdater(
|
||||
environment: Environment,
|
||||
store: RecordSourceSelectorProxy,
|
||||
input: CreateCommentInput
|
||||
) {
|
||||
updateStory(store, input);
|
||||
if (input.local) {
|
||||
localUpdate(store, input);
|
||||
} else {
|
||||
update(store, input);
|
||||
}
|
||||
updateProfile(environment, store, input);
|
||||
}
|
||||
|
||||
function updateStory(
|
||||
store: RecordSourceSelectorProxy,
|
||||
input: CreateCommentInput
|
||||
) {
|
||||
// Updating Comment Count
|
||||
const story = store.get(input.storyID);
|
||||
if (story) {
|
||||
const record = story.getLinkedRecord("commentCounts");
|
||||
if (record) {
|
||||
// TODO: when we have moderation, we'll need to be careful here.
|
||||
const currentCount = record.getValue("totalVisible");
|
||||
record.setValue(currentCount + 1, "totalVisible");
|
||||
}
|
||||
}
|
||||
incrementStoryCommentCounts(store, input.storyID);
|
||||
prependCommentEdgeToProfile(
|
||||
environment,
|
||||
store,
|
||||
store.getRootField("createComment")!.getLinkedRecord("edge")!
|
||||
);
|
||||
addCommentToStory(store, input);
|
||||
}
|
||||
|
||||
/**
|
||||
* update integrates new comment into the CommentConnection.
|
||||
*/
|
||||
function update(store: RecordSourceSelectorProxy, input: CreateCommentInput) {
|
||||
function addCommentToStory(
|
||||
store: RecordSourceSelectorProxy,
|
||||
input: CreateCommentInput
|
||||
) {
|
||||
// Get the payload returned from the server.
|
||||
const payload = store.getRootField("createComment")!;
|
||||
|
||||
// Get the edge of the newly created comment.
|
||||
const newEdge = payload.getLinkedRecord("edge")!;
|
||||
|
||||
// Get parent proxy.
|
||||
const parentProxy = input.parentID
|
||||
? store.get(input.parentID)
|
||||
: store.get(input.storyID);
|
||||
// Get stream proxy.
|
||||
const streamProxy = store.get(input.storyID);
|
||||
const connectionKey = "Stream_comments";
|
||||
const filters = { orderBy: "CREATED_AT_DESC" };
|
||||
|
||||
const connectionKey = input.parentID
|
||||
? "ReplyList_replies"
|
||||
: "Stream_comments";
|
||||
|
||||
const filters = input.parentID
|
||||
? { orderBy: "CREATED_AT_ASC" }
|
||||
: { orderBy: "CREATED_AT_DESC" };
|
||||
|
||||
const where = input.parentID ? "append" : "prepend";
|
||||
|
||||
if (parentProxy) {
|
||||
if (streamProxy) {
|
||||
const con = ConnectionHandler.getConnection(
|
||||
parentProxy,
|
||||
streamProxy,
|
||||
connectionKey,
|
||||
filters
|
||||
);
|
||||
if (con) {
|
||||
if (where === "prepend") {
|
||||
ConnectionHandler.insertEdgeBefore(con, newEdge);
|
||||
} else {
|
||||
ConnectionHandler.insertEdgeAfter(con, newEdge);
|
||||
}
|
||||
ConnectionHandler.insertEdgeBefore(con, newEdge);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* localUpdate is like update but updates the `localReplies` endpoint.
|
||||
*/
|
||||
function localUpdate(
|
||||
store: RecordSourceSelectorProxy,
|
||||
input: CreateCommentInput
|
||||
) {
|
||||
// Get the payload returned from the server.
|
||||
const payload = store.getRootField("createComment")!;
|
||||
|
||||
// Get the edge of the newly created comment.
|
||||
const newEdge = payload.getLinkedRecord("edge")!;
|
||||
const newComment = newEdge.getLinkedRecord("node");
|
||||
|
||||
// Get parent proxy.
|
||||
const parentProxy = store.get(input.parentID!);
|
||||
|
||||
if (parentProxy) {
|
||||
const localReplies = parentProxy.getLinkedRecords("localReplies");
|
||||
const nextLocalReplies = localReplies
|
||||
? localReplies.concat(newComment)
|
||||
: [newComment];
|
||||
parentProxy.setLinkedRecords(nextLocalReplies, "localReplies");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* updateProfile integrates new comment into the profile.
|
||||
*/
|
||||
function updateProfile(
|
||||
environment: Environment,
|
||||
store: RecordSourceSelectorProxy,
|
||||
input: CreateCommentInput
|
||||
) {
|
||||
// Get the payload returned from the server.
|
||||
const payload = store.getRootField("createComment")!;
|
||||
|
||||
// Get the edge of the newly created comment.
|
||||
const newEdge = payload.getLinkedRecord("edge")!;
|
||||
|
||||
const meProxy = store.get(getMeSourceID(environment)!);
|
||||
const con = ConnectionHandler.getConnection(
|
||||
meProxy,
|
||||
"CommentHistory_comments"
|
||||
);
|
||||
// Note: Currently this is always null, until Relay comes
|
||||
// with better data retaintion and data from store support.
|
||||
if (con) {
|
||||
ConnectionHandler.insertEdgeBefore(con, newEdge);
|
||||
}
|
||||
}
|
||||
|
||||
const mutation = graphql`
|
||||
mutation CreateCommentMutation($input: CreateCommentInput!) {
|
||||
createComment(input: $input) {
|
||||
@@ -172,7 +97,6 @@ function commit(
|
||||
variables: {
|
||||
input: {
|
||||
storyID: input.storyID,
|
||||
parentID: input.parentID,
|
||||
body: input.body,
|
||||
clientMutationId: clientMutationId.toString(),
|
||||
},
|
||||
|
||||
@@ -0,0 +1,178 @@
|
||||
import { graphql } from "react-relay";
|
||||
import {
|
||||
ConnectionHandler,
|
||||
Environment,
|
||||
RecordSourceSelectorProxy,
|
||||
} from "relay-runtime";
|
||||
|
||||
import { getMe } from "talk-framework/helpers";
|
||||
import { TalkContext } from "talk-framework/lib/bootstrap";
|
||||
import {
|
||||
commitMutationPromiseNormalized,
|
||||
createMutationContainer,
|
||||
} from "talk-framework/lib/relay";
|
||||
import { Omit } from "talk-framework/types";
|
||||
import { CreateCommentReplyMutation as MutationTypes } from "talk-stream/__generated__/CreateCommentReplyMutation.graphql";
|
||||
|
||||
import {
|
||||
incrementStoryCommentCounts,
|
||||
prependCommentEdgeToProfile,
|
||||
} from "../helpers";
|
||||
|
||||
export type CreateCommentReplyInput = Omit<
|
||||
MutationTypes["variables"]["input"],
|
||||
"clientMutationId"
|
||||
> & { local?: boolean };
|
||||
|
||||
function sharedUpdater(
|
||||
environment: Environment,
|
||||
store: RecordSourceSelectorProxy,
|
||||
input: CreateCommentReplyInput
|
||||
) {
|
||||
incrementStoryCommentCounts(store, input.storyID);
|
||||
prependCommentEdgeToProfile(
|
||||
environment,
|
||||
store,
|
||||
store.getRootField("createCommentReply")!.getLinkedRecord("edge")!
|
||||
);
|
||||
if (input.local) {
|
||||
addLocalCommentReplyToStory(store, input);
|
||||
} else {
|
||||
addCommentReplyToStory(store, input);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* update integrates new comment into the CommentConnection.
|
||||
*/
|
||||
function addCommentReplyToStory(
|
||||
store: RecordSourceSelectorProxy,
|
||||
input: CreateCommentReplyInput
|
||||
) {
|
||||
// Get the payload returned from the server.
|
||||
const payload = store.getRootField("createCommentReply")!;
|
||||
|
||||
// Get the edge of the newly created comment.
|
||||
const newEdge = payload.getLinkedRecord("edge")!;
|
||||
|
||||
// Get parent proxy.
|
||||
const parentProxy = store.get(input.parentID);
|
||||
const connectionKey = "ReplyList_replies";
|
||||
const filters = { orderBy: "CREATED_AT_ASC" };
|
||||
|
||||
if (parentProxy) {
|
||||
const con = ConnectionHandler.getConnection(
|
||||
parentProxy,
|
||||
connectionKey,
|
||||
filters
|
||||
);
|
||||
if (con) {
|
||||
ConnectionHandler.insertEdgeAfter(con, newEdge);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* localUpdate is like update but updates the `localReplies` endpoint.
|
||||
*/
|
||||
function addLocalCommentReplyToStory(
|
||||
store: RecordSourceSelectorProxy,
|
||||
input: CreateCommentReplyInput
|
||||
) {
|
||||
// Get the payload returned from the server.
|
||||
const payload = store.getRootField("createCommentReply")!;
|
||||
|
||||
// Get the edge of the newly created comment.
|
||||
const newEdge = payload.getLinkedRecord("edge")!;
|
||||
const newComment = newEdge.getLinkedRecord("node");
|
||||
|
||||
// Get parent proxy.
|
||||
const parentProxy = store.get(input.parentID!);
|
||||
|
||||
if (parentProxy) {
|
||||
const localReplies = parentProxy.getLinkedRecords("localReplies");
|
||||
const nextLocalReplies = localReplies
|
||||
? localReplies.concat(newComment)
|
||||
: [newComment];
|
||||
parentProxy.setLinkedRecords(nextLocalReplies, "localReplies");
|
||||
}
|
||||
}
|
||||
|
||||
const mutation = graphql`
|
||||
mutation CreateCommentReplyMutation($input: CreateCommentReplyInput!) {
|
||||
createCommentReply(input: $input) {
|
||||
edge {
|
||||
cursor
|
||||
node {
|
||||
...StreamContainer_comment @relay(mask: false)
|
||||
}
|
||||
}
|
||||
clientMutationId
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
let clientMutationId = 0;
|
||||
|
||||
function commit(
|
||||
environment: Environment,
|
||||
input: CreateCommentReplyInput,
|
||||
{ uuidGenerator }: TalkContext
|
||||
) {
|
||||
const me = getMe(environment)!;
|
||||
const currentDate = new Date().toISOString();
|
||||
const id = uuidGenerator();
|
||||
return commitMutationPromiseNormalized<MutationTypes>(environment, {
|
||||
mutation,
|
||||
variables: {
|
||||
input: {
|
||||
storyID: input.storyID,
|
||||
parentID: input.parentID,
|
||||
parentRevisionID: input.parentRevisionID,
|
||||
body: input.body,
|
||||
clientMutationId: clientMutationId.toString(),
|
||||
},
|
||||
},
|
||||
optimisticResponse: {
|
||||
createCommentReply: {
|
||||
edge: {
|
||||
cursor: currentDate,
|
||||
node: {
|
||||
id,
|
||||
createdAt: currentDate,
|
||||
author: {
|
||||
id: me.id,
|
||||
username: me.username,
|
||||
},
|
||||
body: input.body,
|
||||
editing: {
|
||||
editableUntil: new Date(Date.now() + 10000),
|
||||
},
|
||||
actionCounts: {
|
||||
reaction: {
|
||||
total: 0,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
clientMutationId: (clientMutationId++).toString(),
|
||||
},
|
||||
} as any, // TODO: (cvle) generated types should contain one for the optimistic response.
|
||||
optimisticUpdater: store => {
|
||||
sharedUpdater(environment, store, input);
|
||||
store.get(id)!.setValue(true, "pending");
|
||||
},
|
||||
updater: store => {
|
||||
sharedUpdater(environment, store, input);
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
export const withCreateCommentReplyMutation = createMutationContainer(
|
||||
"createCommentReply",
|
||||
commit
|
||||
);
|
||||
|
||||
export type CreateCommentReplyMutation = (
|
||||
input: CreateCommentReplyInput
|
||||
) => Promise<MutationTypes["response"]["createCommentReply"]>;
|
||||
@@ -3,6 +3,11 @@ export {
|
||||
CreateCommentMutation,
|
||||
CreateCommentInput,
|
||||
} from "./CreateCommentMutation";
|
||||
export {
|
||||
withCreateCommentReplyMutation,
|
||||
CreateCommentReplyMutation,
|
||||
CreateCommentReplyInput,
|
||||
} from "./CreateCommentReplyMutation";
|
||||
export {
|
||||
withEditCommentMutation,
|
||||
EditCommentMutation,
|
||||
|
||||
@@ -19,7 +19,7 @@ function getContextKey(commentID: string) {
|
||||
|
||||
it("renders correctly", async () => {
|
||||
const props: PropTypesOf<typeof ReplyCommentFormContainerN> = {
|
||||
createComment: noop as any,
|
||||
createCommentReply: noop as any,
|
||||
story: {
|
||||
id: "story-id",
|
||||
},
|
||||
@@ -28,6 +28,9 @@ it("renders correctly", async () => {
|
||||
author: {
|
||||
username: "Joe",
|
||||
},
|
||||
revision: {
|
||||
id: "revision-id",
|
||||
},
|
||||
},
|
||||
sessionStorage: createPromisifiedStorage(),
|
||||
autofocus: false,
|
||||
@@ -41,7 +44,7 @@ it("renders correctly", async () => {
|
||||
|
||||
it("renders with initialValues", async () => {
|
||||
const props: PropTypesOf<typeof ReplyCommentFormContainerN> = {
|
||||
createComment: noop as any,
|
||||
createCommentReply: noop as any,
|
||||
story: {
|
||||
id: "story-id",
|
||||
},
|
||||
@@ -50,6 +53,9 @@ it("renders with initialValues", async () => {
|
||||
author: {
|
||||
username: "Joe",
|
||||
},
|
||||
revision: {
|
||||
id: "revision-id",
|
||||
},
|
||||
},
|
||||
sessionStorage: createPromisifiedStorage(),
|
||||
autofocus: false,
|
||||
@@ -68,7 +74,7 @@ it("renders with initialValues", async () => {
|
||||
|
||||
it("save values", async () => {
|
||||
const props: PropTypesOf<typeof ReplyCommentFormContainerN> = {
|
||||
createComment: noop as any,
|
||||
createCommentReply: noop as any,
|
||||
story: {
|
||||
id: "story-id",
|
||||
},
|
||||
@@ -77,6 +83,9 @@ it("save values", async () => {
|
||||
author: {
|
||||
username: "Joe",
|
||||
},
|
||||
revision: {
|
||||
id: "revision-id",
|
||||
},
|
||||
},
|
||||
sessionStorage: createPromisifiedStorage(),
|
||||
autofocus: false,
|
||||
@@ -107,7 +116,7 @@ it("creates a comment", async () => {
|
||||
const onCloseStub = sinon.stub();
|
||||
|
||||
const props: PropTypesOf<typeof ReplyCommentFormContainerN> = {
|
||||
createComment: createCommentStub,
|
||||
createCommentReply: createCommentStub,
|
||||
story: {
|
||||
id: "story-id",
|
||||
},
|
||||
@@ -116,6 +125,9 @@ it("creates a comment", async () => {
|
||||
author: {
|
||||
username: "Joe",
|
||||
},
|
||||
revision: {
|
||||
id: "revision-id",
|
||||
},
|
||||
},
|
||||
sessionStorage: createPromisifiedStorage(),
|
||||
onClose: onCloseStub,
|
||||
@@ -138,6 +150,7 @@ it("creates a comment", async () => {
|
||||
createCommentStub.calledWith({
|
||||
storyID,
|
||||
parentID: props.comment.id,
|
||||
parentRevisionID: "revision-id",
|
||||
...input,
|
||||
})
|
||||
).toBeTruthy();
|
||||
@@ -148,7 +161,7 @@ it("creates a comment", async () => {
|
||||
it("closes on cancel", async () => {
|
||||
const onCloseStub = sinon.stub();
|
||||
const props: PropTypesOf<typeof ReplyCommentFormContainerN> = {
|
||||
createComment: noop as any,
|
||||
createCommentReply: noop as any,
|
||||
story: {
|
||||
id: "story-id",
|
||||
},
|
||||
@@ -157,6 +170,9 @@ it("closes on cancel", async () => {
|
||||
author: {
|
||||
username: "Joe",
|
||||
},
|
||||
revision: {
|
||||
id: "revision-id",
|
||||
},
|
||||
},
|
||||
sessionStorage: createPromisifiedStorage(),
|
||||
onClose: onCloseStub,
|
||||
@@ -186,7 +202,7 @@ it("autofocuses", async () => {
|
||||
const focusStub = sinon.stub();
|
||||
const rte = { focus: focusStub };
|
||||
const props: PropTypesOf<typeof ReplyCommentFormContainerN> = {
|
||||
createComment: noop as any,
|
||||
createCommentReply: noop as any,
|
||||
story: {
|
||||
id: "story-id",
|
||||
},
|
||||
@@ -195,6 +211,9 @@ it("autofocuses", async () => {
|
||||
author: {
|
||||
username: "Joe",
|
||||
},
|
||||
revision: {
|
||||
id: "revision-id",
|
||||
},
|
||||
},
|
||||
sessionStorage: createPromisifiedStorage(),
|
||||
autofocus: true,
|
||||
|
||||
@@ -10,8 +10,8 @@ import { PropTypesOf } from "talk-framework/types";
|
||||
import { ReplyCommentFormContainer_comment as CommentData } from "talk-stream/__generated__/ReplyCommentFormContainer_comment.graphql";
|
||||
import { ReplyCommentFormContainer_story as StoryData } from "talk-stream/__generated__/ReplyCommentFormContainer_story.graphql";
|
||||
import {
|
||||
CreateCommentMutation,
|
||||
withCreateCommentMutation,
|
||||
CreateCommentReplyMutation,
|
||||
withCreateCommentReplyMutation,
|
||||
} from "talk-stream/mutations";
|
||||
|
||||
import ReplyCommentForm, {
|
||||
@@ -19,7 +19,7 @@ import ReplyCommentForm, {
|
||||
} from "../components/ReplyCommentForm";
|
||||
|
||||
interface InnerProps {
|
||||
createComment: CreateCommentMutation;
|
||||
createCommentReply: CreateCommentReplyMutation;
|
||||
sessionStorage: PromisifiedStorage;
|
||||
comment: CommentData;
|
||||
story: StoryData;
|
||||
@@ -74,9 +74,10 @@ export class ReplyCommentFormContainer extends Component<InnerProps, State> {
|
||||
form
|
||||
) => {
|
||||
try {
|
||||
await this.props.createComment({
|
||||
await this.props.createCommentReply({
|
||||
storyID: this.props.story.id,
|
||||
parentID: this.props.comment.id,
|
||||
parentRevisionID: this.props.comment.revision.id,
|
||||
local: this.props.localReply,
|
||||
...input,
|
||||
});
|
||||
@@ -127,7 +128,7 @@ const enhanced = withContext(({ sessionStorage, browserInfo }) => ({
|
||||
// Disable autofocus on ios and enable for the rest.
|
||||
autofocus: !browserInfo.ios,
|
||||
}))(
|
||||
withCreateCommentMutation(
|
||||
withCreateCommentReplyMutation(
|
||||
withFragmentContainer<InnerProps>({
|
||||
story: graphql`
|
||||
fragment ReplyCommentFormContainer_story on Story {
|
||||
@@ -140,6 +141,9 @@ const enhanced = withContext(({ sessionStorage, browserInfo }) => ({
|
||||
author {
|
||||
username
|
||||
}
|
||||
revision {
|
||||
id
|
||||
}
|
||||
}
|
||||
`,
|
||||
})(ReplyCommentFormContainer)
|
||||
|
||||
@@ -28,7 +28,7 @@ beforeEach(() => {
|
||||
),
|
||||
},
|
||||
Mutation: {
|
||||
createComment: createSinonStub(
|
||||
createCommentReply: createSinonStub(
|
||||
s => s.throws(),
|
||||
s =>
|
||||
s
|
||||
@@ -36,6 +36,7 @@ beforeEach(() => {
|
||||
input: {
|
||||
storyID: storyWithDeepestReplies.id,
|
||||
parentID: "comment-with-deepest-replies-5",
|
||||
parentRevisionID: "revision-0",
|
||||
body: "<strong>Hello world!</strong>",
|
||||
clientMutationId: "0",
|
||||
},
|
||||
|
||||
@@ -23,7 +23,7 @@ beforeEach(() => {
|
||||
),
|
||||
},
|
||||
Mutation: {
|
||||
createComment: createSinonStub(
|
||||
createCommentReply: createSinonStub(
|
||||
s => s.throws(),
|
||||
s =>
|
||||
s
|
||||
@@ -31,6 +31,7 @@ beforeEach(() => {
|
||||
input: {
|
||||
storyID: stories[0].id,
|
||||
parentID: stories[0].comments.edges[0].node.id,
|
||||
parentRevisionID: stories[0].comments.edges[0].node.revision.id,
|
||||
body: "<strong>Hello world!</strong>",
|
||||
clientMutationId: "0",
|
||||
},
|
||||
|
||||
@@ -4,6 +4,7 @@ import {
|
||||
GQLCreateCommentFlagInput,
|
||||
GQLCreateCommentInput,
|
||||
GQLCreateCommentReactionInput,
|
||||
GQLCreateCommentReplyInput,
|
||||
GQLEditCommentInput,
|
||||
GQLRemoveCommentDontAgreeInput,
|
||||
GQLRemoveCommentFlagInput,
|
||||
@@ -20,12 +21,15 @@ import {
|
||||
} from "talk-server/services/comments/actions";
|
||||
|
||||
export const Comment = (ctx: TenantContext) => ({
|
||||
create: ({ storyID, body, parentID }: GQLCreateCommentInput) =>
|
||||
create: ({
|
||||
clientMutationId,
|
||||
...comment
|
||||
}: GQLCreateCommentInput | GQLCreateCommentReplyInput) =>
|
||||
create(
|
||||
ctx.mongo,
|
||||
ctx.tenant,
|
||||
ctx.user!,
|
||||
{ authorID: ctx.user!.id, storyID, body, parentID },
|
||||
{ authorID: ctx.user!.id, ...comment },
|
||||
ctx.req
|
||||
),
|
||||
edit: ({ commentID, body }: GQLEditCommentInput) =>
|
||||
|
||||
@@ -1,24 +1,30 @@
|
||||
import { GQLMutationTypeResolver } from "talk-server/graph/tenant/schema/__generated__/types";
|
||||
|
||||
export const Mutation: GQLMutationTypeResolver<void> = {
|
||||
export const Mutation: Required<GQLMutationTypeResolver<void>> = {
|
||||
editComment: async (source, { input }, ctx) => ({
|
||||
comment: await ctx.mutators.Comment.edit(input),
|
||||
clientMutationId: input.clientMutationId,
|
||||
}),
|
||||
createComment: async (source, { input }, ctx) => {
|
||||
const comment = await ctx.mutators.Comment.create(input);
|
||||
return {
|
||||
edge: {
|
||||
// NOTE: (cvle)
|
||||
// Depending on the sort we can't determine the accurate cursor in a
|
||||
// performant way, so we return null instead. It seems that Relay does
|
||||
// not directly use this value.
|
||||
cursor: null,
|
||||
node: comment,
|
||||
},
|
||||
clientMutationId: input.clientMutationId,
|
||||
};
|
||||
},
|
||||
createComment: async (source, { input }, ctx) => ({
|
||||
edge: {
|
||||
// Depending on the sort we can't determine the accurate cursor in a
|
||||
// performant way, so we return null instead. It seems that Relay does
|
||||
// not directly use this value.
|
||||
cursor: null,
|
||||
node: await ctx.mutators.Comment.create(input),
|
||||
},
|
||||
clientMutationId: input.clientMutationId,
|
||||
}),
|
||||
createCommentReply: async (source, { input }, ctx) => ({
|
||||
edge: {
|
||||
// Depending on the sort we can't determine the accurate cursor in a
|
||||
// performant way, so we return null instead. It seems that Relay does
|
||||
// not directly use this value.
|
||||
cursor: null,
|
||||
node: await ctx.mutators.Comment.create(input),
|
||||
},
|
||||
clientMutationId: input.clientMutationId,
|
||||
}),
|
||||
updateSettings: async (source, { input }, ctx) => ({
|
||||
settings: await ctx.mutators.Settings.update(input.settings),
|
||||
clientMutationId: input.clientMutationId,
|
||||
|
||||
@@ -1529,11 +1529,6 @@ input CreateCommentInput {
|
||||
"""
|
||||
storyID: ID!
|
||||
|
||||
"""
|
||||
parentID is the optional ID of the Comment that we are replying to.
|
||||
"""
|
||||
parentID: ID
|
||||
|
||||
"""
|
||||
body is the Comment body, the content of the Comment.
|
||||
"""
|
||||
@@ -1561,6 +1556,56 @@ type CreateCommentPayload {
|
||||
clientMutationId: String!
|
||||
}
|
||||
|
||||
##################
|
||||
## createCommentReply
|
||||
##################
|
||||
|
||||
"""
|
||||
CreateCommentReplyInput provides the input for the createCommentReply Mutation.
|
||||
"""
|
||||
input CreateCommentReplyInput {
|
||||
"""
|
||||
storyID is the ID of the Story where we are creating a comment on.
|
||||
"""
|
||||
storyID: ID!
|
||||
|
||||
"""
|
||||
parentID is the ID of the Comment that we are replying to.
|
||||
"""
|
||||
parentID: ID!
|
||||
|
||||
"""
|
||||
parentRevisionID is the ID of the CommentRevision that we are replying to.
|
||||
"""
|
||||
parentRevisionID: ID!
|
||||
|
||||
"""
|
||||
body is the Comment body, the content of the Comment.
|
||||
"""
|
||||
body: String!
|
||||
|
||||
"""
|
||||
clientMutationId is required for Relay support.
|
||||
"""
|
||||
clientMutationId: String!
|
||||
}
|
||||
|
||||
"""
|
||||
CreateCommentReplyPayload contains the created Comment after the createCommentReply
|
||||
mutation.
|
||||
"""
|
||||
type CreateCommentReplyPayload {
|
||||
"""
|
||||
edge is the possibly created comment edge.
|
||||
"""
|
||||
edge: CommentEdge
|
||||
|
||||
"""
|
||||
clientMutationId is required for Relay support.
|
||||
"""
|
||||
clientMutationId: String!
|
||||
}
|
||||
|
||||
##################
|
||||
## editComment
|
||||
##################
|
||||
@@ -2805,6 +2850,12 @@ type Mutation {
|
||||
"""
|
||||
createComment(input: CreateCommentInput!): CreateCommentPayload
|
||||
|
||||
"""
|
||||
createCommentReply will create a Comment as the current logged in User that is
|
||||
in reply to another Comment.
|
||||
"""
|
||||
createCommentReply(input: CreateCommentReplyInput!): CreateCommentReplyPayload
|
||||
|
||||
"""
|
||||
editComment will allow the author of a comment to change the body within the
|
||||
time allotment.
|
||||
|
||||
@@ -64,6 +64,12 @@ export interface Comment extends TenantResource {
|
||||
*/
|
||||
parentID?: string;
|
||||
|
||||
/**
|
||||
* parentRevisionID is the ID of the Revision on the parent Comment that this
|
||||
* was a reply to.
|
||||
*/
|
||||
parentRevisionID?: string;
|
||||
|
||||
/**
|
||||
* authorID stores the ID of the User that created this Comment.
|
||||
*/
|
||||
|
||||
Reference in New Issue
Block a user