@ram_28/kf-ai-sdk 1.0.0 → 1.0.2
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 +363 -721
- package/dist/auth/AuthProvider.d.ts +5 -0
- package/dist/auth/AuthProvider.d.ts.map +1 -0
- package/dist/auth/authClient.d.ts +26 -0
- package/dist/auth/authClient.d.ts.map +1 -0
- package/dist/auth/authConfig.d.ts +38 -0
- package/dist/auth/authConfig.d.ts.map +1 -0
- package/dist/auth/index.d.ts +6 -0
- package/dist/auth/index.d.ts.map +1 -0
- package/dist/auth/types.d.ts +152 -0
- package/dist/auth/types.d.ts.map +1 -0
- package/dist/auth/useAuth.d.ts +27 -0
- package/dist/auth/useAuth.d.ts.map +1 -0
- package/dist/index.cjs +12 -12
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.mjs +1974 -1730
- package/package.json +1 -1
- package/sdk/auth/AuthProvider.tsx +271 -0
- package/sdk/auth/authClient.ts +127 -0
- package/sdk/auth/authConfig.ts +103 -0
- package/sdk/auth/index.ts +40 -0
- package/sdk/auth/types.ts +204 -0
- package/sdk/auth/useAuth.ts +67 -0
- package/sdk/index.ts +4 -1
package/README.md
CHANGED
|
@@ -1,839 +1,481 @@
|
|
|
1
|
-
#
|
|
1
|
+
# @ram_28/kf-ai-sdk
|
|
2
2
|
|
|
3
|
-
A
|
|
3
|
+
A type-safe SDK for building modern web applications with React hooks for forms, tables, kanban boards, and filtering.
|
|
4
4
|
|
|
5
|
-
##
|
|
5
|
+
## Installation
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
7
|
+
```bash
|
|
8
|
+
npm install @ram_28/kf-ai-sdk
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
**Peer Dependencies:**
|
|
12
|
+
```bash
|
|
13
|
+
npm install react @tanstack/react-query
|
|
14
|
+
```
|
|
12
15
|
|
|
13
|
-
|
|
14
|
-
- **Field-Level Control**: Editable, readable, and hidden field permissions per role
|
|
15
|
-
- **Compile-Time Safety**: TypeScript enforcement of permission boundaries
|
|
16
|
-
- **Dynamic UI**: Automatic form field disable/hide based on permissions
|
|
16
|
+
## Features
|
|
17
17
|
|
|
18
|
-
|
|
19
|
-
- **
|
|
20
|
-
- **
|
|
21
|
-
- **
|
|
22
|
-
- **
|
|
18
|
+
- **Authentication** - Cookie-based auth with AuthProvider and useAuth hook
|
|
19
|
+
- **useForm** - Dynamic schema-driven forms with backend validation
|
|
20
|
+
- **useTable** - Data tables with sorting, pagination, and React Query integration
|
|
21
|
+
- **useKanban** - Kanban board state management with drag-drop support
|
|
22
|
+
- **useFilter** - Advanced filtering with logical operators and payload builders
|
|
23
|
+
- **API Client** - Type-safe CRUD operations with structured filtering and sorting
|
|
24
|
+
- **Type System** - 11 semantic field types (IdField, StringField, CurrencyField, etc.)
|
|
25
|
+
- **Utilities** - Formatting helpers for currency, dates, numbers, and more
|
|
23
26
|
|
|
24
|
-
|
|
25
|
-
- **Complete BDO Example**: Full implementation of Amazon Product Master schema
|
|
26
|
-
- **Business Rules**: Auto-calculations, validation, and permission enforcement
|
|
27
|
-
- **Role-Based Views**: Admin, Seller, Buyer, InventoryManager, WarehouseStaff access levels
|
|
28
|
-
- **Real-World Example**: Production-ready e-commerce product management
|
|
27
|
+
## Quick Start
|
|
29
28
|
|
|
30
|
-
|
|
29
|
+
```tsx
|
|
30
|
+
import {
|
|
31
|
+
// Authentication
|
|
32
|
+
AuthProvider,
|
|
33
|
+
useAuth,
|
|
34
|
+
configureAuth,
|
|
35
|
+
|
|
36
|
+
// Hooks
|
|
37
|
+
useForm,
|
|
38
|
+
useTable,
|
|
39
|
+
useKanban,
|
|
40
|
+
useFilter,
|
|
41
|
+
|
|
42
|
+
// API
|
|
43
|
+
api,
|
|
44
|
+
setApiBaseUrl,
|
|
45
|
+
|
|
46
|
+
// Utilities
|
|
47
|
+
formatCurrency,
|
|
48
|
+
formatDate
|
|
49
|
+
} from '@ram_28/kf-ai-sdk';
|
|
50
|
+
|
|
51
|
+
// Configure API base URL
|
|
52
|
+
setApiBaseUrl('https://api.example.com');
|
|
53
|
+
```
|
|
31
54
|
|
|
32
|
-
|
|
33
|
-
- **[Quick Reference](./QUICK_REFERENCE.md)** - Developer cheat sheet and API reference
|
|
34
|
-
- **[Examples](./examples/)** - Real-world usage examples including Amazon Product demo
|
|
55
|
+
## Authentication
|
|
35
56
|
|
|
36
|
-
|
|
57
|
+
The SDK provides a complete authentication solution with cookie-based session management.
|
|
37
58
|
|
|
38
|
-
|
|
59
|
+
### Setup
|
|
39
60
|
|
|
40
|
-
|
|
61
|
+
Wrap your app with `AuthProvider` inside a `QueryClientProvider`:
|
|
41
62
|
|
|
42
|
-
|
|
63
|
+
```tsx
|
|
64
|
+
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
|
|
65
|
+
import { AuthProvider, setApiBaseUrl, configureAuth } from '@ram_28/kf-ai-sdk';
|
|
66
|
+
|
|
67
|
+
// Configure API
|
|
68
|
+
setApiBaseUrl('https://api.example.com');
|
|
69
|
+
|
|
70
|
+
// Optional: customize auth settings
|
|
71
|
+
configureAuth({
|
|
72
|
+
defaultProvider: 'google',
|
|
73
|
+
autoRedirect: true,
|
|
74
|
+
providers: {
|
|
75
|
+
google: {
|
|
76
|
+
loginPath: '/api/auth/google/login',
|
|
77
|
+
logoutPath: '/api/auth/logout',
|
|
78
|
+
},
|
|
79
|
+
},
|
|
80
|
+
});
|
|
43
81
|
|
|
44
|
-
|
|
45
|
-
- **API Client**: Runtime CRUD operations with structured filtering and sorting
|
|
46
|
-
- **Utilities**: Validation and formatting helpers
|
|
47
|
-
- **Components**: React hooks for forms and tables (Phase 2)
|
|
82
|
+
const queryClient = new QueryClient();
|
|
48
83
|
|
|
49
|
-
|
|
84
|
+
function App() {
|
|
85
|
+
return (
|
|
86
|
+
<QueryClientProvider client={queryClient}>
|
|
87
|
+
<AuthProvider
|
|
88
|
+
loadingComponent={<div>Loading...</div>}
|
|
89
|
+
onAuthChange={(status, user) => console.log('Auth:', status, user)}
|
|
90
|
+
>
|
|
91
|
+
<MyApp />
|
|
92
|
+
</AuthProvider>
|
|
93
|
+
</QueryClientProvider>
|
|
94
|
+
);
|
|
95
|
+
}
|
|
96
|
+
```
|
|
50
97
|
|
|
51
|
-
|
|
98
|
+
### useAuth Hook
|
|
52
99
|
|
|
53
|
-
|
|
54
|
-
- **Sources**: Business object definitions (Product, Order, etc.)
|
|
55
|
-
- **Role-based Access**: Type-safe field visibility per role
|
|
56
|
-
- **AI-readable Contracts**: Single source of truth for code generation
|
|
100
|
+
Access authentication state and operations in any component:
|
|
57
101
|
|
|
58
|
-
|
|
102
|
+
```tsx
|
|
103
|
+
import { useAuth } from '@ram_28/kf-ai-sdk';
|
|
59
104
|
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
├── sdk/ # Fixed SDK core
|
|
63
|
-
│ ├── types/ # Field types and common interfaces
|
|
64
|
-
│ ├── api/ # API client and utilities
|
|
65
|
-
│ ├── utils/ # Validation and formatting
|
|
66
|
-
│ └── index.ts # SDK exports
|
|
67
|
-
├── app/ # User-configurable layer
|
|
68
|
-
│ ├── types/roles.ts # Role definitions
|
|
69
|
-
│ ├── sources/ # Business objects
|
|
70
|
-
│ └── index.ts # App exports
|
|
71
|
-
├── config/ # Development configuration
|
|
72
|
-
└── examples/ # Usage examples
|
|
73
|
-
```
|
|
105
|
+
function UserMenu() {
|
|
106
|
+
const { user, isAuthenticated, isLoading, logout, hasRole } = useAuth();
|
|
74
107
|
|
|
75
|
-
|
|
108
|
+
if (isLoading) return <div>Loading...</div>;
|
|
109
|
+
if (!isAuthenticated) return null;
|
|
76
110
|
|
|
77
|
-
|
|
111
|
+
return (
|
|
112
|
+
<div>
|
|
113
|
+
<span>Welcome, {user._name}</span>
|
|
114
|
+
<span>Role: {user.Role}</span>
|
|
78
115
|
|
|
79
|
-
|
|
80
|
-
// 1. Import SDK core utilities
|
|
81
|
-
import { api, formatCurrency, isValidCurrencyField } from "./sdk";
|
|
116
|
+
{hasRole('Admin') && <a href="/admin">Admin Dashboard</a>}
|
|
82
117
|
|
|
83
|
-
|
|
84
|
-
|
|
118
|
+
<button onClick={() => logout({ redirectUrl: '/' })}>
|
|
119
|
+
Logout
|
|
120
|
+
</button>
|
|
121
|
+
</div>
|
|
122
|
+
);
|
|
123
|
+
}
|
|
124
|
+
```
|
|
85
125
|
|
|
86
|
-
|
|
87
|
-
const order = new Order(Roles.Admin);
|
|
88
|
-
const orderData = await order.list();
|
|
126
|
+
### useAuth Return Values
|
|
89
127
|
|
|
90
|
-
|
|
91
|
-
const
|
|
92
|
-
|
|
128
|
+
```tsx
|
|
129
|
+
const {
|
|
130
|
+
// User state
|
|
131
|
+
user, // UserDetails | null
|
|
132
|
+
staticBaseUrl, // string | null
|
|
133
|
+
buildId, // string | null
|
|
134
|
+
status, // 'loading' | 'authenticated' | 'unauthenticated'
|
|
135
|
+
isAuthenticated, // boolean
|
|
136
|
+
isLoading, // boolean
|
|
137
|
+
|
|
138
|
+
// Operations
|
|
139
|
+
login, // (provider?, options?) => void
|
|
140
|
+
logout, // (options?) => Promise<void>
|
|
141
|
+
refreshSession, // () => Promise<SessionResponse | null>
|
|
142
|
+
hasRole, // (role: string) => boolean
|
|
143
|
+
hasAnyRole, // (roles: string[]) => boolean
|
|
144
|
+
|
|
145
|
+
// Error handling
|
|
146
|
+
error, // Error | null
|
|
147
|
+
clearError, // () => void
|
|
148
|
+
} = useAuth();
|
|
149
|
+
```
|
|
93
150
|
|
|
94
|
-
|
|
95
|
-
// Type-safe order client with role-based access
|
|
96
|
-
const order = new Order(Roles.Admin);
|
|
151
|
+
### Multiple Auth Providers
|
|
97
152
|
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
source: "orders",
|
|
101
|
-
enableSorting: true,
|
|
102
|
-
enablePagination: true,
|
|
103
|
-
});
|
|
153
|
+
```tsx
|
|
154
|
+
import { useAuth } from '@ram_28/kf-ai-sdk';
|
|
104
155
|
|
|
105
|
-
|
|
106
|
-
const
|
|
107
|
-
source: "order-validation",
|
|
108
|
-
operation: "create",
|
|
109
|
-
onSuccess: () => table.refetch(),
|
|
110
|
-
});
|
|
156
|
+
function LoginPage() {
|
|
157
|
+
const { login } = useAuth();
|
|
111
158
|
|
|
112
159
|
return (
|
|
113
160
|
<div>
|
|
114
|
-
{
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
<button type="submit">Create Order</button>
|
|
121
|
-
</form>
|
|
122
|
-
|
|
123
|
-
{/* Orders Table */}
|
|
124
|
-
<table>
|
|
125
|
-
<thead>
|
|
126
|
-
<tr>
|
|
127
|
-
<th>ID</th>
|
|
128
|
-
<th>Customer</th>
|
|
129
|
-
<th>Amount</th>
|
|
130
|
-
<th>Profit Margin</th> {/* Admin can see profit margin */}
|
|
131
|
-
<th>Actions</th>
|
|
132
|
-
</tr>
|
|
133
|
-
</thead>
|
|
134
|
-
<tbody>
|
|
135
|
-
{table.rows.map((order: AdminOrder) => (
|
|
136
|
-
<tr key={order._id}>
|
|
137
|
-
<td>{order._id}</td>
|
|
138
|
-
<td>{order.customerId}</td>
|
|
139
|
-
<td>${order.totalAmount}</td>
|
|
140
|
-
<td>{order.profitMargin}%</td>{" "}
|
|
141
|
-
{/* TypeScript knows this exists for Admin */}
|
|
142
|
-
<td>
|
|
143
|
-
<button onClick={() => order.delete(order._id)}>Delete</button>
|
|
144
|
-
</td>
|
|
145
|
-
</tr>
|
|
146
|
-
))}
|
|
147
|
-
</tbody>
|
|
148
|
-
</table>
|
|
161
|
+
<button onClick={() => login('google')}>
|
|
162
|
+
Continue with Google
|
|
163
|
+
</button>
|
|
164
|
+
<button onClick={() => login('microsoft')}>
|
|
165
|
+
Continue with Microsoft
|
|
166
|
+
</button>
|
|
149
167
|
</div>
|
|
150
168
|
);
|
|
151
169
|
}
|
|
152
170
|
```
|
|
153
171
|
|
|
154
|
-
###
|
|
172
|
+
### Protected Routes
|
|
155
173
|
|
|
156
174
|
```tsx
|
|
157
|
-
|
|
158
|
-
import {
|
|
175
|
+
import { useAuth } from '@ram_28/kf-ai-sdk';
|
|
176
|
+
import { Navigate } from 'react-router-dom';
|
|
177
|
+
|
|
178
|
+
function ProtectedRoute({ children, requiredRoles }) {
|
|
179
|
+
const { isAuthenticated, isLoading, hasAnyRole } = useAuth();
|
|
180
|
+
|
|
181
|
+
if (isLoading) return <div>Loading...</div>;
|
|
182
|
+
if (!isAuthenticated) return <Navigate to="/login" />;
|
|
183
|
+
if (requiredRoles && !hasAnyRole(requiredRoles)) {
|
|
184
|
+
return <Navigate to="/unauthorized" />;
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
return children;
|
|
188
|
+
}
|
|
159
189
|
|
|
160
|
-
|
|
161
|
-
|
|
190
|
+
// Usage
|
|
191
|
+
<ProtectedRoute requiredRoles={['Admin', 'Manager']}>
|
|
192
|
+
<AdminDashboard />
|
|
193
|
+
</ProtectedRoute>
|
|
194
|
+
```
|
|
195
|
+
|
|
196
|
+
## Hooks
|
|
197
|
+
|
|
198
|
+
### useTable
|
|
199
|
+
|
|
200
|
+
Data table hook with sorting, pagination, and React Query integration.
|
|
201
|
+
|
|
202
|
+
```tsx
|
|
203
|
+
import { useTable } from '@ram_28/kf-ai-sdk';
|
|
162
204
|
|
|
163
|
-
|
|
164
|
-
|
|
205
|
+
function ProductTable() {
|
|
206
|
+
const table = useTable({
|
|
207
|
+
source: 'products',
|
|
165
208
|
enableSorting: true,
|
|
209
|
+
enablePagination: true,
|
|
210
|
+
pageSize: 25,
|
|
166
211
|
});
|
|
167
212
|
|
|
168
213
|
return (
|
|
169
214
|
<table>
|
|
170
215
|
<thead>
|
|
171
216
|
<tr>
|
|
172
|
-
<th>
|
|
173
|
-
<th>
|
|
174
|
-
<th>Amount</th>
|
|
175
|
-
{/* <th>Profit Margin</th> */} {/* User cannot see profit margin */}
|
|
217
|
+
<th onClick={() => table.toggleSort('name')}>Name</th>
|
|
218
|
+
<th onClick={() => table.toggleSort('price')}>Price</th>
|
|
176
219
|
</tr>
|
|
177
220
|
</thead>
|
|
178
221
|
<tbody>
|
|
179
|
-
{table.rows.map((
|
|
180
|
-
<tr key={
|
|
181
|
-
<td>{
|
|
182
|
-
<td
|
|
183
|
-
<td>${order.totalAmount}</td>
|
|
184
|
-
{/* <td>{order.profitMargin}%</td> */}{" "}
|
|
185
|
-
{/* ❌ TypeScript Error: Property doesn't exist */}
|
|
222
|
+
{table.rows.map((product) => (
|
|
223
|
+
<tr key={product._id}>
|
|
224
|
+
<td>{product.name}</td>
|
|
225
|
+
<td>${product.price}</td>
|
|
186
226
|
</tr>
|
|
187
227
|
))}
|
|
188
228
|
</tbody>
|
|
229
|
+
<tfoot>
|
|
230
|
+
<button onClick={table.previousPage} disabled={!table.hasPreviousPage}>
|
|
231
|
+
Previous
|
|
232
|
+
</button>
|
|
233
|
+
<span>Page {table.currentPage}</span>
|
|
234
|
+
<button onClick={table.nextPage} disabled={!table.hasNextPage}>
|
|
235
|
+
Next
|
|
236
|
+
</button>
|
|
237
|
+
</tfoot>
|
|
189
238
|
</table>
|
|
190
239
|
);
|
|
191
240
|
}
|
|
192
241
|
```
|
|
193
242
|
|
|
194
|
-
###
|
|
243
|
+
### useForm
|
|
244
|
+
|
|
245
|
+
Schema-driven form hook with backend validation support.
|
|
195
246
|
|
|
196
247
|
```tsx
|
|
197
|
-
import {
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
_id: "ORDER_456", // Optional custom ID
|
|
207
|
-
customerId: "CUST_001",
|
|
208
|
-
totalAmount: 299.99,
|
|
209
|
-
status: "pending",
|
|
248
|
+
import { useForm } from '@ram_28/kf-ai-sdk';
|
|
249
|
+
|
|
250
|
+
function ProductForm() {
|
|
251
|
+
const form = useForm({
|
|
252
|
+
source: 'products',
|
|
253
|
+
operation: 'create',
|
|
254
|
+
onSuccess: (data) => {
|
|
255
|
+
console.log('Created:', data);
|
|
256
|
+
},
|
|
210
257
|
});
|
|
211
|
-
console.log(createResponse._id); // "ORDER_456"
|
|
212
258
|
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
});
|
|
259
|
+
return (
|
|
260
|
+
<form onSubmit={form.handleSubmit()}>
|
|
261
|
+
<input {...form.register('name')} placeholder="Product Name" />
|
|
262
|
+
{form.errors.name && <span>{form.errors.name.message}</span>}
|
|
218
263
|
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
console.log(deleteResponse.status); // "success"
|
|
264
|
+
<input {...form.register('price')} type="number" placeholder="Price" />
|
|
265
|
+
{form.errors.price && <span>{form.errors.price.message}</span>}
|
|
222
266
|
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
{
|
|
229
|
-
Operator: "EQ",
|
|
230
|
-
LHSField: "status",
|
|
231
|
-
RHSValue: "pending"
|
|
232
|
-
},
|
|
233
|
-
{
|
|
234
|
-
Operator: "GTE",
|
|
235
|
-
LHSField: "totalAmount",
|
|
236
|
-
RHSValue: 100
|
|
237
|
-
}
|
|
238
|
-
]
|
|
239
|
-
},
|
|
240
|
-
Sort: [
|
|
241
|
-
{ Field: "_created_at", Order: "DESC" },
|
|
242
|
-
{ Field: "totalAmount", Order: "ASC" }
|
|
243
|
-
],
|
|
244
|
-
Page: 1,
|
|
245
|
-
PageSize: 50
|
|
246
|
-
});
|
|
267
|
+
<button type="submit" disabled={form.isSubmitting}>
|
|
268
|
+
{form.isSubmitting ? 'Creating...' : 'Create Product'}
|
|
269
|
+
</button>
|
|
270
|
+
</form>
|
|
271
|
+
);
|
|
247
272
|
}
|
|
248
273
|
```
|
|
249
274
|
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
The KF AI SDK supports comprehensive filtering and sorting through the Runtime API. Here are detailed examples using both Order and Product models:
|
|
275
|
+
### useKanban
|
|
253
276
|
|
|
254
|
-
|
|
277
|
+
Kanban board state management with drag-drop support.
|
|
255
278
|
|
|
256
279
|
```tsx
|
|
257
|
-
import {
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
const
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
{
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
]
|
|
270
|
-
}
|
|
271
|
-
});
|
|
272
|
-
|
|
273
|
-
// Numeric range filter
|
|
274
|
-
const highValueOrders = await new Order(Roles.Admin).list({
|
|
275
|
-
Filter: {
|
|
276
|
-
Operator: "AND",
|
|
277
|
-
Condition: [
|
|
278
|
-
{
|
|
279
|
-
Operator: "GTE",
|
|
280
|
-
LHSField: "totalAmount",
|
|
281
|
-
RHSValue: 500
|
|
282
|
-
}
|
|
283
|
-
]
|
|
284
|
-
}
|
|
285
|
-
});
|
|
280
|
+
import { useKanban, Kanban, KanbanColumn, KanbanCard } from '@ram_28/kf-ai-sdk';
|
|
281
|
+
|
|
282
|
+
function TaskBoard() {
|
|
283
|
+
const kanban = useKanban({
|
|
284
|
+
source: 'tasks',
|
|
285
|
+
groupByField: 'status',
|
|
286
|
+
columns: [
|
|
287
|
+
{ id: 'todo', title: 'To Do' },
|
|
288
|
+
{ id: 'in-progress', title: 'In Progress' },
|
|
289
|
+
{ id: 'done', title: 'Done' },
|
|
290
|
+
],
|
|
291
|
+
});
|
|
286
292
|
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
293
|
+
return (
|
|
294
|
+
<Kanban>
|
|
295
|
+
{kanban.columns.map((column) => (
|
|
296
|
+
<KanbanColumn key={column.id} column={column}>
|
|
297
|
+
{column.cards.map((card) => (
|
|
298
|
+
<KanbanCard key={card.id} card={card}>
|
|
299
|
+
{card.title}
|
|
300
|
+
</KanbanCard>
|
|
301
|
+
))}
|
|
302
|
+
</KanbanColumn>
|
|
303
|
+
))}
|
|
304
|
+
</Kanban>
|
|
305
|
+
);
|
|
306
|
+
}
|
|
300
307
|
```
|
|
301
308
|
|
|
302
|
-
###
|
|
303
|
-
|
|
304
|
-
```tsx
|
|
305
|
-
// AND conditions - all must be true
|
|
306
|
-
const premiumCompletedOrders = await new Order(Roles.Admin).list({
|
|
307
|
-
Filter: {
|
|
308
|
-
Operator: "AND",
|
|
309
|
-
Condition: [
|
|
310
|
-
{
|
|
311
|
-
Operator: "EQ",
|
|
312
|
-
LHSField: "status",
|
|
313
|
-
RHSValue: "completed"
|
|
314
|
-
},
|
|
315
|
-
{
|
|
316
|
-
Operator: "GTE",
|
|
317
|
-
LHSField: "totalAmount",
|
|
318
|
-
RHSValue: 1000
|
|
319
|
-
},
|
|
320
|
-
{
|
|
321
|
-
Operator: "GTE",
|
|
322
|
-
LHSField: "profitMargin",
|
|
323
|
-
RHSValue: 20
|
|
324
|
-
}
|
|
325
|
-
]
|
|
326
|
-
}
|
|
327
|
-
});
|
|
328
|
-
|
|
329
|
-
// OR conditions - any can be true
|
|
330
|
-
const urgentOrders = await new Order(Roles.Admin).list({
|
|
331
|
-
Filter: {
|
|
332
|
-
Operator: "OR",
|
|
333
|
-
Condition: [
|
|
334
|
-
{
|
|
335
|
-
Operator: "EQ",
|
|
336
|
-
LHSField: "status",
|
|
337
|
-
RHSValue: "pending"
|
|
338
|
-
},
|
|
339
|
-
{
|
|
340
|
-
Operator: "EQ",
|
|
341
|
-
LHSField: "status",
|
|
342
|
-
RHSValue: "processing"
|
|
343
|
-
}
|
|
344
|
-
]
|
|
345
|
-
}
|
|
346
|
-
});
|
|
347
|
-
|
|
348
|
-
// Nested AND/OR conditions
|
|
349
|
-
const complexProductFilter = await new Product(Roles.Admin).list({
|
|
350
|
-
Filter: {
|
|
351
|
-
Operator: "AND",
|
|
352
|
-
Condition: [
|
|
353
|
-
{
|
|
354
|
-
Operator: "EQ",
|
|
355
|
-
LHSField: "inStock",
|
|
356
|
-
RHSValue: true
|
|
357
|
-
},
|
|
358
|
-
{
|
|
359
|
-
Operator: "OR",
|
|
360
|
-
Condition: [
|
|
361
|
-
{
|
|
362
|
-
Operator: "EQ",
|
|
363
|
-
LHSField: "category",
|
|
364
|
-
RHSValue: "electronics"
|
|
365
|
-
},
|
|
366
|
-
{
|
|
367
|
-
Operator: "EQ",
|
|
368
|
-
LHSField: "category",
|
|
369
|
-
RHSValue: "clothing"
|
|
370
|
-
}
|
|
371
|
-
]
|
|
372
|
-
},
|
|
373
|
-
{
|
|
374
|
-
Operator: "Between",
|
|
375
|
-
LHSField: "price",
|
|
376
|
-
RHSValue: [50, 500]
|
|
377
|
-
}
|
|
378
|
-
]
|
|
379
|
-
}
|
|
380
|
-
});
|
|
381
|
-
```
|
|
309
|
+
### useFilter
|
|
382
310
|
|
|
383
|
-
|
|
311
|
+
Advanced filtering with logical operators.
|
|
384
312
|
|
|
385
313
|
```tsx
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
{
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
]
|
|
397
|
-
}
|
|
398
|
-
});
|
|
399
|
-
|
|
400
|
-
// List membership
|
|
401
|
-
const specificCategories = await new Product(Roles.Admin).list({
|
|
402
|
-
Filter: {
|
|
403
|
-
Operator: "AND",
|
|
404
|
-
Condition: [
|
|
405
|
-
{
|
|
406
|
-
Operator: "IN",
|
|
407
|
-
LHSField: "category",
|
|
408
|
-
RHSValue: ["electronics", "books", "sports"]
|
|
409
|
-
}
|
|
410
|
-
]
|
|
411
|
-
}
|
|
412
|
-
});
|
|
413
|
-
|
|
414
|
-
// Exclusion filters
|
|
415
|
-
const nonCancelledOrders = await new Order(Roles.Admin).list({
|
|
416
|
-
Filter: {
|
|
417
|
-
Operator: "AND",
|
|
418
|
-
Condition: [
|
|
419
|
-
{
|
|
420
|
-
Operator: "NE",
|
|
421
|
-
LHSField: "status",
|
|
422
|
-
RHSValue: "cancelled"
|
|
423
|
-
}
|
|
424
|
-
]
|
|
425
|
-
}
|
|
426
|
-
});
|
|
427
|
-
|
|
428
|
-
// Empty/Non-empty checks
|
|
429
|
-
const ordersWithNotes = await new Order(Roles.Admin).list({
|
|
430
|
-
Filter: {
|
|
431
|
-
Operator: "AND",
|
|
432
|
-
Condition: [
|
|
433
|
-
{
|
|
434
|
-
Operator: "NotEmpty",
|
|
435
|
-
LHSField: "internalNotes"
|
|
436
|
-
}
|
|
437
|
-
]
|
|
438
|
-
}
|
|
439
|
-
});
|
|
440
|
-
|
|
441
|
-
// String length validation
|
|
442
|
-
const detailedProducts = await new Product(Roles.Admin).list({
|
|
443
|
-
Filter: {
|
|
444
|
-
Operator: "AND",
|
|
445
|
-
Condition: [
|
|
446
|
-
{
|
|
447
|
-
Operator: "MinLength",
|
|
448
|
-
LHSField: "description",
|
|
449
|
-
RHSValue: 50
|
|
450
|
-
}
|
|
451
|
-
]
|
|
452
|
-
}
|
|
453
|
-
});
|
|
454
|
-
```
|
|
455
|
-
|
|
456
|
-
### Comprehensive Sorting Examples
|
|
457
|
-
|
|
458
|
-
```tsx
|
|
459
|
-
// Single field sorting
|
|
460
|
-
const ordersByDate = await new Order(Roles.Admin).list({
|
|
461
|
-
Sort: [
|
|
462
|
-
{ Field: "_created_at", Order: "DESC" }
|
|
463
|
-
]
|
|
464
|
-
});
|
|
314
|
+
import { useFilter, buildFilterPayload } from '@ram_28/kf-ai-sdk';
|
|
315
|
+
|
|
316
|
+
function ProductFilter() {
|
|
317
|
+
const filter = useFilter({
|
|
318
|
+
fields: {
|
|
319
|
+
name: { type: 'string' },
|
|
320
|
+
price: { type: 'number' },
|
|
321
|
+
category: { type: 'select', options: ['electronics', 'clothing', 'books'] },
|
|
322
|
+
},
|
|
323
|
+
});
|
|
465
324
|
|
|
466
|
-
|
|
467
|
-
const
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
{ Field: "price", Order: "DESC" }, // Then by price (high to low)
|
|
471
|
-
{ Field: "name", Order: "ASC" } // Finally by name
|
|
472
|
-
]
|
|
473
|
-
});
|
|
325
|
+
const handleApply = () => {
|
|
326
|
+
const payload = buildFilterPayload(filter.conditions);
|
|
327
|
+
// Use payload with API
|
|
328
|
+
};
|
|
474
329
|
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
{
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
LHSField: "price",
|
|
488
|
-
RHSValue: 100
|
|
489
|
-
}
|
|
490
|
-
]
|
|
491
|
-
},
|
|
492
|
-
Sort: [
|
|
493
|
-
{ Field: "margin", Order: "DESC" },
|
|
494
|
-
{ Field: "price", Order: "ASC" }
|
|
495
|
-
]
|
|
496
|
-
});
|
|
330
|
+
return (
|
|
331
|
+
<div>
|
|
332
|
+
<button onClick={() => filter.addCondition('name', 'contains', '')}>
|
|
333
|
+
Add Name Filter
|
|
334
|
+
</button>
|
|
335
|
+
<button onClick={() => filter.addCondition('price', 'gte', 0)}>
|
|
336
|
+
Add Price Filter
|
|
337
|
+
</button>
|
|
338
|
+
<button onClick={handleApply}>Apply Filters</button>
|
|
339
|
+
</div>
|
|
340
|
+
);
|
|
341
|
+
}
|
|
497
342
|
```
|
|
498
343
|
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
```tsx
|
|
502
|
-
// Complete query with all features
|
|
503
|
-
const paginatedResults = await new Order(Roles.Admin).list({
|
|
504
|
-
// Complex filtering
|
|
505
|
-
Filter: {
|
|
506
|
-
Operator: "AND",
|
|
507
|
-
Condition: [
|
|
508
|
-
{
|
|
509
|
-
Operator: "GTE",
|
|
510
|
-
LHSField: "totalAmount",
|
|
511
|
-
RHSValue: 200
|
|
512
|
-
},
|
|
513
|
-
{
|
|
514
|
-
Operator: "OR",
|
|
515
|
-
Condition: [
|
|
516
|
-
{
|
|
517
|
-
Operator: "EQ",
|
|
518
|
-
LHSField: "status",
|
|
519
|
-
RHSValue: "completed"
|
|
520
|
-
},
|
|
521
|
-
{
|
|
522
|
-
Operator: "EQ",
|
|
523
|
-
LHSField: "status",
|
|
524
|
-
RHSValue: "pending"
|
|
525
|
-
}
|
|
526
|
-
]
|
|
527
|
-
}
|
|
528
|
-
]
|
|
529
|
-
},
|
|
530
|
-
// Multi-field sorting
|
|
531
|
-
Sort: [
|
|
532
|
-
{ Field: "totalAmount", Order: "DESC" },
|
|
533
|
-
{ Field: "_created_at", Order: "DESC" }
|
|
534
|
-
],
|
|
535
|
-
// Pagination
|
|
536
|
-
Page: 1,
|
|
537
|
-
PageSize: 25,
|
|
538
|
-
// Specific fields only (optional)
|
|
539
|
-
Field: ["_id", "customerId", "totalAmount", "status", "_created_at"]
|
|
540
|
-
});
|
|
541
|
-
|
|
542
|
-
// Process results
|
|
543
|
-
console.log(`Found ${paginatedResults.Data.length} orders`);
|
|
544
|
-
paginatedResults.Data.forEach(order => {
|
|
545
|
-
console.log(`Order ${order._id}: $${order.totalAmount} - ${order.status}`);
|
|
546
|
-
});
|
|
547
|
-
```
|
|
344
|
+
## API Client
|
|
548
345
|
|
|
549
|
-
|
|
346
|
+
Type-safe API client for CRUD operations.
|
|
550
347
|
|
|
551
348
|
```tsx
|
|
552
|
-
|
|
553
|
-
const adminProductAnalysis = await new Product(Roles.Admin).list({
|
|
554
|
-
Filter: {
|
|
555
|
-
Operator: "AND",
|
|
556
|
-
Condition: [
|
|
557
|
-
{
|
|
558
|
-
Operator: "GTE",
|
|
559
|
-
LHSField: "margin", // Admin-only field
|
|
560
|
-
RHSValue: 25
|
|
561
|
-
},
|
|
562
|
-
{
|
|
563
|
-
Operator: "Contains",
|
|
564
|
-
LHSField: "supplier", // Admin-only field
|
|
565
|
-
RHSValue: "Premium"
|
|
566
|
-
}
|
|
567
|
-
]
|
|
568
|
-
},
|
|
569
|
-
Sort: [
|
|
570
|
-
{ Field: "margin", Order: "DESC" },
|
|
571
|
-
{ Field: "cost", Order: "ASC" } // Admin-only field
|
|
572
|
-
]
|
|
573
|
-
});
|
|
574
|
-
|
|
575
|
-
// User sees limited data and can only filter on public fields
|
|
576
|
-
const userProducts = await new Product(Roles.User).list({
|
|
577
|
-
Filter: {
|
|
578
|
-
Operator: "AND",
|
|
579
|
-
Condition: [
|
|
580
|
-
{
|
|
581
|
-
Operator: "EQ",
|
|
582
|
-
LHSField: "category", // Public field
|
|
583
|
-
RHSValue: "electronics"
|
|
584
|
-
},
|
|
585
|
-
{
|
|
586
|
-
Operator: "EQ",
|
|
587
|
-
LHSField: "inStock", // Public field
|
|
588
|
-
RHSValue: true
|
|
589
|
-
}
|
|
590
|
-
]
|
|
591
|
-
},
|
|
592
|
-
Sort: [
|
|
593
|
-
{ Field: "price", Order: "ASC" }, // Public field
|
|
594
|
-
{ Field: "name", Order: "ASC" } // Public field
|
|
595
|
-
]
|
|
596
|
-
});
|
|
349
|
+
import { api, setApiBaseUrl } from '@ram_28/kf-ai-sdk';
|
|
597
350
|
|
|
598
|
-
//
|
|
599
|
-
|
|
351
|
+
// Configure base URL
|
|
352
|
+
setApiBaseUrl('https://api.example.com');
|
|
600
353
|
|
|
601
|
-
|
|
354
|
+
// CRUD Operations
|
|
355
|
+
async function productOperations() {
|
|
356
|
+
// Get single record
|
|
357
|
+
const product = await api('products').get('PROD_123');
|
|
602
358
|
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
LHSField: "inStock",
|
|
610
|
-
RHSValue: true
|
|
611
|
-
}
|
|
612
|
-
];
|
|
613
|
-
|
|
614
|
-
if (searchTerm) {
|
|
615
|
-
conditions.push({
|
|
616
|
-
Operator: "Contains" as const,
|
|
617
|
-
LHSField: "name",
|
|
618
|
-
RHSValue: searchTerm
|
|
619
|
-
});
|
|
620
|
-
}
|
|
359
|
+
// Create record
|
|
360
|
+
const created = await api('products').create({
|
|
361
|
+
name: 'New Product',
|
|
362
|
+
price: 99.99,
|
|
363
|
+
category: 'electronics',
|
|
364
|
+
});
|
|
621
365
|
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
RHSValue: category
|
|
627
|
-
});
|
|
628
|
-
}
|
|
366
|
+
// Update record
|
|
367
|
+
const updated = await api('products').update('PROD_123', {
|
|
368
|
+
price: 89.99,
|
|
369
|
+
});
|
|
629
370
|
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
Operator: "LTE" as const,
|
|
633
|
-
LHSField: "price",
|
|
634
|
-
RHSValue: maxPrice
|
|
635
|
-
});
|
|
636
|
-
}
|
|
371
|
+
// Delete record
|
|
372
|
+
await api('products').delete('PROD_123');
|
|
637
373
|
|
|
638
|
-
|
|
374
|
+
// List with filtering and sorting
|
|
375
|
+
const products = await api('products').list({
|
|
639
376
|
Filter: {
|
|
640
|
-
Operator:
|
|
641
|
-
Condition:
|
|
377
|
+
Operator: 'AND',
|
|
378
|
+
Condition: [
|
|
379
|
+
{ Operator: 'EQ', LHSField: 'category', RHSValue: 'electronics' },
|
|
380
|
+
{ Operator: 'GTE', LHSField: 'price', RHSValue: 50 },
|
|
381
|
+
],
|
|
642
382
|
},
|
|
643
383
|
Sort: [
|
|
644
|
-
{ Field:
|
|
384
|
+
{ Field: 'price', Order: 'DESC' },
|
|
645
385
|
],
|
|
646
|
-
|
|
386
|
+
Page: 1,
|
|
387
|
+
PageSize: 25,
|
|
647
388
|
});
|
|
648
|
-
}
|
|
649
|
-
|
|
650
|
-
// Order dashboard with filters
|
|
651
|
-
async function getOrderDashboard(dateRange: { start: string, end: string }, minAmount?: number) {
|
|
652
|
-
const conditions = [
|
|
653
|
-
{
|
|
654
|
-
Operator: "Between" as const,
|
|
655
|
-
LHSField: "_created_at",
|
|
656
|
-
RHSValue: [dateRange.start, dateRange.end]
|
|
657
|
-
}
|
|
658
|
-
];
|
|
659
|
-
|
|
660
|
-
if (minAmount) {
|
|
661
|
-
conditions.push({
|
|
662
|
-
Operator: "GTE" as const,
|
|
663
|
-
LHSField: "totalAmount",
|
|
664
|
-
RHSValue: minAmount
|
|
665
|
-
});
|
|
666
|
-
}
|
|
667
389
|
|
|
668
|
-
|
|
390
|
+
// Count records
|
|
391
|
+
const count = await api('products').count({
|
|
669
392
|
Filter: {
|
|
670
|
-
Operator:
|
|
671
|
-
Condition:
|
|
393
|
+
Operator: 'AND',
|
|
394
|
+
Condition: [
|
|
395
|
+
{ Operator: 'EQ', LHSField: 'inStock', RHSValue: true },
|
|
396
|
+
],
|
|
672
397
|
},
|
|
673
|
-
Sort: [
|
|
674
|
-
{ Field: "totalAmount", Order: "DESC" },
|
|
675
|
-
{ Field: "_created_at", Order: "DESC" }
|
|
676
|
-
],
|
|
677
|
-
PageSize: 50
|
|
678
398
|
});
|
|
679
399
|
}
|
|
680
400
|
```
|
|
681
401
|
|
|
682
|
-
##
|
|
683
|
-
|
|
684
|
-
## Development Setup
|
|
402
|
+
## Type System
|
|
685
403
|
|
|
686
|
-
|
|
687
|
-
- Node.js 18+
|
|
688
|
-
- npm or yarn
|
|
404
|
+
The SDK provides semantic field types for type-safe data modeling:
|
|
689
405
|
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
406
|
+
```tsx
|
|
407
|
+
import type {
|
|
408
|
+
IdField,
|
|
409
|
+
StringField,
|
|
410
|
+
TextAreaField,
|
|
411
|
+
NumberField,
|
|
412
|
+
BooleanField,
|
|
413
|
+
DateField,
|
|
414
|
+
DateTimeField,
|
|
415
|
+
CurrencyField,
|
|
416
|
+
PercentageField,
|
|
417
|
+
SelectField,
|
|
418
|
+
} from '@ram_28/kf-ai-sdk';
|
|
419
|
+
|
|
420
|
+
// Define your data types
|
|
421
|
+
interface Product {
|
|
422
|
+
_id: IdField;
|
|
423
|
+
name: StringField<string>;
|
|
424
|
+
description: TextAreaField;
|
|
425
|
+
price: CurrencyField;
|
|
426
|
+
quantity: NumberField<0>;
|
|
427
|
+
inStock: BooleanField;
|
|
428
|
+
category: SelectField<'electronics' | 'clothing' | 'books'>;
|
|
429
|
+
createdAt: DateTimeField;
|
|
430
|
+
}
|
|
711
431
|
```
|
|
712
432
|
|
|
713
|
-
|
|
714
|
-
The SDK uses configuration files in the `config/` directory:
|
|
715
|
-
- `tsconfig.json` - TypeScript configuration with path mapping
|
|
716
|
-
- `vite.config.js` - Build and development server config
|
|
717
|
-
- `eslint.config.js` - Code linting rules
|
|
718
|
-
- `prettier.config.js` - Code formatting rules
|
|
719
|
-
|
|
720
|
-
### Layer Documentation
|
|
721
|
-
|
|
722
|
-
- **[SDK Core](docs/sdk-core.md)** - Field types, API client, and utilities
|
|
723
|
-
- **[App Layer](docs/app-layer.md)** - Roles and business object creation
|
|
724
|
-
- **[Examples](docs/examples.md)** - Usage patterns and best practices
|
|
725
|
-
|
|
726
|
-
### Migration Guide
|
|
727
|
-
|
|
728
|
-
- **[Migration Guide](MIGRATION.md)** - Upgrading from the previous structure
|
|
729
|
-
|
|
730
|
-
## Features
|
|
731
|
-
|
|
732
|
-
### SDK Core (`sdk/`)
|
|
733
|
-
|
|
734
|
-
- ✅ **Field Type System** - 11 Backend BO field types with semantic meaning
|
|
735
|
-
- ✅ **Runtime API Client** - Full CRUD operations with structured filtering
|
|
736
|
-
- ✅ **Datetime Handling** - Automatic encoding/decoding of API formats
|
|
737
|
-
- ✅ **Validation Utilities** - Runtime type checking and field validation
|
|
738
|
-
- ✅ **Formatting Helpers** - Display formatting for all field types
|
|
739
|
-
- ✅ **TypeScript Support** - Full type safety across all operations
|
|
740
|
-
|
|
741
|
-
### App Layer (`app/`)
|
|
742
|
-
|
|
743
|
-
- ✅ **Role-Based Access Control** - Compile-time enforcement of field visibility
|
|
744
|
-
- ✅ **AI Code Generation** - Single source of truth for AI-readable contracts
|
|
745
|
-
- ✅ **Dynamic Business Objects** - User-configurable source definitions
|
|
746
|
-
- ✅ **Custom Role System** - User-defined role hierarchies
|
|
747
|
-
- ✅ **Type Safety** - TypeScript validation of all generated code
|
|
748
|
-
- ✅ **Single File Per Source** - All logic for a data model in one place
|
|
749
|
-
|
|
750
|
-
### Development Experience
|
|
751
|
-
|
|
752
|
-
- ✅ **Modern Build Tools** - Vite, TypeScript, ESLint, Prettier
|
|
753
|
-
- ✅ **Path Mapping** - Clean imports with `@sdk/` and `@app/` aliases
|
|
754
|
-
- ✅ **Hot Reload** - Fast development with instant feedback
|
|
755
|
-
- ✅ **Type Checking** - Comprehensive TypeScript validation
|
|
756
|
-
- ✅ **Code Quality** - Automated linting and formatting
|
|
757
|
-
|
|
758
|
-
## Key Benefits
|
|
759
|
-
|
|
760
|
-
### For AI Code Generation
|
|
761
|
-
|
|
762
|
-
- **Single Source of Truth**: App layer provides all type definitions in one place
|
|
763
|
-
- **Role Awareness**: AI generates code that respects user permissions
|
|
764
|
-
- **Type Safety**: Any TypeScript error indicates incorrect AI generation
|
|
765
|
-
- **Self-Documenting**: Type definitions serve as API documentation
|
|
766
|
-
|
|
767
|
-
### For Developers
|
|
433
|
+
## Utilities
|
|
768
434
|
|
|
769
|
-
|
|
770
|
-
- **Role-Based Security**: Compile-time enforcement of data access
|
|
771
|
-
- **Modern React**: Hooks, React Query, and TypeScript throughout
|
|
772
|
-
- **Extensible**: Easy to add new data sources and roles
|
|
435
|
+
### Formatting
|
|
773
436
|
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
437
|
+
```tsx
|
|
438
|
+
import {
|
|
439
|
+
formatCurrency,
|
|
440
|
+
formatDate,
|
|
441
|
+
formatDateTime,
|
|
442
|
+
formatNumber,
|
|
443
|
+
formatPercentage
|
|
444
|
+
} from '@ram_28/kf-ai-sdk';
|
|
445
|
+
|
|
446
|
+
formatCurrency(99.99); // "$99.99"
|
|
447
|
+
formatDate(new Date()); // "Jan 11, 2024"
|
|
448
|
+
formatDateTime(new Date()); // "Jan 11, 2024, 10:30 AM"
|
|
449
|
+
formatNumber(1234.56, 2); // "1,234.56"
|
|
450
|
+
formatPercentage(0.156); // "15.6%"
|
|
451
|
+
```
|
|
782
452
|
|
|
783
|
-
|
|
453
|
+
### Class Names
|
|
784
454
|
|
|
785
455
|
```tsx
|
|
786
|
-
import {
|
|
787
|
-
import { useTable, useForm } from "@ram_28/kf-ai-sdk";
|
|
456
|
+
import { cn } from '@ram_28/kf-ai-sdk';
|
|
788
457
|
|
|
789
|
-
//
|
|
790
|
-
|
|
791
|
-
|
|
458
|
+
// Merge Tailwind classes with conflict resolution
|
|
459
|
+
cn('px-4 py-2', 'px-6'); // "py-2 px-6"
|
|
460
|
+
cn('text-red-500', condition && 'text-blue-500');
|
|
461
|
+
```
|
|
792
462
|
|
|
793
|
-
|
|
794
|
-
source: "orders",
|
|
795
|
-
enableSorting: true,
|
|
796
|
-
});
|
|
463
|
+
## Documentation
|
|
797
464
|
|
|
798
|
-
|
|
799
|
-
<table>
|
|
800
|
-
<thead>
|
|
801
|
-
<tr>
|
|
802
|
-
<th>ID</th>
|
|
803
|
-
<th>Customer</th>
|
|
804
|
-
<th>Total Amount</th> {/* Admin can see financial data */}
|
|
805
|
-
<th>Profit Margin</th> {/* Admin can see profit */}
|
|
806
|
-
<th>Internal Notes</th> {/* Admin can see internal notes */}
|
|
807
|
-
</tr>
|
|
808
|
-
</thead>
|
|
809
|
-
<tbody>
|
|
810
|
-
{table.rows.map((order: AdminOrder) => (
|
|
811
|
-
<tr key={order._id}>
|
|
812
|
-
<td>{order._id}</td>
|
|
813
|
-
<td>{order.customerId}</td>
|
|
814
|
-
<td>${order.totalAmount}</td>{" "}
|
|
815
|
-
{/* ✅ TypeScript knows this exists */}
|
|
816
|
-
<td>{order.profitMargin}%</td> {/* ✅ TypeScript knows this exists */}
|
|
817
|
-
<td>{order.internalNotes}</td>{" "}
|
|
818
|
-
{/* ✅ TypeScript knows this exists */}
|
|
819
|
-
</tr>
|
|
820
|
-
))}
|
|
821
|
-
</tbody>
|
|
822
|
-
</table>
|
|
823
|
-
);
|
|
824
|
-
}
|
|
465
|
+
Detailed documentation for each feature:
|
|
825
466
|
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
467
|
+
- [Authentication Documentation](./docs/useAuth.md)
|
|
468
|
+
- [useForm Documentation](./docs/useForm.md)
|
|
469
|
+
- [useTable Documentation](./docs/useTable.md)
|
|
470
|
+
- [useKanban Documentation](./docs/useKanban.md)
|
|
471
|
+
- [useFilter Documentation](./docs/useFilter.md)
|
|
472
|
+
- [Quick Reference](./docs/QUICK_REFERENCE.md)
|
|
830
473
|
|
|
831
|
-
|
|
832
|
-
// Property 'profitMargin' does not exist on type 'UserOrder'
|
|
833
|
-
}
|
|
834
|
-
```
|
|
474
|
+
## Requirements
|
|
835
475
|
|
|
836
|
-
|
|
476
|
+
- Node.js >= 18.0.0
|
|
477
|
+
- React >= 16.8.0
|
|
478
|
+
- @tanstack/react-query >= 5.0.0
|
|
837
479
|
|
|
838
480
|
## License
|
|
839
481
|
|