diff --git a/app/dashboard/404.html b/app/dashboard/404.html index db7833995d..5522400d55 100644 --- a/app/dashboard/404.html +++ b/app/dashboard/404.html @@ -39,8 +39,6 @@
- + diff --git a/app/dashboard/e2e/README.md b/app/dashboard/e2e/README.md index 1e28515a63..168e8eddeb 100644 --- a/app/dashboard/e2e/README.md +++ b/app/dashboard/e2e/README.md @@ -25,7 +25,7 @@ PROD=1 npm run test:e2e:debug -- e2e/file-name-here.spec.ts ## Getting started ```ts -test.test("test name here", ({ page }) => +test.test('test name here', ({ page }) => actions.mockAllAndLogin({ page }).then( // ONLY chain methods from `pageActions`. // Using methods not in `pageActions` is UNDEFINED BEHAVIOR. @@ -34,20 +34,20 @@ test.test("test name here", ({ page }) => // not `Promise`s, which causes Playwright to output a type error. async ({ pageActions }) => await pageActions.goTo.drive(), ), -); +) ``` ### Perform arbitrary actions (e.g. actions on the API) ```ts -test.test("test name here", ({ page }) => +test.test('test name here', ({ page }) => actions.mockAllAndLogin({ page }).then( async ({ pageActions, api }) => await pageActions.do(() => { - api.foo(); - api.bar(); - test.expect(api.baz()?.quux).toEqual("bar"); + api.foo() + api.bar() + test.expect(api.baz()?.quux).toEqual('bar') }), ), -); +) ``` diff --git a/app/dashboard/e2e/actions.ts b/app/dashboard/e2e/actions.ts index 54073802ca..316f3b6d11 100644 --- a/app/dashboard/e2e/actions.ts +++ b/app/dashboard/e2e/actions.ts @@ -621,7 +621,7 @@ export namespace settings { * DO NOT assume the left side of the outer container will change. This means that it is NOT SAFE * to do anything with the returned values other than comparing them. */ export function getAssetRowLeftPx(locator: test.Locator) { - return locator.evaluate(el => el.children[0]?.children[0]?.getBoundingClientRect().left ?? 0) + return locator.evaluate((el) => el.children[0]?.children[0]?.getBoundingClientRect().left ?? 0) } // =================================== @@ -644,7 +644,7 @@ export async function expectOpacity0(locator: test.Locator) { await test.test.step('Expect `opacity: 0`', async () => { await test .expect(async () => { - test.expect(await locator.evaluate(el => getComputedStyle(el).opacity)).toBe('0') + test.expect(await locator.evaluate((el) => getComputedStyle(el).opacity)).toBe('0') }) .toPass() }) @@ -655,7 +655,7 @@ export async function expectNotOpacity0(locator: test.Locator) { await test.test.step('Expect not `opacity: 0`', async () => { await test .expect(async () => { - test.expect(await locator.evaluate(el => getComputedStyle(el).opacity)).not.toBe('0') + test.expect(await locator.evaluate((el) => getComputedStyle(el).opacity)).not.toBe('0') }) .toPass() }) @@ -667,13 +667,13 @@ export async function expectOnScreen(locator: test.Locator) { await test .expect(async () => { const pageBounds = await locator.evaluate(() => document.body.getBoundingClientRect()) - const bounds = await locator.evaluate(el => el.getBoundingClientRect()) + const bounds = await locator.evaluate((el) => el.getBoundingClientRect()) test .expect( bounds.left < pageBounds.right && bounds.right > pageBounds.left && bounds.top < pageBounds.bottom && - bounds.bottom > pageBounds.top + bounds.bottom > pageBounds.top, ) .toBe(true) }) @@ -687,13 +687,13 @@ export async function expectNotOnScreen(locator: test.Locator) { await test .expect(async () => { const pageBounds = await locator.evaluate(() => document.body.getBoundingClientRect()) - const bounds = await locator.evaluate(el => el.getBoundingClientRect()) + const bounds = await locator.evaluate((el) => el.getBoundingClientRect()) test .expect( bounds.left >= pageBounds.right || bounds.right <= pageBounds.left || bounds.top >= pageBounds.bottom || - bounds.bottom <= pageBounds.top + bounds.bottom <= pageBounds.top, ) .toBe(true) }) @@ -773,7 +773,7 @@ export async function login( { page, setupAPI }: MockParams, email = 'email@example.com', password = VALID_PASSWORD, - first = true + first = true, ) { await test.test.step('Login', async () => { await page.goto('/') @@ -812,7 +812,7 @@ export async function reload({ page }: MockParams) { export async function relog( { page, setupAPI }: MockParams, email = 'email@example.com', - password = VALID_PASSWORD + password = VALID_PASSWORD, ) { await test.test.step('Relog', async () => { await page.getByAltText('User Settings').locator('visible=true').click() @@ -901,7 +901,7 @@ export function mockAllAndLogin({ page, setupAPI }: MockParams) { await mockApi({ page, setupAPI }) await mockDate({ page, setupAPI }) }) - .do(thePage => login({ page: thePage, setupAPI })) + .do((thePage) => login({ page: thePage, setupAPI })) } // =================================== diff --git a/app/dashboard/e2e/actions/BaseActions.ts b/app/dashboard/e2e/actions/BaseActions.ts index 8f9f59acf9..424f964884 100644 --- a/app/dashboard/e2e/actions/BaseActions.ts +++ b/app/dashboard/e2e/actions/BaseActions.ts @@ -37,7 +37,7 @@ export default class BaseActions implements Promise { /** Create a {@link BaseActions}. */ constructor( protected readonly page: test.Page, - private readonly promise = Promise.resolve() + private readonly promise = Promise.resolve(), ) {} /** Get the string name of the class of this instance. Required for this class to implement @@ -71,7 +71,7 @@ export default class BaseActions implements Promise { // eslint-disable-next-line no-restricted-syntax onfulfilled?: (() => PromiseLike | T) | null | undefined, // eslint-disable-next-line no-restricted-syntax - onrejected?: ((reason: unknown) => E | PromiseLike) | null | undefined + onrejected?: ((reason: unknown) => E | PromiseLike) | null | undefined, ) { return await this.promise.then(onfulfilled, onrejected) } @@ -109,7 +109,7 @@ export default class BaseActions implements Promise { // eslint-disable-next-line @typescript-eslint/no-unsafe-return return new this.constructor( this.page, - this.then(() => callback(this.page)) + this.then(() => callback(this.page)), ) } @@ -121,18 +121,18 @@ export default class BaseActions implements Promise { /** Press a key, replacing the text `Mod` with `Meta` (`Cmd`) on macOS, and `Control` * on all other platforms. */ press(keyOrShortcut: inputBindings.AutocompleteKeybind) { - return this.do(page => BaseActions.press(page, keyOrShortcut)) + return this.do((page) => BaseActions.press(page, keyOrShortcut)) } /** Perform actions until a predicate passes. */ retry( callback: (actions: this) => this, predicate: (page: test.Page) => Promise, - options: { retries?: number; delay?: number } = {} + options: { retries?: number; delay?: number } = {}, ) { // eslint-disable-next-line @typescript-eslint/no-magic-numbers const { retries = 3, delay = 1_000 } = options - return this.step('Perform actions with retries', async thePage => { + return this.step('Perform actions with retries', async (thePage) => { for (let i = 0; i < retries; i += 1) { await callback(this) if (await predicate(thePage)) { @@ -148,10 +148,10 @@ export default class BaseActions implements Promise { /** Perform actions with the "Mod" modifier key pressed. */ withModPressed(callback: (actions: this) => R) { return callback( - this.step('Press "Mod"', async page => { + this.step('Press "Mod"', async (page) => { await page.keyboard.down(await actions.modModifier(page)) - }) - ).step('Release "Mod"', async page => { + }), + ).step('Release "Mod"', async (page) => { await page.keyboard.up(await actions.modModifier(page)) }) } diff --git a/app/dashboard/e2e/actions/DrivePageActions.ts b/app/dashboard/e2e/actions/DrivePageActions.ts index fa4fd0899c..903217276e 100644 --- a/app/dashboard/e2e/actions/DrivePageActions.ts +++ b/app/dashboard/e2e/actions/DrivePageActions.ts @@ -49,26 +49,26 @@ export default class DrivePageActions extends PageActions { return { /** Switch to the "cloud" category. */ cloud() { - return self.step('Go to "Cloud" category', page => - page.getByRole('button', { name: 'Cloud' }).getByText('Cloud').click() + return self.step('Go to "Cloud" category', (page) => + page.getByRole('button', { name: 'Cloud' }).getByText('Cloud').click(), ) }, /** Switch to the "local" category. */ local() { - return self.step('Go to "Local" category', page => - page.getByRole('button', { name: 'Local' }).getByText('Local').click() + return self.step('Go to "Local" category', (page) => + page.getByRole('button', { name: 'Local' }).getByText('Local').click(), ) }, /** Switch to the "recent" category. */ recent() { - return self.step('Go to "Recent" category', page => - page.getByRole('button', { name: 'Recent' }).getByText('Recent').click() + return self.step('Go to "Recent" category', (page) => + page.getByRole('button', { name: 'Recent' }).getByText('Recent').click(), ) }, /** Switch to the "trash" category. */ trash() { - return self.step('Go to "Trash" category', page => - page.getByRole('button', { name: 'Trash' }).getByText('Trash').click() + return self.step('Go to "Trash" category', (page) => + page.getByRole('button', { name: 'Trash' }).getByText('Trash').click(), ) }, } @@ -81,49 +81,49 @@ export default class DrivePageActions extends PageActions { return { /** Click the column heading for the "name" column to change its sort order. */ clickNameColumnHeading() { - return self.step('Click "name" column heading', page => - page.getByLabel('Sort by name').or(page.getByLabel('Stop sorting by name')).click() + return self.step('Click "name" column heading', (page) => + page.getByLabel('Sort by name').or(page.getByLabel('Stop sorting by name')).click(), ) }, /** Click the column heading for the "modified" column to change its sort order. */ clickModifiedColumnHeading() { - return self.step('Click "modified" column heading', page => + return self.step('Click "modified" column heading', (page) => page .getByLabel('Sort by modification date') .or(page.getByLabel('Stop sorting by modification date')) - .click() + .click(), ) }, /** Click to select a specific row. */ clickRow(index: number) { - return self.step(`Click drive table row #${index}`, page => - locateAssetRows(page).nth(index).click({ position: actions.ASSET_ROW_SAFE_POSITION }) + return self.step(`Click drive table row #${index}`, (page) => + locateAssetRows(page).nth(index).click({ position: actions.ASSET_ROW_SAFE_POSITION }), ) }, /** Right click a specific row to bring up its context menu, or the context menu for multiple * assets when right clicking on a selected asset when multiple assets are selected. */ rightClickRow(index: number) { - return self.step(`Right click drive table row #${index}`, page => + return self.step(`Right click drive table row #${index}`, (page) => locateAssetRows(page) .nth(index) - .click({ button: 'right', position: actions.ASSET_ROW_SAFE_POSITION }) + .click({ button: 'right', position: actions.ASSET_ROW_SAFE_POSITION }), ) }, /** Double click a row. */ doubleClickRow(index: number) { - return self.step(`Double dlick drive table row #${index}`, page => - locateAssetRows(page).nth(index).dblclick({ position: actions.ASSET_ROW_SAFE_POSITION }) + return self.step(`Double dlick drive table row #${index}`, (page) => + locateAssetRows(page).nth(index).dblclick({ position: actions.ASSET_ROW_SAFE_POSITION }), ) }, /** Interact with the set of all rows in the Drive table. */ withRows(callback: baseActions.LocatorCallback) { - return self.step('Interact with drive table rows', async page => { + return self.step('Interact with drive table rows', async (page) => { await callback(locateAssetRows(page)) }) }, /** Drag a row onto another row. */ dragRowToRow(from: number, to: number) { - return self.step(`Drag drive table row #${from} to row #${to}`, async page => { + return self.step(`Drag drive table row #${from} to row #${to}`, async (page) => { const rows = locateAssetRows(page) await rows.nth(from).dragTo(rows.nth(to), { sourcePosition: ASSET_ROW_SAFE_POSITION, @@ -133,19 +133,19 @@ export default class DrivePageActions extends PageActions { }, /** Drag a row onto another row. */ dragRow(from: number, to: test.Locator, force?: boolean) { - return self.step(`Drag drive table row #${from} to custom locator`, page => + return self.step(`Drag drive table row #${from} to custom locator`, (page) => locateAssetRows(page) .nth(from) .dragTo(to, { sourcePosition: ASSET_ROW_SAFE_POSITION, ...(force == null ? {} : { force }), - }) + }), ) }, /** A test assertion to confirm that there is only one row visible, and that row is the * placeholder row displayed when there are no assets to show. */ expectPlaceholderRow() { - return self.step('Expect placeholder row', async page => { + return self.step('Expect placeholder row', async (page) => { const rows = locateAssetRows(page) await test.expect(rows).toHaveCount(1) await test.expect(rows).toHaveText(/You have no files/) @@ -154,7 +154,7 @@ export default class DrivePageActions extends PageActions { /** A test assertion to confirm that there is only one row visible, and that row is the * placeholder row displayed when there are no assets in Trash. */ expectTrashPlaceholderRow() { - return self.step('Expect trash placeholder row', async page => { + return self.step('Expect trash placeholder row', async (page) => { const rows = locateAssetRows(page) await test.expect(rows).toHaveCount(1) await test.expect(rows).toHaveText(/Your trash is empty/) @@ -165,38 +165,38 @@ export default class DrivePageActions extends PageActions { return { /** Toggle visibility for the "modified" column. */ modified() { - return self.step('Expect trash placeholder row', page => - page.getByAltText('Modified').click() + return self.step('Expect trash placeholder row', (page) => + page.getByAltText('Modified').click(), ) }, /** Toggle visibility for the "shared with" column. */ sharedWith() { - return self.step('Expect trash placeholder row', page => - page.getByAltText('Shared With').click() + return self.step('Expect trash placeholder row', (page) => + page.getByAltText('Shared With').click(), ) }, /** Toggle visibility for the "labels" column. */ labels() { - return self.step('Expect trash placeholder row', page => - page.getByAltText('Labels').click() + return self.step('Expect trash placeholder row', (page) => + page.getByAltText('Labels').click(), ) }, /** Toggle visibility for the "accessed by projects" column. */ accessedByProjects() { - return self.step('Expect trash placeholder row', page => - page.getByAltText('Accessed By Projects').click() + return self.step('Expect trash placeholder row', (page) => + page.getByAltText('Accessed By Projects').click(), ) }, /** Toggle visibility for the "accessed data" column. */ accessedData() { - return self.step('Expect trash placeholder row', page => - page.getByAltText('Accessed Data').click() + return self.step('Expect trash placeholder row', (page) => + page.getByAltText('Accessed Data').click(), ) }, /** Toggle visibility for the "docs" column. */ docs() { - return self.step('Expect trash placeholder row', page => - page.getByAltText('Docs').click() + return self.step('Expect trash placeholder row', (page) => + page.getByAltText('Docs').click(), ) }, } @@ -206,27 +206,27 @@ export default class DrivePageActions extends PageActions { /** Open the "start" modal. */ openStartModal() { - return this.step('Open "start" modal', page => - page.getByText('Start with a template').click() + return this.step('Open "start" modal', (page) => + page.getByText('Start with a template').click(), ).into(StartModalActions) } /** Create a new empty project. */ newEmptyProject() { - return this.step('Create empty project', page => - page.getByText('New Empty Project').click() + return this.step('Create empty project', (page) => + page.getByText('New Empty Project').click(), ).into(EditorPageActions) } /** Interact with the drive view (the main container of this page). */ withDriveView(callback: baseActions.LocatorCallback) { - return this.step('Interact with drive view', page => callback(actions.locateDriveView(page))) + return this.step('Interact with drive view', (page) => callback(actions.locateDriveView(page))) } /** Create a new folder using the icon in the Drive Bar. */ createFolder() { - return this.step('Create folder', page => - page.getByRole('button', { name: 'New Folder' }).click() + return this.step('Create folder', (page) => + page.getByRole('button', { name: 'New Folder' }).click(), ) } @@ -234,9 +234,9 @@ export default class DrivePageActions extends PageActions { uploadFile( name: string, contents: WithImplicitCoercion, - mimeType = 'text/plain' + mimeType = 'text/plain', ) { - return this.step(`Upload file '${name}'`, async page => { + return this.step(`Upload file '${name}'`, async (page) => { const fileChooserPromise = page.waitForEvent('filechooser') await page.getByRole('button', { name: 'Import' }).click() const fileChooser = await fileChooserPromise @@ -246,7 +246,7 @@ export default class DrivePageActions extends PageActions { /** Create a new secret using the icon in the Drive Bar. */ createSecret(name: string, value: string) { - return this.step(`Create secret '${name}' = '${value}'`, async page => { + return this.step(`Create secret '${name}' = '${value}'`, async (page) => { await actions.locateNewSecretIcon(page).click() await actions.locateSecretNameInput(page).fill(name) await actions.locateSecretValueInput(page).fill(value) @@ -256,35 +256,35 @@ export default class DrivePageActions extends PageActions { /** Toggle the Asset Panel open or closed. */ toggleAssetPanel() { - return this.step('Toggle asset panel', page => - page.getByLabel('Asset Panel').locator('visible=true').click() + return this.step('Toggle asset panel', (page) => + page.getByLabel('Asset Panel').locator('visible=true').click(), ) } /** Interact with the container element of the assets table. */ withAssetsTable(callback: baseActions.LocatorCallback) { - return this.step('Interact with drive table', async page => { + return this.step('Interact with drive table', async (page) => { await callback(actions.locateAssetsTable(page)) }) } /** Interact with the Asset Panel. */ withAssetPanel(callback: baseActions.LocatorCallback) { - return this.step('Interact with asset panel', async page => { + return this.step('Interact with asset panel', async (page) => { await callback(actions.locateAssetPanel(page)) }) } /** Open the Data Link creation modal by clicking on the Data Link icon. */ openDataLinkModal() { - return this.step('Open "new data link" modal', page => - page.getByRole('button', { name: 'New Datalink' }).click() + return this.step('Open "new data link" modal', (page) => + page.getByRole('button', { name: 'New Datalink' }).click(), ).into(NewDataLinkModalActions) } /** Interact with the context menus (the context menus MUST be visible). */ withContextMenus(callback: baseActions.LocatorCallback) { - return this.step('Interact with context menus', async page => { + return this.step('Interact with context menus', async (page) => { await callback(actions.locateContextMenus(page)) }) } diff --git a/app/dashboard/e2e/actions/LoginPageActions.ts b/app/dashboard/e2e/actions/LoginPageActions.ts index c9bc414fde..935065acb3 100644 --- a/app/dashboard/e2e/actions/LoginPageActions.ts +++ b/app/dashboard/e2e/actions/LoginPageActions.ts @@ -20,7 +20,7 @@ export default class LoginPageActions extends BaseActions { /** Perform a login as a new user (a user that does not yet have a username). */ loginAsNewUser(email = 'email@example.com', password = actions.VALID_PASSWORD) { return this.step('Login (as new user)', () => this.loginInternal(email, password)).into( - SetUsernamePageActions + SetUsernamePageActions, ) } diff --git a/app/dashboard/e2e/actions/NewDataLinkModalActions.ts b/app/dashboard/e2e/actions/NewDataLinkModalActions.ts index 91c9167d0d..c0847a6877 100644 --- a/app/dashboard/e2e/actions/NewDataLinkModalActions.ts +++ b/app/dashboard/e2e/actions/NewDataLinkModalActions.ts @@ -29,7 +29,7 @@ export default class NewDataLinkModalActions extends BaseActions { /** Interact with the "name" input - for example, to set the name using `.fill("")`. */ withNameInput(callback: baseActions.LocatorCallback) { - return this.step('Interact with "name" input', async page => { + return this.step('Interact with "name" input', async (page) => { const locator = locateNewDataLinkModal(page).getByLabel('Name') await callback(locator) }) diff --git a/app/dashboard/e2e/actions/SetUsernamePageActions.ts b/app/dashboard/e2e/actions/SetUsernamePageActions.ts index 7f7839c487..2e9e2de642 100644 --- a/app/dashboard/e2e/actions/SetUsernamePageActions.ts +++ b/app/dashboard/e2e/actions/SetUsernamePageActions.ts @@ -11,7 +11,7 @@ import DrivePageActions from './DrivePageActions' export default class SetUsernamePageActions extends BaseActions { /** Set the userame for a new user that does not yet have a username. */ setUsername(username: string) { - return this.step(`Set username to '${username}'`, async page => { + return this.step(`Set username to '${username}'`, async (page) => { await actions.locateUsernameInput(page).fill(username) await actions.locateSetUsernameButton(page).click() }).into(DrivePageActions) diff --git a/app/dashboard/e2e/actions/StartModalActions.ts b/app/dashboard/e2e/actions/StartModalActions.ts index 39490c580a..7a760c06c6 100644 --- a/app/dashboard/e2e/actions/StartModalActions.ts +++ b/app/dashboard/e2e/actions/StartModalActions.ts @@ -12,18 +12,18 @@ import EditorPageActions from './EditorPageActions' export default class StartModalActions extends BaseActions { /** Close this modal and go back to the Drive page. */ close() { - return this.step('Close "start" modal', page => page.getByLabel('Close').click()).into( - DrivePageActions + return this.step('Close "start" modal', (page) => page.getByLabel('Close').click()).into( + DrivePageActions, ) } /** Create a project from the template at the given index. */ createProjectFromTemplate(index: number) { - return this.step(`Create project from template #${index}`, page => + return this.step(`Create project from template #${index}`, (page) => actions .locateSamples(page) .nth(index + 1) - .click() + .click(), ).into(EditorPageActions) } } diff --git a/app/dashboard/e2e/actions/contextMenuActions.ts b/app/dashboard/e2e/actions/contextMenuActions.ts index ae43c2ead3..e87bd8f50e 100644 --- a/app/dashboard/e2e/actions/contextMenuActions.ts +++ b/app/dashboard/e2e/actions/contextMenuActions.ts @@ -38,102 +38,102 @@ export interface ContextMenuActions { /** Generate actions for the context menu. */ export function contextMenuActions( - step: (name: string, callback: baseActions.PageCallback) => T + step: (name: string, callback: baseActions.PageCallback) => T, ): ContextMenuActions { return { open: () => - step('Open (context menu)', page => - page.getByRole('button', { name: 'Open' }).getByText('Open').click() + step('Open (context menu)', (page) => + page.getByRole('button', { name: 'Open' }).getByText('Open').click(), ), uploadToCloud: () => - step('Upload to cloud (context menu)', page => - page.getByRole('button', { name: 'Upload To Cloud' }).getByText('Upload To Cloud').click() + step('Upload to cloud (context menu)', (page) => + page.getByRole('button', { name: 'Upload To Cloud' }).getByText('Upload To Cloud').click(), ), rename: () => - step('Rename (context menu)', page => - page.getByRole('button', { name: 'Rename' }).getByText('Rename').click() + step('Rename (context menu)', (page) => + page.getByRole('button', { name: 'Rename' }).getByText('Rename').click(), ), snapshot: () => - step('Snapshot (context menu)', page => - page.getByRole('button', { name: 'Snapshot' }).getByText('Snapshot').click() + step('Snapshot (context menu)', (page) => + page.getByRole('button', { name: 'Snapshot' }).getByText('Snapshot').click(), ), moveToTrash: () => - step('Move to trash (context menu)', page => - page.getByRole('button', { name: 'Move To Trash' }).getByText('Move To Trash').click() + step('Move to trash (context menu)', (page) => + page.getByRole('button', { name: 'Move To Trash' }).getByText('Move To Trash').click(), ), moveAllToTrash: () => - step('Move all to trash (context menu)', page => + step('Move all to trash (context menu)', (page) => page .getByRole('button', { name: 'Move All To Trash' }) .getByText('Move All To Trash') - .click() + .click(), ), restoreFromTrash: () => - step('Restore from trash (context menu)', page => + step('Restore from trash (context menu)', (page) => page .getByRole('button', { name: 'Restore From Trash' }) .getByText('Restore From Trash') - .click() + .click(), ), restoreAllFromTrash: () => - step('Restore all from trash (context menu)', page => + step('Restore all from trash (context menu)', (page) => page .getByRole('button', { name: 'Restore All From Trash' }) .getByText('Restore All From Trash') - .click() + .click(), ), share: () => - step('Share (context menu)', page => - page.getByRole('button', { name: 'Share' }).getByText('Share').click() + step('Share (context menu)', (page) => + page.getByRole('button', { name: 'Share' }).getByText('Share').click(), ), label: () => - step('Label (context menu)', page => - page.getByRole('button', { name: 'Label' }).getByText('Label').click() + step('Label (context menu)', (page) => + page.getByRole('button', { name: 'Label' }).getByText('Label').click(), ), duplicate: () => - step('Duplicate (context menu)', page => - page.getByRole('button', { name: 'Duplicate' }).getByText('Duplicate').click() + step('Duplicate (context menu)', (page) => + page.getByRole('button', { name: 'Duplicate' }).getByText('Duplicate').click(), ), duplicateProject: () => - step('Duplicate project (context menu)', page => - page.getByRole('button', { name: 'Duplicate' }).getByText('Duplicate').click() + step('Duplicate project (context menu)', (page) => + page.getByRole('button', { name: 'Duplicate' }).getByText('Duplicate').click(), ).into(EditorPageActions), copy: () => - step('Copy (context menu)', page => - page.getByRole('button', { name: 'Copy' }).getByText('Copy', { exact: true }).click() + step('Copy (context menu)', (page) => + page.getByRole('button', { name: 'Copy' }).getByText('Copy', { exact: true }).click(), ), cut: () => - step('Cut (context menu)', page => - page.getByRole('button', { name: 'Cut' }).getByText('Cut').click() + step('Cut (context menu)', (page) => + page.getByRole('button', { name: 'Cut' }).getByText('Cut').click(), ), paste: () => - step('Paste (context menu)', page => - page.getByRole('button', { name: 'Paste' }).getByText('Paste').click() + step('Paste (context menu)', (page) => + page.getByRole('button', { name: 'Paste' }).getByText('Paste').click(), ), copyAsPath: () => - step('Copy as path (context menu)', page => - page.getByRole('button', { name: 'Copy As Path' }).getByText('Copy As Path').click() + step('Copy as path (context menu)', (page) => + page.getByRole('button', { name: 'Copy As Path' }).getByText('Copy As Path').click(), ), download: () => - step('Download (context menu)', page => - page.getByRole('button', { name: 'Download' }).getByText('Download').click() + step('Download (context menu)', (page) => + page.getByRole('button', { name: 'Download' }).getByText('Download').click(), ), // TODO: Specify the files in parameters. uploadFiles: () => - step('Upload files (context menu)', page => - page.getByRole('button', { name: 'Upload Files' }).getByText('Upload Files').click() + step('Upload files (context menu)', (page) => + page.getByRole('button', { name: 'Upload Files' }).getByText('Upload Files').click(), ), newFolder: () => - step('New folder (context menu)', page => - page.getByRole('button', { name: 'New Folder' }).getByText('New Folder').click() + step('New folder (context menu)', (page) => + page.getByRole('button', { name: 'New Folder' }).getByText('New Folder').click(), ), newSecret: () => - step('New secret (context menu)', page => - page.getByRole('button', { name: 'New Secret' }).getByText('New Secret').click() + step('New secret (context menu)', (page) => + page.getByRole('button', { name: 'New Secret' }).getByText('New Secret').click(), ), newDataLink: () => - step('New Data Link (context menu)', page => - page.getByRole('button', { name: 'New Data Link' }).getByText('New Data Link').click() + step('New Data Link (context menu)', (page) => + page.getByRole('button', { name: 'New Data Link' }).getByText('New Data Link').click(), ), } } diff --git a/app/dashboard/e2e/actions/goToPageActions.ts b/app/dashboard/e2e/actions/goToPageActions.ts index d627f06549..ff054a1a4b 100644 --- a/app/dashboard/e2e/actions/goToPageActions.ts +++ b/app/dashboard/e2e/actions/goToPageActions.ts @@ -22,23 +22,23 @@ export interface GoToPageActions { /** Generate actions for going to a different page. */ export function goToPageActions( - step: (name: string, callback: baseActions.PageCallback) => BaseActions + step: (name: string, callback: baseActions.PageCallback) => BaseActions, ): GoToPageActions { return { drive: () => - step('Go to "Data Catalog" page', page => + step('Go to "Data Catalog" page', (page) => page .getByRole('tab') .filter({ has: page.getByText('Data Catalog') }) - .click() + .click(), ).into(DrivePageActions), editor: () => - step('Go to "Spatial Analysis" page', page => - page.getByTestId('editor-tab-button').click() + step('Go to "Spatial Analysis" page', (page) => + page.getByTestId('editor-tab-button').click(), ).into(EditorPageActions), settings: () => - step('Go to "settings" page', page => BaseActions.press(page, 'Mod+,')).into( - SettingsPageActions + step('Go to "settings" page', (page) => BaseActions.press(page, 'Mod+,')).into( + SettingsPageActions, ), } } diff --git a/app/dashboard/e2e/actions/openUserMenuAction.ts b/app/dashboard/e2e/actions/openUserMenuAction.ts index 31ec3c4164..19172762c8 100644 --- a/app/dashboard/e2e/actions/openUserMenuAction.ts +++ b/app/dashboard/e2e/actions/openUserMenuAction.ts @@ -8,9 +8,9 @@ import type BaseActions from './BaseActions' /** An action to open the User Menu. */ export function openUserMenuAction( - step: (name: string, callback: baseActions.PageCallback) => T + step: (name: string, callback: baseActions.PageCallback) => T, ) { - return step('Open user menu', page => - page.getByAltText('User Settings').locator('visible=true').click() + return step('Open user menu', (page) => + page.getByAltText('User Settings').locator('visible=true').click(), ) } diff --git a/app/dashboard/e2e/actions/userMenuActions.ts b/app/dashboard/e2e/actions/userMenuActions.ts index 11d7878881..ec6f9d0d97 100644 --- a/app/dashboard/e2e/actions/userMenuActions.ts +++ b/app/dashboard/e2e/actions/userMenuActions.ts @@ -24,26 +24,26 @@ export interface UserMenuActions { /** Generate actions for the user menu. */ export function userMenuActions( - step: (name: string, callback: baseActions.PageCallback) => T + step: (name: string, callback: baseActions.PageCallback) => T, ): UserMenuActions { return { downloadApp: (callback: (download: test.Download) => Promise | void) => - step('Download app (user menu)', async page => { + step('Download app (user menu)', async (page) => { const downloadPromise = page.waitForEvent('download') await page.getByRole('button', { name: 'Download App' }).getByText('Download App').click() await callback(await downloadPromise) }), settings: () => - step('Go to Settings (user menu)', async page => { + step('Go to Settings (user menu)', async (page) => { await page.getByRole('button', { name: 'Settings' }).getByText('Settings').click() }).into(SettingsPageActions), logout: () => - step('Logout (user menu)', page => - page.getByRole('button', { name: 'Logout' }).getByText('Logout').click() + step('Logout (user menu)', (page) => + page.getByRole('button', { name: 'Logout' }).getByText('Logout').click(), ).into(LoginPageActions), goToLoginPage: () => - step('Login (user menu)', page => - page.getByRole('button', { name: 'Login', exact: true }).getByText('Login').click() + step('Login (user menu)', (page) => + page.getByRole('button', { name: 'Login', exact: true }).getByText('Login').click(), ).into(LoginPageActions), } } diff --git a/app/dashboard/e2e/api.ts b/app/dashboard/e2e/api.ts index 1756b528b9..21d698c671 100644 --- a/app/dashboard/e2e/api.ts +++ b/app/dashboard/e2e/api.ts @@ -129,7 +129,7 @@ async function mockApiInternal({ page, setupAPI }: MockParams) { const createDirectory = ( title: string, - rest: Partial = {} + rest: Partial = {}, ): backend.DirectoryAsset => object.merge( { @@ -143,12 +143,12 @@ async function mockApiInternal({ page, setupAPI }: MockParams) { parentId: defaultDirectoryId, permissions: [], }, - rest + rest, ) const createProject = ( title: string, - rest: Partial = {} + rest: Partial = {}, ): backend.ProjectAsset => object.merge( { @@ -165,7 +165,7 @@ async function mockApiInternal({ page, setupAPI }: MockParams) { parentId: defaultDirectoryId, permissions: [], }, - rest + rest, ) const createFile = (title: string, rest: Partial = {}): backend.FileAsset => @@ -181,12 +181,12 @@ async function mockApiInternal({ page, setupAPI }: MockParams) { parentId: defaultDirectoryId, permissions: [], }, - rest + rest, ) const createSecret = ( title: string, - rest: Partial = {} + rest: Partial = {}, ): backend.SecretAsset => object.merge( { @@ -200,7 +200,7 @@ async function mockApiInternal({ page, setupAPI }: MockParams) { parentId: defaultDirectoryId, permissions: [], }, - rest + rest, ) const createLabel = (value: string, color: backend.LChColor): backend.Label => ({ @@ -268,7 +268,7 @@ async function mockApiInternal({ page, setupAPI }: MockParams) { const deleteUser = (userId: backend.UserId) => { usersMap.delete(userId) - const index = users.findIndex(user => user.userId === userId) + const index = users.findIndex((user) => user.userId === userId) if (index === -1) { return false } else { @@ -289,7 +289,7 @@ async function mockApiInternal({ page, setupAPI }: MockParams) { } const deleteUserGroup = (userGroupId: backend.UserGroupId) => { - const index = userGroups.findIndex(userGroup => userGroup.id === userGroupId) + const index = userGroups.findIndex((userGroup) => userGroup.id === userGroupId) if (index === -1) { return false } else { @@ -350,14 +350,14 @@ async function mockApiInternal({ page, setupAPI }: MockParams) { // eslint-disable-next-line @typescript-eslint/naming-convention const delete_ = method('DELETE') - await page.route('https://cdn.enso.org/**', route => route.fulfill()) - await page.route('https://www.google-analytics.com/**', route => route.fulfill()) - await page.route('https://www.googletagmanager.com/gtag/js*', route => - route.fulfill({ contentType: 'text/javascript', body: 'export {};' }) + await page.route('https://cdn.enso.org/**', (route) => route.fulfill()) + await page.route('https://www.google-analytics.com/**', (route) => route.fulfill()) + await page.route('https://www.googletagmanager.com/gtag/js*', (route) => + route.fulfill({ contentType: 'text/javascript', body: 'export {};' }), ) const isActuallyOnline = await page.evaluate(() => navigator.onLine) if (!isActuallyOnline) { - await page.route('https://fonts.googleapis.com/*', route => route.abort()) + await page.route('https://fonts.googleapis.com/*', (route) => route.abort()) } await page.route(BASE_URL + '**', (_route, request) => { @@ -402,24 +402,24 @@ async function mockApiInternal({ page, setupAPI }: MockParams) { // The type of the body sent by this app is statically known. // eslint-disable-next-line no-restricted-syntax const body = Object.fromEntries( - new URL(request.url()).searchParams.entries() + new URL(request.url()).searchParams.entries(), ) as unknown as Query const parentId = body.parent_id ?? defaultDirectoryId - let filteredAssets = assets.filter(asset => asset.parentId === parentId) + let filteredAssets = assets.filter((asset) => asset.parentId === parentId) // This lint rule is broken; there is clearly a case for `undefined` below. // eslint-disable-next-line @typescript-eslint/switch-exhaustiveness-check switch (body.filter_by) { case backend.FilterBy.active: { - filteredAssets = filteredAssets.filter(asset => !deletedAssets.has(asset.id)) + filteredAssets = filteredAssets.filter((asset) => !deletedAssets.has(asset.id)) break } case backend.FilterBy.trashed: { - filteredAssets = filteredAssets.filter(asset => deletedAssets.has(asset.id)) + filteredAssets = filteredAssets.filter((asset) => deletedAssets.has(asset.id)) break } case backend.FilterBy.recent: { filteredAssets = assets - .filter(asset => !deletedAssets.has(asset.id)) + .filter((asset) => !deletedAssets.has(asset.id)) // eslint-disable-next-line @typescript-eslint/no-magic-numbers .slice(0, 10) break @@ -436,28 +436,28 @@ async function mockApiInternal({ page, setupAPI }: MockParams) { } } filteredAssets.sort( - (a, b) => backend.ASSET_TYPE_ORDER[a.type] - backend.ASSET_TYPE_ORDER[b.type] + (a, b) => backend.ASSET_TYPE_ORDER[a.type] - backend.ASSET_TYPE_ORDER[b.type], ) const json: remoteBackend.ListDirectoryResponseBody = { assets: filteredAssets } return json }) await get( remoteBackendPaths.LIST_FILES_PATH + '*', - () => ({ files: [] }) satisfies remoteBackend.ListFilesResponseBody + () => ({ files: [] }) satisfies remoteBackend.ListFilesResponseBody, ) await get( remoteBackendPaths.LIST_PROJECTS_PATH + '*', - () => ({ projects: [] }) satisfies remoteBackend.ListProjectsResponseBody + () => ({ projects: [] }) satisfies remoteBackend.ListProjectsResponseBody, ) await get( remoteBackendPaths.LIST_SECRETS_PATH + '*', - () => ({ secrets: [] }) satisfies remoteBackend.ListSecretsResponseBody + () => ({ secrets: [] }) satisfies remoteBackend.ListSecretsResponseBody, ) await get( remoteBackendPaths.LIST_TAGS_PATH + '*', - () => ({ tags: labels }) satisfies remoteBackend.ListTagsResponseBody + () => ({ tags: labels }) satisfies remoteBackend.ListTagsResponseBody, ) - await get(remoteBackendPaths.LIST_USERS_PATH + '*', async route => { + await get(remoteBackendPaths.LIST_USERS_PATH + '*', async (route) => { if (currentUser != null) { return { users } satisfies remoteBackend.ListUsersResponseBody } else { @@ -553,18 +553,18 @@ async function mockApiInternal({ page, setupAPI }: MockParams) { await route.fulfill({ json }) } }) - await get(remoteBackendPaths.INVITATION_PATH + '*', async route => { + await get(remoteBackendPaths.INVITATION_PATH + '*', async (route) => { await route.fulfill({ json: { invitations: [] } satisfies backend.ListInvitationsResponseBody, }) }) - await post(remoteBackendPaths.INVITE_USER_PATH + '*', async route => { + await post(remoteBackendPaths.INVITE_USER_PATH + '*', async (route) => { await route.fulfill() }) - await post(remoteBackendPaths.CREATE_PERMISSION_PATH + '*', async route => { + await post(remoteBackendPaths.CREATE_PERMISSION_PATH + '*', async (route) => { await route.fulfill() }) - await delete_(remoteBackendPaths.deleteAssetPath(GLOB_ASSET_ID), async route => { + await delete_(remoteBackendPaths.deleteAssetPath(GLOB_ASSET_ID), async (route) => { await route.fulfill() }) await post(remoteBackendPaths.closeProjectPath(GLOB_PROJECT_ID), async (route, request) => { @@ -583,10 +583,10 @@ async function mockApiInternal({ page, setupAPI }: MockParams) { } await route.fulfill() }) - await delete_(remoteBackendPaths.deleteTagPath(GLOB_TAG_ID), async route => { + await delete_(remoteBackendPaths.deleteTagPath(GLOB_TAG_ID), async (route) => { await route.fulfill() }) - await post(remoteBackendPaths.POST_LOG_EVENT_PATH, async route => { + await post(remoteBackendPaths.POST_LOG_EVENT_PATH, async (route) => { await route.fulfill() }) @@ -625,7 +625,7 @@ async function mockApiInternal({ page, setupAPI }: MockParams) { // The type of the search params sent by this app is statically known. // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, no-restricted-syntax const searchParams: SearchParams = Object.fromEntries( - new URL(request.url()).searchParams.entries() + new URL(request.url()).searchParams.entries(), ) as never const file = createFile(searchParams.file_name) return { path: '', id: file.id, project: null } satisfies backend.FileInfo @@ -672,7 +672,7 @@ async function mockApiInternal({ page, setupAPI }: MockParams) { // `DirectoryId` to make TypeScript happy. setLabels(backend.DirectoryId(assetId), body.labels) const json: Response = { - tags: body.labels.flatMap(value => { + tags: body.labels.flatMap((value) => { const label = labelsByValue.get(value) return label != null ? [label] : [] }), @@ -722,7 +722,7 @@ async function mockApiInternal({ page, setupAPI }: MockParams) { const body: backend.CreateUserRequestBody = await request.postDataJSON() const organizationId = body.organizationId ?? defaultUser.organizationId const rootDirectoryId = backend.DirectoryId( - organizationId.replace(/^organization-/, 'directory-') + organizationId.replace(/^organization-/, 'directory-'), ) currentUser = { email: body.userEmail, @@ -763,14 +763,14 @@ async function mockApiInternal({ page, setupAPI }: MockParams) { return } }) - await get(remoteBackendPaths.GET_ORGANIZATION_PATH + '*', async route => { + await get(remoteBackendPaths.GET_ORGANIZATION_PATH + '*', async (route) => { await route.fulfill({ json: currentOrganization, // eslint-disable-next-line @typescript-eslint/no-magic-numbers status: currentOrganization == null ? 404 : 200, }) }) - await post(remoteBackendPaths.CREATE_TAG_PATH + '*', route => { + await post(remoteBackendPaths.CREATE_TAG_PATH + '*', (route) => { // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment const body: backend.CreateTagRequestBody = route.request().postDataJSON() const json: backend.Label = { @@ -845,7 +845,7 @@ async function mockApiInternal({ page, setupAPI }: MockParams) { return json }) - await page.route('*', async route => { + await page.route('*', async (route) => { if (!isOnline) { await route.abort('connectionfailed') } diff --git a/app/dashboard/e2e/assetPanel.spec.ts b/app/dashboard/e2e/assetPanel.spec.ts index 897766c718..4db6eb040f 100644 --- a/app/dashboard/e2e/assetPanel.spec.ts +++ b/app/dashboard/e2e/assetPanel.spec.ts @@ -27,24 +27,24 @@ test.test('open and close asset panel', ({ page }) => .mockAllAndLogin({ page }) .createFolder() .driveTable.clickRow(0) - .withAssetPanel(async assetPanel => { + .withAssetPanel(async (assetPanel) => { await actions.expectNotOnScreen(assetPanel) }) .toggleAssetPanel() - .withAssetPanel(async assetPanel => { + .withAssetPanel(async (assetPanel) => { await actions.expectOnScreen(assetPanel) }) .toggleAssetPanel() - .withAssetPanel(async assetPanel => { + .withAssetPanel(async (assetPanel) => { await actions.expectNotOnScreen(assetPanel) - }) + }), ) test.test('asset panel contents', ({ page }) => actions .mockAll({ page, - setupAPI: api => { + setupAPI: (api) => { const { defaultOrganizationId, defaultUserId } = api api.addProject('project', { description: DESCRIPTION, @@ -64,7 +64,7 @@ test.test('asset panel contents', ({ page }) => }, }) .login() - .do(async thePage => { + .do(async (thePage) => { await actions.passTermsAndConditionsDialog({ page: thePage }) }) .driveTable.clickRow(0) @@ -73,5 +73,5 @@ test.test('asset panel contents', ({ page }) => await test.expect(actions.locateAssetPanelDescription(page)).toHaveText(DESCRIPTION) // `getByText` is required so that this assertion works if there are multiple permissions. await test.expect(actions.locateAssetPanelPermissions(page).getByText(USERNAME)).toBeVisible() - }) + }), ) diff --git a/app/dashboard/e2e/assetSearchBar.spec.ts b/app/dashboard/e2e/assetSearchBar.spec.ts index 31c67a51b0..666e7a3d02 100644 --- a/app/dashboard/e2e/assetSearchBar.spec.ts +++ b/app/dashboard/e2e/assetSearchBar.spec.ts @@ -34,7 +34,7 @@ test.test('tags', async ({ page }) => { test.test('labels', async ({ page }) => { await actions.mockAllAndLogin({ page, - setupAPI: api => { + setupAPI: (api) => { api.addLabel('aaaa', backend.COLORS[0]) // eslint-disable-next-line @typescript-eslint/no-non-null-assertion api.addLabel('bbbb', backend.COLORS[1]!) @@ -63,7 +63,7 @@ test.test('labels', async ({ page }) => { test.test('suggestions', async ({ page }) => { await actions.mockAllAndLogin({ page, - setupAPI: api => { + setupAPI: (api) => { api.addDirectory('foo') api.addProject('bar') api.addSecret('baz') @@ -89,7 +89,7 @@ test.test('suggestions', async ({ page }) => { test.test('suggestions (keyboard)', async ({ page }) => { await actions.mockAllAndLogin({ page, - setupAPI: api => { + setupAPI: (api) => { api.addDirectory('foo') api.addProject('bar') api.addSecret('baz') @@ -114,7 +114,7 @@ test.test('complex flows', async ({ page }) => { await actions.mockAllAndLogin({ page, - setupAPI: api => { + setupAPI: (api) => { api.addDirectory(firstName) api.addProject('bar') api.addSecret('baz') diff --git a/app/dashboard/e2e/assetsTableFeatures.spec.ts b/app/dashboard/e2e/assetsTableFeatures.spec.ts index eec21db13f..ab01b960b2 100644 --- a/app/dashboard/e2e/assetsTableFeatures.spec.ts +++ b/app/dashboard/e2e/assetsTableFeatures.spec.ts @@ -10,8 +10,8 @@ test.test('extra columns should stick to right side of assets table', ({ page }) .mockAllAndLogin({ page }) .driveTable.toggleColumn.accessedByProjects() .driveTable.toggleColumn.accessedData() - .withAssetsTable(async table => { - await table.evaluate(element => { + .withAssetsTable(async (table) => { + await table.evaluate((element) => { let scrollableParent: HTMLElement | SVGElement | null = element while ( scrollableParent != null && @@ -23,27 +23,27 @@ test.test('extra columns should stick to right side of assets table', ({ page }) scrollableParent?.scrollTo({ left: 999999, behavior: 'instant' }) }) }) - .do(async thePage => { + .do(async (thePage) => { const extraColumns = actions.locateExtraColumns(thePage) const assetsTable = actions.locateAssetsTable(thePage) await test .expect(async () => { const extraColumnsRight = await extraColumns.evaluate( - element => element.getBoundingClientRect().right + (element) => element.getBoundingClientRect().right, ) const assetsTableRight = await assetsTable.evaluate( - element => element.getBoundingClientRect().right + (element) => element.getBoundingClientRect().right, ) test.expect(extraColumnsRight).toEqual(assetsTableRight) }) .toPass({ timeout: PASS_TIMEOUT }) - }) + }), ) test.test('extra columns should stick to top of scroll container', async ({ page }) => { await actions.mockAllAndLogin({ page, - setupAPI: api => { + setupAPI: (api) => { // eslint-disable-next-line @typescript-eslint/no-magic-numbers for (let i = 0; i < 100; i += 1) { api.addFile('a') @@ -53,7 +53,7 @@ test.test('extra columns should stick to top of scroll container', async ({ page await actions.locateAccessedByProjectsColumnToggle(page).click() await actions.locateAccessedDataColumnToggle(page).click() - await actions.locateAssetsTable(page).evaluate(element => { + await actions.locateAssetsTable(page).evaluate((element) => { let scrollableParent: HTMLElement | SVGElement | null = element while ( scrollableParent != null && @@ -69,9 +69,9 @@ test.test('extra columns should stick to top of scroll container', async ({ page await test .expect(async () => { const extraColumnsTop = await extraColumns.evaluate( - element => element.getBoundingClientRect().top + (element) => element.getBoundingClientRect().top, ) - const assetsTableTop = await assetsTable.evaluate(element => { + const assetsTableTop = await assetsTable.evaluate((element) => { let scrollableParent: HTMLElement | SVGElement | null = element while ( scrollableParent != null && @@ -92,17 +92,17 @@ test.test('can drop onto root directory dropzone', ({ page }) => .createFolder() .uploadFile('b', 'testing') .driveTable.doubleClickRow(0) - .driveTable.withRows(async rows => { + .driveTable.withRows(async (rows) => { const parentLeft = await actions.getAssetRowLeftPx(rows.nth(0)) const childLeft = await actions.getAssetRowLeftPx(rows.nth(1)) test.expect(childLeft, 'Child is indented further than parent').toBeGreaterThan(parentLeft) }) .driveTable.dragRow(1, actions.locateRootDirectoryDropzone(page)) - .driveTable.withRows(async rows => { + .driveTable.withRows(async (rows) => { const firstLeft = await actions.getAssetRowLeftPx(rows.nth(0)) // The second row is the indented child of the directory // (the "this folder is empty" row). const secondLeft = await actions.getAssetRowLeftPx(rows.nth(2)) test.expect(firstLeft, 'Siblings have same indentation').toEqual(secondLeft) - }) + }), ) diff --git a/app/dashboard/e2e/copy.spec.ts b/app/dashboard/e2e/copy.spec.ts index b1f9839d84..373edefcc2 100644 --- a/app/dashboard/e2e/copy.spec.ts +++ b/app/dashboard/e2e/copy.spec.ts @@ -20,14 +20,14 @@ test.test('copy', ({ page }) => .driveTable.rightClickRow(1) // Assets: [0: Folder 2, 1: Folder 1, 2: Folder 2 (copy) ] .contextMenu.paste() - .driveTable.withRows(async rows => { + .driveTable.withRows(async (rows) => { await test.expect(rows).toHaveCount(3) await test.expect(rows.nth(2)).toBeVisible() await test.expect(rows.nth(2)).toHaveText(/^New Folder 2 [(]copy[)]/) const parentLeft = await actions.getAssetRowLeftPx(rows.nth(1)) const childLeft = await actions.getAssetRowLeftPx(rows.nth(2)) test.expect(childLeft, 'child is indented further than parent').toBeGreaterThan(parentLeft) - }) + }), ) test.test('copy (keyboard)', ({ page }) => @@ -43,14 +43,14 @@ test.test('copy (keyboard)', ({ page }) => .driveTable.clickRow(1) // Assets: [0: Folder 2, 1: Folder 1, 2: Folder 2 (copy) ] .press('Mod+V') - .driveTable.withRows(async rows => { + .driveTable.withRows(async (rows) => { await test.expect(rows).toHaveCount(3) await test.expect(rows.nth(2)).toBeVisible() await test.expect(rows.nth(2)).toHaveText(/^New Folder 2 [(]copy[)]/) const parentLeft = await actions.getAssetRowLeftPx(rows.nth(1)) const childLeft = await actions.getAssetRowLeftPx(rows.nth(2)) test.expect(childLeft, 'child is indented further than parent').toBeGreaterThan(parentLeft) - }) + }), ) test.test('move', ({ page }) => @@ -66,14 +66,14 @@ test.test('move', ({ page }) => .driveTable.rightClickRow(1) // Assets: [0: Folder 1, 1: Folder 2 ] .contextMenu.paste() - .driveTable.withRows(async rows => { + .driveTable.withRows(async (rows) => { await test.expect(rows).toHaveCount(2) await test.expect(rows.nth(1)).toBeVisible() await test.expect(rows.nth(1)).toHaveText(/^New Folder 2/) const parentLeft = await actions.getAssetRowLeftPx(rows.nth(0)) const childLeft = await actions.getAssetRowLeftPx(rows.nth(1)) test.expect(childLeft, 'child is indented further than parent').toBeGreaterThan(parentLeft) - }) + }), ) test.test('move (drag)', ({ page }) => @@ -85,14 +85,14 @@ test.test('move (drag)', ({ page }) => .createFolder() // Assets: [0: Folder 1, 1: Folder 2 ] .driveTable.dragRowToRow(0, 1) - .driveTable.withRows(async rows => { + .driveTable.withRows(async (rows) => { await test.expect(rows).toHaveCount(2) await test.expect(rows.nth(1)).toBeVisible() await test.expect(rows.nth(1)).toHaveText(/^New Folder 2/) const parentLeft = await actions.getAssetRowLeftPx(rows.nth(0)) const childLeft = await actions.getAssetRowLeftPx(rows.nth(1)) test.expect(childLeft, 'child is indented further than parent').toBeGreaterThan(parentLeft) - }) + }), ) test.test('move to trash', ({ page }) => @@ -104,13 +104,13 @@ test.test('move to trash', ({ page }) => .createFolder() // NOTE: For some reason, `react-aria-components` causes drag-n-drop to break if `Mod` is still // held. - .withModPressed(modActions => modActions.driveTable.clickRow(0).driveTable.clickRow(1)) + .withModPressed((modActions) => modActions.driveTable.clickRow(0).driveTable.clickRow(1)) .driveTable.dragRow(0, actions.locateTrashCategory(page)) .driveTable.expectPlaceholderRow() .goToCategory.trash() - .driveTable.withRows(async rows => { + .driveTable.withRows(async (rows) => { await test.expect(rows).toHaveText([/^New Folder 1/, /^New Folder 2/]) - }) + }), ) test.test('move (keyboard)', ({ page }) => @@ -126,14 +126,14 @@ test.test('move (keyboard)', ({ page }) => .driveTable.clickRow(1) // Assets: [0: Folder 1, 1: Folder 2 ] .press('Mod+V') - .driveTable.withRows(async rows => { + .driveTable.withRows(async (rows) => { await test.expect(rows).toHaveCount(2) await test.expect(rows.nth(1)).toBeVisible() await test.expect(rows.nth(1)).toHaveText(/^New Folder 2/) const parentLeft = await actions.getAssetRowLeftPx(rows.nth(0)) const childLeft = await actions.getAssetRowLeftPx(rows.nth(1)) test.expect(childLeft, 'child is indented further than parent').toBeGreaterThan(parentLeft) - }) + }), ) test.test('cut (keyboard)', async ({ page }) => @@ -142,16 +142,16 @@ test.test('cut (keyboard)', async ({ page }) => .createFolder() .driveTable.clickRow(0) .press('Mod+X') - .driveTable.withRows(async rows => { + .driveTable.withRows(async (rows) => { // This action is not a builtin `expect` action, so it needs to be manually retried. await test .expect(async () => { test - .expect(await rows.nth(0).evaluate(el => Number(getComputedStyle(el).opacity))) + .expect(await rows.nth(0).evaluate((el) => Number(getComputedStyle(el).opacity))) .toBeLessThan(1) }) .toPass() - }) + }), ) test.test('duplicate', ({ page }) => @@ -163,13 +163,13 @@ test.test('duplicate', ({ page }) => .goToPage.drive() .driveTable.rightClickRow(0) .contextMenu.duplicate() - .driveTable.withRows(async rows => { + .driveTable.withRows(async (rows) => { // Assets: [0: New Project 1 (copy), 1: New Project 1] await test.expect(rows).toHaveCount(2) await test.expect(actions.locateContextMenus(page)).not.toBeVisible() await test.expect(rows.nth(0)).toBeVisible() await test.expect(rows.nth(0)).toHaveText(/^New Project 1 [(]copy[)]/) - }) + }), ) test.test('duplicate (keyboard)', ({ page }) => @@ -181,10 +181,10 @@ test.test('duplicate (keyboard)', ({ page }) => .goToPage.drive() .driveTable.clickRow(0) .press('Mod+D') - .driveTable.withRows(async rows => { + .driveTable.withRows(async (rows) => { // Assets: [0: New Project 1 (copy), 1: New Project 1] await test.expect(rows).toHaveCount(2) await test.expect(rows.nth(0)).toBeVisible() await test.expect(rows.nth(0)).toHaveText(/^New Project 1 [(]copy[)]/) - }) + }), ) diff --git a/app/dashboard/e2e/createAsset.spec.ts b/app/dashboard/e2e/createAsset.spec.ts index 7cce2668a6..ccc59dede6 100644 --- a/app/dashboard/e2e/createAsset.spec.ts +++ b/app/dashboard/e2e/createAsset.spec.ts @@ -24,40 +24,40 @@ test.test('create folder', ({ page }) => actions .mockAllAndLogin({ page }) .createFolder() - .driveTable.withRows(async rows => { + .driveTable.withRows(async (rows) => { await test.expect(rows).toHaveCount(1) await test.expect(rows.nth(0)).toBeVisible() await test.expect(rows.nth(0)).toHaveText(/^New Folder 1/) - }) + }), ) test.test('create project', ({ page }) => actions .mockAllAndLogin({ page }) .newEmptyProject() - .do(thePage => test.expect(actions.locateEditor(thePage)).toBeAttached()) + .do((thePage) => test.expect(actions.locateEditor(thePage)).toBeAttached()) .goToPage.drive() - .driveTable.withRows(rows => test.expect(rows).toHaveCount(1)) + .driveTable.withRows((rows) => test.expect(rows).toHaveCount(1)), ) test.test('upload file', ({ page }) => actions .mockAllAndLogin({ page }) .uploadFile(FILE_NAME, FILE_CONTENTS) - .driveTable.withRows(async rows => { + .driveTable.withRows(async (rows) => { await test.expect(rows).toHaveCount(1) await test.expect(rows.nth(0)).toBeVisible() await test.expect(rows.nth(0)).toHaveText(new RegExp('^' + FILE_NAME)) - }) + }), ) test.test('create secret', ({ page }) => actions .mockAllAndLogin({ page }) .createSecret(SECRET_NAME, SECRET_VALUE) - .driveTable.withRows(async rows => { + .driveTable.withRows(async (rows) => { await test.expect(rows).toHaveCount(1) await test.expect(rows.nth(0)).toBeVisible() await test.expect(rows.nth(0)).toHaveText(new RegExp('^' + SECRET_NAME)) - }) + }), ) diff --git a/app/dashboard/e2e/dataLinkEditor.spec.ts b/app/dashboard/e2e/dataLinkEditor.spec.ts index 1d06ed41a4..ed50465d4e 100644 --- a/app/dashboard/e2e/dataLinkEditor.spec.ts +++ b/app/dashboard/e2e/dataLinkEditor.spec.ts @@ -9,7 +9,7 @@ test.test('data link editor', ({ page }) => actions .mockAllAndLogin({ page }) .openDataLinkModal() - .withNameInput(async input => { + .withNameInput(async (input) => { await input.fill(DATA_LINK_NAME) - }) + }), ) diff --git a/app/dashboard/e2e/delete.spec.ts b/app/dashboard/e2e/delete.spec.ts index f2c36002d8..d445f9a186 100644 --- a/app/dashboard/e2e/delete.spec.ts +++ b/app/dashboard/e2e/delete.spec.ts @@ -7,44 +7,44 @@ test.test('delete and restore', ({ page }) => actions .mockAllAndLogin({ page }) .createFolder() - .driveTable.withRows(async rows => { + .driveTable.withRows(async (rows) => { await test.expect(rows).toHaveCount(1) }) .driveTable.rightClickRow(0) .contextMenu.moveToTrash() .driveTable.expectPlaceholderRow() .goToCategory.trash() - .driveTable.withRows(async rows => { + .driveTable.withRows(async (rows) => { await test.expect(rows).toHaveCount(1) }) .driveTable.rightClickRow(0) .contextMenu.restoreFromTrash() .driveTable.expectTrashPlaceholderRow() .goToCategory.cloud() - .driveTable.withRows(async rows => { + .driveTable.withRows(async (rows) => { await test.expect(rows).toHaveCount(1) - }) + }), ) test.test('delete and restore (keyboard)', ({ page }) => actions .mockAllAndLogin({ page }) .createFolder() - .driveTable.withRows(async rows => { + .driveTable.withRows(async (rows) => { await test.expect(rows).toHaveCount(1) }) .driveTable.clickRow(0) .press('Delete') .driveTable.expectPlaceholderRow() .goToCategory.trash() - .driveTable.withRows(async rows => { + .driveTable.withRows(async (rows) => { await test.expect(rows).toHaveCount(1) }) .driveTable.clickRow(0) .press('Mod+R') .driveTable.expectTrashPlaceholderRow() .goToCategory.cloud() - .driveTable.withRows(async rows => { + .driveTable.withRows(async (rows) => { await test.expect(rows).toHaveCount(1) - }) + }), ) diff --git a/app/dashboard/e2e/driveView.spec.ts b/app/dashboard/e2e/driveView.spec.ts index 71d9776e85..49e614f746 100644 --- a/app/dashboard/e2e/driveView.spec.ts +++ b/app/dashboard/e2e/driveView.spec.ts @@ -6,7 +6,7 @@ import * as actions from './actions' test.test('drive view', ({ page }) => actions .mockAllAndLogin({ page }) - .withDriveView(async view => { + .withDriveView(async (view) => { await test.expect(view).toBeVisible() }) .driveTable.expectPlaceholderRow() @@ -15,7 +15,7 @@ test.test('drive view', ({ page }) => await test.expect(actions.locateEditor(page)).toBeAttached() }) .goToPage.drive() - .driveTable.withRows(async rows => { + .driveTable.withRows(async (rows) => { await test.expect(rows).toHaveCount(1) }) .do(async () => { @@ -26,19 +26,19 @@ test.test('drive view', ({ page }) => await test.expect(actions.locateEditor(page)).toBeAttached() }) .goToPage.drive() - .driveTable.withRows(async rows => { + .driveTable.withRows(async (rows) => { await test.expect(rows).toHaveCount(2) }) // The last opened project needs to be stopped, to remove the toast notification notifying the // user that project creation may take a while. Previously opened projects are stopped when the // new project is created. - .driveTable.withRows(async rows => { + .driveTable.withRows(async (rows) => { await actions.locateStopProjectButton(rows.nth(0)).click() }) // Project context menu .driveTable.rightClickRow(0) .contextMenu.moveToTrash() - .driveTable.withRows(async rows => { + .driveTable.withRows(async (rows) => { await test.expect(rows).toHaveCount(1) - }) + }), ) diff --git a/app/dashboard/e2e/labels.spec.ts b/app/dashboard/e2e/labels.spec.ts index 1594b05b37..92fb3892ed 100644 --- a/app/dashboard/e2e/labels.spec.ts +++ b/app/dashboard/e2e/labels.spec.ts @@ -9,7 +9,7 @@ test.test('drag labels onto single row', async ({ page }) => { const label = 'aaaa' await actions.mockAllAndLogin({ page, - setupAPI: api => { + setupAPI: (api) => { api.addLabel(label, backend.COLORS[0]) // eslint-disable-next-line @typescript-eslint/no-non-null-assertion api.addLabel('bbbb', backend.COLORS[1]!) @@ -39,7 +39,7 @@ test.test('drag labels onto multiple rows', async ({ page }) => { const label = 'aaaa' await actions.mockAllAndLogin({ page, - setupAPI: api => { + setupAPI: (api) => { api.addLabel(label, backend.COLORS[0]) // eslint-disable-next-line @typescript-eslint/no-non-null-assertion api.addLabel('bbbb', backend.COLORS[1]!) diff --git a/app/dashboard/e2e/loginLogout.spec.ts b/app/dashboard/e2e/loginLogout.spec.ts index a363c43fcc..4de5e3feb5 100644 --- a/app/dashboard/e2e/loginLogout.spec.ts +++ b/app/dashboard/e2e/loginLogout.spec.ts @@ -11,15 +11,15 @@ test.test('login and logout', ({ page }) => actions .mockAll({ page }) .login() - .do(async thePage => { + .do(async (thePage) => { await actions.passTermsAndConditionsDialog({ page: thePage }) await test.expect(actions.locateDriveView(thePage)).toBeVisible() await test.expect(actions.locateLoginButton(thePage)).not.toBeVisible() }) .openUserMenu() .userMenu.logout() - .do(async thePage => { + .do(async (thePage) => { await test.expect(actions.locateDriveView(thePage)).not.toBeVisible() await test.expect(actions.locateLoginButton(thePage)).toBeVisible() - }) + }), ) diff --git a/app/dashboard/e2e/loginScreen.spec.ts b/app/dashboard/e2e/loginScreen.spec.ts index 884e936a7e..2dbd7be3ef 100644 --- a/app/dashboard/e2e/loginScreen.spec.ts +++ b/app/dashboard/e2e/loginScreen.spec.ts @@ -17,7 +17,7 @@ test.test('login screen', async ({ page }) => { test .expect( await page.evaluate(() => document.querySelector('form')?.checkValidity()), - 'form should reject invalid email' + 'form should reject invalid email', ) .toBe(false) await actions.locateLoginButton(page).click() @@ -28,7 +28,7 @@ test.test('login screen', async ({ page }) => { test .expect( await page.evaluate(() => document.querySelector('form')?.checkValidity()), - 'form should accept invalid password' + 'form should accept invalid password', ) .toBe(true) await actions.locateLoginButton(page).click() diff --git a/app/dashboard/e2e/pageSwitcher.spec.ts b/app/dashboard/e2e/pageSwitcher.spec.ts index 546100e647..115478fc33 100644 --- a/app/dashboard/e2e/pageSwitcher.spec.ts +++ b/app/dashboard/e2e/pageSwitcher.spec.ts @@ -9,13 +9,13 @@ test.test('page switcher', ({ page }) => // Create a new project so that the editor page can be switched to. .newEmptyProject() .goToPage.drive() - .do(async thePage => { + .do(async (thePage) => { await test.expect(actions.locateDriveView(thePage)).toBeVisible() await test.expect(actions.locateEditor(thePage)).not.toBeVisible() }) .goToPage.editor() - .do(async thePage => { + .do(async (thePage) => { await test.expect(actions.locateDriveView(thePage)).not.toBeVisible() await test.expect(actions.locateEditor(thePage)).toBeVisible() - }) + }), ) diff --git a/app/dashboard/e2e/signUp.spec.ts b/app/dashboard/e2e/signUp.spec.ts index 223d76999a..288a381d1f 100644 --- a/app/dashboard/e2e/signUp.spec.ts +++ b/app/dashboard/e2e/signUp.spec.ts @@ -22,7 +22,7 @@ test.test('sign up with organization id', async ({ page }) => { await page.goto('/') await page.waitForLoadState('domcontentloaded') await page.goto( - '/registration?' + new URLSearchParams([['organization_id', ORGANIZATION_ID]]).toString() + '/registration?' + new URLSearchParams([['organization_id', ORGANIZATION_ID]]).toString(), ) const api = await actions.mockApi({ page }) api.setCurrentUser(null) @@ -81,7 +81,7 @@ test.test('sign up flow', ({ page }) => { return actions .mockAll({ page, - setupAPI: theApi => { + setupAPI: (theApi) => { api = theApi theApi.setCurrentUser(null) @@ -91,11 +91,11 @@ test.test('sign up flow', ({ page }) => { }, }) .loginAsNewUser(EMAIL, actions.VALID_PASSWORD) - .do(async thePage => { + .do(async (thePage) => { await actions.passTermsAndConditionsDialog({ page: thePage }) }) .setUsername(NAME) - .do(async thePage => { + .do(async (thePage) => { await test.expect(actions.locateUpgradeButton(thePage)).toBeVisible() await test.expect(actions.locateDriveView(thePage)).not.toBeVisible() }) diff --git a/app/dashboard/e2e/sort.spec.ts b/app/dashboard/e2e/sort.spec.ts index 6df43f1337..a11b55f3b8 100644 --- a/app/dashboard/e2e/sort.spec.ts +++ b/app/dashboard/e2e/sort.spec.ts @@ -22,7 +22,7 @@ const MIN_MS = 60_000 test.test('sort', async ({ page }) => { await actions.mockAll({ page, - setupAPI: api => { + setupAPI: (api) => { const date1 = dateTime.toRfc3339(new Date(START_DATE_EPOCH_MS)) const date2 = dateTime.toRfc3339(new Date(START_DATE_EPOCH_MS + 1 * MIN_MS)) const date3 = dateTime.toRfc3339(new Date(START_DATE_EPOCH_MS + 2 * MIN_MS)) diff --git a/app/dashboard/e2e/startModal.spec.ts b/app/dashboard/e2e/startModal.spec.ts index 598bb9f22b..f484a6f530 100644 --- a/app/dashboard/e2e/startModal.spec.ts +++ b/app/dashboard/e2e/startModal.spec.ts @@ -8,8 +8,8 @@ test.test('create project from template', ({ page }) => .mockAllAndLogin({ page }) .openStartModal() .createProjectFromTemplate(0) - .do(async thePage => { + .do(async (thePage) => { await test.expect(actions.locateEditor(thePage)).toBeAttached() await test.expect(actions.locateSamples(page).first()).not.toBeVisible() - }) + }), ) diff --git a/app/dashboard/e2e/userMenu.spec.ts b/app/dashboard/e2e/userMenu.spec.ts index 48b5cdb1a7..cb25ebeaca 100644 --- a/app/dashboard/e2e/userMenu.spec.ts +++ b/app/dashboard/e2e/userMenu.spec.ts @@ -7,17 +7,17 @@ test.test('user menu', ({ page }) => actions .mockAllAndLogin({ page }) .openUserMenu() - .do(async thePage => { + .do(async (thePage) => { await test.expect(actions.locateUserMenu(thePage)).toBeVisible() - }) + }), ) test.test('download app', ({ page }) => actions .mockAllAndLogin({ page }) .openUserMenu() - .userMenu.downloadApp(async download => { + .userMenu.downloadApp(async (download) => { await download.cancel() test.expect(download.url()).toMatch(/^https:[/][/]objects.githubusercontent.com/) - }) + }), ) diff --git a/app/dashboard/e2e/userSettings.spec.ts b/app/dashboard/e2e/userSettings.spec.ts index dc79f0a409..aa6da128c8 100644 --- a/app/dashboard/e2e/userSettings.spec.ts +++ b/app/dashboard/e2e/userSettings.spec.ts @@ -38,7 +38,7 @@ test.test('change password form', async ({ page }) => { await localActions .locateNewPasswordInput(page) .evaluate((element: HTMLInputElement) => element.validity.valid), - 'invalid new password should be rejected' + 'invalid new password should be rejected', ) .toBe(false) await test @@ -55,13 +55,13 @@ test.test('change password form', async ({ page }) => { await localActions .locateConfirmNewPasswordInput(page) .evaluate((element: HTMLInputElement) => element.validity.valid), - 'invalid new password confirmation should be rejected' + 'invalid new password confirmation should be rejected', ) .toBe(false) await test .expect( localActions.locateChangeButton(page), - 'invalid new password confirmation should be rejected' + 'invalid new password confirmation should be rejected', ) .toBeDisabled() }) diff --git a/app/dashboard/index.html b/app/dashboard/index.html index 7f12e061b1..7e628ada0d 100644 --- a/app/dashboard/index.html +++ b/app/dashboard/index.html @@ -41,8 +41,6 @@
- + diff --git a/app/dashboard/playwright.config.ts b/app/dashboard/playwright.config.ts index a6980ccfe6..dd9597fc05 100644 --- a/app/dashboard/playwright.config.ts +++ b/app/dashboard/playwright.config.ts @@ -33,12 +33,12 @@ export default test.defineConfig({ launchOptions: { ignoreDefaultArgs: ['--headless'], args: [ - ...(DEBUG - ? [] - : [ - // Much closer to headful Chromium than classic headless. - '--headless=new', - ]), + ...(DEBUG ? + [] + : [ + // Much closer to headful Chromium than classic headless. + '--headless=new', + ]), // Required for `backdrop-filter: blur` to work. '--use-angle=swiftshader', // FIXME: `--disable-gpu` disables `backdrop-filter: blur`, which is not handled by diff --git a/app/dashboard/src/App.tsx b/app/dashboard/src/App.tsx index 8125876333..b0bb4bbc65 100644 --- a/app/dashboard/src/App.tsx +++ b/app/dashboard/src/App.tsx @@ -53,8 +53,8 @@ import DevtoolsProvider from '#/providers/EnsoDevtoolsProvider' import * as httpClientProvider from '#/providers/HttpClientProvider' import InputBindingsProvider from '#/providers/InputBindingsProvider' import LocalStorageProvider, * as localStorageProvider from '#/providers/LocalStorageProvider' -import LoggerProvider from '#/providers/LoggerProvider' import type * as loggerProvider from '#/providers/LoggerProvider' +import LoggerProvider from '#/providers/LoggerProvider' import ModalProvider, * as modalProvider from '#/providers/ModalProvider' import * as navigator2DProvider from '#/providers/Navigator2DProvider' import SessionProvider from '#/providers/SessionProvider' @@ -86,8 +86,7 @@ import * as setOrganizationNameModal from '#/modals/SetOrganizationNameModal' import * as termsOfServiceModal from '#/modals/TermsOfServiceModal' import LocalBackend from '#/services/LocalBackend' -import * as projectManager from '#/services/ProjectManager' -import ProjectManager from '#/services/ProjectManager' +import ProjectManager, * as projectManager from '#/services/ProjectManager' import RemoteBackend from '#/services/RemoteBackend' import * as appBaseUrl from '#/utilities/appBaseUrl' @@ -110,17 +109,17 @@ declare module '#/utilities/LocalStorage' { } LocalStorage.registerKey('inputBindings', { - tryParse: value => - typeof value !== 'object' || value == null - ? null - : Object.fromEntries( - Object.entries({ ...value }).flatMap(kv => { - const [k, v] = kv - return Array.isArray(v) && v.every((item): item is string => typeof item === 'string') - ? [[k, v]] - : [] - }) - ), + tryParse: (value) => + typeof value !== 'object' || value == null ? + null + : Object.fromEntries( + Object.entries({ ...value }).flatMap((kv) => { + const [k, v] = kv + return Array.isArray(v) && v.every((item): item is string => typeof item === 'string') ? + [[k, v]] + : [] + }), + ), }) // ====================== @@ -276,12 +275,12 @@ function AppRouter(props: AppRouterProps) { const localBackend = React.useMemo( () => (projectManagerInstance != null ? new LocalBackend(projectManagerInstance) : null), - [projectManagerInstance] + [projectManagerInstance], ) const remoteBackend = React.useMemo( () => new RemoteBackend(httpClient, logger, getText), - [httpClient, logger, getText] + [httpClient, logger, getText], ) if (detect.IS_DEV_MODE) { @@ -296,7 +295,7 @@ function AppRouter(props: AppRouterProps) { if (savedInputBindings != null) { const filteredInputBindings = object.mapEntries( inputBindingsRaw.metadata, - k => savedInputBindings[k] + (k) => savedInputBindings[k], ) for (const [bindingKey, newBindings] of object.unsafeEntries(filteredInputBindings)) { for (const oldBinding of inputBindingsRaw.metadata[bindingKey].bindings) { @@ -314,11 +313,11 @@ function AppRouter(props: AppRouterProps) { localStorage.set( 'inputBindings', Object.fromEntries( - Object.entries(inputBindingsRaw.metadata).map(kv => { + Object.entries(inputBindingsRaw.metadata).map((kv) => { const [k, v] = kv return [k, v.bindings] - }) - ) + }), + ), ) } return { @@ -438,11 +437,11 @@ function AppRouter(props: AppRouterProps) { }> - ) : null + : null } > }> diff --git a/app/dashboard/src/appUtils.tsx b/app/dashboard/src/appUtils.tsx index 17a4f7260c..da93edc141 100644 --- a/app/dashboard/src/appUtils.tsx +++ b/app/dashboard/src/appUtils.tsx @@ -31,7 +31,7 @@ export const SUBSCRIBE_SUCCESS_PATH = '/subscribe/success' export const ALL_PATHS_REGEX = new RegExp( `(?:${DASHBOARD_PATH}|${LOGIN_PATH}|${REGISTRATION_PATH}|${CONFIRM_REGISTRATION_PATH}|` + `${FORGOT_PASSWORD_PATH}|${RESET_PASSWORD_PATH}|${SET_USERNAME_PATH}|${RESTORE_USER_PATH}|` + - `${SUBSCRIBE_PATH}|${SUBSCRIBE_SUCCESS_PATH})$` + `${SUBSCRIBE_PATH}|${SUBSCRIBE_SUCCESS_PATH})$`, ) // === Constants related to URLs === diff --git a/app/dashboard/src/authentication/cognito.mock.ts b/app/dashboard/src/authentication/cognito.mock.ts index 41d55779e5..9f379103c9 100644 --- a/app/dashboard/src/authentication/cognito.mock.ts +++ b/app/dashboard/src/authentication/cognito.mock.ts @@ -81,7 +81,7 @@ export class Cognito { constructor( private readonly logger: loggerProvider.Logger, private readonly supportsDeepLinks: boolean, - private readonly amplifyConfig: service.AmplifyConfig + private readonly amplifyConfig: service.AmplifyConfig, ) {} /** Save the access token to a file for further reuse. */ @@ -137,7 +137,7 @@ export class Cognito { jti: '5ab178b7-97a6-4956-8913-1cffee4a0da1', username: mockEmail, /* eslint-enable @typescript-eslint/naming-convention */ - }) + }), )}.`, }), }) @@ -269,7 +269,7 @@ export class Cognito { fetch('https://mock-cognito.com/change-password', { method: 'POST', body: JSON.stringify({ oldPassword, newPassword }), - }) + }), ) return result.mapErr(original.intoAmplifyErrorOrThrow) } else { @@ -329,7 +329,7 @@ async function signUp( _supportsDeepLinks: boolean, _username: string, _password: string, - _organizationId: string | null + _organizationId: string | null, ) { const result = await results.Result.wrapAsync(async () => { // Ignored. @@ -346,8 +346,8 @@ async function signUp( async function confirmSignUp(_email: string, _code: string) { return results.Result.wrapAsync(async () => { // Ignored. - }).then(result => - result.mapErr(original.intoAmplifyErrorOrThrow).mapErr(original.intoConfirmSignUpErrorOrThrow) + }).then((result) => + result.mapErr(original.intoAmplifyErrorOrThrow).mapErr(original.intoConfirmSignUpErrorOrThrow), ) } @@ -361,7 +361,7 @@ async function currentAuthenticatedUser() { const result = await results.Result.wrapAsync( // The methods are not needed. // eslint-disable-next-line no-restricted-syntax - async () => await Promise.resolve({} as unknown as amplify.CognitoUser) + async () => await Promise.resolve({} as unknown as amplify.CognitoUser), ) return result.mapErr(original.intoAmplifyErrorOrThrow) } diff --git a/app/dashboard/src/authentication/cognito.ts b/app/dashboard/src/authentication/cognito.ts index cbc2e2a83c..989e61dedd 100644 --- a/app/dashboard/src/authentication/cognito.ts +++ b/app/dashboard/src/authentication/cognito.ts @@ -178,7 +178,7 @@ export class Cognito { constructor( private readonly logger: loggerProvider.Logger, private readonly supportsDeepLinks: boolean, - private readonly amplifyConfig: service.AmplifyConfig + private readonly amplifyConfig: service.AmplifyConfig, ) { /** Amplify expects `Auth.configure` to be called before any other `Auth` methods are * called. By wrapping all the `Auth` methods we care about and returning an `Cognito` API @@ -201,7 +201,7 @@ export class Cognito { const amplifySession = currentSession.mapErr(intoCurrentSessionErrorType) return amplifySession - .map(session => parseUserSession(session, this.amplifyConfig.userPoolWebClientId)) + .map((session) => parseUserSession(session, this.amplifyConfig.userPoolWebClientId)) .unwrapOr(null) } @@ -296,7 +296,7 @@ export class Cognito { }) return result - .map(session => parseUserSession(session, this.amplifyConfig.userPoolWebClientId)) + .map((session) => parseUserSession(session, this.amplifyConfig.userPoolWebClientId)) .unwrapOr(null) } @@ -476,7 +476,7 @@ function intoSignUpParams( supportsDeepLinks: boolean, username: string, password: string, - organizationId: string | null + organizationId: string | null, ): amplify.SignUpParams { return { username, @@ -703,7 +703,7 @@ async function currentAuthenticatedUser() { * Therefore, it is necessary to use `as` to narrow down the type to * `Promise`. */ // eslint-disable-next-line no-restricted-syntax - () => amplify.Auth.currentAuthenticatedUser() as Promise + () => amplify.Auth.currentAuthenticatedUser() as Promise, ) return result.mapErr(intoAmplifyErrorOrThrow) } diff --git a/app/dashboard/src/authentication/listen.ts b/app/dashboard/src/authentication/listen.ts index 9c590975c9..129d332a02 100644 --- a/app/dashboard/src/authentication/listen.ts +++ b/app/dashboard/src/authentication/listen.ts @@ -56,7 +56,7 @@ export type ListenFunction = (listener: ListenerCallback) => UnsubscribeFunction /** Listen to authentication state changes. */ export function registerAuthEventListener(listener: ListenerCallback) { - return amplify.Hub.listen(AUTHENTICATION_HUB, data => { + return amplify.Hub.listen(AUTHENTICATION_HUB, (data) => { if (isAuthEvent(data.payload.event)) { listener(data.payload.event, data.payload.data) } diff --git a/app/dashboard/src/authentication/service.ts b/app/dashboard/src/authentication/service.ts index ad5d2d8dc7..20404e5a95 100644 --- a/app/dashboard/src/authentication/service.ts +++ b/app/dashboard/src/authentication/service.ts @@ -124,20 +124,20 @@ export function initAuthService(authConfig: AuthConfig): AuthService | null { const { logger, supportsDeepLinks, navigate } = authConfig const amplifyConfig = loadAmplifyConfig(logger, supportsDeepLinks, navigate) const cognito = - amplifyConfig == null - ? null - : new cognitoModule.Cognito(logger, supportsDeepLinks, amplifyConfig) + amplifyConfig == null ? null : ( + new cognitoModule.Cognito(logger, supportsDeepLinks, amplifyConfig) + ) - return cognito == null - ? null - : { cognito, registerAuthEventListener: listen.registerAuthEventListener } + return cognito == null ? null : ( + { cognito, registerAuthEventListener: listen.registerAuthEventListener } + ) } /** Return the appropriate Amplify configuration for the current platform. */ function loadAmplifyConfig( logger: loggerProvider.Logger, supportsDeepLinks: boolean, - navigate: (url: string) => void + navigate: (url: string) => void, ): AmplifyConfig | null { let urlOpener: ((url: string) => void) | null = null let saveAccessToken: ((accessToken: saveAccessTokenModule.AccessToken | null) => void) | null = @@ -175,11 +175,13 @@ function loadAmplifyConfig( /** Load the platform-specific Amplify configuration. */ const signInOutRedirect = supportsDeepLinks ? `${common.DEEP_LINK_SCHEME}://auth` : redirectUrl - return process.env.ENSO_CLOUD_COGNITO_USER_POOL_ID == null || - process.env.ENSO_CLOUD_COGNITO_USER_POOL_WEB_CLIENT_ID == null || - process.env.ENSO_CLOUD_COGNITO_DOMAIN == null || - process.env.ENSO_CLOUD_COGNITO_REGION == null - ? null + return ( + process.env.ENSO_CLOUD_COGNITO_USER_POOL_ID == null || + process.env.ENSO_CLOUD_COGNITO_USER_POOL_WEB_CLIENT_ID == null || + process.env.ENSO_CLOUD_COGNITO_DOMAIN == null || + process.env.ENSO_CLOUD_COGNITO_REGION == null + ) ? + null : { userPoolId: process.env.ENSO_CLOUD_COGNITO_USER_POOL_ID, userPoolWebClientId: process.env.ENSO_CLOUD_COGNITO_USER_POOL_WEB_CLIENT_ID, diff --git a/app/dashboard/src/components/AriaComponents/Alert/Alert.tsx b/app/dashboard/src/components/AriaComponents/Alert/Alert.tsx index f058715490..b370b93d15 100644 --- a/app/dashboard/src/components/AriaComponents/Alert/Alert.tsx +++ b/app/dashboard/src/components/AriaComponents/Alert/Alert.tsx @@ -58,7 +58,7 @@ export interface AlertProps /** Alert component. */ export const Alert = React.forwardRef(function Alert( props: AlertProps, - ref: React.ForwardedRef + ref: React.ForwardedRef, ) { const { children, className, variant, size, rounded, fullWidth, ...containerProps } = props @@ -70,7 +70,7 @@ export const Alert = React.forwardRef(function Alert( return (
{ + ref={mergeRefs.mergeRefs(ref, (e) => { if (variant === 'error') { e?.focus() } diff --git a/app/dashboard/src/components/AriaComponents/Button/Button.tsx b/app/dashboard/src/components/AriaComponents/Button/Button.tsx index 775cb40637..e6871e9d16 100644 --- a/app/dashboard/src/components/AriaComponents/Button/Button.tsx +++ b/app/dashboard/src/components/AriaComponents/Button/Button.tsx @@ -280,7 +280,7 @@ export const BUTTON_STYLES = twv.tv({ /** A button allows a user to perform an action, with mouse, touch, and keyboard interactions. */ export const Button = React.forwardRef(function Button( props: ButtonProps, - ref: React.ForwardedRef + ref: React.ForwardedRef, ) { const { className, @@ -341,17 +341,17 @@ export const Button = React.forwardRef(function Button( if (isLoading) { const loaderAnimation = loaderRef.current?.animate( [{ opacity: 0 }, { opacity: 0, offset: 1 }, { opacity: 1 }], - { duration: delay, easing: 'linear', delay: 0, fill: 'forwards' } + { duration: delay, easing: 'linear', delay: 0, fill: 'forwards' }, ) const contentAnimation = - loaderPosition !== 'full' - ? null - : contentRef.current?.animate([{ opacity: 1 }, { opacity: 0 }], { - duration: 0, - easing: 'linear', - delay, - fill: 'forwards', - }) + loaderPosition !== 'full' ? null : ( + contentRef.current?.animate([{ opacity: 1 }, { opacity: 0 }], { + duration: 0, + easing: 'linear', + delay, + fill: 'forwards', + }) + ) return () => { loaderAnimation?.cancel() @@ -399,7 +399,7 @@ export const Button = React.forwardRef(function Button( }) const childrenFactory = ( - render: aria.ButtonRenderProps | aria.LinkRenderProps + render: aria.ButtonRenderProps | aria.LinkRenderProps, ): React.ReactNode => { const iconComponent = (() => { if (icon == null) { @@ -447,12 +447,12 @@ export const Button = React.forwardRef(function Button( // onPress on EXTRA_CLICK_ZONE, but onPress{start,end} are triggered onPressEnd: handlePress, className: aria.composeRenderProps(className, (classNames, states) => - base({ className: classNames, ...states }) + base({ className: classNames, ...states }), ), })} > {/* @ts-expect-error any here is safe because we transparently pass it to the children, and ts infer the type outside correctly */} - {render => ( + {(render) => ( <> @@ -471,17 +471,15 @@ export const Button = React.forwardRef(function Button( ) - return tooltipElement == null ? ( - button - ) : ( - - {button} + return tooltipElement == null ? button : ( + + {button} - - {tooltipElement} - - - ) + + {tooltipElement} + + + ) }) diff --git a/app/dashboard/src/components/AriaComponents/Button/CloseButton.tsx b/app/dashboard/src/components/AriaComponents/Button/CloseButton.tsx index c0bd71aa56..58bb08082b 100644 --- a/app/dashboard/src/components/AriaComponents/Button/CloseButton.tsx +++ b/app/dashboard/src/components/AriaComponents/Button/CloseButton.tsx @@ -34,12 +34,12 @@ export function CloseButton(props: CloseButtonProps) { return ( + className={(values) => tailwindMerge.twMerge( 'bg-primary/30 hover:bg-red-500/80 focus-visible:bg-red-500/80 focus-visible:outline-offset-1', // eslint-disable-next-line @typescript-eslint/no-unsafe-argument // @ts-expect-error ts fails to infer the type of the className prop - typeof className === 'function' ? className(values) : className + typeof className === 'function' ? className(values) : className, ) } tooltip={tooltip} diff --git a/app/dashboard/src/components/AriaComponents/Button/CopyButton.tsx b/app/dashboard/src/components/AriaComponents/Button/CopyButton.tsx index d75b1dfcd0..49bae1b310 100644 --- a/app/dashboard/src/components/AriaComponents/Button/CopyButton.tsx +++ b/app/dashboard/src/components/AriaComponents/Button/CopyButton.tsx @@ -46,7 +46,12 @@ export function CopyButton(props: CopyButtonProps) { const successfullyCopied = copyQuery.isSuccess const isError = copyQuery.isError const showIcon = copyIcon !== false - const icon = showIcon ? (isError ? errorIcon : successfullyCopied ? successIcon : copyIcon) : null + const icon = + showIcon ? + isError ? errorIcon + : successfullyCopied ? successIcon + : copyIcon + : null return ( - >(event => { + >((event) => { dialogContext.close() return props.onPress?.(event) }) diff --git a/app/dashboard/src/components/AriaComponents/Dialog/Dialog.tsx b/app/dashboard/src/components/AriaComponents/Dialog/Dialog.tsx index 296d93c4ed..5f92372882 100644 --- a/app/dashboard/src/components/AriaComponents/Dialog/Dialog.tsx +++ b/app/dashboard/src/components/AriaComponents/Dialog/Dialog.tsx @@ -138,7 +138,7 @@ export function Dialog(props: DialogProps) { const duration = 200 // 200ms dialogRef.current?.animate( [{ transform: 'scale(1)' }, { transform: 'scale(1.015)' }, { transform: 'scale(1)' }], - { duration, iterations: 1, direction: 'alternate' } + { duration, iterations: 1, direction: 'alternate' }, ) } }, @@ -154,7 +154,7 @@ export function Dialog(props: DialogProps) { shouldCloseOnInteractOutside={() => false} {...modalProps} > - {values => { + {(values) => { overlayState.current = values.state return ( @@ -173,7 +173,7 @@ export function Dialog(props: DialogProps) { > { + ref={mergeRefs.mergeRefs(dialogRef, (element) => { if (element) { // This is a workaround for the `data-testid` attribute not being // supported by the 'react-aria-components' library. @@ -189,7 +189,7 @@ export function Dialog(props: DialogProps) { className={dialogSlots.base()} {...ariaDialogProps} > - {opts => { + {(opts) => { return (
{ + ref={(ref) => { if (ref) { handleScroll(ref.scrollTop) } }} className={dialogSlots.content()} - onScroll={event => { + onScroll={(event) => { handleScroll(event.currentTarget.scrollTop) }} > diff --git a/app/dashboard/src/components/AriaComponents/Dialog/DialogStackProvider.tsx b/app/dashboard/src/components/AriaComponents/Dialog/DialogStackProvider.tsx index 8b27615f01..60cf421bd3 100644 --- a/app/dashboard/src/components/AriaComponents/Dialog/DialogStackProvider.tsx +++ b/app/dashboard/src/components/AriaComponents/Dialog/DialogStackProvider.tsx @@ -37,11 +37,11 @@ export function DialogStackProvider(props: React.PropsWithChildren) { const [stack, setStack] = React.useState([]) const addToStack = eventCallbackHooks.useEventCallback((item: DialogStackItem) => { - setStack(currentStack => [...currentStack, item]) + setStack((currentStack) => [...currentStack, item]) }) const sliceFromStack = eventCallbackHooks.useEventCallback((currentId: string) => { - setStack(currentStack => { + setStack((currentStack) => { const lastItem = currentStack.at(-1) if (lastItem?.id === currentId) { @@ -62,11 +62,11 @@ updated properly.`) const value = React.useMemo( () => ({ stack, - dialogsStack: stack.filter(item => ['dialog-fullscreen', 'dialog'].includes(item.type)), + dialogsStack: stack.filter((item) => ['dialog-fullscreen', 'dialog'].includes(item.type)), add: addToStack, slice: sliceFromStack, }), - [stack, addToStack, sliceFromStack] + [stack, addToStack, sliceFromStack], ) return {children} @@ -118,7 +118,7 @@ export function useDialogStackState(props: UseDialogStackStateProps) { const { id } = props const isLatest = ctx.stack.at(-1)?.id === id - const index = ctx.stack.findIndex(item => item.id === id) + const index = ctx.stack.findIndex((item) => item.id === id) return { isLatest, index } } diff --git a/app/dashboard/src/components/AriaComponents/Dialog/DialogTrigger.tsx b/app/dashboard/src/components/AriaComponents/Dialog/DialogTrigger.tsx index 46fe3e89cc..6f2d91e4e1 100644 --- a/app/dashboard/src/components/AriaComponents/Dialog/DialogTrigger.tsx +++ b/app/dashboard/src/components/AriaComponents/Dialog/DialogTrigger.tsx @@ -32,7 +32,7 @@ export function DialogTrigger(props: DialogTriggerProps) { onOpenChange?.(isOpened) }, - [setModal, unsetModal, onOpenChange] + [setModal, unsetModal, onOpenChange], ) return ( diff --git a/app/dashboard/src/components/AriaComponents/Dialog/Popover.tsx b/app/dashboard/src/components/AriaComponents/Dialog/Popover.tsx index 5a0838a456..b95743eee2 100644 --- a/app/dashboard/src/components/AriaComponents/Dialog/Popover.tsx +++ b/app/dashboard/src/components/AriaComponents/Dialog/Popover.tsx @@ -90,7 +90,7 @@ export function Popover(props: PopoverProps) { return ( + className={(values) => POPOVER_STYLES({ ...values, size, @@ -104,7 +104,7 @@ export function Popover(props: PopoverProps) { shouldCloseOnInteractOutside={() => false} {...ariaPopoverProps} > - {opts => ( + {(opts) => ( | undefined = undefined, >( props: types.FormProps, - ref: React.Ref + ref: React.Ref, ) { const formId = React.useId() @@ -67,7 +67,7 @@ export const Form = React.forwardRef(function Form< shouldFocusError: true, schema, ...formOptions, - } + }, ) const dialogContext = dialog.useDialogContext() @@ -96,8 +96,9 @@ export const Form = React.forwardRef(function Form< }) } - const message = isJSError - ? getText('arbitraryFormErrorMessage') + const message = + isJSError ? + getText('arbitraryFormErrorMessage') : errorUtils.tryGetMessage(error, getText('arbitraryFormErrorMessage')) innerForm.setError('root.submit', { message }) @@ -120,14 +121,14 @@ export const Form = React.forwardRef(function Form< const { isOffline } = offlineHooks.useOffline() offlineHooks.useOfflineChange( - offline => { + (offline) => { if (offline) { innerForm.setError('root.offline', { message: getText('unavailableOffline') }) } else { innerForm.clearErrors('root.offline') } }, - { isDisabled: canSubmitOffline } + { isDisabled: canSubmitOffline }, ) const { @@ -160,10 +161,10 @@ export const Form = React.forwardRef(function Form< } } - const onChange: types.UseFormRegisterReturn['onChange'] = value => + const onChange: types.UseFormRegisterReturn['onChange'] = (value) => registered.onChange(mapValueOnEvent(value)) - const onBlur: types.UseFormRegisterReturn['onBlur'] = value => + const onBlur: types.UseFormRegisterReturn['onBlur'] = (value) => registered.onBlur(mapValueOnEvent(value)) const result: types.UseFormRegisterReturn = { @@ -198,14 +199,14 @@ export const Form = React.forwardRef(function Form< Object.entries(formState.errors).map(([key, error]) => { const message = error?.message ?? getText('arbitraryFormErrorMessage') return [key, message] - }) + }), ) as Record return (
{ + onSubmit={(event) => { event.preventDefault() event.stopPropagation() @@ -234,7 +235,7 @@ export const Form = React.forwardRef(function Form< TTransformedValues extends components.FieldValues | undefined = undefined, >( props: React.RefAttributes & - types.FormProps + types.FormProps, // eslint-disable-next-line no-restricted-syntax ) => React.JSX.Element) & { /* eslint-disable @typescript-eslint/naming-convention */ diff --git a/app/dashboard/src/components/AriaComponents/Form/components/Field.tsx b/app/dashboard/src/components/AriaComponents/Form/components/Field.tsx index 74b09e0b8c..d4e345a9b2 100644 --- a/app/dashboard/src/components/AriaComponents/Form/components/Field.tsx +++ b/app/dashboard/src/components/AriaComponents/Form/components/Field.tsx @@ -60,7 +60,7 @@ export const FIELD_STYLES = twv.tv({ */ export const Field = React.forwardRef(function Field( props: FieldComponentProps, - ref: React.ForwardedRef + ref: React.ForwardedRef, ) { const { form = formContext.useFormContext(), @@ -110,15 +110,15 @@ export const Field = React.forwardRef(function Field( )}
- {typeof children === 'function' - ? children({ - isInvalid: invalid, - isDirty: fieldState.isDirty, - isTouched: fieldState.isTouched, - isValidating: fieldState.isValidating, - error: fieldState.error?.message, - }) - : children} + {typeof children === 'function' ? + children({ + isInvalid: invalid, + isDirty: fieldState.isDirty, + isTouched: fieldState.isTouched, + isValidating: fieldState.isValidating, + error: fieldState.error?.message, + }) + : children}
diff --git a/app/dashboard/src/components/AriaComponents/Form/components/FormError.tsx b/app/dashboard/src/components/AriaComponents/Form/components/FormError.tsx index 94af52060d..afc3e19d16 100644 --- a/app/dashboard/src/components/AriaComponents/Form/components/FormError.tsx +++ b/app/dashboard/src/components/AriaComponents/Form/components/FormError.tsx @@ -63,28 +63,28 @@ export function FormError(props: FormErrorProps) { const errorMessage = getSubmitError() const submitErrorAlert = - errorMessage != null ? ( + errorMessage != null ? {errorMessage} - ) : null + : null const offlineErrorAlert = - offlineMessage != null ? ( + offlineMessage != null ? {offlineMessage} - ) : null + : null const hasSomethingToShow = submitErrorAlert || offlineErrorAlert - return hasSomethingToShow ? ( -
- {submitErrorAlert} {offlineErrorAlert} -
- ) : null + return hasSomethingToShow ? +
+ {submitErrorAlert} {offlineErrorAlert} +
+ : null } diff --git a/app/dashboard/src/components/AriaComponents/Form/components/index.ts b/app/dashboard/src/components/AriaComponents/Form/components/index.ts index 5edc9b88dd..ae7aa01ced 100644 --- a/app/dashboard/src/components/AriaComponents/Form/components/index.ts +++ b/app/dashboard/src/components/AriaComponents/Form/components/index.ts @@ -3,12 +3,12 @@ * * Barrel file for form components. */ -export * from './Submit' -export * from './Reset' -export * from './useForm' -export * from './FormError' -export * from './types' -export * from './useFormSchema' -export * from './schema' -export * from './useField' export * from './Field' +export * from './FormError' +export * from './Reset' +export * from './schema' +export * from './Submit' +export * from './types' +export * from './useField' +export * from './useForm' +export * from './useFormSchema' diff --git a/app/dashboard/src/components/AriaComponents/Form/components/types.ts b/app/dashboard/src/components/AriaComponents/Form/components/types.ts index fe13707b30..511fc8ea3f 100644 --- a/app/dashboard/src/components/AriaComponents/Form/components/types.ts +++ b/app/dashboard/src/components/AriaComponents/Form/components/types.ts @@ -15,9 +15,8 @@ import type * as schemaModule from './schema' * Field values type. */ // eslint-disable-next-line no-restricted-syntax -export type FieldValues = Schema extends z.AnyZodObject - ? z.infer - : reactHookForm.FieldValues +export type FieldValues = + Schema extends z.AnyZodObject ? z.infer : reactHookForm.FieldValues /** * Field path type. @@ -84,9 +83,9 @@ export interface FormWithValueValidation< TTransformedValues extends FieldValues | undefined = undefined, > { readonly form?: - | (BaseValueType extends TFieldValues[TFieldName] - ? FormInstance - : 'Type mismatch: Field with this name has a different type than the value of the component.') + | (BaseValueType extends TFieldValues[TFieldName] ? + FormInstance + : 'Type mismatch: Field with this name has a different type than the value of the component.') | undefined } diff --git a/app/dashboard/src/components/AriaComponents/Form/components/useForm.ts b/app/dashboard/src/components/AriaComponents/Form/components/useForm.ts index dd487261f3..f22e40e376 100644 --- a/app/dashboard/src/components/AriaComponents/Form/components/useForm.ts +++ b/app/dashboard/src/components/AriaComponents/Form/components/useForm.ts @@ -34,7 +34,7 @@ export function useForm< >( optionsOrFormInstance: | types.UseFormProps - | types.UseFormReturn + | types.UseFormReturn, ): types.UseFormReturn { const initialTypePassed = React.useRef(getArgsType(optionsOrFormInstance)) @@ -45,7 +45,7 @@ export function useForm< ` Found a switch between form options and form instance. This is not allowed. Please use either form options or form instance and stick to it.\n\n Initially passed: ${initialTypePassed.current}, Currently passed: ${argsType}. - ` + `, ) if ('formState' in optionsOrFormInstance) { @@ -74,7 +74,7 @@ function getArgsType< >( args: | types.UseFormProps - | types.UseFormReturn + | types.UseFormReturn, ) { return 'formState' in args ? 'formInstance' : 'formOptions' } diff --git a/app/dashboard/src/components/AriaComponents/Form/components/useFormSchema.tsx b/app/dashboard/src/components/AriaComponents/Form/components/useFormSchema.tsx index 01c39662fd..ef5f2b47b6 100644 --- a/app/dashboard/src/components/AriaComponents/Form/components/useFormSchema.tsx +++ b/app/dashboard/src/components/AriaComponents/Form/components/useFormSchema.tsx @@ -12,7 +12,7 @@ import type * as types from '#/components/AriaComponents/Form/components/types' /** A hook to create a form schema. */ export function useFormSchema>( - callback: (schema: typeof schemaComponent.schema) => schemaComponent.schema.ZodObject + callback: (schema: typeof schemaComponent.schema) => schemaComponent.schema.ZodObject, ) { const callbackEvent = callbackEventHooks.useEventCallback(callback) diff --git a/app/dashboard/src/components/AriaComponents/Form/types.ts b/app/dashboard/src/components/AriaComponents/Form/types.ts index 0420d1e022..00d79f59d3 100644 --- a/app/dashboard/src/components/AriaComponents/Form/types.ts +++ b/app/dashboard/src/components/AriaComponents/Form/types.ts @@ -50,12 +50,12 @@ interface BaseFormProps< readonly defaultValues?: components.UseFormProps['defaultValues'] readonly onSubmit?: ( values: TFieldValues, - form: components.UseFormReturn + form: components.UseFormReturn, ) => unknown readonly style?: | React.CSSProperties | (( - props: FormStateRenderProps + props: FormStateRenderProps, ) => React.CSSProperties) readonly children: | React.ReactNode @@ -123,7 +123,7 @@ export type UseFormRegister< >, >( name: TFieldName, - options?: reactHookForm.RegisterOptions + options?: reactHookForm.RegisterOptions, // eslint-disable-next-line no-restricted-syntax ) => UseFormRegisterReturn diff --git a/app/dashboard/src/components/AriaComponents/Inputs/ResizableInput/ResizableContentEditableInput.tsx b/app/dashboard/src/components/AriaComponents/Inputs/ResizableInput/ResizableContentEditableInput.tsx index 9b39eefecc..7f451d9e39 100644 --- a/app/dashboard/src/components/AriaComponents/Inputs/ResizableInput/ResizableContentEditableInput.tsx +++ b/app/dashboard/src/components/AriaComponents/Inputs/ResizableInput/ResizableContentEditableInput.tsx @@ -62,7 +62,7 @@ export const ResizableContentEditableInput = React.forwardRef( TTransformedValues extends ariaComponents.FieldValues | undefined = undefined, >( props: ResizableContentEditableInputProps, - ref: React.ForwardedRef + ref: React.ForwardedRef, ) { const { placeholder = '', @@ -87,7 +87,7 @@ export const ResizableContentEditableInput = React.forwardRef( .replace(//g, '>') document.execCommand('insertHTML', false, text) - } + }, ) const { field, fieldState, formInstance } = ariaComponents.Form.useField({ @@ -126,7 +126,7 @@ export const ResizableContentEditableInput = React.forwardRef( aria-autocomplete="none" onPaste={onPaste} onBlur={field.onBlur} - onInput={event => { + onInput={(event) => { field.onChange(event.currentTarget.textContent ?? '') }} /> @@ -146,7 +146,7 @@ export const ResizableContentEditableInput = React.forwardRef(
) - } + }, ) as < Schema extends ariaComponents.TSchema, TFieldName extends ariaComponents.FieldPath, @@ -155,5 +155,5 @@ export const ResizableContentEditableInput = React.forwardRef( TTransformedValues extends ariaComponents.FieldValues | undefined = undefined, >( props: React.RefAttributes & - ResizableContentEditableInputProps + ResizableContentEditableInputProps, ) => React.JSX.Element diff --git a/app/dashboard/src/components/AriaComponents/Inputs/ResizableInput/ResizableInput.tsx b/app/dashboard/src/components/AriaComponents/Inputs/ResizableInput/ResizableInput.tsx index fc9cd8dfcd..e58fced4fa 100644 --- a/app/dashboard/src/components/AriaComponents/Inputs/ResizableInput/ResizableInput.tsx +++ b/app/dashboard/src/components/AriaComponents/Inputs/ResizableInput/ResizableInput.tsx @@ -24,7 +24,7 @@ export interface ResizableInputProps extends aria.TextFieldProps { */ export const ResizableInput = React.forwardRef(function ResizableInput( props: ResizableInputProps, - ref: React.ForwardedRef + ref: React.ForwardedRef, ) { const { value = '', placeholder = '', description = null, ...textFieldProps } = props const inputRef = React.useRef(null) @@ -36,7 +36,7 @@ export const ResizableInput = React.forwardRef(function ResizableInput( event.preventDefault() const text = event.clipboardData.getData('text/plain') document.execCommand('insertHTML', false, text) - } + }, ) React.useLayoutEffect(() => { @@ -57,7 +57,7 @@ export const ResizableInput = React.forwardRef(function ResizableInput(
{ + onClick={(event) => { if (event.target !== inputRef.current && inputRef.current) { inputRef.current.focus({ preventScroll: true }) } diff --git a/app/dashboard/src/components/AriaComponents/Inputs/ResizableInput/index.ts b/app/dashboard/src/components/AriaComponents/Inputs/ResizableInput/index.ts index c47c71e473..a802db581e 100644 --- a/app/dashboard/src/components/AriaComponents/Inputs/ResizableInput/index.ts +++ b/app/dashboard/src/components/AriaComponents/Inputs/ResizableInput/index.ts @@ -3,5 +3,5 @@ * * Barrel export file for ResizableInput component. */ -export * from './ResizableInput' export * from './ResizableContentEditableInput' +export * from './ResizableInput' diff --git a/app/dashboard/src/components/AriaComponents/Radio/Radio.tsx b/app/dashboard/src/components/AriaComponents/Radio/Radio.tsx index dac79e3161..58fc79d07d 100644 --- a/app/dashboard/src/components/AriaComponents/Radio/Radio.tsx +++ b/app/dashboard/src/components/AriaComponents/Radio/Radio.tsx @@ -58,7 +58,7 @@ export interface RadioProps extends aria.RadioProps { // eslint-disable-next-line no-restricted-syntax export const Radio = React.forwardRef(function Radio( props: RadioProps, - ref: React.ForwardedRef + ref: React.ForwardedRef, ) { const { children, label, className, ...ariaProps } = props @@ -77,7 +77,7 @@ export const Radio = React.forwardRef(function Radio( children: label ?? (typeof children === 'function' ? true : children), }), state, - inputRef + inputRef, ) const { isFocused, isFocusVisible, focusProps } = aria.useFocusRing() @@ -149,7 +149,7 @@ export const Radio = React.forwardRef(function Radio( ) }) as unknown as (( - props: RadioProps & React.RefAttributes + props: RadioProps & React.RefAttributes, // eslint-disable-next-line no-restricted-syntax ) => React.JSX.Element) & { // eslint-disable-next-line @typescript-eslint/naming-convention diff --git a/app/dashboard/src/components/AriaComponents/Radio/RadioGroup.tsx b/app/dashboard/src/components/AriaComponents/Radio/RadioGroup.tsx index e04d57931e..092e8d33bf 100644 --- a/app/dashboard/src/components/AriaComponents/Radio/RadioGroup.tsx +++ b/app/dashboard/src/components/AriaComponents/Radio/RadioGroup.tsx @@ -50,7 +50,7 @@ export const RadioGroup = React.forwardRef(function RadioGroup< TTransformedValues extends formComponent.FieldValues | undefined = undefined, >( props: RadioGroupProps, - ref: React.ForwardedRef + ref: React.ForwardedRef, ) { const { children, @@ -117,5 +117,5 @@ export const RadioGroup = React.forwardRef(function RadioGroup< TTransformedValues extends formComponent.FieldValues | undefined = undefined, >( props: RadioGroupProps & - React.RefAttributes + React.RefAttributes, ) => React.JSX.Element diff --git a/app/dashboard/src/components/AriaComponents/Radio/RadioGroupContext.tsx b/app/dashboard/src/components/AriaComponents/Radio/RadioGroupContext.tsx index df6df6d034..dff78a6312 100644 --- a/app/dashboard/src/components/AriaComponents/Radio/RadioGroupContext.tsx +++ b/app/dashboard/src/components/AriaComponents/Radio/RadioGroupContext.tsx @@ -62,7 +62,7 @@ export function RadioGroupProvider(props: React.PropsWithChildren) { setPressedRadio: setRadioPressed, clearPressedRadio, }), - [pressedRadio, setRadioPressed, clearPressedRadio] + [pressedRadio, setRadioPressed, clearPressedRadio], ) return {children} diff --git a/app/dashboard/src/components/AriaComponents/Text/Text.tsx b/app/dashboard/src/components/AriaComponents/Text/Text.tsx index 32b2dcd29b..98da6d691d 100644 --- a/app/dashboard/src/components/AriaComponents/Text/Text.tsx +++ b/app/dashboard/src/components/AriaComponents/Text/Text.tsx @@ -114,7 +114,7 @@ export const TEXT_STYLE = twv.tv({ // eslint-disable-next-line no-restricted-syntax export const Text = React.forwardRef(function Text( props: TextProps, - ref: React.Ref + ref: React.Ref, ) { const { className, @@ -184,10 +184,10 @@ export const Text = React.forwardRef(function Text( {...aria.mergeProps>()( ariaProps, targetProps, - truncate === 'custom' - ? // eslint-disable-next-line @typescript-eslint/naming-convention,no-restricted-syntax - ({ style: { '--line-clamp': `${lineClamp}` } } as React.HTMLAttributes) - : {} + truncate === 'custom' ? + // eslint-disable-next-line @typescript-eslint/naming-convention,no-restricted-syntax + ({ style: { '--line-clamp': `${lineClamp}` } } as React.HTMLAttributes) + : {}, )} > {children} @@ -215,7 +215,7 @@ export interface HeadingProps extends Omit { */ Text.Heading = React.forwardRef(function Heading( props: HeadingProps, - ref: React.Ref + ref: React.Ref, ) { const { level = 1, ...textProps } = props return diff --git a/app/dashboard/src/components/AriaComponents/Text/useVisualTooltip.tsx b/app/dashboard/src/components/AriaComponents/Text/useVisualTooltip.tsx index 20df4a45dd..6ab897a222 100644 --- a/app/dashboard/src/components/AriaComponents/Text/useVisualTooltip.tsx +++ b/app/dashboard/src/components/AriaComponents/Text/useVisualTooltip.tsx @@ -82,8 +82,8 @@ export function useVisualTooltip(props: VisualTooltipProps) { const handleHoverChange = eventCallback.useEventCallback((isHovered: boolean) => { const shouldDisplay = () => { if (isHovered && targetRef.current != null) { - return typeof display === 'function' - ? display(targetRef.current) + return typeof display === 'function' ? + display(targetRef.current) : DISPLAY_STRATEGIES[display](targetRef.current) } else { return false @@ -143,7 +143,7 @@ export function useVisualTooltip(props: VisualTooltipProps) { // Remove z-index from the overlay style // because it's not needed(we show latest element on top) and can cause issues with stacking context style: { zIndex: '' }, - } + }, )} > {children} @@ -159,6 +159,6 @@ export function useVisualTooltip(props: VisualTooltipProps) { const DISPLAY_STRATEGIES: Record boolean> = { always: () => true, - whenOverflowing: target => + whenOverflowing: (target) => target.scrollWidth > target.clientWidth || target.scrollHeight > target.clientHeight, } diff --git a/app/dashboard/src/components/AriaComponents/Tooltip/Tooltip.tsx b/app/dashboard/src/components/AriaComponents/Tooltip/Tooltip.tsx index 47fdf701d6..54b2d8d65e 100644 --- a/app/dashboard/src/components/AriaComponents/Tooltip/Tooltip.tsx +++ b/app/dashboard/src/components/AriaComponents/Tooltip/Tooltip.tsx @@ -79,7 +79,7 @@ export function Tooltip(props: TooltipProps) { containerPadding={containerPadding} UNSTABLE_portalContainer={root} className={aria.composeRenderProps(className, (classNames, values) => - TOOLTIP_STYLES({ className: classNames, ...values }) + TOOLTIP_STYLES({ className: classNames, ...values }), )} data-ignore-click-outside {...ariaTooltipProps} diff --git a/app/dashboard/src/components/AriaComponents/VisuallyHidden.tsx b/app/dashboard/src/components/AriaComponents/VisuallyHidden.tsx index 9af0c0e28d..a646f7cfec 100644 --- a/app/dashboard/src/components/AriaComponents/VisuallyHidden.tsx +++ b/app/dashboard/src/components/AriaComponents/VisuallyHidden.tsx @@ -21,5 +21,5 @@ export const VisuallyHidden = React.forwardRef - } + }, ) diff --git a/app/dashboard/src/components/AriaComponents/index.ts b/app/dashboard/src/components/AriaComponents/index.ts index dc786bbd15..eae16324c1 100644 --- a/app/dashboard/src/components/AriaComponents/index.ts +++ b/app/dashboard/src/components/AriaComponents/index.ts @@ -2,14 +2,14 @@ * @file index.ts * Index file for Aria Components */ -export * from './Button' -export * from './Tooltip' -export * from './Dialog' export * from './Alert' +export * from './Button' export * from './CopyBlock' -export * from './Inputs' +export * from './Dialog' export * from './Form' -export * from './Text' -export * from './Separator' -export * from './VisuallyHidden' +export * from './Inputs' export * from './Radio' +export * from './Separator' +export * from './Text' +export * from './Tooltip' +export * from './VisuallyHidden' diff --git a/app/dashboard/src/components/Autocomplete.tsx b/app/dashboard/src/components/Autocomplete.tsx index e751cd3324..09c0e0fd48 100644 --- a/app/dashboard/src/components/Autocomplete.tsx +++ b/app/dashboard/src/components/Autocomplete.tsx @@ -85,8 +85,8 @@ export default function Autocomplete(props: AutocompleteProps) { const canEditTextRef = React.useRef(canEditText) const isMultipleAndCustomValue = multiple === true && text != null const matchingItems = React.useMemo( - () => (text == null ? items : items.filter(item => matches(item, text))), - [items, matches, text] + () => (text == null ? items : items.filter((item) => matches(item, text))), + [items, matches, text], ) React.useEffect(() => { @@ -124,11 +124,11 @@ export default function Autocomplete(props: AutocompleteProps) { const toggleValue = (value: T) => { overrideValues( - multiple === true && !isMultipleAndCustomValue - ? valuesSet.has(value) - ? values.filter(theItem => theItem !== value) - : [...values, value] - : [value] + multiple === true && !isMultipleAndCustomValue ? + valuesSet.has(value) ? + values.filter((theItem) => theItem !== value) + : [...values, value] + : [value], ) } @@ -184,7 +184,7 @@ export default function Autocomplete(props: AutocompleteProps) {
- {canEditText ? ( + {canEditText ? (props: AutocompleteProps) { setIsDropdownVisible(false) }) }} - onChange={event => { + onChange={(event) => { setIsDropdownVisible(true) setText(event.currentTarget.value === '' ? null : event.currentTarget.value) }} /> - ) : ( -
element?.focus()} + :
element?.focus()} tabIndex={-1} className="text grow cursor-pointer whitespace-nowrap bg-transparent px-button-x" onClick={() => { @@ -223,7 +222,7 @@ export default function Autocomplete(props: AutocompleteProps) { > {itemsToString?.(values) ?? (values[0] != null ? itemToString(values[0]) : ZWSP)}
- )} + }
@@ -232,13 +231,13 @@ export default function Autocomplete(props: AutocompleteProps) { 'relative top-2 z-1 h-max w-full rounded-default shadow-soft before:absolute before:top before:h-full before:w-full before:rounded-default before:bg-frame before:backdrop-blur-default', isDropdownVisible && matchingItems.length !== 0 && - 'before:border before:border-primary/10' + 'before:border before:border-primary/10', )} >
{/* FIXME: "Invite" modal does not take into account the height of the autocomplete, @@ -249,12 +248,12 @@ export default function Autocomplete(props: AutocompleteProps) { className={tailwindMerge.twMerge( 'text relative cursor-pointer whitespace-nowrap px-input-x first:rounded-t-default last:rounded-b-default hover:bg-hover-bg', valuesSet.has(item) && 'bg-hover-bg', - index === selectedIndex && 'bg-black/5' + index === selectedIndex && 'bg-black/5', )} - onMouseDown={event => { + onMouseDown={(event) => { event.preventDefault() }} - onClick={event => { + onClick={(event) => { event.stopPropagation() toggleValue(item) }} diff --git a/app/dashboard/src/components/ColorPicker.tsx b/app/dashboard/src/components/ColorPicker.tsx index edfe621dd0..a5d47b435a 100644 --- a/app/dashboard/src/components/ColorPicker.tsx +++ b/app/dashboard/src/components/ColorPicker.tsx @@ -30,7 +30,7 @@ function ColorPickerItem(props: InternalColorPickerItemProps) { return ( { + ref={(element) => { element?.querySelector('input')?.classList.add(focusChildClass) }} value={cssColor} @@ -63,7 +63,7 @@ function ColorPicker(props: ColorPickerProps, ref: React.ForwardedRef { + onChange={(value) => { const color = backend.COLOR_STRING_TO_COLOR.get(value) if (color != null) { setColor(color) diff --git a/app/dashboard/src/components/ContextMenu.tsx b/app/dashboard/src/components/ContextMenu.tsx index 3c392aba9c..7cacf6804c 100644 --- a/app/dashboard/src/components/ContextMenu.tsx +++ b/app/dashboard/src/components/ContextMenu.tsx @@ -22,26 +22,24 @@ export interface ContextMenuProps extends Readonly { export default function ContextMenu(props: ContextMenuProps) { const { hidden = false, children } = props - return hidden ? ( - children - ) : ( - - {innerProps => ( -
+ return hidden ? children : ( + + {(innerProps) => (
- {children} +
+ {children} +
-
- )} -
- ) + )} + + ) } diff --git a/app/dashboard/src/components/ContextMenus.tsx b/app/dashboard/src/components/ContextMenus.tsx index 6b6a2be8f1..bbe8a7dd7c 100644 --- a/app/dashboard/src/components/ContextMenus.tsx +++ b/app/dashboard/src/components/ContextMenus.tsx @@ -32,30 +32,28 @@ export interface ContextMenusProps extends Readonly { function ContextMenus(props: ContextMenusProps, ref: React.ForwardedRef) { const { hidden = false, children, event } = props - return hidden ? ( - <>{children} - ) : ( - { - innerEvent.preventDefault() - }} - > -
{ - clickEvent.stopPropagation() + return hidden ? + <>{children} + : { + innerEvent.preventDefault() }} > - {children} -
-
- ) +
{ + clickEvent.stopPropagation() + }} + > + {children} +
+ } export default React.forwardRef(ContextMenus) diff --git a/app/dashboard/src/components/ControlledInput.tsx b/app/dashboard/src/components/ControlledInput.tsx index b9f76d1490..443da0ec30 100644 --- a/app/dashboard/src/components/ControlledInput.tsx +++ b/app/dashboard/src/components/ControlledInput.tsx @@ -49,12 +49,12 @@ export default function ControlledInput(props: ControlledInputProps) { {...aria.mergeProps()(inputProps, focusChildProps, { className: 'w-full rounded-full border py-auth-input-y pl-auth-icon-container-w pr-auth-input-r text-sm placeholder-gray-500 transition-all duration-auth hover:bg-gray-100 focus:bg-gray-100', - onKeyDown: event => { + onKeyDown: (event) => { if (!event.isPropagationStopped()) { onKeyDown?.(event) } }, - onChange: event => { + onChange: (event) => { onChange?.(event) setValue(event.target.value) setWasJustBlurred(false) @@ -66,9 +66,9 @@ export default function ControlledInput(props: ControlledInputProps) { if (error != null) { currentTarget.setCustomValidity('') currentTarget.setCustomValidity( - currentTarget.checkValidity() || shouldReportValidityRef?.current === false - ? '' - : error + currentTarget.checkValidity() || shouldReportValidityRef?.current === false ? + '' + : error, ) } if (hasReportedValidity) { @@ -84,13 +84,14 @@ export default function ControlledInput(props: ControlledInputProps) { ) { setHasReportedValidity(true) } - }, DEBOUNCE_MS) + }, DEBOUNCE_MS), ) } } }, - onBlur: validate - ? event => { + onBlur: + validate ? + (event) => { onBlur?.(event) if (wasJustBlurred) { setHasReportedValidity(false) diff --git a/app/dashboard/src/components/DateInput.tsx b/app/dashboard/src/components/DateInput.tsx index 602d23f322..89ca4821c4 100644 --- a/app/dashboard/src/components/DateInput.tsx +++ b/app/dashboard/src/components/DateInput.tsx @@ -2,8 +2,8 @@ import * as React from 'react' import CrossIcon from '#/assets/cross.svg' -import FolderArrowDoubleIcon from '#/assets/folder_arrow_double.svg' import FolderArrowIcon from '#/assets/folder_arrow.svg' +import FolderArrowDoubleIcon from '#/assets/folder_arrow_double.svg' import * as focusHooks from '#/hooks/focusHooks' @@ -97,7 +97,7 @@ export default function DateInput(props: DateInputProps) { return (
{ + onClick={(event) => { event.stopPropagation() }} > @@ -108,13 +108,13 @@ export default function DateInput(props: DateInputProps) { tabIndex: 0, className: tailwindMerge.twMerge( 'flex h-text w-date-picker items-center rounded-full border border-primary/10 px-date-input transition-colors hover:[&:not(:has(button:hover))]:bg-hover-bg', - date == null && 'placeholder' + date == null && 'placeholder', ), - onClick: event => { + onClick: (event) => { event.stopPropagation() setIsPickerVisible(!isPickerVisible) }, - onKeyDown: event => { + onKeyDown: (event) => { if (event.key === 'Enter' || event.key === 'Space') { event.stopPropagation() setIsPickerVisible(!isPickerVisible) @@ -223,7 +223,7 @@ export default function DateInput(props: DateInputProps) { const currentDate = new Date( selectedYear, selectedMonthIndex + day.monthOffset, - day.date + day.date, ) const isSelectedDate = date != null && @@ -238,7 +238,7 @@ export default function DateInput(props: DateInputProps) { isDisabled={isSelectedDate} className={tailwindMerge.twMerge( 'w-full rounded-small-rectangle-button text-center hover:bg-primary/10 disabled:bg-frame disabled:font-bold', - day.monthOffset !== 0 && 'opacity-unimportant' + day.monthOffset !== 0 && 'opacity-unimportant', )} onPress={() => { setIsPickerVisible(false) diff --git a/app/dashboard/src/components/Devtools/EnsoDevtools.tsx b/app/dashboard/src/components/Devtools/EnsoDevtools.tsx index c96953da7b..629eb8ede6 100644 --- a/app/dashboard/src/components/Devtools/EnsoDevtools.tsx +++ b/app/dashboard/src/components/Devtools/EnsoDevtools.tsx @@ -80,9 +80,9 @@ export function EnsoDevtools(props: EnsoDevtoolsProps) { const onConfigurationChange = React.useCallback( (feature: billing.PaywallFeatureName, configuration: PaywallDevtoolsFeatureConfiguration) => { - setFeatures(prev => ({ ...prev, [feature]: configuration })) + setFeatures((prev) => ({ ...prev, [feature]: configuration })) }, - [] + [], ) return ( @@ -114,7 +114,7 @@ export function EnsoDevtools(props: EnsoDevtoolsProps) { schema.object({ plan: schema.string() })} + schema={(schema) => schema.object({ plan: schema.string() })} defaultValues={{ plan: session.user.plan ?? 'free' }} > {({ form }) => ( @@ -122,7 +122,7 @@ export function EnsoDevtools(props: EnsoDevtoolsProps) { { + onChange={(value) => { queryClient.setQueryData(authQueryKey, { ...session, user: { ...session.user, plan: value }, @@ -193,7 +193,7 @@ export function EnsoDevtools(props: EnsoDevtoolsProps) { { + onChange={(value) => { onConfigurationChange(featureName, { isForceEnabled: value, }) diff --git a/app/dashboard/src/components/Devtools/ReactQueryDevtools.tsx b/app/dashboard/src/components/Devtools/ReactQueryDevtools.tsx index 4deda5c769..5d68112385 100644 --- a/app/dashboard/src/components/Devtools/ReactQueryDevtools.tsx +++ b/app/dashboard/src/components/Devtools/ReactQueryDevtools.tsx @@ -8,9 +8,9 @@ import * as reactQueryDevtools from '@tanstack/react-query-devtools' import * as errorBoundary from 'react-error-boundary' const ReactQueryDevtoolsProduction = React.lazy(() => - import('@tanstack/react-query-devtools/build/modern/production.js').then(d => ({ + import('@tanstack/react-query-devtools/build/modern/production.js').then((d) => ({ default: d.ReactQueryDevtools, - })) + })), ) /** Show the React Query Devtools and provide the ability to show them in production. */ @@ -24,7 +24,7 @@ export function ReactQueryDevtools() { React.useEffect(() => { window.toggleDevtools = () => { - setShowDevtools(old => !old) + setShowDevtools((old) => !old) } }, []) diff --git a/app/dashboard/src/components/Dropdown.tsx b/app/dashboard/src/components/Dropdown.tsx index aa559b37dd..9bca48f7dc 100644 --- a/app/dashboard/src/components/Dropdown.tsx +++ b/app/dashboard/src/components/Dropdown.tsx @@ -63,7 +63,7 @@ function Dropdown(props: DropdownProps, ref: React.ForwardedRef { + const selectedItems = selectedIndices.flatMap((index) => { const item = items[index] return item != null ? [item] : [] }) @@ -109,15 +109,16 @@ function Dropdown(props: DropdownProps, ref: React.ForwardedRef index !== tempSelectedIndex) + const newIndices = + selectedIndices.includes(tempSelectedIndex) ? + selectedIndices.filter((index) => index !== tempSelectedIndex) : [...selectedIndices, tempSelectedIndex] props.onClick( - newIndices.flatMap(index => { + newIndices.flatMap((index) => { const otherItem = items[index] return otherItem != null ? [otherItem] : [] }), - newIndices + newIndices, ) } else { props.onClick(item, tempSelectedIndex) @@ -134,11 +135,13 @@ function Dropdown(props: DropdownProps, ref: React.ForwardedRef= items.length - ? items.length - 1 - : tempSelectedIndex - 1 + ( + tempSelectedIndex == null || + tempSelectedIndex === 0 || + tempSelectedIndex >= items.length + ) ? + items.length - 1 + : tempSelectedIndex - 1, ) break } @@ -146,9 +149,9 @@ function Dropdown(props: DropdownProps, ref: React.ForwardedRef= items.length - 1 - ? 0 - : tempSelectedIndex + 1 + tempSelectedIndex == null || tempSelectedIndex >= items.length - 1 ? + 0 + : tempSelectedIndex + 1, ) break } @@ -159,7 +162,7 @@ function Dropdown(props: DropdownProps, ref: React.ForwardedRef
{ + ref={(element) => { if (typeof ref === 'function') { ref(element) } else if (ref != null) { @@ -170,16 +173,16 @@ function Dropdown(props: DropdownProps, ref: React.ForwardedRef { + onFocus={(event) => { if (!justBlurredRef.current && !readOnly && event.target === event.currentTarget) { setIsDropdownVisible(true) justFocusedRef.current = true } justBlurredRef.current = false }} - onBlur={event => { + onBlur={(event) => { if (!readOnly && event.target === event.currentTarget) { setIsDropdownVisible(false) justBlurredRef.current = true @@ -189,28 +192,28 @@ function Dropdown(props: DropdownProps, ref: React.ForwardedRef { justFocusedRef.current = false }} - onClick={event => { + onClick={(event) => { event.stopPropagation() }} >
{/* Spacing. */}
{ + onClick={(event) => { event.stopPropagation() if (!justFocusedRef.current && !readOnly) { setIsDropdownVisible(!isDropdownVisible) @@ -221,7 +224,7 @@ function Dropdown(props: DropdownProps, ref: React.ForwardedRef
@@ -231,12 +234,12 @@ function Dropdown(props: DropdownProps, ref: React.ForwardedRef { + onMouseDown={(event) => { event.preventDefault() isMouseDown.current = true }} @@ -246,15 +249,16 @@ function Dropdown(props: DropdownProps, ref: React.ForwardedRef { if (i !== visuallySelectedIndex) { if (multiple) { - const newIndices = selectedIndices.includes(i) - ? selectedIndices.filter(index => index !== i) + const newIndices = + selectedIndices.includes(i) ? + selectedIndices.filter((index) => index !== i) : [...selectedIndices, i] props.onClick( - newIndices.flatMap(index => { + newIndices.flatMap((index) => { const otherItem = items[index] return otherItem != null ? [otherItem] : [] }), - newIndices + newIndices, ) rootRef.current?.focus() } else { @@ -290,9 +294,9 @@ function Dropdown(props: DropdownProps, ref: React.ForwardedRef { + onClick={(event) => { event.stopPropagation() if (!justFocusedRef.current && !readOnly) { setIsDropdownVisible(!isDropdownVisible) @@ -302,11 +306,9 @@ function Dropdown(props: DropdownProps, ref: React.ForwardedRef
- {visuallySelectedItem != null ? ( + {visuallySelectedItem != null ? - ) : ( - multiple && - )} + : multiple && }
{/* Hidden, but required to exist for the width of the parent element to be correct. @@ -328,5 +330,5 @@ function Dropdown(props: DropdownProps, ref: React.ForwardedRef( - props: DropdownProps & React.RefAttributes + props: DropdownProps & React.RefAttributes, ) => React.JSX.Element diff --git a/app/dashboard/src/components/EditableSpan.tsx b/app/dashboard/src/components/EditableSpan.tsx index ef8c2ef32e..efb7e0d22d 100644 --- a/app/dashboard/src/components/EditableSpan.tsx +++ b/app/dashboard/src/components/EditableSpan.tsx @@ -82,7 +82,7 @@ export default function EditableSpan(props: EditableSpanProps) { return ( { + onBlur={(event) => { const currentTarget = event.currentTarget if (!currentTarget.contains(event.relatedTarget)) { // This must run AFTER the cancel button's event handler runs. @@ -93,7 +93,7 @@ export default function EditableSpan(props: EditableSpanProps) { }) } }} - onSubmit={event => { + onSubmit={(event) => { event.preventDefault() if (inputRef.current != null) { if (isSubmittable) { @@ -107,7 +107,7 @@ export default function EditableSpan(props: EditableSpanProps) { { + ref={(element) => { inputRef.current = element if (element) { element.style.width = '0' @@ -118,10 +118,10 @@ export default function EditableSpan(props: EditableSpanProps) { type="text" size={1} defaultValue={children} - onContextMenu={event => { + onContextMenu={(event) => { event.stopPropagation() }} - onKeyDown={event => { + onKeyDown={(event) => { if (event.key !== 'Escape') { event.stopPropagation() } @@ -132,13 +132,13 @@ export default function EditableSpan(props: EditableSpanProps) { }} {...(inputPattern == null ? {} : { pattern: inputPattern })} {...(inputTitle == null ? {} : { title: inputTitle })} - {...(checkSubmittable == null - ? {} - : { - onInput: event => { - setIsSubmittable(checkSubmittable(event.currentTarget.value)) - }, - })} + {...(checkSubmittable == null ? + {} + : { + onInput: (event) => { + setIsSubmittable(checkSubmittable(event.currentTarget.value)) + }, + })} /> {isSubmittable && ( diff --git a/app/dashboard/src/components/ErrorBoundary.tsx b/app/dashboard/src/components/ErrorBoundary.tsx index 33a94aadaa..c2407deee1 100644 --- a/app/dashboard/src/components/ErrorBoundary.tsx +++ b/app/dashboard/src/components/ErrorBoundary.tsx @@ -44,7 +44,7 @@ export function ErrorBoundary(props: ErrorBoundaryProps) { sentry.captureException(error, { extra: { info } }) onError(error, info) }} - onReset={details => { + onReset={(details) => { reset() onReset(details) }} diff --git a/app/dashboard/src/components/Input.tsx b/app/dashboard/src/components/Input.tsx index cc382baf7f..1e9d9c781e 100644 --- a/app/dashboard/src/components/Input.tsx +++ b/app/dashboard/src/components/Input.tsx @@ -1,8 +1,8 @@ /** @file A styled input that includes an icon. */ import * as React from 'react' -import EyeCrossedIcon from '#/assets/eye_crossed.svg' import EyeIcon from '#/assets/eye.svg' +import EyeCrossedIcon from '#/assets/eye_crossed.svg' import type * as controlledInput from '#/components/ControlledInput' import ControlledInput from '#/components/ControlledInput' @@ -32,7 +32,7 @@ export default function Input(props: InputProps) { src={isShowingPassword ? EyeIcon : EyeCrossedIcon} className="left-[unset] right-0 cursor-pointer rounded-full" onClick={() => { - setIsShowingPassword(show => !show) + setIsShowingPassword((show) => !show) }} /> )} diff --git a/app/dashboard/src/components/JSONSchemaInput.tsx b/app/dashboard/src/components/JSONSchemaInput.tsx index 36f77977f1..4381f9e961 100644 --- a/app/dashboard/src/components/JSONSchemaInput.tsx +++ b/app/dashboard/src/components/JSONSchemaInput.tsx @@ -41,7 +41,7 @@ export default function JSONSchemaInput(props: JSONSchemaInputProps) { const remoteBackend = backendProvider.useRemoteBackend() const { getText } = textProvider.useText() const [autocompleteText, setAutocompleteText] = React.useState(() => - typeof value === 'string' ? value : null + typeof value === 'string' ? value : null, ) const [selectedChildIndex, setSelectedChildIndex] = React.useState(null) const [autocompleteItems, setAutocompleteItems] = React.useState(null) @@ -61,35 +61,35 @@ export default function JSONSchemaInput(props: JSONSchemaInputProps) { setAutocompleteItems([]) void (async () => { const secrets = (await remoteBackend?.listSecrets()) ?? [] - setAutocompleteItems(secrets.map(secret => secret.path)) + setAutocompleteItems(secrets.map((secret) => secret.path)) })() } children.push(
item} - itemToString={item => item} + itemToKey={(item) => item} + itemToString={(item) => item} placeholder={getText('enterSecretPath')} matches={(item, text) => item.toLowerCase().includes(text.toLowerCase())} values={isValid ? [value] : []} - setValues={values => { + setValues={(values) => { setValue(values[0]) }} text={autocompleteText} setText={setAutocompleteText} /> -
+
, ) } else { children.push( - {innerProps => ( + {(innerProps) => ( { + onChange={(event) => { const newValue: string = event.currentTarget.value setValue(newValue) }} @@ -109,7 +109,7 @@ export default function JSONSchemaInput(props: JSONSchemaInputProps) { /> )} - + , ) } break @@ -117,7 +117,7 @@ export default function JSONSchemaInput(props: JSONSchemaInputProps) { case 'number': { children.push( - {innerProps => ( + {(innerProps) => ( { + onChange={(event) => { const newValue: number = event.currentTarget.valueAsNumber if (Number.isFinite(newValue)) { setValue(newValue) @@ -139,14 +139,14 @@ export default function JSONSchemaInput(props: JSONSchemaInputProps) { /> )} - + , ) break } case 'integer': { children.push( - {innerProps => ( + {(innerProps) => ( { + onChange={(event) => { const newValue: number = Math.floor(event.currentTarget.valueAsNumber) setValue(newValue) }} @@ -166,7 +166,7 @@ export default function JSONSchemaInput(props: JSONSchemaInputProps) { /> )} - + , ) break } @@ -176,7 +176,7 @@ export default function JSONSchemaInput(props: JSONSchemaInputProps) { isReadOnly={readOnly} isSelected={typeof value === 'boolean' && value} onChange={setValue} - /> + />, ) break } @@ -190,104 +190,111 @@ export default function JSONSchemaInput(props: JSONSchemaInputProps) { const [k, v] = kv return object .singletonObjectOrNull(v) - .map(childSchema => ({ key: k, schema: childSchema })) - } + .map((childSchema) => ({ key: k, schema: childSchema })) + }, ) if (jsonSchema.constantValue(defs, schema).length !== 1) { children.push(
- {propertyDefinitions.map(definition => { + {propertyDefinitions.map((definition) => { const { key, schema: childSchema } = definition const isOptional = !requiredProperties.includes(key) - return jsonSchema.constantValue(defs, childSchema).length === 1 ? null : ( -
- - {innerProps => { - const isPresent = value != null && key in value - return ( - { - if (isOptional) { - setValue(oldValue => { - if (oldValue != null && key in oldValue) { - // This is SAFE, as `value` is an untyped object. - // The removed key is intentionally unused. - // eslint-disable-next-line no-restricted-syntax, @typescript-eslint/no-unused-vars - const { [key]: removed, ...newValue } = oldValue as Record< - string, - NonNullable | null - > - return newValue - } else { - return { - ...oldValue, - [key]: jsonSchema.constantValue(defs, childSchema, true)[0], + > + + {(innerProps) => { + const isPresent = value != null && key in value + return ( + { + if (isOptional) { + setValue((oldValue) => { + if (oldValue != null && key in oldValue) { + // This is SAFE, as `value` is an untyped object. + // The removed key is intentionally unused. + // eslint-disable-next-line no-restricted-syntax, @typescript-eslint/no-unused-vars + const { [key]: removed, ...newValue } = oldValue as Record< + string, + NonNullable | null + > + return newValue + } else { + return { + ...oldValue, + [key]: jsonSchema.constantValue( + defs, + childSchema, + true, + )[0], + } } - } - }) - } - }} - {...innerProps} - > - {'title' in childSchema ? String(childSchema.title) : key} - - ) - }} - - {value != null && key in value && ( - )[key] ?? null} - setValue={newValue => { - setValue(oldValue => { - if (typeof newValue === 'function') { - const unsafeValue: unknown = newValue( - // This is SAFE; but there is no way to tell TypeScript that an object - // has an index signature. - // eslint-disable-next-line no-restricted-syntax - (oldValue as Readonly>)[key] ?? null - ) - // The value MAY be `null`, but it is better than the value being a - // function (which is *never* the intended result). - // eslint-disable-next-line @typescript-eslint/no-non-null-assertion - newValue = unsafeValue! - } - return typeof oldValue === 'object' && - oldValue != null && - // This is SAFE; but there is no way to tell TypeScript that an object - // has an index signature. - // eslint-disable-next-line no-restricted-syntax - (oldValue as Readonly>)[key] === newValue - ? oldValue - : { ...oldValue, [key]: newValue } - }) + }) + } + }} + {...innerProps} + > + {'title' in childSchema ? String(childSchema.title) : key} + + ) }} - /> - )} -
- ) + + {value != null && key in value && ( + )[key] ?? null} + setValue={(newValue) => { + setValue((oldValue) => { + if (typeof newValue === 'function') { + const unsafeValue: unknown = newValue( + // This is SAFE; but there is no way to tell TypeScript that an object + // has an index signature. + // eslint-disable-next-line no-restricted-syntax + (oldValue as Readonly>)[key] ?? null, + ) + // The value MAY be `null`, but it is better than the value being a + // function (which is *never* the intended result). + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion + newValue = unsafeValue! + } + return ( + typeof oldValue === 'object' && + oldValue != null && + // This is SAFE; but there is no way to tell TypeScript that an object + // has an index signature. + // eslint-disable-next-line no-restricted-syntax + (oldValue as Readonly>)[key] === + newValue + ) ? + oldValue + : { ...oldValue, [key]: newValue } + }) + }} + /> + )} +
})} -
+
, ) } break @@ -303,7 +310,7 @@ export default function JSONSchemaInput(props: JSONSchemaInputProps) { key={schema.$ref} schema={referencedSchema} path={schema.$ref} - /> + />, ) } } @@ -319,7 +326,7 @@ export default function JSONSchemaInput(props: JSONSchemaInputProps) { (selectedChildSchema == null || getValidator(selectedChildPath)(value) !== true) ) { const newIndexRaw = childSchemas.findIndex((_, index) => - getValidator(`${path}/anyOf/${index}`)(value) + getValidator(`${path}/anyOf/${index}`)(value), ) const newIndex = selectedChildSchema == null && newIndexRaw === -1 ? 0 : newIndexRaw if (newIndex !== -1 && newIndex !== selectedChildIndex) { @@ -328,12 +335,12 @@ export default function JSONSchemaInput(props: JSONSchemaInputProps) { } const dropdown = ( - {innerProps => ( + {(innerProps) => ( ( + render={(childProps) => ( {jsonSchema.getSchemaName(defs, childProps.item)} )} className="self-start" @@ -351,17 +358,15 @@ export default function JSONSchemaInput(props: JSONSchemaInputProps) {
- {dropdownTitle != null ? ( + {dropdownTitle != null ?
{dropdownTitle}
{dropdown}
- ) : ( - dropdown - )} + : dropdown} {selectedChildSchema != null && ( )} -
+
, ) } if ('allOf' in schema && Array.isArray(schema.allOf)) { @@ -393,10 +398,10 @@ export default function JSONSchemaInput(props: JSONSchemaInputProps) { )) children.push(...newChildren) } - return children.length === 0 ? null : children.length === 1 && children[0] != null ? ( - children[0] - ) : ( -
{...children}
+ return ( + children.length === 0 ? null + : children.length === 1 && children[0] != null ? children[0] + :
{...children}
) } } diff --git a/app/dashboard/src/components/Link.tsx b/app/dashboard/src/components/Link.tsx index 8c5169fad5..11de3f8123 100644 --- a/app/dashboard/src/components/Link.tsx +++ b/app/dashboard/src/components/Link.tsx @@ -41,7 +41,7 @@ export default function Link(props: LinkProps) { return ( - {openInBrowser ? ( + {openInBrowser ? ()(focusChildProps, { href: to, @@ -54,8 +54,7 @@ export default function Link(props: LinkProps) { > {contents} - ) : ( - ()(focusChildProps, { to, className, @@ -64,7 +63,7 @@ export default function Link(props: LinkProps) { > {contents} - )} + } ) } diff --git a/app/dashboard/src/components/MenuEntry.tsx b/app/dashboard/src/components/MenuEntry.tsx index b505cfd5db..35c090b877 100644 --- a/app/dashboard/src/components/MenuEntry.tsx +++ b/app/dashboard/src/components/MenuEntry.tsx @@ -120,11 +120,11 @@ export default function MenuEntry(props: MenuEntryProps) { const info = inputBindings.metadata[action] const labelTextId: text.TextId = (() => { if (action === 'openInFileBrowser') { - return detect.isOnMacOS() - ? 'openInFileBrowserShortcutMacOs' - : detect.isOnWindows() - ? 'openInFileBrowserShortcutWindows' - : 'openInFileBrowserShortcut' + return ( + detect.isOnMacOS() ? 'openInFileBrowserShortcutMacOs' + : detect.isOnWindows() ? 'openInFileBrowserShortcutWindows' + : 'openInFileBrowserShortcut' + ) } else { return ACTION_TO_TEXT_ID[action] } @@ -143,25 +143,27 @@ export default function MenuEntry(props: MenuEntryProps) { }, [isDisabled, inputBindings, action, doAction]) return hidden ? null : ( - - ()(focusChildProps, { - isDisabled, - className: 'group flex w-full rounded-menu-entry', - onPress: () => { - unsetModal() - doAction() - }, - })} - > -
-
- - {label ?? getText(labelTextId)} + + ()(focusChildProps, { + isDisabled, + className: 'group flex w-full rounded-menu-entry', + onPress: () => { + unsetModal() + doAction() + }, + })} + > +
+
+ + + {label ?? getText(labelTextId)} + +
+
- -
- - - ) + + + ) } diff --git a/app/dashboard/src/components/Modal.tsx b/app/dashboard/src/components/Modal.tsx index 524f1a9c31..1726d93b2e 100644 --- a/app/dashboard/src/components/Modal.tsx +++ b/app/dashboard/src/components/Modal.tsx @@ -44,14 +44,14 @@ export default function Modal(props: ModalProps) { return ( - {innerProps => ( + {(innerProps) => (
{ + ((event) => { if (event.currentTarget === event.target && getSelection()?.type !== 'Range') { event.stopPropagation() unsetModal() @@ -60,7 +60,7 @@ export default function Modal(props: ModalProps) { } onContextMenu={onContextMenu} {...innerProps} - onKeyDown={event => { + onKeyDown={(event) => { innerProps.onKeyDown?.(event) if (event.key !== 'Escape') { event.stopPropagation() diff --git a/app/dashboard/src/components/OfflineNotificationManager.tsx b/app/dashboard/src/components/OfflineNotificationManager.tsx index 07c1d26d23..84803b31a0 100644 --- a/app/dashboard/src/components/OfflineNotificationManager.tsx +++ b/app/dashboard/src/components/OfflineNotificationManager.tsx @@ -38,7 +38,7 @@ export function OfflineNotificationManager(props: OfflineNotificationManagerProp const toastId = 'offline' const { getText } = textProvider.useText() - offlineHooks.useOfflineChange(isOffline => { + offlineHooks.useOfflineChange((isOffline) => { toast.toast.dismiss(toastId) if (isOffline) { diff --git a/app/dashboard/src/components/Page.tsx b/app/dashboard/src/components/Page.tsx index ac779b22fb..fe2268c37e 100644 --- a/app/dashboard/src/components/Page.tsx +++ b/app/dashboard/src/components/Page.tsx @@ -41,17 +41,13 @@ export default function Page(props: PageProps) { {!hideChat && ( <> {/* `session.accessToken` MUST be present in order for the `Chat` component to work. */} - {!hideInfoBar && - session?.accessToken != null && - process.env.ENSO_CLOUD_CHAT_URL != null ? ( + {!hideInfoBar && session?.accessToken != null && process.env.ENSO_CLOUD_CHAT_URL != null ? - ) : ( - - )} + : } )} diff --git a/app/dashboard/src/components/Paywall/ContextMenuEntry.tsx b/app/dashboard/src/components/Paywall/ContextMenuEntry.tsx index 2b50630c66..d97f1e05af 100644 --- a/app/dashboard/src/components/Paywall/ContextMenuEntry.tsx +++ b/app/dashboard/src/components/Paywall/ContextMenuEntry.tsx @@ -39,7 +39,7 @@ export function ContextMenuEntry(props: ContextMenuEntryProps) { icon={LockIcon} doAction={() => { setModal( - + , ) }} /> diff --git a/app/dashboard/src/components/Paywall/components/PaywallBulletPoints.tsx b/app/dashboard/src/components/Paywall/components/PaywallBulletPoints.tsx index 4c25669fc9..b6df80165d 100644 --- a/app/dashboard/src/components/Paywall/components/PaywallBulletPoints.tsx +++ b/app/dashboard/src/components/Paywall/components/PaywallBulletPoints.tsx @@ -33,14 +33,14 @@ export function PaywallBulletPoints(props: PaywallBulletPointsProps) { const { getText } = textProvider.useText() const bulletPoints = getText(bulletPointsTextId) .split(';') - .map(bulletPoint => bulletPoint.trim()) + .map((bulletPoint) => bulletPoint.trim()) if (bulletPoints.length === 0) { return null } else { return (
    - {bulletPoints.map(bulletPoint => ( + {bulletPoints.map((bulletPoint) => (
  • diff --git a/app/dashboard/src/components/Paywall/components/index.ts b/app/dashboard/src/components/Paywall/components/index.ts index 598c9b33d5..84d9756c23 100644 --- a/app/dashboard/src/components/Paywall/components/index.ts +++ b/app/dashboard/src/components/Paywall/components/index.ts @@ -3,6 +3,6 @@ * * Barrel file for the Paywall components. */ -export * from './PaywallLock' export * from './PaywallBulletPoints' export * from './PaywallButton' +export * from './PaywallLock' diff --git a/app/dashboard/src/components/Paywall/index.ts b/app/dashboard/src/components/Paywall/index.ts index 49358574e7..c1ce571440 100644 --- a/app/dashboard/src/components/Paywall/index.ts +++ b/app/dashboard/src/components/Paywall/index.ts @@ -3,10 +3,10 @@ * * Barrel file for Paywall components. */ -export * from './PaywallScreen' -export * from './PaywallDialogButton' -export * from './PaywallDialog' -export * from './UpgradeButton' -export * from './PaywallAlert' -export * from './ContextMenuEntry' export { PaywallButton, type PaywallButtonProps } from './components' +export * from './ContextMenuEntry' +export * from './PaywallAlert' +export * from './PaywallDialog' +export * from './PaywallDialogButton' +export * from './PaywallScreen' +export * from './UpgradeButton' diff --git a/app/dashboard/src/components/Portal/usePortal.ts b/app/dashboard/src/components/Portal/usePortal.ts index fd99111b40..d923b994fa 100644 --- a/app/dashboard/src/components/Portal/usePortal.ts +++ b/app/dashboard/src/components/Portal/usePortal.ts @@ -28,7 +28,7 @@ export function usePortal(props: types.PortalProps) { invariant( !(contextRoot == null && currentRoot == null), - 'Before using Portal, you need to specify a root, where the component should be mounted or put the component under the component' + 'Before using Portal, you need to specify a root, where the component should be mounted or put the component under the component', ) setMountRoot(currentRoot ?? contextRoot) diff --git a/app/dashboard/src/components/Result.tsx b/app/dashboard/src/components/Result.tsx index 2ea69c7a01..44bcd31f9e 100644 --- a/app/dashboard/src/components/Result.tsx +++ b/app/dashboard/src/components/Result.tsx @@ -113,40 +113,32 @@ export function Result(props: ResultProps) { return (
    - {showIcon ? ( + {showIcon ? <> - {statusIcon != null ? ( + {statusIcon != null ?
    - {typeof statusIcon.icon === 'string' ? ( + {typeof statusIcon.icon === 'string' ? - ) : ( - statusIcon.icon - )} + : statusIcon.icon}
    - ) : ( - status - )} + : status} - ) : null} + : null} - {typeof title === 'string' ? ( + {typeof title === 'string' ? {title} - ) : ( - title - )} + : title} - {typeof subtitle === 'string' ? ( + {typeof subtitle === 'string' ? {subtitle} - ) : ( - subtitle - )} + : subtitle} {children != null &&
    {children}
    }
    diff --git a/app/dashboard/src/components/SelectionBrush.tsx b/app/dashboard/src/components/SelectionBrush.tsx index de0bc9bc18..b81e3fc632 100644 --- a/app/dashboard/src/components/SelectionBrush.tsx +++ b/app/dashboard/src/components/SelectionBrush.tsx @@ -51,7 +51,7 @@ export default function SelectionBrush(props: SelectionBrushProps) { const [lastSetAnchor, setLastSetAnchor] = React.useState(null) const anchorAnimFactor = animationHooks.useApproach( anchor != null ? 1 : 0, - ANIMATION_TIME_HORIZON + ANIMATION_TIME_HORIZON, ) const hidden = anchor == null || @@ -112,19 +112,19 @@ export default function SelectionBrush(props: SelectionBrushProps) { didMoveWhileDraggingRef.current = true lastMouseEvent.current = event const positionLeft = - parentBounds.current == null - ? event.pageX - : Math.max( - parentBounds.current.left - margin, - Math.min(parentBounds.current.right + margin, event.pageX) - ) + parentBounds.current == null ? + event.pageX + : Math.max( + parentBounds.current.left - margin, + Math.min(parentBounds.current.right + margin, event.pageX), + ) const positionTop = - parentBounds.current == null - ? event.pageY - : Math.max( - parentBounds.current.top - margin, - Math.min(parentBounds.current.bottom + margin, event.pageY) - ) + parentBounds.current == null ? + event.pageY + : Math.max( + parentBounds.current.top - margin, + Math.min(parentBounds.current.bottom + margin, event.pageY), + ) setPosition({ left: positionLeft, top: positionTop }) } } @@ -188,20 +188,20 @@ export default function SelectionBrush(props: SelectionBrushProps) { }, [selectionRectangle]) const brushStyle = - rectangle == null - ? {} - : { - left: `${rectangle.left}px`, - top: `${rectangle.top}px`, - width: `${rectangle.width}px`, - height: `${rectangle.height}px`, - } + rectangle == null ? + {} + : { + left: `${rectangle.left}px`, + top: `${rectangle.top}px`, + width: `${rectangle.width}px`, + height: `${rectangle.height}px`, + } return (