Skip to content

Commit 90342e7

Browse files
xuyushun441-sysos-zhuangclaude
authored
feat: ADR-0047 account workbench — interface page + quick-filter dropdowns (#383)
Dogfoods the two ADR-0047 run modes on the CRM shapes they were designed for (the Airtable-CRM parity scenario): - pages/account_workbench: curated interface page referencing the all_accounts view — industry (with counts) / type / owner dropdowns, visualization locked to grid, no advanced filtering or view management. owner is a user lookup and renders as a record-picker dropdown. - views/account enterprise_accounts: data-mode dropdown filters on the tab-less view (the default view's tabs are a view switcher, and filter tabs/dropdowns are mutually exclusive on one toolbar). - crm.app nav: Account Workbench entry next to Accounts. Activation note: userFilters requires @objectstack/spec > 9.2.0 (UserFiltersSchema, framework#1792). On 9.2.0 defineStack strips the block — the page renders without a filter bar, a harmless no-op. The spread-as-any casts paper over the 9.2.0 types and come off with the version bump. Co-authored-by: Jack Zhuang <277994282+os-zhuang@users.noreply.github.com> Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
1 parent 2b56571 commit 90342e7

4 files changed

Lines changed: 95 additions & 0 deletions

File tree

src/apps/crm.app.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,9 @@ export const CrmApp = App.create({
4141
children: [
4242
{ id: 'nav_lead', type: 'object', objectName: 'crm_lead', label: 'Leads', icon: 'user-plus' },
4343
{ id: 'nav_account', type: 'object', objectName: 'crm_account', label: 'Accounts', icon: 'building' },
44+
// ADR-0047 interface page — the curated counterpart to the Accounts
45+
// object entry (quick filters only; activates with spec > 9.2.0).
46+
{ id: 'nav_account_workbench', type: 'page', pageName: 'account_workbench', label: 'Account Workbench', icon: 'sliders-horizontal' },
4447
{ id: 'nav_contact', type: 'object', objectName: 'crm_contact', label: 'Contacts', icon: 'user' },
4548
{ id: 'nav_opportunity', type: 'object', objectName: 'crm_opportunity', label: 'Opportunities', icon: 'target' },
4649
{ id: 'nav_pipeline', type: 'object', objectName: 'crm_opportunity', viewName: 'pipeline_kanban', label: 'Pipeline', icon: 'columns-3' },
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.
2+
3+
import { Page } from '@objectstack/spec/ui';
4+
5+
/**
6+
* Account Workbench — ADR-0047 interface page (Airtable Interfaces parity).
7+
*
8+
* The author-curated counterpart to the Accounts object nav entry. Where
9+
* the object entry (data mode) shows every list view as switcher tabs and
10+
* offers the full toolbar, this page is deliberately closed:
11+
*
12+
* • it REFERENCES the account default view (`sourceView`) — columns,
13+
* base filter and sort are inherited, never restated (the iron rule);
14+
* • end users get exactly three quick filters: industry (with record
15+
* counts), customer type, and owner (a user lookup — renders as a
16+
* record-picker dropdown);
17+
* • the visualization is locked to grid (single-entry whitelist);
18+
* • advanced filtering / view management are not offered.
19+
*
20+
* Filter selections persist as `uf_*` URL params — reload-safe, shareable.
21+
*
22+
* NOTE: `interfaceConfig.userFilters` requires @objectstack/spec > 9.2.0
23+
* (ADR-0047). On older specs defineStack strips the unknown keys and the
24+
* page renders without the filter bar — a harmless no-op until the
25+
* dependency bump activates it.
26+
*/
27+
export const AccountWorkbenchPage: Page = {
28+
name: 'account_workbench',
29+
label: 'Account Workbench',
30+
description: 'Curated account list for the sales team: quick filters only, no view management.',
31+
type: 'list',
32+
object: 'crm_account',
33+
kind: 'full',
34+
template: 'default',
35+
isDefault: false,
36+
// Interface pages carry no regions — the list surface is generated from
37+
// `interfaceConfig` (ADR-0047), not composed from components.
38+
regions: [],
39+
interfaceConfig: {
40+
source: 'crm_account',
41+
sourceView: 'all_accounts',
42+
43+
...({
44+
userFilters: {
45+
element: 'dropdown',
46+
fields: [
47+
{ field: 'industry', showCount: true },
48+
{ field: 'type' },
49+
{ field: 'owner' },
50+
],
51+
},
52+
// typed via spread-as-any until @objectstack/spec ships ADR-0047
53+
// (UserFiltersSchema is in framework main, > 9.2.0)
54+
} as any),
55+
56+
appearance: {
57+
showDescription: true,
58+
allowedVisualizations: ['grid'],
59+
},
60+
61+
userActions: {
62+
sort: true,
63+
search: true,
64+
filter: false,
65+
rowHeight: false,
66+
addRecordForm: false,
67+
},
68+
69+
showRecordCount: true,
70+
},
71+
};

src/pages/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
export { LeadDetailPage } from './lead_detail.page';
44
export { OpportunityDetailPage } from './opportunity_detail.page';
55
export { AccountDetailPage } from './account_detail.page';
6+
export { AccountWorkbenchPage } from './account_workbench.page';
67
export { CaseDetailPage } from './case_detail.page';
78
export { SalesHomePage } from './home.page';
89
export { AppLauncherPage } from './app_launcher.page';

src/views/account.view.ts

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,26 @@ export const AccountViews = defineView({
127127
columns: ['name', 'industry', 'annual_revenue', 'number_of_employees', 'owner'],
128128
filter: [{ field: 'annual_revenue', operator: 'greater_than_or_equal', value: 10000000 }],
129129
sort: [{ field: 'annual_revenue', order: 'desc' }],
130+
131+
// ADR-0047 end-user quick filters (Airtable "User filters", Elements:
132+
// dropdowns). Lives on THIS view, not the default one: the default
133+
// view's `tabs` act as the view switcher, and filter tabs/dropdowns
134+
// are mutually exclusive with a tab row on the same toolbar.
135+
// `owner` is a user lookup — it renders as a record-picker dropdown.
136+
// NOTE: requires @objectstack/spec > 9.2.0 (ADR-0047 UserFiltersSchema);
137+
// on older specs defineStack strips this block — harmless no-op.
138+
...({
139+
userFilters: {
140+
element: 'dropdown',
141+
fields: [
142+
{ field: 'industry', showCount: true },
143+
{ field: 'type' },
144+
{ field: 'owner' },
145+
],
146+
},
147+
// typed via spread-as-any until @objectstack/spec ships ADR-0047
148+
// (UserFiltersSchema is in framework main, > 9.2.0)
149+
} as any),
130150
},
131151

132152
my_accounts: {

0 commit comments

Comments
 (0)