Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 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
3 changes: 2 additions & 1 deletion src/i18n/en.i18n.json
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,7 @@
"currentVersion": "Current version",
"newVersion": "New version",
"install": "Install update",
"openAppStore": "Open App Store",
"skip": "Skip this version"
},
"updateInstallLater": {
Expand Down Expand Up @@ -802,4 +803,4 @@
}
}
}
}
}
2 changes: 2 additions & 0 deletions src/store/rootReducer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ import {
updateDownloadStatus,
updateError,
updateChannel,
updateStore,
} from '../updates/reducers';

export const rootReducer = combineReducers({
Expand Down Expand Up @@ -134,6 +135,7 @@ export const rootReducer = combineReducers({
isDetailedEventsLoggingEnabled,
isVerboseOutlookLoggingEnabled,
updateChannel,
updateStore,
screenCaptureFallbackForced,
isVideoCallDevtoolsAutoOpenEnabled,
isTransparentWindowEnabled,
Expand Down
9 changes: 7 additions & 2 deletions src/ui/components/AboutDialog/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,7 @@ export const AboutDialog = () => {
const newUpdateVersion = useSelector(
({ newUpdateVersion }: RootState) => newUpdateVersion
);
const updateStore = useSelector(({ updateStore }: RootState) => updateStore);
const openDialog = useSelector(({ openDialog }: RootState) => openDialog);
const updateError = useSelector(({ updateError }: RootState) => updateError);
const updateChannel = useSelector(
Expand All @@ -113,7 +114,11 @@ export const AboutDialog = () => {
);

const isVisible = openDialog === 'about';
const canUpdate = isUpdatingAllowed && isUpdatingEnabled;
const isMasUpdate = updateStore === 'mas';
// MAS builds cannot use electron-updater (isUpdatingAllowed is false there
// on purpose), but they still get a user-initiated check via the App Store
// lookup, so the button must not be hidden for them.
const canUpdate = (isUpdatingAllowed && isUpdatingEnabled) || isMasUpdate;
const isCheckForUpdatesOnStartupChecked =
isUpdatingAllowed && isUpdatingEnabled && doCheckForUpdatesOnStartup;
const canSetCheckForUpdatesOnStartup =
Expand Down Expand Up @@ -247,7 +252,7 @@ export const AboutDialog = () => {

{canUpdate && (
<Box display='flex' flexDirection='column'>
{isDeveloperModeEnabled && (
{isDeveloperModeEnabled && !isMasUpdate && (
<Box mbe='x16'>
<Field>
<FieldRow>
Expand Down
17 changes: 17 additions & 0 deletions src/ui/components/TopBar/UpdateLabel.spec.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import {
UPDATES_CHECK_FEEDBACK_DISMISSED,
UPDATES_DOWNLOAD_REQUESTED,
UPDATES_INSTALL_REQUESTED,
UPDATES_OPEN_APP_STORE_REQUESTED,
UPDATES_PANEL_TOGGLED,
UPDATES_SKIP_REQUESTED,
} from '../../../updates/actions';
Expand Down Expand Up @@ -123,6 +124,22 @@ describe('UpdateLabel', () => {
});
});

it('opens the App Store instead of downloading on a MAS build', async () => {
const user = userEvent.setup();
renderWithStore(<UpdateLabel />, {
preloadedState: openState({ updateStore: 'mas' }),
});

await user.click(screen.getByText('dialog.update.openAppStore'));

expect(mockDispatch).toHaveBeenCalledWith({
type: UPDATES_OPEN_APP_STORE_REQUESTED,
});
expect(mockDispatch).not.toHaveBeenCalledWith({
type: UPDATES_DOWNLOAD_REQUESTED,
});
});

it('skips the version from the panel skip action', async () => {
const user = userEvent.setup();
renderWithStore(<UpdateLabel />, { preloadedState: openState() });
Expand Down
22 changes: 18 additions & 4 deletions src/ui/components/TopBar/UpdateLabel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import {
UPDATES_CHECK_FEEDBACK_DISMISSED,
UPDATES_DOWNLOAD_REQUESTED,
UPDATES_INSTALL_REQUESTED,
UPDATES_OPEN_APP_STORE_REQUESTED,
UPDATES_PANEL_TOGGLED,
UPDATES_SKIP_REQUESTED,
} from '../../../updates/actions';
Expand Down Expand Up @@ -195,6 +196,8 @@ export const UpdateLabel = () => {
const isUpdatingEnabled = useSelector(
({ isUpdatingEnabled }: RootState) => isUpdatingEnabled
);
const updateStore = useSelector(({ updateStore }: RootState) => updateStore);
const isMasUpdate = updateStore === 'mas';

const reference = useRef<HTMLButtonElement>(null);
const target = useRef<HTMLDivElement>(null);
Expand Down Expand Up @@ -252,10 +255,10 @@ export const UpdateLabel = () => {
if (!newUpdateVersion) {
// In builds that cannot self-update the check listener is never
// registered, so a requested check would sit at "checking" forever —
// show nothing instead.
// show nothing instead. The Mac App Store build has its own check
// listener despite isUpdatingAllowed being false, so it stays exempt.
if (
!isUpdatingAllowed ||
!isUpdatingEnabled ||
(!isMasUpdate && (!isUpdatingAllowed || !isUpdatingEnabled)) ||
updateCheckStatus === 'idle'
) {
return null;
Expand Down Expand Up @@ -337,6 +340,15 @@ export const UpdateLabel = () => {

const handleInstallClick = (): void => {
toggle(false);

if (isMasUpdate) {
// Nothing to download on this build — hand off to the App Store
// listing via a distinct action, so the download-status reducers
// (which see every FSA) never flip to "downloading".
dispatch({ type: UPDATES_OPEN_APP_STORE_REQUESTED });
return;
}

dispatch({ type: UPDATES_DOWNLOAD_REQUESTED });
};

Expand Down Expand Up @@ -433,7 +445,9 @@ export const UpdateLabel = () => {
primary
onClick={handleInstallClick}
>
{t('dialog.update.install')}
{isMasUpdate
? t('dialog.update.openAppStore')
: t('dialog.update.install')}
</Button>
</ButtonGroup>
</Box>
Expand Down
Loading
Loading