@ebay/muse-lib-antd 1.3.3 → 1.3.5
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/build/MUSE_README.md +971 -0
- package/build/dev/lib-manifest.json +74 -74
- package/build/dev/main.js +82 -82
- package/build/dist/deps-manifest.json +1 -1
- package/build/dist/lib-manifest.json +74 -74
- package/build/dist/main.js +1 -1
- package/build/test/deps-manifest.json +3 -3
- package/build/test/lib-manifest.json +74 -74
- package/build/test/main.js +1 -1
- package/package.json +3 -2
|
@@ -0,0 +1,971 @@
|
|
|
1
|
+
# Plugin Integration Guide: @ebay/muse-lib-antd
|
|
2
|
+
|
|
3
|
+
**Generated**: 2026-03-28
|
|
4
|
+
**Plugin Type**: lib
|
|
5
|
+
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
## Table of Contents
|
|
9
|
+
|
|
10
|
+
1. [Plugin Purpose & Overview](#1-plugin-purpose--overview)
|
|
11
|
+
2. [Extension Points Exposed](#2-extension-points-exposed)
|
|
12
|
+
3. [Extension Points Contributed](#3-extension-points-contributed)
|
|
13
|
+
4. [Exported Functionality](#4-exported-functionality)
|
|
14
|
+
5. [Integration Examples](#5-integration-examples)
|
|
15
|
+
|
|
16
|
+
---
|
|
17
|
+
|
|
18
|
+
## 1. Plugin Purpose & Overview
|
|
19
|
+
|
|
20
|
+
### What This Plugin Does
|
|
21
|
+
|
|
22
|
+
`@ebay/muse-lib-antd` is a library plugin that provides Ant Design (antd) UI components and utilities to MUSE applications. It serves as a shared UI framework layer, preventing code duplication by providing a single instance of Ant Design that all consuming plugins can use.
|
|
23
|
+
|
|
24
|
+
### Key Features
|
|
25
|
+
|
|
26
|
+
- **Ant Design Components**: Provides the complete Ant Design 5.x component library as shared modules
|
|
27
|
+
- **Reusable UI Components**: Offers custom-built components like MetaMenu, DropdownMenu, ErrorBox, CodeViewer, and more
|
|
28
|
+
- **Form Utilities**: Provides extensible form and array utilities via `extendFormMeta()` and `extendArray()`
|
|
29
|
+
- **Nice Form Integration**: Pre-configured Nice Form React with Ant Design adapter and custom widgets
|
|
30
|
+
- **Dark Mode Support**: Built-in dark mode theme switching with Redux state management
|
|
31
|
+
- **React Router Integration**: Provides route configuration and React Router setup
|
|
32
|
+
- **Redux State Management**: Includes Redux reducer for common state (dark mode, etc.)
|
|
33
|
+
- **Config Provider Wrapper**: Extensible Ant Design ConfigProvider with theme management
|
|
34
|
+
|
|
35
|
+
### Plugin Type: lib
|
|
36
|
+
|
|
37
|
+
As a **lib plugin**, this plugin loads before normal plugins and provides shared modules to avoid duplicating dependencies. Other plugins that depend on Ant Design or React will consume these modules from this plugin rather than bundling their own copies, reducing bundle size and ensuring version consistency.
|
|
38
|
+
|
|
39
|
+
---
|
|
40
|
+
|
|
41
|
+
## 2. Extension Points Exposed
|
|
42
|
+
|
|
43
|
+
This plugin exposes the following extension points that OTHER plugins can implement to extend its functionality.
|
|
44
|
+
|
|
45
|
+
### Summary
|
|
46
|
+
|
|
47
|
+
- **Total Extension Points**: 7 base patterns (expandable to unlimited via parameter-based extension points)
|
|
48
|
+
- **Categories**: Form Extensions, Array Extensions, Menu Extensions, ConfigProvider Extensions
|
|
49
|
+
|
|
50
|
+
### Extension Point Patterns
|
|
51
|
+
|
|
52
|
+
This plugin uses **parameter-based extension points**, where the extension point name is passed as a parameter to utility functions. This allows unlimited extensibility without hardcoding specific extension point names.
|
|
53
|
+
|
|
54
|
+
#### Form Extension Pattern (via `extendFormMeta`)
|
|
55
|
+
|
|
56
|
+
**Base Extension Point**: `${extBase}.*` (where `extBase` is provided by caller)
|
|
57
|
+
|
|
58
|
+
When a plugin calls `extendFormMeta(meta, extBase, ...args)`, other plugins can implement these extension points:
|
|
59
|
+
|
|
60
|
+
##### `${extBase}.preProcessMeta`
|
|
61
|
+
|
|
62
|
+
- **Purpose**: Hook to modify form metadata before fields are added
|
|
63
|
+
- **When Invoked**: Called at the start of `extendFormMeta()`, before any field processing
|
|
64
|
+
- **Context Parameters**:
|
|
65
|
+
- `...args`: Variable arguments passed through from the caller
|
|
66
|
+
- **Expected Return**: `void` (modifies arguments in place)
|
|
67
|
+
- **Use Case Example**: Initialize form state, add validators, or set up form-level configuration
|
|
68
|
+
- **File Reference**: src/utils.js:12
|
|
69
|
+
|
|
70
|
+
##### `${extBase}.getFields`
|
|
71
|
+
|
|
72
|
+
- **Purpose**: Allows plugins to contribute additional fields to the form
|
|
73
|
+
- **When Invoked**: Called during form metadata construction to gather field definitions
|
|
74
|
+
- **Context Parameters**:
|
|
75
|
+
- `...args`: Variable arguments passed through from the caller (typically includes form context, record data, etc.)
|
|
76
|
+
- **Expected Return**: `Array<FieldDefinition>` - Array of Nice Form field definitions
|
|
77
|
+
- **Use Case Example**: Add custom fields to app creation form, plugin info form, or any extensible form
|
|
78
|
+
- **File Reference**: src/utils.js:13
|
|
79
|
+
|
|
80
|
+
##### `${extBase}.processMeta`
|
|
81
|
+
|
|
82
|
+
- **Purpose**: Hook to modify the complete form metadata after fields are added
|
|
83
|
+
- **When Invoked**: Called after all fields are collected but before post-processing
|
|
84
|
+
- **Context Parameters**:
|
|
85
|
+
- `...args`: Variable arguments passed through from the caller
|
|
86
|
+
- **Expected Return**: `void` (modifies metadata in place)
|
|
87
|
+
- **Use Case Example**: Reorder fields, add field dependencies, modify field properties based on other fields
|
|
88
|
+
- **File Reference**: src/utils.js:15
|
|
89
|
+
|
|
90
|
+
##### `${extBase}.postProcessMeta`
|
|
91
|
+
|
|
92
|
+
- **Purpose**: Final hook to modify form metadata after all processing
|
|
93
|
+
- **When Invoked**: Called after all other form processing is complete
|
|
94
|
+
- **Context Parameters**:
|
|
95
|
+
- `...args`: Variable arguments passed through from the caller
|
|
96
|
+
- **Expected Return**: `void` (modifies metadata in place)
|
|
97
|
+
- **Use Case Example**: Apply final validation rules, add computed fields, or finalize form layout
|
|
98
|
+
- **File Reference**: src/utils.js:16
|
|
99
|
+
|
|
100
|
+
##### `${extBase}.getWatchingFields`
|
|
101
|
+
|
|
102
|
+
- **Purpose**: Allows plugins to define fields that should be watched for changes
|
|
103
|
+
- **When Invoked**: Called during form metadata construction to gather watching field configurations
|
|
104
|
+
- **Context Parameters**:
|
|
105
|
+
- `...args`: Variable arguments passed through from the caller
|
|
106
|
+
- **Expected Return**: `Array<WatchingFieldConfig>` - Array of watching field configurations for Nice Form
|
|
107
|
+
- **Use Case Example**: Define field dependencies where one field's value affects another's visibility or validation
|
|
108
|
+
- **File Reference**: src/utils.js:20
|
|
109
|
+
|
|
110
|
+
#### Array Extension Pattern (via `extendArray`)
|
|
111
|
+
|
|
112
|
+
**Base Extension Point**: `${extBase}.*` (where `extBase` and `extName` are provided by caller)
|
|
113
|
+
|
|
114
|
+
When a plugin calls `extendArray(arr, extName, extBase, ...args)`, other plugins can implement these extension points:
|
|
115
|
+
|
|
116
|
+
##### `${extBase}.preProcess${CapitalizedExtName}`
|
|
117
|
+
|
|
118
|
+
- **Purpose**: Hook to process array before items are added
|
|
119
|
+
- **When Invoked**: Called at the start of `extendArray()`, before collecting items
|
|
120
|
+
- **Context Parameters**:
|
|
121
|
+
- `...args`: Variable arguments passed through from the caller
|
|
122
|
+
- **Expected Return**: `void` (modifies arguments in place)
|
|
123
|
+
- **Use Case Example**: Initialize array context, set up filters
|
|
124
|
+
- **File Reference**: src/utils.js:38
|
|
125
|
+
|
|
126
|
+
##### `${extBase}.get${CapitalizedExtName}`
|
|
127
|
+
|
|
128
|
+
- **Purpose**: Allows plugins to contribute items to the array
|
|
129
|
+
- **When Invoked**: Called during array construction to gather items
|
|
130
|
+
- **Context Parameters**:
|
|
131
|
+
- `...args`: Variable arguments passed through from the caller
|
|
132
|
+
- **Expected Return**: `Array<any>` - Array of items to add
|
|
133
|
+
- **Use Case Example**: Add table columns, menu items, action buttons, tabs, etc.
|
|
134
|
+
- **File Reference**: src/utils.js:39
|
|
135
|
+
|
|
136
|
+
##### `${extBase}.process${CapitalizedExtName}`
|
|
137
|
+
|
|
138
|
+
- **Purpose**: Hook to modify array after items are collected
|
|
139
|
+
- **When Invoked**: Called after all items are gathered but before post-processing
|
|
140
|
+
- **Context Parameters**:
|
|
141
|
+
- `...args`: Variable arguments passed through from the caller
|
|
142
|
+
- **Expected Return**: `void` (modifies array in place)
|
|
143
|
+
- **Use Case Example**: Filter, reorder, or transform items
|
|
144
|
+
- **File Reference**: src/utils.js:41
|
|
145
|
+
|
|
146
|
+
##### `${extBase}.postProcess${CapitalizedExtName}`
|
|
147
|
+
|
|
148
|
+
- **Purpose**: Final hook to modify array after all processing
|
|
149
|
+
- **When Invoked**: Called after all other processing is complete
|
|
150
|
+
- **Context Parameters**:
|
|
151
|
+
- `...args`: Variable arguments passed through from the caller
|
|
152
|
+
- **Expected Return**: `void` (modifies array in place)
|
|
153
|
+
- **Use Case Example**: Apply final transformations, add computed items
|
|
154
|
+
- **File Reference**: src/utils.js:42
|
|
155
|
+
|
|
156
|
+
#### MetaMenu Extension Pattern
|
|
157
|
+
|
|
158
|
+
**Base Extension Point**: `${baseExtPoint}.*` (where `baseExtPoint` is provided via props)
|
|
159
|
+
|
|
160
|
+
##### `${baseExtPoint}.getItems`
|
|
161
|
+
|
|
162
|
+
- **Purpose**: Allows plugins to contribute menu items to a MetaMenu component
|
|
163
|
+
- **When Invoked**: Called when MetaMenu renders, if `baseExtPoint` prop is provided
|
|
164
|
+
- **Context Parameters**:
|
|
165
|
+
- `meta`: Object - The menu metadata object containing configuration
|
|
166
|
+
- **Expected Return**: `Array<MetaMenuItem>` - Array of menu item definitions
|
|
167
|
+
- **Use Case Example**: Add custom menu items to application sidebar, header menu, or dropdown menus
|
|
168
|
+
- **File Reference**: src/features/common/MetaMenu.js:23
|
|
169
|
+
|
|
170
|
+
##### `${baseExtPoint}.processItems`
|
|
171
|
+
|
|
172
|
+
- **Purpose**: Hook to modify all menu items after they're collected and normalized
|
|
173
|
+
- **When Invoked**: Called after all items (from meta and extensions) are collected, normalized, and have parent-child relationships resolved
|
|
174
|
+
- **Context Parameters**:
|
|
175
|
+
- `meta`: Object - The menu metadata object
|
|
176
|
+
- `newItems`: Array - The normalized array of menu items
|
|
177
|
+
- `itemByKey`: Object - Map of menu items keyed by their key property
|
|
178
|
+
- **Expected Return**: `void` (modifies items in place)
|
|
179
|
+
- **Use Case Example**: Reorder items, hide items based on permissions, add badges or notifications
|
|
180
|
+
- **File Reference**: src/features/common/MetaMenu.js:57
|
|
181
|
+
|
|
182
|
+
#### DropdownMenu Extension Pattern
|
|
183
|
+
|
|
184
|
+
**Extension Point**: Custom (passed via `extPoint` prop)
|
|
185
|
+
|
|
186
|
+
When a DropdownMenu component is rendered with an `extPoint` prop, it invokes that extension point:
|
|
187
|
+
|
|
188
|
+
##### Custom Extension Point (via `extPoint` prop)
|
|
189
|
+
|
|
190
|
+
- **Purpose**: Allows plugins to modify dropdown menu items dynamically
|
|
191
|
+
- **When Invoked**: Called during DropdownMenu rendering, before items are processed
|
|
192
|
+
- **Context Parameters**:
|
|
193
|
+
- `items`: Array - The menu items array to modify
|
|
194
|
+
- `...extPointParams`: Variable arguments passed via the `extPointParams` prop
|
|
195
|
+
- **Expected Return**: `void` (modifies items array in place)
|
|
196
|
+
- **Use Case Example**: Add context-specific actions to record dropdown menus, filter items based on permissions
|
|
197
|
+
- **File Reference**: src/features/common/DropdownMenu.js:38
|
|
198
|
+
|
|
199
|
+
#### ConfigProvider Extension
|
|
200
|
+
|
|
201
|
+
##### `museLibAntd.configProvider.processProps`
|
|
202
|
+
|
|
203
|
+
- **Purpose**: Allows plugins to modify Ant Design ConfigProvider props (e.g., theme tokens, component defaults)
|
|
204
|
+
- **When Invoked**: Called when ConfigProviderWrapper renders, before passing props to Ant Design's ConfigProvider
|
|
205
|
+
- **Context Parameters**:
|
|
206
|
+
- `configProps`: Object - The ConfigProvider props object with structure `{ theme: { algorithm: ... } }`
|
|
207
|
+
- **Expected Return**: `void` (modifies configProps in place)
|
|
208
|
+
- **Use Case Example**: Customize theme tokens (borderRadius, colors), add locale configuration, set component-level defaults
|
|
209
|
+
- **File Reference**: src/features/common/ConfigProviderWrapper.js:16
|
|
210
|
+
|
|
211
|
+
### Usage Example
|
|
212
|
+
|
|
213
|
+
**CRITICAL**: Extension points are **nested object properties**, NOT string paths!
|
|
214
|
+
|
|
215
|
+
```javascript
|
|
216
|
+
// Example: Extending a form via extendFormMeta
|
|
217
|
+
// ✅ CORRECT - nested object properties
|
|
218
|
+
plugin.register({
|
|
219
|
+
name: 'my-custom-plugin',
|
|
220
|
+
am: {
|
|
221
|
+
createAppForm: {
|
|
222
|
+
getFields: (context) => {
|
|
223
|
+
return [
|
|
224
|
+
{
|
|
225
|
+
key: 'customField',
|
|
226
|
+
label: 'Custom Field',
|
|
227
|
+
widget: 'input',
|
|
228
|
+
order: 100,
|
|
229
|
+
}
|
|
230
|
+
];
|
|
231
|
+
},
|
|
232
|
+
processMeta: (context) => {
|
|
233
|
+
// Modify form metadata after fields are added
|
|
234
|
+
context.meta.fields.forEach(field => {
|
|
235
|
+
if (field.key === 'appName') {
|
|
236
|
+
field.required = true;
|
|
237
|
+
}
|
|
238
|
+
});
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
});
|
|
243
|
+
|
|
244
|
+
// Example: Customizing Ant Design theme
|
|
245
|
+
// ✅ CORRECT - nested object properties
|
|
246
|
+
plugin.register({
|
|
247
|
+
name: 'my-theme-plugin',
|
|
248
|
+
museLibAntd: {
|
|
249
|
+
configProvider: {
|
|
250
|
+
processProps: (configProps) => {
|
|
251
|
+
configProps.theme.token = {
|
|
252
|
+
colorPrimary: '#00b96b',
|
|
253
|
+
borderRadius: 2,
|
|
254
|
+
};
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
});
|
|
259
|
+
|
|
260
|
+
// Example: Adding items to a MetaMenu
|
|
261
|
+
// ✅ CORRECT - nested object properties
|
|
262
|
+
plugin.register({
|
|
263
|
+
name: 'my-menu-plugin',
|
|
264
|
+
museLayout: {
|
|
265
|
+
siderMenu: {
|
|
266
|
+
getItems: (meta) => {
|
|
267
|
+
return [
|
|
268
|
+
{
|
|
269
|
+
key: 'custom-item',
|
|
270
|
+
label: 'Custom Menu Item',
|
|
271
|
+
icon: 'star',
|
|
272
|
+
link: '/custom-page',
|
|
273
|
+
order: 50,
|
|
274
|
+
}
|
|
275
|
+
];
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
});
|
|
280
|
+
```
|
|
281
|
+
|
|
282
|
+
---
|
|
283
|
+
|
|
284
|
+
## 3. Extension Points Contributed
|
|
285
|
+
|
|
286
|
+
This plugin implements the following extension points from OTHER plugins to integrate with the MUSE ecosystem.
|
|
287
|
+
|
|
288
|
+
### Summary
|
|
289
|
+
|
|
290
|
+
- **Total Contributions**: 3
|
|
291
|
+
- **Host Plugins**: @ebay/muse-lib-react
|
|
292
|
+
|
|
293
|
+
### By Host Plugin
|
|
294
|
+
|
|
295
|
+
#### Contributes to: @ebay/muse-lib-react
|
|
296
|
+
|
|
297
|
+
##### `route`
|
|
298
|
+
|
|
299
|
+
- **Invoked By**: @ebay/muse-lib-react routing system
|
|
300
|
+
- **What This Plugin Provides**: Route configuration for `/plugin-muse-antd` path with common feature routes
|
|
301
|
+
- **Why Needed**: Registers the plugin's route structure so it can be accessed via React Router
|
|
302
|
+
- **File Reference**: src/index.js:17, src/common/routeConfig.js:1-16
|
|
303
|
+
|
|
304
|
+
##### `root.getProviders`
|
|
305
|
+
|
|
306
|
+
- **Invoked By**: @ebay/muse-lib-react root component provider chain
|
|
307
|
+
- **What This Plugin Provides**: Ant Design ConfigProviderWrapper with dark mode support
|
|
308
|
+
- **Why Needed**: Wraps the app with Ant Design's ConfigProvider to enable theming, localization, and component configuration. Sets order to 35 to ensure it wraps most other providers.
|
|
309
|
+
- **File Reference**: src/index.js:18-26, src/features/common/ConfigProviderWrapper.js:1-18
|
|
310
|
+
|
|
311
|
+
##### `reducer`
|
|
312
|
+
|
|
313
|
+
- **Invoked By**: @ebay/muse-lib-react Redux store configuration
|
|
314
|
+
- **What This Plugin Provides**: Redux reducer managing common state (currently dark mode preference)
|
|
315
|
+
- **Why Needed**: Manages shared state for dark mode theme switching and persists preference to localStorage
|
|
316
|
+
- **File Reference**: src/index.js:27, src/common/rootReducer.js:1-14
|
|
317
|
+
|
|
318
|
+
---
|
|
319
|
+
|
|
320
|
+
## 4. Exported Functionality
|
|
321
|
+
|
|
322
|
+
This plugin exports the following functionality for use by other plugins.
|
|
323
|
+
|
|
324
|
+
**Access via**: `plugin.getPlugin('@ebay/muse-lib-antd').exports`
|
|
325
|
+
|
|
326
|
+
### Library Modules (Shared Dependencies)
|
|
327
|
+
|
|
328
|
+
As a **lib plugin**, this plugin's primary export is the complete set of Ant Design and icon modules, which are automatically shared with consuming plugins via MUSE's module federation system:
|
|
329
|
+
|
|
330
|
+
#### Default Export Object
|
|
331
|
+
|
|
332
|
+
```javascript
|
|
333
|
+
{
|
|
334
|
+
antd, // Complete Ant Design 5.x library (all components)
|
|
335
|
+
icons, // @ant-design/icons (all Ant Design icons)
|
|
336
|
+
utils, // This plugin's utility functions
|
|
337
|
+
}
|
|
338
|
+
```
|
|
339
|
+
|
|
340
|
+
- **`antd`**: Complete Ant Design 5.19.0 component library
|
|
341
|
+
- **Access**: Other plugins import from 'antd' and it resolves to this shared instance
|
|
342
|
+
- **Why Exported**: Prevents duplicate Ant Design bundles across plugins, ensures version consistency
|
|
343
|
+
- **Components Include**: Button, Table, Form, Modal, Drawer, Menu, Layout, Input, Select, DatePicker, etc. (100+ components)
|
|
344
|
+
|
|
345
|
+
- **`icons`**: Complete @ant-design/icons 5.3.7 icon library
|
|
346
|
+
- **Access**: Other plugins import from '@ant-design/icons' and it resolves to this shared instance
|
|
347
|
+
- **Why Exported**: Prevents duplicate icon bundles, ensures consistent icon versions
|
|
348
|
+
- **Icons Include**: All Ant Design icons (outlined, filled, two-tone)
|
|
349
|
+
|
|
350
|
+
- **`utils`**: Utility functions for extensibility
|
|
351
|
+
- **Access**: Import from '@ebay/muse-lib-antd/src/utils'
|
|
352
|
+
- **Why Exported**: Provides helpers for making forms and arrays extensible via extension points
|
|
353
|
+
|
|
354
|
+
### Components (from src/features/common)
|
|
355
|
+
|
|
356
|
+
The following custom components are exported via standard ES6 exports (not via plugin.exports):
|
|
357
|
+
|
|
358
|
+
#### UI Components
|
|
359
|
+
|
|
360
|
+
- **`MetaMenu`**: Metadata-driven menu component with extension point support
|
|
361
|
+
- **Purpose**: Render Ant Design menus from declarative configuration with plugin extensibility
|
|
362
|
+
- **Props**: `meta` (menu config), `baseExtPoint` (extension point base), `autoSort` (auto-sort items)
|
|
363
|
+
- **Use Cases**: Sidebar menus, header menus, dropdown menus with plugin-contributed items
|
|
364
|
+
- **File Reference**: src/features/common/MetaMenu.js:1-165
|
|
365
|
+
|
|
366
|
+
- **`DropdownMenu`**: Dropdown menu with actions and extension point support
|
|
367
|
+
- **Purpose**: Render dropdown menus with highlighted actions and extension points
|
|
368
|
+
- **Props**: `items`, `triggerNode`, `extPoint`, `extPointParams`, `size`
|
|
369
|
+
- **Use Cases**: Record action menus, context menus
|
|
370
|
+
- **File Reference**: src/features/common/DropdownMenu.js:1-93
|
|
371
|
+
|
|
372
|
+
- **`ErrorBox`**: Error display component with retry functionality
|
|
373
|
+
- **Purpose**: Display errors with stack traces, retry buttons, and customizable messaging
|
|
374
|
+
- **Props**: `title`, `content`, `error`, `onRetry`, `showStack`, `btnSize`
|
|
375
|
+
- **Use Cases**: Error boundaries, API error display, validation errors
|
|
376
|
+
- **File Reference**: src/features/common/ErrorBox.js
|
|
377
|
+
|
|
378
|
+
- **`ErrorBoundary`**: React error boundary component
|
|
379
|
+
- **Purpose**: Catch React rendering errors and display fallback UI
|
|
380
|
+
- **Props**: `message`, `children`
|
|
381
|
+
- **Use Cases**: Wrap components to prevent entire app crashes
|
|
382
|
+
- **File Reference**: src/features/common/ErrorBoundary.js
|
|
383
|
+
|
|
384
|
+
- **`GlobalLoading`**: Full-page or container loading indicator
|
|
385
|
+
- **Purpose**: Display loading spinner overlays
|
|
386
|
+
- **Props**: `full` (boolean for full-page mode)
|
|
387
|
+
- **Use Cases**: Page transitions, async data loading
|
|
388
|
+
- **File Reference**: src/features/common/GlobalLoading.js
|
|
389
|
+
|
|
390
|
+
- **`GlobalErrorBox`**: Modal error display
|
|
391
|
+
- **Purpose**: Display errors in modal dialogs
|
|
392
|
+
- **Props**: `title`, `error`, `onOk`, `okText`, `onClose`
|
|
393
|
+
- **Use Cases**: Critical errors, API failures that need user acknowledgment
|
|
394
|
+
- **File Reference**: src/features/common/GlobalErrorBox.js
|
|
395
|
+
|
|
396
|
+
- **`CodeViewer`**: Syntax-highlighted code display
|
|
397
|
+
- **Purpose**: Display formatted code with syntax highlighting and copy functionality
|
|
398
|
+
- **Props**: `code`, `language`, `theme`, `allowCopy`, `title`
|
|
399
|
+
- **Use Cases**: Display JSON, YAML, JavaScript, or other code snippets
|
|
400
|
+
- **File Reference**: src/features/common/CodeViewer.js
|
|
401
|
+
|
|
402
|
+
- **`BlockView`**: Formatted value display component
|
|
403
|
+
- **Purpose**: Display values in a consistent block format, with email link support
|
|
404
|
+
- **Props**: `value`, `openEmail`
|
|
405
|
+
- **Use Cases**: Display field values in view mode, form field previews
|
|
406
|
+
- **File Reference**: src/features/common/BlockView.js
|
|
407
|
+
|
|
408
|
+
- **`DateView`**: Date/time display component
|
|
409
|
+
- **Purpose**: Format and display dates/times with various format options
|
|
410
|
+
- **Props**: `value`, `dateOnly`, `timeOnly`, `dateFormat`, `timeFormat`
|
|
411
|
+
- **Use Cases**: Display timestamps, dates, or times in consistent format
|
|
412
|
+
- **File Reference**: src/features/common/DateView.js
|
|
413
|
+
|
|
414
|
+
- **`Highlighter`**: Text search highlighting component
|
|
415
|
+
- **Purpose**: Highlight search terms within text
|
|
416
|
+
- **Props**: `search`, `text`
|
|
417
|
+
- **Use Cases**: Search results, filtered lists
|
|
418
|
+
- **File Reference**: src/features/common/Highlighter.js
|
|
419
|
+
|
|
420
|
+
- **`Icon`**: Icon wrapper component
|
|
421
|
+
- **Purpose**: Render Ant Design icons with consistent API
|
|
422
|
+
- **Props**: `type`, `className`, `onClick`, `style`
|
|
423
|
+
- **Use Cases**: Consistent icon rendering across app
|
|
424
|
+
- **File Reference**: src/features/common/Icon.js
|
|
425
|
+
|
|
426
|
+
- **`LoadingMask`**: Inline loading indicator
|
|
427
|
+
- **Purpose**: Display loading state for components
|
|
428
|
+
- **Use Cases**: Inline component loading states
|
|
429
|
+
- **File Reference**: src/features/common/LoadingMask.js
|
|
430
|
+
|
|
431
|
+
- **`PageNotFound`**: 404 error page component
|
|
432
|
+
- **Purpose**: Display "page not found" error page
|
|
433
|
+
- **Use Cases**: React Router fallback route
|
|
434
|
+
- **File Reference**: src/features/common/PageNotFound.js
|
|
435
|
+
|
|
436
|
+
- **`RequestStatus`**: Request state management component
|
|
437
|
+
- **Purpose**: Handle loading, error, and success states for async requests
|
|
438
|
+
- **Props**: `pending`, `loading`, `error`, `errorMode`, `loadingMode`, `dismissError`
|
|
439
|
+
- **Use Cases**: Wrap async components to handle loading/error states
|
|
440
|
+
- **File Reference**: src/features/common/RequestStatus.js
|
|
441
|
+
|
|
442
|
+
- **`StatusLabel`**: Status badge component
|
|
443
|
+
- **Purpose**: Display status with colored labels
|
|
444
|
+
- **Props**: `label`, `type` (SUCCESS, FAILURE, PROCESSING, etc.)
|
|
445
|
+
- **Use Cases**: Display plugin status, request status, app status
|
|
446
|
+
- **File Reference**: src/features/common/StatusLabel.js
|
|
447
|
+
|
|
448
|
+
- **`TableBar`**: Table toolbar with search
|
|
449
|
+
- **Purpose**: Provide search bar and actions for tables
|
|
450
|
+
- **Props**: `onSearch`, `search`, `placeholder`, `children`
|
|
451
|
+
- **Use Cases**: Table filtering, bulk actions
|
|
452
|
+
- **File Reference**: src/features/common/TableBar.js
|
|
453
|
+
|
|
454
|
+
- **`TagInput`**: Tag input widget
|
|
455
|
+
- **Purpose**: Input component for entering multiple tags
|
|
456
|
+
- **Props**: `max`, `value`, `onChange`
|
|
457
|
+
- **Use Cases**: Form fields for arrays of strings (tags, labels, keywords)
|
|
458
|
+
- **File Reference**: src/features/common/TagInput.js
|
|
459
|
+
|
|
460
|
+
- **`ConfigProviderWrapper`**: Ant Design ConfigProvider with dark mode
|
|
461
|
+
- **Purpose**: Wrap app with Ant Design theme provider and dark mode support
|
|
462
|
+
- **Props**: `children`
|
|
463
|
+
- **Use Cases**: Root-level provider for Ant Design theming
|
|
464
|
+
- **File Reference**: src/features/common/ConfigProviderWrapper.js
|
|
465
|
+
|
|
466
|
+
### Utilities (from src/utils.js)
|
|
467
|
+
|
|
468
|
+
- **`extendFormMeta(meta, extBase, ...args)`**: Make Nice Form metadata extensible
|
|
469
|
+
- **Purpose**: Allow plugins to extend form definitions via extension points
|
|
470
|
+
- **Parameters**:
|
|
471
|
+
- `meta`: FormMeta object with `fields` array
|
|
472
|
+
- `extBase`: String - base name for extension points (e.g., 'am.createAppForm')
|
|
473
|
+
- `...args`: Additional arguments passed to extension point handlers
|
|
474
|
+
- **Returns**: `{ watchingFields: Array, meta: FormMeta }`
|
|
475
|
+
- **Extension Points Invoked**:
|
|
476
|
+
- `${extBase}.preProcessMeta`
|
|
477
|
+
- `${extBase}.getFields`
|
|
478
|
+
- `${extBase}.processMeta`
|
|
479
|
+
- `${extBase}.postProcessMeta`
|
|
480
|
+
- `${extBase}.getWatchingFields`
|
|
481
|
+
- **Use Cases**: Create extensible forms in manager UIs where plugins can add custom fields
|
|
482
|
+
- **File Reference**: src/utils.js:11-23
|
|
483
|
+
|
|
484
|
+
- **`extendArray(arr, extName, extBase, ...args)`**: Make arrays extensible
|
|
485
|
+
- **Purpose**: Allow plugins to extend arrays (columns, actions, tabs, etc.) via extension points
|
|
486
|
+
- **Parameters**:
|
|
487
|
+
- `arr`: Array - the array to extend
|
|
488
|
+
- `extName`: String - name of the array type (e.g., 'columns', 'actions')
|
|
489
|
+
- `extBase`: String - base name for extension points (e.g., 'pm.pluginList')
|
|
490
|
+
- `...args`: Additional arguments passed to extension point handlers
|
|
491
|
+
- **Returns**: The modified array
|
|
492
|
+
- **Extension Points Invoked**:
|
|
493
|
+
- `${extBase}.preProcess${CapitalizedExtName}`
|
|
494
|
+
- `${extBase}.get${CapitalizedExtName}`
|
|
495
|
+
- `${extBase}.process${CapitalizedExtName}`
|
|
496
|
+
- `${extBase}.postProcess${CapitalizedExtName}`
|
|
497
|
+
- **Use Cases**: Create extensible table columns, action menus, tabs, etc.
|
|
498
|
+
- **File Reference**: src/utils.js:36-45
|
|
499
|
+
|
|
500
|
+
### Other Resources
|
|
501
|
+
|
|
502
|
+
- **History Object**: Browser history singleton for programmatic navigation
|
|
503
|
+
- **Access**: Import from '@ebay/muse-lib-antd/src/common/history'
|
|
504
|
+
- **Type**: `BrowserHistory` from history v5
|
|
505
|
+
- **Global Access**: Also available at `window.MUSE_ANTD_HISTORY`
|
|
506
|
+
- **Methods**: `push(path)`, `replace(path)`, `go(n)`, `goBack()`, `goForward()`
|
|
507
|
+
- **Use Cases**: Navigate programmatically without React Router hooks, imperative navigation in non-component code
|
|
508
|
+
- **File Reference**: src/common/history.js:1-6
|
|
509
|
+
|
|
510
|
+
- **Table Configuration**: Default Ant Design table props and utilities
|
|
511
|
+
- **Access**: Import from '@ebay/muse-lib-antd/src/features/common/tableConfig'
|
|
512
|
+
- **Exports**: `defaultProps`, `defaultSorter`, `defaultFilter`
|
|
513
|
+
- **Use Cases**: Consistent table configuration across app
|
|
514
|
+
- **File Reference**: src/features/common/tableConfig.js:1-42
|
|
515
|
+
|
|
516
|
+
- **Redux State**: Dark mode state management
|
|
517
|
+
- **Hook**: `useSetIsDarkMode()` - Returns `{ isDarkMode, setIsDarkMode }`
|
|
518
|
+
- **Action**: `setIsDarkMode(isDarkMode)` - Dispatch action to toggle dark mode
|
|
519
|
+
- **Use Cases**: Theme switching, dark mode preferences
|
|
520
|
+
- **File Reference**: src/features/common/redux/setIsDarkMode.js:1-31
|
|
521
|
+
|
|
522
|
+
- **Modals**: Pre-registered Nice Modal React modals
|
|
523
|
+
- **Modal ID**: `'muse-lib-antd.loading-modal'`
|
|
524
|
+
- **Component**: LoadingModal
|
|
525
|
+
- **Use Cases**: Show loading dialogs via Nice Modal React
|
|
526
|
+
- **File Reference**: src/modals.js:1-4
|
|
527
|
+
|
|
528
|
+
- **Nice Form Widgets**: Custom form widgets registered with Nice Form
|
|
529
|
+
- **Widgets**:
|
|
530
|
+
- `'tag'`: TagInput component
|
|
531
|
+
- `'tag-view'`: BlockView component
|
|
532
|
+
- `'date-view'`: DateView (dateOnly)
|
|
533
|
+
- `'time-view'`: DateView (timeOnly)
|
|
534
|
+
- `'datetime-view'`: DateView (full)
|
|
535
|
+
- **Use Cases**: Use in Nice Form field definitions
|
|
536
|
+
- **File Reference**: src/initNiceForm.jsx:1-16
|
|
537
|
+
|
|
538
|
+
### Using Exported Functionality
|
|
539
|
+
|
|
540
|
+
```javascript
|
|
541
|
+
// Accessing shared Ant Design components (automatic via module federation)
|
|
542
|
+
import { Button, Table, Form } from 'antd';
|
|
543
|
+
import { UserOutlined, SearchOutlined } from '@ant-design/icons';
|
|
544
|
+
|
|
545
|
+
// Using custom components
|
|
546
|
+
import {
|
|
547
|
+
MetaMenu,
|
|
548
|
+
DropdownMenu,
|
|
549
|
+
ErrorBox,
|
|
550
|
+
CodeViewer,
|
|
551
|
+
DateView
|
|
552
|
+
} from '@ebay/muse-lib-antd/src/features/common';
|
|
553
|
+
|
|
554
|
+
// Using utilities
|
|
555
|
+
import { extendFormMeta, extendArray } from '@ebay/muse-lib-antd/src/utils';
|
|
556
|
+
|
|
557
|
+
// Example: Make a form extensible
|
|
558
|
+
const meta = {
|
|
559
|
+
fields: [
|
|
560
|
+
{ key: 'name', label: 'Name', widget: 'input' }
|
|
561
|
+
]
|
|
562
|
+
};
|
|
563
|
+
|
|
564
|
+
const { watchingFields, meta: extendedMeta } = extendFormMeta(
|
|
565
|
+
meta,
|
|
566
|
+
'myPlugin.myForm',
|
|
567
|
+
{ context: 'additional data' }
|
|
568
|
+
);
|
|
569
|
+
|
|
570
|
+
// Example: Make a table columns array extensible
|
|
571
|
+
const columns = [
|
|
572
|
+
{ key: 'name', title: 'Name', dataIndex: 'name' }
|
|
573
|
+
];
|
|
574
|
+
|
|
575
|
+
extendArray(columns, 'columns', 'myPlugin.myTable', tableData);
|
|
576
|
+
|
|
577
|
+
// Example: Using dark mode
|
|
578
|
+
import { useSetIsDarkMode } from '@ebay/muse-lib-antd/src/features/common/redux/hooks';
|
|
579
|
+
|
|
580
|
+
function MyComponent() {
|
|
581
|
+
const { isDarkMode, setIsDarkMode } = useSetIsDarkMode();
|
|
582
|
+
|
|
583
|
+
return (
|
|
584
|
+
<button onClick={() => setIsDarkMode(!isDarkMode)}>
|
|
585
|
+
Toggle Theme (current: {isDarkMode ? 'dark' : 'light'})
|
|
586
|
+
</button>
|
|
587
|
+
);
|
|
588
|
+
}
|
|
589
|
+
|
|
590
|
+
// Example: Using MetaMenu
|
|
591
|
+
const menuMeta = {
|
|
592
|
+
items: [
|
|
593
|
+
{ key: 'home', label: 'Home', link: '/', icon: 'home' },
|
|
594
|
+
{ key: 'settings', label: 'Settings', link: '/settings', icon: 'setting' }
|
|
595
|
+
],
|
|
596
|
+
autoActive: true,
|
|
597
|
+
mode: 'inline'
|
|
598
|
+
};
|
|
599
|
+
|
|
600
|
+
<MetaMenu
|
|
601
|
+
meta={menuMeta}
|
|
602
|
+
baseExtPoint="myPlugin.siderMenu"
|
|
603
|
+
autoSort={true}
|
|
604
|
+
/>
|
|
605
|
+
|
|
606
|
+
// Example: Using history for programmatic navigation
|
|
607
|
+
import history from '@ebay/muse-lib-antd/src/common/history';
|
|
608
|
+
|
|
609
|
+
// Navigate to a different route
|
|
610
|
+
function handleCreateSuccess(newId) {
|
|
611
|
+
history.push(`/items/${newId}`);
|
|
612
|
+
}
|
|
613
|
+
|
|
614
|
+
// Or access via global
|
|
615
|
+
window.MUSE_ANTD_HISTORY.push('/dashboard');
|
|
616
|
+
```
|
|
617
|
+
|
|
618
|
+
**Note**: As a lib plugin, the primary value is providing shared Ant Design modules. The custom components and utilities are secondary exports that build on top of the shared foundation.
|
|
619
|
+
|
|
620
|
+
---
|
|
621
|
+
|
|
622
|
+
## 5. Integration Examples
|
|
623
|
+
|
|
624
|
+
**CRITICAL**: Extension points are **nested object properties**, NOT string paths!
|
|
625
|
+
|
|
626
|
+
### ✅ CORRECT Syntax
|
|
627
|
+
```javascript
|
|
628
|
+
plugin.register({
|
|
629
|
+
name: 'my-plugin',
|
|
630
|
+
pluginName: {
|
|
631
|
+
extensionPoint: (context) => {
|
|
632
|
+
// Your implementation
|
|
633
|
+
}
|
|
634
|
+
}
|
|
635
|
+
});
|
|
636
|
+
```
|
|
637
|
+
|
|
638
|
+
### ❌ INCORRECT Syntax
|
|
639
|
+
```javascript
|
|
640
|
+
plugin.register({
|
|
641
|
+
name: 'my-plugin',
|
|
642
|
+
'pluginName.extensionPoint': (context) => { // WRONG!
|
|
643
|
+
// This will NOT work!
|
|
644
|
+
}
|
|
645
|
+
});
|
|
646
|
+
```
|
|
647
|
+
|
|
648
|
+
---
|
|
649
|
+
|
|
650
|
+
### Example 1: Using Shared Ant Design Components
|
|
651
|
+
|
|
652
|
+
Since `@ebay/muse-lib-antd` is a lib plugin, consuming plugins automatically use its shared Ant Design instance:
|
|
653
|
+
|
|
654
|
+
```javascript
|
|
655
|
+
// In your plugin - automatically uses shared antd from muse-lib-antd
|
|
656
|
+
import React from 'react';
|
|
657
|
+
import { Button, Table, Form, Modal } from 'antd';
|
|
658
|
+
import { UserOutlined, PlusOutlined } from '@ant-design/icons';
|
|
659
|
+
|
|
660
|
+
export default function MyComponent() {
|
|
661
|
+
return (
|
|
662
|
+
<div>
|
|
663
|
+
<Button type="primary" icon={<PlusOutlined />}>
|
|
664
|
+
Create User
|
|
665
|
+
</Button>
|
|
666
|
+
<Table
|
|
667
|
+
dataSource={data}
|
|
668
|
+
columns={columns}
|
|
669
|
+
/>
|
|
670
|
+
</div>
|
|
671
|
+
);
|
|
672
|
+
}
|
|
673
|
+
```
|
|
674
|
+
|
|
675
|
+
### Example 2: Extending Forms with Custom Fields
|
|
676
|
+
|
|
677
|
+
```javascript
|
|
678
|
+
import plugin from 'js-plugin';
|
|
679
|
+
|
|
680
|
+
// ✅ CORRECT - nested object properties
|
|
681
|
+
plugin.register({
|
|
682
|
+
name: 'my-custom-plugin',
|
|
683
|
+
|
|
684
|
+
// Add fields to the create app form
|
|
685
|
+
am: {
|
|
686
|
+
createAppForm: {
|
|
687
|
+
getFields: (context) => {
|
|
688
|
+
return [
|
|
689
|
+
{
|
|
690
|
+
key: 'githubRepo',
|
|
691
|
+
label: 'GitHub Repository',
|
|
692
|
+
widget: 'input',
|
|
693
|
+
placeholder: 'org/repo',
|
|
694
|
+
order: 100,
|
|
695
|
+
required: true,
|
|
696
|
+
},
|
|
697
|
+
{
|
|
698
|
+
key: 'slackChannel',
|
|
699
|
+
label: 'Slack Channel',
|
|
700
|
+
widget: 'input',
|
|
701
|
+
placeholder: '#channel-name',
|
|
702
|
+
order: 101,
|
|
703
|
+
}
|
|
704
|
+
];
|
|
705
|
+
},
|
|
706
|
+
|
|
707
|
+
// Modify form after all fields are added
|
|
708
|
+
processMeta: (context) => {
|
|
709
|
+
const { meta } = context;
|
|
710
|
+
|
|
711
|
+
// Make appName field required
|
|
712
|
+
const appNameField = meta.fields.find(f => f.key === 'appName');
|
|
713
|
+
if (appNameField) {
|
|
714
|
+
appNameField.required = true;
|
|
715
|
+
appNameField.rules = [
|
|
716
|
+
{ required: true, message: 'App name is required' },
|
|
717
|
+
{ pattern: /^[a-z][a-z0-9-]*$/, message: 'Must start with letter, use lowercase and hyphens only' }
|
|
718
|
+
];
|
|
719
|
+
}
|
|
720
|
+
}
|
|
721
|
+
}
|
|
722
|
+
}
|
|
723
|
+
});
|
|
724
|
+
```
|
|
725
|
+
|
|
726
|
+
### Example 3: Customizing Ant Design Theme
|
|
727
|
+
|
|
728
|
+
```javascript
|
|
729
|
+
import plugin from 'js-plugin';
|
|
730
|
+
|
|
731
|
+
// ✅ CORRECT - nested object properties
|
|
732
|
+
plugin.register({
|
|
733
|
+
name: 'my-theme-plugin',
|
|
734
|
+
|
|
735
|
+
museLibAntd: {
|
|
736
|
+
configProvider: {
|
|
737
|
+
processProps: (configProps) => {
|
|
738
|
+
// Customize theme tokens
|
|
739
|
+
configProps.theme.token = {
|
|
740
|
+
colorPrimary: '#1890ff', // Primary color
|
|
741
|
+
colorSuccess: '#52c41a', // Success color
|
|
742
|
+
colorWarning: '#faad14', // Warning color
|
|
743
|
+
colorError: '#f5222d', // Error color
|
|
744
|
+
borderRadius: 4, // Border radius for components
|
|
745
|
+
fontSize: 14, // Base font size
|
|
746
|
+
fontFamily: '-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial',
|
|
747
|
+
};
|
|
748
|
+
|
|
749
|
+
// Add component-level configurations
|
|
750
|
+
configProps.button = {
|
|
751
|
+
defaultProps: {
|
|
752
|
+
size: 'middle'
|
|
753
|
+
}
|
|
754
|
+
};
|
|
755
|
+
|
|
756
|
+
// Add locale if needed
|
|
757
|
+
// configProps.locale = enUS;
|
|
758
|
+
}
|
|
759
|
+
}
|
|
760
|
+
}
|
|
761
|
+
});
|
|
762
|
+
```
|
|
763
|
+
|
|
764
|
+
### Example 4: Creating Extensible UI with MetaMenu
|
|
765
|
+
|
|
766
|
+
```javascript
|
|
767
|
+
import React from 'react';
|
|
768
|
+
import { MetaMenu } from '@ebay/muse-lib-antd/src/features/common';
|
|
769
|
+
import plugin from 'js-plugin';
|
|
770
|
+
|
|
771
|
+
// Define base menu
|
|
772
|
+
function MySidebar() {
|
|
773
|
+
const menuMeta = {
|
|
774
|
+
items: [
|
|
775
|
+
{
|
|
776
|
+
key: 'dashboard',
|
|
777
|
+
label: 'Dashboard',
|
|
778
|
+
link: '/dashboard',
|
|
779
|
+
icon: 'dashboard',
|
|
780
|
+
order: 0
|
|
781
|
+
},
|
|
782
|
+
{
|
|
783
|
+
key: 'users',
|
|
784
|
+
label: 'Users',
|
|
785
|
+
link: '/users',
|
|
786
|
+
icon: 'user',
|
|
787
|
+
order: 10
|
|
788
|
+
},
|
|
789
|
+
],
|
|
790
|
+
mode: 'inline',
|
|
791
|
+
autoActive: true,
|
|
792
|
+
};
|
|
793
|
+
|
|
794
|
+
return (
|
|
795
|
+
<MetaMenu
|
|
796
|
+
meta={menuMeta}
|
|
797
|
+
baseExtPoint="myApp.siderMenu"
|
|
798
|
+
autoSort={true}
|
|
799
|
+
/>
|
|
800
|
+
);
|
|
801
|
+
}
|
|
802
|
+
|
|
803
|
+
// Other plugins can extend the menu
|
|
804
|
+
// ✅ CORRECT - nested object properties
|
|
805
|
+
plugin.register({
|
|
806
|
+
name: 'my-extension-plugin',
|
|
807
|
+
|
|
808
|
+
myApp: {
|
|
809
|
+
siderMenu: {
|
|
810
|
+
getItems: (meta) => {
|
|
811
|
+
return [
|
|
812
|
+
{
|
|
813
|
+
key: 'custom-feature',
|
|
814
|
+
label: 'Custom Feature',
|
|
815
|
+
link: '/custom',
|
|
816
|
+
icon: 'star',
|
|
817
|
+
order: 20,
|
|
818
|
+
}
|
|
819
|
+
];
|
|
820
|
+
},
|
|
821
|
+
|
|
822
|
+
processItems: (meta, items, itemByKey) => {
|
|
823
|
+
// Hide users menu if user doesn't have permission
|
|
824
|
+
const usersItem = itemByKey['users'];
|
|
825
|
+
if (usersItem && !userHasPermission('view_users')) {
|
|
826
|
+
items.splice(items.indexOf(usersItem), 1);
|
|
827
|
+
}
|
|
828
|
+
}
|
|
829
|
+
}
|
|
830
|
+
}
|
|
831
|
+
});
|
|
832
|
+
```
|
|
833
|
+
|
|
834
|
+
### Example 5: Using Extensibility Utilities
|
|
835
|
+
|
|
836
|
+
```javascript
|
|
837
|
+
import React from 'react';
|
|
838
|
+
import { extendFormMeta, extendArray } from '@ebay/muse-lib-antd/src/utils';
|
|
839
|
+
import NiceForm from '@ebay/nice-form-react';
|
|
840
|
+
|
|
841
|
+
function MyForm({ record }) {
|
|
842
|
+
// Create extensible form
|
|
843
|
+
const baseMeta = {
|
|
844
|
+
fields: [
|
|
845
|
+
{ key: 'name', label: 'Name', widget: 'input', required: true },
|
|
846
|
+
{ key: 'email', label: 'Email', widget: 'input', required: true },
|
|
847
|
+
]
|
|
848
|
+
};
|
|
849
|
+
|
|
850
|
+
const { meta, watchingFields } = extendFormMeta(
|
|
851
|
+
baseMeta,
|
|
852
|
+
'myPlugin.userForm',
|
|
853
|
+
{ record, mode: 'create' }
|
|
854
|
+
);
|
|
855
|
+
|
|
856
|
+
return <NiceForm meta={meta} />;
|
|
857
|
+
}
|
|
858
|
+
|
|
859
|
+
// Create extensible table columns
|
|
860
|
+
function MyTable({ dataSource }) {
|
|
861
|
+
const columns = [
|
|
862
|
+
{ key: 'name', title: 'Name', dataIndex: 'name', sorter: true },
|
|
863
|
+
{ key: 'email', title: 'Email', dataIndex: 'email' },
|
|
864
|
+
];
|
|
865
|
+
|
|
866
|
+
// Allow plugins to add columns
|
|
867
|
+
extendArray(columns, 'columns', 'myPlugin.userTable', { dataSource });
|
|
868
|
+
|
|
869
|
+
return <Table dataSource={dataSource} columns={columns} />;
|
|
870
|
+
}
|
|
871
|
+
|
|
872
|
+
// Other plugins can extend these
|
|
873
|
+
// ✅ CORRECT - nested object properties
|
|
874
|
+
plugin.register({
|
|
875
|
+
name: 'my-extension',
|
|
876
|
+
|
|
877
|
+
myPlugin: {
|
|
878
|
+
userForm: {
|
|
879
|
+
getFields: ({ record, mode }) => {
|
|
880
|
+
if (mode === 'create') {
|
|
881
|
+
return [
|
|
882
|
+
{
|
|
883
|
+
key: 'role',
|
|
884
|
+
label: 'Role',
|
|
885
|
+
widget: 'select',
|
|
886
|
+
options: ['admin', 'user'],
|
|
887
|
+
order: 50
|
|
888
|
+
}
|
|
889
|
+
];
|
|
890
|
+
}
|
|
891
|
+
return [];
|
|
892
|
+
}
|
|
893
|
+
},
|
|
894
|
+
|
|
895
|
+
userTable: {
|
|
896
|
+
getColumns: ({ dataSource }) => {
|
|
897
|
+
return [
|
|
898
|
+
{
|
|
899
|
+
key: 'role',
|
|
900
|
+
title: 'Role',
|
|
901
|
+
dataIndex: 'role',
|
|
902
|
+
filters: [
|
|
903
|
+
{ text: 'Admin', value: 'admin' },
|
|
904
|
+
{ text: 'User', value: 'user' }
|
|
905
|
+
],
|
|
906
|
+
onFilter: (value, record) => record.role === value,
|
|
907
|
+
order: 50
|
|
908
|
+
}
|
|
909
|
+
];
|
|
910
|
+
}
|
|
911
|
+
}
|
|
912
|
+
}
|
|
913
|
+
});
|
|
914
|
+
```
|
|
915
|
+
|
|
916
|
+
### Example 6: Using Custom Components
|
|
917
|
+
|
|
918
|
+
```javascript
|
|
919
|
+
import React from 'react';
|
|
920
|
+
import {
|
|
921
|
+
ErrorBox,
|
|
922
|
+
CodeViewer,
|
|
923
|
+
DateView,
|
|
924
|
+
Highlighter,
|
|
925
|
+
StatusLabel,
|
|
926
|
+
DropdownMenu
|
|
927
|
+
} from '@ebay/muse-lib-antd/src/features/common';
|
|
928
|
+
|
|
929
|
+
function MyComponent({ data, error, searchTerm }) {
|
|
930
|
+
if (error) {
|
|
931
|
+
return (
|
|
932
|
+
<ErrorBox
|
|
933
|
+
title="Failed to Load Data"
|
|
934
|
+
error={error}
|
|
935
|
+
onRetry={handleRetry}
|
|
936
|
+
showStack={true}
|
|
937
|
+
/>
|
|
938
|
+
);
|
|
939
|
+
}
|
|
940
|
+
|
|
941
|
+
return (
|
|
942
|
+
<div>
|
|
943
|
+
{/* Display formatted code */}
|
|
944
|
+
<CodeViewer
|
|
945
|
+
code={JSON.stringify(data, null, 2)}
|
|
946
|
+
language="json"
|
|
947
|
+
theme="dark"
|
|
948
|
+
allowCopy={true}
|
|
949
|
+
/>
|
|
950
|
+
|
|
951
|
+
{/* Display dates */}
|
|
952
|
+
<DateView value={data.createdAt} dateOnly />
|
|
953
|
+
|
|
954
|
+
{/* Highlight search terms */}
|
|
955
|
+
<Highlighter text={data.description} search={searchTerm} />
|
|
956
|
+
|
|
957
|
+
{/* Display status */}
|
|
958
|
+
<StatusLabel label={data.status} type="SUCCESS" />
|
|
959
|
+
|
|
960
|
+
{/* Dropdown menu with actions */}
|
|
961
|
+
<DropdownMenu
|
|
962
|
+
items={[
|
|
963
|
+
{ key: 'edit', label: 'Edit', icon: 'edit', onClick: handleEdit },
|
|
964
|
+
{ key: 'delete', label: 'Delete', icon: 'delete', onClick: handleDelete }
|
|
965
|
+
]}
|
|
966
|
+
size="small"
|
|
967
|
+
/>
|
|
968
|
+
</div>
|
|
969
|
+
);
|
|
970
|
+
}
|
|
971
|
+
```
|