Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

Fix various issues on the Dashboard #10256

Merged
merged 72 commits into from
Jun 20, 2024
Merged
Show file tree
Hide file tree
Changes from 42 commits
Commits
Show all changes
72 commits
Select commit Hold shift + click to select a range
f898f5a
Finally fix React DevTools being broken...
somebody1234 May 22, 2024
f5f357b
Fix folders collapsing when refocusing window
somebody1234 Jun 12, 2024
df24732
Clean up code
somebody1234 May 23, 2024
7c6dc48
Change `object.merge` and `object.merger` to reduce unnecessary re-re…
somebody1234 May 24, 2024
41fd415
Cache directory contents in Asset Table
somebody1234 May 24, 2024
c4fa67f
Further debugging and fixes for editing name...
somebody1234 May 24, 2024
9dc2973
WIP: still debugging broken text selection...
somebody1234 May 24, 2024
8dac52f
Avoid caching directory entries
somebody1234 May 26, 2024
729252a
Remove debug logs
somebody1234 May 27, 2024
73ec0e9
Fix Firefox selection bug; document browser-specific behavior
somebody1234 May 27, 2024
89f9b8d
Minor rename of `DragModal` props
somebody1234 May 27, 2024
9ab12c8
Replace disabled `exhaustive-hooks` lints with refs
somebody1234 May 27, 2024
9ae348b
Option to limit `SelectionBrush` to a given element
somebody1234 May 27, 2024
30bca73
Remove `/* should never change */` annotations (they were unnecessary)
somebody1234 May 27, 2024
f4f201a
Update username live for asset permissions when changing username
somebody1234 May 27, 2024
d9947cd
Limit `PermissionDisplay` length and show tooltip when too long
somebody1234 May 27, 2024
a35b8ba
Fix flex containers being too small for buttons in table cells
somebody1234 May 27, 2024
5b31d74
Update design of buttons to be more consistent with other icon buttons
somebody1234 May 27, 2024
0de8375
Fix E2E tests
somebody1234 May 30, 2024
7f1d345
Move classes to `tailwind.css`
somebody1234 May 30, 2024
cf90971
Use `apply` instead of hardcoded CSS rules
somebody1234 May 30, 2024
58f7be5
WIP: Improve button styles
somebody1234 May 30, 2024
2a6a4cc
Stop using `kbd` to display keyboard shortcuts
somebody1234 Jun 12, 2024
1ea5a33
Add `useOnScroll` to `exhaustive-deps` lint
somebody1234 Jun 12, 2024
39871c9
Update `AssetsTable` clip path on resize using `ResizeObserver`
somebody1234 Jun 12, 2024
eb191e4
More consistent buttons
somebody1234 Jun 12, 2024
52ce15c
Switch buttons to `ariaComponents.Button`
somebody1234 Jun 12, 2024
7008681
Adjust styles for buttons; adjust styles for plus button in "shared w…
somebody1234 Jun 12, 2024
4f514a4
Convert tick and cross icons to be consistent with other icons
somebody1234 Jun 12, 2024
b0b959d
Fix cancelling rename not working
somebody1234 Jun 12, 2024
4251a82
Fix duplicate name detection
somebody1234 Jun 12, 2024
d0b6773
Add more validation for directory names
somebody1234 Jun 12, 2024
9dfa3d6
WIP: playing with `Debug`
somebody1234 Jun 12, 2024
31d6fd4
Fix output of `Debug` component
somebody1234 Jun 13, 2024
76945b8
Merge branch 'develop' into wip/sb/dashboard-fixes
somebody1234 Jun 13, 2024
02071c6
Fix lint errors
somebody1234 Jun 13, 2024
7a753a4
Fix `tertiary` buttons
somebody1234 Jun 13, 2024
945136e
Fix duplicate name detection
somebody1234 Jun 13, 2024
a8b3229
Fix E2E tests
somebody1234 Jun 13, 2024
7df23b3
Minor CSS changes
somebody1234 Jun 13, 2024
9e3774e
Prettier
somebody1234 Jun 14, 2024
8f11e9e
Remove `shouldPreventNavigation`
somebody1234 Jun 14, 2024
9262170
Add ESLint rule to ban `<Debug>` component
somebody1234 Jun 17, 2024
e21058b
Use `IntersectionObserver` to determine whether to show secondary dro…
somebody1234 Jun 18, 2024
c447973
Refactor and fix hook to determine whether to show backup dropzone
somebody1234 Jun 18, 2024
e890259
Fix truncation of permission pills
somebody1234 Jun 18, 2024
b0decac
Fix weird behavior when dragging labels...
somebody1234 Jun 18, 2024
709185c
Improve lag when dragging labels on Firefox
somebody1234 Jun 18, 2024
4ffeaa5
Merge branch 'develop' into wip/sb/dashboard-fixes
somebody1234 Jun 18, 2024
3ed3337
Fix permission selector appearance
somebody1234 Jun 18, 2024
9d186d7
Remove `isCentered` prop in favor of custom size
somebody1234 Jun 19, 2024
c4fb8f8
Fix E2E tests
somebody1234 Jun 19, 2024
e31c86e
Use custom `tailwind-merge` config for `tailwind-variants`
somebody1234 Jun 19, 2024
9ecd8cf
Use non-custom size for Project icons
somebody1234 Jun 19, 2024
8e60404
Fix infinite loop in `AssetProperties`
somebody1234 Jun 19, 2024
d2ca958
Fix `package.json`
somebody1234 Jun 19, 2024
8964d62
Merge branch 'develop' into wip/sb/dashboard-fixes
somebody1234 Jun 20, 2024
b336c6d
Unselect current page when switching to settings page
somebody1234 Jun 20, 2024
db9d103
Truncate username and org name on settings page
somebody1234 Jun 20, 2024
cdab7e7
Fix button in kb shortcuts
MrFlashAccount Jun 20, 2024
1284f97
Fix button styling
somebody1234 Jun 20, 2024
cded38b
Hide Keyboard Shortcuts settings page buttons unless `focus-within` o…
somebody1234 Jun 20, 2024
c314d79
Fix buttons on settings pages
somebody1234 Jun 20, 2024
0be5367
Address QA
somebody1234 Jun 20, 2024
ee50727
Address CR
somebody1234 Jun 20, 2024
d9cac07
Refactor name check
somebody1234 Jun 20, 2024
a533769
Merge branch 'develop' into wip/sb/dashboard-fixes
somebody1234 Jun 20, 2024
9e452c4
Fix double clicking project to open
somebody1234 Jun 20, 2024
4e792e9
Auto-resize `EditableSpan` for asset name input
somebody1234 Jun 20, 2024
2dee3f0
Fix E2E tests
somebody1234 Jun 20, 2024
ba32768
Fix keyboard shortcuts
MrFlashAccount Jun 20, 2024
c8df022
Merge branch 'develop' into wip/sb/dashboard-fixes
somebody1234 Jun 20, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion app/ide-desktop/eslint.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -299,7 +299,10 @@ export default [
'react/prop-types': 'off',
'react/self-closing-comp': 'error',
'react-hooks/rules-of-hooks': 'error',
'react-hooks/exhaustive-deps': 'error',
'react-hooks/exhaustive-deps': [
'error',
{ additionalHooks: 'useOnScroll|useStickyTableHeaderOnScroll' },
],
'react/jsx-pascal-case': ['error', { allowNamespace: true }],
// Prefer `interface` over `type`.
'@typescript-eslint/consistent-type-definitions': 'error',
Expand Down
5 changes: 2 additions & 3 deletions app/ide-desktop/lib/assets/cross.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
9 changes: 3 additions & 6 deletions app/ide-desktop/lib/assets/plus2.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
8 changes: 8 additions & 0 deletions app/ide-desktop/lib/assets/reload.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
20 changes: 0 additions & 20 deletions app/ide-desktop/lib/assets/reload_in_circle.svg

This file was deleted.

4 changes: 2 additions & 2 deletions app/ide-desktop/lib/assets/tick.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
7 changes: 7 additions & 0 deletions app/ide-desktop/lib/dashboard/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,13 @@
The dashboard is the entrypoint into the application. It includes project
management, project sharing, and user accounts and authentication.

## Further documentation

Further documentation is provided in the `docs/` folder:

- [Browser-specific behavior](./docs/browser_specific_behavior.md) details
behavior that is inconsistent between browsers and needs to be worked around.

## Folder structure

- `mock/`: Overrides for specific files in `src/` when running Playwright tests.
Expand Down
65 changes: 65 additions & 0 deletions app/ide-desktop/lib/dashboard/docs/browser_specific_behavior.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
# Browser-specific behavior

This document details behavior that is inconsistent between browsers and needs
to be worked around.

## List of inconsistent behaviors

### Drag event missing coordinates

Firefox sets `MouseEvent.pageX` and `MouseEvent.pageY` to `0` for `drag`
events.

#### Fix

Pass the `drag` event handlers to `dragover` event as well, and wrap all `drag`
event handlers in:

````ts
if (event.pageX !== 0 || event.pageY !== 0) {
// original body here
}
```

#### Affected files

- [`DragModal.tsx`](../src/modals/DragModal.tsx)

### Drag event propagation in text inputs

Text selection in text inputs DO NOT WORK on Firefox, when the text input is a
child of an element with `draggable="true"`.
See [Firefox bug 800050].
To solve this problem, use `useDraggable` from
[`dragAndDropHooks.ts`] on ALL elements that MAY contain a text input.

[Firefox bug 800050]: https://bugzilla.mozilla.org/show_bug.cgi?id=800050

#### Fix

Merge `useDraggable` from [`dragAndDropHooks.ts`] on ALL elements that MAY
contain a text input.

It is recommended to use `aria.mergeProps` to combine these props with existing
props.

```tsx
import * as dragAndDropHooks from "#/hooks/dragAndDropHooks.ts";

const draggableProps = dragAndDropHooks.useDraggable();

return <div {...draggableProps}></div>;
````

[`draggableHooks.ts`]: ../src/hooks/dragAndDropHooks.ts

#### Affected browsers

- Firefox (all versions)

#### Affected files

- [`EditableSpan.tsx`](../src/components/EditableSpan.tsx) - the text inputs
that are affected
- [`AssetRow.tsx`](../src/components/dashboard/AssetRow.tsx) - fixes text
selection in `EditableSpan.tsx`
20 changes: 10 additions & 10 deletions app/ide-desktop/lib/dashboard/e2e/actions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -184,12 +184,12 @@ export function locateTrashButton(page: test.Locator | test.Page) {

/** Find a tick button (if any) on the current page. */
export function locateEditingTick(page: test.Locator | test.Page) {
return page.getByAltText('Confirm Edit')
return page.getByLabel('Confirm Edit')
}

/** Find a cross button (if any) on the current page. */
export function locateEditingCross(page: test.Locator | test.Page) {
return page.getByAltText('Cancel Edit')
return page.getByLabel('Cancel Edit')
}

/** Find labels in the "Labels" column of the assets table (if any) on the current page. */
Expand Down Expand Up @@ -793,18 +793,18 @@ async function mockDate({ page }: MockParams) {
}`)
}

/**
* Passes Terms and conditions dialog
*/
/** Pass the Terms and conditions dialog. */
export async function passTermsAndConditionsDialog({ page }: MockParams) {
// wait for terms and conditions dialog to appear
// but don't fail if it doesn't appear
try {
// wait for terms and conditions dialog to appear
// eslint-disable-next-line @typescript-eslint/no-magic-numbers
await page.waitForSelector('#terms-of-service-modal', { timeout: 500 })
await page.getByRole('checkbox').click()
await page.getByRole('button', { name: 'Accept' }).click()
await test.test.step('Accept Terms and Conditions', async () => {
// wait for terms and conditions dialog to appear
// eslint-disable-next-line @typescript-eslint/no-magic-numbers
await page.waitForSelector('#terms-of-service-modal', { timeout: 500 })
await page.getByRole('checkbox').click()
await page.getByRole('button', { name: 'Accept' }).click()
})
} catch (error) {
// do nothing
}
Expand Down
5 changes: 5 additions & 0 deletions app/ide-desktop/lib/dashboard/e2e/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -420,6 +420,11 @@ export async function mockApi({ page }: MockParams) {
}
}
)
await page.route(BASE_URL + remoteBackendPaths.INVITATION_PATH + '*', async route => {
await route.fulfill({
json: { invitations: [] } satisfies backend.ListInvitationsResponseBody,
})
})
await page.route(BASE_URL + remoteBackendPaths.INVITE_USER_PATH + '*', async route => {
await route.fulfill()
})
Expand Down
3 changes: 2 additions & 1 deletion app/ide-desktop/lib/dashboard/e2e/assetPanel.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,8 @@ test.test('asset panel contents', async ({ page }) => {
permission: permissions.PermissionAction.own,
user: {
organizationId: defaultOrganizationId,
userId: defaultUserId,
// Using the default ID causes the asset to have a dynamic username, of course.
userId: backend.UserId(defaultUserId + '2'),
name: username,
email: backend.EmailAddress(email),
},
Expand Down
75 changes: 35 additions & 40 deletions app/ide-desktop/lib/dashboard/e2e/editAssetName.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,85 +8,80 @@ test.test.beforeEach(actions.mockAllAndLogin)
test.test('edit name', async ({ page }) => {
const assetRows = actions.locateAssetRows(page)
const mod = await actions.modModifier(page)
const row = assetRows.nth(0)
const newName = 'foo bar baz'

await actions.locateNewFolderIcon(page).click()
await actions.locateAssetRowName(assetRows.nth(0)).click({ modifiers: [mod] })
await actions.locateAssetRowName(assetRows.nth(0)).fill(newName)
await actions.locateEditingTick(assetRows.nth(0)).click()
await test.expect(assetRows).toHaveCount(1)
await test.expect(assetRows.nth(0)).toBeVisible()
await test.expect(assetRows.nth(0)).toHaveText(new RegExp('^' + newName))
await actions.locateAssetRowName(row).click({ modifiers: [mod] })
await actions.locateAssetRowName(row).fill(newName)
await actions.locateEditingTick(row).click()
await test.expect(row).toHaveText(new RegExp('^' + newName))
})

test.test('edit name (keyboard)', async ({ page }) => {
const assetRows = actions.locateAssetRows(page)
const row = assetRows.nth(0)
const newName = 'foo bar baz quux'

await actions.locateNewFolderIcon(page).click()
await actions.locateAssetRowName(assetRows.nth(0)).click()
await actions.locateAssetRowName(row).click()
await actions.press(page, 'Mod+R')
await actions.locateAssetRowName(assetRows.nth(0)).fill(newName)
await actions.locateAssetRowName(assetRows.nth(0)).press('Enter')
await test.expect(assetRows).toHaveCount(1)
await test.expect(assetRows.nth(0)).toBeVisible()
await test.expect(assetRows.nth(0)).toHaveText(new RegExp('^' + newName))
await actions.locateAssetRowName(row).fill(newName)
await actions.locateAssetRowName(row).press('Enter')
await test.expect(row).toHaveText(new RegExp('^' + newName))
})

test.test('cancel editing name', async ({ page }) => {
const assetRows = actions.locateAssetRows(page)
const mod = await actions.modModifier(page)
const row = assetRows.nth(0)
const newName = 'foo bar baz'

await actions.locateNewFolderIcon(page).click()
const oldName = (await actions.locateAssetRowName(assetRows.nth(0)).textContent()) ?? ''
await actions.locateAssetRowName(assetRows.nth(0)).click({ modifiers: [mod] })
await actions.locateAssetRowName(assetRows.nth(0)).fill(newName)
await actions.locateEditingCross(assetRows.nth(0)).click()
await test.expect(assetRows).toHaveCount(1)
await test.expect(assetRows.nth(0)).toBeVisible()
await test.expect(assetRows.nth(0)).toHaveText(new RegExp('^' + oldName))
const oldName = (await actions.locateAssetRowName(row).textContent()) ?? ''
await actions.locateAssetRowName(row).click({ modifiers: [mod] })
await actions.locateAssetRowName(row).fill(newName)
await actions.locateEditingCross(row).click()
await test.expect(row).toHaveText(new RegExp('^' + oldName))
})

test.test('cancel editing name (keyboard)', async ({ page }) => {
const assetRows = actions.locateAssetRows(page)
const row = assetRows.nth(0)
const newName = 'foo bar baz quux'

await actions.locateNewFolderIcon(page).click()
const oldName = (await actions.locateAssetRowName(assetRows.nth(0)).textContent()) ?? ''
await actions.locateAssetRowName(assetRows.nth(0)).click()
const oldName = (await actions.locateAssetRowName(row).textContent()) ?? ''
await actions.locateAssetRowName(row).click()
await actions.press(page, 'Mod+R')
await actions.locateAssetRowName(assetRows.nth(0)).fill(newName)
await actions.locateAssetRowName(assetRows.nth(0)).press('Escape')
await test.expect(assetRows).toHaveCount(1)
await test.expect(assetRows.nth(0)).toBeVisible()
await test.expect(assetRows.nth(0)).toHaveText(new RegExp('^' + oldName))
await actions.locateAssetRowName(row).fill(newName)
await actions.locateAssetRowName(row).press('Escape')
await test.expect(row).toHaveText(new RegExp('^' + oldName))
})

test.test('change to blank name', async ({ page }) => {
const assetRows = actions.locateAssetRows(page)
const mod = await actions.modModifier(page)
const row = assetRows.nth(0)

await actions.locateNewFolderIcon(page).click()
const oldName = (await actions.locateAssetRowName(assetRows.nth(0)).textContent()) ?? ''
await actions.locateAssetRowName(assetRows.nth(0)).click({ modifiers: [mod] })
await actions.locateAssetRowName(assetRows.nth(0)).fill('')
await actions.locateEditingTick(assetRows.nth(0)).click()
await test.expect(assetRows).toHaveCount(1)
await test.expect(assetRows.nth(0)).toBeVisible()
await test.expect(assetRows.nth(0)).toHaveText(new RegExp('^' + oldName))
const oldName = (await actions.locateAssetRowName(row).textContent()) ?? ''
await actions.locateAssetRowName(row).click({ modifiers: [mod] })
await actions.locateAssetRowName(row).fill('')
await test.expect(actions.locateEditingTick(row)).not.toBeVisible()
await actions.locateEditingCross(row).click()
await test.expect(row).toHaveText(new RegExp('^' + oldName))
})

test.test('change to blank name (keyboard)', async ({ page }) => {
const assetRows = actions.locateAssetRows(page)
const row = assetRows.nth(0)

await actions.locateNewFolderIcon(page).click()
const oldName = (await actions.locateAssetRowName(assetRows.nth(0)).textContent()) ?? ''
await actions.locateAssetRowName(assetRows.nth(0)).click()
const oldName = (await actions.locateAssetRowName(row).textContent()) ?? ''
await actions.locateAssetRowName(row).click()
await actions.press(page, 'Mod+R')
await actions.locateAssetRowName(assetRows.nth(0)).fill('')
await actions.locateAssetRowName(assetRows.nth(0)).press('Enter')
await test.expect(assetRows).toHaveCount(1)
await test.expect(assetRows.nth(0)).toBeVisible()
await test.expect(assetRows.nth(0)).toHaveText(new RegExp('^' + oldName))
await actions.locateAssetRowName(row).fill('')
await actions.locateAssetRowName(row).press('Enter')
await test.expect(row).toHaveText(new RegExp('^' + oldName))
})
1 change: 1 addition & 0 deletions app/ide-desktop/lib/dashboard/e2e/loginLogout.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ test.test.beforeEach(actions.mockAll)
test.test('login and logout', async ({ page }) => {
// After sign in
await actions.login({ page })
await actions.passTermsAndConditionsDialog({ page })
await test.expect(actions.locateDriveView(page)).toBeVisible()
await test.expect(actions.locateLoginButton(page)).not.toBeVisible()

Expand Down
17 changes: 9 additions & 8 deletions app/ide-desktop/lib/dashboard/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -16,14 +16,15 @@
<meta
http-equiv="Content-Security-Policy"
content="
default-src 'self';
frame-src 'self' data: https://js.stripe.com;
script-src 'self' 'unsafe-eval' data: https://*;
style-src 'self' 'unsafe-inline' data: https://*;
connect-src 'self' data: ws://localhost:* ws://127.0.0.1:* http://localhost:* https://* wss://*;
worker-src 'self' blob:;
img-src 'self' blob: data: https://*;
font-src 'self' data: https://*"
default-src 'self';
frame-src 'self' data: https://js.stripe.com;
script-src 'self' 'unsafe-eval' data: https://*;
script-src-elem 'self' 'unsafe-inline' https://*;
style-src 'self' 'unsafe-inline' data: https://*;
connect-src 'self' data: ws://localhost:* ws://127.0.0.1:* http://localhost:* https://* wss://*;
worker-src 'self' blob:;
img-src 'self' blob: data: https://*;
font-src 'self' data: https://*"
/>
<meta
name="viewport"
Expand Down
Loading
Loading