From 2bab94b6249eaae3d2254ba9b74de0e0ce829591 Mon Sep 17 00:00:00 2001 From: Peter Sanderson Date: Mon, 23 Sep 2024 16:15:59 +0200 Subject: [PATCH 1/2] feat: Popover for Upgrade icon in the status bar --- .../src/components/Tooltip/TooltipBox.tsx | 3 +- packages/suite/package.json | 2 +- .../QuickActions/DebugAndExperimental.tsx | 2 +- .../Update/UpdateNotificationBanner.tsx | 134 ++++++++++++++++++ .../Update/UpdateStatusActionBarIcon.tsx | 94 ++++++++---- .../QuickActions/Update/UpdateTooltip.tsx | 13 +- .../Update/updateQuickActionTypes.ts | 40 +++++- .../QuickActions/Update/useUpdateStatus.ts | 48 ++++--- .../reducers/suite/desktopUpdateReducer.ts | 6 +- packages/suite/src/support/messages.ts | 36 +++++ 10 files changed, 316 insertions(+), 62 deletions(-) create mode 100644 packages/suite/src/components/suite/layouts/SuiteLayout/Sidebar/QuickActions/Update/UpdateNotificationBanner.tsx diff --git a/packages/components/src/components/Tooltip/TooltipBox.tsx b/packages/components/src/components/Tooltip/TooltipBox.tsx index b48a1b6c31b..b40fff1b387 100644 --- a/packages/components/src/components/Tooltip/TooltipBox.tsx +++ b/packages/components/src/components/Tooltip/TooltipBox.tsx @@ -29,9 +29,10 @@ const TooltipContainerStyled = styled.div` border-radius: ${TOOLTIP_BORDER_RADIUS}; text-align: left; border: solid 1.5px ${palette.darkGray100}; + margin: ${spacingsPx.xxxs}; max-width: ${props => props.$maxWidth}px; - ${typography.hint} + ${typography.hint} > div { padding: ${({ $isLarge, $isWithHeader }) => getContainerPadding($isLarge, $isWithHeader)}; } diff --git a/packages/suite/package.json b/packages/suite/package.json index b3e017cf011..a7b1e73c463 100644 --- a/packages/suite/package.json +++ b/packages/suite/package.json @@ -1,6 +1,6 @@ { "name": "@trezor/suite", - "suiteVersion": "24.10.0", + "suiteVersion": "0.0.0", "version": "1.0.0", "private": true, "scripts": { diff --git a/packages/suite/src/components/suite/layouts/SuiteLayout/Sidebar/QuickActions/DebugAndExperimental.tsx b/packages/suite/src/components/suite/layouts/SuiteLayout/Sidebar/QuickActions/DebugAndExperimental.tsx index d25b13fc9ca..1502b024096 100644 --- a/packages/suite/src/components/suite/layouts/SuiteLayout/Sidebar/QuickActions/DebugAndExperimental.tsx +++ b/packages/suite/src/components/suite/layouts/SuiteLayout/Sidebar/QuickActions/DebugAndExperimental.tsx @@ -19,7 +19,7 @@ const DebugAndExperimentalTooltip = ({ isEapEnabled, isExperimental, }: DebugAndExperimentalTooltipProps) => ( - + {isExperimental && ( ` + position: absolute; + bottom: 56px; + left: ${spacingsPx.xs}; + z-index: ${zIndices.navigationBar}; + display: flex; + flex-direction: column; + width: 262px; + padding: ${spacingsPx.xs} ${spacingsPx.sm}; + background: ${mapElevationToBackground}; + border-radius: ${borders.radii.sm}; + box-shadow: ${({ theme }) => theme.boxShadowElevated}; + cursor: ${({ onClick }) => (onClick !== undefined ? 'pointer' : undefined)}; +`; + +const CloseIconBackground = styled.div` + width: 36px; + height: 36px; + + display: flex; + justify-content: center; + align-items: center; + background-color: ${({ theme }) => theme.backgroundSurfaceElevation2}; + border-radius: ${borders.radii.full}; + cursor: ${({ onClick }) => (onClick !== undefined ? 'pointer' : undefined)}; +`; + +type UpdateNotificationBannerProps = { + updateStatusDevice: UpdateStatusDevice; + updateStatusSuite: UpdateStatusSuite; + onClose: () => void; +}; + +const mapDeviceUpdateStatusToTranslation: Record = { + 'just-updated': 'TR_QUICK_ACTION_UPDATE_POPOVER_TREZOR_HAS_BEEN_UPDATED', + 'up-to-date': null, + 'update-available': 'TR_QUICK_ACTION_UPDATE_POPOVER_TREZOR_UPDATE_AVAILABLE', +}; + +const mapSuiteUpdateStatusToHeaderTranslation: Record = { + 'update-downloaded-auto-restart-to-update': + 'TR_QUICK_ACTION_UPDATE_POPOVER_APP_HAS_BEEN_UPDATED', + 'update-downloaded-manual': 'TR_QUICK_ACTION_UPDATE_POPOVER_APP_DOWNLOADED', + 'just-updated': 'TR_QUICK_ACTION_UPDATE_POPOVER_APP_HAS_BEEN_UPDATED', + 'up-to-date': null, + 'update-available': 'TR_QUICK_ACTION_UPDATE_POPOVER_APP_UPDATE_AVAILABLE', +}; + +const mapSuiteUpdateStatusToCallToActionTranslation: Record = { + 'just-updated': 'TR_QUICK_ACTION_UPDATE_POPOVER_WHATS_NEW', + 'up-to-date': null, + 'update-available': 'TR_QUICK_ACTION_UPDATE_POPOVER_CLICK_TO_START_UPDATE', + 'update-downloaded-auto-restart-to-update': + 'TR_QUICK_ACTION_UPDATE_POPOVER_CLICK_TO_START_UPDATE', + 'update-downloaded-manual': 'TR_QUICK_ACTION_UPDATE_POPOVER_CLICK_TO_START_UPDATE', +}; + +export const UpdateNotificationBanner = ({ + updateStatusDevice, + updateStatusSuite, + onClose, +}: UpdateNotificationBannerProps) => { + const dispatch = useDispatch(); + + const translationHeader = + updateStatusSuite !== 'up-to-date' // Update suite first, because it will contain the newest firmware + ? mapSuiteUpdateStatusToHeaderTranslation[updateStatusSuite] + : mapDeviceUpdateStatusToTranslation[updateStatusDevice]; + + const translationCallToAction = + mapSuiteUpdateStatusToCallToActionTranslation[ + updateStatusSuite !== 'up-to-date' ? updateStatusSuite : updateStatusDevice + ]; + + if (translationHeader === null || translationCallToAction === null) { + return null; + } + + const handleOnClick = () => { + const onClick = + updateStatusSuite !== 'up-to-date' + ? mapSuiteUpdateToClick[updateStatusSuite] + : mapDeviceUpdateToClick[updateStatusDevice]; + + if (onClick !== null) { + onClick({ dispatch }); + onClose(); + } + }; + + const handleOnClose = (e: MouseEvent) => { + e.preventDefault(); + e.stopPropagation(); + onClose(); + }; + + return createPortal( + + + + + + + + + + + + + + + + + , + document.body, + ); +}; diff --git a/packages/suite/src/components/suite/layouts/SuiteLayout/Sidebar/QuickActions/Update/UpdateStatusActionBarIcon.tsx b/packages/suite/src/components/suite/layouts/SuiteLayout/Sidebar/QuickActions/Update/UpdateStatusActionBarIcon.tsx index 6059101dd33..d6cd723f402 100644 --- a/packages/suite/src/components/suite/layouts/SuiteLayout/Sidebar/QuickActions/Update/UpdateStatusActionBarIcon.tsx +++ b/packages/suite/src/components/suite/layouts/SuiteLayout/Sidebar/QuickActions/Update/UpdateStatusActionBarIcon.tsx @@ -7,6 +7,8 @@ import { borders, Color, CSSColor } from '@trezor/theme'; import { useUpdateStatus } from './useUpdateStatus'; import { UpdateTooltip } from './UpdateTooltip'; import { + mapDeviceUpdateToClick, + mapSuiteUpdateToClick, mapUpdateStatusToIcon, mapUpdateStatusToVariant, UpdateStatus, @@ -14,9 +16,9 @@ import { } from './updateQuickActionTypes'; import { isDesktop } from '@trezor/env-utils'; import { useDispatch } from 'react-redux'; -import { goto } from 'src/actions/suite/routerActions'; -import { SettingsAnchor } from '../../../../../../../constants/suite/anchors'; import { mapTrezorModelToIcon } from '@trezor/product-components'; +import { UpdateNotificationBanner } from './UpdateNotificationBanner'; +import { useState } from 'react'; type MapArgs = { $variant: UpdateVariant; @@ -141,6 +143,8 @@ const SuiteUpdateIcon = ({ iconSize, updateStatus, variant }: SuiteUpdateIconPro export const UpdateStatusActionBarIcon = () => { const theme = useTheme(); + const [closedNotificationDevice, setClosedNotificationDevice] = useState(false); + const [closedNotificationSuite, setClosedNotificationSuite] = useState(false); const { updateStatus, updateStatusDevice, updateStatusSuite } = useUpdateStatus(); const { device } = useDevice(); @@ -157,46 +161,74 @@ export const UpdateStatusActionBarIcon = () => { } const handleOnClick = () => { - if (updateStatusSuite === 'update-available') { - dispatch(goto('settings-index', { anchor: SettingsAnchor.VersionWithUpdate })); - } else if (updateStatusDevice === 'update-available') { - dispatch(goto('settings-device', { anchor: SettingsAnchor.FirmwareVersion })); + if (updateStatusSuite !== 'up-to-date') { + mapSuiteUpdateToClick[updateStatusSuite]?.({ dispatch }); + } else if (updateStatusDevice !== 'up-to-date') { + mapDeviceUpdateToClick[updateStatusDevice]?.({ dispatch }); + } + }; + + const showBannerNotification = + (updateStatusSuite !== 'up-to-date' && !closedNotificationSuite) || + (updateStatusDevice !== 'up-to-date' && !closedNotificationDevice); + + const onNotificationBannerClosed = () => { + console.log('onNotificationBannerClosed'); + console.log('updateStatusSuite', updateStatusSuite); + console.log('updateStatusDevice', updateStatusDevice); + + if (updateStatusSuite !== 'up-to-date') { + setClosedNotificationSuite(true); + } + if (updateStatusDevice !== 'up-to-date') { + setClosedNotificationDevice(true); } }; return ( - + {showBannerNotification && ( + - } - onClick={handleOnClick} - > - + ) + } + onClick={handleOnClick} > - - - {isDesktopSuite && ( - + + - )} - - - + {isDesktopSuite && ( + + )} + + + + ); }; diff --git a/packages/suite/src/components/suite/layouts/SuiteLayout/Sidebar/QuickActions/Update/UpdateTooltip.tsx b/packages/suite/src/components/suite/layouts/SuiteLayout/Sidebar/QuickActions/Update/UpdateTooltip.tsx index 98b281c9e1a..57d28fc414f 100644 --- a/packages/suite/src/components/suite/layouts/SuiteLayout/Sidebar/QuickActions/Update/UpdateTooltip.tsx +++ b/packages/suite/src/components/suite/layouts/SuiteLayout/Sidebar/QuickActions/Update/UpdateTooltip.tsx @@ -5,6 +5,8 @@ import { mapUpdateStatusToIcon, mapUpdateStatusToVariant, UpdateStatus, + UpdateStatusSuite, + UpdateStatusDevice, } from './updateQuickActionTypes'; import { Translation } from '../../../../../Translation'; import { spacings } from '@trezor/theme'; @@ -27,14 +29,15 @@ const SuiteIconRectangle = styled.div<{ $size: IconSize }>` `; const mapUpdateStatusToTranslation: Record = { + 'update-downloaded-manual': 'TR_QUICK_ACTION_TOOLTIP_UPDATE_AVAILABLE', + 'update-downloaded-auto-restart-to-update': 'TR_QUICK_ACTION_TOOLTIP_RESTART_TO_UPDATE', 'up-to-date': 'TR_QUICK_ACTION_TOOLTIP_UP_TO_DATE', 'update-available': 'TR_QUICK_ACTION_TOOLTIP_UPDATE_AVAILABLE', - 'restart-to-update': 'TR_QUICK_ACTION_TOOLTIP_RESTART_TO_UPDATE', 'just-updated': 'TR_QUICK_ACTION_TOOLTIP_JUST_UPDATED', }; type DeviceRowProps = { - updateStatus: UpdateStatus; + updateStatus: UpdateStatusDevice; }; const DeviceRow = ({ updateStatus }: DeviceRowProps) => { @@ -71,7 +74,7 @@ const DeviceRow = ({ updateStatus }: DeviceRowProps) => { }; type SuiteRowProps = { - updateStatus: UpdateStatus; + updateStatus: UpdateStatusSuite; }; const SuiteRow = ({ updateStatus }: SuiteRowProps) => { @@ -102,8 +105,8 @@ const SuiteRow = ({ updateStatus }: SuiteRowProps) => { }; type UpdateTooltipProps = { - updateStatusDevice: UpdateStatus; - updateStatusSuite: UpdateStatus; + updateStatusDevice: UpdateStatusDevice; + updateStatusSuite: UpdateStatusSuite; }; export const UpdateTooltip = ({ updateStatusDevice, updateStatusSuite }: UpdateTooltipProps) => { diff --git a/packages/suite/src/components/suite/layouts/SuiteLayout/Sidebar/QuickActions/Update/updateQuickActionTypes.ts b/packages/suite/src/components/suite/layouts/SuiteLayout/Sidebar/QuickActions/Update/updateQuickActionTypes.ts index 558d41c0b10..d861649595b 100644 --- a/packages/suite/src/components/suite/layouts/SuiteLayout/Sidebar/QuickActions/Update/updateQuickActionTypes.ts +++ b/packages/suite/src/components/suite/layouts/SuiteLayout/Sidebar/QuickActions/Update/updateQuickActionTypes.ts @@ -2,26 +2,60 @@ import { IconName } from '@trezor/components'; import { UIVariant } from '@trezor/components/src/config/types'; import { Color, CSSColor } from '@trezor/theme'; import { DefaultTheme } from 'styled-components'; +import { goto } from '../../../../../../../actions/suite/routerActions'; +import { + installUpdate, + setUpdateModalVisibility, +} from '../../../../../../../actions/suite/desktopUpdateActions'; +import { Dispatch } from '../../../../../../../types/suite'; export const updateVariants = ['tertiary', 'info', 'purple'] as const; export type UpdateVariant = Extract | 'purple'; -export type UpdateStatus = 'up-to-date' | 'update-available' | 'restart-to-update' | 'just-updated'; +export type UpdateStatusDevice = 'up-to-date' | 'update-available' | 'just-updated'; + +export type UpdateStatusSuite = + | 'up-to-date' + | 'update-available' + | 'update-downloaded-manual' + | 'update-downloaded-auto-restart-to-update' + | 'just-updated'; + +export type UpdateStatus = UpdateStatusDevice | UpdateStatusSuite; export const mapUpdateStatusToIcon: Record = { + 'update-downloaded-manual': 'arrowDown', + 'update-downloaded-auto-restart-to-update': 'arrowsClockwiseFilled', 'up-to-date': 'check', 'update-available': 'arrowDown', - 'restart-to-update': 'arrowsClockwiseFilled', 'just-updated': 'check', }; export const mapUpdateStatusToVariant: Record = { + 'update-downloaded-manual': 'info', + 'update-downloaded-auto-restart-to-update': 'info', 'up-to-date': 'tertiary', 'update-available': 'info', - 'restart-to-update': 'info', 'just-updated': 'purple', }; +type OnClickCallbackCallback = ((params: { dispatch: Dispatch }) => void) | null; + +export const mapDeviceUpdateToClick: Record = { + 'up-to-date': null, + 'just-updated': null, // Todo: show changelog + 'update-available': ({ dispatch }) => dispatch(goto('firmware-index')), +}; + +export const mapSuiteUpdateToClick: Record = { + 'up-to-date': null, + 'update-downloaded-auto-restart-to-update': ({ dispatch }) => + dispatch(installUpdate({ shouldInstallOnQuit: false })), + 'update-downloaded-manual': ({ dispatch }) => dispatch(setUpdateModalVisibility('maximized')), + 'just-updated': null, // Todo: show changelog + 'update-available': ({ dispatch }) => dispatch(setUpdateModalVisibility('maximized')), +}; + type MapArgs = { $variant: UpdateVariant; theme: DefaultTheme; diff --git a/packages/suite/src/components/suite/layouts/SuiteLayout/Sidebar/QuickActions/Update/useUpdateStatus.ts b/packages/suite/src/components/suite/layouts/SuiteLayout/Sidebar/QuickActions/Update/useUpdateStatus.ts index dfe89855fdb..d3b80305cd6 100644 --- a/packages/suite/src/components/suite/layouts/SuiteLayout/Sidebar/QuickActions/Update/useUpdateStatus.ts +++ b/packages/suite/src/components/suite/layouts/SuiteLayout/Sidebar/QuickActions/Update/useUpdateStatus.ts @@ -3,32 +3,43 @@ import { DesktopUpdateState, UpdateState, } from '../../../../../../../reducers/suite/desktopUpdateReducer'; -import { UpdateStatus } from './updateQuickActionTypes'; +import { UpdateStatus, UpdateStatusSuite, UpdateStatusDevice } from './updateQuickActionTypes'; type UpdateStatusData = { updateStatus: UpdateStatus; - updateStatusDevice: UpdateStatus; - updateStatusSuite: UpdateStatus; + updateStatusDevice: UpdateStatusDevice; + updateStatusSuite: UpdateStatusSuite; }; -const getSuiteUpdateStatus = ({ desktopUpdate }: { desktopUpdate: DesktopUpdateState }) => { - const isSuiteJustUpdated = desktopUpdate.firstRunAfterUpdate; - - const isSuiteOutdated = [UpdateState.Available, UpdateState.Downloading].includes( - desktopUpdate.state, - ); +type GetSuiteUpdateStatusArgs = { + desktopUpdate: DesktopUpdateState; +}; - const isSuiteRestartRequired = desktopUpdate.state === UpdateState.Ready; +const getSuiteUpdateStatus = ({ desktopUpdate }: GetSuiteUpdateStatusArgs): UpdateStatusSuite => { + const isSuiteJustUpdated = desktopUpdate.firstRunAfterUpdate; + if (isSuiteJustUpdated) { + return 'just-updated'; + } - if (isSuiteRestartRequired) { - return 'restart-to-update'; + // We don't show update-availability in case of auto-updates until the update is downloaded + if (desktopUpdate.isAutomaticUpdateEnabled && desktopUpdate.state === UpdateState.Ready) { + return 'update-downloaded-auto-restart-to-update'; } - if (isSuiteOutdated) { - return 'update-available'; + if (!desktopUpdate.isAutomaticUpdateEnabled) { + const isUpdateAvailable = [UpdateState.Available, UpdateState.Downloading].includes( + desktopUpdate.state, + ); + if (isUpdateAvailable) { + return 'update-available'; + } + + if (desktopUpdate.state === UpdateState.Ready) { + return 'update-downloaded-manual'; + } } - return isSuiteJustUpdated ? 'just-updated' : 'up-to-date'; + return 'up-to-date'; }; export const useUpdateStatus = (): UpdateStatusData => { @@ -42,8 +53,11 @@ export const useUpdateStatus = (): UpdateStatusData => { updateStatusSuite: getSuiteUpdateStatus({ desktopUpdate }), }; - if (common.updateStatusSuite === 'restart-to-update') { - return { updateStatus: 'restart-to-update', ...common }; + if ( + common.updateStatusSuite === 'update-downloaded-auto-restart-to-update' || + common.updateStatusSuite === 'update-downloaded-manual' + ) { + return { updateStatus: common.updateStatusSuite, ...common }; } if ( diff --git a/packages/suite/src/reducers/suite/desktopUpdateReducer.ts b/packages/suite/src/reducers/suite/desktopUpdateReducer.ts index 44cf708a06c..da29acca6fc 100644 --- a/packages/suite/src/reducers/suite/desktopUpdateReducer.ts +++ b/packages/suite/src/reducers/suite/desktopUpdateReducer.ts @@ -58,9 +58,9 @@ const desktopUpdateReducer = ( case DESKTOP_UPDATE.AVAILABLE: draft.state = UpdateState.Available; draft.latest = action.payload; - draft.modalVisibility = draft.isAutomaticUpdateEnabled - ? draft.modalVisibility - : 'maximized'; + // draft.modalVisibility = draft.isAutomaticUpdateEnabled + // ? draft.modalVisibility + // : 'maximized'; break; case DESKTOP_UPDATE.NOT_AVAILABLE: draft.state = UpdateState.NotAvailable; diff --git a/packages/suite/src/support/messages.ts b/packages/suite/src/support/messages.ts index 0b490e7f1ca..e5675e2ef7d 100644 --- a/packages/suite/src/support/messages.ts +++ b/packages/suite/src/support/messages.ts @@ -4005,6 +4005,42 @@ export default defineMessages({ id: 'TR_QUICK_ACTION_TOOLTIP_JUST_UPDATED', defaultMessage: 'Just updated ({currentVersion})', }, + + TR_QUICK_ACTION_UPDATE_POPOVER_APP_UPDATE_AVAILABLE: { + id: 'TR_QUICK_ACTION_UPDATE_POPOVER_APP_UPDATE_AVAILABLE', + defaultMessage: 'App update available', + }, + TR_QUICK_ACTION_UPDATE_POPOVER_APP_HAS_BEEN_UPDATED: { + id: 'TR_QUICK_ACTION_UPDATE_POPOVER_APP_HAS_BEEN_UPDATED', + defaultMessage: 'App’s been updated!', + }, + TR_QUICK_ACTION_UPDATE_POPOVER_APP_DOWNLOADED: { + id: 'TR_QUICK_ACTION_UPDATE_POPOVER_APP_DOWNLOADED', + defaultMessage: 'Suite downloaded a new Trezor update!', + }, + + TR_QUICK_ACTION_UPDATE_POPOVER_TREZOR_UPDATE_AVAILABLE: { + id: 'TR_QUICK_ACTION_UPDATE_POPOVER_TREZOR_UPDATE_AVAILABLE', + defaultMessage: 'Trezor update available', + }, + TR_QUICK_ACTION_UPDATE_POPOVER_TREZOR_HAS_BEEN_UPDATED: { + id: 'TR_QUICK_ACTION_UPDATE_POPOVER_TREZOR_HAS_BEEN_UPDATED', + defaultMessage: 'Trezor’s been updated!', + }, + + TR_QUICK_ACTION_UPDATE_POPOVER_CLICK_TO_START_UPDATE: { + id: 'TR_QUICK_ACTION_UPDATE_POPOVER_CLICK_TO_START_UPDATE', + defaultMessage: 'Click to start update', + }, + TR_QUICK_ACTION_UPDATE_POPOVER_CLICK_TO_RESTART_AND_UPDATE: { + id: 'TR_QUICK_ACTION_UPDATE_POPOVER_CLICK_TO_RESTART_AND_UPDATE', + defaultMessage: 'Click to restart & update', + }, + TR_QUICK_ACTION_UPDATE_POPOVER_WHATS_NEW: { + id: 'TR_QUICK_ACTION_UPDATE_POPOVER_WHATS_NEW', + defaultMessage: 'What’s new?', + }, + TR_QUICK_ACTION_DEBUG_EAP_EXPERIMENTAL_ENABLED: { id: 'TR_QUICK_ACTION_DEBUG_EAP_EXPERIMENTAL_ENABLED', defaultMessage: 'Enabled', From 72f98dbf4fadd821d817702f2067443fd430a78d Mon Sep 17 00:00:00 2001 From: Peter Sanderson Date: Thu, 26 Sep 2024 13:43:31 +0200 Subject: [PATCH 2/2] feat: rework Update:Available modal chore: remove wtf legacy colors object, reference legacy colors directly chore: remove wtf legacy colors object, reference legacy colors directly --- .../components/src/components/Image/images.ts | 2 - .../src/components/NewModal/NewModal.tsx | 8 +- packages/components/src/config/colors.ts | 19 +- .../components/src/support/ThemeProvider.tsx | 0 .../files/images/svg/early-access-disable.svg | 10 - .../files/images/svg/early-access.svg | 8 - packages/suite-desktop-ui/package.json | 3 +- .../src/support/DesktopUpdater.tsx | 20 +- .../src/support/DesktopUpdater/Available.tsx | 192 ++++++++++++------ .../support/DesktopUpdater/Downloading.tsx | 75 +++---- .../DesktopUpdater/EarlyAccessDisable.tsx | 45 ++-- .../DesktopUpdater/EarlyAccessEnable.tsx | 61 +++--- .../src/support/DesktopUpdater/Ready.tsx | 43 ++-- .../src/support/DesktopUpdater/styles.ts | 52 ----- .../src/support/DesktopUpdater/styles.tsx | 12 ++ packages/suite-desktop-ui/styled.d.ts | 8 + packages/suite/src/support/messages.ts | 27 ++- yarn.lock | 1 + 18 files changed, 291 insertions(+), 295 deletions(-) create mode 100644 packages/components/src/support/ThemeProvider.tsx delete mode 100644 packages/suite-data/files/images/svg/early-access-disable.svg delete mode 100644 packages/suite-data/files/images/svg/early-access.svg delete mode 100644 packages/suite-desktop-ui/src/support/DesktopUpdater/styles.ts create mode 100644 packages/suite-desktop-ui/src/support/DesktopUpdater/styles.tsx create mode 100644 packages/suite-desktop-ui/styled.d.ts diff --git a/packages/components/src/components/Image/images.ts b/packages/components/src/components/Image/images.ts index c8450adc9ee..9c9507f04d6 100644 --- a/packages/components/src/components/Image/images.ts +++ b/packages/components/src/components/Image/images.ts @@ -18,8 +18,6 @@ export const SVG_IMAGES = { DEVICE_ANOTHER_SESSION: 'device-another-session.svg', CONNECT_DEVICE: 'connect-device.svg', ERROR_404: 'error-404.svg', - EARLY_ACCESS: 'early-access.svg', - EARLY_ACCESS_DISABLE: 'early-access-disable.svg', INVITY_LOGO: 'invity-logo.svg', COINMARKET_AVATAR: 'coinmarket-avatar.svg', COINMARKET_SUCCESS: 'coinmarket-success.svg', diff --git a/packages/components/src/components/NewModal/NewModal.tsx b/packages/components/src/components/NewModal/NewModal.tsx index e0f062bc592..4172333fa87 100644 --- a/packages/components/src/components/NewModal/NewModal.tsx +++ b/packages/components/src/components/NewModal/NewModal.tsx @@ -6,6 +6,8 @@ import { Elevation, mapElevationToBackground, mapElevationToBackgroundToken, + nextElevation, + prevElevation, spacingsPx, } from '@trezor/theme'; @@ -147,7 +149,9 @@ const NewModalBase = ({ const frameProps = pickAndPrepareFrameProps(rest, allowedNewModalFrameProps); const { scrollElementRef, onScroll, ShadowContainer, ShadowTop, ShadowBottom } = useScrollShadow(); - const modalBackgroundColor = mapElevationToBackgroundToken({ $elevation: MODAL_ELEVATION }); + const modalBackgroundColor = mapElevationToBackgroundToken({ + $elevation: nextElevation[MODAL_ELEVATION], + }); const hasHeader = onBackClick || onCancel || heading || description; useEvent('keydown', (e: KeyboardEvent) => { @@ -157,7 +161,7 @@ const NewModalBase = ({ }); return ( - + ; type PropsOnlyInDarkTheme = Omit; -// all common theme props and their values are nicely listed, props that are specific to given theme are marked optional +/** + * IMPORTANT: + * + * You have to do this in the every package where you are accessing these theme props + * 1) create `styled.d.ts` file in the root of the project with overwrite of DefaultTheme + * 2) add `typescript-styled-plugin` into the packages devDependencies + * + * See `suite` package for reference. + */ + +// All common theme props and their values are nicely listed, +// props that are specific to given theme are marked optional. export type SuiteThemeColors = CommonThemeProps & Partial & Partial; diff --git a/packages/components/src/support/ThemeProvider.tsx b/packages/components/src/support/ThemeProvider.tsx new file mode 100644 index 00000000000..e69de29bb2d diff --git a/packages/suite-data/files/images/svg/early-access-disable.svg b/packages/suite-data/files/images/svg/early-access-disable.svg deleted file mode 100644 index 301d81441ab..00000000000 --- a/packages/suite-data/files/images/svg/early-access-disable.svg +++ /dev/null @@ -1,10 +0,0 @@ - - - - - - - - - - diff --git a/packages/suite-data/files/images/svg/early-access.svg b/packages/suite-data/files/images/svg/early-access.svg deleted file mode 100644 index 4930936c1f9..00000000000 --- a/packages/suite-data/files/images/svg/early-access.svg +++ /dev/null @@ -1,8 +0,0 @@ - - - - - - - - diff --git a/packages/suite-desktop-ui/package.json b/packages/suite-desktop-ui/package.json index 4314ebe24a7..46c1e64c40c 100644 --- a/packages/suite-desktop-ui/package.json +++ b/packages/suite-desktop-ui/package.json @@ -36,6 +36,7 @@ "@types/react": "18.2.79", "@types/react-dom": "18.2.19", "stylelint": "^16.2.1", - "stylelint-config-standard": "^36.0.0" + "stylelint-config-standard": "^36.0.0", + "typescript-styled-plugin": "^0.18.3" } } diff --git a/packages/suite-desktop-ui/src/support/DesktopUpdater.tsx b/packages/suite-desktop-ui/src/support/DesktopUpdater.tsx index 29e97868ea1..ddae3a7f45b 100644 --- a/packages/suite-desktop-ui/src/support/DesktopUpdater.tsx +++ b/packages/suite-desktop-ui/src/support/DesktopUpdater.tsx @@ -18,7 +18,6 @@ import { import { UpdateState } from 'src/reducers/suite/desktopUpdateReducer'; import { ModalContextProvider } from 'src/support/suite/ModalContext'; import { getAppUpdatePayload } from 'src/utils/suite/analytics'; -import { selectRouteName } from 'src/reducers/suite/routerReducer'; import { Available } from './DesktopUpdater/Available'; import { Downloading } from './DesktopUpdater/Downloading'; @@ -33,11 +32,8 @@ interface DesktopUpdaterProps { export const DesktopUpdater = ({ children }: DesktopUpdaterProps) => { const dispatch = useDispatch(); const { desktopUpdate } = useSelector(state => state); - const routeName = useSelector(selectRouteName); - // Closing a modal opened by auto updater outside of device settings might confuse some users, - // especially on app start if closing it unexpectedly by clicking outside. - const isSettingsRoute = routeName === 'settings-index'; + const desktopUpdateState = desktopUpdate.state; useEffect(() => { desktopApi.on('update/allow-prerelease', params => dispatch(allowPrerelease(params))); @@ -90,14 +86,14 @@ export const DesktopUpdater = ({ children }: DesktopUpdaterProps) => { } // Non visible states - if ([UpdateState.Checking, UpdateState.NotAvailable].includes(desktopUpdate.state)) { + if ([UpdateState.Checking, UpdateState.NotAvailable].includes(desktopUpdateState)) { return false; } const isEarlyAccessState = [ UpdateState.EarlyAccessDisable, UpdateState.EarlyAccessEnable, - ].includes(desktopUpdate.state); + ].includes(desktopUpdateState); // Enable to setup Early Access even after updater error (when desktopUpdate.latest is undefined). if (!isEarlyAccessState && !desktopUpdate.latest) { @@ -105,10 +101,10 @@ export const DesktopUpdater = ({ children }: DesktopUpdaterProps) => { } return true; - }, [desktopUpdate.modalVisibility, desktopUpdate.state, desktopUpdate.latest]); + }, [desktopUpdate.modalVisibility, desktopUpdateState, desktopUpdate.latest]); const getUpdateModal = () => { - switch (desktopUpdate.state) { + switch (desktopUpdateState) { case UpdateState.EarlyAccessEnable: return ; case UpdateState.EarlyAccessDisable: @@ -116,15 +112,15 @@ export const DesktopUpdater = ({ children }: DesktopUpdaterProps) => { case UpdateState.Available: return ( ); case UpdateState.Downloading: return ; case UpdateState.Ready: - return ; + return ; default: return null; } diff --git a/packages/suite-desktop-ui/src/support/DesktopUpdater/Available.tsx b/packages/suite-desktop-ui/src/support/DesktopUpdater/Available.tsx index f720c81dc87..29f55686a0c 100644 --- a/packages/suite-desktop-ui/src/support/DesktopUpdater/Available.tsx +++ b/packages/suite-desktop-ui/src/support/DesktopUpdater/Available.tsx @@ -1,72 +1,96 @@ +import { ReactNode } from 'react'; + import styled from 'styled-components'; -import { Button, H2, Link, Markdown } from '@trezor/components'; +import { + Card, + Checkbox, + Column, + ElevationUp, + Icon, + Link, + Markdown, + NewModal, + Paragraph, + Row, + Text, + useElevation, +} from '@trezor/components'; import { desktopApi, UpdateInfo } from '@trezor/suite-desktop-api'; -import { borders } from '@trezor/theme'; +import { borders, Elevation, mapElevationToBackground, spacings, spacingsPx } from '@trezor/theme'; -import { Translation, Modal } from 'src/components/suite'; +import { Translation } from 'src/components/suite'; import { useDispatch } from 'src/hooks/suite'; import { getReleaseUrl } from 'src/services/github'; import { download } from 'src/actions/suite/desktopUpdateActions'; -// eslint-disable-next-line local-rules/no-override-ds-component -const GreenH2 = styled(H2)` - text-align: left; - color: ${({ theme }) => theme.legacy.TYPE_GREEN}; -`; - -const ChangelogWrapper = styled.div` - margin: 20px 0; - background: ${({ theme }) => theme.legacy.BG_GREY}; - border-radius: ${borders.radii.xs}; +const ChangelogWrapper = styled.div<{ $elevation: Elevation }>` + background-color: ${({ theme, $elevation }) => mapElevationToBackground({ theme, $elevation })}; + border-radius: ${borders.radii.md}; max-height: 400px; overflow-y: auto; - padding: 16px 20px; + padding: ${spacingsPx.md} ${spacingsPx.xl}; `; -// eslint-disable-next-line local-rules/no-override-ds-component -const StyledLink = styled(Link)` - align-self: start; +const GrayTag = styled.div` + border-radius: ${borders.radii.full}; + background-color: ${({ theme }) => theme.backgroundNeutralSubtleOnElevation0}; + padding: ${spacingsPx.xxxs} ${spacingsPx.xs}; + color: ${({ theme }) => theme.textSubdued}; `; -const StyledModal = styled(Modal)` - ${Modal.BottomBar} { - > * { - flex: 1; - } - } +const GreenTag = styled.div` + display: flex; + align-items: center; + gap: ${spacingsPx.xxs}; + border-radius: ${borders.radii.full}; + background-color: ${({ theme }) => theme.backgroundPrimarySubtleOnElevation0}; + padding: ${spacingsPx.xxxs} ${spacingsPx.xs}; `; +const NewTag = () => ( + + + + + + +); + +const Changelog = ({ children }: { children: ReactNode }) => { + const { elevation } = useElevation(); + + return {children}; +}; + interface VersionNameProps { latestVersion?: string; prerelease: boolean; } const getVersionName = ({ latestVersion, prerelease }: VersionNameProps): string => { - if (!latestVersion) { - // fallback for undefined version + if (latestVersion === undefined) { return ''; } - if (!prerelease) { - // regular case + + if (prerelease !== undefined) { return latestVersion; } + if (!latestVersion.includes('-')) { - // add beta label for pre-releases, but prevent versions like '21.10.1-alpha-beta' return `${latestVersion}-beta`; } - // fallback for pre-release versions already including some pre-release components return latestVersion; }; interface AvailableProps { - hideWindow: () => void; - isCancelable: boolean; - latest?: UpdateInfo; + onCancel: () => void; + latest: UpdateInfo | undefined; + isAutomaticUpdateEnabled: boolean; } -export const Available = ({ hideWindow, isCancelable, latest }: AvailableProps) => { +export const Available = ({ onCancel, latest, isAutomaticUpdateEnabled }: AvailableProps) => { const dispatch = useDispatch(); const downloadUpdate = () => { @@ -74,46 +98,80 @@ export const Available = ({ hideWindow, isCancelable, latest }: AvailableProps) desktopApi.downloadUpdate(); }; + const suiteCurrentVersion = process.env.VERSION || ''; + const suiteNewVersion = getVersionName({ + latestVersion: latest?.version, + prerelease: !!latest?.prerelease, + }); + + const handleToggleAutoUpdateClick = () => + desktopApi.setAutomaticUpdateEnabled(!isAutomaticUpdateEnabled); + return ( - } - isCancelable={isCancelable} - onCancel={hideWindow} - bottomBarComponents={ + description={ + + } + onCancel={onCancel} + bottomContent={ <> - - + + + + } > - - - - - - {latest?.changelog ? ( - {latest?.changelog} - ) : ( - - )} - - - - - + +
+ + + + + + +
+ + + + {latest?.changelog ? ( + {latest?.changelog} + ) : ( + + )} + + + + + + + + + + + {latest?.releaseDate && {latest?.releaseDate}} + + + + + + + + + + + + +
+ ); }; diff --git a/packages/suite-desktop-ui/src/support/DesktopUpdater/Downloading.tsx b/packages/suite-desktop-ui/src/support/DesktopUpdater/Downloading.tsx index f7e1fb5d3f6..94c8b096592 100644 --- a/packages/suite-desktop-ui/src/support/DesktopUpdater/Downloading.tsx +++ b/packages/suite-desktop-ui/src/support/DesktopUpdater/Downloading.tsx @@ -4,15 +4,10 @@ import styled from 'styled-components'; import { UpdateProgress } from '@trezor/suite-desktop-api'; import { bytesToHumanReadable } from '@trezor/utils'; -import { Button, H2, ProgressBar, variables } from '@trezor/components'; +import { H2, NewModal, ProgressBar, variables, Row, Column } from '@trezor/components'; +import { spacings } from '@trezor/theme'; -import { Translation, Modal } from 'src/components/suite'; - -import { Row } from './styles'; - -const DownloadWrapper = styled(Row)` - margin-top: 16px; -`; +import { Translation } from 'src/components/suite'; const DownloadProgress = styled.span` font-size: 20px; @@ -34,11 +29,6 @@ const Text = styled(H2)` font-weight: ${variables.FONT_WEIGHT.MEDIUM}; `; -// eslint-disable-next-line local-rules/no-override-ds-component -const StyledProgressBar = styled(ProgressBar)` - margin-top: 16px; -`; - interface DownloadingProps { hideWindow: () => void; progress?: UpdateProgress; @@ -56,42 +46,31 @@ export const Downloading = ({ hideWindow, progress }: DownloadingProps) => { }, [step]); return ( - - - - } - onCancel={hideWindow} - > - - {progress?.verifying ? ( - - - {ellipsisArray.filter((_, k) => k < step)} - - ) : ( - <> + + + + {progress?.verifying ? ( - + + {ellipsisArray.filter((_, k) => k < step)} - - - {bytesToHumanReadable(progress?.transferred || 0)} - - /{bytesToHumanReadable(progress?.total || 0)} - - - )} - - - - + ) : ( + <> + + + + + + {bytesToHumanReadable(progress?.transferred || 0)} + + /{bytesToHumanReadable(progress?.total || 0)} + + + )} + + + +
+ ); }; diff --git a/packages/suite-desktop-ui/src/support/DesktopUpdater/EarlyAccessDisable.tsx b/packages/suite-desktop-ui/src/support/DesktopUpdater/EarlyAccessDisable.tsx index 5ff6e333001..34a04de4652 100644 --- a/packages/suite-desktop-ui/src/support/DesktopUpdater/EarlyAccessDisable.tsx +++ b/packages/suite-desktop-ui/src/support/DesktopUpdater/EarlyAccessDisable.tsx @@ -5,25 +5,17 @@ import styled from 'styled-components'; import { SUITE_URL } from '@trezor/urls'; import { analytics, EventType } from '@trezor/suite-analytics'; import { desktopApi } from '@trezor/suite-desktop-api'; -import { Button, Image } from '@trezor/components'; +import { Button, Image, NewModal, Paragraph } from '@trezor/components'; +import { borders, Elevation } from '@trezor/theme'; + +import { Translation, TrezorLink } from 'src/components/suite'; -import { Translation, Modal, TrezorLink } from 'src/components/suite'; -import { DialogModal } from 'src/components/suite/modals/Modal/DialogRenderer'; -import { ImageWrapper, Description, Title } from './styles'; export const Link = styled(TrezorLink)` width: 100%; `; -const StyledModal = styled(Modal)` - ${Modal.BottomBar} { - > * { - flex: 1; - } - } -`; - // eslint-disable-next-line local-rules/no-override-ds-component const LinkButton = styled(Button)` width: 100%; @@ -48,8 +40,8 @@ export const EarlyAccessDisable = ({ hideWindow }: EarlyAccessDisableProps) => { }, []); return enabled ? ( - } - /> + > + + ); }; diff --git a/packages/suite-desktop-ui/src/support/DesktopUpdater/EarlyAccessEnable.tsx b/packages/suite-desktop-ui/src/support/DesktopUpdater/EarlyAccessEnable.tsx index 84afcef66ee..2d14732b235 100644 --- a/packages/suite-desktop-ui/src/support/DesktopUpdater/EarlyAccessEnable.tsx +++ b/packages/suite-desktop-ui/src/support/DesktopUpdater/EarlyAccessEnable.tsx @@ -4,12 +4,11 @@ import styled from 'styled-components'; import { analytics, EventType } from '@trezor/suite-analytics'; import { desktopApi } from '@trezor/suite-desktop-api'; -import { Button, Paragraph, Tooltip, Image } from '@trezor/components'; +import { Button, Paragraph, Tooltip, NewModal, Card, ElevationUp, Icon } from '@trezor/components'; -import { CheckItem, Translation, Modal } from 'src/components/suite'; -import { DialogModal } from 'src/components/suite/modals/Modal/DialogRenderer'; +import { CheckItem, Translation } from 'src/components/suite'; -import { Description, Divider } from './styles'; +import { CircleIconBackground } from './styles'; const DescriptionWrapper = styled.div` display: flex; @@ -51,11 +50,10 @@ export const EarlyAccessEnable = ({ hideWindow }: EarlyAccessEnableProps) => { const checkForUpdates = useCallback(() => desktopApi.checkForUpdates(true), []); return enabled ? ( - } - body={} - bottomBarComponents={ + heading={} + bottomContent={ <> } - /> + > + + ) : ( - } - isCancelable onCancel={hideWindow} - bottomBarComponents={ + bottomContent={ { } > - + + + - + - + - - - - - } - description="" - isChecked={understood} - onClick={() => setUnderstood(!understood)} - /> - + + + + + + + } + description="" + isChecked={understood} + onClick={() => setUnderstood(!understood)} + /> + + + ); }; diff --git a/packages/suite-desktop-ui/src/support/DesktopUpdater/Ready.tsx b/packages/suite-desktop-ui/src/support/DesktopUpdater/Ready.tsx index 071a4fea8f4..fc90908c5df 100644 --- a/packages/suite-desktop-ui/src/support/DesktopUpdater/Ready.tsx +++ b/packages/suite-desktop-ui/src/support/DesktopUpdater/Ready.tsx @@ -1,31 +1,15 @@ -import styled from 'styled-components'; +import { Button, NewModal, Paragraph, Row } from '@trezor/components'; +import { spacings } from '@trezor/theme'; -import { Button, H2, variables } from '@trezor/components'; - -import { Translation, Modal } from 'src/components/suite'; +import { Translation } from 'src/components/suite'; import { useDispatch } from 'src/hooks/suite'; import { installUpdate } from 'src/actions/suite/desktopUpdateActions'; -const Description = styled.span` - font-size: ${variables.FONT_SIZE.SMALL}; - font-weight: ${variables.FONT_WEIGHT.MEDIUM}; - color: ${({ theme }) => theme.legacy.TYPE_LIGHT_GREY}; -`; - -const StyledModal = styled(Modal)` - ${Modal.BottomBar} { - > * { - flex: 1; - } - } -`; - interface ReadyProps { hideWindow: () => void; - isCancelable: boolean; } -export const Ready = ({ hideWindow, isCancelable }: ReadyProps) => { +export const Ready = ({ hideWindow }: ReadyProps) => { const dispatch = useDispatch(); const install = () => dispatch(installUpdate({ shouldInstallOnQuit: false })); @@ -35,27 +19,26 @@ export const Ready = ({ hideWindow, isCancelable }: ReadyProps) => { }; return ( - } - isCancelable={isCancelable} onCancel={installOnQuit} - bottomBarComponents={ - <> + bottomContent={ + - + } > -

+ -

- + + - -
+ + ); }; diff --git a/packages/suite-desktop-ui/src/support/DesktopUpdater/styles.ts b/packages/suite-desktop-ui/src/support/DesktopUpdater/styles.ts deleted file mode 100644 index 77dfb237be0..00000000000 --- a/packages/suite-desktop-ui/src/support/DesktopUpdater/styles.ts +++ /dev/null @@ -1,52 +0,0 @@ -import styled from 'styled-components'; - -import { H2, Paragraph, variables } from '@trezor/components'; - -export const Row = styled.div` - display: flex; - justify-content: space-between; - align-items: center; -`; - -export const LeftCol = styled.div` - display: flex; - flex: 1 1 calc(100% - 40px); -`; - -export const RightCol = styled.div` - display: flex; - margin-left: 40px; - max-width: 280px; - flex: 1 1 100%; -`; - -export const Divider = styled.div` - width: 100%; - height: 1px; - margin: 30px 0; - background: ${({ theme }) => theme.legacy.STROKE_GREY}; -`; - -export const ImageWrapper = styled.div` - top: 50px; - left: 0; - right: 0; -`; - -export const ButtonWrapper = styled.div` - display: flex; - justify-content: center; - padding-top: 24px; -`; - -// eslint-disable-next-line local-rules/no-override-ds-component -export const Title = styled(H2)` - padding-top: 24px; - padding-bottom: 12px; -`; - -// eslint-disable-next-line local-rules/no-override-ds-component -export const Description = styled(Paragraph)` - font-size: ${variables.FONT_SIZE.SMALL}; - color: ${({ theme }) => theme.legacy.TYPE_LIGHT_GREY}; -`; diff --git a/packages/suite-desktop-ui/src/support/DesktopUpdater/styles.tsx b/packages/suite-desktop-ui/src/support/DesktopUpdater/styles.tsx new file mode 100644 index 00000000000..f365f8cafbc --- /dev/null +++ b/packages/suite-desktop-ui/src/support/DesktopUpdater/styles.tsx @@ -0,0 +1,12 @@ +import { borders, Elevation } from '@trezor/theme'; + +export const CircleIconBackground = styled.div<{ $elevation: Elevation }>` + width: 36px; + height: 36px; + + display: flex; + justify-content: center; + align-items: center; + background-color: ${({ theme }) => theme.backgroundSurfaceElevation2}; + border-radius: ${borders.radii.full}; +`; diff --git a/packages/suite-desktop-ui/styled.d.ts b/packages/suite-desktop-ui/styled.d.ts new file mode 100644 index 00000000000..743c8b46f0a --- /dev/null +++ b/packages/suite-desktop-ui/styled.d.ts @@ -0,0 +1,8 @@ +// import original module declarations +import 'styled-components'; +import { SuiteThemeColors } from '@trezor/components'; +import { BoxShadows, Colors } from '@trezor/theme'; + +declare module 'styled-components' { + export interface DefaultTheme extends SuiteThemeColors, Colors, BoxShadows {} +} diff --git a/packages/suite/src/support/messages.ts b/packages/suite/src/support/messages.ts index e5675e2ef7d..f4150756bff 100644 --- a/packages/suite/src/support/messages.ts +++ b/packages/suite/src/support/messages.ts @@ -6326,6 +6326,18 @@ export default defineMessages({ id: 'TR_UPDATE_MODAL_AVAILABLE_HEADING', defaultMessage: 'Update available', }, + TR_UPDATE_MODAL_YOUR_VERSION: { + id: 'TR_UPDATE_MODAL_YOUR_VERSION', + defaultMessage: 'Your version: v{version}', + }, + TR_UPDATE_MODAL_ENABLE_AUTO_UPDATES: { + id: 'TR_UPDATE_MODAL_ENABLE_AUTO_UPDATES', + defaultMessage: 'Enable automatic updates', + }, + TR_UPDATE_MODAL_ENABLE_AUTO_UPDATES_NEW_TAG: { + id: 'TR_UPDATE_MODAL_ENABLE_AUTO_UPDATES_NEW_TAG', + defaultMessage: 'New', + }, TR_UPDATE_MODAL_NOT_NOW: { id: 'TR_UPDATE_MODAL_NOT_NOW', defaultMessage: 'Not now', @@ -6354,13 +6366,18 @@ export default defineMessages({ id: 'TR_MANAGE', defaultMessage: 'manage', }, - TR_VERSION_HAS_BEEN_RELEASED: { + TR_VERSION_HAS_RELEASED: { id: 'TR_VERSION_HAS_BEEN_RELEASED', - defaultMessage: 'Version {version} has been released!', + defaultMessage: 'v {version} has released!', + }, + TR_READ_ALL_ON_GITHUB: { + id: 'TR_READ_ALL_ON_GITHUB', + defaultMessage: 'Read all on Github', }, - TR_CHANGELOG_ON_GITHUB: { - id: 'TR_CHANGELOG_ON_GITHUB', - defaultMessage: 'Changelog on GitHub', + TR_WERE_CONSTANTLY_WORKING_TO_IMPROVE: { + id: 'TR_WERE_CONSTANTLY_WORKING_TO_IMPROVE', + defaultMessage: + 'We’re constantly working to improve your Trezor experience, here’s what has changed:', }, TR_UPDATE_MODAL_UPDATE_DOWNLOADED: { id: 'TR_UPDATE_MODAL_UPDATE_DOWNLOADED', diff --git a/yarn.lock b/yarn.lock index 34ce9e19a3c..c1117da9c81 100644 --- a/yarn.lock +++ b/yarn.lock @@ -11889,6 +11889,7 @@ __metadata: styled-components: "npm:^6.1.8" stylelint: "npm:^16.2.1" stylelint-config-standard: "npm:^36.0.0" + typescript-styled-plugin: "npm:^0.18.3" languageName: unknown linkType: soft