dn-react-router-toolkit 0.4.4 → 0.5.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/create_api_handler.d.mts +28 -0
- package/dist/api/create_api_handler.d.ts +28 -0
- package/dist/api/create_api_handler.js +148 -0
- package/dist/api/create_api_handler.mjs +132 -0
- package/dist/api/create_handler.d.mts +1 -1
- package/dist/api/create_handler.d.ts +1 -1
- package/dist/api/create_handler.js +27 -25
- package/dist/api/create_handler.mjs +27 -25
- package/dist/api/index.js +27 -25
- package/dist/api/index.mjs +27 -25
- package/dist/api/item_api_handler.d.mts +18 -0
- package/dist/api/item_api_handler.d.ts +18 -0
- package/dist/api/item_api_handler.js +55 -0
- package/dist/api/item_api_handler.mjs +30 -0
- package/dist/auth/index.d.mts +1 -2
- package/dist/auth/index.d.ts +1 -2
- package/dist/auth/index.js +13 -21
- package/dist/auth/index.mjs +12 -20
- package/dist/auth/with_auth.d.mts +3 -3
- package/dist/auth/with_auth.d.ts +3 -3
- package/dist/auth/with_auth.js +13 -21
- package/dist/auth/with_auth.mjs +12 -20
- package/dist/crud/crud_form.d.mts +13 -0
- package/dist/crud/crud_form.d.ts +13 -0
- package/dist/crud/crud_form.js +88 -0
- package/dist/crud/crud_form.mjs +55 -0
- package/dist/crud/crud_form_provider.d.mts +34 -0
- package/dist/crud/crud_form_provider.d.ts +34 -0
- package/dist/crud/crud_form_provider.js +160 -0
- package/dist/crud/crud_form_provider.mjs +124 -0
- package/dist/crud/crud_loader.d.mts +21 -0
- package/dist/crud/crud_loader.d.ts +21 -0
- package/dist/crud/crud_loader.js +288 -0
- package/dist/crud/crud_loader.mjs +273 -0
- package/dist/crud/crud_page.d.mts +25 -0
- package/dist/crud/crud_page.d.ts +25 -0
- package/dist/crud/crud_page.js +645 -0
- package/dist/crud/crud_page.mjs +616 -0
- package/dist/crud/generate_handlers.d.mts +15 -0
- package/dist/crud/generate_handlers.d.ts +15 -0
- package/dist/crud/generate_handlers.js +39 -0
- package/dist/crud/generate_handlers.mjs +14 -0
- package/dist/crud/generate_pages.d.mts +11 -0
- package/dist/crud/generate_pages.d.ts +11 -0
- package/dist/crud/generate_pages.js +52 -0
- package/dist/crud/generate_pages.mjs +17 -0
- package/dist/crud/generate_routes.d.mts +5 -0
- package/dist/crud/generate_routes.d.ts +5 -0
- package/dist/crud/generate_routes.js +62 -0
- package/dist/crud/generate_routes.mjs +27 -0
- package/dist/crud/index.d.mts +21 -0
- package/dist/crud/index.d.ts +21 -0
- package/dist/crud/index.js +970 -0
- package/dist/crud/index.mjs +945 -0
- package/dist/db/index.d.mts +4 -0
- package/dist/db/index.d.ts +4 -0
- package/dist/db/index.js +46 -0
- package/dist/db/index.mjs +8 -0
- package/dist/index.d.mts +3 -2
- package/dist/index.d.ts +3 -2
- package/dist/table/buttons.d.mts +10 -0
- package/dist/table/buttons.d.ts +10 -0
- package/dist/table/buttons.js +102 -0
- package/dist/table/buttons.mjs +71 -0
- package/dist/table/index.d.mts +9 -0
- package/dist/table/index.d.ts +9 -0
- package/dist/table/index.js +570 -0
- package/dist/table/index.mjs +543 -0
- package/dist/table/item_loader.d.mts +12 -0
- package/dist/table/item_loader.d.ts +12 -0
- package/dist/table/item_loader.js +51 -0
- package/dist/table/item_loader.mjs +26 -0
- package/dist/table/loader.d.mts +28 -0
- package/dist/table/loader.d.ts +28 -0
- package/dist/table/loader.js +70 -0
- package/dist/table/loader.mjs +48 -0
- package/dist/table/page.d.mts +27 -0
- package/dist/table/page.d.ts +27 -0
- package/dist/table/page.js +444 -0
- package/dist/table/page.mjs +415 -0
- package/dist/table/repository.d.mts +38 -0
- package/dist/table/repository.d.ts +38 -0
- package/dist/table/repository.js +76 -0
- package/dist/table/repository.mjs +56 -0
- package/dist/table/table.d.mts +27 -0
- package/dist/table/table.d.ts +27 -0
- package/dist/table/table.js +290 -0
- package/dist/table/table.mjs +255 -0
- package/package.json +21 -3
- package/dist/auth/temp_user.d.mts +0 -5
- package/dist/auth/temp_user.d.ts +0 -5
- package/dist/auth/temp_user.js +0 -18
- package/dist/auth/temp_user.mjs +0 -0
|
@@ -0,0 +1,273 @@
|
|
|
1
|
+
// src/table/loader.tsx
|
|
2
|
+
import {
|
|
3
|
+
and,
|
|
4
|
+
ilike
|
|
5
|
+
} from "drizzle-orm";
|
|
6
|
+
function tableLoader({
|
|
7
|
+
repository,
|
|
8
|
+
tableOptions
|
|
9
|
+
}) {
|
|
10
|
+
return async ({ request }) => {
|
|
11
|
+
const searchParams = new URL(request.url).searchParams;
|
|
12
|
+
const { where, searchKey, defaultOrderBy, defaultDirection } = tableOptions;
|
|
13
|
+
const query = searchParams.get("query") ?? void 0;
|
|
14
|
+
const limit = Number(searchParams.get("limit") ?? "10");
|
|
15
|
+
const offset = Number(searchParams.get("offset") ?? "0");
|
|
16
|
+
const orderBy = searchParams.get("orderBy") ?? defaultOrderBy;
|
|
17
|
+
const direction = searchParams.get("direction") ?? defaultDirection;
|
|
18
|
+
const whereClauses = and(
|
|
19
|
+
searchKey && query ? ilike(
|
|
20
|
+
repository.schema[searchKey],
|
|
21
|
+
`%${query}%`
|
|
22
|
+
) : void 0,
|
|
23
|
+
...where ?? []
|
|
24
|
+
);
|
|
25
|
+
const total = await repository.countTotal({ where: whereClauses });
|
|
26
|
+
const items = await repository.findAll({
|
|
27
|
+
orderBy,
|
|
28
|
+
direction,
|
|
29
|
+
limit,
|
|
30
|
+
offset,
|
|
31
|
+
where: whereClauses
|
|
32
|
+
});
|
|
33
|
+
return {
|
|
34
|
+
table: {
|
|
35
|
+
items,
|
|
36
|
+
total,
|
|
37
|
+
limit,
|
|
38
|
+
offset,
|
|
39
|
+
orderBy,
|
|
40
|
+
direction,
|
|
41
|
+
searchKey
|
|
42
|
+
}
|
|
43
|
+
};
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
// src/table/item_loader.tsx
|
|
48
|
+
var tableItemloader = ({
|
|
49
|
+
loader,
|
|
50
|
+
repository
|
|
51
|
+
}) => {
|
|
52
|
+
return async ({ params }) => {
|
|
53
|
+
const body = loader ? await (async () => {
|
|
54
|
+
const result = await loader({ params });
|
|
55
|
+
if (result instanceof Response) {
|
|
56
|
+
return result.json();
|
|
57
|
+
}
|
|
58
|
+
return result;
|
|
59
|
+
})() : {};
|
|
60
|
+
if (params["itemId"] === "new") {
|
|
61
|
+
return { item: void 0, ...body };
|
|
62
|
+
}
|
|
63
|
+
const item = params["itemId"] ? await repository.find(params["itemId"]) : void 0;
|
|
64
|
+
return {
|
|
65
|
+
item,
|
|
66
|
+
...body
|
|
67
|
+
};
|
|
68
|
+
};
|
|
69
|
+
};
|
|
70
|
+
|
|
71
|
+
// src/api/create_api_handler.ts
|
|
72
|
+
import {
|
|
73
|
+
BAD_REQUEST,
|
|
74
|
+
CONFLICT,
|
|
75
|
+
CREATED,
|
|
76
|
+
METHOD_NOT_ALLOWED
|
|
77
|
+
} from "dn-react-toolkit/http";
|
|
78
|
+
import {
|
|
79
|
+
and as and2
|
|
80
|
+
} from "drizzle-orm";
|
|
81
|
+
import {
|
|
82
|
+
redirect
|
|
83
|
+
} from "react-router";
|
|
84
|
+
import { v4 } from "uuid";
|
|
85
|
+
function apiHandler({
|
|
86
|
+
withAuthAction,
|
|
87
|
+
repository,
|
|
88
|
+
validators,
|
|
89
|
+
existingConditions,
|
|
90
|
+
injectUserId
|
|
91
|
+
}) {
|
|
92
|
+
const loader = async ({ request }) => {
|
|
93
|
+
return {};
|
|
94
|
+
};
|
|
95
|
+
const action = withAuthAction((auth) => async ({ request }) => {
|
|
96
|
+
if (!auth || auth.role !== "admin") {
|
|
97
|
+
return redirect("/login");
|
|
98
|
+
}
|
|
99
|
+
switch (request.method) {
|
|
100
|
+
case "POST":
|
|
101
|
+
case "PUT": {
|
|
102
|
+
const serilaizedParams = await request.json();
|
|
103
|
+
const params = Object.entries(serilaizedParams).reduce(
|
|
104
|
+
function reducer(acc, [key, value]) {
|
|
105
|
+
const converter = (value2) => {
|
|
106
|
+
if (value2.type === "null") {
|
|
107
|
+
return null;
|
|
108
|
+
}
|
|
109
|
+
if (value2.type === "string") {
|
|
110
|
+
return value2.value;
|
|
111
|
+
}
|
|
112
|
+
if (value2.type === "number") {
|
|
113
|
+
return value2.value;
|
|
114
|
+
}
|
|
115
|
+
if (value2.type === "boolean") {
|
|
116
|
+
return value2.value;
|
|
117
|
+
}
|
|
118
|
+
if (value2.type === "date") {
|
|
119
|
+
return new Date(value2.value);
|
|
120
|
+
}
|
|
121
|
+
if (Array.isArray(value2)) {
|
|
122
|
+
return value2.map((v) => converter(v));
|
|
123
|
+
}
|
|
124
|
+
if (typeof value2 === "object") {
|
|
125
|
+
return Object.entries(value2).reduce(
|
|
126
|
+
reducer,
|
|
127
|
+
{}
|
|
128
|
+
);
|
|
129
|
+
}
|
|
130
|
+
};
|
|
131
|
+
const result = converter(value);
|
|
132
|
+
if (result === void 0) {
|
|
133
|
+
return acc;
|
|
134
|
+
}
|
|
135
|
+
return {
|
|
136
|
+
...acc,
|
|
137
|
+
[key]: result
|
|
138
|
+
};
|
|
139
|
+
},
|
|
140
|
+
{}
|
|
141
|
+
);
|
|
142
|
+
if (validators) {
|
|
143
|
+
const paramsForValidation = Object.keys(validators).filter(
|
|
144
|
+
(key) => Object.prototype.hasOwnProperty.call(
|
|
145
|
+
validators,
|
|
146
|
+
key
|
|
147
|
+
)
|
|
148
|
+
);
|
|
149
|
+
for (const paramKey of paramsForValidation) {
|
|
150
|
+
const value = params[paramKey];
|
|
151
|
+
const validator = validators[paramKey];
|
|
152
|
+
if (validator?.validate && !validator.validate(value)) {
|
|
153
|
+
throw BAD_REQUEST(
|
|
154
|
+
validator.message ? validator.message(value) : void 0
|
|
155
|
+
);
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
const itemId = params.id || v4();
|
|
160
|
+
if (!params.id && existingConditions) {
|
|
161
|
+
const paramsForExistenceCheck = Object.keys(
|
|
162
|
+
existingConditions
|
|
163
|
+
).filter(
|
|
164
|
+
(key) => Object.prototype.hasOwnProperty.call(params, key)
|
|
165
|
+
);
|
|
166
|
+
const where = and2(
|
|
167
|
+
...paramsForExistenceCheck.reduce((acc, key) => {
|
|
168
|
+
const condition = existingConditions[key];
|
|
169
|
+
if (condition) {
|
|
170
|
+
acc.push(condition(params[key]));
|
|
171
|
+
}
|
|
172
|
+
return acc;
|
|
173
|
+
}, [])
|
|
174
|
+
);
|
|
175
|
+
const existing = await repository.findAll({
|
|
176
|
+
limit: 1,
|
|
177
|
+
where
|
|
178
|
+
});
|
|
179
|
+
if (existing.length > 0) {
|
|
180
|
+
throw CONFLICT("\uC790\uB8CC\uAC00 \uC774\uBBF8 \uC874\uC7AC\uD569\uB2C8\uB2E4.");
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
const values = {
|
|
184
|
+
id: itemId,
|
|
185
|
+
userId: injectUserId ? auth.userId : void 0,
|
|
186
|
+
...params
|
|
187
|
+
};
|
|
188
|
+
const item = await repository.save(values);
|
|
189
|
+
return CREATED(item);
|
|
190
|
+
}
|
|
191
|
+
default:
|
|
192
|
+
throw METHOD_NOT_ALLOWED();
|
|
193
|
+
}
|
|
194
|
+
});
|
|
195
|
+
return {
|
|
196
|
+
loader,
|
|
197
|
+
action
|
|
198
|
+
};
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
// src/api/item_api_handler.ts
|
|
202
|
+
import { UNAUTHORIZED } from "dn-react-toolkit/http";
|
|
203
|
+
import "react-router";
|
|
204
|
+
function itemApiHandler({
|
|
205
|
+
withAuthAction,
|
|
206
|
+
repository
|
|
207
|
+
}) {
|
|
208
|
+
const loader = async ({ request }) => {
|
|
209
|
+
return {};
|
|
210
|
+
};
|
|
211
|
+
const action = withAuthAction((auth) => async ({ params, request }) => {
|
|
212
|
+
if (!auth || auth.role !== "admin") {
|
|
213
|
+
return UNAUTHORIZED();
|
|
214
|
+
}
|
|
215
|
+
switch (request.method) {
|
|
216
|
+
case "DELETE": {
|
|
217
|
+
const itemId = params.itemId;
|
|
218
|
+
await repository.delete(itemId);
|
|
219
|
+
return {};
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
});
|
|
223
|
+
return {
|
|
224
|
+
loader,
|
|
225
|
+
action
|
|
226
|
+
};
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
// src/crud/crud_loader.tsx
|
|
230
|
+
function crudHandler({
|
|
231
|
+
repository,
|
|
232
|
+
apiHandlerOptions,
|
|
233
|
+
loaderOptions,
|
|
234
|
+
itemLoaderOptions
|
|
235
|
+
}) {
|
|
236
|
+
return (prefix) => async (args) => {
|
|
237
|
+
const pattern = args.unstable_pattern;
|
|
238
|
+
if (pattern === `/api${prefix}`) {
|
|
239
|
+
const { loader, action } = apiHandler({
|
|
240
|
+
repository,
|
|
241
|
+
...apiHandlerOptions
|
|
242
|
+
});
|
|
243
|
+
if (args.request.method === "GET") {
|
|
244
|
+
return loader(args);
|
|
245
|
+
} else {
|
|
246
|
+
return action(args);
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
if (pattern.startsWith(`/api${prefix}`)) {
|
|
250
|
+
const { loader, action } = itemApiHandler({
|
|
251
|
+
repository,
|
|
252
|
+
...apiHandlerOptions
|
|
253
|
+
});
|
|
254
|
+
if (args.request.method === "GET") {
|
|
255
|
+
return loader(args);
|
|
256
|
+
} else {
|
|
257
|
+
return action(args);
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
if (pattern === prefix) {
|
|
261
|
+
return tableLoader({
|
|
262
|
+
...loaderOptions,
|
|
263
|
+
repository
|
|
264
|
+
})(args);
|
|
265
|
+
}
|
|
266
|
+
if (pattern.startsWith(prefix)) {
|
|
267
|
+
return tableItemloader({ ...itemLoaderOptions, repository })(args);
|
|
268
|
+
}
|
|
269
|
+
};
|
|
270
|
+
}
|
|
271
|
+
export {
|
|
272
|
+
crudHandler
|
|
273
|
+
};
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { CrudFormProps } from './crud_form_provider.mjs';
|
|
2
|
+
import { TablePageOptions } from '../table/page.mjs';
|
|
3
|
+
import React from 'react';
|
|
4
|
+
import 'dn-react-toolkit/store';
|
|
5
|
+
import 'drizzle-orm/pg-core';
|
|
6
|
+
import '../table/table.mjs';
|
|
7
|
+
|
|
8
|
+
type CrudPageOptions<TModel, TPrimaryKey extends keyof TModel> = {
|
|
9
|
+
name: string;
|
|
10
|
+
tablePageOptions: Omit<TablePageOptions<TModel>, "name">;
|
|
11
|
+
formOptions: {
|
|
12
|
+
form?: React.FC;
|
|
13
|
+
columns: CrudFormProps<TModel, TPrimaryKey>["columns"];
|
|
14
|
+
};
|
|
15
|
+
AdminLayout: React.FC<{
|
|
16
|
+
title: string;
|
|
17
|
+
actions?: React.ReactNode;
|
|
18
|
+
className?: string;
|
|
19
|
+
children?: React.ReactNode;
|
|
20
|
+
}>;
|
|
21
|
+
};
|
|
22
|
+
type CrudPage = (prefix: string) => React.FC;
|
|
23
|
+
declare function crudPage<TModel, TPrimaryKey extends keyof TModel = "id" extends keyof TModel ? "id" : never>({ name, tablePageOptions, formOptions, AdminLayout, }: CrudPageOptions<TModel, TPrimaryKey>): CrudPage;
|
|
24
|
+
|
|
25
|
+
export { type CrudPage, type CrudPageOptions, crudPage };
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { CrudFormProps } from './crud_form_provider.js';
|
|
2
|
+
import { TablePageOptions } from '../table/page.js';
|
|
3
|
+
import React from 'react';
|
|
4
|
+
import 'dn-react-toolkit/store';
|
|
5
|
+
import 'drizzle-orm/pg-core';
|
|
6
|
+
import '../table/table.js';
|
|
7
|
+
|
|
8
|
+
type CrudPageOptions<TModel, TPrimaryKey extends keyof TModel> = {
|
|
9
|
+
name: string;
|
|
10
|
+
tablePageOptions: Omit<TablePageOptions<TModel>, "name">;
|
|
11
|
+
formOptions: {
|
|
12
|
+
form?: React.FC;
|
|
13
|
+
columns: CrudFormProps<TModel, TPrimaryKey>["columns"];
|
|
14
|
+
};
|
|
15
|
+
AdminLayout: React.FC<{
|
|
16
|
+
title: string;
|
|
17
|
+
actions?: React.ReactNode;
|
|
18
|
+
className?: string;
|
|
19
|
+
children?: React.ReactNode;
|
|
20
|
+
}>;
|
|
21
|
+
};
|
|
22
|
+
type CrudPage = (prefix: string) => React.FC;
|
|
23
|
+
declare function crudPage<TModel, TPrimaryKey extends keyof TModel = "id" extends keyof TModel ? "id" : never>({ name, tablePageOptions, formOptions, AdminLayout, }: CrudPageOptions<TModel, TPrimaryKey>): CrudPage;
|
|
24
|
+
|
|
25
|
+
export { type CrudPage, type CrudPageOptions, crudPage };
|