mirror of
https://github.com/wassname/talk.git
synced 2026-09-10 12:43:11 +08:00
Q&A Beta (#2845)
* [CORL-863] Allow streams to be converted/configured to Q&A (#2809) * Create preliminary schema changes for Q&A Adds a mode and expert User onto the StorySettings. Adds a mode selection drop down on a story's Configure tab. CORL-863 * Allow multiple experts, remove form elements from search Makes the previous expert user on a Q&A story now an array of users who can be assigned. Converts the previous form based search that was pulled from the admin community area into a set of events built on callbacks. CORL-863 * Create addExpertToStory mutation CORL-863 * Create removeExpertFromStory mutation CORL-863 * Conditionally show the the expert selection options CORL-863 * Create a dropdown search control for Q&A experts CORL-863 * Fixing up tests to match new QA stream options Adds a few localization fixes to make sure tests pass. Updates existing snapshots. CORL-863 * Add load more button to expert search list CORL-863 * Update experts query to match react upgrades CORL-863 * Move the Q&A config to its own section under stream config Create enable and disable Q&A mutations/button toggle. CORL-863 * Fix alignment and layout of expert list items CORL-863 * Define translations and update tests CORL-863 * Use official copy for Q&A config CORL-863 * [CORL-856] Show expert badge on comments (#2829) * Create preliminary schema changes for Q&A Adds a mode and expert User onto the StorySettings. Adds a mode selection drop down on a story's Configure tab. CORL-863 * Allow multiple experts, remove form elements from search Makes the previous expert user on a Q&A story now an array of users who can be assigned. Converts the previous form based search that was pulled from the admin community area into a set of events built on callbacks. CORL-863 * Create addExpertToStory mutation CORL-863 * Create removeExpertFromStory mutation CORL-863 * Conditionally show the the expert selection options CORL-863 * Create a dropdown search control for Q&A experts CORL-863 * Fixing up tests to match new QA stream options Adds a few localization fixes to make sure tests pass. Updates existing snapshots. CORL-863 * Add load more button to expert search list CORL-863 * Update experts query to match react upgrades CORL-863 * Move the Q&A config to its own section under stream config Create enable and disable Q&A mutations/button toggle. CORL-863 * Fix alignment and layout of expert list items CORL-863 * Define translations and update tests CORL-863 * Use official copy for Q&A config CORL-863 * Show expert badges on comments when Q&A is enabled CORL-856 * Update mutation responses and tests due to added expert fields CORL-856 * Use EXPERT user tags to denote expert users Removes the need for viewerIsExpert and authorIsExpert loader/resolvers on Stories and Comments respectively. CORL-856 * [CORL-879] Add an unanswered tab to stream when in Q&A mode (#2838) * Create preliminary schema changes for Q&A Adds a mode and expert User onto the StorySettings. Adds a mode selection drop down on a story's Configure tab. CORL-863 * Allow multiple experts, remove form elements from search Makes the previous expert user on a Q&A story now an array of users who can be assigned. Converts the previous form based search that was pulled from the admin community area into a set of events built on callbacks. CORL-863 * Create addExpertToStory mutation CORL-863 * Create removeExpertFromStory mutation CORL-863 * Conditionally show the the expert selection options CORL-863 * Create a dropdown search control for Q&A experts CORL-863 * Fixing up tests to match new QA stream options Adds a few localization fixes to make sure tests pass. Updates existing snapshots. CORL-863 * Add load more button to expert search list CORL-863 * Update experts query to match react upgrades CORL-863 * Move the Q&A config to its own section under stream config Create enable and disable Q&A mutations/button toggle. CORL-863 * Fix alignment and layout of expert list items CORL-863 * Define translations and update tests CORL-863 * Use official copy for Q&A config CORL-863 * Show expert badges on comments when Q&A is enabled CORL-856 * Update mutation responses and tests due to added expert fields CORL-856 * Use EXPERT user tags to denote expert users Removes the need for viewerIsExpert and authorIsExpert loader/resolvers on Stories and Comments respectively. CORL-856 * Show an unanswered comment stream when Q&A is enabled CORL-879 * Do not visually show the unanswered tag CORL-879 * [CORL-859] Convert Featured stream into Answered for Q&A (#2842) * Create preliminary schema changes for Q&A Adds a mode and expert User onto the StorySettings. Adds a mode selection drop down on a story's Configure tab. CORL-863 * Allow multiple experts, remove form elements from search Makes the previous expert user on a Q&A story now an array of users who can be assigned. Converts the previous form based search that was pulled from the admin community area into a set of events built on callbacks. CORL-863 * Create addExpertToStory mutation CORL-863 * Create removeExpertFromStory mutation CORL-863 * Conditionally show the the expert selection options CORL-863 * Create a dropdown search control for Q&A experts CORL-863 * Fixing up tests to match new QA stream options Adds a few localization fixes to make sure tests pass. Updates existing snapshots. CORL-863 * Add load more button to expert search list CORL-863 * Update experts query to match react upgrades CORL-863 * Move the Q&A config to its own section under stream config Create enable and disable Q&A mutations/button toggle. CORL-863 * Fix alignment and layout of expert list items CORL-863 * Define translations and update tests CORL-863 * Use official copy for Q&A config CORL-863 * Show expert badges on comments when Q&A is enabled CORL-856 * Update mutation responses and tests due to added expert fields CORL-856 * Use EXPERT user tags to denote expert users Removes the need for viewerIsExpert and authorIsExpert loader/resolvers on Stories and Comments respectively. CORL-856 * Show an unanswered comment stream when Q&A is enabled CORL-879 * Create preliminary schema changes for Q&A Adds a mode and expert User onto the StorySettings. Adds a mode selection drop down on a story's Configure tab. CORL-863 * Do not visually show the unanswered tag CORL-879 * Allow multiple experts, remove form elements from search Makes the previous expert user on a Q&A story now an array of users who can be assigned. Converts the previous form based search that was pulled from the admin community area into a set of events built on callbacks. CORL-863 * Create addExpertToStory mutation CORL-863 * Create removeExpertFromStory mutation CORL-863 * Create a dropdown search control for Q&A experts CORL-863 * Fixing up tests to match new QA stream options Adds a few localization fixes to make sure tests pass. Updates existing snapshots. CORL-863 * Add load more button to expert search list CORL-863 * Update experts query to match react upgrades CORL-863 * Move the Q&A config to its own section under stream config Create enable and disable Q&A mutations/button toggle. CORL-863 * Fix alignment and layout of expert list items CORL-863 * Define translations and update tests CORL-863 * Show expert badges on comments when Q&A is enabled CORL-856 * Use official copy for Q&A config CORL-863 * Update mutation responses and tests due to added expert fields CORL-856 * Use EXPERT user tags to denote expert users Removes the need for viewerIsExpert and authorIsExpert loader/resolvers on Stories and Comments respectively. CORL-856 * Create the answered stream for Q&A CORL-859 * Sort the Q&A on Most Voted by default CORL-859 * Fix type mismatch between post comment form and fragments CORL-859 * Adding localizations for Q&A tags * Hide feature flags in Q&A streams * Allow experts to clear answered questions Can click a button that shows up in the unanswered tab under answered questions to refresh the stream, clearing the answered questions from that tab. * Show arrow upvote icon when in Q&A mode Also localized the upvote text so it can be translated. * Hide mod/report buttons on answered questions * Remove unnecessary fragment container * Remove errant debug console log * Make story mode required on story settings * Make remove button outlined, not filled * Further schema changes around Q&A and experts Rename add/remove story expert to removeStoryExpert and addStoryExpert naming. Replace enableQA and disableQA mutators with single updateStoryMode mutator. * Remove story mode from UpdateStorySettings * Replace inline string val's with enum * add dependencies to useEffect * docs cleanup around tags.type index check * Approve a question when it is answered in Q&A Approves using the author's id as the moderator * Add comment around use of TAG on comments edge * Use tagFilter instead of $elemMatch to filter by tags * Improve responsive styles for expert list items * Update copy to "Done" from "Remove answered questions" * Text styling for no users found text Styles the expert search list to have proper text styling when no users are found for the search keyword. * Remove duplicate checks around story experts Not necessary as Mongo does this for us. * Fix a missed "sort imports" during rebase * Refactor Q&A moderation phases for clarity Simplify logic and update comments. Rename: "answered" -> "tagExpertAnswers" Rename: "unanswered" -> "tagUnansweredQuestions" * Remove username & email from add expert mutation * Format expert list emails with Localized * Break out no comments logic into fragment * Remove ref handling from expert search field Use value assignment on TextField instead. * Replace Box with Flex and CSS * Show Q&A tooltip on Answered tab Co-authored-by: Kim Gardner <kgardnr@gmail.com>
This commit is contained in:
@@ -200,12 +200,17 @@ export default (ctx: Context) => ({
|
||||
"tags.type": tag,
|
||||
},
|
||||
}).then(primeCommentsFromConnection(ctx)),
|
||||
forStory: (storyID: string, { first, orderBy, after }: StoryToCommentsArgs) =>
|
||||
forStory: (
|
||||
storyID: string,
|
||||
{ first, orderBy, after, tag }: StoryToCommentsArgs
|
||||
) =>
|
||||
retrieveCommentStoryConnection(ctx.mongo, ctx.tenant.id, storyID, {
|
||||
first: defaultTo(first, 10),
|
||||
orderBy: defaultTo(orderBy, GQLCOMMENT_SORT.CREATED_AT_DESC),
|
||||
after,
|
||||
filter: {
|
||||
// Ensure we filter by the requested tag
|
||||
...tagFilter(tag),
|
||||
// Only get Comments that are top level. If the client wants to load
|
||||
// another layer, they can request another nested connection.
|
||||
parentID: null,
|
||||
|
||||
@@ -5,24 +5,30 @@ import GraphContext from "coral-server/graph/context";
|
||||
import { mapFieldsetToErrorCodes } from "coral-server/graph/errors";
|
||||
import { Story } from "coral-server/models/story";
|
||||
import {
|
||||
addStoryExpert,
|
||||
close,
|
||||
create,
|
||||
merge,
|
||||
open,
|
||||
remove,
|
||||
removeStoryExpert,
|
||||
update,
|
||||
updateSettings,
|
||||
updateStoryMode,
|
||||
} from "coral-server/services/stories";
|
||||
import { scrape } from "coral-server/services/stories/scraper";
|
||||
|
||||
import {
|
||||
GQLAddExpertInput,
|
||||
GQLCloseStoryInput,
|
||||
GQLCreateStoryInput,
|
||||
GQLMergeStoriesInput,
|
||||
GQLOpenStoryInput,
|
||||
GQLRemoveExpertInput,
|
||||
GQLRemoveStoryInput,
|
||||
GQLScrapeStoryInput,
|
||||
GQLUpdateStoryInput,
|
||||
GQLUpdateStoryModeInput,
|
||||
GQLUpdateStorySettingsInput,
|
||||
} from "coral-server/graph/schema/__generated__/types";
|
||||
|
||||
@@ -70,4 +76,10 @@ export const Stories = (ctx: GraphContext) => ({
|
||||
remove(ctx.mongo, ctx.tenant, input.id, input.includeComments),
|
||||
scrape: async (input: GQLScrapeStoryInput): Promise<Readonly<Story> | null> =>
|
||||
scrape(ctx.mongo, ctx.config, ctx.tenant.id, input.id),
|
||||
updateStoryMode: async (input: GQLUpdateStoryModeInput) =>
|
||||
updateStoryMode(ctx.mongo, ctx.tenant, input.storyID, input.mode),
|
||||
addStoryExpert: async (input: GQLAddExpertInput) =>
|
||||
addStoryExpert(ctx.mongo, ctx.tenant, input.storyID, input.userID),
|
||||
removeStoryExpert: async (input: GQLRemoveExpertInput) =>
|
||||
removeStoryExpert(ctx.mongo, ctx.tenant, input.storyID, input.userID),
|
||||
});
|
||||
|
||||
@@ -256,6 +256,18 @@ export const Mutation: Required<GQLMutationTypeResolver<void>> = {
|
||||
site: await ctx.mutators.Sites.update(input),
|
||||
clientMutationId: input.clientMutationId,
|
||||
}),
|
||||
updateStoryMode: async (source, { input }, ctx) => ({
|
||||
story: await ctx.mutators.Stories.updateStoryMode(input),
|
||||
clientMutationId: input.clientMutationId,
|
||||
}),
|
||||
addStoryExpert: async (source, { input }, ctx) => ({
|
||||
story: await ctx.mutators.Stories.addStoryExpert(input),
|
||||
clientMutationId: input.clientMutationId,
|
||||
}),
|
||||
removeStoryExpert: async (source, { input }, ctx) => ({
|
||||
story: await ctx.mutators.Stories.removeStoryExpert(input),
|
||||
clientMutationId: input.clientMutationId,
|
||||
}),
|
||||
createWebhookEndpoint: async (
|
||||
source,
|
||||
{ input: { clientMutationId, ...input } },
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
import * as story from "coral-server/models/story";
|
||||
|
||||
import { GQLStorySettingsTypeResolver } from "../schema/__generated__/types";
|
||||
import {
|
||||
GQLSTORY_MODE,
|
||||
GQLStorySettingsTypeResolver,
|
||||
} from "../schema/__generated__/types";
|
||||
|
||||
export const StorySettings: GQLStorySettingsTypeResolver<
|
||||
story.StorySettings
|
||||
@@ -18,4 +21,18 @@ export const StorySettings: GQLStorySettingsTypeResolver<
|
||||
enabled: false,
|
||||
};
|
||||
},
|
||||
mode: s => {
|
||||
if (s.mode) {
|
||||
return s.mode;
|
||||
}
|
||||
|
||||
return GQLSTORY_MODE.COMMENTS;
|
||||
},
|
||||
experts: (s, input, ctx) => {
|
||||
if (s.expertIDs) {
|
||||
return ctx.loaders.Users.user.loadMany(s.expertIDs);
|
||||
}
|
||||
|
||||
return [];
|
||||
},
|
||||
};
|
||||
|
||||
@@ -372,6 +372,18 @@ type WordList {
|
||||
suspect: [String!]!
|
||||
}
|
||||
|
||||
enum STORY_MODE {
|
||||
"""
|
||||
Coments is when a story is used for general commenting.
|
||||
"""
|
||||
COMMENTS
|
||||
|
||||
"""
|
||||
QA is used for when the story is in Q&A mode.
|
||||
"""
|
||||
QA
|
||||
}
|
||||
|
||||
################################################################################
|
||||
## Moderation
|
||||
################################################################################
|
||||
@@ -2345,6 +2357,18 @@ enum TAG {
|
||||
FEATURED is used when a Comment is marked as such by a staff member.
|
||||
"""
|
||||
FEATURED
|
||||
|
||||
"""
|
||||
EXPERT is used when an a Comment is written by a User that is assigned as
|
||||
an expert on a story.
|
||||
"""
|
||||
EXPERT
|
||||
|
||||
"""
|
||||
UNANSWERED is used when a Comment is written by a User and is unanswered
|
||||
by an expert for that Comment's story.
|
||||
"""
|
||||
UNANSWERED
|
||||
}
|
||||
|
||||
"""
|
||||
@@ -2376,6 +2400,11 @@ type CommentTagCounts {
|
||||
FEATURED is the count of Comment's with the FEATURED tag.
|
||||
"""
|
||||
FEATURED: Int!
|
||||
|
||||
"""
|
||||
UNANSWERED is the count of Comment's with the UNANSWERED tag.
|
||||
"""
|
||||
UNANSWERED: Int!
|
||||
}
|
||||
|
||||
"""
|
||||
@@ -2720,6 +2749,19 @@ type StorySettings {
|
||||
messageBox stores settings related to the Story Message Box.
|
||||
"""
|
||||
messageBox: StoryMessageBox!
|
||||
|
||||
"""
|
||||
mode is whether the story stream is in commenting or Q&A mode.
|
||||
This will determine the appearance of the stream and how it functions.
|
||||
"""
|
||||
mode: STORY_MODE!
|
||||
|
||||
"""
|
||||
experts are used during Q&A mode to assign users to answer questions
|
||||
on a Q&A stream. It is an optional parameter and is only used when
|
||||
the story stream is in Q&A mode.
|
||||
"""
|
||||
experts: [User!]!
|
||||
}
|
||||
|
||||
"""
|
||||
@@ -2783,6 +2825,14 @@ type Story {
|
||||
first: Int = 20 @constraint(max: 50)
|
||||
orderBy: COMMENT_SORT = CREATED_AT_DESC
|
||||
after: Cursor
|
||||
|
||||
"""
|
||||
This is a workaround to allow filtering for current Q&A
|
||||
functionality. This is used to filter on UNANSWERED to
|
||||
populate its corresponding Unanswered questions tab. In
|
||||
the future, we want a dedicated edge for unansweredComments.
|
||||
"""
|
||||
tag: TAG
|
||||
): CommentsConnection!
|
||||
|
||||
"""
|
||||
@@ -5827,6 +5877,97 @@ type DisableFeatureFlagPayload {
|
||||
flags: [FEATURE_FLAG!]!
|
||||
}
|
||||
|
||||
#########################
|
||||
# Add / Remove Expert
|
||||
#########################
|
||||
|
||||
input AddExpertInput {
|
||||
"""
|
||||
clientMutationId is required for Relay support.
|
||||
"""
|
||||
clientMutationId: String!
|
||||
|
||||
"""
|
||||
storyID is the story to add the expert to.
|
||||
"""
|
||||
storyID: ID!
|
||||
|
||||
"""
|
||||
userID is the user to add as an expert to the story.
|
||||
"""
|
||||
userID: ID!
|
||||
}
|
||||
|
||||
type AddExpertPayload {
|
||||
"""
|
||||
clientMutationId is required for Relay support.
|
||||
"""
|
||||
clientMutationId: String!
|
||||
|
||||
"""
|
||||
story is the resultant story the expert was added to.
|
||||
"""
|
||||
story: Story!
|
||||
}
|
||||
|
||||
input RemoveExpertInput {
|
||||
"""
|
||||
clientMutationId is required for Relay support.
|
||||
"""
|
||||
clientMutationId: String!
|
||||
|
||||
"""
|
||||
storyID is the story to remove the expert from.
|
||||
"""
|
||||
storyID: ID!
|
||||
|
||||
"""
|
||||
userID is the user to remove as an expert from the story.
|
||||
"""
|
||||
userID: ID!
|
||||
}
|
||||
|
||||
type RemoveExpertPayload {
|
||||
"""
|
||||
clientMutationId is required for Relay support.
|
||||
"""
|
||||
clientMutationId: String!
|
||||
|
||||
"""
|
||||
story is the resultant story the expert was removed from.
|
||||
"""
|
||||
story: Story!
|
||||
}
|
||||
|
||||
input UpdateStoryModeInput {
|
||||
"""
|
||||
storyID is the story id to enable Q&A on.
|
||||
"""
|
||||
storyID: ID!
|
||||
|
||||
"""
|
||||
mode is the mode to set the story to.
|
||||
"""
|
||||
mode: STORY_MODE!
|
||||
|
||||
"""
|
||||
clientMutationId is required for Relay support.
|
||||
"""
|
||||
clientMutationId: String!
|
||||
}
|
||||
|
||||
type UpdateStoryModePayload {
|
||||
"""
|
||||
story is the resultant story that Q&A was enabled on.
|
||||
"""
|
||||
story: Story!
|
||||
|
||||
"""
|
||||
clientMutationId is required for Relay support.
|
||||
"""
|
||||
clientMutationId: String!
|
||||
}
|
||||
|
||||
##################
|
||||
## Mutation
|
||||
##################
|
||||
@@ -6199,10 +6340,16 @@ type Mutation {
|
||||
input: DisableFeatureFlagInput!
|
||||
): DisableFeatureFlagPayload! @auth(roles: [ADMIN])
|
||||
|
||||
"""
|
||||
createAnnouncement creates a global announcement.
|
||||
"""
|
||||
createAnnouncement(
|
||||
input: CreateAnnouncementInput!
|
||||
): CreateAnnouncementPayload! @auth(roles: [ADMIN])
|
||||
|
||||
"""
|
||||
deleteAnnouncement removes a global announcement.
|
||||
"""
|
||||
deleteAnnouncement(
|
||||
input: DeleteAnnouncementInput!
|
||||
): DeleteAnnouncementPayload! @auth(roles: [ADMIN])
|
||||
@@ -6253,6 +6400,26 @@ type Mutation {
|
||||
rotateWebhookEndpointSecret(
|
||||
input: RotateWebhookEndpointSecretInput!
|
||||
): RotateWebhookEndpointSecretPayload! @auth(roles: [ADMIN])
|
||||
|
||||
"""
|
||||
updateStoryMode will set the story mode.
|
||||
"""
|
||||
updateStoryMode(input: UpdateStoryModeInput!): UpdateStoryModePayload!
|
||||
@auth(roles: [ADMIN, MODERATOR])
|
||||
|
||||
"""
|
||||
addStoryExpert adds an expert to a story.
|
||||
"""
|
||||
addStoryExpert(
|
||||
input: AddExpertInput!
|
||||
): AddExpertPayload! @auth(roles: [ADMIN, MODERATOR])
|
||||
|
||||
"""
|
||||
removeStoryExpert removes an expert from a story.
|
||||
"""
|
||||
removeStoryExpert(
|
||||
input: RemoveExpertInput!
|
||||
): RemoveExpertPayload! @auth(roles: [ADMIN, MODERATOR])
|
||||
}
|
||||
|
||||
##################
|
||||
|
||||
Reference in New Issue
Block a user