diff options
29 files changed, 1124 insertions, 121 deletions
diff --git a/package-lock.json b/package-lock.json index ae32a4ec9..e191b216b 100644 --- a/package-lock.json +++ b/package-lock.json | |||
@@ -25,6 +25,7 @@ | |||
25 | "@krisdages/electron-process-manager": "3.0.0", | 25 | "@krisdages/electron-process-manager": "3.0.0", |
26 | "@mdi/js": "6.9.96", | 26 | "@mdi/js": "6.9.96", |
27 | "@mdi/react": "1.6.0", | 27 | "@mdi/react": "1.6.0", |
28 | "@octokit/core": "4.0.4", | ||
28 | "@superwf/mobx-react-router": "7.4.0", | 29 | "@superwf/mobx-react-router": "7.4.0", |
29 | "auto-launch": "5.0.5", | 30 | "auto-launch": "5.0.5", |
30 | "btoa": "1.2.1", | 31 | "btoa": "1.2.1", |
@@ -47,6 +48,7 @@ | |||
47 | "languagedetect": "2.0.0", | 48 | "languagedetect": "2.0.0", |
48 | "lodash": "4.17.21", | 49 | "lodash": "4.17.21", |
49 | "macos-version": "5.2.1", | 50 | "macos-version": "5.2.1", |
51 | "markdown-to-jsx": "7.1.7", | ||
50 | "mime-types": "2.1.35", | 52 | "mime-types": "2.1.35", |
51 | "minimist": "1.2.6", | 53 | "minimist": "1.2.6", |
52 | "mobx": "6.6.1", | 54 | "mobx": "6.6.1", |
@@ -4354,6 +4356,118 @@ | |||
4354 | "node": ">=10" | 4356 | "node": ">=10" |
4355 | } | 4357 | } |
4356 | }, | 4358 | }, |
4359 | "node_modules/@octokit/auth-token": { | ||
4360 | "version": "3.0.0", | ||
4361 | "resolved": "https://registry.npmjs.org/@octokit/auth-token/-/auth-token-3.0.0.tgz", | ||
4362 | "integrity": "sha512-MDNFUBcJIptB9At7HiV7VCvU3NcL4GnfCQaP8C5lrxWrRPMJBnemYtehaKSOlaM7AYxeRyj9etenu8LVpSpVaQ==", | ||
4363 | "dependencies": { | ||
4364 | "@octokit/types": "^6.0.3" | ||
4365 | }, | ||
4366 | "engines": { | ||
4367 | "node": ">= 14" | ||
4368 | } | ||
4369 | }, | ||
4370 | "node_modules/@octokit/core": { | ||
4371 | "version": "4.0.4", | ||
4372 | "resolved": "https://registry.npmjs.org/@octokit/core/-/core-4.0.4.tgz", | ||
4373 | "integrity": "sha512-sUpR/hc4Gc7K34o60bWC7WUH6Q7T6ftZ2dUmepSyJr9PRF76/qqkWjE2SOEzCqLA5W83SaISymwKtxks+96hPQ==", | ||
4374 | "dependencies": { | ||
4375 | "@octokit/auth-token": "^3.0.0", | ||
4376 | "@octokit/graphql": "^5.0.0", | ||
4377 | "@octokit/request": "^6.0.0", | ||
4378 | "@octokit/request-error": "^3.0.0", | ||
4379 | "@octokit/types": "^6.0.3", | ||
4380 | "before-after-hook": "^2.2.0", | ||
4381 | "universal-user-agent": "^6.0.0" | ||
4382 | }, | ||
4383 | "engines": { | ||
4384 | "node": ">= 14" | ||
4385 | } | ||
4386 | }, | ||
4387 | "node_modules/@octokit/endpoint": { | ||
4388 | "version": "7.0.0", | ||
4389 | "resolved": "https://registry.npmjs.org/@octokit/endpoint/-/endpoint-7.0.0.tgz", | ||
4390 | "integrity": "sha512-Kz/mIkOTjs9rV50hf/JK9pIDl4aGwAtT8pry6Rpy+hVXkAPhXanNQRxMoq6AeRgDCZR6t/A1zKniY2V1YhrzlQ==", | ||
4391 | "dependencies": { | ||
4392 | "@octokit/types": "^6.0.3", | ||
4393 | "is-plain-object": "^5.0.0", | ||
4394 | "universal-user-agent": "^6.0.0" | ||
4395 | }, | ||
4396 | "engines": { | ||
4397 | "node": ">= 14" | ||
4398 | } | ||
4399 | }, | ||
4400 | "node_modules/@octokit/endpoint/node_modules/is-plain-object": { | ||
4401 | "version": "5.0.0", | ||
4402 | "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-5.0.0.tgz", | ||
4403 | "integrity": "sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q==", | ||
4404 | "engines": { | ||
4405 | "node": ">=0.10.0" | ||
4406 | } | ||
4407 | }, | ||
4408 | "node_modules/@octokit/graphql": { | ||
4409 | "version": "5.0.0", | ||
4410 | "resolved": "https://registry.npmjs.org/@octokit/graphql/-/graphql-5.0.0.tgz", | ||
4411 | "integrity": "sha512-1ZZ8tX4lUEcLPvHagfIVu5S2xpHYXAmgN0+95eAOPoaVPzCfUXJtA5vASafcpWcO86ze0Pzn30TAx72aB2aguQ==", | ||
4412 | "dependencies": { | ||
4413 | "@octokit/request": "^6.0.0", | ||
4414 | "@octokit/types": "^6.0.3", | ||
4415 | "universal-user-agent": "^6.0.0" | ||
4416 | }, | ||
4417 | "engines": { | ||
4418 | "node": ">= 14" | ||
4419 | } | ||
4420 | }, | ||
4421 | "node_modules/@octokit/openapi-types": { | ||
4422 | "version": "12.9.0", | ||
4423 | "resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-12.9.0.tgz", | ||
4424 | "integrity": "sha512-x0wjPEnD487oMjODOSIDdVNBebyrAPE4edY0bsxp/ZX1XPPnWQWXseixbhMa5KcwpbHVdk4qbC3zzedoMdP/YQ==" | ||
4425 | }, | ||
4426 | "node_modules/@octokit/request": { | ||
4427 | "version": "6.2.0", | ||
4428 | "resolved": "https://registry.npmjs.org/@octokit/request/-/request-6.2.0.tgz", | ||
4429 | "integrity": "sha512-7IAmHnaezZrgUqtRShMlByJK33MT9ZDnMRgZjnRrRV9a/jzzFwKGz0vxhFU6i7VMLraYcQ1qmcAOin37Kryq+Q==", | ||
4430 | "dependencies": { | ||
4431 | "@octokit/endpoint": "^7.0.0", | ||
4432 | "@octokit/request-error": "^3.0.0", | ||
4433 | "@octokit/types": "^6.16.1", | ||
4434 | "is-plain-object": "^5.0.0", | ||
4435 | "node-fetch": "^2.6.7", | ||
4436 | "universal-user-agent": "^6.0.0" | ||
4437 | }, | ||
4438 | "engines": { | ||
4439 | "node": ">= 14" | ||
4440 | } | ||
4441 | }, | ||
4442 | "node_modules/@octokit/request-error": { | ||
4443 | "version": "3.0.0", | ||
4444 | "resolved": "https://registry.npmjs.org/@octokit/request-error/-/request-error-3.0.0.tgz", | ||
4445 | "integrity": "sha512-WBtpzm9lR8z4IHIMtOqr6XwfkGvMOOILNLxsWvDwtzm/n7f5AWuqJTXQXdDtOvPfTDrH4TPhEvW2qMlR4JFA2w==", | ||
4446 | "dependencies": { | ||
4447 | "@octokit/types": "^6.0.3", | ||
4448 | "deprecation": "^2.0.0", | ||
4449 | "once": "^1.4.0" | ||
4450 | }, | ||
4451 | "engines": { | ||
4452 | "node": ">= 14" | ||
4453 | } | ||
4454 | }, | ||
4455 | "node_modules/@octokit/request/node_modules/is-plain-object": { | ||
4456 | "version": "5.0.0", | ||
4457 | "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-5.0.0.tgz", | ||
4458 | "integrity": "sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q==", | ||
4459 | "engines": { | ||
4460 | "node": ">=0.10.0" | ||
4461 | } | ||
4462 | }, | ||
4463 | "node_modules/@octokit/types": { | ||
4464 | "version": "6.39.0", | ||
4465 | "resolved": "https://registry.npmjs.org/@octokit/types/-/types-6.39.0.tgz", | ||
4466 | "integrity": "sha512-Mq4N9sOAYCitTsBtDdRVrBE80lIrMBhL9Jbrw0d+j96BAzlq4V+GLHFJbHokEsVvO/9tQupQdoFdgVYhD2C8UQ==", | ||
4467 | "dependencies": { | ||
4468 | "@octokit/openapi-types": "^12.7.0" | ||
4469 | } | ||
4470 | }, | ||
4357 | "node_modules/@sideway/address": { | 4471 | "node_modules/@sideway/address": { |
4358 | "version": "4.1.4", | 4472 | "version": "4.1.4", |
4359 | "resolved": "https://registry.npmjs.org/@sideway/address/-/address-4.1.4.tgz", | 4473 | "resolved": "https://registry.npmjs.org/@sideway/address/-/address-4.1.4.tgz", |
@@ -7150,6 +7264,11 @@ | |||
7150 | "resolved": "https://registry.npmjs.org/bcryptjs/-/bcryptjs-2.4.3.tgz", | 7264 | "resolved": "https://registry.npmjs.org/bcryptjs/-/bcryptjs-2.4.3.tgz", |
7151 | "integrity": "sha512-V/Hy/X9Vt7f3BbPJEi8BdVFMByHi+jNXrYkW3huaybV/kQ0KJg0Y6PkEMbn+zeT+i+SiKZ/HMqJGIIt4LZDqNQ==" | 7265 | "integrity": "sha512-V/Hy/X9Vt7f3BbPJEi8BdVFMByHi+jNXrYkW3huaybV/kQ0KJg0Y6PkEMbn+zeT+i+SiKZ/HMqJGIIt4LZDqNQ==" |
7152 | }, | 7266 | }, |
7267 | "node_modules/before-after-hook": { | ||
7268 | "version": "2.2.2", | ||
7269 | "resolved": "https://registry.npmjs.org/before-after-hook/-/before-after-hook-2.2.2.tgz", | ||
7270 | "integrity": "sha512-3pZEU3NT5BFUo/AD5ERPWOgQOCZITni6iavr5AUw5AUwQjMlI0kzu5btnyD39AF0gUEsDPwJT+oY1ORBJijPjQ==" | ||
7271 | }, | ||
7153 | "node_modules/big-integer": { | 7272 | "node_modules/big-integer": { |
7154 | "version": "1.6.51", | 7273 | "version": "1.6.51", |
7155 | "resolved": "https://registry.npmjs.org/big-integer/-/big-integer-1.6.51.tgz", | 7274 | "resolved": "https://registry.npmjs.org/big-integer/-/big-integer-1.6.51.tgz", |
@@ -9599,6 +9718,11 @@ | |||
9599 | "node": ">= 0.6" | 9718 | "node": ">= 0.6" |
9600 | } | 9719 | } |
9601 | }, | 9720 | }, |
9721 | "node_modules/deprecation": { | ||
9722 | "version": "2.3.1", | ||
9723 | "resolved": "https://registry.npmjs.org/deprecation/-/deprecation-2.3.1.tgz", | ||
9724 | "integrity": "sha512-xmHIy4F3scKVwMsQ4WnVaS8bHOx0DmVwRywosKhaILI0ywMDWPtBSku2HNxRvF7jtwDRsoEwYQSfbxj8b7RlJQ==" | ||
9725 | }, | ||
9602 | "node_modules/destroy": { | 9726 | "node_modules/destroy": { |
9603 | "version": "1.0.4", | 9727 | "version": "1.0.4", |
9604 | "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz", | 9728 | "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz", |
@@ -18159,6 +18283,17 @@ | |||
18159 | "node": ">=0.10.0" | 18283 | "node": ">=0.10.0" |
18160 | } | 18284 | } |
18161 | }, | 18285 | }, |
18286 | "node_modules/markdown-to-jsx": { | ||
18287 | "version": "7.1.7", | ||
18288 | "resolved": "https://registry.npmjs.org/markdown-to-jsx/-/markdown-to-jsx-7.1.7.tgz", | ||
18289 | "integrity": "sha512-VI3TyyHlGkO8uFle0IOibzpO1c1iJDcXcS/zBrQrXQQvJ2tpdwVzVZ7XdKsyRz1NdRmre4dqQkMZzUHaKIG/1w==", | ||
18290 | "engines": { | ||
18291 | "node": ">= 10" | ||
18292 | }, | ||
18293 | "peerDependencies": { | ||
18294 | "react": ">= 0.14.0" | ||
18295 | } | ||
18296 | }, | ||
18162 | "node_modules/matchdep": { | 18297 | "node_modules/matchdep": { |
18163 | "version": "2.0.0", | 18298 | "version": "2.0.0", |
18164 | "resolved": "https://registry.npmjs.org/matchdep/-/matchdep-2.0.0.tgz", | 18299 | "resolved": "https://registry.npmjs.org/matchdep/-/matchdep-2.0.0.tgz", |
@@ -25483,6 +25618,11 @@ | |||
25483 | "node": ">=8" | 25618 | "node": ">=8" |
25484 | } | 25619 | } |
25485 | }, | 25620 | }, |
25621 | "node_modules/universal-user-agent": { | ||
25622 | "version": "6.0.0", | ||
25623 | "resolved": "https://registry.npmjs.org/universal-user-agent/-/universal-user-agent-6.0.0.tgz", | ||
25624 | "integrity": "sha512-isyNax3wXoKaulPDZWHQqbmIx1k2tb9fb3GGDBRxCscfYV2Ch7WxPArBsFEG8s/safwXTT7H4QGhaIkTp9447w==" | ||
25625 | }, | ||
25486 | "node_modules/universalify": { | 25626 | "node_modules/universalify": { |
25487 | "version": "2.0.0", | 25627 | "version": "2.0.0", |
25488 | "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz", | 25628 | "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz", |
@@ -30464,6 +30604,98 @@ | |||
30464 | } | 30604 | } |
30465 | } | 30605 | } |
30466 | }, | 30606 | }, |
30607 | "@octokit/auth-token": { | ||
30608 | "version": "3.0.0", | ||
30609 | "resolved": "https://registry.npmjs.org/@octokit/auth-token/-/auth-token-3.0.0.tgz", | ||
30610 | "integrity": "sha512-MDNFUBcJIptB9At7HiV7VCvU3NcL4GnfCQaP8C5lrxWrRPMJBnemYtehaKSOlaM7AYxeRyj9etenu8LVpSpVaQ==", | ||
30611 | "requires": { | ||
30612 | "@octokit/types": "^6.0.3" | ||
30613 | } | ||
30614 | }, | ||
30615 | "@octokit/core": { | ||
30616 | "version": "4.0.4", | ||
30617 | "resolved": "https://registry.npmjs.org/@octokit/core/-/core-4.0.4.tgz", | ||
30618 | "integrity": "sha512-sUpR/hc4Gc7K34o60bWC7WUH6Q7T6ftZ2dUmepSyJr9PRF76/qqkWjE2SOEzCqLA5W83SaISymwKtxks+96hPQ==", | ||
30619 | "requires": { | ||
30620 | "@octokit/auth-token": "^3.0.0", | ||
30621 | "@octokit/graphql": "^5.0.0", | ||
30622 | "@octokit/request": "^6.0.0", | ||
30623 | "@octokit/request-error": "^3.0.0", | ||
30624 | "@octokit/types": "^6.0.3", | ||
30625 | "before-after-hook": "^2.2.0", | ||
30626 | "universal-user-agent": "^6.0.0" | ||
30627 | } | ||
30628 | }, | ||
30629 | "@octokit/endpoint": { | ||
30630 | "version": "7.0.0", | ||
30631 | "resolved": "https://registry.npmjs.org/@octokit/endpoint/-/endpoint-7.0.0.tgz", | ||
30632 | "integrity": "sha512-Kz/mIkOTjs9rV50hf/JK9pIDl4aGwAtT8pry6Rpy+hVXkAPhXanNQRxMoq6AeRgDCZR6t/A1zKniY2V1YhrzlQ==", | ||
30633 | "requires": { | ||
30634 | "@octokit/types": "^6.0.3", | ||
30635 | "is-plain-object": "^5.0.0", | ||
30636 | "universal-user-agent": "^6.0.0" | ||
30637 | }, | ||
30638 | "dependencies": { | ||
30639 | "is-plain-object": { | ||
30640 | "version": "5.0.0", | ||
30641 | "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-5.0.0.tgz", | ||
30642 | "integrity": "sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q==" | ||
30643 | } | ||
30644 | } | ||
30645 | }, | ||
30646 | "@octokit/graphql": { | ||
30647 | "version": "5.0.0", | ||
30648 | "resolved": "https://registry.npmjs.org/@octokit/graphql/-/graphql-5.0.0.tgz", | ||
30649 | "integrity": "sha512-1ZZ8tX4lUEcLPvHagfIVu5S2xpHYXAmgN0+95eAOPoaVPzCfUXJtA5vASafcpWcO86ze0Pzn30TAx72aB2aguQ==", | ||
30650 | "requires": { | ||
30651 | "@octokit/request": "^6.0.0", | ||
30652 | "@octokit/types": "^6.0.3", | ||
30653 | "universal-user-agent": "^6.0.0" | ||
30654 | } | ||
30655 | }, | ||
30656 | "@octokit/openapi-types": { | ||
30657 | "version": "12.9.0", | ||
30658 | "resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-12.9.0.tgz", | ||
30659 | "integrity": "sha512-x0wjPEnD487oMjODOSIDdVNBebyrAPE4edY0bsxp/ZX1XPPnWQWXseixbhMa5KcwpbHVdk4qbC3zzedoMdP/YQ==" | ||
30660 | }, | ||
30661 | "@octokit/request": { | ||
30662 | "version": "6.2.0", | ||
30663 | "resolved": "https://registry.npmjs.org/@octokit/request/-/request-6.2.0.tgz", | ||
30664 | "integrity": "sha512-7IAmHnaezZrgUqtRShMlByJK33MT9ZDnMRgZjnRrRV9a/jzzFwKGz0vxhFU6i7VMLraYcQ1qmcAOin37Kryq+Q==", | ||
30665 | "requires": { | ||
30666 | "@octokit/endpoint": "^7.0.0", | ||
30667 | "@octokit/request-error": "^3.0.0", | ||
30668 | "@octokit/types": "^6.16.1", | ||
30669 | "is-plain-object": "^5.0.0", | ||
30670 | "node-fetch": "^2.6.7", | ||
30671 | "universal-user-agent": "^6.0.0" | ||
30672 | }, | ||
30673 | "dependencies": { | ||
30674 | "is-plain-object": { | ||
30675 | "version": "5.0.0", | ||
30676 | "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-5.0.0.tgz", | ||
30677 | "integrity": "sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q==" | ||
30678 | } | ||
30679 | } | ||
30680 | }, | ||
30681 | "@octokit/request-error": { | ||
30682 | "version": "3.0.0", | ||
30683 | "resolved": "https://registry.npmjs.org/@octokit/request-error/-/request-error-3.0.0.tgz", | ||
30684 | "integrity": "sha512-WBtpzm9lR8z4IHIMtOqr6XwfkGvMOOILNLxsWvDwtzm/n7f5AWuqJTXQXdDtOvPfTDrH4TPhEvW2qMlR4JFA2w==", | ||
30685 | "requires": { | ||
30686 | "@octokit/types": "^6.0.3", | ||
30687 | "deprecation": "^2.0.0", | ||
30688 | "once": "^1.4.0" | ||
30689 | } | ||
30690 | }, | ||
30691 | "@octokit/types": { | ||
30692 | "version": "6.39.0", | ||
30693 | "resolved": "https://registry.npmjs.org/@octokit/types/-/types-6.39.0.tgz", | ||
30694 | "integrity": "sha512-Mq4N9sOAYCitTsBtDdRVrBE80lIrMBhL9Jbrw0d+j96BAzlq4V+GLHFJbHokEsVvO/9tQupQdoFdgVYhD2C8UQ==", | ||
30695 | "requires": { | ||
30696 | "@octokit/openapi-types": "^12.7.0" | ||
30697 | } | ||
30698 | }, | ||
30467 | "@sideway/address": { | 30699 | "@sideway/address": { |
30468 | "version": "4.1.4", | 30700 | "version": "4.1.4", |
30469 | "resolved": "https://registry.npmjs.org/@sideway/address/-/address-4.1.4.tgz", | 30701 | "resolved": "https://registry.npmjs.org/@sideway/address/-/address-4.1.4.tgz", |
@@ -32721,6 +32953,11 @@ | |||
32721 | "resolved": "https://registry.npmjs.org/bcryptjs/-/bcryptjs-2.4.3.tgz", | 32953 | "resolved": "https://registry.npmjs.org/bcryptjs/-/bcryptjs-2.4.3.tgz", |
32722 | "integrity": "sha512-V/Hy/X9Vt7f3BbPJEi8BdVFMByHi+jNXrYkW3huaybV/kQ0KJg0Y6PkEMbn+zeT+i+SiKZ/HMqJGIIt4LZDqNQ==" | 32954 | "integrity": "sha512-V/Hy/X9Vt7f3BbPJEi8BdVFMByHi+jNXrYkW3huaybV/kQ0KJg0Y6PkEMbn+zeT+i+SiKZ/HMqJGIIt4LZDqNQ==" |
32723 | }, | 32955 | }, |
32956 | "before-after-hook": { | ||
32957 | "version": "2.2.2", | ||
32958 | "resolved": "https://registry.npmjs.org/before-after-hook/-/before-after-hook-2.2.2.tgz", | ||
32959 | "integrity": "sha512-3pZEU3NT5BFUo/AD5ERPWOgQOCZITni6iavr5AUw5AUwQjMlI0kzu5btnyD39AF0gUEsDPwJT+oY1ORBJijPjQ==" | ||
32960 | }, | ||
32724 | "big-integer": { | 32961 | "big-integer": { |
32725 | "version": "1.6.51", | 32962 | "version": "1.6.51", |
32726 | "resolved": "https://registry.npmjs.org/big-integer/-/big-integer-1.6.51.tgz", | 32963 | "resolved": "https://registry.npmjs.org/big-integer/-/big-integer-1.6.51.tgz", |
@@ -34642,6 +34879,11 @@ | |||
34642 | "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", | 34879 | "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", |
34643 | "integrity": "sha512-7emPTl6Dpo6JRXOXjLRxck+FlLRX5847cLKEn00PLAgc3g2hTZZgr+e4c2v6QpSmLeFP3n5yUo7ft6avBK/5jQ==" | 34880 | "integrity": "sha512-7emPTl6Dpo6JRXOXjLRxck+FlLRX5847cLKEn00PLAgc3g2hTZZgr+e4c2v6QpSmLeFP3n5yUo7ft6avBK/5jQ==" |
34644 | }, | 34881 | }, |
34882 | "deprecation": { | ||
34883 | "version": "2.3.1", | ||
34884 | "resolved": "https://registry.npmjs.org/deprecation/-/deprecation-2.3.1.tgz", | ||
34885 | "integrity": "sha512-xmHIy4F3scKVwMsQ4WnVaS8bHOx0DmVwRywosKhaILI0ywMDWPtBSku2HNxRvF7jtwDRsoEwYQSfbxj8b7RlJQ==" | ||
34886 | }, | ||
34645 | "destroy": { | 34887 | "destroy": { |
34646 | "version": "1.0.4", | 34888 | "version": "1.0.4", |
34647 | "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz", | 34889 | "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz", |
@@ -41317,6 +41559,11 @@ | |||
41317 | "object-visit": "^1.0.0" | 41559 | "object-visit": "^1.0.0" |
41318 | } | 41560 | } |
41319 | }, | 41561 | }, |
41562 | "markdown-to-jsx": { | ||
41563 | "version": "7.1.7", | ||
41564 | "resolved": "https://registry.npmjs.org/markdown-to-jsx/-/markdown-to-jsx-7.1.7.tgz", | ||
41565 | "integrity": "sha512-VI3TyyHlGkO8uFle0IOibzpO1c1iJDcXcS/zBrQrXQQvJ2tpdwVzVZ7XdKsyRz1NdRmre4dqQkMZzUHaKIG/1w==" | ||
41566 | }, | ||
41320 | "matchdep": { | 41567 | "matchdep": { |
41321 | "version": "2.0.0", | 41568 | "version": "2.0.0", |
41322 | "resolved": "https://registry.npmjs.org/matchdep/-/matchdep-2.0.0.tgz", | 41569 | "resolved": "https://registry.npmjs.org/matchdep/-/matchdep-2.0.0.tgz", |
@@ -47045,6 +47292,11 @@ | |||
47045 | "crypto-random-string": "^2.0.0" | 47292 | "crypto-random-string": "^2.0.0" |
47046 | } | 47293 | } |
47047 | }, | 47294 | }, |
47295 | "universal-user-agent": { | ||
47296 | "version": "6.0.0", | ||
47297 | "resolved": "https://registry.npmjs.org/universal-user-agent/-/universal-user-agent-6.0.0.tgz", | ||
47298 | "integrity": "sha512-isyNax3wXoKaulPDZWHQqbmIx1k2tb9fb3GGDBRxCscfYV2Ch7WxPArBsFEG8s/safwXTT7H4QGhaIkTp9447w==" | ||
47299 | }, | ||
47048 | "universalify": { | 47300 | "universalify": { |
47049 | "version": "2.0.0", | 47301 | "version": "2.0.0", |
47050 | "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz", | 47302 | "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz", |
diff --git a/package.json b/package.json index 2d2c5c6da..2ff08af3e 100644 --- a/package.json +++ b/package.json | |||
@@ -60,6 +60,7 @@ | |||
60 | "@krisdages/electron-process-manager": "3.0.0", | 60 | "@krisdages/electron-process-manager": "3.0.0", |
61 | "@mdi/js": "6.9.96", | 61 | "@mdi/js": "6.9.96", |
62 | "@mdi/react": "1.6.0", | 62 | "@mdi/react": "1.6.0", |
63 | "@octokit/core": "4.0.4", | ||
63 | "@superwf/mobx-react-router": "7.4.0", | 64 | "@superwf/mobx-react-router": "7.4.0", |
64 | "auto-launch": "5.0.5", | 65 | "auto-launch": "5.0.5", |
65 | "btoa": "1.2.1", | 66 | "btoa": "1.2.1", |
@@ -82,6 +83,7 @@ | |||
82 | "languagedetect": "2.0.0", | 83 | "languagedetect": "2.0.0", |
83 | "lodash": "4.17.21", | 84 | "lodash": "4.17.21", |
84 | "macos-version": "5.2.1", | 85 | "macos-version": "5.2.1", |
86 | "markdown-to-jsx": "7.1.7", | ||
85 | "mime-types": "2.1.35", | 87 | "mime-types": "2.1.35", |
86 | "minimist": "1.2.6", | 88 | "minimist": "1.2.6", |
87 | "mobx": "6.6.1", | 89 | "mobx": "6.6.1", |
diff --git a/src/components/AppUpdateInfoBar.tsx b/src/components/AppUpdateInfoBar.tsx index 48efbfb7f..3ff488b74 100644 --- a/src/components/AppUpdateInfoBar.tsx +++ b/src/components/AppUpdateInfoBar.tsx | |||
@@ -2,10 +2,10 @@ import { defineMessages, useIntl } from 'react-intl'; | |||
2 | 2 | ||
3 | import { mdiInformation } from '@mdi/js'; | 3 | import { mdiInformation } from '@mdi/js'; |
4 | import InfoBar from './ui/InfoBar'; | 4 | import InfoBar from './ui/InfoBar'; |
5 | import { GITHUB_FERDIUM_URL } from '../config'; | ||
6 | import { openExternalUrl } from '../helpers/url-helpers'; | ||
7 | import Icon from './ui/icon'; | 5 | import Icon from './ui/icon'; |
8 | 6 | ||
7 | import { onAuthGoToReleaseNotes } from '../helpers/update-helpers'; | ||
8 | |||
9 | const messages = defineMessages({ | 9 | const messages = defineMessages({ |
10 | updateAvailable: { | 10 | updateAvailable: { |
11 | id: 'infobar.updateAvailable', | 11 | id: 'infobar.updateAvailable', |
@@ -24,9 +24,14 @@ const messages = defineMessages({ | |||
24 | type Props = { | 24 | type Props = { |
25 | onInstallUpdate: () => void; | 25 | onInstallUpdate: () => void; |
26 | onHide: () => void; | 26 | onHide: () => void; |
27 | updateVersionParsed: string; | ||
27 | }; | 28 | }; |
28 | 29 | ||
29 | const AppUpdateInfoBar = ({ onInstallUpdate, onHide }: Props) => { | 30 | const AppUpdateInfoBar = ({ |
31 | onInstallUpdate, | ||
32 | updateVersionParsed, | ||
33 | onHide, | ||
34 | }: Props) => { | ||
30 | const intl = useIntl(); | 35 | const intl = useIntl(); |
31 | 36 | ||
32 | return ( | 37 | return ( |
@@ -41,12 +46,12 @@ const AppUpdateInfoBar = ({ onInstallUpdate, onHide }: Props) => { | |||
41 | <button | 46 | <button |
42 | className="info-bar__inline-button" | 47 | className="info-bar__inline-button" |
43 | type="button" | 48 | type="button" |
44 | onClick={() => | 49 | onClick={() => { |
45 | openExternalUrl( | 50 | window.location.href = onAuthGoToReleaseNotes( |
46 | `${GITHUB_FERDIUM_URL}/ferdium-app/blob/develop/CHANGELOG.md`, | 51 | window.location.href, |
47 | true, | 52 | updateVersionParsed, |
48 | ) | 53 | ); |
49 | } | 54 | }} |
50 | > | 55 | > |
51 | <u>{intl.formatMessage(messages.changelog)}</u> | 56 | <u>{intl.formatMessage(messages.changelog)}</u> |
52 | </button> | 57 | </button> |
diff --git a/src/components/auth/AuthLayout.jsx b/src/components/auth/AuthLayout.jsx index 8a88cedb1..5c87c3080 100644 --- a/src/components/auth/AuthLayout.jsx +++ b/src/components/auth/AuthLayout.jsx | |||
@@ -14,6 +14,7 @@ import { | |||
14 | oneOrManyChildElements, | 14 | oneOrManyChildElements, |
15 | globalError as globalErrorPropType, | 15 | globalError as globalErrorPropType, |
16 | } from '../../prop-types'; | 16 | } from '../../prop-types'; |
17 | import { updateVersionParse } from '../../helpers/update-helpers'; | ||
17 | import globalMessages from '../../i18n/globalMessages'; | 18 | import globalMessages from '../../i18n/globalMessages'; |
18 | 19 | ||
19 | import { isWindows } from '../../environment'; | 20 | import { isWindows } from '../../environment'; |
@@ -34,6 +35,7 @@ class AuthLayout extends Component { | |||
34 | isFullScreen: PropTypes.bool.isRequired, | 35 | isFullScreen: PropTypes.bool.isRequired, |
35 | installAppUpdate: PropTypes.func.isRequired, | 36 | installAppUpdate: PropTypes.func.isRequired, |
36 | appUpdateIsDownloaded: PropTypes.bool.isRequired, | 37 | appUpdateIsDownloaded: PropTypes.bool.isRequired, |
38 | updateVersion: PropTypes.string.isRequired, | ||
37 | }; | 39 | }; |
38 | 40 | ||
39 | constructor() { | 41 | constructor() { |
@@ -55,10 +57,10 @@ class AuthLayout extends Component { | |||
55 | isFullScreen, | 57 | isFullScreen, |
56 | installAppUpdate, | 58 | installAppUpdate, |
57 | appUpdateIsDownloaded, | 59 | appUpdateIsDownloaded, |
60 | updateVersion, | ||
58 | } = this.props; | 61 | } = this.props; |
59 | 62 | ||
60 | const { intl } = this.props; | 63 | const { intl } = this.props; |
61 | |||
62 | let serverNameParse = serverName(); | 64 | let serverNameParse = serverName(); |
63 | serverNameParse = | 65 | serverNameParse = |
64 | serverNameParse === 'Custom' ? 'your Custom Server' : serverNameParse; | 66 | serverNameParse === 'Custom' ? 'your Custom Server' : serverNameParse; |
@@ -81,6 +83,7 @@ class AuthLayout extends Component { | |||
81 | {appUpdateIsDownloaded && this.state.shouldShowAppUpdateInfoBar && ( | 83 | {appUpdateIsDownloaded && this.state.shouldShowAppUpdateInfoBar && ( |
82 | <AppUpdateInfoBar | 84 | <AppUpdateInfoBar |
83 | onInstallUpdate={installAppUpdate} | 85 | onInstallUpdate={installAppUpdate} |
86 | updateVersionParsed={updateVersionParse(updateVersion)} | ||
84 | onHide={() => { | 87 | onHide={() => { |
85 | this.setState({ shouldShowAppUpdateInfoBar: false }); | 88 | this.setState({ shouldShowAppUpdateInfoBar: false }); |
86 | }} | 89 | }} |
diff --git a/src/components/layout/AppLayout.js b/src/components/layout/AppLayout.jsx index f7860afc6..685839c0a 100644 --- a/src/components/layout/AppLayout.js +++ b/src/components/layout/AppLayout.jsx | |||
@@ -13,6 +13,7 @@ import { Component as BasicAuth } from '../../features/basicAuth'; | |||
13 | import { Component as QuickSwitch } from '../../features/quickSwitch'; | 13 | import { Component as QuickSwitch } from '../../features/quickSwitch'; |
14 | import { Component as PublishDebugInfo } from '../../features/publishDebugInfo'; | 14 | import { Component as PublishDebugInfo } from '../../features/publishDebugInfo'; |
15 | import ErrorBoundary from '../util/ErrorBoundary'; | 15 | import ErrorBoundary from '../util/ErrorBoundary'; |
16 | import { updateVersionParse } from '../../helpers/update-helpers'; | ||
16 | 17 | ||
17 | // import globalMessages from '../../i18n/globalMessages'; | 18 | // import globalMessages from '../../i18n/globalMessages'; |
18 | 19 | ||
@@ -94,10 +95,14 @@ class AppLayout extends Component { | |||
94 | areRequiredRequestsLoading: PropTypes.bool.isRequired, | 95 | areRequiredRequestsLoading: PropTypes.bool.isRequired, |
95 | }; | 96 | }; |
96 | 97 | ||
97 | state = { | 98 | constructor(props) { |
98 | shouldShowAppUpdateInfoBar: true, | 99 | super(props); |
99 | shouldShowServicesUpdatedInfoBar: true, | 100 | |
100 | }; | 101 | this.state = { |
102 | shouldShowAppUpdateInfoBar: true, | ||
103 | shouldShowServicesUpdatedInfoBar: true, | ||
104 | }; | ||
105 | } | ||
101 | 106 | ||
102 | render() { | 107 | render() { |
103 | const { | 108 | const { |
@@ -115,6 +120,7 @@ class AppLayout extends Component { | |||
115 | areRequiredRequestsSuccessful, | 120 | areRequiredRequestsSuccessful, |
116 | retryRequiredRequests, | 121 | retryRequiredRequests, |
117 | areRequiredRequestsLoading, | 122 | areRequiredRequestsLoading, |
123 | updateVersion, | ||
118 | } = this.props; | 124 | } = this.props; |
119 | 125 | ||
120 | const { intl } = this.props; | 126 | const { intl } = this.props; |
@@ -126,86 +132,90 @@ class AppLayout extends Component { | |||
126 | 132 | ||
127 | return ( | 133 | return ( |
128 | <> | 134 | <> |
129 | {isMac && !isFullScreen && ( | 135 | {isMac && !isFullScreen && <div className="window-draggable" />} |
130 | <div className="window-draggable" /> | 136 | <ErrorBoundary> |
131 | )} | 137 | <div className="app"> |
132 | <ErrorBoundary> | 138 | {isWindows && !isFullScreen && ( |
133 | <div className="app"> | 139 | <TitleBar |
134 | {isWindows && !isFullScreen && ( | 140 | menu={window['ferdium'].menu.template} |
135 | <TitleBar | 141 | icon="assets/images/logo.svg" |
136 | menu={window['ferdium'].menu.template} | 142 | /> |
137 | icon="assets/images/logo.svg" | 143 | )} |
138 | /> | 144 | {isMac && !isFullScreen && ( |
139 | )} | 145 | <span |
140 | {isMac && !isFullScreen && ( | 146 | onDoubleClick={toggleFullScreen} |
141 | <span | 147 | className={classes.titleBar} |
142 | onDoubleClick={toggleFullScreen} | 148 | /> |
143 | className={classes.titleBar} | 149 | )} |
144 | /> | 150 | <div className={`app__content ${classes.appContent}`}> |
145 | )} | 151 | {workspacesDrawer} |
146 | <div className={`app__content ${classes.appContent}`}> | 152 | {sidebar} |
147 | {workspacesDrawer} | 153 | <div className="app__service"> |
148 | {sidebar} | 154 | <WorkspaceSwitchingIndicator /> |
149 | <div className="app__service"> | 155 | {!areRequiredRequestsSuccessful && showRequiredRequestsError && ( |
150 | <WorkspaceSwitchingIndicator /> | 156 | <InfoBar |
151 | {!areRequiredRequestsSuccessful && showRequiredRequestsError && ( | 157 | type="danger" |
152 | <InfoBar | 158 | ctaLabel="Try again" |
153 | type="danger" | 159 | ctaLoading={areRequiredRequestsLoading} |
154 | ctaLabel="Try again" | 160 | sticky |
155 | ctaLoading={areRequiredRequestsLoading} | 161 | onClick={retryRequiredRequests} |
156 | sticky | 162 | > |
157 | onClick={retryRequiredRequests} | 163 | <Icon icon={mdiFlash} /> |
158 | > | 164 | {intl.formatMessage(messages.requiredRequestsFailed)} |
159 | <Icon icon={mdiFlash} /> | 165 | </InfoBar> |
160 | {intl.formatMessage(messages.requiredRequestsFailed)} | 166 | )} |
161 | </InfoBar> | 167 | {authRequestFailed && ( |
162 | )} | ||
163 | {authRequestFailed && ( | ||
164 | <InfoBar | ||
165 | type="danger" | ||
166 | ctaLabel="Try again" | ||
167 | ctaLoading={areRequiredRequestsLoading} | ||
168 | sticky | ||
169 | onClick={retryRequiredRequests} | ||
170 | > | ||
171 | <Icon icon={mdiFlash} /> | ||
172 | {intl.formatMessage(messages.authRequestFailed)} | ||
173 | </InfoBar> | ||
174 | )} | ||
175 | {automaticUpdates && showServicesUpdatedInfoBar && | ||
176 | this.state.shouldShowServicesUpdatedInfoBar && ( | ||
177 | <InfoBar | 168 | <InfoBar |
178 | type="primary" | 169 | type="danger" |
179 | ctaLabel={intl.formatMessage(messages.buttonReloadServices)} | 170 | ctaLabel="Try again" |
180 | onClick={() => window.location.reload()} | 171 | ctaLoading={areRequiredRequestsLoading} |
181 | onHide={() => { | 172 | sticky |
182 | this.setState({ | 173 | onClick={retryRequiredRequests} |
183 | shouldShowServicesUpdatedInfoBar: false, | ||
184 | }); | ||
185 | }} | ||
186 | > | 174 | > |
187 | <Icon icon={mdiPowerPlug} /> | 175 | <Icon icon={mdiFlash} /> |
188 | {intl.formatMessage(messages.servicesUpdated)} | 176 | {intl.formatMessage(messages.authRequestFailed)} |
189 | </InfoBar> | 177 | </InfoBar> |
190 | )} | 178 | )} |
191 | {automaticUpdates && appUpdateIsDownloaded && this.state.shouldShowAppUpdateInfoBar && ( | 179 | {automaticUpdates && |
192 | <AppUpdateInfoBar | 180 | showServicesUpdatedInfoBar && |
193 | onInstallUpdate={installAppUpdate} | 181 | this.state.shouldShowServicesUpdatedInfoBar && ( |
194 | onHide={() => { | 182 | <InfoBar |
195 | this.setState({ shouldShowAppUpdateInfoBar: false }); | 183 | type="primary" |
196 | }} | 184 | ctaLabel={intl.formatMessage( |
197 | /> | 185 | messages.buttonReloadServices, |
198 | )} | 186 | )} |
199 | <BasicAuth /> | 187 | onClick={() => window.location.reload()} |
200 | <QuickSwitch /> | 188 | onHide={() => { |
201 | <PublishDebugInfo /> | 189 | this.setState({ |
202 | {services} | 190 | shouldShowServicesUpdatedInfoBar: false, |
203 | <Outlet /> | 191 | }); |
192 | }} | ||
193 | > | ||
194 | <Icon icon={mdiPowerPlug} /> | ||
195 | {intl.formatMessage(messages.servicesUpdated)} | ||
196 | </InfoBar> | ||
197 | )} | ||
198 | {automaticUpdates && | ||
199 | appUpdateIsDownloaded && | ||
200 | this.state.shouldShowAppUpdateInfoBar && ( | ||
201 | <AppUpdateInfoBar | ||
202 | onInstallUpdate={installAppUpdate} | ||
203 | updateVersionParsed={updateVersionParse(updateVersion)} | ||
204 | onHide={() => { | ||
205 | this.setState({ shouldShowAppUpdateInfoBar: false }); | ||
206 | }} | ||
207 | /> | ||
208 | )} | ||
209 | <BasicAuth /> | ||
210 | <QuickSwitch /> | ||
211 | <PublishDebugInfo /> | ||
212 | {services} | ||
213 | <Outlet /> | ||
214 | </div> | ||
215 | <Todos /> | ||
204 | </div> | 216 | </div> |
205 | <Todos /> | ||
206 | </div> | 217 | </div> |
207 | </div> | 218 | </ErrorBoundary> |
208 | </ErrorBoundary> | ||
209 | </> | 219 | </> |
210 | ); | 220 | ); |
211 | } | 221 | } |
diff --git a/src/components/settings/SettingsLayout.jsx b/src/components/settings/SettingsLayout.jsx index dea4bb387..989c428f2 100644 --- a/src/components/settings/SettingsLayout.jsx +++ b/src/components/settings/SettingsLayout.jsx | |||
@@ -8,6 +8,7 @@ import { Outlet } from 'react-router-dom'; | |||
8 | import ErrorBoundary from '../util/ErrorBoundary'; | 8 | import ErrorBoundary from '../util/ErrorBoundary'; |
9 | import Appear from '../ui/effects/Appear'; | 9 | import Appear from '../ui/effects/Appear'; |
10 | import Icon from '../ui/icon'; | 10 | import Icon from '../ui/icon'; |
11 | import { isEscKeyPress } from '../../jsUtils'; | ||
11 | 12 | ||
12 | const messages = defineMessages({ | 13 | const messages = defineMessages({ |
13 | closeSettings: { | 14 | closeSettings: { |
@@ -36,8 +37,7 @@ class SettingsLayout extends Component { | |||
36 | } | 37 | } |
37 | 38 | ||
38 | handleKeyDown(e) { | 39 | handleKeyDown(e) { |
39 | if (e.keyCode === 27) { | 40 | if (isEscKeyPress(e.keyCode)) { |
40 | // escape key | ||
41 | this.props.closeSettings(); | 41 | this.props.closeSettings(); |
42 | } | 42 | } |
43 | } | 43 | } |
diff --git a/src/components/settings/navigation/SettingsNavigation.jsx b/src/components/settings/navigation/SettingsNavigation.jsx index bbbe8d888..e1242a7fe 100644 --- a/src/components/settings/navigation/SettingsNavigation.jsx +++ b/src/components/settings/navigation/SettingsNavigation.jsx | |||
@@ -5,7 +5,11 @@ import { inject, observer } from 'mobx-react'; | |||
5 | import { RouterStore } from '@superwf/mobx-react-router'; | 5 | import { RouterStore } from '@superwf/mobx-react-router'; |
6 | 6 | ||
7 | import { NavLink } from 'react-router-dom'; | 7 | import { NavLink } from 'react-router-dom'; |
8 | import { LOCAL_SERVER, LIVE_FERDIUM_API, LIVE_FRANZ_API } from '../../../config'; | 8 | import { |
9 | LOCAL_SERVER, | ||
10 | LIVE_FERDIUM_API, | ||
11 | LIVE_FRANZ_API, | ||
12 | } from '../../../config'; | ||
9 | import UIStore from '../../../stores/UIStore'; | 13 | import UIStore from '../../../stores/UIStore'; |
10 | import SettingsStore from '../../../stores/SettingsStore'; | 14 | import SettingsStore from '../../../stores/SettingsStore'; |
11 | import UserStore from '../../../stores/UserStore'; | 15 | import UserStore from '../../../stores/UserStore'; |
@@ -32,6 +36,10 @@ const messages = defineMessages({ | |||
32 | id: 'settings.navigation.team', | 36 | id: 'settings.navigation.team', |
33 | defaultMessage: 'Manage Team', | 37 | defaultMessage: 'Manage Team', |
34 | }, | 38 | }, |
39 | releaseNotes: { | ||
40 | id: 'settings.navigation.releaseNotes', | ||
41 | defaultMessage: 'Release Notes', | ||
42 | }, | ||
35 | supportFerdium: { | 43 | supportFerdium: { |
36 | id: 'settings.navigation.supportFerdium', | 44 | id: 'settings.navigation.supportFerdium', |
37 | defaultMessage: 'About Ferdium', | 45 | defaultMessage: 'About Ferdium', |
@@ -165,6 +173,16 @@ class SettingsNavigation extends Component { | |||
165 | )} | 173 | )} |
166 | </NavLink> | 174 | </NavLink> |
167 | <NavLink | 175 | <NavLink |
176 | to="/settings/releasenotes" | ||
177 | className={({ isActive }) => | ||
178 | isActive | ||
179 | ? 'settings-navigation__link is-active' | ||
180 | : 'settings-navigation__link' | ||
181 | } | ||
182 | > | ||
183 | {intl.formatMessage(messages.releaseNotes)} | ||
184 | </NavLink> | ||
185 | <NavLink | ||
168 | to="/settings/support" | 186 | to="/settings/support" |
169 | className={({ isActive }) => | 187 | className={({ isActive }) => |
170 | isActive | 188 | isActive |
@@ -190,4 +208,6 @@ class SettingsNavigation extends Component { | |||
190 | } | 208 | } |
191 | } | 209 | } |
192 | 210 | ||
193 | export default injectIntl(inject('stores', 'actions')(observer(SettingsNavigation))); | 211 | export default injectIntl( |
212 | inject('stores', 'actions')(observer(SettingsNavigation)), | ||
213 | ); | ||
diff --git a/src/components/settings/releaseNotes/ReleaseNotesDashboard.tsx b/src/components/settings/releaseNotes/ReleaseNotesDashboard.tsx new file mode 100644 index 000000000..d0be82312 --- /dev/null +++ b/src/components/settings/releaseNotes/ReleaseNotesDashboard.tsx | |||
@@ -0,0 +1,99 @@ | |||
1 | import { Component } from 'react'; | ||
2 | import { observer } from 'mobx-react'; | ||
3 | import { defineMessages, injectIntl } from 'react-intl'; | ||
4 | import Markdown from 'markdown-to-jsx'; | ||
5 | import { openExternalUrl } from '../../../helpers/url-helpers'; | ||
6 | import { ferdiumVersion } from '../../../environment-remote'; | ||
7 | import { | ||
8 | getFerdiumVersion, | ||
9 | getUpdateInfoFromGH, | ||
10 | } from '../../../helpers/update-helpers'; | ||
11 | |||
12 | const messages = defineMessages({ | ||
13 | headline: { | ||
14 | id: 'settings.releasenotes.headline', | ||
15 | defaultMessage: 'Release Notes', | ||
16 | }, | ||
17 | connectionError: { | ||
18 | id: 'settings.releasenotes.connectionError', | ||
19 | defaultMessage: | ||
20 | 'An error occured when connecting to Github, please try again later.', | ||
21 | }, | ||
22 | connectionErrorPageMissing: { | ||
23 | id: 'settings.releasenotes.connectionErrorPageMissing', | ||
24 | defaultMessage: | ||
25 | 'An error occured when connecting to Github, the page you are looking for is missing.', | ||
26 | }, | ||
27 | }); | ||
28 | |||
29 | interface IProps { | ||
30 | intl: any; | ||
31 | } | ||
32 | |||
33 | class ReleaseNotesDashboard extends Component<IProps> { | ||
34 | state = { | ||
35 | data: '', | ||
36 | }; | ||
37 | |||
38 | constructor(props) { | ||
39 | super(props); | ||
40 | |||
41 | this.state = { data: '' }; | ||
42 | } | ||
43 | |||
44 | async componentDidMount() { | ||
45 | const { intl } = this.props; | ||
46 | |||
47 | const data = await getUpdateInfoFromGH( | ||
48 | window.location.href, | ||
49 | ferdiumVersion, | ||
50 | intl, | ||
51 | ); | ||
52 | |||
53 | this.setState({ | ||
54 | data, | ||
55 | }); | ||
56 | |||
57 | for (const link of document.querySelectorAll('.releasenotes__body a')) { | ||
58 | link.addEventListener('click', this.handleClick.bind(this), false); | ||
59 | } | ||
60 | } | ||
61 | |||
62 | handleClick(e) { | ||
63 | e.preventDefault(); | ||
64 | openExternalUrl(e.target.href); | ||
65 | } | ||
66 | |||
67 | componentWillUnmount() { | ||
68 | document.removeEventListener( | ||
69 | 'click', | ||
70 | // eslint-disable-next-line unicorn/no-invalid-remove-event-listener | ||
71 | this.handleClick.bind(this), | ||
72 | false, | ||
73 | ); | ||
74 | } | ||
75 | |||
76 | render() { | ||
77 | const { intl } = this.props; | ||
78 | |||
79 | const { data } = this.state; | ||
80 | return ( | ||
81 | <div className="settings__main"> | ||
82 | <div className="settings__header"> | ||
83 | <span className="settings__header-item"> | ||
84 | Ferdium {getFerdiumVersion(window.location.href, ferdiumVersion)}{' '} | ||
85 | {' | '} | ||
86 | </span> | ||
87 | <span className="settings__header-item__secondary"> | ||
88 | {intl.formatMessage(messages.headline)} | ||
89 | </span> | ||
90 | </div> | ||
91 | <div className="settings__body releasenotes__body"> | ||
92 | <Markdown options={{ wrapper: 'article' }}>{data}</Markdown> | ||
93 | </div> | ||
94 | </div> | ||
95 | ); | ||
96 | } | ||
97 | } | ||
98 | |||
99 | export default injectIntl(observer(ReleaseNotesDashboard)); | ||
diff --git a/src/components/settings/releaseNotes/ReleaseNotesLayout.tsx b/src/components/settings/releaseNotes/ReleaseNotesLayout.tsx new file mode 100644 index 000000000..ee0ba75a8 --- /dev/null +++ b/src/components/settings/releaseNotes/ReleaseNotesLayout.tsx | |||
@@ -0,0 +1,79 @@ | |||
1 | import { Component } from 'react'; | ||
2 | import { inject, observer } from 'mobx-react'; | ||
3 | import { defineMessages, injectIntl } from 'react-intl'; | ||
4 | |||
5 | import { mdiClose } from '@mdi/js'; | ||
6 | import { Outlet } from 'react-router-dom'; | ||
7 | import { StoresProps } from '../../../@types/ferdium-components.types'; | ||
8 | import ErrorBoundary from '../../util/ErrorBoundary'; | ||
9 | import Appear from '../../ui/effects/Appear'; | ||
10 | import Icon from '../../ui/icon'; | ||
11 | import { isEscKeyPress } from '../../../jsUtils'; | ||
12 | |||
13 | const messages = defineMessages({ | ||
14 | closeSettings: { | ||
15 | id: 'settings.app.closeSettings', | ||
16 | defaultMessage: 'Close settings', | ||
17 | }, | ||
18 | }); | ||
19 | |||
20 | interface IProps extends StoresProps { | ||
21 | intl: any; | ||
22 | } | ||
23 | |||
24 | class ReleaseNotesLayout extends Component<IProps> { | ||
25 | componentDidMount() { | ||
26 | document.addEventListener('keydown', this.handleKeyDown.bind(this), false); | ||
27 | } | ||
28 | |||
29 | componentWillUnmount() { | ||
30 | document.removeEventListener( | ||
31 | 'keydown', | ||
32 | // eslint-disable-next-line unicorn/no-invalid-remove-event-listener | ||
33 | this.handleKeyDown.bind(this), | ||
34 | false, | ||
35 | ); | ||
36 | } | ||
37 | |||
38 | handleKeyDown(e) { | ||
39 | if (isEscKeyPress(e.keyCode)) { | ||
40 | this.props.actions.ui.closeSettings(); | ||
41 | } | ||
42 | } | ||
43 | |||
44 | render() { | ||
45 | const { closeSettings } = this.props.actions.ui; | ||
46 | |||
47 | const { intl } = this.props; | ||
48 | |||
49 | return ( | ||
50 | <Appear transitionName="fadeIn-fast"> | ||
51 | <div className="settings-wrapper"> | ||
52 | <ErrorBoundary> | ||
53 | <button | ||
54 | type="button" | ||
55 | className="settings-wrapper__action" | ||
56 | onClick={closeSettings} | ||
57 | aria-label={intl.formatMessage(messages.closeSettings)} | ||
58 | /> | ||
59 | <div className="settings franz-form"> | ||
60 | <Outlet /> | ||
61 | <button | ||
62 | type="button" | ||
63 | className="settings__close" | ||
64 | onClick={closeSettings} | ||
65 | aria-label={intl.formatMessage(messages.closeSettings)} | ||
66 | > | ||
67 | <Icon icon={mdiClose} size={1.35} /> | ||
68 | </button> | ||
69 | </div> | ||
70 | </ErrorBoundary> | ||
71 | </div> | ||
72 | </Appear> | ||
73 | ); | ||
74 | } | ||
75 | } | ||
76 | |||
77 | export default injectIntl<'intl', IProps>( | ||
78 | inject('stores', 'actions')(observer(ReleaseNotesLayout)), | ||
79 | ); | ||
diff --git a/src/components/settings/settings/EditSettingsForm.jsx b/src/components/settings/settings/EditSettingsForm.jsx index cb1d261f8..a10d89570 100644 --- a/src/components/settings/settings/EditSettingsForm.jsx +++ b/src/components/settings/settings/EditSettingsForm.jsx | |||
@@ -15,6 +15,13 @@ import Input from '../../ui/Input'; | |||
15 | import ColorPickerInput from '../../ui/ColorPickerInput'; | 15 | import ColorPickerInput from '../../ui/ColorPickerInput'; |
16 | import Infobox from '../../ui/Infobox'; | 16 | import Infobox from '../../ui/Infobox'; |
17 | import { H1, H2, H3, H5 } from '../../ui/headline'; | 17 | import { H1, H2, H3, H5 } from '../../ui/headline'; |
18 | import { | ||
19 | ferdiumVersion, | ||
20 | userDataPath, | ||
21 | userDataRecipesPath, | ||
22 | } from '../../../environment-remote'; | ||
23 | |||
24 | import { updateVersionParse } from '../../../helpers/update-helpers'; | ||
18 | 25 | ||
19 | import { | 26 | import { |
20 | DEFAULT_ACCENT_COLOR, | 27 | DEFAULT_ACCENT_COLOR, |
@@ -25,11 +32,6 @@ import { | |||
25 | SPLIT_COLUMNS_MIN, | 32 | SPLIT_COLUMNS_MIN, |
26 | } from '../../../config'; | 33 | } from '../../../config'; |
27 | import { isMac, isWindows, lockFerdiumShortcutKey } from '../../../environment'; | 34 | import { isMac, isWindows, lockFerdiumShortcutKey } from '../../../environment'; |
28 | import { | ||
29 | ferdiumVersion, | ||
30 | userDataPath, | ||
31 | userDataRecipesPath, | ||
32 | } from '../../../environment-remote'; | ||
33 | import { openExternalUrl, openPath } from '../../../helpers/url-helpers'; | 35 | import { openExternalUrl, openPath } from '../../../helpers/url-helpers'; |
34 | import globalMessages from '../../../i18n/globalMessages'; | 36 | import globalMessages from '../../../i18n/globalMessages'; |
35 | import Icon from '../../ui/icon'; | 37 | import Icon from '../../ui/icon'; |
@@ -213,6 +215,10 @@ const messages = defineMessages({ | |||
213 | id: 'settings.app.buttonInstallUpdate', | 215 | id: 'settings.app.buttonInstallUpdate', |
214 | defaultMessage: 'Restart & install update', | 216 | defaultMessage: 'Restart & install update', |
215 | }, | 217 | }, |
218 | buttonShowChangelog: { | ||
219 | id: 'settings.app.buttonShowChangelog', | ||
220 | defaultMessage: 'Show changelog', | ||
221 | }, | ||
216 | updateStatusSearching: { | 222 | updateStatusSearching: { |
217 | id: 'settings.app.updateStatusSearching', | 223 | id: 'settings.app.updateStatusSearching', |
218 | defaultMessage: 'Searching for updates...', | 224 | defaultMessage: 'Searching for updates...', |
@@ -328,6 +334,7 @@ class EditSettingsForm extends Component { | |||
328 | checkForUpdates, | 334 | checkForUpdates, |
329 | installUpdate, | 335 | installUpdate, |
330 | form, | 336 | form, |
337 | updateVersion, | ||
331 | isCheckingForUpdates, | 338 | isCheckingForUpdates, |
332 | isAdaptableDarkModeEnabled, | 339 | isAdaptableDarkModeEnabled, |
333 | isUseGrayscaleServicesEnabled, | 340 | isUseGrayscaleServicesEnabled, |
@@ -1002,6 +1009,20 @@ class EditSettingsForm extends Component { | |||
1002 | loaded={!isCheckingForUpdates || !isUpdateAvailable} | 1009 | loaded={!isCheckingForUpdates || !isUpdateAvailable} |
1003 | /> | 1010 | /> |
1004 | )} | 1011 | )} |
1012 | {(isUpdateAvailable || updateIsReadyToInstall) && ( | ||
1013 | <Button | ||
1014 | className="settings__updates__changelog-button" | ||
1015 | label={intl.formatMessage( | ||
1016 | messages.buttonShowChangelog, | ||
1017 | )} | ||
1018 | onClick={() => { | ||
1019 | window.location.href = `#/releasenotes${updateVersionParse( | ||
1020 | updateVersion, | ||
1021 | )}`; | ||
1022 | }} | ||
1023 | /> | ||
1024 | )} | ||
1025 | <br /> | ||
1005 | <br /> | 1026 | <br /> |
1006 | </div> | 1027 | </div> |
1007 | <p> | 1028 | <p> |
diff --git a/src/components/ui/effects/Appear.tsx b/src/components/ui/effects/Appear.tsx index 117c02f97..228c7888a 100644 --- a/src/components/ui/effects/Appear.tsx +++ b/src/components/ui/effects/Appear.tsx | |||
@@ -1,10 +1,10 @@ | |||
1 | import { ReactChildren, useEffect, useState } from 'react'; | 1 | import { ReactNode, useEffect, useState } from 'react'; |
2 | import ReactCSSTransitionGroup from 'react-addons-css-transition-group'; | 2 | import ReactCSSTransitionGroup from 'react-addons-css-transition-group'; |
3 | 3 | ||
4 | type Props = { | 4 | type Props = { |
5 | children: ReactChildren; | 5 | children: ReactNode; |
6 | transitionName: string; | 6 | transitionName: string; |
7 | className: string; | 7 | className?: string; |
8 | }; | 8 | }; |
9 | const Appear = ({ | 9 | const Appear = ({ |
10 | children, | 10 | children, |
@@ -36,4 +36,8 @@ const Appear = ({ | |||
36 | ); | 36 | ); |
37 | }; | 37 | }; |
38 | 38 | ||
39 | Appear.defaultProps = { | ||
40 | className: '', | ||
41 | }; | ||
42 | |||
39 | export default Appear; | 43 | export default Appear; |
diff --git a/src/containers/auth/AuthLayoutContainer.tsx b/src/containers/auth/AuthLayoutContainer.tsx index 8d31cfb48..6fc6713f1 100644 --- a/src/containers/auth/AuthLayoutContainer.tsx +++ b/src/containers/auth/AuthLayoutContainer.tsx | |||
@@ -49,6 +49,7 @@ class AuthLayoutContainer extends Component<AuthLayoutContainerProps> { | |||
49 | appUpdateIsDownloaded={ | 49 | appUpdateIsDownloaded={ |
50 | app.updateStatus === app.updateStatusTypes.DOWNLOADED | 50 | app.updateStatus === app.updateStatusTypes.DOWNLOADED |
51 | } | 51 | } |
52 | updateVersion={app.updateVersion} | ||
52 | > | 53 | > |
53 | <Outlet /> | 54 | <Outlet /> |
54 | </AuthLayout> | 55 | </AuthLayout> |
diff --git a/src/containers/auth/AuthReleaseNotesScreen.tsx b/src/containers/auth/AuthReleaseNotesScreen.tsx new file mode 100644 index 000000000..c717529fa --- /dev/null +++ b/src/containers/auth/AuthReleaseNotesScreen.tsx | |||
@@ -0,0 +1,107 @@ | |||
1 | import { Component } from 'react'; | ||
2 | import { inject, observer } from 'mobx-react'; | ||
3 | |||
4 | import { defineMessages, injectIntl } from 'react-intl'; | ||
5 | import Markdown from 'markdown-to-jsx'; | ||
6 | import { mdiArrowLeftCircle } from '@mdi/js'; | ||
7 | import { openExternalUrl } from '../../helpers/url-helpers'; | ||
8 | import Icon from '../../components/ui/icon'; | ||
9 | import { ferdiumVersion } from '../../environment-remote'; | ||
10 | import { | ||
11 | getFerdiumVersion, | ||
12 | getUpdateInfoFromGH, | ||
13 | } from '../../helpers/update-helpers'; | ||
14 | |||
15 | const messages = defineMessages({ | ||
16 | headline: { | ||
17 | id: 'settings.releasenotes.headline', | ||
18 | defaultMessage: 'Release Notes', | ||
19 | }, | ||
20 | }); | ||
21 | |||
22 | interface IProps { | ||
23 | intl: any; | ||
24 | } | ||
25 | |||
26 | class AuthReleaseNotesScreen extends Component<IProps> { | ||
27 | state = { | ||
28 | data: '', | ||
29 | }; | ||
30 | |||
31 | constructor(props) { | ||
32 | super(props); | ||
33 | |||
34 | this.state = { data: '' }; | ||
35 | } | ||
36 | |||
37 | async componentDidMount() { | ||
38 | const { intl } = this.props; | ||
39 | |||
40 | const data = await getUpdateInfoFromGH( | ||
41 | window.location.href, | ||
42 | ferdiumVersion, | ||
43 | intl, | ||
44 | ); | ||
45 | |||
46 | this.setState({ | ||
47 | data, | ||
48 | }); | ||
49 | |||
50 | for (const link of document.querySelectorAll('.releasenotes__body a')) { | ||
51 | link.addEventListener('click', this.handleClick.bind(this), false); | ||
52 | } | ||
53 | } | ||
54 | |||
55 | handleClick(e) { | ||
56 | e.preventDefault(); | ||
57 | openExternalUrl(e.target.href); | ||
58 | } | ||
59 | |||
60 | componentWillUnmount() { | ||
61 | document.removeEventListener( | ||
62 | 'click', | ||
63 | // eslint-disable-next-line unicorn/no-invalid-remove-event-listener | ||
64 | this.handleClick.bind(this), | ||
65 | false, | ||
66 | ); | ||
67 | } | ||
68 | |||
69 | render() { | ||
70 | const { intl } = this.props; | ||
71 | |||
72 | const { data } = this.state; | ||
73 | return ( | ||
74 | <div className="auth__container auth__container--releasenotes"> | ||
75 | <div className="auth__main--releasenotes"> | ||
76 | <div className="auth__header"> | ||
77 | <span className="auth__header-item"> | ||
78 | Ferdium {getFerdiumVersion(window.location.href, ferdiumVersion)}{' '} | ||
79 | {' | '} | ||
80 | </span> | ||
81 | <span className="auth__header-item__secondary"> | ||
82 | {intl.formatMessage(messages.headline)} | ||
83 | </span> | ||
84 | </div> | ||
85 | <div className="auth__body releasenotes__body"> | ||
86 | <Markdown options={{ wrapper: 'article' }}>{data}</Markdown> | ||
87 | </div> | ||
88 | <div className="auth__help"> | ||
89 | <button | ||
90 | type="button" | ||
91 | onClick={() => { | ||
92 | // For some reason <Link> doesn't work here. So we hard code the path to take us to the Welcome Screen | ||
93 | window.location.href = '#/auth/welcome'; | ||
94 | }} | ||
95 | > | ||
96 | <Icon icon={mdiArrowLeftCircle} size={1.5} /> | ||
97 | </button> | ||
98 | </div> | ||
99 | </div> | ||
100 | </div> | ||
101 | ); | ||
102 | } | ||
103 | } | ||
104 | |||
105 | export default injectIntl<'intl', IProps>( | ||
106 | inject('stores', 'actions')(observer(AuthReleaseNotesScreen)), | ||
107 | ); | ||
diff --git a/src/containers/layout/AppLayoutContainer.tsx b/src/containers/layout/AppLayoutContainer.tsx index a4857a426..9c03b0ba4 100644 --- a/src/containers/layout/AppLayoutContainer.tsx +++ b/src/containers/layout/AppLayoutContainer.tsx | |||
@@ -157,6 +157,7 @@ class AppLayoutContainer extends Component<AppLayoutContainerProps> { | |||
157 | areRequiredRequestsSuccessful={requests.areRequiredRequestsSuccessful} | 157 | areRequiredRequestsSuccessful={requests.areRequiredRequestsSuccessful} |
158 | retryRequiredRequests={retryRequiredRequests} | 158 | retryRequiredRequests={retryRequiredRequests} |
159 | areRequiredRequestsLoading={requests.areRequiredRequestsLoading} | 159 | areRequiredRequestsLoading={requests.areRequiredRequestsLoading} |
160 | updateVersion={app.updateVersion} | ||
160 | > | 161 | > |
161 | <Outlet /> | 162 | <Outlet /> |
162 | </AppLayout> | 163 | </AppLayout> |
diff --git a/src/containers/settings/EditSettingsScreen.tsx b/src/containers/settings/EditSettingsScreen.tsx index a6c4561dd..fbbed629a 100644 --- a/src/containers/settings/EditSettingsScreen.tsx +++ b/src/containers/settings/EditSettingsScreen.tsx | |||
@@ -853,6 +853,7 @@ class EditSettingsScreen extends Component<EditSettingsScreenProps> { | |||
853 | const { app } = this.props.stores; | 853 | const { app } = this.props.stores; |
854 | const { | 854 | const { |
855 | updateStatus, | 855 | updateStatus, |
856 | updateVersion, | ||
856 | updateStatusTypes, | 857 | updateStatusTypes, |
857 | isClearingAllCache, | 858 | isClearingAllCache, |
858 | lockingFeatureEnabled, | 859 | lockingFeatureEnabled, |
@@ -860,13 +861,13 @@ class EditSettingsScreen extends Component<EditSettingsScreenProps> { | |||
860 | const { checkForUpdates, installUpdate, clearAllCache } = | 861 | const { checkForUpdates, installUpdate, clearAllCache } = |
861 | this.props.actions.app; | 862 | this.props.actions.app; |
862 | const form = this.prepareForm(); | 863 | const form = this.prepareForm(); |
863 | |||
864 | return ( | 864 | return ( |
865 | <ErrorBoundary> | 865 | <ErrorBoundary> |
866 | <EditSettingsForm | 866 | <EditSettingsForm |
867 | form={form} | 867 | form={form} |
868 | checkForUpdates={checkForUpdates} | 868 | checkForUpdates={checkForUpdates} |
869 | installUpdate={installUpdate} | 869 | installUpdate={installUpdate} |
870 | updateVersion={updateVersion} | ||
870 | isCheckingForUpdates={updateStatus === updateStatusTypes.CHECKING} | 871 | isCheckingForUpdates={updateStatus === updateStatusTypes.CHECKING} |
871 | isUpdateAvailable={updateStatus === updateStatusTypes.AVAILABLE} | 872 | isUpdateAvailable={updateStatus === updateStatusTypes.AVAILABLE} |
872 | noUpdateAvailable={updateStatus === updateStatusTypes.NOT_AVAILABLE} | 873 | noUpdateAvailable={updateStatus === updateStatusTypes.NOT_AVAILABLE} |
diff --git a/src/containers/settings/ReleaseNotesScreen.tsx b/src/containers/settings/ReleaseNotesScreen.tsx new file mode 100644 index 000000000..c3014d187 --- /dev/null +++ b/src/containers/settings/ReleaseNotesScreen.tsx | |||
@@ -0,0 +1,16 @@ | |||
1 | import { Component, ReactElement } from 'react'; | ||
2 | |||
3 | import ReleaseNotes from '../../components/settings/releaseNotes/ReleaseNotesDashboard'; | ||
4 | import ErrorBoundary from '../../components/util/ErrorBoundary'; | ||
5 | |||
6 | class ReleaseNotesScreen extends Component { | ||
7 | render(): ReactElement { | ||
8 | return ( | ||
9 | <ErrorBoundary> | ||
10 | <ReleaseNotes /> | ||
11 | </ErrorBoundary> | ||
12 | ); | ||
13 | } | ||
14 | } | ||
15 | |||
16 | export default ReleaseNotesScreen; | ||
diff --git a/src/containers/settings/ReleaseNotesWindow.tsx b/src/containers/settings/ReleaseNotesWindow.tsx new file mode 100644 index 000000000..3e43727d0 --- /dev/null +++ b/src/containers/settings/ReleaseNotesWindow.tsx | |||
@@ -0,0 +1,42 @@ | |||
1 | import { inject, observer } from 'mobx-react'; | ||
2 | import { Component, ReactPortal } from 'react'; | ||
3 | import ReactDOM from 'react-dom'; | ||
4 | import { Outlet } from 'react-router-dom'; | ||
5 | |||
6 | import { StoresProps } from '../../@types/ferdium-components.types'; | ||
7 | import Layout from '../../components/settings/releaseNotes/ReleaseNotesLayout'; | ||
8 | import ErrorBoundary from '../../components/util/ErrorBoundary'; | ||
9 | |||
10 | class SettingsContainer extends Component<StoresProps> { | ||
11 | portalRoot: any; | ||
12 | |||
13 | el: HTMLDivElement; | ||
14 | |||
15 | constructor(props: StoresProps) { | ||
16 | super(props); | ||
17 | |||
18 | this.portalRoot = document.querySelector('#portalContainer'); | ||
19 | this.el = document.createElement('div'); | ||
20 | } | ||
21 | |||
22 | componentDidMount(): void { | ||
23 | this.portalRoot.append(this.el); | ||
24 | } | ||
25 | |||
26 | componentWillUnmount(): void { | ||
27 | this.el.remove(); | ||
28 | } | ||
29 | |||
30 | render(): ReactPortal { | ||
31 | return ReactDOM.createPortal( | ||
32 | <ErrorBoundary> | ||
33 | <Layout {...this.props}> | ||
34 | <Outlet /> | ||
35 | </Layout> | ||
36 | </ErrorBoundary>, | ||
37 | this.el, | ||
38 | ); | ||
39 | } | ||
40 | } | ||
41 | |||
42 | export default inject('stores', 'actions')(observer(SettingsContainer)); | ||
diff --git a/src/features/workspaces/components/WorkspaceItem.tsx b/src/features/workspaces/components/WorkspaceItem.tsx index f46375c7a..eb33a0376 100644 --- a/src/features/workspaces/components/WorkspaceItem.tsx +++ b/src/features/workspaces/components/WorkspaceItem.tsx | |||
@@ -1,8 +1,6 @@ | |||
1 | import { Component } from 'react'; | 1 | import { Component } from 'react'; |
2 | import PropTypes from 'prop-types'; | ||
3 | import { observer } from 'mobx-react'; | 2 | import { observer } from 'mobx-react'; |
4 | import injectSheet from 'react-jss'; | 3 | import injectSheet from 'react-jss'; |
5 | |||
6 | import Workspace from '../models/Workspace'; | 4 | import Workspace from '../models/Workspace'; |
7 | 5 | ||
8 | const styles = theme => ({ | 6 | const styles = theme => ({ |
@@ -18,17 +16,11 @@ const styles = theme => ({ | |||
18 | 16 | ||
19 | type Props = { | 17 | type Props = { |
20 | classes: any; | 18 | classes: any; |
21 | workspace: any; | 19 | workspace: typeof Workspace; |
22 | onItemClick: (workspace) => void; | 20 | onItemClick: (workspace) => void; |
23 | }; | 21 | }; |
24 | 22 | ||
25 | class WorkspaceItem extends Component<Props> { | 23 | class WorkspaceItem extends Component<Props> { |
26 | static propTypes = { | ||
27 | classes: PropTypes.object.isRequired, | ||
28 | workspace: PropTypes.instanceOf(Workspace).isRequired, | ||
29 | onItemClick: PropTypes.func.isRequired, | ||
30 | }; | ||
31 | |||
32 | render() { | 24 | render() { |
33 | const { classes, workspace, onItemClick } = this.props; | 25 | const { classes, workspace, onItemClick } = this.props; |
34 | 26 | ||
diff --git a/src/helpers/update-helpers.ts b/src/helpers/update-helpers.ts new file mode 100644 index 000000000..daeef5413 --- /dev/null +++ b/src/helpers/update-helpers.ts | |||
@@ -0,0 +1,65 @@ | |||
1 | import { Octokit } from '@octokit/core'; | ||
2 | import { defineMessages, IntlShape } from 'react-intl'; | ||
3 | |||
4 | export function getFerdiumVersion( | ||
5 | currentLocation: string, | ||
6 | ferdiumVersion: string, | ||
7 | ): string { | ||
8 | const matches = currentLocation?.match(/version=([^&]*)/); | ||
9 | if (matches !== null) { | ||
10 | return `v${matches[1]}`; | ||
11 | } | ||
12 | return `v${ferdiumVersion}`; | ||
13 | } | ||
14 | |||
15 | export function updateVersionParse(updateVersion: string): string { | ||
16 | return updateVersion !== '' ? `?version=${updateVersion}` : ''; | ||
17 | } | ||
18 | |||
19 | export function onAuthGoToReleaseNotes( | ||
20 | currentLocation: string, | ||
21 | updateVersionParsed: string = '', | ||
22 | ): string { | ||
23 | return currentLocation.includes('#/auth') | ||
24 | ? `#/auth/releasenotes${updateVersionParsed}` | ||
25 | : `#/releasenotes${updateVersionParsed}`; | ||
26 | } | ||
27 | |||
28 | const messages = defineMessages({ | ||
29 | connectionError: { | ||
30 | id: 'settings.releasenotes.connectionError', | ||
31 | defaultMessage: | ||
32 | 'An error occured when connecting to Github, please try again later.', | ||
33 | }, | ||
34 | connectionErrorPageMissing: { | ||
35 | id: 'settings.releasenotes.connectionErrorPageMissing', | ||
36 | defaultMessage: | ||
37 | 'An error occured when connecting to Github, the page you are looking for is missing.', | ||
38 | }, | ||
39 | }); | ||
40 | |||
41 | export async function getUpdateInfoFromGH( | ||
42 | currentLocation: string, | ||
43 | ferdiumVersion: string, | ||
44 | intl: IntlShape, | ||
45 | ): Promise<string> { | ||
46 | const octokit = new Octokit(); | ||
47 | try { | ||
48 | const response = await octokit.request( | ||
49 | 'GET /repos/{owner}/{repo}/releases/tags/{tag}', | ||
50 | { | ||
51 | owner: 'ferdium', | ||
52 | repo: 'ferdium-app', | ||
53 | tag: getFerdiumVersion(currentLocation, ferdiumVersion), | ||
54 | }, | ||
55 | ); | ||
56 | |||
57 | if (response.status === 200) { | ||
58 | const json = response.data.body; | ||
59 | return json || `### ${intl.formatMessage(messages.connectionError)}`; | ||
60 | } | ||
61 | return `### ${intl.formatMessage(messages.connectionError)}`; | ||
62 | } catch { | ||
63 | return `### ${intl.formatMessage(messages.connectionErrorPageMissing)}`; | ||
64 | } | ||
65 | } | ||
diff --git a/src/i18n/locales/en-US.json b/src/i18n/locales/en-US.json index 3c3beea6f..d45ab5c3c 100644 --- a/src/i18n/locales/en-US.json +++ b/src/i18n/locales/en-US.json | |||
@@ -194,6 +194,7 @@ | |||
194 | "settings.app.buttonOpenFerdiumServiceRecipesFolder": "Open Service Recipes folder", | 194 | "settings.app.buttonOpenFerdiumServiceRecipesFolder": "Open Service Recipes folder", |
195 | "settings.app.buttonOpenImportExport": "Import / Export", | 195 | "settings.app.buttonOpenImportExport": "Import / Export", |
196 | "settings.app.buttonSearchForUpdate": "Check for updates", | 196 | "settings.app.buttonSearchForUpdate": "Check for updates", |
197 | "settings.app.buttonShowChangelog": "Show changelog", | ||
197 | "settings.app.cacheInfo": "Ferdium cache is currently using {size} of disk space.", | 198 | "settings.app.cacheInfo": "Ferdium cache is currently using {size} of disk space.", |
198 | "settings.app.cacheNotCleared": "Couldn't clear all cache", | 199 | "settings.app.cacheNotCleared": "Couldn't clear all cache", |
199 | "settings.app.closeSettings": "Close settings", | 200 | "settings.app.closeSettings": "Close settings", |
@@ -302,6 +303,7 @@ | |||
302 | "settings.navigation.account": "Account", | 303 | "settings.navigation.account": "Account", |
303 | "settings.navigation.availableServices": "Available services", | 304 | "settings.navigation.availableServices": "Available services", |
304 | "settings.navigation.logout": "Logout", | 305 | "settings.navigation.logout": "Logout", |
306 | "settings.navigation.releaseNotes": "Release Notes", | ||
305 | "settings.navigation.supportFerdium": "About Ferdium", | 307 | "settings.navigation.supportFerdium": "About Ferdium", |
306 | "settings.navigation.team": "Manage Team", | 308 | "settings.navigation.team": "Manage Team", |
307 | "settings.navigation.yourServices": "Your services", | 309 | "settings.navigation.yourServices": "Your services", |
@@ -319,6 +321,9 @@ | |||
319 | "settings.recipes.missingService": "Missing a service?", | 321 | "settings.recipes.missingService": "Missing a service?", |
320 | "settings.recipes.nothingFound": "Sorry, but no service matched your search term - but you can still probably add it using the \"Custom Website\" option. Please note that the website might show more services that have been added to Ferdium since the version that you are currently on. To get those new services, please consider upgrading to a newer version of Ferdium.", | 322 | "settings.recipes.nothingFound": "Sorry, but no service matched your search term - but you can still probably add it using the \"Custom Website\" option. Please note that the website might show more services that have been added to Ferdium since the version that you are currently on. To get those new services, please consider upgrading to a newer version of Ferdium.", |
321 | "settings.recipes.servicesSuccessfulAddedInfo": "Service successfully added", | 323 | "settings.recipes.servicesSuccessfulAddedInfo": "Service successfully added", |
324 | "settings.releasenotes.connectionError": "An error occured when connecting to Github, please try again later.", | ||
325 | "settings.releasenotes.connectionErrorPageMissing": "An error occured when connecting to Github, the page you are looking for is missing.", | ||
326 | "settings.releasenotes.headline": "Release Notes", | ||
322 | "settings.searchService": "Search service", | 327 | "settings.searchService": "Search service", |
323 | "settings.service.error.goBack": "Back to services", | 328 | "settings.service.error.goBack": "Back to services", |
324 | "settings.service.error.headline": "Error", | 329 | "settings.service.error.headline": "Error", |
diff --git a/src/jsUtils.ts b/src/jsUtils.ts index f5b39a000..36d70da25 100644 --- a/src/jsUtils.ts +++ b/src/jsUtils.ts | |||
@@ -20,3 +20,5 @@ export const convertToJSON = (data: string | any | undefined | null) => | |||
20 | 20 | ||
21 | export const cleanseJSObject = (data: any | undefined | null) => | 21 | export const cleanseJSObject = (data: any | undefined | null) => |
22 | JSON.parse(JSON.stringify(data)); | 22 | JSON.parse(JSON.stringify(data)); |
23 | |||
24 | export const isEscKeyPress = (keyCode : Number) => keyCode === 27; | ||
diff --git a/src/lib/Menu.js b/src/lib/Menu.js index 8fd3e9e01..41b4aa9f7 100644 --- a/src/lib/Menu.js +++ b/src/lib/Menu.js | |||
@@ -32,11 +32,7 @@ import { | |||
32 | nodeVersion, | 32 | nodeVersion, |
33 | osArch, | 33 | osArch, |
34 | } from '../environment'; | 34 | } from '../environment'; |
35 | import { | 35 | import { CUSTOM_WEBSITE_RECIPE_ID, LIVE_API_FERDIUM_WEBSITE } from '../config'; |
36 | CUSTOM_WEBSITE_RECIPE_ID, | ||
37 | GITHUB_FERDIUM_URL, | ||
38 | LIVE_API_FERDIUM_WEBSITE, | ||
39 | } from '../config'; | ||
40 | import { ferdiumVersion } from '../environment-remote'; | 36 | import { ferdiumVersion } from '../environment-remote'; |
41 | import { todoActions } from '../features/todos/actions'; | 37 | import { todoActions } from '../features/todos/actions'; |
42 | import workspaceActions from '../features/workspaces/actions'; | 38 | import workspaceActions from '../features/workspaces/actions'; |
@@ -44,6 +40,7 @@ import { workspaceStore } from '../features/workspaces/index'; | |||
44 | import { importExportURL, serverBase, serverName } from '../api/apiBase'; | 40 | import { importExportURL, serverBase, serverName } from '../api/apiBase'; |
45 | import { openExternalUrl } from '../helpers/url-helpers'; | 41 | import { openExternalUrl } from '../helpers/url-helpers'; |
46 | import globalMessages from '../i18n/globalMessages'; | 42 | import globalMessages from '../i18n/globalMessages'; |
43 | import { onAuthGoToReleaseNotes } from '../helpers/update-helpers'; | ||
47 | 44 | ||
48 | // @ts-expect-error Cannot find module '../buildInfo.json' or its corresponding type declarations. | 45 | // @ts-expect-error Cannot find module '../buildInfo.json' or its corresponding type declarations. |
49 | import * as buildInfo from '../buildInfo.json'; | 46 | import * as buildInfo from '../buildInfo.json'; |
@@ -586,10 +583,7 @@ const _titleBarTemplateFactory = (intl, locked) => [ | |||
586 | { | 583 | { |
587 | label: intl.formatMessage(menuItems.changelog), | 584 | label: intl.formatMessage(menuItems.changelog), |
588 | click() { | 585 | click() { |
589 | openExternalUrl( | 586 | window.location.href = onAuthGoToReleaseNotes(window.location.href); |
590 | `${GITHUB_FERDIUM_URL}/ferdium-app/releases/tag/v${ferdiumVersion}`, | ||
591 | true, | ||
592 | ); | ||
593 | }, | 587 | }, |
594 | }, | 588 | }, |
595 | { | 589 | { |
diff --git a/src/routes.tsx b/src/routes.tsx index 1f929531e..478d3dfe8 100644 --- a/src/routes.tsx +++ b/src/routes.tsx | |||
@@ -9,6 +9,7 @@ import { | |||
9 | 9 | ||
10 | import AppLayoutContainer from './containers/layout/AppLayoutContainer'; | 10 | import AppLayoutContainer from './containers/layout/AppLayoutContainer'; |
11 | import SettingsWindow from './containers/settings/SettingsWindow'; | 11 | import SettingsWindow from './containers/settings/SettingsWindow'; |
12 | import ReleaseNotesWindow from './containers/settings/ReleaseNotesWindow'; | ||
12 | import RecipesScreen from './containers/settings/RecipesScreen'; | 13 | import RecipesScreen from './containers/settings/RecipesScreen'; |
13 | import ServicesScreen from './containers/settings/ServicesScreen'; | 14 | import ServicesScreen from './containers/settings/ServicesScreen'; |
14 | import EditServiceScreen from './containers/settings/EditServiceScreen'; | 15 | import EditServiceScreen from './containers/settings/EditServiceScreen'; |
@@ -18,8 +19,10 @@ import EditUserScreen from './containers/settings/EditUserScreen'; | |||
18 | import EditSettingsScreen from './containers/settings/EditSettingsScreen'; | 19 | import EditSettingsScreen from './containers/settings/EditSettingsScreen'; |
19 | import InviteSettingsScreen from './containers/settings/InviteScreen'; | 20 | import InviteSettingsScreen from './containers/settings/InviteScreen'; |
20 | import SupportFerdiumScreen from './containers/settings/SupportScreen'; | 21 | import SupportFerdiumScreen from './containers/settings/SupportScreen'; |
22 | import ReleaseNotesScreen from './containers/settings/ReleaseNotesScreen'; | ||
21 | import WelcomeScreen from './containers/auth/WelcomeScreen'; | 23 | import WelcomeScreen from './containers/auth/WelcomeScreen'; |
22 | import LoginScreen from './containers/auth/LoginScreen'; | 24 | import LoginScreen from './containers/auth/LoginScreen'; |
25 | import AuthReleaseNotesScreen from './containers/auth/AuthReleaseNotesScreen'; | ||
23 | import PasswordScreen from './containers/auth/PasswordScreen'; | 26 | import PasswordScreen from './containers/auth/PasswordScreen'; |
24 | import ChangeServerScreen from './containers/auth/ChangeServerScreen'; | 27 | import ChangeServerScreen from './containers/auth/ChangeServerScreen'; |
25 | import SignupScreen from './containers/auth/SignupScreen'; | 28 | import SignupScreen from './containers/auth/SignupScreen'; |
@@ -100,10 +103,25 @@ class FerdiumRoutes extends Component<Props> { | |||
100 | path="/auth/logout" | 103 | path="/auth/logout" |
101 | element={<LoginScreen {...routeProps} {...errorProps} />} | 104 | element={<LoginScreen {...routeProps} {...errorProps} />} |
102 | /> | 105 | /> |
106 | <Route | ||
107 | path="/auth/releasenotes" | ||
108 | element={ | ||
109 | <AuthReleaseNotesScreen {...routeProps} {...errorProps} /> | ||
110 | } | ||
111 | /> | ||
103 | </Route> | 112 | </Route> |
104 | 113 | ||
105 | <Route path="/" element={<AppLayoutContainer {...routeProps} />}> | 114 | <Route path="/" element={<AppLayoutContainer {...routeProps} />}> |
106 | <Route | 115 | <Route |
116 | path="/releasenotes" | ||
117 | element={<ReleaseNotesWindow {...this.props} />} | ||
118 | > | ||
119 | <Route | ||
120 | path="/releasenotes" | ||
121 | element={<ReleaseNotesScreen {...this.props} />} | ||
122 | /> | ||
123 | </Route> | ||
124 | <Route | ||
107 | path="/settings" | 125 | path="/settings" |
108 | element={<SettingsWindow {...this.props} />} | 126 | element={<SettingsWindow {...this.props} />} |
109 | > | 127 | > |
@@ -155,6 +173,10 @@ class FerdiumRoutes extends Component<Props> { | |||
155 | path="/settings/support" | 173 | path="/settings/support" |
156 | element={<SupportFerdiumScreen {...this.props} />} | 174 | element={<SupportFerdiumScreen {...this.props} />} |
157 | /> | 175 | /> |
176 | <Route | ||
177 | path="/settings/releasenotes" | ||
178 | element={<ReleaseNotesScreen {...this.props} />} | ||
179 | /> | ||
158 | </Route> | 180 | </Route> |
159 | </Route> | 181 | </Route> |
160 | </Routes> | 182 | </Routes> |
diff --git a/src/stores/AppStore.ts b/src/stores/AppStore.ts index 116e64756..af1a0daae 100644 --- a/src/stores/AppStore.ts +++ b/src/stores/AppStore.ts | |||
@@ -82,6 +82,8 @@ export default class AppStore extends TypedStore { | |||
82 | 82 | ||
83 | @observable updateStatus = ''; | 83 | @observable updateStatus = ''; |
84 | 84 | ||
85 | @observable updateVersion = ''; | ||
86 | |||
85 | @observable locale = ferdiumLocale; | 87 | @observable locale = ferdiumLocale; |
86 | 88 | ||
87 | @observable isSystemMuteOverridden = false; | 89 | @observable isSystemMuteOverridden = false; |
@@ -94,7 +96,8 @@ export default class AppStore extends TypedStore { | |||
94 | 96 | ||
95 | @observable isFocused = true; | 97 | @observable isFocused = true; |
96 | 98 | ||
97 | @observable lockingFeatureEnabled = DEFAULT_APP_SETTINGS.lockingFeatureEnabled; | 99 | @observable lockingFeatureEnabled = |
100 | DEFAULT_APP_SETTINGS.lockingFeatureEnabled; | ||
98 | 101 | ||
99 | @observable launchInBackground = DEFAULT_APP_SETTINGS.autoLaunchInBackground; | 102 | @observable launchInBackground = DEFAULT_APP_SETTINGS.autoLaunchInBackground; |
100 | 103 | ||
@@ -181,6 +184,7 @@ export default class AppStore extends TypedStore { | |||
181 | ipcRenderer.on('autoUpdate', (_, data) => { | 184 | ipcRenderer.on('autoUpdate', (_, data) => { |
182 | if (this.updateStatus !== this.updateStatusTypes.FAILED) { | 185 | if (this.updateStatus !== this.updateStatusTypes.FAILED) { |
183 | if (data.available) { | 186 | if (data.available) { |
187 | this.updateVersion = data.version; | ||
184 | this.updateStatus = this.updateStatusTypes.AVAILABLE; | 188 | this.updateStatus = this.updateStatusTypes.AVAILABLE; |
185 | if (isMac && this.stores.settings.app.automaticUpdates) { | 189 | if (isMac && this.stores.settings.app.automaticUpdates) { |
186 | app.dock.bounce(); | 190 | app.dock.bounce(); |
diff --git a/src/styles/auth.scss b/src/styles/auth.scss index e60c4971c..53c03a40a 100644 --- a/src/styles/auth.scss +++ b/src/styles/auth.scss | |||
@@ -61,6 +61,12 @@ | |||
61 | width: 350px; | 61 | width: 350px; |
62 | 62 | ||
63 | &.auth__container--signup { width: 450px; } | 63 | &.auth__container--signup { width: 450px; } |
64 | |||
65 | &.auth__container--releasenotes { | ||
66 | width: 90%; | ||
67 | height: -webkit-fill-available; | ||
68 | max-height: 80%; | ||
69 | } | ||
64 | } | 70 | } |
65 | 71 | ||
66 | .auth__logo { | 72 | .auth__logo { |
@@ -92,6 +98,32 @@ | |||
92 | } | 98 | } |
93 | } | 99 | } |
94 | 100 | ||
101 | .releasenotes__body { | ||
102 | overflow-y: scroll; | ||
103 | |||
104 | &::-webkit-scrollbar { | ||
105 | width: 8px; | ||
106 | } | ||
107 | |||
108 | /* Track */ | ||
109 | &::-webkit-scrollbar-track { | ||
110 | background: none; | ||
111 | border-radius: 10px; | ||
112 | -webkit-border-radius: 10px; | ||
113 | } | ||
114 | |||
115 | /* Handle */ | ||
116 | &::-webkit-scrollbar-thumb { | ||
117 | background: $theme-gray-lighter; | ||
118 | border-radius: 10px; | ||
119 | -webkit-border-radius: 10px; | ||
120 | } | ||
121 | |||
122 | &::-webkit-scrollbar-thumb:window-inactive { | ||
123 | background: none; | ||
124 | } | ||
125 | } | ||
126 | |||
95 | .touchid__button { | 127 | .touchid__button { |
96 | margin-bottom: 25px; | 128 | margin-bottom: 25px; |
97 | } | 129 | } |
@@ -135,6 +167,7 @@ | |||
135 | padding-top: 2%; | 167 | padding-top: 2%; |
136 | padding-bottom: 2%; | 168 | padding-bottom: 2%; |
137 | justify-content: center; | 169 | justify-content: center; |
170 | height: fit-content; | ||
138 | } | 171 | } |
139 | 172 | ||
140 | .auth__adlk { | 173 | .auth__adlk { |
@@ -168,3 +201,29 @@ | |||
168 | text-align: center; | 201 | text-align: center; |
169 | } | 202 | } |
170 | } | 203 | } |
204 | |||
205 | .auth__main--releasenotes { | ||
206 | margin: 4% 2% 0% 4%; | ||
207 | display: flex; | ||
208 | flex-direction: column; | ||
209 | justify-content: center; | ||
210 | height: -webkit-fill-available; | ||
211 | } | ||
212 | |||
213 | .auth__header { | ||
214 | font-size: x-large; | ||
215 | display: inline-flex; | ||
216 | flex-direction: row; | ||
217 | align-content: center; | ||
218 | justify-content: center; | ||
219 | flex-wrap: wrap; | ||
220 | height: fit-content; | ||
221 | |||
222 | &-item__secondary { | ||
223 | padding-left: 5px | ||
224 | } | ||
225 | } | ||
226 | |||
227 | .auth__body { | ||
228 | margin-top: 2%; | ||
229 | } | ||
diff --git a/src/styles/settings.scss b/src/styles/settings.scss index 76d167fd4..f16fc91fd 100644 --- a/src/styles/settings.scss +++ b/src/styles/settings.scss | |||
@@ -234,6 +234,10 @@ | |||
234 | 234 | ||
235 | .settings__header-item { | 235 | .settings__header-item { |
236 | @extend %headline; | 236 | @extend %headline; |
237 | |||
238 | &__secondary { | ||
239 | padding-left: 5px | ||
240 | } | ||
237 | } | 241 | } |
238 | 242 | ||
239 | .separator { | 243 | .separator { |
@@ -630,3 +634,94 @@ | |||
630 | display: inline-block; | 634 | display: inline-block; |
631 | } | 635 | } |
632 | } | 636 | } |
637 | |||
638 | .settings__updates__changelog-button { | ||
639 | margin-left: 2% !important; | ||
640 | } | ||
641 | |||
642 | .releasenotes__body { | ||
643 | line-height: 150%; | ||
644 | |||
645 | h1 { | ||
646 | margin-top: 0; | ||
647 | font-weight: 400; | ||
648 | font-size: xx-large; | ||
649 | text-align: center; | ||
650 | } | ||
651 | |||
652 | h2 { | ||
653 | margin-top: 10%; | ||
654 | font-weight: 400; | ||
655 | font-size: x-large; | ||
656 | text-align: center; | ||
657 | margin-bottom: 2%; | ||
658 | } | ||
659 | |||
660 | h3 { | ||
661 | margin-top: 5%; | ||
662 | font-weight: 400; | ||
663 | font-size: large; | ||
664 | text-align: center; | ||
665 | margin-bottom: 2%; | ||
666 | } | ||
667 | |||
668 | h4 { | ||
669 | margin-top: 5%; | ||
670 | font-weight: 400; | ||
671 | font-size: medium; | ||
672 | text-align: center; | ||
673 | margin-bottom: 2%; | ||
674 | } | ||
675 | |||
676 | h5 { | ||
677 | margin-top: 5%; | ||
678 | font-weight: 400; | ||
679 | text-align: center; | ||
680 | margin-bottom: 2%; | ||
681 | } | ||
682 | |||
683 | p { | ||
684 | margin-top: 4%; | ||
685 | margin-bottom: 4%; | ||
686 | user-select: text; | ||
687 | } | ||
688 | |||
689 | a { | ||
690 | color: rgb(0, 102, 255) !important; | ||
691 | user-select: text; | ||
692 | } | ||
693 | |||
694 | code { | ||
695 | background: #f4f4f4; | ||
696 | border: 1px solid #ddd; | ||
697 | border-radius: 5px; | ||
698 | padding: 0.2em 0.4em; | ||
699 | font-size: 85%; | ||
700 | color: #666; | ||
701 | font-family: monospace; | ||
702 | margin-bottom: 1.6em; | ||
703 | max-width: 100%; | ||
704 | overflow: auto; | ||
705 | user-select: text; | ||
706 | } | ||
707 | |||
708 | ul { | ||
709 | padding-left: 2rem; | ||
710 | } | ||
711 | |||
712 | li { | ||
713 | margin-top: 2%; | ||
714 | list-style-type: disc; | ||
715 | user-select: text; | ||
716 | } | ||
717 | |||
718 | img { | ||
719 | max-width: 100%; | ||
720 | margin-top: 2%; | ||
721 | margin-bottom: 2%; | ||
722 | align-items: center; | ||
723 | display: block; | ||
724 | margin-left: auto; | ||
725 | margin-right: auto; | ||
726 | } | ||
727 | } | ||
diff --git a/test/helpers/update-helpers.test.ts b/test/helpers/update-helpers.test.ts new file mode 100644 index 000000000..0494c6855 --- /dev/null +++ b/test/helpers/update-helpers.test.ts | |||
@@ -0,0 +1,89 @@ | |||
1 | import * as update_helpers from '../../src/helpers/update-helpers'; | ||
2 | |||
3 | describe('getFerdiumVersion', () => { | ||
4 | const baseVersion = '6.0.0-nightly.3'; | ||
5 | it(`returns ${baseVersion} for empty string`, () => { | ||
6 | const result = update_helpers.getFerdiumVersion('', baseVersion); | ||
7 | expect(result).toEqual(`v${baseVersion}`); | ||
8 | }); | ||
9 | |||
10 | it(`returns ${baseVersion} for ${baseVersion}`, () => { | ||
11 | const result = update_helpers.getFerdiumVersion('', baseVersion); | ||
12 | expect(result).toEqual(`v${baseVersion}`); | ||
13 | }); | ||
14 | |||
15 | it(`returns v6.0.0-beta.3`, () => { | ||
16 | const result = update_helpers.getFerdiumVersion( | ||
17 | '?version=6.0.0-beta.3', | ||
18 | baseVersion, | ||
19 | ); | ||
20 | expect(result).toEqual(`v6.0.0-beta.3`); | ||
21 | }); | ||
22 | |||
23 | it(`returns v6.0.0`, () => { | ||
24 | const result = update_helpers.getFerdiumVersion( | ||
25 | '?version=6.0.0', | ||
26 | baseVersion, | ||
27 | ); | ||
28 | expect(result).toEqual(`v6.0.0`); | ||
29 | }); | ||
30 | |||
31 | it(`returns ${baseVersion}`, () => { | ||
32 | const result = update_helpers.getFerdiumVersion( | ||
33 | 'http://test/=6.0.0', | ||
34 | baseVersion, | ||
35 | ); | ||
36 | expect(result).toEqual(`v${baseVersion}`); | ||
37 | }); | ||
38 | |||
39 | it(`returns ${baseVersion} for missing 'version='`, () => { | ||
40 | const result = update_helpers.getFerdiumVersion( | ||
41 | 'http://test/', | ||
42 | baseVersion, | ||
43 | ); | ||
44 | expect(result).toEqual(`v${baseVersion}`); | ||
45 | }); | ||
46 | }); | ||
47 | |||
48 | describe('updateVersionParse', () => { | ||
49 | it(`returns empty string for empty string`, () => { | ||
50 | const result = update_helpers.updateVersionParse(''); | ||
51 | expect(result).toEqual(''); | ||
52 | }); | ||
53 | it(`returns '?version=x.x for x.x`, () => { | ||
54 | const result = update_helpers.updateVersionParse('6.0.0'); | ||
55 | expect(result).toEqual('?version=6.0.0'); | ||
56 | }); | ||
57 | }); | ||
58 | |||
59 | describe('onAuthGoToReleaseNotes', () => { | ||
60 | it(`returns '#/releasenotes' string for empty string`, () => { | ||
61 | const result = update_helpers.onAuthGoToReleaseNotes('', ''); | ||
62 | expect(result).toEqual('#/releasenotes'); | ||
63 | }); | ||
64 | |||
65 | it(`returns '#/releasenotes' string for empty string`, () => { | ||
66 | const result = update_helpers.onAuthGoToReleaseNotes('', '?version=6.0.0'); | ||
67 | expect(result).toEqual('#/releasenotes?version=6.0.0'); | ||
68 | }); | ||
69 | |||
70 | it(`returns '#/releasenotes' string for empty string`, () => { | ||
71 | const result = update_helpers.onAuthGoToReleaseNotes(''); | ||
72 | expect(result).toEqual('#/releasenotes'); | ||
73 | }); | ||
74 | |||
75 | it(`returns '#/releasenotes' string for empty string`, () => { | ||
76 | const result = update_helpers.onAuthGoToReleaseNotes('#/auth', ''); | ||
77 | expect(result).toEqual('#/auth/releasenotes'); | ||
78 | }); | ||
79 | |||
80 | it(`returns '#/releasenotes' string for empty string`, () => { | ||
81 | const result = update_helpers.onAuthGoToReleaseNotes('#/auth', '?version=6.0.0'); | ||
82 | expect(result).toEqual('#/auth/releasenotes?version=6.0.0'); | ||
83 | }); | ||
84 | |||
85 | it(`returns '#/releasenotes' string for empty string`, () => { | ||
86 | const result = update_helpers.onAuthGoToReleaseNotes('#/auth'); | ||
87 | expect(result).toEqual('#/auth/releasenotes'); | ||
88 | }); | ||
89 | }); | ||
diff --git a/test/jsUtils.test.ts b/test/jsUtils.test.ts index 8ef69b46f..406326d4b 100644 --- a/test/jsUtils.test.ts +++ b/test/jsUtils.test.ts | |||
@@ -110,4 +110,16 @@ describe('jsUtils', () => { | |||
110 | expect(result).toEqual([{ a: 'b' }, { c: 'd' }]); | 110 | expect(result).toEqual([{ a: 'b' }, { c: 'd' }]); |
111 | }); | 111 | }); |
112 | }); | 112 | }); |
113 | |||
114 | describe('isEscKeyPress', () => { | ||
115 | it('returns true if the key number is 27', () => { | ||
116 | const result = jsUtils.isEscKeyPress(27); | ||
117 | expect(result).toEqual(true); | ||
118 | }); | ||
119 | |||
120 | it('returns false if the key number is 27', () => { | ||
121 | const result = jsUtils.isEscKeyPress(28); | ||
122 | expect(result).toEqual(false); | ||
123 | }); | ||
124 | }); | ||
113 | }); | 125 | }); |
diff --git a/tsconfig.json b/tsconfig.json index 7a50a4a2d..d1465de86 100644 --- a/tsconfig.json +++ b/tsconfig.json | |||
@@ -7,7 +7,8 @@ | |||
7 | "target": "esnext", | 7 | "target": "esnext", |
8 | "lib": [ | 8 | "lib": [ |
9 | "esnext", | 9 | "esnext", |
10 | "dom" | 10 | "dom", |
11 | "dom.iterable" | ||
11 | ], | 12 | ], |
12 | "module": "CommonJS", | 13 | "module": "CommonJS", |
13 | "jsx": "react-jsx", | 14 | "jsx": "react-jsx", |