dn-react-router-toolkit 0.8.0 → 0.9.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/dist/api/index.js +13 -4
- package/dist/api/index.mjs +14 -5
- package/dist/api/item_api_handler.d.mts +4 -2
- package/dist/api/item_api_handler.d.ts +4 -2
- package/dist/api/item_api_handler.js +13 -4
- package/dist/api/item_api_handler.mjs +14 -5
- package/dist/crud/index.d.mts +0 -20
- package/dist/crud/index.d.ts +0 -20
- package/dist/crud/index.js +12 -8508
- package/dist/crud/index.mjs +0 -8516
- package/dist/post/index.js +67 -7705
- package/dist/post/index.mjs +54 -7717
- package/dist/post/post_form_page.js +67 -7705
- package/dist/post/post_form_page.mjs +54 -7717
- package/dist/table/index.d.mts +1 -3
- package/dist/table/index.d.ts +1 -3
- package/dist/table/index.js +83 -76
- package/dist/table/index.mjs +84 -74
- package/dist/table/load_table.d.mts +8 -2
- package/dist/table/load_table.d.ts +8 -2
- package/dist/table/load_table.js +23 -3
- package/dist/table/load_table.mjs +24 -3
- package/dist/table/loader.d.mts +3 -0
- package/dist/table/loader.d.ts +3 -0
- package/dist/table/loader.js +23 -3
- package/dist/table/loader.mjs +24 -3
- package/dist/table/repository.d.mts +6 -4
- package/dist/table/repository.d.ts +6 -4
- package/dist/table/repository.js +4 -0
- package/dist/table/repository.mjs +4 -0
- package/dist/table/table.d.mts +5 -2
- package/dist/table/table.d.ts +5 -2
- package/dist/table/table.js +38 -6
- package/dist/table/table.mjs +38 -6
- package/dist/table/table_form.d.mts +2 -2
- package/dist/table/table_form.d.ts +2 -2
- package/dist/table/table_form.js +52 -19
- package/dist/table/table_form.mjs +52 -19
- package/dist/table/use_table.d.mts +3 -3
- package/dist/table/use_table.d.ts +3 -3
- package/dist/table/use_table.js +1 -10
- package/dist/table/use_table.mjs +1 -10
- package/package.json +1 -1
- package/dist/crud/crud_loader.d.mts +0 -26
- package/dist/crud/crud_loader.d.ts +0 -26
- package/dist/crud/crud_loader.js +0 -322
- package/dist/crud/crud_loader.mjs +0 -307
- package/dist/crud/crud_page.d.mts +0 -32
- package/dist/crud/crud_page.d.ts +0 -32
- package/dist/crud/crud_page.js +0 -726
- package/dist/crud/crud_page.mjs +0 -708
- package/dist/crud/generate_handlers.d.mts +0 -16
- package/dist/crud/generate_handlers.d.ts +0 -16
- package/dist/crud/generate_handlers.js +0 -39
- package/dist/crud/generate_handlers.mjs +0 -14
- package/dist/crud/generate_pages.d.mts +0 -19
- package/dist/crud/generate_pages.d.ts +0 -19
- package/dist/crud/generate_pages.js +0 -55
- package/dist/crud/generate_pages.mjs +0 -30
- package/dist/crud/generate_routes.d.mts +0 -5
- package/dist/crud/generate_routes.d.ts +0 -5
- package/dist/crud/generate_routes.js +0 -7639
- package/dist/crud/generate_routes.mjs +0 -7627
- package/dist/table/item_loader.d.mts +0 -14
- package/dist/table/item_loader.d.ts +0 -14
- package/dist/table/item_loader.js +0 -43
- package/dist/table/item_loader.mjs +0 -18
- package/dist/table/page.d.mts +0 -16
- package/dist/table/page.d.ts +0 -16
- package/dist/table/page.js +0 -325
- package/dist/table/page.mjs +0 -300
package/dist/table/index.d.mts
CHANGED
|
@@ -1,12 +1,10 @@
|
|
|
1
1
|
export { BaseTableRepository, ColumnOf, FindAllOptions, InsertModelOf, SchemaOf, SelectModelOf, TableRepository } from './repository.mjs';
|
|
2
2
|
export { TablePageButtons } from './buttons.mjs';
|
|
3
|
-
export { TableItemLoaderOptions, tableItemloader } from './item_loader.mjs';
|
|
4
3
|
export { tableLoader } from './loader.mjs';
|
|
5
|
-
export { createTablePage } from './page.mjs';
|
|
6
4
|
export { OrderedTableProps, Table, TableColumnOptions, TableColumnProps } from './table.mjs';
|
|
7
5
|
export { TableLoaderOptions, loadTable } from './load_table.mjs';
|
|
8
6
|
export { LoadedModel, TableForm, TablePageOptions } from './table_form.mjs';
|
|
9
|
-
export {
|
|
7
|
+
export { TableLoaderData, useTable } from './use_table.mjs';
|
|
10
8
|
import 'drizzle-orm';
|
|
11
9
|
import 'drizzle-orm/node-postgres';
|
|
12
10
|
import 'drizzle-orm/pg-core';
|
package/dist/table/index.d.ts
CHANGED
|
@@ -1,12 +1,10 @@
|
|
|
1
1
|
export { BaseTableRepository, ColumnOf, FindAllOptions, InsertModelOf, SchemaOf, SelectModelOf, TableRepository } from './repository.js';
|
|
2
2
|
export { TablePageButtons } from './buttons.js';
|
|
3
|
-
export { TableItemLoaderOptions, tableItemloader } from './item_loader.js';
|
|
4
3
|
export { tableLoader } from './loader.js';
|
|
5
|
-
export { createTablePage } from './page.js';
|
|
6
4
|
export { OrderedTableProps, Table, TableColumnOptions, TableColumnProps } from './table.js';
|
|
7
5
|
export { TableLoaderOptions, loadTable } from './load_table.js';
|
|
8
6
|
export { LoadedModel, TableForm, TablePageOptions } from './table_form.js';
|
|
9
|
-
export {
|
|
7
|
+
export { TableLoaderData, useTable } from './use_table.js';
|
|
10
8
|
import 'drizzle-orm';
|
|
11
9
|
import 'drizzle-orm/node-postgres';
|
|
12
10
|
import 'drizzle-orm/pg-core';
|
package/dist/table/index.js
CHANGED
|
@@ -24,9 +24,7 @@ __export(table_exports, {
|
|
|
24
24
|
Table: () => Table,
|
|
25
25
|
TableForm: () => TableForm,
|
|
26
26
|
TablePageButtons: () => TablePageButtons,
|
|
27
|
-
createTablePage: () => createTablePage,
|
|
28
27
|
loadTable: () => loadTable,
|
|
29
|
-
tableItemloader: () => tableItemloader,
|
|
30
28
|
tableLoader: () => tableLoader,
|
|
31
29
|
useTable: () => useTable
|
|
32
30
|
});
|
|
@@ -79,6 +77,10 @@ var BaseTableRepository = class {
|
|
|
79
77
|
async delete(pk) {
|
|
80
78
|
await this.db.delete(this.schema).where((0, import_drizzle_orm.eq)(this.schema[this.pk], pk));
|
|
81
79
|
}
|
|
80
|
+
async select(key) {
|
|
81
|
+
const rows = await this.db.select({ value: this.schema[key] }).from(this.schema).groupBy(this.schema[key]);
|
|
82
|
+
return rows.map((row) => row.value);
|
|
83
|
+
}
|
|
82
84
|
};
|
|
83
85
|
|
|
84
86
|
// src/table/buttons.tsx
|
|
@@ -154,22 +156,6 @@ function TablePageButtons({
|
|
|
154
156
|
] }) });
|
|
155
157
|
}
|
|
156
158
|
|
|
157
|
-
// src/table/item_loader.tsx
|
|
158
|
-
var tableItemloader = ({
|
|
159
|
-
repository
|
|
160
|
-
}) => {
|
|
161
|
-
return async (args) => {
|
|
162
|
-
const { params } = args;
|
|
163
|
-
if (params["itemId"] === "new") {
|
|
164
|
-
return { item: void 0 };
|
|
165
|
-
}
|
|
166
|
-
const item = params["itemId"] ? await repository.find(params["itemId"]) : void 0;
|
|
167
|
-
return {
|
|
168
|
-
item
|
|
169
|
-
};
|
|
170
|
-
};
|
|
171
|
-
};
|
|
172
|
-
|
|
173
159
|
// src/table/load_table.tsx
|
|
174
160
|
var import_drizzle_orm2 = require("drizzle-orm");
|
|
175
161
|
async function loadTable({
|
|
@@ -180,16 +166,27 @@ async function loadTable({
|
|
|
180
166
|
const searchParams = new URL(request.url).searchParams;
|
|
181
167
|
const { where, searchKey, defaultOrderBy, defaultDirection } = options;
|
|
182
168
|
const query = searchParams.get("query") ?? void 0;
|
|
183
|
-
const limit = Number(searchParams.get("limit") ?? "
|
|
169
|
+
const limit = Number(searchParams.get("limit") ?? "10");
|
|
184
170
|
const offset = Number(searchParams.get("offset") ?? "0");
|
|
185
171
|
const orderBy = searchParams.get("orderBy") ?? defaultOrderBy;
|
|
186
172
|
const direction = searchParams.get("direction") ?? defaultDirection;
|
|
173
|
+
const filterWhere = Object.entries(options.filters ?? {}).map(([key, value]) => {
|
|
174
|
+
const param = searchParams.get(key);
|
|
175
|
+
if (param) {
|
|
176
|
+
return (0, import_drizzle_orm2.eq)(
|
|
177
|
+
repository.schema[key],
|
|
178
|
+
decodeURIComponent(param)
|
|
179
|
+
);
|
|
180
|
+
}
|
|
181
|
+
return void 0;
|
|
182
|
+
}).filter(Boolean);
|
|
187
183
|
const whereClauses = (0, import_drizzle_orm2.and)(
|
|
188
184
|
searchKey && query ? (0, import_drizzle_orm2.ilike)(
|
|
189
185
|
repository.schema[searchKey],
|
|
190
186
|
`%${query}%`
|
|
191
187
|
) : void 0,
|
|
192
|
-
...
|
|
188
|
+
...filterWhere,
|
|
189
|
+
where
|
|
193
190
|
);
|
|
194
191
|
const total = await repository.countTotal({ where: whereClauses });
|
|
195
192
|
const items = await repository.findAll({
|
|
@@ -199,6 +196,14 @@ async function loadTable({
|
|
|
199
196
|
offset,
|
|
200
197
|
where: whereClauses
|
|
201
198
|
});
|
|
199
|
+
const filters = Object.fromEntries(
|
|
200
|
+
await Promise.all(
|
|
201
|
+
Object.keys(options.filters ?? {}).map(async (key) => {
|
|
202
|
+
const values = await repository.select(key);
|
|
203
|
+
return [key, values.filter(Boolean)];
|
|
204
|
+
})
|
|
205
|
+
)
|
|
206
|
+
);
|
|
202
207
|
return {
|
|
203
208
|
items,
|
|
204
209
|
total,
|
|
@@ -206,7 +211,8 @@ async function loadTable({
|
|
|
206
211
|
offset,
|
|
207
212
|
orderBy,
|
|
208
213
|
direction,
|
|
209
|
-
searchKey
|
|
214
|
+
searchKey,
|
|
215
|
+
filters
|
|
210
216
|
};
|
|
211
217
|
}
|
|
212
218
|
|
|
@@ -227,13 +233,6 @@ function tableLoader({
|
|
|
227
233
|
};
|
|
228
234
|
}
|
|
229
235
|
|
|
230
|
-
// src/table/page.tsx
|
|
231
|
-
var import_react_router5 = require("react-router");
|
|
232
|
-
|
|
233
|
-
// src/table/table_form.tsx
|
|
234
|
-
var import_react_router4 = require("react-router");
|
|
235
|
-
var import_go2 = require("react-icons/go");
|
|
236
|
-
|
|
237
236
|
// src/table/table.tsx
|
|
238
237
|
var import_utils2 = require("dn-react-toolkit/utils");
|
|
239
238
|
var import_go = require("react-icons/go");
|
|
@@ -248,7 +247,8 @@ function Table({
|
|
|
248
247
|
limit,
|
|
249
248
|
offset,
|
|
250
249
|
orderBy,
|
|
251
|
-
direction
|
|
250
|
+
direction,
|
|
251
|
+
filters
|
|
252
252
|
}) {
|
|
253
253
|
const keys = Object.entries(columns).filter((entry) => entry[1]).map(([key]) => key);
|
|
254
254
|
const sortedArray = [...data];
|
|
@@ -273,8 +273,8 @@ function Table({
|
|
|
273
273
|
"button",
|
|
274
274
|
{
|
|
275
275
|
className: (0, import_utils2.cn)(
|
|
276
|
-
orderBy === key ? "text-
|
|
277
|
-
"px-4
|
|
276
|
+
orderBy === key ? "text-gray-900 font-medium" : "text-gray-500 font-medium",
|
|
277
|
+
"px-4 flex items-center w-full"
|
|
278
278
|
),
|
|
279
279
|
onClick: () => {
|
|
280
280
|
let newDirection = "asc";
|
|
@@ -295,14 +295,45 @@ function Table({
|
|
|
295
295
|
}
|
|
296
296
|
return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_jsx_runtime2.Fragment, { children: reactNode });
|
|
297
297
|
}
|
|
298
|
-
|
|
298
|
+
const filter = filters?.[key];
|
|
299
|
+
return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
|
|
300
|
+
"th",
|
|
301
|
+
{
|
|
302
|
+
className: (0, import_utils2.cn)("py-4 border-y font-normal align-top"),
|
|
303
|
+
children: [
|
|
304
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Head, {}),
|
|
305
|
+
filter && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "px-3 mt-4", children: /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
|
|
306
|
+
"select",
|
|
307
|
+
{
|
|
308
|
+
className: "w-full h-10 px-1.5 border rounded-full outline-none",
|
|
309
|
+
onChange: (e) => {
|
|
310
|
+
const value2 = e.target.value;
|
|
311
|
+
setSearchParams((prev) => {
|
|
312
|
+
if (value2) {
|
|
313
|
+
prev.set(key, encodeURIComponent(value2));
|
|
314
|
+
} else {
|
|
315
|
+
prev.delete(key);
|
|
316
|
+
}
|
|
317
|
+
return prev;
|
|
318
|
+
});
|
|
319
|
+
},
|
|
320
|
+
children: [
|
|
321
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("option", { value: "", children: "\uC804\uCCB4" }),
|
|
322
|
+
filter.map((option) => /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("option", { value: option, children: option }, option))
|
|
323
|
+
]
|
|
324
|
+
}
|
|
325
|
+
) })
|
|
326
|
+
]
|
|
327
|
+
},
|
|
328
|
+
key
|
|
329
|
+
);
|
|
299
330
|
}) }) }),
|
|
300
331
|
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("tbody", { children: [
|
|
301
332
|
sortedArray.length === 0 && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("tr", { children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
302
333
|
"td",
|
|
303
334
|
{
|
|
304
335
|
colSpan: keys.length,
|
|
305
|
-
className: "px-4 h-
|
|
336
|
+
className: "px-4 h-20 text-gray-400 text-center",
|
|
306
337
|
children: "\uB370\uC774\uD130\uAC00 \uC5C6\uC2B5\uB2C8\uB2E4."
|
|
307
338
|
}
|
|
308
339
|
) }),
|
|
@@ -327,7 +358,7 @@ function Table({
|
|
|
327
358
|
className: "block content-center px-4 w-full h-full",
|
|
328
359
|
children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Content, {})
|
|
329
360
|
}
|
|
330
|
-
) : /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Content, {});
|
|
361
|
+
) : /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "px-4 w-full h-full content-center", children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Content, {}) });
|
|
331
362
|
const cell = Mapper ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Mapper, { item, index: i2, children: linkedContent }) : linkedContent;
|
|
332
363
|
return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("td", { className: "px-0 h-14 border-b", children: cell }, key);
|
|
333
364
|
}) }, i))
|
|
@@ -337,20 +368,15 @@ function Table({
|
|
|
337
368
|
);
|
|
338
369
|
}
|
|
339
370
|
|
|
371
|
+
// src/table/table_form.tsx
|
|
372
|
+
var import_react_router4 = require("react-router");
|
|
373
|
+
var import_go2 = require("react-icons/go");
|
|
374
|
+
|
|
340
375
|
// src/table/use_table.tsx
|
|
341
376
|
var import_react_router3 = require("react-router");
|
|
342
377
|
function useTable() {
|
|
343
378
|
const { table } = (0, import_react_router3.useLoaderData)();
|
|
344
|
-
|
|
345
|
-
return {
|
|
346
|
-
items,
|
|
347
|
-
total,
|
|
348
|
-
limit,
|
|
349
|
-
offset,
|
|
350
|
-
orderBy,
|
|
351
|
-
direction,
|
|
352
|
-
searchKey
|
|
353
|
-
};
|
|
379
|
+
return table;
|
|
354
380
|
}
|
|
355
381
|
|
|
356
382
|
// src/table/table_form.tsx
|
|
@@ -360,7 +386,16 @@ function TableForm({
|
|
|
360
386
|
primaryKey = "id"
|
|
361
387
|
}) {
|
|
362
388
|
const { pathname } = (0, import_react_router4.useLocation)();
|
|
363
|
-
const {
|
|
389
|
+
const {
|
|
390
|
+
items,
|
|
391
|
+
total,
|
|
392
|
+
limit,
|
|
393
|
+
offset,
|
|
394
|
+
orderBy,
|
|
395
|
+
direction,
|
|
396
|
+
searchKey,
|
|
397
|
+
filters
|
|
398
|
+
} = useTable();
|
|
364
399
|
const navigate = (0, import_react_router4.useNavigate)();
|
|
365
400
|
const search = (query) => {
|
|
366
401
|
const searchParams2 = new URLSearchParams(window.location.search);
|
|
@@ -373,7 +408,7 @@ function TableForm({
|
|
|
373
408
|
searchKey && /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
|
|
374
409
|
"form",
|
|
375
410
|
{
|
|
376
|
-
className: "h-
|
|
411
|
+
className: "h-20 px-4 flex items-center border-t",
|
|
377
412
|
onSubmit: (e) => {
|
|
378
413
|
e.preventDefault();
|
|
379
414
|
const formData = new FormData(e.currentTarget);
|
|
@@ -410,7 +445,8 @@ function TableForm({
|
|
|
410
445
|
limit,
|
|
411
446
|
offset,
|
|
412
447
|
orderBy,
|
|
413
|
-
direction
|
|
448
|
+
direction,
|
|
449
|
+
filters
|
|
414
450
|
}
|
|
415
451
|
),
|
|
416
452
|
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
@@ -424,42 +460,13 @@ function TableForm({
|
|
|
424
460
|
)
|
|
425
461
|
] });
|
|
426
462
|
}
|
|
427
|
-
|
|
428
|
-
// src/table/page.tsx
|
|
429
|
-
var import_jsx_runtime4 = require("react/jsx-runtime");
|
|
430
|
-
function createTablePage({
|
|
431
|
-
name,
|
|
432
|
-
columns,
|
|
433
|
-
primaryKey = "id"
|
|
434
|
-
}) {
|
|
435
|
-
return function TablePage({
|
|
436
|
-
header: Header
|
|
437
|
-
}) {
|
|
438
|
-
const { pathname } = (0, import_react_router5.useLocation)();
|
|
439
|
-
return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_jsx_runtime4.Fragment, { children: [
|
|
440
|
-
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
441
|
-
Header,
|
|
442
|
-
{
|
|
443
|
-
title: name,
|
|
444
|
-
actions: /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_react_router5.Link, { to: `${pathname}/new`, className: "button-primary", children: [
|
|
445
|
-
name,
|
|
446
|
-
" \uCD94\uAC00"
|
|
447
|
-
] })
|
|
448
|
-
}
|
|
449
|
-
),
|
|
450
|
-
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: "max-w-7xl mx-auto w-full overflow-auto", children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(TableForm, { columns, primaryKey }) })
|
|
451
|
-
] });
|
|
452
|
-
};
|
|
453
|
-
}
|
|
454
463
|
// Annotate the CommonJS export names for ESM import in node:
|
|
455
464
|
0 && (module.exports = {
|
|
456
465
|
BaseTableRepository,
|
|
457
466
|
Table,
|
|
458
467
|
TableForm,
|
|
459
468
|
TablePageButtons,
|
|
460
|
-
createTablePage,
|
|
461
469
|
loadTable,
|
|
462
|
-
tableItemloader,
|
|
463
470
|
tableLoader,
|
|
464
471
|
useTable
|
|
465
472
|
});
|
package/dist/table/index.mjs
CHANGED
|
@@ -50,6 +50,10 @@ var BaseTableRepository = class {
|
|
|
50
50
|
async delete(pk) {
|
|
51
51
|
await this.db.delete(this.schema).where(eq(this.schema[this.pk], pk));
|
|
52
52
|
}
|
|
53
|
+
async select(key) {
|
|
54
|
+
const rows = await this.db.select({ value: this.schema[key] }).from(this.schema).groupBy(this.schema[key]);
|
|
55
|
+
return rows.map((row) => row.value);
|
|
56
|
+
}
|
|
53
57
|
};
|
|
54
58
|
|
|
55
59
|
// src/table/buttons.tsx
|
|
@@ -125,25 +129,10 @@ function TablePageButtons({
|
|
|
125
129
|
] }) });
|
|
126
130
|
}
|
|
127
131
|
|
|
128
|
-
// src/table/item_loader.tsx
|
|
129
|
-
var tableItemloader = ({
|
|
130
|
-
repository
|
|
131
|
-
}) => {
|
|
132
|
-
return async (args) => {
|
|
133
|
-
const { params } = args;
|
|
134
|
-
if (params["itemId"] === "new") {
|
|
135
|
-
return { item: void 0 };
|
|
136
|
-
}
|
|
137
|
-
const item = params["itemId"] ? await repository.find(params["itemId"]) : void 0;
|
|
138
|
-
return {
|
|
139
|
-
item
|
|
140
|
-
};
|
|
141
|
-
};
|
|
142
|
-
};
|
|
143
|
-
|
|
144
132
|
// src/table/load_table.tsx
|
|
145
133
|
import {
|
|
146
134
|
and,
|
|
135
|
+
eq as eq2,
|
|
147
136
|
ilike
|
|
148
137
|
} from "drizzle-orm";
|
|
149
138
|
async function loadTable({
|
|
@@ -154,16 +143,27 @@ async function loadTable({
|
|
|
154
143
|
const searchParams = new URL(request.url).searchParams;
|
|
155
144
|
const { where, searchKey, defaultOrderBy, defaultDirection } = options;
|
|
156
145
|
const query = searchParams.get("query") ?? void 0;
|
|
157
|
-
const limit = Number(searchParams.get("limit") ?? "
|
|
146
|
+
const limit = Number(searchParams.get("limit") ?? "10");
|
|
158
147
|
const offset = Number(searchParams.get("offset") ?? "0");
|
|
159
148
|
const orderBy = searchParams.get("orderBy") ?? defaultOrderBy;
|
|
160
149
|
const direction = searchParams.get("direction") ?? defaultDirection;
|
|
150
|
+
const filterWhere = Object.entries(options.filters ?? {}).map(([key, value]) => {
|
|
151
|
+
const param = searchParams.get(key);
|
|
152
|
+
if (param) {
|
|
153
|
+
return eq2(
|
|
154
|
+
repository.schema[key],
|
|
155
|
+
decodeURIComponent(param)
|
|
156
|
+
);
|
|
157
|
+
}
|
|
158
|
+
return void 0;
|
|
159
|
+
}).filter(Boolean);
|
|
161
160
|
const whereClauses = and(
|
|
162
161
|
searchKey && query ? ilike(
|
|
163
162
|
repository.schema[searchKey],
|
|
164
163
|
`%${query}%`
|
|
165
164
|
) : void 0,
|
|
166
|
-
...
|
|
165
|
+
...filterWhere,
|
|
166
|
+
where
|
|
167
167
|
);
|
|
168
168
|
const total = await repository.countTotal({ where: whereClauses });
|
|
169
169
|
const items = await repository.findAll({
|
|
@@ -173,6 +173,14 @@ async function loadTable({
|
|
|
173
173
|
offset,
|
|
174
174
|
where: whereClauses
|
|
175
175
|
});
|
|
176
|
+
const filters = Object.fromEntries(
|
|
177
|
+
await Promise.all(
|
|
178
|
+
Object.keys(options.filters ?? {}).map(async (key) => {
|
|
179
|
+
const values = await repository.select(key);
|
|
180
|
+
return [key, values.filter(Boolean)];
|
|
181
|
+
})
|
|
182
|
+
)
|
|
183
|
+
);
|
|
176
184
|
return {
|
|
177
185
|
items,
|
|
178
186
|
total,
|
|
@@ -180,7 +188,8 @@ async function loadTable({
|
|
|
180
188
|
offset,
|
|
181
189
|
orderBy,
|
|
182
190
|
direction,
|
|
183
|
-
searchKey
|
|
191
|
+
searchKey,
|
|
192
|
+
filters
|
|
184
193
|
};
|
|
185
194
|
}
|
|
186
195
|
|
|
@@ -201,13 +210,6 @@ function tableLoader({
|
|
|
201
210
|
};
|
|
202
211
|
}
|
|
203
212
|
|
|
204
|
-
// src/table/page.tsx
|
|
205
|
-
import { Link as Link3, useLocation as useLocation3 } from "react-router";
|
|
206
|
-
|
|
207
|
-
// src/table/table_form.tsx
|
|
208
|
-
import { useLocation as useLocation2, useNavigate, useSearchParams as useSearchParams3 } from "react-router";
|
|
209
|
-
import { GoSearch } from "react-icons/go";
|
|
210
|
-
|
|
211
213
|
// src/table/table.tsx
|
|
212
214
|
import { cn as cn2 } from "dn-react-toolkit/utils";
|
|
213
215
|
import { GoArrowDown, GoArrowUp } from "react-icons/go";
|
|
@@ -222,7 +224,8 @@ function Table({
|
|
|
222
224
|
limit,
|
|
223
225
|
offset,
|
|
224
226
|
orderBy,
|
|
225
|
-
direction
|
|
227
|
+
direction,
|
|
228
|
+
filters
|
|
226
229
|
}) {
|
|
227
230
|
const keys = Object.entries(columns).filter((entry) => entry[1]).map(([key]) => key);
|
|
228
231
|
const sortedArray = [...data];
|
|
@@ -247,8 +250,8 @@ function Table({
|
|
|
247
250
|
"button",
|
|
248
251
|
{
|
|
249
252
|
className: cn2(
|
|
250
|
-
orderBy === key ? "text-
|
|
251
|
-
"px-4
|
|
253
|
+
orderBy === key ? "text-gray-900 font-medium" : "text-gray-500 font-medium",
|
|
254
|
+
"px-4 flex items-center w-full"
|
|
252
255
|
),
|
|
253
256
|
onClick: () => {
|
|
254
257
|
let newDirection = "asc";
|
|
@@ -269,14 +272,45 @@ function Table({
|
|
|
269
272
|
}
|
|
270
273
|
return /* @__PURE__ */ jsx2(Fragment2, { children: reactNode });
|
|
271
274
|
}
|
|
272
|
-
|
|
275
|
+
const filter = filters?.[key];
|
|
276
|
+
return /* @__PURE__ */ jsxs2(
|
|
277
|
+
"th",
|
|
278
|
+
{
|
|
279
|
+
className: cn2("py-4 border-y font-normal align-top"),
|
|
280
|
+
children: [
|
|
281
|
+
/* @__PURE__ */ jsx2(Head, {}),
|
|
282
|
+
filter && /* @__PURE__ */ jsx2("div", { className: "px-3 mt-4", children: /* @__PURE__ */ jsxs2(
|
|
283
|
+
"select",
|
|
284
|
+
{
|
|
285
|
+
className: "w-full h-10 px-1.5 border rounded-full outline-none",
|
|
286
|
+
onChange: (e) => {
|
|
287
|
+
const value2 = e.target.value;
|
|
288
|
+
setSearchParams((prev) => {
|
|
289
|
+
if (value2) {
|
|
290
|
+
prev.set(key, encodeURIComponent(value2));
|
|
291
|
+
} else {
|
|
292
|
+
prev.delete(key);
|
|
293
|
+
}
|
|
294
|
+
return prev;
|
|
295
|
+
});
|
|
296
|
+
},
|
|
297
|
+
children: [
|
|
298
|
+
/* @__PURE__ */ jsx2("option", { value: "", children: "\uC804\uCCB4" }),
|
|
299
|
+
filter.map((option) => /* @__PURE__ */ jsx2("option", { value: option, children: option }, option))
|
|
300
|
+
]
|
|
301
|
+
}
|
|
302
|
+
) })
|
|
303
|
+
]
|
|
304
|
+
},
|
|
305
|
+
key
|
|
306
|
+
);
|
|
273
307
|
}) }) }),
|
|
274
308
|
/* @__PURE__ */ jsxs2("tbody", { children: [
|
|
275
309
|
sortedArray.length === 0 && /* @__PURE__ */ jsx2("tr", { children: /* @__PURE__ */ jsx2(
|
|
276
310
|
"td",
|
|
277
311
|
{
|
|
278
312
|
colSpan: keys.length,
|
|
279
|
-
className: "px-4 h-
|
|
313
|
+
className: "px-4 h-20 text-gray-400 text-center",
|
|
280
314
|
children: "\uB370\uC774\uD130\uAC00 \uC5C6\uC2B5\uB2C8\uB2E4."
|
|
281
315
|
}
|
|
282
316
|
) }),
|
|
@@ -301,7 +335,7 @@ function Table({
|
|
|
301
335
|
className: "block content-center px-4 w-full h-full",
|
|
302
336
|
children: /* @__PURE__ */ jsx2(Content, {})
|
|
303
337
|
}
|
|
304
|
-
) : /* @__PURE__ */ jsx2(Content, {});
|
|
338
|
+
) : /* @__PURE__ */ jsx2("div", { className: "px-4 w-full h-full content-center", children: /* @__PURE__ */ jsx2(Content, {}) });
|
|
305
339
|
const cell = Mapper ? /* @__PURE__ */ jsx2(Mapper, { item, index: i2, children: linkedContent }) : linkedContent;
|
|
306
340
|
return /* @__PURE__ */ jsx2("td", { className: "px-0 h-14 border-b", children: cell }, key);
|
|
307
341
|
}) }, i))
|
|
@@ -311,20 +345,15 @@ function Table({
|
|
|
311
345
|
);
|
|
312
346
|
}
|
|
313
347
|
|
|
348
|
+
// src/table/table_form.tsx
|
|
349
|
+
import { useLocation as useLocation2, useNavigate, useSearchParams as useSearchParams3 } from "react-router";
|
|
350
|
+
import { GoSearch } from "react-icons/go";
|
|
351
|
+
|
|
314
352
|
// src/table/use_table.tsx
|
|
315
353
|
import { useLoaderData } from "react-router";
|
|
316
354
|
function useTable() {
|
|
317
355
|
const { table } = useLoaderData();
|
|
318
|
-
|
|
319
|
-
return {
|
|
320
|
-
items,
|
|
321
|
-
total,
|
|
322
|
-
limit,
|
|
323
|
-
offset,
|
|
324
|
-
orderBy,
|
|
325
|
-
direction,
|
|
326
|
-
searchKey
|
|
327
|
-
};
|
|
356
|
+
return table;
|
|
328
357
|
}
|
|
329
358
|
|
|
330
359
|
// src/table/table_form.tsx
|
|
@@ -334,7 +363,16 @@ function TableForm({
|
|
|
334
363
|
primaryKey = "id"
|
|
335
364
|
}) {
|
|
336
365
|
const { pathname } = useLocation2();
|
|
337
|
-
const {
|
|
366
|
+
const {
|
|
367
|
+
items,
|
|
368
|
+
total,
|
|
369
|
+
limit,
|
|
370
|
+
offset,
|
|
371
|
+
orderBy,
|
|
372
|
+
direction,
|
|
373
|
+
searchKey,
|
|
374
|
+
filters
|
|
375
|
+
} = useTable();
|
|
338
376
|
const navigate = useNavigate();
|
|
339
377
|
const search = (query) => {
|
|
340
378
|
const searchParams2 = new URLSearchParams(window.location.search);
|
|
@@ -347,7 +385,7 @@ function TableForm({
|
|
|
347
385
|
searchKey && /* @__PURE__ */ jsxs3(
|
|
348
386
|
"form",
|
|
349
387
|
{
|
|
350
|
-
className: "h-
|
|
388
|
+
className: "h-20 px-4 flex items-center border-t",
|
|
351
389
|
onSubmit: (e) => {
|
|
352
390
|
e.preventDefault();
|
|
353
391
|
const formData = new FormData(e.currentTarget);
|
|
@@ -384,7 +422,8 @@ function TableForm({
|
|
|
384
422
|
limit,
|
|
385
423
|
offset,
|
|
386
424
|
orderBy,
|
|
387
|
-
direction
|
|
425
|
+
direction,
|
|
426
|
+
filters
|
|
388
427
|
}
|
|
389
428
|
),
|
|
390
429
|
/* @__PURE__ */ jsx3(
|
|
@@ -398,41 +437,12 @@ function TableForm({
|
|
|
398
437
|
)
|
|
399
438
|
] });
|
|
400
439
|
}
|
|
401
|
-
|
|
402
|
-
// src/table/page.tsx
|
|
403
|
-
import { Fragment as Fragment4, jsx as jsx4, jsxs as jsxs4 } from "react/jsx-runtime";
|
|
404
|
-
function createTablePage({
|
|
405
|
-
name,
|
|
406
|
-
columns,
|
|
407
|
-
primaryKey = "id"
|
|
408
|
-
}) {
|
|
409
|
-
return function TablePage({
|
|
410
|
-
header: Header
|
|
411
|
-
}) {
|
|
412
|
-
const { pathname } = useLocation3();
|
|
413
|
-
return /* @__PURE__ */ jsxs4(Fragment4, { children: [
|
|
414
|
-
/* @__PURE__ */ jsx4(
|
|
415
|
-
Header,
|
|
416
|
-
{
|
|
417
|
-
title: name,
|
|
418
|
-
actions: /* @__PURE__ */ jsxs4(Link3, { to: `${pathname}/new`, className: "button-primary", children: [
|
|
419
|
-
name,
|
|
420
|
-
" \uCD94\uAC00"
|
|
421
|
-
] })
|
|
422
|
-
}
|
|
423
|
-
),
|
|
424
|
-
/* @__PURE__ */ jsx4("div", { className: "max-w-7xl mx-auto w-full overflow-auto", children: /* @__PURE__ */ jsx4(TableForm, { columns, primaryKey }) })
|
|
425
|
-
] });
|
|
426
|
-
};
|
|
427
|
-
}
|
|
428
440
|
export {
|
|
429
441
|
BaseTableRepository,
|
|
430
442
|
Table,
|
|
431
443
|
TableForm,
|
|
432
444
|
TablePageButtons,
|
|
433
|
-
createTablePage,
|
|
434
445
|
loadTable,
|
|
435
|
-
tableItemloader,
|
|
436
446
|
tableLoader,
|
|
437
447
|
useTable
|
|
438
448
|
};
|
|
@@ -1,13 +1,16 @@
|
|
|
1
1
|
import { SQLWrapper, InferSelectModel } from 'drizzle-orm';
|
|
2
|
-
import { TableRepository, ColumnOf } from './repository.mjs';
|
|
3
2
|
import { PgTableWithColumns } from 'drizzle-orm/pg-core';
|
|
3
|
+
import { TableRepository, ColumnOf } from './repository.mjs';
|
|
4
4
|
import 'drizzle-orm/node-postgres';
|
|
5
5
|
|
|
6
6
|
type TableOptions<T extends PgTableWithColumns<any>> = {
|
|
7
|
-
where?: SQLWrapper
|
|
7
|
+
where?: SQLWrapper;
|
|
8
8
|
searchKey?: ColumnOf<T>;
|
|
9
9
|
defaultOrderBy: keyof InferSelectModel<T>;
|
|
10
10
|
defaultDirection: "asc" | "desc";
|
|
11
|
+
filters?: {
|
|
12
|
+
[key in keyof InferSelectModel<T>]?: "auto";
|
|
13
|
+
};
|
|
11
14
|
};
|
|
12
15
|
type TableLoaderOptions<T extends PgTableWithColumns<any>, TSelect> = {
|
|
13
16
|
repository: TableRepository<T, TSelect>;
|
|
@@ -25,6 +28,9 @@ declare function loadTable<T extends PgTableWithColumns<any>, TSelect>({ request
|
|
|
25
28
|
orderBy: keyof T["_"]["columns"] & string;
|
|
26
29
|
direction: "asc" | "desc";
|
|
27
30
|
searchKey: ColumnOf<T> | undefined;
|
|
31
|
+
filters: {
|
|
32
|
+
[k: string]: unknown[];
|
|
33
|
+
};
|
|
28
34
|
}>;
|
|
29
35
|
|
|
30
36
|
export { type TableLoaderOptions, loadTable };
|
|
@@ -1,13 +1,16 @@
|
|
|
1
1
|
import { SQLWrapper, InferSelectModel } from 'drizzle-orm';
|
|
2
|
-
import { TableRepository, ColumnOf } from './repository.js';
|
|
3
2
|
import { PgTableWithColumns } from 'drizzle-orm/pg-core';
|
|
3
|
+
import { TableRepository, ColumnOf } from './repository.js';
|
|
4
4
|
import 'drizzle-orm/node-postgres';
|
|
5
5
|
|
|
6
6
|
type TableOptions<T extends PgTableWithColumns<any>> = {
|
|
7
|
-
where?: SQLWrapper
|
|
7
|
+
where?: SQLWrapper;
|
|
8
8
|
searchKey?: ColumnOf<T>;
|
|
9
9
|
defaultOrderBy: keyof InferSelectModel<T>;
|
|
10
10
|
defaultDirection: "asc" | "desc";
|
|
11
|
+
filters?: {
|
|
12
|
+
[key in keyof InferSelectModel<T>]?: "auto";
|
|
13
|
+
};
|
|
11
14
|
};
|
|
12
15
|
type TableLoaderOptions<T extends PgTableWithColumns<any>, TSelect> = {
|
|
13
16
|
repository: TableRepository<T, TSelect>;
|
|
@@ -25,6 +28,9 @@ declare function loadTable<T extends PgTableWithColumns<any>, TSelect>({ request
|
|
|
25
28
|
orderBy: keyof T["_"]["columns"] & string;
|
|
26
29
|
direction: "asc" | "desc";
|
|
27
30
|
searchKey: ColumnOf<T> | undefined;
|
|
31
|
+
filters: {
|
|
32
|
+
[k: string]: unknown[];
|
|
33
|
+
};
|
|
28
34
|
}>;
|
|
29
35
|
|
|
30
36
|
export { type TableLoaderOptions, loadTable };
|