@pubflow/react 0.1.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/LICENSE +661 -0
- package/README.md +539 -0
- package/dist/index.d.ts +1908 -0
- package/dist/index.esm.js +9922 -0
- package/dist/index.esm.js.map +1 -0
- package/dist/index.js +9954 -0
- package/dist/index.js.map +1 -0
- package/dist/types/components/AdvancedFilter.d.ts +113 -0
- package/dist/types/components/BridgeForm/index.d.ts +6 -0
- package/dist/types/components/BridgeForm/styles.d.ts +62 -0
- package/dist/types/components/BridgeForm/types.d.ts +128 -0
- package/dist/types/components/BridgeForm/utils.d.ts +60 -0
- package/dist/types/components/BridgeList.d.ts +157 -0
- package/dist/types/components/BridgeTable.d.ts +110 -0
- package/dist/types/components/BridgeView.d.ts +39 -0
- package/dist/types/components/OfflineIndicator.d.ts +58 -0
- package/dist/types/components/auth/AccountCreationForm.d.ts +60 -0
- package/dist/types/components/auth/LoginForm.d.ts +76 -0
- package/dist/types/components/auth/PasswordResetForm.d.ts +60 -0
- package/dist/types/components/auth/index.d.ts +8 -0
- package/dist/types/components/theme/ThemeProvider.d.ts +255 -0
- package/dist/types/components/theme/index.d.ts +6 -0
- package/dist/types/context/PubflowProvider.d.ts +100 -0
- package/dist/types/hooks/useAuth.d.ts +32 -0
- package/dist/types/hooks/useBridgeApi.d.ts +14 -0
- package/dist/types/hooks/useBridgeApiRaw.d.ts +91 -0
- package/dist/types/hooks/useBridgeCrud.d.ts +193 -0
- package/dist/types/hooks/useBridgeMutation.d.ts +69 -0
- package/dist/types/hooks/useBridgeQuery.d.ts +44 -0
- package/dist/types/hooks/useSearchQueryBuilder.d.ts +152 -0
- package/dist/types/hooks/useServerAuth.d.ts +45 -0
- package/dist/types/index.d.ts +26 -0
- package/dist/types/storage/BrowserStorageAdapter.d.ts +112 -0
- package/dist/types/test/setup.d.ts +4 -0
- package/dist/types/utils/auth-utils.d.ts +37 -0
- package/dist/types/utils/index.d.ts +5 -0
- package/dist/types/utils/persistent-cache.d.ts +57 -0
- package/package.json +70 -0
package/README.md
ADDED
|
@@ -0,0 +1,539 @@
|
|
|
1
|
+
# @pubflow/react
|
|
2
|
+
|
|
3
|
+
React adapter for the Pubflow framework with support for any React-based framework.
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
- Complete React integration for Pubflow
|
|
8
|
+
- SWR for data fetching and caching
|
|
9
|
+
- Framework-agnostic design (works with any React framework)
|
|
10
|
+
- Support for Remix, Next.js, Create React App, and more
|
|
11
|
+
- Optimized for React 17+
|
|
12
|
+
- TypeScript support
|
|
13
|
+
- Customizable components
|
|
14
|
+
|
|
15
|
+
## Installation
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
# Install the core package and React adapter
|
|
19
|
+
npm install @pubflow/core @pubflow/react
|
|
20
|
+
|
|
21
|
+
# Install SWR (required)
|
|
22
|
+
npm install swr
|
|
23
|
+
|
|
24
|
+
# Optional: Install Zod for schema validation
|
|
25
|
+
npm install zod
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
## Basic Usage
|
|
29
|
+
|
|
30
|
+
### Provider Setup
|
|
31
|
+
|
|
32
|
+
Wrap your application with the `PubflowProvider`:
|
|
33
|
+
|
|
34
|
+
```jsx
|
|
35
|
+
// App.jsx
|
|
36
|
+
import React from 'react';
|
|
37
|
+
import { PubflowProvider } from '@pubflow/react';
|
|
38
|
+
|
|
39
|
+
function App() {
|
|
40
|
+
return (
|
|
41
|
+
<PubflowProvider
|
|
42
|
+
config={{
|
|
43
|
+
baseUrl: 'https://api.example.com',
|
|
44
|
+
bridgeBasePath: '/bridge',
|
|
45
|
+
authBasePath: '/auth'
|
|
46
|
+
}}
|
|
47
|
+
>
|
|
48
|
+
<YourApp />
|
|
49
|
+
</PubflowProvider>
|
|
50
|
+
);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
export default App;
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
### Authentication
|
|
57
|
+
|
|
58
|
+
Use the `useAuth` hook to access authentication functionality:
|
|
59
|
+
|
|
60
|
+
```jsx
|
|
61
|
+
// Login.jsx
|
|
62
|
+
import React, { useState } from 'react';
|
|
63
|
+
import { useAuth } from '@pubflow/react';
|
|
64
|
+
|
|
65
|
+
function Login() {
|
|
66
|
+
const { login, isLoading } = useAuth();
|
|
67
|
+
const [email, setEmail] = useState('');
|
|
68
|
+
const [password, setPassword] = useState('');
|
|
69
|
+
|
|
70
|
+
const handleSubmit = async (e) => {
|
|
71
|
+
e.preventDefault();
|
|
72
|
+
|
|
73
|
+
try {
|
|
74
|
+
const result = await login({ email, password });
|
|
75
|
+
|
|
76
|
+
if (result.success) {
|
|
77
|
+
// Redirect to dashboard
|
|
78
|
+
}
|
|
79
|
+
} catch (error) {
|
|
80
|
+
console.error('Login failed:', error);
|
|
81
|
+
}
|
|
82
|
+
};
|
|
83
|
+
|
|
84
|
+
return (
|
|
85
|
+
<form onSubmit={handleSubmit}>
|
|
86
|
+
<input
|
|
87
|
+
type="email"
|
|
88
|
+
value={email}
|
|
89
|
+
onChange={(e) => setEmail(e.target.value)}
|
|
90
|
+
placeholder="Email"
|
|
91
|
+
/>
|
|
92
|
+
<input
|
|
93
|
+
type="password"
|
|
94
|
+
value={password}
|
|
95
|
+
onChange={(e) => setPassword(e.target.value)}
|
|
96
|
+
placeholder="Password"
|
|
97
|
+
/>
|
|
98
|
+
<button type="submit" disabled={isLoading}>
|
|
99
|
+
{isLoading ? 'Logging in...' : 'Login'}
|
|
100
|
+
</button>
|
|
101
|
+
</form>
|
|
102
|
+
);
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
export default Login;
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
### Data Fetching with SWR
|
|
109
|
+
|
|
110
|
+
Use the `useBridgeQuery` hook to fetch data:
|
|
111
|
+
|
|
112
|
+
```jsx
|
|
113
|
+
// UserList.jsx
|
|
114
|
+
import React from 'react';
|
|
115
|
+
import { useBridgeApi, useBridgeQuery } from '@pubflow/react';
|
|
116
|
+
|
|
117
|
+
function UserList() {
|
|
118
|
+
const userService = useBridgeApi({ endpoint: 'users' });
|
|
119
|
+
const { data: users, isLoading, error, refetch } = useBridgeQuery(
|
|
120
|
+
userService,
|
|
121
|
+
'list',
|
|
122
|
+
{ limit: 10 }
|
|
123
|
+
);
|
|
124
|
+
|
|
125
|
+
if (isLoading) {
|
|
126
|
+
return <div>Loading...</div>;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
if (error) {
|
|
130
|
+
return (
|
|
131
|
+
<div>
|
|
132
|
+
<div>Error: {error.message}</div>
|
|
133
|
+
<button onClick={refetch}>Retry</button>
|
|
134
|
+
</div>
|
|
135
|
+
);
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
return (
|
|
139
|
+
<div>
|
|
140
|
+
<h1>Users</h1>
|
|
141
|
+
<ul>
|
|
142
|
+
{users.map(user => (
|
|
143
|
+
<li key={user.id}>{user.name}</li>
|
|
144
|
+
))}
|
|
145
|
+
</ul>
|
|
146
|
+
</div>
|
|
147
|
+
);
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
export default UserList;
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
### CRUD Operations
|
|
154
|
+
|
|
155
|
+
Use the `useBridgeCrud` hook for complete CRUD operations:
|
|
156
|
+
|
|
157
|
+
```jsx
|
|
158
|
+
// UserManagement.jsx
|
|
159
|
+
import React, { useState } from 'react';
|
|
160
|
+
import { useBridgeCrud } from '@pubflow/react';
|
|
161
|
+
|
|
162
|
+
function UserManagement() {
|
|
163
|
+
const [formData, setFormData] = useState({ name: '', email: '' });
|
|
164
|
+
|
|
165
|
+
const {
|
|
166
|
+
items: users,
|
|
167
|
+
createItem,
|
|
168
|
+
updateItem,
|
|
169
|
+
deleteItem,
|
|
170
|
+
loading,
|
|
171
|
+
error
|
|
172
|
+
} = useBridgeCrud({
|
|
173
|
+
entityConfig: {
|
|
174
|
+
endpoint: 'users'
|
|
175
|
+
},
|
|
176
|
+
successMessages: {
|
|
177
|
+
create: 'User created successfully',
|
|
178
|
+
update: 'User updated successfully',
|
|
179
|
+
delete: 'User deleted successfully'
|
|
180
|
+
}
|
|
181
|
+
});
|
|
182
|
+
|
|
183
|
+
const handleSubmit = async (e) => {
|
|
184
|
+
e.preventDefault();
|
|
185
|
+
|
|
186
|
+
try {
|
|
187
|
+
await createItem(formData);
|
|
188
|
+
setFormData({ name: '', email: '' });
|
|
189
|
+
} catch (error) {
|
|
190
|
+
console.error('Failed to create user:', error);
|
|
191
|
+
}
|
|
192
|
+
};
|
|
193
|
+
|
|
194
|
+
return (
|
|
195
|
+
<div>
|
|
196
|
+
<h1>User Management</h1>
|
|
197
|
+
|
|
198
|
+
<form onSubmit={handleSubmit}>
|
|
199
|
+
<input
|
|
200
|
+
type="text"
|
|
201
|
+
value={formData.name}
|
|
202
|
+
onChange={(e) => setFormData({ ...formData, name: e.target.value })}
|
|
203
|
+
placeholder="Name"
|
|
204
|
+
/>
|
|
205
|
+
<input
|
|
206
|
+
type="email"
|
|
207
|
+
value={formData.email}
|
|
208
|
+
onChange={(e) => setFormData({ ...formData, email: e.target.value })}
|
|
209
|
+
placeholder="Email"
|
|
210
|
+
/>
|
|
211
|
+
<button type="submit" disabled={loading}>
|
|
212
|
+
{loading ? 'Creating...' : 'Create User'}
|
|
213
|
+
</button>
|
|
214
|
+
</form>
|
|
215
|
+
|
|
216
|
+
{error && <div>Error: {error.message}</div>}
|
|
217
|
+
|
|
218
|
+
<ul>
|
|
219
|
+
{users.map(user => (
|
|
220
|
+
<li key={user.id}>
|
|
221
|
+
{user.name} ({user.email})
|
|
222
|
+
<button onClick={() => deleteItem(user.id)}>Delete</button>
|
|
223
|
+
</li>
|
|
224
|
+
))}
|
|
225
|
+
</ul>
|
|
226
|
+
</div>
|
|
227
|
+
);
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
export default UserManagement;
|
|
231
|
+
```
|
|
232
|
+
|
|
233
|
+
## Persistent Cache
|
|
234
|
+
|
|
235
|
+
Pubflow supports persistent caching to improve performance and offline experience:
|
|
236
|
+
|
|
237
|
+
```jsx
|
|
238
|
+
import { PubflowProvider, createPersistentCache } from '@pubflow/react';
|
|
239
|
+
|
|
240
|
+
function App() {
|
|
241
|
+
// Create a persistent cache provider
|
|
242
|
+
const persistentCacheProvider = createPersistentCache({
|
|
243
|
+
prefix: 'my_app_cache',
|
|
244
|
+
ttl: 24 * 60 * 60 * 1000, // 24 hours
|
|
245
|
+
});
|
|
246
|
+
|
|
247
|
+
return (
|
|
248
|
+
<PubflowProvider
|
|
249
|
+
config={{
|
|
250
|
+
baseUrl: 'https://api.example.com',
|
|
251
|
+
bridgeBasePath: '/bridge',
|
|
252
|
+
authBasePath: '/auth'
|
|
253
|
+
}}
|
|
254
|
+
persistentCache={{
|
|
255
|
+
enabled: true,
|
|
256
|
+
provider: persistentCacheProvider
|
|
257
|
+
}}
|
|
258
|
+
>
|
|
259
|
+
<YourApp />
|
|
260
|
+
</PubflowProvider>
|
|
261
|
+
);
|
|
262
|
+
}
|
|
263
|
+
```
|
|
264
|
+
|
|
265
|
+
For more information, see the [Persistent Cache](./docs/persistent-cache.md) documentation.
|
|
266
|
+
|
|
267
|
+
## BridgeForm Component
|
|
268
|
+
|
|
269
|
+
Pubflow provides a powerful form component that integrates with Zod schemas and Bridge API:
|
|
270
|
+
|
|
271
|
+
```jsx
|
|
272
|
+
import { BridgeForm } from '@pubflow/react';
|
|
273
|
+
import { z } from 'zod';
|
|
274
|
+
|
|
275
|
+
// Define schema
|
|
276
|
+
const userSchema = z.object({
|
|
277
|
+
name: z.string().min(2, 'Name must be at least 2 characters'),
|
|
278
|
+
email: z.string().email('Invalid email address'),
|
|
279
|
+
role: z.enum(['user', 'admin'], 'Role must be either user or admin')
|
|
280
|
+
});
|
|
281
|
+
|
|
282
|
+
function CreateUser() {
|
|
283
|
+
return (
|
|
284
|
+
<div>
|
|
285
|
+
<h1>Create User</h1>
|
|
286
|
+
<BridgeForm
|
|
287
|
+
schema={userSchema}
|
|
288
|
+
mode="create"
|
|
289
|
+
entityConfig={{ endpoint: 'users' }}
|
|
290
|
+
mainColor="#c30000"
|
|
291
|
+
onSuccess={(data) => {
|
|
292
|
+
console.log('User created:', data);
|
|
293
|
+
// Navigate or show success message
|
|
294
|
+
}}
|
|
295
|
+
/>
|
|
296
|
+
</div>
|
|
297
|
+
);
|
|
298
|
+
}
|
|
299
|
+
```
|
|
300
|
+
|
|
301
|
+
For more information, see the [BridgeForm documentation](./docs/bridge-form.md).
|
|
302
|
+
|
|
303
|
+
## Schema Validation
|
|
304
|
+
|
|
305
|
+
Pubflow recommends defining schemas at the application level, not in the adapter:
|
|
306
|
+
|
|
307
|
+
```jsx
|
|
308
|
+
// lib/schemas/user.js
|
|
309
|
+
import { z } from 'zod';
|
|
310
|
+
|
|
311
|
+
// Schema for complete user entity
|
|
312
|
+
export const userSchema = z.object({
|
|
313
|
+
id: z.string().uuid().optional(),
|
|
314
|
+
name: z.string().min(2, 'Name must be at least 2 characters'),
|
|
315
|
+
email: z.string().email('Invalid email address'),
|
|
316
|
+
role: z.enum(['user', 'admin'], 'Role must be either user or admin')
|
|
317
|
+
});
|
|
318
|
+
|
|
319
|
+
// Schema for creating a user
|
|
320
|
+
export const createUserSchema = userSchema.omit({
|
|
321
|
+
id: true
|
|
322
|
+
});
|
|
323
|
+
|
|
324
|
+
// Schema for updating a user
|
|
325
|
+
export const updateUserSchema = userSchema
|
|
326
|
+
.partial()
|
|
327
|
+
.extend({
|
|
328
|
+
id: z.string().uuid()
|
|
329
|
+
});
|
|
330
|
+
|
|
331
|
+
// TypeScript types inferred from schemas
|
|
332
|
+
export type User = z.infer<typeof userSchema>;
|
|
333
|
+
export type CreateUser = z.infer<typeof createUserSchema>;
|
|
334
|
+
export type UpdateUser = z.infer<typeof updateUserSchema>;
|
|
335
|
+
```
|
|
336
|
+
|
|
337
|
+
These schemas can then be used with Pubflow's CRUD operations:
|
|
338
|
+
|
|
339
|
+
```jsx
|
|
340
|
+
import { useBridgeCrud } from '@pubflow/react';
|
|
341
|
+
import { userSchema, createUserSchema, updateUserSchema } from '../lib/schemas/user';
|
|
342
|
+
|
|
343
|
+
function UsersPage() {
|
|
344
|
+
const {
|
|
345
|
+
items: users,
|
|
346
|
+
createItem,
|
|
347
|
+
updateItem,
|
|
348
|
+
deleteItem,
|
|
349
|
+
validationErrors
|
|
350
|
+
} = useBridgeCrud({
|
|
351
|
+
entityConfig: {
|
|
352
|
+
endpoint: 'users'
|
|
353
|
+
},
|
|
354
|
+
schemas: {
|
|
355
|
+
entity: userSchema,
|
|
356
|
+
create: createUserSchema,
|
|
357
|
+
update: updateUserSchema
|
|
358
|
+
}
|
|
359
|
+
});
|
|
360
|
+
|
|
361
|
+
// Component implementation...
|
|
362
|
+
}
|
|
363
|
+
```
|
|
364
|
+
|
|
365
|
+
## Framework Integration
|
|
366
|
+
|
|
367
|
+
Pubflow is designed to work with any React-based framework. Here are examples for popular frameworks:
|
|
368
|
+
|
|
369
|
+
For detailed Remix integration, see the [Remix Integration Guide](./docs/remix-integration.md).
|
|
370
|
+
|
|
371
|
+
### Remix Integration
|
|
372
|
+
|
|
373
|
+
```jsx
|
|
374
|
+
// app/routes/dashboard.jsx
|
|
375
|
+
import { useLoaderData, redirect } from '@remix-run/react';
|
|
376
|
+
import { json } from '@remix-run/node';
|
|
377
|
+
import { useRequireAuth } from '@pubflow/react';
|
|
378
|
+
|
|
379
|
+
// Server-side authentication check
|
|
380
|
+
export async function loader({ request }) {
|
|
381
|
+
// Get session from cookie
|
|
382
|
+
const cookieHeader = request.headers.get('Cookie');
|
|
383
|
+
const token = parseCookie(cookieHeader)['pubflow_session_token'];
|
|
384
|
+
|
|
385
|
+
if (!token) {
|
|
386
|
+
return redirect('/login');
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
// You can also fetch initial data here
|
|
390
|
+
return json({ initialData: 'some data' });
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
// Client-side component
|
|
394
|
+
export default function Dashboard() {
|
|
395
|
+
const { initialData } = useLoaderData();
|
|
396
|
+
|
|
397
|
+
// Client-side authentication check
|
|
398
|
+
useRequireAuth({
|
|
399
|
+
allowedTypes: ['admin', 'user'],
|
|
400
|
+
redirectTo: '/login',
|
|
401
|
+
// Use Remix's navigate function
|
|
402
|
+
redirectFn: (path) => {
|
|
403
|
+
window.location.href = path;
|
|
404
|
+
}
|
|
405
|
+
});
|
|
406
|
+
|
|
407
|
+
return (
|
|
408
|
+
<div>
|
|
409
|
+
<h1>Dashboard</h1>
|
|
410
|
+
{/* Dashboard content */}
|
|
411
|
+
</div>
|
|
412
|
+
);
|
|
413
|
+
}
|
|
414
|
+
```
|
|
415
|
+
|
|
416
|
+
### Next.js Integration
|
|
417
|
+
|
|
418
|
+
```jsx
|
|
419
|
+
// pages/dashboard.jsx
|
|
420
|
+
import { useRouter } from 'next/router';
|
|
421
|
+
import { useRequireAuth } from '@pubflow/react';
|
|
422
|
+
|
|
423
|
+
export default function Dashboard() {
|
|
424
|
+
const router = useRouter();
|
|
425
|
+
|
|
426
|
+
// Client-side authentication check
|
|
427
|
+
useRequireAuth({
|
|
428
|
+
allowedTypes: ['admin', 'user'],
|
|
429
|
+
redirectTo: '/login',
|
|
430
|
+
// Use Next.js router
|
|
431
|
+
redirectFn: (path) => {
|
|
432
|
+
router.push(path);
|
|
433
|
+
}
|
|
434
|
+
});
|
|
435
|
+
|
|
436
|
+
return (
|
|
437
|
+
<div>
|
|
438
|
+
<h1>Dashboard</h1>
|
|
439
|
+
{/* Dashboard content */}
|
|
440
|
+
</div>
|
|
441
|
+
);
|
|
442
|
+
}
|
|
443
|
+
```
|
|
444
|
+
|
|
445
|
+
### Create React App Integration
|
|
446
|
+
|
|
447
|
+
```jsx
|
|
448
|
+
// src/pages/Dashboard.jsx
|
|
449
|
+
import { useNavigate } from 'react-router-dom';
|
|
450
|
+
import { useRequireAuth } from '@pubflow/react';
|
|
451
|
+
|
|
452
|
+
export default function Dashboard() {
|
|
453
|
+
const navigate = useNavigate();
|
|
454
|
+
|
|
455
|
+
// Client-side authentication check
|
|
456
|
+
useRequireAuth({
|
|
457
|
+
allowedTypes: ['admin', 'user'],
|
|
458
|
+
redirectTo: '/login',
|
|
459
|
+
// Use React Router's navigate function
|
|
460
|
+
redirectFn: (path) => {
|
|
461
|
+
navigate(path);
|
|
462
|
+
}
|
|
463
|
+
});
|
|
464
|
+
|
|
465
|
+
return (
|
|
466
|
+
<div>
|
|
467
|
+
<h1>Dashboard</h1>
|
|
468
|
+
{/* Dashboard content */}
|
|
469
|
+
</div>
|
|
470
|
+
);
|
|
471
|
+
}
|
|
472
|
+
```
|
|
473
|
+
|
|
474
|
+
## Components
|
|
475
|
+
|
|
476
|
+
### BridgeView
|
|
477
|
+
|
|
478
|
+
The `BridgeView` component conditionally renders content based on authentication and user type:
|
|
479
|
+
|
|
480
|
+
```jsx
|
|
481
|
+
import { BridgeView } from '@pubflow/react';
|
|
482
|
+
|
|
483
|
+
// Basic example
|
|
484
|
+
<BridgeView>
|
|
485
|
+
<div>This content is only visible to authenticated users</div>
|
|
486
|
+
</BridgeView>
|
|
487
|
+
|
|
488
|
+
// Only for admins
|
|
489
|
+
<BridgeView
|
|
490
|
+
allowedTypes="admin"
|
|
491
|
+
fallback={<div>You don't have permission to view this content</div>}
|
|
492
|
+
>
|
|
493
|
+
<div>This content is only visible to admins</div>
|
|
494
|
+
</BridgeView>
|
|
495
|
+
|
|
496
|
+
// Multiple user types
|
|
497
|
+
<BridgeView
|
|
498
|
+
allowedTypes={['admin', 'editor']}
|
|
499
|
+
loadingComponent={<div>Loading...</div>}
|
|
500
|
+
onUnauthorized={() => console.log('User not authorized')}
|
|
501
|
+
>
|
|
502
|
+
<div>This content is visible to admins and editors</div>
|
|
503
|
+
</BridgeView>
|
|
504
|
+
```
|
|
505
|
+
|
|
506
|
+
### BridgeTable
|
|
507
|
+
|
|
508
|
+
The `BridgeTable` component displays data in a table with sorting, filtering, and pagination:
|
|
509
|
+
|
|
510
|
+
```jsx
|
|
511
|
+
import { BridgeTable } from '@pubflow/react';
|
|
512
|
+
|
|
513
|
+
<BridgeTable
|
|
514
|
+
columns={[
|
|
515
|
+
{ key: 'name', header: 'Name', sortable: true },
|
|
516
|
+
{ key: 'email', header: 'Email', sortable: true },
|
|
517
|
+
{ key: 'role', header: 'Role', sortable: true },
|
|
518
|
+
{
|
|
519
|
+
key: 'createdAt',
|
|
520
|
+
header: 'Created At',
|
|
521
|
+
cell: (item) => new Date(item.createdAt).toLocaleDateString(),
|
|
522
|
+
sortable: true
|
|
523
|
+
}
|
|
524
|
+
]}
|
|
525
|
+
entityConfig={{
|
|
526
|
+
endpoint: 'users'
|
|
527
|
+
}}
|
|
528
|
+
showSearch={true}
|
|
529
|
+
showPagination={true}
|
|
530
|
+
onRowClick={(user) => console.log('Selected user:', user)}
|
|
531
|
+
actions={(user) => (
|
|
532
|
+
<button onClick={() => handleDelete(user.id)}>Delete</button>
|
|
533
|
+
)}
|
|
534
|
+
/>
|
|
535
|
+
```
|
|
536
|
+
|
|
537
|
+
## License
|
|
538
|
+
|
|
539
|
+
AGPL-3.0-or-later
|