Release v2.5.0 - to stage (#2199)

Co-authored-by: Daniel Karski <daniel.karski5q@gmail.com>
Co-authored-by: Michał Kurczewski <michalkurczewski94@gmail.com>
This commit is contained in:
MateuszMudita
2024-11-26 14:18:16 +01:00
committed by GitHub
parent 773bbdf5e5
commit a009946d9c
21 changed files with 185 additions and 71 deletions

View File

@@ -125,6 +125,24 @@ jobs:
if: matrix.os == 'macOS'
run: |
codesign -v -v apps/mudita-center/release/mac/Mudita\ Center.app
- name: Signing via Digicert
if: matrix.os == 'Windows'
env:
SM_HOST: ${{ secrets.SM_HOST }}
SM_API_KEY: ${{ secrets.SM_API_KEY }}
SM_CLIENT_CERT_FILE: "C:\\actions-runner\\certs\\Certificate_pkcs12.p12"
SM_CLIENT_CERT_PASSWORD: ${{ secrets.SM_CLIENT_CERT_PASSWORD }}
SM_CODE_SIGNING_CERT_SHA1_HASH: ${{ secrets.SM_CODE_SIGNING_CERT_SHA1_HASH }}
run: |
SET SM_HOST=%SM_HOST%
SET SM_API_KEY=%SM_API_KEY%
SET SM_CLIENT_CERT_FILE=%SM_CLIENT_CERT_FILE%
SET SM_CLIENT_CERT_PASSWORD=%SM_CLIENT_CERT_PASSWORD%
SET SM_CODE_SIGNING_CERT_SHA1_HASH=%SM_CODE_SIGNING_CERT_SHA1_HASH%
SET PATH=%PATH%;"C:\Program Files\DigiCert\DigiCert One Signing Manager Tools"
SET PATH=%PATH%;"C:\Program Files (x86)\Windows Kits\10\bin\10.0.26100.0\x64"
signtool.exe sign /sha1 %SM_CODE_SIGNING_CERT_SHA1_HASH% /tr http://timestamp.digicert.com /td SHA256 /fd SHA256 ./apps/mudita-center/release/Mudita-Center.exe
shell: cmd
- name: Push artifacts to nexus registry from Windows
if: matrix.os == 'Windows'
env:

View File

@@ -176,6 +176,24 @@ jobs:
if: matrix.os == 'macOS'
run: |
codesign -v -v apps/mudita-center/release/mac/Mudita\ Center.app
- name: Signing via Digicert
if: matrix.os == 'Windows'
env:
SM_HOST: ${{ secrets.SM_HOST }}
SM_API_KEY: ${{ secrets.SM_API_KEY }}
SM_CLIENT_CERT_FILE: "C:\\actions-runner\\certs\\Certificate_pkcs12.p12"
SM_CLIENT_CERT_PASSWORD: ${{ secrets.SM_CLIENT_CERT_PASSWORD }}
SM_CODE_SIGNING_CERT_SHA1_HASH: ${{ secrets.SM_CODE_SIGNING_CERT_SHA1_HASH }}
run: |
SET SM_HOST=%SM_HOST%
SET SM_API_KEY=%SM_API_KEY%
SET SM_CLIENT_CERT_FILE=%SM_CLIENT_CERT_FILE%
SET SM_CLIENT_CERT_PASSWORD=%SM_CLIENT_CERT_PASSWORD%
SET SM_CODE_SIGNING_CERT_SHA1_HASH=%SM_CODE_SIGNING_CERT_SHA1_HASH%
SET PATH=%PATH%;"C:\Program Files\DigiCert\DigiCert One Signing Manager Tools"
SET PATH=%PATH%;"C:\Program Files (x86)\Windows Kits\10\bin\10.0.26100.0\x64"
signtool.exe sign /sha1 %SM_CODE_SIGNING_CERT_SHA1_HASH% /tr http://timestamp.digicert.com /td SHA256 /fd SHA256 ./apps/mudita-center/release/Mudita-Center.exe
shell: cmd
- name: Push artifacts to nexus registry from Windows
if: matrix.os == 'Windows'
env:

View File

@@ -101,6 +101,24 @@ jobs:
if: matrix.os == 'macOS'
run: |
codesign -v -v apps/mudita-center/release/mac/Mudita\ Center.app
- name: Signing via Digicert
if: matrix.os == 'Windows'
env:
SM_HOST: ${{ secrets.SM_HOST }}
SM_API_KEY: ${{ secrets.SM_API_KEY }}
SM_CLIENT_CERT_FILE: "C:\\actions-runner\\certs\\Certificate_pkcs12.p12"
SM_CLIENT_CERT_PASSWORD: ${{ secrets.SM_CLIENT_CERT_PASSWORD }}
SM_CODE_SIGNING_CERT_SHA1_HASH: ${{ secrets.SM_CODE_SIGNING_CERT_SHA1_HASH }}
run: |
SET SM_HOST=%SM_HOST%
SET SM_API_KEY=%SM_API_KEY%
SET SM_CLIENT_CERT_FILE=%SM_CLIENT_CERT_FILE%
SET SM_CLIENT_CERT_PASSWORD=%SM_CLIENT_CERT_PASSWORD%
SET SM_CODE_SIGNING_CERT_SHA1_HASH=%SM_CODE_SIGNING_CERT_SHA1_HASH%
SET PATH=%PATH%;"C:\Program Files\DigiCert\DigiCert One Signing Manager Tools"
SET PATH=%PATH%;"C:\Program Files (x86)\Windows Kits\10\bin\10.0.26100.0\x64"
signtool.exe sign /sha1 %SM_CODE_SIGNING_CERT_SHA1_HASH% /tr http://timestamp.digicert.com /td SHA256 /fd SHA256 ./apps/mudita-center/release/Mudita-Center.exe
shell: cmd
- name: Push artifacts to nexus registry from Windows
if: matrix.os == 'Windows'
env:

View File

@@ -10,6 +10,14 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
Here we write upgrading notes for brands. It's a team effort to make them as
straightforward as possible.
## [2.5.0] - 2024-12-02
Starting with version 2.5.0, users will be able to synchronize the time and date on the Harmony and will be informed about an error in case of fail in the synchronization.
### Added
- Added time synchronization for Mudita Harmony.
## [2.4.0] - 2024-09-16
In this release, we have updated the Help section in the Mudita Center application. As of version 2.4.0, users can benefit from a refreshed help section with intuitive navigation. The article search functionality is also available. In addition, we have fixed two bugs occurring in our software.

View File

@@ -1,12 +1,12 @@
{
"name": "@mudita/mudita-center-app",
"version": "2.4.0",
"version": "2.5.0",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "@mudita/mudita-center-app",
"version": "2.4.0",
"version": "2.5.0",
"license": "GPL-3.0",
"dependencies": {
"serialport": "10.1.0"

View File

@@ -1,6 +1,6 @@
{
"name": "mudita-center",
"version": "2.4.0",
"version": "2.5.0",
"description": "Mudita Center",
"main": "./dist/main.js",
"productName": "Mudita Center",

View File

@@ -58,7 +58,7 @@ export const uploadFile = createAsyncThunk<
if (!openFileResult.ok || !openFileResult.data) {
dispatch(setUploadBlocked(false))
return rejectWithValue("no files to upload")
return
}
const filePaths = openFileResult.data

View File

@@ -7,6 +7,7 @@ import React, { FunctionComponent, useEffect } from "react"
import { BackupError, Modal } from "generic-view/ui"
import { useDispatch, useSelector } from "react-redux"
import {
BackupProcessStatus,
cleanBackupProcess,
selectActiveApiDeviceId,
selectBackupProcessStatus,
@@ -18,7 +19,7 @@ const BackupErrorModal: FunctionComponent = () => {
const dispatch = useDispatch()
const activeDeviceId = useSelector(selectActiveApiDeviceId)
const backupStatus = useSelector(selectBackupProcessStatus)
const opened = backupStatus === "FAILED" && !activeDeviceId
const opened = backupStatus === BackupProcessStatus.Failed && !activeDeviceId
const onClose = () => {
dispatch(cleanBackupProcess())

View File

@@ -8,6 +8,7 @@ import { BackupRestoreError, Modal } from "generic-view/ui"
import { useDispatch, useSelector } from "react-redux"
import {
cleanRestoreProcess,
RestoreProcessStatus,
selectActiveApiDeviceId,
selectBackupRestoreStatus,
setDeviceErrorModalOpened,
@@ -18,7 +19,7 @@ const RestoreErrorModal: FunctionComponent = () => {
const dispatch = useDispatch()
const activeDevice = useSelector(selectActiveApiDeviceId)
const restoreStatus = useSelector(selectBackupRestoreStatus)
const opened = restoreStatus === "FAILED" && !activeDevice
const opened = restoreStatus === RestoreProcessStatus.Failed && !activeDevice
const onClose = () => {
dispatch(cleanRestoreProcess())

View File

@@ -21,6 +21,7 @@ export * from "./lib/file-transfer/send-file.action"
export * from "./lib/file-transfer/get-file.action"
export * from "./lib/backup/load-backup-metadata.action"
export * from "./lib/backup/restore-backup.action"
export * from "./lib/backup/backup.types"
export * from "./lib/imports/start-import-authorization.action"
export * from "./lib/imports/reducer"
export * from "./lib/imports/actions"

View File

@@ -4,13 +4,13 @@
*/
import { createAction } from "@reduxjs/toolkit"
import { BackupProcess } from "./reducer"
import { ActionName } from "../action-names"
import {
BackupProcess,
BackupProcessFileStatus,
BackupProcessStatus,
RestoreProcessStatus,
} from "./reducer"
import { ActionName } from "../action-names"
} from "./backup.types"
export const setBackupProcess = createAction<BackupProcess>(
ActionName.SetBackupProcess

View File

@@ -0,0 +1,28 @@
/**
* 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 BackupProcessStatus {
PreBackup,
FilesTransfer,
SaveFile,
Done,
Failed,
}
export enum BackupProcessFileStatus {
Pending,
InProgress,
Done,
}
export enum RestoreProcessStatus {
PasswordNotRequired,
PasswordRequired,
PreRestore,
FilesTransfer,
Restoring,
Done,
Failed,
}

View File

@@ -21,6 +21,7 @@ import {
setBackupProcessStatus,
} from "./actions"
import { refreshBackupList } from "./refresh-backup-list.action"
import { BackupProcessFileStatus, BackupProcessStatus } from "./backup.types"
export const createBackup = createAsyncThunk<
undefined,
@@ -54,7 +55,7 @@ export const createBackup = createAsyncThunk<
dispatch(
setBackupProcess({
status: "PRE_BACKUP",
status: BackupProcessStatus.PreBackup,
featureFilesTransfer: features.reduce((acc, item) => {
return { ...acc, [item]: { done: false } }
}, {}),
@@ -107,7 +108,7 @@ export const createBackup = createAsyncThunk<
backupFeaturesFiles = checkPreBackupResponse.data.features
}
dispatch(setBackupProcessStatus("FILES_TRANSFER"))
dispatch(setBackupProcessStatus(BackupProcessStatus.FilesTransfer))
for (let i = 0; i < features.length; ++i) {
if (aborted) {
@@ -115,7 +116,12 @@ export const createBackup = createAsyncThunk<
}
const feature = features[i]
dispatch(setBackupProcessFileStatus({ feature, status: "IN_PROGRESS" }))
dispatch(
setBackupProcessFileStatus({
feature,
status: BackupProcessFileStatus.InProgress,
})
)
const filePromise = dispatch(
getFile({
deviceId,
@@ -131,7 +137,12 @@ export const createBackup = createAsyncThunk<
"transferId" in file.payload
) {
featureToTransferId[feature] = file.payload.transferId
dispatch(setBackupProcessFileStatus({ feature, status: "DONE" }))
dispatch(
setBackupProcessFileStatus({
feature,
status: BackupProcessFileStatus.Done,
})
)
} else if (!aborted) {
console.log("Error while downloading file")
await clearTransfers()
@@ -142,7 +153,7 @@ export const createBackup = createAsyncThunk<
if (aborted) {
return rejectWithValue(undefined)
}
dispatch(setBackupProcessStatus("SAVE_FILE"))
dispatch(setBackupProcessStatus(BackupProcessStatus.SaveFile))
const saveBackupFileResponse = await saveBackupFileRequest(
featureToTransferId,
deviceId,

View File

@@ -18,6 +18,11 @@ import { refreshBackupList } from "./refresh-backup-list.action"
import { RestoreMetadata } from "device/models"
import { loadBackupMetadata } from "./load-backup-metadata.action"
import { restoreBackup } from "./restore-backup.action"
import {
BackupProcessFileStatus,
BackupProcessStatus,
RestoreProcessStatus,
} from "./backup.types"
export interface Backup {
fileName: string
@@ -25,15 +30,6 @@ export interface Backup {
serialNumber: string
}
export type BackupProcessStatus =
| "PRE_BACKUP"
| "FILES_TRANSFER"
| "SAVE_FILE"
| "DONE"
| "FAILED"
export type BackupProcessFileStatus = "PENDING" | "IN_PROGRESS" | "DONE"
export interface BackupProcess {
status: BackupProcessStatus
featureFilesTransfer: Record<
@@ -42,15 +38,6 @@ export interface BackupProcess {
>
}
export type RestoreProcessStatus =
| "PASSWORD_NOT_REQUIRED"
| "PASSWORD_REQUIRED"
| "PRE_RESTORE"
| "FILES_TRANSFER"
| "RESTORING"
| "DONE"
| "FAILED"
export interface RestoreProcess {
status: RestoreProcessStatus
metadata?: RestoreMetadata
@@ -93,20 +80,20 @@ export const genericBackupsReducer = createReducer(initialState, (builder) => {
})
builder.addCase(createBackup.rejected, (state, action) => {
if (state.backupProcess) {
state.backupProcess.status = "FAILED"
state.backupProcess.status = BackupProcessStatus.Failed
} else {
state.backupProcess = {
status: "FAILED",
status: BackupProcessStatus.Failed,
featureFilesTransfer: {},
}
}
})
builder.addCase(createBackup.fulfilled, (state, action) => {
if (state.backupProcess) {
state.backupProcess.status = "DONE"
state.backupProcess.status = BackupProcessStatus.Done
} else {
state.backupProcess = {
status: "DONE",
status: BackupProcessStatus.Done,
featureFilesTransfer: {},
}
}
@@ -120,8 +107,8 @@ export const genericBackupsReducer = createReducer(initialState, (builder) => {
builder.addCase(loadBackupMetadata.fulfilled, (state, action) => {
state.restoreProcess = {
status: action.payload.restoreMetadata.header.password
? "PASSWORD_REQUIRED"
: "PASSWORD_NOT_REQUIRED",
? RestoreProcessStatus.PasswordRequired
: RestoreProcessStatus.PasswordNotRequired,
metadata: action.payload.restoreMetadata,
restoreFileId: action.payload.restoreFileId,
}
@@ -131,18 +118,18 @@ export const genericBackupsReducer = createReducer(initialState, (builder) => {
})
builder.addCase(loadBackupMetadata.rejected, (state, action) => {
state.restoreProcess = {
status: "FAILED",
status: RestoreProcessStatus.Failed,
}
})
builder.addCase(restoreBackup.pending, (state, action) => {
state.restoreProcess = {
...state.restoreProcess,
status: "PRE_RESTORE",
status: RestoreProcessStatus.PreRestore,
}
})
builder.addCase(restoreBackup.rejected, (state, action) => {
state.restoreProcess = {
status: "FAILED",
status: RestoreProcessStatus.Failed,
}
})
builder.addCase(setRestoreProcessStatus, (state, action) => {

View File

@@ -19,6 +19,7 @@ import { ActionName } from "../action-names"
import { sendFile } from "../file-transfer/send-file.action"
import { selectActiveApiDeviceId } from "../selectors/select-active-api-device-id"
import { setRestoreProcessFileStatus, setRestoreProcessStatus } from "./actions"
import { BackupProcessFileStatus, RestoreProcessStatus } from "./backup.types"
export const restoreBackup = createAsyncThunk<
undefined,
@@ -133,12 +134,14 @@ export const restoreBackup = createAsyncThunk<
dispatch(
setRestoreProcessFileStatus({
feature: featurePath.feature,
status: "PENDING",
status: BackupProcessFileStatus.Pending,
})
)
}
dispatch(setRestoreProcessStatus({ status: "FILES_TRANSFER" }))
dispatch(
setRestoreProcessStatus({ status: RestoreProcessStatus.FilesTransfer })
)
for (let i = 0; i < features.length; ++i) {
if (aborted) {
@@ -148,7 +151,7 @@ export const restoreBackup = createAsyncThunk<
dispatch(
setRestoreProcessFileStatus({
feature: featurePath.feature,
status: "IN_PROGRESS",
status: BackupProcessFileStatus.InProgress,
})
)
const sendFilePromise = dispatch(
@@ -170,7 +173,7 @@ export const restoreBackup = createAsyncThunk<
dispatch(
setRestoreProcessFileStatus({
feature: featurePath.feature,
status: "DONE",
status: BackupProcessFileStatus.Done,
})
)
}
@@ -178,7 +181,9 @@ export const restoreBackup = createAsyncThunk<
clearTransfers()
dispatch(setRestoreProcessStatus({ status: "RESTORING" }))
dispatch(
setRestoreProcessStatus({ status: RestoreProcessStatus.Restoring })
)
if (aborted) {
return rejectWithValue(undefined)
@@ -213,7 +218,7 @@ export const restoreBackup = createAsyncThunk<
if (aborted) {
return rejectWithValue(undefined)
}
dispatch(setRestoreProcessStatus({ status: "DONE" }))
dispatch(setRestoreProcessStatus({ status: RestoreProcessStatus.Done }))
return undefined
}
)

View File

@@ -26,6 +26,7 @@ import {
} from "../selectors/data-migration-devices"
import { clearEntities } from "../entities/actions"
import { DataMigrationStatus } from "../data-migration/reducer"
import { BackupProcessStatus } from "../backup/backup.types"
export const useAPISerialPortListeners = () => {
const dispatch = useDispatch<Dispatch>()
@@ -112,8 +113,15 @@ const useHandleDevicesDetached = () => {
}
dispatch(closeAllModals())
if (backupProcess) {
dispatch(setBackupProcessStatus("FAILED"))
if (
backupProcess &&
[
BackupProcessStatus.PreBackup,
BackupProcessStatus.SaveFile,
BackupProcessStatus.FilesTransfer,
].includes(backupProcess)
) {
dispatch(setBackupProcessStatus(BackupProcessStatus.Failed))
}
},
[

View File

@@ -6,6 +6,10 @@
import { createSelector } from "@reduxjs/toolkit"
import { ReduxRootState } from "Core/__deprecated__/renderer/store"
import {
BackupProcessFileStatus,
BackupProcessStatus,
} from "../backup/backup.types"
export const backupProgress = createSelector(
[(state: ReduxRootState) => state.genericBackups.backupProcess],
@@ -14,13 +18,13 @@ export const backupProgress = createSelector(
return { progress: 0 }
}
if (backupProcess.status === "DONE") {
if (backupProcess.status === BackupProcessStatus.Done) {
return { progress: 100 }
}
const features = Object.values(backupProcess.featureFilesTransfer)
const downloadedFilesCount = features.filter(
(item) => item.status === "DONE"
(item) => item.status === BackupProcessFileStatus.Done
).length
if (features.length <= downloadedFilesCount) {
@@ -29,7 +33,7 @@ export const backupProgress = createSelector(
const [featureInProgress] =
Object.entries(backupProcess.featureFilesTransfer).find(
([, item]) => item.status === "IN_PROGRESS"
([, item]) => item.status === BackupProcessFileStatus.InProgress
) ?? []
return {

View File

@@ -6,6 +6,10 @@
import { createSelector } from "@reduxjs/toolkit"
import { ReduxRootState } from "Core/__deprecated__/renderer/store"
import {
BackupProcessFileStatus,
RestoreProcessStatus,
} from "../backup/backup.types"
export const selectBackupRestore = createSelector(
[(state: ReduxRootState) => state.genericBackups.restoreProcess],
@@ -29,20 +33,20 @@ export const selectBackupRestoreProgress = createSelector(
}
if (
restoreProcess.status === "PASSWORD_NOT_REQUIRED" ||
restoreProcess.status === "PASSWORD_REQUIRED" ||
restoreProcess.status === "PRE_RESTORE"
restoreProcess.status === RestoreProcessStatus.PasswordNotRequired ||
restoreProcess.status === RestoreProcessStatus.PasswordRequired ||
restoreProcess.status === RestoreProcessStatus.PreRestore
) {
return { progress: 0 }
}
if (restoreProcess.status === "DONE") {
if (restoreProcess.status === RestoreProcessStatus.Done) {
return { progress: 100 }
}
const features = Object.values(restoreProcess.featureFilesTransfer ?? [])
const downloadedFilesCount = features.filter(
(item) => item.status === "DONE"
(item) => item.status === BackupProcessFileStatus.Done
).length
if (features.length <= downloadedFilesCount) {
@@ -51,7 +55,7 @@ export const selectBackupRestoreProgress = createSelector(
const [featureInProgress] =
Object.entries(restoreProcess.featureFilesTransfer ?? []).find(
([, item]) => item.status === "IN_PROGRESS"
([, item]) => item.status === BackupProcessFileStatus.InProgress
) ?? []
return {

View File

@@ -12,6 +12,7 @@ import {
closeModal as closeModalAction,
loadBackupMetadata,
restoreBackup,
RestoreProcessStatus,
selectBackupRestoreStatus,
} from "generic-view/store"
import { useDispatch, useSelector } from "react-redux"
@@ -116,21 +117,21 @@ export const BackupRestoreForm: FunctionComponent<BackupRestoreConfig> = ({
useEffect(() => {
switch (restoreStatus) {
case "PASSWORD_NOT_REQUIRED":
case RestoreProcessStatus.PasswordNotRequired:
startRestore()
break
case "PASSWORD_REQUIRED":
case RestoreProcessStatus.PasswordRequired:
setStep(Step.Password)
break
case "FAILED":
case RestoreProcessStatus.Failed:
setStep(Step.Error)
break
case "DONE":
case RestoreProcessStatus.Done:
setStep(Step.Success)
break
case "PRE_RESTORE":
case "FILES_TRANSFER":
case "RESTORING":
case RestoreProcessStatus.PreRestore:
case RestoreProcessStatus.FilesTransfer:
case RestoreProcessStatus.Restoring:
setStep(Step.Progress)
break
}

View File

@@ -16,6 +16,7 @@ import { Form } from "../../interactive/form/form"
import { useDispatch, useSelector } from "react-redux"
import { Dispatch } from "Core/__deprecated__/renderer/store"
import {
BackupProcessStatus,
cleanBackupProcess,
closeModal as closeModalAction,
createBackup,
@@ -124,15 +125,15 @@ const BackupCreateForm: FunctionComponent<BackupCreateConfig> = ({
useEffect(() => {
switch (backupProcessStatus) {
case "DONE":
case BackupProcessStatus.Done:
setStep(Step.Success)
break
case "FAILED":
case BackupProcessStatus.Failed:
setStep(Step.Error)
break
case "PRE_BACKUP":
case "FILES_TRANSFER":
case "SAVE_FILE":
case BackupProcessStatus.PreBackup:
case BackupProcessStatus.FilesTransfer:
case BackupProcessStatus.SaveFile:
setStep(Step.Progress)
break
}

2
package-lock.json generated
View File

@@ -258,7 +258,7 @@
}
},
"apps/mudita-center": {
"version": "2.4.0",
"version": "2.5.0",
"license": "GPL-3.0",
"dependencies": {
"serialport": "10.1.0"