@nestledjs/data-browser 0.1.24 → 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.
@@ -6,9 +6,7 @@ import { getPluralName } from "../utils/get-plural-names.js";
6
6
  import { AdminLocalStorage } from "../utils/secure-storage.js";
7
7
  import { kebabCase, formatFieldName } from "../utils/string-utils.js";
8
8
  import { useParams, useSearchParams, Link } from "react-router";
9
- import { DateRangeFilter } from "../components/filters/DateRangeFilter.js";
10
- import { NumberRangeFilter } from "../components/filters/NumberRangeFilter.js";
11
- import { RelationFilterField } from "../components/filters/RelationFilterField.js";
9
+ import { FilterField } from "../components/FilterField.js";
12
10
  import { useAdminList } from "../hooks/useAdminList.js";
13
11
  import { getAdminDocuments } from "../utils/graphql-utils.js";
14
12
  import { useAdminDataContext } from "../context/AdminDataContext.js";
@@ -32,6 +30,36 @@ function AdminDataListPage({ modelName: propModelName } = {}) {
32
30
  return null;
33
31
  }
34
32
  }, [sdk]);
33
+ const updateRelatedEnumFilter = useCallback((filters2, relationName, enumFieldName, value) => {
34
+ const newFilters = { ...filters2 };
35
+ if (value === void 0 || value === null || value === "") {
36
+ const relationFilter = newFilters[relationName];
37
+ if (relationFilter && typeof relationFilter === "object") {
38
+ delete relationFilter[enumFieldName];
39
+ if (Object.keys(relationFilter).length === 0) {
40
+ delete newFilters[relationName];
41
+ }
42
+ }
43
+ } else {
44
+ if (!newFilters[relationName]) {
45
+ newFilters[relationName] = {};
46
+ }
47
+ const relationFilter = newFilters[relationName];
48
+ if (relationFilter && typeof relationFilter === "object") {
49
+ relationFilter[enumFieldName] = value;
50
+ }
51
+ }
52
+ return newFilters;
53
+ }, []);
54
+ const updateSimpleFilter = useCallback((filters2, fieldName, value) => {
55
+ const newFilters = { ...filters2 };
56
+ if (value === void 0 || value === null || value === "") {
57
+ delete newFilters[fieldName];
58
+ } else {
59
+ newFilters[fieldName] = value;
60
+ }
61
+ return newFilters;
62
+ }, []);
35
63
  const { state, dispatch } = useAdminList();
36
64
  const {
37
65
  search,
@@ -137,15 +165,15 @@ function AdminDataListPage({ modelName: propModelName } = {}) {
137
165
  return (model == null ? void 0 : model.pluralModelPropertyName) || pluralParam.replace(/-([a-z])/g, (_, letter) => letter.toUpperCase());
138
166
  }, [model, pluralParam]);
139
167
  const paginationPath = useMemo(() => {
140
- return model ? `${model.pluralModelPropertyName}_meta` : `${dataPath}_meta`;
141
- }, [model, dataPath]);
168
+ return "counters";
169
+ }, []);
142
170
  const fieldNames = useMemo(() => {
143
171
  if (!model) return [];
144
172
  return model.fields.filter((field) => !field.relationName || !field.isList).map((field) => field.name);
145
173
  }, [model]);
146
174
  const filterableFieldNames = useMemo(() => {
147
175
  if (!model) return [];
148
- return model.fields.filter((field) => {
176
+ const directFields = model.fields.filter((field) => {
149
177
  if (field.relationName && !field.isList) return true;
150
178
  if (field.relationName) return false;
151
179
  if (field.isList) return false;
@@ -153,7 +181,21 @@ function AdminDataListPage({ modelName: propModelName } = {}) {
153
181
  const fieldType = field.type.toLowerCase();
154
182
  return ["boolean", "int", "float", "date", "datetime"].includes(fieldType) || field.kind === "enum";
155
183
  }).map((field) => field.name);
156
- }, [model]);
184
+ const relatedEnumFields = [];
185
+ model.fields.forEach((field) => {
186
+ if (field.relationName && !field.isList) {
187
+ const relatedModel = databaseModels.find((m) => m.name === field.type);
188
+ if (relatedModel) {
189
+ relatedModel.fields.forEach((relatedField) => {
190
+ if (relatedField.kind === "enum") {
191
+ relatedEnumFields.push(`${field.name}.${relatedField.name}`);
192
+ }
193
+ });
194
+ }
195
+ }
196
+ });
197
+ return [...directFields, ...relatedEnumFields];
198
+ }, [model, databaseModels]);
157
199
  const searchableFieldNames = useMemo(() => {
158
200
  if (!model) return [];
159
201
  return model.fields.filter((field) => {
@@ -588,108 +630,30 @@ function AdminDataListPage({ modelName: propModelName } = {}) {
588
630
  ] })
589
631
  ] }),
590
632
  /* @__PURE__ */ jsx("div", { className: "grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4", children: filterableFieldNames.map((fieldName) => {
591
- const field = model.fields.find((f) => f.name === fieldName);
592
- if (!field) return null;
593
- const currentValue = filters[fieldName];
633
+ const isRelatedEnumField = fieldName.includes(".");
594
634
  const handleChange = (value) => {
595
- const newFilters = { ...filters };
596
- if (value === void 0 || value === null || value === "") {
597
- delete newFilters[fieldName];
635
+ let newFilters;
636
+ if (isRelatedEnumField) {
637
+ const [relationName, enumFieldName] = fieldName.split(".");
638
+ newFilters = updateRelatedEnumFilter(filters, relationName, enumFieldName, value);
598
639
  } else {
599
- newFilters[fieldName] = value;
640
+ newFilters = updateSimpleFilter(filters, fieldName, value);
600
641
  }
601
642
  setFilters(newFilters);
602
643
  dispatch({ type: "RESET_PAGINATION" });
603
644
  };
604
- if (field.relationName && !field.isList) {
605
- return /* @__PURE__ */ jsx(
606
- RelationFilterField,
607
- {
608
- fieldName,
609
- relatedModelName: field.type,
610
- currentValue,
611
- onChange: handleChange
612
- },
613
- fieldName
614
- );
615
- }
616
- if (field.type.toLowerCase() === "datetime" || field.type.toLowerCase() === "date") {
617
- return /* @__PURE__ */ jsx(
618
- DateRangeFilter,
619
- {
620
- fieldName,
621
- currentValue,
622
- onChange: handleChange
623
- },
624
- fieldName
625
- );
626
- }
627
- if (["int", "bigint", "float", "decimal"].includes(field.type.toLowerCase())) {
628
- return /* @__PURE__ */ jsx(
629
- NumberRangeFilter,
630
- {
631
- fieldName,
632
- fieldType: field.type.toLowerCase(),
633
- currentValue,
634
- onChange: handleChange
635
- },
636
- fieldName
637
- );
638
- }
639
- if (field.kind === "enum") {
640
- const enumValues = getEnumValues(field.type);
641
- if (enumValues) {
642
- return /* @__PURE__ */ jsxs("div", { className: "space-y-1", children: [
643
- /* @__PURE__ */ jsx("label", { className: "block text-sm font-medium text-gray-700", children: formatFieldName(fieldName) }),
644
- /* @__PURE__ */ jsxs(
645
- "select",
646
- {
647
- value: typeof currentValue === "string" ? currentValue : "",
648
- onChange: (e) => handleChange(e.target.value || void 0),
649
- className: "w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-green-web focus:border-green-web text-sm",
650
- children: [
651
- /* @__PURE__ */ jsx("option", { value: "", children: "All" }),
652
- enumValues.map((val) => /* @__PURE__ */ jsx("option", { value: val, children: val }, val))
653
- ]
654
- }
655
- )
656
- ] }, fieldName);
657
- }
658
- }
659
- if (field.type.toLowerCase() === "boolean") {
660
- return /* @__PURE__ */ jsxs("div", { className: "space-y-1", children: [
661
- /* @__PURE__ */ jsx("label", { className: "block text-sm font-medium text-gray-700", children: formatFieldName(fieldName) }),
662
- /* @__PURE__ */ jsxs(
663
- "select",
664
- {
665
- value: currentValue === void 0 || currentValue === null ? "" : currentValue.toString(),
666
- onChange: (e) => {
667
- const value = e.target.value;
668
- handleChange(value === "" ? void 0 : value === "true");
669
- },
670
- className: "w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-green-web focus:border-green-web text-sm",
671
- children: [
672
- /* @__PURE__ */ jsx("option", { value: "", children: "All" }),
673
- /* @__PURE__ */ jsx("option", { value: "true", children: "Yes" }),
674
- /* @__PURE__ */ jsx("option", { value: "false", children: "No" })
675
- ]
676
- }
677
- )
678
- ] }, fieldName);
679
- }
680
- return /* @__PURE__ */ jsxs("div", { className: "space-y-1", children: [
681
- /* @__PURE__ */ jsx("label", { className: "block text-sm font-medium text-gray-700", children: formatFieldName(fieldName) }),
682
- /* @__PURE__ */ jsx(
683
- "input",
684
- {
685
- type: "text",
686
- value: typeof currentValue === "string" ? currentValue : "",
687
- onChange: (e) => handleChange(e.target.value || void 0),
688
- placeholder: `Filter by ${formatFieldName(fieldName).toLowerCase()}...`,
689
- className: "w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-green-web focus:border-green-web text-sm"
690
- }
691
- )
692
- ] }, fieldName);
645
+ return /* @__PURE__ */ jsx(
646
+ FilterField,
647
+ {
648
+ fieldName,
649
+ model,
650
+ databaseModels,
651
+ filters,
652
+ onChange: handleChange,
653
+ getEnumValues
654
+ },
655
+ fieldName
656
+ );
693
657
  }) })
694
658
  ] });
695
659
  const searchFilter = /* @__PURE__ */ jsxs("div", { className: "mb-4 flex items-center justify-between", children: [
@@ -1,5 +1,6 @@
1
1
  import { FormField } from '@nestledjs/forms';
2
2
  import { DatabaseModel } from '../types';
3
+ import { DisplayFieldConfig } from '../context/AdminDataContext';
3
4
  /**
4
5
  * Get GraphQL documents for admin CRUD operations
5
6
  */
@@ -14,10 +15,20 @@ export declare function getAdminDocuments(sdk: any, model: DatabaseModel): {
14
15
  * Get the GraphQL mutation name for a given operation
15
16
  */
16
17
  export declare function getMutationName(model: DatabaseModel, operation: 'create' | 'update' | 'delete'): string;
18
+ /**
19
+ * Options for building form fields
20
+ */
21
+ export interface BuildFormFieldsOptions {
22
+ currentItem?: any;
23
+ isSubmitting?: boolean;
24
+ basePath?: string;
25
+ databaseModels?: DatabaseModel[];
26
+ displayFieldConfig?: DisplayFieldConfig;
27
+ }
17
28
  /**
18
29
  * Build form fields for a model and operation
19
30
  */
20
- export declare function buildFormFields(sdk: any, model: DatabaseModel, operation: 'create' | 'update', currentItem?: any, isSubmitting?: boolean, basePath?: string, databaseModels?: DatabaseModel[]): FormField[];
31
+ export declare function buildFormFields(sdk: any, model: DatabaseModel, operation: 'create' | 'update', options?: BuildFormFieldsOptions): FormField[];
21
32
  /**
22
33
  * Clean form input data for GraphQL mutations
23
34
  * Removes Apollo metadata and system fields
@@ -9,6 +9,9 @@ function getEnumValues(sdk, enumType) {
9
9
  if (!enumObject || typeof enumObject !== "object") {
10
10
  return null;
11
11
  }
12
+ if (enumObject.kind === "Document" || enumObject.definitions) {
13
+ return null;
14
+ }
12
15
  const values = Object.values(enumObject).filter((value) => typeof value === "string");
13
16
  if (values.length === 0) {
14
17
  const keys = Object.keys(enumObject).filter((key) => isNaN(Number(key)));
@@ -31,11 +34,11 @@ function getAdminDocuments(sdk, model) {
31
34
  }
32
35
  const normalizedModelName = normalizeModelNameForDocument(model.name);
33
36
  const normalizedPluralName = normalizeModelNameForDocument(getPluralName(model.name));
34
- const singleQueryDocumentName = `__Admin${normalizedModelName}Document`;
35
- const listQueryDocumentName = `__Admin${normalizedPluralName}Document`;
36
- const updateDocumentName = `__AdminUpdate${normalizedModelName}Document`;
37
- const deleteDocumentName = `__AdminDelete${normalizedModelName}Document`;
38
- const createDocumentName = `__AdminCreate${normalizedModelName}Document`;
37
+ const singleQueryDocumentName = `__Admin${normalizedModelName}`;
38
+ const listQueryDocumentName = `__Admin${normalizedPluralName}`;
39
+ const updateDocumentName = `__AdminUpdate${normalizedModelName}`;
40
+ const deleteDocumentName = `__AdminDelete${normalizedModelName}`;
41
+ const createDocumentName = `__AdminCreate${normalizedModelName}`;
39
42
  const documents = {
40
43
  query: sdk[singleQueryDocumentName],
41
44
  // For single item
@@ -90,9 +93,16 @@ function findForeignKeyFieldName(relatedModel, currentModelName, relationName) {
90
93
  });
91
94
  return ((_a = foreignKeyField == null ? void 0 : foreignKeyField.relationFromFields) == null ? void 0 : _a[0]) || null;
92
95
  }
93
- function buildFormFields(sdk, model, operation, currentItem, isSubmitting, basePath = "/admin/data", databaseModels) {
96
+ function buildFormFields(sdk, model, operation, options = {}) {
97
+ const {
98
+ currentItem,
99
+ isSubmitting = false,
100
+ basePath = "/admin/data",
101
+ databaseModels,
102
+ displayFieldConfig
103
+ } = options;
94
104
  const editableFields = model.fields.filter((field) => {
95
- if (operation === "create" && field.isId) return false;
105
+ if (field.isId) return false;
96
106
  if (field.isReadOnly || field.isGenerated) return false;
97
107
  if (field.isUpdatedAt || field.name === "createdAt") return false;
98
108
  return true;
@@ -100,6 +110,18 @@ function buildFormFields(sdk, model, operation, currentItem, isSubmitting, baseP
100
110
  const regularFields = editableFields.filter((f) => !(f.relationName && f.isList));
101
111
  const listRelationFields = editableFields.filter((f) => f.relationName && f.isList);
102
112
  const formFields = [];
113
+ if (operation === "update" && currentItem) {
114
+ const idField = model.fields.find((f) => f.isId);
115
+ if (idField) {
116
+ formFields.push(
117
+ FormFieldClass.text(idField.name, {
118
+ label: idField.name.replaceAll(/([a-z])([A-Z])/g, "$1 $2").replace(/^./, (str) => str.toUpperCase()),
119
+ disabled: true,
120
+ helpText: "ID fields are immutable and cannot be changed"
121
+ })
122
+ );
123
+ }
124
+ }
103
125
  regularFields.forEach((field) => {
104
126
  var _a;
105
127
  const label = field.name.replace(/([a-z])([A-Z])/g, "$1 $2").replace(/^./, (str) => str.toUpperCase());
@@ -132,7 +154,7 @@ function buildFormFields(sdk, model, operation, currentItem, isSubmitting, baseP
132
154
  }
133
155
  const isArrayField = Boolean(field.isList);
134
156
  const isRequired = isArrayField ? false : !field.isOptional;
135
- const options = {
157
+ const options2 = {
136
158
  label,
137
159
  required: isRequired,
138
160
  ...initialValue !== void 0 && { value: initialValue }
@@ -141,35 +163,35 @@ function buildFormFields(sdk, model, operation, currentItem, isSubmitting, baseP
141
163
  switch (field.type.toLowerCase()) {
142
164
  case "string":
143
165
  if (field.name.toLowerCase().includes("email")) {
144
- formField = FormFieldClass.email(field.name, options);
166
+ formField = FormFieldClass.email(field.name, options2);
145
167
  } else if (field.name.toLowerCase().includes("description") || field.name.toLowerCase().includes("content") || field.name.toLowerCase().includes("notes")) {
146
- formField = FormFieldClass.textArea(field.name, options);
168
+ formField = FormFieldClass.textArea(field.name, options2);
147
169
  } else {
148
- formField = FormFieldClass.text(field.name, options);
170
+ formField = FormFieldClass.text(field.name, options2);
149
171
  }
150
172
  break;
151
173
  case "int":
152
174
  case "bigint":
153
- formField = FormFieldClass.text(field.name, options);
175
+ formField = FormFieldClass.text(field.name, options2);
154
176
  break;
155
177
  case "float":
156
178
  case "decimal":
157
- formField = FormFieldClass.text(field.name, options);
179
+ formField = FormFieldClass.text(field.name, options2);
158
180
  break;
159
181
  case "boolean": {
160
182
  const booleanValue = currentItem && operation === "update" ? Boolean(currentItem[field.name]) : false;
161
183
  formField = FormFieldClass.checkbox(field.name, {
162
- ...options,
184
+ ...options2,
163
185
  required: false,
164
186
  ...operation === "update" && { value: booleanValue }
165
187
  });
166
188
  break;
167
189
  }
168
190
  case "datetime":
169
- formField = FormFieldClass.dateTimePicker(field.name, options);
191
+ formField = FormFieldClass.dateTimePicker(field.name, options2);
170
192
  break;
171
193
  case "date":
172
- formField = FormFieldClass.datePicker(field.name, options);
194
+ formField = FormFieldClass.datePicker(field.name, options2);
173
195
  break;
174
196
  default: {
175
197
  const enumValues = getEnumValues(sdk, field.type);
@@ -179,7 +201,7 @@ function buildFormFields(sdk, model, operation, currentItem, isSubmitting, baseP
179
201
  label: value.replace(/_/g, " ").toLowerCase().replace(/^./, (str) => str.toUpperCase())
180
202
  }));
181
203
  formField = FormFieldClass.select(field.name, {
182
- ...options,
204
+ ...options2,
183
205
  options: selectOptions
184
206
  });
185
207
  break;
@@ -200,25 +222,25 @@ function buildFormFields(sdk, model, operation, currentItem, isSubmitting, baseP
200
222
  relationValue = "";
201
223
  }
202
224
  const properPluralName = getPluralName(field.type);
203
- const adminDocumentName = `__Admin${properPluralName}Document`;
204
- const regularDocumentName = `${properPluralName}Document`;
225
+ const adminDocumentName = `__Admin${properPluralName}`;
226
+ const regularDocumentName = `${properPluralName}`;
205
227
  const relationDocument = sdk[adminDocumentName] || sdk[regularDocumentName];
206
228
  if (relationDocument) {
207
- let searchField = "id";
208
- if (field.type === "Course") {
209
- searchField = "title";
210
- } else if (field.type === "User") {
211
- searchField = "name";
212
- } else if (field.type === "Program") {
213
- searchField = "name";
214
- } else {
215
- searchField = "title";
216
- }
229
+ const config = displayFieldConfig == null ? void 0 : displayFieldConfig[field.type];
230
+ const displayFields = (config == null ? void 0 : config.display) || ["name", "title"];
231
+ const searchFields = (config == null ? void 0 : config.search) || displayFields;
232
+ const getDisplayLabel = (item) => {
233
+ const allValues = displayFields.map((field2) => item[field2]).filter((val) => val != null && val !== "");
234
+ if (allValues.length > 0) {
235
+ return allValues.join(" ");
236
+ }
237
+ return item.id;
238
+ };
217
239
  let initialOptions = [];
218
240
  if (currentItem && operation === "update") {
219
241
  const currentRelationData = currentItem[field.name];
220
242
  if (currentRelationData && typeof currentRelationData === "object" && currentRelationData.id) {
221
- const displayLabel = currentRelationData[searchField] || currentRelationData.title || currentRelationData.name || currentRelationData.id;
243
+ const displayLabel = getDisplayLabel(currentRelationData);
222
244
  initialOptions = [
223
245
  {
224
246
  value: currentRelationData.id,
@@ -230,16 +252,16 @@ function buildFormFields(sdk, model, operation, currentItem, isSubmitting, baseP
230
252
  formField = FormFieldClass.searchSelectApollo(relationFieldName, {
231
253
  label,
232
254
  // Remove "ID" suffix - just use the field name
233
- required: options.required,
255
+ required: options2.required,
234
256
  dataType: properPluralName.charAt(0).toLowerCase() + properPluralName.slice(1),
235
257
  // e.g., Course → courses (camelCase)
236
258
  document: relationDocument,
237
- searchFields: [searchField],
259
+ searchFields,
238
260
  // For searching
239
261
  selectOptionsFunction: (items) => {
240
262
  const queryOptions = items.map((item) => ({
241
263
  value: item.id,
242
- label: item[searchField] || item.title || item.name || item.id
264
+ label: getDisplayLabel(item)
243
265
  }));
244
266
  const allOptions = [...initialOptions];
245
267
  queryOptions.forEach((option) => {
@@ -247,6 +269,7 @@ function buildFormFields(sdk, model, operation, currentItem, isSubmitting, baseP
247
269
  allOptions.push(option);
248
270
  }
249
271
  });
272
+ allOptions.sort((a, b) => a.label.localeCompare(b.label));
250
273
  return allOptions;
251
274
  },
252
275
  ...initialOptions.length > 0 && { initialOptions },
@@ -270,7 +293,7 @@ function buildFormFields(sdk, model, operation, currentItem, isSubmitting, baseP
270
293
  } else {
271
294
  formField = FormFieldClass.text(relationFieldName, {
272
295
  label: `${label} ID`,
273
- required: options.required,
296
+ required: options2.required,
274
297
  helpText: "Enter the ID of the related record",
275
298
  ...relationValue !== void 0 && { value: relationValue }
276
299
  });
@@ -283,12 +306,12 @@ function buildFormFields(sdk, model, operation, currentItem, isSubmitting, baseP
283
306
  label: value.replace(/_/g, " ").toLowerCase().replace(/^./, (str) => str.toUpperCase())
284
307
  }));
285
308
  formField = FormFieldClass.select(field.name, {
286
- ...options,
309
+ ...options2,
287
310
  options: selectOptions
288
311
  });
289
312
  break;
290
313
  }
291
- formField = FormFieldClass.text(field.name, options);
314
+ formField = FormFieldClass.text(field.name, options2);
292
315
  break;
293
316
  }
294
317
  }
@@ -429,9 +452,7 @@ function cleanFormInput(input, model) {
429
452
  if (typeof value === "string") {
430
453
  const field = (_c = model == null ? void 0 : model.fields) == null ? void 0 : _c.find((f) => f.name === key);
431
454
  const convertedValue = convertStringValue(value, field);
432
- if (convertedValue !== null) {
433
- cleaned[key] = convertedValue;
434
- }
455
+ cleaned[key] = convertedValue;
435
456
  continue;
436
457
  }
437
458
  if (typeof value === "object" && value !== null && !Array.isArray(value)) {
@@ -5,6 +5,20 @@ function spacedWords(name) {
5
5
  return name.replaceAll(/([a-z])([A-Z])/g, "$1 $2").replaceAll(/([A-Z])([A-Z][a-z])/g, "$1 $2");
6
6
  }
7
7
  function formatFieldName(fieldName) {
8
+ if (fieldName.includes(".")) {
9
+ return fieldName.split(".").map((part) => {
10
+ if (part === part.toUpperCase() && part.length > 1) {
11
+ return part.charAt(0).toUpperCase() + part.slice(1).toLowerCase();
12
+ }
13
+ return part.replaceAll(/([a-z])([A-Z])/g, "$1 $2").replace(/^./, (str) => str.toUpperCase());
14
+ }).join(" ");
15
+ }
16
+ if (fieldName === fieldName.toUpperCase() && fieldName.length > 1) {
17
+ if (fieldName.includes("_")) {
18
+ return fieldName.split("_").map((part) => part.charAt(0).toUpperCase() + part.slice(1).toLowerCase()).join(" ");
19
+ }
20
+ return fieldName.charAt(0).toUpperCase() + fieldName.slice(1).toLowerCase();
21
+ }
8
22
  return fieldName.replaceAll(/([a-z])([A-Z])/g, "$1 $2").replace(/^./, (str) => str.toUpperCase());
9
23
  }
10
24
  function normalizeModelNameForDocument(modelName) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nestledjs/data-browser",
3
- "version": "0.1.24",
3
+ "version": "1.0.0",
4
4
  "description": "Universal admin data browser for Nestled framework projects with full CRUD operations",
5
5
  "main": "./index.js",
6
6
  "module": "./index.js",
@@ -38,7 +38,7 @@
38
38
  "@apollo/client": "^4.0.0",
39
39
  "@heroicons/react": "^2.0.0",
40
40
  "@nestledjs/forms": "^0.5.0",
41
- "@nestledjs/shared-components": "^0.1.24",
41
+ "@nestledjs/shared-components": "^1.0.0",
42
42
  "react": "^19.0.0",
43
43
  "react-router": "^7.0.0"
44
44
  },