Skip to content

Commit d79383c

Browse files
committed
feat(showcase): dogfood ADR-0085 stageField-driven default kanban lanes (#2596)
Two `board` views that deliberately omit the (spec-optional) kanban binding, so the lane field resolves through the shared stageField detector: - showcase_semantic_zoo (stageField:'status') → lanes Draft/Active/Done with zero view-level config — the objectui#2596 role-driven default; - showcase_semantic_zoo_legacy (stageField:false) → NO default lanes; the pre-#2596 hard-coded 'status' fallback would have grouped by Red/Green. detail-shapes e2e gains the paired assertion (lanes present / lanes suppressed, no page errors on either board). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016wpaFMPowSn4nAWsjeGZib
1 parent 4ea0a60 commit d79383c

4 files changed

Lines changed: 62 additions & 2 deletions

File tree

examples/app-showcase/e2e/detail-shapes.spec.ts

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -137,6 +137,27 @@ test('stageField:false: status renders as a plain field, no stepper', async ({ p
137137
expect(errors, 'uncaught page errors on stageField:false detail').toEqual([]);
138138
});
139139

140+
test('kanban default lanes honour stageField — role drives lanes, strict-false suppresses them', async ({ page }) => {
141+
// Both `board` views deliberately carry NO kanban binding (spec-optional),
142+
// so the lane field resolves through the shared stageField detector
143+
// (objectui#2596).
144+
145+
// Positive: zoo declares stageField:'status' → lanes are the option
146+
// labels, with zero view-level config.
147+
let errors = await openRecord(page, `/_console/apps/${APP}/showcase_semantic_zoo?view=board`);
148+
await expect(page.getByText('Draft', { exact: true }).first()).toBeVisible();
149+
await expect(page.getByText('Done', { exact: true }).first()).toBeVisible();
150+
expect(errors, 'uncaught page errors on stageField board').toEqual([]);
151+
152+
// Negative: legacy zoo declares stageField:false (its status is a color,
153+
// not a lifecycle) → NO default lanes. The pre-#2596 hard-coded 'status'
154+
// fallback would have grouped by Red / Green.
155+
errors = await openRecord(page, `/_console/apps/${APP}/showcase_semantic_zoo_legacy?view=board`);
156+
await expect(page.getByText('Red', { exact: true })).toHaveCount(0);
157+
await expect(page.getByText('Green', { exact: true })).toHaveCount(0);
158+
expect(errors, 'uncaught page errors on suppressed board').toEqual([]);
159+
});
160+
140161
test('ungrouped + related-heavy: flat details and related-list tabs on Contoso', async ({ page }) => {
141162
const errors = await openRecord(page, recordUrl('showcase_account', contosoId));
142163

examples/app-showcase/objectstack.config.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ import { ExternalCustomer, ExternalOrder } from './src/data/objects/external/ind
1818
import { setupShowcaseExternalDatasource } from './src/system/datasources/external-fixture.js';
1919
import { registerRecalcEndpoint } from './src/system/server/recalc-endpoint.js';
2020
import { registerShowcasePositionBindings } from './src/security/bind-position-sets.js';
21-
import { TaskViews, ProjectViews, InquiryViews, BusinessUnitViews } from './src/ui/views/index.js';
21+
import { TaskViews, ProjectViews, InquiryViews, BusinessUnitViews, SemanticZooViews, SemanticZooLegacyViews } from './src/ui/views/index.js';
2222
import { ShowcaseApp } from './src/ui/apps/index.js';
2323
import { ChartGalleryDashboard, OpsDashboard, RevenuePulseDashboard } from './src/ui/dashboards/index.js';
2424
import { ShowcaseTaskDataset, ShowcaseProjectDataset, ShowcaseInvoiceDataset, ShowcaseAccountDataset } from './src/ui/datasets/index.js';
@@ -181,7 +181,7 @@ export default defineStack({
181181
// UI
182182
apps: [ShowcaseApp],
183183
portals: allPortals,
184-
views: [TaskViews, ProjectViews, InquiryViews, BusinessUnitViews],
184+
views: [TaskViews, ProjectViews, InquiryViews, BusinessUnitViews, SemanticZooViews, SemanticZooLegacyViews],
185185
pages: [CapabilityMapPage, StartHerePage, ComponentGalleryPage, ProjectWorkspacePage, ProjectDetailPage, TaskWorkbenchPage, TaskTriagePage, TaskBoardPage, TaskCalendarPage, TaskGalleryPage, TaskSchedulePage, TaskTimelinePage, TaskMapPage, TaskAllViewsPage, ActiveProjectsPage, TaskDetailPage, ReviewQueuePage, NewProjectWizardPage, MyWorkPage, SettingsPage, StylingGalleryPage, CommandCenterPage, CommandCenterJsxPage, CrmWorkbenchPage, TaskDeskPage, PageVariablesPage, ContactFormPage, RenewalsPipelinePage],
186186
dashboards: [ChartGalleryDashboard, OpsDashboard, RevenuePulseDashboard],
187187
books: allBooks,

examples/app-showcase/src/ui/views/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,3 +5,4 @@ export { ProjectViews } from './project.view.js';
55
export { InquiryViews } from './inquiry.view.js';
66
export { BusinessUnitViews } from './business-unit.view.js';
77
export { ContactViews } from './contact.view.js';
8+
export { SemanticZooViews, SemanticZooLegacyViews } from './semantic-zoo.view.js';
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
// Copyright (c) 2026 ObjectStack. Licensed under the Apache-2.0 license.
2+
3+
import { defineView } from '@objectstack/spec';
4+
5+
/**
6+
* Semantic-zoo kanban views — runtime dogfood for the ADR-0085 `stageField`
7+
* role driving DEFAULT kanban lanes (objectui#2596).
8+
*
9+
* Both boards deliberately omit the `kanban` binding (it is optional on the
10+
* view schema): with no explicit `groupByField`, the lane field resolves
11+
* through the shared `detectStatusField` semantics —
12+
*
13+
* - `showcase_semantic_zoo` declares `stageField: 'status'` → the board
14+
* lanes by Draft / Active / Done with zero view-level config;
15+
* - `showcase_semantic_zoo_legacy` declares `stageField: false` (its
16+
* `status` is a color, not a lifecycle) → NO default lanes: the board
17+
* renders its empty state instead of grouping by Red / Green, which is
18+
* exactly what the pre-#2596 hard-coded 'status' fallback used to do.
19+
*
20+
* Guarded by `examples/app-showcase/e2e/detail-shapes.spec.ts`.
21+
*/
22+
export const SemanticZooViews = defineView({
23+
board: {
24+
label: 'Board (lanes from stageField)',
25+
type: 'kanban',
26+
data: { provider: 'object' as const, object: 'showcase_semantic_zoo' },
27+
columns: ['name', 'code', 'amount'],
28+
},
29+
});
30+
31+
export const SemanticZooLegacyViews = defineView({
32+
board: {
33+
label: 'Board (no lanes by design)',
34+
type: 'kanban',
35+
data: { provider: 'object' as const, object: 'showcase_semantic_zoo_legacy' },
36+
columns: ['name', 'amount'],
37+
},
38+
});

0 commit comments

Comments
 (0)