5.4.0 Release Bug Fixes (#2789)

* fix: addresses CORL-848

Fixed copy for new commenters feature.

* fix: address CORL-847

Revert the line hight changes on select fields for now.

* fix: addressed CORL-851

Changed copy on CSS field.

* fix: addressed CORL-840

Changed deletion window to 24 hours.
Refactored durations to use TIME enum.
This commit is contained in:
Wyatt Johnson
2020-01-14 16:39:21 +00:00
committed by GitHub
parent a88644d98e
commit 9b8ab6de5f
36 changed files with 1061 additions and 1063 deletions
@@ -2,7 +2,8 @@ import { Localized } from "@fluent/react/compat";
import cn from "classnames";
import React, { FunctionComponent } from "react";
import { reduceSeconds, UNIT } from "coral-common/helpers/i18n";
import { reduceSeconds } from "coral-common/helpers/i18n";
import TIME from "coral-common/time";
import {
Flex,
HorizontalGutter,
@@ -25,7 +26,7 @@ const RecentHistory: FunctionComponent<Props> = ({
rejectionRate,
submitted,
}) => {
const { scaled, unit } = reduceSeconds(timeFrame, [UNIT.DAYS]);
const { scaled, unit } = reduceSeconds(timeFrame, [TIME.DAY]);
return (
<HorizontalGutter spacing={2}>
@@ -30,13 +30,10 @@ const CustomCSSConfig: FunctionComponent<Props> = ({ disabled }) => (
}
>
<FormField>
<Localized
id="configure-advanced-customCSS-explanation"
strong={<strong />}
>
<Localized id="configure-advanced-customCSS-override" strong={<strong />}>
<FormFieldDescription>
URL of a CSS stylesheet that will override default Embed Stream
styles. Can be internal or external.
styles.
</FormFieldDescription>
</Localized>
<Field name="customCSSURL" parse={parseEmptyAsNull} format={formatEmpty}>
@@ -80,9 +80,9 @@ const ClosingCommentStreamsConfig: FunctionComponent<Props> = ({
<DurationField
{...input}
units={[
DURATION_UNIT.HOURS,
DURATION_UNIT.DAYS,
DURATION_UNIT.WEEKS,
DURATION_UNIT.HOUR,
DURATION_UNIT.DAY,
DURATION_UNIT.WEEK,
]}
disabled={disabled}
color={colorFromMeta(meta)}
@@ -67,9 +67,9 @@ const CommentEditingConfig: FunctionComponent<Props> = ({ disabled }) => (
<DurationField
{...input}
units={[
DURATION_UNIT.SECONDS,
DURATION_UNIT.MINUTES,
DURATION_UNIT.HOURS,
DURATION_UNIT.SECOND,
DURATION_UNIT.MINUTE,
DURATION_UNIT.HOUR,
]}
color={colorFromMeta(meta)}
disabled={disabled}
@@ -60,7 +60,7 @@ const NewCommentersConfig: FunctionComponent<Props> = ({ disabled }) => {
</FormField>
<FormField>
<Localized id="configure-moderation-newCommenters-approvedCommentsThreshold">
<Label>Number of first comments sent for approval</Label>
<Label>Number of comments that must be approved</Label>
</Localized>
<Field
name="newCommenters.approvedCommentsThreshold"
@@ -77,7 +77,7 @@ const RecentCommentHistoryConfig: FunctionComponent<Props> = ({ disabled }) => {
{({ input, meta }) => (
<>
<DurationField
units={[DURATION_UNIT.DAYS]}
units={[DURATION_UNIT.DAY]}
disabled={disabled}
color={hasError(meta) ? "error" : "regular"}
{...input}
@@ -234,7 +234,7 @@ each of your sites stories.
<p
className="FormFieldDescription-root"
>
URL of a CSS stylesheet that will override default Embed Stream styles. Can be internal or external.
URL of a CSS stylesheet that will override default Embed Stream styles.
</p>
<div
className="Box-root HorizontalGutter-root HorizontalGutter-spacing-2"
@@ -367,7 +367,7 @@ for moderator approval before publication.
<label
className="Label-root"
>
Number of first comments sent for approval
Number of comments that must be approved
</label>
<div
className="TextField-root"
+5 -5
View File
@@ -1,7 +1,8 @@
import {
DEFAULT_SESSION_LENGTH,
DEFAULT_SESSION_DURATION,
TOXICITY_THRESHOLD_DEFAULT,
} from "coral-common/constants";
import TIME from "coral-common/time";
import { pureMerge } from "coral-common/utils";
import {
GQLComment,
@@ -77,8 +78,7 @@ export const settings = createFixture<GQLSettings>({
},
recentCommentHistory: {
enabled: false,
// 7 days in seconds.
timeFrame: 604800,
timeFrame: 7 * TIME.DAY,
// Rejection rate defaulting to 30%, once exceeded, comments will be
// pre-moderated.
triggerRejectionRate: 0.3,
@@ -94,7 +94,7 @@ export const settings = createFixture<GQLSettings>({
},
},
auth: {
sessionDuration: DEFAULT_SESSION_LENGTH,
sessionDuration: DEFAULT_SESSION_DURATION,
integrations: {
local: {
enabled: true,
@@ -175,7 +175,7 @@ export const settingsWithEmptyAuth = createFixture<GQLSettings>(
{
id: "settings",
auth: {
sessionDuration: DEFAULT_SESSION_LENGTH,
sessionDuration: DEFAULT_SESSION_DURATION,
integrations: {
local: {
enabled: true,
@@ -24,7 +24,7 @@ it("renders correctly with specified units", () => {
value: "",
disabled: false,
onChange: noop,
units: [DURATION_UNIT.SECONDS, DURATION_UNIT.HOURS],
units: [DURATION_UNIT.SECOND, DURATION_UNIT.HOUR],
};
const renderer = createRenderer();
renderer.render(<DurationField {...props} />);
@@ -37,7 +37,7 @@ it("use best matching unit", () => {
value: "3600",
disabled: false,
onChange: noop,
units: [DURATION_UNIT.SECONDS, DURATION_UNIT.MINUTES, DURATION_UNIT.HOURS],
units: [DURATION_UNIT.SECOND, DURATION_UNIT.MINUTE, DURATION_UNIT.HOUR],
};
const renderer = createRenderer();
renderer.render(<DurationField {...props} />);
@@ -50,7 +50,7 @@ it("use initial unit if 0", () => {
value: "0",
disabled: false,
onChange: noop,
units: [DURATION_UNIT.SECONDS, DURATION_UNIT.MINUTES, DURATION_UNIT.HOURS],
units: [DURATION_UNIT.SECOND, DURATION_UNIT.MINUTE, DURATION_UNIT.HOUR],
};
const renderer = createRenderer();
renderer.render(<DurationField {...props} />);
@@ -63,7 +63,7 @@ it("accepts invalid input", () => {
value: "this is so invalid",
disabled: false,
onChange: noop,
units: [DURATION_UNIT.SECONDS, DURATION_UNIT.MINUTES, DURATION_UNIT.HOURS],
units: [DURATION_UNIT.SECOND, DURATION_UNIT.MINUTE, DURATION_UNIT.HOUR],
};
const renderer = createRenderer();
renderer.render(<DurationField {...props} />);
@@ -8,7 +8,7 @@ import React, {
useState,
} from "react";
import { UNIT } from "coral-common/helpers/i18n";
import TIME from "coral-common/time";
import {
Flex,
Option,
@@ -23,14 +23,14 @@ import styles from "./DurationField.css";
* DURATION_UNIT are units that can be used in the
* DurationField components.
*/
export const DURATION_UNIT = UNIT;
export const DURATION_UNIT = TIME;
const DURATION_UNIT_MAP = {
[DURATION_UNIT.SECONDS]: "second",
[DURATION_UNIT.MINUTES]: "minute",
[DURATION_UNIT.HOURS]: "hour",
[DURATION_UNIT.DAYS]: "day",
[DURATION_UNIT.WEEKS]: "week",
[DURATION_UNIT.SECOND]: "second",
[DURATION_UNIT.MINUTE]: "minute",
[DURATION_UNIT.HOUR]: "hour",
[DURATION_UNIT.DAY]: "day",
[DURATION_UNIT.WEEK]: "week",
};
interface Props {
@@ -39,18 +39,18 @@ interface Props {
disabled: boolean;
onChange: (v: string) => void;
/** Specifiy units to include */
units?: ReadonlyArray<UNIT>;
units?: ReadonlyArray<TIME>;
}
function convertToSeconds(value: string, unit?: UNIT) {
function convertToSeconds(value: string, unit?: TIME) {
const parsed = parseInt(value, 10);
return (isNaN(parsed) || !unit ? value : parsed * unit).toString();
}
function convertFromSeconds(
value: string,
units: ReadonlyArray<UNIT>,
unit?: UNIT
units: ReadonlyArray<TIME>,
unit?: TIME
) {
const parsed = parseInt(value, 10);
@@ -82,7 +82,7 @@ function convertFromSeconds(
*/
const DurationField: FunctionComponent<Props> = ({
value,
units = [UNIT.HOURS, UNIT.DAYS, UNIT.WEEKS],
units = [TIME.HOUR, TIME.DAY, TIME.WEEK],
onChange,
disabled,
name,
@@ -7,6 +7,8 @@ import {
urlMiddleware,
} from "react-relay-network-modern/es";
import TIME from "coral-common/time";
import clientIDMiddleware from "./clientIDMiddleware";
import { ManagedSubscriptionClient } from "./createManagedSubscriptionClient";
import customErrorMiddleware from "./customErrorMiddleware";
@@ -45,7 +47,7 @@ export default function createNetwork(
customErrorMiddleware,
cacheMiddleware({
size: 100, // max 100 requests
ttl: 900000, // 15 minutes
ttl: 15 * TIME.MINUTE,
clearOnMutation: true,
}),
urlMiddleware({
@@ -2,7 +2,7 @@ import { Localized } from "@fluent/react/compat";
import React, { FunctionComponent, useCallback } from "react";
import { graphql } from "react-relay";
import { SCHEDULED_DELETION_TIMESPAN_DAYS } from "coral-common/constants";
import { SCHEDULED_DELETION_WINDOW_DURATION } from "coral-common/constants";
import { useCoralContext } from "coral-framework/lib/bootstrap";
import { useMutation, withFragmentContainer } from "coral-framework/lib/relay";
import CLASSES from "coral-stream/classes";
@@ -24,8 +24,8 @@ interface Props {
viewer: StreamDeletionRequestCalloutContainer_viewer;
}
const formatter = (locales: string[], date: Date) => {
return Intl.DateTimeFormat(locales, {
const formatter = (locales: string[], date: Date) =>
Intl.DateTimeFormat(locales, {
year: "numeric",
month: "numeric",
day: "numeric",
@@ -33,11 +33,9 @@ const formatter = (locales: string[], date: Date) => {
minute: "numeric",
second: "numeric",
}).format(date);
};
const subtractDays = (date: Date, days: number) => {
const millisecondsInADay = 86400000;
return new Date(date.getTime() - days * millisecondsInADay);
const subtractSeconds = (date: Date, seconds: number) => {
return new Date(date.getTime() - seconds * 1000);
};
const StreamDeletionRequestCalloutContainer: FunctionComponent<Props> = ({
@@ -57,9 +55,9 @@ const StreamDeletionRequestCalloutContainer: FunctionComponent<Props> = ({
const requestDate = viewer.scheduledDeletionDate
? formatter(
locales,
subtractDays(
subtractSeconds(
new Date(viewer.scheduledDeletionDate),
SCHEDULED_DELETION_TIMESPAN_DAYS
SCHEDULED_DELETION_WINDOW_DURATION
)
)
: null;
@@ -9,8 +9,9 @@ import React, {
} from "react";
import { Field, Form } from "react-final-form";
import { ALLOWED_USERNAME_CHANGE_FREQUENCY } from "coral-common/constants";
import { reduceSeconds, UNIT } from "coral-common/helpers/i18n";
import { ALLOWED_USERNAME_CHANGE_TIMEFRAME_DURATION } from "coral-common/constants";
import { reduceSeconds } from "coral-common/helpers/i18n";
import TIME from "coral-common/time";
import getAuthenticationIntegrations from "coral-framework/helpers/getAuthenticationIntegrations";
import { useCoralContext } from "coral-framework/lib/bootstrap";
import { InvalidRequestError } from "coral-framework/lib/errors";
@@ -50,9 +51,10 @@ import UpdateUsernameMutation from "./UpdateUsernameMutation";
import styles from "./ChangeUsernameContainer.css";
const FREQUENCYSCALED = reduceSeconds(ALLOWED_USERNAME_CHANGE_FREQUENCY, [
UNIT.DAYS,
]);
const FREQUENCYSCALED = reduceSeconds(
ALLOWED_USERNAME_CHANGE_TIMEFRAME_DURATION,
[TIME.DAY]
);
interface Props {
viewer: ViewerData;
@@ -107,7 +109,8 @@ const ChangeUsernameContainer: FunctionComponent<Props> = ({
if (username && username.history.length > 1) {
const lastUsernameEditAllowed = new Date();
lastUsernameEditAllowed.setSeconds(
lastUsernameEditAllowed.getSeconds() - ALLOWED_USERNAME_CHANGE_FREQUENCY
lastUsernameEditAllowed.getSeconds() -
ALLOWED_USERNAME_CHANGE_TIMEFRAME_DURATION
);
const lastUsernameEdit =
username.history[username.history.length - 1].createdAt;
@@ -122,7 +125,9 @@ const ChangeUsernameContainer: FunctionComponent<Props> = ({
const date = new Date(
username.history[username.history.length - 1].createdAt
);
date.setSeconds(date.getSeconds() + ALLOWED_USERNAME_CHANGE_FREQUENCY);
date.setSeconds(
date.getSeconds() + ALLOWED_USERNAME_CHANGE_TIMEFRAME_DURATION
);
return date;
}
return null;
@@ -1,8 +1,7 @@
import { DateTime } from "luxon";
import { graphql } from "react-relay";
import { Environment } from "relay-runtime";
import { SCHEDULED_DELETION_TIMESPAN_DAYS } from "coral-common/constants";
import { SCHEDULED_DELETION_WINDOW_DURATION } from "coral-common/constants";
import { getViewer } from "coral-framework/helpers";
import {
commitMutationPromiseNormalized,
@@ -49,9 +48,9 @@ const RequestAccountDeletionMutation = createMutation(
},
optimisticUpdater: store => {
const viewer = getViewer(environment)!;
const deletionDate = DateTime.fromJSDate(new Date())
.plus({ days: SCHEDULED_DELETION_TIMESPAN_DAYS })
.toISO();
const deletionDate = new Date(
Date.now() + SCHEDULED_DELETION_WINDOW_DURATION * 1000
).toISOString();
const viewerProxy = store.get(viewer.id);
if (viewerProxy !== null) {
viewerProxy.setValue(deletionDate, "scheduledDeletionDate");
@@ -3,8 +3,9 @@ import cn from "classnames";
import React, { FunctionComponent, useCallback } from "react";
import { graphql } from "react-relay";
import { DOWNLOAD_LIMIT_TIMEFRAME } from "coral-common/constants";
import { reduceSeconds, UNIT } from "coral-common/helpers/i18n";
import { DOWNLOAD_LIMIT_TIMEFRAME_DURATION } from "coral-common/constants";
import { reduceSeconds } from "coral-common/helpers/i18n";
import TIME from "coral-common/time";
import { useCoralContext } from "coral-framework/lib/bootstrap";
import { useMutation, withFragmentContainer } from "coral-framework/lib/relay";
import CLASSES from "coral-stream/classes";
@@ -34,8 +35,8 @@ const DownloadCommentsContainer: FunctionComponent<Props> = ({ viewer }) => {
? Math.ceil((Date.now() - lastDownloadedAt.getTime()) / 1000)
: 0;
const canDownload =
!lastDownloadedAt || sinceLastDownload >= DOWNLOAD_LIMIT_TIMEFRAME;
const tilCanDownload = DOWNLOAD_LIMIT_TIMEFRAME - sinceLastDownload;
!lastDownloadedAt || sinceLastDownload >= DOWNLOAD_LIMIT_TIMEFRAME_DURATION;
const tilCanDownload = DOWNLOAD_LIMIT_TIMEFRAME_DURATION - sinceLastDownload;
const formatter = new Intl.DateTimeFormat(locales, {
day: "2-digit",
month: "2-digit",
@@ -46,9 +47,9 @@ const DownloadCommentsContainer: FunctionComponent<Props> = ({ viewer }) => {
timeZoneName: "short",
});
const { scaled, unit } = reduceSeconds(tilCanDownload, [
UNIT.DAYS,
UNIT.HOURS,
UNIT.MINUTES,
TIME.DAY,
TIME.HOUR,
TIME.MINUTE,
]);
return (
@@ -24,7 +24,7 @@ it("renders correctly with specified units", () => {
value: "",
disabled: false,
onChange: noop,
units: [DURATION_UNIT.SECONDS, DURATION_UNIT.HOURS],
units: [DURATION_UNIT.SECOND, DURATION_UNIT.HOUR],
};
const renderer = createRenderer();
renderer.render(<DurationField {...props} />);
@@ -37,7 +37,7 @@ it("use best matching unit", () => {
value: "3600",
disabled: false,
onChange: noop,
units: [DURATION_UNIT.SECONDS, DURATION_UNIT.MINUTES, DURATION_UNIT.HOURS],
units: [DURATION_UNIT.SECOND, DURATION_UNIT.MINUTE, DURATION_UNIT.HOUR],
};
const renderer = createRenderer();
renderer.render(<DurationField {...props} />);
@@ -50,7 +50,7 @@ it("use initial unit if 0", () => {
value: "0",
disabled: false,
onChange: noop,
units: [DURATION_UNIT.SECONDS, DURATION_UNIT.MINUTES, DURATION_UNIT.HOURS],
units: [DURATION_UNIT.SECOND, DURATION_UNIT.MINUTE, DURATION_UNIT.HOUR],
};
const renderer = createRenderer();
renderer.render(<DurationField {...props} />);
@@ -63,7 +63,7 @@ it("accepts invalid input", () => {
value: "this is so invalid",
disabled: false,
onChange: noop,
units: [DURATION_UNIT.SECONDS, DURATION_UNIT.MINUTES, DURATION_UNIT.HOURS],
units: [DURATION_UNIT.SECOND, DURATION_UNIT.MINUTE, DURATION_UNIT.HOUR],
};
const renderer = createRenderer();
renderer.render(<DurationField {...props} />);
@@ -8,7 +8,7 @@ import React, {
useState,
} from "react";
import { UNIT } from "coral-common/helpers/i18n";
import TIME from "coral-common/time";
import { Flex } from "coral-ui/components";
import { Option, SelectField } from "../SelectField";
@@ -20,32 +20,32 @@ import styles from "./DurationField.css";
* DURATION_UNIT are units that can be used in the
* DurationField components.
*/
export const DURATION_UNIT = UNIT;
export const DURATION_UNIT = TIME;
const DURATION_UNIT_MAP = {
[DURATION_UNIT.SECONDS]: "second",
[DURATION_UNIT.MINUTES]: "minute",
[DURATION_UNIT.HOURS]: "hour",
[DURATION_UNIT.DAYS]: "day",
[DURATION_UNIT.WEEKS]: "week",
[DURATION_UNIT.SECOND]: "second",
[DURATION_UNIT.MINUTE]: "minute",
[DURATION_UNIT.HOUR]: "hour",
[DURATION_UNIT.DAY]: "day",
[DURATION_UNIT.WEEK]: "week",
};
interface Props extends Pick<TextFieldProps, "color" | "name" | "disabled"> {
value: string;
onChange: (v: string) => void;
/** Specifiy units to include */
units?: ReadonlyArray<UNIT>;
units?: ReadonlyArray<TIME>;
}
function convertToSeconds(value: string, unit?: UNIT) {
function convertToSeconds(value: string, unit?: TIME) {
const parsed = parseInt(value, 10);
return (isNaN(parsed) || !unit ? value : parsed * unit).toString();
}
function convertFromSeconds(
value: string,
units: ReadonlyArray<UNIT>,
unit?: UNIT
units: ReadonlyArray<TIME>,
unit?: TIME
) {
const parsed = parseInt(value, 10);
@@ -77,7 +77,7 @@ function convertFromSeconds(
*/
const DurationField: FunctionComponent<Props> = ({
value,
units = [UNIT.HOURS, UNIT.DAYS, UNIT.WEEKS],
units = [TIME.HOUR, TIME.DAY, TIME.WEEK],
onChange,
disabled,
name,
@@ -25,7 +25,7 @@
font-family: var(--v2-font-family-primary);
font-weight: var(--v2-font-weight-primary-regular);
font-size: var(--v2-font-size-3);
line-height: var(--v2-line-height-tall);
line-height: var(--v2-line-height-reset);
appearance: none;
outline: none;
color: var(--v2-palette-input-value);
-1
View File
@@ -277,7 +277,6 @@ const variables2 = {
bodyShort: 1.3,
reset: 1,
title: 1.15,
tall: 1.3,
},
fontSize: {
1: "0.75rem",