From 1aa1a0a8257b1c661611d937dc3577cd5888f713 Mon Sep 17 00:00:00 2001
From: Guilherme Oenning
Date: Thu, 25 Mar 2021 20:24:44 +0000
Subject: [PATCH] tooling: tslint to eslint (#930)
---
.eslintignore | 4 +
.eslintrc.js | 30 +
.prettierrc | 5 +-
Makefile | 2 +-
esbuild-shim.js | 22 +-
esbuild.config.js | 28 +-
package-lock.json | 2600 +++++++++++++----
package.json | 12 +-
public/AsyncPages.tsx | 58 +-
public/components/ErrorBoundary.spec.tsx | 44 +-
public/components/ErrorBoundary.tsx | 28 +-
public/components/ShowPostResponse.tsx | 44 +-
public/components/ShowTag.tsx | 40 +-
public/components/SignInModal.tsx | 30 +-
public/components/VoteCounter.spec.tsx | 120 +-
public/components/VoteCounter.tsx | 52 +-
public/components/common/Avatar.tsx | 26 +-
public/components/common/Button.tsx | 68 +-
public/components/common/DropDown.tsx | 122 +-
public/components/common/EnvironmentInfo.tsx | 17 +-
public/components/common/FiderVersion.tsx | 12 +-
public/components/common/Footer.tsx | 19 +-
public/components/common/Header.tsx | 38 +-
public/components/common/Heading.tsx | 37 +-
public/components/common/Hint.tsx | 28 +-
public/components/common/Legal.tsx | 56 +-
public/components/common/List.tsx | 30 +-
public/components/common/Loader.tsx | 14 +-
public/components/common/Logo.tsx | 58 +-
public/components/common/Message.tsx | 20 +-
public/components/common/Modal.tsx | 92 +-
public/components/common/Moment.tsx | 28 +-
public/components/common/MultiLineText.tsx | 22 +-
public/components/common/Segment.tsx | 14 +-
public/components/common/SignInControl.tsx | 42 +-
.../components/common/SocialSignInButton.tsx | 32 +-
public/components/common/Toggle.tsx | 32 +-
public/components/common/UserName.tsx | 22 +-
public/components/common/form/Checkbox.tsx | 26 +-
.../common/form/DisplayError.spec.tsx | 104 +-
.../components/common/form/DisplayError.tsx | 42 +-
public/components/common/form/Field.tsx | 24 +-
public/components/common/form/Form.tsx | 26 +-
.../components/common/form/ImageUploader.tsx | 94 +-
public/components/common/form/ImageViewer.tsx | 46 +-
public/components/common/form/Input.tsx | 58 +-
.../common/form/MultiImageUploader.tsx | 86 +-
public/components/common/form/RadioButton.tsx | 42 +-
public/components/common/form/Select.tsx | 52 +-
public/components/common/form/TextArea.tsx | 36 +-
public/components/common/index.tsx | 70 +-
public/components/index.tsx | 12 +-
public/hooks/index.ts | 4 +-
public/hooks/use-fider.ts | 6 +-
public/hooks/use-timeout.ts | 20 +-
public/index.tsx | 53 +-
public/jest.assets.ts | 4 +-
public/jest.setup.ts | 27 +-
public/models/identity.ts | 52 +-
public/models/index.ts | 8 +-
public/models/notification.ts | 10 +-
public/models/post.ts | 100 +-
public/models/settings.ts | 80 +-
.../components/AdminBasePage.tsx | 30 +-
.../Administration/components/OAuthForm.tsx | 174 +-
.../Administration/components/SideMenu.tsx | 60 +-
.../Administration/components/TagForm.tsx | 72 +-
.../Administration/components/TagListItem.tsx | 78 +-
.../pages/AdvancedSettings.page.tsx | 64 +-
.../Administration/pages/Export.page.tsx | 27 +-
.../pages/GeneralSettings.page.tsx | 114 +-
.../Administration/pages/Invitations.page.tsx | 106 +-
.../pages/ManageAuthentication.page.tsx | 76 +-
.../pages/ManageMembers.page.tsx | 124 +-
.../Administration/pages/ManageTags.page.tsx | 90 +-
.../pages/PrivacySettings.page.tsx | 48 +-
.../CompleteSignInProfile.page.tsx | 38 +-
public/pages/CompleteSignInProfile/index.ts | 2 +-
public/pages/Error/Error.page.spec.tsx | 30 +-
public/pages/Error/Error.page.tsx | 22 +-
public/pages/Error/index.ts | 2 +-
public/pages/Home/Home.page.tsx | 67 +-
public/pages/Home/components/ListPosts.tsx | 28 +-
public/pages/Home/components/PostFilter.tsx | 48 +-
public/pages/Home/components/PostInput.tsx | 88 +-
.../pages/Home/components/PostsContainer.tsx | 90 +-
public/pages/Home/components/SimilarPosts.tsx | 54 +-
public/pages/Home/components/TagsFilter.tsx | 62 +-
public/pages/Home/index.ts | 2 +-
.../MyNotifications/MyNotifications.page.tsx | 40 +-
public/pages/MyNotifications/index.ts | 2 +-
public/pages/MySettings/MySettings.page.tsx | 106 +-
.../MySettings/components/APIKeyForm.tsx | 32 +-
.../MySettings/components/DangerZone.tsx | 46 +-
.../components/NotificationSettings.tsx | 84 +-
public/pages/MySettings/index.ts | 2 +-
public/pages/OAuthEcho/OAuthEcho.page.tsx | 58 +-
public/pages/OAuthEcho/index.ts | 2 +-
public/pages/ShowPost/ShowPost.page.tsx | 101 +-
.../ShowPost/components/CommentInput.tsx | 72 +-
.../ShowPost/components/DiscussionPanel.tsx | 20 +-
.../ShowPost/components/ModerationPanel.tsx | 44 +-
.../components/NotificationsPanel.tsx | 40 +-
.../pages/ShowPost/components/PostSearch.tsx | 64 +-
.../ShowPost/components/ResponseForm.tsx | 72 +-
.../pages/ShowPost/components/ShowComment.tsx | 103 +-
.../pages/ShowPost/components/TagListItem.tsx | 22 +-
.../pages/ShowPost/components/TagsPanel.tsx | 62 +-
.../pages/ShowPost/components/VotesModal.tsx | 52 +-
.../pages/ShowPost/components/VotesPanel.tsx | 38 +-
public/pages/ShowPost/index.ts | 2 +-
public/pages/SignIn/SignIn.page.tsx | 53 +-
public/pages/SignIn/index.ts | 2 +-
public/pages/SignUp/SignUp.page.tsx | 106 +-
public/pages/SignUp/index.ts | 2 +-
public/pages/UI/UIToolkit.page.tsx | 70 +-
public/pages/UI/index.ts | 2 +-
public/router.spec.tsx | 17 +-
public/router.tsx | 28 +-
public/services/actions/index.ts | 14 +-
public/services/actions/infra.ts | 16 +-
public/services/actions/invite.ts | 10 +-
public/services/actions/notification.ts | 12 +-
public/services/actions/post.ts | 82 +-
public/services/actions/tag.ts | 24 +-
public/services/actions/tenant.ts | 104 +-
public/services/actions/user.ts | 28 +-
public/services/analytics.ts | 6 +-
public/services/cache.spec.ts | 26 +-
public/services/cache.ts | 38 +-
public/services/device.ts | 4 +-
public/services/fider.ts | 65 +-
public/services/http.ts | 54 +-
public/services/index.ts | 26 +-
public/services/jwt.spec.ts | 16 +-
public/services/jwt.ts | 8 +-
public/services/markdown.spec.ts | 20 +-
public/services/markdown.ts | 40 +-
public/services/navigator.ts | 18 +-
public/services/notify.ts | 14 +-
public/services/querystring.spec.ts | 67 +-
public/services/querystring.ts | 56 +-
public/services/testing/fider.ts | 16 +-
public/services/testing/http.ts | 18 +-
public/services/testing/index.ts | 6 +-
public/services/testing/react.ts | 10 +-
public/services/toastify.tsx | 28 +-
public/services/utils.spec.ts | 75 +-
public/services/utils.ts | 116 +-
public/ssr.tsx | 40 +-
public/tsd.d.ts | 12 +-
tests/lib/browser.ts | 18 +-
tests/lib/components.ts | 54 +-
tests/lib/conditions.ts | 48 +-
tests/lib/ensure.ts | 58 +-
tests/lib/index.ts | 16 +-
tests/lib/mailgun.ts | 60 +-
tests/lib/page.ts | 12 +-
tests/lib/tab.ts | 60 +-
tests/lib/utils.ts | 18 +-
tests/multi.spec.ts | 8 +-
tests/pages/FacebookSignInPage.ts | 26 +-
tests/pages/GeneralSettingsPage.ts | 34 +-
tests/pages/HomePage.ts | 92 +-
tests/pages/ShowPostPage.ts | 70 +-
tests/pages/SignUpPage.ts | 50 +-
tests/pages/components/CommentList.ts | 8 +-
tests/pages/components/PostList.ts | 28 +-
tests/pages/components/index.ts | 4 +-
tests/pages/index.ts | 36 +-
tests/scenarios/admin-settings.ts | 16 +-
tests/scenarios/email-signup.ts | 38 +-
tests/scenarios/feedback-loop.ts | 144 +-
tests/scenarios/index.ts | 66 +-
tests/single.spec.ts | 6 +-
tslint.json | 14 -
webpack.config.js | 36 +-
177 files changed, 5878 insertions(+), 4181 deletions(-)
create mode 100644 .eslintignore
create mode 100644 .eslintrc.js
delete mode 100644 tslint.json
diff --git a/.eslintignore b/.eslintignore
new file mode 100644
index 000000000..4fed319ba
--- /dev/null
+++ b/.eslintignore
@@ -0,0 +1,4 @@
+dist/
+ssr.js
+node_modules/
+package-lock.json
\ No newline at end of file
diff --git a/.eslintrc.js b/.eslintrc.js
new file mode 100644
index 000000000..8a03afb6d
--- /dev/null
+++ b/.eslintrc.js
@@ -0,0 +1,30 @@
+/* eslint-disable */
+
+module.exports = {
+ root: true,
+ parser: "@typescript-eslint/parser",
+ parserOptions: {
+ ecmaFeatures: { jsx: true },
+ },
+ settings: {
+ react: {
+ version: "detect",
+ },
+ },
+ extends: [
+ "eslint:recommended",
+ "plugin:@typescript-eslint/eslint-recommended",
+ "plugin:@typescript-eslint/recommended",
+ "plugin:react/recommended",
+ "plugin:prettier/recommended",
+ ],
+ rules: {
+ // Include .prettierrc.js rules
+ "prettier/prettier": ["error", {}, { usePrettierrc: true }],
+ "react/react-in-jsx-scope": "off",
+ "react/prop-types": "off",
+ "react/jsx-no-target-blank": ["error", { "allowReferrer": true }],
+ "@typescript-eslint/no-explicit-any": "off", // TODO: turn this on in future
+ "@typescript-eslint/explicit-module-boundary-types": "off" // TODO: turn this on in future
+ },
+};
diff --git a/.prettierrc b/.prettierrc
index 5f38c1702..b4278a70d 100644
--- a/.prettierrc
+++ b/.prettierrc
@@ -1,7 +1,8 @@
{
+ "semi": false,
"trailingComma": "es5",
"singleQuote": false,
- "printWidth": 200,
+ "printWidth": 160,
"tabWidth": 2,
"useTabs": false
-}
+}
\ No newline at end of file
diff --git a/Makefile b/Makefile
index cb744aaa7..8b2e0312a 100644
--- a/Makefile
+++ b/Makefile
@@ -65,7 +65,7 @@ lint-server: ## Lint server code
golangci-lint run
lint-ui: ## Lint ui code
- npx tslint -c tslint.json 'public/**/*.{ts,tsx}' 'tests/**/*.{ts,tsx}'
+ npx eslint .
diff --git a/esbuild-shim.js b/esbuild-shim.js
index 3369f910b..4007b848a 100644
--- a/esbuild-shim.js
+++ b/esbuild-shim.js
@@ -1,23 +1,23 @@
-const global = (1, eval)('this');
-global.global = global;
-global.globalThis = global;
-global.frames = global;
-global.self = global;
+const global = (1, eval)("this")
+global.global = global
+global.globalThis = global
+global.frames = global
+global.self = global
const document = {
documentElement: {},
- getElementById: () => undefined
+ getElementById: () => undefined,
}
const window = {
document,
location: {
- href: ''
- }
+ href: "",
+ },
}
const navigator = {}
-global.navigator = navigator;
-global.window = window;
-global.document = document;
\ No newline at end of file
+global.navigator = navigator
+global.window = window
+global.document = document
diff --git a/esbuild.config.js b/esbuild.config.js
index ed9a37689..67e0cfb6a 100644
--- a/esbuild.config.js
+++ b/esbuild.config.js
@@ -1,17 +1,21 @@
+/* eslint-disable @typescript-eslint/no-var-requires */
+/* eslint-disable no-undef */
let emptyCSS = {
- name: 'empty-css-imports',
+ name: "empty-css-imports",
setup(build) {
- build.onLoad({ filter: /\.(css|scss)$/ }, () => ({ contents: '' }))
+ build.onLoad({ filter: /\.(css|scss)$/ }, () => ({ contents: "" }))
},
}
-require('esbuild').build({
- entryPoints: ['./public/ssr.tsx'],
- bundle: true,
- define: {
- "process.env.NODE_ENV": `"${process.env.NODE_ENV || 'development'}"`
- },
- inject: ['./esbuild-shim.js'],
- outfile: 'ssr.js',
- plugins: [emptyCSS],
-}).catch(() => process.exit(1))
+require("esbuild")
+ .build({
+ entryPoints: ["./public/ssr.tsx"],
+ bundle: true,
+ define: {
+ "process.env.NODE_ENV": `"${process.env.NODE_ENV || "development"}"`,
+ },
+ inject: ["./esbuild-shim.js"],
+ outfile: "ssr.js",
+ plugins: [emptyCSS],
+ })
+ .catch(() => process.exit(1))
diff --git a/package-lock.json b/package-lock.json
index 3fc3099f7..de1aff44a 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -27,11 +27,19 @@
"@types/react": "17.0.3",
"@types/react-dom": "17.0.3",
"@types/react-textarea-autosize": "4.3.5",
+ "@typescript-eslint/eslint-plugin": "4.18.0",
+ "@typescript-eslint/parser": "4.18.0",
"@wojtekmaj/enzyme-adapter-react-17": "0.5.0",
+ "autoprefixer": "10.2.5",
"css-loader": "5.1.1",
"dotenv": "8.2.0",
"enzyme": "3.11.0",
"esbuild": "0.9.5",
+ "eslint": "7.22.0",
+ "eslint-config-prettier": "8.1.0",
+ "eslint-plugin-prettier": "3.3.1",
+ "eslint-plugin-react": "7.22.0",
+ "eslint-plugin-react-hooks": "4.2.0",
"file-loader": "6.2.0",
"fork-ts-checker-webpack-plugin": "6.1.1",
"jest": "26.6.3",
@@ -43,10 +51,6 @@
"sass-loader": "11.0.1",
"ts-jest": "26.5.3",
"ts-loader": "8.0.17",
- "tslint": "6.1.3",
- "tslint-config-prettier": "1.18.0",
- "tslint-plugin-prettier": "2.3.0",
- "tslint-react": "5.0.0",
"typescript": "4.2.3",
"webpack": "5.24.3",
"webpack-bundle-analyzer": "4.4.0",
@@ -58,12 +62,12 @@
}
},
"node_modules/@babel/code-frame": {
- "version": "7.12.13",
- "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.12.13.tgz",
- "integrity": "sha512-HV1Cm0Q3ZrpCR93tkWOYiuYIgLxZXZFVG2VgK+MBWjUqZTundupbfx2aXarXuw5Ko5aMcjtJgbSs4vUGBS5v6g==",
+ "version": "7.12.11",
+ "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.12.11.tgz",
+ "integrity": "sha512-Zt1yodBx1UcyiePMSkWnU4hPqhwq7hGi2nFL1LeA3EUl+q2LQx16MISgJ0+z7dnmgvP9QtIleuETGOiOH1RcIw==",
"dev": true,
"dependencies": {
- "@babel/highlight": "^7.12.13"
+ "@babel/highlight": "^7.10.4"
}
},
"node_modules/@babel/compat-data": {
@@ -103,6 +107,15 @@
"url": "https://opencollective.com/babel"
}
},
+ "node_modules/@babel/core/node_modules/@babel/code-frame": {
+ "version": "7.12.13",
+ "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.12.13.tgz",
+ "integrity": "sha512-HV1Cm0Q3ZrpCR93tkWOYiuYIgLxZXZFVG2VgK+MBWjUqZTundupbfx2aXarXuw5Ko5aMcjtJgbSs4vUGBS5v6g==",
+ "dev": true,
+ "dependencies": {
+ "@babel/highlight": "^7.12.13"
+ }
+ },
"node_modules/@babel/core/node_modules/semver": {
"version": "6.3.0",
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
@@ -544,6 +557,15 @@
"@babel/types": "^7.12.13"
}
},
+ "node_modules/@babel/template/node_modules/@babel/code-frame": {
+ "version": "7.12.13",
+ "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.12.13.tgz",
+ "integrity": "sha512-HV1Cm0Q3ZrpCR93tkWOYiuYIgLxZXZFVG2VgK+MBWjUqZTundupbfx2aXarXuw5Ko5aMcjtJgbSs4vUGBS5v6g==",
+ "dev": true,
+ "dependencies": {
+ "@babel/highlight": "^7.12.13"
+ }
+ },
"node_modules/@babel/traverse": {
"version": "7.13.0",
"resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.13.0.tgz",
@@ -561,6 +583,24 @@
"lodash": "^4.17.19"
}
},
+ "node_modules/@babel/traverse/node_modules/@babel/code-frame": {
+ "version": "7.12.13",
+ "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.12.13.tgz",
+ "integrity": "sha512-HV1Cm0Q3ZrpCR93tkWOYiuYIgLxZXZFVG2VgK+MBWjUqZTundupbfx2aXarXuw5Ko5aMcjtJgbSs4vUGBS5v6g==",
+ "dev": true,
+ "dependencies": {
+ "@babel/highlight": "^7.12.13"
+ }
+ },
+ "node_modules/@babel/traverse/node_modules/globals": {
+ "version": "11.12.0",
+ "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz",
+ "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==",
+ "dev": true,
+ "engines": {
+ "node": ">=4"
+ }
+ },
"node_modules/@babel/types": {
"version": "7.13.12",
"resolved": "https://registry.npmjs.org/@babel/types/-/types-7.13.12.tgz",
@@ -603,6 +643,50 @@
"node": ">=10.0.0"
}
},
+ "node_modules/@eslint/eslintrc": {
+ "version": "0.4.0",
+ "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-0.4.0.tgz",
+ "integrity": "sha512-2ZPCc+uNbjV5ERJr+aKSPRwZgKd2z11x0EgLvb1PURmUrn9QNRXFqje0Ldq454PfAVyaJYyrDvvIKSFP4NnBog==",
+ "dev": true,
+ "dependencies": {
+ "ajv": "^6.12.4",
+ "debug": "^4.1.1",
+ "espree": "^7.3.0",
+ "globals": "^12.1.0",
+ "ignore": "^4.0.6",
+ "import-fresh": "^3.2.1",
+ "js-yaml": "^3.13.1",
+ "minimatch": "^3.0.4",
+ "strip-json-comments": "^3.1.1"
+ },
+ "engines": {
+ "node": "^10.12.0 || >=12.0.0"
+ }
+ },
+ "node_modules/@eslint/eslintrc/node_modules/globals": {
+ "version": "12.4.0",
+ "resolved": "https://registry.npmjs.org/globals/-/globals-12.4.0.tgz",
+ "integrity": "sha512-BWICuzzDvDoH54NHKCseDanAhE3CeDorgDL5MT6LMXXj2WCnd9UC2szdk4AWLfjdgNBCXLUanXYcpBBKOSWGwg==",
+ "dev": true,
+ "dependencies": {
+ "type-fest": "^0.8.1"
+ },
+ "engines": {
+ "node": ">=8"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/@eslint/eslintrc/node_modules/type-fest": {
+ "version": "0.8.1",
+ "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz",
+ "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==",
+ "dev": true,
+ "engines": {
+ "node": ">=8"
+ }
+ },
"node_modules/@istanbuljs/load-nyc-config": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz",
@@ -773,6 +857,7 @@
"jest-resolve": "^26.6.2",
"jest-util": "^26.6.2",
"jest-worker": "^26.6.2",
+ "node-notifier": "^8.0.0",
"slash": "^3.0.0",
"source-map": "^0.6.0",
"string-length": "^4.0.1",
@@ -873,6 +958,41 @@
"node": ">= 10.14.2"
}
},
+ "node_modules/@nodelib/fs.scandir": {
+ "version": "2.1.4",
+ "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.4.tgz",
+ "integrity": "sha512-33g3pMJk3bg5nXbL/+CY6I2eJDzZAni49PfJnL5fghPTggPvBd/pFNSgJsdAgWptuFu7qq/ERvOYFlhvsLTCKA==",
+ "dev": true,
+ "dependencies": {
+ "@nodelib/fs.stat": "2.0.4",
+ "run-parallel": "^1.1.9"
+ },
+ "engines": {
+ "node": ">= 8"
+ }
+ },
+ "node_modules/@nodelib/fs.stat": {
+ "version": "2.0.4",
+ "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.4.tgz",
+ "integrity": "sha512-IYlHJA0clt2+Vg7bccq+TzRdJvv19c2INqBSsoOLp1je7xjtr7J26+WXR72MCdvU9q1qTzIWDfhMf+DRvQJK4Q==",
+ "dev": true,
+ "engines": {
+ "node": ">= 8"
+ }
+ },
+ "node_modules/@nodelib/fs.walk": {
+ "version": "1.2.6",
+ "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.6.tgz",
+ "integrity": "sha512-8Broas6vTtW4GIXTAHDoE32hnN2M5ykgCpWGbuXHQ15vEMqr23pB76e/GZcYsZCHALv50ktd24qhEyKr6wBtow==",
+ "dev": true,
+ "dependencies": {
+ "@nodelib/fs.scandir": "2.1.4",
+ "fastq": "^1.6.0"
+ },
+ "engines": {
+ "node": ">= 8"
+ }
+ },
"node_modules/@polka/url": {
"version": "1.0.0-next.11",
"resolved": "https://registry.npmjs.org/@polka/url/-/url-1.0.0-next.11.tgz",
@@ -1181,6 +1301,163 @@
"@types/node": "*"
}
},
+ "node_modules/@typescript-eslint/eslint-plugin": {
+ "version": "4.18.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-4.18.0.tgz",
+ "integrity": "sha512-Lzkc/2+7EoH7+NjIWLS2lVuKKqbEmJhtXe3rmfA8cyiKnZm3IfLf51irnBcmow8Q/AptVV0XBZmBJKuUJTe6cQ==",
+ "dev": true,
+ "dependencies": {
+ "@typescript-eslint/experimental-utils": "4.18.0",
+ "@typescript-eslint/scope-manager": "4.18.0",
+ "debug": "^4.1.1",
+ "functional-red-black-tree": "^1.0.1",
+ "lodash": "^4.17.15",
+ "regexpp": "^3.0.0",
+ "semver": "^7.3.2",
+ "tsutils": "^3.17.1"
+ },
+ "engines": {
+ "node": "^10.12.0 || >=12.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/typescript-eslint"
+ },
+ "peerDependencies": {
+ "@typescript-eslint/parser": "^4.0.0",
+ "eslint": "^5.0.0 || ^6.0.0 || ^7.0.0"
+ },
+ "peerDependenciesMeta": {
+ "typescript": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@typescript-eslint/experimental-utils": {
+ "version": "4.18.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-4.18.0.tgz",
+ "integrity": "sha512-92h723Kblt9JcT2RRY3QS2xefFKar4ZQFVs3GityOKWQYgtajxt/tuXIzL7sVCUlM1hgreiV5gkGYyBpdOwO6A==",
+ "dev": true,
+ "dependencies": {
+ "@types/json-schema": "^7.0.3",
+ "@typescript-eslint/scope-manager": "4.18.0",
+ "@typescript-eslint/types": "4.18.0",
+ "@typescript-eslint/typescript-estree": "4.18.0",
+ "eslint-scope": "^5.0.0",
+ "eslint-utils": "^2.0.0"
+ },
+ "engines": {
+ "node": "^10.12.0 || >=12.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/typescript-eslint"
+ },
+ "peerDependencies": {
+ "eslint": "*"
+ }
+ },
+ "node_modules/@typescript-eslint/parser": {
+ "version": "4.18.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-4.18.0.tgz",
+ "integrity": "sha512-W3z5S0ZbecwX3PhJEAnq4mnjK5JJXvXUDBYIYGoweCyWyuvAKfGHvzmpUzgB5L4cRBb+cTu9U/ro66dx7dIimA==",
+ "dev": true,
+ "dependencies": {
+ "@typescript-eslint/scope-manager": "4.18.0",
+ "@typescript-eslint/types": "4.18.0",
+ "@typescript-eslint/typescript-estree": "4.18.0",
+ "debug": "^4.1.1"
+ },
+ "engines": {
+ "node": "^10.12.0 || >=12.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/typescript-eslint"
+ },
+ "peerDependencies": {
+ "eslint": "^5.0.0 || ^6.0.0 || ^7.0.0"
+ },
+ "peerDependenciesMeta": {
+ "typescript": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@typescript-eslint/scope-manager": {
+ "version": "4.18.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-4.18.0.tgz",
+ "integrity": "sha512-olX4yN6rvHR2eyFOcb6E4vmhDPsfdMyfQ3qR+oQNkAv8emKKlfxTWUXU5Mqxs2Fwe3Pf1BoPvrwZtwngxDzYzQ==",
+ "dev": true,
+ "dependencies": {
+ "@typescript-eslint/types": "4.18.0",
+ "@typescript-eslint/visitor-keys": "4.18.0"
+ },
+ "engines": {
+ "node": "^8.10.0 || ^10.13.0 || >=11.10.1"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/typescript-eslint"
+ }
+ },
+ "node_modules/@typescript-eslint/types": {
+ "version": "4.18.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-4.18.0.tgz",
+ "integrity": "sha512-/BRociARpj5E+9yQ7cwCF/SNOWwXJ3qhjurMuK2hIFUbr9vTuDeu476Zpu+ptxY2kSxUHDGLLKy+qGq2sOg37A==",
+ "dev": true,
+ "engines": {
+ "node": "^8.10.0 || ^10.13.0 || >=11.10.1"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/typescript-eslint"
+ }
+ },
+ "node_modules/@typescript-eslint/typescript-estree": {
+ "version": "4.18.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-4.18.0.tgz",
+ "integrity": "sha512-wt4xvF6vvJI7epz+rEqxmoNQ4ZADArGQO9gDU+cM0U5fdVv7N+IAuVoVAoZSOZxzGHBfvE3XQMLdy+scsqFfeg==",
+ "dev": true,
+ "dependencies": {
+ "@typescript-eslint/types": "4.18.0",
+ "@typescript-eslint/visitor-keys": "4.18.0",
+ "debug": "^4.1.1",
+ "globby": "^11.0.1",
+ "is-glob": "^4.0.1",
+ "semver": "^7.3.2",
+ "tsutils": "^3.17.1"
+ },
+ "engines": {
+ "node": "^10.12.0 || >=12.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/typescript-eslint"
+ },
+ "peerDependenciesMeta": {
+ "typescript": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@typescript-eslint/visitor-keys": {
+ "version": "4.18.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-4.18.0.tgz",
+ "integrity": "sha512-Q9t90JCvfYaN0OfFUgaLqByOfz8yPeTAdotn/XYNm5q9eHax90gzdb+RJ6E9T5s97Kv/UHWKERTmqA0jTKAEHw==",
+ "dev": true,
+ "dependencies": {
+ "@typescript-eslint/types": "4.18.0",
+ "eslint-visitor-keys": "^2.0.0"
+ },
+ "engines": {
+ "node": "^8.10.0 || ^10.13.0 || >=11.10.1"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/typescript-eslint"
+ }
+ },
"node_modules/@webassemblyjs/ast": {
"version": "1.11.0",
"resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.11.0.tgz",
@@ -1409,9 +1686,9 @@
"dev": true
},
"node_modules/acorn": {
- "version": "8.1.0",
- "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.1.0.tgz",
- "integrity": "sha512-LWCF/Wn0nfHOmJ9rzQApGnxnvgfROzGilS8936rqN/lfcYkY9MYZzdMqN+2NJ4SlTc+m5HiSa+kNfDtI64dwUA==",
+ "version": "7.4.1",
+ "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz",
+ "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==",
"dev": true,
"bin": {
"acorn": "bin/acorn"
@@ -1430,16 +1707,13 @@
"acorn-walk": "^7.1.1"
}
},
- "node_modules/acorn-globals/node_modules/acorn": {
- "version": "7.4.1",
- "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz",
- "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==",
+ "node_modules/acorn-jsx": {
+ "version": "5.3.1",
+ "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.1.tgz",
+ "integrity": "sha512-K0Ptm/47OKfQRpNQ2J/oIN/3QYiK6FwW+eJbILhsdxh2WTLdl+30o8aGdTbm5JbffpFFAg/g+zi1E+jvJha5ng==",
"dev": true,
- "bin": {
- "acorn": "bin/acorn"
- },
- "engines": {
- "node": ">=0.4.0"
+ "peerDependencies": {
+ "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0"
}
},
"node_modules/acorn-walk": {
@@ -1507,12 +1781,12 @@
}
},
"node_modules/ansi-escapes": {
- "version": "4.3.1",
- "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.1.tgz",
- "integrity": "sha512-JWF7ocqNrp8u9oqpgV+wH5ftbt+cfvv+PTjOvKLT3AdYly/LmORARfEVT1iyjwN+4MqE5UmVKoAdIBqeoCHgLA==",
+ "version": "4.3.2",
+ "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz",
+ "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==",
"dev": true,
"dependencies": {
- "type-fest": "^0.11.0"
+ "type-fest": "^0.21.3"
},
"engines": {
"node": ">=8"
@@ -1521,6 +1795,18 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
+ "node_modules/ansi-escapes/node_modules/type-fest": {
+ "version": "0.21.3",
+ "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz",
+ "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==",
+ "dev": true,
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
"node_modules/ansi-regex": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz",
@@ -1625,6 +1911,34 @@
"node": ">=0.10.0"
}
},
+ "node_modules/array-includes": {
+ "version": "3.1.3",
+ "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.3.tgz",
+ "integrity": "sha512-gcem1KlBU7c9rB+Rq8/3PPKsK2kjqeEBa3bD5kkQo4nYlOHQCJqIJFqBXDEfwaRuYTT4E+FxA9xez7Gf/e3Q7A==",
+ "dev": true,
+ "dependencies": {
+ "call-bind": "^1.0.2",
+ "define-properties": "^1.1.3",
+ "es-abstract": "^1.18.0-next.2",
+ "get-intrinsic": "^1.1.1",
+ "is-string": "^1.0.5"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/array-union": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz",
+ "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==",
+ "dev": true,
+ "engines": {
+ "node": ">=8"
+ }
+ },
"node_modules/array-unique": {
"version": "0.3.2",
"resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz",
@@ -1664,6 +1978,24 @@
"url": "https://github.com/sponsors/ljharb"
}
},
+ "node_modules/array.prototype.flatmap": {
+ "version": "1.2.4",
+ "resolved": "https://registry.npmjs.org/array.prototype.flatmap/-/array.prototype.flatmap-1.2.4.tgz",
+ "integrity": "sha512-r9Z0zYoxqHz60vvQbWEdXIEtCwHF0yxaWfno9qzXeNHvfyl3BZqygmGzb84dsubyaXLH4husF+NFgMSdpZhk2Q==",
+ "dev": true,
+ "dependencies": {
+ "call-bind": "^1.0.0",
+ "define-properties": "^1.1.3",
+ "es-abstract": "^1.18.0-next.1",
+ "function-bind": "^1.1.1"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
"node_modules/asn1": {
"version": "0.2.4",
"resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.4.tgz",
@@ -1691,6 +2023,15 @@
"node": ">=0.10.0"
}
},
+ "node_modules/astral-regex": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-2.0.0.tgz",
+ "integrity": "sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==",
+ "dev": true,
+ "engines": {
+ "node": ">=8"
+ }
+ },
"node_modules/async-foreach": {
"version": "0.1.3",
"resolved": "https://registry.npmjs.org/async-foreach/-/async-foreach-0.1.3.tgz",
@@ -1727,17 +2068,44 @@
"node": ">= 4.5.0"
}
},
- "node_modules/aws-sign2": {
- "version": "0.7.0",
- "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz",
- "integrity": "sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg=",
+ "node_modules/autoprefixer": {
+ "version": "10.2.5",
+ "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.2.5.tgz",
+ "integrity": "sha512-7H4AJZXvSsn62SqZyJCP+1AWwOuoYpUfK6ot9vm0e87XD6mT8lDywc9D9OTJPMULyGcvmIxzTAMeG2Cc+YX+fA==",
"dev": true,
+ "dependencies": {
+ "browserslist": "^4.16.3",
+ "caniuse-lite": "^1.0.30001196",
+ "colorette": "^1.2.2",
+ "fraction.js": "^4.0.13",
+ "normalize-range": "^0.1.2",
+ "postcss-value-parser": "^4.1.0"
+ },
+ "bin": {
+ "autoprefixer": "bin/autoprefixer"
+ },
"engines": {
- "node": "*"
- }
- },
- "node_modules/aws4": {
- "version": "1.11.0",
+ "node": "^10 || ^12 || >=14"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/postcss/"
+ },
+ "peerDependencies": {
+ "postcss": "^8.1.0"
+ }
+ },
+ "node_modules/aws-sign2": {
+ "version": "0.7.0",
+ "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz",
+ "integrity": "sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg=",
+ "dev": true,
+ "engines": {
+ "node": "*"
+ }
+ },
+ "node_modules/aws4": {
+ "version": "1.11.0",
"resolved": "https://registry.npmjs.org/aws4/-/aws4-1.11.0.tgz",
"integrity": "sha512-xh1Rl34h6Fi1DC2WWKfxUTVqRsNnr6LsKz2+hfwDxQJWmrx8+c7ylaqBMcHfl1U1r2dsifOvKX3LQuLNZ+XSvA==",
"dev": true
@@ -2059,15 +2427,6 @@
"integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==",
"dev": true
},
- "node_modules/builtin-modules": {
- "version": "1.1.1",
- "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-1.1.1.tgz",
- "integrity": "sha1-Jw8HbFpywC9bZaR9+Uxf46J4iS8=",
- "dev": true,
- "engines": {
- "node": ">=0.10.0"
- }
- },
"node_modules/cache-base": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/cache-base/-/cache-base-1.0.1.tgz",
@@ -2236,6 +2595,7 @@
"dependencies": {
"anymatch": "~3.1.1",
"braces": "~3.0.2",
+ "fsevents": "~2.3.1",
"glob-parent": "~5.1.0",
"is-binary-path": "~2.1.0",
"is-glob": "~4.0.1",
@@ -2843,15 +3203,6 @@
"integrity": "sha512-xd4D8kHQtB0KtWW0c9xBZD5LVtm9chkMOfs/3Yn01RhT/sFIsVtzTtypfKoFfWBaL+7xCYLxjOLkhwPXaX/Kcg==",
"dev": true
},
- "node_modules/diff": {
- "version": "4.0.2",
- "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz",
- "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==",
- "dev": true,
- "engines": {
- "node": ">=0.3.1"
- }
- },
"node_modules/diff-sequences": {
"version": "26.6.2",
"resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-26.6.2.tgz",
@@ -2861,12 +3212,36 @@
"node": ">= 10.14.2"
}
},
+ "node_modules/dir-glob": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz",
+ "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==",
+ "dev": true,
+ "dependencies": {
+ "path-type": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
"node_modules/discontinuous-range": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/discontinuous-range/-/discontinuous-range-1.0.0.tgz",
"integrity": "sha1-44Mx8IRLukm5qctxx3FYWqsbxlo=",
"dev": true
},
+ "node_modules/doctrine": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz",
+ "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==",
+ "dev": true,
+ "dependencies": {
+ "esutils": "^2.0.2"
+ },
+ "engines": {
+ "node": ">=6.0.0"
+ }
+ },
"node_modules/dom-serializer": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-1.2.0.tgz",
@@ -2974,9 +3349,9 @@
}
},
"node_modules/electron-to-chromium": {
- "version": "1.3.695",
- "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.695.tgz",
- "integrity": "sha512-lz66RliUqLHU1Ojxx1A4QUxKydjiQ79Y4dZyPobs2Dmxj5aVL2TM3KoQ2Gs7HS703Bfny+ukI3KOxwAB0xceHQ==",
+ "version": "1.3.700",
+ "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.700.tgz",
+ "integrity": "sha512-wQtaxVZzpOeCjW1CGuC5W3bYjE2jglvk076LcTautBOB9UtHztty7wNzjVsndiMcSsdUsdMy5w76w5J1U7OPTQ==",
"dev": true
},
"node_modules/emittery": {
@@ -3287,7 +3662,8 @@
"esprima": "^4.0.1",
"estraverse": "^5.2.0",
"esutils": "^2.0.2",
- "optionator": "^0.8.1"
+ "optionator": "^0.8.1",
+ "source-map": "~0.6.1"
},
"bin": {
"escodegen": "bin/escodegen.js",
@@ -3300,27 +3676,201 @@
"source-map": "~0.6.1"
}
},
+ "node_modules/escodegen/node_modules/estraverse": {
+ "version": "5.2.0",
+ "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.2.0.tgz",
+ "integrity": "sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ==",
+ "dev": true,
+ "engines": {
+ "node": ">=4.0"
+ }
+ },
+ "node_modules/escodegen/node_modules/levn": {
+ "version": "0.3.0",
+ "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz",
+ "integrity": "sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4=",
+ "dev": true,
+ "dependencies": {
+ "prelude-ls": "~1.1.2",
+ "type-check": "~0.3.2"
+ },
+ "engines": {
+ "node": ">= 0.8.0"
+ }
+ },
+ "node_modules/escodegen/node_modules/optionator": {
+ "version": "0.8.3",
+ "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.3.tgz",
+ "integrity": "sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA==",
+ "dev": true,
+ "dependencies": {
+ "deep-is": "~0.1.3",
+ "fast-levenshtein": "~2.0.6",
+ "levn": "~0.3.0",
+ "prelude-ls": "~1.1.2",
+ "type-check": "~0.3.2",
+ "word-wrap": "~1.2.3"
+ },
+ "engines": {
+ "node": ">= 0.8.0"
+ }
+ },
+ "node_modules/escodegen/node_modules/prelude-ls": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz",
+ "integrity": "sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ=",
+ "dev": true,
+ "engines": {
+ "node": ">= 0.8.0"
+ }
+ },
+ "node_modules/escodegen/node_modules/type-check": {
+ "version": "0.3.2",
+ "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz",
+ "integrity": "sha1-WITKtRLPHTVeP7eE8wgEsrUg23I=",
+ "dev": true,
+ "dependencies": {
+ "prelude-ls": "~1.1.2"
+ },
+ "engines": {
+ "node": ">= 0.8.0"
+ }
+ },
+ "node_modules/eslint": {
+ "version": "7.22.0",
+ "resolved": "https://registry.npmjs.org/eslint/-/eslint-7.22.0.tgz",
+ "integrity": "sha512-3VawOtjSJUQiiqac8MQc+w457iGLfuNGLFn8JmF051tTKbh5/x/0vlcEj8OgDCaw7Ysa2Jn8paGshV7x2abKXg==",
+ "dev": true,
+ "dependencies": {
+ "@babel/code-frame": "7.12.11",
+ "@eslint/eslintrc": "^0.4.0",
+ "ajv": "^6.10.0",
+ "chalk": "^4.0.0",
+ "cross-spawn": "^7.0.2",
+ "debug": "^4.0.1",
+ "doctrine": "^3.0.0",
+ "enquirer": "^2.3.5",
+ "eslint-scope": "^5.1.1",
+ "eslint-utils": "^2.1.0",
+ "eslint-visitor-keys": "^2.0.0",
+ "espree": "^7.3.1",
+ "esquery": "^1.4.0",
+ "esutils": "^2.0.2",
+ "file-entry-cache": "^6.0.1",
+ "functional-red-black-tree": "^1.0.1",
+ "glob-parent": "^5.0.0",
+ "globals": "^13.6.0",
+ "ignore": "^4.0.6",
+ "import-fresh": "^3.0.0",
+ "imurmurhash": "^0.1.4",
+ "is-glob": "^4.0.0",
+ "js-yaml": "^3.13.1",
+ "json-stable-stringify-without-jsonify": "^1.0.1",
+ "levn": "^0.4.1",
+ "lodash": "^4.17.21",
+ "minimatch": "^3.0.4",
+ "natural-compare": "^1.4.0",
+ "optionator": "^0.9.1",
+ "progress": "^2.0.0",
+ "regexpp": "^3.1.0",
+ "semver": "^7.2.1",
+ "strip-ansi": "^6.0.0",
+ "strip-json-comments": "^3.1.0",
+ "table": "^6.0.4",
+ "text-table": "^0.2.0",
+ "v8-compile-cache": "^2.0.3"
+ },
+ "bin": {
+ "eslint": "bin/eslint.js"
+ },
+ "engines": {
+ "node": "^10.12.0 || >=12.0.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/eslint"
+ }
+ },
+ "node_modules/eslint-config-prettier": {
+ "version": "8.1.0",
+ "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-8.1.0.tgz",
+ "integrity": "sha512-oKMhGv3ihGbCIimCAjqkdzx2Q+jthoqnXSP+d86M9tptwugycmTFdVR4IpLgq2c4SHifbwO90z2fQ8/Aio73yw==",
+ "dev": true,
+ "bin": {
+ "eslint-config-prettier": "bin/cli.js"
+ },
+ "peerDependencies": {
+ "eslint": ">=7.0.0"
+ }
+ },
"node_modules/eslint-plugin-prettier": {
- "version": "2.7.0",
- "resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-2.7.0.tgz",
- "integrity": "sha512-CStQYJgALoQBw3FsBzH0VOVDRnJ/ZimUlpLm226U8qgqYJfPOY/CPK6wyRInMxh73HSKg5wyRwdS4BVYYHwokA==",
+ "version": "3.3.1",
+ "resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-3.3.1.tgz",
+ "integrity": "sha512-Rq3jkcFY8RYeQLgk2cCwuc0P7SEFwDravPhsJZOQ5N4YI4DSg50NyqJ/9gdZHzQlHf8MvafSesbNJCcP/FF6pQ==",
"dev": true,
"dependencies": {
- "fast-diff": "^1.1.1",
- "jest-docblock": "^21.0.0"
+ "prettier-linter-helpers": "^1.0.0"
},
"engines": {
- "node": ">=4.0.0"
+ "node": ">=6.0.0"
},
"peerDependencies": {
- "prettier": ">= 0.11.0"
+ "eslint": ">=5.0.0",
+ "prettier": ">=1.13.0"
+ },
+ "peerDependenciesMeta": {
+ "eslint-config-prettier": {
+ "optional": true
+ }
}
},
- "node_modules/eslint-plugin-prettier/node_modules/jest-docblock": {
- "version": "21.2.0",
- "resolved": "https://registry.npmjs.org/jest-docblock/-/jest-docblock-21.2.0.tgz",
- "integrity": "sha512-5IZ7sY9dBAYSV+YjQ0Ovb540Ku7AO9Z5o2Cg789xj167iQuZ2cG+z0f3Uct6WeYLbU6aQiM2pCs7sZ+4dotydw==",
- "dev": true
+ "node_modules/eslint-plugin-react": {
+ "version": "7.22.0",
+ "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.22.0.tgz",
+ "integrity": "sha512-p30tuX3VS+NWv9nQot9xIGAHBXR0+xJVaZriEsHoJrASGCJZDJ8JLNM0YqKqI0AKm6Uxaa1VUHoNEibxRCMQHA==",
+ "dev": true,
+ "dependencies": {
+ "array-includes": "^3.1.1",
+ "array.prototype.flatmap": "^1.2.3",
+ "doctrine": "^2.1.0",
+ "has": "^1.0.3",
+ "jsx-ast-utils": "^2.4.1 || ^3.0.0",
+ "object.entries": "^1.1.2",
+ "object.fromentries": "^2.0.2",
+ "object.values": "^1.1.1",
+ "prop-types": "^15.7.2",
+ "resolve": "^1.18.1",
+ "string.prototype.matchall": "^4.0.2"
+ },
+ "engines": {
+ "node": ">=4"
+ },
+ "peerDependencies": {
+ "eslint": "^3 || ^4 || ^5 || ^6 || ^7"
+ }
+ },
+ "node_modules/eslint-plugin-react-hooks": {
+ "version": "4.2.0",
+ "resolved": "https://registry.npmjs.org/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-4.2.0.tgz",
+ "integrity": "sha512-623WEiZJqxR7VdxFCKLI6d6LLpwJkGPYKODnkH3D7WpOG5KM8yWueBd8TLsNAetEJNF5iJmolaAKO3F8yzyVBQ==",
+ "dev": true,
+ "engines": {
+ "node": ">=10"
+ },
+ "peerDependencies": {
+ "eslint": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0"
+ }
+ },
+ "node_modules/eslint-plugin-react/node_modules/doctrine": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz",
+ "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==",
+ "dev": true,
+ "dependencies": {
+ "esutils": "^2.0.2"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
},
"node_modules/eslint-scope": {
"version": "5.1.1",
@@ -3335,13 +3885,60 @@
"node": ">=8.0.0"
}
},
- "node_modules/eslint-scope/node_modules/estraverse": {
- "version": "4.3.0",
- "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz",
- "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==",
+ "node_modules/eslint-utils": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-2.1.0.tgz",
+ "integrity": "sha512-w94dQYoauyvlDc43XnGB8lU3Zt713vNChgt4EWwhXAP2XkBvndfxF0AgIqKOOasjPIPzj9JqgwkwbCYD0/V3Zg==",
"dev": true,
+ "dependencies": {
+ "eslint-visitor-keys": "^1.1.0"
+ },
"engines": {
- "node": ">=4.0"
+ "node": ">=6"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/mysticatea"
+ }
+ },
+ "node_modules/eslint-utils/node_modules/eslint-visitor-keys": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz",
+ "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==",
+ "dev": true,
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/eslint-visitor-keys": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.0.0.tgz",
+ "integrity": "sha512-QudtT6av5WXels9WjIM7qz1XD1cWGvX4gGXvp/zBn9nXG02D0utdU3Em2m/QjTnrsk6bBjmCygl3rmj118msQQ==",
+ "dev": true,
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/espree": {
+ "version": "7.3.1",
+ "resolved": "https://registry.npmjs.org/espree/-/espree-7.3.1.tgz",
+ "integrity": "sha512-v3JCNCE64umkFpmkFGqzVKsOT0tN1Zr+ueqLZfpV1Ob8e+CEgPWa+OxCoGH3tnhimMKIaBm4m/vaRpJ/krRz2g==",
+ "dev": true,
+ "dependencies": {
+ "acorn": "^7.4.0",
+ "acorn-jsx": "^5.3.1",
+ "eslint-visitor-keys": "^1.3.0"
+ },
+ "engines": {
+ "node": "^10.12.0 || >=12.0.0"
+ }
+ },
+ "node_modules/espree/node_modules/eslint-visitor-keys": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz",
+ "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==",
+ "dev": true,
+ "engines": {
+ "node": ">=4"
}
},
"node_modules/esprima": {
@@ -3357,6 +3954,27 @@
"node": ">=4"
}
},
+ "node_modules/esquery": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.4.0.tgz",
+ "integrity": "sha512-cCDispWt5vHHtwMY2YrAQ4ibFkAL8RbH5YGBnZBc90MolvvfkkQcJro/aZiAQUlQ3qgrYS6D6v8Gc5G5CQsc9w==",
+ "dev": true,
+ "dependencies": {
+ "estraverse": "^5.1.0"
+ },
+ "engines": {
+ "node": ">=0.10"
+ }
+ },
+ "node_modules/esquery/node_modules/estraverse": {
+ "version": "5.2.0",
+ "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.2.0.tgz",
+ "integrity": "sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ==",
+ "dev": true,
+ "engines": {
+ "node": ">=4.0"
+ }
+ },
"node_modules/esrecurse": {
"version": "4.3.0",
"resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz",
@@ -3369,7 +3987,7 @@
"node": ">=4.0"
}
},
- "node_modules/estraverse": {
+ "node_modules/esrecurse/node_modules/estraverse": {
"version": "5.2.0",
"resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.2.0.tgz",
"integrity": "sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ==",
@@ -3378,6 +3996,15 @@
"node": ">=4.0"
}
},
+ "node_modules/estraverse": {
+ "version": "4.3.0",
+ "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz",
+ "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==",
+ "dev": true,
+ "engines": {
+ "node": ">=4.0"
+ }
+ },
"node_modules/esutils": {
"version": "2.0.3",
"resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz",
@@ -3397,9 +4024,9 @@
}
},
"node_modules/exec-sh": {
- "version": "0.3.5",
- "resolved": "https://registry.npmjs.org/exec-sh/-/exec-sh-0.3.5.tgz",
- "integrity": "sha512-0hzpaUazv4mEccxdn3TXC+HWNeVXNKMCJRK6E7Xyg+LwGAYI3yFag6jTkd4injV+kChYDQS1ftqDhnDVWNhU8A==",
+ "version": "0.3.6",
+ "resolved": "https://registry.npmjs.org/exec-sh/-/exec-sh-0.3.6.tgz",
+ "integrity": "sha512-nQn+hI3yp+oD0huYhKwvYI32+JFeq+XkNcD1GAo3Y/MjxsfVGmrrzrnzjWiNY6f+pUCP440fThsFh5gZrRAU/w==",
"dev": true
},
"node_modules/execa": {
@@ -3665,6 +4292,7 @@
"integrity": "sha512-GDhU9ntwuKyGXdZBUgTIe+vXnWj0fppUEtMDL0+idd5Sta8TGpHssn/eusA9mrPr9qNDym6SxAYZjNvCn/9RBg==",
"dev": true,
"dependencies": {
+ "@types/yauzl": "^2.9.1",
"debug": "^4.1.1",
"get-stream": "^5.1.0",
"yauzl": "^2.10.0"
@@ -3700,6 +4328,23 @@
"integrity": "sha512-xJuoT5+L99XlZ8twedaRf6Ax2TgQVxvgZOYoPKqZufmJib0tL2tegPBOZb1pVNgIhlqDlA0eO0c3wBvQcmzx4w==",
"dev": true
},
+ "node_modules/fast-glob": {
+ "version": "3.2.5",
+ "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.5.tgz",
+ "integrity": "sha512-2DtFcgT68wiTTiwZ2hNdJfcHNke9XOfnwmBRWXhmeKM8rF0TGwmC/Qto3S7RoZKp5cilZbxzO5iTNTQsJ+EeDg==",
+ "dev": true,
+ "dependencies": {
+ "@nodelib/fs.stat": "^2.0.2",
+ "@nodelib/fs.walk": "^1.2.3",
+ "glob-parent": "^5.1.0",
+ "merge2": "^1.3.0",
+ "micromatch": "^4.0.2",
+ "picomatch": "^2.2.1"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
"node_modules/fast-json-stable-stringify": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz",
@@ -3718,6 +4363,15 @@
"integrity": "sha512-On2N+BpYJ15xIC974QNVuYGMOlEVt4s0EOI3wwMqOmK1fdDY+FN/zltPV8vosq4ad4c/gJ1KHScUn/6AWIgiow==",
"dev": true
},
+ "node_modules/fastq": {
+ "version": "1.11.0",
+ "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.11.0.tgz",
+ "integrity": "sha512-7Eczs8gIPDrVzT+EksYBcupqMyxSHXXrHOLRRxU2/DicV8789MRBRR8+Hc2uWzUupOs4YS4JzBmBxjjCVBxD/g==",
+ "dev": true,
+ "dependencies": {
+ "reusify": "^1.0.4"
+ }
+ },
"node_modules/fb-watchman": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/fb-watchman/-/fb-watchman-2.0.1.tgz",
@@ -3736,6 +4390,18 @@
"pend": "~1.2.0"
}
},
+ "node_modules/file-entry-cache": {
+ "version": "6.0.1",
+ "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz",
+ "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==",
+ "dev": true,
+ "dependencies": {
+ "flat-cache": "^3.0.4"
+ },
+ "engines": {
+ "node": "^10.12.0 || >=12.0.0"
+ }
+ },
"node_modules/file-loader": {
"version": "6.2.0",
"resolved": "https://registry.npmjs.org/file-loader/-/file-loader-6.2.0.tgz",
@@ -3781,6 +4447,25 @@
"node": ">=8"
}
},
+ "node_modules/flat-cache": {
+ "version": "3.0.4",
+ "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz",
+ "integrity": "sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==",
+ "dev": true,
+ "dependencies": {
+ "flatted": "^3.1.0",
+ "rimraf": "^3.0.2"
+ },
+ "engines": {
+ "node": "^10.12.0 || >=12.0.0"
+ }
+ },
+ "node_modules/flatted": {
+ "version": "3.1.1",
+ "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.1.1.tgz",
+ "integrity": "sha512-zAoAQiudy+r5SvnSw3KJy5os/oRJYHzrzja/tBDqrZtNhUw8bt6y8OBzMWcjWr+8liV8Eb6yOhw8WZ7VFZ5ZzA==",
+ "dev": true
+ },
"node_modules/for-in": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz",
@@ -3855,6 +4540,15 @@
"node": ">= 0.12"
}
},
+ "node_modules/fraction.js": {
+ "version": "4.0.13",
+ "resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-4.0.13.tgz",
+ "integrity": "sha512-E1fz2Xs9ltlUp+qbiyx9wmt2n9dRzPsS11Jtdb8D2o+cC7wr9xkkKsVKJuBX0ST+LVS+LhLO+SbLJNtfWcJvXA==",
+ "dev": true,
+ "engines": {
+ "node": "*"
+ }
+ },
"node_modules/fragment-cache": {
"version": "0.2.1",
"resolved": "https://registry.npmjs.org/fragment-cache/-/fragment-cache-0.2.1.tgz",
@@ -3950,6 +4644,12 @@
"url": "https://github.com/sponsors/ljharb"
}
},
+ "node_modules/functional-red-black-tree": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz",
+ "integrity": "sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=",
+ "dev": true
+ },
"node_modules/functions-have-names": {
"version": "1.2.2",
"resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.2.tgz",
@@ -4108,34 +4808,69 @@
"node": "*"
},
"funding": {
- "url": "https://github.com/sponsors/isaacs"
+ "url": "https://github.com/sponsors/isaacs"
+ }
+ },
+ "node_modules/glob-parent": {
+ "version": "5.1.2",
+ "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz",
+ "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==",
+ "dev": true,
+ "dependencies": {
+ "is-glob": "^4.0.1"
+ },
+ "engines": {
+ "node": ">= 6"
+ }
+ },
+ "node_modules/glob-to-regexp": {
+ "version": "0.4.1",
+ "resolved": "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz",
+ "integrity": "sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==",
+ "dev": true
+ },
+ "node_modules/globals": {
+ "version": "13.7.0",
+ "resolved": "https://registry.npmjs.org/globals/-/globals-13.7.0.tgz",
+ "integrity": "sha512-Aipsz6ZKRxa/xQkZhNg0qIWXT6x6rD46f6x/PCnBomlttdIyAPak4YD9jTmKpZ72uROSMU87qJtcgpgHaVchiA==",
+ "dev": true,
+ "dependencies": {
+ "type-fest": "^0.20.2"
+ },
+ "engines": {
+ "node": ">=8"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
}
},
- "node_modules/glob-parent": {
- "version": "5.1.2",
- "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz",
- "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==",
+ "node_modules/globby": {
+ "version": "11.0.3",
+ "resolved": "https://registry.npmjs.org/globby/-/globby-11.0.3.tgz",
+ "integrity": "sha512-ffdmosjA807y7+lA1NM0jELARVmYul/715xiILEjo3hBLPTcirgQNnXECn5g3mtR8TOLCVbkfua1Hpen25/Xcg==",
"dev": true,
"dependencies": {
- "is-glob": "^4.0.1"
+ "array-union": "^2.1.0",
+ "dir-glob": "^3.0.1",
+ "fast-glob": "^3.1.1",
+ "ignore": "^5.1.4",
+ "merge2": "^1.3.0",
+ "slash": "^3.0.0"
},
"engines": {
- "node": ">= 6"
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
}
},
- "node_modules/glob-to-regexp": {
- "version": "0.4.1",
- "resolved": "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz",
- "integrity": "sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==",
- "dev": true
- },
- "node_modules/globals": {
- "version": "11.12.0",
- "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz",
- "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==",
+ "node_modules/globby/node_modules/ignore": {
+ "version": "5.1.8",
+ "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.1.8.tgz",
+ "integrity": "sha512-BMpfD7PpiETpBl/A6S498BaIJ6Y/ABT93ETbby2fP00v4EbvPBXWEoaR1UBPKs3iR53pJY7EtZk5KACI57i1Uw==",
"dev": true,
"engines": {
- "node": ">=4"
+ "node": ">= 4"
}
},
"node_modules/globule": {
@@ -4472,6 +5207,15 @@
}
]
},
+ "node_modules/ignore": {
+ "version": "4.0.6",
+ "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz",
+ "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==",
+ "dev": true,
+ "engines": {
+ "node": ">= 4"
+ }
+ },
"node_modules/import-fresh": {
"version": "3.3.0",
"resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz",
@@ -4547,6 +5291,20 @@
"integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==",
"dev": true
},
+ "node_modules/internal-slot": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.3.tgz",
+ "integrity": "sha512-O0DB1JC/sPyZl7cIo78n5dR7eUSwwpYPiXRhTzNxZVAMUuB8vlnRFyLxdrVToks6XPLVnFfbzaVd5WLjhgg+vA==",
+ "dev": true,
+ "dependencies": {
+ "get-intrinsic": "^1.1.0",
+ "has": "^1.0.3",
+ "side-channel": "^1.0.4"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
"node_modules/interpret": {
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/interpret/-/interpret-2.2.0.tgz",
@@ -5209,6 +5967,7 @@
"@types/node": "*",
"anymatch": "^3.0.3",
"fb-watchman": "^2.0.0",
+ "fsevents": "^2.1.2",
"graceful-fs": "^4.2.4",
"jest-regex-util": "^26.0.0",
"jest-serializer": "^26.6.2",
@@ -5627,6 +6386,18 @@
}
}
},
+ "node_modules/jsdom/node_modules/acorn": {
+ "version": "8.1.0",
+ "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.1.0.tgz",
+ "integrity": "sha512-LWCF/Wn0nfHOmJ9rzQApGnxnvgfROzGilS8936rqN/lfcYkY9MYZzdMqN+2NJ4SlTc+m5HiSa+kNfDtI64dwUA==",
+ "dev": true,
+ "bin": {
+ "acorn": "bin/acorn"
+ },
+ "engines": {
+ "node": ">=0.4.0"
+ }
+ },
"node_modules/jsesc": {
"version": "2.5.2",
"resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz",
@@ -5663,6 +6434,12 @@
"integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==",
"dev": true
},
+ "node_modules/json-stable-stringify-without-jsonify": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz",
+ "integrity": "sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=",
+ "dev": true
+ },
"node_modules/json-stringify-safe": {
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz",
@@ -5690,6 +6467,7 @@
"integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==",
"dev": true,
"dependencies": {
+ "graceful-fs": "^4.1.6",
"universalify": "^2.0.0"
},
"optionalDependencies": {
@@ -5711,6 +6489,19 @@
"verror": "1.10.0"
}
},
+ "node_modules/jsx-ast-utils": {
+ "version": "3.2.0",
+ "resolved": "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-3.2.0.tgz",
+ "integrity": "sha512-EIsmt3O3ljsU6sot/J4E1zDRxfBNrhjyf/OKjlydwgEimQuznlM4Wv7U+ueONJMyEn1WRE0K8dhi3dVAXYT24Q==",
+ "dev": true,
+ "dependencies": {
+ "array-includes": "^3.1.2",
+ "object.assign": "^4.1.2"
+ },
+ "engines": {
+ "node": ">=4.0"
+ }
+ },
"node_modules/kind-of": {
"version": "6.0.3",
"resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz",
@@ -5748,13 +6539,13 @@
}
},
"node_modules/levn": {
- "version": "0.3.0",
- "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz",
- "integrity": "sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4=",
+ "version": "0.4.1",
+ "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz",
+ "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==",
"dev": true,
"dependencies": {
- "prelude-ls": "~1.1.2",
- "type-check": "~0.3.2"
+ "prelude-ls": "^1.2.1",
+ "type-check": "~0.4.0"
},
"engines": {
"node": ">= 0.8.0"
@@ -5865,12 +6656,6 @@
"integrity": "sha1-QVxEePK8wwEgwizhDtMib30+GOA=",
"dev": true
},
- "node_modules/lodash.sortby": {
- "version": "4.7.0",
- "resolved": "https://registry.npmjs.org/lodash.sortby/-/lodash.sortby-4.7.0.tgz",
- "integrity": "sha1-7dFMgk4sycHgsKG0K7UhBRakJDg=",
- "dev": true
- },
"node_modules/loose-envify": {
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz",
@@ -6105,6 +6890,15 @@
"integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==",
"dev": true
},
+ "node_modules/merge2": {
+ "version": "1.4.1",
+ "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz",
+ "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==",
+ "dev": true,
+ "engines": {
+ "node": ">= 8"
+ }
+ },
"node_modules/micromatch": {
"version": "4.0.2",
"resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.2.tgz",
@@ -6556,6 +7350,15 @@
"node": ">=0.10.0"
}
},
+ "node_modules/normalize-range": {
+ "version": "0.1.2",
+ "resolved": "https://registry.npmjs.org/normalize-range/-/normalize-range-0.1.2.tgz",
+ "integrity": "sha1-LRDAa9/TEuqXd2laTShDlFa3WUI=",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
"node_modules/npm-run-path": {
"version": "4.0.1",
"resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz",
@@ -6870,17 +7673,17 @@
}
},
"node_modules/optionator": {
- "version": "0.8.3",
- "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.3.tgz",
- "integrity": "sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA==",
+ "version": "0.9.1",
+ "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz",
+ "integrity": "sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==",
"dev": true,
"dependencies": {
- "deep-is": "~0.1.3",
- "fast-levenshtein": "~2.0.6",
- "levn": "~0.3.0",
- "prelude-ls": "~1.1.2",
- "type-check": "~0.3.2",
- "word-wrap": "~1.2.3"
+ "deep-is": "^0.1.3",
+ "fast-levenshtein": "^2.0.6",
+ "levn": "^0.4.1",
+ "prelude-ls": "^1.2.1",
+ "type-check": "^0.4.0",
+ "word-wrap": "^1.2.3"
},
"engines": {
"node": ">= 0.8.0"
@@ -7225,9 +8028,9 @@
"dev": true
},
"node_modules/prelude-ls": {
- "version": "1.1.2",
- "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz",
- "integrity": "sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ=",
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz",
+ "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==",
"dev": true,
"engines": {
"node": ">= 0.8.0"
@@ -7245,6 +8048,18 @@
"node": ">=10.13.0"
}
},
+ "node_modules/prettier-linter-helpers": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/prettier-linter-helpers/-/prettier-linter-helpers-1.0.0.tgz",
+ "integrity": "sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w==",
+ "dev": true,
+ "dependencies": {
+ "fast-diff": "^1.1.2"
+ },
+ "engines": {
+ "node": ">=6.0.0"
+ }
+ },
"node_modules/pretty-format": {
"version": "26.6.2",
"resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-26.6.2.tgz",
@@ -7386,6 +8201,26 @@
"node": ">=0.6"
}
},
+ "node_modules/queue-microtask": {
+ "version": "1.2.3",
+ "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz",
+ "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==",
+ "dev": true,
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/feross"
+ },
+ {
+ "type": "patreon",
+ "url": "https://www.patreon.com/feross"
+ },
+ {
+ "type": "consulting",
+ "url": "https://feross.org/support"
+ }
+ ]
+ },
"node_modules/raf": {
"version": "3.4.1",
"resolved": "https://registry.npmjs.org/raf/-/raf-3.4.1.tgz",
@@ -7650,6 +8485,34 @@
"node": ">=0.10.0"
}
},
+ "node_modules/regexp.prototype.flags": {
+ "version": "1.3.1",
+ "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.3.1.tgz",
+ "integrity": "sha512-JiBdRBq91WlY7uRJ0ds7R+dU02i6LKi8r3BuQhNXn+kmeLN+EfHhfjqMRis1zJxnlu88hq/4dx0P2OP3APRTOA==",
+ "dev": true,
+ "dependencies": {
+ "call-bind": "^1.0.2",
+ "define-properties": "^1.1.3"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/regexpp": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.1.0.tgz",
+ "integrity": "sha512-ZOIzd8yVsQQA7j8GCSlPGXwg5PfmA1mrq0JP4nGhh54LaKN3xdai/vHUDu74pKwV8OxseMS65u2NImosQcSD0Q==",
+ "dev": true,
+ "engines": {
+ "node": ">=8"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/mysticatea"
+ }
+ },
"node_modules/remove-trailing-separator": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz",
@@ -7795,6 +8658,15 @@
"node": ">=0.10.0"
}
},
+ "node_modules/require-from-string": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz",
+ "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
"node_modules/require-main-filename": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz",
@@ -7860,6 +8732,16 @@
"node": ">=0.12"
}
},
+ "node_modules/reusify": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz",
+ "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==",
+ "dev": true,
+ "engines": {
+ "iojs": ">=1.0.0",
+ "node": ">=0.10.0"
+ }
+ },
"node_modules/rimraf": {
"version": "3.0.2",
"resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz",
@@ -7894,6 +8776,29 @@
"node": "6.* || >= 7.*"
}
},
+ "node_modules/run-parallel": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz",
+ "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==",
+ "dev": true,
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/feross"
+ },
+ {
+ "type": "patreon",
+ "url": "https://www.patreon.com/feross"
+ },
+ {
+ "type": "consulting",
+ "url": "https://feross.org/support"
+ }
+ ],
+ "dependencies": {
+ "queue-microtask": "^1.2.2"
+ }
+ },
"node_modules/safe-buffer": {
"version": "5.1.2",
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
@@ -8609,6 +9514,20 @@
"dev": true,
"optional": true
},
+ "node_modules/side-channel": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz",
+ "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==",
+ "dev": true,
+ "dependencies": {
+ "call-bind": "^1.0.0",
+ "get-intrinsic": "^1.0.2",
+ "object-inspect": "^1.9.0"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
"node_modules/signal-exit": {
"version": "3.0.3",
"resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.3.tgz",
@@ -8644,6 +9563,32 @@
"node": ">=8"
}
},
+ "node_modules/slice-ansi": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-4.0.0.tgz",
+ "integrity": "sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ==",
+ "dev": true,
+ "dependencies": {
+ "ansi-styles": "^4.0.0",
+ "astral-regex": "^2.0.0",
+ "is-fullwidth-code-point": "^3.0.0"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/slice-ansi?sponsor=1"
+ }
+ },
+ "node_modules/slice-ansi/node_modules/is-fullwidth-code-point": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
+ "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==",
+ "dev": true,
+ "engines": {
+ "node": ">=8"
+ }
+ },
"node_modules/snapdragon": {
"version": "0.8.2",
"resolved": "https://registry.npmjs.org/snapdragon/-/snapdragon-0.8.2.tgz",
@@ -9143,6 +10088,24 @@
"node": ">=0.10.0"
}
},
+ "node_modules/string.prototype.matchall": {
+ "version": "4.0.4",
+ "resolved": "https://registry.npmjs.org/string.prototype.matchall/-/string.prototype.matchall-4.0.4.tgz",
+ "integrity": "sha512-pknFIWVachNcyqRfaQSeu/FUfpvJTe4uskUSZ9Wc1RijsPuzbZ8TyYT8WCNnntCjUEqQ3vUHMAfVj2+wLAisPQ==",
+ "dev": true,
+ "dependencies": {
+ "call-bind": "^1.0.2",
+ "define-properties": "^1.1.3",
+ "es-abstract": "^1.18.0-next.2",
+ "has-symbols": "^1.0.1",
+ "internal-slot": "^1.0.3",
+ "regexp.prototype.flags": "^1.3.1",
+ "side-channel": "^1.0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
"node_modules/string.prototype.trim": {
"version": "1.2.4",
"resolved": "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.2.4.tgz",
@@ -9240,37 +10203,109 @@
"node": ">=0.10.0"
}
},
+ "node_modules/strip-json-comments": {
+ "version": "3.1.1",
+ "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz",
+ "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==",
+ "dev": true,
+ "engines": {
+ "node": ">=8"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
"node_modules/supports-color": {
"version": "7.2.0",
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
"integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
"dev": true,
"dependencies": {
- "has-flag": "^4.0.0"
+ "has-flag": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/supports-hyperlinks": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/supports-hyperlinks/-/supports-hyperlinks-2.1.0.tgz",
+ "integrity": "sha512-zoE5/e+dnEijk6ASB6/qrK+oYdm2do1hjoLWrqUC/8WEIW1gbxFcKuBof7sW8ArN6e+AYvsE8HBGiVRWL/F5CA==",
+ "dev": true,
+ "dependencies": {
+ "has-flag": "^4.0.0",
+ "supports-color": "^7.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/symbol-tree": {
+ "version": "3.2.4",
+ "resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.4.tgz",
+ "integrity": "sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==",
+ "dev": true
+ },
+ "node_modules/table": {
+ "version": "6.0.7",
+ "resolved": "https://registry.npmjs.org/table/-/table-6.0.7.tgz",
+ "integrity": "sha512-rxZevLGTUzWna/qBLObOe16kB2RTnnbhciwgPbMMlazz1yZGVEgnZK762xyVdVznhqxrfCeBMmMkgOOaPwjH7g==",
+ "dev": true,
+ "dependencies": {
+ "ajv": "^7.0.2",
+ "lodash": "^4.17.20",
+ "slice-ansi": "^4.0.0",
+ "string-width": "^4.2.0"
+ },
+ "engines": {
+ "node": ">=10.0.0"
+ }
+ },
+ "node_modules/table/node_modules/ajv": {
+ "version": "7.2.3",
+ "resolved": "https://registry.npmjs.org/ajv/-/ajv-7.2.3.tgz",
+ "integrity": "sha512-idv5WZvKVXDqKralOImQgPM9v6WOdLNa0IY3B3doOjw/YxRGT8I+allIJ6kd7Uaj+SF1xZUSU+nPM5aDNBVtnw==",
+ "dev": true,
+ "dependencies": {
+ "fast-deep-equal": "^3.1.1",
+ "json-schema-traverse": "^1.0.0",
+ "require-from-string": "^2.0.2",
+ "uri-js": "^4.2.2"
},
+ "funding": {
+ "type": "github",
+ "url": "https://github.com/sponsors/epoberezkin"
+ }
+ },
+ "node_modules/table/node_modules/is-fullwidth-code-point": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
+ "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==",
+ "dev": true,
"engines": {
"node": ">=8"
}
},
- "node_modules/supports-hyperlinks": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/supports-hyperlinks/-/supports-hyperlinks-2.1.0.tgz",
- "integrity": "sha512-zoE5/e+dnEijk6ASB6/qrK+oYdm2do1hjoLWrqUC/8WEIW1gbxFcKuBof7sW8ArN6e+AYvsE8HBGiVRWL/F5CA==",
+ "node_modules/table/node_modules/json-schema-traverse": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz",
+ "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==",
+ "dev": true
+ },
+ "node_modules/table/node_modules/string-width": {
+ "version": "4.2.2",
+ "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.2.tgz",
+ "integrity": "sha512-XBJbT3N4JhVumXE0eoLU9DCjcaF92KLNqTmFCnG1pf8duUxFGwtP6AD6nkjw9a3IdiRtL3E2w3JDiE/xi3vOeA==",
"dev": true,
"dependencies": {
- "has-flag": "^4.0.0",
- "supports-color": "^7.0.0"
+ "emoji-regex": "^8.0.0",
+ "is-fullwidth-code-point": "^3.0.0",
+ "strip-ansi": "^6.0.0"
},
"engines": {
"node": ">=8"
}
},
- "node_modules/symbol-tree": {
- "version": "3.2.4",
- "resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.4.tgz",
- "integrity": "sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==",
- "dev": true
- },
"node_modules/tapable": {
"version": "1.1.3",
"resolved": "https://registry.npmjs.org/tapable/-/tapable-1.1.3.tgz",
@@ -9452,6 +10487,12 @@
"node": ">=8"
}
},
+ "node_modules/text-table": {
+ "version": "0.2.0",
+ "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz",
+ "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=",
+ "dev": true
+ },
"node_modules/throat": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/throat/-/throat-5.0.0.tgz",
@@ -9662,94 +10703,7 @@
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.1.0.tgz",
"integrity": "sha512-hcVC3wYEziELGGmEEXue7D75zbwIIVUMWAVbHItGPx0ziyXxrOMQx4rQEVEV45Ut/1IotuEvwqPopzIOkDMf0A=="
},
- "node_modules/tslint": {
- "version": "6.1.3",
- "resolved": "https://registry.npmjs.org/tslint/-/tslint-6.1.3.tgz",
- "integrity": "sha512-IbR4nkT96EQOvKE2PW/djGz8iGNeJ4rF2mBfiYaR/nvUWYKJhLwimoJKgjIFEIDibBtOevj7BqCRL4oHeWWUCg==",
- "deprecated": "TSLint has been deprecated in favor of ESLint. Please see https://github.com/palantir/tslint/issues/4534 for more information.",
- "dev": true,
- "dependencies": {
- "@babel/code-frame": "^7.0.0",
- "builtin-modules": "^1.1.1",
- "chalk": "^2.3.0",
- "commander": "^2.12.1",
- "diff": "^4.0.1",
- "glob": "^7.1.1",
- "js-yaml": "^3.13.1",
- "minimatch": "^3.0.4",
- "mkdirp": "^0.5.3",
- "resolve": "^1.3.2",
- "semver": "^5.3.0",
- "tslib": "^1.13.0",
- "tsutils": "^2.29.0"
- },
- "bin": {
- "tslint": "bin/tslint"
- },
- "engines": {
- "node": ">=4.8.0"
- },
- "peerDependencies": {
- "typescript": ">=2.3.0-dev || >=2.4.0-dev || >=2.5.0-dev || >=2.6.0-dev || >=2.7.0-dev || >=2.8.0-dev || >=2.9.0-dev || >=3.0.0-dev || >= 3.1.0-dev || >= 3.2.0-dev || >= 4.0.0-dev"
- }
- },
- "node_modules/tslint-config-prettier": {
- "version": "1.18.0",
- "resolved": "https://registry.npmjs.org/tslint-config-prettier/-/tslint-config-prettier-1.18.0.tgz",
- "integrity": "sha512-xPw9PgNPLG3iKRxmK7DWr+Ea/SzrvfHtjFt5LBl61gk2UBG/DB9kCXRjv+xyIU1rUtnayLeMUVJBcMX8Z17nDg==",
- "dev": true,
- "bin": {
- "tslint-config-prettier-check": "bin/check.js"
- },
- "engines": {
- "node": ">=4.0.0"
- }
- },
- "node_modules/tslint-plugin-prettier": {
- "version": "2.3.0",
- "resolved": "https://registry.npmjs.org/tslint-plugin-prettier/-/tslint-plugin-prettier-2.3.0.tgz",
- "integrity": "sha512-F9e4K03yc9xuvv+A0v1EmjcnDwpz8SpCD8HzqSDe0eyg34cBinwn9JjmnnRrNAs4HdleRQj7qijp+P/JTxt4vA==",
- "dev": true,
- "dependencies": {
- "eslint-plugin-prettier": "^2.2.0",
- "lines-and-columns": "^1.1.6",
- "tslib": "^1.7.1"
- },
- "engines": {
- "node": ">= 4"
- },
- "peerDependencies": {
- "prettier": "^1.9.0 || ^2.0.0",
- "tslint": "^5.0.0 || ^6.0.0"
- }
- },
- "node_modules/tslint-plugin-prettier/node_modules/tslib": {
- "version": "1.14.1",
- "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz",
- "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==",
- "dev": true
- },
- "node_modules/tslint-react": {
- "version": "5.0.0",
- "resolved": "https://registry.npmjs.org/tslint-react/-/tslint-react-5.0.0.tgz",
- "integrity": "sha512-/IbcSmoBPlFic8kQaRfQ4knTY4mivwo5LVzvozvX6Dyu2ynEnrh1dIcR2ujjyp/IodXqY/H5GbxFxSMo/Kf2Hg==",
- "deprecated": "tslint-react is deprecated along with TSLint",
- "dev": true,
- "dependencies": {
- "tsutils": "^3.17.1"
- },
- "peerDependencies": {
- "tslint": "^6.0.0",
- "typescript": ">=3.4.1"
- }
- },
- "node_modules/tslint-react/node_modules/tslib": {
- "version": "1.14.1",
- "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz",
- "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==",
- "dev": true
- },
- "node_modules/tslint-react/node_modules/tsutils": {
+ "node_modules/tsutils": {
"version": "3.21.0",
"resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.21.0.tgz",
"integrity": "sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==",
@@ -9764,104 +10718,6 @@
"typescript": ">=2.8.0 || >= 3.2.0-dev || >= 3.3.0-dev || >= 3.4.0-dev || >= 3.5.0-dev || >= 3.6.0-dev || >= 3.6.0-beta || >= 3.7.0-dev || >= 3.7.0-beta"
}
},
- "node_modules/tslint/node_modules/ansi-styles": {
- "version": "3.2.1",
- "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz",
- "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==",
- "dev": true,
- "dependencies": {
- "color-convert": "^1.9.0"
- },
- "engines": {
- "node": ">=4"
- }
- },
- "node_modules/tslint/node_modules/chalk": {
- "version": "2.4.2",
- "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
- "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
- "dev": true,
- "dependencies": {
- "ansi-styles": "^3.2.1",
- "escape-string-regexp": "^1.0.5",
- "supports-color": "^5.3.0"
- },
- "engines": {
- "node": ">=4"
- }
- },
- "node_modules/tslint/node_modules/color-convert": {
- "version": "1.9.3",
- "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
- "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==",
- "dev": true,
- "dependencies": {
- "color-name": "1.1.3"
- }
- },
- "node_modules/tslint/node_modules/color-name": {
- "version": "1.1.3",
- "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
- "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=",
- "dev": true
- },
- "node_modules/tslint/node_modules/escape-string-regexp": {
- "version": "1.0.5",
- "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
- "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=",
- "dev": true,
- "engines": {
- "node": ">=0.8.0"
- }
- },
- "node_modules/tslint/node_modules/has-flag": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
- "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=",
- "dev": true,
- "engines": {
- "node": ">=4"
- }
- },
- "node_modules/tslint/node_modules/semver": {
- "version": "5.7.1",
- "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz",
- "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==",
- "dev": true,
- "bin": {
- "semver": "bin/semver"
- }
- },
- "node_modules/tslint/node_modules/supports-color": {
- "version": "5.5.0",
- "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
- "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
- "dev": true,
- "dependencies": {
- "has-flag": "^3.0.0"
- },
- "engines": {
- "node": ">=4"
- }
- },
- "node_modules/tslint/node_modules/tslib": {
- "version": "1.14.1",
- "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz",
- "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==",
- "dev": true
- },
- "node_modules/tsutils": {
- "version": "2.29.0",
- "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-2.29.0.tgz",
- "integrity": "sha512-g5JVHCIJwzfISaXpXE1qvNalca5Jwob6FjI4AoPlqMusJ6ftFE7IkkFoMhVLRgK+4Kx3gkzb8UZK5t5yTTvEmA==",
- "dev": true,
- "dependencies": {
- "tslib": "^1.8.1"
- },
- "peerDependencies": {
- "typescript": ">=2.1.0 || >=2.1.0-dev || >=2.2.0-dev || >=2.3.0-dev || >=2.4.0-dev || >=2.5.0-dev || >=2.6.0-dev || >=2.7.0-dev || >=2.8.0-dev || >=2.9.0-dev || >= 3.0.0-dev || >= 3.1.0-dev"
- }
- },
"node_modules/tsutils/node_modules/tslib": {
"version": "1.14.1",
"resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz",
@@ -9887,12 +10743,12 @@
"dev": true
},
"node_modules/type-check": {
- "version": "0.3.2",
- "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz",
- "integrity": "sha1-WITKtRLPHTVeP7eE8wgEsrUg23I=",
+ "version": "0.4.0",
+ "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz",
+ "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==",
"dev": true,
"dependencies": {
- "prelude-ls": "~1.1.2"
+ "prelude-ls": "^1.2.1"
},
"engines": {
"node": ">= 0.8.0"
@@ -9908,12 +10764,12 @@
}
},
"node_modules/type-fest": {
- "version": "0.11.0",
- "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.11.0.tgz",
- "integrity": "sha512-OdjXJxnCN1AvyLSzeKIgXTXxV+99ZuXl3Hpo9XpJAv9MBcHrrJOQ5kV7ypXOuQie+AmWG25hLbiKdwYTifzcfQ==",
+ "version": "0.20.2",
+ "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz",
+ "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==",
"dev": true,
"engines": {
- "node": ">=8"
+ "node": ">=10"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
@@ -10305,6 +11161,18 @@
"node": ">= 10.13.0"
}
},
+ "node_modules/webpack-bundle-analyzer/node_modules/acorn": {
+ "version": "8.1.0",
+ "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.1.0.tgz",
+ "integrity": "sha512-LWCF/Wn0nfHOmJ9rzQApGnxnvgfROzGilS8936rqN/lfcYkY9MYZzdMqN+2NJ4SlTc+m5HiSa+kNfDtI64dwUA==",
+ "dev": true,
+ "bin": {
+ "acorn": "bin/acorn"
+ },
+ "engines": {
+ "node": ">=0.4.0"
+ }
+ },
"node_modules/webpack-bundle-analyzer/node_modules/acorn-walk": {
"version": "8.0.2",
"resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.0.2.tgz",
@@ -10447,6 +11315,18 @@
"source-map": "~0.6.1"
}
},
+ "node_modules/webpack/node_modules/acorn": {
+ "version": "8.1.0",
+ "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.1.0.tgz",
+ "integrity": "sha512-LWCF/Wn0nfHOmJ9rzQApGnxnvgfROzGilS8936rqN/lfcYkY9MYZzdMqN+2NJ4SlTc+m5HiSa+kNfDtI64dwUA==",
+ "dev": true,
+ "bin": {
+ "acorn": "bin/acorn"
+ },
+ "engines": {
+ "node": ">=0.4.0"
+ }
+ },
"node_modules/webpack/node_modules/enhanced-resolve": {
"version": "5.7.0",
"resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.7.0.tgz",
@@ -10498,12 +11378,12 @@
"dev": true
},
"node_modules/whatwg-url": {
- "version": "8.4.0",
- "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-8.4.0.tgz",
- "integrity": "sha512-vwTUFf6V4zhcPkWp/4CQPr1TW9Ml6SF4lVyaIMBdJw5i6qUUJ1QWM4Z6YYVkfka0OUIzVo/0aNtGVGk256IKWw==",
+ "version": "8.5.0",
+ "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-8.5.0.tgz",
+ "integrity": "sha512-fy+R77xWv0AiqfLl4nuGUlQ3/6b5uNfQ4WAbGQVMYshCTCCPK9psC1nWh3XHuxGVCtlcDDQPQW1csmmIQo+fwg==",
"dev": true,
"dependencies": {
- "lodash.sortby": "^4.7.0",
+ "lodash": "^4.7.0",
"tr46": "^2.0.2",
"webidl-conversions": "^6.1.0"
},
@@ -10782,12 +11662,12 @@
},
"dependencies": {
"@babel/code-frame": {
- "version": "7.12.13",
- "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.12.13.tgz",
- "integrity": "sha512-HV1Cm0Q3ZrpCR93tkWOYiuYIgLxZXZFVG2VgK+MBWjUqZTundupbfx2aXarXuw5Ko5aMcjtJgbSs4vUGBS5v6g==",
+ "version": "7.12.11",
+ "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.12.11.tgz",
+ "integrity": "sha512-Zt1yodBx1UcyiePMSkWnU4hPqhwq7hGi2nFL1LeA3EUl+q2LQx16MISgJ0+z7dnmgvP9QtIleuETGOiOH1RcIw==",
"dev": true,
"requires": {
- "@babel/highlight": "^7.12.13"
+ "@babel/highlight": "^7.10.4"
}
},
"@babel/compat-data": {
@@ -10820,6 +11700,15 @@
"source-map": "^0.5.0"
},
"dependencies": {
+ "@babel/code-frame": {
+ "version": "7.12.13",
+ "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.12.13.tgz",
+ "integrity": "sha512-HV1Cm0Q3ZrpCR93tkWOYiuYIgLxZXZFVG2VgK+MBWjUqZTundupbfx2aXarXuw5Ko5aMcjtJgbSs4vUGBS5v6g==",
+ "dev": true,
+ "requires": {
+ "@babel/highlight": "^7.12.13"
+ }
+ },
"semver": {
"version": "6.3.0",
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
@@ -11195,6 +12084,17 @@
"@babel/code-frame": "^7.12.13",
"@babel/parser": "^7.12.13",
"@babel/types": "^7.12.13"
+ },
+ "dependencies": {
+ "@babel/code-frame": {
+ "version": "7.12.13",
+ "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.12.13.tgz",
+ "integrity": "sha512-HV1Cm0Q3ZrpCR93tkWOYiuYIgLxZXZFVG2VgK+MBWjUqZTundupbfx2aXarXuw5Ko5aMcjtJgbSs4vUGBS5v6g==",
+ "dev": true,
+ "requires": {
+ "@babel/highlight": "^7.12.13"
+ }
+ }
}
},
"@babel/traverse": {
@@ -11212,6 +12112,23 @@
"debug": "^4.1.0",
"globals": "^11.1.0",
"lodash": "^4.17.19"
+ },
+ "dependencies": {
+ "@babel/code-frame": {
+ "version": "7.12.13",
+ "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.12.13.tgz",
+ "integrity": "sha512-HV1Cm0Q3ZrpCR93tkWOYiuYIgLxZXZFVG2VgK+MBWjUqZTundupbfx2aXarXuw5Ko5aMcjtJgbSs4vUGBS5v6g==",
+ "dev": true,
+ "requires": {
+ "@babel/highlight": "^7.12.13"
+ }
+ },
+ "globals": {
+ "version": "11.12.0",
+ "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz",
+ "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==",
+ "dev": true
+ }
}
},
"@babel/types": {
@@ -11247,6 +12164,40 @@
"integrity": "sha512-HyYEUDeIj5rRQU2Hk5HTB2uHsbRQpF70nvMhVzi+VJR0X+xNEhjPui4/kBf3VeH/wqD28PT4sVOm8qqLjBrSZg==",
"dev": true
},
+ "@eslint/eslintrc": {
+ "version": "0.4.0",
+ "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-0.4.0.tgz",
+ "integrity": "sha512-2ZPCc+uNbjV5ERJr+aKSPRwZgKd2z11x0EgLvb1PURmUrn9QNRXFqje0Ldq454PfAVyaJYyrDvvIKSFP4NnBog==",
+ "dev": true,
+ "requires": {
+ "ajv": "^6.12.4",
+ "debug": "^4.1.1",
+ "espree": "^7.3.0",
+ "globals": "^12.1.0",
+ "ignore": "^4.0.6",
+ "import-fresh": "^3.2.1",
+ "js-yaml": "^3.13.1",
+ "minimatch": "^3.0.4",
+ "strip-json-comments": "^3.1.1"
+ },
+ "dependencies": {
+ "globals": {
+ "version": "12.4.0",
+ "resolved": "https://registry.npmjs.org/globals/-/globals-12.4.0.tgz",
+ "integrity": "sha512-BWICuzzDvDoH54NHKCseDanAhE3CeDorgDL5MT6LMXXj2WCnd9UC2szdk4AWLfjdgNBCXLUanXYcpBBKOSWGwg==",
+ "dev": true,
+ "requires": {
+ "type-fest": "^0.8.1"
+ }
+ },
+ "type-fest": {
+ "version": "0.8.1",
+ "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz",
+ "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==",
+ "dev": true
+ }
+ }
+ },
"@istanbuljs/load-nyc-config": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz",
@@ -11472,6 +12423,32 @@
"chalk": "^4.0.0"
}
},
+ "@nodelib/fs.scandir": {
+ "version": "2.1.4",
+ "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.4.tgz",
+ "integrity": "sha512-33g3pMJk3bg5nXbL/+CY6I2eJDzZAni49PfJnL5fghPTggPvBd/pFNSgJsdAgWptuFu7qq/ERvOYFlhvsLTCKA==",
+ "dev": true,
+ "requires": {
+ "@nodelib/fs.stat": "2.0.4",
+ "run-parallel": "^1.1.9"
+ }
+ },
+ "@nodelib/fs.stat": {
+ "version": "2.0.4",
+ "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.4.tgz",
+ "integrity": "sha512-IYlHJA0clt2+Vg7bccq+TzRdJvv19c2INqBSsoOLp1je7xjtr7J26+WXR72MCdvU9q1qTzIWDfhMf+DRvQJK4Q==",
+ "dev": true
+ },
+ "@nodelib/fs.walk": {
+ "version": "1.2.6",
+ "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.6.tgz",
+ "integrity": "sha512-8Broas6vTtW4GIXTAHDoE32hnN2M5ykgCpWGbuXHQ15vEMqr23pB76e/GZcYsZCHALv50ktd24qhEyKr6wBtow==",
+ "dev": true,
+ "requires": {
+ "@nodelib/fs.scandir": "2.1.4",
+ "fastq": "^1.6.0"
+ }
+ },
"@polka/url": {
"version": "1.0.0-next.11",
"resolved": "https://registry.npmjs.org/@polka/url/-/url-1.0.0-next.11.tgz",
@@ -11780,6 +12757,89 @@
"@types/node": "*"
}
},
+ "@typescript-eslint/eslint-plugin": {
+ "version": "4.18.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-4.18.0.tgz",
+ "integrity": "sha512-Lzkc/2+7EoH7+NjIWLS2lVuKKqbEmJhtXe3rmfA8cyiKnZm3IfLf51irnBcmow8Q/AptVV0XBZmBJKuUJTe6cQ==",
+ "dev": true,
+ "requires": {
+ "@typescript-eslint/experimental-utils": "4.18.0",
+ "@typescript-eslint/scope-manager": "4.18.0",
+ "debug": "^4.1.1",
+ "functional-red-black-tree": "^1.0.1",
+ "lodash": "^4.17.15",
+ "regexpp": "^3.0.0",
+ "semver": "^7.3.2",
+ "tsutils": "^3.17.1"
+ }
+ },
+ "@typescript-eslint/experimental-utils": {
+ "version": "4.18.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-4.18.0.tgz",
+ "integrity": "sha512-92h723Kblt9JcT2RRY3QS2xefFKar4ZQFVs3GityOKWQYgtajxt/tuXIzL7sVCUlM1hgreiV5gkGYyBpdOwO6A==",
+ "dev": true,
+ "requires": {
+ "@types/json-schema": "^7.0.3",
+ "@typescript-eslint/scope-manager": "4.18.0",
+ "@typescript-eslint/types": "4.18.0",
+ "@typescript-eslint/typescript-estree": "4.18.0",
+ "eslint-scope": "^5.0.0",
+ "eslint-utils": "^2.0.0"
+ }
+ },
+ "@typescript-eslint/parser": {
+ "version": "4.18.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-4.18.0.tgz",
+ "integrity": "sha512-W3z5S0ZbecwX3PhJEAnq4mnjK5JJXvXUDBYIYGoweCyWyuvAKfGHvzmpUzgB5L4cRBb+cTu9U/ro66dx7dIimA==",
+ "dev": true,
+ "requires": {
+ "@typescript-eslint/scope-manager": "4.18.0",
+ "@typescript-eslint/types": "4.18.0",
+ "@typescript-eslint/typescript-estree": "4.18.0",
+ "debug": "^4.1.1"
+ }
+ },
+ "@typescript-eslint/scope-manager": {
+ "version": "4.18.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-4.18.0.tgz",
+ "integrity": "sha512-olX4yN6rvHR2eyFOcb6E4vmhDPsfdMyfQ3qR+oQNkAv8emKKlfxTWUXU5Mqxs2Fwe3Pf1BoPvrwZtwngxDzYzQ==",
+ "dev": true,
+ "requires": {
+ "@typescript-eslint/types": "4.18.0",
+ "@typescript-eslint/visitor-keys": "4.18.0"
+ }
+ },
+ "@typescript-eslint/types": {
+ "version": "4.18.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-4.18.0.tgz",
+ "integrity": "sha512-/BRociARpj5E+9yQ7cwCF/SNOWwXJ3qhjurMuK2hIFUbr9vTuDeu476Zpu+ptxY2kSxUHDGLLKy+qGq2sOg37A==",
+ "dev": true
+ },
+ "@typescript-eslint/typescript-estree": {
+ "version": "4.18.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-4.18.0.tgz",
+ "integrity": "sha512-wt4xvF6vvJI7epz+rEqxmoNQ4ZADArGQO9gDU+cM0U5fdVv7N+IAuVoVAoZSOZxzGHBfvE3XQMLdy+scsqFfeg==",
+ "dev": true,
+ "requires": {
+ "@typescript-eslint/types": "4.18.0",
+ "@typescript-eslint/visitor-keys": "4.18.0",
+ "debug": "^4.1.1",
+ "globby": "^11.0.1",
+ "is-glob": "^4.0.1",
+ "semver": "^7.3.2",
+ "tsutils": "^3.17.1"
+ }
+ },
+ "@typescript-eslint/visitor-keys": {
+ "version": "4.18.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-4.18.0.tgz",
+ "integrity": "sha512-Q9t90JCvfYaN0OfFUgaLqByOfz8yPeTAdotn/XYNm5q9eHax90gzdb+RJ6E9T5s97Kv/UHWKERTmqA0jTKAEHw==",
+ "dev": true,
+ "requires": {
+ "@typescript-eslint/types": "4.18.0",
+ "eslint-visitor-keys": "^2.0.0"
+ }
+ },
"@webassemblyjs/ast": {
"version": "1.11.0",
"resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.11.0.tgz",
@@ -11990,9 +13050,9 @@
"dev": true
},
"acorn": {
- "version": "8.1.0",
- "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.1.0.tgz",
- "integrity": "sha512-LWCF/Wn0nfHOmJ9rzQApGnxnvgfROzGilS8936rqN/lfcYkY9MYZzdMqN+2NJ4SlTc+m5HiSa+kNfDtI64dwUA==",
+ "version": "7.4.1",
+ "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz",
+ "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==",
"dev": true
},
"acorn-globals": {
@@ -12003,16 +13063,15 @@
"requires": {
"acorn": "^7.1.1",
"acorn-walk": "^7.1.1"
- },
- "dependencies": {
- "acorn": {
- "version": "7.4.1",
- "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz",
- "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==",
- "dev": true
- }
}
},
+ "acorn-jsx": {
+ "version": "5.3.1",
+ "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.1.tgz",
+ "integrity": "sha512-K0Ptm/47OKfQRpNQ2J/oIN/3QYiK6FwW+eJbILhsdxh2WTLdl+30o8aGdTbm5JbffpFFAg/g+zi1E+jvJha5ng==",
+ "dev": true,
+ "requires": {}
+ },
"acorn-walk": {
"version": "7.2.0",
"resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-7.2.0.tgz",
@@ -12060,12 +13119,20 @@
"dev": true
},
"ansi-escapes": {
- "version": "4.3.1",
- "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.1.tgz",
- "integrity": "sha512-JWF7ocqNrp8u9oqpgV+wH5ftbt+cfvv+PTjOvKLT3AdYly/LmORARfEVT1iyjwN+4MqE5UmVKoAdIBqeoCHgLA==",
+ "version": "4.3.2",
+ "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz",
+ "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==",
"dev": true,
"requires": {
- "type-fest": "^0.11.0"
+ "type-fest": "^0.21.3"
+ },
+ "dependencies": {
+ "type-fest": {
+ "version": "0.21.3",
+ "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz",
+ "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==",
+ "dev": true
+ }
}
},
"ansi-regex": {
@@ -12148,6 +13215,25 @@
"integrity": "sha1-3wEKoSh+Fku9pvlyOwqWoexBh6E=",
"dev": true
},
+ "array-includes": {
+ "version": "3.1.3",
+ "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.3.tgz",
+ "integrity": "sha512-gcem1KlBU7c9rB+Rq8/3PPKsK2kjqeEBa3bD5kkQo4nYlOHQCJqIJFqBXDEfwaRuYTT4E+FxA9xez7Gf/e3Q7A==",
+ "dev": true,
+ "requires": {
+ "call-bind": "^1.0.2",
+ "define-properties": "^1.1.3",
+ "es-abstract": "^1.18.0-next.2",
+ "get-intrinsic": "^1.1.1",
+ "is-string": "^1.0.5"
+ }
+ },
+ "array-union": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz",
+ "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==",
+ "dev": true
+ },
"array-unique": {
"version": "0.3.2",
"resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz",
@@ -12175,6 +13261,18 @@
"es-abstract": "^1.18.0-next.1"
}
},
+ "array.prototype.flatmap": {
+ "version": "1.2.4",
+ "resolved": "https://registry.npmjs.org/array.prototype.flatmap/-/array.prototype.flatmap-1.2.4.tgz",
+ "integrity": "sha512-r9Z0zYoxqHz60vvQbWEdXIEtCwHF0yxaWfno9qzXeNHvfyl3BZqygmGzb84dsubyaXLH4husF+NFgMSdpZhk2Q==",
+ "dev": true,
+ "requires": {
+ "call-bind": "^1.0.0",
+ "define-properties": "^1.1.3",
+ "es-abstract": "^1.18.0-next.1",
+ "function-bind": "^1.1.1"
+ }
+ },
"asn1": {
"version": "0.2.4",
"resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.4.tgz",
@@ -12196,6 +13294,12 @@
"integrity": "sha1-WWZ/QfrdTyDMvCu5a41Pf3jsA2c=",
"dev": true
},
+ "astral-regex": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-2.0.0.tgz",
+ "integrity": "sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==",
+ "dev": true
+ },
"async-foreach": {
"version": "0.1.3",
"resolved": "https://registry.npmjs.org/async-foreach/-/async-foreach-0.1.3.tgz",
@@ -12220,6 +13324,20 @@
"integrity": "sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==",
"dev": true
},
+ "autoprefixer": {
+ "version": "10.2.5",
+ "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.2.5.tgz",
+ "integrity": "sha512-7H4AJZXvSsn62SqZyJCP+1AWwOuoYpUfK6ot9vm0e87XD6mT8lDywc9D9OTJPMULyGcvmIxzTAMeG2Cc+YX+fA==",
+ "dev": true,
+ "requires": {
+ "browserslist": "^4.16.3",
+ "caniuse-lite": "^1.0.30001196",
+ "colorette": "^1.2.2",
+ "fraction.js": "^4.0.13",
+ "normalize-range": "^0.1.2",
+ "postcss-value-parser": "^4.1.0"
+ }
+ },
"aws-sign2": {
"version": "0.7.0",
"resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz",
@@ -12470,12 +13588,6 @@
"integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==",
"dev": true
},
- "builtin-modules": {
- "version": "1.1.1",
- "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-1.1.1.tgz",
- "integrity": "sha1-Jw8HbFpywC9bZaR9+Uxf46J4iS8=",
- "dev": true
- },
"cache-base": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/cache-base/-/cache-base-1.0.1.tgz",
@@ -13087,24 +14199,36 @@
"integrity": "sha512-xd4D8kHQtB0KtWW0c9xBZD5LVtm9chkMOfs/3Yn01RhT/sFIsVtzTtypfKoFfWBaL+7xCYLxjOLkhwPXaX/Kcg==",
"dev": true
},
- "diff": {
- "version": "4.0.2",
- "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz",
- "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==",
- "dev": true
- },
"diff-sequences": {
"version": "26.6.2",
"resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-26.6.2.tgz",
"integrity": "sha512-Mv/TDa3nZ9sbc5soK+OoA74BsS3mL37yixCvUAQkiuA4Wz6YtwP/K47n2rv2ovzHZvoiQeA5FTQOschKkEwB0Q==",
"dev": true
},
+ "dir-glob": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz",
+ "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==",
+ "dev": true,
+ "requires": {
+ "path-type": "^4.0.0"
+ }
+ },
"discontinuous-range": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/discontinuous-range/-/discontinuous-range-1.0.0.tgz",
"integrity": "sha1-44Mx8IRLukm5qctxx3FYWqsbxlo=",
"dev": true
},
+ "doctrine": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz",
+ "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==",
+ "dev": true,
+ "requires": {
+ "esutils": "^2.0.2"
+ }
+ },
"dom-serializer": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-1.2.0.tgz",
@@ -13187,9 +14311,9 @@
}
},
"electron-to-chromium": {
- "version": "1.3.695",
- "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.695.tgz",
- "integrity": "sha512-lz66RliUqLHU1Ojxx1A4QUxKydjiQ79Y4dZyPobs2Dmxj5aVL2TM3KoQ2Gs7HS703Bfny+ukI3KOxwAB0xceHQ==",
+ "version": "1.3.700",
+ "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.700.tgz",
+ "integrity": "sha512-wQtaxVZzpOeCjW1CGuC5W3bYjE2jglvk076LcTautBOB9UtHztty7wNzjVsndiMcSsdUsdMy5w76w5J1U7OPTQ==",
"dev": true
},
"emittery": {
@@ -13431,26 +14555,153 @@
"esutils": "^2.0.2",
"optionator": "^0.8.1",
"source-map": "~0.6.1"
+ },
+ "dependencies": {
+ "estraverse": {
+ "version": "5.2.0",
+ "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.2.0.tgz",
+ "integrity": "sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ==",
+ "dev": true
+ },
+ "levn": {
+ "version": "0.3.0",
+ "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz",
+ "integrity": "sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4=",
+ "dev": true,
+ "requires": {
+ "prelude-ls": "~1.1.2",
+ "type-check": "~0.3.2"
+ }
+ },
+ "optionator": {
+ "version": "0.8.3",
+ "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.3.tgz",
+ "integrity": "sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA==",
+ "dev": true,
+ "requires": {
+ "deep-is": "~0.1.3",
+ "fast-levenshtein": "~2.0.6",
+ "levn": "~0.3.0",
+ "prelude-ls": "~1.1.2",
+ "type-check": "~0.3.2",
+ "word-wrap": "~1.2.3"
+ }
+ },
+ "prelude-ls": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz",
+ "integrity": "sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ=",
+ "dev": true
+ },
+ "type-check": {
+ "version": "0.3.2",
+ "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz",
+ "integrity": "sha1-WITKtRLPHTVeP7eE8wgEsrUg23I=",
+ "dev": true,
+ "requires": {
+ "prelude-ls": "~1.1.2"
+ }
+ }
+ }
+ },
+ "eslint": {
+ "version": "7.22.0",
+ "resolved": "https://registry.npmjs.org/eslint/-/eslint-7.22.0.tgz",
+ "integrity": "sha512-3VawOtjSJUQiiqac8MQc+w457iGLfuNGLFn8JmF051tTKbh5/x/0vlcEj8OgDCaw7Ysa2Jn8paGshV7x2abKXg==",
+ "dev": true,
+ "requires": {
+ "@babel/code-frame": "7.12.11",
+ "@eslint/eslintrc": "^0.4.0",
+ "ajv": "^6.10.0",
+ "chalk": "^4.0.0",
+ "cross-spawn": "^7.0.2",
+ "debug": "^4.0.1",
+ "doctrine": "^3.0.0",
+ "enquirer": "^2.3.5",
+ "eslint-scope": "^5.1.1",
+ "eslint-utils": "^2.1.0",
+ "eslint-visitor-keys": "^2.0.0",
+ "espree": "^7.3.1",
+ "esquery": "^1.4.0",
+ "esutils": "^2.0.2",
+ "file-entry-cache": "^6.0.1",
+ "functional-red-black-tree": "^1.0.1",
+ "glob-parent": "^5.0.0",
+ "globals": "^13.6.0",
+ "ignore": "^4.0.6",
+ "import-fresh": "^3.0.0",
+ "imurmurhash": "^0.1.4",
+ "is-glob": "^4.0.0",
+ "js-yaml": "^3.13.1",
+ "json-stable-stringify-without-jsonify": "^1.0.1",
+ "levn": "^0.4.1",
+ "lodash": "^4.17.21",
+ "minimatch": "^3.0.4",
+ "natural-compare": "^1.4.0",
+ "optionator": "^0.9.1",
+ "progress": "^2.0.0",
+ "regexpp": "^3.1.0",
+ "semver": "^7.2.1",
+ "strip-ansi": "^6.0.0",
+ "strip-json-comments": "^3.1.0",
+ "table": "^6.0.4",
+ "text-table": "^0.2.0",
+ "v8-compile-cache": "^2.0.3"
}
},
+ "eslint-config-prettier": {
+ "version": "8.1.0",
+ "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-8.1.0.tgz",
+ "integrity": "sha512-oKMhGv3ihGbCIimCAjqkdzx2Q+jthoqnXSP+d86M9tptwugycmTFdVR4IpLgq2c4SHifbwO90z2fQ8/Aio73yw==",
+ "dev": true,
+ "requires": {}
+ },
"eslint-plugin-prettier": {
- "version": "2.7.0",
- "resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-2.7.0.tgz",
- "integrity": "sha512-CStQYJgALoQBw3FsBzH0VOVDRnJ/ZimUlpLm226U8qgqYJfPOY/CPK6wyRInMxh73HSKg5wyRwdS4BVYYHwokA==",
+ "version": "3.3.1",
+ "resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-3.3.1.tgz",
+ "integrity": "sha512-Rq3jkcFY8RYeQLgk2cCwuc0P7SEFwDravPhsJZOQ5N4YI4DSg50NyqJ/9gdZHzQlHf8MvafSesbNJCcP/FF6pQ==",
+ "dev": true,
+ "requires": {
+ "prettier-linter-helpers": "^1.0.0"
+ }
+ },
+ "eslint-plugin-react": {
+ "version": "7.22.0",
+ "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.22.0.tgz",
+ "integrity": "sha512-p30tuX3VS+NWv9nQot9xIGAHBXR0+xJVaZriEsHoJrASGCJZDJ8JLNM0YqKqI0AKm6Uxaa1VUHoNEibxRCMQHA==",
"dev": true,
"requires": {
- "fast-diff": "^1.1.1",
- "jest-docblock": "^21.0.0"
+ "array-includes": "^3.1.1",
+ "array.prototype.flatmap": "^1.2.3",
+ "doctrine": "^2.1.0",
+ "has": "^1.0.3",
+ "jsx-ast-utils": "^2.4.1 || ^3.0.0",
+ "object.entries": "^1.1.2",
+ "object.fromentries": "^2.0.2",
+ "object.values": "^1.1.1",
+ "prop-types": "^15.7.2",
+ "resolve": "^1.18.1",
+ "string.prototype.matchall": "^4.0.2"
},
"dependencies": {
- "jest-docblock": {
- "version": "21.2.0",
- "resolved": "https://registry.npmjs.org/jest-docblock/-/jest-docblock-21.2.0.tgz",
- "integrity": "sha512-5IZ7sY9dBAYSV+YjQ0Ovb540Ku7AO9Z5o2Cg789xj167iQuZ2cG+z0f3Uct6WeYLbU6aQiM2pCs7sZ+4dotydw==",
- "dev": true
+ "doctrine": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz",
+ "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==",
+ "dev": true,
+ "requires": {
+ "esutils": "^2.0.2"
+ }
}
}
},
+ "eslint-plugin-react-hooks": {
+ "version": "4.2.0",
+ "resolved": "https://registry.npmjs.org/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-4.2.0.tgz",
+ "integrity": "sha512-623WEiZJqxR7VdxFCKLI6d6LLpwJkGPYKODnkH3D7WpOG5KM8yWueBd8TLsNAetEJNF5iJmolaAKO3F8yzyVBQ==",
+ "dev": true,
+ "requires": {}
+ },
"eslint-scope": {
"version": "5.1.1",
"resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz",
@@ -13459,12 +14710,46 @@
"requires": {
"esrecurse": "^4.3.0",
"estraverse": "^4.1.1"
+ }
+ },
+ "eslint-utils": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-2.1.0.tgz",
+ "integrity": "sha512-w94dQYoauyvlDc43XnGB8lU3Zt713vNChgt4EWwhXAP2XkBvndfxF0AgIqKOOasjPIPzj9JqgwkwbCYD0/V3Zg==",
+ "dev": true,
+ "requires": {
+ "eslint-visitor-keys": "^1.1.0"
},
"dependencies": {
- "estraverse": {
- "version": "4.3.0",
- "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz",
- "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==",
+ "eslint-visitor-keys": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz",
+ "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==",
+ "dev": true
+ }
+ }
+ },
+ "eslint-visitor-keys": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.0.0.tgz",
+ "integrity": "sha512-QudtT6av5WXels9WjIM7qz1XD1cWGvX4gGXvp/zBn9nXG02D0utdU3Em2m/QjTnrsk6bBjmCygl3rmj118msQQ==",
+ "dev": true
+ },
+ "espree": {
+ "version": "7.3.1",
+ "resolved": "https://registry.npmjs.org/espree/-/espree-7.3.1.tgz",
+ "integrity": "sha512-v3JCNCE64umkFpmkFGqzVKsOT0tN1Zr+ueqLZfpV1Ob8e+CEgPWa+OxCoGH3tnhimMKIaBm4m/vaRpJ/krRz2g==",
+ "dev": true,
+ "requires": {
+ "acorn": "^7.4.0",
+ "acorn-jsx": "^5.3.1",
+ "eslint-visitor-keys": "^1.3.0"
+ },
+ "dependencies": {
+ "eslint-visitor-keys": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz",
+ "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==",
"dev": true
}
}
@@ -13475,6 +14760,23 @@
"integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==",
"dev": true
},
+ "esquery": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.4.0.tgz",
+ "integrity": "sha512-cCDispWt5vHHtwMY2YrAQ4ibFkAL8RbH5YGBnZBc90MolvvfkkQcJro/aZiAQUlQ3qgrYS6D6v8Gc5G5CQsc9w==",
+ "dev": true,
+ "requires": {
+ "estraverse": "^5.1.0"
+ },
+ "dependencies": {
+ "estraverse": {
+ "version": "5.2.0",
+ "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.2.0.tgz",
+ "integrity": "sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ==",
+ "dev": true
+ }
+ }
+ },
"esrecurse": {
"version": "4.3.0",
"resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz",
@@ -13482,12 +14784,20 @@
"dev": true,
"requires": {
"estraverse": "^5.2.0"
+ },
+ "dependencies": {
+ "estraverse": {
+ "version": "5.2.0",
+ "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.2.0.tgz",
+ "integrity": "sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ==",
+ "dev": true
+ }
}
},
"estraverse": {
- "version": "5.2.0",
- "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.2.0.tgz",
- "integrity": "sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ==",
+ "version": "4.3.0",
+ "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz",
+ "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==",
"dev": true
},
"esutils": {
@@ -13503,9 +14813,9 @@
"dev": true
},
"exec-sh": {
- "version": "0.3.5",
- "resolved": "https://registry.npmjs.org/exec-sh/-/exec-sh-0.3.5.tgz",
- "integrity": "sha512-0hzpaUazv4mEccxdn3TXC+HWNeVXNKMCJRK6E7Xyg+LwGAYI3yFag6jTkd4injV+kChYDQS1ftqDhnDVWNhU8A==",
+ "version": "0.3.6",
+ "resolved": "https://registry.npmjs.org/exec-sh/-/exec-sh-0.3.6.tgz",
+ "integrity": "sha512-nQn+hI3yp+oD0huYhKwvYI32+JFeq+XkNcD1GAo3Y/MjxsfVGmrrzrnzjWiNY6f+pUCP440fThsFh5gZrRAU/w==",
"dev": true
},
"execa": {
@@ -13746,6 +15056,20 @@
"integrity": "sha512-xJuoT5+L99XlZ8twedaRf6Ax2TgQVxvgZOYoPKqZufmJib0tL2tegPBOZb1pVNgIhlqDlA0eO0c3wBvQcmzx4w==",
"dev": true
},
+ "fast-glob": {
+ "version": "3.2.5",
+ "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.5.tgz",
+ "integrity": "sha512-2DtFcgT68wiTTiwZ2hNdJfcHNke9XOfnwmBRWXhmeKM8rF0TGwmC/Qto3S7RoZKp5cilZbxzO5iTNTQsJ+EeDg==",
+ "dev": true,
+ "requires": {
+ "@nodelib/fs.stat": "^2.0.2",
+ "@nodelib/fs.walk": "^1.2.3",
+ "glob-parent": "^5.1.0",
+ "merge2": "^1.3.0",
+ "micromatch": "^4.0.2",
+ "picomatch": "^2.2.1"
+ }
+ },
"fast-json-stable-stringify": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz",
@@ -13764,6 +15088,15 @@
"integrity": "sha512-On2N+BpYJ15xIC974QNVuYGMOlEVt4s0EOI3wwMqOmK1fdDY+FN/zltPV8vosq4ad4c/gJ1KHScUn/6AWIgiow==",
"dev": true
},
+ "fastq": {
+ "version": "1.11.0",
+ "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.11.0.tgz",
+ "integrity": "sha512-7Eczs8gIPDrVzT+EksYBcupqMyxSHXXrHOLRRxU2/DicV8789MRBRR8+Hc2uWzUupOs4YS4JzBmBxjjCVBxD/g==",
+ "dev": true,
+ "requires": {
+ "reusify": "^1.0.4"
+ }
+ },
"fb-watchman": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/fb-watchman/-/fb-watchman-2.0.1.tgz",
@@ -13782,6 +15115,15 @@
"pend": "~1.2.0"
}
},
+ "file-entry-cache": {
+ "version": "6.0.1",
+ "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz",
+ "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==",
+ "dev": true,
+ "requires": {
+ "flat-cache": "^3.0.4"
+ }
+ },
"file-loader": {
"version": "6.2.0",
"resolved": "https://registry.npmjs.org/file-loader/-/file-loader-6.2.0.tgz",
@@ -13811,6 +15153,22 @@
"path-exists": "^4.0.0"
}
},
+ "flat-cache": {
+ "version": "3.0.4",
+ "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz",
+ "integrity": "sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==",
+ "dev": true,
+ "requires": {
+ "flatted": "^3.1.0",
+ "rimraf": "^3.0.2"
+ }
+ },
+ "flatted": {
+ "version": "3.1.1",
+ "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.1.1.tgz",
+ "integrity": "sha512-zAoAQiudy+r5SvnSw3KJy5os/oRJYHzrzja/tBDqrZtNhUw8bt6y8OBzMWcjWr+8liV8Eb6yOhw8WZ7VFZ5ZzA==",
+ "dev": true
+ },
"for-in": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz",
@@ -13867,6 +15225,12 @@
"mime-types": "^2.1.12"
}
},
+ "fraction.js": {
+ "version": "4.0.13",
+ "resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-4.0.13.tgz",
+ "integrity": "sha512-E1fz2Xs9ltlUp+qbiyx9wmt2n9dRzPsS11Jtdb8D2o+cC7wr9xkkKsVKJuBX0ST+LVS+LhLO+SbLJNtfWcJvXA==",
+ "dev": true
+ },
"fragment-cache": {
"version": "0.2.1",
"resolved": "https://registry.npmjs.org/fragment-cache/-/fragment-cache-0.2.1.tgz",
@@ -13940,6 +15304,12 @@
"functions-have-names": "^1.2.2"
}
},
+ "functional-red-black-tree": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz",
+ "integrity": "sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=",
+ "dev": true
+ },
"functions-have-names": {
"version": "1.2.2",
"resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.2.tgz",
@@ -14077,10 +15447,35 @@
"dev": true
},
"globals": {
- "version": "11.12.0",
- "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz",
- "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==",
- "dev": true
+ "version": "13.7.0",
+ "resolved": "https://registry.npmjs.org/globals/-/globals-13.7.0.tgz",
+ "integrity": "sha512-Aipsz6ZKRxa/xQkZhNg0qIWXT6x6rD46f6x/PCnBomlttdIyAPak4YD9jTmKpZ72uROSMU87qJtcgpgHaVchiA==",
+ "dev": true,
+ "requires": {
+ "type-fest": "^0.20.2"
+ }
+ },
+ "globby": {
+ "version": "11.0.3",
+ "resolved": "https://registry.npmjs.org/globby/-/globby-11.0.3.tgz",
+ "integrity": "sha512-ffdmosjA807y7+lA1NM0jELARVmYul/715xiILEjo3hBLPTcirgQNnXECn5g3mtR8TOLCVbkfua1Hpen25/Xcg==",
+ "dev": true,
+ "requires": {
+ "array-union": "^2.1.0",
+ "dir-glob": "^3.0.1",
+ "fast-glob": "^3.1.1",
+ "ignore": "^5.1.4",
+ "merge2": "^1.3.0",
+ "slash": "^3.0.0"
+ },
+ "dependencies": {
+ "ignore": {
+ "version": "5.1.8",
+ "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.1.8.tgz",
+ "integrity": "sha512-BMpfD7PpiETpBl/A6S498BaIJ6Y/ABT93ETbby2fP00v4EbvPBXWEoaR1UBPKs3iR53pJY7EtZk5KACI57i1Uw==",
+ "dev": true
+ }
+ }
},
"globule": {
"version": "1.3.2",
@@ -14325,6 +15720,12 @@
"integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==",
"dev": true
},
+ "ignore": {
+ "version": "4.0.6",
+ "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz",
+ "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==",
+ "dev": true
+ },
"import-fresh": {
"version": "3.3.0",
"resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz",
@@ -14382,6 +15783,17 @@
"integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==",
"dev": true
},
+ "internal-slot": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.3.tgz",
+ "integrity": "sha512-O0DB1JC/sPyZl7cIo78n5dR7eUSwwpYPiXRhTzNxZVAMUuB8vlnRFyLxdrVToks6XPLVnFfbzaVd5WLjhgg+vA==",
+ "dev": true,
+ "requires": {
+ "get-intrinsic": "^1.1.0",
+ "has": "^1.0.3",
+ "side-channel": "^1.0.4"
+ }
+ },
"interpret": {
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/interpret/-/interpret-2.2.0.tgz",
@@ -15200,6 +16612,14 @@
"whatwg-url": "^8.0.0",
"ws": "^7.4.4",
"xml-name-validator": "^3.0.0"
+ },
+ "dependencies": {
+ "acorn": {
+ "version": "8.1.0",
+ "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.1.0.tgz",
+ "integrity": "sha512-LWCF/Wn0nfHOmJ9rzQApGnxnvgfROzGilS8936rqN/lfcYkY9MYZzdMqN+2NJ4SlTc+m5HiSa+kNfDtI64dwUA==",
+ "dev": true
+ }
}
},
"jsesc": {
@@ -15232,6 +16652,12 @@
"integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==",
"dev": true
},
+ "json-stable-stringify-without-jsonify": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz",
+ "integrity": "sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=",
+ "dev": true
+ },
"json-stringify-safe": {
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz",
@@ -15269,6 +16695,16 @@
"verror": "1.10.0"
}
},
+ "jsx-ast-utils": {
+ "version": "3.2.0",
+ "resolved": "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-3.2.0.tgz",
+ "integrity": "sha512-EIsmt3O3ljsU6sot/J4E1zDRxfBNrhjyf/OKjlydwgEimQuznlM4Wv7U+ueONJMyEn1WRE0K8dhi3dVAXYT24Q==",
+ "dev": true,
+ "requires": {
+ "array-includes": "^3.1.2",
+ "object.assign": "^4.1.2"
+ }
+ },
"kind-of": {
"version": "6.0.3",
"resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz",
@@ -15294,13 +16730,13 @@
"dev": true
},
"levn": {
- "version": "0.3.0",
- "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz",
- "integrity": "sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4=",
+ "version": "0.4.1",
+ "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz",
+ "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==",
"dev": true,
"requires": {
- "prelude-ls": "~1.1.2",
- "type-check": "~0.3.2"
+ "prelude-ls": "^1.2.1",
+ "type-check": "~0.4.0"
}
},
"lines-and-columns": {
@@ -15392,12 +16828,6 @@
"integrity": "sha1-QVxEePK8wwEgwizhDtMib30+GOA=",
"dev": true
},
- "lodash.sortby": {
- "version": "4.7.0",
- "resolved": "https://registry.npmjs.org/lodash.sortby/-/lodash.sortby-4.7.0.tgz",
- "integrity": "sha1-7dFMgk4sycHgsKG0K7UhBRakJDg=",
- "dev": true
- },
"loose-envify": {
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz",
@@ -15579,6 +17009,12 @@
"integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==",
"dev": true
},
+ "merge2": {
+ "version": "1.4.1",
+ "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz",
+ "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==",
+ "dev": true
+ },
"micromatch": {
"version": "4.0.2",
"resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.2.tgz",
@@ -15923,6 +17359,12 @@
"integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==",
"dev": true
},
+ "normalize-range": {
+ "version": "0.1.2",
+ "resolved": "https://registry.npmjs.org/normalize-range/-/normalize-range-0.1.2.tgz",
+ "integrity": "sha1-LRDAa9/TEuqXd2laTShDlFa3WUI=",
+ "dev": true
+ },
"npm-run-path": {
"version": "4.0.1",
"resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz",
@@ -16157,17 +17599,17 @@
"dev": true
},
"optionator": {
- "version": "0.8.3",
- "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.3.tgz",
- "integrity": "sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA==",
+ "version": "0.9.1",
+ "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz",
+ "integrity": "sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==",
"dev": true,
"requires": {
- "deep-is": "~0.1.3",
- "fast-levenshtein": "~2.0.6",
- "levn": "~0.3.0",
- "prelude-ls": "~1.1.2",
- "type-check": "~0.3.2",
- "word-wrap": "~1.2.3"
+ "deep-is": "^0.1.3",
+ "fast-levenshtein": "^2.0.6",
+ "levn": "^0.4.1",
+ "prelude-ls": "^1.2.1",
+ "type-check": "^0.4.0",
+ "word-wrap": "^1.2.3"
}
},
"p-each-series": {
@@ -16407,9 +17849,9 @@
"dev": true
},
"prelude-ls": {
- "version": "1.1.2",
- "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz",
- "integrity": "sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ=",
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz",
+ "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==",
"dev": true
},
"prettier": {
@@ -16418,6 +17860,15 @@
"integrity": "sha512-PqyhM2yCjg/oKkFPtTGUojv7gnZAoG80ttl45O6x2Ug/rMJw4wcc9k6aaf2hibP7BGVCCM33gZoGjyvt9mm16Q==",
"dev": true
},
+ "prettier-linter-helpers": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/prettier-linter-helpers/-/prettier-linter-helpers-1.0.0.tgz",
+ "integrity": "sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w==",
+ "dev": true,
+ "requires": {
+ "fast-diff": "^1.1.2"
+ }
+ },
"pretty-format": {
"version": "26.6.2",
"resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-26.6.2.tgz",
@@ -16542,6 +17993,12 @@
"integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==",
"dev": true
},
+ "queue-microtask": {
+ "version": "1.2.3",
+ "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz",
+ "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==",
+ "dev": true
+ },
"raf": {
"version": "3.4.1",
"resolved": "https://registry.npmjs.org/raf/-/raf-3.4.1.tgz",
@@ -16756,6 +18213,22 @@
"safe-regex": "^1.1.0"
}
},
+ "regexp.prototype.flags": {
+ "version": "1.3.1",
+ "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.3.1.tgz",
+ "integrity": "sha512-JiBdRBq91WlY7uRJ0ds7R+dU02i6LKi8r3BuQhNXn+kmeLN+EfHhfjqMRis1zJxnlu88hq/4dx0P2OP3APRTOA==",
+ "dev": true,
+ "requires": {
+ "call-bind": "^1.0.2",
+ "define-properties": "^1.1.3"
+ }
+ },
+ "regexpp": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.1.0.tgz",
+ "integrity": "sha512-ZOIzd8yVsQQA7j8GCSlPGXwg5PfmA1mrq0JP4nGhh54LaKN3xdai/vHUDu74pKwV8OxseMS65u2NImosQcSD0Q==",
+ "dev": true
+ },
"remove-trailing-separator": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz",
@@ -16867,6 +18340,12 @@
"integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=",
"dev": true
},
+ "require-from-string": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz",
+ "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==",
+ "dev": true
+ },
"require-main-filename": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz",
@@ -16918,6 +18397,12 @@
"integrity": "sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg==",
"dev": true
},
+ "reusify": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz",
+ "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==",
+ "dev": true
+ },
"rimraf": {
"version": "3.0.2",
"resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz",
@@ -16943,6 +18428,15 @@
"integrity": "sha512-nfMOlASu9OnRJo1mbEk2cz0D56a1MBNrJ7orjRZQG10XDyuvwksKbuXNp6qa+kbn839HwjwhBzhFmdsaEAfauA==",
"dev": true
},
+ "run-parallel": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz",
+ "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==",
+ "dev": true,
+ "requires": {
+ "queue-microtask": "^1.2.2"
+ }
+ },
"safe-buffer": {
"version": "5.1.2",
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
@@ -17509,6 +19003,17 @@
"dev": true,
"optional": true
},
+ "side-channel": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz",
+ "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==",
+ "dev": true,
+ "requires": {
+ "call-bind": "^1.0.0",
+ "get-intrinsic": "^1.0.2",
+ "object-inspect": "^1.9.0"
+ }
+ },
"signal-exit": {
"version": "3.0.3",
"resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.3.tgz",
@@ -17538,6 +19043,25 @@
"integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==",
"dev": true
},
+ "slice-ansi": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-4.0.0.tgz",
+ "integrity": "sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ==",
+ "dev": true,
+ "requires": {
+ "ansi-styles": "^4.0.0",
+ "astral-regex": "^2.0.0",
+ "is-fullwidth-code-point": "^3.0.0"
+ },
+ "dependencies": {
+ "is-fullwidth-code-point": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
+ "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==",
+ "dev": true
+ }
+ }
+ },
"snapdragon": {
"version": "0.8.2",
"resolved": "https://registry.npmjs.org/snapdragon/-/snapdragon-0.8.2.tgz",
@@ -17954,6 +19478,21 @@
}
}
},
+ "string.prototype.matchall": {
+ "version": "4.0.4",
+ "resolved": "https://registry.npmjs.org/string.prototype.matchall/-/string.prototype.matchall-4.0.4.tgz",
+ "integrity": "sha512-pknFIWVachNcyqRfaQSeu/FUfpvJTe4uskUSZ9Wc1RijsPuzbZ8TyYT8WCNnntCjUEqQ3vUHMAfVj2+wLAisPQ==",
+ "dev": true,
+ "requires": {
+ "call-bind": "^1.0.2",
+ "define-properties": "^1.1.3",
+ "es-abstract": "^1.18.0-next.2",
+ "has-symbols": "^1.0.1",
+ "internal-slot": "^1.0.3",
+ "regexp.prototype.flags": "^1.3.1",
+ "side-channel": "^1.0.4"
+ }
+ },
"string.prototype.trim": {
"version": "1.2.4",
"resolved": "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.2.4.tgz",
@@ -18021,6 +19560,12 @@
"get-stdin": "^4.0.1"
}
},
+ "strip-json-comments": {
+ "version": "3.1.1",
+ "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz",
+ "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==",
+ "dev": true
+ },
"supports-color": {
"version": "7.2.0",
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
@@ -18046,6 +19591,55 @@
"integrity": "sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==",
"dev": true
},
+ "table": {
+ "version": "6.0.7",
+ "resolved": "https://registry.npmjs.org/table/-/table-6.0.7.tgz",
+ "integrity": "sha512-rxZevLGTUzWna/qBLObOe16kB2RTnnbhciwgPbMMlazz1yZGVEgnZK762xyVdVznhqxrfCeBMmMkgOOaPwjH7g==",
+ "dev": true,
+ "requires": {
+ "ajv": "^7.0.2",
+ "lodash": "^4.17.20",
+ "slice-ansi": "^4.0.0",
+ "string-width": "^4.2.0"
+ },
+ "dependencies": {
+ "ajv": {
+ "version": "7.2.3",
+ "resolved": "https://registry.npmjs.org/ajv/-/ajv-7.2.3.tgz",
+ "integrity": "sha512-idv5WZvKVXDqKralOImQgPM9v6WOdLNa0IY3B3doOjw/YxRGT8I+allIJ6kd7Uaj+SF1xZUSU+nPM5aDNBVtnw==",
+ "dev": true,
+ "requires": {
+ "fast-deep-equal": "^3.1.1",
+ "json-schema-traverse": "^1.0.0",
+ "require-from-string": "^2.0.2",
+ "uri-js": "^4.2.2"
+ }
+ },
+ "is-fullwidth-code-point": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
+ "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==",
+ "dev": true
+ },
+ "json-schema-traverse": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz",
+ "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==",
+ "dev": true
+ },
+ "string-width": {
+ "version": "4.2.2",
+ "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.2.tgz",
+ "integrity": "sha512-XBJbT3N4JhVumXE0eoLU9DCjcaF92KLNqTmFCnG1pf8duUxFGwtP6AD6nkjw9a3IdiRtL3E2w3JDiE/xi3vOeA==",
+ "dev": true,
+ "requires": {
+ "emoji-regex": "^8.0.0",
+ "is-fullwidth-code-point": "^3.0.0",
+ "strip-ansi": "^6.0.0"
+ }
+ }
+ }
+ },
"tapable": {
"version": "1.1.3",
"resolved": "https://registry.npmjs.org/tapable/-/tapable-1.1.3.tgz",
@@ -18185,6 +19779,12 @@
"minimatch": "^3.0.4"
}
},
+ "text-table": {
+ "version": "0.2.0",
+ "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz",
+ "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=",
+ "dev": true
+ },
"throat": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/throat/-/throat-5.0.0.tgz",
@@ -18348,152 +19948,10 @@
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.1.0.tgz",
"integrity": "sha512-hcVC3wYEziELGGmEEXue7D75zbwIIVUMWAVbHItGPx0ziyXxrOMQx4rQEVEV45Ut/1IotuEvwqPopzIOkDMf0A=="
},
- "tslint": {
- "version": "6.1.3",
- "resolved": "https://registry.npmjs.org/tslint/-/tslint-6.1.3.tgz",
- "integrity": "sha512-IbR4nkT96EQOvKE2PW/djGz8iGNeJ4rF2mBfiYaR/nvUWYKJhLwimoJKgjIFEIDibBtOevj7BqCRL4oHeWWUCg==",
- "dev": true,
- "requires": {
- "@babel/code-frame": "^7.0.0",
- "builtin-modules": "^1.1.1",
- "chalk": "^2.3.0",
- "commander": "^2.12.1",
- "diff": "^4.0.1",
- "glob": "^7.1.1",
- "js-yaml": "^3.13.1",
- "minimatch": "^3.0.4",
- "mkdirp": "^0.5.3",
- "resolve": "^1.3.2",
- "semver": "^5.3.0",
- "tslib": "^1.13.0",
- "tsutils": "^2.29.0"
- },
- "dependencies": {
- "ansi-styles": {
- "version": "3.2.1",
- "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz",
- "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==",
- "dev": true,
- "requires": {
- "color-convert": "^1.9.0"
- }
- },
- "chalk": {
- "version": "2.4.2",
- "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
- "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
- "dev": true,
- "requires": {
- "ansi-styles": "^3.2.1",
- "escape-string-regexp": "^1.0.5",
- "supports-color": "^5.3.0"
- }
- },
- "color-convert": {
- "version": "1.9.3",
- "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
- "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==",
- "dev": true,
- "requires": {
- "color-name": "1.1.3"
- }
- },
- "color-name": {
- "version": "1.1.3",
- "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
- "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=",
- "dev": true
- },
- "escape-string-regexp": {
- "version": "1.0.5",
- "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
- "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=",
- "dev": true
- },
- "has-flag": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
- "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=",
- "dev": true
- },
- "semver": {
- "version": "5.7.1",
- "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz",
- "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==",
- "dev": true
- },
- "supports-color": {
- "version": "5.5.0",
- "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
- "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
- "dev": true,
- "requires": {
- "has-flag": "^3.0.0"
- }
- },
- "tslib": {
- "version": "1.14.1",
- "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz",
- "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==",
- "dev": true
- }
- }
- },
- "tslint-config-prettier": {
- "version": "1.18.0",
- "resolved": "https://registry.npmjs.org/tslint-config-prettier/-/tslint-config-prettier-1.18.0.tgz",
- "integrity": "sha512-xPw9PgNPLG3iKRxmK7DWr+Ea/SzrvfHtjFt5LBl61gk2UBG/DB9kCXRjv+xyIU1rUtnayLeMUVJBcMX8Z17nDg==",
- "dev": true
- },
- "tslint-plugin-prettier": {
- "version": "2.3.0",
- "resolved": "https://registry.npmjs.org/tslint-plugin-prettier/-/tslint-plugin-prettier-2.3.0.tgz",
- "integrity": "sha512-F9e4K03yc9xuvv+A0v1EmjcnDwpz8SpCD8HzqSDe0eyg34cBinwn9JjmnnRrNAs4HdleRQj7qijp+P/JTxt4vA==",
- "dev": true,
- "requires": {
- "eslint-plugin-prettier": "^2.2.0",
- "lines-and-columns": "^1.1.6",
- "tslib": "^1.7.1"
- },
- "dependencies": {
- "tslib": {
- "version": "1.14.1",
- "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz",
- "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==",
- "dev": true
- }
- }
- },
- "tslint-react": {
- "version": "5.0.0",
- "resolved": "https://registry.npmjs.org/tslint-react/-/tslint-react-5.0.0.tgz",
- "integrity": "sha512-/IbcSmoBPlFic8kQaRfQ4knTY4mivwo5LVzvozvX6Dyu2ynEnrh1dIcR2ujjyp/IodXqY/H5GbxFxSMo/Kf2Hg==",
- "dev": true,
- "requires": {
- "tsutils": "^3.17.1"
- },
- "dependencies": {
- "tslib": {
- "version": "1.14.1",
- "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz",
- "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==",
- "dev": true
- },
- "tsutils": {
- "version": "3.21.0",
- "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.21.0.tgz",
- "integrity": "sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==",
- "dev": true,
- "requires": {
- "tslib": "^1.8.1"
- }
- }
- }
- },
"tsutils": {
- "version": "2.29.0",
- "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-2.29.0.tgz",
- "integrity": "sha512-g5JVHCIJwzfISaXpXE1qvNalca5Jwob6FjI4AoPlqMusJ6ftFE7IkkFoMhVLRgK+4Kx3gkzb8UZK5t5yTTvEmA==",
+ "version": "3.21.0",
+ "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.21.0.tgz",
+ "integrity": "sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==",
"dev": true,
"requires": {
"tslib": "^1.8.1"
@@ -18523,12 +19981,12 @@
"dev": true
},
"type-check": {
- "version": "0.3.2",
- "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz",
- "integrity": "sha1-WITKtRLPHTVeP7eE8wgEsrUg23I=",
+ "version": "0.4.0",
+ "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz",
+ "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==",
"dev": true,
"requires": {
- "prelude-ls": "~1.1.2"
+ "prelude-ls": "^1.2.1"
}
},
"type-detect": {
@@ -18538,9 +19996,9 @@
"dev": true
},
"type-fest": {
- "version": "0.11.0",
- "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.11.0.tgz",
- "integrity": "sha512-OdjXJxnCN1AvyLSzeKIgXTXxV+99ZuXl3Hpo9XpJAv9MBcHrrJOQ5kV7ypXOuQie+AmWG25hLbiKdwYTifzcfQ==",
+ "version": "0.20.2",
+ "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz",
+ "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==",
"dev": true
},
"typedarray-to-buffer": {
@@ -18828,6 +20286,12 @@
"webpack-sources": "^2.1.1"
},
"dependencies": {
+ "acorn": {
+ "version": "8.1.0",
+ "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.1.0.tgz",
+ "integrity": "sha512-LWCF/Wn0nfHOmJ9rzQApGnxnvgfROzGilS8936rqN/lfcYkY9MYZzdMqN+2NJ4SlTc+m5HiSa+kNfDtI64dwUA==",
+ "dev": true
+ },
"enhanced-resolve": {
"version": "5.7.0",
"resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.7.0.tgz",
@@ -18873,6 +20337,12 @@
"ws": "^7.3.1"
},
"dependencies": {
+ "acorn": {
+ "version": "8.1.0",
+ "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.1.0.tgz",
+ "integrity": "sha512-LWCF/Wn0nfHOmJ9rzQApGnxnvgfROzGilS8936rqN/lfcYkY9MYZzdMqN+2NJ4SlTc+m5HiSa+kNfDtI64dwUA==",
+ "dev": true
+ },
"acorn-walk": {
"version": "8.0.2",
"resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.0.2.tgz",
@@ -18982,12 +20452,12 @@
"dev": true
},
"whatwg-url": {
- "version": "8.4.0",
- "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-8.4.0.tgz",
- "integrity": "sha512-vwTUFf6V4zhcPkWp/4CQPr1TW9Ml6SF4lVyaIMBdJw5i6qUUJ1QWM4Z6YYVkfka0OUIzVo/0aNtGVGk256IKWw==",
+ "version": "8.5.0",
+ "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-8.5.0.tgz",
+ "integrity": "sha512-fy+R77xWv0AiqfLl4nuGUlQ3/6b5uNfQ4WAbGQVMYshCTCCPK9psC1nWh3XHuxGVCtlcDDQPQW1csmmIQo+fwg==",
"dev": true,
"requires": {
- "lodash.sortby": "^4.7.0",
+ "lodash": "^4.7.0",
"tr46": "^2.0.2",
"webidl-conversions": "^6.1.0"
}
diff --git a/package.json b/package.json
index 7743c9bde..0704ec789 100644
--- a/package.json
+++ b/package.json
@@ -24,11 +24,19 @@
"@types/react": "17.0.3",
"@types/react-dom": "17.0.3",
"@types/react-textarea-autosize": "4.3.5",
+ "@typescript-eslint/eslint-plugin": "4.18.0",
+ "@typescript-eslint/parser": "4.18.0",
"@wojtekmaj/enzyme-adapter-react-17": "0.5.0",
+ "autoprefixer": "10.2.5",
"css-loader": "5.1.1",
"dotenv": "8.2.0",
"enzyme": "3.11.0",
"esbuild": "0.9.5",
+ "eslint": "7.22.0",
+ "eslint-config-prettier": "8.1.0",
+ "eslint-plugin-prettier": "3.3.1",
+ "eslint-plugin-react": "7.22.0",
+ "eslint-plugin-react-hooks": "4.2.0",
"file-loader": "6.2.0",
"fork-ts-checker-webpack-plugin": "6.1.1",
"jest": "26.6.3",
@@ -40,10 +48,6 @@
"sass-loader": "11.0.1",
"ts-jest": "26.5.3",
"ts-loader": "8.0.17",
- "tslint": "6.1.3",
- "tslint-config-prettier": "1.18.0",
- "tslint-plugin-prettier": "2.3.0",
- "tslint-react": "5.0.0",
"typescript": "4.2.3",
"webpack": "5.24.3",
"webpack-bundle-analyzer": "4.4.0",
diff --git a/public/AsyncPages.tsx b/public/AsyncPages.tsx
index a235d9515..4811dca5a 100644
--- a/public/AsyncPages.tsx
+++ b/public/AsyncPages.tsx
@@ -1,9 +1,9 @@
-import { lazy, ComponentType } from "react";
+import { lazy, ComponentType } from "react"
-type LazyImport = () => Promise<{ default: ComponentType }>;
+type LazyImport = () => Promise<{ default: ComponentType }>
-const MAX_RETRIES = 10;
-const INTERVAL = 500;
+const MAX_RETRIES = 10
+const INTERVAL = 500
const retry = (fn: LazyImport, retriesLeft = MAX_RETRIES): Promise<{ default: ComponentType }> => {
return new Promise((resolve, reject) => {
@@ -12,16 +12,16 @@ const retry = (fn: LazyImport, retriesLeft = MAX_RETRIES): Promise<{ default: Co
.catch((err) => {
setTimeout(() => {
if (retriesLeft === 1) {
- reject(new Error(`${err} after ${MAX_RETRIES} retries`));
- return;
+ reject(new Error(`${err} after ${MAX_RETRIES} retries`))
+ return
}
- retry(fn, retriesLeft - 1).then(resolve, reject);
- }, INTERVAL);
- });
- });
-};
+ retry(fn, retriesLeft - 1).then(resolve, reject)
+ }, INTERVAL)
+ })
+ })
+}
-const load = (fn: LazyImport) => lazy(() => retry(() => fn()));
+const load = (fn: LazyImport) => lazy(() => retry(() => fn()))
export const AsyncHomePage = load(
() =>
@@ -29,7 +29,7 @@ export const AsyncHomePage = load(
/* webpackChunkName: "Home.page" */
"@fider/pages/Home/Home.page"
)
-);
+)
export const AsyncShowPostPage = load(
() =>
@@ -37,7 +37,7 @@ export const AsyncShowPostPage = load(
/* webpackChunkName: "ShowPost.page" */
"@fider/pages/ShowPost/ShowPost.page"
)
-);
+)
export const AsyncManageMembersPage = load(
() =>
@@ -45,7 +45,7 @@ export const AsyncManageMembersPage = load(
/* webpackChunkName: "ManageMembers.page" */
"@fider/pages/Administration/pages/ManageMembers.page"
)
-);
+)
export const AsyncManageTagsPage = load(
() =>
@@ -53,7 +53,7 @@ export const AsyncManageTagsPage = load(
/* webpackChunkName: "ManageTags.page" */
"@fider/pages/Administration/pages/ManageTags.page"
)
-);
+)
export const AsyncPrivacySettingsPage = load(
() =>
@@ -61,7 +61,7 @@ export const AsyncPrivacySettingsPage = load(
/* webpackChunkName: "PrivacySettings.page" */
"@fider/pages/Administration/pages/PrivacySettings.page"
)
-);
+)
export const AsyncExportPage = load(
() =>
@@ -69,7 +69,7 @@ export const AsyncExportPage = load(
/* webpackChunkName: "Export.page" */
"@fider/pages/Administration/pages/Export.page"
)
-);
+)
export const AsyncInvitationsPage = load(
() =>
@@ -77,7 +77,7 @@ export const AsyncInvitationsPage = load(
/* webpackChunkName: "Invitations.page" */
"@fider/pages/Administration/pages/Invitations.page"
)
-);
+)
export const AsyncManageAuthenticationPage = load(
() =>
@@ -85,7 +85,7 @@ export const AsyncManageAuthenticationPage = load(
/* webpackChunkName: "ManageAuthentication.page" */
"@fider/pages/Administration/pages/ManageAuthentication.page"
)
-);
+)
export const AsyncAdvancedSettingsPage = load(
() =>
@@ -93,7 +93,7 @@ export const AsyncAdvancedSettingsPage = load(
/* webpackChunkName: "AdvancedSettings.page" */
"@fider/pages/Administration/pages/AdvancedSettings.page"
)
-);
+)
export const AsyncGeneralSettingsPage = load(
() =>
@@ -101,7 +101,7 @@ export const AsyncGeneralSettingsPage = load(
/* webpackChunkName: "GeneralSettings.page" */
"@fider/pages/Administration/pages/GeneralSettings.page"
)
-);
+)
export const AsyncSignInPage = load(
() =>
@@ -109,7 +109,7 @@ export const AsyncSignInPage = load(
/* webpackChunkName: "SignIn.page" */
"@fider/pages/SignIn/SignIn.page"
)
-);
+)
export const AsyncSignUpPage = load(
() =>
@@ -117,7 +117,7 @@ export const AsyncSignUpPage = load(
/* webpackChunkName: "SignUp.page" */
"@fider/pages/SignUp/SignUp.page"
)
-);
+)
export const AsyncCompleteSignInProfilePage = load(
() =>
@@ -125,7 +125,7 @@ export const AsyncCompleteSignInProfilePage = load(
/* webpackChunkName: "CompleteSignInProfile.page" */
"@fider/pages/CompleteSignInProfile/CompleteSignInProfile.page"
)
-);
+)
export const AsyncMyNotificationsPage = load(
() =>
@@ -133,7 +133,7 @@ export const AsyncMyNotificationsPage = load(
/* webpackChunkName: "MyNotifications.page" */
"@fider/pages/MyNotifications/MyNotifications.page"
)
-);
+)
export const AsyncMySettingsPage = load(
() =>
@@ -141,7 +141,7 @@ export const AsyncMySettingsPage = load(
/* webpackChunkName: "MySettings.page" */
"@fider/pages/MySettings/MySettings.page"
)
-);
+)
export const AsyncOAuthEchoPage = load(
() =>
@@ -149,7 +149,7 @@ export const AsyncOAuthEchoPage = load(
/* webpackChunkName: "OAuthEcho.page" */
"@fider/pages/OAuthEcho/OAuthEcho.page"
)
-);
+)
export const AsyncUIToolkitPage = load(
() =>
@@ -157,4 +157,4 @@ export const AsyncUIToolkitPage = load(
/* webpackChunkName: "UIToolkit.page" */
"@fider/pages/UI/UIToolkit.page"
)
-);
+)
diff --git a/public/components/ErrorBoundary.spec.tsx b/public/components/ErrorBoundary.spec.tsx
index 57f4df247..c4c3f7a5c 100644
--- a/public/components/ErrorBoundary.spec.tsx
+++ b/public/components/ErrorBoundary.spec.tsx
@@ -1,43 +1,43 @@
-import React from "react";
-import { shallow } from "enzyme";
-import { ErrorBoundary } from "@fider/components";
+import React from "react"
+import { shallow } from "enzyme"
+import { ErrorBoundary } from "@fider/components"
describe(" ", () => {
- let errorMethod: () => void;
+ let errorMethod: () => void
// Stub out console.error to hide noisy Virtual DOM exceptions.
beforeAll(() => {
- errorMethod = console.error; // tslint:disable-line
- console.error = () => null; // tslint:disable-line
- });
+ errorMethod = console.error
+ console.error = () => null
+ })
afterAll(() => {
- console.error = errorMethod; // tslint:disable-line
- });
+ console.error = errorMethod
+ })
test("when no error caught", () => {
- const errorSpy = jest.fn();
+ const errorSpy = jest.fn()
shallow(
No Error!
- );
+ )
- expect(errorSpy).not.toHaveBeenCalled();
- });
+ expect(errorSpy).not.toHaveBeenCalled()
+ })
describe("when error caught", () => {
test("error should be passed to onError", () => {
- const error = new Error("Whoops!");
- const errorSpy = jest.fn();
- const wrapper = shallow( );
+ const error = new Error("Whoops!")
+ const errorSpy = jest.fn()
+ const wrapper = shallow( )
- const componentDidCatch = wrapper.instance().componentDidCatch;
+ const componentDidCatch = wrapper.instance().componentDidCatch
if (componentDidCatch) {
- componentDidCatch.bind(wrapper.instance())(error, {} as React.ErrorInfo);
+ componentDidCatch.bind(wrapper.instance())(error, {} as React.ErrorInfo)
}
- expect(errorSpy).toHaveBeenCalledWith(error);
- });
- });
-});
+ expect(errorSpy).toHaveBeenCalledWith(error)
+ })
+ })
+})
diff --git a/public/components/ErrorBoundary.tsx b/public/components/ErrorBoundary.tsx
index 31330f5c0..7418da426 100644
--- a/public/components/ErrorBoundary.tsx
+++ b/public/components/ErrorBoundary.tsx
@@ -1,45 +1,45 @@
-import React from "react";
-import { ErrorPage } from "@fider/pages/Error/Error.page";
-import { FiderContext } from "@fider/services";
+import React from "react"
+import { ErrorPage } from "@fider/pages/Error/Error.page"
+import { FiderContext } from "@fider/services"
interface ErrorBoundaryProps {
- onError?: (err: Error) => void;
+ onError?: (err: Error) => void
}
interface ErrorBoundaryState {
- error?: Error;
- errorInfo?: React.ErrorInfo;
+ error?: Error
+ errorInfo?: React.ErrorInfo
}
export class ErrorBoundary extends React.Component {
constructor(props: any) {
- super(props);
+ super(props)
this.state = {
error: undefined,
errorInfo: undefined,
- };
+ }
}
public componentDidCatch(error: Error, errorInfo: React.ErrorInfo) {
- const onError = this.props.onError;
+ const onError = this.props.onError
if (onError) {
- onError(error);
+ onError(error)
}
this.setState({
error,
errorInfo,
- });
+ })
}
public render() {
- const { error, errorInfo } = this.state;
+ const { error, errorInfo } = this.state
if (error && errorInfo) {
- return {(fider) => } ;
+ return {(fider) => }
} else {
- return this.props.children;
+ return this.props.children
}
}
}
diff --git a/public/components/ShowPostResponse.tsx b/public/components/ShowPostResponse.tsx
index 9c5985923..e90674c51 100644
--- a/public/components/ShowPostResponse.tsx
+++ b/public/components/ShowPostResponse.tsx
@@ -1,54 +1,54 @@
-import "./ShowPostResponse.scss";
+import "./ShowPostResponse.scss"
-import React from "react";
-import { PostResponse, PostStatus } from "@fider/models";
-import { Avatar, MultiLineText, UserName, Segment } from "@fider/components/common";
+import React from "react"
+import { PostResponse, PostStatus } from "@fider/models"
+import { Avatar, MultiLineText, UserName, Segment } from "@fider/components/common"
interface ShowPostStatusProps {
- status: PostStatus;
+ status: PostStatus
}
export const ShowPostStatus = (props: ShowPostStatusProps) => {
- return {props.status.title} ;
-};
+ return {props.status.title}
+}
const DuplicateDetails = (props: PostResponseProps): JSX.Element | null => {
if (!props.response) {
- return null;
+ return null
}
- const original = props.response.original;
+ const original = props.response.original
if (!original) {
- return null;
+ return null
}
return (
- );
-};
+ )
+}
interface PostResponseProps {
- status: string;
- response: PostResponse | null;
- showUser: boolean;
+ status: string
+ response: PostResponse | null
+ showUser: boolean
}
const StatusDetails = (props: PostResponseProps): JSX.Element | null => {
if (!props.response || !props.response.text) {
- return null;
+ return null
}
return (
- );
-};
+ )
+}
export const ShowPostResponse = (props: PostResponseProps): JSX.Element => {
- const status = PostStatus.Get(props.status);
+ const status = PostStatus.Get(props.status)
if (props.response && (status.show || props.response.text)) {
return (
@@ -61,8 +61,8 @@ export const ShowPostResponse = (props: PostResponseProps): JSX.Element => {
)}
{status === PostStatus.Duplicate ? DuplicateDetails(props) : StatusDetails(props)}
- );
+ )
}
- return
;
-};
+ return
+}
diff --git a/public/components/ShowTag.tsx b/public/components/ShowTag.tsx
index 2328af6ea..e909042a8 100644
--- a/public/components/ShowTag.tsx
+++ b/public/components/ShowTag.tsx
@@ -1,40 +1,40 @@
-import "./ShowTag.scss";
+import "./ShowTag.scss"
-import React from "react";
-import { Tag } from "@fider/models";
-import { classSet } from "@fider/services";
-import { FaLock } from "react-icons/fa";
+import React from "react"
+import { Tag } from "@fider/models"
+import { classSet } from "@fider/services"
+import { FaLock } from "react-icons/fa"
interface TagProps {
- tag: Tag;
- size?: "mini" | "tiny" | "small" | "normal";
- circular?: boolean;
+ tag: Tag
+ size?: "mini" | "tiny" | "small" | "normal"
+ circular?: boolean
}
const getRGB = (color: string) => {
- const r = color.substring(0, 2);
- const g = color.substring(2, 4);
- const b = color.substring(4, 6);
+ const r = color.substring(0, 2)
+ const g = color.substring(2, 4)
+ const b = color.substring(4, 6)
return {
R: parseInt(r, 16),
G: parseInt(g, 16),
B: parseInt(b, 16),
- };
-};
+ }
+}
const textColor = (color: string) => {
- const components = getRGB(color);
- const bgDelta = components.R * 0.299 + components.G * 0.587 + components.B * 0.114;
- return bgDelta > 140 ? "#333" : "#fff";
-};
+ const components = getRGB(color)
+ const bgDelta = components.R * 0.299 + components.G * 0.587 + components.B * 0.114
+ return bgDelta > 140 ? "#333" : "#fff"
+}
export const ShowTag = (props: TagProps) => {
const className = classSet({
"c-tag": true,
[`m-${props.size || "normal"}`]: true,
"m-circular": props.circular === true,
- });
+ })
return (
{
{!props.tag.isPublic && !props.circular && }
{props.circular ? "" : props.tag.name || "Tag"}
- );
-};
+ )
+}
diff --git a/public/components/SignInModal.tsx b/public/components/SignInModal.tsx
index 195d5da55..f91fbb2ed 100644
--- a/public/components/SignInModal.tsx
+++ b/public/components/SignInModal.tsx
@@ -1,28 +1,28 @@
-import React, { useState, useEffect } from "react";
-import { Modal, SignInControl, LegalFooter } from "@fider/components/common";
+import React, { useState, useEffect } from "react"
+import { Modal, SignInControl, LegalFooter } from "@fider/components/common"
interface SignInModalProps {
- isOpen: boolean;
- onClose: () => void;
+ isOpen: boolean
+ onClose: () => void
}
export const SignInModal: React.StatelessComponent = (props) => {
- const [confirmationAddress, setConfirmationAddress] = useState("");
+ const [confirmationAddress, setConfirmationAddress] = useState("")
useEffect(() => {
if (confirmationAddress) {
- setTimeout(() => setConfirmationAddress(""), 5000);
+ setTimeout(() => setConfirmationAddress(""), 5000)
}
- }, [confirmationAddress]);
+ }, [confirmationAddress])
const onEmailSent = (email: string): void => {
- setConfirmationAddress(email);
- };
+ setConfirmationAddress(email)
+ }
const closeModal = () => {
- setConfirmationAddress("");
- props.onClose();
- };
+ setConfirmationAddress("")
+ props.onClose()
+ }
const content = confirmationAddress ? (
<>
@@ -37,7 +37,7 @@ export const SignInModal: React.StatelessComponent = (props) =
>
) : (
- );
+ )
return (
@@ -45,5 +45,5 @@ export const SignInModal: React.StatelessComponent = (props) =
{content}
- );
-};
+ )
+}
diff --git a/public/components/VoteCounter.spec.tsx b/public/components/VoteCounter.spec.tsx
index 90ba5ef5e..88b888a69 100644
--- a/public/components/VoteCounter.spec.tsx
+++ b/public/components/VoteCounter.spec.tsx
@@ -1,10 +1,10 @@
-import React from "react";
-import { shallow } from "enzyme";
-import { Post, UserRole, PostStatus, UserStatus } from "@fider/models";
-import { VoteCounter, SignInModal } from "@fider/components";
-import { httpMock, fiderMock, rerender } from "@fider/services/testing";
+import React from "react"
+import { shallow } from "enzyme"
+import { Post, UserRole, PostStatus, UserStatus } from "@fider/models"
+import { VoteCounter, SignInModal } from "@fider/components"
+import { httpMock, fiderMock, rerender } from "@fider/services/testing"
-let post: Post;
+let post: Post
beforeEach(() => {
post = {
@@ -27,78 +27,78 @@ beforeEach(() => {
votesCount: 5,
commentsCount: 2,
tags: [],
- };
-});
+ }
+})
describe(" ", () => {
test("when hasVoted === true", () => {
- post.hasVoted = true;
- post.votesCount = 9;
- const wrapper = shallow( );
- const button = wrapper.find("button");
- expect(button.text()).toBe(" 9");
- expect(button.hasClass("m-voted")).toBe(true);
- expect(button.hasClass("m-disabled")).toBe(false);
- });
+ post.hasVoted = true
+ post.votesCount = 9
+ const wrapper = shallow( )
+ const button = wrapper.find("button")
+ expect(button.text()).toBe(" 9")
+ expect(button.hasClass("m-voted")).toBe(true)
+ expect(button.hasClass("m-disabled")).toBe(false)
+ })
test("when hasVoted === false", () => {
- post.hasVoted = false;
- post.votesCount = 2;
- const wrapper = shallow( );
- const button = wrapper.find("button");
- expect(button.text()).toBe(" 2");
- expect(button.hasClass("m-voted")).toBe(false);
- expect(button.hasClass("m-disabled")).toBe(false);
- });
+ post.hasVoted = false
+ post.votesCount = 2
+ const wrapper = shallow( )
+ const button = wrapper.find("button")
+ expect(button.text()).toBe(" 2")
+ expect(button.hasClass("m-voted")).toBe(false)
+ expect(button.hasClass("m-disabled")).toBe(false)
+ })
test("when post is closed", () => {
- post.status = PostStatus.Completed.value;
- const wrapper = shallow( );
- const button = wrapper.find("button");
- expect(button.text()).toBe(" 5");
- expect(button.hasClass("m-voted")).toBe(false);
- expect(button.hasClass("m-disabled")).toBe(true);
- });
+ post.status = PostStatus.Completed.value
+ const wrapper = shallow( )
+ const button = wrapper.find("button")
+ expect(button.text()).toBe(" 5")
+ expect(button.hasClass("m-voted")).toBe(false)
+ expect(button.hasClass("m-disabled")).toBe(true)
+ })
test("click when unauthenticated", async () => {
- fiderMock.notAuthenticated();
+ fiderMock.notAuthenticated()
- const mock = httpMock.alwaysOk();
+ const mock = httpMock.alwaysOk()
- const wrapper = shallow( );
- wrapper.find("button").simulate("click");
- await rerender(wrapper);
- expect(wrapper.find(SignInModal).length).toBe(1);
- expect(mock.post).toHaveBeenCalledTimes(0);
- expect(mock.delete).toHaveBeenCalledTimes(0);
- });
+ const wrapper = shallow( )
+ wrapper.find("button").simulate("click")
+ await rerender(wrapper)
+ expect(wrapper.find(SignInModal).length).toBe(1)
+ expect(mock.post).toHaveBeenCalledTimes(0)
+ expect(mock.delete).toHaveBeenCalledTimes(0)
+ })
test("click when authenticated and hasVoted === false", async () => {
- fiderMock.authenticated();
+ fiderMock.authenticated()
- const mock = httpMock.alwaysOk();
+ const mock = httpMock.alwaysOk()
- const wrapper = shallow( );
- wrapper.find("button").simulate("click");
- expect(mock.post).toHaveBeenCalledWith("/api/v1/posts/10/votes");
- expect(mock.post).toHaveBeenCalledTimes(1);
+ const wrapper = shallow( )
+ wrapper.find("button").simulate("click")
+ expect(mock.post).toHaveBeenCalledWith("/api/v1/posts/10/votes")
+ expect(mock.post).toHaveBeenCalledTimes(1)
- await rerender(wrapper);
- expect(wrapper.find("button").text()).toBe(" 6");
- });
+ await rerender(wrapper)
+ expect(wrapper.find("button").text()).toBe(" 6")
+ })
test("click when authenticated and hasVoted === true", async () => {
- post.hasVoted = true;
- fiderMock.authenticated();
+ post.hasVoted = true
+ fiderMock.authenticated()
- const mock = httpMock.alwaysOk();
+ const mock = httpMock.alwaysOk()
- const wrapper = shallow( );
- wrapper.find("button").simulate("click");
- expect(mock.delete).toHaveBeenCalledWith("/api/v1/posts/10/votes");
- expect(mock.delete).toHaveBeenCalledTimes(1);
+ const wrapper = shallow( )
+ wrapper.find("button").simulate("click")
+ expect(mock.delete).toHaveBeenCalledWith("/api/v1/posts/10/votes")
+ expect(mock.delete).toHaveBeenCalledTimes(1)
- await rerender(wrapper);
- expect(wrapper.find("button").text()).toBe(" 4");
- });
-});
+ await rerender(wrapper)
+ expect(wrapper.find("button").text()).toBe(" 4")
+ })
+})
diff --git a/public/components/VoteCounter.tsx b/public/components/VoteCounter.tsx
index e432364da..5b702b993 100644
--- a/public/components/VoteCounter.tsx
+++ b/public/components/VoteCounter.tsx
@@ -1,65 +1,65 @@
-import "./VoteCounter.scss";
+import "./VoteCounter.scss"
-import React, { useState } from "react";
-import { Post, PostStatus } from "@fider/models";
-import { actions, device, classSet } from "@fider/services";
-import { SignInModal } from "@fider/components";
-import { FaCaretUp } from "react-icons/fa";
-import { useFider } from "@fider/hooks";
+import React, { useState } from "react"
+import { Post, PostStatus } from "@fider/models"
+import { actions, device, classSet } from "@fider/services"
+import { SignInModal } from "@fider/components"
+import { FaCaretUp } from "react-icons/fa"
+import { useFider } from "@fider/hooks"
interface VoteCounterProps {
- post: Post;
+ post: Post
}
export const VoteCounter = (props: VoteCounterProps) => {
- const fider = useFider();
- const [hasVoted, setHasVoted] = useState(props.post.hasVoted);
- const [votesCount, setVotesCount] = useState(props.post.votesCount);
- const [isSignInModalOpen, setIsSignInModalOpen] = useState(false);
+ const fider = useFider()
+ const [hasVoted, setHasVoted] = useState(props.post.hasVoted)
+ const [votesCount, setVotesCount] = useState(props.post.votesCount)
+ const [isSignInModalOpen, setIsSignInModalOpen] = useState(false)
const voteOrUndo = async () => {
if (!fider.session.isAuthenticated) {
- setIsSignInModalOpen(true);
- return;
+ setIsSignInModalOpen(true)
+ return
}
- const action = hasVoted ? actions.removeVote : actions.addVote;
+ const action = hasVoted ? actions.removeVote : actions.addVote
- const response = await action(props.post.number);
+ const response = await action(props.post.number)
if (response.ok) {
- setVotesCount(votesCount + (hasVoted ? -1 : 1));
- setHasVoted(!hasVoted);
+ setVotesCount(votesCount + (hasVoted ? -1 : 1))
+ setHasVoted(!hasVoted)
}
- };
+ }
- const hideModal = () => setIsSignInModalOpen(false);
+ const hideModal = () => setIsSignInModalOpen(false)
- const status = PostStatus.Get(props.post.status);
+ const status = PostStatus.Get(props.post.status)
const className = classSet({
"m-voted": !status.closed && hasVoted,
"m-disabled": status.closed,
"no-touch": !device.isTouch(),
- });
+ })
const vote = (
{votesCount}
- );
+ )
const disabled = (
{votesCount}
- );
+ )
return (
<>
{status.closed ? disabled : vote}
>
- );
-};
+ )
+}
diff --git a/public/components/common/Avatar.tsx b/public/components/common/Avatar.tsx
index d226bee72..8f832578d 100644
--- a/public/components/common/Avatar.tsx
+++ b/public/components/common/Avatar.tsx
@@ -1,26 +1,26 @@
-import "./Avatar.scss";
+import "./Avatar.scss"
-import React from "react";
-import { classSet } from "@fider/services";
-import { isCollaborator, UserRole } from "@fider/models";
+import React from "react"
+import { classSet } from "@fider/services"
+import { isCollaborator, UserRole } from "@fider/models"
interface AvatarProps {
user: {
- role?: UserRole;
- avatarURL: string;
- name: string;
- };
- size?: "small" | "normal" | "large";
+ role?: UserRole
+ avatarURL: string
+ name: string
+ }
+ size?: "small" | "normal" | "large"
}
export const Avatar = (props: AvatarProps) => {
- const size = props.size || "normal";
+ const size = props.size || "normal"
const className = classSet({
"c-avatar": true,
[`m-${size}`]: true,
"m-staff": props.user.role && isCollaborator(props.user.role),
- });
+ })
- return ;
-};
+ return
+}
diff --git a/public/components/common/Button.tsx b/public/components/common/Button.tsx
index d329be0c0..66da5964d 100644
--- a/public/components/common/Button.tsx
+++ b/public/components/common/Button.tsx
@@ -1,74 +1,74 @@
-import React from "react";
-import { classSet } from "@fider/services";
+import React from "react"
+import { classSet } from "@fider/services"
interface ButtonProps {
- className?: string;
- disabled?: boolean;
- href?: string;
- rel?: "nofollow";
- type?: "button" | "submit";
- color?: "positive" | "danger" | "default" | "cancel";
- fluid?: boolean;
- size?: "mini" | "tiny" | "small" | "normal" | "large";
- onClick?: (event: ButtonClickEvent) => Promise;
+ className?: string
+ disabled?: boolean
+ href?: string
+ rel?: "nofollow"
+ type?: "button" | "submit"
+ color?: "positive" | "danger" | "default" | "cancel"
+ fluid?: boolean
+ size?: "mini" | "tiny" | "small" | "normal" | "large"
+ onClick?: (event: ButtonClickEvent) => Promise
}
interface ButtonState {
- clicked: boolean;
+ clicked: boolean
}
-import "./Button.scss";
+import "./Button.scss"
export class ButtonClickEvent {
- private shouldEnable = true;
+ private shouldEnable = true
public preventEnable(): void {
- this.shouldEnable = false;
+ this.shouldEnable = false
}
public canEnable(): boolean {
- return this.shouldEnable;
+ return this.shouldEnable
}
}
export class Button extends React.Component {
- private unmounted: boolean = false;
+ private unmounted = false
public static defaultProps: Partial = {
size: "small",
fluid: false,
color: "default",
type: "button",
- };
+ }
public constructor(props: ButtonProps) {
- super(props);
+ super(props)
this.state = {
clicked: false,
- };
+ }
}
public componentWillUnmount() {
- this.unmounted = true;
+ this.unmounted = true
}
public click = async (e?: React.SyntheticEvent) => {
if (e) {
- e.preventDefault();
- e.stopPropagation();
+ e.preventDefault()
+ e.stopPropagation()
}
if (this.state.clicked) {
- return;
+ return
}
- const event = new ButtonClickEvent();
- this.setState({ clicked: true });
+ const event = new ButtonClickEvent()
+ this.setState({ clicked: true })
if (this.props.onClick) {
- await this.props.onClick(event);
+ await this.props.onClick(event)
if (!this.unmounted && event.canEnable()) {
- this.setState({ clicked: false });
+ this.setState({ clicked: false })
}
}
- };
+ }
public render() {
const className = classSet({
@@ -78,27 +78,27 @@ export class Button extends React.Component {
[`m-${this.props.color}`]: this.props.color,
"m-loading": this.state.clicked,
"m-disabled": this.state.clicked || this.props.disabled,
- [this.props.className!]: this.props.className,
- });
+ [this.props.className || ""]: this.props.className,
+ })
if (this.props.href) {
return (
{this.props.children}
- );
+ )
} else if (this.props.onClick) {
return (
{this.props.children}
- );
+ )
} else {
return (
{this.props.children}
- );
+ )
}
}
}
diff --git a/public/components/common/DropDown.tsx b/public/components/common/DropDown.tsx
index f5f2e14e6..707ba9c8f 100644
--- a/public/components/common/DropDown.tsx
+++ b/public/components/common/DropDown.tsx
@@ -1,147 +1,147 @@
-import React from "react";
-import { classSet } from "@fider/services";
+import React from "react"
+import { classSet } from "@fider/services"
-import "./DropDown.scss";
+import "./DropDown.scss"
export interface DropDownItem {
- value: any;
- label: string;
- render?: JSX.Element;
+ value: any
+ label: string
+ render?: JSX.Element
}
export interface DropDownProps {
- className?: string;
- defaultValue?: any;
- items: (DropDownItem | undefined | false)[];
- placeholder?: string;
- searchable?: boolean;
- inline?: boolean;
- style: "normal" | "simple";
- highlightSelected?: boolean;
- header?: string;
- direction?: "left" | "right";
- onChange?: (item: DropDownItem) => void;
- onSearchChange?: (e: React.FormEvent) => void;
- renderText?: (item?: DropDownItem) => JSX.Element | string | undefined;
- renderControl?: (item?: DropDownItem) => JSX.Element | string | undefined;
+ className?: string
+ defaultValue?: any
+ items: (DropDownItem | undefined | false)[]
+ placeholder?: string
+ searchable?: boolean
+ inline?: boolean
+ style: "normal" | "simple"
+ highlightSelected?: boolean
+ header?: string
+ direction?: "left" | "right"
+ onChange?: (item: DropDownItem) => void
+ onSearchChange?: (e: React.FormEvent) => void
+ renderText?: (item?: DropDownItem) => JSX.Element | string | undefined
+ renderControl?: (item?: DropDownItem) => JSX.Element | string | undefined
}
export interface DropDownState {
- isOpen: boolean;
- selected?: DropDownItem;
+ isOpen: boolean
+ selected?: DropDownItem
}
export class DropDown extends React.Component {
- private rootElementRef: React.RefObject;
- private mounted = false;
+ private rootElementRef: React.RefObject
+ private mounted = false
public static defaultProps: Partial = {
direction: "right",
style: "normal",
highlightSelected: true,
- };
+ }
constructor(props: DropDownProps) {
- super(props);
- this.rootElementRef = React.createRef();
+ super(props)
+ this.rootElementRef = React.createRef()
this.state = {
selected: this.findItem(props.defaultValue, props.items),
isOpen: false,
- };
+ }
}
public componentDidMount() {
- this.mounted = true;
+ this.mounted = true
}
public componentWillUnmount() {
- this.mounted = false;
- this.removeListeners();
+ this.mounted = false
+ this.removeListeners()
}
private addListeners() {
- document.addEventListener("click", this.handleDocumentClick, false);
- document.addEventListener("touchend", this.handleDocumentClick, false);
+ document.addEventListener("click", this.handleDocumentClick, false)
+ document.addEventListener("touchend", this.handleDocumentClick, false)
}
private removeListeners() {
- document.removeEventListener("click", this.handleDocumentClick, false);
- document.removeEventListener("touchend", this.handleDocumentClick, false);
+ document.removeEventListener("click", this.handleDocumentClick, false)
+ document.removeEventListener("touchend", this.handleDocumentClick, false)
}
public handleMouseDown = (event: any) => {
if (event.type === "mousedown" && event.button !== 0) {
- return;
+ return
}
- event.stopPropagation();
- event.preventDefault();
+ event.stopPropagation()
+ event.preventDefault()
this.setState(
{
isOpen: true,
},
this.addListeners
- );
- };
+ )
+ }
public findItem(value: any, items: (DropDownItem | undefined | false)[]): DropDownItem | undefined {
for (const item of items) {
if (item && item.value === value) {
- return item;
+ return item
}
}
- return undefined;
+ return undefined
}
public setSelected(selected: DropDownItem) {
const newState = {
selected,
isOpen: false,
- };
- this.fireChangeEvent(newState);
- this.setState(newState, this.removeListeners);
+ }
+ this.fireChangeEvent(newState)
+ this.setState(newState, this.removeListeners)
}
public fireChangeEvent(newState: DropDownState) {
if (newState.selected && newState.selected !== this.state.selected && this.props.onChange) {
- this.props.onChange(newState.selected);
+ this.props.onChange(newState.selected)
}
}
public renderItem = (item: DropDownItem | undefined | false) => {
if (!item) {
- return;
+ return
}
- const { label, value } = item;
- const isSelected = this.props.highlightSelected && this.state.selected && value === this.state.selected.value;
+ const { label, value } = item
+ const isSelected = this.props.highlightSelected && this.state.selected && value === this.state.selected.value
const className = classSet({
"c-dropdown-item": true,
"is-selected": isSelected,
- });
+ })
return (
{item.render ? item.render : label}
- );
- };
+ )
+ }
public buildItemList() {
- const items = this.props.items.map(this.renderItem);
+ const items = this.props.items.map(this.renderItem)
return (
{this.props.header &&
{this.props.header}
}
{items.length ? items :
No results found
}
- );
+ )
}
public handleDocumentClick = (event: any) => {
if (this.mounted) {
- const node = this.rootElementRef.current;
+ const node = this.rootElementRef.current
if (node && !node.contains(event.target)) {
if (this.state.isOpen) {
this.setState(
@@ -149,16 +149,16 @@ export class DropDown extends React.Component {
isOpen: false,
},
this.removeListeners
- );
+ )
}
}
}
- };
+ }
public render() {
- const text = this.state.selected ? this.state.selected.label : {this.props.placeholder} ;
+ const text = this.state.selected ? this.state.selected.label : {this.props.placeholder}
- const search = ;
+ const search =
const dropdownClass = classSet({
"c-dropdown": true,
@@ -168,7 +168,7 @@ export class DropDown extends React.Component {
"is-inline": this.props.inline,
"m-right": this.props.direction === "right",
"m-left": this.props.direction === "left",
- });
+ })
return (
@@ -184,6 +184,6 @@ export class DropDown extends React.Component {
{this.state.isOpen && this.buildItemList()}
- );
+ )
}
}
diff --git a/public/components/common/EnvironmentInfo.tsx b/public/components/common/EnvironmentInfo.tsx
index 3945d0ce0..e33661f76 100644
--- a/public/components/common/EnvironmentInfo.tsx
+++ b/public/components/common/EnvironmentInfo.tsx
@@ -1,17 +1,18 @@
-import React from "react";
-import { useFider } from "@fider/hooks";
+import React from "react"
+import { useFider } from "@fider/hooks"
export const EnvironmentInfo = () => {
- const fider = useFider();
+ const fider = useFider()
if (fider.isProduction()) {
- return null;
+ return null
}
return (
- Env: {fider.settings.environment} | Compiler: {fider.settings.compiler} | Version: {fider.settings.version} | BuildTime: {fider.settings.buildTime || "N/A"} |
- {!fider.isSingleHostMode() && `TenantID: ${fider.session.tenant.id}`} | {fider.session.isAuthenticated && `UserID: ${fider.session.user.id}`}
+ Env: {fider.settings.environment} | Compiler: {fider.settings.compiler} | Version: {fider.settings.version} | BuildTime:{" "}
+ {fider.settings.buildTime || "N/A"} |{!fider.isSingleHostMode() && `TenantID: ${fider.session.tenant.id}`} |{" "}
+ {fider.session.isAuthenticated && `UserID: ${fider.session.user.id}`}
- );
-};
+ )
+}
diff --git a/public/components/common/FiderVersion.tsx b/public/components/common/FiderVersion.tsx
index 6aa3c2d96..b8c5d00e7 100644
--- a/public/components/common/FiderVersion.tsx
+++ b/public/components/common/FiderVersion.tsx
@@ -1,17 +1,17 @@
-import React from "react";
-import { useFider } from "@fider/hooks";
+import React from "react"
+import { useFider } from "@fider/hooks"
export const FiderVersion = () => {
- const fider = useFider();
+ const fider = useFider()
return (
Support our{" "}
-
+
OpenCollective
Fider v{fider.settings.version}
- );
-};
+ )
+}
diff --git a/public/components/common/Footer.tsx b/public/components/common/Footer.tsx
index 513b0dc0a..a9ef06c0f 100644
--- a/public/components/common/Footer.tsx
+++ b/public/components/common/Footer.tsx
@@ -1,27 +1,16 @@
-import "./Footer.scss";
+import "./Footer.scss"
-import React from "react";
-import { PrivacyPolicy, TermsOfService } from "@fider/components";
-import { useFider } from "@fider/hooks";
+import React from "react"
export const Footer = () => {
- const fider = useFider();
-
return (
- );
-};
+ )
+}
diff --git a/public/components/common/Header.tsx b/public/components/common/Header.tsx
index ed73ed6bf..1d5b9e780 100644
--- a/public/components/common/Header.tsx
+++ b/public/components/common/Header.tsx
@@ -1,33 +1,33 @@
-import "./Header.scss";
+import "./Header.scss"
-import React, { useState, useEffect } from "react";
-import { SignInModal, EnvironmentInfo, Avatar, TenantLogo } from "@fider/components";
-import { actions } from "@fider/services";
-import { FaUser, FaCog, FaCaretDown } from "react-icons/fa";
-import { useFider } from "@fider/hooks";
+import React, { useState, useEffect } from "react"
+import { SignInModal, EnvironmentInfo, Avatar, TenantLogo } from "@fider/components"
+import { actions } from "@fider/services"
+import { FaUser, FaCog, FaCaretDown } from "react-icons/fa"
+import { useFider } from "@fider/hooks"
export const Header = () => {
- const fider = useFider();
- const [isSignInModalOpen, setIsSignInModalOpen] = useState(false);
- const [unreadNotifications, setUnreadNotifications] = useState(0);
+ const fider = useFider()
+ const [isSignInModalOpen, setIsSignInModalOpen] = useState(false)
+ const [unreadNotifications, setUnreadNotifications] = useState(0)
useEffect(() => {
if (fider.session.isAuthenticated) {
actions.getTotalUnreadNotifications().then((result) => {
if (result.ok && result.data > 0) {
- setUnreadNotifications(result.data);
+ setUnreadNotifications(result.data)
}
- });
+ })
}
- }, [fider.session.isAuthenticated]);
+ }, [fider.session.isAuthenticated])
const showModal = () => {
if (!fider.session.isAuthenticated) {
- setIsSignInModalOpen(true);
+ setIsSignInModalOpen(true)
}
- };
+ }
- const hideModal = () => setIsSignInModalOpen(false);
+ const hideModal = () => setIsSignInModalOpen(false)
const items = fider.session.isAuthenticated && (
@@ -55,9 +55,9 @@ export const Header = () => {
Sign out
- );
+ )
- const showRightMenu = fider.session.isAuthenticated || !fider.session.tenant.isPrivate;
+ const showRightMenu = fider.session.isAuthenticated || !fider.session.tenant.isPrivate
return (
- );
-};
+ )
+}
diff --git a/public/components/common/Heading.tsx b/public/components/common/Heading.tsx
index 621fefb68..2985013c6 100644
--- a/public/components/common/Heading.tsx
+++ b/public/components/common/Heading.tsx
@@ -1,36 +1,37 @@
-import "./Heading.scss";
+import "./Heading.scss"
-import React from "react";
-import { classSet } from "@fider/services";
-import { IconType } from "react-icons";
+import React from "react"
+import { classSet } from "@fider/services"
+import { IconType } from "react-icons"
interface HeadingLogo {
- title: string;
- dividing?: boolean;
- size?: "normal" | "small";
- icon?: IconType;
- subtitle?: string;
- className?: string;
+ title: string
+ dividing?: boolean
+ size?: "normal" | "small"
+ icon?: IconType
+ subtitle?: string
+ className?: string
}
-const Header: React.FunctionComponent<{ level: number; className: string }> = (props) => React.createElement(`h${props.level}`, { className: props.className }, props.children);
+const Header: React.FunctionComponent<{ level: number; className: string }> = (props) =>
+ React.createElement(`h${props.level}`, { className: props.className }, props.children)
export const Heading = (props: HeadingLogo) => {
- const size = props.size || "normal";
- const level = size === "normal" ? 2 : 3;
+ const size = props.size || "normal"
+ const level = size === "normal" ? 2 : 3
const className = classSet({
"c-heading": true,
"m-dividing": props.dividing || false,
[`m-${size}`]: true,
[`${props.className}`]: props.className,
- });
+ })
const iconClassName = classSet({
"c-heading-icon": true,
circular: level <= 2,
- });
+ })
- const icon = props.icon && {React.createElement(props.icon)}
;
+ const icon = props.icon && {React.createElement(props.icon)}
return (
@@ -40,5 +41,5 @@ export const Heading = (props: HeadingLogo) => {
{props.subtitle}
- );
-};
+ )
+}
diff --git a/public/components/common/Hint.tsx b/public/components/common/Hint.tsx
index 43b96bca6..cf5692537 100644
--- a/public/components/common/Hint.tsx
+++ b/public/components/common/Hint.tsx
@@ -1,33 +1,33 @@
-import "./Hint.scss";
+import "./Hint.scss"
-import React, { useState } from "react";
-import { FaTimes } from "react-icons/fa";
+import React, { useState } from "react"
+import { FaTimes } from "react-icons/fa"
-import { cache } from "@fider/services";
+import { cache } from "@fider/services"
interface HintProps {
- permanentCloseKey?: string;
- condition?: boolean;
+ permanentCloseKey?: string
+ condition?: boolean
}
export const Hint: React.FC = (props) => {
- const cacheKey: string | undefined = props.permanentCloseKey ? `Hint-Closed-${props.permanentCloseKey}` : undefined;
- const [isClosed, setIsClosed] = useState(cacheKey ? cache.local.has(cacheKey) : false);
+ const cacheKey: string | undefined = props.permanentCloseKey ? `Hint-Closed-${props.permanentCloseKey}` : undefined
+ const [isClosed, setIsClosed] = useState(cacheKey ? cache.local.has(cacheKey) : false)
const close = () => {
if (cacheKey) {
- cache.local.set(cacheKey, "true");
+ cache.local.set(cacheKey, "true")
}
- setIsClosed(true);
- };
+ setIsClosed(true)
+ }
if (props.condition === false || isClosed) {
- return null;
+ return null
}
return (
HINT: {props.children}
{cacheKey && }
- );
-};
+ )
+}
diff --git a/public/components/common/Legal.tsx b/public/components/common/Legal.tsx
index 9285dd70c..dababcb98 100644
--- a/public/components/common/Legal.tsx
+++ b/public/components/common/Legal.tsx
@@ -1,72 +1,72 @@
-import React from "react";
-import { Modal, Checkbox } from "@fider/components/common";
-import { useFider } from "@fider/hooks";
+import React from "react"
+import { Modal, Checkbox } from "@fider/components/common"
+import { useFider } from "@fider/hooks"
interface LegalAgreementProps {
- onChange: (agreed: boolean) => void;
+ onChange: (agreed: boolean) => void
}
-export const TermsOfService: React.FunctionComponent<{}> = () => {
- const fider = useFider();
+export const TermsOfService: React.FunctionComponent = () => {
+ const fider = useFider()
if (fider.settings.hasLegal) {
return (
Terms of Service
- );
+ )
}
- return null;
-};
+ return null
+}
-export const PrivacyPolicy: React.FunctionComponent<{}> = () => {
- const fider = useFider();
+export const PrivacyPolicy: React.FunctionComponent = () => {
+ const fider = useFider()
if (fider.settings.hasLegal) {
return (
Privacy Policy
- );
+ )
}
- return null;
-};
+ return null
+}
-export const LegalNotice: React.FunctionComponent<{}> = () => {
- const fider = useFider();
+export const LegalNotice: React.FunctionComponent = () => {
+ const fider = useFider()
if (fider.settings.hasLegal) {
return (
By signing in, you agree to the and .
- );
+ )
}
- return null;
-};
+ return null
+}
-export const LegalFooter: React.FunctionComponent<{}> = () => {
- const fider = useFider();
+export const LegalFooter: React.FunctionComponent = () => {
+ const fider = useFider()
if (fider.settings.hasLegal) {
return (
- );
+ )
}
- return null;
-};
+ return null
+}
export const LegalAgreement: React.FunctionComponent = (props) => {
- const fider = useFider();
+ const fider = useFider()
if (fider.settings.hasLegal) {
return (
I have read and agree to the and .
- );
+ )
}
- return null;
-};
+ return null
+}
diff --git a/public/components/common/List.tsx b/public/components/common/List.tsx
index d3f6e7c6c..0e5e0ab07 100644
--- a/public/components/common/List.tsx
+++ b/public/components/common/List.tsx
@@ -1,17 +1,17 @@
-import "./List.scss";
+import "./List.scss"
-import React from "react";
-import { classSet } from "@fider/services";
+import React from "react"
+import { classSet } from "@fider/services"
interface ListProps {
- className?: string;
- divided?: boolean;
- hover?: boolean;
+ className?: string
+ divided?: boolean
+ hover?: boolean
}
interface ListItemProps {
- className?: string;
- onClick?: () => void;
+ className?: string
+ onClick?: () => void
}
export const List: React.FunctionComponent = (props) => {
@@ -20,24 +20,24 @@ export const List: React.FunctionComponent = (props) => {
[props.className || ""]: true,
"m-divided": props.divided,
"m-hover": props.hover,
- });
+ })
- return {props.children}
;
-};
+ return {props.children}
+}
export const ListItem: React.FunctionComponent = (props) => {
const className = classSet({
"c-list-item": true,
[props.className || ""]: true,
"m-selectable": props.onClick,
- });
+ })
if (props.onClick) {
return (
{props.children}
- );
+ )
}
- return {props.children}
;
-};
+ return {props.children}
+}
diff --git a/public/components/common/Loader.tsx b/public/components/common/Loader.tsx
index ce0beb2dd..a5b7ac3f4 100644
--- a/public/components/common/Loader.tsx
+++ b/public/components/common/Loader.tsx
@@ -1,14 +1,14 @@
-import "./Loader.scss";
+import "./Loader.scss"
-import React, { useState } from "react";
-import { useTimeout } from "@fider/hooks";
+import React, { useState } from "react"
+import { useTimeout } from "@fider/hooks"
export function Loader() {
- const [show, setShow] = useState(false);
+ const [show, setShow] = useState(false)
useTimeout(() => {
- setShow(true);
- }, 500);
+ setShow(true)
+ }, 500)
- return show ?
: null;
+ return show ?
: null
}
diff --git a/public/components/common/Logo.tsx b/public/components/common/Logo.tsx
index 38f46a81c..980ae1265 100644
--- a/public/components/common/Logo.tsx
+++ b/public/components/common/Logo.tsx
@@ -1,44 +1,44 @@
-import React from "react";
-import { uploadedImageURL } from "@fider/services";
-import { useFider } from "@fider/hooks";
-import { Tenant } from "@fider/models";
+import React from "react"
+import { uploadedImageURL } from "@fider/services"
+import { useFider } from "@fider/hooks"
+import { Tenant } from "@fider/models"
-type Size = 24 | 50 | 100 | 200;
+type Size = 24 | 50 | 100 | 200
interface TenantLogoProps {
- size: Size;
- useFiderIfEmpty?: boolean;
+ size: Size
+ useFiderIfEmpty?: boolean
}
export const TenantLogoURL = (tenant: Tenant, size: Size): string | undefined => {
if (tenant && tenant.logoBlobKey) {
- return uploadedImageURL(tenant.logoBlobKey, size);
+ return uploadedImageURL(tenant.logoBlobKey, size)
}
- return undefined;
-};
+ return undefined
+}
export const TenantLogo = (props: TenantLogoProps) => {
- const fider = useFider();
+ const fider = useFider()
- const tenant = fider.session.tenant;
+ const tenant = fider.session.tenant
if (tenant && tenant.logoBlobKey) {
- return ;
+ return
} else if (props.useFiderIfEmpty) {
- return ;
+ return
}
- return null;
-};
+ return null
+}
TenantLogo.defaultProps = {
useFiderIfEmpty: false,
-};
+}
interface OAuthProviderLogoProps {
option: {
- provider?: string;
- displayName: string;
- logoBlobKey?: string;
- };
+ provider?: string
+ displayName: string
+ logoBlobKey?: string
+ }
}
const systemProvidersLogo: { [key: string]: string } = {
@@ -46,23 +46,23 @@ const systemProvidersLogo: { [key: string]: string } = {
facebook: `data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiA/PjwhRE9DVFlQRSBzdmcgIFBVQkxJQyAnLS8vVzNDLy9EVEQgU1ZHIDEuMC8vRU4nICAnaHR0cDovL3d3dy53My5vcmcvVFIvMjAwMS9SRUMtU1ZHLTIwMDEwOTA0L0RURC9zdmcxMC5kdGQnPjxzdmcgZW5hYmxlLWJhY2tncm91bmQ9Im5ldyAwIDAgMzIgMzIiIGhlaWdodD0iMzJweCIgaWQ9IkxheWVyXzEiIHZlcnNpb249IjEuMCIgdmlld0JveD0iMCAwIDMyIDMyIiB3aWR0aD0iMzJweCIgeG1sOnNwYWNlPSJwcmVzZXJ2ZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayI+PGc+PHBhdGggZD0iTTMyLDMwYzAsMS4xMDQtMC44OTYsMi0yLDJIMmMtMS4xMDQsMC0yLTAuODk2LTItMlYyYzAtMS4xMDQsMC44OTYtMiwyLTJoMjhjMS4xMDQsMCwyLDAuODk2LDIsMlYzMHoiIGZpbGw9IiMzQjU5OTgiLz48cGF0aCBkPSJNMjIsMzJWMjBoNGwxLTVoLTV2LTJjMC0yLDEuMDAyLTMsMy0zaDJWNWMtMSwwLTIuMjQsMC00LDBjLTMuNjc1LDAtNiwyLjg4MS02LDd2M2gtNHY1aDR2MTJIMjJ6IiBmaWxsPSIjRkZGRkZGIiBpZD0iZiIvPjwvZz48Zy8+PGcvPjxnLz48Zy8+PGcvPjxnLz48L3N2Zz4=`,
github:
"data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiA/PjwhRE9DVFlQRSBzdmcgIFBVQkxJQyAnLS8vVzNDLy9EVEQgU1ZHIDEuMC8vRU4nICAnaHR0cDovL3d3dy53My5vcmcvVFIvMjAwMS9SRUMtU1ZHLTIwMDEwOTA0L0RURC9zdmcxMC5kdGQnPjxzdmcgZW5hYmxlLWJhY2tncm91bmQ9Im5ldyAwIDAgMzIgMzIiIGhlaWdodD0iMzJweCIgaWQ9IkxheWVyXzEiIHZlcnNpb249IjEuMCIgdmlld0JveD0iMCAwIDMyIDMyIiB3aWR0aD0iMzJweCIgeG1sOnNwYWNlPSJwcmVzZXJ2ZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayI+PHBhdGggY2xpcC1ydWxlPSJldmVub2RkIiBkPSJNMTYuMDAzLDBDNy4xNywwLDAuMDA4LDcuMTYyLDAuMDA4LDE1Ljk5NyAgYzAsNy4wNjcsNC41ODIsMTMuMDYzLDEwLjk0LDE1LjE3OWMwLjgsMC4xNDYsMS4wNTItMC4zMjgsMS4wNTItMC43NTJjMC0wLjM4LDAuMDA4LTEuNDQyLDAtMi43NzcgIGMtNC40NDksMC45NjctNS4zNzEtMi4xMDctNS4zNzEtMi4xMDdjLTAuNzI3LTEuODQ4LTEuNzc1LTIuMzQtMS43NzUtMi4zNGMtMS40NTItMC45OTIsMC4xMDktMC45NzMsMC4xMDktMC45NzMgIGMxLjYwNSwwLjExMywyLjQ1MSwxLjY0OSwyLjQ1MSwxLjY0OWMxLjQyNywyLjQ0MywzLjc0MywxLjczNyw0LjY1NCwxLjMyOWMwLjE0Ni0xLjAzNCwwLjU2LTEuNzM5LDEuMDE3LTIuMTM5ICBjLTMuNTUyLTAuNDA0LTcuMjg2LTEuNzc2LTcuMjg2LTcuOTA2YzAtMS43NDcsMC42MjMtMy4xNzQsMS42NDYtNC4yOTJDNy4yOCwxMC40NjQsNi43Myw4LjgzNyw3LjYwMiw2LjYzNCAgYzAsMCwxLjM0My0wLjQzLDQuMzk4LDEuNjQxYzEuMjc2LTAuMzU1LDIuNjQ1LTAuNTMyLDQuMDA1LTAuNTM4YzEuMzU5LDAuMDA2LDIuNzI3LDAuMTgzLDQuMDA1LDAuNTM4ICBjMy4wNTUtMi4wNyw0LjM5Ni0xLjY0MSw0LjM5Ni0xLjY0MWMwLjg3MiwyLjIwMywwLjMyMywzLjgzLDAuMTU5LDQuMjM0YzEuMDIzLDEuMTE4LDEuNjQ0LDIuNTQ1LDEuNjQ0LDQuMjkyICBjMCw2LjE0Ni0zLjc0LDcuNDk4LTcuMzA0LDcuODkzQzE5LjQ3OSwyMy41NDgsMjAsMjQuNTA4LDIwLDI2YzAsMiwwLDMuOTAyLDAsNC40MjhjMCwwLjQyOCwwLjI1OCwwLjkwMSwxLjA3LDAuNzQ2ICBDMjcuNDIyLDI5LjA1NSwzMiwyMy4wNjIsMzIsMTUuOTk3QzMyLDcuMTYyLDI0LjgzOCwwLDE2LjAwMywweiIgZmlsbD0iIzE4MTYxNiIgZmlsbC1ydWxlPSJldmVub2RkIi8+PGcvPjxnLz48Zy8+PGcvPjxnLz48Zy8+PC9zdmc+",
-};
+}
export const OAuthProviderLogoURL = (logoBlobKey?: string): string | undefined => {
if (logoBlobKey) {
- return uploadedImageURL(logoBlobKey, 100);
+ return uploadedImageURL(logoBlobKey, 100)
}
- return undefined;
-};
+ return undefined
+}
export const OAuthProviderLogo = (props: OAuthProviderLogoProps) => {
if (props.option.logoBlobKey) {
- return ;
+ return
}
if (props.option.provider && props.option.provider in systemProvidersLogo) {
- return ;
+ return
}
- return null;
-};
+ return null
+}
diff --git a/public/components/common/Message.tsx b/public/components/common/Message.tsx
index 82d4477b8..0e28e5f46 100644
--- a/public/components/common/Message.tsx
+++ b/public/components/common/Message.tsx
@@ -1,26 +1,26 @@
-import "./Message.scss";
+import "./Message.scss"
-import React from "react";
-import { classSet } from "@fider/services";
-import { FaBan, FaRegCheckCircle, FaExclamationTriangle } from "react-icons/fa";
+import React from "react"
+import { classSet } from "@fider/services"
+import { FaBan, FaRegCheckCircle, FaExclamationTriangle } from "react-icons/fa"
interface MessageProps {
- type: "success" | "warning" | "error";
- showIcon?: boolean;
+ type: "success" | "warning" | "error"
+ showIcon?: boolean
}
export const Message: React.FunctionComponent = (props) => {
const className = classSet({
"c-message": true,
[`m-${props.type}`]: true,
- });
+ })
- const icon = props.type === "error" ? : props.type === "warning" ? : ;
+ const icon = props.type === "error" ? : props.type === "warning" ? :
return (
{props.showIcon === true && icon}
{props.children}
- );
-};
+ )
+}
diff --git a/public/components/common/Modal.tsx b/public/components/common/Modal.tsx
index 0cafa7504..fe359b5bc 100644
--- a/public/components/common/Modal.tsx
+++ b/public/components/common/Modal.tsx
@@ -1,55 +1,55 @@
-import "./Modal.scss";
+import "./Modal.scss"
-import React, { useEffect, useRef } from "react";
-import ReactDOM from "react-dom";
-import { classSet } from "@fider/services";
+import React, { useEffect, useRef } from "react"
+import ReactDOM from "react-dom"
+import { classSet } from "@fider/services"
interface ModalWindowProps {
- className?: string;
- isOpen: boolean;
- size?: "small" | "large" | "fluid";
- canClose?: boolean;
- center?: boolean;
- onClose: () => void;
+ className?: string
+ isOpen: boolean
+ size?: "small" | "large" | "fluid"
+ canClose?: boolean
+ center?: boolean
+ onClose: () => void
}
interface ModalFooterProps {
- align?: "left" | "center" | "right";
- children?: React.ReactNode;
+ align?: "left" | "center" | "right"
+ children?: React.ReactNode
}
const ModalWindow: React.FunctionComponent = (props) => {
- const root = useRef(document.getElementById("root-modal"));
+ const root = useRef(document.getElementById("root-modal"))
useEffect(() => {
if (props.isOpen) {
- document.body.style.overflow = "hidden";
- document.addEventListener("keydown", keyDown, false);
+ document.body.style.overflow = "hidden"
+ document.addEventListener("keydown", keyDown, false)
} else {
- document.body.style.overflow = "";
- document.removeEventListener("keydown", keyDown, false);
+ document.body.style.overflow = ""
+ document.removeEventListener("keydown", keyDown, false)
}
- }, [props.isOpen]);
+ }, [props.isOpen])
const swallow = (evt: React.MouseEvent) => {
- evt.stopPropagation();
- };
+ evt.stopPropagation()
+ }
const keyDown = (event: KeyboardEvent) => {
if (event.keyCode === 27) {
// ESC
- close();
+ close()
}
- };
+ }
const close = () => {
if (props.canClose) {
- props.onClose();
+ props.onClose()
}
- };
+ }
- if (!props.isOpen) {
- return null;
+ if (!props.isOpen || !root.current) {
+ return null
}
const className = classSet({
@@ -57,7 +57,7 @@ const ModalWindow: React.FunctionComponent = (props) => {
[`${props.className}`]: !!props.className,
"m-center": props.center,
[`m-${props.size}`]: true,
- });
+ })
return ReactDOM.createPortal(
@@ -65,30 +65,30 @@ const ModalWindow: React.FunctionComponent = (props) => {
{props.children}
,
- root.current!
- );
-};
+ root.current
+ )
+}
ModalWindow.defaultProps = {
size: "small",
canClose: true,
center: true,
-};
+}
+
+const Header = (props: { children: React.ReactNode }) => {props.children}
+const Content = (props: { children: React.ReactNode }) => {props.children}
+const Footer = (props: ModalFooterProps) => {
+ const align = props.align || "right"
+ const className = classSet({
+ "c-modal-footer": true,
+ [`m-${align}`]: true,
+ })
+ return {props.children}
+}
export const Modal = {
Window: ModalWindow,
- Header: (props: { children: React.ReactNode }) => {
- return {props.children}
;
- },
- Content: (props: { children: React.ReactNode }) => {
- return {props.children}
;
- },
- Footer: (props: ModalFooterProps) => {
- const align = props.align || "right";
- const className = classSet({
- "c-modal-footer": true,
- [`m-${align}`]: true,
- });
- return {props.children}
;
- },
-};
+ Header,
+ Content,
+ Footer,
+}
diff --git a/public/components/common/Moment.tsx b/public/components/common/Moment.tsx
index f7654d787..be5cdef23 100644
--- a/public/components/common/Moment.tsx
+++ b/public/components/common/Moment.tsx
@@ -1,29 +1,29 @@
-import React from "react";
-import { formatDate, timeSince } from "@fider/services";
+import React from "react"
+import { formatDate, timeSince } from "@fider/services"
interface MomentText {
- date: Date | string;
- useRelative?: boolean;
- format?: "full" | "short";
+ date: Date | string
+ useRelative?: boolean
+ format?: "full" | "short"
}
export const Moment = (props: MomentText) => {
if (!props.date) {
- return ;
+ return
}
- const format = props.format || "full";
- const useRelative = typeof props.useRelative !== "undefined" ? props.useRelative : true;
+ const format = props.format || "full"
+ const useRelative = typeof props.useRelative !== "undefined" ? props.useRelative : true
- const now = new Date();
- const date = props.date instanceof Date ? props.date : new Date(props.date);
+ const now = new Date()
+ const date = props.date instanceof Date ? props.date : new Date(props.date)
- const diff = (now.getTime() - date.getTime()) / (60 * 60 * 24 * 1000);
- const display = !useRelative || diff >= 365 ? formatDate(props.date, format) : timeSince(now, date);
+ const diff = (now.getTime() - date.getTime()) / (60 * 60 * 24 * 1000)
+ const display = !useRelative || diff >= 365 ? formatDate(props.date, format) : timeSince(now, date)
return (
{display}
- );
-};
+ )
+}
diff --git a/public/components/common/MultiLineText.tsx b/public/components/common/MultiLineText.tsx
index a5edca3f3..de0d23825 100644
--- a/public/components/common/MultiLineText.tsx
+++ b/public/components/common/MultiLineText.tsx
@@ -1,17 +1,17 @@
-import React from "react";
-import { markdown } from "@fider/services";
+import React from "react"
+import { markdown } from "@fider/services"
-interface MultiLineText {
- className?: string;
- text?: string;
- style: "full" | "simple";
+interface MultiLineTextProps {
+ className?: string
+ text?: string
+ style: "full" | "simple"
}
-export const MultiLineText = (props: MultiLineText) => {
+export const MultiLineText = (props: MultiLineTextProps) => {
if (!props.text) {
- return
;
+ return
}
- const func = props.style === "full" ? markdown.full : markdown.simple;
- return
;
-};
+ const func = props.style === "full" ? markdown.full : markdown.simple
+ return
+}
diff --git a/public/components/common/Segment.tsx b/public/components/common/Segment.tsx
index 83b5174dd..b9f23235a 100644
--- a/public/components/common/Segment.tsx
+++ b/public/components/common/Segment.tsx
@@ -1,15 +1,15 @@
-import "./Segment.scss";
+import "./Segment.scss"
-import React from "react";
+import React from "react"
interface SegmentProps {
- className?: string;
+ className?: string
}
export const Segments: React.FunctionComponent = (props) => {
- return {props.children}
;
-};
+ return {props.children}
+}
export const Segment: React.FunctionComponent = (props) => {
- return {props.children}
;
-};
+ return {props.children}
+}
diff --git a/public/components/common/SignInControl.tsx b/public/components/common/SignInControl.tsx
index c4d1c873b..d19b0b215 100644
--- a/public/components/common/SignInControl.tsx
+++ b/public/components/common/SignInControl.tsx
@@ -1,35 +1,35 @@
-import "./SignInControl.scss";
+import "./SignInControl.scss"
-import React, { useState } from "react";
-import { SocialSignInButton, Form, Button, Input, Message } from "@fider/components";
-import { device, actions, Failure, isCookieEnabled } from "@fider/services";
-import { useFider } from "@fider/hooks";
+import React, { useState } from "react"
+import { SocialSignInButton, Form, Button, Input, Message } from "@fider/components"
+import { device, actions, Failure, isCookieEnabled } from "@fider/services"
+import { useFider } from "@fider/hooks"
interface SignInControlProps {
- useEmail: boolean;
- redirectTo?: string;
- onEmailSent?: (email: string) => void;
+ useEmail: boolean
+ redirectTo?: string
+ onEmailSent?: (email: string) => void
}
export const SignInControl: React.FunctionComponent = (props) => {
- const fider = useFider();
- const [email, setEmail] = useState("");
- const [error, setError] = useState(undefined);
+ const fider = useFider()
+ const [email, setEmail] = useState("")
+ const [error, setError] = useState(undefined)
const signIn = async () => {
- const result = await actions.signIn(email);
+ const result = await actions.signIn(email)
if (result.ok) {
- setEmail("");
- setError(undefined);
+ setEmail("")
+ setError(undefined)
if (props.onEmailSent) {
- props.onEmailSent(email);
+ props.onEmailSent(email)
}
} else if (result.error) {
- setError(result.error);
+ setError(result.error)
}
- };
+ }
- const providersLen = fider.settings.oauth.length;
+ const providersLen = fider.settings.oauth.length
if (!isCookieEnabled()) {
return (
@@ -37,7 +37,7 @@ export const SignInControl: React.FunctionComponent = (props
Cookies Required
Cookies are not enabled on your browser. Please enable cookies in your browser preferences to continue.
- );
+ )
}
return (
@@ -80,5 +80,5 @@ export const SignInControl: React.FunctionComponent = (props
)}
- );
-};
+ )
+}
diff --git a/public/components/common/SocialSignInButton.tsx b/public/components/common/SocialSignInButton.tsx
index 70d55acf4..286abb878 100644
--- a/public/components/common/SocialSignInButton.tsx
+++ b/public/components/common/SocialSignInButton.tsx
@@ -1,30 +1,30 @@
-import React from "react";
-import { Button, OAuthProviderLogo } from "@fider/components/common";
-import { classSet } from "@fider/services";
+import React from "react"
+import { Button, OAuthProviderLogo } from "@fider/components/common"
+import { classSet } from "@fider/services"
interface SocialSignInButtonProps {
option: {
- displayName: string;
- provider?: string;
- url?: string;
- logoBlobKey?: string;
- logoURL?: string;
- };
- redirectTo?: string;
+ displayName: string
+ provider?: string
+ url?: string
+ logoBlobKey?: string
+ logoURL?: string
+ }
+ redirectTo?: string
}
export const SocialSignInButton = (props: SocialSignInButtonProps) => {
- const redirectTo = props.redirectTo || window.location.href;
- const href = props.option.url ? `${props.option.url}?redirect=${redirectTo}` : undefined;
+ const redirectTo = props.redirectTo || window.location.href
+ const href = props.option.url ? `${props.option.url}?redirect=${redirectTo}` : undefined
const className = classSet({
"m-social": true,
[`m-${props.option.provider}`]: props.option.provider,
- });
+ })
return (
- {props.option.logoURL ? : }
+ {props.option.logoURL ? : }
{props.option.displayName}
- );
-};
+ )
+}
diff --git a/public/components/common/Toggle.tsx b/public/components/common/Toggle.tsx
index c9b572bd3..1f8f0dde4 100644
--- a/public/components/common/Toggle.tsx
+++ b/public/components/common/Toggle.tsx
@@ -1,34 +1,34 @@
-import "./Toggle.scss";
+import "./Toggle.scss"
-import React, { useState } from "react";
-import { classSet } from "@fider/services";
+import React, { useState } from "react"
+import { classSet } from "@fider/services"
interface ToggleProps {
- label?: string;
- active: boolean;
- disabled?: boolean;
- onToggle?: (active: boolean) => void;
+ label?: string
+ active: boolean
+ disabled?: boolean
+ onToggle?: (active: boolean) => void
}
export const Toggle: React.StatelessComponent = (props) => {
- const [active, setActive] = useState(props.active);
+ const [active, setActive] = useState(props.active)
const toggle = () => {
if (props.disabled) {
- return;
+ return
}
- const newActive = !active;
- setActive(newActive);
+ const newActive = !active
+ setActive(newActive)
if (props.onToggle) {
- props.onToggle(newActive);
+ props.onToggle(newActive)
}
- };
+ }
const className = classSet({
"c-toggle": true,
"m-disabled": !!props.disabled,
- });
+ })
return (
@@ -38,5 +38,5 @@ export const Toggle: React.StatelessComponent = (props) => {
{!!props.label && props.label}
- );
-};
+ )
+}
diff --git a/public/components/common/UserName.tsx b/public/components/common/UserName.tsx
index fd38ab405..debbdf633 100644
--- a/public/components/common/UserName.tsx
+++ b/public/components/common/UserName.tsx
@@ -1,22 +1,22 @@
-import "./UserName.scss";
+import "./UserName.scss"
-import React from "react";
-import { isCollaborator, UserRole } from "@fider/models";
-import { classSet } from "@fider/services";
+import React from "react"
+import { isCollaborator, UserRole } from "@fider/models"
+import { classSet } from "@fider/services"
interface UserNameProps {
user: {
- id: number;
- name: string;
- role?: UserRole;
- };
+ id: number
+ name: string
+ role?: UserRole
+ }
}
export const UserName = (props: UserNameProps) => {
const className = classSet({
"c-username": true,
"m-staff": props.user.role && isCollaborator(props.user.role),
- });
+ })
- return {props.user.name || "Anonymous"} ;
-};
+ return {props.user.name || "Anonymous"}
+}
diff --git a/public/components/common/form/Checkbox.tsx b/public/components/common/form/Checkbox.tsx
index 7127085d9..4fea69a14 100644
--- a/public/components/common/form/Checkbox.tsx
+++ b/public/components/common/form/Checkbox.tsx
@@ -1,22 +1,22 @@
-import React, { useState } from "react";
-import { classSet } from "@fider/services";
-import { DisplayError, ValidationContext, hasError } from "../";
+import React, { useState } from "react"
+import { classSet } from "@fider/services"
+import { DisplayError, ValidationContext, hasError } from "../"
interface CheckboxProps {
- field: string;
- checked?: boolean;
- onChange: (checked: boolean) => void;
+ field: string
+ checked?: boolean
+ onChange: (checked: boolean) => void
}
export const Checkbox: React.FC = (props) => {
- const [checked, setChecked] = useState(props.checked || false);
+ const [checked, setChecked] = useState(props.checked || false)
const onChange = (e: React.ChangeEvent) => {
- const isChecked: boolean = e.currentTarget.checked;
+ const isChecked: boolean = e.currentTarget.checked
- setChecked(isChecked);
- props.onChange(isChecked);
- };
+ setChecked(isChecked)
+ props.onChange(isChecked)
+ }
return (
@@ -35,5 +35,5 @@ export const Checkbox: React.FC = (props) => {
)}
- );
-};
+ )
+}
diff --git a/public/components/common/form/DisplayError.spec.tsx b/public/components/common/form/DisplayError.spec.tsx
index c53ea2338..39dfe35d8 100644
--- a/public/components/common/form/DisplayError.spec.tsx
+++ b/public/components/common/form/DisplayError.spec.tsx
@@ -1,39 +1,39 @@
-import React from "react";
-import { shallow } from "enzyme";
-import { DisplayError } from "./DisplayError";
-import { Failure } from "@fider/services";
+import React from "react"
+import { shallow } from "enzyme"
+import { DisplayError } from "./DisplayError"
+import { Failure } from "@fider/services"
describe(" ", () => {
test("when error is undefined", () => {
- const wrapper = shallow( );
- expect(wrapper.getElement()).toBeNull();
+ const wrapper = shallow( )
+ expect(wrapper.getElement()).toBeNull()
- const wrapper1 = shallow( );
- expect(wrapper1.getElement()).toBeNull();
- });
+ const wrapper1 = shallow( )
+ expect(wrapper1.getElement()).toBeNull()
+ })
test("when error has only top level messages and fields is empty", () => {
const error: Failure = {
errors: [{ message: "Something went wrong." }],
- };
+ }
- const wrapper = shallow( );
- const root = wrapper.find("div");
- expect(root.hasClass("c-form-field-error")).toBe(true);
- const items = root.find("ul li");
- expect(items).toHaveLength(1);
- expect(items.at(0).key()).toBe("Something went wrong.");
- expect(items.at(0).text()).toBe("Something went wrong.");
- });
+ const wrapper = shallow( )
+ const root = wrapper.find("div")
+ expect(root.hasClass("c-form-field-error")).toBe(true)
+ const items = root.find("ul li")
+ expect(items).toHaveLength(1)
+ expect(items.at(0).key()).toBe("Something went wrong.")
+ expect(items.at(0).text()).toBe("Something went wrong.")
+ })
test("when error has only top level messages and fields is given", () => {
const error: Failure = {
errors: [{ message: "Something went wrong." }],
- };
+ }
- const wrapper = shallow( );
- expect(wrapper.getElement()).toBeNull();
- });
+ const wrapper = shallow( )
+ expect(wrapper.getElement()).toBeNull()
+ })
test("when error has both field and top level messages and fields are given", () => {
const error: Failure = {
@@ -43,36 +43,36 @@ describe(" ", () => {
{ field: "name", message: "Name must have between 0 and 10 chars" },
{ field: "age", message: "Age must be >= 18" },
],
- };
+ }
- const wrapper1 = shallow( );
- const root1 = wrapper1.find("div");
- expect(root1.hasClass("c-form-field-error")).toBe(true);
- const items1 = root1.find("ul li");
- expect(items1).toHaveLength(2);
- expect(items1.at(0).key()).toBe("Name is required");
- expect(items1.at(0).text()).toBe("Name is required");
- expect(items1.at(1).key()).toBe("Name must have between 0 and 10 chars");
- expect(items1.at(1).text()).toBe("Name must have between 0 and 10 chars");
+ const wrapper1 = shallow( )
+ const root1 = wrapper1.find("div")
+ expect(root1.hasClass("c-form-field-error")).toBe(true)
+ const items1 = root1.find("ul li")
+ expect(items1).toHaveLength(2)
+ expect(items1.at(0).key()).toBe("Name is required")
+ expect(items1.at(0).text()).toBe("Name is required")
+ expect(items1.at(1).key()).toBe("Name must have between 0 and 10 chars")
+ expect(items1.at(1).text()).toBe("Name must have between 0 and 10 chars")
- const wrapper2 = shallow( );
- const root2 = wrapper2.find("div");
- expect(root2.hasClass("c-form-field-error")).toBe(true);
- const items2 = root2.find("ul li");
- expect(items2).toHaveLength(1);
- expect(items2.at(0).key()).toBe("Age must be >= 18");
- expect(items2.at(0).text()).toBe("Age must be >= 18");
+ const wrapper2 = shallow( )
+ const root2 = wrapper2.find("div")
+ expect(root2.hasClass("c-form-field-error")).toBe(true)
+ const items2 = root2.find("ul li")
+ expect(items2).toHaveLength(1)
+ expect(items2.at(0).key()).toBe("Age must be >= 18")
+ expect(items2.at(0).text()).toBe("Age must be >= 18")
- const wrapper3 = shallow( );
- const root3 = wrapper3.find("div");
- expect(root3.hasClass("c-form-field-error")).toBe(true);
- const items3 = root3.find("ul li");
- expect(items3).toHaveLength(3);
- expect(items3.at(0).key()).toBe("Name is required");
- expect(items3.at(0).text()).toBe("Name is required");
- expect(items3.at(1).key()).toBe("Name must have between 0 and 10 chars");
- expect(items3.at(1).text()).toBe("Name must have between 0 and 10 chars");
- expect(items3.at(2).key()).toBe("Age must be >= 18");
- expect(items3.at(2).text()).toBe("Age must be >= 18");
- });
-});
+ const wrapper3 = shallow( )
+ const root3 = wrapper3.find("div")
+ expect(root3.hasClass("c-form-field-error")).toBe(true)
+ const items3 = root3.find("ul li")
+ expect(items3).toHaveLength(3)
+ expect(items3.at(0).key()).toBe("Name is required")
+ expect(items3.at(0).text()).toBe("Name is required")
+ expect(items3.at(1).key()).toBe("Name must have between 0 and 10 chars")
+ expect(items3.at(1).text()).toBe("Name must have between 0 and 10 chars")
+ expect(items3.at(2).key()).toBe("Age must be >= 18")
+ expect(items3.at(2).text()).toBe("Age must be >= 18")
+ })
+})
diff --git a/public/components/common/form/DisplayError.tsx b/public/components/common/form/DisplayError.tsx
index 6cb66bb2e..cc18297c0 100644
--- a/public/components/common/form/DisplayError.tsx
+++ b/public/components/common/form/DisplayError.tsx
@@ -1,46 +1,46 @@
-import React from "react";
-import { Failure } from "@fider/services";
+import React from "react"
+import { Failure } from "@fider/services"
const arrayToTag = (items: string[]) => {
- return items.map((m) => {m} );
-};
+ return items.map((m) => {m} )
+}
interface DisplayErrorProps {
- error?: Failure;
- fields?: string[];
+ error?: Failure
+ fields?: string[]
}
export const hasError = (field?: string, error?: Failure): boolean => {
if (field && error && error.errors) {
for (const err of error.errors) {
if (err.field === field) {
- return true;
+ return true
}
}
}
- return false;
-};
+ return false
+}
export const DisplayError = (props: DisplayErrorProps) => {
if (!props.error || !props.error.errors) {
- return null;
+ return null
}
const dict = props.error.errors.reduce((result, err) => {
- result[err.field || ""] = result[err.field || ""] || [];
- result[err.field || ""].push(err.message);
- return result;
- }, {} as { [key: string]: string[] });
+ result[err.field || ""] = result[err.field || ""] || []
+ result[err.field || ""].push(err.message)
+ return result
+ }, {} as { [key: string]: string[] })
- let items: JSX.Element[] = [];
+ let items: JSX.Element[] = []
if (dict[""] && !props.fields) {
- items = arrayToTag(dict[""]);
+ items = arrayToTag(dict[""])
} else if (props.fields) {
for (const field of props.fields || Object.keys(dict)) {
- if (dict.hasOwnProperty(field)) {
- const tags = arrayToTag(dict[field]);
- tags.forEach((t) => items.push(t));
+ if (Object.prototype.hasOwnProperty.call(dict, field)) {
+ const tags = arrayToTag(dict[field])
+ tags.forEach((t) => items.push(t))
}
}
}
@@ -49,5 +49,5 @@ export const DisplayError = (props: DisplayErrorProps) => {
- ) : null;
-};
+ ) : null
+}
diff --git a/public/components/common/form/Field.tsx b/public/components/common/form/Field.tsx
index 9bcf2b9b1..805f14023 100644
--- a/public/components/common/form/Field.tsx
+++ b/public/components/common/form/Field.tsx
@@ -1,17 +1,17 @@
-import React from "react";
-import { classSet } from "@fider/services";
-import { ValidationContext } from "./Form";
-import { DisplayError, hasError } from "./DisplayError";
+import React from "react"
+import { classSet } from "@fider/services"
+import { ValidationContext } from "./Form"
+import { DisplayError, hasError } from "./DisplayError"
interface FieldProps {
- className?: string;
- label?: string;
- field?: string;
- afterLabel?: JSX.Element;
+ className?: string
+ label?: string
+ field?: string
+ afterLabel?: JSX.Element
}
export const Field: React.FunctionComponent = (props) => {
- const fields = props.field ? [props.field] : undefined;
+ const fields = props.field ? [props.field] : undefined
return (
{(ctx) => (
@@ -19,7 +19,7 @@ export const Field: React.FunctionComponent = (props) => {
className={classSet({
"c-form-field": true,
"m-error": hasError(props.field, ctx.error),
- [props.className!]: props.className,
+ [props.className || ""]: props.className,
})}
>
{!!props.label && (
@@ -33,5 +33,5 @@ export const Field: React.FunctionComponent = (props) => {
)}
- );
-};
+ )
+}
diff --git a/public/components/common/form/Form.tsx b/public/components/common/form/Form.tsx
index 2ee58d875..b2a397a9b 100644
--- a/public/components/common/form/Form.tsx
+++ b/public/components/common/form/Form.tsx
@@ -1,32 +1,32 @@
-import "./Form.scss";
+import "./Form.scss"
-import React from "react";
-import { Failure, classSet } from "@fider/services";
-import { DisplayError } from "@fider/components";
+import React from "react"
+import { Failure, classSet } from "@fider/services"
+import { DisplayError } from "@fider/components"
interface ValidationContext {
- error?: Failure;
+ error?: Failure
}
interface FormProps {
- className?: string;
- size?: "mini" | "normal";
- error?: Failure;
+ className?: string
+ size?: "mini" | "normal"
+ error?: Failure
}
-export const ValidationContext = React.createContext({});
+export const ValidationContext = React.createContext({})
export const Form: React.FunctionComponent = (props) => {
const className = classSet({
"c-form": true,
- [props.className!]: props.className,
+ [props.className || ""]: props.className,
[`m-${props.size}`]: props.size,
- });
+ })
return (
- );
-};
+ )
+}
diff --git a/public/components/common/form/ImageUploader.tsx b/public/components/common/form/ImageUploader.tsx
index 4080a109a..8d4019875 100644
--- a/public/components/common/form/ImageUploader.tsx
+++ b/public/components/common/form/ImageUploader.tsx
@@ -1,52 +1,52 @@
-import "./ImageUploader.scss";
+import "./ImageUploader.scss"
-import React from "react";
-import { ValidationContext } from "./Form";
-import { DisplayError, hasError } from "./DisplayError";
-import { classSet, fileToBase64, uploadedImageURL } from "@fider/services";
-import { Button, ButtonClickEvent, Modal } from "@fider/components";
-import { FaRegImage } from "react-icons/fa";
-import { ImageUpload } from "@fider/models";
+import React from "react"
+import { ValidationContext } from "./Form"
+import { DisplayError, hasError } from "./DisplayError"
+import { classSet, fileToBase64, uploadedImageURL } from "@fider/services"
+import { Button, Modal } from "@fider/components"
+import { FaRegImage } from "react-icons/fa"
+import { ImageUpload } from "@fider/models"
-const hardFileSizeLimit = 5 * 1024 * 1024;
+const hardFileSizeLimit = 5 * 1024 * 1024
interface ImageUploaderProps {
- instanceID?: string;
- field: string;
- label?: string;
- bkey?: string;
- disabled?: boolean;
- previewMaxWidth: number;
- onChange(state: ImageUpload, instanceID?: string, previewURL?: string): void;
+ instanceID?: string
+ field: string
+ label?: string
+ bkey?: string
+ disabled?: boolean
+ previewMaxWidth: number
+ onChange(state: ImageUpload, instanceID?: string, previewURL?: string): void
}
interface ImageUploaderState extends ImageUpload {
- previewURL?: string;
- showModal: boolean;
+ previewURL?: string
+ showModal: boolean
}
export class ImageUploader extends React.Component {
- private fileSelector?: HTMLInputElement | null;
+ private fileSelector?: HTMLInputElement | null
constructor(props: ImageUploaderProps) {
- super(props);
+ super(props)
this.state = {
upload: undefined,
remove: false,
showModal: false,
previewURL: uploadedImageURL(this.props.bkey, this.props.previewMaxWidth),
- };
+ }
}
public fileChanged = async (e: React.ChangeEvent) => {
if (e.target.files && e.target.files[0]) {
- const file = e.target.files[0];
+ const file = e.target.files[0]
if (file.size > hardFileSizeLimit) {
- alert("The image size must be smaller than 5MB.");
- return;
+ alert("The image size must be smaller than 5MB.")
+ return
}
- const base64 = await fileToBase64(file);
+ const base64 = await fileToBase64(file)
this.setState(
{
bkey: this.props.bkey,
@@ -59,15 +59,15 @@ export class ImageUploader extends React.Component {
- this.props.onChange(this.state, this.props.instanceID, this.state.previewURL);
+ this.props.onChange(this.state, this.props.instanceID, this.state.previewURL)
}
- );
+ )
}
- };
+ }
- public removeFile = async (e: ButtonClickEvent) => {
+ public removeFile = async () => {
if (this.fileSelector) {
- this.fileSelector.value = "";
+ this.fileSelector.value = ""
}
this.setState(
@@ -86,29 +86,29 @@ export class ImageUploader extends React.Component {
+ public selectFile = async () => {
if (this.fileSelector) {
- this.fileSelector.click();
+ this.fileSelector.click()
}
- };
+ }
private openModal = () => {
- this.setState({ showModal: true });
- };
+ this.setState({ showModal: true })
+ }
private closeModal = async () => {
- this.setState({ showModal: false });
- };
+ this.setState({ showModal: false })
+ }
private modal() {
return (
- {this.props.bkey ? : }
+ {this.props.bkey ? : }
@@ -116,16 +116,16 @@ export class ImageUploader extends React.Component
- );
+ )
}
public render() {
- const isUploading = !!this.state.upload;
- const hasFile = (!this.state.remove && this.props.bkey) || isUploading;
+ const isUploading = !!this.state.upload
+ const hasFile = (!this.state.remove && this.props.bkey) || isUploading
const imgStyles: React.CSSProperties = {
maxWidth: `${this.props.previewMaxWidth}px`,
- };
+ }
return (
@@ -142,7 +142,7 @@ export class ImageUploader extends React.Component
-
+
{!this.props.disabled && (
X
@@ -164,6 +164,6 @@ export class ImageUploader extends React.Component
)}
- );
+ )
}
}
diff --git a/public/components/common/form/ImageViewer.tsx b/public/components/common/form/ImageViewer.tsx
index 09118d759..160079b64 100644
--- a/public/components/common/form/ImageViewer.tsx
+++ b/public/components/common/form/ImageViewer.tsx
@@ -1,54 +1,54 @@
-import React from "react";
-import { uploadedImageURL } from "@fider/services";
-import { Modal, Button, Loader } from "@fider/components";
+import React from "react"
+import { uploadedImageURL } from "@fider/services"
+import { Modal, Button, Loader } from "@fider/components"
-import "./ImageViewer.scss";
+import "./ImageViewer.scss"
interface ImageViewerProps {
- bkey: string;
+ bkey: string
}
interface ImageViewerState {
- showModal: boolean;
- loadedThumbnail: boolean;
- loadedPreview: boolean;
+ showModal: boolean
+ loadedThumbnail: boolean
+ loadedPreview: boolean
}
export class ImageViewer extends React.Component {
constructor(props: ImageViewerProps) {
- super(props);
+ super(props)
this.state = {
showModal: false,
loadedThumbnail: false,
loadedPreview: false,
- };
+ }
}
private openModal = () => {
if (this.state.loadedThumbnail) {
- this.setState({ showModal: true });
+ this.setState({ showModal: true })
}
- };
+ }
private closeModal = async () => {
- this.setState({ showModal: false });
- };
+ this.setState({ showModal: false })
+ }
private onThumbnailLoad = () => {
- this.setState({ loadedThumbnail: true });
- };
+ this.setState({ loadedThumbnail: true })
+ }
private onPreviewLoad = () => {
- this.setState({ loadedPreview: true });
- };
+ this.setState({ loadedPreview: true })
+ }
private modal() {
return (
{!this.state.loadedPreview && }
-
+
@@ -57,17 +57,17 @@ export class ImageViewer extends React.Component
- );
+ )
}
public render() {
- const previewURL = uploadedImageURL(this.props.bkey, 200);
+ const previewURL = uploadedImageURL(this.props.bkey, 200)
return (
{this.modal()}
{!this.state.loadedThumbnail &&
}
-
+
- );
+ )
}
}
diff --git a/public/components/common/form/Input.tsx b/public/components/common/form/Input.tsx
index 36bf78eac..a3eab1c1b 100644
--- a/public/components/common/form/Input.tsx
+++ b/public/components/common/form/Input.tsx
@@ -1,44 +1,44 @@
-import React from "react";
-import { classSet } from "@fider/services";
-import { ValidationContext } from "./Form";
-import { DisplayError, hasError } from "./DisplayError";
-import { IconType } from "react-icons";
+import React from "react"
+import { classSet } from "@fider/services"
+import { ValidationContext } from "./Form"
+import { DisplayError, hasError } from "./DisplayError"
+import { IconType } from "react-icons"
interface InputProps {
- field: string;
- label?: string;
- className?: string;
- autoComplete?: string;
- autoFocus?: boolean;
- noTabFocus?: boolean;
- afterLabel?: JSX.Element;
- icon?: IconType;
- maxLength?: number;
- value?: string;
- disabled?: boolean;
- suffix?: string | JSX.Element;
- placeholder?: string;
- onIconClick?: () => void;
- onFocus?: () => void;
- inputRef?: React.MutableRefObject;
- onChange?: (value: string) => void;
+ field: string
+ label?: string
+ className?: string
+ autoComplete?: string
+ autoFocus?: boolean
+ noTabFocus?: boolean
+ afterLabel?: JSX.Element
+ icon?: IconType
+ maxLength?: number
+ value?: string
+ disabled?: boolean
+ suffix?: string | JSX.Element
+ placeholder?: string
+ onIconClick?: () => void
+ onFocus?: () => void
+ inputRef?: React.MutableRefObject
+ onChange?: (value: string) => void
}
export const Input: React.FunctionComponent = (props) => {
const onChange = (e: React.FormEvent) => {
if (props.onChange) {
- props.onChange(e.currentTarget.value);
+ props.onChange(e.currentTarget.value)
}
- };
+ }
- const suffix = typeof props.suffix === "string" ? {props.suffix} : props.suffix;
+ const suffix = typeof props.suffix === "string" ? {props.suffix} : props.suffix
- const icon = !!props.icon
+ const icon = props.icon
? React.createElement(props.icon, {
onClick: props.onIconClick,
className: classSet({ link: !!props.onIconClick }),
})
- : undefined;
+ : undefined
return (
@@ -81,5 +81,5 @@ export const Input: React.FunctionComponent = (props) => {
)}
- );
-};
+ )
+}
diff --git a/public/components/common/form/MultiImageUploader.tsx b/public/components/common/form/MultiImageUploader.tsx
index 572b9a52e..f66de2d58 100644
--- a/public/components/common/form/MultiImageUploader.tsx
+++ b/public/components/common/form/MultiImageUploader.tsx
@@ -1,93 +1,95 @@
-import React from "react";
-import { ImageUploader } from "./ImageUploader";
-import { ImageUpload } from "@fider/models";
-import { ValidationContext, hasError, DisplayError } from "@fider/components";
-import { classSet } from "@fider/services";
+import React from "react"
+import { ImageUploader } from "./ImageUploader"
+import { ImageUpload } from "@fider/models"
+import { ValidationContext, hasError, DisplayError } from "@fider/components"
+import { classSet } from "@fider/services"
-import "./MultiImageUploader.scss";
+import "./MultiImageUploader.scss"
interface MultiImageUploaderProps {
- field: string;
- maxUploads: number;
- bkeys?: string[];
- previewMaxWidth: number;
- onChange?: (uploads: ImageUpload[]) => void;
+ field: string
+ maxUploads: number
+ bkeys?: string[]
+ previewMaxWidth: number
+ onChange?: (uploads: ImageUpload[]) => void
}
interface MultiImageUploaderInstances {
[key: string]: {
- element: JSX.Element;
- upload?: ImageUpload;
- };
+ element: JSX.Element
+ upload?: ImageUpload
+ }
}
interface MultiImageUploaderState {
- count: number;
- instances: MultiImageUploaderInstances;
- removed: ImageUpload[];
+ count: number
+ instances: MultiImageUploaderInstances
+ removed: ImageUpload[]
}
export class MultiImageUploader extends React.Component {
constructor(props: MultiImageUploaderProps) {
- super(props);
+ super(props)
- let count = 1;
- const instances = {};
+ let count = 1
+ const instances = {}
if (props.bkeys) {
for (const bkey of props.bkeys) {
- count++;
- this.addNewElement(instances, bkey);
+ count++
+ this.addNewElement(instances, bkey)
}
}
if (count <= this.props.maxUploads) {
- count++;
- this.addNewElement(instances);
+ count++
+ this.addNewElement(instances)
}
- this.state = { instances, count, removed: [] };
+ this.state = { instances, count, removed: [] }
}
private imageUploaded = (upload: ImageUpload, instanceID: string) => {
- const instances = { ...this.state.instances };
- const removed = [...this.state.removed];
- let count = this.state.count;
+ const instances = { ...this.state.instances }
+ const removed = [...this.state.removed]
+ let count = this.state.count
if (upload.remove) {
if (upload.bkey) {
- removed.push(upload);
+ removed.push(upload)
}
- delete instances[instanceID];
+ delete instances[instanceID]
if (--count === this.props.maxUploads) {
- this.addNewElement(instances);
+ this.addNewElement(instances)
}
} else {
- instances[instanceID].upload = upload;
+ instances[instanceID].upload = upload
if (count++ <= this.props.maxUploads) {
- this.addNewElement(instances);
+ this.addNewElement(instances)
}
}
- this.setState({ instances, count, removed }, this.triggerOnChange);
- };
+ this.setState({ instances, count, removed }, this.triggerOnChange)
+ }
private triggerOnChange() {
if (this.props.onChange) {
const uploads = Object.keys(this.state.instances)
.map((k) => this.state.instances[k].upload)
.concat(this.state.removed)
- .filter((x) => !!x) as ImageUpload[];
- this.props.onChange(uploads);
+ .filter((x) => !!x) as ImageUpload[]
+ this.props.onChange(uploads)
}
}
private addNewElement(instances: MultiImageUploaderInstances, bkey?: string) {
- const id = btoa(Math.random().toString());
+ const id = btoa(Math.random().toString())
instances[id] = {
- element: ,
- };
+ element: (
+
+ ),
+ }
}
public render() {
- const elements = Object.keys(this.state.instances).map((k) => this.state.instances[k].element);
+ const elements = Object.keys(this.state.instances).map((k) => this.state.instances[k].element)
return (
{(ctx) => (
@@ -103,6 +105,6 @@ export class MultiImageUploader extends React.Component
)}
- );
+ )
}
}
diff --git a/public/components/common/form/RadioButton.tsx b/public/components/common/form/RadioButton.tsx
index 6a50c270f..f4bda7335 100644
--- a/public/components/common/form/RadioButton.tsx
+++ b/public/components/common/form/RadioButton.tsx
@@ -1,53 +1,59 @@
-import React from "react";
+import React from "react"
interface RadioButtonOption {
- value: string;
- label: string;
+ value: string
+ label: string
}
interface RadioButtonProps {
- label: string;
- field: string;
- defaultOption: RadioButtonOption;
- options: RadioButtonOption[];
- onSelect?: (value: RadioButtonOption) => void;
+ label: string
+ field: string
+ defaultOption: RadioButtonOption
+ options: RadioButtonOption[]
+ onSelect?: (value: RadioButtonOption) => void
}
interface RadioButtonState {
- selected: RadioButtonOption;
+ selected: RadioButtonOption
}
export class RadioButton extends React.Component {
constructor(props: RadioButtonProps) {
- super(props);
+ super(props)
this.state = {
selected: props.defaultOption || props.options[0],
- };
+ }
}
private onChange = (selected: RadioButtonOption) => {
this.setState({ selected }, () => {
if (this.props.onSelect) {
- this.props.onSelect(this.state.selected);
+ this.props.onSelect(this.state.selected)
}
- });
- };
+ })
+ }
public render() {
const inputs = this.props.options.map((option) => {
return (
-
+
{option.label}
- );
- });
+ )
+ })
return (
{this.props.label}
{inputs}
- );
+ )
}
}
diff --git a/public/components/common/form/Select.tsx b/public/components/common/form/Select.tsx
index 7a2e6dd82..89a2d8bd3 100644
--- a/public/components/common/form/Select.tsx
+++ b/public/components/common/form/Select.tsx
@@ -1,58 +1,58 @@
-import React from "react";
-import { classSet } from "@fider/services";
-import { ValidationContext } from "./Form";
-import { DisplayError, hasError } from "./DisplayError";
+import React from "react"
+import { classSet } from "@fider/services"
+import { ValidationContext } from "./Form"
+import { DisplayError, hasError } from "./DisplayError"
export interface SelectOption {
- value: string;
- label: string;
+ value: string
+ label: string
}
interface SelectProps {
- field: string;
- label?: string;
- maxLength?: number;
- defaultValue?: string;
- options: SelectOption[];
- onChange?: (option?: SelectOption) => void;
+ field: string
+ label?: string
+ maxLength?: number
+ defaultValue?: string
+ options: SelectOption[]
+ onChange?: (option?: SelectOption) => void
}
interface SelectState {
- selected?: SelectOption;
+ selected?: SelectOption
}
export class Select extends React.Component {
constructor(props: SelectProps) {
- super(props);
+ super(props)
this.state = {
selected: this.getOption(props.defaultValue),
- };
+ }
}
private getOption(value?: string): SelectOption | undefined {
if (value && this.props.options) {
- const filtered = this.props.options.filter((x) => x.value === value);
+ const filtered = this.props.options.filter((x) => x.value === value)
if (filtered && filtered.length > 0) {
- return filtered[0];
+ return filtered[0]
}
}
}
private onChange = (e: React.FormEvent) => {
- let selected: SelectOption | undefined;
+ let selected: SelectOption | undefined
if (e.currentTarget.value) {
- const options = this.props.options.filter((o) => o.value === e.currentTarget.value);
+ const options = this.props.options.filter((o) => o.value === e.currentTarget.value)
if (options && options.length > 0) {
- selected = options[0];
+ selected = options[0]
}
}
this.setState({ selected }, () => {
if (this.props.onChange) {
- this.props.onChange(this.state.selected);
+ this.props.onChange(this.state.selected)
}
- });
- };
+ })
+ }
public render() {
const options = this.props.options.map((option) => {
@@ -60,8 +60,8 @@ export class Select extends React.Component {
{option.label}
- );
- });
+ )
+ })
return (
@@ -85,6 +85,6 @@ export class Select extends React.Component {
>
)}
- );
+ )
}
}
diff --git a/public/components/common/form/TextArea.tsx b/public/components/common/form/TextArea.tsx
index 813a9c683..1ea1d6e9f 100644
--- a/public/components/common/form/TextArea.tsx
+++ b/public/components/common/form/TextArea.tsx
@@ -1,27 +1,27 @@
-import React from "react";
-import { classSet } from "@fider/services";
-import { ValidationContext } from "../";
-import { DisplayError, hasError } from "./DisplayError";
-import Textarea from "react-textarea-autosize";
+import React from "react"
+import { classSet } from "@fider/services"
+import { ValidationContext } from "../"
+import { DisplayError, hasError } from "./DisplayError"
+import Textarea from "react-textarea-autosize"
interface TextAreaProps {
- label?: string;
- field: string;
- value?: string;
- disabled?: boolean;
- minRows?: number;
- placeholder?: string;
- onChange?: (value: string) => void;
- inputRef?: React.MutableRefObject;
- onFocus?: React.FocusEventHandler;
+ label?: string
+ field: string
+ value?: string
+ disabled?: boolean
+ minRows?: number
+ placeholder?: string
+ onChange?: (value: string) => void
+ inputRef?: React.MutableRefObject
+ onFocus?: React.FocusEventHandler
}
export const TextArea: React.FunctionComponent = (props) => {
const onChange = (e: React.FormEvent) => {
if (props.onChange) {
- props.onChange(e.currentTarget.value);
+ props.onChange(e.currentTarget.value)
}
- };
+ }
return (
@@ -52,5 +52,5 @@ export const TextArea: React.FunctionComponent = (props) => {
>
)}
- );
-};
+ )
+}
diff --git a/public/components/common/index.tsx b/public/components/common/index.tsx
index 791467873..b57b84d72 100644
--- a/public/components/common/index.tsx
+++ b/public/components/common/index.tsx
@@ -1,36 +1,36 @@
-export * from "./Button";
-export * from "./form/Form";
-export * from "./form/Input";
-export * from "./form/ImageUploader";
-export * from "./form/MultiImageUploader";
-export * from "./form/TextArea";
-export * from "./form/RadioButton";
-export * from "./form/DisplayError";
-export * from "./form/Select";
-export * from "./form/Field";
-export * from "./form/Checkbox";
-export * from "./form/ImageViewer";
-export * from "./MultiLineText";
-export * from "./EnvironmentInfo";
-export * from "./Avatar";
-export * from "./Message";
-export * from "./Hint";
-export * from "./Footer";
-export * from "./Header";
-export * from "./Heading";
-export * from "./Legal";
-export * from "./SocialSignInButton";
-export * from "./SignInControl";
-export * from "./Segment";
-export * from "./List";
-export * from "./Moment";
-export * from "./Modal";
-export * from "./UserName";
-export * from "./Loader";
-export * from "./Logo";
-export * from "./Toggle";
-export * from "./FiderVersion";
-export * from "./DropDown";
+export * from "./Button"
+export * from "./form/Form"
+export * from "./form/Input"
+export * from "./form/ImageUploader"
+export * from "./form/MultiImageUploader"
+export * from "./form/TextArea"
+export * from "./form/RadioButton"
+export * from "./form/DisplayError"
+export * from "./form/Select"
+export * from "./form/Field"
+export * from "./form/Checkbox"
+export * from "./form/ImageViewer"
+export * from "./MultiLineText"
+export * from "./EnvironmentInfo"
+export * from "./Avatar"
+export * from "./Message"
+export * from "./Hint"
+export * from "./Footer"
+export * from "./Header"
+export * from "./Heading"
+export * from "./Legal"
+export * from "./SocialSignInButton"
+export * from "./SignInControl"
+export * from "./Segment"
+export * from "./List"
+export * from "./Moment"
+export * from "./Modal"
+export * from "./UserName"
+export * from "./Loader"
+export * from "./Logo"
+export * from "./Toggle"
+export * from "./FiderVersion"
+export * from "./DropDown"
-import Textarea from "react-textarea-autosize";
-export { Textarea };
+import Textarea from "react-textarea-autosize"
+export { Textarea }
diff --git a/public/components/index.tsx b/public/components/index.tsx
index 48e7ed408..1884a5630 100644
--- a/public/components/index.tsx
+++ b/public/components/index.tsx
@@ -1,6 +1,6 @@
-export * from "./ErrorBoundary";
-export * from "./ShowPostResponse";
-export * from "./ShowTag";
-export * from "./SignInModal";
-export * from "./VoteCounter";
-export * from "./common";
+export * from "./ErrorBoundary"
+export * from "./ShowPostResponse"
+export * from "./ShowTag"
+export * from "./SignInModal"
+export * from "./VoteCounter"
+export * from "./common"
diff --git a/public/hooks/index.ts b/public/hooks/index.ts
index c5f46f3bc..71e608ba6 100644
--- a/public/hooks/index.ts
+++ b/public/hooks/index.ts
@@ -1,2 +1,2 @@
-export * from "./use-timeout";
-export * from "./use-fider";
+export * from "./use-timeout"
+export * from "./use-fider"
diff --git a/public/hooks/use-fider.ts b/public/hooks/use-fider.ts
index 32559beec..31e57a270 100644
--- a/public/hooks/use-fider.ts
+++ b/public/hooks/use-fider.ts
@@ -1,4 +1,4 @@
-import { useContext } from "react";
-import { FiderContext } from "@fider/services";
+import { useContext } from "react"
+import { FiderContext } from "@fider/services"
-export const useFider = () => useContext(FiderContext);
+export const useFider = () => useContext(FiderContext)
diff --git a/public/hooks/use-timeout.ts b/public/hooks/use-timeout.ts
index 95ba79bdb..d2927914c 100644
--- a/public/hooks/use-timeout.ts
+++ b/public/hooks/use-timeout.ts
@@ -1,23 +1,23 @@
-import { useRef, useEffect } from "react";
+import { useRef, useEffect } from "react"
-type CallbackFunction = () => void;
+type CallbackFunction = () => void
export function useTimeout(callback: CallbackFunction, delay: number) {
- const savedCallback = useRef();
+ const savedCallback = useRef()
useEffect(() => {
- savedCallback.current = callback;
- });
+ savedCallback.current = callback
+ })
useEffect(() => {
function tick() {
if (savedCallback.current) {
- savedCallback.current();
+ savedCallback.current()
}
}
- const timer = window.setTimeout(tick, delay);
+ const timer = window.setTimeout(tick, delay)
return function cleanup() {
- window.clearTimeout(timer);
- };
- }, [delay]);
+ window.clearTimeout(timer)
+ }
+ }, [delay])
}
diff --git a/public/index.tsx b/public/index.tsx
index 39f479e95..2cd8e06bb 100644
--- a/public/index.tsx
+++ b/public/index.tsx
@@ -1,52 +1,49 @@
-import React, { Suspense } from "react";
-import ReactDOM from "react-dom";
-import { resolveRootComponent } from "@fider/router";
-import { Header, Footer, Loader } from "@fider/components/common";
-import { ErrorBoundary } from "@fider/components";
-import { classSet, Fider, FiderContext, actions } from "@fider/services";
-import { IconContext } from "react-icons";
-import "@fider/assets/styles/index.scss";
+import React, { Suspense } from "react"
+import ReactDOM from "react-dom"
+import { resolveRootComponent } from "@fider/router"
+import { Header, Footer, Loader } from "@fider/components/common"
+import { ErrorBoundary } from "@fider/components"
+import { classSet, Fider, FiderContext, actions } from "@fider/services"
+import { IconContext } from "react-icons"
+import "@fider/assets/styles/index.scss"
const Loading = () => (
-);
+)
const logProductionError = (err: Error) => {
if (Fider.isProduction()) {
- console.error(err); // tslint:disable-line
- actions.logError(`react.ErrorBoundary: ${err.message}`, err);
+ console.error(err)
+ actions.logError(`react.ErrorBoundary: ${err.message}`, err)
}
-};
+}
window.addEventListener("unhandledrejection", (evt: PromiseRejectionEvent) => {
if (evt.reason instanceof Error) {
- actions.logError(`window.unhandledrejection: ${evt.reason.message}`, evt.reason);
+ actions.logError(`window.unhandledrejection: ${evt.reason.message}`, evt.reason)
} else if (evt.reason) {
- actions.logError(`window.unhandledrejection: ${evt.reason.toString()}`);
+ actions.logError(`window.unhandledrejection: ${evt.reason.toString()}`)
}
-});
+})
window.addEventListener("error", (evt: ErrorEvent) => {
if (evt.error && evt.colno > 0 && evt.lineno > 0) {
- actions.logError(`window.error: ${evt.message}`, evt.error);
+ actions.logError(`window.error: ${evt.message}`, evt.error)
}
-});
+})
+;(() => {
+ const fider = Fider.initialize()
-(() => {
- let fider;
+ __webpack_nonce__ = fider.session.contextID
+ __webpack_public_path__ = `${fider.settings.globalAssetsURL}/assets/`
- fider = Fider.initialize();
-
- __webpack_nonce__ = fider.session.contextID;
- __webpack_public_path__ = `${fider.settings.globalAssetsURL}/assets/`;
-
- const config = resolveRootComponent(location.pathname);
+ const config = resolveRootComponent(location.pathname)
document.body.className = classSet({
"is-authenticated": fider.session.isAuthenticated,
"is-staff": fider.session.isAuthenticated && fider.session.user.isCollaborator,
- });
+ })
ReactDOM.render(
@@ -60,5 +57,5 @@ window.addEventListener("error", (evt: ErrorEvent) => {
,
document.getElementById("root")
- );
-})();
+ )
+})()
diff --git a/public/jest.assets.ts b/public/jest.assets.ts
index efa1a7e9f..56e832a77 100644
--- a/public/jest.assets.ts
+++ b/public/jest.assets.ts
@@ -1,2 +1,2 @@
-const stub = {};
-export default stub;
+const stub = {}
+export default stub
diff --git a/public/jest.setup.ts b/public/jest.setup.ts
index 13d8d603d..b410e69e6 100644
--- a/public/jest.setup.ts
+++ b/public/jest.setup.ts
@@ -1,25 +1,24 @@
-import { configure } from "enzyme";
-import Adapter from "@wojtekmaj/enzyme-adapter-react-17";
+import { configure } from "enzyme"
+import Adapter from "@wojtekmaj/enzyme-adapter-react-17"
-configure({ adapter: new Adapter() });
+configure({ adapter: new Adapter() })
let localStorageCache: {
- [key: string]: string | undefined;
-};
+ [key: string]: string | undefined
+}
beforeEach(() => {
- localStorageCache = {};
-});
-
-(window as any).localStorage = {
+ localStorageCache = {}
+})
+;(window as any).localStorage = {
getItem: (key: string) => {
- const value = localStorageCache[key];
- return typeof value === "undefined" ? null : value;
+ const value = localStorageCache[key]
+ return typeof value === "undefined" ? null : value
},
setItem: (key: string, value: string) => {
- localStorageCache[key] = value;
+ localStorageCache[key] = value
},
removeItem: (key: string) => {
- return delete localStorageCache[key];
+ return delete localStorageCache[key]
},
-};
+}
diff --git a/public/models/identity.ts b/public/models/identity.ts
index 530c3fa20..ef109465e 100644
--- a/public/models/identity.ts
+++ b/public/models/identity.ts
@@ -1,13 +1,13 @@
export interface Tenant {
- id: number;
- name: string;
- cname: string;
- subdomain: string;
- invitation: string;
- welcomeMessage: string;
- status: TenantStatus;
- isPrivate: boolean;
- logoBlobKey: string;
+ id: number
+ name: string
+ cname: string
+ subdomain: string
+ invitation: string
+ welcomeMessage: string
+ status: TenantStatus
+ isPrivate: boolean
+ logoBlobKey: string
}
export enum TenantStatus {
@@ -17,11 +17,11 @@ export enum TenantStatus {
}
export interface User {
- id: number;
- name: string;
- role: UserRole;
- status: UserStatus;
- avatarURL: string;
+ id: number
+ name: string
+ role: UserRole
+ status: UserStatus
+ avatarURL: string
}
export enum UserAvatarType {
@@ -43,18 +43,18 @@ export enum UserRole {
}
export const isCollaborator = (role: UserRole): boolean => {
- return role === UserRole.Collaborator || role === UserRole.Administrator;
-};
+ return role === UserRole.Collaborator || role === UserRole.Administrator
+}
export interface CurrentUser {
- id: number;
- name: string;
- email: string;
- avatarType: UserAvatarType;
- avatarBlobKey: string;
- avatarURL: string;
- role: UserRole;
- status: UserStatus;
- isAdministrator: boolean;
- isCollaborator: boolean;
+ id: number
+ name: string
+ email: string
+ avatarType: UserAvatarType
+ avatarBlobKey: string
+ avatarURL: string
+ role: UserRole
+ status: UserStatus
+ isAdministrator: boolean
+ isCollaborator: boolean
}
diff --git a/public/models/index.ts b/public/models/index.ts
index be6347622..bc4a3f5d9 100644
--- a/public/models/index.ts
+++ b/public/models/index.ts
@@ -1,4 +1,4 @@
-export * from "./post";
-export * from "./identity";
-export * from "./settings";
-export * from "./notification";
+export * from "./post"
+export * from "./identity"
+export * from "./settings"
+export * from "./notification"
diff --git a/public/models/notification.ts b/public/models/notification.ts
index 00802411b..b85940827 100644
--- a/public/models/notification.ts
+++ b/public/models/notification.ts
@@ -1,7 +1,7 @@
export interface Notification {
- id: number;
- title: string;
- link: string;
- read: boolean;
- createdAt: string;
+ id: number
+ title: string
+ link: string
+ read: boolean
+ createdAt: string
}
diff --git a/public/models/post.ts b/public/models/post.ts
index 09db1e849..57bc2b372 100644
--- a/public/models/post.ts
+++ b/public/models/post.ts
@@ -1,80 +1,80 @@
-import { User } from "./identity";
+import { User } from "./identity"
export interface Post {
- id: number;
- number: number;
- slug: string;
- title: string;
- description: string;
- createdAt: string;
- status: string;
- user: User;
- hasVoted: boolean;
- response: PostResponse | null;
- votesCount: number;
- commentsCount: number;
- tags: string[];
+ id: number
+ number: number
+ slug: string
+ title: string
+ description: string
+ createdAt: string
+ status: string
+ user: User
+ hasVoted: boolean
+ response: PostResponse | null
+ votesCount: number
+ commentsCount: number
+ tags: string[]
}
export class PostStatus {
constructor(public title: string, public value: string, public show: boolean, public closed: boolean, public filterable: boolean) {}
- public static Open = new PostStatus("Open", "open", false, false, false);
- public static Planned = new PostStatus("Planned", "planned", true, false, true);
- public static Started = new PostStatus("Started", "started", true, false, true);
- public static Completed = new PostStatus("Completed", "completed", true, true, true);
- public static Declined = new PostStatus("Declined", "declined", true, true, true);
- public static Duplicate = new PostStatus("Duplicate", "duplicate", true, true, false);
- public static Deleted = new PostStatus("Deleted", "deleted", false, true, false);
+ public static Open = new PostStatus("Open", "open", false, false, false)
+ public static Planned = new PostStatus("Planned", "planned", true, false, true)
+ public static Started = new PostStatus("Started", "started", true, false, true)
+ public static Completed = new PostStatus("Completed", "completed", true, true, true)
+ public static Declined = new PostStatus("Declined", "declined", true, true, true)
+ public static Duplicate = new PostStatus("Duplicate", "duplicate", true, true, false)
+ public static Deleted = new PostStatus("Deleted", "deleted", false, true, false)
public static Get(value: string): PostStatus {
for (const status of PostStatus.All) {
if (status.value === value) {
- return status;
+ return status
}
}
- throw new Error(`PostStatus not found for value ${value}.`);
+ throw new Error(`PostStatus not found for value ${value}.`)
}
- public static All = [PostStatus.Open, PostStatus.Planned, PostStatus.Started, PostStatus.Completed, PostStatus.Duplicate, PostStatus.Declined];
+ public static All = [PostStatus.Open, PostStatus.Planned, PostStatus.Started, PostStatus.Completed, PostStatus.Duplicate, PostStatus.Declined]
}
export interface PostResponse {
- user: User;
- text: string;
- respondedAt: Date;
+ user: User
+ text: string
+ respondedAt: Date
original?: {
- number: number;
- title: string;
- slug: string;
- status: string;
- };
+ number: number
+ title: string
+ slug: string
+ status: string
+ }
}
export interface Comment {
- id: number;
- content: string;
- createdAt: string;
- user: User;
- attachments?: string[];
- editedAt?: string;
- editedBy?: User;
+ id: number
+ content: string
+ createdAt: string
+ user: User
+ attachments?: string[]
+ editedAt?: string
+ editedBy?: User
}
export interface Tag {
- id: number;
- slug: string;
- name: string;
- color: string;
- isPublic: boolean;
+ id: number
+ slug: string
+ name: string
+ color: string
+ isPublic: boolean
}
export interface Vote {
- createdAt: Date;
+ createdAt: Date
user: {
- id: number;
- name: string;
- email: string;
- avatarURL: string;
- };
+ id: number
+ name: string
+ email: string
+ avatarURL: string
+ }
}
diff --git a/public/models/settings.ts b/public/models/settings.ts
index d5e7478fd..ee365c842 100644
--- a/public/models/settings.ts
+++ b/public/models/settings.ts
@@ -1,59 +1,59 @@
export interface OAuthProviderOption {
- provider: string;
- displayName: string;
- clientID: string;
- url: string;
- callbackURL: string;
- logoBlobKey: string;
- isCustomProvider: boolean;
- isEnabled: boolean;
+ provider: string
+ displayName: string
+ clientID: string
+ url: string
+ callbackURL: string
+ logoBlobKey: string
+ isCustomProvider: boolean
+ isEnabled: boolean
}
export interface SystemSettings {
- mode: string;
- buildTime: string;
- version: string;
- environment: string;
- compiler: string;
- domain: string;
- hasLegal: boolean;
- baseURL: string;
- tenantAssetsURL: string;
- globalAssetsURL: string;
- oauth: OAuthProviderOption[];
+ mode: string
+ buildTime: string
+ version: string
+ environment: string
+ compiler: string
+ domain: string
+ hasLegal: boolean
+ baseURL: string
+ tenantAssetsURL: string
+ globalAssetsURL: string
+ oauth: OAuthProviderOption[]
}
export interface UserSettings {
- [key: string]: string;
+ [key: string]: string
}
export const OAuthConfigStatus = {
Disabled: 1,
Enabled: 2,
-};
+}
export interface OAuthConfig {
- provider: string;
- displayName: string;
- status: number;
- clientID: string;
- clientSecret: string;
- authorizeURL: string;
- tokenURL: string;
- profileURL: string;
- logoBlobKey: string;
- scope: string;
- jsonUserIDPath: string;
- jsonUserNamePath: string;
- jsonUserEmailPath: string;
+ provider: string
+ displayName: string
+ status: number
+ clientID: string
+ clientSecret: string
+ authorizeURL: string
+ tokenURL: string
+ profileURL: string
+ logoBlobKey: string
+ scope: string
+ jsonUserIDPath: string
+ jsonUserNamePath: string
+ jsonUserEmailPath: string
}
export interface ImageUpload {
- bkey?: string;
+ bkey?: string
upload?: {
- fileName?: string;
- content?: string;
- contentType?: string;
- };
- remove: boolean;
+ fileName?: string
+ content?: string
+ contentType?: string
+ }
+ remove: boolean
}
diff --git a/public/pages/Administration/components/AdminBasePage.tsx b/public/pages/Administration/components/AdminBasePage.tsx
index 9a66f297f..d5e279434 100644
--- a/public/pages/Administration/components/AdminBasePage.tsx
+++ b/public/pages/Administration/components/AdminBasePage.tsx
@@ -1,24 +1,24 @@
-import "./AdminBasePage.scss";
+import "./AdminBasePage.scss"
-import React from "react";
-import { Heading } from "@fider/components";
-import { SideMenu, SideMenuToggler } from "./SideMenu";
-import { IconType } from "react-icons";
+import React from "react"
+import { Heading } from "@fider/components"
+import { SideMenu, SideMenuToggler } from "./SideMenu"
+import { IconType } from "react-icons"
export abstract class AdminBasePage extends React.Component
{
- public abstract id: string;
- public abstract name: string;
- public abstract icon: IconType;
- public abstract title: string;
- public abstract subtitle: string;
- public abstract content(): JSX.Element;
+ public abstract id: string
+ public abstract name: string
+ public abstract icon: IconType
+ public abstract title: string
+ public abstract subtitle: string
+ public abstract content(): JSX.Element
private toggleSideMenu = (active: boolean) => {
- const el = document.querySelector(".hidden-lg .c-side-menu") as HTMLElement;
+ const el = document.querySelector(".hidden-lg .c-side-menu") as HTMLElement
if (el) {
- el.style.display = active ? "" : "none";
+ el.style.display = active ? "" : "none"
}
- };
+ }
public render() {
return (
@@ -36,6 +36,6 @@ export abstract class AdminBasePage
extends React.Component
{
- );
+ )
}
}
diff --git a/public/pages/Administration/components/OAuthForm.tsx b/public/pages/Administration/components/OAuthForm.tsx
index cb7fab591..a63edc2d2 100644
--- a/public/pages/Administration/components/OAuthForm.tsx
+++ b/public/pages/Administration/components/OAuthForm.tsx
@@ -1,33 +1,33 @@
-import React, { useState } from "react";
-import { OAuthConfig, OAuthConfigStatus, ImageUpload } from "@fider/models";
-import { Failure, actions } from "@fider/services";
-import { Form, Button, Input, Heading, SocialSignInButton, Field, ImageUploader, Toggle } from "@fider/components";
-import { useFider } from "@fider/hooks";
+import React, { useState } from "react"
+import { OAuthConfig, OAuthConfigStatus, ImageUpload } from "@fider/models"
+import { Failure, actions } from "@fider/services"
+import { Form, Button, Input, Heading, SocialSignInButton, Field, ImageUploader, Toggle } from "@fider/components"
+import { useFider } from "@fider/hooks"
interface OAuthFormProps {
- config?: OAuthConfig;
- onCancel: () => void;
+ config?: OAuthConfig
+ onCancel: () => void
}
export const OAuthForm: React.FC = (props) => {
- const fider = useFider();
- const [provider] = useState((props.config && props.config.provider) || "");
- const [displayName, setDisplayName] = useState((props.config && props.config.displayName) || "");
- const [enabled, setEnabled] = useState((props.config && props.config.status === OAuthConfigStatus.Enabled) || false);
- const [clientID, setClientID] = useState((props.config && props.config.clientID) || "");
- const [clientSecret, setClientSecret] = useState((props.config && props.config.clientSecret) || "");
- const [clientSecretEnabled, setClientSecretEnabled] = useState(!props.config);
- const [authorizeURL, setAuthorizeURL] = useState((props.config && props.config.authorizeURL) || "");
- const [tokenURL, setTokenURL] = useState((props.config && props.config.tokenURL) || "");
- const [profileURL, setProfileURL] = useState((props.config && props.config.profileURL) || "");
- const [scope, setScope] = useState((props.config && props.config.scope) || "");
- const [jsonUserIDPath, setJSONUserIDPath] = useState((props.config && props.config.jsonUserIDPath) || "");
- const [jsonUserNamePath, setJSONUserNamePath] = useState((props.config && props.config.jsonUserNamePath) || "");
- const [jsonUserEmailPath, setJSONUserEmailPath] = useState((props.config && props.config.jsonUserEmailPath) || "");
- const [logo, setLogo] = useState();
- const [logoURL, setLogoURL] = useState();
- const [logoBlobKey, setLogoBlobKey] = useState((props.config && props.config.logoBlobKey) || "");
- const [error, setError] = useState();
+ const fider = useFider()
+ const [provider] = useState((props.config && props.config.provider) || "")
+ const [displayName, setDisplayName] = useState((props.config && props.config.displayName) || "")
+ const [enabled, setEnabled] = useState((props.config && props.config.status === OAuthConfigStatus.Enabled) || false)
+ const [clientID, setClientID] = useState((props.config && props.config.clientID) || "")
+ const [clientSecret, setClientSecret] = useState((props.config && props.config.clientSecret) || "")
+ const [clientSecretEnabled, setClientSecretEnabled] = useState(!props.config)
+ const [authorizeURL, setAuthorizeURL] = useState((props.config && props.config.authorizeURL) || "")
+ const [tokenURL, setTokenURL] = useState((props.config && props.config.tokenURL) || "")
+ const [profileURL, setProfileURL] = useState((props.config && props.config.profileURL) || "")
+ const [scope, setScope] = useState((props.config && props.config.scope) || "")
+ const [jsonUserIDPath, setJSONUserIDPath] = useState((props.config && props.config.jsonUserIDPath) || "")
+ const [jsonUserNamePath, setJSONUserNamePath] = useState((props.config && props.config.jsonUserNamePath) || "")
+ const [jsonUserEmailPath, setJSONUserEmailPath] = useState((props.config && props.config.jsonUserEmailPath) || "")
+ const [logo, setLogo] = useState()
+ const [logoURL, setLogoURL] = useState()
+ const [logoBlobKey, setLogoBlobKey] = useState((props.config && props.config.logoBlobKey) || "")
+ const [error, setError] = useState()
const handleSave = async () => {
const result = await actions.saveOAuthConfig({
@@ -44,40 +44,56 @@ export const OAuthForm: React.FC = (props) => {
jsonUserNamePath,
jsonUserEmailPath,
logo,
- });
+ })
if (result.ok) {
- location.reload();
+ location.reload()
} else {
- setError(result.error);
+ setError(result.error)
}
- };
+ }
const handleLogoChange = (newLogo: ImageUpload, instanceID: string, previewURL: string) => {
- setLogo(newLogo);
- setLogoURL(previewURL);
- setLogoBlobKey("");
- };
+ setLogo(newLogo)
+ setLogoURL(previewURL)
+ setLogoBlobKey("")
+ }
const handleCancel = async () => {
- props.onCancel();
- };
+ props.onCancel()
+ }
const enableClientSecret = () => {
- setClientSecret("");
- setClientSecretEnabled(true);
- };
+ setClientSecret("")
+ setClientSecretEnabled(true)
+ }
- const title = props.config ? `OAuth Provider: ${props.config.displayName}` : "New OAuth Provider";
+ const title = props.config ? `OAuth Provider: ${props.config.displayName}` : "New OAuth Provider"
return (
<>
>
- );
-};
+ )
+}
diff --git a/public/pages/Administration/components/SideMenu.tsx b/public/pages/Administration/components/SideMenu.tsx
index e87c33076..ce576c181 100644
--- a/public/pages/Administration/components/SideMenu.tsx
+++ b/public/pages/Administration/components/SideMenu.tsx
@@ -1,48 +1,48 @@
-import "./SideMenu.scss";
+import "./SideMenu.scss"
-import React from "react";
-import { classSet } from "@fider/services";
-import { FiderVersion } from "@fider/components";
-import { useFider } from "@fider/hooks";
+import React from "react"
+import { classSet } from "@fider/services"
+import { FiderVersion } from "@fider/components"
+import { useFider } from "@fider/hooks"
interface SiteMenuProps {
- activeItem: string;
- visible: boolean;
- className?: string;
+ activeItem: string
+ visible: boolean
+ className?: string
}
interface SideMenuItemProps {
- name: string;
- title: string;
- isActive: boolean;
- href: string;
+ name: string
+ title: string
+ isActive: boolean
+ href: string
}
const SideMenuItem = (props: SideMenuItemProps) => {
const className = classSet({
"c-side-menu-item": true,
"m-active": props.isActive,
- });
+ })
if (props.isActive) {
return (
{props.title}
- );
+ )
}
return (
{props.title}
- );
-};
+ )
+}
export const SideMenu = (props: SiteMenuProps) => {
- const fider = useFider();
- const activeItem = props.activeItem || "general";
- const style = { display: props.visible ? "" : "none" };
+ const fider = useFider()
+ const activeItem = props.activeItem || "general"
+ const style = { display: props.visible ? "" : "none" }
return (
@@ -62,44 +62,44 @@ export const SideMenu = (props: SiteMenuProps) => {
- );
-};
+ )
+}
interface SideMenuTogglerProps {
- onToggle: (active: boolean) => void;
+ onToggle: (active: boolean) => void
}
interface SideMenuTogglerState {
- active: boolean;
+ active: boolean
}
export class SideMenuToggler extends React.Component {
constructor(props: SideMenuTogglerProps) {
- super(props);
+ super(props)
this.state = {
active: false,
- };
+ }
}
private toggle = () => {
this.setState(
(state) => ({ active: !state.active }),
() => {
- this.props.onToggle(this.state.active);
+ this.props.onToggle(this.state.active)
}
- );
- };
+ )
+ }
public render() {
const className = classSet({
"c-side-menu-toggler": true,
active: this.state.active,
- });
+ })
return (
- );
+ )
}
}
diff --git a/public/pages/Administration/components/TagForm.tsx b/public/pages/Administration/components/TagForm.tsx
index 314712ece..a9bfabb50 100644
--- a/public/pages/Administration/components/TagForm.tsx
+++ b/public/pages/Administration/components/TagForm.tsx
@@ -1,79 +1,79 @@
-import "./TagForm.scss";
+import "./TagForm.scss"
-import React from "react";
-import { Button, Input, ShowTag, Form, RadioButton, Field, SelectOption } from "@fider/components";
-import { Failure } from "@fider/services";
+import React from "react"
+import { Button, Input, ShowTag, Form, RadioButton, Field, SelectOption } from "@fider/components"
+import { Failure } from "@fider/services"
interface TagFormProps {
- name?: string;
- color?: string;
- isPublic?: boolean;
- onSave: (data: TagFormState) => Promise;
- onCancel: () => void;
+ name?: string
+ color?: string
+ isPublic?: boolean
+ onSave: (data: TagFormState) => Promise
+ onCancel: () => void
}
export interface TagFormState {
- name: string;
- color: string;
- isPublic: boolean;
- error?: Failure;
+ name: string
+ color: string
+ isPublic: boolean
+ error?: Failure
}
export class TagForm extends React.Component {
- private visibilityPublic = { label: "Public", value: "public" };
- private visibilityPrivate = { label: "Private", value: "private" };
+ private visibilityPublic = { label: "Public", value: "public" }
+ private visibilityPrivate = { label: "Private", value: "private" }
constructor(props: TagFormProps) {
- super(props);
+ super(props)
this.state = {
color: props.color || this.getRandomColor(),
name: props.name || "",
isPublic: props.isPublic || false,
- };
+ }
}
private getRandomColor(): string {
- const letters = "0123456789ABCDEF";
- let color = "";
+ const letters = "0123456789ABCDEF"
+ let color = ""
for (let i = 0; i < 6; i++) {
- color += letters[Math.floor(Math.random() * 16)];
+ color += letters[Math.floor(Math.random() * 16)]
}
- return color;
+ return color
}
private handleSave = async () => {
- const error = await this.props.onSave(this.state);
+ const error = await this.props.onSave(this.state)
if (error) {
- this.setState({ error });
+ this.setState({ error })
}
- };
+ }
private handleCancel = async () => {
- this.props.onCancel();
- };
+ this.props.onCancel()
+ }
private setName = (name: string) => {
- this.setState({ name });
- };
+ this.setState({ name })
+ }
private setColor = (color: string) => {
- this.setState({ color });
- };
+ this.setState({ color })
+ }
private setVisibility = (option: SelectOption) => {
- this.setState({ isPublic: option === this.visibilityPublic });
- };
+ this.setState({ isPublic: option === this.visibilityPublic })
+ }
private randomize = () => {
- this.setColor(this.getRandomColor());
- };
+ this.setColor(this.getRandomColor())
+ }
public render() {
const randomizer = (
randomize
- );
+ )
return (
- );
+ )
}
}
diff --git a/public/pages/Administration/components/TagListItem.tsx b/public/pages/Administration/components/TagListItem.tsx
index 8a063be3e..3db71f8e7 100644
--- a/public/pages/Administration/components/TagListItem.tsx
+++ b/public/pages/Administration/components/TagListItem.tsx
@@ -1,48 +1,48 @@
-import React, { useState } from "react";
-import { Tag } from "@fider/models";
-import { ListItem, ShowTag, Button } from "@fider/components";
-import { TagFormState, TagForm } from "./TagForm";
-import { actions, Failure } from "@fider/services";
-import { FaTimes, FaEdit } from "react-icons/fa";
-import { useFider } from "@fider/hooks";
+import React, { useState } from "react"
+import { Tag } from "@fider/models"
+import { ListItem, ShowTag, Button } from "@fider/components"
+import { TagFormState, TagForm } from "./TagForm"
+import { actions, Failure } from "@fider/services"
+import { FaTimes, FaEdit } from "react-icons/fa"
+import { useFider } from "@fider/hooks"
interface TagListItemProps {
- tag: Tag;
- onTagEdited: (tag: Tag) => void;
- onTagDeleted: (tag: Tag) => void;
+ tag: Tag
+ onTagEdited: (tag: Tag) => void
+ onTagDeleted: (tag: Tag) => void
}
export const TagListItem = (props: TagListItemProps) => {
- const fider = useFider();
- const [tag] = useState(props.tag);
- const [state, setState] = useState<"view" | "edit" | "delete">("view");
+ const fider = useFider()
+ const [tag] = useState(props.tag)
+ const [state, setState] = useState<"view" | "edit" | "delete">("view")
- const startDelete = async () => setState("delete");
- const startEdit = async () => setState("edit");
- const resetState = async () => setState("view");
+ const startDelete = async () => setState("delete")
+ const startEdit = async () => setState("edit")
+ const resetState = async () => setState("view")
const deleteTag = async () => {
- const result = await actions.deleteTag(tag.slug);
+ const result = await actions.deleteTag(tag.slug)
if (result.ok) {
- resetState();
- props.onTagDeleted(tag);
+ resetState()
+ props.onTagDeleted(tag)
}
- };
+ }
const updateTag = async (data: TagFormState): Promise => {
- const result = await actions.updateTag(tag.slug, data.name, data.color, data.isPublic);
+ const result = await actions.updateTag(tag.slug, data.name, data.color, data.isPublic)
if (result.ok) {
- tag.name = result.data.name;
- tag.slug = result.data.slug;
- tag.color = result.data.color;
- tag.isPublic = result.data.isPublic;
+ tag.name = result.data.name
+ tag.slug = result.data.slug
+ tag.color = result.data.color
+ tag.isPublic = result.data.isPublic
- resetState();
- props.onTagEdited(tag);
+ resetState()
+ props.onTagEdited(tag)
} else {
- return result.error;
+ return result.error
}
- };
+ }
const renderDeleteMode = () => {
return (
@@ -60,8 +60,8 @@ export const TagListItem = (props: TagListItemProps) => {
Delete tag
>
- );
- };
+ )
+ }
const renderViewMode = () => {
const buttons = fider.session.user.isAdministrator && [
@@ -73,21 +73,21 @@ export const TagListItem = (props: TagListItemProps) => {
Edit
,
- ];
+ ]
return (
<>
{buttons}
>
- );
- };
+ )
+ }
const renderEditMode = () => {
- return ;
- };
+ return
+ }
- const view = state === "delete" ? renderDeleteMode() : state === "edit" ? renderEditMode() : renderViewMode();
+ const view = state === "delete" ? renderDeleteMode() : state === "edit" ? renderEditMode() : renderViewMode()
- return {view} ;
-};
+ return {view}
+}
diff --git a/public/pages/Administration/pages/AdvancedSettings.page.tsx b/public/pages/Administration/pages/AdvancedSettings.page.tsx
index 4cce71608..75a3d9961 100644
--- a/public/pages/Administration/pages/AdvancedSettings.page.tsx
+++ b/public/pages/Administration/pages/AdvancedSettings.page.tsx
@@ -1,65 +1,73 @@
-import "./AdvancedSettings.page.scss";
+import "./AdvancedSettings.page.scss"
-import React from "react";
+import React from "react"
-import { TextArea, Form, Button, ButtonClickEvent } from "@fider/components";
-import { Failure, actions, Fider } from "@fider/services";
-import { FaStar } from "react-icons/fa";
-import { AdminBasePage } from "../components/AdminBasePage";
+import { TextArea, Form, Button } from "@fider/components"
+import { Failure, actions, Fider } from "@fider/services"
+import { FaStar } from "react-icons/fa"
+import { AdminBasePage } from "../components/AdminBasePage"
interface AdvancedSettingsPageProps {
- customCSS: string;
+ customCSS: string
}
interface AdvancedSettingsPageState {
- customCSS: string;
- error?: Failure;
+ customCSS: string
+ error?: Failure
}
export default class AdvancedSettingsPage extends AdminBasePage {
- public id = "p-admin-advanced";
- public name = "advanced";
- public icon = FaStar;
- public title = "Advanced";
- public subtitle = "Manage your site settings";
+ public id = "p-admin-advanced"
+ public name = "advanced"
+ public icon = FaStar
+ public title = "Advanced"
+ public subtitle = "Manage your site settings"
constructor(props: AdvancedSettingsPageProps) {
- super(props);
+ super(props)
this.state = {
customCSS: this.props.customCSS,
- };
+ }
}
private setCustomCSS = (customCSS: string): void => {
- this.setState({ customCSS });
- };
+ this.setState({ customCSS })
+ }
- private handleSave = async (e: ButtonClickEvent): Promise => {
- const result = await actions.updateTenantAdvancedSettings(this.state.customCSS);
+ private handleSave = async (): Promise => {
+ const result = await actions.updateTenantAdvancedSettings(this.state.customCSS)
if (result.ok) {
- location.reload();
+ location.reload()
} else {
- this.setState({ error: result.error });
+ this.setState({ error: result.error })
}
- };
+ }
public content() {
return (
- );
+ )
}
}
diff --git a/public/pages/Administration/pages/Export.page.tsx b/public/pages/Administration/pages/Export.page.tsx
index 995c3f1b4..320f36230 100644
--- a/public/pages/Administration/pages/Export.page.tsx
+++ b/public/pages/Administration/pages/Export.page.tsx
@@ -1,22 +1,25 @@
-import React from "react";
+import React from "react"
-import { Button, Form, Field, Segment } from "@fider/components";
-import { FaRegFileExcel } from "react-icons/fa";
-import { AdminBasePage } from "../components/AdminBasePage";
+import { Button, Form, Field, Segment } from "@fider/components"
+import { FaRegFileExcel } from "react-icons/fa"
+import { AdminBasePage } from "../components/AdminBasePage"
-export default class ExportPage extends AdminBasePage<{}, {}> {
- public id = "p-admin-export";
- public name = "export";
- public icon = FaRegFileExcel;
- public title = "Export";
- public subtitle = "Download your data";
+export default class ExportPage extends AdminBasePage {
+ public id = "p-admin-export"
+ public name = "export"
+ public icon = FaRegFileExcel
+ public title = "Export"
+ public subtitle = "Download your data"
public content() {
return (
- Use this button to download a CSV file with all posts in this site. This can be useful to analyse the data with an external tool or simply to back it up.
+
+ Use this button to download a CSV file with all posts in this site. This can be useful to analyse the data with an external tool or simply to back
+ it up.
+
@@ -35,6 +38,6 @@ export default class ExportPage extends AdminBasePage<{}, {}> {
- );
+ )
}
}
diff --git a/public/pages/Administration/pages/GeneralSettings.page.tsx b/public/pages/Administration/pages/GeneralSettings.page.tsx
index c2b65e65b..86b54fd59 100644
--- a/public/pages/Administration/pages/GeneralSettings.page.tsx
+++ b/public/pages/Administration/pages/GeneralSettings.page.tsx
@@ -1,53 +1,53 @@
-import "./GeneralSettings.page.scss";
+import "./GeneralSettings.page.scss"
-import React from "react";
+import React from "react"
-import { Button, ButtonClickEvent, TextArea, Form, Input, ImageUploader } from "@fider/components/common";
-import { actions, Failure, Fider } from "@fider/services";
-import { FaCogs } from "react-icons/fa";
-import { AdminBasePage } from "../components/AdminBasePage";
-import { ImageUpload } from "@fider/models";
+import { Button, ButtonClickEvent, TextArea, Form, Input, ImageUploader } from "@fider/components/common"
+import { actions, Failure, Fider } from "@fider/services"
+import { FaCogs } from "react-icons/fa"
+import { AdminBasePage } from "../components/AdminBasePage"
+import { ImageUpload } from "@fider/models"
interface GeneralSettingsPageState {
- logo?: ImageUpload;
- title: string;
- invitation: string;
- welcomeMessage: string;
- cname: string;
- error?: Failure;
+ logo?: ImageUpload
+ title: string
+ invitation: string
+ welcomeMessage: string
+ cname: string
+ error?: Failure
}
-export default class GeneralSettingsPage extends AdminBasePage<{}, GeneralSettingsPageState> {
- public id = "p-admin-general";
- public name = "general";
- public icon = FaCogs;
- public title = "General";
- public subtitle = "Manage your site settings";
+export default class GeneralSettingsPage extends AdminBasePage {
+ public id = "p-admin-general"
+ public name = "general"
+ public icon = FaCogs
+ public title = "General"
+ public subtitle = "Manage your site settings"
- constructor(props: {}) {
- super(props);
+ constructor(props: any) {
+ super(props)
this.state = {
title: Fider.session.tenant.name,
cname: Fider.session.tenant.cname,
welcomeMessage: Fider.session.tenant.welcomeMessage,
invitation: Fider.session.tenant.invitation,
- };
+ }
}
private handleSave = async (e: ButtonClickEvent) => {
- const result = await actions.updateTenantSettings(this.state);
+ const result = await actions.updateTenantSettings(this.state)
if (result.ok) {
- e.preventEnable();
- location.href = `/`;
+ e.preventEnable()
+ location.href = `/`
} else if (result.error) {
- this.setState({ error: result.error });
+ this.setState({ error: result.error })
}
- };
+ }
public dnsInstructions(): JSX.Element {
- const isApex = this.state.cname.split(".").length <= 2;
- const recordType = isApex ? "ALIAS" : "CNAME";
+ const isApex = this.state.cname.split(".").length <= 2
+ const recordType = isApex ? "ALIAS" : "CNAME"
return (
<>
{this.state.cname} {recordType}{" "}
@@ -56,39 +56,49 @@ export default class GeneralSettingsPage extends AdminBasePage<{}, GeneralSettin
{Fider.settings.domain}
>
- );
+ )
}
private setTitle = (title: string): void => {
- this.setState({ title });
- };
+ this.setState({ title })
+ }
private setWelcomeMessage = (welcomeMessage: string): void => {
- this.setState({ welcomeMessage });
- };
+ this.setState({ welcomeMessage })
+ }
private setInvitation = (invitation: string): void => {
- this.setState({ invitation });
- };
+ this.setState({ invitation })
+ }
private setLogo = (logo: ImageUpload): void => {
- this.setState({ logo });
- };
+ this.setState({ logo })
+ }
private setCNAME = (cname: string): void => {
- this.setState({ cname });
- };
+ this.setState({ cname })
+ }
public content() {
return (
- The title is used on the header, emails, notifications and SEO content. Keep it short and simple. The product/service name is usually the best choice.
+
+ The title is used on the header, emails, notifications and SEO content. Keep it short and simple. The product/service name is usually the best
+ choice.
+
-
+
- The message is shown on this site's home page. Use it to help visitors understad what this space is about and the importance of their feedback. Leave it empty for a default message.
+ The message is shown on this site's home page. Use it to help visitors understad what this space is about and the importance of their feedback.
+ Leave it empty for a default message.
@@ -102,12 +112,22 @@ export default class GeneralSettingsPage extends AdminBasePage<{}, GeneralSettin
onChange={this.setInvitation}
>
- This text is used as a placeholder for the suggestion's text box. Use it to invite your visitors into sharing their suggestions and feedback. Leave it empty for a default message.
+ This text is used as a placeholder for the suggestion's text box. Use it to invite your visitors into sharing their suggestions and feedback.
+ Leave it empty for a default message.
-
- We accept JPG, GIF and PNG images, smaller than 100KB and with an aspect ratio of 1:1 with minimum dimensions of 200x200 pixels.
+
+
+ We accept JPG, GIF and PNG images, smaller than 100KB and with an aspect ratio of 1:1 with minimum dimensions of 200x200 pixels.
+
{!Fider.isSingleHostMode() && (
@@ -143,6 +163,6 @@ export default class GeneralSettingsPage extends AdminBasePage<{}, GeneralSettin
- );
+ )
}
}
diff --git a/public/pages/Administration/pages/Invitations.page.tsx b/public/pages/Administration/pages/Invitations.page.tsx
index b0587bee5..e1eb229d8 100644
--- a/public/pages/Administration/pages/Invitations.page.tsx
+++ b/public/pages/Administration/pages/Invitations.page.tsx
@@ -1,28 +1,28 @@
-import React from "react";
+import React from "react"
-import { Button, ButtonClickEvent, TextArea, Form, Input, Field } from "@fider/components";
-import { actions, notify, Failure, Fider } from "@fider/services";
-import { AdminBasePage } from "../components/AdminBasePage";
-import { FaEnvelope } from "react-icons/fa";
+import { Button, TextArea, Form, Input, Field } from "@fider/components"
+import { actions, notify, Failure, Fider } from "@fider/services"
+import { AdminBasePage } from "../components/AdminBasePage"
+import { FaEnvelope } from "react-icons/fa"
interface InvitationsPageState {
- subject: string;
- message: string;
- recipients: string[];
- numOfRecipients: number;
- rawRecipients: string;
- error?: Failure;
+ subject: string
+ message: string
+ recipients: string[]
+ numOfRecipients: number
+ rawRecipients: string
+ error?: Failure
}
-export default class InvitationsPage extends AdminBasePage<{}, InvitationsPageState> {
- public id = "p-admin-invitations";
- public name = "invitations";
- public icon = FaEnvelope;
- public title = "Invitations";
- public subtitle = "Invite people to share their feedback";
+export default class InvitationsPage extends AdminBasePage {
+ public id = "p-admin-invitations"
+ public name = "invitations"
+ public icon = FaEnvelope
+ public title = "Invitations"
+ public subtitle = "Invite people to share their feedback"
- constructor(props: {}) {
- super(props);
+ constructor(props: any) {
+ super(props)
this.state = {
subject: `Share your ideas and thoughts about ${Fider.session.tenant.name}`,
@@ -41,52 +41,59 @@ ${Fider.session.user.name} (${Fider.session.tenant.name})`,
recipients: [],
numOfRecipients: 0,
rawRecipients: "",
- };
+ }
}
private setRecipients = (rawRecipients: string) => {
- const recipients = rawRecipients.split(/\n|;|,|\s/gm).filter((x) => !!x);
- this.setState({ rawRecipients, recipients, numOfRecipients: recipients.length });
- };
+ const recipients = rawRecipients.split(/\n|;|,|\s/gm).filter((x) => !!x)
+ this.setState({ rawRecipients, recipients, numOfRecipients: recipients.length })
+ }
- private sendSample = async (e: ButtonClickEvent) => {
- const result = await actions.sendSampleInvite(this.state.subject, this.state.message);
+ private sendSample = async () => {
+ const result = await actions.sendSampleInvite(this.state.subject, this.state.message)
if (result.ok) {
notify.success(
An email message was sent to {Fider.session.user.email}
- );
+ )
}
- this.setState({ error: result.error });
- };
+ this.setState({ error: result.error })
+ }
- private sendInvites = async (e: ButtonClickEvent) => {
- const result = await actions.sendInvites(this.state.subject, this.state.message, this.state.recipients);
+ private sendInvites = async () => {
+ const result = await actions.sendInvites(this.state.subject, this.state.message, this.state.recipients)
if (result.ok) {
- notify.success("Your invites have been sent.");
- this.setState({ rawRecipients: "", numOfRecipients: 0, recipients: [], error: undefined });
+ notify.success("Your invites have been sent.")
+ this.setState({ rawRecipients: "", numOfRecipients: 0, recipients: [], error: undefined })
} else {
- this.setState({ error: result.error });
+ this.setState({ error: result.error })
}
- };
+ }
private setSubject = (subject: string): void => {
- this.setState({ subject });
- };
+ this.setState({ subject })
+ }
private setMessage = (message: string): void => {
- this.setState({ message });
- };
+ this.setState({ message })
+ }
public content() {
return (
-
+
- Input the list of all email addresses you wish to invite. Separate each address with either semicolon , comma , whitespace or{" "}
- line break .
+ Input the list of all email addresses you wish to invite. Separate each address with either semicolon , comma ,{" "}
+ whitespace or line break .
You can send this invite to a maximum of 30 recipients each time.
@@ -98,29 +105,34 @@ ${Fider.session.user.name} (${Fider.session.tenant.name})`,
-
This is the content of the invite. Be polite and explain what this invite is for, otherwise there's a high change people will ignore your message.
- You're allowed to write whatever you want as long as you include the invitation link placeholder named %invite% .
+ This is the content of the invite. Be polite and explain what this invite is for, otherwise there's a high change people will ignore your
+ message.
+
+
+ You're allowed to write whatever you want as long as you include the invitation link placeholder named %invite% .
- We highly recommend to send yourself a sample email for you to verify if everything is correct before inviting your list of contacts.
+
+ We highly recommend to send yourself a sample email for you to verify if everything is correct before inviting your list of contacts.
+
{Fider.session.user.email ? (
Send a sample email to {Fider.session.user.email}
) : (
- Your profile doesn't have an email
+ Your profile doesn't have an email
)}
- Whenever you're ready, click the following button to send out these invites.
+ Whenever you're ready, click the following button to send out these invites.
Send {this.state.numOfRecipients} {this.state.numOfRecipients === 1 ? "invite" : "invites"}
- );
+ )
}
}
diff --git a/public/pages/Administration/pages/ManageAuthentication.page.tsx b/public/pages/Administration/pages/ManageAuthentication.page.tsx
index 875b5019b..13537aec3 100644
--- a/public/pages/Administration/pages/ManageAuthentication.page.tsx
+++ b/public/pages/Administration/pages/ManageAuthentication.page.tsx
@@ -1,77 +1,81 @@
-import React from "react";
+import React from "react"
-import { Segment, List, ListItem, Button, Heading, OAuthProviderLogo } from "@fider/components";
-import { OAuthConfig, OAuthProviderOption } from "@fider/models";
-import { OAuthForm } from "../components/OAuthForm";
-import { actions, notify, Fider } from "@fider/services";
-import { FaEdit, FaPlay, FaSignInAlt } from "react-icons/fa";
-import { AdminBasePage } from "../components/AdminBasePage";
+import { Segment, List, ListItem, Button, Heading, OAuthProviderLogo } from "@fider/components"
+import { OAuthConfig, OAuthProviderOption } from "@fider/models"
+import { OAuthForm } from "../components/OAuthForm"
+import { actions, notify, Fider } from "@fider/services"
+import { FaEdit, FaPlay, FaSignInAlt } from "react-icons/fa"
+import { AdminBasePage } from "../components/AdminBasePage"
-import "./ManageAuthentication.page.scss";
+import "./ManageAuthentication.page.scss"
interface ManageAuthenticationPageProps {
- providers: OAuthProviderOption[];
+ providers: OAuthProviderOption[]
}
interface ManageAuthenticationPageState {
- isAdding: boolean;
- editing?: OAuthConfig;
+ isAdding: boolean
+ editing?: OAuthConfig
}
export default class ManageAuthenticationPage extends AdminBasePage {
- public id = "p-admin-authentication";
- public name = "authentication";
- public icon = FaSignInAlt;
- public title = "Authentication";
- public subtitle = "Manage your site authentication";
+ public id = "p-admin-authentication"
+ public name = "authentication"
+ public icon = FaSignInAlt
+ public title = "Authentication"
+ public subtitle = "Manage your site authentication"
constructor(props: ManageAuthenticationPageProps) {
- super(props);
+ super(props)
this.state = {
isAdding: false,
- };
+ }
}
private addNew = async () => {
- this.setState({ isAdding: true, editing: undefined });
- };
+ this.setState({ isAdding: true, editing: undefined })
+ }
private edit = async (provider: string) => {
- const result = await actions.getOAuthConfig(provider);
+ const result = await actions.getOAuthConfig(provider)
if (result.ok) {
- this.setState({ editing: result.data, isAdding: false });
+ this.setState({ editing: result.data, isAdding: false })
} else {
- notify.error("Failed to retrieve OAuth configuration. Try again later");
+ notify.error("Failed to retrieve OAuth configuration. Try again later")
}
- };
+ }
private startTest = async (provider: string) => {
- const redirect = `${Fider.settings.baseURL}/oauth/${provider}/echo`;
- window.open(`/oauth/${provider}?redirect=${redirect}`, "oauth-test", "width=1100,height=600,status=no,menubar=no");
- };
+ const redirect = `${Fider.settings.baseURL}/oauth/${provider}/echo`
+ window.open(`/oauth/${provider}?redirect=${redirect}`, "oauth-test", "width=1100,height=600,status=no,menubar=no")
+ }
private cancel = async () => {
- this.setState({ isAdding: false, editing: undefined });
- };
+ this.setState({ isAdding: false, editing: undefined })
+ }
public content() {
if (this.state.isAdding) {
- return ;
+ return
}
if (this.state.editing) {
- return ;
+ return
}
- const enabled = Enabled
;
- const disabled = Disabled
;
+ const enabled = Enabled
+ const disabled = Disabled
return (
<>
-
+
Additional information is available in our{" "}
-
+
OAuth Documentation
.
@@ -115,6 +119,6 @@ export default class ManageAuthenticationPage extends AdminBasePage
)}
>
- );
+ )
}
}
diff --git a/public/pages/Administration/pages/ManageMembers.page.tsx b/public/pages/Administration/pages/ManageMembers.page.tsx
index be3c837a7..48e87dc2a 100644
--- a/public/pages/Administration/pages/ManageMembers.page.tsx
+++ b/public/pages/Administration/pages/ManageMembers.page.tsx
@@ -1,40 +1,40 @@
-import "./ManageMembers.page.scss";
+import "./ManageMembers.page.scss"
-import React from "react";
-import { Segment, List, Input, ListItem, Avatar, UserName, DropDown, DropDownItem } from "@fider/components/common";
-import { User, UserRole, UserStatus } from "@fider/models";
-import { AdminBasePage } from "../components/AdminBasePage";
-import { FaUsers, FaEllipsisH, FaTimes, FaSearch } from "react-icons/fa";
-import { actions, Fider } from "@fider/services";
+import React from "react"
+import { Segment, List, Input, ListItem, Avatar, UserName, DropDown, DropDownItem } from "@fider/components/common"
+import { User, UserRole, UserStatus } from "@fider/models"
+import { AdminBasePage } from "../components/AdminBasePage"
+import { FaUsers, FaEllipsisH, FaTimes, FaSearch } from "react-icons/fa"
+import { actions, Fider } from "@fider/services"
interface ManageMembersPageState {
- query: string;
- users: User[];
- visibleUsers: User[];
+ query: string
+ users: User[]
+ visibleUsers: User[]
}
interface ManageMembersPageProps {
- users: User[];
+ users: User[]
}
interface UserListItemProps {
- user: User;
- onAction: (actionName: string, user: User) => Promise;
+ user: User
+ onAction: (actionName: string, user: User) => Promise
}
const UserListItem = (props: UserListItemProps) => {
- const admin = props.user.role === UserRole.Administrator && administrator ;
- const collaborator = props.user.role === UserRole.Collaborator && collaborator ;
- const blocked = props.user.status === UserStatus.Blocked && blocked ;
- const isVisitor = props.user.role === UserRole.Visitor;
+ const admin = props.user.role === UserRole.Administrator && administrator
+ const collaborator = props.user.role === UserRole.Collaborator && collaborator
+ const blocked = props.user.status === UserStatus.Blocked && blocked
+ const isVisitor = props.user.role === UserRole.Visitor
const renderEllipsis = () => {
- return ;
- };
+ return
+ }
const actionSelected = (item: DropDownItem) => {
- props.onAction(item.value, props.user);
- };
+ props.onAction(item.value, props.user)
+ }
return (
@@ -63,89 +63,89 @@ const UserListItem = (props: UserListItemProps) => {
/>
)}
- );
-};
+ )
+}
export default class ManageMembersPage extends AdminBasePage {
- public id = "p-admin-members";
- public name = "members";
- public icon = FaUsers;
- public title = "Members";
- public subtitle = "Manage your site administrators and collaborators";
+ public id = "p-admin-members"
+ public name = "members"
+ public icon = FaUsers
+ public title = "Members"
+ public subtitle = "Manage your site administrators and collaborators"
constructor(props: ManageMembersPageProps) {
- super(props);
+ super(props)
- const users = this.props.users.sort(this.sortByStaff);
+ const users = this.props.users.sort(this.sortByStaff)
this.state = {
query: "",
users,
visibleUsers: users.slice(0, 10),
- };
+ }
}
private showMore = (event: React.MouseEvent | React.TouchEvent): void => {
- event.preventDefault();
+ event.preventDefault()
this.setState({
visibleUsers: this.state.users.slice(0, this.state.visibleUsers.length + 10),
- });
- };
+ })
+ }
private clearSearch = () => {
- this.handleSearchFilterChanged("");
- };
+ this.handleSearchFilterChanged("")
+ }
private handleSearchFilterChanged = (query: string) => {
- const users = this.props.users.filter((x) => x.name.toLowerCase().indexOf(query.toLowerCase()) >= 0).sort(this.sortByStaff);
- this.setState({ query, users, visibleUsers: users.slice(0, 10) });
- };
+ const users = this.props.users.filter((x) => x.name.toLowerCase().indexOf(query.toLowerCase()) >= 0).sort(this.sortByStaff)
+ this.setState({ query, users, visibleUsers: users.slice(0, 10) })
+ }
private handleAction = async (actionName: string, user: User) => {
const changeRole = async (role: UserRole) => {
- const result = await actions.changeUserRole(user.id, role);
+ const result = await actions.changeUserRole(user.id, role)
if (result.ok) {
- user.role = role;
+ user.role = role
}
- this.handleSearchFilterChanged(this.state.query);
- };
+ this.handleSearchFilterChanged(this.state.query)
+ }
const changeStatus = async (status: UserStatus) => {
- const action = status === UserStatus.Blocked ? actions.blockUser : actions.unblockUser;
- const result = await action(user.id);
+ const action = status === UserStatus.Blocked ? actions.blockUser : actions.unblockUser
+ const result = await action(user.id)
if (result.ok) {
- user.status = status;
+ user.status = status
}
- this.forceUpdate();
- };
+ this.forceUpdate()
+ }
if (actionName === "to-collaborator") {
- await changeRole(UserRole.Collaborator);
+ await changeRole(UserRole.Collaborator)
} else if (actionName === "to-visitor") {
- await changeRole(UserRole.Visitor);
+ await changeRole(UserRole.Visitor)
} else if (actionName === "to-administrator") {
- await changeRole(UserRole.Administrator);
+ await changeRole(UserRole.Administrator)
} else if (actionName === "block") {
- await changeStatus(UserStatus.Blocked);
+ await changeStatus(UserStatus.Blocked)
} else if (actionName === "unblock") {
- await changeStatus(UserStatus.Active);
+ await changeStatus(UserStatus.Active)
}
- };
+ }
private sortByStaff = (left: User, right: User) => {
if (right.role === left.role) {
if (left.name < right.name) {
- return -1;
+ return -1
} else if (left.name > right.name) {
- return 1;
+ return 1
}
- return 0;
+ return 0
}
if (right.role !== UserRole.Visitor) {
- return 1;
+ return 1
}
- return -1;
- };
+ return -1
+ }
public content() {
return (
@@ -174,7 +174,7 @@ export default class ManageMembersPage extends AdminBasePage
- Showing {this.state.visibleUsers.length} of {this.state.users.length} users matching '{this.state.query}'
+ Showing {this.state.visibleUsers.length} of {this.state.users.length} users matching '{this.state.query}'
>
)}
{this.state.visibleUsers.length < this.state.users.length && (
@@ -195,6 +195,6 @@ export default class ManageMembersPage extends AdminBasePage
>
- );
+ )
}
}
diff --git a/public/pages/Administration/pages/ManageTags.page.tsx b/public/pages/Administration/pages/ManageTags.page.tsx
index a4d93001f..fa86d9365 100644
--- a/public/pages/Administration/pages/ManageTags.page.tsx
+++ b/public/pages/Administration/pages/ManageTags.page.tsx
@@ -1,48 +1,48 @@
-import "./ManageTags.page.scss";
+import "./ManageTags.page.scss"
-import React from "react";
-import { Button, Segment, List, ListItem, Heading } from "@fider/components";
+import React from "react"
+import { Button, Segment, List, ListItem, Heading } from "@fider/components"
-import { Tag } from "@fider/models";
-import { actions, Failure, Fider } from "@fider/services";
-import { FaTags } from "react-icons/fa";
-import { AdminBasePage } from "../components/AdminBasePage";
-import { TagFormState, TagForm } from "../components/TagForm";
-import { TagListItem } from "../components/TagListItem";
+import { Tag } from "@fider/models"
+import { actions, Failure, Fider } from "@fider/services"
+import { FaTags } from "react-icons/fa"
+import { AdminBasePage } from "../components/AdminBasePage"
+import { TagFormState, TagForm } from "../components/TagForm"
+import { TagListItem } from "../components/TagListItem"
interface ManageTagsPageProps {
- tags: Tag[];
+ tags: Tag[]
}
interface ManageTagsPageState {
- isAdding: boolean;
- allTags: Tag[];
- deleting?: number;
- editing?: number;
+ isAdding: boolean
+ allTags: Tag[]
+ deleting?: number
+ editing?: number
}
const tagSorter = (t1: Tag, t2: Tag) => {
if (t1.name < t2.name) {
- return -1;
+ return -1
} else if (t1.name > t2.name) {
- return 1;
+ return 1
}
- return 0;
-};
+ return 0
+}
export default class ManageTagsPage extends AdminBasePage {
- public id = "p-admin-tags";
- public name = "tags";
- public icon = FaTags;
- public title = "Tags";
- public subtitle = "Manage your site tags";
+ public id = "p-admin-tags"
+ public name = "tags"
+ public icon = FaTags
+ public title = "Tags"
+ public subtitle = "Manage your site tags"
constructor(props: ManageTagsPageProps) {
- super(props);
+ super(props)
this.state = {
isAdding: false,
allTags: this.props.tags,
- };
+ }
}
private addNew = async () => {
@@ -50,47 +50,47 @@ export default class ManageTagsPage extends AdminBasePage {
- this.setState({ isAdding: false });
- };
+ this.setState({ isAdding: false })
+ }
private saveNewTag = async (data: TagFormState): Promise => {
- const result = await actions.createTag(data.name, data.color, data.isPublic);
+ const result = await actions.createTag(data.name, data.color, data.isPublic)
if (result.ok) {
this.setState({
isAdding: false,
allTags: this.state.allTags.concat(result.data).sort(tagSorter),
- });
+ })
} else {
- return result.error;
+ return result.error
}
- };
+ }
private handleTagDeleted = (tag: Tag) => {
- const idx = this.state.allTags.indexOf(tag);
+ const idx = this.state.allTags.indexOf(tag)
this.setState({
allTags: this.state.allTags.splice(idx, 1) && this.state.allTags,
- });
- };
+ })
+ }
- private handleTagEdited = (tag: Tag) => {
+ private handleTagEdited = () => {
this.setState({
allTags: this.state.allTags.sort(tagSorter),
- });
- };
+ })
+ }
private getTagList(filter: (tag: Tag) => boolean) {
return this.state.allTags.filter(filter).map((t) => {
- return ;
- });
+ return
+ })
}
public content() {
- const publicTaglist = this.getTagList((t) => t.isPublic);
- const privateTagList = this.getTagList((t) => !t.isPublic);
+ const publicTaglist = this.getTagList((t) => t.isPublic)
+ const privateTagList = this.getTagList((t) => !t.isPublic)
const form =
Fider.session.user.isAdministrator &&
@@ -102,7 +102,7 @@ export default class ManageTagsPage extends AdminBasePage
Add new
- ));
+ ))
return (
<>
@@ -125,6 +125,6 @@ export default class ManageTagsPage extends AdminBasePage
{form}
>
- );
+ )
}
}
diff --git a/public/pages/Administration/pages/PrivacySettings.page.tsx b/public/pages/Administration/pages/PrivacySettings.page.tsx
index 7e21e795d..0fba8e72e 100644
--- a/public/pages/Administration/pages/PrivacySettings.page.tsx
+++ b/public/pages/Administration/pages/PrivacySettings.page.tsx
@@ -1,43 +1,43 @@
-import "./PrivacySettings.page.scss";
+import "./PrivacySettings.page.scss"
-import React from "react";
-import { Toggle, Form } from "@fider/components/common";
-import { actions, notify, Fider } from "@fider/services";
-import { AdminBasePage } from "@fider/pages/Administration/components/AdminBasePage";
-import { FaKey } from "react-icons/fa";
+import React from "react"
+import { Toggle, Form } from "@fider/components/common"
+import { actions, notify, Fider } from "@fider/services"
+import { AdminBasePage } from "@fider/pages/Administration/components/AdminBasePage"
+import { FaKey } from "react-icons/fa"
interface PrivacySettingsPageState {
- isPrivate: boolean;
+ isPrivate: boolean
}
-export default class PrivacySettingsPage extends AdminBasePage<{}, PrivacySettingsPageState> {
- public id = "p-admin-privacy";
- public name = "privacy";
- public icon = FaKey;
- public title = "Privacy";
- public subtitle = "Manage your site privacy";
+export default class PrivacySettingsPage extends AdminBasePage {
+ public id = "p-admin-privacy"
+ public name = "privacy"
+ public icon = FaKey
+ public title = "Privacy"
+ public subtitle = "Manage your site privacy"
- constructor(props: {}) {
- super(props);
+ constructor(props: any) {
+ super(props)
this.state = {
isPrivate: Fider.session.tenant.isPrivate,
- };
+ }
}
private toggle = async (active: boolean) => {
this.setState(
- (state) => ({
+ () => ({
isPrivate: active,
}),
async () => {
- const response = await actions.updateTenantPrivacy(this.state.isPrivate);
+ const response = await actions.updateTenantPrivacy(this.state.isPrivate)
if (response.ok) {
- notify.success("Your privacy settings have been saved.");
+ notify.success("Your privacy settings have been saved.")
}
}
- );
- };
+ )
+ }
public content() {
return (
@@ -46,11 +46,11 @@ export default class PrivacySettingsPage extends AdminBasePage<{}, PrivacySettin
Private site
- A private site prevents unauthenticated users from viewing or interacting with its content. If enabled, only already registered and invited users will be able to sign in to this
- site.
+ A private site prevents unauthenticated users from viewing or interacting with its content. If enabled, only already registered and invited
+ users will be able to sign in to this site.
- );
+ )
}
}
diff --git a/public/pages/CompleteSignInProfile/CompleteSignInProfile.page.tsx b/public/pages/CompleteSignInProfile/CompleteSignInProfile.page.tsx
index b6ca53a45..fc838493e 100644
--- a/public/pages/CompleteSignInProfile/CompleteSignInProfile.page.tsx
+++ b/public/pages/CompleteSignInProfile/CompleteSignInProfile.page.tsx
@@ -1,42 +1,42 @@
-import React from "react";
+import React from "react"
-import HomePage, { HomePageProps } from "../Home/Home.page";
-import SignInPage from "../SignIn/SignIn.page";
-import { Modal, Button, Form, Input, LegalFooter } from "@fider/components";
-import { actions, Failure, querystring, Fider } from "@fider/services";
+import HomePage, { HomePageProps } from "../Home/Home.page"
+import SignInPage from "../SignIn/SignIn.page"
+import { Modal, Button, Form, Input, LegalFooter } from "@fider/components"
+import { actions, Failure, querystring, Fider } from "@fider/services"
interface CompleteSignInProfilePageState {
- name: string;
- error?: Failure;
+ name: string
+ error?: Failure
}
export default class CompleteSignInProfilePage extends React.Component {
- private key: string;
+ private key: string
constructor(props: HomePageProps) {
- super(props);
- this.key = querystring.get("k");
+ super(props)
+ this.key = querystring.get("k")
this.state = {
name: "",
- };
+ }
}
private submit = async () => {
- const result = await actions.completeProfile(this.key, this.state.name);
+ const result = await actions.completeProfile(this.key, this.state.name)
if (result.ok) {
- location.href = "/";
+ location.href = "/"
} else if (result.error) {
- this.setState({ error: result.error });
+ this.setState({ error: result.error })
}
- };
+ }
private setName = (name: string) => {
- this.setState({ name });
- };
+ this.setState({ name })
+ }
private noop = () => {
// do nothing
- };
+ }
public render() {
return (
@@ -63,6 +63,6 @@ export default class CompleteSignInProfilePage extends React.Component
{Fider.session.tenant.isPrivate ? React.createElement(SignInPage, this.props) : React.createElement(HomePage, this.props)}
>
- );
+ )
}
}
diff --git a/public/pages/CompleteSignInProfile/index.ts b/public/pages/CompleteSignInProfile/index.ts
index c202aa12a..140ec0c8a 100644
--- a/public/pages/CompleteSignInProfile/index.ts
+++ b/public/pages/CompleteSignInProfile/index.ts
@@ -1 +1 @@
-export * from "./CompleteSignInProfile.page";
+export * from "./CompleteSignInProfile.page"
diff --git a/public/pages/Error/Error.page.spec.tsx b/public/pages/Error/Error.page.spec.tsx
index e00067387..a6e9fec84 100644
--- a/public/pages/Error/Error.page.spec.tsx
+++ b/public/pages/Error/Error.page.spec.tsx
@@ -1,24 +1,24 @@
-import React from "react";
-import { shallow } from "enzyme";
-import { ErrorPage } from "./Error.page";
+import React from "react"
+import { shallow } from "enzyme"
+import { ErrorPage } from "./Error.page"
describe(" ", () => {
- const createFakeErrorInfo = () => ({ componentStack: "" } as React.ErrorInfo);
+ const createFakeErrorInfo = () => ({ componentStack: "" } as React.ErrorInfo)
test("it should show the error when showError returns true", () => {
- const error = new Error("Hello");
- const errorInfo = createFakeErrorInfo();
+ const error = new Error("Hello")
+ const errorInfo = createFakeErrorInfo()
- const wrapper = shallow( );
- expect(wrapper.find("pre")).toHaveLength(1);
- });
+ const wrapper = shallow( )
+ expect(wrapper.find("pre")).toHaveLength(1)
+ })
test("it should not show the error when showError returns false", () => {
- const error = new Error("Hello");
- const errorInfo = createFakeErrorInfo();
+ const error = new Error("Hello")
+ const errorInfo = createFakeErrorInfo()
- const wrapper = shallow( );
+ const wrapper = shallow( )
- expect(wrapper.find("pre")).toHaveLength(0);
- });
-});
+ expect(wrapper.find("pre")).toHaveLength(0)
+ })
+})
diff --git a/public/pages/Error/Error.page.tsx b/public/pages/Error/Error.page.tsx
index 3858ef062..0720e94c0 100644
--- a/public/pages/Error/Error.page.tsx
+++ b/public/pages/Error/Error.page.tsx
@@ -1,23 +1,23 @@
-import "./Error.page.scss";
+import "./Error.page.scss"
-import React from "react";
-import { TenantLogo } from "@fider/components";
-import { useFider } from "@fider/hooks";
+import React from "react"
+import { TenantLogo } from "@fider/components"
+import { useFider } from "@fider/hooks"
interface ErrorPageProps {
- error: Error;
- errorInfo: React.ErrorInfo;
- showDetails?: boolean;
+ error: Error
+ errorInfo: React.ErrorInfo
+ showDetails?: boolean
}
export const ErrorPage = (props: ErrorPageProps) => {
- const fider = useFider();
+ const fider = useFider()
return (
Shoot! Well, this is unexpected…
-
An error has occurred and we're working to fix the problem!
+
An error has occurred and we're working to fix the problem!
{fider.settings && (
Take me back to {fider.settings.baseURL} home page.
@@ -30,5 +30,5 @@ export const ErrorPage = (props: ErrorPageProps) => {
)}
- );
-};
+ )
+}
diff --git a/public/pages/Error/index.ts b/public/pages/Error/index.ts
index 3b465175c..a034829a2 100644
--- a/public/pages/Error/index.ts
+++ b/public/pages/Error/index.ts
@@ -1 +1 @@
-export * from "./Error.page";
+export * from "./Error.page"
diff --git a/public/pages/Home/Home.page.tsx b/public/pages/Home/Home.page.tsx
index 383aacc27..adb0ca1a7 100644
--- a/public/pages/Home/Home.page.tsx
+++ b/public/pages/Home/Home.page.tsx
@@ -1,60 +1,61 @@
-import "./Home.page.scss";
+import "./Home.page.scss"
-import React, { useState } from "react";
-import { Post, Tag, PostStatus } from "@fider/models";
-import { MultiLineText, Hint } from "@fider/components";
-import { SimilarPosts } from "./components/SimilarPosts";
-import { FaRegLightbulb } from "react-icons/fa";
-import { PostInput } from "./components/PostInput";
-import { PostsContainer } from "./components/PostsContainer";
-import { useFider } from "@fider/hooks";
+import React, { useState } from "react"
+import { Post, Tag, PostStatus } from "@fider/models"
+import { MultiLineText, Hint } from "@fider/components"
+import { SimilarPosts } from "./components/SimilarPosts"
+import { FaRegLightbulb } from "react-icons/fa"
+import { PostInput } from "./components/PostInput"
+import { PostsContainer } from "./components/PostsContainer"
+import { useFider } from "@fider/hooks"
export interface HomePageProps {
- posts: Post[];
- tags: Tag[];
- countPerStatus: { [key: string]: number };
+ posts: Post[]
+ tags: Tag[]
+ countPerStatus: { [key: string]: number }
}
export interface HomePageState {
- title: string;
+ title: string
}
const Lonely = () => {
- const fider = useFider();
+ const fider = useFider()
return (
- It's recommended that you post at least 3 suggestions here before sharing this site. The initial content is key to start the interactions with your audience.
+ It's recommended that you post at least 3 suggestions here before sharing this site. The initial content is key to start the
+ interactions with your audience.
-
It's lonely out here. Start by sharing a suggestion!
+
It's lonely out here. Start by sharing a suggestion!
- );
-};
+ )
+}
const defaultWelcomeMessage = `We'd love to hear what you're thinking about.
-What can we do better? This is the place for you to vote, discuss and share ideas.`;
+What can we do better? This is the place for you to vote, discuss and share ideas.`
const HomePage = (props: HomePageProps) => {
- const fider = useFider();
- const [title, setTitle] = useState("");
+ const fider = useFider()
+ const [title, setTitle] = useState("")
const isLonely = () => {
- const len = Object.keys(props.countPerStatus).length;
+ const len = Object.keys(props.countPerStatus).length
if (len === 0) {
- return true;
+ return true
}
if (len === 1 && PostStatus.Deleted.value in props.countPerStatus) {
- return true;
+ return true
}
- return false;
- };
+ return false
+ }
return (
@@ -64,11 +65,17 @@ const HomePage = (props: HomePageProps) => {
- {isLonely() ?
: title ?
:
}
+ {isLonely() ? (
+
+ ) : title ? (
+
+ ) : (
+
+ )}
- );
-};
+ )
+}
-export default HomePage;
+export default HomePage
diff --git a/public/pages/Home/components/ListPosts.tsx b/public/pages/Home/components/ListPosts.tsx
index ec6451262..1129ae638 100644
--- a/public/pages/Home/components/ListPosts.tsx
+++ b/public/pages/Home/components/ListPosts.tsx
@@ -1,14 +1,14 @@
-import "./ListPosts.scss";
+import "./ListPosts.scss"
-import React from "react";
-import { Post, Tag, CurrentUser } from "@fider/models";
-import { ShowTag, ShowPostResponse, VoteCounter, MultiLineText, ListItem, List } from "@fider/components";
-import { FaRegComments } from "react-icons/fa";
+import React from "react"
+import { Post, Tag, CurrentUser } from "@fider/models"
+import { ShowTag, ShowPostResponse, VoteCounter, MultiLineText, ListItem, List } from "@fider/components"
+import { FaRegComments } from "react-icons/fa"
interface ListPostsProps {
- posts?: Post[];
- tags: Tag[];
- emptyText: string;
+ posts?: Post[]
+ tags: Tag[]
+ emptyText: string
}
const ListPostItem = (props: { post: Post; user?: CurrentUser; tags: Tag[] }) => {
@@ -31,16 +31,16 @@ const ListPostItem = (props: { post: Post; user?: CurrentUser; tags: Tag[] }) =>
))}
- );
-};
+ )
+}
export const ListPosts = (props: ListPostsProps) => {
if (!props.posts) {
- return null;
+ return null
}
if (props.posts.length === 0) {
- return {props.emptyText}
;
+ return {props.emptyText}
}
return (
@@ -49,5 +49,5 @@ export const ListPosts = (props: ListPostsProps) => {
post.tags.indexOf(tag.slug) >= 0)} />
))}
- );
-};
+ )
+}
diff --git a/public/pages/Home/components/PostFilter.tsx b/public/pages/Home/components/PostFilter.tsx
index 8c4e20b09..658afb585 100644
--- a/public/pages/Home/components/PostFilter.tsx
+++ b/public/pages/Home/components/PostFilter.tsx
@@ -1,32 +1,32 @@
-import "./PostFilter.scss";
+import "./PostFilter.scss"
-import React from "react";
-import { PostStatus } from "@fider/models";
-import { DropDown, DropDownItem } from "@fider/components";
-import { useFider } from "@fider/hooks";
+import React from "react"
+import { PostStatus } from "@fider/models"
+import { DropDown, DropDownItem } from "@fider/components"
+import { useFider } from "@fider/hooks"
interface PostFilterProps {
- activeView: string;
- countPerStatus: { [key: string]: number };
- viewChanged: (name: string) => void;
+ activeView: string
+ countPerStatus: { [key: string]: number }
+ viewChanged: (name: string) => void
}
export const PostFilter = (props: PostFilterProps) => {
- const fider = useFider();
+ const fider = useFider()
const handleChangeView = (item: DropDownItem) => {
- props.viewChanged(item.value as string);
- };
+ props.viewChanged(item.value as string)
+ }
const options: DropDownItem[] = [
{ value: "trending", label: "Trending" },
{ value: "recent", label: "Recent" },
{ value: "most-wanted", label: "Most Wanted" },
{ value: "most-discussed", label: "Most Discussed" },
- ];
+ ]
if (fider.session.isAuthenticated) {
- options.push({ value: "my-votes", label: "My Votes" });
+ options.push({ value: "my-votes", label: "My Votes" })
}
PostStatus.All.filter((s) => s.filterable && props.countPerStatus[s.value]).forEach((s) => {
@@ -38,16 +38,24 @@ export const PostFilter = (props: PostFilterProps) => {
{s.title} {props.countPerStatus[s.value]}
),
- });
- });
+ })
+ })
- const viewExists = options.filter((x) => x.value === props.activeView).length > 0;
- const activeView = viewExists ? props.activeView : "trending";
+ const viewExists = options.filter((x) => x.value === props.activeView).length > 0
+ const activeView = viewExists ? props.activeView : "trending"
return (
View
-
+
- );
-};
+ )
+}
diff --git a/public/pages/Home/components/PostInput.tsx b/public/pages/Home/components/PostInput.tsx
index a2e4cec2a..7f830ff65 100644
--- a/public/pages/Home/components/PostInput.tsx
+++ b/public/pages/Home/components/PostInput.tsx
@@ -1,72 +1,72 @@
-import React, { useState, useEffect, useRef } from "react";
-import { Button, ButtonClickEvent, Input, Form, TextArea, MultiImageUploader } from "@fider/components";
-import { SignInModal } from "@fider/components";
-import { cache, actions, Failure } from "@fider/services";
-import { ImageUpload } from "@fider/models";
-import { useFider } from "@fider/hooks";
+import React, { useState, useEffect, useRef } from "react"
+import { Button, ButtonClickEvent, Input, Form, TextArea, MultiImageUploader } from "@fider/components"
+import { SignInModal } from "@fider/components"
+import { cache, actions, Failure } from "@fider/services"
+import { ImageUpload } from "@fider/models"
+import { useFider } from "@fider/hooks"
interface PostInputProps {
- placeholder: string;
- onTitleChanged: (title: string) => void;
+ placeholder: string
+ onTitleChanged: (title: string) => void
}
-const CACHE_TITLE_KEY = "PostInput-Title";
-const CACHE_DESCRIPTION_KEY = "PostInput-Description";
+const CACHE_TITLE_KEY = "PostInput-Title"
+const CACHE_DESCRIPTION_KEY = "PostInput-Description"
export const PostInput = (props: PostInputProps) => {
const getCachedValue = (key: string): string => {
if (fider.session.isAuthenticated) {
- return cache.session.get(key) || "";
+ return cache.session.get(key) || ""
}
- return "";
- };
+ return ""
+ }
- const fider = useFider();
- const titleRef = useRef();
- const [title, setTitle] = useState(getCachedValue(CACHE_TITLE_KEY));
- const [description, setDescription] = useState(getCachedValue(CACHE_DESCRIPTION_KEY));
- const [isSignInModalOpen, setIsSignInModalOpen] = useState(false);
- const [attachments, setAttachments] = useState([]);
- const [error, setError] = useState(undefined);
+ const fider = useFider()
+ const titleRef = useRef()
+ const [title, setTitle] = useState(getCachedValue(CACHE_TITLE_KEY))
+ const [description, setDescription] = useState(getCachedValue(CACHE_DESCRIPTION_KEY))
+ const [isSignInModalOpen, setIsSignInModalOpen] = useState(false)
+ const [attachments, setAttachments] = useState([])
+ const [error, setError] = useState(undefined)
useEffect(() => {
- props.onTitleChanged(title);
- }, [title]);
+ props.onTitleChanged(title)
+ }, [title])
const handleTitleFocus = () => {
if (!fider.session.isAuthenticated && titleRef.current) {
- titleRef.current.blur();
- setIsSignInModalOpen(true);
+ titleRef.current.blur()
+ setIsSignInModalOpen(true)
}
- };
+ }
const handleTitleChange = (value: string) => {
- cache.session.set(CACHE_TITLE_KEY, value);
- setTitle(value);
- props.onTitleChanged(value);
- };
+ cache.session.set(CACHE_TITLE_KEY, value)
+ setTitle(value)
+ props.onTitleChanged(value)
+ }
- const hideModal = () => setIsSignInModalOpen(false);
- const clearError = () => setError(undefined);
+ const hideModal = () => setIsSignInModalOpen(false)
+ const clearError = () => setError(undefined)
const handleDescriptionChange = (value: string) => {
- cache.session.set(CACHE_DESCRIPTION_KEY, value);
- setDescription(value);
- };
+ cache.session.set(CACHE_DESCRIPTION_KEY, value)
+ setDescription(value)
+ }
const submit = async (event: ButtonClickEvent) => {
if (title) {
- const result = await actions.createPost(title, description, attachments);
+ const result = await actions.createPost(title, description, attachments)
if (result.ok) {
- clearError();
- cache.session.remove(CACHE_TITLE_KEY, CACHE_DESCRIPTION_KEY);
- location.href = `/posts/${result.data.number}/${result.data.slug}`;
- event.preventEnable();
+ clearError()
+ cache.session.remove(CACHE_TITLE_KEY, CACHE_DESCRIPTION_KEY)
+ location.href = `/posts/${result.data.number}/${result.data.slug}`
+ event.preventEnable()
} else if (result.error) {
- setError(result.error);
+ setError(result.error)
}
}
- };
+ }
const details = () => (
<>
@@ -76,7 +76,7 @@ export const PostInput = (props: PostInputProps) => {
Submit
>
- );
+ )
return (
<>
@@ -95,5 +95,5 @@ export const PostInput = (props: PostInputProps) => {
{title && details()}
>
- );
-};
+ )
+}
diff --git a/public/pages/Home/components/PostsContainer.tsx b/public/pages/Home/components/PostsContainer.tsx
index b15f34832..cf349a223 100644
--- a/public/pages/Home/components/PostsContainer.tsx
+++ b/public/pages/Home/components/PostsContainer.tsx
@@ -1,32 +1,32 @@
-import React from "react";
+import React from "react"
-import { Post, Tag, CurrentUser } from "@fider/models";
-import { Loader, Field, Input } from "@fider/components";
-import { actions, navigator, querystring } from "@fider/services";
-import { FaTimes, FaSearch } from "react-icons/fa";
-import { PostFilter } from "./PostFilter";
-import { ListPosts } from "./ListPosts";
-import { TagsFilter } from "./TagsFilter";
+import { Post, Tag, CurrentUser } from "@fider/models"
+import { Loader, Field, Input } from "@fider/components"
+import { actions, navigator, querystring } from "@fider/services"
+import { FaTimes, FaSearch } from "react-icons/fa"
+import { PostFilter } from "./PostFilter"
+import { ListPosts } from "./ListPosts"
+import { TagsFilter } from "./TagsFilter"
interface PostsContainerProps {
- user?: CurrentUser;
- posts: Post[];
- tags: Tag[];
- countPerStatus: { [key: string]: number };
+ user?: CurrentUser
+ posts: Post[]
+ tags: Tag[]
+ countPerStatus: { [key: string]: number }
}
interface PostsContainerState {
- loading: boolean;
- posts?: Post[];
- view: string;
- tags: string[];
- query: string;
- limit?: number;
+ loading: boolean
+ posts?: Post[]
+ view: string
+ tags: string[]
+ query: string
+ limit?: number
}
export class PostsContainer extends React.Component {
constructor(props: PostsContainerProps) {
- super(props);
+ super(props)
this.state = {
posts: this.props.posts,
@@ -35,12 +35,12 @@ export class PostsContainer extends React.Component(obj: Pick, reset: boolean): void {
this.setState(obj, () => {
- const query = this.state.query.trim().toLowerCase();
+ const query = this.state.query.trim().toLowerCase()
navigator.replaceState(
querystring.stringify({
tags: this.state.tags,
@@ -48,54 +48,54 @@ export class PostsContainer extends React.Component {
actions.searchPosts({ query, view, limit, tags }).then((response) => {
if (response.ok && this.state.loading) {
- this.setState({ loading: false, posts: response.data });
+ this.setState({ loading: false, posts: response.data })
}
- });
- }, 500);
+ })
+ }, 500)
}
private handleViewChanged = (view: string) => {
- this.changeFilterCriteria({ view }, true);
- };
+ this.changeFilterCriteria({ view }, true)
+ }
private handleTagsFilterChanged = (tags: string[]) => {
- this.changeFilterCriteria({ tags }, true);
- };
+ this.changeFilterCriteria({ tags }, true)
+ }
private handleSearchFilterChanged = (query: string) => {
- this.changeFilterCriteria({ query }, true);
- };
+ this.changeFilterCriteria({ query }, true)
+ }
private clearSearch = () => {
- this.changeFilterCriteria({ query: "" }, true);
- };
+ this.changeFilterCriteria({ query: "" }, true)
+ }
private showMore = (event: React.MouseEvent | React.TouchEvent): void => {
- event.preventDefault();
- this.changeFilterCriteria({ limit: (this.state.limit || 30) + 10 }, false);
- };
+ event.preventDefault()
+ this.changeFilterCriteria({ limit: (this.state.limit || 30) + 10 }, false)
+ }
private getShowMoreLink = (): string | undefined => {
if (this.state.posts && this.state.posts.length >= (this.state.limit || 30)) {
- return querystring.set("limit", (this.state.limit || 30) + 10);
+ return querystring.set("limit", (this.state.limit || 30) + 10)
}
- };
+ }
public render() {
- const showMoreLink = this.getShowMoreLink();
+ const showMoreLink = this.getShowMoreLink()
return (
<>
@@ -126,6 +126,6 @@ export class PostsContainer extends React.Component
)}
>
- );
+ )
}
}
diff --git a/public/pages/Home/components/SimilarPosts.tsx b/public/pages/Home/components/SimilarPosts.tsx
index e6e0d33cb..13c49c681 100644
--- a/public/pages/Home/components/SimilarPosts.tsx
+++ b/public/pages/Home/components/SimilarPosts.tsx
@@ -1,30 +1,30 @@
-import React from "react";
-import { Post, Tag, CurrentUser } from "@fider/models";
-import { Heading, Loader } from "@fider/components";
-import { ListPosts } from "./ListPosts";
-import { actions } from "@fider/services";
-import { FaRegLightbulb } from "react-icons/fa";
+import React from "react"
+import { Post, Tag, CurrentUser } from "@fider/models"
+import { Heading, Loader } from "@fider/components"
+import { ListPosts } from "./ListPosts"
+import { actions } from "@fider/services"
+import { FaRegLightbulb } from "react-icons/fa"
interface SimilarPostsProps {
- title: string;
- tags: Tag[];
- user?: CurrentUser;
+ title: string
+ tags: Tag[]
+ user?: CurrentUser
}
interface SimilarPostsState {
- title: string;
- posts: Post[];
- loading: boolean;
+ title: string
+ posts: Post[]
+ loading: boolean
}
export class SimilarPosts extends React.Component {
constructor(props: SimilarPostsProps) {
- super(props);
+ super(props)
this.state = {
title: props.title,
loading: !!props.title,
posts: [],
- };
+ }
}
public static getDerivedStateFromProps(nextProps: SimilarPostsProps, prevState: SimilarPostsState) {
@@ -32,36 +32,40 @@ export class SimilarPosts extends React.Component {
if (this.state.loading) {
actions.searchPosts({ query: this.state.title }).then((x) => {
if (x.ok) {
- this.setState({ loading: false, posts: x.data });
+ this.setState({ loading: false, posts: x.data })
}
- });
+ })
}
- };
+ }
public render() {
return (
<>
- {this.state.loading ? : }
+ {this.state.loading ? (
+
+ ) : (
+
+ )}
>
- );
+ )
}
}
diff --git a/public/pages/Home/components/TagsFilter.tsx b/public/pages/Home/components/TagsFilter.tsx
index a55c3209f..e6f406cb2 100644
--- a/public/pages/Home/components/TagsFilter.tsx
+++ b/public/pages/Home/components/TagsFilter.tsx
@@ -1,49 +1,49 @@
-import "./TagsFilter.scss";
+import "./TagsFilter.scss"
-import React from "react";
-import { Tag } from "@fider/models";
-import { ShowTag } from "@fider/components/ShowTag";
-import { DropDown, DropDownItem } from "@fider/components";
-import { FaCheck } from "react-icons/fa";
+import React from "react"
+import { Tag } from "@fider/models"
+import { ShowTag } from "@fider/components/ShowTag"
+import { DropDown, DropDownItem } from "@fider/components"
+import { FaCheck } from "react-icons/fa"
interface TagsFilterProps {
- tags: Tag[];
- defaultSelection: string[];
- selectionChanged: (selected: string[]) => void;
+ tags: Tag[]
+ defaultSelection: string[]
+ selectionChanged: (selected: string[]) => void
}
interface TagsFilterState {
- selected: string[];
+ selected: string[]
}
export class TagsFilter extends React.Component {
constructor(props: TagsFilterProps) {
- super(props);
+ super(props)
this.state = {
selected: props.defaultSelection,
- };
+ }
}
private onChange = (item: DropDownItem) => {
- let selected = [];
- const idx = this.state.selected.indexOf(item.value as string);
+ let selected = []
+ const idx = this.state.selected.indexOf(item.value as string)
if (idx >= 0) {
- selected = this.state.selected.splice(idx, 1) && this.state.selected;
+ selected = this.state.selected.splice(idx, 1) && this.state.selected
} else {
- selected = this.state.selected.concat(item.value as string);
+ selected = this.state.selected.concat(item.value as string)
}
- this.setState({ selected });
- this.props.selectionChanged(selected);
- };
+ this.setState({ selected })
+ this.props.selectionChanged(selected)
+ }
private renderText = () => {
- const text = this.state.selected.length === 0 ? "any tag" : this.state.selected.length === 1 ? "1 tag" : `${this.state.selected.length} tags`;
- return <>{text}>;
- };
+ const text = this.state.selected.length === 0 ? "any tag" : this.state.selected.length === 1 ? "1 tag" : `${this.state.selected.length} tags`
+ return <>{text}>
+ }
public render() {
if (this.props.tags.length === 0) {
- return null;
+ return null
}
const items = this.props.tags.map((t) => {
@@ -57,14 +57,22 @@ export class TagsFilter extends React.Component
),
- };
- });
+ }
+ })
return (
with
-
+
- );
+ )
}
}
diff --git a/public/pages/Home/index.ts b/public/pages/Home/index.ts
index 9372d4b5f..3f31d61c5 100644
--- a/public/pages/Home/index.ts
+++ b/public/pages/Home/index.ts
@@ -1 +1 @@
-export * from "./Home.page";
+export * from "./Home.page"
diff --git a/public/pages/MyNotifications/MyNotifications.page.tsx b/public/pages/MyNotifications/MyNotifications.page.tsx
index 6b157e7d6..e5965ddeb 100644
--- a/public/pages/MyNotifications/MyNotifications.page.tsx
+++ b/public/pages/MyNotifications/MyNotifications.page.tsx
@@ -1,37 +1,37 @@
-import "./MyNotifications.page.scss";
+import "./MyNotifications.page.scss"
-import React from "react";
+import React from "react"
-import { Notification } from "@fider/models";
-import { MultiLineText, Moment, Heading, List, ListItem } from "@fider/components";
-import { actions } from "@fider/services";
-import { FaBell } from "react-icons/fa";
+import { Notification } from "@fider/models"
+import { MultiLineText, Moment, Heading, List, ListItem } from "@fider/components"
+import { actions } from "@fider/services"
+import { FaBell } from "react-icons/fa"
interface MyNotificationsPageProps {
- notifications: Notification[];
+ notifications: Notification[]
}
interface MyNotificationsPageState {
- unread: Notification[];
- recent: Notification[];
+ unread: Notification[]
+ recent: Notification[]
}
export default class MyNotificationsPage extends React.Component {
constructor(props: MyNotificationsPageProps) {
- super(props);
+ super(props)
const [unread, recent] = (this.props.notifications || []).reduce(
(result, item) => {
- result[item.read ? 1 : 0].push(item);
- return result;
+ result[item.read ? 1 : 0].push(item)
+ return result
},
[[] as Notification[], [] as Notification[]]
- );
+ )
this.state = {
unread,
recent,
- };
+ }
}
private items(notifications: Notification[]): JSX.Element[] {
@@ -45,16 +45,16 @@ export default class MyNotificationsPage extends React.Component
- );
- });
+ )
+ })
}
private markAllAsRead = async () => {
- const response = await actions.markAllAsRead();
+ const response = await actions.markAllAsRead()
if (response.ok) {
- location.reload();
+ location.reload()
}
- };
+ }
public render() {
return (
@@ -82,6 +82,6 @@ export default class MyNotificationsPage extends React.Component
)}
- );
+ )
}
}
diff --git a/public/pages/MyNotifications/index.ts b/public/pages/MyNotifications/index.ts
index 9b3c5df4c..1c5b310c2 100644
--- a/public/pages/MyNotifications/index.ts
+++ b/public/pages/MyNotifications/index.ts
@@ -1 +1 @@
-export * from "./MyNotifications.page";
+export * from "./MyNotifications.page"
diff --git a/public/pages/MySettings/MySettings.page.tsx b/public/pages/MySettings/MySettings.page.tsx
index 73ff91d03..5367b08a2 100644
--- a/public/pages/MySettings/MySettings.page.tsx
+++ b/public/pages/MySettings/MySettings.page.tsx
@@ -1,34 +1,34 @@
-import "./MySettings.page.scss";
+import "./MySettings.page.scss"
-import React from "react";
+import React from "react"
-import { Modal, Form, Button, Heading, Input, Select, SelectOption, ImageUploader } from "@fider/components";
+import { Modal, Form, Button, Heading, Input, Select, SelectOption, ImageUploader } from "@fider/components"
-import { UserSettings, UserAvatarType, ImageUpload } from "@fider/models";
-import { Failure, actions, Fider } from "@fider/services";
-import { FaRegAddressCard } from "react-icons/fa";
-import { NotificationSettings } from "./components/NotificationSettings";
-import { APIKeyForm } from "./components/APIKeyForm";
-import { DangerZone } from "./components/DangerZone";
+import { UserSettings, UserAvatarType, ImageUpload } from "@fider/models"
+import { Failure, actions, Fider } from "@fider/services"
+import { FaRegAddressCard } from "react-icons/fa"
+import { NotificationSettings } from "./components/NotificationSettings"
+import { APIKeyForm } from "./components/APIKeyForm"
+import { DangerZone } from "./components/DangerZone"
interface MySettingsPageState {
- showModal: boolean;
- name: string;
- newEmail: string;
- avatar?: ImageUpload;
- avatarType: UserAvatarType;
- changingEmail: boolean;
- error?: Failure;
- userSettings: UserSettings;
+ showModal: boolean
+ name: string
+ newEmail: string
+ avatar?: ImageUpload
+ avatarType: UserAvatarType
+ changingEmail: boolean
+ error?: Failure
+ userSettings: UserSettings
}
interface MySettingsPageProps {
- userSettings: UserSettings;
+ userSettings: UserSettings
}
export default class MySettingsPage extends React.Component {
constructor(props: MySettingsPageProps) {
- super(props);
+ super(props)
this.state = {
showModal: false,
changingEmail: false,
@@ -36,7 +36,7 @@ export default class MySettingsPage extends React.Component {
@@ -45,71 +45,71 @@ export default class MySettingsPage extends React.Component {
- const result = await actions.changeUserEmail(this.state.newEmail);
+ const result = await actions.changeUserEmail(this.state.newEmail)
if (result.ok) {
this.setState({
error: undefined,
changingEmail: false,
showModal: true,
- });
+ })
} else if (result.error) {
- this.setState({ error: result.error });
+ this.setState({ error: result.error })
}
- };
+ }
private startChangeEmail = () => {
- this.setState({ changingEmail: true });
- };
+ this.setState({ changingEmail: true })
+ }
private cancelChangeEmail = async () => {
this.setState({
changingEmail: false,
newEmail: "",
error: undefined,
- });
- };
+ })
+ }
private avatarTypeChanged = (opt?: SelectOption) => {
if (opt) {
- this.setState({ avatarType: opt.value as UserAvatarType });
+ this.setState({ avatarType: opt.value as UserAvatarType })
}
- };
+ }
private setName = (name: string) => {
- this.setState({ name });
- };
+ this.setState({ name })
+ }
private setNotificationSettings = (userSettings: UserSettings) => {
- this.setState({ userSettings });
- };
+ this.setState({ userSettings })
+ }
private closeModal = () => {
- this.setState({ showModal: false });
- };
+ this.setState({ showModal: false })
+ }
private setNewEmail = (newEmail: string) => {
- this.setState({ newEmail });
- };
+ this.setState({ newEmail })
+ }
private setAvatar = (avatar: ImageUpload): void => {
- this.setState({ avatar });
- };
+ this.setState({ avatar })
+ }
public render() {
const changeEmail = (
change
- );
+ )
return (
@@ -143,7 +143,11 @@ export default class MySettingsPage extends React.Component
- {Fider.session.user.email || this.state.changingEmail ? "Your email is private and will never be publicly displayed." : "Your account doesn't have an email."}
+
+ {Fider.session.user.email || this.state.changingEmail
+ ? "Your email is private and will never be publicly displayed."
+ : "Your account doesn't have an email."}
+
{this.state.changingEmail && (
<>
@@ -172,16 +176,18 @@ export default class MySettingsPage extends React.Component
A{" "}
-
+
Gravatar
{" "}
- will be used based on your email. If you don't have a Gravatar, a letter avatar based on your initials is generated for you.
+ will be used based on your email. If you don't have a Gravatar, a letter avatar based on your initials is generated for you.
)}
{this.state.avatarType === UserAvatarType.Letter && A letter avatar based on your initials is generated for you.
}
{this.state.avatarType === UserAvatarType.Custom && (
- We accept JPG, GIF and PNG images, smaller than 100KB and with an aspect ratio of 1:1 with minimum dimensions of 50x50 pixels.
+
+ We accept JPG, GIF and PNG images, smaller than 100KB and with an aspect ratio of 1:1 with minimum dimensions of 50x50 pixels.
+
)}
@@ -209,6 +215,6 @@ export default class MySettingsPage extends React.Component
- );
+ )
}
}
diff --git a/public/pages/MySettings/components/APIKeyForm.tsx b/public/pages/MySettings/components/APIKeyForm.tsx
index 007263440..e05eed94c 100644
--- a/public/pages/MySettings/components/APIKeyForm.tsx
+++ b/public/pages/MySettings/components/APIKeyForm.tsx
@@ -1,23 +1,23 @@
-import React from "react";
-import { Button } from "@fider/components";
-import { actions } from "@fider/services";
+import React from "react"
+import { Button } from "@fider/components"
+import { actions } from "@fider/services"
interface APIKeyFormState {
- apiKey?: string;
+ apiKey?: string
}
-export class APIKeyForm extends React.Component<{}, APIKeyFormState> {
- constructor(props: {}) {
- super(props);
- this.state = {};
+export class APIKeyForm extends React.Component {
+ constructor(props: any) {
+ super(props)
+ this.state = {}
}
private regenerate = async () => {
- const result = await actions.regenerateAPIKey();
+ const result = await actions.regenerateAPIKey()
if (result.ok) {
- this.setState({ apiKey: result.data.apiKey });
+ this.setState({ apiKey: result.data.apiKey })
}
- };
+ }
private showAPIKey() {
return (
@@ -27,17 +27,19 @@ export class APIKeyForm extends React.Component<{}, APIKeyFormState> {
Stored it securely on your servers and never store it in the client side of your app.
>
- );
+ )
}
public render() {
return (
API Key
-
The API Key is only shown whenever generated. If your Key is lost or has been compromised, generated a new one and take note of it.
+
+ The API Key is only shown whenever generated. If your Key is lost or has been compromised, generated a new one and take note of it.
+
To learn how to use the API, read the{" "}
-
+
official documentation
.
@@ -49,6 +51,6 @@ export class APIKeyForm extends React.Component<{}, APIKeyFormState> {
{this.state.apiKey && this.showAPIKey()}
- );
+ )
}
}
diff --git a/public/pages/MySettings/components/DangerZone.tsx b/public/pages/MySettings/components/DangerZone.tsx
index ecf94a3a1..e4026308d 100644
--- a/public/pages/MySettings/components/DangerZone.tsx
+++ b/public/pages/MySettings/components/DangerZone.tsx
@@ -1,37 +1,37 @@
-import React from "react";
+import React from "react"
-import { Button, Modal, ButtonClickEvent } from "@fider/components";
-import { actions, notify, navigator } from "@fider/services";
+import { Button, Modal, ButtonClickEvent } from "@fider/components"
+import { actions, notify, navigator } from "@fider/services"
interface DangerZoneState {
- clicked: boolean;
+ clicked: boolean
}
-export class DangerZone extends React.Component<{}, DangerZoneState> {
- constructor(props: {}) {
- super(props);
+export class DangerZone extends React.Component {
+ constructor(props: any) {
+ super(props)
this.state = {
clicked: false,
- };
+ }
}
public onClickDelete = async () => {
- this.setState({ clicked: true });
- };
+ this.setState({ clicked: true })
+ }
public onCancel = async () => {
- this.setState({ clicked: false });
- };
+ this.setState({ clicked: false })
+ }
public onConfirm = async (e: ButtonClickEvent) => {
- const response = await actions.deleteCurrentAccount();
+ const response = await actions.deleteCurrentAccount()
if (response.ok) {
- e.preventEnable();
- navigator.goHome();
+ e.preventEnable()
+ navigator.goHome()
} else {
- notify.error("Failed to delete your account. Try again later");
+ notify.error("Failed to delete your account. Try again later")
}
- };
+ }
public render() {
return (
@@ -39,7 +39,10 @@ export class DangerZone extends React.Component<{}, DangerZoneState> {
Delete account
- When you choose to delete your account, we will erase all your personal information forever. The content you have published will remain, but it will be anonymised.
+
+ When you choose to delete your account, we will erase all your personal information forever. The content you have published will remain, but it
+ will be anonymised.
+
This process is irreversible. Are you sure?
@@ -55,12 +58,15 @@ export class DangerZone extends React.Component<{}, DangerZoneState> {
Delete account
- When you choose to delete your account, we will erase all your personal information forever. The content you have published will remain, but it will be anonymised.
+
+ When you choose to delete your account, we will erase all your personal information forever. The content you have published will remain, but it will
+ be anonymised.
+
This process is irreversible. Please be certain.
Delete My Account
- );
+ )
}
}
diff --git a/public/pages/MySettings/components/NotificationSettings.tsx b/public/pages/MySettings/components/NotificationSettings.tsx
index e362a5083..988d4b67a 100644
--- a/public/pages/MySettings/components/NotificationSettings.tsx
+++ b/public/pages/MySettings/components/NotificationSettings.tsx
@@ -1,82 +1,82 @@
-import React, { useState } from "react";
+import React, { useState } from "react"
-import { UserSettings } from "@fider/models";
-import { Toggle, Segment, Segments, Field } from "@fider/components";
-import { useFider } from "@fider/hooks";
+import { UserSettings } from "@fider/models"
+import { Toggle, Segment, Segments, Field } from "@fider/components"
+import { useFider } from "@fider/hooks"
interface NotificationSettingsProps {
- userSettings: UserSettings;
- settingsChanged: (settings: UserSettings) => void;
+ userSettings: UserSettings
+ settingsChanged: (settings: UserSettings) => void
}
-type Channel = number;
-const WebChannel: Channel = 1;
-const EmailChannel: Channel = 2;
+type Channel = number
+const WebChannel: Channel = 1
+const EmailChannel: Channel = 2
export const NotificationSettings = (props: NotificationSettingsProps) => {
- const fider = useFider();
- const [userSettings, setUserSettings] = useState(props.userSettings);
+ const fider = useFider()
+ const [userSettings, setUserSettings] = useState(props.userSettings)
const isEnabled = (settingsKey: string, channel: Channel): boolean => {
if (settingsKey in userSettings) {
- return (parseInt(userSettings[settingsKey], 10) & channel) > 0;
+ return (parseInt(userSettings[settingsKey], 10) & channel) > 0
}
- return false;
- };
+ return false
+ }
const toggle = async (settingsKey: string, channel: Channel) => {
const nextSettings = {
...userSettings,
[settingsKey]: (parseInt(userSettings[settingsKey], 10) ^ channel).toString(),
- };
- setUserSettings(nextSettings);
- props.settingsChanged(nextSettings);
- };
+ }
+ setUserSettings(nextSettings)
+ props.settingsChanged(nextSettings)
+ }
const icon = (settingsKey: string, channel: Channel) => {
- const active = isEnabled(settingsKey, channel);
- const label = channel === WebChannel ? "Web" : "Email";
- const onToggle = () => toggle(settingsKey, channel);
- return ;
- };
+ const active = isEnabled(settingsKey, channel)
+ const label = channel === WebChannel ? "Web" : "Email"
+ const onToggle = () => toggle(settingsKey, channel)
+ return
+ }
const info = (settingsKey: string, aboutForVisitors: string, aboutForCollaborators: string) => {
- const about = fider.session.user.isCollaborator ? aboutForCollaborators : aboutForVisitors;
- const webEnabled = isEnabled(settingsKey, WebChannel);
- const emailEnabled = isEnabled(settingsKey, EmailChannel);
+ const about = fider.session.user.isCollaborator ? aboutForCollaborators : aboutForVisitors
+ const webEnabled = isEnabled(settingsKey, WebChannel)
+ const emailEnabled = isEnabled(settingsKey, EmailChannel)
if (!webEnabled && !emailEnabled) {
return (
- You'll NOT receive any notification about this event.
+ You'll NOT receive any notification about this event.
- );
+ )
} else if (webEnabled && !emailEnabled) {
return (
- You'll receive web notifications about {about}.
+ You'll receive web notifications about {about}.
- );
+ )
} else if (!webEnabled && emailEnabled) {
return (
- You'll receive email notifications about {about}.
+ You'll receive email notifications about {about}.
- );
+ )
} else if (webEnabled && emailEnabled) {
return (
- You'll receive web and email notifications about {about}.
+ You'll receive web and email notifications about {about}.
- );
+ )
}
- return null;
- };
+ return null
+ }
return (
<>
- Use following panel to choose which events you'd like to receive notification
+ Use following panel to choose which events you'd like to receive notification
@@ -99,7 +99,11 @@ export const NotificationSettings = (props: NotificationSettingsProps) => {
Status Changed
- {info("event_notification_change_status", "status change on posts you've subscribed to", "status change on all posts unless individually unsubscribed")}
+ {info(
+ "event_notification_change_status",
+ "status change on posts you've subscribed to",
+ "status change on all posts unless individually unsubscribed"
+ )}
{icon("event_notification_change_status", WebChannel)}
{icon("event_notification_change_status", EmailChannel)}
@@ -108,5 +112,5 @@ export const NotificationSettings = (props: NotificationSettingsProps) => {
>
- );
-};
+ )
+}
diff --git a/public/pages/MySettings/index.ts b/public/pages/MySettings/index.ts
index 1a0e7a5bb..1d42aba77 100644
--- a/public/pages/MySettings/index.ts
+++ b/public/pages/MySettings/index.ts
@@ -1 +1 @@
-export * from "./MySettings.page";
+export * from "./MySettings.page"
diff --git a/public/pages/OAuthEcho/OAuthEcho.page.tsx b/public/pages/OAuthEcho/OAuthEcho.page.tsx
index 30f7b36b6..b8fef6a50 100644
--- a/public/pages/OAuthEcho/OAuthEcho.page.tsx
+++ b/public/pages/OAuthEcho/OAuthEcho.page.tsx
@@ -1,27 +1,27 @@
-import "./OAuthEcho.page.scss";
+import "./OAuthEcho.page.scss"
-import React from "react";
-import { navigator } from "@fider/services";
-import { Segments, Segment } from "@fider/components";
-import { FaCheckCircle, FaTimesCircle, FaExclamationTriangle } from "react-icons/fa";
+import React from "react"
+import { navigator } from "@fider/services"
+import { Segments, Segment } from "@fider/components"
+import { FaCheckCircle, FaTimesCircle, FaExclamationTriangle } from "react-icons/fa"
interface OAuthEchoPageProps {
- err: string | undefined;
- body: string;
+ err: string | undefined
+ body: string
profile: {
- id: string;
- name: string;
- email: string;
- };
+ id: string
+ name: string
+ email: string
+ }
}
-const ok = ;
-const error = ;
-const warn = ;
+const ok =
+const error =
+const warn =
-export default class OAuthEchoPage extends React.Component {
+export default class OAuthEchoPage extends React.Component {
public componentDidMount() {
- navigator.replaceState("/");
+ navigator.replaceState("/")
}
private renderError() {
@@ -30,19 +30,19 @@ export default class OAuthEchoPage extends React.ComponentError
{this.props.err}
>
- );
+ )
}
private renderParseResult() {
- const idOk = this.props.profile && this.props.profile.id !== "";
- const nameOk = this.props.profile && this.props.profile.name !== "Anonymous";
- const emailOk = this.props.profile && this.props.profile.email !== "";
+ const idOk = this.props.profile && this.props.profile.id !== ""
+ const nameOk = this.props.profile && this.props.profile.name !== "Anonymous"
+ const emailOk = this.props.profile && this.props.profile.email !== ""
- let responseBody = "";
+ let responseBody = ""
try {
- responseBody = JSON.stringify(JSON.parse(this.props.body), null, " ");
+ responseBody = JSON.stringify(JSON.parse(this.props.body), null, " ")
} catch {
- responseBody = this.props.body;
+ responseBody = this.props.body
}
return (
@@ -64,7 +64,7 @@ export default class OAuthEchoPage extends React.ComponentName: {this.props.profile && this.props.profile.name}
{!nameOk && (
- Name is required, if not found we'll use Anonymous as the name of every new user.
+ Name is required, if not found we'll use Anonymous as the name of every new user.
)}
@@ -73,12 +73,16 @@ export default class OAuthEchoPage extends React.Component
{emailOk ? ok : warn}
Email: {this.props.profile && this.props.profile.email}
- {!emailOk && Email is not required, but highly recommended. If invalid or not found, new users won't be able to receive notifications.
}
+ {!emailOk && (
+
+ Email is not required, but highly recommended. If invalid or not found, new users won't be able to receive notifications.
+
+ )}
>
- );
+ )
}
public render() {
@@ -86,6 +90,6 @@ export default class OAuthEchoPage extends React.Component
{this.props.err ? this.renderError() : this.renderParseResult()}
- );
+ )
}
}
diff --git a/public/pages/OAuthEcho/index.ts b/public/pages/OAuthEcho/index.ts
index 0bd990b2d..f7293623c 100644
--- a/public/pages/OAuthEcho/index.ts
+++ b/public/pages/OAuthEcho/index.ts
@@ -1 +1 @@
-export * from "./OAuthEcho.page";
+export * from "./OAuthEcho.page"
diff --git a/public/pages/ShowPost/ShowPost.page.tsx b/public/pages/ShowPost/ShowPost.page.tsx
index 80889860f..5800216e0 100644
--- a/public/pages/ShowPost/ShowPost.page.tsx
+++ b/public/pages/ShowPost/ShowPost.page.tsx
@@ -1,78 +1,93 @@
-import "./ShowPost.page.scss";
-
-import React from "react";
-
-import { Comment, Post, Tag, Vote, ImageUpload } from "@fider/models";
-import { actions, Failure, Fider } from "@fider/services";
-
-import { VoteCounter, ShowPostResponse, Button, UserName, Avatar, Moment, MultiLineText, List, ListItem, Input, Form, TextArea, MultiImageUploader, ImageViewer } from "@fider/components";
-import { FaSave, FaTimes, FaEdit } from "react-icons/fa";
-import { ResponseForm } from "./components/ResponseForm";
-import { TagsPanel } from "./components/TagsPanel";
-import { NotificationsPanel } from "./components/NotificationsPanel";
-import { ModerationPanel } from "./components/ModerationPanel";
-import { DiscussionPanel } from "./components/DiscussionPanel";
-import { VotesPanel } from "./components/VotesPanel";
+import "./ShowPost.page.scss"
+
+import React from "react"
+
+import { Comment, Post, Tag, Vote, ImageUpload } from "@fider/models"
+import { actions, Failure, Fider } from "@fider/services"
+
+import {
+ VoteCounter,
+ ShowPostResponse,
+ Button,
+ UserName,
+ Avatar,
+ Moment,
+ MultiLineText,
+ List,
+ ListItem,
+ Input,
+ Form,
+ TextArea,
+ MultiImageUploader,
+ ImageViewer,
+} from "@fider/components"
+import { FaSave, FaTimes, FaEdit } from "react-icons/fa"
+import { ResponseForm } from "./components/ResponseForm"
+import { TagsPanel } from "./components/TagsPanel"
+import { NotificationsPanel } from "./components/NotificationsPanel"
+import { ModerationPanel } from "./components/ModerationPanel"
+import { DiscussionPanel } from "./components/DiscussionPanel"
+import { VotesPanel } from "./components/VotesPanel"
interface ShowPostPageProps {
- post: Post;
- subscribed: boolean;
- comments: Comment[];
- tags: Tag[];
- votes: Vote[];
- attachments: string[];
+ post: Post
+ subscribed: boolean
+ comments: Comment[]
+ tags: Tag[]
+ votes: Vote[]
+ attachments: string[]
}
interface ShowPostPageState {
- editMode: boolean;
- newTitle: string;
- attachments: ImageUpload[];
- newDescription: string;
- error?: Failure;
+ editMode: boolean
+ newTitle: string
+ attachments: ImageUpload[]
+ newDescription: string
+ error?: Failure
}
export default class ShowPostPage extends React.Component {
constructor(props: ShowPostPageProps) {
- super(props);
+ super(props)
this.state = {
editMode: false,
newTitle: this.props.post.title,
newDescription: this.props.post.description,
attachments: [],
- };
+ }
}
private saveChanges = async () => {
- const result = await actions.updatePost(this.props.post.number, this.state.newTitle, this.state.newDescription, this.state.attachments);
+ const result = await actions.updatePost(this.props.post.number, this.state.newTitle, this.state.newDescription, this.state.attachments)
if (result.ok) {
- location.reload();
+ location.reload()
} else {
this.setState({
error: result.error,
- });
+ })
}
- };
+ }
private setNewTitle = (newTitle: string) => {
- this.setState({ newTitle });
- };
+ this.setState({ newTitle })
+ }
private setNewDescription = (newDescription: string) => {
- this.setState({ newDescription });
- };
+ this.setState({ newDescription })
+ }
private setAttachments = (attachments: ImageUpload[]) => {
- this.setState({ attachments });
- };
+ this.setState({ attachments })
+ }
private cancelEdit = async () => {
- this.setState({ error: undefined, editMode: false });
- };
+ this.setState({ error: undefined, editMode: false })
+ }
private startEdit = async () => {
- this.setState({ editMode: true });
- };
+ this.setState({ editMode: true })
+ }
public render() {
return (
@@ -157,6 +172,6 @@ export default class ShowPostPage extends React.Component
- );
+ )
}
}
diff --git a/public/pages/ShowPost/components/CommentInput.tsx b/public/pages/ShowPost/components/CommentInput.tsx
index 17e8c5699..97cd882ec 100644
--- a/public/pages/ShowPost/components/CommentInput.tsx
+++ b/public/pages/ShowPost/components/CommentInput.tsx
@@ -1,54 +1,54 @@
-import React, { useState, useRef } from "react";
+import React, { useState, useRef } from "react"
-import { Post, ImageUpload } from "@fider/models";
-import { Avatar, UserName, Button, TextArea, Form, MultiImageUploader } from "@fider/components/common";
-import { SignInModal } from "@fider/components";
+import { Post, ImageUpload } from "@fider/models"
+import { Avatar, UserName, Button, TextArea, Form, MultiImageUploader } from "@fider/components/common"
+import { SignInModal } from "@fider/components"
-import { cache, actions, Failure, Fider } from "@fider/services";
-import { useFider } from "@fider/hooks";
+import { cache, actions, Failure, Fider } from "@fider/services"
+import { useFider } from "@fider/hooks"
interface CommentInputProps {
- post: Post;
+ post: Post
}
-const CACHE_TITLE_KEY = "CommentInput-Comment-";
+const CACHE_TITLE_KEY = "CommentInput-Comment-"
export const CommentInput = (props: CommentInputProps) => {
- const getCacheKey = () => `${CACHE_TITLE_KEY}${props.post.id}`;
+ const getCacheKey = () => `${CACHE_TITLE_KEY}${props.post.id}`
- const fider = useFider();
- const inputRef = useRef();
- const [content, setContent] = useState((fider.session.isAuthenticated && cache.session.get(getCacheKey())) || "");
- const [isSignInModalOpen, setIsSignInModalOpen] = useState(false);
- const [attachments, setAttachments] = useState([]);
- const [error, setError] = useState(undefined);
+ const fider = useFider()
+ const inputRef = useRef()
+ const [content, setContent] = useState((fider.session.isAuthenticated && cache.session.get(getCacheKey())) || "")
+ const [isSignInModalOpen, setIsSignInModalOpen] = useState(false)
+ const [attachments, setAttachments] = useState([])
+ const [error, setError] = useState(undefined)
const commentChanged = (newContent: string) => {
- cache.session.set(getCacheKey(), newContent);
- setContent(newContent);
- };
+ cache.session.set(getCacheKey(), newContent)
+ setContent(newContent)
+ }
- const hideModal = () => setIsSignInModalOpen(false);
- const clearError = () => setError(undefined);
+ const hideModal = () => setIsSignInModalOpen(false)
+ const clearError = () => setError(undefined)
const submit = async () => {
- clearError();
+ clearError()
- const result = await actions.createComment(props.post.number, content, attachments);
+ const result = await actions.createComment(props.post.number, content, attachments)
if (result.ok) {
- cache.session.remove(getCacheKey());
- location.reload();
+ cache.session.remove(getCacheKey())
+ location.reload()
} else {
- setError(result.error);
+ setError(result.error)
}
- };
+ }
const handleOnFocus = () => {
if (!fider.session.isAuthenticated && inputRef.current) {
- inputRef.current.blur();
- setIsSignInModalOpen(true);
+ inputRef.current.blur()
+ setIsSignInModalOpen(true)
}
- };
+ }
return (
<>
@@ -57,7 +57,15 @@ export const CommentInput = (props: CommentInputProps) => {
{Fider.session.isAuthenticated && }
{Fider.session.isAuthenticated && }
-
+
{content && (
<>
@@ -69,5 +77,5 @@ export const CommentInput = (props: CommentInputProps) => {
>
- );
-};
+ )
+}
diff --git a/public/pages/ShowPost/components/DiscussionPanel.tsx b/public/pages/ShowPost/components/DiscussionPanel.tsx
index 7e6f4d22c..0f56a1fe0 100644
--- a/public/pages/ShowPost/components/DiscussionPanel.tsx
+++ b/public/pages/ShowPost/components/DiscussionPanel.tsx
@@ -1,14 +1,14 @@
-import "./Comments.scss";
+import "./Comments.scss"
-import React from "react";
-import { CurrentUser, Comment, Post } from "@fider/models";
-import { ShowComment } from "./ShowComment";
-import { CommentInput } from "./CommentInput";
+import React from "react"
+import { CurrentUser, Comment, Post } from "@fider/models"
+import { ShowComment } from "./ShowComment"
+import { CommentInput } from "./CommentInput"
interface DiscussionPanelProps {
- user?: CurrentUser;
- post: Post;
- comments: Comment[];
+ user?: CurrentUser
+ post: Post
+ comments: Comment[]
}
export const DiscussionPanel = (props: DiscussionPanelProps) => {
@@ -22,5 +22,5 @@ export const DiscussionPanel = (props: DiscussionPanelProps) => {
- );
-};
+ )
+}
diff --git a/public/pages/ShowPost/components/ModerationPanel.tsx b/public/pages/ShowPost/components/ModerationPanel.tsx
index 1bd8bf601..15def63b0 100644
--- a/public/pages/ShowPost/components/ModerationPanel.tsx
+++ b/public/pages/ShowPost/components/ModerationPanel.tsx
@@ -1,35 +1,35 @@
-import React, { useState } from "react";
-import { PostStatus, Post } from "@fider/models";
-import { actions, navigator, Failure } from "@fider/services";
-import { Form, Modal, Button, List, ListItem, TextArea } from "@fider/components";
-import { useFider } from "@fider/hooks";
+import React, { useState } from "react"
+import { PostStatus, Post } from "@fider/models"
+import { actions, navigator, Failure } from "@fider/services"
+import { Form, Modal, Button, List, ListItem, TextArea } from "@fider/components"
+import { useFider } from "@fider/hooks"
interface ModerationPanelProps {
- post: Post;
+ post: Post
}
export const ModerationPanel = (props: ModerationPanelProps) => {
- const fider = useFider();
- const [showConfirmation, setShowConfirmation] = useState(false);
- const [text, setText] = useState("");
- const [error, setError] = useState();
+ const fider = useFider()
+ const [showConfirmation, setShowConfirmation] = useState(false)
+ const [text, setText] = useState("")
+ const [error, setError] = useState()
- const hideModal = async () => setShowConfirmation(false);
- const showModal = async () => setShowConfirmation(true);
+ const hideModal = async () => setShowConfirmation(false)
+ const showModal = async () => setShowConfirmation(true)
const handleDelete = async () => {
- const response = await actions.deletePost(props.post.number, text);
+ const response = await actions.deletePost(props.post.number, text)
if (response.ok) {
- hideModal();
- navigator.goHome();
+ hideModal()
+ navigator.goHome()
} else if (response.error) {
- setError(response.error);
+ setError(response.error)
}
- };
+ }
- const status = PostStatus.Get(props.post.status);
+ const status = PostStatus.Get(props.post.status)
if (!fider.session.isAuthenticated || !fider.session.user.isAdministrator || status.closed) {
- return null;
+ return null
}
const modal = (
@@ -53,7 +53,7 @@ export const ModerationPanel = (props: ModerationPanelProps) => {
- );
+ )
return (
<>
@@ -67,5 +67,5 @@ export const ModerationPanel = (props: ModerationPanelProps) => {
>
- );
-};
+ )
+}
diff --git a/public/pages/ShowPost/components/NotificationsPanel.tsx b/public/pages/ShowPost/components/NotificationsPanel.tsx
index 241d1c375..ba8203ddb 100644
--- a/public/pages/ShowPost/components/NotificationsPanel.tsx
+++ b/public/pages/ShowPost/components/NotificationsPanel.tsx
@@ -1,30 +1,30 @@
-import React, { useState } from "react";
-import { Post } from "@fider/models";
-import { Button, List, ListItem } from "@fider/components";
-import { actions } from "@fider/services";
-import { FaVolumeUp, FaVolumeMute } from "react-icons/fa";
-import { useFider } from "@fider/hooks";
+import React, { useState } from "react"
+import { Post } from "@fider/models"
+import { Button, List, ListItem } from "@fider/components"
+import { actions } from "@fider/services"
+import { FaVolumeUp, FaVolumeMute } from "react-icons/fa"
+import { useFider } from "@fider/hooks"
interface NotificationsPanelProps {
- post: Post;
- subscribed: boolean;
+ post: Post
+ subscribed: boolean
}
export const NotificationsPanel = (props: NotificationsPanelProps) => {
- const fider = useFider();
- const [subscribed, setSubscribed] = useState(props.subscribed);
+ const fider = useFider()
+ const [subscribed, setSubscribed] = useState(props.subscribed)
const subscribeOrUnsubscribe = async () => {
- const action = subscribed ? actions.unsubscribe : actions.subscribe;
+ const action = subscribed ? actions.unsubscribe : actions.subscribe
- const response = await action(props.post.number);
+ const response = await action(props.post.number)
if (response.ok) {
- setSubscribed(!subscribed);
+ setSubscribed(!subscribed)
}
- };
+ }
if (!fider.session.isAuthenticated) {
- return null;
+ return null
}
const button = subscribed ? (
@@ -35,13 +35,13 @@ export const NotificationsPanel = (props: NotificationsPanelProps) => {
Subscribe
- );
+ )
const text = subscribed ? (
You’re receiving notifications about activity on this post.
) : (
- You'll not receive any notification about this post.
- );
+ You'll not receive any notification about this post.
+ )
return (
<>
@@ -53,5 +53,5 @@ export const NotificationsPanel = (props: NotificationsPanelProps) => {
>
- );
-};
+ )
+}
diff --git a/public/pages/ShowPost/components/PostSearch.tsx b/public/pages/ShowPost/components/PostSearch.tsx
index 7976fe30b..7c0a4255e 100644
--- a/public/pages/ShowPost/components/PostSearch.tsx
+++ b/public/pages/ShowPost/components/PostSearch.tsx
@@ -1,55 +1,58 @@
-import React from "react";
-import { Post, PostStatus } from "@fider/models";
-import { actions } from "@fider/services";
-import { DropDown, DropDownItem } from "@fider/components";
-import { FaCaretUp } from "react-icons/fa";
+import React from "react"
+import { Post, PostStatus } from "@fider/models"
+import { actions } from "@fider/services"
+import { DropDown, DropDownItem } from "@fider/components"
+import { FaCaretUp } from "react-icons/fa"
interface PostSearchProps {
- exclude?: number[];
- onChanged(postNumber: number): void;
+ exclude?: number[]
+ onChanged(postNumber: number): void
}
interface PostSearchState {
- posts: Post[];
+ posts: Post[]
}
export class PostSearch extends React.Component {
- private timer?: number;
+ private timer?: number
constructor(props: PostSearchProps) {
- super(props);
+ super(props)
this.state = {
posts: [],
- };
+ }
}
public componentDidMount() {
- this.search("");
+ this.search("")
}
private onSearchChange = (e: React.SyntheticEvent) => {
- this.search(e.currentTarget.value);
- };
+ this.search(e.currentTarget.value)
+ }
private onChange = (item: DropDownItem) => {
- this.props.onChanged(item.value as number);
- };
+ this.props.onChanged(item.value as number)
+ }
private search = (searchQuery: string) => {
- window.clearTimeout(this.timer);
+ window.clearTimeout(this.timer)
this.timer = window.setTimeout(() => {
actions.searchPosts({ query: searchQuery }).then((res) => {
if (res.ok) {
- const posts = this.props.exclude && this.props.exclude.length > 0 ? res.data.filter((i) => this.props.exclude!.indexOf(i.number) === -1) : res.data;
- this.setState({ posts });
+ const posts =
+ this.props.exclude && this.props.exclude.length > 0
+ ? res.data.filter((i) => this.props.exclude && this.props.exclude.indexOf(i.number) === -1)
+ : res.data
+ this.setState({ posts })
}
- });
- }, 500);
- };
+ })
+ }, 500)
+ }
public render() {
const items = this.state.posts.map((p) => {
- const status = PostStatus.Get(p.status);
+ const status = PostStatus.Get(p.status)
return {
label: p.title,
value: p.number,
@@ -63,9 +66,18 @@ export class PostSearch extends React.Component
),
- };
- });
+ }
+ })
- return ;
+ return (
+
+ )
}
}
diff --git a/public/pages/ShowPost/components/ResponseForm.tsx b/public/pages/ShowPost/components/ResponseForm.tsx
index a4f9bfbff..3c0e53cbd 100644
--- a/public/pages/ShowPost/components/ResponseForm.tsx
+++ b/public/pages/ShowPost/components/ResponseForm.tsx
@@ -1,80 +1,80 @@
-import React from "react";
+import React from "react"
-import { Modal, Button, DisplayError, Select, Form, TextArea, Field, SelectOption } from "@fider/components";
-import { Post, PostStatus } from "@fider/models";
+import { Modal, Button, DisplayError, Select, Form, TextArea, Field, SelectOption } from "@fider/components"
+import { Post, PostStatus } from "@fider/models"
-import { actions, Failure } from "@fider/services";
-import { FaBullhorn } from "react-icons/fa";
-import { PostSearch } from "./PostSearch";
+import { actions, Failure } from "@fider/services"
+import { FaBullhorn } from "react-icons/fa"
+import { PostSearch } from "./PostSearch"
interface ResponseFormProps {
- post: Post;
+ post: Post
}
interface ResponseFormState {
- showModal: boolean;
- status: string;
- text: string;
- originalNumber: number;
- error?: Failure;
+ showModal: boolean
+ status: string
+ text: string
+ originalNumber: number
+ error?: Failure
}
export class ResponseForm extends React.Component {
constructor(props: ResponseFormProps) {
- super(props);
+ super(props)
this.state = {
showModal: false,
status: this.props.post.status,
originalNumber: 0,
text: this.props.post.response ? this.props.post.response.text : "",
- };
+ }
}
private submit = async () => {
- const result = await actions.respond(this.props.post.number, this.state);
+ const result = await actions.respond(this.props.post.number, this.state)
if (result.ok) {
- location.reload();
+ location.reload()
} else {
this.setState({
error: result.error,
- });
+ })
}
- };
+ }
private showModal = async () => {
- this.setState({ showModal: true });
- };
+ this.setState({ showModal: true })
+ }
private closeModal = async () => {
- this.setState({ showModal: false });
- };
+ this.setState({ showModal: false })
+ }
private setStatus = (opt?: SelectOption) => {
if (opt) {
- this.setState({ status: opt.value });
+ this.setState({ status: opt.value })
}
- };
+ }
private setOriginalNumber = (originalNumber: number) => {
- this.setState({ originalNumber });
- };
+ this.setState({ originalNumber })
+ }
private setText = (text: string) => {
- this.setState({ text });
- };
+ this.setState({ text })
+ }
public render() {
const button = (
Respond
- );
+ )
const options = PostStatus.All.map((s) => ({
value: s.value.toString(),
label: s.title,
- }));
+ }))
const modal = (
@@ -90,7 +90,13 @@ export class ResponseForm extends React.ComponentVotes from this post will be merged into original post.
>
) : (
-
+
)}
@@ -104,13 +110,13 @@ export class ResponseForm extends React.Component
- );
+ )
return (
<>
{button}
{modal}
>
- );
+ )
}
}
diff --git a/public/pages/ShowPost/components/ShowComment.tsx b/public/pages/ShowPost/components/ShowComment.tsx
index 5cdbc06b7..74a1a0696 100644
--- a/public/pages/ShowPost/components/ShowComment.tsx
+++ b/public/pages/ShowPost/components/ShowComment.tsx
@@ -1,71 +1,84 @@
-import React, { useState } from "react";
-import { Comment, Post, ImageUpload } from "@fider/models";
-import { Avatar, UserName, Moment, Form, TextArea, Button, MultiLineText, DropDown, DropDownItem, Modal, ImageViewer, MultiImageUploader } from "@fider/components";
-import { formatDate, Failure, actions } from "@fider/services";
-import { FaEllipsisH } from "react-icons/fa";
-import { useFider } from "@fider/hooks";
+import React, { useState } from "react"
+import { Comment, Post, ImageUpload } from "@fider/models"
+import {
+ Avatar,
+ UserName,
+ Moment,
+ Form,
+ TextArea,
+ Button,
+ MultiLineText,
+ DropDown,
+ DropDownItem,
+ Modal,
+ ImageViewer,
+ MultiImageUploader,
+} from "@fider/components"
+import { formatDate, Failure, actions } from "@fider/services"
+import { FaEllipsisH } from "react-icons/fa"
+import { useFider } from "@fider/hooks"
interface ShowCommentProps {
- post: Post;
- comment: Comment;
+ post: Post
+ comment: Comment
}
export const ShowComment = (props: ShowCommentProps) => {
- const fider = useFider();
- const [isEditing, setIsEditing] = useState(false);
- const [newContent, setNewContent] = useState("");
- const [isDeleteConfirmationModalOpen, setIsDeleteConfirmationModalOpen] = useState(false);
- const [attachments, setAttachments] = useState([]);
- const [error, setError] = useState();
+ const fider = useFider()
+ const [isEditing, setIsEditing] = useState(false)
+ const [newContent, setNewContent] = useState("")
+ const [isDeleteConfirmationModalOpen, setIsDeleteConfirmationModalOpen] = useState(false)
+ const [attachments, setAttachments] = useState([])
+ const [error, setError] = useState()
const canEditComment = (): boolean => {
if (fider.session.isAuthenticated) {
- return fider.session.user.isCollaborator || props.comment.user.id === fider.session.user.id;
+ return fider.session.user.isCollaborator || props.comment.user.id === fider.session.user.id
}
- return false;
- };
+ return false
+ }
- const clearError = () => setError(undefined);
+ const clearError = () => setError(undefined)
const cancelEdit = async () => {
- setIsEditing(false);
- setNewContent("");
- clearError();
- };
+ setIsEditing(false)
+ setNewContent("")
+ clearError()
+ }
const saveEdit = async () => {
- const response = await actions.updateComment(props.post.number, props.comment.id, newContent, attachments);
+ const response = await actions.updateComment(props.post.number, props.comment.id, newContent, attachments)
if (response.ok) {
- location.reload();
+ location.reload()
} else {
- setError(response.error);
+ setError(response.error)
}
- };
+ }
const renderEllipsis = () => {
- return ;
- };
+ return
+ }
const closeModal = async () => {
- setIsDeleteConfirmationModalOpen(false);
- };
+ setIsDeleteConfirmationModalOpen(false)
+ }
const deleteComment = async () => {
- const response = await actions.deleteComment(props.post.number, props.comment.id);
+ const response = await actions.deleteComment(props.post.number, props.comment.id)
if (response.ok) {
- location.reload();
+ location.reload()
}
- };
+ }
const onActionSelected = (item: DropDownItem) => {
if (item.value === "edit") {
- setIsEditing(true);
- setNewContent(props.comment.content);
- clearError();
+ setIsEditing(true)
+ setNewContent(props.comment.content)
+ clearError()
} else if (item.value === "delete") {
- setIsDeleteConfirmationModalOpen(true);
+ setIsDeleteConfirmationModalOpen(true)
}
- };
+ }
const modal = () => {
return (
@@ -86,16 +99,16 @@ export const ShowComment = (props: ShowCommentProps) => {
- );
- };
+ )
+ }
- const comment = props.comment;
+ const comment = props.comment
const editedMetadata = !!comment.editedAt && !!comment.editedBy && (
- · edited
+ · edited
- );
+ )
return (
@@ -143,5 +156,5 @@ export const ShowComment = (props: ShowCommentProps) => {
- );
-};
+ )
+}
diff --git a/public/pages/ShowPost/components/TagListItem.tsx b/public/pages/ShowPost/components/TagListItem.tsx
index 4d246f7a8..ecfb978e9 100644
--- a/public/pages/ShowPost/components/TagListItem.tsx
+++ b/public/pages/ShowPost/components/TagListItem.tsx
@@ -1,18 +1,18 @@
-import React from "react";
-import { Tag } from "@fider/models";
-import { ListItem, ShowTag } from "@fider/components";
-import { FaCheck } from "react-icons/fa";
+import React from "react"
+import { Tag } from "@fider/models"
+import { ListItem, ShowTag } from "@fider/components"
+import { FaCheck } from "react-icons/fa"
interface TagListItemProps {
- tag: Tag;
- assigned: boolean;
- onClick: (tag: Tag) => void;
+ tag: Tag
+ assigned: boolean
+ onClick: (tag: Tag) => void
}
export const TagListItem = (props: TagListItemProps) => {
const onClick = () => {
- props.onClick(props.tag);
- };
+ props.onClick(props.tag)
+ }
return (
@@ -20,5 +20,5 @@ export const TagListItem = (props: TagListItemProps) => {
{props.tag.name}
- );
-};
+ )
+}
diff --git a/public/pages/ShowPost/components/TagsPanel.tsx b/public/pages/ShowPost/components/TagsPanel.tsx
index 159cf3e06..00e6cdb49 100644
--- a/public/pages/ShowPost/components/TagsPanel.tsx
+++ b/public/pages/ShowPost/components/TagsPanel.tsx
@@ -1,51 +1,51 @@
-import React, { useState } from "react";
-import { Tag, Post } from "@fider/models";
-import { actions } from "@fider/services";
-import { ShowTag, List, ListItem } from "@fider/components";
-import { TagListItem } from "./TagListItem";
-import { FaCheckCircle, FaCog } from "react-icons/fa";
-import { useFider } from "@fider/hooks";
+import React, { useState } from "react"
+import { Tag, Post } from "@fider/models"
+import { actions } from "@fider/services"
+import { ShowTag, List, ListItem } from "@fider/components"
+import { TagListItem } from "./TagListItem"
+import { FaCheckCircle, FaCog } from "react-icons/fa"
+import { useFider } from "@fider/hooks"
interface TagsPanelProps {
- post: Post;
- tags: Tag[];
+ post: Post
+ tags: Tag[]
}
export const TagsPanel = (props: TagsPanelProps) => {
- const fider = useFider();
- const canEdit = fider.session.isAuthenticated && fider.session.user.isCollaborator && props.tags.length > 0;
+ const fider = useFider()
+ const canEdit = fider.session.isAuthenticated && fider.session.user.isCollaborator && props.tags.length > 0
- const [isEditing, setIsEditing] = useState(false);
- const [assignedTags, setAssignedTags] = useState(props.tags.filter((t) => props.post.tags.indexOf(t.slug) >= 0));
+ const [isEditing, setIsEditing] = useState(false)
+ const [assignedTags, setAssignedTags] = useState(props.tags.filter((t) => props.post.tags.indexOf(t.slug) >= 0))
const assignOrUnassignTag = async (tag: Tag) => {
- const idx = assignedTags.indexOf(tag);
- let nextAssignedTags: Tag[] = [];
+ const idx = assignedTags.indexOf(tag)
+ let nextAssignedTags: Tag[] = []
if (idx >= 0) {
- const response = await actions.unassignTag(tag.slug, props.post.number);
+ const response = await actions.unassignTag(tag.slug, props.post.number)
if (response.ok) {
- nextAssignedTags = [...assignedTags];
- nextAssignedTags.splice(idx, 1);
+ nextAssignedTags = [...assignedTags]
+ nextAssignedTags.splice(idx, 1)
}
} else {
- const response = await actions.assignTag(tag.slug, props.post.number);
+ const response = await actions.assignTag(tag.slug, props.post.number)
if (response.ok) {
- nextAssignedTags = [...assignedTags, tag];
+ nextAssignedTags = [...assignedTags, tag]
}
}
- setAssignedTags(nextAssignedTags);
- };
+ setAssignedTags(nextAssignedTags)
+ }
const onSubtitleClick = () => {
if (canEdit) {
- setIsEditing(!isEditing);
+ setIsEditing(!isEditing)
}
- };
+ }
if (!canEdit && assignedTags.length === 0) {
- return null;
+ return null
}
const tagsList =
@@ -59,7 +59,7 @@ export const TagsPanel = (props: TagsPanelProps) => {
) : (
None yet
- );
+ )
const editTagsList = props.tags.length > 0 && (
@@ -67,10 +67,10 @@ export const TagsPanel = (props: TagsPanelProps) => {
= 0} onClick={assignOrUnassignTag} />
))}
- );
+ )
- const subtitleClasses = `subtitle ${canEdit && "active"}`;
- const icon = canEdit && (isEditing ? : );
+ const subtitleClasses = `subtitle ${canEdit && "active"}`
+ const icon = canEdit && (isEditing ? : )
return (
<>
@@ -81,5 +81,5 @@ export const TagsPanel = (props: TagsPanelProps) => {
{!isEditing && tagsList}
{isEditing && editTagsList}
>
- );
-};
+ )
+}
diff --git a/public/pages/ShowPost/components/VotesModal.tsx b/public/pages/ShowPost/components/VotesModal.tsx
index 634e64a05..ef1730374 100644
--- a/public/pages/ShowPost/components/VotesModal.tsx
+++ b/public/pages/ShowPost/components/VotesModal.tsx
@@ -1,35 +1,35 @@
-import "./VotesModal.scss";
+import "./VotesModal.scss"
-import React from "react";
-import { Post, Vote } from "@fider/models";
-import { Modal, Button, Loader, List, ListItem, Avatar, UserName, Moment, Input } from "@fider/components";
-import { actions } from "@fider/services";
-import { FaTimes, FaSearch } from "react-icons/fa";
+import React from "react"
+import { Post, Vote } from "@fider/models"
+import { Modal, Button, Loader, List, ListItem, Avatar, UserName, Moment, Input } from "@fider/components"
+import { actions } from "@fider/services"
+import { FaTimes, FaSearch } from "react-icons/fa"
interface VotesModalProps {
- isOpen: boolean;
- post: Post;
- onClose?: () => void;
+ isOpen: boolean
+ post: Post
+ onClose?: () => void
}
interface VotesModalState {
- searchText: string;
- allVotes: Vote[];
- filteredVotes: Vote[];
- isLoading: boolean;
- query: string;
+ searchText: string
+ allVotes: Vote[]
+ filteredVotes: Vote[]
+ isLoading: boolean
+ query: string
}
export class VotesModal extends React.Component {
constructor(props: VotesModalProps) {
- super(props);
+ super(props)
this.state = {
searchText: "",
query: "",
allVotes: [],
filteredVotes: [],
isLoading: true,
- };
+ }
}
public componentDidUpdate(prevProps: VotesModalProps) {
@@ -40,26 +40,26 @@ export class VotesModal extends React.Component {
if (this.props.onClose) {
- this.props.onClose();
+ this.props.onClose()
}
- };
+ }
private clearSearch = () => {
- this.handleSearchFilterChanged("");
- };
+ this.handleSearchFilterChanged("")
+ }
private handleSearchFilterChanged = (query: string) => {
- const votes = this.state.allVotes.filter((x) => x.user.name.toLowerCase().indexOf(query.toLowerCase()) >= 0);
- this.setState({ query, filteredVotes: votes });
- };
+ const votes = this.state.allVotes.filter((x) => x.user.name.toLowerCase().indexOf(query.toLowerCase()) >= 0)
+ this.setState({ query, filteredVotes: votes })
+ }
public render() {
return (
@@ -100,6 +100,6 @@ export class VotesModal extends React.Component
- );
+ )
}
}
diff --git a/public/pages/ShowPost/components/VotesPanel.tsx b/public/pages/ShowPost/components/VotesPanel.tsx
index bc2acf801..826c5e958 100644
--- a/public/pages/ShowPost/components/VotesPanel.tsx
+++ b/public/pages/ShowPost/components/VotesPanel.tsx
@@ -1,35 +1,35 @@
-import "./VotesPanel.scss";
+import "./VotesPanel.scss"
-import React, { useState } from "react";
-import { Post, Vote } from "@fider/models";
-import { Avatar } from "@fider/components";
-import { Fider, classSet } from "@fider/services";
-import { useFider } from "@fider/hooks";
-import { VotesModal } from "./VotesModal";
+import React, { useState } from "react"
+import { Post, Vote } from "@fider/models"
+import { Avatar } from "@fider/components"
+import { Fider, classSet } from "@fider/services"
+import { useFider } from "@fider/hooks"
+import { VotesModal } from "./VotesModal"
interface VotesPanelProps {
- post: Post;
- votes: Vote[];
+ post: Post
+ votes: Vote[]
}
export const VotesPanel = (props: VotesPanelProps) => {
- const fider = useFider();
- const [isVotesModalOpen, setIsVotesModalOpen] = useState(false);
+ const fider = useFider()
+ const [isVotesModalOpen, setIsVotesModalOpen] = useState(false)
const openModal = () => {
if (canShowAll()) {
- setIsVotesModalOpen(true);
+ setIsVotesModalOpen(true)
}
- };
+ }
- const closeModal = () => setIsVotesModalOpen(false);
- const canShowAll = () => fider.session.isAuthenticated && Fider.session.user.isCollaborator;
+ const closeModal = () => setIsVotesModalOpen(false)
+ const canShowAll = () => fider.session.isAuthenticated && Fider.session.user.isCollaborator
- const extraVotesCount = props.post.votesCount - props.votes.length;
+ const extraVotesCount = props.post.votesCount - props.votes.length
const moreVotesClassName = classSet({
"l-votes-more": true,
clickable: canShowAll(),
- });
+ })
return (
<>
@@ -52,5 +52,5 @@ export const VotesPanel = (props: VotesPanelProps) => {
{props.votes.length === 0 && None yet }
>
- );
-};
+ )
+}
diff --git a/public/pages/ShowPost/index.ts b/public/pages/ShowPost/index.ts
index 95c1c1cff..b49ea5650 100644
--- a/public/pages/ShowPost/index.ts
+++ b/public/pages/ShowPost/index.ts
@@ -1 +1 @@
-export * from "./ShowPost.page";
+export * from "./ShowPost.page"
diff --git a/public/pages/SignIn/SignIn.page.tsx b/public/pages/SignIn/SignIn.page.tsx
index 21df79bea..b6dd2c194 100644
--- a/public/pages/SignIn/SignIn.page.tsx
+++ b/public/pages/SignIn/SignIn.page.tsx
@@ -1,47 +1,46 @@
-import "./SignIn.page.scss";
+import "./SignIn.page.scss"
-import React from "react";
-import { SignInControl, TenantLogo, LegalNotice } from "@fider/components";
-import { notify, Fider } from "@fider/services";
+import React from "react"
+import { SignInControl, TenantLogo, LegalNotice } from "@fider/components"
+import { notify, Fider } from "@fider/services"
-const messages = {
- locked: () => (
- <>
-
- {Fider.session.tenant.name} is currently locked.
-
- To reactivate this site, sign in with an administrator account and update the required settings.
- >
- ),
- private: () => (
- <>
-
- {Fider.session.tenant.name} is a private space and requires an invitation to join it.
-
- If you have an account or an invitation, you may use following options to sign in.
- >
- ),
-};
+const Locked = (): JSX.Element => (
+ <>
+
+ {Fider.session.tenant.name} is currently locked.
+
+ To reactivate this site, sign in with an administrator account and update the required settings.
+ >
+)
-export default class SignInPage extends React.Component {
+const Private = (): JSX.Element => (
+ <>
+
+ {Fider.session.tenant.name} is a private space and requires an invitation to join it.
+
+ If you have an account or an invitation, you may use following options to sign in.
+ >
+)
+
+export default class SignInPage extends React.Component {
private onEmailSent = (email: string) => {
notify.success(
We have just sent a confirmation link to {email} . Click the link and you’ll be signed in.
- );
- };
+ )
+ }
public render() {
return (
- {Fider.session.tenant.isPrivate ? messages.private() : messages.locked()}
+ {Fider.session.tenant.isPrivate ?
:
}
- );
+ )
}
}
diff --git a/public/pages/SignIn/index.ts b/public/pages/SignIn/index.ts
index 3c59e2054..a525ad381 100644
--- a/public/pages/SignIn/index.ts
+++ b/public/pages/SignIn/index.ts
@@ -1 +1 @@
-export * from "./SignIn.page";
+export * from "./SignIn.page"
diff --git a/public/pages/SignUp/SignUp.page.tsx b/public/pages/SignUp/SignUp.page.tsx
index 8bc0e71bb..35b4ec41f 100644
--- a/public/pages/SignUp/SignUp.page.tsx
+++ b/public/pages/SignUp/SignUp.page.tsx
@@ -1,50 +1,50 @@
-import "./SignUp.page.scss";
+import "./SignUp.page.scss"
-import React from "react";
-import { SignInControl, Modal, Button, DisplayError, Form, Input, Message, LegalAgreement } from "@fider/components";
-import { jwt, actions, Failure, querystring, Fider } from "@fider/services";
+import React from "react"
+import { SignInControl, Modal, Button, DisplayError, Form, Input, Message, LegalAgreement } from "@fider/components"
+import { jwt, actions, Failure, querystring, Fider } from "@fider/services"
interface OAuthUser {
- token: string;
- name: string;
- email: string;
+ token: string
+ name: string
+ email: string
}
interface SignUpPageState {
- submitted: boolean;
- tenantName: string;
- legalAgreement: boolean;
- error?: Failure;
- name?: string;
- email?: string;
+ submitted: boolean
+ tenantName: string
+ legalAgreement: boolean
+ error?: Failure
+ name?: string
+ email?: string
subdomain: {
- available: boolean;
- message?: string;
- value?: string;
- };
+ available: boolean
+ message?: string
+ value?: string
+ }
}
-export default class SignUpPage extends React.Component<{}, SignUpPageState> {
- private user?: OAuthUser;
+export default class SignUpPage extends React.Component {
+ private user?: OAuthUser
- constructor(props: {}) {
- super(props);
+ constructor(props: any) {
+ super(props)
this.state = {
submitted: false,
legalAgreement: false,
tenantName: "",
subdomain: { available: false },
- };
+ }
- const token = querystring.get("token");
+ const token = querystring.get("token")
if (token) {
- const data = jwt.decode(token);
+ const data = jwt.decode(token)
if (data) {
this.user = {
token,
name: data["oauth/name"],
email: data["oauth/email"],
- };
+ }
}
}
}
@@ -57,31 +57,31 @@ export default class SignUpPage extends React.Component<{}, SignUpPageState> {
subdomain: this.state.subdomain.value,
name: this.state.name,
email: this.state.email,
- });
+ })
if (result.ok) {
if (this.user) {
if (Fider.isSingleHostMode()) {
- location.reload();
+ location.reload()
} else {
- let baseURL = `${location.protocol}//${this.state.subdomain.value}${Fider.settings.domain}`;
+ let baseURL = `${location.protocol}//${this.state.subdomain.value}${Fider.settings.domain}`
if (location.port) {
- baseURL = `${baseURL}:${location.port}`;
+ baseURL = `${baseURL}:${location.port}`
}
- location.href = baseURL;
+ location.href = baseURL
}
} else {
- this.setState({ submitted: true });
+ this.setState({ submitted: true })
}
} else if (result.error) {
- this.setState({ error: result.error, submitted: false });
+ this.setState({ error: result.error, submitted: false })
}
- };
+ }
- private timer?: number;
+ private timer?: number
private checkAvailability = (subdomain: string) => {
- window.clearTimeout(this.timer);
+ window.clearTimeout(this.timer)
this.timer = window.setTimeout(() => {
actions.checkAvailability(subdomain).then((result) => {
this.setState({
@@ -90,10 +90,10 @@ export default class SignUpPage extends React.Component<{}, SignUpPageState> {
available: !result.data.message,
message: result.data.message,
},
- });
- });
- }, 500);
- };
+ })
+ })
+ }, 500)
+ }
private setSubdomain = async (subdomain: string) => {
this.setState(
@@ -104,28 +104,28 @@ export default class SignUpPage extends React.Component<{}, SignUpPageState> {
},
},
this.checkAvailability.bind(this, subdomain)
- );
- };
+ )
+ }
private onAgree = (agreed: boolean): void => {
- this.setState({ legalAgreement: agreed });
- };
+ this.setState({ legalAgreement: agreed })
+ }
private setName = (name: string): void => {
- this.setState({ name });
- };
+ this.setState({ name })
+ }
private setEmail = (email: string): void => {
- this.setState({ email });
- };
+ this.setState({ email })
+ }
private setTenantName = (tenantName: string): void => {
- this.setState({ tenantName });
- };
+ this.setState({ tenantName })
+ }
private noop = () => {
// do nothing
- };
+ }
public render() {
const modal = (
@@ -137,12 +137,12 @@ export default class SignUpPage extends React.Component<{}, SignUpPageState> {
- );
+ )
return (
{modal}
-
+
1. Who are you?
@@ -194,6 +194,6 @@ export default class SignUpPage extends React.Component<{}, SignUpPageState> {
Confirm
- );
+ )
}
}
diff --git a/public/pages/SignUp/index.ts b/public/pages/SignUp/index.ts
index 1dd5ac86b..3da95d669 100644
--- a/public/pages/SignUp/index.ts
+++ b/public/pages/SignUp/index.ts
@@ -1 +1 @@
-export * from "./SignUp.page";
+export * from "./SignUp.page"
diff --git a/public/pages/UI/UIToolkit.page.tsx b/public/pages/UI/UIToolkit.page.tsx
index a54bbfeac..e081e33ce 100644
--- a/public/pages/UI/UIToolkit.page.tsx
+++ b/public/pages/UI/UIToolkit.page.tsx
@@ -1,7 +1,7 @@
-import "./UIToolkit.page.scss";
+import "./UIToolkit.page.scss"
-import React, { useState } from "react";
-import { PostStatus, UserStatus } from "@fider/models";
+import React, { useState } from "react"
+import { PostStatus, UserStatus } from "@fider/models"
import {
Heading,
Button,
@@ -26,11 +26,11 @@ import {
ButtonClickEvent,
Message,
Hint,
-} from "@fider/components";
-import { User, UserRole, Tag } from "@fider/models";
-import { notify, Failure } from "@fider/services";
-import { DropDown, DropDownItem } from "@fider/components";
-import { FaSearch, FaRegLightbulb, FaCogs } from "react-icons/fa";
+} from "@fider/components"
+import { User, UserRole, Tag } from "@fider/models"
+import { notify, Failure } from "@fider/services"
+import { DropDown, DropDownItem } from "@fider/components"
+import { FaSearch, FaRegLightbulb, FaCogs } from "react-icons/fa"
const jonSnow: User = {
id: 0,
@@ -38,7 +38,7 @@ const jonSnow: User = {
role: UserRole.Administrator,
status: UserStatus.Active,
avatarURL: "/avatars/letter/0/Jon%20Snow",
-};
+}
const aryaStark: User = {
id: 0,
@@ -46,34 +46,34 @@ const aryaStark: User = {
role: UserRole.Visitor,
status: UserStatus.Active,
avatarURL: "/avatars/letter/0/Arya%20Snow",
-};
+}
-const easyTag: Tag = { id: 2, slug: "easy", name: "easy", color: "FB3A62", isPublic: true };
-const hardTag: Tag = { id: 3, slug: "hard", name: "hard", color: "fbca04", isPublic: false };
+const easyTag: Tag = { id: 2, slug: "easy", name: "easy", color: "FB3A62", isPublic: true }
+const hardTag: Tag = { id: 3, slug: "hard", name: "hard", color: "fbca04", isPublic: false }
-const visibilityPublic = { label: "Public", value: "public" };
-const visibilityPrivate = { label: "Private", value: "private" };
+const visibilityPublic = { label: "Public", value: "public" }
+const visibilityPrivate = { label: "Private", value: "private" }
const UIToolkitPage = () => {
- const [error, setError] = useState(undefined);
+ const [error, setError] = useState(undefined)
const notifyError = async () => {
- notify.error("Something went wrong...");
- };
+ notify.error("Something went wrong...")
+ }
const notifySuccess = async () => {
- notify.success("Congratulations! It worked!");
- };
+ notify.success("Congratulations! It worked!")
+ }
const notifyStatusChange = (opt?: SelectOption) => {
if (opt) {
- notify.success(opt.value);
+ notify.success(opt.value)
}
- };
+ }
const showLoading = async (e: ButtonClickEvent) => {
- return e.preventEnable();
- };
+ return e.preventEnable()
+ }
const forceError = async () => {
setError({
@@ -83,22 +83,22 @@ const UIToolkitPage = () => {
{ field: "description", message: "Error #2" },
{ field: "status", message: "Status is mandatory" },
],
- });
- };
+ })
+ }
const renderText = (item?: DropDownItem) => {
if (item) {
- return `${item.label} (value: ${item.value})`;
+ return `${item.label} (value: ${item.value})`
}
- return No country is selected ;
- };
+ return No country is selected
+ }
const renderControl = (item?: DropDownItem) => {
if (item) {
- return item.render;
+ return item.render
}
- return ... ;
- };
+ return ...
+ }
return (
@@ -406,7 +406,7 @@ const UIToolkitPage = () => {
Hints
Did you know that you can close this permanently?
- You can't close this one :)
+ You can't close this one :)
Form
@@ -496,7 +496,7 @@ const UIToolkitPage = () => {
- );
-};
+ )
+}
-export default UIToolkitPage;
+export default UIToolkitPage
diff --git a/public/pages/UI/index.ts b/public/pages/UI/index.ts
index a63cf2b80..be74474cb 100644
--- a/public/pages/UI/index.ts
+++ b/public/pages/UI/index.ts
@@ -1 +1 @@
-export * from "./UIToolkit.page";
+export * from "./UIToolkit.page"
diff --git a/public/router.spec.tsx b/public/router.spec.tsx
index a641dea0b..ebd00ac8c 100644
--- a/public/router.spec.tsx
+++ b/public/router.spec.tsx
@@ -1,7 +1,6 @@
-import { resolveRootComponent } from "./router";
-import * as Pages from "@fider/AsyncPages";
-
-[
+import { resolveRootComponent } from "./router"
+import * as Pages from "@fider/AsyncPages"
+;[
{ path: "", expected: Pages.AsyncHomePage },
{ path: "/posts/123", expected: Pages.AsyncShowPostPage },
{ path: "/posts/123/the-slug", expected: Pages.AsyncShowPostPage },
@@ -12,10 +11,10 @@ import * as Pages from "@fider/AsyncPages";
].forEach((x) => {
test(`Router should resolve correct component for path '${x.path}'`, () => {
if (x.expected) {
- const page = resolveRootComponent(x.path);
- expect(page.component).toEqual(x.expected);
+ const page = resolveRootComponent(x.path)
+ expect(page.component).toEqual(x.expected)
} else {
- expect(() => resolveRootComponent(x.path)).toThrowError();
+ expect(() => resolveRootComponent(x.path)).toThrowError()
}
- });
-});
+ })
+})
diff --git a/public/router.tsx b/public/router.tsx
index b2b450b69..673edf1d4 100644
--- a/public/router.tsx
+++ b/public/router.tsx
@@ -1,17 +1,17 @@
-import * as Pages from "@fider/AsyncPages";
+import * as Pages from "@fider/AsyncPages"
interface PageConfiguration {
- regex: RegExp;
- component: any;
- showHeader: boolean;
+ regex: RegExp
+ component: any
+ showHeader: boolean
}
-export const route = (path: string, component: any, showHeader: boolean = true): PageConfiguration => {
- path = path.replace("/", "/").replace(":number", "\\d+").replace(":string", ".+").replace("*", "/?.*");
+export const route = (path: string, component: any, showHeader = true): PageConfiguration => {
+ path = path.replace("/", "/").replace(":number", "\\d+").replace(":string", ".+").replace("*", "/?.*")
- const regex = new RegExp(`^${path}$`);
- return { regex, component, showHeader };
-};
+ const regex = new RegExp(`^${path}$`)
+ return { regex, component, showHeader }
+}
const defaultRoutes = [
route("", Pages.AsyncHomePage),
@@ -32,16 +32,16 @@ const defaultRoutes = [
route("/settings", Pages.AsyncMySettingsPage),
route("/oauth/:string/echo", Pages.AsyncOAuthEchoPage, false),
route("/-/ui", Pages.AsyncUIToolkitPage),
-];
+]
export const resolveRootComponent = (path: string, routes: PageConfiguration[] = defaultRoutes): PageConfiguration => {
if (path.length > 0 && path.charAt(path.length - 1) === "/") {
- path = path.substring(0, path.length - 1);
+ path = path.substring(0, path.length - 1)
}
for (const entry of routes) {
if (entry && entry.regex.test(path)) {
- return entry;
+ return entry
}
}
- throw new Error(`Component not found for route ${path}.`);
-};
+ throw new Error(`Component not found for route ${path}.`)
+}
diff --git a/public/services/actions/index.ts b/public/services/actions/index.ts
index ade45197f..e1229d34c 100644
--- a/public/services/actions/index.ts
+++ b/public/services/actions/index.ts
@@ -1,7 +1,7 @@
-export * from "./user";
-export * from "./tag";
-export * from "./post";
-export * from "./tenant";
-export * from "./notification";
-export * from "./invite";
-export * from "./infra";
+export * from "./user"
+export * from "./tag"
+export * from "./post"
+export * from "./tenant"
+export * from "./notification"
+export * from "./invite"
+export * from "./infra"
diff --git a/public/services/actions/infra.ts b/public/services/actions/infra.ts
index 0b9426fa1..4d1572a7b 100644
--- a/public/services/actions/infra.ts
+++ b/public/services/actions/infra.ts
@@ -1,4 +1,4 @@
-import { http, Result, navigator, analytics } from "@fider/services";
+import { http, Result, navigator, analytics } from "@fider/services"
const ignoreErrors = [
"http://gj.track.uc.cn/collect", // CSP error: UC Browser tries to use sendBeacon to this domain, which is blocked by our CSP rule
@@ -6,24 +6,24 @@ const ignoreErrors = [
"Refused to evaluate a string as JavaScript because 'unsafe-eval'", // CSP error: usually thrown because of bad Chrome Extensions
"vid_mate_check is not defined", // CSP error: thrown by VidMate, an Android Browser
"SecurityError: Failed to read the 'cssRules' property from 'CSSStyleSheet': Cannot access rules", // CSP error: usually thrown because of bad Chrome Extensions
-];
+]
export const logError = async (message: string, err?: Error): Promise => {
for (const pattern of ignoreErrors) {
if (message.indexOf(pattern) >= 0) {
- return;
+ return
}
}
const data = {
url: navigator.url(),
stack: err ? err.stack : "",
- };
+ }
try {
- analytics.error(err);
- return await http.post("/_api/log-error", { message, data });
+ analytics.error(err)
+ return await http.post("/_api/log-error", { message, data })
} catch (err) {
- // tslint:disable-next-line:no-empty
+ console.error(err)
}
-};
+}
diff --git a/public/services/actions/invite.ts b/public/services/actions/invite.ts
index 470f2f026..fc8672e61 100644
--- a/public/services/actions/invite.ts
+++ b/public/services/actions/invite.ts
@@ -1,9 +1,9 @@
-import { http, Result } from "@fider/services";
+import { http, Result } from "@fider/services"
export const sendInvites = async (subject: string, message: string, recipients: string[]): Promise => {
- return http.post("/api/v1/invitations/send", { subject, message, recipients }).then(http.event("invite", "send"));
-};
+ return http.post("/api/v1/invitations/send", { subject, message, recipients }).then(http.event("invite", "send"))
+}
export const sendSampleInvite = async (subject: string, message: string): Promise => {
- return http.post("/api/v1/invitations/sample", { subject, message }).then(http.event("invite", "sample"));
-};
+ return http.post("/api/v1/invitations/sample", { subject, message }).then(http.event("invite", "sample"))
+}
diff --git a/public/services/actions/notification.ts b/public/services/actions/notification.ts
index d90b1dc20..b2b7fe857 100644
--- a/public/services/actions/notification.ts
+++ b/public/services/actions/notification.ts
@@ -1,4 +1,4 @@
-import { http, Result } from "@fider/services";
+import { http, Result } from "@fider/services"
export const getTotalUnreadNotifications = async (): Promise> => {
return http.get<{ total: number }>("/_api/notifications/unread/total").then((result) => {
@@ -6,10 +6,10 @@ export const getTotalUnreadNotifications = async (): Promise> =>
ok: result.ok,
error: result.error,
data: result.data ? result.data.total : 0,
- };
- });
-};
+ }
+ })
+}
export const markAllAsRead = async (): Promise => {
- return await http.post("/_api/notifications/read-all");
-};
+ return await http.post("/_api/notifications/read-all")
+}
diff --git a/public/services/actions/post.ts b/public/services/actions/post.ts
index 4195b3775..43ed7ee71 100644
--- a/public/services/actions/post.ts
+++ b/public/services/actions/post.ts
@@ -1,15 +1,15 @@
-import { http, Result, querystring } from "@fider/services";
-import { Post, Vote, ImageUpload } from "@fider/models";
+import { http, Result, querystring } from "@fider/services"
+import { Post, Vote, ImageUpload } from "@fider/models"
export const getAllPosts = async (): Promise> => {
- return await http.get("/api/v1/posts");
-};
+ return await http.get("/api/v1/posts")
+}
export interface SearchPostsParams {
- query?: string;
- view?: string;
- limit?: number;
- tags?: string[];
+ query?: string
+ view?: string
+ limit?: number
+ tags?: string[]
}
export const searchPosts = async (params: SearchPostsParams): Promise> => {
@@ -20,53 +20,53 @@ export const searchPosts = async (params: SearchPostsParams): Promise => {
return http
.delete(`/api/v1/posts/${postNumber}`, {
text,
})
- .then(http.event("post", "delete"));
-};
+ .then(http.event("post", "delete"))
+}
export const addVote = async (postNumber: number): Promise => {
- return http.post(`/api/v1/posts/${postNumber}/votes`).then(http.event("post", "vote"));
-};
+ return http.post(`/api/v1/posts/${postNumber}/votes`).then(http.event("post", "vote"))
+}
export const removeVote = async (postNumber: number): Promise => {
- return http.delete(`/api/v1/posts/${postNumber}/votes`).then(http.event("post", "unvote"));
-};
+ return http.delete(`/api/v1/posts/${postNumber}/votes`).then(http.event("post", "unvote"))
+}
export const subscribe = async (postNumber: number): Promise => {
- return http.post(`/api/v1/posts/${postNumber}/subscription`).then(http.event("post", "subscribe"));
-};
+ return http.post(`/api/v1/posts/${postNumber}/subscription`).then(http.event("post", "subscribe"))
+}
export const unsubscribe = async (postNumber: number): Promise => {
- return http.delete(`/api/v1/posts/${postNumber}/subscription`).then(http.event("post", "unsubscribe"));
-};
+ return http.delete(`/api/v1/posts/${postNumber}/subscription`).then(http.event("post", "unsubscribe"))
+}
export const listVotes = async (postNumber: number): Promise> => {
- return http.get(`/api/v1/posts/${postNumber}/votes`);
-};
+ return http.get(`/api/v1/posts/${postNumber}/votes`)
+}
export const createComment = async (postNumber: number, content: string, attachments: ImageUpload[]): Promise => {
- return http.post(`/api/v1/posts/${postNumber}/comments`, { content, attachments }).then(http.event("comment", "create"));
-};
+ return http.post(`/api/v1/posts/${postNumber}/comments`, { content, attachments }).then(http.event("comment", "create"))
+}
export const updateComment = async (postNumber: number, commentID: number, content: string, attachments: ImageUpload[]): Promise => {
- return http.put(`/api/v1/posts/${postNumber}/comments/${commentID}`, { content, attachments }).then(http.event("comment", "update"));
-};
+ return http.put(`/api/v1/posts/${postNumber}/comments/${commentID}`, { content, attachments }).then(http.event("comment", "update"))
+}
export const deleteComment = async (postNumber: number, commentID: number): Promise => {
- return http.delete(`/api/v1/posts/${postNumber}/comments/${commentID}`).then(http.event("comment", "delete"));
-};
+ return http.delete(`/api/v1/posts/${postNumber}/comments/${commentID}`).then(http.event("comment", "delete"))
+}
interface SetResponseInput {
- status: string;
- text: string;
- originalNumber: number;
+ status: string
+ text: string
+ originalNumber: number
}
export const respond = async (postNumber: number, input: SetResponseInput): Promise => {
@@ -76,22 +76,22 @@ export const respond = async (postNumber: number, input: SetResponseInput): Prom
text: input.text,
originalNumber: input.originalNumber,
})
- .then(http.event("post", "respond"));
-};
+ .then(http.event("post", "respond"))
+}
interface CreatePostResponse {
- id: number;
- number: number;
- title: string;
- slug: string;
+ id: number
+ number: number
+ title: string
+ slug: string
}
export const createPost = async (title: string, description: string, attachments: ImageUpload[]): Promise> => {
return http
.post(`/api/v1/posts`, { title, description, attachments })
- .then(http.event("post", "create"));
-};
+ .then(http.event("post", "create"))
+}
export const updatePost = async (postNumber: number, title: string, description: string, attachments: ImageUpload[]): Promise => {
- return http.put(`/api/v1/posts/${postNumber}`, { title, description, attachments }).then(http.event("post", "update"));
-};
+ return http.put(`/api/v1/posts/${postNumber}`, { title, description, attachments }).then(http.event("post", "update"))
+}
diff --git a/public/services/actions/tag.ts b/public/services/actions/tag.ts
index 20d41c189..cb9adc0c7 100644
--- a/public/services/actions/tag.ts
+++ b/public/services/actions/tag.ts
@@ -1,26 +1,26 @@
-import { http, Result } from "@fider/services/http";
-import { Tag } from "@fider/models";
+import { http, Result } from "@fider/services/http"
+import { Tag } from "@fider/models"
export const createTag = async (name: string, color: string, isPublic: boolean): Promise> => {
return http
.post(`/api/v1/tags`, { name, color, isPublic })
- .then(http.event("tag", "create"));
-};
+ .then(http.event("tag", "create"))
+}
export const updateTag = async (slug: string, name: string, color: string, isPublic: boolean): Promise> => {
return http
.put(`/api/v1/tags/${slug}`, { name, color, isPublic })
- .then(http.event("tag", "update"));
-};
+ .then(http.event("tag", "update"))
+}
export const deleteTag = async (slug: string): Promise => {
- return http.delete(`/api/v1/tags/${slug}`).then(http.event("tag", "delete"));
-};
+ return http.delete(`/api/v1/tags/${slug}`).then(http.event("tag", "delete"))
+}
export const assignTag = async (slug: string, postNumber: number): Promise => {
- return http.post(`/api/v1/posts/${postNumber}/tags/${slug}`).then(http.event("tag", "assign"));
-};
+ return http.post(`/api/v1/posts/${postNumber}/tags/${slug}`).then(http.event("tag", "assign"))
+}
export const unassignTag = async (slug: string, postNumber: number): Promise => {
- return http.delete(`/api/v1/posts/${postNumber}/tags/${slug}`).then(http.event("tag", "unassign"));
-};
+ return http.delete(`/api/v1/posts/${postNumber}/tags/${slug}`).then(http.event("tag", "unassign"))
+}
diff --git a/public/services/actions/tenant.ts b/public/services/actions/tenant.ts
index 602d60df9..99a8b565d 100644
--- a/public/services/actions/tenant.ts
+++ b/public/services/actions/tenant.ts
@@ -1,100 +1,100 @@
-import { http, Result } from "@fider/services/http";
-import { UserRole, OAuthConfig, ImageUpload } from "@fider/models";
+import { http, Result } from "@fider/services/http"
+import { UserRole, OAuthConfig, ImageUpload } from "@fider/models"
export interface CheckAvailabilityResponse {
- message: string;
+ message: string
}
export interface CreateTenantRequest {
- legalAgreement: boolean;
- tenantName: string;
- subdomain?: string;
- name?: string;
- token?: string;
- email?: string;
+ legalAgreement: boolean
+ tenantName: string
+ subdomain?: string
+ name?: string
+ token?: string
+ email?: string
}
export interface CreateTenantResponse {
- token?: string;
+ token?: string
}
export const createTenant = async (request: CreateTenantRequest): Promise> => {
- return await http.post("/_api/tenants", request);
-};
+ return await http.post("/_api/tenants", request)
+}
export interface UpdateTenantSettingsRequest {
- logo?: ImageUpload;
- title: string;
- invitation: string;
- welcomeMessage: string;
- cname: string;
+ logo?: ImageUpload
+ title: string
+ invitation: string
+ welcomeMessage: string
+ cname: string
}
export const updateTenantSettings = async (request: UpdateTenantSettingsRequest): Promise => {
- return await http.post("/_api/admin/settings/general", request);
-};
+ return await http.post("/_api/admin/settings/general", request)
+}
export const updateTenantAdvancedSettings = async (customCSS: string): Promise => {
- return await http.post("/_api/admin/settings/advanced", { customCSS });
-};
+ return await http.post("/_api/admin/settings/advanced", { customCSS })
+}
export const updateTenantPrivacy = async (isPrivate: boolean): Promise => {
return await http.post("/_api/admin/settings/privacy", {
isPrivate,
- });
-};
+ })
+}
export const checkAvailability = async (subdomain: string): Promise> => {
- return await http.get(`/_api/tenants/${subdomain}/availability`);
-};
+ return await http.get(`/_api/tenants/${subdomain}/availability`)
+}
export const signIn = async (email: string): Promise => {
return await http.post("/_api/signin", {
email,
- });
-};
+ })
+}
export const completeProfile = async (key: string, name: string): Promise => {
return await http.post("/_api/signin/complete", {
key,
name,
- });
-};
+ })
+}
export const changeUserRole = async (userID: number, role: UserRole): Promise => {
return await http.post(`/_api/admin/roles/${role}/users`, {
userID,
- });
-};
+ })
+}
export const blockUser = async (userID: number): Promise => {
- return await http.put(`/_api/admin/users/${userID}/block`);
-};
+ return await http.put(`/_api/admin/users/${userID}/block`)
+}
export const unblockUser = async (userID: number): Promise => {
- return await http.delete(`/_api/admin/users/${userID}/block`);
-};
+ return await http.delete(`/_api/admin/users/${userID}/block`)
+}
export const getOAuthConfig = async (provider: string): Promise> => {
- return await http.get(`/_api/admin/oauth/${provider}`);
-};
+ return await http.get(`/_api/admin/oauth/${provider}`)
+}
export interface CreateEditOAuthConfigRequest {
- provider: string;
- status: number;
- displayName: string;
- clientID: string;
- clientSecret: string;
- authorizeURL: string;
- tokenURL: string;
- scope: string;
- profileURL: string;
- jsonUserIDPath: string;
- jsonUserNamePath: string;
- jsonUserEmailPath: string;
- logo?: ImageUpload;
+ provider: string
+ status: number
+ displayName: string
+ clientID: string
+ clientSecret: string
+ authorizeURL: string
+ tokenURL: string
+ scope: string
+ profileURL: string
+ jsonUserIDPath: string
+ jsonUserNamePath: string
+ jsonUserEmailPath: string
+ logo?: ImageUpload
}
export const saveOAuthConfig = async (request: CreateEditOAuthConfigRequest): Promise => {
- return await http.post("/_api/admin/oauth", request);
-};
+ return await http.post("/_api/admin/oauth", request)
+}
diff --git a/public/services/actions/user.ts b/public/services/actions/user.ts
index bf91e4f1e..8e7039c32 100644
--- a/public/services/actions/user.ts
+++ b/public/services/actions/user.ts
@@ -1,27 +1,27 @@
-import { http, Result } from "@fider/services/http";
-import { UserSettings, UserAvatarType, ImageUpload } from "@fider/models";
+import { http, Result } from "@fider/services/http"
+import { UserSettings, UserAvatarType, ImageUpload } from "@fider/models"
interface UpdateUserSettings {
- name: string;
- avatar?: ImageUpload;
- avatarType: UserAvatarType;
- settings: UserSettings;
+ name: string
+ avatar?: ImageUpload
+ avatarType: UserAvatarType
+ settings: UserSettings
}
export const updateUserSettings = async (request: UpdateUserSettings): Promise => {
- return await http.post("/_api/user/settings", request);
-};
+ return await http.post("/_api/user/settings", request)
+}
export const changeUserEmail = async (email: string): Promise => {
return await http.post("/_api/user/change-email", {
email,
- });
-};
+ })
+}
export const deleteCurrentAccount = async (): Promise => {
- return await http.delete("/_api/user");
-};
+ return await http.delete("/_api/user")
+}
export const regenerateAPIKey = async (): Promise> => {
- return await http.post<{ apiKey: string }>("/_api/user/regenerate-apikey");
-};
+ return await http.post<{ apiKey: string }>("/_api/user/regenerate-apikey")
+}
diff --git a/public/services/analytics.ts b/public/services/analytics.ts
index 163f798f0..00f1d811c 100644
--- a/public/services/analytics.ts
+++ b/public/services/analytics.ts
@@ -4,7 +4,7 @@ export const analytics = {
window.ga("send", "event", {
eventCategory,
eventAction,
- });
+ })
}
},
error: (err?: Error): void => {
@@ -12,7 +12,7 @@ export const analytics = {
window.ga("send", "exception", {
exDescription: err ? err.stack : "",
exFatal: false,
- });
+ })
}
},
-};
+}
diff --git a/public/services/cache.spec.ts b/public/services/cache.spec.ts
index 0cb27d137..bb59c9034 100644
--- a/public/services/cache.spec.ts
+++ b/public/services/cache.spec.ts
@@ -1,19 +1,19 @@
-import { cache } from "./cache";
+import { cache } from "./cache"
test("cache starts empty", () => {
- const value = cache.local.get("my-key");
- expect(value).toBeNull();
+ const value = cache.local.get("my-key")
+ expect(value).toBeNull()
- expect(cache.local.has("my-key")).toBeFalsy();
-});
+ expect(cache.local.has("my-key")).toBeFalsy()
+})
test("can set, remove and get from cache", () => {
- cache.local.set("my-key", "Hello World");
- const value = cache.local.get("my-key");
- expect(value).toBe("Hello World");
- expect(cache.local.has("my-key")).toBeTruthy();
+ cache.local.set("my-key", "Hello World")
+ const value = cache.local.get("my-key")
+ expect(value).toBe("Hello World")
+ expect(cache.local.has("my-key")).toBeTruthy()
- cache.local.remove("my-key");
- const newValue = cache.local.get("my-key");
- expect(newValue).toBeNull();
-});
+ cache.local.remove("my-key")
+ const newValue = cache.local.get("my-key")
+ expect(newValue).toBeNull()
+})
diff --git a/public/services/cache.ts b/public/services/cache.ts
index c802717c9..83ae793e2 100644
--- a/public/services/cache.ts
+++ b/public/services/cache.ts
@@ -1,58 +1,58 @@
const set = (storage: Storage, key: string, value: string): void => {
if (storage) {
- storage.setItem(key, value);
+ storage.setItem(key, value)
}
-};
+}
const get = (storage: Storage, key: string): string | null => {
if (window.localStorage) {
- return storage.getItem(key);
+ return storage.getItem(key)
}
- return null;
-};
+ return null
+}
const has = (storage: Storage, key: string): boolean => {
if (storage) {
- return !!storage.getItem(key);
+ return !!storage.getItem(key)
}
- return false;
-};
+ return false
+}
const remove = (storage: Storage, ...keys: string[]): void => {
if (storage && keys) {
for (const key of keys) {
- storage.removeItem(key);
+ storage.removeItem(key)
}
}
-};
+}
export const cache = {
local: {
set: (key: string, value: string): void => {
- set(window.localStorage, key, value);
+ set(window.localStorage, key, value)
},
get: (key: string): string | null => {
- return get(window.localStorage, key);
+ return get(window.localStorage, key)
},
has: (key: string): boolean => {
- return has(window.localStorage, key);
+ return has(window.localStorage, key)
},
remove: (...keys: string[]): void => {
- remove(window.localStorage, ...keys);
+ remove(window.localStorage, ...keys)
},
},
session: {
set: (key: string, value: string): void => {
- set(window.sessionStorage, key, value);
+ set(window.sessionStorage, key, value)
},
get: (key: string): string | null => {
- return get(window.sessionStorage, key);
+ return get(window.sessionStorage, key)
},
has: (key: string): boolean => {
- return has(window.sessionStorage, key);
+ return has(window.sessionStorage, key)
},
remove: (...keys: string[]): void => {
- remove(window.sessionStorage, ...keys);
+ remove(window.sessionStorage, ...keys)
},
},
-};
+}
diff --git a/public/services/device.ts b/public/services/device.ts
index 4d312bd49..e0d0af053 100644
--- a/public/services/device.ts
+++ b/public/services/device.ts
@@ -1,3 +1,3 @@
export const isTouch = (): boolean => {
- return "ontouchstart" in window || navigator.maxTouchPoints > 0 || navigator.msMaxTouchPoints > 0;
-};
+ return "ontouchstart" in window || navigator.maxTouchPoints > 0 || navigator.msMaxTouchPoints > 0
+}
diff --git a/public/services/fider.ts b/public/services/fider.ts
index 0619a3faa..c50134248 100644
--- a/public/services/fider.ts
+++ b/public/services/fider.ts
@@ -1,75 +1,76 @@
-import { createContext } from "react";
-import { CurrentUser, SystemSettings, Tenant } from "@fider/models";
+import { createContext } from "react"
+import { CurrentUser, SystemSettings, Tenant } from "@fider/models"
export class FiderSession {
- private pContextID: string;
- private pTenant: Tenant;
- private pUser: CurrentUser | undefined;
- private pProps: { [key: string]: any } = {};
+ private pContextID: string
+ private pTenant: Tenant
+ private pUser: CurrentUser | undefined
+ private pProps: { [key: string]: any } = {}
constructor(data: any) {
- this.pContextID = data.contextID;
- this.pProps = data.props;
- this.pUser = data.user;
- this.pTenant = data.tenant;
+ this.pContextID = data.contextID
+ this.pProps = data.props
+ this.pUser = data.user
+ this.pTenant = data.tenant
}
public get contextID(): string {
- return this.pContextID;
+ return this.pContextID
}
public get user(): CurrentUser {
- return this.pUser!;
+ if (!this.pUser) throw new Error("User is undefined")
+ return this.pUser
}
public get tenant(): Tenant {
- return this.pTenant;
+ return this.pTenant
}
public get props(): { [key: string]: any } {
- return this.pProps;
+ return this.pProps
}
public get isAuthenticated(): boolean {
- return !!this.pUser;
+ return !!this.pUser
}
}
export class FiderImpl {
- private pSettings!: SystemSettings;
- private pSession!: FiderSession;
+ private pSettings!: SystemSettings
+ private pSession!: FiderSession
public initialize = (initData?: any): FiderImpl => {
if (initData) {
- this.pSettings = initData.settings;
- this.pSession = new FiderSession(initData);
- return this;
+ this.pSettings = initData.settings
+ this.pSession = new FiderSession(initData)
+ return this
}
- const el = document.getElementById("server-data");
- const data = el ? JSON.parse(el.textContent || el.innerText) : {};
- this.pSettings = data.settings;
- this.pSession = new FiderSession(data);
- return this;
- };
+ const el = document.getElementById("server-data")
+ const data = el ? JSON.parse(el.textContent || el.innerText) : {}
+ this.pSettings = data.settings
+ this.pSession = new FiderSession(data)
+ return this
+ }
public get session(): FiderSession {
- return this.pSession;
+ return this.pSession
}
public get settings(): SystemSettings {
- return this.pSettings;
+ return this.pSettings
}
public isProduction(): boolean {
- return this.pSettings.environment === "production";
+ return this.pSettings.environment === "production"
}
public isSingleHostMode(): boolean {
- return this.pSettings.mode === "single";
+ return this.pSettings.mode === "single"
}
}
-export let Fider = new FiderImpl();
+export const Fider = new FiderImpl()
-export const FiderContext = createContext(Fider);
+export const FiderContext = createContext(Fider)
diff --git a/public/services/http.ts b/public/services/http.ts
index 6d21fe601..7565cafda 100644
--- a/public/services/http.ts
+++ b/public/services/http.ts
@@ -1,34 +1,34 @@
-import { analytics, notify, truncate } from "@fider/services";
+import { analytics, notify, truncate } from "@fider/services"
export interface ErrorItem {
- field?: string;
- message: string;
+ field?: string
+ message: string
}
export interface Failure {
- errors?: ErrorItem[];
+ errors?: ErrorItem[]
}
export interface Result {
- ok: boolean;
- data: T;
- error?: Failure;
+ ok: boolean
+ data: T
+ error?: Failure
}
async function toResult(response: Response): Promise> {
- const body = await response.json();
+ const body = await response.json()
if (response.status < 400) {
return {
ok: true,
data: body as T,
- };
+ }
}
if (response.status === 500) {
- notify.error("An unexpected error occurred while processing your request.");
+ notify.error("An unexpected error occurred while processing your request.")
} else if (response.status === 403) {
- notify.error("You are not authorized to perform this operation.");
+ notify.error("You are not authorized to perform this operation.")
}
return {
@@ -37,44 +37,44 @@ async function toResult(response: Response): Promise> {
error: {
errors: body.errors,
},
- };
+ }
}
async function request(url: string, method: "GET" | "POST" | "PUT" | "DELETE", body?: any): Promise> {
const headers = [
["Accept", "application/json"],
["Content-Type", "application/json"],
- ];
+ ]
try {
const response = await fetch(url, {
method,
headers,
body: JSON.stringify(body),
credentials: "same-origin",
- });
- return await toResult(response);
+ })
+ return await toResult(response)
} catch (err) {
- const truncatedBody = truncate(body ? JSON.stringify(body) : "", 1000);
- throw new Error(`Failed to ${method} ${url} with body '${truncatedBody}'`);
+ const truncatedBody = truncate(body ? JSON.stringify(body) : "", 1000)
+ throw new Error(`Failed to ${method} ${url} with body '${truncatedBody}'`)
}
}
export const http = {
get: async (url: string): Promise> => {
- return await request(url, "GET");
+ return await request(url, "GET")
},
- post: async (url: string, body?: {}): Promise> => {
- return await request(url, "POST", body);
+ post: async (url: string, body?: any): Promise> => {
+ return await request(url, "POST", body)
},
- put: async (url: string, body?: {}): Promise> => {
- return await request(url, "PUT", body);
+ put: async (url: string, body?: any): Promise> => {
+ return await request(url, "PUT", body)
},
- delete: async (url: string, body?: {}): Promise> => {
- return await request(url, "DELETE", body);
+ delete: async (url: string, body?: any): Promise> => {
+ return await request(url, "DELETE", body)
},
event: (category: string, action: string) => (result: Result): Result => {
if (result && result.ok) {
- analytics.event(category, action);
+ analytics.event(category, action)
}
- return result;
+ return result
},
-};
+}
diff --git a/public/services/index.ts b/public/services/index.ts
index 03ff4ec8a..56ff3c135 100644
--- a/public/services/index.ts
+++ b/public/services/index.ts
@@ -1,13 +1,13 @@
-export * from "./http";
-export * from "./cache";
-export * from "./analytics";
-export * from "./fider";
-export * from "./jwt";
-export * from "./utils";
-import * as markdown from "./markdown";
-import * as notify from "./notify";
-import * as querystring from "./querystring";
-import * as device from "./device";
-import * as actions from "./actions";
-import navigator from "./navigator";
-export { actions, querystring, navigator, device, notify, markdown };
+export * from "./http"
+export * from "./cache"
+export * from "./analytics"
+export * from "./fider"
+export * from "./jwt"
+export * from "./utils"
+import * as markdown from "./markdown"
+import * as notify from "./notify"
+import * as querystring from "./querystring"
+import * as device from "./device"
+import * as actions from "./actions"
+import navigator from "./navigator"
+export { actions, querystring, navigator, device, notify, markdown }
diff --git a/public/services/jwt.spec.ts b/public/services/jwt.spec.ts
index 0303bdfbd..bb345ac43 100644
--- a/public/services/jwt.spec.ts
+++ b/public/services/jwt.spec.ts
@@ -1,6 +1,5 @@
-import { jwt } from "./jwt";
-
-[
+import { jwt } from "./jwt"
+;[
{
expected: {
sub: "1234567890",
@@ -8,7 +7,8 @@ import { jwt } from "./jwt";
age: "30",
iat: 1516239022,
},
- token: "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gU25vdyIsImFnZSI6IjMwIiwiaWF0IjoxNTE2MjM5MDIyfQ.A4e171Ry70APUJ2a9uo9G9Aju9G08AJB_Cr9B9ivX-o",
+ token:
+ "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gU25vdyIsImFnZSI6IjMwIiwiaWF0IjoxNTE2MjM5MDIyfQ.A4e171Ry70APUJ2a9uo9G9Aju9G08AJB_Cr9B9ivX-o",
},
{
expected: undefined,
@@ -16,7 +16,7 @@ import { jwt } from "./jwt";
},
].forEach((x) => {
test(`decode('${x.token}') should be ${x.expected}`, () => {
- const result = jwt.decode(x.token);
- expect(result).toEqual(x.expected);
- });
-});
+ const result = jwt.decode(x.token)
+ expect(result).toEqual(x.expected)
+ })
+})
diff --git a/public/services/jwt.ts b/public/services/jwt.ts
index 4c4d17e25..a9ca4aa97 100644
--- a/public/services/jwt.ts
+++ b/public/services/jwt.ts
@@ -1,12 +1,12 @@
export const jwt = {
decode: (token: string): any => {
if (token) {
- const segments = token.split(".");
+ const segments = token.split(".")
try {
- return JSON.parse(window.atob(segments[1]));
+ return JSON.parse(window.atob(segments[1]))
} catch {
- return undefined;
+ return undefined
}
}
},
-};
+}
diff --git a/public/services/markdown.spec.ts b/public/services/markdown.spec.ts
index 3f9e75b35..cb4cccb89 100644
--- a/public/services/markdown.spec.ts
+++ b/public/services/markdown.spec.ts
@@ -1,4 +1,4 @@
-import * as markdown from "./markdown";
+import * as markdown from "./markdown"
const testCases = [
{
@@ -50,18 +50,18 @@ How are you?`,
expectedFull: "-123 -456 -789
",
expectedSimple: "-123 -456 -789
",
},
-];
+]
testCases.forEach((x) => {
test(`Can parse markdown ${x.input} to ${x.expectedFull} (full mode)`, () => {
- const result = markdown.full(x.input);
- expect(result).toEqual(x.expectedFull);
- });
-});
+ const result = markdown.full(x.input)
+ expect(result).toEqual(x.expectedFull)
+ })
+})
testCases.forEach((x) => {
test(`Can parse markdown ${x.input} to ${x.expectedSimple} (simple mode)`, () => {
- const result = markdown.simple(x.input);
- expect(result).toEqual(x.expectedSimple);
- });
-});
+ const result = markdown.simple(x.input)
+ expect(result).toEqual(x.expectedSimple)
+ })
+})
diff --git a/public/services/markdown.ts b/public/services/markdown.ts
index 53221b91d..df45fbe4d 100644
--- a/public/services/markdown.ts
+++ b/public/services/markdown.ts
@@ -1,5 +1,5 @@
-import marked from "marked";
-import DOMPurify from "dompurify";
+import marked from "marked"
+import DOMPurify from "dompurify"
marked.setOptions({
headerIds: false,
@@ -7,7 +7,7 @@ marked.setOptions({
smartLists: true,
gfm: true,
breaks: true,
-});
+})
if (DOMPurify.isSupported) {
DOMPurify.setConfig({
@@ -15,34 +15,34 @@ if (DOMPurify.isSupported) {
html: true,
},
ADD_ATTR: ["target"],
- });
+ })
}
const link = (href: string, title: string, text: string) => {
- const titleAttr = title ? ` title=${title}` : "";
- return `${text} `;
-};
+ const titleAttr = title ? ` title=${title}` : ""
+ return `${text} `
+}
-const simpleRenderer = new marked.Renderer();
-simpleRenderer.heading = (text, level, raw) => `${raw}
`;
-simpleRenderer.image = (href, title, text) => "";
-simpleRenderer.link = link;
+const simpleRenderer = new marked.Renderer()
+simpleRenderer.heading = (_text, _level, raw) => `${raw}
`
+simpleRenderer.image = () => ""
+simpleRenderer.link = link
-const fullRenderer = new marked.Renderer();
-fullRenderer.link = link;
+const fullRenderer = new marked.Renderer()
+fullRenderer.link = link
const entities: { [key: string]: string } = {
"<": "<",
">": ">",
-};
+}
-const encodeHTML = (s: string) => s.replace(/[<>]/g, (tag) => entities[tag] || tag);
-const sanitize = (input: string) => (DOMPurify.isSupported ? DOMPurify.sanitize(input) : input);
+const encodeHTML = (s: string) => s.replace(/[<>]/g, (tag) => entities[tag] || tag)
+const sanitize = (input: string) => (DOMPurify.isSupported ? DOMPurify.sanitize(input) : input)
export const full = (input: string): string => {
- return sanitize(marked(encodeHTML(input), { renderer: fullRenderer }).trim());
-};
+ return sanitize(marked(encodeHTML(input), { renderer: fullRenderer }).trim())
+}
export const simple = (input: string): string => {
- return sanitize(marked(encodeHTML(input), { renderer: simpleRenderer }).trim());
-};
+ return sanitize(marked(encodeHTML(input), { renderer: simpleRenderer }).trim())
+}
diff --git a/public/services/navigator.ts b/public/services/navigator.ts
index 1981aaf51..09d866f07 100644
--- a/public/services/navigator.ts
+++ b/public/services/navigator.ts
@@ -1,24 +1,24 @@
-import { Fider } from "@fider/services";
+import { Fider } from "@fider/services"
const navigator = {
url: () => {
- return window.location.href;
+ return window.location.href
},
goHome: () => {
- window.location.href = "/";
+ window.location.href = "/"
},
goTo: (url: string) => {
- const isEqual = window.location.href === url || window.location.pathname === url;
+ const isEqual = window.location.href === url || window.location.pathname === url
if (!isEqual) {
- window.location.href = url;
+ window.location.href = url
}
},
replaceState: (path: string): void => {
if (history.replaceState !== undefined) {
- const newURL = Fider.settings.baseURL + path;
- window.history.replaceState({ path: newURL }, "", newURL);
+ const newURL = Fider.settings.baseURL + path
+ window.history.replaceState({ path: newURL }, "", newURL)
}
},
-};
+}
-export default navigator;
+export default navigator
diff --git a/public/services/notify.ts b/public/services/notify.ts
index 1764f056f..ad664c83e 100644
--- a/public/services/notify.ts
+++ b/public/services/notify.ts
@@ -1,13 +1,13 @@
-const toastify = () => import(/* webpackChunkName: "toastify" */ "./toastify");
+const toastify = () => import(/* webpackChunkName: "toastify" */ "./toastify")
export const success = (content: string | JSX.Element) => {
return toastify().then((toast) => {
- toast.success(content);
- });
-};
+ toast.success(content)
+ })
+}
export const error = (content: string | JSX.Element) => {
return toastify().then((toast) => {
- toast.error(content);
- });
-};
+ toast.error(content)
+ })
+}
diff --git a/public/services/querystring.spec.ts b/public/services/querystring.spec.ts
index ed2a16d84..9533a4efc 100644
--- a/public/services/querystring.spec.ts
+++ b/public/services/querystring.spec.ts
@@ -1,57 +1,52 @@
-import * as qs from "./querystring";
-import navigator from "./navigator";
-
-[
+import * as qs from "./querystring"
+import navigator from "./navigator"
+;[
{ qs: "?name=John&age=30", name: "name", expected: "John" },
{ qs: "?name=John&age=30", name: "age", expected: "30" },
{ qs: "?name=", name: "name", expected: "" },
{ qs: "", name: "name", expected: "" },
].forEach((x) => {
test(`get('${x.name}') should be ${x.expected}`, () => {
- navigator.url = () => `http://example.com${x.qs}`;
- const result = qs.get(x.name);
- expect(result).toEqual(x.expected);
- });
-});
-
-[
+ navigator.url = () => `http://example.com${x.qs}`
+ const result = qs.get(x.name)
+ expect(result).toEqual(x.expected)
+ })
+})
+;[
{ qs: "?name=John,Arya&age=30", name: "name", expected: ["John", "Arya"] },
{ qs: "?name=John&age=30", name: "age", expected: ["30"] },
{ qs: "?name=", name: "name", expected: [] },
{ qs: "", name: "name", expected: [] },
].forEach((x) => {
test(`getArray('${x.name}') should be ${x.expected}`, () => {
- navigator.url = () => `http://example.com${x.qs}`;
- const result = qs.getArray(x.name);
- expect(result).toEqual(x.expected);
- });
-});
-
-[
+ navigator.url = () => `http://example.com${x.qs}`
+ const result = qs.getArray(x.name)
+ expect(result).toEqual(x.expected)
+ })
+})
+;[
{ qs: "?name=John&age=30", name: "age", expected: 30 },
{ qs: "?name=", name: "name", expected: undefined },
{ qs: "", name: "name", expected: undefined },
].forEach((x) => {
test(`getNumber('${x.name}') should be ${x.expected}`, () => {
- navigator.url = () => `http://example.com${x.qs}`;
- const result = qs.getNumber(x.name);
- expect(result).toEqual(x.expected);
- });
-});
-
-[
+ navigator.url = () => `http://example.com${x.qs}`
+ const result = qs.getNumber(x.name)
+ expect(result).toEqual(x.expected)
+ })
+})
+;[
{ qs: "?name=John&age=30", name: "age", value: 60, expected: "http://example.com?name=John&age=60" },
{ qs: "", name: "age", value: 50, expected: "http://example.com?age=50" },
{ qs: "?age=2", name: "age", value: 21, expected: "http://example.com?age=21" },
].forEach((x) => {
test(`set(${x.name}, ${x.value}) should return ${x.expected}`, () => {
- navigator.url = () => `http://example.com${x.qs}`;
- const newQueryString = qs.set(x.name, x.value);
- expect(newQueryString).toEqual(x.expected);
- });
-});
-
-[
+ navigator.url = () => `http://example.com${x.qs}`
+ const newQueryString = qs.set(x.name, x.value)
+ expect(newQueryString).toEqual(x.expected)
+ })
+})
+;[
{ object: {}, expected: "" },
{ object: undefined, expected: "" },
{
@@ -76,7 +71,7 @@ import navigator from "./navigator";
},
].forEach((x) => {
test(`stringfy('${x.object}') should be ${x.expected}`, () => {
- const result = qs.stringify(x.object);
- expect(result).toEqual(x.expected);
- });
-});
+ const result = qs.stringify(x.object)
+ expect(result).toEqual(x.expected)
+ })
+})
diff --git a/public/services/querystring.ts b/public/services/querystring.ts
index 8e47bb0c3..9b29fe959 100644
--- a/public/services/querystring.ts
+++ b/public/services/querystring.ts
@@ -1,63 +1,63 @@
-import navigator from "./navigator";
+import navigator from "./navigator"
export const getNumber = (name: string): number | undefined => {
- return parseInt(get(name), 10) || undefined;
-};
+ return parseInt(get(name), 10) || undefined
+}
export const set = (name: string, value: any): string => {
- const uri = navigator.url();
- const re = new RegExp("([?&])" + name + "=.*?(&|$)", "i");
+ const uri = navigator.url()
+ const re = new RegExp("([?&])" + name + "=.*?(&|$)", "i")
if (uri.match(re)) {
- return uri.replace(re, "$1" + name + "=" + value + "$2");
+ return uri.replace(re, "$1" + name + "=" + value + "$2")
} else {
- const separator = uri.indexOf("?") !== -1 ? "&" : "?";
- return uri + separator + name + "=" + value;
+ const separator = uri.indexOf("?") !== -1 ? "&" : "?"
+ return uri + separator + name + "=" + value
}
-};
+}
export const get = (name: string): string => {
- name = name.replace(/[\[\]]/g, "\\$&");
- const regex = new RegExp("[?&]" + name + "(=([^]*)|&|#|$)");
- const results = regex.exec(navigator.url());
+ name = name.replace(/[[\]]/g, "\\$&")
+ const regex = new RegExp("[?&]" + name + "(=([^]*)|&|#|$)")
+ const results = regex.exec(navigator.url())
if (!results || !results[2]) {
- return "";
+ return ""
}
- return decodeURIComponent(results[2].replace(/\+/g, " "));
-};
+ return decodeURIComponent(results[2].replace(/\+/g, " "))
+}
export const getArray = (name: string): string[] => {
- const qs = get(name);
+ const qs = get(name)
if (qs) {
- return qs.split(",").filter((i) => i);
+ return qs.split(",").filter((i) => i)
}
- return [];
-};
+ return []
+}
export interface QueryString {
- [key: string]: string | string[] | number | undefined;
+ [key: string]: string | string[] | number | undefined
}
export const stringify = (object: QueryString | undefined): string => {
if (!object) {
- return "";
+ return ""
}
- let qs = "";
+ let qs = ""
for (const key of Object.keys(object)) {
- const symbol = qs ? "&" : "?";
- const value = object[key];
+ const symbol = qs ? "&" : "?"
+ const value = object[key]
if (value instanceof Array) {
if (value.length > 0) {
- qs += `${symbol}${key}=${value.join(",")}`;
+ qs += `${symbol}${key}=${value.join(",")}`
}
} else if (value) {
- qs += `${symbol}${key}=${encodeURIComponent(value.toString()).replace(/%20/g, "+")}`;
+ qs += `${symbol}${key}=${encodeURIComponent(value.toString()).replace(/%20/g, "+")}`
}
}
- return qs;
-};
+ return qs
+}
diff --git a/public/services/testing/fider.ts b/public/services/testing/fider.ts
index f673d4c41..0a19ed439 100644
--- a/public/services/testing/fider.ts
+++ b/public/services/testing/fider.ts
@@ -1,20 +1,20 @@
-import { Fider } from "@fider/services";
+import { Fider } from "@fider/services"
export const fiderMock = {
notAuthenticated: () => {
- Fider.initialize();
+ Fider.initialize()
Object.defineProperty(Fider.session, "isAuthenticated", {
get() {
- return false;
+ return false
},
- });
+ })
},
authenticated: () => {
- Fider.initialize();
+ Fider.initialize()
Object.defineProperty(Fider.session, "isAuthenticated", {
get() {
- return true;
+ return true
},
- });
+ })
},
-};
+}
diff --git a/public/services/testing/http.ts b/public/services/testing/http.ts
index 3900858f8..4864cd530 100644
--- a/public/services/testing/http.ts
+++ b/public/services/testing/http.ts
@@ -1,4 +1,4 @@
-import { http } from "@fider/services";
+import { http } from "@fider/services"
export const httpMock = {
alwaysOk: () => {
@@ -6,12 +6,12 @@ export const httpMock = {
return Promise.resolve({
ok: true,
data: null as any,
- });
- });
- http.get = fn;
- http.post = fn;
- http.put = fn;
- http.delete = fn;
- return http;
+ })
+ })
+ http.get = fn
+ http.post = fn
+ http.put = fn
+ http.delete = fn
+ return http
},
-};
+}
diff --git a/public/services/testing/index.ts b/public/services/testing/index.ts
index 8b9541759..f88cd9230 100644
--- a/public/services/testing/index.ts
+++ b/public/services/testing/index.ts
@@ -1,3 +1,3 @@
-export * from "./http";
-export * from "./fider";
-export * from "./react";
+export * from "./http"
+export * from "./fider"
+export * from "./react"
diff --git a/public/services/testing/react.ts b/public/services/testing/react.ts
index 083413bb2..348275eb4 100644
--- a/public/services/testing/react.ts
+++ b/public/services/testing/react.ts
@@ -1,8 +1,8 @@
-import { ShallowWrapper } from "enzyme";
+import { ShallowWrapper } from "enzyme"
-const flushPromises = () => new Promise((resolve) => setImmediate(resolve));
+const flushPromises = () => new Promise((resolve) => setImmediate(resolve))
export const rerender = async (component: ShallowWrapper) => {
- await flushPromises();
- return component.update();
-};
+ await flushPromises()
+ return component.update()
+}
diff --git a/public/services/toastify.tsx b/public/services/toastify.tsx
index 07dd24113..c2962b015 100644
--- a/public/services/toastify.tsx
+++ b/public/services/toastify.tsx
@@ -1,24 +1,24 @@
-import React from "react";
-import ReactDOM from "react-dom";
+import React from "react"
+import ReactDOM from "react-dom"
-import { ToastContainer, toast, ToastContent, ToastOptions } from "react-toastify";
-import "react-toastify/dist/ReactToastify.css";
+import { ToastContainer, toast, ToastContent, ToastOptions } from "react-toastify"
+import "react-toastify/dist/ReactToastify.css"
-let hasContainer = false;
+let hasContainer = false
const setup = () => {
if (!hasContainer) {
- hasContainer = true;
- ReactDOM.render( , document.getElementById("root-toastify"));
+ hasContainer = true
+ ReactDOM.render( , document.getElementById("root-toastify"))
}
-};
+}
export const success = (content: ToastContent, options?: ToastOptions) => {
- setup();
- toast.success(content, options);
-};
+ setup()
+ toast.success(content, options)
+}
export const error = (content: ToastContent, options?: ToastOptions) => {
- setup();
- toast.error(content, options);
-};
+ setup()
+ toast.error(content, options)
+}
diff --git a/public/services/utils.spec.ts b/public/services/utils.spec.ts
index dd5fe6d58..651f4604c 100644
--- a/public/services/utils.spec.ts
+++ b/public/services/utils.spec.ts
@@ -1,7 +1,6 @@
-import { classSet, formatDate, timeSince, fileToBase64 } from "./utils";
-import { readFileSync } from "fs";
-
-[
+import { classSet, formatDate, timeSince, fileToBase64 } from "./utils"
+import { readFileSync } from "fs"
+;[
{ input: null, expected: "" },
{ input: undefined, expected: "" },
{ input: {}, expected: "" },
@@ -14,43 +13,40 @@ import { readFileSync } from "fs";
{
input: {
green: () => {
- throw Error();
+ throw Error()
},
},
expected: "green",
},
].forEach((x) => {
test(`classSet of ${JSON.stringify(x.input)} should be ${x.expected}`, () => {
- const className = classSet(x.input);
- expect(className).toEqual(x.expected);
- });
-});
-
-[
+ const className = classSet(x.input)
+ expect(className).toEqual(x.expected)
+ })
+})
+;[
{ input: new Date(2018, 4, 27, 10, 12, 59), expected: "May 27, 2018 · 10:12" },
{ input: new Date(2058, 12, 12, 23, 21, 53), expected: "January 12, 2059 · 23:21" },
{ input: "2018-04-11T18:13:33.128082", expected: "April 11, 2018 · 18:13" },
{ input: "2017-11-20T07:47:42.158142", expected: "November 20, 2017 · 07:47" },
].forEach((x) => {
test(`formatDate (full) of ${x.input} should be ${x.expected}`, () => {
- const result = formatDate(x.input, "full");
- expect(result).toEqual(x.expected);
- });
-});
-
-[
+ const result = formatDate(x.input, "full")
+ expect(result).toEqual(x.expected)
+ })
+})
+;[
{ input: new Date(2018, 4, 27, 10, 12, 59), expected: "May 2018" },
{ input: new Date(2058, 12, 12, 23, 21, 53), expected: "Jan 2059" },
{ input: "2018-04-11T18:13:33.128082", expected: "Apr 2018" },
{ input: "2017-11-20T07:47:42.158142", expected: "Nov 2017" },
].forEach((x) => {
test(`formatDate (short) of ${x.input} should be ${x.expected}`, () => {
- const result = formatDate(x.input, "short");
- expect(result).toEqual(x.expected);
- });
-});
-
-[
+ const result = formatDate(x.input, "short")
+ expect(result).toEqual(x.expected)
+ })
+})
+;[
{ input: new Date(2018, 4, 27, 19, 51, 9), expected: "less than a minute ago" },
{ input: new Date(2018, 4, 27, 10, 12, 59), expected: "about 10 hours ago" },
{ input: new Date(2018, 4, 26, 10, 12, 59), expected: "a day ago" },
@@ -61,13 +57,12 @@ import { readFileSync } from "fs";
{ input: new Date(2013, 3, 22, 10, 12, 59), expected: "5 years ago" },
].forEach((x) => {
test(`timeSince ${x.input} should be ${x.expected}`, () => {
- const now = new Date(2018, 4, 27, 19, 51, 10);
- const result = timeSince(now, x.input);
- expect(result).toEqual(x.expected);
- });
-});
-
-[
+ const now = new Date(2018, 4, 27, 19, 51, 10)
+ const result = timeSince(now, x.input)
+ expect(result).toEqual(x.expected)
+ })
+})
+;[
{ input: new Date(2018, 4, 27, 19, 51, 9), expected: "less than a minute ago" },
{ input: new Date(2018, 4, 27, 10, 12, 59), expected: "about 10 hours ago" },
{ input: new Date(2018, 4, 26, 10, 12, 59), expected: "a day ago" },
@@ -78,15 +73,15 @@ import { readFileSync } from "fs";
{ input: new Date(2013, 3, 22, 10, 12, 59), expected: "5 years ago" },
].forEach((x) => {
test(`timeSince ${x.input} should be ${x.expected}`, () => {
- const now = new Date(2018, 4, 27, 19, 51, 10);
- const result = timeSince(now, x.input);
- expect(result).toEqual(x.expected);
- });
-});
+ const now = new Date(2018, 4, 27, 19, 51, 10)
+ const result = timeSince(now, x.input)
+ expect(result).toEqual(x.expected)
+ })
+})
test("Can convert file to base64", async () => {
- const content = readFileSync("./favicon.png");
- const favicon = new File([content], "favicon.png");
- const base64 = await fileToBase64(favicon);
- expect(base64).toBe(Buffer.from(content).toString("base64"));
-});
+ const content = readFileSync("./favicon.png")
+ const favicon = new File([content], "favicon.png")
+ const base64 = await fileToBase64(favicon)
+ expect(base64).toBe(Buffer.from(content).toString("base64"))
+})
diff --git a/public/services/utils.ts b/public/services/utils.ts
index 743d172f6..b38b064fb 100644
--- a/public/services/utils.ts
+++ b/public/services/utils.ts
@@ -1,56 +1,56 @@
-import { Fider } from ".";
+import { Fider } from "."
export const delay = (ms: number) => {
- return new Promise((resolve) => setTimeout(resolve, ms));
-};
+ return new Promise((resolve) => setTimeout(resolve, ms))
+}
export const classSet = (input?: any): string => {
- let classes = "";
+ let classes = ""
if (input) {
for (const key in input) {
if (key && !!input[key]) {
- classes += ` ${key}`;
+ classes += ` ${key}`
}
}
- return classes.trim();
+ return classes.trim()
}
- return "";
-};
+ return ""
+}
-const monthNames = ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"];
+const monthNames = ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"]
export const currencySymbol = (currencyCode: string): string => {
- currencyCode = currencyCode ? currencyCode.toLowerCase() : "";
+ currencyCode = currencyCode ? currencyCode.toLowerCase() : ""
switch (currencyCode) {
case "eur":
- return "€";
+ return "€"
case "usd":
- return "$";
+ return "$"
}
- throw new Error(`Invalid currency code '${currencyCode}'`);
-};
+ throw new Error(`Invalid currency code '${currencyCode}'`)
+}
const twoDigits = (value: number): string => {
- return value <= 9 ? `0${value}` : value.toString();
-};
+ return value <= 9 ? `0${value}` : value.toString()
+}
-type DateFormat = "full" | "short";
+type DateFormat = "full" | "short"
export const formatDate = (input: Date | string, format: DateFormat = "full"): string => {
- const date = input instanceof Date ? input : new Date(input);
+ const date = input instanceof Date ? input : new Date(input)
- const monthIndex = date.getMonth();
- const year = date.getFullYear();
+ const monthIndex = date.getMonth()
+ const year = date.getFullYear()
if (format === "short") {
- return `${monthNames[monthIndex].substring(0, 3)} ${year}`;
+ return `${monthNames[monthIndex].substring(0, 3)} ${year}`
}
- const day = date.getDate();
- const hours = twoDigits(date.getHours());
- const minutes = twoDigits(date.getMinutes());
- return `${monthNames[monthIndex]} ${day}, ${year} · ${hours}:${minutes}`;
-};
+ const day = date.getDate()
+ const hours = twoDigits(date.getHours())
+ const minutes = twoDigits(date.getMinutes())
+ return `${monthNames[monthIndex]} ${day}, ${year} · ${hours}:${minutes}`
+}
const templates: { [key: string]: string } = {
seconds: "less than a minute",
@@ -64,18 +64,18 @@ const templates: { [key: string]: string } = {
months: "%d months",
year: "about a year",
years: "%d years",
-};
+}
const template = (t: string, n: number): string => {
- return templates[t] && templates[t].replace(/%d/i, Math.abs(Math.round(n)).toString());
-};
+ return templates[t] && templates[t].replace(/%d/i, Math.abs(Math.round(n)).toString())
+}
export const timeSince = (now: Date, date: Date): string => {
- const seconds = (now.getTime() - date.getTime()) / 1000;
- const minutes = seconds / 60;
- const hours = minutes / 60;
- const days = hours / 24;
- const years = days / 365;
+ const seconds = (now.getTime() - date.getTime()) / 1000
+ const minutes = seconds / 60
+ const hours = minutes / 60
+ const days = hours / 24
+ const years = days / 365
return (
((seconds < 45 && template("seconds", seconds)) ||
@@ -89,57 +89,57 @@ export const timeSince = (now: Date, date: Date): string => {
(days < 365 && template("months", days / 30)) ||
(years < 1.5 && template("year", 1)) ||
template("years", years)) + " ago"
- );
-};
+ )
+}
export const fileToBase64 = async (file: File): Promise => {
return new Promise((resolve, reject) => {
- const reader = new FileReader();
+ const reader = new FileReader()
reader.addEventListener(
"load",
() => {
- const parts = (reader.result as string).split("base64,");
- resolve(parts[1]);
+ const parts = (reader.result as string).split("base64,")
+ resolve(parts[1])
},
false
- );
+ )
reader.addEventListener(
"error",
() => {
- reject(reader.error);
+ reject(reader.error)
},
false
- );
+ )
- reader.readAsDataURL(file);
- });
-};
+ reader.readAsDataURL(file)
+ })
+}
export const isCookieEnabled = (): boolean => {
try {
- document.cookie = "cookietest=1";
- const ret = document.cookie.indexOf("cookietest=") !== -1;
- document.cookie = "cookietest=1; expires=Thu, 01-Jan-1970 00:00:01 GMT";
- return ret;
+ document.cookie = "cookietest=1"
+ const ret = document.cookie.indexOf("cookietest=") !== -1
+ document.cookie = "cookietest=1; expires=Thu, 01-Jan-1970 00:00:01 GMT"
+ return ret
} catch (e) {
- return false;
+ return false
}
-};
+}
export const uploadedImageURL = (bkey: string | undefined, size?: number): string | undefined => {
if (bkey) {
if (size) {
- return `${Fider.settings.tenantAssetsURL}/images/${bkey}?size=${size}`;
+ return `${Fider.settings.tenantAssetsURL}/images/${bkey}?size=${size}`
}
- return `${Fider.settings.tenantAssetsURL}/images/${bkey}`;
+ return `${Fider.settings.tenantAssetsURL}/images/${bkey}`
}
- return undefined;
-};
+ return undefined
+}
export const truncate = (input: string, maxLength: number): string => {
if (input && input.length > 1000) {
- return `${input.substr(0, maxLength)}...`;
+ return `${input.substr(0, maxLength)}...`
}
- return input;
-};
+ return input
+}
diff --git a/public/ssr.tsx b/public/ssr.tsx
index 560bfc756..0b26f3bde 100644
--- a/public/ssr.tsx
+++ b/public/ssr.tsx
@@ -1,24 +1,30 @@
-import React from "react";
-import { renderToStaticMarkup } from "react-dom/server";
-import { Fider, FiderContext } from "./services/fider";
-import { IconContext } from "react-icons";
-import { Footer, Header } from "./components";
-import { resolveRootComponent, route } from "./router";
+import React from "react"
+import { renderToStaticMarkup } from "react-dom/server"
+import { Fider, FiderContext } from "./services/fider"
+import { IconContext } from "react-icons"
+import { Footer, Header } from "./components"
+import { resolveRootComponent, route } from "./router"
-import HomePage from "./pages/Home/Home.page";
-import ShowPostPage from "./pages/ShowPost/ShowPost.page";
-import SignInPage from "./pages/SignIn/SignIn.page";
-import SignUpPage from "./pages/SignUp/SignUp.page";
-import UIToolkitPage from "./pages/UI/UIToolkit.page";
+import HomePage from "./pages/Home/Home.page"
+import ShowPostPage from "./pages/ShowPost/ShowPost.page"
+import SignInPage from "./pages/SignIn/SignIn.page"
+import SignUpPage from "./pages/SignUp/SignUp.page"
+import UIToolkitPage from "./pages/UI/UIToolkit.page"
// Only public routes should be here
// Routes behind authentication are not crawled
-const routes = [route("", HomePage), route("/posts/:number*", ShowPostPage), route("/signin", SignInPage, false), route("/signup", SignUpPage, false), route("/-/ui", UIToolkitPage)];
+const routes = [
+ route("", HomePage),
+ route("/posts/:number*", ShowPostPage),
+ route("/signin", SignInPage, false),
+ route("/signup", SignUpPage, false),
+ route("/-/ui", UIToolkitPage),
+]
function ssrRender(url: string, pathname: string, args: any) {
- const fider = Fider.initialize({ ...args });
- const config = resolveRootComponent(pathname, routes);
- window.location.href = url;
+ const fider = Fider.initialize({ ...args })
+ const config = resolveRootComponent(pathname, routes)
+ window.location.href = url
return renderToStaticMarkup(
@@ -28,7 +34,7 @@ function ssrRender(url: string, pathname: string, args: any) {
{config.showHeader && }
- );
+ )
}
-(globalThis as any).ssrRender = ssrRender;
+;(globalThis as any).ssrRender = ssrRender
diff --git a/public/tsd.d.ts b/public/tsd.d.ts
index 4d98c8a33..e7a01d5b1 100644
--- a/public/tsd.d.ts
+++ b/public/tsd.d.ts
@@ -1,13 +1,11 @@
-import { CurrentUser, SystemSettings, Tenant } from "@fider/models";
+export {}
declare global {
interface Window {
- ga?: (cmd: string, evt: string, args?: any) => void;
- set: (key: string, value: any) => void;
+ ga?: (cmd: string, evt: string, args?: any) => void
+ set: (key: string, value: any) => void
}
- var __webpack_nonce__: string; // tslint:disable-line
- var __webpack_public_path__: string; // tslint:disable-line
+ let __webpack_nonce__: string
+ let __webpack_public_path__: string
}
-
-declare var require: (id: string) => any;
diff --git a/tests/lib/browser.ts b/tests/lib/browser.ts
index 2ee3e6819..9b742802f 100644
--- a/tests/lib/browser.ts
+++ b/tests/lib/browser.ts
@@ -1,11 +1,11 @@
-import puppeteer from "puppeteer";
-import { BrowserTab } from ".";
+import puppeteer from "puppeteer"
+import { BrowserTab } from "."
export class Browser {
- private browser: puppeteer.Browser;
+ private browser: puppeteer.Browser
public constructor(browser: puppeteer.Browser) {
- this.browser = browser;
+ this.browser = browser
}
public static async launch(): Promise {
@@ -13,16 +13,16 @@ export class Browser {
headless: true,
devtools: false,
ignoreHTTPSErrors: true,
- });
- return new Browser(browser);
+ })
+ return new Browser(browser)
}
public async newTab(baseURL: string): Promise {
- const page = await this.browser.newPage();
- return new BrowserTab(page, baseURL);
+ const page = await this.browser.newPage()
+ return new BrowserTab(page, baseURL)
}
public async close(): Promise {
- await this.browser.close();
+ await this.browser.close()
}
}
diff --git a/tests/lib/components.ts b/tests/lib/components.ts
index 198343493..20eb0fdbb 100644
--- a/tests/lib/components.ts
+++ b/tests/lib/components.ts
@@ -1,92 +1,92 @@
-import { elementIsVisible, BrowserTab } from ".";
+import { elementIsVisible, BrowserTab } from "."
export class WebComponent {
constructor(protected tab: BrowserTab, public selector: string) {}
public async click() {
- await this.tab.click(this.selector);
+ await this.tab.click(this.selector)
}
public async getText(): Promise {
return await this.tab.evaluate(
(selector: string) => {
- const el = document.querySelector(selector) as HTMLElement | undefined;
- return el ? el.textContent : "";
+ const el = document.querySelector(selector) as HTMLElement | undefined
+ return el ? el.textContent : ""
},
[this.selector]
- );
+ )
}
public async getAttribute(attributeName: string): Promise {
return await this.tab.evaluate(
(selector: string, attrName: string) => {
- const el = document.querySelector(selector) as HTMLElement | undefined;
- return el ? el.getAttribute(attrName) || "" : "";
+ const el = document.querySelector(selector) as HTMLElement | undefined
+ return el ? el.getAttribute(attrName) || "" : ""
},
[this.selector, attributeName]
- );
+ )
}
public async isVisible(): Promise {
- const condition = elementIsVisible(this.selector);
- const instance = condition(this.tab);
- return this.tab.evaluate(instance.function, instance.args);
+ const condition = elementIsVisible(this.selector)
+ const instance = condition(this.tab)
+ return this.tab.evaluate(instance.function, instance.args)
}
}
export class Button extends WebComponent {
constructor(protected tab: BrowserTab, selector: string) {
- super(tab, selector);
+ super(tab, selector)
}
}
export class DropDownList extends WebComponent {
constructor(protected tab: BrowserTab, selector: string) {
- super(tab, selector);
+ super(tab, selector)
}
public async selectByText(text: string): Promise {
const value = await this.tab.evaluate(
(selector: string, textToSelect: string) => {
- const options = document.querySelectorAll(`${selector} option`);
+ const options = document.querySelectorAll(`${selector} option`)
for (let i = 0; i <= options.length; i++) {
if (options[i] && options[i].textContent === textToSelect) {
- return (options[i] as HTMLOptionElement).value;
+ return (options[i] as HTMLOptionElement).value
}
}
- return "";
+ return ""
},
[this.selector, text]
- );
- await this.tab.select(this.selector, value);
+ )
+ await this.tab.select(this.selector, value)
}
}
export abstract class List {
constructor(protected tab: BrowserTab, public selector: string) {}
- public abstract count(): Promise;
+ public abstract count(): Promise
}
export class TextInput extends WebComponent {
constructor(protected tab: BrowserTab, selector: string) {
- super(tab, selector);
+ super(tab, selector)
}
public async type(text: string) {
- await this.tab.type(this.selector, text);
- const current = await this.getText();
+ await this.tab.type(this.selector, text)
+ const current = await this.getText()
if (current !== text) {
- await this.clear();
- await this.type(text);
+ await this.clear()
+ await this.type(text)
}
}
public async getText(): Promise {
- return await this.tab.evaluate((selector: string) => (document.querySelector(selector) as HTMLInputElement).value, [this.selector]);
+ return await this.tab.evaluate((selector: string) => (document.querySelector(selector) as HTMLInputElement).value, [this.selector])
}
public async clear() {
- await this.tab.click(this.selector, { clickCount: 3 });
- await this.tab.press("Backspace");
+ await this.tab.click(this.selector, { clickCount: 3 })
+ await this.tab.press("Backspace")
}
}
diff --git a/tests/lib/conditions.ts b/tests/lib/conditions.ts
index 22085a340..9029f98a6 100644
--- a/tests/lib/conditions.ts
+++ b/tests/lib/conditions.ts
@@ -1,48 +1,48 @@
-import { NewablePage, Page, BrowserTab, WebComponent } from ".";
+import { NewablePage, Page, BrowserTab, WebComponent } from "."
export type WaitCondition = (
browser: BrowserTab
) => {
- function: (...args: any[]) => boolean;
- args: any[];
-};
+ function: (...args: any[]) => boolean
+ args: any[]
+}
export const elementIsVisible = (target: string | WebComponent): WaitCondition => {
- return (tab: BrowserTab) => {
- const selector = typeof target === "string" ? target : target.selector;
+ return () => {
+ const selector = typeof target === "string" ? target : target.selector
return {
function: (query: string) => {
- const node = document.querySelector(query);
+ const node = document.querySelector(query)
if (!node) {
- return false;
+ return false
}
- const style = window.getComputedStyle(node);
- return style && style.display !== "none" && style.visibility !== "hidden" && style.opacity !== "0";
+ const style = window.getComputedStyle(node)
+ return style && style.display !== "none" && style.visibility !== "hidden" && style.opacity !== "0"
},
args: [selector],
- };
- };
-};
+ }
+ }
+}
export const elementIsNotVisible = (target: string | WebComponent): WaitCondition => {
- return (tab: BrowserTab) => {
- const selector = typeof target === "string" ? target : target.selector;
+ return () => {
+ const selector = typeof target === "string" ? target : target.selector
return {
function: (query: string) => {
- const node = document.querySelector(query);
+ const node = document.querySelector(query)
if (!node) {
- return true;
+ return true
}
- const style = window.getComputedStyle(node);
- return style && (style.display === "none" || style.visibility === "hidden" || style.opacity === "0");
+ const style = window.getComputedStyle(node)
+ return style && (style.display === "none" || style.visibility === "hidden" || style.opacity === "0")
},
args: [selector],
- };
- };
-};
+ }
+ }
+}
export function pageHasLoaded(page: NewablePage): WaitCondition {
return (tab: BrowserTab) => {
- return new page(tab).loadCondition()(tab);
- };
+ return new page(tab).loadCondition()(tab)
+ }
}
diff --git a/tests/lib/ensure.ts b/tests/lib/ensure.ts
index c855b44d4..4520746ae 100644
--- a/tests/lib/ensure.ts
+++ b/tests/lib/ensure.ts
@@ -1,41 +1,41 @@
-import { WebComponent, Button, TextInput, delay, List } from ".";
+import { WebComponent, Button, TextInput, delay, List } from "."
const retry = async (fn: () => Promise) => {
- let count = 0;
- let lastErr: Error;
+ let count = 0
+ let lastErr: Error
do {
try {
- return await fn();
+ return await fn()
} catch (err) {
- lastErr = err;
- await delay(500);
- count++;
+ lastErr = err
+ await delay(500)
+ count++
}
- } while (count !== 3);
- throw lastErr;
-};
+ } while (count !== 3)
+ throw lastErr
+}
class WebComponentEnsurer {
constructor(protected component: WebComponent) {}
public async textIs(expected: string) {
await retry(async () => {
- const text = await this.component.getText();
+ const text = await this.component.getText()
if (expected.trim() !== text.trim()) {
- throw new Error(`Element ${this.component.selector} text is '${text}'. Expected value is '${expected}'`);
+ throw new Error(`Element ${this.component.selector} text is '${text}'. Expected value is '${expected}'`)
}
- });
+ })
}
public async attributeIs(attrName: string, expected: string) {
await retry(async () => {
- const attrValue = await this.component.getAttribute(attrName);
+ const attrValue = await this.component.getAttribute(attrName)
if (expected.trim() !== attrValue.trim()) {
- throw new Error(`Element ${this.component.selector} ${attrName} is '${attrValue}'. Expected value is '${expected}'`);
+ throw new Error(`Element ${this.component.selector} ${attrName} is '${attrValue}'. Expected value is '${expected}'`)
}
- });
+ })
}
// public async attributeIs(attrName: string, expected: string) {
@@ -69,7 +69,7 @@ class WebComponentEnsurer {
class ButtonEnsurer extends WebComponentEnsurer {
constructor(protected button: Button) {
- super(button);
+ super(button)
}
// public async isNotDisabled() {
@@ -86,31 +86,31 @@ class ListEnsurer {
public async countIs(expected: number) {
await retry(async () => {
- const count = await this.list.count();
+ const count = await this.list.count()
if (count !== expected) {
- throw new Error(`Count of ${this.list.selector} is ${count}, expected ${expected}`);
+ throw new Error(`Count of ${this.list.selector} is ${count}, expected ${expected}`)
}
- });
+ })
}
}
class TextInputEnsurer extends WebComponentEnsurer {
constructor(component: TextInput) {
- super(component);
+ super(component)
}
}
-export function ensure(component: Button): ButtonEnsurer;
-export function ensure(component: TextInput): TextInputEnsurer;
-export function ensure(component: WebComponent): WebComponentEnsurer;
-export function ensure(component: List): ListEnsurer;
-export function ensure(component: WebComponent): WebComponentEnsurer;
+export function ensure(component: Button): ButtonEnsurer
+export function ensure(component: TextInput): TextInputEnsurer
+export function ensure(component: WebComponent): WebComponentEnsurer
+export function ensure(component: List): ListEnsurer
+export function ensure(component: WebComponent): WebComponentEnsurer
export function ensure(component: WebComponent | List | Button): any {
if (component instanceof Button) {
- return new ButtonEnsurer(component);
+ return new ButtonEnsurer(component)
} else if (component instanceof List) {
- return new ListEnsurer(component);
+ return new ListEnsurer(component)
} else if (component instanceof WebComponent) {
- return new WebComponentEnsurer(component);
+ return new WebComponentEnsurer(component)
}
}
diff --git a/tests/lib/index.ts b/tests/lib/index.ts
index 05a6a3f0a..5ee20db5e 100644
--- a/tests/lib/index.ts
+++ b/tests/lib/index.ts
@@ -1,8 +1,8 @@
-export * from "./conditions";
-export * from "./components";
-export * from "./utils";
-export * from "./browser";
-export * from "./page";
-export * from "./tab";
-export * from "./mailgun";
-export * from "./ensure";
+export * from "./conditions"
+export * from "./components"
+export * from "./utils"
+export * from "./browser"
+export * from "./page"
+export * from "./tab"
+export * from "./mailgun"
+export * from "./ensure"
diff --git a/tests/lib/mailgun.ts b/tests/lib/mailgun.ts
index 5de0a441c..9848ace37 100644
--- a/tests/lib/mailgun.ts
+++ b/tests/lib/mailgun.ts
@@ -1,59 +1,61 @@
-require("dotenv").config();
-import { parse as parseURL } from "url";
-import * as http from "http";
-import * as https from "https";
-import { delay } from "./";
+import dotenv from "dotenv"
+dotenv.config()
+
+import { parse as parseURL } from "url"
+import * as http from "http"
+import * as https from "https"
+import { delay } from "./"
const httpGet = (endpoint: string): Promise => {
- const url = parseURL(endpoint);
- return new Promise((resolve, reject) => {
+ const url = parseURL(endpoint)
+ return new Promise((resolve) => {
const opts = {
host: url.host,
port: 443,
method: "GET",
auth: `api:${process.env.EMAIL_MAILGUN_API}`,
path: url.path,
- };
+ }
https.get(opts, (res: http.IncomingMessage) => {
- const content: any[] = [];
- res.on("data", (chunk) => content.push(chunk));
- res.on("end", () => resolve(JSON.parse(content.join(""))));
- });
- });
-};
+ const content: any[] = []
+ res.on("data", (chunk) => content.push(chunk))
+ res.on("end", () => resolve(JSON.parse(content.join(""))))
+ })
+ })
+}
export const mailgun = {
getLinkFromLastEmailTo: async (tenant: string, subject: string, to: string): Promise => {
- let messageURL = "";
- let count = 0;
+ let messageURL = ""
+ let count = 0
do {
- count++;
+ count++
- let url = `https://api.mailgun.net/v3/${process.env.EMAIL_MAILGUN_DOMAIN}/events?to=${to}&subject=${subject}&event=accepted&limit=1&ascending=no`;
+ let url = `https://api.mailgun.net/v3/${process.env.EMAIL_MAILGUN_DOMAIN}/events?to=${to}&subject=${subject}&event=accepted&limit=1&ascending=no`
if (tenant !== "login") {
- url += `&tags=tenant:${tenant}`;
+ url += `&tags=tenant:${tenant}`
}
- const events = await httpGet(url);
+ const events = await httpGet(url)
if (events.items.length > 0 && events.items[0].recipient === to) {
- messageURL = events.items[0].storage.url;
+ messageURL = events.items[0].storage.url
} else {
- await delay(500);
+ await delay(500)
}
- } while (!messageURL && count < 30);
+ } while (!messageURL && count < 30)
if (count === 30) {
- throw new Error(`Message not found for ${to}.`);
+ throw new Error(`Message not found for ${to}.`)
}
- const messages = await httpGet(messageURL);
+ const messages = await httpGet(messageURL)
- const matches = /]*?\s+)?href=(["'])(.*?)\1/.exec(messages["body-html"]);
+ const matches = / ]*?\s+)?href=(["'])(.*?)\1/.exec(messages["body-html"])
if (matches) {
- return matches[2];
+ return matches[2]
}
- return "";
+ return ""
},
-};
+}
diff --git a/tests/lib/page.ts b/tests/lib/page.ts
index ff932ef3f..fd7559053 100644
--- a/tests/lib/page.ts
+++ b/tests/lib/page.ts
@@ -1,17 +1,17 @@
-import { BrowserTab, WaitCondition } from ".";
+import { BrowserTab, WaitCondition } from "."
-export type NewablePage = new (tab: BrowserTab) => T;
+export type NewablePage = new (tab: BrowserTab) => T
export abstract class Page {
public async navigate(): Promise {
- await this.tab.navigate(this.getURL());
- await this.tab.wait(this.loadCondition());
+ await this.tab.navigate(this.getURL())
+ await this.tab.wait(this.loadCondition())
}
- public abstract loadCondition(): WaitCondition;
+ public abstract loadCondition(): WaitCondition
protected getURL(): string {
- throw new Error("getURL not implemented");
+ throw new Error("getURL not implemented")
}
public constructor(protected tab: BrowserTab) {}
diff --git a/tests/lib/tab.ts b/tests/lib/tab.ts
index 6854bb92f..3dd124a87 100644
--- a/tests/lib/tab.ts
+++ b/tests/lib/tab.ts
@@ -1,72 +1,72 @@
-import * as puppeteer from "puppeteer";
-import { AllPages } from "../pages";
-import { WaitCondition, Page, NewablePage } from ".";
-import { pageHasLoaded } from "./conditions";
+import * as puppeteer from "puppeteer"
+import { AllPages } from "../pages"
+import { WaitCondition, Page, NewablePage } from "."
+import { pageHasLoaded } from "./conditions"
export class BrowserTab {
- private page: puppeteer.Page;
- public pages: AllPages;
- public baseURL: string;
+ private page: puppeteer.Page
+ public pages: AllPages
+ public baseURL: string
public constructor(page: puppeteer.Page, baseURL: string) {
- this.page = page;
- this.baseURL = baseURL;
- this.pages = new AllPages(this);
+ this.page = page
+ this.baseURL = baseURL
+ this.pages = new AllPages(this)
}
public async navigate(url: string): Promise {
- await this.page.goto(url);
+ await this.page.goto(url)
}
public async reload(page: NewablePage): Promise {
- await this.page.goto(this.page.url());
- await this.wait(pageHasLoaded(page));
+ await this.page.goto(this.page.url())
+ await this.wait(pageHasLoaded(page))
}
public async clearCookies(): Promise {
- const cookies = (await this.page.cookies()).map((x) => ({ name: x.name }));
- await this.page.deleteCookie(...cookies);
+ const cookies = (await this.page.cookies()).map((x) => ({ name: x.name }))
+ await this.page.deleteCookie(...cookies)
}
public async wait(condition: WaitCondition, timeout = 30000): Promise {
- const inst = condition(this);
- await this.page.waitForFunction(inst.function, { timeout }, ...inst.args);
+ const inst = condition(this)
+ await this.page.waitForFunction(inst.function, { timeout }, ...inst.args)
}
- public async press(key: string): Promise {
- await this.page.keyboard.press(key);
+ public async press(key: puppeteer.KeyInput): Promise {
+ await this.page.keyboard.press(key)
}
public async click(selector: string, options?: puppeteer.ClickOptions): Promise {
- await this.page.click(selector, options);
+ await this.page.click(selector, options)
}
public async type(selector: string, text: string): Promise {
- await this.page.type(selector, text);
+ await this.page.type(selector, text)
}
public async select(selector: string, value: string): Promise {
- await this.page.select(selector, value);
+ await this.page.select(selector, value)
}
public async evaluate(fn: puppeteer.EvaluateFn, args: any[]): Promise {
- return await this.page.evaluate(fn, ...args);
+ return await this.page.evaluate(fn, ...args)
}
public async waitAny(conditions: WaitCondition | WaitCondition[]): Promise {
- const all = !(conditions instanceof Array) ? [conditions] : conditions;
+ const all = !(conditions instanceof Array) ? [conditions] : conditions
- let retry = 20;
+ let retry = 20
do {
for (const condition of all) {
- retry--;
+ retry--
try {
- await this.wait(condition, 200);
- return;
+ await this.wait(condition, 200)
+ return
} catch (ex) {
- continue;
+ continue
}
}
- } while (retry >= 0);
+ } while (retry >= 0)
}
}
diff --git a/tests/lib/utils.ts b/tests/lib/utils.ts
index 4f743f9e7..63bca6b34 100644
--- a/tests/lib/utils.ts
+++ b/tests/lib/utils.ts
@@ -1,19 +1,19 @@
-import "reflect-metadata";
+import "reflect-metadata"
export const delay = (ms: number) => {
- return new Promise((resolve) => setTimeout(resolve, ms));
-};
+ return new Promise((resolve) => setTimeout(resolve, ms))
+}
export function findBy(selector: string) {
- return (target: any, propertyKey: string) => {
- const type = Reflect.getMetadata("design:type", target, propertyKey);
+ return (target: unknown, propertyKey: string) => {
+ const type = Reflect.getMetadata("design:type", target, propertyKey)
Object.defineProperty(target, propertyKey, {
configurable: true,
enumerable: true,
get() {
- const tab = (this as any).tab;
- return new type(tab, selector);
+ const tab = this.tab
+ return new type(tab, selector)
},
- });
- };
+ })
+ }
}
diff --git a/tests/multi.spec.ts b/tests/multi.spec.ts
index 7dde8c499..6d652ee39 100644
--- a/tests/multi.spec.ts
+++ b/tests/multi.spec.ts
@@ -1,4 +1,4 @@
-process.env.HOST_MODE = "multi";
-jest.setTimeout(30000);
-require("./scenarios/email-signup");
-require("./scenarios/index");
+process.env.HOST_MODE = "multi"
+jest.setTimeout(30000)
+require("./scenarios/email-signup")
+require("./scenarios/index")
diff --git a/tests/pages/FacebookSignInPage.ts b/tests/pages/FacebookSignInPage.ts
index 3d79f5b5c..13148dda1 100644
--- a/tests/pages/FacebookSignInPage.ts
+++ b/tests/pages/FacebookSignInPage.ts
@@ -1,34 +1,34 @@
-import { findBy, Page, BrowserTab, TextInput, elementIsVisible, Button, pageHasLoaded } from "../lib";
-import { HomePage, SignUpPage } from ".";
+import { findBy, Page, BrowserTab, TextInput, elementIsVisible, Button, pageHasLoaded } from "../lib"
+import { HomePage, SignUpPage } from "."
export class FacebookSignInPage extends Page {
constructor(tab: BrowserTab) {
- super(tab);
+ super(tab)
}
@findBy("#email")
- public Email!: TextInput;
+ public Email!: TextInput
@findBy('input[type="password"]')
- public Password!: TextInput;
+ public Password!: TextInput
@findBy("#loginbutton")
- public Confirm!: Button;
+ public Confirm!: Button
public loadCondition() {
- return elementIsVisible(this.Email);
+ return elementIsVisible(this.Email)
}
public async signInAsJonSnow() {
- await this.signInAs("jon_jdrtrsd_snow@tfbnw.net", "jon_jdrtrsd_snow");
+ await this.signInAs("jon_jdrtrsd_snow@tfbnw.net", "jon_jdrtrsd_snow")
}
public async signInAsAryaStark() {
- await this.signInAs("arya_xittsrj_stark@tfbnw.net", "arya_xittsrj_stark");
+ await this.signInAs("arya_xittsrj_stark@tfbnw.net", "arya_xittsrj_stark")
}
public async signInAs(email: string, password: string) {
- await this.Email.type(email);
- await this.Password.type(password);
- await this.Confirm.click();
- await this.tab.waitAny([pageHasLoaded(HomePage), pageHasLoaded(SignUpPage)]);
+ await this.Email.type(email)
+ await this.Password.type(password)
+ await this.Confirm.click()
+ await this.tab.waitAny([pageHasLoaded(HomePage), pageHasLoaded(SignUpPage)])
}
}
diff --git a/tests/pages/GeneralSettingsPage.ts b/tests/pages/GeneralSettingsPage.ts
index 34a7cf30c..5f7feee34 100644
--- a/tests/pages/GeneralSettingsPage.ts
+++ b/tests/pages/GeneralSettingsPage.ts
@@ -1,36 +1,36 @@
-import { BrowserTab, WaitCondition, Page, elementIsVisible, findBy, TextInput, WebComponent, Button, pageHasLoaded } from "../lib";
-import { HomePage, FacebookSignInPage } from ".";
+import { BrowserTab, WaitCondition, Page, elementIsVisible, findBy, TextInput, Button, pageHasLoaded } from "../lib"
+import { HomePage } from "."
export class GeneralSettingsPage extends Page {
constructor(tab: BrowserTab) {
- super(tab);
+ super(tab)
}
public getURL(): string {
- return `${this.tab.baseURL}/admin`;
+ return `${this.tab.baseURL}/admin`
}
@findBy("#p-admin-general #input-title")
- private TitleInput!: TextInput;
+ private TitleInput!: TextInput
@findBy("#p-admin-general #input-welcomeMessage")
- private WelcomeMessageInput!: TextInput;
+ private WelcomeMessageInput!: TextInput
@findBy("#p-admin-general #input-invitation")
- private InvitationInput!: TextInput;
+ private InvitationInput!: TextInput
@findBy("#p-admin-general .c-button.m-positive")
- private SaveChangesButton!: Button;
+ private SaveChangesButton!: Button
public loadCondition(): WaitCondition {
- return elementIsVisible(this.TitleInput);
+ return elementIsVisible(this.TitleInput)
}
public async changeSettings(title: string, welcomeMessage: string, invitation: string): Promise {
- await this.TitleInput.clear();
- await this.TitleInput.type(title);
- await this.WelcomeMessageInput.clear();
- await this.WelcomeMessageInput.type(welcomeMessage);
- await this.InvitationInput.clear();
- await this.InvitationInput.type(invitation);
- await this.SaveChangesButton.click();
- await this.tab.wait(pageHasLoaded(HomePage));
+ await this.TitleInput.clear()
+ await this.TitleInput.type(title)
+ await this.WelcomeMessageInput.clear()
+ await this.WelcomeMessageInput.type(welcomeMessage)
+ await this.InvitationInput.clear()
+ await this.InvitationInput.type(invitation)
+ await this.SaveChangesButton.click()
+ await this.tab.wait(pageHasLoaded(HomePage))
}
}
diff --git a/tests/pages/HomePage.ts b/tests/pages/HomePage.ts
index f8d77d306..877b46c52 100644
--- a/tests/pages/HomePage.ts
+++ b/tests/pages/HomePage.ts
@@ -1,94 +1,94 @@
-import { BrowserTab, Page, findBy, TextInput, elementIsVisible, WebComponent, pageHasLoaded, Button, elementIsNotVisible } from "../lib";
-import { ShowPostPage, FacebookSignInPage } from ".";
-import { PostList } from "./components";
+import { BrowserTab, Page, findBy, TextInput, elementIsVisible, WebComponent, pageHasLoaded, Button, elementIsNotVisible } from "../lib"
+import { ShowPostPage, FacebookSignInPage } from "."
+import { PostList } from "./components"
export class HomePage extends Page {
constructor(tab: BrowserTab) {
- super(tab);
+ super(tab)
}
public getURL(): string {
- return `${this.tab.baseURL}/`;
+ return `${this.tab.baseURL}/`
}
@findBy(".c-menu-item-title")
- public MenuTitle!: WebComponent;
+ public MenuTitle!: WebComponent
@findBy(".welcome-message")
- public WelcomeMessage!: WebComponent;
+ public WelcomeMessage!: WebComponent
@findBy("#input-title")
- public PostTitle!: TextInput;
+ public PostTitle!: TextInput
@findBy("#input-description")
- public PostDescription!: TextInput;
+ public PostDescription!: TextInput
@findBy(".c-button.m-positive")
- public SubmitPost!: Button;
+ public SubmitPost!: Button
@findBy(".c-menu-item-signin")
- public UserMenu!: WebComponent;
+ public UserMenu!: WebComponent
@findBy(".c-unread-count")
- public UnreadCounter!: WebComponent;
+ public UnreadCounter!: WebComponent
@findBy(".c-menu-user-heading")
- public UserName!: WebComponent;
+ public UserName!: WebComponent
@findBy(".c-modal-window")
- public SignInModal!: WebComponent;
+ public SignInModal!: WebComponent
@findBy(".c-modal-window .c-button.m-facebook")
- public FacebookSignIn!: Button;
+ public FacebookSignIn!: Button
@findBy(".c-modal-window .c-signin-control #input-email")
- private EmailSignInInput!: TextInput;
+ private EmailSignInInput!: TextInput
@findBy(".c-modal-window .c-signin-control .c-button.m-positive")
- private EmailSignInButton!: TextInput;
+ private EmailSignInButton!: TextInput
@findBy(".signout")
- private SignOut!: Button;
+ private SignOut!: Button
@findBy(".c-post-list")
- public PostList!: PostList;
+ public PostList!: PostList
@findBy(".c-modal-window input")
- private CompleteEmailSignInInput!: TextInput;
+ private CompleteEmailSignInInput!: TextInput
@findBy(".c-modal-window button")
- private CompleteEmailSignInButton!: Button;
+ private CompleteEmailSignInButton!: Button
public loadCondition() {
- return elementIsVisible("#p-home");
+ return elementIsVisible("#p-home")
}
public async submitNewPost(title: string, description: string): Promise {
- await this.PostTitle.type(title);
- await this.PostDescription.type(description);
- await this.SubmitPost.click();
- await this.tab.wait(pageHasLoaded(ShowPostPage));
+ await this.PostTitle.type(title)
+ await this.PostDescription.type(description)
+ await this.SubmitPost.click()
+ await this.tab.wait(pageHasLoaded(ShowPostPage))
}
public async signOut(): Promise {
if (await this.SignOut.isVisible()) {
- await this.UserMenu.click();
- await this.SignOut.click();
- await this.tab.wait(pageHasLoaded(HomePage));
+ await this.UserMenu.click()
+ await this.SignOut.click()
+ await this.tab.wait(pageHasLoaded(HomePage))
}
}
public async signInWithFacebook(): Promise {
- await this.signOut();
- await this.signIn(this.FacebookSignIn);
- await this.tab.wait(pageHasLoaded(FacebookSignInPage));
+ await this.signOut()
+ await this.signIn(this.FacebookSignIn)
+ await this.tab.wait(pageHasLoaded(FacebookSignInPage))
}
public async signInWithEmail(email: string): Promise {
- await this.signOut();
- await this.UserMenu.click();
- await this.tab.wait(elementIsVisible(this.EmailSignInInput));
- await this.EmailSignInInput.type(email);
- await this.EmailSignInButton.click();
- await this.tab.wait(elementIsNotVisible(this.EmailSignInButton));
+ await this.signOut()
+ await this.UserMenu.click()
+ await this.tab.wait(elementIsVisible(this.EmailSignInInput))
+ await this.EmailSignInInput.type(email)
+ await this.EmailSignInButton.click()
+ await this.tab.wait(elementIsNotVisible(this.EmailSignInButton))
}
public async completeSignIn(name: string): Promise {
- await this.tab.wait(elementIsVisible(this.CompleteEmailSignInInput));
- await this.CompleteEmailSignInInput.type(name);
- await this.CompleteEmailSignInButton.click();
- await this.tab.wait(elementIsNotVisible(this.CompleteEmailSignInInput));
- await this.tab.wait(this.loadCondition());
+ await this.tab.wait(elementIsVisible(this.CompleteEmailSignInInput))
+ await this.CompleteEmailSignInInput.type(name)
+ await this.CompleteEmailSignInButton.click()
+ await this.tab.wait(elementIsNotVisible(this.CompleteEmailSignInInput))
+ await this.tab.wait(this.loadCondition())
}
private async signIn(locator: WebComponent): Promise {
- await this.UserMenu.click();
- await this.tab.wait(elementIsVisible(locator));
- await locator.click();
+ await this.UserMenu.click()
+ await this.tab.wait(elementIsVisible(locator))
+ await locator.click()
}
}
diff --git a/tests/pages/ShowPostPage.ts b/tests/pages/ShowPostPage.ts
index 5157cd427..a6aad24ec 100644
--- a/tests/pages/ShowPostPage.ts
+++ b/tests/pages/ShowPostPage.ts
@@ -1,73 +1,73 @@
-import { BrowserTab, Page, WebComponent, TextInput, Button, findBy, elementIsVisible, DropDownList } from "../lib";
-import { CommentList } from "./components";
+import { BrowserTab, Page, WebComponent, TextInput, Button, findBy, elementIsVisible, DropDownList } from "../lib"
+import { CommentList } from "./components"
export class ShowPostPage extends Page {
constructor(tab: BrowserTab) {
- super(tab);
+ super(tab)
}
@findBy(".post-header h1")
- public Title!: WebComponent;
+ public Title!: WebComponent
@findBy(".description")
- public Description!: WebComponent;
+ public Description!: WebComponent
@findBy(".c-segment.l-response .status-label")
- public Status!: WebComponent;
+ public Status!: WebComponent
@findBy(".c-segment.l-response .content")
- public ResponseText!: WebComponent;
+ public ResponseText!: WebComponent
@findBy(".c-vote-counter button")
- public VoteCounter!: WebComponent;
+ public VoteCounter!: WebComponent
@findBy(".action-col .c-button.respond")
- public RespondButton!: Button;
+ public RespondButton!: Button
@findBy(".c-modal-window .c-response-form")
- public ResponseModal!: WebComponent;
+ public ResponseModal!: WebComponent
@findBy(".c-comment-list")
- public Comments!: CommentList;
+ public Comments!: CommentList
@findBy(".c-modal-window .c-response-form #input-status")
- private ResponseModalStatus!: DropDownList;
+ private ResponseModalStatus!: DropDownList
@findBy(".c-modal-window .c-response-form #input-text")
- private ResponseModalText!: TextInput;
+ private ResponseModalText!: TextInput
@findBy(".c-modal-window .c-modal-footer .c-button.m-positive")
- private ResponseModalSubmitButton!: Button;
+ private ResponseModalSubmitButton!: Button
@findBy(".c-comment-input #input-content")
- private CommentInput!: TextInput;
+ private CommentInput!: TextInput
@findBy(".c-comment-input .c-button.m-positive")
- private SubmitCommentButton!: Button;
+ private SubmitCommentButton!: Button
@findBy(".action-col .c-button.edit")
- private Edit!: Button;
+ private Edit!: Button
@findBy("#input-title")
- private EditTitle!: TextInput;
+ private EditTitle!: TextInput
@findBy("#input-description")
- private EditDescription!: TextInput;
+ private EditDescription!: TextInput
@findBy(".action-col .c-button.save")
- private SaveEdit!: Button;
+ private SaveEdit!: Button
public loadCondition() {
- return elementIsVisible(this.Title);
+ return elementIsVisible(this.Title)
}
public async changeStatus(status: string, text: string): Promise {
- await this.RespondButton.click();
- await this.tab.wait(elementIsVisible(this.ResponseModal));
- await this.ResponseModalStatus.selectByText(status);
- await this.ResponseModalText.clear();
- await this.ResponseModalText.type(text);
- await this.ResponseModalSubmitButton.click();
+ await this.RespondButton.click()
+ await this.tab.wait(elementIsVisible(this.ResponseModal))
+ await this.ResponseModalStatus.selectByText(status)
+ await this.ResponseModalText.clear()
+ await this.ResponseModalText.type(text)
+ await this.ResponseModalSubmitButton.click()
}
public async edit(newTitle: string, newDescription: string): Promise {
- await this.Edit.click();
- await this.EditTitle.clear();
- await this.EditTitle.type(newTitle);
- await this.EditDescription.clear();
- await this.EditDescription.type(newDescription);
- await this.SaveEdit.click();
+ await this.Edit.click()
+ await this.EditTitle.clear()
+ await this.EditTitle.type(newTitle)
+ await this.EditDescription.clear()
+ await this.EditDescription.type(newDescription)
+ await this.SaveEdit.click()
}
public async comment(text: string): Promise {
- await this.CommentInput.type(text);
- await this.SubmitCommentButton.click();
+ await this.CommentInput.type(text)
+ await this.SubmitCommentButton.click()
}
}
diff --git a/tests/pages/SignUpPage.ts b/tests/pages/SignUpPage.ts
index 5801eb733..d0ac1f5b0 100644
--- a/tests/pages/SignUpPage.ts
+++ b/tests/pages/SignUpPage.ts
@@ -1,60 +1,60 @@
-import { BrowserTab, WaitCondition, Page, elementIsVisible, findBy, TextInput, WebComponent, Button, pageHasLoaded } from "../lib";
-import { HomePage, FacebookSignInPage } from ".";
+import { BrowserTab, WaitCondition, Page, elementIsVisible, findBy, TextInput, WebComponent, Button, pageHasLoaded } from "../lib"
+import { HomePage, FacebookSignInPage } from "."
export class SignUpPage extends Page {
constructor(tab: BrowserTab) {
- super(tab);
+ super(tab)
}
public getURL(): string {
- return `${this.tab.baseURL}/signup`;
+ return `${this.tab.baseURL}/signup`
}
@findBy("#p-signup")
- private Container!: WebComponent;
+ private Container!: WebComponent
@findBy("#p-signup .c-button.m-facebook")
- public FacebookSignIn!: Button;
+ public FacebookSignIn!: Button
@findBy("#p-signup #input-name")
- public UserName!: TextInput;
+ public UserName!: TextInput
@findBy("#p-signup #input-email")
- public UserEmail!: TextInput;
+ public UserEmail!: TextInput
@findBy("#p-signup #input-tenantName")
- public TenantName!: TextInput;
+ public TenantName!: TextInput
@findBy("#p-signup #input-subdomain")
- public Subdomain!: TextInput;
+ public Subdomain!: TextInput
@findBy("#p-signup #input-legalAgreement")
- private LegalAgreement!: WebComponent;
+ private LegalAgreement!: WebComponent
@findBy("#p-signup .c-button.m-positive")
- public Confirm!: Button;
+ public Confirm!: Button
@findBy("#p-signup .c-message.m-success")
- private SubdomainOk!: WebComponent;
+ private SubdomainOk!: WebComponent
@findBy(".c-modal-window")
- private ConfirmationModal!: WebComponent;
+ private ConfirmationModal!: WebComponent
public loadCondition(): WaitCondition {
- return elementIsVisible(this.Container);
+ return elementIsVisible(this.Container)
}
public async signInWithFacebook(): Promise {
- await this.FacebookSignIn.click();
- await this.tab.wait(pageHasLoaded(FacebookSignInPage));
+ await this.FacebookSignIn.click()
+ await this.tab.wait(pageHasLoaded(FacebookSignInPage))
}
public async signInWithEmail(name: string, email: string): Promise {
- await this.UserName.type(name);
- await this.UserEmail.type(email);
+ await this.UserName.type(name)
+ await this.UserEmail.type(email)
}
public async signUpAs(name: string, subdomain: string): Promise {
- await this.TenantName.type(name);
+ await this.TenantName.type(name)
if (await this.Subdomain.isVisible()) {
- await this.Subdomain.type(subdomain);
- await this.tab.wait(elementIsVisible(this.SubdomainOk));
+ await this.Subdomain.type(subdomain)
+ await this.tab.wait(elementIsVisible(this.SubdomainOk))
}
if (await this.LegalAgreement.isVisible()) {
- await this.LegalAgreement.click();
+ await this.LegalAgreement.click()
}
- await this.Confirm.click();
- await this.tab.waitAny([pageHasLoaded(HomePage), elementIsVisible(this.ConfirmationModal)]);
+ await this.Confirm.click()
+ await this.tab.waitAny([pageHasLoaded(HomePage), elementIsVisible(this.ConfirmationModal)])
}
}
diff --git a/tests/pages/components/CommentList.ts b/tests/pages/components/CommentList.ts
index c105d6b52..aef7dc795 100644
--- a/tests/pages/components/CommentList.ts
+++ b/tests/pages/components/CommentList.ts
@@ -1,16 +1,16 @@
-import { BrowserTab, List } from "../../lib";
+import { BrowserTab, List } from "../../lib"
export class CommentList extends List {
constructor(tab: BrowserTab, selector: string) {
- super(tab, selector);
+ super(tab, selector)
}
public async count(): Promise {
return await this.tab.evaluate(
(selector: string) => {
- return document.querySelectorAll(`${selector} .c-comment`).length;
+ return document.querySelectorAll(`${selector} .c-comment`).length
},
[this.selector]
- );
+ )
}
}
diff --git a/tests/pages/components/PostList.ts b/tests/pages/components/PostList.ts
index 7690cfc24..0eb01591b 100644
--- a/tests/pages/components/PostList.ts
+++ b/tests/pages/components/PostList.ts
@@ -1,18 +1,18 @@
-import { WebComponent, BrowserTab, pageHasLoaded } from "../../lib";
-import { ShowPostPage } from "..";
+import { WebComponent, BrowserTab, pageHasLoaded } from "../../lib"
+import { ShowPostPage } from ".."
export class PostItem {
- public Vote: WebComponent;
- private Link: WebComponent;
+ public Vote: WebComponent
+ private Link: WebComponent
constructor(protected tab: BrowserTab, public selector: string) {
- this.Vote = new WebComponent(tab, `${this.selector} .c-vote-counter button`);
- this.Link = new WebComponent(tab, `${this.selector} .c-list-item-title`);
+ this.Vote = new WebComponent(tab, `${this.selector} .c-vote-counter button`)
+ this.Link = new WebComponent(tab, `${this.selector} .c-list-item-title`)
}
public async navigate(): Promise {
- await this.Link.click();
- await this.tab.wait(pageHasLoaded(ShowPostPage));
+ await this.Link.click()
+ await this.tab.wait(pageHasLoaded(ShowPostPage))
}
}
@@ -22,20 +22,20 @@ export class PostList {
private async findPostIndex(title: string): Promise {
return this.tab.evaluate(
(text: string, selector: string) => {
- const elements = document.querySelectorAll(`${selector} .c-list-item-title`);
+ const elements = document.querySelectorAll(`${selector} .c-list-item-title`)
for (let i = 0; i <= elements.length; i++) {
if (elements[i].textContent === text) {
- return i;
+ return i
}
}
- return -1;
+ return -1
},
[title, this.selector]
- );
+ )
}
public async get(title: string): Promise {
- const idx = await this.findPostIndex(title);
- return new PostItem(this.tab, `${this.selector} > .c-list-item:nth-child(${idx + 1})`);
+ const idx = await this.findPostIndex(title)
+ return new PostItem(this.tab, `${this.selector} > .c-list-item:nth-child(${idx + 1})`)
}
}
diff --git a/tests/pages/components/index.ts b/tests/pages/components/index.ts
index 36bc64b4e..0e344a4e6 100644
--- a/tests/pages/components/index.ts
+++ b/tests/pages/components/index.ts
@@ -1,2 +1,2 @@
-export * from "./PostList";
-export * from "./CommentList";
+export * from "./PostList"
+export * from "./CommentList"
diff --git a/tests/pages/index.ts b/tests/pages/index.ts
index 84a37ad93..6d259b2af 100644
--- a/tests/pages/index.ts
+++ b/tests/pages/index.ts
@@ -1,28 +1,28 @@
-import { HomePage } from "./HomePage";
-import { SignUpPage } from "./SignUpPage";
-import { FacebookSignInPage } from "./FacebookSignInPage";
-import { GeneralSettingsPage } from "./GeneralSettingsPage";
-import { ShowPostPage } from "./ShowPostPage";
-import { BrowserTab } from "../lib";
+import { HomePage } from "./HomePage"
+import { SignUpPage } from "./SignUpPage"
+import { FacebookSignInPage } from "./FacebookSignInPage"
+import { GeneralSettingsPage } from "./GeneralSettingsPage"
+import { ShowPostPage } from "./ShowPostPage"
+import { BrowserTab } from "../lib"
-export { SignUpPage, ShowPostPage, HomePage, FacebookSignInPage, GeneralSettingsPage };
+export { SignUpPage, ShowPostPage, HomePage, FacebookSignInPage, GeneralSettingsPage }
export class AllPages {
- public home: HomePage;
- public signup: SignUpPage;
- public showPost: ShowPostPage;
- public facebook: FacebookSignInPage;
- public generalSettings: GeneralSettingsPage;
+ public home: HomePage
+ public signup: SignUpPage
+ public showPost: ShowPostPage
+ public facebook: FacebookSignInPage
+ public generalSettings: GeneralSettingsPage
constructor(public tab: BrowserTab) {
- this.home = new HomePage(tab);
- this.signup = new SignUpPage(tab);
- this.showPost = new ShowPostPage(tab);
- this.facebook = new FacebookSignInPage(tab);
- this.generalSettings = new GeneralSettingsPage(tab);
+ this.home = new HomePage(tab)
+ this.signup = new SignUpPage(tab)
+ this.showPost = new ShowPostPage(tab)
+ this.facebook = new FacebookSignInPage(tab)
+ this.generalSettings = new GeneralSettingsPage(tab)
}
public async goTo(url: string): Promise {
- return this.tab.navigate(url);
+ return this.tab.navigate(url)
}
}
diff --git a/tests/scenarios/admin-settings.ts b/tests/scenarios/admin-settings.ts
index 9db8c2723..444f39a36 100644
--- a/tests/scenarios/admin-settings.ts
+++ b/tests/scenarios/admin-settings.ts
@@ -1,13 +1,13 @@
-import { ensure } from "../lib";
-import { ctx } from ".";
+import { ensure } from "../lib"
+import { ctx } from "."
it("Tab1: User can change general settings", async () => {
// Action
- await ctx.tab1.pages.generalSettings.navigate();
- await ctx.tab1.pages.generalSettings.changeSettings("Feedback for X", "Leave your feedback below", "Enter here...");
+ await ctx.tab1.pages.generalSettings.navigate()
+ await ctx.tab1.pages.generalSettings.changeSettings("Feedback for X", "Leave your feedback below", "Enter here...")
// Assert
- await ensure(ctx.tab1.pages.home.MenuTitle).textIs("Feedback for X");
- await ensure(ctx.tab1.pages.home.PostTitle).attributeIs("placeholder", "Enter here...");
- await ensure(ctx.tab1.pages.home.WelcomeMessage).textIs("Leave your feedback below");
-});
+ await ensure(ctx.tab1.pages.home.MenuTitle).textIs("Feedback for X")
+ await ensure(ctx.tab1.pages.home.PostTitle).attributeIs("placeholder", "Enter here...")
+ await ensure(ctx.tab1.pages.home.WelcomeMessage).textIs("Leave your feedback below")
+})
diff --git a/tests/scenarios/email-signup.ts b/tests/scenarios/email-signup.ts
index be48a489f..138eed825 100644
--- a/tests/scenarios/email-signup.ts
+++ b/tests/scenarios/email-signup.ts
@@ -1,33 +1,33 @@
-import { Browser, BrowserTab, mailgun, pageHasLoaded, ensure } from "../lib";
-import { HomePage } from "../pages";
+import { Browser, BrowserTab, mailgun, pageHasLoaded, ensure } from "../lib"
+import { HomePage } from "../pages"
describe("E2E: Sign up with e-mail", () => {
- let browser: Browser;
- let tab: BrowserTab;
+ let browser: Browser
+ let tab: BrowserTab
beforeAll(async () => {
- browser = await Browser.launch();
- tab = await browser.newTab("https://login.dev.fider.io:3000");
- });
+ browser = await Browser.launch()
+ tab = await browser.newTab("https://login.dev.fider.io:3000")
+ })
afterAll(async () => {
- await browser.close();
- });
+ await browser.close()
+ })
it("User can sign up using email", async () => {
- const now = new Date().getTime();
+ const now = new Date().getTime()
// Action
- await tab.pages.signup.navigate();
- await tab.pages.signup.signInWithEmail(`Darth Vader ${now}`, `darthvader.fider@gmail.com`);
- await tab.pages.signup.signUpAs(`Selenium ${now}`, `selenium${now}`);
+ await tab.pages.signup.navigate()
+ await tab.pages.signup.signInWithEmail(`Darth Vader ${now}`, `darthvader.fider@gmail.com`)
+ await tab.pages.signup.signUpAs(`Selenium ${now}`, `selenium${now}`)
- const link = await mailgun.getLinkFromLastEmailTo(`selenium${now}`, `Confirm your new Fider instance`, `darthvader.fider@gmail.com`);
+ const link = await mailgun.getLinkFromLastEmailTo(`selenium${now}`, `Confirm your new Fider instance`, `darthvader.fider@gmail.com`)
- await tab.pages.goTo(link);
- await tab.wait(pageHasLoaded(HomePage));
+ await tab.pages.goTo(link)
+ await tab.wait(pageHasLoaded(HomePage))
// Assert
- await ensure(tab.pages.home.UserName).textIs(`Darth Vader ${now}`);
- });
-});
+ await ensure(tab.pages.home.UserName).textIs(`Darth Vader ${now}`)
+ })
+})
diff --git a/tests/scenarios/feedback-loop.ts b/tests/scenarios/feedback-loop.ts
index 9a0a96a2d..8fe5d74d0 100644
--- a/tests/scenarios/feedback-loop.ts
+++ b/tests/scenarios/feedback-loop.ts
@@ -1,135 +1,135 @@
-import { Browser, BrowserTab, pageHasLoaded, ensure, elementIsNotVisible, delay, elementIsVisible, mailgun } from "../lib";
-import { HomePage, ShowPostPage } from "../pages";
-import { ctx } from ".";
+import { pageHasLoaded, ensure, elementIsNotVisible, elementIsVisible, mailgun } from "../lib"
+import { HomePage, ShowPostPage } from "../pages"
+import { ctx } from "."
it("Tab1: User is authenticated after sign up", async () => {
// Action
- await ctx.tab1.pages.home.navigate();
+ await ctx.tab1.pages.home.navigate()
// Assert
- await ensure(ctx.tab1.pages.home.UserName).textIs("Jon Snow");
-});
+ await ensure(ctx.tab1.pages.home.UserName).textIs("Jon Snow")
+})
it("Tab1: User doesn't lose what they typed", async () => {
// Action
- await ctx.tab1.pages.home.navigate();
- await ctx.tab1.pages.home.PostTitle.type("My Great Post");
- await ctx.tab1.pages.home.PostDescription.type("With an awesome description");
- await ctx.tab1.pages.home.PostTitle.clear();
- await ctx.tab1.pages.home.PostTitle.type("My Great Post has a new title");
+ await ctx.tab1.pages.home.navigate()
+ await ctx.tab1.pages.home.PostTitle.type("My Great Post")
+ await ctx.tab1.pages.home.PostDescription.type("With an awesome description")
+ await ctx.tab1.pages.home.PostTitle.clear()
+ await ctx.tab1.pages.home.PostTitle.type("My Great Post has a new title")
// Assert
- await ensure(ctx.tab1.pages.home.PostTitle).textIs("My Great Post has a new title");
- await ensure(ctx.tab1.pages.home.PostDescription).textIs("With an awesome description");
+ await ensure(ctx.tab1.pages.home.PostTitle).textIs("My Great Post has a new title")
+ await ensure(ctx.tab1.pages.home.PostDescription).textIs("With an awesome description")
// Action
- await ctx.tab1.pages.home.navigate();
+ await ctx.tab1.pages.home.navigate()
// Assert
- await ensure(ctx.tab1.pages.home.PostTitle).textIs("My Great Post has a new title");
- await ensure(ctx.tab1.pages.home.PostDescription).textIs("With an awesome description");
+ await ensure(ctx.tab1.pages.home.PostTitle).textIs("My Great Post has a new title")
+ await ensure(ctx.tab1.pages.home.PostDescription).textIs("With an awesome description")
// Action
- await ctx.tab1.pages.home.PostDescription.clear();
- await ctx.tab1.pages.home.PostTitle.clear();
- await ctx.tab1.pages.home.navigate();
+ await ctx.tab1.pages.home.PostDescription.clear()
+ await ctx.tab1.pages.home.PostTitle.clear()
+ await ctx.tab1.pages.home.navigate()
// Assert
- await ensure(ctx.tab1.pages.home.PostTitle).textIs("");
- await ctx.tab1.wait(elementIsNotVisible(ctx.tab1.pages.home.PostDescription));
-});
+ await ensure(ctx.tab1.pages.home.PostTitle).textIs("")
+ await ctx.tab1.wait(elementIsNotVisible(ctx.tab1.pages.home.PostDescription))
+})
it("Tab1: Can submit Posts", async () => {
// Action
- await ctx.tab1.pages.home.navigate();
- await ctx.tab1.pages.home.submitNewPost("Add support to TypeScript", "Because the language and community is awesome! :)");
+ await ctx.tab1.pages.home.navigate()
+ await ctx.tab1.pages.home.submitNewPost("Add support to TypeScript", "Because the language and community is awesome! :)")
// Assert
- await ensure(ctx.tab1.pages.showPost.Title).textIs("Add support to TypeScript");
- await ensure(ctx.tab1.pages.showPost.Description).textIs("Because the language and community is awesome! :)");
- await ensure(ctx.tab1.pages.showPost.VoteCounter).textIs("1");
-});
+ await ensure(ctx.tab1.pages.showPost.Title).textIs("Add support to TypeScript")
+ await ensure(ctx.tab1.pages.showPost.Description).textIs("Because the language and community is awesome! :)")
+ await ensure(ctx.tab1.pages.showPost.VoteCounter).textIs("1")
+})
it("Tab1: Can edit title and description", async () => {
// Action
- await ctx.tab1.pages.showPost.edit("Support for TypeScript", "Because the language and community is awesome!");
+ await ctx.tab1.pages.showPost.edit("Support for TypeScript", "Because the language and community is awesome!")
// Assert
- await ensure(ctx.tab1.pages.showPost.Title).textIs("Support for TypeScript");
- await ensure(ctx.tab1.pages.showPost.Description).textIs("Because the language and community is awesome!");
- await ensure(ctx.tab1.pages.showPost.VoteCounter).textIs("1");
-});
+ await ensure(ctx.tab1.pages.showPost.Title).textIs("Support for TypeScript")
+ await ensure(ctx.tab1.pages.showPost.Description).textIs("Because the language and community is awesome!")
+ await ensure(ctx.tab1.pages.showPost.VoteCounter).textIs("1")
+})
it("Tab2: Can login as another user", async () => {
// Action
- await ctx.tab2.pages.home.navigate();
- await ctx.tab2.pages.home.signInWithFacebook();
- await ctx.tab2.pages.facebook.signInAsAryaStark();
- await ctx.tab2.wait(pageHasLoaded(HomePage));
+ await ctx.tab2.pages.home.navigate()
+ await ctx.tab2.pages.home.signInWithFacebook()
+ await ctx.tab2.pages.facebook.signInAsAryaStark()
+ await ctx.tab2.wait(pageHasLoaded(HomePage))
// Assert
- await ensure(ctx.tab2.pages.home.UserName).textIs("Arya Stark");
-});
+ await ensure(ctx.tab2.pages.home.UserName).textIs("Arya Stark")
+})
it("Tab2: User can vote on Post", async () => {
// Action
- await ctx.tab2.pages.home.navigate();
- const item = await ctx.tab2.pages.home.PostList.get("Support for TypeScript");
- await item.Vote.click();
+ await ctx.tab2.pages.home.navigate()
+ const item = await ctx.tab2.pages.home.PostList.get("Support for TypeScript")
+ await item.Vote.click()
// Assert
- await ensure(item.Vote).textIs("2");
-});
+ await ensure(item.Vote).textIs("2")
+})
it("Tab2: Open Post and vote on it", async () => {
// Action
- const item = await ctx.tab2.pages.home.PostList.get("Support for TypeScript");
- await item.navigate();
- await ctx.tab2.pages.showPost.comment("I support this request!");
+ const item = await ctx.tab2.pages.home.PostList.get("Support for TypeScript")
+ await item.navigate()
+ await ctx.tab2.pages.showPost.comment("I support this request!")
// Assert
- await ensure(ctx.tab2.pages.showPost.Comments).countIs(1);
-});
+ await ensure(ctx.tab2.pages.showPost.Comments).countIs(1)
+})
it("Tab1: Open Post and change status", async () => {
// Action
- await ctx.tab1.pages.home.navigate();
- const item = await ctx.tab1.pages.home.PostList.get("Support for TypeScript");
- await item.navigate();
- await ctx.tab1.pages.showPost.changeStatus("Started", "This will be delivered on next release.");
- await ctx.tab1.wait(elementIsVisible(ctx.tab1.pages.showPost.Status));
+ await ctx.tab1.pages.home.navigate()
+ const item = await ctx.tab1.pages.home.PostList.get("Support for TypeScript")
+ await item.navigate()
+ await ctx.tab1.pages.showPost.changeStatus("Started", "This will be delivered on next release.")
+ await ctx.tab1.wait(elementIsVisible(ctx.tab1.pages.showPost.Status))
// Assert
- await ensure(ctx.tab1.pages.showPost.Status).textIs("Started");
- await ensure(ctx.tab1.pages.showPost.ResponseText).textIs("This will be delivered on next release.");
-});
+ await ensure(ctx.tab1.pages.showPost.Status).textIs("Started")
+ await ensure(ctx.tab1.pages.showPost.ResponseText).textIs("This will be delivered on next release.")
+})
it("Tab2: Refresh and see status", async () => {
// Action
- await ctx.tab2.reload(ShowPostPage);
+ await ctx.tab2.reload(ShowPostPage)
// Assert
- await ensure(ctx.tab1.pages.showPost.Status).textIs("Started");
- await ensure(ctx.tab1.pages.showPost.ResponseText).textIs("This will be delivered on next release.");
-});
+ await ensure(ctx.tab1.pages.showPost.Status).textIs("Started")
+ await ensure(ctx.tab1.pages.showPost.ResponseText).textIs("This will be delivered on next release.")
+})
it("Tab2: Check notifications", async () => {
// Action
- await ctx.tab2.pages.home.navigate();
- await ctx.tab2.pages.home.UserMenu.click();
+ await ctx.tab2.pages.home.navigate()
+ await ctx.tab2.pages.home.UserMenu.click()
// Assert
- await ensure(ctx.tab2.pages.home.UnreadCounter).textIs("1");
-});
+ await ensure(ctx.tab2.pages.home.UnreadCounter).textIs("1")
+})
it("Tab2: Logout and sign in with email", async () => {
// Action
- await ctx.tab2.pages.home.navigate();
- await ctx.tab2.pages.home.signInWithEmail("darthvader.fider@gmail.com");
- const link = await mailgun.getLinkFromLastEmailTo(ctx.tenantSubdomain, `Sign in to ${ctx.tenantName}`, `darthvader.fider@gmail.com`);
- await ctx.tab2.navigate(link);
- await ctx.tab2.pages.home.completeSignIn("Darth Vader");
+ await ctx.tab2.pages.home.navigate()
+ await ctx.tab2.pages.home.signInWithEmail("darthvader.fider@gmail.com")
+ const link = await mailgun.getLinkFromLastEmailTo(ctx.tenantSubdomain, `Sign in to ${ctx.tenantName}`, `darthvader.fider@gmail.com`)
+ await ctx.tab2.navigate(link)
+ await ctx.tab2.pages.home.completeSignIn("Darth Vader")
// Assert
- await ensure(ctx.tab2.pages.home.UserName).textIs("Darth Vader");
-});
+ await ensure(ctx.tab2.pages.home.UserName).textIs("Darth Vader")
+})
diff --git a/tests/scenarios/index.ts b/tests/scenarios/index.ts
index 01cec1144..91553e1ac 100644
--- a/tests/scenarios/index.ts
+++ b/tests/scenarios/index.ts
@@ -1,27 +1,27 @@
-import { Browser, BrowserTab, pageHasLoaded, ensure, elementIsNotVisible, delay, elementIsVisible, mailgun } from "../lib";
-import { HomePage, ShowPostPage } from "../pages";
+import { Browser, BrowserTab, pageHasLoaded } from "../lib"
+import { HomePage } from "../pages"
export interface TestContext {
- browser1: Browser;
- browser2: Browser;
- tab1: BrowserTab;
- tab2: BrowserTab;
- tenantName: string;
- tenantSubdomain: string;
+ browser1: Browser
+ browser2: Browser
+ tab1: BrowserTab
+ tab2: BrowserTab
+ tenantName: string
+ tenantSubdomain: string
}
-export let ctx: TestContext;
+export let ctx: TestContext
describe("E2E", () => {
beforeAll(async () => {
- const now = new Date().getTime();
- const tenantName = `Selenium ${now}`;
- const tenantSubdomain = process.env.HOST_MODE === "single" ? "login" : `selenium${now}`;
- const baseURL = `https://${tenantSubdomain}.dev.fider.io:3000`;
- const browser1 = await Browser.launch();
- const tab1 = await browser1.newTab(baseURL);
- const browser2 = await Browser.launch();
- const tab2 = await browser2.newTab(baseURL);
+ const now = new Date().getTime()
+ const tenantName = `Selenium ${now}`
+ const tenantSubdomain = process.env.HOST_MODE === "single" ? "login" : `selenium${now}`
+ const baseURL = `https://${tenantSubdomain}.dev.fider.io:3000`
+ const browser1 = await Browser.launch()
+ const tab1 = await browser1.newTab(baseURL)
+ const browser2 = await Browser.launch()
+ const tab2 = await browser2.newTab(baseURL)
ctx = {
tenantName,
@@ -30,29 +30,29 @@ describe("E2E", () => {
tab1,
browser2,
tab2,
- };
- });
+ }
+ })
afterAll(async () => {
- await ctx.browser1.close();
- await ctx.browser2.close();
- });
+ await ctx.browser1.close()
+ await ctx.browser2.close()
+ })
it("Tab1: User can sign up with facebook", async () => {
- await ctx.tab1.pages.signup.navigate();
- await ctx.tab1.pages.signup.signInWithFacebook();
- await ctx.tab1.pages.facebook.signInAsJonSnow();
+ await ctx.tab1.pages.signup.navigate()
+ await ctx.tab1.pages.signup.signInWithFacebook()
+ await ctx.tab1.pages.facebook.signInAsJonSnow()
- await ctx.tab1.pages.signup.signUpAs(ctx.tenantName, ctx.tenantSubdomain);
+ await ctx.tab1.pages.signup.signUpAs(ctx.tenantName, ctx.tenantSubdomain)
- await ctx.tab1.wait(pageHasLoaded(HomePage));
- });
+ await ctx.tab1.wait(pageHasLoaded(HomePage))
+ })
describe("E2E: Feedback Loop", () => {
- require("./feedback-loop");
- });
+ require("./feedback-loop")
+ })
describe("E2E: Admin Settings", () => {
- require("./admin-settings");
- });
-});
+ require("./admin-settings")
+ })
+})
diff --git a/tests/single.spec.ts b/tests/single.spec.ts
index 2659f7c44..7ef2c1a58 100644
--- a/tests/single.spec.ts
+++ b/tests/single.spec.ts
@@ -1,3 +1,3 @@
-process.env.HOST_MODE = "single";
-jest.setTimeout(30000);
-require("./scenarios/index");
+process.env.HOST_MODE = "single"
+jest.setTimeout(30000)
+require("./scenarios/index")
diff --git a/tslint.json b/tslint.json
deleted file mode 100644
index 02c0ed9c9..000000000
--- a/tslint.json
+++ /dev/null
@@ -1,14 +0,0 @@
-{
- "extends": ["tslint:recommended", "tslint-react", "tslint-plugin-prettier", "tslint-config-prettier"],
- "rules": {
- "interface-name": [false],
- "jsx-no-multiline-js": false,
- "max-classes-per-file": [false],
- "member-ordering": [false],
- "no-bitwise": false,
- "no-var-requires": false,
- "object-literal-sort-keys": false,
- "ordered-imports": [false],
- "prettier": [true]
- }
-}
diff --git a/webpack.config.js b/webpack.config.js
index c3bd47716..ebb567dbc 100755
--- a/webpack.config.js
+++ b/webpack.config.js
@@ -1,11 +1,13 @@
-const path = require("path");
+/* eslint-disable no-undef */
+/* eslint-disable @typescript-eslint/no-var-requires */
+const path = require("path")
-const MiniCssExtractPlugin = require("mini-css-extract-plugin");
-const ForkTsCheckerWebpackPlugin = require("fork-ts-checker-webpack-plugin");
-const BundleAnalyzerPlugin = require("webpack-bundle-analyzer").BundleAnalyzerPlugin;
-const publicFolder = path.resolve(__dirname, "public");
+const MiniCssExtractPlugin = require("mini-css-extract-plugin")
+const ForkTsCheckerWebpackPlugin = require("fork-ts-checker-webpack-plugin")
+const BundleAnalyzerPlugin = require("webpack-bundle-analyzer").BundleAnalyzerPlugin
+const publicFolder = path.resolve(__dirname, "public")
-const isProduction = process.env.NODE_ENV === "production";
+const isProduction = process.env.NODE_ENV === "production"
const plugins = [
new MiniCssExtractPlugin({
@@ -26,10 +28,10 @@ const plugins = [
modules: false,
},
}),
-];
+]
// On Development Mode, we allow Assets to be up to 14 times bigger than on Production Mode
-const maxSizeFactor = isProduction ? 1 : 14;
+const maxSizeFactor = isProduction ? 1 : 14
module.exports = {
mode: process.env.NODE_ENV || "development",
@@ -79,8 +81,8 @@ module.exports = {
],
},
optimization: {
- moduleIds: 'deterministic',
- runtimeChunk: 'single',
+ moduleIds: "deterministic",
+ runtimeChunk: "single",
splitChunks: {
cacheGroups: {
common: {
@@ -89,14 +91,14 @@ module.exports = {
test: /[\\/]public[\\/](components|services|models)[\\/]/,
},
markdown: {
- chunks: 'all',
- name: 'markdown',
- test: /dompurify|marked/
+ chunks: "all",
+ name: "markdown",
+ test: /dompurify|marked/,
},
vendor: {
- chunks: 'all',
- name: 'vendor',
- test: /react|react-dom|tslib|react-textarea-autosize|react-icons/
+ chunks: "all",
+ name: "vendor",
+ test: /react|react-dom|tslib|react-textarea-autosize|react-icons/,
},
},
},
@@ -108,4 +110,4 @@ module.exports = {
entrypoints: false,
modules: false,
},
-};
\ No newline at end of file
+}