Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: Add some exclusion to types to better handle remmaped DeviceEvent type to Redux Actions #17520

Open
wants to merge 2 commits into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions packages/suite/src/reducers/onboarding/onboardingReducer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { OnboardingAnalytics } from '@trezor/suite-analytics';
import { ONBOARDING } from 'src/actions/onboarding/constants';
import * as STEP from 'src/constants/onboarding/steps';
import type { AnyPath, AnyStepId } from 'src/types/onboarding';
import { Action, TrezorDevice } from 'src/types/suite';
import { Action } from 'src/types/suite';

export interface OnboardingRootState {
onboarding: OnboardingState;
Expand All @@ -26,7 +26,7 @@ export type BackupType = (typeof selectBackupTypes)[number];
export interface OnboardingState {
backupType: BackupType;
isActive: boolean;
prevDevice: TrezorDevice | null;
prevDeviceId: string | null;
activeStepId: AnyStepId;
path: AnyPath[];
onboardingAnalytics: Partial<OnboardingAnalytics>;
Expand All @@ -40,7 +40,7 @@ const initialState: OnboardingState = {
// prevDevice is used only in firmwareUpdate so maybe move it to firmwareUpdate
// and here leave only isMatchingPrevDevice ?

prevDevice: null,
prevDeviceId: null,
activeStepId: STEP.ID_FIRMWARE_STEP,
path: [],
onboardingAnalytics: {},
Expand Down Expand Up @@ -82,7 +82,7 @@ const onboarding = (state: OnboardingState = initialState, action: Action) => {
draft.path = removePath(action.payload, state);
break;
case DEVICE.DISCONNECT:
draft.prevDevice = action.payload;
draft.prevDeviceId = action.payload.id ?? null;
break;
case ONBOARDING.ANALYTICS:
draft.onboardingAnalytics = { ...state.onboardingAnalytics, ...action.payload };
Expand Down
16 changes: 13 additions & 3 deletions packages/suite/src/types/suite/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@ import { messageSystemActions } from '@suite-common/message-system';
import type { Route } from '@suite-common/suite-types';
import { notificationsActions } from '@suite-common/toast-notifications';
import { deviceActions, discoveryActions, transactionsActions } from '@suite-common/wallet-core';
import type { BlockchainEvent, TransportEvent, UiEvent } from '@trezor/connect';
import { BlockchainEvent, DEVICE, DeviceEvent, TransportEvent, UiEvent } from '@trezor/connect';
import { FilterOutFromUnionByTypeProperty } from '@trezor/type-utils';

import type { BackupAction } from 'src/actions/backup/backupActions';
import type { OnboardingAction } from 'src/actions/onboarding/onboardingActions';
Expand Down Expand Up @@ -41,7 +42,15 @@ export type {
TrezorDevice,
} from '@suite-common/suite-types';

type TrezorConnectEvents = TransportEvent | UiEvent | BlockchainEvent;
type FilteredDeviceEvents = FilterOutFromUnionByTypeProperty<
DeviceEvent,
'type',
// Those types are remapped onto different actions in the connectInitThunks.ts and not used directly
// as the rest of the DeviceEvents.
typeof DEVICE.CONNECT | typeof DEVICE.CONNECT_UNACQUIRED
>;

type TrezorConnectEvents = TransportEvent | UiEvent | FilteredDeviceEvents | BlockchainEvent;

export type TransactionAction = ReturnType<
(typeof transactionsActions)[keyof typeof transactionsActions]
Expand All @@ -62,7 +71,7 @@ type DeviceAuthenticityAction = ReturnType<

// all actions from all apps used to properly type Dispatch.
export type Action =
| TrezorConnectEvents // Todo: This should not be here, actions shall be defined independently from Connect Events (and they shall be mapped onto them)
| TrezorConnectEvents
| RouterAction
| WindowAction
| StorageAction
Expand Down Expand Up @@ -113,6 +122,7 @@ export type ForegroundAppProps = {
export type ToastNotificationVariant = 'success' | 'info' | 'warning' | 'error' | 'transparent';

export { TorStatus } from '@trezor/suite-desktop-api/src/enums';

export interface TorBootstrap {
current: number;
total: number;
Expand Down
5 changes: 2 additions & 3 deletions packages/suite/src/views/onboarding/UnexpectedState/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -27,12 +27,11 @@ const UnexpectedState = ({ children }: UnexpectedStateProps) => {
const device = useSelector(selectSelectedDevice);
const prerequisite = useSelector(selectPrerequisite);

const { prevDevice, activeStepId, showPinMatrix } = useOnboarding();
const { prevDeviceId, activeStepId, showPinMatrix } = useOnboarding();

const activeStep = steps.find(s => s.id === activeStepId);

const isNotSameDevice = useMemo(() => {
const prevDeviceId = prevDevice?.id;
// if no device was connected before, assume it is same device
if (!prevDeviceId) {
return false;
Expand All @@ -44,7 +43,7 @@ const UnexpectedState = ({ children }: UnexpectedStateProps) => {
}

return deviceId !== prevDeviceId;
}, [prevDevice, device]);
}, [prevDeviceId, device]);

const UnexpectedStateComponent = useMemo(() => {
if (!activeStep?.prerequisites) return null;
Expand Down
24 changes: 24 additions & 0 deletions packages/type-utils/src/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -108,3 +108,27 @@ export type DefinedUnionMember<T> = T extends string ? T : never;
export type FilterPropertiesByType<T, ValueFilter> = {
[Key in keyof T as T[Key] extends ValueFilter ? Key : never]: T[Key];
};

/**
* Removed the type from the union where `{ KeyName: ValueToExclude }`.
*
* Example:
* ```
* type T1 =
* | { type: 'A'; a: string }
* | { type: 'B'; b: number }
* | { type: 'C' | 'D' | 'E'; cde: boolean };
*
* // { type: 'A', a: string } | { type: 'B', b: number } | { type: 'D' | 'E', cde: boolean };
* type NotC = FilterOutFromUnionByTypeProperty<T1, 'type', 'C'>;
* ```
*/
export type FilterOutFromUnionByTypeProperty<
Union,
KeyName extends keyof Union,
ValueToExclude extends Union[KeyName],
> = Union extends { [K in KeyName]: infer ActualValue }
? ActualValue extends ValueToExclude
? never
: { [K in KeyName]: Exclude<ActualValue, ValueToExclude> } & Omit<Union, KeyName>
: Union;
5 changes: 3 additions & 2 deletions suite-common/connect-init/src/connectInitThunks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,11 +35,12 @@ export const connectInitThunk = createThunk(

// set event listeners and dispatch as
TrezorConnect.on(DEVICE_EVENT, ({ event: _, ...eventData }) => {
// dispatch event as action

if (eventData.type === DEVICE.CONNECT || eventData.type === DEVICE.CONNECT_UNACQUIRED) {
// This special case here allows us to "inject" extra data into action's payload
// and change the type of the action (in this case DeviceEvent type !== Redux Action type)
dispatch(deviceConnectThunks({ type: eventData.type, device: eventData.payload }));
} else {
// dispatch event as action
dispatch({ type: eventData.type, payload: eventData.payload });
}
});
Expand Down
13 changes: 1 addition & 12 deletions suite-common/wallet-core/src/device/deviceActions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { createAction } from '@reduxjs/toolkit';

import { ButtonRequest, TrezorDevice } from '@suite-common/suite-types';
import { WalletType } from '@suite-common/wallet-types';
import { DEVICE, Device, DeviceVersionChanged } from '@trezor/connect';
import { DEVICE, Device } from '@trezor/connect';

export const DEVICE_MODULE_PREFIX = '@suite/device';

Expand All @@ -29,16 +29,6 @@ const deviceDisconnect = createAction(DEVICE.DISCONNECT, (payload: TrezorDevice)
payload,
}));

// this action is not used but is required because of the typings
// changed here: https://github.com/trezor/trezor-suite/commit/c02412bccf80da7c827f624b7a7c85cdedf278c5#diff-2e9d057f0bfe2cc92fe50d4ce28838622d9e79fcca010ab8847a0fa288da13fd
// in fact action is dispatched from connectInitThunk same as the rest of events
const deviceFirmwareVersionChanged = createAction(
DEVICE.FIRMWARE_VERSION_CHANGED,
(payload: DeviceVersionChanged['payload']) => ({
payload,
}),
);

const updatePassphraseMode = createAction(
`${DEVICE_MODULE_PREFIX}/updatePassphraseMode`,
(payload: { device: TrezorDevice; hidden: boolean; alwaysOnDevice?: boolean }) => ({ payload }),
Expand Down Expand Up @@ -118,5 +108,4 @@ export const deviceActions = {
updateSelectedDevice,
removeButtonRequests,
setEntropyCheckFail,
deviceFirmwareVersionChanged,
};
1 change: 0 additions & 1 deletion suite-common/wallet-core/src/device/deviceThunks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,6 @@ type SelectDeviceThunkParams = {
* Called from:
* - `@trezor/connect` events handler `handleDeviceConnect`, `handleDeviceDisconnect`
* - from user action in `@suite-components/DeviceMenu`
* @param {(Device | TrezorDevice | undefined)} device
*/
export const selectDeviceThunk = createThunk<void, SelectDeviceThunkParams, void>(
`${DEVICE_MODULE_PREFIX}/selectDevice`,
Expand Down