@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
|
@@ -97,22 +97,22 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
97
97
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
98
98
|
};
|
|
99
99
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
100
|
-
exports.FormEngine = exports.getTypeAndCanBeNull = exports.flattenOptions = exports.fixOptions = exports.OptionsContext = exports.hasRequiredOptions = exports.fixOperatorValue = exports.getType = void 0;
|
|
100
|
+
exports.FormEngine = exports.getTypeAndCanBeNull = exports.flattenOptions = exports.shouldEmitLocalValue = exports.agreementFromRebuild = exports.isMirrorOfValue = exports.fixOptions = exports.OptionsContext = exports.hasRequiredOptions = exports.getOptionFieldStorageType = exports.fixOperatorValue = exports.getType = exports.inheritedScopeFor = void 0;
|
|
101
101
|
var react_1 = require("react");
|
|
102
102
|
var jsx_runtime_1 = require("react/jsx-runtime");
|
|
103
103
|
var reqore_1 = require("@qoretechnologies/reqore");
|
|
104
104
|
var colors_1 = require("@qoretechnologies/reqore/dist/helpers/colors");
|
|
105
|
+
var argumentPresence_1 = require("../expressions/argumentPresence");
|
|
106
|
+
var typeChoices_1 = require("./typeChoices");
|
|
105
107
|
var optionActions_1 = require("./optionActions");
|
|
106
108
|
var rendererTypes_1 = require("./rendererTypes");
|
|
107
109
|
var lodash_1 = require("lodash");
|
|
108
|
-
var isArray_1 = __importDefault(require("lodash/isArray"));
|
|
109
110
|
var map_1 = __importDefault(require("lodash/map"));
|
|
110
111
|
var reduce_1 = __importDefault(require("lodash/reduce"));
|
|
111
112
|
var size_1 = __importDefault(require("lodash/size"));
|
|
112
113
|
var react_2 = __importStar(require("react"));
|
|
113
114
|
var react_use_1 = require("react-use");
|
|
114
115
|
var styled_components_1 = __importStar(require("styled-components"));
|
|
115
|
-
var use_context_selector_1 = require("use-context-selector");
|
|
116
116
|
var common_1 = require("../../../helpers/common");
|
|
117
117
|
var options_1 = require("../../../helpers/options");
|
|
118
118
|
var validations_1 = require("../../../helpers/validations");
|
|
@@ -124,13 +124,16 @@ var FocusedEditing_1 = require("../../FocusedEditing");
|
|
|
124
124
|
var Select_1 = require("../fields/select/Select");
|
|
125
125
|
var TemplateField_1 = require("../fields/template/TemplateField");
|
|
126
126
|
var CompactRow_1 = require("./CompactRow");
|
|
127
|
+
var FormFieldsSkeleton_1 = require("./FormFieldsSkeleton");
|
|
127
128
|
var compactRowContext_1 = require("./compactRowContext");
|
|
128
129
|
var compactRowStyles_1 = require("./compactRowStyles");
|
|
129
130
|
var CompactToolbar_1 = require("./CompactToolbar");
|
|
130
131
|
var compactToolbarContext_1 = require("./compactToolbarContext");
|
|
131
132
|
var OptionFieldMessages_1 = require("./OptionFieldMessages");
|
|
133
|
+
var optionsContext_1 = require("./optionsContext");
|
|
132
134
|
var markdownRendererContext_1 = require("../../Description/markdownRendererContext");
|
|
133
135
|
var OptionsHelpDialog_1 = require("./OptionsHelpDialog");
|
|
136
|
+
var optionUiTypes_1 = require("../../../helpers/optionUiTypes");
|
|
134
137
|
var readFirst_1 = require("./readFirst");
|
|
135
138
|
/**
|
|
136
139
|
* Resolve a field's `inherit_props` map against the current available
|
|
@@ -170,6 +173,43 @@ var resolveInheritProps = function (inheritProps, availableOptions, inheritedFro
|
|
|
170
173
|
}
|
|
171
174
|
return out;
|
|
172
175
|
};
|
|
176
|
+
/** One shared "nothing came down from above" bag. See `inheritedScopeFor`. */
|
|
177
|
+
var NO_INHERITED_SCOPE = Object.freeze({});
|
|
178
|
+
/**
|
|
179
|
+
* The inheritance bag ONE field forwards to any `arg_schema` sub-form it hosts:
|
|
180
|
+
* whatever the ancestor chain passed down, plus whatever this field's own
|
|
181
|
+
* `inherit_props` resolves to.
|
|
182
|
+
*
|
|
183
|
+
* Written as a function with a stable answer because it is a PROP, and a prop
|
|
184
|
+
* that is a new object on every render re-renders the field that receives it
|
|
185
|
+
* every time this form renders — for most fields, forever, over a value that
|
|
186
|
+
* never changed. It showed up in the console as `Template field kind Updated
|
|
187
|
+
* because: {inheritedFromParent}` repeating on a form nobody was touching:
|
|
188
|
+
* `kind` declares no `inherit_props` at all, so the bag it was handed was
|
|
189
|
+
* `{ ...(undefined ?? {}) }` — a fresh empty object each time, unequal to the
|
|
190
|
+
* last one, and `TemplateField` is memoised precisely so it does not re-render
|
|
191
|
+
* on a prop that did not change.
|
|
192
|
+
*
|
|
193
|
+
* So a field with nothing of its own to add forwards the bag it was HANDED,
|
|
194
|
+
* unchanged and unwrapped, and a form with no inherited scope at all forwards
|
|
195
|
+
* one shared frozen object rather than minting one per field per render.
|
|
196
|
+
*
|
|
197
|
+
* Mirrored in qorus-ide's `systemOptions.tsx` (which grew this treatment
|
|
198
|
+
* first); per the CLAUDE.md rule there, the forwarding logic is kept identical
|
|
199
|
+
* in both until FormEngine replaces that renderer.
|
|
200
|
+
*
|
|
201
|
+
* @param inheritProps the field's `inherit_props` map, if it declares one
|
|
202
|
+
* @param availableOptions this form's fields, where a sibling's value is read
|
|
203
|
+
* @param inheritedFromParent the bag threaded in from an outer form
|
|
204
|
+
*/
|
|
205
|
+
var inheritedScopeFor = function (inheritProps, availableOptions, inheritedFromParent) {
|
|
206
|
+
var resolved = resolveInheritProps(inheritProps, availableOptions, inheritedFromParent);
|
|
207
|
+
if (!Object.keys(resolved).length) {
|
|
208
|
+
return inheritedFromParent !== null && inheritedFromParent !== void 0 ? inheritedFromParent : NO_INHERITED_SCOPE;
|
|
209
|
+
}
|
|
210
|
+
return __assign(__assign({}, (inheritedFromParent !== null && inheritedFromParent !== void 0 ? inheritedFromParent : {})), resolved);
|
|
211
|
+
};
|
|
212
|
+
exports.inheritedScopeFor = inheritedScopeFor;
|
|
173
213
|
var NegativeColorEffect = {
|
|
174
214
|
gradient: {
|
|
175
215
|
colors: { 0: 'danger', 100: 'danger:darken:2' },
|
|
@@ -188,8 +228,7 @@ var PositiveColorEffect = {
|
|
|
188
228
|
// group panels; colours come in as props so the layout follows the Reqore theme.
|
|
189
229
|
var StyledCompactWrap = styled_components_1.default.div(templateObject_3 || (templateObject_3 = __makeTemplateObject(["\n display: flex;\n flex-flow: column;\n gap: 10px;\n width: 100%;\n /* Allow the wrap to shrink inside flex/grid parents so its rows' ellipsis can\n engage instead of overflowing the container horizontally. */\n min-width: 0;\n max-width: 100%;\n\n /* Scroll ownership \u2014 see `compactScroll`.\n\n 'host' (the default): the page or panel around us already scrolls, so we\n must not cap our height and scroll our own body, or the reader gets two\n scrollbars in two styles and cannot tell which moves what.\n\n `overflow-x: clip`, NOT `hidden`: CSS coerces an `overflow-y: visible`\n to `auto` whenever the other axis is neither visible nor clip, which would\n leave this box a scroll container \u2014 the element stops scrolling only\n because `max-height: none` means nothing overflows, while `position:\n sticky` inside it still resolves against US instead of the host, so the\n toolbar silently stops pinning. `clip` keeps the horizontal guard without\n that coercion. */\n ", "\n\n /* Option logos (e.g. language images) render as <img> inside ReqoreIcon's\n square box; constrain them so portrait PNGs don't overflow the row. */\n .reqore-icon img {\n width: 100%;\n height: 100%;\n object-fit: contain;\n }\n"], ["\n display: flex;\n flex-flow: column;\n gap: 10px;\n width: 100%;\n /* Allow the wrap to shrink inside flex/grid parents so its rows' ellipsis can\n engage instead of overflowing the container horizontally. */\n min-width: 0;\n max-width: 100%;\n\n /* Scroll ownership \u2014 see \\`compactScroll\\`.\n\n 'host' (the default): the page or panel around us already scrolls, so we\n must not cap our height and scroll our own body, or the reader gets two\n scrollbars in two styles and cannot tell which moves what.\n\n \\`overflow-x: clip\\`, NOT \\`hidden\\`: CSS coerces an \\`overflow-y: visible\\`\n to \\`auto\\` whenever the other axis is neither visible nor clip, which would\n leave this box a scroll container \u2014 the element stops scrolling only\n because \\`max-height: none\\` means nothing overflows, while \\`position:\n sticky\\` inside it still resolves against US instead of the host, so the\n toolbar silently stops pinning. \\`clip\\` keeps the horizontal guard without\n that coercion. */\n ", "\n\n /* Option logos (e.g. language images) render as <img> inside ReqoreIcon's\n square box; constrain them so portrait PNGs don't overflow the row. */\n .reqore-icon img {\n width: 100%;\n height: 100%;\n object-fit: contain;\n }\n"])), function (_a) {
|
|
190
230
|
var $ownScroll = _a.$ownScroll;
|
|
191
|
-
return $ownScroll
|
|
192
|
-
? (0, styled_components_1.css)(templateObject_1 || (templateObject_1 = __makeTemplateObject(["\n /* 'own': we are the scroller. The sticky toolbar pins to whatever\n scrolls, so a host whose scrollport carries top padding would\n resolve sticky `top: 0` against its padding box and leave an\n unblurred strip above the toolbar. Scrolling in this unpadded box\n pins it flush. Cap at the host's available height, but do not grow\n to fill it \u2014 short forms still hug their content.\n\n `min-height: 0` is what lets a flex item shrink below its content\n so there is something to scroll; it belongs to this branch only. */\n min-height: 0;\n max-height: 100%;\n overflow-y: auto;\n overflow-x: hidden;\n "], ["\n /* 'own': we are the scroller. The sticky toolbar pins to whatever\n scrolls, so a host whose scrollport carries top padding would\n resolve sticky \\`top: 0\\` against its padding box and leave an\n unblurred strip above the toolbar. Scrolling in this unpadded box\n pins it flush. Cap at the host's available height, but do not grow\n to fill it \u2014 short forms still hug their content.\n\n \\`min-height: 0\\` is what lets a flex item shrink below its content\n so there is something to scroll; it belongs to this branch only. */\n min-height: 0;\n max-height: 100%;\n overflow-y: auto;\n overflow-x: hidden;\n "]))) : (0, styled_components_1.css)(templateObject_2 || (templateObject_2 = __makeTemplateObject(["\n /* `min-height: auto` is load-bearing, not a default: inside a column\n flex parent the shrink allowance above collapses this box to zero\n height while its rows paint outside it, so the form looks right but\n contributes nothing to layout \u2014 the host cannot size or scroll to\n it and anything below it stacks against nothing. */\n min-height: auto;\n max-height: none;\n overflow-y: visible;\n overflow-x: clip;\n "], ["\n /* \\`min-height: auto\\` is load-bearing, not a default: inside a column\n flex parent the shrink allowance above collapses this box to zero\n height while its rows paint outside it, so the form looks right but\n contributes nothing to layout \u2014 the host cannot size or scroll to\n it and anything below it stacks against nothing. */\n min-height: auto;\n max-height: none;\n overflow-y: visible;\n overflow-x: clip;\n "])));
|
|
231
|
+
return $ownScroll ? (0, styled_components_1.css)(templateObject_1 || (templateObject_1 = __makeTemplateObject(["\n /* 'own': we are the scroller. The sticky toolbar pins to whatever\n scrolls, so a host whose scrollport carries top padding would\n resolve sticky `top: 0` against its padding box and leave an\n unblurred strip above the toolbar. Scrolling in this unpadded box\n pins it flush. Cap at the host's available height, but do not grow\n to fill it \u2014 short forms still hug their content.\n\n `min-height: 0` is what lets a flex item shrink below its content\n so there is something to scroll; it belongs to this branch only. */\n min-height: 0;\n max-height: 100%;\n overflow-y: auto;\n overflow-x: hidden;\n "], ["\n /* 'own': we are the scroller. The sticky toolbar pins to whatever\n scrolls, so a host whose scrollport carries top padding would\n resolve sticky \\`top: 0\\` against its padding box and leave an\n unblurred strip above the toolbar. Scrolling in this unpadded box\n pins it flush. Cap at the host's available height, but do not grow\n to fill it \u2014 short forms still hug their content.\n\n \\`min-height: 0\\` is what lets a flex item shrink below its content\n so there is something to scroll; it belongs to this branch only. */\n min-height: 0;\n max-height: 100%;\n overflow-y: auto;\n overflow-x: hidden;\n "]))) : (0, styled_components_1.css)(templateObject_2 || (templateObject_2 = __makeTemplateObject(["\n /* `min-height: auto` is load-bearing, not a default: inside a column\n flex parent the shrink allowance above collapses this box to zero\n height while its rows paint outside it, so the form looks right but\n contributes nothing to layout \u2014 the host cannot size or scroll to\n it and anything below it stacks against nothing. */\n min-height: auto;\n max-height: none;\n overflow-y: visible;\n overflow-x: clip;\n "], ["\n /* \\`min-height: auto\\` is load-bearing, not a default: inside a column\n flex parent the shrink allowance above collapses this box to zero\n height while its rows paint outside it, so the form looks right but\n contributes nothing to layout \u2014 the host cannot size or scroll to\n it and anything below it stacks against nothing. */\n min-height: auto;\n max-height: none;\n overflow-y: visible;\n overflow-x: clip;\n "])));
|
|
193
232
|
});
|
|
194
233
|
// Batched-commit dock: a floating Save/Discard card pinned bottom-right. Sticky
|
|
195
234
|
// (not fixed) so it stays within the form's own scroll bounds when the engine
|
|
@@ -207,7 +246,7 @@ var StyledCommitDock = styled_components_1.default.div(templateObject_4 || (temp
|
|
|
207
246
|
});
|
|
208
247
|
var getType = function (type, operators, operator) {
|
|
209
248
|
var finalType = getTypeFromOperator(operators, (0, common_1.fixOperatorValue)(operator)) || type;
|
|
210
|
-
var resolvedType = (0,
|
|
249
|
+
var resolvedType = (0, optionUiTypes_1.firstDeclaredType)(finalType);
|
|
211
250
|
// A value can be received before its server-driven option schema. Keep the
|
|
212
251
|
// renderer type-safe during that transition without guessing a concrete type.
|
|
213
252
|
return (resolvedType || 'any');
|
|
@@ -231,20 +270,64 @@ var getOptionSchemaStorageType = function (option, isRendererOnly) {
|
|
|
231
270
|
: isRendererOnly(option === null || option === void 0 ? void 0 : option.ui_type) ? (option === null || option === void 0 ? void 0 : option.type) || (option === null || option === void 0 ? void 0 : option.ui_type)
|
|
232
271
|
: (option === null || option === void 0 ? void 0 : option.ui_type) || (option === null || option === void 0 ? void 0 : option.type)) || 'any');
|
|
233
272
|
};
|
|
234
|
-
|
|
273
|
+
/**
|
|
274
|
+
* Whether an option currently holds an expression, in EITHER shape it comes in.
|
|
275
|
+
*
|
|
276
|
+
* At runtime the editor writes the flag onto the option itself
|
|
277
|
+
* (`{ type, is_expression: true, value }`), but a value loaded from a saved
|
|
278
|
+
* draft carries the envelope NESTED (`{ type, value: { is_expression: true,
|
|
279
|
+
* value } }`). Same thing, two shapes, and only the flat one was ever checked —
|
|
280
|
+
* so a freshly typed expression behaved while a reloaded one did not, which is
|
|
281
|
+
* exactly how this survived several fixes: every test used the runtime shape.
|
|
282
|
+
*/
|
|
283
|
+
var optionHoldsExpression = function (option) {
|
|
284
|
+
var _a;
|
|
285
|
+
var o = option;
|
|
286
|
+
return !!((o === null || o === void 0 ? void 0 : o.is_expression) || ((_a = o === null || o === void 0 ? void 0 : o.value) === null || _a === void 0 ? void 0 : _a.is_expression));
|
|
287
|
+
};
|
|
288
|
+
/**
|
|
289
|
+
* Which type an option resolves to — the schema's, or the one stored on the
|
|
290
|
+
* value.
|
|
291
|
+
*
|
|
292
|
+
* Exported because this single decision is what every option field is rendered
|
|
293
|
+
* with, and what an expression's return type is checked against. It deserves
|
|
294
|
+
* to be assertable without standing up a form.
|
|
295
|
+
*/
|
|
296
|
+
var getOptionFieldStorageType = function (optionName, fieldType, schema, operators, operatorData, isRendererOnly,
|
|
297
|
+
/** Whether the stored value is an expression — see below. */
|
|
298
|
+
isExpression) {
|
|
235
299
|
if (isRendererOnly === void 0) { isRendererOnly = rendererTypes_1.isRendererOnlyUiType; }
|
|
236
300
|
var schemaOption = schema === null || schema === void 0 ? void 0 : schema[optionName];
|
|
237
|
-
|
|
301
|
+
/* A STORED type does not describe an expression.
|
|
302
|
+
|
|
303
|
+
An expression value is `{ is_expression: true, value: {...} }`, so the type
|
|
304
|
+
recorded beside it describes that envelope — `hash` — and not what the
|
|
305
|
+
field holds. Letting it win means the SCHEMA's declared type is ignored and
|
|
306
|
+
the wrong answer is handed to the expression editor as the return type to
|
|
307
|
+
check against: `1 + 2` on a field declared `"type": "auto"` came back
|
|
308
|
+
"The expression returns int, and this field holds hash". A literal `1` was
|
|
309
|
+
fine, because a literal is stored as a plain value whose type matches.
|
|
310
|
+
|
|
311
|
+
`auto`/`any` accept anything, which is exactly why nothing should be
|
|
312
|
+
checked against them; a concrete declared type still is. The schema is the
|
|
313
|
+
only party that knows what the field accepts. */
|
|
314
|
+
var storedType = (!isExpression &&
|
|
315
|
+
fieldType &&
|
|
316
|
+
!(fieldType === (schemaOption === null || schemaOption === void 0 ? void 0 : schemaOption.ui_type) && isRendererOnly(fieldType))) ?
|
|
238
317
|
fieldType
|
|
239
318
|
: getOptionSchemaStorageType(schemaOption, isRendererOnly);
|
|
240
319
|
return (0, exports.getType)(storedType, operators, operatorData);
|
|
241
320
|
};
|
|
321
|
+
exports.getOptionFieldStorageType = getOptionFieldStorageType;
|
|
242
322
|
var hasRequiredOptions = function (options) {
|
|
243
323
|
if (options === void 0) { options = {}; }
|
|
244
324
|
return !!(0, lodash_1.findKey)(options, function (option) { return option.required; });
|
|
245
325
|
};
|
|
246
326
|
exports.hasRequiredOptions = hasRequiredOptions;
|
|
247
|
-
|
|
327
|
+
/* Re-exported from the module that owns it so the existing import path keeps
|
|
328
|
+
working; see `optionsContext.ts` for why it is not declared here. */
|
|
329
|
+
var optionsContext_2 = require("./optionsContext");
|
|
330
|
+
Object.defineProperty(exports, "OptionsContext", { enumerable: true, get: function () { return optionsContext_2.OptionsContext; } });
|
|
248
331
|
var fixOptions = function (value, options, operators, isRendererOnly) {
|
|
249
332
|
if (value === void 0) { value = {}; }
|
|
250
333
|
if (isRendererOnly === void 0) { isRendererOnly = rendererTypes_1.isRendererOnlyUiType; }
|
|
@@ -370,6 +453,64 @@ var normalizeEmptyFieldValues = function (fields) {
|
|
|
370
453
|
return acc;
|
|
371
454
|
}, {});
|
|
372
455
|
};
|
|
456
|
+
/**
|
|
457
|
+
* Does this rebuild say anything the parent does not already hold?
|
|
458
|
+
*
|
|
459
|
+
* `false` means the rebuild is a MIRROR: `fixOptions` found no default to
|
|
460
|
+
* materialise, so the result repeats the `value` the parent handed down. The
|
|
461
|
+
* compare is empty-normalized because `fixOptions` round-trips a required-empty
|
|
462
|
+
* field between `{ value: '' }` and no `value` key, and that cosmetic
|
|
463
|
+
* difference would otherwise read as new information forever.
|
|
464
|
+
*/
|
|
465
|
+
var isMirrorOfValue = function (fixedValue, value) { return (0, lodash_1.isEqual)(normalizeEmptyFieldValues(fixedValue), normalizeEmptyFieldValues(value)); };
|
|
466
|
+
exports.isMirrorOfValue = isMirrorOfValue;
|
|
467
|
+
/**
|
|
468
|
+
* What this rebuild lets the form agree with the parent on, if anything.
|
|
469
|
+
*
|
|
470
|
+
* Returns the rebuild when it mirrors `value`, and `undefined` when it
|
|
471
|
+
* contributed something the parent has yet to learn.
|
|
472
|
+
*
|
|
473
|
+
* Adopting the parent's value IS agreement, and saying so matters as much as
|
|
474
|
+
* staying quiet about it. The sync-down skips only when the parent echoed what
|
|
475
|
+
* this form last sent; if adopting a value never updates that record, it points
|
|
476
|
+
* at an older state forever, the skip can never fire again, and the form
|
|
477
|
+
* rebuilds on every single change. Holding the mirror back WITHOUT recording
|
|
478
|
+
* the agreement was measured making the starvation worse, not better — 8 s
|
|
479
|
+
* became a 45 s timeout — which is why the two belong together.
|
|
480
|
+
*/
|
|
481
|
+
var agreementFromRebuild = function (fixedValue, value) {
|
|
482
|
+
return (0, exports.isMirrorOfValue)(fixedValue, value) ? fixedValue : undefined;
|
|
483
|
+
};
|
|
484
|
+
exports.agreementFromRebuild = agreementFromRebuild;
|
|
485
|
+
/**
|
|
486
|
+
* Should the form report `localValue` to its parent as an answer?
|
|
487
|
+
*
|
|
488
|
+
* Extracted and pure because the situation it exists for cannot be reproduced
|
|
489
|
+
* through a rendered form: it needs the emit to be decided against a `value`
|
|
490
|
+
* NEWER than the `localValue` built from it, which only happens when two
|
|
491
|
+
* components' effects land in one React commit — and a test renderer flushes
|
|
492
|
+
* effects between updates, so the two never fall out of step. The states below
|
|
493
|
+
* were recorded from a live instrumented run instead, and this is what makes
|
|
494
|
+
* them assertable.
|
|
495
|
+
*
|
|
496
|
+
* Two ways the answer is no:
|
|
497
|
+
*
|
|
498
|
+
* 1. `localValue` is a mirror — a rebuild of the parent's own value that added
|
|
499
|
+
* nothing. Repeating it back is not an answer. **Checked first**, because
|
|
500
|
+
* the comparison in (2) reads whatever `value` has become by now, which,
|
|
501
|
+
* when a nested engine shares the parent value, is already that engine's
|
|
502
|
+
* newer write; comparing against it would find a difference this form never
|
|
503
|
+
* made and emit the older mirror over the newer write. That is the loop.
|
|
504
|
+
* 2. `localValue` already equals `value` — there is nothing to report.
|
|
505
|
+
*/
|
|
506
|
+
var shouldEmitLocalValue = function (_a) {
|
|
507
|
+
var localValue = _a.localValue, value = _a.value, mirroredValue = _a.mirroredValue;
|
|
508
|
+
if (mirroredValue !== undefined && (0, lodash_1.isEqual)(localValue, mirroredValue)) {
|
|
509
|
+
return false;
|
|
510
|
+
}
|
|
511
|
+
return !(0, lodash_1.isEqual)(localValue, value);
|
|
512
|
+
};
|
|
513
|
+
exports.shouldEmitLocalValue = shouldEmitLocalValue;
|
|
373
514
|
var flattenOptions = function (options) {
|
|
374
515
|
return (0, reduce_1.default)(options, function (newOptions, option, optionName) {
|
|
375
516
|
var _a;
|
|
@@ -390,7 +531,7 @@ var getTypeAndCanBeNull = function (type, allowed_values, operatorData, operator
|
|
|
390
531
|
return {
|
|
391
532
|
type: realType,
|
|
392
533
|
defaultType: realType,
|
|
393
|
-
defaultInternalType:
|
|
534
|
+
defaultInternalType: (0, optionUiTypes_1.isUntypedOptionType)(realType) ? undefined : realType,
|
|
394
535
|
canBeNull: canBeNull,
|
|
395
536
|
};
|
|
396
537
|
};
|
|
@@ -398,29 +539,29 @@ exports.getTypeAndCanBeNull = getTypeAndCanBeNull;
|
|
|
398
539
|
// Option types rendered full-width (IDE Options parity, commit 8e6b7781).
|
|
399
540
|
var STRECHABLE_TYPES = new Set(['tool-catalog']);
|
|
400
541
|
var FormEngineImpl = function (_a) {
|
|
401
|
-
var _b, _c, _d, _f, _g
|
|
542
|
+
var _b, _c, _d, _f, _g;
|
|
402
543
|
var name = _a.name, uniqueName = _a.uniqueName, value = _a.value, onChange = _a.onChange, onSingleOptionsChange = _a.onSingleOptionsChange, onDependableOptionChange = _a.onDependableOptionChange, placeholder = _a.placeholder, noValueString = _a.noValueString, // eslint-disable-line @typescript-eslint/no-unused-vars
|
|
403
544
|
isValid = _a.isValid, // eslint-disable-line @typescript-eslint/no-unused-vars
|
|
404
|
-
url = _a.url, customUrl = _a.customUrl, operatorsUrl = _a.operatorsUrl, onOptionsLoaded = _a.onOptionsLoaded, recordRequiresSearchOptions = _a.recordRequiresSearchOptions, readOnly = _a.readOnly,
|
|
545
|
+
url = _a.url, customUrl = _a.customUrl, operatorsUrl = _a.operatorsUrl, onOptionsLoaded = _a.onOptionsLoaded, recordRequiresSearchOptions = _a.recordRequiresSearchOptions, readOnly = _a.readOnly, onReadOnlyActivate = _a.onReadOnlyActivate, _h = _a.allowTemplates, allowTemplates = _h === void 0 ? true : _h, interfaceContext = _a.interfaceContext, templateFieldProps = _a.templateFieldProps, forceDropdown = _a.forceDropdown, _j = _a.showTypeToggle, showTypeToggle = _j === void 0 ? true : _j, compact = _a.compact,
|
|
405
546
|
// Destructured only to keep it out of `rest` (and so off the DOM). The gutter
|
|
406
547
|
// this prop documents was never implemented: it was passed to the wrap as
|
|
407
548
|
// `$flush`, whose styled template had no interpolation slot, so it has always
|
|
408
549
|
// been a no-op. Removing it from the API is a separate, breaking change —
|
|
409
550
|
// every consumer passing it today already gets the flush layout by default.
|
|
410
551
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
411
|
-
|
|
552
|
+
_k = _a.compactFlush,
|
|
412
553
|
// Destructured only to keep it out of `rest` (and so off the DOM). The gutter
|
|
413
554
|
// this prop documents was never implemented: it was passed to the wrap as
|
|
414
555
|
// `$flush`, whose styled template had no interpolation slot, so it has always
|
|
415
556
|
// been a no-op. Removing it from the API is a separate, breaking change —
|
|
416
557
|
// every consumer passing it today already gets the flush layout by default.
|
|
417
558
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
418
|
-
compactFlush =
|
|
559
|
+
compactFlush = _k === void 0 ? false : _k, _l = _a.compactNested, compactNested = _l === void 0 ? false : _l, _m = _a.compactScroll, compactScroll = _m === void 0 ? 'host' : _m, compactPanelProps = _a.compactPanelProps, compactCollapsedGroupsProp = _a.compactCollapsedGroups, compactBoxLabels = _a.compactBoxLabels, _o = _a.compactStickyBoxHeaders, compactStickyBoxHeaders = _o === void 0 ? true : _o, _p = _a.compactStickyOffset, compactStickyOffset = _p === void 0 ? 0 : _p, _q = _a.compactToolbar, compactToolbar = _q === void 0 ? true : _q, _r = _a.commitMode, commitMode = _r === void 0 ? 'immediate' : _r, _s = _a.expandMode, expandMode = _s === void 0 ? 'single' : _s, onCommit = _a.onCommit, operatorsProp = _a.operators, groups = _a.groups, optionsLoader = _a.optionsLoader, onValidityChange = _a.onValidityChange, optionActions = _a.optionActions, _t = _a.optionActionsCollapse, optionActionsCollapse = _t === void 0 ? 'auto' : _t, componentOverrides = _a.componentOverrides, codePreviewRenderer = _a.codePreviewRenderer,
|
|
419
560
|
// consumed by the wrapper below, which publishes it to every description this
|
|
420
561
|
// form draws; destructured here only so it cannot reach `rest` and be spread
|
|
421
562
|
// onto a DOM node
|
|
422
563
|
_markdownRenderer = _a.markdownRenderer, // eslint-disable-line @typescript-eslint/no-unused-vars
|
|
423
|
-
rendererOnlyUiTypes = _a.rendererOnlyUiTypes, inheritedFromParent = _a.inheritedFromParent, autoFocusFirstRequired = _a.autoFocusFirstRequired, expandFirstRequired = _a.expandFirstRequired, initialExpandedOptions = _a.initialExpandedOptions, maxFieldsShown = _a.maxFieldsShown, rest = __rest(_a, ["name", "uniqueName", "value", "onChange", "onSingleOptionsChange", "onDependableOptionChange", "placeholder", "noValueString", "isValid", "url", "customUrl", "operatorsUrl", "onOptionsLoaded", "recordRequiresSearchOptions", "readOnly", "allowTemplates", "interfaceContext", "templateFieldProps", "forceDropdown", "showTypeToggle", "compact", "compactFlush", "compactNested", "compactScroll", "compactPanelProps", "compactCollapsedGroups", "compactToolbar", "commitMode", "expandMode", "onCommit", "operators", "groups", "optionsLoader", "onValidityChange", "optionActions", "optionActionsCollapse", "componentOverrides", "codePreviewRenderer", "markdownRenderer", "rendererOnlyUiTypes", "inheritedFromParent", "autoFocusFirstRequired", "expandFirstRequired", "initialExpandedOptions", "maxFieldsShown"]);
|
|
564
|
+
rendererOnlyUiTypes = _a.rendererOnlyUiTypes, templateAwareUiTypes = _a.templateAwareUiTypes, anyLikeUiTypes = _a.anyLikeUiTypes, inheritedFromParent = _a.inheritedFromParent, autoFocusFirstRequired = _a.autoFocusFirstRequired, expandFirstRequired = _a.expandFirstRequired, initialExpandedOptions = _a.initialExpandedOptions, maxFieldsShown = _a.maxFieldsShown, rest = __rest(_a, ["name", "uniqueName", "value", "onChange", "onSingleOptionsChange", "onDependableOptionChange", "placeholder", "noValueString", "isValid", "url", "customUrl", "operatorsUrl", "onOptionsLoaded", "recordRequiresSearchOptions", "readOnly", "onReadOnlyActivate", "allowTemplates", "interfaceContext", "templateFieldProps", "forceDropdown", "showTypeToggle", "compact", "compactFlush", "compactNested", "compactScroll", "compactPanelProps", "compactCollapsedGroups", "compactBoxLabels", "compactStickyBoxHeaders", "compactStickyOffset", "compactToolbar", "commitMode", "expandMode", "onCommit", "operators", "groups", "optionsLoader", "onValidityChange", "optionActions", "optionActionsCollapse", "componentOverrides", "codePreviewRenderer", "markdownRenderer", "rendererOnlyUiTypes", "templateAwareUiTypes", "anyLikeUiTypes", "inheritedFromParent", "autoFocusFirstRequired", "expandFirstRequired", "initialExpandedOptions", "maxFieldsShown"]);
|
|
424
565
|
// Built-ins + whatever the consumer declared for its own injected editors.
|
|
425
566
|
var isRendererOnly = (0, react_2.useMemo)(function () { return (0, rendererTypes_1.createRendererOnlyUiTypeCheck)(rendererOnlyUiTypes); }, [JSON.stringify(rendererOnlyUiTypes)]);
|
|
426
567
|
// Pointer CAPABILITY and viewport WIDTH are different questions and both
|
|
@@ -429,16 +570,24 @@ var FormEngineImpl = function (_a) {
|
|
|
429
570
|
// from Reqore's context (one subscription for the whole app) rather than a
|
|
430
571
|
// reqraft-local matchMedia hook.
|
|
431
572
|
//
|
|
432
|
-
//
|
|
433
|
-
//
|
|
434
|
-
//
|
|
435
|
-
//
|
|
436
|
-
var isHoverCapable = (
|
|
573
|
+
// Both are always set by `ReqoreProvider`, and the peer floor (>= 0.74.0) is
|
|
574
|
+
// the version that sets them. A defensive `?? true` here would be dead code:
|
|
575
|
+
// `useReqoreProperty` THROWS on a context that lacks the key, so an older
|
|
576
|
+
// Reqore fails at the hook rather than degrading to a default.
|
|
577
|
+
var isHoverCapable = (0, reqore_1.useReqoreProperty)('isHoverCapable');
|
|
437
578
|
var isMobile = (0, reqore_1.useReqoreProperty)('isMobile');
|
|
438
579
|
var collapseOptionActions = optionActionsCollapse === 'always' ? true
|
|
439
580
|
: optionActionsCollapse === 'never' ? false
|
|
440
581
|
: !isHoverCapable || !!isMobile;
|
|
441
|
-
|
|
582
|
+
/* The schema, as the form should ASK it — not always as it was served.
|
|
583
|
+
`resolveDegenerateRequiredGroups` turns a one-of group that has a single
|
|
584
|
+
member in this schema back into a plain required field, because a choice
|
|
585
|
+
with one option is not a choice. Applied here, at the one place the schema
|
|
586
|
+
enters the component, so the header, the chips, the messages, the meter and
|
|
587
|
+
the read-first summary cannot disagree about it: every one of them reads
|
|
588
|
+
`options`, and none of them has to know the rule. */
|
|
589
|
+
var _u = (0, react_2.useState)((rest === null || rest === void 0 ? void 0 : rest.options) || undefined), servedOptions = _u[0], setOptions = _u[1];
|
|
590
|
+
var options = (0, react_2.useMemo)(function () { return (0, options_1.resolveDegenerateRequiredGroups)(servedOptions); }, [servedOptions]);
|
|
442
591
|
// optionsLoader lifecycle: loading feeds the skeleton gate, error the banner.
|
|
443
592
|
var _v = (0, react_2.useState)(!!optionsLoader && !(rest === null || rest === void 0 ? void 0 : rest.options)), optionsLoading = _v[0], setOptionsLoading = _v[1];
|
|
444
593
|
var _w = (0, react_2.useState)(), optionsError = _w[0], setOptionsError = _w[1];
|
|
@@ -526,6 +675,65 @@ var FormEngineImpl = function (_a) {
|
|
|
526
675
|
compactWrapNodeRef.current = node;
|
|
527
676
|
setCompactWrapNode(function (prev) { return (prev === node ? prev : node); });
|
|
528
677
|
}, [compactWrapRef]);
|
|
678
|
+
/* Declared here, not where it is first USED in the render: the sticky
|
|
679
|
+
measurement below takes it as a dependency, and a dependency array is
|
|
680
|
+
evaluated during render — a `const` declared further down would still be
|
|
681
|
+
in its temporal dead zone. */
|
|
682
|
+
var compactNarrow = !!compactWrapWidth && compactWrapWidth < 480;
|
|
683
|
+
/* How much pinned chrome sits above a status-box header.
|
|
684
|
+
|
|
685
|
+
Sticky offsets do not compose on their own: everything pinned in one
|
|
686
|
+
scroller resolves `top` against the same scrollport, so a box header and
|
|
687
|
+
this form's own toolbar both asking for 0 land on top of each other — and
|
|
688
|
+
the toolbar is the loser, because it renders first and the box header wins
|
|
689
|
+
on z-order. Covering it hides the search, which is the one control that
|
|
690
|
+
forces a collapsed box open.
|
|
691
|
+
|
|
692
|
+
So the box headers pin BELOW the toolbar, at the host's own offset plus the
|
|
693
|
+
toolbar's height. Measured, not assumed: the toolbar is a completion meter,
|
|
694
|
+
a search row and a field picker that each hide themselves when they have
|
|
695
|
+
nothing to say, and what is left wraps differently at every form width.
|
|
696
|
+
Zero when this form draws no toolbar at all. */
|
|
697
|
+
var _9 = (0, react_2.useState)(0), compactToolbarHeight = _9[0], setCompactToolbarHeight = _9[1];
|
|
698
|
+
(0, react_2.useLayoutEffect)(function () {
|
|
699
|
+
var wrap = compactWrapNode;
|
|
700
|
+
if (!compact || !wrap || compactNested || !compactStickyBoxHeaders) {
|
|
701
|
+
setCompactToolbarHeight(0);
|
|
702
|
+
return undefined;
|
|
703
|
+
}
|
|
704
|
+
var header = wrap.querySelector(':scope > .reqore-panel > .reqore-panel-title');
|
|
705
|
+
if (!header) {
|
|
706
|
+
setCompactToolbarHeight(0);
|
|
707
|
+
return undefined;
|
|
708
|
+
}
|
|
709
|
+
var read = function () {
|
|
710
|
+
return setCompactToolbarHeight(function (prev) {
|
|
711
|
+
/* Only a toolbar that is ITSELF pinned takes room off the top. A host
|
|
712
|
+
can switch the pin off (`compactPanelProps.stickyHeader`), and it
|
|
713
|
+
does where the form is a couple of fields inside a longer page — and
|
|
714
|
+
a box header offset by a toolbar that scrolls away would float a
|
|
715
|
+
header's height below the top edge with nothing under it. Read from
|
|
716
|
+
the element rather than from the props that produced it, so every
|
|
717
|
+
route to that decision is accounted for. */
|
|
718
|
+
var pinned = getComputedStyle(header).position === 'sticky';
|
|
719
|
+
var next = pinned ? Math.round(header.getBoundingClientRect().height) : 0;
|
|
720
|
+
return prev === next ? prev : next;
|
|
721
|
+
});
|
|
722
|
+
};
|
|
723
|
+
read();
|
|
724
|
+
/* jsdom and older engines have no ResizeObserver; the one-shot read above
|
|
725
|
+
still gives the right answer for a form whose toolbar never reflows. */
|
|
726
|
+
if (typeof ResizeObserver === 'undefined') {
|
|
727
|
+
return undefined;
|
|
728
|
+
}
|
|
729
|
+
var observer = new ResizeObserver(read);
|
|
730
|
+
observer.observe(header);
|
|
731
|
+
return function () { return observer.disconnect(); };
|
|
732
|
+
/* `compactNarrow` is a dependency, not decoration: crossing the width
|
|
733
|
+
breakpoint takes the pin OFF the toolbar without changing its height, so
|
|
734
|
+
the ResizeObserver never fires and a stale 124px would go on offsetting
|
|
735
|
+
the box headers below a toolbar that is no longer there. */
|
|
736
|
+
}, [compact, compactNested, compactStickyBoxHeaders, compactNarrow, compactWrapNode, options]);
|
|
529
737
|
// Global label-column sizing: size the label column to the WIDEST field label
|
|
530
738
|
// across the whole form, clamped to [MIN, MAX], and publish it as a CSS var on
|
|
531
739
|
// the scroll wrap. Both the grid column and the value-surface offsets read the
|
|
@@ -571,8 +779,8 @@ var FormEngineImpl = function (_a) {
|
|
|
571
779
|
var readRowHeights = (0, react_2.useRef)({});
|
|
572
780
|
// Required-groups linkage: hovering a group chip highlights every member row;
|
|
573
781
|
// clicking a sibling in the chip's popover scrolls to it and flashes it.
|
|
574
|
-
var
|
|
575
|
-
var
|
|
782
|
+
var _10 = (0, react_2.useState)([]), highlightedOptions = _10[0], setHighlightedOptions = _10[1];
|
|
783
|
+
var _11 = (0, react_2.useState)([]), flashedOptions = _11[0], setFlashedOptions = _11[1];
|
|
576
784
|
var flashTimeout = (0, react_2.useRef)();
|
|
577
785
|
var flashOptions = (0, react_2.useCallback)(function (optionNames, scrollToFirst) {
|
|
578
786
|
if (scrollToFirst === void 0) { scrollToFirst = false; }
|
|
@@ -619,30 +827,59 @@ var FormEngineImpl = function (_a) {
|
|
|
619
827
|
flashOptions([moved], true);
|
|
620
828
|
}
|
|
621
829
|
});
|
|
622
|
-
var compactNarrow = !!compactWrapWidth && compactWrapWidth < 480;
|
|
623
830
|
// Info panels auto-open on Tier-1 content; the per-row user override sticks.
|
|
624
|
-
var
|
|
831
|
+
var _12 = (0, react_2.useState)({}), infoPanelOverrides = _12[0], setInfoPanelOverrides = _12[1];
|
|
625
832
|
// Toolbar filters affect the listed rows only — the meter reflects the full set.
|
|
626
|
-
var
|
|
627
|
-
var
|
|
833
|
+
var _13 = (0, react_2.useState)(false), requiredOnly = _13[0], setRequiredOnly = _13[1];
|
|
834
|
+
var _14 = (0, react_2.useState)(''), compactQuery = _14[0], setCompactQuery = _14[1];
|
|
628
835
|
// Compact field sort (Fields menu → "Sort by"); 'schema' = declared order.
|
|
629
|
-
var
|
|
630
|
-
var
|
|
836
|
+
var _15 = (0, react_2.useState)('schema'), compactSort = _15[0], setCompactSort = _15[1];
|
|
837
|
+
var _16 = (0, react_2.useState)(function () { return ({
|
|
631
838
|
fields: (0, exports.fixOptions)(value, options || {}, undefined, isRendererOnly),
|
|
632
839
|
meta: undefined,
|
|
633
|
-
}); }), localValue =
|
|
840
|
+
}); }), localValue = _16[0], setLocalValue = _16[1];
|
|
634
841
|
var originalValue = (0, react_2.useRef)();
|
|
635
842
|
// Track the last value we emitted via onChange so we can skip re-applying fixOptions
|
|
636
843
|
// when the parent echoes it back as the new value prop (controlled component loop prevention)
|
|
637
844
|
var lastEmittedValue = (0, react_2.useRef)(value);
|
|
845
|
+
/**
|
|
846
|
+
* A `localValue` that is only a MIRROR of the incoming `value`, and so must
|
|
847
|
+
* never be emitted back as though this form had answered something.
|
|
848
|
+
*
|
|
849
|
+
* `localValue` is derived state: the sync-down effect below rebuilds it from
|
|
850
|
+
* the `value` prop. When that rebuild adds nothing (`fixOptions` had no
|
|
851
|
+
* default to materialise), the result says exactly what the parent already
|
|
852
|
+
* holds, and emitting it is not a change — it is this form repeating the
|
|
853
|
+
* parent's own words back at it.
|
|
854
|
+
*
|
|
855
|
+
* That repetition is harmless in a form that owns its state outright and
|
|
856
|
+
* fatal in one that shares a parent with a NESTED engine. The two write to
|
|
857
|
+
* the same parent value, so each sees the other's write arrive as an external
|
|
858
|
+
* change; `lastEmittedValue` is then always one step behind and its guard
|
|
859
|
+
* never fires. The engines alternate between two states forever, several
|
|
860
|
+
* times a second, and the newer write is repeatedly overwritten by the older
|
|
861
|
+
* one. Measured in the test editor: the row's summary flipped between two
|
|
862
|
+
* readings indefinitely and `setTimeout` was starved past a 45-second
|
|
863
|
+
* deadline.
|
|
864
|
+
*
|
|
865
|
+
* Only a mirror that CHANGES nothing is held back. A rebuild that restores a
|
|
866
|
+
* required or preselected field's default still emits, because that default
|
|
867
|
+
* is genuinely new information the parent has to be told about — which is the
|
|
868
|
+
* whole reason the sync-down runs `fixOptions` at all.
|
|
869
|
+
*/
|
|
870
|
+
var mirroredValue = (0, react_2.useRef)(undefined);
|
|
638
871
|
if (originalValue.current === undefined && (0, size_1.default)(value)) {
|
|
639
872
|
originalValue.current = localValue.fields;
|
|
640
873
|
}
|
|
641
874
|
var unavailableOptionsCount = (0, react_2.useRef)(0);
|
|
642
|
-
var
|
|
875
|
+
var _17 = (0, useQorusTypes_1.useQorusTypes)(), compactValue = _17.compactValue, typesLoading = _17.loading;
|
|
643
876
|
var templates = (0, useTemplates_1.useTemplates)(allowTemplates, rest.stringTemplates, interfaceContext);
|
|
644
877
|
(0, react_2.useEffect)(function () {
|
|
645
|
-
if ((0,
|
|
878
|
+
if (!(0, exports.shouldEmitLocalValue)({
|
|
879
|
+
localValue: localValue.fields,
|
|
880
|
+
value: value,
|
|
881
|
+
mirroredValue: mirroredValue.current,
|
|
882
|
+
})) {
|
|
646
883
|
return;
|
|
647
884
|
}
|
|
648
885
|
var toEmit = (0, size_1.default)(localValue.fields) ? localValue.fields : undefined;
|
|
@@ -822,22 +1059,51 @@ var FormEngineImpl = function (_a) {
|
|
|
822
1059
|
// Note: compare fixedValue against value, not localValue.fields — localValue may have been
|
|
823
1060
|
// updated by nested FormEngine emissions, so comparing against it would never skip.
|
|
824
1061
|
var normalizedValue = normalizeEmptyFieldValues(value);
|
|
1062
|
+
/* What this rebuild lets us agree with the parent on — `undefined` when it
|
|
1063
|
+
contributed something the parent has yet to learn. */
|
|
1064
|
+
var agreed = (0, exports.agreementFromRebuild)(fixedValue, value);
|
|
825
1065
|
if ((0, lodash_1.isEqual)(normalizedValue, normalizeEmptyFieldValues(lastEmittedValue.current)) &&
|
|
826
|
-
|
|
1066
|
+
agreed !== undefined) {
|
|
827
1067
|
return;
|
|
828
1068
|
}
|
|
829
1069
|
if (!originalValue.current && (0, size_1.default)(fixedValue)) {
|
|
830
1070
|
originalValue.current = fixedValue;
|
|
831
1071
|
}
|
|
1072
|
+
/* Remember a mirror so the emit effect can tell one from an answer, and
|
|
1073
|
+
record the agreement it represents. A rebuild that DID add something
|
|
1074
|
+
leaves both alone — the parent has to learn about it. */
|
|
1075
|
+
mirroredValue.current = agreed;
|
|
1076
|
+
if (agreed !== undefined) {
|
|
1077
|
+
lastEmittedValue.current = agreed;
|
|
1078
|
+
}
|
|
832
1079
|
setLocalValue === null || setLocalValue === void 0 ? void 0 : setLocalValue({ fields: fixedValue, meta: undefined });
|
|
833
1080
|
}, [JSON.stringify(options), JSON.stringify(value), isRendererOnly]);
|
|
1081
|
+
/**
|
|
1082
|
+
* Fields the reader has actually edited in this instance.
|
|
1083
|
+
*
|
|
1084
|
+
* "This field is required" is an ERROR message, and an error is a report that
|
|
1085
|
+
* something went wrong. Under a field nobody has been in yet it reports
|
|
1086
|
+
* nothing — the form is empty because it is new — while the requirement is
|
|
1087
|
+
* already stated by the asterisk, by the Needs-attention box the row sits in,
|
|
1088
|
+
* and by the completion meter. A form whose first act is to accuse the reader
|
|
1089
|
+
* of a mistake they have not made teaches them to discount its warnings.
|
|
1090
|
+
*
|
|
1091
|
+
* So the message waits for a touch. Being IN the field and leaving it empty
|
|
1092
|
+
* is a real gap, and that one shows. A ref, not state: every edit re-renders
|
|
1093
|
+
* anyway, so the following render reads the current set with no second pass.
|
|
1094
|
+
*/
|
|
1095
|
+
var touchedOptionsRef = (0, react_2.useRef)(new Set());
|
|
834
1096
|
var handleValueChange = (0, react_2.useCallback)(function (optionName, val, _type, isFunction) {
|
|
1097
|
+
// Every route into this handler is a person acting: typing, picking from a
|
|
1098
|
+
// menu, clearing the value, adding an optional field. Marked here rather
|
|
1099
|
+
// than inside the updater below, which React may invoke twice.
|
|
1100
|
+
touchedOptionsRef.current.add(optionName);
|
|
835
1101
|
setLocalValue(function (_a) {
|
|
836
1102
|
var _b, _c;
|
|
837
|
-
var _d, _f, _g, _h, _j, _k, _l, _m, _o, _p;
|
|
838
|
-
var
|
|
1103
|
+
var _d, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q;
|
|
1104
|
+
var _r = _a.fields, fields = _r === void 0 ? {} : _r;
|
|
839
1105
|
var schemaType = getOptionSchemaStorageType(options === null || options === void 0 ? void 0 : options[optionName], isRendererOnly);
|
|
840
|
-
var isAnyLike =
|
|
1106
|
+
var isAnyLike = (0, optionUiTypes_1.isUntypedOptionType)(schemaType);
|
|
841
1107
|
// For any/auto schema types, preserve the user's chosen type stored in the field
|
|
842
1108
|
var resolvedSchemaType = isAnyLike && ((_d = fields[optionName]) === null || _d === void 0 ? void 0 : _d.type) ?
|
|
843
1109
|
fields[optionName].type
|
|
@@ -868,27 +1134,46 @@ var FormEngineImpl = function (_a) {
|
|
|
868
1134
|
// by TemplateField/auto) drives the option's `is_expression` flag;
|
|
869
1135
|
// the value itself is the raw AST `{ exp, args }`.
|
|
870
1136
|
var updatedValue = __assign(__assign({}, fields), (_c = {}, _c[optionName] = __assign(__assign({}, fields[optionName]), { type: type, value: val }), _c));
|
|
871
|
-
|
|
1137
|
+
/* The flag belongs to the VALUE, so a change that said nothing about it
|
|
1138
|
+
does not throw it away — `undefined` is no opinion, not a denial.
|
|
1139
|
+
Deleting it unconditionally left the AST on the row with nothing
|
|
1140
|
+
marking it as one: an assertion's Expected Value came back from a
|
|
1141
|
+
saved draft drawn as a two-field hash of `exp` and `args`, because
|
|
1142
|
+
merely opening the row and reverting had stripped the flag. */
|
|
1143
|
+
if ((0, argumentPresence_1.shouldMarkAsExpression)(isFunction, val, (_l = fields[optionName]) === null || _l === void 0 ? void 0 : _l.is_expression)) {
|
|
872
1144
|
updatedValue[optionName].is_expression = true;
|
|
873
1145
|
}
|
|
874
1146
|
else {
|
|
875
1147
|
delete updatedValue[optionName].is_expression;
|
|
876
1148
|
}
|
|
877
1149
|
var meta = {};
|
|
878
|
-
if (((
|
|
1150
|
+
if (((_m = options === null || options === void 0 ? void 0 : options[optionName]) === null || _m === void 0 ? void 0 : _m.has_dependents) &&
|
|
879
1151
|
val !== undefined &&
|
|
880
|
-
val !== ((
|
|
1152
|
+
val !== ((_o = fields[optionName]) === null || _o === void 0 ? void 0 : _o.value)) {
|
|
881
1153
|
(0, lodash_1.forEach)(options, function (option, depName) {
|
|
1154
|
+
/* A dependency is `name`, `name=value` or `name!=value`, so the
|
|
1155
|
+
entry has to be PARSED to find which option it names. Compared as
|
|
1156
|
+
a whole string, only the bare spelling ever matched — so a field
|
|
1157
|
+
declared `depends_on: ['subject_iface_kind=workflow']` was never
|
|
1158
|
+
cleared when that option changed.
|
|
1159
|
+
|
|
1160
|
+
What that cost: a test whose subject was switched from a workflow
|
|
1161
|
+
to a service kept the workflow's `Subject Interface Version`.
|
|
1162
|
+
Services and jobs are versioned but only the latest is testable,
|
|
1163
|
+
so the field no longer applied, yet it stayed on the form as a
|
|
1164
|
+
locked control in front of a value the author could not clear —
|
|
1165
|
+
the value being there is exactly what stops the field being
|
|
1166
|
+
withheld outright. */
|
|
882
1167
|
if (option.depends_on &&
|
|
883
|
-
(0, lodash_1.flatten)(option.depends_on).
|
|
1168
|
+
(0, lodash_1.flatten)(option.depends_on).some(function (dependency) { return (0, validations_1.parseDependency)(dependency).name === optionName; }) &&
|
|
884
1169
|
updatedValue[depName]) {
|
|
885
1170
|
updatedValue[depName].value = undefined;
|
|
886
1171
|
}
|
|
887
1172
|
});
|
|
888
1173
|
onDependableOptionChange === null || onDependableOptionChange === void 0 ? void 0 : onDependableOptionChange(optionName, val, updatedValue, options);
|
|
889
1174
|
}
|
|
890
|
-
if ((0, size_1.default)((
|
|
891
|
-
meta.events = (
|
|
1175
|
+
if ((0, size_1.default)((_p = options === null || options === void 0 ? void 0 : options[optionName]) === null || _p === void 0 ? void 0 : _p.on_change)) {
|
|
1176
|
+
meta.events = (_q = options === null || options === void 0 ? void 0 : options[optionName]) === null || _q === void 0 ? void 0 : _q.on_change;
|
|
892
1177
|
}
|
|
893
1178
|
onSingleOptionsChange === null || onSingleOptionsChange === void 0 ? void 0 : onSingleOptionsChange(optionName, updatedValue[optionName]);
|
|
894
1179
|
if (compact && !readOnly && (0, readFirst_1.shouldAutoCollapseCompactOption)(options === null || options === void 0 ? void 0 : options[optionName], val)) {
|
|
@@ -1006,7 +1291,7 @@ var FormEngineImpl = function (_a) {
|
|
|
1006
1291
|
return newValue;
|
|
1007
1292
|
}
|
|
1008
1293
|
var rendererType = (0, exports.getType)((options[optionName].ui_type || options[optionName].type), operators, option === null || option === void 0 ? void 0 : option.op);
|
|
1009
|
-
var storageType = getOptionFieldStorageType(optionName, option === null || option === void 0 ? void 0 : option.type, options, operators, option === null || option === void 0 ? void 0 : option.op, isRendererOnly);
|
|
1294
|
+
var storageType = (0, exports.getOptionFieldStorageType)(optionName, option === null || option === void 0 ? void 0 : option.type, options, operators, option === null || option === void 0 ? void 0 : option.op, isRendererOnly, optionHoldsExpression(option));
|
|
1010
1295
|
if (!(0, lodash_1.isPlainObject)(option)) {
|
|
1011
1296
|
return __assign(__assign({}, newValue), (_a = {}, _a[optionName] = {
|
|
1012
1297
|
type: storageType || rendererType,
|
|
@@ -1038,6 +1323,21 @@ var FormEngineImpl = function (_a) {
|
|
|
1038
1323
|
});
|
|
1039
1324
|
return { members: members, satisfiedBy: satisfiedBy };
|
|
1040
1325
|
}, [JSON.stringify(options), JSON.stringify(availableOptions)]);
|
|
1326
|
+
/* One bag per field, rebuilt only when something it is made of changes — the
|
|
1327
|
+
schema that declares the `inherit_props`, the sibling values they resolve
|
|
1328
|
+
against, or the scope handed in from an outer form. Held per field rather
|
|
1329
|
+
than per form because each field's bag is different: `inherit_props` is
|
|
1330
|
+
declared on the field. See `inheritedScopeFor` for what a churning bag
|
|
1331
|
+
costs the field that receives it. */
|
|
1332
|
+
var inheritedScopes = (0, react_2.useMemo)(function () {
|
|
1333
|
+
var _a;
|
|
1334
|
+
var scopes = new Map();
|
|
1335
|
+
for (var _i = 0, _b = Object.keys(options !== null && options !== void 0 ? options : {}); _i < _b.length; _i++) {
|
|
1336
|
+
var optionName = _b[_i];
|
|
1337
|
+
scopes.set(optionName, (0, exports.inheritedScopeFor)((_a = options === null || options === void 0 ? void 0 : options[optionName]) === null || _a === void 0 ? void 0 : _a.inherit_props, availableOptions, inheritedFromParent));
|
|
1338
|
+
}
|
|
1339
|
+
return scopes;
|
|
1340
|
+
}, [options, availableOptions, inheritedFromParent]);
|
|
1041
1341
|
// Dependency linkage (3a): when filling a dependency unlocks rows, flash
|
|
1042
1342
|
// them once — the form visibly "opens up" instead of silently changing.
|
|
1043
1343
|
var dependencyLockedNames = (0, react_2.useMemo)(function () {
|
|
@@ -1062,6 +1362,49 @@ var FormEngineImpl = function (_a) {
|
|
|
1062
1362
|
flashOptions(unlocked);
|
|
1063
1363
|
}
|
|
1064
1364
|
}, [dependencyLockedNames.join('|')]);
|
|
1365
|
+
/* The same thing one level down: a CHOICE that becomes available is as
|
|
1366
|
+
invisible as a field that becomes editable, and it is worse, because it
|
|
1367
|
+
opens up inside a control the reader may not have open. So the field that
|
|
1368
|
+
offers it flashes, which is the affordance that says "look here" without
|
|
1369
|
+
claiming the choice was made.
|
|
1370
|
+
|
|
1371
|
+
Keyed by field and by the value's identity, so a value that merely moves in
|
|
1372
|
+
the list is not mistaken for one that opened. Fields whose values gate on
|
|
1373
|
+
nothing never enter the set, which is nearly all of them. */
|
|
1374
|
+
var lockedAllowedValues = (0, react_2.useMemo)(function () {
|
|
1375
|
+
var locked = [];
|
|
1376
|
+
(0, lodash_1.forEach)(options || {}, function (optionSchema, name) {
|
|
1377
|
+
(0, lodash_1.forEach)((optionSchema === null || optionSchema === void 0 ? void 0 : optionSchema.allowed_values) || [], function (allowedValue) {
|
|
1378
|
+
var _a;
|
|
1379
|
+
if (!(0, OptionFieldMessages_1.getAllowedValueAvailability)(allowedValue, availableOptions, options || {}).available) {
|
|
1380
|
+
locked.push("".concat(name, "\0").concat(JSON.stringify((_a = allowedValue === null || allowedValue === void 0 ? void 0 : allowedValue.value) === null || _a === void 0 ? void 0 : _a.value)));
|
|
1381
|
+
}
|
|
1382
|
+
});
|
|
1383
|
+
});
|
|
1384
|
+
return locked;
|
|
1385
|
+
}, [JSON.stringify(options), JSON.stringify(availableOptions)]);
|
|
1386
|
+
var previousLockedAllowedValues = (0, react_2.useRef)(null);
|
|
1387
|
+
(0, react_2.useEffect)(function () {
|
|
1388
|
+
var previous = previousLockedAllowedValues.current;
|
|
1389
|
+
previousLockedAllowedValues.current = lockedAllowedValues;
|
|
1390
|
+
if (!previous) {
|
|
1391
|
+
return;
|
|
1392
|
+
}
|
|
1393
|
+
var opened = previous
|
|
1394
|
+
.filter(function (key) { return !lockedAllowedValues.includes(key); })
|
|
1395
|
+
.map(function (key) { return key.split('\u0000')[0]; });
|
|
1396
|
+
var fields = (0, lodash_1.uniq)(opened).filter(function (name) {
|
|
1397
|
+
var _a;
|
|
1398
|
+
return !!(options === null || options === void 0 ? void 0 : options[name]) &&
|
|
1399
|
+
!((_a = options === null || options === void 0 ? void 0 : options[name]) === null || _a === void 0 ? void 0 : _a.disabled) &&
|
|
1400
|
+
// A field that is itself still locked flashes for its OWN unlocking, in
|
|
1401
|
+
// the effect above; two flashes for one change is a flicker, not a cue.
|
|
1402
|
+
!dependencyLockedNames.includes(name);
|
|
1403
|
+
});
|
|
1404
|
+
if (fields.length) {
|
|
1405
|
+
flashOptions(fields);
|
|
1406
|
+
}
|
|
1407
|
+
}, [lockedAllowedValues.join('|')]);
|
|
1065
1408
|
// The not-yet-added optional fields: everything in the schema the form is not
|
|
1066
1409
|
// already showing a row for. This ONE list feeds all three ways a field gets
|
|
1067
1410
|
// added — the inline addable rows, the Fields menu, and its "Select all" — so
|
|
@@ -1107,7 +1450,7 @@ var FormEngineImpl = function (_a) {
|
|
|
1107
1450
|
var getValidityData = (0, react_2.useCallback)(function () {
|
|
1108
1451
|
var fields = (0, reduce_1.default)(availableOptions, function (result, option, optionName) {
|
|
1109
1452
|
var _a, _b;
|
|
1110
|
-
var type = getOptionFieldStorageType(optionName, option.type, options, operators, option.op, isRendererOnly);
|
|
1453
|
+
var type = (0, exports.getOptionFieldStorageType)(optionName, option.type, options, operators, option.op, isRendererOnly, optionHoldsExpression(option));
|
|
1111
1454
|
var optionValue = option.value;
|
|
1112
1455
|
var isRequired = (_a = options === null || options === void 0 ? void 0 : options[optionName]) === null || _a === void 0 ? void 0 : _a.required;
|
|
1113
1456
|
var hasRequiredGroups = !!((_b = options === null || options === void 0 ? void 0 : options[optionName]) === null || _b === void 0 ? void 0 : _b.required_groups);
|
|
@@ -1151,7 +1494,7 @@ var FormEngineImpl = function (_a) {
|
|
|
1151
1494
|
return (0, reduce_1.default)(availableOptions, function (newValue, option, optionName) {
|
|
1152
1495
|
var _a;
|
|
1153
1496
|
if (showInvalidOptionsOnly &&
|
|
1154
|
-
isOptionValid(optionName, getOptionFieldStorageType(optionName, option.type, options, operators, option.op, isRendererOnly), option.value)) {
|
|
1497
|
+
isOptionValid(optionName, (0, exports.getOptionFieldStorageType)(optionName, option.type, options, operators, option.op, isRendererOnly, optionHoldsExpression(option)), option.value)) {
|
|
1155
1498
|
return newValue;
|
|
1156
1499
|
}
|
|
1157
1500
|
return __assign(__assign({}, newValue), (_a = {}, _a[optionName] = option, _a));
|
|
@@ -1185,7 +1528,7 @@ var FormEngineImpl = function (_a) {
|
|
|
1185
1528
|
if (hidden)
|
|
1186
1529
|
return 'optional';
|
|
1187
1530
|
var schema = options === null || options === void 0 ? void 0 : options[name];
|
|
1188
|
-
var type = getOptionFieldStorageType(name, (_a = availableOptions === null || availableOptions === void 0 ? void 0 : availableOptions[name]) === null || _a === void 0 ? void 0 : _a.type, options, operators, (_b = availableOptions === null || availableOptions === void 0 ? void 0 : availableOptions[name]) === null || _b === void 0 ? void 0 : _b.op, isRendererOnly);
|
|
1531
|
+
var type = (0, exports.getOptionFieldStorageType)(name, (_a = availableOptions === null || availableOptions === void 0 ? void 0 : availableOptions[name]) === null || _a === void 0 ? void 0 : _a.type, options, operators, (_b = availableOptions === null || availableOptions === void 0 ? void 0 : availableOptions[name]) === null || _b === void 0 ? void 0 : _b.op, isRendererOnly, optionHoldsExpression(availableOptions === null || availableOptions === void 0 ? void 0 : availableOptions[name]));
|
|
1189
1532
|
var value = (_c = availableOptions === null || availableOptions === void 0 ? void 0 : availableOptions[name]) === null || _c === void 0 ? void 0 : _c.value;
|
|
1190
1533
|
// A schema-declared hash whose every entry is a materialised-but-unset
|
|
1191
1534
|
// field holds nothing, so it is not "set" — without this the row showed a
|
|
@@ -1307,11 +1650,16 @@ var FormEngineImpl = function (_a) {
|
|
|
1307
1650
|
if (!names.length) {
|
|
1308
1651
|
return;
|
|
1309
1652
|
}
|
|
1310
|
-
hasAppliedInitialExpansionRef.current = true;
|
|
1311
1653
|
var toExpand = initialExpandedOptions.filter(function (name) { return names.includes(name); });
|
|
1312
1654
|
if (!toExpand.length) {
|
|
1655
|
+
// Not "there is no such row" — "not YET". A server-driven schema arrives
|
|
1656
|
+
// in pieces, and the row the caller named can be in a later one (a test's
|
|
1657
|
+
// `cases` field materialises once its step-kind catalogue lands). Latching
|
|
1658
|
+
// here would spend the one shot on a form that did not yet contain the
|
|
1659
|
+
// field, and the address would never be applied at all.
|
|
1313
1660
|
return;
|
|
1314
1661
|
}
|
|
1662
|
+
hasAppliedInitialExpansionRef.current = true;
|
|
1315
1663
|
setExpandedOptions(function (prev) { return __spreadArray(__spreadArray([], prev, true), toExpand.filter(function (name) { return !prev.includes(name); }), true); });
|
|
1316
1664
|
}, [initialExpandedOptions, compact, availableOptions]);
|
|
1317
1665
|
// --- First-attention-field autofocus (opt-in) -----------------------------
|
|
@@ -1331,15 +1679,13 @@ var FormEngineImpl = function (_a) {
|
|
|
1331
1679
|
// genuine remount (a fresh instance) auto-focuses again, which is the intended
|
|
1332
1680
|
// on-mount behaviour.
|
|
1333
1681
|
var hasAutoFocusedRef = (0, react_2.useRef)(false);
|
|
1334
|
-
// The field expanded programmatically for autofocus. A ref (not state) so
|
|
1335
|
-
// CompactRow's 60ms focus timer reads the current value regardless of render
|
|
1336
|
-
// batching; CompactRow focuses this one with `preventScroll` so an off-screen
|
|
1337
|
-
// (or below-the-fold) form is never scrolled into view on mount.
|
|
1338
|
-
var autoFocusNameRef = (0, react_2.useRef)(undefined);
|
|
1339
1682
|
(0, react_2.useEffect)(function () {
|
|
1340
|
-
// Two decisions, one scan.
|
|
1341
|
-
//
|
|
1342
|
-
// the
|
|
1683
|
+
// Two decisions, one scan. Both open the row that needs attention;
|
|
1684
|
+
// `autoFocusFirstRequired` additionally promises the caret lands in it, and
|
|
1685
|
+
// so refuses to run at all while the reader holds the caret somewhere else
|
|
1686
|
+
// (the guard below). An opened row takes the caret either way — that is
|
|
1687
|
+
// CompactRow's tap-to-edit rule, and it declines just as firmly to take one
|
|
1688
|
+
// that is already somewhere outside the row.
|
|
1343
1689
|
var wantsFocus = !!autoFocusFirstRequired;
|
|
1344
1690
|
if ((!wantsFocus && !expandFirstRequired) || !compact || !options) {
|
|
1345
1691
|
return;
|
|
@@ -1387,14 +1733,16 @@ var FormEngineImpl = function (_a) {
|
|
|
1387
1733
|
// again.
|
|
1388
1734
|
hasAutoFocusedRef.current = true;
|
|
1389
1735
|
if (target) {
|
|
1390
|
-
// Set the ref before the state update so CompactRow's focus timer sees it.
|
|
1391
|
-
// Expand-only leaves it unset, which is what keeps the caret where it is.
|
|
1392
|
-
if (wantsFocus) {
|
|
1393
|
-
autoFocusNameRef.current = target;
|
|
1394
|
-
}
|
|
1395
1736
|
setExpandedOptions(function (prev) {
|
|
1396
1737
|
return prev.includes(target) ? prev
|
|
1397
|
-
: expandMode === 'multi' ? __spreadArray(__spreadArray([], prev, true), [target], false)
|
|
1738
|
+
: expandMode === 'multi' ? __spreadArray(__spreadArray([], prev, true), [target], false)
|
|
1739
|
+
// `expandMode: 'single'` is a rule about what a CLICK does: opening a
|
|
1740
|
+
// row closes the one the reader last opened. It is not a licence to
|
|
1741
|
+
// close a row the HOST named through `initialExpandedOptions`. That
|
|
1742
|
+
// is an address — a statement about what the page is FOR, made before
|
|
1743
|
+
// the reader did anything — and this scan is a convenience layered on
|
|
1744
|
+
// top of it. Keep the named rows; replace only what a click could.
|
|
1745
|
+
: __spreadArray(__spreadArray([], prev.filter(function (name) { return initialExpandedOptions === null || initialExpandedOptions === void 0 ? void 0 : initialExpandedOptions.includes(name); }), true), [target], false);
|
|
1398
1746
|
});
|
|
1399
1747
|
}
|
|
1400
1748
|
}, [
|
|
@@ -1407,10 +1755,13 @@ var FormEngineImpl = function (_a) {
|
|
|
1407
1755
|
dependencyLockedNames,
|
|
1408
1756
|
getOptionBucket,
|
|
1409
1757
|
expandMode,
|
|
1758
|
+
initialExpandedOptions,
|
|
1410
1759
|
]);
|
|
1411
1760
|
// Read-first completion summary (how many shown options have a value set),
|
|
1412
1761
|
// surfaced as a progress meter at the top of the compact form.
|
|
1413
|
-
var readFirstCompletion = (0, react_2.useMemo)(function () {
|
|
1762
|
+
var readFirstCompletion = (0, react_2.useMemo)(function () {
|
|
1763
|
+
return (0, readFirst_1.getReadFirstCompletion)(availableOptions, function (name) { return getOptionBucket(name) === 'attention'; });
|
|
1764
|
+
}, [JSON.stringify(availableOptions), getOptionBucket]);
|
|
1414
1765
|
var optionalFields = (0, react_2.useMemo)(function () {
|
|
1415
1766
|
return Object.keys(filteredOptions).map(function (option) {
|
|
1416
1767
|
var _a, _b, _c, _d, _f, _g;
|
|
@@ -1477,7 +1828,7 @@ var FormEngineImpl = function (_a) {
|
|
|
1477
1828
|
// The info panel below the row keeps showing schema messages while editing —
|
|
1478
1829
|
// rendering them in the editor too would balloon a one-line edit.
|
|
1479
1830
|
suppressSchemaMessages) {
|
|
1480
|
-
var _b, _c, _d, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t;
|
|
1831
|
+
var _b, _c, _d, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t, _u, _v;
|
|
1481
1832
|
var type = _a.type, other = __rest(_a, ["type"]);
|
|
1482
1833
|
var operatorParts = (0, common_1.fixOperatorValue)(other.op);
|
|
1483
1834
|
// The RENDERER type for this row — which editor mounts. Distinct from the
|
|
@@ -1493,12 +1844,55 @@ var FormEngineImpl = function (_a) {
|
|
|
1493
1844
|
// schema has not arrived yet (`type` undefined) instead of crashing.
|
|
1494
1845
|
var optionSchema = options === null || options === void 0 ? void 0 : options[optionName];
|
|
1495
1846
|
var schemaUiType = optionSchema === null || optionSchema === void 0 ? void 0 : optionSchema.ui_type;
|
|
1496
|
-
var uiTypeIsAnyLike =
|
|
1847
|
+
var uiTypeIsAnyLike = (0, optionUiTypes_1.isUntypedOptionType)(schemaUiType);
|
|
1848
|
+
/* An EXPRESSION's stored type is skipped in this chain.
|
|
1849
|
+
|
|
1850
|
+
The value is `{ is_expression: true, value: {...} }`, so the type saved
|
|
1851
|
+
beside it describes that envelope — `hash` — not what the field holds.
|
|
1852
|
+
With no `ui_type` to win first, that `hash` beat the schema's `auto`
|
|
1853
|
+
and was handed to the expression editor as the return type to check
|
|
1854
|
+
against: `1 + 2` on a field declared `auto` came back "This does not
|
|
1855
|
+
fit. The expression returns int, and this field holds hash". A literal
|
|
1856
|
+
`1` was fine, because a literal is stored as a plain value whose type
|
|
1857
|
+
matches.
|
|
1858
|
+
|
|
1859
|
+
Dropping the stored type here lets the schema decide, which is the
|
|
1860
|
+
only party that knows what the field accepts. This is the row
|
|
1861
|
+
renderer's OWN resolution and does not go through
|
|
1862
|
+
`getOptionFieldStorageType`, so guarding that one alone left this
|
|
1863
|
+
untouched. */
|
|
1864
|
+
var storedRowType = optionHoldsExpression(other) ? undefined : type;
|
|
1865
|
+
/* A RELOADED expression is handed to the editor in the shape the editor
|
|
1866
|
+
was written against.
|
|
1867
|
+
|
|
1868
|
+
An expression is written as `{ type, is_expression: true, value: ast }`
|
|
1869
|
+
and saved as `{ type, value: { is_expression: true, value: ast } }` —
|
|
1870
|
+
the flag moves ONTO the value. The editor was only ever given
|
|
1871
|
+
`other.is_expression`, which is absent in the saved shape, so a
|
|
1872
|
+
reloaded expression was not recognised as one: an `auto` field then
|
|
1873
|
+
resolved its type from the value it could see, decided the envelope was
|
|
1874
|
+
a `hash`, and rendered `1 + 2` as a raw tree of `is_expression` /
|
|
1875
|
+
`exp` / `args` for the author to edit by hand.
|
|
1876
|
+
|
|
1877
|
+
Both halves have to move together. Flipping the flag alone would put
|
|
1878
|
+
the editor into expression mode and then hand it the ENVELOPE where it
|
|
1879
|
+
expects the expression, so the value is unwrapped here too — after
|
|
1880
|
+
which a saved expression is indistinguishable from one just typed,
|
|
1881
|
+
which is what every component downstream already assumes.
|
|
1882
|
+
|
|
1883
|
+
Reported as "after Run assertion the value shows as raw data", but the
|
|
1884
|
+
run is incidental: the field beside it, which no run touched, was
|
|
1885
|
+
equally raw. The trigger is a RELOAD, which is the only thing that puts
|
|
1886
|
+
an expression into its saved shape. */
|
|
1887
|
+
var nestedExpression = !!((_b = other === null || other === void 0 ? void 0 : other.value) === null || _b === void 0 ? void 0 : _b.is_expression);
|
|
1888
|
+
var expressionAwareValue = nestedExpression ?
|
|
1889
|
+
other.value.value
|
|
1890
|
+
: other.value;
|
|
1497
1891
|
var resolvedType = ((0, readFirst_1.isFixedCompactAllowedValueOption)(optionSchema) ?
|
|
1498
1892
|
getOptionSchemaStorageType(optionSchema, isRendererOnly)
|
|
1499
1893
|
: schemaUiType && !uiTypeIsAnyLike ? schemaUiType
|
|
1500
1894
|
: undefined) ||
|
|
1501
|
-
|
|
1895
|
+
storedRowType ||
|
|
1502
1896
|
schemaUiType ||
|
|
1503
1897
|
(optionSchema === null || optionSchema === void 0 ? void 0 : optionSchema.type) ||
|
|
1504
1898
|
'any';
|
|
@@ -1537,7 +1931,7 @@ var FormEngineImpl = function (_a) {
|
|
|
1537
1931
|
(0, jsx_runtime_1.jsx)(reqore_1.ReqoreButton, { disabled: readOnly, icon: 'DeleteBinLine', effect: NegativeColorEffect, fixed: true, onClick: function () { return handleRemoveOperator(optionName, fixedValue, index); } })
|
|
1538
1932
|
: null] }, index));
|
|
1539
1933
|
}) }), (0, jsx_runtime_1.jsx)(reqore_1.ReqoreVerticalSpacer, { height: 5 })] })
|
|
1540
|
-
: null, (0, react_1.createElement)(TemplateField_1.TemplateField, __assign({ fluid: true }, options === null || options === void 0 ? void 0 : options[optionName], resolveInheritProps((
|
|
1934
|
+
: null, (0, react_1.createElement)(TemplateField_1.TemplateField, __assign({ fluid: true }, options === null || options === void 0 ? void 0 : options[optionName], resolveInheritProps((_c = options === null || options === void 0 ? void 0 : options[optionName]) === null || _c === void 0 ? void 0 : _c.inherit_props, availableOptions, inheritedFromParent), {
|
|
1541
1935
|
// qorus#347-followup (scope forwarding): merge accumulated
|
|
1542
1936
|
// inheritance (`inheritedFromParent`) with THIS field's freshly
|
|
1543
1937
|
// resolved inherit_props, and pass down as a single bag so any
|
|
@@ -1549,13 +1943,20 @@ var FormEngineImpl = function (_a) {
|
|
|
1549
1943
|
// `inherit_props: { language: 'language' }`, the list renderer
|
|
1550
1944
|
// forwards it into each row, and the row's body resolves against
|
|
1551
1945
|
// the accumulated bag.
|
|
1552
|
-
|
|
1946
|
+
//
|
|
1947
|
+
// Read from the memoised map rather than built here: this is a
|
|
1948
|
+
// PROP, and one built inline is a new object on every render of
|
|
1949
|
+
// the form, which re-renders every field that receives it. The
|
|
1950
|
+
// `??` chain answers for a field the schema does not describe —
|
|
1951
|
+
// `inheritedScopeFor` returns the SAME references, so an
|
|
1952
|
+
// undescribed field is as stable as a described one.
|
|
1953
|
+
inheritedFromParent: (_f = (_d = inheritedScopes.get(optionName)) !== null && _d !== void 0 ? _d : inheritedFromParent) !== null && _f !== void 0 ? _f : NO_INHERITED_SCOPE,
|
|
1553
1954
|
// Propagate compact so an arg_schema field renders a COMPACT sub-form
|
|
1554
1955
|
// (consistent with the parent) rather than the classic FormEngine.
|
|
1555
1956
|
compact: compact,
|
|
1556
1957
|
// SEAM: forwarded through TemplateField's rest-spread to AutoFormField,
|
|
1557
1958
|
// which renders consumer-injected editors by field type/ui_type.
|
|
1558
|
-
componentOverrides: componentOverrides, allowTemplates: !!(allowTemplates && ((
|
|
1959
|
+
componentOverrides: componentOverrides, templateAwareUiTypes: templateAwareUiTypes, allowTemplates: !!(allowTemplates && ((_g = options === null || options === void 0 ? void 0 : options[optionName]) === null || _g === void 0 ? void 0 : _g.supports_templates)), allowFunctions: !!((_h = options === null || options === void 0 ? void 0 : options[optionName]) === null || _h === void 0 ? void 0 : _h.supports_expressions),
|
|
1559
1960
|
// reqraft: form-level expression fields get the Visual/Text shell
|
|
1560
1961
|
// (DPQL text mode); opt out per-form via `templateFieldProps`.
|
|
1561
1962
|
allowTextExpressions: true,
|
|
@@ -1567,25 +1968,42 @@ var FormEngineImpl = function (_a) {
|
|
|
1567
1968
|
// control groups. The allowed-values renderer itself enforces the
|
|
1568
1969
|
// fixed catalogue and never exposes free-form entry.
|
|
1569
1970
|
allowCustomValues: (0, readFirst_1.isFixedCompactAllowedValueOption)(optionSchema) ||
|
|
1570
|
-
(((
|
|
1971
|
+
(((_j = options === null || options === void 0 ? void 0 : options[optionName]) === null || _j === void 0 ? void 0 : _j.supports_custom_values) !== false && resolvedType !== 'any'),
|
|
1972
|
+
// A field may declare a template list OF ITS OWN, and when it does
|
|
1973
|
+
// that list is the one to offer. The engine-wide `stringTemplates`
|
|
1974
|
+
// are the form's shared vocabulary - config items, system properties
|
|
1975
|
+
// - and every field draws on the same set. A per-field list answers a
|
|
1976
|
+
// question only that field asks: a test assertion's `$.` references
|
|
1977
|
+
// are the values ITS case captured, and no other field in the form
|
|
1978
|
+
// should be offering them.
|
|
1979
|
+
//
|
|
1980
|
+
// Passing the engine's list unconditionally overwrote the schema's,
|
|
1981
|
+
// so a field that declared templates had none by the time it
|
|
1982
|
+
// rendered. On a typed field that only cost the picker; on an
|
|
1983
|
+
// ANY-LIKE one it changed the question, because `TemplateField`
|
|
1984
|
+
// opens on the template selector only when there is something to
|
|
1985
|
+
// pick and otherwise falls back to the type picker. An untyped field
|
|
1986
|
+
// therefore asked the author to choose `string`/`int`/`hash` before
|
|
1987
|
+
// it would let them name a value they had already captured.
|
|
1988
|
+
templates: (_k = optionSchema === null || optionSchema === void 0 ? void 0 : optionSchema.templates) !== null && _k !== void 0 ? _k : templates.value }, (0, exports.getTypeAndCanBeNull)(
|
|
1571
1989
|
// The RENDERER type picks the editor — the storage type lives on
|
|
1572
1990
|
// the value envelope. Passing storage here rendered a `richtext`
|
|
1573
1991
|
// field as a plain string input.
|
|
1574
|
-
resolvedType, (
|
|
1992
|
+
resolvedType, (_l = options === null || options === void 0 ? void 0 : options[optionName]) === null || _l === void 0 ? void 0 : _l.allowed_values, other.op), { ui_type: resolvedType, name: optionName, uniqueName: "".concat(uniqueName ? "".concat(uniqueName, ".") : "".concat(name ? "".concat(name, ".") : '')).concat(optionName), onChange:
|
|
1575
1993
|
// Identity-stable on purpose: the typed fields debounce on
|
|
1576
1994
|
// `[localValue, onChange]` — an inline lambda resets the pending emit
|
|
1577
1995
|
// every render and the typed value can starve.
|
|
1578
|
-
handleValueChange, key: optionName, arg_schema: (
|
|
1996
|
+
handleValueChange, key: optionName, arg_schema: (_m = options === null || options === void 0 ? void 0 : options[optionName]) === null || _m === void 0 ? void 0 : _m.arg_schema, noSoft: !!(rest === null || rest === void 0 ? void 0 : rest.options), value: expressionAwareValue, isFunction: optionHoldsExpression(other), isDefaultFunction: ((_o = options === null || options === void 0 ? void 0 : options[optionName]) === null || _o === void 0 ? void 0 : _o.default_view) === 'expression', sensitive: (_p = options === null || options === void 0 ? void 0 : options[optionName]) === null || _p === void 0 ? void 0 : _p.sensitive, default_value: (0, common_1.getDefaultValue)(options === null || options === void 0 ? void 0 : options[optionName]), isDefaultTemplate: ((_q = options === null || options === void 0 ? void 0 : options[optionName]) === null || _q === void 0 ? void 0 : _q.default_view) === 'template', allowed_values: (_r = options === null || options === void 0 ? void 0 : options[optionName]) === null || _r === void 0 ? void 0 : _r.allowed_values, allowed_values_creatable: (_s = options === null || options === void 0 ? void 0 : options[optionName]) === null || _s === void 0 ? void 0 : _s.allowed_values_creatable, disabled: ((_t = options === null || options === void 0 ? void 0 : options[optionName]) === null || _t === void 0 ? void 0 : _t.disabled) ||
|
|
1579
1997
|
(
|
|
1580
1998
|
// a system-owned field states that as `readonly`; only the older
|
|
1581
1999
|
// compat projection also sent `disabled`, so honouring only
|
|
1582
2000
|
// `disabled` rendered an editable control for a value the user
|
|
1583
2001
|
// cannot change (see CompactRow's `fieldReadonly`)
|
|
1584
|
-
(
|
|
2002
|
+
(_u = options === null || options === void 0 ? void 0 : options[optionName]) === null || _u === void 0 ? void 0 : _u.readonly) ||
|
|
1585
2003
|
readOnly ||
|
|
1586
|
-
!(0, validations_1.hasAllDependenciesFullfilled)((
|
|
2004
|
+
!(0, validations_1.hasAllDependenciesFullfilled)((_v = options === null || options === void 0 ? void 0 : options[optionName]) === null || _v === void 0 ? void 0 : _v.depends_on, availableOptions, options || {}), readOnly: readOnly, size: editorSize || rest.size, menuItems: (0, typeChoices_1.offersTypeChoices)(options === null || options === void 0 ? void 0 : options[optionName], anyLikeUiTypes) ?
|
|
1587
2005
|
getCustomMenuTemplateItems(optionName)
|
|
1588
|
-
: undefined }, templateFieldProps, { forceDropdown: effectiveForceDropdown })), (0, jsx_runtime_1.jsx)(OptionFieldMessages_1.OptionFieldMessages, { schema: options || {}, allOptions: availableOptions, name: optionName, option: __assign({ type: resolvedType }, other), getType: getTypeForOption }), operators && (0, size_1.default)(operators) && (0, size_1.default)(other.op) ?
|
|
2006
|
+
: undefined }, templateFieldProps, { forceDropdown: effectiveForceDropdown })), (0, jsx_runtime_1.jsx)(OptionFieldMessages_1.OptionFieldMessages, { schema: options || {}, allOptions: availableOptions, name: optionName, option: __assign({ type: resolvedType }, other), getType: getTypeForOption, untouched: !touchedOptionsRef.current.has(optionName) }), operators && (0, size_1.default)(operators) && (0, size_1.default)(other.op) ?
|
|
1589
2007
|
(0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [(0, jsx_runtime_1.jsx)(reqore_1.ReqoreVerticalSpacer, { height: 5 }), (0, jsx_runtime_1.jsx)(reqore_1.ReqoreMessage, { size: 'small', children: (0, jsx_runtime_1.jsxs)(reqore_1.ReqoreTagGroup, { children: [(0, jsx_runtime_1.jsx)(reqore_1.ReqoreTag, { size: 'small', labelKey: 'WHERE', label: optionName }), (0, jsx_runtime_1.jsx)(reqore_1.ReqoreTag, { size: 'small', labelKey: 'IS', label: operatorParts.join(' ') }), (0, jsx_runtime_1.jsx)(reqore_1.ReqoreTag, { size: 'small', intent: 'info', label: other.value ?
|
|
1590
2008
|
resolvedType === 'richtext' ?
|
|
1591
2009
|
(0, common_1.richtextToString)(other.value)
|
|
@@ -1615,10 +2033,12 @@ var FormEngineImpl = function (_a) {
|
|
|
1615
2033
|
handleRemoveOperator,
|
|
1616
2034
|
getCustomMenuTemplateItems,
|
|
1617
2035
|
getTypeForOption,
|
|
2036
|
+
inheritedScopes,
|
|
2037
|
+
inheritedFromParent,
|
|
1618
2038
|
]);
|
|
1619
2039
|
// Compact (read-first) rendering.
|
|
1620
2040
|
// Theme-derived colours so the flat-row layout adapts to light/dark/custom themes.
|
|
1621
|
-
var cText = ((
|
|
2041
|
+
var cText = ((_b = theme === null || theme === void 0 ? void 0 : theme.text) === null || _b === void 0 ? void 0 : _b.color) || '#f1f0ee';
|
|
1622
2042
|
// Text emphasis tiers via reqore's readable-colour helper (key = full readable
|
|
1623
2043
|
// text, muted = its dimmed variant, faint = the dimmed variant softened
|
|
1624
2044
|
// further) instead of hand-rolled hex-alpha suffixes on the raw text colour.
|
|
@@ -1627,10 +2047,10 @@ var FormEngineImpl = function (_a) {
|
|
|
1627
2047
|
var cFaint = "".concat(cMuted, "99");
|
|
1628
2048
|
var cDivider = "".concat(cText, "14");
|
|
1629
2049
|
var cHover = "".concat(cText, "0d");
|
|
1630
|
-
var cDanger = ((
|
|
1631
|
-
var cWarning = ((
|
|
1632
|
-
var cInfo = ((
|
|
1633
|
-
var cSuccess = ((
|
|
2050
|
+
var cDanger = ((_c = theme === null || theme === void 0 ? void 0 : theme.intents) === null || _c === void 0 ? void 0 : _c.danger) || '#e35a5a';
|
|
2051
|
+
var cWarning = ((_d = theme === null || theme === void 0 ? void 0 : theme.intents) === null || _d === void 0 ? void 0 : _d.warning) || '#ffdf34';
|
|
2052
|
+
var cInfo = ((_f = theme === null || theme === void 0 ? void 0 : theme.intents) === null || _f === void 0 ? void 0 : _f.info) || '#3b8eea';
|
|
2053
|
+
var cSuccess = ((_g = theme === null || theme === void 0 ? void 0 : theme.intents) === null || _g === void 0 ? void 0 : _g.success) || '#36b37e';
|
|
1634
2054
|
var cBg = (theme === null || theme === void 0 ? void 0 : theme.main) || '#181818';
|
|
1635
2055
|
var cRowBg = (0, colors_1.changeDarkness)((0, colors_1.getMainBackgroundColor)(theme), 0.01);
|
|
1636
2056
|
var cGroupLine = "".concat(cText, "1f");
|
|
@@ -1643,6 +2063,7 @@ var FormEngineImpl = function (_a) {
|
|
|
1643
2063
|
var compactRowContextValue = (0, react_2.useMemo)(function () { return ({
|
|
1644
2064
|
templates: templates.value,
|
|
1645
2065
|
readOnly: readOnly,
|
|
2066
|
+
onReadOnlyActivate: onReadOnlyActivate,
|
|
1646
2067
|
commitMode: commitMode,
|
|
1647
2068
|
expandMode: expandMode,
|
|
1648
2069
|
options: options,
|
|
@@ -1652,7 +2073,6 @@ var FormEngineImpl = function (_a) {
|
|
|
1652
2073
|
codePreviewRenderer: codePreviewRenderer,
|
|
1653
2074
|
showAllDescriptions: showAllDescriptions,
|
|
1654
2075
|
expandedOptions: expandedOptions,
|
|
1655
|
-
autoFocusNameRef: autoFocusNameRef,
|
|
1656
2076
|
highlightedOptions: highlightedOptions,
|
|
1657
2077
|
flashedOptions: flashedOptions,
|
|
1658
2078
|
infoPanelOverrides: infoPanelOverrides,
|
|
@@ -1699,7 +2119,6 @@ var FormEngineImpl = function (_a) {
|
|
|
1699
2119
|
codePreviewRenderer,
|
|
1700
2120
|
showAllDescriptions,
|
|
1701
2121
|
expandedOptions,
|
|
1702
|
-
autoFocusNameRef,
|
|
1703
2122
|
highlightedOptions,
|
|
1704
2123
|
flashedOptions,
|
|
1705
2124
|
infoPanelOverrides,
|
|
@@ -1756,7 +2175,21 @@ var FormEngineImpl = function (_a) {
|
|
|
1756
2175
|
fields: false,
|
|
1757
2176
|
help: false,
|
|
1758
2177
|
},
|
|
1759
|
-
|
|
2178
|
+
/* From the SCHEMA, not from the value.
|
|
2179
|
+
*
|
|
2180
|
+
* `availableOptions` is keyed off the form's VALUE, so it grows as data
|
|
2181
|
+
* arrives — and the search row is rendered only when this is true
|
|
2182
|
+
* (`CompactToolbar`). A form whose value lands after its first render
|
|
2183
|
+
* therefore ADDED a 38px row to its header a beat later, and everything
|
|
2184
|
+
* below it moved. Measured on the Qorus IDE's test editor, on the nested
|
|
2185
|
+
* sub-form of a case: 33 elements jumped down 51px in one frame, on every
|
|
2186
|
+
* cold load.
|
|
2187
|
+
*
|
|
2188
|
+
* How many fields a form has is a property of its schema. The two agree
|
|
2189
|
+
* once the value has arrived — `fixOptions` materialises an entry per
|
|
2190
|
+
* declared field — so this only changes the answer during the load, which
|
|
2191
|
+
* is the whole point. */
|
|
2192
|
+
hasMultipleOptions: (0, size_1.default)(options) > 1,
|
|
1760
2193
|
compactQuery: compactQuery,
|
|
1761
2194
|
setCompactQuery: setCompactQuery,
|
|
1762
2195
|
requiredOnly: requiredOnly,
|
|
@@ -1776,6 +2209,7 @@ var FormEngineImpl = function (_a) {
|
|
|
1776
2209
|
onRevertAll: handleRevertChangesClick,
|
|
1777
2210
|
}); }, [
|
|
1778
2211
|
readOnly,
|
|
2212
|
+
onReadOnlyActivate,
|
|
1779
2213
|
validityData,
|
|
1780
2214
|
readFirstAttentionCount,
|
|
1781
2215
|
readFirstCompletion,
|
|
@@ -1807,6 +2241,7 @@ var FormEngineImpl = function (_a) {
|
|
|
1807
2241
|
// removes it, and then the header carries just the consumer's own actions.
|
|
1808
2242
|
var compactHeaderActions = (0, react_2.useMemo)(function () { return __spreadArray(__spreadArray([], (compactToolbarParts ? [{ as: CompactToolbar_1.CompactToolbar, responsive: false }] : []), true), ((compactPanelProps === null || compactPanelProps === void 0 ? void 0 : compactPanelProps.actions) || []), true); }, [compactPanelProps === null || compactPanelProps === void 0 ? void 0 : compactPanelProps.actions, compactToolbarParts]);
|
|
1809
2243
|
var renderCompact = function () {
|
|
2244
|
+
var _a, _b, _c;
|
|
1810
2245
|
var headerBg = "".concat((0, colors_1.changeDarkness)((0, colors_1.getMainBackgroundColor)(theme), 0.02)).concat((0, colors_1.percentToHexAlpha)(88));
|
|
1811
2246
|
// Toolbar filters narrow the listed rows; the meter reflects the full set.
|
|
1812
2247
|
var query = compactQuery.trim().toLowerCase();
|
|
@@ -1899,7 +2334,7 @@ var FormEngineImpl = function (_a) {
|
|
|
1899
2334
|
var isUnset_1 = function (name) { var _a; return (0, readFirst_1.isOptionValueEmpty)((_a = shownOptions[name]) === null || _a === void 0 ? void 0 : _a.value); };
|
|
1900
2335
|
var isFieldInvalid_1 = function (name) {
|
|
1901
2336
|
var _a, _b, _c;
|
|
1902
|
-
return !isOptionValid(name, getOptionFieldStorageType(name, (_a = shownOptions[name]) === null || _a === void 0 ? void 0 : _a.type, options, operators, (_b = shownOptions[name]) === null || _b === void 0 ? void 0 : _b.op, isRendererOnly), (_c = shownOptions[name]) === null || _c === void 0 ? void 0 : _c.value);
|
|
2337
|
+
return !isOptionValid(name, (0, exports.getOptionFieldStorageType)(name, (_a = shownOptions[name]) === null || _a === void 0 ? void 0 : _a.type, options, operators, (_b = shownOptions[name]) === null || _b === void 0 ? void 0 : _b.op, isRendererOnly), (_c = shownOptions[name]) === null || _c === void 0 ? void 0 : _c.value);
|
|
1903
2338
|
};
|
|
1904
2339
|
var comparator_1 = function (a, b) {
|
|
1905
2340
|
switch (compactSort) {
|
|
@@ -1985,6 +2420,13 @@ var FormEngineImpl = function (_a) {
|
|
|
1985
2420
|
var bucketCount = function (b) {
|
|
1986
2421
|
return bucketGroups[b].reduce(function (n, g) { return n + buckets[b][g].length; }, 0);
|
|
1987
2422
|
};
|
|
2423
|
+
/* The default is to collapse the Optional box, and an explicit pass is
|
|
2424
|
+
what waives the "never collapse the sole box" escape below. Resolving it
|
|
2425
|
+
here rather than in the parameter list is what makes the two
|
|
2426
|
+
distinguishable — `['optional']` as a default and `['optional']` from a
|
|
2427
|
+
caller mean different things. */
|
|
2428
|
+
var compactCollapsedGroups = compactCollapsedGroupsProp !== null && compactCollapsedGroupsProp !== void 0 ? compactCollapsedGroupsProp : ['optional'];
|
|
2429
|
+
var collapsedGroupsRequested = compactCollapsedGroupsProp !== undefined;
|
|
1988
2430
|
// "Is the Optional box the whole form?" — when nothing needs attention and
|
|
1989
2431
|
// nothing is set, collapsing it leaves a card with no visible content at all.
|
|
1990
2432
|
var onlyOptionalRows = bucketCount('optional') > 0 && bucketCount('attention') === 0 && bucketCount('set') === 0;
|
|
@@ -2024,10 +2466,23 @@ var FormEngineImpl = function (_a) {
|
|
|
2024
2466
|
return boxKey === 'optional' &&
|
|
2025
2467
|
bucketGroups[boxKey].some(function (groupName) { return groupHasPreselectedRow(boxKey, groupName); });
|
|
2026
2468
|
};
|
|
2469
|
+
/* The pin, and where it lands. A nested sub-form sits inside the parent's
|
|
2470
|
+
card and owns no scroll context, so it never pins. */
|
|
2471
|
+
var stickyBoxHeaders = compactStickyBoxHeaders && !compactNested;
|
|
2472
|
+
var boxStickyOffset = compactStickyOffset + compactToolbarHeight;
|
|
2027
2473
|
var STATUS_BOXES = [
|
|
2028
|
-
{
|
|
2029
|
-
|
|
2030
|
-
|
|
2474
|
+
{
|
|
2475
|
+
key: 'attention',
|
|
2476
|
+
label: (_a = compactBoxLabels === null || compactBoxLabels === void 0 ? void 0 : compactBoxLabels.attention) !== null && _a !== void 0 ? _a : 'Needs attention',
|
|
2477
|
+
intent: 'warning',
|
|
2478
|
+
icon: 'ErrorWarningLine',
|
|
2479
|
+
},
|
|
2480
|
+
{ key: 'set', label: (_b = compactBoxLabels === null || compactBoxLabels === void 0 ? void 0 : compactBoxLabels.set) !== null && _b !== void 0 ? _b : 'Set', intent: 'success', icon: 'CheckLine' },
|
|
2481
|
+
{
|
|
2482
|
+
key: 'optional',
|
|
2483
|
+
label: (_c = compactBoxLabels === null || compactBoxLabels === void 0 ? void 0 : compactBoxLabels.optional) !== null && _c !== void 0 ? _c : 'Optional',
|
|
2484
|
+
icon: 'CheckboxBlankCircleLine',
|
|
2485
|
+
},
|
|
2031
2486
|
];
|
|
2032
2487
|
// Build the rows for one group: contiguous required-group members are pulled
|
|
2033
2488
|
// together at the first member's slot and rendered as a connected rail (flat
|
|
@@ -2104,17 +2559,59 @@ var FormEngineImpl = function (_a) {
|
|
|
2104
2559
|
}, children: groupConfig.subtitle })
|
|
2105
2560
|
: null, renderGroupRows(rows)] }, groupName));
|
|
2106
2561
|
};
|
|
2107
|
-
return ((0, jsx_runtime_1.jsx)(
|
|
2562
|
+
return ((0, jsx_runtime_1.jsx)(optionsContext_1.OptionsContext.Provider, { value: { schema: options, value: availableOptions }, children: (0, jsx_runtime_1.jsx)(compactRowContext_1.CompactRowContext.Provider, { value: compactRowContextValue, children: (0, jsx_runtime_1.jsxs)(reqore_1.ReqoreErrorBoundary, { children: [showHelpForOption && ((0, jsx_runtime_1.jsx)(OptionsHelpDialog_1.OptionsHelpDialog, { onClose: function () { return setShowHelpForOption(undefined); }, option: options[showHelpForOption] })), (0, jsx_runtime_1.jsx)(compactToolbarContext_1.CompactToolbarContext.Provider, { value: compactToolbarContextValue, children: (0, jsx_runtime_1.jsxs)(StyledCompactWrap, { ref: setCompactWrap, className: 'options-readfirst-scroll', "$ownScroll": compactScroll === 'own' && !compactNested, children: [(0, jsx_runtime_1.jsxs)(compactRowStyles_1.StyledCompactPanel
|
|
2108
2563
|
// Mirrors the toolbar's own search-row gate: when no search
|
|
2109
2564
|
// row renders, the header is a thin strip and sits tight to
|
|
2110
2565
|
// the first status box (see StyledCompactPanel).
|
|
2111
|
-
, __assign({ "$tightHeader": !((compactToolbarParts === null || compactToolbarParts === void 0 ? void 0 : compactToolbarParts.search) && (0, size_1.default)(
|
|
2566
|
+
, __assign({ "$tightHeader": !((compactToolbarParts === null || compactToolbarParts === void 0 ? void 0 : compactToolbarParts.search) && (0, size_1.default)(options) > 1), "$headerBg": compactNested ? 'transparent' : headerBg, "$nested": compactNested, "$stickyBoxes": compactStickyBoxHeaders && !compactNested, flat: true, raised: true, minimal: true,
|
|
2112
2567
|
// No panel background: the form sits transparently on whatever
|
|
2113
2568
|
// hosts it (page, drawer, or — for an arg_schema field — the
|
|
2114
2569
|
// parent's edit card) instead of stacking its own dark surface.
|
|
2115
2570
|
// The status boxes keep their own tints; the sticky toolbar keeps
|
|
2116
2571
|
// its blurred header via the $headerBg override.
|
|
2117
|
-
|
|
2572
|
+
// NARROW: the toolbar gives up its pin so the box headers
|
|
2573
|
+
// can keep theirs.
|
|
2574
|
+
//
|
|
2575
|
+
// Measured at 380px, a pinned toolbar is 124px and a pinned
|
|
2576
|
+
// box header is 48 — together a third of a phone's readable
|
|
2577
|
+
// body, before the form has drawn a line. Only one of them
|
|
2578
|
+
// can be afforded there, and the box header is the better
|
|
2579
|
+
// buy: the toolbar is chrome you GO to (a search, a field
|
|
2580
|
+
// picker, a meter — all of it still one scroll away at the
|
|
2581
|
+
// top of the form), while the box header is chrome you READ,
|
|
2582
|
+
// and it is the only thing that says which bucket the rows
|
|
2583
|
+
// under the pointer are in.
|
|
2584
|
+
//
|
|
2585
|
+
// Same shape of decision the engine already makes one level
|
|
2586
|
+
// down, where `optionActionsCollapse: 'auto'` folds a row's
|
|
2587
|
+
// actions into a menu because a narrow row has no width for
|
|
2588
|
+
// a button strip.
|
|
2589
|
+
//
|
|
2590
|
+
// A consumer can still force either way: `compactPanelProps`
|
|
2591
|
+
// spreads after this.
|
|
2592
|
+
stickyHeader: !compactNested && !(compactNarrow && compactStickyBoxHeaders),
|
|
2593
|
+
// Below the host's own pinned chrome, if it has any — see
|
|
2594
|
+
// `compactStickyOffset`.
|
|
2595
|
+
stickyHeaderOffset: compactStickyOffset || undefined }, compactPanelProps, { actions: compactHeaderActions, contentStyle: __assign({ display: 'flex', flexFlow: 'column', gap: '10px',
|
|
2596
|
+
/* The panel body must not be a SCROLL CONTAINER.
|
|
2597
|
+
|
|
2598
|
+
`StyledPanelContent` ships `overflow: auto` so a
|
|
2599
|
+
height-capped panel can scroll its body. This one is never
|
|
2600
|
+
capped — in `compactScroll: 'host'` the page scrolls and in
|
|
2601
|
+
'own' the wrap above does — so the `auto` never engages and
|
|
2602
|
+
reads as inert. It is not: an `overflow: auto` box is a
|
|
2603
|
+
scrollport whether or not it scrolls, and every
|
|
2604
|
+
`position: sticky` inside resolves against IT. The status
|
|
2605
|
+
box headers (and the toolbar, in a nested host) would pin
|
|
2606
|
+
to a box that never moves, which looks exactly like sticky
|
|
2607
|
+
being ignored.
|
|
2608
|
+
|
|
2609
|
+
`overflow-x: clip`, NOT `hidden`, for the reason spelled
|
|
2610
|
+
out on `StyledCompactWrap`: CSS coerces an `overflow-y:
|
|
2611
|
+
visible` to `auto` unless the other axis is visible or
|
|
2612
|
+
clip, which would put the scrollport straight back. `clip`
|
|
2613
|
+
keeps the horizontal guard the row ellipsis relies on. */
|
|
2614
|
+
overflowY: 'visible', overflowX: 'clip' }, compactPanelProps === null || compactPanelProps === void 0 ? void 0 : compactPanelProps.contentStyle), children: [(0, size_1.default)(groupKeys) === 0 || (readOnly && !bucketCount('set')) ?
|
|
2118
2615
|
(0, jsx_runtime_1.jsx)(reqore_1.ReqoreMessage, { flat: true, opaque: false, size: 'small', children: readOnly && !query ?
|
|
2119
2616
|
'Nothing is set.'
|
|
2120
2617
|
: 'No fields match the current filters.' })
|
|
@@ -2130,7 +2627,7 @@ var FormEngineImpl = function (_a) {
|
|
|
2130
2627
|
var hasPreselectedRows = boxHasPreselectedRows(box.key);
|
|
2131
2628
|
var wouldCollapse = compactCollapsedGroups.includes(box.key) &&
|
|
2132
2629
|
!query &&
|
|
2133
|
-
!(box.key === 'optional' && onlyOptionalRows);
|
|
2630
|
+
!(box.key === 'optional' && onlyOptionalRows && !collapsedGroupsRequested);
|
|
2134
2631
|
// Only a box that was opened SOLELY to reveal a preselected
|
|
2135
2632
|
// row splits its body; a box that renders open anyway shows
|
|
2136
2633
|
// all of its groups as before.
|
|
@@ -2174,14 +2671,19 @@ var FormEngineImpl = function (_a) {
|
|
|
2174
2671
|
var boxBg = box.key === 'optional' ?
|
|
2175
2672
|
(0, colors_1.changeDarkness)((0, colors_1.getMainBackgroundColor)(theme), 0.06)
|
|
2176
2673
|
: undefined;
|
|
2177
|
-
return ((0, jsx_runtime_1.jsx)(compactRowStyles_1.StyledStatusBox, { "$accent": accent, "$bg": boxBg, ref: function (node) {
|
|
2674
|
+
return ((0, jsx_runtime_1.jsx)(compactRowStyles_1.StyledStatusBox, { "$accent": accent, "$bg": boxBg, "$surface": stickyBoxHeaders ? (0, colors_1.getMainBackgroundColor)(theme) : undefined, ref: function (node) {
|
|
2178
2675
|
statusBoxRefs.current[box.key] = node;
|
|
2179
2676
|
},
|
|
2180
2677
|
// Opening arms the reveal; collapsing disarms it, so a
|
|
2181
2678
|
// close never scrolls.
|
|
2182
2679
|
onCollapseChange: function (collapsed) {
|
|
2183
2680
|
return setOpenedStatusBox(collapsed ? undefined : box.key);
|
|
2184
|
-
}, flat: true, minimal: true,
|
|
2681
|
+
}, flat: true, minimal: true,
|
|
2682
|
+
/* The header stays on screen while its own box is
|
|
2683
|
+
being read — see `compactStickyBoxHeaders`. Sticky
|
|
2684
|
+
is bounded by its containing block, so the header
|
|
2685
|
+
leaves with its box and only one is ever pinned. */
|
|
2686
|
+
stickyHeader: stickyBoxHeaders, stickyHeaderOffset: stickyBoxHeaders ? boxStickyOffset : undefined, collapseButtonProps: { flat: true, minimal: true, size: 'small' }, collapsible: true,
|
|
2185
2687
|
// Which boxes start closed is the consumer's call
|
|
2186
2688
|
// (`compactCollapsedGroups`, default `['optional']`: the
|
|
2187
2689
|
// Optional box holds every not-yet-added field, so a form
|
|
@@ -2231,15 +2733,23 @@ var FormEngineImpl = function (_a) {
|
|
|
2231
2733
|
: 'Resolve the invalid fields before saving', onClick: handleCommitClick, children: "Save" }), (0, jsx_runtime_1.jsx)(reqore_1.ReqoreButton, { size: 'small', minimal: true, flat: true, fixed: true, icon: 'HistoryLine', className: 'options-readfirst-discard', onClick: handleRevertChangesClick, children: "Discard" })] }) })
|
|
2232
2734
|
: null] }) })] }) }) }));
|
|
2233
2735
|
};
|
|
2234
|
-
|
|
2235
|
-
|
|
2236
|
-
|
|
2237
|
-
|
|
2238
|
-
|
|
2239
|
-
|
|
2240
|
-
|
|
2241
|
-
|
|
2242
|
-
|
|
2736
|
+
/* Which of the seven waits is holding the form, in the order they are
|
|
2737
|
+
tested. Rendered as `data-wait` on the placeholder so a page can be asked
|
|
2738
|
+
what it is waiting FOR instead of only that it is waiting. */
|
|
2739
|
+
var waitReason = rest.skeleton ? (rest.skeletonReason ? "host:".concat(rest.skeletonReason) : 'host')
|
|
2740
|
+
: templates.loading ? 'templates'
|
|
2741
|
+
: typesLoading ? 'types'
|
|
2742
|
+
: optionsLoading ? 'options'
|
|
2743
|
+
: loading ? 'fetch'
|
|
2744
|
+
: operatorsUrl && !operators ? 'operators'
|
|
2745
|
+
: (url || customUrl) && !options ? 'schema'
|
|
2746
|
+
: undefined;
|
|
2747
|
+
if (waitReason) {
|
|
2748
|
+
/* The shape of the FORM, not a generic block arrangement. This used to be
|
|
2749
|
+
three bars over three big panels, which resembles nothing this gate is
|
|
2750
|
+
waiting for and shared no vocabulary with the other waits on the same
|
|
2751
|
+
page — see `FormFieldsSkeleton`. */
|
|
2752
|
+
return (0, jsx_runtime_1.jsx)(FormFieldsSkeleton_1.FormFieldsSkeleton, { fill: true, className: 'options-loading-skeleton', reason: waitReason });
|
|
2243
2753
|
}
|
|
2244
2754
|
// A loader that rejected (and produced no usable schema) surfaces its error
|
|
2245
2755
|
// instead of the generic "No options available" empty state.
|
|
@@ -2252,7 +2762,7 @@ var FormEngineImpl = function (_a) {
|
|
|
2252
2762
|
if (compact) {
|
|
2253
2763
|
return renderCompact();
|
|
2254
2764
|
}
|
|
2255
|
-
return ((0, jsx_runtime_1.jsx)(
|
|
2765
|
+
return ((0, jsx_runtime_1.jsx)(optionsContext_1.OptionsContext.Provider, { value: { schema: options, value: availableOptions }, children: (0, jsx_runtime_1.jsxs)(reqore_1.ReqoreErrorBoundary, { children: [showHelpForOption && ((0, jsx_runtime_1.jsx)(OptionsHelpDialog_1.OptionsHelpDialog, { onClose: function () { return setShowHelpForOption(undefined); }, option: options[showHelpForOption] })), recordRequiresSearchOptions && !readOnly ?
|
|
2256
2766
|
(0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [(0, jsx_runtime_1.jsx)(reqore_1.ReqoreMessage, { intent: 'info', children: "This provider record requires some search options to be set. You can set them below." }), (0, jsx_runtime_1.jsx)(reqore_1.ReqoreVerticalSpacer, { height: 10 })] })
|
|
2257
2767
|
: null, (0, jsx_runtime_1.jsx)(reqore_1.ReqoreCollection, __assign({ minColumnWidth: '350px', flat: true, padded: false, minimal: true }, rest, { label: compact ? undefined : rest.label, responsiveTitle: false, inputProps: {
|
|
2258
2768
|
disabled: (0, size_1.default)(availableOptions) < 2,
|
|
@@ -2314,72 +2824,67 @@ var FormEngineImpl = function (_a) {
|
|
|
2314
2824
|
stretch: STRECHABLE_TYPES.has(options[optionName].type) ||
|
|
2315
2825
|
options[optionName].stretch,
|
|
2316
2826
|
size: 'small',
|
|
2317
|
-
|
|
2318
|
-
|
|
2319
|
-
|
|
2320
|
-
|
|
2321
|
-
|
|
2322
|
-
|
|
2323
|
-
|
|
2324
|
-
|
|
2325
|
-
|
|
2326
|
-
|
|
2327
|
-
|
|
2328
|
-
|
|
2827
|
+
/* No floating bar. It is portalled over whatever sits above the
|
|
2828
|
+
row — on the first row, the form's own header buttons, which it
|
|
2829
|
+
made unclickable — and a bar that only appears on a hover is out
|
|
2830
|
+
of reach on a phone. The row's actions render in its own
|
|
2831
|
+
header: injected ones as buttons (all of them in the menu on
|
|
2832
|
+
touch or a narrow viewport), the row's own secondary ones in
|
|
2833
|
+
its ⋯ menu. */
|
|
2834
|
+
actions: (0, optionActions_1.optionRowActions)({
|
|
2835
|
+
injected: (0, optionActions_1.resolveOptionActions)(optionActions, {
|
|
2836
|
+
name: optionName,
|
|
2837
|
+
schema: options[optionName],
|
|
2838
|
+
value: availableOptions === null || availableOptions === void 0 ? void 0 : availableOptions[optionName],
|
|
2839
|
+
}).filter(function (action) { return action.show !== false; }),
|
|
2840
|
+
collapse: collapseOptionActions,
|
|
2841
|
+
menu: [
|
|
2842
|
+
!readOnly &&
|
|
2329
2843
|
type !== 'code-editor' &&
|
|
2330
2844
|
(((_m = options[optionName]) === null || _m === void 0 ? void 0 : _m.ui_type) || ((_o = options[optionName]) === null || _o === void 0 ? void 0 : _o.type)) !==
|
|
2331
|
-
'code-editor'
|
|
2332
|
-
'
|
|
2333
|
-
:
|
|
2334
|
-
|
|
2335
|
-
|
|
2336
|
-
|
|
2337
|
-
|
|
2338
|
-
|
|
2339
|
-
|
|
2340
|
-
|
|
2341
|
-
|
|
2845
|
+
'code-editor' && {
|
|
2846
|
+
label: 'Focused editing',
|
|
2847
|
+
icon: 'FullscreenLine',
|
|
2848
|
+
className: 'options-item-fullscreen',
|
|
2849
|
+
onClick: function () { return setFocusedEditing(optionName); },
|
|
2850
|
+
},
|
|
2851
|
+
!readOnly &&
|
|
2852
|
+
hasOptionChanged(other.value, optionName) && {
|
|
2853
|
+
label: 'Revert changes',
|
|
2854
|
+
icon: 'HistoryLine',
|
|
2855
|
+
className: 'options-item-revert',
|
|
2856
|
+
onClick: function () {
|
|
2857
|
+
var _a, _b, _c, _d;
|
|
2858
|
+
handleValueChange(optionName, (_b = (_a = originalValue.current) === null || _a === void 0 ? void 0 : _a[optionName]) === null || _b === void 0 ? void 0 : _b.value, (_d = (_c = originalValue.current) === null || _c === void 0 ? void 0 : _c[optionName]) === null || _d === void 0 ? void 0 : _d.type);
|
|
2859
|
+
},
|
|
2860
|
+
},
|
|
2861
|
+
!readOnly &&
|
|
2342
2862
|
other.value &&
|
|
2343
2863
|
!(0, lodash_1.isEqual)(other.value, (0, common_1.getDefaultValue)(options[optionName])) &&
|
|
2344
|
-
!(((_p = options[optionName]) === null || _p === void 0 ? void 0 : _p.disabled) || ((_q = options[optionName]) === null || _q === void 0 ? void 0 : _q.readonly))
|
|
2345
|
-
'
|
|
2346
|
-
:
|
|
2347
|
-
|
|
2348
|
-
|
|
2349
|
-
{
|
|
2350
|
-
size: 'tiny',
|
|
2351
|
-
icon: 'HistoryLine',
|
|
2352
|
-
className: 'options-item-revert',
|
|
2353
|
-
tooltip: 'Revert Changes',
|
|
2354
|
-
show: !readOnly && hasOptionChanged(other.value, optionName) ?
|
|
2355
|
-
'hover'
|
|
2356
|
-
: false,
|
|
2357
|
-
onClick: function () {
|
|
2358
|
-
var _a, _b, _c, _d;
|
|
2359
|
-
handleValueChange(optionName, (_b = (_a = originalValue.current) === null || _a === void 0 ? void 0 : _a[optionName]) === null || _b === void 0 ? void 0 : _b.value, (_d = (_c = originalValue.current) === null || _c === void 0 ? void 0 : _c[optionName]) === null || _d === void 0 ? void 0 : _d.type);
|
|
2864
|
+
!(((_p = options[optionName]) === null || _p === void 0 ? void 0 : _p.disabled) || ((_q = options[optionName]) === null || _q === void 0 ? void 0 : _q.readonly)) && {
|
|
2865
|
+
label: 'Remove value',
|
|
2866
|
+
icon: 'CloseLine',
|
|
2867
|
+
className: 'options-item-remove',
|
|
2868
|
+
onClick: function () { return handleValueChange(optionName, undefined); },
|
|
2360
2869
|
},
|
|
2361
|
-
|
|
2362
|
-
{
|
|
2363
|
-
size: 'tiny',
|
|
2364
|
-
icon: 'DeleteBinLine',
|
|
2365
|
-
intent: 'danger',
|
|
2366
|
-
minimal: true,
|
|
2367
|
-
className: 'options-optional-remove',
|
|
2368
|
-
show: (!readOnly &&
|
|
2870
|
+
!readOnly &&
|
|
2369
2871
|
!((_r = options[optionName]) === null || _r === void 0 ? void 0 : _r.preselected) &&
|
|
2370
|
-
!((_s = options[optionName]) === null || _s === void 0 ? void 0 : _s.required)
|
|
2371
|
-
'
|
|
2372
|
-
:
|
|
2373
|
-
|
|
2374
|
-
|
|
2375
|
-
|
|
2376
|
-
|
|
2377
|
-
|
|
2378
|
-
|
|
2379
|
-
|
|
2872
|
+
!((_s = options[optionName]) === null || _s === void 0 ? void 0 : _s.required) && {
|
|
2873
|
+
label: 'Remove option',
|
|
2874
|
+
icon: 'DeleteBinLine',
|
|
2875
|
+
intent: 'danger',
|
|
2876
|
+
className: 'options-optional-remove',
|
|
2877
|
+
onClick: function () {
|
|
2878
|
+
confirmAction({
|
|
2879
|
+
title: 'Remove Selected Option',
|
|
2880
|
+
onConfirm: function () {
|
|
2881
|
+
removeSelectedOption(optionName);
|
|
2882
|
+
},
|
|
2883
|
+
});
|
|
2884
|
+
},
|
|
2380
2885
|
},
|
|
2381
|
-
|
|
2382
|
-
|
|
2886
|
+
],
|
|
2887
|
+
}),
|
|
2383
2888
|
content: ((0, jsx_runtime_1.jsxs)(FocusedEditing_1.FocusedEditing, { isFullscreen: focusedEditing === optionName, onClose: function () { return setFocusedEditing(undefined); }, description: (_t = options[optionName]) === null || _t === void 0 ? void 0 : _t.display_name, intent: getIntent(optionName, type, other.value, other.op), children: [focusedEditing === optionName ?
|
|
2384
2889
|
(0, jsx_runtime_1.jsx)(Description_1.Description, { longDescription: (_u = options[optionName]) === null || _u === void 0 ? void 0 : _u.desc, shortDescription: (_v = options[optionName]) === null || _v === void 0 ? void 0 : _v.short_desc, longDescriptionShownByDefault: true })
|
|
2385
2890
|
: null, renderOption(optionName, __assign({ type: type }, other))] })),
|