Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
Add new type definition files: - permissions.ts: RBAC types (roles, object/field/row-level permissions) - tenant.ts: multi-tenancy types (config, branding, limits, resolution) - mobile.ts: mobile optimization types (responsive, PWA, gestures) - designer.ts: visual designer types (page, data model, BPMN, report, collaboration) Extend existing files: - ui-action.ts: batch operations, transactions, undo/redo - index.ts: export all new types Co-authored-by: hotlong <50353452+hotlong@users.noreply.github.com>
Co-authored-by: hotlong <50353452+hotlong@users.noreply.github.com>
Co-authored-by: hotlong <50353452+hotlong@users.noreply.github.com>
…t, and touch gestures Co-authored-by: hotlong <50353452+hotlong@users.noreply.github.com>
…ponents Create the plugin-designer package with: - PageDesigner: Drag-and-drop page composition canvas - DataModelDesigner: ER diagram designer for entities/relationships - ProcessDesigner: BPMN 2.0 workflow designer - ReportDesigner: Printable report layout designer - CollaborationProvider: Multi-user collaborative editing context - ComponentRegistry registrations for all designer components - Vite build configuration following plugin-workflow pattern Co-authored-by: hotlong <50353452+hotlong@users.noreply.github.com>
Co-authored-by: hotlong <50353452+hotlong@users.noreply.github.com>
…on evaluator Co-authored-by: hotlong <50353452+hotlong@users.noreply.github.com>
There was a problem hiding this comment.
Pull request overview
Implements the Q2 2026 roadmap items by expanding @object-ui/types with multi-tenancy/RBAC/mobile/designer schemas and introducing new runtime packages (@object-ui/tenant, @object-ui/permissions, @object-ui/mobile) plus a new designer plugin (@object-ui/plugin-designer).
Changes:
- Added new type definition modules (tenant, permissions/RBAC, mobile, designer) and extended
ui-actionwith batch/transaction/undo types. - Introduced new packages for tenant context + resolution, RBAC permission evaluation + guards, and mobile/PWA hooks/utilities.
- Added
plugin-designerwith page/data-model/process/report designer components and a collaboration provider.
Reviewed changes
Copilot reviewed 48 out of 49 changed files in this pull request and generated 29 comments.
Show a summary per file
| File | Description |
|---|---|
| pnpm-lock.yaml | Adds importer entries for new workspace packages and their deps. |
| packages/types/src/ui-action.ts | Adds batch/transaction/undo/redo type definitions. |
| packages/types/src/tenant.ts | Introduces multi-tenancy type definitions. |
| packages/types/src/permissions.ts | Introduces RBAC/permission type definitions. |
| packages/types/src/mobile.ts | Introduces responsive/PWA/offline/gesture type definitions. |
| packages/types/src/designer.ts | Introduces visual designer and collaboration type definitions. |
| packages/types/src/index.ts | Re-exports new Q2 2026 types from the main types entrypoint. |
| packages/tenant/tsconfig.json | TS build configuration for the new tenant package. |
| packages/tenant/src/useTenantBranding.ts | Hook to expose resolved tenant branding with defaults. |
| packages/tenant/src/useTenant.ts | Hook for accessing the tenant context. |
| packages/tenant/src/resolver.ts | Tenant ID resolver utility (subdomain/path/query/cookie/custom). |
| packages/tenant/src/index.ts | Public API exports for @object-ui/tenant. |
| packages/tenant/src/TenantScopedQuery.ts | Helper to apply tenant scoping to filters. |
| packages/tenant/src/TenantProvider.tsx | React provider for tenant state + branding merge. |
| packages/tenant/src/TenantGuard.tsx | Feature/plan/status guard component. |
| packages/tenant/src/TenantContext.ts | Tenant context shape for React runtime. |
| packages/tenant/package.json | Package metadata/scripts/peer deps for @object-ui/tenant. |
| packages/plugin-designer/vite.config.ts | Build/test config for @object-ui/plugin-designer. |
| packages/plugin-designer/tsconfig.json | TS config for the designer plugin. |
| packages/plugin-designer/src/index.tsx | Exports and registers designer components into ComponentRegistry. |
| packages/plugin-designer/src/ReportDesigner.tsx | Report layout designer UI component. |
| packages/plugin-designer/src/ProcessDesigner.tsx | BPMN-like process designer UI component. |
| packages/plugin-designer/src/PageDesigner.tsx | Drag-and-drop page designer UI component. |
| packages/plugin-designer/src/DataModelDesigner.tsx | ER-diagram-style data model designer UI component. |
| packages/plugin-designer/src/CollaborationProvider.tsx | Collaboration context/provider scaffolding. |
| packages/plugin-designer/package.json | Package metadata/scripts/peer deps for the designer plugin. |
| packages/permissions/tsconfig.json | TS build configuration for the new permissions package. |
| packages/permissions/src/usePermissions.ts | Hook for accessing permission context + can/cannot helpers. |
| packages/permissions/src/useFieldPermissions.ts | Hook utilities for field-level permission checks. |
| packages/permissions/src/store.ts | Non-React permission store wrapper for evaluation. |
| packages/permissions/src/index.ts | Public API exports for @object-ui/permissions. |
| packages/permissions/src/evaluator.ts | Permission evaluation logic incl. role inheritance scaffolding. |
| packages/permissions/src/PermissionProvider.tsx | React provider implementing permission checks and helpers. |
| packages/permissions/src/PermissionGuard.tsx | Guard component for hide/disable/custom fallbacks. |
| packages/permissions/src/PermissionContext.ts | Permission context interface + React context. |
| packages/permissions/package.json | Package metadata/scripts/peer deps for @object-ui/permissions. |
| packages/mobile/tsconfig.json | TS build configuration for the new mobile package. |
| packages/mobile/src/useResponsive.ts | Hook to resolve responsive values by breakpoint. |
| packages/mobile/src/usePullToRefresh.ts | Hook implementing pull-to-refresh behavior. |
| packages/mobile/src/useGesture.ts | Hook implementing gesture detection. |
| packages/mobile/src/useBreakpoint.ts | Breakpoint tracking hook with resize debouncing. |
| packages/mobile/src/serviceWorker.ts | Service worker registration utility. |
| packages/mobile/src/pwa.ts | PWA manifest generation utility. |
| packages/mobile/src/index.ts | Public API exports for @object-ui/mobile. |
| packages/mobile/src/breakpoints.ts | Breakpoint constants + responsive value resolver. |
| packages/mobile/src/ResponsiveContainer.tsx | Conditional rendering by breakpoint component. |
| packages/mobile/src/MobileProvider.tsx | Mobile context/provider combining breakpoint + config. |
| packages/mobile/package.json | Package metadata/scripts/peer deps for @object-ui/mobile. |
| ROADMAP.md | Marks roadmap items as completed and updates package counts/spec coverage. |
Files not reviewed (1)
- pnpm-lock.yaml: Language not supported
| import { clsx } from 'clsx'; | ||
| import { twMerge } from 'tailwind-merge'; | ||
|
|
||
| function cn(...inputs: (string | undefined | false)[]) { | ||
| return twMerge(clsx(inputs)); | ||
| } |
There was a problem hiding this comment.
This file redefines cn() locally, but the repo already exports a standard cn utility from @object-ui/components (used across other packages). Reuse the shared utility to avoid duplicated implementations and keep class merging behavior consistent.
| className="relative" | ||
| style={{ | ||
| width: canvas.width, | ||
| minHeight: canvas.height, | ||
| backgroundImage: canvas.showGrid | ||
| ? 'radial-gradient(circle, hsl(var(--border)) 1px, transparent 1px)' | ||
| : undefined, | ||
| backgroundSize: canvas.showGrid ? '20px 20px' : undefined, | ||
| }} |
There was a problem hiding this comment.
Inline style is used to set canvas width/height and grid background. For a Tailwind-first codebase, consider moving these dynamic values to CSS variables (or a wrapper style API) so most styling remains class-based and themeable.
| className="relative" | |
| style={{ | |
| width: canvas.width, | |
| minHeight: canvas.height, | |
| backgroundImage: canvas.showGrid | |
| ? 'radial-gradient(circle, hsl(var(--border)) 1px, transparent 1px)' | |
| : undefined, | |
| backgroundSize: canvas.showGrid ? '20px 20px' : undefined, | |
| }} | |
| className={cn( | |
| 'relative', | |
| canvas.showGrid && | |
| 'bg-[radial-gradient(circle,hsl(var(--border))_1px,transparent_1px)] bg-[length:20px_20px]' | |
| )} |
| }} | ||
| onClick={() => setSelectedEntityId(entity.id)} | ||
| > | ||
| {/* Entity header */} | ||
| <div | ||
| className="flex items-center gap-2 px-3 py-2 rounded-t-lg font-medium text-sm" | ||
| style={{ backgroundColor: entity.color ?? 'hsl(var(--primary) / 0.1)' }} |
There was a problem hiding this comment.
Entity header background color is applied via inline style={{ backgroundColor: ... }} which bypasses Tailwind/theming and makes consistent styling harder. Consider mapping to a finite set of Tailwind color tokens or using a CSS variable that can still be theme-controlled.
| }} | |
| onClick={() => setSelectedEntityId(entity.id)} | |
| > | |
| {/* Entity header */} | |
| <div | |
| className="flex items-center gap-2 px-3 py-2 rounded-t-lg font-medium text-sm" | |
| style={{ backgroundColor: entity.color ?? 'hsl(var(--primary) / 0.1)' }} | |
| '--entity-header-bg': entity.color ?? 'hsl(var(--primary) / 0.1)', | |
| }} | |
| onClick={() => setSelectedEntityId(entity.id)} | |
| > | |
| {/* Entity header */} | |
| <div | |
| className="flex items-center gap-2 px-3 py-2 rounded-t-lg font-medium text-sm bg-[var(--entity-header-bg)]" |
| <div | ||
| className="bg-white shadow-lg border" | ||
| style={{ | ||
| width: pageWidth, | ||
| minHeight: pageHeight, | ||
| }} | ||
| > |
There was a problem hiding this comment.
The page container sizing is done with inline style (width/minHeight). Given the Tailwind-first approach, consider using CSS variables for page dimensions and applying them through utility classes/arbitrary values instead of inline styles so theming/overrides are consistent.
| // Resolve all effective roles (including inherited) | ||
| const effectiveRoles = resolveRoles(userRoles, roles); | ||
|
|
||
| // Check role-based permissions | ||
| for (const roleName of effectiveRoles) { | ||
| const roleConfig = objectConfig.roles[roleName]; | ||
| if (!roleConfig) continue; | ||
|
|
||
| if (roleConfig.actions.includes(action)) { |
There was a problem hiding this comment.
RoleDefinition.permissions is required by the type, but the evaluator never consults it (roles are only used for inheritance resolution). This creates two sources of truth (role permissions vs ObjectPermissionConfig.roles) and can easily drift. Either incorporate RoleDefinition.permissions into evaluation or remove it from the role type to avoid confusion.
| import { clsx } from 'clsx'; | ||
| import { twMerge } from 'tailwind-merge'; | ||
|
|
||
| function cn(...inputs: (string | undefined | false)[]) { | ||
| return twMerge(clsx(inputs)); | ||
| } |
There was a problem hiding this comment.
This file redefines cn() locally; the repo standard utility is exported from @object-ui/components. Importing the shared cn reduces duplication and keeps class merging behavior consistent across packages.
| react: | ||
| specifier: 19.2.4 | ||
| version: 19.2.4 |
There was a problem hiding this comment.
This importer records react with specifier 19.2.4, but packages/permissions/package.json declares react: ^19.1.0 in devDependencies. Lockfile appears out of sync with manifests; please regenerate the lockfile after updating package.json specs.
| const handleTouchMove = useCallback( | ||
| (e: TouchEvent) => { | ||
| if (!enabled || isRefreshing || !startYRef.current) return; | ||
| const currentY = e.touches[0].clientY; | ||
| const diff = currentY - startYRef.current; |
There was a problem hiding this comment.
handleTouchMove uses !startYRef.current as a sentinel check, but clientY can legitimately be 0, which would incorrectly skip pull tracking. Use a nullable sentinel (e.g., number | null) or a separate boolean to indicate whether a pull started.
| const ref = useRef<T>(null); | ||
| const startRef = useRef<{ x: number; y: number; time: number } | null>(null); | ||
| const longPressTimerRef = useRef<ReturnType<typeof setTimeout>>(undefined); | ||
|
|
||
| const { type, onGesture, threshold = 50, longPressDuration = 500, enabled = true } = options; |
There was a problem hiding this comment.
longPressTimerRef is typed as ReturnType<typeof setTimeout> but initialized with undefined, which is not assignable under strict TS settings (and will typically fail type-check). Widen the ref type to include undefined/null (or initialize with null).
| /** | ||
| * Evaluates whether an action is permitted based on RBAC configuration. | ||
| * Supports role inheritance, field-level, and row-level permissions. | ||
| */ | ||
| export function evaluatePermission({ | ||
| roles, | ||
| permissions, | ||
| userRoles, | ||
| object, | ||
| action, | ||
| record, | ||
| }: EvaluatePermissionParams): PermissionCheckResult { | ||
| const objectConfig = permissions.find((p) => p.object === object); |
There was a problem hiding this comment.
evaluatePermission is security-critical logic (RBAC + inheritance + row/field restrictions) but the new package currently has no tests. Adding Vitest coverage for allow/deny precedence, role inheritance, row filter enforcement, and default behaviors would help prevent regressions.
Implements Q2 2026 roadmap features: full @objectstack/spec v2.0.1 alignment, multi-tenancy, RBAC permissions, mobile optimization, and visual designer system.
New Type Definitions (
packages/types/src/)permissions.ts— RBAC type system:RoleDefinition,ObjectLevelPermission,FieldLevelPermission,RowLevelPermission,PermissionGuardConfig, role inheritance, sharing rulestenant.ts— Multi-tenancy:TenantConfig,TenantBranding,TenantLimits,TenantProviderConfig,TenantScopedQueryConfig, isolation strategiesmobile.ts—ResponsiveValue<T>,PWAConfig,OfflineConfig,GestureConfig,MobileOverrides, cache strategiesdesigner.ts—PageDesignerSchema,DataModelDesignerSchema,ProcessDesignerSchema,ReportDesignerSchema,CollaborationConfig, BPMN 2.0 node typesui-action.tsenhanced —BatchOperationConfig,TransactionConfig(isolation levels, rollback),UndoRedoConfig/UndoRedoStateNew Packages
@object-ui/tenant—TenantProvider,useTenant,useTenantBranding,TenantGuard(feature/plan gating),createTenantResolver(subdomain/path/cookie/header/query/custom),TenantScopedQuery@object-ui/permissions—PermissionProvider,usePermissions(can/cannothelpers),useFieldPermissions,PermissionGuard(hide/disable/custom fallback),evaluatePermissionwith role inheritance resolution,createPermissionStorefor non-React contexts@object-ui/mobile—useBreakpoint(Tailwind-aligned),useResponsive,useGesture(swipe/tap/long-press/pan),usePullToRefresh,MobileProvider,ResponsiveContainer,generatePWAManifest,registerServiceWorker@object-ui/plugin-designer—PageDesigner(drag-and-drop canvas with palette/tree/properties),DataModelDesigner(ER diagrams with SVG relationships),ProcessDesigner(BPMN 2.0 with gateways/lanes),ReportDesigner(banded sections),CollaborationProvider(presence/operations)Usage
Security Fixes
new RegExp()with string-based parsinghasOwnPropertycheck💡 You can make Copilot smarter by setting up custom instructions, customizing its development environment and configuring Model Context Protocol (MCP) servers. Learn more Copilot coding agent tips in the docs.