diff --git a/app/common/src/text/english.json b/app/common/src/text/english.json index 091d892ce3..9480a8b54a 100644 --- a/app/common/src/text/english.json +++ b/app/common/src/text/english.json @@ -365,10 +365,13 @@ "startWithATemplate": "Discover", "openInfoMenu": "Open info menu", "noProjectIsCurrentlyOpen": "No project is currently open.", - "versionOutdatedTitle": "Upgrade Enso Now", - "versionOutdatedPrompt": "Download the latest version to get the latest upgrades and Cloud functionality.", + "versionOutdatedTitle": "Update available", + "versionOutdatedPrompt": "A new version of Enso is available. We recommend updating to access the latest features, improvements, and security enhancements.", "yourVersion": "Your version:", - "latestVersion": "Latest version:", + "latestVersion": "$0 ($1)", + "changeLog": "View changelog", + "downloadingAppMessage": "The latest version of Enso is now downloading, which may take a while depending on your internet speed. Please check your downloads folder, and you may close this dialog.", + "remindMeLater": "Remind me later", "offlineTitle": "You are offline", "offlineErrorMessage": "It seems like you are offline. Please make sure you are connected to the internet and try again", "offlineToastMessage": "You are offline. Some features may be unavailable.", diff --git a/app/common/src/text/index.ts b/app/common/src/text/index.ts index 11d3f3f142..a53743c6eb 100644 --- a/app/common/src/text/index.ts +++ b/app/common/src/text/index.ts @@ -145,6 +145,8 @@ interface PlaceholderOverrides { readonly arbitraryFieldTooLarge: [maxSize: string] readonly arbitraryFieldTooSmall: [minSize: string] readonly uploadLargeFileStatus: [uploadedParts: number, totalParts: number] + + readonly latestVersion: [version: string, date: string] } /** An tuple of `string` for placeholders for each {@link TextId}. */ diff --git a/app/gui/src/dashboard/assets/download.svg b/app/gui/src/dashboard/assets/download.svg new file mode 100644 index 0000000000..38d86ac187 --- /dev/null +++ b/app/gui/src/dashboard/assets/download.svg @@ -0,0 +1,4 @@ + + + + diff --git a/app/gui/src/dashboard/assets/new_tab.svg b/app/gui/src/dashboard/assets/new_tab.svg new file mode 100644 index 0000000000..afbbdde321 --- /dev/null +++ b/app/gui/src/dashboard/assets/new_tab.svg @@ -0,0 +1,3 @@ + + + diff --git a/app/gui/src/dashboard/assets/snooze.svg b/app/gui/src/dashboard/assets/snooze.svg new file mode 100644 index 0000000000..30ddb929aa --- /dev/null +++ b/app/gui/src/dashboard/assets/snooze.svg @@ -0,0 +1,3 @@ + + + diff --git a/app/gui/src/dashboard/components/AriaComponents/Dialog/Close.tsx b/app/gui/src/dashboard/components/AriaComponents/Dialog/Close.tsx index c4567a91f4..f49ea796f9 100644 --- a/app/gui/src/dashboard/components/AriaComponents/Dialog/Close.tsx +++ b/app/gui/src/dashboard/components/AriaComponents/Dialog/Close.tsx @@ -3,17 +3,15 @@ * * Close button for a dialog. */ -import * as React from 'react' import invariant from 'tiny-invariant' -import * as eventCallback from '#/hooks/eventCallbackHooks' - -import * as button from '../Button' +import { useEventCallback } from '#/hooks/eventCallbackHooks' +import { type ButtonProps, Button } from '../Button' import * as dialogProvider from './DialogProvider' /** Props for {@link Close} component. */ -export type CloseProps = button.ButtonProps +export type CloseProps = ButtonProps /** Close button for a dialog. */ export function Close(props: CloseProps) { @@ -21,12 +19,10 @@ export function Close(props: CloseProps) { invariant(dialogContext, 'Close must be used inside a DialogProvider') - const onPressCallback = eventCallback.useEventCallback< - NonNullable - >((event) => { + const onPressCallback = useEventCallback>((event) => { dialogContext.close() return props.onPress?.(event) }) - return + return - - - + {() => ( + + +
+ + {getText('versionOutdatedPrompt')} + +
+ + {getText('latestVersion', latestVersion, publishedAt)} + + + + + {getText('yourVersion')}{' '} + + {CURRENT_VERSION} + + + +
+ + + + + +
+
+ + +
+ + {getText('downloadingAppMessage')} + + + + {getText('close')} + +
+
+
+ )} ) } + +/** + * Get the version number from a version string. + * @param version - The version string. + * @returns The version number, or null if the version string is not a valid version number. + */ +function getVersionNumber(version: string) { + const versionNumber = Number(version.replace('.', '')) + return isNaN(versionNumber) ? null : versionNumber +} diff --git a/app/ide-desktop/client/tests/electronTest.ts b/app/ide-desktop/client/tests/electronTest.ts index fccafc8846..05ab538bac 100644 --- a/app/ide-desktop/client/tests/electronTest.ts +++ b/app/ide-desktop/client/tests/electronTest.ts @@ -1,11 +1,13 @@ /** @file Commonly used functions for electron tests */ import { _electron, expect, type Page, test } from '@playwright/test' +import { TEXTS } from 'enso-common/src/text' import fs from 'node:fs/promises' import os from 'node:os' import pathModule from 'node:path' const LOADING_TIMEOUT = 10000 +const TEXT = TEXTS.english /** * Tests run on electron executable. @@ -45,19 +47,20 @@ export async function loginAsTestUser(page: Page) { 'Cannot log in; `ENSO_TEST_USER` and `ENSO_TEST_USER_PASSWORD` env variables are not provided', ) } - await page.getByRole('textbox', { name: 'email' }).click() - await page.keyboard.insertText(process.env.ENSO_TEST_USER) - await page.keyboard.press('Tab') - await page.keyboard.insertText(process.env.ENSO_TEST_USER_PASSWORD) - await page.keyboard.press('Enter') + await page.getByRole('textbox', { name: 'email' }).fill(process.env.ENSO_TEST_USER) + await page.getByRole('textbox', { name: 'password' }).fill(process.env.ENSO_TEST_USER_PASSWORD) + await page.getByTestId('form-submit-button').click() - // Accept terms screen - await expect(page.getByText('I agree')).toHaveCount(2) - await expect(page.getByRole('button')).toHaveCount(1) - for (const checkbox of await page.getByText('I agree').all()) { - await checkbox.click() - } - await page.getByRole('button').click() + await page + .getByRole('group', { name: TEXT.licenseAgreementCheckbox }) + .getByText(TEXT.licenseAgreementCheckbox) + .click() + await page + .getByRole('group', { name: TEXT.privacyPolicyCheckbox }) + .getByText(TEXT.privacyPolicyCheckbox) + .click() + + await page.getByTestId('form-submit-button').click() } /**