aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLibravatar MCMXC <16797721+mcmxcdev@users.noreply.github.com>2023-07-29 21:12:16 -0600
committerLibravatar GitHub <noreply@github.com>2023-07-30 08:42:16 +0530
commit32f76b74a69ad4d60a014bf075c39517888436bc (patch)
tree753378cc30f52d1e0e51be64b5a83d39f08f39c8
parent6.4.1-nightly.15 [skip ci] (diff)
downloadferdium-app-32f76b74a69ad4d60a014bf075c39517888436bc.tar.gz
ferdium-app-32f76b74a69ad4d60a014bf075c39517888436bc.tar.zst
ferdium-app-32f76b74a69ad4d60a014bf075c39517888436bc.zip
refactor: various improvements (#1296)
* refactor: various improvements - enable no-use-before-define eslint rule - shuffle code to conform to no-use-before-define eslint rule - remove btoa dependency which is deprecated and replace with Buffer.from(string).toString('base64') - convert some any types into useful ones - add type annotations where possible - remove unused @types/expect.js - install @types/semver and ts-node which were missing - repair and rewrite add-crowdin-contributors script - remove export keyword from variables which are never consumed in another file - remove unity indicator hack where linked issue was closed - remove module declaration for kebab-case which is unused - add missing state interface for certain components - remove default exports for files which already have a named export - export IRecipePreview so it can be used throughout codebase - remove unused removeCacheForCallWith method from CachedRequest.ts - cleanup unused colors and styles inside legacy theme * - improve ColorPickerInput - fix invalid DOM nesting with div inside p in EditSettingsForm - fix progressbarAccentColor color picker not updating input when using slider - install missing @types/react-color dependency
-rw-r--r--.eslintrc.js3
-rw-r--r--package.json5
-rw-r--r--pnpm-lock.yaml45
-rw-r--r--scripts/add-crowdin-contributors.ts42
-rw-r--r--src/@types/kebab-case.d.ts1
-rw-r--r--src/@types/mobx-form.types.ts32
-rw-r--r--src/@types/stores.types.ts9
-rw-r--r--src/actions/index.ts4
-rw-r--r--src/api/server/ServerApi.ts30
-rw-r--r--src/components/auth/Login.tsx2
-rw-r--r--src/components/layout/Sidebar.tsx2
-rw-r--r--src/components/settings/releaseNotes/ReleaseNotesDashboard.tsx12
-rw-r--r--src/components/settings/releaseNotes/ReleaseNotesLayout.tsx1
-rw-r--r--src/components/settings/settings/EditSettingsForm.tsx68
-rw-r--r--src/components/ui/badge/ProBadge.tsx14
-rw-r--r--src/components/ui/badge/index.tsx18
-rw-r--r--src/components/ui/button/index.tsx3
-rw-r--r--src/components/ui/colorPickerInput/index.tsx37
-rw-r--r--src/components/ui/headline/index.tsx16
-rw-r--r--src/components/ui/icon/index.tsx12
-rw-r--r--src/components/ui/infobox/index.tsx1
-rw-r--r--src/components/ui/loader/index.tsx13
-rw-r--r--src/components/ui/toggle/index.tsx14
-rw-r--r--src/components/ui/typings/generic.ts2
-rw-r--r--src/components/ui/wrapper/index.tsx2
-rw-r--r--src/components/util/ErrorBoundary/index.tsx16
-rw-r--r--src/config.ts6
-rw-r--r--src/containers/auth/AuthReleaseNotesScreen.tsx12
-rw-r--r--src/containers/settings/EditSettingsScreen.tsx19
-rw-r--r--src/containers/settings/EditUserScreen.tsx4
-rw-r--r--src/features/communityRecipes/store.ts2
-rw-r--r--src/features/todos/actions.ts2
-rw-r--r--src/features/workspaces/actions.ts3
-rw-r--r--src/i18n/languages.ts2
-rw-r--r--src/index.ts17
-rw-r--r--src/internal-server/app/Controllers/Http/UserController.js5
-rw-r--r--src/models/RecipePreview.ts2
-rw-r--r--src/stores/ServicesStore.ts17
-rw-r--r--src/stores/lib/CachedRequest.ts6
-rw-r--r--src/stores/lib/Request.ts1
-rw-r--r--src/themes/default/index.ts2
-rw-r--r--src/themes/legacy/index.ts11
-rw-r--r--src/webview/contextMenuBuilder.ts7
43 files changed, 254 insertions, 268 deletions
diff --git a/.eslintrc.js b/.eslintrc.js
index db66bbc4a..ef8af48c8 100644
--- a/.eslintrc.js
+++ b/.eslintrc.js
@@ -47,6 +47,9 @@ module.exports = {
47 parser: '@typescript-eslint/parser', 47 parser: '@typescript-eslint/parser',
48 plugins: [], 48 plugins: [],
49 rules: { 49 rules: {
50 // eslint
51 'no-use-before-define': 2,
52
50 // @typescript-eslint 53 // @typescript-eslint
51 // This is necessary as workaround for window.ferdium vs window['ferdium'] 54 // This is necessary as workaround for window.ferdium vs window['ferdium']
52 '@typescript-eslint/dot-notation': 0, 55 '@typescript-eslint/dot-notation': 0,
diff --git a/package.json b/package.json
index 45628a99d..e3e4a4f44 100644
--- a/package.json
+++ b/package.json
@@ -69,7 +69,6 @@
69 "@sentry/electron": "4.1.2", 69 "@sentry/electron": "4.1.2",
70 "@superwf/mobx-react-router": "7.4.0", 70 "@superwf/mobx-react-router": "7.4.0",
71 "auto-launch": "5.0.6", 71 "auto-launch": "5.0.6",
72 "btoa": "1.2.1",
73 "classnames": "2.3.2", 72 "classnames": "2.3.2",
74 "color": "4.2.3", 73 "color": "4.2.3",
75 "csstype": "3.1.2", 74 "csstype": "3.1.2",
@@ -137,7 +136,6 @@
137 "@formatjs/cli": "6.1.3", 136 "@formatjs/cli": "6.1.3",
138 "@jest/types": "29.6.1", 137 "@jest/types": "29.6.1",
139 "@types/color": "3.0.3", 138 "@types/color": "3.0.3",
140 "@types/expect.js": "0.3.29",
141 "@types/fs-extra": "11.0.1", 139 "@types/fs-extra": "11.0.1",
142 "@types/jest": "29.5.3", 140 "@types/jest": "29.5.3",
143 "@types/lodash": "4.14.195", 141 "@types/lodash": "4.14.195",
@@ -145,10 +143,12 @@
145 "@types/node": "18.15.3", 143 "@types/node": "18.15.3",
146 "@types/prop-types": "15.7.5", 144 "@types/prop-types": "15.7.5",
147 "@types/react": "18.2.12", 145 "@types/react": "18.2.12",
146 "@types/react-color": "3.0.6",
148 "@types/react-dom": "18.2.5", 147 "@types/react-dom": "18.2.5",
149 "@types/react-loader": "2.4.5", 148 "@types/react-loader": "2.4.5",
150 "@types/react-transition-group": "4.4.6", 149 "@types/react-transition-group": "4.4.6",
151 "@types/route-parser": "0.1.4", 150 "@types/route-parser": "0.1.4",
151 "@types/semver": "7.5.0",
152 "@types/tar": "6.1.5", 152 "@types/tar": "6.1.5",
153 "@types/uuid": "9.0.2", 153 "@types/uuid": "9.0.2",
154 "@types/validator": "13.7.17", 154 "@types/validator": "13.7.17",
@@ -184,6 +184,7 @@
184 "rimraf": "5.0.1", 184 "rimraf": "5.0.1",
185 "simple-git": "3.19.1", 185 "simple-git": "3.19.1",
186 "tiny-glob": "0.2.9", 186 "tiny-glob": "0.2.9",
187 "ts-node": "10.9.1",
187 "typescript": "5.0.4", 188 "typescript": "5.0.4",
188 "wait-on": "7.0.1" 189 "wait-on": "7.0.1"
189 }, 190 },
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 4c96e3e65..17b636a08 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -68,9 +68,6 @@ dependencies:
68 auto-launch: 68 auto-launch:
69 specifier: 5.0.6 69 specifier: 5.0.6
70 version: 5.0.6 70 version: 5.0.6
71 btoa:
72 specifier: 1.2.1
73 version: 1.2.1
74 classnames: 71 classnames:
75 specifier: 2.3.2 72 specifier: 2.3.2
76 version: 2.3.2 73 version: 2.3.2
@@ -276,9 +273,6 @@ devDependencies:
276 '@types/color': 273 '@types/color':
277 specifier: 3.0.3 274 specifier: 3.0.3
278 version: 3.0.3 275 version: 3.0.3
279 '@types/expect.js':
280 specifier: 0.3.29
281 version: 0.3.29
282 '@types/fs-extra': 276 '@types/fs-extra':
283 specifier: 11.0.1 277 specifier: 11.0.1
284 version: 11.0.1 278 version: 11.0.1
@@ -300,6 +294,9 @@ devDependencies:
300 '@types/react': 294 '@types/react':
301 specifier: 18.2.12 295 specifier: 18.2.12
302 version: 18.2.12 296 version: 18.2.12
297 '@types/react-color':
298 specifier: 3.0.6
299 version: 3.0.6
303 '@types/react-dom': 300 '@types/react-dom':
304 specifier: 18.2.5 301 specifier: 18.2.5
305 version: 18.2.5 302 version: 18.2.5
@@ -312,6 +309,9 @@ devDependencies:
312 '@types/route-parser': 309 '@types/route-parser':
313 specifier: 0.1.4 310 specifier: 0.1.4
314 version: 0.1.4 311 version: 0.1.4
312 '@types/semver':
313 specifier: 7.5.0
314 version: 7.5.0
315 '@types/tar': 315 '@types/tar':
316 specifier: 6.1.5 316 specifier: 6.1.5
317 version: 6.1.5 317 version: 6.1.5
@@ -417,6 +417,9 @@ devDependencies:
417 tiny-glob: 417 tiny-glob:
418 specifier: 0.2.9 418 specifier: 0.2.9
419 version: 0.2.9 419 version: 0.2.9
420 ts-node:
421 specifier: 10.9.1
422 version: 10.9.1(@types/node@18.15.3)(typescript@5.0.4)
420 typescript: 423 typescript:
421 specifier: 5.0.4 424 specifier: 5.0.4
422 version: 5.0.4 425 version: 5.0.4
@@ -2421,10 +2424,6 @@ packages:
2421 '@types/ms': 0.7.31 2424 '@types/ms': 0.7.31
2422 dev: true 2425 dev: true
2423 2426
2424 /@types/expect.js@0.3.29:
2425 resolution: {integrity: sha512-zLlr7lW52PKk7GAMJc2v8zaVJUgkrOJBa+6/aGbzq/TYsrqrNT719kkf/98lrgCiV+VO/uwJM0E328NGtcB5yQ==}
2426 dev: true
2427
2428 /@types/fs-extra@11.0.1: 2427 /@types/fs-extra@11.0.1:
2429 resolution: {integrity: sha512-MxObHvNl4A69ofaTRU8DFqvgzzv8s9yRtaPPm5gud9HDNvpB3GPQFvNuTWAI59B9huVGV5jXYJwbCsmBsOGYWA==} 2428 resolution: {integrity: sha512-MxObHvNl4A69ofaTRU8DFqvgzzv8s9yRtaPPm5gud9HDNvpB3GPQFvNuTWAI59B9huVGV5jXYJwbCsmBsOGYWA==}
2430 dependencies: 2429 dependencies:
@@ -2531,6 +2530,13 @@ packages:
2531 /@types/prop-types@15.7.5: 2530 /@types/prop-types@15.7.5:
2532 resolution: {integrity: sha512-JCB8C6SnDoQf0cNycqd/35A7MjcnK+ZTqE7judS6o7utxUCg6imJg3QK2qzHKszlTjcj2cn+NwMB2i96ubpj7w==} 2531 resolution: {integrity: sha512-JCB8C6SnDoQf0cNycqd/35A7MjcnK+ZTqE7judS6o7utxUCg6imJg3QK2qzHKszlTjcj2cn+NwMB2i96ubpj7w==}
2533 2532
2533 /@types/react-color@3.0.6:
2534 resolution: {integrity: sha512-OzPIO5AyRmLA7PlOyISlgabpYUa3En74LP8mTMa0veCA719SvYQov4WLMsHvCgXP+L+KI9yGhYnqZafVGG0P4w==}
2535 dependencies:
2536 '@types/react': 18.2.12
2537 '@types/reactcss': 1.2.6
2538 dev: true
2539
2534 /@types/react-dom@18.2.5: 2540 /@types/react-dom@18.2.5:
2535 resolution: {integrity: sha512-sRQsOS/sCLnpQhR4DSKGTtWFE3FZjpQa86KPVbhUqdYMRZ9FEFcfAytKhR/vUG2rH1oFbOOej6cuD7MFSobDRQ==} 2541 resolution: {integrity: sha512-sRQsOS/sCLnpQhR4DSKGTtWFE3FZjpQa86KPVbhUqdYMRZ9FEFcfAytKhR/vUG2rH1oFbOOej6cuD7MFSobDRQ==}
2536 dependencies: 2542 dependencies:
@@ -2556,6 +2562,12 @@ packages:
2556 '@types/scheduler': 0.16.2 2562 '@types/scheduler': 0.16.2
2557 csstype: 3.1.2 2563 csstype: 3.1.2
2558 2564
2565 /@types/reactcss@1.2.6:
2566 resolution: {integrity: sha512-qaIzpCuXNWomGR1Xq8SCFTtF4v8V27Y6f+b9+bzHiv087MylI/nTCqqdChNeWS7tslgROmYB7yeiruWX7WnqNg==}
2567 dependencies:
2568 '@types/react': 18.2.12
2569 dev: true
2570
2559 /@types/responselike@1.0.0: 2571 /@types/responselike@1.0.0:
2560 resolution: {integrity: sha512-85Y2BjiufFzaMIlvJDvTTB8Fxl2xfLo4HgmHzVBz08w4wDePCTjYw66PdrolO0kzli3yam/YCgRufyo1DdQVTA==} 2572 resolution: {integrity: sha512-85Y2BjiufFzaMIlvJDvTTB8Fxl2xfLo4HgmHzVBz08w4wDePCTjYw66PdrolO0kzli3yam/YCgRufyo1DdQVTA==}
2561 dependencies: 2573 dependencies:
@@ -2568,13 +2580,8 @@ packages:
2568 /@types/scheduler@0.16.2: 2580 /@types/scheduler@0.16.2:
2569 resolution: {integrity: sha512-hppQEBDmlwhFAXKJX2KnWLYu5yMfi91yazPb2l+lbJiwW+wdo1gNeRA+3RgNSO39WYX2euey41KEwnqesU2Jew==} 2581 resolution: {integrity: sha512-hppQEBDmlwhFAXKJX2KnWLYu5yMfi91yazPb2l+lbJiwW+wdo1gNeRA+3RgNSO39WYX2euey41KEwnqesU2Jew==}
2570 2582
2571 /@types/semver@7.3.13:
2572 resolution: {integrity: sha512-21cFJr9z3g5dW8B0CVI9g2O9beqaThGQ6ZFBqHfwhzLDKUxaqTIy3vnfah/UPkfOiF2pLq+tGz+W8RyCskuslw==}
2573 dev: false
2574
2575 /@types/semver@7.5.0: 2583 /@types/semver@7.5.0:
2576 resolution: {integrity: sha512-G8hZ6XJiHnuhQKR7ZmysCeJWE08o8T0AXtk5darsCaTVsYZhhgUrq53jizaR2FvsoeCwJhlmwTjkXBY5Pn/ZHw==} 2584 resolution: {integrity: sha512-G8hZ6XJiHnuhQKR7ZmysCeJWE08o8T0AXtk5darsCaTVsYZhhgUrq53jizaR2FvsoeCwJhlmwTjkXBY5Pn/ZHw==}
2577 dev: true
2578 2585
2579 /@types/stack-trace@0.0.29: 2586 /@types/stack-trace@0.0.29:
2580 resolution: {integrity: sha512-TgfOX+mGY/NyNxJLIbDWrO9DjGoVSW9+aB8H2yy1fy32jsvxijhmyJI9fDFgvz3YP4lvJaq9DzdR/M1bOgVc9g==} 2587 resolution: {integrity: sha512-TgfOX+mGY/NyNxJLIbDWrO9DjGoVSW9+aB8H2yy1fy32jsvxijhmyJI9fDFgvz3YP4lvJaq9DzdR/M1bOgVc9g==}
@@ -3771,12 +3778,6 @@ packages:
3771 engines: {node: '>=0.6.19'} 3778 engines: {node: '>=0.6.19'}
3772 dev: false 3779 dev: false
3773 3780
3774 /btoa@1.2.1:
3775 resolution: {integrity: sha512-SB4/MIGlsiVkMcHmT+pSmIPoNDoHg+7cMzmt3Uxt628MTz2487DKSqK/fuhFBrkuqrYv5UCEnACpF4dTFNKc/g==}
3776 engines: {node: '>= 0.4.0'}
3777 hasBin: true
3778 dev: false
3779
3780 /buffer-alloc-unsafe@1.1.0: 3781 /buffer-alloc-unsafe@1.1.0:
3781 resolution: {integrity: sha512-TEM2iMIEQdJ2yjPJoSIsldnleVaAk1oW3DBVUykyOLsEsFmEc9kn+SFFPz+gl54KQNxlDnAwCXosOS9Okx2xAg==} 3782 resolution: {integrity: sha512-TEM2iMIEQdJ2yjPJoSIsldnleVaAk1oW3DBVUykyOLsEsFmEc9kn+SFFPz+gl54KQNxlDnAwCXosOS9Okx2xAg==}
3782 dev: false 3783 dev: false
@@ -5106,7 +5107,7 @@ packages:
5106 /electron-updater@5.3.0: 5107 /electron-updater@5.3.0:
5107 resolution: {integrity: sha512-iKEr7yQBcvnQUPnSDYGSWC9t0eF2YbZWeYYYZzYxdl+HiRejXFENjYMnYjoOm2zxyD6Cr2JTHZhp9pqxiXuCOw==} 5108 resolution: {integrity: sha512-iKEr7yQBcvnQUPnSDYGSWC9t0eF2YbZWeYYYZzYxdl+HiRejXFENjYMnYjoOm2zxyD6Cr2JTHZhp9pqxiXuCOw==}
5108 dependencies: 5109 dependencies:
5109 '@types/semver': 7.3.13 5110 '@types/semver': 7.5.0
5110 builder-util-runtime: 9.1.1 5111 builder-util-runtime: 9.1.1
5111 fs-extra: 10.1.0 5112 fs-extra: 10.1.0
5112 js-yaml: 4.1.0 5113 js-yaml: 4.1.0
diff --git a/scripts/add-crowdin-contributors.ts b/scripts/add-crowdin-contributors.ts
index 242d338ce..7a0d0e769 100644
--- a/scripts/add-crowdin-contributors.ts
+++ b/scripts/add-crowdin-contributors.ts
@@ -53,7 +53,7 @@ console.log(JSON.stringify(members));
53 * 5. Regenerate the README table using the CLI ('all-contributors generate') 53 * 5. Regenerate the README table using the CLI ('all-contributors generate')
54 * Please check if the generated data is ok and no data is lost. 54 * Please check if the generated data is ok and no data is lost.
55*/ 55*/
56const list: any[] = [ 56const list: { name: string; login: string; avatar_url: string }[] = [
57 { 57 {
58 name: 'vantezzen_', 58 name: 'vantezzen_',
59 login: 'vantezzen_', 59 login: 'vantezzen_',
@@ -1064,21 +1064,27 @@ const list: any[] = [
1064 }, 1064 },
1065]; 1065];
1066 1066
1067const infoPath = path.join(__dirname, '..', '.all-contributorsrc'); 1067const allContributorsFile = path.join(__dirname, '..', '.all-contributorsrc');
1068const info = fs.readJSONSync(infoPath); 1068const allContributorsJSON = fs.readJSONSync(allContributorsFile);
1069for (const user of list) {
1070 if (user.login) {
1071 info.contributors = allContributors.addContributorWithDetails({
1072 ...user,
1073 contributions: ['translation'],
1074 profile: `https://crowdin.com/profile/${user.login}`,
1075 options: {
1076 contributors: info.contributors,
1077 },
1078 });
1079 }
1080}
1081 1069
1082fs.writeJSONSync(infoPath, info, { 1070// eslint-disable-next-line unicorn/prefer-top-level-await
1083 spaces: 2, 1071(async () => {
1084}); 1072 allContributorsJSON.contributors = await Promise.all(
1073 list
1074 .filter(user => user.login)
1075 .map(user => {
1076 return allContributors.addContributorWithDetails({
1077 ...user,
1078 contributions: ['translation'],
1079 profile: `https://crowdin.com/profile/${user.login}`,
1080 options: {
1081 contributors: allContributorsJSON.contributors,
1082 },
1083 });
1084 }),
1085 );
1086
1087 fs.writeJSONSync(allContributorsFile, allContributorsJSON, {
1088 spaces: 2,
1089 });
1090})();
diff --git a/src/@types/kebab-case.d.ts b/src/@types/kebab-case.d.ts
deleted file mode 100644
index 712405ac0..000000000
--- a/src/@types/kebab-case.d.ts
+++ /dev/null
@@ -1 +0,0 @@
1declare module 'kebab-case';
diff --git a/src/@types/mobx-form.types.ts b/src/@types/mobx-form.types.ts
index 07234a47a..aa274b9db 100644
--- a/src/@types/mobx-form.types.ts
+++ b/src/@types/mobx-form.types.ts
@@ -1,17 +1,17 @@
1import { File } from 'electron-dl';
2import { ChangeEventHandler, FocusEventHandler } from 'react'; 1import { ChangeEventHandler, FocusEventHandler } from 'react';
3import { GlobalError } from './ferdium-components.types'; 2import { GlobalError } from './ferdium-components.types';
4 3
5export interface FormFieldOptions { 4interface SelectOptions {
6 value?: string;
7 label?: string;
8 disabled?: boolean; 5 disabled?: boolean;
6 label?: string;
7 value?: string;
9} 8}
10 9
11export interface FormFields { 10interface Listeners {
12 fields: { 11 onChange?: ChangeEventHandler<HTMLInputElement | HTMLSelectElement>;
13 [key: string]: Field; 12 onBlur?: FocusEventHandler<HTMLElement>;
14 }; 13 onFocus?: FocusEventHandler<HTMLElement>;
14 onDrop?: (file: File) => void;
15} 15}
16 16
17export interface Field extends Listeners { 17export interface Field extends Listeners {
@@ -29,16 +29,8 @@ export interface Field extends Listeners {
29 set?: (value: any) => void; 29 set?: (value: any) => void;
30 [key: string]: any; 30 [key: string]: any;
31} 31}
32 32export interface FormFields {
33export interface SelectOptions { 33 fields: {
34 disabled?: boolean; 34 [key: string]: Field;
35 label?: string; 35 };
36 value?: string;
37}
38
39export interface Listeners {
40 onChange?: ChangeEventHandler<HTMLInputElement | HTMLSelectElement>;
41 onBlur?: FocusEventHandler<HTMLElement>;
42 onFocus?: FocusEventHandler<HTMLElement>;
43 onDrop?: (file: File) => void;
44} 36}
diff --git a/src/@types/stores.types.ts b/src/@types/stores.types.ts
index ff8f127ed..dc5da563f 100644
--- a/src/@types/stores.types.ts
+++ b/src/@types/stores.types.ts
@@ -1,3 +1,4 @@
1/* eslint-disable no-use-before-define */
1import Workspace from '../features/workspaces/models/Workspace'; 2import Workspace from '../features/workspaces/models/Workspace';
2import Recipe from '../models/Recipe'; 3import Recipe from '../models/Recipe';
3import Service from '../models/Service'; 4import Service from '../models/Service';
@@ -201,7 +202,7 @@ interface RouterStore {
201 replace: () => void; 202 replace: () => void;
202} 203}
203 204
204export interface ServicesStore extends TypedStore { 205interface ServicesStore extends TypedStore {
205 clearCacheRequest: () => void; 206 clearCacheRequest: () => void;
206 createServiceRequest: CachedRequest; 207 createServiceRequest: CachedRequest;
207 deleteServiceRequest: () => void; 208 deleteServiceRequest: () => void;
@@ -227,7 +228,7 @@ interface ISettings {
227 [key: string]: any; 228 [key: string]: any;
228} 229}
229 230
230export interface SettingsStore extends TypedStore { 231interface SettingsStore extends TypedStore {
231 update: (value: any) => void; 232 update: (value: any) => void;
232 remove: (value: any) => void; 233 remove: (value: any) => void;
233 fileSystemSettingsTypes: any[]; 234 fileSystemSettingsTypes: any[];
@@ -288,7 +289,7 @@ interface UIStore extends TypedStore {
288 theme: () => void; 289 theme: () => void;
289} 290}
290 291
291export interface UserStore extends TypedStore { 292interface UserStore extends TypedStore {
292 BASE_ROUTE: '/auth'; 293 BASE_ROUTE: '/auth';
293 CHANGE_SERVER_ROUTE: '/auth/server'; 294 CHANGE_SERVER_ROUTE: '/auth/server';
294 IMPORT_ROUTE: '/auth/signup/import'; 295 IMPORT_ROUTE: '/auth/signup/import';
@@ -338,7 +339,7 @@ export interface UserStore extends TypedStore {
338 team: () => void; 339 team: () => void;
339} 340}
340 341
341export interface WorkspacesStore extends TypedStore { 342interface WorkspacesStore extends TypedStore {
342 activeWorkspace: () => void; 343 activeWorkspace: () => void;
343 delete: ({ workspace }) => void; 344 delete: ({ workspace }) => void;
344 update: ({ workspace }) => void; 345 update: ({ workspace }) => void;
diff --git a/src/actions/index.ts b/src/actions/index.ts
index 983afa64b..5297a7a7b 100644
--- a/src/actions/index.ts
+++ b/src/actions/index.ts
@@ -10,7 +10,7 @@ import user from './user';
10import settings from './settings'; 10import settings from './settings';
11import requests from './requests'; 11import requests from './requests';
12import workspaces from '../features/workspaces/actions'; 12import workspaces from '../features/workspaces/actions';
13import todos from '../features/todos/actions'; 13import { todoActions } from '../features/todos/actions';
14 14
15const actions = { 15const actions = {
16 service, 16 service,
@@ -26,5 +26,5 @@ const actions = {
26export default Object.assign( 26export default Object.assign(
27 defineActions(actions, PropTypes.checkPropTypes), 27 defineActions(actions, PropTypes.checkPropTypes),
28 { workspaces }, 28 { workspaces },
29 { todos }, 29 { todos: todoActions },
30); 30);
diff --git a/src/api/server/ServerApi.ts b/src/api/server/ServerApi.ts
index 860b7b76e..de8e0a85c 100644
--- a/src/api/server/ServerApi.ts
+++ b/src/api/server/ServerApi.ts
@@ -15,8 +15,8 @@ import {
15} from 'fs-extra'; 15} from 'fs-extra';
16 16
17import ServiceModel from '../../models/Service'; 17import ServiceModel from '../../models/Service';
18import RecipePreviewModel from '../../models/RecipePreview'; 18import RecipePreviewModel, { IRecipePreview } from '../../models/RecipePreview';
19import RecipeModel from '../../models/Recipe'; 19import RecipeModel, { IRecipe } from '../../models/Recipe';
20import UserModel from '../../models/User'; 20import UserModel from '../../models/User';
21 21
22import sleep from '../../helpers/async-helpers'; 22import sleep from '../../helpers/async-helpers';
@@ -44,9 +44,9 @@ const debug = require('../../preload-safe-debug')('Ferdium:ServerApi');
44module.paths.unshift(getDevRecipeDirectory(), getRecipeDirectory()); 44module.paths.unshift(getDevRecipeDirectory(), getRecipeDirectory());
45 45
46export default class ServerApi { 46export default class ServerApi {
47 recipePreviews: any[] = []; 47 recipePreviews: IRecipePreview[] = [];
48 48
49 recipes: any[] = []; 49 recipes: IRecipe[] = [];
50 50
51 // User 51 // User
52 async login(email: string, passwordHash: string) { 52 async login(email: string, passwordHash: string) {
@@ -55,7 +55,9 @@ export default class ServerApi {
55 { 55 {
56 method: 'POST', 56 method: 'POST',
57 headers: { 57 headers: {
58 Authorization: `Basic ${window.btoa(`${email}:${passwordHash}`)}`, 58 Authorization: `Basic ${Buffer.from(
59 `${email}:${passwordHash}`,
60 ).toString('base64')}`,
59 }, 61 },
60 }, 62 },
61 false, 63 false,
@@ -346,6 +348,7 @@ export default class ServerApi {
346 }) 348 })
347 .filter(recipe => recipe.id); 349 .filter(recipe => recipe.id);
348 350
351 // @ts-expect-error Type 'boolean' is not assignable to type 'ConcatArray<IRecipe>'.
349 // eslint-disable-next-line unicorn/prefer-spread 352 // eslint-disable-next-line unicorn/prefer-spread
350 this.recipes = this.recipes.concat(this._getDevRecipes()); 353 this.recipes = this.recipes.concat(this._getDevRecipes());
351 354
@@ -515,9 +518,8 @@ export default class ServerApi {
515 } 518 }
516 519
517 async _prepareServiceModel(service: { recipeId: string }) { 520 async _prepareServiceModel(service: { recipeId: string }) {
518 let recipe: undefined;
519 try { 521 try {
520 recipe = this.recipes.find(r => r.id === service.recipeId); 522 const recipe = this.recipes.find(r => r.id === service.recipeId);
521 523
522 if (!recipe) { 524 if (!recipe) {
523 console.warn(`Recipe ${service.recipeId} not loaded`); 525 console.warn(`Recipe ${service.recipeId} not loaded`);
@@ -531,11 +533,10 @@ export default class ServerApi {
531 } 533 }
532 } 534 }
533 535
534 async _bulkRecipeCheck(unfilteredRecipes: any[]) { 536 async _bulkRecipeCheck(unfilteredRecipes: string[]) {
535 // Filter recipe duplicates as we don't need to download 3 Slack recipes 537 // Filter recipe duplicates as we don't need to download 3 Slack recipes
536 const recipes = unfilteredRecipes.filter( 538 const recipes = unfilteredRecipes.filter(
537 (elem: any, pos: number, arr: string | any[]) => 539 (elem: string, pos: number, arr: string[]) => arr.indexOf(elem) === pos,
538 arr.indexOf(elem) === pos,
539 ); 540 );
540 541
541 return Promise.all( 542 return Promise.all(
@@ -565,7 +566,7 @@ export default class ServerApi {
565 ).catch(error => console.error("Can't load recipe", error)); 566 ).catch(error => console.error("Can't load recipe", error));
566 } 567 }
567 568
568 _mapRecipePreviewModel(recipes: any[]) { 569 _mapRecipePreviewModel(recipes: IRecipePreview[]) {
569 return recipes 570 return recipes
570 .map(recipe => { 571 .map(recipe => {
571 try { 572 try {
@@ -575,7 +576,7 @@ export default class ServerApi {
575 return null; 576 return null;
576 } 577 }
577 }) 578 })
578 .filter(recipe => recipe !== null); 579 .filter(Boolean);
579 } 580 }
580 581
581 _getDevRecipes() { 582 _getDevRecipes() {
@@ -589,15 +590,14 @@ export default class ServerApi {
589 590
590 const recipes = paths 591 const recipes = paths
591 .map(id => { 592 .map(id => {
592 let Recipe;
593 try { 593 try {
594 // eslint-disable-next-line import/no-dynamic-require 594 // eslint-disable-next-line import/no-dynamic-require
595 Recipe = require(id)(RecipeModel); 595 const Recipe = require(id)(RecipeModel);
596
596 return new Recipe(loadRecipeConfig(id)); 597 return new Recipe(loadRecipeConfig(id));
597 } catch (error) { 598 } catch (error) {
598 console.error(error); 599 console.error(error);
599 } 600 }
600
601 return false; 601 return false;
602 }) 602 })
603 .filter(recipe => recipe.id) 603 .filter(recipe => recipe.id)
diff --git a/src/components/auth/Login.tsx b/src/components/auth/Login.tsx
index eaa04256c..cf7abe654 100644
--- a/src/components/auth/Login.tsx
+++ b/src/components/auth/Login.tsx
@@ -99,7 +99,7 @@ class Login extends Component<IProps> {
99 submit(e: FormEvent<HTMLFormElement>): void { 99 submit(e: FormEvent<HTMLFormElement>): void {
100 e.preventDefault(); 100 e.preventDefault();
101 this.form.submit({ 101 this.form.submit({
102 onSuccess: form => { 102 onSuccess: (form: Form) => {
103 this.props.onSubmit(form.values()); 103 this.props.onSubmit(form.values());
104 }, 104 },
105 onError: noop, 105 onError: noop,
diff --git a/src/components/layout/Sidebar.tsx b/src/components/layout/Sidebar.tsx
index ceb9cfff9..6fd911a24 100644
--- a/src/components/layout/Sidebar.tsx
+++ b/src/components/layout/Sidebar.tsx
@@ -80,6 +80,7 @@ interface IProps extends WrappedComponentProps {
80 showServiceNameSetting: boolean; 80 showServiceNameSetting: boolean;
81 showMessageBadgesEvenWhenMuted: boolean; 81 showMessageBadgesEvenWhenMuted: boolean;
82 isAppMuted: boolean; 82 isAppMuted: boolean;
83 // eslint-disable-next-line react/no-unused-prop-types
83 isMenuCollapsed: boolean; 84 isMenuCollapsed: boolean;
84 isWorkspaceDrawerOpen: boolean; 85 isWorkspaceDrawerOpen: boolean;
85 isTodosServiceActive: boolean; 86 isTodosServiceActive: boolean;
@@ -90,6 +91,7 @@ interface IProps extends WrappedComponentProps {
90 toggleCollapseMenu: () => void; 91 toggleCollapseMenu: () => void;
91 toggleWorkspaceDrawer: () => void; 92 toggleWorkspaceDrawer: () => void;
92 openSettings: (args: { path: string }) => void; 93 openSettings: (args: { path: string }) => void;
94 // eslint-disable-next-line react/no-unused-prop-types
93 closeSettings: () => void; 95 closeSettings: () => void;
94 setActive: (args: { serviceId: string }) => void; 96 setActive: (args: { serviceId: string }) => void;
95 reorder: (args: { oldIndex: number; newIndex: number }) => void; 97 reorder: (args: { oldIndex: number; newIndex: number }) => void;
diff --git a/src/components/settings/releaseNotes/ReleaseNotesDashboard.tsx b/src/components/settings/releaseNotes/ReleaseNotesDashboard.tsx
index ff7c45bb1..9b17e551c 100644
--- a/src/components/settings/releaseNotes/ReleaseNotesDashboard.tsx
+++ b/src/components/settings/releaseNotes/ReleaseNotesDashboard.tsx
@@ -1,6 +1,6 @@
1import { Component } from 'react'; 1import { Component } from 'react';
2import { observer } from 'mobx-react'; 2import { observer } from 'mobx-react';
3import { defineMessages, injectIntl } from 'react-intl'; 3import { IntlShape, defineMessages, injectIntl } from 'react-intl';
4import Markdown from 'markdown-to-jsx'; 4import Markdown from 'markdown-to-jsx';
5import { ferdiumVersion } from '../../../environment-remote'; 5import { ferdiumVersion } from '../../../environment-remote';
6import { 6import {
@@ -26,14 +26,14 @@ const messages = defineMessages({
26}); 26});
27 27
28interface IProps { 28interface IProps {
29 intl: any; 29 intl: IntlShape;
30} 30}
31 31
32class ReleaseNotesDashboard extends Component<IProps> { 32interface IState {
33 state = { 33 data: string;
34 data: '', 34}
35 };
36 35
36class ReleaseNotesDashboard extends Component<IProps, IState> {
37 constructor(props) { 37 constructor(props) {
38 super(props); 38 super(props);
39 39
diff --git a/src/components/settings/releaseNotes/ReleaseNotesLayout.tsx b/src/components/settings/releaseNotes/ReleaseNotesLayout.tsx
index bc38aa603..4a6fe54f4 100644
--- a/src/components/settings/releaseNotes/ReleaseNotesLayout.tsx
+++ b/src/components/settings/releaseNotes/ReleaseNotesLayout.tsx
@@ -19,6 +19,7 @@ const messages = defineMessages({
19 19
20interface IProps extends WrappedComponentProps { 20interface IProps extends WrappedComponentProps {
21 actions?: Actions; 21 actions?: Actions;
22 // eslint-disable-next-line react/no-unused-prop-types
22 children?: React.ReactNode; 23 children?: React.ReactNode;
23} 24}
24 25
diff --git a/src/components/settings/settings/EditSettingsForm.tsx b/src/components/settings/settings/EditSettingsForm.tsx
index 11ae63737..099a27ebe 100644
--- a/src/components/settings/settings/EditSettingsForm.tsx
+++ b/src/components/settings/settings/EditSettingsForm.tsx
@@ -333,7 +333,7 @@ class EditSettingsForm extends Component<IProps, IState> {
333 } 333 }
334 334
335 this.props.form.submit({ 335 this.props.form.submit({
336 onSuccess: form => { 336 onSuccess: (form: Form) => {
337 const values = form.values(); 337 const values = form.values();
338 const { accentColor } = values; 338 const { accentColor } = values;
339 if (accentColor.trim().length === 0) { 339 if (accentColor.trim().length === 0) {
@@ -386,8 +386,9 @@ class EditSettingsForm extends Component<IProps, IState> {
386 const { lockingFeatureEnabled, scheduledDNDEnabled, reloadAfterResume } = 386 const { lockingFeatureEnabled, scheduledDNDEnabled, reloadAfterResume } =
387 window['ferdium'].stores.settings.all.app; 387 window['ferdium'].stores.settings.all.app;
388 388
389 let cacheSize; 389 let cacheSize: string;
390 let notCleared; 390 let notCleared: boolean;
391
391 if (this.state.activeSetttingsTab === 'advanced') { 392 if (this.state.activeSetttingsTab === 'advanced') {
392 const cacheSizeBytes = getCacheSize(); 393 const cacheSizeBytes = getCacheSize();
393 debug('cacheSizeBytes:', cacheSizeBytes); 394 debug('cacheSizeBytes:', cacheSizeBytes);
@@ -740,38 +741,35 @@ class EditSettingsForm extends Component<IProps, IState> {
740 defaultAccentColor: DEFAULT_APP_SETTINGS.accentColor, 741 defaultAccentColor: DEFAULT_APP_SETTINGS.accentColor,
741 })} 742 })}
742 </p> 743 </p>
743 <p> 744 <p>{intl.formatMessage(messages.overallTheme)}</p>
744 {intl.formatMessage(messages.overallTheme)} 745 <div className="settings__settings-group__apply-color">
745 <div className="settings__settings-group__apply-color"> 746 <ColorPickerInput
746 <ColorPickerInput 747 {...form.$('accentColor').bind()}
747 {...form.$('accentColor').bind()} 748 name="accentColor"
748 onColorChange={this.submit.bind(this)} 749 onColorChange={e => this.submit(e)}
749 className="color-picker-input" 750 className="color-picker-input"
750 /> 751 />
751 </div> 752 </div>
752 </p> 753 <p>{intl.formatMessage(messages.progressbarTheme)}</p>
753 <p> 754 <div className="settings__settings-group__apply-color">
754 {intl.formatMessage(messages.progressbarTheme)} 755 <ColorPickerInput
755 <div className="settings__settings-group__apply-color"> 756 {...form.$('progressbarAccentColor').bind()}
756 <ColorPickerInput 757 name="progressbarAccentColor"
757 {...form.$('progressbarAccentColor').bind()} 758 onColorChange={e => this.submit(e)}
758 onColorChange={this.submit.bind(this)} 759 className="color-picker-input"
759 className="color-picker-input" 760 />
760 /> 761 </div>
761 </div> 762
762 </p> 763 <div className="settings__settings-group__apply-color">
763 <p> 764 <Button
764 <div className="settings__settings-group__apply-color"> 765 buttonType="secondary"
765 <Button 766 className="settings__settings-group__apply-color__button"
766 buttonType="secondary" 767 label="Apply color"
767 className="settings__settings-group__apply-color__button" 768 onClick={e => {
768 label="Apply color" 769 this.submit(e);
769 onClick={e => { 770 }}
770 this.submit(e); 771 />
771 }} 772 </div>
772 />
773 </div>
774 </p>
775 <HrSections /> 773 <HrSections />
776 774
777 <H2 className="settings__section_header"> 775 <H2 className="settings__section_header">
diff --git a/src/components/ui/badge/ProBadge.tsx b/src/components/ui/badge/ProBadge.tsx
index 62c45b77c..a5947d3a8 100644
--- a/src/components/ui/badge/ProBadge.tsx
+++ b/src/components/ui/badge/ProBadge.tsx
@@ -7,13 +7,6 @@ import { Theme } from '../../../themes';
7import Icon from '../icon'; 7import Icon from '../icon';
8import Badge from './index'; 8import Badge from './index';
9 9
10interface IProps extends WithStylesProps<typeof styles> {
11 badgeClasses?: string;
12 iconClasses?: string;
13 inverted?: boolean;
14 className?: string;
15}
16
17const styles = (theme: Theme) => ({ 10const styles = (theme: Theme) => ({
18 badge: { 11 badge: {
19 height: 'auto', 12 height: 'auto',
@@ -32,6 +25,13 @@ const styles = (theme: Theme) => ({
32 }, 25 },
33}); 26});
34 27
28interface IProps extends WithStylesProps<typeof styles> {
29 badgeClasses?: string;
30 iconClasses?: string;
31 inverted?: boolean;
32 className?: string;
33}
34
35class ProBadgeComponent extends Component<IProps> { 35class ProBadgeComponent extends Component<IProps> {
36 render() { 36 render() {
37 const { classes, badgeClasses, iconClasses, inverted, className } = 37 const { classes, badgeClasses, iconClasses, inverted, className } =
diff --git a/src/components/ui/badge/index.tsx b/src/components/ui/badge/index.tsx
index 33e2f5d53..44fbf2d4a 100644
--- a/src/components/ui/badge/index.tsx
+++ b/src/components/ui/badge/index.tsx
@@ -4,23 +4,17 @@ import injectStyle, { WithStylesProps } from 'react-jss';
4 4
5import { Theme } from '../../../themes'; 5import { Theme } from '../../../themes';
6 6
7interface IProps extends WithStylesProps<typeof styles> {
8 type: string;
9 className?: string;
10 children: ReactNode;
11}
12
13const badgeStyles = (theme: Theme) => { 7const badgeStyles = (theme: Theme) => {
14 const styles = {}; 8 const styles = {};
15 Object.keys(theme.styleTypes).map(style => { 9 Object.keys(theme.styleTypes).map(style =>
16 Object.assign(styles, { 10 Object.assign(styles, {
17 [style]: { 11 [style]: {
18 background: theme.styleTypes[style].accent, 12 background: theme.styleTypes[style].accent,
19 color: theme.styleTypes[style].contrast, 13 color: theme.styleTypes[style].contrast,
20 border: theme.styleTypes[style].border, 14 border: theme.styleTypes[style].border,
21 }, 15 },
22 }); 16 }),
23 }); 17 );
24 18
25 return styles; 19 return styles;
26}; 20};
@@ -44,6 +38,12 @@ const styles = (theme: Theme) => ({
44 ...badgeStyles(theme), 38 ...badgeStyles(theme),
45}); 39});
46 40
41interface IProps extends WithStylesProps<typeof styles> {
42 type: string;
43 className?: string;
44 children: ReactNode;
45}
46
47class BadgeComponent extends Component<IProps> { 47class BadgeComponent extends Component<IProps> {
48 public static defaultProps = { 48 public static defaultProps = {
49 type: 'primary', 49 type: 'primary',
diff --git a/src/components/ui/button/index.tsx b/src/components/ui/button/index.tsx
index 1b648b1d5..3c31ca952 100644
--- a/src/components/ui/button/index.tsx
+++ b/src/components/ui/button/index.tsx
@@ -1,3 +1,4 @@
1/* eslint-disable no-use-before-define */
1import Icon from '@mdi/react'; 2import Icon from '@mdi/react';
2import classnames from 'classnames'; 3import classnames from 'classnames';
3import { Property } from 'csstype'; 4import { Property } from 'csstype';
@@ -135,7 +136,7 @@ interface IProps extends IFormField, WithStylesProps<typeof styles> {
135 label?: string; 136 label?: string;
136 disabled?: boolean; 137 disabled?: boolean;
137 id?: string; 138 id?: string;
138 type?: 'button' | 'reset' | 'submit' | undefined; 139 type?: 'button' | 'reset' | 'submit';
139 onClick?: MouseEventHandler<HTMLInputElement>; 140 onClick?: MouseEventHandler<HTMLInputElement>;
140 buttonType?: ButtonType; 141 buttonType?: ButtonType;
141 loaded?: boolean; 142 loaded?: boolean;
diff --git a/src/components/ui/colorPickerInput/index.tsx b/src/components/ui/colorPickerInput/index.tsx
index 2367175bd..39fd0220a 100644
--- a/src/components/ui/colorPickerInput/index.tsx
+++ b/src/components/ui/colorPickerInput/index.tsx
@@ -1,21 +1,18 @@
1import { 1import {
2 ChangeEvent,
2 Component, 3 Component,
3 createRef, 4 createRef,
4 InputHTMLAttributes, 5 InputHTMLAttributes,
5 ReactElement,
6 RefObject, 6 RefObject,
7} from 'react'; 7} from 'react';
8import { observer } from 'mobx-react'; 8import { observer } from 'mobx-react';
9import classnames from 'classnames'; 9import classnames from 'classnames';
10import { SliderPicker } from 'react-color'; 10import { Color, ColorResult, SliderPicker } from 'react-color';
11import { noop } from 'lodash'; 11import { noop } from 'lodash';
12import { FormFields } from '../../../@types/mobx-form.types'; 12import { FormFields } from '../../../@types/mobx-form.types';
13 13
14interface IProps extends InputHTMLAttributes<HTMLInputElement>, FormFields { 14interface IProps extends InputHTMLAttributes<HTMLInputElement>, FormFields {
15 className?: string; 15 onColorChange: (event: ChangeEvent<HTMLInputElement>) => void;
16 focus?: boolean;
17 onColorChange?: () => void;
18 error: string;
19} 16}
20 17
21@observer 18@observer
@@ -23,20 +20,13 @@ class ColorPickerInput extends Component<IProps> {
23 private inputElement: RefObject<HTMLInputElement> = 20 private inputElement: RefObject<HTMLInputElement> =
24 createRef<HTMLInputElement>(); 21 createRef<HTMLInputElement>();
25 22
26 componentDidMount(): void { 23 onChange(color: ColorResult, event: ChangeEvent<HTMLInputElement>): void {
27 const { focus = false } = this.props; 24 const { onColorChange, onChange = noop } = this.props;
28 if (focus && this.inputElement?.current) { 25 onColorChange(event);
29 this.inputElement.current.focus(); 26 onChange(color.hex);
30 }
31 } 27 }
32 28
33 onChange({ hex }: { hex: string }): void { 29 render() {
34 const { onColorChange = noop, onChange = noop } = this.props;
35 onColorChange();
36 onChange(hex);
37 }
38
39 render(): ReactElement {
40 const { 30 const {
41 id, 31 id,
42 name, 32 name,
@@ -45,7 +35,6 @@ class ColorPickerInput extends Component<IProps> {
45 disabled = false, 35 disabled = false,
46 className = null, 36 className = null,
47 type = 'text', 37 type = 'text',
48 error = '',
49 onChange = noop, 38 onChange = noop,
50 } = this.props; 39 } = this.props;
51 40
@@ -53,20 +42,14 @@ class ColorPickerInput extends Component<IProps> {
53 <div 42 <div
54 className={classnames({ 43 className={classnames({
55 'franz-form__field': true, 44 'franz-form__field': true,
56 'has-error': error,
57 [`${className}`]: className, 45 [`${className}`]: className,
58 })} 46 })}
59 ref={this.inputElement} 47 ref={this.inputElement}
60 > 48 >
61 <SliderPicker 49 <SliderPicker
62 color={value} 50 color={value as Color}
63 onChange={this.onChange.bind(this)} 51 onChange={(color, event) => this.onChange(color, event)}
64 id={`${id}-SliderPicker`}
65 type={type}
66 className="franz-form__input" 52 className="franz-form__input"
67 name={name}
68 placeholder={placeholder}
69 disabled={disabled}
70 /> 53 />
71 <div className="franz-form__input-wrapper franz-form__input-wrapper__color-picker"> 54 <div className="franz-form__input-wrapper franz-form__input-wrapper__color-picker">
72 <input 55 <input
diff --git a/src/components/ui/headline/index.tsx b/src/components/ui/headline/index.tsx
index 424190a6a..8e40fa896 100644
--- a/src/components/ui/headline/index.tsx
+++ b/src/components/ui/headline/index.tsx
@@ -11,14 +11,6 @@ import injectStyle, { WithStylesProps } from 'react-jss';
11import { Theme } from '../../../themes'; 11import { Theme } from '../../../themes';
12import { Omit } from '../typings/generic'; 12import { Omit } from '../typings/generic';
13 13
14interface IProps extends WithStylesProps<typeof styles> {
15 children: ReactNode;
16 level?: number;
17 className?: string;
18 id?: string;
19 onClick?: MouseEventHandler<HTMLButtonElement>;
20}
21
22const styles = (theme: Theme) => ({ 14const styles = (theme: Theme) => ({
23 headline: { 15 headline: {
24 fontWeight: 'lighter', 16 fontWeight: 'lighter',
@@ -45,6 +37,14 @@ const styles = (theme: Theme) => ({
45 }, 37 },
46}); 38});
47 39
40interface IProps extends WithStylesProps<typeof styles> {
41 children: ReactNode;
42 level?: number;
43 className?: string;
44 id?: string;
45 onClick?: MouseEventHandler<HTMLButtonElement>;
46}
47
48class HeadlineComponent extends Component<IProps> { 48class HeadlineComponent extends Component<IProps> {
49 render(): ReactElement { 49 render(): ReactElement {
50 const { classes, level, className, children, id, onClick } = this.props; 50 const { classes, level, className, children, id, onClick } = this.props;
diff --git a/src/components/ui/icon/index.tsx b/src/components/ui/icon/index.tsx
index 5b432a194..04a00d0e0 100644
--- a/src/components/ui/icon/index.tsx
+++ b/src/components/ui/icon/index.tsx
@@ -5,18 +5,18 @@ import injectStyle, { WithStylesProps } from 'react-jss';
5 5
6import { Theme } from '../../../themes'; 6import { Theme } from '../../../themes';
7 7
8interface IProps extends WithStylesProps<typeof styles> {
9 icon: string;
10 size?: number;
11 className?: string;
12}
13
14const styles = (theme: Theme) => ({ 8const styles = (theme: Theme) => ({
15 icon: { 9 icon: {
16 fill: theme.colorText, 10 fill: theme.colorText,
17 }, 11 },
18}); 12});
19 13
14interface IProps extends WithStylesProps<typeof styles> {
15 icon: string;
16 size?: number;
17 className?: string;
18}
19
20class IconComponent extends Component<IProps> { 20class IconComponent extends Component<IProps> {
21 render(): ReactElement { 21 render(): ReactElement {
22 const { classes, icon, size = 1, className } = this.props; 22 const { classes, icon, size = 1, className } = this.props;
diff --git a/src/components/ui/infobox/index.tsx b/src/components/ui/infobox/index.tsx
index 28ec2ff90..a1c4f9d21 100644
--- a/src/components/ui/infobox/index.tsx
+++ b/src/components/ui/infobox/index.tsx
@@ -1,3 +1,4 @@
1/* eslint-disable no-use-before-define */
1import { mdiClose } from '@mdi/js'; 2import { mdiClose } from '@mdi/js';
2import classnames from 'classnames'; 3import classnames from 'classnames';
3import { noop } from 'lodash'; 4import { noop } from 'lodash';
diff --git a/src/components/ui/loader/index.tsx b/src/components/ui/loader/index.tsx
index 361fc477b..957899bdc 100644
--- a/src/components/ui/loader/index.tsx
+++ b/src/components/ui/loader/index.tsx
@@ -2,13 +2,9 @@ import classnames from 'classnames';
2import { Component } from 'react'; 2import { Component } from 'react';
3import injectStyle, { WithStylesProps } from 'react-jss'; 3import injectStyle, { WithStylesProps } from 'react-jss';
4import ReactLoader from 'react-loader'; 4import ReactLoader from 'react-loader';
5import { Theme } from '../../../themes';
5 6
6interface IProps extends WithStylesProps<typeof styles> { 7const styles = (theme: Theme) => ({
7 className?: string;
8 color?: string;
9}
10
11const styles = theme => ({
12 container: { 8 container: {
13 position: 'relative', 9 position: 'relative',
14 height: 60, 10 height: 60,
@@ -17,6 +13,11 @@ const styles = theme => ({
17 color: theme.colorText, 13 color: theme.colorText,
18}); 14});
19 15
16interface IProps extends WithStylesProps<typeof styles> {
17 className?: string;
18 color?: string;
19}
20
20class LoaderComponent extends Component<IProps> { 21class LoaderComponent extends Component<IProps> {
21 render() { 22 render() {
22 const { classes, className, color } = this.props; 23 const { classes, className, color } = this.props;
diff --git a/src/components/ui/toggle/index.tsx b/src/components/ui/toggle/index.tsx
index 48f68943b..275d28bf6 100644
--- a/src/components/ui/toggle/index.tsx
+++ b/src/components/ui/toggle/index.tsx
@@ -9,13 +9,6 @@ import Label from '../label';
9import { IFormField } from '../typings/generic'; 9import { IFormField } from '../typings/generic';
10import Wrapper from '../wrapper'; 10import Wrapper from '../wrapper';
11 11
12interface IProps
13 extends InputHTMLAttributes<HTMLInputElement>,
14 IFormField,
15 WithStylesProps<typeof styles> {
16 className?: string;
17}
18
19const buttonTransition: string = window?.matchMedia( 12const buttonTransition: string = window?.matchMedia(
20 '(prefers-reduced-motion: no-preference)', 13 '(prefers-reduced-motion: no-preference)',
21) 14)
@@ -62,6 +55,13 @@ const styles = (theme: Theme) => ({
62 }, 55 },
63}); 56});
64 57
58interface IProps
59 extends InputHTMLAttributes<HTMLInputElement>,
60 IFormField,
61 WithStylesProps<typeof styles> {
62 className?: string;
63}
64
65class Toggle extends Component<IProps> { 65class Toggle extends Component<IProps> {
66 render(): ReactElement { 66 render(): ReactElement {
67 const { 67 const {
diff --git a/src/components/ui/typings/generic.ts b/src/components/ui/typings/generic.ts
index 3aec0bc40..bf45e4ce0 100644
--- a/src/components/ui/typings/generic.ts
+++ b/src/components/ui/typings/generic.ts
@@ -6,5 +6,5 @@ export interface IFormField {
6 noMargin?: boolean; 6 noMargin?: boolean;
7} 7}
8 8
9export type Merge<M, N> = Omit<M, Extract<keyof M, keyof N>> & N;
10export type Omit<T, K extends keyof T> = Pick<T, Exclude<keyof T, K>>; 9export type Omit<T, K extends keyof T> = Pick<T, Exclude<keyof T, K>>;
10export type Merge<M, N> = Omit<M, Extract<keyof M, keyof N>> & N;
diff --git a/src/components/ui/wrapper/index.tsx b/src/components/ui/wrapper/index.tsx
index d733d050e..450d09fd1 100644
--- a/src/components/ui/wrapper/index.tsx
+++ b/src/components/ui/wrapper/index.tsx
@@ -2,10 +2,12 @@ import classnames from 'classnames';
2import { Component, ReactNode } from 'react'; 2import { Component, ReactNode } from 'react';
3import injectStyle, { WithStylesProps } from 'react-jss'; 3import injectStyle, { WithStylesProps } from 'react-jss';
4 4
5// eslint-disable-next-line no-use-before-define
5interface IProps extends WithStylesProps<typeof styles> { 6interface IProps extends WithStylesProps<typeof styles> {
6 children: ReactNode; 7 children: ReactNode;
7 className?: string; 8 className?: string;
8 identifier: string; 9 identifier: string;
10 // eslint-disable-next-line react/no-unused-prop-types
9 noMargin?: boolean; 11 noMargin?: boolean;
10} 12}
11 13
diff --git a/src/components/util/ErrorBoundary/index.tsx b/src/components/util/ErrorBoundary/index.tsx
index bef211ef9..66f860835 100644
--- a/src/components/util/ErrorBoundary/index.tsx
+++ b/src/components/util/ErrorBoundary/index.tsx
@@ -23,10 +23,18 @@ interface ErrorBoundaryProps extends WithStylesProps<typeof styles> {
23 children?: React.ReactNode; 23 children?: React.ReactNode;
24} 24}
25 25
26class ErrorBoundary extends Component<ErrorBoundaryProps> { 26interface ErrorBoundaryState {
27 state = { 27 hasError: boolean;
28 hasError: false, 28}
29 }; 29
30class ErrorBoundary extends Component<ErrorBoundaryProps, ErrorBoundaryState> {
31 constructor(props) {
32 super(props);
33
34 this.state = {
35 hasError: false,
36 };
37 }
30 38
31 componentDidCatch(): void { 39 componentDidCatch(): void {
32 this.setState({ hasError: true }); 40 this.setState({ hasError: true });
diff --git a/src/config.ts b/src/config.ts
index 336085685..21a7462b9 100644
--- a/src/config.ts
+++ b/src/config.ts
@@ -92,9 +92,9 @@ export const NAVIGATION_BAR_BEHAVIOURS = {
92 never: 'Never show navigation bar', 92 never: 'Never show navigation bar',
93}; 93};
94 94
95export const SEARCH_ENGINE_STARTPAGE = 'startPage'; 95const SEARCH_ENGINE_STARTPAGE = 'startPage';
96export const SEARCH_ENGINE_GOOGLE = 'google'; 96const SEARCH_ENGINE_GOOGLE = 'google';
97export const SEARCH_ENGINE_DDG = 'duckDuckGo'; 97const SEARCH_ENGINE_DDG = 'duckDuckGo';
98export const SEARCH_ENGINE_NAMES = { 98export const SEARCH_ENGINE_NAMES = {
99 [SEARCH_ENGINE_STARTPAGE]: 'Startpage', 99 [SEARCH_ENGINE_STARTPAGE]: 'Startpage',
100 [SEARCH_ENGINE_GOOGLE]: 'Google', 100 [SEARCH_ENGINE_GOOGLE]: 'Google',
diff --git a/src/containers/auth/AuthReleaseNotesScreen.tsx b/src/containers/auth/AuthReleaseNotesScreen.tsx
index c717529fa..c9d2286e1 100644
--- a/src/containers/auth/AuthReleaseNotesScreen.tsx
+++ b/src/containers/auth/AuthReleaseNotesScreen.tsx
@@ -1,7 +1,7 @@
1import { Component } from 'react'; 1import { Component } from 'react';
2import { inject, observer } from 'mobx-react'; 2import { inject, observer } from 'mobx-react';
3 3
4import { defineMessages, injectIntl } from 'react-intl'; 4import { IntlShape, defineMessages, injectIntl } from 'react-intl';
5import Markdown from 'markdown-to-jsx'; 5import Markdown from 'markdown-to-jsx';
6import { mdiArrowLeftCircle } from '@mdi/js'; 6import { mdiArrowLeftCircle } from '@mdi/js';
7import { openExternalUrl } from '../../helpers/url-helpers'; 7import { openExternalUrl } from '../../helpers/url-helpers';
@@ -20,14 +20,14 @@ const messages = defineMessages({
20}); 20});
21 21
22interface IProps { 22interface IProps {
23 intl: any; 23 intl: IntlShape;
24} 24}
25 25
26class AuthReleaseNotesScreen extends Component<IProps> { 26interface IState {
27 state = { 27 data: string;
28 data: '', 28}
29 };
30 29
30class AuthReleaseNotesScreen extends Component<IProps, IState> {
31 constructor(props) { 31 constructor(props) {
32 super(props); 32 super(props);
33 33
diff --git a/src/containers/settings/EditSettingsScreen.tsx b/src/containers/settings/EditSettingsScreen.tsx
index 7cdff7fde..b9732ead0 100644
--- a/src/containers/settings/EditSettingsScreen.tsx
+++ b/src/containers/settings/EditSettingsScreen.tsx
@@ -319,12 +319,23 @@ const messages = defineMessages({
319 319
320interface EditSettingsScreenProps extends StoresProps, WrappedComponentProps {} 320interface EditSettingsScreenProps extends StoresProps, WrappedComponentProps {}
321 321
322interface EditSettingsScreenState {
323 lockedPassword: string;
324}
325
322@inject('stores', 'actions') 326@inject('stores', 'actions')
323@observer 327@observer
324class EditSettingsScreen extends Component<EditSettingsScreenProps> { 328class EditSettingsScreen extends Component<
325 state = { 329 EditSettingsScreenProps,
326 lockedPassword: '', 330 EditSettingsScreenState
327 }; 331> {
332 constructor(props) {
333 super(props);
334
335 this.state = {
336 lockedPassword: '',
337 };
338 }
328 339
329 onSubmit(settingsData) { 340 onSubmit(settingsData) {
330 const { todos, workspaces } = this.props.stores; 341 const { todos, workspaces } = this.props.stores;
diff --git a/src/containers/settings/EditUserScreen.tsx b/src/containers/settings/EditUserScreen.tsx
index 10c308524..62df170fc 100644
--- a/src/containers/settings/EditUserScreen.tsx
+++ b/src/containers/settings/EditUserScreen.tsx
@@ -1,6 +1,6 @@
1import { Component, ReactElement } from 'react'; 1import { Component, ReactElement } from 'react';
2import { inject, observer } from 'mobx-react'; 2import { inject, observer } from 'mobx-react';
3import { defineMessages, injectIntl } from 'react-intl'; 3import { IntlShape, defineMessages, injectIntl } from 'react-intl';
4 4
5import { StoresProps } from '../../@types/ferdium-components.types'; 5import { StoresProps } from '../../@types/ferdium-components.types';
6import { FormFields } from '../../@types/mobx-form.types'; 6import { FormFields } from '../../@types/mobx-form.types';
@@ -50,7 +50,7 @@ const messages = defineMessages({
50}); 50});
51 51
52interface EditUserScreenProps extends StoresProps { 52interface EditUserScreenProps extends StoresProps {
53 intl: any; 53 intl: IntlShape;
54} 54}
55 55
56class EditUserScreen extends Component<EditUserScreenProps> { 56class EditUserScreen extends Component<EditUserScreenProps> {
diff --git a/src/features/communityRecipes/store.ts b/src/features/communityRecipes/store.ts
index d3b3318fa..1c21908e2 100644
--- a/src/features/communityRecipes/store.ts
+++ b/src/features/communityRecipes/store.ts
@@ -37,5 +37,3 @@ export class CommunityRecipesStore extends FeatureStore {
37 ); 37 );
38 } 38 }
39} 39}
40
41export default CommunityRecipesStore;
diff --git a/src/features/todos/actions.ts b/src/features/todos/actions.ts
index 31b14d40b..5273cc858 100644
--- a/src/features/todos/actions.ts
+++ b/src/features/todos/actions.ts
@@ -44,5 +44,3 @@ export const todoActions = createActionsFromDefinitions<TodoActionsType>(
44 }, 44 },
45 PropTypes.checkPropTypes, 45 PropTypes.checkPropTypes,
46); 46);
47
48export default todoActions;
diff --git a/src/features/workspaces/actions.ts b/src/features/workspaces/actions.ts
index 5f3fefec4..cfe4f9e8e 100644
--- a/src/features/workspaces/actions.ts
+++ b/src/features/workspaces/actions.ts
@@ -3,7 +3,8 @@ import Workspace from './models/Workspace';
3import { createActionsFromDefinitions } from '../../actions/lib/actions'; 3import { createActionsFromDefinitions } from '../../actions/lib/actions';
4 4
5type WorkspaceArg = { workspace: Workspace }; 5type WorkspaceArg = { workspace: Workspace };
6export interface WorkspaceActions { 6
7interface WorkspaceActions {
7 openWorkspaceSettings: () => void; 8 openWorkspaceSettings: () => void;
8 toggleWorkspaceDrawer: () => void; 9 toggleWorkspaceDrawer: () => void;
9 deactivate: () => void; 10 deactivate: () => void;
diff --git a/src/i18n/languages.ts b/src/i18n/languages.ts
index 6a4101bc0..209848b37 100644
--- a/src/i18n/languages.ts
+++ b/src/i18n/languages.ts
@@ -145,5 +145,3 @@ export const SPELLCHECKER_LOCALES = {
145 uk: 'Українська (Ukrainian)', 145 uk: 'Українська (Ukrainian)',
146 vi: 'Tiếng Việt', 146 vi: 'Tiếng Việt',
147}; 147};
148
149export default APP_LOCALES;
diff --git a/src/index.ts b/src/index.ts
index 0487d692c..1c616b499 100644
--- a/src/index.ts
+++ b/src/index.ts
@@ -156,16 +156,6 @@ if (gotTheLock) {
156 app.quit(); 156 app.quit();
157} 157}
158 158
159// Fix Unity indicator issue
160// https://github.com/electron/electron/issues/9046
161if (
162 isLinux &&
163 process.env.XDG_CURRENT_DESKTOP &&
164 ['Pantheon', 'Unity:Unity7'].includes(process.env.XDG_CURRENT_DESKTOP)
165) {
166 process.env.XDG_CURRENT_DESKTOP = 'Unity';
167}
168
169// Disable GPU acceleration 159// Disable GPU acceleration
170if ( 160if (
171 !retrieveSettingValue( 161 !retrieveSettingValue(
@@ -674,8 +664,11 @@ ipcMain.handle('get-desktop-capturer-sources', () =>
674); 664);
675 665
676ipcMain.on('window.toolbar-double-clicked', () => { 666ipcMain.on('window.toolbar-double-clicked', () => {
677 // eslint-disable-next-line @typescript-eslint/no-unused-expressions 667 if (mainWindow?.isMaximized()) {
678 mainWindow?.isMaximized() ? mainWindow.unmaximize() : mainWindow?.maximize(); 668 mainWindow.unmaximize();
669 } else {
670 mainWindow?.maximize();
671 }
679}); 672});
680 673
681// Quit when all windows are closed. 674// Quit when all windows are closed.
diff --git a/src/internal-server/app/Controllers/Http/UserController.js b/src/internal-server/app/Controllers/Http/UserController.js
index a9c67a1b2..43d925119 100644
--- a/src/internal-server/app/Controllers/Http/UserController.js
+++ b/src/internal-server/app/Controllers/Http/UserController.js
@@ -4,7 +4,6 @@ const Service = use('App/Models/Service');
4const Workspace = use('App/Models/Workspace'); 4const Workspace = use('App/Models/Workspace');
5const { validateAll } = use('Validator'); 5const { validateAll } = use('Validator');
6 6
7const btoa = require('btoa');
8const fetch = require('node-fetch'); 7const fetch = require('node-fetch');
9const { v4: uuid } = require('uuid'); 8const { v4: uuid } = require('uuid');
10const crypto = require('crypto'); 9const crypto = require('crypto');
@@ -152,7 +151,9 @@ class UserController {
152 // Try to get an authentication token 151 // Try to get an authentication token
153 let token; 152 let token;
154 try { 153 try {
155 const basicToken = btoa(`${email}:${hashedPassword}`); 154 const basicToken = Buffer.from(`${email}:${hashedPassword}`).toString(
155 'base64',
156 );
156 157
157 const rawResponse = await fetch(`${server}/${API_VERSION}/auth/login`, { 158 const rawResponse = await fetch(`${server}/${API_VERSION}/auth/login`, {
158 method: 'POST', 159 method: 'POST',
diff --git a/src/models/RecipePreview.ts b/src/models/RecipePreview.ts
index 33b5e1432..8ace01a33 100644
--- a/src/models/RecipePreview.ts
+++ b/src/models/RecipePreview.ts
@@ -1,4 +1,4 @@
1interface IRecipePreview { 1export interface IRecipePreview {
2 id: string; 2 id: string;
3 name: string; 3 name: string;
4 icon: string; 4 icon: string;
diff --git a/src/stores/ServicesStore.ts b/src/stores/ServicesStore.ts
index 7f4693cad..82f3b95ce 100644
--- a/src/stores/ServicesStore.ts
+++ b/src/stores/ServicesStore.ts
@@ -594,7 +594,7 @@ export default class ServicesStore extends TypedStore {
594 this.stores.router.push(redirect); 594 this.stores.router.push(redirect);
595 } 595 }
596 596
597 this.allServicesRequest.patch(result => { 597 this.allServicesRequest.patch((result: Service[]) => {
598 remove(result, (c: Service) => c.id === serviceId); 598 remove(result, (c: Service) => c.id === serviceId);
599 }); 599 });
600 600
@@ -606,7 +606,7 @@ export default class ServicesStore extends TypedStore {
606 // Get directory for recipe 606 // Get directory for recipe
607 const normalDirectory = getRecipeDirectory(recipe); 607 const normalDirectory = getRecipeDirectory(recipe);
608 const devDirectory = getDevRecipeDirectory(recipe); 608 const devDirectory = getDevRecipeDirectory(recipe);
609 let directory; 609 let directory: string;
610 610
611 if (pathExistsSync(normalDirectory)) { 611 if (pathExistsSync(normalDirectory)) {
612 directory = normalDirectory; 612 directory = normalDirectory;
@@ -1028,7 +1028,7 @@ export default class ServicesStore extends TypedStore {
1028 } 1028 }
1029 1029
1030 this.reorderServicesRequest.execute(services); 1030 this.reorderServicesRequest.execute(services);
1031 this.allServicesRequest.patch(data => { 1031 this.allServicesRequest.patch((data: Service[]) => {
1032 for (const s of data) { 1032 for (const s of data) {
1033 s.order = services[s.id]; 1033 s.order = services[s.id];
1034 } 1034 }
@@ -1172,7 +1172,7 @@ export default class ServicesStore extends TypedStore {
1172 ); 1172 );
1173 1173
1174 // eslint-disable-next-line unicorn/consistent-function-scoping 1174 // eslint-disable-next-line unicorn/consistent-function-scoping
1175 const resetTimer = service => { 1175 const resetTimer = (service: Service) => {
1176 service.lastPollAnswer = Date.now(); 1176 service.lastPollAnswer = Date.now();
1177 service.lastPoll = Date.now(); 1177 service.lastPoll = Date.now();
1178 }; 1178 };
@@ -1306,7 +1306,7 @@ export default class ServicesStore extends TypedStore {
1306 }); 1306 });
1307 } 1307 }
1308 1308
1309 _cleanUpTeamIdAndCustomUrl(recipeId, data): any { 1309 _cleanUpTeamIdAndCustomUrl(recipeId: string, data: Service): any {
1310 const serviceData = data; 1310 const serviceData = data;
1311 const recipe = this.stores.recipes.one(recipeId); 1311 const recipe = this.stores.recipes.one(recipeId);
1312 1312
@@ -1318,6 +1318,7 @@ export default class ServicesStore extends TypedStore {
1318 data.team && 1318 data.team &&
1319 data.customUrl 1319 data.customUrl
1320 ) { 1320 ) {
1321 // @ts-expect-error The operand of a 'delete' operator must be optional.
1321 delete serviceData.team; 1322 delete serviceData.team;
1322 } 1323 }
1323 1324
@@ -1343,7 +1344,7 @@ export default class ServicesStore extends TypedStore {
1343 } 1344 }
1344 1345
1345 // Helper 1346 // Helper
1346 _initializeServiceRecipeInWebview(serviceId) { 1347 _initializeServiceRecipeInWebview(serviceId: string) {
1347 const service = this.one(serviceId); 1348 const service = this.one(serviceId);
1348 1349
1349 if (service.webview) { 1350 if (service.webview) {
@@ -1362,7 +1363,7 @@ export default class ServicesStore extends TypedStore {
1362 } 1363 }
1363 } 1364 }
1364 1365
1365 _initRecipePolling(serviceId) { 1366 _initRecipePolling(serviceId: string) {
1366 const service = this.one(serviceId); 1367 const service = this.one(serviceId);
1367 1368
1368 const delay = ms('2s'); 1369 const delay = ms('2s');
@@ -1385,7 +1386,7 @@ export default class ServicesStore extends TypedStore {
1385 } 1386 }
1386 } 1387 }
1387 1388
1388 _wrapIndex(index, delta, size) { 1389 _wrapIndex(index: number, delta: number, size: number) {
1389 return (((index + delta) % size) + size) % size; 1390 return (((index + delta) % size) + size) % size;
1390 } 1391 }
1391} 1392}
diff --git a/src/stores/lib/CachedRequest.ts b/src/stores/lib/CachedRequest.ts
index 25cc365e2..b24336fe6 100644
--- a/src/stores/lib/CachedRequest.ts
+++ b/src/stores/lib/CachedRequest.ts
@@ -1,5 +1,5 @@
1import { action } from 'mobx'; 1import { action } from 'mobx';
2import { isEqual, remove } from 'lodash'; 2import { isEqual } from 'lodash';
3import Request from './Request'; 3import Request from './Request';
4 4
5export default class CachedRequest extends Request { 5export default class CachedRequest extends Request {
@@ -110,10 +110,6 @@ export default class CachedRequest extends Request {
110 }); 110 });
111 } 111 }
112 112
113 removeCacheForCallWith(...args: any): void {
114 remove(this._apiCalls, c => isEqual(c.args, args));
115 }
116
117 _addApiCall(args: any) { 113 _addApiCall(args: any) {
118 const newCall = { args, result: null }; 114 const newCall = { args, result: null };
119 this._apiCalls.push(newCall); 115 this._apiCalls.push(newCall);
diff --git a/src/stores/lib/Request.ts b/src/stores/lib/Request.ts
index f9424ac99..911c5ccfb 100644
--- a/src/stores/lib/Request.ts
+++ b/src/stores/lib/Request.ts
@@ -1,6 +1,7 @@
1import { observable, action, computed, makeObservable } from 'mobx'; 1import { observable, action, computed, makeObservable } from 'mobx';
2import { isEqual } from 'lodash/fp'; 2import { isEqual } from 'lodash/fp';
3 3
4// eslint-disable-next-line no-use-before-define
4type Hook = (request: Request) => void; 5type Hook = (request: Request) => void;
5 6
6export default class Request { 7export default class Request {
diff --git a/src/themes/default/index.ts b/src/themes/default/index.ts
index 2e18e1307..31c6cbd63 100644
--- a/src/themes/default/index.ts
+++ b/src/themes/default/index.ts
@@ -15,7 +15,7 @@ export default (brandPrimary: string) => {
15 const uiFontSize = 14; 15 const uiFontSize = 14;
16 const colorBackground = legacyStyles.themeGrayLighter; 16 const colorBackground = legacyStyles.themeGrayLighter;
17 const colorContentBackground = '#FFFFFF'; 17 const colorContentBackground = '#FFFFFF';
18 const colorText = legacyStyles.themeTextColor; 18 const colorText = legacyStyles.themeGrayDark;
19 const inputColor = legacyStyles.themeGray; 19 const inputColor = legacyStyles.themeGray;
20 const inputBackground = legacyStyles.themeGrayLightest; 20 const inputBackground = legacyStyles.themeGrayLightest;
21 const inputHeight = 40; 21 const inputHeight = 40;
diff --git a/src/themes/legacy/index.ts b/src/themes/legacy/index.ts
index ca3216e7f..9caefc698 100644
--- a/src/themes/legacy/index.ts
+++ b/src/themes/legacy/index.ts
@@ -1,10 +1,7 @@
1/* legacy config, injected into sass */ 1/* legacy config, injected into sass */
2export { DEFAULT_ACCENT_COLOR as themeBrandPrimary } from '../../config'; 2export { DEFAULT_ACCENT_COLOR as themeBrandPrimary } from '../../config';
3 3
4export const themeBrandSuccess = '#5cb85c';
5export const themeBrandInfo = '#5bc0de'; 4export const themeBrandInfo = '#5bc0de';
6export const themeBrandWarning = '#FF9F00';
7export const themeBrandDanger = '#d9534f';
8 5
9export const themeGrayDark = '#373a3c'; 6export const themeGrayDark = '#373a3c';
10export const themeGray = '#55595c'; 7export const themeGray = '#55595c';
@@ -15,14 +12,6 @@ export const themeGrayLightest = '#f7f7f9';
15export const themeBorderRadius = '6px'; 12export const themeBorderRadius = '6px';
16export const themeBorderRadiusSmall = '3px'; 13export const themeBorderRadiusSmall = '3px';
17 14
18export const themeSidebarWidth = '68px';
19
20export const themeTextColor = themeGrayDark;
21
22export const themeTransitionTime = '.5s';
23
24export const themeInsetShadow = 'inset 0 2px 5px rgba(0, 0, 0, .03)';
25
26export const darkThemeBlack = '#1A1A1A'; 15export const darkThemeBlack = '#1A1A1A';
27 16
28export const darkThemeGrayDarkest = '#1E1E1E'; 17export const darkThemeGrayDarkest = '#1E1E1E';
diff --git a/src/webview/contextMenuBuilder.ts b/src/webview/contextMenuBuilder.ts
index 0d8b659f0..93dfbebb6 100644
--- a/src/webview/contextMenuBuilder.ts
+++ b/src/webview/contextMenuBuilder.ts
@@ -675,7 +675,7 @@ export class ContextMenuBuilder {
675 const clickHandler = menuInfo.srcURL.startsWith('blob:') 675 const clickHandler = menuInfo.srcURL.startsWith('blob:')
676 ? () => { 676 ? () => {
677 const urlWithoutBlob = menuInfo.srcURL.slice(5); 677 const urlWithoutBlob = menuInfo.srcURL.slice(5);
678 this.convertImageToBase64(menuInfo.srcURL, (dataURL: any) => { 678 this.convertImageToBase64(menuInfo.srcURL, (dataURL: string) => {
679 const url = new window.URL(urlWithoutBlob); 679 const url = new window.URL(urlWithoutBlob);
680 const fileName = url.pathname.slice(1); 680 const fileName = url.pathname.slice(1);
681 ipcRenderer.send('download-file', { 681 ipcRenderer.send('download-file', {
@@ -834,9 +834,8 @@ export class ContextMenuBuilder {
834 convertImageToBase64( 834 convertImageToBase64(
835 url: string, 835 url: string,
836 callback: { 836 callback: {
837 (dataURL: any): void; 837 (dataURL: string): void;
838 (dataURL: any): void; 838 (dataURL: string): void;
839 // eslint-disable-next-line @typescript-eslint/unified-signatures
840 (arg0: string): void; 839 (arg0: string): void;
841 }, 840 },
842 outputFormat: string = 'image/png', 841 outputFormat: string = 'image/png',