@nestledjs/data-browser 0.1.15 → 0.1.17
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +0 -2
- package/index.d.ts +1 -0
- package/index.js +2 -0
- package/lib/components/RelationFieldWrapper.d.ts +2 -1
- package/lib/hooks/useAdminList.js +2 -0
- package/lib/hooks/useRelationData.js +0 -3
- package/lib/layouts/AdminDataLayout.js +1 -1
- package/lib/pages/AdminDataCreatePage.js +38 -42
- package/lib/pages/AdminDataEditPage.js +98 -119
- package/lib/pages/AdminDataIndexPage.js +1 -1
- package/lib/pages/AdminDataListPage.js +111 -125
- package/lib/types/index.d.ts +3 -0
- package/lib/utils/get-plural-names.d.ts +21 -0
- package/lib/utils/get-plural-names.js +41 -0
- package/lib/utils/graphql-utils.js +1 -16
- package/lib/utils/secure-storage.js +0 -13
- package/package.json +2 -3
package/README.md
CHANGED
|
@@ -30,7 +30,6 @@ This package requires a Nestled framework project with:
|
|
|
30
30
|
- **Apollo Client v4+** for GraphQL operations
|
|
31
31
|
- **React Router v7+** for routing
|
|
32
32
|
- **@nestledjs/forms** for form generation
|
|
33
|
-
- **@nestledjs/helpers** for utility functions
|
|
34
33
|
- **Prisma** for database models
|
|
35
34
|
- **Generated GraphQL SDK** with admin CRUD operations
|
|
36
35
|
|
|
@@ -40,7 +39,6 @@ This package requires a Nestled framework project with:
|
|
|
40
39
|
{
|
|
41
40
|
"@apollo/client": "^4.0.0",
|
|
42
41
|
"@nestledjs/forms": "^0.5.0",
|
|
43
|
-
"@nestledjs/helpers": "^0.1.0",
|
|
44
42
|
"react": "^19.0.0",
|
|
45
43
|
"react-router": "^7.0.0"
|
|
46
44
|
}
|
package/index.d.ts
CHANGED
package/index.js
CHANGED
|
@@ -20,6 +20,7 @@ import { RelationFieldWrapper } from "./lib/components/RelationFieldWrapper.js";
|
|
|
20
20
|
import { buildFormFields, cleanFormInput, getAdminDocuments, getMutationName } from "./lib/utils/graphql-utils.js";
|
|
21
21
|
import { AdminLocalStorage, SecureAdminLocalStorage } from "./lib/utils/secure-storage.js";
|
|
22
22
|
import { formatFieldName, getItemDisplayName, getSmartSearchFields, kebabCase, normalizeModelNameForDocument, spacedWords } from "./lib/utils/string-utils.js";
|
|
23
|
+
import { getPluralName } from "./lib/utils/get-plural-names.js";
|
|
23
24
|
export {
|
|
24
25
|
AdminBreadcrumbs,
|
|
25
26
|
AdminDataCreateErrorBoundary,
|
|
@@ -53,6 +54,7 @@ export {
|
|
|
53
54
|
getAdminDocuments,
|
|
54
55
|
getItemDisplayName,
|
|
55
56
|
getMutationName,
|
|
57
|
+
getPluralName,
|
|
56
58
|
getSmartSearchFields,
|
|
57
59
|
initialState,
|
|
58
60
|
kebabCase,
|
|
@@ -24,6 +24,8 @@ function adminListReducer(state, action) {
|
|
|
24
24
|
return { ...state, filters: action.payload };
|
|
25
25
|
case "TOGGLE_FILTERS":
|
|
26
26
|
return { ...state, showFilters: !state.showFilters };
|
|
27
|
+
case "SET_SHOW_FILTERS":
|
|
28
|
+
return { ...state, showFilters: action.payload };
|
|
27
29
|
case "RESET_PAGINATION":
|
|
28
30
|
return { ...state, skip: 0 };
|
|
29
31
|
case "RESET_FILTERS":
|
|
@@ -55,14 +55,12 @@ function useRelationData(relatedModelName, searchTerm, isOpen, currentValueId) {
|
|
|
55
55
|
});
|
|
56
56
|
const relatedItems = useMemo(() => {
|
|
57
57
|
if (relationError) {
|
|
58
|
-
console.warn("[RelationData] GraphQL error:", relationError.message);
|
|
59
58
|
return [];
|
|
60
59
|
}
|
|
61
60
|
if (!relatedData) return [];
|
|
62
61
|
try {
|
|
63
62
|
const items = relatedData[relatedDataPath] || [];
|
|
64
63
|
if (!Array.isArray(items)) {
|
|
65
|
-
console.warn("[RelationData] Expected array but got:", typeof items);
|
|
66
64
|
return [];
|
|
67
65
|
}
|
|
68
66
|
return items.filter((item) => {
|
|
@@ -71,7 +69,6 @@ function useRelationData(relatedModelName, searchTerm, isOpen, currentValueId) {
|
|
|
71
69
|
return true;
|
|
72
70
|
});
|
|
73
71
|
} catch (error) {
|
|
74
|
-
console.error("[RelationData] Error processing relation data:", error);
|
|
75
72
|
return [];
|
|
76
73
|
}
|
|
77
74
|
}, [relatedData, relatedDataPath, relationError]);
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import React, { useState, useRef, useMemo } from "react";
|
|
2
|
-
import { getPluralName } from "
|
|
2
|
+
import { getPluralName } from "../utils/get-plural-names.js";
|
|
3
3
|
import { useNavigate, useParams, Outlet } from "react-router";
|
|
4
4
|
import { AdminLocalStorage } from "../utils/secure-storage.js";
|
|
5
5
|
import { spacedWords, kebabCase } from "../utils/string-utils.js";
|
|
@@ -142,7 +142,6 @@ function AdminDataCreatePageContent({
|
|
|
142
142
|
try {
|
|
143
143
|
return getAdminDocuments(sdk, model);
|
|
144
144
|
} catch (error) {
|
|
145
|
-
console.error("[AdminDataCreatePage] Error getting documents:", error);
|
|
146
145
|
return null;
|
|
147
146
|
}
|
|
148
147
|
}, [sdk, model]);
|
|
@@ -155,7 +154,6 @@ function AdminDataCreatePageContent({
|
|
|
155
154
|
}
|
|
156
155
|
return gql(documents.create);
|
|
157
156
|
} catch (error) {
|
|
158
|
-
console.error("[AdminDataCreatePage] Error parsing CREATE mutation:", error);
|
|
159
157
|
return null;
|
|
160
158
|
}
|
|
161
159
|
}, [documents]);
|
|
@@ -167,39 +165,39 @@ function AdminDataCreatePageContent({
|
|
|
167
165
|
if (!documents || !CREATE_MUTATION) {
|
|
168
166
|
return /* @__PURE__ */ React.createElement("div", { className: "min-h-screen bg-gray-50 dark:bg-gray-900 flex flex-col justify-center py-12 sm:px-6 lg:px-8", __self: this, __source: {
|
|
169
167
|
fileName: _jsxFileName,
|
|
170
|
-
lineNumber:
|
|
168
|
+
lineNumber: 220,
|
|
171
169
|
columnNumber: 7
|
|
172
170
|
} }, /* @__PURE__ */ React.createElement("div", { className: "mt-8 sm:mx-auto sm:w-full sm:max-w-2xl", __self: this, __source: {
|
|
173
171
|
fileName: _jsxFileName,
|
|
174
|
-
lineNumber:
|
|
172
|
+
lineNumber: 221,
|
|
175
173
|
columnNumber: 9
|
|
176
174
|
} }, /* @__PURE__ */ React.createElement("div", { className: "bg-white dark:bg-gray-800 py-8 px-4 shadow sm:rounded-lg sm:px-10", __self: this, __source: {
|
|
177
175
|
fileName: _jsxFileName,
|
|
178
|
-
lineNumber:
|
|
176
|
+
lineNumber: 222,
|
|
179
177
|
columnNumber: 11
|
|
180
178
|
} }, /* @__PURE__ */ React.createElement("div", { className: "text-center", __self: this, __source: {
|
|
181
179
|
fileName: _jsxFileName,
|
|
182
|
-
lineNumber:
|
|
180
|
+
lineNumber: 223,
|
|
183
181
|
columnNumber: 13
|
|
184
182
|
} }, /* @__PURE__ */ React.createElement(ExclamationCircleIcon, { className: "mx-auto h-12 w-12 text-red-400", __self: this, __source: {
|
|
185
183
|
fileName: _jsxFileName,
|
|
186
|
-
lineNumber:
|
|
184
|
+
lineNumber: 224,
|
|
187
185
|
columnNumber: 15
|
|
188
186
|
} }), /* @__PURE__ */ React.createElement("h2", { className: "mt-4 text-lg font-medium text-gray-900 dark:text-gray-100", __self: this, __source: {
|
|
189
187
|
fileName: _jsxFileName,
|
|
190
|
-
lineNumber:
|
|
188
|
+
lineNumber: 225,
|
|
191
189
|
columnNumber: 15
|
|
192
190
|
} }, "GraphQL Schema Error"), /* @__PURE__ */ React.createElement("p", { className: "mt-2 text-sm text-gray-600 dark:text-gray-400", __self: this, __source: {
|
|
193
191
|
fileName: _jsxFileName,
|
|
194
|
-
lineNumber:
|
|
192
|
+
lineNumber: 226,
|
|
195
193
|
columnNumber: 15
|
|
196
194
|
} }, "Unable to load GraphQL documents for this model. Please ensure the API server is running and the GraphQL schema is up to date."), /* @__PURE__ */ React.createElement("div", { className: "mt-6", __self: this, __source: {
|
|
197
195
|
fileName: _jsxFileName,
|
|
198
|
-
lineNumber:
|
|
196
|
+
lineNumber: 230,
|
|
199
197
|
columnNumber: 15
|
|
200
198
|
} }, /* @__PURE__ */ React.createElement(Link, { to: basePath, className: "w-full flex justify-center py-2 px-4 border border-transparent rounded-md shadow-sm text-sm font-medium text-white bg-green-web hover:bg-green-web-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-green-web", __self: this, __source: {
|
|
201
199
|
fileName: _jsxFileName,
|
|
202
|
-
lineNumber:
|
|
200
|
+
lineNumber: 231,
|
|
203
201
|
columnNumber: 17
|
|
204
202
|
} }, "Return to Data Browser"))))));
|
|
205
203
|
}
|
|
@@ -216,7 +214,6 @@ function AdminDataCreatePageContent({
|
|
|
216
214
|
}
|
|
217
215
|
});
|
|
218
216
|
if (result.errors) {
|
|
219
|
-
console.error("GraphQL errors:", result.errors);
|
|
220
217
|
setSubmissionState({
|
|
221
218
|
status: "error",
|
|
222
219
|
message: result.errors.map((err) => err.message).join(", ")
|
|
@@ -231,7 +228,6 @@ function AdminDataCreatePageContent({
|
|
|
231
228
|
navigate(`${basePath}/${toKebabCase(model.pluralName)}`);
|
|
232
229
|
}, 1500);
|
|
233
230
|
} catch (error) {
|
|
234
|
-
console.error("Error creating record:", error);
|
|
235
231
|
setSubmissionState({
|
|
236
232
|
status: "error",
|
|
237
233
|
message: error instanceof Error ? error.message : "An unexpected error occurred"
|
|
@@ -250,115 +246,115 @@ function AdminDataCreatePageContent({
|
|
|
250
246
|
}, [submissionState.status]);
|
|
251
247
|
return /* @__PURE__ */ React.createElement("div", { className: "space-y-6", __self: this, __source: {
|
|
252
248
|
fileName: _jsxFileName,
|
|
253
|
-
lineNumber:
|
|
249
|
+
lineNumber: 299,
|
|
254
250
|
columnNumber: 5
|
|
255
251
|
} }, /* @__PURE__ */ React.createElement("div", { className: "mb-8", __self: this, __source: {
|
|
256
252
|
fileName: _jsxFileName,
|
|
257
|
-
lineNumber:
|
|
253
|
+
lineNumber: 301,
|
|
258
254
|
columnNumber: 7
|
|
259
255
|
} }, /* @__PURE__ */ React.createElement("nav", { className: "flex mb-6", "aria-label": "Breadcrumb", __self: this, __source: {
|
|
260
256
|
fileName: _jsxFileName,
|
|
261
|
-
lineNumber:
|
|
257
|
+
lineNumber: 302,
|
|
262
258
|
columnNumber: 11
|
|
263
259
|
} }, /* @__PURE__ */ React.createElement("ol", { className: "flex items-center space-x-4", __self: this, __source: {
|
|
264
260
|
fileName: _jsxFileName,
|
|
265
|
-
lineNumber:
|
|
261
|
+
lineNumber: 303,
|
|
266
262
|
columnNumber: 13
|
|
267
263
|
} }, /* @__PURE__ */ React.createElement("li", { __self: this, __source: {
|
|
268
264
|
fileName: _jsxFileName,
|
|
269
|
-
lineNumber:
|
|
265
|
+
lineNumber: 304,
|
|
270
266
|
columnNumber: 15
|
|
271
267
|
} }, /* @__PURE__ */ React.createElement(Link, { to: basePath, className: "text-gray-400 dark:text-gray-500 hover:text-gray-500 dark:hover:text-gray-400", __self: this, __source: {
|
|
272
268
|
fileName: _jsxFileName,
|
|
273
|
-
lineNumber:
|
|
269
|
+
lineNumber: 305,
|
|
274
270
|
columnNumber: 17
|
|
275
271
|
} }, "Data Browser")), /* @__PURE__ */ React.createElement("li", { __self: this, __source: {
|
|
276
272
|
fileName: _jsxFileName,
|
|
277
|
-
lineNumber:
|
|
273
|
+
lineNumber: 309,
|
|
278
274
|
columnNumber: 15
|
|
279
275
|
} }, /* @__PURE__ */ React.createElement("div", { className: "flex items-center", __self: this, __source: {
|
|
280
276
|
fileName: _jsxFileName,
|
|
281
|
-
lineNumber:
|
|
277
|
+
lineNumber: 310,
|
|
282
278
|
columnNumber: 17
|
|
283
279
|
} }, /* @__PURE__ */ React.createElement("svg", { className: "flex-shrink-0 h-5 w-5 text-gray-300 dark:text-gray-600", fill: "currentColor", viewBox: "0 0 20 20", __self: this, __source: {
|
|
284
280
|
fileName: _jsxFileName,
|
|
285
|
-
lineNumber:
|
|
281
|
+
lineNumber: 311,
|
|
286
282
|
columnNumber: 19
|
|
287
283
|
} }, /* @__PURE__ */ React.createElement("path", { fillRule: "evenodd", d: "M7.293 14.707a1 1 0 010-1.414L10.586 10 7.293 6.707a1 1 0 111.414-1.414l4 4a1 1 0 010 1.414l-4 4a1 1 0 01-1.414 0z", clipRule: "evenodd", __self: this, __source: {
|
|
288
284
|
fileName: _jsxFileName,
|
|
289
|
-
lineNumber:
|
|
285
|
+
lineNumber: 316,
|
|
290
286
|
columnNumber: 21
|
|
291
287
|
} })), /* @__PURE__ */ React.createElement(Link, { to: `${basePath}/${toKebabCase(model.pluralName)}`, className: "ml-4 text-gray-400 dark:text-gray-500 hover:text-gray-500 dark:hover:text-gray-400", __self: this, __source: {
|
|
292
288
|
fileName: _jsxFileName,
|
|
293
|
-
lineNumber:
|
|
289
|
+
lineNumber: 322,
|
|
294
290
|
columnNumber: 19
|
|
295
291
|
} }, toReadableText(model.pluralName)))), /* @__PURE__ */ React.createElement("li", { __self: this, __source: {
|
|
296
292
|
fileName: _jsxFileName,
|
|
297
|
-
lineNumber:
|
|
293
|
+
lineNumber: 330,
|
|
298
294
|
columnNumber: 15
|
|
299
295
|
} }, /* @__PURE__ */ React.createElement("div", { className: "flex items-center", __self: this, __source: {
|
|
300
296
|
fileName: _jsxFileName,
|
|
301
|
-
lineNumber:
|
|
297
|
+
lineNumber: 331,
|
|
302
298
|
columnNumber: 17
|
|
303
299
|
} }, /* @__PURE__ */ React.createElement("svg", { className: "flex-shrink-0 h-5 w-5 text-gray-300 dark:text-gray-600", fill: "currentColor", viewBox: "0 0 20 20", __self: this, __source: {
|
|
304
300
|
fileName: _jsxFileName,
|
|
305
|
-
lineNumber:
|
|
301
|
+
lineNumber: 332,
|
|
306
302
|
columnNumber: 19
|
|
307
303
|
} }, /* @__PURE__ */ React.createElement("path", { fillRule: "evenodd", d: "M7.293 14.707a1 1 0 010-1.414L10.586 10 7.293 6.707a1 1 0 111.414-1.414l4 4a1 1 0 010 1.414l-4 4a1 1 0 01-1.414 0z", clipRule: "evenodd", __self: this, __source: {
|
|
308
304
|
fileName: _jsxFileName,
|
|
309
|
-
lineNumber:
|
|
305
|
+
lineNumber: 337,
|
|
310
306
|
columnNumber: 21
|
|
311
307
|
} })), /* @__PURE__ */ React.createElement("span", { className: "ml-4 text-gray-500 dark:text-gray-400", __self: this, __source: {
|
|
312
308
|
fileName: _jsxFileName,
|
|
313
|
-
lineNumber:
|
|
309
|
+
lineNumber: 343,
|
|
314
310
|
columnNumber: 19
|
|
315
311
|
} }, "Create New"))))), /* @__PURE__ */ React.createElement("h1", { className: "mt-4 text-3xl font-bold text-gray-900 dark:text-gray-100", __self: this, __source: {
|
|
316
312
|
fileName: _jsxFileName,
|
|
317
|
-
lineNumber:
|
|
313
|
+
lineNumber: 348,
|
|
318
314
|
columnNumber: 11
|
|
319
315
|
} }, "Create ", toReadableText(model.name))), submissionState.status !== "idle" && /* @__PURE__ */ React.createElement("div", { className: `mb-6 rounded-md p-4 ${submissionState.status === "success" ? "bg-green-50 border border-green-200" : submissionState.status === "error" ? "bg-red-50 border border-red-200" : "bg-blue-50 border border-blue-200"}`, __self: this, __source: {
|
|
320
316
|
fileName: _jsxFileName,
|
|
321
|
-
lineNumber:
|
|
317
|
+
lineNumber: 355,
|
|
322
318
|
columnNumber: 11
|
|
323
319
|
} }, /* @__PURE__ */ React.createElement("div", { className: "flex", __self: this, __source: {
|
|
324
320
|
fileName: _jsxFileName,
|
|
325
|
-
lineNumber:
|
|
321
|
+
lineNumber: 364,
|
|
326
322
|
columnNumber: 13
|
|
327
323
|
} }, /* @__PURE__ */ React.createElement("div", { className: "flex-shrink-0", __self: this, __source: {
|
|
328
324
|
fileName: _jsxFileName,
|
|
329
|
-
lineNumber:
|
|
325
|
+
lineNumber: 365,
|
|
330
326
|
columnNumber: 15
|
|
331
327
|
} }, submissionState.status === "success" ? /* @__PURE__ */ React.createElement(CheckCircleIcon, { className: "h-5 w-5 text-green-400", __self: this, __source: {
|
|
332
328
|
fileName: _jsxFileName,
|
|
333
|
-
lineNumber:
|
|
329
|
+
lineNumber: 367,
|
|
334
330
|
columnNumber: 19
|
|
335
331
|
} }) : submissionState.status === "error" ? /* @__PURE__ */ React.createElement(ExclamationCircleIcon, { className: "h-5 w-5 text-red-400", __self: this, __source: {
|
|
336
332
|
fileName: _jsxFileName,
|
|
337
|
-
lineNumber:
|
|
333
|
+
lineNumber: 369,
|
|
338
334
|
columnNumber: 19
|
|
339
335
|
} }) : /* @__PURE__ */ React.createElement("div", { className: "h-5 w-5 border-2 border-blue-400 border-t-transparent rounded-full animate-spin", __self: this, __source: {
|
|
340
336
|
fileName: _jsxFileName,
|
|
341
|
-
lineNumber:
|
|
337
|
+
lineNumber: 371,
|
|
342
338
|
columnNumber: 19
|
|
343
339
|
} })), /* @__PURE__ */ React.createElement("div", { className: "ml-3", __self: this, __source: {
|
|
344
340
|
fileName: _jsxFileName,
|
|
345
|
-
lineNumber:
|
|
341
|
+
lineNumber: 374,
|
|
346
342
|
columnNumber: 15
|
|
347
343
|
} }, /* @__PURE__ */ React.createElement("p", { className: `text-sm font-medium ${submissionState.status === "success" ? "text-green-800" : submissionState.status === "error" ? "text-red-800" : "text-blue-800"}`, __self: this, __source: {
|
|
348
344
|
fileName: _jsxFileName,
|
|
349
|
-
lineNumber:
|
|
345
|
+
lineNumber: 375,
|
|
350
346
|
columnNumber: 17
|
|
351
347
|
} }, submissionState.status === "loading" ? `Creating ${toReadableText(model.name)}...` : submissionState.message)))), /* @__PURE__ */ React.createElement("div", { className: "bg-white dark:bg-gray-800 shadow-sm rounded-lg", __self: this, __source: {
|
|
352
348
|
fileName: _jsxFileName,
|
|
353
|
-
lineNumber:
|
|
349
|
+
lineNumber: 394,
|
|
354
350
|
columnNumber: 9
|
|
355
351
|
} }, /* @__PURE__ */ React.createElement("div", { className: "px-6 py-8", __self: this, __source: {
|
|
356
352
|
fileName: _jsxFileName,
|
|
357
|
-
lineNumber:
|
|
353
|
+
lineNumber: 395,
|
|
358
354
|
columnNumber: 11
|
|
359
355
|
} }, /* @__PURE__ */ React.createElement(Form, { id: `create-${model.name.toLowerCase()}-form`, fields: formFields, submit: handleSubmit, disabled: submissionState.status === "loading", theme: formTheme, __self: this, __source: {
|
|
360
356
|
fileName: _jsxFileName,
|
|
361
|
-
lineNumber:
|
|
357
|
+
lineNumber: 396,
|
|
362
358
|
columnNumber: 13
|
|
363
359
|
} }))));
|
|
364
360
|
}
|
|
@@ -367,7 +363,7 @@ function AdminDataCreateErrorBoundary({
|
|
|
367
363
|
}) {
|
|
368
364
|
return /* @__PURE__ */ React.createElement(ErrorBoundary, { error, __self: this, __source: {
|
|
369
365
|
fileName: _jsxFileName,
|
|
370
|
-
lineNumber:
|
|
366
|
+
lineNumber: 410,
|
|
371
367
|
columnNumber: 10
|
|
372
368
|
} });
|
|
373
369
|
}
|