[CORL-645] Resolve mismanaged branch merging (#2746)

* Create preliminary schema for setting Slack channels

CORL-645

* Implement preliminary slack notification using tenant slack channels

CORL-645

* Very preliminarily get data loading with FieldArray's for slack channels

CORL-645

* Update settings input on schema to allow saving Slack settings to tenant

CORL-645

* Filter off UNMODERATED queue events from slack channels

We don't send these to slack through our filters, we only care
about pending, reported, and featured

CORL-645

* Include a moderation link in comments pushed to Slack

CORL-645

* Hook up proper callback functions for adding/removing slack channels

CORL-645

* Add missing translation for Slack navigation item

CORL-645

* Update snapshots for preliminary Slack configuration changes

CORL-645

* Add some FormField wrappers around slack config elements

Makes the UI appear a little nicer

CORL-645

* Set up slack config to only provide one slack channel

We need to do this until we can get ArrayField's working
in final-form.

CORL-645

* Disable the other trigger checkboxes when "All Comments" is checked

CORL-645

* Clean up the formatting of Slack messages

CORL-645

* Add error handling around sending comments to Slack

CORL-645

* Add links to external Slack setup documentation

CORL-645

* Replace form state with wrapped field element

CORL-645

* Clean up fetch request sending Slack notifications

CORL-645

* Prefer global string replacement over RegEx

CORL-645

* Use URL class to construct comment URL's

CORL-645

* Require slack configuration in schema

CORL-645

* Initialize Slack in fixtures

Also fix up a flaky test that wasn't waiting
on form submission and on-change events.

CORL-645

* Preliminarily fix up styles to match other config pages

CORL-645

* Create placeholder add/remove buttons

* Convert SlackConfigContainer to FunctionalComponent

CORL-645

* Add name field to slack channels

CORL-645

* Disable inner fields on Slack channel when not enabled

CORL-645

* Improve the delete channel button

CORL-645

* Use pureMerge to extract slack channel settings

CORL-645

* Do a bit of cleanup on the add channel button

CORL-645

* Update the styling of the Slack config

- Use sub header for channel headings
- Update add channel button text
- Move the remove channel button down
- Other minor spacing tweaks

CORL-645
This commit is contained in:
Nick Funk
2019-12-09 16:29:57 -05:00
committed by Kim Gardner
parent f60fac651b
commit ec93789cff
6 changed files with 255 additions and 207 deletions
+1 -1
View File
@@ -24980,7 +24980,7 @@
"dependencies": {
"async": {
"version": "1.5.2",
"resolved": "https://registry.npmjs.org/async/-/async-1.5.2.tgz",
"resolved": "http://registry.npmjs.org/async/-/async-1.5.2.tgz",
"integrity": "sha1-7GphrlZIDAw8skHJVhjiCJL5Zyo=",
"dev": true
}
@@ -1,28 +1,41 @@
.header {
flex: 1;
}
.description {
padding-bottom: var(--spacing-1);
padding-bottom: var(--v2-spacing-1);
}
.channelName {
margin-right: var(--spacing-2);
.enabledCheckbox {
margin-right: var(--v2-spacing-1);
}
.trigger {
padding-left: var(--spacing-1);
padding-left: var(--v2-spacing-1);
padding-bottom: var(--v2-spacing-2);
}
.button {
padding-top: var(--v2-spacing-1);
padding-bottom: var(--v2-spacing-1);
}
.removeButton {
padding-top: 0px;
padding-bottom: 0px;
margin-bottom: 2px;
float: right;
margin-bottom: var(--v2-spacing-1);
}
.buttonIcon {
padding-right: var(--spacing-1);
padding-right: var(--v2-spacing-1);
}
.content {
padding: var(--v2-spacing-3) var(--v2-spacing-2) 0 var(--v2-spacing-2);
}
.textField {
padding-bottom: var(--v2-spacing-4);
}
.notificationsLabel {
padding-bottom: var(--v2-spacing-1);
}
.notificationToggles {
padding-bottom: var(--v2-spacing-3);
}
@@ -1,21 +1,22 @@
import cn from "classnames";
import { Localized } from "fluent-react/compat";
import React, { FunctionComponent, useCallback } from "react";
import { Field } from "react-final-form";
import { parseBool } from "coral-framework/lib/form";
import { ExternalLink } from "coral-framework/lib/i18n/components";
import { InputDescription, InputLabel } from "coral-ui/components";
import {
Box,
Button,
ButtonIcon,
CheckBox,
Flex,
FormField,
FormFieldDescription,
Label,
TextField,
} from "coral-ui/components/v2";
import Header from "../../Header";
import ConfigBoxWithToggleField from "../Auth/ConfigBoxWithToggleField";
import Subheader from "../../Subheader";
import styles from "./SlackChannel.css";
@@ -37,193 +38,221 @@ const SlackChannel: FunctionComponent<Props> = ({
}, [index, onRemoveClicked]);
return (
<ConfigBoxWithToggleField
title={
<Flex
className={styles.header}
justifyContent="space-between"
alignItems="center"
>
<div>
<Field name={`${channel}.name`}>
{({ input }) => (
<Header className={styles.channelName}>{input.value}</Header>
)}
</Field>
</div>
<div>
<Button
size="small"
variant="filled"
color="alert"
onClick={onRemove}
className={styles.removeButton}
>
<ButtonIcon size="md" className={styles.buttonIcon}>
delete_forever
</ButtonIcon>
<Localized id="configure-slack-channel-remove">Remove</Localized>
</Button>
</div>
</Flex>
}
name={`${channel}.enabled`}
disabled={disabled}
>
{(disabledInside: boolean) => (
<>
<FormField>
<Field name={`${channel}.name`}>
{({ input, meta }) => (
<>
<Localized id="configure-slack-channel-name-label">
<InputLabel container="legend">Name</InputLabel>
<>
<Field name={`${channel}.name`}>
{({ input }) => (
<Subheader>
<Flex justifyContent="space-between">
<div>
{input.value ? (
input.value
) : (
<Localized id="configure-slack-channel-defaultName">
New channel
</Localized>
<Localized id="configure-slack-channel-name-description">
<InputDescription className={styles.description}>
This is only for your information, to easily identify each
Slack connection. Slack does not tell us the name of the
channel/s you're connecting to Coral.
</InputDescription>
</Localized>
<TextField
id={`configure-slack-channel-name-${input.name}`}
disabled={disabled || disabledInside}
autoComplete="off"
autoCorrect="off"
autoCapitalize="off"
spellCheck={false}
fullWidth
{...input}
/>
</>
)}
</Field>
</FormField>
<FormField>
<Field name={`${channel}.hookURL`}>
{({ input, meta }) => (
<>
<Localized id="configure-slack-channel-hookURL-label">
<InputLabel container="legend">Webhook URL</InputLabel>
</Localized>
<Localized
id="configure-slack-channel-hookURL-description"
externalLink={
<ExternalLink href="https://docs.coralproject.net/coral/v5/integrating/slack/#i-need-to-find-the-webhook-url-again-where-is-it" />
}
>
<InputDescription className={styles.description}>
Slack provides a channel-specific URL to activate webhook
connections. To find the URL for one of your Slack
channels, follow the instructions here.
</InputDescription>
</Localized>
<TextField
id={`configure-slack-channel-hookURL-${input.name}`}
disabled={disabled || disabledInside}
autoComplete="off"
autoCorrect="off"
autoCapitalize="off"
spellCheck={false}
fullWidth
{...input}
/>
</>
)}
</Field>
</FormField>
<FormField>
<Localized id="configure-slack-channel-triggers-label">
<InputLabel container="legend">
Receive notifications in this Slack channel for
</InputLabel>
</Localized>
<Field
name={`${channel}.triggers.allComments`}
subscription={{ value: true }}
>
{({ input: { value } }) => (
<>
<Field
name={`${channel}.triggers.allComments`}
type="checkbox"
parse={parseBool}
>
{({ input }) => (
)}
</div>
<div>
<Field
name={`${channel}.enabled`}
type="checkbox"
parse={parseBool}
>
{({ input: enabledInput }) => (
<Localized id="configure-auth-configBoxEnabled">
<CheckBox
id={`configure-slack-channel-triggers-allComments-${input.name}`}
disabled={disabled || disabledInside}
className={styles.trigger}
{...input}
id={`${channel}.enabled`}
disabled={disabled}
className={styles.enabledCheckbox}
{...enabledInput}
>
<Localized id="configure-slack-channel-triggers-allComments">
All Comments
</Localized>
Enabled
</CheckBox>
)}
</Field>
<Field
name={`${channel}.triggers.reportedComments`}
type="checkbox"
parse={parseBool}
>
{({ input }) => (
<CheckBox
id={`configure-slack-channel-triggers-reportedComments-${input.name}`}
disabled={disabled || value || disabledInside}
className={styles.trigger}
{...input}
>
<Localized id="configure-slack-channel-triggers-reportedComments">
Reported Comments
</Localized>
</CheckBox>
)}
</Field>
<Field
name={`${channel}.triggers.pendingComments`}
type="checkbox"
parse={parseBool}
>
{({ input }) => (
<CheckBox
id={`configure-slack-channel-triggers-pendingComments-${input.name}`}
disabled={disabled || value || disabledInside}
className={styles.trigger}
{...input}
>
<Localized id="configure-slack-channel-triggers-pendingComments">
Pending Comments
</Localized>
</CheckBox>
)}
</Field>
<Field
name={`${channel}.triggers.featuredComments`}
type="checkbox"
parse={parseBool}
>
{({ input }) => (
<CheckBox
id={`configure-slack-channel-triggers-featuredComments-${input.name}`}
disabled={disabled || value || disabledInside}
className={styles.trigger}
{...input}
>
<Localized id="configure-slack-channel-triggers-featuredComments">
Featured Comments
</Localized>
</CheckBox>
)}
</Field>
</>
)}
</Field>
</FormField>
</>
)}
</ConfigBoxWithToggleField>
</Localized>
)}
</Field>
</div>
</Flex>
</Subheader>
)}
</Field>
<Field name={`${channel}.enabled`} subscription={{ value: true }}>
{({ input: { value: channelEnabled } }) => (
<Box className={styles.content}>
<FormField>
<Field name={`${channel}.name`}>
{({ input }) => (
<>
<Localized id="configure-slack-channel-name-label">
<Label>Name</Label>
</Localized>
<Localized id="configure-slack-channel-name-description">
<FormFieldDescription className={styles.description}>
This is only for your information, to easily identify
each Slack connection. Slack does not tell us the name
of the channel/s you're connecting to Coral.
</FormFieldDescription>
</Localized>
<TextField
id={`configure-slack-channel-name-${input.name}`}
disabled={disabled || !channelEnabled}
autoComplete="off"
autoCorrect="off"
autoCapitalize="off"
spellCheck={false}
fullWidth
className={styles.textField}
{...input}
/>
</>
)}
</Field>
</FormField>
<FormField>
<Field name={`${channel}.hookURL`}>
{({ input }) => (
<>
<Localized id="configure-slack-channel-hookURL-label">
<Label>Webhook URL</Label>
</Localized>
<Localized
id="configure-slack-channel-hookURL-description"
externalLink={
<ExternalLink href="https://docs.coralproject.net/coral/v5/integrating/slack/#i-need-to-find-the-webhook-url-again-where-is-it" />
}
>
<FormFieldDescription className={styles.description}>
Slack provides a channel-specific URL to activate
webhook connections. To find the URL for one of your
Slack channels, follow the instructions here.
</FormFieldDescription>
</Localized>
<TextField
id={`configure-slack-channel-hookURL-${input.name}`}
disabled={disabled || !channelEnabled}
autoComplete="off"
autoCorrect="off"
autoCapitalize="off"
spellCheck={false}
fullWidth
className={styles.textField}
{...input}
/>
</>
)}
</Field>
</FormField>
<FormField>
<div className={styles.notificationsLabel}>
<Localized id="configure-slack-channel-triggers-label">
<Label>Receive notifications in this Slack channel for</Label>
</Localized>
</div>
<Field
name={`${channel}.triggers.allComments`}
subscription={{ value: true }}
>
{({ input: { value: allCommentsValue } }) => (
<div className={styles.notificationToggles}>
<Field
name={`${channel}.triggers.allComments`}
type="checkbox"
parse={parseBool}
>
{({ input }) => (
<CheckBox
id={`configure-slack-channel-triggers-allComments-${input.name}`}
disabled={disabled || !channelEnabled}
className={styles.trigger}
{...input}
>
<Localized id="configure-slack-channel-triggers-allComments">
All Comments
</Localized>
</CheckBox>
)}
</Field>
<Field
name={`${channel}.triggers.reportedComments`}
type="checkbox"
parse={parseBool}
>
{({ input }) => (
<CheckBox
id={`configure-slack-channel-triggers-reportedComments-${input.name}`}
disabled={
disabled || allCommentsValue || !channelEnabled
}
className={styles.trigger}
{...input}
>
<Localized id="configure-slack-channel-triggers-reportedComments">
Reported Comments
</Localized>
</CheckBox>
)}
</Field>
<Field
name={`${channel}.triggers.pendingComments`}
type="checkbox"
parse={parseBool}
>
{({ input }) => (
<CheckBox
id={`configure-slack-channel-triggers-pendingComments-${input.name}`}
disabled={
disabled || allCommentsValue || !channelEnabled
}
className={styles.trigger}
{...input}
>
<Localized id="configure-slack-channel-triggers-pendingComments">
Pending Comments
</Localized>
</CheckBox>
)}
</Field>
<Field
name={`${channel}.triggers.featuredComments`}
type="checkbox"
parse={parseBool}
>
{({ input }) => (
<CheckBox
id={`configure-slack-channel-triggers-featuredComments-${input.name}`}
disabled={
disabled || allCommentsValue || !channelEnabled
}
className={styles.trigger}
{...input}
>
<Localized id="configure-slack-channel-triggers-featuredComments">
Featured Comments
</Localized>
</CheckBox>
)}
</Field>
</div>
)}
</Field>
</FormField>
<div>
<Button
size="medium"
variant="filled"
color="alert"
onClick={onRemove}
className={cn(styles.removeButton, styles.button)}
>
<Localized id="configure-slack-channel-remove">
Remove
</Localized>
</Button>
</div>
</Box>
)}
</Field>
</>
);
};
@@ -1,3 +1,8 @@
.icon {
padding-right: var(--spacing-2);
}
.button {
padding-top: var(--v2-spacing-1);
padding-bottom: var(--v2-spacing-1);
}
@@ -112,13 +112,13 @@ const SlackConfigContainer: FunctionComponent<Props> = ({ form, settings }) => {
<Button
size="medium"
variant="filled"
color="emphasis"
onClick={onAddChannel}
className={styles.button}
>
<ButtonIcon size="md" className={styles.icon}>
add
</ButtonIcon>
<Localized id="configure-slack-addChannel">Add</Localized>
<Localized id="configure-slack-addChannel">Add Channel</Localized>
</Button>
<FieldArray name="slack.channels">
{({ fields }) =>
+3 -2
View File
@@ -388,10 +388,11 @@ configure-slack-description =
Automatically send comments from Coral moderation queues to Slack
channels. You will need Slack admin access to set this up. For
steps on how to create a Slack App see our <externalLink>documentation</externalLink>.
configure-slack-addChannel = Add
configure-slack-addChannel = Add Channel
configure-slack-channel-defaultName = New channel
configure-slack-channel-enabled = Enabled
configure-slack-channel-remove = Remove
configure-slack-channel-remove = Remove Channel
configure-slack-channel-name-label = Name
configure-slack-channel-name-description =
This is only for your information, to easily identify