All notable changes to this project will be documented in this file.
The format is based on Keep a Changelog, and this project adheres to Semantic Versioning.
-
Unified metadata management architecture (
@object-ui/console): New centralized metadata type registry (config/metadataTypeRegistry.ts) that defines all manageable metadata categories (app, object, dashboard, page, report) as configuration entries. Registry-driven approach eliminates code duplication — adding a new metadata type requires only a single config entry. IncludesgetMetadataTypeConfig(),getGenericMetadataTypes(), andgetHubMetadataTypes()helpers. -
Generic MetadataManagerPage (
@object-ui/console): New reusable page component (pages/system/MetadataManagerPage.tsx) for listing and managing metadata items of any registered type. Driven by the:metadataTypeURL parameter, it fetches items viaMetadataService.getItems(), supports search filtering, soft-delete with confirm pattern, and displays items in a responsive card grid. Routes:/system/metadata/:metadataType. -
Generic MetadataService methods (
@object-ui/console): ExtendedMetadataServicewithgetItems(category),saveMetadataItem(category, name, data), anddeleteMetadataItem(category, name)methods that work for any metadata type, complementing the existing object/field-specific methods. -
SystemHubPage registry integration (
@object-ui/console): RefactoredSystemHubPageto auto-generate metadata type cards from the registry instead of hardcoded arrays. New cards (Dashboards, Pages, Reports) appear automatically. Types with custom pages (app, object) link to their existing routes; generic types link to the unified MetadataManagerPage. No breaking changes — all existing hub cards (Users, Orgs, Roles, etc.) remain unchanged. -
Dynamic routing for metadata types (
@object-ui/console): Added/system/metadata/:metadataTyperoutes across all three route blocks (SystemRoutes, AppContent minimal, AppContent full) so the generic manager is accessible from both top-level/system/*and app-scoped/apps/:appName/system/*contexts. -
Metadata service layer (
@object-ui/console): NewMetadataServiceclass (services/MetadataService.ts) that encapsulates object and field CRUD operations against the ObjectStack metadata API (client.meta.saveItem). ProvidessaveObject(),deleteObject(), andsaveFields()methods with automatic cache invalidation. Includes staticdiffObjects()anddiffFields()helpers to detect create/update/delete changes between arrays. CompanionuseMetadataServicehook (hooks/useMetadataService.ts) provides a memoised service instance from theuseAdapter()context. 16 new unit tests.
-
Object/field changes now persist to backend (
@object-ui/console): RefactoredObjectManagerPageso thathandleObjectsChangeandhandleFieldsChangecall the MetadataService API instead of only updating local state. Implements optimistic update pattern — UI updates immediately, rolls back on API failure. After successful persistence, the MetadataProvider is refreshed so changes survive page reloads. Toast messages now accurately reflect the operation performed (create/update/delete) and display error details on failure. Added saving state indicators with a loading spinner during API operations. -
ObjectManager & FieldDesigner read-only grid fix (
@object-ui/plugin-designer): Addedoperations: { create: true, update: true, delete: true }to theObjectGridSchemain bothObjectManagerandFieldDesignercomponents. The realObjectGridrequiresschema.operationsto render action buttons (add/edit/delete); without it, the grid renders as read-only regardless of thereadOnlyprop or callback handlers. Theoperationsproperty is now conditionally set based on thereadOnlyprop. -
FieldDesigner modal dialog for add/edit (
@object-ui/plugin-designer): Replaced the inlineFieldEditorpanel (rendered below the grid) with a properModalFormdialog, matching theObjectManagerpattern. Add Field and Edit Field now open a modal with all field properties (name, label, type, group, description, toggles for required/unique/readonly/hidden/indexed/externalId/trackHistory, default value, placeholder, referenceTo, formula). This provides a consistent, professional UX across both object and field management. -
Duplicate action column in ObjectGrid (
@object-ui/plugin-grid): Fixed a bug whereObjectGridrendered two action columns whenschema.operationswas set — one viaRowActionMenu(working dropdown with Edit/Delete) and another via DataTable's built-inrowActions(inline buttons calling unsetschema.onRowEdit/schema.onRowDelete). The DataTable'srowActionsis now only enabled for inline-editable grids, preventing the duplicate column and dead buttons. -
AI service discovery (
@object-ui/react): Addedaiservice type toDiscoveryInfo.servicesinterface withenabled,status, androutefields. AddedisAiEnabledconvenience property touseDiscovery()hook return value — returnstrueonly whenservices.ai.enabled === trueandservices.ai.status === 'available', defaults tofalseotherwise. -
Conditional chatbot rendering (
@object-ui/console): Console floating chatbot (FAB) now only renders when the AI service is detected as available viauseDiscovery().isAiEnabled. Previously the chatbot was always visible; now it is hidden when the server has no AI plugin installed. -
Home page user menu (
@object-ui/console): Added complete user menu dropdown (Profile, Settings, Sign Out) to the Home Dashboard via newHomeLayoutshell component. Users can now access account actions directly from the/homepage without navigating elsewhere. -
"Return to Home" navigation (
@object-ui/console): Added a "Home" entry in the AppSidebar app switcher dropdown, allowing users to navigate back to/homefrom any application context. Previously, the only way to return to the Home Dashboard was to manually edit the URL. -
HomeLayout shell (
@object-ui/console): New lightweight layout wrapper for the Home Dashboard providing a sticky top navigation bar with Home branding, Settings, and user menu dropdown. Replaces bare<HomePage />rendering with a consistent navigation frame for future extensibility (notifications, global guide, unified theming).
-
CSP-safe expression evaluation (
@object-ui/core): Replacednew Function()inExpressionCache.compileExpression()with a newSafeExpressionParser— a recursive-descent interpreter that evaluates expressions without any dynamic code execution. This fixesContent Security Policyviolations ('unsafe-eval' is not an allowed source of script) that occurred when evaluating schema expressions like${stage !== 'closed_won' && stage !== 'closed_lost'}in enterprise deployments with strict CSP headers. TheSafeExpressionParsersupports the full ObjectUI expression language: all comparison and logical operators, ternary and nullish coalescing, arithmetic, unary operators (!,-,+,typeof), dot/bracket/optional-chaining member access, function calls (formula functions, method calls,Math.*), single-param arrow functions (for.filter(u => u.isActive),.map(x => x.name)etc.), array literals,new Date()/new RegExp()constructors, and all literal types. TheExpressionCachepublic API is unchanged. 41 new tests added. -
CI build errors (
@object-ui/console): Removed unused imports (resolveI18nLabelinHomePage.tsx,Upload/FileTextinQuickActions.tsx) that caused TS6133 errors. FixedappConfig→appConfigs[0]ini18n-translations.test.ts(TS2552). ExtractedcustomReportsConfigfrom aggregatedsharedConfiginto a standalone export so the mock server kernel includes thesales_performance_q1report, fixingReportView.test.tsxfailures. -
Charts groupBy value→label resolution (
@object-ui/plugin-charts): Chart X-axis labels now display human-readable labels instead of raw values. Select/picklist fields resolve value→label via field metadata options, lookup/master_detail fields batch-fetch referenced record names, and all other fields fall back tohumanizeLabel()(snake_case → Title Case). Removed hardcodedvalue.slice(0, 3)truncation fromAdvancedChartImpl.tsxXAxis tick formatters — desktop now shows full labels with angle rotation for long text, mobile truncates at 8 characters with "…". -
Analytics aggregate measures format (
@object-ui/data-objectstack): Fixedaggregate()method to sendmeasuresas string array (['amount_sum'],['count']) instead of object array ([{ field, function }]). The backendMemoryAnalyticsService.resolveMeasure()expects strings and calls.split('.'), causingTypeError: t.split is not a functionwhen receiving objects. Also fixeddimensionsto send an empty array whengroupByis'_all'(single-bucket aggregation), and added response mapping to rename measure keys (e.g.amount_sum) back to the original field name (amount) for consumer compatibility. Additionally fixed chart rendering blank issue: therawRowsextraction now handles the{ rows: [...] }envelope (when the SDK unwraps the outer{ success, data }wrapper) and the{ data: { rows: [...] } }envelope (when the SDK returns the full response), matching the actual shape returned by the analytics API (/api/v1/analytics/query). -
Fields SSR build (
@object-ui/fields): Added@object-ui/i18nto Viteexternalinvite.config.tsand converted to regex-based externalization pattern (consistent with@object-ui/components) to preventreact-i18nextCJS code from being bundled. Fixes"dynamic usage of require is not supported"error during Next.js SSR prerendering of/docs/components/basic/text. -
Console build (
@object-ui/console): Added missing@object-ui/plugin-chatbotdevDependency that causedTS2307: Cannot find module '@object-ui/plugin-chatbot'during build. -
Site SSR build (
@object-ui/site): Added@object-ui/i18ntotranspilePackagesinnext.config.mjsto fix "dynamic usage of require is not supported" error when prerendering the tooltip docs page. The i18n package is a transitive dependency of@object-ui/reactand itsreact-i18nextdependency requires transpilation for Turbopack SSR compatibility.
-
Floating Chatbot FAB Widget (
@object-ui/plugin-chatbot): Airtable-style floating action button (FAB) that opens a chatbot panel overlay. New components:FloatingChatbot,FloatingChatbotPanel,FloatingChatbotTrigger,FloatingChatbotProvider. Features include configurable position (bottom-right/left), fullscreen toggle, close, portal rendering to avoid z-index conflicts, anduseFloatingChatbothook for programmatic control. Registered aschatbot-floatingin ComponentRegistry. 21 new unit tests. -
New ChatbotSchema floating fields (
@object-ui/types): ExtendedChatbotSchemawithdisplayMode('inline' | 'floating') andfloatingConfig(FloatingChatbotConfig) for schema-driven floating chatbot configuration. NewFloatingChatbotConfiginterface withposition,defaultOpen,panelWidth,panelHeight,title,triggerIcon, andtriggerSizeoptions. -
Console floating chatbot integration (
@object-ui/console): Added the floating chatbot FAB toConsoleLayout, making it available on every authenticated page. UsesuseObjectChatwith metadata-aware context (app name, object list) for intelligent auto-responses. Wired with demo auto-response mode by default, switchable to API streaming whenapiendpoint is configured. -
AI SDUI Chatbot integration (
@object-ui/plugin-chatbot): Refactored chatbot plugin to support full AI streaming viaservice-aibackend andvercel/aiSDK (@ai-sdk/react). NewuseObjectChatcomposable hook wraps@ai-sdk/react'suseChatfor SSE streaming, tool-calling, and production-grade chat. Auto-detects API mode (whenapischema field is set) vs legacy local auto-response mode. ChatbotEnhanced component now supports stop, reload, error display, and streaming state indicators. 44 unit tests (19 new hook tests, 10 new streaming tests). -
New ChatbotSchema fields (
@object-ui/types): ExtendedChatbotSchemawithapi,conversationId,systemPrompt,model,streamingEnabled,headers,requestBody,maxToolRoundtrips, andonErrorfields for service-ai integration. ExtendedChatMessagewithstreaming,toolInvocationsfields and addedChatToolInvocationinterface for tool-calling flows. -
New Storybook stories for AI chatbot (
@object-ui/components): AddedAIStreamingMode,AIWithSystemPrompt, andAIWithToolCallsstories demonstrating the new AI SDUI chat modes alongside existing local/demo stories. -
Object Manager visual designer (
@object-ui/plugin-designer): Enterprise-grade object management interface for creating, editing, deleting, and configuring meta-object definitions. Uses standard ObjectGrid for the list view and ModalForm for create/edit operations. Features include property editing (name, label, plural label, description, icon, group, sort order, enabled toggle), object relationship display, search/filter, system object protection, confirm dialogs for destructive actions, and read-only mode. 18 unit tests. -
Field Designer visual designer (
@object-ui/plugin-designer): Enterprise-grade field configuration wizard supporting 27 field types with full CRUD operations. Uses standard ObjectGrid for the list view with a specialized FieldEditor panel for advanced type-specific properties. Features include uniqueness constraints, default values, picklist/option set management, read-only, hidden, validation rules (min/max/length/pattern/custom), external ID, history tracking, and database indexing. Type-specific editors for lookup references, formula expressions, and select options. Field type filtering, search, system field protection, and read-only mode. 22 unit tests. -
New type definitions (
@object-ui/types): AddedObjectDefinition,ObjectDefinitionRelationship,ObjectManagerSchema,DesignerFieldType(27 field types),DesignerFieldOption,DesignerValidationRule,DesignerFieldDefinition, andFieldDesignerSchemainterfaces for the Object Manager and Field Designer components. -
New i18n keys for Object Manager and Field Designer (
@object-ui/i18n): Added 50 new translation keys per locale across all 10 locale packs (en, zh, ja, ko, de, fr, es, pt, ru, ar) covering bothobjectManagerandfieldDesignersubsections ofappDesigner. -
Designer translation fallbacks (
@object-ui/plugin-designer): UpdateduseDesignerTranslationwith fallback translations for all new Object Manager and Field Designer keys. -
Console integration (
@object-ui/console): Object Manager and Field Designer are now accessible in the console application at/system/objects. Added ObjectManagerPage to system admin routes, SystemHubPage card, and sidebar navigation. Selecting an object drills into its FieldDesigner for field configuration. 7 unit tests.
- System settings pages refactored to ObjectView (
apps/console): All five system management pages (Users, Organizations, Roles, Permissions, Audit Log) now use the metadata-drivenObjectViewfrom@object-ui/plugin-viewinstead of hand-written HTML tables. Each page's UI is driven by the object definitions insystemObjects.ts, providing automatic search, sort, filter, and CRUD capabilities. A sharedSystemObjectViewPagecomponent eliminates code duplication across all system pages.
-
TypeScript build error in ObjectManagerPage (
apps/console): FixedTS2322: Type 'string' is not assignable to type 'DesignerFieldType'by adding proper type assertion and missing import forDesignerFieldType. -
ChatbotSchema
bodyproperty conflict with BaseSchema (@object-ui/types): RenamedChatbotSchema.bodytorequestBodyto resolveTS2430: Interface 'ChatbotSchema' incorrectly extends interface 'BaseSchema'— the chatbot's HTTP request body parameter conflicted withBaseSchema.body(child schema nodes). Updated all references in@object-ui/plugin-chatbotrenderer accordingly. -
Fields package SSR compatibility for Next.js docs site (
@object-ui/fields): Addedreact/jsx-runtimeto the Vite build externals configuration to prevent it from being bundled. This fixes theError: dynamic usage of require is not supportedfailure during Next.js static page prerendering of the/docs/components/overlay/tooltippage. -
Dashboard widgets now surface API errors instead of showing hardcoded data (
@object-ui/plugin-dashboard,@object-ui/plugin-charts):- ObjectChart: Added error state tracking. When
dataSource.aggregate()ordataSource.find()fails, the chart now shows a prominent error message with a red alert icon instead of silently swallowing errors and rendering an empty chart. - MetricWidget / MetricCard: Added
loadinganderrorprops. When provided, the widget shows a loading spinner or a destructive-colored error message instead of the metric value, making API failures immediately visible. - ObjectMetricWidget (new component): Data-bound metric widget that fetches live values from the server via
dataSource.aggregate()ordataSource.find(). Shows explicit loading/error states. Falls back to staticfallbackValueonly when nodataSourceis available (demo mode). - DashboardRenderer: Metric widgets with
widget.objectbinding are now routed toObjectMetricWidget(object-metrictype) for async data loading, instead of always rendering static hardcoded values. Static-only metric widgets (noobjectbinding) continue to work as before. - CRM dashboard example: Documented that
options.valuefields are demo/fallback values that only display when no dataSource is connected. - 13 new tests covering error states, loading states, fallback behavior, and routing logic.
- ObjectChart: Added error state tracking. When
-
Plugin designer test infrastructure (
@object-ui/plugin-designer): Created missingvitest.setup.tswith ResizeObserver polyfill and jest-dom matchers. Added@object-ui/i18nalias to vite config. These fixes resolved 9 pre-existing test suite failures, bringing total passing tests from 45 to 246. -
Chinese language pack (zh.ts) untranslated key (
@object-ui/i18n): Fixedconsole.objectView.toolbarEnabledCountwhich was still in English ('{{count}} of {{total}} enabled') — now properly translated to'已启用 {{count}}/{{total}} 项'. Also fixed the same untranslated key in all other 8 non-English locales (ja, ko, de, fr, es, pt, ru, ar). -
Hardcoded English strings in platform UI (
apps/console,@object-ui/fields,@object-ui/react,@object-ui/components): Replaced hardcoded English strings with i18nt()calls:- Console
App.tsx: Modal dialog title ("Create/Edit Contact"), description ("Add a new ... to your database."), submitText ("Save Record"), and cancelText ("Cancel") now use i18n keys. SelectField: Default placeholder"Select an option"now usest('common.selectOption').LookupField: Default placeholder"Select..."and search placeholder"Search..."now use i18n keys.FieldFactory: Default select option placeholder now usest('common.selectOption').- Form renderer: Default select placeholder now uses
t('common.selectOption').
- Console
-
New i18n keys for select/form components (
@object-ui/i18n): Added new translation keys across all 10 locale packs:common.selectOption— Default select field placeholder (e.g., '请选择' in Chinese)common.select— Short select placeholder (e.g., '选择...' in Chinese)form.createTitle— Form dialog create title with interpolation (e.g., '新建{{object}}' in Chinese)form.editTitle— Form dialog edit title with interpolationform.createDescription— Form dialog create description with interpolationform.editDescription— Form dialog edit description with interpolationform.saveRecord— Save record button text
-
Safe translation hook for field widgets (
@object-ui/fields): AddeduseFieldTranslationhook that provides fallback to English defaults when noI18nProvideris available, following the same pattern asuseDetailTranslationin@object-ui/plugin-detail.
- ObjectView ChatterPanel test assertion mismatch (
apps/console): Fixed the failing CI test inObjectView.test.tsxwhere the RecordChatterPanel drawer test usedgetByLabelText('Show discussion')but the actual aria-label rendered by the component is'Show Discussion (0)'(from the i18n default translationdetail.showDiscussionwith count parameter). Updated the test assertion to match the correct aria-label.
- Upgrade @objectstack packages from v3.2.9 to v3.3.0: Upgraded all
@objectstack/*dependencies across the entire monorepo (root,apps/console,examples/crm,examples/todo,examples/msw-todo,examples/kitchen-sink,packages/core,packages/types,packages/react,packages/data-objectstack,packages/plugin-map,packages/plugin-gantt,packages/plugin-timeline) from^3.2.9to^3.3.0. All 42 build tasks pass and all 7,224 tests pass with no breaking changes.
-
Standardized List Refresh After Mutation (P0/P1/P2) (
@object-ui/types,@object-ui/plugin-list,@object-ui/plugin-view,@object-ui/plugin-kanban,@object-ui/plugin-calendar,@object-ui/react,@object-ui/core,apps/console): Resolved a platform-level architectural deficiency where list views did not refresh after create/update/delete mutations. The fix spans three phases:- P0 — refreshTrigger Prop: Added
refreshTrigger?: numbertoListViewSchema. When a parent component (e.g.,ObjectView) increments this value after a mutation,ListViewautomatically re-fetches data. The plugin-view'sObjectView.renderContent()now passes its internalrefreshKeyas both a direct callback prop and embedded in the schema'srefreshTrigger. The consoleObjectViewcombines both its own and the plugin's refresh signals for full propagation. - P1 — Imperative
refresh()API +useDataRefreshhook:ListViewis now wrapped withReact.forwardRefand exposes arefresh()method viauseImperativeHandle. Parents can trigger a re-fetch programmatically vialistRef.current?.refresh(). ExportedListViewHandletype from@object-ui/plugin-list. Added reusableuseDataRefresh(dataSource, objectName)hook to@object-ui/reactthat encapsulates the refreshKey state +onMutationsubscription pattern for any view component. - P2 — DataSource Mutation Event Bus: Added
MutationEventinterface and optionalonMutation(callback): unsubscribemethod to theDataSourceinterface. All data-bound views now auto-subscribe to mutation events when the DataSource implements this:ListView,ObjectView(plugin-view),ObjectKanban(plugin-kanban), andObjectCalendar(plugin-calendar).ValueDataSourceemits mutation events on create/update/delete. Includes 22 new tests covering all three phases.
- P0 — refreshTrigger Prop: Added
-
Unified i18n Plugin Loading & Translation Injection (
examples/crm,apps/console): Unified the i18n loading mechanism so that both server and MSW/mock environments use the same translation pipeline. CRM'sobjectstack.config.tsnow declares its translations viai18n: { namespace: 'crm', translations: crmLocales }. The shared config (objectstack.shared.ts) merges i18n bundles from all composed stacks.createKernelregisters an i18n kernel service from the config bundles and auto-generates the/api/v1/i18n/translations/:langMSW handler, returning translations in the standard{ data: { locale, translations } }spec envelope. Removed all manually-maintained i18n custom handlers and duplicateloadAppLocalefunctions frombrowser.tsandserver.ts. The broker shim now supportsi18n.getTranslationsfor server-side dispatch. -
ObjectDataTable: columns now support
string[]shorthand (@object-ui/plugin-dashboard):ObjectDataTablenow normalizescolumnsentries so that bothstring[](e.g.['name', 'close_date']) andobject[]formats are accepted. String entries are automatically converted to{ header, accessorKey }objects with title-cased headers derived from snake_case and camelCase field names. Previously, passing astring[]caused the downstreamdata-tablerenderer to crash when accessingcol.accessorKeyon a plain string. Mixed arrays (some strings, some objects) are also handled correctly. Includes 8 new unit tests.
-
i18n Kernel Service
getTranslationsReturns Wrong Format (apps/console): Fixed thecreateKerneli18n service registration wheregetTranslationsreturned a wrapped{ locale, translations }object instead of the flatRecord<string, any>dictionary expected by the spec'sII18nServiceinterface. The HttpDispatcher wraps the service return value in{ data: { locale, translations } }, so the extra wrapping caused translations to be empty or double-nested in the API response (/api/v1/i18n/translations/:lang). The service now returnsresolveI18nTranslations(bundles, lang)directly, aligning with the spec and making CRM business translations work correctly in all environments (MSW, server, dev). -
i18n Translations Empty in Server Mode (
pnpm start) (apps/console): Fixed translations returning{}when running the real ObjectStack server on port 3000. The root cause was that the CLI'sisHostConfig()function detects plugins withinitmethods in the config'spluginsarray and treats it as a "host config" — skipping auto-registration ofAppPlugin. WithoutAppPlugin, the config's translations, objects, and seed data were never loaded. Additionally, the kernel's memory i18n fallback is only auto-registered invalidateSystemRequirements()(after all plugin starts), too late forAppPlugin.start()→loadTranslations(). Fixed by: (1) explicitly addingAppPlugin(sharedConfig)toobjectstack.config.tsplugins, and (2) addingMemoryI18nPluginbefore it to register the i18n service during init phase. Also added a spec-formattranslationsarray toobjectstack.shared.tssoAppPlugin.loadTranslations()can iterate and load the CRM locale bundles. -
i18n Translations Empty in Root Dev Mode (
pnpm dev) (rootobjectstack.config.ts): Fixed translations returning{}when runningpnpm devfrom the monorepo root. The root config usesobjectstack dev→objectstack serve --devwhich loads the rootobjectstack.config.ts— but this config did not aggregate i18n bundles from the example stacks (CRM, Todo, etc.). ThecomposeStacks()function doesn't handle the customi18nfield, so translation data was lost during composition. Fixed by: (1) aggregating i18n bundles from all plugin configs (same pattern asobjectstack.shared.ts), (2) building a spec-formattranslationsarray passed toAppPlugin(mergedApp), and (3) addingMemoryI18nPluginto register the i18n service during init phase. -
Duplicate Data in Calendar and Kanban Views (
@object-ui/plugin-view,@object-ui/plugin-kanban,@object-ui/plugin-list): Fixed a bug where Calendar and Kanban views displayed every record twice. The root cause was thatObjectView(plugin-view) unconditionally fetched data even when arenderListViewcallback was provided — causing parallel duplicate requests sinceListView(plugin-list) independently fetches its own data. The duplicate fetch results triggered re-renders that destabilised child component rendering, leading to duplicate events in the calendar and duplicate cards on the kanban board. Additionally,ObjectKanbanlacked proper external-data handling (data/loadingprops withhasExternalDataguard), unlikeObjectCalendarwhich already had this pattern. Fixes: (1)ObjectViewnow skips its own fetch whenrenderListViewis provided, (2)ObjectKanbannow accepts explicitdata/loadingprops and skips internal fetch when external data is supplied (matchingObjectCalendar's pattern), (3)ListViewnow handles{ value: [] }OData response format consistently withextractRecordsutility. Includes regression tests. -
CI Build Fix: Replace dynamic
require()with static imports (@object-ui/plugin-view): Replaced module-levelrequire('@object-ui/react')calls inindex.tsxandObjectView.tsxwith staticimportstatements. The dynamicrequire()pattern is not supported by Next.js Turbopack, causing the docs site build to fail during SSR prerendering of the/docs/components/complex/view-switcherpage withError: dynamic usage of require is not supported. Since@object-ui/reactis already a declared dependency and other files in the package use static imports from it, replacing therequire()with static imports is safe and eliminates the SSR compatibility issue. -
CI Build Fix: Remove unused
...restparameter (@object-ui/plugin-calendar): Removed unused...restdestructured parameter fromObjectCalendarcomponent props (TS6133), which caused the declaration file generation to emit a TypeScript error during the build. -
CI Build Fix: Unused Parameters in Test Mocks (
apps/console): Fixed TypeScriptnoUnusedParameterserrors (TS6133) inListToolbarActions.test.tsxwhere mock componentpropsparameters were declared but never used in@object-ui/plugin-kanbanand@object-ui/plugin-calendarmocks, causing the consoletscbuild step to fail in CI. -
i18n loadLanguage Not Compatible with Spec REST API Response Format (
apps/console): FixedloadLanguageinapps/console/src/main.tsxto correctly unwrap the@objectstack/specREST API envelope{ data: { locale, translations } }. Previously, the function returned the raw JSON response, which meantuseObjectLabelanduseObjectTranslationhooks received a wrapped object instead of the flat translation map, causing business object and field labels (e.g., CRM contact/account) to fall back to English. The fix extractsdata.translationswhen the spec envelope is detected, while preserving backward compatibility with mock/dev environments that return flat translation objects. Includes 6 unit tests covering spec envelope unwrapping, flat fallback, HTTP errors, network failures, and edge cases. -
List Toolbar Action Buttons Not Responding (
apps/console): Fixed a bug where schema-driven action buttons in the upper-right corner of the list view (rendered viaaction:barwithlocations: ['list_toolbar']) did not respond to clicks. The root cause: the consoleObjectViewcomponent rendered these action buttons viaSchemaRendererwithout wrapping them in anActionProvider. This causeduseAction()to fall back to a localActionRunnerwith no handlers, toast, confirmation, or navigation capabilities — so clicks executed silently with no visible effect. AddedActionProviderwith proper handlers (toast via Sonner, confirmation dialog, navigation via React Router, param collection dialog, and a generic API handler) to the consoleObjectView, following the same pattern already used inRecordDetailView. Includes 4 new integration tests validating the full action chain (render, confirm, execute, cancel). -
CRM Seed Data Lookup References (
examples/crm): Fixed all CRM seed data files to use natural key (name) references for lookup fields instead of rawidvalues. TheSeedLoaderServiceresolves foreign key references by the target object'snamefield (the defaultexternalId), so seed data values likeorder: "o1"oraccount: "2"could not be resolved and were set tonull. Updated all 8 affected data files (account,contact,opportunity,order,order_item,opportunity_contact,project_task,event) to use human-readable name references (e.g.,order: "ORD-2024-001",product: "Workstation Pro Laptop",account: "Salesforce Tower"). This fixes the issue where Order and Product columns displayed as empty in the Order Item grid view.
-
Lookup Field Selection Display Fix (
@object-ui/fields): Fixed a bug where selecting a record from the RecordPickerDialog (Level 2 popup) produced no visible feedback in the LookupField. The root cause:findOptiononly searched static and popover-fetched options, which did not include records loaded by the dialog. AddedonSelectRecordscallback toRecordPickerDialogPropsthat returns full record objects alongside IDs. LookupField now caches selected records from the dialog and displays their labels/badges correctly. Both single-select and multi-select modes are supported. Includes aselectedRecordsMapref in RecordPickerDialog that persists selected record data across page navigation for multi-select scenarios. -
RecordPickerDialog UI/UX Overhaul (
@object-ui/fields): Major enterprise-grade improvements referencing mainstream low-code platforms:- Skeleton Loading Screen: Replaced simple spinner with a table-shaped skeleton screen during initial data load, matching the column layout for a polished loading experience.
- Sticky Table Header: Table header now sticks to the top during vertical scroll, keeping column labels visible at all times.
- Loading Overlay: Subsequent data fetches (page navigation, sorting, filtering) show a semi-transparent overlay with spinner over the existing data, preventing layout jank.
- Page Jump Input: New input field in pagination bar allows users to type a page number and press Enter to jump directly to any page.
- Enhanced Search Bar: Redesigned with a subtle background container and borderless input for a cleaner, more modern appearance.
- Improved Table Styling: Even/odd row striping (
bg-muted/20), refined selected-row highlighting (bg-primary/5), uppercase column headers with tighter tracking, rounded table border, and improved cell padding. - Responsive Dialog: Responsive dialog sizing from
sm:max-w-3xltolg:max-w-5xlfor optimal data density across screen sizes; filter panel supports 3-column layout on wide viewports (lg:grid-cols-3). - Fixed Close-Reset Cycle: Separated dialog close-reset logic into its own
useEffect(depends only onopen) to prevent cascading state updates that could trigger React Error #185 (Maximum update depth exceeded) when selecting a record. - 8 New Unit Tests: Comprehensive test coverage for skeleton loading (column count validation), sticky header classes, page jump navigation (valid/invalid/single-page), and loading overlay behavior.
-
"Browse All" Button for Lookup Fields (
@object-ui/fields): Added an always-visible "Browse All" (table icon) button next to the Lookup quick-select trigger. Opens the full RecordPickerDialog directly, regardless of record count — making enterprise features (multi-column table, sort/filter bar, cell renderers) discoverable at all times. Previously, the dialog was only accessible via the "Show All Results" in-popover button, which only appeared when total records exceeded the page size. The button uses accessiblearia-label,title, and LucideTablePropertiesicon. Keyboard and screen reader accessible. -
CRM Enterprise Lookup Metadata (
examples/crm): All 14 lookup fields across 8 CRM objects now have enterprise-grade RecordPicker configuration —lookup_columns(with type hints for cell rendering: select, currency, boolean, date, number, percent),lookup_filters(base business filters using eq/ne/in/notIn operators), anddescription_field. Uses post-createObject.assigninjection pattern to bypassObjectSchema.create()Zod stripping (analogous to the listViews passthrough approach). -
Enterprise Lookup Tests (
examples/crm): 12 new test cases validating lookup_columns presence & type diversity, lookup_filters operator validity, description_field coverage, and specific business logic (e.g., active-only users, non-cancelled orders, open opportunities). -
RecordPickerDialog Component (
@object-ui/fields): New enterprise-grade record selection dialog with multi-column table display, pagination, search, column sorting with$orderby, keyboard navigation (Arrow keys + Enter), loading/error/empty states, and single/multi-select support. Responsive layout with mobile-friendly width. Provides the foundation for Salesforce-style Lookup experience. -
LookupField Popover Typeahead (
@object-ui/fields): Level 1 quick-select upgraded from Dialog to Popover for inline typeahead experience (anchored dropdown, not modal). Includes "Show All Results" footer button that opens the full RecordPickerDialog (Level 2). -
LookupFieldMetadata Schema Enhancement (
@object-ui/types): Addedlookup_columns,description_field,lookup_page_size,lookup_filterstoLookupFieldMetadata. NewLookupColumnDefinterface withtypehint for cell formatting. NewLookupFilterDefinterface for base filter configuration.
- @objectstack v3.2.6 Upgrade: Upgraded all
@objectstack/*packages from^3.2.5to^3.2.6across 13 package.json files (43 references) - @objectstack v3.0.4 Upgrade: Upgraded all
@objectstack/*packages from^3.0.2to^3.0.4across 42 references - @objectstack v3.0.0 Upgrade: Upgraded all
@objectstack/*packages from^2.0.7to^3.0.0across 13 package.json files - Breaking change migrations:
Hubnamespace →Cloudin @object-ui/types re-exportsdefinePluginremoved (onlydefineStackremains)PaginatedResult.value→.recordsacross all data plugins and adaptersPaginatedResult.count→.totalin data-objectstack adapterclient.meta.getObject()→client.meta.getItem('object', name)in data adapter
- Updated spec version references across ROADMAP.md, SPEC_COMPLIANCE_EVALUATION.md, OBJECTSTACK_CLIENT_EVALUATION.md, and console docs
- Updated ROADMAP with v3.0.0 migration table and next phase roadmap (N.1-N.5)
- Updated namespace-exports tests to reflect v3.0.0 exports
- Preview Mode (
@object-ui/auth): NewpreviewModeprop onAuthProviderfor auto-login with simulated identity — skip login/registration for marketplace demos and app showcases. IncludesPreviewBannercomponent,isPreviewMode/previewModeonuseAuth(), andPreviewModeOptionstype. Aligns with@objectstack/speckernelPreviewModeConfig. - Discovery Preview Detection (
@object-ui/react): ExtendedDiscoveryInfowithmodeandpreviewModefields for server-driven preview mode detection. - Console Preview Support:
ConditionalAuthWrapperauto-detectsmode === 'preview'from server discovery and configures auth accordingly. - Console Bundle Optimization: Split monolithic 3.7 MB main chunk into 17 granular cacheable chunks via
manualChunks— main entry reduced from 1,008 KB gzip to 48.5 KB gzip (95% reduction) - Gzip + Brotli Compression: Pre-compressed assets via
vite-plugin-compression2— Brotli main entry at 40 KB - Bundle Analysis: Added
rollup-plugin-visualizergenerating interactive treemap atdist/stats.html; newbuild:analyzescript - Lazy MSW Loading: MSW mock server now loaded via dynamic
import()— fully excluded frombuild:serveroutput (~150 KB gzip saved) - ROADMAP Console v1.0 Section: Added production release optimization roadmap with detailed before/after metrics
- Maintenance release - Documentation and build improvements
- Updated internal dependencies across all packages
0.3.0 - 2026-01-17
- New Plugin:
@object-ui/plugin-object- ObjectQL plugin for automatic table and form generationObjectTable: Auto-generates tables from ObjectQL object schemasObjectForm: Auto-generates forms from ObjectQL object schemas with create/edit/view modes- Full TypeScript support with comprehensive type definitions
- Type Definitions: Added
ObjectTableSchemaandObjectFormSchemato@object-ui/types - ObjectQL Integration: Enhanced
ObjectQLDataSourcewithgetObjectSchema()method using MetadataApiClient
- Updated
@objectql/sdkfrom ^1.8.3 to ^1.9.1 - Updated
@objectql/typesfrom ^1.8.3 to ^1.9.1
0.2.1 - 2026-01-15
- Fixed changeset configuration to remove non-existent @apps/* pattern
- Added automated changeset-based version management and release workflow
- Enhanced CI/CD workflows with GitHub Actions
- Improved documentation for contributing and releasing
0.2.0 - 2026-01-15
- Comprehensive test suite using Vitest and React Testing Library
- Test coverage for @object-ui/core, @object-ui/react, @object-ui/components, and @object-ui/designer packages
- GitHub Actions CI/CD workflows:
- CI workflow for automated testing, linting, and building
- Release workflow for publishing new versions
- Test coverage reporting with @vitest/coverage-v8
- Contributing guidelines (CONTRIBUTING.md)
- Documentation for testing and development workflow in README
- README files for all core packages
- Updated package.json scripts to use Vitest instead of placeholder test commands
- Enhanced README with testing instructions and CI status badges
0.1.0 - Initial Release
- Core packages:
- @object-ui/core - Core logic, types, and validation (Zero React dependencies)
- @object-ui/react - React bindings and SchemaRenderer component
- @object-ui/components - Standard UI components built with Tailwind CSS & Shadcn
- @object-ui/designer - Drag-and-drop visual editor
- Monorepo structure using pnpm workspaces
- Basic TypeScript configuration
- Example applications in the examples directory
- Complete documentation site with VitePress