@qoretechnologies/reqraft 0.10.54 → 0.10.55-pr.115.g37abdfc
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/.claude/CLAUDE.md +25 -0
- package/.tasks/INDEX.md +1 -0
- package/.tasks/STORY_NETWORK_ISOLATION.md +98 -0
- package/README.md +1 -1
- package/design/FORM_ENGINE_COMPACT.md +34 -0
- package/design/FORM_ENGINE_EXPRESSIONS.md +110 -0
- package/design/FORM_ENGINE_FIELD_MIGRATION.md +155 -1
- package/design/IDE_INTEGRATION.md +13 -0
- package/design/RENDER_EXPRESSION_TRANSPORT.md +76 -10
- package/design/SELECT_DIALOG_FLOOR.md +86 -0
- package/design/SMART_EDITOR_UX.md +21 -0
- package/design/UNAVAILABLE_ALLOWED_VALUES.md +226 -0
- package/dist/components/composer/Composer.d.ts +8 -3
- package/dist/components/composer/Composer.d.ts.map +1 -1
- 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 +3 -3
- package/dist/components/dpqlEditor/DpqlEditor.js.map +1 -1
- package/dist/components/dpqlEditor/dpqlHelpers.d.ts +6 -0
- package/dist/components/dpqlEditor/dpqlHelpers.d.ts.map +1 -1
- package/dist/components/dpqlEditor/dpqlHelpers.js +21 -2
- package/dist/components/dpqlEditor/dpqlHelpers.js.map +1 -1
- package/dist/components/dpqlEditor/dpqlProbe.d.ts +37 -0
- package/dist/components/dpqlEditor/dpqlProbe.d.ts.map +1 -0
- package/dist/components/dpqlEditor/dpqlProbe.js +203 -0
- package/dist/components/dpqlEditor/dpqlProbe.js.map +1 -0
- package/dist/components/dpqlEditor/dpqlTags.d.ts +8 -0
- package/dist/components/dpqlEditor/dpqlTags.d.ts.map +1 -1
- package/dist/components/dpqlEditor/dpqlTags.js +5 -1
- package/dist/components/dpqlEditor/dpqlTags.js.map +1 -1
- package/dist/components/dpqlEditor/index.d.ts +4 -0
- package/dist/components/dpqlEditor/index.d.ts.map +1 -1
- package/dist/components/dpqlEditor/index.js +5 -1
- package/dist/components/dpqlEditor/index.js.map +1 -1
- package/dist/components/dpqlEditor/types.d.ts +42 -2
- package/dist/components/dpqlEditor/types.d.ts.map +1 -1
- package/dist/components/dpqlEditor/types.js +0 -4
- package/dist/components/dpqlEditor/types.js.map +1 -1
- package/dist/components/dpqlEditor/useDpqlProbe.d.ts +4 -0
- package/dist/components/dpqlEditor/useDpqlProbe.d.ts.map +1 -0
- package/dist/components/dpqlEditor/useDpqlProbe.js +29 -0
- package/dist/components/dpqlEditor/useDpqlProbe.js.map +1 -0
- package/dist/components/dpqlEditor/useDpqlSession.d.ts +5 -2
- package/dist/components/dpqlEditor/useDpqlSession.d.ts.map +1 -1
- package/dist/components/dpqlEditor/useDpqlSession.js +8 -2
- 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 +414 -128
- 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 +5 -2
- package/dist/components/form/engine/CompactToolbar.js.map +1 -1
- package/dist/components/form/engine/FormEngine.d.ts +272 -19
- package/dist/components/form/engine/FormEngine.d.ts.map +1 -1
- package/dist/components/form/engine/FormEngine.js +666 -161
- package/dist/components/form/engine/FormEngine.js.map +1 -1
- package/dist/components/form/engine/FormFieldsSkeleton.d.ts +48 -0
- package/dist/components/form/engine/FormFieldsSkeleton.d.ts.map +1 -0
- package/dist/components/form/engine/FormFieldsSkeleton.js +41 -0
- package/dist/components/form/engine/FormFieldsSkeleton.js.map +1 -0
- package/dist/components/form/engine/OptionFieldMessages.d.ts +108 -2
- package/dist/components/form/engine/OptionFieldMessages.d.ts.map +1 -1
- package/dist/components/form/engine/OptionFieldMessages.js +203 -13
- package/dist/components/form/engine/OptionFieldMessages.js.map +1 -1
- package/dist/components/form/engine/_structuredData/SchemaDataView.d.ts.map +1 -1
- package/dist/components/form/engine/_structuredData/SchemaDataView.js +68 -5
- package/dist/components/form/engine/_structuredData/SchemaDataView.js.map +1 -1
- package/dist/components/form/engine/compactRowContext.d.ts +15 -1
- 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.map +1 -1
- package/dist/components/form/engine/compactRowStyles.js +55 -29
- package/dist/components/form/engine/compactRowStyles.js.map +1 -1
- package/dist/components/form/engine/compactToolbarContext.d.ts +1 -0
- package/dist/components/form/engine/compactToolbarContext.d.ts.map +1 -1
- package/dist/components/form/engine/optionActions.d.ts +37 -1
- package/dist/components/form/engine/optionActions.d.ts.map +1 -1
- package/dist/components/form/engine/optionActions.js +71 -1
- package/dist/components/form/engine/optionActions.js.map +1 -1
- package/dist/components/form/engine/optionsContext.d.ts +22 -0
- package/dist/components/form/engine/optionsContext.d.ts.map +1 -0
- package/dist/components/form/engine/optionsContext.js +20 -0
- package/dist/components/form/engine/optionsContext.js.map +1 -0
- package/dist/components/form/engine/readFirst.d.ts +42 -1
- package/dist/components/form/engine/readFirst.d.ts.map +1 -1
- package/dist/components/form/engine/readFirst.js +76 -8
- package/dist/components/form/engine/readFirst.js.map +1 -1
- package/dist/components/form/engine/rendererTypes.d.ts +42 -3
- package/dist/components/form/engine/rendererTypes.d.ts.map +1 -1
- package/dist/components/form/engine/rendererTypes.js +3 -1
- package/dist/components/form/engine/rendererTypes.js.map +1 -1
- package/dist/components/form/engine/rowFocus.d.ts +30 -0
- package/dist/components/form/engine/rowFocus.d.ts.map +1 -0
- package/dist/components/form/engine/rowFocus.js +93 -0
- package/dist/components/form/engine/rowFocus.js.map +1 -0
- package/dist/components/form/engine/rowMenuContext.d.ts +78 -0
- package/dist/components/form/engine/rowMenuContext.d.ts.map +1 -0
- package/dist/components/form/engine/rowMenuContext.js +103 -0
- package/dist/components/form/engine/rowMenuContext.js.map +1 -0
- package/dist/components/form/engine/rowOpenPicker.d.ts +27 -0
- package/dist/components/form/engine/rowOpenPicker.d.ts.map +1 -0
- package/dist/components/form/engine/rowOpenPicker.js +30 -0
- package/dist/components/form/engine/rowOpenPicker.js.map +1 -0
- package/dist/components/form/engine/typeChoices.d.ts +42 -0
- package/dist/components/form/engine/typeChoices.d.ts.map +1 -0
- package/dist/components/form/engine/typeChoices.js +33 -0
- package/dist/components/form/engine/typeChoices.js.map +1 -0
- package/dist/components/form/expressions/DpqlRendering.d.ts +26 -0
- package/dist/components/form/expressions/DpqlRendering.d.ts.map +1 -0
- package/dist/components/form/expressions/DpqlRendering.js +53 -0
- package/dist/components/form/expressions/DpqlRendering.js.map +1 -0
- package/dist/components/form/expressions/ExpressionField.d.ts +7 -1
- package/dist/components/form/expressions/ExpressionField.d.ts.map +1 -1
- package/dist/components/form/expressions/ExpressionField.js +203 -45
- package/dist/components/form/expressions/ExpressionField.js.map +1 -1
- package/dist/components/form/expressions/argumentPresence.d.ts +84 -0
- package/dist/components/form/expressions/argumentPresence.d.ts.map +1 -0
- package/dist/components/form/expressions/argumentPresence.js +217 -0
- package/dist/components/form/expressions/argumentPresence.js.map +1 -0
- package/dist/components/form/expressions/builder/argumentLabel.d.ts.map +1 -1
- package/dist/components/form/expressions/builder/argumentLabel.js +9 -4
- package/dist/components/form/expressions/builder/argumentLabel.js.map +1 -1
- package/dist/components/form/expressions/builder/index.d.ts +15 -2
- package/dist/components/form/expressions/builder/index.d.ts.map +1 -1
- package/dist/components/form/expressions/builder/index.js +21 -65
- package/dist/components/form/expressions/builder/index.js.map +1 -1
- package/dist/components/form/expressions/builder/renderTemplate.d.ts +4 -1
- package/dist/components/form/expressions/builder/renderTemplate.d.ts.map +1 -1
- package/dist/components/form/expressions/builder/renderTemplate.js +10 -67
- package/dist/components/form/expressions/builder/renderTemplate.js.map +1 -1
- package/dist/components/form/expressions/mockExpressions.d.ts.map +1 -1
- package/dist/components/form/expressions/mockExpressions.js +8 -4
- package/dist/components/form/expressions/mockExpressions.js.map +1 -1
- package/dist/components/form/expressions/renderExpressionToText.d.ts +1 -1
- package/dist/components/form/expressions/renderExpressionToText.d.ts.map +1 -1
- package/dist/components/form/expressions/renderExpressionToText.js +95 -19
- package/dist/components/form/expressions/renderExpressionToText.js.map +1 -1
- package/dist/components/form/expressions/types.d.ts +7 -0
- package/dist/components/form/expressions/types.d.ts.map +1 -1
- package/dist/components/form/expressions/useExpressions.d.ts.map +1 -1
- package/dist/components/form/expressions/useExpressions.js +5 -2
- package/dist/components/form/expressions/useExpressions.js.map +1 -1
- package/dist/components/form/expressions/useRenderExpression.d.ts +7 -16
- package/dist/components/form/expressions/useRenderExpression.d.ts.map +1 -1
- package/dist/components/form/expressions/useRenderExpression.js +50 -126
- package/dist/components/form/expressions/useRenderExpression.js.map +1 -1
- package/dist/components/form/fields/Field.d.ts +18 -0
- package/dist/components/form/fields/Field.d.ts.map +1 -1
- package/dist/components/form/fields/Field.js +54 -8
- package/dist/components/form/fields/Field.js.map +1 -1
- package/dist/components/form/fields/allowed-values/AllowedValues.d.ts +11 -1
- package/dist/components/form/fields/allowed-values/AllowedValues.d.ts.map +1 -1
- package/dist/components/form/fields/allowed-values/AllowedValues.js +52 -8
- package/dist/components/form/fields/allowed-values/AllowedValues.js.map +1 -1
- package/dist/components/form/fields/auto/AutoFormField.d.ts +7 -1
- package/dist/components/form/fields/auto/AutoFormField.d.ts.map +1 -1
- package/dist/components/form/fields/auto/AutoFormField.js +91 -28
- package/dist/components/form/fields/auto/AutoFormField.js.map +1 -1
- package/dist/components/form/fields/date/Date.d.ts +1 -1
- package/dist/components/form/fields/date/Date.d.ts.map +1 -1
- package/dist/components/form/fields/date/Date.js +16 -2
- package/dist/components/form/fields/date/Date.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 +14 -2
- package/dist/components/form/fields/long-string/LongString.js.map +1 -1
- package/dist/components/form/fields/multi-select/MultiSelectFormField.d.ts.map +1 -1
- package/dist/components/form/fields/multi-select/MultiSelectFormField.js +50 -4
- package/dist/components/form/fields/multi-select/MultiSelectFormField.js.map +1 -1
- package/dist/components/form/fields/rich-text/RichText.d.ts +47 -2
- package/dist/components/form/fields/rich-text/RichText.d.ts.map +1 -1
- package/dist/components/form/fields/rich-text/RichText.js +153 -12
- package/dist/components/form/fields/rich-text/RichText.js.map +1 -1
- package/dist/components/form/fields/select/Select.d.ts.map +1 -1
- package/dist/components/form/fields/select/Select.js +120 -20
- package/dist/components/form/fields/select/Select.js.map +1 -1
- package/dist/components/form/fields/select/SelectCollection.d.ts +166 -9
- package/dist/components/form/fields/select/SelectCollection.d.ts.map +1 -1
- package/dist/components/form/fields/select/SelectCollection.js +200 -7
- package/dist/components/form/fields/select/SelectCollection.js.map +1 -1
- package/dist/components/form/fields/template/ReadOnlyTemplateTag.d.ts +2 -1
- package/dist/components/form/fields/template/ReadOnlyTemplateTag.d.ts.map +1 -1
- package/dist/components/form/fields/template/ReadOnlyTemplateTag.js +3 -2
- package/dist/components/form/fields/template/ReadOnlyTemplateTag.js.map +1 -1
- package/dist/components/form/fields/template/TemplateField.d.ts +34 -2
- package/dist/components/form/fields/template/TemplateField.d.ts.map +1 -1
- package/dist/components/form/fields/template/TemplateField.js +606 -58
- package/dist/components/form/fields/template/TemplateField.js.map +1 -1
- package/dist/components/form/fields/template/TemplateText.d.ts +36 -0
- package/dist/components/form/fields/template/TemplateText.d.ts.map +1 -0
- package/dist/components/form/fields/template/TemplateText.js +80 -0
- package/dist/components/form/fields/template/TemplateText.js.map +1 -0
- package/dist/components/form/index.d.ts +2 -0
- package/dist/components/form/index.d.ts.map +1 -1
- package/dist/components/form/index.js +4 -0
- package/dist/components/form/index.js.map +1 -1
- package/dist/components/smartEditor/SmartEditor.d.ts.map +1 -1
- package/dist/components/smartEditor/SmartEditor.js +29 -8
- package/dist/components/smartEditor/SmartEditor.js.map +1 -1
- package/dist/components/smartEditor/useLspSession.d.ts +5 -1
- package/dist/components/smartEditor/useLspSession.d.ts.map +1 -1
- package/dist/components/smartEditor/useLspSession.js +16 -2
- package/dist/components/smartEditor/useLspSession.js.map +1 -1
- package/dist/components/supportTicket/TicketReplyBox.d.ts +8 -4
- package/dist/components/supportTicket/TicketReplyBox.d.ts.map +1 -1
- package/dist/components/supportTicket/TicketReplyBox.js.map +1 -1
- package/dist/helpers/common.d.ts.map +1 -1
- package/dist/helpers/common.js +7 -3
- package/dist/helpers/common.js.map +1 -1
- package/dist/helpers/dpqlDetection.d.ts +58 -0
- package/dist/helpers/dpqlDetection.d.ts.map +1 -0
- package/dist/helpers/dpqlDetection.js +164 -0
- package/dist/helpers/dpqlDetection.js.map +1 -0
- package/dist/helpers/optionUiTypes.d.ts +31 -3
- package/dist/helpers/optionUiTypes.d.ts.map +1 -1
- package/dist/helpers/optionUiTypes.js +36 -1
- package/dist/helpers/optionUiTypes.js.map +1 -1
- package/dist/helpers/options.d.ts +57 -0
- package/dist/helpers/options.d.ts.map +1 -1
- package/dist/helpers/options.js +97 -1
- package/dist/helpers/options.js.map +1 -1
- package/dist/helpers/templateItems.d.ts +47 -0
- package/dist/helpers/templateItems.d.ts.map +1 -0
- package/dist/helpers/templateItems.js +88 -0
- package/dist/helpers/templateItems.js.map +1 -0
- package/dist/helpers/templateText.d.ts +80 -0
- package/dist/helpers/templateText.d.ts.map +1 -0
- package/dist/helpers/templateText.js +291 -0
- package/dist/helpers/templateText.js.map +1 -0
- package/dist/helpers/templates.d.ts +30 -12
- package/dist/helpers/templates.d.ts.map +1 -1
- package/dist/helpers/templates.js +91 -33
- package/dist/helpers/templates.js.map +1 -1
- package/dist/helpers/validations.d.ts +17 -8
- package/dist/helpers/validations.d.ts.map +1 -1
- package/dist/helpers/validations.js +117 -22
- package/dist/helpers/validations.js.map +1 -1
- package/dist/hooks/useArgSchema.d.ts +2 -1
- package/dist/hooks/useArgSchema.d.ts.map +1 -1
- package/dist/hooks/useFetch/useFetch.d.ts +3 -1
- package/dist/hooks/useFetch/useFetch.d.ts.map +1 -1
- package/dist/hooks/useFetch/useFetch.js +47 -9
- package/dist/hooks/useFetch/useFetch.js.map +1 -1
- package/dist/hooks/useTemplates.d.ts +20 -0
- package/dist/hooks/useTemplates.d.ts.map +1 -1
- package/dist/hooks/useTemplates.js +34 -2
- package/dist/hooks/useTemplates.js.map +1 -1
- package/dist/index.d.ts +2 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +5 -1
- package/dist/index.js.map +1 -1
- package/dist/utils/fetch.d.ts +151 -1
- package/dist/utils/fetch.d.ts.map +1 -1
- package/dist/utils/fetch.js +256 -44
- package/dist/utils/fetch.js.map +1 -1
- package/dist/utils/lspClient.d.ts +6 -0
- package/dist/utils/lspClient.d.ts.map +1 -1
- package/dist/utils/lspClient.js +62 -11
- package/dist/utils/lspClient.js.map +1 -1
- package/dist/utils/websocket.d.ts +6 -0
- package/dist/utils/websocket.d.ts.map +1 -1
- package/dist/utils/websocket.js +15 -7
- package/dist/utils/websocket.js.map +1 -1
- package/package.json +8 -4
- package/src/components/composer/Composer.tsx +7 -2
- package/src/components/dpqlEditor/DpqlEditor.stories.tsx +3 -119
- package/src/components/dpqlEditor/DpqlEditor.tsx +5 -2
- package/src/components/dpqlEditor/dpqlHelpers.ts +20 -1
- package/src/components/dpqlEditor/dpqlProbe.ts +165 -0
- package/src/components/dpqlEditor/dpqlTags.ts +13 -0
- package/src/components/dpqlEditor/index.ts +4 -0
- package/src/components/dpqlEditor/types.ts +38 -2
- package/src/components/dpqlEditor/useDpqlProbe.ts +33 -0
- package/src/components/dpqlEditor/useDpqlSession.ts +20 -4
- package/src/components/form/engine/CompactRow.tsx +487 -160
- package/src/components/form/engine/CompactToolbar.tsx +10 -3
- package/src/components/form/engine/FormEngine.stories.tsx +1294 -161
- package/src/components/form/engine/FormEngine.tsx +916 -213
- package/src/components/form/engine/FormEngineStickyHeaders.stories.tsx +331 -0
- package/src/components/form/engine/FormFieldsSkeleton.tsx +77 -0
- package/src/components/form/engine/OptionFieldMessages.tsx +300 -14
- package/src/components/form/engine/_structuredData/SchemaDataView.tsx +94 -3
- package/src/components/form/engine/compactRowContext.ts +15 -6
- package/src/components/form/engine/compactRowStyles.ts +56 -2
- package/src/components/form/engine/compactToolbarContext.ts +1 -1
- package/src/components/form/engine/optionActions.ts +89 -1
- package/src/components/form/engine/optionsContext.ts +24 -0
- package/src/components/form/engine/readFirst.ts +88 -8
- package/src/components/form/engine/rendererTypes.ts +48 -4
- package/src/components/form/engine/rowFocus.ts +101 -0
- package/src/components/form/engine/rowMenuContext.ts +159 -0
- package/src/components/form/engine/rowOpenPicker.ts +27 -0
- package/src/components/form/engine/typeChoices.ts +63 -0
- package/src/components/form/expressions/DpqlRendering.tsx +85 -0
- package/src/components/form/expressions/ExpressionField.stories.tsx +826 -48
- package/src/components/form/expressions/ExpressionField.tsx +269 -55
- package/src/components/form/expressions/argumentPresence.ts +213 -0
- package/src/components/form/expressions/builder/ExpressionBuilder.stories.tsx +38 -21
- package/src/components/form/expressions/builder/argumentLabel.tsx +10 -4
- package/src/components/form/expressions/builder/index.tsx +39 -81
- package/src/components/form/expressions/builder/renderTemplate.tsx +23 -56
- package/src/components/form/expressions/dpqlMockLanguage.ts +565 -0
- package/src/components/form/expressions/dpqlMockLsp.ts +109 -83
- package/src/components/form/expressions/mockExpressions.ts +8 -4
- package/src/components/form/expressions/renderExpressionToText.ts +112 -22
- package/src/components/form/expressions/types.ts +7 -0
- package/src/components/form/expressions/useExpressions.ts +5 -1
- package/src/components/form/expressions/useRenderExpression.ts +43 -127
- package/src/components/form/fields/Field.tsx +99 -20
- package/src/components/form/fields/allowed-values/AllowedValues.tsx +106 -44
- package/src/components/form/fields/auto/AutoFormField.stories.tsx +85 -18
- package/src/components/form/fields/auto/AutoFormField.tsx +97 -21
- package/src/components/form/fields/date/Date.tsx +17 -1
- package/src/components/form/fields/long-string/LongString.tsx +15 -3
- package/src/components/form/fields/multi-select/MultiSelectFormField.tsx +65 -6
- package/src/components/form/fields/rich-text/RichText.tsx +248 -30
- package/src/components/form/fields/select/Select.stories.tsx +392 -0
- package/src/components/form/fields/select/Select.tsx +164 -27
- package/src/components/form/fields/select/SelectCollection.tsx +350 -6
- package/src/components/form/fields/template/ReadOnlyTemplateTag.tsx +4 -2
- package/src/components/form/fields/template/TemplateField.stories.tsx +93 -14
- package/src/components/form/fields/template/TemplateField.tsx +825 -131
- package/src/components/form/fields/template/TemplateText.tsx +115 -0
- package/src/components/form/index.tsx +4 -0
- package/src/components/log/Log.stories.tsx +2 -1
- package/src/components/searchFilterBar/SearchFilterBar.stories.tsx +3 -3
- package/src/components/smartEditor/SmartEditor.tsx +41 -9
- package/src/components/smartEditor/__fixtures__/mockLspServer.ts +52 -3
- package/src/components/smartEditor/useLspSession.ts +21 -3
- package/src/components/supportTicket/TicketReplyBox.tsx +8 -4
- package/src/components/ticketThread/TicketThread.stories.tsx +1 -0
- package/src/helpers/common.ts +7 -3
- package/src/helpers/dpqlDetection.ts +209 -0
- package/src/helpers/optionUiTypes.ts +38 -0
- package/src/helpers/options.ts +96 -0
- package/src/helpers/templateItems.ts +81 -0
- package/src/helpers/templateText.ts +350 -0
- package/src/helpers/templates.ts +94 -41
- package/src/helpers/validations.ts +138 -39
- package/src/hooks/useFetch/useFetch.stories.tsx +6 -5
- package/src/hooks/useFetch/useFetch.tsx +53 -7
- package/src/hooks/useStorage/useStorage.stories.tsx +2 -1
- package/src/hooks/useTemplates.ts +41 -0
- package/src/hooks/useWebSocket/useWebsocket.stories.tsx +2 -1
- package/src/index.tsx +14 -1
- package/src/stores/currentUser/currentUser.stories.tsx +2 -1
- package/src/stories/storyNetwork.ts +92 -0
- package/src/utils/fetch.ts +311 -21
- package/src/utils/lspClient.ts +68 -11
- package/src/utils/websocket.ts +20 -9
- package/dist/components/form/engine/__fixtures__/basicFormOptions.d.ts +0 -73
- package/dist/components/form/engine/__fixtures__/basicFormOptions.d.ts.map +0 -1
- package/dist/components/form/engine/__fixtures__/basicFormOptions.js +0 -317
- package/dist/components/form/engine/__fixtures__/basicFormOptions.js.map +0 -1
- package/dist/components/form/engine/__fixtures__/fieldChromeOptions.d.ts +0 -41
- package/dist/components/form/engine/__fixtures__/fieldChromeOptions.d.ts.map +0 -1
- package/dist/components/form/engine/__fixtures__/fieldChromeOptions.js +0 -45
- package/dist/components/form/engine/__fixtures__/fieldChromeOptions.js.map +0 -1
- package/dist/components/form/expressions/dpqlMockLsp.d.ts +0 -3
- package/dist/components/form/expressions/dpqlMockLsp.d.ts.map +0 -1
- package/dist/components/form/expressions/dpqlMockLsp.js +0 -91
- package/dist/components/form/expressions/dpqlMockLsp.js.map +0 -1
- package/dist/components/form/fields/template/__fixtures__/longExampleValue.d.ts +0 -2
- package/dist/components/form/fields/template/__fixtures__/longExampleValue.d.ts.map +0 -1
- package/dist/components/form/fields/template/__fixtures__/longExampleValue.js +0 -9
- package/dist/components/form/fields/template/__fixtures__/longExampleValue.js.map +0 -1
- package/dist/components/smartEditor/__fixtures__/mockLspServer.d.ts +0 -55
- package/dist/components/smartEditor/__fixtures__/mockLspServer.d.ts.map +0 -1
- package/dist/components/smartEditor/__fixtures__/mockLspServer.js +0 -126
- package/dist/components/smartEditor/__fixtures__/mockLspServer.js.map +0 -1
- package/dist/stories/Data/fileFieldArgSchema.json +0 -86
|
@@ -54,22 +54,24 @@ const waitForText = async (text: string | RegExp) => {
|
|
|
54
54
|
|
|
55
55
|
// --- reqraft behavioral stories (kept from the field-migration batch) -------
|
|
56
56
|
|
|
57
|
-
/**
|
|
57
|
+
/** Untyped, no value — the field opens on an editor to type into, never on a type question. */
|
|
58
58
|
export const Empty: Story = {
|
|
59
59
|
args: {},
|
|
60
60
|
parameters: {
|
|
61
61
|
docs: {
|
|
62
62
|
description: {
|
|
63
63
|
story:
|
|
64
|
-
'Renders AutoFormField with no value or defaultType
|
|
64
|
+
'Renders AutoFormField with no value or defaultType. The field opens on a text editor to type into; it does not show a type picker or ask for a data type.',
|
|
65
65
|
},
|
|
66
66
|
},
|
|
67
67
|
},
|
|
68
68
|
async play({ canvasElement }) {
|
|
69
69
|
const canvas = within(canvasElement);
|
|
70
|
-
// The
|
|
71
|
-
await expect(
|
|
72
|
-
|
|
70
|
+
// The type resolves in a mount effect — assert asynchronously.
|
|
71
|
+
await waitFor(() => expect(canvasElement.querySelector('textarea')).toBeInTheDocument(), {
|
|
72
|
+
timeout: 5000,
|
|
73
|
+
});
|
|
74
|
+
await expect(canvas.queryByText('Please select data type')).not.toBeInTheDocument();
|
|
73
75
|
await expect(canvasElement.querySelector('input[type="number"]')).not.toBeInTheDocument();
|
|
74
76
|
},
|
|
75
77
|
};
|
|
@@ -179,7 +181,7 @@ export const Nullable: Story = {
|
|
|
179
181
|
},
|
|
180
182
|
};
|
|
181
183
|
|
|
182
|
-
/**
|
|
184
|
+
/** A field declaring several allowed types still picks between them. */
|
|
183
185
|
export const AllowedTypesSubset: Story = {
|
|
184
186
|
args: {
|
|
185
187
|
allowedTypes: [
|
|
@@ -191,14 +193,14 @@ export const AllowedTypesSubset: Story = {
|
|
|
191
193
|
docs: {
|
|
192
194
|
description: {
|
|
193
195
|
story:
|
|
194
|
-
'Renders AutoFormField with allowedTypes restricted to Integer and Text
|
|
196
|
+
'Renders AutoFormField with allowedTypes restricted to Integer and Text. The type picker offers those 2 types (its badge reads 2), and the field can be typed into meanwhile without being asked for a data type.',
|
|
195
197
|
},
|
|
196
198
|
},
|
|
197
199
|
},
|
|
198
|
-
async play() {
|
|
200
|
+
async play({ canvasElement }) {
|
|
199
201
|
// The picker badge reflects the restricted list — 2 instead of 14.
|
|
200
|
-
await waitForText('Please select data type');
|
|
201
202
|
await waitForText('2');
|
|
203
|
+
await expect(within(canvasElement).queryByText('Please select data type')).not.toBeInTheDocument();
|
|
202
204
|
},
|
|
203
205
|
};
|
|
204
206
|
|
|
@@ -206,31 +208,35 @@ export const AllowedTypesSubset: Story = {
|
|
|
206
208
|
export const NoSoftTypes: Story = {
|
|
207
209
|
args: {
|
|
208
210
|
noSoft: true,
|
|
211
|
+
/* The picker belongs to a value with a type: an untyped field that is
|
|
212
|
+
empty is typed into, and one holding text has resolved to `string`. */
|
|
213
|
+
defaultType: 'auto',
|
|
214
|
+
value: 'some text',
|
|
209
215
|
},
|
|
210
216
|
parameters: {
|
|
211
217
|
docs: {
|
|
212
218
|
description: {
|
|
213
219
|
story:
|
|
214
|
-
'Renders AutoFormField with noSoft enabled
|
|
220
|
+
'Renders an untyped AutoFormField holding a text value with noSoft enabled. The picker for the type the value resolved to leaves out the soft* variants, so its badge reads 9 instead of 14.',
|
|
215
221
|
},
|
|
216
222
|
},
|
|
217
223
|
},
|
|
218
|
-
async play() {
|
|
219
|
-
await waitForText('Please select data type');
|
|
224
|
+
async play({ canvasElement }) {
|
|
220
225
|
await waitForText('9');
|
|
226
|
+
await expect(within(canvasElement).queryByText('Please select data type')).not.toBeInTheDocument();
|
|
221
227
|
},
|
|
222
228
|
};
|
|
223
229
|
|
|
224
230
|
/**
|
|
225
231
|
* The whole point of the migration: a `FormEngine` schema with a field typed
|
|
226
|
-
* `auto` renders the
|
|
232
|
+
* `auto` renders the untyped editor for free, via FormEngine → TemplateField → auto.
|
|
227
233
|
*/
|
|
228
234
|
export const ViaFormEngine: Story = {
|
|
229
235
|
parameters: {
|
|
230
236
|
docs: {
|
|
231
237
|
description: {
|
|
232
238
|
story:
|
|
233
|
-
'Renders a FormEngine schema whose single option is typed as auto
|
|
239
|
+
'Renders a FormEngine schema whose single option is typed as auto. The engine flows through TemplateField to the untyped editor without any extra wiring: an editor to type into, with no data-type question.',
|
|
234
240
|
},
|
|
235
241
|
},
|
|
236
242
|
},
|
|
@@ -255,15 +261,76 @@ export const ViaFormEngine: Story = {
|
|
|
255
261
|
async play({ canvasElement }) {
|
|
256
262
|
const canvas = within(canvasElement);
|
|
257
263
|
// Generous timeout: findByText defaults to 1s, which flakes under CI load
|
|
258
|
-
// while the engine boots the auto field
|
|
259
|
-
// waits ~10s).
|
|
264
|
+
// while the engine boots the auto field (the rest of the suite waits ~10s).
|
|
260
265
|
await expect(
|
|
261
266
|
await canvas.findByText('My Auto Field', undefined, { timeout: 10000 })
|
|
262
267
|
).toBeInTheDocument();
|
|
263
|
-
// The
|
|
268
|
+
// The untyped field opens on an editor inside the engine-driven form, and
|
|
269
|
+
// never asks for a data type.
|
|
270
|
+
await waitFor(() => expect(canvasElement.querySelector('textarea')).toBeInTheDocument(), {
|
|
271
|
+
timeout: 10000,
|
|
272
|
+
});
|
|
273
|
+
await expect(canvas.queryByText('Please select data type')).not.toBeInTheDocument();
|
|
274
|
+
},
|
|
275
|
+
};
|
|
276
|
+
|
|
277
|
+
/**
|
|
278
|
+
* The ⋮ on that same field holds one group — "Set Custom Value" and the data
|
|
279
|
+
* types under it — and opens it, rather than asking for a click to reach the
|
|
280
|
+
* only thing on offer.
|
|
281
|
+
*/
|
|
282
|
+
export const ViaFormEngineMenuOpensItsOnlyGroup: Story = {
|
|
283
|
+
parameters: {
|
|
284
|
+
docs: {
|
|
285
|
+
description: {
|
|
286
|
+
story:
|
|
287
|
+
'The untyped field\'s ⋮ holds nothing but the "Set Custom Value" section, so that section is already open: the data types are one click from the menu, not two. Where a menu holds more than one group the sections stay shut, because there the click is the choice.',
|
|
288
|
+
},
|
|
289
|
+
},
|
|
290
|
+
},
|
|
291
|
+
render: () => {
|
|
292
|
+
const [val, setVal] = useState<any>({});
|
|
293
|
+
return (
|
|
294
|
+
<FormEngine
|
|
295
|
+
name='autoFieldMenuDemo'
|
|
296
|
+
options={{
|
|
297
|
+
myAutoField: {
|
|
298
|
+
type: 'auto',
|
|
299
|
+
ui_type: 'auto',
|
|
300
|
+
display_name: 'My Auto Field',
|
|
301
|
+
preselected: true,
|
|
302
|
+
},
|
|
303
|
+
}}
|
|
304
|
+
value={val}
|
|
305
|
+
onChange={(_n, v) => setVal(v)}
|
|
306
|
+
/>
|
|
307
|
+
);
|
|
308
|
+
},
|
|
309
|
+
async play({ canvasElement }) {
|
|
310
|
+
const canvas = within(canvasElement);
|
|
264
311
|
await expect(
|
|
265
|
-
await canvas.findByText('
|
|
312
|
+
await canvas.findByText('My Auto Field', undefined, { timeout: 10000 })
|
|
266
313
|
).toBeInTheDocument();
|
|
314
|
+
|
|
315
|
+
const menu = await waitFor(
|
|
316
|
+
() => {
|
|
317
|
+
const el = canvasElement.querySelector('.template-more');
|
|
318
|
+
expect(el).toBeTruthy();
|
|
319
|
+
return el as HTMLElement;
|
|
320
|
+
},
|
|
321
|
+
{ timeout: 10000 }
|
|
322
|
+
);
|
|
323
|
+
await userEvent.click(menu);
|
|
324
|
+
|
|
325
|
+
// The section still names its rows...
|
|
326
|
+
await waitFor(
|
|
327
|
+
() => expect(document.body.textContent).toContain('Set Custom Value'),
|
|
328
|
+
{ timeout: 10000 }
|
|
329
|
+
);
|
|
330
|
+
// ...and the rows are there to click, with no header click in between.
|
|
331
|
+
await waitFor(() => expect(document.body.textContent).toContain('Ordered key-value pair'), {
|
|
332
|
+
timeout: 10000,
|
|
333
|
+
});
|
|
267
334
|
},
|
|
268
335
|
};
|
|
269
336
|
|
|
@@ -7,7 +7,6 @@ import {
|
|
|
7
7
|
ReqoreControlGroup,
|
|
8
8
|
ReqoreErrorBoundary,
|
|
9
9
|
ReqoreMessage,
|
|
10
|
-
ReqoreSpinner,
|
|
11
10
|
ReqoreTag,
|
|
12
11
|
} from '@qoretechnologies/reqore';
|
|
13
12
|
import { IReqoreFormTemplates } from '@qoretechnologies/reqore/dist/components/Textarea';
|
|
@@ -19,6 +18,7 @@ import { useUpdateEffect } from 'react-use';
|
|
|
19
18
|
import useMount from 'react-use/lib/useMount';
|
|
20
19
|
import { typedToYaml, yamlToTyped } from '../../../../helpers/common';
|
|
21
20
|
import { getListElementValue } from '../../../../helpers/options';
|
|
21
|
+
import { isSingleLineStringType } from '../../../../helpers/singleLineString';
|
|
22
22
|
import {
|
|
23
23
|
getTypeFromValue,
|
|
24
24
|
getValueOrDefaultValue,
|
|
@@ -53,6 +53,8 @@ import { IDataSchemaDefinition } from '../schema-definition/types';
|
|
|
53
53
|
import { ISelectFormFieldItem, SelectFormField } from '../select/Select';
|
|
54
54
|
import { StringFormField } from '../string/String';
|
|
55
55
|
import { UrlFormField } from '../url/Url';
|
|
56
|
+
import { FormFieldsSkeleton } from '../../engine/FormFieldsSkeleton';
|
|
57
|
+
import { isUntypedOptionType } from '../../../../helpers/optionUiTypes';
|
|
56
58
|
|
|
57
59
|
/** UI superset of `TQorusType` — the IDE's `Field/systemOptions` `IQorusType`. */
|
|
58
60
|
export type IQorusType = TQorusType | string;
|
|
@@ -62,9 +64,15 @@ export interface IAutoFieldProps
|
|
|
62
64
|
IWithReqoreSize,
|
|
63
65
|
Omit<
|
|
64
66
|
TQorusFormFieldSchema,
|
|
65
|
-
'get_message' | 'return_message' | 'on_change' | 'type' | 'arg_schema'
|
|
67
|
+
'get_message' | 'return_message' | 'on_change' | 'type' | 'arg_schema' | 'ui_type'
|
|
66
68
|
> {
|
|
67
69
|
name?: string;
|
|
70
|
+
/**
|
|
71
|
+
* The editor the schema asks for. Optional here although the shared
|
|
72
|
+
* descriptor requires it: the field renders from `type` / `defaultType` when
|
|
73
|
+
* there is none, and reads this only to pick an override or a special editor.
|
|
74
|
+
*/
|
|
75
|
+
ui_type?: IQorusType;
|
|
68
76
|
value?: any;
|
|
69
77
|
default_value?: any;
|
|
70
78
|
type?: IQorusType;
|
|
@@ -261,7 +269,7 @@ function AutoField<T = any>({
|
|
|
261
269
|
let internalType: IQorusType;
|
|
262
270
|
// If value already exists, but the type is auto or any
|
|
263
271
|
// set the type based on the value
|
|
264
|
-
if (value && (defType
|
|
272
|
+
if (value && isUntypedOptionType(defType) && !defaultInternalType) {
|
|
265
273
|
internalType = getTypeFromValue(maybeParseYaml(value)) as IQorusType;
|
|
266
274
|
} else {
|
|
267
275
|
internalType = defaultInternalType || defType;
|
|
@@ -296,7 +304,7 @@ function AutoField<T = any>({
|
|
|
296
304
|
if (typeValue && typeValue !== currentType) {
|
|
297
305
|
// If this is auto / any field
|
|
298
306
|
// set the internal type
|
|
299
|
-
if (typeValue
|
|
307
|
+
if (isUntypedOptionType(typeValue)) {
|
|
300
308
|
setInternalType(value ? (getTypeFromValue(maybeParseYaml(value)) as IQorusType) : 'any');
|
|
301
309
|
} else {
|
|
302
310
|
setInternalType(typeValue);
|
|
@@ -395,6 +403,13 @@ function AutoField<T = any>({
|
|
|
395
403
|
arg_schema={arg_schema}
|
|
396
404
|
element_type={element_type}
|
|
397
405
|
ui_element_type={ui_element_type}
|
|
406
|
+
// Same reason as the three above: it is destructured out of `rest` so the
|
|
407
|
+
// primitive renderers do not spread it onto a DOM node, which also took
|
|
408
|
+
// it away from host editors — and a host editor is exactly what
|
|
409
|
+
// `inherit_props` exists to feed. A field declaring it got the values
|
|
410
|
+
// resolved and then had nowhere to send them, so every consumer
|
|
411
|
+
// downstream saw `undefined` and silently did nothing.
|
|
412
|
+
inheritedFromParent={inheritedFromParent}
|
|
398
413
|
name={name}
|
|
399
414
|
value={value}
|
|
400
415
|
onChange={(val: any, emittedType?: IQorusType, emittedIsFunction?: boolean) => {
|
|
@@ -457,7 +472,10 @@ function AutoField<T = any>({
|
|
|
457
472
|
}
|
|
458
473
|
|
|
459
474
|
if (arg_schema && !finalArgSchema) {
|
|
460
|
-
|
|
475
|
+
/* One ROW, because this stands in for one field. It was a spinner reading
|
|
476
|
+
"Loading field data…", which is a different picture from every other
|
|
477
|
+
wait on the page and announces a delay the reader cannot act on. */
|
|
478
|
+
return <FormFieldsSkeleton rows={1} />;
|
|
461
479
|
}
|
|
462
480
|
|
|
463
481
|
const renderAllowedValues = (currentType: IQorusType) => {
|
|
@@ -490,6 +508,40 @@ function AutoField<T = any>({
|
|
|
490
508
|
);
|
|
491
509
|
};
|
|
492
510
|
|
|
511
|
+
/* Text that may hold template references is edited in the chip editor
|
|
512
|
+
whenever the field offers templates (`RichTextFormField`, `text` format):
|
|
513
|
+
each reference is drawn as the name it was chosen by and the value stays the
|
|
514
|
+
plain string. Text holding a reference anywhere but its start
|
|
515
|
+
(`Interface $local:id failed`) never enters template mode, so in a textarea
|
|
516
|
+
its references read as their spelling. */
|
|
517
|
+
const offersTemplates = rest.allowTemplates !== false && size(rest.templates?.items) > 0;
|
|
518
|
+
const renderTextEditor = (editorType: string) =>
|
|
519
|
+
offersTemplates ?
|
|
520
|
+
<RichTextFormField
|
|
521
|
+
{...rest}
|
|
522
|
+
valueFormat='text'
|
|
523
|
+
singleLine={isSingleLineStringType(editorType)}
|
|
524
|
+
allowTemplates
|
|
525
|
+
/* Stringified rather than blanked: an `auto` field resolved to a text
|
|
526
|
+
type can be holding a number, and showing an empty box for it reads
|
|
527
|
+
as the value having been lost. A non-string coming back out is not a
|
|
528
|
+
value this editor produced, so it is ignored rather than written as
|
|
529
|
+
'' over what is there. */
|
|
530
|
+
value={String(value ?? '')}
|
|
531
|
+
onChange={(next) => {
|
|
532
|
+
if (typeof next !== 'string') {
|
|
533
|
+
return;
|
|
534
|
+
}
|
|
535
|
+
handleChange(name, next);
|
|
536
|
+
}}
|
|
537
|
+
/>
|
|
538
|
+
: <LongStringFormField
|
|
539
|
+
{...rest}
|
|
540
|
+
type={editorType}
|
|
541
|
+
onChange={(next) => handleChange(name, next)}
|
|
542
|
+
value={value}
|
|
543
|
+
/>;
|
|
544
|
+
|
|
493
545
|
const renderField = (currentType: IQorusType) => {
|
|
494
546
|
// If this field is set to null
|
|
495
547
|
if (isSetToNull) {
|
|
@@ -565,18 +617,35 @@ function AutoField<T = any>({
|
|
|
565
617
|
// reqraft FormField vocabulary — the IDE calls it `string` (both render
|
|
566
618
|
// the textarea field).
|
|
567
619
|
switch (currentType) {
|
|
620
|
+
/* These four share an editor but not a shape: a `string` holds exactly
|
|
621
|
+
one line, while `data`, `binary` and `long-string` hold a document.
|
|
622
|
+
Without the type the field cannot tell them apart and treats them all
|
|
623
|
+
as documents, so an interface's Internal Name — which becomes a YAML
|
|
624
|
+
key — accepted Enter. Only text takes references; `data` and
|
|
625
|
+
`binary` are encoded content, where a chip would stand for nothing. */
|
|
568
626
|
case 'string':
|
|
627
|
+
case 'long-string':
|
|
628
|
+
return renderTextEditor(currentType);
|
|
569
629
|
case 'data':
|
|
570
630
|
case 'binary':
|
|
571
|
-
case 'long-string':
|
|
572
631
|
return (
|
|
573
632
|
<LongStringFormField
|
|
574
633
|
{...rest}
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
634
|
+
/* Say what the field takes before it is typed into. The server
|
|
635
|
+
decodes a binary value as base64 unless it is told otherwise
|
|
636
|
+
(`lib/misc.ql` `_priv_parse_ui_hash_value_intern`, symmetric
|
|
637
|
+
with the `toBase64()` it encodes with), and bare hex is the
|
|
638
|
+
trap: it is not rejected, it is read as base64 and corrupts.
|
|
639
|
+
`validateField` already accepts exactly these three spellings
|
|
640
|
+
— this is that rule said up front instead of after the fact.
|
|
641
|
+
Kept short enough to read in one line at phone width, where a
|
|
642
|
+
longer hint wrapped out of the field's single visible row. */
|
|
643
|
+
placeholder={
|
|
644
|
+
currentType === 'binary' ?
|
|
645
|
+
((rest as { placeholder?: string }).placeholder ??
|
|
646
|
+
'Base64, 0x hex, or data: URL')
|
|
647
|
+
: (rest as { placeholder?: string }).placeholder
|
|
648
|
+
}
|
|
580
649
|
type={currentType}
|
|
581
650
|
onChange={(value) => handleChange(name, value)}
|
|
582
651
|
value={value}
|
|
@@ -941,17 +1010,17 @@ function AutoField<T = any>({
|
|
|
941
1010
|
/>
|
|
942
1011
|
);
|
|
943
1012
|
}
|
|
1013
|
+
/* An UNTYPED field is typed into, never asked for a type.
|
|
1014
|
+
|
|
1015
|
+
It used to show a type picker and "Please select data type" — a
|
|
1016
|
+
question about storage ("is this a Text or a Number?") that an author
|
|
1017
|
+
writing a value often cannot answer, asked before they could write
|
|
1018
|
+
anything. What is typed is stored untyped, exactly as template mode
|
|
1019
|
+
stores it; a value of an explicit type is set from the field's ⋮ menu
|
|
1020
|
+
(see `FormEngine`'s `getCustomMenuTemplateItems`). */
|
|
944
1021
|
case 'any':
|
|
945
|
-
return null;
|
|
946
1022
|
case 'auto':
|
|
947
|
-
return (
|
|
948
|
-
<ReqoreTag
|
|
949
|
-
intent='warning'
|
|
950
|
-
minimal
|
|
951
|
-
icon='ErrorWarningLine'
|
|
952
|
-
label='Please select data type'
|
|
953
|
-
/>
|
|
954
|
-
);
|
|
1023
|
+
return renderTextEditor('string');
|
|
955
1024
|
default:
|
|
956
1025
|
return <ReqoreTag intent='danger' icon='SpamLine' label='Unknown type!' />;
|
|
957
1026
|
}
|
|
@@ -964,9 +1033,16 @@ function AutoField<T = any>({
|
|
|
964
1033
|
);
|
|
965
1034
|
};
|
|
966
1035
|
|
|
1036
|
+
/* No picker while the type is unresolved: the field is typed into instead
|
|
1037
|
+
(see the `auto` / `any` editor above). A field declaring several allowed
|
|
1038
|
+
types still picks between THOSE — that is a choice the schema offers, not a
|
|
1039
|
+
question about storage. */
|
|
1040
|
+
const typeIsUnresolved =
|
|
1041
|
+
!currentInternalType || isUntypedOptionType(currentInternalType);
|
|
967
1042
|
const showPicker =
|
|
968
1043
|
size(allowedTypes) > 1 ||
|
|
969
|
-
(
|
|
1044
|
+
(!typeIsUnresolved &&
|
|
1045
|
+
(!size(rest.allowed_values) ||
|
|
970
1046
|
(size(rest?.allowed_values) > 0 && !rest.allowed_values_creatable) ||
|
|
971
1047
|
!size(rest.element_allowed_values) ||
|
|
972
1048
|
(size(rest?.element_allowed_values) > 0 && !rest.element_allowed_values_creatable)) &&
|
|
@@ -17,7 +17,22 @@ const toFullIso = (value?: string | Date): string | Date | null => {
|
|
|
17
17
|
return value;
|
|
18
18
|
};
|
|
19
19
|
|
|
20
|
-
|
|
20
|
+
/**
|
|
21
|
+
* The language a date is written in: the page's own (`<html lang>`, which is the
|
|
22
|
+
* application's interface language), else the browser's preferred language.
|
|
23
|
+
*
|
|
24
|
+
* Reqore's DatePicker, given no locale, takes the first NON-English entry of
|
|
25
|
+
* `navigator.languages`, so a browser set to English with French as its second
|
|
26
|
+
* language showed "jj / mm / aaaa" in an English application.
|
|
27
|
+
*/
|
|
28
|
+
const pageLocale = (): string | undefined => {
|
|
29
|
+
if (typeof document !== 'undefined' && document.documentElement.lang) {
|
|
30
|
+
return document.documentElement.lang;
|
|
31
|
+
}
|
|
32
|
+
return typeof navigator !== 'undefined' ? navigator.language : undefined;
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
export const DateFormField = ({ value, onChange, disabled, locale, ...rest }: IDateFormFieldProps) => {
|
|
21
36
|
const theme = useReqoreTheme();
|
|
22
37
|
|
|
23
38
|
const handleChange = (date: TDateValue): void => {
|
|
@@ -27,6 +42,7 @@ export const DateFormField = ({ value, onChange, disabled, ...rest }: IDateFormF
|
|
|
27
42
|
return (
|
|
28
43
|
<DatePicker
|
|
29
44
|
{...rest}
|
|
45
|
+
locale={locale ?? pageLocale()}
|
|
30
46
|
style={{ width: '100%' }}
|
|
31
47
|
value={toFullIso(value) as TDateValue}
|
|
32
48
|
onChange={handleChange}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { ReqoreTextarea } from '@qoretechnologies/reqore';
|
|
2
2
|
import { IReqoreTextareaProps } from '@qoretechnologies/reqore/dist/components/Textarea';
|
|
3
|
-
import { ChangeEvent, KeyboardEvent, useCallback, useEffect, useState } from 'react';
|
|
3
|
+
import { ChangeEvent, KeyboardEvent, useCallback, useEffect, useRef, useState } from 'react';
|
|
4
4
|
import { useDebounce } from 'react-use';
|
|
5
5
|
import {
|
|
6
6
|
flattenToSingleLine,
|
|
@@ -29,16 +29,28 @@ export const LongStringFormField = ({
|
|
|
29
29
|
...rest
|
|
30
30
|
}: ILongStringFormFieldProps) => {
|
|
31
31
|
const [localValue, setLocalValue] = useState<string>(value ?? '');
|
|
32
|
+
/* What this field last TOLD its parent, which is not the same as the value it
|
|
33
|
+
was given. Comparing against the prop loses a clear wherever the parent
|
|
34
|
+
does not feed the value back: the prop stays `undefined`, so emptying the
|
|
35
|
+
text makes `localValue` '' and `value ?? ''` '' too, and the parent never
|
|
36
|
+
learns the field was emptied. Seeded from the initial value so a mount
|
|
37
|
+
reports nothing — an empty field's text is '' and its value `undefined`,
|
|
38
|
+
and reporting that difference marked every form holding an empty text
|
|
39
|
+
field as changed before anyone typed. */
|
|
40
|
+
const lastEmittedRef = useRef<string>(value ?? '');
|
|
32
41
|
|
|
33
42
|
useEffect(() => {
|
|
34
|
-
if (value !== localValue) {
|
|
43
|
+
if ((value ?? '') !== localValue) {
|
|
35
44
|
setLocalValue(value ?? '');
|
|
36
45
|
}
|
|
46
|
+
// A value from outside is not something to report back to whoever sent it.
|
|
47
|
+
lastEmittedRef.current = value ?? '';
|
|
37
48
|
}, [value]);
|
|
38
49
|
|
|
39
50
|
useDebounce(
|
|
40
51
|
() => {
|
|
41
|
-
if (localValue !==
|
|
52
|
+
if (localValue !== lastEmittedRef.current) {
|
|
53
|
+
lastEmittedRef.current = localValue;
|
|
42
54
|
onChange?.(localValue);
|
|
43
55
|
}
|
|
44
56
|
},
|
|
@@ -2,7 +2,11 @@ import { ReqoreMultiSelect } from '@qoretechnologies/reqore';
|
|
|
2
2
|
import { TReqoreMultiSelectItem } from '@qoretechnologies/reqore/dist/components/MultiSelect';
|
|
3
3
|
import { IQorusAllowedValue } from '@qoretechnologies/ts-toolkit';
|
|
4
4
|
import { memo, useMemo } from 'react';
|
|
5
|
-
import {
|
|
5
|
+
import {
|
|
6
|
+
getSelectItemShortDescription,
|
|
7
|
+
getSelectItemUnavailability,
|
|
8
|
+
UNAVAILABLE_ITEM_CLASS,
|
|
9
|
+
} from '../select/SelectCollection';
|
|
6
10
|
|
|
7
11
|
export interface IMultiSelectFormFieldProps {
|
|
8
12
|
/** Currently selected values (plain scalars) */
|
|
@@ -32,19 +36,62 @@ export const MultiSelectFormField = memo(
|
|
|
32
36
|
[JSON.stringify(value)]
|
|
33
37
|
);
|
|
34
38
|
|
|
39
|
+
/**
|
|
40
|
+
* The values this picker will not take, by their string form.
|
|
41
|
+
*
|
|
42
|
+
* Only a refusal the SERVER resolved reaches here: this component is handed
|
|
43
|
+
* the raw `allowed_values`, not the mapped items the single-value pickers
|
|
44
|
+
* build, so a value's own `depends_on` is not judged against the form —
|
|
45
|
+
* see `design/UNAVAILABLE_ALLOWED_VALUES.md`.
|
|
46
|
+
*/
|
|
47
|
+
const refusedValues = useMemo<Set<string>>(
|
|
48
|
+
() =>
|
|
49
|
+
new Set(
|
|
50
|
+
items
|
|
51
|
+
.filter(
|
|
52
|
+
(item) =>
|
|
53
|
+
!!getSelectItemUnavailability({
|
|
54
|
+
disabled: item.disabled,
|
|
55
|
+
messages: item.messages,
|
|
56
|
+
})
|
|
57
|
+
)
|
|
58
|
+
.map((item) => String(item.value?.value ?? ''))
|
|
59
|
+
),
|
|
60
|
+
[JSON.stringify(items)]
|
|
61
|
+
);
|
|
62
|
+
|
|
35
63
|
const reqoreItems = useMemo<TReqoreMultiSelectItem[]>(() => {
|
|
36
64
|
const base = items.map(
|
|
37
65
|
(item): TReqoreMultiSelectItem => {
|
|
38
66
|
const description = getSelectItemShortDescription(item);
|
|
67
|
+
/* Never reqore's `disabled` for a refused VALUE: it applies
|
|
68
|
+
`DisabledElement` (`pointer-events: none`), which takes the row's
|
|
69
|
+
tooltip with it — the one place the whole reason fits. The
|
|
70
|
+
refusal itself is in `onValueChange` below, because reqore owns
|
|
71
|
+
this list's selection and there is no per-row handler to drop. */
|
|
72
|
+
const unavailable = getSelectItemUnavailability({
|
|
73
|
+
disabled: item.disabled,
|
|
74
|
+
messages: item.messages,
|
|
75
|
+
});
|
|
39
76
|
|
|
40
77
|
return {
|
|
41
78
|
value: item.value?.value as string,
|
|
42
79
|
label: item.display_name ?? String(item.value?.value ?? ''),
|
|
43
|
-
description
|
|
80
|
+
description:
|
|
81
|
+
unavailable ?
|
|
82
|
+
[unavailable.title, unavailable.content, description].filter(Boolean).join(' — ')
|
|
83
|
+
: description,
|
|
84
|
+
tooltip: unavailable ? unavailable.content : undefined,
|
|
85
|
+
icon: unavailable ? ('LockLine' as const) : undefined,
|
|
86
|
+
className: unavailable ? UNAVAILABLE_ITEM_CLASS : undefined,
|
|
87
|
+
effect: unavailable ? { opacity: 0.55 } : undefined,
|
|
88
|
+
readOnly: !!unavailable,
|
|
44
89
|
wrap: true,
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
90
|
+
/* IDE parity: when `*` is selected, every other item is disabled.
|
|
91
|
+
That one stays reqore's `disabled` — the wildcard is a state of
|
|
92
|
+
the SELECTION rather than a refusal of the value, and it has no
|
|
93
|
+
reason of its own to protect. */
|
|
94
|
+
disabled: selectedValues.includes('*') && item.value?.value !== '*',
|
|
48
95
|
};
|
|
49
96
|
}
|
|
50
97
|
);
|
|
@@ -63,8 +110,20 @@ export const MultiSelectFormField = memo(
|
|
|
63
110
|
items={reqoreItems}
|
|
64
111
|
value={selectedValues}
|
|
65
112
|
onValueChange={(selected) => {
|
|
113
|
+
/* The refusal, for the same reason the rows carry no `disabled`: the
|
|
114
|
+
row itself has no handler to withhold, so this is where a refused
|
|
115
|
+
value is dropped. A value already HELD is kept even once it is
|
|
116
|
+
refused — the picker will not take it again, but clearing an
|
|
117
|
+
answer the author gave because a sibling edit closed the value is
|
|
118
|
+
worse than holding one the form can no longer offer.
|
|
119
|
+
|
|
120
|
+
Before the wildcard, so that a refused `*` is refused too. */
|
|
121
|
+
const accepted = selected.filter(
|
|
122
|
+
(val) => selectedValues.includes(val) || !refusedValues.has(val)
|
|
123
|
+
);
|
|
124
|
+
|
|
66
125
|
// IDE parity: picking the `*` wildcard collapses the selection.
|
|
67
|
-
onChange?.(
|
|
126
|
+
onChange?.(accepted.includes('*') ? ['*'] : (accepted as unknown[]));
|
|
68
127
|
}}
|
|
69
128
|
disabled={disabled}
|
|
70
129
|
size={size as any}
|