From 8d08787941aef52b1d0d9513a632648a4cc7a964 Mon Sep 17 00:00:00 2001 From: Daniel Karski Date: Wed, 22 May 2024 11:39:41 +0200 Subject: [PATCH] Release v2.3.0 - to stage (#1840) --- .github/workflows/e2e-development.yml | 2 +- .github/workflows/e2e-feature-branch.yml | 2 +- .github/workflows/e2e-pre-production.yml | 2 +- .github/workflows/e2e-production.yml | 2 +- .github/workflows/nexus-development.yml | 1 + .github/workflows/nexus-feature-branch.yml | 1 + .github/workflows/nexus-mass-update.yml | 3 +- .../workflows/nexus-pre-production-latest.yml | 3 +- .github/workflows/nexus-pre-production.yml | 3 +- .../workflows/nexus-production-with-os-rc.yml | 3 +- .github/workflows/nexus-production.yml | 3 +- LICENSE.md | 2 +- apps/mudita-center/package-lock.json | 4 +- apps/mudita-center/package.json | 4 +- .../input-search/input-search.component.tsx | 2 +- .../core/modal/modal.styled.elements.tsx | 2 - .../menu/__snapshots__/menu.test.tsx.snap | 54 ------ .../renderer/constants/menu-elements.ts | 10 -- .../renderer/locales/default/en-US.json | 5 - .../use-help-search/use-help-search.test.ts | 5 - .../app-update-step-modal.component.tsx | 11 +- .../services/analytic-data-tracker.service.ts | 16 +- ...is-app-initialization-finished.selector.ts | 10 +- .../is-app-update-process-passed.selector.ts | 34 +++- ...should-app-update-flow-visible.selector.ts | 5 +- .../error-connecting-modal-test-ids.enum.tsx | 8 - .../error-connecting-modal.stories.tsx | 27 --- .../components/error-connecting-modal.tsx | 97 ----------- .../register-first-phone-connection.ts | 12 -- .../contact-support-flow.container.test.tsx | 2 +- .../contacts/contacts.component.tsx | 7 + .../apps/base-app/base-app.component.tsx | 2 +- .../crash-dump/crash-dump.component.test.tsx | 7 +- .../crash-dump/crash-dump.component.tsx | 1 - libs/core/desktop/desktop.service.ts | 45 +++-- .../actions/initialize-mudita-pure.action.ts | 6 +- .../passcode-inputs.component.tsx | 2 +- .../passcode-modal/passcode-modal.test.tsx | 19 ++- .../device-select-drawer.component.tsx | 9 +- .../components/drawer-device.component.tsx | 9 +- .../actions/get-unlock-status.action.ts | 23 ++- libs/core/device/reducers/device.reducer.ts | 10 -- libs/core/help/components/help.component.tsx | 7 +- ...quires-serial-port-group-to-show.action.ts | 4 +- .../components/modals-manager.component.tsx | 28 ++-- .../components/modals-manager.container.tsx | 22 --- .../modals-manager/constants/event.enum.ts | 7 - .../constants/modal-layers.enum.ts | 1 - .../should-app-update-visible.selector.ts | 20 +++ .../onboarding/onboarding-ui.component.tsx | 2 +- .../components/backup/backup.test.tsx | 5 - libs/core/settings/actions/base.action.ts | 2 + .../actions/delete-collecting-data.action.ts | 17 -- libs/core/settings/actions/index.ts | 4 - .../actions/load-settings.action.test.ts | 5 +- .../settings/actions/load-settings.action.ts | 4 - .../send-diagnostic-data.action.test.ts | 158 ------------------ .../actions/send-diagnostic-data.action.ts | 51 ------ .../set-diagnostic-timestamp.action.test.ts | 43 ----- .../set-diagnostic-timestamp.action.ts | 17 -- .../actions/toggle-collection-data.action.ts | 17 -- .../actions/toggle-tethering.action.test.ts | 36 ---- .../actions/toggle-tethering.action.ts | 17 -- .../app-update-flow.component.tsx | 2 + .../privacy-policy-modal.component.tsx | 29 +--- .../core/settings/constants/event.constant.ts | 4 - .../controllers/settings.controller.test.ts | 5 - libs/core/settings/dto/settings.object.ts | 6 +- .../reducers/settings.reducer.test.ts | 73 -------- .../settings/reducers/settings.reducer.ts | 23 --- .../services/settings.service.test.ts | 5 - .../002-privacy-policy-accepted.migration.ts | 6 +- .../004-remove-deprecated-fields.migration.ts | 14 ++ .../settings/store/schemas/settings.schema.ts | 25 +-- libs/core/settings/store/settings.store.ts | 2 + package-lock.json | 6 +- package.json | 2 +- 77 files changed, 230 insertions(+), 914 deletions(-) delete mode 100644 libs/core/connecting/components/error-connecting-modal-test-ids.enum.tsx delete mode 100644 libs/core/connecting/components/error-connecting-modal.stories.tsx delete mode 100644 libs/core/connecting/components/error-connecting-modal.tsx delete mode 100644 libs/core/connecting/requests/register-first-phone-connection.ts delete mode 100644 libs/core/modals-manager/components/modals-manager.container.tsx create mode 100644 libs/core/modals-manager/selectors/should-app-update-visible.selector.ts delete mode 100644 libs/core/settings/actions/delete-collecting-data.action.ts delete mode 100644 libs/core/settings/actions/send-diagnostic-data.action.test.ts delete mode 100644 libs/core/settings/actions/send-diagnostic-data.action.ts delete mode 100644 libs/core/settings/actions/set-diagnostic-timestamp.action.test.ts delete mode 100644 libs/core/settings/actions/set-diagnostic-timestamp.action.ts delete mode 100644 libs/core/settings/actions/toggle-collection-data.action.ts delete mode 100644 libs/core/settings/actions/toggle-tethering.action.test.ts delete mode 100644 libs/core/settings/actions/toggle-tethering.action.ts create mode 100644 libs/core/settings/store/migrations/004-remove-deprecated-fields.migration.ts diff --git a/.github/workflows/e2e-development.yml b/.github/workflows/e2e-development.yml index e9d151d4a..27c72424a 100644 --- a/.github/workflows/e2e-development.yml +++ b/.github/workflows/e2e-development.yml @@ -17,7 +17,7 @@ jobs: node-version: 18.16.1 - name: Setup environment variables env: - CI: "true" + E2ECI: "true" TEST_GITHUB_TOKEN: ${{ secrets.MC_GITHUB_ACCESS_TOKEN }} TEST_BINARY_PATH: "../mudita-center/release/linux-unpacked/Mudita Center" PHRASE_API_KEY: ${{ secrets.PHRASE_API_KEY }} diff --git a/.github/workflows/e2e-feature-branch.yml b/.github/workflows/e2e-feature-branch.yml index 2bcc7b06e..fbbcceaf9 100644 --- a/.github/workflows/e2e-feature-branch.yml +++ b/.github/workflows/e2e-feature-branch.yml @@ -18,7 +18,7 @@ jobs: node-version: 18.16.1 - name: Setup environment variables env: - CI: "true" + E2ECI: "true" TEST_GITHUB_TOKEN: ${{ secrets.MC_GITHUB_ACCESS_TOKEN }} TEST_BINARY_PATH: "../mudita-center/release/linux-unpacked/Mudita Center" PHRASE_API_KEY: ${{ secrets.PHRASE_API_KEY }} diff --git a/.github/workflows/e2e-pre-production.yml b/.github/workflows/e2e-pre-production.yml index 6eb1dab4f..11bd7664a 100644 --- a/.github/workflows/e2e-pre-production.yml +++ b/.github/workflows/e2e-pre-production.yml @@ -19,7 +19,7 @@ jobs: node-version: 18.16.1 - name: Setup environment variables env: - CI: "true" + E2ECI: "true" TEST_GITHUB_TOKEN: ${{ secrets.MC_GITHUB_ACCESS_TOKEN }} TEST_BINARY_PATH: "../mudita-center/release/linux-unpacked/Mudita Center" PHRASE_API_KEY: ${{ secrets.PHRASE_API_KEY }} diff --git a/.github/workflows/e2e-production.yml b/.github/workflows/e2e-production.yml index 9dcece88c..8596de691 100644 --- a/.github/workflows/e2e-production.yml +++ b/.github/workflows/e2e-production.yml @@ -19,7 +19,7 @@ jobs: node-version: 18.16.1 - name: Setup environment variables env: - CI: "true" + E2ECI: "true" TEST_GITHUB_TOKEN: ${{ secrets.MC_GITHUB_ACCESS_TOKEN }} TEST_BINARY_PATH: "../mudita-center/release/linux-unpacked/Mudita Center" PHRASE_API_KEY: ${{ secrets.PHRASE_API_KEY }} diff --git a/.github/workflows/nexus-development.yml b/.github/workflows/nexus-development.yml index f3029450c..7380062de 100644 --- a/.github/workflows/nexus-development.yml +++ b/.github/workflows/nexus-development.yml @@ -21,6 +21,7 @@ jobs: - name: Setup Env for Windows if: matrix.os == 'Windows' env: + E2ECI: "false" PHRASE_API_KEY: ${{ secrets.PHRASE_API_KEY }} PHRASE_API_URL: ${{ secrets.PHRASE_API_URL }} PHRASE_API_KEY_DEV: ${{ secrets.PHRASE_API_KEY_DEV }} diff --git a/.github/workflows/nexus-feature-branch.yml b/.github/workflows/nexus-feature-branch.yml index 07e796d4b..a8ca95652 100644 --- a/.github/workflows/nexus-feature-branch.yml +++ b/.github/workflows/nexus-feature-branch.yml @@ -21,6 +21,7 @@ jobs: - name: Setup Env for Windows if: matrix.os == 'Windows' env: + E2ECI: "false" PHRASE_API_KEY: ${{ secrets.PHRASE_API_KEY }} PHRASE_API_URL: ${{ secrets.PHRASE_API_URL }} PHRASE_API_KEY_DEV: ${{ secrets.PHRASE_API_KEY_DEV }} diff --git a/.github/workflows/nexus-mass-update.yml b/.github/workflows/nexus-mass-update.yml index 652bd44d6..5431f5ee4 100644 --- a/.github/workflows/nexus-mass-update.yml +++ b/.github/workflows/nexus-mass-update.yml @@ -23,6 +23,7 @@ jobs: - name: Setup Env for Windows if: matrix.os == 'Windows' env: + E2ECI: "false" PHRASE_API_KEY: ${{ secrets.PHRASE_API_KEY }} PHRASE_API_URL: ${{ secrets.PHRASE_API_URL }} PHRASE_API_KEY_DEV: ${{ secrets.PHRASE_API_KEY_DEV }} @@ -142,13 +143,11 @@ jobs: run: | $env:NODE_OPTIONS="--max-old-space-size=4096" $env:LOCALAPPDATA="" - cd apps/mudita-center/ npm run app:dist - name: Build App for Linux/Mac if: matrix.os != 'Windows' run: | export NODE_OPTIONS="--max-old-space-size=4096" - cd apps/mudita-center/ npm run app:dist - name: Verify apple sign if: matrix.os == 'macOS' diff --git a/.github/workflows/nexus-pre-production-latest.yml b/.github/workflows/nexus-pre-production-latest.yml index d739001b5..e26222f05 100644 --- a/.github/workflows/nexus-pre-production-latest.yml +++ b/.github/workflows/nexus-pre-production-latest.yml @@ -24,6 +24,7 @@ jobs: - name: Setup Env for Windows if: matrix.os == 'Windows' env: + E2ECI: "false" PHRASE_API_KEY: ${{ secrets.PHRASE_API_KEY }} PHRASE_API_URL: ${{ secrets.PHRASE_API_URL }} PHRASE_API_KEY_DEV: ${{ secrets.PHRASE_API_KEY_DEV }} @@ -165,13 +166,11 @@ jobs: run: | $env:NODE_OPTIONS="--max-old-space-size=4096" $env:LOCALAPPDATA="" - cd apps/mudita-center/ npm run app:dist - name: Build App for Linux/Mac if: matrix.os != 'Windows' run: | export NODE_OPTIONS="--max-old-space-size=4096" - cd apps/mudita-center/ npm run app:dist - name: Verify apple sign if: matrix.os == 'macOS' diff --git a/.github/workflows/nexus-pre-production.yml b/.github/workflows/nexus-pre-production.yml index 614f7a31b..76eebf3f8 100644 --- a/.github/workflows/nexus-pre-production.yml +++ b/.github/workflows/nexus-pre-production.yml @@ -23,6 +23,7 @@ jobs: - name: Setup Env for Windows if: matrix.os == 'Windows' env: + E2ECI: "false" PHRASE_API_KEY: ${{ secrets.PHRASE_API_KEY }} PHRASE_API_URL: ${{ secrets.PHRASE_API_URL }} PHRASE_API_KEY_DEV: ${{ secrets.PHRASE_API_KEY_DEV }} @@ -90,13 +91,11 @@ jobs: run: | $env:NODE_OPTIONS="--max-old-space-size=4096" $env:LOCALAPPDATA="" - cd apps/mudita-center/ npm run app:dist - name: Build App for Linux/Mac if: matrix.os != 'Windows' run: | export NODE_OPTIONS="--max-old-space-size=4096" - cd apps/mudita-center/ npm run app:dist - name: Verify apple sign if: matrix.os == 'macOS' diff --git a/.github/workflows/nexus-production-with-os-rc.yml b/.github/workflows/nexus-production-with-os-rc.yml index a5bc80882..5cc4d8402 100644 --- a/.github/workflows/nexus-production-with-os-rc.yml +++ b/.github/workflows/nexus-production-with-os-rc.yml @@ -23,6 +23,7 @@ jobs: - name: Setup Env for Windows if: matrix.os == 'Windows' env: + E2ECI: "false" PHRASE_API_KEY: ${{ secrets.PHRASE_API_KEY }} PHRASE_API_URL: ${{ secrets.PHRASE_API_URL }} PHRASE_API_KEY_DEV: ${{ secrets.PHRASE_API_KEY_DEV }} @@ -142,13 +143,11 @@ jobs: run: | $env:NODE_OPTIONS="--max-old-space-size=4096" $env:LOCALAPPDATA="" - cd apps/mudita-center/ npm run app:dist - name: Build App for Linux/Mac if: matrix.os != 'Windows' run: | export NODE_OPTIONS="--max-old-space-size=4096" - cd apps/mudita-center/ npm run app:dist - name: Verify apple sign if: matrix.os == 'macOS' diff --git a/.github/workflows/nexus-production.yml b/.github/workflows/nexus-production.yml index e76e45be6..47e76ef14 100644 --- a/.github/workflows/nexus-production.yml +++ b/.github/workflows/nexus-production.yml @@ -23,6 +23,7 @@ jobs: - name: Setup Env for Windows if: matrix.os == 'Windows' env: + E2ECI: "false" PHRASE_API_KEY: ${{ secrets.PHRASE_API_KEY }} PHRASE_API_URL: ${{ secrets.PHRASE_API_URL }} PHRASE_API_KEY_DEV: ${{ secrets.PHRASE_API_KEY_DEV }} @@ -90,13 +91,11 @@ jobs: run: | $env:NODE_OPTIONS="--max-old-space-size=4096" $env:LOCALAPPDATA="" - cd apps/mudita-center/ npm run app:dist - name: Build App for Linux/Mac if: matrix.os != 'Windows' run: | export NODE_OPTIONS="--max-old-space-size=4096" - cd apps/mudita-center/ npm run app:dist - name: Verify apple sign if: matrix.os == 'macOS' diff --git a/LICENSE.md b/LICENSE.md index f7b1f15d1..303f496d1 100644 --- a/LICENSE.md +++ b/LICENSE.md @@ -1,7 +1,7 @@ # Software License Agreement Mudita Center – https://github.com/mudita/mudita-center -Copyright (c) 2017-2021, Mudita Sp. z o.o. All rights reserved. +Copyright (c) 2017-2024, Mudita Sp. z o.o. All rights reserved. ## Sources of Intellectual Property Included in Mudita Center diff --git a/apps/mudita-center/package-lock.json b/apps/mudita-center/package-lock.json index 04f7e32a5..8d1100c69 100644 --- a/apps/mudita-center/package-lock.json +++ b/apps/mudita-center/package-lock.json @@ -1,12 +1,12 @@ { "name": "@mudita/mudita-center-app", - "version": "2.2.8", + "version": "2.3.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@mudita/mudita-center-app", - "version": "2.2.8", + "version": "2.3.0", "license": "GPL-3.0", "dependencies": { "serialport": "10.1.0" diff --git a/apps/mudita-center/package.json b/apps/mudita-center/package.json index 4ea3efe27..40b7cfc25 100644 --- a/apps/mudita-center/package.json +++ b/apps/mudita-center/package.json @@ -1,6 +1,6 @@ { "name": "mudita-center", - "version": "2.2.8", + "version": "2.3.0", "description": "Mudita Center", "main": "./dist/main.js", "productName": "Mudita Center", @@ -39,7 +39,7 @@ "build": { "productName": "Mudita Center", "appId": "com.mudita.center", - "copyright": "Copyright (c) 2017-2023, Mudita sp. z o.o. All rights reserved.", + "copyright": "Copyright (c) 2017-2024, Mudita sp. z o.o. All rights reserved.", "mac": { "category": "public.app-category.utilities", "icon": "./icons/mac/icon.icns", diff --git a/libs/core/__deprecated__/renderer/components/core/input-search/input-search.component.tsx b/libs/core/__deprecated__/renderer/components/core/input-search/input-search.component.tsx index 611e030d1..01a663c07 100644 --- a/libs/core/__deprecated__/renderer/components/core/input-search/input-search.component.tsx +++ b/libs/core/__deprecated__/renderer/components/core/input-search/input-search.component.tsx @@ -436,7 +436,7 @@ const InputSearchComponent: FunctionComponent = ({ useEffect(() => { if (listRef.current) { listRef.current.children[activeItemIndex]?.scrollIntoView({ - behavior: "smooth", + behavior: "auto", block: "nearest", }) } diff --git a/libs/core/__deprecated__/renderer/components/core/modal/modal.styled.elements.tsx b/libs/core/__deprecated__/renderer/components/core/modal/modal.styled.elements.tsx index 4a02c9f55..d2e8715df 100644 --- a/libs/core/__deprecated__/renderer/components/core/modal/modal.styled.elements.tsx +++ b/libs/core/__deprecated__/renderer/components/core/modal/modal.styled.elements.tsx @@ -107,8 +107,6 @@ export const ModalSubTitle = styled(Text)` ` export const Close = styled(Button)` - margin-top: -0.6rem; - margin-right: -0.8rem; grid-area: Close; justify-self: end; width: 2.8rem; diff --git a/libs/core/__deprecated__/renderer/components/rest/menu/__snapshots__/menu.test.tsx.snap b/libs/core/__deprecated__/renderer/components/rest/menu/__snapshots__/menu.test.tsx.snap index c5d13a88a..abc2ad771 100644 --- a/libs/core/__deprecated__/renderer/components/rest/menu/__snapshots__/menu.test.tsx.snap +++ b/libs/core/__deprecated__/renderer/components/rest/menu/__snapshots__/menu.test.tsx.snap @@ -300,33 +300,6 @@ exports[`Device: Mudita harmony matches snapshot 1`] = ` /> -
@@ -724,33 +697,6 @@ exports[`Device: Mudita pure matches snapshot 1`] = ` />
-
diff --git a/libs/core/__deprecated__/renderer/constants/menu-elements.ts b/libs/core/__deprecated__/renderer/constants/menu-elements.ts index d43650606..12a9c2c37 100644 --- a/libs/core/__deprecated__/renderer/constants/menu-elements.ts +++ b/libs/core/__deprecated__/renderer/constants/menu-elements.ts @@ -93,16 +93,6 @@ export interface MenuElement { } export const baseMenuElements: MenuElement[] = [ - { - items: [ - { - button: views[View.Onboarding], - icon: IconType.Send, - visibleOn: [DeviceType.MuditaPure, DeviceType.MuditaHarmony], - }, - ], - viewKey: View.Onboarding, - }, { items: [ { diff --git a/libs/core/__deprecated__/renderer/locales/default/en-US.json b/libs/core/__deprecated__/renderer/locales/default/en-US.json index 8e4c81d4c..e39dac538 100644 --- a/libs/core/__deprecated__/renderer/locales/default/en-US.json +++ b/libs/core/__deprecated__/renderer/locales/default/en-US.json @@ -257,11 +257,6 @@ "module.connecting.criticalBatteryLevelModalDescription": "Charge your Pure, then disconnect and reconnect your phone to use Mudita Center.", "module.connecting.criticalBatteryLevelModalHeaderTitle": "MuditaOS", "module.connecting.criticalBatteryLevelModalTitle": "The battery in your Pure is flat.", - "module.connecting.errorConnectingDescription": "If you still have problems connecting to your device, have a look at our help pages.", - "module.connecting.errorConnectingModalHeaderSubTitle": "We couldn't connect to your device", - "module.connecting.errorConnectingModalHeaderTitle": "Error", - "module.connecting.errorConnectingModalSecondaryButton": "Cancel", - "module.connecting.errorConnectingModalTitle": "Make sure your device is plugged in using a USB C cable and restart Mudita Center or your computer to try again", "module.connecting.errorSyncModalButton": "Try again", "module.connecting.errorSyncModalDescription": "Please try to reconnect your device", "module.connecting.errorSyncModalHeaderTitle": "Error", diff --git a/libs/core/__deprecated__/renderer/utils/hooks/use-help-search/use-help-search.test.ts b/libs/core/__deprecated__/renderer/utils/hooks/use-help-search/use-help-search.test.ts index 27f48387d..dd39804f6 100644 --- a/libs/core/__deprecated__/renderer/utils/hooks/use-help-search/use-help-search.test.ts +++ b/libs/core/__deprecated__/renderer/utils/hooks/use-help-search/use-help-search.test.ts @@ -14,14 +14,9 @@ import { Settings } from "Core/settings/dto" export const fakeAppSettings: Settings = { applicationId: "app-Nr8uiSV7KmWxX3WOFqZPF7uB", - autostart: false, - tethering: false, - tray: true, osBackupLocation: `fake/path/pure/phone/backups/`, osDownloadLocation: `fake/path/pure/os/downloads/`, language: "en-US", - neverConnected: true, - collectingData: undefined, privacyPolicyAccepted: false, diagnosticSentTimestamp: 0, ignoredCrashDumps: [], diff --git a/libs/core/__deprecated__/renderer/wrappers/app-update-step-modal/app-update-step-modal.component.tsx b/libs/core/__deprecated__/renderer/wrappers/app-update-step-modal/app-update-step-modal.component.tsx index add6ed78c..05d643a00 100644 --- a/libs/core/__deprecated__/renderer/wrappers/app-update-step-modal/app-update-step-modal.component.tsx +++ b/libs/core/__deprecated__/renderer/wrappers/app-update-step-modal/app-update-step-modal.component.tsx @@ -61,7 +61,7 @@ const AppUpdateStepModal: FunctionComponent = ({ }) return () => unregister() - }) + }, [appCurrentVersion, appLatestVersion]) useEffect(() => { const unregister = registerErrorAppUpdateListener(() => { @@ -70,10 +70,15 @@ const AppUpdateStepModal: FunctionComponent = ({ toCenterVersion: appLatestVersion, state: TrackCenterUpdateState.Fail, }) - setAppUpdateStep(AppUpdateStep.Error) + setAppUpdateStep((prevAppUpdateStep) => { + // allow user to try updating before throw error to handle no network connection + return prevAppUpdateStep === AppUpdateStep.Updating + ? AppUpdateStep.Error + : prevAppUpdateStep + }) }) return () => unregister() - }) + }, [appCurrentVersion, appLatestVersion]) const handleProcessDownload = () => { void trackCenterUpdate({ diff --git a/libs/core/analytic-data-tracker/services/analytic-data-tracker.service.ts b/libs/core/analytic-data-tracker/services/analytic-data-tracker.service.ts index 0a3d589a3..4754fcd2d 100644 --- a/libs/core/analytic-data-tracker/services/analytic-data-tracker.service.ts +++ b/libs/core/analytic-data-tracker/services/analytic-data-tracker.service.ts @@ -91,7 +91,9 @@ export class AnalyticDataTrackerService implements AnalyticDataTrackerClass { this.visitorMetadata = visitorMetadata } - private trackRequest(event: TrackEvent): Promise { + private async trackRequest( + event: TrackEvent + ): Promise { const params: AxiosRequestConfig["params"] = { rec: 1, apiv: 1, @@ -101,10 +103,12 @@ export class AnalyticDataTrackerService implements AnalyticDataTrackerClass { ...event, } - return this.httpClient.post(this.apiUrl, undefined, { - // AUTO DISABLED - fix me if you like :) - // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment - params, - }) + try { + return await this.httpClient.post(this.apiUrl, undefined, { + params, + }) + } catch { + return undefined + } } } diff --git a/libs/core/app-initialization/selectors/is-app-initialization-finished.selector.ts b/libs/core/app-initialization/selectors/is-app-initialization-finished.selector.ts index 399f47ebe..959f52982 100644 --- a/libs/core/app-initialization/selectors/is-app-initialization-finished.selector.ts +++ b/libs/core/app-initialization/selectors/is-app-initialization-finished.selector.ts @@ -6,11 +6,17 @@ import { createSelector } from "@reduxjs/toolkit" import { isAppUpdateProcessPassed } from "Core/app-initialization/selectors/is-app-update-process-passed.selector" import { isUsbAccessGrantedSelector } from "Core/settings/selectors/is-usb-access-granted.selector" +import { settingsStateSelector } from "Core/settings/selectors" export const isAppInitializationFinishedSelector = createSelector( isAppUpdateProcessPassed, isUsbAccessGrantedSelector, - (appUpdateProcessPassed, usbAccessGranted): boolean => { - return appUpdateProcessPassed && usbAccessGranted + settingsStateSelector, + ( + appUpdateProcessPassed, + usbAccessGranted, + { privacyPolicyAccepted } + ): boolean => { + return appUpdateProcessPassed && usbAccessGranted && Boolean(privacyPolicyAccepted) } ) diff --git a/libs/core/app-initialization/selectors/is-app-update-process-passed.selector.ts b/libs/core/app-initialization/selectors/is-app-update-process-passed.selector.ts index 1c9c6a92f..10716025d 100644 --- a/libs/core/app-initialization/selectors/is-app-update-process-passed.selector.ts +++ b/libs/core/app-initialization/selectors/is-app-update-process-passed.selector.ts @@ -5,11 +5,37 @@ import { createSelector } from "@reduxjs/toolkit" import { settingsStateSelector } from "Core/settings/selectors" +import { shouldAppUpdateFlowVisible } from "Core/app-initialization/selectors/should-app-update-flow-visible.selector" -export const isAppUpdateProcessPassed = createSelector( +const selectNoDataAboutUpdateAvaible = createSelector( settingsStateSelector, - (settingsState): boolean => { - const { updateAvailable, updateAvailableSkipped, checkingForUpdateFailed } = settingsState - return checkingForUpdateFailed || updateAvailableSkipped || updateAvailable === false + ({ + updateAvailable, + updateAvailableSkipped, + checkingForUpdateFailed, + updateRequired, + }): boolean => { + return ( + updateAvailableSkipped === undefined && + updateAvailable === undefined && + checkingForUpdateFailed && + !updateRequired + ) + } +) + +const selectAppUpdateFlowPassed = createSelector( + settingsStateSelector, + shouldAppUpdateFlowVisible, + ({ updateAvailable }, appUpdateFlowVisible): boolean => { + return updateAvailable !== undefined && !appUpdateFlowVisible + } +) + +export const isAppUpdateProcessPassed = createSelector( + selectNoDataAboutUpdateAvaible, + selectAppUpdateFlowPassed, + (noDataAboutUpdateAvaible, appUpdateFlowPassed): boolean => { + return appUpdateFlowPassed || noDataAboutUpdateAvaible } ) diff --git a/libs/core/app-initialization/selectors/should-app-update-flow-visible.selector.ts b/libs/core/app-initialization/selectors/should-app-update-flow-visible.selector.ts index b4b60281b..ffd494241 100644 --- a/libs/core/app-initialization/selectors/should-app-update-flow-visible.selector.ts +++ b/libs/core/app-initialization/selectors/should-app-update-flow-visible.selector.ts @@ -8,8 +8,7 @@ import { settingsStateSelector } from "Core/settings/selectors" export const shouldAppUpdateFlowVisible = createSelector( settingsStateSelector, - (settingsState): boolean => { - const { updateAvailable, updateAvailableSkipped } = settingsState - return updateAvailable === true && !updateAvailableSkipped + ({ updateAvailable, updateAvailableSkipped, updateRequired }): boolean => { + return (updateAvailable && !updateAvailableSkipped) || updateRequired } ) diff --git a/libs/core/connecting/components/error-connecting-modal-test-ids.enum.tsx b/libs/core/connecting/components/error-connecting-modal-test-ids.enum.tsx deleted file mode 100644 index ea9d24bf7..000000000 --- a/libs/core/connecting/components/error-connecting-modal-test-ids.enum.tsx +++ /dev/null @@ -1,8 +0,0 @@ -/** - * Copyright (c) Mudita sp. z o.o. All rights reserved. - * For licensing, see https://github.com/mudita/mudita-center/blob/master/LICENSE.md - */ - -export enum ErrorConnectingModalTestIds { - Container = "error-connecting-modal-container" -} diff --git a/libs/core/connecting/components/error-connecting-modal.stories.tsx b/libs/core/connecting/components/error-connecting-modal.stories.tsx deleted file mode 100644 index d8cf5235a..000000000 --- a/libs/core/connecting/components/error-connecting-modal.stories.tsx +++ /dev/null @@ -1,27 +0,0 @@ -/** - * Copyright (c) Mudita sp. z o.o. All rights reserved. - * For licensing, see https://github.com/mudita/mudita-center/blob/master/LICENSE.md - */ - -import React from "react" -import { Meta } from "@storybook/react" -import Story from "Core/__deprecated__/renderer/components/storybook/story.component" -import { action } from "@storybook/addon-actions" -import ErrorConnectingModal from "Core/connecting/components/error-connecting-modal" - -export const ErrorConnectingModalStory = (): JSX.Element => { - return ( - - - - ) -} - -export default { - title: "Views|Connecting/Backup Modal Dialogs", - component: ErrorConnectingModalStory, -} as Meta diff --git a/libs/core/connecting/components/error-connecting-modal.tsx b/libs/core/connecting/components/error-connecting-modal.tsx deleted file mode 100644 index abb4befc0..000000000 --- a/libs/core/connecting/components/error-connecting-modal.tsx +++ /dev/null @@ -1,97 +0,0 @@ -/** - * Copyright (c) Mudita sp. z o.o. All rights reserved. - * For licensing, see https://github.com/mudita/mudita-center/blob/master/LICENSE.md - */ - -import { FunctionComponent } from "Core/core/types/function-component.interface" -import { intl } from "Core/__deprecated__/renderer/utils/intl" -import Icon from "Core/__deprecated__/renderer/components/core/icon/icon.component" -import Text, { - TextDisplayStyle, -} from "Core/__deprecated__/renderer/components/core/text/text.component" -import React, { ComponentProps, ReactNode } from "react" -import { defineMessages } from "react-intl" -import { - ModalContent, - ModalDialog, - ModalLink, - RoundIconWrapper, -} from "Core/ui/components/modal-dialog" -import { ModalSize } from "Core/__deprecated__/renderer/components/core/modal/modal.interface" -import { Size } from "Core/__deprecated__/renderer/components/core/button/button.config" -import { ErrorConnectingModalTestIds } from "Core/connecting/components/error-connecting-modal-test-ids.enum" -import { IconType } from "Core/__deprecated__/renderer/components/core/icon/icon-type" -import { ModalLayers } from "Core/modals-manager/constants/modal-layers.enum" -import { ipcRenderer } from "electron-better-ipc" -import { HelpActions } from "Core/__deprecated__/common/enums/help-actions.enum" - -const messages = defineMessages({ - errorConnectingModalHeaderTitle: { - id: "module.connecting.errorConnectingModalHeaderTitle", - }, - errorConnectingModalHeaderSubtitle: { - id: "module.connecting.errorConnectingModalHeaderSubTitle", - }, - errorConnectingModalSecondaryButton: { - id: "module.connecting.errorConnectingModalSecondaryButton", - }, - errorConnectingModalTitle: { - id: "module.connecting.errorConnectingModalTitle", - }, - errorConnectingDescription: { - id: "module.connecting.errorConnectingDescription", - }, -}) - -const ErrorConnectingModal: FunctionComponent< - ComponentProps -> = ({ closeModal, onClose, ...props }) => { - const openHelpWindow = () => ipcRenderer.callMain(HelpActions.OpenWindow) - return ( - - - - - - - - ( - {chunks} - ), - }, - }} - /> - - - ) -} - -export default ErrorConnectingModal diff --git a/libs/core/connecting/requests/register-first-phone-connection.ts b/libs/core/connecting/requests/register-first-phone-connection.ts deleted file mode 100644 index 4ecc8c7cf..000000000 --- a/libs/core/connecting/requests/register-first-phone-connection.ts +++ /dev/null @@ -1,12 +0,0 @@ -/** - * Copyright (c) Mudita sp. z o.o. All rights reserved. - * For licensing, see https://github.com/mudita/mudita-center/blob/master/LICENSE.md - */ - -import { updateSettings } from "Core/settings/requests" - -const registerFirstPhoneConnection = (): void => { - void updateSettings({ key: "neverConnected", value: false }) -} - -export default registerFirstPhoneConnection diff --git a/libs/core/contact-support/containers/contact-support-flow.container.test.tsx b/libs/core/contact-support/containers/contact-support-flow.container.test.tsx index 3d622c96c..4b2412b54 100644 --- a/libs/core/contact-support/containers/contact-support-flow.container.test.tsx +++ b/libs/core/contact-support/containers/contact-support-flow.container.test.tsx @@ -7,7 +7,7 @@ import React, { ComponentProps } from "react" import { Provider } from "react-redux" import store from "Core/__deprecated__/renderer/store" import { renderWithThemeAndIntl } from "Core/__deprecated__/renderer/utils/render-with-theme-and-intl" -import ModalsManager from "Core/modals-manager/components/modals-manager.container" +import ModalsManager from "Core/modals-manager/components/modals-manager.component" import ContactSupportFlow from "Core/contact-support/containers/contact-support-flow.container" import { ContactSupportFlowTestIds } from "Core/contact-support/components/contact-support-flow-test-ids.component" diff --git a/libs/core/contacts/components/contacts/contacts.component.tsx b/libs/core/contacts/components/contacts/contacts.component.tsx index 33abb2ca4..b13ea7940 100644 --- a/libs/core/contacts/components/contacts/contacts.component.tsx +++ b/libs/core/contacts/components/contacts/contacts.component.tsx @@ -274,6 +274,13 @@ const Contacts: FunctionComponent = ({ if (payload || message) { const newError: FormError[] = [] + + if (message === "Edit Contact request failed") { + void modalService.openModal(, true) + reject() + return + } + if ( message === "phone-number-duplicated" && payload?.primaryPhoneNumberIsDuplicated diff --git a/libs/core/core/components/apps/base-app/base-app.component.tsx b/libs/core/core/components/apps/base-app/base-app.component.tsx index 5ed7f88cb..9cfb2730f 100644 --- a/libs/core/core/components/apps/base-app/base-app.component.tsx +++ b/libs/core/core/components/apps/base-app/base-app.component.tsx @@ -10,7 +10,7 @@ import { useDeviceConnectedEffect } from "Core/core/hooks/use-device-connected-e import { useApplicationUpdateEffects } from "Core/core/hooks/use-application-update-effects" import { CrashDump } from "Core/crash-dump" import NetworkStatusChecker from "Core/__deprecated__/renderer/components/core/network-status-checker/network-status-checker.container" -import ModalsManager from "Core/modals-manager/components/modals-manager.container" +import ModalsManager from "Core/modals-manager/components/modals-manager.component" import { useWatchOutboxEntriesEffect } from "Core/core/hooks/use-watch-outbox-entries-effect" import { useWatchUnlockStatus } from "Core/core/hooks/use-watch-unlock-status-effect" import { useDeviceLockedEffect } from "Core/core/hooks/use-device-locked-effect" diff --git a/libs/core/crash-dump/components/crash-dump/crash-dump.component.test.tsx b/libs/core/crash-dump/components/crash-dump/crash-dump.component.test.tsx index 4d2ae68a9..5830bf751 100644 --- a/libs/core/crash-dump/components/crash-dump/crash-dump.component.test.tsx +++ b/libs/core/crash-dump/components/crash-dump/crash-dump.component.test.tsx @@ -198,14 +198,13 @@ test("Don't display any modal when `loadingState` flag is equal to `State.Loadin ).not.toBeInTheDocument() }) -test("display `Error` modal if data.files list isn't empty and `loadingState` flag is equal to `State.Failed`", () => { +test("Don't display any modal when `loadingState` flag is equal to `State.Failed`", () => { render({ ...initialStateMock, crashDump: { ...initialStateMock.crashDump, data: { ...initialStateMock.crashDump.data, - files: ["/pure/logs/crash-dumps/file.hex"], }, loadingState: State.Failed, }, @@ -214,7 +213,9 @@ test("display `Error` modal if data.files list isn't empty and `loadingState` fl expect( screen.queryByTestId(CrashDumpModalTestingIds.Content) ).not.toBeInTheDocument() - expect(screen.queryByTestId(CrashDumpTestingIds.Failed)).toBeInTheDocument() + expect( + screen.queryByTestId(CrashDumpTestingIds.Failed) + ).not.toBeInTheDocument() expect( screen.queryByTestId(CrashDumpTestingIds.Success) ).not.toBeInTheDocument() diff --git a/libs/core/crash-dump/components/crash-dump/crash-dump.component.tsx b/libs/core/crash-dump/components/crash-dump/crash-dump.component.tsx index 1531d018a..da2bf1040 100644 --- a/libs/core/crash-dump/components/crash-dump/crash-dump.component.tsx +++ b/libs/core/crash-dump/components/crash-dump/crash-dump.component.tsx @@ -157,7 +157,6 @@ const mapStateToProps = (state: ReduxRootState) => ({ state.crashDump.downloadingState === State.Loaded && state.crashDump.sendingState === State.Loaded, failed: - state.crashDump.loadingState === State.Failed || state.crashDump.downloadingState === State.Failed || state.crashDump.sendingState === State.Failed, deviceType: state.device.deviceType, diff --git a/libs/core/desktop/desktop.service.ts b/libs/core/desktop/desktop.service.ts index 61b76b8d0..2c207f11c 100644 --- a/libs/core/desktop/desktop.service.ts +++ b/libs/core/desktop/desktop.service.ts @@ -11,49 +11,42 @@ enum SerialPortGroup { uucp = "uucp", } -const POTENTIAL_GROUPS = [SerialPortGroup.dialout, SerialPortGroup.uucp]; - export class DesktopService { public async isLinux(): Promise { return process.platform === "linux" } public async hasUserSerialPortAccess(): Promise { - const userGroups = await this.getUserGroups(); - return POTENTIAL_GROUPS.some(group => userGroups.includes(group)); + const userGroups = await this.getUserGroups() + return userGroups.includes(SerialPortGroup.dialout) } public async addUserToSerialPortGroup(): Promise { - const userGroups = await this.getUserGroups(); - const groupName = POTENTIAL_GROUPS.find(group => !userGroups.includes(group)); + const command = `usermod -aG ${SerialPortGroup.dialout} $USER & usermod -aG ${SerialPortGroup.uucp} $USER` + // Set simpler process.title, otherwise, there is an error from sudoPrompt.exec - 'process.title cannot be used as a valid name.' + process.title = "Mudita Center: assign serial port access" - if (groupName) { - const command = `usermod -aG ${groupName} $USER`; - // Set simpler process.title, otherwise, there is an error from sudoPrompt.exec - 'process.title cannot be used as a valid name.' - process.title = "Mudita Center: assign serial port access"; - - return new Promise((resolve, reject) => { - sudoPrompt.exec(command, { name: 'User Serial Port Access' }, (error) => { - if (error === null) { - resolve(); - } else { - reject("Could not add user to serial port group"); - } - }); - }); - } + return new Promise((resolve, reject) => { + sudoPrompt.exec(command, { name: "User Serial Port Access" }, (error) => { + if (error === null) { + resolve() + } else { + reject("Could not add user to serial port group") + } + }) + }) } private async getUserGroups(): Promise { return new Promise((resolve, reject) => { exec("groups", (error, stdout, stderr) => { if (error || stderr) { - reject(`${error?.name} - ${error?.message} - ${stderr}`); + reject(`${error?.name} - ${error?.message} - ${stderr}`) } else { - const groups = stdout.trim().split(/\s+/); - resolve(groups); + const groups = stdout.trim().split(/\s+/) + resolve(groups) } - }); - }); + }) + }) } } diff --git a/libs/core/device-initialization/actions/initialize-mudita-pure.action.ts b/libs/core/device-initialization/actions/initialize-mudita-pure.action.ts index e5263d87b..8a4e5539b 100644 --- a/libs/core/device-initialization/actions/initialize-mudita-pure.action.ts +++ b/libs/core/device-initialization/actions/initialize-mudita-pure.action.ts @@ -55,11 +55,9 @@ export const initializeMuditaPure = createAsyncThunk< return DeviceInitializationStatus.Aborted } const unlockStatus = await dispatch(getUnlockStatus()) - if (!unlockStatus.payload) { + if (unlockStatus.payload === "LOCKED") { return DeviceInitializationStatus.Initializing - } - - if (!isActiveDeviceAttachedSelector(getState())) { + } else if (unlockStatus.payload === "ABORTED") { dispatch( setDeviceInitializationStatus(DeviceInitializationStatus.Aborted) ) diff --git a/libs/core/device-initialization/components/passcode-modal/passcode-inputs.component.tsx b/libs/core/device-initialization/components/passcode-modal/passcode-inputs.component.tsx index 826a7d750..62040558b 100644 --- a/libs/core/device-initialization/components/passcode-modal/passcode-inputs.component.tsx +++ b/libs/core/device-initialization/components/passcode-modal/passcode-inputs.component.tsx @@ -86,7 +86,7 @@ export const PasscodeInputs: FunctionComponent = ({ const onKeyDownHandler = (number: number) => (e: { key: string; code: string; preventDefault: () => void }) => { - if (/[0-9]/.test(e.key)) { + if (/^[0-9]$/.test(e.key)) { const backspaceEdgeCase = activeInput === 0 && e.key === "" if ( activeInput !== undefined && diff --git a/libs/core/device-initialization/components/passcode-modal/passcode-modal.test.tsx b/libs/core/device-initialization/components/passcode-modal/passcode-modal.test.tsx index a39826908..ce67b5533 100644 --- a/libs/core/device-initialization/components/passcode-modal/passcode-modal.test.tsx +++ b/libs/core/device-initialization/components/passcode-modal/passcode-modal.test.tsx @@ -46,6 +46,13 @@ const letterKeyEvent = { charCode: 0, } as KeyboardEvent +const F1KeyEvent = { + key: "F1", + code: "F1", + keyCode: 112, + charCode: 0, +} as KeyboardEvent + const backspaceKeyEvent = { key: "Backspace", code: "Backspace", @@ -88,7 +95,7 @@ test("Passcode inputs are disabled when filled", () => { expect(inputsList()[0]).toHaveStyleRule("background-color", "#f4f5f6") }) -test("Show typing error message", async () => { +test("Show typing error message when a latter is typed", async () => { const { inputsList, errorMessage } = renderer() fireEvent.keyDown(inputsList()[0] as Element, letterKeyEvent) await waitFor(() => @@ -98,6 +105,16 @@ test("Show typing error message", async () => { ) }) +test("Show typing error message when F1 is typed", async () => { + const { inputsList, errorMessage } = renderer() + fireEvent.keyDown(inputsList()[0] as Element, F1KeyEvent) + await waitFor(() => + expect(errorMessage()).toHaveTextContent( + "[value] component.passcodeModalErrorTyping" + ) + ) +}) + test("Message is displayed properly when request about phone lock return internal server error", async () => { const { inputsList, errorMessage } = renderer({ unlockDevice: jest.fn().mockReturnValue({ diff --git a/libs/core/device-select/components/device-select-drawer.component.tsx b/libs/core/device-select/components/device-select-drawer.component.tsx index e893e1635..7b07b7b36 100644 --- a/libs/core/device-select/components/device-select-drawer.component.tsx +++ b/libs/core/device-select/components/device-select-drawer.component.tsx @@ -44,21 +44,24 @@ const DrawerWrapper = styled("div")` .EZDrawer .EZDrawer__checkbox:checked ~ .EZDrawer__container { transition: transform 500ms; } + * { + box-sizing: border-box; + } ` const DrawerChildrenContainer = styled("div")` - padding: 1.3rem 1.8rem 1.3rem 1.8rem; + padding: 1.8rem; overflow: hidden; display: flex; flex-direction: column; - gap: 3.2rem; + gap: 3.4rem; height: 100%; ` const Header = styled("div")` display: flex; justify-content: space-between; - padding-right: 1.8rem; + padding-right: 0.7rem; ` const DevicesContainer = styled("div")` diff --git a/libs/core/device-select/components/drawer-device.component.tsx b/libs/core/device-select/components/drawer-device.component.tsx index 160071f7b..87383c2ee 100644 --- a/libs/core/device-select/components/drawer-device.component.tsx +++ b/libs/core/device-select/components/drawer-device.component.tsx @@ -25,10 +25,9 @@ import { intl } from "Core/__deprecated__/renderer/utils/intl" import { getSerialNumberValue } from "Core/utils/get-serial-number-value" const Device = styled("div")<{ active: boolean }>` - padding: 1.8rem 2.4rem 1.8rem 1rem; + padding: 1.8rem 2.1rem; display: flex; - min-width: 27.2rem; - max-width: 27.2rem; + width: 100%; &:hover { background: ${backgroundColor("main")}; @@ -55,7 +54,7 @@ const DeviceImageContainer = styled("div")` justify-content: center; min-height: 9.6rem; min-width: 9.1rem; - padding: 0 2.4rem 0 0rem; + padding: 0 2.8rem 0 0; ` export const DeviceImageStyled = styled(DeviceImage)` @@ -101,7 +100,7 @@ const ActiveDot = styled("span")` background-color: ${textColor("primary")}; border-radius: 50%; display: inline-block; - margin: 0rem 0.5rem 0.8rem 0.5rem; + margin: 0 0.5rem 0.8rem 0.5rem; ` const DeviceName = styled(Text)` diff --git a/libs/core/device/actions/get-unlock-status.action.ts b/libs/core/device/actions/get-unlock-status.action.ts index c53566bee..1e5d68672 100644 --- a/libs/core/device/actions/get-unlock-status.action.ts +++ b/libs/core/device/actions/get-unlock-status.action.ts @@ -4,19 +4,22 @@ */ import { createAsyncThunk } from "@reduxjs/toolkit" -import { DeviceEvent } from "Core/device/constants" +import { DeviceCommunicationError, DeviceEvent } from "Core/device/constants" import { unlockDeviceStatusRequest } from "Core/device/requests" import { ReduxRootState } from "Core/__deprecated__/renderer/store" -import { setLockTime } from "Core/device/actions/base.action" +import { setLockTime, setUnlockedStatus } from "Core/device/actions/base.action" import { getLeftTimeSelector } from "Core/device/selectors" import { handleCommunicationError } from "Core/device/actions/handle-communication-error.action" +export type UnlockStatus = "UNLOCKED" | "LOCKED" | "ABORTED" + export const getUnlockStatus = createAsyncThunk< - boolean, + UnlockStatus, void, { state: ReduxRootState } >(DeviceEvent.GetUnlockedStatus, async (_, { dispatch, getState }) => { - const { ok, error } = await unlockDeviceStatusRequest() + const result = await unlockDeviceStatusRequest() + const { ok, error } = result const leftTime = getLeftTimeSelector(getState()) if (ok && leftTime !== undefined) { @@ -27,5 +30,15 @@ export const getUnlockStatus = createAsyncThunk< await dispatch(handleCommunicationError(error)) } - return ok + if (error?.type === DeviceCommunicationError.DeviceLocked) { + dispatch(setUnlockedStatus(false)) + return "LOCKED" + } + + if (ok) { + dispatch(setUnlockedStatus(true)) + return "UNLOCKED" + } else { + return "ABORTED" + } }) diff --git a/libs/core/device/reducers/device.reducer.ts b/libs/core/device/reducers/device.reducer.ts index 7aa73a166..83bc95072 100644 --- a/libs/core/device/reducers/device.reducer.ts +++ b/libs/core/device/reducers/device.reducer.ts @@ -5,7 +5,6 @@ import { createReducer } from "@reduxjs/toolkit" import { - getUnlockStatus, loadDeviceData, loadStorageInfoAction, setCriticalBatteryLevelStatus, @@ -110,15 +109,6 @@ export const deviceReducer = createReducer( error: action.payload as AppError, } }) - .addCase(getUnlockStatus.fulfilled, (state, action) => { - return { - ...state, - status: { - ...state.status, - unlocked: action.payload, - }, - } - }) .addCase(setLockTime, (state, action) => { return { ...state, diff --git a/libs/core/help/components/help.component.tsx b/libs/core/help/components/help.component.tsx index 0c758b42d..cfaf62009 100644 --- a/libs/core/help/components/help.component.tsx +++ b/libs/core/help/components/help.component.tsx @@ -25,8 +25,7 @@ import Icon, { IconSize, } from "Core/__deprecated__/renderer/components/core/icon/icon.component" import { NormalizedHelpEntry } from "Core/__deprecated__/renderer/utils/contentful/normalize-help-data" -import ModalsManager from "Core/modals-manager/components/modals-manager.container" -import { fontWeight } from "Core/core/styles/theming/theme-getters" +import ModalsManager from "Core/modals-manager/components/modals-manager.component" import { IconButtonWithSecondaryTooltip } from "Core/__deprecated__/renderer/components/core/icon-button-with-tooltip/icon-button-with-secondary-tooltip.component" import { defineMessages } from "react-intl" import { IconType } from "Core/__deprecated__/renderer/components/core/icon/icon-type" @@ -91,10 +90,6 @@ const ArrowIcon = styled(Icon)` transform: rotate(270deg); ` -const NormalHeading = styled(Text)` - font-weight: ${fontWeight("default")}; -` - const Help: FunctionComponent = ({ list: { collection = [], items }, searchQuestion, diff --git a/libs/core/modals-manager/actions/check-app-requires-serial-port-group-to-show.action.ts b/libs/core/modals-manager/actions/check-app-requires-serial-port-group-to-show.action.ts index c6f45d4c3..07eb78564 100644 --- a/libs/core/modals-manager/actions/check-app-requires-serial-port-group-to-show.action.ts +++ b/libs/core/modals-manager/actions/check-app-requires-serial-port-group-to-show.action.ts @@ -19,9 +19,9 @@ export const checkAppRequiresSerialPortGroup = createAsyncThunk< ModalsManagerEvent.ShowAppRequiresSerialPortGroup, async (_, { dispatch }) => { const runningOnLinux = await isLinux() - const runningOnCI = process.env.CI === "true" + const runningOnE2ECI = process.env.E2ECI === "true" - if (!runningOnLinux || runningOnCI) { + if (!runningOnLinux || runningOnE2ECI) { dispatch(setUserHasSerialPortAccess(true)) return } diff --git a/libs/core/modals-manager/components/modals-manager.component.tsx b/libs/core/modals-manager/components/modals-manager.component.tsx index c33288ae4..2a0053019 100644 --- a/libs/core/modals-manager/components/modals-manager.component.tsx +++ b/libs/core/modals-manager/components/modals-manager.component.tsx @@ -4,34 +4,28 @@ */ import React from "react" +import { useSelector } from "react-redux" import { FunctionComponent } from "Core/core/types/function-component.interface" import ContactSupportFlow from "Core/contact-support/containers/contact-support-flow.container" import { UpdateOsInterruptedFlowContainer } from "Core/update/components/update-os-interrupted-flow" -import ErrorConnectingModal from "Core/connecting/components/error-connecting-modal" import ConnectingLoaderModal from "Core/modals-manager/components/connecting-loader-modal.component" -import DetachedDuringUploadErrorModal - from "Core/files-manager/components/dettached-during-upload-error-modal/dettached-during-upload-error-modal.component" +import DetachedDuringUploadErrorModal from "Core/files-manager/components/dettached-during-upload-error-modal/dettached-during-upload-error-modal.component" +import { AppUpdateFlow } from "Core/settings/components" +import { shouldAppUpdateVisibleSelector } from "Core/modals-manager/selectors/should-app-update-visible.selector" +import { ReduxRootState } from "Core/__deprecated__/renderer/store" -type Props = { - contactSupportFlowShow: boolean - deviceInitializationFailedModalShowEnabled: boolean - hideModals: () => void -} - -const ModalsManager: FunctionComponent = ({ - contactSupportFlowShow, - deviceInitializationFailedModalShowEnabled, - hideModals, -}) => { +const ModalsManager: FunctionComponent = () => { + const appUpdateVisible = useSelector(shouldAppUpdateVisibleSelector) + const contactSupportFlowShow = useSelector( + (state: ReduxRootState) => state.modalsManager.contactSupportFlowShow + ) return ( <> - {deviceInitializationFailedModalShowEnabled && ( - - )} {contactSupportFlowShow && } + {appUpdateVisible && } ) } diff --git a/libs/core/modals-manager/components/modals-manager.container.tsx b/libs/core/modals-manager/components/modals-manager.container.tsx deleted file mode 100644 index 1cb7af851..000000000 --- a/libs/core/modals-manager/components/modals-manager.container.tsx +++ /dev/null @@ -1,22 +0,0 @@ -/** - * Copyright (c) Mudita sp. z o.o. All rights reserved. - * For licensing, see https://github.com/mudita/mudita-center/blob/master/LICENSE.md - */ - -import { connect } from "react-redux" -import { ReduxRootState, RootState } from "Core/__deprecated__/renderer/store" -import ModalsManager from "Core/modals-manager/components/modals-manager.component" -import { hideModals } from "Core/modals-manager" - -const mapStateToProps = (state: RootState & ReduxRootState) => { - return { - ...state.modalsManager, - deviceInitializationFailedModalShowEnabled: false, - } -} - -const mapDispatchToProps = { - hideModals, -} - -export default connect(mapStateToProps, mapDispatchToProps)(ModalsManager) diff --git a/libs/core/modals-manager/constants/event.enum.ts b/libs/core/modals-manager/constants/event.enum.ts index 57c63d874..795d6d3f3 100644 --- a/libs/core/modals-manager/constants/event.enum.ts +++ b/libs/core/modals-manager/constants/event.enum.ts @@ -4,14 +4,7 @@ */ export enum ModalsManagerEvent { - CheckAppForcedUpdateFlowToShow = "CHECK_APP_FORCED_UPDATE_FLOW_TO_SHOW", - CheckAppUpdateFlowToShow = "CHECK_APP_UPDATE_FLOW_TO_SHOW", - CheckCollectingDataModalToShow = "CHECK_COLLECTING_DATA_MODAL_TO_SHOW", HideModals = "HIDE_MODALS", - HideCollectingDataModal = "HIDE_COLLECTING_DATA_MODAL", ShowModal = "SHOW_MODAL", - ShowCollectingDataModal = "SHOW_COLLECTING_DATA_MODAL", - ShowAppForcedUpdateFlow = "SHOW_APP_FORCED_UPDATE_FLOW", ShowAppRequiresSerialPortGroup = "SHOW_APP_REQUIRES_SERIAL_PORT_GROUP", - AddUSBAccess = "ADD_USB_ACCESS", } diff --git a/libs/core/modals-manager/constants/modal-layers.enum.ts b/libs/core/modals-manager/constants/modal-layers.enum.ts index dca356f52..0b69139f0 100644 --- a/libs/core/modals-manager/constants/modal-layers.enum.ts +++ b/libs/core/modals-manager/constants/modal-layers.enum.ts @@ -10,7 +10,6 @@ export enum ModalLayers { ContactSupport, Passcode, EULA, - ErrorConnecting, LinuxSerialPortGroup, UpdateApp, PrivacyPolicy, diff --git a/libs/core/modals-manager/selectors/should-app-update-visible.selector.ts b/libs/core/modals-manager/selectors/should-app-update-visible.selector.ts new file mode 100644 index 000000000..df8c7e612 --- /dev/null +++ b/libs/core/modals-manager/selectors/should-app-update-visible.selector.ts @@ -0,0 +1,20 @@ +/** + * Copyright (c) Mudita sp. z o.o. All rights reserved. + * For licensing, see https://github.com/mudita/mudita-center/blob/master/LICENSE.md + */ + +import { createSelector } from "@reduxjs/toolkit" +import { getAppInitializationStatus } from "Core/app-initialization/selectors/get-app-initialization-status.selector" +import { modalsManagerStateSelector } from "Core/modals-manager" +import { AppInitializationStatus } from "Core/app-initialization/reducers/app-initialization.interface" + +export const shouldAppUpdateVisibleSelector = createSelector( + modalsManagerStateSelector, + getAppInitializationStatus, + ({ appUpdateFlowShow }, appInitializationStatus): boolean => { + return ( + appUpdateFlowShow && + appInitializationStatus === AppInitializationStatus.Initialized + ) + } +) diff --git a/libs/core/onboarding/components/onboarding/onboarding-ui.component.tsx b/libs/core/onboarding/components/onboarding/onboarding-ui.component.tsx index ecfd0acf6..49a9d0ee8 100644 --- a/libs/core/onboarding/components/onboarding/onboarding-ui.component.tsx +++ b/libs/core/onboarding/components/onboarding/onboarding-ui.component.tsx @@ -41,7 +41,7 @@ export interface Props { onTroubleshooting?: VoidFunction } -const deviceNames = ["Harmony 1", "Harmony 2", "Pure", "Kompakt"] +const deviceNames = ["Harmony 1", "Harmony 2", "Pure"] const OnboardingUI: FunctionComponent = ({ onCancel = noop, diff --git a/libs/core/overview/components/backup/backup.test.tsx b/libs/core/overview/components/backup/backup.test.tsx index dc33a7190..dc5e9bbb7 100644 --- a/libs/core/overview/components/backup/backup.test.tsx +++ b/libs/core/overview/components/backup/backup.test.tsx @@ -17,14 +17,9 @@ const lastBackupDate = new Date("2020-01-15T07:35:01.562Z") type Props = ComponentProps const defaultProps: Props = { - autostart: false, - collectingData: undefined, - tethering: false, - tray: false, diagnosticSentTimestamp: 0, language: "en-US", onBackupCreate: noop, - neverConnected: false, osBackupLocation: "", osDownloadLocation: "", backupActionDisabled: false, diff --git a/libs/core/settings/actions/base.action.ts b/libs/core/settings/actions/base.action.ts index ab9c49339..358f1ff3a 100644 --- a/libs/core/settings/actions/base.action.ts +++ b/libs/core/settings/actions/base.action.ts @@ -15,6 +15,8 @@ export const setSettings = createAction< | "updateAvailable" | "latestVersion" | "updateAvailableSkipped" + | "checkingForUpdate" + | "checkingForUpdateFailed" > >(SettingsEvent.SetSettings) diff --git a/libs/core/settings/actions/delete-collecting-data.action.ts b/libs/core/settings/actions/delete-collecting-data.action.ts deleted file mode 100644 index 035e7d177..000000000 --- a/libs/core/settings/actions/delete-collecting-data.action.ts +++ /dev/null @@ -1,17 +0,0 @@ -/** - * Copyright (c) Mudita sp. z o.o. All rights reserved. - * For licensing, see https://github.com/mudita/mudita-center/blob/master/LICENSE.md - */ - -import { createAsyncThunk } from "@reduxjs/toolkit" -import { SettingsEvent } from "Core/settings/constants" -import { updateSettings } from "Core/settings/requests" - -export const deleteCollectingData = createAsyncThunk( - SettingsEvent.DeleteCollectingData, - async () => { - await updateSettings({ key: "collectingData", value: undefined }) - - return - } -) diff --git a/libs/core/settings/actions/index.ts b/libs/core/settings/actions/index.ts index 9a2377530..399583026 100644 --- a/libs/core/settings/actions/index.ts +++ b/libs/core/settings/actions/index.ts @@ -6,9 +6,5 @@ export * from "./base.action" export * from "./check-update-available.action" export * from "./load-settings.action" -export * from "./send-diagnostic-data.action" -export * from "./set-diagnostic-timestamp.action" export * from "./set-os-backup-location.action" -export * from "./toggle-tethering.action" -export * from "./toggle-collection-data.action" export * from "./toggle-privacy-policy-accepted.action" diff --git a/libs/core/settings/actions/load-settings.action.test.ts b/libs/core/settings/actions/load-settings.action.test.ts index 452545a3f..a925acb86 100644 --- a/libs/core/settings/actions/load-settings.action.test.ts +++ b/libs/core/settings/actions/load-settings.action.test.ts @@ -18,7 +18,7 @@ jest.mock("../../../../apps/mudita-center/package.json", () => ({ })) jest.mock("Core/settings/requests", () => ({ - getSettings: jest.fn().mockReturnValue({ collectingData: false }), + getSettings: jest.fn().mockReturnValue({}), getConfiguration: jest.fn().mockReturnValue({ centerVersion: "1.0.0", productVersions: { @@ -63,9 +63,6 @@ test("`loadSettings` action dispatch SettingsEvent.LoadSettings event and calls { type: SettingsEvent.SetSettings, payload: { - checkingForUpdate: false, - checkingForUpdateFailed: false, - collectingData: false, currentVersion: `${packageInfo.version}`, lowestSupportedVersions: { lowestSupportedCenterVersion: "1.0.0", diff --git a/libs/core/settings/actions/load-settings.action.ts b/libs/core/settings/actions/load-settings.action.ts index 637f73bc0..e31a1467b 100644 --- a/libs/core/settings/actions/load-settings.action.ts +++ b/libs/core/settings/actions/load-settings.action.ts @@ -37,15 +37,11 @@ export const loadSettings = createAsyncThunk< ) } - settings.collectingData ? logger.enableRollbar() : logger.disableRollbar() - dispatch( setSettings({ ...settings, updateRequired, currentVersion: packageInfo.version, - checkingForUpdate: false, - checkingForUpdateFailed: false, lowestSupportedVersions: { lowestSupportedCenterVersion: configuration.centerVersion, lowestSupportedProductVersion: configuration.productVersions, diff --git a/libs/core/settings/actions/send-diagnostic-data.action.test.ts b/libs/core/settings/actions/send-diagnostic-data.action.test.ts deleted file mode 100644 index b3850f16c..000000000 --- a/libs/core/settings/actions/send-diagnostic-data.action.test.ts +++ /dev/null @@ -1,158 +0,0 @@ -/** - * Copyright (c) Mudita sp. z o.o. All rights reserved. - * For licensing, see https://github.com/mudita/mudita-center/blob/master/LICENSE.md - */ - -import { AnyAction } from "@reduxjs/toolkit" -import thunk from "redux-thunk" -import createMockStore from "redux-mock-store" -import MockDate from "mockdate" -import { sendDiagnosticData } from "./send-diagnostic-data.action" -import logger from "Core/__deprecated__/main/utils/logger" - -const dayBeforeDateMock = "2021-07-05T11:50:35.157Z" -const todayDateMock = "2021-08-05T11:50:35.157Z" - -MockDate.set(new Date(todayDateMock)) - -const setDiagnosticTimestampMock = jest.fn() - -jest.mock("Core/__deprecated__/main/utils/logger", () => ({ - error: jest.fn(), - info: jest.fn(), -})) -jest.mock("Core/settings/actions/set-diagnostic-timestamp.action", () => ({ - setDiagnosticTimestamp: () => setDiagnosticTimestampMock, -})) - -afterAll(() => { - MockDate.reset() -}) - -afterEach(() => { - jest.resetAllMocks() -}) - -describe("When `serialNumber` is equal to `undefined`", () => { - test("calls `logger.error` with error message and skip `setDiagnosticTimestamp`", async () => { - const mockStore = createMockStore([thunk])({ - settings: { - collectingData: undefined, - diagnosticSentTimestamp: undefined, - }, - device: { - data: { - serialNumber: undefined, - }, - }, - }) - - const { - meta: { requestId }, - // AUTO DISABLED - fix me if you like :) - // eslint-disable-next-line @typescript-eslint/await-thenable - } = await mockStore.dispatch(sendDiagnosticData() as unknown as AnyAction) - - expect(mockStore.getActions()).toEqual([ - sendDiagnosticData.pending(requestId), - sendDiagnosticData.fulfilled(undefined, requestId, undefined), - ]) - expect(logger.error).toHaveBeenCalledWith( - "Send Diagnostic Data: device logs fail. SerialNumber is undefined." - ) - expect(setDiagnosticTimestampMock).not.toHaveBeenCalled() - }) -}) - -describe("When user disallow sending diagnostic data", () => { - test("calls `logger.info` with info message and skip `setDiagnosticTimestamp`", async () => { - const mockStore = createMockStore([thunk])({ - settings: { - collectingData: false, - diagnosticSentTimestamp: undefined, - }, - device: { - data: { - serialNumber: "0000000000", - }, - }, - }) - - const { - meta: { requestId }, - // AUTO DISABLED - fix me if you like :) - // eslint-disable-next-line @typescript-eslint/await-thenable - } = await mockStore.dispatch(sendDiagnosticData() as unknown as AnyAction) - - expect(mockStore.getActions()).toEqual([ - sendDiagnosticData.pending(requestId), - sendDiagnosticData.fulfilled(undefined, requestId, undefined), - ]) - expect(logger.info).toHaveBeenCalledWith( - "Send Diagnostic Data: user no allowed sent data" - ) - expect(setDiagnosticTimestampMock).not.toHaveBeenCalled() - }) -}) - -describe("When diagnostic data has been sended today", () => { - test("calls `logger.info` with info message and skip `setDiagnosticTimestamp`", async () => { - const mockStore = createMockStore([thunk])({ - settings: { - collectingData: true, - diagnosticSentTimestamp: todayDateMock, - }, - device: { - data: { - serialNumber: "0000000000", - }, - }, - }) - - const { - meta: { requestId }, - // AUTO DISABLED - fix me if you like :) - // eslint-disable-next-line @typescript-eslint/await-thenable - } = await mockStore.dispatch(sendDiagnosticData() as unknown as AnyAction) - - expect(mockStore.getActions()).toEqual([ - sendDiagnosticData.pending(requestId), - sendDiagnosticData.fulfilled(undefined, requestId, undefined), - ]) - expect(logger.info).toHaveBeenCalledWith( - `Send Diagnostic Data: data was sent at ${todayDateMock}` - ) - expect(setDiagnosticTimestampMock).not.toHaveBeenCalled() - }) -}) - -describe("When diagnostic data has been sended day before", () => { - test("calls `logger.info` with info message and set `diagnosticSentTimestamp` via `setDiagnosticTimestamp`", async () => { - const mockStore = createMockStore([thunk])({ - settings: { - collectingData: true, - diagnosticSentTimestamp: dayBeforeDateMock, - }, - device: { - data: { - serialNumber: "0000000000", - }, - }, - }) - - const { - meta: { requestId }, - // AUTO DISABLED - fix me if you like :) - // eslint-disable-next-line @typescript-eslint/await-thenable - } = await mockStore.dispatch(sendDiagnosticData() as unknown as AnyAction) - - expect(mockStore.getActions()).toEqual([ - sendDiagnosticData.pending(requestId), - sendDiagnosticData.fulfilled(undefined, requestId, undefined), - ]) - expect(logger.info).toHaveBeenCalledWith( - `Send Diagnostic Data: skipped until the diagnostic data and storage system will be refined` - ) - expect(setDiagnosticTimestampMock).toHaveBeenCalled() - }) -}) diff --git a/libs/core/settings/actions/send-diagnostic-data.action.ts b/libs/core/settings/actions/send-diagnostic-data.action.ts deleted file mode 100644 index 40ccb7acd..000000000 --- a/libs/core/settings/actions/send-diagnostic-data.action.ts +++ /dev/null @@ -1,51 +0,0 @@ -/** - * Copyright (c) Mudita sp. z o.o. All rights reserved. - * For licensing, see https://github.com/mudita/mudita-center/blob/master/LICENSE.md - */ - -import { createAsyncThunk } from "@reduxjs/toolkit" -import { ReduxRootState } from "Core/__deprecated__/renderer/store" -import logger from "Core/__deprecated__/main/utils/logger" -import { isToday } from "Core/__deprecated__/renderer/utils/is-today" -import { SettingsEvent } from "Core/settings/constants" -import { setDiagnosticTimestamp } from "Core/settings/actions/set-diagnostic-timestamp.action" - -export const sendDiagnosticData = createAsyncThunk( - SettingsEvent.SendDiagnosticData, - // AUTO DISABLED - fix me if you like :) - // eslint-disable-next-line @typescript-eslint/require-await - async (_, { dispatch, getState }) => { - const state = getState() as ReduxRootState - - const { collectingData, diagnosticSentTimestamp } = state.settings - const serialNumber = state.device.data?.serialNumber - - if (serialNumber === undefined) { - logger.error( - `Send Diagnostic Data: device logs fail. SerialNumber is undefined.` - ) - return - } - if (!collectingData) { - logger.info("Send Diagnostic Data: user no allowed sent data") - return - } - - if (isToday(new Date(diagnosticSentTimestamp))) { - logger.info( - `Send Diagnostic Data: data was sent at ${diagnosticSentTimestamp}` - ) - return - } - - logger.info( - `Send Diagnostic Data: skipped until the diagnostic data and storage system will be refined` - ) - - const nowTimestamp = Date.now() - - void dispatch(setDiagnosticTimestamp(nowTimestamp)) - - return - } -) diff --git a/libs/core/settings/actions/set-diagnostic-timestamp.action.test.ts b/libs/core/settings/actions/set-diagnostic-timestamp.action.test.ts deleted file mode 100644 index b2837f325..000000000 --- a/libs/core/settings/actions/set-diagnostic-timestamp.action.test.ts +++ /dev/null @@ -1,43 +0,0 @@ -/** - * Copyright (c) Mudita sp. z o.o. All rights reserved. - * For licensing, see https://github.com/mudita/mudita-center/blob/master/LICENSE.md - */ - -import { AnyAction } from "@reduxjs/toolkit" -import thunk from "redux-thunk" -import createMockStore from "redux-mock-store" -import { setDiagnosticTimestamp } from "./set-diagnostic-timestamp.action" -import { updateSettings } from "Core/settings/requests" - -jest.mock("Core/settings/requests", () => ({ - updateSettings: jest.fn(), -})) - -const dateMock = new Date("2021-08-05T11:50:35.157Z").getDate() - -const mockStore = createMockStore([thunk])() - -afterEach(() => { - jest.clearAllMocks() -}) - -test("calls `setDiagnosticTimestamp` and `updateSettings` request with timestamp", async () => { - expect(updateSettings).not.toHaveBeenCalled() - - const { - meta: { requestId }, - // AUTO DISABLED - fix me if you like :) - // eslint-disable-next-line @typescript-eslint/await-thenable - } = await mockStore.dispatch( - setDiagnosticTimestamp(dateMock) as unknown as AnyAction - ) - - expect(mockStore.getActions()).toEqual([ - setDiagnosticTimestamp.pending(requestId, dateMock), - setDiagnosticTimestamp.fulfilled(dateMock, requestId, dateMock), - ]) - expect(updateSettings).toHaveBeenCalledWith({ - key: "diagnosticSentTimestamp", - value: dateMock, - }) -}) diff --git a/libs/core/settings/actions/set-diagnostic-timestamp.action.ts b/libs/core/settings/actions/set-diagnostic-timestamp.action.ts deleted file mode 100644 index b88007149..000000000 --- a/libs/core/settings/actions/set-diagnostic-timestamp.action.ts +++ /dev/null @@ -1,17 +0,0 @@ -/** - * Copyright (c) Mudita sp. z o.o. All rights reserved. - * For licensing, see https://github.com/mudita/mudita-center/blob/master/LICENSE.md - */ - -import { createAsyncThunk } from "@reduxjs/toolkit" -import { SettingsEvent } from "Core/settings/constants" -import { updateSettings } from "Core/settings/requests" - -export const setDiagnosticTimestamp = createAsyncThunk( - SettingsEvent.SetDiagnosticTimestamp, - async (payload) => { - await updateSettings({ key: "diagnosticSentTimestamp", value: payload }) - - return payload - } -) diff --git a/libs/core/settings/actions/toggle-collection-data.action.ts b/libs/core/settings/actions/toggle-collection-data.action.ts deleted file mode 100644 index 9ebc96106..000000000 --- a/libs/core/settings/actions/toggle-collection-data.action.ts +++ /dev/null @@ -1,17 +0,0 @@ -/** - * Copyright (c) Mudita sp. z o.o. All rights reserved. - * For licensing, see https://github.com/mudita/mudita-center/blob/master/LICENSE.md - */ - -import { createAsyncThunk } from "@reduxjs/toolkit" -import { SettingsEvent } from "Core/settings/constants" -import { updateSettings } from "Core/settings/requests" - -export const toggleCollectionData = createAsyncThunk( - SettingsEvent.ToggleCollectionData, - async (payload) => { - await updateSettings({ key: "collectingData", value: payload }) - - return payload - } -) diff --git a/libs/core/settings/actions/toggle-tethering.action.test.ts b/libs/core/settings/actions/toggle-tethering.action.test.ts deleted file mode 100644 index fd52531a7..000000000 --- a/libs/core/settings/actions/toggle-tethering.action.test.ts +++ /dev/null @@ -1,36 +0,0 @@ -/** - * Copyright (c) Mudita sp. z o.o. All rights reserved. - * For licensing, see https://github.com/mudita/mudita-center/blob/master/LICENSE.md - */ - -import { AnyAction } from "@reduxjs/toolkit" -import thunk from "redux-thunk" -import createMockStore from "redux-mock-store" -import { toggleTethering } from "./toggle-tethering.action" -import { updateSettings } from "Core/settings/requests" - -jest.mock("Core/settings/requests", () => ({ - updateSettings: jest.fn(), -})) - -const mockStore = createMockStore([thunk])() - -afterEach(() => { - jest.clearAllMocks() -}) - -test("calls `toggleTethering` and `updateSettings` request with boolean", async () => { - expect(updateSettings).not.toHaveBeenCalled() - - const { - meta: { requestId }, - // AUTO DISABLED - fix me if you like :) - // eslint-disable-next-line @typescript-eslint/await-thenable - } = await mockStore.dispatch(toggleTethering(true) as unknown as AnyAction) - - expect(mockStore.getActions()).toEqual([ - toggleTethering.pending(requestId, true), - toggleTethering.fulfilled(true, requestId, true), - ]) - expect(updateSettings).toHaveBeenCalledWith({ key: "tethering", value: true }) -}) diff --git a/libs/core/settings/actions/toggle-tethering.action.ts b/libs/core/settings/actions/toggle-tethering.action.ts deleted file mode 100644 index f84b4216f..000000000 --- a/libs/core/settings/actions/toggle-tethering.action.ts +++ /dev/null @@ -1,17 +0,0 @@ -/** - * Copyright (c) Mudita sp. z o.o. All rights reserved. - * For licensing, see https://github.com/mudita/mudita-center/blob/master/LICENSE.md - */ - -import { createAsyncThunk } from "@reduxjs/toolkit" -import { SettingsEvent } from "Core/settings/constants" -import { updateSettings } from "Core/settings/requests" - -export const toggleTethering = createAsyncThunk( - SettingsEvent.ToggleTethering, - async (payload) => { - await updateSettings({ key: "tethering", value: payload }) - - return payload - } -) diff --git a/libs/core/settings/components/app-update-flow/app-update-flow.component.tsx b/libs/core/settings/components/app-update-flow/app-update-flow.component.tsx index 69f390868..5440eebb7 100644 --- a/libs/core/settings/components/app-update-flow/app-update-flow.component.tsx +++ b/libs/core/settings/components/app-update-flow/app-update-flow.component.tsx @@ -12,6 +12,7 @@ import { ModalLayers } from "Core/modals-manager/constants/modal-layers.enum" import { settingsStateSelector } from "Core/settings/selectors" import { Dispatch } from "Core/__deprecated__/renderer/store" import { skipAvailableUpdate } from "Core/settings/actions/base.action" +import { hideModals } from "Core/modals-manager" export const AppUpdateFlow: FunctionComponent = () => { const dispatch = useDispatch() @@ -21,6 +22,7 @@ export const AppUpdateFlow: FunctionComponent = () => { const handleCloseModal = () => { dispatch(skipAvailableUpdate()) + dispatch(hideModals()) } return ( diff --git a/libs/core/settings/components/privacy-policy-modal/privacy-policy-modal.component.tsx b/libs/core/settings/components/privacy-policy-modal/privacy-policy-modal.component.tsx index 61710271c..8be43acb8 100644 --- a/libs/core/settings/components/privacy-policy-modal/privacy-policy-modal.component.tsx +++ b/libs/core/settings/components/privacy-policy-modal/privacy-policy-modal.component.tsx @@ -3,6 +3,11 @@ * For licensing, see https://github.com/mudita/mudita-center/blob/master/LICENSE.md */ +import React from "react" +import { defineMessages } from "react-intl" +import { useDispatch } from "react-redux" +import { ipcRenderer } from "electron-better-ipc" +import styled from "styled-components" import { ModalContent, ModalDialog, @@ -10,24 +15,17 @@ import { } from "Core/ui/components/modal-dialog" import { ModalSize } from "Core/__deprecated__/renderer/components/core/modal/modal.interface" import Icon from "Core/__deprecated__/renderer/components/core/icon/icon.component" - -import React, { useEffect } from "react" import { IconType } from "Core/__deprecated__/renderer/components/core/icon/icon-type" import Text from "Core/__deprecated__/renderer/components/core/text/text.component" import { TextDisplayStyle } from "Core/__deprecated__/renderer/components/core/text/text.component" -import styled from "styled-components" import { fontWeight, textColor, } from "Core/core/styles/theming/theme-getters" -import { defineMessages } from "react-intl" import { intl } from "Core/__deprecated__/renderer/utils/intl" -import { ipcRenderer } from "electron-better-ipc" import { AboutActions } from "Core/__deprecated__/common/enums/about-actions.enum" -import { useDispatch, useSelector } from "react-redux" import { togglePrivacyPolicyAccepted } from "Core/settings/actions" -import { Dispatch, ReduxRootState } from "Core/__deprecated__/renderer/store" -import { deleteCollectingData } from "Core/settings/actions/delete-collecting-data.action" +import { Dispatch } from "Core/__deprecated__/renderer/store" import { FunctionComponent } from "Core/core/types/function-component.interface" import { ModalLayers } from "Core/modals-manager/constants/modal-layers.enum" @@ -55,30 +53,15 @@ export const DescriptionText = styled(Text)` ` const PrivacyPolicyModal: FunctionComponent = () => { - const { collectingData } = useSelector( - (state: ReduxRootState) => state.settings - ) - const dispatch = useDispatch() const openPrivacyPolicyWindow = () => ipcRenderer.callMain(AboutActions.PolicyOpenBrowser) const handleAgreeButtonClick = (): void => { - void dispatch(deleteCollectingData()) void dispatch(togglePrivacyPolicyAccepted(true)) } - useEffect(() => { - if (collectingData === undefined) { - void dispatch(togglePrivacyPolicyAccepted(true)) - } - }, [collectingData, dispatch]) - - if (collectingData === undefined) { - return null - } - return ( { }) }) -describe("Functionality: toggle tethering", () => { - test("Event: ToggleTethering/fulfilled set `tethering` value", () => { - expect( - settingsReducer(undefined, { - type: fulfilledAction(SettingsEvent.ToggleTethering), - payload: true, - }) - ).toEqual({ - ...initialState, - tethering: true, - }) - expect( - settingsReducer(undefined, { - type: fulfilledAction(SettingsEvent.ToggleTethering), - payload: false, - }) - ).toEqual({ - ...initialState, - tethering: false, - }) - }) -}) - -describe("Functionality: toggle data collection", () => { - test("Event: ToggleCollectionData/fulfilled set `collectingData` value", () => { - expect( - settingsReducer(undefined, { - type: fulfilledAction(SettingsEvent.ToggleCollectionData), - payload: true, - }) - ).toEqual({ - ...initialState, - collectingData: true, - }) - expect( - settingsReducer(undefined, { - type: fulfilledAction(SettingsEvent.ToggleCollectionData), - payload: false, - }) - ).toEqual({ - ...initialState, - collectingData: false, - }) - }) -}) - -describe("Functionality: diagnostic data timestamp", () => { - test("Event: SetDiagnosticTimestamp/fulfilled set `diagnosticSentTimestamp` value", () => { - const timestamp = new Date().getDate() - - expect( - settingsReducer( - { - ...initialState, - diagnosticSentTimestamp: 0, - }, - { - type: fulfilledAction(SettingsEvent.SetDiagnosticTimestamp), - payload: timestamp, - } - ) - ).toEqual({ - ...initialState, - diagnosticSentTimestamp: timestamp, - }) - }) -}) - describe("Functionality: os backup location", () => { test("Event: SetOsBackupLocation/fulfilled set `osBackupLocation` value", () => { expect( diff --git a/libs/core/settings/reducers/settings.reducer.ts b/libs/core/settings/reducers/settings.reducer.ts index 09f0a461b..60fbb54e1 100644 --- a/libs/core/settings/reducers/settings.reducer.ts +++ b/libs/core/settings/reducers/settings.reducer.ts @@ -10,15 +10,11 @@ import { setLatestVersion, setOsBackupLocation, setSettings, - setDiagnosticTimestamp, - toggleTethering, toggleApplicationUpdateAvailable, - toggleCollectionData, togglePrivacyPolicyAccepted, setCheckingForUpdate, setUserHasSerialPortAccess, } from "Core/settings/actions" -import { deleteCollectingData } from "Core/settings/actions/delete-collecting-data.action" import { setCheckingForUpdateFailed, skipAvailableUpdate, @@ -35,12 +31,7 @@ export const initialState: SettingsState = { language: "", ignoredCrashDumps: [], diagnosticSentTimestamp: 0, - collectingData: undefined, privacyPolicyAccepted: undefined, - neverConnected: false, - tray: false, - autostart: false, - tethering: false, updateRequired: false, updateAvailable: undefined, updateAvailableSkipped: undefined, @@ -73,27 +64,13 @@ export const settingsReducer = createReducer( state.latestVersion = action.payload }) - .addCase(toggleTethering.fulfilled, (state, action) => { - state.tethering = action.payload - }) - .addCase(toggleApplicationUpdateAvailable, (state, action) => { state.updateAvailable = action.payload }) - .addCase(toggleCollectionData.fulfilled, (state, action) => { - state.collectingData = action.payload - }) - .addCase(togglePrivacyPolicyAccepted.fulfilled, (state, action) => { state.privacyPolicyAccepted = action.payload }) - .addCase(deleteCollectingData.fulfilled, (state, _) => { - state.collectingData = undefined - }) - .addCase(setDiagnosticTimestamp.fulfilled, (state, action) => { - state.diagnosticSentTimestamp = action.payload - }) .addCase(setOsBackupLocation.fulfilled, (state, action) => { state.osBackupLocation = action.payload diff --git a/libs/core/settings/services/settings.service.test.ts b/libs/core/settings/services/settings.service.test.ts index 6bf9c2f32..ee9fe4ca5 100644 --- a/libs/core/settings/services/settings.service.test.ts +++ b/libs/core/settings/services/settings.service.test.ts @@ -17,14 +17,9 @@ jest.mock("Core/settings/store/schemas", () => ({ export const fakeSettings: Settings = { applicationId: "app-Nr8uiSV7KmWxX3WOFqZPF7uB", - autostart: false, - tethering: false, - tray: true, osBackupLocation: `fake/path/pure/phone/backups/`, osDownloadLocation: `fake/path/pure/os/downloads/`, language: "en-US", - neverConnected: true, - collectingData: false, privacyPolicyAccepted: false, diagnosticSentTimestamp: 0, ignoredCrashDumps: [], diff --git a/libs/core/settings/store/migrations/002-privacy-policy-accepted.migration.ts b/libs/core/settings/store/migrations/002-privacy-policy-accepted.migration.ts index 240e6a577..ffa0964df 100644 --- a/libs/core/settings/store/migrations/002-privacy-policy-accepted.migration.ts +++ b/libs/core/settings/store/migrations/002-privacy-policy-accepted.migration.ts @@ -6,7 +6,7 @@ // AUTO DISABLED - fix me if you like :) // eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types, @typescript-eslint/no-explicit-any export const privacyPolicyAcceptedMigration = (store: any) => { - // AUTO DISABLED - fix me if you like :) - // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-unsafe-call - store.set("privacyPolicyAccepted", false) + if (store.get("settingsSchemaVersion") === undefined) { + store.set("privacyPolicyAccepted", false) + } } diff --git a/libs/core/settings/store/migrations/004-remove-deprecated-fields.migration.ts b/libs/core/settings/store/migrations/004-remove-deprecated-fields.migration.ts new file mode 100644 index 000000000..09ef48987 --- /dev/null +++ b/libs/core/settings/store/migrations/004-remove-deprecated-fields.migration.ts @@ -0,0 +1,14 @@ +/** + * Copyright (c) Mudita sp. z o.o. All rights reserved. + * For licensing, see https://github.com/mudita/mudita-center/blob/master/LICENSE.md + */ + +// AUTO DISABLED - fix me if you like :) +// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types, @typescript-eslint/no-explicit-any +export const removeDeprecatedFieldsMigration = (store: any) => { + store.set("settingsSchemaVersion", 4) + store.delete("collectingData") + store.delete("autostart") + store.delete("tray") + store.delete("neverConnected") +} diff --git a/libs/core/settings/store/schemas/settings.schema.ts b/libs/core/settings/store/schemas/settings.schema.ts index ebc04b698..510ee6e33 100644 --- a/libs/core/settings/store/schemas/settings.schema.ts +++ b/libs/core/settings/store/schemas/settings.schema.ts @@ -11,22 +11,13 @@ import translationConfig from "App/translations.config.json" import { generateApplicationId } from "Core/settings/store/schemas/generate-application-id" export const settingsSchema: Schema = { + settingsSchemaVersion: { + type: "number", + }, applicationId: { type: ["string", "null"], default: generateApplicationId(), }, - autostart: { - type: "boolean", - default: false, - }, - tethering: { - type: "boolean", - default: false, - }, - tray: { - type: "boolean", - default: false, - }, osBackupLocation: { type: "string", default: path.join(getAppPath(), "pure", "phone", "backups"), @@ -39,17 +30,9 @@ export const settingsSchema: Schema = { type: "string", default: translationConfig.defaultLanguage, }, - neverConnected: { - type: "boolean", - default: true, - }, - collectingData: { - type: "boolean", - default: undefined, - }, privacyPolicyAccepted: { type: "boolean", - default: false, + default: true, }, diagnosticSentTimestamp: { type: "number", diff --git a/libs/core/settings/store/settings.store.ts b/libs/core/settings/store/settings.store.ts index 7c788d0eb..7e85c9f51 100644 --- a/libs/core/settings/store/settings.store.ts +++ b/libs/core/settings/store/settings.store.ts @@ -13,6 +13,7 @@ import { removeUnusedFields, osDownloadLocationMigration, } from "Core/settings/store/migrations" +import { removeDeprecatedFieldsMigration } from "Core/settings/store/migrations/004-remove-deprecated-fields.migration" export const settingsStore = new Store({ name: "settings", @@ -27,5 +28,6 @@ export const settingsStore = new Store({ ">=1.4.1": removeUnusedFields, ">=2.0.2": privacyPolicyAcceptedMigration, ">=2.1.0": osDownloadLocationMigration, + ">=2.3.0": removeDeprecatedFieldsMigration, }, }) diff --git a/package-lock.json b/package-lock.json index 20e8fa148..965d21553 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "mudita-center", - "version": "2.2.8", + "version": "2.3.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "mudita-center", - "version": "2.2.8", + "version": "2.3.0", "license": "GPL-3.0", "workspaces": [ "apps/mudita-center", @@ -247,7 +247,7 @@ } }, "apps/mudita-center": { - "version": "2.2.8", + "version": "2.3.0", "license": "GPL-3.0", "dependencies": { "serialport": "10.1.0" diff --git a/package.json b/package.json index d7c295a77..0bc5ed111 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "name": "mudita-center", "description": "Mudita Center", "productName": "Mudita Center", - "version": "2.2.8", + "version": "2.3.0", "private": true, "workspaces": { "packages": [