Skip to content

Commit c7965e8

Browse files
Copilothotlong
andcommitted
fix: address PR review comments — license header, tests, deprecated re-export, ROADMAP
- Add standard ObjectUI MIT license header to merge-views-into-objects.ts - Add 6 unit tests for mergeViewsIntoObjects helper - Add deprecated composeStacks re-export from @objectstack/spec in core index - Reword ROADMAP to clarify removed test suite lives upstream in @objectstack/spec Co-authored-by: hotlong <50353452+hotlong@users.noreply.github.com>
1 parent 26ee64a commit c7965e8

File tree

4 files changed

+127
-2
lines changed

4 files changed

+127
-2
lines changed

ROADMAP.md

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1188,11 +1188,10 @@ Plugin architecture refactoring to support true modular development, plugin isol
11881188
- [x] Remove duplicate `mergeActionsIntoObjects()` from root config and console shared config
11891189
- [x] Remove duplicate `mergeViewsIntoObjects()` from root config and console shared config (moved into `composeStacks`)
11901190
- [x] Refactor root `objectstack.config.ts` and `apps/console/objectstack.shared.ts` to use `composeStacks()`
1191-
- [x] Unit tests for `composeStacks()` (15 tests covering merging, dedup, views, actions, cross-stack, conflict detection)
11921191
- [x] Eliminate `defineStack()` double-pass hack — single `composeStacks()` call produces final config with runtime properties (listViews, actions) preserved. `defineStack()` Zod validation stripped these fields, requiring a second `composeStacks` pass to restore them.
11931192
- [x] Use `composed.apps` unified flow in console shared config — replaced manual `[...crmApps, ...(todoConfig.apps || []), ...]` spreading with CRM navigation patch applied to composed output
11941193
- [x] Use `composed.reports` in console shared config — replaced `...(crmConfig.reports || [])` with `...(composed.reports || [])` to include reports from all stacks
1195-
- [x] **composeStacks unified to `@objectstack/spec`:** Removed `@object-ui/core` composeStacks implementation. All config composition now uses `composeStacks` from `@objectstack/spec` (protocol-level: object dedup, array concatenation, actions→objects mapping, manifest selection, i18n). Runtime-specific `mergeViewsIntoObjects` adapter applied inline at call sites until the runtime/provider layer handles it natively.
1194+
- [x] **composeStacks unified to `@objectstack/spec`:** Removed `@object-ui/core` composeStacks implementation and its 15-test suite (coverage now lives upstream in `@objectstack/spec`). All config composition now uses `composeStacks` from `@objectstack/spec` (protocol-level: object dedup, array concatenation, actions→objects mapping, manifest selection, i18n). Runtime-specific `mergeViewsIntoObjects` adapter extracted to `@object-ui/core` and applied post-composition at call sites. A deprecated re-export of `composeStacks` is kept in `@object-ui/core` for backward compatibility.
11961195

11971196
**Phase 2 — Dynamic Plugin Loading (Planned)**
11981197
- [ ] Hot-reload / lazy loading of plugins for development

packages/core/src/index.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,3 +28,11 @@ export * from './utils/debug.js';
2828
export * from './utils/debug-collector.js';
2929
export * from './utils/merge-views-into-objects.js';
3030
export * from './protocols/index.js';
31+
32+
/**
33+
* @deprecated Import `composeStacks` from `@objectstack/spec` instead.
34+
*
35+
* This re-export is kept only for backward compatibility and will be removed
36+
* in the next major version of `@object-ui/core`.
37+
*/
38+
export { composeStacks } from '@objectstack/spec';
Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
/**
2+
* ObjectUI
3+
* Copyright (c) 2024-present ObjectStack Inc.
4+
*
5+
* This source code is licensed under the MIT license found in the
6+
* LICENSE file in the root directory of this source tree.
7+
*/
8+
9+
import { describe, it, expect } from 'vitest';
10+
import { mergeViewsIntoObjects } from '../merge-views-into-objects';
11+
12+
describe('mergeViewsIntoObjects', () => {
13+
it('should merge listViews from views into corresponding objects', () => {
14+
const objects = [{ name: 'account', label: 'Account', fields: {} }];
15+
const views = [
16+
{
17+
listViews: {
18+
all_accounts: {
19+
name: 'all_accounts',
20+
label: 'All Accounts',
21+
type: 'grid',
22+
data: { provider: 'object', object: 'account' },
23+
},
24+
},
25+
},
26+
];
27+
28+
const result = mergeViewsIntoObjects(objects, views);
29+
expect(result[0].listViews.all_accounts).toBeDefined();
30+
expect(result[0].listViews.all_accounts.label).toBe('All Accounts');
31+
});
32+
33+
it('should preserve existing listViews on objects', () => {
34+
const objects = [
35+
{
36+
name: 'todo_task',
37+
label: 'Task',
38+
fields: {},
39+
listViews: {
40+
existing: { name: 'existing', label: 'Existing View', type: 'grid', data: { provider: 'object', object: 'todo_task' } },
41+
},
42+
},
43+
];
44+
const views = [
45+
{
46+
listViews: {
47+
new_view: {
48+
name: 'new_view',
49+
label: 'New View',
50+
type: 'grid',
51+
data: { provider: 'object', object: 'todo_task' },
52+
},
53+
},
54+
},
55+
];
56+
57+
const result = mergeViewsIntoObjects(objects, views);
58+
const task = result[0];
59+
expect(task.listViews.existing).toBeDefined();
60+
expect(task.listViews.new_view).toBeDefined();
61+
});
62+
63+
it('should ignore listViews without data.object', () => {
64+
const objects = [{ name: 'account', label: 'Account', fields: {} }];
65+
const views = [
66+
{
67+
listViews: {
68+
orphan: { name: 'orphan', label: 'Orphan View', type: 'grid' },
69+
},
70+
},
71+
];
72+
73+
const result = mergeViewsIntoObjects(objects, views);
74+
expect(result[0].listViews).toBeUndefined();
75+
});
76+
77+
it('should return objects unchanged when views is empty', () => {
78+
const objects = [{ name: 'account', label: 'Account', fields: {} }];
79+
80+
const result = mergeViewsIntoObjects(objects, []);
81+
expect(result).toEqual(objects);
82+
});
83+
84+
it('should ignore views without listViews property', () => {
85+
const objects = [{ name: 'account', label: 'Account', fields: {} }];
86+
const views = [{ someOtherProp: true }];
87+
88+
const result = mergeViewsIntoObjects(objects, views);
89+
expect(result).toEqual(objects);
90+
});
91+
92+
it('should merge views from multiple view entries into different objects', () => {
93+
const objects = [
94+
{ name: 'account', label: 'Account', fields: {} },
95+
{ name: 'contact', label: 'Contact', fields: {} },
96+
];
97+
const views = [
98+
{
99+
listViews: {
100+
all_accounts: { name: 'all_accounts', label: 'All Accounts', type: 'grid', data: { provider: 'object', object: 'account' } },
101+
all_contacts: { name: 'all_contacts', label: 'All Contacts', type: 'grid', data: { provider: 'object', object: 'contact' } },
102+
},
103+
},
104+
];
105+
106+
const result = mergeViewsIntoObjects(objects, views);
107+
expect(result[0].listViews.all_accounts).toBeDefined();
108+
expect(result[1].listViews.all_contacts).toBeDefined();
109+
});
110+
});

packages/core/src/utils/merge-views-into-objects.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,11 @@
1+
/**
2+
* ObjectUI
3+
* Copyright (c) 2024-present ObjectStack Inc.
4+
*
5+
* This source code is licensed under the MIT license found in the
6+
* LICENSE file in the root directory of this source tree.
7+
*/
8+
19
/**
210
* Adapter: merge stack-level views into object definitions.
311
*

0 commit comments

Comments
 (0)