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

Dashboard UX improvements #10868

Merged
merged 52 commits into from
Aug 29, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
52 commits
Select commit Hold shift + click to select a range
7e162ac
Update rust-toolchain hash in Nix
somebody1234 Aug 19, 2024
361990a
Fix styling for JSON Schema Input
somebody1234 Aug 19, 2024
8aed375
Rewrite Dropdown component
somebody1234 Aug 19, 2024
c689194
Move Dropdown `render` prop to `children`
somebody1234 Aug 19, 2024
17b18ac
Make error display fit on screen
somebody1234 Aug 19, 2024
25f2d1b
Switch secret from Modal to Dialog
somebody1234 Aug 19, 2024
f700791
Finish switching Dropdown to react-aria-components
somebody1234 Aug 20, 2024
931b34c
Switch Dropdown to tailwind-variants
somebody1234 Aug 20, 2024
719b1f1
Fix checkmark not showing for Dropdown; fix Dropdown toggle not working
somebody1234 Aug 20, 2024
3941041
Pull in form refactor from Async Execution PR
somebody1234 Aug 20, 2024
6a0d886
Migrate from `React.forwardRef` to generic `forwardRef` wrapper
somebody1234 Aug 20, 2024
a04c1fe
Fix exports
somebody1234 Aug 21, 2024
09f2e22
Update launch.json
somebody1234 Aug 21, 2024
6c45dd6
Update react-aria-components
somebody1234 Aug 21, 2024
6c5dc08
Migrate ActivityLogSettingsSection to DatePicker
somebody1234 Aug 21, 2024
9b1180f
Adjust DatePicker tailwind-variants configuration
somebody1234 Aug 21, 2024
8bb18d7
Fixed size for Activity Log DatePicker
somebody1234 Aug 21, 2024
3ea825e
(Not working) Max date for Activity Log date picker
somebody1234 Aug 21, 2024
48a05b4
Highlight selected dates
somebody1234 Aug 21, 2024
836b43b
Add reset button to DatePicker
somebody1234 Aug 21, 2024
32f9739
Fix lint errors
somebody1234 Aug 21, 2024
4d180a7
Clean up ActivityLogSettingsSection
somebody1234 Aug 21, 2024
bc65e02
Clean up SettingsSidebar
somebody1234 Aug 21, 2024
3619938
Visual adjustments to Settings page
somebody1234 Aug 21, 2024
a5e7fd2
Refactor SidebarTabButton
somebody1234 Aug 21, 2024
f18b592
Refactor AssetsTable column headings
somebody1234 Aug 21, 2024
e48ae22
Adjustments to Dropdown and Dialog styles
somebody1234 Aug 21, 2024
cb2ce01
WIP: Fix mouse toggle for Dropdown
somebody1234 Aug 21, 2024
ca4dc15
Fix errors
somebody1234 Aug 21, 2024
04a358c
Fix dialog sizing
somebody1234 Aug 22, 2024
7cd5596
Fix incorrect type of input props
somebody1234 Aug 22, 2024
b3bc7a4
Address other type errors
somebody1234 Aug 22, 2024
d6a6dbc
Improve Dropdown mouse UX
somebody1234 Aug 22, 2024
2d0daec
Move DatePicker dropdown button to left for consistency with Dropdown
somebody1234 Aug 22, 2024
a21dda8
Fix Navigator2D handler to not move focus away if the event is alread…
somebody1234 Aug 22, 2024
fbfa7a6
Fix Dropdown mouse focus issues
somebody1234 Aug 22, 2024
d13d9f2
Fix width of `integer` JSON Schema input
somebody1234 Aug 22, 2024
76a190c
Fix type error
somebody1234 Aug 22, 2024
85f8bb8
Merge branch 'develop' into wip/sb/rac-dropdown
somebody1234 Aug 22, 2024
7935856
Switch DriveBar to {} imports
somebody1234 Aug 22, 2024
36af0dd
Make "new secret" and "new datalink" forms close modal
somebody1234 Aug 22, 2024
518ccf9
oops wrong prop name
somebody1234 Aug 22, 2024
84c8a6f
Fix selector for Datalink name
somebody1234 Aug 22, 2024
66fa690
Fix locator for Datalink modal
somebody1234 Aug 22, 2024
813279d
Address CR
somebody1234 Aug 23, 2024
4b9af2e
Refactor ConfirmDeleteModal from Modal to Dialog
somebody1234 Aug 23, 2024
664490e
Merge branch 'develop' into wip/sb/rac-dropdown
somebody1234 Aug 28, 2024
d657ad8
Fix E2E tests
somebody1234 Aug 29, 2024
35034d8
Fix "confirm delete" modal
somebody1234 Aug 29, 2024
427f1de
Fix `defaultOpen` for modals
somebody1234 Aug 29, 2024
3ce7de2
Make Drive sidebar scrollable if window is too small
somebody1234 Aug 29, 2024
ef14e29
Merge branch 'develop' into wip/sb/rac-dropdown
somebody1234 Aug 29, 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
14 changes: 2 additions & 12 deletions app/dashboard/e2e/actions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -65,12 +65,12 @@ export function locateNewLabelModalColorButtons(page: test.Page) {

/** Find a "name" input for an "upsert secret" modal (if any) on the current page. */
export function locateSecretNameInput(page: test.Page) {
return locateUpsertSecretModal(page).getByPlaceholder('Enter the name of the secret')
return locateUpsertSecretModal(page).getByPlaceholder(TEXT.secretNamePlaceholder)
}

/** Find a "value" input for an "upsert secret" modal (if any) on the current page. */
export function locateSecretValueInput(page: test.Page) {
return locateUpsertSecretModal(page).getByPlaceholder('Enter the value of the secret')
return locateUpsertSecretModal(page).getByPlaceholder(TEXT.secretValuePlaceholder)
}

/** Find a search bar input (if any) on the current page. */
Expand Down Expand Up @@ -100,16 +100,6 @@ export function locateSetUsernameButton(page: test.Locator | test.Page) {
return page.getByRole('button', { name: 'Set Username' }).getByText('Set Username')
}

/** Find a "delete" button (if any) on the current page. */
export function locateDeleteButton(page: test.Locator | test.Page) {
return page.getByRole('button', { name: 'Delete' }).getByText('Delete')
}

/** Find a button to delete something (if any) on the current page. */
export function locateDeleteIcon(page: test.Locator | test.Page) {
return page.getByAltText('Delete')
}

/** Find a "create" button (if any) on the current page. */
export function locateCreateButton(page: test.Locator | test.Page) {
return page.getByRole('button', { name: 'Create' }).getByText('Create')
Expand Down
5 changes: 3 additions & 2 deletions app/dashboard/e2e/actions/NewDataLinkModalActions.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
/** @file Actions for a "new Data Link" modal. */
import type * as test from 'playwright/test'

import { TEXT } from '../actions'
import type * as baseActions from './BaseActions'
import BaseActions from './BaseActions'
import DrivePageActions from './DrivePageActions'
Expand All @@ -11,7 +12,7 @@ import DrivePageActions from './DrivePageActions'

/** Locate the "new data link" modal. */
function locateNewDataLinkModal(page: test.Page) {
return page.getByRole('heading').and(page.getByText('Create Datalink')).locator('..')
return page.getByRole('dialog').filter({ has: page.getByText('Create Datalink') })
}

// ===============================
Expand All @@ -30,7 +31,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) => {
const locator = locateNewDataLinkModal(page).getByLabel('Name')
const locator = locateNewDataLinkModal(page).getByPlaceholder(TEXT.datalinkNamePlaceholder)
await callback(locator)
})
}
Expand Down
61 changes: 37 additions & 24 deletions app/dashboard/e2e/labelsPanel.spec.ts
Original file line number Diff line number Diff line change
@@ -1,51 +1,64 @@
/** @file Test the labels sidebar panel. */
import * as test from '@playwright/test'

import * as actions from './actions'
import {
locateCreateButton,
locateLabelsPanel,
locateLabelsPanelLabels,
locateModalBackground,
locateNewLabelButton,
locateNewLabelModal,
locateNewLabelModalColorButtons,
locateNewLabelModalNameInput,
mockAllAndLogin,
TEXT,
} from './actions'

test.test.beforeEach(({ page }) => actions.mockAllAndLogin({ page }))
test.test.beforeEach(({ page }) => mockAllAndLogin({ page }))

test.test('labels', async ({ page }) => {
// Empty labels panel
await test.expect(actions.locateLabelsPanel(page)).toBeVisible()
await test.expect(locateLabelsPanel(page)).toBeVisible()

// "Create label" modal
await actions.locateNewLabelButton(page).click()
await test.expect(actions.locateNewLabelModal(page)).toBeVisible()
await locateNewLabelButton(page).click()
await test.expect(locateNewLabelModal(page)).toBeVisible()
await page.press('body', 'Escape')
await test.expect(actions.locateNewLabelModal(page)).not.toBeVisible()
await actions.locateNewLabelButton(page).click()
await actions.locateModalBackground(page).click()
await test.expect(actions.locateNewLabelModal(page)).not.toBeVisible()
await actions.locateNewLabelButton(page).click()
await test.expect(locateNewLabelModal(page)).not.toBeVisible()
await locateNewLabelButton(page).click()
await locateModalBackground(page).click()
await test.expect(locateNewLabelModal(page)).not.toBeVisible()
await locateNewLabelButton(page).click()

// "Create label" modal with name set
await actions.locateNewLabelModalNameInput(page).fill('New Label')
await test.expect(actions.locateNewLabelModal(page)).toHaveText(/^New Label/)
await locateNewLabelModalNameInput(page).fill('New Label')
await test.expect(locateNewLabelModal(page)).toHaveText(/^New Label/)

await page.press('body', 'Escape')

// "Create label" modal with color set
// The exact number is allowed to vary; but to click the fourth color, there must be at least
// four colors.
await actions.locateNewLabelButton(page).click()
test.expect(await actions.locateNewLabelModalColorButtons(page).count()).toBeGreaterThanOrEqual(4)
await locateNewLabelButton(page).click()
test.expect(await locateNewLabelModalColorButtons(page).count()).toBeGreaterThanOrEqual(4)
// `force: true` is required because the `label` needs to handle the click event, not the
// `button`.
await actions.locateNewLabelModalColorButtons(page).nth(4).click({ force: true })
await test.expect(actions.locateNewLabelModal(page)).toBeVisible()
await locateNewLabelModalColorButtons(page).nth(4).click({ force: true })
await test.expect(locateNewLabelModal(page)).toBeVisible()

// "Create label" modal with name and color set
await actions.locateNewLabelModalNameInput(page).fill('New Label')
await test.expect(actions.locateNewLabelModal(page)).toHaveText(/^New Label/)
await locateNewLabelModalNameInput(page).fill('New Label')
await test.expect(locateNewLabelModal(page)).toHaveText(/^New Label/)

// Labels panel with one entry
await actions.locateCreateButton(actions.locateNewLabelModal(page)).click()
await test.expect(actions.locateLabelsPanel(page)).toBeVisible()
await locateCreateButton(locateNewLabelModal(page)).click()
await test.expect(locateLabelsPanel(page)).toBeVisible()

// Empty labels panel again, after deleting the only entry
await actions.locateLabelsPanelLabels(page).first().hover()
await actions.locateDeleteIcon(actions.locateLabelsPanel(page)).first().click()
await actions.locateDeleteButton(page).click()
test.expect(await actions.locateLabelsPanelLabels(page).count()).toBeGreaterThanOrEqual(1)
await locateLabelsPanelLabels(page).first().hover()

const labelsPanel = locateLabelsPanel(page)
await labelsPanel.getByRole('button').and(labelsPanel.getByLabel(TEXT.delete)).click()
await page.getByRole('button', { name: 'Delete' }).getByText('Delete').click()
test.expect(await locateLabelsPanelLabels(page).count()).toBeGreaterThanOrEqual(1)
})
11 changes: 6 additions & 5 deletions app/dashboard/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
"@aws-amplify/auth": "5.6.5",
"@aws-amplify/core": "5.8.5",
"@hookform/resolvers": "^3.4.0",
"@internationalized/date": "^3.5.5",
"@monaco-editor/react": "4.6.0",
"@sentry/react": "^7.74.0",
"@stripe/react-stripe-js": "^2.7.1",
Expand All @@ -40,26 +41,26 @@
"ajv": "^8.12.0",
"clsx": "^2.1.1",
"enso-common": "workspace:*",
"framer-motion": "11.3.0",
"is-network-error": "^1.0.1",
"monaco-editor": "0.48.0",
"react": "^18.3.1",
"react-aria": "^3.33.0",
"react-aria-components": "^1.2.0",
"react-aria": "^3.34.3",
"react-aria-components": "^1.3.3",
"react-dom": "^18.3.1",
"react-error-boundary": "4.0.13",
"react-hook-form": "^7.51.4",
"react-router": "^6.23.1",
"react-router-dom": "^6.23.1",
"react-stately": "^3.31.0",
"react-stately": "^3.32.2",
"react-toastify": "^9.1.3",
"tailwind-merge": "^2.3.0",
"tailwind-variants": "0.2.1",
"tiny-invariant": "^1.3.3",
"ts-results": "^3.3.0",
"validator": "^13.12.0",
"zod": "^3.23.8",
"zustand": "^4.5.4",
"framer-motion": "11.3.0"
"zustand": "^4.5.4"
},
"devDependencies": {
"@fast-check/vitest": "^0.0.8",
Expand Down
8 changes: 0 additions & 8 deletions app/dashboard/src/assets/folder_arrow_double.svg

This file was deleted.

21 changes: 11 additions & 10 deletions app/dashboard/src/components/AriaComponents/Alert/Alert.tsx
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
/** @file Alert component. */
import * as React from 'react'
import { type ForwardedRef, type HTMLAttributes, type PropsWithChildren } from 'react'

import * as mergeRefs from '#/utilities/mergeRefs'
import * as twv from '#/utilities/tailwindVariants'
import { mergeRefs } from '#/utilities/mergeRefs'
import { forwardRef } from '#/utilities/react'
import { tv, type VariantProps } from '#/utilities/tailwindVariants'

// =================
// === Constants ===
// =================

export const ALERT_STYLES = twv.tv({
export const ALERT_STYLES = tv({
base: 'flex flex-col items-stretch',
variants: {
fullWidth: { true: 'w-full' },
Expand Down Expand Up @@ -51,14 +52,14 @@ export const ALERT_STYLES = twv.tv({

/** Props for an {@link Alert}. */
export interface AlertProps
extends React.PropsWithChildren,
twv.VariantProps<typeof ALERT_STYLES>,
React.HTMLAttributes<HTMLDivElement> {}
extends PropsWithChildren,
VariantProps<typeof ALERT_STYLES>,
HTMLAttributes<HTMLDivElement> {}

/** Alert component. */
export const Alert = React.forwardRef(function Alert(
export const Alert = forwardRef(function Alert(
props: AlertProps,
ref: React.ForwardedRef<HTMLDivElement>,
ref: ForwardedRef<HTMLDivElement>,
) {
const { children, className, variant, size, rounded, fullWidth, ...containerProps } = props

Expand All @@ -70,7 +71,7 @@ export const Alert = React.forwardRef(function Alert(
return (
<div
className={ALERT_STYLES({ variant, size, className, rounded, fullWidth })}
ref={mergeRefs.mergeRefs(ref, (e) => {
ref={mergeRefs(ref, (e) => {
if (variant === 'error') {
e?.focus()
}
Expand Down
20 changes: 12 additions & 8 deletions app/dashboard/src/components/AriaComponents/Button/Button.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,8 @@ import SvgMask from '#/components/SvgMask'

import * as twv from '#/utilities/tailwindVariants'

import * as text from '../Text'
import { forwardRef } from '#/utilities/react'
import { TEXT_STYLE } from '../Text'

// ==============
// === Button ===
Expand Down Expand Up @@ -106,7 +107,7 @@ export const BUTTON_STYLES = twv.tv({
custom: { base: '', extraClickZone: '', icon: 'h-full' },
hero: { base: 'px-8 py-4 text-lg font-bold', content: 'gap-[0.75em]' },
large: {
base: text.TEXT_STYLE({
base: TEXT_STYLE({
variant: 'body',
color: 'custom',
weight: 'semibold',
Expand All @@ -117,7 +118,7 @@ export const BUTTON_STYLES = twv.tv({
extraClickZone: 'after:inset-[-6px]',
},
medium: {
base: text.TEXT_STYLE({
base: TEXT_STYLE({
variant: 'body',
color: 'custom',
weight: 'semibold',
Expand All @@ -128,7 +129,7 @@ export const BUTTON_STYLES = twv.tv({
extraClickZone: 'after:inset-[-8px]',
},
small: {
base: text.TEXT_STYLE({
base: TEXT_STYLE({
variant: 'body',
color: 'custom',
weight: 'medium',
Expand All @@ -139,7 +140,7 @@ export const BUTTON_STYLES = twv.tv({
extraClickZone: 'after:inset-[-10px]',
},
xsmall: {
base: text.TEXT_STYLE({
base: TEXT_STYLE({
variant: 'body',
color: 'custom',
weight: 'medium',
Expand All @@ -151,7 +152,7 @@ export const BUTTON_STYLES = twv.tv({
extraClickZone: 'after:inset-[-12px]',
},
xxsmall: {
base: text.TEXT_STYLE({
base: TEXT_STYLE({
variant: 'body',
color: 'custom',
className: 'flex px-[3px] pt-[0.5px] pb-[2.5px] leading-[16px]',
Expand All @@ -166,7 +167,7 @@ export const BUTTON_STYLES = twv.tv({
},
iconOnly: {
true: {
base: text.TEXT_STYLE({
base: TEXT_STYLE({
disableLineHeightCompensation: true,
className: 'border-0 outline-offset-[5px]',
}),
Expand Down Expand Up @@ -202,6 +203,9 @@ export const BUTTON_STYLES = twv.tv({
},
ghost:
'text-primary hover:text-primary/80 hover:bg-white focus-visible:text-primary/80 focus-visible:bg-white',
// eslint-disable-next-line @typescript-eslint/naming-convention
'ghost-fading':
'text-primary opacity-80 hover:opacity-100 hover:bg-white focus-visible:bg-white',
submit: 'bg-invite text-white opacity-80 hover:opacity-100',
outline: 'border-primary/20 text-primary hover:border-primary hover:bg-primary/5',
},
Expand Down Expand Up @@ -280,7 +284,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(
export const Button = forwardRef(function Button(
props: ButtonProps,
ref: React.ForwardedRef<HTMLButtonElement>,
) {
Expand Down
Loading
Loading