@object-ui/app-shell 6.1.0 → 6.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +110 -0
- package/README.md +10 -1
- package/dist/console/AppContent.js +24 -2
- package/dist/console/ai/AiChatPage.d.ts +8 -0
- package/dist/console/ai/AiChatPage.js +188 -0
- package/dist/console/ai/ConversationsSidebar.d.ts +7 -0
- package/dist/console/ai/ConversationsSidebar.js +111 -0
- package/dist/console/auth/LoginPage.js +19 -2
- package/dist/console/auth/RegisterPage.js +30 -1
- package/dist/console/marketplace/MarketplaceAccessDenied.js +3 -1
- package/dist/console/marketplace/MarketplaceInstalledPage.js +11 -3
- package/dist/console/marketplace/MarketplacePackagePage.js +57 -19
- package/dist/console/marketplace/MarketplacePage.js +55 -18
- package/dist/console/marketplace/marketplaceApi.d.ts +20 -0
- package/dist/console/marketplace/usePackageL10n.d.ts +38 -0
- package/dist/console/marketplace/usePackageL10n.js +110 -0
- package/dist/console/organizations/CreateWorkspaceDialog.js +29 -1
- package/dist/console/organizations/OrganizationsPage.js +24 -3
- package/dist/context/FavoritesProvider.d.ts +40 -2
- package/dist/context/FavoritesProvider.js +201 -20
- package/dist/hooks/index.d.ts +1 -0
- package/dist/hooks/index.js +1 -0
- package/dist/hooks/useChatConversation.d.ts +7 -0
- package/dist/hooks/useChatConversation.js +37 -5
- package/dist/hooks/useConversationList.d.ts +25 -0
- package/dist/hooks/useConversationList.js +131 -0
- package/dist/hooks/useNavPins.d.ts +11 -4
- package/dist/hooks/useNavPins.js +104 -53
- package/dist/index.d.ts +7 -0
- package/dist/index.js +14 -0
- package/dist/layout/AppHeader.js +2 -2
- package/dist/layout/AppSidebar.js +20 -1
- package/dist/layout/UnifiedSidebar.js +1 -1
- package/dist/providers/ExpressionProvider.d.ts +11 -1
- package/dist/providers/ExpressionProvider.js +11 -6
- package/dist/services/builtinComponents.d.ts +1 -0
- package/dist/services/builtinComponents.js +166 -0
- package/dist/services/componentRegistry.d.ts +63 -0
- package/dist/services/componentRegistry.js +36 -0
- package/dist/views/ComponentNavView.d.ts +6 -0
- package/dist/views/ComponentNavView.js +26 -0
- package/dist/views/RecordDetailView.js +66 -6
- package/dist/views/RecordFormPage.js +15 -3
- package/dist/views/SearchResultsPage.js +4 -0
- package/dist/views/metadata-admin/DesignerEditorWrapper.d.ts +58 -0
- package/dist/views/metadata-admin/DesignerEditorWrapper.js +140 -0
- package/dist/views/metadata-admin/DirectoryPage.d.ts +1 -0
- package/dist/views/metadata-admin/DirectoryPage.js +135 -0
- package/dist/views/metadata-admin/LayeredDiff.d.ts +6 -0
- package/dist/views/metadata-admin/LayeredDiff.js +26 -0
- package/dist/views/metadata-admin/PageShell.d.ts +34 -0
- package/dist/views/metadata-admin/PageShell.js +33 -0
- package/dist/views/metadata-admin/PermissionMatrixEditor.d.ts +5 -0
- package/dist/views/metadata-admin/PermissionMatrixEditor.js +288 -0
- package/dist/views/metadata-admin/QuickFind.d.ts +5 -0
- package/dist/views/metadata-admin/QuickFind.js +152 -0
- package/dist/views/metadata-admin/ResourceEditPage.d.ts +7 -0
- package/dist/views/metadata-admin/ResourceEditPage.js +256 -0
- package/dist/views/metadata-admin/ResourceHistoryPage.d.ts +5 -0
- package/dist/views/metadata-admin/ResourceHistoryPage.js +97 -0
- package/dist/views/metadata-admin/ResourceListPage.d.ts +4 -0
- package/dist/views/metadata-admin/ResourceListPage.js +144 -0
- package/dist/views/metadata-admin/ResourceRouter.d.ts +10 -0
- package/dist/views/metadata-admin/ResourceRouter.js +47 -0
- package/dist/views/metadata-admin/SchemaForm.d.ts +99 -0
- package/dist/views/metadata-admin/SchemaForm.js +556 -0
- package/dist/views/metadata-admin/default-schemas.d.ts +6 -0
- package/dist/views/metadata-admin/default-schemas.js +207 -0
- package/dist/views/metadata-admin/i18n.d.ts +33 -0
- package/dist/views/metadata-admin/i18n.js +303 -0
- package/dist/views/metadata-admin/index.d.ts +31 -0
- package/dist/views/metadata-admin/index.js +33 -0
- package/dist/views/metadata-admin/predicate.d.ts +31 -0
- package/dist/views/metadata-admin/predicate.js +150 -0
- package/dist/views/metadata-admin/registry.d.ts +125 -0
- package/dist/views/metadata-admin/registry.js +48 -0
- package/dist/views/metadata-admin/useMetadata.d.ts +37 -0
- package/dist/views/metadata-admin/useMetadata.js +96 -0
- package/dist/views/metadata-admin/widgets.d.ts +68 -0
- package/dist/views/metadata-admin/widgets.js +287 -0
- package/package.json +27 -26
|
@@ -0,0 +1,207 @@
|
|
|
1
|
+
// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.
|
|
2
|
+
/**
|
|
3
|
+
* default-schemas — minimal JSONSchemas used by SchemaForm when the
|
|
4
|
+
* framework's `/meta/types` registry row doesn't carry a `schema` field
|
|
5
|
+
* (i.e. for every type today — full Zod→JSONSchema generation in the
|
|
6
|
+
* framework is a deferred milestone).
|
|
7
|
+
*
|
|
8
|
+
* These schemas cover the universal metadata header (name/label/
|
|
9
|
+
* description/scope) plus the small set of per-type "obvious" fields
|
|
10
|
+
* users expect on day one. Anything that doesn't fit here can still be
|
|
11
|
+
* edited via the raw JSON escape hatch — the schema is intentionally
|
|
12
|
+
* lax (no `additionalProperties: false`) so unknown payload keys round-
|
|
13
|
+
* trip untouched.
|
|
14
|
+
*
|
|
15
|
+
* When the framework starts emitting JSONSchemas in the registry, this
|
|
16
|
+
* file becomes a no-op (SchemaForm receives the real schema and ignores
|
|
17
|
+
* `defaultSchema`).
|
|
18
|
+
*/
|
|
19
|
+
import { registerMetadataResource } from './registry';
|
|
20
|
+
/** Shared header fields every metadata item has. */
|
|
21
|
+
const headerProps = {
|
|
22
|
+
name: {
|
|
23
|
+
type: 'string',
|
|
24
|
+
title: 'Name',
|
|
25
|
+
description: 'Machine name. snake_case, used as the URL path and DB key.',
|
|
26
|
+
pattern: '^[a-z_][a-z0-9_]*$',
|
|
27
|
+
},
|
|
28
|
+
label: {
|
|
29
|
+
type: 'string',
|
|
30
|
+
title: 'Label',
|
|
31
|
+
description: 'Human-readable display name.',
|
|
32
|
+
},
|
|
33
|
+
description: {
|
|
34
|
+
type: 'string',
|
|
35
|
+
title: 'Description',
|
|
36
|
+
format: 'multiline',
|
|
37
|
+
},
|
|
38
|
+
};
|
|
39
|
+
/** Per-type fallback schemas. */
|
|
40
|
+
const SCHEMAS = {
|
|
41
|
+
role: {
|
|
42
|
+
type: 'object',
|
|
43
|
+
title: 'Role',
|
|
44
|
+
required: ['name'],
|
|
45
|
+
properties: {
|
|
46
|
+
...headerProps,
|
|
47
|
+
level: {
|
|
48
|
+
type: 'string',
|
|
49
|
+
title: 'Level',
|
|
50
|
+
description: 'Coarse seniority tier (used by UI / sort order).',
|
|
51
|
+
enum: ['member', 'lead', 'manager', 'director', 'executive', 'admin'],
|
|
52
|
+
},
|
|
53
|
+
parentRole: {
|
|
54
|
+
type: 'string',
|
|
55
|
+
title: 'Parent Role',
|
|
56
|
+
description: 'Optional parent role name for hierarchy.',
|
|
57
|
+
},
|
|
58
|
+
},
|
|
59
|
+
},
|
|
60
|
+
profile: {
|
|
61
|
+
type: 'object',
|
|
62
|
+
title: 'Profile',
|
|
63
|
+
required: ['name'],
|
|
64
|
+
properties: {
|
|
65
|
+
...headerProps,
|
|
66
|
+
isProfile: { type: 'boolean', title: 'Is profile', description: 'Profiles are mutually exclusive (one per user).' },
|
|
67
|
+
objects: {
|
|
68
|
+
type: 'object',
|
|
69
|
+
title: 'Object Permissions',
|
|
70
|
+
description: 'Edit this via the Permission Matrix tab for a row-by-row UI.',
|
|
71
|
+
},
|
|
72
|
+
},
|
|
73
|
+
},
|
|
74
|
+
permission: {
|
|
75
|
+
type: 'object',
|
|
76
|
+
title: 'Permission Set',
|
|
77
|
+
required: ['name'],
|
|
78
|
+
properties: {
|
|
79
|
+
...headerProps,
|
|
80
|
+
isProfile: { type: 'boolean', title: 'Is profile' },
|
|
81
|
+
objects: { type: 'object', title: 'Object Permissions' },
|
|
82
|
+
fields: { type: 'object', title: 'Field Permissions' },
|
|
83
|
+
},
|
|
84
|
+
},
|
|
85
|
+
translation: {
|
|
86
|
+
type: 'object',
|
|
87
|
+
title: 'Translation Bundle',
|
|
88
|
+
required: ['name'],
|
|
89
|
+
properties: {
|
|
90
|
+
name: { ...headerProps.name, description: 'Bundle id (e.g. zh_CN, en_US, package-locale).' },
|
|
91
|
+
label: headerProps.label,
|
|
92
|
+
description: headerProps.description,
|
|
93
|
+
locale: {
|
|
94
|
+
type: 'string',
|
|
95
|
+
title: 'Locale',
|
|
96
|
+
description: 'BCP-47 tag, e.g. en, zh-Hans, ja-JP.',
|
|
97
|
+
},
|
|
98
|
+
strings: {
|
|
99
|
+
type: 'object',
|
|
100
|
+
title: 'Strings',
|
|
101
|
+
description: 'Key → translated string map.',
|
|
102
|
+
},
|
|
103
|
+
},
|
|
104
|
+
},
|
|
105
|
+
tool: {
|
|
106
|
+
type: 'object',
|
|
107
|
+
title: 'AI Tool',
|
|
108
|
+
required: ['name'],
|
|
109
|
+
properties: {
|
|
110
|
+
...headerProps,
|
|
111
|
+
kind: {
|
|
112
|
+
type: 'string',
|
|
113
|
+
title: 'Kind',
|
|
114
|
+
enum: ['function', 'http', 'mcp'],
|
|
115
|
+
},
|
|
116
|
+
inputSchema: { type: 'object', title: 'Input Schema (JSON Schema)' },
|
|
117
|
+
outputSchema: { type: 'object', title: 'Output Schema (JSON Schema)' },
|
|
118
|
+
},
|
|
119
|
+
},
|
|
120
|
+
skill: {
|
|
121
|
+
type: 'object',
|
|
122
|
+
title: 'AI Skill',
|
|
123
|
+
required: ['name'],
|
|
124
|
+
properties: {
|
|
125
|
+
...headerProps,
|
|
126
|
+
instructions: { type: 'string', title: 'Instructions', format: 'multiline' },
|
|
127
|
+
tools: { type: 'array', title: 'Tools', items: { type: 'string' } },
|
|
128
|
+
},
|
|
129
|
+
},
|
|
130
|
+
app: {
|
|
131
|
+
type: 'object',
|
|
132
|
+
title: 'Application',
|
|
133
|
+
required: ['name'],
|
|
134
|
+
properties: {
|
|
135
|
+
...headerProps,
|
|
136
|
+
icon: { type: 'string', title: 'Icon' },
|
|
137
|
+
navigation: { type: 'array', title: 'Navigation', items: { type: 'object' } },
|
|
138
|
+
},
|
|
139
|
+
},
|
|
140
|
+
page: {
|
|
141
|
+
type: 'object',
|
|
142
|
+
title: 'Page',
|
|
143
|
+
required: ['name'],
|
|
144
|
+
properties: {
|
|
145
|
+
...headerProps,
|
|
146
|
+
route: { type: 'string', title: 'Route', description: 'URL path under the app.' },
|
|
147
|
+
layout: { type: 'string', title: 'Layout' },
|
|
148
|
+
},
|
|
149
|
+
},
|
|
150
|
+
view: {
|
|
151
|
+
type: 'object',
|
|
152
|
+
title: 'View',
|
|
153
|
+
required: ['name'],
|
|
154
|
+
properties: {
|
|
155
|
+
...headerProps,
|
|
156
|
+
type: {
|
|
157
|
+
type: 'string',
|
|
158
|
+
title: 'View Type',
|
|
159
|
+
enum: ['grid', 'kanban', 'calendar', 'gantt', 'simple', 'tabbed', 'wizard', 'split', 'drawer', 'modal'],
|
|
160
|
+
},
|
|
161
|
+
},
|
|
162
|
+
},
|
|
163
|
+
dashboard: {
|
|
164
|
+
type: 'object',
|
|
165
|
+
title: 'Dashboard',
|
|
166
|
+
required: ['name'],
|
|
167
|
+
properties: {
|
|
168
|
+
...headerProps,
|
|
169
|
+
widgets: { type: 'array', title: 'Widgets', items: { type: 'object' } },
|
|
170
|
+
},
|
|
171
|
+
},
|
|
172
|
+
report: {
|
|
173
|
+
type: 'object',
|
|
174
|
+
title: 'Report',
|
|
175
|
+
required: ['name'],
|
|
176
|
+
properties: {
|
|
177
|
+
...headerProps,
|
|
178
|
+
object: { type: 'string', title: 'Object' },
|
|
179
|
+
filters: { type: 'array', title: 'Filters', items: { type: 'object' } },
|
|
180
|
+
},
|
|
181
|
+
},
|
|
182
|
+
email_template: {
|
|
183
|
+
type: 'object',
|
|
184
|
+
title: 'Email Template',
|
|
185
|
+
required: ['name'],
|
|
186
|
+
properties: {
|
|
187
|
+
...headerProps,
|
|
188
|
+
subject: { type: 'string', title: 'Subject' },
|
|
189
|
+
body: { type: 'string', title: 'Body (HTML / text)', format: 'multiline' },
|
|
190
|
+
from: { type: 'string', title: 'From address' },
|
|
191
|
+
},
|
|
192
|
+
},
|
|
193
|
+
};
|
|
194
|
+
/**
|
|
195
|
+
* Register fallback schemas for every writable type. Idempotent — uses
|
|
196
|
+
* `registerMetadataResource` so any prior registration (e.g. a bespoke
|
|
197
|
+
* EditPage from PermissionMatrixEditor) is merged via the engine.
|
|
198
|
+
*/
|
|
199
|
+
export function registerDefaultMetadataSchemas() {
|
|
200
|
+
for (const [type, schema] of Object.entries(SCHEMAS)) {
|
|
201
|
+
registerMetadataResource({
|
|
202
|
+
type,
|
|
203
|
+
defaultSchema: schema,
|
|
204
|
+
fieldOrder: ['name', 'label', 'description'],
|
|
205
|
+
});
|
|
206
|
+
}
|
|
207
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Metadata admin i18n bundle (Phase 3f).
|
|
3
|
+
*
|
|
4
|
+
* Lightweight static label table for the 27 built-in metadata types,
|
|
5
|
+
* plus a tiny `t()` helper for engine UI strings.
|
|
6
|
+
*
|
|
7
|
+
* Why not i18next? The engine already consumes `label` from the
|
|
8
|
+
* server's `/meta/types` response (which is sourced from
|
|
9
|
+
* `DEFAULT_METADATA_TYPE_REGISTRY`). This bundle exists as a fallback
|
|
10
|
+
* for environments without translation bundles configured, and as the
|
|
11
|
+
* single source of truth for Chinese labels until the platform's
|
|
12
|
+
* `setup.translation.ts` ships zh-CN coverage.
|
|
13
|
+
*
|
|
14
|
+
* Usage:
|
|
15
|
+
* import { translateMetadataType, t } from './i18n';
|
|
16
|
+
* translateMetadataType('view', 'zh-CN') // → '视图'
|
|
17
|
+
* t('engine.directory.title', 'zh-CN') // → '元数据'
|
|
18
|
+
*
|
|
19
|
+
* The DirectoryPage / PageShell call these to localise headings when
|
|
20
|
+
* the consumer hasn't wired the global i18n provider.
|
|
21
|
+
*/
|
|
22
|
+
export type SupportedLocale = 'en-US' | 'zh-CN';
|
|
23
|
+
export declare function translateMetadataType(type: string, locale?: SupportedLocale | string, fallback?: string): string;
|
|
24
|
+
export declare function translateMetadataDomain(domain: string, locale?: SupportedLocale | string): string;
|
|
25
|
+
export declare function t(key: string, locale?: SupportedLocale | string): string;
|
|
26
|
+
/**
|
|
27
|
+
* Format a translated string with `{token}` placeholders.
|
|
28
|
+
*
|
|
29
|
+
* tFormat('engine.directory.description', 'zh-CN', { count: 28, writable: 4 })
|
|
30
|
+
*/
|
|
31
|
+
export declare function tFormat(key: string, locale: SupportedLocale | string | undefined, vars: Record<string, string | number>): string;
|
|
32
|
+
/** Returns the locale string most browsers report (matches navigator.language). */
|
|
33
|
+
export declare function detectLocale(): SupportedLocale;
|
|
@@ -0,0 +1,303 @@
|
|
|
1
|
+
// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.
|
|
2
|
+
const TYPE_LABELS_EN = {
|
|
3
|
+
// Data
|
|
4
|
+
object: 'Object',
|
|
5
|
+
field: 'Field',
|
|
6
|
+
trigger: 'Trigger',
|
|
7
|
+
validation: 'Validation Rule',
|
|
8
|
+
hook: 'Hook',
|
|
9
|
+
// UI
|
|
10
|
+
view: 'View',
|
|
11
|
+
page: 'Page',
|
|
12
|
+
dashboard: 'Dashboard',
|
|
13
|
+
app: 'Application',
|
|
14
|
+
action: 'Action',
|
|
15
|
+
report: 'Report',
|
|
16
|
+
// Automation
|
|
17
|
+
flow: 'Flow',
|
|
18
|
+
workflow: 'Workflow',
|
|
19
|
+
approval: 'Approval Process',
|
|
20
|
+
// System
|
|
21
|
+
datasource: 'Datasource',
|
|
22
|
+
translation: 'Translation',
|
|
23
|
+
router: 'Router',
|
|
24
|
+
function: 'Function',
|
|
25
|
+
service: 'Service',
|
|
26
|
+
email_template: 'Email Template',
|
|
27
|
+
// Security
|
|
28
|
+
permission: 'Permission Set',
|
|
29
|
+
profile: 'Profile',
|
|
30
|
+
role: 'Role',
|
|
31
|
+
// AI
|
|
32
|
+
agent: 'AI Agent',
|
|
33
|
+
tool: 'AI Tool',
|
|
34
|
+
skill: 'AI Skill',
|
|
35
|
+
// Platform
|
|
36
|
+
package: 'Package',
|
|
37
|
+
data: 'Dataset',
|
|
38
|
+
};
|
|
39
|
+
const TYPE_LABELS_ZH = {
|
|
40
|
+
object: '对象',
|
|
41
|
+
field: '字段',
|
|
42
|
+
trigger: '触发器',
|
|
43
|
+
validation: '校验规则',
|
|
44
|
+
hook: '钩子',
|
|
45
|
+
view: '视图',
|
|
46
|
+
page: '页面',
|
|
47
|
+
dashboard: '仪表板',
|
|
48
|
+
app: '应用',
|
|
49
|
+
action: '操作',
|
|
50
|
+
report: '报表',
|
|
51
|
+
flow: '流程',
|
|
52
|
+
workflow: '工作流',
|
|
53
|
+
approval: '审批流程',
|
|
54
|
+
datasource: '数据源',
|
|
55
|
+
translation: '翻译',
|
|
56
|
+
router: '路由',
|
|
57
|
+
function: '函数',
|
|
58
|
+
service: '服务',
|
|
59
|
+
email_template: '邮件模板',
|
|
60
|
+
permission: '权限集',
|
|
61
|
+
profile: '配置文件',
|
|
62
|
+
role: '角色',
|
|
63
|
+
agent: 'AI 智能体',
|
|
64
|
+
tool: 'AI 工具',
|
|
65
|
+
skill: 'AI 技能',
|
|
66
|
+
package: '包',
|
|
67
|
+
data: '数据集',
|
|
68
|
+
};
|
|
69
|
+
const DOMAIN_LABELS_EN = {
|
|
70
|
+
data: 'Data',
|
|
71
|
+
ui: 'UI',
|
|
72
|
+
automation: 'Automation',
|
|
73
|
+
ai: 'AI',
|
|
74
|
+
system: 'System',
|
|
75
|
+
platform: 'Platform',
|
|
76
|
+
identity: 'Identity',
|
|
77
|
+
security: 'Security',
|
|
78
|
+
other: 'Other',
|
|
79
|
+
};
|
|
80
|
+
const DOMAIN_LABELS_ZH = {
|
|
81
|
+
data: '数据',
|
|
82
|
+
ui: '界面',
|
|
83
|
+
automation: '自动化',
|
|
84
|
+
ai: 'AI',
|
|
85
|
+
system: '系统',
|
|
86
|
+
platform: '平台',
|
|
87
|
+
identity: '身份',
|
|
88
|
+
security: '安全',
|
|
89
|
+
other: '其他',
|
|
90
|
+
};
|
|
91
|
+
const ENGINE_STRINGS_EN = {
|
|
92
|
+
'engine.directory.title': 'All Metadata Types',
|
|
93
|
+
'engine.directory.description': 'The platform protocol exposes {count} metadata types ({writable} writable at runtime). Click any tile to browse, override, or create instances.',
|
|
94
|
+
'engine.directory.search': 'Search metadata types…',
|
|
95
|
+
'engine.directory.writableOnly': 'Writable only',
|
|
96
|
+
'engine.directory.quickFind': 'Quick Find',
|
|
97
|
+
'engine.directory.noMatches': 'No matches',
|
|
98
|
+
'engine.directory.noMatchesHint': 'Adjust your search or filters to see more metadata types.',
|
|
99
|
+
'engine.directory.loading': 'Loading metadata types…',
|
|
100
|
+
'engine.directory.loadFailed': 'Failed to load metadata types',
|
|
101
|
+
'engine.directory.all': 'All',
|
|
102
|
+
'engine.list.create': 'New',
|
|
103
|
+
'engine.list.refresh': 'Refresh',
|
|
104
|
+
'engine.list.search': 'Search name, label, description…',
|
|
105
|
+
'engine.list.empty': 'No items yet.',
|
|
106
|
+
'engine.list.items': 'Items',
|
|
107
|
+
'engine.list.filtered': 'Filtered',
|
|
108
|
+
'engine.list.allSources': 'All sources',
|
|
109
|
+
'engine.list.col.name': 'Name',
|
|
110
|
+
'engine.list.col.label': 'Label',
|
|
111
|
+
'engine.list.col.source': 'Source',
|
|
112
|
+
'engine.list.col.object': 'Object',
|
|
113
|
+
'engine.list.col.type': 'Type',
|
|
114
|
+
'engine.edit.save': 'Save',
|
|
115
|
+
'engine.edit.reset': 'Reset overlay',
|
|
116
|
+
'engine.edit.resetConfirm': 'Reset overlay for {type}/{name}?',
|
|
117
|
+
'engine.edit.history': 'History',
|
|
118
|
+
'engine.edit.layers': 'Layers',
|
|
119
|
+
'engine.edit.references': 'References',
|
|
120
|
+
'engine.edit.form': 'Form',
|
|
121
|
+
'engine.edit.readOnly': 'Read-only (runtime overrides disabled).',
|
|
122
|
+
'engine.edit.loading': 'Loading',
|
|
123
|
+
'engine.edit.bespokeDesigner': 'Designer',
|
|
124
|
+
'engine.edit.readOnlyHint': 'Read-only — this metadata type does not allow runtime overrides. Edit the source in the package and redeploy.',
|
|
125
|
+
'engine.edit.unsaved': 'Unsaved',
|
|
126
|
+
'engine.edit.unsavedHint': 'You have unsaved changes.',
|
|
127
|
+
'engine.edit.destructive': 'Destructive change',
|
|
128
|
+
'engine.edit.destructiveHint': 'The change would break existing references. Review the issues and confirm to force-save.',
|
|
129
|
+
'engine.edit.forceSave': 'Force save',
|
|
130
|
+
'engine.cancel': 'Cancel',
|
|
131
|
+
'engine.quickfind.placeholder': "Find metadata types or items… (try 'view', 'account')",
|
|
132
|
+
'engine.quickfind.empty': 'Type to search across all metadata types.',
|
|
133
|
+
'engine.quickfind.title': 'Quick Find',
|
|
134
|
+
'engine.quickfind.indexing': 'Indexing items across',
|
|
135
|
+
'engine.quickfind.noMatches': 'No matches.',
|
|
136
|
+
'engine.breadcrumb.allTypes': 'All Metadata Types',
|
|
137
|
+
// Permission matrix
|
|
138
|
+
'perm.action.create': 'Create',
|
|
139
|
+
'perm.action.read': 'Read',
|
|
140
|
+
'perm.action.edit': 'Edit',
|
|
141
|
+
'perm.action.delete': 'Delete',
|
|
142
|
+
'perm.action.transfer': 'Transfer ownership',
|
|
143
|
+
'perm.action.restore': 'Restore from trash',
|
|
144
|
+
'perm.action.purge': 'Hard delete (purge)',
|
|
145
|
+
'perm.action.viewAll': 'View All Records (bypass sharing)',
|
|
146
|
+
'perm.action.modifyAll': 'Modify All Records (bypass sharing)',
|
|
147
|
+
'perm.col.object': 'Object',
|
|
148
|
+
'perm.col.bulk': 'Bulk',
|
|
149
|
+
'perm.bulk.read': 'R',
|
|
150
|
+
'perm.bulk.crud': 'CRUD',
|
|
151
|
+
'perm.bulk.all': 'All',
|
|
152
|
+
'perm.bulk.none': 'None',
|
|
153
|
+
'perm.filter.placeholder': 'Filter objects…',
|
|
154
|
+
'perm.filter.onlyGranted': 'Only granted',
|
|
155
|
+
'perm.filter.empty': 'No objects match the filter.',
|
|
156
|
+
'perm.field.name': 'Name',
|
|
157
|
+
'perm.field.label': 'Label',
|
|
158
|
+
'perm.field.isProfile': 'Is profile',
|
|
159
|
+
'perm.field.loading': 'Loading fields…',
|
|
160
|
+
'perm.field.empty': 'No fields registered for this object.',
|
|
161
|
+
'perm.field.col.name': 'Field',
|
|
162
|
+
'perm.field.read': 'Read',
|
|
163
|
+
'perm.field.edit': 'Edit',
|
|
164
|
+
'perm.stat.objects': 'Objects granted',
|
|
165
|
+
'perm.stat.fields': 'Fields granted',
|
|
166
|
+
'perm.stat.objectsGranted': 'Objects granted',
|
|
167
|
+
'perm.stat.fieldOverrides': 'Field overrides',
|
|
168
|
+
'perm.stat.objectsSuffix': 'objects',
|
|
169
|
+
'perm.subtitle.profile': 'Profile',
|
|
170
|
+
'perm.subtitle.set': 'Permission set',
|
|
171
|
+
'perm.loading': 'Loading permission set {name}…',
|
|
172
|
+
'perm.readOnly': 'Read-only (OS_METADATA_WRITABLE not enabled)',
|
|
173
|
+
// Designer wrapper
|
|
174
|
+
'designer.unsavedChanges': 'Unsaved changes',
|
|
175
|
+
'designer.editingOverlay': 'Editing overlay',
|
|
176
|
+
'designer.codeBaseline': 'Code baseline',
|
|
177
|
+
};
|
|
178
|
+
const ENGINE_STRINGS_ZH = {
|
|
179
|
+
'engine.directory.title': '元数据',
|
|
180
|
+
'engine.directory.description': '平台协议共暴露 {count} 个元数据类型(其中 {writable} 个支持运行时覆盖)。点击任意卡片即可浏览、覆盖或创建实例。',
|
|
181
|
+
'engine.directory.search': '搜索元数据类型…',
|
|
182
|
+
'engine.directory.writableOnly': '仅显示可写',
|
|
183
|
+
'engine.directory.quickFind': '快速查找',
|
|
184
|
+
'engine.directory.noMatches': '没有匹配项',
|
|
185
|
+
'engine.directory.noMatchesHint': '调整搜索或筛选条件以查看更多元数据类型。',
|
|
186
|
+
'engine.directory.loading': '正在加载元数据类型…',
|
|
187
|
+
'engine.directory.loadFailed': '加载元数据类型失败',
|
|
188
|
+
'engine.directory.all': '全部',
|
|
189
|
+
'engine.list.create': '新建',
|
|
190
|
+
'engine.list.refresh': '刷新',
|
|
191
|
+
'engine.list.search': '搜索名称、标签或描述…',
|
|
192
|
+
'engine.list.empty': '暂无数据。',
|
|
193
|
+
'engine.list.items': '条目',
|
|
194
|
+
'engine.list.filtered': '已筛选',
|
|
195
|
+
'engine.list.allSources': '全部来源',
|
|
196
|
+
'engine.list.col.name': '名称',
|
|
197
|
+
'engine.list.col.label': '标签',
|
|
198
|
+
'engine.list.col.source': '来源',
|
|
199
|
+
'engine.list.col.object': '对象',
|
|
200
|
+
'engine.list.col.type': '类型',
|
|
201
|
+
'engine.edit.save': '保存',
|
|
202
|
+
'engine.edit.reset': '重置覆盖',
|
|
203
|
+
'engine.edit.resetConfirm': '重置 {type}/{name} 的覆盖层?',
|
|
204
|
+
'engine.edit.history': '历史',
|
|
205
|
+
'engine.edit.layers': '层次',
|
|
206
|
+
'engine.edit.references': '引用关系',
|
|
207
|
+
'engine.edit.form': '表单',
|
|
208
|
+
'engine.edit.readOnly': '只读(运行时覆盖未启用)。',
|
|
209
|
+
'engine.edit.loading': '加载中',
|
|
210
|
+
'engine.edit.bespokeDesigner': '可视化编辑器',
|
|
211
|
+
'engine.edit.readOnlyHint': '只读 — 该元数据类型不支持运行时覆盖。请修改包内源代码并重新部署。',
|
|
212
|
+
'engine.edit.unsaved': '未保存',
|
|
213
|
+
'engine.edit.unsavedHint': '当前存在未保存的修改。',
|
|
214
|
+
'engine.edit.destructive': '破坏性变更',
|
|
215
|
+
'engine.edit.destructiveHint': '该修改会破坏现有引用关系。请检查问题清单后确认强制保存。',
|
|
216
|
+
'engine.edit.forceSave': '强制保存',
|
|
217
|
+
'engine.cancel': '取消',
|
|
218
|
+
'engine.quickfind.placeholder': '搜索元数据类型或条目…(如:view、account)',
|
|
219
|
+
'engine.quickfind.empty': '输入关键字以搜索所有元数据类型。',
|
|
220
|
+
'engine.quickfind.title': '快速查找',
|
|
221
|
+
'engine.quickfind.indexing': '正在索引所有类型,共',
|
|
222
|
+
'engine.quickfind.noMatches': '没有匹配项。',
|
|
223
|
+
'engine.breadcrumb.allTypes': '元数据',
|
|
224
|
+
// Permission matrix
|
|
225
|
+
'perm.action.create': '创建',
|
|
226
|
+
'perm.action.read': '读取',
|
|
227
|
+
'perm.action.edit': '编辑',
|
|
228
|
+
'perm.action.delete': '删除',
|
|
229
|
+
'perm.action.transfer': '转移所有者',
|
|
230
|
+
'perm.action.restore': '从回收站恢复',
|
|
231
|
+
'perm.action.purge': '彻底删除',
|
|
232
|
+
'perm.action.viewAll': '查看所有记录(绕过共享规则)',
|
|
233
|
+
'perm.action.modifyAll': '修改所有记录(绕过共享规则)',
|
|
234
|
+
'perm.col.object': '对象',
|
|
235
|
+
'perm.col.bulk': '批量',
|
|
236
|
+
'perm.bulk.read': '读',
|
|
237
|
+
'perm.bulk.crud': '增改删',
|
|
238
|
+
'perm.bulk.all': '全选',
|
|
239
|
+
'perm.bulk.none': '清空',
|
|
240
|
+
'perm.filter.placeholder': '筛选对象…',
|
|
241
|
+
'perm.filter.onlyGranted': '只看已授权',
|
|
242
|
+
'perm.filter.empty': '没有匹配的对象。',
|
|
243
|
+
'perm.field.name': '名称',
|
|
244
|
+
'perm.field.label': '标签',
|
|
245
|
+
'perm.field.isProfile': '作为 Profile',
|
|
246
|
+
'perm.field.loading': '加载字段中…',
|
|
247
|
+
'perm.field.empty': '该对象未注册字段。',
|
|
248
|
+
'perm.field.col.name': '字段',
|
|
249
|
+
'perm.field.read': '读',
|
|
250
|
+
'perm.field.edit': '改',
|
|
251
|
+
'perm.stat.objects': '已授权对象',
|
|
252
|
+
'perm.stat.fields': '已授权字段',
|
|
253
|
+
'perm.stat.objectsGranted': '已授权对象',
|
|
254
|
+
'perm.stat.fieldOverrides': '字段覆盖',
|
|
255
|
+
'perm.stat.objectsSuffix': '个对象',
|
|
256
|
+
'perm.subtitle.profile': 'Profile',
|
|
257
|
+
'perm.subtitle.set': '权限集',
|
|
258
|
+
'perm.loading': '加载权限集 {name}…',
|
|
259
|
+
'perm.readOnly': '只读(OS_METADATA_WRITABLE 未启用)',
|
|
260
|
+
// Designer wrapper
|
|
261
|
+
'designer.unsavedChanges': '未保存的修改',
|
|
262
|
+
'designer.editingOverlay': '编辑覆盖层',
|
|
263
|
+
'designer.codeBaseline': '代码基线',
|
|
264
|
+
};
|
|
265
|
+
function pickTable(locale) {
|
|
266
|
+
const lower = (locale ?? '').toLowerCase();
|
|
267
|
+
if (lower.startsWith('zh')) {
|
|
268
|
+
return { types: TYPE_LABELS_ZH, domains: DOMAIN_LABELS_ZH, strings: ENGINE_STRINGS_ZH };
|
|
269
|
+
}
|
|
270
|
+
return { types: TYPE_LABELS_EN, domains: DOMAIN_LABELS_EN, strings: ENGINE_STRINGS_EN };
|
|
271
|
+
}
|
|
272
|
+
export function translateMetadataType(type, locale, fallback) {
|
|
273
|
+
// Prefer locale table when the locale has a translation for this type.
|
|
274
|
+
// This ensures Chinese labels win over the English `label` baked into
|
|
275
|
+
// the server's metadata registry (which would otherwise show "Field"
|
|
276
|
+
// even when the user's locale is zh-CN).
|
|
277
|
+
const localized = pickTable(locale).types[type];
|
|
278
|
+
if (localized)
|
|
279
|
+
return localized;
|
|
280
|
+
// Fall back to caller-supplied label (typically the server's English one).
|
|
281
|
+
return fallback ?? type;
|
|
282
|
+
}
|
|
283
|
+
export function translateMetadataDomain(domain, locale) {
|
|
284
|
+
return pickTable(locale).domains[domain] ?? domain;
|
|
285
|
+
}
|
|
286
|
+
export function t(key, locale) {
|
|
287
|
+
return pickTable(locale).strings[key] ?? key;
|
|
288
|
+
}
|
|
289
|
+
/**
|
|
290
|
+
* Format a translated string with `{token}` placeholders.
|
|
291
|
+
*
|
|
292
|
+
* tFormat('engine.directory.description', 'zh-CN', { count: 28, writable: 4 })
|
|
293
|
+
*/
|
|
294
|
+
export function tFormat(key, locale, vars) {
|
|
295
|
+
const template = t(key, locale);
|
|
296
|
+
return template.replace(/\{(\w+)\}/g, (_m, name) => name in vars ? String(vars[name]) : `{${name}}`);
|
|
297
|
+
}
|
|
298
|
+
/** Returns the locale string most browsers report (matches navigator.language). */
|
|
299
|
+
export function detectLocale() {
|
|
300
|
+
if (typeof navigator !== 'undefined' && /^zh/i.test(navigator.language))
|
|
301
|
+
return 'zh-CN';
|
|
302
|
+
return 'en-US';
|
|
303
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Public surface for the metadata-admin engine (Phase 3c).
|
|
3
|
+
*
|
|
4
|
+
* Pages are registered with the ComponentRegistry in
|
|
5
|
+
* `../../services/builtinComponents.ts`; consumers (and plugins) can
|
|
6
|
+
* still import directly to compose custom shells.
|
|
7
|
+
*
|
|
8
|
+
* The Registry export lets plugin authors opt their bespoke editors
|
|
9
|
+
* into the generic shell:
|
|
10
|
+
*
|
|
11
|
+
* import { registerMetadataResource } from '@object-ui/app-shell';
|
|
12
|
+
* registerMetadataResource({ type: 'view', EditPage: MyViewEditor });
|
|
13
|
+
*/
|
|
14
|
+
export { MetadataDirectoryPage } from './DirectoryPage';
|
|
15
|
+
export { MetadataResourceRouter } from './ResourceRouter';
|
|
16
|
+
export { MetadataResourceListPage } from './ResourceListPage';
|
|
17
|
+
export { MetadataResourceEditPage } from './ResourceEditPage';
|
|
18
|
+
export { MetadataResourceHistoryPage } from './ResourceHistoryPage';
|
|
19
|
+
export { MetadataQuickFind } from './QuickFind';
|
|
20
|
+
export { PageShell as MetadataPageShell } from './PageShell';
|
|
21
|
+
export { SchemaForm } from './SchemaForm';
|
|
22
|
+
export { LayeredDiff } from './LayeredDiff';
|
|
23
|
+
export { PermissionMatrixEditPage } from './PermissionMatrixEditor';
|
|
24
|
+
export { DesignerEditorWrapper } from './DesignerEditorWrapper';
|
|
25
|
+
export type { DesignerEditorWrapperProps } from './DesignerEditorWrapper';
|
|
26
|
+
export { translateMetadataType, translateMetadataDomain, t as translateMetadataAdmin, detectLocale, } from './i18n';
|
|
27
|
+
export type { SupportedLocale } from './i18n';
|
|
28
|
+
export { registerMetadataResource, getMetadataResource, listMetadataResources, resolveResourceConfig, } from './registry';
|
|
29
|
+
export type { MetadataResourceConfig, MetadataDomain, } from './registry';
|
|
30
|
+
export { useMetadataClient, useMetadataTypes, useTypesIndex, matchesQuery, } from './useMetadata';
|
|
31
|
+
export type { RichMetadataTypeEntry } from './useMetadata';
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.
|
|
2
|
+
/**
|
|
3
|
+
* Public surface for the metadata-admin engine (Phase 3c).
|
|
4
|
+
*
|
|
5
|
+
* Pages are registered with the ComponentRegistry in
|
|
6
|
+
* `../../services/builtinComponents.ts`; consumers (and plugins) can
|
|
7
|
+
* still import directly to compose custom shells.
|
|
8
|
+
*
|
|
9
|
+
* The Registry export lets plugin authors opt their bespoke editors
|
|
10
|
+
* into the generic shell:
|
|
11
|
+
*
|
|
12
|
+
* import { registerMetadataResource } from '@object-ui/app-shell';
|
|
13
|
+
* registerMetadataResource({ type: 'view', EditPage: MyViewEditor });
|
|
14
|
+
*/
|
|
15
|
+
export { MetadataDirectoryPage } from './DirectoryPage';
|
|
16
|
+
export { MetadataResourceRouter } from './ResourceRouter';
|
|
17
|
+
export { MetadataResourceListPage } from './ResourceListPage';
|
|
18
|
+
export { MetadataResourceEditPage } from './ResourceEditPage';
|
|
19
|
+
export { MetadataResourceHistoryPage } from './ResourceHistoryPage';
|
|
20
|
+
export { MetadataQuickFind } from './QuickFind';
|
|
21
|
+
export { PageShell as MetadataPageShell } from './PageShell';
|
|
22
|
+
export { SchemaForm } from './SchemaForm';
|
|
23
|
+
export { LayeredDiff } from './LayeredDiff';
|
|
24
|
+
export { PermissionMatrixEditPage } from './PermissionMatrixEditor';
|
|
25
|
+
export { DesignerEditorWrapper } from './DesignerEditorWrapper';
|
|
26
|
+
export { translateMetadataType, translateMetadataDomain, t as translateMetadataAdmin, detectLocale, } from './i18n';
|
|
27
|
+
export { registerMetadataResource, getMetadataResource, listMetadataResources, resolveResourceConfig, } from './registry';
|
|
28
|
+
// Side-effect: register fallback JSONSchemas for the 12 writable types
|
|
29
|
+
// so the generic SchemaForm renders a real form (vs raw-JSON fallback)
|
|
30
|
+
// until the framework wires Zod→JSONSchema generation into /meta/types.
|
|
31
|
+
import { registerDefaultMetadataSchemas } from './default-schemas';
|
|
32
|
+
registerDefaultMetadataSchemas();
|
|
33
|
+
export { useMetadataClient, useMetadataTypes, useTypesIndex, matchesQuery, } from './useMetadata';
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tiny predicate evaluator for FormView `visibleOn` expressions.
|
|
3
|
+
*
|
|
4
|
+
* This is an interim stand-in for the full CEL runtime
|
|
5
|
+
* (`@objectstack/formula`) — we keep it intentionally small so the
|
|
6
|
+
* Setup admin engine has zero new runtime dependencies. When CEL is
|
|
7
|
+
* unified across the platform (ROADMAP M9), swap `evaluatePredicate`
|
|
8
|
+
* for the real CEL evaluator without touching SchemaForm.tsx.
|
|
9
|
+
*
|
|
10
|
+
* Supported subset (covers everything used in spec `*.form.ts` today):
|
|
11
|
+
* - `path == 'literal'` string equality
|
|
12
|
+
* - `path != 'literal'` string inequality
|
|
13
|
+
* - `path == 123` number equality
|
|
14
|
+
* - `path == true|false` boolean equality
|
|
15
|
+
* - `path in ['a','b']` membership
|
|
16
|
+
* - `!path` negation (truthy)
|
|
17
|
+
* - `path` truthy check
|
|
18
|
+
* - `path && expr` conjunction
|
|
19
|
+
* - `path || expr` disjunction
|
|
20
|
+
*
|
|
21
|
+
* Paths support dot notation: `data.type`, `data.config.kind`.
|
|
22
|
+
*
|
|
23
|
+
* On any parse error → returns `true` (fail-open): better to show a
|
|
24
|
+
* field than to silently hide it.
|
|
25
|
+
*/
|
|
26
|
+
export declare function evaluatePredicate(expr: string | {
|
|
27
|
+
dialect?: string;
|
|
28
|
+
source: string;
|
|
29
|
+
} | null | undefined, ctx: {
|
|
30
|
+
data: Record<string, unknown>;
|
|
31
|
+
}): boolean;
|