mirror of
https://github.com/wassname/talk.git
synced 2026-09-11 12:51:33 +08:00
[CORL-729] Upgrade Final Form & improve tests (#2735)
* CORL-729 Upgrade final form, fix and improve tests This is a squashed rebase from these commits: a300b31c23ab11e5e6f0668bc03ece7697360aaa feat: error on optimisic response warnings during test dd8a9776865ec41d346e23ae0743d0d4fb0caa21 fix: turn off @typescript-eslint/prefer-regexp-exec rule b995daacf1722cace60d755e672cb6a3a20d6bc2 feat: mute false warnings in test e44f9e28307cd63a82c1fb7ac013667dd7b7bc46 fix: wrap remaining tests with act afbd4329b97f3dbc9f873ea4ff234d98bb651ccf feat: fail when act(async () => ...) without await warnings 51dfb60b7d75411ba2e1a28db33f4aba5cf84de1 feat: fail tests with act warnings 97f93546ed8113e207882411eb4cdb7675b0796c fix: mock window.resizeTo globally in tests 850958b8c4d2fc0aca67ae580296433af223f8ab fix: more tests with act 24c05ab88e9a416e4962acc3f20f2c764ba07657 fix: wrap charCountEditComment test in acts ed590b82d147470bba74055dc682e6b70d2e76fb fix signInWithEmail 4a2b9402cb6ce9565d99ae1a950eaa422ff603c3 fix: PostCommentFormContainer 815ebe6ef364d954d4bd0a35495934c9d014170b fix: use final form initialize instead of reset and remove obsolete d3101f2112ed3ffe8d06609620e31e6655d2cf6d Merge branch 'feature/CORL-729-final-form' of https://github.com/coralproject/talk into feature/CORL-729-final-form a0658da610a5f39b6fae78ffb8dd291b22d54e50 fix: addEmailAddress 60f7fc99a44dfa49dfd401a0ef49c60973b3e8e3 fix: use proper act pattern in renderConfigure.spec.tsx d66bdfc2245c2b1ee03a1b3a3a56f1d5ba14ddc4 Stop propagation of Modal content click events (#2706) ec6689594136e22a5b9f05ea284162702dc4955d fix: use proper act pattern in createUsername.spec.tsx ef239496964a5f9a91ee1c4424ad81537c4f47fe fix: stream configuration c7e06a0c6aef6b299c41392af81f8a20855028bf fix: user proper act pattern in streamConfiguration 9712e659e394a898500ed649464ff14d4870e589 Merge branch 'feature/CORL-729-final-form' of https://github.com/coralproject/talk into feature/CORL-729-final-form 9e5cfbaf3593615b457055de23f187fa07edd4c4 fix: signIn test 99b44a4a1bbb7ff2cd44c6821ad33b80f90c4a99 fix: user proper act pattern in stories.spec.tsx ed7c1a92f93ab9aaa85ff92837b0ed21560cb358 fix: user proper act pattern in addEmailAddress a04b392cb2148b9a24791b062027796c409d053e fix: remove obsolete snapshots 59df67c0f9b9d26c74e2cca7d333f5868b0b202d fix: signUp test 7656f179df95b4cd96b37afbc88a1c3a2944fdf4 fix: use proper act pattern on createPassword 85246fbf1f9ab49ad3a09c11ab79bf537059b548 fix: use correct act() pattern in createUsername.spec.tsx d5239373a2d1bbed0bfe8c1ca62ef6a70ef5c7d9 fix: the correct way to use act on form submit :-) d84ecd168354f4acb422a5ddb725fb8faf9c3184 fix: moderation test d8df62ab1a6486144684ff917c47e6e375ffbe03 fix: reportComment test 2756e3184bb292168e8d34e201f340c3799941e6 fix: auth tests a28695dbdd313a7bc3dade9ac1f92d6ef0061526 Properly handle final-form actions in tests 2fafc8ea3458c5b15b66f3d65f0947672dd1a516 Update snapshots now that final form isn't overwriting props 1f9bbaec8678a7653124898ba4a2e84ddc1ef243 fix: prevent final form from overwriting field props f6c66c003d1917db2dcb3f757e8a303266c381fa fix: prevent final form fields overwrite out props 48d1fc7318ee4ba7bf72839127e9a0b1487c1729 chore: rename translation string 728373da5728a4e7c039bd0c3a3cf0037e9f5177 fix: purge relay metadata from request 7cdea925087a6b9b6e318bbb1b31b798be87dc2f fix: radiobuttons 9735bae79222219a81a28d458976a596201b650b chore: revert obsolete checks 0b556e1693584430a5814e81d87b0f233efd1a30 fix: refactor admin configure b245afc7b196035bcb454e031c966e63c77ce522 fix: implement withForm HOC 5787400051211f5d2e1773d7207f32b66b02a2a1 Update the Configure page form state to properly load form values 8c2af3e22a96a3d2e50e7f06fb45d1fb79cf0c8e Replace form.reset() with setTimeout(form.reset) 27d9c90e3f0166cc2db45db461619be15a3cb950 Update radio buttons and on/off fields to work with final-form updates b852dd14af85b14ff8e0d2823e1e83bf278b29b9 Replace any on OnSubmit with typed form submission interfaces f049a70aaf4872825ac3b2aa62dc5cb7f945290a (f) Preliminarily get Coral compiling with latest final-form libraries * feat: act is now actAndReturn * fix: print original filename and line number in custom console impl * feat: trace process warnings * fix: server warnings about potentially memory leak with too many listeners
This commit is contained in:
@@ -102,6 +102,8 @@ let typescriptTypeCheckingOverrides = {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
}],
|
}],
|
||||||
|
// 28.11.19: (cvle) Disabled because behavior of regexp.exec seems different than str.match?
|
||||||
|
"@typescript-eslint/prefer-regexp-exec": "off",
|
||||||
"@typescript-eslint/require-await": "off",
|
"@typescript-eslint/require-await": "off",
|
||||||
"@typescript-eslint/no-misused-promises": "off",
|
"@typescript-eslint/no-misused-promises": "off",
|
||||||
"@typescript-eslint/unbound-method": "off", // 10.10.19: (cvle) seems to give false positive.
|
"@typescript-eslint/unbound-method": "off", // 10.10.19: (cvle) seems to give false positive.
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ module.exports = {
|
|||||||
roots: ["<rootDir>/src"],
|
roots: ["<rootDir>/src"],
|
||||||
collectCoverageFrom: ["**/*.{js,jsx,mjs,ts,tsx}"],
|
collectCoverageFrom: ["**/*.{js,jsx,mjs,ts,tsx}"],
|
||||||
coveragePathIgnorePatterns: ["/node_modules/"],
|
coveragePathIgnorePatterns: ["/node_modules/"],
|
||||||
|
setupFilesAfterEnv: ["<rootDir>/src/core/server/test/setupTestFramework.ts"],
|
||||||
testMatch: ["**/*.spec.{js,jsx,mjs,ts,tsx}"],
|
testMatch: ["**/*.spec.{js,jsx,mjs,ts,tsx}"],
|
||||||
testPathIgnorePatterns: ["/node_modules/", "/client/"],
|
testPathIgnorePatterns: ["/node_modules/", "/client/"],
|
||||||
testEnvironment: "node",
|
testEnvironment: "node",
|
||||||
|
|||||||
Generated
+38
-8
@@ -4342,6 +4342,12 @@
|
|||||||
"@types/node": "*"
|
"@types/node": "*"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"@types/stack-trace": {
|
||||||
|
"version": "0.0.29",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/stack-trace/-/stack-trace-0.0.29.tgz",
|
||||||
|
"integrity": "sha512-TgfOX+mGY/NyNxJLIbDWrO9DjGoVSW9+aB8H2yy1fy32jsvxijhmyJI9fDFgvz3YP4lvJaq9DzdR/M1bOgVc9g==",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
"@types/stack-utils": {
|
"@types/stack-utils": {
|
||||||
"version": "1.0.1",
|
"version": "1.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-1.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-1.0.1.tgz",
|
||||||
@@ -14549,12 +14555,12 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"final-form": {
|
"final-form": {
|
||||||
"version": "4.11.0",
|
"version": "4.18.6",
|
||||||
"resolved": "https://registry.npmjs.org/final-form/-/final-form-4.11.0.tgz",
|
"resolved": "https://registry.npmjs.org/final-form/-/final-form-4.18.6.tgz",
|
||||||
"integrity": "sha512-uO0VhAEbWvV8LHBpBHoIpbYqonYBXyd8gpTYFEAPCHEy5tcNqdVX4EnWQoxKl//+U9Vk0kTUsnPOWiBP2PiOUg==",
|
"integrity": "sha512-LssWTXTGkoNv5WxowFTTUyC86oLYlEHH2glARBxOq8RpjiQdOyUyVG7qfPaCeOwoOw7Y5wrhSWdePyOydqSrCw==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"@babel/runtime": "^7.1.5"
|
"@babel/runtime": "^7.3.1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"finalhandler": {
|
"finalhandler": {
|
||||||
@@ -29389,12 +29395,30 @@
|
|||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"react-final-form": {
|
"react-final-form": {
|
||||||
"version": "4.0.2",
|
"version": "6.3.0",
|
||||||
"resolved": "https://registry.npmjs.org/react-final-form/-/react-final-form-4.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/react-final-form/-/react-final-form-6.3.0.tgz",
|
||||||
"integrity": "sha512-EdFWrT8nMWu5sHViuZ/VmlaYT+mLu/q5TMDWZZj5gnssUAWfgcila0QpptFNDg6+qNtepGgFh5ZPASlivoEXUA==",
|
"integrity": "sha512-jijhXR1fFGUBQwNOSqF4MK8XJO7Ynl1p8vcFsnQS0INSkGI52+4IagjUgtHj3w8EviIHPFK/Eflji6FELUl07w==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"@babel/runtime": "^7.1.2"
|
"@babel/runtime": "^7.4.5",
|
||||||
|
"ts-essentials": "^2.0.8"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"@babel/runtime": {
|
||||||
|
"version": "7.7.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.7.2.tgz",
|
||||||
|
"integrity": "sha512-JONRbXbTXc9WQE2mAZd1p0Z3DZ/6vaQIkgYMSTP3KjRCyd7rCZCcfhCyX+YjwcKxcZ82UrxbRD358bpExNgrjw==",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"regenerator-runtime": "^0.13.2"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"regenerator-runtime": {
|
||||||
|
"version": "0.13.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.3.tgz",
|
||||||
|
"integrity": "sha512-naKIZz2GQ8JWh///G7L3X6LaQUAMp2lvb1rvwwsURe/VXwD6VMfr+/1NuNw3ag8v2kY1aQ/go5SNn79O9JU7yw==",
|
||||||
|
"dev": true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"react-helmet": {
|
"react-helmet": {
|
||||||
@@ -33398,6 +33422,12 @@
|
|||||||
"integrity": "sha512-c3zayb8/kWWpycWYg87P71E1S1ZL6b6IJxfb5fvsUgsf0S2MVGaDhDXXjDMpdCpfWXqptc+4mXwmiy1ypXqRAA==",
|
"integrity": "sha512-c3zayb8/kWWpycWYg87P71E1S1ZL6b6IJxfb5fvsUgsf0S2MVGaDhDXXjDMpdCpfWXqptc+4mXwmiy1ypXqRAA==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"ts-essentials": {
|
||||||
|
"version": "2.0.12",
|
||||||
|
"resolved": "https://registry.npmjs.org/ts-essentials/-/ts-essentials-2.0.12.tgz",
|
||||||
|
"integrity": "sha512-3IVX4nI6B5cc31/GFFE+i8ey/N2eA0CZDbo6n0yrz0zDX8ZJ8djmU1p+XRz7G3is0F3bB3pu2pAroFdAWQKU3w==",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
"ts-invariant": {
|
"ts-invariant": {
|
||||||
"version": "0.4.4",
|
"version": "0.4.4",
|
||||||
"resolved": "https://registry.npmjs.org/ts-invariant/-/ts-invariant-0.4.4.tgz",
|
"resolved": "https://registry.npmjs.org/ts-invariant/-/ts-invariant-0.4.4.tgz",
|
||||||
|
|||||||
+7
-5
@@ -48,7 +48,7 @@
|
|||||||
"lint:scripts": "eslint 'scripts/**/*.{js,ts,tsx}'",
|
"lint:scripts": "eslint 'scripts/**/*.{js,ts,tsx}'",
|
||||||
"lint:graphql": "graphql-schema-linter src/core/server/graph/tenant/schema/schema.graphql",
|
"lint:graphql": "graphql-schema-linter src/core/server/graph/tenant/schema/schema.graphql",
|
||||||
"lint-fix": "npm run lint:server -- --fix && npm run lint:client -- --fix && npm run lint:scripts -- --fix",
|
"lint-fix": "npm run lint:server -- --fix && npm run lint:client -- --fix && npm run lint:scripts -- --fix",
|
||||||
"test": "node scripts/test.js --env=jsdom",
|
"test": "node --trace-warnings scripts/test.js --env=jsdom",
|
||||||
"tscheck": "npm-run-all --parallel tscheck:*",
|
"tscheck": "npm-run-all --parallel tscheck:*",
|
||||||
"tscheck:server": "tsc --project ./src/tsconfig.json --noEmit",
|
"tscheck:server": "tsc --project ./src/tsconfig.json --noEmit",
|
||||||
"tscheck:client": "tsc --project ./src/core/client/tsconfig.json --noEmit",
|
"tscheck:client": "tsc --project ./src/core/client/tsconfig.json --noEmit",
|
||||||
@@ -223,6 +223,7 @@
|
|||||||
"@types/simplemde": "^1.11.7",
|
"@types/simplemde": "^1.11.7",
|
||||||
"@types/sinon": "^7.0.11",
|
"@types/sinon": "^7.0.11",
|
||||||
"@types/source-map-support": "^0.5.0",
|
"@types/source-map-support": "^0.5.0",
|
||||||
|
"@types/stack-trace": "0.0.29",
|
||||||
"@types/stack-utils": "^1.0.1",
|
"@types/stack-utils": "^1.0.1",
|
||||||
"@types/throng": "^4.0.2",
|
"@types/throng": "^4.0.2",
|
||||||
"@types/uuid": "^3.4.4",
|
"@types/uuid": "^3.4.4",
|
||||||
@@ -275,7 +276,7 @@
|
|||||||
"eslint-plugin-react": "^7.15.1",
|
"eslint-plugin-react": "^7.15.1",
|
||||||
"eventemitter2": "^5.0.1",
|
"eventemitter2": "^5.0.1",
|
||||||
"farce": "^0.2.6",
|
"farce": "^0.2.6",
|
||||||
"final-form": "4.11.0",
|
"final-form": "4.18.6",
|
||||||
"flat": "^4.1.0",
|
"flat": "^4.1.0",
|
||||||
"fluent-intl-polyfill": "^0.1.0",
|
"fluent-intl-polyfill": "^0.1.0",
|
||||||
"fluent-langneg": "^0.1.1",
|
"fluent-langneg": "^0.1.1",
|
||||||
@@ -326,7 +327,7 @@
|
|||||||
"react-dev-utils": "^9.0.0",
|
"react-dev-utils": "^9.0.0",
|
||||||
"react-dom": "^16.9.0-alpha.0",
|
"react-dom": "^16.9.0-alpha.0",
|
||||||
"react-error-overlay": "^5.1.6",
|
"react-error-overlay": "^5.1.6",
|
||||||
"react-final-form": "4.0.2",
|
"react-final-form": "6.3.0",
|
||||||
"react-popper": "^1.3.2",
|
"react-popper": "^1.3.2",
|
||||||
"react-relay": "^4.0.0",
|
"react-relay": "^4.0.0",
|
||||||
"react-relay-network-modern": "^4.0.4",
|
"react-relay-network-modern": "^4.0.4",
|
||||||
@@ -347,6 +348,7 @@
|
|||||||
"simulant": "^0.2.2",
|
"simulant": "^0.2.2",
|
||||||
"sinon": "^7.3.2",
|
"sinon": "^7.3.2",
|
||||||
"sockjs-client": "^1.3.0",
|
"sockjs-client": "^1.3.0",
|
||||||
|
"stack-trace": "0.0.10",
|
||||||
"strip-ansi": "^5.2.0",
|
"strip-ansi": "^5.2.0",
|
||||||
"style-loader": "^0.23.1",
|
"style-loader": "^0.23.1",
|
||||||
"subscriptions-transport-ws": "^0.9.16",
|
"subscriptions-transport-ws": "^0.9.16",
|
||||||
@@ -362,11 +364,11 @@
|
|||||||
"tslint": "^5.20.0",
|
"tslint": "^5.20.0",
|
||||||
"typed-css-modules": "^0.4.2",
|
"typed-css-modules": "^0.4.2",
|
||||||
"typeface-manuale": "^0.0.71",
|
"typeface-manuale": "^0.0.71",
|
||||||
|
"typeface-nunito": "0.0.72",
|
||||||
|
"typeface-open-sans": "0.0.75",
|
||||||
"typeface-source-sans-pro": "^0.0.54",
|
"typeface-source-sans-pro": "^0.0.54",
|
||||||
"typescript": "3.3.4000",
|
"typescript": "3.3.4000",
|
||||||
"typescript-snapshots-plugin": "^1.6.0",
|
"typescript-snapshots-plugin": "^1.6.0",
|
||||||
"typeface-nunito": "0.0.72",
|
|
||||||
"typeface-open-sans": "0.0.75",
|
|
||||||
"wait-for-expect": "^1.1.1",
|
"wait-for-expect": "^1.1.1",
|
||||||
"webpack": "^4.30.0",
|
"webpack": "^4.30.0",
|
||||||
"webpack-assets-manifest": "^3.1.1",
|
"webpack-assets-manifest": "^3.1.1",
|
||||||
|
|||||||
@@ -52,7 +52,7 @@ const UserDrawerNotesContainer: FunctionComponent<Props> = ({
|
|||||||
userID: user.id,
|
userID: user.id,
|
||||||
body,
|
body,
|
||||||
});
|
});
|
||||||
form.reset();
|
form.initialize({});
|
||||||
},
|
},
|
||||||
[user]
|
[user]
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -25,6 +25,11 @@ interface Props {
|
|||||||
lastFocusableRef: RefObject<any>;
|
lastFocusableRef: RefObject<any>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
interface FormStateValues {
|
||||||
|
duration: any;
|
||||||
|
emailMessage: any;
|
||||||
|
}
|
||||||
|
|
||||||
const DURATIONS: ScaledUnit[] = [
|
const DURATIONS: ScaledUnit[] = [
|
||||||
{ original: 3600, value: "3600", unit: "hour", scaled: 1 }, // 1 hour
|
{ original: 3600, value: "3600", unit: "hour", scaled: 1 }, // 1 hour
|
||||||
{ original: 10800, value: "10800", unit: "hour", scaled: 3 }, // 3 hours
|
{ original: 10800, value: "10800", unit: "hour", scaled: 3 }, // 3 hours
|
||||||
@@ -69,7 +74,8 @@ const SuspendForm: FunctionComponent<Props> = ({
|
|||||||
const setMessageValue: Mutator = useCallback(
|
const setMessageValue: Mutator = useCallback(
|
||||||
([name, newValue], state, { changeValue }) => {
|
([name, newValue], state, { changeValue }) => {
|
||||||
if (state.lastFormState) {
|
if (state.lastFormState) {
|
||||||
const { duration, emailMessage } = state.lastFormState.values;
|
const { duration, emailMessage } = state.lastFormState
|
||||||
|
.values as FormStateValues;
|
||||||
const unit = DURATIONS.find(d => d.value === duration);
|
const unit = DURATIONS.find(d => d.value === duration);
|
||||||
const expectedEmailMessage = getMessageWithDuration(unit!);
|
const expectedEmailMessage = getMessageWithDuration(unit!);
|
||||||
if (expectedEmailMessage === emailMessage) {
|
if (expectedEmailMessage === emailMessage) {
|
||||||
@@ -86,7 +92,8 @@ const SuspendForm: FunctionComponent<Props> = ({
|
|||||||
{ changeValue }
|
{ changeValue }
|
||||||
) => {
|
) => {
|
||||||
if (state.lastFormState && !checked) {
|
if (state.lastFormState && !checked) {
|
||||||
const { duration, emailMessage } = state.lastFormState.values;
|
const { duration, emailMessage } = state.lastFormState
|
||||||
|
.values as FormStateValues;
|
||||||
const unit = DURATIONS.find(d => d.value === duration);
|
const unit = DURATIONS.find(d => d.value === duration);
|
||||||
const expectedEmailMessage = getMessageWithDuration(unit!);
|
const expectedEmailMessage = getMessageWithDuration(unit!);
|
||||||
if (expectedEmailMessage !== emailMessage) {
|
if (expectedEmailMessage !== emailMessage) {
|
||||||
@@ -132,8 +139,8 @@ const SuspendForm: FunctionComponent<Props> = ({
|
|||||||
$unit={unit}
|
$unit={unit}
|
||||||
>
|
>
|
||||||
<RadioButton
|
<RadioButton
|
||||||
id={`duration-${value}`}
|
|
||||||
{...input}
|
{...input}
|
||||||
|
id={`duration-${value}`}
|
||||||
onChange={event => {
|
onChange={event => {
|
||||||
form.mutators.setMessageValue(
|
form.mutators.setMessageValue(
|
||||||
"emailMessage",
|
"emailMessage",
|
||||||
@@ -156,8 +163,8 @@ const SuspendForm: FunctionComponent<Props> = ({
|
|||||||
{({ input }) => (
|
{({ input }) => (
|
||||||
<Localized id="community-suspendModal-customize">
|
<Localized id="community-suspendModal-customize">
|
||||||
<CheckBox
|
<CheckBox
|
||||||
id="suspendModal-editMessage"
|
|
||||||
{...input}
|
{...input}
|
||||||
|
id="suspendModal-editMessage"
|
||||||
onChange={event => {
|
onChange={event => {
|
||||||
form.mutators.resetMessageValue(
|
form.mutators.resetMessageValue(
|
||||||
"emailMessage",
|
"emailMessage",
|
||||||
|
|||||||
@@ -20,11 +20,11 @@ const EmailField: FunctionComponent<Props> = ({ index, disabled }) => (
|
|||||||
<Label htmlFor={input.name}>Email Address:</Label>
|
<Label htmlFor={input.name}>Email Address:</Label>
|
||||||
</Localized>
|
</Localized>
|
||||||
<TextField
|
<TextField
|
||||||
|
{...input}
|
||||||
data-testid={`invite-users-email.${index}`}
|
data-testid={`invite-users-email.${index}`}
|
||||||
color={colorFromMeta(meta)}
|
color={colorFromMeta(meta)}
|
||||||
disabled={disabled}
|
disabled={disabled}
|
||||||
fullWidth
|
fullWidth
|
||||||
{...input}
|
|
||||||
/>
|
/>
|
||||||
<ValidationMessage meta={meta} fullWidth />
|
<ValidationMessage meta={meta} fullWidth />
|
||||||
</FormField>
|
</FormField>
|
||||||
|
|||||||
@@ -21,9 +21,9 @@ const RoleField: FunctionComponent<Props> = ({ disabled }) => (
|
|||||||
{({ input }) => (
|
{({ input }) => (
|
||||||
<Localized id="role-staff">
|
<Localized id="role-staff">
|
||||||
<RadioButton
|
<RadioButton
|
||||||
|
{...input}
|
||||||
id={`${input.name}-staff`}
|
id={`${input.name}-staff`}
|
||||||
disabled={disabled}
|
disabled={disabled}
|
||||||
{...input}
|
|
||||||
>
|
>
|
||||||
Staff
|
Staff
|
||||||
</RadioButton>
|
</RadioButton>
|
||||||
@@ -34,9 +34,9 @@ const RoleField: FunctionComponent<Props> = ({ disabled }) => (
|
|||||||
{({ input }) => (
|
{({ input }) => (
|
||||||
<Localized id="role-moderator">
|
<Localized id="role-moderator">
|
||||||
<RadioButton
|
<RadioButton
|
||||||
|
{...input}
|
||||||
id={`${input.name}-moderator`}
|
id={`${input.name}-moderator`}
|
||||||
disabled={disabled}
|
disabled={disabled}
|
||||||
{...input}
|
|
||||||
>
|
>
|
||||||
Moderator
|
Moderator
|
||||||
</RadioButton>
|
</RadioButton>
|
||||||
@@ -47,9 +47,9 @@ const RoleField: FunctionComponent<Props> = ({ disabled }) => (
|
|||||||
{({ input }) => (
|
{({ input }) => (
|
||||||
<Localized id="role-admin">
|
<Localized id="role-admin">
|
||||||
<RadioButton
|
<RadioButton
|
||||||
|
{...input}
|
||||||
id={`${input.name}-admin`}
|
id={`${input.name}-admin`}
|
||||||
disabled={disabled}
|
disabled={disabled}
|
||||||
{...input}
|
|
||||||
>
|
>
|
||||||
Admin
|
Admin
|
||||||
</RadioButton>
|
</RadioButton>
|
||||||
|
|||||||
@@ -60,12 +60,12 @@ const UserTableFilter: FunctionComponent<Props> = props => (
|
|||||||
attrs={{ placeholder: true, "aria-label": true }}
|
attrs={{ placeholder: true, "aria-label": true }}
|
||||||
>
|
>
|
||||||
<TextField
|
<TextField
|
||||||
|
{...input}
|
||||||
className={styles.textField}
|
className={styles.textField}
|
||||||
color="dark"
|
color="dark"
|
||||||
placeholder="Search by username or email address..."
|
placeholder="Search by username or email address..."
|
||||||
aria-label="Search by username or email address"
|
aria-label="Search by username or email address"
|
||||||
variant="seamlessAdornment"
|
variant="seamlessAdornment"
|
||||||
{...input}
|
|
||||||
adornment={
|
adornment={
|
||||||
<Localized
|
<Localized
|
||||||
id="community-filter-searchButton"
|
id="community-filter-searchButton"
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ import SideBar from "./SideBar";
|
|||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
onSubmit: (settings: any, form: FormApi) => void;
|
onSubmit: (settings: any, form: FormApi) => void;
|
||||||
onChange: (formState: FormState) => void;
|
onChange: (formState: FormState<any>) => void;
|
||||||
children: React.ReactElement;
|
children: React.ReactElement;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -25,7 +25,7 @@ const Configure: FunctionComponent<Props> = ({
|
|||||||
}) => (
|
}) => (
|
||||||
<MainLayout data-testid="configure-container">
|
<MainLayout data-testid="configure-container">
|
||||||
<Form onSubmit={onSubmit}>
|
<Form onSubmit={onSubmit}>
|
||||||
{({ handleSubmit, submitting, pristine, form, submitError }) => (
|
{({ handleSubmit, submitting, form, pristine, submitError }) => (
|
||||||
<form autoComplete="off" onSubmit={handleSubmit} id="configure-form">
|
<form autoComplete="off" onSubmit={handleSubmit} id="configure-form">
|
||||||
<FormSpy onChange={onChange} />
|
<FormSpy onChange={onChange} />
|
||||||
<Layout>
|
<Layout>
|
||||||
|
|||||||
@@ -36,7 +36,7 @@ class ConfigureRoute extends React.Component<Props, State> {
|
|||||||
form.initialize(data);
|
form.initialize(data);
|
||||||
};
|
};
|
||||||
|
|
||||||
private handleChange = ({ dirty }: FormState) => {
|
private handleChange = ({ dirty }: FormState<any>) => {
|
||||||
if (dirty !== this.state.dirty) {
|
if (dirty !== this.state.dirty) {
|
||||||
this.setState({ dirty });
|
this.setState({ dirty });
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import { Localized } from "fluent-react/compat";
|
|||||||
import React, { FunctionComponent } from "react";
|
import React, { FunctionComponent } from "react";
|
||||||
import { Field } from "react-final-form";
|
import { Field } from "react-final-form";
|
||||||
|
|
||||||
import { parseStringBool } from "coral-framework/lib/form";
|
import { formatBool, parseStringBool } from "coral-framework/lib/form";
|
||||||
import { Validator } from "coral-framework/lib/validation";
|
import { Validator } from "coral-framework/lib/validation";
|
||||||
import { RadioButton } from "coral-ui/components/v2";
|
import { RadioButton } from "coral-ui/components/v2";
|
||||||
|
|
||||||
@@ -13,8 +13,8 @@ interface Props {
|
|||||||
invert?: boolean;
|
invert?: boolean;
|
||||||
onLabel?: React.ReactNode;
|
onLabel?: React.ReactNode;
|
||||||
offLabel?: React.ReactNode;
|
offLabel?: React.ReactNode;
|
||||||
format?: ((value: any, name: string) => any) | null;
|
format?: (value: any, name: string) => any;
|
||||||
parse?: ((value: any, name: string) => any) | null;
|
parse?: (value: any, name: string) => any;
|
||||||
className?: string;
|
className?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -25,19 +25,19 @@ const OnOffField: FunctionComponent<Props> = ({
|
|||||||
offLabel,
|
offLabel,
|
||||||
invert = false,
|
invert = false,
|
||||||
parse = parseStringBool,
|
parse = parseStringBool,
|
||||||
format,
|
format = formatBool,
|
||||||
className,
|
className,
|
||||||
}) => (
|
}) => (
|
||||||
<div className={className}>
|
<div className={className}>
|
||||||
<Field
|
<Field
|
||||||
name={name}
|
name={name}
|
||||||
type="radio"
|
type="radio"
|
||||||
value={!invert}
|
value={JSON.stringify(!invert)}
|
||||||
parse={parse}
|
parse={parse}
|
||||||
format={format}
|
format={format}
|
||||||
>
|
>
|
||||||
{({ input }) => (
|
{({ input }) => (
|
||||||
<RadioButton id={`${input.name}-true`} disabled={disabled} {...input}>
|
<RadioButton {...input} id={`${input.name}-true`} disabled={disabled}>
|
||||||
{onLabel || (
|
{onLabel || (
|
||||||
<Localized id="configure-onOffField-on">
|
<Localized id="configure-onOffField-on">
|
||||||
<span>On</span>
|
<span>On</span>
|
||||||
@@ -51,10 +51,10 @@ const OnOffField: FunctionComponent<Props> = ({
|
|||||||
type="radio"
|
type="radio"
|
||||||
parse={parse}
|
parse={parse}
|
||||||
format={format}
|
format={format}
|
||||||
value={invert}
|
value={JSON.stringify(invert)}
|
||||||
>
|
>
|
||||||
{({ input }) => (
|
{({ input }) => (
|
||||||
<RadioButton id={`${input.name}-false`} disabled={disabled} {...input}>
|
<RadioButton {...input} id={`${input.name}-false`} disabled={disabled}>
|
||||||
{offLabel || (
|
{offLabel || (
|
||||||
<Localized id="configure-onOffField-off">
|
<Localized id="configure-onOffField-off">
|
||||||
<span>Off</span>
|
<span>Off</span>
|
||||||
|
|||||||
@@ -1,51 +0,0 @@
|
|||||||
import { Localized } from "fluent-react/compat";
|
|
||||||
import React, { FunctionComponent } from "react";
|
|
||||||
import { Field } from "react-final-form";
|
|
||||||
|
|
||||||
import { parseStringBool } from "coral-framework/lib/form";
|
|
||||||
import { Validator } from "coral-framework/lib/validation";
|
|
||||||
import { RadioButton } from "coral-ui/components/v2";
|
|
||||||
|
|
||||||
interface Props {
|
|
||||||
validate?: Validator;
|
|
||||||
name: string;
|
|
||||||
disabled: boolean;
|
|
||||||
invert?: boolean;
|
|
||||||
}
|
|
||||||
|
|
||||||
const PermissionField: FunctionComponent<Props> = ({
|
|
||||||
name,
|
|
||||||
disabled,
|
|
||||||
invert = false,
|
|
||||||
}) => (
|
|
||||||
<div>
|
|
||||||
<Field name={name} type="radio" parse={parseStringBool} value={!invert}>
|
|
||||||
{({ input }) => (
|
|
||||||
<Localized id="configure-permissionField-allow">
|
|
||||||
<RadioButton
|
|
||||||
id={`${input.name}-allow`}
|
|
||||||
disabled={disabled}
|
|
||||||
{...input}
|
|
||||||
>
|
|
||||||
Allow
|
|
||||||
</RadioButton>
|
|
||||||
</Localized>
|
|
||||||
)}
|
|
||||||
</Field>
|
|
||||||
<Field name={name} type="radio" parse={parseStringBool} value={invert}>
|
|
||||||
{({ input }) => (
|
|
||||||
<Localized id="configure-permissionField-dontAllow">
|
|
||||||
<RadioButton
|
|
||||||
id={`${input.name}-dontAllow`}
|
|
||||||
disabled={disabled}
|
|
||||||
{...input}
|
|
||||||
>
|
|
||||||
Don't allow
|
|
||||||
</RadioButton>
|
|
||||||
</Localized>
|
|
||||||
)}
|
|
||||||
</Field>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
|
|
||||||
export default PermissionField;
|
|
||||||
@@ -1,54 +0,0 @@
|
|||||||
import React, { FunctionComponent } from "react";
|
|
||||||
|
|
||||||
import { PropTypesOf } from "coral-framework/types";
|
|
||||||
import { HorizontalGutter } from "coral-ui/components/v2";
|
|
||||||
|
|
||||||
import CommentStreamLiveUpdatesContainer from "./CommentStreamLiveUpdatesContainer";
|
|
||||||
import CustomCSSConfigContainer from "./CustomCSSConfigContainer";
|
|
||||||
import EmbedCodeContainer from "./EmbedCodeContainer";
|
|
||||||
import PermittedDomainsConfigContainer from "./PermittedDomainsConfigContainer";
|
|
||||||
import StoryCreationConfigContainer from "./StoryCreationConfigContainer";
|
|
||||||
|
|
||||||
interface Props {
|
|
||||||
disabled: boolean;
|
|
||||||
settings: PropTypesOf<typeof CustomCSSConfigContainer>["settings"] &
|
|
||||||
PropTypesOf<typeof PermittedDomainsConfigContainer>["settings"] &
|
|
||||||
PropTypesOf<typeof CommentStreamLiveUpdatesContainer>["settings"] &
|
|
||||||
PropTypesOf<typeof CommentStreamLiveUpdatesContainer>["settingsReadOnly"] &
|
|
||||||
PropTypesOf<typeof EmbedCodeContainer>["settings"] &
|
|
||||||
PropTypesOf<typeof StoryCreationConfigContainer>["settings"];
|
|
||||||
onInitValues: (values: any) => void;
|
|
||||||
}
|
|
||||||
|
|
||||||
const AdvancedConfig: FunctionComponent<Props> = ({
|
|
||||||
disabled,
|
|
||||||
settings,
|
|
||||||
onInitValues,
|
|
||||||
}) => (
|
|
||||||
<HorizontalGutter size="double" data-testid="configure-advancedContainer">
|
|
||||||
<EmbedCodeContainer settings={settings} />
|
|
||||||
<CustomCSSConfigContainer
|
|
||||||
disabled={disabled}
|
|
||||||
settings={settings}
|
|
||||||
onInitValues={onInitValues}
|
|
||||||
/>
|
|
||||||
<CommentStreamLiveUpdatesContainer
|
|
||||||
disabled={disabled}
|
|
||||||
settings={settings}
|
|
||||||
settingsReadOnly={settings}
|
|
||||||
onInitValues={onInitValues}
|
|
||||||
/>
|
|
||||||
<PermittedDomainsConfigContainer
|
|
||||||
disabled={disabled}
|
|
||||||
settings={settings}
|
|
||||||
onInitValues={onInitValues}
|
|
||||||
/>
|
|
||||||
<StoryCreationConfigContainer
|
|
||||||
disabled={disabled}
|
|
||||||
settings={settings}
|
|
||||||
onInitValues={onInitValues}
|
|
||||||
/>
|
|
||||||
</HorizontalGutter>
|
|
||||||
);
|
|
||||||
|
|
||||||
export default AdvancedConfig;
|
|
||||||
+35
-36
@@ -1,57 +1,56 @@
|
|||||||
import { FormApi } from "final-form";
|
import React, { useMemo } from "react";
|
||||||
import { RouteProps } from "found";
|
import { useForm } from "react-final-form";
|
||||||
import React from "react";
|
|
||||||
import { graphql } from "react-relay";
|
import { graphql } from "react-relay";
|
||||||
|
|
||||||
import { pureMerge } from "coral-common/utils";
|
import {
|
||||||
import { withFragmentContainer } from "coral-framework/lib/relay";
|
purgeMetadata,
|
||||||
|
withFragmentContainer,
|
||||||
|
} from "coral-framework/lib/relay";
|
||||||
|
import { HorizontalGutter } from "coral-ui/components";
|
||||||
|
|
||||||
import { AdvancedConfigContainer_settings } from "coral-admin/__generated__/AdvancedConfigContainer_settings.graphql";
|
import { AdvancedConfigContainer_settings } from "coral-admin/__generated__/AdvancedConfigContainer_settings.graphql";
|
||||||
|
|
||||||
import AdvancedConfig from "./AdvancedConfig";
|
import CommentStreamLiveUpdatesContainer from "./CommentStreamLiveUpdatesContainer";
|
||||||
|
import CustomCSSConfig from "./CustomCSSConfig";
|
||||||
|
import EmbedCodeContainer from "./EmbedCodeContainer";
|
||||||
|
import PermittedDomainsConfig from "./PermittedDomainsConfig";
|
||||||
|
import StoryCreationConfig from "./StoryCreationConfig";
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
form: FormApi;
|
|
||||||
submitting: boolean;
|
submitting: boolean;
|
||||||
settings: AdvancedConfigContainer_settings;
|
settings: AdvancedConfigContainer_settings;
|
||||||
}
|
}
|
||||||
|
|
||||||
class AdvancedConfigContainer extends React.Component<Props> {
|
const AdvancedConfigContainer: React.FunctionComponent<Props> = ({
|
||||||
public static routeConfig: RouteProps;
|
settings,
|
||||||
private initialValues = {};
|
submitting,
|
||||||
|
}) => {
|
||||||
constructor(props: Props) {
|
const form = useForm();
|
||||||
super(props);
|
useMemo(() => form.initialize(purgeMetadata(settings)), []);
|
||||||
}
|
return (
|
||||||
|
<HorizontalGutter size="double" data-testid="configure-advancedContainer">
|
||||||
public componentDidMount() {
|
<EmbedCodeContainer settings={settings} />
|
||||||
this.props.form.initialize(this.initialValues);
|
<CustomCSSConfig disabled={submitting} />
|
||||||
}
|
<CommentStreamLiveUpdatesContainer
|
||||||
|
disabled={submitting}
|
||||||
private handleOnInitValues = (values: any) => {
|
settings={settings}
|
||||||
this.initialValues = pureMerge(this.initialValues, values);
|
|
||||||
};
|
|
||||||
|
|
||||||
public render() {
|
|
||||||
return (
|
|
||||||
<AdvancedConfig
|
|
||||||
disabled={this.props.submitting}
|
|
||||||
settings={this.props.settings}
|
|
||||||
onInitValues={this.handleOnInitValues}
|
|
||||||
/>
|
/>
|
||||||
);
|
<PermittedDomainsConfig disabled={submitting} />
|
||||||
}
|
<StoryCreationConfig disabled={submitting} />
|
||||||
}
|
</HorizontalGutter>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
const enhanced = withFragmentContainer<Props>({
|
const enhanced = withFragmentContainer<Props>({
|
||||||
settings: graphql`
|
settings: graphql`
|
||||||
fragment AdvancedConfigContainer_settings on Settings {
|
fragment AdvancedConfigContainer_settings on Settings {
|
||||||
|
...CustomCSSConfig_formValues @relay(mask: false)
|
||||||
|
...PermittedDomainsConfig_formValues @relay(mask: false)
|
||||||
|
...CommentStreamLiveUpdates_formValues @relay(mask: false)
|
||||||
|
...StoryCreationConfig_formValues @relay(mask: false)
|
||||||
|
|
||||||
...EmbedCodeContainer_settings
|
...EmbedCodeContainer_settings
|
||||||
...CustomCSSConfigContainer_settings
|
|
||||||
...PermittedDomainsConfigContainer_settings
|
|
||||||
...CommentStreamLiveUpdatesContainer_settings
|
...CommentStreamLiveUpdatesContainer_settings
|
||||||
...CommentStreamLiveUpdatesContainer_settingsReadOnly
|
|
||||||
...StoryCreationConfigContainer_settings
|
|
||||||
}
|
}
|
||||||
`,
|
`,
|
||||||
})(AdvancedConfigContainer);
|
})(AdvancedConfigContainer);
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
import { FormApi } from "final-form";
|
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import { graphql } from "react-relay";
|
import { graphql } from "react-relay";
|
||||||
|
|
||||||
@@ -11,7 +10,6 @@ import AdvancedConfigContainer from "./AdvancedConfigContainer";
|
|||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
data: AdvancedConfigRouteQueryResponse | null;
|
data: AdvancedConfigRouteQueryResponse | null;
|
||||||
form: FormApi;
|
|
||||||
submitting: boolean;
|
submitting: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -27,7 +25,6 @@ class AdvancedConfigRoute extends React.Component<Props> {
|
|||||||
return (
|
return (
|
||||||
<AdvancedConfigContainer
|
<AdvancedConfigContainer
|
||||||
settings={this.props.data.settings}
|
settings={this.props.data.settings}
|
||||||
form={this.props.form}
|
|
||||||
submitting={this.props.submitting}
|
submitting={this.props.submitting}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import { Localized } from "fluent-react/compat";
|
import { Localized } from "fluent-react/compat";
|
||||||
import React, { FunctionComponent } from "react";
|
import React, { FunctionComponent } from "react";
|
||||||
|
import { graphql } from "react-relay";
|
||||||
|
|
||||||
import { FormField, FormFieldDescription } from "coral-ui/components/v2";
|
import { FormField, FormFieldDescription } from "coral-ui/components/v2";
|
||||||
|
|
||||||
@@ -7,6 +8,15 @@ import ConfigBox from "../../ConfigBox";
|
|||||||
import Header from "../../Header";
|
import Header from "../../Header";
|
||||||
import OnOffField from "../../OnOffField";
|
import OnOffField from "../../OnOffField";
|
||||||
|
|
||||||
|
// eslint-disable-next-line no-unused-expressions
|
||||||
|
graphql`
|
||||||
|
fragment CommentStreamLiveUpdates_formValues on Settings {
|
||||||
|
live {
|
||||||
|
enabled
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
disabled: boolean;
|
disabled: boolean;
|
||||||
}
|
}
|
||||||
|
|||||||
+10
-29
@@ -4,49 +4,30 @@ import { graphql } from "react-relay";
|
|||||||
import { withFragmentContainer } from "coral-framework/lib/relay";
|
import { withFragmentContainer } from "coral-framework/lib/relay";
|
||||||
|
|
||||||
import { CommentStreamLiveUpdatesContainer_settings } from "coral-admin/__generated__/CommentStreamLiveUpdatesContainer_settings.graphql";
|
import { CommentStreamLiveUpdatesContainer_settings } from "coral-admin/__generated__/CommentStreamLiveUpdatesContainer_settings.graphql";
|
||||||
import { CommentStreamLiveUpdatesContainer_settingsReadOnly } from "coral-admin/__generated__/CommentStreamLiveUpdatesContainer_settingsReadOnly.graphql";
|
|
||||||
|
|
||||||
import CommentStreamLiveUpdates from "./CommentStreamLiveUpdates";
|
import CommentStreamLiveUpdates from "./CommentStreamLiveUpdates";
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
settingsReadOnly: CommentStreamLiveUpdatesContainer_settingsReadOnly;
|
|
||||||
settings: CommentStreamLiveUpdatesContainer_settings;
|
settings: CommentStreamLiveUpdatesContainer_settings;
|
||||||
onInitValues: (values: CommentStreamLiveUpdatesContainer_settings) => void;
|
|
||||||
disabled: boolean;
|
disabled: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
class CommentStreamLiveUpdatesContainer extends React.Component<Props> {
|
const CommentStreamLiveUpdatesContainer: React.FunctionComponent<Props> = ({
|
||||||
constructor(props: Props) {
|
disabled,
|
||||||
super(props);
|
settings: {
|
||||||
props.onInitValues(props.settings);
|
live: { configurable },
|
||||||
|
},
|
||||||
|
}) => {
|
||||||
|
if (!configurable) {
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public render() {
|
return <CommentStreamLiveUpdates disabled={disabled} />;
|
||||||
const {
|
};
|
||||||
disabled,
|
|
||||||
settingsReadOnly: {
|
|
||||||
live: { configurable },
|
|
||||||
},
|
|
||||||
} = this.props;
|
|
||||||
|
|
||||||
if (!configurable) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
return <CommentStreamLiveUpdates disabled={disabled} />;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const enhanced = withFragmentContainer<Props>({
|
const enhanced = withFragmentContainer<Props>({
|
||||||
settings: graphql`
|
settings: graphql`
|
||||||
fragment CommentStreamLiveUpdatesContainer_settings on Settings {
|
fragment CommentStreamLiveUpdatesContainer_settings on Settings {
|
||||||
live {
|
|
||||||
enabled
|
|
||||||
}
|
|
||||||
}
|
|
||||||
`,
|
|
||||||
settingsReadOnly: graphql`
|
|
||||||
fragment CommentStreamLiveUpdatesContainer_settingsReadOnly on Settings {
|
|
||||||
live {
|
live {
|
||||||
configurable
|
configurable
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import { Localized } from "fluent-react/compat";
|
import { Localized } from "fluent-react/compat";
|
||||||
import React, { FunctionComponent } from "react";
|
import React, { FunctionComponent } from "react";
|
||||||
import { Field } from "react-final-form";
|
import { Field } from "react-final-form";
|
||||||
|
import { graphql } from "react-relay";
|
||||||
|
|
||||||
import { formatEmpty, parseEmptyAsNull } from "coral-framework/lib/form";
|
import { formatEmpty, parseEmptyAsNull } from "coral-framework/lib/form";
|
||||||
import { FormField, FormFieldDescription } from "coral-ui/components/v2";
|
import { FormField, FormFieldDescription } from "coral-ui/components/v2";
|
||||||
@@ -9,6 +10,13 @@ import ConfigBox from "../../ConfigBox";
|
|||||||
import Header from "../../Header";
|
import Header from "../../Header";
|
||||||
import TextFieldWithValidation from "../../TextFieldWithValidation";
|
import TextFieldWithValidation from "../../TextFieldWithValidation";
|
||||||
|
|
||||||
|
// eslint-disable-next-line no-unused-expressions
|
||||||
|
graphql`
|
||||||
|
fragment CustomCSSConfig_formValues on Settings {
|
||||||
|
customCSSURL
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
disabled: boolean;
|
disabled: boolean;
|
||||||
}
|
}
|
||||||
@@ -34,6 +42,7 @@ const CustomCSSConfig: FunctionComponent<Props> = ({ disabled }) => (
|
|||||||
<Field name="customCSSURL" parse={parseEmptyAsNull} format={formatEmpty}>
|
<Field name="customCSSURL" parse={parseEmptyAsNull} format={formatEmpty}>
|
||||||
{({ input, meta }) => (
|
{({ input, meta }) => (
|
||||||
<TextFieldWithValidation
|
<TextFieldWithValidation
|
||||||
|
{...input}
|
||||||
id={`configure-advanced-${input.name}`}
|
id={`configure-advanced-${input.name}`}
|
||||||
disabled={disabled}
|
disabled={disabled}
|
||||||
autoComplete="off"
|
autoComplete="off"
|
||||||
@@ -42,7 +51,6 @@ const CustomCSSConfig: FunctionComponent<Props> = ({ disabled }) => (
|
|||||||
spellCheck={false}
|
spellCheck={false}
|
||||||
fullWidth
|
fullWidth
|
||||||
meta={meta}
|
meta={meta}
|
||||||
{...input}
|
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
</Field>
|
</Field>
|
||||||
|
|||||||
@@ -1,36 +0,0 @@
|
|||||||
import React from "react";
|
|
||||||
import { graphql } from "react-relay";
|
|
||||||
|
|
||||||
import { withFragmentContainer } from "coral-framework/lib/relay";
|
|
||||||
|
|
||||||
import { CustomCSSConfigContainer_settings as SettingsData } from "coral-admin/__generated__/CustomCSSConfigContainer_settings.graphql";
|
|
||||||
|
|
||||||
import CustomCSSConfig from "./CustomCSSConfig";
|
|
||||||
|
|
||||||
interface Props {
|
|
||||||
settings: SettingsData;
|
|
||||||
onInitValues: (values: SettingsData) => void;
|
|
||||||
disabled: boolean;
|
|
||||||
}
|
|
||||||
|
|
||||||
class CustomCSSConfigContainer extends React.Component<Props> {
|
|
||||||
constructor(props: Props) {
|
|
||||||
super(props);
|
|
||||||
props.onInitValues(props.settings);
|
|
||||||
}
|
|
||||||
|
|
||||||
public render() {
|
|
||||||
const { disabled } = this.props;
|
|
||||||
return <CustomCSSConfig disabled={disabled} />;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const enhanced = withFragmentContainer<Props>({
|
|
||||||
settings: graphql`
|
|
||||||
fragment CustomCSSConfigContainer_settings on Settings {
|
|
||||||
customCSSURL
|
|
||||||
}
|
|
||||||
`,
|
|
||||||
})(CustomCSSConfigContainer);
|
|
||||||
|
|
||||||
export default enhanced;
|
|
||||||
@@ -1,6 +1,7 @@
|
|||||||
import { Localized } from "fluent-react/compat";
|
import { Localized } from "fluent-react/compat";
|
||||||
import React, { FunctionComponent } from "react";
|
import React, { FunctionComponent } from "react";
|
||||||
import { Field } from "react-final-form";
|
import { Field } from "react-final-form";
|
||||||
|
import { graphql } from "react-relay";
|
||||||
|
|
||||||
import { formatStringList, parseStringList } from "coral-framework/lib/form";
|
import { formatStringList, parseStringList } from "coral-framework/lib/form";
|
||||||
import { validateStrictURLList } from "coral-framework/lib/validation";
|
import { validateStrictURLList } from "coral-framework/lib/validation";
|
||||||
@@ -10,6 +11,13 @@ import ConfigBox from "../../ConfigBox";
|
|||||||
import Header from "../../Header";
|
import Header from "../../Header";
|
||||||
import TextFieldWithValidation from "../../TextFieldWithValidation";
|
import TextFieldWithValidation from "../../TextFieldWithValidation";
|
||||||
|
|
||||||
|
// eslint-disable-next-line no-unused-expressions
|
||||||
|
graphql`
|
||||||
|
fragment PermittedDomainsConfig_formValues on Settings {
|
||||||
|
allowedDomains
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
disabled: boolean;
|
disabled: boolean;
|
||||||
}
|
}
|
||||||
@@ -44,6 +52,7 @@ const PermittedDomainsConfig: FunctionComponent<Props> = ({ disabled }) => (
|
|||||||
>
|
>
|
||||||
{({ input, meta }) => (
|
{({ input, meta }) => (
|
||||||
<TextFieldWithValidation
|
<TextFieldWithValidation
|
||||||
|
{...input}
|
||||||
id={`configure-advanced-${input.name}`}
|
id={`configure-advanced-${input.name}`}
|
||||||
disabled={disabled}
|
disabled={disabled}
|
||||||
autoComplete="off"
|
autoComplete="off"
|
||||||
@@ -51,7 +60,6 @@ const PermittedDomainsConfig: FunctionComponent<Props> = ({ disabled }) => (
|
|||||||
autoCapitalize="off"
|
autoCapitalize="off"
|
||||||
spellCheck={false}
|
spellCheck={false}
|
||||||
meta={meta}
|
meta={meta}
|
||||||
{...input}
|
|
||||||
fullWidth
|
fullWidth
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
|||||||
-36
@@ -1,36 +0,0 @@
|
|||||||
import React from "react";
|
|
||||||
import { graphql } from "react-relay";
|
|
||||||
|
|
||||||
import { withFragmentContainer } from "coral-framework/lib/relay";
|
|
||||||
|
|
||||||
import { PermittedDomainsConfigContainer_settings as SettingsData } from "coral-admin/__generated__/PermittedDomainsConfigContainer_settings.graphql";
|
|
||||||
|
|
||||||
import PermittedDomainsConfig from "./PermittedDomainsConfig";
|
|
||||||
|
|
||||||
interface Props {
|
|
||||||
settings: SettingsData;
|
|
||||||
onInitValues: (values: SettingsData) => void;
|
|
||||||
disabled: boolean;
|
|
||||||
}
|
|
||||||
|
|
||||||
class PermittedDomainsConfigContainer extends React.Component<Props> {
|
|
||||||
constructor(props: Props) {
|
|
||||||
super(props);
|
|
||||||
props.onInitValues(props.settings);
|
|
||||||
}
|
|
||||||
|
|
||||||
public render() {
|
|
||||||
const { disabled } = this.props;
|
|
||||||
return <PermittedDomainsConfig disabled={disabled} />;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const enhanced = withFragmentContainer<Props>({
|
|
||||||
settings: graphql`
|
|
||||||
fragment PermittedDomainsConfigContainer_settings on Settings {
|
|
||||||
allowedDomains
|
|
||||||
}
|
|
||||||
`,
|
|
||||||
})(PermittedDomainsConfigContainer);
|
|
||||||
|
|
||||||
export default enhanced;
|
|
||||||
@@ -1,6 +1,7 @@
|
|||||||
import { Localized } from "fluent-react/compat";
|
import { Localized } from "fluent-react/compat";
|
||||||
import React, { FunctionComponent } from "react";
|
import React, { FunctionComponent } from "react";
|
||||||
import { Field } from "react-final-form";
|
import { Field } from "react-final-form";
|
||||||
|
import { graphql } from "react-relay";
|
||||||
|
|
||||||
import { parseEmptyAsNull } from "coral-framework/lib/form";
|
import { parseEmptyAsNull } from "coral-framework/lib/form";
|
||||||
import { ExternalLink } from "coral-framework/lib/i18n/components";
|
import { ExternalLink } from "coral-framework/lib/i18n/components";
|
||||||
@@ -18,6 +19,19 @@ import HelperText from "../../HelperText";
|
|||||||
import OnOffField from "../../OnOffField";
|
import OnOffField from "../../OnOffField";
|
||||||
import TextFieldWithValidation from "../../TextFieldWithValidation";
|
import TextFieldWithValidation from "../../TextFieldWithValidation";
|
||||||
|
|
||||||
|
// eslint-disable-next-line no-unused-expressions
|
||||||
|
graphql`
|
||||||
|
fragment StoryCreationConfig_formValues on Settings {
|
||||||
|
stories {
|
||||||
|
scraping {
|
||||||
|
enabled
|
||||||
|
proxyURL
|
||||||
|
}
|
||||||
|
disableLazy
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
disabled: boolean;
|
disabled: boolean;
|
||||||
}
|
}
|
||||||
@@ -90,6 +104,7 @@ const StoryCreationConfig: FunctionComponent<Props> = ({ disabled }) => (
|
|||||||
>
|
>
|
||||||
{({ input, meta }) => (
|
{({ input, meta }) => (
|
||||||
<TextFieldWithValidation
|
<TextFieldWithValidation
|
||||||
|
{...input}
|
||||||
id="configure-advanced-stories-proxy-url"
|
id="configure-advanced-stories-proxy-url"
|
||||||
disabled={disabled}
|
disabled={disabled}
|
||||||
fullWidth
|
fullWidth
|
||||||
@@ -98,7 +113,6 @@ const StoryCreationConfig: FunctionComponent<Props> = ({ disabled }) => (
|
|||||||
autoCapitalize="off"
|
autoCapitalize="off"
|
||||||
spellCheck={false}
|
spellCheck={false}
|
||||||
meta={meta}
|
meta={meta}
|
||||||
{...input}
|
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
</Field>
|
</Field>
|
||||||
|
|||||||
-42
@@ -1,42 +0,0 @@
|
|||||||
import React from "react";
|
|
||||||
import { graphql } from "react-relay";
|
|
||||||
|
|
||||||
import { withFragmentContainer } from "coral-framework/lib/relay";
|
|
||||||
|
|
||||||
import { StoryCreationConfigContainer_settings as SettingsData } from "coral-admin/__generated__/StoryCreationConfigContainer_settings.graphql";
|
|
||||||
|
|
||||||
import StoryCreationConfig from "./StoryCreationConfig";
|
|
||||||
|
|
||||||
interface Props {
|
|
||||||
settings: SettingsData;
|
|
||||||
onInitValues: (values: SettingsData) => void;
|
|
||||||
disabled: boolean;
|
|
||||||
}
|
|
||||||
|
|
||||||
class StoryCreationConfigContainer extends React.Component<Props> {
|
|
||||||
constructor(props: Props) {
|
|
||||||
super(props);
|
|
||||||
props.onInitValues(props.settings);
|
|
||||||
}
|
|
||||||
|
|
||||||
public render() {
|
|
||||||
const { disabled } = this.props;
|
|
||||||
return <StoryCreationConfig disabled={disabled} />;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const enhanced = withFragmentContainer<Props>({
|
|
||||||
settings: graphql`
|
|
||||||
fragment StoryCreationConfigContainer_settings on Settings {
|
|
||||||
stories {
|
|
||||||
scraping {
|
|
||||||
enabled
|
|
||||||
proxyURL
|
|
||||||
}
|
|
||||||
disableLazy
|
|
||||||
}
|
|
||||||
}
|
|
||||||
`,
|
|
||||||
})(StoryCreationConfigContainer);
|
|
||||||
|
|
||||||
export default enhanced;
|
|
||||||
@@ -1,5 +1,6 @@
|
|||||||
import { Localized } from "fluent-react/compat";
|
import { Localized } from "fluent-react/compat";
|
||||||
import React, { FunctionComponent } from "react";
|
import React, { FunctionComponent } from "react";
|
||||||
|
import { graphql } from "react-relay";
|
||||||
|
|
||||||
import {
|
import {
|
||||||
Flex,
|
Flex,
|
||||||
@@ -16,6 +17,17 @@ import OnOffField from "../../OnOffField";
|
|||||||
|
|
||||||
import styles from "./AccountFeaturesConfig.css";
|
import styles from "./AccountFeaturesConfig.css";
|
||||||
|
|
||||||
|
// eslint-disable-next-line no-unused-expressions
|
||||||
|
graphql`
|
||||||
|
fragment AccountFeaturesConfig_formValues on Settings {
|
||||||
|
accountFeatures {
|
||||||
|
changeUsername
|
||||||
|
deleteAccount
|
||||||
|
downloadComments
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
disabled?: boolean;
|
disabled?: boolean;
|
||||||
}
|
}
|
||||||
|
|||||||
-45
@@ -1,45 +0,0 @@
|
|||||||
import React from "react";
|
|
||||||
import { graphql } from "react-relay";
|
|
||||||
|
|
||||||
import { DeepNullable, DeepPartial } from "coral-common/types";
|
|
||||||
import { withFragmentContainer } from "coral-framework/lib/relay";
|
|
||||||
import { GQLSettings } from "coral-framework/schema";
|
|
||||||
|
|
||||||
import { AccountFeaturesConfigContainer_settings as SettingsData } from "coral-admin/__generated__/AccountFeaturesConfigContainer_settings.graphql";
|
|
||||||
|
|
||||||
import AccountFeaturesConfig from "./AccountFeaturesConfig";
|
|
||||||
|
|
||||||
export type FormProps = DeepNullable<Pick<GQLSettings, "accountFeatures">>;
|
|
||||||
export type OnInitValuesFct = (values: DeepPartial<FormProps>) => void;
|
|
||||||
|
|
||||||
interface Props {
|
|
||||||
settings: SettingsData;
|
|
||||||
onInitValues: (values: SettingsData) => void;
|
|
||||||
disabled?: boolean;
|
|
||||||
}
|
|
||||||
|
|
||||||
class AccountFeaturesConfigContainer extends React.Component<Props> {
|
|
||||||
constructor(props: Props) {
|
|
||||||
super(props);
|
|
||||||
props.onInitValues(props.settings);
|
|
||||||
}
|
|
||||||
|
|
||||||
public render() {
|
|
||||||
const { disabled } = this.props;
|
|
||||||
return <AccountFeaturesConfig disabled={disabled} />;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const enhanced = withFragmentContainer<Props>({
|
|
||||||
settings: graphql`
|
|
||||||
fragment AccountFeaturesConfigContainer_settings on Settings {
|
|
||||||
accountFeatures {
|
|
||||||
changeUsername
|
|
||||||
deleteAccount
|
|
||||||
downloadComments
|
|
||||||
}
|
|
||||||
}
|
|
||||||
`,
|
|
||||||
})(AccountFeaturesConfigContainer);
|
|
||||||
|
|
||||||
export default enhanced;
|
|
||||||
@@ -1,36 +0,0 @@
|
|||||||
import React, { FunctionComponent } from "react";
|
|
||||||
|
|
||||||
import { PropTypesOf } from "coral-framework/types";
|
|
||||||
import { HorizontalGutter } from "coral-ui/components/v2";
|
|
||||||
|
|
||||||
import { OnInitValuesFct } from "./AuthConfigContainer";
|
|
||||||
import AuthIntegrationsConfig from "./AuthIntegrationsConfig";
|
|
||||||
import SessionConfigContainer from "./SessionConfigContainer";
|
|
||||||
|
|
||||||
interface Props {
|
|
||||||
disabled?: boolean;
|
|
||||||
auth: PropTypesOf<typeof AuthIntegrationsConfig>["auth"] &
|
|
||||||
PropTypesOf<typeof SessionConfigContainer>["auth"];
|
|
||||||
onInitValues: OnInitValuesFct;
|
|
||||||
}
|
|
||||||
|
|
||||||
const AuthConfig: FunctionComponent<Props> = ({
|
|
||||||
disabled,
|
|
||||||
auth,
|
|
||||||
onInitValues,
|
|
||||||
}) => (
|
|
||||||
<HorizontalGutter size="double" data-testid="configure-authContainer">
|
|
||||||
<SessionConfigContainer
|
|
||||||
auth={auth}
|
|
||||||
disabled={disabled}
|
|
||||||
onInitValues={onInitValues}
|
|
||||||
/>
|
|
||||||
<AuthIntegrationsConfig
|
|
||||||
disabled={disabled}
|
|
||||||
auth={auth}
|
|
||||||
onInitValues={onInitValues}
|
|
||||||
/>
|
|
||||||
</HorizontalGutter>
|
|
||||||
);
|
|
||||||
|
|
||||||
export default AuthConfig;
|
|
||||||
@@ -5,24 +5,28 @@ import React from "react";
|
|||||||
import { graphql } from "react-relay";
|
import { graphql } from "react-relay";
|
||||||
|
|
||||||
import { DeepNullable, DeepPartial } from "coral-common/types";
|
import { DeepNullable, DeepPartial } from "coral-common/types";
|
||||||
import { pureMerge } from "coral-common/utils";
|
|
||||||
import { CoralContext, withContext } from "coral-framework/lib/bootstrap";
|
import { CoralContext, withContext } from "coral-framework/lib/bootstrap";
|
||||||
import {
|
import {
|
||||||
AddSubmitHook,
|
AddSubmitHook,
|
||||||
RemoveSubmitHook,
|
RemoveSubmitHook,
|
||||||
SubmitHook,
|
SubmitHook,
|
||||||
|
withForm,
|
||||||
withSubmitHookContext,
|
withSubmitHookContext,
|
||||||
} from "coral-framework/lib/form";
|
} from "coral-framework/lib/form";
|
||||||
import { getMessage } from "coral-framework/lib/i18n";
|
import { getMessage } from "coral-framework/lib/i18n";
|
||||||
import { withFragmentContainer } from "coral-framework/lib/relay";
|
import {
|
||||||
|
purgeMetadata,
|
||||||
|
withFragmentContainer,
|
||||||
|
} from "coral-framework/lib/relay";
|
||||||
import { GQLSettings } from "coral-framework/schema";
|
import { GQLSettings } from "coral-framework/schema";
|
||||||
import { HorizontalGutter } from "coral-ui/components/v2";
|
import { HorizontalGutter } from "coral-ui/components/v2";
|
||||||
|
|
||||||
import { AuthConfigContainer_auth as AuthData } from "coral-admin/__generated__/AuthConfigContainer_auth.graphql";
|
import { AuthConfigContainer_auth as AuthData } from "coral-admin/__generated__/AuthConfigContainer_auth.graphql";
|
||||||
import { AuthConfigContainer_settings as SettingsData } from "coral-admin/__generated__/AuthConfigContainer_settings.graphql";
|
import { AuthConfigContainer_settings as SettingsData } from "coral-admin/__generated__/AuthConfigContainer_settings.graphql";
|
||||||
|
|
||||||
import AccountFeaturesConfigContainer from "./AccountFeaturesConfigContainer";
|
import AccountFeaturesConfig from "./AccountFeaturesConfig";
|
||||||
import AuthConfig from "./AuthConfig";
|
import AuthIntegrationsConfig from "./AuthIntegrationsConfig";
|
||||||
|
import SessionConfig from "./SessionConfig";
|
||||||
|
|
||||||
export type FormProps = DeepNullable<
|
export type FormProps = DeepNullable<
|
||||||
Pick<GQLSettings, "auth" | "accountFeatures">
|
Pick<GQLSettings, "auth" | "accountFeatures">
|
||||||
@@ -40,16 +44,17 @@ interface Props {
|
|||||||
|
|
||||||
class AuthConfigContainer extends React.Component<Props> {
|
class AuthConfigContainer extends React.Component<Props> {
|
||||||
public static routeConfig: RouteProps;
|
public static routeConfig: RouteProps;
|
||||||
private initialValues: DeepPartial<FormProps> = {};
|
|
||||||
private removeSubmitHook: RemoveSubmitHook;
|
private removeSubmitHook: RemoveSubmitHook;
|
||||||
|
|
||||||
constructor(props: Props) {
|
constructor(props: Props) {
|
||||||
super(props);
|
super(props);
|
||||||
this.removeSubmitHook = this.props.addSubmitHook(this.submitHook);
|
this.removeSubmitHook = this.props.addSubmitHook(this.submitHook);
|
||||||
}
|
this.props.form.initialize(
|
||||||
|
purgeMetadata({
|
||||||
public componentDidMount() {
|
...props.settings,
|
||||||
this.props.form.initialize(this.initialValues);
|
auth: props.auth,
|
||||||
|
})
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
public componentWillUnmount() {
|
public componentWillUnmount() {
|
||||||
@@ -97,51 +102,48 @@ class AuthConfigContainer extends React.Component<Props> {
|
|||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
|
|
||||||
private handleOnInitValues: OnInitValuesFct = values => {
|
|
||||||
this.initialValues = pureMerge(this.initialValues, values);
|
|
||||||
};
|
|
||||||
|
|
||||||
public render() {
|
public render() {
|
||||||
return (
|
return (
|
||||||
<HorizontalGutter size="double">
|
<HorizontalGutter size="double" data-testid="configure-authContainer">
|
||||||
<AccountFeaturesConfigContainer
|
<AccountFeaturesConfig disabled={this.props.submitting} />
|
||||||
onInitValues={this.handleOnInitValues}
|
<SessionConfig disabled={this.props.submitting} />
|
||||||
settings={this.props.settings}
|
<AuthIntegrationsConfig
|
||||||
disabled={this.props.submitting}
|
|
||||||
/>
|
|
||||||
<AuthConfig
|
|
||||||
disabled={this.props.submitting}
|
|
||||||
auth={this.props.auth}
|
auth={this.props.auth}
|
||||||
onInitValues={this.handleOnInitValues}
|
disabled={this.props.submitting}
|
||||||
/>
|
/>
|
||||||
</HorizontalGutter>
|
</HorizontalGutter>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const enhanced = withFragmentContainer<Props>({
|
const enhanced = withForm(
|
||||||
settings: graphql`
|
withFragmentContainer<Props>({
|
||||||
fragment AuthConfigContainer_settings on Settings {
|
settings: graphql`
|
||||||
...AccountFeaturesConfigContainer_settings
|
fragment AuthConfigContainer_settings on Settings {
|
||||||
}
|
...AccountFeaturesConfig_formValues @relay(mask: false)
|
||||||
`,
|
}
|
||||||
auth: graphql`
|
`,
|
||||||
fragment AuthConfigContainer_auth on Auth {
|
auth: graphql`
|
||||||
...FacebookConfigContainer_auth
|
fragment AuthConfigContainer_auth on Auth {
|
||||||
...FacebookConfigContainer_authReadOnly
|
...FacebookConfig_formValues @relay(mask: false)
|
||||||
...GoogleConfigContainer_auth
|
...GoogleConfig_formValues @relay(mask: false)
|
||||||
...GoogleConfigContainer_authReadOnly
|
...SSOConfig_formValues @relay(mask: false)
|
||||||
...SSOConfigContainer_auth
|
...LocalAuthConfig_formValues @relay(mask: false)
|
||||||
...SSOConfigContainer_authReadOnly
|
...OIDCConfig_formValues @relay(mask: false)
|
||||||
...LocalAuthConfigContainer_auth
|
...SessionConfig_formValues @relay(mask: false)
|
||||||
...OIDCConfigContainer_auth
|
|
||||||
...OIDCConfigContainer_authReadOnly
|
...FacebookConfigContainer_auth
|
||||||
...SessionConfigContainer_auth
|
...GoogleConfigContainer_auth
|
||||||
}
|
...SSOConfigContainer_auth
|
||||||
`,
|
...OIDCConfigContainer_auth
|
||||||
})(
|
}
|
||||||
withSubmitHookContext(addSubmitHook => ({ addSubmitHook }))(
|
`,
|
||||||
withContext(({ localeBundles }) => ({ localeBundles }))(AuthConfigContainer)
|
})(
|
||||||
|
withSubmitHookContext(addSubmitHook => ({ addSubmitHook }))(
|
||||||
|
withContext(({ localeBundles }) => ({ localeBundles }))(
|
||||||
|
AuthConfigContainer
|
||||||
|
)
|
||||||
|
)
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
import { FormApi } from "final-form";
|
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import { graphql } from "react-relay";
|
import { graphql } from "react-relay";
|
||||||
|
|
||||||
@@ -11,7 +10,6 @@ import AuthConfigContainer from "./AuthConfigContainer";
|
|||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
data: AuthConfigRouteContainerQueryResponse | null;
|
data: AuthConfigRouteContainerQueryResponse | null;
|
||||||
form: FormApi;
|
|
||||||
submitting?: boolean;
|
submitting?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -28,7 +26,6 @@ class AuthConfigRoute extends React.Component<Props> {
|
|||||||
<AuthConfigContainer
|
<AuthConfigContainer
|
||||||
settings={this.props.data.settings}
|
settings={this.props.data.settings}
|
||||||
auth={this.props.data.settings.auth}
|
auth={this.props.data.settings.auth}
|
||||||
form={this.props.form}
|
|
||||||
submitting={this.props.submitting}
|
submitting={this.props.submitting}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
@@ -42,7 +39,6 @@ const enhanced = withRouteConfig<Props>({
|
|||||||
...AuthConfigContainer_settings
|
...AuthConfigContainer_settings
|
||||||
auth {
|
auth {
|
||||||
...AuthConfigContainer_auth
|
...AuthConfigContainer_auth
|
||||||
...SessionConfigContainer_auth
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,62 +3,30 @@ import React, { FunctionComponent } from "react";
|
|||||||
import { PropTypesOf } from "coral-framework/types";
|
import { PropTypesOf } from "coral-framework/types";
|
||||||
import { HorizontalGutter } from "coral-ui/components/v2";
|
import { HorizontalGutter } from "coral-ui/components/v2";
|
||||||
|
|
||||||
import { OnInitValuesFct } from "./AuthConfigContainer";
|
|
||||||
import FacebookConfigContainer from "./FacebookConfigContainer";
|
import FacebookConfigContainer from "./FacebookConfigContainer";
|
||||||
import GoogleConfigContainer from "./GoogleConfigContainer";
|
import GoogleConfigContainer from "./GoogleConfigContainer";
|
||||||
import LocalAuthConfigContainer from "./LocalAuthConfigContainer";
|
import LocalAuthConfig from "./LocalAuthConfig";
|
||||||
import OIDCConfigContainer from "./OIDCConfigContainer";
|
import OIDCConfigContainer from "./OIDCConfigContainer";
|
||||||
import SSOConfigContainer from "./SSOConfigContainer";
|
import SSOConfigContainer from "./SSOConfigContainer";
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
disabled?: boolean;
|
disabled?: boolean;
|
||||||
auth: PropTypesOf<typeof FacebookConfigContainer>["auth"] &
|
auth: PropTypesOf<typeof FacebookConfigContainer>["auth"] &
|
||||||
PropTypesOf<typeof FacebookConfigContainer>["authReadOnly"] &
|
|
||||||
PropTypesOf<typeof GoogleConfigContainer>["auth"] &
|
PropTypesOf<typeof GoogleConfigContainer>["auth"] &
|
||||||
PropTypesOf<typeof GoogleConfigContainer>["authReadOnly"] &
|
|
||||||
PropTypesOf<typeof SSOConfigContainer>["auth"] &
|
PropTypesOf<typeof SSOConfigContainer>["auth"] &
|
||||||
PropTypesOf<typeof SSOConfigContainer>["authReadOnly"] &
|
PropTypesOf<typeof OIDCConfigContainer>["auth"];
|
||||||
PropTypesOf<typeof LocalAuthConfigContainer>["auth"] &
|
|
||||||
PropTypesOf<typeof OIDCConfigContainer>["auth"] &
|
|
||||||
PropTypesOf<typeof OIDCConfigContainer>["authReadOnly"];
|
|
||||||
onInitValues: OnInitValuesFct;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const AuthIntegrationsConfig: FunctionComponent<Props> = ({
|
const AuthIntegrationsConfig: FunctionComponent<Props> = ({
|
||||||
disabled,
|
disabled,
|
||||||
auth,
|
auth,
|
||||||
onInitValues,
|
|
||||||
}) => (
|
}) => (
|
||||||
<HorizontalGutter size="double">
|
<HorizontalGutter size="double">
|
||||||
<LocalAuthConfigContainer
|
<LocalAuthConfig disabled={disabled} />
|
||||||
disabled={disabled}
|
<OIDCConfigContainer disabled={disabled} auth={auth} />
|
||||||
auth={auth}
|
<SSOConfigContainer disabled={disabled} auth={auth} />
|
||||||
onInitValues={onInitValues}
|
<GoogleConfigContainer disabled={disabled} auth={auth} />
|
||||||
/>
|
<FacebookConfigContainer disabled={disabled} auth={auth} />
|
||||||
<OIDCConfigContainer
|
|
||||||
disabled={disabled}
|
|
||||||
auth={auth}
|
|
||||||
authReadOnly={auth}
|
|
||||||
onInitValues={onInitValues}
|
|
||||||
/>
|
|
||||||
<SSOConfigContainer
|
|
||||||
disabled={disabled}
|
|
||||||
auth={auth}
|
|
||||||
authReadOnly={auth}
|
|
||||||
onInitValues={onInitValues}
|
|
||||||
/>
|
|
||||||
<GoogleConfigContainer
|
|
||||||
disabled={disabled}
|
|
||||||
auth={auth}
|
|
||||||
authReadOnly={auth}
|
|
||||||
onInitValues={onInitValues}
|
|
||||||
/>
|
|
||||||
<FacebookConfigContainer
|
|
||||||
disabled={disabled}
|
|
||||||
auth={auth}
|
|
||||||
authReadOnly={auth}
|
|
||||||
onInitValues={onInitValues}
|
|
||||||
/>
|
|
||||||
</HorizontalGutter>
|
</HorizontalGutter>
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|||||||
@@ -20,21 +20,24 @@ const ClientSecretField: FunctionComponent<Props> = ({
|
|||||||
validate,
|
validate,
|
||||||
}) => (
|
}) => (
|
||||||
<FormField>
|
<FormField>
|
||||||
<Localized id="configure-auth-clientID">
|
|
||||||
<Label>Client ID</Label>
|
|
||||||
</Localized>
|
|
||||||
<Field name={name} parse={parseEmptyAsNull} validate={validate}>
|
<Field name={name} parse={parseEmptyAsNull} validate={validate}>
|
||||||
{({ input, meta }) => (
|
{({ input, meta }) => (
|
||||||
<TextFieldWithValidation
|
<>
|
||||||
disabled={disabled}
|
<Localized id="configure-auth-clientID">
|
||||||
autoComplete="off"
|
<Label htmlFor={input.name}>Client ID</Label>
|
||||||
autoCorrect="off"
|
</Localized>
|
||||||
autoCapitalize="off"
|
<TextFieldWithValidation
|
||||||
meta={meta}
|
{...input}
|
||||||
{...input}
|
id={input.name}
|
||||||
spellCheck={false}
|
disabled={disabled}
|
||||||
fullWidth
|
autoComplete="off"
|
||||||
/>
|
autoCorrect="off"
|
||||||
|
autoCapitalize="off"
|
||||||
|
meta={meta}
|
||||||
|
spellCheck={false}
|
||||||
|
fullWidth
|
||||||
|
/>
|
||||||
|
</>
|
||||||
)}
|
)}
|
||||||
</Field>
|
</Field>
|
||||||
</FormField>
|
</FormField>
|
||||||
|
|||||||
@@ -18,9 +18,6 @@ const ClientSecretField: FunctionComponent<Props> = ({
|
|||||||
validate,
|
validate,
|
||||||
}) => (
|
}) => (
|
||||||
<FormField>
|
<FormField>
|
||||||
<Localized id="configure-auth-clientSecret">
|
|
||||||
<Label>Client secret</Label>
|
|
||||||
</Localized>
|
|
||||||
<Field
|
<Field
|
||||||
name={name}
|
name={name}
|
||||||
key={(disabled && "on") || "off"}
|
key={(disabled && "on") || "off"}
|
||||||
@@ -29,13 +26,17 @@ const ClientSecretField: FunctionComponent<Props> = ({
|
|||||||
>
|
>
|
||||||
{({ input, meta }) => (
|
{({ input, meta }) => (
|
||||||
<>
|
<>
|
||||||
|
<Localized id="configure-auth-clientSecret">
|
||||||
|
<Label htmlFor={input.name}>Client secret</Label>
|
||||||
|
</Localized>
|
||||||
<PasswordField
|
<PasswordField
|
||||||
|
{...input}
|
||||||
|
id={input.name}
|
||||||
disabled={disabled || meta.submitting}
|
disabled={disabled || meta.submitting}
|
||||||
// TODO: (wyattjoh) figure out how to add translations to these props
|
// TODO: (wyattjoh) figure out how to add translations to these props
|
||||||
hidePasswordTitle="Show Client Secret"
|
hidePasswordTitle="Show Client Secret"
|
||||||
showPasswordTitle="Hide Client Secret"
|
showPasswordTitle="Hide Client Secret"
|
||||||
fullWidth
|
fullWidth
|
||||||
{...input}
|
|
||||||
/>
|
/>
|
||||||
<ValidationMessage meta={meta} fullWidth />
|
<ValidationMessage meta={meta} fullWidth />
|
||||||
</>
|
</>
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ const ConfigBoxWithToggleField: FunctionComponent<Props> = ({
|
|||||||
topRight={
|
topRight={
|
||||||
<FormField>
|
<FormField>
|
||||||
<Localized id="configure-auth-configBoxEnabled">
|
<Localized id="configure-auth-configBoxEnabled">
|
||||||
<CheckBox id={input.name} disabled={disabled} light {...input}>
|
<CheckBox {...input} id={input.name} disabled={disabled} light>
|
||||||
Enabled
|
Enabled
|
||||||
</CheckBox>
|
</CheckBox>
|
||||||
</Localized>
|
</Localized>
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import { Localized } from "fluent-react/compat";
|
import { Localized } from "fluent-react/compat";
|
||||||
import React, { FunctionComponent } from "react";
|
import React, { FunctionComponent } from "react";
|
||||||
|
import { graphql } from "react-relay";
|
||||||
|
|
||||||
import {
|
import {
|
||||||
Condition,
|
Condition,
|
||||||
@@ -17,6 +18,24 @@ import RedirectField from "./RedirectField";
|
|||||||
import RegistrationField from "./RegistrationField";
|
import RegistrationField from "./RegistrationField";
|
||||||
import TargetFilterField from "./TargetFilterField";
|
import TargetFilterField from "./TargetFilterField";
|
||||||
|
|
||||||
|
// eslint-disable-next-line no-unused-expressions
|
||||||
|
graphql`
|
||||||
|
fragment FacebookConfig_formValues on Auth {
|
||||||
|
integrations {
|
||||||
|
facebook {
|
||||||
|
enabled
|
||||||
|
allowRegistration
|
||||||
|
targetFilter {
|
||||||
|
admin
|
||||||
|
stream
|
||||||
|
}
|
||||||
|
clientID
|
||||||
|
clientSecret
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
disabled?: boolean;
|
disabled?: boolean;
|
||||||
callbackURL: string;
|
callbackURL: string;
|
||||||
@@ -29,7 +48,12 @@ const FacebookLink = () => (
|
|||||||
);
|
);
|
||||||
|
|
||||||
const isEnabled: Condition = (value, values) =>
|
const isEnabled: Condition = (value, values) =>
|
||||||
Boolean(values.auth.integrations.facebook.enabled);
|
Boolean(
|
||||||
|
values.auth &&
|
||||||
|
values.auth.integrations &&
|
||||||
|
values.auth.integrations.facebook &&
|
||||||
|
values.auth.integrations.facebook.enabled
|
||||||
|
);
|
||||||
|
|
||||||
const FacebookConfig: FunctionComponent<Props> = ({
|
const FacebookConfig: FunctionComponent<Props> = ({
|
||||||
disabled,
|
disabled,
|
||||||
|
|||||||
@@ -4,54 +4,29 @@ import { graphql } from "react-relay";
|
|||||||
import { withFragmentContainer } from "coral-framework/lib/relay";
|
import { withFragmentContainer } from "coral-framework/lib/relay";
|
||||||
|
|
||||||
import { FacebookConfigContainer_auth as AuthData } from "coral-admin/__generated__/FacebookConfigContainer_auth.graphql";
|
import { FacebookConfigContainer_auth as AuthData } from "coral-admin/__generated__/FacebookConfigContainer_auth.graphql";
|
||||||
import { FacebookConfigContainer_authReadOnly as AuthReadOnlyData } from "coral-admin/__generated__/FacebookConfigContainer_authReadOnly.graphql";
|
|
||||||
|
|
||||||
import { OnInitValuesFct } from "./AuthConfigContainer";
|
|
||||||
import FacebookConfig from "./FacebookConfig";
|
import FacebookConfig from "./FacebookConfig";
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
auth: AuthData;
|
auth: AuthData;
|
||||||
authReadOnly: AuthReadOnlyData;
|
|
||||||
onInitValues: OnInitValuesFct;
|
|
||||||
disabled?: boolean;
|
disabled?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
class FacebookConfigContainer extends React.Component<Props> {
|
const FacebookConfigContainer: React.FunctionComponent<Props> = ({
|
||||||
constructor(props: Props) {
|
disabled,
|
||||||
super(props);
|
auth,
|
||||||
props.onInitValues({ auth: props.auth });
|
}) => {
|
||||||
}
|
return (
|
||||||
|
<FacebookConfig
|
||||||
public render() {
|
disabled={disabled}
|
||||||
const { disabled, authReadOnly } = this.props;
|
callbackURL={auth.integrations.facebook.callbackURL}
|
||||||
return (
|
/>
|
||||||
<FacebookConfig
|
);
|
||||||
disabled={disabled}
|
};
|
||||||
callbackURL={authReadOnly.integrations.facebook.callbackURL}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const enhanced = withFragmentContainer<Props>({
|
const enhanced = withFragmentContainer<Props>({
|
||||||
auth: graphql`
|
auth: graphql`
|
||||||
fragment FacebookConfigContainer_auth on Auth {
|
fragment FacebookConfigContainer_auth on Auth {
|
||||||
integrations {
|
|
||||||
facebook {
|
|
||||||
enabled
|
|
||||||
allowRegistration
|
|
||||||
targetFilter {
|
|
||||||
admin
|
|
||||||
stream
|
|
||||||
}
|
|
||||||
clientID
|
|
||||||
clientSecret
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
`,
|
|
||||||
authReadOnly: graphql`
|
|
||||||
fragment FacebookConfigContainer_authReadOnly on Auth {
|
|
||||||
integrations {
|
integrations {
|
||||||
facebook {
|
facebook {
|
||||||
callbackURL
|
callbackURL
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import { Localized } from "fluent-react/compat";
|
import { Localized } from "fluent-react/compat";
|
||||||
import React, { FunctionComponent } from "react";
|
import React, { FunctionComponent } from "react";
|
||||||
|
import { graphql } from "react-relay";
|
||||||
|
|
||||||
import {
|
import {
|
||||||
Condition,
|
Condition,
|
||||||
@@ -17,6 +18,23 @@ import RedirectField from "./RedirectField";
|
|||||||
import RegistrationField from "./RegistrationField";
|
import RegistrationField from "./RegistrationField";
|
||||||
import TargetFilterField from "./TargetFilterField";
|
import TargetFilterField from "./TargetFilterField";
|
||||||
|
|
||||||
|
// eslint-disable-next-line no-unused-expressions
|
||||||
|
graphql`
|
||||||
|
fragment GoogleConfig_formValues on Auth {
|
||||||
|
integrations {
|
||||||
|
google {
|
||||||
|
enabled
|
||||||
|
allowRegistration
|
||||||
|
targetFilter {
|
||||||
|
admin
|
||||||
|
stream
|
||||||
|
}
|
||||||
|
clientID
|
||||||
|
clientSecret
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`;
|
||||||
interface Props {
|
interface Props {
|
||||||
disabled?: boolean;
|
disabled?: boolean;
|
||||||
callbackURL: string;
|
callbackURL: string;
|
||||||
@@ -42,6 +60,7 @@ const GoogleConfig: FunctionComponent<Props> = ({ disabled, callbackURL }) => (
|
|||||||
}
|
}
|
||||||
name="auth.integrations.google.enabled"
|
name="auth.integrations.google.enabled"
|
||||||
disabled={disabled}
|
disabled={disabled}
|
||||||
|
data-testid="configure-auth-google"
|
||||||
>
|
>
|
||||||
{disabledInside => (
|
{disabledInside => (
|
||||||
<>
|
<>
|
||||||
|
|||||||
@@ -4,54 +4,29 @@ import { graphql } from "react-relay";
|
|||||||
import { withFragmentContainer } from "coral-framework/lib/relay";
|
import { withFragmentContainer } from "coral-framework/lib/relay";
|
||||||
|
|
||||||
import { GoogleConfigContainer_auth as AuthData } from "coral-admin/__generated__/GoogleConfigContainer_auth.graphql";
|
import { GoogleConfigContainer_auth as AuthData } from "coral-admin/__generated__/GoogleConfigContainer_auth.graphql";
|
||||||
import { GoogleConfigContainer_authReadOnly as AuthReadOnlyData } from "coral-admin/__generated__/GoogleConfigContainer_authReadOnly.graphql";
|
|
||||||
|
|
||||||
import { OnInitValuesFct } from "./AuthConfigContainer";
|
|
||||||
import GoogleConfig from "./GoogleConfig";
|
import GoogleConfig from "./GoogleConfig";
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
auth: AuthData;
|
auth: AuthData;
|
||||||
authReadOnly: AuthReadOnlyData;
|
|
||||||
onInitValues: OnInitValuesFct;
|
|
||||||
disabled?: boolean;
|
disabled?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
class GoogleConfigContainer extends React.Component<Props> {
|
const GoogleConfigContainer: React.FunctionComponent<Props> = ({
|
||||||
constructor(props: Props) {
|
disabled,
|
||||||
super(props);
|
auth,
|
||||||
props.onInitValues({ auth: props.auth });
|
}) => {
|
||||||
}
|
return (
|
||||||
|
<GoogleConfig
|
||||||
public render() {
|
disabled={disabled}
|
||||||
const { disabled, authReadOnly } = this.props;
|
callbackURL={auth.integrations.google.callbackURL}
|
||||||
return (
|
/>
|
||||||
<GoogleConfig
|
);
|
||||||
disabled={disabled}
|
};
|
||||||
callbackURL={authReadOnly.integrations.google.callbackURL}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const enhanced = withFragmentContainer<Props>({
|
const enhanced = withFragmentContainer<Props>({
|
||||||
auth: graphql`
|
auth: graphql`
|
||||||
fragment GoogleConfigContainer_auth on Auth {
|
fragment GoogleConfigContainer_auth on Auth {
|
||||||
integrations {
|
|
||||||
google {
|
|
||||||
enabled
|
|
||||||
allowRegistration
|
|
||||||
targetFilter {
|
|
||||||
admin
|
|
||||||
stream
|
|
||||||
}
|
|
||||||
clientID
|
|
||||||
clientSecret
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
`,
|
|
||||||
authReadOnly: graphql`
|
|
||||||
fragment GoogleConfigContainer_authReadOnly on Auth {
|
|
||||||
integrations {
|
integrations {
|
||||||
google {
|
google {
|
||||||
callbackURL
|
callbackURL
|
||||||
|
|||||||
@@ -1,11 +1,28 @@
|
|||||||
import { Localized } from "fluent-react/compat";
|
import { Localized } from "fluent-react/compat";
|
||||||
import React, { FunctionComponent } from "react";
|
import React, { FunctionComponent } from "react";
|
||||||
|
import { graphql } from "react-relay";
|
||||||
|
|
||||||
import Header from "../../Header";
|
import Header from "../../Header";
|
||||||
import ConfigBoxWithToggleField from "./ConfigBoxWithToggleField";
|
import ConfigBoxWithToggleField from "./ConfigBoxWithToggleField";
|
||||||
import RegistrationField from "./RegistrationField";
|
import RegistrationField from "./RegistrationField";
|
||||||
import TargetFilterField from "./TargetFilterField";
|
import TargetFilterField from "./TargetFilterField";
|
||||||
|
|
||||||
|
// eslint-disable-next-line no-unused-expressions
|
||||||
|
graphql`
|
||||||
|
fragment LocalAuthConfig_formValues on Auth {
|
||||||
|
integrations {
|
||||||
|
local {
|
||||||
|
enabled
|
||||||
|
allowRegistration
|
||||||
|
targetFilter {
|
||||||
|
admin
|
||||||
|
stream
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
disabled?: boolean;
|
disabled?: boolean;
|
||||||
}
|
}
|
||||||
@@ -19,6 +36,7 @@ const LocalAuthConfig: FunctionComponent<Props> = ({ disabled }) => (
|
|||||||
}
|
}
|
||||||
name="auth.integrations.local.enabled"
|
name="auth.integrations.local.enabled"
|
||||||
disabled={disabled}
|
disabled={disabled}
|
||||||
|
data-testid="configure-auth-local"
|
||||||
>
|
>
|
||||||
{disabledInside => (
|
{disabledInside => (
|
||||||
<>
|
<>
|
||||||
|
|||||||
@@ -1,46 +0,0 @@
|
|||||||
import React from "react";
|
|
||||||
import { graphql } from "react-relay";
|
|
||||||
|
|
||||||
import { withFragmentContainer } from "coral-framework/lib/relay";
|
|
||||||
|
|
||||||
import { LocalAuthConfigContainer_auth as AuthData } from "coral-admin/__generated__/LocalAuthConfigContainer_auth.graphql";
|
|
||||||
|
|
||||||
import { OnInitValuesFct } from "./AuthConfigContainer";
|
|
||||||
import LocalAuthConfig from "./LocalAuthConfig";
|
|
||||||
|
|
||||||
interface Props {
|
|
||||||
auth: AuthData;
|
|
||||||
onInitValues: OnInitValuesFct;
|
|
||||||
disabled?: boolean;
|
|
||||||
}
|
|
||||||
|
|
||||||
class LocalAuthConfigContainer extends React.Component<Props> {
|
|
||||||
constructor(props: Props) {
|
|
||||||
super(props);
|
|
||||||
props.onInitValues({ auth: props.auth });
|
|
||||||
}
|
|
||||||
|
|
||||||
public render() {
|
|
||||||
const { disabled } = this.props;
|
|
||||||
return <LocalAuthConfig disabled={disabled} />;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const enhanced = withFragmentContainer<Props>({
|
|
||||||
auth: graphql`
|
|
||||||
fragment LocalAuthConfigContainer_auth on Auth {
|
|
||||||
integrations {
|
|
||||||
local {
|
|
||||||
enabled
|
|
||||||
allowRegistration
|
|
||||||
targetFilter {
|
|
||||||
admin
|
|
||||||
stream
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
`,
|
|
||||||
})(LocalAuthConfigContainer);
|
|
||||||
|
|
||||||
export default enhanced;
|
|
||||||
@@ -1,6 +1,7 @@
|
|||||||
import { Localized } from "fluent-react/compat";
|
import { Localized } from "fluent-react/compat";
|
||||||
import React, { FunctionComponent } from "react";
|
import React, { FunctionComponent } from "react";
|
||||||
import { Field } from "react-final-form";
|
import { Field } from "react-final-form";
|
||||||
|
import { graphql } from "react-relay";
|
||||||
|
|
||||||
import { colorFromMeta, parseEmptyAsNull } from "coral-framework/lib/form";
|
import { colorFromMeta, parseEmptyAsNull } from "coral-framework/lib/form";
|
||||||
import {
|
import {
|
||||||
@@ -33,6 +34,29 @@ import RedirectField from "./RedirectField";
|
|||||||
import RegistrationField from "./RegistrationField";
|
import RegistrationField from "./RegistrationField";
|
||||||
import TargetFilterField from "./TargetFilterField";
|
import TargetFilterField from "./TargetFilterField";
|
||||||
|
|
||||||
|
// eslint-disable-next-line no-unused-expressions
|
||||||
|
graphql`
|
||||||
|
fragment OIDCConfig_formValues on Auth {
|
||||||
|
integrations {
|
||||||
|
oidc {
|
||||||
|
enabled
|
||||||
|
allowRegistration
|
||||||
|
targetFilter {
|
||||||
|
admin
|
||||||
|
stream
|
||||||
|
}
|
||||||
|
name
|
||||||
|
clientID
|
||||||
|
clientSecret
|
||||||
|
authorizationURL
|
||||||
|
tokenURL
|
||||||
|
jwksURI
|
||||||
|
issuer
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
disabled?: boolean;
|
disabled?: boolean;
|
||||||
callbackURL: string;
|
callbackURL: string;
|
||||||
@@ -76,7 +100,9 @@ const OIDCConfig: FunctionComponent<Props> = ({
|
|||||||
<FormField>
|
<FormField>
|
||||||
<FormFieldHeader>
|
<FormFieldHeader>
|
||||||
<Localized id="configure-auth-oidc-providerName">
|
<Localized id="configure-auth-oidc-providerName">
|
||||||
<Label>Provider name</Label>
|
<Label htmlFor="auth.integrations.oidc.name">
|
||||||
|
Provider name
|
||||||
|
</Label>
|
||||||
</Localized>
|
</Localized>
|
||||||
<Localized id="configure-auth-oidc-providerNameDescription">
|
<Localized id="configure-auth-oidc-providerNameDescription">
|
||||||
<HelperText>
|
<HelperText>
|
||||||
@@ -94,6 +120,8 @@ const OIDCConfig: FunctionComponent<Props> = ({
|
|||||||
>
|
>
|
||||||
{({ input, meta }) => (
|
{({ input, meta }) => (
|
||||||
<TextFieldWithValidation
|
<TextFieldWithValidation
|
||||||
|
{...input}
|
||||||
|
id={input.name}
|
||||||
disabled={disabledInside}
|
disabled={disabledInside}
|
||||||
autoComplete="off"
|
autoComplete="off"
|
||||||
autoCorrect="off"
|
autoCorrect="off"
|
||||||
@@ -102,7 +130,6 @@ const OIDCConfig: FunctionComponent<Props> = ({
|
|||||||
color={colorFromMeta(meta)}
|
color={colorFromMeta(meta)}
|
||||||
fullWidth
|
fullWidth
|
||||||
meta={meta}
|
meta={meta}
|
||||||
{...input}
|
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
</Field>
|
</Field>
|
||||||
@@ -120,7 +147,7 @@ const OIDCConfig: FunctionComponent<Props> = ({
|
|||||||
<FormField>
|
<FormField>
|
||||||
<FormFieldHeader>
|
<FormFieldHeader>
|
||||||
<Localized id="configure-auth-oidc-issuer">
|
<Localized id="configure-auth-oidc-issuer">
|
||||||
<Label>Issuer</Label>
|
<Label htmlFor="auth.integrations.oidc.issuer">Issuer</Label>
|
||||||
</Localized>
|
</Localized>
|
||||||
<Localized id="configure-auth-oidc-issuerDescription">
|
<Localized id="configure-auth-oidc-issuerDescription">
|
||||||
<HelperText>
|
<HelperText>
|
||||||
@@ -139,6 +166,8 @@ const OIDCConfig: FunctionComponent<Props> = ({
|
|||||||
<>
|
<>
|
||||||
<Flex direction="row" itemGutter="half" alignItems="center">
|
<Flex direction="row" itemGutter="half" alignItems="center">
|
||||||
<TextField
|
<TextField
|
||||||
|
{...input}
|
||||||
|
id={input.name}
|
||||||
disabled={disabledInside || disableForDiscover}
|
disabled={disabledInside || disableForDiscover}
|
||||||
autoComplete="off"
|
autoComplete="off"
|
||||||
autoCorrect="off"
|
autoCorrect="off"
|
||||||
@@ -146,7 +175,6 @@ const OIDCConfig: FunctionComponent<Props> = ({
|
|||||||
spellCheck={false}
|
spellCheck={false}
|
||||||
color={colorFromMeta(meta)}
|
color={colorFromMeta(meta)}
|
||||||
fullWidth
|
fullWidth
|
||||||
{...input}
|
|
||||||
/>
|
/>
|
||||||
<Button
|
<Button
|
||||||
id="configure-auth-oidc-discover"
|
id="configure-auth-oidc-discover"
|
||||||
@@ -174,6 +202,8 @@ const OIDCConfig: FunctionComponent<Props> = ({
|
|||||||
>
|
>
|
||||||
{({ input, meta }) => (
|
{({ input, meta }) => (
|
||||||
<TextFieldWithValidation
|
<TextFieldWithValidation
|
||||||
|
{...input}
|
||||||
|
id={input.name}
|
||||||
disabled={disabledInside || disableForDiscover}
|
disabled={disabledInside || disableForDiscover}
|
||||||
autoComplete="off"
|
autoComplete="off"
|
||||||
autoCorrect="off"
|
autoCorrect="off"
|
||||||
@@ -181,7 +211,6 @@ const OIDCConfig: FunctionComponent<Props> = ({
|
|||||||
spellCheck={false}
|
spellCheck={false}
|
||||||
fullWidth
|
fullWidth
|
||||||
meta={meta}
|
meta={meta}
|
||||||
{...input}
|
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
</Field>
|
</Field>
|
||||||
@@ -197,6 +226,8 @@ const OIDCConfig: FunctionComponent<Props> = ({
|
|||||||
>
|
>
|
||||||
{({ input, meta }) => (
|
{({ input, meta }) => (
|
||||||
<TextFieldWithValidation
|
<TextFieldWithValidation
|
||||||
|
{...input}
|
||||||
|
id={input.name}
|
||||||
disabled={disabledInside || disableForDiscover}
|
disabled={disabledInside || disableForDiscover}
|
||||||
autoComplete="off"
|
autoComplete="off"
|
||||||
autoCorrect="off"
|
autoCorrect="off"
|
||||||
@@ -204,7 +235,6 @@ const OIDCConfig: FunctionComponent<Props> = ({
|
|||||||
spellCheck={false}
|
spellCheck={false}
|
||||||
meta={meta}
|
meta={meta}
|
||||||
fullWidth
|
fullWidth
|
||||||
{...input}
|
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
</Field>
|
</Field>
|
||||||
@@ -220,6 +250,8 @@ const OIDCConfig: FunctionComponent<Props> = ({
|
|||||||
>
|
>
|
||||||
{({ input, meta }) => (
|
{({ input, meta }) => (
|
||||||
<TextFieldWithValidation
|
<TextFieldWithValidation
|
||||||
|
{...input}
|
||||||
|
id={input.name}
|
||||||
disabled={disabledInside || disableForDiscover}
|
disabled={disabledInside || disableForDiscover}
|
||||||
autoComplete="off"
|
autoComplete="off"
|
||||||
autoCorrect="off"
|
autoCorrect="off"
|
||||||
@@ -227,7 +259,6 @@ const OIDCConfig: FunctionComponent<Props> = ({
|
|||||||
spellCheck={false}
|
spellCheck={false}
|
||||||
meta={meta}
|
meta={meta}
|
||||||
fullWidth
|
fullWidth
|
||||||
{...input}
|
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
</Field>
|
</Field>
|
||||||
|
|||||||
@@ -1,29 +1,25 @@
|
|||||||
import { FormApi } from "final-form";
|
import { FormApi } from "final-form";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import { ReactContext, withReactFinalForm } from "react-final-form";
|
|
||||||
import { graphql } from "react-relay";
|
import { graphql } from "react-relay";
|
||||||
import { InferableComponentEnhancer } from "recompose";
|
|
||||||
|
|
||||||
|
import { withForm } from "coral-framework/lib/form";
|
||||||
import {
|
import {
|
||||||
FetchProp,
|
FetchProp,
|
||||||
withFetch,
|
withFetch,
|
||||||
withFragmentContainer,
|
withFragmentContainer,
|
||||||
} from "coral-framework/lib/relay";
|
} from "coral-framework/lib/relay";
|
||||||
|
|
||||||
|
import { OIDCConfig_formValues } from "coral-admin/__generated__/OIDCConfig_formValues.graphql";
|
||||||
import { OIDCConfigContainer_auth as AuthData } from "coral-admin/__generated__/OIDCConfigContainer_auth.graphql";
|
import { OIDCConfigContainer_auth as AuthData } from "coral-admin/__generated__/OIDCConfigContainer_auth.graphql";
|
||||||
import { OIDCConfigContainer_authReadOnly as AuthReadOnlyData } from "coral-admin/__generated__/OIDCConfigContainer_authReadOnly.graphql";
|
|
||||||
|
|
||||||
import { OnInitValuesFct } from "./AuthConfigContainer";
|
|
||||||
import DiscoverOIDCConfigurationFetch from "./DiscoverOIDCConfigurationFetch";
|
import DiscoverOIDCConfigurationFetch from "./DiscoverOIDCConfigurationFetch";
|
||||||
import OIDCConfig from "./OIDCConfig";
|
import OIDCConfig from "./OIDCConfig";
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
auth: AuthData;
|
auth: AuthData;
|
||||||
authReadOnly: AuthReadOnlyData;
|
|
||||||
onInitValues: OnInitValuesFct;
|
|
||||||
disabled?: boolean;
|
disabled?: boolean;
|
||||||
discoverOIDCConfiguration: FetchProp<typeof DiscoverOIDCConfigurationFetch>;
|
discoverOIDCConfiguration: FetchProp<typeof DiscoverOIDCConfigurationFetch>;
|
||||||
reactFinalForm: FormApi;
|
form: FormApi<{ auth: AuthData & OIDCConfig_formValues }>;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface State {
|
interface State {
|
||||||
@@ -36,22 +32,35 @@ class OIDCConfigContainer extends React.Component<Props, State> {
|
|||||||
};
|
};
|
||||||
|
|
||||||
private handleDiscover = async () => {
|
private handleDiscover = async () => {
|
||||||
const form = this.props.reactFinalForm;
|
const issuer = this.props.form.getState().values.auth.integrations.oidc
|
||||||
|
.issuer;
|
||||||
|
if (!issuer) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
this.setState({ awaitingResponse: true });
|
this.setState({ awaitingResponse: true });
|
||||||
try {
|
try {
|
||||||
const config = await this.props.discoverOIDCConfiguration({
|
const config = await this.props.discoverOIDCConfiguration({
|
||||||
issuer: form.getState().values.auth.integrations.oidc.issuer,
|
issuer,
|
||||||
});
|
});
|
||||||
if (config) {
|
if (config) {
|
||||||
if (config.issuer) {
|
if (config.issuer) {
|
||||||
form.change("auth.integrations.oidc.issuer", config.issuer);
|
this.props.form.change(
|
||||||
|
"auth.integrations.oidc.issuer",
|
||||||
|
config.issuer
|
||||||
|
);
|
||||||
}
|
}
|
||||||
form.change(
|
this.props.form.change(
|
||||||
"auth.integrations.oidc.authorizationURL",
|
"auth.integrations.oidc.authorizationURL",
|
||||||
config.authorizationURL
|
config.authorizationURL
|
||||||
);
|
);
|
||||||
form.change("auth.integrations.oidc.jwksURI", config.jwksURI);
|
this.props.form.change(
|
||||||
form.change("auth.integrations.oidc.tokenURL", config.tokenURL);
|
"auth.integrations.oidc.jwksURI",
|
||||||
|
config.jwksURI
|
||||||
|
);
|
||||||
|
this.props.form.change(
|
||||||
|
"auth.integrations.oidc.tokenURL",
|
||||||
|
config.tokenURL
|
||||||
|
);
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
// FIXME: (wyattjoh) handle error
|
// FIXME: (wyattjoh) handle error
|
||||||
@@ -61,17 +70,12 @@ class OIDCConfigContainer extends React.Component<Props, State> {
|
|||||||
this.setState({ awaitingResponse: false });
|
this.setState({ awaitingResponse: false });
|
||||||
};
|
};
|
||||||
|
|
||||||
constructor(props: Props) {
|
|
||||||
super(props);
|
|
||||||
props.onInitValues({ auth: props.auth });
|
|
||||||
}
|
|
||||||
|
|
||||||
public render() {
|
public render() {
|
||||||
const { disabled, authReadOnly } = this.props;
|
const { disabled, auth } = this.props;
|
||||||
return (
|
return (
|
||||||
<OIDCConfig
|
<OIDCConfig
|
||||||
disabled={disabled}
|
disabled={disabled}
|
||||||
callbackURL={authReadOnly.integrations.oidc.callbackURL}
|
callbackURL={auth.integrations.oidc.callbackURL}
|
||||||
onDiscover={this.handleDiscover}
|
onDiscover={this.handleDiscover}
|
||||||
disableForDiscover={this.state.awaitingResponse}
|
disableForDiscover={this.state.awaitingResponse}
|
||||||
/>
|
/>
|
||||||
@@ -79,36 +83,11 @@ class OIDCConfigContainer extends React.Component<Props, State> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// (cvle) Fix `withReactFinalForm` typings (v4.1.0), forgive this, we'll
|
|
||||||
// probably only use hooks in the future instead anyway ;-)
|
|
||||||
const withForm = withReactFinalForm as InferableComponentEnhancer<ReactContext>;
|
|
||||||
|
|
||||||
const enhanced = withForm(
|
const enhanced = withForm(
|
||||||
withFetch(DiscoverOIDCConfigurationFetch)(
|
withFetch(DiscoverOIDCConfigurationFetch)(
|
||||||
withFragmentContainer<Props>({
|
withFragmentContainer<Props>({
|
||||||
auth: graphql`
|
auth: graphql`
|
||||||
fragment OIDCConfigContainer_auth on Auth {
|
fragment OIDCConfigContainer_auth on Auth {
|
||||||
integrations {
|
|
||||||
oidc {
|
|
||||||
enabled
|
|
||||||
allowRegistration
|
|
||||||
targetFilter {
|
|
||||||
admin
|
|
||||||
stream
|
|
||||||
}
|
|
||||||
name
|
|
||||||
clientID
|
|
||||||
clientSecret
|
|
||||||
authorizationURL
|
|
||||||
tokenURL
|
|
||||||
jwksURI
|
|
||||||
issuer
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
`,
|
|
||||||
authReadOnly: graphql`
|
|
||||||
fragment OIDCConfigContainer_authReadOnly on Auth {
|
|
||||||
integrations {
|
integrations {
|
||||||
oidc {
|
oidc {
|
||||||
callbackURL
|
callbackURL
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ const RegistrationField: FunctionComponent<Props> = ({ name, disabled }) => (
|
|||||||
<Field name={name} type="checkbox">
|
<Field name={name} type="checkbox">
|
||||||
{({ input }) => (
|
{({ input }) => (
|
||||||
<Localized id="configure-auth-registrationCheckBox">
|
<Localized id="configure-auth-registrationCheckBox">
|
||||||
<CheckBox id={input.name} disabled={disabled} {...input}>
|
<CheckBox {...input} id={input.name} disabled={disabled}>
|
||||||
Allow Registration
|
Allow Registration
|
||||||
</CheckBox>
|
</CheckBox>
|
||||||
</Localized>
|
</Localized>
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import { Localized } from "fluent-react/compat";
|
import { Localized } from "fluent-react/compat";
|
||||||
import React, { FunctionComponent } from "react";
|
import React, { FunctionComponent } from "react";
|
||||||
|
import { graphql } from "react-relay";
|
||||||
|
|
||||||
import { PropTypesOf } from "coral-framework/types";
|
import { PropTypesOf } from "coral-framework/types";
|
||||||
|
|
||||||
@@ -9,6 +10,22 @@ import RegistrationField from "./RegistrationField";
|
|||||||
import SSOKeyFieldContainer from "./SSOKeyFieldContainer";
|
import SSOKeyFieldContainer from "./SSOKeyFieldContainer";
|
||||||
import TargetFilterField from "./TargetFilterField";
|
import TargetFilterField from "./TargetFilterField";
|
||||||
|
|
||||||
|
// eslint-disable-next-line no-unused-expressions
|
||||||
|
graphql`
|
||||||
|
fragment SSOConfig_formValues on Auth {
|
||||||
|
integrations {
|
||||||
|
sso {
|
||||||
|
enabled
|
||||||
|
allowRegistration
|
||||||
|
targetFilter {
|
||||||
|
admin
|
||||||
|
stream
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
disabled?: boolean;
|
disabled?: boolean;
|
||||||
sso: PropTypesOf<typeof SSOKeyFieldContainer>["sso"];
|
sso: PropTypesOf<typeof SSOKeyFieldContainer>["sso"];
|
||||||
@@ -23,6 +40,7 @@ const SSOConfig: FunctionComponent<Props> = ({ disabled, sso }) => (
|
|||||||
}
|
}
|
||||||
name="auth.integrations.sso.enabled"
|
name="auth.integrations.sso.enabled"
|
||||||
disabled={disabled}
|
disabled={disabled}
|
||||||
|
data-testid="configure-auth-sso"
|
||||||
>
|
>
|
||||||
{disabledInside => (
|
{disabledInside => (
|
||||||
<>
|
<>
|
||||||
|
|||||||
@@ -4,52 +4,24 @@ import { graphql } from "react-relay";
|
|||||||
import { withFragmentContainer } from "coral-framework/lib/relay";
|
import { withFragmentContainer } from "coral-framework/lib/relay";
|
||||||
|
|
||||||
import { SSOConfigContainer_auth as AuthData } from "coral-admin/__generated__/SSOConfigContainer_auth.graphql";
|
import { SSOConfigContainer_auth as AuthData } from "coral-admin/__generated__/SSOConfigContainer_auth.graphql";
|
||||||
import { SSOConfigContainer_authReadOnly as AuthReadOnlyData } from "coral-admin/__generated__/SSOConfigContainer_authReadOnly.graphql";
|
|
||||||
|
|
||||||
import { OnInitValuesFct } from "./AuthConfigContainer";
|
|
||||||
import SSOConfig from "./SSOConfig";
|
import SSOConfig from "./SSOConfig";
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
auth: AuthData;
|
auth: AuthData;
|
||||||
authReadOnly: AuthReadOnlyData;
|
|
||||||
onInitValues: OnInitValuesFct;
|
|
||||||
disabled?: boolean;
|
disabled?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
class SSOConfigContainer extends React.Component<Props> {
|
const SSOConfigContainer: React.FunctionComponent<Props> = ({
|
||||||
constructor(props: Props) {
|
disabled,
|
||||||
super(props);
|
auth,
|
||||||
props.onInitValues({ auth: props.auth });
|
}) => {
|
||||||
}
|
return <SSOConfig disabled={disabled} sso={auth.integrations.sso} />;
|
||||||
|
};
|
||||||
public render() {
|
|
||||||
const { disabled } = this.props;
|
|
||||||
return (
|
|
||||||
<SSOConfig
|
|
||||||
disabled={disabled}
|
|
||||||
sso={this.props.authReadOnly.integrations.sso}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const enhanced = withFragmentContainer<Props>({
|
const enhanced = withFragmentContainer<Props>({
|
||||||
auth: graphql`
|
auth: graphql`
|
||||||
fragment SSOConfigContainer_auth on Auth {
|
fragment SSOConfigContainer_auth on Auth {
|
||||||
integrations {
|
|
||||||
sso {
|
|
||||||
enabled
|
|
||||||
allowRegistration
|
|
||||||
targetFilter {
|
|
||||||
admin
|
|
||||||
stream
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
`,
|
|
||||||
authReadOnly: graphql`
|
|
||||||
fragment SSOConfigContainer_authReadOnly on Auth {
|
|
||||||
integrations {
|
integrations {
|
||||||
sso {
|
sso {
|
||||||
...SSOKeyFieldContainer_sso
|
...SSOKeyFieldContainer_sso
|
||||||
|
|||||||
@@ -27,11 +27,12 @@ const SSOKeyField: FunctionComponent<Props> = ({
|
|||||||
disabled,
|
disabled,
|
||||||
onRegenerate,
|
onRegenerate,
|
||||||
}) => (
|
}) => (
|
||||||
<FormField className={styles.root} data-testid="configure-auth-sso-key">
|
<FormField className={styles.root}>
|
||||||
<Localized id="configure-auth-sso-key">
|
<Localized id="configure-auth-sso-key">
|
||||||
<Label>Key</Label>
|
<Label htmlFor="configure-auth-sso-key">Key</Label>
|
||||||
</Localized>
|
</Localized>
|
||||||
<PasswordField
|
<PasswordField
|
||||||
|
id="configure-auth-sso-key"
|
||||||
name="key"
|
name="key"
|
||||||
value={generatedKey}
|
value={generatedKey}
|
||||||
readOnly
|
readOnly
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import { Localized } from "fluent-react/compat";
|
import { Localized } from "fluent-react/compat";
|
||||||
import React, { FunctionComponent } from "react";
|
import React, { FunctionComponent } from "react";
|
||||||
import { Field } from "react-final-form";
|
import { Field } from "react-final-form";
|
||||||
|
import { graphql } from "react-relay";
|
||||||
|
|
||||||
import { colorFromMeta } from "coral-framework/lib/form";
|
import { colorFromMeta } from "coral-framework/lib/form";
|
||||||
import {
|
import {
|
||||||
@@ -19,6 +20,13 @@ import ConfigBox from "../../ConfigBox";
|
|||||||
import Header from "../../Header";
|
import Header from "../../Header";
|
||||||
import ValidationMessage from "../../ValidationMessage";
|
import ValidationMessage from "../../ValidationMessage";
|
||||||
|
|
||||||
|
// eslint-disable-next-line no-unused-expressions
|
||||||
|
graphql`
|
||||||
|
fragment SessionConfig_formValues on Auth {
|
||||||
|
sessionDuration
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
disabled?: boolean;
|
disabled?: boolean;
|
||||||
}
|
}
|
||||||
@@ -45,9 +53,9 @@ const SessionConfig: FunctionComponent<Props> = ({ disabled }) => (
|
|||||||
{({ input, meta }) => (
|
{({ input, meta }) => (
|
||||||
<>
|
<>
|
||||||
<DurationField
|
<DurationField
|
||||||
|
{...input}
|
||||||
color={colorFromMeta(meta)}
|
color={colorFromMeta(meta)}
|
||||||
disabled={!!disabled}
|
disabled={!!disabled}
|
||||||
{...input}
|
|
||||||
/>
|
/>
|
||||||
<ValidationMessage meta={meta} fullWidth />
|
<ValidationMessage meta={meta} fullWidth />
|
||||||
</>
|
</>
|
||||||
|
|||||||
@@ -1,36 +0,0 @@
|
|||||||
import React from "react";
|
|
||||||
import { graphql } from "react-relay";
|
|
||||||
|
|
||||||
import { withFragmentContainer } from "coral-framework/lib/relay";
|
|
||||||
|
|
||||||
import { SessionConfigContainer_auth as AuthData } from "coral-admin/__generated__/SessionConfigContainer_auth.graphql";
|
|
||||||
|
|
||||||
import { OnInitValuesFct } from "./AuthConfigContainer";
|
|
||||||
import SessionConfig from "./SessionConfig";
|
|
||||||
|
|
||||||
interface Props {
|
|
||||||
auth: AuthData;
|
|
||||||
onInitValues: OnInitValuesFct;
|
|
||||||
disabled?: boolean;
|
|
||||||
}
|
|
||||||
|
|
||||||
class SessionConfigContainer extends React.Component<Props> {
|
|
||||||
constructor(props: Props) {
|
|
||||||
super(props);
|
|
||||||
props.onInitValues({ auth: props.auth });
|
|
||||||
}
|
|
||||||
|
|
||||||
public render() {
|
|
||||||
const { disabled } = this.props;
|
|
||||||
return <SessionConfig disabled={disabled} />;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const enhanced = withFragmentContainer<Props>({
|
|
||||||
auth: graphql`
|
|
||||||
fragment SessionConfigContainer_auth on Auth {
|
|
||||||
sessionDuration
|
|
||||||
}
|
|
||||||
`,
|
|
||||||
})(SessionConfigContainer);
|
|
||||||
export default enhanced;
|
|
||||||
@@ -22,7 +22,7 @@ const TargetFilterField: FunctionComponent<Props> = ({
|
|||||||
<Field name={`${name}.admin`} type="checkbox" parse={parseBool}>
|
<Field name={`${name}.admin`} type="checkbox" parse={parseBool}>
|
||||||
{({ input }) => (
|
{({ input }) => (
|
||||||
<Localized id="configure-auth-targetFilterCoralAdmin">
|
<Localized id="configure-auth-targetFilterCoralAdmin">
|
||||||
<CheckBox id={input.name} disabled={disabled} {...input}>
|
<CheckBox {...input} id={input.name} disabled={disabled}>
|
||||||
Coral Admin
|
Coral Admin
|
||||||
</CheckBox>
|
</CheckBox>
|
||||||
</Localized>
|
</Localized>
|
||||||
@@ -31,7 +31,7 @@ const TargetFilterField: FunctionComponent<Props> = ({
|
|||||||
<Field name={`${name}.stream`} type="checkbox" parse={parseBool}>
|
<Field name={`${name}.stream`} type="checkbox" parse={parseBool}>
|
||||||
{({ input }) => (
|
{({ input }) => (
|
||||||
<Localized id="configure-auth-targetFilterCommentStream">
|
<Localized id="configure-auth-targetFilterCommentStream">
|
||||||
<CheckBox id={input.name} disabled={disabled} {...input}>
|
<CheckBox {...input} id={input.name} disabled={disabled}>
|
||||||
Comment Stream
|
Comment Stream
|
||||||
</CheckBox>
|
</CheckBox>
|
||||||
</Localized>
|
</Localized>
|
||||||
|
|||||||
@@ -1,108 +1,80 @@
|
|||||||
import { FormApi } from "final-form";
|
|
||||||
import { Localized } from "fluent-react/compat";
|
import { Localized } from "fluent-react/compat";
|
||||||
import { RouteProps } from "found";
|
import React, { useMemo } from "react";
|
||||||
import React from "react";
|
import { useForm } from "react-final-form";
|
||||||
import { graphql } from "react-relay";
|
import { graphql } from "react-relay";
|
||||||
|
|
||||||
import { DeepNullable, DeepPartial } from "coral-common/types";
|
import { DeepNullable } from "coral-common/types";
|
||||||
import { pureMerge } from "coral-common/utils";
|
import {
|
||||||
import { withFragmentContainer } from "coral-framework/lib/relay";
|
purgeMetadata,
|
||||||
|
withFragmentContainer,
|
||||||
|
} from "coral-framework/lib/relay";
|
||||||
import { GQLSettings } from "coral-framework/schema";
|
import { GQLSettings } from "coral-framework/schema";
|
||||||
|
|
||||||
import { EmailConfigContainer_email } from "coral-admin/__generated__/EmailConfigContainer_email.graphql";
|
import { EmailConfigContainer_email } from "coral-admin/__generated__/EmailConfigContainer_email.graphql";
|
||||||
|
|
||||||
import Header from "../../Header";
|
import Header from "../../Header";
|
||||||
import ConfigBoxWithToggleField from "../Auth/ConfigBoxWithToggleField";
|
import ConfigBoxWithToggleField from "../Auth/ConfigBoxWithToggleField";
|
||||||
import FromContainer from "./FromContainer";
|
import From from "./From";
|
||||||
import SMTPContainer from "./SMTPContainer";
|
import SMTP from "./SMTP";
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
form: FormApi;
|
|
||||||
submitting: boolean;
|
submitting: boolean;
|
||||||
email: EmailConfigContainer_email;
|
email: EmailConfigContainer_email;
|
||||||
}
|
}
|
||||||
|
|
||||||
export type FormProps = DeepNullable<Pick<GQLSettings, "email">>;
|
export type FormProps = DeepNullable<Pick<GQLSettings, "email">>;
|
||||||
export type OnInitValuesFct = (values: DeepPartial<FormProps>) => void;
|
|
||||||
|
|
||||||
class EmailConfigContainer extends React.Component<Props> {
|
const EmailConfigContainer: React.FunctionComponent<Props> = ({
|
||||||
public static routeConfig: RouteProps;
|
email,
|
||||||
private initialValues: DeepPartial<FormProps> = {};
|
submitting,
|
||||||
|
}) => {
|
||||||
public componentDidMount() {
|
const form = useForm();
|
||||||
this.props.form.initialize(this.initialValues);
|
useMemo(() => {
|
||||||
}
|
let values: any = { email };
|
||||||
|
if (email && email.smtp && email.smtp.authentication === null) {
|
||||||
private handleOnInitValues: OnInitValuesFct = values => {
|
|
||||||
if (
|
|
||||||
values.email &&
|
|
||||||
values.email.smtp &&
|
|
||||||
values.email.smtp.authentication === null
|
|
||||||
) {
|
|
||||||
values = {
|
values = {
|
||||||
email: {
|
email: {
|
||||||
...values.email,
|
...email,
|
||||||
smtp: { ...values.email.smtp, authentication: true },
|
smtp: { ...email.smtp, authentication: true },
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
if (
|
if (email && email.smtp && email.smtp.secure === null) {
|
||||||
values.email &&
|
|
||||||
values.email.smtp &&
|
|
||||||
values.email.smtp.secure === null
|
|
||||||
) {
|
|
||||||
values = {
|
values = {
|
||||||
email: {
|
email: {
|
||||||
...values.email,
|
...email,
|
||||||
smtp: { ...values.email.smtp, secure: true },
|
smtp: { ...email.smtp, secure: true },
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
form.initialize(purgeMetadata(values));
|
||||||
this.initialValues = pureMerge<DeepPartial<FormProps>>(
|
}, []);
|
||||||
this.initialValues,
|
return (
|
||||||
values
|
<ConfigBoxWithToggleField
|
||||||
);
|
disabled={submitting}
|
||||||
};
|
title={
|
||||||
|
<Localized id="configure-email">
|
||||||
public render() {
|
<Header container="h2">Email settings</Header>
|
||||||
const { email, submitting } = this.props;
|
</Localized>
|
||||||
|
}
|
||||||
return (
|
name="email.enabled"
|
||||||
<ConfigBoxWithToggleField
|
>
|
||||||
disabled={submitting}
|
{disabledInside => (
|
||||||
title={
|
<>
|
||||||
<Localized id="configure-email">
|
<From disabled={disabledInside} />
|
||||||
<Header container="h2">Email settings</Header>
|
<SMTP disabled={disabledInside} />
|
||||||
</Localized>
|
</>
|
||||||
}
|
)}
|
||||||
name="email.enabled"
|
</ConfigBoxWithToggleField>
|
||||||
>
|
);
|
||||||
{disabledInside => (
|
};
|
||||||
<>
|
|
||||||
<FromContainer
|
|
||||||
email={email}
|
|
||||||
disabled={disabledInside}
|
|
||||||
onInitValues={this.handleOnInitValues}
|
|
||||||
/>
|
|
||||||
<SMTPContainer
|
|
||||||
email={email}
|
|
||||||
disabled={disabledInside}
|
|
||||||
onInitValues={this.handleOnInitValues}
|
|
||||||
/>
|
|
||||||
</>
|
|
||||||
)}
|
|
||||||
</ConfigBoxWithToggleField>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const enhanced = withFragmentContainer<Props>({
|
const enhanced = withFragmentContainer<Props>({
|
||||||
email: graphql`
|
email: graphql`
|
||||||
fragment EmailConfigContainer_email on EmailConfiguration {
|
fragment EmailConfigContainer_email on EmailConfiguration {
|
||||||
enabled
|
enabled
|
||||||
...FromContainer_email
|
...From_formValues @relay(mask: false)
|
||||||
...SMTPContainer_email
|
...SMTP_formValues @relay(mask: false)
|
||||||
}
|
}
|
||||||
`,
|
`,
|
||||||
})(EmailConfigContainer);
|
})(EmailConfigContainer);
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
import { FormApi } from "final-form";
|
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import { graphql } from "react-relay";
|
import { graphql } from "react-relay";
|
||||||
|
|
||||||
@@ -11,7 +10,6 @@ import EmailConfigContainer from "./EmailConfigContainer";
|
|||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
data: EmailConfigRouteQueryResponse | null;
|
data: EmailConfigRouteQueryResponse | null;
|
||||||
form: FormApi;
|
|
||||||
submitting: boolean;
|
submitting: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -27,7 +25,6 @@ class EmailConfigRoute extends React.Component<Props> {
|
|||||||
return (
|
return (
|
||||||
<EmailConfigContainer
|
<EmailConfigContainer
|
||||||
email={this.props.data.settings.email}
|
email={this.props.data.settings.email}
|
||||||
form={this.props.form}
|
|
||||||
submitting={this.props.submitting}
|
submitting={this.props.submitting}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import { Localized } from "fluent-react/compat";
|
import { Localized } from "fluent-react/compat";
|
||||||
import React, { FunctionComponent } from "react";
|
import React, { FunctionComponent } from "react";
|
||||||
import { Field } from "react-final-form";
|
import { Field } from "react-final-form";
|
||||||
|
import { graphql } from "react-relay";
|
||||||
|
|
||||||
import { parseEmptyAsNull } from "coral-framework/lib/form";
|
import { parseEmptyAsNull } from "coral-framework/lib/form";
|
||||||
import { validateEmail } from "coral-framework/lib/validation";
|
import { validateEmail } from "coral-framework/lib/validation";
|
||||||
@@ -13,6 +14,15 @@ import {
|
|||||||
|
|
||||||
import TextFieldWithValidation from "../../TextFieldWithValidation";
|
import TextFieldWithValidation from "../../TextFieldWithValidation";
|
||||||
|
|
||||||
|
// eslint-disable-next-line no-unused-expressions
|
||||||
|
graphql`
|
||||||
|
fragment From_formValues on EmailConfiguration {
|
||||||
|
enabled
|
||||||
|
fromName
|
||||||
|
fromEmail
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
disabled: boolean;
|
disabled: boolean;
|
||||||
}
|
}
|
||||||
@@ -31,10 +41,10 @@ const From: FunctionComponent<Props> = ({ disabled }) => (
|
|||||||
<Field name="email.fromName" parse={parseEmptyAsNull}>
|
<Field name="email.fromName" parse={parseEmptyAsNull}>
|
||||||
{({ input, meta }) => (
|
{({ input, meta }) => (
|
||||||
<TextFieldWithValidation
|
<TextFieldWithValidation
|
||||||
|
{...input}
|
||||||
fullWidth
|
fullWidth
|
||||||
disabled={disabled}
|
disabled={disabled}
|
||||||
meta={meta}
|
meta={meta}
|
||||||
{...input}
|
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
</Field>
|
</Field>
|
||||||
@@ -57,11 +67,11 @@ const From: FunctionComponent<Props> = ({ disabled }) => (
|
|||||||
>
|
>
|
||||||
{({ input, meta }) => (
|
{({ input, meta }) => (
|
||||||
<TextFieldWithValidation
|
<TextFieldWithValidation
|
||||||
|
{...input}
|
||||||
type="email"
|
type="email"
|
||||||
fullWidth
|
fullWidth
|
||||||
meta={meta}
|
meta={meta}
|
||||||
disabled={disabled}
|
disabled={disabled}
|
||||||
{...input}
|
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
</Field>
|
</Field>
|
||||||
|
|||||||
@@ -1,39 +0,0 @@
|
|||||||
import React from "react";
|
|
||||||
import { graphql } from "react-relay";
|
|
||||||
|
|
||||||
import { withFragmentContainer } from "coral-framework/lib/relay";
|
|
||||||
|
|
||||||
import { FromContainer_email } from "coral-admin/__generated__/FromContainer_email.graphql";
|
|
||||||
|
|
||||||
import { OnInitValuesFct } from "./EmailConfigContainer";
|
|
||||||
import From from "./From";
|
|
||||||
|
|
||||||
interface Props {
|
|
||||||
disabled: boolean;
|
|
||||||
onInitValues: OnInitValuesFct;
|
|
||||||
email: FromContainer_email;
|
|
||||||
}
|
|
||||||
|
|
||||||
class FromContainer extends React.Component<Props> {
|
|
||||||
constructor(props: Props) {
|
|
||||||
super(props);
|
|
||||||
props.onInitValues({ email: props.email });
|
|
||||||
}
|
|
||||||
|
|
||||||
public render() {
|
|
||||||
const { disabled } = this.props;
|
|
||||||
return <From disabled={disabled} />;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const enhanced = withFragmentContainer<Props>({
|
|
||||||
email: graphql`
|
|
||||||
fragment FromContainer_email on EmailConfiguration {
|
|
||||||
enabled
|
|
||||||
fromName
|
|
||||||
fromEmail
|
|
||||||
}
|
|
||||||
`,
|
|
||||||
})(FromContainer);
|
|
||||||
|
|
||||||
export default enhanced;
|
|
||||||
@@ -1,6 +1,7 @@
|
|||||||
import { Localized } from "fluent-react/compat";
|
import { Localized } from "fluent-react/compat";
|
||||||
import React, { FunctionComponent } from "react";
|
import React, { FunctionComponent } from "react";
|
||||||
import { Field } from "react-final-form";
|
import { Field } from "react-final-form";
|
||||||
|
import { graphql } from "react-relay";
|
||||||
|
|
||||||
import {
|
import {
|
||||||
colorFromMeta,
|
colorFromMeta,
|
||||||
@@ -25,12 +26,26 @@ import Subheader from "../../Subheader";
|
|||||||
import TextFieldWithValidation from "../../TextFieldWithValidation";
|
import TextFieldWithValidation from "../../TextFieldWithValidation";
|
||||||
import { FormProps } from "./EmailConfigContainer";
|
import { FormProps } from "./EmailConfigContainer";
|
||||||
|
|
||||||
|
// eslint-disable-next-line no-unused-expressions
|
||||||
|
graphql`
|
||||||
|
fragment SMTP_formValues on EmailConfiguration {
|
||||||
|
enabled
|
||||||
|
smtp {
|
||||||
|
host
|
||||||
|
port
|
||||||
|
secure
|
||||||
|
authentication
|
||||||
|
username
|
||||||
|
password
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`;
|
||||||
interface Props {
|
interface Props {
|
||||||
disabled: boolean;
|
disabled: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
const isEnabled: Condition<any, FormProps> = (value, values) =>
|
const isEnabled: Condition<any, FormProps> = (value, values) =>
|
||||||
Boolean(values.email.enabled);
|
Boolean(values.email && values.email.enabled);
|
||||||
|
|
||||||
const isAuthenticating: Condition<any, FormProps> = (value, values) =>
|
const isAuthenticating: Condition<any, FormProps> = (value, values) =>
|
||||||
Boolean(values.email.enabled && values.email.smtp.authentication);
|
Boolean(values.email.enabled && values.email.smtp.authentication);
|
||||||
@@ -52,11 +67,11 @@ const SMTP: FunctionComponent<Props> = ({ disabled }) => (
|
|||||||
>
|
>
|
||||||
{({ input, meta }) => (
|
{({ input, meta }) => (
|
||||||
<TextFieldWithValidation
|
<TextFieldWithValidation
|
||||||
|
{...input}
|
||||||
id={input.name}
|
id={input.name}
|
||||||
fullWidth
|
fullWidth
|
||||||
disabled={disabled}
|
disabled={disabled}
|
||||||
meta={meta}
|
meta={meta}
|
||||||
{...input}
|
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
</Field>
|
</Field>
|
||||||
@@ -76,12 +91,12 @@ const SMTP: FunctionComponent<Props> = ({ disabled }) => (
|
|||||||
>
|
>
|
||||||
{({ input, meta }) => (
|
{({ input, meta }) => (
|
||||||
<TextFieldWithValidation
|
<TextFieldWithValidation
|
||||||
|
{...input}
|
||||||
id={input.name}
|
id={input.name}
|
||||||
type="number"
|
type="number"
|
||||||
fullWidth
|
fullWidth
|
||||||
disabled={disabled}
|
disabled={disabled}
|
||||||
meta={meta}
|
meta={meta}
|
||||||
{...input}
|
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
</Field>
|
</Field>
|
||||||
@@ -123,11 +138,11 @@ const SMTP: FunctionComponent<Props> = ({ disabled }) => (
|
|||||||
>
|
>
|
||||||
{({ input, meta }) => (
|
{({ input, meta }) => (
|
||||||
<TextFieldWithValidation
|
<TextFieldWithValidation
|
||||||
|
{...input}
|
||||||
id={input.name}
|
id={input.name}
|
||||||
disabled={disabled || !enabled}
|
disabled={disabled || !enabled}
|
||||||
fullWidth
|
fullWidth
|
||||||
meta={meta}
|
meta={meta}
|
||||||
{...input}
|
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
</Field>
|
</Field>
|
||||||
@@ -144,11 +159,11 @@ const SMTP: FunctionComponent<Props> = ({ disabled }) => (
|
|||||||
{({ input, meta }) => (
|
{({ input, meta }) => (
|
||||||
<>
|
<>
|
||||||
<PasswordField
|
<PasswordField
|
||||||
|
{...input}
|
||||||
id={input.name}
|
id={input.name}
|
||||||
disabled={disabled || !enabled}
|
disabled={disabled || !enabled}
|
||||||
fullWidth
|
fullWidth
|
||||||
color={colorFromMeta(meta)}
|
color={colorFromMeta(meta)}
|
||||||
{...input}
|
|
||||||
/>
|
/>
|
||||||
<ValidationMessage fullWidth meta={meta} />
|
<ValidationMessage fullWidth meta={meta} />
|
||||||
</>
|
</>
|
||||||
|
|||||||
@@ -1,45 +0,0 @@
|
|||||||
import React from "react";
|
|
||||||
import { graphql } from "react-relay";
|
|
||||||
|
|
||||||
import { withFragmentContainer } from "coral-framework/lib/relay";
|
|
||||||
|
|
||||||
import { SMTPContainer_email } from "coral-admin/__generated__/SMTPContainer_email.graphql";
|
|
||||||
|
|
||||||
import { OnInitValuesFct } from "./EmailConfigContainer";
|
|
||||||
import SMTP from "./SMTP";
|
|
||||||
|
|
||||||
interface Props {
|
|
||||||
email: SMTPContainer_email;
|
|
||||||
disabled: boolean;
|
|
||||||
onInitValues: OnInitValuesFct;
|
|
||||||
}
|
|
||||||
|
|
||||||
class SMTPContainer extends React.Component<Props> {
|
|
||||||
constructor(props: Props) {
|
|
||||||
super(props);
|
|
||||||
props.onInitValues({ email: props.email });
|
|
||||||
}
|
|
||||||
|
|
||||||
public render() {
|
|
||||||
const { disabled } = this.props;
|
|
||||||
return <SMTP disabled={disabled} />;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const enhanced = withFragmentContainer<Props>({
|
|
||||||
email: graphql`
|
|
||||||
fragment SMTPContainer_email on EmailConfiguration {
|
|
||||||
enabled
|
|
||||||
smtp {
|
|
||||||
host
|
|
||||||
port
|
|
||||||
secure
|
|
||||||
authentication
|
|
||||||
username
|
|
||||||
password
|
|
||||||
}
|
|
||||||
}
|
|
||||||
`,
|
|
||||||
})(SMTPContainer);
|
|
||||||
|
|
||||||
export default enhanced;
|
|
||||||
+11
-1
@@ -1,6 +1,7 @@
|
|||||||
import { Localized } from "fluent-react/compat";
|
import { Localized } from "fluent-react/compat";
|
||||||
import React, { FunctionComponent, Suspense } from "react";
|
import React, { FunctionComponent, Suspense } from "react";
|
||||||
import { Field } from "react-final-form";
|
import { Field } from "react-final-form";
|
||||||
|
import { graphql } from "react-relay";
|
||||||
|
|
||||||
import { MarkdownEditor } from "coral-framework/components/loadables";
|
import { MarkdownEditor } from "coral-framework/components/loadables";
|
||||||
import { parseEmptyAsNull } from "coral-framework/lib/form";
|
import { parseEmptyAsNull } from "coral-framework/lib/form";
|
||||||
@@ -10,6 +11,15 @@ import ConfigBox from "../../ConfigBox";
|
|||||||
import Header from "../../Header";
|
import Header from "../../Header";
|
||||||
import ValidationMessage from "../../ValidationMessage";
|
import ValidationMessage from "../../ValidationMessage";
|
||||||
|
|
||||||
|
// eslint-disable-next-line no-unused-expressions
|
||||||
|
graphql`
|
||||||
|
fragment ClosedStreamMessageConfig_formValues on Settings {
|
||||||
|
closeCommenting {
|
||||||
|
message
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
disabled: boolean;
|
disabled: boolean;
|
||||||
}
|
}
|
||||||
@@ -37,8 +47,8 @@ const ClosedStreamMessageConfig: FunctionComponent<Props> = ({ disabled }) => (
|
|||||||
<>
|
<>
|
||||||
<Suspense fallback={<Spinner />}>
|
<Suspense fallback={<Spinner />}>
|
||||||
<MarkdownEditor
|
<MarkdownEditor
|
||||||
id="configure-general-closedStreamMessage-content"
|
|
||||||
{...input}
|
{...input}
|
||||||
|
id="configure-general-closedStreamMessage-content"
|
||||||
/>
|
/>
|
||||||
</Suspense>
|
</Suspense>
|
||||||
<ValidationMessage meta={meta} fullWidth />
|
<ValidationMessage meta={meta} fullWidth />
|
||||||
|
|||||||
-38
@@ -1,38 +0,0 @@
|
|||||||
import React from "react";
|
|
||||||
import { graphql } from "react-relay";
|
|
||||||
|
|
||||||
import { withFragmentContainer } from "coral-framework/lib/relay";
|
|
||||||
|
|
||||||
import { ClosedStreamMessageConfigContainer_settings as SettingsData } from "coral-admin/__generated__/ClosedStreamMessageConfigContainer_settings.graphql";
|
|
||||||
|
|
||||||
import ClosedStreamMessageConfig from "./ClosedStreamMessageConfig";
|
|
||||||
|
|
||||||
interface Props {
|
|
||||||
settings: SettingsData;
|
|
||||||
onInitValues: (values: SettingsData) => void;
|
|
||||||
disabled: boolean;
|
|
||||||
}
|
|
||||||
|
|
||||||
class ClosedStreamMessageConfigContainer extends React.Component<Props> {
|
|
||||||
constructor(props: Props) {
|
|
||||||
super(props);
|
|
||||||
props.onInitValues(props.settings);
|
|
||||||
}
|
|
||||||
|
|
||||||
public render() {
|
|
||||||
const { disabled } = this.props;
|
|
||||||
return <ClosedStreamMessageConfig disabled={disabled} />;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const enhanced = withFragmentContainer<Props>({
|
|
||||||
settings: graphql`
|
|
||||||
fragment ClosedStreamMessageConfigContainer_settings on Settings {
|
|
||||||
closeCommenting {
|
|
||||||
message
|
|
||||||
}
|
|
||||||
}
|
|
||||||
`,
|
|
||||||
})(ClosedStreamMessageConfigContainer);
|
|
||||||
|
|
||||||
export default enhanced;
|
|
||||||
+12
-1
@@ -1,6 +1,7 @@
|
|||||||
import { Localized } from "fluent-react/compat";
|
import { Localized } from "fluent-react/compat";
|
||||||
import React, { FunctionComponent } from "react";
|
import React, { FunctionComponent } from "react";
|
||||||
import { Field } from "react-final-form";
|
import { Field } from "react-final-form";
|
||||||
|
import { graphql } from "react-relay";
|
||||||
|
|
||||||
import { colorFromMeta } from "coral-framework/lib/form";
|
import { colorFromMeta } from "coral-framework/lib/form";
|
||||||
import {
|
import {
|
||||||
@@ -22,6 +23,16 @@ import Header from "../../Header";
|
|||||||
import OnOffField from "../../OnOffField";
|
import OnOffField from "../../OnOffField";
|
||||||
import ValidationMessage from "../../ValidationMessage";
|
import ValidationMessage from "../../ValidationMessage";
|
||||||
|
|
||||||
|
// eslint-disable-next-line no-unused-expressions
|
||||||
|
graphql`
|
||||||
|
fragment ClosingCommentStreamsConfig_formValues on Settings {
|
||||||
|
closeCommenting {
|
||||||
|
auto
|
||||||
|
timeout
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
disabled: boolean;
|
disabled: boolean;
|
||||||
}
|
}
|
||||||
@@ -67,6 +78,7 @@ const ClosingCommentStreamsConfig: FunctionComponent<Props> = ({
|
|||||||
{({ input, meta }) => (
|
{({ input, meta }) => (
|
||||||
<>
|
<>
|
||||||
<DurationField
|
<DurationField
|
||||||
|
{...input}
|
||||||
units={[
|
units={[
|
||||||
DURATION_UNIT.HOURS,
|
DURATION_UNIT.HOURS,
|
||||||
DURATION_UNIT.DAYS,
|
DURATION_UNIT.DAYS,
|
||||||
@@ -74,7 +86,6 @@ const ClosingCommentStreamsConfig: FunctionComponent<Props> = ({
|
|||||||
]}
|
]}
|
||||||
disabled={disabled}
|
disabled={disabled}
|
||||||
color={colorFromMeta(meta)}
|
color={colorFromMeta(meta)}
|
||||||
{...input}
|
|
||||||
/>
|
/>
|
||||||
<ValidationMessage meta={meta} fullWidth />
|
<ValidationMessage meta={meta} fullWidth />
|
||||||
</>
|
</>
|
||||||
|
|||||||
-39
@@ -1,39 +0,0 @@
|
|||||||
import React from "react";
|
|
||||||
import { graphql } from "react-relay";
|
|
||||||
|
|
||||||
import { withFragmentContainer } from "coral-framework/lib/relay";
|
|
||||||
|
|
||||||
import { ClosingCommentStreamsConfigContainer_settings as SettingsData } from "coral-admin/__generated__/ClosingCommentStreamsConfigContainer_settings.graphql";
|
|
||||||
|
|
||||||
import ClosingCommentStreamsConfig from "./ClosingCommentStreamsConfig";
|
|
||||||
|
|
||||||
interface Props {
|
|
||||||
settings: SettingsData;
|
|
||||||
onInitValues: (values: SettingsData) => void;
|
|
||||||
disabled: boolean;
|
|
||||||
}
|
|
||||||
|
|
||||||
class ClosingCommentStreamsConfigContainer extends React.Component<Props> {
|
|
||||||
constructor(props: Props) {
|
|
||||||
super(props);
|
|
||||||
props.onInitValues(props.settings);
|
|
||||||
}
|
|
||||||
|
|
||||||
public render() {
|
|
||||||
const { disabled } = this.props;
|
|
||||||
return <ClosingCommentStreamsConfig disabled={disabled} />;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const enhanced = withFragmentContainer<Props>({
|
|
||||||
settings: graphql`
|
|
||||||
fragment ClosingCommentStreamsConfigContainer_settings on Settings {
|
|
||||||
closeCommenting {
|
|
||||||
auto
|
|
||||||
timeout
|
|
||||||
}
|
|
||||||
}
|
|
||||||
`,
|
|
||||||
})(ClosingCommentStreamsConfigContainer);
|
|
||||||
|
|
||||||
export default enhanced;
|
|
||||||
@@ -1,6 +1,7 @@
|
|||||||
import { Localized } from "fluent-react/compat";
|
import { Localized } from "fluent-react/compat";
|
||||||
import React, { FunctionComponent } from "react";
|
import React, { FunctionComponent } from "react";
|
||||||
import { Field } from "react-final-form";
|
import { Field } from "react-final-form";
|
||||||
|
import { graphql } from "react-relay";
|
||||||
|
|
||||||
import { colorFromMeta } from "coral-framework/lib/form";
|
import { colorFromMeta } from "coral-framework/lib/form";
|
||||||
import {
|
import {
|
||||||
@@ -21,6 +22,12 @@ import ConfigBox from "../../ConfigBox";
|
|||||||
import Header from "../../Header";
|
import Header from "../../Header";
|
||||||
import ValidationMessage from "../../ValidationMessage";
|
import ValidationMessage from "../../ValidationMessage";
|
||||||
|
|
||||||
|
// eslint-disable-next-line no-unused-expressions
|
||||||
|
graphql`
|
||||||
|
fragment CommentEditingConfig_formValues on Settings {
|
||||||
|
editCommentWindowLength
|
||||||
|
}
|
||||||
|
`;
|
||||||
interface Props {
|
interface Props {
|
||||||
disabled: boolean;
|
disabled: boolean;
|
||||||
}
|
}
|
||||||
@@ -58,6 +65,7 @@ const CommentEditingConfig: FunctionComponent<Props> = ({ disabled }) => (
|
|||||||
{({ input, meta }) => (
|
{({ input, meta }) => (
|
||||||
<>
|
<>
|
||||||
<DurationField
|
<DurationField
|
||||||
|
{...input}
|
||||||
units={[
|
units={[
|
||||||
DURATION_UNIT.SECONDS,
|
DURATION_UNIT.SECONDS,
|
||||||
DURATION_UNIT.MINUTES,
|
DURATION_UNIT.MINUTES,
|
||||||
@@ -65,7 +73,6 @@ const CommentEditingConfig: FunctionComponent<Props> = ({ disabled }) => (
|
|||||||
]}
|
]}
|
||||||
color={colorFromMeta(meta)}
|
color={colorFromMeta(meta)}
|
||||||
disabled={disabled}
|
disabled={disabled}
|
||||||
{...input}
|
|
||||||
/>
|
/>
|
||||||
<ValidationMessage meta={meta} fullWidth />
|
<ValidationMessage meta={meta} fullWidth />
|
||||||
</>
|
</>
|
||||||
|
|||||||
-36
@@ -1,36 +0,0 @@
|
|||||||
import React from "react";
|
|
||||||
import { graphql } from "react-relay";
|
|
||||||
|
|
||||||
import { withFragmentContainer } from "coral-framework/lib/relay";
|
|
||||||
|
|
||||||
import { CommentEditingConfigContainer_settings as SettingsData } from "coral-admin/__generated__/CommentEditingConfigContainer_settings.graphql";
|
|
||||||
|
|
||||||
import CommentEditingConfig from "./CommentEditingConfig";
|
|
||||||
|
|
||||||
interface Props {
|
|
||||||
settings: SettingsData;
|
|
||||||
onInitValues: (values: SettingsData) => void;
|
|
||||||
disabled: boolean;
|
|
||||||
}
|
|
||||||
|
|
||||||
class CommentEditingConfigContainer extends React.Component<Props> {
|
|
||||||
constructor(props: Props) {
|
|
||||||
super(props);
|
|
||||||
props.onInitValues(props.settings);
|
|
||||||
}
|
|
||||||
|
|
||||||
public render() {
|
|
||||||
const { disabled } = this.props;
|
|
||||||
return <CommentEditingConfig disabled={disabled} />;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const enhanced = withFragmentContainer<Props>({
|
|
||||||
settings: graphql`
|
|
||||||
fragment CommentEditingConfigContainer_settings on Settings {
|
|
||||||
editCommentWindowLength
|
|
||||||
}
|
|
||||||
`,
|
|
||||||
})(CommentEditingConfigContainer);
|
|
||||||
|
|
||||||
export default enhanced;
|
|
||||||
@@ -1,6 +1,7 @@
|
|||||||
import { Localized } from "fluent-react/compat";
|
import { Localized } from "fluent-react/compat";
|
||||||
import React, { FunctionComponent } from "react";
|
import React, { FunctionComponent } from "react";
|
||||||
import { Field } from "react-final-form";
|
import { Field } from "react-final-form";
|
||||||
|
import { graphql } from "react-relay";
|
||||||
|
|
||||||
import { formatEmpty, parseEmptyAsNull } from "coral-framework/lib/form";
|
import { formatEmpty, parseEmptyAsNull } from "coral-framework/lib/form";
|
||||||
import {
|
import {
|
||||||
@@ -23,8 +24,19 @@ import TextFieldWithValidation from "../../TextFieldWithValidation";
|
|||||||
|
|
||||||
import styles from "./CommentLengthConfig.css";
|
import styles from "./CommentLengthConfig.css";
|
||||||
|
|
||||||
|
// eslint-disable-next-line no-unused-expressions
|
||||||
|
graphql`
|
||||||
|
fragment CommentLengthConfig_formValues on Settings {
|
||||||
|
charCount {
|
||||||
|
enabled
|
||||||
|
min
|
||||||
|
max
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
const validateMaxLongerThanMin = createValidator(
|
const validateMaxLongerThanMin = createValidator(
|
||||||
(v, values) =>
|
(v: any, values: any) =>
|
||||||
v === null ||
|
v === null ||
|
||||||
values.charCount.min === null ||
|
values.charCount.min === null ||
|
||||||
parseInt(v, 10) > parseInt(values.charCount.min, 10),
|
parseInt(v, 10) > parseInt(values.charCount.min, 10),
|
||||||
@@ -82,11 +94,11 @@ const CommentLengthConfig: FunctionComponent<Props> = ({ disabled }) => (
|
|||||||
attrs={{ placeholder: true }}
|
attrs={{ placeholder: true }}
|
||||||
>
|
>
|
||||||
<TextFieldWithValidation
|
<TextFieldWithValidation
|
||||||
|
{...input}
|
||||||
id="configure-general-commentLength-min"
|
id="configure-general-commentLength-min"
|
||||||
classes={{
|
classes={{
|
||||||
input: styles.commentLengthTextInput,
|
input: styles.commentLengthTextInput,
|
||||||
}}
|
}}
|
||||||
{...input}
|
|
||||||
disabled={disabled}
|
disabled={disabled}
|
||||||
autoComplete="off"
|
autoComplete="off"
|
||||||
meta={meta}
|
meta={meta}
|
||||||
@@ -126,6 +138,7 @@ const CommentLengthConfig: FunctionComponent<Props> = ({ disabled }) => (
|
|||||||
attrs={{ placeholder: true }}
|
attrs={{ placeholder: true }}
|
||||||
>
|
>
|
||||||
<TextFieldWithValidation
|
<TextFieldWithValidation
|
||||||
|
{...input}
|
||||||
id="configure-general-commentLength-max"
|
id="configure-general-commentLength-max"
|
||||||
classes={{
|
classes={{
|
||||||
input: styles.commentLengthTextInput,
|
input: styles.commentLengthTextInput,
|
||||||
@@ -143,7 +156,6 @@ const CommentLengthConfig: FunctionComponent<Props> = ({ disabled }) => (
|
|||||||
placeholder={"No limit"}
|
placeholder={"No limit"}
|
||||||
textAlignCenter
|
textAlignCenter
|
||||||
meta={meta}
|
meta={meta}
|
||||||
{...input}
|
|
||||||
/>
|
/>
|
||||||
</Localized>
|
</Localized>
|
||||||
)}
|
)}
|
||||||
|
|||||||
-40
@@ -1,40 +0,0 @@
|
|||||||
import React from "react";
|
|
||||||
import { graphql } from "react-relay";
|
|
||||||
|
|
||||||
import { withFragmentContainer } from "coral-framework/lib/relay";
|
|
||||||
|
|
||||||
import { CommentLengthConfigContainer_settings as SettingsData } from "coral-admin/__generated__/CommentLengthConfigContainer_settings.graphql";
|
|
||||||
|
|
||||||
import CommentLengthConfig from "./CommentLengthConfig";
|
|
||||||
|
|
||||||
interface Props {
|
|
||||||
settings: SettingsData;
|
|
||||||
onInitValues: (values: SettingsData) => void;
|
|
||||||
disabled: boolean;
|
|
||||||
}
|
|
||||||
|
|
||||||
class CommentLengthConfigContainer extends React.Component<Props> {
|
|
||||||
constructor(props: Props) {
|
|
||||||
super(props);
|
|
||||||
props.onInitValues(props.settings);
|
|
||||||
}
|
|
||||||
|
|
||||||
public render() {
|
|
||||||
const { disabled } = this.props;
|
|
||||||
return <CommentLengthConfig disabled={disabled} />;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const enhanced = withFragmentContainer<Props>({
|
|
||||||
settings: graphql`
|
|
||||||
fragment CommentLengthConfigContainer_settings on Settings {
|
|
||||||
charCount {
|
|
||||||
enabled
|
|
||||||
min
|
|
||||||
max
|
|
||||||
}
|
|
||||||
}
|
|
||||||
`,
|
|
||||||
})(CommentLengthConfigContainer);
|
|
||||||
|
|
||||||
export default enhanced;
|
|
||||||
@@ -1,84 +0,0 @@
|
|||||||
import React, { FunctionComponent } from "react";
|
|
||||||
|
|
||||||
import { PropTypesOf } from "coral-framework/types";
|
|
||||||
import { HorizontalGutter } from "coral-ui/components/v2";
|
|
||||||
|
|
||||||
import ClosedStreamMessageConfigContainer from "./ClosedStreamMessageConfigContainer";
|
|
||||||
import ClosingCommentStreamsConfigContainer from "./ClosingCommentStreamsConfigContainer";
|
|
||||||
import CommentEditingConfigContainer from "./CommentEditingConfigContainer";
|
|
||||||
import CommentLengthConfigContainer from "./CommentLengthConfigContainer";
|
|
||||||
import GuidelinesConfigContainer from "./GuidelinesConfigContainer";
|
|
||||||
import LocaleConfigContainer from "./LocaleConfigContainer";
|
|
||||||
import ReactionConfigContainer from "./ReactionConfigContainer";
|
|
||||||
import SitewideCommentingConfigContainer from "./SitewideCommentingConfigContainer";
|
|
||||||
import StaffConfigContainer from "./StaffConfigContainer";
|
|
||||||
|
|
||||||
interface Props {
|
|
||||||
disabled: boolean;
|
|
||||||
settings: PropTypesOf<typeof GuidelinesConfigContainer>["settings"] &
|
|
||||||
PropTypesOf<typeof CommentLengthConfigContainer>["settings"] &
|
|
||||||
PropTypesOf<typeof CommentEditingConfigContainer>["settings"] &
|
|
||||||
PropTypesOf<typeof ClosedStreamMessageConfigContainer>["settings"] &
|
|
||||||
PropTypesOf<typeof ReactionConfigContainer>["settings"] &
|
|
||||||
PropTypesOf<typeof StaffConfigContainer>["settings"] &
|
|
||||||
PropTypesOf<typeof ClosingCommentStreamsConfigContainer>["settings"] &
|
|
||||||
PropTypesOf<typeof SitewideCommentingConfigContainer>["settings"] &
|
|
||||||
PropTypesOf<typeof LocaleConfigContainer>["settings"];
|
|
||||||
onInitValues: (values: any) => void;
|
|
||||||
}
|
|
||||||
|
|
||||||
const General: FunctionComponent<Props> = ({
|
|
||||||
disabled,
|
|
||||||
settings,
|
|
||||||
onInitValues,
|
|
||||||
}) => (
|
|
||||||
<HorizontalGutter size="double" data-testid="configure-generalContainer">
|
|
||||||
<LocaleConfigContainer
|
|
||||||
disabled={disabled}
|
|
||||||
settings={settings}
|
|
||||||
onInitValues={onInitValues}
|
|
||||||
/>
|
|
||||||
<SitewideCommentingConfigContainer
|
|
||||||
disabled={disabled}
|
|
||||||
settings={settings}
|
|
||||||
onInitValues={onInitValues}
|
|
||||||
/>
|
|
||||||
<GuidelinesConfigContainer
|
|
||||||
disabled={disabled}
|
|
||||||
settings={settings}
|
|
||||||
onInitValues={onInitValues}
|
|
||||||
/>
|
|
||||||
<CommentLengthConfigContainer
|
|
||||||
disabled={disabled}
|
|
||||||
settings={settings}
|
|
||||||
onInitValues={onInitValues}
|
|
||||||
/>
|
|
||||||
<CommentEditingConfigContainer
|
|
||||||
disabled={disabled}
|
|
||||||
settings={settings}
|
|
||||||
onInitValues={onInitValues}
|
|
||||||
/>
|
|
||||||
<ClosingCommentStreamsConfigContainer
|
|
||||||
disabled={disabled}
|
|
||||||
settings={settings}
|
|
||||||
onInitValues={onInitValues}
|
|
||||||
/>
|
|
||||||
<ClosedStreamMessageConfigContainer
|
|
||||||
disabled={disabled}
|
|
||||||
settings={settings}
|
|
||||||
onInitValues={onInitValues}
|
|
||||||
/>
|
|
||||||
<ReactionConfigContainer
|
|
||||||
disabled={disabled}
|
|
||||||
settings={settings}
|
|
||||||
onInitValues={onInitValues}
|
|
||||||
/>
|
|
||||||
<StaffConfigContainer
|
|
||||||
disabled={disabled}
|
|
||||||
settings={settings}
|
|
||||||
onInitValues={onInitValues}
|
|
||||||
/>
|
|
||||||
</HorizontalGutter>
|
|
||||||
);
|
|
||||||
|
|
||||||
export default General;
|
|
||||||
+46
-41
@@ -1,60 +1,65 @@
|
|||||||
import { FormApi } from "final-form";
|
import React, { useMemo } from "react";
|
||||||
import { RouteProps } from "found";
|
import { useForm } from "react-final-form";
|
||||||
import React from "react";
|
|
||||||
import { graphql } from "react-relay";
|
import { graphql } from "react-relay";
|
||||||
|
|
||||||
import { pureMerge } from "coral-common/utils";
|
import {
|
||||||
import { withFragmentContainer } from "coral-framework/lib/relay";
|
purgeMetadata,
|
||||||
|
withFragmentContainer,
|
||||||
|
} from "coral-framework/lib/relay";
|
||||||
|
import { HorizontalGutter } from "coral-ui/components";
|
||||||
|
|
||||||
import { GeneralConfigContainer_settings as SettingsData } from "coral-admin/__generated__/GeneralConfigContainer_settings.graphql";
|
import { GeneralConfigContainer_settings as SettingsData } from "coral-admin/__generated__/GeneralConfigContainer_settings.graphql";
|
||||||
|
|
||||||
import GeneralConfig from "./GeneralConfig";
|
import ClosedStreamMessageConfig from "./ClosedStreamMessageConfig";
|
||||||
|
import ClosingCommentStreamsConfig from "./ClosingCommentStreamsConfig";
|
||||||
|
import CommentEditingConfig from "./CommentEditingConfig";
|
||||||
|
import CommentLengthConfig from "./CommentLengthConfig";
|
||||||
|
import GuidelinesConfig from "./GuidelinesConfig";
|
||||||
|
import LocaleConfig from "./LocaleConfig";
|
||||||
|
import ReactionConfigContainer from "./ReactionConfigContainer";
|
||||||
|
import SitewideCommentingConfig from "./SitewideCommentingConfig";
|
||||||
|
import StaffConfig from "./StaffConfig";
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
form: FormApi;
|
|
||||||
submitting: boolean;
|
submitting: boolean;
|
||||||
settings: SettingsData;
|
settings: SettingsData;
|
||||||
}
|
}
|
||||||
|
|
||||||
class GeneralConfigContainer extends React.Component<Props> {
|
const GeneralConfigContainer: React.FunctionComponent<Props> = ({
|
||||||
public static routeConfig: RouteProps;
|
settings,
|
||||||
private initialValues = {};
|
submitting,
|
||||||
|
}) => {
|
||||||
constructor(props: Props) {
|
const form = useForm();
|
||||||
super(props);
|
useMemo(() => form.initialize(purgeMetadata(settings)), []);
|
||||||
}
|
return (
|
||||||
|
<HorizontalGutter size="double" data-testid="configure-generalContainer">
|
||||||
public componentDidMount() {
|
<LocaleConfig disabled={submitting} />
|
||||||
this.props.form.initialize(this.initialValues);
|
<SitewideCommentingConfig disabled={submitting} />
|
||||||
}
|
<GuidelinesConfig disabled={submitting} />
|
||||||
|
<CommentLengthConfig disabled={submitting} />
|
||||||
private handleOnInitValues = (values: any) => {
|
<CommentEditingConfig disabled={submitting} />
|
||||||
this.initialValues = pureMerge(this.initialValues, values);
|
<ClosingCommentStreamsConfig disabled={submitting} />
|
||||||
};
|
<ClosedStreamMessageConfig disabled={submitting} />
|
||||||
|
<ReactionConfigContainer disabled={submitting} settings={settings} />
|
||||||
public render() {
|
<StaffConfig disabled={submitting} />
|
||||||
return (
|
</HorizontalGutter>
|
||||||
<GeneralConfig
|
);
|
||||||
disabled={this.props.submitting}
|
};
|
||||||
settings={this.props.settings}
|
|
||||||
onInitValues={this.handleOnInitValues}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const enhanced = withFragmentContainer<Props>({
|
const enhanced = withFragmentContainer<Props>({
|
||||||
settings: graphql`
|
settings: graphql`
|
||||||
fragment GeneralConfigContainer_settings on Settings {
|
fragment GeneralConfigContainer_settings on Settings {
|
||||||
...LocaleConfigContainer_settings
|
...LocaleConfig_formValues @relay(mask: false)
|
||||||
...GuidelinesConfigContainer_settings
|
...GuidelinesConfig_formValues @relay(mask: false)
|
||||||
...CommentLengthConfigContainer_settings
|
...CommentLengthConfig_formValues @relay(mask: false)
|
||||||
...CommentEditingConfigContainer_settings
|
...CommentEditingConfig_formValues @relay(mask: false)
|
||||||
...ClosedStreamMessageConfigContainer_settings
|
...ClosedStreamMessageConfig_formValues @relay(mask: false)
|
||||||
...ClosingCommentStreamsConfigContainer_settings
|
...ClosingCommentStreamsConfig_formValues @relay(mask: false)
|
||||||
...SitewideCommentingConfigContainer_settings
|
...SitewideCommentingConfig_formValues @relay(mask: false)
|
||||||
|
...ReactionConfig_formValues @relay(mask: false)
|
||||||
|
...StaffConfig_formValues @relay(mask: false)
|
||||||
|
|
||||||
...ReactionConfigContainer_settings
|
...ReactionConfigContainer_settings
|
||||||
...StaffConfigContainer_settings
|
|
||||||
}
|
}
|
||||||
`,
|
`,
|
||||||
})(GeneralConfigContainer);
|
})(GeneralConfigContainer);
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
import { FormApi } from "final-form";
|
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import { graphql } from "react-relay";
|
import { graphql } from "react-relay";
|
||||||
|
|
||||||
@@ -12,7 +11,6 @@ import GeneralConfigContainer from "./GeneralConfigContainer";
|
|||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
data: GeneralConfigRouteQueryResponse | null;
|
data: GeneralConfigRouteQueryResponse | null;
|
||||||
form: FormApi;
|
|
||||||
submitting: boolean;
|
submitting: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -28,7 +26,6 @@ class GeneralConfigRoute extends React.Component<Props> {
|
|||||||
return (
|
return (
|
||||||
<GeneralConfigContainer
|
<GeneralConfigContainer
|
||||||
settings={this.props.data.settings}
|
settings={this.props.data.settings}
|
||||||
form={this.props.form}
|
|
||||||
submitting={this.props.submitting}
|
submitting={this.props.submitting}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import { Localized } from "fluent-react/compat";
|
import { Localized } from "fluent-react/compat";
|
||||||
import React, { FunctionComponent, Suspense } from "react";
|
import React, { FunctionComponent, Suspense } from "react";
|
||||||
import { Field } from "react-final-form";
|
import { Field } from "react-final-form";
|
||||||
|
import { graphql } from "react-relay";
|
||||||
|
|
||||||
import { MarkdownEditor } from "coral-framework/components/loadables";
|
import { MarkdownEditor } from "coral-framework/components/loadables";
|
||||||
import { parseEmptyAsNull } from "coral-framework/lib/form";
|
import { parseEmptyAsNull } from "coral-framework/lib/form";
|
||||||
@@ -19,6 +20,16 @@ import Header from "../../Header";
|
|||||||
import OnOffField from "../../OnOffField";
|
import OnOffField from "../../OnOffField";
|
||||||
import ValidationMessage from "../../ValidationMessage";
|
import ValidationMessage from "../../ValidationMessage";
|
||||||
|
|
||||||
|
// eslint-disable-next-line no-unused-expressions
|
||||||
|
graphql`
|
||||||
|
fragment GuidelinesConfig_formValues on Settings {
|
||||||
|
communityGuidelines {
|
||||||
|
enabled
|
||||||
|
content
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
disabled: boolean;
|
disabled: boolean;
|
||||||
}
|
}
|
||||||
@@ -65,8 +76,8 @@ const GuidelinesConfig: FunctionComponent<Props> = ({ disabled }) => (
|
|||||||
<>
|
<>
|
||||||
<Suspense fallback={<Spinner />}>
|
<Suspense fallback={<Spinner />}>
|
||||||
<MarkdownEditor
|
<MarkdownEditor
|
||||||
id="configure-general-guidelines-content"
|
|
||||||
{...input}
|
{...input}
|
||||||
|
id="configure-general-guidelines-content"
|
||||||
/>
|
/>
|
||||||
</Suspense>
|
</Suspense>
|
||||||
<ValidationMessage meta={meta} />
|
<ValidationMessage meta={meta} />
|
||||||
|
|||||||
@@ -1,39 +0,0 @@
|
|||||||
import React from "react";
|
|
||||||
import { graphql } from "react-relay";
|
|
||||||
|
|
||||||
import { withFragmentContainer } from "coral-framework/lib/relay";
|
|
||||||
|
|
||||||
import { GuidelinesConfigContainer_settings as SettingsData } from "coral-admin/__generated__/GuidelinesConfigContainer_settings.graphql";
|
|
||||||
|
|
||||||
import GuidelinesConfig from "./GuidelinesConfig";
|
|
||||||
|
|
||||||
interface Props {
|
|
||||||
settings: SettingsData;
|
|
||||||
onInitValues: (values: SettingsData) => void;
|
|
||||||
disabled: boolean;
|
|
||||||
}
|
|
||||||
|
|
||||||
class GuidelinesConfigContainer extends React.Component<Props> {
|
|
||||||
constructor(props: Props) {
|
|
||||||
super(props);
|
|
||||||
props.onInitValues(props.settings);
|
|
||||||
}
|
|
||||||
|
|
||||||
public render() {
|
|
||||||
const { disabled } = this.props;
|
|
||||||
return <GuidelinesConfig disabled={disabled} />;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const enhanced = withFragmentContainer<Props>({
|
|
||||||
settings: graphql`
|
|
||||||
fragment GuidelinesConfigContainer_settings on Settings {
|
|
||||||
communityGuidelines {
|
|
||||||
enabled
|
|
||||||
content
|
|
||||||
}
|
|
||||||
}
|
|
||||||
`,
|
|
||||||
})(GuidelinesConfigContainer);
|
|
||||||
|
|
||||||
export default enhanced;
|
|
||||||
+11
-18
@@ -1,27 +1,28 @@
|
|||||||
import { Localized } from "fluent-react/compat";
|
import { Localized } from "fluent-react/compat";
|
||||||
import React, { useMemo } from "react";
|
import React from "react";
|
||||||
import { Field } from "react-final-form";
|
import { Field } from "react-final-form";
|
||||||
import { graphql } from "react-relay";
|
import { graphql } from "react-relay";
|
||||||
|
|
||||||
import { withFragmentContainer } from "coral-framework/lib/relay";
|
|
||||||
import { required } from "coral-framework/lib/validation";
|
import { required } from "coral-framework/lib/validation";
|
||||||
import { FormFieldDescription, HorizontalGutter } from "coral-ui/components/v2";
|
import { FormFieldDescription, HorizontalGutter } from "coral-ui/components/v2";
|
||||||
|
|
||||||
import { LocaleConfigContainer_settings } from "coral-admin/__generated__/LocaleConfigContainer_settings.graphql";
|
|
||||||
|
|
||||||
import ConfigBox from "../../ConfigBox";
|
import ConfigBox from "../../ConfigBox";
|
||||||
import LocaleField from "../../Fields/LocaleField";
|
import LocaleField from "../../Fields/LocaleField";
|
||||||
import Header from "../../Header";
|
import Header from "../../Header";
|
||||||
import ValidationMessage from "../../ValidationMessage";
|
import ValidationMessage from "../../ValidationMessage";
|
||||||
|
|
||||||
|
// eslint-disable-next-line no-unused-expressions
|
||||||
|
graphql`
|
||||||
|
fragment LocaleConfig_formValues on Settings {
|
||||||
|
locale
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
settings: LocaleConfigContainer_settings;
|
|
||||||
onInitValues: (values: LocaleConfigContainer_settings) => void;
|
|
||||||
disabled: boolean;
|
disabled: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
const LocaleConfigContainer: React.FunctionComponent<Props> = props => {
|
const LocaleConfig: React.FunctionComponent<Props> = props => {
|
||||||
useMemo(() => props.onInitValues(props.settings), [props.onInitValues]);
|
|
||||||
return (
|
return (
|
||||||
<ConfigBox
|
<ConfigBox
|
||||||
title={
|
title={
|
||||||
@@ -40,9 +41,9 @@ const LocaleConfigContainer: React.FunctionComponent<Props> = props => {
|
|||||||
{({ input, meta }) => (
|
{({ input, meta }) => (
|
||||||
<>
|
<>
|
||||||
<LocaleField
|
<LocaleField
|
||||||
|
{...input}
|
||||||
id={`configure-locale-${input.name}`}
|
id={`configure-locale-${input.name}`}
|
||||||
disabled={props.disabled}
|
disabled={props.disabled}
|
||||||
{...input}
|
|
||||||
/>
|
/>
|
||||||
<ValidationMessage meta={meta} fullWidth />
|
<ValidationMessage meta={meta} fullWidth />
|
||||||
</>
|
</>
|
||||||
@@ -53,12 +54,4 @@ const LocaleConfigContainer: React.FunctionComponent<Props> = props => {
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
const enhanced = withFragmentContainer<Props>({
|
export default LocaleConfig;
|
||||||
settings: graphql`
|
|
||||||
fragment LocaleConfigContainer_settings on Settings {
|
|
||||||
locale
|
|
||||||
}
|
|
||||||
`,
|
|
||||||
})(LocaleConfigContainer);
|
|
||||||
|
|
||||||
export default enhanced;
|
|
||||||
@@ -1,6 +1,7 @@
|
|||||||
import { Localized } from "fluent-react/compat";
|
import { Localized } from "fluent-react/compat";
|
||||||
import React, { FunctionComponent } from "react";
|
import React, { FunctionComponent } from "react";
|
||||||
import { Field } from "react-final-form";
|
import { Field } from "react-final-form";
|
||||||
|
import { graphql } from "react-relay";
|
||||||
|
|
||||||
import { required } from "coral-framework/lib/validation";
|
import { required } from "coral-framework/lib/validation";
|
||||||
import ReactionButton from "coral-stream/tabs/Comments/Comment/ReactionButton/ReactionButton";
|
import ReactionButton from "coral-stream/tabs/Comments/Comment/ReactionButton/ReactionButton";
|
||||||
@@ -15,20 +16,36 @@ import {
|
|||||||
SelectField,
|
SelectField,
|
||||||
} from "coral-ui/components/v2";
|
} from "coral-ui/components/v2";
|
||||||
|
|
||||||
import { ReactionConfigContainer_settings as SettingsData } from "coral-admin/__generated__/ReactionConfigContainer_settings.graphql";
|
|
||||||
|
|
||||||
import ConfigBox from "../../ConfigBox";
|
import ConfigBox from "../../ConfigBox";
|
||||||
import Header from "../../Header";
|
import Header from "../../Header";
|
||||||
import TextFieldWithValidation from "../../TextFieldWithValidation";
|
import TextFieldWithValidation from "../../TextFieldWithValidation";
|
||||||
|
|
||||||
import styles from "./ReactionConfig.css";
|
import styles from "./ReactionConfig.css";
|
||||||
|
|
||||||
|
// eslint-disable-next-line no-unused-expressions
|
||||||
|
graphql`
|
||||||
|
fragment ReactionConfig_formValues on Settings {
|
||||||
|
reaction {
|
||||||
|
label
|
||||||
|
labelActive
|
||||||
|
sortLabel
|
||||||
|
icon
|
||||||
|
iconActive
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
|
icon: string;
|
||||||
|
iconActive: string | null;
|
||||||
disabled: boolean;
|
disabled: boolean;
|
||||||
settings: SettingsData;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const ReactionsConfig: FunctionComponent<Props> = ({ disabled, settings }) => (
|
const ReactionsConfig: FunctionComponent<Props> = ({
|
||||||
|
disabled,
|
||||||
|
icon,
|
||||||
|
iconActive,
|
||||||
|
}) => (
|
||||||
<ConfigBox
|
<ConfigBox
|
||||||
title={
|
title={
|
||||||
<Localized id="configure-general-reactions-title">
|
<Localized id="configure-general-reactions-title">
|
||||||
@@ -54,6 +71,7 @@ const ReactionsConfig: FunctionComponent<Props> = ({ disabled, settings }) => (
|
|||||||
</Localized>
|
</Localized>
|
||||||
<Localized id="configure-general-reactions-input">
|
<Localized id="configure-general-reactions-input">
|
||||||
<TextFieldWithValidation
|
<TextFieldWithValidation
|
||||||
|
{...input}
|
||||||
className={styles.textInput}
|
className={styles.textInput}
|
||||||
id={input.name}
|
id={input.name}
|
||||||
type="text"
|
type="text"
|
||||||
@@ -61,7 +79,6 @@ const ReactionsConfig: FunctionComponent<Props> = ({ disabled, settings }) => (
|
|||||||
placeholder="E.g. Respect"
|
placeholder="E.g. Respect"
|
||||||
disabled={disabled}
|
disabled={disabled}
|
||||||
meta={meta}
|
meta={meta}
|
||||||
{...input}
|
|
||||||
/>
|
/>
|
||||||
</Localized>
|
</Localized>
|
||||||
</FormField>
|
</FormField>
|
||||||
@@ -74,9 +91,9 @@ const ReactionsConfig: FunctionComponent<Props> = ({ disabled, settings }) => (
|
|||||||
className={styles.reactionButton}
|
className={styles.reactionButton}
|
||||||
reacted={false}
|
reacted={false}
|
||||||
label={input.value}
|
label={input.value}
|
||||||
labelActive={settings.reaction.labelActive}
|
labelActive={input.value}
|
||||||
icon={settings.reaction.icon}
|
icon={icon}
|
||||||
iconActive={settings.reaction.iconActive}
|
iconActive={iconActive}
|
||||||
totalReactions={0}
|
totalReactions={0}
|
||||||
onClick={() => null}
|
onClick={() => null}
|
||||||
/>
|
/>
|
||||||
@@ -93,6 +110,7 @@ const ReactionsConfig: FunctionComponent<Props> = ({ disabled, settings }) => (
|
|||||||
</Localized>
|
</Localized>
|
||||||
<Localized id="configure-general-reactions-active-input">
|
<Localized id="configure-general-reactions-active-input">
|
||||||
<TextFieldWithValidation
|
<TextFieldWithValidation
|
||||||
|
{...input}
|
||||||
className={styles.textInput}
|
className={styles.textInput}
|
||||||
id={input.name}
|
id={input.name}
|
||||||
type="text"
|
type="text"
|
||||||
@@ -100,7 +118,6 @@ const ReactionsConfig: FunctionComponent<Props> = ({ disabled, settings }) => (
|
|||||||
fullWidth
|
fullWidth
|
||||||
disabled={disabled}
|
disabled={disabled}
|
||||||
meta={meta}
|
meta={meta}
|
||||||
{...input}
|
|
||||||
/>
|
/>
|
||||||
</Localized>
|
</Localized>
|
||||||
</FormField>
|
</FormField>
|
||||||
@@ -112,10 +129,10 @@ const ReactionsConfig: FunctionComponent<Props> = ({ disabled, settings }) => (
|
|||||||
className={styles.reactionButton}
|
className={styles.reactionButton}
|
||||||
readOnly
|
readOnly
|
||||||
reacted
|
reacted
|
||||||
label={settings.reaction.label}
|
label={input.value}
|
||||||
labelActive={input.value}
|
labelActive={input.value}
|
||||||
icon={settings.reaction.icon}
|
icon={icon}
|
||||||
iconActive={settings.reaction.iconActive}
|
iconActive={iconActive}
|
||||||
totalReactions={0}
|
totalReactions={0}
|
||||||
onClick={() => null}
|
onClick={() => null}
|
||||||
/>
|
/>
|
||||||
@@ -132,6 +149,7 @@ const ReactionsConfig: FunctionComponent<Props> = ({ disabled, settings }) => (
|
|||||||
</Localized>
|
</Localized>
|
||||||
<Localized id="configure-general-reactions-sort-input">
|
<Localized id="configure-general-reactions-sort-input">
|
||||||
<TextFieldWithValidation
|
<TextFieldWithValidation
|
||||||
|
{...input}
|
||||||
id={input.name}
|
id={input.name}
|
||||||
className={styles.textInput}
|
className={styles.textInput}
|
||||||
type="text"
|
type="text"
|
||||||
@@ -139,7 +157,6 @@ const ReactionsConfig: FunctionComponent<Props> = ({ disabled, settings }) => (
|
|||||||
fullWidth
|
fullWidth
|
||||||
disabled={disabled}
|
disabled={disabled}
|
||||||
meta={meta}
|
meta={meta}
|
||||||
{...input}
|
|
||||||
/>
|
/>
|
||||||
</Localized>
|
</Localized>
|
||||||
</FormField>
|
</FormField>
|
||||||
|
|||||||
+12
-15
@@ -9,29 +9,26 @@ import ReactionConfig from "./ReactionConfig";
|
|||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
settings: SettingsData;
|
settings: SettingsData;
|
||||||
onInitValues: (values: SettingsData) => void;
|
|
||||||
disabled: boolean;
|
disabled: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
class ReactionConfigContainer extends React.Component<Props> {
|
const ReactionConfigContainer: React.FunctionComponent<Props> = ({
|
||||||
constructor(props: Props) {
|
disabled,
|
||||||
super(props);
|
settings,
|
||||||
props.onInitValues(props.settings);
|
}) => {
|
||||||
}
|
return (
|
||||||
|
<ReactionConfig
|
||||||
public render() {
|
iconActive={settings.reaction.iconActive}
|
||||||
const { disabled, settings } = this.props;
|
icon={settings.reaction.icon}
|
||||||
return <ReactionConfig settings={settings} disabled={disabled} />;
|
disabled={disabled}
|
||||||
}
|
/>
|
||||||
}
|
);
|
||||||
|
};
|
||||||
|
|
||||||
const enhanced = withFragmentContainer<Props>({
|
const enhanced = withFragmentContainer<Props>({
|
||||||
settings: graphql`
|
settings: graphql`
|
||||||
fragment ReactionConfigContainer_settings on Settings {
|
fragment ReactionConfigContainer_settings on Settings {
|
||||||
reaction {
|
reaction {
|
||||||
label
|
|
||||||
labelActive
|
|
||||||
sortLabel
|
|
||||||
icon
|
icon
|
||||||
iconActive
|
iconActive
|
||||||
}
|
}
|
||||||
|
|||||||
+12
-1
@@ -1,6 +1,7 @@
|
|||||||
import { Localized } from "fluent-react/compat";
|
import { Localized } from "fluent-react/compat";
|
||||||
import React, { FunctionComponent, Suspense } from "react";
|
import React, { FunctionComponent, Suspense } from "react";
|
||||||
import { Field } from "react-final-form";
|
import { Field } from "react-final-form";
|
||||||
|
import { graphql } from "react-relay";
|
||||||
|
|
||||||
import { MarkdownEditor } from "coral-framework/components/loadables";
|
import { MarkdownEditor } from "coral-framework/components/loadables";
|
||||||
import { parseEmptyAsNull } from "coral-framework/lib/form";
|
import { parseEmptyAsNull } from "coral-framework/lib/form";
|
||||||
@@ -19,6 +20,16 @@ import Header from "../../Header";
|
|||||||
import OnOffField from "../../OnOffField";
|
import OnOffField from "../../OnOffField";
|
||||||
import ValidationMessage from "../../ValidationMessage";
|
import ValidationMessage from "../../ValidationMessage";
|
||||||
|
|
||||||
|
// eslint-disable-next-line no-unused-expressions
|
||||||
|
graphql`
|
||||||
|
fragment SitewideCommentingConfig_formValues on Settings {
|
||||||
|
disableCommenting {
|
||||||
|
enabled
|
||||||
|
message
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
disabled: boolean;
|
disabled: boolean;
|
||||||
}
|
}
|
||||||
@@ -82,8 +93,8 @@ const SitewideCommentingConfig: FunctionComponent<Props> = ({ disabled }) => (
|
|||||||
<>
|
<>
|
||||||
<Suspense fallback={<Spinner />}>
|
<Suspense fallback={<Spinner />}>
|
||||||
<MarkdownEditor
|
<MarkdownEditor
|
||||||
id="configure-general-sitewideCommenting-message"
|
|
||||||
{...input}
|
{...input}
|
||||||
|
id="configure-general-sitewideCommenting-message"
|
||||||
/>
|
/>
|
||||||
</Suspense>
|
</Suspense>
|
||||||
<ValidationMessage meta={meta} fullWidth />
|
<ValidationMessage meta={meta} fullWidth />
|
||||||
|
|||||||
-39
@@ -1,39 +0,0 @@
|
|||||||
import React from "react";
|
|
||||||
import { graphql } from "react-relay";
|
|
||||||
|
|
||||||
import { withFragmentContainer } from "coral-framework/lib/relay";
|
|
||||||
|
|
||||||
import { SitewideCommentingConfigContainer_settings as SettingsData } from "coral-admin/__generated__/SitewideCommentingConfigContainer_settings.graphql";
|
|
||||||
|
|
||||||
import SitewideCommentingConfig from "./SitewideCommentingConfig";
|
|
||||||
|
|
||||||
interface Props {
|
|
||||||
settings: SettingsData;
|
|
||||||
onInitValues: (values: SettingsData) => void;
|
|
||||||
disabled: boolean;
|
|
||||||
}
|
|
||||||
|
|
||||||
class SitewideCommentingConfigContainer extends React.Component<Props> {
|
|
||||||
constructor(props: Props) {
|
|
||||||
super(props);
|
|
||||||
props.onInitValues(props.settings);
|
|
||||||
}
|
|
||||||
|
|
||||||
public render() {
|
|
||||||
const { disabled } = this.props;
|
|
||||||
return <SitewideCommentingConfig disabled={disabled} />;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const enhanced = withFragmentContainer<Props>({
|
|
||||||
settings: graphql`
|
|
||||||
fragment SitewideCommentingConfigContainer_settings on Settings {
|
|
||||||
disableCommenting {
|
|
||||||
enabled
|
|
||||||
message
|
|
||||||
}
|
|
||||||
}
|
|
||||||
`,
|
|
||||||
})(SitewideCommentingConfigContainer);
|
|
||||||
|
|
||||||
export default enhanced;
|
|
||||||
@@ -1,6 +1,7 @@
|
|||||||
import { Localized } from "fluent-react/compat";
|
import { Localized } from "fluent-react/compat";
|
||||||
import React, { FunctionComponent } from "react";
|
import React, { FunctionComponent } from "react";
|
||||||
import { Field } from "react-final-form";
|
import { Field } from "react-final-form";
|
||||||
|
import { graphql } from "react-relay";
|
||||||
|
|
||||||
import { required } from "coral-framework/lib/validation";
|
import { required } from "coral-framework/lib/validation";
|
||||||
import {
|
import {
|
||||||
@@ -13,20 +14,26 @@ import {
|
|||||||
Tag,
|
Tag,
|
||||||
} from "coral-ui/components/v2";
|
} from "coral-ui/components/v2";
|
||||||
|
|
||||||
import { StaffConfigContainer_settings as SettingsData } from "coral-admin/__generated__/StaffConfigContainer_settings.graphql";
|
|
||||||
|
|
||||||
import ConfigBox from "../../ConfigBox";
|
import ConfigBox from "../../ConfigBox";
|
||||||
import Header from "../../Header";
|
import Header from "../../Header";
|
||||||
import TextFieldWithValidation from "../../TextFieldWithValidation";
|
import TextFieldWithValidation from "../../TextFieldWithValidation";
|
||||||
|
|
||||||
import styles from "./StaffConfig.css";
|
import styles from "./StaffConfig.css";
|
||||||
|
|
||||||
|
// eslint-disable-next-line no-unused-expressions
|
||||||
|
graphql`
|
||||||
|
fragment StaffConfig_formValues on Settings {
|
||||||
|
staff {
|
||||||
|
label
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
disabled: boolean;
|
disabled: boolean;
|
||||||
settings: SettingsData;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const StaffConfig: FunctionComponent<Props> = ({ disabled, settings }) => (
|
const StaffConfig: FunctionComponent<Props> = ({ disabled }) => (
|
||||||
<ConfigBox
|
<ConfigBox
|
||||||
title={
|
title={
|
||||||
<Localized id="configure-general-staff-title">
|
<Localized id="configure-general-staff-title">
|
||||||
@@ -50,6 +57,7 @@ const StaffConfig: FunctionComponent<Props> = ({ disabled, settings }) => (
|
|||||||
</Localized>
|
</Localized>
|
||||||
<Localized id="configure-general-staff-input">
|
<Localized id="configure-general-staff-input">
|
||||||
<TextFieldWithValidation
|
<TextFieldWithValidation
|
||||||
|
{...input}
|
||||||
className={styles.textInput}
|
className={styles.textInput}
|
||||||
id={input.name}
|
id={input.name}
|
||||||
type="text"
|
type="text"
|
||||||
@@ -57,7 +65,6 @@ const StaffConfig: FunctionComponent<Props> = ({ disabled, settings }) => (
|
|||||||
placeholder="E.g. Staff"
|
placeholder="E.g. Staff"
|
||||||
disabled={disabled}
|
disabled={disabled}
|
||||||
meta={meta}
|
meta={meta}
|
||||||
{...input}
|
|
||||||
/>
|
/>
|
||||||
</Localized>
|
</Localized>
|
||||||
</FormField>
|
</FormField>
|
||||||
|
|||||||
@@ -1,38 +0,0 @@
|
|||||||
import React from "react";
|
|
||||||
import { graphql } from "react-relay";
|
|
||||||
|
|
||||||
import { withFragmentContainer } from "coral-framework/lib/relay";
|
|
||||||
|
|
||||||
import { StaffConfigContainer_settings as SettingsData } from "coral-admin/__generated__/StaffConfigContainer_settings.graphql";
|
|
||||||
|
|
||||||
import StaffConfig from "./StaffConfig";
|
|
||||||
|
|
||||||
interface Props {
|
|
||||||
settings: SettingsData;
|
|
||||||
onInitValues: (values: SettingsData) => void;
|
|
||||||
disabled: boolean;
|
|
||||||
}
|
|
||||||
|
|
||||||
class StaffConfigContainer extends React.Component<Props> {
|
|
||||||
constructor(props: Props) {
|
|
||||||
super(props);
|
|
||||||
props.onInitValues(props.settings);
|
|
||||||
}
|
|
||||||
|
|
||||||
public render() {
|
|
||||||
const { disabled, settings } = this.props;
|
|
||||||
return <StaffConfig settings={settings} disabled={disabled} />;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const enhanced = withFragmentContainer<Props>({
|
|
||||||
settings: graphql`
|
|
||||||
fragment StaffConfigContainer_settings on Settings {
|
|
||||||
staff {
|
|
||||||
label
|
|
||||||
}
|
|
||||||
}
|
|
||||||
`,
|
|
||||||
})(StaffConfigContainer);
|
|
||||||
|
|
||||||
export default enhanced;
|
|
||||||
@@ -29,6 +29,7 @@ const APIKeyField: FunctionComponent<Props> = ({
|
|||||||
</Label>
|
</Label>
|
||||||
</Localized>
|
</Localized>
|
||||||
<PasswordField
|
<PasswordField
|
||||||
|
{...input}
|
||||||
id={`configure-moderation-${input.name}`}
|
id={`configure-moderation-${input.name}`}
|
||||||
disabled={disabled}
|
disabled={disabled}
|
||||||
// TODO: (wyattjoh) figure out how to add translations to these props
|
// TODO: (wyattjoh) figure out how to add translations to these props
|
||||||
@@ -36,7 +37,6 @@ const APIKeyField: FunctionComponent<Props> = ({
|
|||||||
showPasswordTitle="Hide API Key"
|
showPasswordTitle="Hide API Key"
|
||||||
color={colorFromMeta(meta)}
|
color={colorFromMeta(meta)}
|
||||||
fullWidth
|
fullWidth
|
||||||
{...input}
|
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<ValidationMessage meta={meta} />
|
<ValidationMessage meta={meta} />
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import { Localized } from "fluent-react/compat";
|
import { Localized } from "fluent-react/compat";
|
||||||
import React, { FunctionComponent } from "react";
|
import React, { FunctionComponent } from "react";
|
||||||
import { Field } from "react-final-form";
|
import { Field } from "react-final-form";
|
||||||
|
import { graphql } from "react-relay";
|
||||||
|
|
||||||
import { parseEmptyAsNull } from "coral-framework/lib/form";
|
import { parseEmptyAsNull } from "coral-framework/lib/form";
|
||||||
import { ExternalLink } from "coral-framework/lib/i18n/components";
|
import { ExternalLink } from "coral-framework/lib/i18n/components";
|
||||||
@@ -25,6 +26,19 @@ import Subheader from "../../Subheader";
|
|||||||
import TextFieldWithValidation from "../../TextFieldWithValidation";
|
import TextFieldWithValidation from "../../TextFieldWithValidation";
|
||||||
import APIKeyField from "./APIKeyField";
|
import APIKeyField from "./APIKeyField";
|
||||||
|
|
||||||
|
// eslint-disable-next-line no-unused-expressions
|
||||||
|
graphql`
|
||||||
|
fragment AkismetConfig_formValues on Settings {
|
||||||
|
integrations {
|
||||||
|
akismet {
|
||||||
|
enabled
|
||||||
|
key
|
||||||
|
site
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
disabled: boolean;
|
disabled: boolean;
|
||||||
}
|
}
|
||||||
@@ -95,6 +109,7 @@ const AkismetConfig: FunctionComponent<Props> = ({ disabled }) => {
|
|||||||
>
|
>
|
||||||
{({ input, meta }) => (
|
{({ input, meta }) => (
|
||||||
<TextFieldWithValidation
|
<TextFieldWithValidation
|
||||||
|
{...input}
|
||||||
id="configure-moderation-akismet-site"
|
id="configure-moderation-akismet-site"
|
||||||
disabled={disabled}
|
disabled={disabled}
|
||||||
autoComplete="off"
|
autoComplete="off"
|
||||||
@@ -103,7 +118,6 @@ const AkismetConfig: FunctionComponent<Props> = ({ disabled }) => {
|
|||||||
spellCheck={false}
|
spellCheck={false}
|
||||||
fullWidth
|
fullWidth
|
||||||
meta={meta}
|
meta={meta}
|
||||||
{...input}
|
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
</Field>
|
</Field>
|
||||||
|
|||||||
@@ -1,42 +0,0 @@
|
|||||||
import React from "react";
|
|
||||||
import { graphql } from "react-relay";
|
|
||||||
|
|
||||||
import { withFragmentContainer } from "coral-framework/lib/relay";
|
|
||||||
|
|
||||||
import { AkismetConfigContainer_settings as SettingsData } from "coral-admin/__generated__/AkismetConfigContainer_settings.graphql";
|
|
||||||
|
|
||||||
import AkismetConfig from "./AkismetConfig";
|
|
||||||
|
|
||||||
interface Props {
|
|
||||||
settings: SettingsData;
|
|
||||||
onInitValues: (values: SettingsData) => void;
|
|
||||||
disabled: boolean;
|
|
||||||
}
|
|
||||||
|
|
||||||
class AkismetConfigContainer extends React.Component<Props> {
|
|
||||||
constructor(props: Props) {
|
|
||||||
super(props);
|
|
||||||
props.onInitValues(props.settings);
|
|
||||||
}
|
|
||||||
|
|
||||||
public render() {
|
|
||||||
const { disabled } = this.props;
|
|
||||||
return <AkismetConfig disabled={disabled} />;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const enhanced = withFragmentContainer<Props>({
|
|
||||||
settings: graphql`
|
|
||||||
fragment AkismetConfigContainer_settings on Settings {
|
|
||||||
integrations {
|
|
||||||
akismet {
|
|
||||||
enabled
|
|
||||||
key
|
|
||||||
site
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
`,
|
|
||||||
})(AkismetConfigContainer);
|
|
||||||
|
|
||||||
export default enhanced;
|
|
||||||
@@ -1,21 +0,0 @@
|
|||||||
import { noop } from "lodash";
|
|
||||||
import React from "react";
|
|
||||||
import { createRenderer } from "react-test-renderer/shallow";
|
|
||||||
|
|
||||||
import { removeFragmentRefs } from "coral-framework/testHelpers";
|
|
||||||
import { PropTypesOf } from "coral-framework/types";
|
|
||||||
|
|
||||||
import ModerationConfig from "./ModerationConfig";
|
|
||||||
|
|
||||||
const ModerationConfigN = removeFragmentRefs(ModerationConfig);
|
|
||||||
|
|
||||||
it("renders correctly", () => {
|
|
||||||
const props: PropTypesOf<typeof ModerationConfigN> = {
|
|
||||||
disabled: false,
|
|
||||||
settings: {},
|
|
||||||
onInitValues: noop,
|
|
||||||
};
|
|
||||||
const renderer = createRenderer();
|
|
||||||
renderer.render(<ModerationConfigN {...props} />);
|
|
||||||
expect(renderer.getRenderOutput()).toMatchSnapshot();
|
|
||||||
});
|
|
||||||
@@ -1,49 +0,0 @@
|
|||||||
import React, { FunctionComponent } from "react";
|
|
||||||
|
|
||||||
import { PropTypesOf } from "coral-framework/types";
|
|
||||||
import { HorizontalGutter } from "coral-ui/components/v2";
|
|
||||||
|
|
||||||
import AkismetConfigContainer from "./AkismetConfigContainer";
|
|
||||||
import PerspectiveConfigContainer from "./PerspectiveConfigContainer";
|
|
||||||
import PreModerationConfigContainer from "./PreModerationConfigContainer";
|
|
||||||
import RecentCommentHistoryConfigContainer from "./RecentCommentHistoryConfigContainer";
|
|
||||||
|
|
||||||
interface Props {
|
|
||||||
disabled: boolean;
|
|
||||||
settings: PropTypesOf<typeof AkismetConfigContainer>["settings"] &
|
|
||||||
PropTypesOf<typeof PerspectiveConfigContainer>["settings"] &
|
|
||||||
PropTypesOf<typeof PreModerationConfigContainer>["settings"] &
|
|
||||||
PropTypesOf<typeof RecentCommentHistoryConfigContainer>["settings"];
|
|
||||||
onInitValues: (values: any) => void;
|
|
||||||
}
|
|
||||||
|
|
||||||
const ModerationConfig: FunctionComponent<Props> = ({
|
|
||||||
disabled,
|
|
||||||
settings,
|
|
||||||
onInitValues,
|
|
||||||
}) => (
|
|
||||||
<HorizontalGutter size="double" data-testid="configure-moderationContainer">
|
|
||||||
<PreModerationConfigContainer
|
|
||||||
disabled={disabled}
|
|
||||||
settings={settings}
|
|
||||||
onInitValues={onInitValues}
|
|
||||||
/>
|
|
||||||
<RecentCommentHistoryConfigContainer
|
|
||||||
disabled={disabled}
|
|
||||||
settings={settings}
|
|
||||||
onInitValues={onInitValues}
|
|
||||||
/>
|
|
||||||
<PerspectiveConfigContainer
|
|
||||||
disabled={disabled}
|
|
||||||
settings={settings}
|
|
||||||
onInitValues={onInitValues}
|
|
||||||
/>
|
|
||||||
<AkismetConfigContainer
|
|
||||||
disabled={disabled}
|
|
||||||
settings={settings}
|
|
||||||
onInitValues={onInitValues}
|
|
||||||
/>
|
|
||||||
</HorizontalGutter>
|
|
||||||
);
|
|
||||||
|
|
||||||
export default ModerationConfig;
|
|
||||||
+30
-37
@@ -1,55 +1,48 @@
|
|||||||
import { FormApi } from "final-form";
|
import React, { useMemo } from "react";
|
||||||
import { RouteProps } from "found";
|
import { useForm } from "react-final-form";
|
||||||
import React from "react";
|
|
||||||
import { graphql } from "react-relay";
|
import { graphql } from "react-relay";
|
||||||
|
|
||||||
import { pureMerge } from "coral-common/utils";
|
import {
|
||||||
import { withFragmentContainer } from "coral-framework/lib/relay";
|
purgeMetadata,
|
||||||
|
withFragmentContainer,
|
||||||
|
} from "coral-framework/lib/relay";
|
||||||
|
import { HorizontalGutter } from "coral-ui/components";
|
||||||
|
|
||||||
import { ModerationConfigContainer_settings as SettingsData } from "coral-admin/__generated__/ModerationConfigContainer_settings.graphql";
|
import { ModerationConfigContainer_settings as SettingsData } from "coral-admin/__generated__/ModerationConfigContainer_settings.graphql";
|
||||||
|
|
||||||
import ModerationConfig from "./ModerationConfig";
|
import AkismetConfig from "./AkismetConfig";
|
||||||
|
import PerspectiveConfig from "./PerspectiveConfig";
|
||||||
|
import PreModerationConfig from "./PreModerationConfig";
|
||||||
|
import RecentCommentHistoryConfig from "./RecentCommentHistoryConfig";
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
form: FormApi;
|
|
||||||
submitting: boolean;
|
submitting: boolean;
|
||||||
settings: SettingsData;
|
settings: SettingsData;
|
||||||
}
|
}
|
||||||
|
|
||||||
class ModerationConfigContainer extends React.Component<Props> {
|
export const ModerationConfigContainer: React.FunctionComponent<Props> = ({
|
||||||
public static routeConfig: RouteProps;
|
settings,
|
||||||
private initialValues = {};
|
submitting,
|
||||||
|
}) => {
|
||||||
constructor(props: Props) {
|
const form = useForm();
|
||||||
super(props);
|
useMemo(() => form.initialize(purgeMetadata(settings)), []);
|
||||||
}
|
return (
|
||||||
|
<HorizontalGutter size="double" data-testid="configure-moderationContainer">
|
||||||
public componentDidMount() {
|
<PreModerationConfig disabled={submitting} />
|
||||||
this.props.form.initialize(this.initialValues);
|
<RecentCommentHistoryConfig disabled={submitting} />
|
||||||
}
|
<PerspectiveConfig disabled={submitting} />
|
||||||
|
<AkismetConfig disabled={submitting} />
|
||||||
private handleOnInitValues = (values: any) => {
|
</HorizontalGutter>
|
||||||
this.initialValues = pureMerge(this.initialValues, values);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
public render() {
|
|
||||||
return (
|
|
||||||
<ModerationConfig
|
|
||||||
disabled={this.props.submitting}
|
|
||||||
settings={this.props.settings}
|
|
||||||
onInitValues={this.handleOnInitValues}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const enhanced = withFragmentContainer<Props>({
|
const enhanced = withFragmentContainer<Props>({
|
||||||
settings: graphql`
|
settings: graphql`
|
||||||
fragment ModerationConfigContainer_settings on Settings {
|
fragment ModerationConfigContainer_settings on Settings {
|
||||||
...AkismetConfigContainer_settings
|
...AkismetConfig_formValues @relay(mask: false)
|
||||||
...PerspectiveConfigContainer_settings
|
...PerspectiveConfig_formValues @relay(mask: false)
|
||||||
...PreModerationConfigContainer_settings
|
...PreModerationConfig_formValues @relay(mask: false)
|
||||||
...RecentCommentHistoryConfigContainer_settings
|
...RecentCommentHistoryConfig_formValues @relay(mask: false)
|
||||||
}
|
}
|
||||||
`,
|
`,
|
||||||
})(ModerationConfigContainer);
|
})(ModerationConfigContainer);
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
import { FormApi } from "final-form";
|
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import { graphql } from "react-relay";
|
import { graphql } from "react-relay";
|
||||||
|
|
||||||
@@ -11,7 +10,6 @@ import ModerationConfigContainer from "./ModerationConfigContainer";
|
|||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
data: ModerationConfigRouteQueryResponse | null;
|
data: ModerationConfigRouteQueryResponse | null;
|
||||||
form: FormApi;
|
|
||||||
submitting: boolean;
|
submitting: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -27,7 +25,6 @@ class ModerationConfigRoute extends React.Component<Props> {
|
|||||||
return (
|
return (
|
||||||
<ModerationConfigContainer
|
<ModerationConfigContainer
|
||||||
settings={this.props.data.settings}
|
settings={this.props.data.settings}
|
||||||
form={this.props.form}
|
|
||||||
submitting={this.props.submitting}
|
submitting={this.props.submitting}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import { Localized } from "fluent-react/compat";
|
import { Localized } from "fluent-react/compat";
|
||||||
import React, { FunctionComponent } from "react";
|
import React, { FunctionComponent } from "react";
|
||||||
import { Field } from "react-final-form";
|
import { Field } from "react-final-form";
|
||||||
|
import { graphql } from "react-relay";
|
||||||
|
|
||||||
import {
|
import {
|
||||||
TOXICITY_ENDPOINT_DEFAULT,
|
TOXICITY_ENDPOINT_DEFAULT,
|
||||||
@@ -34,13 +35,28 @@ import {
|
|||||||
import ConfigBox from "../../ConfigBox";
|
import ConfigBox from "../../ConfigBox";
|
||||||
import Header from "../../Header";
|
import Header from "../../Header";
|
||||||
import OnOffField from "../../OnOffField";
|
import OnOffField from "../../OnOffField";
|
||||||
import PermissionField from "../../PermissionField";
|
|
||||||
import Subheader from "../../Subheader";
|
import Subheader from "../../Subheader";
|
||||||
import TextFieldWithValidation from "../../TextFieldWithValidation";
|
import TextFieldWithValidation from "../../TextFieldWithValidation";
|
||||||
import APIKeyField from "./APIKeyField";
|
import APIKeyField from "./APIKeyField";
|
||||||
|
|
||||||
import styles from "./PerspectiveConfig.css";
|
import styles from "./PerspectiveConfig.css";
|
||||||
|
|
||||||
|
// eslint-disable-next-line no-unused-expressions
|
||||||
|
graphql`
|
||||||
|
fragment PerspectiveConfig_formValues on Settings {
|
||||||
|
integrations {
|
||||||
|
perspective {
|
||||||
|
enabled
|
||||||
|
endpoint
|
||||||
|
key
|
||||||
|
model
|
||||||
|
threshold
|
||||||
|
doNotStore
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
disabled: boolean;
|
disabled: boolean;
|
||||||
}
|
}
|
||||||
@@ -108,6 +124,7 @@ const PerspectiveConfig: FunctionComponent<Props> = ({ disabled }) => {
|
|||||||
>
|
>
|
||||||
{({ input, meta }) => (
|
{({ input, meta }) => (
|
||||||
<TextFieldWithValidation
|
<TextFieldWithValidation
|
||||||
|
{...input}
|
||||||
id="configure-moderation-perspective-threshold"
|
id="configure-moderation-perspective-threshold"
|
||||||
classes={{
|
classes={{
|
||||||
input: styles.thresholdTextField,
|
input: styles.thresholdTextField,
|
||||||
@@ -121,7 +138,6 @@ const PerspectiveConfig: FunctionComponent<Props> = ({ disabled }) => {
|
|||||||
placeholder={TOXICITY_THRESHOLD_DEFAULT.toString()}
|
placeholder={TOXICITY_THRESHOLD_DEFAULT.toString()}
|
||||||
textAlignCenter
|
textAlignCenter
|
||||||
meta={meta}
|
meta={meta}
|
||||||
{...input}
|
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
</Field>
|
</Field>
|
||||||
@@ -154,6 +170,7 @@ const PerspectiveConfig: FunctionComponent<Props> = ({ disabled }) => {
|
|||||||
<Field name="integrations.perspective.model" parse={parseEmptyAsNull}>
|
<Field name="integrations.perspective.model" parse={parseEmptyAsNull}>
|
||||||
{({ input, meta }) => (
|
{({ input, meta }) => (
|
||||||
<TextFieldWithValidation
|
<TextFieldWithValidation
|
||||||
|
{...input}
|
||||||
id="configure-moderation-perspective-model"
|
id="configure-moderation-perspective-model"
|
||||||
disabled={disabled}
|
disabled={disabled}
|
||||||
autoComplete="off"
|
autoComplete="off"
|
||||||
@@ -163,7 +180,6 @@ const PerspectiveConfig: FunctionComponent<Props> = ({ disabled }) => {
|
|||||||
spellCheck={false}
|
spellCheck={false}
|
||||||
meta={meta}
|
meta={meta}
|
||||||
fullWidth
|
fullWidth
|
||||||
{...input}
|
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
</Field>
|
</Field>
|
||||||
@@ -181,9 +197,19 @@ const PerspectiveConfig: FunctionComponent<Props> = ({ disabled }) => {
|
|||||||
</HelperText>
|
</HelperText>
|
||||||
</Localized>
|
</Localized>
|
||||||
</FormFieldHeader>
|
</FormFieldHeader>
|
||||||
<PermissionField
|
<OnOffField
|
||||||
name="integrations.perspective.doNotStore"
|
name="integrations.perspective.doNotStore"
|
||||||
disabled={disabled}
|
disabled={disabled}
|
||||||
|
onLabel={
|
||||||
|
<Localized id="configure-radioButton-allow">
|
||||||
|
<span>Allow</span>
|
||||||
|
</Localized>
|
||||||
|
}
|
||||||
|
offLabel={
|
||||||
|
<Localized id="configure-radioButton-dontAllow">
|
||||||
|
<span>Don't Allow</span>
|
||||||
|
</Localized>
|
||||||
|
}
|
||||||
invert
|
invert
|
||||||
/>
|
/>
|
||||||
</FormField>
|
</FormField>
|
||||||
@@ -229,6 +255,7 @@ const PerspectiveConfig: FunctionComponent<Props> = ({ disabled }) => {
|
|||||||
>
|
>
|
||||||
{({ input, meta }) => (
|
{({ input, meta }) => (
|
||||||
<TextFieldWithValidation
|
<TextFieldWithValidation
|
||||||
|
{...input}
|
||||||
id="configure-moderation-perspective-customEndpoint"
|
id="configure-moderation-perspective-customEndpoint"
|
||||||
disabled={disabled}
|
disabled={disabled}
|
||||||
autoComplete="off"
|
autoComplete="off"
|
||||||
@@ -238,7 +265,6 @@ const PerspectiveConfig: FunctionComponent<Props> = ({ disabled }) => {
|
|||||||
spellCheck={false}
|
spellCheck={false}
|
||||||
fullWidth
|
fullWidth
|
||||||
meta={meta}
|
meta={meta}
|
||||||
{...input}
|
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
</Field>
|
</Field>
|
||||||
|
|||||||
-45
@@ -1,45 +0,0 @@
|
|||||||
import React from "react";
|
|
||||||
import { graphql } from "react-relay";
|
|
||||||
|
|
||||||
import { withFragmentContainer } from "coral-framework/lib/relay";
|
|
||||||
|
|
||||||
import { PerspectiveConfigContainer_settings as SettingsData } from "coral-admin/__generated__/PerspectiveConfigContainer_settings.graphql";
|
|
||||||
|
|
||||||
import PerspectiveConfig from "./PerspectiveConfig";
|
|
||||||
|
|
||||||
interface Props {
|
|
||||||
settings: SettingsData;
|
|
||||||
onInitValues: (values: SettingsData) => void;
|
|
||||||
disabled: boolean;
|
|
||||||
}
|
|
||||||
|
|
||||||
class PerspectiveConfigContainer extends React.Component<Props> {
|
|
||||||
constructor(props: Props) {
|
|
||||||
super(props);
|
|
||||||
props.onInitValues(props.settings);
|
|
||||||
}
|
|
||||||
|
|
||||||
public render() {
|
|
||||||
const { disabled } = this.props;
|
|
||||||
return <PerspectiveConfig disabled={disabled} />;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const enhanced = withFragmentContainer<Props>({
|
|
||||||
settings: graphql`
|
|
||||||
fragment PerspectiveConfigContainer_settings on Settings {
|
|
||||||
integrations {
|
|
||||||
perspective {
|
|
||||||
enabled
|
|
||||||
endpoint
|
|
||||||
key
|
|
||||||
model
|
|
||||||
threshold
|
|
||||||
doNotStore
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
`,
|
|
||||||
})(PerspectiveConfigContainer);
|
|
||||||
|
|
||||||
export default enhanced;
|
|
||||||
@@ -1,7 +1,8 @@
|
|||||||
import { Localized } from "fluent-react/compat";
|
import { Localized } from "fluent-react/compat";
|
||||||
import React, { FunctionComponent } from "react";
|
import React, { FunctionComponent } from "react";
|
||||||
|
import { graphql } from "react-relay";
|
||||||
|
|
||||||
import { parseStringBool } from "coral-framework/lib/form";
|
import { formatBool, parseStringBool } from "coral-framework/lib/form";
|
||||||
import {
|
import {
|
||||||
FieldSet,
|
FieldSet,
|
||||||
FormField,
|
FormField,
|
||||||
@@ -13,6 +14,14 @@ import ConfigBox from "../../ConfigBox";
|
|||||||
import Header from "../../Header";
|
import Header from "../../Header";
|
||||||
import OnOffField from "../../OnOffField";
|
import OnOffField from "../../OnOffField";
|
||||||
|
|
||||||
|
// eslint-disable-next-line no-unused-expressions
|
||||||
|
graphql`
|
||||||
|
fragment PreModerationConfig_formValues on Settings {
|
||||||
|
moderation
|
||||||
|
premodLinksEnable
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
disabled: boolean;
|
disabled: boolean;
|
||||||
}
|
}
|
||||||
@@ -22,7 +31,7 @@ const parse = (v: string) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const format = (v: "PRE" | "POST") => {
|
const format = (v: "PRE" | "POST") => {
|
||||||
return v === "PRE";
|
return formatBool(v === "PRE");
|
||||||
};
|
};
|
||||||
|
|
||||||
const PreModerationConfig: FunctionComponent<Props> = ({ disabled }) => {
|
const PreModerationConfig: FunctionComponent<Props> = ({ disabled }) => {
|
||||||
|
|||||||
-37
@@ -1,37 +0,0 @@
|
|||||||
import React from "react";
|
|
||||||
import { graphql } from "react-relay";
|
|
||||||
|
|
||||||
import { withFragmentContainer } from "coral-framework/lib/relay";
|
|
||||||
|
|
||||||
import { PreModerationConfigContainer_settings as SettingsData } from "coral-admin/__generated__/PreModerationConfigContainer_settings.graphql";
|
|
||||||
|
|
||||||
import PreModerationConfig from "./PreModerationConfig";
|
|
||||||
|
|
||||||
interface Props {
|
|
||||||
settings: SettingsData;
|
|
||||||
onInitValues: (values: SettingsData) => void;
|
|
||||||
disabled: boolean;
|
|
||||||
}
|
|
||||||
|
|
||||||
class PreModerationConfigContainer extends React.Component<Props> {
|
|
||||||
constructor(props: Props) {
|
|
||||||
super(props);
|
|
||||||
props.onInitValues(props.settings);
|
|
||||||
}
|
|
||||||
|
|
||||||
public render() {
|
|
||||||
const { disabled } = this.props;
|
|
||||||
return <PreModerationConfig disabled={disabled} />;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const enhanced = withFragmentContainer<Props>({
|
|
||||||
settings: graphql`
|
|
||||||
fragment PreModerationConfigContainer_settings on Settings {
|
|
||||||
moderation
|
|
||||||
premodLinksEnable
|
|
||||||
}
|
|
||||||
`,
|
|
||||||
})(PreModerationConfigContainer);
|
|
||||||
|
|
||||||
export default enhanced;
|
|
||||||
+13
-1
@@ -1,6 +1,7 @@
|
|||||||
import { Localized } from "fluent-react/compat";
|
import { Localized } from "fluent-react/compat";
|
||||||
import React, { FunctionComponent } from "react";
|
import React, { FunctionComponent } from "react";
|
||||||
import { Field } from "react-final-form";
|
import { Field } from "react-final-form";
|
||||||
|
import { graphql } from "react-relay";
|
||||||
|
|
||||||
import { formatPercentage, parsePercentage } from "coral-framework/lib/form";
|
import { formatPercentage, parsePercentage } from "coral-framework/lib/form";
|
||||||
import { hasError } from "coral-framework/lib/form/helpers";
|
import { hasError } from "coral-framework/lib/form/helpers";
|
||||||
@@ -29,6 +30,17 @@ import ValidationMessage from "../../ValidationMessage";
|
|||||||
|
|
||||||
import styles from "./RecentCommentHistoryConfig.css";
|
import styles from "./RecentCommentHistoryConfig.css";
|
||||||
|
|
||||||
|
// eslint-disable-next-line no-unused-expressions
|
||||||
|
graphql`
|
||||||
|
fragment RecentCommentHistoryConfig_formValues on Settings {
|
||||||
|
recentCommentHistory {
|
||||||
|
enabled
|
||||||
|
timeFrame
|
||||||
|
triggerRejectionRate
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
disabled: boolean;
|
disabled: boolean;
|
||||||
}
|
}
|
||||||
@@ -117,6 +129,7 @@ const RecentCommentHistoryConfig: FunctionComponent<Props> = ({ disabled }) => {
|
|||||||
>
|
>
|
||||||
{({ input, meta }) => (
|
{({ input, meta }) => (
|
||||||
<TextFieldWithValidation
|
<TextFieldWithValidation
|
||||||
|
{...input}
|
||||||
classes={{
|
classes={{
|
||||||
input: styles.thresholdTextField,
|
input: styles.thresholdTextField,
|
||||||
}}
|
}}
|
||||||
@@ -128,7 +141,6 @@ const RecentCommentHistoryConfig: FunctionComponent<Props> = ({ disabled }) => {
|
|||||||
adornment={<TextFieldAdornment>%</TextFieldAdornment>}
|
adornment={<TextFieldAdornment>%</TextFieldAdornment>}
|
||||||
meta={meta}
|
meta={meta}
|
||||||
textAlignCenter
|
textAlignCenter
|
||||||
{...input}
|
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
</Field>
|
</Field>
|
||||||
|
|||||||
-40
@@ -1,40 +0,0 @@
|
|||||||
import React from "react";
|
|
||||||
import { graphql } from "react-relay";
|
|
||||||
|
|
||||||
import { withFragmentContainer } from "coral-framework/lib/relay";
|
|
||||||
|
|
||||||
import { RecentCommentHistoryConfigContainer_settings as SettingsData } from "coral-admin/__generated__/RecentCommentHistoryConfigContainer_settings.graphql";
|
|
||||||
|
|
||||||
import RecentCommentHistoryConfig from "./RecentCommentHistoryConfig";
|
|
||||||
|
|
||||||
interface Props {
|
|
||||||
settings: SettingsData;
|
|
||||||
onInitValues: (values: SettingsData) => void;
|
|
||||||
disabled: boolean;
|
|
||||||
}
|
|
||||||
|
|
||||||
class RecentCommentHistoryConfigContainer extends React.Component<Props> {
|
|
||||||
constructor(props: Props) {
|
|
||||||
super(props);
|
|
||||||
props.onInitValues(props.settings);
|
|
||||||
}
|
|
||||||
|
|
||||||
public render() {
|
|
||||||
const { disabled } = this.props;
|
|
||||||
return <RecentCommentHistoryConfig disabled={disabled} />;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const enhanced = withFragmentContainer<Props>({
|
|
||||||
settings: graphql`
|
|
||||||
fragment RecentCommentHistoryConfigContainer_settings on Settings {
|
|
||||||
recentCommentHistory {
|
|
||||||
enabled
|
|
||||||
timeFrame
|
|
||||||
triggerRejectionRate
|
|
||||||
}
|
|
||||||
}
|
|
||||||
`,
|
|
||||||
})(RecentCommentHistoryConfigContainer);
|
|
||||||
|
|
||||||
export default enhanced;
|
|
||||||
-29
@@ -1,29 +0,0 @@
|
|||||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
|
||||||
|
|
||||||
exports[`renders correctly 1`] = `
|
|
||||||
<ForwardRef(forwardRef)
|
|
||||||
data-testid="configure-moderationContainer"
|
|
||||||
size="double"
|
|
||||||
>
|
|
||||||
<Relay(PreModerationConfigContainer)
|
|
||||||
disabled={false}
|
|
||||||
onInitValues={[Function]}
|
|
||||||
settings={Object {}}
|
|
||||||
/>
|
|
||||||
<Relay(RecentCommentHistoryConfigContainer)
|
|
||||||
disabled={false}
|
|
||||||
onInitValues={[Function]}
|
|
||||||
settings={Object {}}
|
|
||||||
/>
|
|
||||||
<Relay(PerspectiveConfigContainer)
|
|
||||||
disabled={false}
|
|
||||||
onInitValues={[Function]}
|
|
||||||
settings={Object {}}
|
|
||||||
/>
|
|
||||||
<Relay(AkismetConfigContainer)
|
|
||||||
disabled={false}
|
|
||||||
onInitValues={[Function]}
|
|
||||||
settings={Object {}}
|
|
||||||
/>
|
|
||||||
</ForwardRef(forwardRef)>
|
|
||||||
`;
|
|
||||||
@@ -1,42 +0,0 @@
|
|||||||
import React, { FunctionComponent } from "react";
|
|
||||||
|
|
||||||
import { PropTypesOf } from "coral-framework/types";
|
|
||||||
import { HorizontalGutter } from "coral-ui/components/v2";
|
|
||||||
|
|
||||||
import OrganizationContactEmailConfigContainer from "./OrganizationContactEmailConfigContainer";
|
|
||||||
import OrganizationNameConfigContainer from "./OrganizationNameConfigContainer";
|
|
||||||
import OrganizationURLConfigContainer from "./OrganizationURLConfigContainer";
|
|
||||||
|
|
||||||
interface Props {
|
|
||||||
disabled: boolean;
|
|
||||||
settings: PropTypesOf<typeof OrganizationNameConfigContainer>["settings"] &
|
|
||||||
PropTypesOf<typeof OrganizationContactEmailConfigContainer>["settings"] &
|
|
||||||
PropTypesOf<typeof OrganizationURLConfigContainer>["settings"];
|
|
||||||
onInitValues: (values: any) => void;
|
|
||||||
}
|
|
||||||
|
|
||||||
const OrganizationConfig: FunctionComponent<Props> = ({
|
|
||||||
disabled,
|
|
||||||
settings,
|
|
||||||
onInitValues,
|
|
||||||
}) => (
|
|
||||||
<HorizontalGutter size="double" data-testid="configure-organizationContainer">
|
|
||||||
<OrganizationNameConfigContainer
|
|
||||||
disabled={disabled}
|
|
||||||
settings={settings}
|
|
||||||
onInitValues={onInitValues}
|
|
||||||
/>
|
|
||||||
<OrganizationContactEmailConfigContainer
|
|
||||||
disabled={disabled}
|
|
||||||
settings={settings}
|
|
||||||
onInitValues={onInitValues}
|
|
||||||
/>
|
|
||||||
<OrganizationURLConfigContainer
|
|
||||||
disabled={disabled}
|
|
||||||
settings={settings}
|
|
||||||
onInitValues={onInitValues}
|
|
||||||
/>
|
|
||||||
</HorizontalGutter>
|
|
||||||
);
|
|
||||||
|
|
||||||
export default OrganizationConfig;
|
|
||||||
+30
-39
@@ -1,56 +1,47 @@
|
|||||||
import { FormApi } from "final-form";
|
import React, { useMemo } from "react";
|
||||||
import { RouteProps } from "found";
|
import { useForm } from "react-final-form";
|
||||||
import React from "react";
|
|
||||||
import { graphql } from "react-relay";
|
import { graphql } from "react-relay";
|
||||||
|
|
||||||
import { pureMerge } from "coral-common/utils";
|
import {
|
||||||
import { withFragmentContainer } from "coral-framework/lib/relay";
|
purgeMetadata,
|
||||||
|
withFragmentContainer,
|
||||||
|
} from "coral-framework/lib/relay";
|
||||||
|
import { HorizontalGutter } from "coral-ui/components";
|
||||||
|
|
||||||
import { OrganizationConfigContainer_settings as SettingsData } from "coral-admin/__generated__/OrganizationConfigContainer_settings.graphql";
|
import { OrganizationConfigContainer_settings as SettingsData } from "coral-admin/__generated__/OrganizationConfigContainer_settings.graphql";
|
||||||
|
|
||||||
import OrganizationConfig from "./OrganizationConfig";
|
import OrganizationContactEmailConfig from "./OrganizationContactEmailConfig";
|
||||||
|
import OrganizationNameConfig from "./OrganizationNameConfig";
|
||||||
|
import OrganizationURLConfig from "./OrganizationURLConfig";
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
form: FormApi;
|
|
||||||
submitting: boolean;
|
submitting: boolean;
|
||||||
settings: SettingsData;
|
settings: SettingsData;
|
||||||
}
|
}
|
||||||
|
const OrganizationConfigContainer: React.FunctionComponent<Props> = ({
|
||||||
class OrganizationConfigContainer extends React.Component<Props> {
|
settings,
|
||||||
public static routeConfig: RouteProps;
|
submitting,
|
||||||
private initialValues = {};
|
}) => {
|
||||||
|
const form = useForm();
|
||||||
constructor(props: Props) {
|
useMemo(() => form.initialize(purgeMetadata(settings)), []);
|
||||||
super(props);
|
return (
|
||||||
}
|
<HorizontalGutter
|
||||||
|
size="double"
|
||||||
public componentDidMount() {
|
data-testid="configure-organizationContainer"
|
||||||
this.props.form.initialize(this.initialValues);
|
>
|
||||||
}
|
<OrganizationNameConfig disabled={submitting} />
|
||||||
|
<OrganizationContactEmailConfig disabled={submitting} />
|
||||||
private handleOnInitValues = (values: any) => {
|
<OrganizationURLConfig disabled={submitting} />
|
||||||
this.initialValues = pureMerge(this.initialValues, values);
|
</HorizontalGutter>
|
||||||
};
|
);
|
||||||
|
};
|
||||||
public render() {
|
|
||||||
return (
|
|
||||||
<OrganizationConfig
|
|
||||||
disabled={this.props.submitting}
|
|
||||||
settings={this.props.settings}
|
|
||||||
onInitValues={this.handleOnInitValues}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const enhanced = withFragmentContainer<Props>({
|
const enhanced = withFragmentContainer<Props>({
|
||||||
settings: graphql`
|
settings: graphql`
|
||||||
fragment OrganizationConfigContainer_settings on Settings {
|
fragment OrganizationConfigContainer_settings on Settings {
|
||||||
...OrganizationNameConfigContainer_settings
|
...OrganizationNameConfig_formValues @relay(mask: false)
|
||||||
...OrganizationContactEmailConfigContainer_settings
|
...OrganizationContactEmailConfig_formValues @relay(mask: false)
|
||||||
...OrganizationURLConfigContainer_settings
|
...OrganizationURLConfig_formValues @relay(mask: false)
|
||||||
}
|
}
|
||||||
`,
|
`,
|
||||||
})(OrganizationConfigContainer);
|
})(OrganizationConfigContainer);
|
||||||
|
|
||||||
export default enhanced;
|
export default enhanced;
|
||||||
|
|||||||
-3
@@ -1,4 +1,3 @@
|
|||||||
import { FormApi } from "final-form";
|
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import { graphql } from "react-relay";
|
import { graphql } from "react-relay";
|
||||||
|
|
||||||
@@ -11,7 +10,6 @@ import OrganizationConfigContainer from "./OrganizationConfigContainer";
|
|||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
data: OrganizationConfigRouteQueryResponse | null;
|
data: OrganizationConfigRouteQueryResponse | null;
|
||||||
form: FormApi;
|
|
||||||
submitting: boolean;
|
submitting: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -27,7 +25,6 @@ class OrganizationConfigRoute extends React.Component<Props> {
|
|||||||
return (
|
return (
|
||||||
<OrganizationConfigContainer
|
<OrganizationConfigContainer
|
||||||
settings={this.props.data.settings}
|
settings={this.props.data.settings}
|
||||||
form={this.props.form}
|
|
||||||
submitting={this.props.submitting}
|
submitting={this.props.submitting}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
|
|||||||
+15
-3
@@ -1,6 +1,7 @@
|
|||||||
import { Localized } from "fluent-react/compat";
|
import { Localized } from "fluent-react/compat";
|
||||||
import React, { FunctionComponent } from "react";
|
import React, { FunctionComponent } from "react";
|
||||||
import { Field } from "react-final-form";
|
import { Field } from "react-final-form";
|
||||||
|
import { graphql } from "react-relay";
|
||||||
|
|
||||||
import {
|
import {
|
||||||
composeValidators,
|
composeValidators,
|
||||||
@@ -13,11 +14,22 @@ import ConfigBox from "../../ConfigBox";
|
|||||||
import Header from "../../Header";
|
import Header from "../../Header";
|
||||||
import TextFieldWithValidation from "../../TextFieldWithValidation";
|
import TextFieldWithValidation from "../../TextFieldWithValidation";
|
||||||
|
|
||||||
|
// eslint-disable-next-line no-unused-expressions
|
||||||
|
graphql`
|
||||||
|
fragment OrganizationContactEmailConfig_formValues on Settings {
|
||||||
|
organization {
|
||||||
|
contactEmail
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
disabled: boolean;
|
disabled: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
const OrganizationNameConfig: FunctionComponent<Props> = ({ disabled }) => (
|
const OrganizationContactEmailConfig: FunctionComponent<Props> = ({
|
||||||
|
disabled,
|
||||||
|
}) => (
|
||||||
<ConfigBox
|
<ConfigBox
|
||||||
title={
|
title={
|
||||||
<Localized id="configure-organization-email">
|
<Localized id="configure-organization-email">
|
||||||
@@ -41,6 +53,7 @@ const OrganizationNameConfig: FunctionComponent<Props> = ({ disabled }) => (
|
|||||||
>
|
>
|
||||||
{({ input, meta }) => (
|
{({ input, meta }) => (
|
||||||
<TextFieldWithValidation
|
<TextFieldWithValidation
|
||||||
|
{...input}
|
||||||
id={`configure-organization-${input.name}`}
|
id={`configure-organization-${input.name}`}
|
||||||
disabled={disabled}
|
disabled={disabled}
|
||||||
autoComplete="off"
|
autoComplete="off"
|
||||||
@@ -49,11 +62,10 @@ const OrganizationNameConfig: FunctionComponent<Props> = ({ disabled }) => (
|
|||||||
spellCheck={false}
|
spellCheck={false}
|
||||||
fullWidth
|
fullWidth
|
||||||
meta={meta}
|
meta={meta}
|
||||||
{...input}
|
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
</Field>
|
</Field>
|
||||||
</ConfigBox>
|
</ConfigBox>
|
||||||
);
|
);
|
||||||
|
|
||||||
export default OrganizationNameConfig;
|
export default OrganizationContactEmailConfig;
|
||||||
|
|||||||
-38
@@ -1,38 +0,0 @@
|
|||||||
import React from "react";
|
|
||||||
import { graphql } from "react-relay";
|
|
||||||
|
|
||||||
import { withFragmentContainer } from "coral-framework/lib/relay";
|
|
||||||
|
|
||||||
import { OrganizationContactEmailConfigContainer_settings as SettingsData } from "coral-admin/__generated__/OrganizationContactEmailConfigContainer_settings.graphql";
|
|
||||||
|
|
||||||
import OrganizationContactEmailConfig from "./OrganizationContactEmailConfig";
|
|
||||||
|
|
||||||
interface Props {
|
|
||||||
settings: SettingsData;
|
|
||||||
onInitValues: (values: SettingsData) => void;
|
|
||||||
disabled: boolean;
|
|
||||||
}
|
|
||||||
|
|
||||||
class OrganizationContactEmailConfigContainer extends React.Component<Props> {
|
|
||||||
constructor(props: Props) {
|
|
||||||
super(props);
|
|
||||||
props.onInitValues(props.settings);
|
|
||||||
}
|
|
||||||
|
|
||||||
public render() {
|
|
||||||
const { disabled } = this.props;
|
|
||||||
return <OrganizationContactEmailConfig disabled={disabled} />;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const enhanced = withFragmentContainer<Props>({
|
|
||||||
settings: graphql`
|
|
||||||
fragment OrganizationContactEmailConfigContainer_settings on Settings {
|
|
||||||
organization {
|
|
||||||
contactEmail
|
|
||||||
}
|
|
||||||
}
|
|
||||||
`,
|
|
||||||
})(OrganizationContactEmailConfigContainer);
|
|
||||||
|
|
||||||
export default enhanced;
|
|
||||||
+11
-1
@@ -1,6 +1,7 @@
|
|||||||
import { Localized } from "fluent-react/compat";
|
import { Localized } from "fluent-react/compat";
|
||||||
import React, { FunctionComponent } from "react";
|
import React, { FunctionComponent } from "react";
|
||||||
import { Field } from "react-final-form";
|
import { Field } from "react-final-form";
|
||||||
|
import { graphql } from "react-relay";
|
||||||
|
|
||||||
import { required } from "coral-framework/lib/validation";
|
import { required } from "coral-framework/lib/validation";
|
||||||
import { FormFieldDescription } from "coral-ui/components/v2";
|
import { FormFieldDescription } from "coral-ui/components/v2";
|
||||||
@@ -9,6 +10,15 @@ import ConfigBox from "../../ConfigBox";
|
|||||||
import Header from "../../Header";
|
import Header from "../../Header";
|
||||||
import TextFieldWithValidation from "../../TextFieldWithValidation";
|
import TextFieldWithValidation from "../../TextFieldWithValidation";
|
||||||
|
|
||||||
|
// eslint-disable-next-line no-unused-expressions
|
||||||
|
graphql`
|
||||||
|
fragment OrganizationNameConfig_formValues on Settings {
|
||||||
|
organization {
|
||||||
|
name
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
disabled: boolean;
|
disabled: boolean;
|
||||||
}
|
}
|
||||||
@@ -32,6 +42,7 @@ const OrganizationNameConfig: FunctionComponent<Props> = ({ disabled }) => (
|
|||||||
<Field name="organization.name" validate={required}>
|
<Field name="organization.name" validate={required}>
|
||||||
{({ input, meta }) => (
|
{({ input, meta }) => (
|
||||||
<TextFieldWithValidation
|
<TextFieldWithValidation
|
||||||
|
{...input}
|
||||||
id={`configure-organization-${input.name}`}
|
id={`configure-organization-${input.name}`}
|
||||||
disabled={disabled}
|
disabled={disabled}
|
||||||
autoComplete="off"
|
autoComplete="off"
|
||||||
@@ -40,7 +51,6 @@ const OrganizationNameConfig: FunctionComponent<Props> = ({ disabled }) => (
|
|||||||
spellCheck={false}
|
spellCheck={false}
|
||||||
meta={meta}
|
meta={meta}
|
||||||
fullWidth
|
fullWidth
|
||||||
{...input}
|
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
</Field>
|
</Field>
|
||||||
|
|||||||
-38
@@ -1,38 +0,0 @@
|
|||||||
import React from "react";
|
|
||||||
import { graphql } from "react-relay";
|
|
||||||
|
|
||||||
import { withFragmentContainer } from "coral-framework/lib/relay";
|
|
||||||
|
|
||||||
import { OrganizationNameConfigContainer_settings as SettingsData } from "coral-admin/__generated__/OrganizationNameConfigContainer_settings.graphql";
|
|
||||||
|
|
||||||
import OrganizationNameConfig from "./OrganizationNameConfig";
|
|
||||||
|
|
||||||
interface Props {
|
|
||||||
settings: SettingsData;
|
|
||||||
onInitValues: (values: SettingsData) => void;
|
|
||||||
disabled: boolean;
|
|
||||||
}
|
|
||||||
|
|
||||||
class OrganizationNameConfigContainer extends React.Component<Props> {
|
|
||||||
constructor(props: Props) {
|
|
||||||
super(props);
|
|
||||||
props.onInitValues(props.settings);
|
|
||||||
}
|
|
||||||
|
|
||||||
public render() {
|
|
||||||
const { disabled } = this.props;
|
|
||||||
return <OrganizationNameConfig disabled={disabled} />;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const enhanced = withFragmentContainer<Props>({
|
|
||||||
settings: graphql`
|
|
||||||
fragment OrganizationNameConfigContainer_settings on Settings {
|
|
||||||
organization {
|
|
||||||
name
|
|
||||||
}
|
|
||||||
}
|
|
||||||
`,
|
|
||||||
})(OrganizationNameConfigContainer);
|
|
||||||
|
|
||||||
export default enhanced;
|
|
||||||
+11
-1
@@ -1,6 +1,7 @@
|
|||||||
import { Localized } from "fluent-react/compat";
|
import { Localized } from "fluent-react/compat";
|
||||||
import React, { FunctionComponent } from "react";
|
import React, { FunctionComponent } from "react";
|
||||||
import { Field } from "react-final-form";
|
import { Field } from "react-final-form";
|
||||||
|
import { graphql } from "react-relay";
|
||||||
|
|
||||||
import {
|
import {
|
||||||
composeValidators,
|
composeValidators,
|
||||||
@@ -13,6 +14,15 @@ import ConfigBox from "../../ConfigBox";
|
|||||||
import Header from "../../Header";
|
import Header from "../../Header";
|
||||||
import TextFieldWithValidation from "../../TextFieldWithValidation";
|
import TextFieldWithValidation from "../../TextFieldWithValidation";
|
||||||
|
|
||||||
|
// eslint-disable-next-line no-unused-expressions
|
||||||
|
graphql`
|
||||||
|
fragment OrganizationURLConfig_formValues on Settings {
|
||||||
|
organization {
|
||||||
|
url
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
disabled: boolean;
|
disabled: boolean;
|
||||||
}
|
}
|
||||||
@@ -36,6 +46,7 @@ const OrganizationURLConfig: FunctionComponent<Props> = ({ disabled }) => (
|
|||||||
>
|
>
|
||||||
{({ input, meta }) => (
|
{({ input, meta }) => (
|
||||||
<TextFieldWithValidation
|
<TextFieldWithValidation
|
||||||
|
{...input}
|
||||||
id={`configure-organization-${input.name}`}
|
id={`configure-organization-${input.name}`}
|
||||||
disabled={disabled}
|
disabled={disabled}
|
||||||
autoComplete="off"
|
autoComplete="off"
|
||||||
@@ -44,7 +55,6 @@ const OrganizationURLConfig: FunctionComponent<Props> = ({ disabled }) => (
|
|||||||
spellCheck={false}
|
spellCheck={false}
|
||||||
fullWidth
|
fullWidth
|
||||||
meta={meta}
|
meta={meta}
|
||||||
{...input}
|
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
</Field>
|
</Field>
|
||||||
|
|||||||
-38
@@ -1,38 +0,0 @@
|
|||||||
import React from "react";
|
|
||||||
import { graphql } from "react-relay";
|
|
||||||
|
|
||||||
import { withFragmentContainer } from "coral-framework/lib/relay";
|
|
||||||
|
|
||||||
import { OrganizationURLConfigContainer_settings as SettingsData } from "coral-admin/__generated__/OrganizationURLConfigContainer_settings.graphql";
|
|
||||||
|
|
||||||
import OrganizationURLConfig from "./OrganizationURLConfig";
|
|
||||||
|
|
||||||
interface Props {
|
|
||||||
settings: SettingsData;
|
|
||||||
onInitValues: (values: SettingsData) => void;
|
|
||||||
disabled: boolean;
|
|
||||||
}
|
|
||||||
|
|
||||||
class OrganizationURLConfigContainer extends React.Component<Props> {
|
|
||||||
constructor(props: Props) {
|
|
||||||
super(props);
|
|
||||||
props.onInitValues(props.settings);
|
|
||||||
}
|
|
||||||
|
|
||||||
public render() {
|
|
||||||
const { disabled } = this.props;
|
|
||||||
return <OrganizationURLConfig disabled={disabled} />;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const enhanced = withFragmentContainer<Props>({
|
|
||||||
settings: graphql`
|
|
||||||
fragment OrganizationURLConfigContainer_settings on Settings {
|
|
||||||
organization {
|
|
||||||
url
|
|
||||||
}
|
|
||||||
}
|
|
||||||
`,
|
|
||||||
})(OrganizationURLConfigContainer);
|
|
||||||
|
|
||||||
export default enhanced;
|
|
||||||
@@ -1,5 +1,6 @@
|
|||||||
import { Localized } from "fluent-react/compat";
|
import { Localized } from "fluent-react/compat";
|
||||||
import React, { FunctionComponent } from "react";
|
import React, { FunctionComponent } from "react";
|
||||||
|
import { graphql } from "react-relay";
|
||||||
|
|
||||||
import {
|
import {
|
||||||
FormField,
|
FormField,
|
||||||
@@ -15,6 +16,15 @@ import WordListTextArea from "./WordListTextArea";
|
|||||||
|
|
||||||
import styles from "./BannedWordListConfig.css";
|
import styles from "./BannedWordListConfig.css";
|
||||||
|
|
||||||
|
// eslint-disable-next-line no-unused-expressions
|
||||||
|
graphql`
|
||||||
|
fragment BannedWordListConfig_formValues on Settings {
|
||||||
|
wordList {
|
||||||
|
banned
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
disabled: boolean;
|
disabled: boolean;
|
||||||
}
|
}
|
||||||
|
|||||||
-38
@@ -1,38 +0,0 @@
|
|||||||
import React from "react";
|
|
||||||
import { graphql } from "react-relay";
|
|
||||||
|
|
||||||
import { withFragmentContainer } from "coral-framework/lib/relay";
|
|
||||||
|
|
||||||
import { BannedWordListConfigContainer_settings as SettingsData } from "coral-admin/__generated__/BannedWordListConfigContainer_settings.graphql";
|
|
||||||
|
|
||||||
import BannedWordListConfig from "./BannedWordListConfig";
|
|
||||||
|
|
||||||
interface Props {
|
|
||||||
settings: SettingsData;
|
|
||||||
onInitValues: (values: SettingsData) => void;
|
|
||||||
disabled: boolean;
|
|
||||||
}
|
|
||||||
|
|
||||||
class BannedWordListConfigContainer extends React.Component<Props> {
|
|
||||||
constructor(props: Props) {
|
|
||||||
super(props);
|
|
||||||
props.onInitValues(props.settings);
|
|
||||||
}
|
|
||||||
|
|
||||||
public render() {
|
|
||||||
const { disabled } = this.props;
|
|
||||||
return <BannedWordListConfig disabled={disabled} />;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const enhanced = withFragmentContainer<Props>({
|
|
||||||
settings: graphql`
|
|
||||||
fragment BannedWordListConfigContainer_settings on Settings {
|
|
||||||
wordList {
|
|
||||||
banned
|
|
||||||
}
|
|
||||||
}
|
|
||||||
`,
|
|
||||||
})(BannedWordListConfigContainer);
|
|
||||||
|
|
||||||
export default enhanced;
|
|
||||||
@@ -1,5 +1,6 @@
|
|||||||
import { Localized } from "fluent-react/compat";
|
import { Localized } from "fluent-react/compat";
|
||||||
import React, { FunctionComponent } from "react";
|
import React, { FunctionComponent } from "react";
|
||||||
|
import { graphql } from "react-relay";
|
||||||
|
|
||||||
import {
|
import {
|
||||||
FormField,
|
FormField,
|
||||||
@@ -15,6 +16,15 @@ import WordListTextArea from "./WordListTextArea";
|
|||||||
|
|
||||||
import styles from "./SuspectWordListConfig.css";
|
import styles from "./SuspectWordListConfig.css";
|
||||||
|
|
||||||
|
// eslint-disable-next-line no-unused-expressions
|
||||||
|
graphql`
|
||||||
|
fragment SuspectWordListConfig_formValues on Settings {
|
||||||
|
wordList {
|
||||||
|
suspect
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
disabled: boolean;
|
disabled: boolean;
|
||||||
}
|
}
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user