6395 Commits
Author SHA1 Message Date
Oleg Isonen f9371e6aea ::migrate:: run workspace migration on dev 2026-03-19 15:02:58 +00:00
Oleg Isonen fdc9b01d10 revert: restore original migrate.yaml workflow 2026-03-19 15:02:34 +00:00
Oleg Isonen 6e975169bd ci: gate migrate follow-up jobs to ::migrate:: commits ::migrate:: 2026-03-19 14:39:05 +00:00
Oleg Isonen 4c27710a42 fix: allow migrate trigger anywhere and fix builder typecheck ::migrate:: 2026-03-19 14:34:54 +00:00
Oleg Isonen e76c7e7621 ci: allow feat/** branches and ::migrate:: anywhere in message ::migrate:: 2026-03-19 14:25:26 +00:00
Oleg Isonen 7aa8fb09ea ::migrate:: 2026-03-19 14:22:18 +00:00
Oleg Isonen b7b5da7afa ::migrate:: fix: workspace review fixes — auth view, clone errors, remove order, approval filter, cleanup 2026-03-19 14:16:20 +00:00
Oleg Isonen ae5814cfcf fix: remove OwnedWorkspaces story, fix notification typecheck errors\n\n- Delete unused OwnedWorkspaces story from transfer-dialog.stories\n- Add missing projectTitle/workspaceName to notification story items\n- Fix JsonifyObject incompatibility for notifications in dashboard route 2026-03-18 08:59:57 +00:00
Oleg Isonen bcf55861e3 fix: dashboard stories crashing on missing notifications
The story data object was missing the `notifications` field added to
DashboardData, causing seedNotifications to call .filter() on undefined.
2026-03-18 08:46:41 +00:00
Oleg Isonen a076c7806d refactor: decouple notification popover from notification types
Move description generation to the server (notification.list) so the
popover renders a pre-built string. Adding a new notification type
now only requires updating describeNotification on the server — the
UI stays generic.

- Remove discriminated union types and WorkspaceInvitePayload import
  from notification-popover.tsx
- NotificationItem is now derived from the server return type
- Move getDescription tests → describeNotification tests
- Remove unused __testing__ export from cross-tab-manager.ts
2026-03-18 08:44:11 +00:00
Oleg Isonen 585c3a6f35 feat: cross-tab polling deduplication for Polly
Only one browser tab actively polls the server. Other tabs receive
data via BroadcastChannel, eliminating duplicate network requests.

- Leader election via heartbeat protocol (lowest tab-id wins)
- Instant failover on leader tab close (abdication broadcast)
- Follower topic sync so leader tracks all tabs' subscriptions
- Drop-in replacement for createPollingManager (same interface)
- Dashboard subscription now uses createCrossTabPollingManager
- 10 new tests (leader election, failover, topic sync, destroy)
- Future topic ideas documented in types.ts registry comment
2026-03-18 08:35:59 +00:00
Oleg Isonen 96cc8d9c58 feat: real-time notification polling with toast and browser alerts
Add a universal topic-based polling system (polly) that replaces the
old notification-store with a more extensible architecture:

- Backoff, polling-client, polling-manager with full test coverage (86 tests)
- Server-side topic resolvers + tRPC subscription router
- Dashboard subscription wiring with loader-seeded notifications
- In-app toast as primary alert, browser Notification as supplement
- Notification popover reads from shared nanostore atom
- project-queue.ts uses polly backoff, tests migrated to vi.mock()
2026-03-18 08:03:33 +00:00
Oleg Isonen 873e40a5c8 feat: revoke invite wiring, store, maxProjectsAllowedPerUser, transfer/move guards
- notification.create returns notification ID
- addMember returns notificationId (fake UUID for non-existent users)
- workspace router exposes notificationId in addMember response
- workspace-dialogs: trash button calls notification.cancel with stored ID
- replace $userEmail atom with $user storing full User object
- add maxProjectsAllowedPerUser to UserPlanFeatures + all plan constructors
- plan-limit check on transfer accept
- global dedup: one pending transfer per project
- notification.cancel endpoint
- cross-owner move restriction in moveProject
- self-transfer check in transfer dialog
2026-03-17 21:08:41 +00:00
Oleg Isonen a0ff1e6783 fix: notification popover story renders open with mock data, remove impossible NoWorkspaces transfer story 2026-03-17 18:32:48 +00:00
Oleg Isonen 3ff41c5b55 refactor: extract shared WorkspaceDropdown component\n\n- Create workspace-dropdown.tsx with reusable dropdown (trigger + radio groups + children slot)\n- Refactor workspace-selector to use WorkspaceDropdown with color=ghost and action items as children\n- Refactor transfer-dialog to use WorkspaceDropdown without color prop and no action items\n- Add OR separator between workspace and recipient sections 2026-03-17 17:34:40 +00:00
Oleg Isonen c3dab01e30 fix: transfer dialog uses DropdownMenu for workspace selection, full-width separator 2026-03-17 15:41:02 +00:00
Oleg Isonen 17ea428a64 fix: transfer dialog defaults to current workspace, adds separator before email 2026-03-17 15:36:56 +00:00
Oleg Isonen ecd7133752 ::migrate:: apply workspace and notification migrations 2026-03-17 15:11:07 +00:00
Oleg Isonen 9ec8896b5b feat: add stories for transfer dialog and notification popover 2026-03-17 15:04:46 +00:00
Oleg Isonen bddab370c1 ::migrate:: 2026-03-17 14:59:24 +00:00
Oleg Isonen f2a0d96ae0 test: add canTransfer to permissions test expectations 2026-03-17 14:51:21 +00:00
Oleg Isonen 4dfe557aa7 feat: add project transfer and move functionality
- Add transfer dialog with workspace selector and email input
- Support moving projects between workspaces (instant) and
  transferring to another user via notification (async)
- Add project transfer notification type with accept/decline flow
- Verify sender ownership and auto-decline stale transfers
- Add audit logging for ownership changes
- Add canTransfer permission for owners and admins
- Use camelCase notification types (workspaceInvite, projectTransfer)
- Use .select("id").single() on all notification status updates
- Debounce email search with stale response rejection
- Use Set-based loading state for concurrent notification actions
- Filter unknown notification types before rendering
- Use theme tokens for all spacing values
2026-03-17 13:14:45 +00:00
Oleg Isonen b43f67701d feat: notification pipeline and workspace invite flow
- Add Notification model with pending/accepted/declined status
- Add WorkspaceMember soft-delete via removedAt column
- Create notification CRUD (create, list, count, accept, decline)
- Wire addMember to create notifications instead of direct insert
- Accept handler upserts WorkspaceMember, verifies workspace exists
- 7-day TTL expiration on all notification queries
- Idempotent duplicate detection for pending invites
- Add bell icon with dot indicator and notification popover
- Add notification tRPC router (list, count, accept, decline)
- Refactor dashboard findMany to object params with UUID validation
- Add toast errors on accept/decline failures
- Anti-enumeration: silent succeed for non-existent emails
2026-03-17 01:01:06 +00:00
Oleg Isonen efb81f69e9 feat: make workspaces non-optional in getPermissions and DashboardData 2026-03-16 21:04:23 +00:00
Oleg Isonen ff06f58e32 feat: workspace downgrade — revoke member access when owner's plan drops
When a workspace owner's plan no longer supports workspaces (maxWorkspaces <= 1),
member access is revoked while preserving workspace data and memberships:

- Add getOwnerPlanFeatures callback to AppContext for cross-user plan lookups
- Check workspace owner plan in hasProjectPermit to deny non-owner access
- Mark member workspaces as isDowngraded in findMany based on owner plan
- Gate updateWorkspaceRelation behind maxWorkspaces check
- Block downgraded workspace members in builder route loader
- Show ProBadge "Suspended" and disable selection for downgraded workspaces
2026-03-16 19:43:51 +00:00
Oleg Isonen b8d4e60928 feat: always show workspace selector, minimum 1 workspace, gate members on plan 2026-03-16 18:30:47 +00:00
Oleg Isonen aa32e08c53 feat: refactor dashboard sidebar to Grid layout with workspace separator and update neutral notification color 2026-03-16 16:53:06 +00:00
Oleg Isonen 50630640d7 fix: move Free badge outside profile button to prevent layout overflow 2026-03-16 16:19:19 +00:00
Oleg Isonen ab8b0ab429 fix: filter null relations in workspace authorization query 2026-03-16 16:01:09 +00:00
Oleg Isonen b8d07af7e6 feat: gate workspace features behind maxWorkspaces plan limit
- Replace workspaces feature flag with maxWorkspaces-based gating
- Default maxWorkspaces to 0 (controlled via MAX_WORKSPACES env var)
- Skip workspace queries in dashboard loader when maxWorkspaces is 0
- Extract pure functions (resolveCurrentWorkspace, isWorkspaceRelationPermitted, getView) with tests
- Remove workspaces feature flag from all files
2026-03-16 15:58:16 +00:00
Oleg Isonen 67153dba0e feat: dashboard welcome view, profile name, and template approval bypass
- Show user name next to profile avatar in dashboard sidebar
- Separate welcome view from templates into its own component
- Welcome subtitle with create blank project button (permission-gated)
- Allow PROJECT_TEMPLATES to skip marketplace approval check
- Templates view shows clean "Starter templates" title
2026-03-16 10:08:05 +00:00
Oleg Isonen d06e56d8a0 Update menu.stories.tsx 2026-03-16 00:34:10 +00:00
Oleg Isonen 3601aa6604 ::migrate::workspaces schema 2026-03-16 00:33:55 +00:00
Oleg Isonen d542352a6c Merge branch 'feat/workspaces' into feat/workspaces-rebased
# Conflicts:
#	apps/builder/app/builder/features/menu/menu.tsx
#	apps/builder/app/dashboard/dashboard.stories.tsx
2026-03-16 00:17:07 +00:00
Oleg Isonen c4d26cbf62 chore: more stories updates (#5646)
## Description

1. What is this PR about (link the issue and add a short description)

## Steps for reproduction

1. click button
2. expect xyz

## Code Review

- [ ] hi @kof, I need you to do
  - conceptual review (architecture, feature-correctness)
  - detailed review (read every line)
  - test it on preview

## Before requesting a review

- [ ] made a self-review
- [ ] added inline comments where things may be not obvious (the "why",
not "what")

## Before merging

- [ ] tested locally and on preview environment (preview dev login:
0000)
- [ ] updated [test
cases](https://github.com/webstudio-is/webstudio/blob/main/apps/builder/docs/test-cases.md)
document
- [ ] added tests
- [ ] if any new env variables are added, added them to `.env` file
2026-03-15 22:19:30 +01:00
Oleg Isonen 91d2136921 refactor(stories): consolidate exports, add StorySection/StoryGrid everywhere, remove argTypes/args 2026-03-15 19:21:33 +00:00
Oleg Isonen 2216adf4f0 fix: expand story coverage and apply sentence case to all story titles
- Add new story variants across ~100 files covering previously untested props
- Fix all story titles to use sentence case per UI label guidelines
- Consolidate duplicate card, thumbnail, and value-text stories into parent files
- Add interactive/controlled variants for checkbox, radio, switch, select, etc.
- Add style source, disabled, icon, placeholder, unit options variants to CssValueInput
- Add sub-menu, radio group, destructive, and disabled variants to dropdown/context menus
- Add dialog resize, maximize, actions, and non-draggable variants
- Add popover title, actions, and side placement variants
- Add tooltip side placements and content variant stories
2026-03-15 15:34:17 +00:00
Oleg Isonen 9d9331cb32 chore: update sdk-components-animation submodule 2026-03-15 13:53:28 +00:00
Oleg Isonen 8cab7763d5 fix: rename single-story exports, add sidebarWidth wrapping, improve variant coverage\n\nRename 22 single-story exports to match their title (e.g. Basic/Story/Default\n→ ComponentName) to eliminate unnecessary Storybook sidebar nesting.\n\nWrap all settings-panel and style-panel stories in theme.sizes.sidebarWidth\nfor realistic rendering width.\n\nImprove variant coverage in kbd, style-source-badge, and other stories." 2026-03-15 13:48:56 +00:00
Oleg Isonen 211f4e9b2d improve story variant coverage and fix TS errors
- separator: add horizontal + vertical orientations
- kbd: add color variants, regular variant, diverse key combos
- search-field: add autoFocus and disabled states
- component-card: add description/tooltip, state labels, remove storyName
- enhanced-tooltip: add JSX content, side placements, custom delay
- style-source-badge: add all 5 source variants + truncation test
- text: add full variant, color, alignment, truncate, userSelect coverage
- fix keyboard-shortcuts-dialog import alias conflict
- fix inset-layout renderCell signature and CssProperty types
- fix asset-manager broken component reference
2026-03-15 13:43:03 +00:00
Oleg Isonen f62a34bbff fix: resolve naming conflicts in story exports and fix TS errors\n\nAlias component imports to avoid conflicts with story export names\n(e.g., import { Card as CardComponent }). Fix unused imports/variables\nin about.stories.tsx and css-value-input.stories.tsx. Fix CssProperty\ntype, help-center icon, and typeof self-references. 2026-03-15 12:46:51 +00:00
Oleg Isonen 64e5c17129 fix: stories render open by default, remove Demo nesting, use data URLs for images
- Make interaction-requiring stories render content immediately:
  - import-redirects-dialog: render dialog open directly
  - context-menu: use DropdownMenu with defaultOpen
  - enhanced-tooltip: add defaultOpen prop
  - tooltip: add open prop, pre-populate error state
  - command-panel: call openCommandPanel() on mount
  - toast: remove interactive InAction story

- Rename single 'Demo' exports to match component names,
  eliminating redundant navigation nesting in Storybook
  (e.g. 'Search Preview / Demo' → 'Search Preview')

- Replace external image URLs with inline data:image/svg+xml:
  - avatar: pravatar.cc → inline SVG
  - marketplace/card: placehold.co → inline SVG
  - search-preview: favicon.ico → inline SVG
  - animate-children-scroll: unsplash → inline gradient SVG
  - toast: Blob/createObjectURL → inline data URL
2026-03-15 12:29:53 +00:00
Oleg Isonen f733bdf20a more stories 2026-03-15 11:28:23 +00:00
Oleg Isonen 32d641c286 refactor: remove trivial crossAxis/mainAxis aliases in shouldHideDot 2026-03-15 10:02:06 +00:00
Oleg Isonen 706a7254d4 fix: alignment UI dot hiding, stories, and unit tests
- Fix shouldHideDot axis mapping: x always maps to justify-content
  (main-axis), y always maps to align-items (cross-axis). The visual
  transposition for column direction is handled by the CSS grid swap
  in the render code, not in the dot-hiding logic.
- Export shouldHideDot and cover with 21 unit tests.
- Refactor stories into Flex_ and Grid_ combination grids showing
  all alignItems x justifyContent combinations.
- Delete old flex-alignment.stories.tsx (used hooks, could not work).
2026-03-15 09:57:51 +00:00
Oleg Isonen 7d308a5a7f fix: hide alignment UI dots at line intersections to avoid sub-pixel artifacts
- Rewrite shouldHideDot as cross-axis × main-axis intersection check
- Use visibility:hidden instead of conditional rendering to preserve layout
- Consolidate stories into FlexRow/FlexColumn combination grids
- Include normal/default values in story combinations
- Use real style panel dimensions (64×62)
2026-03-15 09:31:09 +00:00
Oleg Isonen f2a10ada38 unneded 2026-03-15 09:11:20 +00:00
Oleg Isonen 0107eb8c4d fix: support data URIs in Image component, clean up stories
- Skip loader/optimization for data: src in getImageAttributes
- Replace external picsum.photos URL with inline SVG data URI in social-preview story
- Remove unnecessary ThumbnailWrapper from thumbnail stories
2026-03-15 09:02:56 +00:00
Oleg Isonen b67aaafe15 chore: delete unused ai-command-bar components and stories 2026-03-15 08:51:42 +00:00
Oleg Isonen d250b9bd02 test 2026-03-15 08:33:50 +00:00