@donotdev/crud 0.0.17 → 0.0.19
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.js +2 -2
- package/dist/CrudStore.js +1 -1
- package/dist/FieldRegistry.js +1 -1
- package/dist/adapters/FunctionsAdapter.js +1 -1
- package/dist/components/CrudButton.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.d.ts +2 -4
- package/dist/components/DisplayFieldRenderer.d.ts.map +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.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.d.ts +20 -0
- package/dist/components/controlled/select/ControlledReferenceField.d.ts.map +1 -0
- package/dist/components/controlled/select/ControlledReferenceField.js +1 -0
- package/dist/components/controlled/select/ControlledYearField.js +1 -1
- package/dist/components/controlled/select/index.d.ts +1 -0
- package/dist/components/controlled/select/index.d.ts.map +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.d.ts.map +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.d.ts.map +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.d.ts.map +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 +3 -1
- 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.d.ts +3 -0
- package/dist/hooks/index.d.ts.map +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.d.ts +27 -0
- package/dist/hooks/useFieldConditions.d.ts.map +1 -0
- package/dist/hooks/useFieldConditions.js +1 -0
- package/dist/hooks/useFileUpload.js +1 -1
- package/dist/hooks/useReferenceResolver.d.ts +15 -0
- package/dist/hooks/useReferenceResolver.d.ts.map +1 -0
- package/dist/hooks/useReferenceResolver.js +1 -0
- package/dist/hooks/useRelatedItems.js +1 -1
- package/dist/hooks/useUnsavedChangesWarning.js +1 -1
- package/dist/index.d.ts +5 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/registerBuiltinFieldTypes.d.ts.map +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.d.ts.map +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.js +1 -1
- package/dist/utils/imageProcessing.d.ts +1 -3
- package/dist/utils/imageProcessing.d.ts.map +1 -1
- package/dist/utils/imageProcessing.js +1 -1
- package/dist/utils/imageStorage.js +1 -1
- package/dist/utils/imageUtils.js +1 -1
- package/dist/utils/matchesFilter.d.ts.map +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.d.ts +31 -0
- package/dist/workflows/WorkflowPersistence.d.ts.map +1 -0
- package/dist/workflows/WorkflowPersistence.js +1 -0
- package/dist/workflows/defineWorkflow.d.ts +92 -0
- package/dist/workflows/defineWorkflow.d.ts.map +1 -0
- package/dist/workflows/defineWorkflow.js +1 -0
- package/dist/workflows/index.d.ts +15 -0
- package/dist/workflows/index.d.ts.map +1 -0
- package/dist/workflows/index.js +1 -0
- package/dist/workflows/useEntityWorkflow.d.ts +54 -0
- package/dist/workflows/useEntityWorkflow.d.ts.map +1 -0
- package/dist/workflows/useEntityWorkflow.js +1 -0
- package/package.json +8 -5
- package/dist/components/__tests__/EntityFilters.test.d.ts +0 -2
- package/dist/components/__tests__/EntityFilters.test.d.ts.map +0 -1
- package/dist/components/__tests__/EntityFilters.test.js +0 -1
- package/dist/components/__tests__/FormFieldRenderer.test.d.ts +0 -2
- package/dist/components/__tests__/FormFieldRenderer.test.d.ts.map +0 -1
- package/dist/components/__tests__/FormFieldRenderer.test.js +0 -1
package/dist/types.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
const
|
|
1
|
+
const E={PENDING:"pending",CONFIRMED:"confirmed",FAILED:"failed"},e={ADD:"add",UPDATE:"update",SET:"set",DELETE:"delete"};export{e as CRUD_OPERATION,E as OPTIMISTIC_STATUSES};
|
package/dist/useBaseCrudList.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{useMemo as
|
|
1
|
+
import{useMemo as F,useCallback as G,useRef as P}from"react";import{useQuery as H}from"@donotdev/core";import{useCrudStore as J}from"./CrudStore";import{useCrud as z,getCrudServiceInstance as X,EMPTY_OPTIMISTIC as Z}from"./useCrud";import{mergeWithOptimistic as $}from"./utils/mergeWithOptimistic";import{injectScopeFilter as ee,getCurrentScopeValue as te}from"./utils/scopeUtils";import{CRUD_OPERATION as Q}from"./types";function se(R,f,t,p={}){const V=p.enabled??!0,C=z("status"),a=C==="ready",j=z(R,p),{error:q,invalidate:_,_collection:m,_schemas:g,_cacheOptions:O,_scope:b}=j,M=J(e=>e.collections[m]?.optimistic||Z),T=P(new Map([[1,null]])),h=P(0),x=te(b),v=F(()=>{if(!a||!g)return null;const e=X();if(!e)return null;const y=f==="listCard"?g.listCard:g.list,d=ee(p.queryOptions,b);if(!t||t.mode==="client")return e.getListQueryOptions(m,d,y,O,f);const o=T.current,n=h.current,{page:l,pageSize:s}=t;let i,r;if(o.has(l))i=o.get(l)??void 0,r=s;else if(l>n&&o.has(n)){const u=l-n;i=o.get(n)??void 0,r=u*s}else i=void 0,r=l*s;return e.getListQueryOptions(m,{...d,limit:r,startAfter:i},y,O,f)},[a,m,O,g?"hasSchema":"noSchema",f,t?.mode,t?.page,t?.pageSize,p.queryOptions,b?.provider,x]),{data:c,isLoading:K,isFetching:k,error:B,refetch:w}=H({queryKey:v?.queryKey??["crud",m,"disabled"],queryFn:v?.queryFn??(()=>Promise.resolve({items:[]})),staleTime:v?.staleTime,enabled:V&&!!v}),A=F(()=>{if(!c||!a)return{items:[],total:void 0};let e=c.items;if(t?.mode==="server"&&e.length>0){const s=T.current,i=h.current,{page:r,pageSize:u}=t,U=e.length;if(Math.ceil(U/u)>1||r>i){const L=s.has(r)?r:i+1;for(let S=L;S<=r;S++){const D=(S-L+1)*u-1;if(D<e.length){const Y=e[D];s.set(S+1,Y.id)}}}c.lastVisible&&s.set(r+1,c.lastVisible),h.current=Math.max(i,r);const I=s.has(r)?0:(r-i-1)*u,W=I+u;e=e.slice(I,W)}const y=$(e,M),d=new Set(e.map(s=>s.id));let o=0,n=0;for(const[s,i]of Object.entries(M))i.operation===Q.ADD&&!d.has(s)?o++:i.operation===Q.DELETE&&d.has(s)&&n++;const l=(c.total??e.length)+o-n;return{items:y,total:t?l:void 0}},[c,M,a,t?.mode,t?.page,t?.pageSize]),E=G(async()=>{a&&(t?.mode==="server"&&(T.current=new Map([[1,null]]),h.current=0),await _(),await w())},[_,w,a,t?.mode]);if(!a){const e=async()=>{};return{status:C,data:{items:[],total:void 0},items:[],loading:!1,fetching:!1,error:q,mutate:e,refresh:e,isAvailable:!1}}const N=A?.items??[];return{status:C,data:A,items:N,loading:K,fetching:k,error:B??q,mutate:E,refresh:E,isAvailable:!0}}export{se as useBaseCrudList};
|
package/dist/useCrud.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
"use client";import{useEffect as
|
|
1
|
+
"use client";import{useEffect as L,useMemo as F,useCallback as n}from"react";import{useFeatureConsent as W,FRAMEWORK_FEATURES as Z,FEATURE_STATUS as d,handleError as B,isClient as H,createSchemas as J,DEGRADED_CRUD_API as K}from"@donotdev/core";import{getCrudService as Q}from"./CrudService";import{useCrudStore as u}from"./CrudStore";import{injectScope as M,injectScopeFilter as V}from"./utils/scopeUtils";const X={},$={};let _=null,E=null,b=!1;function r(){return _}function ee(l,m={}){const f=W(Z.CRUD),U=u(e=>e.crudService),g=f&&!U,y=f?g?d.INITIALIZING:d.READY:d.DEGRADED,S=l==="status",p=!S&&typeof l=="object"?l:m.entity,a=S?"__status__":typeof l=="string"?l:l.collection,o=p?.scope,v=m.noCache??!1,T=m.staleTime,h=F(()=>({noCache:v,staleTime:T}),[v,T]),t=F(()=>{if(!S){if(m.schema){const e=m.schema;return{create:e,draft:e,update:e,get:e,list:e,listCard:e,delete:e}}if(p)return J(p)}},[S,m.schema,p?.name,a]),Y=u(e=>e.collections[a]?.loading||!1),A=u(e=>e.collections[a]?.error||null),O=null;L(()=>{if(!H()||!f||!t)return;const{crudService:e}=u.getState();e||_||E||(E=(async()=>{try{if(_||u.getState().crudService)return;const s=Q();_=s,s.setStore(u),await s.initialize(),b=!1,u.getState().setCrudService(s)}catch(s){b||(B(s,{userMessage:"Failed to initialize CRUD service.",context:{collection:a},severity:"error"}),b=!0)}finally{E=null}})())},[f,a,t?"hasSchema":"noSchema"]);const D=g||Y,P=y===d.READY,j=n(async e=>{const s=r();return!s||!t?null:s.get(a,e,t.get,h)},[a,t?"hasSchema":"noSchema",h]),G=n(async(e,s,c)=>{const i=r();if(!i||!t)return;const C=M(s,o),k=C?.status==="draft"?t.draft:t.create;await i.set(a,e,C,k,c)},[a,t?"hasSchema":"noSchema",o?.provider]),q=n(async(e,s,c)=>{const i=r();i&&await i.update(a,e,s,t?.update,c)},[a,t]),x=n(async(e,s)=>{const c=r();c&&await c.delete(a,e,s)},[a]),z=n(async(e,s)=>{const c=r();if(!c||!t)return"";const i=M(e,o),C=i?.status==="draft"?t.draft:t.create;return c.add(a,i,C,s)},[a,t?"hasSchema":"noSchema",o?.provider]),N=n(async e=>{const s=r();if(!s||!t)return[];const c=V(e,o);return(await s.query(a,c,t.list,h)).items},[a,t?"hasSchema":"noSchema",h,o?.provider]),R=n((e,s)=>{const c=r();return!c||!t?()=>{}:c.subscribe(a,e,s,t.get)},[a,t?"hasSchema":"noSchema"]),I=n((e,s)=>{const c=r();return!c||!t?()=>{}:c.subscribeToCollection(a,e,s,t.list)},[a,t?"hasSchema":"noSchema"]),w=n(async()=>{const e=r();e&&await e.invalidateCollection(a)},[a]);return S?y:P?{status:d.READY,data:O,loading:D,error:A,get:j,set:G,update:q,delete:x,add:z,query:N,subscribe:R,subscribeToCollection:I,invalidate:w,isAvailable:!0,_collection:a,_schemas:t,_cacheOptions:h,_scope:o}:{...K,status:y,loading:D,error:A,subscribe:R,subscribeToCollection:I,invalidate:w,_collection:a,_schemas:t,_cacheOptions:h,_scope:o}}export{X as EMPTY_DATA,$ as EMPTY_OPTIMISTIC,r as getCrudServiceInstance,ee as useCrud};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useCrudCardList.d.ts","sourceRoot":"","sources":["../src/useCrudCardList.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"useCrudCardList.d.ts","sourceRoot":"","sources":["../src/useCrudCardList.ts"],"names":[],"mappings":"AAmBA,OAAO,KAAK,EAAE,MAAM,EAAE,aAAa,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAM1E,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC;AAQhD,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,8BAA8B,CAAC;AAErE,MAAM,WAAW,sBAAsB,CAAC,CAAC,CAAE,SAAQ,cAAc,CAAC,CAAC,CAAC;IAClE,wDAAwD;IACxD,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,mDAAmD;IACnD,YAAY,CAAC,EAAE,YAAY,CAAC;IAC5B,uDAAuD;IACvD,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,qFAAqF;IACrF,UAAU,CAAC,EAAE,gBAAgB,GAAG,IAAI,CAAC;CACtC;AAED,MAAM,WAAW,qBAAqB,CAAC,CAAC;IACtC,MAAM,EAAE,aAAa,CAAC;IACtB,IAAI,EAAE;QAAE,KAAK,EAAE,CAAC,EAAE,CAAA;KAAE,GAAG,IAAI,CAAC;IAC5B,4FAA4F;IAC5F,KAAK,EAAE,CAAC,EAAE,CAAC;IACX,wEAAwE;IACxE,SAAS,EAAE,CAAC,EAAE,CAAC;IACf,gEAAgE;IAChE,aAAa,EAAE,MAAM,CAAC;IACtB,iDAAiD;IACjD,OAAO,EAAE,OAAO,CAAC;IACjB,6DAA6D;IAC7D,QAAQ,EAAE,OAAO,CAAC;IAClB,KAAK,EAAE,KAAK,GAAG,IAAI,CAAC;IACpB,8BAA8B;IAC9B,MAAM,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IAC5B,wCAAwC;IACxC,OAAO,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IAC7B,WAAW,EAAE,OAAO,CAAC;CACtB;AAED;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAgB,eAAe,CAAC,CAAC,SAAS;IAAE,EAAE,EAAE,MAAM,CAAA;CAAE,GAAG;IAAE,EAAE,EAAE,MAAM,CAAA;CAAE,EACvE,kBAAkB,EAAE,MAAM,GAAG,MAAM,EACnC,OAAO,GAAE,sBAAsB,CAAC,CAAC,CAAM,GACtC,qBAAqB,CAAC,CAAC,CAAC,CAuE1B"}
|
package/dist/useCrudCardList.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{useMemo as
|
|
1
|
+
import{useMemo as d}from"react";import{useBaseCrudList as p}from"./useBaseCrudList";import{useCrudFilters as f}from"./hooks/useCrudFilters";import{applyFilters as h,applySearch as y,applySort as g}from"./utils/clientListProcessing";function C(a,t={}){const o={enabled:t.enabled,queryOptions:t.queryOptions,schema:t.schema,entity:t.entity,staleTime:t.staleTime,noCache:t.noCache},e=p(a,"listCard",null,o),s=typeof a=="string"?null:a,n=s?.collection??a,{filters:l}=f({collection:n}),i=t.clientSort===null?null:t.clientSort??s?.defaultSort??null,{processed:u,filteredTotal:c}=d(()=>{let r=e.items;s&&Object.keys(l).length>0&&(r=h(r,l,s)),s&&t.searchQuery&&(r=y(r,t.searchQuery,s));const m=r.length;return i&&(r=g(r,i)),{processed:r,filteredTotal:m}},[e.items,l,t.searchQuery,i,s]);return{status:e.status,data:e.data?{items:e.data.items}:null,items:e.items,processed:u,filteredTotal:c,loading:e.loading,fetching:e.fetching,error:e.error,mutate:e.mutate,refresh:e.refresh,isAvailable:e.isAvailable}}export{C as useCrudCardList};
|
package/dist/useCrudList.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{useMemo as h}from"react";import{useBaseCrudList as
|
|
1
|
+
import{useMemo as h}from"react";import{useBaseCrudList as g}from"./useBaseCrudList";import{useCrudFilters as S}from"./hooks/useCrudFilters";import{applyFilters as T,applySearch as C,applySort as b}from"./utils/clientListProcessing";function Q(l,e={}){const i=e.pagination??"client",n=e.page??1,c=e.pageSize??10,p={mode:i,page:n,pageSize:c},u={enabled:e.enabled,queryOptions:e.queryOptions,schema:e.schema,entity:e.entity,staleTime:e.staleTime,noCache:e.noCache},s=g(l,"list",p,u),r=typeof l=="string"?null:l,m=r?.collection??l,{filters:o}=S({collection:m}),a=e.clientSort===null?null:e.clientSort??r?.defaultSort??null,{processed:d,filteredTotal:y}=h(()=>{let t=s.items;r&&Object.keys(o).length>0&&(t=T(t,o,r)),r&&e.searchQuery&&(t=C(t,e.searchQuery,r));const f=t.length;return a&&(t=b(t,a)),{processed:t,filteredTotal:f}},[s.items,o,e.searchQuery,a,r]);return{...s,processed:d,filteredTotal:y}}export{Q as useCrudList};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{matchesFilter as u}from"./matchesFilter";import{getValueType as
|
|
1
|
+
import{matchesFilter as u}from"./matchesFilter";import{getValueType as f}from"../fieldTypeRegistry";function d(t,i,a){const o=Object.entries(i);return o.length===0?t:t.filter(n=>o.every(([r,l])=>{const e=a.fields[r]?.type||"text";return u(n[r],l,e)}))}function c(t){if(t.search?.fields&&t.search.fields.length>0)return t.search.fields;const i=new Set(["string"]),a=[];for(const[o,n]of Object.entries(t.fields)){if(n.visibility==="hidden"||n.visibility==="technical")continue;const r=f(n.type);r&&i.has(r)&&a.push(o)}return a}function m(t,i,a){if(!i||i.trim()==="")return t;const o=i.toLowerCase(),n=c(a);return n.length===0?t.filter(r=>Object.values(r).some(l=>l==null?!1:String(l).toLowerCase().includes(o))):t.filter(r=>n.some(l=>{const e=r[l];return e==null?!1:typeof e=="object"&&"formatted_address"in e?String(e.formatted_address).toLowerCase().includes(o):String(e).toLowerCase().includes(o)}))}function p(t,i){const{field:a,direction:o="asc"}=i,n=o==="desc"?-1:1;return[...t].sort((r,l)=>{const e=r[a],s=l[a];return e==null&&s==null?0:e==null?1:s==null?-1:typeof e=="number"&&typeof s=="number"?(e-s)*n:typeof e=="object"&&"amount"in e&&typeof s=="object"&&"amount"in s?(e.amount-s.amount)*n:e instanceof Date&&s instanceof Date?(e.getTime()-s.getTime())*n:String(e).localeCompare(String(s))*n})}export{d as applyFilters,m as applySearch,p as applySort,c as getSearchableFields};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{getCrudService as
|
|
1
|
+
import{getCrudService as c}from"../CrudService";async function d(r,n){const a=c(),e=[],t=n.range?.start??1,s=n.range?.end??28;for(let o=t;o<=s;o++){const m=String(o),i=await a.get(n.path(r),m,n.schema);i&&e.push(i)}return e}async function h(r,n,a){const e=c();for(const t of a){const s=n.idOf(t);await e.set(n.path(r),s,t,n.schema)}}async function p(r,n,a){const e=c();if(n.idFrom){const t=n.idFrom(a);return e.set(n.path(r),t,a,n.schema)}return e.add(n.path(r),a,n.schema)}export{p as appendToCollection,d as loadDeterministicRange,h as upsertDeterministic};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
"use client";import{handleError as d,hasProvider as
|
|
1
|
+
"use client";import{handleError as d,hasProvider as u,getProvider as f}from"@donotdev/core";function y(e){return e.replace(/[^a-zA-Z0-9.-]/g,"_").replace(/_{2,}/g,"_").toLowerCase()}async function m(e,t={}){const{storagePath:r="uploads/files",filename:s,onProgress:o}=t,n=Date.now(),i=y(e.name),l=s||`${n}_${i}`,c=`${r}/${l}`;try{let a;if(u("storage"))a=(await f("storage").upload(e,{storagePath:r,filename:l,onProgress:o?p=>o({bytesTransferred:0,totalBytes:0,progress:p}):void 0})).url;else{const{uploadFileResumable:p}=await import("@donotdev/firebase"),{promise:w}=p(e,{basePath:r,filename:l,onProgress:o,metadata:{contentType:e.type}});a=(await w).url}return{url:a,filename:e.name,size:e.size,mimeType:e.type,uploadedAt:new Date().toISOString()}}catch(a){throw d(a,{userMessage:"Failed to upload file",severity:"error",context:{filename:e.name,fileSize:e.size}})}}async function v(e,t={}){const r=[],s=e.reduce((n,i)=>n+i.size,0);let o=0;for(const n of e){const i=t.onProgress?c=>{const a=c.bytesTransferred/c.totalBytes*n.size;t.onProgress({bytesTransferred:o+a,totalBytes:s,progress:(o+a)/s*100})}:void 0,l=await m(n,{...t,onProgress:i});r.push(l),o+=n.size}return r}async function F(e){try{if(u("storage"))await f("storage").delete(e.url);else{const{deleteFileByUrl:t}=await import("@donotdev/firebase");await t(e.url)}}catch(t){throw d(t,{userMessage:"Failed to delete file",severity:"error",context:{url:e.url,filename:e.filename}}),t}}function M(){return`${Date.now()}-${Math.random().toString(36).slice(2,9)}`}function g(e){const t=e.split(".");return t.length>1?t.pop().toLowerCase():""}function P(e,t){const r=t?g(t):"";if(e){if(e.startsWith("image/"))return"image";if(e.startsWith("video/"))return"video";if(e.startsWith("audio/"))return"audio";if(e==="application/pdf")return"pdf";if(e.includes("word")||e.includes("document"))return"doc";if(e.includes("excel")||e.includes("spreadsheet"))return"xls";if(e.includes("powerpoint")||e.includes("presentation"))return"ppt"}switch(r){case"pdf":return"pdf";case"doc":case"docx":return"doc";case"xls":case"xlsx":case"csv":return"xls";case"ppt":case"pptx":return"ppt";case"md":case"txt":return"text";case"html":case"htm":return"html";case"zip":case"rar":case"7z":return"archive";default:return"file"}}function z(e){if(e===0)return"0 B";const t=1024,r=["B","KB","MB","GB"],s=Math.floor(Math.log(e)/Math.log(t));return`${parseFloat((e/Math.pow(t,s)).toFixed(1))} ${r[s]}`}const h=["application/pdf","application/msword","application/vnd.openxmlformats-officedocument.wordprocessingml.document","application/vnd.ms-excel","application/vnd.openxmlformats-officedocument.spreadsheetml.sheet","application/vnd.ms-powerpoint","application/vnd.openxmlformats-officedocument.presentationml.presentation","text/plain","text/markdown","text/html","text/csv"],x=[".pdf",".doc",".docx",".xls",".xlsx",".ppt",".pptx",".txt",".md",".html",".csv"];function B(){return[...h,...x].join(",")}export{x as DOCUMENT_EXTENSIONS,h as DOCUMENT_MIME_TYPES,F as deleteFile,z as formatFileSize,M as generateFileId,B as getDocumentAcceptString,g as getFileExtension,P as getFileIcon,m as uploadFile,v as uploadFiles};
|
|
@@ -25,9 +25,7 @@ export interface ProcessImageOptions {
|
|
|
25
25
|
aspectRatio?: number;
|
|
26
26
|
/** WebP quality (0-1, default: 0.85 for full, 0.65 for thumb) */
|
|
27
27
|
quality?: number;
|
|
28
|
-
/**
|
|
29
|
-
transparentBackground?: boolean;
|
|
30
|
-
/** Crop region (if provided, overrides automatic center crop) */
|
|
28
|
+
/** Crop region from react-easy-crop (overrides automatic center crop) */
|
|
31
29
|
crop?: {
|
|
32
30
|
x: number;
|
|
33
31
|
y: number;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"imageProcessing.d.ts","sourceRoot":"","sources":["../../src/utils/imageProcessing.ts"],"names":[],"mappings":"AAEA;;;;;;;GAOG;AAEH,MAAM,WAAW,cAAc;IAC7B,QAAQ,EAAE,IAAI,CAAC;IACf,SAAS,EAAE,IAAI,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,mBAAmB;IAClC,wDAAwD;IACxD,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,yDAAyD;IACzD,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,qCAAqC;IACrC,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,sCAAsC;IACtC,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,yCAAyC;IACzC,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,iEAAiE;IACjE,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,
|
|
1
|
+
{"version":3,"file":"imageProcessing.d.ts","sourceRoot":"","sources":["../../src/utils/imageProcessing.ts"],"names":[],"mappings":"AAEA;;;;;;;GAOG;AAEH,MAAM,WAAW,cAAc;IAC7B,QAAQ,EAAE,IAAI,CAAC;IACf,SAAS,EAAE,IAAI,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,mBAAmB;IAClC,wDAAwD;IACxD,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,yDAAyD;IACzD,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,qCAAqC;IACrC,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,sCAAsC;IACtC,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,yCAAyC;IACzC,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,iEAAiE;IACjE,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,yEAAyE;IACzE,IAAI,CAAC,EAAE;QAAE,CAAC,EAAE,MAAM,CAAC;QAAC,CAAC,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC;CAChE;AAED;;GAEG;AACH,wBAAsB,YAAY,CAChC,IAAI,EAAE,IAAI,EACV,OAAO,GAAE,mBAAwB,GAChC,OAAO,CAAC,cAAc,CAAC,CAmEzB;AAmHD;;GAEG;AACH,wBAAgB,iBAAiB,CAC/B,IAAI,EAAE,IAAI,EACV,YAAY,CAAC,EAAE,MAAM,GACpB;IAAE,KAAK,EAAE,OAAO,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE,CAgBpC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
async function
|
|
1
|
+
async function f(a,o={}){const{maxWidth:h=1920,maxHeight:n=1440,thumbWidth:l=300,thumbHeight:t=225,aspectRatio:e=4/3,quality:d=.85,crop:r}=o;return new Promise((w,c)=>{const i=new Image,s=new FileReader;s.onload=g=>{i.src=g.target?.result},s.onerror=()=>c(new Error("Failed to read file")),i.onload=async()=>{try{const{width:g,height:m}=v(r?r.width:i.width,r?r.height:i.height,h,n,e),F=await u(i,g,m,e,d,r),b=await u(i,l,t,e,.65,r);w({fullBlob:F,thumbBlob:b,width:g,height:m})}catch(g){c(g)}},i.onerror=()=>c(new Error("Failed to load image")),s.readAsDataURL(a)})}function v(a,o,h,n,l){let t=a,e=o;t>h&&(e=h/t*e,t=h),e>n&&(t=n/e*t,e=n);const d=t/e;return Math.abs(d-l)>.01&&(d>l?e=t/l:t=e*l),{width:Math.round(t),height:Math.round(e)}}async function u(a,o,h,n,l,t){const e=document.createElement("canvas"),d=e.getContext("2d");if(!d)throw new Error("Failed to get canvas context");e.width=o,e.height=h,d.fillStyle="#FFFFFF",d.fillRect(0,0,o,h);let r,w,c,i;if(t)r=t.x,w=t.y,c=t.width,i=t.height;else{const s=a.width/a.height;c=a.width,i=a.height,r=0,w=0,s>n?(c=a.height*n,r=(a.width-c)/2):s<n&&(i=a.width/n,w=(a.height-i)/2)}return d.drawImage(a,r,w,c,i,0,0,o,h),new Promise((s,g)=>{e.toBlob(m=>{m?s(m):g(new Error("Failed to convert canvas to blob"))},"image/webp",l)})}function x(a,o){return a.type.startsWith("image/")?o&&a.size>o?{valid:!1,error:`File size exceeds ${(o/1048576).toFixed(1)}MB limit`}:{valid:!0}:{valid:!1,error:"File must be an image"}}export{f as processImage,x as validateImageFile};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{handleError as
|
|
1
|
+
import{handleError as _,hasProvider as w,getProvider as m}from"@donotdev/core";function v(e){return e.replace(/[^a-zA-Z0-9.-]/g,"_").replace(/_{2,}/g,"_").toLowerCase()}async function B(e,t,o,d={}){const{storagePath:i="uploads/images",filename:f,onProgress:a}=d,y=Date.now(),r=(f||`${y}_${v(o)}`).replace(/\.[^/.]+$/,""),b=`${i}/${r}_full.webp`,h=`${i}/${r}_thumb.webp`;try{const g=new File([e],`${r}_full.webp`,{type:"image/webp"}),s=new File([t],`${r}_thumb.webp`,{type:"image/webp"});let n,u;if(w("storage")){const l=m("storage");n=(await l.upload(g,{storagePath:i,filename:`${r}_full.webp`,onProgress:a?p=>a({bytesTransferred:0,totalBytes:0,progress:p*.5}):void 0})).url,u=(await l.upload(s,{storagePath:i,filename:`${r}_thumb.webp`,onProgress:a?p=>a({bytesTransferred:0,totalBytes:0,progress:50+p*.5}):void 0})).url}else{const{uploadFileResumable:l}=await import("@donotdev/firebase"),p=a?c=>{a({bytesTransferred:c.bytesTransferred,totalBytes:c.totalBytes*2,progress:c.progress*.5})}:void 0,{promise:U}=l(g,{basePath:i,filename:`${r}_full.webp`,onProgress:p,metadata:{contentType:"image/webp"}});n=(await U).url;const P=a?c=>{a({bytesTransferred:c.bytesTransferred+e.size,totalBytes:e.size+t.size,progress:50+c.progress*.5})}:void 0,{promise:$}=l(s,{basePath:i,filename:`${r}_thumb.webp`,onProgress:P,metadata:{contentType:"image/webp"}});u=(await $).url}return{fullUrl:n,thumbUrl:u}}catch(g){try{if(w("storage")){const s=m("storage");await s.delete(b).catch(()=>{}),await s.delete(h).catch(()=>{})}else{const{getFileUrl:s,deleteFileByUrl:n}=await import("@donotdev/firebase"),u=await s(b).catch(()=>null),l=await s(h).catch(()=>null);u&&await n(u).catch(()=>{}),l&&await n(l).catch(()=>{})}}catch{}throw g}}async function F(e){try{if(w("storage")){const t=m("storage"),o=[t.delete(e.fullUrl)];e.thumbUrl&&o.push(t.delete(e.thumbUrl)),await Promise.all(o)}else{const{deleteFileByUrl:t}=await import("@donotdev/firebase"),o=[t(e.fullUrl)];e.thumbUrl&&o.push(t(e.thumbUrl)),await Promise.all(o)}}catch(t){throw _(t,{userMessage:"Failed to delete image",severity:"error",context:{fullUrl:e.fullUrl,thumbUrl:e.thumbUrl}}),t}}export{F as deleteImage,B as uploadImage};
|
package/dist/utils/imageUtils.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
async function d(e){const t=await e.arrayBuffer(),r=await crypto.subtle.digest("SHA-256",t);return Array.from(new Uint8Array(r)).map(
|
|
1
|
+
async function d(e){const t=await e.arrayBuffer(),r=await crypto.subtle.digest("SHA-256",t);return Array.from(new Uint8Array(r)).map(a=>a.toString(16).padStart(2,"0")).join("")}function h(e){return URL.createObjectURL(e)}function u(e){e.startsWith("blob:")&&URL.revokeObjectURL(e)}async function l(e){return new Promise((t,r)=>{const a=new Image,i=new FileReader;i.onload=n=>{if(!n.target?.result){r(new Error("Failed to read file"));return}a.src=n.target.result},i.onerror=()=>r(new Error("Failed to read file")),a.onload=()=>{const n=document.createElement("canvas"),o=n.getContext("2d");if(!o){r(new Error("Failed to get canvas context"));return}n.width=a.height,n.height=a.width,o.translate(n.width/2,n.height/2),o.rotate(Math.PI/2),o.drawImage(a,-a.width/2,-a.height/2),n.toBlob(s=>{if(s){const c=new File([s],e.name,{type:e.type,lastModified:Date.now()});t(c)}else r(new Error("Failed to create blob from canvas"))},e.type,.95)},a.onerror=()=>r(new Error("Failed to load image")),i.readAsDataURL(e)})}class g{undoStack=[];redoStack=[];maxStackSize=50;push(t){this.undoStack.push(t),this.undoStack.length>this.maxStackSize&&this.undoStack.shift(),this.redoStack=[]}undo(){const t=this.undoStack.pop();return t?(this.redoStack.push(t),t):null}redo(){const t=this.redoStack.pop();return t?(this.undoStack.push(t),t):null}canUndo(){return this.undoStack.length>0}canRedo(){return this.redoStack.length>0}clear(){this.undoStack=[],this.redoStack=[]}}function S(e,t){return e.filter(r=>r.hash===t)}function w(){return`img_${Date.now()}_${Math.random().toString(36).substr(2,9)}`}export{g as UndoRedoManager,h as createPreviewURL,S as findDuplicatesByHash,d as generateFileHash,w as generateImageId,u as revokePreviewURL,l as rotateImage90};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"matchesFilter.d.ts","sourceRoot":"","sources":["../../src/utils/matchesFilter.ts"],"names":[],"mappings":"AAcA;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,wBAAgB,aAAa,CAC3B,SAAS,EAAE,GAAG,EAEd,WAAW,EACP,MAAM,GACN;IAAE,GAAG,CAAC,EAAE,MAAM,CAAC;IAAC,GAAG,CAAC,EAAE,MAAM,CAAA;CAAE,GAC9B,MAAM,EAAE,GACR;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,CAAA;CAAE,GAC/B;IACE,GAAG,CAAC,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IACtC,GAAG,CAAC,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;CACvC,GACD;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,CAAA;CAAE,EAAE,EAErC,SAAS,EAAE,MAAM,GAChB,OAAO,
|
|
1
|
+
{"version":3,"file":"matchesFilter.d.ts","sourceRoot":"","sources":["../../src/utils/matchesFilter.ts"],"names":[],"mappings":"AAcA;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,wBAAgB,aAAa,CAC3B,SAAS,EAAE,GAAG,EAEd,WAAW,EACP,MAAM,GACN;IAAE,GAAG,CAAC,EAAE,MAAM,CAAC;IAAC,GAAG,CAAC,EAAE,MAAM,CAAA;CAAE,GAC9B,MAAM,EAAE,GACR;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,CAAA;CAAE,GAC/B;IACE,GAAG,CAAC,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IACtC,GAAG,CAAC,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;CACvC,GACD;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,CAAA;CAAE,EAAE,EAErC,SAAS,EAAE,MAAM,GAChB,OAAO,CA8VT"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{getFilterType as
|
|
1
|
+
import{getFilterType as N}from"../fieldTypeRegistry";function T(e,t,r){if(!t)return!0;if(Array.isArray(t)){if(t.length===0)return!0;if(!(N(r)==="range"&&(r==="date"||r==="datetime-local"||r==="timestamp")))return t.some(i=>{if(typeof i=="object"&&"date"in i){const g=i.date;return(e instanceof Date?e.toISOString().split("T")[0]:new Date(e).toISOString().split("T")[0])===g}return String(e)===String(i)});const a=e instanceof Date?e.toISOString().split("T")[0]:new Date(e).toISOString().split("T")[0];return t.some(i=>typeof i=="string"?a===i:typeof i=="object"&&"date"in i?a===i.date:!1)}if(typeof t=="object"&&"date"in t&&!("min"in t)&&!Array.isArray(t)){if(!(N(r)==="range"&&(r==="date"||r==="datetime-local"||r==="timestamp")))return!1;const a=t.date;if(!a)return!0;if(e==null)return!1;const i=e instanceof Date?e.toISOString().split("T")[0]:new Date(e).toISOString().split("T")[0];if((r==="datetime-local"||r==="timestamp")&&t.time){const g=e instanceof Date?e.toISOString().slice(11,16):new Date(e).toISOString().slice(11,16);return i===a&&g===t.time}return i===a}if(typeof t=="object"&&"min"in t){const a=N(r);if(!a)return!0;const i=a==="range"&&(r==="date"||r==="datetime-local"||r==="timestamp"),g=a==="range"&&!i,w=r==="price",f=w&&e!=null&&typeof e=="object"?Number(e.amount):g&&e!=null?typeof e=="number"?e:Number(e):NaN;if(g||w){if(typeof t.min=="object"&&t.min!==null&&"date"in t.min)return!1;const n=t,l=typeof n.min=="string"&&n.min!=="",c=typeof n.max=="string"&&n.max!=="";return l&&!c?e==null||isNaN(f)?!1:f>=Number(n.min):!l&&c?e==null?!0:isNaN(f)?!1:f<=Number(n.max):l&&c?e==null||isNaN(f)?!1:f>=Number(n.min)&&f<=Number(n.max):!0}if(i){if(typeof t.min=="object"&&t.min!==null&&"date"in t.min&&!("min"in t.min)){const o=t,u=o.min,s=o.max,D=u?.date&&u.date!=="",S=s?.date&&s.date!=="";if(D&&!S){if(e==null)return!1;const m=e instanceof Date?e:new Date(e);if(isNaN(m.getTime()))return!1;const d=new Date(u.date+(u.time?`T${u.time}:00`:"T00:00:00"));return m>=d}if(!D&&S&&s){if(e==null)return!0;const m=e instanceof Date?e:new Date(e);if(isNaN(m.getTime()))return!1;const d=new Date(s.date+(s.time?`T${s.time}:00`:"T23:59:59"));return m<=d}if(D&&S&&s){if(e==null)return!1;const m=e instanceof Date?e:new Date(e);if(isNaN(m.getTime()))return!1;const d=new Date(u.date+(u.time?`T${u.time}:00`:"T00:00:00")),y=new Date(s.date+(s.time?`T${s.time}:00`:"T23:59:59"));return m>=d&&m<=y}return!0}const n=t,l=typeof n.min=="string"&&n.min!=="",c=typeof n.max=="string"&&n.max!=="";if(l&&!c){if(e==null)return!1;const o=e instanceof Date?e:new Date(e);return isNaN(o.getTime())?!1:o>=new Date(n.min)}if(!l&&c){if(e==null)return!0;const o=e instanceof Date?e:new Date(e);return isNaN(o.getTime())?!1:o<=new Date(n.max)}if(l&&c){if(e==null)return!1;const o=e instanceof Date?e:new Date(e);return isNaN(o.getTime())?!1:o>=new Date(n.min)&&o<=new Date(n.max)}return!0}}if(typeof t=="string"&&N(r)==="rating"){if(e==null)return!1;const a=Number(t),i=typeof e=="number"?e:Number(e);return isNaN(a)||isNaN(i)?!0:i>=a}const p=N(r);if(!p)return!0;if(p==="address")return e==null?!1:typeof e=="object"&&"formatted_address"in e?String(e.formatted_address).toLowerCase().includes(String(t).toLowerCase()):!1;if(p==="multiselect"){if(!Array.isArray(e)||e.length===0)return!1;const a=String(t).toLowerCase();return e.some(i=>String(i).toLowerCase().includes(a))}return e==null?!1:String(e).toLowerCase().includes(String(t).toLowerCase())}export{T as matchesFilter};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{CRUD_OPERATION as
|
|
1
|
+
import{CRUD_OPERATION as a}from"../types";function p(n,s){const o=[],e=new Set;for(const i of n){const t=s[i.id];t?.operation!==a.DELETE&&(t?.operation===a.UPDATE&&t.optimisticData?o.push(t.optimisticData):o.push(i),e.add(i.id))}for(const[i,t]of Object.entries(s))t.operation===a.ADD&&!e.has(i)&&t.optimisticData&&o.push(t.optimisticData);return o}export{p as mergeWithOptimistic};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
const
|
|
1
|
+
const r=/<script[\s\S]*?<\/script>/gi,e=/\s+on\w+\s*=\s*["'][^"']*["']/gi,i=/\s+(?:xlink:)?href\s*=\s*["']\s*javascript:[^"']*["']/gi,c=/\s+src\s*=\s*["']\s*javascript:[^"']*["']/gi;function t(s){return s.replace(r,"").replace(e,"").replace(i,"").replace(c,"")}export{t as sanitizeHtml};
|
package/dist/utils/scopeUtils.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{getScopeValue as n,CRUD_OPERATORS as
|
|
1
|
+
import{getScopeValue as n,CRUD_OPERATORS as u}from"@donotdev/core";function c(e,r){if(!r)return e;const t=n(r.provider);return t?{...e,[r.field]:t}:e}function f(e,r){const t=e??{};if(!r||typeof r.field!="string")return t;const i=n(r.provider);if(!i)return t;const o={field:r.field,operator:u.EQ,value:i};return{...t,where:t.where?[...t.where,o]:[o]}}function p(e){return e?n(e.provider):null}export{p as getCurrentScopeValue,c as injectScope,f as injectScopeFilter};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
"use client";function
|
|
1
|
+
"use client";function n(t){return!t||typeof t!="string"?!1:t.startsWith("https://")&&!t.startsWith("blob:")}function h(t){return!(!t||typeof t!="object"||!n(t.fullUrl)||t.thumbUrl&&!n(t.thumbUrl))}function u(t,o=""){const s=[];if(t==null)return s;if(typeof t=="string")return t.startsWith("blob:")&&s.push(o||"root"),s;if(typeof t!="object")return s;if(Array.isArray(t))t.forEach((r,l)=>{const e=o?`${o}[${l}]`:`[${l}]`;s.push(...u(r,e))});else{const r=t;if(r.fullUrl!==void 0&&r.thumbUrl!==void 0){const l=r.fullUrl,e=r.thumbUrl,i=typeof l=="string"&&!n(l),c=e&&typeof e=="string"&&!n(e);if(i||c){const f=o||"root";s.push(`${f}.fullUrl or ${f}.thumbUrl contains blob URL`)}}else Object.entries(r).forEach(([l,e])=>{const i=o?`${o}.${l}`:l;s.push(...u(e,i))})}return s}function b(t){return u(t).length>0}export{u as checkForBlobUrls,b as hasBlobUrls,n as isStorageUrl,h as validatePicture};
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Workflow persistence adapter
|
|
3
|
+
* @description Saves and restores workflow progress to/from localStorage.
|
|
4
|
+
*
|
|
5
|
+
* @version 0.0.1
|
|
6
|
+
* @since 0.0.1
|
|
7
|
+
* @author AMBROISE PARK Consulting
|
|
8
|
+
*/
|
|
9
|
+
/** Persisted workflow state */
|
|
10
|
+
export interface PersistedWorkflowState {
|
|
11
|
+
/** Current step index */
|
|
12
|
+
currentStepIndex: number;
|
|
13
|
+
/** Data per step (keyed by step id) */
|
|
14
|
+
stepData: Record<string, Record<string, unknown>>;
|
|
15
|
+
/** Timestamp of last save */
|
|
16
|
+
savedAt: number;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Save workflow state to localStorage.
|
|
20
|
+
*/
|
|
21
|
+
export declare function saveWorkflowState(workflowId: string, state: PersistedWorkflowState): void;
|
|
22
|
+
/**
|
|
23
|
+
* Load workflow state from localStorage.
|
|
24
|
+
* Returns null if no saved state exists or parsing fails.
|
|
25
|
+
*/
|
|
26
|
+
export declare function loadWorkflowState(workflowId: string): PersistedWorkflowState | null;
|
|
27
|
+
/**
|
|
28
|
+
* Clear persisted workflow state.
|
|
29
|
+
*/
|
|
30
|
+
export declare function clearWorkflowState(workflowId: string): void;
|
|
31
|
+
//# sourceMappingURL=WorkflowPersistence.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"WorkflowPersistence.d.ts","sourceRoot":"","sources":["../../src/workflows/WorkflowPersistence.ts"],"names":[],"mappings":"AAEA;;;;;;;GAOG;AAEH,+BAA+B;AAC/B,MAAM,WAAW,sBAAsB;IACrC,yBAAyB;IACzB,gBAAgB,EAAE,MAAM,CAAC;IACzB,uCAAuC;IACvC,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;IAClD,6BAA6B;IAC7B,OAAO,EAAE,MAAM,CAAC;CACjB;AAID;;GAEG;AACH,wBAAgB,iBAAiB,CAC/B,UAAU,EAAE,MAAM,EAClB,KAAK,EAAE,sBAAsB,GAC5B,IAAI,CAON;AAED;;;GAGG;AACH,wBAAgB,iBAAiB,CAC/B,UAAU,EAAE,MAAM,GACjB,sBAAsB,GAAG,IAAI,CAS/B;AAED;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,UAAU,EAAE,MAAM,GAAG,IAAI,CAO3D"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
const a="dndev-workflow-";function r(t,o){try{const e=`${a}${t}`;localStorage.setItem(e,JSON.stringify(o))}catch{}}function c(t){try{const o=`${a}${t}`,e=localStorage.getItem(o);return e?JSON.parse(e):null}catch{return null}}function n(t){try{const o=`${a}${t}`;localStorage.removeItem(o)}catch{}}export{n as clearWorkflowState,c as loadWorkflowState,r as saveWorkflowState};
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview defineWorkflow utility
|
|
3
|
+
* @description Creates a type-safe workflow configuration for multi-step entity forms.
|
|
4
|
+
*
|
|
5
|
+
* @example
|
|
6
|
+
* ```typescript
|
|
7
|
+
* import { defineWorkflow } from '@donotdev/crud';
|
|
8
|
+
* import { companyEntity, contactEntity } from './entities';
|
|
9
|
+
*
|
|
10
|
+
* const onboarding = defineWorkflow({
|
|
11
|
+
* id: 'customer-onboarding',
|
|
12
|
+
* name: 'Customer Onboarding',
|
|
13
|
+
* persist: true,
|
|
14
|
+
* steps: [
|
|
15
|
+
* { id: 'company', title: 'Company Info', entity: companyEntity, fields: ['name', 'industry'] },
|
|
16
|
+
* { id: 'contact', title: 'Primary Contact', entity: contactEntity, fields: ['firstName', 'email'] },
|
|
17
|
+
* ],
|
|
18
|
+
* });
|
|
19
|
+
* ```
|
|
20
|
+
*
|
|
21
|
+
* @version 0.0.1
|
|
22
|
+
* @since 0.0.1
|
|
23
|
+
* @author AMBROISE PARK Consulting
|
|
24
|
+
*/
|
|
25
|
+
import type { Entity } from '@donotdev/core';
|
|
26
|
+
import type { ConditionInput, ConditionalBehavior } from '@donotdev/core';
|
|
27
|
+
import type { ReactNode } from 'react';
|
|
28
|
+
/** Configuration for a single workflow step */
|
|
29
|
+
export interface WorkflowStep {
|
|
30
|
+
/** Unique step identifier */
|
|
31
|
+
id: string;
|
|
32
|
+
/** Step title displayed in stepper */
|
|
33
|
+
title: string;
|
|
34
|
+
/** Step description (optional) */
|
|
35
|
+
description?: string;
|
|
36
|
+
/** Entity definition to use for this step's form */
|
|
37
|
+
entity?: Entity;
|
|
38
|
+
/** Subset of entity fields to show in this step (if omitted, shows all) */
|
|
39
|
+
fields?: string[];
|
|
40
|
+
/** Whether the user can skip this step */
|
|
41
|
+
allowSkip?: boolean;
|
|
42
|
+
/** Conditions for step visibility (cross-step references use 'stepId.field' notation) */
|
|
43
|
+
conditions?: {
|
|
44
|
+
visible?: ConditionInput;
|
|
45
|
+
};
|
|
46
|
+
/** Field-level condition overrides for this step (e.g., make a field required based on previous step data) */
|
|
47
|
+
fieldConditions?: Record<string, ConditionalBehavior>;
|
|
48
|
+
/** Callback after step is completed */
|
|
49
|
+
after?: (context: WorkflowStepContext) => void | Promise<void>;
|
|
50
|
+
/** Custom render function for non-entity steps (e.g., review/summary) */
|
|
51
|
+
custom?: (allData: Record<string, unknown>) => ReactNode;
|
|
52
|
+
/** Custom validation for the step */
|
|
53
|
+
validation?: {
|
|
54
|
+
validate?: (data: Record<string, unknown>) => boolean | string;
|
|
55
|
+
message?: string;
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
/** Context passed to step callbacks */
|
|
59
|
+
export interface WorkflowStepContext {
|
|
60
|
+
/** Data collected in the current step */
|
|
61
|
+
data: Record<string, unknown>;
|
|
62
|
+
/** All data collected across all steps */
|
|
63
|
+
allData: Record<string, unknown>;
|
|
64
|
+
/** Helper to prefill next step */
|
|
65
|
+
next: {
|
|
66
|
+
prefill: (values: Record<string, unknown>) => void;
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
/** Full workflow configuration */
|
|
70
|
+
export interface WorkflowConfig {
|
|
71
|
+
/** Unique workflow identifier */
|
|
72
|
+
id: string;
|
|
73
|
+
/** Workflow display name */
|
|
74
|
+
name: string;
|
|
75
|
+
/** Whether to persist progress to localStorage */
|
|
76
|
+
persist?: boolean;
|
|
77
|
+
/** Persistence key prefix (defaults to workflow id) */
|
|
78
|
+
persistKey?: string;
|
|
79
|
+
/** Workflow steps */
|
|
80
|
+
steps: WorkflowStep[];
|
|
81
|
+
/** Callback when all steps are completed */
|
|
82
|
+
onComplete?: (allData: Record<string, unknown>) => void | Promise<void>;
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* Define a multi-step workflow configuration.
|
|
86
|
+
* Identity function that provides type safety and documentation.
|
|
87
|
+
*
|
|
88
|
+
* @param config - Workflow configuration
|
|
89
|
+
* @returns The same config, typed as WorkflowConfig
|
|
90
|
+
*/
|
|
91
|
+
export declare function defineWorkflow(config: WorkflowConfig): WorkflowConfig;
|
|
92
|
+
//# sourceMappingURL=defineWorkflow.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"defineWorkflow.d.ts","sourceRoot":"","sources":["../../src/workflows/defineWorkflow.ts"],"names":[],"mappings":"AAEA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAEH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,gBAAgB,CAAC;AAC7C,OAAO,KAAK,EAAE,cAAc,EAAE,mBAAmB,EAAE,MAAM,gBAAgB,CAAC;AAC1E,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAEvC,+CAA+C;AAC/C,MAAM,WAAW,YAAY;IAC3B,6BAA6B;IAC7B,EAAE,EAAE,MAAM,CAAC;IACX,sCAAsC;IACtC,KAAK,EAAE,MAAM,CAAC;IACd,kCAAkC;IAClC,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,oDAAoD;IACpD,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,2EAA2E;IAC3E,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;IAClB,0CAA0C;IAC1C,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,yFAAyF;IACzF,UAAU,CAAC,EAAE;QACX,OAAO,CAAC,EAAE,cAAc,CAAC;KAC1B,CAAC;IACF,8GAA8G;IAC9G,eAAe,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,mBAAmB,CAAC,CAAC;IACtD,uCAAuC;IACvC,KAAK,CAAC,EAAE,CAAC,OAAO,EAAE,mBAAmB,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC/D,yEAAyE;IACzE,MAAM,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,SAAS,CAAC;IACzD,qCAAqC;IACrC,UAAU,CAAC,EAAE;QACX,QAAQ,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,OAAO,GAAG,MAAM,CAAC;QAC/D,OAAO,CAAC,EAAE,MAAM,CAAC;KAClB,CAAC;CACH;AAED,uCAAuC;AACvC,MAAM,WAAW,mBAAmB;IAClC,yCAAyC;IACzC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC9B,0CAA0C;IAC1C,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACjC,kCAAkC;IAClC,IAAI,EAAE;QACJ,OAAO,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,IAAI,CAAC;KACpD,CAAC;CACH;AAED,kCAAkC;AAClC,MAAM,WAAW,cAAc;IAC7B,iCAAiC;IACjC,EAAE,EAAE,MAAM,CAAC;IACX,4BAA4B;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,kDAAkD;IAClD,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,uDAAuD;IACvD,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,qBAAqB;IACrB,KAAK,EAAE,YAAY,EAAE,CAAC;IACtB,4CAA4C;IAC5C,UAAU,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CACzE;AAED;;;;;;GAMG;AACH,wBAAgB,cAAc,CAAC,MAAM,EAAE,cAAc,GAAG,cAAc,CAErE"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
function e(n){return n}export{e as defineWorkflow};
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Workflow engine exports
|
|
3
|
+
* @description Multi-step entity workflow: defineWorkflow, useEntityWorkflow, persistence.
|
|
4
|
+
*
|
|
5
|
+
* @version 0.0.1
|
|
6
|
+
* @since 0.0.1
|
|
7
|
+
* @author AMBROISE PARK Consulting
|
|
8
|
+
*/
|
|
9
|
+
export { defineWorkflow } from './defineWorkflow';
|
|
10
|
+
export type { WorkflowConfig, WorkflowStep, WorkflowStepContext, } from './defineWorkflow';
|
|
11
|
+
export { useEntityWorkflow } from './useEntityWorkflow';
|
|
12
|
+
export type { UseEntityWorkflowOptions, EntityWorkflowReturn, } from './useEntityWorkflow';
|
|
13
|
+
export { saveWorkflowState, loadWorkflowState, clearWorkflowState, } from './WorkflowPersistence';
|
|
14
|
+
export type { PersistedWorkflowState } from './WorkflowPersistence';
|
|
15
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/workflows/index.ts"],"names":[],"mappings":"AAEA;;;;;;;GAOG;AAEH,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAClD,YAAY,EACV,cAAc,EACd,YAAY,EACZ,mBAAmB,GACpB,MAAM,kBAAkB,CAAC;AAE1B,OAAO,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAC;AACxD,YAAY,EACV,wBAAwB,EACxB,oBAAoB,GACrB,MAAM,qBAAqB,CAAC;AAE7B,OAAO,EACL,iBAAiB,EACjB,iBAAiB,EACjB,kBAAkB,GACnB,MAAM,uBAAuB,CAAC;AAC/B,YAAY,EAAE,sBAAsB,EAAE,MAAM,uBAAuB,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{defineWorkflow as o}from"./defineWorkflow";import{useEntityWorkflow as a}from"./useEntityWorkflow";import{saveWorkflowState as t,loadWorkflowState as r,clearWorkflowState as e}from"./WorkflowPersistence";export{e as clearWorkflowState,o as defineWorkflow,r as loadWorkflowState,t as saveWorkflowState,a as useEntityWorkflow};
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import type { WorkflowConfig, WorkflowStep } from './defineWorkflow';
|
|
2
|
+
/** Options for useEntityWorkflow */
|
|
3
|
+
export interface UseEntityWorkflowOptions {
|
|
4
|
+
/** Callback when all steps are completed and data is submitted */
|
|
5
|
+
onComplete?: (allData: Record<string, unknown>) => void | Promise<void>;
|
|
6
|
+
/** Callback when step changes */
|
|
7
|
+
onStepChange?: (fromIndex: number, toIndex: number) => void;
|
|
8
|
+
/** Default values to pre-fill across steps */
|
|
9
|
+
defaultValues?: Record<string, unknown>;
|
|
10
|
+
}
|
|
11
|
+
/** Return type of useEntityWorkflow */
|
|
12
|
+
export interface EntityWorkflowReturn {
|
|
13
|
+
/** Current step configuration */
|
|
14
|
+
currentStep: WorkflowStep;
|
|
15
|
+
/** Current step index (0-based, relative to visible steps) */
|
|
16
|
+
currentStepIndex: number;
|
|
17
|
+
/** Steps after condition filtering (only visible steps) */
|
|
18
|
+
visibleSteps: WorkflowStep[];
|
|
19
|
+
/** Data per step (keyed by step id) */
|
|
20
|
+
stepData: Record<string, Record<string, unknown>>;
|
|
21
|
+
/** Merged data across all steps */
|
|
22
|
+
allData: Record<string, unknown>;
|
|
23
|
+
/** Navigate to next step (validates current step first) */
|
|
24
|
+
goNext: (currentStepData?: Record<string, unknown>) => Promise<boolean>;
|
|
25
|
+
/** Navigate to previous step */
|
|
26
|
+
goPrevious: () => void;
|
|
27
|
+
/** Skip current step (only if allowSkip is true) */
|
|
28
|
+
skipStep: () => void;
|
|
29
|
+
/** Jump to a specific step by index */
|
|
30
|
+
goToStep: (index: number) => void;
|
|
31
|
+
/** Whether current step is the first visible step */
|
|
32
|
+
isFirst: boolean;
|
|
33
|
+
/** Whether current step is the last visible step */
|
|
34
|
+
isLast: boolean;
|
|
35
|
+
/** Whether the workflow is submitting (final step) */
|
|
36
|
+
isSubmitting: boolean;
|
|
37
|
+
/** Whether the current step can proceed (no validation errors) */
|
|
38
|
+
canGoNext: boolean;
|
|
39
|
+
/** Force save current state to localStorage */
|
|
40
|
+
persistNow: () => void;
|
|
41
|
+
/** Clear all persisted state */
|
|
42
|
+
clearPersisted: () => void;
|
|
43
|
+
/** Prefill data for a specific step */
|
|
44
|
+
prefillStep: (stepId: string, values: Record<string, unknown>) => void;
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Orchestrate a multi-step entity workflow.
|
|
48
|
+
*
|
|
49
|
+
* @param config - Workflow configuration from defineWorkflow()
|
|
50
|
+
* @param options - Workflow options (callbacks, defaults)
|
|
51
|
+
* @returns Workflow state and navigation methods
|
|
52
|
+
*/
|
|
53
|
+
export declare function useEntityWorkflow(config: WorkflowConfig, options?: UseEntityWorkflowOptions): EntityWorkflowReturn;
|
|
54
|
+
//# sourceMappingURL=useEntityWorkflow.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useEntityWorkflow.d.ts","sourceRoot":"","sources":["../../src/workflows/useEntityWorkflow.ts"],"names":[],"mappings":"AA0BA,OAAO,KAAK,EAAE,cAAc,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAOrE,oCAAoC;AACpC,MAAM,WAAW,wBAAwB;IACvC,kEAAkE;IAClE,UAAU,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACxE,iCAAiC;IACjC,YAAY,CAAC,EAAE,CAAC,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;IAC5D,8CAA8C;IAC9C,aAAa,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACzC;AAED,uCAAuC;AACvC,MAAM,WAAW,oBAAoB;IACnC,iCAAiC;IACjC,WAAW,EAAE,YAAY,CAAC;IAC1B,8DAA8D;IAC9D,gBAAgB,EAAE,MAAM,CAAC;IACzB,2DAA2D;IAC3D,YAAY,EAAE,YAAY,EAAE,CAAC;IAC7B,uCAAuC;IACvC,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;IAClD,mCAAmC;IACnC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACjC,2DAA2D;IAC3D,MAAM,EAAE,CAAC,eAAe,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;IACxE,gCAAgC;IAChC,UAAU,EAAE,MAAM,IAAI,CAAC;IACvB,oDAAoD;IACpD,QAAQ,EAAE,MAAM,IAAI,CAAC;IACrB,uCAAuC;IACvC,QAAQ,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IAClC,qDAAqD;IACrD,OAAO,EAAE,OAAO,CAAC;IACjB,oDAAoD;IACpD,MAAM,EAAE,OAAO,CAAC;IAChB,sDAAsD;IACtD,YAAY,EAAE,OAAO,CAAC;IACtB,kEAAkE;IAClE,SAAS,EAAE,OAAO,CAAC;IACnB,+CAA+C;IAC/C,UAAU,EAAE,MAAM,IAAI,CAAC;IACvB,gCAAgC;IAChC,cAAc,EAAE,MAAM,IAAI,CAAC;IAC3B,uCAAuC;IACvC,WAAW,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,IAAI,CAAC;CACxE;AAED;;;;;;GAMG;AACH,wBAAgB,iBAAiB,CAC/B,MAAM,EAAE,cAAc,EACtB,OAAO,GAAE,wBAA6B,GACrC,oBAAoB,CAyPtB"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use client";import{useState as m,useCallback as p,useMemo as D,useEffect as L,useRef as M}from"react";import{evaluateCondition as R}from"@donotdev/core";import{saveWorkflowState as K,loadWorkflowState as j,clearWorkflowState as C}from"./WorkflowPersistence";function V(e,O={}){const{onComplete:w,onStepChange:f,defaultValues:y}=O,g=M(w);g.current=w;const[a,v]=m(()=>{if(e.persist){const t=j(e.persistKey??e.id);if(t)return t.stepData}if(y){const t={};for(const r of e.steps)if(r.entity&&r.fields){const o={};for(const i of r.fields)i in y&&(o[i]=y[i]);Object.keys(o).length>0&&(t[r.id]=o)}return t}return{}}),[s,S]=m(()=>{if(e.persist){const t=j(e.persistKey??e.id);if(t)return t.currentStepIndex}return 0}),[k,x]=m(!1),l=D(()=>{const t={};for(const[r,o]of Object.entries(a))for(const[i,c]of Object.entries(o))t[i]=c,t[`${r}.${i}`]=c;return t},[a]),n=D(()=>e.steps.filter(t=>t.conditions?.visible?R(t.conditions.visible,l):!0),[e.steps,l]),I=n[s]??n[0],b=s===0,d=s===n.length-1;L(()=>{e.persist&&K(e.persistKey??e.id,{currentStepIndex:s,stepData:a,savedAt:Date.now()})},[e.persist,e.persistKey,e.id,s,a]);const W=p(async t=>{const r=n[s];if(!r)return!1;if(t&&v(i=>({...i,[r.id]:{...i[r.id],...t}})),r.validation?.validate){const i={...l,...t??{}};if(r.validation.validate(i)!==!0)return!1}if(r.after){const i={};await r.after({data:t??a[r.id]??{},allData:{...l,...t??{}},next:{prefill:c=>{const u=n[s+1];u&&(i[u.id]=c)}}}),Object.keys(i).length>0&&v(c=>{const u={...c};for(const[h,G]of Object.entries(i))u[h]={...u[h],...G};return u})}if(d){x(!0);try{const i={...l,...t??{}},c=g.current??e.onComplete;return c&&await c(i),e.persist&&C(e.persistKey??e.id),!0}catch{return!1}finally{x(!1)}}const o=s+1;return S(o),f?.(s,o),!0},[n,s,l,a,d,e,f]),N=p(()=>{if(b)return;const t=s-1;S(t),f?.(s,t)},[s,b,f]),A=p(()=>{if(!n[s]?.allowSkip||d)return;const t=s+1;S(t),f?.(s,t)},[n,s,d,f]),E=p(t=>{t>=0&&t<n.length&&(f?.(s,t),S(t))},[n.length,s,f]),P=p(()=>{e.persist&&K(e.persistKey??e.id,{currentStepIndex:s,stepData:a,savedAt:Date.now()})},[e,s,a]),$=p(()=>{C(e.persistKey??e.id)},[e]),F=p((t,r)=>{v(o=>({...o,[t]:{...o[t],...r}}))},[]);return{currentStep:I,currentStepIndex:s,visibleSteps:n,stepData:a,allData:l,goNext:W,goPrevious:N,skipStep:A,goToStep:E,isFirst:b,isLast:d,isSubmitting:k,canGoNext:!k,persistNow:P,clearPersisted:$,prefillStep:F}}export{V as useEntityWorkflow};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@donotdev/crud",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.19",
|
|
4
4
|
"private": false,
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "SEE LICENSE IN LICENSE.md",
|
|
@@ -53,13 +53,13 @@
|
|
|
53
53
|
"@dnd-kit/core": "^6.3.1",
|
|
54
54
|
"@dnd-kit/sortable": "^10.0.0",
|
|
55
55
|
"@dnd-kit/utilities": "^3.2.2",
|
|
56
|
-
"@donotdev/components": "^0.0.
|
|
57
|
-
"@donotdev/core": "^0.0.
|
|
56
|
+
"@donotdev/components": "^0.0.22",
|
|
57
|
+
"@donotdev/core": "^0.0.28",
|
|
58
58
|
"@hookform/resolvers": "^5.2.2",
|
|
59
59
|
"react-easy-crop": "^5.5.6"
|
|
60
60
|
},
|
|
61
61
|
"peerDependencies": {
|
|
62
|
-
"@donotdev/firebase": "^0.0.
|
|
62
|
+
"@donotdev/firebase": "^0.0.14",
|
|
63
63
|
"@tiptap/extension-placeholder": "^3.19.0",
|
|
64
64
|
"@tiptap/pm": "^3.19.0",
|
|
65
65
|
"@tiptap/react": "^3.19.0",
|
|
@@ -68,7 +68,7 @@
|
|
|
68
68
|
"lucide-react": "^0.574.0",
|
|
69
69
|
"react": "^19.2.4",
|
|
70
70
|
"react-dom": "^19.2.4",
|
|
71
|
-
"react-hook-form": "^7.71.
|
|
71
|
+
"react-hook-form": "^7.71.2",
|
|
72
72
|
"valibot": "^1.2.0"
|
|
73
73
|
},
|
|
74
74
|
"peerDependenciesMeta": {
|
|
@@ -89,6 +89,9 @@
|
|
|
89
89
|
},
|
|
90
90
|
"firebase": {
|
|
91
91
|
"optional": true
|
|
92
|
+
},
|
|
93
|
+
"tiptap": {
|
|
94
|
+
"optional": true
|
|
92
95
|
}
|
|
93
96
|
}
|
|
94
97
|
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"EntityFilters.test.d.ts","sourceRoot":"","sources":["../../../src/components/__tests__/EntityFilters.test.tsx"],"names":[],"mappings":""}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{jsx as i}from"react/jsx-runtime";import{describe as d,it as r,expect as a,vi as t,beforeEach as c}from"vitest";import{render as n,screen as o}from"@testing-library/react";import{EntityFilters as s}from"../EntityFilters";import{defineEntity as u}from"@donotdev/core";t.mock("@donotdev/core",async()=>({...await t.importActual("@donotdev/core"),useTranslation:t.fn(()=>e=>e),handleError:t.fn()})),t.mock("@donotdev/components",()=>({Button:({children:e,...l})=>i("button",{...l,children:e}),Grid:({children:e})=>i("div",{children:e}),Combobox:({children:e})=>i("div",{children:e})})),t.mock("../hooks/useCrudFilters",()=>({useCrudFilters:t.fn(()=>({filters:{},setFilter:t.fn(),clearFilters:t.fn()}))})),d("EntityFilters",()=>{const e=u({name:"Product",collection:"products",fields:{title:{name:"title",label:"Title",type:"text",visibility:"user"},status:{name:"status",label:"Status",type:"select",visibility:"user",validation:{options:[{value:"active",label:"Active"},{value:"inactive",label:"Inactive"}]}}}});c(()=>{t.clearAllMocks()}),r("renders filters for entity fields",()=>{n(i(s,{entity:e})),a(o.getByRole("button",{name:/clear/i})).toBeDefined()}),r("renders with data prop",()=>{n(i(s,{entity:e,data:[{id:"1",title:"Product 1",status:"active"},{id:"2",title:"Product 2",status:"inactive"}]})),a(o.getByRole("button",{name:/clear/i})).toBeDefined()}),r("renders with sidebar variant",()=>{n(i(s,{entity:e,variant:"sidebar"})),a(o.getByRole("button",{name:/clear/i})).toBeDefined()})});
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"FormFieldRenderer.test.d.ts","sourceRoot":"","sources":["../../../src/components/__tests__/FormFieldRenderer.test.tsx"],"names":[],"mappings":""}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{jsx as n}from"react/jsx-runtime";import{describe as d,it as i,expect as a,vi as e,beforeEach as f}from"vitest";import{render as l}from"@testing-library/react";import{FormFieldRenderer as s}from"../FormFieldRenderer";e.mock("react-hook-form",()=>({useFormContext:e.fn(()=>({register:e.fn(),control:{},formState:{errors:{}}})),Controller:({render:t})=>{const o={onChange:e.fn(),onBlur:e.fn(),value:"",name:"test-field"};return t({field:o})}})),e.mock("../FieldRegistry",()=>({getFieldRegistry:e.fn(()=>({getComponent:e.fn(()=>()=>n("div",{children:"Mock Field"}))}))})),d("FormFieldRenderer",()=>{const t={name:"title",label:"Title",type:"text",visibility:"user",validation:{required:!0}},o=e.fn(r=>r);f(()=>{e.clearAllMocks()}),i("renders field with correct props",()=>{const{container:r}=l(n(s,{name:"title",config:t,t:o,control:{},errors:{}}));a(r).toBeDefined()}),i("renders textarea field for textarea type",()=>{const r={...t,type:"textarea",name:"description",label:"Description"},{container:c}=l(n(s,{name:"description",config:r,t:o,control:{},errors:{}}));a(c).toBeDefined()}),i("handles uncontrolled mode",()=>{const{container:r}=l(n(s,{name:"title",config:t,t:o,value:"",onChange:e.fn()}));a(r).toBeDefined()})});
|