Commit Graph
6378 Commits
Author SHA1 Message Date
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
Oleg Isonen 8292755fb6 fix: remove redundant title prefixes and use design system wrappers in stories\n\n- Remove redundant Builder/ prefix from 9 builder story titles (titlePrefix already adds it)\n- Remove redundant Design System/ prefix from 6 design-system story titles\n- Replace raw <div style={}> with Box/Flex and theme tokens in dashboard card/thumbnail stories 2026-03-14 16:14:14 +00:00
Oleg Isonen 2bdd6fd8e1 refactor: dissolve features/topbar into standalone features\n\n- Move share, clone, safe-mode, builder-mode, view-mode, sync-status directly under features/\n- Move publish cluster (publish, domains, add-domain, entri, cname) into features/publish/\n- Move menu into features/menu/\n- Move topbar-layout (utility) and topbar (composition) into shared/\n- Remove spinner story (animated SVG causes flaky visual tests)\n- Remove avatar NoImageNoFallback variant (invalid state)\n- Update story titles to reflect new structure 2026-03-14 15:47:19 +00:00
Oleg Isonen a06bedb8fc feat: add visual regression stories for style panel, dashboard, and design system components 2026-03-14 14:59:00 +00:00
Oleg Isonen ae872f520d refactor: rename "Manage members" to "Members", remove menu icons
- Rename dialog title and dropdown item from "Manage members" to "Members"
- Remove icons from workspace selector dropdown menu items
- Remove separator before Delete item
- Set withIndicator={false} to fix indentation without icons
2026-03-14 14:26:04 +00:00
Oleg Isonen 8880da1ac4 refactor: rename MemberRelation → WorkspaceRelation, remove permissions prop-drilling, unify shared stores
- Rename userRelation → workspaceRelation across schema, DB, router, and UI
- Rename MemberRelation type → WorkspaceRelation everywhere
- Create canonical UserPlanFeatures/UserPurchase module in trpc-interface
- Make userPlanFeatures non-optional in AppContext
- Separate purchases from UserPlanFeatures
- Compute workspaceRelation in route loaders instead of consumer sites
- Add $workspaceRelation atom, use real relation in $permissions computed
- Remove permissions prop-drilling from all dashboard components
- Leaf components use useStore($permissions) directly
- Create setSharedStores() for unified store initialization
- Combine workspace + membership into single PostgREST query in builder route
- Replace purchases.length checks with canDownloadAssets/canRestoreBackups
- getUserPlanFeatures() → getUserPlanInfo() returning { userPlanFeatures, purchases }
2026-03-14 14:14:14 +00:00
Oleg Isonen bd3f596247 feat: workspace member permissions and plan-based action gating
- Add unified getPermissions() combining role + plan permissions
- Gate project actions (create, delete, publish, share, etc.) by workspace role
- Introduce MemberRelation schema (owners/admins/builders/viewers)
- Compute $permissions from $userPlanFeatures + $authPermit in nano-states
- Set $userPlanFeatures globally in DashboardSetup (matching builder pattern)
- Add workspace dialogs for managing members and invitations
- Enforce permissions across dashboard, builder, and settings UI
2026-03-14 11:57:07 +00:00
Oleg Isonen c47672144d feat: add workspace selector and dialogs stories, fix missing feature-flags dep 2026-03-14 01:58:08 +00:00
Oleg Isonen aac71ffaa8 fix: add WorkspaceMember FK/index, clone workspace inheritance, addMember response parity 2026-03-14 01:47:35 +00:00
Oleg Isonen ed6ffc24f1 fix: workspace security hardening and cleanup\n\n- Add membership check when creating projects in a workspace\n- Remove placeholder user creation on invite (prevent DB pollution)\n- Show invited emails client-side to prevent email enumeration\n- Show only email in member rows (no username leak)\n- Throw on workspace plan resolution error instead of silent fallback\n- DRY navigation items in dashboard sidebar\n- Replace null with empty string in listMembers return\n- Restore useEffect in DashboardSetup to fix React render warning 2026-03-14 01:27:53 +00:00
Oleg Isonen 8a7f98b3f9 fix: code review fixes — shared soft-delete, project ownership, cleanup
- Extract softDeleteProject helper so unique domain invariant lives in one place
- Projects created in a workspace are owned by workspace owner, not creator
- Remove unnecessary useEffect around $data.set
- Remove unused parseTrpcError helper
- Remove unsafe `as TokenAuthPermit` cast
- Add sortWorkspaces tests
- Document idempotent retry safety in workspace remove()
2026-03-14 00:46:40 +00:00
Oleg Isonen ee6a830d82 feat: delete workspace with projects and redirect on stale workspace URL
- Backend: accept deleteProjects flag to soft-delete all projects before removing workspace
- Frontend: warning text mentions all projects will be deleted, with 'All projects' in red
- Dashboard: detect stale workspaceId in URL and redirect to default workspace
2026-03-13 23:36:46 +00:00
Oleg Isonen 0fde5063fb feat: workspace ownership-based UI restrictions and avatar
- Pass userId to WorkspaceSelector for ownership checks
- Disable Rename/Delete menu items for non-owners
- Hide invite input and remove buttons for non-owners in ManageMembersDialog
- Add empty state for member list
- Add Avatar with small size variant (data-size attribute) to workspace selector
- Use userId prop instead of isOwner boolean for future role extensibility
2026-03-13 21:40:03 +00:00
Oleg Isonen a1a4410353 feat: workspace management dialogs and UI improvements
- Add workspace dialogs: create, rename, manage members, delete
- Rewrite workspace selector as dropdown menu with action items
- Support comma-separated multi-email member invites
- Create placeholder users for non-existing email invites
- Add ScrollAreaNative component with native thin scrollbar
- Show newest members first in member list
- Preserve workspaceId query param in navigation links
- Fix DashboardSetup to use useEffect for data sync
2026-03-13 12:33:55 +00:00
Oleg Isonen ed493d1e3a feat: workspace selector with ghost Select, remove collapsible section\n\n- Add color='ghost' variant to SelectButton (transparent bg, hover highlight)\n- Pass color prop through Select to SelectButton\n- Rewrite workspace selector to use Select with color='ghost'\n- Render workspace selector directly in sidebar nav (no CollapsibleSection) 2026-03-12 22:11:27 +00:00
Oleg Isonen 51011394a4 feat: stage 8 — dashboard workspace selector UI\n\n- Add WorkspaceSelector component with design system Select\n- Wire workspace selector into dashboard sidebar (feature-flagged)\n- Update shouldRevalidate to reload data on workspace switch\n- Pass currentWorkspaceId through to CreateProject so new projects\n are created in the currently viewed workspace\n- Rename sidebar section from \"Workspace\" to \"Navigation\" when\n workspace selector is visible 2026-03-12 21:46:46 +00:00
Oleg Isonen 2a04b0eb50 feat: workspace members get access to workspace projects\n\n- Add WorkspaceProjectAuthorization SQL view (workspace owner = own, members = their relation)\n- Update authorization check() to query workspace view when flag is on\n- Dashboard findMany filters by workspaceId instead of userId for workspace members\n- Builder resolves plan features from workspace owner when project belongs to a workspace\n- Add @webstudio-is/feature-flags dependency to trpc-interface and dashboard packages 2026-03-12 21:22:51 +00:00
Oleg Isonen 4748940abd feat(workspaces): workspace member management backend (Stage 6)
Add/remove/list workspace members by email.

- addMember: owner-only, looks up user by email, inserts as
  administrator, rejects duplicates and self-add
- removeMember: owner-only, prevents removing the owner
- listMembers: visible to owner and members, returns user email/username

tRPC procedures: workspace.addMember, workspace.removeMember,
workspace.listMembers.
2026-03-12 20:59:28 +00:00