diff --git a/package-lock.json b/package-lock.json index 7a8c2da87..5973c0a88 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10712,11 +10712,8 @@ "resolved": "https://registry.npmjs.org/fluent-intl-polyfill/-/fluent-intl-polyfill-0.1.0.tgz", "integrity": "sha1-ETOUSrJHeINHOZVZaIPg05z4hc8=", "dev": true, - "dependencies": { - "intl-pluralrules": { - "version": "github:projectfluent/IntlPluralRules#94cb0fa1c23ad943bc5aafef43cea132fa51d68b", - "from": "github:projectfluent/IntlPluralRules#94cb0fa1c23ad943bc5aafef43cea132fa51d68b" - } + "requires": { + "intl-pluralrules": "github:projectfluent/IntlPluralRules#94cb0fa1c23ad943bc5aafef43cea132fa51d68b" } }, "fluent-langneg": { @@ -13384,6 +13381,11 @@ "integrity": "sha1-ftGxQQxqDg94z5XTuEQMY/eLhhQ=", "dev": true }, + "intl-pluralrules": { + "version": "github:projectfluent/IntlPluralRules#94cb0fa1c23ad943bc5aafef43cea132fa51d68b", + "from": "github:projectfluent/IntlPluralRules#module", + "dev": true + }, "invariant": { "version": "2.2.4", "resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz", diff --git a/package.json b/package.json index 8d3e07e9c..dbf012e03 100644 --- a/package.json +++ b/package.json @@ -233,6 +233,7 @@ "postcss-prepend-imports": "^1.0.1", "postcss-preset-env": "^5.2.1", "prettier": "^1.13.7", + "prop-types": "^15.6.2", "pstree.remy": "^1.1.0", "pym.js": "^1.3.2", "query-string": "^6.1.0", diff --git a/scripts/test.js b/scripts/test.js index 07d349c42..7a922b2b1 100644 --- a/scripts/test.js +++ b/scripts/test.js @@ -1,6 +1,8 @@ #!/usr/bin/env node "use strict"; +// Set timezone to UTC for stable tests. +process.env.TZ = "UTC"; // Allow importing typescript files. require("ts-node/register"); diff --git a/src/core/client/admin/fetches/DiscoverOIDCConfigurationQuery.ts b/src/core/client/admin/fetches/DiscoverOIDCConfigurationQuery.ts new file mode 100644 index 000000000..9dbf89c61 --- /dev/null +++ b/src/core/client/admin/fetches/DiscoverOIDCConfigurationQuery.ts @@ -0,0 +1,39 @@ +import { graphql } from "react-relay"; +import { Environment } from "relay-runtime"; + +import { DiscoverOIDCConfigurationQuery as QueryTypes } from "talk-admin/__generated__/DiscoverOIDCConfigurationQuery.graphql"; +import { createFetchContainer, fetchQuery } from "talk-framework/lib/relay"; + +export type DiscoverOIDCConfigurationVariables = QueryTypes["variables"]; + +const query = graphql` + query DiscoverOIDCConfigurationQuery($issuer: String!) { + discoverOIDCConfiguration(issuer: $issuer) { + issuer + authorizationURL + tokenURL + jwksURI + } + } +`; + +function fetch( + environment: Environment, + variables: DiscoverOIDCConfigurationVariables +) { + return fetchQuery( + environment, + query, + variables, + { force: true } + ); +} + +export const withDiscoverOIDCConfigurationFetch = createFetchContainer( + "discoverOIDCConfiguration", + fetch +); + +export type DiscoverOIDCConfigurationFetch = ( + variables: DiscoverOIDCConfigurationVariables +) => Promise; diff --git a/src/core/client/admin/fetches/index.ts b/src/core/client/admin/fetches/index.ts new file mode 100644 index 000000000..f286876b6 --- /dev/null +++ b/src/core/client/admin/fetches/index.ts @@ -0,0 +1,4 @@ +export { + withDiscoverOIDCConfigurationFetch, + DiscoverOIDCConfigurationFetch, +} from "./DiscoverOIDCConfigurationQuery"; diff --git a/src/core/client/admin/mutations/CreateOIDCAuthIntegrationMutation.ts b/src/core/client/admin/mutations/CreateOIDCAuthIntegrationMutation.ts new file mode 100644 index 000000000..836cc1382 --- /dev/null +++ b/src/core/client/admin/mutations/CreateOIDCAuthIntegrationMutation.ts @@ -0,0 +1,71 @@ +import { graphql } from "react-relay"; +import { Environment } from "relay-runtime"; + +import { + commitMutationPromiseNormalized, + createMutationContainer, +} from "talk-framework/lib/relay"; +import { Omit } from "talk-framework/types"; + +import { CreateOIDCAuthIntegrationMutation as MutationTypes } from "talk-admin/__generated__/CreateOIDCAuthIntegrationMutation.graphql"; + +export type CreateOIDCAuthIntegrationInput = Omit< + MutationTypes["variables"]["input"], + "clientMutationId" +>; + +const mutation = graphql` + mutation CreateOIDCAuthIntegrationMutation( + $input: CreateOIDCAuthIntegrationInput! + ) { + createOIDCAuthIntegration(input: $input) { + settings { + auth { + ...OIDCConfigListContainer_authReadOnly + } + } + clientMutationId + } + } +`; + +let clientMutationId = 0; + +function commit( + environment: Environment, + input: CreateOIDCAuthIntegrationInput +) { + return commitMutationPromiseNormalized(environment, { + mutation, + variables: { + input: { + ...input, + clientMutationId: (clientMutationId++).toString(), + }, + }, + updater: store => { + const record = store + .getRootField("createOIDCAuthIntegration")! + .getLinkedRecord("settings")! + .getLinkedRecord("auth")! + .getLinkedRecord("integrations"); + if (record) { + store + .getRoot() + .getLinkedRecord("settings")! + .getLinkedRecord("auth")! + .getLinkedRecord("integrations")! + .copyFieldsFrom(record); + } + }, + }); +} + +export const withCreateOIDCAuthIntegrationMutation = createMutationContainer( + "createOIDCAuthIntegration", + commit +); + +export type CreateOIDCAuthIntegrationMutation = ( + input: CreateOIDCAuthIntegrationInput +) => Promise; diff --git a/src/core/client/admin/mutations/RegenerateSSOKeyMutation.ts b/src/core/client/admin/mutations/RegenerateSSOKeyMutation.ts new file mode 100644 index 000000000..01b551459 --- /dev/null +++ b/src/core/client/admin/mutations/RegenerateSSOKeyMutation.ts @@ -0,0 +1,66 @@ +import { graphql } from "react-relay"; +import { Environment } from "relay-runtime"; + +import { + commitMutationPromiseNormalized, + createMutationContainer, +} from "talk-framework/lib/relay"; + +import { RegenerateSSOKeyMutation as MutationTypes } from "talk-admin/__generated__/RegenerateSSOKeyMutation.graphql"; + +const mutation = graphql` + mutation RegenerateSSOKeyMutation($input: RegenerateSSOKeyInput!) { + regenerateSSOKey(input: $input) { + settings { + auth { + integrations { + sso { + key + keyGeneratedAt + } + } + } + } + clientMutationId + } + } +`; + +let clientMutationId = 0; + +function commit(environment: Environment) { + return commitMutationPromiseNormalized(environment, { + mutation, + variables: { + input: { + clientMutationId: (clientMutationId++).toString(), + }, + }, + updater: store => { + const record = store + .getRootField("regenerateSSOKey")! + .getLinkedRecord("settings")! + .getLinkedRecord("auth")! + .getLinkedRecord("integrations")! + .getLinkedRecord("sso"); + if (record) { + store + .getRoot() + .getLinkedRecord("settings")! + .getLinkedRecord("auth")! + .getLinkedRecord("integrations")! + .getLinkedRecord("sso")! + .copyFieldsFrom(record); + } + }, + }); +} + +export const withRegenerateSSOKeyMutation = createMutationContainer( + "regenerateSSOKey", + commit +); + +export type RegenerateSSOKeyMutation = () => Promise< + MutationTypes["response"]["regenerateSSOKey"] +>; diff --git a/src/core/client/admin/mutations/UpdateOIDCAuthIntegrationMutation.ts b/src/core/client/admin/mutations/UpdateOIDCAuthIntegrationMutation.ts new file mode 100644 index 000000000..c1d71cc2d --- /dev/null +++ b/src/core/client/admin/mutations/UpdateOIDCAuthIntegrationMutation.ts @@ -0,0 +1,56 @@ +import { graphql } from "react-relay"; +import { Environment } from "relay-runtime"; + +import { + commitMutationPromiseNormalized, + createMutationContainer, +} from "talk-framework/lib/relay"; +import { Omit } from "talk-framework/types"; + +import { UpdateOIDCAuthIntegrationMutation as MutationTypes } from "talk-admin/__generated__/UpdateOIDCAuthIntegrationMutation.graphql"; + +export type UpdateOIDCAuthIntegrationInput = Omit< + MutationTypes["variables"]["input"], + "clientMutationId" +>; + +const mutation = graphql` + mutation UpdateOIDCAuthIntegrationMutation( + $input: UpdateOIDCAuthIntegrationInput! + ) { + updateOIDCAuthIntegration(input: $input) { + settings { + auth { + ...OIDCConfigListContainer_authReadOnly + } + } + clientMutationId + } + } +`; + +let clientMutationId = 0; + +function commit( + environment: Environment, + input: UpdateOIDCAuthIntegrationInput +) { + return commitMutationPromiseNormalized(environment, { + mutation, + variables: { + input: { + ...input, + clientMutationId: (clientMutationId++).toString(), + }, + }, + }); +} + +export const withUpdateOIDCAuthIntegrationMutation = createMutationContainer( + "updateOIDCAuthIntegration", + commit +); + +export type UpdateOIDCAuthIntegrationMutation = ( + input: UpdateOIDCAuthIntegrationInput +) => Promise; diff --git a/src/core/client/admin/mutations/UpdateSettingsMutation.ts b/src/core/client/admin/mutations/UpdateSettingsMutation.ts new file mode 100644 index 000000000..6491ffffc --- /dev/null +++ b/src/core/client/admin/mutations/UpdateSettingsMutation.ts @@ -0,0 +1,70 @@ +import { graphql } from "react-relay"; +import { Environment } from "relay-runtime"; + +import { + commitMutationPromiseNormalized, + createMutationContainer, +} from "talk-framework/lib/relay"; +import { Omit } from "talk-framework/types"; + +import { UpdateSettingsMutation as MutationTypes } from "talk-admin/__generated__/UpdateSettingsMutation.graphql"; + +export type UpdateSettingsInput = Omit< + MutationTypes["variables"]["input"], + "clientMutationId" +>; + +const mutation = graphql` + mutation UpdateSettingsMutation($input: UpdateSettingsInput!) { + updateSettings(input: $input) { + settings { + auth { + ...FacebookConfigContainer_auth + ...FacebookConfigContainer_authReadOnly + ...GoogleConfigContainer_auth + ...GoogleConfigContainer_authReadOnly + ...SSOConfigContainer_auth + ...SSOConfigContainer_authReadOnly + ...OIDCConfigListContainer_auth + ...OIDCConfigListContainer_authReadOnly + ...DisplayNamesConfigContainer_auth + } + } + clientMutationId + } + } +`; + +let clientMutationId = 0; + +function commit(environment: Environment, input: UpdateSettingsInput) { + return commitMutationPromiseNormalized(environment, { + mutation, + variables: { + input: { + ...input, + clientMutationId: (clientMutationId++).toString(), + }, + }, + updater: store => { + const record = store + .getRootField("updateSettings")! + .getLinkedRecord("settings"); + if (record) { + store + .getRoot() + .getLinkedRecord("settings")! + .copyFieldsFrom(record); + } + }, + }); +} + +export const withUpdateSettingsMutation = createMutationContainer( + "updateSettings", + commit +); + +export type UpdateSettingsMutation = ( + input: UpdateSettingsInput +) => Promise; diff --git a/src/core/client/admin/mutations/index.ts b/src/core/client/admin/mutations/index.ts index 245732316..2836dec09 100644 --- a/src/core/client/admin/mutations/index.ts +++ b/src/core/client/admin/mutations/index.ts @@ -3,3 +3,20 @@ export { withSetRedirectPathMutation, SetRedirectPathMutation, } from "./SetRedirectPathMutation"; +export { + withUpdateSettingsMutation, + UpdateSettingsMutation, + UpdateSettingsInput, +} from "./UpdateSettingsMutation"; +export { + withRegenerateSSOKeyMutation, + RegenerateSSOKeyMutation, +} from "./RegenerateSSOKeyMutation"; +export { + withCreateOIDCAuthIntegrationMutation, + CreateOIDCAuthIntegrationMutation, +} from "./CreateOIDCAuthIntegrationMutation"; +export { + withUpdateOIDCAuthIntegrationMutation, + UpdateOIDCAuthIntegrationMutation, +} from "./UpdateOIDCAuthIntegrationMutation"; diff --git a/src/core/client/admin/routeConfig.tsx b/src/core/client/admin/routeConfig.tsx index c724f8e80..62de716a4 100644 --- a/src/core/client/admin/routeConfig.tsx +++ b/src/core/client/admin/routeConfig.tsx @@ -5,7 +5,9 @@ import App from "./components/App"; import RedirectAppContainer from "./containers/RedirectAppContainer"; import RedirectLoginContainer from "./containers/RedirectLoginContainer"; import Community from "./routes/community/components/Community"; -import Configure from "./routes/configure/components/Configure"; +import ConfigureMisc from "./routes/configure/components/Misc"; +import ConfigureContainer from "./routes/configure/containers/ConfigureContainer"; +import ConfigureAuthContainer from "./routes/configure/sections/auth/containers/AuthContainer"; import Login from "./routes/login/components/Login"; import Moderate from "./routes/moderate/components/Moderate"; import Stories from "./routes/stories/components/Stories"; @@ -18,7 +20,11 @@ export default makeRouteConfig( - + + + + + diff --git a/src/core/client/admin/routes/configure/components/ConfigBox.css b/src/core/client/admin/routes/configure/components/ConfigBox.css new file mode 100644 index 000000000..e975d330f --- /dev/null +++ b/src/core/client/admin/routes/configure/components/ConfigBox.css @@ -0,0 +1,20 @@ +.root { + border: 1px solid var(--palette-grey-lighter); +} + +.title { + padding: calc(0.5 * var(--spacing-unit)) calc(1.5 * var(--spacing-unit)); + + background-color: var(--palette-text-primary); + + color: var(--palette-text-light); + font-family: var(--font-family-sans-serif); + font-weight: var(--font-weight-medium); + font-size: calc(18rem / var(--rem-base)); + line-height: calc(20em / 18); + letter-spacing: calc(-0.1em / 18); +} + +.content { + padding: calc(2 * var(--spacing-unit)) calc(3 * var(--spacing-unit)); +} diff --git a/src/core/client/admin/routes/configure/components/ConfigBox.spec.tsx b/src/core/client/admin/routes/configure/components/ConfigBox.spec.tsx new file mode 100644 index 000000000..42502e05d --- /dev/null +++ b/src/core/client/admin/routes/configure/components/ConfigBox.spec.tsx @@ -0,0 +1,16 @@ +import { shallow } from "enzyme"; +import React from "react"; + +import { PropTypesOf } from "talk-framework/types"; + +import ConfigBox from "./ConfigBox"; + +it("renders correctly", () => { + const props: PropTypesOf = { + topRight: topRight, + title: title, + children: "child", + }; + const wrapper = shallow(); + expect(wrapper).toMatchSnapshot(); +}); diff --git a/src/core/client/admin/routes/configure/components/ConfigBox.tsx b/src/core/client/admin/routes/configure/components/ConfigBox.tsx new file mode 100644 index 000000000..8a6207cec --- /dev/null +++ b/src/core/client/admin/routes/configure/components/ConfigBox.tsx @@ -0,0 +1,29 @@ +import React, { StatelessComponent } from "react"; + +import { Flex } from "talk-ui/components"; + +import styles from "./ConfigBox.css"; + +interface Props { + id?: string; + topRight?: React.ReactElement; + title?: React.ReactNode; + children: React.ReactNode; +} + +const ConfigBox: StatelessComponent = ({ + id, + title, + topRight, + children, +}) => ( +
+ +
{title}
+
{topRight}
+
+
{children}
+
+); + +export default ConfigBox; diff --git a/src/core/client/admin/routes/configure/components/Configure.spec.tsx b/src/core/client/admin/routes/configure/components/Configure.spec.tsx index e0e20a5a4..6f1b81fc0 100644 --- a/src/core/client/admin/routes/configure/components/Configure.spec.tsx +++ b/src/core/client/admin/routes/configure/components/Configure.spec.tsx @@ -1,9 +1,16 @@ import { shallow } from "enzyme"; +import { noop } from "lodash"; import React from "react"; +import { PropTypesOf } from "talk-framework/types"; + import Configure from "./Configure"; it("renders correctly", () => { - const wrapper = shallow(); + const props: PropTypesOf = { + onSave: noop, + onChange: noop, + }; + const wrapper = shallow(); expect(wrapper).toMatchSnapshot(); }); diff --git a/src/core/client/admin/routes/configure/components/Configure.tsx b/src/core/client/admin/routes/configure/components/Configure.tsx index 264c0a614..310ba13ec 100644 --- a/src/core/client/admin/routes/configure/components/Configure.tsx +++ b/src/core/client/admin/routes/configure/components/Configure.tsx @@ -1,10 +1,62 @@ +import { FormApi, FormState } from "final-form"; +import { Localized } from "fluent-react/compat"; import React, { StatelessComponent } from "react"; -import { HorizontalGutter, Typography } from "talk-ui/components"; +import { Form, FormSpy } from "react-final-form"; -const Configure: StatelessComponent = ({ children }) => ( - - Configure - +import { Button, HorizontalGutter } from "talk-ui/components"; +import Layout from "./Layout"; +import Main from "./Main"; +import { Link, Navigation } from "./Navigation"; +import SideBar from "./SideBar"; + +interface Props { + onSave: (settings: any, form: FormApi) => void; + onChange: (formState: FormState) => void; +} + +const Configure: StatelessComponent = ({ + onSave, + onChange, + children, +}) => ( +
+
+ {({ handleSubmit, submitting, pristine, form }) => ( + + + + + + + + Auth + + Misc + + + + + + +
+ {React.cloneElement(React.Children.only(children), { + form, + submitting, + })} +
+
+ + )} + +
); export default Configure; diff --git a/src/core/client/admin/routes/configure/components/Header.css b/src/core/client/admin/routes/configure/components/Header.css new file mode 100644 index 000000000..18daf9bde --- /dev/null +++ b/src/core/client/admin/routes/configure/components/Header.css @@ -0,0 +1,5 @@ +.root { + padding-bottom: calc(0.5 * var(--spacing-unit)); + border-bottom: 1px solid var(--palette-text-primary); + margin-bottom: calc(1.5 * var(--spacing-unit)); +} diff --git a/src/core/client/admin/routes/configure/components/Header.spec.tsx b/src/core/client/admin/routes/configure/components/Header.spec.tsx new file mode 100644 index 000000000..2099fad47 --- /dev/null +++ b/src/core/client/admin/routes/configure/components/Header.spec.tsx @@ -0,0 +1,14 @@ +import { shallow } from "enzyme"; +import React from "react"; + +import { PropTypesOf } from "talk-framework/types"; + +import Header from "./Header"; + +it("renders correctly", () => { + const props: PropTypesOf = { + children: "child", + }; + const wrapper = shallow(
); + expect(wrapper).toMatchSnapshot(); +}); diff --git a/src/core/client/admin/routes/configure/components/Header.tsx b/src/core/client/admin/routes/configure/components/Header.tsx new file mode 100644 index 000000000..01642289d --- /dev/null +++ b/src/core/client/admin/routes/configure/components/Header.tsx @@ -0,0 +1,12 @@ +import React, { StatelessComponent } from "react"; +import { Typography } from "talk-ui/components"; + +import styles from "./Header.css"; + +const Header: StatelessComponent = ({ children }) => ( + + {children} + +); + +export default Header; diff --git a/src/core/client/admin/routes/configure/components/HorizontalRule.css b/src/core/client/admin/routes/configure/components/HorizontalRule.css new file mode 100644 index 000000000..f412a976b --- /dev/null +++ b/src/core/client/admin/routes/configure/components/HorizontalRule.css @@ -0,0 +1,5 @@ +.root { + border: 0; + border-bottom: 1px solid var(--palette-divider); + padding-top: 1px; +} diff --git a/src/core/client/admin/routes/configure/components/HorizontalRule.d.ts b/src/core/client/admin/routes/configure/components/HorizontalRule.d.ts new file mode 100644 index 000000000..f99662ba2 --- /dev/null +++ b/src/core/client/admin/routes/configure/components/HorizontalRule.d.ts @@ -0,0 +1 @@ +export const root: string; diff --git a/src/core/client/admin/routes/configure/components/HorizontalRule.spec.tsx b/src/core/client/admin/routes/configure/components/HorizontalRule.spec.tsx new file mode 100644 index 000000000..606b08ed2 --- /dev/null +++ b/src/core/client/admin/routes/configure/components/HorizontalRule.spec.tsx @@ -0,0 +1,9 @@ +import { shallow } from "enzyme"; +import React from "react"; + +import HorizontalRule from "./HorizontalRule"; + +it("renders correctly", () => { + const wrapper = shallow(); + expect(wrapper).toMatchSnapshot(); +}); diff --git a/src/core/client/admin/routes/configure/components/HorizontalRule.tsx b/src/core/client/admin/routes/configure/components/HorizontalRule.tsx new file mode 100644 index 000000000..0f07a0314 --- /dev/null +++ b/src/core/client/admin/routes/configure/components/HorizontalRule.tsx @@ -0,0 +1,9 @@ +import React, { StatelessComponent } from "react"; + +import styles from "./HorizontalRule.css"; + +const HorizontalRule: StatelessComponent = ({ children }) => ( +
+); + +export default HorizontalRule; diff --git a/src/core/client/admin/routes/configure/components/Layout.css b/src/core/client/admin/routes/configure/components/Layout.css new file mode 100644 index 000000000..60dc8a113 --- /dev/null +++ b/src/core/client/admin/routes/configure/components/Layout.css @@ -0,0 +1,4 @@ +.root { + padding: calc(3 * var(--spacing-unit)) calc(5 * var(--spacing-unit)) + calc(5 * var(--spacing-unit)) calc(5 * var(--spacing-unit)); +} diff --git a/src/core/client/admin/routes/configure/components/Layout.spec.tsx b/src/core/client/admin/routes/configure/components/Layout.spec.tsx new file mode 100644 index 000000000..b7ff95c53 --- /dev/null +++ b/src/core/client/admin/routes/configure/components/Layout.spec.tsx @@ -0,0 +1,14 @@ +import { shallow } from "enzyme"; +import React from "react"; + +import { PropTypesOf } from "talk-framework/types"; + +import Layout from "./Layout"; + +it("renders correctly", () => { + const props: PropTypesOf = { + children: "child", + }; + const wrapper = shallow(); + expect(wrapper).toMatchSnapshot(); +}); diff --git a/src/core/client/admin/routes/configure/components/Layout.tsx b/src/core/client/admin/routes/configure/components/Layout.tsx new file mode 100644 index 000000000..f644c00e6 --- /dev/null +++ b/src/core/client/admin/routes/configure/components/Layout.tsx @@ -0,0 +1,10 @@ +import React, { StatelessComponent } from "react"; +import { Flex } from "talk-ui/components"; + +import styles from "./Layout.css"; + +const Layout: StatelessComponent = ({ children }) => ( + {children} +); + +export default Layout; diff --git a/src/core/client/admin/routes/configure/components/Main.css b/src/core/client/admin/routes/configure/components/Main.css new file mode 100644 index 000000000..85fb0e12e --- /dev/null +++ b/src/core/client/admin/routes/configure/components/Main.css @@ -0,0 +1,4 @@ +.root { + width: 100%; + max-width: calc(67 * var(--spacing-unit)); +} diff --git a/src/core/client/admin/routes/configure/components/Main.spec.tsx b/src/core/client/admin/routes/configure/components/Main.spec.tsx new file mode 100644 index 000000000..590945d6e --- /dev/null +++ b/src/core/client/admin/routes/configure/components/Main.spec.tsx @@ -0,0 +1,14 @@ +import { shallow } from "enzyme"; +import React from "react"; + +import { PropTypesOf } from "talk-framework/types"; + +import Main from "./Main"; + +it("renders correctly", () => { + const props: PropTypesOf = { + children: "child", + }; + const wrapper = shallow(
); + expect(wrapper).toMatchSnapshot(); +}); diff --git a/src/core/client/admin/routes/configure/components/Main.tsx b/src/core/client/admin/routes/configure/components/Main.tsx new file mode 100644 index 000000000..6b8035a8b --- /dev/null +++ b/src/core/client/admin/routes/configure/components/Main.tsx @@ -0,0 +1,9 @@ +import React, { StatelessComponent } from "react"; + +import styles from "./Main.css"; + +const Main: StatelessComponent = ({ children }) => ( +
{children}
+); + +export default Main; diff --git a/src/core/client/admin/routes/configure/components/Misc.spec.tsx b/src/core/client/admin/routes/configure/components/Misc.spec.tsx new file mode 100644 index 000000000..67ca2c8e6 --- /dev/null +++ b/src/core/client/admin/routes/configure/components/Misc.spec.tsx @@ -0,0 +1,14 @@ +import { shallow } from "enzyme"; +import React from "react"; + +import { PropTypesOf } from "talk-framework/types"; + +import Misc from "./Misc"; + +it("renders correctly", () => { + const props: PropTypesOf = { + children: "child", + }; + const wrapper = shallow(); + expect(wrapper).toMatchSnapshot(); +}); diff --git a/src/core/client/admin/routes/configure/components/Misc.tsx b/src/core/client/admin/routes/configure/components/Misc.tsx new file mode 100644 index 000000000..69cf155a5 --- /dev/null +++ b/src/core/client/admin/routes/configure/components/Misc.tsx @@ -0,0 +1,14 @@ +import React, { StatelessComponent } from "react"; + +import { Typography } from "talk-ui/components"; + +import Header from "./Header"; + +const Misc: StatelessComponent = ({ children }) => ( +
+
Misc Integrations
+ Other stuff +
+); + +export default Misc; diff --git a/src/core/client/admin/routes/configure/components/Navigation/Link.css b/src/core/client/admin/routes/configure/components/Navigation/Link.css new file mode 100644 index 000000000..617d9e924 --- /dev/null +++ b/src/core/client/admin/routes/configure/components/Navigation/Link.css @@ -0,0 +1,26 @@ +.link { + display: inline-block; + text-decoration: none; + text-transform: uppercase; + padding: calc(0.5 * var(--spacing-unit)) var(--spacing-unit) + calc(0.5 * var(--spacing-unit)) calc(var(--spacing-unit) + 2px); + margin-left: 2px; + border-left: 1px solid var(--palette-grey-lighter); + + color: var(--palette-text-primary); + font-family: var(--font-family-sans-serif); + font-weight: var(--font-weight-bold); + font-size: calc(18rem / var(--rem-base)); + line-height: calc(20em / 18); + letter-spacing: calc(-0.1em / 18); + + &:hover { + cursor: pointer; + } +} + +.linkActive { + margin-left: 0px; + border-left: calc(0.5 * var(--spacing-unit)) solid var(--palette-brand); + padding-left: var(--spacing-unit); +} diff --git a/src/core/client/admin/routes/configure/components/Navigation/Link.spec.tsx b/src/core/client/admin/routes/configure/components/Navigation/Link.spec.tsx new file mode 100644 index 000000000..5caaa4b20 --- /dev/null +++ b/src/core/client/admin/routes/configure/components/Navigation/Link.spec.tsx @@ -0,0 +1,16 @@ +import { shallow } from "enzyme"; +import React from "react"; + +import { PropTypesOf } from "talk-framework/types"; + +import Link from "./Link"; + +it("renders correctly", () => { + const props: PropTypesOf = { + className: "customClassName", + to: "/admin", + children: "child", + }; + const wrapper = shallow(); + expect(wrapper).toMatchSnapshot(); +}); diff --git a/src/core/client/admin/routes/configure/components/Navigation/Link.tsx b/src/core/client/admin/routes/configure/components/Navigation/Link.tsx new file mode 100644 index 000000000..3972908de --- /dev/null +++ b/src/core/client/admin/routes/configure/components/Navigation/Link.tsx @@ -0,0 +1,24 @@ +import { Link as FoundLink, LocationDescriptor } from "found"; +import React, { StatelessComponent } from "react"; + +import styles from "./Link.css"; + +interface Props { + className?: string; + children: React.ReactNode; + to: string | LocationDescriptor; +} + +const Link: StatelessComponent = props => ( +
  • + + {props.children} + +
  • +); + +export default Link; diff --git a/src/core/client/admin/routes/configure/components/Navigation/Navigation.css b/src/core/client/admin/routes/configure/components/Navigation/Navigation.css new file mode 100644 index 000000000..b70978427 --- /dev/null +++ b/src/core/client/admin/routes/configure/components/Navigation/Navigation.css @@ -0,0 +1,7 @@ +.root { +} + +.ul { + list-style: none; + padding: 0; +} diff --git a/src/core/client/admin/routes/configure/components/Navigation/Navigation.spec.tsx b/src/core/client/admin/routes/configure/components/Navigation/Navigation.spec.tsx new file mode 100644 index 000000000..118b20786 --- /dev/null +++ b/src/core/client/admin/routes/configure/components/Navigation/Navigation.spec.tsx @@ -0,0 +1,14 @@ +import { shallow } from "enzyme"; +import React from "react"; + +import { PropTypesOf } from "talk-framework/types"; + +import Navigation from "./Navigation"; + +it("renders correctly", () => { + const props: PropTypesOf = { + children: "child", + }; + const wrapper = shallow(); + expect(wrapper).toMatchSnapshot(); +}); diff --git a/src/core/client/admin/routes/configure/components/Navigation/Navigation.tsx b/src/core/client/admin/routes/configure/components/Navigation/Navigation.tsx new file mode 100644 index 000000000..44f0a97f5 --- /dev/null +++ b/src/core/client/admin/routes/configure/components/Navigation/Navigation.tsx @@ -0,0 +1,11 @@ +import React, { StatelessComponent } from "react"; + +import styles from "./Navigation.css"; + +const Navigation: StatelessComponent = ({ children }) => ( + +); + +export default Navigation; diff --git a/src/core/client/admin/routes/configure/components/Navigation/__snapshots__/Link.spec.tsx.snap b/src/core/client/admin/routes/configure/components/Navigation/__snapshots__/Link.spec.tsx.snap new file mode 100644 index 000000000..435b55960 --- /dev/null +++ b/src/core/client/admin/routes/configure/components/Navigation/__snapshots__/Link.spec.tsx.snap @@ -0,0 +1,15 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`renders correctly 1`] = ` +
  • + + child + +
  • +`; diff --git a/src/core/client/admin/routes/configure/components/Navigation/__snapshots__/Navigation.spec.tsx.snap b/src/core/client/admin/routes/configure/components/Navigation/__snapshots__/Navigation.spec.tsx.snap new file mode 100644 index 000000000..1040caebb --- /dev/null +++ b/src/core/client/admin/routes/configure/components/Navigation/__snapshots__/Navigation.spec.tsx.snap @@ -0,0 +1,13 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`renders correctly 1`] = ` + +`; diff --git a/src/core/client/admin/routes/configure/components/Navigation/index.ts b/src/core/client/admin/routes/configure/components/Navigation/index.ts new file mode 100644 index 000000000..dd3df0eb6 --- /dev/null +++ b/src/core/client/admin/routes/configure/components/Navigation/index.ts @@ -0,0 +1,2 @@ +export { default as Navigation } from "./Navigation"; +export { default as Link } from "./Link"; diff --git a/src/core/client/admin/routes/configure/components/SideBar.css b/src/core/client/admin/routes/configure/components/SideBar.css new file mode 100644 index 000000000..56773400b --- /dev/null +++ b/src/core/client/admin/routes/configure/components/SideBar.css @@ -0,0 +1,8 @@ +.root { + width: calc(25 * var(--spacing-unit)); + padding-top: calc(0.5 * var(--spacing-unit)); + padding-right: calc(3 * var(--spacing-unit)); + position: sticky; + top: 0; + align-self: flex-start; +} diff --git a/src/core/client/admin/routes/configure/components/SideBar.spec.tsx b/src/core/client/admin/routes/configure/components/SideBar.spec.tsx new file mode 100644 index 000000000..5ed32270d --- /dev/null +++ b/src/core/client/admin/routes/configure/components/SideBar.spec.tsx @@ -0,0 +1,14 @@ +import { shallow } from "enzyme"; +import React from "react"; + +import { PropTypesOf } from "talk-framework/types"; + +import SideBar from "./SideBar"; + +it("renders correctly", () => { + const props: PropTypesOf = { + children: "child", + }; + const wrapper = shallow(); + expect(wrapper).toMatchSnapshot(); +}); diff --git a/src/core/client/admin/routes/configure/components/SideBar.tsx b/src/core/client/admin/routes/configure/components/SideBar.tsx new file mode 100644 index 000000000..8a37b2e1c --- /dev/null +++ b/src/core/client/admin/routes/configure/components/SideBar.tsx @@ -0,0 +1,9 @@ +import React, { StatelessComponent } from "react"; + +import styles from "./SideBar.css"; + +const SideBar: StatelessComponent = ({ children }) => ( +
    {children}
    +); + +export default SideBar; diff --git a/src/core/client/admin/routes/configure/components/__snapshots__/ConfigBox.spec.tsx.snap b/src/core/client/admin/routes/configure/components/__snapshots__/ConfigBox.spec.tsx.snap new file mode 100644 index 000000000..bfab5d597 --- /dev/null +++ b/src/core/client/admin/routes/configure/components/__snapshots__/ConfigBox.spec.tsx.snap @@ -0,0 +1,28 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`renders correctly 1`] = ` +
    + +
    + + title + +
    +
    + + topRight + +
    +
    +
    + child +
    +
    +`; diff --git a/src/core/client/admin/routes/configure/components/__snapshots__/Configure.spec.tsx.snap b/src/core/client/admin/routes/configure/components/__snapshots__/Configure.spec.tsx.snap index eaf351718..5495b1145 100644 --- a/src/core/client/admin/routes/configure/components/__snapshots__/Configure.spec.tsx.snap +++ b/src/core/client/admin/routes/configure/components/__snapshots__/Configure.spec.tsx.snap @@ -1,11 +1,13 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP exports[`renders correctly 1`] = ` - - + - Configure - - + + + `; diff --git a/src/core/client/admin/routes/configure/components/__snapshots__/Header.spec.tsx.snap b/src/core/client/admin/routes/configure/components/__snapshots__/Header.spec.tsx.snap new file mode 100644 index 000000000..c4b8ab3ff --- /dev/null +++ b/src/core/client/admin/routes/configure/components/__snapshots__/Header.spec.tsx.snap @@ -0,0 +1,10 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`renders correctly 1`] = ` + + child + +`; diff --git a/src/core/client/admin/routes/configure/components/__snapshots__/HorizontalRule.spec.tsx.snap b/src/core/client/admin/routes/configure/components/__snapshots__/HorizontalRule.spec.tsx.snap new file mode 100644 index 000000000..f72e5ddab --- /dev/null +++ b/src/core/client/admin/routes/configure/components/__snapshots__/HorizontalRule.spec.tsx.snap @@ -0,0 +1,7 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`renders correctly 1`] = ` +
    +`; diff --git a/src/core/client/admin/routes/configure/components/__snapshots__/Layout.spec.tsx.snap b/src/core/client/admin/routes/configure/components/__snapshots__/Layout.spec.tsx.snap new file mode 100644 index 000000000..75a06c012 --- /dev/null +++ b/src/core/client/admin/routes/configure/components/__snapshots__/Layout.spec.tsx.snap @@ -0,0 +1,9 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`renders correctly 1`] = ` + + child + +`; diff --git a/src/core/client/admin/routes/configure/components/__snapshots__/Main.spec.tsx.snap b/src/core/client/admin/routes/configure/components/__snapshots__/Main.spec.tsx.snap new file mode 100644 index 000000000..f572e543d --- /dev/null +++ b/src/core/client/admin/routes/configure/components/__snapshots__/Main.spec.tsx.snap @@ -0,0 +1,9 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`renders correctly 1`] = ` +
    + child +
    +`; diff --git a/src/core/client/admin/routes/configure/components/__snapshots__/Misc.spec.tsx.snap b/src/core/client/admin/routes/configure/components/__snapshots__/Misc.spec.tsx.snap new file mode 100644 index 000000000..0ed7b1c04 --- /dev/null +++ b/src/core/client/admin/routes/configure/components/__snapshots__/Misc.spec.tsx.snap @@ -0,0 +1,12 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`renders correctly 1`] = ` +
    +
    + Misc Integrations +
    + + Other stuff + +
    +`; diff --git a/src/core/client/admin/routes/configure/components/__snapshots__/SideBar.spec.tsx.snap b/src/core/client/admin/routes/configure/components/__snapshots__/SideBar.spec.tsx.snap new file mode 100644 index 000000000..44d9e8bd1 --- /dev/null +++ b/src/core/client/admin/routes/configure/components/__snapshots__/SideBar.spec.tsx.snap @@ -0,0 +1,9 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`renders correctly 1`] = ` +
    + child +
    +`; diff --git a/src/core/client/admin/routes/configure/containers/ConfigureContainer.tsx b/src/core/client/admin/routes/configure/containers/ConfigureContainer.tsx new file mode 100644 index 000000000..c5b2365be --- /dev/null +++ b/src/core/client/admin/routes/configure/containers/ConfigureContainer.tsx @@ -0,0 +1,104 @@ +import { FormApi, FormState } from "final-form"; +import { Router } from "found"; +import React from "react"; + +import { + UpdateSettingsInput, + UpdateSettingsMutation, + withUpdateSettingsMutation, +} from "talk-admin/mutations"; +import { TalkContext, withContext } from "talk-framework/lib/bootstrap"; +import { BadUserInputError } from "talk-framework/lib/errors"; +import { getMessage } from "talk-framework/lib/i18n"; + +import Configure from "../components/Configure"; +import { + AddSubmitHook, + SubmitHook, + SubmitHookContextProvider, +} from "../submitHook"; + +interface Props { + localeBundles: TalkContext["localeBundles"]; + router: Router; + updateSettings: UpdateSettingsMutation; + children: React.ReactNode; +} + +class ConfigureContainer extends React.Component { + private dirty = false; + private removeTransitionHook: () => void; + private submitHooks: SubmitHook[] = []; + + constructor(props: Props) { + super(props); + + this.dirty = false; + const warningMessage = getMessage( + props.localeBundles, + "configure-unsavedInputWarning", + "You have unsaved input. Are you sure you want to leave this page?" + ); + + this.removeTransitionHook = props.router.addTransitionHook( + () => (this.dirty ? warningMessage : true) + ); + } + + public componentWillUnmount() { + this.removeTransitionHook(); + } + + private handleSave = async ( + data: UpdateSettingsInput["settings"], + form: FormApi + ) => { + try { + // Call submit hooks, that can manipulate what + // we send as the mutation. + let nextData = data; + for (const hook of this.submitHooks) { + const result = await hook(nextData); + if (result) { + nextData = result; + } + } + + await this.props.updateSettings({ settings: nextData }); + form.initialize(data); + } catch (error) { + if (error instanceof BadUserInputError) { + return error.invalidArgsLocalized; + } + // tslint:disable-next-line:no-console + console.error(error); + } + return undefined; + }; + + private handleChange = ({ dirty }: FormState) => { + this.dirty = dirty; + }; + + private addSubmitHook: AddSubmitHook = hook => { + this.submitHooks.push(hook); + return () => { + this.submitHooks = this.submitHooks.filter(h => h === hook); + }; + }; + + public render() { + return ( + + + {this.props.children} + + + ); + } +} + +const enhanced = withContext(({ localeBundles }) => ({ localeBundles }))( + withUpdateSettingsMutation(ConfigureContainer) +); +export default enhanced; diff --git a/src/core/client/admin/routes/configure/sections/auth/components/Auth.tsx b/src/core/client/admin/routes/configure/sections/auth/components/Auth.tsx new file mode 100644 index 000000000..070858a93 --- /dev/null +++ b/src/core/client/admin/routes/configure/sections/auth/components/Auth.tsx @@ -0,0 +1,31 @@ +import React, { StatelessComponent } from "react"; + +import { PropTypesOf } from "talk-framework/types"; +import { HorizontalGutter } from "talk-ui/components"; + +import DisplayNamesConfigContainer from "../containers/DisplayNamesConfigContainer"; +import AuthIntegrationsConfig from "./AuthIntegrationsConfig"; + +interface Props { + disabled?: boolean; + auth: PropTypesOf["auth"] & + PropTypesOf["auth"]; + onInitValues: (values: any) => void; +} + +const Auth: StatelessComponent = ({ disabled, auth, onInitValues }) => ( + + + + +); + +export default Auth; diff --git a/src/core/client/admin/routes/configure/sections/auth/components/AuthIntegrationsConfig.tsx b/src/core/client/admin/routes/configure/sections/auth/components/AuthIntegrationsConfig.tsx new file mode 100644 index 000000000..86f359f7e --- /dev/null +++ b/src/core/client/admin/routes/configure/sections/auth/components/AuthIntegrationsConfig.tsx @@ -0,0 +1,69 @@ +import { Localized } from "fluent-react/compat"; +import React, { StatelessComponent } from "react"; + +import { PropTypesOf } from "talk-framework/types"; +import { HorizontalGutter } from "talk-ui/components"; + +import Header from "../../../components/Header"; +import FacebookConfigContainer from "../containers/FacebookConfigContainer"; +import GoogleConfigContainer from "../containers/GoogleConfigContainer"; +import LocalAuthConfigContainer from "../containers/LocalAuthConfigContainer"; +import OIDCConfigListContainer from "../containers/OIDCConfigListContainer"; +import SSOConfigContainer from "../containers/SSOConfigContainer"; + +interface Props { + disabled?: boolean; + auth: PropTypesOf["auth"] & + PropTypesOf["authReadOnly"] & + PropTypesOf["auth"] & + PropTypesOf["authReadOnly"] & + PropTypesOf["auth"] & + PropTypesOf["authReadOnly"] & + PropTypesOf["auth"] & + PropTypesOf["auth"] & + PropTypesOf["authReadOnly"]; + onInitValues: (values: any) => void; +} + +const AuthIntegrationsConfig: StatelessComponent = ({ + disabled, + auth, + onInitValues, +}) => ( + + +
    Auth Integrations
    +
    + + + + + +
    +); + +export default AuthIntegrationsConfig; diff --git a/src/core/client/admin/routes/configure/sections/auth/components/ClientIDField.tsx b/src/core/client/admin/routes/configure/sections/auth/components/ClientIDField.tsx new file mode 100644 index 000000000..c8512b627 --- /dev/null +++ b/src/core/client/admin/routes/configure/sections/auth/components/ClientIDField.tsx @@ -0,0 +1,51 @@ +import { Localized } from "fluent-react/compat"; +import { identity } from "lodash"; +import React, { StatelessComponent } from "react"; +import { Field } from "react-final-form"; + +import { Validator } from "talk-framework/lib/validation"; +import { FormField, InputLabel, TextField } from "talk-ui/components"; + +import ValidationMessage from "./ValidationMessage"; + +interface Props { + validate?: Validator; + name: string; + disabled: boolean; +} + +const ClientSecretField: StatelessComponent = ({ + name, + disabled, + validate, +}) => ( + + + Client ID + + + {({ input, meta }) => ( + <> + + {meta.touched && + (meta.error || meta.submitError) && ( + + {meta.error || meta.submitError} + + )} + + )} + + +); + +export default ClientSecretField; diff --git a/src/core/client/admin/routes/configure/sections/auth/components/ClientSecretField.tsx b/src/core/client/admin/routes/configure/sections/auth/components/ClientSecretField.tsx new file mode 100644 index 000000000..fbd35f82e --- /dev/null +++ b/src/core/client/admin/routes/configure/sections/auth/components/ClientSecretField.tsx @@ -0,0 +1,56 @@ +import { Localized } from "fluent-react/compat"; +import { identity } from "lodash"; +import React, { StatelessComponent } from "react"; +import { Field } from "react-final-form"; + +import { Validator } from "talk-framework/lib/validation"; +import { FormField, InputLabel, TextField } from "talk-ui/components"; + +import ValidationMessage from "./ValidationMessage"; + +interface Props { + validate?: Validator; + name: string; + disabled: boolean; +} + +const ClientSecretField: StatelessComponent = ({ + name, + disabled, + validate, +}) => ( + + + Client Secret + + + {({ input, meta }) => ( + <> + + {meta.touched && + (meta.error || meta.submitError) && ( + + {meta.error || meta.submitError} + + )} + + )} + + +); + +export default ClientSecretField; diff --git a/src/core/client/admin/routes/configure/sections/auth/components/ConfigBoxWithToggleField.tsx b/src/core/client/admin/routes/configure/sections/auth/components/ConfigBoxWithToggleField.tsx new file mode 100644 index 000000000..fbc3c91c1 --- /dev/null +++ b/src/core/client/admin/routes/configure/sections/auth/components/ConfigBoxWithToggleField.tsx @@ -0,0 +1,54 @@ +import { Localized } from "fluent-react/compat"; +import React, { StatelessComponent } from "react"; +import { Field } from "react-final-form"; + +import { CheckBox, FormField } from "talk-ui/components"; + +import ConfigBox from "../../../components/ConfigBox"; + +interface Props { + id?: string; + name: string; + title: React.ReactNode; + disabled?: boolean; + children: (disabledInside: boolean) => React.ReactNode; +} + +const bool = (v: any) => !!v; + +const ConfigBoxWithToggleField: StatelessComponent = ({ + id, + name, + title, + disabled, + children, +}) => ( + + {({ input }) => ( + + + + Enabled + + + + } + > + {children(disabled || !input.value)} + + )} + +); + +export default ConfigBoxWithToggleField; diff --git a/src/core/client/admin/routes/configure/sections/auth/components/ConfigDescription.css b/src/core/client/admin/routes/configure/sections/auth/components/ConfigDescription.css new file mode 100644 index 000000000..c28dbafe5 --- /dev/null +++ b/src/core/client/admin/routes/configure/sections/auth/components/ConfigDescription.css @@ -0,0 +1,3 @@ +.description { + width: calc(30 * var(--spacing-unit)); +} diff --git a/src/core/client/admin/routes/configure/sections/auth/components/ConfigDescription.tsx b/src/core/client/admin/routes/configure/sections/auth/components/ConfigDescription.tsx new file mode 100644 index 000000000..1e37450c3 --- /dev/null +++ b/src/core/client/admin/routes/configure/sections/auth/components/ConfigDescription.tsx @@ -0,0 +1,22 @@ +import React, { StatelessComponent } from "react"; + +import { InputDescription } from "talk-ui/components"; +import { PropTypesOf } from "talk-ui/types"; + +interface Props { + container?: PropTypesOf["container"]; + children: React.ReactNode; +} + +import styles from "./ConfigDescription.css"; + +const ConfigDescription: StatelessComponent = ({ + children, + container, +}) => ( + + {children} + +); + +export default ConfigDescription; diff --git a/src/core/client/admin/routes/configure/sections/auth/components/DisplayNamesConfig.tsx b/src/core/client/admin/routes/configure/sections/auth/components/DisplayNamesConfig.tsx new file mode 100644 index 000000000..4622f1c83 --- /dev/null +++ b/src/core/client/admin/routes/configure/sections/auth/components/DisplayNamesConfig.tsx @@ -0,0 +1,94 @@ +import { Localized } from "fluent-react/compat"; +import React, { StatelessComponent } from "react"; +import { Field } from "react-final-form"; + +import { + Flex, + FormField, + HorizontalGutter, + RadioButton, + Typography, +} from "talk-ui/components"; + +import Header from "../../../components/Header"; + +interface Props { + disabled?: boolean; +} + +const parseStringBool = (v: string) => v === "true"; + +const DisplayNamesConfig: StatelessComponent = ({ disabled }) => ( + + +
    Display Names
    +
    + + + Some AUTH integrations include a Display Name as well as a User Name. + + + + + A User Name has to be unique (there can only be one Juan_Doe, for + example), whereas a Display Name does not. If your AUTH provider allows + for Display Names, you can enable this option. This allows for fewer + strange names (Juan_Doe23245) – however it could also be used to + spoof/impersonate another user. + + + + + + + {({ input }) => ( + + + Show Display Names (if available) + + + )} + + + {({ input }) => ( + + + Hide Display Names (if available) + + + )} + + + +
    +); + +export default DisplayNamesConfig; diff --git a/src/core/client/admin/routes/configure/sections/auth/components/FacebookConfig.tsx b/src/core/client/admin/routes/configure/sections/auth/components/FacebookConfig.tsx new file mode 100644 index 000000000..befc3a2ea --- /dev/null +++ b/src/core/client/admin/routes/configure/sections/auth/components/FacebookConfig.tsx @@ -0,0 +1,93 @@ +import { Localized } from "fluent-react/compat"; +import React, { StatelessComponent } from "react"; + +import { required, Validator } from "talk-framework/lib/validation"; +import { HorizontalGutter, TextLink, Typography } from "talk-ui/components"; + +import HorizontalRule from "../../../components/HorizontalRule"; +import ClientIDField from "./ClientIDField"; +import ClientSecretField from "./ClientSecretField"; +import ConfigBoxWithToggleField from "./ConfigBoxWithToggleField"; +import RedirectField from "./RedirectField"; +import RegistrationField from "./RegistrationField"; +import TargetFilterField from "./TargetFilterField"; + +interface Props { + disabled?: boolean; + callbackURL: string; +} + +const FacebookLink = () => ( + + {"https://developers.facebook.com/docs/facebook-login/web"} + +); + +const validateWhenEnabled = (validator: Validator): Validator => ( + v, + values +) => { + if (values.auth.integrations.facebook.enabled) { + return validator(v, values); + } + return ""; +}; + +const FacebookConfig: StatelessComponent = ({ + disabled, + callbackURL, +}) => ( + + Login with Facebook + + } + name="auth.integrations.facebook.enabled" + disabled={disabled} + > + {disabledInside => ( + + } + > + + To enable the integration with Facebook Authentication, you need to + create and set up a web application. For more information visit:
    + {"https://developers.facebook.com/docs/facebook-login/web"} +
    +
    + + + + + + + Use Facebook login on + + } + name="auth.integrations.facebook.targetFilter" + disabled={disabledInside} + /> + +
    + )} +
    +); + +export default FacebookConfig; diff --git a/src/core/client/admin/routes/configure/sections/auth/components/GoogleConfig.tsx b/src/core/client/admin/routes/configure/sections/auth/components/GoogleConfig.tsx new file mode 100644 index 000000000..7d6d3014d --- /dev/null +++ b/src/core/client/admin/routes/configure/sections/auth/components/GoogleConfig.tsx @@ -0,0 +1,93 @@ +import { Localized } from "fluent-react/compat"; +import React, { StatelessComponent } from "react"; + +import { required, Validator } from "talk-framework/lib/validation"; +import { HorizontalGutter, TextLink, Typography } from "talk-ui/components"; + +import HorizontalRule from "../../../components/HorizontalRule"; +import ClientIDField from "./ClientIDField"; +import ClientSecretField from "./ClientSecretField"; +import ConfigBoxWithToggleField from "./ConfigBoxWithToggleField"; +import RedirectField from "./RedirectField"; +import RegistrationField from "./RegistrationField"; +import TargetFilterField from "./TargetFilterField"; + +interface Props { + disabled?: boolean; + callbackURL: string; +} + +const GoogleLink = () => ( + + { + "https://developers.google.com/identity/protocols/OAuth2WebServer#creatingcred" + } + +); + +const validateWhenEnabled = (validator: Validator): Validator => ( + v, + values +) => { + if (values.auth.integrations.google.enabled) { + return validator(v, values); + } + return ""; +}; + +const GoogleConfig: StatelessComponent = ({ disabled, callbackURL }) => ( + + Login with Google + + } + name="auth.integrations.google.enabled" + disabled={disabled} + > + {disabledInside => ( + + } + > + + To enable the integration with Google Authentication you need to + create and set up a web application. For more information visit:
    + { + "https://developers.google.com/identity/protocols/OAuth2WebServer#creatingcred" + } +
    +
    + + + + + + + Use Google login on + + } + name="auth.integrations.google.targetFilter" + disabled={disabledInside} + /> + +
    + )} +
    +); + +export default GoogleConfig; diff --git a/src/core/client/admin/routes/configure/sections/auth/components/LocalAuthConfig.tsx b/src/core/client/admin/routes/configure/sections/auth/components/LocalAuthConfig.tsx new file mode 100644 index 000000000..1e796cfd1 --- /dev/null +++ b/src/core/client/admin/routes/configure/sections/auth/components/LocalAuthConfig.tsx @@ -0,0 +1,44 @@ +import { Localized } from "fluent-react/compat"; +import React, { StatelessComponent } from "react"; + +import { HorizontalGutter } from "talk-ui/components"; + +import ConfigBoxWithToggleField from "./ConfigBoxWithToggleField"; +import RegistrationField from "./RegistrationField"; +import TargetFilterField from "./TargetFilterField"; + +interface Props { + disabled?: boolean; +} + +const LocalAuthConfig: StatelessComponent = ({ disabled }) => ( + + Login with LocalAuth + + } + name="auth.integrations.local.enabled" + disabled={disabled} + > + {disabledInside => ( + + + Use LocalAuth login on + + } + name="auth.integrations.local.targetFilter" + disabled={disabledInside} + /> + + + )} + +); + +export default LocalAuthConfig; diff --git a/src/core/client/admin/routes/configure/sections/auth/components/OIDCConfig.css b/src/core/client/admin/routes/configure/sections/auth/components/OIDCConfig.css new file mode 100644 index 000000000..a139c0e3b --- /dev/null +++ b/src/core/client/admin/routes/configure/sections/auth/components/OIDCConfig.css @@ -0,0 +1,4 @@ +.redirectDescriptionIcon { + color: var(--palette-text-secondary); + flex-shrink: 0; +} diff --git a/src/core/client/admin/routes/configure/sections/auth/components/OIDCConfig.tsx b/src/core/client/admin/routes/configure/sections/auth/components/OIDCConfig.tsx new file mode 100644 index 000000000..d1d588dce --- /dev/null +++ b/src/core/client/admin/routes/configure/sections/auth/components/OIDCConfig.tsx @@ -0,0 +1,317 @@ +import { Localized } from "fluent-react/compat"; +import { identity } from "lodash"; +import React, { StatelessComponent } from "react"; +import { Field } from "react-final-form"; + +import { + composeValidators, + required, + validateURL, + Validator, +} from "talk-framework/lib/validation"; +import { + Button, + Flex, + FormField, + HorizontalGutter, + Icon, + InputLabel, + TextField, + TextLink, + Typography, +} from "talk-ui/components"; + +import HorizontalRule from "../../../components/HorizontalRule"; +import ClientIDField from "./ClientIDField"; +import ClientSecretField from "./ClientSecretField"; +import ConfigBoxWithToggleField from "./ConfigBoxWithToggleField"; +import ConfigDescription from "./ConfigDescription"; +import styles from "./OIDCConfig.css"; +import RedirectField from "./RedirectField"; +import RegistrationField from "./RegistrationField"; +import TargetFilterField from "./TargetFilterField"; +import ValidationMessage from "./ValidationMessage"; + +interface Props { + index: number; + disabled?: boolean; + callbackURL: string; + disableForDiscover?: boolean; + onDiscover?: () => void; +} + +const OIDCLink = () => ( + {"https://openid.net/connect/"} +); + +const OIDCConfig: StatelessComponent = ({ + disabled, + callbackURL, + index, + onDiscover, + disableForDiscover, +}) => { + const validateWhenEnabled = (validator: Validator): Validator => ( + v, + values + ) => { + if (values.auth.integrations.oidc[0].enabled) { + return validator(v, values); + } + return ""; + }; + return ( + + Login with OIDC + + } + name={`auth.integrations.oidc.${index}.enabled`} + disabled={disabled} + > + {disabledInside => ( + + }> + + {"To learn more: https://openid.net/connect/"} + + + + + + error + +
    + For OpenID Connect, your Redirect URI will not appear + until you after you save this integration +
    +
    +
    + + } + /> + + + + Provider Name + + + + The provider of the OIDC integration. This will be used when the + name of the provider needs to be displayed, e.g. “Log in with + {" "}” + + + + {({ input, meta }) => ( + <> + + {meta.touched && + (meta.error || meta.submitError) && ( + + {meta.error || meta.submitError} + + )} + + )} + + + + + + + Issuer + + + + After entering your Issuer information, click the Discover + button to have Talk complete the remaining fields. You may also + enter the information manually + + + + {({ input, meta }) => ( + <> + + + + + {meta.touched && + (meta.error || meta.submitError) && ( + + {meta.error || meta.submitError} + + )} + + )} + + + + + authorizationURL + + + {({ input, meta }) => ( + <> + + {meta.touched && + (meta.error || meta.submitError) && ( + + {meta.error || meta.submitError} + + )} + + )} + + + + + tokenURL + + + {({ input, meta }) => ( + <> + + {meta.touched && + (meta.error || meta.submitError) && ( + + {meta.error || meta.submitError} + + )} + + )} + + + + + jwksURI + + + {({ input, meta }) => ( + <> + + {meta.touched && + (meta.error || meta.submitError) && ( + + {meta.error || meta.submitError} + + )} + + )} + + + + Use OIDC login on + + } + name={`auth.integrations.oidc.${index}.targetFilter`} + disabled={disabledInside} + /> + +
    + )} +
    + ); +}; + +export default OIDCConfig; diff --git a/src/core/client/admin/routes/configure/sections/auth/components/RedirectField.tsx b/src/core/client/admin/routes/configure/sections/auth/components/RedirectField.tsx new file mode 100644 index 000000000..a106be2fb --- /dev/null +++ b/src/core/client/admin/routes/configure/sections/auth/components/RedirectField.tsx @@ -0,0 +1,25 @@ +import { Localized } from "fluent-react/compat"; +import React, { StatelessComponent } from "react"; + +import { CopyButton } from "talk-framework/components"; +import { Flex, FormField, InputLabel, TextField } from "talk-ui/components"; + +interface Props { + description?: React.ReactNode; + url: string; +} + +const RedirectField: StatelessComponent = ({ url, description }) => ( + + + Redirect URI + + {description} + + + + + +); + +export default RedirectField; diff --git a/src/core/client/admin/routes/configure/sections/auth/components/RegistrationField.tsx b/src/core/client/admin/routes/configure/sections/auth/components/RegistrationField.tsx new file mode 100644 index 000000000..f5291475b --- /dev/null +++ b/src/core/client/admin/routes/configure/sections/auth/components/RegistrationField.tsx @@ -0,0 +1,44 @@ +import { Localized } from "fluent-react/compat"; +import React, { StatelessComponent } from "react"; +import { Field } from "react-final-form"; + +import { CheckBox, FormField, InputLabel } from "talk-ui/components"; + +import ConfigDescription from "./ConfigDescription"; + +interface Props { + name: string; + disabled: boolean; +} + +const RegistrationField: StatelessComponent = ({ name, disabled }) => ( + + + Registration + + + + Allow users to create a new account with this provider. + + + + + {({ input }) => ( + + + Allow Registration + + + )} + + + +); + +export default RegistrationField; diff --git a/src/core/client/admin/routes/configure/sections/auth/components/SSOConfig.tsx b/src/core/client/admin/routes/configure/sections/auth/components/SSOConfig.tsx new file mode 100644 index 000000000..2f527ae61 --- /dev/null +++ b/src/core/client/admin/routes/configure/sections/auth/components/SSOConfig.tsx @@ -0,0 +1,48 @@ +import { Localized } from "fluent-react/compat"; +import React, { StatelessComponent } from "react"; + +import { PropTypesOf } from "talk-framework/types"; +import { HorizontalGutter } from "talk-ui/components"; + +import SSOKeyFieldContainer from "../containers/SSOKeyFieldContainer"; +import ConfigBoxWithToggleField from "./ConfigBoxWithToggleField"; +import RegistrationField from "./RegistrationField"; +import TargetFilterField from "./TargetFilterField"; + +interface Props { + disabled?: boolean; + sso: PropTypesOf["sso"]; +} + +const SSOConfig: StatelessComponent = ({ disabled, sso }) => ( + + Login with SSO + + } + name="auth.integrations.sso.enabled" + disabled={disabled} + > + {disabledInside => ( + + + + Use SSO login on + + } + name="auth.integrations.sso.targetFilter" + disabled={disabledInside} + /> + + + )} + +); + +export default SSOConfig; diff --git a/src/core/client/admin/routes/configure/sections/auth/components/SSOKeyField.css b/src/core/client/admin/routes/configure/sections/auth/components/SSOKeyField.css new file mode 100644 index 000000000..0e072efc3 --- /dev/null +++ b/src/core/client/admin/routes/configure/sections/auth/components/SSOKeyField.css @@ -0,0 +1,16 @@ +.keyGenerated { + composes: button from "talk-ui/shared/typography.css"; + color: var(--palette-text-secondary); + width: calc(29 * var(--spacing-unit)); + flex-shrink: 0; +} + +.warnIcon { + color: var(--palette-text-secondary); + flex-shrink: 0; + padding-top: 3px; +} + +.warn { + color: var(--palette-text-secondary); +} diff --git a/src/core/client/admin/routes/configure/sections/auth/components/SSOKeyField.tsx b/src/core/client/admin/routes/configure/sections/auth/components/SSOKeyField.tsx new file mode 100644 index 000000000..ed34b8f37 --- /dev/null +++ b/src/core/client/admin/routes/configure/sections/auth/components/SSOKeyField.tsx @@ -0,0 +1,65 @@ +import { Localized } from "fluent-react/compat"; +import React, { StatelessComponent } from "react"; + +import { + Button, + Flex, + FormField, + Icon, + InputLabel, + TextField, + Typography, +} from "talk-ui/components"; + +import styles from "./SSOKeyField.css"; + +interface Props { + disabled?: boolean; + generatedKey?: string; + keyGeneratedAt?: any; + onRegenerate?: () => void; +} + +const SSOKeyField: StatelessComponent = ({ + generatedKey, + keyGeneratedAt, + disabled, + onRegenerate, +}) => ( + + + Key + + + + + + + + + + + KEY GENERATED AT: {keyGeneratedAt} + + + warning + + + Regenerating a key will invalidate any existing user sessions, and all + signed-in users will be signed out + + + + +); + +export default SSOKeyField; diff --git a/src/core/client/admin/routes/configure/sections/auth/components/TargetFilterField.tsx b/src/core/client/admin/routes/configure/sections/auth/components/TargetFilterField.tsx new file mode 100644 index 000000000..ba0e5174d --- /dev/null +++ b/src/core/client/admin/routes/configure/sections/auth/components/TargetFilterField.tsx @@ -0,0 +1,57 @@ +import { Localized } from "fluent-react/compat"; +import React, { StatelessComponent } from "react"; +import { Field } from "react-final-form"; + +import { CheckBox, Flex, FormField, InputLabel } from "talk-ui/components"; + +const bool = (v: any) => !!v; + +interface Props { + label: React.ReactNode; + name: string; + disabled: boolean; +} + +const TargetFilterField: StatelessComponent = ({ + name, + label, + disabled, +}) => ( + + {label} + + + {({ input, meta }) => ( + + + Talk Admin + + + )} + + + {({ input }) => ( + + + Comment Stream + + + )} + + + +); + +export default TargetFilterField; diff --git a/src/core/client/admin/routes/configure/sections/auth/components/ValidationMessage.css b/src/core/client/admin/routes/configure/sections/auth/components/ValidationMessage.css new file mode 100644 index 000000000..1ff2ae13c --- /dev/null +++ b/src/core/client/admin/routes/configure/sections/auth/components/ValidationMessage.css @@ -0,0 +1,3 @@ +.root { + min-width: calc(29 * var(--spacing-unit)); +} diff --git a/src/core/client/admin/routes/configure/sections/auth/components/ValidationMessage.tsx b/src/core/client/admin/routes/configure/sections/auth/components/ValidationMessage.tsx new file mode 100644 index 000000000..649091875 --- /dev/null +++ b/src/core/client/admin/routes/configure/sections/auth/components/ValidationMessage.tsx @@ -0,0 +1,15 @@ +import React, { StatelessComponent } from "react"; + +import { ValidationMessage as UIValidationMessage } from "talk-ui/components"; + +interface Props { + children: React.ReactNode; +} + +import styles from "./ValidationMessage.css"; + +const ValidationMessage: StatelessComponent = ({ children }) => ( + {children} +); + +export default ValidationMessage; diff --git a/src/core/client/admin/routes/configure/sections/auth/containers/AuthContainer.tsx b/src/core/client/admin/routes/configure/sections/auth/containers/AuthContainer.tsx new file mode 100644 index 000000000..916518e6e --- /dev/null +++ b/src/core/client/admin/routes/configure/sections/auth/containers/AuthContainer.tsx @@ -0,0 +1,67 @@ +import { FormApi } from "final-form"; +import { RouteProps } from "found"; +import { merge } from "lodash"; +import React from "react"; +import { graphql } from "react-relay"; + +import { AuthContainerQueryResponse } from "talk-admin/__generated__/AuthContainerQuery.graphql"; +import { Spinner } from "talk-ui/components"; + +import Auth from "../components/Auth"; + +interface Props extends AuthContainerQueryResponse { + form: FormApi; + submitting?: boolean; +} + +export default class AuthContainer extends React.Component { + public static routeConfig: RouteProps; + private initialValues = {}; + + constructor(props: Props) { + super(props); + } + + public componentDidMount() { + this.props.form.initialize({ auth: this.initialValues }); + } + + private handleOnInitValues = (values: any) => { + this.initialValues = merge(this.initialValues, values); + }; + + public render() { + return ( + + ); + } +} + +AuthContainer.routeConfig = { + Component: AuthContainer, + query: graphql` + query AuthContainerQuery { + settings { + auth { + ...FacebookConfigContainer_auth + ...FacebookConfigContainer_authReadOnly + ...GoogleConfigContainer_auth + ...GoogleConfigContainer_authReadOnly + ...SSOConfigContainer_auth + ...SSOConfigContainer_authReadOnly + ...LocalAuthConfigContainer_auth + ...DisplayNamesConfigContainer_auth + ...OIDCConfigListContainer_auth + ...OIDCConfigListContainer_authReadOnly + } + } + } + `, + cacheConfig: { force: true }, + render: ({ Component, props }) => + props && Component ? : , +}; diff --git a/src/core/client/admin/routes/configure/sections/auth/containers/DisplayNamesConfigContainer.tsx b/src/core/client/admin/routes/configure/sections/auth/containers/DisplayNamesConfigContainer.tsx new file mode 100644 index 000000000..ed5c57285 --- /dev/null +++ b/src/core/client/admin/routes/configure/sections/auth/containers/DisplayNamesConfigContainer.tsx @@ -0,0 +1,37 @@ +import React from "react"; +import { graphql } from "react-relay"; + +import { DisplayNamesConfigContainer_auth as AuthData } from "talk-admin/__generated__/DisplayNamesConfigContainer_auth.graphql"; +import { withFragmentContainer } from "talk-framework/lib/relay"; + +import DisplayNamesConfig from "../components/DisplayNamesConfig"; + +interface Props { + auth: AuthData; + onInitValues: (values: AuthData) => void; + disabled?: boolean; +} + +class DisplayNamesConfigContainer extends React.Component { + constructor(props: Props) { + super(props); + props.onInitValues(props.auth); + } + + public render() { + const { disabled } = this.props; + return ; + } +} + +const enhanced = withFragmentContainer({ + auth: graphql` + fragment DisplayNamesConfigContainer_auth on Auth { + displayName { + enabled + } + } + `, +})(DisplayNamesConfigContainer); + +export default enhanced; diff --git a/src/core/client/admin/routes/configure/sections/auth/containers/FacebookConfigContainer.tsx b/src/core/client/admin/routes/configure/sections/auth/containers/FacebookConfigContainer.tsx new file mode 100644 index 000000000..fddaf3b7c --- /dev/null +++ b/src/core/client/admin/routes/configure/sections/auth/containers/FacebookConfigContainer.tsx @@ -0,0 +1,62 @@ +import React from "react"; +import { graphql } from "react-relay"; + +import { FacebookConfigContainer_auth as AuthData } from "talk-admin/__generated__/FacebookConfigContainer_auth.graphql"; +import { FacebookConfigContainer_authReadOnly as AuthReadOnlyData } from "talk-admin/__generated__/FacebookConfigContainer_authReadOnly.graphql"; +import { withFragmentContainer } from "talk-framework/lib/relay"; + +import FacebookConfig from "../components/FacebookConfig"; + +interface Props { + auth: AuthData; + authReadOnly: AuthReadOnlyData; + onInitValues: (values: AuthData) => void; + disabled?: boolean; +} + +class FacebookConfigContainer extends React.Component { + constructor(props: Props) { + super(props); + props.onInitValues(props.auth); + } + + public render() { + const { disabled, authReadOnly } = this.props; + return ( + + ); + } +} + +const enhanced = withFragmentContainer({ + auth: graphql` + fragment FacebookConfigContainer_auth on Auth { + integrations { + facebook { + enabled + allowRegistration + targetFilter { + admin + stream + } + clientID + clientSecret + } + } + } + `, + authReadOnly: graphql` + fragment FacebookConfigContainer_authReadOnly on Auth { + integrations { + facebook { + callbackURL + } + } + } + `, +})(FacebookConfigContainer); + +export default enhanced; diff --git a/src/core/client/admin/routes/configure/sections/auth/containers/GoogleConfigContainer.tsx b/src/core/client/admin/routes/configure/sections/auth/containers/GoogleConfigContainer.tsx new file mode 100644 index 000000000..b38e4136f --- /dev/null +++ b/src/core/client/admin/routes/configure/sections/auth/containers/GoogleConfigContainer.tsx @@ -0,0 +1,62 @@ +import React from "react"; +import { graphql } from "react-relay"; + +import { GoogleConfigContainer_auth as AuthData } from "talk-admin/__generated__/GoogleConfigContainer_auth.graphql"; +import { GoogleConfigContainer_authReadOnly as AuthReadOnlyData } from "talk-admin/__generated__/GoogleConfigContainer_authReadOnly.graphql"; +import { withFragmentContainer } from "talk-framework/lib/relay"; + +import GoogleConfig from "../components/GoogleConfig"; + +interface Props { + auth: AuthData; + authReadOnly: AuthReadOnlyData; + onInitValues: (values: AuthData) => void; + disabled?: boolean; +} + +class GoogleConfigContainer extends React.Component { + constructor(props: Props) { + super(props); + props.onInitValues(props.auth); + } + + public render() { + const { disabled, authReadOnly } = this.props; + return ( + + ); + } +} + +const enhanced = withFragmentContainer({ + auth: graphql` + fragment GoogleConfigContainer_auth on Auth { + integrations { + google { + enabled + allowRegistration + targetFilter { + admin + stream + } + clientID + clientSecret + } + } + } + `, + authReadOnly: graphql` + fragment GoogleConfigContainer_authReadOnly on Auth { + integrations { + google { + callbackURL + } + } + } + `, +})(GoogleConfigContainer); + +export default enhanced; diff --git a/src/core/client/admin/routes/configure/sections/auth/containers/LocalAuthConfigContainer.tsx b/src/core/client/admin/routes/configure/sections/auth/containers/LocalAuthConfigContainer.tsx new file mode 100644 index 000000000..7c3b18dca --- /dev/null +++ b/src/core/client/admin/routes/configure/sections/auth/containers/LocalAuthConfigContainer.tsx @@ -0,0 +1,44 @@ +import React from "react"; +import { graphql } from "react-relay"; + +import { LocalAuthConfigContainer_auth as AuthData } from "talk-admin/__generated__/LocalAuthConfigContainer_auth.graphql"; +import { withFragmentContainer } from "talk-framework/lib/relay"; + +import LocalAuthConfig from "../components/LocalAuthConfig"; + +interface Props { + auth: AuthData; + onInitValues: (values: AuthData) => void; + disabled?: boolean; +} + +class LocalAuthConfigContainer extends React.Component { + constructor(props: Props) { + super(props); + props.onInitValues(props.auth); + } + + public render() { + const { disabled } = this.props; + return ; + } +} + +const enhanced = withFragmentContainer({ + auth: graphql` + fragment LocalAuthConfigContainer_auth on Auth { + integrations { + local { + enabled + allowRegistration + targetFilter { + admin + stream + } + } + } + } + `, +})(LocalAuthConfigContainer); + +export default enhanced; diff --git a/src/core/client/admin/routes/configure/sections/auth/containers/OIDCConfigContainer.tsx b/src/core/client/admin/routes/configure/sections/auth/containers/OIDCConfigContainer.tsx new file mode 100644 index 000000000..b576fe571 --- /dev/null +++ b/src/core/client/admin/routes/configure/sections/auth/containers/OIDCConfigContainer.tsx @@ -0,0 +1,70 @@ +import { FormApi } from "final-form"; +import PropTypes from "prop-types"; +import React from "react"; + +import { + DiscoverOIDCConfigurationFetch, + withDiscoverOIDCConfigurationFetch, +} from "talk-admin/fetches"; + +import OIDCConfig from "../components/OIDCConfig"; + +interface Props { + index: number; + callbackURL: string; + disabled?: boolean; + discoverOIDCConfiguration: DiscoverOIDCConfigurationFetch; +} + +interface State { + awaitingResponse: boolean; +} + +class OIDCConfigContainer extends React.Component { + public static contextTypes = { + reactFinalForm: PropTypes.object, + }; + + public state = { + awaitingResponse: false, + }; + + private handleDiscover = async () => { + const form = this.context.reactFinalForm as FormApi; + this.setState({ awaitingResponse: true }); + try { + const config = await this.props.discoverOIDCConfiguration({ + issuer: form.getState().values.auth.integrations.oidc[0].issuer, + }); + if (config) { + form.change( + "auth.integrations.oidc.0.authorizationURL", + config.authorizationURL + ); + form.change("auth.integrations.oidc.0.jwksURI", config.jwksURI); + form.change("auth.integrations.oidc.0.tokenURL", config.tokenURL); + } + } catch (error) { + // tslint:disable-next-line:no-console + console.warn(error); + } + this.setState({ awaitingResponse: false }); + }; + + public render() { + const { disabled, index, callbackURL } = this.props; + return ( + + ); + } +} + +const enhanced = withDiscoverOIDCConfigurationFetch(OIDCConfigContainer); + +export default enhanced; diff --git a/src/core/client/admin/routes/configure/sections/auth/containers/OIDCConfigListContainer.tsx b/src/core/client/admin/routes/configure/sections/auth/containers/OIDCConfigListContainer.tsx new file mode 100644 index 000000000..9b7a4b6d2 --- /dev/null +++ b/src/core/client/admin/routes/configure/sections/auth/containers/OIDCConfigListContainer.tsx @@ -0,0 +1,150 @@ +import { cloneDeep } from "lodash"; +import React from "react"; +import { graphql } from "react-relay"; + +import { OIDCConfigListContainer_auth as AuthData } from "talk-admin/__generated__/OIDCConfigListContainer_auth.graphql"; +import { OIDCConfigListContainer_authReadOnly as AuthReadOnlyData } from "talk-admin/__generated__/OIDCConfigListContainer_authReadOnly.graphql"; +import { + CreateOIDCAuthIntegrationMutation, + UpdateOIDCAuthIntegrationMutation, + withCreateOIDCAuthIntegrationMutation, + withUpdateOIDCAuthIntegrationMutation, +} from "talk-admin/mutations"; +import { withFragmentContainer } from "talk-framework/lib/relay"; + +import { + AddSubmitHook, + RemoveSubmitHook, + SubmitHook, + withSubmitHookContext, +} from "../../../submitHook"; +import OIDCConfigContainer from "./OIDCConfigContainer"; + +interface Props { + auth: AuthData; + authReadOnly: AuthReadOnlyData; + disabled?: boolean; + addSubmitHook: AddSubmitHook; + onInitValues: (values: AuthData) => void; + createOIDCAuthIntegration: CreateOIDCAuthIntegrationMutation; + updateOIDCAuthIntegration: UpdateOIDCAuthIntegrationMutation; +} + +class OIDCConfigListContainer extends React.Component { + private removeSubmitHook: RemoveSubmitHook; + + constructor(props: Props) { + super(props); + props.onInitValues(this.getAuthWithDefault()); + this.removeSubmitHook = this.props.addSubmitHook(this.submitHook); + } + + public componentWillUnmount() { + this.removeSubmitHook(); + } + + private submitHook: SubmitHook = async (data: any) => { + const cloned = cloneDeep(data); + const oidc = cloned.auth.integrations.oidc; + delete cloned.auth.integrations.oidc; + if (this.props.auth.integrations.oidc.length === 0) { + if (oidc[0].enabled) { + await this.props.createOIDCAuthIntegration({ configuration: oidc[0] }); + } + } else { + await this.props.updateOIDCAuthIntegration({ + configuration: oidc[0], + id: this.props.authReadOnly.integrations.oidc[0].id, + }); + } + return cloned; + }; + + private getAuthWithDefault(): AuthData { + return this.props.auth.integrations.oidc.length === 0 + ? ({ + integrations: { + oidc: [ + { + clientID: "", + clientSecret: "", + allowRegistration: false, + targetFilter: { + admin: true, + stream: true, + }, + name: "", + authorizationURL: "", + tokenURL: "", + jwksURI: "", + issuer: "", + }, + ], + }, + } as any) + : this.props.auth; + } + + public render() { + const { disabled, authReadOnly } = this.props; + const integrations = this.getAuthWithDefault().integrations.oidc.map( + (data, i) => ( + + ) + ); + return <>{integrations}; + } +} + +const enhanced = withFragmentContainer({ + auth: graphql` + fragment OIDCConfigListContainer_auth on Auth { + integrations { + oidc { + enabled + allowRegistration + targetFilter { + admin + stream + } + name + clientID + clientSecret + authorizationURL + tokenURL + jwksURI + issuer + } + } + } + `, + authReadOnly: graphql` + fragment OIDCConfigListContainer_authReadOnly on Auth { + integrations { + oidc { + id + callbackURL + } + } + } + `, +})( + withCreateOIDCAuthIntegrationMutation( + withUpdateOIDCAuthIntegrationMutation( + withSubmitHookContext(addSubmitHook => ({ addSubmitHook }))( + OIDCConfigListContainer + ) + ) + ) +); + +export default enhanced; diff --git a/src/core/client/admin/routes/configure/sections/auth/containers/SSOConfigContainer.tsx b/src/core/client/admin/routes/configure/sections/auth/containers/SSOConfigContainer.tsx new file mode 100644 index 000000000..3201d0b98 --- /dev/null +++ b/src/core/client/admin/routes/configure/sections/auth/containers/SSOConfigContainer.tsx @@ -0,0 +1,60 @@ +import React from "react"; +import { graphql } from "react-relay"; + +import { SSOConfigContainer_auth as AuthData } from "talk-admin/__generated__/SSOConfigContainer_auth.graphql"; +import { SSOConfigContainer_authReadOnly as AuthReadOnlyData } from "talk-admin/__generated__/SSOConfigContainer_authReadOnly.graphql"; +import { withFragmentContainer } from "talk-framework/lib/relay"; + +import SSOConfig from "../components/SSOConfig"; + +interface Props { + auth: AuthData; + authReadOnly: AuthReadOnlyData; + onInitValues: (values: AuthData) => void; + disabled?: boolean; +} + +class SSOConfigContainer extends React.Component { + constructor(props: Props) { + super(props); + props.onInitValues(props.auth); + } + + public render() { + const { disabled } = this.props; + return ( + + ); + } +} + +const enhanced = withFragmentContainer({ + auth: graphql` + fragment SSOConfigContainer_auth on Auth { + integrations { + sso { + enabled + allowRegistration + targetFilter { + admin + stream + } + } + } + } + `, + authReadOnly: graphql` + fragment SSOConfigContainer_authReadOnly on Auth { + integrations { + sso { + ...SSOKeyFieldContainer_sso + } + } + } + `, +})(SSOConfigContainer); + +export default enhanced; diff --git a/src/core/client/admin/routes/configure/sections/auth/containers/SSOKeyFieldContainer.tsx b/src/core/client/admin/routes/configure/sections/auth/containers/SSOKeyFieldContainer.tsx new file mode 100644 index 000000000..ebc68ba03 --- /dev/null +++ b/src/core/client/admin/routes/configure/sections/auth/containers/SSOKeyFieldContainer.tsx @@ -0,0 +1,58 @@ +import React from "react"; +import { graphql } from "react-relay"; + +import { SSOKeyFieldContainer_sso as SSOData } from "talk-admin/__generated__/SSOKeyFieldContainer_sso.graphql"; +import { + RegenerateSSOKeyMutation, + withRegenerateSSOKeyMutation, +} from "talk-admin/mutations"; +import { withFragmentContainer } from "talk-framework/lib/relay"; + +import SSOKeyField from "../components/SSOKeyField"; + +interface Props { + sso: SSOData; + disabled?: boolean; + regenerateSSOKey: RegenerateSSOKeyMutation; +} + +interface State { + awaitingResponse: boolean; +} + +class SSOKeyFieldContainer extends React.Component { + public state = { + awaitingResponse: false, + }; + + private handleRegenerate = async () => { + this.setState({ awaitingResponse: true }); + await this.props.regenerateSSOKey(); + this.setState({ awaitingResponse: false }); + }; + + public render() { + const { disabled } = this.props; + return ( + + ); + } +} + +const enhanced = withRegenerateSSOKeyMutation( + withFragmentContainer({ + sso: graphql` + fragment SSOKeyFieldContainer_sso on SSOAuthIntegration { + key + keyGeneratedAt + } + `, + })(SSOKeyFieldContainer) +); + +export default enhanced; diff --git a/src/core/client/admin/routes/configure/submitHook/SubmitHookContext.tsx b/src/core/client/admin/routes/configure/submitHook/SubmitHookContext.tsx new file mode 100644 index 000000000..aaf25133f --- /dev/null +++ b/src/core/client/admin/routes/configure/submitHook/SubmitHookContext.tsx @@ -0,0 +1,14 @@ +import { noop } from "lodash"; +import React from "react"; + +export type SubmitHook = (data: any) => Promise | any; +export type RemoveSubmitHook = () => void; +export type AddSubmitHook = (hook: SubmitHook) => RemoveSubmitHook; +export type SubmitHookContext = AddSubmitHook; + +const { Provider, Consumer } = React.createContext( + () => noop +); + +export const SubmitHookContextProvider = Provider; +export const SubmitHookContextConsumer = Consumer; diff --git a/src/core/client/admin/routes/configure/submitHook/index.ts b/src/core/client/admin/routes/configure/submitHook/index.ts new file mode 100644 index 000000000..d2edb61aa --- /dev/null +++ b/src/core/client/admin/routes/configure/submitHook/index.ts @@ -0,0 +1,9 @@ +export { + AddSubmitHook, + SubmitHook, + RemoveSubmitHook, + SubmitHookContext, + SubmitHookContextConsumer, + SubmitHookContextProvider, +} from "./SubmitHookContext"; +export { default as withSubmitHookContext } from "./withSubmitHookContext"; diff --git a/src/core/client/admin/routes/configure/submitHook/withSubmitHookContext.ts b/src/core/client/admin/routes/configure/submitHook/withSubmitHookContext.ts new file mode 100644 index 000000000..ebd33be53 --- /dev/null +++ b/src/core/client/admin/routes/configure/submitHook/withSubmitHookContext.ts @@ -0,0 +1,12 @@ +import { createContextHOC } from "talk-framework/helpers"; +import { + SubmitHookContext, + SubmitHookContextConsumer, +} from "./SubmitHookContext"; + +const withSubmitHookContext = createContextHOC( + "withSubmitHookContext", + SubmitHookContextConsumer +); + +export default withSubmitHookContext; diff --git a/src/core/client/admin/test/__snapshots__/login.spec.tsx.snap b/src/core/client/admin/test/__snapshots__/login.spec.tsx.snap index daa441ee9..9d5d1c4d5 100644 --- a/src/core/client/admin/test/__snapshots__/login.spec.tsx.snap +++ b/src/core/client/admin/test/__snapshots__/login.spec.tsx.snap @@ -195,7 +195,6 @@ exports[`accepts correct password 1`] = ` disabled={false} onBlur={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -405,7 +404,6 @@ exports[`accepts valid email 1`] = ` disabled={false} onBlur={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -628,7 +626,6 @@ exports[`checks for invalid email 1`] = ` disabled={false} onBlur={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -825,7 +822,6 @@ exports[`renders sign in form 1`] = ` disabled={false} onBlur={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -1048,7 +1044,6 @@ exports[`shows error when submitting empty form 1`] = ` disabled={false} onBlur={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -1245,7 +1240,6 @@ exports[`shows server error 1`] = ` disabled={true} onBlur={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -1447,7 +1441,6 @@ exports[`shows server error 2`] = ` disabled={false} onBlur={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -1644,7 +1637,6 @@ exports[`submits form successfully 1`] = ` disabled={true} onBlur={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -1841,7 +1833,6 @@ exports[`submits form successfully 2`] = ` disabled={false} onBlur={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} diff --git a/src/core/client/admin/test/configure/__snapshots__/auth.spec.tsx.snap b/src/core/client/admin/test/configure/__snapshots__/auth.spec.tsx.snap new file mode 100644 index 000000000..ff25323e7 --- /dev/null +++ b/src/core/client/admin/test/configure/__snapshots__/auth.spec.tsx.snap @@ -0,0 +1,3148 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`change settings: during submit: oidc without errors 1`] = ` +
    +
    +
    + + Login with OpenID Connect + +
    +
    +
    +
    + + +
    +
    +
    +
    +
    +
    +

    + To learn more: + + https://openid.net/connect/ + +

    +
    +
    + +
    +
    + +
    + For OpenID Connect, your Redirect URI will not appear until you after you save this integration. +
    +
    +
    +
    + + +
    +
    +
    +
    + +

    + The provider of the OpenID Connect integration. This will be used when the name of the provider +needs to be displayed, e.g. “Log in with <Facebook>”. +

    + +
    +
    + + +
    +
    + + +
    +
    + +

    + After entering your Issuer information, click the Discover button to have Talk complete +the remaining fields. You may also enter the information manually. +

    +
    + + +
    +
    +
    + + +
    +
    + + +
    +
    + + +
    +
    + +
    +
    + + +
    +
    + + +
    +
    +
    +
    + +

    + Allow users that have not signed up before with this authentication +integration to register for a new account. +

    +
    +
    + + +
    +
    +
    +
    +
    +
    +`; + +exports[`change settings: enable facebook configure box 1`] = ` +
    +
    +
    + + Login with Facebook + +
    +
    +
    +
    + + +
    +
    +
    +
    +
    +
    +

    + To enable the integration with Facebook Authentication, +you need to create and set up a web application. +For more information visit: + + https://developers.facebook.com/docs/facebook-login/web + + . +

    +
    +
    + +
    + + +
    +
    +
    +
    + + +
    +
    + + +
    +
    + +
    +
    + + +
    +
    + + +
    +
    +
    +
    + +

    + Allow users that have not signed up before with this authentication +integration to register for a new account. +

    +
    +
    + + +
    +
    +
    +
    +
    +
    +`; + +exports[`change settings: enable oidc configure box 1`] = ` +
    +
    +
    + + Login with OpenID Connect + +
    +
    +
    +
    + + +
    +
    +
    +
    +
    +
    +

    + To learn more: + + https://openid.net/connect/ + +

    +
    +
    + +
    +
    + +
    + For OpenID Connect, your Redirect URI will not appear until you after you save this integration. +
    +
    +
    +
    + + +
    +
    +
    +
    + +

    + The provider of the OpenID Connect integration. This will be used when the name of the provider +needs to be displayed, e.g. “Log in with <Facebook>”. +

    + +
    +
    + + +
    +
    + + +
    +
    + +

    + After entering your Issuer information, click the Discover button to have Talk complete +the remaining fields. You may also enter the information manually. +

    +
    + + +
    +
    +
    + + +
    +
    + + +
    +
    + + +
    +
    + +
    +
    + + +
    +
    + + +
    +
    +
    +
    + +

    + Allow users that have not signed up before with this authentication +integration to register for a new account. +

    +
    +
    + + +
    +
    +
    +
    +
    +
    +`; + +exports[`change settings: oidc validation errors 1`] = ` +
    +
    +
    + + Login with OpenID Connect + +
    +
    +
    +
    + + +
    +
    +
    +
    +
    +
    +

    + To learn more: + + https://openid.net/connect/ + +

    +
    +
    + +
    +
    + +
    + For OpenID Connect, your Redirect URI will not appear until you after you save this integration. +
    +
    +
    +
    + + +
    +
    +
    +
    + +

    + The provider of the OpenID Connect integration. This will be used when the name of the provider +needs to be displayed, e.g. “Log in with <Facebook>”. +

    + +
    + + + This field is required. + +
    +
    +
    + + +
    + + + This field is required. + +
    +
    +
    + + +
    + + + This field is required. + +
    +
    +
    + +

    + After entering your Issuer information, click the Discover button to have Talk complete +the remaining fields. You may also enter the information manually. +

    +
    + + +
    +
    + + + This field is required. + +
    +
    +
    + + +
    + + + This field is required. + +
    +
    +
    + + +
    + + + This field is required. + +
    +
    +
    + + +
    + + + This field is required. + +
    +
    +
    + +
    +
    + + +
    +
    + + +
    +
    +
    +
    + +

    + Allow users that have not signed up before with this authentication +integration to register for a new account. +

    +
    +
    + + +
    +
    +
    +
    +
    +
    +`; + +exports[`regenerate sso key 1`] = ` +
    + +
    + + +
    +
    +

    + KEY GENERATED AT: +⁨11/12/2018, 11:26 PM⁩ +

    + +

    + Regenerating a key will invalidate any existing user sessions, +and all signed-in users will be signed out. +

    +
    +
    +`; + +exports[`renders configure auth 1`] = ` +
    +
    +
    +
    +
    + +
    + +
    +
    +
    +
    +

    + Display Names +

    +

    + Some Authentication Integrations include a Display Name as well as a User Name. +

    +

    + A User Name has to be unique (there can only be one Juan_Doe, for example), +whereas a Display Name does not. If your authentication provider allows for Display Names, +you can enable this option. This allows for fewer strange names (Juan_Doe23245) – +however it could also be used to spoof/impersonate another user. +

    +
    +
    +
    + + +
    +
    + + +
    +
    +
    +
    +
    +

    + Authentication Integrations +

    +
    +
    +
    + + Login with Email Authentication + +
    +
    +
    +
    + + +
    +
    +
    +
    +
    +
    +
    + +
    +
    + + +
    +
    + + +
    +
    +
    +
    + +

    + Allow users that have not signed up before with this authentication +integration to register for a new account. +

    +
    +
    + + +
    +
    +
    +
    +
    +
    +
    +
    +
    + + Login with OpenID Connect + +
    +
    +
    +
    + + +
    +
    +
    +
    +
    +
    +

    + To learn more: + + https://openid.net/connect/ + +

    +
    +
    + +
    +
    + +
    + For OpenID Connect, your Redirect URI will not appear until you after you save this integration. +
    +
    +
    +
    + + +
    +
    +
    +
    + +

    + The provider of the OpenID Connect integration. This will be used when the name of the provider +needs to be displayed, e.g. “Log in with <Facebook>”. +

    + +
    +
    + + +
    +
    + + +
    +
    + +

    + After entering your Issuer information, click the Discover button to have Talk complete +the remaining fields. You may also enter the information manually. +

    +
    + + +
    +
    +
    + + +
    +
    + + +
    +
    + + +
    +
    + +
    +
    + + +
    +
    + + +
    +
    +
    +
    + +

    + Allow users that have not signed up before with this authentication +integration to register for a new account. +

    +
    +
    + + +
    +
    +
    +
    +
    +
    +
    +
    +
    + + Login with Single Sign On + +
    +
    +
    +
    + + +
    +
    +
    +
    +
    +
    +
    + +
    + + +
    +
    +

    + KEY GENERATED AT: +⁨Invalid Date⁩ +

    + +

    + Regenerating a key will invalidate any existing user sessions, +and all signed-in users will be signed out. +

    +
    +
    +
    + +
    +
    + + +
    +
    + + +
    +
    +
    +
    + +

    + Allow users that have not signed up before with this authentication +integration to register for a new account. +

    +
    +
    + + +
    +
    +
    +
    +
    +
    +
    +
    +
    + + Login with Google + +
    +
    +
    +
    + + +
    +
    +
    +
    +
    +
    +

    + To enable the integration with Google Authentication you need +to create and set up a web application. For more information visit: + + + https://developers.google.com/identity/protocols/OAuth2WebServer#creatingcred + + . +

    +
    +
    + +
    + + +
    +
    +
    +
    + + +
    +
    + + +
    +
    + +
    +
    + + +
    +
    + + +
    +
    +
    +
    + +

    + Allow users that have not signed up before with this authentication +integration to register for a new account. +

    +
    +
    + + +
    +
    +
    +
    +
    +
    +
    +
    +
    + + Login with Facebook + +
    +
    +
    +
    + + +
    +
    +
    +
    +
    +
    +

    + To enable the integration with Facebook Authentication, +you need to create and set up a web application. +For more information visit: + + https://developers.facebook.com/docs/facebook-login/web + + . +

    +
    +
    + +
    + + +
    +
    +
    +
    + + +
    +
    + + +
    +
    + +
    +
    + + +
    +
    + + +
    +
    +
    +
    + +

    + Allow users that have not signed up before with this authentication +integration to register for a new account. +

    +
    +
    + + +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +`; diff --git a/src/core/client/admin/test/configure/auth.spec.tsx b/src/core/client/admin/test/configure/auth.spec.tsx new file mode 100644 index 000000000..a8e781249 --- /dev/null +++ b/src/core/client/admin/test/configure/auth.spec.tsx @@ -0,0 +1,287 @@ +import { cloneDeep, get, merge } from "lodash"; +import sinon from "sinon"; + +import { timeout } from "talk-common/utils"; +import { + createSinonStub, + inputPredicate, + limitSnapshotTo, + replaceHistoryLocation, +} from "talk-framework/testHelpers"; + +import create from "../create"; +import { settings } from "../fixtures"; + +beforeEach(async () => { + replaceHistoryLocation("http://localhost/admin/configure/auth"); +}); + +const createTestRenderer = async (resolver: any = {}) => { + const resolvers = { + ...resolver, + Query: { + ...resolver.Query, + settings: sinon + .stub() + .returns(merge(settings, get(resolver, "Query.settings"))), + }, + }; + const { testRenderer } = create({ + // Set this to true, to see graphql responses. + logNetwork: false, + resolvers, + initLocalState: localRecord => { + localRecord.setValue(true, "loggedIn"); + }, + }); + await timeout(); + return testRenderer; +}; + +it("renders configure auth", async () => { + const testRenderer = await createTestRenderer(); + expect( + limitSnapshotTo("configure-container", testRenderer.toJSON()) + ).toMatchSnapshot(); +}); + +it("regenerate sso key", async () => { + const testRenderer = await createTestRenderer({ + Mutation: { + regenerateSSOKey: createSinonStub(s => + s.callsFake((_: any, data: any) => { + return { + settings: { + auth: { + integrations: { + sso: { + key: "==GENERATED_KEY==", + keyGeneratedAt: "2018-11-12T23:26:06.239Z", + }, + }, + }, + }, + clientMutationId: data.input.clientMutationId, + }; + }) + ), + }, + }); + testRenderer.root + .find(inputPredicate("auth.integrations.sso.enabled")) + .props.onChange({}); + + testRenderer.root + .find(inputPredicate("configure-auth-sso-regenerate")) + .props.onClick(); + + await timeout(); + + expect( + limitSnapshotTo("configure-auth-sso-key", testRenderer.toJSON()) + ).toMatchSnapshot(); +}); + +it("change settings", async () => { + let settingsRecord = cloneDeep(settings); + const testRenderer = await createTestRenderer({ + Query: { + discoverOIDCConfiguration: createSinonStub(s => + s.callsFake((_: any, data: any) => { + expect(data).toEqual({ issuer: "http://issuer.com" }); + return { + issuer: "http://issuer.com", + tokenURL: "http://issuer.com/tokenURL", + jwksURI: "http://issuer.com/jwksURI", + authorizationURL: "http://issuer.com/authorizationURL", + }; + }) + ), + }, + Mutation: { + updateSettings: createSinonStub(s => + s.callsFake((_: any, data: any) => { + expect(data.input.settings.auth.integrations.facebook).toEqual({ + enabled: true, + allowRegistration: true, + targetFilter: { + admin: true, + stream: true, + }, + clientID: "myClientID", + clientSecret: "myClientSecret", + }); + settingsRecord = merge(settingsRecord, data.input.settings); + return { + settings: settingsRecord, + clientMutationId: data.input.clientMutationId, + }; + }) + ), + createOIDCAuthIntegration: createSinonStub(s => + s.callsFake((_: any, data: any) => { + expect(data.input.configuration).toEqual({ + enabled: true, + allowRegistration: false, + targetFilter: { + admin: true, + stream: true, + }, + name: "name", + clientID: "clientID", + clientSecret: "clientSecret", + issuer: "http://issuer.com", + jwksURI: "http://issuer.com/jwksURI", + authorizationURL: "http://issuer.com/authorizationURL", + tokenURL: "http://issuer.com/tokenURL", + }); + (settingsRecord.auth.integrations.oidc as any).push({ + id: "generatedID", + enabled: false, + callbackURL: "http://localhost/oidc/callback", + ...data.input.configuration, + }); + return { + settings: settingsRecord, + clientMutationId: data.input.clientMutationId, + }; + }) + ), + updateOIDCAuthIntegration: createSinonStub(s => + s.callsFake((_: any, data: any) => { + expect(data.input.configuration).toEqual({ + enabled: true, + allowRegistration: false, + targetFilter: { + admin: true, + stream: true, + }, + name: "name", + clientID: "clientID", + clientSecret: "clientSecret2", + issuer: "http://issuer.com", + jwksURI: "http://issuer.com/jwksURI", + authorizationURL: "http://issuer.com/authorizationURL", + tokenURL: "http://issuer.com/tokenURL", + }); + (settingsRecord.auth.integrations.oidc[0] as any) = merge( + settingsRecord.auth.integrations.oidc[0], + data.input.configuration + ); + return { + integration: settingsRecord.auth.integrations.oidc[0], + settings: settingsRecord, + clientMutationId: data.input.clientMutationId, + }; + }) + ), + }, + }); + + // Let's change some facebook settings. + testRenderer.root + .find(inputPredicate("auth.integrations.facebook.enabled")) + .props.onChange({}); + testRenderer.root + .find(inputPredicate("auth.integrations.facebook.clientID")) + .props.onChange("myClientID"); + testRenderer.root + .find(inputPredicate("auth.integrations.facebook.clientSecret")) + .props.onChange("myClientSecret"); + expect( + limitSnapshotTo("configure-auth-facebook-container", testRenderer.toJSON()) + ).toMatchSnapshot("enable facebook configure box"); + + // Send form, this will perform creating an initial oidc record and update settings. + testRenderer.root.findByProps({ id: "configure-form" }).props.onSubmit(); + + // Submit button should be disabled. + expect( + testRenderer.root.find(inputPredicate("configure-sideBar-saveChanges")) + .props.disabled + ).toBe(true); + + // Disable other fields while submitting + // We are only testing for one here right now.. + expect( + testRenderer.root.find(inputPredicate("auth.integrations.facebook.enabled")) + .props.disabled + ).toBe(true); + await timeout(); + expect( + testRenderer.root.find(inputPredicate("auth.integrations.facebook.enabled")) + .props.disabled + ).toBe(false); + + // Now let's enable oidc + testRenderer.root + .find(inputPredicate("auth.integrations.oidc.0.enabled")) + .props.onChange({}); + + expect( + limitSnapshotTo("configure-auth-oidc-container-0", testRenderer.toJSON()) + ).toMatchSnapshot("enable oidc configure box"); + + // Try to submit form, this will give validation error messages. + testRenderer.root.findByProps({ id: "configure-form" }).props.onSubmit(); + expect( + limitSnapshotTo("configure-auth-oidc-container-0", testRenderer.toJSON()) + ).toMatchSnapshot("oidc validation errors"); + + // Fill form + testRenderer.root + .find(inputPredicate("auth.integrations.oidc.0.name")) + .props.onChange("name"); + testRenderer.root + .find(inputPredicate("auth.integrations.oidc.0.clientID")) + .props.onChange("clientID"); + testRenderer.root + .find(inputPredicate("auth.integrations.oidc.0.clientSecret")) + .props.onChange("clientSecret"); + testRenderer.root + .find(inputPredicate("auth.integrations.oidc.0.issuer")) + .props.onChange("http://issuer.com"); + + // Discover the rest. + testRenderer.root + .find(inputPredicate("configure-auth-oidc-discover-0")) + .props.onClick(); + await timeout(); + + // Try to submit again, this should work now. + testRenderer.root.findByProps({ id: "configure-form" }).props.onSubmit(); + expect( + limitSnapshotTo("configure-auth-oidc-container-0", testRenderer.toJSON()) + ).toMatchSnapshot("during submit: oidc without errors"); + + // Disable other fields while submitting + // We are only testing for one here right now.. + expect( + testRenderer.root.find(inputPredicate("auth.integrations.oidc.0.enabled")) + .props.disabled + ).toBe(true); + await timeout(); + expect( + testRenderer.root.find(inputPredicate("auth.integrations.oidc.0.enabled")) + .props.disabled + ).toBe(false); + + // Change clientSecret + testRenderer.root + .find(inputPredicate("auth.integrations.oidc.0.clientSecret")) + .props.onChange("clientSecret2"); + + testRenderer.root.findByProps({ id: "configure-form" }).props.onSubmit(); + + // Disable other fields while submitting + // We are only testing for one here right now.. + expect( + testRenderer.root.find(inputPredicate("auth.integrations.oidc.0.enabled")) + .props.disabled + ).toBe(true); + await timeout(); + expect( + testRenderer.root.find(inputPredicate("auth.integrations.oidc.0.enabled")) + .props.disabled + ).toBe(false); +}); diff --git a/src/core/client/admin/test/fixtures.ts b/src/core/client/admin/test/fixtures.ts new file mode 100644 index 000000000..584188b61 --- /dev/null +++ b/src/core/client/admin/test/fixtures.ts @@ -0,0 +1,50 @@ +export const settings = { + auth: { + displayName: { + enabled: false, + }, + integrations: { + oidc: [], + local: { + enabled: false, + allowRegistration: true, + targetFilter: { + admin: true, + stream: true, + }, + }, + sso: { + enabled: false, + allowRegistration: true, + targetFilter: { + admin: true, + stream: true, + }, + key: null, + keyGeneratedAt: null, + }, + google: { + enabled: false, + allowRegistration: true, + targetFilter: { + admin: true, + stream: true, + }, + clientID: "", + clientSecret: "", + callbackURL: "http://localhost/google/callback", + }, + facebook: { + enabled: false, + allowRegistration: true, + targetFilter: { + admin: true, + stream: true, + }, + clientID: "", + clientSecret: "", + callbackURL: "http://localhost/facebook/callback", + }, + }, + }, +}; diff --git a/src/core/client/admin/test/redirectLoggedIn.spec.tsx b/src/core/client/admin/test/redirectLoggedIn.spec.tsx index ef8e345e9..0d0addc8d 100644 --- a/src/core/client/admin/test/redirectLoggedIn.spec.tsx +++ b/src/core/client/admin/test/redirectLoggedIn.spec.tsx @@ -23,9 +23,9 @@ it("redirect to redirectPath when already logged in", async () => { logNetwork: false, initLocalState: localRecord => { localRecord.setValue(true, "loggedIn"); - localRecord.setValue("/admin/configure", "redirectPath"); + localRecord.setValue("/admin/community", "redirectPath"); }, }); await timeout(); - expect(window.location.toString()).toBe("http://localhost/admin/configure"); + expect(window.location.toString()).toBe("http://localhost/admin/community"); }); diff --git a/src/core/client/auth/components/App.tsx b/src/core/client/auth/components/App.tsx index 1cdbe1f76..76096b66b 100644 --- a/src/core/client/auth/components/App.tsx +++ b/src/core/client/auth/components/App.tsx @@ -1,5 +1,5 @@ import React, { StatelessComponent } from "react"; -import * as styles from "./App.css"; +import styles from "./App.css"; import ForgotPasswordContainer from "../containers/ForgotPasswordContainer"; import ResetPasswordContainer from "../containers/ResetPasswordContainer"; diff --git a/src/core/client/auth/test/__snapshots__/navigation.spec.tsx.snap b/src/core/client/auth/test/__snapshots__/navigation.spec.tsx.snap index 248adc0d2..948914ed3 100644 --- a/src/core/client/auth/test/__snapshots__/navigation.spec.tsx.snap +++ b/src/core/client/auth/test/__snapshots__/navigation.spec.tsx.snap @@ -45,7 +45,6 @@ reset your password. disabled={false} onBlur={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -119,7 +118,6 @@ exports[`navigates to sign in form 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -134,7 +132,6 @@ exports[`navigates to sign in form 1`] = ` disabled={false} onBlur={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -158,7 +155,6 @@ exports[`navigates to sign in form 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -276,7 +272,6 @@ exports[`navigates to sign up form 1`] = ` disabled={false} onBlur={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -300,7 +295,6 @@ exports[`navigates to sign up form 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -376,7 +370,6 @@ exports[`renders sign in form 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -391,7 +384,6 @@ exports[`renders sign in form 1`] = ` disabled={false} onBlur={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -415,7 +407,6 @@ exports[`renders sign in form 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} diff --git a/src/core/client/auth/test/__snapshots__/signIn.spec.tsx.snap b/src/core/client/auth/test/__snapshots__/signIn.spec.tsx.snap index 0a1d85bb9..900918a5f 100644 --- a/src/core/client/auth/test/__snapshots__/signIn.spec.tsx.snap +++ b/src/core/client/auth/test/__snapshots__/signIn.spec.tsx.snap @@ -74,7 +74,6 @@ exports[`accepts correct password 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -89,7 +88,6 @@ exports[`accepts correct password 1`] = ` disabled={false} onBlur={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -113,7 +111,6 @@ exports[`accepts correct password 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -202,7 +199,6 @@ exports[`accepts valid email 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -217,7 +213,6 @@ exports[`accepts valid email 1`] = ` disabled={false} onBlur={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -241,7 +236,6 @@ exports[`accepts valid email 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -343,7 +337,6 @@ exports[`checks for invalid email 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -358,7 +351,6 @@ exports[`checks for invalid email 1`] = ` disabled={false} onBlur={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -382,7 +374,6 @@ exports[`checks for invalid email 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -458,7 +449,6 @@ exports[`renders sign in form 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -473,7 +463,6 @@ exports[`renders sign in form 1`] = ` disabled={false} onBlur={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -497,7 +486,6 @@ exports[`renders sign in form 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -599,7 +587,6 @@ exports[`shows error when submitting empty form 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -614,7 +601,6 @@ exports[`shows error when submitting empty form 1`] = ` disabled={false} onBlur={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -638,7 +624,6 @@ exports[`shows error when submitting empty form 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -714,7 +699,6 @@ exports[`shows server error 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -729,7 +713,6 @@ exports[`shows server error 1`] = ` disabled={true} onBlur={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -753,7 +736,6 @@ exports[`shows server error 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -834,7 +816,6 @@ exports[`shows server error 2`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -849,7 +830,6 @@ exports[`shows server error 2`] = ` disabled={false} onBlur={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -873,7 +853,6 @@ exports[`shows server error 2`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -949,7 +928,6 @@ exports[`submits form successfully 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -964,7 +942,6 @@ exports[`submits form successfully 1`] = ` disabled={true} onBlur={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -988,7 +965,6 @@ exports[`submits form successfully 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -1064,7 +1040,6 @@ exports[`submits form successfully 2`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -1079,7 +1054,6 @@ exports[`submits form successfully 2`] = ` disabled={false} onBlur={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -1103,7 +1077,6 @@ exports[`submits form successfully 2`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} diff --git a/src/core/client/auth/test/__snapshots__/signUp.spec.tsx.snap b/src/core/client/auth/test/__snapshots__/signUp.spec.tsx.snap index 812641400..f96885fd9 100644 --- a/src/core/client/auth/test/__snapshots__/signUp.spec.tsx.snap +++ b/src/core/client/auth/test/__snapshots__/signUp.spec.tsx.snap @@ -142,7 +142,6 @@ exports[`accepts correct password 1`] = ` disabled={false} onBlur={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -166,7 +165,6 @@ exports[`accepts correct password 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -336,7 +334,6 @@ exports[`accepts correct password confirmation 1`] = ` disabled={false} onBlur={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -360,7 +357,6 @@ exports[`accepts correct password confirmation 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -517,7 +513,6 @@ exports[`accepts valid email 1`] = ` disabled={false} onBlur={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -541,7 +536,6 @@ exports[`accepts valid email 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -698,7 +692,6 @@ exports[`accepts valid username 1`] = ` disabled={false} onBlur={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -722,7 +715,6 @@ exports[`accepts valid username 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -892,7 +884,6 @@ exports[`checks for invalid characters in username 1`] = ` disabled={false} onBlur={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -916,7 +907,6 @@ exports[`checks for invalid characters in username 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -1086,7 +1076,6 @@ exports[`checks for invalid email 1`] = ` disabled={false} onBlur={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -1110,7 +1099,6 @@ exports[`checks for invalid email 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -1280,7 +1268,6 @@ exports[`checks for too long username 1`] = ` disabled={false} onBlur={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -1304,7 +1291,6 @@ exports[`checks for too long username 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -1474,7 +1460,6 @@ exports[`checks for too short password 1`] = ` disabled={false} onBlur={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -1498,7 +1483,6 @@ exports[`checks for too short password 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -1668,7 +1652,6 @@ exports[`checks for too short username 1`] = ` disabled={false} onBlur={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -1692,7 +1675,6 @@ exports[`checks for too short username 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -1862,7 +1844,6 @@ exports[`checks for wrong password confirmation 1`] = ` disabled={false} onBlur={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -1886,7 +1867,6 @@ exports[`checks for wrong password confirmation 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -2004,7 +1984,6 @@ exports[`renders sign up form 1`] = ` disabled={false} onBlur={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -2028,7 +2007,6 @@ exports[`renders sign up form 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -2198,7 +2176,6 @@ exports[`shows error when submitting empty form 1`] = ` disabled={false} onBlur={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -2222,7 +2199,6 @@ exports[`shows error when submitting empty form 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -2340,7 +2316,6 @@ exports[`shows server error 1`] = ` disabled={true} onBlur={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -2364,7 +2339,6 @@ exports[`shows server error 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -2487,7 +2461,6 @@ exports[`shows server error 2`] = ` disabled={false} onBlur={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -2511,7 +2484,6 @@ exports[`shows server error 2`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -2629,7 +2601,6 @@ exports[`submits form successfully 1`] = ` disabled={true} onBlur={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -2653,7 +2624,6 @@ exports[`submits form successfully 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -2771,7 +2741,6 @@ exports[`submits form successfully 2`] = ` disabled={false} onBlur={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -2795,7 +2764,6 @@ exports[`submits form successfully 2`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} diff --git a/src/core/client/embed/index.html b/src/core/client/embed/index.html index 6498664ed..a686f5f5b 100644 --- a/src/core/client/embed/index.html +++ b/src/core/client/embed/index.html @@ -1,30 +1,31 @@ + + Talk 5.0 – Embed Stream + + + + + - - Talk 5.0 – Embed Stream - - - - - - - -

    - Story | Story With Button -

    -

    Talk 5.0 – Embed Stream

    -
    - - - + +

    + Admin | Story | + Story With Button +

    +

    Talk 5.0 – Embed Stream

    +
    + + diff --git a/src/core/client/embed/story.html b/src/core/client/embed/story.html index c4fd41b00..8cb260365 100644 --- a/src/core/client/embed/story.html +++ b/src/core/client/embed/story.html @@ -1,88 +1,128 @@ + + Talk 5.0 – Embed Stream + + + + + - - Talk 5.0 – Embed Stream - - - - - - - -

    - Default | Story With Button -

    -

    Talk 5.0 – Story

    -

    Dismember a mouse and then regurgitate parts of it on the family room floor. Dont wait for the storm to pass, - dance in the rain stand in front of the computer screen, so stares at human while pushing stuff off a table chew - the plant meow hiss at vacuum cleaner. Terrorize the hundred-and-twenty-pound rottweiler and steal his bed, not - sorry chew the plant. Litter kitter kitty litty little kitten big roar roar feed me rub whiskers on bare skin act - innocent sleep on keyboard, so give me attention or face the wrath of my claws for demand to be let outside at - once, and expect owner to wait for me as i think about it spread kitty litter all over house so nya nya nyan. Catty - ipsum massacre a bird in the living room and then look like the cutest and most innocent animal on the planet you - have cat to be kitten me right meow. Hiss and stare at nothing then run suddenly away refuse to come home when - humans are going to bed; stay out all night then yowl like i am dying at 4am and lick plastic bags. Chase dog then - run away purrr purr littel cat, little cat purr purr and step on your keyboard while you're gaming and then turn in - a circle . Twitch tail in permanent irritation put butt in owner's face and the dog smells bad yet attempt to leap - between furniture but woefully miscalibrate and bellyflop onto the floor; what's your problem? i meant to do that - now i shall wash myself intently. Sniff all the things groom forever, stretch tongue and leave it slightly out, - blep, but bring your owner a dead bird decide to want nothing to do with my owner today for lay on arms while - you're using the keyboard meow meow, i tell my human or scratch. Sleep on my human's head then cats take over the - world bleghbleghvomit my furball really tie the room together sleep more napping, more napping all the napping is - exhausting. When in doubt, wash drink water out of the faucet, cats are fats i like to pets them they like to meow - back and cat dog hate mouse eat string barf pillow no baths hate everything yet swat at dog kitty kitty but you - call this cat food. Cough furball into food bowl then scratch owner for a new one flex claws on the human's belly - and purr like a lawnmower for has closed eyes but still sees you groom yourself 4 hours - checked, have your beauty - sleep 18 hours - checked, be fabulous for the rest of the day - checked. Freak human out make funny noise mow mow - mow mow mow mow success now attack human flex claws on the human's belly and purr like a lawnmower or meowwww. - Terrorize the hundred-and-twenty-pound rottweiler and steal his bed, not sorry paw at your fat belly so yowling - nonstop the whole night small kitty warm kitty little balls of fur or eat owner's food reward the chosen human with - a slow blink. Gate keepers of hell plan steps for world domination for more napping, more napping all the napping - is exhausting give me some of your food give me some of your food give me some of your food meh, i don't want it so - flop over. Make meme, make cute face ears back wide eyed so sit and stare. Dead stare with ears cocked furrier and - even more furrier hairball. Stand in front of the computer screen demand to have some of whatever the human is - cooking, then sniff the offering and walk away for catasstrophe, kitty scratches couch bad kitty. Wack the mini - furry mouse intrigued by the shower, and pooping rainbow while flying in a toasted bread costume in space. - Mesmerizing birds love me! shake treat bag, yet lies down where is my slave? I'm getting hungry so lick face hiss - at owner, pee a lot, and meow repeatedly scratch at fence purrrrrr eat muffins and poutine until owner comes back. - You have cat to be kitten me right meow sniff other cat's butt and hang jaw half open thereafter but run outside as - soon as door open so munch on tasty moths or munch on tasty moths, for paw at beetle and eat it before it gets - away. Sit on human. Gnaw the corn cob massacre a bird in the living room and then look like the cutest and most - innocent animal on the planet for sit on the laptop. Meow scratch leg; meow for can opener to feed me cat fur is - the new black but hide when guests come over, and Gate keepers of hell. Refuse to come home when humans are going - to bed; stay out all night then yowl like i am dying at 4am cat slap dog in face or eat a rug and furry furry hairs - everywhere oh no human coming lie on counter don't get off counter for i like fish sit on human they not getting up - ever but meow meow but cuddle no cuddle cuddle love scratch scratch.

    -

    I show my fluffy belly but it's a trap! if you pet it i will tear up your hand refuse to drink water except out of - someone's glass mice, so cough hairball, eat toilet paper or curl into a furry donut lick sellotape but wack the - mini furry mouse. When owners are asleep, cry for no apparent reason. Chase imaginary bugs. Stinky cat reward the - chosen human with a slow blink, or chase dog then run away. Chew on cable scratch the furniture for you are a - captive audience while sitting on the toilet, pet me for i like cats because they are fat and fluffy and spend all - night ensuring people don't sleep sleep all day. Scoot butt on the rug need to check on human, have not seen in an - hour might be dead oh look, human is alive, hiss at human, feed me, leave fur on owners clothes, so instantly break - out into full speed gallop across the house for no reason play riveting piece on synthesizer keyboard and scoot - butt on the rug yet meow meow. Attack dog, run away and pretend to be victim annoy the old grumpy cat, start a - fight and then retreat to wash when i lose or meow go back to sleep owner brings food and water tries to pet on - head, so scratch get sprayed by water because bad cat. Meowwww pelt around the house and up and down stairs chasing - phantoms drink water out of the faucet meow meow, i tell my human. Destroy couch.

    -

    Ask to go outside and ask to come inside and ask to go outside and ask to come inside the dog smells bad. Lick - butt and make a weird face. Toilet paper attack claws fluff everywhere meow miao french ciao litterbox. Shake treat - bag immediately regret falling into bathtub or white cat sleeps on a black shirt so what a cat-ass-trophy! eat - owner's food spit up on light gray carpet instead of adjacent linoleum. Warm up laptop with butt lick butt fart - rainbows until owner yells pee in litter box hiss at cats scratch the box so loved it, hated it, loved it, hated it - but need to check on human, have not seen in an hour might be dead oh look, human is alive, hiss at human, feed me. -

    -
    - - - + +

    + Admin | Default | + Story With Button +

    +

    Talk 5.0 – Story

    +

    + Dismember a mouse and then regurgitate parts of it on the family room + floor. Dont wait for the storm to pass, dance in the rain stand in front + of the computer screen, so stares at human while pushing stuff off a table + chew the plant meow hiss at vacuum cleaner. Terrorize the + hundred-and-twenty-pound rottweiler and steal his bed, not sorry chew the + plant. Litter kitter kitty litty little kitten big roar roar feed me rub + whiskers on bare skin act innocent sleep on keyboard, so give me attention + or face the wrath of my claws for demand to be let outside at once, and + expect owner to wait for me as i think about it spread kitty litter all + over house so nya nya nyan. Catty ipsum massacre a bird in the living room + and then look like the cutest and most innocent animal on the planet you + have cat to be kitten me right meow. Hiss and stare at nothing then run + suddenly away refuse to come home when humans are going to bed; stay out + all night then yowl like i am dying at 4am and lick plastic bags. Chase + dog then run away purrr purr littel cat, little cat purr purr and step on + your keyboard while you're gaming and then turn in a circle . Twitch tail + in permanent irritation put butt in owner's face and the dog smells bad + yet attempt to leap between furniture but woefully miscalibrate and + bellyflop onto the floor; what's your problem? i meant to do that now i + shall wash myself intently. Sniff all the things groom forever, stretch + tongue and leave it slightly out, blep, but bring your owner a dead bird + decide to want nothing to do with my owner today for lay on arms while + you're using the keyboard meow meow, i tell my human or scratch. Sleep on + my human's head then cats take over the world bleghbleghvomit my furball + really tie the room together sleep more napping, more napping all the + napping is exhausting. When in doubt, wash drink water out of the faucet, + cats are fats i like to pets them they like to meow back and cat dog hate + mouse eat string barf pillow no baths hate everything yet swat at dog + kitty kitty but you call this cat food. Cough furball into food bowl then + scratch owner for a new one flex claws on the human's belly and purr like + a lawnmower for has closed eyes but still sees you groom yourself 4 hours + - checked, have your beauty sleep 18 hours - checked, be fabulous for the + rest of the day - checked. Freak human out make funny noise mow mow mow + mow mow mow success now attack human flex claws on the human's belly and + purr like a lawnmower or meowwww. Terrorize the hundred-and-twenty-pound + rottweiler and steal his bed, not sorry paw at your fat belly so yowling + nonstop the whole night small kitty warm kitty little balls of fur or eat + owner's food reward the chosen human with a slow blink. Gate keepers of + hell plan steps for world domination for more napping, more napping all + the napping is exhausting give me some of your food give me some of your + food give me some of your food meh, i don't want it so flop over. Make + meme, make cute face ears back wide eyed so sit and stare. Dead stare with + ears cocked furrier and even more furrier hairball. Stand in front of the + computer screen demand to have some of whatever the human is cooking, then + sniff the offering and walk away for catasstrophe, kitty scratches couch + bad kitty. Wack the mini furry mouse intrigued by the shower, and pooping + rainbow while flying in a toasted bread costume in space. Mesmerizing + birds love me! shake treat bag, yet lies down where is my slave? I'm + getting hungry so lick face hiss at owner, pee a lot, and meow repeatedly + scratch at fence purrrrrr eat muffins and poutine until owner comes back. + You have cat to be kitten me right meow sniff other cat's butt and hang + jaw half open thereafter but run outside as soon as door open so munch on + tasty moths or munch on tasty moths, for paw at beetle and eat it before + it gets away. Sit on human. Gnaw the corn cob massacre a bird in the + living room and then look like the cutest and most innocent animal on the + planet for sit on the laptop. Meow scratch leg; meow for can opener to + feed me cat fur is the new black but hide when guests come over, and Gate + keepers of hell. Refuse to come home when humans are going to bed; stay + out all night then yowl like i am dying at 4am cat slap dog in face or eat + a rug and furry furry hairs everywhere oh no human coming lie on counter + don't get off counter for i like fish sit on human they not getting up + ever but meow meow but cuddle no cuddle cuddle love scratch scratch. +

    +

    + I show my fluffy belly but it's a trap! if you pet it i will tear up your + hand refuse to drink water except out of someone's glass mice, so cough + hairball, eat toilet paper or curl into a furry donut lick sellotape but + wack the mini furry mouse. When owners are asleep, cry for no apparent + reason. Chase imaginary bugs. Stinky cat reward the chosen human with a + slow blink, or chase dog then run away. Chew on cable scratch the + furniture for you are a captive audience while sitting on the toilet, pet + me for i like cats because they are fat and fluffy and spend all night + ensuring people don't sleep sleep all day. Scoot butt on the rug need to + check on human, have not seen in an hour might be dead oh look, human is + alive, hiss at human, feed me, leave fur on owners clothes, so instantly + break out into full speed gallop across the house for no reason play + riveting piece on synthesizer keyboard and scoot butt on the rug yet meow + meow. Attack dog, run away and pretend to be victim annoy the old grumpy + cat, start a fight and then retreat to wash when i lose or meow go back to + sleep owner brings food and water tries to pet on head, so scratch get + sprayed by water because bad cat. Meowwww pelt around the house and up and + down stairs chasing phantoms drink water out of the faucet meow meow, i + tell my human. Destroy couch. +

    +

    + Ask to go outside and ask to come inside and ask to go outside and ask to + come inside the dog smells bad. Lick butt and make a weird face. Toilet + paper attack claws fluff everywhere meow miao french ciao litterbox. Shake + treat bag immediately regret falling into bathtub or white cat sleeps on a + black shirt so what a cat-ass-trophy! eat owner's food spit up on light + gray carpet instead of adjacent linoleum. Warm up laptop with butt lick + butt fart rainbows until owner yells pee in litter box hiss at cats + scratch the box so loved it, hated it, loved it, hated it but need to + check on human, have not seen in an hour might be dead oh look, human is + alive, hiss at human, feed me. +

    +
    + + diff --git a/src/core/client/embed/storyButton.html b/src/core/client/embed/storyButton.html index 95dd556de..83bb011e2 100644 --- a/src/core/client/embed/storyButton.html +++ b/src/core/client/embed/storyButton.html @@ -1,103 +1,140 @@ + + Talk 5.0 – Embed Stream + + + + + - - Talk 5.0 – Embed Stream - - - - - + +

    + Admin | Default | + Story +

    +

    Talk 5.0 – Story with Button

    +

    + Dismember a mouse and then regurgitate parts of it on the family room + floor. Dont wait for the storm to pass, dance in the rain stand in front + of the computer screen, so stares at human while pushing stuff off a table + chew the plant meow hiss at vacuum cleaner. Terrorize the + hundred-and-twenty-pound rottweiler and steal his bed, not sorry chew the + plant. Litter kitter kitty litty little kitten big roar roar feed me rub + whiskers on bare skin act innocent sleep on keyboard, so give me attention + or face the wrath of my claws for demand to be let outside at once, and + expect owner to wait for me as i think about it spread kitty litter all + over house so nya nya nyan. Catty ipsum massacre a bird in the living room + and then look like the cutest and most innocent animal on the planet you + have cat to be kitten me right meow. Hiss and stare at nothing then run + suddenly away refuse to come home when humans are going to bed; stay out + all night then yowl like i am dying at 4am and lick plastic bags. Chase + dog then run away purrr purr littel cat, little cat purr purr and step on + your keyboard while you're gaming and then turn in a circle . Twitch tail + in permanent irritation put butt in owner's face and the dog smells bad + yet attempt to leap between furniture but woefully miscalibrate and + bellyflop onto the floor; what's your problem? i meant to do that now i + shall wash myself intently. Sniff all the things groom forever, stretch + tongue and leave it slightly out, blep, but bring your owner a dead bird + decide to want nothing to do with my owner today for lay on arms while + you're using the keyboard meow meow, i tell my human or scratch. Sleep on + my human's head then cats take over the world bleghbleghvomit my furball + really tie the room together sleep more napping, more napping all the + napping is exhausting. When in doubt, wash drink water out of the faucet, + cats are fats i like to pets them they like to meow back and cat dog hate + mouse eat string barf pillow no baths hate everything yet swat at dog + kitty kitty but you call this cat food. Cough furball into food bowl then + scratch owner for a new one flex claws on the human's belly and purr like + a lawnmower for has closed eyes but still sees you groom yourself 4 hours + - checked, have your beauty sleep 18 hours - checked, be fabulous for the + rest of the day - checked. Freak human out make funny noise mow mow mow + mow mow mow success now attack human flex claws on the human's belly and + purr like a lawnmower or meowwww. Terrorize the hundred-and-twenty-pound + rottweiler and steal his bed, not sorry paw at your fat belly so yowling + nonstop the whole night small kitty warm kitty little balls of fur or eat + owner's food reward the chosen human with a slow blink. Gate keepers of + hell plan steps for world domination for more napping, more napping all + the napping is exhausting give me some of your food give me some of your + food give me some of your food meh, i don't want it so flop over. Make + meme, make cute face ears back wide eyed so sit and stare. Dead stare with + ears cocked furrier and even more furrier hairball. Stand in front of the + computer screen demand to have some of whatever the human is cooking, then + sniff the offering and walk away for catasstrophe, kitty scratches couch + bad kitty. Wack the mini furry mouse intrigued by the shower, and pooping + rainbow while flying in a toasted bread costume in space. Mesmerizing + birds love me! shake treat bag, yet lies down where is my slave? I'm + getting hungry so lick face hiss at owner, pee a lot, and meow repeatedly + scratch at fence purrrrrr eat muffins and poutine until owner comes back. + You have cat to be kitten me right meow sniff other cat's butt and hang + jaw half open thereafter but run outside as soon as door open so munch on + tasty moths or munch on tasty moths, for paw at beetle and eat it before + it gets away. Sit on human. Gnaw the corn cob massacre a bird in the + living room and then look like the cutest and most innocent animal on the + planet for sit on the laptop. Meow scratch leg; meow for can opener to + feed me cat fur is the new black but hide when guests come over, and Gate + keepers of hell. Refuse to come home when humans are going to bed; stay + out all night then yowl like i am dying at 4am cat slap dog in face or eat + a rug and furry furry hairs everywhere oh no human coming lie on counter + don't get off counter for i like fish sit on human they not getting up + ever but meow meow but cuddle no cuddle cuddle love scratch scratch. +

    +

    + I show my fluffy belly but it's a trap! if you pet it i will tear up your + hand refuse to drink water except out of someone's glass mice, so cough + hairball, eat toilet paper or curl into a furry donut lick sellotape but + wack the mini furry mouse. When owners are asleep, cry for no apparent + reason. Chase imaginary bugs. Stinky cat reward the chosen human with a + slow blink, or chase dog then run away. Chew on cable scratch the + furniture for you are a captive audience while sitting on the toilet, pet + me for i like cats because they are fat and fluffy and spend all night + ensuring people don't sleep sleep all day. Scoot butt on the rug need to + check on human, have not seen in an hour might be dead oh look, human is + alive, hiss at human, feed me, leave fur on owners clothes, so instantly + break out into full speed gallop across the house for no reason play + riveting piece on synthesizer keyboard and scoot butt on the rug yet meow + meow. Attack dog, run away and pretend to be victim annoy the old grumpy + cat, start a fight and then retreat to wash when i lose or meow go back to + sleep owner brings food and water tries to pet on head, so scratch get + sprayed by water because bad cat. Meowwww pelt around the house and up and + down stairs chasing phantoms drink water out of the faucet meow meow, i + tell my human. Destroy couch. +

    +

    + Ask to go outside and ask to come inside and ask to go outside and ask to + come inside the dog smells bad. Lick butt and make a weird face. Toilet + paper attack claws fluff everywhere meow miao french ciao litterbox. Shake + treat bag immediately regret falling into bathtub or white cat sleeps on a + black shirt so what a cat-ass-trophy! eat owner's food spit up on light + gray carpet instead of adjacent linoleum. Warm up laptop with butt lick + butt fart rainbows until owner yells pee in litter box hiss at cats + scratch the box so loved it, hated it, loved it, hated it but need to + check on human, have not seen in an hour might be dead oh look, human is + alive, hiss at human, feed me. +

    +
    +
    + +
    + - + const showStreamEmbed = () => { + TalkStreamEmbed.render(); + button.parentElement.removeChild(button); + }; + button.onclick = showStreamEmbed; + TalkStreamEmbed.on("showPermalink", showStreamEmbed); + + diff --git a/src/core/client/framework/components/CopyButton/CopyButton.tsx b/src/core/client/framework/components/CopyButton/CopyButton.tsx new file mode 100644 index 000000000..d23e664c8 --- /dev/null +++ b/src/core/client/framework/components/CopyButton/CopyButton.tsx @@ -0,0 +1,62 @@ +import { Localized } from "fluent-react/compat"; +import React from "react"; +import CopyToClipboard from "react-copy-to-clipboard"; + +import { Button } from "talk-ui/components"; +import { PropTypesOf } from "talk-ui/types"; + +interface InnerProps extends PropTypesOf { + text: string; +} + +interface State { + copied: boolean; +} + +class PermalinkPopover extends React.Component { + private timeout: any = null; + + public state: State = { + copied: false, + }; + + public componentWillUnmount() { + clearTimeout(this.timeout); + } + + private handleCopy = () => { + this.setCopied(true); + clearTimeout(this.timeout); + this.timeout = setTimeout(() => { + this.setCopied(false); + }, 500); + }; + + private setCopied = (b: boolean) => { + this.setState({ + copied: b, + }); + }; + + public render() { + const { text, ...rest } = this.props; + const { copied } = this.state; + return ( + + + + ); + } +} + +export default PermalinkPopover; diff --git a/src/core/client/framework/components/CopyButton/index.ts b/src/core/client/framework/components/CopyButton/index.ts new file mode 100644 index 000000000..a58fe3206 --- /dev/null +++ b/src/core/client/framework/components/CopyButton/index.ts @@ -0,0 +1 @@ +export { default } from "./CopyButton"; diff --git a/src/core/client/framework/components/index.ts b/src/core/client/framework/components/index.ts new file mode 100644 index 000000000..087db8cd4 --- /dev/null +++ b/src/core/client/framework/components/index.ts @@ -0,0 +1 @@ +export { default as CopyButton } from "./CopyButton"; diff --git a/src/core/client/framework/helpers/createContextHOC.tsx b/src/core/client/framework/helpers/createContextHOC.tsx new file mode 100644 index 000000000..fd3f10e41 --- /dev/null +++ b/src/core/client/framework/helpers/createContextHOC.tsx @@ -0,0 +1,36 @@ +import * as React from "react"; +import { + hoistStatics, + InferableComponentEnhancer, + wrapDisplayName, +} from "recompose"; + +/** + * withContext is a HOC wrapper around `TalkContextConsumer`. + * `propsCallback` must be provided which accepts the `TalkContext` + * and returns the props the should be injected. + */ +function createContextHOC( + displayName: string, + Consumer: React.ComponentType> +) { + return function withContext( + propsCallback: (context: Context) => T + ): InferableComponentEnhancer { + return hoistStatics( + (WrappedComponent: React.ComponentType) => { + const Component: React.StatelessComponent = props => ( + + {context => ( + + )} + + ); + Component.displayName = wrapDisplayName(WrappedComponent, displayName); + return Component; + } + ); + }; +} + +export default createContextHOC; diff --git a/src/core/client/framework/helpers/index.ts b/src/core/client/framework/helpers/index.ts index 583e3e3ad..68a105148 100644 --- a/src/core/client/framework/helpers/index.ts +++ b/src/core/client/framework/helpers/index.ts @@ -2,3 +2,4 @@ export { default as getMe } from "./getMe"; export { default as getMeSourceID } from "./getMeSourceID"; export { default as getURLWithCommentID } from "./getURLWithCommentID"; export { default as urls } from "./urls"; +export { default as createContextHOC } from "./createContextHOC"; diff --git a/src/core/client/framework/helpers/urls.tsx b/src/core/client/framework/helpers/urls.tsx index c57435d04..c2e99fe39 100644 --- a/src/core/client/framework/helpers/urls.tsx +++ b/src/core/client/framework/helpers/urls.tsx @@ -7,7 +7,7 @@ export default (process.env.NODE_ENV !== "development" }, } : { - admin: "/admin.html", + admin: "/admin", embed: { stream: "/stream.html", auth: "/auth.html", diff --git a/src/core/client/framework/lib/bootstrap/withContext.tsx b/src/core/client/framework/lib/bootstrap/withContext.tsx index 677da236a..fe4e43c5f 100644 --- a/src/core/client/framework/lib/bootstrap/withContext.tsx +++ b/src/core/client/framework/lib/bootstrap/withContext.tsx @@ -1,33 +1,9 @@ -import * as React from "react"; -import { - hoistStatics, - InferableComponentEnhancer, - wrapDisplayName, -} from "recompose"; - +import { createContextHOC } from "talk-framework/helpers"; import { TalkContext, TalkContextConsumer } from "./TalkContext"; -/** - * withContext is a HOC wrapper around `TalkContextConsumer`. - * `propsCallback` must be provided which accepts the `TalkContext` - * and returns the props the should be injected. - */ -function withContext( - propsCallback: (context: TalkContext) => T -): InferableComponentEnhancer { - return hoistStatics( - (WrappedComponent: React.ComponentType) => { - const Component: React.StatelessComponent = props => ( - - {context => ( - - )} - - ); - Component.displayName = wrapDisplayName(WrappedComponent, "withContext"); - return Component; - } - ); -} +const withContext = createContextHOC( + "withContext", + TalkContextConsumer +); export default withContext; diff --git a/src/core/client/framework/lib/i18n/getMessage.ts b/src/core/client/framework/lib/i18n/getMessage.ts new file mode 100644 index 000000000..3966a3ce9 --- /dev/null +++ b/src/core/client/framework/lib/i18n/getMessage.ts @@ -0,0 +1,17 @@ +import { FluentBundle } from "fluent/compat"; + +export default function getMessage( + bundles: FluentBundle[], + key: string, + defaultTo = "" +): string { + const res = bundles.reduce((val, bundle) => { + const got = bundle.getMessage(key); + if (!got && process.env.NODE_ENV !== "production") { + // tslint:disable-next-line:no-console + console.warn(`Translation ${key} was not found for ${bundle.locales}`); + } + return val || got; + }, ""); + return res || defaultTo; +} diff --git a/src/core/client/framework/lib/i18n/index.ts b/src/core/client/framework/lib/i18n/index.ts index 98ef23eec..efe1aa4e6 100644 --- a/src/core/client/framework/lib/i18n/index.ts +++ b/src/core/client/framework/lib/i18n/index.ts @@ -1,3 +1,4 @@ export { default as generateBundles } from "./generateBundles"; export { default as negotiateLanguages } from "./negotiateLanguages"; export { BundledLocales, LoadableLocales, LocalesData } from "./locales"; +export { default as getMessage } from "./getMessage"; diff --git a/src/core/client/framework/lib/relay/commitMutationPromise.ts b/src/core/client/framework/lib/relay/commitMutationPromise.ts index b94fd7dde..35f1ca117 100644 --- a/src/core/client/framework/lib/relay/commitMutationPromise.ts +++ b/src/core/client/framework/lib/relay/commitMutationPromise.ts @@ -3,6 +3,8 @@ import { Environment, MutationConfig, OperationBase } from "relay-runtime"; import { Omit } from "talk-framework/types"; +import extractPayload from "./extractPayload"; + /** * Like `MutationConfig` but omits `onCompleted` and `onError` * because we are going to use a Promise API. @@ -12,15 +14,6 @@ export type MutationPromiseConfig = Omit< "onCompleted" | "onError" >; -// Extract the payload from the response, -function getPayload(response: { [key: string]: any }): any { - const keys = Object.keys(response); - if (keys.length !== 1) { - return response; - } - return response[keys[0]]; -} - /** * Normalizes response and error from `commitMutationPromise`. * Meaning `response` will directly contain the payload @@ -33,7 +26,7 @@ export async function commitMutationPromiseNormalized( ): Promise { try { const response = await commitMutationPromise(environment, config); - return getPayload(response); + return extractPayload(response); } catch (e) { throw e; } @@ -57,7 +50,7 @@ export function commitMutationPromise( reject(errors); return; } - resolve(getPayload(response)); + resolve(extractPayload(response)); }, onError: error => { reject(error); diff --git a/src/core/client/framework/lib/relay/createFetchContainer.tsx b/src/core/client/framework/lib/relay/createFetchContainer.tsx new file mode 100644 index 000000000..789d4e6a2 --- /dev/null +++ b/src/core/client/framework/lib/relay/createFetchContainer.tsx @@ -0,0 +1,56 @@ +import * as React from "react"; +import { + compose, + hoistStatics, + InferableComponentEnhancer, + wrapDisplayName, +} from "recompose"; +import { Environment } from "relay-runtime"; + +import { TalkContext, withContext } from "../bootstrap"; + +/** + * createFetchContainer creates a HOC that + * injects a property with the name specified in `propName` + * and the signature (input: I) => Promise. Calling + * this will start a one off query. + */ +function createFetchContainer( + propName: T, + fetch: ( + environment: Environment, + variables: V, + context: TalkContext + ) => Promise +): InferableComponentEnhancer<{ [P in T]: (variables: V) => Promise }> { + return compose( + withContext(context => ({ context })), + hoistStatics((BaseComponent: React.ComponentType) => { + class CreateFetchContainer extends React.Component { + public static displayName = wrapDisplayName( + BaseComponent, + "createFetchContainer" + ); + + private fetch = (variables: V) => { + return fetch( + this.props.context.relayEnvironment, + variables, + this.props.context + ); + }; + + public render() { + const { context: _, ...rest } = this.props; + const inject = { + [propName]: this.fetch, + }; + return ; + } + } + return CreateFetchContainer as React.ComponentType; + }) + ); +} + +export default createFetchContainer; diff --git a/src/core/client/framework/lib/relay/extractPayload.ts b/src/core/client/framework/lib/relay/extractPayload.ts new file mode 100644 index 000000000..f419fdd61 --- /dev/null +++ b/src/core/client/framework/lib/relay/extractPayload.ts @@ -0,0 +1,8 @@ +// Extract the payload from the response, +export default function extractPayload(response: { [key: string]: any }): any { + const keys = Object.keys(response); + if (keys.length !== 1) { + return response; + } + return response[keys[0]]; +} diff --git a/src/core/client/framework/lib/relay/fetchQuery.ts b/src/core/client/framework/lib/relay/fetchQuery.ts new file mode 100644 index 000000000..c94e826a0 --- /dev/null +++ b/src/core/client/framework/lib/relay/fetchQuery.ts @@ -0,0 +1,24 @@ +import { fetchQuery as relayFetchQuery } from "react-relay"; +import { + CacheConfig, + Environment, + GraphQLTaggedNode, + Variables, +} from "relay-runtime"; + +import extractPayload from "./extractPayload"; + +export default async function fetchQuery( + environment: Environment, + taggedNode: GraphQLTaggedNode, + variables: Variables, + cacheConfig?: CacheConfig +): Promise { + const result = await relayFetchQuery( + environment, + taggedNode, + variables, + cacheConfig + ); + return extractPayload(result); +} diff --git a/src/core/client/framework/lib/relay/index.ts b/src/core/client/framework/lib/relay/index.ts index 998d9af3b..b97cd6381 100644 --- a/src/core/client/framework/lib/relay/index.ts +++ b/src/core/client/framework/lib/relay/index.ts @@ -6,6 +6,7 @@ export * from "./withLocalStateContainer"; export { default as QueryRenderer } from "./QueryRenderer"; export * from "./QueryRenderer"; export { default as createMutationContainer } from "./createMutationContainer"; +export { default as createFetchContainer } from "./createFetchContainer"; export { default as createAndRetain } from "./createAndRetain"; export { default as wrapFetchWithLogger } from "./wrapFetchWithLogger"; export { @@ -17,3 +18,4 @@ export { default as commitLocalUpdatePromisified, } from "./commitLocalUpdatePromisified"; export { initLocalBaseState, setAuthTokenInLocalState } from "./localState"; +export { default as fetchQuery } from "./fetchQuery"; diff --git a/src/core/client/framework/lib/validation.tsx b/src/core/client/framework/lib/validation.tsx index 58153f1fc..9c7840664 100644 --- a/src/core/client/framework/lib/validation.tsx +++ b/src/core/client/framework/lib/validation.tsx @@ -10,7 +10,7 @@ import { VALIDATION_REQUIRED, } from "./messages"; -type Validator = (v: T, values: V) => ReactNode; +export type Validator = (v: T, values: V) => ReactNode; /** * createValidator returns a Validator that returns given `error` when `condition` is falsey. @@ -62,7 +62,7 @@ export const validateUsernameCharacters = createValidator( */ export const validateURL = createValidator( v => - /^(http:\/\/www\.|https:\/\/www\.|http:\/\/|https:\/\/)[a-z0-9]+([\-\.]{1}[a-z0-9]+)*\.[a-z]{2,5}(:[0-9]{1,5})?(\/.*)?$/.test( + /^(http:\/\/www\.|https:\/\/www\.|http:\/\/|https:\/\/)[a-zA-Z0-9]+([\-\.]{1}[a-zA-Z0-9]+)*\.[a-zA-Z]{2,5}(:[0-9]{1,5})?(\/.*)?$/.test( v ), INVALID_URL() diff --git a/src/core/client/framework/testHelpers/index.ts b/src/core/client/framework/testHelpers/index.ts index 9547b9c49..c9b807f90 100644 --- a/src/core/client/framework/testHelpers/index.ts +++ b/src/core/client/framework/testHelpers/index.ts @@ -11,3 +11,5 @@ export { export { default as createUUIDGenerator } from "./createUUIDGenerator"; export * from "./denormalize"; export { default as replaceHistoryLocation } from "./replaceHistoryLocation"; +export { default as limitSnapshotTo } from "./limitSnapshotTo"; +export { default as inputPredicate } from "./inputPredicate"; diff --git a/src/core/client/framework/testHelpers/inputPredicate.ts b/src/core/client/framework/testHelpers/inputPredicate.ts new file mode 100644 index 000000000..a35c38b73 --- /dev/null +++ b/src/core/client/framework/testHelpers/inputPredicate.ts @@ -0,0 +1,10 @@ +import { ReactTestInstance } from "react-test-renderer"; + +const inputPredicate = (nameOrID: string) => (n: ReactTestInstance) => { + return ( + [n.props.name, n.props.id].indexOf(nameOrID) > -1 && + ["input", "button"].indexOf(n.type) > -1 + ); +}; + +export default inputPredicate; diff --git a/src/core/client/framework/testHelpers/limitSnapshotTo.ts b/src/core/client/framework/testHelpers/limitSnapshotTo.ts new file mode 100644 index 000000000..e09031d66 --- /dev/null +++ b/src/core/client/framework/testHelpers/limitSnapshotTo.ts @@ -0,0 +1,14 @@ +export default function limitSnapshotTo(id: string, node: any) { + if (node.props && node.props.id === id) { + return node; + } + if (node.children) { + for (const child of node.children) { + const result: any = limitSnapshotTo(id, child); + if (result) { + return result; + } + } + } + return ""; +} diff --git a/src/core/client/install/components/App.tsx b/src/core/client/install/components/App.tsx index 7a118c841..f98add230 100644 --- a/src/core/client/install/components/App.tsx +++ b/src/core/client/install/components/App.tsx @@ -1,5 +1,5 @@ import React, { Component } from "react"; -import * as styles from "./App.css"; +import styles from "./App.css"; import WizardContainer from "../containers/WizardContainer"; import MainBar from "./MainBar"; diff --git a/src/core/client/install/components/Header.tsx b/src/core/client/install/components/Header.tsx index 0fa1e2632..75c715e40 100644 --- a/src/core/client/install/components/Header.tsx +++ b/src/core/client/install/components/Header.tsx @@ -4,7 +4,7 @@ import React, { StatelessComponent } from "react"; import { Flex, Typography } from "talk-ui/components"; -import * as styles from "./Header.css"; +import styles from "./Header.css"; interface HeaderProps { main?: boolean; diff --git a/src/core/client/install/components/MainBar.tsx b/src/core/client/install/components/MainBar.tsx index 5a68d98c5..01db8d346 100644 --- a/src/core/client/install/components/MainBar.tsx +++ b/src/core/client/install/components/MainBar.tsx @@ -2,7 +2,7 @@ import React from "react"; import { Typography } from "talk-ui/components"; -import * as styles from "./MainBar.css"; +import styles from "./MainBar.css"; const MainBar = () => { return ( diff --git a/src/core/client/install/components/Wizard.tsx b/src/core/client/install/components/Wizard.tsx index 3be114509..9e8c5e6ec 100644 --- a/src/core/client/install/components/Wizard.tsx +++ b/src/core/client/install/components/Wizard.tsx @@ -6,7 +6,7 @@ import { Step, StepBar } from "talk-ui/components"; import { WizardProps } from "../components/Wizard"; import Header from "./Header"; -import * as styles from "./Wizard.css"; +import styles from "./Wizard.css"; export interface WizardProps { currentStep: number; diff --git a/src/core/client/stream/components/App.tsx b/src/core/client/stream/components/App.tsx index e1b6916f2..3a117512e 100644 --- a/src/core/client/stream/components/App.tsx +++ b/src/core/client/stream/components/App.tsx @@ -5,7 +5,7 @@ import { HorizontalGutter, TabContent, TabPane } from "talk-ui/components"; import CommentsPaneContainer from "../tabs/comments/containers/CommentsPaneContainer"; import ProfileQuery from "../tabs/profile/queries/ProfileQuery"; -import * as styles from "./App.css"; +import styles from "./App.css"; type TabValue = "COMMENTS" | "PROFILE" | "%future added value"; diff --git a/src/core/client/stream/components/Timestamp.tsx b/src/core/client/stream/components/Timestamp.tsx index e6228416f..8c982744f 100644 --- a/src/core/client/stream/components/Timestamp.tsx +++ b/src/core/client/stream/components/Timestamp.tsx @@ -3,7 +3,7 @@ import { StatelessComponent } from "react"; import { RelativeTime } from "talk-ui/components"; -import * as styles from "./Timestamp.css"; +import styles from "./Timestamp.css"; export interface TimestampProps { children: string; diff --git a/src/core/client/stream/components/UserBoxUnauthenticated.tsx b/src/core/client/stream/components/UserBoxUnauthenticated.tsx index 44c9cd246..013a10fc7 100644 --- a/src/core/client/stream/components/UserBoxUnauthenticated.tsx +++ b/src/core/client/stream/components/UserBoxUnauthenticated.tsx @@ -4,7 +4,7 @@ import React, { StatelessComponent } from "react"; import { Button, Flex, Typography } from "talk-ui/components"; import MatchMedia from "talk-ui/components/MatchMedia"; -import * as styles from "./UserBoxUnauthenticated.css"; +import styles from "./UserBoxUnauthenticated.css"; export interface UserBoxUnauthenticatedProps { onSignIn: () => void; diff --git a/src/core/client/stream/listeners/OnPostMessageSetAuthToken.spec.tsx b/src/core/client/stream/listeners/OnPostMessageSetAuthToken.spec.tsx index da2eb5816..290d917e6 100644 --- a/src/core/client/stream/listeners/OnPostMessageSetAuthToken.spec.tsx +++ b/src/core/client/stream/listeners/OnPostMessageSetAuthToken.spec.tsx @@ -20,7 +20,18 @@ beforeAll(() => { }); it("Sets auth token", () => { - const token = "auth-token"; + const token = `${btoa( + JSON.stringify({ + alg: "HS256", + typ: "JWT", + }) + )}.${btoa( + JSON.stringify({ + exp: 1540503165, + jti: "31b26591-4e9a-4388-a7ff-e1bdc5d97cce", + }) + )}`; + const context: Partial = { postMessage: { on: (name: string, cb: (token: string) => void) => { diff --git a/src/core/client/stream/mutations/RemoveCommentReactionMutation.ts b/src/core/client/stream/mutations/RemoveCommentReactionMutation.ts index 1ed7a0de4..5a5a87804 100644 --- a/src/core/client/stream/mutations/RemoveCommentReactionMutation.ts +++ b/src/core/client/stream/mutations/RemoveCommentReactionMutation.ts @@ -20,7 +20,7 @@ const mutation = graphql` } `; -const clientMutationId = 0; +let clientMutationId = 0; function commit(environment: Environment, input: CreateCommentReactionInput) { const source = environment.getStore().getSource(); @@ -32,7 +32,7 @@ function commit(environment: Environment, input: CreateCommentReactionInput) { variables: { input: { ...input, - clientMutationId: clientMutationId.toString(), + clientMutationId: (clientMutationId++).toString(), }, }, optimisticResponse: { diff --git a/src/core/client/stream/tabs/comments/components/Comment/Comment.tsx b/src/core/client/stream/tabs/comments/components/Comment/Comment.tsx index ad463b581..034621611 100644 --- a/src/core/client/stream/tabs/comments/components/Comment/Comment.tsx +++ b/src/core/client/stream/tabs/comments/components/Comment/Comment.tsx @@ -5,7 +5,7 @@ import HTMLContent from "talk-stream/components/HTMLContent"; import Timestamp from "talk-stream/components/Timestamp"; import { Flex, HorizontalGutter } from "talk-ui/components"; -import * as styles from "./Comment.css"; +import styles from "./Comment.css"; import EditedMarker from "./EditedMarker"; import InReplyTo from "./InReplyTo"; import TopBarLeft from "./TopBarLeft"; diff --git a/src/core/client/stream/tabs/comments/components/Comment/IndentedComment.tsx b/src/core/client/stream/tabs/comments/components/Comment/IndentedComment.tsx index 157689517..30be393aa 100644 --- a/src/core/client/stream/tabs/comments/components/Comment/IndentedComment.tsx +++ b/src/core/client/stream/tabs/comments/components/Comment/IndentedComment.tsx @@ -5,7 +5,7 @@ import { PropTypesOf } from "talk-framework/types"; import Indent from "../Indent"; import Comment from "./Comment"; -import * as styles from "./IndentedComment.css"; +import styles from "./IndentedComment.css"; export interface IndentedCommentProps extends PropTypesOf { indentLevel?: number; diff --git a/src/core/client/stream/tabs/comments/components/Comment/Username.tsx b/src/core/client/stream/tabs/comments/components/Comment/Username.tsx index 728944ea2..ac8899b77 100644 --- a/src/core/client/stream/tabs/comments/components/Comment/Username.tsx +++ b/src/core/client/stream/tabs/comments/components/Comment/Username.tsx @@ -3,7 +3,7 @@ import { StatelessComponent } from "react"; import { MatchMedia, Typography } from "talk-ui/components"; -import * as styles from "./Username.css"; +import styles from "./Username.css"; export interface UsernameProps { children: string; diff --git a/src/core/client/stream/tabs/comments/components/ConversationThread.tsx b/src/core/client/stream/tabs/comments/components/ConversationThread.tsx index c786edac9..2ea994816 100644 --- a/src/core/client/stream/tabs/comments/components/ConversationThread.tsx +++ b/src/core/client/stream/tabs/comments/components/ConversationThread.tsx @@ -8,7 +8,7 @@ import { Button, Flex, HorizontalGutter } from "talk-ui/components"; import CommentContainer from "../containers/CommentContainer"; import LocalReplyListContainer from "../containers/LocalReplyListContainer"; import { RootParent } from "./Comment"; -import * as styles from "./ConversationThread.css"; +import styles from "./ConversationThread.css"; import Counter from "./Counter"; import { Circle, Line } from "./Timeline"; diff --git a/src/core/client/stream/tabs/comments/components/Counter.tsx b/src/core/client/stream/tabs/comments/components/Counter.tsx index bcf64e0cf..fc8eef709 100644 --- a/src/core/client/stream/tabs/comments/components/Counter.tsx +++ b/src/core/client/stream/tabs/comments/components/Counter.tsx @@ -1,7 +1,7 @@ import cn from "classnames"; import React, { StatelessComponent } from "react"; -import * as styles from "./Counter.css"; +import styles from "./Counter.css"; interface Props { className?: string; diff --git a/src/core/client/stream/tabs/comments/components/Indent.tsx b/src/core/client/stream/tabs/comments/components/Indent.tsx index 81a418d63..cc63be62b 100644 --- a/src/core/client/stream/tabs/comments/components/Indent.tsx +++ b/src/core/client/stream/tabs/comments/components/Indent.tsx @@ -1,7 +1,7 @@ import cn from "classnames"; import React, { StatelessComponent } from "react"; -import * as styles from "./Indent.css"; +import styles from "./Indent.css"; export interface IndentProps { className?: string; diff --git a/src/core/client/stream/tabs/comments/components/PermalinkButton/PermalinkButton.tsx b/src/core/client/stream/tabs/comments/components/PermalinkButton/PermalinkButton.tsx index 1b34a1e6c..e981dac55 100644 --- a/src/core/client/stream/tabs/comments/components/PermalinkButton/PermalinkButton.tsx +++ b/src/core/client/stream/tabs/comments/components/PermalinkButton/PermalinkButton.tsx @@ -10,7 +10,7 @@ import { Popover, } from "talk-ui/components"; -import * as styles from "./PermalinkButton.css"; +import styles from "./PermalinkButton.css"; import PermalinkPopover from "./PermalinkPopover"; interface PermalinkProps { @@ -42,10 +42,7 @@ class Permalink extends React.Component { this.toggleVisibilityOncePerFrame(toggleVisibility) } > - + )} > diff --git a/src/core/client/stream/tabs/comments/components/PermalinkButton/PermalinkPopover.tsx b/src/core/client/stream/tabs/comments/components/PermalinkButton/PermalinkPopover.tsx index 9e7afcc9d..378edf238 100644 --- a/src/core/client/stream/tabs/comments/components/PermalinkButton/PermalinkPopover.tsx +++ b/src/core/client/stream/tabs/comments/components/PermalinkButton/PermalinkPopover.tsx @@ -1,41 +1,17 @@ -import { Localized } from "fluent-react/compat"; import React from "react"; -import CopyToClipboard from "react-copy-to-clipboard"; -import { Button, Flex, TextField } from "talk-ui/components"; +import { CopyButton } from "talk-framework/components"; +import { Flex, TextField } from "talk-ui/components"; -import * as styles from "./PermalinkPopover.css"; +import styles from "./PermalinkPopover.css"; interface InnerProps { permalinkURL: string; - toggleVisibility: () => void; -} - -interface State { - copied: boolean; } class PermalinkPopover extends React.Component { - public state: State = { - copied: false, - }; - - private onCopy = async () => { - await this.toggleCopied(); - setTimeout(() => { - this.toggleCopied(); - }, 800); - }; - - private toggleCopied = () => { - this.setState((state: State) => ({ - copied: !state.copied, - })); - }; - public render() { const { permalinkURL } = this.props; - const { copied } = this.state; return ( { className={styles.textField} readOnly /> - - - + ); } diff --git a/src/core/client/stream/tabs/comments/components/PermalinkView.tsx b/src/core/client/stream/tabs/comments/components/PermalinkView.tsx index ca4a87809..469f14027 100644 --- a/src/core/client/stream/tabs/comments/components/PermalinkView.tsx +++ b/src/core/client/stream/tabs/comments/components/PermalinkView.tsx @@ -7,7 +7,7 @@ import { Button, Flex, HorizontalGutter, Typography } from "talk-ui/components"; import UserBoxContainer from "../../../containers/UserBoxContainer"; import ConversationThreadContainer from "../containers/ConversationThreadContainer"; import ReplyListContainer from "../containers/ReplyListContainer"; -import * as styles from "./PermalinkView.css"; +import styles from "./PermalinkView.css"; export interface PermalinkViewProps { me: PropTypesOf["me"] & diff --git a/src/core/client/stream/tabs/comments/components/PostCommentForm.tsx b/src/core/client/stream/tabs/comments/components/PostCommentForm.tsx index 5772271e6..ea24917f3 100644 --- a/src/core/client/stream/tabs/comments/components/PostCommentForm.tsx +++ b/src/core/client/stream/tabs/comments/components/PostCommentForm.tsx @@ -13,7 +13,7 @@ import { Typography, } from "talk-ui/components"; -import * as styles from "./PostCommentForm.css"; +import styles from "./PostCommentForm.css"; import PoweredBy from "./PoweredBy"; import RTE from "./RTE"; diff --git a/src/core/client/stream/tabs/comments/components/PostCommentFormFake.tsx b/src/core/client/stream/tabs/comments/components/PostCommentFormFake.tsx index 4f755a519..cdf51d046 100644 --- a/src/core/client/stream/tabs/comments/components/PostCommentFormFake.tsx +++ b/src/core/client/stream/tabs/comments/components/PostCommentFormFake.tsx @@ -1,7 +1,7 @@ import { Localized } from "fluent-react/compat"; import React, { StatelessComponent } from "react"; import { Button, HorizontalGutter } from "talk-ui/components"; -import * as styles from "./PostCommentFormFake.css"; +import styles from "./PostCommentFormFake.css"; import RTE from "./RTE"; const PostCommentFormFake: StatelessComponent = props => ( diff --git a/src/core/client/stream/tabs/comments/components/RTE.tsx b/src/core/client/stream/tabs/comments/components/RTE.tsx index 507b8a5f1..c6a56cf23 100644 --- a/src/core/client/stream/tabs/comments/components/RTE.tsx +++ b/src/core/client/stream/tabs/comments/components/RTE.tsx @@ -5,7 +5,7 @@ import React, { Ref, StatelessComponent } from "react"; import { Icon } from "talk-ui/components"; import { PropTypesOf } from "talk-ui/types"; -import * as styles from "./RTE.css"; +import styles from "./RTE.css"; // Use a special Localized version that forwards // ref and passes the api prop to the children. diff --git a/src/core/client/stream/tabs/comments/components/Stream.tsx b/src/core/client/stream/tabs/comments/components/Stream.tsx index 815455365..d8e3744da 100644 --- a/src/core/client/stream/tabs/comments/components/Stream.tsx +++ b/src/core/client/stream/tabs/comments/components/Stream.tsx @@ -10,7 +10,7 @@ import CommentContainer from "../containers/CommentContainer"; import PostCommentFormContainer from "../containers/PostCommentFormContainer"; import ReplyListContainer from "../containers/ReplyListContainer"; import PostCommentFormFake from "./PostCommentFormFake"; -import * as styles from "./Stream.css"; +import styles from "./Stream.css"; export interface StreamProps { story: { diff --git a/src/core/client/stream/tabs/profile/components/HistoryComment.tsx b/src/core/client/stream/tabs/profile/components/HistoryComment.tsx index 0262474c4..7aebf2b5d 100644 --- a/src/core/client/stream/tabs/profile/components/HistoryComment.tsx +++ b/src/core/client/stream/tabs/profile/components/HistoryComment.tsx @@ -11,7 +11,7 @@ import { Typography, } from "talk-ui/components"; import HTMLContent from "../../../components/HTMLContent"; -import * as styles from "./HistoryComment.css"; +import styles from "./HistoryComment.css"; export interface HistoryCommentProps { body: string | null; diff --git a/src/core/client/stream/test/comments/__snapshots__/editComment.spec.tsx.snap b/src/core/client/stream/test/comments/__snapshots__/editComment.spec.tsx.snap index 06aefabe2..97dcd8750 100644 --- a/src/core/client/stream/test/comments/__snapshots__/editComment.spec.tsx.snap +++ b/src/core/client/stream/test/comments/__snapshots__/editComment.spec.tsx.snap @@ -20,7 +20,6 @@ exports[`cancel edit: edit canceled 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -44,7 +43,6 @@ exports[`cancel edit: edit canceled 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -97,7 +95,6 @@ exports[`cancel edit: edit canceled 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -225,7 +222,6 @@ exports[`cancel edit: edit canceled 1`] = ` disabled={true} onBlur={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -290,7 +286,6 @@ exports[`cancel edit: edit canceled 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -320,7 +315,6 @@ exports[`cancel edit: edit canceled 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -339,7 +333,6 @@ exports[`cancel edit: edit canceled 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -368,7 +361,6 @@ exports[`cancel edit: edit canceled 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -446,7 +438,6 @@ exports[`cancel edit: edit canceled 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -465,7 +456,6 @@ exports[`cancel edit: edit canceled 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -494,7 +484,6 @@ exports[`cancel edit: edit canceled 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -537,7 +526,6 @@ exports[`edit a comment: edit form 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -561,7 +549,6 @@ exports[`edit a comment: edit form 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -614,7 +601,6 @@ exports[`edit a comment: edit form 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -742,7 +728,6 @@ exports[`edit a comment: edit form 1`] = ` disabled={true} onBlur={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -900,7 +885,6 @@ exports[`edit a comment: edit form 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -913,7 +897,6 @@ exports[`edit a comment: edit form 1`] = ` disabled={true} onBlur={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -986,7 +969,6 @@ exports[`edit a comment: edit form 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -1005,7 +987,6 @@ exports[`edit a comment: edit form 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -1034,7 +1015,6 @@ exports[`edit a comment: edit form 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -1077,7 +1057,6 @@ exports[`edit a comment: optimistic response 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -1101,7 +1080,6 @@ exports[`edit a comment: optimistic response 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -1154,7 +1132,6 @@ exports[`edit a comment: optimistic response 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -1282,7 +1259,6 @@ exports[`edit a comment: optimistic response 1`] = ` disabled={true} onBlur={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -1440,7 +1416,6 @@ exports[`edit a comment: optimistic response 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -1453,7 +1428,6 @@ exports[`edit a comment: optimistic response 1`] = ` disabled={true} onBlur={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -1526,7 +1500,6 @@ exports[`edit a comment: optimistic response 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -1545,7 +1518,6 @@ exports[`edit a comment: optimistic response 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -1574,7 +1546,6 @@ exports[`edit a comment: optimistic response 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -1617,7 +1588,6 @@ exports[`edit a comment: render stream 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -1641,7 +1611,6 @@ exports[`edit a comment: render stream 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -1694,7 +1663,6 @@ exports[`edit a comment: render stream 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -1822,7 +1790,6 @@ exports[`edit a comment: render stream 1`] = ` disabled={true} onBlur={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -1887,7 +1854,6 @@ exports[`edit a comment: render stream 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -1917,7 +1883,6 @@ exports[`edit a comment: render stream 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -1936,7 +1901,6 @@ exports[`edit a comment: render stream 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -1965,7 +1929,6 @@ exports[`edit a comment: render stream 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -2043,7 +2006,6 @@ exports[`edit a comment: render stream 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -2062,7 +2024,6 @@ exports[`edit a comment: render stream 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -2091,7 +2052,6 @@ exports[`edit a comment: render stream 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -2134,7 +2094,6 @@ exports[`edit a comment: server response 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -2158,7 +2117,6 @@ exports[`edit a comment: server response 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -2211,7 +2169,6 @@ exports[`edit a comment: server response 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -2339,7 +2296,6 @@ exports[`edit a comment: server response 1`] = ` disabled={true} onBlur={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -2413,7 +2369,6 @@ exports[`edit a comment: server response 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -2443,7 +2398,6 @@ exports[`edit a comment: server response 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -2462,7 +2416,6 @@ exports[`edit a comment: server response 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -2491,7 +2444,6 @@ exports[`edit a comment: server response 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -2569,7 +2521,6 @@ exports[`edit a comment: server response 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -2588,7 +2539,6 @@ exports[`edit a comment: server response 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -2617,7 +2567,6 @@ exports[`edit a comment: server response 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -2660,7 +2609,6 @@ exports[`shows expiry message: edit form closed 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -2684,7 +2632,6 @@ exports[`shows expiry message: edit form closed 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -2737,7 +2684,6 @@ exports[`shows expiry message: edit form closed 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -2865,7 +2811,6 @@ exports[`shows expiry message: edit form closed 1`] = ` disabled={true} onBlur={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -2930,7 +2875,6 @@ exports[`shows expiry message: edit form closed 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -2960,7 +2904,6 @@ exports[`shows expiry message: edit form closed 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -2979,7 +2922,6 @@ exports[`shows expiry message: edit form closed 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -3008,7 +2950,6 @@ exports[`shows expiry message: edit form closed 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -3086,7 +3027,6 @@ exports[`shows expiry message: edit form closed 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -3105,7 +3045,6 @@ exports[`shows expiry message: edit form closed 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -3134,7 +3073,6 @@ exports[`shows expiry message: edit form closed 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -3177,7 +3115,6 @@ exports[`shows expiry message: edit time expired 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -3201,7 +3138,6 @@ exports[`shows expiry message: edit time expired 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -3254,7 +3190,6 @@ exports[`shows expiry message: edit time expired 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -3382,7 +3317,6 @@ exports[`shows expiry message: edit time expired 1`] = ` disabled={true} onBlur={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -3530,7 +3464,6 @@ exports[`shows expiry message: edit time expired 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -3603,7 +3536,6 @@ exports[`shows expiry message: edit time expired 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -3622,7 +3554,6 @@ exports[`shows expiry message: edit time expired 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -3651,7 +3582,6 @@ exports[`shows expiry message: edit time expired 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} diff --git a/src/core/client/stream/test/comments/__snapshots__/loadMore.spec.tsx.snap b/src/core/client/stream/test/comments/__snapshots__/loadMore.spec.tsx.snap index 66c898c8a..9e20970c9 100644 --- a/src/core/client/stream/test/comments/__snapshots__/loadMore.spec.tsx.snap +++ b/src/core/client/stream/test/comments/__snapshots__/loadMore.spec.tsx.snap @@ -20,7 +20,6 @@ exports[`loads more comments 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -53,7 +52,6 @@ exports[`loads more comments 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -66,7 +64,6 @@ exports[`loads more comments 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -164,7 +161,6 @@ exports[`loads more comments 1`] = ` disabled={true} onBlur={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -241,7 +237,6 @@ exports[`loads more comments 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -260,7 +255,6 @@ exports[`loads more comments 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -289,7 +283,6 @@ exports[`loads more comments 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -367,7 +360,6 @@ exports[`loads more comments 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -386,7 +378,6 @@ exports[`loads more comments 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -415,7 +406,6 @@ exports[`loads more comments 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -493,7 +483,6 @@ exports[`loads more comments 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -512,7 +501,6 @@ exports[`loads more comments 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -541,7 +529,6 @@ exports[`loads more comments 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -584,7 +571,6 @@ exports[`renders comment stream 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -617,7 +603,6 @@ exports[`renders comment stream 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -630,7 +615,6 @@ exports[`renders comment stream 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -728,7 +712,6 @@ exports[`renders comment stream 1`] = ` disabled={true} onBlur={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -805,7 +788,6 @@ exports[`renders comment stream 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -824,7 +806,6 @@ exports[`renders comment stream 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -853,7 +834,6 @@ exports[`renders comment stream 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -931,7 +911,6 @@ exports[`renders comment stream 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -950,7 +929,6 @@ exports[`renders comment stream 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -979,7 +957,6 @@ exports[`renders comment stream 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -1004,7 +981,6 @@ exports[`renders comment stream 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} diff --git a/src/core/client/stream/test/comments/__snapshots__/permalinkView.spec.tsx.snap b/src/core/client/stream/test/comments/__snapshots__/permalinkView.spec.tsx.snap index 304440f0f..fd7ec9a3c 100644 --- a/src/core/client/stream/test/comments/__snapshots__/permalinkView.spec.tsx.snap +++ b/src/core/client/stream/test/comments/__snapshots__/permalinkView.spec.tsx.snap @@ -20,7 +20,6 @@ exports[`renders permalink view 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -50,7 +49,6 @@ exports[`renders permalink view 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -63,7 +61,6 @@ exports[`renders permalink view 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -92,7 +89,6 @@ exports[`renders permalink view 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -190,7 +186,6 @@ exports[`renders permalink view 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -209,7 +204,6 @@ exports[`renders permalink view 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -238,7 +232,6 @@ exports[`renders permalink view 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -333,7 +326,6 @@ exports[`renders permalink view 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -352,7 +344,6 @@ exports[`renders permalink view 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -381,7 +372,6 @@ exports[`renders permalink view 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -474,7 +464,6 @@ exports[`renders permalink view 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -493,7 +482,6 @@ exports[`renders permalink view 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -522,7 +510,6 @@ exports[`renders permalink view 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -610,7 +597,6 @@ exports[`renders permalink view 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -629,7 +615,6 @@ exports[`renders permalink view 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -658,7 +643,6 @@ exports[`renders permalink view 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -736,7 +720,6 @@ exports[`renders permalink view 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -755,7 +738,6 @@ exports[`renders permalink view 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -784,7 +766,6 @@ exports[`renders permalink view 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -829,7 +810,6 @@ exports[`show all comments 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -862,7 +842,6 @@ exports[`show all comments 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -875,7 +854,6 @@ exports[`show all comments 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -973,7 +951,6 @@ exports[`show all comments 1`] = ` disabled={true} onBlur={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -1050,7 +1027,6 @@ exports[`show all comments 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -1069,7 +1045,6 @@ exports[`show all comments 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -1098,7 +1073,6 @@ exports[`show all comments 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -1180,7 +1154,6 @@ exports[`show all comments 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -1199,7 +1172,6 @@ exports[`show all comments 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -1228,7 +1200,6 @@ exports[`show all comments 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -1306,7 +1277,6 @@ exports[`show all comments 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -1325,7 +1295,6 @@ exports[`show all comments 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -1354,7 +1323,6 @@ exports[`show all comments 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} diff --git a/src/core/client/stream/test/comments/__snapshots__/permalinkViewCommentNotFound.spec.tsx.snap b/src/core/client/stream/test/comments/__snapshots__/permalinkViewCommentNotFound.spec.tsx.snap index 0cd2d17f6..99b204934 100644 --- a/src/core/client/stream/test/comments/__snapshots__/permalinkViewCommentNotFound.spec.tsx.snap +++ b/src/core/client/stream/test/comments/__snapshots__/permalinkViewCommentNotFound.spec.tsx.snap @@ -20,7 +20,6 @@ exports[`renders permalink view with unknown comment 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -50,7 +49,6 @@ exports[`renders permalink view with unknown comment 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -63,7 +61,6 @@ exports[`renders permalink view with unknown comment 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -92,7 +89,6 @@ exports[`renders permalink view with unknown comment 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -132,7 +128,6 @@ exports[`show all comments 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -165,7 +160,6 @@ exports[`show all comments 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -178,7 +172,6 @@ exports[`show all comments 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -276,7 +269,6 @@ exports[`show all comments 1`] = ` disabled={true} onBlur={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -353,7 +345,6 @@ exports[`show all comments 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -372,7 +363,6 @@ exports[`show all comments 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -401,7 +391,6 @@ exports[`show all comments 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} diff --git a/src/core/client/stream/test/comments/__snapshots__/permalinkViewLoadMoreParents.spec.tsx.snap b/src/core/client/stream/test/comments/__snapshots__/permalinkViewLoadMoreParents.spec.tsx.snap index 7eacde3f6..432c50559 100644 --- a/src/core/client/stream/test/comments/__snapshots__/permalinkViewLoadMoreParents.spec.tsx.snap +++ b/src/core/client/stream/test/comments/__snapshots__/permalinkViewLoadMoreParents.spec.tsx.snap @@ -20,7 +20,6 @@ exports[`renders permalink view 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -50,7 +49,6 @@ exports[`renders permalink view 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -63,7 +61,6 @@ exports[`renders permalink view 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -92,7 +89,6 @@ exports[`renders permalink view 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -185,7 +181,6 @@ exports[`renders permalink view 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -280,7 +275,6 @@ exports[`renders permalink view 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -299,7 +293,6 @@ exports[`renders permalink view 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -328,7 +321,6 @@ exports[`renders permalink view 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -376,7 +368,6 @@ exports[`views pervious comments 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -406,7 +397,6 @@ exports[`views pervious comments 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -419,7 +409,6 @@ exports[`views pervious comments 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -448,7 +437,6 @@ exports[`views pervious comments 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -546,7 +534,6 @@ exports[`views pervious comments 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -565,7 +552,6 @@ exports[`views pervious comments 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -594,7 +580,6 @@ exports[`views pervious comments 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -689,7 +674,6 @@ exports[`views pervious comments 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -708,7 +692,6 @@ exports[`views pervious comments 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -737,7 +720,6 @@ exports[`views pervious comments 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -830,7 +812,6 @@ exports[`views pervious comments 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -849,7 +830,6 @@ exports[`views pervious comments 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -878,7 +858,6 @@ exports[`views pervious comments 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} diff --git a/src/core/client/stream/test/comments/__snapshots__/permalinkViewStoryNotFound.spec.tsx.snap b/src/core/client/stream/test/comments/__snapshots__/permalinkViewStoryNotFound.spec.tsx.snap index 55249b6f1..bf33eab9f 100644 --- a/src/core/client/stream/test/comments/__snapshots__/permalinkViewStoryNotFound.spec.tsx.snap +++ b/src/core/client/stream/test/comments/__snapshots__/permalinkViewStoryNotFound.spec.tsx.snap @@ -20,7 +20,6 @@ exports[`renders permalink view with unknown story 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} diff --git a/src/core/client/stream/test/comments/__snapshots__/postComment.spec.tsx.snap b/src/core/client/stream/test/comments/__snapshots__/postComment.spec.tsx.snap index f66b7776a..f6469c57e 100644 --- a/src/core/client/stream/test/comments/__snapshots__/postComment.spec.tsx.snap +++ b/src/core/client/stream/test/comments/__snapshots__/postComment.spec.tsx.snap @@ -20,7 +20,6 @@ exports[`post a comment: optimistic response 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -44,7 +43,6 @@ exports[`post a comment: optimistic response 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -97,7 +95,6 @@ exports[`post a comment: optimistic response 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -219,7 +216,6 @@ exports[`post a comment: optimistic response 1`] = ` disabled={true} onBlur={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -284,7 +280,6 @@ exports[`post a comment: optimistic response 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -314,7 +309,6 @@ exports[`post a comment: optimistic response 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -333,7 +327,6 @@ exports[`post a comment: optimistic response 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -362,7 +355,6 @@ exports[`post a comment: optimistic response 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -440,7 +432,6 @@ exports[`post a comment: optimistic response 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -459,7 +450,6 @@ exports[`post a comment: optimistic response 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -488,7 +478,6 @@ exports[`post a comment: optimistic response 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -566,7 +555,6 @@ exports[`post a comment: optimistic response 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -585,7 +573,6 @@ exports[`post a comment: optimistic response 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -614,7 +601,6 @@ exports[`post a comment: optimistic response 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -657,7 +643,6 @@ exports[`post a comment: server response 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -681,7 +666,6 @@ exports[`post a comment: server response 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -734,7 +718,6 @@ exports[`post a comment: server response 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -862,7 +845,6 @@ exports[`post a comment: server response 1`] = ` disabled={true} onBlur={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -941,7 +923,6 @@ exports[`post a comment: server response 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -960,7 +941,6 @@ exports[`post a comment: server response 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -989,7 +969,6 @@ exports[`post a comment: server response 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -1067,7 +1046,6 @@ exports[`post a comment: server response 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -1086,7 +1064,6 @@ exports[`post a comment: server response 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -1115,7 +1092,6 @@ exports[`post a comment: server response 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -1193,7 +1169,6 @@ exports[`post a comment: server response 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -1212,7 +1187,6 @@ exports[`post a comment: server response 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -1241,7 +1215,6 @@ exports[`post a comment: server response 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -1284,7 +1257,6 @@ exports[`renders comment stream 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -1308,7 +1280,6 @@ exports[`renders comment stream 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -1361,7 +1332,6 @@ exports[`renders comment stream 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -1489,7 +1459,6 @@ exports[`renders comment stream 1`] = ` disabled={true} onBlur={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -1568,7 +1537,6 @@ exports[`renders comment stream 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -1587,7 +1555,6 @@ exports[`renders comment stream 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -1616,7 +1583,6 @@ exports[`renders comment stream 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -1694,7 +1660,6 @@ exports[`renders comment stream 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -1713,7 +1678,6 @@ exports[`renders comment stream 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -1742,7 +1706,6 @@ exports[`renders comment stream 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} diff --git a/src/core/client/stream/test/comments/__snapshots__/postLocalReply.spec.tsx.snap b/src/core/client/stream/test/comments/__snapshots__/postLocalReply.spec.tsx.snap index 778e60021..712998980 100644 --- a/src/core/client/stream/test/comments/__snapshots__/postLocalReply.spec.tsx.snap +++ b/src/core/client/stream/test/comments/__snapshots__/postLocalReply.spec.tsx.snap @@ -20,7 +20,6 @@ exports[`post a reply: open reply form 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -44,7 +43,6 @@ exports[`post a reply: open reply form 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -97,7 +95,6 @@ exports[`post a reply: open reply form 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -225,7 +222,6 @@ exports[`post a reply: open reply form 1`] = ` disabled={true} onBlur={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -304,7 +300,6 @@ exports[`post a reply: open reply form 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -323,7 +318,6 @@ exports[`post a reply: open reply form 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -352,7 +346,6 @@ exports[`post a reply: open reply form 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -434,7 +427,6 @@ exports[`post a reply: open reply form 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -453,7 +445,6 @@ exports[`post a reply: open reply form 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -482,7 +473,6 @@ exports[`post a reply: open reply form 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -564,7 +554,6 @@ exports[`post a reply: open reply form 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -583,7 +572,6 @@ exports[`post a reply: open reply form 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -612,7 +600,6 @@ exports[`post a reply: open reply form 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -694,7 +681,6 @@ exports[`post a reply: open reply form 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -713,7 +699,6 @@ exports[`post a reply: open reply form 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -742,7 +727,6 @@ exports[`post a reply: open reply form 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -824,7 +808,6 @@ exports[`post a reply: open reply form 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -843,7 +826,6 @@ exports[`post a reply: open reply form 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -872,7 +854,6 @@ exports[`post a reply: open reply form 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -954,7 +935,6 @@ exports[`post a reply: open reply form 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -973,7 +953,6 @@ exports[`post a reply: open reply form 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -1002,7 +981,6 @@ exports[`post a reply: open reply form 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -1020,7 +998,6 @@ exports[`post a reply: open reply form 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -1159,7 +1136,6 @@ exports[`post a reply: open reply form 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -1172,7 +1148,6 @@ exports[`post a reply: open reply form 1`] = ` disabled={true} onBlur={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -1221,7 +1196,6 @@ exports[`post a reply: optimistic response 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -1245,7 +1219,6 @@ exports[`post a reply: optimistic response 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -1298,7 +1271,6 @@ exports[`post a reply: optimistic response 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -1426,7 +1398,6 @@ exports[`post a reply: optimistic response 1`] = ` disabled={true} onBlur={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -1505,7 +1476,6 @@ exports[`post a reply: optimistic response 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -1524,7 +1494,6 @@ exports[`post a reply: optimistic response 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -1553,7 +1522,6 @@ exports[`post a reply: optimistic response 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -1635,7 +1603,6 @@ exports[`post a reply: optimistic response 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -1654,7 +1621,6 @@ exports[`post a reply: optimistic response 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -1683,7 +1649,6 @@ exports[`post a reply: optimistic response 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -1765,7 +1730,6 @@ exports[`post a reply: optimistic response 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -1784,7 +1748,6 @@ exports[`post a reply: optimistic response 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -1813,7 +1776,6 @@ exports[`post a reply: optimistic response 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -1895,7 +1857,6 @@ exports[`post a reply: optimistic response 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -1914,7 +1875,6 @@ exports[`post a reply: optimistic response 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -1943,7 +1903,6 @@ exports[`post a reply: optimistic response 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -2025,7 +1984,6 @@ exports[`post a reply: optimistic response 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -2044,7 +2002,6 @@ exports[`post a reply: optimistic response 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -2073,7 +2030,6 @@ exports[`post a reply: optimistic response 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -2155,7 +2111,6 @@ exports[`post a reply: optimistic response 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -2174,7 +2129,6 @@ exports[`post a reply: optimistic response 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -2203,7 +2157,6 @@ exports[`post a reply: optimistic response 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -2221,7 +2174,6 @@ exports[`post a reply: optimistic response 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -2354,7 +2306,6 @@ exports[`post a reply: optimistic response 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -2367,7 +2318,6 @@ exports[`post a reply: optimistic response 1`] = ` disabled={true} onBlur={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -2431,7 +2381,6 @@ exports[`post a reply: optimistic response 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -2464,7 +2413,6 @@ exports[`post a reply: optimistic response 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -2493,7 +2441,6 @@ exports[`post a reply: optimistic response 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -2548,7 +2495,6 @@ exports[`post a reply: server response 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -2572,7 +2518,6 @@ exports[`post a reply: server response 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -2625,7 +2570,6 @@ exports[`post a reply: server response 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -2753,7 +2697,6 @@ exports[`post a reply: server response 1`] = ` disabled={true} onBlur={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -2832,7 +2775,6 @@ exports[`post a reply: server response 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -2851,7 +2793,6 @@ exports[`post a reply: server response 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -2880,7 +2821,6 @@ exports[`post a reply: server response 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -2962,7 +2902,6 @@ exports[`post a reply: server response 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -2981,7 +2920,6 @@ exports[`post a reply: server response 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -3010,7 +2948,6 @@ exports[`post a reply: server response 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -3092,7 +3029,6 @@ exports[`post a reply: server response 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -3111,7 +3047,6 @@ exports[`post a reply: server response 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -3140,7 +3075,6 @@ exports[`post a reply: server response 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -3222,7 +3156,6 @@ exports[`post a reply: server response 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -3241,7 +3174,6 @@ exports[`post a reply: server response 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -3270,7 +3202,6 @@ exports[`post a reply: server response 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -3352,7 +3283,6 @@ exports[`post a reply: server response 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -3371,7 +3301,6 @@ exports[`post a reply: server response 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -3400,7 +3329,6 @@ exports[`post a reply: server response 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -3482,7 +3410,6 @@ exports[`post a reply: server response 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -3501,7 +3428,6 @@ exports[`post a reply: server response 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -3530,7 +3456,6 @@ exports[`post a reply: server response 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -3548,7 +3473,6 @@ exports[`post a reply: server response 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -3631,7 +3555,6 @@ exports[`post a reply: server response 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -3660,7 +3583,6 @@ exports[`post a reply: server response 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -3715,7 +3637,6 @@ exports[`renders comment stream 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -3739,7 +3660,6 @@ exports[`renders comment stream 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -3792,7 +3712,6 @@ exports[`renders comment stream 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -3920,7 +3839,6 @@ exports[`renders comment stream 1`] = ` disabled={true} onBlur={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -3999,7 +3917,6 @@ exports[`renders comment stream 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -4018,7 +3935,6 @@ exports[`renders comment stream 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -4047,7 +3963,6 @@ exports[`renders comment stream 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -4129,7 +4044,6 @@ exports[`renders comment stream 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -4148,7 +4062,6 @@ exports[`renders comment stream 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -4177,7 +4090,6 @@ exports[`renders comment stream 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -4259,7 +4171,6 @@ exports[`renders comment stream 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -4278,7 +4189,6 @@ exports[`renders comment stream 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -4307,7 +4217,6 @@ exports[`renders comment stream 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -4389,7 +4298,6 @@ exports[`renders comment stream 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -4408,7 +4316,6 @@ exports[`renders comment stream 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -4437,7 +4344,6 @@ exports[`renders comment stream 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -4519,7 +4425,6 @@ exports[`renders comment stream 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -4538,7 +4443,6 @@ exports[`renders comment stream 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -4567,7 +4471,6 @@ exports[`renders comment stream 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -4649,7 +4552,6 @@ exports[`renders comment stream 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -4668,7 +4570,6 @@ exports[`renders comment stream 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -4697,7 +4598,6 @@ exports[`renders comment stream 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -4715,7 +4615,6 @@ exports[`renders comment stream 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} diff --git a/src/core/client/stream/test/comments/__snapshots__/postReply.spec.tsx.snap b/src/core/client/stream/test/comments/__snapshots__/postReply.spec.tsx.snap index 8114a0987..85b887323 100644 --- a/src/core/client/stream/test/comments/__snapshots__/postReply.spec.tsx.snap +++ b/src/core/client/stream/test/comments/__snapshots__/postReply.spec.tsx.snap @@ -20,7 +20,6 @@ exports[`post a reply: open reply form 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -44,7 +43,6 @@ exports[`post a reply: open reply form 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -97,7 +95,6 @@ exports[`post a reply: open reply form 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -225,7 +222,6 @@ exports[`post a reply: open reply form 1`] = ` disabled={true} onBlur={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -304,7 +300,6 @@ exports[`post a reply: open reply form 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -323,7 +318,6 @@ exports[`post a reply: open reply form 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -352,7 +346,6 @@ exports[`post a reply: open reply form 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -493,7 +486,6 @@ exports[`post a reply: open reply form 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -506,7 +498,6 @@ exports[`post a reply: open reply form 1`] = ` disabled={true} onBlur={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -580,7 +571,6 @@ exports[`post a reply: open reply form 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -599,7 +589,6 @@ exports[`post a reply: open reply form 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -628,7 +617,6 @@ exports[`post a reply: open reply form 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -671,7 +659,6 @@ exports[`post a reply: optimistic response 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -695,7 +682,6 @@ exports[`post a reply: optimistic response 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -748,7 +734,6 @@ exports[`post a reply: optimistic response 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -876,7 +861,6 @@ exports[`post a reply: optimistic response 1`] = ` disabled={true} onBlur={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -955,7 +939,6 @@ exports[`post a reply: optimistic response 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -974,7 +957,6 @@ exports[`post a reply: optimistic response 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -1003,7 +985,6 @@ exports[`post a reply: optimistic response 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -1138,7 +1119,6 @@ exports[`post a reply: optimistic response 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -1151,7 +1131,6 @@ exports[`post a reply: optimistic response 1`] = ` disabled={true} onBlur={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -1215,7 +1194,6 @@ exports[`post a reply: optimistic response 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -1245,7 +1223,6 @@ exports[`post a reply: optimistic response 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -1264,7 +1241,6 @@ exports[`post a reply: optimistic response 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -1293,7 +1269,6 @@ exports[`post a reply: optimistic response 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -1373,7 +1348,6 @@ exports[`post a reply: optimistic response 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -1392,7 +1366,6 @@ exports[`post a reply: optimistic response 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -1421,7 +1394,6 @@ exports[`post a reply: optimistic response 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -1464,7 +1436,6 @@ exports[`post a reply: server response 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -1488,7 +1459,6 @@ exports[`post a reply: server response 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -1541,7 +1511,6 @@ exports[`post a reply: server response 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -1669,7 +1638,6 @@ exports[`post a reply: server response 1`] = ` disabled={true} onBlur={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -1748,7 +1716,6 @@ exports[`post a reply: server response 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -1767,7 +1734,6 @@ exports[`post a reply: server response 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -1796,7 +1762,6 @@ exports[`post a reply: server response 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -1878,7 +1843,6 @@ exports[`post a reply: server response 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -1897,7 +1861,6 @@ exports[`post a reply: server response 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -1926,7 +1889,6 @@ exports[`post a reply: server response 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -2006,7 +1968,6 @@ exports[`post a reply: server response 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -2025,7 +1986,6 @@ exports[`post a reply: server response 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -2054,7 +2014,6 @@ exports[`post a reply: server response 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -2097,7 +2056,6 @@ exports[`renders comment stream 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -2121,7 +2079,6 @@ exports[`renders comment stream 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -2174,7 +2131,6 @@ exports[`renders comment stream 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -2302,7 +2258,6 @@ exports[`renders comment stream 1`] = ` disabled={true} onBlur={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -2381,7 +2336,6 @@ exports[`renders comment stream 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -2400,7 +2354,6 @@ exports[`renders comment stream 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -2429,7 +2382,6 @@ exports[`renders comment stream 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -2507,7 +2459,6 @@ exports[`renders comment stream 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -2526,7 +2477,6 @@ exports[`renders comment stream 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -2555,7 +2505,6 @@ exports[`renders comment stream 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} diff --git a/src/core/client/stream/test/comments/__snapshots__/renderReplies.spec.tsx.snap b/src/core/client/stream/test/comments/__snapshots__/renderReplies.spec.tsx.snap index 962e4d499..6b3173960 100644 --- a/src/core/client/stream/test/comments/__snapshots__/renderReplies.spec.tsx.snap +++ b/src/core/client/stream/test/comments/__snapshots__/renderReplies.spec.tsx.snap @@ -20,7 +20,6 @@ exports[`renders comment stream 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -53,7 +52,6 @@ exports[`renders comment stream 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -66,7 +64,6 @@ exports[`renders comment stream 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -164,7 +161,6 @@ exports[`renders comment stream 1`] = ` disabled={true} onBlur={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -241,7 +237,6 @@ exports[`renders comment stream 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -260,7 +255,6 @@ exports[`renders comment stream 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -289,7 +283,6 @@ exports[`renders comment stream 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -367,7 +360,6 @@ exports[`renders comment stream 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -386,7 +378,6 @@ exports[`renders comment stream 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -415,7 +406,6 @@ exports[`renders comment stream 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -497,7 +487,6 @@ exports[`renders comment stream 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -516,7 +505,6 @@ exports[`renders comment stream 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -545,7 +533,6 @@ exports[`renders comment stream 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -627,7 +614,6 @@ exports[`renders comment stream 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -646,7 +632,6 @@ exports[`renders comment stream 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -675,7 +660,6 @@ exports[`renders comment stream 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -753,7 +737,6 @@ exports[`renders comment stream 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -772,7 +755,6 @@ exports[`renders comment stream 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -801,7 +783,6 @@ exports[`renders comment stream 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -881,7 +862,6 @@ exports[`renders comment stream 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -900,7 +880,6 @@ exports[`renders comment stream 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -929,7 +908,6 @@ exports[`renders comment stream 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} diff --git a/src/core/client/stream/test/comments/__snapshots__/renderStream.spec.tsx.snap b/src/core/client/stream/test/comments/__snapshots__/renderStream.spec.tsx.snap index 05250ec3f..d1d07d9f6 100644 --- a/src/core/client/stream/test/comments/__snapshots__/renderStream.spec.tsx.snap +++ b/src/core/client/stream/test/comments/__snapshots__/renderStream.spec.tsx.snap @@ -20,7 +20,6 @@ exports[`renders comment stream 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -53,7 +52,6 @@ exports[`renders comment stream 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -66,7 +64,6 @@ exports[`renders comment stream 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -164,7 +161,6 @@ exports[`renders comment stream 1`] = ` disabled={true} onBlur={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -241,7 +237,6 @@ exports[`renders comment stream 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -260,7 +255,6 @@ exports[`renders comment stream 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -289,7 +283,6 @@ exports[`renders comment stream 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -367,7 +360,6 @@ exports[`renders comment stream 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -386,7 +378,6 @@ exports[`renders comment stream 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -415,7 +406,6 @@ exports[`renders comment stream 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} diff --git a/src/core/client/stream/test/comments/__snapshots__/showAllReplies.spec.tsx.snap b/src/core/client/stream/test/comments/__snapshots__/showAllReplies.spec.tsx.snap index 0dfe5f46e..618f2c4fe 100644 --- a/src/core/client/stream/test/comments/__snapshots__/showAllReplies.spec.tsx.snap +++ b/src/core/client/stream/test/comments/__snapshots__/showAllReplies.spec.tsx.snap @@ -20,7 +20,6 @@ exports[`renders comment stream 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -53,7 +52,6 @@ exports[`renders comment stream 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -66,7 +64,6 @@ exports[`renders comment stream 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -164,7 +161,6 @@ exports[`renders comment stream 1`] = ` disabled={true} onBlur={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -241,7 +237,6 @@ exports[`renders comment stream 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -260,7 +255,6 @@ exports[`renders comment stream 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -289,7 +283,6 @@ exports[`renders comment stream 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -371,7 +364,6 @@ exports[`renders comment stream 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -390,7 +382,6 @@ exports[`renders comment stream 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -419,7 +410,6 @@ exports[`renders comment stream 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -450,7 +440,6 @@ exports[`renders comment stream 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -488,7 +477,6 @@ exports[`show all replies 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -521,7 +509,6 @@ exports[`show all replies 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -534,7 +521,6 @@ exports[`show all replies 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -632,7 +618,6 @@ exports[`show all replies 1`] = ` disabled={true} onBlur={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -709,7 +694,6 @@ exports[`show all replies 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -728,7 +712,6 @@ exports[`show all replies 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -757,7 +740,6 @@ exports[`show all replies 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -839,7 +821,6 @@ exports[`show all replies 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -858,7 +839,6 @@ exports[`show all replies 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -887,7 +867,6 @@ exports[`show all replies 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -965,7 +944,6 @@ exports[`show all replies 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -984,7 +962,6 @@ exports[`show all replies 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -1013,7 +990,6 @@ exports[`show all replies 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} diff --git a/src/core/client/stream/test/comments/__snapshots__/showConversation.spec.tsx.snap b/src/core/client/stream/test/comments/__snapshots__/showConversation.spec.tsx.snap index d79429976..6de8accd5 100644 --- a/src/core/client/stream/test/comments/__snapshots__/showConversation.spec.tsx.snap +++ b/src/core/client/stream/test/comments/__snapshots__/showConversation.spec.tsx.snap @@ -20,7 +20,6 @@ exports[`renders comment stream 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -53,7 +52,6 @@ exports[`renders comment stream 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -66,7 +64,6 @@ exports[`renders comment stream 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -164,7 +161,6 @@ exports[`renders comment stream 1`] = ` disabled={true} onBlur={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -241,7 +237,6 @@ exports[`renders comment stream 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -260,7 +255,6 @@ exports[`renders comment stream 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -289,7 +283,6 @@ exports[`renders comment stream 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -371,7 +364,6 @@ exports[`renders comment stream 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -390,7 +382,6 @@ exports[`renders comment stream 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -419,7 +410,6 @@ exports[`renders comment stream 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -501,7 +491,6 @@ exports[`renders comment stream 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -520,7 +509,6 @@ exports[`renders comment stream 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -549,7 +537,6 @@ exports[`renders comment stream 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -631,7 +618,6 @@ exports[`renders comment stream 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -650,7 +636,6 @@ exports[`renders comment stream 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -679,7 +664,6 @@ exports[`renders comment stream 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -761,7 +745,6 @@ exports[`renders comment stream 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -780,7 +763,6 @@ exports[`renders comment stream 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -809,7 +791,6 @@ exports[`renders comment stream 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -891,7 +872,6 @@ exports[`renders comment stream 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -910,7 +890,6 @@ exports[`renders comment stream 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -939,7 +918,6 @@ exports[`renders comment stream 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -957,7 +935,6 @@ exports[`renders comment stream 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -1008,7 +985,6 @@ exports[`shows conversation 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -1038,7 +1014,6 @@ exports[`shows conversation 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -1051,7 +1026,6 @@ exports[`shows conversation 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -1080,7 +1054,6 @@ exports[`shows conversation 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -1154,7 +1127,6 @@ exports[`shows conversation 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -1173,7 +1145,6 @@ exports[`shows conversation 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -1202,7 +1173,6 @@ exports[`shows conversation 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} diff --git a/src/core/client/stream/test/profile/__snapshots__/loadMore.spec.tsx.snap b/src/core/client/stream/test/profile/__snapshots__/loadMore.spec.tsx.snap index 868221212..dc3925390 100644 --- a/src/core/client/stream/test/profile/__snapshots__/loadMore.spec.tsx.snap +++ b/src/core/client/stream/test/profile/__snapshots__/loadMore.spec.tsx.snap @@ -20,7 +20,6 @@ exports[`loads more comments 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -70,7 +69,6 @@ exports[`loads more comments 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -125,7 +123,6 @@ exports[`loads more comments 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -180,7 +177,6 @@ exports[`loads more comments 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -235,7 +231,6 @@ exports[`loads more comments 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -280,7 +275,6 @@ exports[`renders comment stream 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -330,7 +324,6 @@ exports[`renders comment stream 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -385,7 +378,6 @@ exports[`renders comment stream 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -440,7 +432,6 @@ exports[`renders comment stream 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -467,7 +458,6 @@ exports[`renders comment stream 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} diff --git a/src/core/client/stream/test/profile/__snapshots__/renderProfile.spec.tsx.snap b/src/core/client/stream/test/profile/__snapshots__/renderProfile.spec.tsx.snap index f65586d21..df0256a54 100644 --- a/src/core/client/stream/test/profile/__snapshots__/renderProfile.spec.tsx.snap +++ b/src/core/client/stream/test/profile/__snapshots__/renderProfile.spec.tsx.snap @@ -20,7 +20,6 @@ exports[`renders profile 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -70,7 +69,6 @@ exports[`renders profile 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -125,7 +123,6 @@ exports[`renders profile 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -180,7 +177,6 @@ exports[`renders profile 1`] = ` onBlur={[Function]} onClick={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} diff --git a/src/core/client/ui/components/AriaInfo/AriaInfo.tsx b/src/core/client/ui/components/AriaInfo/AriaInfo.tsx index fc88b0e03..9f730db66 100644 --- a/src/core/client/ui/components/AriaInfo/AriaInfo.tsx +++ b/src/core/client/ui/components/AriaInfo/AriaInfo.tsx @@ -4,7 +4,7 @@ import React, { AllHTMLAttributes, Ref, StatelessComponent } from "react"; import { withForwardRef, withStyles } from "talk-ui/hocs"; import { PropTypesOf } from "talk-ui/types"; -import * as styles from "./AriaInfo.css"; +import styles from "./AriaInfo.css"; interface InnerProps extends AllHTMLAttributes { /** diff --git a/src/core/client/ui/components/BaseButton/BaseButton.tsx b/src/core/client/ui/components/BaseButton/BaseButton.tsx index 39ed4cd48..150a2ae48 100644 --- a/src/core/client/ui/components/BaseButton/BaseButton.tsx +++ b/src/core/client/ui/components/BaseButton/BaseButton.tsx @@ -16,7 +16,7 @@ import { } from "talk-ui/hocs"; import { PropTypesOf } from "talk-ui/types"; -import * as styles from "./BaseButton.css"; +import styles from "./BaseButton.css"; interface InnerProps extends ButtonHTMLAttributes { /** If set renders an anchor tag instead */ @@ -44,7 +44,6 @@ interface InnerProps extends ButtonHTMLAttributes { // These handlers are passed down by the `withKeyboardFocus` HOC. onFocus: EventHandler>; onBlur: EventHandler>; - onMouseDown: EventHandler>; keyboardFocus: boolean; } diff --git a/src/core/client/ui/components/BaseButton/__snapshots__/BaseButton.spec.tsx.snap b/src/core/client/ui/components/BaseButton/__snapshots__/BaseButton.spec.tsx.snap index 84b67f69c..c7f55a935 100644 --- a/src/core/client/ui/components/BaseButton/__snapshots__/BaseButton.spec.tsx.snap +++ b/src/core/client/ui/components/BaseButton/__snapshots__/BaseButton.spec.tsx.snap @@ -5,7 +5,6 @@ exports[`renders as anchor 1`] = ` className="BaseButton-root" onBlur={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} @@ -20,7 +19,6 @@ exports[`renders correctly 1`] = ` className="BaseButton-root my-class" onBlur={[Function]} onFocus={[Function]} - onMouseDown={[Function]} onMouseOut={[Function]} onMouseOver={[Function]} onTouchEnd={[Function]} diff --git a/src/core/client/ui/components/Button/Button.tsx b/src/core/client/ui/components/Button/Button.tsx index fe2a8aa4a..95ca5c305 100644 --- a/src/core/client/ui/components/Button/Button.tsx +++ b/src/core/client/ui/components/Button/Button.tsx @@ -6,7 +6,7 @@ import { withForwardRef, withStyles } from "talk-ui/hocs"; import { PropTypesOf } from "talk-ui/types"; import BaseButton, { BaseButtonProps } from "../BaseButton"; -import * as styles from "./Button.css"; +import styles from "./Button.css"; // This should extend from BaseButton instead but we can't because of this bug // TODO: add bug link. diff --git a/src/core/client/ui/components/Button/ButtonIcon.tsx b/src/core/client/ui/components/Button/ButtonIcon.tsx index 90660c1aa..31a3e1c98 100644 --- a/src/core/client/ui/components/Button/ButtonIcon.tsx +++ b/src/core/client/ui/components/Button/ButtonIcon.tsx @@ -5,7 +5,7 @@ import Icon, { IconProps } from "talk-ui/components/Icon"; import { withForwardRef, withStyles } from "talk-ui/hocs"; import { PropTypesOf } from "talk-ui/types"; -import * as styles from "./ButtonIcon.css"; +import styles from "./ButtonIcon.css"; interface InnerProps extends HTMLAttributes { /** diff --git a/src/core/client/ui/components/CallOut/CallOut.tsx b/src/core/client/ui/components/CallOut/CallOut.tsx index 5124b3197..70176426b 100644 --- a/src/core/client/ui/components/CallOut/CallOut.tsx +++ b/src/core/client/ui/components/CallOut/CallOut.tsx @@ -2,7 +2,7 @@ import cn from "classnames"; import React from "react"; import { ReactNode, StatelessComponent } from "react"; import { withStyles } from "talk-ui/hocs"; -import * as styles from "./CallOut.css"; +import styles from "./CallOut.css"; export interface CallOutProps { /** diff --git a/src/core/client/ui/components/CheckBox/CheckBox.css b/src/core/client/ui/components/CheckBox/CheckBox.css new file mode 100644 index 000000000..563ee234c --- /dev/null +++ b/src/core/client/ui/components/CheckBox/CheckBox.css @@ -0,0 +1,85 @@ +.root { +} + +.input { + cursor: pointer; + position: absolute; /* take it out of document flow */ + opacity: 0; /* hide it */ +} + +.label { + composes: bodyCopy from "talk-ui/shared/typography.css"; + display: inline-flex; + align-items: center; + position: relative; + cursor: pointer; + user-select: none; +} + +.labelSpan { + padding-bottom: 1px; +} + +.labelLight { + color: var(--palette-text-light); +} + +/* Box. */ +.input + .label:before { + content: ""; + margin-right: 10px; + display: inline-block; + width: 14px; + height: 14px; + background: var(--palette-common-white); + border: 1px solid var(--palette-text-primary); + box-sizing: border-box; +} + +/* Box focus */ +.label.focus:before { + outline-width: 3px; + outline-color: Highlight; + outline-color: -webkit-focus-ring-color; + outline-style: auto; +} + +/* Box checked */ +.input:checked + .label:before { + background: var(--palette-primary-main); + border: 1px solid var(--palette-primary-main); +} + +/* Disabled state label. */ +.input:disabled + .label { + cursor: auto; + opacity: 0.6; +} + +/* Disabled box. */ +.input:disabled + .label:before { + box-shadow: none; + border: 1px solid var(--palette-grey-main); + background: var(--palette-grey-lightest); +} + +/* Checkmark. Could be replaced with an image */ +.input:checked + .label:after { + content: ""; + position: absolute; + left: 2px; + top: 10px; + color: var(--palette-text-light); + background: currentColor; + width: 2px; + height: 2px; + box-shadow: 2px 0 0 currentColor, 4px 0 0 currentColor, + 4px -2px 0 currentColor, 4px -4px 0 currentColor, 4px -6px 0 currentColor, + 4px -8px 0 currentColor; + transform: rotate(45deg); + box-sizing: border-box; +} + +.input:checked:disabled + .label:after { + color: var(--palette-text-primary); +} diff --git a/src/core/client/ui/components/CheckBox/CheckBox.mdx b/src/core/client/ui/components/CheckBox/CheckBox.mdx new file mode 100644 index 000000000..ae33bbbf5 --- /dev/null +++ b/src/core/client/ui/components/CheckBox/CheckBox.mdx @@ -0,0 +1,19 @@ +--- +name: CheckBox +menu: UI Kit +--- + +import { Playground, PropsTable } from 'docz' +import CheckBox from './CheckBox.tsx' +import HorizontalGutter from '../HorizontalGutter' + +# CheckBox + +## Basic Use + + + Yes I agree + No I don't agree + I don't know + + diff --git a/src/core/client/ui/components/CheckBox/CheckBox.spec.tsx b/src/core/client/ui/components/CheckBox/CheckBox.spec.tsx new file mode 100644 index 000000000..69a5cdb3b --- /dev/null +++ b/src/core/client/ui/components/CheckBox/CheckBox.spec.tsx @@ -0,0 +1,17 @@ +import React from "react"; +import TestRenderer from "react-test-renderer"; + +import { PropTypesOf } from "talk-ui/types"; + +import CheckBox from "./CheckBox"; + +it("renders correctly", () => { + const props: PropTypesOf = { + className: "custom", + id: "checkboxID", + checked: true, + children: "Yes I agree", + }; + const renderer = TestRenderer.create(); + expect(renderer.toJSON()).toMatchSnapshot(); +}); diff --git a/src/core/client/ui/components/CheckBox/CheckBox.tsx b/src/core/client/ui/components/CheckBox/CheckBox.tsx new file mode 100644 index 000000000..d0dbf96d5 --- /dev/null +++ b/src/core/client/ui/components/CheckBox/CheckBox.tsx @@ -0,0 +1,89 @@ +import cn from "classnames"; +import React, { ChangeEvent, Component, EventHandler, FocusEvent } from "react"; +import uuid from "uuid/v4"; + +import { withKeyboardFocus, withStyles } from "talk-ui/hocs"; + +import styles from "./CheckBox.css"; +export interface CheckBoxProps { + id?: string; + /** + * checked or not. + */ + checked?: boolean; + /** + * Convenient prop to override the root styling. + */ + className?: string; + /** + * Override or extend the styles applied to the component. + */ + classes: typeof styles; + /** + * Mark as readonly + */ + readOnly?: boolean; + /** + * Name + */ + name?: string; + /** + * onChange + */ + onChange?: EventHandler>; + + disabled?: boolean; + children: React.ReactNode; + /** + * Display a light text. + */ + light?: boolean; + + // These handlers are passed down by the `withKeyboardFocus` HOC. + onFocus: EventHandler>; + onBlur: EventHandler>; + keyboardFocus: boolean; +} + +class CheckBox extends Component { + public state = { + randomID: uuid(), + }; + public render() { + const { + className, + classes, + id, + light, + children, + keyboardFocus, + ...rest + } = this.props; + + const rootClassName = cn(classes.root, className); + const finalID = this.props.id || this.state.randomID; + + return ( +
    + + +
    + ); + } +} + +const enhanced = withStyles(styles)(withKeyboardFocus(CheckBox)); +export default enhanced; diff --git a/src/core/client/ui/components/CheckBox/__snapshots__/CheckBox.spec.tsx.snap b/src/core/client/ui/components/CheckBox/__snapshots__/CheckBox.spec.tsx.snap new file mode 100644 index 000000000..11ce87d61 --- /dev/null +++ b/src/core/client/ui/components/CheckBox/__snapshots__/CheckBox.spec.tsx.snap @@ -0,0 +1,26 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`renders correctly 1`] = ` +
    + + +
    +`; diff --git a/src/core/client/ui/components/CheckBox/index.ts b/src/core/client/ui/components/CheckBox/index.ts new file mode 100644 index 000000000..151b40bd5 --- /dev/null +++ b/src/core/client/ui/components/CheckBox/index.ts @@ -0,0 +1,2 @@ +export * from "./CheckBox"; +export { default } from "./CheckBox"; diff --git a/src/core/client/ui/components/Flex/Flex.tsx b/src/core/client/ui/components/Flex/Flex.tsx index 1d2dd932a..e648f2832 100644 --- a/src/core/client/ui/components/Flex/Flex.tsx +++ b/src/core/client/ui/components/Flex/Flex.tsx @@ -6,7 +6,7 @@ import { pascalCase } from "talk-common/utils"; import { withForwardRef, withStyles } from "talk-ui/hocs"; import { PropTypesOf } from "talk-ui/types"; -import * as styles from "./Flex.css"; +import styles from "./Flex.css"; interface InnerProps { /** diff --git a/src/core/client/ui/components/FormField/FormField.tsx b/src/core/client/ui/components/FormField/FormField.tsx index 64dab3140..9f878ffd8 100644 --- a/src/core/client/ui/components/FormField/FormField.tsx +++ b/src/core/client/ui/components/FormField/FormField.tsx @@ -5,7 +5,7 @@ import { StatelessComponent } from "react"; import { withStyles } from "talk-ui/hocs"; import HorizontalGutter from "../HorizontalGutter"; -import * as styles from "./FormField.css"; +import styles from "./FormField.css"; interface InnerProps { children: ReactNode; diff --git a/src/core/client/ui/components/HorizontalGutter/HorizontalGutter.css b/src/core/client/ui/components/HorizontalGutter/HorizontalGutter.css index aa588d983..ddd1d9134 100644 --- a/src/core/client/ui/components/HorizontalGutter/HorizontalGutter.css +++ b/src/core/client/ui/components/HorizontalGutter/HorizontalGutter.css @@ -17,6 +17,14 @@ margin: 0 !important; } } +.oneAndAHalf { + & > * { + margin: 0 0 calc(1.5 * var(--spacing-unit)) 0 !important; + } + & > *:last-child { + margin: 0 !important; + } +} .double { & > * { margin: 0 0 calc(2 * var(--spacing-unit)) 0 !important; diff --git a/src/core/client/ui/components/HorizontalGutter/HorizontalGutter.tsx b/src/core/client/ui/components/HorizontalGutter/HorizontalGutter.tsx index de93ba767..d661b8e86 100644 --- a/src/core/client/ui/components/HorizontalGutter/HorizontalGutter.tsx +++ b/src/core/client/ui/components/HorizontalGutter/HorizontalGutter.tsx @@ -4,7 +4,7 @@ import React, { HTMLAttributes, Ref, StatelessComponent } from "react"; import { withForwardRef, withStyles } from "talk-ui/hocs"; import { PropTypesOf } from "talk-ui/types"; -import * as styles from "./HorizontalGutter.css"; +import styles from "./HorizontalGutter.css"; interface InnerProps extends HTMLAttributes { /** @@ -13,7 +13,7 @@ interface InnerProps extends HTMLAttributes { */ classes: typeof styles; - size?: "half" | "full" | "double"; + size?: "half" | "full" | "double" | "oneAndAHalf"; /** The name of the HorizontalGutter to render */ children?: React.ReactNode; diff --git a/src/core/client/ui/components/Icon/Icon.tsx b/src/core/client/ui/components/Icon/Icon.tsx index 3baae6c27..02404e95c 100644 --- a/src/core/client/ui/components/Icon/Icon.tsx +++ b/src/core/client/ui/components/Icon/Icon.tsx @@ -4,7 +4,7 @@ import React, { HTMLAttributes, Ref, StatelessComponent } from "react"; import { withForwardRef, withStyles } from "talk-ui/hocs"; import { PropTypesOf } from "talk-ui/types"; -import * as styles from "./Icon.css"; +import styles from "./Icon.css"; interface InnerProps extends HTMLAttributes { /** diff --git a/src/core/client/ui/components/InputDescription/InputDescription.tsx b/src/core/client/ui/components/InputDescription/InputDescription.tsx index ae84ed141..8e0fa9374 100644 --- a/src/core/client/ui/components/InputDescription/InputDescription.tsx +++ b/src/core/client/ui/components/InputDescription/InputDescription.tsx @@ -1,10 +1,12 @@ import React, { ReactNode, StatelessComponent } from "react"; import { Typography } from "talk-ui/components"; +import { PropTypesOf } from "talk-ui/types"; interface InputDescriptionProps { children: ReactNode; id?: string; className?: string; + container?: PropTypesOf["container"]; } const InputDescription: StatelessComponent = props => { diff --git a/src/core/client/ui/components/InputLabel/InputLabel.tsx b/src/core/client/ui/components/InputLabel/InputLabel.tsx index 5445d8ccd..d66d010e9 100644 --- a/src/core/client/ui/components/InputLabel/InputLabel.tsx +++ b/src/core/client/ui/components/InputLabel/InputLabel.tsx @@ -3,7 +3,7 @@ import React, { ReactNode } from "react"; import { StatelessComponent } from "react"; import { withStyles } from "talk-ui/hocs"; import Typography from "../Typography"; -import * as styles from "./InputLabel.css"; +import styles from "./InputLabel.css"; export interface InputLabelProps { /** diff --git a/src/core/client/ui/components/Message/Message.tsx b/src/core/client/ui/components/Message/Message.tsx index 7547d8442..ae46c0ff0 100644 --- a/src/core/client/ui/components/Message/Message.tsx +++ b/src/core/client/ui/components/Message/Message.tsx @@ -1,7 +1,7 @@ import cn from "classnames"; import React, { ReactNode, StatelessComponent } from "react"; import { withStyles } from "talk-ui/hocs"; -import * as styles from "./Message.css"; +import styles from "./Message.css"; export interface MessageProps { /** diff --git a/src/core/client/ui/components/Message/MessageIcon.tsx b/src/core/client/ui/components/Message/MessageIcon.tsx index cd4d0ad13..63a80aef6 100644 --- a/src/core/client/ui/components/Message/MessageIcon.tsx +++ b/src/core/client/ui/components/Message/MessageIcon.tsx @@ -4,7 +4,7 @@ import React, { HTMLAttributes, Ref, StatelessComponent } from "react"; import Icon, { IconProps } from "talk-ui/components/Icon"; import { withForwardRef, withStyles } from "talk-ui/hocs"; -import * as styles from "./MessageIcon.css"; +import styles from "./MessageIcon.css"; interface InnerProps extends HTMLAttributes { /** diff --git a/src/core/client/ui/components/Popover/Popover.tsx b/src/core/client/ui/components/Popover/Popover.tsx index a1ad1122e..30b2f6a3b 100644 --- a/src/core/client/ui/components/Popover/Popover.tsx +++ b/src/core/client/ui/components/Popover/Popover.tsx @@ -11,7 +11,7 @@ import { import { withStyles } from "talk-ui/hocs"; import AriaInfo from "../AriaInfo"; -import * as styles from "./Popover.css"; +import styles from "./Popover.css"; type Placement = | "top-start" diff --git a/src/core/client/ui/components/RadioButton/RadioButton.css b/src/core/client/ui/components/RadioButton/RadioButton.css new file mode 100644 index 000000000..b7124ddac --- /dev/null +++ b/src/core/client/ui/components/RadioButton/RadioButton.css @@ -0,0 +1,78 @@ +.root { +} + +.input { + cursor: pointer; + position: absolute; /* take it out of document flow */ + opacity: 0; /* hide it */ +} + +.label { + composes: bodyCopy from "talk-ui/shared/typography.css"; + display: inline-flex; + align-items: center; + position: relative; + cursor: pointer; + user-select: none; +} + +.labelLight { + color: var(--palette-text-light); +} + +/* Box. */ +.input + .label:before { + content: ""; + margin-right: 10px; + display: inline-block; + width: 14px; + height: 14px; + background: var(--palette-common-white); + border: 1px solid var(--palette-text-primary); + border-radius: 50%; + box-sizing: border-box; +} + +/* Box focus */ +.label.focus:before { + outline-width: 3px; + outline-color: Highlight; + outline-color: -webkit-focus-ring-color; + outline-style: auto; +} + +/* Box checked */ +.input:checked + .label:before { + border: 1px solid var(--palette-primary-main); + background: var(--palette-common-white); +} + +/* Disabled state label. */ +.input:disabled + .label { + cursor: auto; + opacity: 0.6; +} + +/* Disabled box. */ +.input:disabled + .label:before { + box-shadow: none; + border: 1px solid var(--palette-grey-main); + background: var(--palette-grey-lightest); +} + +/* Checkmark. Could be replaced with an image */ +.input:checked + .label:after { + content: ""; + background: var(--palette-primary-main); + border-radius: 50%; + position: absolute; + left: 3px; + top: 6px; + width: 8px; + height: 8px; + box-sizing: border-box; +} + +.input:checked:disabled + .label:after { + background: var(--palette-text-primary); +} diff --git a/src/core/client/ui/components/RadioButton/RadioButton.mdx b/src/core/client/ui/components/RadioButton/RadioButton.mdx new file mode 100644 index 000000000..20377f4bc --- /dev/null +++ b/src/core/client/ui/components/RadioButton/RadioButton.mdx @@ -0,0 +1,20 @@ +--- +name: RadioButton +menu: UI Kit +--- + +import { Playground, PropsTable } from 'docz' +import RadioButton from './RadioButton.tsx' +import HorizontalGutter from '../HorizontalGutter' + +# RadioButton + +## Basic Use + + + Yes I agree + I don't agree + Disabled + Disabled + Checked + + diff --git a/src/core/client/ui/components/RadioButton/RadioButton.spec.tsx b/src/core/client/ui/components/RadioButton/RadioButton.spec.tsx new file mode 100644 index 000000000..f0520192c --- /dev/null +++ b/src/core/client/ui/components/RadioButton/RadioButton.spec.tsx @@ -0,0 +1,18 @@ +import React from "react"; +import TestRenderer from "react-test-renderer"; + +import { PropTypesOf } from "talk-ui/types"; + +import RadioButton from "./RadioButton"; + +it("renders correctly", () => { + const props: PropTypesOf = { + className: "custom", + id: "radioID", + name: "key", + value: "true", + children: "Yes I agree", + }; + const renderer = TestRenderer.create(); + expect(renderer.toJSON()).toMatchSnapshot(); +}); diff --git a/src/core/client/ui/components/RadioButton/RadioButton.tsx b/src/core/client/ui/components/RadioButton/RadioButton.tsx new file mode 100644 index 000000000..924760a43 --- /dev/null +++ b/src/core/client/ui/components/RadioButton/RadioButton.tsx @@ -0,0 +1,88 @@ +import cn from "classnames"; +import React, { ChangeEvent, Component, EventHandler, FocusEvent } from "react"; +import uuid from "uuid/v4"; + +import { Flex } from "talk-ui/components"; +import { withKeyboardFocus, withStyles } from "talk-ui/hocs"; + +import styles from "./RadioButton.css"; +export interface RadioButtonProps { + id?: string; + /** + * The content value of the component. + */ + value?: string; + + checked?: boolean; + + /** + * Convenient prop to override the root styling. + */ + className?: string; + /** + * Override or extend the styles applied to the component. + */ + classes: typeof styles; + /** + * Mark as readonly + */ + readOnly?: boolean; + /** + * Name + */ + name?: string; + /** + * onChange + */ + onChange?: EventHandler>; + + disabled?: boolean; + children: React.ReactNode; + /** + * Display a light text. + */ + light?: boolean; + + // These handlers are passed down by the `withKeyboardFocus` HOC. + onFocus: EventHandler>; + onBlur: EventHandler>; + keyboardFocus: boolean; +} + +class RadioButton extends Component { + public state = { + randomID: uuid(), + }; + public render() { + const { + className, + classes, + id, + light, + children, + keyboardFocus, + ...rest + } = this.props; + + const rootClassName = cn(classes.root, className); + const finalID = this.props.id || this.state.randomID; + + return ( + + + + + ); + } +} + +const enhanced = withStyles(styles)(withKeyboardFocus(RadioButton)); +export default enhanced; diff --git a/src/core/client/ui/components/RadioButton/__snapshots__/RadioButton.spec.tsx.snap b/src/core/client/ui/components/RadioButton/__snapshots__/RadioButton.spec.tsx.snap new file mode 100644 index 000000000..48afcbe9f --- /dev/null +++ b/src/core/client/ui/components/RadioButton/__snapshots__/RadioButton.spec.tsx.snap @@ -0,0 +1,23 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`renders correctly 1`] = ` +
    + + +
    +`; diff --git a/src/core/client/ui/components/RadioButton/index.ts b/src/core/client/ui/components/RadioButton/index.ts new file mode 100644 index 000000000..ed12488fa --- /dev/null +++ b/src/core/client/ui/components/RadioButton/index.ts @@ -0,0 +1,2 @@ +export * from "./RadioButton"; +export { default } from "./RadioButton"; diff --git a/src/core/client/ui/components/RelativeTime/RelativeTime.tsx b/src/core/client/ui/components/RelativeTime/RelativeTime.tsx index 265a64978..247f43b92 100644 --- a/src/core/client/ui/components/RelativeTime/RelativeTime.tsx +++ b/src/core/client/ui/components/RelativeTime/RelativeTime.tsx @@ -6,7 +6,7 @@ import { UIContext } from "talk-ui/components"; import { withForwardRef, withStyles } from "talk-ui/hocs"; import { PropTypesOf } from "talk-ui/types"; -import * as styles from "./RelativeTime.css"; +import styles from "./RelativeTime.css"; interface InnerProps { date: string; diff --git a/src/core/client/ui/components/SelectField/SelectField.tsx b/src/core/client/ui/components/SelectField/SelectField.tsx index 64e595092..680e1b59b 100644 --- a/src/core/client/ui/components/SelectField/SelectField.tsx +++ b/src/core/client/ui/components/SelectField/SelectField.tsx @@ -1,16 +1,11 @@ import cn from "classnames"; -import React, { - ChangeEvent, - EventHandler, - FocusEvent, - MouseEvent, -} from "react"; +import React, { ChangeEvent, EventHandler, FocusEvent } from "react"; import { StatelessComponent } from "react"; import { withKeyboardFocus, withStyles } from "talk-ui/hocs"; import Icon from "../Icon"; -import * as styles from "./SelectField.css"; +import styles from "./SelectField.css"; export interface SelectFieldProps { /** @@ -42,7 +37,6 @@ export interface SelectFieldProps { // These handlers are passed down by the `withKeyboardFocus` HOC. onFocus: EventHandler>; onBlur: EventHandler>; - onMouseDown: EventHandler>; keyboardFocus: boolean; } diff --git a/src/core/client/ui/components/SelectField/__snapshots__/SelectField.spec.tsx.snap b/src/core/client/ui/components/SelectField/__snapshots__/SelectField.spec.tsx.snap index 918a32133..8808ae325 100644 --- a/src/core/client/ui/components/SelectField/__snapshots__/SelectField.spec.tsx.snap +++ b/src/core/client/ui/components/SelectField/__snapshots__/SelectField.spec.tsx.snap @@ -13,7 +13,6 @@ exports[`renders correctly 1`] = ` onBlur={[Function]} onChange={[Function]} onFocus={[Function]} - onMouseDown={[Function]} value="pie" /> >; disabled?: boolean; + + autoComplete?: AllHTMLAttributes["autoComplete"]; + autoCorrect?: AllHTMLAttributes["autoCorrect"]; + autoCapitalize?: AllHTMLAttributes["autoCapitalize"]; + spellCheck?: AllHTMLAttributes["spellCheck"]; } const TextField: StatelessComponent = props => { diff --git a/src/core/client/ui/components/TextLink/TextLink.css b/src/core/client/ui/components/TextLink/TextLink.css new file mode 100644 index 000000000..b097ef9d8 --- /dev/null +++ b/src/core/client/ui/components/TextLink/TextLink.css @@ -0,0 +1,4 @@ +.root { + color: var(--palette-primary-main); + text-decoration: underline; +} diff --git a/src/core/client/ui/components/TextLink/TextLink.mdx b/src/core/client/ui/components/TextLink/TextLink.mdx new file mode 100644 index 000000000..8f6f42813 --- /dev/null +++ b/src/core/client/ui/components/TextLink/TextLink.mdx @@ -0,0 +1,19 @@ +--- +name: TextLink +menu: UI Kit +--- + +import { Playground, PropsTable } from 'docz' +import TextLink from './TextLink.tsx' +import HorizontalGutter from '../HorizontalGutter' + +# TextLink + +## Basic Use + + + Well... Hello there. + + + + diff --git a/src/core/client/ui/components/TextLink/TextLink.spec.tsx b/src/core/client/ui/components/TextLink/TextLink.spec.tsx new file mode 100644 index 000000000..c1164ba8e --- /dev/null +++ b/src/core/client/ui/components/TextLink/TextLink.spec.tsx @@ -0,0 +1,14 @@ +import React from "react"; +import TestRenderer from "react-test-renderer"; + +import { PropTypesOf } from "talk-ui/types"; + +import TextLink from "./TextLink"; + +it("renders correctly", () => { + const props: PropTypesOf = { + className: "custom", + }; + const renderer = TestRenderer.create(Hello); + expect(renderer.toJSON()).toMatchSnapshot(); +}); diff --git a/src/core/client/ui/components/TextLink/TextLink.tsx b/src/core/client/ui/components/TextLink/TextLink.tsx new file mode 100644 index 000000000..0e02cb1ff --- /dev/null +++ b/src/core/client/ui/components/TextLink/TextLink.tsx @@ -0,0 +1,31 @@ +import cn from "classnames"; +import React, { AnchorHTMLAttributes } from "react"; +import { StatelessComponent } from "react"; +import { withStyles } from "talk-ui/hocs"; +import styles from "./TextLink.css"; + +interface Props extends AnchorHTMLAttributes { + /** + * Override or extend the styles applied to the component. + */ + classes: typeof styles; +} + +const TextLinkProps: StatelessComponent = props => { + const { className, children, classes, ...rest } = props; + + const rootClassName = cn(classes.root, className); + + return ( + + {children} + + ); +}; + +const enhanced = withStyles(styles)(TextLinkProps); +export default enhanced; diff --git a/src/core/client/ui/components/TextLink/__snapshots__/TextLink.spec.tsx.snap b/src/core/client/ui/components/TextLink/__snapshots__/TextLink.spec.tsx.snap new file mode 100644 index 000000000..f0947cfb7 --- /dev/null +++ b/src/core/client/ui/components/TextLink/__snapshots__/TextLink.spec.tsx.snap @@ -0,0 +1,10 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`renders correctly 1`] = ` + + Hello + +`; diff --git a/src/core/client/ui/components/TextLink/index.ts b/src/core/client/ui/components/TextLink/index.ts new file mode 100644 index 000000000..423f16141 --- /dev/null +++ b/src/core/client/ui/components/TextLink/index.ts @@ -0,0 +1 @@ +export { default } from "./TextLink"; diff --git a/src/core/client/ui/components/Typography/Typography.tsx b/src/core/client/ui/components/Typography/Typography.tsx index 8464f8441..9b7a5b36c 100644 --- a/src/core/client/ui/components/Typography/Typography.tsx +++ b/src/core/client/ui/components/Typography/Typography.tsx @@ -5,7 +5,7 @@ import { HTMLAttributes, ReactNode, StatelessComponent } from "react"; import { withForwardRef, withStyles } from "talk-ui/hocs"; import { PropTypesOf } from "talk-ui/types"; -import * as styles from "./Typography.css"; +import styles from "./Typography.css"; type Variant = | "heading1" diff --git a/src/core/client/ui/components/index.ts b/src/core/client/ui/components/index.ts index fdd1d41a8..980d962d1 100644 --- a/src/core/client/ui/components/index.ts +++ b/src/core/client/ui/components/index.ts @@ -24,3 +24,6 @@ export { default as Message, MessageIcon } from "./Message"; export { Tab, TabBar, TabContent, TabPane } from "./Tabs"; export { StepBar, Step } from "./Steps"; export { SelectField, Option, OptGroup } from "./SelectField"; +export { default as TextLink } from "./TextLink"; +export { default as CheckBox } from "./CheckBox"; +export { default as RadioButton } from "./RadioButton"; diff --git a/src/core/client/ui/hocs/withKeyboardFocus.tsx b/src/core/client/ui/hocs/withKeyboardFocus.tsx index 230ce8f77..fa8892db2 100644 --- a/src/core/client/ui/hocs/withKeyboardFocus.tsx +++ b/src/core/client/ui/hocs/withKeyboardFocus.tsx @@ -1,11 +1,10 @@ import * as React from "react"; -import { FocusEvent, MouseEvent } from "react"; +import { FocusEvent } from "react"; import { DefaultingInferableComponentEnhancer, hoistStatics } from "recompose"; interface InjectedProps { onFocus: React.EventHandler>; onBlur: React.EventHandler>; - onMouseDown: React.EventHandler>; keyboardFocus: boolean; } @@ -24,6 +23,15 @@ const withKeyboardFocus: DefaultingInferableComponentEnhancer< keyboardFocus: false, }; + constructor(props: any) { + super(props); + document.addEventListener("mousedown", this.handleMouseDown); + } + + public componentWillUnmount() { + document.removeEventListener("mousedown", this.handleMouseDown); + } + private handleFocus: React.EventHandler> = event => { if (this.props.onFocus) { this.props.onFocus(event); @@ -41,10 +49,7 @@ const withKeyboardFocus: DefaultingInferableComponentEnhancer< this.setState({ keyboardFocus: false }); }; - private handleMouseDown: React.EventHandler> = event => { - if (this.props.onMouseDown) { - this.props.onMouseDown(event); - } + private handleMouseDown = () => { this.lastMouseDownTime = new Date().getTime(); }; @@ -54,7 +59,6 @@ const withKeyboardFocus: DefaultingInferableComponentEnhancer< {...this.props} onFocus={this.handleFocus} onBlur={this.handleBlur} - onMouseDown={this.handleMouseDown} keyboardFocus={this.state.keyboardFocus} /> ); diff --git a/src/core/client/ui/shared/typography.css b/src/core/client/ui/shared/typography.css index 77b44280a..36d124aaa 100644 --- a/src/core/client/ui/shared/typography.css +++ b/src/core/client/ui/shared/typography.css @@ -104,7 +104,7 @@ font-size: calc(16rem / var(--rem-base)); font-weight: var(--font-weight-regular); font-family: var(--font-family-sans-serif); - line-height: calc(18em / 16); + line-height: calc(20em / 16); letter-spacing: calc(0.2em / 16); color: var(--palette-text-primary); } diff --git a/src/core/server/graph/common/middleware/extensions/logger.ts b/src/core/server/graph/common/middleware/extensions/logger.ts index 76afbc750..0bbb27d5c 100644 --- a/src/core/server/graph/common/middleware/extensions/logger.ts +++ b/src/core/server/graph/common/middleware/extensions/logger.ts @@ -1,6 +1,16 @@ import { formatApolloErrors } from "apollo-server-errors"; -import { GraphQLError } from "graphql"; -import { GraphQLExtension, GraphQLResponse } from "graphql-extensions"; +import { + DocumentNode, + ExecutionArgs, + GraphQLError, + OperationDefinitionNode, +} from "graphql"; +import { + EndHandler, + GraphQLExtension, + GraphQLResponse, +} from "graphql-extensions"; +import now from "performance-now"; import CommonContext from "talk-server/graph/common/context"; @@ -15,11 +25,49 @@ export class LoggerExtension implements GraphQLExtension { return err; }; - public requestDidStart(o: { - operationName?: string; - context: CommonContext; - }) { - o.context.logger.debug({ operationName: o.operationName }, "graphql query"); + private getOperationMetadata(doc: DocumentNode) { + if (doc.kind === "Document") { + const operationDefinition = doc.definitions.find( + ({ kind }) => kind === "OperationDefinition" + ) as OperationDefinitionNode | undefined; + if (operationDefinition) { + let operationName: string | undefined; + if (operationDefinition.name) { + operationName = operationDefinition.name.value; + } + + return { + operationName, + operation: operationDefinition.operation, + }; + } + } + + return {}; + } + + public executionDidStart(o: { + executionArgs: ExecutionArgs; + }): EndHandler | void { + // Only try to log things if the context is provided. + if (o.executionArgs.contextValue) { + // Grab the start time so we can calculate the time it takes to execute + // the graph query. + const startTime = now(); + return () => { + // Compute the end time. + const responseTime = Math.round(now() - startTime); + + // Log out the details of the request. + o.executionArgs.contextValue.logger.debug( + { + responseTime, + ...this.getOperationMetadata(o.executionArgs.document), + }, + "graphql query" + ); + }; + } } public willSendResponse(o: { diff --git a/src/core/server/graph/tenant/resolvers/facebook_auth_integration.ts b/src/core/server/graph/tenant/resolvers/facebook_auth_integration.ts new file mode 100644 index 000000000..7b09a3c52 --- /dev/null +++ b/src/core/server/graph/tenant/resolvers/facebook_auth_integration.ts @@ -0,0 +1,26 @@ +import { constructTenantURL, reconstructURL } from "talk-server/app/url"; +import { + GQLFacebookAuthIntegration, + GQLFacebookAuthIntegrationTypeResolver, +} from "talk-server/graph/tenant/schema/__generated__/types"; + +const FacebookAuthIntegration: GQLFacebookAuthIntegrationTypeResolver< + GQLFacebookAuthIntegration +> = { + callbackURL: (integration, args, ctx) => { + const path = `/api/tenant/auth/facebook/callback`; + + // If the request is available, then prefer it over building from the tenant + // as the tenant does not include the port number. This should only really + // be a problem if the graph API is called internally. + if (ctx.req) { + return reconstructURL(ctx.req, path); + } + + // Note that when constructing the callback url with the tenant, the port + // information is lost. + return constructTenantURL(ctx.config, ctx.tenant, path); + }, +}; + +export default FacebookAuthIntegration; diff --git a/src/core/server/graph/tenant/resolvers/google_auth_integration.ts b/src/core/server/graph/tenant/resolvers/google_auth_integration.ts new file mode 100644 index 000000000..b6293b562 --- /dev/null +++ b/src/core/server/graph/tenant/resolvers/google_auth_integration.ts @@ -0,0 +1,26 @@ +import { constructTenantURL, reconstructURL } from "talk-server/app/url"; +import { + GQLGoogleAuthIntegration, + GQLGoogleAuthIntegrationTypeResolver, +} from "talk-server/graph/tenant/schema/__generated__/types"; + +const GoogleAuthIntegration: GQLGoogleAuthIntegrationTypeResolver< + GQLGoogleAuthIntegration +> = { + callbackURL: (integration, args, ctx) => { + const path = `/api/tenant/auth/google/callback`; + + // If the request is available, then prefer it over building from the tenant + // as the tenant does not include the port number. This should only really + // be a problem if the graph API is called internally. + if (ctx.req) { + return reconstructURL(ctx.req, path); + } + + // Note that when constructing the callback url with the tenant, the port + // information is lost. + return constructTenantURL(ctx.config, ctx.tenant, path); + }, +}; + +export default GoogleAuthIntegration; diff --git a/src/core/server/graph/tenant/resolvers/index.ts b/src/core/server/graph/tenant/resolvers/index.ts index e94466653..add6ed2c9 100644 --- a/src/core/server/graph/tenant/resolvers/index.ts +++ b/src/core/server/graph/tenant/resolvers/index.ts @@ -6,6 +6,8 @@ import { GQLResolver } from "talk-server/graph/tenant/schema/__generated__/types import AuthIntegrations from "./auth_integrations"; import Comment from "./comment"; import CommentCounts from "./comment_counts"; +import FacebookAuthIntegration from "./facebook_auth_integration"; +import GoogleAuthIntegration from "./google_auth_integration"; import Mutation from "./mutation"; import OIDCAuthIntegration from "./oidc_auth_integration"; import Profile from "./profile"; @@ -20,6 +22,8 @@ const Resolvers: GQLResolver = { Cursor, Mutation, OIDCAuthIntegration, + FacebookAuthIntegration, + GoogleAuthIntegration, Profile, Query, Time, diff --git a/src/core/server/graph/tenant/schema/schema.graphql b/src/core/server/graph/tenant/schema/schema.graphql index c731e8c46..38f7d6fee 100644 --- a/src/core/server/graph/tenant/schema/schema.graphql +++ b/src/core/server/graph/tenant/schema/schema.graphql @@ -275,7 +275,7 @@ type LocalAuthIntegration { displayed. If the value of targetFilter is null, then the authentication integration should be displayed in all targets. """ - targetFilter: AuthenticationTargetFilter + targetFilter: AuthenticationTargetFilter! } ########################## @@ -301,7 +301,7 @@ type SSOAuthIntegration { displayed. If the value of targetFilter is null, then the authentication integration should be displayed in all targets. """ - targetFilter: AuthenticationTargetFilter + targetFilter: AuthenticationTargetFilter! """ key is the secret that is used to sign tokens. @@ -385,7 +385,7 @@ type OIDCAuthIntegration { displayed. If the value of targetFilter is null, then the authentication integration should be displayed in all targets. """ - targetFilter: AuthenticationTargetFilter + targetFilter: AuthenticationTargetFilter! """ name is the label assigned to reference the provider of the OIDC integration, @@ -462,10 +462,17 @@ type GoogleAuthIntegration { displayed. If the value of targetFilter is null, then the authentication integration should be displayed in all targets. """ - targetFilter: AuthenticationTargetFilter + targetFilter: AuthenticationTargetFilter! clientID: String @auth(roles: [ADMIN]) clientSecret: String @auth(roles: [ADMIN]) + + """ + callbackURL is the URL that the user should be redirected to in order to start + the authentication flow. This field is not stored, and is instead computed from + the Tenant. + """ + callbackURL: String! } ########################## @@ -486,10 +493,17 @@ type FacebookAuthIntegration { displayed. If the value of targetFilter is null, then the authentication integration should be displayed in all targets. """ - targetFilter: AuthenticationTargetFilter + targetFilter: AuthenticationTargetFilter! clientID: String @auth(roles: [ADMIN]) clientSecret: String @auth(roles: [ADMIN]) + + """ + callbackURL is the URL that the user should be redirected to in order to start + the authentication flow. This field is not stored, and is instead computed from + the Tenant. + """ + callbackURL: String! } ########################## @@ -530,7 +544,7 @@ type Auth { displayName contains configuration related to the use of Display Names across AuthIntegrations. """ - displayName: AuthDisplayNameConfiguration @auth(roles: [ADMIN]) + displayName: AuthDisplayNameConfiguration! @auth(roles: [ADMIN]) } ################################################################################ @@ -1598,11 +1612,25 @@ input SettingsAuthIntegrationsInput { facebook: SettingsFacebookAuthIntegrationInput } +input SettingsAuthDisplayNameInput { + """ + enabled when true will allow the display name to be used by other + AuthIntegrations. + """ + enabled: Boolean! +} + """ Auth contains all the settings related to authentication and authorization. """ input SettingsAuthInput { + """ + " + displayName allows configuration related to Display Names. + """ + displayName: SettingsAuthDisplayNameInput + """ integrations are the set of configurations for the variations of authentication solutions. @@ -2090,6 +2118,24 @@ type RegenerateSSOKeyPayload { ################## input CreateOIDCAuthIntegrationConfigurationInput { + """ + enabled, when true, allows the integration to be enabled. + """ + enabled: Boolean + + """ + allowRegistration when true will allow users that have not signed up + before with this authentication integration to sign up. + """ + allowRegistration: Boolean + + """ + targetFilter will restrict where the authentication integration should be + displayed. If the value of targetFilter is null, then the authentication + integration should be displayed in all targets. + """ + targetFilter: SettingsAuthenticationTargetFilterInput + """ name is the label assigned to reference the provider of the OIDC integration, and will be used in situations where the name of the provider needs to be diff --git a/src/core/server/models/tenant.ts b/src/core/server/models/tenant.ts index ceb9e2ad1..7636029dc 100644 --- a/src/core/server/models/tenant.ts +++ b/src/core/server/models/tenant.ts @@ -1,9 +1,10 @@ import crypto from "crypto"; +import { isNull, omitBy } from "lodash"; import { Db } from "mongodb"; import uuid from "uuid"; import { DeepPartial, Omit, Sub } from "talk-common/types"; -import { dotize } from "talk-common/utils/dotize"; +import { dotize, DotizeOptions } from "talk-common/utils/dotize"; import { GQLMODERATION_MODE, GQLOIDCAuthIntegration, @@ -14,6 +15,10 @@ function collection(db: Db) { return db.collection>("tenants"); } +function dotizeDropNull(o: Record, options?: DotizeOptions) { + return omitBy(dotize(o, options), isNull); +} + export interface TenantResource { readonly tenant_id: string; } @@ -83,23 +88,46 @@ export async function createTenant(mongo: Db, input: CreateTenantInput) { banned: [], }, auth: { + displayName: { + enabled: false, + }, integrations: { local: { enabled: true, allowRegistration: true, + targetFilter: { + admin: true, + stream: true, + }, }, sso: { enabled: false, allowRegistration: false, + targetFilter: { + admin: true, + stream: true, + }, + key: generateSSOKey(), + keyGeneratedAt: new Date(), }, oidc: [], google: { enabled: false, allowRegistration: false, + callbackURL: "" as any, // FIXME: this should not be required + targetFilter: { + admin: true, + stream: true, + }, }, facebook: { enabled: false, allowRegistration: false, + callbackURL: "", // FIXME: this should not be required + targetFilter: { + admin: true, + stream: true, + }, }, }, }, @@ -201,7 +229,7 @@ export async function updateTenant( const result = await collection(db).findOneAndUpdate( { id }, // Only update fields that have been updated. - { $set: dotize(update, { embedArrays: true }) }, + { $set: dotizeDropNull(update, { embedArrays: true }) }, // False to return the updated document instead of the original // document. { returnOriginal: false } @@ -210,26 +238,26 @@ export async function updateTenant( return result.value || null; } +function generateSSOKey() { + // Generate a new key. We generate a key of minimum length 32 up to 37 bytes, + // as 16 was the minimum length recommended. + // + // Reference: https://security.stackexchange.com/a/96176 + return crypto.randomBytes(32 + Math.floor(Math.random() * 5)).toString("hex"); +} + /** * regenerateTenantSSOKey will regenerate the SSO key used for Single Sing-On * for the specified Tenant. All existing user sessions signed with the old * secret will be invalidated. */ export async function regenerateTenantSSOKey(db: Db, id: string) { - // Generate a new key. We generate a key of minimum length 32 up to 37 bytes, - // as 16 was the minimum length recommended. - // - // Reference: https://security.stackexchange.com/a/96176 - const key = crypto - .randomBytes(32 + Math.floor(Math.random() * 5)) - .toString("hex"); - // Construct the update. const update: DeepPartial = { auth: { integrations: { sso: { - key, + key: generateSSOKey(), keyGeneratedAt: new Date(), }, }, @@ -320,7 +348,7 @@ export async function updateTenantOIDCAuthIntegration( const result = await collection(mongo).findOneAndUpdate( { id }, { - $set: dotize({ + $set: dotizeDropNull({ "auth.integrations.oidc.$[oidc]": input, }), }, diff --git a/src/core/server/services/tenant/index.ts b/src/core/server/services/tenant/index.ts index 0dfba01bb..f19df2675 100644 --- a/src/core/server/services/tenant/index.ts +++ b/src/core/server/services/tenant/index.ts @@ -137,6 +137,10 @@ export async function createOIDCAuthIntegration( const result = await createTenantOIDCAuthIntegration(mongo, tenant.id, { enabled: false, allowRegistration: false, + targetFilter: { + admin: true, + stream: true, + }, ...input, }); if (!result.wasCreated || !result.tenant) { diff --git a/src/locales/en-US/admin.ftl b/src/locales/en-US/admin.ftl index 2867cd485..9e72bc4cf 100644 --- a/src/locales/en-US/admin.ftl +++ b/src/locales/en-US/admin.ftl @@ -25,3 +25,82 @@ login-signIn-passwordTextField = .placeholder = Password login-signIn-signIn = Sign in + + +## Configure + +configure-unsavedInputWarning = + You have unsaved input. + Are you sure you want to leave this page? +configure-sideBarNavigation-authentication = Authentication +configure-sideBar-saveChanges = Save Changes + +# Authentication + +configure-auth-authIntegrations = Authentication Integrations +configure-auth-clientID = Client ID +configure-auth-clientSecret = Client Secret +configure-auth-configBoxEnabled = Enabled +configure-auth-targetFilterTalkAdmin = Talk Admin +configure-auth-targetFilterCommentStream = Comment Stream +configure-auth-redirectURI = Redirect URI +configure-auth-registration = Registration +configure-auth-registrationDescription = + Allow users that have not signed up before with this authentication + integration to register for a new account. +configure-auth-registrationCheckBox = Allow Registration + +configure-auth-facebook-loginWith = Login with Facebook +configure-auth-facebook-toEnableIntegration = + To enable the integration with Facebook Authentication, + you need to create and set up a web application. + For more information visit: . +configure-auth-facebook-useLoginOn = Use Facebook login on + +configure-auth-google-loginWith = Login with Google +configure-auth-google-toEnableIntegration = + To enable the integration with Google Authentication you need + to create and set up a web application. For more information visit: + . +configure-auth-google-useLoginOn = Use Google login on + +configure-auth-sso-loginWith = Login with Single Sign On +configure-auth-sso-useLoginOn = Use Single Sign On login on +configure-auth-sso-key = Key +configure-auth-sso-regenerate = Regenerate +configure-auth-sso-regenerateAt = KEY GENERATED AT: + { DATETIME($date, year: "numeric", month: "numeric", day: "numeric", hour: "numeric", minute: "numeric") } +configure-auth-sso-regenerateWarning = + Regenerating a key will invalidate any existing user sessions, + and all signed-in users will be signed out. + +configure-auth-local-loginWith = Login with Email Authentication +configure-auth-local-useLoginOn = Use Email Authentication login on + +configure-auth-displayNamesConfig-title = Display Names +configure-auth-displayNamesConfig-explanationShort = + Some Authentication Integrations include a Display Name as well as a User Name. +configure-auth-displayNamesConfig-explanationLong = + A User Name has to be unique (there can only be one Juan_Doe, for example), + whereas a Display Name does not. If your authentication provider allows for Display Names, + you can enable this option. This allows for fewer strange names (Juan_Doe23245) – + however it could also be used to spoof/impersonate another user. +configure-auth-displayNamesConfig-showDisplayNames = Show Display Names (if available) +configure-auth-displayNamesConfig-hideDisplayNames = Hide Display Names (if available) + +configure-auth-oidc-loginWith = Login with OpenID Connect +configure-auth-oidc-toLearnMore = To learn more: +configure-auth-oidc-redirectDescription = + For OpenID Connect, your Redirect URI will not appear until you after you save this integration. +configure-auth-oidc-providerName = Provider Name +configure-auth-oidc-providerNameDescription = + The provider of the OpenID Connect integration. This will be used when the name of the provider + needs to be displayed, e.g. “Log in with <Facebook>”. +configure-auth-oidc-issuer = Issuer +configure-auth-oidc-issuerDescription = + After entering your Issuer information, click the Discover button to have Talk complete + the remaining fields. You may also enter the information manually. +configure-auth-oidc-authorizationURL = Authorization URL +configure-auth-oidc-tokenURL = Token URL +configure-auth-oidc-jwksURI = JWKS URI +configure-auth-oidc-useLoginOn = Use OpenID Connect login on diff --git a/src/locales/en-US/framework.ftl b/src/locales/en-US/framework.ftl index ce96259c6..13cbd0fee 100644 --- a/src/locales/en-US/framework.ftl +++ b/src/locales/en-US/framework.ftl @@ -68,3 +68,8 @@ framework-timeago = [ago] {framework-timeago-time} ago [noSuffix] {framework-timeago-time} } + +## Components + +framework-copyButton-copy = Copy +framework-copyButton-copied = Copied diff --git a/src/locales/en-US/stream.ftl b/src/locales/en-US/stream.ftl index 30b16047d..e912972b2 100644 --- a/src/locales/en-US/stream.ftl +++ b/src/locales/en-US/stream.ftl @@ -28,8 +28,6 @@ comments-stream-loadMore = Load More comments-replyList-showAll = Show All comments-permalinkButton-share = Share -comments-permalinkPopover-copy = Copy -comments-permalinkPopover-copied = Copied comments-permalinkView-viewFullDiscussion = View Full Discussion comments-permalinkView-commentNotFound = Comment not found