@donotdev/crud 0.0.22 → 0.0.24
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/CrudService.d.ts.map +1 -1
- package/dist/CrudService.js +2 -2
- package/dist/CrudStore.js +1 -1
- package/dist/FieldRegistry.js +1 -1
- package/dist/adapters/FunctionsAdapter.d.ts +13 -1
- package/dist/adapters/FunctionsAdapter.d.ts.map +1 -1
- package/dist/adapters/FunctionsAdapter.js +1 -1
- package/dist/builtinFieldTypes.d.ts +12 -10
- package/dist/builtinFieldTypes.d.ts.map +1 -1
- package/dist/components/CrudButton.js +1 -1
- package/dist/components/CrudCard.js +1 -1
- package/dist/components/DateFilter.js +1 -1
- package/dist/components/DisplayFieldRenderer.js +1 -1
- package/dist/components/DisplayThumbnail.js +1 -1
- package/dist/components/EntityFilters.d.ts.map +1 -1
- package/dist/components/EntityFilters.js +1 -1
- package/dist/components/FormFieldRenderer.d.ts +0 -1
- package/dist/components/FormFieldRenderer.d.ts.map +1 -1
- package/dist/components/FormFieldRenderer.js +1 -1
- package/dist/components/FormLayout.js +1 -1
- package/dist/components/controlled/complex/ControlledAddressField.js +1 -1
- package/dist/components/controlled/complex/ControlledDateField.js +1 -1
- package/dist/components/controlled/complex/ControlledFieldArrayField.js +1 -1
- package/dist/components/controlled/complex/ControlledGeoPointField.js +1 -1
- package/dist/components/controlled/complex/ControlledMapField.js +1 -1
- package/dist/components/controlled/complex/ControlledMultiInputField.js +1 -1
- package/dist/components/controlled/complex/ControlledRichTextField.js +1 -1
- package/dist/components/controlled/complex/ControlledTimestampField.js +1 -1
- package/dist/components/controlled/complex/index.js +1 -1
- package/dist/components/controlled/file/ControlledDocumentField.js +1 -1
- package/dist/components/controlled/file/ControlledFileField.js +1 -1
- package/dist/components/controlled/file/ControlledImageField.js +1 -1
- package/dist/components/controlled/file/ControlledMultiDocumentField.js +1 -1
- package/dist/components/controlled/file/ControlledMultiFileField.js +1 -1
- package/dist/components/controlled/file/ControlledMultiImageField.js +1 -1
- package/dist/components/controlled/file/index.js +1 -1
- package/dist/components/controlled/index.js +1 -1
- package/dist/components/controlled/input/ControlledCheckboxField.js +1 -1
- package/dist/components/controlled/input/ControlledCurrencyField.js +1 -1
- package/dist/components/controlled/input/ControlledDurationField.js +1 -1
- package/dist/components/controlled/input/ControlledGdprConsentField.js +1 -1
- package/dist/components/controlled/input/ControlledNumberField.js +1 -1
- package/dist/components/controlled/input/ControlledPasswordField.js +1 -1
- package/dist/components/controlled/input/ControlledPhoneField.js +1 -1
- package/dist/components/controlled/input/ControlledPriceField.js +1 -1
- package/dist/components/controlled/input/ControlledRangeField.js +1 -1
- package/dist/components/controlled/input/ControlledRatingField.js +1 -1
- package/dist/components/controlled/input/ControlledSwitchField.js +1 -1
- package/dist/components/controlled/input/ControlledTextField.js +1 -1
- package/dist/components/controlled/input/ControlledTextareaField.js +1 -1
- package/dist/components/controlled/input/index.js +1 -1
- package/dist/components/controlled/select/ControlledComboboxField.js +1 -1
- package/dist/components/controlled/select/ControlledDropdownField.js +1 -1
- package/dist/components/controlled/select/ControlledMultiDropdownField.js +1 -1
- package/dist/components/controlled/select/ControlledRadioField.js +1 -1
- package/dist/components/controlled/select/ControlledReferenceField.js +1 -1
- package/dist/components/controlled/select/ControlledYearField.js +1 -1
- package/dist/components/controlled/select/index.js +1 -1
- package/dist/components/controlled/types.js +1 -1
- package/dist/components/fields/display/AvatarFieldDisplay.js +1 -1
- package/dist/components/fields/display/BadgeFieldDisplay.js +1 -1
- package/dist/components/fields/display/ButtonFieldDisplay.js +1 -1
- package/dist/components/fields/display/CheckboxFieldDisplay.js +1 -1
- package/dist/components/fields/display/DateFieldDisplay.js +1 -1
- package/dist/components/fields/display/DropdownDisplay.js +1 -1
- package/dist/components/fields/display/FileFieldDisplay.js +1 -1
- package/dist/components/fields/display/GeoPointFieldDisplay.js +1 -1
- package/dist/components/fields/display/HiddenFieldDisplay.js +1 -1
- package/dist/components/fields/display/ImageFieldDisplay.js +1 -1
- package/dist/components/fields/display/LinkFieldDisplay.js +1 -1
- package/dist/components/fields/display/MapFieldDisplay.js +1 -1
- package/dist/components/fields/display/MultiDropdownDisplay.js +1 -1
- package/dist/components/fields/display/MultiInputTextFieldDisplay.js +1 -1
- package/dist/components/fields/display/NumberFieldDisplay.js +1 -1
- package/dist/components/fields/display/PasswordFieldDisplay.js +1 -1
- package/dist/components/fields/display/PhoneNumberDisplay.js +1 -1
- package/dist/components/fields/display/RadioFieldDisplay.js +1 -1
- package/dist/components/fields/display/RangeFieldDisplay.js +1 -1
- package/dist/components/fields/display/ReferenceFieldDisplay.js +1 -1
- package/dist/components/fields/display/RichTextDisplay.js +2 -2
- package/dist/components/fields/display/TextAreaDisplay.js +1 -1
- package/dist/components/fields/display/TextFieldDisplay.js +1 -1
- package/dist/components/fields/display/TimestampFieldDisplay.js +1 -1
- package/dist/components/fields/display/index.js +1 -1
- package/dist/components/form/fields/AddressFieldComponent.js +1 -1
- package/dist/components/form/fields/AvatarFieldComponent.js +1 -1
- package/dist/components/form/fields/BadgeFieldComponent.js +1 -1
- package/dist/components/form/fields/ButtonFieldComponent.js +1 -1
- package/dist/components/form/fields/CheckboxFieldComponent.js +1 -1
- package/dist/components/form/fields/ComboboxComponent.js +1 -1
- package/dist/components/form/fields/CurrencyFieldComponent.js +1 -1
- package/dist/components/form/fields/DateFieldComponent.js +1 -1
- package/dist/components/form/fields/DocumentFieldComponent.js +1 -1
- package/dist/components/form/fields/DropdownComponent.js +1 -1
- package/dist/components/form/fields/DurationFieldComponent.js +1 -1
- package/dist/components/form/fields/FileFieldComponent.js +1 -1
- package/dist/components/form/fields/GdprConsentFieldComponent.js +1 -1
- package/dist/components/form/fields/GeoPointFieldComponent.js +1 -1
- package/dist/components/form/fields/HiddenFieldComponent.js +1 -1
- package/dist/components/form/fields/ImageFieldComponent.js +1 -1
- package/dist/components/form/fields/MapFieldComponent.js +1 -1
- package/dist/components/form/fields/MultiDropdownComponent.js +1 -1
- package/dist/components/form/fields/MultiInputTextFieldComponent.js +1 -1
- package/dist/components/form/fields/NumberFieldComponent.js +1 -1
- package/dist/components/form/fields/PasswordFieldComponent.js +1 -1
- package/dist/components/form/fields/PhoneNumberComponent.js +1 -1
- package/dist/components/form/fields/PriceFieldComponent.js +1 -1
- package/dist/components/form/fields/RadioFieldComponent.js +1 -1
- package/dist/components/form/fields/RangeFieldComponent.js +1 -1
- package/dist/components/form/fields/RatingFieldComponent.js +1 -1
- package/dist/components/form/fields/ReferenceFieldComponent.js +1 -1
- package/dist/components/form/fields/RichTextComponent.js +1 -1
- package/dist/components/form/fields/SwitchFieldComponent.js +1 -1
- package/dist/components/form/fields/TextAreaComponent.js +1 -1
- package/dist/components/form/fields/TextFieldComponent.js +1 -1
- package/dist/components/form/fields/TimestampFieldComponent.js +1 -1
- package/dist/components/form/fields/index.js +1 -1
- package/dist/components/form/fields/internal/TiptapEditor.js +2 -2
- package/dist/components/form/internal/ImageViewerDialog.js +1 -1
- package/dist/components/index.js +1 -1
- package/dist/contexts/UploadContext.js +1 -1
- package/dist/contexts/index.js +1 -1
- package/dist/fieldTypeRegistry.d.ts +38 -14
- package/dist/fieldTypeRegistry.d.ts.map +1 -1
- package/dist/fieldTypeRegistry.js +1 -1
- package/dist/forms/hooks/index.js +1 -1
- package/dist/forms/hooks/useController.js +1 -1
- package/dist/forms/hooks/useEntityField.js +1 -1
- package/dist/forms/hooks/useEntityForm.js +1 -1
- package/dist/forms/index.js +1 -1
- package/dist/forms/utils/buildInitialValues.js +1 -1
- package/dist/forms/utils/getFieldsForOperation.js +1 -1
- package/dist/forms/utils/index.js +1 -1
- package/dist/forms/utils/isFieldEditable.js +1 -1
- package/dist/forms/utils/translateFieldLabel.js +1 -1
- package/dist/forms/utils/validateEntity.js +1 -1
- package/dist/hooks/index.js +1 -1
- package/dist/hooks/useCrudFilters.js +1 -1
- package/dist/hooks/useEntityFavorites.js +1 -1
- package/dist/hooks/useFieldConditions.js +1 -1
- package/dist/hooks/useFileUpload.js +1 -1
- package/dist/hooks/useReferenceResolver.js +1 -1
- package/dist/hooks/useRelatedItems.js +1 -1
- package/dist/hooks/useUnsavedChangesWarning.js +1 -1
- package/dist/index.d.ts +5 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/registerBuiltinFieldTypes.js +1 -1
- package/dist/stores/FormStore.js +1 -1
- package/dist/stores/UploadStore.js +1 -1
- package/dist/stores/index.js +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/dist/types.js +1 -1
- package/dist/useBaseCrudList.js +1 -1
- package/dist/useCrud.js +1 -1
- package/dist/useCrudCardList.js +1 -1
- package/dist/useCrudList.js +1 -1
- package/dist/utils/clientListProcessing.js +1 -1
- package/dist/utils/collections.js +1 -1
- package/dist/utils/fileStorage.d.ts.map +1 -1
- package/dist/utils/fileStorage.js +1 -1
- package/dist/utils/imageProcessing.js +1 -1
- package/dist/utils/imageStorage.d.ts.map +1 -1
- package/dist/utils/imageStorage.js +1 -1
- package/dist/utils/imageUtils.js +1 -1
- package/dist/utils/matchesFilter.js +1 -1
- package/dist/utils/mergeWithOptimistic.js +1 -1
- package/dist/utils/sanitizeHtml.js +1 -1
- package/dist/utils/scopeUtils.js +1 -1
- package/dist/utils/uploadValidation.js +1 -1
- package/dist/workflows/WorkflowPersistence.js +1 -1
- package/dist/workflows/index.js +1 -1
- package/dist/workflows/useEntityWorkflow.js +1 -1
- package/package.json +3 -14
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CrudService.d.ts","sourceRoot":"","sources":["../src/CrudService.ts"],"names":[],"mappings":"AA+CA,OAAO,KAAK,EACV,WAAW,EACX,WAAW,EAEX,YAAY,EACZ,oBAAoB,EACpB,cAAc,EACd,eAAe,EAChB,MAAM,gBAAgB,CAAC;
|
|
1
|
+
{"version":3,"file":"CrudService.d.ts","sourceRoot":"","sources":["../src/CrudService.ts"],"names":[],"mappings":"AA+CA,OAAO,KAAK,EACV,WAAW,EACX,WAAW,EAEX,YAAY,EACZ,oBAAoB,EACpB,cAAc,EACd,eAAe,EAChB,MAAM,gBAAgB,CAAC;AAexB,OAAO,KAAK,EAGV,YAAY,EACZ,oBAAoB,EACpB,YAAY,EACZ,eAAe,EAEhB,MAAM,SAAS,CAAC;AASjB,YAAY,EAAE,YAAY,EAAE,CAAC;AAQ7B;;;;;;GAMG;AACH,cAAM,WAAY,YAAW,oBAAoB;IAC/C,OAAO,CAAC,OAAO,CAA6B;IAC5C,OAAO,CAAC,KAAK,CAA6B;IAC1C,oFAAoF;IACpF,OAAO,CAAC,QAAQ,CAAgC;IAChD;;;;OAIG;IACH,OAAO,CAAC,aAAa,CAAuB;IAM5C;;;;;OAKG;IACH,OAAO,CAAC,uBAAuB;IAW/B,QAAQ,CAAC,KAAK,EAAE,YAAY,GAAG,IAAI;IAInC;;;;;;;;;OASG;IACH,WAAW,CAAC,QAAQ,EAAE,eAAe,GAAG,IAAI;IAI5C;;;;;;;;;;OAUG;IACH,cAAc,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,GAAG,IAAI;IAI3C;;;OAGG;IACH,OAAO,CAAC,aAAa;IAMrB;;;OAGG;IACH,OAAO,CAAC,UAAU;IAelB;;;;;;;;;OASG;IACH,OAAO,CAAC,aAAa;IAMrB,4DAA4D;YAC9C,cAAc;IAK5B;;;OAGG;IACH,OAAO,CAAC,gBAAgB;IAsBxB;;;;;OAKG;IACG,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;IA4BjC;;;OAGG;IACH,cAAc,IAAI,WAAW;IAI7B;;;;OAIG;IACH,mBAAmB,CAAC,CAAC,EACnB,UAAU,EAAE,MAAM,EAClB,YAAY,EAAE,YAAY,EAC1B,MAAM,EAAE,WAAW,CAAC,OAAO,CAAC,EAC5B,YAAY,CAAC,EAAE,YAAY,EAC3B,UAAU,GAAE,cAAsC;;uBAa7B,OAAO,CAAC,oBAAoB,CAAC,CAAC,CAAC,CAAC;;;IAcvD;;;;OAIG;IACH,kBAAkB,CAAC,CAAC,EAClB,UAAU,EAAE,MAAM,EAClB,EAAE,EAAE,MAAM,EACV,MAAM,EAAE,WAAW,CAAC,OAAO,CAAC,EAC5B,YAAY,CAAC,EAAE,YAAY;;uBAON,OAAO,CAAC,CAAC,GAAG,IAAI,CAAC;;;IASxC;;;OAGG;IACH,OAAO,CAAC,eAAe;IA4BvB;;;OAGG;IACH,OAAO,CAAC,iBAAiB;IAkHzB;;;;;OAKG;IACH,OAAO,CAAC,yBAAyB;IAgFjC;;;OAGG;IACH,OAAO,CAAC,qBAAqB;IAgB7B;;OAEG;IACG,oBAAoB,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAWvD,GAAG,CAAC,CAAC,EACT,UAAU,EAAE,MAAM,EAClB,EAAE,EAAE,MAAM,EACV,MAAM,EAAE,WAAW,CAAC,CAAC,CAAC,EACtB,OAAO,CAAC,EAAE,YAAY,GACrB,OAAO,CAAC,CAAC,GAAG,IAAI,CAAC;IA0CpB,sDAAsD;YACxC,eAAe;IAgDvB,KAAK,CAAC,CAAC,EACX,UAAU,EAAE,MAAM,EAClB,OAAO,EAAE,YAAY,EACrB,MAAM,EAAE,WAAW,CAAC,CAAC,CAAC,EACtB,YAAY,CAAC,EAAE,YAAY,EAC3B,UAAU,GAAE,cAAsC,GACjD,OAAO,CAAC,oBAAoB,CAAC,CAAC,CAAC,CAAC;IAyDnC,sDAAsD;YACxC,iBAAiB;IA6D/B;;;;OAIG;IACH,OAAO,CAAC,cAAc;IAqChB,GAAG,CAAC,CAAC,EACT,UAAU,EAAE,MAAM,EAClB,EAAE,EAAE,MAAM,EACV,IAAI,EAAE,CAAC,EACP,MAAM,EAAE,WAAW,CAAC,CAAC,CAAC,EACtB,OAAO,CAAC,EAAE,eAAe,GACxB,OAAO,CAAC,IAAI,CAAC;IAiGV,MAAM,CAAC,CAAC,EACZ,UAAU,EAAE,MAAM,EAClB,EAAE,EAAE,MAAM,EACV,IAAI,EAAE,OAAO,CAAC,CAAC,CAAC,EAChB,MAAM,CAAC,EAAE,WAAW,CAAC,CAAC,CAAC,EACvB,OAAO,CAAC,EAAE,eAAe,GACxB,OAAO,CAAC,IAAI,CAAC;IAmHV,MAAM,CACV,UAAU,EAAE,MAAM,EAClB,EAAE,EAAE,MAAM,EACV,OAAO,CAAC,EAAE,eAAe,GACxB,OAAO,CAAC,IAAI,CAAC;IA0FV,GAAG,CAAC,CAAC,EACT,UAAU,EAAE,MAAM,EAClB,IAAI,EAAE,CAAC,EACP,MAAM,EAAE,WAAW,CAAC,CAAC,CAAC,EACtB,OAAO,CAAC,EAAE,eAAe,GACxB,OAAO,CAAC,MAAM,CAAC;IAuHlB,SAAS,CAAC,CAAC,EACT,UAAU,EAAE,MAAM,EAClB,EAAE,EAAE,MAAM,EACV,QAAQ,EAAE,CAAC,IAAI,EAAE,CAAC,GAAG,IAAI,EAAE,KAAK,CAAC,EAAE,KAAK,KAAK,IAAI,EACjD,MAAM,EAAE,WAAW,CAAC,CAAC,CAAC,GACrB,MAAM,IAAI;IA+Bb,2EAA2E;IAC3E,OAAO,CAAC,cAAc;IAqCtB,qBAAqB,CAAC,CAAC,EACrB,UAAU,EAAE,MAAM,EAClB,OAAO,EAAE,YAAY,EACrB,QAAQ,EAAE,CAAC,IAAI,EAAE,CAAC,EAAE,EAAE,KAAK,CAAC,EAAE,KAAK,KAAK,IAAI,EAC5C,MAAM,EAAE,WAAW,CAAC,CAAC,CAAC,GACrB,MAAM,IAAI;IAkCb,uFAAuF;IACvF,OAAO,CAAC,0BAA0B;IA2C5B,aAAa,CAAC,CAAC,SAAS;QAAE,EAAE,CAAC,EAAE,MAAM,CAAA;KAAE,EAC3C,UAAU,EAAE,MAAM,EAClB,IAAI,EAAE,CAAC,EACP,MAAM,EAAE,WAAW,CAAC,CAAC,CAAC,EACtB,OAAO,CAAC,EAAE,eAAe,GACxB,OAAO,CAAC,CAAC,GAAG;QAAE,EAAE,EAAE,MAAM,CAAA;KAAE,CAAC;IAsFxB,gBAAgB,CAAC,CAAC,EACtB,UAAU,EAAE,MAAM,EAClB,EAAE,EAAE,MAAM,EACV,IAAI,EAAE,OAAO,CAAC,CAAC,CAAC,EAChB,MAAM,EAAE,WAAW,CAAC,CAAC,CAAC,EACtB,OAAO,CAAC,EAAE,eAAe,GACxB,OAAO,CAAC,CAAC,CAAC;IA4FP,gBAAgB,CACpB,UAAU,EAAE,MAAM,EAClB,EAAE,EAAE,MAAM,EACV,OAAO,CAAC,EAAE,eAAe,GACxB,OAAO,CAAC,IAAI,CAAC;CA6EjB;AAED;;;;;;GAMG;AACH,eAAO,MAAM,cAAc,mBAE1B,CAAC"}
|
package/dist/CrudService.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import{toast as
|
|
1
|
+
import{toast as w}from"@donotdev/components";import{createSingleton as A,handleError as f,getQueryClient as L,getI18nInstance as m,hasProvider as D,getProvider as T,hasRestrictedVisibility as F,DEFAULT_STATUS_VALUE as q}from"@donotdev/core";import{LIST_SCHEMA_TYPE as _}from"@donotdev/core";import{CRUD_OPERATION as y}from"./types";const S=1/0,P=1e3*60*30;class b{adapter=null;store=null;security=null;currentUserId=null;_shouldShowSuccessToast(t){return t?.showSuccessToast===!0?!0:t?.showSuccessToast===!1?!1:!this.store?.getState().hideSuccessToasts}setStore(t){this.store=t}setSecurity(t){this.security=t}setCurrentUser(t){this.currentUserId=t}_getPiiFields(t){return t?.security?.piiFields??[]}_auditCrud(t,e,s,i){this.security&&this.security.audit({type:t,collection:e,docId:s,userId:i??this.currentUserId??void 0})}_rateLimitKey(t){return this.currentUserId?`${this.currentUserId}:${t}`:t}async _ensureAdapter(){this.adapter||await this.initialize()}_assertCanAccess(t,e){if(this.adapter&&e&&F(e)&&!this.adapter.serverSideOnly&&!this.adapter.dbLevelSecurity)throw new Error(`[dndev] Direct adapter cannot access "${t}": entity has restricted field visibility. Use a server-side adapter (FunctionsAdapter for Firebase, or SupabaseCrudAdapter with RLS enabled) to enforce field-level security (serverSideOnly = true | dbLevelSecurity = true).`)}async initialize(){if(!this.adapter){if(!D("crud"))throw new Error(`[dndev] No CRUD adapter configured. Call configureProviders({ crud: yourAdapter }) at app startup.
|
|
2
2
|
Examples:
|
|
3
3
|
import { FirestoreAdapter } from "@donotdev/firebase";
|
|
4
4
|
import { FunctionsAdapter } from "@donotdev/crud";
|
|
@@ -6,4 +6,4 @@ Examples:
|
|
|
6
6
|
|
|
7
7
|
configureProviders({ crud: new FirestoreAdapter() }) // Firebase direct
|
|
8
8
|
configureProviders({ crud: new FunctionsAdapter() }) // via callable functions
|
|
9
|
-
configureProviders({ crud: new SupabaseCrudAdapter(sb) }) // Supabase direct (RLS)`);this.adapter=C("crud"),this.store&&this.store.getState().setCrudService(this)}}getQueryClient(){return _()}getListQueryOptions(t,e,i,r,o=S.LIST){const s=this.adapter,a=()=>this._ensureAdapter();return{queryKey:["crud",t,"query",JSON.stringify(e)],queryFn:async()=>{if(s||await a(),!this.adapter)throw new Error("Adapter not initialized");return this.adapter.query(t,e,i,o)},staleTime:r?.staleTime??m}}getDocQueryOptions(t,e,i,r){const o=this.adapter,s=()=>this._ensureAdapter();return{queryKey:["crud",t,"get",e],queryFn:async()=>{if(o||await s(),!this.adapter)throw new Error("Adapter not initialized");return this.adapter.get(t,e,i)},staleTime:r?.staleTime??m}}_updateGetCache(t,e,i,r){const o=this.getQueryClient(),s=["crud",t,"get",e];r===h.DELETE?o.removeQueries({queryKey:s}):r===h.SET&&i?o.setQueryData(s,i):(r===h.UPDATE||r===h.ADD)&&i&&o.setQueryData(s,a=>a?{...a,...i}:i)}_updateListCaches(t,e,i,r){const o=this.getQueryClient();this._updateGetCache(t,e,i,r),o.setQueriesData({queryKey:["crud",t]},s=>{if(s&&typeof s=="object"&&"items"in s){const a=s;let c=a.items;return r===h.DELETE?(c=a.items.filter(n=>n!=null&&typeof n=="object"&&n.id!==e),{...a,items:c,total:Math.max(0,(a.total??c.length)-1)}):r===h.ADD&&i?(c=[...a.items,{...i,id:e}],{...a,items:c,total:(a.total??a.items.length)+1}):(r===h.UPDATE||r===h.SET)&&i&&a.items.some(n=>n!=null&&typeof n=="object"&&n.id===e)?(c=a.items.map(n=>n==null||typeof n!="object"||n.id!==e?n:r===h.SET?{...i,id:e}:{...n,...i}),{...a,items:c}):s}if(Array.isArray(s)){if(r===h.DELETE)return s.filter(a=>a.id!==e);if(r===h.ADD&&i)return[...s,{...i,id:e}];if((r===h.UPDATE||r===h.SET)&&i)return s.some(a=>a!=null&&typeof a=="object"&&a.id===e)?s.map(a=>a==null||typeof a!="object"||a.id!==e?a:r===h.SET?{...i,id:e}:{...a,...i}):s}return s})}_checkUniquenessFromCache(t,e,i){const r=i.metadata?.uniqueKeys;if(!r||r.length===0)return null;const o=this.getQueryClient().getQueriesData({queryKey:["crud",t]}),s=[];for(const[,c]of o)c&&typeof c=="object"&&"items"in c?s.push(...c.items):Array.isArray(c)&&s.push(...c);if(s.length===0)return null;const a=e;for(const c of r){if(!c.fields.every(u=>a[u]!=null&&a[u]!==""))continue;const n=s.find(u=>c.fields.every(l=>{const g=typeof a[l]=="string"?a[l].toLowerCase():a[l],f=typeof u[l]=="string"?u[l].toLowerCase():u[l];return g===f}));if(n){if(c.findOrCreate)return n.id;const u=c.fields.join(" + ");throw d(new Error(c.errorMessage||`Duplicate ${u}`),{userMessage:c.errorMessage||`A record with this ${u} already exists`,showNotification:!0})}}return null}_getItemFromListCache(t,e){const i=this.getQueryClient().getQueriesData({queryKey:["crud",t]});for(const[,r]of i)if(r?.items){const o=r.items.find(s=>s.id===e);if(o)return o}return null}async invalidateCollection(t){await this.getQueryClient().invalidateQueries({queryKey:["crud",t]})}async get(t,e,i,r){if(await this._ensureAdapter(),r?.noCache)return this._getFromAdapter(t,e,i);this.store&&(this.store.getState().setLoading(t,!0),this.store.getState().setError(t,null));try{return await this.getQueryClient().fetchQuery({queryKey:["crud",t,"get",e],queryFn:()=>this._getFromAdapter(t,e,i,!1),staleTime:r?.staleTime??m})}catch(o){const s=d(o,{userMessage:`Failed to fetch ${t}`,showNotification:!0});throw this.store&&this.store.getState().setError(t,s),s}finally{this.store&&this.store.getState().setLoading(t,!1)}}async _getFromAdapter(t,e,i,r=!0){this.store&&r&&(this.store.getState().setLoading(t,!0),this.store.getState().setError(t,null));try{if(!this.adapter)throw new Error("Adapter not initialized");this._assertCanAccess(t,i);const o=await this.adapter.get(t,e,i);if(o&&this.security){const s=this._getPiiFields(i);if(s.length>0)return this.security.decryptPii(o,s)}return o}catch(o){const s=d(o,{userMessage:`Failed to fetch ${t}`,showNotification:!0});throw this.store&&this.store.getState().setError(t,s),s}finally{this.store&&r&&this.store.getState().setLoading(t,!1)}}async query(t,e,i,r,o=S.LIST){if(await this._ensureAdapter(),r?.noCache)return this._queryFromAdapter(t,e,i,!0,o);this.store&&(this.store.getState().setLoading(t,!0),this.store.getState().setError(t,null));try{return await this.getQueryClient().fetchQuery({queryKey:["crud",t,"query",JSON.stringify(e)],queryFn:()=>this._queryFromAdapter(t,e,i,!1,o),staleTime:r?.staleTime??m})}catch(s){const a=d(s,{userMessage:`Failed to query ${t}`,showNotification:!0});throw this.store&&this.store.getState().setError(t,a),a}finally{this.store&&this.store.getState().setLoading(t,!1)}}async _queryFromAdapter(t,e,i,r=!0,o=S.LIST){this.store&&r&&(this.store.getState().setLoading(t,!0),this.store.getState().setError(t,null));try{if(!this.adapter)throw new Error("Adapter not initialized");this._assertCanAccess(t,i);const s=await this.adapter.query(t,e,i,o);if(this.security&&s.items.length>0){const a=this._getPiiFields(i);a.length>0&&(s.items=s.items.map(c=>this.security.decryptPii(c,a)))}return s}catch(s){const a=d(s,{userMessage:`Failed to query ${t}`,showNotification:!0});throw this.store&&this.store.getState().setError(t,a),a}finally{this.store&&r&&this.store.getState().setLoading(t,!1)}}_getEntityName(t){const e=y();let i=`entity-${t}`,r=e.t("name",{ns:i,defaultValue:null});return r&&r!=="name"&&r!==`${i}:name`||t.endsWith("s")&&t.length>1&&(i=`entity-${t.slice(0,-1)}`,r=e.t("name",{ns:i,defaultValue:null}),r&&r!=="name"&&r!==`${i}:name`)?r:t}async set(t,e,i,r,o){await this._ensureAdapter(),this.store&&(this.store.getState().setLoading(t,!0),this.store.getState().setError(t,null));const s=this.getQueryClient().getQueryData(["crud",t,"get",e])??null;this.store&&this.store.getState().updateOptimistic(t,e,i,s);try{if(!this.adapter)throw new Error("Adapter not initialized");this._assertCanAccess(t,r),this.security&&await this.security.checkRateLimit(this._rateLimitKey(t),"write");const a=this._getPiiFields(r),c=a.length>0&&this.security?this.security.encryptPii(i,a):i;if(await this.adapter.set(t,e,c,r),this._updateListCaches(t,e,i,h.SET),this.store&&this.store.getState().confirmUpdate(t,e),this._auditCrud("crud.update",t,e),this._shouldShowSuccessToast(o)){const n=y(),u=this._getEntityName(t);p("success",n.t("messages.updateSuccess",{ns:"crud",entity:u}))}}catch(a){s&&this._updateListCaches(t,e,s,h.SET),this.store&&this.store.getState().rejectUpdate(t,e);const c=d(a,{userMessage:`Failed to save ${t}`,showNotification:!0});throw this.store&&this.store.getState().setError(t,c),c}finally{this.store&&this.store.getState().setLoading(t,!1)}}async update(t,e,i,r,o){await this._ensureAdapter(),this.store&&(this.store.getState().setLoading(t,!0),this.store.getState().setError(t,null));const s=this.getQueryClient().getQueryData(["crud",t,"get",e])??this._getItemFromListCache(t,e),a=s?{...s,...i}:{...i,id:e};this.store&&this.store.getState().updateOptimistic(t,e,a,s??null);try{if(!this.adapter)throw new Error("Adapter not initialized");r&&this._assertCanAccess(t,r),this.security&&await this.security.checkRateLimit(this._rateLimitKey(t),"write");const c=r?this._getPiiFields(r):[],n=c.length>0&&this.security?this.security.encryptPii(i,c):i;if(await this.adapter.update(t,e,n),this._updateListCaches(t,e,a,h.UPDATE),this.store&&this.store.getState().confirmUpdate(t,e),this._auditCrud("crud.update",t,e),this._shouldShowSuccessToast(o)){const u=y(),l=this._getEntityName(t);p("success",u.t("messages.updateSuccess",{ns:"crud",entity:l}))}}catch(c){s?this._updateListCaches(t,e,s,h.UPDATE):this.invalidateCollection(t),this.store&&this.store.getState().rejectUpdate(t,e);const n=d(c,{userMessage:`Failed to update ${t}`,showNotification:!0});throw this.store&&this.store.getState().setError(t,n),n}finally{this.store&&this.store.getState().setLoading(t,!1)}}async delete(t,e,i){await this._ensureAdapter(),this.store&&(this.store.getState().setLoading(t,!0),this.store.getState().setError(t,null));const r=this.getQueryClient().getQueryData(["crud",t,"get",e])??this._getItemFromListCache(t,e);this.store&&r&&this.store.getState().deleteOptimistic(t,e,r);try{if(!this.adapter)throw new Error("Adapter not initialized");if(this.security&&await this.security.checkRateLimit(this._rateLimitKey(t),"write"),await this.adapter.delete(t,e),this._updateListCaches(t,e,null,h.DELETE),this.store&&this.store.getState().confirmDelete(t,e),this._auditCrud("crud.delete",t,e),this.security?.recordAnomaly?.("bulk.deletes",this.currentUserId??void 0),this._shouldShowSuccessToast(i)){const o=y(),s=this._getEntityName(t);p("success",o.t("messages.deleteSuccess",{ns:"crud",entity:s}))}}catch(o){r&&this._updateListCaches(t,e,r,h.ADD),this.store&&this.store.getState().rejectDelete(t,e);const s=d(o,{userMessage:`Failed to delete ${t}`,showNotification:!0});throw this.store&&this.store.getState().setError(t,s),s}finally{this.store&&this.store.getState().setLoading(t,!1)}}async add(t,e,i,r){await this._ensureAdapter();const o=this._checkUniquenessFromCache(t,e,i);if(o)return o;this.store&&(this.store.getState().setLoading(t,!0),this.store.getState().setError(t,null));const s=`temp_${crypto.randomUUID()}`;this.store&&this.store.getState().addOptimistic(t,s,{...e,id:s});try{if(!this.adapter)throw new Error("Adapter not initialized");this._assertCanAccess(t,i),this.security&&await this.security.checkRateLimit(this._rateLimitKey(t),"write");const a=this._getPiiFields(i),c=a.length>0&&this.security?this.security.encryptPii(e,a):e,n=await this.adapter.add(t,c,i),u=n.id,l=n.data;if(this._updateListCaches(t,s,null,h.DELETE),this._updateListCaches(t,u,l,h.ADD),this.store&&this.store.getState().confirmOptimistic(t,s,u,l),this._auditCrud("crud.create",t,u),this._shouldShowSuccessToast(r)){const g=y(),f=this._getEntityName(t);p("success",g.t("messages.createSuccess",{ns:"crud",entity:f}))}return u}catch(a){this._updateListCaches(t,s,null,h.DELETE),this.store&&this.store.getState().rejectOptimistic(t,s);const c=d(a,{userMessage:`Failed to create ${t}`,showNotification:!0});throw this.store&&this.store.getState().setError(t,c),c}finally{this.store&&this.store.getState().setLoading(t,!1)}}subscribe(t,e,i,r){if(!this.adapter){let o=!1,s=null;return this._ensureAdapter().then(()=>{o||(s=this._subscribeSync(t,e,i,r))}).catch(a=>{o||i(null,d(a))}),()=>{o=!0,s?.()}}return this._subscribeSync(t,e,i,r)}_subscribeSync(t,e,i,r){try{const o=this.adapter;return o?o.subscribe?(this._assertCanAccess(t,r),o.subscribe(t,e,(s,a)=>{s&&this.getQueryClient().setQueryData(["crud",t,"get",e],s),i(s,a)},r)):()=>{}:(i(null,new Error("Adapter not initialized")),()=>{})}catch(o){return i(null,d(o)),()=>{}}}subscribeToCollection(t,e,i,r){if(!this.adapter){let o=!1,s=null;return this._ensureAdapter().then(()=>{o||(s=this._subscribeToCollectionSync(t,e,i,r))}).catch(a=>{o||i([],d(a))}),()=>{o=!0,s?.()}}return this._subscribeToCollectionSync(t,e,i,r)}_subscribeToCollectionSync(t,e,i,r){try{const o=this.adapter;return o?o.subscribeToCollection?(this._assertCanAccess(t,r),o.subscribeToCollection(t,e,(s,a)=>{s&&this.getQueryClient().setQueryData(["crud",t,"query",JSON.stringify(e)],c=>c?{...c,items:s}:{items:s}),i(s,a)},r)):()=>{}:(i([],new Error("Adapter not initialized")),()=>{})}catch(o){return i([],d(o)),()=>{}}}async addOptimistic(t,e,i,r){await this._ensureAdapter();const o=this._checkUniquenessFromCache(t,e,i);if(o)return{...e,id:o};this.security&&await this.security.checkRateLimit(this._rateLimitKey(t),"write");const s=`temp_${crypto.randomUUID()}`,a={...e,id:s,_optimistic:!0};this.store&&this.store.getState().addOptimistic(t,s,a);try{if(!this.adapter)throw new Error("Adapter not initialized");const c=await this.adapter.add(t,e,i),n=c.id,u=c.data;if(this._updateListCaches(t,s,null,h.DELETE),this._updateListCaches(t,n,u,h.ADD),this.store&&this.store.getState().confirmOptimistic(t,s,n,u),this._auditCrud("crud.create",t,n),this._shouldShowSuccessToast(r)){const l=y(),g=this._getEntityName(t);p("success",l.t("messages.createSuccess",{ns:"crud",entity:g}))}return u}catch(c){throw this._updateListCaches(t,s,null,h.DELETE),this.store&&this.store.getState().rejectOptimistic(t,s),d(c,{userMessage:`Failed to create ${t}`,showNotification:!0})}}async updateOptimistic(t,e,i,r,o){await this._ensureAdapter(),this.security&&await this.security.checkRateLimit(this._rateLimitKey(t),"write");const s=this.getQueryClient().getQueryData(["crud",t,"get",e])??this._getItemFromListCache(t,e),a=s?{...s,...i,_optimistic:!0}:{...i,id:e,_optimistic:!0};this.store&&s&&this.store.getState().updateOptimistic(t,e,a,s);try{if(!this.adapter)throw new Error("Adapter not initialized");await this.adapter.update(t,e,i);const{_optimistic:c,...n}=a;if(this._updateListCaches(t,e,n,h.UPDATE),this.store&&this.store.getState().confirmUpdate(t,e),this._auditCrud("crud.update",t,e),this._shouldShowSuccessToast(o)){const u=y(),l=this._getEntityName(t);p("success",u.t("messages.updateSuccess",{ns:"crud",entity:l}))}return n}catch(c){throw s&&this._updateListCaches(t,e,s,h.UPDATE),this.store&&this.store.getState().rejectUpdate(t,e),d(c,{userMessage:`Failed to update ${t}`,showNotification:!0})}}async deleteOptimistic(t,e,i){await this._ensureAdapter(),this.security&&await this.security.checkRateLimit(this._rateLimitKey(t),"write");const r=this.getQueryClient().getQueryData(["crud",t,"get",e])??this._getItemFromListCache(t,e);this.store&&r&&this.store.getState().deleteOptimistic(t,e,r);try{if(!this.adapter)throw new Error("Adapter not initialized");if(await this.adapter.delete(t,e),this._updateListCaches(t,e,null,h.DELETE),this.store&&this.store.getState().confirmDelete(t,e),this._auditCrud("crud.delete",t,e),this.security?.recordAnomaly?.("bulk.deletes",this.currentUserId??void 0),this._shouldShowSuccessToast(i)){const o=y(),s=this._getEntityName(t);p("success",o.t("messages.deleteSuccess",{ns:"crud",entity:s}))}}catch(o){throw r&&this._updateListCaches(t,e,r,h.ADD),this.store&&this.store.getState().rejectDelete(t,e),d(o,{userMessage:`Failed to delete ${t}`,showNotification:!0})}}}const T=w(()=>new L);export{T as getCrudService};
|
|
9
|
+
configureProviders({ crud: new SupabaseCrudAdapter(sb) }) // Supabase direct (RLS)`);this.adapter=T("crud"),this.store&&this.store.getState().setCrudService(this)}}getQueryClient(){return L()}getListQueryOptions(t,e,s,i,a=_.LIST){const r=this.adapter,u=()=>this._ensureAdapter();return{queryKey:["crud",t,"query",JSON.stringify(e)],queryFn:async()=>{if(r||await u(),!this.adapter)throw new Error("Adapter not initialized");return this.adapter.query(t,e,s,a)},staleTime:i?.staleTime??S}}getDocQueryOptions(t,e,s,i){const a=this.adapter,r=()=>this._ensureAdapter();return{queryKey:["crud",t,"get",e],queryFn:async()=>{if(a||await r(),!this.adapter)throw new Error("Adapter not initialized");return this.adapter.get(t,e,s)},staleTime:i?.staleTime??S}}_updateGetCache(t,e,s,i){const a=this.getQueryClient(),r=["crud",t,"get",e];i===y.DELETE?a.removeQueries({queryKey:r}):i===y.SET&&s?a.setQueryData(r,s):(i===y.UPDATE||i===y.ADD)&&s&&a.setQueryData(r,u=>u?{...u,...s}:s)}_updateListCaches(t,e,s,i){const a=this.getQueryClient();this._updateGetCache(t,e,s,i),a.setQueriesData({queryKey:["crud",t]},r=>{if(r&&typeof r=="object"&&"items"in r){const u=r;let n=u.items;return i===y.DELETE?(n=u.items.filter(d=>d!=null&&typeof d=="object"&&d.id!==e),{...u,items:n,total:Math.max(0,(u.total??n.length)-1)}):i===y.ADD&&s?(n=[...u.items,{...s,id:e}],{...u,items:n,total:(u.total??u.items.length)+1}):(i===y.UPDATE||i===y.SET)&&s&&u.items.some(h=>h!=null&&typeof h=="object"&&h.id===e)?(n=u.items.map(h=>h==null||typeof h!="object"||h.id!==e?h:i===y.SET?{...s,id:e}:{...h,...s}),{...u,items:n}):r}if(Array.isArray(r)){if(i===y.DELETE)return r.filter(u=>u.id!==e);if(i===y.ADD&&s)return[...r,{...s,id:e}];if((i===y.UPDATE||i===y.SET)&&s)return r.some(n=>n!=null&&typeof n=="object"&&n.id===e)?r.map(n=>n==null||typeof n!="object"||n.id!==e?n:i===y.SET?{...s,id:e}:{...n,...s}):r}return r})}_checkUniquenessFromCache(t,e,s){const a=s.metadata?.uniqueKeys;if(!a||a.length===0)return null;const u=this.getQueryClient().getQueriesData({queryKey:["crud",t]}),n=[];for(const[,h]of u)h&&typeof h=="object"&&"items"in h?n.push(...h.items):Array.isArray(h)&&n.push(...h);if(n.length===0)return null;const d=e;for(const h of a){if(!h.fields.every(g=>d[g]!=null&&d[g]!==""))continue;const p=n.find(g=>h.fields.every(c=>{const E=typeof d[c]=="string"?d[c].toLowerCase():d[c],C=typeof g[c]=="string"?g[c].toLowerCase():g[c];return E===C}));if(p){if(h.findOrCreate)return p.id;const g=h.fields.join(" + ");throw f(new Error(h.errorMessage||`Duplicate ${g}`),{userMessage:h.errorMessage||`A record with this ${g} already exists`,showNotification:!0})}}return null}_getItemFromListCache(t,e){const i=this.getQueryClient().getQueriesData({queryKey:["crud",t]});for(const[,a]of i)if(a?.items){const r=a.items.find(u=>u.id===e);if(r)return r}return null}async invalidateCollection(t){await this.getQueryClient().invalidateQueries({queryKey:["crud",t]})}async get(t,e,s,i){if(await this._ensureAdapter(),i?.noCache)return this._getFromAdapter(t,e,s);this.store&&(this.store.getState().setLoading(t,!0),this.store.getState().setError(t,null));try{return await this.getQueryClient().fetchQuery({queryKey:["crud",t,"get",e],queryFn:()=>this._getFromAdapter(t,e,s,!1),staleTime:i?.staleTime??S})}catch(a){const r=f(a,{userMessage:`Failed to fetch ${t}`,showNotification:!0});throw this.store&&this.store.getState().setError(t,r),r}finally{this.store&&this.store.getState().setLoading(t,!1)}}async _getFromAdapter(t,e,s,i=!0){this.store&&i&&(this.store.getState().setLoading(t,!0),this.store.getState().setError(t,null));try{if(!this.adapter)throw new Error("Adapter not initialized");this._assertCanAccess(t,s);const a=await this.adapter.get(t,e,s);if(a&&this.security){const r=this._getPiiFields(s);if(r.length>0)return this.security.decryptPii(a,r)}return a}catch(a){const r=f(a,{userMessage:`Failed to fetch ${t}`,showNotification:!0});throw this.store&&this.store.getState().setError(t,r),r}finally{this.store&&i&&this.store.getState().setLoading(t,!1)}}async query(t,e,s,i,a=_.LIST){if(await this._ensureAdapter(),i?.noCache)return this._queryFromAdapter(t,e,s,!0,a);this.store&&(this.store.getState().setLoading(t,!0),this.store.getState().setError(t,null));try{return await this.getQueryClient().fetchQuery({queryKey:["crud",t,"query",JSON.stringify(e)],queryFn:()=>this._queryFromAdapter(t,e,s,!1,a),staleTime:i?.staleTime??S})}catch(r){const u=f(r,{userMessage:`Failed to query ${t}`,showNotification:!0});throw this.store&&this.store.getState().setError(t,u),u}finally{this.store&&this.store.getState().setLoading(t,!1)}}async _queryFromAdapter(t,e,s,i=!0,a=_.LIST){this.store&&i&&(this.store.getState().setLoading(t,!0),this.store.getState().setError(t,null));try{if(!this.adapter)throw new Error("Adapter not initialized");this._assertCanAccess(t,s);const r=await this.adapter.query(t,e,s,a);if(this.security&&r.items.length>0){const u=this._getPiiFields(s);u.length>0&&(r.items=r.items.map(n=>this.security.decryptPii(n,u)))}return r}catch(r){const u=f(r,{userMessage:`Failed to query ${t}`,showNotification:!0});throw this.store&&this.store.getState().setError(t,u),u}finally{this.store&&i&&this.store.getState().setLoading(t,!1)}}_getEntityName(t){const e=m();let s=`entity-${t}`,i=e.t("name",{ns:s,defaultValue:null});return i&&i!=="name"&&i!==`${s}:name`||t.endsWith("s")&&t.length>1&&(s=`entity-${t.slice(0,-1)}`,i=e.t("name",{ns:s,defaultValue:null}),i&&i!=="name"&&i!==`${s}:name`)?i:t}async set(t,e,s,i,a){await this._ensureAdapter(),this.store&&(this.store.getState().setLoading(t,!0),this.store.getState().setError(t,null));const u=this.getQueryClient().getQueryData(["crud",t,"get",e])??null;this.store&&this.store.getState().updateOptimistic(t,e,s,u);try{if(!this.adapter)throw new Error("Adapter not initialized");this._assertCanAccess(t,i),this.security&&await this.security.checkRateLimit(this._rateLimitKey(t),"write");const n=this._getPiiFields(i),d=n.length>0&&this.security?this.security.encryptPii(s,n):s;if(await this.adapter.set(t,e,d,i),this._updateListCaches(t,e,s,y.SET),this.store&&this.store.getState().confirmUpdate(t,e),this._auditCrud("crud.update",t,e),this._shouldShowSuccessToast(a)){const h=m(),o=this._getEntityName(t);w("success",h.t("messages.updateSuccess",{ns:"crud",entity:o}))}}catch(n){u&&this._updateListCaches(t,e,u,y.SET),this.store&&this.store.getState().rejectUpdate(t,e);const d=f(n,{userMessage:`Failed to save ${t}`,showNotification:!0});throw this.store&&this.store.getState().setError(t,d),d}finally{this.store&&this.store.getState().setLoading(t,!1)}}async update(t,e,s,i,a){await this._ensureAdapter(),this.store&&(this.store.getState().setLoading(t,!0),this.store.getState().setError(t,null));const u=this.getQueryClient().getQueryData(["crud",t,"get",e])??this._getItemFromListCache(t,e),n=u?{...u,...s}:{...s,id:e};this.store&&this.store.getState().updateOptimistic(t,e,n,u??null);try{if(!this.adapter)throw new Error("Adapter not initialized");i&&this._assertCanAccess(t,i),this.security&&await this.security.checkRateLimit(this._rateLimitKey(t),"write");const d=i?this._getPiiFields(i):[],h=d.length>0&&this.security?this.security.encryptPii(s,d):s;if(await this.adapter.update(t,e,h),this._updateListCaches(t,e,n,y.UPDATE),this.store&&this.store.getState().confirmUpdate(t,e),this._auditCrud("crud.update",t,e),this._shouldShowSuccessToast(a)){const o=m(),p=this._getEntityName(t);w("success",o.t("messages.updateSuccess",{ns:"crud",entity:p}))}}catch(d){u?this._updateListCaches(t,e,u,y.UPDATE):this.invalidateCollection(t),this.store&&this.store.getState().rejectUpdate(t,e);const h=f(d,{userMessage:`Failed to update ${t}`,showNotification:!0});throw this.store&&this.store.getState().setError(t,h),h}finally{this.store&&this.store.getState().setLoading(t,!1)}}async delete(t,e,s){await this._ensureAdapter(),this.store&&(this.store.getState().setLoading(t,!0),this.store.getState().setError(t,null));const a=this.getQueryClient().getQueryData(["crud",t,"get",e])??this._getItemFromListCache(t,e);this.store&&a&&this.store.getState().deleteOptimistic(t,e,a);try{if(!this.adapter)throw new Error("Adapter not initialized");if(this.security&&await this.security.checkRateLimit(this._rateLimitKey(t),"write"),await this.adapter.delete(t,e),this._updateListCaches(t,e,null,y.DELETE),this.store&&this.store.getState().confirmDelete(t,e),this._auditCrud("crud.delete",t,e),this.security?.recordAnomaly?.("bulk.deletes",this.currentUserId??void 0),this._shouldShowSuccessToast(s)){const r=m(),u=this._getEntityName(t);w("success",r.t("messages.deleteSuccess",{ns:"crud",entity:u}))}}catch(r){a&&this._updateListCaches(t,e,a,y.ADD),this.store&&this.store.getState().rejectDelete(t,e);const u=f(r,{userMessage:`Failed to delete ${t}`,showNotification:!0});throw this.store&&this.store.getState().setError(t,u),u}finally{this.store&&this.store.getState().setLoading(t,!1)}}async add(t,e,s,i){await this._ensureAdapter();const a=this._checkUniquenessFromCache(t,e,s);if(a)return a;this.store&&(this.store.getState().setLoading(t,!0),this.store.getState().setError(t,null));const r=`temp_${crypto.randomUUID()}`;this.store&&this.store.getState().addOptimistic(t,r,{...e,id:r});try{if(!this.adapter)throw new Error("Adapter not initialized");this._assertCanAccess(t,s),this.security&&await this.security.checkRateLimit(this._rateLimitKey(t),"write");const u=this._getPiiFields(s),n=u.length>0&&this.security?this.security.encryptPii(e,u):e,d=n;(d.status===void 0||d.status===null)&&(d.status=q);const h=await this.adapter.add(t,n,s),o=h.id,p=h.data;if(this._updateListCaches(t,r,null,y.DELETE),this._updateListCaches(t,o,p,y.ADD),this.store&&this.store.getState().confirmOptimistic(t,r,o,p),this._auditCrud("crud.create",t,o),this._shouldShowSuccessToast(i)){const g=m(),c=this._getEntityName(t);w("success",g.t("messages.createSuccess",{ns:"crud",entity:c}))}return o}catch(u){this._updateListCaches(t,r,null,y.DELETE),this.store&&this.store.getState().rejectOptimistic(t,r);const n=f(u,{userMessage:`Failed to create ${t}`,showNotification:!0});throw this.store&&this.store.getState().setError(t,n),n}finally{this.store&&this.store.getState().setLoading(t,!1)}}subscribe(t,e,s,i){if(!this.adapter){let a=!1,r=null;return this._ensureAdapter().then(()=>{a||(r=this._subscribeSync(t,e,s,i))}).catch(u=>{a||s(null,f(u))}),()=>{a=!0,r?.()}}return this._subscribeSync(t,e,s,i)}_subscribeSync(t,e,s,i){try{const a=this.adapter;return a?a.subscribe?(this._assertCanAccess(t,i),a.subscribe(t,e,(r,u)=>{r&&this.getQueryClient().setQueryData(["crud",t,"get",e],r),s(r,u)},i)):()=>{}:(s(null,new Error("Adapter not initialized")),()=>{})}catch(a){return s(null,f(a)),()=>{}}}subscribeToCollection(t,e,s,i){if(!this.adapter){let a=!1,r=null;return this._ensureAdapter().then(()=>{a||(r=this._subscribeToCollectionSync(t,e,s,i))}).catch(u=>{a||s([],f(u))}),()=>{a=!0,r?.()}}return this._subscribeToCollectionSync(t,e,s,i)}_subscribeToCollectionSync(t,e,s,i){try{const a=this.adapter;return a?a.subscribeToCollection?(this._assertCanAccess(t,i),a.subscribeToCollection(t,e,(r,u)=>{r&&this.getQueryClient().setQueryData(["crud",t,"query",JSON.stringify(e)],n=>n?{...n,items:r}:{items:r}),s(r,u)},i)):()=>{}:(s([],new Error("Adapter not initialized")),()=>{})}catch(a){return s([],f(a)),()=>{}}}async addOptimistic(t,e,s,i){await this._ensureAdapter();const a=this._checkUniquenessFromCache(t,e,s);if(a)return{...e,id:a};this.security&&await this.security.checkRateLimit(this._rateLimitKey(t),"write");const r=`temp_${crypto.randomUUID()}`,u={...e,id:r,_optimistic:!0};this.store&&this.store.getState().addOptimistic(t,r,u);try{if(!this.adapter)throw new Error("Adapter not initialized");const n=await this.adapter.add(t,e,s),d=n.id,h=n.data;if(this._updateListCaches(t,r,null,y.DELETE),this._updateListCaches(t,d,h,y.ADD),this.store&&this.store.getState().confirmOptimistic(t,r,d,h),this._auditCrud("crud.create",t,d),this._shouldShowSuccessToast(i)){const o=m(),p=this._getEntityName(t);w("success",o.t("messages.createSuccess",{ns:"crud",entity:p}))}return h}catch(n){throw this._updateListCaches(t,r,null,y.DELETE),this.store&&this.store.getState().rejectOptimistic(t,r),f(n,{userMessage:`Failed to create ${t}`,showNotification:!0})}}async updateOptimistic(t,e,s,i,a){await this._ensureAdapter(),this.security&&await this.security.checkRateLimit(this._rateLimitKey(t),"write");const u=this.getQueryClient().getQueryData(["crud",t,"get",e])??this._getItemFromListCache(t,e),n=u?{...u,...s,_optimistic:!0}:{...s,id:e,_optimistic:!0};this.store&&u&&this.store.getState().updateOptimistic(t,e,n,u);try{if(!this.adapter)throw new Error("Adapter not initialized");await this.adapter.update(t,e,s);const{_optimistic:d,...h}=n;if(this._updateListCaches(t,e,h,y.UPDATE),this.store&&this.store.getState().confirmUpdate(t,e),this._auditCrud("crud.update",t,e),this._shouldShowSuccessToast(a)){const o=m(),p=this._getEntityName(t);w("success",o.t("messages.updateSuccess",{ns:"crud",entity:p}))}return h}catch(d){throw u&&this._updateListCaches(t,e,u,y.UPDATE),this.store&&this.store.getState().rejectUpdate(t,e),f(d,{userMessage:`Failed to update ${t}`,showNotification:!0})}}async deleteOptimistic(t,e,s){await this._ensureAdapter(),this.security&&await this.security.checkRateLimit(this._rateLimitKey(t),"write");const a=this.getQueryClient().getQueryData(["crud",t,"get",e])??this._getItemFromListCache(t,e);this.store&&a&&this.store.getState().deleteOptimistic(t,e,a);try{if(!this.adapter)throw new Error("Adapter not initialized");if(await this.adapter.delete(t,e),this._updateListCaches(t,e,null,y.DELETE),this.store&&this.store.getState().confirmDelete(t,e),this._auditCrud("crud.delete",t,e),this.security?.recordAnomaly?.("bulk.deletes",this.currentUserId??void 0),this._shouldShowSuccessToast(s)){const r=m(),u=this._getEntityName(t);w("success",r.t("messages.deleteSuccess",{ns:"crud",entity:u}))}}catch(r){throw a&&this._updateListCaches(t,e,a,y.ADD),this.store&&this.store.getState().rejectDelete(t,e),f(r,{userMessage:`Failed to delete ${t}`,showNotification:!0})}}}const l=A(()=>new b);export{l as getCrudService};
|
package/dist/CrudStore.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{createDoNotDevStore as d}from"@donotdev/core";import{OPTIMISTIC_STATUSES as
|
|
1
|
+
import{createDoNotDevStore as d}from"@donotdev/core";import{OPTIMISTIC_STATUSES as m,CRUD_OPERATION as a}from"./types";const S={filters:{},showFavoritesOnly:!1};function r(){return{loading:!1,error:null,lastUpdated:0,optimistic:{},ui:{...S}}}const D={crudService:null,hideSuccessToasts:!1,collections:{}},E=d({name:"crud-store",createStore:(n,s)=>({...D,setCrudService:t=>{n({crudService:t})},setHideSuccessToasts:t=>{n({hideSuccessToasts:t})},setLoading:(t,c)=>{n(i=>{const o=i.collections[t]||r();return{collections:{...i.collections,[t]:{...o,loading:c}}}})},setError:(t,c)=>{n(i=>{const o=i.collections[t]||r();return{collections:{...i.collections,[t]:{...o,error:c,loading:!1}}}})},setFilters:(t,c)=>{n(i=>{const o=i.collections[t]||r();return{collections:{...i.collections,[t]:{...o,ui:{...o.ui,filters:c}}}}})},setShowFavoritesOnly:(t,c)=>{n(i=>{const o=i.collections[t]||r();return{collections:{...i.collections,[t]:{...o,ui:{...o.ui,showFavoritesOnly:c}}}}})},getFilters:t=>s().collections[t]?.ui?.filters||{},getShowFavoritesOnly:t=>s().collections[t]?.ui?.showFavoritesOnly||!1,clearCollection:t=>{n(c=>{const{[t]:i,...o}=c.collections;return{collections:o}})},clearError:t=>{n(c=>{const i=c.collections[t];return i?{collections:{...c.collections,[t]:{...i,error:null}}}:c})},addOptimistic:(t,c,i)=>{n(o=>{const e=o.collections[t]||r();return{collections:{...o.collections,[t]:{...e,optimistic:{...e.optimistic,[c]:{tempId:c,originalData:null,optimisticData:i,status:m.PENDING,operation:a.ADD}},lastUpdated:Date.now()}}}})},confirmOptimistic:(t,c,i,o)=>{n(e=>{const l=e.collections[t];if(!l)return e;const{[c]:p,...u}=l.optimistic;return{collections:{...e.collections,[t]:{...l,optimistic:u,lastUpdated:Date.now()}}}})},rejectOptimistic:(t,c)=>{n(i=>{const o=i.collections[t];if(!o)return i;const{[c]:e,...l}=o.optimistic;return{collections:{...i.collections,[t]:{...o,optimistic:l,lastUpdated:Date.now()}}}})},updateOptimistic:(t,c,i,o)=>{n(e=>{const l=e.collections[t]||r();return{collections:{...e.collections,[t]:{...l,optimistic:{...l.optimistic,[c]:{tempId:c,originalData:o,optimisticData:i,status:m.PENDING,operation:a.UPDATE}},lastUpdated:Date.now()}}}})},confirmUpdate:(t,c)=>{n(i=>{const o=i.collections[t];if(!o)return i;const{[c]:e,...l}=o.optimistic;return{collections:{...i.collections,[t]:{...o,optimistic:l}}}})},rejectUpdate:(t,c)=>{n(i=>{const o=i.collections[t];if(!o)return i;const e=o.optimistic[c];if(!e||e.operation!==a.UPDATE)return i;const{[c]:l,...p}=o.optimistic;return{collections:{...i.collections,[t]:{...o,optimistic:p,lastUpdated:Date.now()}}}})},deleteOptimistic:(t,c,i)=>{n(o=>{const e=o.collections[t];return e?{collections:{...o.collections,[t]:{...e,optimistic:{...e.optimistic,[c]:{tempId:c,originalData:i,optimisticData:null,status:m.PENDING,operation:a.DELETE}},lastUpdated:Date.now()}}}:o})},confirmDelete:(t,c)=>{n(i=>{const o=i.collections[t];if(!o)return i;const{[c]:e,...l}=o.optimistic;return{collections:{...i.collections,[t]:{...o,optimistic:l}}}})},rejectDelete:(t,c)=>{n(i=>{const o=i.collections[t];if(!o)return i;const e=o.optimistic[c];if(!e||e.operation!==a.DELETE)return i;const{[c]:l,...p}=o.optimistic;return{collections:{...i.collections,[t]:{...o,optimistic:p,lastUpdated:Date.now()}}}})},getLoading:t=>s().collections[t]?.loading||!1,getError:t=>s().collections[t]?.error||null,isOptimistic:(t,c)=>s().collections[t]?.optimistic[c]?.status==="pending",getOptimisticStatus:(t,c)=>s().collections[t]?.optimistic[c]?.status??null,getOptimisticData:(t,c)=>s().collections[t]?.optimistic[c]?.optimisticData??null})});export{E as useCrudStore};
|
package/dist/FieldRegistry.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
"use client";class
|
|
1
|
+
"use client";class d{components=new Map;displayFormatters=new Map;filterMetadata=new Map;registerComponent(e,t,n){this.components.set(e,{controlled:t,uncontrolled:n})}register(e){const{type:t,controlledComponent:n,uncontrolledComponent:p,displayFormatter:i,filterable:o,filterType:l}=e;this.components.set(t,{controlled:n,uncontrolled:p}),i&&this.displayFormatters.set(t,i),(o!==void 0||l!==void 0)&&this.filterMetadata.set(t,{filterable:o??!1,filterType:l})}getControlledComponent(e){return this.components.get(e)?.controlled}getUncontrolledComponent(e){return this.components.get(e)?.uncontrolled}getDisplayFormatter(e){return this.displayFormatters.get(e)}getFilterType(e){return this.filterMetadata.get(e)?.filterType}isFilterable(e){return this.filterMetadata.get(e)?.filterable??!1}has(e){return this.components.has(e)}getRegisteredTypes(){return Array.from(this.components.keys())}clear(){this.components.clear(),this.displayFormatters.clear(),this.filterMetadata.clear()}}let s=null;function a(){return s||(s=new d),s}function c(r){a().register(r)}function f(r){return a().has(r)}export{a as getFieldRegistry,f as isFieldTypeRegistered,c as registerFieldType};
|
|
@@ -36,10 +36,22 @@ export interface FunctionsQueryOptions {
|
|
|
36
36
|
startAfter?: string | null;
|
|
37
37
|
startAfterId?: string;
|
|
38
38
|
}
|
|
39
|
+
/**
|
|
40
|
+
* Functions backend adapter
|
|
41
|
+
* Works with any collection dynamically (collection name passed per operation)
|
|
42
|
+
* Assumes Functions are named: `get_${collection}`, `create_${collection}`, etc.
|
|
43
|
+
*
|
|
44
|
+
* All backends go through ICallableProvider. If none configured, falls back to FirebaseCallableProvider.
|
|
45
|
+
*
|
|
46
|
+
* @version 0.0.1
|
|
47
|
+
* @since 0.0.1
|
|
48
|
+
* @author AMBROISE PARK Consulting
|
|
49
|
+
*/
|
|
39
50
|
export declare class FunctionsAdapter implements ICrudAdapter {
|
|
40
51
|
readonly serverSideOnly = true;
|
|
41
52
|
/**
|
|
42
|
-
* Resolve ICallableProvider
|
|
53
|
+
* Resolve ICallableProvider from provider registry.
|
|
54
|
+
* Consumer must configure via configureProviders({ callable: adapter }).
|
|
43
55
|
*/
|
|
44
56
|
private getCallable;
|
|
45
57
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"FunctionsAdapter.d.ts","sourceRoot":"","sources":["../../src/adapters/FunctionsAdapter.ts"],"names":[],"mappings":"AAEA;;;;;;;;;;;;;;GAcG;AAEH,OAAO,KAAK,EACV,WAAW,EAEX,YAAY,EACZ,cAAc,EACd,oBAAoB,EACrB,MAAM,gBAAgB,CAAC;
|
|
1
|
+
{"version":3,"file":"FunctionsAdapter.d.ts","sourceRoot":"","sources":["../../src/adapters/FunctionsAdapter.ts"],"names":[],"mappings":"AAEA;;;;;;;;;;;;;;GAcG;AAEH,OAAO,KAAK,EACV,WAAW,EAEX,YAAY,EACZ,cAAc,EACd,oBAAoB,EACrB,MAAM,gBAAgB,CAAC;AAQxB;;;;;;GAMG;AACH,MAAM,WAAW,qBAAqB;IACpC,KAAK,CAAC,EAAE,KAAK,CAAC;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,OAAO,CAAA;KAAE,CAAC,CAAC;IACnE,OAAO,CAAC,EAAE,KAAK,CAAC;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,SAAS,CAAC,EAAE,KAAK,GAAG,MAAM,CAAA;KAAE,CAAC,CAAC;IAC/D,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,yFAAyF;IACzF,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED;;;;;;;;;;GAUG;AACH,qBAAa,gBAAiB,YAAW,YAAY;IACnD,QAAQ,CAAC,cAAc,QAAQ;IAE/B;;;OAGG;IACH,OAAO,CAAC,WAAW;IAInB;;OAEG;YACW,aAAa;IASrB,GAAG,CAAC,CAAC,EACT,cAAc,EAAE,MAAM,EACtB,EAAE,EAAE,MAAM,EACV,MAAM,EAAE,WAAW,CAAC,OAAO,CAAC,GAC3B,OAAO,CAAC,CAAC,GAAG,IAAI,CAAC;IAgBd,GAAG,CAAC,CAAC,EACT,cAAc,EAAE,MAAM,EACtB,EAAE,EAAE,MAAM,EACV,IAAI,EAAE,CAAC,EACP,MAAM,EAAE,WAAW,CAAC,CAAC,CAAC,GACrB,OAAO,CAAC,IAAI,CAAC;IAaV,MAAM,CAAC,CAAC,EACZ,cAAc,EAAE,MAAM,EACtB,EAAE,EAAE,MAAM,EACV,IAAI,EAAE,OAAO,CAAC,CAAC,CAAC,GACf,OAAO,CAAC,IAAI,CAAC;IAmBV,MAAM,CAAC,cAAc,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAkBzD,GAAG,CAAC,CAAC,EACT,cAAc,EAAE,MAAM,EACtB,IAAI,EAAE,CAAC,EACP,MAAM,EAAE,WAAW,CAAC,CAAC,CAAC,GACrB,OAAO,CAAC;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;KAAE,CAAC;IAwBnD,KAAK,CAAC,CAAC,EACX,cAAc,EAAE,MAAM,EACtB,OAAO,EAAE,qBAAqB,EAC9B,MAAM,EAAE,WAAW,CAAC,OAAO,CAAC,EAC5B,UAAU,GAAE,cAAsC,GACjD,OAAO,CAAC,oBAAoB,CAAC,CAAC,CAAC,CAAC;IAqEnC,SAAS,CAAC,CAAC,KAAK,MAAM,IAAI;IAS1B,qBAAqB,CAAC,CAAC,KAAK,MAAM,IAAI;CAQvC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{
|
|
1
|
+
import{getProvider as l,wrapCrudError as o,validateWithSchema as c}from"@donotdev/core";import{LIST_SCHEMA_TYPE as u}from"@donotdev/core";class h{serverSideOnly=!0;getCallable(){return l("callable")}async getCallableFn(a){const t=this.getCallable();return async n=>({data:await t.call(a,n)})}async get(a,t,n){const d=`get_${a}`,i=await this.getCallableFn(d);try{const s=(await i({id:t})).data;return n?c(n,s,"FunctionsAdapter.get"):s}catch(r){throw o(r,"FunctionsAdapter","get",a,t)}}async set(a,t,n,d){const i=c(d,n,"FunctionsAdapter.set"),r=`update_${a}`,s=await this.getCallableFn(r);try{await s({id:t,payload:i})}catch(e){throw o(e,"FunctionsAdapter","set",a,t)}}async update(a,t,n){const d=`update_${a}`,i=await this.getCallableFn(d);try{await i({id:t,payload:n})}catch(r){throw o(r,"FunctionsAdapter","update",a,t)}}async delete(a,t){const n=`delete_${a}`,d=await this.getCallableFn(n);try{await d({id:t})}catch(i){throw o(i,"FunctionsAdapter","delete",a,t)}}async add(a,t,n){const d=c(n,t,"FunctionsAdapter.add"),i=`create_${a}`,r=await this.getCallableFn(i);try{const s=await r({payload:d});if(!s.data)throw o(new Error("Create function returned no data"),"FunctionsAdapter","add",a);return{id:s.data.id,data:s.data}}catch(s){throw o(s,"FunctionsAdapter","add",a)}}async query(a,t,n,d=u.LIST){const i=d===u.LIST_CARD?`listCard_${a}`:`list_${a}`,r={};t.where&&(r.where=t.where.map(e=>[e.field,e.operator,e.value])),t.orderBy&&(r.orderBy=t.orderBy.map(e=>[e.field,e.direction||"asc"])),t.limit&&(r.limit=t.limit),t.startAfter&&(r.startAfterId=t.startAfter);const s=await this.getCallableFn(i);try{const e=await s(r);if(!e.data)throw o(new Error("Query function returned no data"),"FunctionsAdapter","query",a);return{items:e.data.items,total:e.data.count,hasMore:e.data.hasMore,lastVisible:e.data.lastVisible}}catch(e){throw o(e,"FunctionsAdapter","query",a)}}subscribe(){return()=>{}}subscribeToCollection(){return()=>{}}}export{h as FunctionsAdapter};
|
|
@@ -1,22 +1,24 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* @fileoverview Built-in Field Type Registrations
|
|
3
|
-
* @description Legacy wrapper - now delegates to unified registry.
|
|
2
|
+
* @fileoverview Built-in Field Type Registrations — legacy compatibility shim.
|
|
4
3
|
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
4
|
+
* Registration is now handled at the source: `fieldTypeRegistry.ts` imports
|
|
5
|
+
* `registerBuiltinFieldTypes.tsx` as a side-effect, guaranteeing built-ins are
|
|
6
|
+
* available for every code path (display, form, filter, Expo).
|
|
8
7
|
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
8
|
+
* This file is kept solely for backward compatibility — existing consumers that
|
|
9
|
+
* import `registerBuiltinFieldTypes` from `@donotdev/crud` still get a no-op
|
|
10
|
+
* function that won't break their startup code.
|
|
11
11
|
*
|
|
12
|
-
*
|
|
12
|
+
* For custom field types, use `registerFieldType()` from `@donotdev/crud`.
|
|
13
|
+
*
|
|
14
|
+
* @version 0.0.3
|
|
13
15
|
* @since 0.0.1
|
|
14
16
|
* @author AMBROISE PARK Consulting
|
|
15
17
|
*/
|
|
16
18
|
import './registerBuiltinFieldTypes';
|
|
17
19
|
/**
|
|
18
|
-
* @deprecated
|
|
19
|
-
* Kept for
|
|
20
|
+
* @deprecated No-op. Built-in registration is now automatic via `fieldTypeRegistry.ts`.
|
|
21
|
+
* Kept for API compatibility with consumers that call this at app startup.
|
|
20
22
|
*/
|
|
21
23
|
export declare function registerBuiltinFieldTypes(): void;
|
|
22
24
|
//# sourceMappingURL=builtinFieldTypes.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"builtinFieldTypes.d.ts","sourceRoot":"","sources":["../src/builtinFieldTypes.tsx"],"names":[],"mappings":"AAGA
|
|
1
|
+
{"version":3,"file":"builtinFieldTypes.d.ts","sourceRoot":"","sources":["../src/builtinFieldTypes.tsx"],"names":[],"mappings":"AAGA;;;;;;;;;;;;;;;;GAgBG;AAEH,OAAO,6BAA6B,CAAC;AAErC;;;GAGG;AACH,wBAAgB,yBAAyB,IAAI,IAAI,CAEhD"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
"use client";import{jsx as
|
|
1
|
+
"use client";import{jsx as n}from"react/jsx-runtime";import{ActionButton as d}from"@donotdev/components";import{useCrudStore as l}from"../CrudStore";function a({requiresAuth:t=!0,user:e,disabled:r=!1,children:i,...o}){const s=l(u=>!!u.crudService);return n(d,{...o,disabled:r||!s||t&&!e,children:i})}var p=a;export{p as default};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{jsx as
|
|
1
|
+
import{jsx as i,jsxs as A}from"react/jsx-runtime";import{Trash2 as G}from"lucide-react";import{useMemo as F}from"react";import{Card as H,Stack as R,Text as B,ActionButton as J}from"@donotdev/components";import{useTranslation as k,getListCardFieldNames as K}from"@donotdev/core";import{formatValue as v}from"./DisplayFieldRenderer";import{DisplayThumbnail as y}from"./DisplayThumbnail";import{translateFieldLabel as O}from"../forms/utils/translateFieldLabel";import{useCrud as Q}from"../useCrud";function u(t){return t==="image"||t==="images"}function U(t){return F(()=>{const e=t.listCardFields;if(e&&!Array.isArray(e)){const o=e;return{titleFields:o.title??[],subtitleFields:o.subtitle??[],contentFields:o.content??[],footerFields:o.footer??[]}}const f=K(t),g=f.filter(o=>!u(t.fields[o]?.type)),x=f.filter(o=>u(t.fields[o]?.type)),S=g.length>0?[g[0]]:[],C=[...g.slice(1,4),...x];return{titleFields:S,subtitleFields:[],contentFields:C,footerFields:[]}},[t])}function W({item:t,entity:e,onClick:f,titleFields:g,subtitleFields:x,contentFields:S,footerFields:C,showDelete:o=!1,renderActions:D,elevated:M=!0,className:P}){const{t:n}=k([e.namespace,"crud"]),{t:m}=k("crud"),b=U(e),T=g??b.titleFields,I=x??b.subtitleFields,j=S??b.contentFields,h=C??b.footerFields,V=F(()=>{if(!T?.length)return t.id??"";const c=T.filter(l=>typeof l=="string").filter(l=>!u(e.fields[l]?.type)).map(l=>{const s=e.fields[l],a=t[l],p=s?v(a,s,n,{compact:!0,asString:!0}):a;return typeof p=="string"?p:String(p??"")}).filter(Boolean),r=!Array.isArray(e.listCardFields)&&e.listCardFields?.titleSeparator!=null?e.listCardFields.titleSeparator:" ";return c.join(r)||String(t.id??"")},[t,e.fields,T,e.listCardFields,n]),_=F(()=>I?.length&&I.filter(r=>typeof r=="string").filter(r=>!u(e.fields[r]?.type)).map(r=>{const l=e.fields[r],s=t[r],a=l?v(s,l,n,{compact:!0,asString:!0}):s;return typeof a=="string"?a:String(a??"")}).filter(Boolean).join(" ")||void 0,[t,e.fields,I,n]),z=F(()=>{if(!j?.length)return null;const c=j.map(r=>{const l=e.fields[r];if(!l)return null;if(u(l.type)){const s=t[r];return s==null?null:i(y,{pictures:s,alt:String(V),aspectRatio:"16/9"},r)}return A("div",{children:[i(B,{level:"small",variant:"muted",children:O(r,l,n)}),i(B,{children:v(t[r],l,n,{compact:!0})})]},r)}).filter(Boolean);return c.length>0?i(R,{direction:"column",gap:"tight",children:c}):null},[t,e.fields,j,V,n]),q=F(()=>{if(!h?.length)return;if(h.some(r=>u(e.fields[r]?.type))){const r=h.map(l=>{const s=e.fields[l];if(!s)return null;if(u(s.type)){const p=t[l];return p==null?null:i(y,{pictures:p,alt:"",aspectRatio:"1"},l)}const a=v(t[l],s,n,{compact:!0});return i("span",{children:a},l)});return i(R,{direction:"row",gap:"tight",align:"center",children:r.filter(Boolean)})}const c=h.map(r=>{const l=e.fields[r];return l?v(t[r],l,n,{compact:!0}):t[r]});return i(B,{level:"small",children:c.join(" \xB7 ")})},[t,e.fields,h,n]),E=Q(e).delete,w=i(H,{title:String(V??""),subtitle:_,content:z??void 0,footer:q,clickable:!!f,onClick:f?()=>f(t.id):void 0,elevated:M,className:P}),L=D||o?A("div",{style:{position:"absolute",top:"var(--gap-sm)",right:"var(--gap-sm)",zIndex:10,display:"flex",alignItems:"flex-start",gap:"var(--gap-xs)"},onClick:d=>d.stopPropagation(),onMouseDown:d=>d.stopPropagation(),children:[D,o&&i(J,{action:async()=>{await E(t.id)},confirmText:m("delete.confirm",{defaultValue:"Are you sure you want to delete this item?"}),confirmTitle:m("delete.title",{defaultValue:"Delete Item"}),loadingText:m("delete.loading",{defaultValue:"Deleting..."}),variant:"destructive",icon:G,"aria-label":m("delete",{defaultValue:"Delete"}),children:m("delete",{defaultValue:"Delete"})})]}):null;return L?A("div",{style:{position:"relative",height:"100%"},children:[w,L]}):w}var st=W;export{W as CrudCard,st as default};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
"use client";import{jsx as e,jsxs as
|
|
1
|
+
"use client";import{jsx as e,jsxs as k,Fragment as ht}from"react/jsx-runtime";import{X as Dt}from"lucide-react";import{useState as T,useMemo as pt}from"react";import{Button as S,Calendar as St,FloatingLabel as yt,Sheet as E,Text as ut}from"@donotdev/components";import{formatDate as ft}from"@donotdev/core";function Ft({label:y,fieldType:xt,value:s,onChange:u,tCrud:o,locale:N="en"}){const[Y,i]=T(!1),[v,f]=T(null),O=pt(()=>s?typeof s=="object"&&s!==null&&"min"in s?{min:s.min||"",max:s.max||""}:{min:"",max:""}:{min:"",max:""},[s]),F=t=>{if(!t)return"";try{const n=new Date(t+"T00:00:00");return ft(n,N)}catch{return t}},W=()=>{const t=new Date;t.setHours(0,0,0,0);const n=t.getFullYear(),c=String(t.getMonth()+1).padStart(2,"0"),r=String(t.getDate()).padStart(2,"0"),d=`${n}-${c}-${r}`,l=new Date(t);l.setDate(l.getDate()-1);const M=l.getFullYear(),x=String(l.getMonth()+1).padStart(2,"0"),C=String(l.getDate()).padStart(2,"0"),R=`${M}-${x}-${C}`,g=new Date(t);g.setDate(g.getDate()+1);const z=g.getFullYear(),A=String(g.getMonth()+1).padStart(2,"0"),B=String(g.getDate()).padStart(2,"0"),H=`${z}-${A}-${B}`,m=new Date(t);m.setDate(m.getDate()-7);const L=m.getFullYear(),P=String(m.getMonth()+1).padStart(2,"0"),X=String(m.getDate()).padStart(2,"0"),q=`${L}-${P}-${X}`,h=new Date(t);h.setDate(h.getDate()-30);const G=h.getFullYear(),I=String(h.getMonth()+1).padStart(2,"0"),J=String(h.getDate()).padStart(2,"0"),K=`${G}-${I}-${J}`,D=new Date(t);D.setDate(D.getDate()+7);const Q=D.getFullYear(),U=String(D.getMonth()+1).padStart(2,"0"),Z=String(D.getDate()).padStart(2,"0"),tt=`${Q}-${U}-${Z}`,p=new Date(t);p.setDate(p.getDate()+30);const et=p.getFullYear(),at=String(p.getMonth()+1).padStart(2,"0"),nt=String(p.getDate()).padStart(2,"0"),rt=`${et}-${at}-${nt}`,$=new Date(t.getFullYear(),t.getMonth(),1),st=$.getFullYear(),ot=String($.getMonth()+1).padStart(2,"0"),it=String($.getDate()).padStart(2,"0"),lt=`${st}-${ot}-${it}`,w=new Date(t.getFullYear(),t.getMonth()+1,0),ct=w.getFullYear(),dt=String(w.getMonth()+1).padStart(2,"0"),gt=String(w.getDate()).padStart(2,"0"),mt=`${ct}-${dt}-${gt}`;return{today:d,yesterday:R,tomorrow:H,last7Days:q,last30Days:K,next7Days:tt,next30Days:rt,thisMonthStart:lt,thisMonthEnd:mt}},a=O,_=W(),b=!!(a?.min||a?.max),V=t=>{const n=t==="start",c=n?a?.min:a?.max;return e("div",{style:{padding:"var(--gap-md)"},children:k("div",{style:{display:"flex",flexDirection:"column",gap:"var(--gap-md)"},children:[e("div",{style:{display:"flex",flexWrap:"wrap",gap:"var(--gap-tight)"},children:(n?["today","yesterday","last7Days","last30Days","thisMonthStart"]:["today","tomorrow","next7Days","next30Days","thisMonthEnd"]).map(r=>{const d=_[r];return e(S,{variant:"outline",onClick:()=>{u({min:n?d:a?.min||"",max:n?a?.max||"":d}),i(!1)},children:o(`filter.${r}`,{defaultValue:r})},r)})}),e(St,{selected:c?new Date(c+"T00:00:00"):void 0,mode:"single",onSelect:r=>{if(!r)return;const d=r.getFullYear(),l=String(r.getMonth()+1).padStart(2,"0"),M=String(r.getDate()).padStart(2,"0"),x=`${d}-${l}-${M}`;u({min:n?x:a?.min||"",max:n?a?.max||"":x}),i(!1)},defaultMonth:c?new Date(c+"T00:00:00"):new Date}),e(S,{variant:"ghost",display:"compact",onClick:()=>{u({min:n?"":a?.min||"",max:n&&a?.max||""}),i(!1)},children:o("filter.clear",{defaultValue:"Clear"})})]})})},j=k(ht,{children:[e(E,{trigger:e(S,{variant:"ghost",onClick:()=>{f("start"),i(!0)},style:{minWidth:0,overflow:"hidden",textOverflow:"ellipsis",whiteSpace:"nowrap"},children:a?.min?F(a.min):o("filter.min",{defaultValue:"Min"})}),title:`${y} - ${o("filter.min",{defaultValue:"Min"})}`,open:Y&&v==="start",onOpenChange:t=>{i(t),t||f(null)},children:V("start")}),e(ut,{level:"small",variant:"muted",className:"dndev-range-input-separator",children:"\u2013"}),e(E,{trigger:e(S,{variant:"ghost",onClick:()=>{f("end"),i(!0)},style:{minWidth:0,overflow:"hidden",textOverflow:"ellipsis",whiteSpace:"nowrap"},children:a?.max?F(a.max):o("filter.max",{defaultValue:"Max"})}),title:`${y} - ${o("filter.max",{defaultValue:"Max"})}`,open:Y&&v==="end",onOpenChange:t=>{i(t),t||f(null)},children:V("end")}),e(S,{variant:"ghost",display:"compact",icon:e(Dt,{size:16}),onClick:()=>{u(void 0)},disabled:!b,"aria-label":o("filter.clear",{defaultValue:"Clear"})})]});return y?e(yt,{label:y,children:e("div",{className:"dndev-range-input",children:j})}):e("div",{className:"dndev-range-input",children:j})}export{Ft as DateFilter};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
"use client";import{jsx as t,jsxs as s}from"react/jsx-runtime";import{Text as a,Stack as
|
|
1
|
+
"use client";import{jsx as t,jsxs as s}from"react/jsx-runtime";import{Text as a,Stack as p}from"@donotdev/components";import{handleError as d}from"@donotdev/core";import{getDisplayFormatter as f}from"../fieldTypeRegistry";import{translateFieldLabel as y}from"../forms/utils";function c(r,e,o,n){const i=n?.compact??!1;if(r==null||r==="")return i?t("span",{style:{color:"var(--muted-foreground)"},children:"\u2014"}):t(a,{variant:"muted",children:"\u2014"});const l=f(e.type);if(l)try{return l(r,e,o,n)}catch(m){return d(m,{userMessage:`Error formatting field "${e.label||e.name}"`,context:{fieldType:e.type,fieldName:e.label||"unknown",operation:"display_format"},severity:"warning"}),i?t("span",{style:{color:"var(--muted-foreground)"},children:String(r)}):t(a,{variant:"muted",children:String(r)})}return d(new Error(`Display formatter not registered for field type: ${e.type}`),{userMessage:`Field type "${e.type}" is missing display formatter`,context:{fieldType:e.type,fieldName:e.label||"unknown",operation:"display_format",fix:"Add displayFormatter to registerBuiltinFieldType() in registerBuiltinFieldTypes.tsx"},severity:"warning"}),i?t("span",{style:{color:"var(--muted-foreground)"},children:String(r)}):t(a,{variant:"muted",children:String(r)})}function u({name:r,config:e,value:o,t:n}){const i=c(o,e,n,{compact:!1}),l=y(r,e,n);return s(p,{direction:"row",align:"baseline",style:{marginBottom:"var(--gap-sm)",padding:"var(--gap-sm)",minHeight:"38px",alignItems:"center"},children:[s(a,{variant:"muted",style:{fontSize:"var(--font-size-sm)",fontWeight:500,minWidth:"fit-content",flexShrink:0},children:[l,":"]}),t("div",{style:{flex:1,display:"flex",alignItems:"center"},children:typeof i=="string"?t(a,{children:i}):i})]})}var b=u;export{u as DisplayFieldRenderer,b as default,c as formatValue};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
"use client";import{jsx as
|
|
1
|
+
"use client";import{jsx as e}from"react/jsx-runtime";function u(r){if(r==null)return null;if(typeof r=="string")return r||null;const l=Array.isArray(r)&&r.length>0?r[0]:r;if(!l||typeof l!="object")return null;const t=l.thumbUrl??l.fullUrl;return typeof t=="string"?t:null}function a({pictures:r,alt:l="",aspectRatio:t="16/9",className:o,style:i}){const n=u(r);return n?e("div",{className:o,style:{width:"100%",aspectRatio:t,borderRadius:"var(--radius-md)",overflow:"hidden",backgroundColor:"var(--muted)",position:"relative",...i},children:e("img",{src:n,alt:l,loading:"lazy",style:{width:"100%",height:"100%",objectFit:"cover"}})}):null}var d=a;export{a as DisplayThumbnail,d as default};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"EntityFilters.d.ts","sourceRoot":"","sources":["../../src/components/EntityFilters.tsx"],"names":[],"mappings":"AAqDA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AACrD,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,gBAAgB,CAAC;
|
|
1
|
+
{"version":3,"file":"EntityFilters.d.ts","sourceRoot":"","sources":["../../src/components/EntityFilters.tsx"],"names":[],"mappings":"AAqDA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AACrD,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,gBAAgB,CAAC;AAc7C,OAAO,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAC;AAEvD,MAAM,WAAW,kBAAkB,CACjC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG;IAAE,EAAE,EAAE,MAAM,CAAA;CAAE,GAAG,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG;IACrE,EAAE,EAAE,MAAM,CAAC;CACZ;IAED,4BAA4B;IAC5B,MAAM,EAAE,MAAM,CAAC;IAEf,oFAAoF;IACpF,cAAc,CAAC,EAAE,MAAM,EAAE,CAAC;IAE1B,sFAAsF;IACtF,OAAO,CAAC,EAAE,QAAQ,GAAG,SAAS,CAAC;IAE/B,sFAAsF;IACtF,IAAI,CAAC,EAAE,QAAQ,CAAC;IAEhB,8GAA8G;IAC9G,IAAI,CAAC,EAAE,CAAC,EAAE,CAAC;CACZ;AAED;;;;;;;;;;;;;;;;;;GAkBG;AAEH,wBAAgB,aAAa,CAC3B,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG;IAAE,EAAE,EAAE,MAAM,CAAA;CAAE,GAAG,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG;IACrE,EAAE,EAAE,MAAM,CAAC;CACZ,EACD,EACA,MAAM,EACN,IAAI,EAAE,QAAQ,EACd,cAAc,EACd,OAAkB,EAClB,IAAI,GACL,EAAE,kBAAkB,CAAC,CAAC,CAAC,kDA0pBvB"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
"use client";import{jsx as
|
|
1
|
+
"use client";import{jsx as m,jsxs as P}from"react/jsx-runtime";import{FilterX as N}from"lucide-react";import{useMemo as O}from"react";import{Button as ee,Combobox as te,Grid as ne,Rating as ie,RangeInput as re,Slider as se,Stack as le}from"@donotdev/components";import{useTranslation as B,handleError as L}from"@donotdev/core";import{DateFilter as ae}from"./DateFilter";import{getFilterType as $,isFilterable as oe}from"../fieldTypeRegistry";import{translateFieldLabel as ce,translateLabel as I}from"../forms/utils";import{useCrudFilters as de}from"../hooks/useCrudFilters";import{useCrudCardList as me}from"../useCrudCardList";import{matchesFilter as ue}from"../utils/matchesFilter";import{matchesFilter as ke}from"../utils/matchesFilter";function Oe({entity:d,data:R,fieldsToFilter:S,variant:z="inline",cols:G}){const X=z==="sidebar",{t:g,i18n:q}=B("crud"),{t:j}=B([d.namespace,"crud"]),H=q?.language||"en",{data:J}=me(d,{enabled:!R}),f=R??(J?.items||[]),{filters:y,setFilters:k}=de({collection:d.collection}),h=O(()=>(S&&S.length>0?S:d.listFields||Object.keys(d.fields)).filter(t=>{const n=d.fields[t]?.type||"text";return oe(n)}),[S,d.listFields,d.fields]),v=O(()=>{const i={};return h.forEach(t=>{const o=Object.fromEntries(Object.entries(y).filter(([n])=>n!==t));if(Object.keys(o).length===0){i[t]=f;return}i[t]=f.filter(n=>Object.entries(o).every(([c,x])=>{const F=n[c],s=d.fields[c]?.type||"text";return ue(F,x,s)}))}),i},[f,y,d.fields,h]),K=O(()=>{const i={};return h.forEach(t=>{const o=d.fields[t];if(!o)return;const n=o.type||"text",c=$(n);if(!c){L(new Error(`Field type "${n}" not registered in field type registry`),{userMessage:`Field type "${n}" is missing from registry`,context:{fieldType:n,fieldName:t,operation:"minmax_computation",fix:"Add to registerBuiltinFieldTypes.ts or registerFieldType()"},severity:"warning"});return}const x=c==="range"&&(n==="date"||n==="datetime-local"||n==="timestamp"||n==="time"||n==="week"||n==="month"||n==="year"),F=c==="range"&&!x,C=n==="price";if(F||C){const s=f.map(r=>r[t]).filter(r=>r!=null&&r!=="").map(r=>C&&typeof r=="object"&&r!==null?Number(r.amount):typeof r=="number"?r:Number(r)).filter(r=>!isNaN(r));s.length>0&&(i[t]={min:Math.min(...s),max:Math.max(...s)})}else if(x){const s=f.map(r=>r[t]).filter(r=>r!=null&&r!=="").map(r=>r instanceof Date?r:new Date(r)).filter(r=>!isNaN(r.getTime()));if(s.length>0){const r=new Date(Math.min(...s.map(T=>T.getTime()))),p=new Date(Math.max(...s.map(T=>T.getTime()))),_=r.toISOString().split("T")[0],E=p.toISOString().split("T")[0];i[t]={min:_||"",max:E||""}}}}),i},[f,d.fields,h]),b=(i,t)=>{const o={...y};if(!t||t==="")delete o[i];else if(Array.isArray(t))o[i]=t;else if(typeof t=="object"&&"min"in t){const n=t.min&&t.min!=="",c=t.max&&t.max!=="";!n&&!c?delete o[i]:o[i]=t}else o[i]=t;k(o)},Q=()=>{k({})},V=O(()=>h.length===0?null:h.map(i=>{const t=d.fields[i];if(!t)return null;const o=ce(i,t,j),n=t.type||"text",c=$(n);if(!c)return L(new Error(`Field type "${n}" not registered in field type registry`),{userMessage:`Field type "${n}" is missing from registry`,context:{fieldType:n,fieldName:i,operation:"filter_ui_render",fix:"Add to registerBuiltinFieldTypes.ts or registerFieldType()"},severity:"warning"}),null;const x=c==="range"&&(n==="date"||n==="datetime-local"||n==="timestamp"||n==="time"||n==="week"||n==="month"||n==="year"),F=c==="range"&&!x,C=c==="select",s=y[i],p=typeof s=="object"&&s!==null&&"min"in s?s:{min:"",max:""};if(c==="rating"){const l=t.validation?.max??5,a=typeof s=="string"&&s!==""?Number(s):0;return m("div",{style:{gridColumn:"span 2",gridRow:"span 1"},children:m(ie,{value:a,max:l,"aria-label":o,onChange:e=>{b(i,e===a?void 0:String(e))}})},i)}if(F){const l=K[i],a=l?.min??0,e=l?.max??100,u=p.min?Number(p.min):a,A=p.max?Number(p.max):e;return P(le,{gap:"tight",style:{gridColumn:"span 2"},children:[m(re,{type:"number",label:o,minPlaceholder:g("filter.min",{defaultValue:"Min"}),maxPlaceholder:g("filter.max",{defaultValue:"Max"}),minValue:p.min||"",maxValue:p.max||"",actualMin:a,actualMax:e,onChange:(M,Z)=>{b(i,{min:M,max:Z})},onClear:()=>b(i,void 0)}),m(se,{value:[u,A],min:a,max:e,step:1,onValueChange:M=>{b(i,{min:String(M[0]),max:String(M[1])})}})]},i)}if(x){const l=n==="week"||n==="month"||n==="year"?n:"date",a=(()=>{if(s){if(typeof s=="object"&&"min"in s){const e=s;return{min:e.min&&e.min.split("T")[0]||"",max:e.max&&e.max.split("T")[0]||""}}if(typeof s=="string"){const e=s.split("T")[0]||"";return{min:e,max:e}}}})();return m("div",{style:{gridColumn:"span 2",gridRow:"span 1"},children:m(ae,{label:o,fieldType:l,value:a,locale:H,onChange:e=>{if(!e){b(i,void 0);return}typeof e=="object"&&"min"in e&&b(i,{min:e.min||"",max:e.max||""})},tCrud:g})},i)}const E=C&&t.validation&&"options"in t.validation&&t.validation?Array.isArray(t.validation.options)?t.validation.options:typeof t.validation.options=="function"?t.validation.options():[]:[],T=v[i]||f,D=new Set,Y=c==="address";T.forEach(l=>{const a=l[i];if(a!=null)if(Y&&typeof a=="object"&&"formatted_address"in a){const e=a;e.formatted_address&&D.add(String(e.formatted_address))}else D.add(String(a))});const w=[{value:"all",label:g("filter.selectPlaceholder",{defaultValue:"All"})}];if(E.length>0){const l=[],a=[];E.forEach(e=>{const u=typeof e=="string"?e:e.value,A=typeof e=="string"?e:e.label;D.has(u)?l.push({value:u,label:A}):a.push({value:u,label:A})}),l.sort((e,u)=>e.label.localeCompare(u.label)),a.sort((e,u)=>e.label.localeCompare(u.label)),l.forEach(e=>{w.push({value:e.value,label:I(e.label,j),disabled:!1})}),a.forEach(e=>{w.push({value:e.value,label:I(e.label,j),disabled:!0})})}else Array.from(D).sort().slice(0,100).forEach(l=>{w.push({value:l,label:l})});return m("div",{style:{gridColumn:"span 1",gridRow:"span 1"},children:m(te,{label:o,value:typeof s=="string"?s:void 0,onValueChange:l=>{b(i,l==="all"||!l?"":String(l))},options:w,placeholder:g("filter.placeholder",{defaultValue:"Filter..."}),clearable:!0})},i)}),[h,d.fields,f,y,j,g,v]);if(!V||V.length===0)return null;const U=V.filter(Boolean),W=Object.keys(y).length>0;return P(ne,{cols:G??(X?2:[2,4,4,6]),children:[U,m(ee,{variant:"outline",icon:m(N,{size:18}),onClick:Q,disabled:!W,style:{gridColumn:"1 / -1",gridRow:"span 1"},children:g("filter.clear",{defaultValue:"Clear Filters"})})]})}export{Oe as EntityFilters,ke as matchesFilter};
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import type { EntityField, FieldType, ValueTypeForField } from '@donotdev/core';
|
|
2
2
|
import type { ReactElement } from 'react';
|
|
3
3
|
import type { Control, FieldValues } from 'react-hook-form';
|
|
4
|
-
import '../builtinFieldTypes';
|
|
5
4
|
interface FormFieldRendererBaseProps<T extends FieldType = FieldType> {
|
|
6
5
|
name: string;
|
|
7
6
|
config: EntityField<T>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"FormFieldRenderer.d.ts","sourceRoot":"","sources":["../../src/components/FormFieldRenderer.tsx"],"names":[],"mappings":"AAaA,OAAO,KAAK,EAAE,WAAW,EAAE,SAAS,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AAMhF,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,OAAO,CAAC;AAC1C,OAAO,KAAK,EAAE,OAAO,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC;
|
|
1
|
+
{"version":3,"file":"FormFieldRenderer.d.ts","sourceRoot":"","sources":["../../src/components/FormFieldRenderer.tsx"],"names":[],"mappings":"AAaA,OAAO,KAAK,EAAE,WAAW,EAAE,SAAS,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AAMhF,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,OAAO,CAAC;AAC1C,OAAO,KAAK,EAAE,OAAO,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC;AAO5D,UAAU,0BAA0B,CAAC,CAAC,SAAS,SAAS,GAAG,SAAS;IAClE,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,WAAW,CAAC,CAAC,CAAC,CAAC;IACvB,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,KAAK,MAAM,CAAC;CAC3D;AAED,UAAU,iBAAiB,CACzB,CAAC,SAAS,SAAS,CACnB,SAAQ,0BAA0B,CAAC,CAAC,CAAC;IACrC,KAAK,EAAE,iBAAiB,CAAC,CAAC,CAAC,CAAC;IAC5B,QAAQ,EAAE,CAAC,KAAK,EAAE,iBAAiB,CAAC,CAAC,CAAC,KAAK,IAAI,CAAC;IAChD,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,KAAK,CAAC;IAChB,MAAM,CAAC,EAAE,KAAK,CAAC;CAChB;AAED,UAAU,eAAe,CACvB,CAAC,SAAS,SAAS,EACnB,YAAY,SAAS,WAAW,GAAG,WAAW,CAC9C,SAAQ,0BAA0B,CAAC,CAAC,CAAC;IACrC,OAAO,EAAE,OAAO,CAAC,YAAY,CAAC,CAAC;IAC/B,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;IAC5B,KAAK,CAAC,EAAE,KAAK,CAAC;IACd,QAAQ,CAAC,EAAE,KAAK,CAAC;IACjB,KAAK,CAAC,EAAE,KAAK,CAAC;CACf;AAED,MAAM,MAAM,sBAAsB,CAChC,CAAC,SAAS,SAAS,EACnB,YAAY,SAAS,WAAW,GAAG,WAAW,IAC5C,iBAAiB,CAAC,CAAC,CAAC,GAAG,eAAe,CAAC,CAAC,EAAE,YAAY,CAAC,CAAC;AAE5D;;GAEG;AACH,wBAAgB,iBAAiB,CAC/B,CAAC,SAAS,SAAS,EACnB,YAAY,SAAS,WAAW,GAAG,WAAW,EAC9C,EACA,IAAI,EACJ,MAAM,EACN,CAAC,EACD,GAAG,KAAK,EACT,EAAE,sBAAsB,CAAC,CAAC,EAAE,YAAY,CAAC,GAAG,YAAY,CA0GxD;AAED,eAAe,iBAAiB,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
"use client";import{jsx as
|
|
1
|
+
"use client";import{jsx as l}from"react/jsx-runtime";import{handleError as h}from"@donotdev/core";import{getFieldRegistry as T}from"../FieldRegistry";import{ControlledTextField as S}from"./controlled";import{TextFieldComponent as g}from"./form/fields";const x=T();function w({name:r,config:e,t,...o}){const s=n=>d=>{try{n(d)}catch(C){h(C,{userMessage:`Error updating field ${e.label||r}`,context:{fieldName:r,fieldType:e.type},severity:"warning"})}},i="control"in o&&o.control,p=e.type==="submit"||e.type==="reset";if(i&&!p){const{control:n,errors:d}=o,F=e.options?.fieldSpecific?.placeholder,f={control:n,errors:d,fieldConfig:{...e,label:e.label||r},t,placeholder:F,onChange:s(()=>{})},m=x.getControlledComponent(e.type);return m?l(m,{...f}):(h(new Error(`Unregistered field type: ${e.type}`),{userMessage:t("errors.unsupportedFieldType",{type:e.type}),context:{fieldName:r,fieldType:e.type},severity:"warning"}),l(S,{...f,fieldConfig:{...e,type:"text"}}))}const b=i&&p?{name:r,config:e,t,value:void 0,onChange:()=>{},error:void 0}:o,{value:a,onChange:v,error:u}=b,y=s(v),c=x.getUncontrolledComponent(e.type);return c?l(c,{name:r,label:e.label||r,value:a,onChange:y,error:u,t,config:e,...e.options}):l(g,{label:e.label||r,value:a,onChange:y,error:u||void 0,...e.options})}var P=w;export{w as FormFieldRenderer,P as default};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
"use client";import{jsx as
|
|
1
|
+
"use client";import{jsx as e,jsxs as r,Fragment as N}from"react/jsx-runtime";import{useState as j}from"react";import{FormProvider as w}from"react-hook-form";import{Button as s,BUTTON_VARIANT as C,Spinner as F,cn as _,Stack as i,Grid as I}from"@donotdev/components";import{useTranslation as L}from"@donotdev/core";const k=({title:m,onSubmit:c,children:u,formMethods:f,loading:n=!1,submitText:g,cancelText:v,showCancel:p=!1,onCancel:b,variant:l="default",columns:h=1,description:o})=>{const{t:d}=L("crud"),[t,a]=j(!1),y=g||d("form.submit","Submit"),S=v||d("form.cancel","Cancel"),x=async T=>{a(!0);try{await c(T)}finally{a(!1)}},z={1:"dndev-grid-cols-1",2:"dndev-grid-cols-1 dndev-md:grid-cols-2",3:"dndev-grid-cols-1 dndev-md:grid-cols-2 dndev-md:grid-cols-3",4:"dndev-grid-cols-1 dndev-md:grid-cols-2 dndev-md:grid-cols-4"};return e(w,{...f,children:e("form",{onSubmit:x,className:_("dndev-mx-auto",{default:"dndev-surface",card:"dndev-surface",minimal:""}[l]),style:l!=="minimal"?{padding:"var(--gap-lg)"}:void 0,role:"form","aria-labelledby":"form-title",noValidate:!0,children:r(i,{gap:"large",children:[r(i,{gap:"tight",children:[e("h2",{id:"form-title",style:{fontSize:"var(--font-size-2xl)",fontWeight:600,color:"var(--foreground)"},children:m}),o&&e("p",{style:{color:"var(--muted-foreground)"},children:o})]}),e(I,{cols:h,className:"dndev-w-full dndev-min-w-0",children:u}),r(i,{direction:"row",align:"center",justify:"end",style:{paddingTop:"var(--gap-md)",borderTop:"1px solid var(--border)"},children:[p&&e(s,{type:"button",variant:C.OUTLINE,onClick:b,disabled:n||t,children:S}),e(s,{type:"submit",disabled:n||t,style:{minWidth:"120px"},children:n||t?r(N,{children:[e(F,{className:"me-component-gap"}),t?d("form.submitting","Submitting..."):d("form.loading","Loading...")]}):y})]})]})})})};var E=k;export{E as default};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
"use client";import{jsx as
|
|
1
|
+
"use client";import{jsx as l}from"react/jsx-runtime";import{Controller as f}from"react-hook-form";import{AddressFieldComponent as m}from"../../form/fields";import{convertValidationRules as u}from"../types";function h(s){const{control:a,errors:r,fieldConfig:n,t:d}=s,{name:e,label:c,validation:o}=n,t=(n.options||{}).fieldSpecific;return l(f,{name:e,control:a,rules:o?u(o):void 0,render:({field:i})=>l(m,{label:d(c),value:i.value??void 0,onChange:p=>i.onChange(p),error:!!r[e],helperText:r[e]?.message,required:o?.required,enableGoogleMaps:t?.enableGoogleMaps,extractDistrictCode:t?.extractDistrictCode})})}export{h as ControlledAddressField};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
"use client";import{jsx as
|
|
1
|
+
"use client";import{jsx as n}from"react/jsx-runtime";import{Controller as p}from"react-hook-form";import{DateFieldComponent as f}from"../../form/fields";import{convertValidationRules as C}from"../types";function j(a){const{control:l,errors:r,fieldConfig:m,t:i}=a,{name:e,label:d,validation:o,type:s}=m,c={date:"date","datetime-local":"datetime-local",month:"month",time:"time",week:"week"}[s]||"date";return n(p,{name:e,control:l,rules:o?C(o):void 0,render:({field:t})=>n(f,{...t,label:i(d),value:t.value??null,onChange:u=>t.onChange(u),error:!!r[e],helperText:r[e]?.message,required:o?.required,mode:c})})}export{j as ControlledDateField};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
"use client";import{jsxs as t,jsx as
|
|
1
|
+
"use client";import{jsxs as t,jsx as n}from"react/jsx-runtime";import{Plus as j,Trash2 as R}from"lucide-react";import{useFieldArray as $,Controller as q}from"react-hook-form";import{Button as y}from"@donotdev/components";import{getFieldRegistry as A}from"../../../FieldRegistry";import{convertValidationRules as B}from"../types";function D(s){switch(s){case"number":return 0;case"boolean":return!1;default:return""}}function N(s){const{control:d,errors:h,fieldConfig:c,t:o}=s,{name:m,label:p,validation:b}=c,f=c.options?.fieldSpecific??{},r=f.fields??[],l=f.direction??"row",{fields:x,append:C,remove:S}=$({control:d,name:m}),w=A(),z=()=>{if(r.length===0)return;const a={};for(const i of r)a[i.name]=D(i.type);C(a)};return r.length===0?t("div",{style:{fontSize:"var(--font-size-sm)",color:"var(--muted-foreground)"},children:[o(p),": no sub-fields configured"]}):t("div",{style:{display:"flex",flexDirection:"column",gap:"var(--gap-sm)"},children:[t("div",{style:{display:"flex",alignItems:"center",gap:"var(--gap-sm)"},children:[t("span",{style:{fontSize:"var(--font-size-sm)",fontWeight:"var(--font-weight-medium)"},children:[o(p),b?.required&&n("span",{style:{color:"var(--destructive)",marginInlineStart:"var(--gap-tight)"},children:"*"})]}),n(y,{type:"button",variant:"ghost",display:"compact",icon:j,onClick:z,"aria-label":o(p)+" \u2014 add"})]}),x.map((a,i)=>t("div",{style:{display:"flex",flexDirection:l,gap:"var(--gap-sm)",alignItems:l==="row"?"flex-start":void 0},children:[r.map(e=>{const g=`${m}.${i}.${e.name}`,F={name:g,type:e.type,label:e.label,visibility:c.visibility,validation:{...e.validation??{},...e.required?{required:!0}:{}},options:e.options??{}},v=w.getControlledComponent(e.type);return v?n("div",{style:{flex:l==="row"?1:void 0},children:n(v,{control:d,errors:h,fieldConfig:F,t:o})},e.name):n("div",{style:{flex:l==="row"?1:void 0},children:n(q,{name:g,control:d,rules:e.validation?B(e.validation):void 0,render:({field:u})=>t("label",{style:{display:"flex",flexDirection:"column",gap:"var(--gap-tight)"},children:[n("span",{style:{fontSize:"var(--font-size-xs)"},children:o(e.label)}),n("input",{className:"dndev-input",value:String(u.value??""),onChange:u.onChange,onBlur:u.onBlur})]})})},e.name)}),n(y,{type:"button",variant:"ghost",display:"compact",icon:R,onClick:()=>S(i),"aria-label":`Remove row ${i+1}`,style:{alignSelf:l==="row"?"center":"flex-end"}})]},a.id))]})}export{N as ControlledFieldArrayField};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
"use client";import{jsx as
|
|
1
|
+
"use client";import{jsx as a}from"react/jsx-runtime";import{Controller as u}from"react-hook-form";import{GeoPointFieldComponent as p}from"../../form/fields";import{convertValidationRules as C}from"../types";function b(l){const{control:i,errors:t,fieldConfig:s,t:g}=l,{name:n,label:m,validation:o}=s;return a(u,{name:n,control:i,rules:o?C(o):void 0,render:({field:e})=>{const c=r=>{if("target"in r)try{const d=JSON.parse(r.target.value);e.onChange(d)}catch{e.onChange({lat:0,lng:0})}else e.onChange(r||{lat:0,lng:0})};return a(p,{label:g(m),value:e.value||{lat:0,lng:0},onChange:c,error:!!t[n],helperText:t[n]?.message,required:o?.required})}})}export{b as ControlledGeoPointField};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
"use client";import{jsx as
|
|
1
|
+
"use client";import{jsx as a}from"react/jsx-runtime";import{Controller as u}from"react-hook-form";import{MapFieldComponent as g}from"../../form/fields";import{convertValidationRules as C}from"../types";function b(l){const{control:i,errors:t,fieldConfig:s,t:m}=l,{name:r,label:c,validation:n}=s;return a(u,{name:r,control:i,rules:n?C(n):void 0,render:({field:e})=>{const p=o=>{if("target"in o)try{const d=JSON.parse(o.target.value);e.onChange(d)}catch{e.onChange({})}else e.onChange(o||{})};return a(g,{label:m(c),value:e.value||{},onChange:p,error:!!t[r],helperText:t[r]?.message,required:n?.required})}})}export{b as ControlledMapField};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
"use client";import{jsx as
|
|
1
|
+
"use client";import{jsx as t}from"react/jsx-runtime";import{Controller as d}from"react-hook-form";import{MultiInputTextFieldComponent as C}from"../../form/fields";import{convertValidationRules as g}from"../types";function x(a){const{control:l,errors:h,fieldConfig:s,t:i}=a,{name:u,label:c,validation:e,options:m={}}=s;return t(d,{name:u,control:l,rules:e?g(e):void 0,render:({field:r})=>{const p=n=>{if(Array.isArray(n))r.onChange(n);else try{const o=JSON.parse(n.target.value);r.onChange(Array.isArray(o)?o:[])}catch{r.onChange([])}};return t(C,{label:i(c),value:Array.isArray(r.value)?r.value:[],onChange:p,required:e?.required,className:m.className})}})}export{x as ControlledMultiInputField};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
"use client";import{jsx as
|
|
1
|
+
"use client";import{jsx as t}from"react/jsx-runtime";import{Controller as u}from"react-hook-form";import{RichTextComponent as h}from"../../form/fields";import{convertValidationRules as f}from"../types";function R(a){const{control:i,errors:r,fieldConfig:s,t:m,placeholder:c}=a,{name:e,label:d,validation:o,options:l={}}=s;return t(u,{name:e,control:i,rules:o?f(o):void 0,render:({field:n})=>t(h,{label:m(d),value:n.value??"",onChange:p=>n.onChange(p),error:r[e]?.message,helperText:r[e]?.message,required:o?.required,placeholder:c||l.placeholder,className:l.className})})}export{R as ControlledRichTextField};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
"use client";import{jsx as
|
|
1
|
+
"use client";import{jsx as t}from"react/jsx-runtime";import{Controller as d}from"react-hook-form";import{TimestampFieldComponent as p}from"../../form/fields";import{convertValidationRules as c}from"../types";function x(l){const{control:i,errors:n,fieldConfig:a,t:m}=l,{name:e,label:s,validation:r}=a;return t(d,{name:e,control:i,rules:r?c(r):void 0,render:({field:o})=>t(p,{...o,label:m(s),value:o.value??null,onChange:u=>o.onChange(u),error:!!n[e],helperText:n[e]?.message,required:r?.required})})}export{x as ControlledTimestampField};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{ControlledAddressField as
|
|
1
|
+
import{ControlledAddressField as r}from"./ControlledAddressField";import{ControlledFieldArrayField as t}from"./ControlledFieldArrayField";import{ControlledDateField as i}from"./ControlledDateField";import{ControlledGeoPointField as m}from"./ControlledGeoPointField";import{ControlledMapField as x}from"./ControlledMapField";import{ControlledMultiInputField as f}from"./ControlledMultiInputField";import{ControlledRichTextField as a}from"./ControlledRichTextField";import{ControlledTimestampField as u}from"./ControlledTimestampField";export{r as ControlledAddressField,i as ControlledDateField,t as ControlledFieldArrayField,m as ControlledGeoPointField,x as ControlledMapField,f as ControlledMultiInputField,a as ControlledRichTextField,u as ControlledTimestampField};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
"use client";import{jsx as a}from"react/jsx-runtime";import{Controller as
|
|
1
|
+
"use client";import{jsx as a}from"react/jsx-runtime";import{Controller as d}from"react-hook-form";import{DocumentFieldComponent as p}from"../../form/fields";import{convertValidationRules as f}from"../types";function v(i){const{control:m,errors:r,fieldConfig:n,t:s}=i,{name:e,label:u,validation:o}=n,t=n.options||{};return a(d,{name:e,control:m,rules:o?f(o):void 0,render:({field:l})=>a(p,{name:e,label:s(u),value:l.value??null,onChange:c=>l.onChange(c),error:!!r[e],helperText:r[e]?.message,required:o?.required,multiple:!1,maxFiles:1,maxSize:t.maxSize,storagePath:t.storagePath})})}export{v as ControlledDocumentField};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
"use client";import{jsx as
|
|
1
|
+
"use client";import{jsx as i}from"react/jsx-runtime";import{Controller as p}from"react-hook-form";import{FileFieldComponent as c}from"../../form/fields";import{convertValidationRules as f}from"../types";function F(a){const{control:s,errors:r,fieldConfig:n,t:m}=a,{name:e,label:u,validation:o}=n,l=n.options||{};return i(p,{name:e,control:s,rules:o?f(o):void 0,render:({field:t})=>i(c,{name:e,label:m(u),value:t.value??null,onChange:d=>t.onChange(d),error:!!r[e],helperText:r[e]?.message,required:o?.required,multiple:!1,maxFiles:1,maxSize:l.maxSize,storagePath:l.storagePath})})}export{F as ControlledFileField};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
"use client";import{jsx as
|
|
1
|
+
"use client";import{jsx as a}from"react/jsx-runtime";import{Controller as p}from"react-hook-form";import{ImageFieldComponent as c}from"../../form/fields";import{convertValidationRules as f}from"../types";function v(i){const{control:m,errors:r,fieldConfig:n,t:s}=i,{name:e,label:u,validation:o}=n,t=n.options||{};return a(p,{name:e,control:m,rules:o?f(o):void 0,render:({field:l})=>a(c,{name:e,label:s(u),value:l.value??null,onChange:d=>l.onChange(d),error:!!r[e],helperText:r[e]?.message,required:o?.required,multiple:!1,maxFiles:1,maxSize:t.maxSize,storagePath:t.storagePath})})}export{v as ControlledImageField};
|