Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
55 commits
Select commit Hold shift + click to select a range
f76034b
Add ShadCN MCP
tjementum Dec 23, 2025
40d8043
Add BaseUI and ShadCN component configuraiton
tjementum Dec 23, 2025
b2b8cb4
Update frontend rules to document ShadCN 2.0 with BaseUI patterns
tjementum Dec 24, 2025
8079248
Migrate Button component from React Aria to ShadCN 2.0
tjementum Dec 24, 2025
3ff2de3
Migrate Input component from React Aria to ShadCN 2.0
tjementum Dec 24, 2025
c2e9346
Migrate Label component from React Aria to ShadCN 2.0
tjementum Dec 24, 2025
12aa562
Migrate Badge component from React Aria to ShadCN 2.0
tjementum Dec 24, 2025
35b7661
Migrate Separator component from React Aria to ShadCN 2.0
tjementum Dec 24, 2025
33cfab3
Migrate TextField component from React Aria to ShadCN 2.0
tjementum Dec 24, 2025
03fa8ee
Migrate Checkbox component from React Aria to ShadCN 2.0
tjementum Dec 24, 2025
ca3b60f
Migrate RadioGroup component from React Aria to ShadCN 2.0
tjementum Dec 24, 2025
feb26fa
Migrate Select component from React Aria to ShadCN 2.0
tjementum Dec 24, 2025
cc09722
Migrate Dialog and Modal components from React Aria to ShadCN 2.0
tjementum Dec 24, 2025
531b6f0
Migrate AlertDialog component from React Aria to ShadCN 2.0
tjementum Dec 24, 2025
fc64ea2
Migrate Menu components from React Aria to ShadCN 2.0 DropdownMenu
tjementum Dec 24, 2025
86bccb1
Migrate Popover component from React Aria to ShadCN 2.0
tjementum Dec 24, 2025
fbc0df9
Migrate Tooltip component from React Aria to BaseUI
tjementum Dec 24, 2025
e0b5b20
Migrate Table component from React Aria to ShadCN 2.0
tjementum Dec 24, 2025
e3f29fe
Migrate Toast component from React Aria to Sonner and replace custom …
tjementum Dec 25, 2025
73bde0c
Migrate OneTimeCodeInput component from React Aria to ShadCN 2.0 Inpu…
tjementum Dec 25, 2025
9def778
Migrate SearchField component from React Aria to ShadCN composition
tjementum Dec 25, 2025
7a709d4
Migrate NumberField component from React Aria to ShadCN composition
tjementum Dec 25, 2025
9ee071d
Migrate Link component from React Aria to native/ShadCN composition
tjementum Dec 25, 2025
b061e47
Migrate Heading and Text components from React Aria to native HTML el…
tjementum Dec 25, 2025
e836142
Migrate Breadcrumbs component from React Aria to ShadCN 2.0
tjementum Dec 25, 2025
55238cb
Migrate Form component from React Aria to native HTML form with FormV…
tjementum Dec 25, 2025
f1c41a0
Migrate ListBox component from React Aria to native HTML
tjementum Dec 25, 2025
b21af4e
Migrate ToggleButton component from React Aria to ShadCN 2.0 Toggle
tjementum Dec 25, 2025
cf5e2c7
Migrate Calendar and DatePicker components to ShadCN compatible React…
tjementum Dec 25, 2025
8f1bc34
Delete all unused React Aria components
tjementum Dec 25, 2025
25492bf
Remove remaining React Aria Component dependencies and complete ShadC…
tjementum Dec 25, 2025
dda6fa0
Update stock ShadCN Dialog with DialogBody for mobile full-screen and…
tjementum Jan 18, 2026
efb1c06
Update stock ShadCN DialogClose to support DirtyDialog cancel bypass …
tjementum Jan 18, 2026
06d7a41
Update ShadCN Select stock to add larger touch targets and display th…
tjementum Jan 18, 2026
05c3ba4
Update stock ShadCN BreadcrumbLink to include text-sm styling
tjementum Jan 18, 2026
f9f1f83
Update stock ShadCN DropdownMenu with w-auto width and larger touch t…
tjementum Jan 18, 2026
8bae7de
Update stock ShadCN Button destructive variant with solid background …
tjementum Jan 18, 2026
c67a6a5
Stabilize Firefox E2E tests under parallel load using dispatchEvent f…
tjementum Jan 19, 2026
35a7d1f
Update stock ShadCN AlertDialogMedia to vertically center icons and a…
tjementum Jan 19, 2026
87a3da8
Update TablePagination to use ShadCN pagination
tjementum Jan 19, 2026
e0feb43
Replace custom Avatar with stock ShadCN 2.0 Avatar component
tjementum Jan 19, 2026
bf44069
Replace custom TenantLogo implementation with stock ShadCN Avatar wra…
tjementum Jan 20, 2026
7fb06c9
Remove custom Image component in favor of native img with localized a…
tjementum Jan 20, 2026
cd0af90
Standardize heading elements with global styles and remove Heading co…
tjementum Jan 20, 2026
cb42e2b
Standardize icon sizing to use size-N utility
tjementum Jan 20, 2026
2dcdc2f
Replace deprecated social media icons and fix tooltips in PublicFooter
tjementum Jan 21, 2026
1db27fd
Enable hot reload for shared-webapp monorepo packages with source bui…
tjementum Jan 20, 2026
75f7264
Add README documenting UI component inventory and ShadCN divergences
tjementum Jan 21, 2026
03d9935
Ensure input and other UI components have consistent background colors
tjementum Jan 22, 2026
1b83b94
Update color theme to macOS-inspired dark mode
tjementum Jan 22, 2026
f0faee8
Ensure consistent focus ring when tabbing through the app using outli…
tjementum Jan 22, 2026
b75124d
Fix TenantSelector logo animation during sidebar collapse and expand
tjementum Jan 22, 2026
b26da4a
Increase interactive control heights to 44px for Apple HIG compliance…
tjementum Jan 22, 2026
24ee769
Fix support dialog not opening from mobile menu by moving state to pa…
tjementum Jan 22, 2026
57d739a
Reorder keyboard navigation to prioritize skip link and defer sidebar…
tjementum Jan 22, 2026
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
47 changes: 37 additions & 10 deletions .agent/rules/end-to-end-tests/end-to-end-tests.md
Original file line number Diff line number Diff line change
Expand Up @@ -80,34 +80,59 @@ These rules outline the structure, patterns, and best practices for writing end-
- Don't add timeouts to `.click()`, `.waitForSelector()`, etc.
- Global timeout configuration is handled in the shared Playwright—don't change this

8. Write deterministic tests for reliable testing:
8. Dropdown Menu Animation Handling:
- When clicking dropdown menu items (DropdownMenu, user profile menu, etc.), use `.dispatchEvent("click")` instead of regular `.click()`
- This is required because the DropdownMenu component has a 100ms animation and under parallel load Firefox doesn't reliably process regular clicks
- Pattern: Click trigger button, wait for menu visible, click menu item with dispatchEvent, verify menu closes
- Always wait for the menu to be visible before clicking: `await expect(page.getByRole("menu")).toBeVisible();`
- Don't use `waitForTimeout()` for menu animations - it causes focus loss which closes the dropdown

9. Write deterministic tests for reliable testing:
- Each test should have a clear, linear flow of actions and assertions
- Don't use if statements, custom error handling, or try/catch blocks in tests
- Don't use regular expressions in tests—use simple string matching instead

9. What to test:
- Enter invalid values such as empty strings, only whitespace characters, long strings, negative numbers, Unicode, etc.
- Tooltips, keyboard navigation, accessibility, validation messages, translations, responsiveness, etc.
10. What to test:
- Enter invalid values such as empty strings, only whitespace characters, long strings, negative numbers, Unicode, etc.
- Tooltips, keyboard navigation, accessibility, validation messages, translations, responsiveness, etc.

10. Test Fixtures and Page Management:
11. Test Fixtures and Page Management:
- Use appropriate fixtures: `{ page }` for basic tests, `{ anonymousPage }` for tests with existing tenant/owner but not logged in, `{ ownerPage }`, `{ adminPage }`, `{ memberPage }` for authenticated tests
- Destructure anonymous page data: `const { page, tenant } = anonymousPage; const existingUser = tenant.owner;`
- Pre-logged in users (`ownerPage`, `adminPage`, `memberPage`) are isolated between workers and will not conflict between tests
- When using pre-logged in users, do not put the tenant or user into an invalid state that could affect other tests

11. Test Data and Constants:
12. Test Data and Constants:
- Use underscore separators: `const timeout = 30_000; // 30 seconds`
- Generate unique data: `const email = uniqueEmail();`
- Use faker.js to generate realistic test data: `const firstName = faker.person.firstName(); const email = faker.internet.email();`
- Long string testing: `const longEmail = \`${"a".repeat(90)}@example.com\`; // 101 characters total`

12. Memory Management in End-to-End Tests:
13. Memory Management in End-to-End Tests:
- Playwright automatically handles browser context cleanup after tests
- Manual cleanup steps are unnecessary—focus on test clarity over micro-optimizations
- End-to-End test suites have minimal memory leak concerns due to their limited scope and duration

## Examples

### Dropdown Menu Clicks
```typescript
// ✅ DO: Use dispatchEvent for menu item clicks
await page.getByRole("button", { name: "User profile menu" }).click();
const menu = page.getByRole("menu");
await expect(menu).toBeVisible();
const menuItem = page.getByRole("menuitem", { name: "Log out" });
await expect(menuItem).toBeVisible();
await menuItem.dispatchEvent("click");

// ❌ DON'T: Use waitForTimeout - causes focus loss and menu closure
await page.getByRole("button", { name: "User profile menu" }).click();
const menu = page.getByRole("menu");
await expect(menu).toBeVisible();
await page.waitForTimeout(200); // Focus is lost, menu closes during wait
await page.getByRole("menuitem", { name: "Log out" }).click(); // Fails - menu is closed
```

### ✅ Good Step Naming Examples
```typescript
// ✅ DO: Business action + details & expected outcome
Expand All @@ -126,10 +151,12 @@ await step("Sign up with valid credentials & verify account creation")(async ()

await step("Update user role to admin & verify permission change")(async () => {
const userRow = page.locator("tbody tr").first();

await userRow.getByLabel("User actions").click();
await page.getByRole("menuitem", { name: "Change role" }).click();

const menu = page.getByRole("menu");
await expect(menu).toBeVisible();
await page.getByRole("menuitem", { name: "Change role" }).dispatchEvent("click");

await expect(page.getByRole("alertdialog", { name: "Change user role" })).toBeVisible();
})();
```
Expand Down
10 changes: 5 additions & 5 deletions .agent/rules/frontend/form-with-validation.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,11 @@ Guidelines for implementing forms with validation in the frontend, covering UI c

## Implementation

1. Use React Aria Components from `@repo/ui/components` for form elements
1. Use ShadCN components from `@repo/ui/components` for form elements
2. Use `api.useMutation` or TanStack's `useMutation` for form submissions
3. Use the custom `mutationSubmitter` to handle form submission and data mapping
4. Handle validation errors using the `validationErrors` prop from the mutation error
5. Show loading state in submit buttons
5. Show loading state in submit buttons using `disabled={mutation.isPending}`
6. For complex scenarios with multiple API calls, create a custom mutation with a `mutationFn`

## Anti-patterns
Expand Down Expand Up @@ -66,7 +66,7 @@ export function UserProfileForm({ user }) {
defaultValue={user?.title}
/>

<Button type="submit" isDisabled={updateUserMutation.isPending}>
<Button type="submit" disabled={updateUserMutation.isPending}>
{updateUserMutation.isPending ? <Trans>Saving...</Trans> : <Trans>Save changes</Trans>}
</Button>
</Form>
Expand Down Expand Up @@ -105,7 +105,7 @@ function BadUserProfileForm({ user }) {
<TextField name="lastName" defaultValue={user?.lastName} isRequired />
<TextField name="title" defaultValue={user?.title} />

<Button type="submit" isDisabled={isLoading}>
<Button type="submit" disabled={isLoading}>
{isLoading ? <Trans>Saving...</Trans> : <Trans>Save changes</Trans>}
</Button>
</Form>
Expand Down Expand Up @@ -160,7 +160,7 @@ export function UserProfileWithAvatarForm({ user, onSuccess, onClose }) {
>
{/* Form fields */}

<Button type="submit" isDisabled={saveMutation.isPending}>
<Button type="submit" disabled={saveMutation.isPending}>
{saveMutation.isPending ? <Trans>Saving...</Trans> : <Trans>Save changes</Trans>}
</Button>
</Form>
Expand Down
Loading
Loading