@wise/dynamic-flow-client 5.8.1 → 5.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/build/DynamicFlowCore.js +5 -0
- package/build/common/errorBoundary/ErrorBoundary.js +26 -0
- package/build/common/errorBoundary/ErrorBoundary.test.js +29 -0
- package/build/common/errorBoundary/ErrorBoundaryAlert.js +11 -0
- package/build/common/makeHttpClient/api-utils.js +3 -0
- package/build/common/makeHttpClient/index.js +1 -0
- package/build/common/makeHttpClient/makeHttpClient.js +10 -0
- package/build/common/makeHttpClient/makeHttpClient.test.js +186 -0
- package/build/common/messages/external-confirmation.messages.js +23 -0
- package/build/common/messages/file-upload.messages.js +13 -0
- package/build/common/messages/generic-error.messages.js +18 -0
- package/build/common/messages/help.messages.js +8 -0
- package/build/common/messages/multi-file-upload.messages.js +18 -0
- package/build/common/messages/multi-select.messages.js +8 -0
- package/build/common/messages/paragraph.messages.js +13 -0
- package/build/common/messages/repeatable.messages.js +23 -0
- package/build/common/messages/search.messages.js +8 -0
- package/build/common/messages/validation.array.messages.js +13 -0
- package/build/common/messages/validation.messages.js +53 -0
- package/build/controller/FlowController.js +368 -0
- package/build/controller/executePoll.js +49 -0
- package/build/controller/executeRefresh.js +39 -0
- package/build/controller/executeRequest.js +77 -0
- package/build/controller/executeSubmission.js +69 -0
- package/build/controller/getErrorMessage.js +7 -0
- package/build/controller/getRequestAbortController.js +13 -0
- package/build/controller/getResponseType.js +35 -0
- package/build/controller/getSafeHttpClient.js +8 -0
- package/build/controller/getStepCounter.js +16 -0
- package/build/controller/handleErrorResponse.js +26 -0
- package/build/controller/makeSafeHttpClient.js +8 -0
- package/build/controller/response-utils.js +72 -0
- package/build/domain/components/AlertComponent.js +1 -0
- package/build/domain/components/AllOfComponent.js +40 -0
- package/build/domain/components/BooleanInputComponent.js +50 -0
- package/build/domain/components/BoxComponent.js +3 -0
- package/build/domain/components/ButtonComponent.js +1 -0
- package/build/domain/components/ColumnsComponent.js +3 -0
- package/build/domain/components/ConstComponent.js +18 -0
- package/build/domain/components/ContainerComponent.js +3 -0
- package/build/domain/components/DateInputComponent.js +75 -0
- package/build/domain/components/DecisionComponent.js +1 -0
- package/build/domain/components/DividerComponent.js +1 -0
- package/build/domain/components/FormComponent.js +3 -0
- package/build/domain/components/FormattedValueComponent.js +44 -0
- package/build/domain/components/HeadingComponent.js +1 -0
- package/build/domain/components/ImageComponent.js +1 -0
- package/build/domain/components/InstructionsComponent.js +1 -0
- package/build/domain/components/IntegerInputComponent.js +74 -0
- package/build/domain/components/ListComponent.js +1 -0
- package/build/domain/components/LoadingIndicatorComponent.js +1 -0
- package/build/domain/components/MarkdownComponent.js +1 -0
- package/build/domain/components/MediaComponent.js +1 -0
- package/build/domain/components/ModalComponent.js +16 -0
- package/build/domain/components/ModalLayoutComponent.js +3 -0
- package/build/domain/components/MoneyInputComponent.js +57 -0
- package/build/domain/components/MultiSelectInputComponent.js +81 -0
- package/build/domain/components/MultiUploadInputComponent.js +88 -0
- package/build/domain/components/NumberInputComponent.js +73 -0
- package/build/domain/components/ObjectComponent.js +45 -0
- package/build/domain/components/ParagraphComponent.js +1 -0
- package/build/domain/components/PersistAsyncComponent.js +92 -0
- package/build/domain/components/ProgressComponent.js +1 -0
- package/build/domain/components/RepeatableComponent.js +103 -0
- package/build/domain/components/ReviewComponent.js +1 -0
- package/build/domain/components/RootDomainComponent.js +173 -0
- package/build/domain/components/SectionComponent.js +5 -0
- package/build/domain/components/SelectInputComponent.js +88 -0
- package/build/domain/components/StatusListComponent.js +1 -0
- package/build/domain/components/SubflowDomainComponent.js +9 -0
- package/build/domain/components/TabsComponent.js +1 -0
- package/build/domain/components/TextInputComponent.js +76 -0
- package/build/domain/components/TupleComponent.js +41 -0
- package/build/domain/components/UploadInputComponent.js +83 -0
- package/build/domain/components/UpsellComponent.js +25 -0
- package/build/domain/components/searchComponent/SearchComponent.js +92 -0
- package/build/domain/components/searchComponent/SearchComponent.test.js +190 -0
- package/build/domain/components/step/ExternalConfirmationComponent.js +28 -0
- package/build/domain/components/step/StepDomainComponent.js +73 -0
- package/build/domain/components/step/ToolbarComponent.js +1 -0
- package/build/domain/components/utils/WithUpdate.js +1 -0
- package/build/domain/components/utils/component-utils.js +12 -0
- package/build/domain/components/utils/debounce.js +34 -0
- package/build/domain/components/utils/debounce.test.js +67 -0
- package/build/domain/components/utils/file-utils.js +21 -0
- package/build/domain/components/utils/file-utils.test.js +27 -0
- package/build/domain/components/utils/getRandomId.js +1 -0
- package/build/domain/components/utils/isExactLocalValueMatch.js +14 -0
- package/build/domain/components/utils/isOrWasValid.js +5 -0
- package/build/domain/components/utils/isPartialModelMatch.js +18 -0
- package/build/domain/components/utils/isPartialModelMatch.test.js +74 -0
- package/build/domain/features/eventNames.js +24 -0
- package/build/domain/features/events.js +1 -0
- package/build/domain/features/persistAsync/getComponentMultiPersistAsync.js +50 -0
- package/build/domain/features/persistAsync/getInitialPersistedState.js +7 -0
- package/build/domain/features/persistAsync/getPerformPersistAsync.js +43 -0
- package/build/domain/features/persistAsync/getPerformPersistAsync.test.js +139 -0
- package/build/domain/features/polling/getStepPolling.js +43 -0
- package/build/domain/features/polling/getStepPolling.test.js +90 -0
- package/build/domain/features/prefetch/getStepPrefetch.js +43 -0
- package/build/domain/features/prefetch/request-cache.js +49 -0
- package/build/domain/features/prefetch/request-cache.test.js +70 -0
- package/build/domain/features/refreshAfter/getStepRefreshAfter.js +24 -0
- package/build/domain/features/refreshAfter/getStepRefreshAfter.test.js +40 -0
- package/build/domain/features/schema-on-change/getDebouncedSchemaOnChange.js +50 -0
- package/build/domain/features/schema-on-change/getSchemaOnChange.js +34 -0
- package/build/domain/features/search/getPerformSearchFunction.js +75 -0
- package/build/domain/features/search/getPerformSearchFunction.test.js +301 -0
- package/build/domain/features/summary/summary-utils.js +40 -0
- package/build/domain/features/summary/summary-utils.test.js +125 -0
- package/build/domain/features/utils/http-utils.js +21 -0
- package/build/domain/features/utils/response-utils.js +9 -0
- package/build/domain/features/validation/spec-utils.js +19 -0
- package/build/domain/features/validation/validateStringPattern.js +24 -0
- package/build/domain/features/validation/validation-functions.js +6 -0
- package/build/domain/features/validation/validation-functions.test.js +108 -0
- package/build/domain/features/validation/value-checks.js +125 -0
- package/build/domain/features/validation/value-checks.test.js +262 -0
- package/build/domain/features/validationAsync/getComponentValidationAsync.js +53 -0
- package/build/domain/features/validationAsync/getComponentValidationAsync.test.js +67 -0
- package/build/domain/features/validationAsync/getInitialValidationAsyncState.js +5 -0
- package/build/domain/features/validationAsync/getPerformValidationAsync.js +45 -0
- package/build/domain/features/validationAsync/getPerformValidationAsync.test.js +143 -0
- package/build/domain/mappers/layout/alertLayoutToComponent.js +16 -0
- package/build/domain/mappers/layout/boxLayoutToComponent.js +13 -0
- package/build/domain/mappers/layout/buttonLayoutToComponent.js +77 -0
- package/build/domain/mappers/layout/columnsLayoutToComponent.js +13 -0
- package/build/domain/mappers/layout/decisionLayoutToComponent.js +22 -0
- package/build/domain/mappers/layout/deprecatedListLayoutToComponent.js +30 -0
- package/build/domain/mappers/layout/dividerLayoutToComponent.js +2 -0
- package/build/domain/mappers/layout/formLayoutToComponent.js +19 -0
- package/build/domain/mappers/layout/headingLayoutToComponent.js +12 -0
- package/build/domain/mappers/layout/imageLayoutToComponent.js +20 -0
- package/build/domain/mappers/layout/infoLayoutToComponent.js +12 -0
- package/build/domain/mappers/layout/instructionsLayoutToComponent.js +12 -0
- package/build/domain/mappers/layout/listLayoutToComponent.js +39 -0
- package/build/domain/mappers/layout/loadingIndicatorLayoutToComponent.js +9 -0
- package/build/domain/mappers/layout/markdownLayoutToComponent.js +12 -0
- package/build/domain/mappers/layout/mediaLayoutToComponent.js +12 -0
- package/build/domain/mappers/layout/modalLayoutToComponent.js +17 -0
- package/build/domain/mappers/layout/modalToComponent.js +8 -0
- package/build/domain/mappers/layout/paragraphLayoutToComponent.js +12 -0
- package/build/domain/mappers/layout/progressLayoutToComponent.js +15 -0
- package/build/domain/mappers/layout/reviewLayoutToComponent.js +48 -0
- package/build/domain/mappers/layout/searchLayoutToComponent.js +44 -0
- package/build/domain/mappers/layout/sectionLayoutToComponent.js +15 -0
- package/build/domain/mappers/layout/statusListLayoutToComponent.js +15 -0
- package/build/domain/mappers/layout/tabsLayoutToComponent.js +16 -0
- package/build/domain/mappers/layout/upsellLayoutToComponent.js +25 -0
- package/build/domain/mappers/mapLayoutToComponent.js +81 -0
- package/build/domain/mappers/mapSchemaToComponent.js +61 -0
- package/build/domain/mappers/mapSchemaToComponent.test.js +112 -0
- package/build/domain/mappers/mapStepSchemas.js +17 -0
- package/build/domain/mappers/mapStepToComponent.js +132 -0
- package/build/domain/mappers/mapStepToComponent.test.js +221 -0
- package/build/domain/mappers/mapToolbarToComponent.js +15 -0
- package/build/domain/mappers/schema/allOfSchemaToComponent.js +16 -0
- package/build/domain/mappers/schema/arraySchemaToComponent/arraySchemaToComponent.js +26 -0
- package/build/domain/mappers/schema/arraySchemaToComponent/arraySchemaToMultiSelectComponent.js +55 -0
- package/build/domain/mappers/schema/arraySchemaToComponent/arraySchemaToMultiUploadComponent.js +67 -0
- package/build/domain/mappers/schema/arraySchemaToComponent/arraySchemaToRepeatableComponent.js +57 -0
- package/build/domain/mappers/schema/arraySchemaToComponent/arraySchemaToTupleComponent.js +20 -0
- package/build/domain/mappers/schema/blobSchemaToComponent.js +15 -0
- package/build/domain/mappers/schema/booleanSchemaToComponent.js +29 -0
- package/build/domain/mappers/schema/constSchemaToComponent.js +23 -0
- package/build/domain/mappers/schema/integerSchemaToComponent.js +28 -0
- package/build/domain/mappers/schema/numberSchemaToComponent.js +26 -0
- package/build/domain/mappers/schema/objectSchemaToComponent/assertDisplayOrder.js +23 -0
- package/build/domain/mappers/schema/objectSchemaToComponent/objectSchemaToFormattedValueComponent.js +9 -0
- package/build/domain/mappers/schema/objectSchemaToComponent/objectSchemaToMoneyInputComponent.js +119 -0
- package/build/domain/mappers/schema/objectSchemaToComponent/objectSchemaToMoneyInputComponent.test.js +96 -0
- package/build/domain/mappers/schema/objectSchemaToComponent/objectSchemaToObjectComponent.js +31 -0
- package/build/domain/mappers/schema/objectSchemaToComponent/objectSchemaToObjectComponent.test.js +99 -0
- package/build/domain/mappers/schema/oneOfSchemaToComponent/oneOfSchemaToComponent.js +76 -0
- package/build/domain/mappers/schema/oneOfSchemaToComponent/oneOfSchemaToComponent.test.js +265 -0
- package/build/domain/mappers/schema/persistAsyncSchemaToComponent.js +29 -0
- package/build/domain/mappers/schema/stringSchemaToComponent/stringSchemaToComponent.js +18 -0
- package/build/domain/mappers/schema/stringSchemaToComponent/stringSchemaToComponent.test.js +133 -0
- package/build/domain/mappers/schema/stringSchemaToComponent/stringSchemaToDateInputComponent.js +48 -0
- package/build/domain/mappers/schema/stringSchemaToComponent/stringSchemaToTextInputComponent.js +37 -0
- package/build/domain/mappers/schema/stringSchemaToComponent/stringSchemaToUploadInputComponent.js +28 -0
- package/build/domain/mappers/schema/tests/test-utils.js +16 -0
- package/build/domain/mappers/schema/types.js +1 -0
- package/build/domain/mappers/schema/utils/getPerformPersistAsyncFn.js +19 -0
- package/build/domain/mappers/schema/utils/getValidationAsyncInitialState.js +23 -0
- package/build/domain/mappers/schema/utils/mapCommonSchemaProps.js +16 -0
- package/build/domain/mappers/types.js +1 -0
- package/build/domain/mappers/utils/FeatureFlags.js +22 -0
- package/build/domain/mappers/utils/behavior-utils.js +44 -0
- package/build/domain/mappers/utils/call-to-action-utils.js +21 -0
- package/build/domain/mappers/utils/getAutocompleteString.js +76 -0
- package/build/domain/mappers/utils/getAutocompleteString.test.js +21 -0
- package/build/domain/mappers/utils/groupLayoutByPinned.js +38 -0
- package/build/domain/mappers/utils/groupLayoutByPinned.test.js +166 -0
- package/build/domain/mappers/utils/image.js +9 -0
- package/build/domain/mappers/utils/layout-utils.js +11 -0
- package/build/domain/mappers/utils/legacy-utils.js +49 -0
- package/build/domain/mappers/utils/media-utils.js +14 -0
- package/build/domain/mappers/utils/suggestions-utils.js +26 -0
- package/build/domain/mappers/utils/suggestions-utils.test.js +36 -0
- package/build/domain/mappers/utils/tags-utils.js +1 -0
- package/build/domain/mappers/utils/utils.js +35 -0
- package/build/domain/types.js +1 -0
- package/build/getSubflowCallbacks.js +38 -0
- package/build/i18n/index.js +40 -0
- package/build/index.js +8 -0
- package/build/main.js +112 -54
- package/build/main.mjs +111 -53
- package/build/renderers/CoreContainerRenderer.js +5 -0
- package/build/renderers/CoreRootRenderer.js +12 -0
- package/build/renderers/EmptyLoadingStateRenderer.js +5 -0
- package/build/renderers/getRenderFunction.js +24 -0
- package/build/renderers/getSchemaErrorMessageFunction.js +97 -0
- package/build/renderers/mappers/alertComponentToProps.js +2 -0
- package/build/renderers/mappers/allOfComponentToProps.js +6 -0
- package/build/renderers/mappers/booleanInputComponentToProps.js +5 -0
- package/build/renderers/mappers/boxComponentToProps.js +13 -0
- package/build/renderers/mappers/buttonComponentToProps.js +4 -0
- package/build/renderers/mappers/columnsComponentToProps.js +11 -0
- package/build/renderers/mappers/componentToRendererProps.js +164 -0
- package/build/renderers/mappers/constComponentToProps.js +5 -0
- package/build/renderers/mappers/containerComponentToProps.js +7 -0
- package/build/renderers/mappers/dateInputComponentToProps.js +2 -0
- package/build/renderers/mappers/decisionComponentToProps.js +16 -0
- package/build/renderers/mappers/dividerComponentToProps.js +2 -0
- package/build/renderers/mappers/externalComponentToProps.js +3 -0
- package/build/renderers/mappers/formComponentToProps.js +12 -0
- package/build/renderers/mappers/formattedValueComponentToProps.js +5 -0
- package/build/renderers/mappers/headingComponentToProps.js +2 -0
- package/build/renderers/mappers/hiddenComponentToProps.js +4 -0
- package/build/renderers/mappers/imageComponentToProps.js +2 -0
- package/build/renderers/mappers/instructionsComponentToProps.js +2 -0
- package/build/renderers/mappers/integerInputComponentToProps.js +2 -0
- package/build/renderers/mappers/listComponentToProps.js +2 -0
- package/build/renderers/mappers/loadingIndicatorComponentToProps.js +2 -0
- package/build/renderers/mappers/markdownComponentToProps.js +2 -0
- package/build/renderers/mappers/mediaComponentToProps.js +2 -0
- package/build/renderers/mappers/modalComponentToProps.js +11 -0
- package/build/renderers/mappers/modalLayoutComponentToProps.js +16 -0
- package/build/renderers/mappers/moneyInputComponentToProps.js +36 -0
- package/build/renderers/mappers/multiSelectComponentToProps.js +23 -0
- package/build/renderers/mappers/multiUploadInputComponentToProps.js +12 -0
- package/build/renderers/mappers/numberInputComponentToProps.js +2 -0
- package/build/renderers/mappers/objectComponentToProps.js +8 -0
- package/build/renderers/mappers/paragraphComponentToProps.js +2 -0
- package/build/renderers/mappers/persistAsyncComponentToProps.js +8 -0
- package/build/renderers/mappers/progressComponentToProps.js +2 -0
- package/build/renderers/mappers/repeatableComponentToProps.js +30 -0
- package/build/renderers/mappers/reviewComponentToProps.js +2 -0
- package/build/renderers/mappers/rootComponentToProps.js +21 -0
- package/build/renderers/mappers/searchComponentToProps.js +57 -0
- package/build/renderers/mappers/sectionComponentToProps.js +6 -0
- package/build/renderers/mappers/selectInputComponentToProps.js +26 -0
- package/build/renderers/mappers/statusListComponentToProps.js +2 -0
- package/build/renderers/mappers/subflowComponentToRendererProps.js +4 -0
- package/build/renderers/mappers/tabsComponentToProps.js +14 -0
- package/build/renderers/mappers/textInputComponentToProps.js +2 -0
- package/build/renderers/mappers/tupleComponentToProps.js +8 -0
- package/build/renderers/mappers/uploadInputComponentToProps.js +8 -0
- package/build/renderers/mappers/upsellComponentToProps.js +2 -0
- package/build/renderers/mappers/utils/getValidationState.js +12 -0
- package/build/renderers/mappers/utils/inputComponentToProps.js +26 -0
- package/build/renderers/mappers/utils/mapErrorsToValidationState.js +9 -0
- package/build/renderers/mappers/utils/pick.js +8 -0
- package/build/renderers/mappers/utils/selectInputOptionsToProps.js +11 -0
- package/build/renderers/stepComponentToProps.js +32 -0
- package/build/renderers/utils.js +69 -0
- package/build/renderers/utils.test.js +70 -0
- package/build/stories/dev-tools/ContainerQueries.story.js +66 -0
- package/build/stories/dev-tools/Debugger.story.js +38 -0
- package/build/stories/dev-tools/FixtureSelect.story.js +23 -0
- package/build/stories/dev-tools/TestServer.story.js +32 -0
- package/build/stories/examples/NativeFlow.story.js +80 -0
- package/build/stories/examples/Recipients.story.js +568 -0
- package/build/stories/spec/behavior/Copy.story.js +59 -0
- package/build/stories/spec/behavior/Modal.story.js +76 -0
- package/build/stories/spec/behavior/Subflow.story.js +267 -0
- package/build/stories/spec/layouts/Decision.story.js +241 -0
- package/build/stories/spec/layouts/Image.story.js +42 -0
- package/build/stories/spec/layouts/Modal.story.js +81 -0
- package/build/stories/spec/layouts/Search.story.js +325 -0
- package/build/stories/spec/layouts/Upsell.story.js +55 -0
- package/build/stories/spec/layouts/button/Button.story.js +100 -0
- package/build/stories/spec/layouts/button/PinnedButton.story.js +81 -0
- package/build/stories/spec/response/ActionResponse.story.js +66 -0
- package/build/stories/spec/schemas/MultiSelect.story.js +148 -0
- package/build/stories/spec/schemas/Upload.story.js +168 -0
- package/build/stories/spec/schemas/const/ConstLayout.story.js +159 -0
- package/build/stories/spec/schemas/const/ObjectConst.story.js +94 -0
- package/build/stories/spec/schemas/features/PersistAsync.story.js +176 -0
- package/build/stories/spec/schemas/features/ValidationAsync.story.js +103 -0
- package/build/stories/spec/schemas/object/FormattedValue.story.js +92 -0
- package/build/stories/spec/schemas/object/MoneyInput.story.js +240 -0
- package/build/stories/spec/schemas/oneOf/OneOfInitialisation.story.js +55 -0
- package/build/stories/spec/step/Controls.story.js +109 -0
- package/build/stories/spec/step/DFModal.story.js +58 -0
- package/build/stories/spec/step/Footer.story.js +70 -0
- package/build/stories/spec/step/Navigation.story.js +20 -0
- package/build/stories/spec/step/Tags.story.js +39 -0
- package/build/stories/spec/step/ToolBar.story.js +60 -0
- package/build/stories/spec/step/features/ErrorHandling.story.js +92 -0
- package/build/stories/spec/step/features/External.story.js +44 -0
- package/build/stories/spec/step/features/Polling.story.js +108 -0
- package/build/stories/spec/step/features/RefreshAfter.story.js +92 -0
- package/build/stories/spec/step/features/refresh/Refresh.story.js +258 -0
- package/build/stories/spec/step/features/refresh/RefreshWithPersistAsync.story.js +958 -0
- package/build/stories/types.js +1 -0
- package/build/stories/utils/fixtureHttpClient.js +70 -0
- package/build/stories/utils/getBasicStep.js +223 -0
- package/build/stories/utils/mockSearchHandler.js +71 -0
- package/build/stories/utils/render-utils.js +41 -0
- package/build/stories/visual-tests/layouts/NotUsingListItem.story.js +17 -0
- package/build/test-utils/DynamicFlowWise.js +32 -0
- package/build/test-utils/DynamicFlowWiseModal.js +34 -0
- package/build/test-utils/NeptuneProviders.js +11 -0
- package/build/test-utils/component-utils.js +5 -0
- package/build/test-utils/fetch-utils.js +45 -0
- package/build/test-utils/getMergedTestRenderers.js +34 -0
- package/build/test-utils/getRandomId.js +1 -0
- package/build/test-utils/index.js +3 -0
- package/build/test-utils/rtl-utils.js +7 -0
- package/build/test-utils/step-utils.js +6 -0
- package/build/test-utils/wait.js +3 -0
- package/build/tests/AlertLayout.test.js +78 -0
- package/build/tests/ArrayTuple.test.js +118 -0
- package/build/tests/ButtonLayout.test.js +308 -0
- package/build/tests/ConstLayout.test.js +95 -0
- package/build/tests/DateInput.test.js +163 -0
- package/build/tests/DecisionLayout.test.js +146 -0
- package/build/tests/DynamicFlow.test.js +147 -0
- package/build/tests/External.test.js +169 -0
- package/build/tests/Flow.test.js +328 -0
- package/build/tests/FormLayout.test.js +28 -0
- package/build/tests/FormattedValue.test.js +107 -0
- package/build/tests/ImageRenderer.test.js +78 -0
- package/build/tests/InitialAction.test.js +179 -0
- package/build/tests/InitialStep.test.js +168 -0
- package/build/tests/InstructionsLayout.test.js +45 -0
- package/build/tests/ListLayout.test.js +145 -0
- package/build/tests/Logging.test.js +53 -0
- package/build/tests/ModalBehavior.test.js +149 -0
- package/build/tests/MoneyInput.test.js +316 -0
- package/build/tests/MultiUpload.test.js +293 -0
- package/build/tests/NativeBack.test.js +267 -0
- package/build/tests/OneOfInitialisation.test.js +571 -0
- package/build/tests/PersistAsync.test.js +653 -0
- package/build/tests/Polling.test.js +617 -0
- package/build/tests/Prefetching.test.js +230 -0
- package/build/tests/RefreshAfter.test.js +63 -0
- package/build/tests/RefreshOnChange.ResponseHandling.test.js +205 -0
- package/build/tests/RefreshOnChange.test.js +233 -0
- package/build/tests/RefreshOnChange.with.Segmented.test.js +348 -0
- package/build/tests/RefreshOnChange.with.Tabs.test.js +358 -0
- package/build/tests/RefreshOnChangePreserve.test.js +224 -0
- package/build/tests/RendererProps.test.js +342 -0
- package/build/tests/Repeatable.test.js +107 -0
- package/build/tests/Rerendering.test.js +67 -0
- package/build/tests/ReviewLayout.test.js +274 -0
- package/build/tests/SchemaOnChange.test.js +133 -0
- package/build/tests/ScrollToError.test.js +217 -0
- package/build/tests/SegmentedControl.test.js +49 -0
- package/build/tests/SingleFileUpload.test.js +88 -0
- package/build/tests/StatusList.test.js +85 -0
- package/build/tests/Subflow.test.js +710 -0
- package/build/tests/Submission.ResponseHandling.test.js +557 -0
- package/build/tests/Submission.merging.test.js +202 -0
- package/build/tests/Submission.test.js +523 -0
- package/build/tests/Tags.test.js +475 -0
- package/build/tests/Upsell.test.js +126 -0
- package/build/tests/ValidationAsync.test.js +295 -0
- package/build/tests/legacy/Actions.test.js +158 -0
- package/build/tests/legacy/BackButton.test.js +114 -0
- package/build/tests/legacy/HiddenSchemas.test.js +246 -0
- package/build/tests/legacy/MultiSelect.test.js +497 -0
- package/build/tests/legacy/MultipleFileUploadSchema.test.js +341 -0
- package/build/tests/legacy/PersistAsync.blob-schema.test.js +224 -0
- package/build/tests/legacy/PersistAsync.string-schema.test.js +211 -0
- package/build/tests/legacy/RefreshStepOnChange.debouncing.test.js +209 -0
- package/build/tests/legacy/RefreshStepOnChange.test.js +424 -0
- package/build/tests/legacy/Search.test.js +437 -0
- package/build/tests/renderers/MultiSelectInputRendererProps.test.js +58 -0
- package/build/tests/renderers/SelectInputRendererProps.test.js +42 -0
- package/build/tests/renderers/TextInputRenderer.test.js +51 -0
- package/build/types/domain/components/UpsellComponent.d.ts +2 -3
- package/build/types/domain/components/UpsellComponent.d.ts.map +1 -1
- package/build/types/domain/components/searchComponent/SearchComponent.d.ts +5 -4
- package/build/types/domain/components/searchComponent/SearchComponent.d.ts.map +1 -1
- package/build/types/domain/features/search/getPerformSearchFunction.d.ts +1 -1
- package/build/types/domain/features/search/getPerformSearchFunction.d.ts.map +1 -1
- package/build/types/domain/mappers/layout/searchLayoutToComponent.d.ts +2 -1
- package/build/types/domain/mappers/layout/searchLayoutToComponent.d.ts.map +1 -1
- package/build/types/domain/mappers/layout/upsellLayoutToComponent.d.ts +1 -1
- package/build/types/domain/mappers/layout/upsellLayoutToComponent.d.ts.map +1 -1
- package/build/types/renderers/EmptyLoadingStateRenderer.d.ts +3 -0
- package/build/types/renderers/EmptyLoadingStateRenderer.d.ts.map +1 -0
- package/build/types/renderers/mappers/rootComponentToProps.d.ts.map +1 -1
- package/build/types/renderers/mappers/searchComponentToProps.d.ts +1 -1
- package/build/types/renderers/mappers/searchComponentToProps.d.ts.map +1 -1
- package/build/types/renderers/mappers/upsellComponentToProps.d.ts +2 -2
- package/build/types/renderers/mappers/upsellComponentToProps.d.ts.map +1 -1
- package/build/types/test-utils/getMergedTestRenderers.d.ts +1 -1
- package/build/types/test-utils/getMergedTestRenderers.d.ts.map +1 -1
- package/build/types/useDynamicFlow.d.ts.map +1 -1
- package/build/types.js +1 -0
- package/build/useDynamicFlow.js +104 -0
- package/build/useDynamicFlowModal.js +58 -0
- package/build/utils/analyse-step.js +14 -0
- package/build/utils/component-utils.js +8 -0
- package/build/utils/component-utils.test.js +113 -0
- package/build/utils/getScrollToTop.js +12 -0
- package/build/utils/normalise-flow-id.js +1 -0
- package/build/utils/normalise-flow-id.test.js +24 -0
- package/build/utils/openLinkInNewTab.js +10 -0
- package/build/utils/recursiveMerge.js +40 -0
- package/build/utils/recursiveMerge.test.js +93 -0
- package/build/utils/type-utils.js +21 -0
- package/build/utils/type-validators.js +11 -0
- package/build/utils/type-validators.test.js +180 -0
- package/build/utils/useStableCallback.js +15 -0
- package/package.json +4 -4
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
var __rest = (this && this.__rest) || function (s, e) {
|
|
2
|
+
var t = {};
|
|
3
|
+
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
|
|
4
|
+
t[p] = s[p];
|
|
5
|
+
if (s != null && typeof Object.getOwnPropertySymbols === "function")
|
|
6
|
+
for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
|
|
7
|
+
if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
|
|
8
|
+
t[p[i]] = s[p[i]];
|
|
9
|
+
}
|
|
10
|
+
return t;
|
|
11
|
+
};
|
|
12
|
+
import { getLocalValues, getSubmittableData, getSubmittableDataSync, } from '../../../utils/component-utils';
|
|
13
|
+
import { getInputUpdateFunction } from '../utils/component-utils';
|
|
14
|
+
export const createStepComponent = (stepProps) => {
|
|
15
|
+
const { uid, stepPolling, stepRefreshAfter, stepPrefetch, onComponentUpdate } = stepProps, rest = __rest(stepProps, ["uid", "stepPolling", "stepRefreshAfter", "stepPrefetch", "onComponentUpdate"]);
|
|
16
|
+
const update = getInputUpdateFunction(onComponentUpdate);
|
|
17
|
+
const component = Object.assign(Object.assign({ uid }, rest), { type: 'step', kind: 'step', modals: [], requestCache: stepPrefetch.requestCache, dismissModal() {
|
|
18
|
+
var _a;
|
|
19
|
+
(_a = this.modals.at(-1)) === null || _a === void 0 ? void 0 : _a.close();
|
|
20
|
+
},
|
|
21
|
+
dismissAllModals() {
|
|
22
|
+
this._update((draft) => {
|
|
23
|
+
draft.modals = draft.modals.map((m) => (Object.assign(Object.assign({}, m), { open: false })));
|
|
24
|
+
});
|
|
25
|
+
},
|
|
26
|
+
showModal(modal) {
|
|
27
|
+
this._update((draft) => {
|
|
28
|
+
draft.modals = [...draft.modals, modal];
|
|
29
|
+
});
|
|
30
|
+
},
|
|
31
|
+
_update(updateFn) {
|
|
32
|
+
update(this, updateFn);
|
|
33
|
+
},
|
|
34
|
+
getChildren() {
|
|
35
|
+
return this.externalConfirmation
|
|
36
|
+
? [...this.layoutComponents, this.externalConfirmation]
|
|
37
|
+
: this.layoutComponents;
|
|
38
|
+
},
|
|
39
|
+
getModals() {
|
|
40
|
+
return this.modals;
|
|
41
|
+
},
|
|
42
|
+
async getSubmittableValue() {
|
|
43
|
+
return getSubmittableData(this.schemaComponents);
|
|
44
|
+
},
|
|
45
|
+
getSubmittableValueSync() {
|
|
46
|
+
return getSubmittableDataSync(this.schemaComponents);
|
|
47
|
+
},
|
|
48
|
+
getLocalValue() {
|
|
49
|
+
return getLocalValues(this.schemaComponents);
|
|
50
|
+
},
|
|
51
|
+
validate() {
|
|
52
|
+
return this.schemaComponents.every((inputComponent) => inputComponent.isSchemaReferencedInStep ? inputComponent.validate() : true);
|
|
53
|
+
},
|
|
54
|
+
setLoadingState(loadingState) {
|
|
55
|
+
this._update((draft) => {
|
|
56
|
+
draft.loadingState = loadingState;
|
|
57
|
+
});
|
|
58
|
+
},
|
|
59
|
+
start() {
|
|
60
|
+
stepPolling === null || stepPolling === void 0 ? void 0 : stepPolling.start();
|
|
61
|
+
stepRefreshAfter === null || stepRefreshAfter === void 0 ? void 0 : stepRefreshAfter.start();
|
|
62
|
+
stepPrefetch.start(this.getSubmittableValueSync());
|
|
63
|
+
},
|
|
64
|
+
stop() {
|
|
65
|
+
stepPolling === null || stepPolling === void 0 ? void 0 : stepPolling.stop();
|
|
66
|
+
stepRefreshAfter === null || stepRefreshAfter === void 0 ? void 0 : stepRefreshAfter.stop();
|
|
67
|
+
stepPrefetch.stop();
|
|
68
|
+
this._update((draft) => {
|
|
69
|
+
draft.modals = [];
|
|
70
|
+
});
|
|
71
|
+
} });
|
|
72
|
+
return component;
|
|
73
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Helper function to update a component.
|
|
3
|
+
*
|
|
4
|
+
* @param onComponentUpdate the function that will notify the view layer that something has changed in the domain layer
|
|
5
|
+
* @returns a function that can be used to update components without the linter shouting at us.
|
|
6
|
+
*/
|
|
7
|
+
export const getInputUpdateFunction = (onComponentUpdate) => {
|
|
8
|
+
return (component, updateFn) => {
|
|
9
|
+
updateFn(component);
|
|
10
|
+
onComponentUpdate();
|
|
11
|
+
};
|
|
12
|
+
};
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
export const debounce = (callback, waitMs) => {
|
|
2
|
+
let timeoutId = null;
|
|
3
|
+
let lastArgs = null;
|
|
4
|
+
const clearTimer = () => {
|
|
5
|
+
if (timeoutId) {
|
|
6
|
+
clearTimeout(timeoutId);
|
|
7
|
+
timeoutId = null;
|
|
8
|
+
}
|
|
9
|
+
lastArgs = null;
|
|
10
|
+
};
|
|
11
|
+
const debouncedFn = (...args) => {
|
|
12
|
+
lastArgs = args;
|
|
13
|
+
if (timeoutId !== null) {
|
|
14
|
+
clearTimeout(timeoutId);
|
|
15
|
+
}
|
|
16
|
+
timeoutId = setTimeout(() => {
|
|
17
|
+
callback(...lastArgs);
|
|
18
|
+
timeoutId = null;
|
|
19
|
+
lastArgs = null;
|
|
20
|
+
}, waitMs);
|
|
21
|
+
};
|
|
22
|
+
debouncedFn.cancel = () => {
|
|
23
|
+
if (timeoutId !== null) {
|
|
24
|
+
clearTimer();
|
|
25
|
+
}
|
|
26
|
+
};
|
|
27
|
+
debouncedFn.flush = () => {
|
|
28
|
+
if (timeoutId !== null) {
|
|
29
|
+
callback(...lastArgs);
|
|
30
|
+
clearTimer();
|
|
31
|
+
}
|
|
32
|
+
};
|
|
33
|
+
return debouncedFn;
|
|
34
|
+
};
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import { vi } from 'vitest';
|
|
2
|
+
import { debounce } from './debounce';
|
|
3
|
+
describe('debounce', () => {
|
|
4
|
+
it('will delay function execution until the wait period has passed', () => {
|
|
5
|
+
const fn = vi.fn();
|
|
6
|
+
const debouncedFn = debounce(fn, 5);
|
|
7
|
+
debouncedFn();
|
|
8
|
+
expect(fn).toHaveBeenCalledTimes(0);
|
|
9
|
+
vi.advanceTimersByTime(5);
|
|
10
|
+
expect(fn).toHaveBeenCalledTimes(1);
|
|
11
|
+
});
|
|
12
|
+
it('will call function with provided arguments', () => {
|
|
13
|
+
const fn = vi.fn();
|
|
14
|
+
const debouncedFn = debounce(fn, 5);
|
|
15
|
+
debouncedFn('a', 'b', 'c');
|
|
16
|
+
vi.advanceTimersByTime(5);
|
|
17
|
+
expect(fn).toHaveBeenCalledTimes(1);
|
|
18
|
+
expect(fn).toHaveBeenCalledWith('a', 'b', 'c');
|
|
19
|
+
});
|
|
20
|
+
it('will reset the wait period and ignore previous executions if called within the wait period', () => {
|
|
21
|
+
const fn = vi.fn();
|
|
22
|
+
const debouncedFn = debounce(fn, 5);
|
|
23
|
+
debouncedFn(1, 2, 3);
|
|
24
|
+
vi.advanceTimersByTime(4);
|
|
25
|
+
debouncedFn('a', 'b', 'c');
|
|
26
|
+
vi.advanceTimersByTime(5);
|
|
27
|
+
expect(fn).toHaveBeenCalledTimes(1);
|
|
28
|
+
expect(fn).toHaveBeenCalledWith('a', 'b', 'c');
|
|
29
|
+
});
|
|
30
|
+
it('will call the same function twice if invoked after the wait period', () => {
|
|
31
|
+
const fn = vi.fn();
|
|
32
|
+
const debouncedFn = debounce(fn, 5);
|
|
33
|
+
debouncedFn();
|
|
34
|
+
vi.advanceTimersByTime(5);
|
|
35
|
+
debouncedFn();
|
|
36
|
+
vi.advanceTimersByTime(5);
|
|
37
|
+
expect(fn).toHaveBeenCalledTimes(2);
|
|
38
|
+
});
|
|
39
|
+
describe('flush', () => {
|
|
40
|
+
it('will call the callback immediately', () => {
|
|
41
|
+
const fn = vi.fn();
|
|
42
|
+
const debouncedFn = debounce(fn, 5);
|
|
43
|
+
debouncedFn();
|
|
44
|
+
debouncedFn.flush();
|
|
45
|
+
expect(fn).toHaveBeenCalledTimes(1);
|
|
46
|
+
});
|
|
47
|
+
it('uses the last passed args', () => {
|
|
48
|
+
const fn = vi.fn();
|
|
49
|
+
const debouncedFn = debounce(fn, 5);
|
|
50
|
+
debouncedFn(1, 2, 3);
|
|
51
|
+
debouncedFn('a', 'b', 'c');
|
|
52
|
+
debouncedFn.flush();
|
|
53
|
+
expect(fn).toHaveBeenCalledTimes(1);
|
|
54
|
+
expect(fn).toHaveBeenCalledWith('a', 'b', 'c');
|
|
55
|
+
});
|
|
56
|
+
});
|
|
57
|
+
describe('cancel', () => {
|
|
58
|
+
it('cancels any waiting callback', () => {
|
|
59
|
+
const fn = vi.fn();
|
|
60
|
+
const debouncedFn = debounce(fn, 5);
|
|
61
|
+
debouncedFn();
|
|
62
|
+
debouncedFn.cancel();
|
|
63
|
+
vi.advanceTimersByTime(5);
|
|
64
|
+
expect(fn).toHaveBeenCalledTimes(0);
|
|
65
|
+
});
|
|
66
|
+
});
|
|
67
|
+
});
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
export const toBase64 = async (file) => new Promise((resolve, reject) => {
|
|
2
|
+
const reader = new FileReader();
|
|
3
|
+
reader.addEventListener('load', () => resolve(reader.result));
|
|
4
|
+
reader.addEventListener('error', reject);
|
|
5
|
+
reader.readAsDataURL(file);
|
|
6
|
+
});
|
|
7
|
+
export const base64dataUrltoFile = (dataurl, filename) => {
|
|
8
|
+
if (!isBase64DataUrl(dataurl)) {
|
|
9
|
+
return null;
|
|
10
|
+
}
|
|
11
|
+
const [, base64data] = dataurl.split(',');
|
|
12
|
+
return new File([base64ToBytes(base64data)], filename, { type: getMimeType(dataurl) });
|
|
13
|
+
};
|
|
14
|
+
const isBase64DataUrl = (dataurl) => dataurl.startsWith('data:') && dataurl.includes('base64') && dataurl.includes(',');
|
|
15
|
+
const getMimeType = (base64dataUrl) => base64dataUrl.substring('data:'.length).split(';')[0];
|
|
16
|
+
const base64ToBytes = (base64) => {
|
|
17
|
+
const charCodes = atob(base64)
|
|
18
|
+
.split('')
|
|
19
|
+
.map((m) => m.charCodeAt(0));
|
|
20
|
+
return Uint8Array.from(charCodes);
|
|
21
|
+
};
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/* eslint-disable @typescript-eslint/no-non-null-assertion */
|
|
2
|
+
import { base64dataUrltoFile, toBase64 } from './file-utils';
|
|
3
|
+
describe('toBase64', () => {
|
|
4
|
+
describe('given a valid file', () => {
|
|
5
|
+
it('should return a base64 string', async () => {
|
|
6
|
+
const file = new File(['hello'], 'test.txt', { type: 'text/plain' });
|
|
7
|
+
await expect(toBase64(file)).resolves.toBe('data:text/plain;base64,aGVsbG8=');
|
|
8
|
+
});
|
|
9
|
+
});
|
|
10
|
+
});
|
|
11
|
+
describe('dataURLtoFile', () => {
|
|
12
|
+
describe('given a valid data URL', () => {
|
|
13
|
+
const dataurl = 'data:text/plain;base64,aGVsbG8=';
|
|
14
|
+
it('should return a file that can be encoded back to the given string', async () => {
|
|
15
|
+
const file = base64dataUrltoFile(dataurl, 'test.txt');
|
|
16
|
+
expect(file).toBeInstanceOf(File);
|
|
17
|
+
expect(file.type).toBe('text/plain');
|
|
18
|
+
expect(file.name).toBe('test.txt');
|
|
19
|
+
await expect(toBase64(file)).resolves.toBe(dataurl);
|
|
20
|
+
});
|
|
21
|
+
});
|
|
22
|
+
describe('given an invalid data URL', () => {
|
|
23
|
+
it('should return null', () => {
|
|
24
|
+
expect(base64dataUrltoFile('invalid', 'test.txt')).toBeNull();
|
|
25
|
+
});
|
|
26
|
+
});
|
|
27
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export const getRandomId = () => Math.random().toString(36).substring(2);
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { isArrayLocalValue, isObjectLocalValue } from '../../../utils/type-utils';
|
|
2
|
+
export const isExactLocalValueMatch = (valueA, valueB) => {
|
|
3
|
+
if (isArrayLocalValue(valueA) && isArrayLocalValue(valueB)) {
|
|
4
|
+
return (valueA.length === valueB.length &&
|
|
5
|
+
valueA.every((value, index) => isExactLocalValueMatch(value, valueB[index])));
|
|
6
|
+
}
|
|
7
|
+
if (isObjectLocalValue(valueA) && isObjectLocalValue(valueB)) {
|
|
8
|
+
const keysA = Object.keys(valueA);
|
|
9
|
+
const keysB = Object.keys(valueB);
|
|
10
|
+
return (keysA.length === keysB.length &&
|
|
11
|
+
keysA.every((key) => isExactLocalValueMatch(valueA[key], valueB[key])));
|
|
12
|
+
}
|
|
13
|
+
return valueA === valueB;
|
|
14
|
+
};
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { isArrayModel, isObjectModel } from '../../../utils/type-utils';
|
|
2
|
+
import { isNullish } from '../../../utils/type-validators';
|
|
3
|
+
export const isPartialModelMatch = (localModel, incomingModel) => {
|
|
4
|
+
if (isArrayModel(localModel) && isArrayModel(incomingModel)) {
|
|
5
|
+
return (localModel.length === incomingModel.length &&
|
|
6
|
+
localModel.every((value, index) => isPartialModelMatch(value, incomingModel[index])));
|
|
7
|
+
}
|
|
8
|
+
if (isObjectModel(localModel) && isObjectModel(incomingModel)) {
|
|
9
|
+
if (Object.keys(localModel).length === 0 && Object.keys(incomingModel).length === 0) {
|
|
10
|
+
return true;
|
|
11
|
+
}
|
|
12
|
+
const nonNullishKeysInBoth = nonNullishKeys(localModel).filter((key) => nonNullishKeys(incomingModel).includes(key));
|
|
13
|
+
return (nonNullishKeysInBoth.length > 0 &&
|
|
14
|
+
nonNullishKeysInBoth.every((key) => isPartialModelMatch(localModel[key], incomingModel[key])));
|
|
15
|
+
}
|
|
16
|
+
return localModel === incomingModel;
|
|
17
|
+
};
|
|
18
|
+
const nonNullishKeys = (model) => Object.keys(model).filter((key) => !isNullish(model[key]));
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import { isPartialModelMatch } from './isPartialModelMatch';
|
|
2
|
+
describe('isPartialModelMatch', () => {
|
|
3
|
+
describe('when both models are arrays', () => {
|
|
4
|
+
it('will return true if both models are empty', () => {
|
|
5
|
+
expect(isPartialModelMatch([], [])).toBe(true);
|
|
6
|
+
});
|
|
7
|
+
it('will return false if the models have different lengths', () => {
|
|
8
|
+
expect(isPartialModelMatch([1], [1, 2])).toBe(false);
|
|
9
|
+
expect(isPartialModelMatch([1, 2], [1])).toBe(false);
|
|
10
|
+
});
|
|
11
|
+
it('will return false if any of the items in the array do not partially match', () => {
|
|
12
|
+
expect(isPartialModelMatch([1], [2])).toBe(false);
|
|
13
|
+
expect(isPartialModelMatch([[1]], [[2]])).toBe(false);
|
|
14
|
+
expect(isPartialModelMatch([{ prop: 'value' }], [{ prop: 'different value' }])).toBe(false);
|
|
15
|
+
});
|
|
16
|
+
it('will return true if all items in the arrays partially match', () => {
|
|
17
|
+
expect(isPartialModelMatch([1], [1])).toBe(true);
|
|
18
|
+
});
|
|
19
|
+
});
|
|
20
|
+
describe('when both models are objects', () => {
|
|
21
|
+
it('wil return true if both localModel and incomingModel are empty', () => {
|
|
22
|
+
expect(isPartialModelMatch({}, {})).toBe(true);
|
|
23
|
+
});
|
|
24
|
+
it('will return false if localModel is empty', () => {
|
|
25
|
+
expect(isPartialModelMatch({}, { prop: 1 })).toBe(false);
|
|
26
|
+
});
|
|
27
|
+
it('will return false if incomingModel is empty', () => {
|
|
28
|
+
expect(isPartialModelMatch({ prop: 1 }, {})).toBe(false);
|
|
29
|
+
});
|
|
30
|
+
it('will return false if the models have matching keys with different values', () => {
|
|
31
|
+
expect(isPartialModelMatch({ key: 1 }, { key: 2 })).toBe(false);
|
|
32
|
+
expect(isPartialModelMatch({ key: 2 }, { key: 1 })).toBe(false);
|
|
33
|
+
});
|
|
34
|
+
it('will return true if matching keys have the same value', () => {
|
|
35
|
+
expect(isPartialModelMatch({ key: 1 }, { key: 1 })).toBe(true);
|
|
36
|
+
});
|
|
37
|
+
it('will ignore the value of non-matching keys', () => {
|
|
38
|
+
expect(isPartialModelMatch({ matchingKey: 1 }, { matchingKey: 1, otherKey: 2 })).toBe(true);
|
|
39
|
+
expect(isPartialModelMatch({ otherKey: 2, matchingKey: 1 }, { matchingKey: 1 })).toBe(true);
|
|
40
|
+
});
|
|
41
|
+
it('will ignore the value of nullish keys', () => {
|
|
42
|
+
expect(isPartialModelMatch({ matchingKey: 1, otherKey: 2 }, { matchingKey: 1, otherKey: null })).toBe(true);
|
|
43
|
+
expect(isPartialModelMatch({ otherKey: null, matchingKey: 1 }, { matchingKey: 1, otherKey: 2 })).toBe(true);
|
|
44
|
+
expect(isPartialModelMatch({ matchingKey: 1, otherKey: null }, { matchingKey: 1 })).toBe(true);
|
|
45
|
+
expect(isPartialModelMatch({ matchingKey: 1 }, { matchingKey: 1, otherKey: null })).toBe(true);
|
|
46
|
+
});
|
|
47
|
+
it('looks for matches recursively', () => {
|
|
48
|
+
expect(isPartialModelMatch({ matchingKey: [{ matchingKey: 2 }] }, { matchingKey: [{ matchingKey: 2 }] })).toBe(true);
|
|
49
|
+
expect(isPartialModelMatch({ matchingKey: [{ matchingKey: 2 }] }, { matchingKey: [{ matchingKey: 3 }] })).toBe(false);
|
|
50
|
+
});
|
|
51
|
+
});
|
|
52
|
+
describe('when both models are matching primitives', () => {
|
|
53
|
+
it('will return true if the models are equal', () => {
|
|
54
|
+
expect(isPartialModelMatch(1, 1)).toBe(true);
|
|
55
|
+
expect(isPartialModelMatch('value', 'value')).toBe(true);
|
|
56
|
+
expect(isPartialModelMatch(true, true)).toBe(true);
|
|
57
|
+
});
|
|
58
|
+
it('will return false if the models are not equal', () => {
|
|
59
|
+
expect(isPartialModelMatch(1, 2)).toBe(false);
|
|
60
|
+
expect(isPartialModelMatch('value', 'different value')).toBe(false);
|
|
61
|
+
expect(isPartialModelMatch(true, false)).toBe(false);
|
|
62
|
+
});
|
|
63
|
+
});
|
|
64
|
+
describe('when models are of different types', () => {
|
|
65
|
+
it('will always return false', () => {
|
|
66
|
+
expect(isPartialModelMatch(null, 1)).toBe(false);
|
|
67
|
+
expect(isPartialModelMatch(1, null)).toBe(false);
|
|
68
|
+
expect(isPartialModelMatch({}, [])).toBe(false);
|
|
69
|
+
expect(isPartialModelMatch([], {})).toBe(false);
|
|
70
|
+
expect(isPartialModelMatch(1, {})).toBe(false);
|
|
71
|
+
expect(isPartialModelMatch({}, 1)).toBe(false);
|
|
72
|
+
});
|
|
73
|
+
});
|
|
74
|
+
});
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
export const eventNames = [
|
|
2
|
+
'Initiated',
|
|
3
|
+
'Succeeded',
|
|
4
|
+
'Failed',
|
|
5
|
+
'Cancelled',
|
|
6
|
+
'Step Shown',
|
|
7
|
+
'Action Triggered',
|
|
8
|
+
'Action Succeeded',
|
|
9
|
+
'Action Aborted',
|
|
10
|
+
'Action Failed',
|
|
11
|
+
'Refresh Triggered',
|
|
12
|
+
'Refresh Succeeded',
|
|
13
|
+
'Refresh Aborted',
|
|
14
|
+
'Refresh Failed',
|
|
15
|
+
'OneOf Selected',
|
|
16
|
+
'OneOf Option Selected',
|
|
17
|
+
'PersistAsync Triggered',
|
|
18
|
+
'PersistAsync Succeeded',
|
|
19
|
+
'PersistAsync Failed',
|
|
20
|
+
'Polling Failed',
|
|
21
|
+
'ValidationAsync Triggered',
|
|
22
|
+
'ValidationAsync Succeeded',
|
|
23
|
+
'ValidationAsync Failed',
|
|
24
|
+
];
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { isNullish } from '../../../utils/type-validators';
|
|
2
|
+
import { getRandomId } from '../../components/utils/getRandomId';
|
|
3
|
+
/**
|
|
4
|
+
* Creates an onPersistAsync handler for a component.
|
|
5
|
+
*/
|
|
6
|
+
export const getComponentMultiPersistAsync = (update, performPersistAsync) =>
|
|
7
|
+
/**
|
|
8
|
+
* Will update the persistedState when a new request is made, and will update
|
|
9
|
+
* the value or set errors when the request completes.
|
|
10
|
+
*/
|
|
11
|
+
async (component, index, value) => {
|
|
12
|
+
if (isNullish(value)) {
|
|
13
|
+
throw new Error('Value must be a file or base64 string.');
|
|
14
|
+
}
|
|
15
|
+
const newAbortController = new AbortController();
|
|
16
|
+
const { signal } = newAbortController;
|
|
17
|
+
const newSubmission = performPersistAsync({ value, signal })
|
|
18
|
+
.then((newValue) => {
|
|
19
|
+
update(component, (draft) => {
|
|
20
|
+
draft.persistedState[index].lastResponse = newValue;
|
|
21
|
+
});
|
|
22
|
+
return newValue;
|
|
23
|
+
})
|
|
24
|
+
.catch((error) => {
|
|
25
|
+
update(component, (draft) => {
|
|
26
|
+
// The file was not persisted, so delete it
|
|
27
|
+
draft.persistedState = [
|
|
28
|
+
...draft.persistedState.slice(0, index),
|
|
29
|
+
...draft.persistedState.slice(index + 1),
|
|
30
|
+
];
|
|
31
|
+
draft.value.splice(index, 1);
|
|
32
|
+
draft.files.splice(index, 1);
|
|
33
|
+
});
|
|
34
|
+
throw error;
|
|
35
|
+
});
|
|
36
|
+
update(component, (draft) => {
|
|
37
|
+
draft.persistedState = [
|
|
38
|
+
...draft.persistedState.slice(0, index),
|
|
39
|
+
{
|
|
40
|
+
id: getRandomId(),
|
|
41
|
+
abortController: newAbortController,
|
|
42
|
+
lastResponse: null,
|
|
43
|
+
lastSubmitted: null,
|
|
44
|
+
submission: newSubmission,
|
|
45
|
+
},
|
|
46
|
+
...draft.persistedState.slice(index),
|
|
47
|
+
];
|
|
48
|
+
});
|
|
49
|
+
return newSubmission;
|
|
50
|
+
};
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { isNullish } from '../../../utils/type-validators';
|
|
2
|
+
export const getInitialPersistedState = (lastSubmitted, model) => ({
|
|
3
|
+
abortController: new AbortController(),
|
|
4
|
+
lastSubmitted: !isNullish(model) ? (lastSubmitted !== null && lastSubmitted !== void 0 ? lastSubmitted : null) : null,
|
|
5
|
+
lastResponse: model !== null && model !== void 0 ? model : null,
|
|
6
|
+
submission: Promise.resolve(model !== null && model !== void 0 ? model : null),
|
|
7
|
+
});
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { isObject, isString } from '../../../utils/type-validators';
|
|
2
|
+
import { constructPayload } from '../utils/http-utils';
|
|
3
|
+
import { getAnalyticsFromErrorResponse } from '../utils/response-utils';
|
|
4
|
+
/**
|
|
5
|
+
* Takes an httpClient and schema persist async config and returns a function that can
|
|
6
|
+
* execute a persist async request.
|
|
7
|
+
*/
|
|
8
|
+
export const getPerformPersistAsync = ({ genericErrorMessage, httpClient, persistAsyncConfig, schemaId, logEvent, trackEvent, }) => {
|
|
9
|
+
const { idProperty, param, method, url } = persistAsyncConfig;
|
|
10
|
+
const trackFailure = (json) => {
|
|
11
|
+
const analytics = getAnalyticsFromErrorResponse(json);
|
|
12
|
+
trackEvent('PersistAsync Failed', Object.assign({ schema: schemaId }, analytics));
|
|
13
|
+
};
|
|
14
|
+
return async function performPersistAsync({ value, signal }) {
|
|
15
|
+
let response;
|
|
16
|
+
let json;
|
|
17
|
+
try {
|
|
18
|
+
trackEvent('PersistAsync Triggered', { schema: schemaId });
|
|
19
|
+
response = await httpClient(url, constructPayload({ value, signal, requestConfig: { method, param } }));
|
|
20
|
+
json = (await response.json());
|
|
21
|
+
if (response.ok && isObject(json)) {
|
|
22
|
+
trackEvent('PersistAsync Succeeded', { schema: schemaId });
|
|
23
|
+
if (json[idProperty] === undefined) {
|
|
24
|
+
logEvent('error', `Response from persist async did not contain expected property ${idProperty}.`);
|
|
25
|
+
throw new Error(genericErrorMessage);
|
|
26
|
+
}
|
|
27
|
+
return json[idProperty];
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
catch (_a) {
|
|
31
|
+
trackFailure();
|
|
32
|
+
throw new Error(genericErrorMessage);
|
|
33
|
+
}
|
|
34
|
+
const validationError = !response.ok && isObject(json) ? getValidationError(param, json) : null;
|
|
35
|
+
trackFailure(json);
|
|
36
|
+
throw new Error(validationError !== null && validationError !== void 0 ? validationError : genericErrorMessage);
|
|
37
|
+
};
|
|
38
|
+
};
|
|
39
|
+
const getValidationError = (param, response) => {
|
|
40
|
+
var _a;
|
|
41
|
+
const message = (_a = response.validation) === null || _a === void 0 ? void 0 : _a[param];
|
|
42
|
+
return isString(message) ? message : null;
|
|
43
|
+
};
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
import { vi } from 'vitest';
|
|
2
|
+
import { getMockHttpClient, respondWith } from '../../../test-utils';
|
|
3
|
+
import { getPerformPersistAsync } from './getPerformPersistAsync';
|
|
4
|
+
describe('getPerformPersistAsync', () => {
|
|
5
|
+
const genericErrorMessage = 'Error';
|
|
6
|
+
const trackEvent = vi.fn();
|
|
7
|
+
const logEvent = vi.fn();
|
|
8
|
+
const signal = {};
|
|
9
|
+
const persistAsyncConfig = {
|
|
10
|
+
idProperty: 'id',
|
|
11
|
+
method: 'POST',
|
|
12
|
+
param: 'param',
|
|
13
|
+
url: '/persist',
|
|
14
|
+
};
|
|
15
|
+
it('should make the request using the specified parameter', async () => {
|
|
16
|
+
const spyHttpClient = vi.fn().mockResolvedValue(respondWith({ id: 1 }));
|
|
17
|
+
const spyTrackEvent = vi.fn();
|
|
18
|
+
const performPersistAsync = getPerformPersistAsync({
|
|
19
|
+
httpClient: spyHttpClient,
|
|
20
|
+
trackEvent: spyTrackEvent,
|
|
21
|
+
logEvent,
|
|
22
|
+
persistAsyncConfig,
|
|
23
|
+
genericErrorMessage,
|
|
24
|
+
schemaId: 'schemaId',
|
|
25
|
+
});
|
|
26
|
+
await performPersistAsync({ value: 'value', signal });
|
|
27
|
+
expect(spyHttpClient).toHaveBeenCalledWith('/persist', {
|
|
28
|
+
body: '{"param":"value"}',
|
|
29
|
+
headers: { 'Content-Type': 'application/json' },
|
|
30
|
+
method: 'POST',
|
|
31
|
+
signal,
|
|
32
|
+
});
|
|
33
|
+
expect(spyTrackEvent).toHaveBeenCalledWith('PersistAsync Triggered', expect.objectContaining({ schema: 'schemaId' }));
|
|
34
|
+
});
|
|
35
|
+
it('should wrap blobs in form data before submitting', async () => {
|
|
36
|
+
const spyHttpClient = vi.fn().mockResolvedValue(respondWith({ id: 1 }));
|
|
37
|
+
const performPersistAsync = getPerformPersistAsync({
|
|
38
|
+
httpClient: spyHttpClient,
|
|
39
|
+
trackEvent,
|
|
40
|
+
logEvent,
|
|
41
|
+
persistAsyncConfig,
|
|
42
|
+
genericErrorMessage,
|
|
43
|
+
});
|
|
44
|
+
const file = new File(['file'], 'file.txt');
|
|
45
|
+
await performPersistAsync({ value: file, signal });
|
|
46
|
+
expect(spyHttpClient).toHaveBeenCalledWith('/persist', {
|
|
47
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
|
|
48
|
+
body: expect.any(FormData),
|
|
49
|
+
headers: {},
|
|
50
|
+
method: 'POST',
|
|
51
|
+
signal,
|
|
52
|
+
});
|
|
53
|
+
});
|
|
54
|
+
describe('when the response is ok', () => {
|
|
55
|
+
it('should read response value from idProperty', async () => {
|
|
56
|
+
const httpClient = getMockHttpClient({
|
|
57
|
+
'/persist': async () => respondWith({ id: 1 }),
|
|
58
|
+
});
|
|
59
|
+
const spyTrackEvent = vi.fn();
|
|
60
|
+
const performPersistAsync = getPerformPersistAsync({
|
|
61
|
+
httpClient,
|
|
62
|
+
trackEvent: spyTrackEvent,
|
|
63
|
+
logEvent,
|
|
64
|
+
persistAsyncConfig,
|
|
65
|
+
genericErrorMessage,
|
|
66
|
+
schemaId: 'schemaId',
|
|
67
|
+
});
|
|
68
|
+
const result = await performPersistAsync({ value: 'value', signal });
|
|
69
|
+
expect(result).toBe(1);
|
|
70
|
+
expect(spyTrackEvent).toHaveBeenLastCalledWith('PersistAsync Succeeded', expect.objectContaining({ schema: 'schemaId' }));
|
|
71
|
+
});
|
|
72
|
+
it('should throw a generic error if the response is not an object', async () => {
|
|
73
|
+
const httpClient = getMockHttpClient({
|
|
74
|
+
'/persist': async () => respondWith(1),
|
|
75
|
+
});
|
|
76
|
+
const spyTrackEvent = vi.fn();
|
|
77
|
+
const performPersistAsync = getPerformPersistAsync({
|
|
78
|
+
httpClient,
|
|
79
|
+
trackEvent: spyTrackEvent,
|
|
80
|
+
logEvent,
|
|
81
|
+
persistAsyncConfig,
|
|
82
|
+
genericErrorMessage,
|
|
83
|
+
schemaId: 'schemaId',
|
|
84
|
+
});
|
|
85
|
+
await expect(performPersistAsync({ value: 'value', signal })).rejects.toThrow(genericErrorMessage);
|
|
86
|
+
expect(spyTrackEvent).toHaveBeenLastCalledWith('PersistAsync Failed', expect.objectContaining({ schema: 'schemaId' }));
|
|
87
|
+
});
|
|
88
|
+
});
|
|
89
|
+
describe.each([[401], [422], [504]])('when the response is %s', (errorStatusCode) => {
|
|
90
|
+
it('should throw if the response includes a validation message', async () => {
|
|
91
|
+
const httpClient = getMockHttpClient({
|
|
92
|
+
'/persist': async () => respondWith({ validation: { param: 'error with this field' } }, { status: errorStatusCode }),
|
|
93
|
+
});
|
|
94
|
+
const spyTrackEvent = vi.fn();
|
|
95
|
+
const performPersistAsync = getPerformPersistAsync({
|
|
96
|
+
httpClient,
|
|
97
|
+
trackEvent: spyTrackEvent,
|
|
98
|
+
logEvent,
|
|
99
|
+
persistAsyncConfig,
|
|
100
|
+
genericErrorMessage,
|
|
101
|
+
schemaId: 'schemaId',
|
|
102
|
+
});
|
|
103
|
+
await expect(performPersistAsync({ value: 'value', signal })).rejects.toThrow('error with this field');
|
|
104
|
+
expect(spyTrackEvent).toHaveBeenLastCalledWith('PersistAsync Failed', expect.objectContaining({ schema: 'schemaId' }));
|
|
105
|
+
});
|
|
106
|
+
it('should include analytics if passed', async () => {
|
|
107
|
+
const httpClient = getMockHttpClient({
|
|
108
|
+
'/persist': async () => respondWith({ validation: { param: 'error with this field' }, analytics: { some: 'extras' } }, { status: errorStatusCode }),
|
|
109
|
+
});
|
|
110
|
+
const spyTrackEvent = vi.fn();
|
|
111
|
+
const performPersistAsync = getPerformPersistAsync({
|
|
112
|
+
httpClient,
|
|
113
|
+
trackEvent: spyTrackEvent,
|
|
114
|
+
logEvent,
|
|
115
|
+
persistAsyncConfig,
|
|
116
|
+
genericErrorMessage,
|
|
117
|
+
schemaId: 'schemaId',
|
|
118
|
+
});
|
|
119
|
+
await expect(performPersistAsync({ value: 'value', signal })).rejects.toThrow('error with this field');
|
|
120
|
+
expect(spyTrackEvent).toHaveBeenLastCalledWith('PersistAsync Failed', expect.objectContaining({ schema: 'schemaId', some: 'extras' }));
|
|
121
|
+
});
|
|
122
|
+
});
|
|
123
|
+
it('should throw a generic error if request fails', async () => {
|
|
124
|
+
const httpClient = getMockHttpClient({
|
|
125
|
+
'/persist': async () => Promise.reject(new Error()),
|
|
126
|
+
});
|
|
127
|
+
const spyTrackEvent = vi.fn();
|
|
128
|
+
const performPersistAsync = getPerformPersistAsync({
|
|
129
|
+
httpClient,
|
|
130
|
+
trackEvent: spyTrackEvent,
|
|
131
|
+
logEvent,
|
|
132
|
+
persistAsyncConfig,
|
|
133
|
+
genericErrorMessage,
|
|
134
|
+
schemaId: 'schemaId',
|
|
135
|
+
});
|
|
136
|
+
await expect(performPersistAsync({ value: 'value', signal })).rejects.toThrow(genericErrorMessage);
|
|
137
|
+
expect(spyTrackEvent).toHaveBeenLastCalledWith('PersistAsync Failed', expect.objectContaining({ schema: 'schemaId' }));
|
|
138
|
+
});
|
|
139
|
+
});
|