diff --git a/src/apps/crm.app.ts b/src/apps/crm.app.ts index c3d031a0..4c784398 100644 --- a/src/apps/crm.app.ts +++ b/src/apps/crm.app.ts @@ -41,6 +41,9 @@ export const CrmApp = App.create({ children: [ { id: 'nav_lead', type: 'object', objectName: 'crm_lead', label: 'Leads', icon: 'user-plus' }, { id: 'nav_account', type: 'object', objectName: 'crm_account', label: 'Accounts', icon: 'building' }, + // ADR-0047 interface page — the curated counterpart to the Accounts + // object entry (quick filters only; activates with spec > 9.2.0). + { id: 'nav_account_workbench', type: 'page', pageName: 'account_workbench', label: 'Account Workbench', icon: 'sliders-horizontal' }, { id: 'nav_contact', type: 'object', objectName: 'crm_contact', label: 'Contacts', icon: 'user' }, { id: 'nav_opportunity', type: 'object', objectName: 'crm_opportunity', label: 'Opportunities', icon: 'target' }, { id: 'nav_pipeline', type: 'object', objectName: 'crm_opportunity', viewName: 'pipeline_kanban', label: 'Pipeline', icon: 'columns-3' }, diff --git a/src/pages/account_workbench.page.ts b/src/pages/account_workbench.page.ts new file mode 100644 index 00000000..7e55ee05 --- /dev/null +++ b/src/pages/account_workbench.page.ts @@ -0,0 +1,71 @@ +// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license. + +import { Page } from '@objectstack/spec/ui'; + +/** + * Account Workbench — ADR-0047 interface page (Airtable Interfaces parity). + * + * The author-curated counterpart to the Accounts object nav entry. Where + * the object entry (data mode) shows every list view as switcher tabs and + * offers the full toolbar, this page is deliberately closed: + * + * • it REFERENCES the account default view (`sourceView`) — columns, + * base filter and sort are inherited, never restated (the iron rule); + * • end users get exactly three quick filters: industry (with record + * counts), customer type, and owner (a user lookup — renders as a + * record-picker dropdown); + * • the visualization is locked to grid (single-entry whitelist); + * • advanced filtering / view management are not offered. + * + * Filter selections persist as `uf_*` URL params — reload-safe, shareable. + * + * NOTE: `interfaceConfig.userFilters` requires @objectstack/spec > 9.2.0 + * (ADR-0047). On older specs defineStack strips the unknown keys and the + * page renders without the filter bar — a harmless no-op until the + * dependency bump activates it. + */ +export const AccountWorkbenchPage: Page = { + name: 'account_workbench', + label: 'Account Workbench', + description: 'Curated account list for the sales team: quick filters only, no view management.', + type: 'list', + object: 'crm_account', + kind: 'full', + template: 'default', + isDefault: false, + // Interface pages carry no regions — the list surface is generated from + // `interfaceConfig` (ADR-0047), not composed from components. + regions: [], + interfaceConfig: { + source: 'crm_account', + sourceView: 'all_accounts', + + ...({ + userFilters: { + element: 'dropdown', + fields: [ + { field: 'industry', showCount: true }, + { field: 'type' }, + { field: 'owner' }, + ], + }, + // typed via spread-as-any until @objectstack/spec ships ADR-0047 + // (UserFiltersSchema is in framework main, > 9.2.0) + } as any), + + appearance: { + showDescription: true, + allowedVisualizations: ['grid'], + }, + + userActions: { + sort: true, + search: true, + filter: false, + rowHeight: false, + addRecordForm: false, + }, + + showRecordCount: true, + }, +}; diff --git a/src/pages/index.ts b/src/pages/index.ts index ec72cf35..b54a9025 100644 --- a/src/pages/index.ts +++ b/src/pages/index.ts @@ -3,6 +3,7 @@ export { LeadDetailPage } from './lead_detail.page'; export { OpportunityDetailPage } from './opportunity_detail.page'; export { AccountDetailPage } from './account_detail.page'; +export { AccountWorkbenchPage } from './account_workbench.page'; export { CaseDetailPage } from './case_detail.page'; export { SalesHomePage } from './home.page'; export { AppLauncherPage } from './app_launcher.page'; diff --git a/src/views/account.view.ts b/src/views/account.view.ts index 2b44b5a3..5dd4af0c 100644 --- a/src/views/account.view.ts +++ b/src/views/account.view.ts @@ -127,6 +127,26 @@ export const AccountViews = defineView({ columns: ['name', 'industry', 'annual_revenue', 'number_of_employees', 'owner'], filter: [{ field: 'annual_revenue', operator: 'greater_than_or_equal', value: 10000000 }], sort: [{ field: 'annual_revenue', order: 'desc' }], + + // ADR-0047 end-user quick filters (Airtable "User filters", Elements: + // dropdowns). Lives on THIS view, not the default one: the default + // view's `tabs` act as the view switcher, and filter tabs/dropdowns + // are mutually exclusive with a tab row on the same toolbar. + // `owner` is a user lookup — it renders as a record-picker dropdown. + // NOTE: requires @objectstack/spec > 9.2.0 (ADR-0047 UserFiltersSchema); + // on older specs defineStack strips this block — harmless no-op. + ...({ + userFilters: { + element: 'dropdown', + fields: [ + { field: 'industry', showCount: true }, + { field: 'type' }, + { field: 'owner' }, + ], + }, + // typed via spread-as-any until @objectstack/spec ships ADR-0047 + // (UserFiltersSchema is in framework main, > 9.2.0) + } as any), }, my_accounts: {