dp-widgets-framework 1.5.4 → 1.5.6
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/README.md +477 -477
- package/dist/index.esm.js +145 -13
- package/dist/index.js +145 -13
- package/package.json +138 -138
package/README.md
CHANGED
|
@@ -1,478 +1,478 @@
|
|
|
1
|
-
# Widget Framework Components Documentation
|
|
2
|
-
|
|
3
|
-
## Table of Contents
|
|
4
|
-
1. [WidgetPalette](#widgetpalette)
|
|
5
|
-
2. [WidgetSettingsPanel](#widgetsettingspanel)
|
|
6
|
-
3. [WidgetDashboard](#widgetdashboard)
|
|
7
|
-
4. [Widget (Type Interface)](#widget-type-interface)
|
|
8
|
-
5. [SavedPages](#savedpages)
|
|
9
|
-
6. [DashboardPages](#dashboardpages)
|
|
10
|
-
|
|
11
|
-
---
|
|
12
|
-
|
|
13
|
-
## WidgetPalette
|
|
14
|
-
|
|
15
|
-
A draggable widget palette component that displays available widget types and allows users to drag them onto the dashboard.
|
|
16
|
-
|
|
17
|
-
### Props
|
|
18
|
-
|
|
19
|
-
| Prop | Type | Required | Default | Description |
|
|
20
|
-
|------|------|----------|---------|-------------|
|
|
21
|
-
| `widgetBackendUrl` | `string` | No | `undefined` | Base URL for the backend API. If not provided, uses relative URLs |
|
|
22
|
-
|
|
23
|
-
### Features
|
|
24
|
-
|
|
25
|
-
- **Search Functionality**: Built-in search to filter widgets by name or description
|
|
26
|
-
- **Drag & Drop**: Widgets can be dragged from the palette to the dashboard
|
|
27
|
-
- **Dynamic Loading**: Fetches available widget types from the backend API
|
|
28
|
-
- **Icon Mapping**: Displays appropriate icons for each widget type
|
|
29
|
-
|
|
30
|
-
### Usage Example
|
|
31
|
-
|
|
32
|
-
npm install di-widgets-framework
|
|
33
|
-
|
|
34
|
-
```jsx
|
|
35
|
-
import { WidgetPalette } from 'di-widgets-framework';
|
|
36
|
-
|
|
37
|
-
function App() {
|
|
38
|
-
return (
|
|
39
|
-
<WidgetPalette
|
|
40
|
-
widgetBackendUrl="http://localhost:3001"
|
|
41
|
-
/>
|
|
42
|
-
);
|
|
43
|
-
}
|
|
44
|
-
```
|
|
45
|
-
|
|
46
|
-
### Widget Types Supported
|
|
47
|
-
|
|
48
|
-
- **search**: Search input widget (12x2 grid)
|
|
49
|
-
- **filter**: Filter/facet widget (3x8 grid)
|
|
50
|
-
- **results**: Results display widget (9x8 grid)
|
|
51
|
-
- **analytics**: Analytics/charts widget (6x4 grid)
|
|
52
|
-
- **header**: Header section widget (12x2 grid)
|
|
53
|
-
- **footer**: Footer section widget (12x2 grid)
|
|
54
|
-
- **text**: Text content widget (6x2 grid)
|
|
55
|
-
- **agent**: AI agent interaction widget (6x4 grid)
|
|
56
|
-
|
|
57
|
-
---
|
|
58
|
-
|
|
59
|
-
## WidgetSettingsPanel
|
|
60
|
-
|
|
61
|
-
A comprehensive settings panel for configuring widget properties including styling, behavior, and type-specific options.
|
|
62
|
-
|
|
63
|
-
### Props
|
|
64
|
-
|
|
65
|
-
| Prop | Type | Required | Default | Description |
|
|
66
|
-
|------|------|----------|---------|-------------|
|
|
67
|
-
| `pageId` | `string` | Yes | - | The ID of the page containing the widget |
|
|
68
|
-
| `widget` | `Widget` | Yes | - | The widget object to configure |
|
|
69
|
-
| `onClose` | `() => void` | Yes | - | Callback function when the panel is closed |
|
|
70
|
-
| `onWidgetUpdate` | `() => void` | No | `undefined` | Callback function when widget is updated |
|
|
71
|
-
| `widgetBackendUrl` | `string` | No | `undefined` | Base URL for the backend API |
|
|
72
|
-
| `agentIds` | `string[]` | No | `undefined` | Array of available agent IDs for dropdown selection |
|
|
73
|
-
|
|
74
|
-
### Features
|
|
75
|
-
|
|
76
|
-
#### Common Settings (All Widgets)
|
|
77
|
-
- **Title**: Widget display title
|
|
78
|
-
- **Show Header**: Toggle widget header visibility
|
|
79
|
-
- **Resizable**: Enable/disable widget resizing
|
|
80
|
-
- **Draggable**: Enable/disable widget dragging
|
|
81
|
-
- **Styling Options**:
|
|
82
|
-
- Background color (color picker + text input)
|
|
83
|
-
- Border radius (none, rounded, large, extra-large)
|
|
84
|
-
- Padding (small, medium, large, extra-large)
|
|
85
|
-
- Text color (color picker + text input)
|
|
86
|
-
- Font size (custom CSS values)
|
|
87
|
-
- Text alignment (left, center, right)
|
|
88
|
-
|
|
89
|
-
#### Search Widget Settings
|
|
90
|
-
- **Placeholder Text**: Search input placeholder
|
|
91
|
-
- **Minimum Characters**: Required characters before search (1-10)
|
|
92
|
-
- **Search Delay**: Debounce delay in milliseconds (0-1000)
|
|
93
|
-
- **Auto Focus**: Automatically focus the search input
|
|
94
|
-
- **Voice Search**: Enable voice search functionality
|
|
95
|
-
- **Recent Searches**: Show recent search history
|
|
96
|
-
- **Maximum Recent Searches**: Number of recent searches to store
|
|
97
|
-
- **Facets Configuration**: Enable and configure search facets
|
|
98
|
-
|
|
99
|
-
#### Results Widget Settings
|
|
100
|
-
- **Layout Type**: Grid, list, or table display
|
|
101
|
-
- **Items Per Page**: 5, 10, 20, 50, or 100 items
|
|
102
|
-
- **Infinite Scroll**: Enable infinite scrolling
|
|
103
|
-
- **Show Pagination**: Display pagination controls
|
|
104
|
-
- **Hide Relevance**: Hide relevance scores
|
|
105
|
-
- **Title Template**: Field to use for result titles
|
|
106
|
-
- **Metadata Fields**: Configure displayed metadata
|
|
107
|
-
|
|
108
|
-
#### Filter Widget Settings
|
|
109
|
-
- **Show Clear Button**: Display clear all filters button
|
|
110
|
-
- **Collapsible Sections**: Make filter sections collapsible
|
|
111
|
-
- **Default Expanded**: Default expansion state for sections
|
|
112
|
-
- **Facets Configuration**: Configure filter facets
|
|
113
|
-
|
|
114
|
-
#### Agent Widget Settings
|
|
115
|
-
- **Agent Type**: Chatbot Agent, Bar Chart Agent, or Pie Chart Agent
|
|
116
|
-
- **Agent ID**: Unique identifier for the agent (dropdown if agentIds prop provided, otherwise text input)
|
|
117
|
-
- **Query**: Custom query for non-chatbot agents
|
|
118
|
-
|
|
119
|
-
#### Code Settings (Search Widget)
|
|
120
|
-
- **Custom Widget Code**: JavaScript code editor for custom functionality
|
|
121
|
-
|
|
122
|
-
### Usage Example
|
|
123
|
-
|
|
124
|
-
```jsx
|
|
125
|
-
import { WidgetSettingsPanel } from 'di-widgets-framework';
|
|
126
|
-
|
|
127
|
-
function MyComponent() {
|
|
128
|
-
const [selectedWidget, setSelectedWidget] = useState(null);
|
|
129
|
-
const agentIds = ['agent-1', 'agent-2', 'chatbot-agent']; // Optional: provide agent IDs
|
|
130
|
-
|
|
131
|
-
return (
|
|
132
|
-
<WidgetSettingsPanel
|
|
133
|
-
pageId="page-123"
|
|
134
|
-
widget={selectedWidget}
|
|
135
|
-
onClose={() => setSelectedWidget(null)}
|
|
136
|
-
onWidgetUpdate={handleWidgetUpdate}
|
|
137
|
-
widgetBackendUrl="http://localhost:3001"
|
|
138
|
-
agentIds={agentIds}
|
|
139
|
-
/>
|
|
140
|
-
);
|
|
141
|
-
}
|
|
142
|
-
```
|
|
143
|
-
|
|
144
|
-
---
|
|
145
|
-
|
|
146
|
-
## WidgetDashboard
|
|
147
|
-
|
|
148
|
-
The main dashboard component that provides a drag-and-drop grid layout for widgets with editing capabilities.
|
|
149
|
-
|
|
150
|
-
### Props
|
|
151
|
-
|
|
152
|
-
| Prop | Type | Required | Default | Description |
|
|
153
|
-
|------|------|----------|---------|-------------|
|
|
154
|
-
| `pageId` | `string` | Yes | - | The ID of the page to display |
|
|
155
|
-
| `isEditing` | `boolean` | Yes | - | Whether the dashboard is in edit mode |
|
|
156
|
-
| `selectedWidget` | `Widget \| null` | No | `null` | Currently selected widget |
|
|
157
|
-
| `onWidgetSelect` | `(widget: Widget \| null) => void` | No | `undefined` | Callback when a widget is selected |
|
|
158
|
-
| `refreshKey` | `number` | No | `undefined` | Key to trigger data refresh |
|
|
159
|
-
| `widgetBackendUrl` | `string` | No | `undefined` | Base URL for the backend API |
|
|
160
|
-
|
|
161
|
-
### Features
|
|
162
|
-
|
|
163
|
-
- **Grid Layout**: 12-column responsive grid system using react-grid-layout
|
|
164
|
-
- **Drag & Drop**: Accept widgets from the palette and arrange existing widgets
|
|
165
|
-
- **Editing Mode**: Toggle between view and edit modes
|
|
166
|
-
- **Widget Selection**: Click to select widgets for configuration
|
|
167
|
-
- **Auto-save**: Automatically saves layout changes with debouncing (2-second delay)
|
|
168
|
-
- **Widget Management**: Add, remove, and configure widgets
|
|
169
|
-
- **Responsive**: Adjusts to container width
|
|
170
|
-
- **Collision Prevention**: Prevents widgets from overlapping
|
|
171
|
-
|
|
172
|
-
### Layout Configuration
|
|
173
|
-
|
|
174
|
-
- **Columns**: 12-column grid
|
|
175
|
-
- **Row Height**: 50px per row
|
|
176
|
-
- **Margins**: 8px between widgets
|
|
177
|
-
- **Minimum Size**: 3 columns wide, 2 rows high
|
|
178
|
-
|
|
179
|
-
### Required CSS Imports
|
|
180
|
-
|
|
181
|
-
To use the WidgetDashboard component, you must import the following CSS files:
|
|
182
|
-
|
|
183
|
-
```css
|
|
184
|
-
import "@copilotkit/react-ui/styles.css";
|
|
185
|
-
import "react-grid-layout/css/styles.css";
|
|
186
|
-
import "react-resizable/css/styles.css";
|
|
187
|
-
```
|
|
188
|
-
|
|
189
|
-
### Usage Example
|
|
190
|
-
|
|
191
|
-
```jsx
|
|
192
|
-
import { WidgetDashboard } from 'di-widgets-framework';
|
|
193
|
-
import "@copilotkit/react-ui/styles.css";
|
|
194
|
-
import "react-grid-layout/css/styles.css";
|
|
195
|
-
import "react-resizable/css/styles.css";
|
|
196
|
-
|
|
197
|
-
function Dashboard() {
|
|
198
|
-
const [isEditing, setIsEditing] = useState(false);
|
|
199
|
-
const [selectedWidget, setSelectedWidget] = useState(null);
|
|
200
|
-
|
|
201
|
-
return (
|
|
202
|
-
<WidgetDashboard
|
|
203
|
-
pageId="page-123"
|
|
204
|
-
isEditing={isEditing}
|
|
205
|
-
selectedWidget={selectedWidget}
|
|
206
|
-
onWidgetSelect={setSelectedWidget}
|
|
207
|
-
widgetBackendUrl="http://localhost:3001"
|
|
208
|
-
/>
|
|
209
|
-
);
|
|
210
|
-
}
|
|
211
|
-
```
|
|
212
|
-
|
|
213
|
-
---
|
|
214
|
-
|
|
215
|
-
## Widget (Type Interface)
|
|
216
|
-
|
|
217
|
-
The core widget data structure used throughout the framework.
|
|
218
|
-
|
|
219
|
-
### Interface Definition
|
|
220
|
-
|
|
221
|
-
```typescript
|
|
222
|
-
interface Widget {
|
|
223
|
-
id: string; // Unique widget identifier
|
|
224
|
-
page_id: string; // ID of the containing page
|
|
225
|
-
type: string; // Widget type (search, filter, results, etc.)
|
|
226
|
-
title: string; // Display title
|
|
227
|
-
position_x: number; // Grid X position (0-11)
|
|
228
|
-
position_y: number; // Grid Y position
|
|
229
|
-
width: number; // Grid width (1-12)
|
|
230
|
-
height: number; // Grid height in rows
|
|
231
|
-
config: any; // Widget-specific configuration
|
|
232
|
-
category_id?: string; // Optional category identifier
|
|
233
|
-
is_resizable: boolean; // Whether widget can be resized
|
|
234
|
-
is_draggable: boolean; // Whether widget can be dragged
|
|
235
|
-
}
|
|
236
|
-
```
|
|
237
|
-
|
|
238
|
-
### Widget Configuration Examples
|
|
239
|
-
|
|
240
|
-
#### Search Widget Config
|
|
241
|
-
```typescript
|
|
242
|
-
{
|
|
243
|
-
placeholder: "Search...",
|
|
244
|
-
minCharacters: 3,
|
|
245
|
-
searchDelay: 300,
|
|
246
|
-
autoFocus: true,
|
|
247
|
-
voiceSearch: false,
|
|
248
|
-
recentSearches: true,
|
|
249
|
-
maxRecentSearches: 5,
|
|
250
|
-
facets: {
|
|
251
|
-
enabled: true,
|
|
252
|
-
fields: [
|
|
253
|
-
{ field: "category", displayName: "Category", order: 1, enabled: true }
|
|
254
|
-
]
|
|
255
|
-
}
|
|
256
|
-
}
|
|
257
|
-
```
|
|
258
|
-
|
|
259
|
-
#### Results Widget Config
|
|
260
|
-
```typescript
|
|
261
|
-
{
|
|
262
|
-
layout: {
|
|
263
|
-
type: "grid",
|
|
264
|
-
itemsPerPage: 10,
|
|
265
|
-
infiniteScroll: false
|
|
266
|
-
},
|
|
267
|
-
showPagination: true,
|
|
268
|
-
hideRelevance: false,
|
|
269
|
-
titleTemplate: "filename",
|
|
270
|
-
metadata: {
|
|
271
|
-
fields: ["author", "date", "category"]
|
|
272
|
-
}
|
|
273
|
-
}
|
|
274
|
-
```
|
|
275
|
-
|
|
276
|
-
#### Styling Config
|
|
277
|
-
```typescript
|
|
278
|
-
{
|
|
279
|
-
styles: {
|
|
280
|
-
backgroundColor: "#ffffff",
|
|
281
|
-
textColor: "#000000",
|
|
282
|
-
fontSize: "14px",
|
|
283
|
-
padding: "medium",
|
|
284
|
-
borderRadius: "rounded",
|
|
285
|
-
alignment: "left"
|
|
286
|
-
},
|
|
287
|
-
showHeader: true
|
|
288
|
-
}
|
|
289
|
-
```
|
|
290
|
-
|
|
291
|
-
---
|
|
292
|
-
|
|
293
|
-
## SavedPages
|
|
294
|
-
|
|
295
|
-
A page management component for listing, creating, and managing saved widget pages.
|
|
296
|
-
|
|
297
|
-
### Props
|
|
298
|
-
|
|
299
|
-
| Prop | Type | Required | Default | Description |
|
|
300
|
-
|------|------|----------|---------|-------------|
|
|
301
|
-
| `onEditPage` | `(pageId: string) => void` | Yes | - | Callback function when a page is selected for editing |
|
|
302
|
-
| `widgetBackendUrl` | `string` | No | `undefined` | Base URL for the backend API |
|
|
303
|
-
|
|
304
|
-
### Features
|
|
305
|
-
|
|
306
|
-
- **Page Listing**: Grid view of all saved pages
|
|
307
|
-
- **Search**: Filter pages by title
|
|
308
|
-
- **Create Pages**: Modal dialog for creating new pages
|
|
309
|
-
- **Edit Pages**: Navigation to page editor
|
|
310
|
-
- **Delete Pages**: Remove existing pages
|
|
311
|
-
- **Public/Private**: Configure page visibility
|
|
312
|
-
|
|
313
|
-
### Page Properties
|
|
314
|
-
|
|
315
|
-
- **Title**: Page display name
|
|
316
|
-
- **Public Status**: Whether the page is publicly accessible
|
|
317
|
-
- **Creation Date**: When the page was created
|
|
318
|
-
- **Owner**: Page owner identifier
|
|
319
|
-
|
|
320
|
-
### Usage Example
|
|
321
|
-
|
|
322
|
-
```jsx
|
|
323
|
-
import { SavedPages } from 'di-widgets-framework';
|
|
324
|
-
|
|
325
|
-
function PageManager() {
|
|
326
|
-
const handleEditPage = (pageId) => {
|
|
327
|
-
// Navigate to page editor
|
|
328
|
-
router.push(`/editor/${pageId}`);
|
|
329
|
-
};
|
|
330
|
-
|
|
331
|
-
return (
|
|
332
|
-
<SavedPages
|
|
333
|
-
onEditPage={handleEditPage}
|
|
334
|
-
widgetBackendUrl="http://localhost:3001"
|
|
335
|
-
/>
|
|
336
|
-
);
|
|
337
|
-
}
|
|
338
|
-
```
|
|
339
|
-
|
|
340
|
-
### Create Page Modal
|
|
341
|
-
|
|
342
|
-
The component includes a modal for creating new pages with:
|
|
343
|
-
- **Title Input**: Required page title
|
|
344
|
-
- **Public Checkbox**: Make page publicly accessible
|
|
345
|
-
- **Validation**: Ensures title is provided
|
|
346
|
-
- **Error Handling**: Displays creation errors
|
|
347
|
-
|
|
348
|
-
---
|
|
349
|
-
|
|
350
|
-
## API Integration
|
|
351
|
-
|
|
352
|
-
All components integrate with a backend API and require the following endpoints:
|
|
353
|
-
|
|
354
|
-
### Required Endpoints
|
|
355
|
-
|
|
356
|
-
- `GET /api/pages` - List all pages
|
|
357
|
-
- `GET /api/pages/{id}` - Get specific page with widgets
|
|
358
|
-
- `POST /api/pages` - Create new page
|
|
359
|
-
- `PUT /api/pages/{id}` - Update page and widgets
|
|
360
|
-
- `DELETE /api/pages/{id}` - Delete page
|
|
361
|
-
- `GET /api/widgets/types` - Get available widget types
|
|
362
|
-
|
|
363
|
-
### Authentication
|
|
364
|
-
|
|
365
|
-
Components assume API authentication is handled at the application level through:
|
|
366
|
-
- HTTP headers
|
|
367
|
-
- Cookies
|
|
368
|
-
- URL parameters
|
|
369
|
-
- Environment configuration
|
|
370
|
-
|
|
371
|
-
### Error Handling
|
|
372
|
-
|
|
373
|
-
All components include:
|
|
374
|
-
- Loading states with spinners
|
|
375
|
-
- Error boundaries with user-friendly messages
|
|
376
|
-
- Retry mechanisms for failed requests
|
|
377
|
-
- Graceful degradation when APIs are unavailable
|
|
378
|
-
|
|
379
|
-
---
|
|
380
|
-
|
|
381
|
-
## Styling and Theming
|
|
382
|
-
|
|
383
|
-
Components use Tailwind CSS classes and support:
|
|
384
|
-
- **Dark/Light Mode**: Automatic theme detection
|
|
385
|
-
- **Custom Colors**: Configurable through CSS variables
|
|
386
|
-
- **Responsive Design**: Mobile-first responsive layouts
|
|
387
|
-
- **Accessibility**: ARIA labels and keyboard navigation
|
|
388
|
-
|
|
389
|
-
### CSS Dependencies
|
|
390
|
-
|
|
391
|
-
Required CSS imports for WidgetDashboard:
|
|
392
|
-
```css
|
|
393
|
-
import "@copilotkit/react-ui/styles.css";
|
|
394
|
-
import "react-grid-layout/css/styles.css";
|
|
395
|
-
import "react-resizable/css/styles.css";
|
|
396
|
-
```
|
|
397
|
-
|
|
398
|
-
---
|
|
399
|
-
|
|
400
|
-
## DashboardPages
|
|
401
|
-
|
|
402
|
-
A tab-based dashboard component that displays all saved pages in non-edit mode, with each page rendered in a separate tab using the WidgetDashboard component.
|
|
403
|
-
|
|
404
|
-
### Props
|
|
405
|
-
|
|
406
|
-
| Prop | Type | Required | Default | Description |
|
|
407
|
-
|------|------|----------|---------|-------------|
|
|
408
|
-
| `widgetBackendUrl` | `string` | No | `undefined` | Base URL for the backend API. If not provided, uses relative URLs |
|
|
409
|
-
|
|
410
|
-
### Features
|
|
411
|
-
|
|
412
|
-
- **Tab Interface**: Each saved page appears as a separate tab with the page title as the tab name
|
|
413
|
-
- **Non-Edit Mode**: All WidgetDashboard components are rendered in view-only mode (`isEditing={false}`)
|
|
414
|
-
- **Dynamic Loading**: Fetches saved pages from the backend API using `/api/pages?view=list`
|
|
415
|
-
- **Error Handling**: Proper loading states and error messages
|
|
416
|
-
- **Responsive Design**: Tabs adjust to accommodate any number of pages
|
|
417
|
-
- **Empty State**: Shows helpful message when no pages are found
|
|
418
|
-
|
|
419
|
-
### Usage Example
|
|
420
|
-
|
|
421
|
-
```jsx
|
|
422
|
-
import { DashboardPages } from 'di-widgets-framework';
|
|
423
|
-
|
|
424
|
-
function App() {
|
|
425
|
-
return (
|
|
426
|
-
<DashboardPages
|
|
427
|
-
widgetBackendUrl="http://localhost:3001"
|
|
428
|
-
/>
|
|
429
|
-
);
|
|
430
|
-
}
|
|
431
|
-
```
|
|
432
|
-
|
|
433
|
-
### Component Behavior
|
|
434
|
-
|
|
435
|
-
1. **Loading State**: Shows spinner while fetching pages
|
|
436
|
-
2. **Tab Creation**: Creates a tab for each saved page using the page title
|
|
437
|
-
3. **Default Tab**: Automatically selects the first page as the default active tab
|
|
438
|
-
4. **Widget Rendering**: Each tab content renders a WidgetDashboard component in non-edit mode
|
|
439
|
-
5. **Error Handling**: Displays error messages if API calls fail
|
|
440
|
-
|
|
441
|
-
### Required API Endpoints
|
|
442
|
-
|
|
443
|
-
- `GET /api/pages?view=list` - List all saved pages with basic information
|
|
444
|
-
|
|
445
|
-
### API Response Format
|
|
446
|
-
|
|
447
|
-
Expected response from `/api/pages?view=list`:
|
|
448
|
-
```json
|
|
449
|
-
[
|
|
450
|
-
{
|
|
451
|
-
"id": "page-123",
|
|
452
|
-
"title": "My Dashboard",
|
|
453
|
-
"owner_id": "user-456",
|
|
454
|
-
"is_public": false,
|
|
455
|
-
"allowed_domains": [],
|
|
456
|
-
"theme_id": null
|
|
457
|
-
}
|
|
458
|
-
]
|
|
459
|
-
```
|
|
460
|
-
|
|
461
|
-
### Styling
|
|
462
|
-
|
|
463
|
-
- Uses consistent tab styling with the framework's design system
|
|
464
|
-
- Supports responsive breakpoints for different screen sizes
|
|
465
|
-
- Includes proper spacing and visual hierarchy
|
|
466
|
-
- Tab titles are truncated with ellipsis for long names and show full title on hover
|
|
467
|
-
|
|
468
|
-
---
|
|
469
|
-
|
|
470
|
-
## Best Practices
|
|
471
|
-
|
|
472
|
-
1. **Performance**: Use `refreshKey` prop to trigger selective re-renders
|
|
473
|
-
2. **State Management**: Lift state up to parent components when needed
|
|
474
|
-
3. **Error Boundaries**: Wrap components in error boundaries
|
|
475
|
-
4. **Loading States**: Show loading indicators during API calls
|
|
476
|
-
5. **Accessibility**: Ensure keyboard navigation and screen reader support
|
|
477
|
-
6. **Responsive Design**: Test on different screen sizes
|
|
1
|
+
# Widget Framework Components Documentation
|
|
2
|
+
|
|
3
|
+
## Table of Contents
|
|
4
|
+
1. [WidgetPalette](#widgetpalette)
|
|
5
|
+
2. [WidgetSettingsPanel](#widgetsettingspanel)
|
|
6
|
+
3. [WidgetDashboard](#widgetdashboard)
|
|
7
|
+
4. [Widget (Type Interface)](#widget-type-interface)
|
|
8
|
+
5. [SavedPages](#savedpages)
|
|
9
|
+
6. [DashboardPages](#dashboardpages)
|
|
10
|
+
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
## WidgetPalette
|
|
14
|
+
|
|
15
|
+
A draggable widget palette component that displays available widget types and allows users to drag them onto the dashboard.
|
|
16
|
+
|
|
17
|
+
### Props
|
|
18
|
+
|
|
19
|
+
| Prop | Type | Required | Default | Description |
|
|
20
|
+
|------|------|----------|---------|-------------|
|
|
21
|
+
| `widgetBackendUrl` | `string` | No | `undefined` | Base URL for the backend API. If not provided, uses relative URLs |
|
|
22
|
+
|
|
23
|
+
### Features
|
|
24
|
+
|
|
25
|
+
- **Search Functionality**: Built-in search to filter widgets by name or description
|
|
26
|
+
- **Drag & Drop**: Widgets can be dragged from the palette to the dashboard
|
|
27
|
+
- **Dynamic Loading**: Fetches available widget types from the backend API
|
|
28
|
+
- **Icon Mapping**: Displays appropriate icons for each widget type
|
|
29
|
+
|
|
30
|
+
### Usage Example
|
|
31
|
+
|
|
32
|
+
npm install di-widgets-framework
|
|
33
|
+
|
|
34
|
+
```jsx
|
|
35
|
+
import { WidgetPalette } from 'di-widgets-framework';
|
|
36
|
+
|
|
37
|
+
function App() {
|
|
38
|
+
return (
|
|
39
|
+
<WidgetPalette
|
|
40
|
+
widgetBackendUrl="http://localhost:3001"
|
|
41
|
+
/>
|
|
42
|
+
);
|
|
43
|
+
}
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
### Widget Types Supported
|
|
47
|
+
|
|
48
|
+
- **search**: Search input widget (12x2 grid)
|
|
49
|
+
- **filter**: Filter/facet widget (3x8 grid)
|
|
50
|
+
- **results**: Results display widget (9x8 grid)
|
|
51
|
+
- **analytics**: Analytics/charts widget (6x4 grid)
|
|
52
|
+
- **header**: Header section widget (12x2 grid)
|
|
53
|
+
- **footer**: Footer section widget (12x2 grid)
|
|
54
|
+
- **text**: Text content widget (6x2 grid)
|
|
55
|
+
- **agent**: AI agent interaction widget (6x4 grid)
|
|
56
|
+
|
|
57
|
+
---
|
|
58
|
+
|
|
59
|
+
## WidgetSettingsPanel
|
|
60
|
+
|
|
61
|
+
A comprehensive settings panel for configuring widget properties including styling, behavior, and type-specific options.
|
|
62
|
+
|
|
63
|
+
### Props
|
|
64
|
+
|
|
65
|
+
| Prop | Type | Required | Default | Description |
|
|
66
|
+
|------|------|----------|---------|-------------|
|
|
67
|
+
| `pageId` | `string` | Yes | - | The ID of the page containing the widget |
|
|
68
|
+
| `widget` | `Widget` | Yes | - | The widget object to configure |
|
|
69
|
+
| `onClose` | `() => void` | Yes | - | Callback function when the panel is closed |
|
|
70
|
+
| `onWidgetUpdate` | `() => void` | No | `undefined` | Callback function when widget is updated |
|
|
71
|
+
| `widgetBackendUrl` | `string` | No | `undefined` | Base URL for the backend API |
|
|
72
|
+
| `agentIds` | `string[]` | No | `undefined` | Array of available agent IDs for dropdown selection |
|
|
73
|
+
|
|
74
|
+
### Features
|
|
75
|
+
|
|
76
|
+
#### Common Settings (All Widgets)
|
|
77
|
+
- **Title**: Widget display title
|
|
78
|
+
- **Show Header**: Toggle widget header visibility
|
|
79
|
+
- **Resizable**: Enable/disable widget resizing
|
|
80
|
+
- **Draggable**: Enable/disable widget dragging
|
|
81
|
+
- **Styling Options**:
|
|
82
|
+
- Background color (color picker + text input)
|
|
83
|
+
- Border radius (none, rounded, large, extra-large)
|
|
84
|
+
- Padding (small, medium, large, extra-large)
|
|
85
|
+
- Text color (color picker + text input)
|
|
86
|
+
- Font size (custom CSS values)
|
|
87
|
+
- Text alignment (left, center, right)
|
|
88
|
+
|
|
89
|
+
#### Search Widget Settings
|
|
90
|
+
- **Placeholder Text**: Search input placeholder
|
|
91
|
+
- **Minimum Characters**: Required characters before search (1-10)
|
|
92
|
+
- **Search Delay**: Debounce delay in milliseconds (0-1000)
|
|
93
|
+
- **Auto Focus**: Automatically focus the search input
|
|
94
|
+
- **Voice Search**: Enable voice search functionality
|
|
95
|
+
- **Recent Searches**: Show recent search history
|
|
96
|
+
- **Maximum Recent Searches**: Number of recent searches to store
|
|
97
|
+
- **Facets Configuration**: Enable and configure search facets
|
|
98
|
+
|
|
99
|
+
#### Results Widget Settings
|
|
100
|
+
- **Layout Type**: Grid, list, or table display
|
|
101
|
+
- **Items Per Page**: 5, 10, 20, 50, or 100 items
|
|
102
|
+
- **Infinite Scroll**: Enable infinite scrolling
|
|
103
|
+
- **Show Pagination**: Display pagination controls
|
|
104
|
+
- **Hide Relevance**: Hide relevance scores
|
|
105
|
+
- **Title Template**: Field to use for result titles
|
|
106
|
+
- **Metadata Fields**: Configure displayed metadata
|
|
107
|
+
|
|
108
|
+
#### Filter Widget Settings
|
|
109
|
+
- **Show Clear Button**: Display clear all filters button
|
|
110
|
+
- **Collapsible Sections**: Make filter sections collapsible
|
|
111
|
+
- **Default Expanded**: Default expansion state for sections
|
|
112
|
+
- **Facets Configuration**: Configure filter facets
|
|
113
|
+
|
|
114
|
+
#### Agent Widget Settings
|
|
115
|
+
- **Agent Type**: Chatbot Agent, Bar Chart Agent, or Pie Chart Agent
|
|
116
|
+
- **Agent ID**: Unique identifier for the agent (dropdown if agentIds prop provided, otherwise text input)
|
|
117
|
+
- **Query**: Custom query for non-chatbot agents
|
|
118
|
+
|
|
119
|
+
#### Code Settings (Search Widget)
|
|
120
|
+
- **Custom Widget Code**: JavaScript code editor for custom functionality
|
|
121
|
+
|
|
122
|
+
### Usage Example
|
|
123
|
+
|
|
124
|
+
```jsx
|
|
125
|
+
import { WidgetSettingsPanel } from 'di-widgets-framework';
|
|
126
|
+
|
|
127
|
+
function MyComponent() {
|
|
128
|
+
const [selectedWidget, setSelectedWidget] = useState(null);
|
|
129
|
+
const agentIds = ['agent-1', 'agent-2', 'chatbot-agent']; // Optional: provide agent IDs
|
|
130
|
+
|
|
131
|
+
return (
|
|
132
|
+
<WidgetSettingsPanel
|
|
133
|
+
pageId="page-123"
|
|
134
|
+
widget={selectedWidget}
|
|
135
|
+
onClose={() => setSelectedWidget(null)}
|
|
136
|
+
onWidgetUpdate={handleWidgetUpdate}
|
|
137
|
+
widgetBackendUrl="http://localhost:3001"
|
|
138
|
+
agentIds={agentIds}
|
|
139
|
+
/>
|
|
140
|
+
);
|
|
141
|
+
}
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
---
|
|
145
|
+
|
|
146
|
+
## WidgetDashboard
|
|
147
|
+
|
|
148
|
+
The main dashboard component that provides a drag-and-drop grid layout for widgets with editing capabilities.
|
|
149
|
+
|
|
150
|
+
### Props
|
|
151
|
+
|
|
152
|
+
| Prop | Type | Required | Default | Description |
|
|
153
|
+
|------|------|----------|---------|-------------|
|
|
154
|
+
| `pageId` | `string` | Yes | - | The ID of the page to display |
|
|
155
|
+
| `isEditing` | `boolean` | Yes | - | Whether the dashboard is in edit mode |
|
|
156
|
+
| `selectedWidget` | `Widget \| null` | No | `null` | Currently selected widget |
|
|
157
|
+
| `onWidgetSelect` | `(widget: Widget \| null) => void` | No | `undefined` | Callback when a widget is selected |
|
|
158
|
+
| `refreshKey` | `number` | No | `undefined` | Key to trigger data refresh |
|
|
159
|
+
| `widgetBackendUrl` | `string` | No | `undefined` | Base URL for the backend API |
|
|
160
|
+
|
|
161
|
+
### Features
|
|
162
|
+
|
|
163
|
+
- **Grid Layout**: 12-column responsive grid system using react-grid-layout
|
|
164
|
+
- **Drag & Drop**: Accept widgets from the palette and arrange existing widgets
|
|
165
|
+
- **Editing Mode**: Toggle between view and edit modes
|
|
166
|
+
- **Widget Selection**: Click to select widgets for configuration
|
|
167
|
+
- **Auto-save**: Automatically saves layout changes with debouncing (2-second delay)
|
|
168
|
+
- **Widget Management**: Add, remove, and configure widgets
|
|
169
|
+
- **Responsive**: Adjusts to container width
|
|
170
|
+
- **Collision Prevention**: Prevents widgets from overlapping
|
|
171
|
+
|
|
172
|
+
### Layout Configuration
|
|
173
|
+
|
|
174
|
+
- **Columns**: 12-column grid
|
|
175
|
+
- **Row Height**: 50px per row
|
|
176
|
+
- **Margins**: 8px between widgets
|
|
177
|
+
- **Minimum Size**: 3 columns wide, 2 rows high
|
|
178
|
+
|
|
179
|
+
### Required CSS Imports
|
|
180
|
+
|
|
181
|
+
To use the WidgetDashboard component, you must import the following CSS files:
|
|
182
|
+
|
|
183
|
+
```css
|
|
184
|
+
import "@copilotkit/react-ui/styles.css";
|
|
185
|
+
import "react-grid-layout/css/styles.css";
|
|
186
|
+
import "react-resizable/css/styles.css";
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
### Usage Example
|
|
190
|
+
|
|
191
|
+
```jsx
|
|
192
|
+
import { WidgetDashboard } from 'di-widgets-framework';
|
|
193
|
+
import "@copilotkit/react-ui/styles.css";
|
|
194
|
+
import "react-grid-layout/css/styles.css";
|
|
195
|
+
import "react-resizable/css/styles.css";
|
|
196
|
+
|
|
197
|
+
function Dashboard() {
|
|
198
|
+
const [isEditing, setIsEditing] = useState(false);
|
|
199
|
+
const [selectedWidget, setSelectedWidget] = useState(null);
|
|
200
|
+
|
|
201
|
+
return (
|
|
202
|
+
<WidgetDashboard
|
|
203
|
+
pageId="page-123"
|
|
204
|
+
isEditing={isEditing}
|
|
205
|
+
selectedWidget={selectedWidget}
|
|
206
|
+
onWidgetSelect={setSelectedWidget}
|
|
207
|
+
widgetBackendUrl="http://localhost:3001"
|
|
208
|
+
/>
|
|
209
|
+
);
|
|
210
|
+
}
|
|
211
|
+
```
|
|
212
|
+
|
|
213
|
+
---
|
|
214
|
+
|
|
215
|
+
## Widget (Type Interface)
|
|
216
|
+
|
|
217
|
+
The core widget data structure used throughout the framework.
|
|
218
|
+
|
|
219
|
+
### Interface Definition
|
|
220
|
+
|
|
221
|
+
```typescript
|
|
222
|
+
interface Widget {
|
|
223
|
+
id: string; // Unique widget identifier
|
|
224
|
+
page_id: string; // ID of the containing page
|
|
225
|
+
type: string; // Widget type (search, filter, results, etc.)
|
|
226
|
+
title: string; // Display title
|
|
227
|
+
position_x: number; // Grid X position (0-11)
|
|
228
|
+
position_y: number; // Grid Y position
|
|
229
|
+
width: number; // Grid width (1-12)
|
|
230
|
+
height: number; // Grid height in rows
|
|
231
|
+
config: any; // Widget-specific configuration
|
|
232
|
+
category_id?: string; // Optional category identifier
|
|
233
|
+
is_resizable: boolean; // Whether widget can be resized
|
|
234
|
+
is_draggable: boolean; // Whether widget can be dragged
|
|
235
|
+
}
|
|
236
|
+
```
|
|
237
|
+
|
|
238
|
+
### Widget Configuration Examples
|
|
239
|
+
|
|
240
|
+
#### Search Widget Config
|
|
241
|
+
```typescript
|
|
242
|
+
{
|
|
243
|
+
placeholder: "Search...",
|
|
244
|
+
minCharacters: 3,
|
|
245
|
+
searchDelay: 300,
|
|
246
|
+
autoFocus: true,
|
|
247
|
+
voiceSearch: false,
|
|
248
|
+
recentSearches: true,
|
|
249
|
+
maxRecentSearches: 5,
|
|
250
|
+
facets: {
|
|
251
|
+
enabled: true,
|
|
252
|
+
fields: [
|
|
253
|
+
{ field: "category", displayName: "Category", order: 1, enabled: true }
|
|
254
|
+
]
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
```
|
|
258
|
+
|
|
259
|
+
#### Results Widget Config
|
|
260
|
+
```typescript
|
|
261
|
+
{
|
|
262
|
+
layout: {
|
|
263
|
+
type: "grid",
|
|
264
|
+
itemsPerPage: 10,
|
|
265
|
+
infiniteScroll: false
|
|
266
|
+
},
|
|
267
|
+
showPagination: true,
|
|
268
|
+
hideRelevance: false,
|
|
269
|
+
titleTemplate: "filename",
|
|
270
|
+
metadata: {
|
|
271
|
+
fields: ["author", "date", "category"]
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
```
|
|
275
|
+
|
|
276
|
+
#### Styling Config
|
|
277
|
+
```typescript
|
|
278
|
+
{
|
|
279
|
+
styles: {
|
|
280
|
+
backgroundColor: "#ffffff",
|
|
281
|
+
textColor: "#000000",
|
|
282
|
+
fontSize: "14px",
|
|
283
|
+
padding: "medium",
|
|
284
|
+
borderRadius: "rounded",
|
|
285
|
+
alignment: "left"
|
|
286
|
+
},
|
|
287
|
+
showHeader: true
|
|
288
|
+
}
|
|
289
|
+
```
|
|
290
|
+
|
|
291
|
+
---
|
|
292
|
+
|
|
293
|
+
## SavedPages
|
|
294
|
+
|
|
295
|
+
A page management component for listing, creating, and managing saved widget pages.
|
|
296
|
+
|
|
297
|
+
### Props
|
|
298
|
+
|
|
299
|
+
| Prop | Type | Required | Default | Description |
|
|
300
|
+
|------|------|----------|---------|-------------|
|
|
301
|
+
| `onEditPage` | `(pageId: string) => void` | Yes | - | Callback function when a page is selected for editing |
|
|
302
|
+
| `widgetBackendUrl` | `string` | No | `undefined` | Base URL for the backend API |
|
|
303
|
+
|
|
304
|
+
### Features
|
|
305
|
+
|
|
306
|
+
- **Page Listing**: Grid view of all saved pages
|
|
307
|
+
- **Search**: Filter pages by title
|
|
308
|
+
- **Create Pages**: Modal dialog for creating new pages
|
|
309
|
+
- **Edit Pages**: Navigation to page editor
|
|
310
|
+
- **Delete Pages**: Remove existing pages
|
|
311
|
+
- **Public/Private**: Configure page visibility
|
|
312
|
+
|
|
313
|
+
### Page Properties
|
|
314
|
+
|
|
315
|
+
- **Title**: Page display name
|
|
316
|
+
- **Public Status**: Whether the page is publicly accessible
|
|
317
|
+
- **Creation Date**: When the page was created
|
|
318
|
+
- **Owner**: Page owner identifier
|
|
319
|
+
|
|
320
|
+
### Usage Example
|
|
321
|
+
|
|
322
|
+
```jsx
|
|
323
|
+
import { SavedPages } from 'di-widgets-framework';
|
|
324
|
+
|
|
325
|
+
function PageManager() {
|
|
326
|
+
const handleEditPage = (pageId) => {
|
|
327
|
+
// Navigate to page editor
|
|
328
|
+
router.push(`/editor/${pageId}`);
|
|
329
|
+
};
|
|
330
|
+
|
|
331
|
+
return (
|
|
332
|
+
<SavedPages
|
|
333
|
+
onEditPage={handleEditPage}
|
|
334
|
+
widgetBackendUrl="http://localhost:3001"
|
|
335
|
+
/>
|
|
336
|
+
);
|
|
337
|
+
}
|
|
338
|
+
```
|
|
339
|
+
|
|
340
|
+
### Create Page Modal
|
|
341
|
+
|
|
342
|
+
The component includes a modal for creating new pages with:
|
|
343
|
+
- **Title Input**: Required page title
|
|
344
|
+
- **Public Checkbox**: Make page publicly accessible
|
|
345
|
+
- **Validation**: Ensures title is provided
|
|
346
|
+
- **Error Handling**: Displays creation errors
|
|
347
|
+
|
|
348
|
+
---
|
|
349
|
+
|
|
350
|
+
## API Integration
|
|
351
|
+
|
|
352
|
+
All components integrate with a backend API and require the following endpoints:
|
|
353
|
+
|
|
354
|
+
### Required Endpoints
|
|
355
|
+
|
|
356
|
+
- `GET /api/pages` - List all pages
|
|
357
|
+
- `GET /api/pages/{id}` - Get specific page with widgets
|
|
358
|
+
- `POST /api/pages` - Create new page
|
|
359
|
+
- `PUT /api/pages/{id}` - Update page and widgets
|
|
360
|
+
- `DELETE /api/pages/{id}` - Delete page
|
|
361
|
+
- `GET /api/widgets/types` - Get available widget types
|
|
362
|
+
|
|
363
|
+
### Authentication
|
|
364
|
+
|
|
365
|
+
Components assume API authentication is handled at the application level through:
|
|
366
|
+
- HTTP headers
|
|
367
|
+
- Cookies
|
|
368
|
+
- URL parameters
|
|
369
|
+
- Environment configuration
|
|
370
|
+
|
|
371
|
+
### Error Handling
|
|
372
|
+
|
|
373
|
+
All components include:
|
|
374
|
+
- Loading states with spinners
|
|
375
|
+
- Error boundaries with user-friendly messages
|
|
376
|
+
- Retry mechanisms for failed requests
|
|
377
|
+
- Graceful degradation when APIs are unavailable
|
|
378
|
+
|
|
379
|
+
---
|
|
380
|
+
|
|
381
|
+
## Styling and Theming
|
|
382
|
+
|
|
383
|
+
Components use Tailwind CSS classes and support:
|
|
384
|
+
- **Dark/Light Mode**: Automatic theme detection
|
|
385
|
+
- **Custom Colors**: Configurable through CSS variables
|
|
386
|
+
- **Responsive Design**: Mobile-first responsive layouts
|
|
387
|
+
- **Accessibility**: ARIA labels and keyboard navigation
|
|
388
|
+
|
|
389
|
+
### CSS Dependencies
|
|
390
|
+
|
|
391
|
+
Required CSS imports for WidgetDashboard:
|
|
392
|
+
```css
|
|
393
|
+
import "@copilotkit/react-ui/styles.css";
|
|
394
|
+
import "react-grid-layout/css/styles.css";
|
|
395
|
+
import "react-resizable/css/styles.css";
|
|
396
|
+
```
|
|
397
|
+
|
|
398
|
+
---
|
|
399
|
+
|
|
400
|
+
## DashboardPages
|
|
401
|
+
|
|
402
|
+
A tab-based dashboard component that displays all saved pages in non-edit mode, with each page rendered in a separate tab using the WidgetDashboard component.
|
|
403
|
+
|
|
404
|
+
### Props
|
|
405
|
+
|
|
406
|
+
| Prop | Type | Required | Default | Description |
|
|
407
|
+
|------|------|----------|---------|-------------|
|
|
408
|
+
| `widgetBackendUrl` | `string` | No | `undefined` | Base URL for the backend API. If not provided, uses relative URLs |
|
|
409
|
+
|
|
410
|
+
### Features
|
|
411
|
+
|
|
412
|
+
- **Tab Interface**: Each saved page appears as a separate tab with the page title as the tab name
|
|
413
|
+
- **Non-Edit Mode**: All WidgetDashboard components are rendered in view-only mode (`isEditing={false}`)
|
|
414
|
+
- **Dynamic Loading**: Fetches saved pages from the backend API using `/api/pages?view=list`
|
|
415
|
+
- **Error Handling**: Proper loading states and error messages
|
|
416
|
+
- **Responsive Design**: Tabs adjust to accommodate any number of pages
|
|
417
|
+
- **Empty State**: Shows helpful message when no pages are found
|
|
418
|
+
|
|
419
|
+
### Usage Example
|
|
420
|
+
|
|
421
|
+
```jsx
|
|
422
|
+
import { DashboardPages } from 'di-widgets-framework';
|
|
423
|
+
|
|
424
|
+
function App() {
|
|
425
|
+
return (
|
|
426
|
+
<DashboardPages
|
|
427
|
+
widgetBackendUrl="http://localhost:3001"
|
|
428
|
+
/>
|
|
429
|
+
);
|
|
430
|
+
}
|
|
431
|
+
```
|
|
432
|
+
|
|
433
|
+
### Component Behavior
|
|
434
|
+
|
|
435
|
+
1. **Loading State**: Shows spinner while fetching pages
|
|
436
|
+
2. **Tab Creation**: Creates a tab for each saved page using the page title
|
|
437
|
+
3. **Default Tab**: Automatically selects the first page as the default active tab
|
|
438
|
+
4. **Widget Rendering**: Each tab content renders a WidgetDashboard component in non-edit mode
|
|
439
|
+
5. **Error Handling**: Displays error messages if API calls fail
|
|
440
|
+
|
|
441
|
+
### Required API Endpoints
|
|
442
|
+
|
|
443
|
+
- `GET /api/pages?view=list` - List all saved pages with basic information
|
|
444
|
+
|
|
445
|
+
### API Response Format
|
|
446
|
+
|
|
447
|
+
Expected response from `/api/pages?view=list`:
|
|
448
|
+
```json
|
|
449
|
+
[
|
|
450
|
+
{
|
|
451
|
+
"id": "page-123",
|
|
452
|
+
"title": "My Dashboard",
|
|
453
|
+
"owner_id": "user-456",
|
|
454
|
+
"is_public": false,
|
|
455
|
+
"allowed_domains": [],
|
|
456
|
+
"theme_id": null
|
|
457
|
+
}
|
|
458
|
+
]
|
|
459
|
+
```
|
|
460
|
+
|
|
461
|
+
### Styling
|
|
462
|
+
|
|
463
|
+
- Uses consistent tab styling with the framework's design system
|
|
464
|
+
- Supports responsive breakpoints for different screen sizes
|
|
465
|
+
- Includes proper spacing and visual hierarchy
|
|
466
|
+
- Tab titles are truncated with ellipsis for long names and show full title on hover
|
|
467
|
+
|
|
468
|
+
---
|
|
469
|
+
|
|
470
|
+
## Best Practices
|
|
471
|
+
|
|
472
|
+
1. **Performance**: Use `refreshKey` prop to trigger selective re-renders
|
|
473
|
+
2. **State Management**: Lift state up to parent components when needed
|
|
474
|
+
3. **Error Boundaries**: Wrap components in error boundaries
|
|
475
|
+
4. **Loading States**: Show loading indicators during API calls
|
|
476
|
+
5. **Accessibility**: Ensure keyboard navigation and screen reader support
|
|
477
|
+
6. **Responsive Design**: Test on different screen sizes
|
|
478
478
|
7. **API Error Handling**: Implement retry logic and user feedback
|