@qoretechnologies/reqraft 0.10.62 → 0.10.63-pr.142.g0b675cd
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +21 -1
- package/dist/components/Description/describedControl.d.ts +48 -0
- package/dist/components/Description/describedControl.d.ts.map +1 -0
- package/dist/components/Description/describedControl.js +81 -0
- package/dist/components/Description/describedControl.js.map +1 -0
- package/dist/components/Description/index.d.ts.map +1 -1
- package/dist/components/Description/index.js +3 -2
- package/dist/components/Description/index.js.map +1 -1
- package/dist/components/colorValue/colorValue.d.ts +59 -0
- package/dist/components/colorValue/colorValue.d.ts.map +1 -0
- package/dist/components/colorValue/colorValue.js +245 -0
- package/dist/components/colorValue/colorValue.js.map +1 -0
- package/dist/components/colorValue/index.d.ts +34 -0
- package/dist/components/colorValue/index.d.ts.map +1 -0
- package/dist/components/colorValue/index.js +136 -0
- package/dist/components/colorValue/index.js.map +1 -0
- package/dist/components/colorValue/labels.d.ts +12 -0
- package/dist/components/colorValue/labels.d.ts.map +1 -0
- package/dist/components/colorValue/labels.js +11 -0
- package/dist/components/colorValue/labels.js.map +1 -0
- package/dist/components/composer/Composer.d.ts +1 -1
- package/dist/components/composer/Composer.d.ts.map +1 -1
- package/dist/components/composer/Composer.js +2 -2
- package/dist/components/composer/Composer.js.map +1 -1
- package/dist/components/dpqlEditor/DpqlEditor.d.ts.map +1 -1
- package/dist/components/dpqlEditor/DpqlEditor.js +25 -5
- package/dist/components/dpqlEditor/DpqlEditor.js.map +1 -1
- package/dist/components/dpqlEditor/dpqlHelpers.d.ts +10 -1
- package/dist/components/dpqlEditor/dpqlHelpers.d.ts.map +1 -1
- package/dist/components/dpqlEditor/dpqlHelpers.js +30 -13
- package/dist/components/dpqlEditor/dpqlHelpers.js.map +1 -1
- package/dist/components/dpqlEditor/dpqlTags.d.ts +11 -7
- package/dist/components/dpqlEditor/dpqlTags.d.ts.map +1 -1
- package/dist/components/dpqlEditor/dpqlTags.js +11 -6
- package/dist/components/dpqlEditor/dpqlTags.js.map +1 -1
- package/dist/components/dpqlEditor/types.d.ts +47 -8
- package/dist/components/dpqlEditor/types.d.ts.map +1 -1
- package/dist/components/dpqlEditor/useDpqlSession.d.ts +2 -2
- package/dist/components/dpqlEditor/useDpqlSession.d.ts.map +1 -1
- package/dist/components/dpqlEditor/useDpqlSession.js +16 -7
- package/dist/components/dpqlEditor/useDpqlSession.js.map +1 -1
- package/dist/components/form/engine/CompactRow.d.ts.map +1 -1
- package/dist/components/form/engine/CompactRow.js +151 -83
- package/dist/components/form/engine/CompactRow.js.map +1 -1
- package/dist/components/form/engine/CompactToolbar.d.ts.map +1 -1
- package/dist/components/form/engine/CompactToolbar.js +29 -3
- package/dist/components/form/engine/CompactToolbar.js.map +1 -1
- package/dist/components/form/engine/FormEngine.d.ts +34 -1
- package/dist/components/form/engine/FormEngine.d.ts.map +1 -1
- package/dist/components/form/engine/FormEngine.js +487 -87
- package/dist/components/form/engine/FormEngine.js.map +1 -1
- package/dist/components/form/engine/HiddenFieldsNote.d.ts +28 -0
- package/dist/components/form/engine/HiddenFieldsNote.d.ts.map +1 -0
- package/dist/components/form/engine/HiddenFieldsNote.js +32 -0
- package/dist/components/form/engine/HiddenFieldsNote.js.map +1 -0
- package/dist/components/form/engine/OptionFieldMessages.d.ts.map +1 -1
- package/dist/components/form/engine/OptionFieldMessages.js +24 -3
- package/dist/components/form/engine/OptionFieldMessages.js.map +1 -1
- package/dist/components/form/engine/_structuredData/SchemaDataView.d.ts +2 -2
- package/dist/components/form/engine/_structuredData/SchemaDataView.d.ts.map +1 -1
- package/dist/components/form/engine/_structuredData/SchemaDataView.js +12 -6
- package/dist/components/form/engine/_structuredData/SchemaDataView.js.map +1 -1
- package/dist/components/form/engine/compactRowContext.d.ts +19 -0
- package/dist/components/form/engine/compactRowContext.d.ts.map +1 -1
- package/dist/components/form/engine/compactRowContext.js.map +1 -1
- package/dist/components/form/engine/compactRowStyles.d.ts +0 -1
- package/dist/components/form/engine/compactRowStyles.d.ts.map +1 -1
- package/dist/components/form/engine/compactRowStyles.js +12 -20
- package/dist/components/form/engine/compactRowStyles.js.map +1 -1
- package/dist/components/form/engine/compactToolbarColors.d.ts +16 -0
- package/dist/components/form/engine/compactToolbarColors.d.ts.map +1 -0
- package/dist/components/form/engine/compactToolbarColors.js +21 -0
- package/dist/components/form/engine/compactToolbarColors.js.map +1 -0
- package/dist/components/form/engine/readFirst.d.ts +24 -8
- package/dist/components/form/engine/readFirst.d.ts.map +1 -1
- package/dist/components/form/engine/readFirst.js +77 -109
- package/dist/components/form/engine/readFirst.js.map +1 -1
- package/dist/components/form/engine/readFirstColors.d.ts +30 -0
- package/dist/components/form/engine/readFirstColors.d.ts.map +1 -0
- package/dist/components/form/engine/readFirstColors.js +51 -0
- package/dist/components/form/engine/readFirstColors.js.map +1 -0
- package/dist/components/form/engine/rowFocus.d.ts +2 -0
- package/dist/components/form/engine/rowFocus.d.ts.map +1 -1
- package/dist/components/form/engine/rowFocus.js +26 -3
- package/dist/components/form/engine/rowFocus.js.map +1 -1
- package/dist/components/form/engine/typeChoices.d.ts +1 -1
- package/dist/components/form/engine/variants/VariantCalmTable.d.ts.map +1 -1
- package/dist/components/form/engine/variants/VariantCalmTable.js +2 -1
- package/dist/components/form/engine/variants/VariantCalmTable.js.map +1 -1
- package/dist/components/form/engine/variants/VariantCards.d.ts.map +1 -1
- package/dist/components/form/engine/variants/VariantCards.js +2 -1
- package/dist/components/form/engine/variants/VariantCards.js.map +1 -1
- package/dist/components/form/engine/variants/VariantFocus.js +1 -1
- package/dist/components/form/engine/variants/VariantFocus.js.map +1 -1
- package/dist/components/form/engine/variants/VariantMinimal.d.ts.map +1 -1
- package/dist/components/form/engine/variants/VariantMinimal.js +2 -1
- package/dist/components/form/engine/variants/VariantMinimal.js.map +1 -1
- package/dist/components/form/engine/variants/variantParts.d.ts +1 -1
- package/dist/components/form/engine/variants/variantParts.d.ts.map +1 -1
- package/dist/components/form/engine/variants/variantParts.js +25 -17
- package/dist/components/form/engine/variants/variantParts.js.map +1 -1
- package/dist/components/form/expressions/DpqlRendering.d.ts +1 -1
- package/dist/components/form/expressions/DpqlRendering.d.ts.map +1 -1
- package/dist/components/form/expressions/DpqlRendering.js +3 -3
- package/dist/components/form/expressions/DpqlRendering.js.map +1 -1
- package/dist/components/form/expressions/ExpressionField.d.ts +41 -3
- package/dist/components/form/expressions/ExpressionField.d.ts.map +1 -1
- package/dist/components/form/expressions/ExpressionField.js +396 -99
- package/dist/components/form/expressions/ExpressionField.js.map +1 -1
- package/dist/components/form/expressions/builder/argumentDetail.d.ts.map +1 -1
- package/dist/components/form/expressions/builder/argumentDetail.js +4 -1
- package/dist/components/form/expressions/builder/argumentDetail.js.map +1 -1
- package/dist/components/form/expressions/builder/argumentLabel.d.ts.map +1 -1
- package/dist/components/form/expressions/builder/argumentLabel.js +27 -9
- package/dist/components/form/expressions/builder/argumentLabel.js.map +1 -1
- package/dist/components/form/expressions/builder/argumentWrapper.d.ts.map +1 -1
- package/dist/components/form/expressions/builder/argumentWrapper.js +4 -2
- package/dist/components/form/expressions/builder/argumentWrapper.js.map +1 -1
- package/dist/components/form/expressions/builder/confirmMismatchedTypesModal.d.ts.map +1 -1
- package/dist/components/form/expressions/builder/confirmMismatchedTypesModal.js +5 -4
- package/dist/components/form/expressions/builder/confirmMismatchedTypesModal.js.map +1 -1
- package/dist/components/form/expressions/builder/confirmUnsupportedTypeModal.d.ts +1 -1
- package/dist/components/form/expressions/builder/confirmUnsupportedTypeModal.d.ts.map +1 -1
- package/dist/components/form/expressions/builder/confirmUnsupportedTypeModal.js +6 -3
- package/dist/components/form/expressions/builder/confirmUnsupportedTypeModal.js.map +1 -1
- package/dist/components/form/expressions/builder/index.d.ts +24 -2
- package/dist/components/form/expressions/builder/index.d.ts.map +1 -1
- package/dist/components/form/expressions/builder/index.js +121 -77
- package/dist/components/form/expressions/builder/index.js.map +1 -1
- package/dist/components/form/expressions/builder/item.d.ts +6 -2
- package/dist/components/form/expressions/builder/item.d.ts.map +1 -1
- package/dist/components/form/expressions/builder/item.js +19 -5
- package/dist/components/form/expressions/builder/item.js.map +1 -1
- package/dist/components/form/expressions/builder/renderTemplate.js +1 -1
- package/dist/components/form/expressions/builder/renderTemplate.js.map +1 -1
- package/dist/components/form/expressions/expressionOperands.d.ts +16 -0
- package/dist/components/form/expressions/expressionOperands.d.ts.map +1 -0
- package/dist/components/form/expressions/expressionOperands.js +97 -0
- package/dist/components/form/expressions/expressionOperands.js.map +1 -0
- package/dist/components/form/expressions/mockExpressions.d.ts.map +1 -1
- package/dist/components/form/expressions/mockExpressions.js +22 -5
- package/dist/components/form/expressions/mockExpressions.js.map +1 -1
- package/dist/components/form/expressions/renderExpressionToText.d.ts +2 -0
- package/dist/components/form/expressions/renderExpressionToText.d.ts.map +1 -1
- package/dist/components/form/expressions/renderExpressionToText.js +35 -9
- package/dist/components/form/expressions/renderExpressionToText.js.map +1 -1
- package/dist/components/form/expressions/textOfExpression.d.ts +18 -0
- package/dist/components/form/expressions/textOfExpression.d.ts.map +1 -0
- package/dist/components/form/expressions/textOfExpression.js +37 -0
- package/dist/components/form/expressions/textOfExpression.js.map +1 -0
- package/dist/components/form/expressions/useExpressionType.d.ts +26 -0
- package/dist/components/form/expressions/useExpressionType.d.ts.map +1 -0
- package/dist/components/form/expressions/useExpressionType.js +181 -0
- package/dist/components/form/expressions/useExpressionType.js.map +1 -0
- package/dist/components/form/expressions/useRenderExpression.d.ts.map +1 -1
- package/dist/components/form/expressions/useRenderExpression.js +7 -7
- package/dist/components/form/expressions/useRenderExpression.js.map +1 -1
- package/dist/components/form/fields/Field.d.ts.map +1 -1
- package/dist/components/form/fields/Field.js +20 -7
- package/dist/components/form/fields/Field.js.map +1 -1
- package/dist/components/form/fields/allowed-values/AllowedValues.d.ts.map +1 -1
- package/dist/components/form/fields/allowed-values/AllowedValues.js +17 -4
- package/dist/components/form/fields/allowed-values/AllowedValues.js.map +1 -1
- package/dist/components/form/fields/array/ArrayAuto.d.ts.map +1 -1
- package/dist/components/form/fields/array/ArrayAuto.js +24 -0
- package/dist/components/form/fields/array/ArrayAuto.js.map +1 -1
- package/dist/components/form/fields/array/ArrayAutoField.d.ts.map +1 -1
- package/dist/components/form/fields/array/ArrayAutoField.js +36 -13
- package/dist/components/form/fields/array/ArrayAutoField.js.map +1 -1
- package/dist/components/form/fields/auto/AutoFormField.d.ts +20 -1
- package/dist/components/form/fields/auto/AutoFormField.d.ts.map +1 -1
- package/dist/components/form/fields/auto/AutoFormField.js +81 -36
- package/dist/components/form/fields/auto/AutoFormField.js.map +1 -1
- package/dist/components/form/fields/auto/hostEditorValue.d.ts +30 -0
- package/dist/components/form/fields/auto/hostEditorValue.d.ts.map +1 -0
- package/dist/components/form/fields/auto/hostEditorValue.js +53 -0
- package/dist/components/form/fields/auto/hostEditorValue.js.map +1 -0
- package/dist/components/form/fields/binary/Binary.d.ts.map +1 -1
- package/dist/components/form/fields/binary/Binary.js +23 -3
- package/dist/components/form/fields/binary/Binary.js.map +1 -1
- package/dist/components/form/fields/boolean/Boolean.d.ts +5 -0
- package/dist/components/form/fields/boolean/Boolean.d.ts.map +1 -1
- package/dist/components/form/fields/boolean/Boolean.js +9 -1
- package/dist/components/form/fields/boolean/Boolean.js.map +1 -1
- package/dist/components/form/fields/color/Color.d.ts +103 -16
- package/dist/components/form/fields/color/Color.d.ts.map +1 -1
- package/dist/components/form/fields/color/Color.js +611 -16
- package/dist/components/form/fields/color/Color.js.map +1 -1
- package/dist/components/form/fields/emittedValues.d.ts +34 -3
- package/dist/components/form/fields/emittedValues.d.ts.map +1 -1
- package/dist/components/form/fields/emittedValues.js +24 -1
- package/dist/components/form/fields/emittedValues.js.map +1 -1
- package/dist/components/form/fields/file/File.d.ts +1 -1
- package/dist/components/form/fields/file/File.d.ts.map +1 -1
- package/dist/components/form/fields/file/File.js +4 -2
- package/dist/components/form/fields/file/File.js.map +1 -1
- package/dist/components/form/fields/long-string/LongString.d.ts.map +1 -1
- package/dist/components/form/fields/long-string/LongString.js +17 -3
- package/dist/components/form/fields/long-string/LongString.js.map +1 -1
- package/dist/components/form/fields/markdown/MarkdownView.js +1 -1
- package/dist/components/form/fields/multi-select/MultiSelectFormField.d.ts.map +1 -1
- package/dist/components/form/fields/multi-select/MultiSelectFormField.js +4 -1
- package/dist/components/form/fields/multi-select/MultiSelectFormField.js.map +1 -1
- package/dist/components/form/fields/number/Number.d.ts +6 -0
- package/dist/components/form/fields/number/Number.d.ts.map +1 -1
- package/dist/components/form/fields/number/Number.js +41 -6
- package/dist/components/form/fields/number/Number.js.map +1 -1
- package/dist/components/form/fields/object/Object.d.ts +1 -1
- package/dist/components/form/fields/object/Object.d.ts.map +1 -1
- package/dist/components/form/fields/object/Object.js +4 -2
- package/dist/components/form/fields/object/Object.js.map +1 -1
- package/dist/components/form/fields/pendingEdit.d.ts +52 -0
- package/dist/components/form/fields/pendingEdit.d.ts.map +1 -0
- package/dist/components/form/fields/pendingEdit.js +79 -0
- package/dist/components/form/fields/pendingEdit.js.map +1 -0
- package/dist/components/form/fields/rich-text/RichText.d.ts +8 -1
- package/dist/components/form/fields/rich-text/RichText.d.ts.map +1 -1
- package/dist/components/form/fields/rich-text/RichText.js +190 -81
- package/dist/components/form/fields/rich-text/RichText.js.map +1 -1
- package/dist/components/form/fields/rich-text/useTemplateTags.d.ts +18 -0
- package/dist/components/form/fields/rich-text/useTemplateTags.d.ts.map +1 -0
- package/dist/components/form/fields/rich-text/useTemplateTags.js +49 -0
- package/dist/components/form/fields/rich-text/useTemplateTags.js.map +1 -0
- package/dist/components/form/fields/schema-definition/CatalogLeafForm.d.ts.map +1 -1
- package/dist/components/form/fields/schema-definition/CatalogLeafForm.js +4 -1
- package/dist/components/form/fields/schema-definition/CatalogLeafForm.js.map +1 -1
- package/dist/components/form/fields/schema-definition/CatalogNodeEditor.d.ts.map +1 -1
- package/dist/components/form/fields/schema-definition/CatalogNodeEditor.js +20 -5
- package/dist/components/form/fields/schema-definition/CatalogNodeEditor.js.map +1 -1
- package/dist/components/form/fields/schema-definition/TableEditor.d.ts.map +1 -1
- package/dist/components/form/fields/schema-definition/TableEditor.js +10 -2
- package/dist/components/form/fields/schema-definition/TableEditor.js.map +1 -1
- package/dist/components/form/fields/schema-definition/index.d.ts.map +1 -1
- package/dist/components/form/fields/schema-definition/index.js +8 -4
- package/dist/components/form/fields/schema-definition/index.js.map +1 -1
- package/dist/components/form/fields/select/Select.d.ts +2 -0
- package/dist/components/form/fields/select/Select.d.ts.map +1 -1
- package/dist/components/form/fields/select/Select.js +19 -10
- package/dist/components/form/fields/select/Select.js.map +1 -1
- package/dist/components/form/fields/select/SelectCollection.d.ts.map +1 -1
- package/dist/components/form/fields/select/SelectCollection.js +8 -2
- package/dist/components/form/fields/select/SelectCollection.js.map +1 -1
- package/dist/components/form/fields/select/unavailableRow.d.ts +23 -0
- package/dist/components/form/fields/select/unavailableRow.d.ts.map +1 -0
- package/dist/components/form/fields/select/unavailableRow.js +55 -0
- package/dist/components/form/fields/select/unavailableRow.js.map +1 -0
- package/dist/components/form/fields/template/ReadOnlyTemplateTag.d.ts +5 -5
- package/dist/components/form/fields/template/ReadOnlyTemplateTag.d.ts.map +1 -1
- package/dist/components/form/fields/template/ReadOnlyTemplateTag.js +11 -4
- package/dist/components/form/fields/template/ReadOnlyTemplateTag.js.map +1 -1
- package/dist/components/form/fields/template/TemplateBrowser.d.ts +22 -0
- package/dist/components/form/fields/template/TemplateBrowser.d.ts.map +1 -0
- package/dist/components/form/fields/template/TemplateBrowser.js +54 -0
- package/dist/components/form/fields/template/TemplateBrowser.js.map +1 -0
- package/dist/components/form/fields/template/TemplateField.d.ts +83 -1
- package/dist/components/form/fields/template/TemplateField.d.ts.map +1 -1
- package/dist/components/form/fields/template/TemplateField.js +535 -85
- package/dist/components/form/fields/template/TemplateField.js.map +1 -1
- package/dist/components/form/fields/template/TemplateText.d.ts +0 -17
- package/dist/components/form/fields/template/TemplateText.d.ts.map +1 -1
- package/dist/components/form/fields/template/TemplateText.js +8 -4
- package/dist/components/form/fields/template/TemplateText.js.map +1 -1
- package/dist/components/form/fields/template/writtenAsText.d.ts +55 -0
- package/dist/components/form/fields/template/writtenAsText.d.ts.map +1 -0
- package/dist/components/form/fields/template/writtenAsText.js +188 -0
- package/dist/components/form/fields/template/writtenAsText.js.map +1 -0
- package/dist/components/form/index.d.ts +10 -0
- package/dist/components/form/index.d.ts.map +1 -1
- package/dist/components/form/index.js +23 -1
- package/dist/components/form/index.js.map +1 -1
- package/dist/components/imageLightbox/ImageLightbox.d.ts.map +1 -1
- package/dist/components/imageLightbox/ImageLightbox.js +19 -7
- package/dist/components/imageLightbox/ImageLightbox.js.map +1 -1
- package/dist/components/log/Log.d.ts.map +1 -1
- package/dist/components/log/Log.js +15 -7
- package/dist/components/log/Log.js.map +1 -1
- package/dist/components/menu/Menu.d.ts.map +1 -1
- package/dist/components/menu/Menu.js +19 -10
- package/dist/components/menu/Menu.js.map +1 -1
- package/dist/components/smartEditor/CompletionMenu.d.ts +43 -0
- package/dist/components/smartEditor/CompletionMenu.d.ts.map +1 -0
- package/dist/components/smartEditor/CompletionMenu.js +196 -0
- package/dist/components/smartEditor/CompletionMenu.js.map +1 -0
- package/dist/components/smartEditor/MarkdownDoc.d.ts +1 -1
- package/dist/components/smartEditor/MarkdownDoc.js +1 -1
- package/dist/components/smartEditor/MarkdownDoc.js.map +1 -1
- package/dist/components/smartEditor/SmartEditor.d.ts.map +1 -1
- package/dist/components/smartEditor/SmartEditor.js +51 -136
- package/dist/components/smartEditor/SmartEditor.js.map +1 -1
- package/dist/components/smartEditor/completionStyle.d.ts +27 -0
- package/dist/components/smartEditor/completionStyle.d.ts.map +1 -0
- package/dist/components/smartEditor/completionStyle.js +66 -0
- package/dist/components/smartEditor/completionStyle.js.map +1 -0
- package/dist/components/smartEditor/index.d.ts +5 -1
- package/dist/components/smartEditor/index.d.ts.map +1 -1
- package/dist/components/smartEditor/index.js +19 -1
- package/dist/components/smartEditor/index.js.map +1 -1
- package/dist/components/smartEditor/templateCompletions.d.ts +18 -0
- package/dist/components/smartEditor/templateCompletions.d.ts.map +1 -0
- package/dist/components/smartEditor/templateCompletions.js +94 -0
- package/dist/components/smartEditor/templateCompletions.js.map +1 -0
- package/dist/components/smartEditor/types.d.ts +12 -1
- package/dist/components/smartEditor/types.d.ts.map +1 -1
- package/dist/components/smartEditor/useLspAutocomplete.d.ts +32 -0
- package/dist/components/smartEditor/useLspAutocomplete.d.ts.map +1 -1
- package/dist/components/smartEditor/useLspAutocomplete.js +228 -118
- package/dist/components/smartEditor/useLspAutocomplete.js.map +1 -1
- package/dist/components/smartEditor/useLspHover.d.ts +22 -7
- package/dist/components/smartEditor/useLspHover.d.ts.map +1 -1
- package/dist/components/smartEditor/useLspHover.js +86 -17
- package/dist/components/smartEditor/useLspHover.js.map +1 -1
- package/dist/components/smartEditor/useLspSemanticTokens.js +1 -1
- package/dist/components/smartEditor/useLspSemanticTokens.js.map +1 -1
- package/dist/components/smartEditor/useLspSession.d.ts +6 -0
- package/dist/components/smartEditor/useLspSession.d.ts.map +1 -1
- package/dist/components/smartEditor/useLspSession.js +7 -6
- package/dist/components/smartEditor/useLspSession.js.map +1 -1
- package/dist/components/supportTicket/AttachmentChips.d.ts.map +1 -1
- package/dist/components/supportTicket/AttachmentChips.js +15 -5
- package/dist/components/supportTicket/AttachmentChips.js.map +1 -1
- package/dist/components/supportTicket/ReferencePicker.d.ts +9 -2
- package/dist/components/supportTicket/ReferencePicker.d.ts.map +1 -1
- package/dist/components/supportTicket/ReferencePicker.js +27 -6
- package/dist/components/supportTicket/ReferencePicker.js.map +1 -1
- package/dist/components/supportTicket/TicketHeader.d.ts +3 -4
- package/dist/components/supportTicket/TicketHeader.d.ts.map +1 -1
- package/dist/components/supportTicket/TicketHeader.js +20 -2
- package/dist/components/supportTicket/TicketHeader.js.map +1 -1
- package/dist/components/supportTicket/TicketMetaTags.d.ts +1 -1
- package/dist/components/ticketReferences/TicketReferences.d.ts.map +1 -1
- package/dist/components/ticketReferences/TicketReferences.js +9 -4
- package/dist/components/ticketReferences/TicketReferences.js.map +1 -1
- package/dist/components/ticketThread/TicketThread.d.ts.map +1 -1
- package/dist/components/ticketThread/TicketThread.js +36 -11
- package/dist/components/ticketThread/TicketThread.js.map +1 -1
- package/dist/helpers/descriptionTooltip.d.ts +43 -0
- package/dist/helpers/descriptionTooltip.d.ts.map +1 -0
- package/dist/helpers/descriptionTooltip.js +70 -0
- package/dist/helpers/descriptionTooltip.js.map +1 -0
- package/dist/helpers/domProps.d.ts +5 -0
- package/dist/helpers/domProps.d.ts.map +1 -0
- package/dist/helpers/domProps.js +47 -0
- package/dist/helpers/domProps.js.map +1 -0
- package/dist/helpers/expressions.d.ts +107 -2
- package/dist/helpers/expressions.d.ts.map +1 -1
- package/dist/helpers/expressions.js +223 -8
- package/dist/helpers/expressions.js.map +1 -1
- package/dist/helpers/hoveringPointer.d.ts +26 -0
- package/dist/helpers/hoveringPointer.d.ts.map +1 -0
- package/dist/helpers/hoveringPointer.js +29 -0
- package/dist/helpers/hoveringPointer.js.map +1 -0
- package/dist/helpers/markdownText.d.ts +14 -0
- package/dist/helpers/markdownText.d.ts.map +1 -0
- package/dist/helpers/markdownText.js +160 -0
- package/dist/helpers/markdownText.js.map +1 -0
- package/dist/helpers/qorusTypeCatalogue.d.ts +53 -0
- package/dist/helpers/qorusTypeCatalogue.d.ts.map +1 -0
- package/dist/helpers/qorusTypeCatalogue.js +262 -0
- package/dist/helpers/qorusTypeCatalogue.js.map +1 -0
- package/dist/helpers/readableColors.d.ts +36 -0
- package/dist/helpers/readableColors.d.ts.map +1 -0
- package/dist/helpers/readableColors.js +116 -0
- package/dist/helpers/readableColors.js.map +1 -0
- package/dist/helpers/templateItems.d.ts +2 -2
- package/dist/helpers/templateItems.d.ts.map +1 -1
- package/dist/helpers/templateItems.js +6 -4
- package/dist/helpers/templateItems.js.map +1 -1
- package/dist/helpers/templates.d.ts +26 -1
- package/dist/helpers/templates.d.ts.map +1 -1
- package/dist/helpers/templates.js +41 -6
- package/dist/helpers/templates.js.map +1 -1
- package/dist/helpers/validations.d.ts +9 -0
- package/dist/helpers/validations.d.ts.map +1 -1
- package/dist/helpers/validations.js +139 -33
- package/dist/helpers/validations.js.map +1 -1
- package/dist/hooks/useQorusTypes.d.ts +7 -15
- package/dist/hooks/useQorusTypes.d.ts.map +1 -1
- package/dist/hooks/useQorusTypes.js +25 -166
- package/dist/hooks/useQorusTypes.js.map +1 -1
- package/dist/hooks/useReadableIntentShade.d.ts +9 -0
- package/dist/hooks/useReadableIntentShade.d.ts.map +1 -0
- package/dist/hooks/useReadableIntentShade.js +23 -0
- package/dist/hooks/useReadableIntentShade.js.map +1 -0
- package/dist/hooks/useReadableOpacity.d.ts +6 -0
- package/dist/hooks/useReadableOpacity.d.ts.map +1 -0
- package/dist/hooks/useReadableOpacity.js +17 -0
- package/dist/hooks/useReadableOpacity.js.map +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/tracking/ui/ExperimentCard.d.ts +1 -1
- package/dist/tracking/ui/ExperimentCard.d.ts.map +1 -1
- package/dist/tracking/ui/ExperimentCard.js +26 -10
- package/dist/tracking/ui/ExperimentCard.js.map +1 -1
- package/dist/tracking/ui/card.d.ts +2 -2
- package/dist/tracking/ui/card.d.ts.map +1 -1
- package/dist/tracking/ui/card.js +2 -2
- package/dist/tracking/ui/card.js.map +1 -1
- package/dist/tracking/ui/readable.d.ts +14 -0
- package/dist/tracking/ui/readable.d.ts.map +1 -0
- package/dist/tracking/ui/readable.js +60 -0
- package/dist/tracking/ui/readable.js.map +1 -0
- package/package.json +14 -5
- package/.claude/CLAUDE.md +0 -317
- package/.tasks/EXPORT_EXPRESSION_BUILDER.md +0 -38
- package/.tasks/EXPRESSION_BUILDER_REPORT.md +0 -149
- package/.tasks/EXPRESSION_FIELD_SEAMS.md +0 -66
- package/.tasks/FIELD_STACK_REPORT.md +0 -234
- package/.tasks/FORM_ENGINE_COMPACT_READ_FIRST.md +0 -558
- package/.tasks/FORM_ENGINE_EXPRESSIONS.md +0 -197
- package/.tasks/FORM_ENGINE_OPTIONS_SYNC.md +0 -95
- package/.tasks/FORM_FIELD_EXTRAS.md +0 -72
- package/.tasks/INDEX.md +0 -111
- package/.tasks/LSP_SHARED_CONNECTION.md +0 -75
- package/.tasks/QONSOLE_ASSIST_FEATURES.md +0 -306
- package/.tasks/RENDER_EXPRESSION_LSP.md +0 -159
- package/.tasks/REQRAFT_AUTO_FIELD.md +0 -176
- package/.tasks/SCHEMA_DEFINITION_FIELD.md +0 -250
- package/.tasks/SMART_EDITOR_CONTEXT_AND_POLISH.md +0 -340
- package/.tasks/SMART_EDITOR_LSP_FEATURES.md +0 -299
- package/.tasks/SMART_EDITOR_REVIEW_FOLLOWUPS.md +0 -280
- package/.tasks/SMART_EDITOR_UX_POLISH.md +0 -383
- package/.tasks/SMART_EDITOR_VISUAL_POLISH.md +0 -246
- package/.tasks/STORY_NETWORK_ISOLATION.md +0 -98
- package/.tasks/TEMPLATE_TOKEN_GRAMMAR.md +0 -72
- package/CODE_OF_CONDUCT.md +0 -105
- package/CONTRIBUTING.MD +0 -78
- package/SECURITY.md +0 -3
- package/chromatic.config.json +0 -5
- package/design/COMPACT_ENGINE_REDESIGN.md +0 -156
- package/design/COMPACT_INFO_DISPLAY.md +0 -87
- package/design/COMPACT_PARITY.md +0 -85
- package/design/EXPRESSION_BUILDER_REPORT_STRATEGY.md +0 -92
- package/design/FORM_ENGINE_COMPACT.md +0 -300
- package/design/FORM_ENGINE_COMPACT_UX_PLAN.md +0 -353
- package/design/FORM_ENGINE_EXPRESSIONS.md +0 -257
- package/design/FORM_ENGINE_FIELD_MIGRATION.md +0 -419
- package/design/IDE_INTEGRATION.md +0 -64
- package/design/RENDER_EXPRESSION_TRANSPORT.md +0 -156
- package/design/SELECT_DIALOG_FLOOR.md +0 -86
- package/design/SMART_EDITOR_UX.md +0 -438
- package/design/TRACKING.md +0 -290
- package/design/UNAVAILABLE_ALLOWED_VALUES.md +0 -226
- package/src/components/Description/index.tsx +0 -254
- package/src/components/Description/markdownRendererContext.tsx +0 -29
- package/src/components/FocusedEditing/index.tsx +0 -50
- package/src/components/codeSize/index.tsx +0 -79
- package/src/components/composer/Composer.stories.tsx +0 -238
- package/src/components/composer/Composer.tsx +0 -554
- package/src/components/composer/helpers.ts +0 -74
- package/src/components/composer/index.ts +0 -2
- package/src/components/dpqlEditor/DpqlEditor.stories.tsx +0 -1183
- package/src/components/dpqlEditor/DpqlEditor.tsx +0 -219
- package/src/components/dpqlEditor/dpqlHelpers.ts +0 -287
- package/src/components/dpqlEditor/dpqlInserter.ts +0 -121
- package/src/components/dpqlEditor/dpqlProbe.ts +0 -165
- package/src/components/dpqlEditor/dpqlTags.ts +0 -114
- package/src/components/dpqlEditor/index.ts +0 -41
- package/src/components/dpqlEditor/types.ts +0 -203
- package/src/components/dpqlEditor/useDpqlProbe.ts +0 -33
- package/src/components/dpqlEditor/useDpqlSession.ts +0 -411
- package/src/components/form/engine/CompactRow.tsx +0 -2620
- package/src/components/form/engine/CompactToolbar.tsx +0 -330
- package/src/components/form/engine/FormEngine.stories.tsx +0 -9920
- package/src/components/form/engine/FormEngine.tsx +0 -4569
- package/src/components/form/engine/FormEngineRemote.stories.tsx +0 -679
- package/src/components/form/engine/FormEngineStickyHeaders.stories.tsx +0 -331
- package/src/components/form/engine/FormFieldsSkeleton.tsx +0 -82
- package/src/components/form/engine/OptionFieldMessages.tsx +0 -477
- package/src/components/form/engine/OptionsHelpDialog.tsx +0 -29
- package/src/components/form/engine/__fixtures__/basicFormOptions.ts +0 -309
- package/src/components/form/engine/__fixtures__/fieldChromeOptions.ts +0 -45
- package/src/components/form/engine/_structuredData/SchemaDataView.stories.tsx +0 -233
- package/src/components/form/engine/_structuredData/SchemaDataView.tsx +0 -742
- package/src/components/form/engine/_structuredData/StructuredDataView.stories.tsx +0 -85
- package/src/components/form/engine/_structuredData/StructuredDataView.tsx +0 -75
- package/src/components/form/engine/_structuredData/structuredData.ts +0 -145
- package/src/components/form/engine/compactRowContext.ts +0 -148
- package/src/components/form/engine/compactRowStyles.ts +0 -898
- package/src/components/form/engine/compactToolbarContext.ts +0 -69
- package/src/components/form/engine/optionActions.ts +0 -128
- package/src/components/form/engine/optionsContext.ts +0 -24
- package/src/components/form/engine/readFirst.ts +0 -1077
- package/src/components/form/engine/rendererTypes.ts +0 -107
- package/src/components/form/engine/revealRow.ts +0 -123
- package/src/components/form/engine/rowFocus.ts +0 -101
- package/src/components/form/engine/rowMenuContext.ts +0 -159
- package/src/components/form/engine/rowOpenPicker.ts +0 -27
- package/src/components/form/engine/typeChoices.ts +0 -63
- package/src/components/form/engine/variants/FormEngineVariants.stories.tsx +0 -159
- package/src/components/form/engine/variants/VariantCalmTable.tsx +0 -244
- package/src/components/form/engine/variants/VariantCards.tsx +0 -212
- package/src/components/form/engine/variants/VariantFocus.tsx +0 -382
- package/src/components/form/engine/variants/VariantMinimal.tsx +0 -170
- package/src/components/form/engine/variants/focusDemo.ts +0 -145
- package/src/components/form/engine/variants/variantModel.ts +0 -223
- package/src/components/form/engine/variants/variantParts.tsx +0 -313
- package/src/components/form/expressions/DpqlRendering.tsx +0 -85
- package/src/components/form/expressions/ExpressionField.stories.tsx +0 -1395
- package/src/components/form/expressions/ExpressionField.tsx +0 -503
- package/src/components/form/expressions/argumentPresence.ts +0 -213
- package/src/components/form/expressions/builder/ExpressionBuilder.stories.tsx +0 -1683
- package/src/components/form/expressions/builder/argumentDetail.tsx +0 -17
- package/src/components/form/expressions/builder/argumentLabel.tsx +0 -146
- package/src/components/form/expressions/builder/argumentSlot.tsx +0 -101
- package/src/components/form/expressions/builder/argumentWrapper.tsx +0 -243
- package/src/components/form/expressions/builder/confirmMismatchedTypesModal.tsx +0 -120
- package/src/components/form/expressions/builder/confirmUnsupportedTypeModal.tsx +0 -69
- package/src/components/form/expressions/builder/index.tsx +0 -1545
- package/src/components/form/expressions/builder/item.tsx +0 -89
- package/src/components/form/expressions/builder/moveToPositionStrip.tsx +0 -156
- package/src/components/form/expressions/builder/renderTemplate.tsx +0 -42
- package/src/components/form/expressions/dpqlMockLanguage.ts +0 -566
- package/src/components/form/expressions/dpqlMockLsp.ts +0 -126
- package/src/components/form/expressions/mockExpressions.ts +0 -317
- package/src/components/form/expressions/renderExpressionToText.ts +0 -137
- package/src/components/form/expressions/types.ts +0 -110
- package/src/components/form/expressions/useExpressions.ts +0 -101
- package/src/components/form/expressions/useRenderExpression.ts +0 -165
- package/src/components/form/fields/Field.stories.tsx +0 -143
- package/src/components/form/fields/Field.tsx +0 -732
- package/src/components/form/fields/allowed-values/AllowedValues.tsx +0 -297
- package/src/components/form/fields/array/ArrayAuto.tsx +0 -237
- package/src/components/form/fields/array/ArrayAutoField.stories.tsx +0 -475
- package/src/components/form/fields/array/ArrayAutoField.tsx +0 -367
- package/src/components/form/fields/auto/AutoFormField.stories.tsx +0 -825
- package/src/components/form/fields/auto/AutoFormField.tsx +0 -1164
- package/src/components/form/fields/binary/Binary.stories.tsx +0 -122
- package/src/components/form/fields/binary/Binary.tsx +0 -91
- package/src/components/form/fields/boolean/Boolean.stories.tsx +0 -125
- package/src/components/form/fields/boolean/Boolean.tsx +0 -34
- package/src/components/form/fields/byte-size/ByteSize.stories.tsx +0 -87
- package/src/components/form/fields/byte-size/ByteSize.tsx +0 -58
- package/src/components/form/fields/color/Color.stories.tsx +0 -99
- package/src/components/form/fields/color/Color.tsx +0 -46
- package/src/components/form/fields/cron/Cron.stories.tsx +0 -68
- package/src/components/form/fields/cron/Cron.tsx +0 -80
- package/src/components/form/fields/date/Date.stories.tsx +0 -77
- package/src/components/form/fields/date/Date.tsx +0 -55
- package/src/components/form/fields/emittedValues.ts +0 -70
- package/src/components/form/fields/file/File.stories.tsx +0 -161
- package/src/components/form/fields/file/File.tsx +0 -227
- package/src/components/form/fields/long-string/LongString.stories.tsx +0 -120
- package/src/components/form/fields/long-string/LongString.tsx +0 -130
- package/src/components/form/fields/markdown/Markdown.stories.tsx +0 -76
- package/src/components/form/fields/markdown/Markdown.tsx +0 -81
- package/src/components/form/fields/markdown/MarkdownView.tsx +0 -222
- package/src/components/form/fields/multi-select/MultiSelectFormField.tsx +0 -139
- package/src/components/form/fields/number/Number.stories.tsx +0 -159
- package/src/components/form/fields/number/Number.tsx +0 -160
- package/src/components/form/fields/object/Object.stories.tsx +0 -398
- package/src/components/form/fields/object/Object.tsx +0 -255
- package/src/components/form/fields/radio-group/RadioGroup.stories.tsx +0 -95
- package/src/components/form/fields/radio-group/RadioGroup.tsx +0 -46
- package/src/components/form/fields/radio-group/images/java-96x128.png +0 -0
- package/src/components/form/fields/radio-group/images/python-129x128.png +0 -0
- package/src/components/form/fields/radio-group/images/qore-106x128.png +0 -0
- package/src/components/form/fields/rich-text/RichText.stories.tsx +0 -260
- package/src/components/form/fields/rich-text/RichText.tsx +0 -537
- package/src/components/form/fields/schema-definition/CatalogLeafForm.tsx +0 -242
- package/src/components/form/fields/schema-definition/CatalogNodeEditor.tsx +0 -758
- package/src/components/form/fields/schema-definition/Hint.tsx +0 -22
- package/src/components/form/fields/schema-definition/InlineValidationBanner.tsx +0 -138
- package/src/components/form/fields/schema-definition/Loader.tsx +0 -20
- package/src/components/form/fields/schema-definition/MigrationsTab.tsx +0 -187
- package/src/components/form/fields/schema-definition/SchemaDefinitionField.stories.tsx +0 -286
- package/src/components/form/fields/schema-definition/TableEditor.tsx +0 -155
- package/src/components/form/fields/schema-definition/TablesTab.tsx +0 -138
- package/src/components/form/fields/schema-definition/catalog.ts +0 -237
- package/src/components/form/fields/schema-definition/helpers.ts +0 -90
- package/src/components/form/fields/schema-definition/index.tsx +0 -418
- package/src/components/form/fields/schema-definition/mockCatalog.ts +0 -325
- package/src/components/form/fields/schema-definition/mockDefinition.ts +0 -111
- package/src/components/form/fields/schema-definition/referenceSuggestions.tsx +0 -152
- package/src/components/form/fields/schema-definition/starterTemplate.ts +0 -68
- package/src/components/form/fields/schema-definition/types.ts +0 -185
- package/src/components/form/fields/schema-definition/useSchemaOptionCatalog.ts +0 -49
- package/src/components/form/fields/select/Select.stories.tsx +0 -872
- package/src/components/form/fields/select/Select.tsx +0 -624
- package/src/components/form/fields/select/SelectCollection.tsx +0 -594
- package/src/components/form/fields/string/String.stories.tsx +0 -86
- package/src/components/form/fields/string/String.tsx +0 -43
- package/src/components/form/fields/template/ExampleValueModal.stories.tsx +0 -114
- package/src/components/form/fields/template/ExampleValueModal.tsx +0 -99
- package/src/components/form/fields/template/ReadOnlyTemplateTag.tsx +0 -47
- package/src/components/form/fields/template/TemplateField.stories.tsx +0 -1121
- package/src/components/form/fields/template/TemplateField.tsx +0 -1717
- package/src/components/form/fields/template/TemplateText.tsx +0 -115
- package/src/components/form/fields/template/__fixtures__/longExampleValue.ts +0 -7
- package/src/components/form/fields/template/__fixtures__/multiLevelTemplates.json +0 -147
- package/src/components/form/fields/template/__fixtures__/templates.json +0 -83
- package/src/components/form/fields/timeout/Timeout.stories.tsx +0 -228
- package/src/components/form/fields/timeout/Timeout.tsx +0 -87
- package/src/components/form/fields/url/Url.stories.tsx +0 -94
- package/src/components/form/fields/url/Url.tsx +0 -85
- package/src/components/form/index.tsx +0 -47
- package/src/components/imageLightbox/ImageLightbox.stories.tsx +0 -238
- package/src/components/imageLightbox/ImageLightbox.tsx +0 -236
- package/src/components/imageLightbox/index.ts +0 -1
- package/src/components/log/Log.stories.tsx +0 -333
- package/src/components/log/Log.tsx +0 -285
- package/src/components/menu/Menu.stories.tsx +0 -155
- package/src/components/menu/Menu.tsx +0 -312
- package/src/components/qonsoleSmartInput/QonsoleSmartInput.stories.tsx +0 -797
- package/src/components/qonsoleSmartInput/QonsoleSmartInput.tsx +0 -105
- package/src/components/qonsoleSmartInput/index.ts +0 -16
- package/src/components/qonsoleSmartInput/qonsoleInserter.ts +0 -77
- package/src/components/qonsoleSmartInput/types.ts +0 -133
- package/src/components/qonsoleSmartInput/useQonsoleSession.ts +0 -124
- package/src/components/searchFilterBar/SearchFilterBar.stories.tsx +0 -62
- package/src/components/searchFilterBar/SearchFilterBar.tsx +0 -144
- package/src/components/searchFilterBar/index.ts +0 -1
- package/src/components/smartEditor/MarkdownDoc.tsx +0 -190
- package/src/components/smartEditor/SmartEditor.stories.tsx +0 -475
- package/src/components/smartEditor/SmartEditor.tsx +0 -808
- package/src/components/smartEditor/__fixtures__/mockLspServer.ts +0 -205
- package/src/components/smartEditor/helpers.ts +0 -217
- package/src/components/smartEditor/index.ts +0 -35
- package/src/components/smartEditor/styling.ts +0 -45
- package/src/components/smartEditor/types.ts +0 -211
- package/src/components/smartEditor/useLspAutocomplete.ts +0 -758
- package/src/components/smartEditor/useLspDiagnosticDecorations.ts +0 -125
- package/src/components/smartEditor/useLspHover.ts +0 -230
- package/src/components/smartEditor/useLspSemanticTokens.ts +0 -298
- package/src/components/smartEditor/useLspSession.ts +0 -231
- package/src/components/smartEditor/useLspSignatureHelp.ts +0 -198
- package/src/components/supportTicket/AttachmentChips.stories.tsx +0 -171
- package/src/components/supportTicket/AttachmentChips.tsx +0 -147
- package/src/components/supportTicket/InterfaceReferenceTags.stories.tsx +0 -257
- package/src/components/supportTicket/InterfaceReferenceTags.tsx +0 -129
- package/src/components/supportTicket/ReferencePicker.stories.tsx +0 -584
- package/src/components/supportTicket/ReferencePicker.tsx +0 -563
- package/src/components/supportTicket/TicketConversation.stories.tsx +0 -121
- package/src/components/supportTicket/TicketHeader.stories.tsx +0 -183
- package/src/components/supportTicket/TicketHeader.tsx +0 -247
- package/src/components/supportTicket/TicketMetaTags.stories.tsx +0 -103
- package/src/components/supportTicket/TicketMetaTags.tsx +0 -85
- package/src/components/supportTicket/TicketReplyBox.stories.tsx +0 -354
- package/src/components/supportTicket/TicketReplyBox.tsx +0 -150
- package/src/components/supportTicket/__fixtures__/kindMarks.ts +0 -28
- package/src/components/supportTicket/attachmentAccess.ts +0 -97
- package/src/components/supportTicket/fileToAttachment.ts +0 -24
- package/src/components/supportTicket/index.ts +0 -10
- package/src/components/supportTicket/meta.ts +0 -206
- package/src/components/supportTicket/ticketModel.ts +0 -131
- package/src/components/supportTicket/useLoadedImages.ts +0 -73
- package/src/components/ticketReferences/TicketReferences.stories.tsx +0 -315
- package/src/components/ticketReferences/TicketReferences.tsx +0 -906
- package/src/components/ticketReferences/index.ts +0 -2
- package/src/components/ticketThread/TicketThread.stories.tsx +0 -829
- package/src/components/ticketThread/TicketThread.tsx +0 -719
- package/src/components/ticketThread/index.ts +0 -6
- package/src/contexts/FetchContext.tsx +0 -25
- package/src/contexts/ReqraftContext.tsx +0 -9
- package/src/contexts/StorageContext.tsx +0 -33
- package/src/global.d.ts +0 -4
- package/src/helpers/allowedValues.ts +0 -249
- package/src/helpers/choiceChip.ts +0 -227
- package/src/helpers/common.ts +0 -326
- package/src/helpers/dpqlDetection.ts +0 -209
- package/src/helpers/expressions.ts +0 -140
- package/src/helpers/optionUiTypes.ts +0 -199
- package/src/helpers/options.ts +0 -150
- package/src/helpers/providerValue.ts +0 -125
- package/src/helpers/scrollbar.ts +0 -32
- package/src/helpers/singleLineString.ts +0 -61
- package/src/helpers/templateItems.ts +0 -81
- package/src/helpers/templateText.ts +0 -350
- package/src/helpers/templates.ts +0 -602
- package/src/helpers/validations.ts +0 -2085
- package/src/hooks/useArgSchema.ts +0 -37
- package/src/hooks/useCoarsePointer.ts +0 -30
- package/src/hooks/useFetch/useFetch.stories.tsx +0 -379
- package/src/hooks/useFetch/useFetch.tsx +0 -154
- package/src/hooks/usePhoneViewport.ts +0 -34
- package/src/hooks/useQorusTypes.ts +0 -233
- package/src/hooks/useReqraftProperty.ts +0 -16
- package/src/hooks/useStorage/useStorage.stories.tsx +0 -168
- package/src/hooks/useStorage/useStorage.ts +0 -35
- package/src/hooks/useTemplates.ts +0 -123
- package/src/hooks/useValidation.ts +0 -9
- package/src/hooks/useWebSocket/useWebSocket.ts +0 -224
- package/src/hooks/useWebSocket/useWebsocket.stories.tsx +0 -640
- package/src/hooks/useWhyDidYouUpdate.ts +0 -38
- package/src/index.tsx +0 -86
- package/src/providers/FetchProvider.tsx +0 -40
- package/src/providers/ReqraftProvider.tsx +0 -52
- package/src/providers/StorageProvider.tsx +0 -131
- package/src/stores/currentUser/currentUser.stories.tsx +0 -100
- package/src/stores/currentUser/currentUser.tsx +0 -94
- package/src/stories/Data/fileFieldArgSchema.json +0 -86
- package/src/stories/Tests/utils.ts +0 -320
- package/src/stories/storyNetwork.ts +0 -92
- package/src/stories/tracking.tsx +0 -206
- package/src/tracking/browser/attach.ts +0 -186
- package/src/tracking/browser/env.ts +0 -78
- package/src/tracking/core/consent.ts +0 -37
- package/src/tracking/core/engagement.ts +0 -47
- package/src/tracking/core/experiments.ts +0 -258
- package/src/tracking/core/hash.ts +0 -26
- package/src/tracking/core/ids.ts +0 -25
- package/src/tracking/core/observable.ts +0 -23
- package/src/tracking/core/queue.ts +0 -131
- package/src/tracking/core/sections.ts +0 -166
- package/src/tracking/core/storage.ts +0 -69
- package/src/tracking/core/tracker.ts +0 -417
- package/src/tracking/core/types.ts +0 -162
- package/src/tracking/core/utm.ts +0 -23
- package/src/tracking/index.ts +0 -72
- package/src/tracking/markup.ts +0 -17
- package/src/tracking/react/Experiment.tsx +0 -44
- package/src/tracking/react/TrackingProvider.tsx +0 -56
- package/src/tracking/react/hooks.ts +0 -106
- package/src/tracking/react/index.ts +0 -13
- package/src/tracking/testing.ts +0 -108
- package/src/tracking/ui/ExperimentCard.stories.tsx +0 -296
- package/src/tracking/ui/ExperimentCard.tsx +0 -667
- package/src/tracking/ui/ExperimentsOverlay.stories.tsx +0 -155
- package/src/tracking/ui/ExperimentsOverlay.tsx +0 -437
- package/src/tracking/ui/anchor.ts +0 -180
- package/src/tracking/ui/card.ts +0 -464
- package/src/tracking/ui/client.ts +0 -117
- package/src/tracking/ui/index.ts +0 -77
- package/src/tracking/ui/types.ts +0 -110
- package/src/tracking/ui/useExperimentsAdmin.ts +0 -103
- package/src/types/Form.ts +0 -29
- package/src/types.ts +0 -14
- package/src/utils/datetime.ts +0 -10
- package/src/utils/fetch.ts +0 -457
- package/src/utils/lspClient.ts +0 -711
- package/src/utils/lspClient.types.ts +0 -211
- package/src/utils/queryUnlessCancelled.ts +0 -28
- package/src/utils/websocket.ts +0 -293
- package/vite.config.ts +0 -58
- package/vitest.config.ts +0 -69
|
@@ -1,2085 +0,0 @@
|
|
|
1
|
-
import { isValidSixCharHex } from '@qoretechnologies/reqore/dist/helpers/colors';
|
|
2
|
-
import { IQorusFormSchema, TQorusForm, TQorusFormFieldSchema } from '@qoretechnologies/ts-toolkit';
|
|
3
|
-
import { isValidCron } from 'cron-validator';
|
|
4
|
-
import jsyaml from 'js-yaml';
|
|
5
|
-
import { isBoolean, isNull, isString, isUndefined, memoize, omit } from 'lodash';
|
|
6
|
-
import every from 'lodash/every';
|
|
7
|
-
import isArray from 'lodash/isArray';
|
|
8
|
-
import isDate from 'lodash/isDate';
|
|
9
|
-
import isNaN from 'lodash/isNaN';
|
|
10
|
-
import isNumber from 'lodash/isNumber';
|
|
11
|
-
import isObject from 'lodash/isPlainObject';
|
|
12
|
-
import size from 'lodash/size';
|
|
13
|
-
import uniqWith from 'lodash/uniqWith';
|
|
14
|
-
import { fixOperatorValue, getAddress, getProtocol, splitByteSize } from './common';
|
|
15
|
-
import { isOptionInterfaceUiType } from './optionUiTypes';
|
|
16
|
-
import { getListElementValue, getOptionsFromRequiredGroups } from './options';
|
|
17
|
-
import { IProviderType, TVariableActionValue, maybeBuildOptionProvider } from './providerValue';
|
|
18
|
-
import { getTemplateKey, getTemplateValue, isValueTemplate } from './templates';
|
|
19
|
-
import { getUnlistedChoiceReason } from './allowedValues';
|
|
20
|
-
|
|
21
|
-
/** The five cron fields, in order, as a schedule hash may name them. */
|
|
22
|
-
const CRON_FIELDS: [string, string][] = [
|
|
23
|
-
['minutes', 'minute'],
|
|
24
|
-
['hours', 'hour'],
|
|
25
|
-
['days', 'day'],
|
|
26
|
-
['months', 'month'],
|
|
27
|
-
['dow', 'weekday'],
|
|
28
|
-
];
|
|
29
|
-
|
|
30
|
-
/**
|
|
31
|
-
* A five-field cron expression, from either representation a caller may hold.
|
|
32
|
-
*
|
|
33
|
-
* A schedule reaches the form in one of two shapes, and both are legitimate: a
|
|
34
|
-
* joined string (`"0 0 1 1 *"`), or the hash a Qorus job carries
|
|
35
|
-
* (`{minutes, hours, days, months, dow}` — also accepted under the singular
|
|
36
|
-
* `minute`/`hour`/`day`/`month`/`weekday` spellings). The renderer already
|
|
37
|
-
* accepted both; validation did not, and fed the hash straight to
|
|
38
|
-
* `isValidCron`, which calls `.trim()` on it.
|
|
39
|
-
*
|
|
40
|
-
* Returns `undefined` for anything that is neither, so the caller reports an
|
|
41
|
-
* invalid value rather than throwing.
|
|
42
|
-
*/
|
|
43
|
-
export const cronExpressionFromValue = (value: unknown): string | undefined => {
|
|
44
|
-
if (typeof value === 'string') {
|
|
45
|
-
return value;
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
if (!value || typeof value !== 'object' || Array.isArray(value)) {
|
|
49
|
-
return undefined;
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
const hash = value as Record<string, unknown>;
|
|
53
|
-
const parts = CRON_FIELDS.map(([plural, singular]) => {
|
|
54
|
-
const field = hash[plural] ?? hash[singular];
|
|
55
|
-
return field === undefined || field === null || field === '' ? '*' : String(field);
|
|
56
|
-
});
|
|
57
|
-
|
|
58
|
-
// An object with none of the five keys is not a schedule — every part
|
|
59
|
-
// defaulting to `*` would otherwise turn any object at all into "* * * * *"
|
|
60
|
-
return parts.every((part) => part === '*') &&
|
|
61
|
-
!CRON_FIELDS.some(([plural, singular]) => plural in hash || singular in hash)
|
|
62
|
-
? undefined
|
|
63
|
-
: parts.join(' ');
|
|
64
|
-
};
|
|
65
|
-
|
|
66
|
-
export interface IValidationResult {
|
|
67
|
-
isValid: boolean;
|
|
68
|
-
reason?: string;
|
|
69
|
-
reasons: string[];
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
interface IFieldValidationProps {
|
|
73
|
-
has_to_have_value?: boolean;
|
|
74
|
-
has_to_be_valid_identifier?: boolean;
|
|
75
|
-
/** Server options-schema validation rules (e.g. `['valid_identifier']`) —
|
|
76
|
-
* mapped onto the corresponding `has_to_be_*` flags. */
|
|
77
|
-
rules?: string[];
|
|
78
|
-
validation_regex?: string;
|
|
79
|
-
/**
|
|
80
|
-
* The inclusive bounds a numeric field accepts — read only by the `int`, `float`
|
|
81
|
-
* and `number` validators.
|
|
82
|
-
*
|
|
83
|
-
* Declared here rather than imported because ts-toolkit still does not carry them:
|
|
84
|
-
* 0.5.82 added the allowed-value and message members reqraft was waiting on, but
|
|
85
|
-
* `IQorusFormFieldSchemaBase` has no numeric bound. These two collapse into the
|
|
86
|
-
* imported type once it does — unlike the allowed-value shapes, which stay local
|
|
87
|
-
* for a reason of their own.
|
|
88
|
-
*
|
|
89
|
-
* The server declares a bound only where that same bound is already enforced on the
|
|
90
|
-
* write (`MetaFieldInfo::min_value`), so refusing a value here turns an error the
|
|
91
|
-
* author would otherwise meet on save into one they meet while the field is still on
|
|
92
|
-
* screen. It never enforces the bound, and it never refuses a value the server would
|
|
93
|
-
* have accepted.
|
|
94
|
-
*/
|
|
95
|
-
min_value?: number;
|
|
96
|
-
max_value?: number;
|
|
97
|
-
required_groups?: string[];
|
|
98
|
-
optionSchema?: IQorusFormSchema;
|
|
99
|
-
/** The sibling option VALUES, for required-group and dependency checks.
|
|
100
|
-
* Widened because a schema entry is also passed straight in as `field`, and
|
|
101
|
-
* a schema entry carries an `options` of its own — the field's UI options
|
|
102
|
-
* bag (`{ file?: DropzoneOptions }`) — under the same name. */
|
|
103
|
-
options?: TQorusForm | Record<string, any>;
|
|
104
|
-
isFunction?: boolean;
|
|
105
|
-
arg_schema?: IQorusFormSchema;
|
|
106
|
-
ui_element_type?: string;
|
|
107
|
-
element_type?: string;
|
|
108
|
-
allowed_values?: any[];
|
|
109
|
-
element_allowed_values?: any[];
|
|
110
|
-
disabled?: boolean;
|
|
111
|
-
metadata?: Record<string, any>;
|
|
112
|
-
/** The expression catalogue, when a caller holds one already — see
|
|
113
|
-
* {@link setExpressionCatalogueReader} for where it comes from otherwise. */
|
|
114
|
-
expressions?: any[];
|
|
115
|
-
/** The two key names an `array-of-pairs` row is made of. */
|
|
116
|
-
fields?: string[];
|
|
117
|
-
/** Set for a provider chosen as an FSM variable, which must support an action. */
|
|
118
|
-
isVariable?: boolean;
|
|
119
|
-
/** The declaration a `var-action` is resolved against. Partial because it
|
|
120
|
-
* carries only the provider half — the action supplies the variable half,
|
|
121
|
-
* and the two are merged before the provider validator sees them. */
|
|
122
|
-
variableData?: { value?: Partial<TVariableActionValue> };
|
|
123
|
-
[key: string]: any;
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
/**
|
|
127
|
-
* Where the expression catalogue comes from when a caller does not carry one.
|
|
128
|
-
*
|
|
129
|
-
* Every other rule here is a pure function of the value and its schema, but an
|
|
130
|
-
* expression can only be checked against the catalogue of operations the server
|
|
131
|
-
* publishes — which is application state, fetched once and held in a store. The
|
|
132
|
-
* library must not reach into a consumer's store, so the consumer hands the
|
|
133
|
-
* reader in instead: qorus-ide registers one that reads its expressions store.
|
|
134
|
-
*
|
|
135
|
-
* Unregistered, the catalogue is empty, and `case 'expression'` then validates
|
|
136
|
-
* only what an expression can be judged on by itself (see the ordering there).
|
|
137
|
-
*/
|
|
138
|
-
type TExpressionCatalogueReader = () => any[] | undefined;
|
|
139
|
-
|
|
140
|
-
let expressionCatalogueReader: TExpressionCatalogueReader | undefined;
|
|
141
|
-
|
|
142
|
-
export const setExpressionCatalogueReader = (reader?: TExpressionCatalogueReader): void => {
|
|
143
|
-
expressionCatalogueReader = reader;
|
|
144
|
-
};
|
|
145
|
-
|
|
146
|
-
const readExpressionCatalogue = (field?: IFieldValidationProps): any[] =>
|
|
147
|
-
field?.expressions ?? expressionCatalogueReader?.() ?? [];
|
|
148
|
-
|
|
149
|
-
// permissive patterns for the semantic string formats — mirror the qore DataProvider
|
|
150
|
-
// QoreStringFormatDataType server backstop (email/uuid/hostname/ipv4/ipv6/phone)
|
|
151
|
-
const SEMANTIC_FORMAT_PATTERNS: Record<string, RegExp> = {
|
|
152
|
-
email: /^[^@\s]+@[^@\s]+$/,
|
|
153
|
-
uuid: /^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$/,
|
|
154
|
-
hostname: /^[A-Za-z0-9.-]+$/,
|
|
155
|
-
ipv4: /^(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)(\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}$/,
|
|
156
|
-
ipv6: /^([0-9A-Fa-f]{0,4}:){2,7}[0-9A-Fa-f]{0,4}$/,
|
|
157
|
-
phone: /^\+?[0-9 ().-]{3,}$/,
|
|
158
|
-
};
|
|
159
|
-
|
|
160
|
-
const validResult = (): IValidationResult => ({ isValid: true, reasons: [] });
|
|
161
|
-
|
|
162
|
-
const invalidResult = (
|
|
163
|
-
reason?: string | string[],
|
|
164
|
-
childReasons: string[] = []
|
|
165
|
-
): IValidationResult => {
|
|
166
|
-
const reasons = [
|
|
167
|
-
...(Array.isArray(reason) ? reason.filter(Boolean) : reason ? [reason] : []),
|
|
168
|
-
...childReasons,
|
|
169
|
-
];
|
|
170
|
-
|
|
171
|
-
return {
|
|
172
|
-
isValid: false,
|
|
173
|
-
reason: reasons[0],
|
|
174
|
-
reasons,
|
|
175
|
-
};
|
|
176
|
-
};
|
|
177
|
-
|
|
178
|
-
const withContext = (result: IValidationResult, context?: string): IValidationResult => {
|
|
179
|
-
if (result.isValid || !context) {
|
|
180
|
-
return result;
|
|
181
|
-
}
|
|
182
|
-
|
|
183
|
-
const reasons =
|
|
184
|
-
result.reasons.length > 0 ? result.reasons.map((reason) => `${context}: ${reason}`) : [context];
|
|
185
|
-
|
|
186
|
-
return {
|
|
187
|
-
isValid: false,
|
|
188
|
-
reason: reasons[0],
|
|
189
|
-
reasons,
|
|
190
|
-
};
|
|
191
|
-
};
|
|
192
|
-
|
|
193
|
-
const resultFromBoolean = (isValid: boolean, reason: string): IValidationResult =>
|
|
194
|
-
isValid ? validResult() : invalidResult(reason);
|
|
195
|
-
|
|
196
|
-
/**
|
|
197
|
-
* Whether the value is a number at all — the check the `number` and `float` cases both
|
|
198
|
-
* make before any bound is read. Shared because the two differ only in the wording of
|
|
199
|
-
* the refusal, and a predicate that drifted between them would leave one of the pair
|
|
200
|
-
* accepting what the other refuses.
|
|
201
|
-
*/
|
|
202
|
-
const isNumericValue = (value: any): boolean =>
|
|
203
|
-
!isNaN(value) && (getTypeFromValue(value) === 'float' || getTypeFromValue(value) === 'int');
|
|
204
|
-
|
|
205
|
-
/**
|
|
206
|
-
* The schema-declared range for a value that is already the right kind of number.
|
|
207
|
-
*
|
|
208
|
-
* Both bounds are inclusive and either may stand alone — the server declares only the
|
|
209
|
-
* side it can point at an enforcing line for, so a count with a floor and no ceiling
|
|
210
|
-
* arrives with `min_value` alone. A bound that is not a finite number is ignored rather
|
|
211
|
-
* than treated as zero: a schema that says nothing must not refuse everything.
|
|
212
|
-
*
|
|
213
|
-
* Kept out of the type checks above it so the reason a value is refused says which
|
|
214
|
-
* thing is wrong — "must be a whole number" and "must be at least 1" are different
|
|
215
|
-
* corrections, and collapsing them into one message makes the author guess.
|
|
216
|
-
*/
|
|
217
|
-
const checkNumericBounds = (value: any, field?: IFieldValidationProps): IValidationResult => {
|
|
218
|
-
const num = Number(value);
|
|
219
|
-
const min = field?.min_value;
|
|
220
|
-
const max = field?.max_value;
|
|
221
|
-
|
|
222
|
-
if (typeof min === 'number' && Number.isFinite(min) && num < min) {
|
|
223
|
-
return invalidResult(`Value must be ${min} or more`);
|
|
224
|
-
}
|
|
225
|
-
if (typeof max === 'number' && Number.isFinite(max) && num > max) {
|
|
226
|
-
return invalidResult(`Value must be ${max} or less`);
|
|
227
|
-
}
|
|
228
|
-
return validResult();
|
|
229
|
-
};
|
|
230
|
-
|
|
231
|
-
const isRichTextWithoutValue = (value: any): boolean => {
|
|
232
|
-
return (
|
|
233
|
-
value === undefined ||
|
|
234
|
-
value === '' ||
|
|
235
|
-
JSON.stringify(value) === '[{"type":"paragraph","children":[{"text":""}]}]'
|
|
236
|
-
);
|
|
237
|
-
};
|
|
238
|
-
|
|
239
|
-
const isValueDefined = (type: string, value: any): boolean => {
|
|
240
|
-
if (type === 'richtext') {
|
|
241
|
-
return !isRichTextWithoutValue(value);
|
|
242
|
-
}
|
|
243
|
-
|
|
244
|
-
return value !== undefined && value !== '';
|
|
245
|
-
};
|
|
246
|
-
|
|
247
|
-
export const _validateField = (
|
|
248
|
-
type: string,
|
|
249
|
-
value?: any,
|
|
250
|
-
field?: IFieldValidationProps,
|
|
251
|
-
canBeNull?: boolean
|
|
252
|
-
): IValidationResult => {
|
|
253
|
-
if (!type) {
|
|
254
|
-
if (value === undefined || value === null) {
|
|
255
|
-
return invalidResult('Missing value');
|
|
256
|
-
}
|
|
257
|
-
|
|
258
|
-
return invalidResult('Missing type');
|
|
259
|
-
}
|
|
260
|
-
|
|
261
|
-
// Check if the type starts with a * to indicate it can be null
|
|
262
|
-
if (type.startsWith('*')) {
|
|
263
|
-
type = type.substring(1);
|
|
264
|
-
canBeNull = true;
|
|
265
|
-
}
|
|
266
|
-
// If the value can be null and is null, immediately return valid
|
|
267
|
-
if (canBeNull && (value === null || value === undefined)) {
|
|
268
|
-
return validResult();
|
|
269
|
-
}
|
|
270
|
-
// Strip type parameters e.g. hash<string, int> → hash
|
|
271
|
-
const pos: number = type.indexOf('<');
|
|
272
|
-
if (pos > 0) {
|
|
273
|
-
type = type.slice(0, pos);
|
|
274
|
-
}
|
|
275
|
-
// Check if the value is a template string
|
|
276
|
-
if (isValueTemplate(value)) {
|
|
277
|
-
const hasKey = !!getTemplateKey(value);
|
|
278
|
-
const hasValue = !!getTemplateValue(value);
|
|
279
|
-
|
|
280
|
-
return resultFromBoolean(hasKey && hasValue, 'Template must include key and value');
|
|
281
|
-
}
|
|
282
|
-
// Expression values (`is_expression`) carry the AST `{ exp, args }` instead of
|
|
283
|
-
// a typed literal, so the declared type says nothing about them — validate
|
|
284
|
-
// them as the expression they are, arguments and all. (`isFunction` is set by
|
|
285
|
-
// FormEngine, and by the option recursion below, for expression options.)
|
|
286
|
-
if (field?.isFunction) {
|
|
287
|
-
// The AST is normally the value itself; a caller that still holds the
|
|
288
|
-
// option envelope hands over `{ value: ast }`, so accept both.
|
|
289
|
-
const ast = (value as { value?: any })?.value ?? value;
|
|
290
|
-
|
|
291
|
-
return validateFieldWithResult(
|
|
292
|
-
'expression',
|
|
293
|
-
{ value: ast },
|
|
294
|
-
omit(field, ['isFunction']),
|
|
295
|
-
canBeNull
|
|
296
|
-
);
|
|
297
|
-
}
|
|
298
|
-
|
|
299
|
-
// Check if the field has required groups
|
|
300
|
-
if (field?.required_groups) {
|
|
301
|
-
if (
|
|
302
|
-
!isValueDefined(type, value) &&
|
|
303
|
-
validateOptionWithRequiredGroups(
|
|
304
|
-
field.options as TQorusForm,
|
|
305
|
-
field.optionSchema,
|
|
306
|
-
field.required_groups
|
|
307
|
-
)
|
|
308
|
-
) {
|
|
309
|
-
return validResult();
|
|
310
|
-
}
|
|
311
|
-
}
|
|
312
|
-
|
|
313
|
-
// A value that is not one of the field's fixed choices is INVALID — never
|
|
314
|
-
// erased. The form used to drop such a value when the choices arrived, and
|
|
315
|
-
// three times the dropped value was a real one (a document naming a choice,
|
|
316
|
-
// a bare-declared choice, a value whose choices had not loaded yet) that the
|
|
317
|
-
// emptied form then saved. Keeping it and saying why it cannot be submitted
|
|
318
|
-
// leaves the author to decide. Templates and expression values returned
|
|
319
|
-
// above; `allowed_values: []` and creatable choices are not judged. An
|
|
320
|
-
// `expression` is never judged either: the expression branch above recurses
|
|
321
|
-
// here with the field's schema (choices included) and the AST as the value.
|
|
322
|
-
const unlistedChoiceReason =
|
|
323
|
-
type === 'expression' ? undefined : getUnlistedChoiceReason(value, field);
|
|
324
|
-
if (unlistedChoiceReason) {
|
|
325
|
-
return invalidResult(unlistedChoiceReason);
|
|
326
|
-
}
|
|
327
|
-
|
|
328
|
-
// An interface type names another Qorus object by its name, so a non-empty
|
|
329
|
-
// string is the whole contract. `connection` is the exception: it carries
|
|
330
|
-
// enablement and authentication state of its own, checked below.
|
|
331
|
-
if (isOptionInterfaceUiType(type) && type !== 'connection') {
|
|
332
|
-
return validateFieldWithResult('string', value, field);
|
|
333
|
-
}
|
|
334
|
-
|
|
335
|
-
switch (type) {
|
|
336
|
-
case 'richtext': {
|
|
337
|
-
if (!value || !size(value)) {
|
|
338
|
-
return invalidResult('Text value is empty');
|
|
339
|
-
}
|
|
340
|
-
|
|
341
|
-
if (typeof value === 'string') {
|
|
342
|
-
return validResult();
|
|
343
|
-
}
|
|
344
|
-
|
|
345
|
-
if (isRichTextWithoutValue(value)) {
|
|
346
|
-
return invalidResult('Text value is empty');
|
|
347
|
-
}
|
|
348
|
-
|
|
349
|
-
return validResult();
|
|
350
|
-
}
|
|
351
|
-
case 'bool':
|
|
352
|
-
case 'boolean':
|
|
353
|
-
return resultFromBoolean(
|
|
354
|
-
value === true ||
|
|
355
|
-
value === false ||
|
|
356
|
-
(value === undefined && field?.has_to_have_value === false),
|
|
357
|
-
'Value must be a True or False value'
|
|
358
|
-
);
|
|
359
|
-
case 'connection': {
|
|
360
|
-
if (!value) {
|
|
361
|
-
return invalidResult('Connection value is missing');
|
|
362
|
-
}
|
|
363
|
-
|
|
364
|
-
if (field?.allowed_values) {
|
|
365
|
-
const allowedValue = field.allowed_values.find(
|
|
366
|
-
(val: any) => val.value?.value === value || val.name === value
|
|
367
|
-
);
|
|
368
|
-
|
|
369
|
-
if (!allowedValue) {
|
|
370
|
-
return invalidResult('Connection is not allowed');
|
|
371
|
-
}
|
|
372
|
-
|
|
373
|
-
if (allowedValue.disabled || allowedValue.metadata?.needs_auth) {
|
|
374
|
-
return invalidResult('Connection is disabled or not authenticated');
|
|
375
|
-
}
|
|
376
|
-
}
|
|
377
|
-
|
|
378
|
-
if (field?.disabled || field?.metadata?.needs_auth) {
|
|
379
|
-
return invalidResult('Connection is disabled or not authenticated');
|
|
380
|
-
}
|
|
381
|
-
|
|
382
|
-
return withContext(
|
|
383
|
-
validateFieldWithResult('string', value, field),
|
|
384
|
-
'Connection string validation failed'
|
|
385
|
-
);
|
|
386
|
-
}
|
|
387
|
-
// semantic string formats — permissive patterns mirror the qore DataProvider
|
|
388
|
-
// QoreStringFormatDataType backstop; a server-supplied validation_regex, if
|
|
389
|
-
// present, is also enforced
|
|
390
|
-
case 'email':
|
|
391
|
-
case 'uuid':
|
|
392
|
-
case 'hostname':
|
|
393
|
-
case 'ipv4':
|
|
394
|
-
case 'ipv6':
|
|
395
|
-
case 'phone': {
|
|
396
|
-
if (value === undefined || value === null || value === '' || typeof value !== 'string') {
|
|
397
|
-
return invalidResult('Value must be a non-empty text');
|
|
398
|
-
}
|
|
399
|
-
if (field?.validation_regex && !value.match(field.validation_regex)) {
|
|
400
|
-
return invalidResult('Value does not match the required format');
|
|
401
|
-
}
|
|
402
|
-
return resultFromBoolean(
|
|
403
|
-
SEMANTIC_FORMAT_PATTERNS[type].test(value),
|
|
404
|
-
`Value is not a valid ${type}`
|
|
405
|
-
);
|
|
406
|
-
}
|
|
407
|
-
case 'binary': {
|
|
408
|
-
if (typeof value !== 'string') {
|
|
409
|
-
return invalidResult('Binary value must be a string');
|
|
410
|
-
}
|
|
411
|
-
|
|
412
|
-
const trimmed = value.trim();
|
|
413
|
-
|
|
414
|
-
if (trimmed.length === 0) {
|
|
415
|
-
return invalidResult('Binary value is empty');
|
|
416
|
-
}
|
|
417
|
-
|
|
418
|
-
// the canonical wire form is base64 (matching the server decode); a "data:<mime>;base64,..." URL
|
|
419
|
-
// and legacy "0x"-prefixed hex are also accepted
|
|
420
|
-
if (/^data:[^;]+;base64,/.test(trimmed)) {
|
|
421
|
-
return validResult();
|
|
422
|
-
}
|
|
423
|
-
|
|
424
|
-
if (/^0x/i.test(trimmed)) {
|
|
425
|
-
const hex = trimmed.replace(/^0x/i, '');
|
|
426
|
-
return resultFromBoolean(
|
|
427
|
-
hex.length % 2 === 0 && /^[0-9a-fA-F]+$/.test(hex),
|
|
428
|
-
'Binary hex value is invalid'
|
|
429
|
-
);
|
|
430
|
-
}
|
|
431
|
-
|
|
432
|
-
return resultFromBoolean(
|
|
433
|
-
/^[A-Za-z0-9+/]+={0,2}$/.test(trimmed),
|
|
434
|
-
'Binary value must be base64, a data: URL, or 0x-prefixed hex'
|
|
435
|
-
);
|
|
436
|
-
}
|
|
437
|
-
case 'string':
|
|
438
|
-
case 'mapper':
|
|
439
|
-
case 'workflow':
|
|
440
|
-
case 'service':
|
|
441
|
-
case 'job':
|
|
442
|
-
case 'softstring':
|
|
443
|
-
case 'select-string':
|
|
444
|
-
case 'file-string':
|
|
445
|
-
case 'file-as-string':
|
|
446
|
-
case 'long-string':
|
|
447
|
-
case 'method-name':
|
|
448
|
-
case 'code-editor':
|
|
449
|
-
case 'data': {
|
|
450
|
-
if (value === undefined || value === null || value === '' || typeof value !== 'string') {
|
|
451
|
-
return invalidResult('Value must be a non-empty text');
|
|
452
|
-
}
|
|
453
|
-
|
|
454
|
-
const reasons: string[] = [];
|
|
455
|
-
|
|
456
|
-
if (field?.validation_regex && !value.match(field.validation_regex)) {
|
|
457
|
-
reasons.push('Value does not match validation pattern');
|
|
458
|
-
}
|
|
459
|
-
|
|
460
|
-
// Server `rules[]` contract: 'valid_identifier' is the only rule the
|
|
461
|
-
// server sends today; unknown rule strings are deliberately ignored
|
|
462
|
-
// (validation passes) — extend this mapping when the server grows rules.
|
|
463
|
-
if (
|
|
464
|
-
field?.has_to_be_valid_identifier ||
|
|
465
|
-
(Array.isArray(field?.rules) && field.rules.includes('valid_identifier'))
|
|
466
|
-
) {
|
|
467
|
-
if (value.match(/^[0-9]|\W/)) {
|
|
468
|
-
reasons.push('Value is not a valid identifier');
|
|
469
|
-
}
|
|
470
|
-
}
|
|
471
|
-
|
|
472
|
-
if (field?.has_to_have_value) {
|
|
473
|
-
if (value === '' || value.length === 0) {
|
|
474
|
-
reasons.push('Value is required');
|
|
475
|
-
}
|
|
476
|
-
}
|
|
477
|
-
|
|
478
|
-
return reasons.length ? invalidResult(undefined, reasons) : validResult();
|
|
479
|
-
}
|
|
480
|
-
case 'file': {
|
|
481
|
-
// Support both the Build-tab typed format ({ name: { type, value } })
|
|
482
|
-
// and the Upload-tab flat format ({ name: 'file.txt' })
|
|
483
|
-
//
|
|
484
|
-
// A Build-tab sub-value is a full option envelope: it carries its own
|
|
485
|
-
// `type` and may hold an expression (`is_expression`) or a rich-text
|
|
486
|
-
// paragraph array rather than a bare string. This used to unwrap `.value`
|
|
487
|
-
// and validate it as a hard-coded `string` with no field, discarding both
|
|
488
|
-
// the declared type and the expression flag — so a `concat(...)` filename
|
|
489
|
-
// arrived at the string validator as `{ exp, args }`, rich text arrived as
|
|
490
|
-
// an array, and both were rejected with "Value must be a non-empty text".
|
|
491
|
-
//
|
|
492
|
-
// Validate each part against its OWN type and route `is_expression`
|
|
493
|
-
// through `isFunction`, exactly as the `system-options` recursion below
|
|
494
|
-
// does, so the `field?.isFunction` branch above gets a chance to run.
|
|
495
|
-
const validateFilePart = (part: any, fallbackType: string): IValidationResult => {
|
|
496
|
-
const isEnvelope = !!part && isObject(part) && ('value' in part || 'is_expression' in part);
|
|
497
|
-
|
|
498
|
-
return isEnvelope
|
|
499
|
-
? validateFieldWithResult(part.type || fallbackType, part.value, {
|
|
500
|
-
isFunction: part.is_expression,
|
|
501
|
-
} as IFieldValidationProps)
|
|
502
|
-
: validateFieldWithResult(fallbackType, part);
|
|
503
|
-
};
|
|
504
|
-
|
|
505
|
-
// Fall back to the arg_schema's declared types for the flat Upload-tab
|
|
506
|
-
// shape: `name` is `richtext` (which also accepts a plain string) and
|
|
507
|
-
// `content` is `data`.
|
|
508
|
-
const nameResult = validateFilePart(value?.name, 'richtext');
|
|
509
|
-
const contentResult = validateFilePart(value?.content, 'data');
|
|
510
|
-
|
|
511
|
-
// Report both parts. Returning on the first failure meant a bad file name
|
|
512
|
-
// masked the content result entirely, so the form could only ever surface
|
|
513
|
-
// one problem at a time.
|
|
514
|
-
const reasons = [
|
|
515
|
-
...(nameResult.isValid ? [] : withContext(nameResult, 'File name is invalid').reasons),
|
|
516
|
-
...(contentResult.isValid
|
|
517
|
-
? []
|
|
518
|
-
: withContext(contentResult, 'File content is invalid').reasons),
|
|
519
|
-
];
|
|
520
|
-
|
|
521
|
-
return reasons.length ? invalidResult(reasons) : validResult();
|
|
522
|
-
}
|
|
523
|
-
case 'collection-documents': {
|
|
524
|
-
// The value is an array of rows in mixed lifecycle states.
|
|
525
|
-
// A row is valid when it's either:
|
|
526
|
-
// 1. Server-managed: has `ai_documentid` (number) + `name`.
|
|
527
|
-
// 2. Client-managed: has `name` + `content` (base64) — i.e.
|
|
528
|
-
// a fresh upload that hasn't landed yet.
|
|
529
|
-
// Failed rows count as valid for form-level purposes (the
|
|
530
|
-
// user can Retry; the form shouldn't block save just because
|
|
531
|
-
// an upload errored). Empty list is valid here — the
|
|
532
|
-
// top-level required check (`field.required`) handles "must
|
|
533
|
-
// pick at least one" gating.
|
|
534
|
-
if (value === undefined || value === null) {
|
|
535
|
-
return validResult();
|
|
536
|
-
}
|
|
537
|
-
if (!Array.isArray(value)) {
|
|
538
|
-
return invalidResult('Value must be a list of documents');
|
|
539
|
-
}
|
|
540
|
-
const reasons: string[] = [];
|
|
541
|
-
value.forEach((row: any, idx: number) => {
|
|
542
|
-
if (!row || typeof row !== 'object') {
|
|
543
|
-
reasons.push(`Row ${idx + 1} is not an object`);
|
|
544
|
-
return;
|
|
545
|
-
}
|
|
546
|
-
if (typeof row.name !== 'string' || !row.name) {
|
|
547
|
-
reasons.push(`Row ${idx + 1} is missing a name`);
|
|
548
|
-
return;
|
|
549
|
-
}
|
|
550
|
-
const hasServerId = typeof row.ai_documentid === 'number';
|
|
551
|
-
const hasContent = typeof row.content === 'string' && !!row.content;
|
|
552
|
-
if (!hasServerId && !hasContent) {
|
|
553
|
-
reasons.push(
|
|
554
|
-
`Row ${idx + 1} ("${row.name}") has neither uploaded ` +
|
|
555
|
-
`content nor a server document id`
|
|
556
|
-
);
|
|
557
|
-
}
|
|
558
|
-
});
|
|
559
|
-
return reasons.length ? invalidResult(undefined, reasons) : validResult();
|
|
560
|
-
}
|
|
561
|
-
case 'array-of-pairs': {
|
|
562
|
-
let valid = true;
|
|
563
|
-
const reasons: string[] = [];
|
|
564
|
-
// Check if every pair has key & value
|
|
565
|
-
// assigned properly
|
|
566
|
-
if (!Array.isArray(value)) {
|
|
567
|
-
return invalidResult('Value must be a list');
|
|
568
|
-
}
|
|
569
|
-
if (
|
|
570
|
-
!value?.every(
|
|
571
|
-
(pair: { [key: string]: string }): boolean =>
|
|
572
|
-
pair[field.fields[0]] !== '' && pair[field.fields[1]] !== ''
|
|
573
|
-
)
|
|
574
|
-
) {
|
|
575
|
-
valid = false;
|
|
576
|
-
reasons.push('All pairs must include both fields');
|
|
577
|
-
}
|
|
578
|
-
// Get a list of unique values
|
|
579
|
-
const uniqueValues: any[] = uniqWith(
|
|
580
|
-
value,
|
|
581
|
-
(cur, prev) => cur[field.fields[0]] === prev[field.fields[0]]
|
|
582
|
-
);
|
|
583
|
-
// Check if there are any duplicates
|
|
584
|
-
if (size(uniqueValues) !== size(value)) {
|
|
585
|
-
valid = false;
|
|
586
|
-
reasons.push('Pairs must use unique keys');
|
|
587
|
-
}
|
|
588
|
-
|
|
589
|
-
return valid ? validResult() : invalidResult(undefined, reasons);
|
|
590
|
-
}
|
|
591
|
-
case 'class-connectors': {
|
|
592
|
-
if (!Array.isArray(value) || value.length === 0) {
|
|
593
|
-
return invalidResult('At least one connector is required');
|
|
594
|
-
}
|
|
595
|
-
let valid = true;
|
|
596
|
-
const reasons: string[] = [];
|
|
597
|
-
// Check if every pair has name, input method and output method
|
|
598
|
-
// assigned properly
|
|
599
|
-
if (
|
|
600
|
-
!value?.every(
|
|
601
|
-
(pair: { [key: string]: string }): boolean =>
|
|
602
|
-
!!pair.name && pair.name !== '' && !!pair.method && pair.method !== ''
|
|
603
|
-
)
|
|
604
|
-
) {
|
|
605
|
-
valid = false;
|
|
606
|
-
reasons.push('Each connector must have a name and method');
|
|
607
|
-
}
|
|
608
|
-
// Get a list of unique values
|
|
609
|
-
const uniqueValues: any[] = uniqWith(value, (cur, prev) => cur.name === prev.name);
|
|
610
|
-
// Check if there are any duplicates
|
|
611
|
-
if (size(uniqueValues) !== size(value)) {
|
|
612
|
-
valid = false;
|
|
613
|
-
reasons.push('Connector names must be unique');
|
|
614
|
-
}
|
|
615
|
-
|
|
616
|
-
return valid ? validResult() : invalidResult(undefined, reasons);
|
|
617
|
-
}
|
|
618
|
-
// Classes check
|
|
619
|
-
case 'class-array': {
|
|
620
|
-
if (!(Array.isArray(value) && value.length > 0)) {
|
|
621
|
-
return invalidResult('At least one class must be provided');
|
|
622
|
-
}
|
|
623
|
-
let valid = true;
|
|
624
|
-
const reasons: string[] = [];
|
|
625
|
-
// Check if the fields are not empty
|
|
626
|
-
if (
|
|
627
|
-
!value?.every((pair: { [key: string]: string }): boolean => !!pair.name && pair.name !== '')
|
|
628
|
-
) {
|
|
629
|
-
valid = false;
|
|
630
|
-
reasons.push('Each class must have a name');
|
|
631
|
-
}
|
|
632
|
-
// Get a list of unique values
|
|
633
|
-
const uniqueValues: any[] = uniqWith(
|
|
634
|
-
value,
|
|
635
|
-
(cur, prev) => `${cur.prefix}${cur.name}` === `${prev.prefix}${prev.name}`
|
|
636
|
-
);
|
|
637
|
-
// Check if there are any duplicates
|
|
638
|
-
if (size(uniqueValues) !== size(value)) {
|
|
639
|
-
valid = false;
|
|
640
|
-
reasons.push('Class names must be unique');
|
|
641
|
-
}
|
|
642
|
-
|
|
643
|
-
return valid ? validResult() : invalidResult(undefined, reasons);
|
|
644
|
-
}
|
|
645
|
-
case 'number': {
|
|
646
|
-
if (!isNumericValue(value)) {
|
|
647
|
-
return invalidResult('Value must be a number');
|
|
648
|
-
}
|
|
649
|
-
return checkNumericBounds(value, field);
|
|
650
|
-
}
|
|
651
|
-
case 'int':
|
|
652
|
-
if (!(!Number.isNaN(value) && getTypeFromValue(value) === 'int')) {
|
|
653
|
-
return invalidResult('Value must be an integer');
|
|
654
|
-
}
|
|
655
|
-
return checkNumericBounds(value, field);
|
|
656
|
-
case 'float':
|
|
657
|
-
if (!isNumericValue(value)) {
|
|
658
|
-
return invalidResult('Value must be a float');
|
|
659
|
-
}
|
|
660
|
-
return checkNumericBounds(value, field);
|
|
661
|
-
case 'select-array':
|
|
662
|
-
case 'multi-select':
|
|
663
|
-
case 'array':
|
|
664
|
-
case 'file-tree':
|
|
665
|
-
return resultFromBoolean(value && value.length > 0, 'At least one value is required');
|
|
666
|
-
case 'cron': {
|
|
667
|
-
if (!value) {
|
|
668
|
-
return invalidResult('Cron value is required');
|
|
669
|
-
}
|
|
670
|
-
const expression = cronExpressionFromValue(value);
|
|
671
|
-
// A value that is neither a cron string nor a schedule hash is INVALID,
|
|
672
|
-
// not a crash: `isValidCron` calls `.trim()` on whatever it is given, so
|
|
673
|
-
// passing it a hash threw a TypeError out of validation and took the
|
|
674
|
-
// whole form down through the host's error boundary.
|
|
675
|
-
if (expression === undefined) {
|
|
676
|
-
return invalidResult('Cron expression is invalid');
|
|
677
|
-
}
|
|
678
|
-
return resultFromBoolean(
|
|
679
|
-
isValidCron(expression, { alias: true }),
|
|
680
|
-
'Cron expression is invalid'
|
|
681
|
-
);
|
|
682
|
-
}
|
|
683
|
-
case 'date':
|
|
684
|
-
return resultFromBoolean(
|
|
685
|
-
value !== undefined &&
|
|
686
|
-
value !== null &&
|
|
687
|
-
value !== '' &&
|
|
688
|
-
new Date(value).toString() !== 'Invalid Date',
|
|
689
|
-
'Date is invalid'
|
|
690
|
-
);
|
|
691
|
-
case 'hash':
|
|
692
|
-
case 'free-hash': {
|
|
693
|
-
const parsedValue: any = typeof value === 'object' ? value : maybeParseYaml(value);
|
|
694
|
-
|
|
695
|
-
if (field?.arg_schema) {
|
|
696
|
-
const result = every(
|
|
697
|
-
field.arg_schema,
|
|
698
|
-
(fieldData: TQorusFormFieldSchema, argName: string) => {
|
|
699
|
-
const argValue = readArgValue(parsedValue?.[argName]);
|
|
700
|
-
|
|
701
|
-
// Absent and present-but-empty are the same answer to the only
|
|
702
|
-
// question the schema asks here: was the arg supplied?
|
|
703
|
-
if (argValue === undefined) {
|
|
704
|
-
return !fieldData.required;
|
|
705
|
-
}
|
|
706
|
-
|
|
707
|
-
return validateFieldWithResult(
|
|
708
|
-
(fieldData.ui_type as string) || (fieldData.type as string),
|
|
709
|
-
argValue,
|
|
710
|
-
fieldData as unknown as IFieldValidationProps
|
|
711
|
-
).isValid;
|
|
712
|
-
}
|
|
713
|
-
);
|
|
714
|
-
|
|
715
|
-
return resultFromBoolean(result, 'Hash arguments are invalid');
|
|
716
|
-
}
|
|
717
|
-
|
|
718
|
-
if (!parsedValue || !isObject(parsedValue)) {
|
|
719
|
-
return invalidResult('Hash value must be an object');
|
|
720
|
-
}
|
|
721
|
-
|
|
722
|
-
return validResult();
|
|
723
|
-
}
|
|
724
|
-
case 'rgbcolor': {
|
|
725
|
-
return resultFromBoolean(
|
|
726
|
-
isValidSixCharHex(value?.hex) ||
|
|
727
|
-
((value?.r || value?.r === 0) &&
|
|
728
|
-
(value?.g || value?.g === 0) &&
|
|
729
|
-
(value?.b || value?.b === 0)),
|
|
730
|
-
'RGB color is invalid'
|
|
731
|
-
);
|
|
732
|
-
}
|
|
733
|
-
case 'list':
|
|
734
|
-
case 'free-list': {
|
|
735
|
-
const parsedValue: any = maybeParseYaml(value);
|
|
736
|
-
|
|
737
|
-
if (
|
|
738
|
-
!field?.has_to_have_value &&
|
|
739
|
-
(parsedValue === undefined || (!size(parsedValue) && isArray(parsedValue)))
|
|
740
|
-
) {
|
|
741
|
-
return validResult();
|
|
742
|
-
}
|
|
743
|
-
|
|
744
|
-
if (!isArray(parsedValue)) {
|
|
745
|
-
return invalidResult('Value must be a list');
|
|
746
|
-
}
|
|
747
|
-
|
|
748
|
-
if (field?.ui_element_type || field?.element_type) {
|
|
749
|
-
for (let i = 0; i < parsedValue.length; i++) {
|
|
750
|
-
const itemResult = validateFieldWithResult(
|
|
751
|
-
(field.ui_element_type as string) || (field.element_type as string),
|
|
752
|
-
// An element arrives bare OR in a `{value, type}` envelope: the
|
|
753
|
-
// envelope is what the editor writes, the bare form is what storage
|
|
754
|
-
// holds. Reaching straight for `.value` failed every stored element
|
|
755
|
-
// as empty, so a reloaded alert rule reported its delivery action
|
|
756
|
-
// invalid while showing all six options set -- and threw outright on
|
|
757
|
-
// a null element.
|
|
758
|
-
getListElementValue(parsedValue[i]),
|
|
759
|
-
field
|
|
760
|
-
);
|
|
761
|
-
|
|
762
|
-
if (!itemResult.isValid) {
|
|
763
|
-
return withContext(itemResult, `List item ${i} is invalid`);
|
|
764
|
-
}
|
|
765
|
-
}
|
|
766
|
-
}
|
|
767
|
-
|
|
768
|
-
return validResult();
|
|
769
|
-
}
|
|
770
|
-
case 'list-of-hashes': {
|
|
771
|
-
const parsedValue: any = maybeParseYaml(value);
|
|
772
|
-
|
|
773
|
-
if (!parsedValue || !isArray(parsedValue)) {
|
|
774
|
-
return invalidResult('Value must be a list of hashes');
|
|
775
|
-
}
|
|
776
|
-
|
|
777
|
-
for (let i = 0; i < parsedValue.length; i++) {
|
|
778
|
-
const item = parsedValue[i];
|
|
779
|
-
|
|
780
|
-
if (!size(item)) {
|
|
781
|
-
return invalidResult(`Hash at index ${i} must not be empty`);
|
|
782
|
-
}
|
|
783
|
-
|
|
784
|
-
const itemResult = validateFieldWithResult('hash', item);
|
|
785
|
-
|
|
786
|
-
if (!itemResult.isValid) {
|
|
787
|
-
return withContext(itemResult, `Hash at index ${i} is invalid`);
|
|
788
|
-
}
|
|
789
|
-
}
|
|
790
|
-
|
|
791
|
-
return validResult();
|
|
792
|
-
}
|
|
793
|
-
case 'mapper-code': {
|
|
794
|
-
if (!value) {
|
|
795
|
-
return invalidResult('Mapper code is required');
|
|
796
|
-
}
|
|
797
|
-
// Split the value
|
|
798
|
-
const [code, method] = value.split('::');
|
|
799
|
-
// Both fields need to be strings & filled
|
|
800
|
-
const codeResult = validateFieldWithResult('string', code);
|
|
801
|
-
|
|
802
|
-
if (!codeResult.isValid) {
|
|
803
|
-
return withContext(codeResult, 'Mapper code is invalid');
|
|
804
|
-
}
|
|
805
|
-
|
|
806
|
-
const methodResult = validateFieldWithResult('string', method);
|
|
807
|
-
|
|
808
|
-
if (!methodResult.isValid) {
|
|
809
|
-
return withContext(methodResult, 'Mapper method is invalid');
|
|
810
|
-
}
|
|
811
|
-
|
|
812
|
-
return validResult();
|
|
813
|
-
}
|
|
814
|
-
case 'var-action': {
|
|
815
|
-
const varAction: TVariableActionValue = value;
|
|
816
|
-
|
|
817
|
-
if (
|
|
818
|
-
varAction?.var_type !== 'localvar' &&
|
|
819
|
-
varAction?.var_type !== 'globalvar' &&
|
|
820
|
-
varAction?.var_type !== 'autovar'
|
|
821
|
-
) {
|
|
822
|
-
return invalidResult('Variable type is invalid');
|
|
823
|
-
}
|
|
824
|
-
|
|
825
|
-
const nameResult = validateFieldWithResult('string', varAction.var_name, {
|
|
826
|
-
has_to_have_value: true,
|
|
827
|
-
});
|
|
828
|
-
|
|
829
|
-
if (!nameResult.isValid) {
|
|
830
|
-
return withContext(nameResult, 'Variable name is invalid');
|
|
831
|
-
}
|
|
832
|
-
|
|
833
|
-
const actionResult = validateFieldWithResult('string', varAction.action_type, {
|
|
834
|
-
has_to_have_value: true,
|
|
835
|
-
});
|
|
836
|
-
|
|
837
|
-
if (!actionResult.isValid) {
|
|
838
|
-
return withContext(actionResult, 'Variable action type is invalid');
|
|
839
|
-
}
|
|
840
|
-
|
|
841
|
-
// If the action type is transaction, the transaction_action needs to be set
|
|
842
|
-
if (varAction.action_type === 'transaction') {
|
|
843
|
-
const transactionResult = validateFieldWithResult('string', varAction.transaction_action, {
|
|
844
|
-
has_to_have_value: true,
|
|
845
|
-
});
|
|
846
|
-
|
|
847
|
-
if (!transactionResult.isValid) {
|
|
848
|
-
return withContext(transactionResult, 'Transaction action is invalid');
|
|
849
|
-
}
|
|
850
|
-
|
|
851
|
-
return validResult();
|
|
852
|
-
}
|
|
853
|
-
|
|
854
|
-
// If the variable data is missing
|
|
855
|
-
if (!field?.variableData?.value) {
|
|
856
|
-
return invalidResult('Variable data is missing');
|
|
857
|
-
}
|
|
858
|
-
|
|
859
|
-
// Get the variable data
|
|
860
|
-
const variableData: TVariableActionValue = {
|
|
861
|
-
...value,
|
|
862
|
-
...field.variableData.value,
|
|
863
|
-
};
|
|
864
|
-
|
|
865
|
-
return withContext(
|
|
866
|
-
validateFieldWithResult(varAction.action_type, variableData, field),
|
|
867
|
-
'Variable action is invalid'
|
|
868
|
-
);
|
|
869
|
-
}
|
|
870
|
-
case 'type-selector':
|
|
871
|
-
case 'data-provider':
|
|
872
|
-
case 'api-call':
|
|
873
|
-
case 'search-single':
|
|
874
|
-
case 'send-message':
|
|
875
|
-
case 'search':
|
|
876
|
-
case 'update':
|
|
877
|
-
case 'delete':
|
|
878
|
-
case 'create': {
|
|
879
|
-
const newValue: IProviderType | null = maybeBuildOptionProvider(value);
|
|
880
|
-
|
|
881
|
-
if (!newValue) {
|
|
882
|
-
return invalidResult('Provider value is invalid');
|
|
883
|
-
}
|
|
884
|
-
|
|
885
|
-
// Api call only supports requests / response
|
|
886
|
-
if (type === 'api-call' && !value.supports_request) {
|
|
887
|
-
return invalidResult('API call must support requests');
|
|
888
|
-
}
|
|
889
|
-
|
|
890
|
-
// If the provider is from FSM variables, it needs pass this
|
|
891
|
-
if (
|
|
892
|
-
field?.isVariable &&
|
|
893
|
-
!(
|
|
894
|
-
newValue.supports_read ||
|
|
895
|
-
newValue.supports_create ||
|
|
896
|
-
newValue.supports_update ||
|
|
897
|
-
newValue.supports_delete ||
|
|
898
|
-
newValue.supports_request ||
|
|
899
|
-
newValue.supports_messages ||
|
|
900
|
-
newValue.transaction_management
|
|
901
|
-
)
|
|
902
|
-
) {
|
|
903
|
-
return invalidResult('Variable provider must support at least one action');
|
|
904
|
-
}
|
|
905
|
-
|
|
906
|
-
// Send message only supports messages
|
|
907
|
-
if (
|
|
908
|
-
type === 'send-message' &&
|
|
909
|
-
(!newValue.supports_messages || !newValue.message_id || !newValue.message)
|
|
910
|
-
) {
|
|
911
|
-
return invalidResult('Send message provider must include message id and content');
|
|
912
|
-
}
|
|
913
|
-
|
|
914
|
-
if (newValue.message_id) {
|
|
915
|
-
const messageIdResult = validateFieldWithResult('string', newValue.message_id);
|
|
916
|
-
|
|
917
|
-
if (!messageIdResult.isValid) {
|
|
918
|
-
return withContext(messageIdResult, 'Message id is invalid');
|
|
919
|
-
}
|
|
920
|
-
|
|
921
|
-
if (!newValue.message) {
|
|
922
|
-
return invalidResult('Message content is missing');
|
|
923
|
-
}
|
|
924
|
-
|
|
925
|
-
const messageResult = validateFieldWithResult(
|
|
926
|
-
newValue.message.type,
|
|
927
|
-
newValue.message.value
|
|
928
|
-
);
|
|
929
|
-
|
|
930
|
-
if (!messageResult.isValid) {
|
|
931
|
-
return withContext(messageResult, 'Message content is invalid');
|
|
932
|
-
}
|
|
933
|
-
}
|
|
934
|
-
|
|
935
|
-
if (newValue.use_args) {
|
|
936
|
-
if (newValue.args?.type !== 'nothing') {
|
|
937
|
-
if (!newValue.args) {
|
|
938
|
-
return invalidResult('Arguments are missing');
|
|
939
|
-
}
|
|
940
|
-
|
|
941
|
-
const argsResult = validateFieldWithResult(
|
|
942
|
-
newValue.args.type === 'hash' ? 'system-options' : newValue.args.type,
|
|
943
|
-
newValue.args.value
|
|
944
|
-
);
|
|
945
|
-
|
|
946
|
-
if (!argsResult.isValid) {
|
|
947
|
-
return withContext(argsResult, 'Arguments are invalid');
|
|
948
|
-
}
|
|
949
|
-
}
|
|
950
|
-
}
|
|
951
|
-
|
|
952
|
-
if (
|
|
953
|
-
(type === 'search-single' || type === 'search') &&
|
|
954
|
-
size(newValue.search_args) !== 0 &&
|
|
955
|
-
!validateFieldWithResult('system-options-with-operators', newValue.search_args).isValid
|
|
956
|
-
) {
|
|
957
|
-
return invalidResult('Search arguments are invalid');
|
|
958
|
-
}
|
|
959
|
-
|
|
960
|
-
const isUpdateOrCreate = type === 'update' || type === 'create';
|
|
961
|
-
|
|
962
|
-
if (isUpdateOrCreate) {
|
|
963
|
-
const areNormalArgsInvalid =
|
|
964
|
-
`${type}_args` in newValue &&
|
|
965
|
-
(size(newValue[`${type}_args`]) === 0 ||
|
|
966
|
-
!validateFieldWithResult('system-options', newValue[`${type}_args`]).isValid);
|
|
967
|
-
|
|
968
|
-
const areFreeFormArgsInvalid =
|
|
969
|
-
`${type}_args_freeform` in newValue &&
|
|
970
|
-
(size(newValue[`${type}_args_freeform`]) === 0 ||
|
|
971
|
-
!validateFieldWithResult('list-of-hashes', newValue[`${type}_args_freeform`]).isValid);
|
|
972
|
-
|
|
973
|
-
if (`${type}_args` in newValue && areNormalArgsInvalid && areFreeFormArgsInvalid) {
|
|
974
|
-
return invalidResult('Update/create arguments are invalid');
|
|
975
|
-
}
|
|
976
|
-
|
|
977
|
-
if (`${type}_args_freeform` in newValue && areFreeFormArgsInvalid && areNormalArgsInvalid) {
|
|
978
|
-
return invalidResult('Update/create arguments are invalid');
|
|
979
|
-
}
|
|
980
|
-
}
|
|
981
|
-
|
|
982
|
-
if (newValue?.type === 'factory') {
|
|
983
|
-
if (newValue.optionsChanged) {
|
|
984
|
-
return invalidResult('Factory options are not saved');
|
|
985
|
-
}
|
|
986
|
-
|
|
987
|
-
let options = true;
|
|
988
|
-
|
|
989
|
-
if (newValue.options) {
|
|
990
|
-
options = validateFieldWithResult('system-options', newValue.options).isValid;
|
|
991
|
-
}
|
|
992
|
-
|
|
993
|
-
// Type path and name are required
|
|
994
|
-
return resultFromBoolean(
|
|
995
|
-
!!(newValue.type && newValue.name && options),
|
|
996
|
-
'Factory provider is incomplete'
|
|
997
|
-
);
|
|
998
|
-
}
|
|
999
|
-
|
|
1000
|
-
if (newValue.record_requires_search_options && newValue.searchOptionsChanged) {
|
|
1001
|
-
return invalidResult('Search options must be saved');
|
|
1002
|
-
}
|
|
1003
|
-
|
|
1004
|
-
if (
|
|
1005
|
-
newValue.search_options &&
|
|
1006
|
-
!validateFieldWithResult('system-options', newValue.search_options).isValid
|
|
1007
|
-
) {
|
|
1008
|
-
return invalidResult('Search options are invalid');
|
|
1009
|
-
}
|
|
1010
|
-
|
|
1011
|
-
return resultFromBoolean(
|
|
1012
|
-
!!(newValue.type && newValue.name),
|
|
1013
|
-
'Provider type and name required'
|
|
1014
|
-
);
|
|
1015
|
-
}
|
|
1016
|
-
case 'context-selector': {
|
|
1017
|
-
if (isString(value)) {
|
|
1018
|
-
const cont: string[] = value.split(':');
|
|
1019
|
-
const contextResult = validateFieldWithResult('string', cont[0]);
|
|
1020
|
-
|
|
1021
|
-
if (!contextResult.isValid) {
|
|
1022
|
-
return withContext(contextResult, 'Context selector prefix is invalid');
|
|
1023
|
-
}
|
|
1024
|
-
|
|
1025
|
-
const nameResult = validateFieldWithResult('string', cont[1]);
|
|
1026
|
-
|
|
1027
|
-
if (!nameResult.isValid) {
|
|
1028
|
-
return withContext(nameResult, 'Context selector name is invalid');
|
|
1029
|
-
}
|
|
1030
|
-
|
|
1031
|
-
return validResult();
|
|
1032
|
-
}
|
|
1033
|
-
return resultFromBoolean(
|
|
1034
|
-
!!value?.iface_kind && !!value?.name,
|
|
1035
|
-
'Context selector requires iface_kind and name'
|
|
1036
|
-
);
|
|
1037
|
-
}
|
|
1038
|
-
case 'service-event': {
|
|
1039
|
-
const typeResult = validateFieldWithResult('type-selector', value);
|
|
1040
|
-
|
|
1041
|
-
if (!typeResult.isValid) {
|
|
1042
|
-
return withContext(typeResult, 'Service event type is invalid');
|
|
1043
|
-
}
|
|
1044
|
-
|
|
1045
|
-
if (
|
|
1046
|
-
!size(value.handlers) ||
|
|
1047
|
-
!every(
|
|
1048
|
-
value.handlers,
|
|
1049
|
-
(handler: any) => (handler.type === 'fsm' || handler.type === 'method') && handler.value
|
|
1050
|
-
)
|
|
1051
|
-
) {
|
|
1052
|
-
return invalidResult('Service event handlers are invalid');
|
|
1053
|
-
}
|
|
1054
|
-
|
|
1055
|
-
return validResult();
|
|
1056
|
-
}
|
|
1057
|
-
case 'service-events': {
|
|
1058
|
-
if (!isArray(value) || !size(value)) {
|
|
1059
|
-
return invalidResult('At least one service event is required');
|
|
1060
|
-
}
|
|
1061
|
-
|
|
1062
|
-
for (let i = 0; i < value.length; i++) {
|
|
1063
|
-
const serviceEventResult = validateFieldWithResult('service-event', value[i]);
|
|
1064
|
-
|
|
1065
|
-
if (!serviceEventResult.isValid) {
|
|
1066
|
-
return withContext(serviceEventResult, `Service event ${i} is invalid`);
|
|
1067
|
-
}
|
|
1068
|
-
}
|
|
1069
|
-
|
|
1070
|
-
return validResult();
|
|
1071
|
-
}
|
|
1072
|
-
case 'service-webhook': {
|
|
1073
|
-
if (
|
|
1074
|
-
!validateFieldWithResult('string', value?.name).isValid ||
|
|
1075
|
-
!validateFieldWithResult('string', value?.['rest-method']).isValid ||
|
|
1076
|
-
!validateFieldWithResult('string', value?.auth).isValid
|
|
1077
|
-
) {
|
|
1078
|
-
return invalidResult('Webhook name, method and auth are required');
|
|
1079
|
-
}
|
|
1080
|
-
|
|
1081
|
-
if (value.handler) {
|
|
1082
|
-
if (value.handler.type !== 'fsm' && value.handler.type !== 'method') {
|
|
1083
|
-
return invalidResult('Webhook handler type is invalid');
|
|
1084
|
-
}
|
|
1085
|
-
|
|
1086
|
-
const handlerResult = validateFieldWithResult('string', value.handler.value);
|
|
1087
|
-
|
|
1088
|
-
if (!handlerResult.isValid) {
|
|
1089
|
-
return withContext(handlerResult, 'Webhook handler value is invalid');
|
|
1090
|
-
}
|
|
1091
|
-
}
|
|
1092
|
-
|
|
1093
|
-
return validResult();
|
|
1094
|
-
}
|
|
1095
|
-
case 'service-webhooks': {
|
|
1096
|
-
if (!isArray(value) || !size(value)) {
|
|
1097
|
-
return invalidResult('At least one webhook is required');
|
|
1098
|
-
}
|
|
1099
|
-
|
|
1100
|
-
for (let i = 0; i < value.length; i++) {
|
|
1101
|
-
const webhookResult = validateFieldWithResult('service-webhook', value[i]);
|
|
1102
|
-
|
|
1103
|
-
if (!webhookResult.isValid) {
|
|
1104
|
-
return withContext(webhookResult, `Service webhook ${i} is invalid`);
|
|
1105
|
-
}
|
|
1106
|
-
}
|
|
1107
|
-
|
|
1108
|
-
return validResult();
|
|
1109
|
-
}
|
|
1110
|
-
case 'auto':
|
|
1111
|
-
case 'any': {
|
|
1112
|
-
// Only a STRING has YAML in it. An `auto` field's value is usually
|
|
1113
|
-
// already the structure it describes -- a hash the form's hash editor
|
|
1114
|
-
// wrote, a list from a list editor -- and `jsyaml.load()` stringifies
|
|
1115
|
-
// whatever it is handed first: an object becomes `"[object Object]"`,
|
|
1116
|
-
// which YAML then reads as the flow sequence `["object Object"]`. So the
|
|
1117
|
-
// auto-detected type came back `list`, the value was validated as a list,
|
|
1118
|
-
// and every hash stored in an `auto` field was reported *"Value must be a
|
|
1119
|
-
// list"* -- an invalid marker on a value that is fine. A list fared no
|
|
1120
|
-
// better: `[1, 2]` stringified to `"1,2"` and detected as a string.
|
|
1121
|
-
//
|
|
1122
|
-
// Every other branch that accepts either shape already parses through
|
|
1123
|
-
// `maybeParseYaml`, which passes a non-string straight through; this one
|
|
1124
|
-
// reached for `jsyaml` directly. It cannot use `maybeParseYaml` as-is
|
|
1125
|
-
// because that reports a YAML error as an absent value, and "not valid
|
|
1126
|
-
// YAML" and "empty" are different answers here.
|
|
1127
|
-
let parsedData: any = value;
|
|
1128
|
-
if (isString(value)) {
|
|
1129
|
-
try {
|
|
1130
|
-
parsedData = jsyaml.load(value);
|
|
1131
|
-
} catch (e) {
|
|
1132
|
-
return invalidResult('Value is not valid YAML');
|
|
1133
|
-
}
|
|
1134
|
-
}
|
|
1135
|
-
|
|
1136
|
-
/* A FALSY value is not an ABSENT one. `null`, `0`, `false` and `""` are
|
|
1137
|
-
all values an author may hold in an `auto`/`any` field — a test
|
|
1138
|
-
assertion expecting a count of zero, a flag that is off, or a blank
|
|
1139
|
-
string — and the truthiness gate that used to stand here refused every
|
|
1140
|
-
one of them as *"Value is empty"*. It surfaced on an assertion's
|
|
1141
|
-
Expected Value holding `null`: opening it reported *"Value for argument
|
|
1142
|
-
1 ("any") is invalid: Value is empty"* on the value the author had
|
|
1143
|
-
deliberately chosen. Only `undefined` is actually empty.
|
|
1144
|
-
|
|
1145
|
-
`null` and `""` are answered here rather than delegated, for two
|
|
1146
|
-
different reasons: `getTypeFromValue(null)` answers `auto`, which would
|
|
1147
|
-
re-enter this very branch, and the `string` validator rejects `""`
|
|
1148
|
-
because that is the rule for a REQUIRED text field — a different
|
|
1149
|
-
question from whether an untyped field may hold a blank string. */
|
|
1150
|
-
if (parsedData === undefined) {
|
|
1151
|
-
return invalidResult('Value is empty');
|
|
1152
|
-
}
|
|
1153
|
-
|
|
1154
|
-
if (parsedData === null || parsedData === '') {
|
|
1155
|
-
return validResult();
|
|
1156
|
-
}
|
|
1157
|
-
|
|
1158
|
-
/* Validate what was PARSED, against the type detected from the same
|
|
1159
|
-
parse. Validating the raw `value` instead made the two disagree
|
|
1160
|
-
whenever parsing changed the shape: typing `1` into an `auto` field
|
|
1161
|
-
parsed to the number 1, detected `int`, and then validated the STRING
|
|
1162
|
-
"1" against it — "Value must be an integer", on a value that is one.
|
|
1163
|
-
The author saw their field go invalid on the first character they
|
|
1164
|
-
typed. */
|
|
1165
|
-
return withContext(
|
|
1166
|
-
validateFieldWithResult(getTypeFromValue(parsedData), parsedData),
|
|
1167
|
-
'Auto-detected type is invalid'
|
|
1168
|
-
);
|
|
1169
|
-
}
|
|
1170
|
-
case 'processor': {
|
|
1171
|
-
if (!value || !value['processor-input-type'] || !value['processor-output-type']) {
|
|
1172
|
-
return invalidResult('Processor input and output types are required');
|
|
1173
|
-
}
|
|
1174
|
-
// Validate the input and output types
|
|
1175
|
-
if (value?.['processor-input-type']) {
|
|
1176
|
-
const inputResult = validateFieldWithResult(
|
|
1177
|
-
'type-selector',
|
|
1178
|
-
value?.['processor-input-type']
|
|
1179
|
-
);
|
|
1180
|
-
|
|
1181
|
-
if (!inputResult.isValid) {
|
|
1182
|
-
return withContext(inputResult, 'Processor input type is invalid');
|
|
1183
|
-
}
|
|
1184
|
-
}
|
|
1185
|
-
|
|
1186
|
-
if (value?.['processor-output-type']) {
|
|
1187
|
-
const outputResult = validateFieldWithResult(
|
|
1188
|
-
'type-selector',
|
|
1189
|
-
value?.['processor-output-type']
|
|
1190
|
-
);
|
|
1191
|
-
|
|
1192
|
-
if (!outputResult.isValid) {
|
|
1193
|
-
return withContext(outputResult, 'Processor output type is invalid');
|
|
1194
|
-
}
|
|
1195
|
-
}
|
|
1196
|
-
|
|
1197
|
-
return validResult();
|
|
1198
|
-
}
|
|
1199
|
-
case 'processor-mappings': {
|
|
1200
|
-
// processor-mappings is an array of field mappings
|
|
1201
|
-
// Each mapping must have an outputPath (the target field being mapped)
|
|
1202
|
-
// and either an inputPath (source field) or options configured
|
|
1203
|
-
if (!isArray(value)) {
|
|
1204
|
-
return canBeNull ? validResult() : invalidResult('Processor mappings must be a list');
|
|
1205
|
-
}
|
|
1206
|
-
|
|
1207
|
-
for (let i = 0; i < value.length; i++) {
|
|
1208
|
-
const mapping = value[i];
|
|
1209
|
-
|
|
1210
|
-
if (!mapping || !isObject(mapping)) {
|
|
1211
|
-
return invalidResult(`Mapping at index ${i} is invalid`);
|
|
1212
|
-
}
|
|
1213
|
-
|
|
1214
|
-
// outputPath is always required - it identifies which output field is being mapped
|
|
1215
|
-
const outputPathResult = validateFieldWithResult('string', mapping.outputPath);
|
|
1216
|
-
|
|
1217
|
-
if (!outputPathResult.isValid) {
|
|
1218
|
-
return withContext(outputPathResult, `Mapping ${i} output path is invalid`);
|
|
1219
|
-
}
|
|
1220
|
-
|
|
1221
|
-
// A mapping must have either an inputPath or options (or both)
|
|
1222
|
-
const hasInputPath = mapping.inputPath && mapping.inputPath !== '';
|
|
1223
|
-
const hasOptions = mapping.options && size(mapping.options) > 0;
|
|
1224
|
-
|
|
1225
|
-
if (!hasInputPath && !hasOptions) {
|
|
1226
|
-
return invalidResult(
|
|
1227
|
-
`Mapping for "${mapping.outputPath}" must have an input path or options configured`
|
|
1228
|
-
);
|
|
1229
|
-
}
|
|
1230
|
-
}
|
|
1231
|
-
|
|
1232
|
-
return validResult();
|
|
1233
|
-
}
|
|
1234
|
-
case 'tool-catalog': {
|
|
1235
|
-
// tool-catalog is a flat string[] of selectors; each selector is one of:
|
|
1236
|
-
// "*" — all tools from every source
|
|
1237
|
-
// "system:*" — all Qorus system tools
|
|
1238
|
-
// "system:<tool>" — a specific system tool
|
|
1239
|
-
// "<connection>" — all tools from a connection
|
|
1240
|
-
// "<connection>/<tool>" — a specific tool from a connection
|
|
1241
|
-
if (!isArray(value)) {
|
|
1242
|
-
return canBeNull ? validResult() : invalidResult('Tool catalog must be a list');
|
|
1243
|
-
}
|
|
1244
|
-
|
|
1245
|
-
for (let i = 0; i < value.length; i++) {
|
|
1246
|
-
const selector = value[i];
|
|
1247
|
-
if (typeof selector !== 'string' || selector.length === 0) {
|
|
1248
|
-
return invalidResult(`Tool selector at index ${i} must be a non-empty string`);
|
|
1249
|
-
}
|
|
1250
|
-
}
|
|
1251
|
-
|
|
1252
|
-
return validResult();
|
|
1253
|
-
}
|
|
1254
|
-
case 'fsm-list': {
|
|
1255
|
-
if (!isArray(value)) {
|
|
1256
|
-
return invalidResult('FSM list must be an array');
|
|
1257
|
-
}
|
|
1258
|
-
|
|
1259
|
-
for (let i = 0; i < value.length; i++) {
|
|
1260
|
-
const itemResult = validateFieldWithResult('string', value[i]?.name);
|
|
1261
|
-
|
|
1262
|
-
if (!itemResult.isValid) {
|
|
1263
|
-
return withContext(itemResult, `FSM entry ${i} name is invalid`);
|
|
1264
|
-
}
|
|
1265
|
-
}
|
|
1266
|
-
|
|
1267
|
-
return validResult();
|
|
1268
|
-
}
|
|
1269
|
-
case 'api-manager': {
|
|
1270
|
-
if (!value) {
|
|
1271
|
-
return invalidResult('API manager value is missing');
|
|
1272
|
-
}
|
|
1273
|
-
|
|
1274
|
-
const factoryResult = validateFieldWithResult('string', value.factory);
|
|
1275
|
-
|
|
1276
|
-
if (!factoryResult.isValid) {
|
|
1277
|
-
return withContext(factoryResult, 'API manager factory is invalid');
|
|
1278
|
-
}
|
|
1279
|
-
|
|
1280
|
-
const endpointsResult = validateFieldWithResult('api-endpoints', value.endpoints);
|
|
1281
|
-
|
|
1282
|
-
if (!endpointsResult.isValid) {
|
|
1283
|
-
return withContext(endpointsResult, 'API manager endpoints are invalid');
|
|
1284
|
-
}
|
|
1285
|
-
|
|
1286
|
-
return validResult();
|
|
1287
|
-
}
|
|
1288
|
-
case 'api-endpoints': {
|
|
1289
|
-
if (!isArray(value) || !size(value)) {
|
|
1290
|
-
return invalidResult('At least one API endpoint is required');
|
|
1291
|
-
}
|
|
1292
|
-
|
|
1293
|
-
for (let i = 0; i < value.length; i++) {
|
|
1294
|
-
const endpointResult = validateFieldWithResult('string', value[i]?.value);
|
|
1295
|
-
|
|
1296
|
-
if (!endpointResult.isValid) {
|
|
1297
|
-
return withContext(endpointResult, `Endpoint ${i} value is invalid`);
|
|
1298
|
-
}
|
|
1299
|
-
|
|
1300
|
-
const authorizationResult = validateFieldWithResult(
|
|
1301
|
-
'api-endpoint-authorization',
|
|
1302
|
-
value[i]?.authorization,
|
|
1303
|
-
undefined,
|
|
1304
|
-
true
|
|
1305
|
-
);
|
|
1306
|
-
|
|
1307
|
-
if (!authorizationResult.isValid) {
|
|
1308
|
-
return withContext(authorizationResult, `Endpoint ${i} authorization is invalid`);
|
|
1309
|
-
}
|
|
1310
|
-
}
|
|
1311
|
-
|
|
1312
|
-
return validResult();
|
|
1313
|
-
}
|
|
1314
|
-
case 'api-endpoint-authorization': {
|
|
1315
|
-
if (!value) {
|
|
1316
|
-
return canBeNull ? validResult() : invalidResult('Authorization override is missing');
|
|
1317
|
-
}
|
|
1318
|
-
|
|
1319
|
-
if (typeof value !== 'object' || isArray(value)) {
|
|
1320
|
-
return invalidResult('Authorization override must be an object');
|
|
1321
|
-
}
|
|
1322
|
-
|
|
1323
|
-
if (value.mode !== undefined && !['merge', 'replace'].includes(value.mode)) {
|
|
1324
|
-
return invalidResult('Authorization mode must be merge or replace');
|
|
1325
|
-
}
|
|
1326
|
-
|
|
1327
|
-
if (value.allow_anonymous !== undefined && typeof value.allow_anonymous !== 'boolean') {
|
|
1328
|
-
return invalidResult('Authorization allow_anonymous must be a boolean');
|
|
1329
|
-
}
|
|
1330
|
-
|
|
1331
|
-
if (value.roles !== undefined) {
|
|
1332
|
-
if (!isArray(value.roles)) {
|
|
1333
|
-
return invalidResult('Authorization roles must be a list');
|
|
1334
|
-
}
|
|
1335
|
-
|
|
1336
|
-
for (let i = 0; i < value.roles.length; i++) {
|
|
1337
|
-
const roleResult = validateFieldWithResult('string', value.roles[i]);
|
|
1338
|
-
|
|
1339
|
-
if (!roleResult.isValid) {
|
|
1340
|
-
return withContext(roleResult, `Authorization role ${i} is invalid`);
|
|
1341
|
-
}
|
|
1342
|
-
}
|
|
1343
|
-
}
|
|
1344
|
-
|
|
1345
|
-
return validResult();
|
|
1346
|
-
}
|
|
1347
|
-
case 'options':
|
|
1348
|
-
case 'pipeline-options':
|
|
1349
|
-
case 'mapper-options':
|
|
1350
|
-
case 'system-options': {
|
|
1351
|
-
const getIsValid = (
|
|
1352
|
-
options?: TQorusForm,
|
|
1353
|
-
optionSchema: IQorusFormSchema = {}
|
|
1354
|
-
): IValidationResult => {
|
|
1355
|
-
if (!options || size(options) === 0) {
|
|
1356
|
-
if (!canBeNull) {
|
|
1357
|
-
return invalidResult('Options are required');
|
|
1358
|
-
}
|
|
1359
|
-
|
|
1360
|
-
return validResult();
|
|
1361
|
-
}
|
|
1362
|
-
|
|
1363
|
-
// Check if all required options are resolved by the current values
|
|
1364
|
-
const [unresolvedRequiredOption] = getUnresolvedRequiredOptions(optionSchema, options);
|
|
1365
|
-
|
|
1366
|
-
if (unresolvedRequiredOption) {
|
|
1367
|
-
return unresolvedRequiredOption.validation
|
|
1368
|
-
? withContext(
|
|
1369
|
-
unresolvedRequiredOption.validation,
|
|
1370
|
-
`Option ${unresolvedRequiredOption.name} is invalid`
|
|
1371
|
-
)
|
|
1372
|
-
: invalidResult(
|
|
1373
|
-
getUnresolvedRequiredOptionReason(unresolvedRequiredOption, optionSchema)
|
|
1374
|
-
);
|
|
1375
|
-
}
|
|
1376
|
-
|
|
1377
|
-
for (const option of Object.keys(options)) {
|
|
1378
|
-
const optionData = options[option];
|
|
1379
|
-
const optionType = ((typeof optionData === 'object' ? optionData?.type : undefined) ||
|
|
1380
|
-
(optionSchema?.[option] as TQorusFormFieldSchema)?.ui_type ||
|
|
1381
|
-
(optionSchema?.[option] as TQorusFormFieldSchema)?.type) as string;
|
|
1382
|
-
const optionValue =
|
|
1383
|
-
optionData && typeof optionData === 'object' ? optionData.value : optionData;
|
|
1384
|
-
|
|
1385
|
-
if (
|
|
1386
|
-
!(optionSchema?.[option] as TQorusFormFieldSchema)?.required &&
|
|
1387
|
-
!isValueDefined(optionType, optionValue)
|
|
1388
|
-
) {
|
|
1389
|
-
continue;
|
|
1390
|
-
}
|
|
1391
|
-
|
|
1392
|
-
/* An option whose dependencies are not fulfilled is not part of this
|
|
1393
|
-
object, so it cannot make the object invalid.
|
|
1394
|
-
|
|
1395
|
-
The form already takes that view — it HIDES such an option — and
|
|
1396
|
-
the two disagreeing is a trap with no way out of it: a test whose
|
|
1397
|
-
subject moved from a versioned kind to a service keeps the
|
|
1398
|
-
`subject_iface_version` it no longer has a field for, and Submit
|
|
1399
|
-
goes dead naming an option that is nowhere on screen. Nulling the
|
|
1400
|
-
value does not help either, because a null is still a value the
|
|
1401
|
-
loop reaches.
|
|
1402
|
-
|
|
1403
|
-
A REQUIRED option with unfulfilled dependencies is unaffected:
|
|
1404
|
-
`getUnresolvedRequiredOptions` above reports it as `dependency`
|
|
1405
|
-
before this loop runs, and it is the only owner of that question.
|
|
1406
|
-
This branch was therefore only ever able to fail an option the
|
|
1407
|
-
author could not see and did not need. */
|
|
1408
|
-
if (
|
|
1409
|
-
(optionSchema?.[option] as TQorusFormFieldSchema)?.depends_on &&
|
|
1410
|
-
!hasAllDependenciesFullfilled(
|
|
1411
|
-
(optionSchema[option] as TQorusFormFieldSchema).depends_on,
|
|
1412
|
-
options,
|
|
1413
|
-
optionSchema
|
|
1414
|
-
)
|
|
1415
|
-
) {
|
|
1416
|
-
continue;
|
|
1417
|
-
}
|
|
1418
|
-
|
|
1419
|
-
const optionResult =
|
|
1420
|
-
typeof optionData !== 'object'
|
|
1421
|
-
? validateFieldWithResult(getTypeFromValue(optionData), optionData)
|
|
1422
|
-
: validateFieldWithResult(optionData.type, optionData.value, {
|
|
1423
|
-
...(optionSchema?.[option] as any),
|
|
1424
|
-
optionSchema,
|
|
1425
|
-
options,
|
|
1426
|
-
isFunction: optionData.is_expression,
|
|
1427
|
-
});
|
|
1428
|
-
|
|
1429
|
-
if (!optionResult.isValid) {
|
|
1430
|
-
return withContext(optionResult, `Option ${option} is invalid`);
|
|
1431
|
-
}
|
|
1432
|
-
}
|
|
1433
|
-
|
|
1434
|
-
return validResult();
|
|
1435
|
-
};
|
|
1436
|
-
|
|
1437
|
-
if (isArray(value)) {
|
|
1438
|
-
for (let i = 0; i < value.length; i++) {
|
|
1439
|
-
const optionResult = getIsValid(value[i], field?.optionSchema);
|
|
1440
|
-
|
|
1441
|
-
if (!optionResult.isValid) {
|
|
1442
|
-
return withContext(optionResult, `Option set ${i} is invalid`);
|
|
1443
|
-
}
|
|
1444
|
-
}
|
|
1445
|
-
|
|
1446
|
-
return validResult();
|
|
1447
|
-
}
|
|
1448
|
-
|
|
1449
|
-
return getIsValid(value, field?.optionSchema);
|
|
1450
|
-
}
|
|
1451
|
-
case 'system-options-with-operators': {
|
|
1452
|
-
const isValid = (val: TQorusForm): IValidationResult => {
|
|
1453
|
-
if (!val || size(val) === 0) {
|
|
1454
|
-
if (canBeNull) {
|
|
1455
|
-
return validResult();
|
|
1456
|
-
}
|
|
1457
|
-
|
|
1458
|
-
return invalidResult('Options with operators are required');
|
|
1459
|
-
}
|
|
1460
|
-
|
|
1461
|
-
for (const option of Object.keys(val)) {
|
|
1462
|
-
const optionData = val[option];
|
|
1463
|
-
const optionResult =
|
|
1464
|
-
typeof optionData !== 'object'
|
|
1465
|
-
? validateFieldWithResult(getTypeFromValue(optionData), optionData)
|
|
1466
|
-
: validateFieldWithResult(optionData.type, optionData.value);
|
|
1467
|
-
|
|
1468
|
-
if (!optionResult.isValid) {
|
|
1469
|
-
return withContext(optionResult, `Option ${option} is invalid`);
|
|
1470
|
-
}
|
|
1471
|
-
|
|
1472
|
-
if (
|
|
1473
|
-
!optionData.op ||
|
|
1474
|
-
!fixOperatorValue(optionData.op).every(
|
|
1475
|
-
(operator) => validateFieldWithResult('string', operator).isValid
|
|
1476
|
-
)
|
|
1477
|
-
) {
|
|
1478
|
-
return invalidResult(`Operators for option ${option} are invalid`);
|
|
1479
|
-
}
|
|
1480
|
-
}
|
|
1481
|
-
|
|
1482
|
-
return validResult();
|
|
1483
|
-
};
|
|
1484
|
-
|
|
1485
|
-
if (isArray(value)) {
|
|
1486
|
-
for (let i = 0; i < value.length; i++) {
|
|
1487
|
-
const optionResult = isValid(value[i]);
|
|
1488
|
-
|
|
1489
|
-
if (!optionResult.isValid) {
|
|
1490
|
-
return withContext(optionResult, `Option set ${i} is invalid`);
|
|
1491
|
-
}
|
|
1492
|
-
}
|
|
1493
|
-
|
|
1494
|
-
return validResult();
|
|
1495
|
-
}
|
|
1496
|
-
|
|
1497
|
-
return isValid(value);
|
|
1498
|
-
}
|
|
1499
|
-
case 'byte-size': {
|
|
1500
|
-
if (typeof value !== 'string') return invalidResult('Byte size must be a string');
|
|
1501
|
-
|
|
1502
|
-
const [bytes, sizeUnit] = splitByteSize(value);
|
|
1503
|
-
|
|
1504
|
-
const bytesResult = validateFieldWithResult('number', bytes);
|
|
1505
|
-
|
|
1506
|
-
if (!bytesResult.isValid) {
|
|
1507
|
-
return withContext(bytesResult, 'Byte size numeric part is invalid');
|
|
1508
|
-
}
|
|
1509
|
-
|
|
1510
|
-
const sizeResult = validateFieldWithResult('string', sizeUnit);
|
|
1511
|
-
|
|
1512
|
-
if (!sizeResult.isValid) {
|
|
1513
|
-
return withContext(sizeResult, 'Byte size unit is invalid');
|
|
1514
|
-
}
|
|
1515
|
-
|
|
1516
|
-
return validResult();
|
|
1517
|
-
}
|
|
1518
|
-
case 'timeout': {
|
|
1519
|
-
// An integer count of milliseconds — the unit selector is display-only,
|
|
1520
|
-
// so the stored value validates as an int.
|
|
1521
|
-
const msResult = validateFieldWithResult('int', value);
|
|
1522
|
-
|
|
1523
|
-
if (!msResult.isValid) {
|
|
1524
|
-
return withContext(msResult, 'Timeout must be a whole number of milliseconds');
|
|
1525
|
-
}
|
|
1526
|
-
|
|
1527
|
-
return validResult();
|
|
1528
|
-
}
|
|
1529
|
-
case 'url':
|
|
1530
|
-
case 'uri': {
|
|
1531
|
-
const protocolResult = validateFieldWithResult('string', getProtocol(value));
|
|
1532
|
-
|
|
1533
|
-
if (!protocolResult.isValid) {
|
|
1534
|
-
return withContext(protocolResult, 'URL protocol is invalid');
|
|
1535
|
-
}
|
|
1536
|
-
|
|
1537
|
-
const addressResult = validateFieldWithResult('string', getAddress(value));
|
|
1538
|
-
|
|
1539
|
-
if (!addressResult.isValid) {
|
|
1540
|
-
return withContext(addressResult, 'URL address is invalid');
|
|
1541
|
-
}
|
|
1542
|
-
|
|
1543
|
-
return validResult();
|
|
1544
|
-
}
|
|
1545
|
-
case 'schema-definition': {
|
|
1546
|
-
// The minimal NEW_FIELD.md shape check, so malformed definitions can't
|
|
1547
|
-
// silently save through FormEngine.
|
|
1548
|
-
if (!isObject(value)) {
|
|
1549
|
-
return invalidResult('Schema definition must be an object');
|
|
1550
|
-
}
|
|
1551
|
-
if (!isObject((value as { schema?: unknown }).schema)) {
|
|
1552
|
-
return invalidResult('Schema definition must contain a `schema` section');
|
|
1553
|
-
}
|
|
1554
|
-
return validResult();
|
|
1555
|
-
}
|
|
1556
|
-
case 'expression': {
|
|
1557
|
-
const castedValue = value as {
|
|
1558
|
-
value?: { exp?: string; args?: any[] };
|
|
1559
|
-
is_expression?: boolean;
|
|
1560
|
-
type?: string;
|
|
1561
|
-
};
|
|
1562
|
-
const expressions = readExpressionCatalogue(field);
|
|
1563
|
-
|
|
1564
|
-
// Expressions validation is complicated and needs to follow the following rules
|
|
1565
|
-
// 1. If the expression is empty, it is invalid
|
|
1566
|
-
// 2. If the expression has a type, it means its a normal argument (sub expressions don't have type)
|
|
1567
|
-
// 3. If the expression has no type and `exp` is present, it is a sub expression and must be validated as such
|
|
1568
|
-
// 4. If there are no `args` we need to check if the expression actually has any required arguments or what is the `min_args` property
|
|
1569
|
-
|
|
1570
|
-
// 1. If the expression is empty
|
|
1571
|
-
//
|
|
1572
|
-
// Checked BEFORE the catalogue guard below, and deliberately: an
|
|
1573
|
-
// expression with no value, or with no operation chosen, is incomplete on
|
|
1574
|
-
// its own terms. Nothing in the catalogue can make it valid, so making
|
|
1575
|
-
// these two answers wait for a network fetch meant the same option
|
|
1576
|
-
// reported valid or invalid depending on whether that fetch had landed —
|
|
1577
|
-
// the field's own "show invalid only" filter listed a different set of
|
|
1578
|
-
// rows on a fast machine than on a slow one.
|
|
1579
|
-
if (!castedValue) {
|
|
1580
|
-
return invalidResult('Expression value is empty');
|
|
1581
|
-
}
|
|
1582
|
-
|
|
1583
|
-
if (!castedValue.value?.exp) {
|
|
1584
|
-
return invalidResult('Expression operation is required');
|
|
1585
|
-
}
|
|
1586
|
-
|
|
1587
|
-
// Everything past this point needs the expression's definition, which
|
|
1588
|
-
// only the catalogue can supply. Until it loads there is nothing to check
|
|
1589
|
-
// against, so an expression that names an operation is left alone rather
|
|
1590
|
-
// than reported against a catalogue we do not have.
|
|
1591
|
-
if (!size(expressions)) {
|
|
1592
|
-
return validResult();
|
|
1593
|
-
}
|
|
1594
|
-
|
|
1595
|
-
// Get the expression definition from the catalogue
|
|
1596
|
-
const expressionDefinition = expressions.find(
|
|
1597
|
-
(expr: any) => expr.name === castedValue.value?.exp
|
|
1598
|
-
);
|
|
1599
|
-
|
|
1600
|
-
if (!expressionDefinition) {
|
|
1601
|
-
return invalidResult(`Expression definition ${String(castedValue.value?.exp)} not found`);
|
|
1602
|
-
}
|
|
1603
|
-
|
|
1604
|
-
// If the expression has no required args, we can consider it valid
|
|
1605
|
-
const hasRequiredArgs = expressionDefinition.args?.some((arg: any) => arg.required);
|
|
1606
|
-
|
|
1607
|
-
if (!hasRequiredArgs && size(castedValue.value?.args || []) === 0) {
|
|
1608
|
-
return validResult();
|
|
1609
|
-
}
|
|
1610
|
-
|
|
1611
|
-
// If there are no args provided but the expression requires some (normal expressions require at least 1 arg
|
|
1612
|
-
// because we checked for required args earlier), or min_args is set
|
|
1613
|
-
if (size(castedValue.value?.args || []) < (expressionDefinition.min_args || 1)) {
|
|
1614
|
-
return invalidResult('Not enough arguments provided');
|
|
1615
|
-
}
|
|
1616
|
-
|
|
1617
|
-
// Now we need to validate each argument, either as a normal value or as a sub-expression
|
|
1618
|
-
const args = castedValue.value?.args ?? [];
|
|
1619
|
-
|
|
1620
|
-
for (let index = 0; index < args.length; index++) {
|
|
1621
|
-
const argValue: any = args[index];
|
|
1622
|
-
const argDefinition = expressionDefinition.varargs
|
|
1623
|
-
? expressionDefinition.args[0]
|
|
1624
|
-
: expressionDefinition.args[index];
|
|
1625
|
-
/* The argument's name for the message.
|
|
1626
|
-
|
|
1627
|
-
`display_name` is what a catalogue MAY carry; the served one carries
|
|
1628
|
-
`name`, so every message about an argument read "argument 1
|
|
1629
|
-
("undefined") is invalid" and named a field that does not exist. */
|
|
1630
|
-
const argLabel =
|
|
1631
|
-
argDefinition?.display_name ?? argDefinition?.name ?? `argument ${index + 1}`;
|
|
1632
|
-
|
|
1633
|
-
/* An explicit null is a VALUE, and DPQL says so: `null` is a literal
|
|
1634
|
-
that parses, serializes and round-trips like any other.
|
|
1635
|
-
|
|
1636
|
-
Treated as a missing one, it made "this returns no value"
|
|
1637
|
-
unsayable. Typing `null` into the text editor produces the literal
|
|
1638
|
-
expression `{exp: "value", args: [null]}`; the visual view then
|
|
1639
|
-
called it invalid and refused to render a summary, and a raw null
|
|
1640
|
-
argument crashed the validator outright on `argValue.type`. Reported
|
|
1641
|
-
from the live IDE by an author with no other way to assert that a
|
|
1642
|
-
service method returns nothing.
|
|
1643
|
-
|
|
1644
|
-
Only an EXPLICIT null counts. An argument that is simply absent, or
|
|
1645
|
-
an envelope holding `undefined`, is still missing — which is the
|
|
1646
|
-
distinction the author is making when they write it. */
|
|
1647
|
-
if (argValue === null || (isObject(argValue) && (argValue as any).value === null)) {
|
|
1648
|
-
continue;
|
|
1649
|
-
}
|
|
1650
|
-
|
|
1651
|
-
if (!argValue?.value && !argDefinition?.required) {
|
|
1652
|
-
continue;
|
|
1653
|
-
}
|
|
1654
|
-
|
|
1655
|
-
if (argValue?.is_expression) {
|
|
1656
|
-
const result = validateFieldWithResult('expression', argValue, {
|
|
1657
|
-
expressions,
|
|
1658
|
-
has_to_have_value: argDefinition?.required,
|
|
1659
|
-
});
|
|
1660
|
-
|
|
1661
|
-
if (!result.isValid) {
|
|
1662
|
-
return withContext(
|
|
1663
|
-
result,
|
|
1664
|
-
`Sub-expression for argument ${index + 1} ("${argLabel}") is invalid`
|
|
1665
|
-
);
|
|
1666
|
-
}
|
|
1667
|
-
|
|
1668
|
-
continue;
|
|
1669
|
-
}
|
|
1670
|
-
|
|
1671
|
-
/* A slot with no operand at all is judged as what it is — a missing
|
|
1672
|
-
value — rather than read for a `type` it does not have.
|
|
1673
|
-
|
|
1674
|
-
An operand that HOLDS something is judged by the envelope's own type,
|
|
1675
|
-
or — when the envelope carries none (a raw parse operand widened
|
|
1676
|
-
without a `ui_type`, a slot reset by a type change) — by the type the
|
|
1677
|
-
catalogue declares. Without that fallback `_validateField` refuses it
|
|
1678
|
-
for "Missing type" however right the value is. */
|
|
1679
|
-
const operandType =
|
|
1680
|
-
argValue?.type ?? (argValue?.value === undefined ? undefined : argDefinition?.ui_type);
|
|
1681
|
-
const result = validateFieldWithResult(operandType, argValue?.value, {
|
|
1682
|
-
expressions,
|
|
1683
|
-
allowed_values: argDefinition?.allowed_values,
|
|
1684
|
-
element_allowed_values: argDefinition?.element_allowed_values,
|
|
1685
|
-
has_to_have_value: argDefinition?.required,
|
|
1686
|
-
});
|
|
1687
|
-
|
|
1688
|
-
if (!result.isValid) {
|
|
1689
|
-
return withContext(
|
|
1690
|
-
result,
|
|
1691
|
-
`Value for argument ${index + 1} ("${argLabel}") is invalid`
|
|
1692
|
-
);
|
|
1693
|
-
}
|
|
1694
|
-
}
|
|
1695
|
-
|
|
1696
|
-
return validResult();
|
|
1697
|
-
}
|
|
1698
|
-
case 'nothing':
|
|
1699
|
-
return invalidResult('Nothing is not a valid value');
|
|
1700
|
-
default:
|
|
1701
|
-
return validResult();
|
|
1702
|
-
}
|
|
1703
|
-
};
|
|
1704
|
-
|
|
1705
|
-
/**
|
|
1706
|
-
* Read one arg out of a hash, whichever of the two legitimate shapes it is in.
|
|
1707
|
-
*
|
|
1708
|
-
* A hash reaches validation both as plain values (`{name: 'init'}` — what the
|
|
1709
|
-
* server sends, and what a list-of-hash row holds until it is edited) and as
|
|
1710
|
-
* typed envelopes (`{name: {type: 'string', value: 'init'}}` — what FormEngine
|
|
1711
|
-
* emits once the row has been through the form). `fixOptions` already
|
|
1712
|
-
* reconciles the two for RENDERING; validation never learned the same rule, so
|
|
1713
|
-
* a freshly-loaded row read as invalid while an edited one read as valid. That
|
|
1714
|
-
* is what made every complete service-method row report "Hash arguments are
|
|
1715
|
-
* invalid" while showing correct values.
|
|
1716
|
-
*
|
|
1717
|
-
* The `'value' in arg` test is the one `fixOptions` uses, including its known
|
|
1718
|
-
* edge — an arg whose own value is a hash carrying a `value` key. Agreeing with
|
|
1719
|
-
* the renderer beats being differently wrong from it.
|
|
1720
|
-
*/
|
|
1721
|
-
export const readArgValue = (arg: any): any =>
|
|
1722
|
-
isObject(arg) && 'value' in (arg as object) ? (arg as { value: unknown }).value : arg;
|
|
1723
|
-
|
|
1724
|
-
// Memoized version
|
|
1725
|
-
export const validateFieldWithResult: (
|
|
1726
|
-
type: string,
|
|
1727
|
-
value?: any,
|
|
1728
|
-
field?: IFieldValidationProps,
|
|
1729
|
-
canBeNull?: boolean
|
|
1730
|
-
) => IValidationResult = memoize(
|
|
1731
|
-
_validateField,
|
|
1732
|
-
(type, value, field, canBeNull) =>
|
|
1733
|
-
`${type}-${JSON.stringify(value)}-${JSON.stringify(field)}-${canBeNull}`
|
|
1734
|
-
);
|
|
1735
|
-
|
|
1736
|
-
export const validateField: (
|
|
1737
|
-
type: string,
|
|
1738
|
-
value?: any,
|
|
1739
|
-
field?: IFieldValidationProps,
|
|
1740
|
-
canBeNull?: boolean
|
|
1741
|
-
) => boolean = (type, value, field, canBeNull) =>
|
|
1742
|
-
validateFieldWithResult(type, value, field, canBeNull).isValid;
|
|
1743
|
-
|
|
1744
|
-
export const maybeParseYaml = (yaml: any): any => {
|
|
1745
|
-
if (yaml === true || yaml === false) {
|
|
1746
|
-
return yaml;
|
|
1747
|
-
}
|
|
1748
|
-
if (isNumber(yaml)) {
|
|
1749
|
-
return yaml;
|
|
1750
|
-
}
|
|
1751
|
-
if (isDate(yaml)) {
|
|
1752
|
-
return yaml;
|
|
1753
|
-
}
|
|
1754
|
-
if (yaml === undefined || yaml === null || yaml === '') {
|
|
1755
|
-
return undefined;
|
|
1756
|
-
}
|
|
1757
|
-
if (!isString(yaml)) {
|
|
1758
|
-
return yaml;
|
|
1759
|
-
}
|
|
1760
|
-
|
|
1761
|
-
let yamlCorrect = true;
|
|
1762
|
-
let parsedData: any;
|
|
1763
|
-
try {
|
|
1764
|
-
parsedData = jsyaml.load(String(yaml));
|
|
1765
|
-
} catch (e) {
|
|
1766
|
-
yamlCorrect = false;
|
|
1767
|
-
}
|
|
1768
|
-
|
|
1769
|
-
if (!yamlCorrect) {
|
|
1770
|
-
return undefined;
|
|
1771
|
-
}
|
|
1772
|
-
|
|
1773
|
-
if (!isNull(parsedData) && !isUndefined(parsedData)) {
|
|
1774
|
-
return parsedData;
|
|
1775
|
-
}
|
|
1776
|
-
|
|
1777
|
-
return undefined;
|
|
1778
|
-
};
|
|
1779
|
-
|
|
1780
|
-
export const isValueSet = (value: any, canBeNull?: boolean): boolean => {
|
|
1781
|
-
if (canBeNull) {
|
|
1782
|
-
return !isUndefined(value);
|
|
1783
|
-
}
|
|
1784
|
-
|
|
1785
|
-
return !isNull(value) && !isUndefined(value);
|
|
1786
|
-
};
|
|
1787
|
-
|
|
1788
|
-
export const getValueOrDefaultValue = (value: any, defaultValue: any, canBeNull?: boolean) => {
|
|
1789
|
-
if (isValueSet(value, canBeNull)) {
|
|
1790
|
-
return value;
|
|
1791
|
-
}
|
|
1792
|
-
|
|
1793
|
-
if (isValueSet(defaultValue, canBeNull)) {
|
|
1794
|
-
return defaultValue;
|
|
1795
|
-
}
|
|
1796
|
-
|
|
1797
|
-
return undefined;
|
|
1798
|
-
};
|
|
1799
|
-
|
|
1800
|
-
/** Deliberately un-annotated: the inferred literal union is what callers assign
|
|
1801
|
-
* into their own narrower type aliases, and widening it to `string` breaks
|
|
1802
|
-
* them. */
|
|
1803
|
-
export const getTypeFromValue = (value: any) => {
|
|
1804
|
-
switch (true) {
|
|
1805
|
-
case isNull(value):
|
|
1806
|
-
case isUndefined(value):
|
|
1807
|
-
return 'auto';
|
|
1808
|
-
case isBoolean(value):
|
|
1809
|
-
return 'bool';
|
|
1810
|
-
case Number(value) === value && value % 1 === 0:
|
|
1811
|
-
return 'int';
|
|
1812
|
-
case Number(value) === value && value % 1 !== 0:
|
|
1813
|
-
return 'float';
|
|
1814
|
-
case isObject(value):
|
|
1815
|
-
return 'hash';
|
|
1816
|
-
case isArray(value):
|
|
1817
|
-
return 'list';
|
|
1818
|
-
case new Date(value).toString() !== 'Invalid Date':
|
|
1819
|
-
return 'date';
|
|
1820
|
-
case isString(value):
|
|
1821
|
-
return 'string';
|
|
1822
|
-
default:
|
|
1823
|
-
return 'any';
|
|
1824
|
-
}
|
|
1825
|
-
};
|
|
1826
|
-
|
|
1827
|
-
/**
|
|
1828
|
-
* The groups of `groups` none of whose options has a value. A required group asks for one of its
|
|
1829
|
-
* options; an option in several groups is settled only when each of them is.
|
|
1830
|
-
*/
|
|
1831
|
-
export const unsatisfiedRequiredGroups = (
|
|
1832
|
-
options: TQorusForm,
|
|
1833
|
-
schema: IQorusFormSchema,
|
|
1834
|
-
groups: string[]
|
|
1835
|
-
): string[] =>
|
|
1836
|
-
(groups ?? []).filter(
|
|
1837
|
-
(group) =>
|
|
1838
|
-
!getOptionsFromRequiredGroups(schema, [group]).some((option) =>
|
|
1839
|
-
isValueDefined(
|
|
1840
|
-
((schema[option] as TQorusFormFieldSchema)?.ui_type as string) ||
|
|
1841
|
-
((schema[option] as TQorusFormFieldSchema)?.type as string),
|
|
1842
|
-
options?.[option]?.value
|
|
1843
|
-
)
|
|
1844
|
-
)
|
|
1845
|
-
);
|
|
1846
|
-
|
|
1847
|
-
/**
|
|
1848
|
-
* Whether an option's required groups are settled: each has an option with a value. Any value in any of
|
|
1849
|
-
* the groups used to do, so an option in two groups passed while one of them was still empty - it was
|
|
1850
|
-
* neither flagged nor counted, and the form said fewer fields needed attention than did.
|
|
1851
|
-
*/
|
|
1852
|
-
export const validateOptionWithRequiredGroups = (
|
|
1853
|
-
options: TQorusForm,
|
|
1854
|
-
schema: IQorusFormSchema,
|
|
1855
|
-
groups: string[]
|
|
1856
|
-
): boolean => !unsatisfiedRequiredGroups(options, schema, groups).length;
|
|
1857
|
-
|
|
1858
|
-
/** Why a required option is not satisfied by the current values. */
|
|
1859
|
-
export type TUnresolvedRequiredOptionReason =
|
|
1860
|
-
/** No value at all — neither typed, nor defaulted, nor preselected. */
|
|
1861
|
-
| 'missing'
|
|
1862
|
-
/** The option's dependencies are not fulfilled, so its value cannot be final yet. */
|
|
1863
|
-
| 'dependency'
|
|
1864
|
-
/** A value is present but does not validate against the option's type / schema. */
|
|
1865
|
-
| 'invalid';
|
|
1866
|
-
|
|
1867
|
-
export interface IUnresolvedRequiredOption {
|
|
1868
|
-
/** The option's key in the schema. */
|
|
1869
|
-
name: string;
|
|
1870
|
-
reason: TUnresolvedRequiredOptionReason;
|
|
1871
|
-
/** The failing validation, present only for the `invalid` reason. */
|
|
1872
|
-
validation?: IValidationResult;
|
|
1873
|
-
}
|
|
1874
|
-
|
|
1875
|
-
export const getUnresolvedRequiredOptionReason = (
|
|
1876
|
-
{ name, reason }: IUnresolvedRequiredOption,
|
|
1877
|
-
optionSchema?: IQorusFormSchema
|
|
1878
|
-
): string => {
|
|
1879
|
-
switch (reason) {
|
|
1880
|
-
case 'dependency':
|
|
1881
|
-
return `Option ${name} dependencies are not fulfilled`;
|
|
1882
|
-
case 'invalid':
|
|
1883
|
-
return `Option ${name} is invalid`;
|
|
1884
|
-
default:
|
|
1885
|
-
return (optionSchema?.[name] as TQorusFormFieldSchema)?.required
|
|
1886
|
-
? `Option ${name} is required`
|
|
1887
|
-
: `Option ${name} requires a value`;
|
|
1888
|
-
}
|
|
1889
|
-
};
|
|
1890
|
-
|
|
1891
|
-
/**
|
|
1892
|
-
* List every required option that the given values do not resolve.
|
|
1893
|
-
*
|
|
1894
|
-
* `required` on an option schema means "the effective configuration must carry
|
|
1895
|
-
* this option" — NOT "the user has to type it in". An option whose schema
|
|
1896
|
-
* default or preselected value already resolves it needs no user input at all,
|
|
1897
|
-
* which is why callers pass values that have been through `fixOptions()`
|
|
1898
|
-
* (defaults, preselected values and rich-text default envelopes applied)
|
|
1899
|
-
* rather than the raw values the server returned.
|
|
1900
|
-
*
|
|
1901
|
-
* This is the single owner of the "which required options still need input"
|
|
1902
|
-
* question: `validateField('options', …)` uses it for form validity, and
|
|
1903
|
-
* qorus-ide's `ConnectionManagementModal` uses it to decide whether a
|
|
1904
|
-
* connection can be created — and its OAuth2 flow started — without showing a
|
|
1905
|
-
* form at all.
|
|
1906
|
-
*/
|
|
1907
|
-
export const getUnresolvedRequiredOptions = (
|
|
1908
|
-
optionSchema: IQorusFormSchema = {},
|
|
1909
|
-
options: TQorusForm = {}
|
|
1910
|
-
): IUnresolvedRequiredOption[] => {
|
|
1911
|
-
const unresolved: IUnresolvedRequiredOption[] = [];
|
|
1912
|
-
|
|
1913
|
-
for (const [name, schemaEntry] of Object.entries(optionSchema ?? {})) {
|
|
1914
|
-
const optionData = schemaEntry as TQorusFormFieldSchema;
|
|
1915
|
-
|
|
1916
|
-
if (!optionData?.required && !size(optionData?.required_groups)) {
|
|
1917
|
-
continue;
|
|
1918
|
-
}
|
|
1919
|
-
|
|
1920
|
-
const optionField = options?.[name];
|
|
1921
|
-
const optionValue =
|
|
1922
|
-
optionField && typeof optionField === 'object' ? optionField.value : optionField;
|
|
1923
|
-
const optionType = ((typeof optionField === 'object' ? optionField?.type : undefined) ||
|
|
1924
|
-
optionData.ui_type ||
|
|
1925
|
-
optionData.type) as string;
|
|
1926
|
-
|
|
1927
|
-
// A dependent option cannot be considered resolved while its dependencies
|
|
1928
|
-
// are not: the schema it will be validated against — and with it any
|
|
1929
|
-
// default the server would send — is not final yet.
|
|
1930
|
-
if (
|
|
1931
|
-
optionData.depends_on &&
|
|
1932
|
-
!hasAllDependenciesFullfilled(optionData.depends_on, options, optionSchema)
|
|
1933
|
-
) {
|
|
1934
|
-
unresolved.push({ name, reason: 'dependency' });
|
|
1935
|
-
continue;
|
|
1936
|
-
}
|
|
1937
|
-
|
|
1938
|
-
if (!isValueDefined(optionType, optionValue)) {
|
|
1939
|
-
// An option required only through a group is resolved by any sibling in
|
|
1940
|
-
// that group carrying a value.
|
|
1941
|
-
if (
|
|
1942
|
-
optionData.required ||
|
|
1943
|
-
!validateOptionWithRequiredGroups(options, optionSchema, optionData.required_groups)
|
|
1944
|
-
) {
|
|
1945
|
-
unresolved.push({ name, reason: 'missing' });
|
|
1946
|
-
}
|
|
1947
|
-
|
|
1948
|
-
continue;
|
|
1949
|
-
}
|
|
1950
|
-
|
|
1951
|
-
const validation =
|
|
1952
|
-
typeof optionField !== 'object'
|
|
1953
|
-
? validateFieldWithResult(getTypeFromValue(optionField), optionField)
|
|
1954
|
-
: validateFieldWithResult(optionField.type, optionField.value, {
|
|
1955
|
-
...(optionData as any),
|
|
1956
|
-
optionSchema,
|
|
1957
|
-
options,
|
|
1958
|
-
isFunction: optionField.is_expression,
|
|
1959
|
-
});
|
|
1960
|
-
|
|
1961
|
-
if (!validation.isValid) {
|
|
1962
|
-
unresolved.push({ name, reason: 'invalid', validation });
|
|
1963
|
-
}
|
|
1964
|
-
}
|
|
1965
|
-
|
|
1966
|
-
return unresolved;
|
|
1967
|
-
};
|
|
1968
|
-
|
|
1969
|
-
/**
|
|
1970
|
-
* Split a dependency entry into the sibling it names and how its value is compared.
|
|
1971
|
-
*
|
|
1972
|
-
* Four forms: `name` (the sibling must simply have a value), `!name` (it must have
|
|
1973
|
-
* none), `name=value` (it must have exactly that value) and `name!=value` (it must
|
|
1974
|
-
* have a value, and not that one). The negative comparison is what lets a field say
|
|
1975
|
-
* it applies to every variant of a record but one — spelling that as an `any-of`
|
|
1976
|
-
* list of every other variant is both unreadable in the "Depends on" lock and
|
|
1977
|
-
* silently wrong the moment a variant is added.
|
|
1978
|
-
*
|
|
1979
|
-
* `!=` deliberately requires the sibling to be answered: "not X" is a statement about
|
|
1980
|
-
* an answer, so an unanswered sibling does not satisfy it and the field stays locked.
|
|
1981
|
-
*
|
|
1982
|
-
* `!name` is the form that statement cannot make. Two options that exclude one
|
|
1983
|
-
* another (a converter that reads NodeSet2 and one that writes OpenAPI 3) each
|
|
1984
|
-
* apply only while the OTHER has not been answered at all, and `name!=value` cannot
|
|
1985
|
-
* say that: it requires an answer. Being a predicate like any other, it composes
|
|
1986
|
-
* with the AND of the top-level entries and the OR of a nested list for free.
|
|
1987
|
-
*
|
|
1988
|
-
* `!` binds to the whole entry, so `!name` never carries a value; `!=` is checked
|
|
1989
|
-
* first, which is what keeps `name!=value` from being read as a leading `!`.
|
|
1990
|
-
*/
|
|
1991
|
-
export const parseDependency = (
|
|
1992
|
-
dependency: string
|
|
1993
|
-
): { name: string; op?: '=' | '!=' | '!'; value?: string } => {
|
|
1994
|
-
const neqIdx = dependency.indexOf('!=');
|
|
1995
|
-
if (neqIdx !== -1) {
|
|
1996
|
-
return {
|
|
1997
|
-
name: dependency.substring(0, neqIdx),
|
|
1998
|
-
op: '!=',
|
|
1999
|
-
value: dependency.substring(neqIdx + 2),
|
|
2000
|
-
};
|
|
2001
|
-
}
|
|
2002
|
-
|
|
2003
|
-
const eqIdx = dependency.indexOf('=');
|
|
2004
|
-
if (eqIdx !== -1) {
|
|
2005
|
-
return {
|
|
2006
|
-
name: dependency.substring(0, eqIdx),
|
|
2007
|
-
op: '=',
|
|
2008
|
-
value: dependency.substring(eqIdx + 1),
|
|
2009
|
-
};
|
|
2010
|
-
}
|
|
2011
|
-
|
|
2012
|
-
if (dependency.startsWith('!')) {
|
|
2013
|
-
return { name: dependency.substring(1), op: '!' };
|
|
2014
|
-
}
|
|
2015
|
-
|
|
2016
|
-
return { name: dependency };
|
|
2017
|
-
};
|
|
2018
|
-
|
|
2019
|
-
/** Whether the named sibling currently holds a value this form accepts. */
|
|
2020
|
-
const siblingHasValue = (
|
|
2021
|
-
name: string,
|
|
2022
|
-
options: TQorusForm,
|
|
2023
|
-
optionsSchema?: IQorusFormSchema
|
|
2024
|
-
): boolean =>
|
|
2025
|
-
validateField(options?.[name]?.type, options?.[name]?.value, {
|
|
2026
|
-
...(optionsSchema?.[name] as unknown as IFieldValidationProps),
|
|
2027
|
-
options,
|
|
2028
|
-
optionSchema: optionsSchema,
|
|
2029
|
-
});
|
|
2030
|
-
|
|
2031
|
-
/** Whether one dependency entry holds against the current form values. */
|
|
2032
|
-
const isDependencyFulfilled = (
|
|
2033
|
-
dependency: string,
|
|
2034
|
-
options: TQorusForm,
|
|
2035
|
-
optionsSchema?: IQorusFormSchema
|
|
2036
|
-
): boolean => {
|
|
2037
|
-
const { name, op, value } = parseDependency(dependency);
|
|
2038
|
-
|
|
2039
|
-
if (op === '!') {
|
|
2040
|
-
// "Has no value" is true of a field the form has not materialized at all —
|
|
2041
|
-
// there is nothing there to be the value. So an absent sibling satisfies
|
|
2042
|
-
// this, exactly as it satisfies the bare form below: neither has an answer
|
|
2043
|
-
// to judge, and a mutual exclusion that locked both halves until one of
|
|
2044
|
-
// them was added would offer the author no way in.
|
|
2045
|
-
return !options?.[name] || !siblingHasValue(name, options, optionsSchema);
|
|
2046
|
-
}
|
|
2047
|
-
|
|
2048
|
-
if (op) {
|
|
2049
|
-
const optValue = options?.[name]?.value;
|
|
2050
|
-
if (optValue == null) {
|
|
2051
|
-
return false;
|
|
2052
|
-
}
|
|
2053
|
-
return op === '=' ? String(optValue) === value : String(optValue) !== value;
|
|
2054
|
-
}
|
|
2055
|
-
|
|
2056
|
-
return options?.[name] ? siblingHasValue(name, options, optionsSchema) : true;
|
|
2057
|
-
};
|
|
2058
|
-
|
|
2059
|
-
export const hasAllDependenciesFullfilled = (
|
|
2060
|
-
/** Every entry must hold; a nested list is an ANY of its entries. Mixed freely. */
|
|
2061
|
-
dependencies: ReadonlyArray<string | readonly string[]>,
|
|
2062
|
-
options: TQorusForm,
|
|
2063
|
-
optionsSchema?: IQorusFormSchema
|
|
2064
|
-
): boolean => {
|
|
2065
|
-
if (size(dependencies) === 0) {
|
|
2066
|
-
return true;
|
|
2067
|
-
}
|
|
2068
|
-
|
|
2069
|
-
return dependencies.every((dependency) => {
|
|
2070
|
-
// A nested list is an ANY. It used to look each entry up as a whole form-field
|
|
2071
|
-
// name, so a `name=value` entry inside one found no field and returned `true`
|
|
2072
|
-
// unconditionally — the any-of group was satisfied by anything at all, while
|
|
2073
|
-
// CompactRow's lock rendered those same entries as real comparisons. Both halves
|
|
2074
|
-
// now go through one parser, so the grammar cannot mean two things.
|
|
2075
|
-
if (isArray(dependency)) {
|
|
2076
|
-
return (dependency as readonly string[]).some((dep) =>
|
|
2077
|
-
isDependencyFulfilled(dep, options, optionsSchema)
|
|
2078
|
-
);
|
|
2079
|
-
}
|
|
2080
|
-
|
|
2081
|
-
return isString(dependency)
|
|
2082
|
-
? isDependencyFulfilled(dependency, options, optionsSchema)
|
|
2083
|
-
: true;
|
|
2084
|
-
});
|
|
2085
|
-
};
|