Skip to content

Commit

Permalink
Merge pull request #4360 from coralproject/develop
Browse files Browse the repository at this point in the history
8.5.2
  • Loading branch information
tessalt authored Oct 4, 2023
2 parents e5c72eb + 55e9344 commit d3fab0c
Show file tree
Hide file tree
Showing 60 changed files with 401 additions and 128 deletions.
4 changes: 2 additions & 2 deletions client/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion client/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@coralproject/talk",
"version": "8.5.1",
"version": "8.5.2",
"author": "The Coral Project",
"homepage": "https://coralproject.net/",
"sideEffects": [
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import { AdvancedConfigContainer_settings } from "coral-admin/__generated__/Adva
import AMPConfig from "./AMPConfig";
import CommentStreamLiveUpdatesContainer from "./CommentStreamLiveUpdatesContainer";
import CustomCSSConfig from "./CustomCSSConfig";
import EmbeddedCommentRepliesConfig from "./EmbeddedCommentRepliesConfig";
import EmbeddedCommentsConfig from "./EmbeddedCommentsConfig";
import ForReviewQueueConfig from "./ForReviewQueueConfig";
import StoryCreationConfig from "./StoryCreationConfig";

Expand All @@ -31,7 +31,7 @@ const AdvancedConfigContainer: React.FunctionComponent<Props> = ({
return (
<HorizontalGutter size="double" data-testid="configure-advancedContainer">
<CustomCSSConfig disabled={submitting} />
<EmbeddedCommentRepliesConfig disabled={submitting} />
<EmbeddedCommentsConfig disabled={submitting} />
<CommentStreamLiveUpdatesContainer
disabled={submitting}
settings={settings}
Expand All @@ -47,7 +47,7 @@ const enhanced = withFragmentContainer<Props>({
settings: graphql`
fragment AdvancedConfigContainer_settings on Settings {
...CustomCSSConfig_formValues @relay(mask: false)
...EmbeddedCommentRepliesConfig_formValues @relay(mask: false)
...EmbeddedCommentsConfig_formValues @relay(mask: false)
...CommentStreamLiveUpdates_formValues @relay(mask: false)
...StoryCreationConfig_formValues @relay(mask: false)
...CommentStreamLiveUpdatesContainer_settings
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
import { Localized } from "@fluent/react/compat";
import React, { FunctionComponent } from "react";
import { graphql } from "react-relay";

import { FormField, HelperText, Label } from "coral-ui/components/v2";

import ConfigBox from "../../ConfigBox";
import Header from "../../Header";
import OnOffField from "../../OnOffField";
import Subheader from "../../Subheader";
import AllowedOriginsTextarea from "../Sites/AllowedOriginsTextarea";

// eslint-disable-next-line no-unused-expressions
graphql`
fragment EmbeddedCommentsConfig_formValues on Settings {
embeddedComments {
allowReplies
oEmbedAllowedOrigins
}
}
`;

interface Props {
disabled: boolean;
}

const EmbeddedCommentsConfig: FunctionComponent<Props> = ({ disabled }) => (
<ConfigBox
data-testid="embedded-comments-config"
title={
<Localized id="configure-advanced-embeddedComments">
<Header htmlFor="configure-advanced-embeddedComments">
Embedded comments
</Header>
</Localized>
}
>
<FormField>
<Localized id="configure-advanced-embeddedCommentReplies-label">
<Label>Allow replies to embedded comments</Label>
</Localized>
<Localized id="configure-advanced-embeddedCommentReplies-explanation">
<HelperText>
When enabled, a reply button will appear with each embedded comment to
encourage additional discussion on that specific comment or story.
</HelperText>
</Localized>
<OnOffField name="embeddedComments.allowReplies" disabled={disabled} />
</FormField>
<Localized id="configure-advanced-embeddedComments-subheader">
<Subheader>For sites using oEmbed</Subheader>
</Localized>
<FormField>
<Localized id="configure-advanced-oembedAllowedOrigins-label">
<Label>oEmbed permitted domains</Label>
</Localized>
<Localized id="configure-advanced-oembedAllowedOrigins-description">
<HelperText>
Domains that are permitted to make calls to the oEmbed API (ex.
http://localhost:3000, https://staging.domain.com,
https://domain.com).
</HelperText>
</Localized>
<AllowedOriginsTextarea
name="embeddedComments.oEmbedAllowedOrigins"
disabled={disabled}
/>
</FormField>
</ConfigBox>
);

export default EmbeddedCommentsConfig;
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,18 @@ import ValidationMessage from "../../ValidationMessage";
import styles from "./AllowedOriginsTextarea.css";

interface Props {
name: string;
defaultValue?: ReadonlyArray<string>;
disabled?: boolean;
}

const AllowedOriginsTextarea: FunctionComponent<Props> = ({ defaultValue }) => (
const AllowedOriginsTextarea: FunctionComponent<Props> = ({
name,
defaultValue,
disabled = false,
}) => (
<Field
name="allowedOrigins"
name={name}
parse={parseStringList}
format={formatStringList}
validate={validateStrictURLList}
Expand All @@ -32,6 +38,7 @@ const AllowedOriginsTextarea: FunctionComponent<Props> = ({ defaultValue }) => (
autoCapitalize="off"
spellCheck={false}
fullwidth
disabled={disabled}
/>
<ValidationMessage meta={meta} />
</>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ const CreateSiteForm: FunctionComponent<Props> = ({ onCreate }) => {
</HelperText>
</Localized>
</FormFieldHeader>
<AllowedOriginsTextarea />
<AllowedOriginsTextarea name="allowedOrigins" />
</FormField>
{submitError && (
<CallOut fullWidth color="error">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,10 @@ const EditSiteForm: FunctionComponent<Props> = ({
</HelperText>
</Localized>
</FormFieldHeader>
<AllowedOriginsTextarea defaultValue={site.allowedOrigins} />
<AllowedOriginsTextarea
defaultValue={site.allowedOrigins}
name="allowedOrigins"
/>
</FormField>
<FormField>
<FormFieldHeader>
Expand Down
44 changes: 42 additions & 2 deletions client/src/core/client/admin/test/configure/advanced.spec.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ it("renders configure advanced", async () => {
const { configureContainer } = await createTestRenderer();
expect(within(configureContainer).getByLabelText("Custom CSS")).toBeDefined();
expect(
within(configureContainer).getByText("Embedded comment replies")
within(configureContainer).getByText("Embedded comments")
).toBeDefined();
expect(
within(configureContainer).getByText("Comment stream live updates")
Expand Down Expand Up @@ -223,7 +223,7 @@ it("change embedded comments allow replies", async () => {
});

const embeddedCommentReplies = within(advancedContainer).getByTestId(
"embedded-comment-replies-config"
"embedded-comments-config"
);

const offField = within(embeddedCommentReplies).getByText("Off");
Expand All @@ -241,3 +241,43 @@ it("change embedded comments allow replies", async () => {
expect(resolvers.Mutation!.updateSettings!.called).toBe(true);
});
});

it("change oembed permitted domains", async () => {
const resolvers = createResolversStub<GQLResolver>({
Mutation: {
updateSettings: ({ variables }) => {
expectAndFail(
variables.settings.embeddedComments?.oEmbedAllowedOrigins
).toEqual(["http://localhost:8080"]);
return {
settings: pureMerge(settings, variables.settings),
};
},
},
});
const { advancedContainer, saveChangesButton } = await createTestRenderer({
resolvers,
});

const oembedAllowedOriginsConfig = within(advancedContainer).getByTestId(
"embedded-comments-config"
);

const allowedOriginsTextArea = within(oembedAllowedOriginsConfig).getByRole(
"textbox"
);

userEvent.type(allowedOriginsTextArea, "http://");

userEvent.click(saveChangesButton);

expect(within(advancedContainer).getByText("Invalid URL"));

userEvent.type(allowedOriginsTextArea, "localhost:8080");

userEvent.click(saveChangesButton);

await waitFor(() => {
expect(resolvers.Mutation!.updateSettings!.called).toBe(true);
});
});
1 change: 1 addition & 0 deletions client/src/core/client/admin/test/fixtures.ts
Original file line number Diff line number Diff line change
Expand Up @@ -224,6 +224,7 @@ export const settings = createFixture<GQLSettings>({
emailDomainModeration: [],
embeddedComments: {
allowReplies: true,
oEmbedAllowedOrigins: [],
},
flairBadges: {
flairBadgesEnabled: false,
Expand Down
2 changes: 2 additions & 0 deletions client/src/core/client/stream/common/scrollToBeginning.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ function scrollToBeginning(
} else {
window.scrollTo({ top: getElementWindowTopOffset(window, tab) });
}
// set keyboard focus to Comments button for accessibility
tab.getElementsByTagName("button")[0].focus();
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ const CommentToggle: FunctionComponent<Props> = (props) => {
onClick={props.toggleCollapsed}
className={cn(styles.root, CLASSES.comment.collapseToggle.$root)}
aria-label={"Expand comment thread"}
aria-expanded="false"
>
<Flex alignItems="baseline" spacing={1}>
<SvgIcon
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@ const IndentedComment: FunctionComponent<IndentedCommentProps> = ({
styles.toggleButton,
CLASSES.comment.collapseToggle.$root
)}
aria-expanded="true"
>
<SvgIcon
className={cn(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,7 @@ const MediaSectionContainer: FunctionComponent<Props> = ({
onClick={onToggleExpand}
size="small"
className={styles.button}
aria-expanded="false"
>
<ButtonSvgIcon Icon={AddIcon} size="xxs" className={styles.icon} />
{media.__typename === "TwitterMedia" && (
Expand Down Expand Up @@ -129,6 +130,7 @@ const MediaSectionContainer: FunctionComponent<Props> = ({
size="small"
iconLeft
className={styles.button}
aria-expanded="true"
>
<ButtonSvgIcon
Icon={SubtractIcon}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,7 @@ const CopyCommentEmbedCodeContainer: FunctionComponent<Props> = ({

const permalinkUrl = getURLWithCommentID(story.url, comment.id);

const embedCode = `<div class="coral-comment-embed coral-comment-embed-simple" style="background-color: #f4f7f7; padding: 8px; position: relative;" data-commentID=${
const embedCode = `<div class="coral-comment-embed coral-comment-embed-simple" style="background-color: #f4f7f7; padding: 8px; position: relative; text-align: left;" data-commentID=${
comment.id
} data-reactionLabel="${
settings.reaction.label
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,13 +57,44 @@ const CommentsLinks: FunctionComponent<Props> = ({
showGoToProfile,
}) => {
const { renderWindow, customScrollContainer } = useCoralContext();

// Find first keyboard focusable element for accessibility
const getFirstKeyboardFocusableElement = useCallback(() => {
const container = customScrollContainer ?? renderWindow.document;
let firstFocusableElement: Element | null = null;
let counter = 0;
const focusableElements = container.querySelectorAll(
'a[href], button, input, textarea, select, details, [tabindex]:not([tabindex="-1"])'
);
while (
firstFocusableElement === null &&
counter < focusableElements.length
) {
if (
!focusableElements[counter].hasAttribute("disabled") &&
!focusableElements[counter].getAttribute("aria-hidden") &&
!focusableElements[counter].getAttribute("hidden")
) {
firstFocusableElement = focusableElements[counter];
}
counter++;
}
return firstFocusableElement;
}, [renderWindow, customScrollContainer]);

const root = useShadowRootOrDocument();
const onGoToArticleTop = useCallback(() => {
if (customScrollContainer) {
customScrollContainer.scrollTo({ top: 0 });
}
renderWindow.scrollTo({ top: 0 });
}, [renderWindow, customScrollContainer]);
// programmatically apply focus to first keyboard focusable element
// after scroll for accessibility
const firstKeyboardFocusableElement = getFirstKeyboardFocusableElement();
if (firstKeyboardFocusableElement instanceof HTMLElement) {
firstKeyboardFocusableElement.focus();
}
}, [renderWindow, customScrollContainer, getFirstKeyboardFocusableElement]);
const onGoToCommentsTop = useCallback(() => {
scrollToBeginning(root, renderWindow, customScrollContainer);
}, [root, renderWindow, customScrollContainer]);
Expand Down
Loading

0 comments on commit d3fab0c

Please sign in to comment.