diff --git a/CHANGELOG.md b/CHANGELOG.md index abde745a..e6562a82 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Fixed +- **CI build errors** (`@object-ui/console`): Removed unused imports (`resolveI18nLabel` in `HomePage.tsx`, `Upload`/`FileText` in `QuickActions.tsx`) that caused TS6133 errors. Fixed `appConfig` → `appConfigs[0]` in `i18n-translations.test.ts` (TS2552). Extracted `customReportsConfig` from aggregated `sharedConfig` into a standalone export so the mock server kernel includes the `sales_performance_q1` report, fixing `ReportView.test.tsx` failures. + - **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 to `humanizeLabel()` (snake_case → Title Case). Removed hardcoded `value.slice(0, 3)` truncation from `AdvancedChartImpl.tsx` XAxis 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`): Fixed `aggregate()` method to send `measures` as string array (`['amount_sum']`, `['count']`) instead of object array (`[{ field, function }]`). The backend `MemoryAnalyticsService.resolveMeasure()` expects strings and calls `.split('.')`, causing `TypeError: t.split is not a function` when receiving objects. Also fixed `dimensions` to send an empty array when `groupBy` is `'_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: the `rawRows` extraction 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`). diff --git a/apps/console/objectstack.shared.ts b/apps/console/objectstack.shared.ts index fa3580a6..08d98367 100644 --- a/apps/console/objectstack.shared.ts +++ b/apps/console/objectstack.shared.ts @@ -51,6 +51,31 @@ export const setupAppConfig = { manifest: { id: 'setup', name: 'setup' }, }; +/** + * Additional reports that are not part of any individual app config. + * Loaded as a separate AppPlugin instance by the mock server (server.ts) + * and browser mock (browser.ts) so that these reports appear in the + * kernel's metadata alongside the app-specific reports. + */ +export const customReportsConfig = { + reports: [ + { + name: 'sales_performance_q1', + label: 'Q1 Sales Performance', + description: 'Quarterly analysis of sales revenue by region and product line', + objectName: 'opportunity', + type: 'summary', + columns: [ + { field: 'name', label: 'Deal Name' }, + { field: 'amount', label: 'Amount', aggregate: 'sum' }, + { field: 'stage', label: 'Stage' }, + { field: 'close_date', label: 'Close Date' } + ] + } + ], + manifest: { id: 'reports', name: 'reports' }, +}; + // Patch CRM App Navigation to include Report using a supported navigation type const apps = [ ...JSON.parse(JSON.stringify(appConfigs.flatMap((c: any) => c.apps || []))), @@ -92,19 +117,7 @@ export const sharedConfig = { dashboards: appConfigs.flatMap((c: any) => c.dashboards || []), reports: [ ...appConfigs.flatMap((c: any) => c.reports || []), - { - name: 'sales_performance_q1', - label: 'Q1 Sales Performance', - description: 'Quarterly analysis of sales revenue by region and product line', - objectName: 'opportunity', - type: 'summary', - columns: [ - { field: 'name', label: 'Deal Name' }, - { field: 'amount', label: 'Amount', aggregate: 'sum' }, - { field: 'stage', label: 'Stage' }, - { field: 'close_date', label: 'Close Date' } - ] - } + ...customReportsConfig.reports, ], pages: appConfigs.flatMap((c: any) => c.pages || []), manifest: { diff --git a/apps/console/src/__tests__/i18n-translations.test.ts b/apps/console/src/__tests__/i18n-translations.test.ts index d2d83dc8..ab8ca870 100644 --- a/apps/console/src/__tests__/i18n-translations.test.ts +++ b/apps/console/src/__tests__/i18n-translations.test.ts @@ -135,7 +135,7 @@ describe('i18n translations pipeline', () => { }); it('appConfig.translations is spec-format array for AppPlugin', () => { - const translations = (appConfig as any).translations; + const translations = (appConfigs[0] as any).translations; expect(Array.isArray(translations)).toBe(true); expect(translations.length).toBeGreaterThan(0); @@ -162,7 +162,7 @@ describe('i18n translations pipeline', () => { const svc = createMemoryI18n(); // Simulate AppPlugin.loadTranslations() iterating the spec-format translations array - const translations = (appConfig as any).translations; + const translations = (appConfigs[0] as any).translations; for (const bundle of translations) { for (const [locale, data] of Object.entries(bundle)) { if (data && typeof data === 'object') { diff --git a/apps/console/src/mocks/browser.ts b/apps/console/src/mocks/browser.ts index a22395e3..44fb9f69 100644 --- a/apps/console/src/mocks/browser.ts +++ b/apps/console/src/mocks/browser.ts @@ -16,7 +16,7 @@ import { setupWorker } from 'msw/browser'; import { ObjectKernel } from '@objectstack/runtime'; import { InMemoryDriver } from '@objectstack/driver-memory'; import type { MSWPlugin } from '@objectstack/plugin-msw'; -import { appConfigs, setupAppConfig } from '../../objectstack.shared'; +import { appConfigs, setupAppConfig, customReportsConfig } from '../../objectstack.shared'; import { createKernel } from './createKernel'; import { createAuthHandlers } from './authHandlers'; @@ -43,7 +43,7 @@ export async function startMockServer() { if (import.meta.env.DEV) console.log('[MSW] Starting ObjectStack Runtime (Browser Mode)...'); const result = await createKernel({ - appConfigs: [...appConfigs, setupAppConfig], + appConfigs: [...appConfigs, setupAppConfig, customReportsConfig], mswOptions: { enableBrowser: false, baseUrl: '/api/v1', diff --git a/apps/console/src/mocks/server.ts b/apps/console/src/mocks/server.ts index bc1c3baf..f5a20df1 100644 --- a/apps/console/src/mocks/server.ts +++ b/apps/console/src/mocks/server.ts @@ -16,7 +16,7 @@ import { ObjectKernel } from '@objectstack/runtime'; import { InMemoryDriver } from '@objectstack/driver-memory'; import { setupServer } from 'msw/node'; import type { MSWPlugin } from '@objectstack/plugin-msw'; -import { appConfigs, setupAppConfig } from '../../objectstack.shared'; +import { appConfigs, setupAppConfig, customReportsConfig } from '../../objectstack.shared'; import { createKernel } from './createKernel'; import { createAuthHandlers } from './authHandlers'; @@ -34,7 +34,7 @@ export async function startMockServer() { console.log('[MSW] Starting ObjectStack Runtime (Test Mode)...'); const result = await createKernel({ - appConfigs: [...appConfigs, setupAppConfig], + appConfigs: [...appConfigs, setupAppConfig, customReportsConfig], persistence: false, mswOptions: { enableBrowser: false, diff --git a/apps/console/src/pages/home/HomePage.tsx b/apps/console/src/pages/home/HomePage.tsx index df7d22f7..4dbf264b 100644 --- a/apps/console/src/pages/home/HomePage.tsx +++ b/apps/console/src/pages/home/HomePage.tsx @@ -21,7 +21,6 @@ import { useMetadata } from '../../context/MetadataProvider'; import { useRecentItems } from '../../hooks/useRecentItems'; import { useFavorites } from '../../hooks/useFavorites'; import { useObjectTranslation } from '@object-ui/i18n'; -import { resolveI18nLabel } from '../../utils'; import { QuickActions } from './QuickActions'; import { AppCard } from './AppCard'; import { RecentApps } from './RecentApps'; diff --git a/apps/console/src/pages/home/QuickActions.tsx b/apps/console/src/pages/home/QuickActions.tsx index 06b05f84..37a722c9 100644 --- a/apps/console/src/pages/home/QuickActions.tsx +++ b/apps/console/src/pages/home/QuickActions.tsx @@ -10,7 +10,7 @@ import { useNavigate } from 'react-router-dom'; import { useObjectTranslation } from '@object-ui/i18n'; import { Card, CardContent } from '@object-ui/components'; -import { Plus, Upload, Settings, Database, FileText } from 'lucide-react'; +import { Plus, Settings, Database } from 'lucide-react'; import { cn } from '@object-ui/components'; interface QuickAction {