Skip to content

Commit 9f84ff1

Browse files
committed
Refactor entity to object terminology in schemas
Renamed 'entity' references to 'object' across Zod schemas and types for consistency. Updated navigation, dashboard, workflow, and manifest schemas to use 'object' terminology. Replaced 'entity.zod.ts' with 'object.zod.ts' and adjusted exports and inferred types accordingly. Enhanced app navigation schema to support structured navigation trees.
1 parent 1b6551c commit 9f84ff1

File tree

6 files changed

+142
-46
lines changed

6 files changed

+142
-46
lines changed

packages/spec/src/index.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99

1010
// Zod Schemas & Inferred Types (Meta)
1111
export * from './zod/meta/field.zod';
12-
export * from './zod/meta/entity.zod';
12+
export * from './zod/meta/object.zod';
1313
export * from './zod/meta/view.zod';
1414
export * from './zod/meta/action.zod';
1515
export * from './zod/meta/validation.zod';

packages/spec/src/zod/bundle/manifest.zod.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -62,10 +62,10 @@ export const ManifestSchema = z.object({
6262
menus: z.array(MenuItemSchema).optional().describe('Navigation menu structure'),
6363

6464
/**
65-
* Glob patterns specifying ObjectQL schemas files.
66-
* Example: `["./src/schemas/*.gql", "./src/schemas/**\/*.graphql"]`
65+
* Glob patterns specifying ObjectQL schemas files (typically *.object.yml or *.object.ts).
66+
* Example: `["./src/objects/*.object.yml"]`
6767
*/
68-
entities: z.array(z.string()).optional().describe('Glob patterns for ObjectQL schemas files'),
68+
objects: z.array(z.string()).optional().describe('Glob patterns for ObjectQL schemas files'),
6969

7070
/**
7171
* Extension points contributed by this package.
Lines changed: 129 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -1,64 +1,159 @@
11
import { z } from 'zod';
22

33
/**
4-
* Navigation Tab Type
4+
* Base Navigation Item Schema
5+
* Shared properties for all navigation types.
56
*/
6-
export const TabType = z.enum([
7-
'entity', // Standard object list view
8-
'dashboard',// Dashboard page
9-
'page', // Custom page
10-
'url' // External link
11-
]);
12-
13-
/**
14-
* Schema for App Navigation Items (Tabs)
15-
*/
16-
export const AppTabSchema = z.object({
17-
name: z.string().describe('Tab unique name'),
18-
label: z.string().optional().describe('Override label'),
19-
type: TabType.default('entity').describe('Tab type'),
7+
const BaseNavItemSchema = z.object({
8+
/** Unique identifier for the item */
9+
id: z.string().describe('Unique identifier for this navigation item'),
2010

21-
/**
22-
* Reference ID based on type:
23-
* - entity: entity_name
24-
* - dashboard: dashboard_name
25-
* - page: page_component_name
26-
* - url: https://...
27-
*/
28-
reference: z.string().describe('Target reference ID'),
11+
/** Display label */
12+
label: z.string().describe('Display proper label'),
2913

14+
/** Icon name (Lucide) */
3015
icon: z.string().optional().describe('Icon name'),
16+
17+
/**
18+
* Visibility condition.
19+
* Formula expression returning boolean.
20+
* e.g. "user.is_admin || user.department == 'sales'"
21+
*/
22+
visible: z.string().optional().describe('Visibility formula condition'),
23+
});
24+
25+
/**
26+
* 1. Object Navigation Item
27+
* Navigates to an object's list view.
28+
*/
29+
export const ObjectNavItemSchema = BaseNavItemSchema.extend({
30+
type: z.literal('object'),
31+
objectName: z.string().describe('Target object name'),
32+
viewName: z.string().optional().describe('Default list view to open. Defaults to "all"'),
33+
});
34+
35+
/**
36+
* 2. Dashboard Navigation Item
37+
* Navigates to a specific dashboard.
38+
*/
39+
export const DashboardNavItemSchema = BaseNavItemSchema.extend({
40+
type: z.literal('dashboard'),
41+
dashboardName: z.string().describe('Target dashboard name'),
42+
});
43+
44+
/**
45+
* 3. Page Navigation Item
46+
* Navigates to a custom UI page/component.
47+
*/
48+
export const PageNavItemSchema = BaseNavItemSchema.extend({
49+
type: z.literal('page'),
50+
pageName: z.string().describe('Target custom page component name'),
51+
params: z.record(z.any()).optional().describe('Parameters passed to the page context'),
52+
});
53+
54+
/**
55+
* 4. URL Navigation Item
56+
* Navigates to an external or absolute URL.
57+
*/
58+
export const UrlNavItemSchema = BaseNavItemSchema.extend({
59+
type: z.literal('url'),
60+
url: z.string().describe('Target external URL'),
61+
target: z.enum(['_self', '_blank']).default('_self').describe('Link target window'),
62+
});
63+
64+
/**
65+
* 5. Group Navigation Item
66+
* A container for child navigation items (Sub-menu).
67+
* Does not perform navigation itself.
68+
*/
69+
export const GroupNavItemSchema = BaseNavItemSchema.extend({
70+
type: z.literal('group'),
71+
expanded: z.boolean().default(false).describe('Default expansion state in sidebar'),
72+
// children property is added in the recursive definition below
73+
});
74+
75+
/**
76+
* Recursive Union of all navigation item types.
77+
* Allows constructing a navigation tree.
78+
*/
79+
export const NavigationItemSchema: z.ZodType<any> = z.lazy(() =>
80+
z.union([
81+
ObjectNavItemSchema,
82+
DashboardNavItemSchema,
83+
PageNavItemSchema,
84+
UrlNavItemSchema,
85+
GroupNavItemSchema.extend({
86+
children: z.array(NavigationItemSchema).describe('Child navigation items'),
87+
})
88+
])
89+
);
90+
91+
/**
92+
* App Branding Configuration
93+
* Allows configuring the look and feel of the specific app.
94+
*/
95+
export const AppBrandingSchema = z.object({
96+
primaryColor: z.string().optional().describe('Primary theme color hex code'),
97+
logo: z.string().optional().describe('Custom logo URL for this app'),
98+
favicon: z.string().optional().describe('Custom favicon URL for this app'),
3199
});
32100

33101
/**
34102
* Schema for Applications (Apps).
35-
* An App is a container that groups tabs/entities for a specific business function.
103+
* A logical container for business functionality (e.g., "Sales CRM", "HR Portal").
36104
*/
37105
export const AppSchema = z.object({
38-
/** Machine name */
106+
/** Machine name (id) */
39107
name: z.string().regex(/^[a-z_][a-z0-9_]*$/).describe('App unique machine name'),
40108

41-
/** Display label (e.g., "Sales CRM") */
109+
/** Display label */
42110
label: z.string().describe('App display label'),
43111

44112
/** Description */
45113
description: z.string().optional().describe('App description'),
46114

47115
/** Icon name (Lucide) */
48-
icon: z.string().optional().describe('App icon'),
116+
icon: z.string().optional().describe('App icon used in the App Launcher'),
49117

50-
/** Active status */
118+
/** Branding/Theming Configuration */
119+
branding: AppBrandingSchema.optional().describe('App-specific branding'),
120+
121+
/** Application status */
51122
active: z.boolean().default(true).describe('Whether the app is enabled'),
123+
124+
/** Is this the default app for new users? */
125+
isDefault: z.boolean().default(false).describe('Is default app'),
52126

53-
/** Ordered list of tabs/menu items */
54-
tabs: z.array(AppTabSchema).describe('Navigation structure'),
127+
/**
128+
* Navigation Tree Structure.
129+
* Replaces the old flat 'tabs' list with a structured menu.
130+
*/
131+
navigation: z.array(NavigationItemSchema).describe('Structured navigation menu tree'),
55132

56133
/**
57-
* Profiles/Roles that can access this app.
58-
* If empty, accessible to everyone (or controlled by other means).
134+
* App-level Home Page Override
135+
* ID of the navigation item to act as the landing page.
136+
* If not set, usually defaults to the first navigation item.
59137
*/
60-
profiles: z.array(z.string()).optional().describe('Profiles that can access this app'),
138+
homePageId: z.string().optional().describe('ID of the navigation item to serve as landing page'),
139+
140+
/**
141+
* Access Control
142+
* List of permissions required to access this app.
143+
* Modern replacement for role/profile based assignment.
144+
* Example: ["app.access.crm"]
145+
*/
146+
requiredPermissions: z.array(z.string()).optional().describe('Permissions required to access this app'),
61147
});
62148

149+
// Main Types
63150
export type App = z.infer<typeof AppSchema>;
64-
export type AppTab = z.infer<typeof AppTabSchema>;
151+
export type AppBranding = z.infer<typeof AppBrandingSchema>;
152+
export type NavigationItem = z.infer<typeof NavigationItemSchema>;
153+
154+
// Discriminated Item Types (Helper exports)
155+
export type ObjectNavItem = z.infer<typeof ObjectNavItemSchema>;
156+
export type DashboardNavItem = z.infer<typeof DashboardNavItemSchema>;
157+
export type PageNavItem = z.infer<typeof PageNavItemSchema>;
158+
export type UrlNavItem = z.infer<typeof UrlNavItemSchema>;
159+
export type GroupNavItem = z.infer<typeof GroupNavItemSchema> & { children: NavigationItem[] };

packages/spec/src/zod/meta/dashboard.zod.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,8 @@ export const DashboardWidgetSchema = z.object({
2525
/** Visualization Type */
2626
type: ChartType.default('metric').describe('Visualization type'),
2727

28-
/** Data Source Entity */
29-
entity: z.string().optional().describe('Data source entity name'),
28+
/** Data Source Object */
29+
object: z.string().optional().describe('Data source object name'),
3030

3131
/** Data Filter (ObjectQL JSON) */
3232
filter: z.any().optional().describe('Data filter criteria'),
Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,9 @@ export const IndexSchema = z.object({
1111
});
1212

1313
/**
14-
* Schema for Entities (Models/Tables).
14+
* Schema for Objects (Models/Tables).
1515
*/
16-
export const EntitySchema = z.object({
16+
export const ObjectSchema = z.object({
1717
/** Machine name (snake_case) */
1818
name: z.string().regex(/^[a-z_][a-z0-9_]*$/).describe('Machine name (snake_case)'),
1919

@@ -40,6 +40,7 @@ export const EntitySchema = z.object({
4040
});
4141

4242
/**
43-
* TypeScript type inferred from EntitySchema.
43+
* TypeScript type inferred from ObjectSchema.
44+
* Note: 'Object' is a reserved word in JavaScript/TypeScript, so we use 'ServiceObject'.
4445
*/
45-
export type Entity = z.infer<typeof EntitySchema>;
46+
export type ServiceObject = z.infer<typeof ObjectSchema>;

packages/spec/src/zod/meta/workflow.zod.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -51,8 +51,8 @@ export const WorkflowRuleSchema = z.object({
5151
/** Machine name */
5252
name: z.string().regex(/^[a-z_][a-z0-9_]*$/).describe('Unique workflow name'),
5353

54-
/** Target Entity */
55-
entity_name: z.string().describe('Target Object/Entity'),
54+
/** Target Object */
55+
object_name: z.string().describe('Target Object'),
5656

5757
/** When to evaluate the rule */
5858
trigger_type: WorkflowTriggerType.describe('When to evaluate'),

0 commit comments

Comments
 (0)