@ram_28/kf-ai-sdk 1.0.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 +21 -0
- package/README.md +840 -0
- package/dist/api/client.d.ts +78 -0
- package/dist/api/client.d.ts.map +1 -0
- package/dist/api/datetime.d.ts +21 -0
- package/dist/api/datetime.d.ts.map +1 -0
- package/dist/api/index.d.ts +7 -0
- package/dist/api/index.d.ts.map +1 -0
- package/dist/api/metadata.d.ts +75 -0
- package/dist/api/metadata.d.ts.map +1 -0
- package/dist/components/hooks/index.d.ts +8 -0
- package/dist/components/hooks/index.d.ts.map +1 -0
- package/dist/components/hooks/useFilter/index.d.ts +5 -0
- package/dist/components/hooks/useFilter/index.d.ts.map +1 -0
- package/dist/components/hooks/useFilter/payloadBuilder.utils.d.ts +33 -0
- package/dist/components/hooks/useFilter/payloadBuilder.utils.d.ts.map +1 -0
- package/dist/components/hooks/useFilter/types.d.ts +137 -0
- package/dist/components/hooks/useFilter/types.d.ts.map +1 -0
- package/dist/components/hooks/useFilter/useFilter.d.ts +3 -0
- package/dist/components/hooks/useFilter/useFilter.d.ts.map +1 -0
- package/dist/components/hooks/useFilter/validation.utils.d.ts +38 -0
- package/dist/components/hooks/useFilter/validation.utils.d.ts.map +1 -0
- package/dist/components/hooks/useForm/apiClient.d.ts +71 -0
- package/dist/components/hooks/useForm/apiClient.d.ts.map +1 -0
- package/dist/components/hooks/useForm/expressionValidator.utils.d.ts +28 -0
- package/dist/components/hooks/useForm/expressionValidator.utils.d.ts.map +1 -0
- package/dist/components/hooks/useForm/index.d.ts +6 -0
- package/dist/components/hooks/useForm/index.d.ts.map +1 -0
- package/dist/components/hooks/useForm/optimizedExpressionValidator.utils.d.ts +88 -0
- package/dist/components/hooks/useForm/optimizedExpressionValidator.utils.d.ts.map +1 -0
- package/dist/components/hooks/useForm/ruleClassifier.utils.d.ts +28 -0
- package/dist/components/hooks/useForm/ruleClassifier.utils.d.ts.map +1 -0
- package/dist/components/hooks/useForm/schemaParser.utils.d.ts +29 -0
- package/dist/components/hooks/useForm/schemaParser.utils.d.ts.map +1 -0
- package/dist/components/hooks/useForm/types.d.ts +412 -0
- package/dist/components/hooks/useForm/types.d.ts.map +1 -0
- package/dist/components/hooks/useForm/useForm.d.ts +3 -0
- package/dist/components/hooks/useForm/useForm.d.ts.map +1 -0
- package/dist/components/hooks/useKanban/apiClient.d.ts +99 -0
- package/dist/components/hooks/useKanban/apiClient.d.ts.map +1 -0
- package/dist/components/hooks/useKanban/context.d.ts +4 -0
- package/dist/components/hooks/useKanban/context.d.ts.map +1 -0
- package/dist/components/hooks/useKanban/dragDropManager.d.ts +27 -0
- package/dist/components/hooks/useKanban/dragDropManager.d.ts.map +1 -0
- package/dist/components/hooks/useKanban/index.d.ts +6 -0
- package/dist/components/hooks/useKanban/index.d.ts.map +1 -0
- package/dist/components/hooks/useKanban/types.d.ts +438 -0
- package/dist/components/hooks/useKanban/types.d.ts.map +1 -0
- package/dist/components/hooks/useKanban/useKanban.d.ts +3 -0
- package/dist/components/hooks/useKanban/useKanban.d.ts.map +1 -0
- package/dist/components/hooks/useKanban/useKanbanSimple.d.ts +62 -0
- package/dist/components/hooks/useKanban/useKanbanSimple.d.ts.map +1 -0
- package/dist/components/hooks/useTable/index.d.ts +3 -0
- package/dist/components/hooks/useTable/index.d.ts.map +1 -0
- package/dist/components/hooks/useTable/types.d.ts +107 -0
- package/dist/components/hooks/useTable/types.d.ts.map +1 -0
- package/dist/components/hooks/useTable/useTable.d.ts +8 -0
- package/dist/components/hooks/useTable/useTable.d.ts.map +1 -0
- package/dist/components/index.d.ts +3 -0
- package/dist/components/index.d.ts.map +1 -0
- package/dist/components/ui/index.d.ts +2 -0
- package/dist/components/ui/index.d.ts.map +1 -0
- package/dist/components/ui/kanban/Kanban.d.ts +12 -0
- package/dist/components/ui/kanban/Kanban.d.ts.map +1 -0
- package/dist/components/ui/kanban/index.d.ts +2 -0
- package/dist/components/ui/kanban/index.d.ts.map +1 -0
- package/dist/index.cjs +45 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.mjs +6522 -0
- package/dist/types/base-fields.d.ts +182 -0
- package/dist/types/base-fields.d.ts.map +1 -0
- package/dist/types/common.d.ts +238 -0
- package/dist/types/common.d.ts.map +1 -0
- package/dist/types/index.d.ts +3 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/utils/cn.d.ts +7 -0
- package/dist/utils/cn.d.ts.map +1 -0
- package/dist/utils/formatting.d.ts +52 -0
- package/dist/utils/formatting.d.ts.map +1 -0
- package/dist/utils/index.d.ts +3 -0
- package/dist/utils/index.d.ts.map +1 -0
- package/package.json +98 -0
- package/sdk/api/client.ts +447 -0
- package/sdk/api/datetime.ts +33 -0
- package/sdk/api/index.ts +61 -0
- package/sdk/api/metadata.ts +148 -0
- package/sdk/components/hooks/index.ts +34 -0
- package/sdk/components/hooks/useFilter/index.ts +37 -0
- package/sdk/components/hooks/useFilter/payloadBuilder.utils.ts +298 -0
- package/sdk/components/hooks/useFilter/types.ts +158 -0
- package/sdk/components/hooks/useFilter/useFilter.llm.txt +497 -0
- package/sdk/components/hooks/useFilter/useFilter.ts +494 -0
- package/sdk/components/hooks/useFilter/validation.utils.ts +401 -0
- package/sdk/components/hooks/useForm/apiClient.ts +441 -0
- package/sdk/components/hooks/useForm/expressionValidator.utils.ts +444 -0
- package/sdk/components/hooks/useForm/index.ts +64 -0
- package/sdk/components/hooks/useForm/optimizedExpressionValidator.utils.ts +482 -0
- package/sdk/components/hooks/useForm/ruleClassifier.utils.ts +424 -0
- package/sdk/components/hooks/useForm/schemaParser.utils.ts +519 -0
- package/sdk/components/hooks/useForm/types.ts +630 -0
- package/sdk/components/hooks/useForm/useForm.llm.txt +340 -0
- package/sdk/components/hooks/useForm/useForm.ts +821 -0
- package/sdk/components/hooks/useKanban/apiClient.ts +494 -0
- package/sdk/components/hooks/useKanban/context.ts +14 -0
- package/sdk/components/hooks/useKanban/dragDropManager.ts +529 -0
- package/sdk/components/hooks/useKanban/index.ts +63 -0
- package/sdk/components/hooks/useKanban/types.ts +606 -0
- package/sdk/components/hooks/useKanban/useKanban.llm.txt +482 -0
- package/sdk/components/hooks/useKanban/useKanban.ts +725 -0
- package/sdk/components/hooks/useKanban/useKanbanSimple.ts +389 -0
- package/sdk/components/hooks/useTable/index.ts +5 -0
- package/sdk/components/hooks/useTable/types.ts +154 -0
- package/sdk/components/hooks/useTable/useTable.llm.txt +344 -0
- package/sdk/components/hooks/useTable/useTable.ts +413 -0
- package/sdk/components/index.ts +15 -0
- package/sdk/components/ui/index.ts +2 -0
- package/sdk/components/ui/kanban/Kanban.tsx +134 -0
- package/sdk/components/ui/kanban/index.ts +11 -0
- package/sdk/index.ts +13 -0
- package/sdk/types/base-fields.ts +221 -0
- package/sdk/types/common.ts +306 -0
- package/sdk/types/index.ts +5 -0
- package/sdk/utils/cn.ts +10 -0
- package/sdk/utils/formatting.ts +212 -0
- package/sdk/utils/index.ts +5 -0
|
@@ -0,0 +1,413 @@
|
|
|
1
|
+
import { useState, useMemo, useCallback } from "react";
|
|
2
|
+
import { useQuery } from "@tanstack/react-query";
|
|
3
|
+
import { api } from "../../../api";
|
|
4
|
+
import type { ListResponse, ListOptions } from "../../../types/common";
|
|
5
|
+
import { useFilter } from "../useFilter";
|
|
6
|
+
import type { UseTableOptions, UseTableReturn } from "./types";
|
|
7
|
+
|
|
8
|
+
// ============================================================
|
|
9
|
+
// INTERNAL STATE TYPES
|
|
10
|
+
// ============================================================
|
|
11
|
+
|
|
12
|
+
interface SearchState {
|
|
13
|
+
query: string;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
interface SortingState<T> {
|
|
17
|
+
field: keyof T | null;
|
|
18
|
+
direction: "asc" | "desc" | null;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
interface FilteringState {
|
|
22
|
+
global: string;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
interface PaginationState {
|
|
26
|
+
pageNo: number; // 1-indexed page number
|
|
27
|
+
pageSize: number;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
// ============================================================
|
|
31
|
+
// FIELD TYPE DETECTION
|
|
32
|
+
// ============================================================
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Detect field type for auto-formatting
|
|
36
|
+
* This will be enhanced with actual type introspection in the future
|
|
37
|
+
* Currently unused but kept for future auto-formatting implementation
|
|
38
|
+
*/
|
|
39
|
+
// function _detectFieldType<T>(fieldId: keyof T): string {
|
|
40
|
+
// const fieldName = String(fieldId);
|
|
41
|
+
//
|
|
42
|
+
// // Basic pattern matching - will be replaced with actual type introspection
|
|
43
|
+
// if (fieldName.includes('price') || fieldName.includes('cost') || fieldName.includes('amount')) {
|
|
44
|
+
// return 'currency';
|
|
45
|
+
// }
|
|
46
|
+
// if (fieldName.includes('date') || fieldName.includes('At') || fieldName === 'created' || fieldName === 'updated') {
|
|
47
|
+
// return 'datetime';
|
|
48
|
+
// }
|
|
49
|
+
// if (fieldName.includes('stock') || fieldName.includes('quantity') || fieldName.includes('count')) {
|
|
50
|
+
// return 'number';
|
|
51
|
+
// }
|
|
52
|
+
// if (fieldName.includes('status') || fieldName.includes('type') || fieldName.includes('category')) {
|
|
53
|
+
// return 'string';
|
|
54
|
+
// }
|
|
55
|
+
//
|
|
56
|
+
// return 'string'; // default
|
|
57
|
+
// }
|
|
58
|
+
|
|
59
|
+
// ============================================================
|
|
60
|
+
// MAIN HOOK
|
|
61
|
+
// ============================================================
|
|
62
|
+
|
|
63
|
+
export function useTable<T = any>(
|
|
64
|
+
options: UseTableOptions<T>
|
|
65
|
+
): UseTableReturn<T> {
|
|
66
|
+
// ============================================================
|
|
67
|
+
// STATE MANAGEMENT
|
|
68
|
+
// ============================================================
|
|
69
|
+
|
|
70
|
+
const [search, setSearch] = useState<SearchState>({
|
|
71
|
+
query: "",
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
const [sorting, setSorting] = useState<SortingState<T>>({
|
|
75
|
+
field: options.initialState?.sorting?.field || null,
|
|
76
|
+
direction: options.initialState?.sorting?.direction || null,
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
const [filtering, setFiltering] = useState<FilteringState>({
|
|
80
|
+
global: options.initialState?.globalFilter || "",
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
const [pagination, setPagination] = useState<PaginationState>({
|
|
84
|
+
pageNo: options.initialState?.pagination?.pageNo || 1, // Start at page 1
|
|
85
|
+
pageSize: options.initialState?.pagination?.pageSize || 10,
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
// ============================================================
|
|
89
|
+
// FILTER HOOK INTEGRATION
|
|
90
|
+
// ============================================================
|
|
91
|
+
|
|
92
|
+
const filterHook = useFilter<T>({
|
|
93
|
+
initialConditions: options.initialState?.filters,
|
|
94
|
+
initialLogicalOperator: options.initialState?.filterOperator || "And",
|
|
95
|
+
fieldDefinitions: options.fieldDefinitions,
|
|
96
|
+
validateOnChange: true,
|
|
97
|
+
onValidationError: options.onFilterError,
|
|
98
|
+
onConditionAdd: () => {
|
|
99
|
+
// Reset to first page when adding filters
|
|
100
|
+
setPagination((prev) => ({ ...prev, pageNo: 1 }));
|
|
101
|
+
},
|
|
102
|
+
onConditionUpdate: () => {
|
|
103
|
+
// Reset to first page when updating filters
|
|
104
|
+
setPagination((prev) => ({ ...prev, pageNo: 1 }));
|
|
105
|
+
},
|
|
106
|
+
onConditionRemove: () => {
|
|
107
|
+
// Reset to first page when removing filters
|
|
108
|
+
setPagination((prev) => ({ ...prev, pageNo: 1 }));
|
|
109
|
+
},
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
// ============================================================
|
|
113
|
+
// API OPTIONS BUILDER
|
|
114
|
+
// ============================================================
|
|
115
|
+
|
|
116
|
+
// Options for count query - excludes sorting and pagination (they don't affect count)
|
|
117
|
+
const countApiOptions = useMemo((): ListOptions => {
|
|
118
|
+
const opts: ListOptions = {};
|
|
119
|
+
|
|
120
|
+
// Add search query (affects count)
|
|
121
|
+
if (search.query) {
|
|
122
|
+
opts.Search = search.query;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
// Add filter conditions (affects count)
|
|
126
|
+
if (filterHook.filterPayload) {
|
|
127
|
+
opts.Filter = filterHook.filterPayload;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
return opts;
|
|
131
|
+
}, [search.query, filterHook.filterPayload]);
|
|
132
|
+
|
|
133
|
+
// Options for list query - includes all options
|
|
134
|
+
const apiOptions = useMemo((): ListOptions => {
|
|
135
|
+
const opts: ListOptions = { ...countApiOptions };
|
|
136
|
+
|
|
137
|
+
// Add sorting - using correct API format: [{ "fieldName": "ASC" }]
|
|
138
|
+
if (sorting.field && sorting.direction) {
|
|
139
|
+
opts.Sort = [
|
|
140
|
+
{
|
|
141
|
+
[String(sorting.field)]: sorting.direction === "asc" ? "ASC" : "DESC",
|
|
142
|
+
},
|
|
143
|
+
];
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
// Add pagination
|
|
147
|
+
if (options.enablePagination) {
|
|
148
|
+
opts.Page = pagination.pageNo; // Already 1-indexed
|
|
149
|
+
opts.PageSize = pagination.pageSize;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
return opts;
|
|
153
|
+
}, [countApiOptions, sorting, pagination, options.enablePagination]);
|
|
154
|
+
|
|
155
|
+
// ============================================================
|
|
156
|
+
// DATA FETCHING
|
|
157
|
+
// ============================================================
|
|
158
|
+
|
|
159
|
+
const {
|
|
160
|
+
data,
|
|
161
|
+
isLoading,
|
|
162
|
+
isFetching,
|
|
163
|
+
error,
|
|
164
|
+
refetch: queryRefetch,
|
|
165
|
+
} = useQuery({
|
|
166
|
+
queryKey: ["table", options.source, apiOptions],
|
|
167
|
+
queryFn: async (): Promise<ListResponse<T>> => {
|
|
168
|
+
try {
|
|
169
|
+
const response = await api<T>(options.source).list(apiOptions);
|
|
170
|
+
if (options.onSuccess) {
|
|
171
|
+
options.onSuccess(response.Data);
|
|
172
|
+
}
|
|
173
|
+
return response;
|
|
174
|
+
} catch (err) {
|
|
175
|
+
if (options.onError) {
|
|
176
|
+
options.onError(err as Error);
|
|
177
|
+
}
|
|
178
|
+
throw err;
|
|
179
|
+
}
|
|
180
|
+
},
|
|
181
|
+
staleTime: 0,
|
|
182
|
+
gcTime: 0,
|
|
183
|
+
});
|
|
184
|
+
|
|
185
|
+
// Count query for accurate total items (only depends on filters/search, not sorting/pagination)
|
|
186
|
+
const {
|
|
187
|
+
data: countData,
|
|
188
|
+
isLoading: isCountLoading,
|
|
189
|
+
isFetching: isCountFetching,
|
|
190
|
+
error: countError,
|
|
191
|
+
refetch: countRefetch,
|
|
192
|
+
} = useQuery({
|
|
193
|
+
queryKey: ["table-count", options.source, countApiOptions],
|
|
194
|
+
queryFn: async () => {
|
|
195
|
+
try {
|
|
196
|
+
return await api<T>(options.source).count(countApiOptions);
|
|
197
|
+
} catch (err) {
|
|
198
|
+
if (options.onError) {
|
|
199
|
+
options.onError(err as Error);
|
|
200
|
+
}
|
|
201
|
+
throw err;
|
|
202
|
+
}
|
|
203
|
+
},
|
|
204
|
+
staleTime: 0,
|
|
205
|
+
gcTime: 0,
|
|
206
|
+
});
|
|
207
|
+
|
|
208
|
+
// ============================================================
|
|
209
|
+
// COMPUTED VALUES
|
|
210
|
+
// ============================================================
|
|
211
|
+
|
|
212
|
+
const rows = useMemo(() => data?.Data || [], [data]);
|
|
213
|
+
const totalItems = useMemo(() => countData?.Count || 0, [countData]);
|
|
214
|
+
|
|
215
|
+
const totalPages = useMemo(() => {
|
|
216
|
+
return Math.ceil(totalItems / pagination.pageSize);
|
|
217
|
+
}, [totalItems, pagination.pageSize]);
|
|
218
|
+
|
|
219
|
+
// ============================================================
|
|
220
|
+
// SORTING OPERATIONS
|
|
221
|
+
// ============================================================
|
|
222
|
+
|
|
223
|
+
const toggleSort = useCallback((field: keyof T) => {
|
|
224
|
+
setSorting((prev) => {
|
|
225
|
+
if (prev.field === field) {
|
|
226
|
+
// Same field - toggle direction or clear
|
|
227
|
+
if (prev.direction === "asc") {
|
|
228
|
+
return { field, direction: "desc" };
|
|
229
|
+
} else if (prev.direction === "desc") {
|
|
230
|
+
return { field: null, direction: null };
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
// New field or no current sort
|
|
234
|
+
return { field, direction: "asc" };
|
|
235
|
+
});
|
|
236
|
+
}, []);
|
|
237
|
+
|
|
238
|
+
const clearSort = useCallback(() => {
|
|
239
|
+
setSorting({ field: null, direction: null });
|
|
240
|
+
}, []);
|
|
241
|
+
|
|
242
|
+
const setSort = useCallback(
|
|
243
|
+
(field: keyof T | null, direction: "asc" | "desc" | null) => {
|
|
244
|
+
setSorting({ field, direction });
|
|
245
|
+
},
|
|
246
|
+
[]
|
|
247
|
+
);
|
|
248
|
+
|
|
249
|
+
// ============================================================
|
|
250
|
+
// SEARCH OPERATIONS
|
|
251
|
+
// ============================================================
|
|
252
|
+
|
|
253
|
+
const setSearchQuery = useCallback((value: string) => {
|
|
254
|
+
setSearch({ query: value });
|
|
255
|
+
// Reset to first page when searching
|
|
256
|
+
setPagination((prev) => ({ ...prev, pageNo: 1 }));
|
|
257
|
+
}, []);
|
|
258
|
+
|
|
259
|
+
const clearSearch = useCallback(() => {
|
|
260
|
+
setSearch({ query: "" });
|
|
261
|
+
}, []);
|
|
262
|
+
|
|
263
|
+
// ============================================================
|
|
264
|
+
// FILTERING OPERATIONS
|
|
265
|
+
// ============================================================
|
|
266
|
+
|
|
267
|
+
const setGlobalFilter = useCallback((value: string) => {
|
|
268
|
+
setFiltering((prev) => ({ ...prev, global: value }));
|
|
269
|
+
// Reset to first page when filtering
|
|
270
|
+
setPagination((prev) => ({ ...prev, pageNo: 1 }));
|
|
271
|
+
}, []);
|
|
272
|
+
|
|
273
|
+
const clearFilter = useCallback(() => {
|
|
274
|
+
setFiltering({ global: "" });
|
|
275
|
+
}, []);
|
|
276
|
+
|
|
277
|
+
// ============================================================
|
|
278
|
+
// PAGINATION OPERATIONS
|
|
279
|
+
// ============================================================
|
|
280
|
+
|
|
281
|
+
const canGoNext = pagination.pageNo < totalPages;
|
|
282
|
+
const canGoPrevious = pagination.pageNo > 1;
|
|
283
|
+
|
|
284
|
+
const goToNext = useCallback(() => {
|
|
285
|
+
if (canGoNext) {
|
|
286
|
+
setPagination((prev) => ({ ...prev, pageNo: prev.pageNo + 1 }));
|
|
287
|
+
}
|
|
288
|
+
}, [canGoNext]);
|
|
289
|
+
|
|
290
|
+
const goToPrevious = useCallback(() => {
|
|
291
|
+
if (canGoPrevious) {
|
|
292
|
+
setPagination((prev) => ({ ...prev, pageNo: prev.pageNo - 1 }));
|
|
293
|
+
}
|
|
294
|
+
}, [canGoPrevious]);
|
|
295
|
+
|
|
296
|
+
const goToPage = useCallback(
|
|
297
|
+
(page: number) => {
|
|
298
|
+
const pageNo = Math.max(1, Math.min(page, totalPages)); // Clamp between 1 and totalPages
|
|
299
|
+
setPagination((prev) => ({ ...prev, pageNo }));
|
|
300
|
+
},
|
|
301
|
+
[totalPages]
|
|
302
|
+
);
|
|
303
|
+
|
|
304
|
+
const setPageSize = useCallback((size: number) => {
|
|
305
|
+
setPagination((prev) => ({
|
|
306
|
+
...prev,
|
|
307
|
+
pageSize: size,
|
|
308
|
+
pageNo: 1, // Reset to first page
|
|
309
|
+
}));
|
|
310
|
+
}, []);
|
|
311
|
+
|
|
312
|
+
// ============================================================
|
|
313
|
+
// REFETCH OPERATION
|
|
314
|
+
// ============================================================
|
|
315
|
+
|
|
316
|
+
const refetch = useCallback(async (): Promise<ListResponse<T>> => {
|
|
317
|
+
const [listResult] = await Promise.all([queryRefetch(), countRefetch()]);
|
|
318
|
+
return listResult.data || { Data: [] };
|
|
319
|
+
}, [queryRefetch, countRefetch]);
|
|
320
|
+
|
|
321
|
+
// ============================================================
|
|
322
|
+
// RETURN OBJECT
|
|
323
|
+
// ============================================================
|
|
324
|
+
|
|
325
|
+
return {
|
|
326
|
+
// Data
|
|
327
|
+
rows,
|
|
328
|
+
totalItems,
|
|
329
|
+
|
|
330
|
+
// Loading States
|
|
331
|
+
isLoading: isLoading || isCountLoading,
|
|
332
|
+
isFetching: isFetching || isCountFetching,
|
|
333
|
+
|
|
334
|
+
// Error Handling
|
|
335
|
+
error: (error || countError) as Error | null,
|
|
336
|
+
|
|
337
|
+
// Search (Flat Access)
|
|
338
|
+
search: {
|
|
339
|
+
query: search.query,
|
|
340
|
+
setQuery: setSearchQuery,
|
|
341
|
+
clear: clearSearch,
|
|
342
|
+
},
|
|
343
|
+
|
|
344
|
+
// Sorting (Flat Access)
|
|
345
|
+
sort: {
|
|
346
|
+
field: sorting.field,
|
|
347
|
+
direction: sorting.direction,
|
|
348
|
+
toggle: toggleSort,
|
|
349
|
+
clear: clearSort,
|
|
350
|
+
set: setSort,
|
|
351
|
+
},
|
|
352
|
+
|
|
353
|
+
// Legacy Global Filtering (Flat Access)
|
|
354
|
+
globalFilter: {
|
|
355
|
+
value: filtering.global,
|
|
356
|
+
setValue: setGlobalFilter,
|
|
357
|
+
clear: clearFilter,
|
|
358
|
+
},
|
|
359
|
+
|
|
360
|
+
// Advanced Filtering (Filter Conditions)
|
|
361
|
+
filter: {
|
|
362
|
+
// State
|
|
363
|
+
conditions: filterHook.conditions,
|
|
364
|
+
logicalOperator: filterHook.logicalOperator,
|
|
365
|
+
isValid: filterHook.isValid,
|
|
366
|
+
validationErrors: filterHook.validationErrors,
|
|
367
|
+
hasConditions: filterHook.hasConditions,
|
|
368
|
+
|
|
369
|
+
// Condition Management
|
|
370
|
+
addCondition: filterHook.addCondition,
|
|
371
|
+
updateCondition: filterHook.updateCondition,
|
|
372
|
+
removeCondition: filterHook.removeCondition,
|
|
373
|
+
clearConditions: filterHook.clearConditions,
|
|
374
|
+
getCondition: filterHook.getCondition,
|
|
375
|
+
|
|
376
|
+
// Logical Operator
|
|
377
|
+
setLogicalOperator: filterHook.setLogicalOperator,
|
|
378
|
+
|
|
379
|
+
// Bulk Operations
|
|
380
|
+
setConditions: filterHook.setConditions,
|
|
381
|
+
replaceCondition: filterHook.replaceCondition,
|
|
382
|
+
|
|
383
|
+
// Validation
|
|
384
|
+
validateCondition: filterHook.validateCondition,
|
|
385
|
+
validateAllConditions: filterHook.validateAllConditions,
|
|
386
|
+
|
|
387
|
+
// State Management
|
|
388
|
+
exportState: filterHook.exportState,
|
|
389
|
+
importState: filterHook.importState,
|
|
390
|
+
resetToInitial: filterHook.resetToInitial,
|
|
391
|
+
|
|
392
|
+
// Utilities
|
|
393
|
+
getConditionCount: filterHook.getConditionCount,
|
|
394
|
+
},
|
|
395
|
+
|
|
396
|
+
// Pagination (Flat Access)
|
|
397
|
+
pagination: {
|
|
398
|
+
currentPage: pagination.pageNo, // Already 1-indexed
|
|
399
|
+
pageSize: pagination.pageSize,
|
|
400
|
+
totalPages,
|
|
401
|
+
totalItems,
|
|
402
|
+
canGoNext,
|
|
403
|
+
canGoPrevious,
|
|
404
|
+
goToNext,
|
|
405
|
+
goToPrevious,
|
|
406
|
+
goToPage,
|
|
407
|
+
setPageSize,
|
|
408
|
+
},
|
|
409
|
+
|
|
410
|
+
// Operations
|
|
411
|
+
refetch,
|
|
412
|
+
};
|
|
413
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
// Hooks
|
|
2
|
+
export * from "./hooks";
|
|
3
|
+
|
|
4
|
+
// UI Components (explicit exports to avoid naming conflicts with types)
|
|
5
|
+
export {
|
|
6
|
+
Kanban,
|
|
7
|
+
KanbanColumn,
|
|
8
|
+
KanbanColumnHeader,
|
|
9
|
+
KanbanColumnTitle,
|
|
10
|
+
KanbanColumnContent,
|
|
11
|
+
KanbanCard,
|
|
12
|
+
KanbanCardTitle,
|
|
13
|
+
KanbanCardDescription,
|
|
14
|
+
KanbanColumnFooter,
|
|
15
|
+
} from "./ui";
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
import { cn } from "../../../utils";
|
|
3
|
+
|
|
4
|
+
// Simple styled wrapper components following the Table pattern
|
|
5
|
+
// No complex logic - just styling and basic structure
|
|
6
|
+
|
|
7
|
+
const Kanban = React.forwardRef<
|
|
8
|
+
HTMLDivElement,
|
|
9
|
+
React.HTMLAttributes<HTMLDivElement>
|
|
10
|
+
>(({ className, ...props }, ref) => (
|
|
11
|
+
<div
|
|
12
|
+
ref={ref}
|
|
13
|
+
className={cn(
|
|
14
|
+
"flex h-full flex-grow items-start gap-x-4 overflow-x-auto py-2",
|
|
15
|
+
className
|
|
16
|
+
)}
|
|
17
|
+
{...props}
|
|
18
|
+
/>
|
|
19
|
+
));
|
|
20
|
+
Kanban.displayName = "Kanban";
|
|
21
|
+
|
|
22
|
+
const KanbanColumn = React.forwardRef<
|
|
23
|
+
HTMLDivElement,
|
|
24
|
+
React.HTMLAttributes<HTMLDivElement>
|
|
25
|
+
>(({ className, ...props }, ref) => (
|
|
26
|
+
<div
|
|
27
|
+
ref={ref}
|
|
28
|
+
className={cn(
|
|
29
|
+
"flex h-full min-w-[300px] flex-col rounded-lg border bg-gray-50 p-3",
|
|
30
|
+
className
|
|
31
|
+
)}
|
|
32
|
+
{...props}
|
|
33
|
+
/>
|
|
34
|
+
));
|
|
35
|
+
KanbanColumn.displayName = "KanbanColumn";
|
|
36
|
+
|
|
37
|
+
const KanbanColumnHeader = React.forwardRef<
|
|
38
|
+
HTMLDivElement,
|
|
39
|
+
React.HTMLAttributes<HTMLDivElement>
|
|
40
|
+
>(({ className, ...props }, ref) => (
|
|
41
|
+
<div
|
|
42
|
+
ref={ref}
|
|
43
|
+
className={cn("mb-3 flex items-center justify-between", className)}
|
|
44
|
+
{...props}
|
|
45
|
+
/>
|
|
46
|
+
));
|
|
47
|
+
KanbanColumnHeader.displayName = "KanbanColumnHeader";
|
|
48
|
+
|
|
49
|
+
const KanbanColumnTitle = React.forwardRef<
|
|
50
|
+
HTMLHeadingElement,
|
|
51
|
+
React.HTMLAttributes<HTMLHeadingElement>
|
|
52
|
+
>(({ className, ...props }, ref) => (
|
|
53
|
+
<h3
|
|
54
|
+
ref={ref}
|
|
55
|
+
className={cn("text-sm font-semibold text-gray-700", className)}
|
|
56
|
+
{...props}
|
|
57
|
+
/>
|
|
58
|
+
));
|
|
59
|
+
KanbanColumnTitle.displayName = "KanbanColumnTitle";
|
|
60
|
+
|
|
61
|
+
const KanbanColumnContent = React.forwardRef<
|
|
62
|
+
HTMLDivElement,
|
|
63
|
+
React.HTMLAttributes<HTMLDivElement>
|
|
64
|
+
>(({ className, ...props }, ref) => (
|
|
65
|
+
<div
|
|
66
|
+
ref={ref}
|
|
67
|
+
className={cn("flex-1 space-y-2 overflow-y-auto", className)}
|
|
68
|
+
{...props}
|
|
69
|
+
/>
|
|
70
|
+
));
|
|
71
|
+
KanbanColumnContent.displayName = "KanbanColumnContent";
|
|
72
|
+
|
|
73
|
+
const KanbanCard = React.forwardRef<
|
|
74
|
+
HTMLDivElement,
|
|
75
|
+
React.HTMLAttributes<HTMLDivElement>
|
|
76
|
+
>(({ className, ...props }, ref) => (
|
|
77
|
+
<div
|
|
78
|
+
ref={ref}
|
|
79
|
+
className={cn(
|
|
80
|
+
"rounded-lg border border-gray-200 bg-white p-3 shadow-sm hover:shadow-md transition-shadow cursor-move",
|
|
81
|
+
className
|
|
82
|
+
)}
|
|
83
|
+
{...props}
|
|
84
|
+
/>
|
|
85
|
+
));
|
|
86
|
+
KanbanCard.displayName = "KanbanCard";
|
|
87
|
+
|
|
88
|
+
const KanbanCardTitle = React.forwardRef<
|
|
89
|
+
HTMLDivElement,
|
|
90
|
+
React.HTMLAttributes<HTMLDivElement>
|
|
91
|
+
>(({ className, ...props }, ref) => (
|
|
92
|
+
<div
|
|
93
|
+
ref={ref}
|
|
94
|
+
className={cn("font-medium text-gray-900 mb-1", className)}
|
|
95
|
+
{...props}
|
|
96
|
+
/>
|
|
97
|
+
));
|
|
98
|
+
KanbanCardTitle.displayName = "KanbanCardTitle";
|
|
99
|
+
|
|
100
|
+
const KanbanCardDescription = React.forwardRef<
|
|
101
|
+
HTMLDivElement,
|
|
102
|
+
React.HTMLAttributes<HTMLDivElement>
|
|
103
|
+
>(({ className, ...props }, ref) => (
|
|
104
|
+
<div
|
|
105
|
+
ref={ref}
|
|
106
|
+
className={cn("text-sm text-gray-600", className)}
|
|
107
|
+
{...props}
|
|
108
|
+
/>
|
|
109
|
+
));
|
|
110
|
+
KanbanCardDescription.displayName = "KanbanCardDescription";
|
|
111
|
+
|
|
112
|
+
const KanbanColumnFooter = React.forwardRef<
|
|
113
|
+
HTMLDivElement,
|
|
114
|
+
React.HTMLAttributes<HTMLDivElement>
|
|
115
|
+
>(({ className, ...props }, ref) => (
|
|
116
|
+
<div
|
|
117
|
+
ref={ref}
|
|
118
|
+
className={cn("mt-3 pt-3 border-t border-gray-200", className)}
|
|
119
|
+
{...props}
|
|
120
|
+
/>
|
|
121
|
+
));
|
|
122
|
+
KanbanColumnFooter.displayName = "KanbanColumnFooter";
|
|
123
|
+
|
|
124
|
+
export {
|
|
125
|
+
Kanban,
|
|
126
|
+
KanbanColumn,
|
|
127
|
+
KanbanColumnHeader,
|
|
128
|
+
KanbanColumnTitle,
|
|
129
|
+
KanbanColumnContent,
|
|
130
|
+
KanbanCard,
|
|
131
|
+
KanbanCardTitle,
|
|
132
|
+
KanbanCardDescription,
|
|
133
|
+
KanbanColumnFooter,
|
|
134
|
+
};
|