dn-react-router-toolkit 0.8.0 → 0.8.1
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/crud_loader.js +34 -5
- package/dist/crud/crud_loader.mjs +36 -6
- package/dist/crud/crud_page.js +69 -19
- package/dist/crud/crud_page.mjs +69 -19
- package/dist/crud/index.js +109 -30
- package/dist/crud/index.mjs +111 -31
- package/dist/post/index.js +6 -6
- package/dist/post/index.mjs +8 -7
- package/dist/post/post_form_page.js +6 -6
- package/dist/post/post_form_page.mjs +8 -7
- package/dist/table/index.d.mts +1 -1
- package/dist/table/index.d.ts +1 -1
- package/dist/table/index.js +94 -20
- package/dist/table/index.mjs +95 -20
- package/dist/table/load_table.d.mts +7 -1
- package/dist/table/load_table.d.ts +7 -1
- package/dist/table/load_table.js +21 -1
- package/dist/table/load_table.mjs +22 -1
- package/dist/table/loader.d.mts +3 -0
- package/dist/table/loader.d.ts +3 -0
- package/dist/table/loader.js +21 -1
- package/dist/table/loader.mjs +22 -1
- package/dist/table/page.js +69 -19
- package/dist/table/page.mjs +69 -19
- 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 +4 -1
- package/dist/table/table.d.ts +4 -1
- package/dist/table/table.js +55 -6
- package/dist/table/table.mjs +55 -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 +69 -19
- package/dist/table/table_form.mjs +69 -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 +2 -2
package/dist/api/index.js
CHANGED
|
@@ -379,18 +379,27 @@ function apiHandler({
|
|
|
379
379
|
var import_http3 = require("dn-react-toolkit/http");
|
|
380
380
|
function itemApiHandler({
|
|
381
381
|
withAuthAction,
|
|
382
|
-
repository
|
|
382
|
+
repository,
|
|
383
|
+
isOwnedBy,
|
|
384
|
+
roles
|
|
383
385
|
}) {
|
|
384
386
|
const loader = async ({ request }) => {
|
|
385
387
|
return {};
|
|
386
388
|
};
|
|
387
389
|
const action = withAuthAction((auth) => async ({ params, request }) => {
|
|
388
|
-
if (!auth || auth.role
|
|
389
|
-
|
|
390
|
+
if (roles && roles.length > 0 && (!auth || !roles.includes(auth.role))) {
|
|
391
|
+
throw (0, import_http3.UNAUTHORIZED)();
|
|
392
|
+
}
|
|
393
|
+
const itemId = params.itemId;
|
|
394
|
+
const existing = await repository.find(itemId);
|
|
395
|
+
if (!existing) {
|
|
396
|
+
throw (0, import_http3.NOT_FOUND)();
|
|
397
|
+
}
|
|
398
|
+
if (isOwnedBy && !isOwnedBy(existing, auth)) {
|
|
399
|
+
throw (0, import_http3.FORBIDDEN)();
|
|
390
400
|
}
|
|
391
401
|
switch (request.method) {
|
|
392
402
|
case "DELETE": {
|
|
393
|
-
const itemId = params.itemId;
|
|
394
403
|
await repository.delete(itemId);
|
|
395
404
|
return {};
|
|
396
405
|
}
|
package/dist/api/index.mjs
CHANGED
|
@@ -371,21 +371,30 @@ function apiHandler({
|
|
|
371
371
|
}
|
|
372
372
|
|
|
373
373
|
// src/api/item_api_handler.ts
|
|
374
|
-
import { UNAUTHORIZED as UNAUTHORIZED2 } from "dn-react-toolkit/http";
|
|
374
|
+
import { FORBIDDEN, NOT_FOUND as NOT_FOUND2, UNAUTHORIZED as UNAUTHORIZED2 } from "dn-react-toolkit/http";
|
|
375
375
|
function itemApiHandler({
|
|
376
376
|
withAuthAction,
|
|
377
|
-
repository
|
|
377
|
+
repository,
|
|
378
|
+
isOwnedBy,
|
|
379
|
+
roles
|
|
378
380
|
}) {
|
|
379
381
|
const loader = async ({ request }) => {
|
|
380
382
|
return {};
|
|
381
383
|
};
|
|
382
384
|
const action = withAuthAction((auth) => async ({ params, request }) => {
|
|
383
|
-
if (!auth || auth.role
|
|
384
|
-
|
|
385
|
+
if (roles && roles.length > 0 && (!auth || !roles.includes(auth.role))) {
|
|
386
|
+
throw UNAUTHORIZED2();
|
|
387
|
+
}
|
|
388
|
+
const itemId = params.itemId;
|
|
389
|
+
const existing = await repository.find(itemId);
|
|
390
|
+
if (!existing) {
|
|
391
|
+
throw NOT_FOUND2();
|
|
392
|
+
}
|
|
393
|
+
if (isOwnedBy && !isOwnedBy(existing, auth)) {
|
|
394
|
+
throw FORBIDDEN();
|
|
385
395
|
}
|
|
386
396
|
switch (request.method) {
|
|
387
397
|
case "DELETE": {
|
|
388
|
-
const itemId = params.itemId;
|
|
389
398
|
await repository.delete(itemId);
|
|
390
399
|
return {};
|
|
391
400
|
}
|
|
@@ -2,16 +2,18 @@ import { LoaderFunctionArgs } from 'react-router';
|
|
|
2
2
|
import { TableRepository } from '../table/repository.mjs';
|
|
3
3
|
import { PgTableWithColumns } from 'drizzle-orm/pg-core';
|
|
4
4
|
import { WithAuthHandler } from '../auth/with_auth.mjs';
|
|
5
|
+
import { AccessTokenPayload } from 'dn-react-toolkit/auth';
|
|
5
6
|
import 'drizzle-orm';
|
|
6
7
|
import 'drizzle-orm/node-postgres';
|
|
7
|
-
import 'dn-react-toolkit/auth';
|
|
8
8
|
import 'dn-react-toolkit/auth/server';
|
|
9
9
|
|
|
10
10
|
type ItemAPIHandlerOptions<T extends PgTableWithColumns<any>, TSelect> = {
|
|
11
11
|
withAuthAction: WithAuthHandler<LoaderFunctionArgs>;
|
|
12
12
|
repository: TableRepository<T, TSelect>;
|
|
13
|
+
isOwnedBy?: (item: TSelect, auth: AccessTokenPayload | undefined) => boolean;
|
|
14
|
+
roles?: string[];
|
|
13
15
|
};
|
|
14
|
-
declare function itemApiHandler<T extends PgTableWithColumns<any>, TSelect>({ withAuthAction, repository, }: ItemAPIHandlerOptions<T, TSelect>): {
|
|
16
|
+
declare function itemApiHandler<T extends PgTableWithColumns<any>, TSelect>({ withAuthAction, repository, isOwnedBy, roles, }: ItemAPIHandlerOptions<T, TSelect>): {
|
|
15
17
|
loader: ({ request }: LoaderFunctionArgs) => Promise<{}>;
|
|
16
18
|
action: (arg: LoaderFunctionArgs<any>) => Promise<unknown> | unknown;
|
|
17
19
|
};
|
|
@@ -2,16 +2,18 @@ import { LoaderFunctionArgs } from 'react-router';
|
|
|
2
2
|
import { TableRepository } from '../table/repository.js';
|
|
3
3
|
import { PgTableWithColumns } from 'drizzle-orm/pg-core';
|
|
4
4
|
import { WithAuthHandler } from '../auth/with_auth.js';
|
|
5
|
+
import { AccessTokenPayload } from 'dn-react-toolkit/auth';
|
|
5
6
|
import 'drizzle-orm';
|
|
6
7
|
import 'drizzle-orm/node-postgres';
|
|
7
|
-
import 'dn-react-toolkit/auth';
|
|
8
8
|
import 'dn-react-toolkit/auth/server';
|
|
9
9
|
|
|
10
10
|
type ItemAPIHandlerOptions<T extends PgTableWithColumns<any>, TSelect> = {
|
|
11
11
|
withAuthAction: WithAuthHandler<LoaderFunctionArgs>;
|
|
12
12
|
repository: TableRepository<T, TSelect>;
|
|
13
|
+
isOwnedBy?: (item: TSelect, auth: AccessTokenPayload | undefined) => boolean;
|
|
14
|
+
roles?: string[];
|
|
13
15
|
};
|
|
14
|
-
declare function itemApiHandler<T extends PgTableWithColumns<any>, TSelect>({ withAuthAction, repository, }: ItemAPIHandlerOptions<T, TSelect>): {
|
|
16
|
+
declare function itemApiHandler<T extends PgTableWithColumns<any>, TSelect>({ withAuthAction, repository, isOwnedBy, roles, }: ItemAPIHandlerOptions<T, TSelect>): {
|
|
15
17
|
loader: ({ request }: LoaderFunctionArgs) => Promise<{}>;
|
|
16
18
|
action: (arg: LoaderFunctionArgs<any>) => Promise<unknown> | unknown;
|
|
17
19
|
};
|
|
@@ -26,18 +26,27 @@ module.exports = __toCommonJS(item_api_handler_exports);
|
|
|
26
26
|
var import_http = require("dn-react-toolkit/http");
|
|
27
27
|
function itemApiHandler({
|
|
28
28
|
withAuthAction,
|
|
29
|
-
repository
|
|
29
|
+
repository,
|
|
30
|
+
isOwnedBy,
|
|
31
|
+
roles
|
|
30
32
|
}) {
|
|
31
33
|
const loader = async ({ request }) => {
|
|
32
34
|
return {};
|
|
33
35
|
};
|
|
34
36
|
const action = withAuthAction((auth) => async ({ params, request }) => {
|
|
35
|
-
if (!auth || auth.role
|
|
36
|
-
|
|
37
|
+
if (roles && roles.length > 0 && (!auth || !roles.includes(auth.role))) {
|
|
38
|
+
throw (0, import_http.UNAUTHORIZED)();
|
|
39
|
+
}
|
|
40
|
+
const itemId = params.itemId;
|
|
41
|
+
const existing = await repository.find(itemId);
|
|
42
|
+
if (!existing) {
|
|
43
|
+
throw (0, import_http.NOT_FOUND)();
|
|
44
|
+
}
|
|
45
|
+
if (isOwnedBy && !isOwnedBy(existing, auth)) {
|
|
46
|
+
throw (0, import_http.FORBIDDEN)();
|
|
37
47
|
}
|
|
38
48
|
switch (request.method) {
|
|
39
49
|
case "DELETE": {
|
|
40
|
-
const itemId = params.itemId;
|
|
41
50
|
await repository.delete(itemId);
|
|
42
51
|
return {};
|
|
43
52
|
}
|
|
@@ -1,19 +1,28 @@
|
|
|
1
1
|
// src/api/item_api_handler.ts
|
|
2
|
-
import { UNAUTHORIZED } from "dn-react-toolkit/http";
|
|
2
|
+
import { FORBIDDEN, NOT_FOUND, UNAUTHORIZED } from "dn-react-toolkit/http";
|
|
3
3
|
function itemApiHandler({
|
|
4
4
|
withAuthAction,
|
|
5
|
-
repository
|
|
5
|
+
repository,
|
|
6
|
+
isOwnedBy,
|
|
7
|
+
roles
|
|
6
8
|
}) {
|
|
7
9
|
const loader = async ({ request }) => {
|
|
8
10
|
return {};
|
|
9
11
|
};
|
|
10
12
|
const action = withAuthAction((auth) => async ({ params, request }) => {
|
|
11
|
-
if (!auth || auth.role
|
|
12
|
-
|
|
13
|
+
if (roles && roles.length > 0 && (!auth || !roles.includes(auth.role))) {
|
|
14
|
+
throw UNAUTHORIZED();
|
|
15
|
+
}
|
|
16
|
+
const itemId = params.itemId;
|
|
17
|
+
const existing = await repository.find(itemId);
|
|
18
|
+
if (!existing) {
|
|
19
|
+
throw NOT_FOUND();
|
|
20
|
+
}
|
|
21
|
+
if (isOwnedBy && !isOwnedBy(existing, auth)) {
|
|
22
|
+
throw FORBIDDEN();
|
|
13
23
|
}
|
|
14
24
|
switch (request.method) {
|
|
15
25
|
case "DELETE": {
|
|
16
|
-
const itemId = params.itemId;
|
|
17
26
|
await repository.delete(itemId);
|
|
18
27
|
return {};
|
|
19
28
|
}
|
package/dist/crud/crud_loader.js
CHANGED
|
@@ -38,11 +38,22 @@ async function loadTable({
|
|
|
38
38
|
const offset = Number(searchParams.get("offset") ?? "0");
|
|
39
39
|
const orderBy = searchParams.get("orderBy") ?? defaultOrderBy;
|
|
40
40
|
const direction = searchParams.get("direction") ?? defaultDirection;
|
|
41
|
+
const filterWhere = Object.entries(options.filters ?? {}).map(([key, value]) => {
|
|
42
|
+
const param = searchParams.get(key);
|
|
43
|
+
if (param) {
|
|
44
|
+
return (0, import_drizzle_orm.eq)(
|
|
45
|
+
repository.schema[key],
|
|
46
|
+
decodeURIComponent(param)
|
|
47
|
+
);
|
|
48
|
+
}
|
|
49
|
+
return void 0;
|
|
50
|
+
}).filter(Boolean);
|
|
41
51
|
const whereClauses = (0, import_drizzle_orm.and)(
|
|
42
52
|
searchKey && query ? (0, import_drizzle_orm.ilike)(
|
|
43
53
|
repository.schema[searchKey],
|
|
44
54
|
`%${query}%`
|
|
45
55
|
) : void 0,
|
|
56
|
+
...filterWhere,
|
|
46
57
|
...where ?? []
|
|
47
58
|
);
|
|
48
59
|
const total = await repository.countTotal({ where: whereClauses });
|
|
@@ -53,6 +64,14 @@ async function loadTable({
|
|
|
53
64
|
offset,
|
|
54
65
|
where: whereClauses
|
|
55
66
|
});
|
|
67
|
+
const filters = Object.fromEntries(
|
|
68
|
+
await Promise.all(
|
|
69
|
+
Object.keys(options.filters ?? {}).map(async (key) => {
|
|
70
|
+
const values = await repository.select(key);
|
|
71
|
+
return [key, values.filter(Boolean)];
|
|
72
|
+
})
|
|
73
|
+
)
|
|
74
|
+
);
|
|
56
75
|
return {
|
|
57
76
|
items,
|
|
58
77
|
total,
|
|
@@ -60,7 +79,8 @@ async function loadTable({
|
|
|
60
79
|
offset,
|
|
61
80
|
orderBy,
|
|
62
81
|
direction,
|
|
63
|
-
searchKey
|
|
82
|
+
searchKey,
|
|
83
|
+
filters
|
|
64
84
|
};
|
|
65
85
|
}
|
|
66
86
|
|
|
@@ -229,18 +249,27 @@ function apiHandler({
|
|
|
229
249
|
var import_http2 = require("dn-react-toolkit/http");
|
|
230
250
|
function itemApiHandler({
|
|
231
251
|
withAuthAction,
|
|
232
|
-
repository
|
|
252
|
+
repository,
|
|
253
|
+
isOwnedBy,
|
|
254
|
+
roles
|
|
233
255
|
}) {
|
|
234
256
|
const loader = async ({ request }) => {
|
|
235
257
|
return {};
|
|
236
258
|
};
|
|
237
259
|
const action = withAuthAction((auth) => async ({ params, request }) => {
|
|
238
|
-
if (!auth || auth.role
|
|
239
|
-
|
|
260
|
+
if (roles && roles.length > 0 && (!auth || !roles.includes(auth.role))) {
|
|
261
|
+
throw (0, import_http2.UNAUTHORIZED)();
|
|
262
|
+
}
|
|
263
|
+
const itemId = params.itemId;
|
|
264
|
+
const existing = await repository.find(itemId);
|
|
265
|
+
if (!existing) {
|
|
266
|
+
throw (0, import_http2.NOT_FOUND)();
|
|
267
|
+
}
|
|
268
|
+
if (isOwnedBy && !isOwnedBy(existing, auth)) {
|
|
269
|
+
throw (0, import_http2.FORBIDDEN)();
|
|
240
270
|
}
|
|
241
271
|
switch (request.method) {
|
|
242
272
|
case "DELETE": {
|
|
243
|
-
const itemId = params.itemId;
|
|
244
273
|
await repository.delete(itemId);
|
|
245
274
|
return {};
|
|
246
275
|
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
// src/table/load_table.tsx
|
|
2
2
|
import {
|
|
3
3
|
and,
|
|
4
|
+
eq,
|
|
4
5
|
ilike
|
|
5
6
|
} from "drizzle-orm";
|
|
6
7
|
async function loadTable({
|
|
@@ -15,11 +16,22 @@ async function loadTable({
|
|
|
15
16
|
const offset = Number(searchParams.get("offset") ?? "0");
|
|
16
17
|
const orderBy = searchParams.get("orderBy") ?? defaultOrderBy;
|
|
17
18
|
const direction = searchParams.get("direction") ?? defaultDirection;
|
|
19
|
+
const filterWhere = Object.entries(options.filters ?? {}).map(([key, value]) => {
|
|
20
|
+
const param = searchParams.get(key);
|
|
21
|
+
if (param) {
|
|
22
|
+
return eq(
|
|
23
|
+
repository.schema[key],
|
|
24
|
+
decodeURIComponent(param)
|
|
25
|
+
);
|
|
26
|
+
}
|
|
27
|
+
return void 0;
|
|
28
|
+
}).filter(Boolean);
|
|
18
29
|
const whereClauses = and(
|
|
19
30
|
searchKey && query ? ilike(
|
|
20
31
|
repository.schema[searchKey],
|
|
21
32
|
`%${query}%`
|
|
22
33
|
) : void 0,
|
|
34
|
+
...filterWhere,
|
|
23
35
|
...where ?? []
|
|
24
36
|
);
|
|
25
37
|
const total = await repository.countTotal({ where: whereClauses });
|
|
@@ -30,6 +42,14 @@ async function loadTable({
|
|
|
30
42
|
offset,
|
|
31
43
|
where: whereClauses
|
|
32
44
|
});
|
|
45
|
+
const filters = Object.fromEntries(
|
|
46
|
+
await Promise.all(
|
|
47
|
+
Object.keys(options.filters ?? {}).map(async (key) => {
|
|
48
|
+
const values = await repository.select(key);
|
|
49
|
+
return [key, values.filter(Boolean)];
|
|
50
|
+
})
|
|
51
|
+
)
|
|
52
|
+
);
|
|
33
53
|
return {
|
|
34
54
|
items,
|
|
35
55
|
total,
|
|
@@ -37,7 +57,8 @@ async function loadTable({
|
|
|
37
57
|
offset,
|
|
38
58
|
orderBy,
|
|
39
59
|
direction,
|
|
40
|
-
searchKey
|
|
60
|
+
searchKey,
|
|
61
|
+
filters
|
|
41
62
|
};
|
|
42
63
|
}
|
|
43
64
|
|
|
@@ -212,21 +233,30 @@ function apiHandler({
|
|
|
212
233
|
}
|
|
213
234
|
|
|
214
235
|
// src/api/item_api_handler.ts
|
|
215
|
-
import { UNAUTHORIZED as UNAUTHORIZED2 } from "dn-react-toolkit/http";
|
|
236
|
+
import { FORBIDDEN, NOT_FOUND, UNAUTHORIZED as UNAUTHORIZED2 } from "dn-react-toolkit/http";
|
|
216
237
|
function itemApiHandler({
|
|
217
238
|
withAuthAction,
|
|
218
|
-
repository
|
|
239
|
+
repository,
|
|
240
|
+
isOwnedBy,
|
|
241
|
+
roles
|
|
219
242
|
}) {
|
|
220
243
|
const loader = async ({ request }) => {
|
|
221
244
|
return {};
|
|
222
245
|
};
|
|
223
246
|
const action = withAuthAction((auth) => async ({ params, request }) => {
|
|
224
|
-
if (!auth || auth.role
|
|
225
|
-
|
|
247
|
+
if (roles && roles.length > 0 && (!auth || !roles.includes(auth.role))) {
|
|
248
|
+
throw UNAUTHORIZED2();
|
|
249
|
+
}
|
|
250
|
+
const itemId = params.itemId;
|
|
251
|
+
const existing = await repository.find(itemId);
|
|
252
|
+
if (!existing) {
|
|
253
|
+
throw NOT_FOUND();
|
|
254
|
+
}
|
|
255
|
+
if (isOwnedBy && !isOwnedBy(existing, auth)) {
|
|
256
|
+
throw FORBIDDEN();
|
|
226
257
|
}
|
|
227
258
|
switch (request.method) {
|
|
228
259
|
case "DELETE": {
|
|
229
|
-
const itemId = params.itemId;
|
|
230
260
|
await repository.delete(itemId);
|
|
231
261
|
return {};
|
|
232
262
|
}
|
package/dist/crud/crud_page.js
CHANGED
|
@@ -195,7 +195,8 @@ function Table({
|
|
|
195
195
|
limit,
|
|
196
196
|
offset,
|
|
197
197
|
orderBy,
|
|
198
|
-
direction
|
|
198
|
+
direction,
|
|
199
|
+
filters
|
|
199
200
|
}) {
|
|
200
201
|
const keys = Object.entries(columns).filter((entry) => entry[1]).map(([key]) => key);
|
|
201
202
|
const sortedArray = [...data];
|
|
@@ -203,7 +204,10 @@ function Table({
|
|
|
203
204
|
return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
|
|
204
205
|
"table",
|
|
205
206
|
{
|
|
206
|
-
className: (0, import_utils2.cn)(
|
|
207
|
+
className: (0, import_utils2.cn)(
|
|
208
|
+
className,
|
|
209
|
+
"text-[15px] border-separate border-spacing-0"
|
|
210
|
+
),
|
|
207
211
|
children: [
|
|
208
212
|
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("thead", { children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("tr", { children: keys.map((key) => {
|
|
209
213
|
const value = columns[key];
|
|
@@ -220,8 +224,8 @@ function Table({
|
|
|
220
224
|
"button",
|
|
221
225
|
{
|
|
222
226
|
className: (0, import_utils2.cn)(
|
|
223
|
-
orderBy === key ? "text-
|
|
224
|
-
"px-4
|
|
227
|
+
orderBy === key ? "text-gray-900 font-medium" : "text-gray-500 font-medium",
|
|
228
|
+
"px-4 flex items-center w-full"
|
|
225
229
|
),
|
|
226
230
|
onClick: () => {
|
|
227
231
|
let newDirection = "asc";
|
|
@@ -242,14 +246,59 @@ function Table({
|
|
|
242
246
|
}
|
|
243
247
|
return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_jsx_runtime2.Fragment, { children: reactNode });
|
|
244
248
|
}
|
|
245
|
-
|
|
249
|
+
const filter = filters[key];
|
|
250
|
+
return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
|
|
251
|
+
"th",
|
|
252
|
+
{
|
|
253
|
+
className: (0, import_utils2.cn)(
|
|
254
|
+
"py-4 border-y font-normal align-top"
|
|
255
|
+
),
|
|
256
|
+
children: [
|
|
257
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Head, {}),
|
|
258
|
+
filter && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "px-3 mt-4", children: /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
|
|
259
|
+
"select",
|
|
260
|
+
{
|
|
261
|
+
className: "w-full h-10 px-1.5 border rounded-full outline-none",
|
|
262
|
+
onChange: (e) => {
|
|
263
|
+
const value2 = e.target.value;
|
|
264
|
+
setSearchParams((prev) => {
|
|
265
|
+
if (value2) {
|
|
266
|
+
prev.set(
|
|
267
|
+
key,
|
|
268
|
+
encodeURIComponent(
|
|
269
|
+
value2
|
|
270
|
+
)
|
|
271
|
+
);
|
|
272
|
+
} else {
|
|
273
|
+
prev.delete(key);
|
|
274
|
+
}
|
|
275
|
+
return prev;
|
|
276
|
+
});
|
|
277
|
+
},
|
|
278
|
+
children: [
|
|
279
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("option", { value: "", children: "\uC804\uCCB4" }),
|
|
280
|
+
filter.map((option) => /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
281
|
+
"option",
|
|
282
|
+
{
|
|
283
|
+
value: option,
|
|
284
|
+
children: option
|
|
285
|
+
},
|
|
286
|
+
option
|
|
287
|
+
))
|
|
288
|
+
]
|
|
289
|
+
}
|
|
290
|
+
) })
|
|
291
|
+
]
|
|
292
|
+
},
|
|
293
|
+
key
|
|
294
|
+
);
|
|
246
295
|
}) }) }),
|
|
247
296
|
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("tbody", { children: [
|
|
248
297
|
sortedArray.length === 0 && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("tr", { children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
249
298
|
"td",
|
|
250
299
|
{
|
|
251
300
|
colSpan: keys.length,
|
|
252
|
-
className: "px-4 h-
|
|
301
|
+
className: "px-4 h-20 text-gray-400 text-center",
|
|
253
302
|
children: "\uB370\uC774\uD130\uAC00 \uC5C6\uC2B5\uB2C8\uB2E4."
|
|
254
303
|
}
|
|
255
304
|
) }),
|
|
@@ -288,16 +337,7 @@ function Table({
|
|
|
288
337
|
var import_react_router3 = require("react-router");
|
|
289
338
|
function useTable() {
|
|
290
339
|
const { table } = (0, import_react_router3.useLoaderData)();
|
|
291
|
-
|
|
292
|
-
return {
|
|
293
|
-
items,
|
|
294
|
-
total,
|
|
295
|
-
limit,
|
|
296
|
-
offset,
|
|
297
|
-
orderBy,
|
|
298
|
-
direction,
|
|
299
|
-
searchKey
|
|
300
|
-
};
|
|
340
|
+
return table;
|
|
301
341
|
}
|
|
302
342
|
|
|
303
343
|
// src/table/buttons.tsx
|
|
@@ -380,7 +420,16 @@ function TableForm({
|
|
|
380
420
|
primaryKey = "id"
|
|
381
421
|
}) {
|
|
382
422
|
const { pathname } = (0, import_react_router5.useLocation)();
|
|
383
|
-
const {
|
|
423
|
+
const {
|
|
424
|
+
items,
|
|
425
|
+
total,
|
|
426
|
+
limit,
|
|
427
|
+
offset,
|
|
428
|
+
orderBy,
|
|
429
|
+
direction,
|
|
430
|
+
searchKey,
|
|
431
|
+
filters
|
|
432
|
+
} = useTable();
|
|
384
433
|
const navigate = (0, import_react_router5.useNavigate)();
|
|
385
434
|
const search = (query) => {
|
|
386
435
|
const searchParams2 = new URLSearchParams(window.location.search);
|
|
@@ -393,7 +442,7 @@ function TableForm({
|
|
|
393
442
|
searchKey && /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
|
|
394
443
|
"form",
|
|
395
444
|
{
|
|
396
|
-
className: "h-
|
|
445
|
+
className: "h-20 px-4 flex items-center border-t",
|
|
397
446
|
onSubmit: (e) => {
|
|
398
447
|
e.preventDefault();
|
|
399
448
|
const formData = new FormData(e.currentTarget);
|
|
@@ -430,7 +479,8 @@ function TableForm({
|
|
|
430
479
|
limit,
|
|
431
480
|
offset,
|
|
432
481
|
orderBy,
|
|
433
|
-
direction
|
|
482
|
+
direction,
|
|
483
|
+
filters
|
|
434
484
|
}
|
|
435
485
|
),
|
|
436
486
|
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
package/dist/crud/crud_page.mjs
CHANGED
|
@@ -174,7 +174,8 @@ function Table({
|
|
|
174
174
|
limit,
|
|
175
175
|
offset,
|
|
176
176
|
orderBy,
|
|
177
|
-
direction
|
|
177
|
+
direction,
|
|
178
|
+
filters
|
|
178
179
|
}) {
|
|
179
180
|
const keys = Object.entries(columns).filter((entry) => entry[1]).map(([key]) => key);
|
|
180
181
|
const sortedArray = [...data];
|
|
@@ -182,7 +183,10 @@ function Table({
|
|
|
182
183
|
return /* @__PURE__ */ jsxs(
|
|
183
184
|
"table",
|
|
184
185
|
{
|
|
185
|
-
className: cn(
|
|
186
|
+
className: cn(
|
|
187
|
+
className,
|
|
188
|
+
"text-[15px] border-separate border-spacing-0"
|
|
189
|
+
),
|
|
186
190
|
children: [
|
|
187
191
|
/* @__PURE__ */ jsx2("thead", { children: /* @__PURE__ */ jsx2("tr", { children: keys.map((key) => {
|
|
188
192
|
const value = columns[key];
|
|
@@ -199,8 +203,8 @@ function Table({
|
|
|
199
203
|
"button",
|
|
200
204
|
{
|
|
201
205
|
className: cn(
|
|
202
|
-
orderBy === key ? "text-
|
|
203
|
-
"px-4
|
|
206
|
+
orderBy === key ? "text-gray-900 font-medium" : "text-gray-500 font-medium",
|
|
207
|
+
"px-4 flex items-center w-full"
|
|
204
208
|
),
|
|
205
209
|
onClick: () => {
|
|
206
210
|
let newDirection = "asc";
|
|
@@ -221,14 +225,59 @@ function Table({
|
|
|
221
225
|
}
|
|
222
226
|
return /* @__PURE__ */ jsx2(Fragment, { children: reactNode });
|
|
223
227
|
}
|
|
224
|
-
|
|
228
|
+
const filter = filters[key];
|
|
229
|
+
return /* @__PURE__ */ jsxs(
|
|
230
|
+
"th",
|
|
231
|
+
{
|
|
232
|
+
className: cn(
|
|
233
|
+
"py-4 border-y font-normal align-top"
|
|
234
|
+
),
|
|
235
|
+
children: [
|
|
236
|
+
/* @__PURE__ */ jsx2(Head, {}),
|
|
237
|
+
filter && /* @__PURE__ */ jsx2("div", { className: "px-3 mt-4", children: /* @__PURE__ */ jsxs(
|
|
238
|
+
"select",
|
|
239
|
+
{
|
|
240
|
+
className: "w-full h-10 px-1.5 border rounded-full outline-none",
|
|
241
|
+
onChange: (e) => {
|
|
242
|
+
const value2 = e.target.value;
|
|
243
|
+
setSearchParams((prev) => {
|
|
244
|
+
if (value2) {
|
|
245
|
+
prev.set(
|
|
246
|
+
key,
|
|
247
|
+
encodeURIComponent(
|
|
248
|
+
value2
|
|
249
|
+
)
|
|
250
|
+
);
|
|
251
|
+
} else {
|
|
252
|
+
prev.delete(key);
|
|
253
|
+
}
|
|
254
|
+
return prev;
|
|
255
|
+
});
|
|
256
|
+
},
|
|
257
|
+
children: [
|
|
258
|
+
/* @__PURE__ */ jsx2("option", { value: "", children: "\uC804\uCCB4" }),
|
|
259
|
+
filter.map((option) => /* @__PURE__ */ jsx2(
|
|
260
|
+
"option",
|
|
261
|
+
{
|
|
262
|
+
value: option,
|
|
263
|
+
children: option
|
|
264
|
+
},
|
|
265
|
+
option
|
|
266
|
+
))
|
|
267
|
+
]
|
|
268
|
+
}
|
|
269
|
+
) })
|
|
270
|
+
]
|
|
271
|
+
},
|
|
272
|
+
key
|
|
273
|
+
);
|
|
225
274
|
}) }) }),
|
|
226
275
|
/* @__PURE__ */ jsxs("tbody", { children: [
|
|
227
276
|
sortedArray.length === 0 && /* @__PURE__ */ jsx2("tr", { children: /* @__PURE__ */ jsx2(
|
|
228
277
|
"td",
|
|
229
278
|
{
|
|
230
279
|
colSpan: keys.length,
|
|
231
|
-
className: "px-4 h-
|
|
280
|
+
className: "px-4 h-20 text-gray-400 text-center",
|
|
232
281
|
children: "\uB370\uC774\uD130\uAC00 \uC5C6\uC2B5\uB2C8\uB2E4."
|
|
233
282
|
}
|
|
234
283
|
) }),
|
|
@@ -267,16 +316,7 @@ function Table({
|
|
|
267
316
|
import { useLoaderData } from "react-router";
|
|
268
317
|
function useTable() {
|
|
269
318
|
const { table } = useLoaderData();
|
|
270
|
-
|
|
271
|
-
return {
|
|
272
|
-
items,
|
|
273
|
-
total,
|
|
274
|
-
limit,
|
|
275
|
-
offset,
|
|
276
|
-
orderBy,
|
|
277
|
-
direction,
|
|
278
|
-
searchKey
|
|
279
|
-
};
|
|
319
|
+
return table;
|
|
280
320
|
}
|
|
281
321
|
|
|
282
322
|
// src/table/buttons.tsx
|
|
@@ -359,7 +399,16 @@ function TableForm({
|
|
|
359
399
|
primaryKey = "id"
|
|
360
400
|
}) {
|
|
361
401
|
const { pathname } = useLocation2();
|
|
362
|
-
const {
|
|
402
|
+
const {
|
|
403
|
+
items,
|
|
404
|
+
total,
|
|
405
|
+
limit,
|
|
406
|
+
offset,
|
|
407
|
+
orderBy,
|
|
408
|
+
direction,
|
|
409
|
+
searchKey,
|
|
410
|
+
filters
|
|
411
|
+
} = useTable();
|
|
363
412
|
const navigate = useNavigate2();
|
|
364
413
|
const search = (query) => {
|
|
365
414
|
const searchParams2 = new URLSearchParams(window.location.search);
|
|
@@ -372,7 +421,7 @@ function TableForm({
|
|
|
372
421
|
searchKey && /* @__PURE__ */ jsxs3(
|
|
373
422
|
"form",
|
|
374
423
|
{
|
|
375
|
-
className: "h-
|
|
424
|
+
className: "h-20 px-4 flex items-center border-t",
|
|
376
425
|
onSubmit: (e) => {
|
|
377
426
|
e.preventDefault();
|
|
378
427
|
const formData = new FormData(e.currentTarget);
|
|
@@ -409,7 +458,8 @@ function TableForm({
|
|
|
409
458
|
limit,
|
|
410
459
|
offset,
|
|
411
460
|
orderBy,
|
|
412
|
-
direction
|
|
461
|
+
direction,
|
|
462
|
+
filters
|
|
413
463
|
}
|
|
414
464
|
),
|
|
415
465
|
/* @__PURE__ */ jsx4(
|