Skip to content

Commit 5e8965c

Browse files
xuyushun441-sysos-zhuangclaude
authored
feat(studio): complete block config coverage + prune shell-only blocks (#1493)
- Add config panels for page:accordion, record:path, record:quick_actions, ai:chat_window, ai:input (every content block with authorable props is now configurable; pure containers correctly have none). - Prune shell singletons (app:launcher, global:notifications, user:profile) from the page block palette — they are shell-provided, not page content. Browser-verified (palette prune + record:path config) + unit tests (5). Co-authored-by: Jack Zhuang <277994282+os-zhuang@users.noreply.github.com> Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
1 parent c681874 commit 5e8965c

4 files changed

Lines changed: 81 additions & 18 deletions

File tree

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@object-ui/app-shell": minor
3+
---
4+
5+
Complete the page-editor block configuration and prune shell-only blocks. Adds configurable property panels for the remaining content blocks with authorable properties — `page:accordion`, `record:path`, `record:quick_actions`, `ai:chat_window`, `ai:input` — so every page-content block in the palette is configurable in the UI (pure containers like `page:section` / `element:divider` correctly have no panel). Removes shell-singleton blocks (`app:launcher`, `global:notifications`, `user:profile`) from the page block palette — those are provided by the app shell, not authored as page content.

packages/app-shell/src/views/metadata-admin/previews/__tests__/block-config.test.ts

Lines changed: 19 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,34 @@
11
import { describe, it, expect } from 'vitest';
22
import { BLOCK_CONFIG, blockHasConfig } from '../block-config';
3+
import { BLOCK_TYPE_META } from '../block-types';
34

45
describe('block-config', () => {
5-
it('exposes a configurable panel for the minimal SDUI block set', () => {
6-
for (const type of ['element:text', 'element:image', 'page:header', 'page:card', 'record:related_list']) {
7-
expect(blockHasConfig(type)).toBe(true);
6+
it('exposes a configurable panel for every content block with authorable props', () => {
7+
for (const type of [
8+
'element:text', 'element:image', 'element:number', 'element:button',
9+
'page:header', 'page:card', 'page:tabs', 'page:accordion',
10+
'record:related_list', 'record:highlights', 'record:details', 'record:alert',
11+
'record:path', 'record:quick_actions', 'ai:chat_window', 'ai:input',
12+
]) {
13+
expect(blockHasConfig(type), type).toBe(true);
814
expect(BLOCK_CONFIG[type].length).toBeGreaterThan(0);
915
}
1016
});
1117

12-
it('returns false for blocks without a config schema (and for undefined)', () => {
18+
it('returns false for pure-container blocks without scalar props (and undefined)', () => {
1319
expect(blockHasConfig('page:section')).toBe(false);
14-
expect(blockHasConfig('nav:menu')).toBe(false);
20+
expect(blockHasConfig('element:divider')).toBe(false);
1521
expect(blockHasConfig(undefined)).toBe(false);
1622
});
1723

24+
it('prunes shell-singleton blocks from the page palette', () => {
25+
for (const type of ['app:launcher', 'global:notifications', 'user:profile']) {
26+
expect((BLOCK_TYPE_META as any)[type]).toBeUndefined();
27+
}
28+
// page-content navigation stays
29+
expect((BLOCK_TYPE_META as any)['nav:menu']).toBeTruthy();
30+
});
31+
1832
it('also exposes the array-valued blocks', () => {
1933
for (const type of ['page:tabs', 'record:details', 'record:highlights']) {
2034
expect(blockHasConfig(type)).toBe(true);

packages/app-shell/src/views/metadata-admin/previews/block-config.ts

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -137,6 +137,19 @@ export const BLOCK_CONFIG: Record<string, BlockPropField[]> = {
137137
],
138138
},
139139
],
140+
'page:accordion': [
141+
{ name: 'title', label: 'Title', kind: 'text' },
142+
{
143+
name: 'items',
144+
label: 'Sections',
145+
kind: 'array',
146+
addLabel: 'Add section',
147+
itemFields: [
148+
{ name: 'value', label: 'Key', kind: 'text' },
149+
{ name: 'label', label: 'Label', kind: 'text' },
150+
],
151+
},
152+
],
140153

141154
// ── Record context ────────────────────────────────────────────────────────
142155
'record:related_list': [
@@ -178,6 +191,46 @@ export const BLOCK_CONFIG: Record<string, BlockPropField[]> = {
178191
{ name: 'icon', label: 'Icon', kind: 'text', placeholder: 'lucide icon name' },
179192
{ name: 'dismissible', label: 'Dismissible', kind: 'boolean' },
180193
],
194+
'record:path': [
195+
{ name: 'statusField', label: 'Status field', kind: 'text', placeholder: 'e.g. stage' },
196+
{
197+
name: 'stages',
198+
label: 'Stages',
199+
kind: 'array',
200+
addLabel: 'Add stage',
201+
itemFields: [
202+
{ name: 'value', label: 'Value', kind: 'text' },
203+
{ name: 'label', label: 'Label', kind: 'text' },
204+
],
205+
},
206+
],
207+
'record:quick_actions': [
208+
{ name: 'actionNames', label: 'Action names', kind: 'string-list', placeholder: 'action name' },
209+
{
210+
name: 'location',
211+
label: 'Location',
212+
kind: 'select',
213+
options: [
214+
{ value: 'record_header', label: 'Record header' },
215+
{ value: 'record_more', label: 'Record more menu' },
216+
{ value: 'record_section', label: 'Record section' },
217+
{ value: 'record_related', label: 'Record related' },
218+
{ value: 'list_toolbar', label: 'List toolbar' },
219+
{ value: 'list_item', label: 'List item' },
220+
{ value: 'global_nav', label: 'Global nav' },
221+
],
222+
},
223+
],
224+
225+
// ── AI ────────────────────────────────────────────────────────────────────
226+
'ai:chat_window': [
227+
{ name: 'agentName', label: 'Agent', kind: 'text', placeholder: 'agent name' },
228+
{ name: 'placeholder', label: 'Input placeholder', kind: 'text' },
229+
],
230+
'ai:input': [
231+
{ name: 'agentName', label: 'Agent', kind: 'text', placeholder: 'agent name' },
232+
{ name: 'placeholder', label: 'Input placeholder', kind: 'text' },
233+
],
181234
};
182235

183236
/** Block types that expose a configurable property panel. */

packages/app-shell/src/views/metadata-admin/previews/block-types.ts

Lines changed: 4 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -29,11 +29,8 @@ import {
2929
Zap,
3030
BookOpen,
3131
History,
32-
Rocket,
3332
Menu,
3433
Search,
35-
Bell,
36-
User,
3734
Bot,
3835
Sparkles,
3936
Type,
@@ -56,14 +53,11 @@ export type BlockTypeId =
5653
| 'record:details' | 'record:highlights' | 'record:related_list'
5754
| 'record:activity' | 'record:chatter' | 'record:path' | 'record:alert'
5855
| 'record:quick_actions' | 'record:reference_rail' | 'record:history'
59-
// app:*
60-
| 'app:launcher'
61-
// nav:*
56+
// nav:* — page-content navigation (shell singletons like app:launcher /
57+
// global:notifications / user:profile are intentionally NOT page blocks)
6258
| 'nav:menu' | 'nav:breadcrumb'
6359
// global:*
64-
| 'global:search' | 'global:notifications'
65-
// user:*
66-
| 'user:profile'
60+
| 'global:search'
6761
// ai:*
6862
| 'ai:chat_window' | 'ai:suggestion'
6963
// element:*
@@ -101,13 +95,10 @@ export const BLOCK_TYPE_META: Record<BlockTypeId, Omit<BlockTypeMeta, 'id'>> = {
10195
'record:reference_rail': { label: 'Reference rail', category: 'record', Icon: BookOpen },
10296
'record:history': { label: 'History', category: 'record', Icon: History },
10397

104-
// App & navigation
105-
'app:launcher': { label: 'App launcher', category: 'navigation', Icon: Rocket },
98+
// Navigation (page-content only; shell singletons are not page blocks)
10699
'nav:menu': { label: 'Nav menu', category: 'navigation', Icon: Menu },
107100
'nav:breadcrumb': { label: 'Breadcrumb', category: 'navigation', Icon: Compass },
108101
'global:search': { label: 'Global search', category: 'navigation', Icon: Search },
109-
'global:notifications': { label: 'Notifications', category: 'navigation', Icon: Bell },
110-
'user:profile': { label: 'User profile', category: 'navigation', Icon: User },
111102

112103
// AI
113104
'ai:chat_window': { label: 'AI chat window', category: 'ai', Icon: Bot },

0 commit comments

Comments
 (0)