From f967739f7ae7b58b59c59f6e952bed27590559ad Mon Sep 17 00:00:00 2001 From: Marta Bondyra <marta.bondyra@elastic.co> Date: Mon, 24 Feb 2020 17:42:34 +0100 Subject: [PATCH] Advanced settings UI change to centralize save state (#53693) --- .../advanced_settings/public/_index.scss | 2 +- .../public/management_app/_index.scss | 3 + .../management_app/advanced_settings.scss | 40 +- .../management_app/advanced_settings.tsx | 16 +- .../management_app/components/_index.scss | 1 + .../field/__snapshots__/field.test.tsx.snap | 7069 ++++++++--------- .../components/field/field.test.tsx | 267 +- .../management_app/components/field/field.tsx | 545 +- .../management_app/components/field/index.ts | 2 +- .../form/__snapshots__/form.test.tsx.snap | 1228 ++- .../management_app/components/form/_form.scss | 13 + .../components/form/_index.scss | 1 + .../components/form/form.test.tsx | 114 +- .../management_app/components/form/form.tsx | 280 +- .../public/management_app/types.ts | 13 + .../telemetry_management_section.tsx | 54 +- test/functional/page_objects/settings_page.ts | 6 +- .../translations/translations/ja-JP.json | 11 - .../translations/translations/zh-CN.json | 10 - 19 files changed, 5086 insertions(+), 4589 deletions(-) create mode 100644 src/plugins/advanced_settings/public/management_app/_index.scss create mode 100644 src/plugins/advanced_settings/public/management_app/components/_index.scss create mode 100644 src/plugins/advanced_settings/public/management_app/components/form/_form.scss create mode 100644 src/plugins/advanced_settings/public/management_app/components/form/_index.scss diff --git a/src/plugins/advanced_settings/public/_index.scss b/src/plugins/advanced_settings/public/_index.scss index f3fe78bf6a9c0..d13c37bff32d0 100644 --- a/src/plugins/advanced_settings/public/_index.scss +++ b/src/plugins/advanced_settings/public/_index.scss @@ -17,4 +17,4 @@ * under the License. */ - @import './management_app/advanced_settings'; +@import './management_app/index'; diff --git a/src/plugins/advanced_settings/public/management_app/_index.scss b/src/plugins/advanced_settings/public/management_app/_index.scss new file mode 100644 index 0000000000000..aa1980692f7b7 --- /dev/null +++ b/src/plugins/advanced_settings/public/management_app/_index.scss @@ -0,0 +1,3 @@ +@import './advanced_settings'; + +@import './components/index'; diff --git a/src/plugins/advanced_settings/public/management_app/advanced_settings.scss b/src/plugins/advanced_settings/public/management_app/advanced_settings.scss index 79b6feccb6b7d..016edb2817da8 100644 --- a/src/plugins/advanced_settings/public/management_app/advanced_settings.scss +++ b/src/plugins/advanced_settings/public/management_app/advanced_settings.scss @@ -17,21 +17,27 @@ * under the License. */ -.mgtAdvancedSettings__field { + .mgtAdvancedSettings__field { + * { margin-top: $euiSize; } - &Wrapper { - width: 640px; - @include internetExplorerOnly() { - min-height: 1px; - } + padding-left: $euiSizeS; + margin-left: -$euiSizeS; + &--unsaved { + // Simulates a left side border without shifting content + box-shadow: -$euiSizeXS 0px $euiColorSecondary; } - - &Actions { - padding-top: $euiSizeM; + &--invalid { + // Simulates a left side border without shifting content + box-shadow: -$euiSizeXS 0px $euiColorDanger; + } + @include internetExplorerOnly() { + min-height: 1px; + } + &Row { + padding-left: $euiSizeS; } @include internetExplorerOnly { @@ -40,3 +46,19 @@ } } } + +.mgtAdvancedSettingsForm__unsavedCount { + @include euiBreakpoint('xs', 's') { + display: none; + } +} + +.mgtAdvancedSettingsForm__unsavedCountMessage{ + // Simulates a left side border without shifting content + box-shadow: -$euiSizeXS 0px $euiColorSecondary; + padding-left: $euiSizeS; +} + +.mgtAdvancedSettingsForm__button { + width: 100%; +} diff --git a/src/plugins/advanced_settings/public/management_app/advanced_settings.tsx b/src/plugins/advanced_settings/public/management_app/advanced_settings.tsx index 5057d072e3e41..39312c9340ff9 100644 --- a/src/plugins/advanced_settings/public/management_app/advanced_settings.tsx +++ b/src/plugins/advanced_settings/public/management_app/advanced_settings.tsx @@ -38,7 +38,7 @@ import { ComponentRegistry } from '../'; import { getAriaName, toEditableConfig, DEFAULT_CATEGORY } from './lib'; -import { FieldSetting, IQuery } from './types'; +import { FieldSetting, IQuery, SettingsChanges } from './types'; interface AdvancedSettingsProps { enableSaving: boolean; @@ -177,6 +177,13 @@ export class AdvancedSettingsComponent extends Component< }); }; + saveConfig = async (changes: SettingsChanges) => { + const arr = Object.entries(changes).map(([key, value]) => + this.props.uiSettings.set(key, value) + ); + return Promise.all(arr); + }; + render() { const { filteredSettings, query, footerQueryMatched } = this.state; const componentRegistry = this.props.componentRegistry; @@ -205,18 +212,19 @@ export class AdvancedSettingsComponent extends Component< <AdvancedSettingsVoiceAnnouncement queryText={query.text} settings={filteredSettings} /> <Form - settings={filteredSettings} + settings={this.groupedSettings} + visibleSettings={filteredSettings} categories={this.categories} categoryCounts={this.categoryCounts} clearQuery={this.clearQuery} - save={this.props.uiSettings.set.bind(this.props.uiSettings)} - clear={this.props.uiSettings.remove.bind(this.props.uiSettings)} + save={this.saveConfig} showNoResultsMessage={!footerQueryMatched} enableSaving={this.props.enableSaving} dockLinks={this.props.dockLinks} toasts={this.props.toasts} /> <PageFooter + toasts={this.props.toasts} query={query} onQueryMatchChange={this.onFooterQueryMatchChange} enableSaving={this.props.enableSaving} diff --git a/src/plugins/advanced_settings/public/management_app/components/_index.scss b/src/plugins/advanced_settings/public/management_app/components/_index.scss new file mode 100644 index 0000000000000..d2d2e38947f76 --- /dev/null +++ b/src/plugins/advanced_settings/public/management_app/components/_index.scss @@ -0,0 +1 @@ +@import './form/index'; diff --git a/src/plugins/advanced_settings/public/management_app/components/field/__snapshots__/field.test.tsx.snap b/src/plugins/advanced_settings/public/management_app/components/field/__snapshots__/field.test.tsx.snap index 5121785b05cad..2f4d806e60244 100644 --- a/src/plugins/advanced_settings/public/management_app/components/field/__snapshots__/field.test.tsx.snap +++ b/src/plugins/advanced_settings/public/management_app/components/field/__snapshots__/field.test.tsx.snap @@ -1,3912 +1,3821 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP exports[`Field for array setting should render as read only if saving is disabled 1`] = ` -<EuiFlexGroup +<EuiDescribedFormGroup className="mgtAdvancedSettings__field" + description={ + <React.Fragment> + <div + dangerouslySetInnerHTML={ + Object { + "__html": "Description for Array test setting", + } + } + /> + </React.Fragment> + } + fullWidth={true} + title={ + <h3> + Array test setting + + </h3> + } > - <EuiFlexItem - grow={false} + <EuiFormRow + className="mgtAdvancedSettings__fieldRow" + describedByIds={Array []} + display="row" + fullWidth={true} + hasChildLabel={true} + hasEmptyLabelSpace={false} + helpText={null} + label="array:test:setting" + labelType="label" > - <EuiDescribedFormGroup - className="mgtAdvancedSettings__fieldWrapper" - description={ - <React.Fragment> - <div - dangerouslySetInnerHTML={ - Object { - "__html": "Description for Array test setting", - } - } - /> - </React.Fragment> - } - title={ - <h3> - Array test setting - - </h3> - } - > - <EuiFormRow - className="mgtAdvancedSettings__fieldRow" - describedByIds={ - Array [ - "array:test:setting-aria", - ] - } - display="row" - error={null} - fullWidth={false} - hasChildLabel={true} - hasEmptyLabelSpace={false} - helpText={null} - isInvalid={false} - label="array:test:setting" - labelType="label" - > - <EuiFieldText - aria-label="array test setting" - data-test-subj="advancedSetting-editField-array:test:setting" - disabled={true} - isLoading={false} - onChange={[Function]} - onKeyDown={[Function]} - value="default_value" - /> - </EuiFormRow> - </EuiDescribedFormGroup> - </EuiFlexItem> - <EuiFlexItem - grow={false} - /> -</EuiFlexGroup> + <EuiFieldText + aria-label="array test setting" + data-test-subj="advancedSetting-editField-array:test:setting" + disabled={true} + fullWidth={true} + onChange={[Function]} + value="default_value" + /> + </EuiFormRow> +</EuiDescribedFormGroup> `; exports[`Field for array setting should render as read only with help text if overridden 1`] = ` -<EuiFlexGroup +<EuiDescribedFormGroup className="mgtAdvancedSettings__field" -> - <EuiFlexItem - grow={false} - > - <EuiDescribedFormGroup - className="mgtAdvancedSettings__fieldWrapper" - description={ - <React.Fragment> - <div - dangerouslySetInnerHTML={ - Object { - "__html": "Description for Array test setting", - } - } - /> + description={ + <React.Fragment> + <div + dangerouslySetInnerHTML={ + Object { + "__html": "Description for Array test setting", + } + } + /> + <React.Fragment> + <EuiSpacer + size="s" + /> + <EuiText + size="xs" + > <React.Fragment> - <EuiSpacer - size="s" - /> - <EuiText - size="xs" - > - <React.Fragment> - <FormattedMessage - defaultMessage="Default: {value}" - id="advancedSettings.field.defaultValueText" - values={ - Object { - "value": <EuiCode> - default_value - </EuiCode>, - } - } - /> - </React.Fragment> - </EuiText> - </React.Fragment> - </React.Fragment> - } - title={ - <h3> - Array test setting - - </h3> - } - > - <EuiFormRow - className="mgtAdvancedSettings__fieldRow" - describedByIds={ - Array [ - "array:test:setting-aria", - ] - } - display="row" - error={null} - fullWidth={false} - hasChildLabel={true} - hasEmptyLabelSpace={false} - helpText={ - <EuiText - size="xs" - > <FormattedMessage - defaultMessage="This setting is overridden by the Kibana server and can not be changed." - id="advancedSettings.field.helpText" - values={Object {}} + defaultMessage="Default: {value}" + id="advancedSettings.field.defaultValueText" + values={ + Object { + "value": <EuiCode> + default_value + </EuiCode>, + } + } /> - </EuiText> - } - isInvalid={false} - label="array:test:setting" - labelType="label" + </React.Fragment> + </EuiText> + </React.Fragment> + </React.Fragment> + } + fullWidth={true} + title={ + <h3> + Array test setting + + </h3> + } +> + <EuiFormRow + className="mgtAdvancedSettings__fieldRow" + describedByIds={Array []} + display="row" + fullWidth={true} + hasChildLabel={true} + hasEmptyLabelSpace={false} + helpText={ + <EuiText + size="xs" > - <EuiFieldText - aria-label="array test setting" - data-test-subj="advancedSetting-editField-array:test:setting" - disabled={true} - isLoading={false} - onChange={[Function]} - onKeyDown={[Function]} - value="user, value" + <FormattedMessage + defaultMessage="This setting is overridden by the Kibana server and can not be changed." + id="advancedSettings.field.helpText" + values={Object {}} /> - </EuiFormRow> - </EuiDescribedFormGroup> - </EuiFlexItem> - <EuiFlexItem - grow={false} - /> -</EuiFlexGroup> + </EuiText> + } + label="array:test:setting" + labelType="label" + > + <EuiFieldText + aria-label="array test setting" + data-test-subj="advancedSetting-editField-array:test:setting" + disabled={true} + fullWidth={true} + onChange={[Function]} + value="user, value" + /> + </EuiFormRow> +</EuiDescribedFormGroup> `; exports[`Field for array setting should render custom setting icon if it is custom 1`] = ` -<EuiFlexGroup +<EuiDescribedFormGroup className="mgtAdvancedSettings__field" + description={ + <React.Fragment> + <div + dangerouslySetInnerHTML={ + Object { + "__html": "Description for Array test setting", + } + } + /> + </React.Fragment> + } + fullWidth={true} + title={ + <h3> + Array test setting + <EuiIconTip + aria-label="Custom setting" + color="primary" + content={ + <FormattedMessage + defaultMessage="Custom setting" + id="advancedSettings.field.customSettingTooltip" + values={Object {}} + /> + } + type="asterisk" + /> + </h3> + } > - <EuiFlexItem - grow={false} + <EuiFormRow + className="mgtAdvancedSettings__fieldRow" + describedByIds={Array []} + display="row" + fullWidth={true} + hasChildLabel={true} + hasEmptyLabelSpace={false} + helpText={null} + label="array:test:setting" + labelType="label" > - <EuiDescribedFormGroup - className="mgtAdvancedSettings__fieldWrapper" - description={ - <React.Fragment> - <div - dangerouslySetInnerHTML={ - Object { - "__html": "Description for Array test setting", - } - } - /> - </React.Fragment> - } - title={ - <h3> - Array test setting - <EuiIconTip - aria-label="Custom setting" - color="primary" - content={ - <FormattedMessage - defaultMessage="Custom setting" - id="advancedSettings.field.customSettingTooltip" - values={Object {}} - /> - } - type="asterisk" - /> - </h3> - } - > - <EuiFormRow - className="mgtAdvancedSettings__fieldRow" - describedByIds={ - Array [ - "array:test:setting-aria", - ] - } - display="row" - error={null} - fullWidth={false} - hasChildLabel={true} - hasEmptyLabelSpace={false} - helpText={null} - isInvalid={false} - label="array:test:setting" - labelType="label" - > - <EuiFieldText - aria-label="array test setting" - data-test-subj="advancedSetting-editField-array:test:setting" - disabled={false} - isLoading={false} - onChange={[Function]} - onKeyDown={[Function]} - value="default_value" - /> - </EuiFormRow> - </EuiDescribedFormGroup> - </EuiFlexItem> - <EuiFlexItem - grow={false} - /> -</EuiFlexGroup> + <EuiFieldText + aria-label="array test setting" + data-test-subj="advancedSetting-editField-array:test:setting" + disabled={false} + fullWidth={true} + onChange={[Function]} + value="default_value" + /> + </EuiFormRow> +</EuiDescribedFormGroup> `; exports[`Field for array setting should render default value if there is no user value set 1`] = ` -<EuiFlexGroup +<EuiDescribedFormGroup className="mgtAdvancedSettings__field" + description={ + <React.Fragment> + <div + dangerouslySetInnerHTML={ + Object { + "__html": "Description for Array test setting", + } + } + /> + </React.Fragment> + } + fullWidth={true} + title={ + <h3> + Array test setting + + </h3> + } > - <EuiFlexItem - grow={false} + <EuiFormRow + className="mgtAdvancedSettings__fieldRow" + describedByIds={Array []} + display="row" + fullWidth={true} + hasChildLabel={true} + hasEmptyLabelSpace={false} + helpText={null} + label="array:test:setting" + labelType="label" > - <EuiDescribedFormGroup - className="mgtAdvancedSettings__fieldWrapper" - description={ - <React.Fragment> - <div - dangerouslySetInnerHTML={ - Object { - "__html": "Description for Array test setting", - } - } - /> - </React.Fragment> - } - title={ - <h3> - Array test setting - - </h3> - } - > - <EuiFormRow - className="mgtAdvancedSettings__fieldRow" - describedByIds={ - Array [ - "array:test:setting-aria", - ] - } - display="row" - error={null} - fullWidth={false} - hasChildLabel={true} - hasEmptyLabelSpace={false} - helpText={null} - isInvalid={false} - label="array:test:setting" - labelType="label" + <EuiFieldText + aria-label="array test setting" + data-test-subj="advancedSetting-editField-array:test:setting" + disabled={false} + fullWidth={true} + onChange={[Function]} + value="default_value" + /> + </EuiFormRow> +</EuiDescribedFormGroup> +`; + +exports[`Field for array setting should render unsaved value if there are unsaved changes 1`] = ` +<EuiDescribedFormGroup + className="mgtAdvancedSettings__field mgtAdvancedSettings__field--unsaved" + description={ + <React.Fragment> + <div + dangerouslySetInnerHTML={ + Object { + "__html": "Description for Array test setting", + } + } + /> + </React.Fragment> + } + fullWidth={true} + title={ + <h3> + Array test setting + <EuiIconTip + aria-label="Custom setting" + color="primary" + content={ + <FormattedMessage + defaultMessage="Custom setting" + id="advancedSettings.field.customSettingTooltip" + values={Object {}} + /> + } + type="asterisk" + /> + </h3> + } +> + <EuiFormRow + className="mgtAdvancedSettings__fieldRow" + describedByIds={Array []} + display="row" + fullWidth={true} + hasChildLabel={true} + hasEmptyLabelSpace={false} + helpText={null} + label="array:test:setting" + labelType="label" + > + <EuiFieldText + aria-describedby="array:test:setting" + aria-label="array test setting" + data-test-subj="advancedSetting-editField-array:test:setting" + disabled={false} + fullWidth={true} + onChange={[Function]} + value={ + Array [ + "example_value", + ] + } + /> + <EuiScreenReaderOnly> + <p + id="array:test:setting" > - <EuiFieldText - aria-label="array test setting" - data-test-subj="advancedSetting-editField-array:test:setting" - disabled={false} - isLoading={false} - onChange={[Function]} - onKeyDown={[Function]} - value="default_value" - /> - </EuiFormRow> - </EuiDescribedFormGroup> - </EuiFlexItem> - <EuiFlexItem - grow={false} - /> -</EuiFlexGroup> + Setting is currently not saved. + </p> + </EuiScreenReaderOnly> + </EuiFormRow> +</EuiDescribedFormGroup> `; exports[`Field for array setting should render user value if there is user value is set 1`] = ` -<EuiFlexGroup +<EuiDescribedFormGroup className="mgtAdvancedSettings__field" -> - <EuiFlexItem - grow={false} - > - <EuiDescribedFormGroup - className="mgtAdvancedSettings__fieldWrapper" - description={ - <React.Fragment> - <div - dangerouslySetInnerHTML={ - Object { - "__html": "Description for Array test setting", - } - } - /> + description={ + <React.Fragment> + <div + dangerouslySetInnerHTML={ + Object { + "__html": "Description for Array test setting", + } + } + /> + <React.Fragment> + <EuiSpacer + size="s" + /> + <EuiText + size="xs" + > <React.Fragment> - <EuiSpacer - size="s" + <FormattedMessage + defaultMessage="Default: {value}" + id="advancedSettings.field.defaultValueText" + values={ + Object { + "value": <EuiCode> + default_value + </EuiCode>, + } + } /> - <EuiText - size="xs" - > - <React.Fragment> - <FormattedMessage - defaultMessage="Default: {value}" - id="advancedSettings.field.defaultValueText" - values={ - Object { - "value": <EuiCode> - default_value - </EuiCode>, - } - } - /> - </React.Fragment> - </EuiText> </React.Fragment> - </React.Fragment> - } - title={ - <h3> - Array test setting - - </h3> - } - > - <EuiFormRow - className="mgtAdvancedSettings__fieldRow" - describedByIds={ - Array [ - "array:test:setting-aria", - ] - } - display="row" - error={null} - fullWidth={false} - hasChildLabel={true} - hasEmptyLabelSpace={false} - helpText={ - <span> - <span> - <ForwardRef - aria-label="Reset array test setting to default" - data-test-subj="advancedSetting-resetField-array:test:setting" - onClick={[Function]} - > - <FormattedMessage - defaultMessage="Reset to default" - id="advancedSettings.field.resetToDefaultLinkText" - values={Object {}} - /> - </ForwardRef> - - </span> - </span> - } - isInvalid={false} - label="array:test:setting" - labelType="label" - > - <EuiFieldText - aria-label="array test setting" - data-test-subj="advancedSetting-editField-array:test:setting" - disabled={false} - isLoading={false} - onChange={[Function]} - onKeyDown={[Function]} - value="user, value" - /> - </EuiFormRow> - </EuiDescribedFormGroup> - </EuiFlexItem> - <EuiFlexItem - grow={false} - /> -</EuiFlexGroup> + </EuiText> + </React.Fragment> + </React.Fragment> + } + fullWidth={true} + title={ + <h3> + Array test setting + + </h3> + } +> + <EuiFormRow + className="mgtAdvancedSettings__fieldRow" + describedByIds={Array []} + display="row" + fullWidth={true} + hasChildLabel={true} + hasEmptyLabelSpace={false} + helpText={ + <span> + <span> + <ForwardRef + aria-label="Reset array test setting to default" + data-test-subj="advancedSetting-resetField-array:test:setting" + onClick={[Function]} + > + <FormattedMessage + defaultMessage="Reset to default" + id="advancedSettings.field.resetToDefaultLinkText" + values={Object {}} + /> + </ForwardRef> + + </span> + </span> + } + label="array:test:setting" + labelType="label" + > + <EuiFieldText + aria-label="array test setting" + data-test-subj="advancedSetting-editField-array:test:setting" + disabled={false} + fullWidth={true} + onChange={[Function]} + value="user, value" + /> + </EuiFormRow> +</EuiDescribedFormGroup> `; exports[`Field for boolean setting should render as read only if saving is disabled 1`] = ` -<EuiFlexGroup +<EuiDescribedFormGroup className="mgtAdvancedSettings__field" + description={ + <React.Fragment> + <div + dangerouslySetInnerHTML={ + Object { + "__html": "Description for Boolean test setting", + } + } + /> + </React.Fragment> + } + fullWidth={true} + title={ + <h3> + Boolean test setting + + </h3> + } > - <EuiFlexItem - grow={false} + <EuiFormRow + className="mgtAdvancedSettings__fieldRow" + describedByIds={Array []} + display="row" + fullWidth={true} + hasChildLabel={false} + hasEmptyLabelSpace={false} + helpText={null} + label="boolean:test:setting" + labelType="label" > - <EuiDescribedFormGroup - className="mgtAdvancedSettings__fieldWrapper" - description={ - <React.Fragment> - <div - dangerouslySetInnerHTML={ - Object { - "__html": "Description for Boolean test setting", - } - } - /> - </React.Fragment> - } - title={ - <h3> - Boolean test setting - - </h3> - } - > - <EuiFormRow - className="mgtAdvancedSettings__fieldRow" - describedByIds={ - Array [ - "boolean:test:setting-aria", - ] - } - display="row" - error={null} - fullWidth={false} - hasChildLabel={false} - hasEmptyLabelSpace={false} - helpText={null} - isInvalid={false} - label="boolean:test:setting" - labelType="label" - > - <EuiSwitch - aria-label="boolean test setting" - checked={true} - data-test-subj="advancedSetting-editField-boolean:test:setting" - disabled={true} - label={ - <FormattedMessage - defaultMessage="On" - id="advancedSettings.field.onLabel" - values={Object {}} - /> - } - onChange={[Function]} - onKeyDown={[Function]} + <EuiSwitch + aria-label="boolean test setting" + checked={true} + data-test-subj="advancedSetting-editField-boolean:test:setting" + disabled={true} + label={ + <FormattedMessage + defaultMessage="On" + id="advancedSettings.field.onLabel" + values={Object {}} /> - </EuiFormRow> - </EuiDescribedFormGroup> - </EuiFlexItem> - <EuiFlexItem - grow={false} - /> -</EuiFlexGroup> + } + onChange={[Function]} + /> + </EuiFormRow> +</EuiDescribedFormGroup> `; exports[`Field for boolean setting should render as read only with help text if overridden 1`] = ` -<EuiFlexGroup +<EuiDescribedFormGroup className="mgtAdvancedSettings__field" -> - <EuiFlexItem - grow={false} - > - <EuiDescribedFormGroup - className="mgtAdvancedSettings__fieldWrapper" - description={ - <React.Fragment> - <div - dangerouslySetInnerHTML={ - Object { - "__html": "Description for Boolean test setting", - } - } - /> + description={ + <React.Fragment> + <div + dangerouslySetInnerHTML={ + Object { + "__html": "Description for Boolean test setting", + } + } + /> + <React.Fragment> + <EuiSpacer + size="s" + /> + <EuiText + size="xs" + > <React.Fragment> - <EuiSpacer - size="s" - /> - <EuiText - size="xs" - > - <React.Fragment> - <FormattedMessage - defaultMessage="Default: {value}" - id="advancedSettings.field.defaultValueText" - values={ - Object { - "value": <EuiCode> - true - </EuiCode>, - } - } - /> - </React.Fragment> - </EuiText> - </React.Fragment> - </React.Fragment> - } - title={ - <h3> - Boolean test setting - - </h3> - } - > - <EuiFormRow - className="mgtAdvancedSettings__fieldRow" - describedByIds={ - Array [ - "boolean:test:setting-aria", - ] - } - display="row" - error={null} - fullWidth={false} - hasChildLabel={false} - hasEmptyLabelSpace={false} - helpText={ - <EuiText - size="xs" - > <FormattedMessage - defaultMessage="This setting is overridden by the Kibana server and can not be changed." - id="advancedSettings.field.helpText" - values={Object {}} + defaultMessage="Default: {value}" + id="advancedSettings.field.defaultValueText" + values={ + Object { + "value": <EuiCode> + true + </EuiCode>, + } + } /> - </EuiText> - } - isInvalid={false} - label="boolean:test:setting" - labelType="label" + </React.Fragment> + </EuiText> + </React.Fragment> + </React.Fragment> + } + fullWidth={true} + title={ + <h3> + Boolean test setting + + </h3> + } +> + <EuiFormRow + className="mgtAdvancedSettings__fieldRow" + describedByIds={Array []} + display="row" + fullWidth={true} + hasChildLabel={false} + hasEmptyLabelSpace={false} + helpText={ + <EuiText + size="xs" > - <EuiSwitch - aria-label="boolean test setting" - checked={false} - data-test-subj="advancedSetting-editField-boolean:test:setting" - disabled={true} - label={ - <FormattedMessage - defaultMessage="Off" - id="advancedSettings.field.offLabel" - values={Object {}} - /> - } - onChange={[Function]} - onKeyDown={[Function]} + <FormattedMessage + defaultMessage="This setting is overridden by the Kibana server and can not be changed." + id="advancedSettings.field.helpText" + values={Object {}} + /> + </EuiText> + } + label="boolean:test:setting" + labelType="label" + > + <EuiSwitch + aria-label="boolean test setting" + checked={false} + data-test-subj="advancedSetting-editField-boolean:test:setting" + disabled={true} + label={ + <FormattedMessage + defaultMessage="Off" + id="advancedSettings.field.offLabel" + values={Object {}} /> - </EuiFormRow> - </EuiDescribedFormGroup> - </EuiFlexItem> - <EuiFlexItem - grow={false} - /> -</EuiFlexGroup> + } + onChange={[Function]} + /> + </EuiFormRow> +</EuiDescribedFormGroup> `; exports[`Field for boolean setting should render custom setting icon if it is custom 1`] = ` -<EuiFlexGroup +<EuiDescribedFormGroup className="mgtAdvancedSettings__field" + description={ + <React.Fragment> + <div + dangerouslySetInnerHTML={ + Object { + "__html": "Description for Boolean test setting", + } + } + /> + </React.Fragment> + } + fullWidth={true} + title={ + <h3> + Boolean test setting + <EuiIconTip + aria-label="Custom setting" + color="primary" + content={ + <FormattedMessage + defaultMessage="Custom setting" + id="advancedSettings.field.customSettingTooltip" + values={Object {}} + /> + } + type="asterisk" + /> + </h3> + } > - <EuiFlexItem - grow={false} + <EuiFormRow + className="mgtAdvancedSettings__fieldRow" + describedByIds={Array []} + display="row" + fullWidth={true} + hasChildLabel={false} + hasEmptyLabelSpace={false} + helpText={null} + label="boolean:test:setting" + labelType="label" > - <EuiDescribedFormGroup - className="mgtAdvancedSettings__fieldWrapper" - description={ - <React.Fragment> - <div - dangerouslySetInnerHTML={ - Object { - "__html": "Description for Boolean test setting", - } - } - /> - </React.Fragment> - } - title={ - <h3> - Boolean test setting - <EuiIconTip - aria-label="Custom setting" - color="primary" - content={ - <FormattedMessage - defaultMessage="Custom setting" - id="advancedSettings.field.customSettingTooltip" - values={Object {}} - /> - } - type="asterisk" - /> - </h3> - } - > - <EuiFormRow - className="mgtAdvancedSettings__fieldRow" - describedByIds={ - Array [ - "boolean:test:setting-aria", - ] - } - display="row" - error={null} - fullWidth={false} - hasChildLabel={false} - hasEmptyLabelSpace={false} - helpText={null} - isInvalid={false} - label="boolean:test:setting" - labelType="label" - > - <EuiSwitch - aria-label="boolean test setting" - checked={true} - data-test-subj="advancedSetting-editField-boolean:test:setting" - disabled={false} - label={ - <FormattedMessage - defaultMessage="On" - id="advancedSettings.field.onLabel" - values={Object {}} - /> - } - onChange={[Function]} - onKeyDown={[Function]} + <EuiSwitch + aria-label="boolean test setting" + checked={true} + data-test-subj="advancedSetting-editField-boolean:test:setting" + disabled={false} + label={ + <FormattedMessage + defaultMessage="On" + id="advancedSettings.field.onLabel" + values={Object {}} /> - </EuiFormRow> - </EuiDescribedFormGroup> - </EuiFlexItem> - <EuiFlexItem - grow={false} - /> -</EuiFlexGroup> + } + onChange={[Function]} + /> + </EuiFormRow> +</EuiDescribedFormGroup> `; exports[`Field for boolean setting should render default value if there is no user value set 1`] = ` -<EuiFlexGroup +<EuiDescribedFormGroup className="mgtAdvancedSettings__field" + description={ + <React.Fragment> + <div + dangerouslySetInnerHTML={ + Object { + "__html": "Description for Boolean test setting", + } + } + /> + </React.Fragment> + } + fullWidth={true} + title={ + <h3> + Boolean test setting + + </h3> + } > - <EuiFlexItem - grow={false} + <EuiFormRow + className="mgtAdvancedSettings__fieldRow" + describedByIds={Array []} + display="row" + fullWidth={true} + hasChildLabel={false} + hasEmptyLabelSpace={false} + helpText={null} + label="boolean:test:setting" + labelType="label" > - <EuiDescribedFormGroup - className="mgtAdvancedSettings__fieldWrapper" - description={ - <React.Fragment> - <div - dangerouslySetInnerHTML={ - Object { - "__html": "Description for Boolean test setting", - } - } - /> - </React.Fragment> - } - title={ - <h3> - Boolean test setting - - </h3> + <EuiSwitch + aria-label="boolean test setting" + checked={true} + data-test-subj="advancedSetting-editField-boolean:test:setting" + disabled={false} + label={ + <FormattedMessage + defaultMessage="On" + id="advancedSettings.field.onLabel" + values={Object {}} + /> } - > - <EuiFormRow - className="mgtAdvancedSettings__fieldRow" - describedByIds={ - Array [ - "boolean:test:setting-aria", - ] - } - display="row" - error={null} - fullWidth={false} - hasChildLabel={false} - hasEmptyLabelSpace={false} - helpText={null} - isInvalid={false} - label="boolean:test:setting" - labelType="label" - > - <EuiSwitch - aria-label="boolean test setting" - checked={true} - data-test-subj="advancedSetting-editField-boolean:test:setting" - disabled={false} - label={ - <FormattedMessage - defaultMessage="On" - id="advancedSettings.field.onLabel" - values={Object {}} - /> + onChange={[Function]} + /> + </EuiFormRow> +</EuiDescribedFormGroup> +`; + +exports[`Field for boolean setting should render unsaved value if there are unsaved changes 1`] = ` +<EuiDescribedFormGroup + className="mgtAdvancedSettings__field mgtAdvancedSettings__field--unsaved" + description={ + <React.Fragment> + <div + dangerouslySetInnerHTML={ + Object { + "__html": "Description for Boolean test setting", } - onChange={[Function]} - onKeyDown={[Function]} + } + /> + </React.Fragment> + } + fullWidth={true} + title={ + <h3> + Boolean test setting + <EuiIconTip + aria-label="Custom setting" + color="primary" + content={ + <FormattedMessage + defaultMessage="Custom setting" + id="advancedSettings.field.customSettingTooltip" + values={Object {}} + /> + } + type="asterisk" + /> + </h3> + } +> + <EuiFormRow + className="mgtAdvancedSettings__fieldRow" + describedByIds={Array []} + display="row" + fullWidth={true} + hasChildLabel={false} + hasEmptyLabelSpace={false} + helpText={null} + label="boolean:test:setting" + labelType="label" + > + <EuiSwitch + aria-describedby="boolean:test:setting" + aria-label="boolean test setting" + checked={false} + data-test-subj="advancedSetting-editField-boolean:test:setting" + disabled={false} + label={ + <FormattedMessage + defaultMessage="Off" + id="advancedSettings.field.offLabel" + values={Object {}} /> - </EuiFormRow> - </EuiDescribedFormGroup> - </EuiFlexItem> - <EuiFlexItem - grow={false} - /> -</EuiFlexGroup> + } + onChange={[Function]} + /> + <EuiScreenReaderOnly> + <p + id="boolean:test:setting" + > + Setting is currently not saved. + </p> + </EuiScreenReaderOnly> + </EuiFormRow> +</EuiDescribedFormGroup> `; exports[`Field for boolean setting should render user value if there is user value is set 1`] = ` -<EuiFlexGroup +<EuiDescribedFormGroup className="mgtAdvancedSettings__field" -> - <EuiFlexItem - grow={false} - > - <EuiDescribedFormGroup - className="mgtAdvancedSettings__fieldWrapper" - description={ - <React.Fragment> - <div - dangerouslySetInnerHTML={ - Object { - "__html": "Description for Boolean test setting", - } - } - /> + description={ + <React.Fragment> + <div + dangerouslySetInnerHTML={ + Object { + "__html": "Description for Boolean test setting", + } + } + /> + <React.Fragment> + <EuiSpacer + size="s" + /> + <EuiText + size="xs" + > <React.Fragment> - <EuiSpacer - size="s" + <FormattedMessage + defaultMessage="Default: {value}" + id="advancedSettings.field.defaultValueText" + values={ + Object { + "value": <EuiCode> + true + </EuiCode>, + } + } /> - <EuiText - size="xs" - > - <React.Fragment> - <FormattedMessage - defaultMessage="Default: {value}" - id="advancedSettings.field.defaultValueText" - values={ - Object { - "value": <EuiCode> - true - </EuiCode>, - } - } - /> - </React.Fragment> - </EuiText> </React.Fragment> - </React.Fragment> - } - title={ - <h3> - Boolean test setting - - </h3> - } - > - <EuiFormRow - className="mgtAdvancedSettings__fieldRow" - describedByIds={ - Array [ - "boolean:test:setting-aria", - ] - } - display="row" - error={null} - fullWidth={false} - hasChildLabel={false} - hasEmptyLabelSpace={false} - helpText={ - <span> - <span> - <ForwardRef - aria-label="Reset boolean test setting to default" - data-test-subj="advancedSetting-resetField-boolean:test:setting" - onClick={[Function]} - > - <FormattedMessage - defaultMessage="Reset to default" - id="advancedSettings.field.resetToDefaultLinkText" - values={Object {}} - /> - </ForwardRef> - - </span> - </span> - } - isInvalid={false} - label="boolean:test:setting" - labelType="label" - > - <EuiSwitch - aria-label="boolean test setting" - checked={false} - data-test-subj="advancedSetting-editField-boolean:test:setting" - disabled={false} - label={ + </EuiText> + </React.Fragment> + </React.Fragment> + } + fullWidth={true} + title={ + <h3> + Boolean test setting + + </h3> + } +> + <EuiFormRow + className="mgtAdvancedSettings__fieldRow" + describedByIds={Array []} + display="row" + fullWidth={true} + hasChildLabel={false} + hasEmptyLabelSpace={false} + helpText={ + <span> + <span> + <ForwardRef + aria-label="Reset boolean test setting to default" + data-test-subj="advancedSetting-resetField-boolean:test:setting" + onClick={[Function]} + > <FormattedMessage - defaultMessage="Off" - id="advancedSettings.field.offLabel" + defaultMessage="Reset to default" + id="advancedSettings.field.resetToDefaultLinkText" values={Object {}} /> - } - onChange={[Function]} - onKeyDown={[Function]} + </ForwardRef> + + </span> + </span> + } + label="boolean:test:setting" + labelType="label" + > + <EuiSwitch + aria-label="boolean test setting" + checked={false} + data-test-subj="advancedSetting-editField-boolean:test:setting" + disabled={false} + label={ + <FormattedMessage + defaultMessage="Off" + id="advancedSettings.field.offLabel" + values={Object {}} /> - </EuiFormRow> - </EuiDescribedFormGroup> - </EuiFlexItem> - <EuiFlexItem - grow={false} - /> -</EuiFlexGroup> + } + onChange={[Function]} + /> + </EuiFormRow> +</EuiDescribedFormGroup> `; exports[`Field for image setting should render as read only if saving is disabled 1`] = ` -<EuiFlexGroup +<EuiDescribedFormGroup className="mgtAdvancedSettings__field" + description={ + <React.Fragment> + <div + dangerouslySetInnerHTML={ + Object { + "__html": "Description for Image test setting", + } + } + /> + </React.Fragment> + } + fullWidth={true} + title={ + <h3> + Image test setting + + </h3> + } > - <EuiFlexItem - grow={false} + <EuiFormRow + className="mgtAdvancedSettings__fieldRow" + describedByIds={Array []} + display="row" + fullWidth={true} + hasChildLabel={true} + hasEmptyLabelSpace={false} + helpText={null} + label="image:test:setting" + labelType="label" > - <EuiDescribedFormGroup - className="mgtAdvancedSettings__fieldWrapper" - description={ - <React.Fragment> - <div - dangerouslySetInnerHTML={ - Object { - "__html": "Description for Image test setting", - } - } - /> - </React.Fragment> - } - title={ - <h3> - Image test setting - - </h3> - } - > - <EuiFormRow - className="mgtAdvancedSettings__fieldRow" - describedByIds={ - Array [ - "image:test:setting-aria", - ] - } - display="row" - error={null} - fullWidth={false} - hasChildLabel={true} - hasEmptyLabelSpace={false} - helpText={null} - isInvalid={false} - label="image:test:setting" - labelType="label" - > - <EuiFilePicker - accept=".jpg,.jpeg,.png" - compressed={false} - data-test-subj="advancedSetting-editField-image:test:setting" - disabled={true} - display="large" - initialPromptText="Select or drag and drop a file" - onChange={[Function]} - onKeyDown={[Function]} - /> - </EuiFormRow> - </EuiDescribedFormGroup> - </EuiFlexItem> - <EuiFlexItem - grow={false} - /> -</EuiFlexGroup> + <EuiFilePicker + accept=".jpg,.jpeg,.png" + compressed={false} + data-test-subj="advancedSetting-editField-image:test:setting" + disabled={true} + display="large" + fullWidth={true} + initialPromptText="Select or drag and drop a file" + onChange={[Function]} + /> + </EuiFormRow> +</EuiDescribedFormGroup> `; exports[`Field for image setting should render as read only with help text if overridden 1`] = ` -<EuiFlexGroup +<EuiDescribedFormGroup className="mgtAdvancedSettings__field" -> - <EuiFlexItem - grow={false} - > - <EuiDescribedFormGroup - className="mgtAdvancedSettings__fieldWrapper" - description={ - <React.Fragment> - <div - dangerouslySetInnerHTML={ - Object { - "__html": "Description for Image test setting", - } - } - /> + description={ + <React.Fragment> + <div + dangerouslySetInnerHTML={ + Object { + "__html": "Description for Image test setting", + } + } + /> + <React.Fragment> + <EuiSpacer + size="s" + /> + <EuiText + size="xs" + > <React.Fragment> - <EuiSpacer - size="s" - /> - <EuiText - size="xs" - > - <React.Fragment> - <FormattedMessage - defaultMessage="Default: {value}" - id="advancedSettings.field.defaultValueText" - values={ - Object { - "value": <EuiCode> - null - </EuiCode>, - } - } - /> - </React.Fragment> - </EuiText> - </React.Fragment> - </React.Fragment> - } - title={ - <h3> - Image test setting - - </h3> - } - > - <EuiFormRow - className="mgtAdvancedSettings__fieldRow" - describedByIds={ - Array [ - "image:test:setting-aria", - ] - } - display="row" - error={null} - fullWidth={false} - hasChildLabel={true} - hasEmptyLabelSpace={false} - helpText={ - <EuiText - size="xs" - > <FormattedMessage - defaultMessage="This setting is overridden by the Kibana server and can not be changed." - id="advancedSettings.field.helpText" - values={Object {}} + defaultMessage="Default: {value}" + id="advancedSettings.field.defaultValueText" + values={ + Object { + "value": <EuiCode> + null + </EuiCode>, + } + } /> - </EuiText> - } - isInvalid={false} - label="image:test:setting" - labelType="label" + </React.Fragment> + </EuiText> + </React.Fragment> + </React.Fragment> + } + fullWidth={true} + title={ + <h3> + Image test setting + + </h3> + } +> + <EuiFormRow + className="mgtAdvancedSettings__fieldRow" + describedByIds={Array []} + display="row" + fullWidth={true} + hasChildLabel={true} + hasEmptyLabelSpace={false} + helpText={ + <EuiText + size="xs" > - <EuiImage - allowFullScreen={true} - alt="image:test:setting" - aria-label="image test setting" - url="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACH5BAEAAAAALAAAAAABAAEAAAICRAEAOw==" + <FormattedMessage + defaultMessage="This setting is overridden by the Kibana server and can not be changed." + id="advancedSettings.field.helpText" + values={Object {}} /> - </EuiFormRow> - </EuiDescribedFormGroup> - </EuiFlexItem> - <EuiFlexItem - grow={false} - /> -</EuiFlexGroup> + </EuiText> + } + label="image:test:setting" + labelType="label" + > + <EuiImage + allowFullScreen={true} + alt="image:test:setting" + aria-label="image test setting" + url="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACH5BAEAAAAALAAAAAABAAEAAAICRAEAOw==" + /> + </EuiFormRow> +</EuiDescribedFormGroup> `; exports[`Field for image setting should render custom setting icon if it is custom 1`] = ` -<EuiFlexGroup +<EuiDescribedFormGroup className="mgtAdvancedSettings__field" + description={ + <React.Fragment> + <div + dangerouslySetInnerHTML={ + Object { + "__html": "Description for Image test setting", + } + } + /> + </React.Fragment> + } + fullWidth={true} + title={ + <h3> + Image test setting + <EuiIconTip + aria-label="Custom setting" + color="primary" + content={ + <FormattedMessage + defaultMessage="Custom setting" + id="advancedSettings.field.customSettingTooltip" + values={Object {}} + /> + } + type="asterisk" + /> + </h3> + } > - <EuiFlexItem - grow={false} + <EuiFormRow + className="mgtAdvancedSettings__fieldRow" + describedByIds={Array []} + display="row" + fullWidth={true} + hasChildLabel={true} + hasEmptyLabelSpace={false} + helpText={null} + label="image:test:setting" + labelType="label" > - <EuiDescribedFormGroup - className="mgtAdvancedSettings__fieldWrapper" - description={ - <React.Fragment> - <div - dangerouslySetInnerHTML={ - Object { - "__html": "Description for Image test setting", - } - } - /> - </React.Fragment> - } - title={ - <h3> - Image test setting - <EuiIconTip - aria-label="Custom setting" - color="primary" - content={ - <FormattedMessage - defaultMessage="Custom setting" - id="advancedSettings.field.customSettingTooltip" - values={Object {}} - /> - } - type="asterisk" - /> - </h3> - } - > - <EuiFormRow - className="mgtAdvancedSettings__fieldRow" - describedByIds={ - Array [ - "image:test:setting-aria", - ] - } - display="row" - error={null} - fullWidth={false} - hasChildLabel={true} - hasEmptyLabelSpace={false} - helpText={null} - isInvalid={false} - label="image:test:setting" - labelType="label" - > - <EuiFilePicker - accept=".jpg,.jpeg,.png" - compressed={false} - data-test-subj="advancedSetting-editField-image:test:setting" - disabled={false} - display="large" - initialPromptText="Select or drag and drop a file" - onChange={[Function]} - onKeyDown={[Function]} - /> - </EuiFormRow> - </EuiDescribedFormGroup> - </EuiFlexItem> - <EuiFlexItem - grow={false} - /> -</EuiFlexGroup> + <EuiFilePicker + accept=".jpg,.jpeg,.png" + compressed={false} + data-test-subj="advancedSetting-editField-image:test:setting" + disabled={false} + display="large" + fullWidth={true} + initialPromptText="Select or drag and drop a file" + onChange={[Function]} + /> + </EuiFormRow> +</EuiDescribedFormGroup> `; exports[`Field for image setting should render default value if there is no user value set 1`] = ` -<EuiFlexGroup +<EuiDescribedFormGroup className="mgtAdvancedSettings__field" + description={ + <React.Fragment> + <div + dangerouslySetInnerHTML={ + Object { + "__html": "Description for Image test setting", + } + } + /> + </React.Fragment> + } + fullWidth={true} + title={ + <h3> + Image test setting + + </h3> + } > - <EuiFlexItem - grow={false} + <EuiFormRow + className="mgtAdvancedSettings__fieldRow" + describedByIds={Array []} + display="row" + fullWidth={true} + hasChildLabel={true} + hasEmptyLabelSpace={false} + helpText={null} + label="image:test:setting" + labelType="label" > - <EuiDescribedFormGroup - className="mgtAdvancedSettings__fieldWrapper" - description={ - <React.Fragment> - <div - dangerouslySetInnerHTML={ - Object { - "__html": "Description for Image test setting", - } - } - /> - </React.Fragment> - } - title={ - <h3> - Image test setting - - </h3> - } - > - <EuiFormRow - className="mgtAdvancedSettings__fieldRow" - describedByIds={ - Array [ - "image:test:setting-aria", - ] - } - display="row" - error={null} - fullWidth={false} - hasChildLabel={true} - hasEmptyLabelSpace={false} - helpText={null} - isInvalid={false} - label="image:test:setting" - labelType="label" + <EuiFilePicker + accept=".jpg,.jpeg,.png" + compressed={false} + data-test-subj="advancedSetting-editField-image:test:setting" + disabled={false} + display="large" + fullWidth={true} + initialPromptText="Select or drag and drop a file" + onChange={[Function]} + /> + </EuiFormRow> +</EuiDescribedFormGroup> +`; + +exports[`Field for image setting should render unsaved value if there are unsaved changes 1`] = ` +<EuiDescribedFormGroup + className="mgtAdvancedSettings__field mgtAdvancedSettings__field--unsaved" + description={ + <React.Fragment> + <div + dangerouslySetInnerHTML={ + Object { + "__html": "Description for Image test setting", + } + } + /> + </React.Fragment> + } + fullWidth={true} + title={ + <h3> + Image test setting + <EuiIconTip + aria-label="Custom setting" + color="primary" + content={ + <FormattedMessage + defaultMessage="Custom setting" + id="advancedSettings.field.customSettingTooltip" + values={Object {}} + /> + } + type="asterisk" + /> + </h3> + } +> + <EuiFormRow + className="mgtAdvancedSettings__fieldRow" + describedByIds={Array []} + display="row" + fullWidth={true} + hasChildLabel={true} + hasEmptyLabelSpace={false} + helpText={null} + label="image:test:setting" + labelType="label" + > + <EuiFilePicker + accept=".jpg,.jpeg,.png" + compressed={false} + data-test-subj="advancedSetting-editField-image:test:setting" + disabled={false} + display="large" + fullWidth={true} + initialPromptText="Select or drag and drop a file" + onChange={[Function]} + /> + <EuiScreenReaderOnly> + <p + id="image:test:setting" > - <EuiFilePicker - accept=".jpg,.jpeg,.png" - compressed={false} - data-test-subj="advancedSetting-editField-image:test:setting" - disabled={false} - display="large" - initialPromptText="Select or drag and drop a file" - onChange={[Function]} - onKeyDown={[Function]} - /> - </EuiFormRow> - </EuiDescribedFormGroup> - </EuiFlexItem> - <EuiFlexItem - grow={false} - /> -</EuiFlexGroup> + Setting is currently not saved. + </p> + </EuiScreenReaderOnly> + </EuiFormRow> +</EuiDescribedFormGroup> `; exports[`Field for image setting should render user value if there is user value is set 1`] = ` -<EuiFlexGroup +<EuiDescribedFormGroup className="mgtAdvancedSettings__field" -> - <EuiFlexItem - grow={false} - > - <EuiDescribedFormGroup - className="mgtAdvancedSettings__fieldWrapper" - description={ - <React.Fragment> - <div - dangerouslySetInnerHTML={ - Object { - "__html": "Description for Image test setting", - } - } - /> + description={ + <React.Fragment> + <div + dangerouslySetInnerHTML={ + Object { + "__html": "Description for Image test setting", + } + } + /> + <React.Fragment> + <EuiSpacer + size="s" + /> + <EuiText + size="xs" + > <React.Fragment> - <EuiSpacer - size="s" + <FormattedMessage + defaultMessage="Default: {value}" + id="advancedSettings.field.defaultValueText" + values={ + Object { + "value": <EuiCode> + null + </EuiCode>, + } + } /> - <EuiText - size="xs" - > - <React.Fragment> - <FormattedMessage - defaultMessage="Default: {value}" - id="advancedSettings.field.defaultValueText" - values={ - Object { - "value": <EuiCode> - null - </EuiCode>, - } - } - /> - </React.Fragment> - </EuiText> </React.Fragment> - </React.Fragment> - } - title={ - <h3> - Image test setting - - </h3> - } - > - <EuiFormRow - className="mgtAdvancedSettings__fieldRow" - describedByIds={ - Array [ - "image:test:setting-aria", - ] - } - display="row" - error={null} - fullWidth={false} - hasChildLabel={true} - hasEmptyLabelSpace={false} - helpText={ - <span> - <span> - <ForwardRef - aria-label="Reset image test setting to default" - data-test-subj="advancedSetting-resetField-image:test:setting" - onClick={[Function]} - > - <FormattedMessage - defaultMessage="Reset to default" - id="advancedSettings.field.resetToDefaultLinkText" - values={Object {}} - /> - </ForwardRef> - - </span> - <span> - <ForwardRef - aria-label="Change image test setting" - data-test-subj="advancedSetting-changeImage-image:test:setting" - onClick={[Function]} - > - <FormattedMessage - defaultMessage="Change image" - id="advancedSettings.field.changeImageLinkText" - values={Object {}} - /> - </ForwardRef> - </span> - </span> - } - isInvalid={false} - label="image:test:setting" - labelType="label" - > - <EuiImage - allowFullScreen={true} - alt="image:test:setting" - aria-label="image test setting" - url="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACH5BAEAAAAALAAAAAABAAEAAAICRAEAOw==" - /> - </EuiFormRow> - </EuiDescribedFormGroup> - </EuiFlexItem> - <EuiFlexItem - grow={false} - /> -</EuiFlexGroup> + </EuiText> + </React.Fragment> + </React.Fragment> + } + fullWidth={true} + title={ + <h3> + Image test setting + + </h3> + } +> + <EuiFormRow + className="mgtAdvancedSettings__fieldRow" + describedByIds={Array []} + display="row" + fullWidth={true} + hasChildLabel={true} + hasEmptyLabelSpace={false} + helpText={ + <span> + <span> + <ForwardRef + aria-label="Reset image test setting to default" + data-test-subj="advancedSetting-resetField-image:test:setting" + onClick={[Function]} + > + <FormattedMessage + defaultMessage="Reset to default" + id="advancedSettings.field.resetToDefaultLinkText" + values={Object {}} + /> + </ForwardRef> + + </span> + <span> + <ForwardRef + aria-label="Change image test setting" + data-test-subj="advancedSetting-changeImage-image:test:setting" + onClick={[Function]} + > + <FormattedMessage + defaultMessage="Change image" + id="advancedSettings.field.changeImageLinkText" + values={Object {}} + /> + </ForwardRef> + </span> + </span> + } + label="image:test:setting" + labelType="label" + > + <EuiImage + allowFullScreen={true} + alt="image:test:setting" + aria-label="image test setting" + url="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACH5BAEAAAAALAAAAAABAAEAAAICRAEAOw==" + /> + </EuiFormRow> +</EuiDescribedFormGroup> `; exports[`Field for json setting should render as read only if saving is disabled 1`] = ` -<EuiFlexGroup +<EuiDescribedFormGroup className="mgtAdvancedSettings__field" -> - <EuiFlexItem - grow={false} - > - <EuiDescribedFormGroup - className="mgtAdvancedSettings__fieldWrapper" - description={ - <React.Fragment> - <div - dangerouslySetInnerHTML={ - Object { - "__html": "Description for Json test setting", - } - } - /> + description={ + <React.Fragment> + <div + dangerouslySetInnerHTML={ + Object { + "__html": "Description for Json test setting", + } + } + /> + <React.Fragment> + <EuiSpacer + size="s" + /> + <EuiText + size="xs" + > <React.Fragment> - <EuiSpacer - size="s" + <FormattedMessage + defaultMessage="Default: {value}" + id="advancedSettings.field.defaultValueTypeJsonText" + values={ + Object { + "value": <EuiCodeBlock + language="json" + paddingSize="s" + > + {} + </EuiCodeBlock>, + } + } /> - <EuiText - size="xs" - > - <React.Fragment> - <FormattedMessage - defaultMessage="Default: {value}" - id="advancedSettings.field.defaultValueTypeJsonText" - values={ - Object { - "value": <EuiCodeBlock - language="json" - paddingSize="s" - > - {} - </EuiCodeBlock>, - } - } - /> - </React.Fragment> - </EuiText> </React.Fragment> - </React.Fragment> - } - title={ - <h3> - Json test setting - - </h3> - } + </EuiText> + </React.Fragment> + </React.Fragment> + } + fullWidth={true} + title={ + <h3> + Json test setting + + </h3> + } +> + <EuiFormRow + className="mgtAdvancedSettings__fieldRow" + describedByIds={Array []} + display="row" + fullWidth={true} + hasChildLabel={true} + hasEmptyLabelSpace={false} + helpText={null} + label="json:test:setting" + labelType="label" + > + <div + data-test-subj="advancedSetting-editField-json:test:setting" > - <EuiFormRow - className="mgtAdvancedSettings__fieldRow" - describedByIds={ - Array [ - "json:test:setting-aria", - ] - } - display="row" - error={null} - fullWidth={false} - hasChildLabel={true} - hasEmptyLabelSpace={false} - helpText={null} - isInvalid={false} - label="json:test:setting" - labelType="label" - > - <div - data-test-subj="advancedSetting-editField-json:test:setting" - > - <EuiCodeEditor - aria-label="json test setting" - editorProps={ - Object { - "$blockScrolling": Infinity, - } - } - height="auto" - isReadOnly={true} - maxLines={30} - minLines={6} - mode="json" - onChange={[Function]} - setOptions={ - Object { - "showLineNumbers": false, - "tabSize": 2, - } - } - showGutter={false} - theme="textmate" - value="{\\"foo\\": \\"bar\\"}" - width="100%" - /> - </div> - </EuiFormRow> - </EuiDescribedFormGroup> - </EuiFlexItem> - <EuiFlexItem - grow={false} - /> -</EuiFlexGroup> + <EuiCodeEditor + aria-label="json test setting" + editorProps={ + Object { + "$blockScrolling": Infinity, + } + } + fullWidth={true} + height="auto" + isReadOnly={true} + maxLines={30} + minLines={6} + mode="json" + onChange={[Function]} + setOptions={ + Object { + "showLineNumbers": false, + "tabSize": 2, + } + } + showGutter={false} + theme="textmate" + value="{\\"foo\\": \\"bar\\"}" + width="100%" + /> + </div> + </EuiFormRow> +</EuiDescribedFormGroup> `; exports[`Field for json setting should render as read only with help text if overridden 1`] = ` -<EuiFlexGroup +<EuiDescribedFormGroup className="mgtAdvancedSettings__field" -> - <EuiFlexItem - grow={false} - > - <EuiDescribedFormGroup - className="mgtAdvancedSettings__fieldWrapper" - description={ - <React.Fragment> - <div - dangerouslySetInnerHTML={ - Object { - "__html": "Description for Json test setting", - } - } - /> + description={ + <React.Fragment> + <div + dangerouslySetInnerHTML={ + Object { + "__html": "Description for Json test setting", + } + } + /> + <React.Fragment> + <EuiSpacer + size="s" + /> + <EuiText + size="xs" + > <React.Fragment> - <EuiSpacer - size="s" + <FormattedMessage + defaultMessage="Default: {value}" + id="advancedSettings.field.defaultValueTypeJsonText" + values={ + Object { + "value": <EuiCodeBlock + language="json" + paddingSize="s" + > + {} + </EuiCodeBlock>, + } + } /> - <EuiText - size="xs" - > - <React.Fragment> - <FormattedMessage - defaultMessage="Default: {value}" - id="advancedSettings.field.defaultValueTypeJsonText" - values={ - Object { - "value": <EuiCodeBlock - language="json" - paddingSize="s" - > - {} - </EuiCodeBlock>, - } - } - /> - </React.Fragment> - </EuiText> </React.Fragment> - </React.Fragment> - } - title={ - <h3> - Json test setting - - </h3> - } + </EuiText> + </React.Fragment> + </React.Fragment> + } + fullWidth={true} + title={ + <h3> + Json test setting + + </h3> + } +> + <EuiFormRow + className="mgtAdvancedSettings__fieldRow" + describedByIds={Array []} + display="row" + fullWidth={true} + hasChildLabel={true} + hasEmptyLabelSpace={false} + helpText={ + <EuiText + size="xs" + > + <FormattedMessage + defaultMessage="This setting is overridden by the Kibana server and can not be changed." + id="advancedSettings.field.helpText" + values={Object {}} + /> + </EuiText> + } + label="json:test:setting" + labelType="label" + > + <div + data-test-subj="advancedSetting-editField-json:test:setting" > - <EuiFormRow - className="mgtAdvancedSettings__fieldRow" - describedByIds={ - Array [ - "json:test:setting-aria", - ] - } - display="row" - error={null} - fullWidth={false} - hasChildLabel={true} - hasEmptyLabelSpace={false} - helpText={ - <EuiText - size="xs" - > - <FormattedMessage - defaultMessage="This setting is overridden by the Kibana server and can not be changed." - id="advancedSettings.field.helpText" - values={Object {}} - /> - </EuiText> + <EuiCodeEditor + aria-label="json test setting" + editorProps={ + Object { + "$blockScrolling": Infinity, + } } - isInvalid={false} - label="json:test:setting" - labelType="label" - > - <div - data-test-subj="advancedSetting-editField-json:test:setting" - > - <EuiCodeEditor - aria-label="json test setting" - editorProps={ - Object { - "$blockScrolling": Infinity, - } - } - height="auto" - isReadOnly={true} - maxLines={30} - minLines={6} - mode="json" - onChange={[Function]} - setOptions={ - Object { - "showLineNumbers": false, - "tabSize": 2, - } - } - showGutter={false} - theme="textmate" - value="{\\"hello\\": \\"world\\"}" - width="100%" - /> - </div> - </EuiFormRow> - </EuiDescribedFormGroup> - </EuiFlexItem> - <EuiFlexItem - grow={false} - /> -</EuiFlexGroup> + fullWidth={true} + height="auto" + isReadOnly={true} + maxLines={30} + minLines={6} + mode="json" + onChange={[Function]} + setOptions={ + Object { + "showLineNumbers": false, + "tabSize": 2, + } + } + showGutter={false} + theme="textmate" + value="{\\"hello\\": \\"world\\"}" + width="100%" + /> + </div> + </EuiFormRow> +</EuiDescribedFormGroup> `; exports[`Field for json setting should render custom setting icon if it is custom 1`] = ` -<EuiFlexGroup +<EuiDescribedFormGroup className="mgtAdvancedSettings__field" + description={ + <React.Fragment> + <div + dangerouslySetInnerHTML={ + Object { + "__html": "Description for Json test setting", + } + } + /> + </React.Fragment> + } + fullWidth={true} + title={ + <h3> + Json test setting + <EuiIconTip + aria-label="Custom setting" + color="primary" + content={ + <FormattedMessage + defaultMessage="Custom setting" + id="advancedSettings.field.customSettingTooltip" + values={Object {}} + /> + } + type="asterisk" + /> + </h3> + } > - <EuiFlexItem - grow={false} + <EuiFormRow + className="mgtAdvancedSettings__fieldRow" + describedByIds={Array []} + display="row" + fullWidth={true} + hasChildLabel={true} + hasEmptyLabelSpace={false} + helpText={null} + label="json:test:setting" + labelType="label" > - <EuiDescribedFormGroup - className="mgtAdvancedSettings__fieldWrapper" - description={ - <React.Fragment> - <div - dangerouslySetInnerHTML={ - Object { - "__html": "Description for Json test setting", - } - } - /> - </React.Fragment> - } - title={ - <h3> - Json test setting - <EuiIconTip - aria-label="Custom setting" - color="primary" - content={ - <FormattedMessage - defaultMessage="Custom setting" - id="advancedSettings.field.customSettingTooltip" - values={Object {}} - /> - } - type="asterisk" - /> - </h3> - } + <div + data-test-subj="advancedSetting-editField-json:test:setting" > - <EuiFormRow - className="mgtAdvancedSettings__fieldRow" - describedByIds={ - Array [ - "json:test:setting-aria", - ] - } - display="row" - error={null} - fullWidth={false} - hasChildLabel={true} - hasEmptyLabelSpace={false} - helpText={null} - isInvalid={false} - label="json:test:setting" - labelType="label" - > - <div - data-test-subj="advancedSetting-editField-json:test:setting" - > - <EuiCodeEditor - aria-label="json test setting" - editorProps={ - Object { - "$blockScrolling": Infinity, - } - } - height="auto" - isReadOnly={false} - maxLines={30} - minLines={6} - mode="json" - onChange={[Function]} - setOptions={ - Object { - "showLineNumbers": false, - "tabSize": 2, - } - } - showGutter={false} - theme="textmate" - value="{\\"foo\\": \\"bar\\"}" - width="100%" - /> - </div> - </EuiFormRow> - </EuiDescribedFormGroup> - </EuiFlexItem> - <EuiFlexItem - grow={false} - /> -</EuiFlexGroup> + <EuiCodeEditor + aria-label="json test setting" + editorProps={ + Object { + "$blockScrolling": Infinity, + } + } + fullWidth={true} + height="auto" + isReadOnly={false} + maxLines={30} + minLines={6} + mode="json" + onChange={[Function]} + setOptions={ + Object { + "showLineNumbers": false, + "tabSize": 2, + } + } + showGutter={false} + theme="textmate" + value="{\\"foo\\": \\"bar\\"}" + width="100%" + /> + </div> + </EuiFormRow> +</EuiDescribedFormGroup> `; exports[`Field for json setting should render default value if there is no user value set 1`] = ` -<EuiFlexGroup +<EuiDescribedFormGroup className="mgtAdvancedSettings__field" -> - <EuiFlexItem - grow={false} - > - <EuiDescribedFormGroup - className="mgtAdvancedSettings__fieldWrapper" - description={ - <React.Fragment> - <div - dangerouslySetInnerHTML={ - Object { - "__html": "Description for Json test setting", - } - } - /> + description={ + <React.Fragment> + <div + dangerouslySetInnerHTML={ + Object { + "__html": "Description for Json test setting", + } + } + /> + <React.Fragment> + <EuiSpacer + size="s" + /> + <EuiText + size="xs" + > <React.Fragment> - <EuiSpacer - size="s" + <FormattedMessage + defaultMessage="Default: {value}" + id="advancedSettings.field.defaultValueTypeJsonText" + values={ + Object { + "value": <EuiCodeBlock + language="json" + paddingSize="s" + > + {} + </EuiCodeBlock>, + } + } /> - <EuiText - size="xs" - > - <React.Fragment> - <FormattedMessage - defaultMessage="Default: {value}" - id="advancedSettings.field.defaultValueTypeJsonText" - values={ - Object { - "value": <EuiCodeBlock - language="json" - paddingSize="s" - > - {} - </EuiCodeBlock>, - } - } - /> - </React.Fragment> - </EuiText> </React.Fragment> - </React.Fragment> - } - title={ - <h3> - Json test setting - - </h3> - } + </EuiText> + </React.Fragment> + </React.Fragment> + } + fullWidth={true} + title={ + <h3> + Json test setting + + </h3> + } +> + <EuiFormRow + className="mgtAdvancedSettings__fieldRow" + describedByIds={Array []} + display="row" + fullWidth={true} + hasChildLabel={true} + hasEmptyLabelSpace={false} + helpText={ + <span> + <span> + <ForwardRef + aria-label="Reset json test setting to default" + data-test-subj="advancedSetting-resetField-json:test:setting" + onClick={[Function]} + > + <FormattedMessage + defaultMessage="Reset to default" + id="advancedSettings.field.resetToDefaultLinkText" + values={Object {}} + /> + </ForwardRef> + + </span> + </span> + } + label="json:test:setting" + labelType="label" + > + <div + data-test-subj="advancedSetting-editField-json:test:setting" > - <EuiFormRow - className="mgtAdvancedSettings__fieldRow" - describedByIds={ - Array [ - "json:test:setting-aria", - ] - } - display="row" - error={null} - fullWidth={false} - hasChildLabel={true} - hasEmptyLabelSpace={false} - helpText={ - <span> - <span> - <ForwardRef - aria-label="Reset json test setting to default" - data-test-subj="advancedSetting-resetField-json:test:setting" - onClick={[Function]} - > - <FormattedMessage - defaultMessage="Reset to default" - id="advancedSettings.field.resetToDefaultLinkText" - values={Object {}} - /> - </ForwardRef> - - </span> - </span> - } - isInvalid={false} - label="json:test:setting" - labelType="label" + <EuiCodeEditor + aria-label="json test setting" + editorProps={ + Object { + "$blockScrolling": Infinity, + } + } + fullWidth={true} + height="auto" + isReadOnly={false} + maxLines={30} + minLines={6} + mode="json" + onChange={[Function]} + setOptions={ + Object { + "showLineNumbers": false, + "tabSize": 2, + } + } + showGutter={false} + theme="textmate" + value="{\\"foo\\": \\"bar\\"}" + width="100%" + /> + </div> + </EuiFormRow> +</EuiDescribedFormGroup> +`; + +exports[`Field for json setting should render unsaved value if there are unsaved changes 1`] = ` +<EuiDescribedFormGroup + className="mgtAdvancedSettings__field mgtAdvancedSettings__field--unsaved" + description={ + <React.Fragment> + <div + dangerouslySetInnerHTML={ + Object { + "__html": "Description for Json test setting", + } + } + /> + </React.Fragment> + } + fullWidth={true} + title={ + <h3> + Json test setting + <EuiIconTip + aria-label="Custom setting" + color="primary" + content={ + <FormattedMessage + defaultMessage="Custom setting" + id="advancedSettings.field.customSettingTooltip" + values={Object {}} + /> + } + type="asterisk" + /> + </h3> + } +> + <EuiFormRow + className="mgtAdvancedSettings__fieldRow" + describedByIds={Array []} + display="row" + fullWidth={true} + hasChildLabel={true} + hasEmptyLabelSpace={false} + helpText={null} + label="json:test:setting" + labelType="label" + > + <div + data-test-subj="advancedSetting-editField-json:test:setting" + > + <EuiCodeEditor + aria-describedby="json:test:setting" + aria-label="json test setting" + editorProps={ + Object { + "$blockScrolling": Infinity, + } + } + fullWidth={true} + height="auto" + isReadOnly={false} + maxLines={30} + minLines={6} + mode="json" + onChange={[Function]} + setOptions={ + Object { + "showLineNumbers": false, + "tabSize": 2, + } + } + showGutter={false} + theme="textmate" + value={ + Object { + "foo": "bar2", + } + } + width="100%" + /> + </div> + <EuiScreenReaderOnly> + <p + id="json:test:setting" > - <div - data-test-subj="advancedSetting-editField-json:test:setting" - > - <EuiCodeEditor - aria-label="json test setting" - editorProps={ - Object { - "$blockScrolling": Infinity, - } - } - height="auto" - isReadOnly={false} - maxLines={30} - minLines={6} - mode="json" - onChange={[Function]} - setOptions={ - Object { - "showLineNumbers": false, - "tabSize": 2, - } - } - showGutter={false} - theme="textmate" - value="{\\"foo\\": \\"bar\\"}" - width="100%" - /> - </div> - </EuiFormRow> - </EuiDescribedFormGroup> - </EuiFlexItem> - <EuiFlexItem - grow={false} - /> -</EuiFlexGroup> + Setting is currently not saved. + </p> + </EuiScreenReaderOnly> + </EuiFormRow> +</EuiDescribedFormGroup> `; exports[`Field for json setting should render user value if there is user value is set 1`] = ` -<EuiFlexGroup +<EuiDescribedFormGroup className="mgtAdvancedSettings__field" -> - <EuiFlexItem - grow={false} - > - <EuiDescribedFormGroup - className="mgtAdvancedSettings__fieldWrapper" - description={ - <React.Fragment> - <div - dangerouslySetInnerHTML={ - Object { - "__html": "Description for Json test setting", - } - } - /> + description={ + <React.Fragment> + <div + dangerouslySetInnerHTML={ + Object { + "__html": "Description for Json test setting", + } + } + /> + <React.Fragment> + <EuiSpacer + size="s" + /> + <EuiText + size="xs" + > <React.Fragment> - <EuiSpacer - size="s" + <FormattedMessage + defaultMessage="Default: {value}" + id="advancedSettings.field.defaultValueTypeJsonText" + values={ + Object { + "value": <EuiCodeBlock + language="json" + paddingSize="s" + > + {} + </EuiCodeBlock>, + } + } /> - <EuiText - size="xs" - > - <React.Fragment> - <FormattedMessage - defaultMessage="Default: {value}" - id="advancedSettings.field.defaultValueTypeJsonText" - values={ - Object { - "value": <EuiCodeBlock - language="json" - paddingSize="s" - > - {} - </EuiCodeBlock>, - } - } - /> - </React.Fragment> - </EuiText> </React.Fragment> - </React.Fragment> - } - title={ - <h3> - Json test setting - - </h3> - } + </EuiText> + </React.Fragment> + </React.Fragment> + } + fullWidth={true} + title={ + <h3> + Json test setting + + </h3> + } +> + <EuiFormRow + className="mgtAdvancedSettings__fieldRow" + describedByIds={Array []} + display="row" + fullWidth={true} + hasChildLabel={true} + hasEmptyLabelSpace={false} + helpText={ + <span> + <span> + <ForwardRef + aria-label="Reset json test setting to default" + data-test-subj="advancedSetting-resetField-json:test:setting" + onClick={[Function]} + > + <FormattedMessage + defaultMessage="Reset to default" + id="advancedSettings.field.resetToDefaultLinkText" + values={Object {}} + /> + </ForwardRef> + + </span> + </span> + } + label="json:test:setting" + labelType="label" + > + <div + data-test-subj="advancedSetting-editField-json:test:setting" > - <EuiFormRow - className="mgtAdvancedSettings__fieldRow" - describedByIds={ - Array [ - "json:test:setting-aria", - ] - } - display="row" - error={null} - fullWidth={false} - hasChildLabel={true} - hasEmptyLabelSpace={false} - helpText={ - <span> - <span> - <ForwardRef - aria-label="Reset json test setting to default" - data-test-subj="advancedSetting-resetField-json:test:setting" - onClick={[Function]} - > - <FormattedMessage - defaultMessage="Reset to default" - id="advancedSettings.field.resetToDefaultLinkText" - values={Object {}} - /> - </ForwardRef> - - </span> - </span> - } - isInvalid={false} - label="json:test:setting" - labelType="label" - > - <div - data-test-subj="advancedSetting-editField-json:test:setting" - > - <EuiCodeEditor - aria-label="json test setting" - editorProps={ - Object { - "$blockScrolling": Infinity, - } - } - height="auto" - isReadOnly={false} - maxLines={30} - minLines={6} - mode="json" - onChange={[Function]} - setOptions={ - Object { - "showLineNumbers": false, - "tabSize": 2, - } - } - showGutter={false} - theme="textmate" - value="{\\"hello\\": \\"world\\"}" - width="100%" - /> - </div> - </EuiFormRow> - </EuiDescribedFormGroup> - </EuiFlexItem> - <EuiFlexItem - grow={false} - /> -</EuiFlexGroup> + <EuiCodeEditor + aria-label="json test setting" + editorProps={ + Object { + "$blockScrolling": Infinity, + } + } + fullWidth={true} + height="auto" + isReadOnly={false} + maxLines={30} + minLines={6} + mode="json" + onChange={[Function]} + setOptions={ + Object { + "showLineNumbers": false, + "tabSize": 2, + } + } + showGutter={false} + theme="textmate" + value="{\\"hello\\": \\"world\\"}" + width="100%" + /> + </div> + </EuiFormRow> +</EuiDescribedFormGroup> `; exports[`Field for markdown setting should render as read only if saving is disabled 1`] = ` -<EuiFlexGroup +<EuiDescribedFormGroup className="mgtAdvancedSettings__field" + description={ + <React.Fragment> + <div + dangerouslySetInnerHTML={ + Object { + "__html": "Description for Markdown test setting", + } + } + /> + </React.Fragment> + } + fullWidth={true} + title={ + <h3> + Markdown test setting + + </h3> + } > - <EuiFlexItem - grow={false} + <EuiFormRow + className="mgtAdvancedSettings__fieldRow" + describedByIds={Array []} + display="row" + fullWidth={true} + hasChildLabel={true} + hasEmptyLabelSpace={false} + helpText={null} + label="markdown:test:setting" + labelType="label" > - <EuiDescribedFormGroup - className="mgtAdvancedSettings__fieldWrapper" - description={ - <React.Fragment> - <div - dangerouslySetInnerHTML={ - Object { - "__html": "Description for Markdown test setting", - } - } - /> - </React.Fragment> - } - title={ - <h3> - Markdown test setting - - </h3> - } + <div + data-test-subj="advancedSetting-editField-markdown:test:setting" > - <EuiFormRow - className="mgtAdvancedSettings__fieldRow" - describedByIds={ - Array [ - "markdown:test:setting-aria", - ] - } - display="row" - error={null} - fullWidth={false} - hasChildLabel={true} - hasEmptyLabelSpace={false} - helpText={null} - isInvalid={false} - label="markdown:test:setting" - labelType="label" - > - <div - data-test-subj="advancedSetting-editField-markdown:test:setting" - > - <EuiCodeEditor - aria-label="markdown test setting" - editorProps={ - Object { - "$blockScrolling": Infinity, - } - } - height="auto" - isReadOnly={true} - maxLines={30} - minLines={6} - mode="markdown" - onChange={[Function]} - setOptions={ - Object { - "showLineNumbers": false, - "tabSize": 2, - } - } - showGutter={false} - theme="textmate" - value="" - width="100%" - /> - </div> - </EuiFormRow> - </EuiDescribedFormGroup> - </EuiFlexItem> - <EuiFlexItem - grow={false} - /> -</EuiFlexGroup> + <EuiCodeEditor + aria-label="markdown test setting" + editorProps={ + Object { + "$blockScrolling": Infinity, + } + } + fullWidth={true} + height="auto" + isReadOnly={true} + maxLines={30} + minLines={6} + mode="markdown" + onChange={[Function]} + setOptions={ + Object { + "showLineNumbers": false, + "tabSize": 2, + } + } + showGutter={false} + theme="textmate" + value="" + width="100%" + /> + </div> + </EuiFormRow> +</EuiDescribedFormGroup> `; exports[`Field for markdown setting should render as read only with help text if overridden 1`] = ` -<EuiFlexGroup +<EuiDescribedFormGroup className="mgtAdvancedSettings__field" -> - <EuiFlexItem - grow={false} - > - <EuiDescribedFormGroup - className="mgtAdvancedSettings__fieldWrapper" - description={ - <React.Fragment> - <div - dangerouslySetInnerHTML={ - Object { - "__html": "Description for Markdown test setting", - } - } - /> + description={ + <React.Fragment> + <div + dangerouslySetInnerHTML={ + Object { + "__html": "Description for Markdown test setting", + } + } + /> + <React.Fragment> + <EuiSpacer + size="s" + /> + <EuiText + size="xs" + > <React.Fragment> - <EuiSpacer - size="s" + <FormattedMessage + defaultMessage="Default: {value}" + id="advancedSettings.field.defaultValueText" + values={ + Object { + "value": <EuiCode> + null + </EuiCode>, + } + } /> - <EuiText - size="xs" - > - <React.Fragment> - <FormattedMessage - defaultMessage="Default: {value}" - id="advancedSettings.field.defaultValueText" - values={ - Object { - "value": <EuiCode> - null - </EuiCode>, - } - } - /> - </React.Fragment> - </EuiText> </React.Fragment> - </React.Fragment> - } - title={ - <h3> - Markdown test setting - - </h3> - } + </EuiText> + </React.Fragment> + </React.Fragment> + } + fullWidth={true} + title={ + <h3> + Markdown test setting + + </h3> + } +> + <EuiFormRow + className="mgtAdvancedSettings__fieldRow" + describedByIds={Array []} + display="row" + fullWidth={true} + hasChildLabel={true} + hasEmptyLabelSpace={false} + helpText={ + <EuiText + size="xs" + > + <FormattedMessage + defaultMessage="This setting is overridden by the Kibana server and can not be changed." + id="advancedSettings.field.helpText" + values={Object {}} + /> + </EuiText> + } + label="markdown:test:setting" + labelType="label" + > + <div + data-test-subj="advancedSetting-editField-markdown:test:setting" > - <EuiFormRow - className="mgtAdvancedSettings__fieldRow" - describedByIds={ - Array [ - "markdown:test:setting-aria", - ] - } - display="row" - error={null} - fullWidth={false} - hasChildLabel={true} - hasEmptyLabelSpace={false} - helpText={ - <EuiText - size="xs" - > - <FormattedMessage - defaultMessage="This setting is overridden by the Kibana server and can not be changed." - id="advancedSettings.field.helpText" - values={Object {}} - /> - </EuiText> + <EuiCodeEditor + aria-label="markdown test setting" + editorProps={ + Object { + "$blockScrolling": Infinity, + } } - isInvalid={false} - label="markdown:test:setting" - labelType="label" - > - <div - data-test-subj="advancedSetting-editField-markdown:test:setting" - > - <EuiCodeEditor - aria-label="markdown test setting" - editorProps={ - Object { - "$blockScrolling": Infinity, - } - } - height="auto" - isReadOnly={true} - maxLines={30} - minLines={6} - mode="markdown" - onChange={[Function]} - setOptions={ - Object { - "showLineNumbers": false, - "tabSize": 2, - } - } - showGutter={false} - theme="textmate" - value="**bold**" - width="100%" - /> - </div> - </EuiFormRow> - </EuiDescribedFormGroup> - </EuiFlexItem> - <EuiFlexItem - grow={false} - /> -</EuiFlexGroup> + fullWidth={true} + height="auto" + isReadOnly={true} + maxLines={30} + minLines={6} + mode="markdown" + onChange={[Function]} + setOptions={ + Object { + "showLineNumbers": false, + "tabSize": 2, + } + } + showGutter={false} + theme="textmate" + value="**bold**" + width="100%" + /> + </div> + </EuiFormRow> +</EuiDescribedFormGroup> `; exports[`Field for markdown setting should render custom setting icon if it is custom 1`] = ` -<EuiFlexGroup +<EuiDescribedFormGroup className="mgtAdvancedSettings__field" + description={ + <React.Fragment> + <div + dangerouslySetInnerHTML={ + Object { + "__html": "Description for Markdown test setting", + } + } + /> + </React.Fragment> + } + fullWidth={true} + title={ + <h3> + Markdown test setting + <EuiIconTip + aria-label="Custom setting" + color="primary" + content={ + <FormattedMessage + defaultMessage="Custom setting" + id="advancedSettings.field.customSettingTooltip" + values={Object {}} + /> + } + type="asterisk" + /> + </h3> + } > - <EuiFlexItem - grow={false} + <EuiFormRow + className="mgtAdvancedSettings__fieldRow" + describedByIds={Array []} + display="row" + fullWidth={true} + hasChildLabel={true} + hasEmptyLabelSpace={false} + helpText={null} + label="markdown:test:setting" + labelType="label" > - <EuiDescribedFormGroup - className="mgtAdvancedSettings__fieldWrapper" - description={ - <React.Fragment> - <div - dangerouslySetInnerHTML={ - Object { - "__html": "Description for Markdown test setting", - } - } - /> - </React.Fragment> - } - title={ - <h3> - Markdown test setting - <EuiIconTip - aria-label="Custom setting" - color="primary" - content={ - <FormattedMessage - defaultMessage="Custom setting" - id="advancedSettings.field.customSettingTooltip" - values={Object {}} - /> - } - type="asterisk" - /> - </h3> - } + <div + data-test-subj="advancedSetting-editField-markdown:test:setting" > - <EuiFormRow - className="mgtAdvancedSettings__fieldRow" - describedByIds={ - Array [ - "markdown:test:setting-aria", - ] - } - display="row" - error={null} - fullWidth={false} - hasChildLabel={true} - hasEmptyLabelSpace={false} - helpText={null} - isInvalid={false} - label="markdown:test:setting" - labelType="label" - > - <div - data-test-subj="advancedSetting-editField-markdown:test:setting" - > - <EuiCodeEditor - aria-label="markdown test setting" - editorProps={ - Object { - "$blockScrolling": Infinity, - } - } - height="auto" - isReadOnly={false} - maxLines={30} - minLines={6} - mode="markdown" - onChange={[Function]} - setOptions={ - Object { - "showLineNumbers": false, - "tabSize": 2, - } - } - showGutter={false} - theme="textmate" - value="" - width="100%" - /> - </div> - </EuiFormRow> - </EuiDescribedFormGroup> - </EuiFlexItem> - <EuiFlexItem - grow={false} - /> -</EuiFlexGroup> + <EuiCodeEditor + aria-label="markdown test setting" + editorProps={ + Object { + "$blockScrolling": Infinity, + } + } + fullWidth={true} + height="auto" + isReadOnly={false} + maxLines={30} + minLines={6} + mode="markdown" + onChange={[Function]} + setOptions={ + Object { + "showLineNumbers": false, + "tabSize": 2, + } + } + showGutter={false} + theme="textmate" + value="" + width="100%" + /> + </div> + </EuiFormRow> +</EuiDescribedFormGroup> `; exports[`Field for markdown setting should render default value if there is no user value set 1`] = ` -<EuiFlexGroup +<EuiDescribedFormGroup className="mgtAdvancedSettings__field" + description={ + <React.Fragment> + <div + dangerouslySetInnerHTML={ + Object { + "__html": "Description for Markdown test setting", + } + } + /> + </React.Fragment> + } + fullWidth={true} + title={ + <h3> + Markdown test setting + + </h3> + } > - <EuiFlexItem - grow={false} + <EuiFormRow + className="mgtAdvancedSettings__fieldRow" + describedByIds={Array []} + display="row" + fullWidth={true} + hasChildLabel={true} + hasEmptyLabelSpace={false} + helpText={null} + label="markdown:test:setting" + labelType="label" > - <EuiDescribedFormGroup - className="mgtAdvancedSettings__fieldWrapper" - description={ - <React.Fragment> - <div - dangerouslySetInnerHTML={ - Object { - "__html": "Description for Markdown test setting", - } - } - /> - </React.Fragment> - } - title={ - <h3> - Markdown test setting - - </h3> - } + <div + data-test-subj="advancedSetting-editField-markdown:test:setting" + > + <EuiCodeEditor + aria-label="markdown test setting" + editorProps={ + Object { + "$blockScrolling": Infinity, + } + } + fullWidth={true} + height="auto" + isReadOnly={false} + maxLines={30} + minLines={6} + mode="markdown" + onChange={[Function]} + setOptions={ + Object { + "showLineNumbers": false, + "tabSize": 2, + } + } + showGutter={false} + theme="textmate" + value="" + width="100%" + /> + </div> + </EuiFormRow> +</EuiDescribedFormGroup> +`; + +exports[`Field for markdown setting should render unsaved value if there are unsaved changes 1`] = ` +<EuiDescribedFormGroup + className="mgtAdvancedSettings__field mgtAdvancedSettings__field--unsaved" + description={ + <React.Fragment> + <div + dangerouslySetInnerHTML={ + Object { + "__html": "Description for Markdown test setting", + } + } + /> + </React.Fragment> + } + fullWidth={true} + title={ + <h3> + Markdown test setting + <EuiIconTip + aria-label="Custom setting" + color="primary" + content={ + <FormattedMessage + defaultMessage="Custom setting" + id="advancedSettings.field.customSettingTooltip" + values={Object {}} + /> + } + type="asterisk" + /> + </h3> + } +> + <EuiFormRow + className="mgtAdvancedSettings__fieldRow" + describedByIds={Array []} + display="row" + fullWidth={true} + hasChildLabel={true} + hasEmptyLabelSpace={false} + helpText={null} + label="markdown:test:setting" + labelType="label" + > + <div + data-test-subj="advancedSetting-editField-markdown:test:setting" > - <EuiFormRow - className="mgtAdvancedSettings__fieldRow" - describedByIds={ - Array [ - "markdown:test:setting-aria", - ] - } - display="row" - error={null} - fullWidth={false} - hasChildLabel={true} - hasEmptyLabelSpace={false} - helpText={null} - isInvalid={false} - label="markdown:test:setting" - labelType="label" + <EuiCodeEditor + aria-describedby="markdown:test:setting" + aria-label="markdown test setting" + editorProps={ + Object { + "$blockScrolling": Infinity, + } + } + fullWidth={true} + height="auto" + isReadOnly={false} + maxLines={30} + minLines={6} + mode="markdown" + onChange={[Function]} + setOptions={ + Object { + "showLineNumbers": false, + "tabSize": 2, + } + } + showGutter={false} + theme="textmate" + value="Hello World" + width="100%" + /> + </div> + <EuiScreenReaderOnly> + <p + id="markdown:test:setting" > - <div - data-test-subj="advancedSetting-editField-markdown:test:setting" - > - <EuiCodeEditor - aria-label="markdown test setting" - editorProps={ - Object { - "$blockScrolling": Infinity, - } - } - height="auto" - isReadOnly={false} - maxLines={30} - minLines={6} - mode="markdown" - onChange={[Function]} - setOptions={ - Object { - "showLineNumbers": false, - "tabSize": 2, - } - } - showGutter={false} - theme="textmate" - value="" - width="100%" - /> - </div> - </EuiFormRow> - </EuiDescribedFormGroup> - </EuiFlexItem> - <EuiFlexItem - grow={false} - /> -</EuiFlexGroup> + Setting is currently not saved. + </p> + </EuiScreenReaderOnly> + </EuiFormRow> +</EuiDescribedFormGroup> `; exports[`Field for markdown setting should render user value if there is user value is set 1`] = ` -<EuiFlexGroup +<EuiDescribedFormGroup className="mgtAdvancedSettings__field" -> - <EuiFlexItem - grow={false} - > - <EuiDescribedFormGroup - className="mgtAdvancedSettings__fieldWrapper" - description={ - <React.Fragment> - <div - dangerouslySetInnerHTML={ - Object { - "__html": "Description for Markdown test setting", - } - } - /> + description={ + <React.Fragment> + <div + dangerouslySetInnerHTML={ + Object { + "__html": "Description for Markdown test setting", + } + } + /> + <React.Fragment> + <EuiSpacer + size="s" + /> + <EuiText + size="xs" + > <React.Fragment> - <EuiSpacer - size="s" + <FormattedMessage + defaultMessage="Default: {value}" + id="advancedSettings.field.defaultValueText" + values={ + Object { + "value": <EuiCode> + null + </EuiCode>, + } + } /> - <EuiText - size="xs" - > - <React.Fragment> - <FormattedMessage - defaultMessage="Default: {value}" - id="advancedSettings.field.defaultValueText" - values={ - Object { - "value": <EuiCode> - null - </EuiCode>, - } - } - /> - </React.Fragment> - </EuiText> </React.Fragment> - </React.Fragment> - } - title={ - <h3> - Markdown test setting - - </h3> - } + </EuiText> + </React.Fragment> + </React.Fragment> + } + fullWidth={true} + title={ + <h3> + Markdown test setting + + </h3> + } +> + <EuiFormRow + className="mgtAdvancedSettings__fieldRow" + describedByIds={Array []} + display="row" + fullWidth={true} + hasChildLabel={true} + hasEmptyLabelSpace={false} + helpText={ + <span> + <span> + <ForwardRef + aria-label="Reset markdown test setting to default" + data-test-subj="advancedSetting-resetField-markdown:test:setting" + onClick={[Function]} + > + <FormattedMessage + defaultMessage="Reset to default" + id="advancedSettings.field.resetToDefaultLinkText" + values={Object {}} + /> + </ForwardRef> + + </span> + </span> + } + label="markdown:test:setting" + labelType="label" + > + <div + data-test-subj="advancedSetting-editField-markdown:test:setting" > - <EuiFormRow - className="mgtAdvancedSettings__fieldRow" - describedByIds={ - Array [ - "markdown:test:setting-aria", - ] - } - display="row" - error={null} - fullWidth={false} - hasChildLabel={true} - hasEmptyLabelSpace={false} - helpText={ - <span> - <span> - <ForwardRef - aria-label="Reset markdown test setting to default" - data-test-subj="advancedSetting-resetField-markdown:test:setting" - onClick={[Function]} - > - <FormattedMessage - defaultMessage="Reset to default" - id="advancedSettings.field.resetToDefaultLinkText" - values={Object {}} - /> - </ForwardRef> - - </span> - </span> - } - isInvalid={false} - label="markdown:test:setting" - labelType="label" - > - <div - data-test-subj="advancedSetting-editField-markdown:test:setting" - > - <EuiCodeEditor - aria-label="markdown test setting" - editorProps={ - Object { - "$blockScrolling": Infinity, - } - } - height="auto" - isReadOnly={false} - maxLines={30} - minLines={6} - mode="markdown" - onChange={[Function]} - setOptions={ - Object { - "showLineNumbers": false, - "tabSize": 2, - } - } - showGutter={false} - theme="textmate" - value="**bold**" - width="100%" - /> - </div> - </EuiFormRow> - </EuiDescribedFormGroup> - </EuiFlexItem> - <EuiFlexItem - grow={false} - /> -</EuiFlexGroup> + <EuiCodeEditor + aria-label="markdown test setting" + editorProps={ + Object { + "$blockScrolling": Infinity, + } + } + fullWidth={true} + height="auto" + isReadOnly={false} + maxLines={30} + minLines={6} + mode="markdown" + onChange={[Function]} + setOptions={ + Object { + "showLineNumbers": false, + "tabSize": 2, + } + } + showGutter={false} + theme="textmate" + value="**bold**" + width="100%" + /> + </div> + </EuiFormRow> +</EuiDescribedFormGroup> `; exports[`Field for number setting should render as read only if saving is disabled 1`] = ` -<EuiFlexGroup +<EuiDescribedFormGroup className="mgtAdvancedSettings__field" + description={ + <React.Fragment> + <div + dangerouslySetInnerHTML={ + Object { + "__html": "Description for Number test setting", + } + } + /> + </React.Fragment> + } + fullWidth={true} + title={ + <h3> + Number test setting + + </h3> + } > - <EuiFlexItem - grow={false} + <EuiFormRow + className="mgtAdvancedSettings__fieldRow" + describedByIds={Array []} + display="row" + fullWidth={true} + hasChildLabel={true} + hasEmptyLabelSpace={false} + helpText={null} + label="number:test:setting" + labelType="label" > - <EuiDescribedFormGroup - className="mgtAdvancedSettings__fieldWrapper" - description={ - <React.Fragment> - <div - dangerouslySetInnerHTML={ - Object { - "__html": "Description for Number test setting", - } - } - /> - </React.Fragment> - } - title={ - <h3> - Number test setting - - </h3> - } - > - <EuiFormRow - className="mgtAdvancedSettings__fieldRow" - describedByIds={ - Array [ - "number:test:setting-aria", - ] - } - display="row" - error={null} - fullWidth={false} - hasChildLabel={true} - hasEmptyLabelSpace={false} - helpText={null} - isInvalid={false} - label="number:test:setting" - labelType="label" - > - <EuiFieldNumber - aria-label="number test setting" - data-test-subj="advancedSetting-editField-number:test:setting" - disabled={true} - isLoading={false} - onChange={[Function]} - onKeyDown={[Function]} - value={5} - /> - </EuiFormRow> - </EuiDescribedFormGroup> - </EuiFlexItem> - <EuiFlexItem - grow={false} - /> -</EuiFlexGroup> + <EuiFieldNumber + aria-label="number test setting" + data-test-subj="advancedSetting-editField-number:test:setting" + disabled={true} + fullWidth={true} + onChange={[Function]} + value={5} + /> + </EuiFormRow> +</EuiDescribedFormGroup> `; exports[`Field for number setting should render as read only with help text if overridden 1`] = ` -<EuiFlexGroup +<EuiDescribedFormGroup className="mgtAdvancedSettings__field" -> - <EuiFlexItem - grow={false} - > - <EuiDescribedFormGroup - className="mgtAdvancedSettings__fieldWrapper" - description={ - <React.Fragment> - <div - dangerouslySetInnerHTML={ - Object { - "__html": "Description for Number test setting", - } - } - /> + description={ + <React.Fragment> + <div + dangerouslySetInnerHTML={ + Object { + "__html": "Description for Number test setting", + } + } + /> + <React.Fragment> + <EuiSpacer + size="s" + /> + <EuiText + size="xs" + > <React.Fragment> - <EuiSpacer - size="s" - /> - <EuiText - size="xs" - > - <React.Fragment> - <FormattedMessage - defaultMessage="Default: {value}" - id="advancedSettings.field.defaultValueText" - values={ - Object { - "value": <EuiCode> - 5 - </EuiCode>, - } - } - /> - </React.Fragment> - </EuiText> - </React.Fragment> - </React.Fragment> - } - title={ - <h3> - Number test setting - - </h3> - } - > - <EuiFormRow - className="mgtAdvancedSettings__fieldRow" - describedByIds={ - Array [ - "number:test:setting-aria", - ] - } - display="row" - error={null} - fullWidth={false} - hasChildLabel={true} - hasEmptyLabelSpace={false} - helpText={ - <EuiText - size="xs" - > <FormattedMessage - defaultMessage="This setting is overridden by the Kibana server and can not be changed." - id="advancedSettings.field.helpText" - values={Object {}} + defaultMessage="Default: {value}" + id="advancedSettings.field.defaultValueText" + values={ + Object { + "value": <EuiCode> + 5 + </EuiCode>, + } + } /> - </EuiText> - } - isInvalid={false} - label="number:test:setting" - labelType="label" + </React.Fragment> + </EuiText> + </React.Fragment> + </React.Fragment> + } + fullWidth={true} + title={ + <h3> + Number test setting + + </h3> + } +> + <EuiFormRow + className="mgtAdvancedSettings__fieldRow" + describedByIds={Array []} + display="row" + fullWidth={true} + hasChildLabel={true} + hasEmptyLabelSpace={false} + helpText={ + <EuiText + size="xs" > - <EuiFieldNumber - aria-label="number test setting" - data-test-subj="advancedSetting-editField-number:test:setting" - disabled={true} - isLoading={false} - onChange={[Function]} - onKeyDown={[Function]} - value={10} + <FormattedMessage + defaultMessage="This setting is overridden by the Kibana server and can not be changed." + id="advancedSettings.field.helpText" + values={Object {}} /> - </EuiFormRow> - </EuiDescribedFormGroup> - </EuiFlexItem> - <EuiFlexItem - grow={false} - /> -</EuiFlexGroup> + </EuiText> + } + label="number:test:setting" + labelType="label" + > + <EuiFieldNumber + aria-label="number test setting" + data-test-subj="advancedSetting-editField-number:test:setting" + disabled={true} + fullWidth={true} + onChange={[Function]} + value={10} + /> + </EuiFormRow> +</EuiDescribedFormGroup> `; exports[`Field for number setting should render custom setting icon if it is custom 1`] = ` -<EuiFlexGroup +<EuiDescribedFormGroup className="mgtAdvancedSettings__field" + description={ + <React.Fragment> + <div + dangerouslySetInnerHTML={ + Object { + "__html": "Description for Number test setting", + } + } + /> + </React.Fragment> + } + fullWidth={true} + title={ + <h3> + Number test setting + <EuiIconTip + aria-label="Custom setting" + color="primary" + content={ + <FormattedMessage + defaultMessage="Custom setting" + id="advancedSettings.field.customSettingTooltip" + values={Object {}} + /> + } + type="asterisk" + /> + </h3> + } > - <EuiFlexItem - grow={false} + <EuiFormRow + className="mgtAdvancedSettings__fieldRow" + describedByIds={Array []} + display="row" + fullWidth={true} + hasChildLabel={true} + hasEmptyLabelSpace={false} + helpText={null} + label="number:test:setting" + labelType="label" > - <EuiDescribedFormGroup - className="mgtAdvancedSettings__fieldWrapper" - description={ - <React.Fragment> - <div - dangerouslySetInnerHTML={ - Object { - "__html": "Description for Number test setting", - } - } - /> - </React.Fragment> - } - title={ - <h3> - Number test setting - <EuiIconTip - aria-label="Custom setting" - color="primary" - content={ - <FormattedMessage - defaultMessage="Custom setting" - id="advancedSettings.field.customSettingTooltip" - values={Object {}} - /> - } - type="asterisk" - /> - </h3> - } - > - <EuiFormRow - className="mgtAdvancedSettings__fieldRow" - describedByIds={ - Array [ - "number:test:setting-aria", - ] - } - display="row" - error={null} - fullWidth={false} - hasChildLabel={true} - hasEmptyLabelSpace={false} - helpText={null} - isInvalid={false} - label="number:test:setting" - labelType="label" - > - <EuiFieldNumber - aria-label="number test setting" - data-test-subj="advancedSetting-editField-number:test:setting" - disabled={false} - isLoading={false} - onChange={[Function]} - onKeyDown={[Function]} - value={5} - /> - </EuiFormRow> - </EuiDescribedFormGroup> - </EuiFlexItem> - <EuiFlexItem - grow={false} - /> -</EuiFlexGroup> + <EuiFieldNumber + aria-label="number test setting" + data-test-subj="advancedSetting-editField-number:test:setting" + disabled={false} + fullWidth={true} + onChange={[Function]} + value={5} + /> + </EuiFormRow> +</EuiDescribedFormGroup> +`; + +exports[`Field for number setting should render default value if there is no user value set 1`] = ` +<EuiDescribedFormGroup + className="mgtAdvancedSettings__field" + description={ + <React.Fragment> + <div + dangerouslySetInnerHTML={ + Object { + "__html": "Description for Number test setting", + } + } + /> + </React.Fragment> + } + fullWidth={true} + title={ + <h3> + Number test setting + + </h3> + } +> + <EuiFormRow + className="mgtAdvancedSettings__fieldRow" + describedByIds={Array []} + display="row" + fullWidth={true} + hasChildLabel={true} + hasEmptyLabelSpace={false} + helpText={null} + label="number:test:setting" + labelType="label" + > + <EuiFieldNumber + aria-label="number test setting" + data-test-subj="advancedSetting-editField-number:test:setting" + disabled={false} + fullWidth={true} + onChange={[Function]} + value={5} + /> + </EuiFormRow> +</EuiDescribedFormGroup> `; -exports[`Field for number setting should render default value if there is no user value set 1`] = ` -<EuiFlexGroup - className="mgtAdvancedSettings__field" +exports[`Field for number setting should render unsaved value if there are unsaved changes 1`] = ` +<EuiDescribedFormGroup + className="mgtAdvancedSettings__field mgtAdvancedSettings__field--unsaved" + description={ + <React.Fragment> + <div + dangerouslySetInnerHTML={ + Object { + "__html": "Description for Number test setting", + } + } + /> + </React.Fragment> + } + fullWidth={true} + title={ + <h3> + Number test setting + <EuiIconTip + aria-label="Custom setting" + color="primary" + content={ + <FormattedMessage + defaultMessage="Custom setting" + id="advancedSettings.field.customSettingTooltip" + values={Object {}} + /> + } + type="asterisk" + /> + </h3> + } > - <EuiFlexItem - grow={false} + <EuiFormRow + className="mgtAdvancedSettings__fieldRow" + describedByIds={Array []} + display="row" + fullWidth={true} + hasChildLabel={true} + hasEmptyLabelSpace={false} + helpText={null} + label="number:test:setting" + labelType="label" > - <EuiDescribedFormGroup - className="mgtAdvancedSettings__fieldWrapper" - description={ - <React.Fragment> - <div - dangerouslySetInnerHTML={ - Object { - "__html": "Description for Number test setting", - } - } - /> - </React.Fragment> - } - title={ - <h3> - Number test setting - - </h3> - } - > - <EuiFormRow - className="mgtAdvancedSettings__fieldRow" - describedByIds={ - Array [ - "number:test:setting-aria", - ] - } - display="row" - error={null} - fullWidth={false} - hasChildLabel={true} - hasEmptyLabelSpace={false} - helpText={null} - isInvalid={false} - label="number:test:setting" - labelType="label" + <EuiFieldNumber + aria-describedby="number:test:setting" + aria-label="number test setting" + data-test-subj="advancedSetting-editField-number:test:setting" + disabled={false} + fullWidth={true} + onChange={[Function]} + value={1} + /> + <EuiScreenReaderOnly> + <p + id="number:test:setting" > - <EuiFieldNumber - aria-label="number test setting" - data-test-subj="advancedSetting-editField-number:test:setting" - disabled={false} - isLoading={false} - onChange={[Function]} - onKeyDown={[Function]} - value={5} - /> - </EuiFormRow> - </EuiDescribedFormGroup> - </EuiFlexItem> - <EuiFlexItem - grow={false} - /> -</EuiFlexGroup> + Setting is currently not saved. + </p> + </EuiScreenReaderOnly> + </EuiFormRow> +</EuiDescribedFormGroup> `; exports[`Field for number setting should render user value if there is user value is set 1`] = ` -<EuiFlexGroup +<EuiDescribedFormGroup className="mgtAdvancedSettings__field" -> - <EuiFlexItem - grow={false} - > - <EuiDescribedFormGroup - className="mgtAdvancedSettings__fieldWrapper" - description={ - <React.Fragment> - <div - dangerouslySetInnerHTML={ - Object { - "__html": "Description for Number test setting", - } - } - /> + description={ + <React.Fragment> + <div + dangerouslySetInnerHTML={ + Object { + "__html": "Description for Number test setting", + } + } + /> + <React.Fragment> + <EuiSpacer + size="s" + /> + <EuiText + size="xs" + > <React.Fragment> - <EuiSpacer - size="s" + <FormattedMessage + defaultMessage="Default: {value}" + id="advancedSettings.field.defaultValueText" + values={ + Object { + "value": <EuiCode> + 5 + </EuiCode>, + } + } /> - <EuiText - size="xs" - > - <React.Fragment> - <FormattedMessage - defaultMessage="Default: {value}" - id="advancedSettings.field.defaultValueText" - values={ - Object { - "value": <EuiCode> - 5 - </EuiCode>, - } - } - /> - </React.Fragment> - </EuiText> </React.Fragment> - </React.Fragment> - } - title={ - <h3> - Number test setting - - </h3> - } - > - <EuiFormRow - className="mgtAdvancedSettings__fieldRow" - describedByIds={ - Array [ - "number:test:setting-aria", - ] - } - display="row" - error={null} - fullWidth={false} - hasChildLabel={true} - hasEmptyLabelSpace={false} - helpText={ - <span> - <span> - <ForwardRef - aria-label="Reset number test setting to default" - data-test-subj="advancedSetting-resetField-number:test:setting" - onClick={[Function]} - > - <FormattedMessage - defaultMessage="Reset to default" - id="advancedSettings.field.resetToDefaultLinkText" - values={Object {}} - /> - </ForwardRef> - - </span> - </span> - } - isInvalid={false} - label="number:test:setting" - labelType="label" - > - <EuiFieldNumber - aria-label="number test setting" - data-test-subj="advancedSetting-editField-number:test:setting" - disabled={false} - isLoading={false} - onChange={[Function]} - onKeyDown={[Function]} - value={10} - /> - </EuiFormRow> - </EuiDescribedFormGroup> - </EuiFlexItem> - <EuiFlexItem - grow={false} - /> -</EuiFlexGroup> + </EuiText> + </React.Fragment> + </React.Fragment> + } + fullWidth={true} + title={ + <h3> + Number test setting + + </h3> + } +> + <EuiFormRow + className="mgtAdvancedSettings__fieldRow" + describedByIds={Array []} + display="row" + fullWidth={true} + hasChildLabel={true} + hasEmptyLabelSpace={false} + helpText={ + <span> + <span> + <ForwardRef + aria-label="Reset number test setting to default" + data-test-subj="advancedSetting-resetField-number:test:setting" + onClick={[Function]} + > + <FormattedMessage + defaultMessage="Reset to default" + id="advancedSettings.field.resetToDefaultLinkText" + values={Object {}} + /> + </ForwardRef> + + </span> + </span> + } + label="number:test:setting" + labelType="label" + > + <EuiFieldNumber + aria-label="number test setting" + data-test-subj="advancedSetting-editField-number:test:setting" + disabled={false} + fullWidth={true} + onChange={[Function]} + value={10} + /> + </EuiFormRow> +</EuiDescribedFormGroup> `; exports[`Field for select setting should render as read only if saving is disabled 1`] = ` -<EuiFlexGroup +<EuiDescribedFormGroup className="mgtAdvancedSettings__field" + description={ + <React.Fragment> + <div + dangerouslySetInnerHTML={ + Object { + "__html": "Description for Select test setting", + } + } + /> + </React.Fragment> + } + fullWidth={true} + title={ + <h3> + Select test setting + + </h3> + } > - <EuiFlexItem - grow={false} + <EuiFormRow + className="mgtAdvancedSettings__fieldRow" + describedByIds={Array []} + display="row" + fullWidth={true} + hasChildLabel={true} + hasEmptyLabelSpace={false} + helpText={null} + label="select:test:setting" + labelType="label" > - <EuiDescribedFormGroup - className="mgtAdvancedSettings__fieldWrapper" - description={ - <React.Fragment> - <div - dangerouslySetInnerHTML={ - Object { - "__html": "Description for Select test setting", - } - } - /> - </React.Fragment> - } - title={ - <h3> - Select test setting - - </h3> - } - > - <EuiFormRow - className="mgtAdvancedSettings__fieldRow" - describedByIds={ - Array [ - "select:test:setting-aria", - ] - } - display="row" - error={null} - fullWidth={false} - hasChildLabel={true} - hasEmptyLabelSpace={false} - helpText={null} - isInvalid={false} - label="select:test:setting" - labelType="label" - > - <EuiSelect - aria-label="select test setting" - data-test-subj="advancedSetting-editField-select:test:setting" - disabled={true} - isLoading={false} - onChange={[Function]} - onKeyDown={[Function]} - options={ - Array [ - Object { - "text": "Apple", - "value": "apple", - }, - Object { - "text": "Orange", - "value": "orange", - }, - Object { - "text": "banana", - "value": "banana", - }, - ] - } - value="orange" - /> - </EuiFormRow> - </EuiDescribedFormGroup> - </EuiFlexItem> - <EuiFlexItem - grow={false} - /> -</EuiFlexGroup> + <EuiSelect + aria-label="select test setting" + data-test-subj="advancedSetting-editField-select:test:setting" + disabled={true} + fullWidth={true} + onChange={[Function]} + options={ + Array [ + Object { + "text": "Apple", + "value": "apple", + }, + Object { + "text": "Orange", + "value": "orange", + }, + Object { + "text": "banana", + "value": "banana", + }, + ] + } + value="orange" + /> + </EuiFormRow> +</EuiDescribedFormGroup> `; exports[`Field for select setting should render as read only with help text if overridden 1`] = ` -<EuiFlexGroup +<EuiDescribedFormGroup className="mgtAdvancedSettings__field" -> - <EuiFlexItem - grow={false} - > - <EuiDescribedFormGroup - className="mgtAdvancedSettings__fieldWrapper" - description={ - <React.Fragment> - <div - dangerouslySetInnerHTML={ - Object { - "__html": "Description for Select test setting", - } - } - /> + description={ + <React.Fragment> + <div + dangerouslySetInnerHTML={ + Object { + "__html": "Description for Select test setting", + } + } + /> + <React.Fragment> + <EuiSpacer + size="s" + /> + <EuiText + size="xs" + > <React.Fragment> - <EuiSpacer - size="s" - /> - <EuiText - size="xs" - > - <React.Fragment> - <FormattedMessage - defaultMessage="Default: {value}" - id="advancedSettings.field.defaultValueText" - values={ - Object { - "value": <EuiCode> - Orange - </EuiCode>, - } - } - /> - </React.Fragment> - </EuiText> - </React.Fragment> - </React.Fragment> - } - title={ - <h3> - Select test setting - - </h3> - } - > - <EuiFormRow - className="mgtAdvancedSettings__fieldRow" - describedByIds={ - Array [ - "select:test:setting-aria", - ] - } - display="row" - error={null} - fullWidth={false} - hasChildLabel={true} - hasEmptyLabelSpace={false} - helpText={ - <EuiText - size="xs" - > <FormattedMessage - defaultMessage="This setting is overridden by the Kibana server and can not be changed." - id="advancedSettings.field.helpText" - values={Object {}} + defaultMessage="Default: {value}" + id="advancedSettings.field.defaultValueText" + values={ + Object { + "value": <EuiCode> + Orange + </EuiCode>, + } + } /> - </EuiText> - } - isInvalid={false} - label="select:test:setting" - labelType="label" + </React.Fragment> + </EuiText> + </React.Fragment> + </React.Fragment> + } + fullWidth={true} + title={ + <h3> + Select test setting + + </h3> + } +> + <EuiFormRow + className="mgtAdvancedSettings__fieldRow" + describedByIds={Array []} + display="row" + fullWidth={true} + hasChildLabel={true} + hasEmptyLabelSpace={false} + helpText={ + <EuiText + size="xs" > - <EuiSelect - aria-label="select test setting" - data-test-subj="advancedSetting-editField-select:test:setting" - disabled={true} - isLoading={false} - onChange={[Function]} - onKeyDown={[Function]} - options={ - Array [ - Object { - "text": "Apple", - "value": "apple", - }, - Object { - "text": "Orange", - "value": "orange", - }, - Object { - "text": "banana", - "value": "banana", - }, - ] - } - value="banana" + <FormattedMessage + defaultMessage="This setting is overridden by the Kibana server and can not be changed." + id="advancedSettings.field.helpText" + values={Object {}} /> - </EuiFormRow> - </EuiDescribedFormGroup> - </EuiFlexItem> - <EuiFlexItem - grow={false} - /> -</EuiFlexGroup> + </EuiText> + } + label="select:test:setting" + labelType="label" + > + <EuiSelect + aria-label="select test setting" + data-test-subj="advancedSetting-editField-select:test:setting" + disabled={true} + fullWidth={true} + onChange={[Function]} + options={ + Array [ + Object { + "text": "Apple", + "value": "apple", + }, + Object { + "text": "Orange", + "value": "orange", + }, + Object { + "text": "banana", + "value": "banana", + }, + ] + } + value="banana" + /> + </EuiFormRow> +</EuiDescribedFormGroup> `; exports[`Field for select setting should render custom setting icon if it is custom 1`] = ` -<EuiFlexGroup +<EuiDescribedFormGroup className="mgtAdvancedSettings__field" + description={ + <React.Fragment> + <div + dangerouslySetInnerHTML={ + Object { + "__html": "Description for Select test setting", + } + } + /> + </React.Fragment> + } + fullWidth={true} + title={ + <h3> + Select test setting + <EuiIconTip + aria-label="Custom setting" + color="primary" + content={ + <FormattedMessage + defaultMessage="Custom setting" + id="advancedSettings.field.customSettingTooltip" + values={Object {}} + /> + } + type="asterisk" + /> + </h3> + } > - <EuiFlexItem - grow={false} + <EuiFormRow + className="mgtAdvancedSettings__fieldRow" + describedByIds={Array []} + display="row" + fullWidth={true} + hasChildLabel={true} + hasEmptyLabelSpace={false} + helpText={null} + label="select:test:setting" + labelType="label" > - <EuiDescribedFormGroup - className="mgtAdvancedSettings__fieldWrapper" - description={ - <React.Fragment> - <div - dangerouslySetInnerHTML={ - Object { - "__html": "Description for Select test setting", - } - } - /> - </React.Fragment> - } - title={ - <h3> - Select test setting - <EuiIconTip - aria-label="Custom setting" - color="primary" - content={ - <FormattedMessage - defaultMessage="Custom setting" - id="advancedSettings.field.customSettingTooltip" - values={Object {}} - /> - } - type="asterisk" - /> - </h3> - } - > - <EuiFormRow - className="mgtAdvancedSettings__fieldRow" - describedByIds={ - Array [ - "select:test:setting-aria", - ] - } - display="row" - error={null} - fullWidth={false} - hasChildLabel={true} - hasEmptyLabelSpace={false} - helpText={null} - isInvalid={false} - label="select:test:setting" - labelType="label" - > - <EuiSelect - aria-label="select test setting" - data-test-subj="advancedSetting-editField-select:test:setting" - disabled={false} - isLoading={false} - onChange={[Function]} - onKeyDown={[Function]} - options={ - Array [ - Object { - "text": "Apple", - "value": "apple", - }, - Object { - "text": "Orange", - "value": "orange", - }, - Object { - "text": "banana", - "value": "banana", - }, - ] - } - value="orange" - /> - </EuiFormRow> - </EuiDescribedFormGroup> - </EuiFlexItem> - <EuiFlexItem - grow={false} - /> -</EuiFlexGroup> + <EuiSelect + aria-label="select test setting" + data-test-subj="advancedSetting-editField-select:test:setting" + disabled={false} + fullWidth={true} + onChange={[Function]} + options={ + Array [ + Object { + "text": "Apple", + "value": "apple", + }, + Object { + "text": "Orange", + "value": "orange", + }, + Object { + "text": "banana", + "value": "banana", + }, + ] + } + value="orange" + /> + </EuiFormRow> +</EuiDescribedFormGroup> `; exports[`Field for select setting should render default value if there is no user value set 1`] = ` -<EuiFlexGroup +<EuiDescribedFormGroup className="mgtAdvancedSettings__field" + description={ + <React.Fragment> + <div + dangerouslySetInnerHTML={ + Object { + "__html": "Description for Select test setting", + } + } + /> + </React.Fragment> + } + fullWidth={true} + title={ + <h3> + Select test setting + + </h3> + } > - <EuiFlexItem - grow={false} + <EuiFormRow + className="mgtAdvancedSettings__fieldRow" + describedByIds={Array []} + display="row" + fullWidth={true} + hasChildLabel={true} + hasEmptyLabelSpace={false} + helpText={null} + label="select:test:setting" + labelType="label" > - <EuiDescribedFormGroup - className="mgtAdvancedSettings__fieldWrapper" - description={ - <React.Fragment> - <div - dangerouslySetInnerHTML={ - Object { - "__html": "Description for Select test setting", - } - } - /> - </React.Fragment> - } - title={ - <h3> - Select test setting - - </h3> - } - > - <EuiFormRow - className="mgtAdvancedSettings__fieldRow" - describedByIds={ - Array [ - "select:test:setting-aria", - ] - } - display="row" - error={null} - fullWidth={false} - hasChildLabel={true} - hasEmptyLabelSpace={false} - helpText={null} - isInvalid={false} - label="select:test:setting" - labelType="label" + <EuiSelect + aria-label="select test setting" + data-test-subj="advancedSetting-editField-select:test:setting" + disabled={false} + fullWidth={true} + onChange={[Function]} + options={ + Array [ + Object { + "text": "Apple", + "value": "apple", + }, + Object { + "text": "Orange", + "value": "orange", + }, + Object { + "text": "banana", + "value": "banana", + }, + ] + } + value="orange" + /> + </EuiFormRow> +</EuiDescribedFormGroup> +`; + +exports[`Field for select setting should render unsaved value if there are unsaved changes 1`] = ` +<EuiDescribedFormGroup + className="mgtAdvancedSettings__field mgtAdvancedSettings__field--unsaved" + description={ + <React.Fragment> + <div + dangerouslySetInnerHTML={ + Object { + "__html": "Description for Select test setting", + } + } + /> + </React.Fragment> + } + fullWidth={true} + title={ + <h3> + Select test setting + <EuiIconTip + aria-label="Custom setting" + color="primary" + content={ + <FormattedMessage + defaultMessage="Custom setting" + id="advancedSettings.field.customSettingTooltip" + values={Object {}} + /> + } + type="asterisk" + /> + </h3> + } +> + <EuiFormRow + className="mgtAdvancedSettings__fieldRow" + describedByIds={Array []} + display="row" + fullWidth={true} + hasChildLabel={true} + hasEmptyLabelSpace={false} + helpText={null} + label="select:test:setting" + labelType="label" + > + <EuiSelect + aria-describedby="select:test:setting" + aria-label="select test setting" + data-test-subj="advancedSetting-editField-select:test:setting" + disabled={false} + fullWidth={true} + onChange={[Function]} + options={ + Array [ + Object { + "text": "Apple", + "value": "apple", + }, + Object { + "text": "Orange", + "value": "orange", + }, + Object { + "text": "banana", + "value": "banana", + }, + ] + } + value="banana" + /> + <EuiScreenReaderOnly> + <p + id="select:test:setting" > - <EuiSelect - aria-label="select test setting" - data-test-subj="advancedSetting-editField-select:test:setting" - disabled={false} - isLoading={false} - onChange={[Function]} - onKeyDown={[Function]} - options={ - Array [ - Object { - "text": "Apple", - "value": "apple", - }, - Object { - "text": "Orange", - "value": "orange", - }, - Object { - "text": "banana", - "value": "banana", - }, - ] - } - value="orange" - /> - </EuiFormRow> - </EuiDescribedFormGroup> - </EuiFlexItem> - <EuiFlexItem - grow={false} - /> -</EuiFlexGroup> + Setting is currently not saved. + </p> + </EuiScreenReaderOnly> + </EuiFormRow> +</EuiDescribedFormGroup> `; exports[`Field for select setting should render user value if there is user value is set 1`] = ` -<EuiFlexGroup +<EuiDescribedFormGroup className="mgtAdvancedSettings__field" -> - <EuiFlexItem - grow={false} - > - <EuiDescribedFormGroup - className="mgtAdvancedSettings__fieldWrapper" - description={ - <React.Fragment> - <div - dangerouslySetInnerHTML={ - Object { - "__html": "Description for Select test setting", - } - } - /> + description={ + <React.Fragment> + <div + dangerouslySetInnerHTML={ + Object { + "__html": "Description for Select test setting", + } + } + /> + <React.Fragment> + <EuiSpacer + size="s" + /> + <EuiText + size="xs" + > <React.Fragment> - <EuiSpacer - size="s" + <FormattedMessage + defaultMessage="Default: {value}" + id="advancedSettings.field.defaultValueText" + values={ + Object { + "value": <EuiCode> + Orange + </EuiCode>, + } + } /> - <EuiText - size="xs" - > - <React.Fragment> - <FormattedMessage - defaultMessage="Default: {value}" - id="advancedSettings.field.defaultValueText" - values={ - Object { - "value": <EuiCode> - Orange - </EuiCode>, - } - } - /> - </React.Fragment> - </EuiText> </React.Fragment> - </React.Fragment> - } - title={ - <h3> - Select test setting - - </h3> - } - > - <EuiFormRow - className="mgtAdvancedSettings__fieldRow" - describedByIds={ - Array [ - "select:test:setting-aria", - ] - } - display="row" - error={null} - fullWidth={false} - hasChildLabel={true} - hasEmptyLabelSpace={false} - helpText={ - <span> - <span> - <ForwardRef - aria-label="Reset select test setting to default" - data-test-subj="advancedSetting-resetField-select:test:setting" - onClick={[Function]} - > - <FormattedMessage - defaultMessage="Reset to default" - id="advancedSettings.field.resetToDefaultLinkText" - values={Object {}} - /> - </ForwardRef> - - </span> - </span> - } - isInvalid={false} - label="select:test:setting" - labelType="label" - > - <EuiSelect - aria-label="select test setting" - data-test-subj="advancedSetting-editField-select:test:setting" - disabled={false} - isLoading={false} - onChange={[Function]} - onKeyDown={[Function]} - options={ - Array [ - Object { - "text": "Apple", - "value": "apple", - }, - Object { - "text": "Orange", - "value": "orange", - }, - Object { - "text": "banana", - "value": "banana", - }, - ] - } - value="banana" - /> - </EuiFormRow> - </EuiDescribedFormGroup> - </EuiFlexItem> - <EuiFlexItem - grow={false} - /> -</EuiFlexGroup> + </EuiText> + </React.Fragment> + </React.Fragment> + } + fullWidth={true} + title={ + <h3> + Select test setting + + </h3> + } +> + <EuiFormRow + className="mgtAdvancedSettings__fieldRow" + describedByIds={Array []} + display="row" + fullWidth={true} + hasChildLabel={true} + hasEmptyLabelSpace={false} + helpText={ + <span> + <span> + <ForwardRef + aria-label="Reset select test setting to default" + data-test-subj="advancedSetting-resetField-select:test:setting" + onClick={[Function]} + > + <FormattedMessage + defaultMessage="Reset to default" + id="advancedSettings.field.resetToDefaultLinkText" + values={Object {}} + /> + </ForwardRef> + + </span> + </span> + } + label="select:test:setting" + labelType="label" + > + <EuiSelect + aria-label="select test setting" + data-test-subj="advancedSetting-editField-select:test:setting" + disabled={false} + fullWidth={true} + onChange={[Function]} + options={ + Array [ + Object { + "text": "Apple", + "value": "apple", + }, + Object { + "text": "Orange", + "value": "orange", + }, + Object { + "text": "banana", + "value": "banana", + }, + ] + } + value="banana" + /> + </EuiFormRow> +</EuiDescribedFormGroup> `; exports[`Field for string setting should render as read only if saving is disabled 1`] = ` -<EuiFlexGroup +<EuiDescribedFormGroup className="mgtAdvancedSettings__field" + description={ + <React.Fragment> + <div + dangerouslySetInnerHTML={ + Object { + "__html": "Description for String test setting", + } + } + /> + </React.Fragment> + } + fullWidth={true} + title={ + <h3> + String test setting + + </h3> + } > - <EuiFlexItem - grow={false} + <EuiFormRow + className="mgtAdvancedSettings__fieldRow" + describedByIds={Array []} + display="row" + fullWidth={true} + hasChildLabel={true} + hasEmptyLabelSpace={false} + helpText={null} + label="string:test:setting" + labelType="label" > - <EuiDescribedFormGroup - className="mgtAdvancedSettings__fieldWrapper" - description={ - <React.Fragment> - <div - dangerouslySetInnerHTML={ - Object { - "__html": "Description for String test setting", - } - } - /> - </React.Fragment> - } - title={ - <h3> - String test setting - - </h3> - } - > - <EuiFormRow - className="mgtAdvancedSettings__fieldRow" - describedByIds={ - Array [ - "string:test:setting-aria", - ] - } - display="row" - error={null} - fullWidth={false} - hasChildLabel={true} - hasEmptyLabelSpace={false} - helpText={null} - isInvalid={false} - label="string:test:setting" - labelType="label" - > - <EuiFieldText - aria-label="string test setting" - data-test-subj="advancedSetting-editField-string:test:setting" - disabled={true} - isLoading={false} - onChange={[Function]} - onKeyDown={[Function]} - value="" - /> - </EuiFormRow> - </EuiDescribedFormGroup> - </EuiFlexItem> - <EuiFlexItem - grow={false} - /> -</EuiFlexGroup> + <EuiFieldText + aria-label="string test setting" + data-test-subj="advancedSetting-editField-string:test:setting" + disabled={true} + fullWidth={true} + onChange={[Function]} + value="" + /> + </EuiFormRow> +</EuiDescribedFormGroup> `; exports[`Field for string setting should render as read only with help text if overridden 1`] = ` -<EuiFlexGroup +<EuiDescribedFormGroup className="mgtAdvancedSettings__field" -> - <EuiFlexItem - grow={false} - > - <EuiDescribedFormGroup - className="mgtAdvancedSettings__fieldWrapper" - description={ - <React.Fragment> - <div - dangerouslySetInnerHTML={ - Object { - "__html": "Description for String test setting", - } - } - /> + description={ + <React.Fragment> + <div + dangerouslySetInnerHTML={ + Object { + "__html": "Description for String test setting", + } + } + /> + <React.Fragment> + <EuiSpacer + size="s" + /> + <EuiText + size="xs" + > <React.Fragment> - <EuiSpacer - size="s" - /> - <EuiText - size="xs" - > - <React.Fragment> - <FormattedMessage - defaultMessage="Default: {value}" - id="advancedSettings.field.defaultValueText" - values={ - Object { - "value": <EuiCode> - null - </EuiCode>, - } - } - /> - </React.Fragment> - </EuiText> - </React.Fragment> - </React.Fragment> - } - title={ - <h3> - String test setting - - </h3> - } - > - <EuiFormRow - className="mgtAdvancedSettings__fieldRow" - describedByIds={ - Array [ - "string:test:setting-aria", - ] - } - display="row" - error={null} - fullWidth={false} - hasChildLabel={true} - hasEmptyLabelSpace={false} - helpText={ - <EuiText - size="xs" - > <FormattedMessage - defaultMessage="This setting is overridden by the Kibana server and can not be changed." - id="advancedSettings.field.helpText" - values={Object {}} + defaultMessage="Default: {value}" + id="advancedSettings.field.defaultValueText" + values={ + Object { + "value": <EuiCode> + null + </EuiCode>, + } + } /> - </EuiText> - } - isInvalid={false} - label="string:test:setting" - labelType="label" + </React.Fragment> + </EuiText> + </React.Fragment> + </React.Fragment> + } + fullWidth={true} + title={ + <h3> + String test setting + + </h3> + } +> + <EuiFormRow + className="mgtAdvancedSettings__fieldRow" + describedByIds={Array []} + display="row" + fullWidth={true} + hasChildLabel={true} + hasEmptyLabelSpace={false} + helpText={ + <EuiText + size="xs" > - <EuiFieldText - aria-label="string test setting" - data-test-subj="advancedSetting-editField-string:test:setting" - disabled={true} - isLoading={false} - onChange={[Function]} - onKeyDown={[Function]} - value="foo" + <FormattedMessage + defaultMessage="This setting is overridden by the Kibana server and can not be changed." + id="advancedSettings.field.helpText" + values={Object {}} /> - </EuiFormRow> - </EuiDescribedFormGroup> - </EuiFlexItem> - <EuiFlexItem - grow={false} - /> -</EuiFlexGroup> + </EuiText> + } + label="string:test:setting" + labelType="label" + > + <EuiFieldText + aria-label="string test setting" + data-test-subj="advancedSetting-editField-string:test:setting" + disabled={true} + fullWidth={true} + onChange={[Function]} + value="foo" + /> + </EuiFormRow> +</EuiDescribedFormGroup> `; exports[`Field for string setting should render custom setting icon if it is custom 1`] = ` -<EuiFlexGroup +<EuiDescribedFormGroup className="mgtAdvancedSettings__field" + description={ + <React.Fragment> + <div + dangerouslySetInnerHTML={ + Object { + "__html": "Description for String test setting", + } + } + /> + </React.Fragment> + } + fullWidth={true} + title={ + <h3> + String test setting + <EuiIconTip + aria-label="Custom setting" + color="primary" + content={ + <FormattedMessage + defaultMessage="Custom setting" + id="advancedSettings.field.customSettingTooltip" + values={Object {}} + /> + } + type="asterisk" + /> + </h3> + } > - <EuiFlexItem - grow={false} + <EuiFormRow + className="mgtAdvancedSettings__fieldRow" + describedByIds={Array []} + display="row" + fullWidth={true} + hasChildLabel={true} + hasEmptyLabelSpace={false} + helpText={null} + label="string:test:setting" + labelType="label" > - <EuiDescribedFormGroup - className="mgtAdvancedSettings__fieldWrapper" - description={ - <React.Fragment> - <div - dangerouslySetInnerHTML={ - Object { - "__html": "Description for String test setting", - } - } - /> - </React.Fragment> - } - title={ - <h3> - String test setting - <EuiIconTip - aria-label="Custom setting" - color="primary" - content={ - <FormattedMessage - defaultMessage="Custom setting" - id="advancedSettings.field.customSettingTooltip" - values={Object {}} - /> - } - type="asterisk" - /> - </h3> - } - > - <EuiFormRow - className="mgtAdvancedSettings__fieldRow" - describedByIds={ - Array [ - "string:test:setting-aria", - ] - } - display="row" - error={null} - fullWidth={false} - hasChildLabel={true} - hasEmptyLabelSpace={false} - helpText={null} - isInvalid={false} - label="string:test:setting" - labelType="label" - > - <EuiFieldText - aria-label="string test setting" - data-test-subj="advancedSetting-editField-string:test:setting" - disabled={false} - isLoading={false} - onChange={[Function]} - onKeyDown={[Function]} - value="" - /> - </EuiFormRow> - </EuiDescribedFormGroup> - </EuiFlexItem> - <EuiFlexItem - grow={false} - /> -</EuiFlexGroup> + <EuiFieldText + aria-label="string test setting" + data-test-subj="advancedSetting-editField-string:test:setting" + disabled={false} + fullWidth={true} + onChange={[Function]} + value="" + /> + </EuiFormRow> +</EuiDescribedFormGroup> `; exports[`Field for string setting should render default value if there is no user value set 1`] = ` -<EuiFlexGroup +<EuiDescribedFormGroup className="mgtAdvancedSettings__field" + description={ + <React.Fragment> + <div + dangerouslySetInnerHTML={ + Object { + "__html": "Description for String test setting", + } + } + /> + </React.Fragment> + } + fullWidth={true} + title={ + <h3> + String test setting + + </h3> + } > - <EuiFlexItem - grow={false} + <EuiFormRow + className="mgtAdvancedSettings__fieldRow" + describedByIds={Array []} + display="row" + fullWidth={true} + hasChildLabel={true} + hasEmptyLabelSpace={false} + helpText={null} + label="string:test:setting" + labelType="label" > - <EuiDescribedFormGroup - className="mgtAdvancedSettings__fieldWrapper" - description={ - <React.Fragment> - <div - dangerouslySetInnerHTML={ - Object { - "__html": "Description for String test setting", - } - } - /> - </React.Fragment> - } - title={ - <h3> - String test setting - - </h3> - } - > - <EuiFormRow - className="mgtAdvancedSettings__fieldRow" - describedByIds={ - Array [ - "string:test:setting-aria", - ] - } - display="row" - error={null} - fullWidth={false} - hasChildLabel={true} - hasEmptyLabelSpace={false} - helpText={null} - isInvalid={false} - label="string:test:setting" - labelType="label" + <EuiFieldText + aria-label="string test setting" + data-test-subj="advancedSetting-editField-string:test:setting" + disabled={false} + fullWidth={true} + onChange={[Function]} + value="" + /> + </EuiFormRow> +</EuiDescribedFormGroup> +`; + +exports[`Field for string setting should render unsaved value if there are unsaved changes 1`] = ` +<EuiDescribedFormGroup + className="mgtAdvancedSettings__field mgtAdvancedSettings__field--unsaved" + description={ + <React.Fragment> + <div + dangerouslySetInnerHTML={ + Object { + "__html": "Description for String test setting", + } + } + /> + </React.Fragment> + } + fullWidth={true} + title={ + <h3> + String test setting + <EuiIconTip + aria-label="Custom setting" + color="primary" + content={ + <FormattedMessage + defaultMessage="Custom setting" + id="advancedSettings.field.customSettingTooltip" + values={Object {}} + /> + } + type="asterisk" + /> + </h3> + } +> + <EuiFormRow + className="mgtAdvancedSettings__fieldRow" + describedByIds={Array []} + display="row" + fullWidth={true} + hasChildLabel={true} + hasEmptyLabelSpace={false} + helpText={null} + label="string:test:setting" + labelType="label" + > + <EuiFieldText + aria-describedby="string:test:setting" + aria-label="string test setting" + data-test-subj="advancedSetting-editField-string:test:setting" + disabled={false} + fullWidth={true} + onChange={[Function]} + value="hello world" + /> + <EuiScreenReaderOnly> + <p + id="string:test:setting" > - <EuiFieldText - aria-label="string test setting" - data-test-subj="advancedSetting-editField-string:test:setting" - disabled={false} - isLoading={false} - onChange={[Function]} - onKeyDown={[Function]} - value="" - /> - </EuiFormRow> - </EuiDescribedFormGroup> - </EuiFlexItem> - <EuiFlexItem - grow={false} - /> -</EuiFlexGroup> + Setting is currently not saved. + </p> + </EuiScreenReaderOnly> + </EuiFormRow> +</EuiDescribedFormGroup> `; exports[`Field for string setting should render user value if there is user value is set 1`] = ` -<EuiFlexGroup +<EuiDescribedFormGroup className="mgtAdvancedSettings__field" -> - <EuiFlexItem - grow={false} - > - <EuiDescribedFormGroup - className="mgtAdvancedSettings__fieldWrapper" - description={ - <React.Fragment> - <div - dangerouslySetInnerHTML={ - Object { - "__html": "Description for String test setting", - } - } - /> + description={ + <React.Fragment> + <div + dangerouslySetInnerHTML={ + Object { + "__html": "Description for String test setting", + } + } + /> + <React.Fragment> + <EuiSpacer + size="s" + /> + <EuiText + size="xs" + > <React.Fragment> - <EuiSpacer - size="s" + <FormattedMessage + defaultMessage="Default: {value}" + id="advancedSettings.field.defaultValueText" + values={ + Object { + "value": <EuiCode> + null + </EuiCode>, + } + } /> - <EuiText - size="xs" - > - <React.Fragment> - <FormattedMessage - defaultMessage="Default: {value}" - id="advancedSettings.field.defaultValueText" - values={ - Object { - "value": <EuiCode> - null - </EuiCode>, - } - } - /> - </React.Fragment> - </EuiText> </React.Fragment> - </React.Fragment> - } - title={ - <h3> - String test setting - - </h3> - } - > - <EuiFormRow - className="mgtAdvancedSettings__fieldRow" - describedByIds={ - Array [ - "string:test:setting-aria", - ] - } - display="row" - error={null} - fullWidth={false} - hasChildLabel={true} - hasEmptyLabelSpace={false} - helpText={ - <span> - <span> - <ForwardRef - aria-label="Reset string test setting to default" - data-test-subj="advancedSetting-resetField-string:test:setting" - onClick={[Function]} - > - <FormattedMessage - defaultMessage="Reset to default" - id="advancedSettings.field.resetToDefaultLinkText" - values={Object {}} - /> - </ForwardRef> - - </span> - </span> - } - isInvalid={false} - label="string:test:setting" - labelType="label" - > - <EuiFieldText - aria-label="string test setting" - data-test-subj="advancedSetting-editField-string:test:setting" - disabled={false} - isLoading={false} - onChange={[Function]} - onKeyDown={[Function]} - value="foo" - /> - </EuiFormRow> - </EuiDescribedFormGroup> - </EuiFlexItem> - <EuiFlexItem - grow={false} - /> -</EuiFlexGroup> + </EuiText> + </React.Fragment> + </React.Fragment> + } + fullWidth={true} + title={ + <h3> + String test setting + + </h3> + } +> + <EuiFormRow + className="mgtAdvancedSettings__fieldRow" + describedByIds={Array []} + display="row" + fullWidth={true} + hasChildLabel={true} + hasEmptyLabelSpace={false} + helpText={ + <span> + <span> + <ForwardRef + aria-label="Reset string test setting to default" + data-test-subj="advancedSetting-resetField-string:test:setting" + onClick={[Function]} + > + <FormattedMessage + defaultMessage="Reset to default" + id="advancedSettings.field.resetToDefaultLinkText" + values={Object {}} + /> + </ForwardRef> + + </span> + </span> + } + label="string:test:setting" + labelType="label" + > + <EuiFieldText + aria-label="string test setting" + data-test-subj="advancedSetting-editField-string:test:setting" + disabled={false} + fullWidth={true} + onChange={[Function]} + value="foo" + /> + </EuiFormRow> +</EuiDescribedFormGroup> `; exports[`Field for stringWithValidation setting should render as read only if saving is disabled 1`] = ` -<EuiFlexGroup +<EuiDescribedFormGroup className="mgtAdvancedSettings__field" + description={ + <React.Fragment> + <div + dangerouslySetInnerHTML={ + Object { + "__html": "Description for String test validation setting", + } + } + /> + </React.Fragment> + } + fullWidth={true} + title={ + <h3> + String test validation setting + + </h3> + } > - <EuiFlexItem - grow={false} + <EuiFormRow + className="mgtAdvancedSettings__fieldRow" + describedByIds={Array []} + display="row" + fullWidth={true} + hasChildLabel={true} + hasEmptyLabelSpace={false} + helpText={null} + label="string:test-validation:setting" + labelType="label" > - <EuiDescribedFormGroup - className="mgtAdvancedSettings__fieldWrapper" - description={ - <React.Fragment> - <div - dangerouslySetInnerHTML={ - Object { - "__html": "Description for String test validation setting", - } - } - /> - </React.Fragment> - } - title={ - <h3> - String test validation setting - - </h3> - } - > - <EuiFormRow - className="mgtAdvancedSettings__fieldRow" - describedByIds={ - Array [ - "string:test-validation:setting-aria", - ] - } - display="row" - error={null} - fullWidth={false} - hasChildLabel={true} - hasEmptyLabelSpace={false} - helpText={null} - isInvalid={false} - label="string:test-validation:setting" - labelType="label" - > - <EuiFieldText - aria-label="string test validation setting" - data-test-subj="advancedSetting-editField-string:test-validation:setting" - disabled={true} - isLoading={false} - onChange={[Function]} - onKeyDown={[Function]} - value="foo-default" - /> - </EuiFormRow> - </EuiDescribedFormGroup> - </EuiFlexItem> - <EuiFlexItem - grow={false} - /> -</EuiFlexGroup> + <EuiFieldText + aria-label="string test validation setting" + data-test-subj="advancedSetting-editField-string:test-validation:setting" + disabled={true} + fullWidth={true} + onChange={[Function]} + value="foo-default" + /> + </EuiFormRow> +</EuiDescribedFormGroup> `; exports[`Field for stringWithValidation setting should render as read only with help text if overridden 1`] = ` -<EuiFlexGroup +<EuiDescribedFormGroup className="mgtAdvancedSettings__field" -> - <EuiFlexItem - grow={false} - > - <EuiDescribedFormGroup - className="mgtAdvancedSettings__fieldWrapper" - description={ - <React.Fragment> - <div - dangerouslySetInnerHTML={ - Object { - "__html": "Description for String test validation setting", - } - } - /> + description={ + <React.Fragment> + <div + dangerouslySetInnerHTML={ + Object { + "__html": "Description for String test validation setting", + } + } + /> + <React.Fragment> + <EuiSpacer + size="s" + /> + <EuiText + size="xs" + > <React.Fragment> - <EuiSpacer - size="s" - /> - <EuiText - size="xs" - > - <React.Fragment> - <FormattedMessage - defaultMessage="Default: {value}" - id="advancedSettings.field.defaultValueText" - values={ - Object { - "value": <EuiCode> - foo-default - </EuiCode>, - } - } - /> - </React.Fragment> - </EuiText> - </React.Fragment> - </React.Fragment> - } - title={ - <h3> - String test validation setting - - </h3> - } - > - <EuiFormRow - className="mgtAdvancedSettings__fieldRow" - describedByIds={ - Array [ - "string:test-validation:setting-aria", - ] - } - display="row" - error={null} - fullWidth={false} - hasChildLabel={true} - hasEmptyLabelSpace={false} - helpText={ - <EuiText - size="xs" - > <FormattedMessage - defaultMessage="This setting is overridden by the Kibana server and can not be changed." - id="advancedSettings.field.helpText" - values={Object {}} + defaultMessage="Default: {value}" + id="advancedSettings.field.defaultValueText" + values={ + Object { + "value": <EuiCode> + foo-default + </EuiCode>, + } + } /> - </EuiText> - } - isInvalid={false} - label="string:test-validation:setting" - labelType="label" + </React.Fragment> + </EuiText> + </React.Fragment> + </React.Fragment> + } + fullWidth={true} + title={ + <h3> + String test validation setting + + </h3> + } +> + <EuiFormRow + className="mgtAdvancedSettings__fieldRow" + describedByIds={Array []} + display="row" + fullWidth={true} + hasChildLabel={true} + hasEmptyLabelSpace={false} + helpText={ + <EuiText + size="xs" > - <EuiFieldText - aria-label="string test validation setting" - data-test-subj="advancedSetting-editField-string:test-validation:setting" - disabled={true} - isLoading={false} - onChange={[Function]} - onKeyDown={[Function]} - value="fooUserValue" + <FormattedMessage + defaultMessage="This setting is overridden by the Kibana server and can not be changed." + id="advancedSettings.field.helpText" + values={Object {}} /> - </EuiFormRow> - </EuiDescribedFormGroup> - </EuiFlexItem> - <EuiFlexItem - grow={false} - /> -</EuiFlexGroup> + </EuiText> + } + label="string:test-validation:setting" + labelType="label" + > + <EuiFieldText + aria-label="string test validation setting" + data-test-subj="advancedSetting-editField-string:test-validation:setting" + disabled={true} + fullWidth={true} + onChange={[Function]} + value="fooUserValue" + /> + </EuiFormRow> +</EuiDescribedFormGroup> `; exports[`Field for stringWithValidation setting should render custom setting icon if it is custom 1`] = ` -<EuiFlexGroup +<EuiDescribedFormGroup className="mgtAdvancedSettings__field" + description={ + <React.Fragment> + <div + dangerouslySetInnerHTML={ + Object { + "__html": "Description for String test validation setting", + } + } + /> + </React.Fragment> + } + fullWidth={true} + title={ + <h3> + String test validation setting + <EuiIconTip + aria-label="Custom setting" + color="primary" + content={ + <FormattedMessage + defaultMessage="Custom setting" + id="advancedSettings.field.customSettingTooltip" + values={Object {}} + /> + } + type="asterisk" + /> + </h3> + } > - <EuiFlexItem - grow={false} + <EuiFormRow + className="mgtAdvancedSettings__fieldRow" + describedByIds={Array []} + display="row" + fullWidth={true} + hasChildLabel={true} + hasEmptyLabelSpace={false} + helpText={null} + label="string:test-validation:setting" + labelType="label" > - <EuiDescribedFormGroup - className="mgtAdvancedSettings__fieldWrapper" - description={ - <React.Fragment> - <div - dangerouslySetInnerHTML={ - Object { - "__html": "Description for String test validation setting", - } - } - /> - </React.Fragment> - } - title={ - <h3> - String test validation setting - <EuiIconTip - aria-label="Custom setting" - color="primary" - content={ - <FormattedMessage - defaultMessage="Custom setting" - id="advancedSettings.field.customSettingTooltip" - values={Object {}} - /> - } - type="asterisk" - /> - </h3> - } - > - <EuiFormRow - className="mgtAdvancedSettings__fieldRow" - describedByIds={ - Array [ - "string:test-validation:setting-aria", - ] - } - display="row" - error={null} - fullWidth={false} - hasChildLabel={true} - hasEmptyLabelSpace={false} - helpText={null} - isInvalid={false} - label="string:test-validation:setting" - labelType="label" - > - <EuiFieldText - aria-label="string test validation setting" - data-test-subj="advancedSetting-editField-string:test-validation:setting" - disabled={false} - isLoading={false} - onChange={[Function]} - onKeyDown={[Function]} - value="foo-default" - /> - </EuiFormRow> - </EuiDescribedFormGroup> - </EuiFlexItem> - <EuiFlexItem - grow={false} - /> -</EuiFlexGroup> + <EuiFieldText + aria-label="string test validation setting" + data-test-subj="advancedSetting-editField-string:test-validation:setting" + disabled={false} + fullWidth={true} + onChange={[Function]} + value="foo-default" + /> + </EuiFormRow> +</EuiDescribedFormGroup> `; exports[`Field for stringWithValidation setting should render default value if there is no user value set 1`] = ` -<EuiFlexGroup +<EuiDescribedFormGroup className="mgtAdvancedSettings__field" + description={ + <React.Fragment> + <div + dangerouslySetInnerHTML={ + Object { + "__html": "Description for String test validation setting", + } + } + /> + </React.Fragment> + } + fullWidth={true} + title={ + <h3> + String test validation setting + + </h3> + } > - <EuiFlexItem - grow={false} + <EuiFormRow + className="mgtAdvancedSettings__fieldRow" + describedByIds={Array []} + display="row" + fullWidth={true} + hasChildLabel={true} + hasEmptyLabelSpace={false} + helpText={null} + label="string:test-validation:setting" + labelType="label" > - <EuiDescribedFormGroup - className="mgtAdvancedSettings__fieldWrapper" - description={ - <React.Fragment> - <div - dangerouslySetInnerHTML={ - Object { - "__html": "Description for String test validation setting", - } - } - /> - </React.Fragment> - } - title={ - <h3> - String test validation setting - - </h3> - } - > - <EuiFormRow - className="mgtAdvancedSettings__fieldRow" - describedByIds={ - Array [ - "string:test-validation:setting-aria", - ] - } - display="row" - error={null} - fullWidth={false} - hasChildLabel={true} - hasEmptyLabelSpace={false} - helpText={null} - isInvalid={false} - label="string:test-validation:setting" - labelType="label" + <EuiFieldText + aria-label="string test validation setting" + data-test-subj="advancedSetting-editField-string:test-validation:setting" + disabled={false} + fullWidth={true} + onChange={[Function]} + value="foo-default" + /> + </EuiFormRow> +</EuiDescribedFormGroup> +`; + +exports[`Field for stringWithValidation setting should render unsaved value if there are unsaved changes 1`] = ` +<EuiDescribedFormGroup + className="mgtAdvancedSettings__field mgtAdvancedSettings__field--unsaved" + description={ + <React.Fragment> + <div + dangerouslySetInnerHTML={ + Object { + "__html": "Description for String test validation setting", + } + } + /> + </React.Fragment> + } + fullWidth={true} + title={ + <h3> + String test validation setting + <EuiIconTip + aria-label="Custom setting" + color="primary" + content={ + <FormattedMessage + defaultMessage="Custom setting" + id="advancedSettings.field.customSettingTooltip" + values={Object {}} + /> + } + type="asterisk" + /> + </h3> + } +> + <EuiFormRow + className="mgtAdvancedSettings__fieldRow" + describedByIds={Array []} + display="row" + fullWidth={true} + hasChildLabel={true} + hasEmptyLabelSpace={false} + helpText={null} + label="string:test-validation:setting" + labelType="label" + > + <EuiFieldText + aria-describedby="string:test-validation:setting" + aria-label="string test validation setting" + data-test-subj="advancedSetting-editField-string:test-validation:setting" + disabled={false} + fullWidth={true} + onChange={[Function]} + value="hello world" + /> + <EuiScreenReaderOnly> + <p + id="string:test-validation:setting" > - <EuiFieldText - aria-label="string test validation setting" - data-test-subj="advancedSetting-editField-string:test-validation:setting" - disabled={false} - isLoading={false} - onChange={[Function]} - onKeyDown={[Function]} - value="foo-default" - /> - </EuiFormRow> - </EuiDescribedFormGroup> - </EuiFlexItem> - <EuiFlexItem - grow={false} - /> -</EuiFlexGroup> + Setting is currently not saved. + </p> + </EuiScreenReaderOnly> + </EuiFormRow> +</EuiDescribedFormGroup> `; exports[`Field for stringWithValidation setting should render user value if there is user value is set 1`] = ` -<EuiFlexGroup +<EuiDescribedFormGroup className="mgtAdvancedSettings__field" -> - <EuiFlexItem - grow={false} - > - <EuiDescribedFormGroup - className="mgtAdvancedSettings__fieldWrapper" - description={ - <React.Fragment> - <div - dangerouslySetInnerHTML={ - Object { - "__html": "Description for String test validation setting", - } - } - /> + description={ + <React.Fragment> + <div + dangerouslySetInnerHTML={ + Object { + "__html": "Description for String test validation setting", + } + } + /> + <React.Fragment> + <EuiSpacer + size="s" + /> + <EuiText + size="xs" + > <React.Fragment> - <EuiSpacer - size="s" + <FormattedMessage + defaultMessage="Default: {value}" + id="advancedSettings.field.defaultValueText" + values={ + Object { + "value": <EuiCode> + foo-default + </EuiCode>, + } + } /> - <EuiText - size="xs" - > - <React.Fragment> - <FormattedMessage - defaultMessage="Default: {value}" - id="advancedSettings.field.defaultValueText" - values={ - Object { - "value": <EuiCode> - foo-default - </EuiCode>, - } - } - /> - </React.Fragment> - </EuiText> </React.Fragment> - </React.Fragment> - } - title={ - <h3> - String test validation setting - - </h3> - } - > - <EuiFormRow - className="mgtAdvancedSettings__fieldRow" - describedByIds={ - Array [ - "string:test-validation:setting-aria", - ] - } - display="row" - error={null} - fullWidth={false} - hasChildLabel={true} - hasEmptyLabelSpace={false} - helpText={ - <span> - <span> - <ForwardRef - aria-label="Reset string test validation setting to default" - data-test-subj="advancedSetting-resetField-string:test-validation:setting" - onClick={[Function]} - > - <FormattedMessage - defaultMessage="Reset to default" - id="advancedSettings.field.resetToDefaultLinkText" - values={Object {}} - /> - </ForwardRef> - - </span> - </span> - } - isInvalid={false} - label="string:test-validation:setting" - labelType="label" - > - <EuiFieldText - aria-label="string test validation setting" - data-test-subj="advancedSetting-editField-string:test-validation:setting" - disabled={false} - isLoading={false} - onChange={[Function]} - onKeyDown={[Function]} - value="fooUserValue" - /> - </EuiFormRow> - </EuiDescribedFormGroup> - </EuiFlexItem> - <EuiFlexItem - grow={false} - /> -</EuiFlexGroup> + </EuiText> + </React.Fragment> + </React.Fragment> + } + fullWidth={true} + title={ + <h3> + String test validation setting + + </h3> + } +> + <EuiFormRow + className="mgtAdvancedSettings__fieldRow" + describedByIds={Array []} + display="row" + fullWidth={true} + hasChildLabel={true} + hasEmptyLabelSpace={false} + helpText={ + <span> + <span> + <ForwardRef + aria-label="Reset string test validation setting to default" + data-test-subj="advancedSetting-resetField-string:test-validation:setting" + onClick={[Function]} + > + <FormattedMessage + defaultMessage="Reset to default" + id="advancedSettings.field.resetToDefaultLinkText" + values={Object {}} + /> + </ForwardRef> + + </span> + </span> + } + label="string:test-validation:setting" + labelType="label" + > + <EuiFieldText + aria-label="string test validation setting" + data-test-subj="advancedSetting-editField-string:test-validation:setting" + disabled={false} + fullWidth={true} + onChange={[Function]} + value="fooUserValue" + /> + </EuiFormRow> +</EuiDescribedFormGroup> `; diff --git a/src/plugins/advanced_settings/public/management_app/components/field/field.test.tsx b/src/plugins/advanced_settings/public/management_app/components/field/field.test.tsx index 81df22ccf6e43..8e41fed685898 100644 --- a/src/plugins/advanced_settings/public/management_app/components/field/field.test.tsx +++ b/src/plugins/advanced_settings/public/management_app/components/field/field.test.tsx @@ -20,21 +20,14 @@ import React from 'react'; import { I18nProvider } from '@kbn/i18n/react'; import { shallowWithI18nProvider, mountWithI18nProvider } from 'test_utils/enzyme_helpers'; -import { mount } from 'enzyme'; +import { mount, ReactWrapper } from 'enzyme'; import { FieldSetting } from '../../types'; import { UiSettingsType, StringValidation } from '../../../../../../core/public'; import { notificationServiceMock, docLinksServiceMock } from '../../../../../../core/public/mocks'; // @ts-ignore import { findTestSubject } from '@elastic/eui/lib/test'; -import { Field } from './field'; - -jest.mock('ui/notify', () => ({ - toastNotifications: { - addDanger: () => {}, - add: jest.fn(), - }, -})); +import { Field, getEditableValue } from './field'; jest.mock('brace/theme/textmate', () => 'brace/theme/textmate'); jest.mock('brace/mode/markdown', () => 'brace/mode/markdown'); @@ -45,6 +38,18 @@ const defaults = { category: ['category'], }; +const exampleValues = { + array: ['example_value'], + boolean: false, + image: 'data:image/gif;base64,R0lGODlhAQABAIAAAAUEBAAAACwAAAAAAQABAAACAkQBADs=', + json: { foo: 'bar2' }, + markdown: 'Hello World', + number: 1, + select: 'banana', + string: 'hello world', + stringWithValidation: 'foo', +}; + const settings: Record<string, FieldSetting> = { array: { name: 'array:test:setting', @@ -161,7 +166,7 @@ const settings: Record<string, FieldSetting> = { description: 'Description for String test validation setting', type: 'string', validation: { - regex: new RegExp('/^foo'), + regex: new RegExp('^foo'), message: 'must start with "foo"', }, value: undefined, @@ -182,11 +187,22 @@ const userValues = { string: 'foo', stringWithValidation: 'fooUserValue', }; + const invalidUserValues = { stringWithValidation: 'invalidUserValue', }; -const save = jest.fn(() => Promise.resolve(true)); -const clear = jest.fn(() => Promise.resolve(true)); + +const handleChange = jest.fn(); +const clearChange = jest.fn(); + +const getFieldSettingValue = (wrapper: ReactWrapper, name: string, type: string) => { + const field = findTestSubject(wrapper, `advancedSetting-editField-${name}`); + if (type === 'boolean') { + return field.props()['aria-checked']; + } else { + return field.props().value; + } +}; describe('Field', () => { Object.keys(settings).forEach(type => { @@ -197,8 +213,7 @@ describe('Field', () => { const component = shallowWithI18nProvider( <Field setting={setting} - save={save} - clear={clear} + handleChange={handleChange} enableSaving={true} toasts={notificationServiceMock.createStartContract().toasts} dockLinks={docLinksServiceMock.createStartContract().links} @@ -217,8 +232,7 @@ describe('Field', () => { value: userValues[type], isOverridden: true, }} - save={save} - clear={clear} + handleChange={handleChange} enableSaving={true} toasts={notificationServiceMock.createStartContract().toasts} dockLinks={docLinksServiceMock.createStartContract().links} @@ -232,14 +246,12 @@ describe('Field', () => { const component = shallowWithI18nProvider( <Field setting={setting} - save={save} - clear={clear} + handleChange={handleChange} enableSaving={false} toasts={notificationServiceMock.createStartContract().toasts} dockLinks={docLinksServiceMock.createStartContract().links} /> ); - expect(component).toMatchSnapshot(); }); @@ -251,8 +263,7 @@ describe('Field', () => { // @ts-ignore value: userValues[type], }} - save={save} - clear={clear} + handleChange={handleChange} enableSaving={true} toasts={notificationServiceMock.createStartContract().toasts} dockLinks={docLinksServiceMock.createStartContract().links} @@ -269,48 +280,44 @@ describe('Field', () => { ...setting, isCustom: true, }} - save={save} - clear={clear} + handleChange={handleChange} enableSaving={true} toasts={notificationServiceMock.createStartContract().toasts} dockLinks={docLinksServiceMock.createStartContract().links} /> ); - expect(component).toMatchSnapshot(); }); - }); - - if (type === 'select') { - it('should use options for rendering values', () => { - const component = mountWithI18nProvider( + it('should render unsaved value if there are unsaved changes', async () => { + const component = shallowWithI18nProvider( <Field setting={{ ...setting, isCustom: true, }} - save={save} - clear={clear} + handleChange={handleChange} enableSaving={true} toasts={notificationServiceMock.createStartContract().toasts} dockLinks={docLinksServiceMock.createStartContract().links} + unsavedChanges={{ + // @ts-ignore + value: exampleValues[setting.type], + }} /> ); - const select = findTestSubject(component, `advancedSetting-editField-${setting.name}`); - // @ts-ignore - const labels = select.find('option').map(option => option.prop('value')); - expect(labels).toEqual(['apple', 'orange', 'banana']); + expect(component).toMatchSnapshot(); }); + }); - it('should use optionLabels for rendering labels', () => { + if (type === 'select') { + it('should use options for rendering values and optionsLabels for rendering labels', () => { const component = mountWithI18nProvider( <Field setting={{ ...setting, isCustom: true, }} - save={save} - clear={clear} + handleChange={handleChange} enableSaving={true} toasts={notificationServiceMock.createStartContract().toasts} dockLinks={docLinksServiceMock.createStartContract().links} @@ -318,6 +325,9 @@ describe('Field', () => { ); const select = findTestSubject(component, `advancedSetting-editField-${setting.name}`); // @ts-ignore + const values = select.find('option').map(option => option.prop('value')); + expect(values).toEqual(['apple', 'orange', 'banana']); + // @ts-ignore const labels = select.find('option').map(option => option.text()); expect(labels).toEqual(['Apple', 'Orange', 'banana']); }); @@ -328,8 +338,8 @@ describe('Field', () => { <I18nProvider> <Field setting={setting} - save={save} - clear={clear} + clearChange={clearChange} + handleChange={handleChange} enableSaving={true} toasts={notificationServiceMock.createStartContract().toasts} dockLinks={docLinksServiceMock.createStartContract().links} @@ -352,90 +362,52 @@ describe('Field', () => { const userValue = userValues[type]; (component.instance() as Field).getImageAsBase64 = ({}: Blob) => Promise.resolve(''); - it('should be able to change value from no value and cancel', async () => { - await (component.instance() as Field).onImageChange([userValue]); - const updated = wrapper.update(); - findTestSubject(updated, `advancedSetting-cancelEditField-${setting.name}`).simulate( - 'click' - ); - expect( - (component.instance() as Field).state.unsavedValue === - (component.instance() as Field).state.savedValue - ).toBe(true); - }); - - it('should be able to change value and save', async () => { - await (component.instance() as Field).onImageChange([userValue]); - const updated = wrapper.update(); - findTestSubject(updated, `advancedSetting-saveEditField-${setting.name}`).simulate( - 'click' - ); - expect(save).toBeCalled(); - component.setState({ savedValue: userValue }); + it('should be able to change value and cancel', async () => { + (component.instance() as Field).onImageChange([userValue]); + expect(handleChange).toBeCalled(); await wrapper.setProps({ + unsavedChanges: { + value: userValue, + changeImage: true, + }, setting: { ...(component.instance() as Field).props.setting, value: userValue, }, }); - await (component.instance() as Field).cancelChangeImage(); + expect(clearChange).toBeCalledWith(setting.name); wrapper.update(); }); - it('should be able to change value from existing value and save', async () => { + it('should be able to change value from existing value', async () => { + await wrapper.setProps({ + unsavedChanges: {}, + }); const updated = wrapper.update(); findTestSubject(updated, `advancedSetting-changeImage-${setting.name}`).simulate('click'); - const newUserValue = `${userValue}=`; await (component.instance() as Field).onImageChange([newUserValue]); - const updated2 = wrapper.update(); - findTestSubject(updated2, `advancedSetting-saveEditField-${setting.name}`).simulate( - 'click' - ); - expect(save).toBeCalled(); - component.setState({ savedValue: newUserValue }); - await wrapper.setProps({ - setting: { - ...(component.instance() as Field).props.setting, - value: newUserValue, - }, - }); - wrapper.update(); + expect(handleChange).toBeCalled(); }); it('should be able to reset to default value', async () => { const updated = wrapper.update(); findTestSubject(updated, `advancedSetting-resetField-${setting.name}`).simulate('click'); - expect(clear).toBeCalled(); + expect(handleChange).toBeCalledWith(setting.name, { + value: getEditableValue(setting.type, setting.defVal), + changeImage: true, + }); }); }); } else if (type === 'markdown' || type === 'json') { describe(`for changing ${type} setting`, () => { const { wrapper, component } = setup(); const userValue = userValues[type]; - const fieldUserValue = userValue; - - it('should be able to change value and cancel', async () => { - (component.instance() as Field).onCodeEditorChange(fieldUserValue as UiSettingsType); - const updated = wrapper.update(); - findTestSubject(updated, `advancedSetting-cancelEditField-${setting.name}`).simulate( - 'click' - ); - expect( - (component.instance() as Field).state.unsavedValue === - (component.instance() as Field).state.savedValue - ).toBe(true); - }); - it('should be able to change value and save', async () => { - (component.instance() as Field).onCodeEditorChange(fieldUserValue as UiSettingsType); - const updated = wrapper.update(); - findTestSubject(updated, `advancedSetting-saveEditField-${setting.name}`).simulate( - 'click' - ); - expect(save).toBeCalled(); - component.setState({ savedValue: fieldUserValue }); + it('should be able to change value', async () => { + (component.instance() as Field).onCodeEditorChange(userValue as UiSettingsType); + expect(handleChange).toBeCalledWith(setting.name, { value: userValue }); await wrapper.setProps({ setting: { ...(component.instance() as Field).props.setting, @@ -445,19 +417,21 @@ describe('Field', () => { wrapper.update(); }); + it('should be able to reset to default value', async () => { + const updated = wrapper.update(); + findTestSubject(updated, `advancedSetting-resetField-${setting.name}`).simulate('click'); + expect(handleChange).toBeCalledWith(setting.name, { + value: getEditableValue(setting.type, setting.defVal), + }); + }); + if (type === 'json') { it('should be able to clear value and have empty object populate', async () => { - (component.instance() as Field).onCodeEditorChange('' as UiSettingsType); + await (component.instance() as Field).onCodeEditorChange('' as UiSettingsType); wrapper.update(); - expect((component.instance() as Field).state.unsavedValue).toEqual('{}'); + expect(handleChange).toBeCalledWith(setting.name, { value: setting.defVal }); }); } - - it('should be able to reset to default value', async () => { - const updated = wrapper.update(); - findTestSubject(updated, `advancedSetting-resetField-${setting.name}`).simulate('click'); - expect(clear).toBeCalled(); - }); }); } else { describe(`for changing ${type} setting`, () => { @@ -470,76 +444,45 @@ describe('Field', () => { // @ts-ignore const invalidUserValue = invalidUserValues[type]; it('should display an error when validation fails', async () => { - (component.instance() as Field).onFieldChange(invalidUserValue); + await (component.instance() as Field).onFieldChange(invalidUserValue); + const expectedUnsavedChanges = { + value: invalidUserValue, + error: (setting.validation as StringValidation).message, + isInvalid: true, + }; + expect(handleChange).toBeCalledWith(setting.name, expectedUnsavedChanges); + wrapper.setProps({ unsavedChanges: expectedUnsavedChanges }); const updated = wrapper.update(); const errorMessage = updated.find('.euiFormErrorText').text(); - expect(errorMessage).toEqual((setting.validation as StringValidation).message); + expect(errorMessage).toEqual(expectedUnsavedChanges.error); }); } - it('should be able to change value and cancel', async () => { - (component.instance() as Field).onFieldChange(fieldUserValue); + it('should be able to change value', async () => { + await (component.instance() as Field).onFieldChange(fieldUserValue); const updated = wrapper.update(); - findTestSubject(updated, `advancedSetting-cancelEditField-${setting.name}`).simulate( - 'click' - ); - expect( - (component.instance() as Field).state.unsavedValue === - (component.instance() as Field).state.savedValue - ).toBe(true); + expect(handleChange).toBeCalledWith(setting.name, { value: fieldUserValue }); + updated.setProps({ unsavedChanges: { value: fieldUserValue } }); + const currentValue = getFieldSettingValue(updated, setting.name, type); + expect(currentValue).toEqual(fieldUserValue); }); - it('should be able to change value and save', async () => { - (component.instance() as Field).onFieldChange(fieldUserValue); - const updated = wrapper.update(); - findTestSubject(updated, `advancedSetting-saveEditField-${setting.name}`).simulate( - 'click' - ); - expect(save).toBeCalled(); - component.setState({ savedValue: fieldUserValue }); + it('should be able to reset to default value', async () => { await wrapper.setProps({ - setting: { - ...(component.instance() as Field).props.setting, - value: userValue, - }, + unsavedChanges: {}, + setting: { ...setting, value: fieldUserValue }, }); - wrapper.update(); - }); - - it('should be able to reset to default value', async () => { const updated = wrapper.update(); findTestSubject(updated, `advancedSetting-resetField-${setting.name}`).simulate('click'); - expect(clear).toBeCalled(); + const expectedEditableValue = getEditableValue(setting.type, setting.defVal); + expect(handleChange).toBeCalledWith(setting.name, { + value: expectedEditableValue, + }); + updated.setProps({ unsavedChanges: { value: expectedEditableValue } }); + const currentValue = getFieldSettingValue(updated, setting.name, type); + expect(currentValue).toEqual(expectedEditableValue); }); }); } }); - - it('should show a reload toast when saving setting requiring a page reload', async () => { - const setting = { - ...settings.string, - requiresPageReload: true, - }; - const toasts = notificationServiceMock.createStartContract().toasts; - const wrapper = mountWithI18nProvider( - <Field - setting={setting} - save={save} - clear={clear} - enableSaving={true} - toasts={toasts} - dockLinks={docLinksServiceMock.createStartContract().links} - /> - ); - (wrapper.instance() as Field).onFieldChange({ target: { value: 'a new value' } }); - const updated = wrapper.update(); - findTestSubject(updated, `advancedSetting-saveEditField-${setting.name}`).simulate('click'); - expect(save).toHaveBeenCalled(); - await save(); - expect(toasts.add).toHaveBeenCalledWith( - expect.objectContaining({ - title: expect.stringContaining('Please reload the page'), - }) - ); - }); }); diff --git a/src/plugins/advanced_settings/public/management_app/components/field/field.tsx b/src/plugins/advanced_settings/public/management_app/components/field/field.tsx index 7158e3d5e7b3e..d9c3752d1c0a5 100644 --- a/src/plugins/advanced_settings/public/management_app/components/field/field.tsx +++ b/src/plugins/advanced_settings/public/management_app/components/field/field.tsx @@ -18,17 +18,16 @@ */ import React, { PureComponent, Fragment } from 'react'; -import ReactDOM from 'react-dom'; +import classNames from 'classnames'; import 'brace/theme/textmate'; import 'brace/mode/markdown'; import { EuiBadge, - EuiButton, - EuiButtonEmpty, EuiCode, EuiCodeBlock, + EuiScreenReaderOnly, // @ts-ignore EuiCodeEditor, EuiDescribedFormGroup, @@ -36,23 +35,20 @@ import { EuiFieldText, // @ts-ignore EuiFilePicker, - EuiFlexGroup, - EuiFlexItem, EuiFormRow, EuiIconTip, EuiImage, EuiLink, EuiSpacer, - EuiToolTip, EuiText, EuiSelect, EuiSwitch, EuiSwitchEvent, - keyCodes, + EuiToolTip, } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n/react'; -import { FieldSetting } from '../../types'; +import { FieldSetting, FieldState } from '../../types'; import { isDefaultValue } from '../../lib'; import { UiSettingsType, @@ -64,71 +60,37 @@ import { interface FieldProps { setting: FieldSetting; - save: (name: string, value: string) => Promise<boolean>; - clear: (name: string) => Promise<boolean>; + handleChange: (name: string, value: FieldState) => void; enableSaving: boolean; dockLinks: DocLinksStart['links']; toasts: ToastsStart; + clearChange?: (name: string) => void; + unsavedChanges?: FieldState; + loading?: boolean; } -interface FieldState { - unsavedValue: any; - savedValue: any; - loading: boolean; - isInvalid: boolean; - error: string | null; - changeImage: boolean; - isJsonArray: boolean; -} - -export class Field extends PureComponent<FieldProps, FieldState> { - private changeImageForm: EuiFilePicker | undefined; - constructor(props: FieldProps) { - super(props); - const { type, value, defVal } = this.props.setting; - const editableValue = this.getEditableValue(type, value, defVal); - - this.state = { - isInvalid: false, - error: null, - loading: false, - changeImage: false, - savedValue: editableValue, - unsavedValue: editableValue, - isJsonArray: type === 'json' ? Array.isArray(JSON.parse(String(defVal) || '{}')) : false, - }; - } - - UNSAFE_componentWillReceiveProps(nextProps: FieldProps) { - const { unsavedValue } = this.state; - const { type, value, defVal } = nextProps.setting; - const editableValue = this.getEditableValue(type, value, defVal); - - this.setState({ - savedValue: editableValue, - unsavedValue: value === null || value === undefined ? editableValue : unsavedValue, - }); +export const getEditableValue = ( + type: UiSettingsType, + value: FieldSetting['value'], + defVal?: FieldSetting['defVal'] +) => { + const val = value === null || value === undefined ? defVal : value; + switch (type) { + case 'array': + return (val as string[]).join(', '); + case 'boolean': + return !!val; + case 'number': + return Number(val); + case 'image': + return val; + default: + return val || ''; } +}; - getEditableValue( - type: UiSettingsType, - value: FieldSetting['value'], - defVal: FieldSetting['defVal'] - ) { - const val = value === null || value === undefined ? defVal : value; - switch (type) { - case 'array': - return (val as string[]).join(', '); - case 'boolean': - return !!val; - case 'number': - return Number(val); - case 'image': - return val; - default: - return val || ''; - } - } +export class Field extends PureComponent<FieldProps> { + private changeImageForm: EuiFilePicker | undefined = React.createRef(); getDisplayedDefaultValue( type: UiSettingsType, @@ -150,47 +112,60 @@ export class Field extends PureComponent<FieldProps, FieldState> { } } - setLoading(loading: boolean) { - this.setState({ - loading, - }); - } + handleChange = (unsavedChanges: FieldState) => { + this.props.handleChange(this.props.setting.name, unsavedChanges); + }; - clearError() { - this.setState({ - isInvalid: false, - error: null, - }); + resetField = () => { + const { type, defVal } = this.props.setting; + if (type === 'image') { + this.cancelChangeImage(); + return this.handleChange({ + value: getEditableValue(type, defVal), + changeImage: true, + }); + } + return this.handleChange({ value: getEditableValue(type, defVal) }); + }; + + componentDidUpdate(prevProps: FieldProps) { + if ( + prevProps.setting.type === 'image' && + prevProps.unsavedChanges?.value && + !this.props.unsavedChanges?.value + ) { + this.cancelChangeImage(); + } } onCodeEditorChange = (value: UiSettingsType) => { - const { type } = this.props.setting; - const { isJsonArray } = this.state; + const { defVal, type } = this.props.setting; let newUnsavedValue; - let isInvalid = false; - let error = null; + let errorParams = {}; switch (type) { case 'json': + const isJsonArray = Array.isArray(JSON.parse((defVal as string) || '{}')); newUnsavedValue = value.trim() || (isJsonArray ? '[]' : '{}'); try { JSON.parse(newUnsavedValue); } catch (e) { - isInvalid = true; - error = i18n.translate('advancedSettings.field.codeEditorSyntaxErrorMessage', { - defaultMessage: 'Invalid JSON syntax', - }); + errorParams = { + error: i18n.translate('advancedSettings.field.codeEditorSyntaxErrorMessage', { + defaultMessage: 'Invalid JSON syntax', + }), + isInvalid: true, + }; } break; default: newUnsavedValue = value; } - this.setState({ - error, - isInvalid, - unsavedValue: newUnsavedValue, + this.handleChange({ + value: newUnsavedValue, + ...errorParams, }); }; @@ -201,58 +176,44 @@ export class Field extends PureComponent<FieldProps, FieldState> { onFieldChangeEvent = (e: React.ChangeEvent<HTMLInputElement | HTMLSelectElement>) => this.onFieldChange(e.target.value); - onFieldChange = (value: any) => { - const { type, validation } = this.props.setting; - const { unsavedValue } = this.state; - + onFieldChange = (targetValue: any) => { + const { type, validation, value, defVal } = this.props.setting; let newUnsavedValue; switch (type) { case 'boolean': - newUnsavedValue = !unsavedValue; + const { unsavedChanges } = this.props; + const currentValue = unsavedChanges + ? unsavedChanges.value + : getEditableValue(type, value, defVal); + newUnsavedValue = !currentValue; break; case 'number': - newUnsavedValue = Number(value); + newUnsavedValue = Number(targetValue); break; default: - newUnsavedValue = value; + newUnsavedValue = targetValue; } - let isInvalid = false; - let error = null; + let errorParams = {}; - if (validation && (validation as StringValidationRegex).regex) { + if ((validation as StringValidationRegex)?.regex) { if (!(validation as StringValidationRegex).regex!.test(newUnsavedValue.toString())) { - error = (validation as StringValidationRegex).message; - isInvalid = true; + errorParams = { + error: (validation as StringValidationRegex).message, + isInvalid: true, + }; } } - this.setState({ - unsavedValue: newUnsavedValue, - isInvalid, - error, + this.handleChange({ + value: newUnsavedValue, + ...errorParams, }); }; - onFieldKeyDown = ({ keyCode }: { keyCode: number }) => { - if (keyCode === keyCodes.ENTER) { - this.saveEdit(); - } - if (keyCode === keyCodes.ESCAPE) { - this.cancelEdit(); - } - }; - - onFieldEscape = ({ keyCode }: { keyCode: number }) => { - if (keyCode === keyCodes.ESCAPE) { - this.cancelEdit(); - } - }; - onImageChange = async (files: any[]) => { if (!files.length) { - this.clearError(); this.setState({ unsavedValue: null, }); @@ -266,19 +227,24 @@ export class Field extends PureComponent<FieldProps, FieldState> { if (file instanceof File) { base64Image = (await this.getImageAsBase64(file)) as string; } - const isInvalid = !!(maxSize && maxSize.length && base64Image.length > maxSize.length); - this.setState({ - isInvalid, - error: isInvalid - ? i18n.translate('advancedSettings.field.imageTooLargeErrorMessage', { - defaultMessage: 'Image is too large, maximum size is {maxSizeDescription}', - values: { - maxSizeDescription: maxSize.description, - }, - }) - : null, + + let errorParams = {}; + const isInvalid = !!(maxSize?.length && base64Image.length > maxSize.length); + if (isInvalid) { + errorParams = { + isInvalid, + error: i18n.translate('advancedSettings.field.imageTooLargeErrorMessage', { + defaultMessage: 'Image is too large, maximum size is {maxSizeDescription}', + values: { + maxSizeDescription: maxSize.description, + }, + }), + }; + } + this.handleChange({ changeImage: true, - unsavedValue: base64Image, + value: base64Image, + ...errorParams, }); } catch (err) { this.props.toasts.addDanger( @@ -305,152 +271,62 @@ export class Field extends PureComponent<FieldProps, FieldState> { } changeImage = () => { - this.setState({ + this.handleChange({ + value: null, changeImage: true, }); }; cancelChangeImage = () => { - const { savedValue } = this.state; - - if (this.changeImageForm) { - this.changeImageForm.fileInput.value = null; - this.changeImageForm.handleChange(); - } - - this.setState({ - changeImage: false, - unsavedValue: savedValue, - }); - }; - - cancelEdit = () => { - const { savedValue } = this.state; - this.clearError(); - this.setState({ - unsavedValue: savedValue, - }); - }; - - showPageReloadToast = () => { - if (this.props.setting.requiresPageReload) { - this.props.toasts.add({ - title: i18n.translate('advancedSettings.field.requiresPageReloadToastDescription', { - defaultMessage: 'Please reload the page for the "{settingName}" setting to take effect.', - values: { - settingName: this.props.setting.displayName || this.props.setting.name, - }, - }), - text: element => { - const content = ( - <> - <EuiFlexGroup justifyContent="flexEnd" gutterSize="s"> - <EuiFlexItem grow={false}> - <EuiButton size="s" onClick={() => window.location.reload()}> - {i18n.translate('advancedSettings.field.requiresPageReloadToastButtonLabel', { - defaultMessage: 'Reload page', - })} - </EuiButton> - </EuiFlexItem> - </EuiFlexGroup> - </> - ); - ReactDOM.render(content, element); - return () => ReactDOM.unmountComponentAtNode(element); - }, - color: 'success', - }); - } - }; - - saveEdit = async () => { - const { name, defVal, type } = this.props.setting; - const { changeImage, savedValue, unsavedValue, isJsonArray } = this.state; - - if (savedValue === unsavedValue) { - return; - } - - let valueToSave = unsavedValue; - let isSameValue = false; - - switch (type) { - case 'array': - valueToSave = valueToSave.split(',').map((val: string) => val.trim()); - isSameValue = valueToSave.join(',') === (defVal as string[]).join(','); - break; - case 'json': - valueToSave = valueToSave.trim(); - valueToSave = valueToSave || (isJsonArray ? '[]' : '{}'); - default: - isSameValue = valueToSave === defVal; - } - - this.setLoading(true); - try { - if (isSameValue) { - await this.props.clear(name); - } else { - await this.props.save(name, valueToSave); - } - - this.showPageReloadToast(); - - if (changeImage) { - this.cancelChangeImage(); - } - } catch (e) { - this.props.toasts.addDanger( - i18n.translate('advancedSettings.field.saveFieldErrorMessage', { - defaultMessage: 'Unable to save {name}', - values: { name }, - }) - ); + if (this.changeImageForm.current) { + this.changeImageForm.current.fileInput.value = null; + this.changeImageForm.current.handleChange({}); } - this.setLoading(false); - }; - - resetField = async () => { - const { name } = this.props.setting; - this.setLoading(true); - try { - await this.props.clear(name); - this.showPageReloadToast(); - this.cancelChangeImage(); - this.clearError(); - } catch (e) { - this.props.toasts.addDanger( - i18n.translate('advancedSettings.field.resetFieldErrorMessage', { - defaultMessage: 'Unable to reset {name}', - values: { name }, - }) - ); + if (this.props.clearChange) { + this.props.clearChange(this.props.setting.name); } - this.setLoading(false); }; - renderField(setting: FieldSetting) { - const { enableSaving } = this.props; - const { loading, changeImage, unsavedValue } = this.state; - const { name, value, type, options, optionLabels = {}, isOverridden, ariaName } = setting; + renderField(id: string, setting: FieldSetting) { + const { enableSaving, unsavedChanges, loading } = this.props; + const { + name, + value, + type, + options, + optionLabels = {}, + isOverridden, + defVal, + ariaName, + } = setting; + const a11yProps: { [key: string]: string } = unsavedChanges + ? { + 'aria-label': ariaName, + 'aria-describedby': id, + } + : { + 'aria-label': ariaName, + }; + const currentValue = unsavedChanges + ? unsavedChanges.value + : getEditableValue(type, value, defVal); switch (type) { case 'boolean': return ( <EuiSwitch label={ - !!unsavedValue ? ( + !!currentValue ? ( <FormattedMessage id="advancedSettings.field.onLabel" defaultMessage="On" /> ) : ( <FormattedMessage id="advancedSettings.field.offLabel" defaultMessage="Off" /> ) } - checked={!!unsavedValue} + checked={!!currentValue} onChange={this.onFieldChangeSwitch} disabled={loading || isOverridden || !enableSaving} - onKeyDown={this.onFieldKeyDown} data-test-subj={`advancedSetting-editField-${name}`} - aria-label={ariaName} + {...a11yProps} /> ); case 'markdown': @@ -458,10 +334,10 @@ export class Field extends PureComponent<FieldProps, FieldState> { return ( <div data-test-subj={`advancedSetting-editField-${name}`}> <EuiCodeEditor - aria-label={ariaName} + {...a11yProps} mode={type} theme="textmate" - value={unsavedValue} + value={currentValue} onChange={this.onCodeEditorChange} width="100%" height="auto" @@ -476,24 +352,22 @@ export class Field extends PureComponent<FieldProps, FieldState> { $blockScrolling: Infinity, }} showGutter={false} + fullWidth /> </div> ); case 'image': + const changeImage = unsavedChanges?.changeImage; if (!isDefaultValue(setting) && !changeImage) { - return ( - <EuiImage aria-label={ariaName} allowFullScreen url={value as string} alt={name} /> - ); + return <EuiImage {...a11yProps} allowFullScreen url={value as string} alt={name} />; } else { return ( <EuiFilePicker disabled={loading || isOverridden || !enableSaving} onChange={this.onImageChange} accept=".jpg,.jpeg,.png" - ref={(input: HTMLInputElement) => { - this.changeImageForm = input; - }} - onKeyDown={this.onFieldEscape} + ref={this.changeImageForm} + fullWidth data-test-subj={`advancedSetting-editField-${name}`} /> ); @@ -501,8 +375,8 @@ export class Field extends PureComponent<FieldProps, FieldState> { case 'select': return ( <EuiSelect - aria-label={ariaName} - value={unsavedValue} + {...a11yProps} + value={currentValue} options={(options as string[]).map(option => { return { text: optionLabels.hasOwnProperty(option) ? optionLabels[option] : option, @@ -512,31 +386,31 @@ export class Field extends PureComponent<FieldProps, FieldState> { onChange={this.onFieldChangeEvent} isLoading={loading} disabled={loading || isOverridden || !enableSaving} - onKeyDown={this.onFieldKeyDown} + fullWidth data-test-subj={`advancedSetting-editField-${name}`} /> ); case 'number': return ( <EuiFieldNumber - aria-label={ariaName} - value={unsavedValue} + {...a11yProps} + value={currentValue} onChange={this.onFieldChangeEvent} isLoading={loading} disabled={loading || isOverridden || !enableSaving} - onKeyDown={this.onFieldKeyDown} + fullWidth data-test-subj={`advancedSetting-editField-${name}`} /> ); default: return ( <EuiFieldText - aria-label={ariaName} - value={unsavedValue} + {...a11yProps} + value={currentValue} onChange={this.onFieldChangeEvent} isLoading={loading} disabled={loading || isOverridden || !enableSaving} - onKeyDown={this.onFieldKeyDown} + fullWidth data-test-subj={`advancedSetting-editField-${name}`} /> ); @@ -699,8 +573,12 @@ export class Field extends PureComponent<FieldProps, FieldState> { } renderResetToDefaultLink(setting: FieldSetting) { - const { ariaName, name } = setting; - if (isDefaultValue(setting)) { + const { defVal, ariaName, name } = setting; + if ( + defVal === this.props.unsavedChanges?.value || + isDefaultValue(setting) || + this.props.loading + ) { return; } return ( @@ -726,7 +604,7 @@ export class Field extends PureComponent<FieldProps, FieldState> { } renderChangeImageLink(setting: FieldSetting) { - const { changeImage } = this.state; + const changeImage = this.props.unsavedChanges?.changeImage; const { type, value, ariaName, name } = setting; if (type !== 'image' || !value || changeImage) { return; @@ -752,84 +630,49 @@ export class Field extends PureComponent<FieldProps, FieldState> { ); } - renderActions(setting: FieldSetting) { - const { ariaName, name } = setting; - const { loading, isInvalid, changeImage, savedValue, unsavedValue } = this.state; - const isDisabled = loading || setting.isOverridden; - - if (savedValue === unsavedValue && !changeImage) { - return; - } - - return ( - <EuiFormRow className="mgtAdvancedSettings__fieldActions" hasEmptyLabelSpace> - <EuiFlexGroup> - <EuiFlexItem grow={false}> - <EuiButton - fill - aria-label={i18n.translate('advancedSettings.field.saveButtonAriaLabel', { - defaultMessage: 'Save {ariaName}', - values: { - ariaName, - }, - })} - onClick={this.saveEdit} - disabled={isDisabled || isInvalid} - data-test-subj={`advancedSetting-saveEditField-${name}`} - > - <FormattedMessage id="advancedSettings.field.saveButtonLabel" defaultMessage="Save" /> - </EuiButton> - </EuiFlexItem> - <EuiFlexItem grow={false}> - <EuiButtonEmpty - aria-label={i18n.translate('advancedSettings.field.cancelEditingButtonAriaLabel', { - defaultMessage: 'Cancel editing {ariaName}', - values: { - ariaName, - }, - })} - onClick={() => (changeImage ? this.cancelChangeImage() : this.cancelEdit())} - disabled={isDisabled} - data-test-subj={`advancedSetting-cancelEditField-${name}`} - > - <FormattedMessage - id="advancedSettings.field.cancelEditingButtonLabel" - defaultMessage="Cancel" - /> - </EuiButtonEmpty> - </EuiFlexItem> - </EuiFlexGroup> - </EuiFormRow> - ); - } - render() { - const { setting } = this.props; - const { error, isInvalid } = this.state; + const { setting, unsavedChanges } = this.props; + const error = unsavedChanges?.error; + const isInvalid = unsavedChanges?.isInvalid; + + const className = classNames('mgtAdvancedSettings__field', { + 'mgtAdvancedSettings__field--unsaved': unsavedChanges, + 'mgtAdvancedSettings__field--invalid': isInvalid, + }); + const id = setting.name; return ( - <EuiFlexGroup className="mgtAdvancedSettings__field"> - <EuiFlexItem grow={false}> - <EuiDescribedFormGroup - className="mgtAdvancedSettings__fieldWrapper" - title={this.renderTitle(setting)} - description={this.renderDescription(setting)} - > - <EuiFormRow - isInvalid={isInvalid} - error={error} - label={this.renderLabel(setting)} - helpText={this.renderHelpText(setting)} - describedByIds={[`${setting.name}-aria`]} - className="mgtAdvancedSettings__fieldRow" - hasChildLabel={setting.type !== 'boolean'} - > - {this.renderField(setting)} - </EuiFormRow> - </EuiDescribedFormGroup> - </EuiFlexItem> - <EuiFlexItem grow={false}>{this.renderActions(setting)}</EuiFlexItem> - </EuiFlexGroup> + <EuiDescribedFormGroup + className={className} + title={this.renderTitle(setting)} + description={this.renderDescription(setting)} + fullWidth + > + <EuiFormRow + isInvalid={isInvalid} + error={error} + label={this.renderLabel(setting)} + helpText={this.renderHelpText(setting)} + className="mgtAdvancedSettings__fieldRow" + hasChildLabel={setting.type !== 'boolean'} + fullWidth + > + <> + {this.renderField(id, setting)} + {unsavedChanges && ( + <EuiScreenReaderOnly> + <p id={id}> + {unsavedChanges.error + ? unsavedChanges.error + : i18n.translate('advancedSettings.field.settingIsUnsaved', { + defaultMessage: 'Setting is currently not saved.', + })} + </p> + </EuiScreenReaderOnly> + )} + </> + </EuiFormRow> + </EuiDescribedFormGroup> ); } } diff --git a/src/plugins/advanced_settings/public/management_app/components/field/index.ts b/src/plugins/advanced_settings/public/management_app/components/field/index.ts index 5c86519116fe9..d1b9b34515532 100644 --- a/src/plugins/advanced_settings/public/management_app/components/field/index.ts +++ b/src/plugins/advanced_settings/public/management_app/components/field/index.ts @@ -17,4 +17,4 @@ * under the License. */ -export { Field } from './field'; +export { Field, getEditableValue } from './field'; diff --git a/src/plugins/advanced_settings/public/management_app/components/form/__snapshots__/form.test.tsx.snap b/src/plugins/advanced_settings/public/management_app/components/form/__snapshots__/form.test.tsx.snap index 8c471f5f5be9c..bce9cb67537db 100644 --- a/src/plugins/advanced_settings/public/management_app/components/form/__snapshots__/form.test.tsx.snap +++ b/src/plugins/advanced_settings/public/management_app/components/form/__snapshots__/form.test.tsx.snap @@ -1,449 +1,849 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`Form should not render no settings message when instructed not to 1`] = `<Fragment />`; +exports[`Form should not render no settings message when instructed not to 1`] = ` +<Fragment> + <div> + <EuiPanel + paddingSize="l" + > + <EuiForm> + <EuiText> + <EuiFlexGroup + alignItems="baseline" + > + <EuiFlexItem + grow={false} + > + <h2> + General + </h2> + </EuiFlexItem> + </EuiFlexGroup> + </EuiText> + <EuiSpacer + size="m" + /> + <Field + clearChange={[Function]} + dockLinks={Object {}} + enableSaving={true} + handleChange={[Function]} + key="general:test:date" + setting={ + Object { + "ariaName": "general test date", + "category": Array [ + "general", + ], + "defVal": "defVal", + "description": "bar", + "displayName": "Test date", + "isCustom": false, + "isOverridden": false, + "name": "general:test:date", + "readOnly": false, + "requiresPageReload": false, + "type": "string", + "value": "value", + } + } + toasts={Object {}} + /> + <Field + clearChange={[Function]} + dockLinks={Object {}} + enableSaving={true} + handleChange={[Function]} + key="setting:test" + setting={ + Object { + "ariaName": "setting test", + "category": Array [ + "general", + ], + "defVal": "defVal", + "description": "foo", + "displayName": "Test setting", + "isCustom": false, + "isOverridden": false, + "name": "setting:test", + "readOnly": false, + "requiresPageReload": false, + "type": "string", + "value": "value", + } + } + toasts={Object {}} + /> + </EuiForm> + </EuiPanel> + <EuiSpacer + size="l" + /> + <EuiPanel + paddingSize="l" + > + <EuiForm> + <EuiText> + <EuiFlexGroup + alignItems="baseline" + > + <EuiFlexItem + grow={false} + > + <h2> + Dashboard + </h2> + </EuiFlexItem> + </EuiFlexGroup> + </EuiText> + <EuiSpacer + size="m" + /> + <Field + clearChange={[Function]} + dockLinks={Object {}} + enableSaving={true} + handleChange={[Function]} + key="dashboard:test:setting" + setting={ + Object { + "ariaName": "dashboard test setting", + "category": Array [ + "dashboard", + ], + "defVal": "defVal", + "description": "description", + "displayName": "Dashboard test setting", + "isCustom": false, + "isOverridden": false, + "name": "dashboard:test:setting", + "readOnly": false, + "requiresPageReload": true, + "type": "string", + "value": "value", + } + } + toasts={Object {}} + /> + </EuiForm> + </EuiPanel> + <EuiSpacer + size="l" + /> + <EuiPanel + paddingSize="l" + > + <EuiForm> + <EuiText> + <EuiFlexGroup + alignItems="baseline" + > + <EuiFlexItem + grow={false} + > + <h2> + X-pack + </h2> + </EuiFlexItem> + <EuiFlexItem + grow={false} + > + <em> + <FormattedMessage + defaultMessage="Search terms are hiding {settingsCount} settings {clearSearch}" + id="advancedSettings.form.searchResultText" + values={ + Object { + "clearSearch": <ForwardRef + onClick={[Function]} + > + <em> + <FormattedMessage + defaultMessage="(clear search)" + id="advancedSettings.form.clearSearchResultText" + values={Object {}} + /> + </em> + </ForwardRef>, + "settingsCount": 9, + } + } + /> + </em> + </EuiFlexItem> + </EuiFlexGroup> + </EuiText> + <EuiSpacer + size="m" + /> + <Field + clearChange={[Function]} + dockLinks={Object {}} + enableSaving={true} + handleChange={[Function]} + key="xpack:test:setting" + setting={ + Object { + "ariaName": "xpack test setting", + "category": Array [ + "x-pack", + ], + "defVal": "defVal", + "description": "bar", + "displayName": "X-Pack test setting", + "isCustom": false, + "isOverridden": false, + "name": "xpack:test:setting", + "readOnly": false, + "requiresPageReload": false, + "type": "string", + "value": "value", + } + } + toasts={Object {}} + /> + </EuiForm> + </EuiPanel> + <EuiSpacer + size="l" + /> + </div> +</Fragment> +`; exports[`Form should render no settings message when there are no settings 1`] = ` <Fragment> - <EuiPanel - paddingSize="l" - > - <FormattedMessage - defaultMessage="No settings found {clearSearch}" - id="advancedSettings.form.noSearchResultText" - values={ - Object { - "clearSearch": <ForwardRef - onClick={[Function]} + <div> + <EuiPanel + paddingSize="l" + > + <EuiForm> + <EuiText> + <EuiFlexGroup + alignItems="baseline" > - <FormattedMessage - defaultMessage="(clear search)" - id="advancedSettings.form.clearNoSearchResultText" - values={Object {}} - /> - </ForwardRef>, - } - } + <EuiFlexItem + grow={false} + > + <h2> + General + </h2> + </EuiFlexItem> + </EuiFlexGroup> + </EuiText> + <EuiSpacer + size="m" + /> + <Field + clearChange={[Function]} + dockLinks={Object {}} + enableSaving={true} + handleChange={[Function]} + key="general:test:date" + setting={ + Object { + "ariaName": "general test date", + "category": Array [ + "general", + ], + "defVal": "defVal", + "description": "bar", + "displayName": "Test date", + "isCustom": false, + "isOverridden": false, + "name": "general:test:date", + "readOnly": false, + "requiresPageReload": false, + "type": "string", + "value": "value", + } + } + toasts={Object {}} + /> + <Field + clearChange={[Function]} + dockLinks={Object {}} + enableSaving={true} + handleChange={[Function]} + key="setting:test" + setting={ + Object { + "ariaName": "setting test", + "category": Array [ + "general", + ], + "defVal": "defVal", + "description": "foo", + "displayName": "Test setting", + "isCustom": false, + "isOverridden": false, + "name": "setting:test", + "readOnly": false, + "requiresPageReload": false, + "type": "string", + "value": "value", + } + } + toasts={Object {}} + /> + </EuiForm> + </EuiPanel> + <EuiSpacer + size="l" /> - </EuiPanel> + <EuiPanel + paddingSize="l" + > + <EuiForm> + <EuiText> + <EuiFlexGroup + alignItems="baseline" + > + <EuiFlexItem + grow={false} + > + <h2> + Dashboard + </h2> + </EuiFlexItem> + </EuiFlexGroup> + </EuiText> + <EuiSpacer + size="m" + /> + <Field + clearChange={[Function]} + dockLinks={Object {}} + enableSaving={true} + handleChange={[Function]} + key="dashboard:test:setting" + setting={ + Object { + "ariaName": "dashboard test setting", + "category": Array [ + "dashboard", + ], + "defVal": "defVal", + "description": "description", + "displayName": "Dashboard test setting", + "isCustom": false, + "isOverridden": false, + "name": "dashboard:test:setting", + "readOnly": false, + "requiresPageReload": true, + "type": "string", + "value": "value", + } + } + toasts={Object {}} + /> + </EuiForm> + </EuiPanel> + <EuiSpacer + size="l" + /> + <EuiPanel + paddingSize="l" + > + <EuiForm> + <EuiText> + <EuiFlexGroup + alignItems="baseline" + > + <EuiFlexItem + grow={false} + > + <h2> + X-pack + </h2> + </EuiFlexItem> + <EuiFlexItem + grow={false} + > + <em> + <FormattedMessage + defaultMessage="Search terms are hiding {settingsCount} settings {clearSearch}" + id="advancedSettings.form.searchResultText" + values={ + Object { + "clearSearch": <ForwardRef + onClick={[Function]} + > + <em> + <FormattedMessage + defaultMessage="(clear search)" + id="advancedSettings.form.clearSearchResultText" + values={Object {}} + /> + </em> + </ForwardRef>, + "settingsCount": 9, + } + } + /> + </em> + </EuiFlexItem> + </EuiFlexGroup> + </EuiText> + <EuiSpacer + size="m" + /> + <Field + clearChange={[Function]} + dockLinks={Object {}} + enableSaving={true} + handleChange={[Function]} + key="xpack:test:setting" + setting={ + Object { + "ariaName": "xpack test setting", + "category": Array [ + "x-pack", + ], + "defVal": "defVal", + "description": "bar", + "displayName": "X-Pack test setting", + "isCustom": false, + "isOverridden": false, + "name": "xpack:test:setting", + "readOnly": false, + "requiresPageReload": false, + "type": "string", + "value": "value", + } + } + toasts={Object {}} + /> + </EuiForm> + </EuiPanel> + <EuiSpacer + size="l" + /> + </div> </Fragment> `; exports[`Form should render normally 1`] = ` <Fragment> - <EuiPanel - paddingSize="l" - > - <EuiForm> - <EuiText> - <EuiFlexGroup - alignItems="baseline" - > - <EuiFlexItem - grow={false} + <div> + <EuiPanel + paddingSize="l" + > + <EuiForm> + <EuiText> + <EuiFlexGroup + alignItems="baseline" > - <h2> - General - </h2> - </EuiFlexItem> - </EuiFlexGroup> - </EuiText> - <EuiSpacer - size="m" - /> - <Field - clear={[Function]} - dockLinks={Object {}} - enableSaving={true} - key="general:test:date" - save={[Function]} - setting={ - Object { - "ariaName": "general test date", - "category": Array [ - "general", - ], - "defVal": "defVal", - "description": "description", - "displayName": "Test date", - "isCustom": false, - "isOverridden": false, - "name": "general:test:date", - "readOnly": false, - "requiresPageReload": false, - "type": "string", - "value": "value", + <EuiFlexItem + grow={false} + > + <h2> + General + </h2> + </EuiFlexItem> + </EuiFlexGroup> + </EuiText> + <EuiSpacer + size="m" + /> + <Field + clearChange={[Function]} + dockLinks={Object {}} + enableSaving={true} + handleChange={[Function]} + key="general:test:date" + setting={ + Object { + "ariaName": "general test date", + "category": Array [ + "general", + ], + "defVal": "defVal", + "description": "bar", + "displayName": "Test date", + "isCustom": false, + "isOverridden": false, + "name": "general:test:date", + "readOnly": false, + "requiresPageReload": false, + "type": "string", + "value": "value", + } } - } - toasts={Object {}} - /> - <Field - clear={[Function]} - dockLinks={Object {}} - enableSaving={true} - key="setting:test" - save={[Function]} - setting={ - Object { - "ariaName": "setting test", - "category": Array [ - "general", - ], - "defVal": "defVal", - "description": "description", - "displayName": "Test setting", - "isCustom": false, - "isOverridden": false, - "name": "setting:test", - "readOnly": false, - "requiresPageReload": false, - "type": "string", - "value": "value", + toasts={Object {}} + /> + <Field + clearChange={[Function]} + dockLinks={Object {}} + enableSaving={true} + handleChange={[Function]} + key="setting:test" + setting={ + Object { + "ariaName": "setting test", + "category": Array [ + "general", + ], + "defVal": "defVal", + "description": "foo", + "displayName": "Test setting", + "isCustom": false, + "isOverridden": false, + "name": "setting:test", + "readOnly": false, + "requiresPageReload": false, + "type": "string", + "value": "value", + } } - } - toasts={Object {}} - /> - </EuiForm> - </EuiPanel> - <EuiSpacer - size="l" - /> - <EuiPanel - paddingSize="l" - > - <EuiForm> - <EuiText> - <EuiFlexGroup - alignItems="baseline" - > - <EuiFlexItem - grow={false} + toasts={Object {}} + /> + </EuiForm> + </EuiPanel> + <EuiSpacer + size="l" + /> + <EuiPanel + paddingSize="l" + > + <EuiForm> + <EuiText> + <EuiFlexGroup + alignItems="baseline" > - <h2> - Dashboard - </h2> - </EuiFlexItem> - </EuiFlexGroup> - </EuiText> - <EuiSpacer - size="m" - /> - <Field - clear={[Function]} - dockLinks={Object {}} - enableSaving={true} - key="dashboard:test:setting" - save={[Function]} - setting={ - Object { - "ariaName": "dashboard test setting", - "category": Array [ - "dashboard", - ], - "defVal": "defVal", - "description": "description", - "displayName": "Dashboard test setting", - "isCustom": false, - "isOverridden": false, - "name": "dashboard:test:setting", - "readOnly": false, - "requiresPageReload": false, - "type": "string", - "value": "value", + <EuiFlexItem + grow={false} + > + <h2> + Dashboard + </h2> + </EuiFlexItem> + </EuiFlexGroup> + </EuiText> + <EuiSpacer + size="m" + /> + <Field + clearChange={[Function]} + dockLinks={Object {}} + enableSaving={true} + handleChange={[Function]} + key="dashboard:test:setting" + setting={ + Object { + "ariaName": "dashboard test setting", + "category": Array [ + "dashboard", + ], + "defVal": "defVal", + "description": "description", + "displayName": "Dashboard test setting", + "isCustom": false, + "isOverridden": false, + "name": "dashboard:test:setting", + "readOnly": false, + "requiresPageReload": true, + "type": "string", + "value": "value", + } } - } - toasts={Object {}} - /> - </EuiForm> - </EuiPanel> - <EuiSpacer - size="l" - /> - <EuiPanel - paddingSize="l" - > - <EuiForm> - <EuiText> - <EuiFlexGroup - alignItems="baseline" - > - <EuiFlexItem - grow={false} - > - <h2> - X-pack - </h2> - </EuiFlexItem> - <EuiFlexItem - grow={false} + toasts={Object {}} + /> + </EuiForm> + </EuiPanel> + <EuiSpacer + size="l" + /> + <EuiPanel + paddingSize="l" + > + <EuiForm> + <EuiText> + <EuiFlexGroup + alignItems="baseline" > - <em> - <FormattedMessage - defaultMessage="Search terms are hiding {settingsCount} settings {clearSearch}" - id="advancedSettings.form.searchResultText" - values={ - Object { - "clearSearch": <ForwardRef - onClick={[Function]} - > - <em> - <FormattedMessage - defaultMessage="(clear search)" - id="advancedSettings.form.clearSearchResultText" - values={Object {}} - /> - </em> - </ForwardRef>, - "settingsCount": 9, + <EuiFlexItem + grow={false} + > + <h2> + X-pack + </h2> + </EuiFlexItem> + <EuiFlexItem + grow={false} + > + <em> + <FormattedMessage + defaultMessage="Search terms are hiding {settingsCount} settings {clearSearch}" + id="advancedSettings.form.searchResultText" + values={ + Object { + "clearSearch": <ForwardRef + onClick={[Function]} + > + <em> + <FormattedMessage + defaultMessage="(clear search)" + id="advancedSettings.form.clearSearchResultText" + values={Object {}} + /> + </em> + </ForwardRef>, + "settingsCount": 9, + } } - } - /> - </em> - </EuiFlexItem> - </EuiFlexGroup> - </EuiText> - <EuiSpacer - size="m" - /> - <Field - clear={[Function]} - dockLinks={Object {}} - enableSaving={true} - key="xpack:test:setting" - save={[Function]} - setting={ - Object { - "ariaName": "xpack test setting", - "category": Array [ - "x-pack", - ], - "defVal": "defVal", - "description": "description", - "displayName": "X-Pack test setting", - "isCustom": false, - "isOverridden": false, - "name": "xpack:test:setting", - "readOnly": false, - "requiresPageReload": false, - "type": "string", - "value": "value", + /> + </em> + </EuiFlexItem> + </EuiFlexGroup> + </EuiText> + <EuiSpacer + size="m" + /> + <Field + clearChange={[Function]} + dockLinks={Object {}} + enableSaving={true} + handleChange={[Function]} + key="xpack:test:setting" + setting={ + Object { + "ariaName": "xpack test setting", + "category": Array [ + "x-pack", + ], + "defVal": "defVal", + "description": "bar", + "displayName": "X-Pack test setting", + "isCustom": false, + "isOverridden": false, + "name": "xpack:test:setting", + "readOnly": false, + "requiresPageReload": false, + "type": "string", + "value": "value", + } } - } - toasts={Object {}} - /> - </EuiForm> - </EuiPanel> - <EuiSpacer - size="l" - /> + toasts={Object {}} + /> + </EuiForm> + </EuiPanel> + <EuiSpacer + size="l" + /> + </div> </Fragment> `; exports[`Form should render read-only when saving is disabled 1`] = ` <Fragment> - <EuiPanel - paddingSize="l" - > - <EuiForm> - <EuiText> - <EuiFlexGroup - alignItems="baseline" - > - <EuiFlexItem - grow={false} + <div> + <EuiPanel + paddingSize="l" + > + <EuiForm> + <EuiText> + <EuiFlexGroup + alignItems="baseline" > - <h2> - General - </h2> - </EuiFlexItem> - </EuiFlexGroup> - </EuiText> - <EuiSpacer - size="m" - /> - <Field - clear={[Function]} - dockLinks={Object {}} - enableSaving={false} - key="general:test:date" - save={[Function]} - setting={ - Object { - "ariaName": "general test date", - "category": Array [ - "general", - ], - "defVal": "defVal", - "description": "description", - "displayName": "Test date", - "isCustom": false, - "isOverridden": false, - "name": "general:test:date", - "readOnly": false, - "requiresPageReload": false, - "type": "string", - "value": "value", + <EuiFlexItem + grow={false} + > + <h2> + General + </h2> + </EuiFlexItem> + </EuiFlexGroup> + </EuiText> + <EuiSpacer + size="m" + /> + <Field + clearChange={[Function]} + dockLinks={Object {}} + enableSaving={false} + handleChange={[Function]} + key="general:test:date" + setting={ + Object { + "ariaName": "general test date", + "category": Array [ + "general", + ], + "defVal": "defVal", + "description": "bar", + "displayName": "Test date", + "isCustom": false, + "isOverridden": false, + "name": "general:test:date", + "readOnly": false, + "requiresPageReload": false, + "type": "string", + "value": "value", + } } - } - toasts={Object {}} - /> - <Field - clear={[Function]} - dockLinks={Object {}} - enableSaving={false} - key="setting:test" - save={[Function]} - setting={ - Object { - "ariaName": "setting test", - "category": Array [ - "general", - ], - "defVal": "defVal", - "description": "description", - "displayName": "Test setting", - "isCustom": false, - "isOverridden": false, - "name": "setting:test", - "readOnly": false, - "requiresPageReload": false, - "type": "string", - "value": "value", + toasts={Object {}} + /> + <Field + clearChange={[Function]} + dockLinks={Object {}} + enableSaving={false} + handleChange={[Function]} + key="setting:test" + setting={ + Object { + "ariaName": "setting test", + "category": Array [ + "general", + ], + "defVal": "defVal", + "description": "foo", + "displayName": "Test setting", + "isCustom": false, + "isOverridden": false, + "name": "setting:test", + "readOnly": false, + "requiresPageReload": false, + "type": "string", + "value": "value", + } } - } - toasts={Object {}} - /> - </EuiForm> - </EuiPanel> - <EuiSpacer - size="l" - /> - <EuiPanel - paddingSize="l" - > - <EuiForm> - <EuiText> - <EuiFlexGroup - alignItems="baseline" - > - <EuiFlexItem - grow={false} + toasts={Object {}} + /> + </EuiForm> + </EuiPanel> + <EuiSpacer + size="l" + /> + <EuiPanel + paddingSize="l" + > + <EuiForm> + <EuiText> + <EuiFlexGroup + alignItems="baseline" > - <h2> - Dashboard - </h2> - </EuiFlexItem> - </EuiFlexGroup> - </EuiText> - <EuiSpacer - size="m" - /> - <Field - clear={[Function]} - dockLinks={Object {}} - enableSaving={false} - key="dashboard:test:setting" - save={[Function]} - setting={ - Object { - "ariaName": "dashboard test setting", - "category": Array [ - "dashboard", - ], - "defVal": "defVal", - "description": "description", - "displayName": "Dashboard test setting", - "isCustom": false, - "isOverridden": false, - "name": "dashboard:test:setting", - "readOnly": false, - "requiresPageReload": false, - "type": "string", - "value": "value", + <EuiFlexItem + grow={false} + > + <h2> + Dashboard + </h2> + </EuiFlexItem> + </EuiFlexGroup> + </EuiText> + <EuiSpacer + size="m" + /> + <Field + clearChange={[Function]} + dockLinks={Object {}} + enableSaving={false} + handleChange={[Function]} + key="dashboard:test:setting" + setting={ + Object { + "ariaName": "dashboard test setting", + "category": Array [ + "dashboard", + ], + "defVal": "defVal", + "description": "description", + "displayName": "Dashboard test setting", + "isCustom": false, + "isOverridden": false, + "name": "dashboard:test:setting", + "readOnly": false, + "requiresPageReload": true, + "type": "string", + "value": "value", + } } - } - toasts={Object {}} - /> - </EuiForm> - </EuiPanel> - <EuiSpacer - size="l" - /> - <EuiPanel - paddingSize="l" - > - <EuiForm> - <EuiText> - <EuiFlexGroup - alignItems="baseline" - > - <EuiFlexItem - grow={false} - > - <h2> - X-pack - </h2> - </EuiFlexItem> - <EuiFlexItem - grow={false} + toasts={Object {}} + /> + </EuiForm> + </EuiPanel> + <EuiSpacer + size="l" + /> + <EuiPanel + paddingSize="l" + > + <EuiForm> + <EuiText> + <EuiFlexGroup + alignItems="baseline" > - <em> - <FormattedMessage - defaultMessage="Search terms are hiding {settingsCount} settings {clearSearch}" - id="advancedSettings.form.searchResultText" - values={ - Object { - "clearSearch": <ForwardRef - onClick={[Function]} - > - <em> - <FormattedMessage - defaultMessage="(clear search)" - id="advancedSettings.form.clearSearchResultText" - values={Object {}} - /> - </em> - </ForwardRef>, - "settingsCount": 9, + <EuiFlexItem + grow={false} + > + <h2> + X-pack + </h2> + </EuiFlexItem> + <EuiFlexItem + grow={false} + > + <em> + <FormattedMessage + defaultMessage="Search terms are hiding {settingsCount} settings {clearSearch}" + id="advancedSettings.form.searchResultText" + values={ + Object { + "clearSearch": <ForwardRef + onClick={[Function]} + > + <em> + <FormattedMessage + defaultMessage="(clear search)" + id="advancedSettings.form.clearSearchResultText" + values={Object {}} + /> + </em> + </ForwardRef>, + "settingsCount": 9, + } } - } - /> - </em> - </EuiFlexItem> - </EuiFlexGroup> - </EuiText> - <EuiSpacer - size="m" - /> - <Field - clear={[Function]} - dockLinks={Object {}} - enableSaving={false} - key="xpack:test:setting" - save={[Function]} - setting={ - Object { - "ariaName": "xpack test setting", - "category": Array [ - "x-pack", - ], - "defVal": "defVal", - "description": "description", - "displayName": "X-Pack test setting", - "isCustom": false, - "isOverridden": false, - "name": "xpack:test:setting", - "readOnly": false, - "requiresPageReload": false, - "type": "string", - "value": "value", + /> + </em> + </EuiFlexItem> + </EuiFlexGroup> + </EuiText> + <EuiSpacer + size="m" + /> + <Field + clearChange={[Function]} + dockLinks={Object {}} + enableSaving={false} + handleChange={[Function]} + key="xpack:test:setting" + setting={ + Object { + "ariaName": "xpack test setting", + "category": Array [ + "x-pack", + ], + "defVal": "defVal", + "description": "bar", + "displayName": "X-Pack test setting", + "isCustom": false, + "isOverridden": false, + "name": "xpack:test:setting", + "readOnly": false, + "requiresPageReload": false, + "type": "string", + "value": "value", + } } - } - toasts={Object {}} - /> - </EuiForm> - </EuiPanel> - <EuiSpacer - size="l" - /> + toasts={Object {}} + /> + </EuiForm> + </EuiPanel> + <EuiSpacer + size="l" + /> + </div> </Fragment> `; diff --git a/src/plugins/advanced_settings/public/management_app/components/form/_form.scss b/src/plugins/advanced_settings/public/management_app/components/form/_form.scss new file mode 100644 index 0000000000000..02ebb90221d90 --- /dev/null +++ b/src/plugins/advanced_settings/public/management_app/components/form/_form.scss @@ -0,0 +1,13 @@ +@import '@elastic/eui/src/components/header/variables'; +@import '@elastic/eui/src/components/nav_drawer/variables'; + +.mgtAdvancedSettingsForm__bottomBar { + margin-left: $euiNavDrawerWidthCollapsed; + z-index: 9; // Puts it inuder the nav drawer when expanded + &--pushForNav { + margin-left: $euiNavDrawerWidthExpanded; + } + @include euiBreakpoint('xs', 's') { + margin-left: 0; + } +} diff --git a/src/plugins/advanced_settings/public/management_app/components/form/_index.scss b/src/plugins/advanced_settings/public/management_app/components/form/_index.scss new file mode 100644 index 0000000000000..2ef4ef1d20ce9 --- /dev/null +++ b/src/plugins/advanced_settings/public/management_app/components/form/_index.scss @@ -0,0 +1 @@ +@import './form'; diff --git a/src/plugins/advanced_settings/public/management_app/components/form/form.test.tsx b/src/plugins/advanced_settings/public/management_app/components/form/form.test.tsx index 468cfbfc70820..0e942665b23a9 100644 --- a/src/plugins/advanced_settings/public/management_app/components/form/form.test.tsx +++ b/src/plugins/advanced_settings/public/management_app/components/form/form.test.tsx @@ -18,9 +18,14 @@ */ import React from 'react'; -import { shallowWithI18nProvider } from 'test_utils/enzyme_helpers'; +import { shallowWithI18nProvider, mountWithI18nProvider } from 'test_utils/enzyme_helpers'; import { UiSettingsType } from '../../../../../../core/public'; +// @ts-ignore +import { findTestSubject } from '@elastic/eui/lib/test'; + +import { notificationServiceMock } from '../../../../../../core/public/mocks'; +import { SettingsChanges } from '../../types'; import { Form } from './form'; jest.mock('../field', () => ({ @@ -29,6 +34,25 @@ jest.mock('../field', () => ({ }, })); +beforeAll(() => { + const localStorage: Record<string, any> = { + 'core.chrome.isLocked': true, + }; + + Object.defineProperty(window, 'localStorage', { + value: { + getItem: (key: string) => { + return localStorage[key] || null; + }, + }, + writable: true, + }); +}); + +afterAll(() => { + delete (window as any).localStorage; +}); + const defaults = { requiresPageReload: false, readOnly: false, @@ -43,50 +67,52 @@ const defaults = { const settings = { dashboard: [ { + ...defaults, name: 'dashboard:test:setting', ariaName: 'dashboard test setting', displayName: 'Dashboard test setting', category: ['dashboard'], - ...defaults, + requiresPageReload: true, }, ], general: [ { + ...defaults, name: 'general:test:date', ariaName: 'general test date', displayName: 'Test date', description: 'bar', category: ['general'], - ...defaults, }, { + ...defaults, name: 'setting:test', ariaName: 'setting test', displayName: 'Test setting', description: 'foo', category: ['general'], - ...defaults, }, ], 'x-pack': [ { + ...defaults, name: 'xpack:test:setting', ariaName: 'xpack test setting', displayName: 'X-Pack test setting', category: ['x-pack'], description: 'bar', - ...defaults, }, ], }; + const categories = ['general', 'dashboard', 'hiddenCategory', 'x-pack']; const categoryCounts = { general: 2, dashboard: 1, 'x-pack': 10, }; -const save = (key: string, value: any) => Promise.resolve(true); -const clear = (key: string) => Promise.resolve(true); +const save = jest.fn((changes: SettingsChanges) => Promise.resolve([true])); + const clearQuery = () => {}; describe('Form', () => { @@ -94,10 +120,10 @@ describe('Form', () => { const component = shallowWithI18nProvider( <Form settings={settings} + visibleSettings={settings} categories={categories} categoryCounts={categoryCounts} save={save} - clear={clear} clearQuery={clearQuery} showNoResultsMessage={true} enableSaving={true} @@ -113,10 +139,10 @@ describe('Form', () => { const component = shallowWithI18nProvider( <Form settings={settings} + visibleSettings={settings} categories={categories} categoryCounts={categoryCounts} save={save} - clear={clear} clearQuery={clearQuery} showNoResultsMessage={true} enableSaving={false} @@ -132,10 +158,10 @@ describe('Form', () => { const component = shallowWithI18nProvider( <Form settings={{}} + visibleSettings={settings} categories={categories} categoryCounts={categoryCounts} save={save} - clear={clear} clearQuery={clearQuery} showNoResultsMessage={true} enableSaving={true} @@ -151,10 +177,10 @@ describe('Form', () => { const component = shallowWithI18nProvider( <Form settings={{}} + visibleSettings={settings} categories={categories} categoryCounts={categoryCounts} save={save} - clear={clear} clearQuery={clearQuery} showNoResultsMessage={false} enableSaving={true} @@ -165,4 +191,70 @@ describe('Form', () => { expect(component).toMatchSnapshot(); }); + + it('should hide bottom bar when clicking on the cancel changes button', async () => { + const wrapper = mountWithI18nProvider( + <Form + settings={settings} + visibleSettings={settings} + categories={categories} + categoryCounts={categoryCounts} + save={save} + clearQuery={clearQuery} + showNoResultsMessage={true} + enableSaving={false} + toasts={{} as any} + dockLinks={{} as any} + /> + ); + (wrapper.instance() as Form).setState({ + unsavedChanges: { + 'dashboard:test:setting': { + value: 'changedValue', + }, + }, + }); + const updated = wrapper.update(); + expect(updated.exists('[data-test-subj="advancedSetting-bottomBar"]')).toEqual(true); + await findTestSubject(updated, `advancedSetting-cancelButton`).simulate('click'); + updated.update(); + expect(updated.exists('[data-test-subj="advancedSetting-bottomBar"]')).toEqual(false); + }); + + it('should show a reload toast when saving setting requiring a page reload', async () => { + const toasts = notificationServiceMock.createStartContract().toasts; + const wrapper = mountWithI18nProvider( + <Form + settings={settings} + visibleSettings={settings} + categories={categories} + categoryCounts={categoryCounts} + save={save} + clearQuery={clearQuery} + showNoResultsMessage={true} + enableSaving={false} + toasts={toasts} + dockLinks={{} as any} + /> + ); + (wrapper.instance() as Form).setState({ + unsavedChanges: { + 'dashboard:test:setting': { + value: 'changedValue', + }, + }, + }); + const updated = wrapper.update(); + + findTestSubject(updated, `advancedSetting-saveButton`).simulate('click'); + expect(save).toHaveBeenCalled(); + await save({ 'dashboard:test:setting': 'changedValue' }); + expect(toasts.add).toHaveBeenCalledWith( + expect.objectContaining({ + title: expect.stringContaining( + 'One or more settings require you to reload the page to take effect.' + ), + }) + ); + }); }); diff --git a/src/plugins/advanced_settings/public/management_app/components/form/form.tsx b/src/plugins/advanced_settings/public/management_app/components/form/form.tsx index 91d587866836e..ef433dd990d33 100644 --- a/src/plugins/advanced_settings/public/management_app/components/form/form.tsx +++ b/src/plugins/advanced_settings/public/management_app/components/form/form.tsx @@ -18,7 +18,7 @@ */ import React, { PureComponent, Fragment } from 'react'; - +import classNames from 'classnames'; import { EuiFlexGroup, EuiFlexItem, @@ -27,30 +27,188 @@ import { EuiPanel, EuiSpacer, EuiText, + EuiTextColor, + EuiBottomBar, + EuiButton, + EuiToolTip, + EuiButtonEmpty, } from '@elastic/eui'; import { FormattedMessage } from '@kbn/i18n/react'; +import { isEmpty } from 'lodash'; +import { i18n } from '@kbn/i18n'; +import { toMountPoint } from '../../../../../kibana_react/public'; import { DocLinksStart, ToastsStart } from '../../../../../../core/public'; import { getCategoryName } from '../../lib'; -import { Field } from '../field'; -import { FieldSetting } from '../../types'; +import { Field, getEditableValue } from '../field'; +import { FieldSetting, SettingsChanges, FieldState } from '../../types'; type Category = string; +const NAV_IS_LOCKED_KEY = 'core.chrome.isLocked'; interface FormProps { settings: Record<string, FieldSetting[]>; + visibleSettings: Record<string, FieldSetting[]>; categories: Category[]; categoryCounts: Record<string, number>; clearQuery: () => void; - save: (key: string, value: any) => Promise<boolean>; - clear: (key: string) => Promise<boolean>; + save: (changes: SettingsChanges) => Promise<boolean[]>; showNoResultsMessage: boolean; enableSaving: boolean; dockLinks: DocLinksStart['links']; toasts: ToastsStart; } +interface FormState { + unsavedChanges: { + [key: string]: FieldState; + }; + loading: boolean; +} + export class Form extends PureComponent<FormProps> { + state: FormState = { + unsavedChanges: {}, + loading: false, + }; + + setLoading(loading: boolean) { + this.setState({ + loading, + }); + } + + getSettingByKey = (key: string): FieldSetting | undefined => { + return Object.values(this.props.settings) + .flat() + .find(el => el.name === key); + }; + + getCountOfUnsavedChanges = (): number => { + return Object.keys(this.state.unsavedChanges).length; + }; + + getCountOfHiddenUnsavedChanges = (): number => { + const shownSettings = Object.values(this.props.visibleSettings) + .flat() + .map(setting => setting.name); + return Object.keys(this.state.unsavedChanges).filter(key => !shownSettings.includes(key)) + .length; + }; + + areChangesInvalid = (): boolean => { + const { unsavedChanges } = this.state; + return Object.values(unsavedChanges).some(({ isInvalid }) => isInvalid); + }; + + handleChange = (key: string, change: FieldState) => { + const setting = this.getSettingByKey(key); + if (!setting) { + return; + } + const { type, defVal, value } = setting; + const savedValue = getEditableValue(type, value, defVal); + if (change.value === savedValue) { + return this.clearChange(key); + } + this.setState({ + unsavedChanges: { + ...this.state.unsavedChanges, + [key]: change, + }, + }); + }; + + clearChange = (key: string) => { + if (!this.state.unsavedChanges[key]) { + return; + } + const unsavedChanges = { ...this.state.unsavedChanges }; + delete unsavedChanges[key]; + + this.setState({ + unsavedChanges, + }); + }; + + clearAllUnsaved = () => { + this.setState({ unsavedChanges: {} }); + }; + + saveAll = async () => { + this.setLoading(true); + const { unsavedChanges } = this.state; + + if (isEmpty(unsavedChanges)) { + return; + } + const configToSave: SettingsChanges = {}; + let requiresReload = false; + + Object.entries(unsavedChanges).forEach(([name, { value }]) => { + const setting = this.getSettingByKey(name); + if (!setting) { + return; + } + const { defVal, type, requiresPageReload } = setting; + let valueToSave = value; + let equalsToDefault = false; + switch (type) { + case 'array': + valueToSave = valueToSave.split(',').map((val: string) => val.trim()); + equalsToDefault = valueToSave.join(',') === (defVal as string[]).join(','); + break; + case 'json': + const isArray = Array.isArray(JSON.parse((defVal as string) || '{}')); + valueToSave = valueToSave.trim(); + valueToSave = valueToSave || (isArray ? '[]' : '{}'); + default: + equalsToDefault = valueToSave === defVal; + } + if (requiresPageReload) { + requiresReload = true; + } + configToSave[name] = equalsToDefault ? null : valueToSave; + }); + + try { + await this.props.save(configToSave); + this.clearAllUnsaved(); + if (requiresReload) { + this.renderPageReloadToast(); + } + } catch (e) { + this.props.toasts.addDanger( + i18n.translate('advancedSettings.form.saveErrorMessage', { + defaultMessage: 'Unable to save', + }) + ); + } + this.setLoading(false); + }; + + renderPageReloadToast = () => { + this.props.toasts.add({ + title: i18n.translate('advancedSettings.form.requiresPageReloadToastDescription', { + defaultMessage: 'One or more settings require you to reload the page to take effect.', + }), + text: toMountPoint( + <> + <EuiFlexGroup justifyContent="flexEnd" gutterSize="s"> + <EuiFlexItem grow={false}> + <EuiButton size="s" onClick={() => window.location.reload()}> + {i18n.translate('advancedSettings.form.requiresPageReloadToastButtonLabel', { + defaultMessage: 'Reload page', + })} + </EuiButton> + </EuiFlexItem> + </EuiFlexGroup> + </> + ), + color: 'success', + }); + }; + renderClearQueryLink(totalSettings: number, currentSettings: number) { const { clearQuery } = this.props; @@ -102,8 +260,9 @@ export class Form extends PureComponent<FormProps> { <Field key={setting.name} setting={setting} - save={this.props.save} - clear={this.props.clear} + handleChange={this.handleChange} + unsavedChanges={this.state.unsavedChanges[setting.name]} + clearChange={this.clearChange} enableSaving={this.props.enableSaving} dockLinks={this.props.dockLinks} toasts={this.props.toasts} @@ -141,23 +300,116 @@ export class Form extends PureComponent<FormProps> { return null; } + renderCountOfUnsaved = () => { + const unsavedCount = this.getCountOfUnsavedChanges(); + const hiddenUnsavedCount = this.getCountOfHiddenUnsavedChanges(); + return ( + <EuiTextColor className="mgtAdvancedSettingsForm__unsavedCountMessage" color="ghost"> + <FormattedMessage + id="advancedSettings.form.countOfSettingsChanged" + defaultMessage="{unsavedCount} unsaved {unsavedCount, plural, + one {setting} + other {settings} + }{hiddenCount, plural, + =0 {} + other {, # hidden} + }" + values={{ + unsavedCount, + hiddenCount: hiddenUnsavedCount, + }} + /> + </EuiTextColor> + ); + }; + + renderBottomBar = () => { + const areChangesInvalid = this.areChangesInvalid(); + const bottomBarClasses = classNames('mgtAdvancedSettingsForm__bottomBar', { + 'mgtAdvancedSettingsForm__bottomBar--pushForNav': + localStorage.getItem(NAV_IS_LOCKED_KEY) === 'true', + }); + return ( + <EuiBottomBar className={bottomBarClasses} data-test-subj="advancedSetting-bottomBar"> + <EuiFlexGroup justifyContent="spaceBetween" alignItems="center"> + <EuiFlexItem grow={false} className="mgtAdvancedSettingsForm__unsavedCount"> + <p id="aria-describedby.countOfUnsavedSettings">{this.renderCountOfUnsaved()}</p> + </EuiFlexItem> + <EuiFlexItem grow={false}> + <EuiFlexGroup gutterSize="s"> + <EuiFlexItem grow={false}> + <EuiButtonEmpty + color="ghost" + size="s" + iconType="cross" + onClick={this.clearAllUnsaved} + aria-describedby="aria-describedby.countOfUnsavedSettings" + data-test-subj="advancedSetting-cancelButton" + > + {i18n.translate('advancedSettings.form.cancelButtonLabel', { + defaultMessage: 'Cancel changes', + })} + </EuiButtonEmpty> + </EuiFlexItem> + <EuiFlexItem grow={false}> + <EuiToolTip + content={ + areChangesInvalid && + i18n.translate('advancedSettings.form.saveButtonTooltipWithInvalidChanges', { + defaultMessage: 'Fix invalid settings before saving.', + }) + } + > + <EuiButton + className="mgtAdvancedSettingsForm__button" + disabled={areChangesInvalid} + color="secondary" + fill + size="s" + iconType="check" + onClick={this.saveAll} + aria-describedby="aria-describedby.countOfUnsavedSettings" + isLoading={this.state.loading} + data-test-subj="advancedSetting-saveButton" + > + {i18n.translate('advancedSettings.form.saveButtonLabel', { + defaultMessage: 'Save changes', + })} + </EuiButton> + </EuiToolTip> + </EuiFlexItem> + </EuiFlexGroup> + </EuiFlexItem> + </EuiFlexGroup> + </EuiBottomBar> + ); + }; + render() { - const { settings, categories, categoryCounts, clearQuery } = this.props; + const { unsavedChanges } = this.state; + const { visibleSettings, categories, categoryCounts, clearQuery } = this.props; const currentCategories: Category[] = []; categories.forEach(category => { - if (settings[category] && settings[category].length) { + if (visibleSettings[category] && visibleSettings[category].length) { currentCategories.push(category); } }); return ( <Fragment> - {currentCategories.length - ? currentCategories.map(category => { - return this.renderCategory(category, settings[category], categoryCounts[category]); - }) - : this.maybeRenderNoSettings(clearQuery)} + <div> + {currentCategories.length + ? currentCategories.map(category => { + return this.renderCategory( + category, + visibleSettings[category], + categoryCounts[category] + ); + }) + : this.maybeRenderNoSettings(clearQuery)} + </div> + {!isEmpty(unsavedChanges) && this.renderBottomBar()} </Fragment> ); } diff --git a/src/plugins/advanced_settings/public/management_app/types.ts b/src/plugins/advanced_settings/public/management_app/types.ts index 05bb5e754563d..d44a05ce36f5d 100644 --- a/src/plugins/advanced_settings/public/management_app/types.ts +++ b/src/plugins/advanced_settings/public/management_app/types.ts @@ -47,6 +47,19 @@ export interface FieldSetting { } // until eui searchbar and query are typed + +export interface SettingsChanges { + [key: string]: any; +} + +export interface FieldState { + value?: any; + changeImage?: boolean; + loading?: boolean; + isInvalid?: boolean; + error?: string | null; +} + export interface IQuery { ast: any; // incomplete text: string; diff --git a/src/plugins/telemetry/public/components/telemetry_management_section.tsx b/src/plugins/telemetry/public/components/telemetry_management_section.tsx index 20c8873b13272..bf14c33a48048 100644 --- a/src/plugins/telemetry/public/components/telemetry_management_section.tsx +++ b/src/plugins/telemetry/public/components/telemetry_management_section.tsx @@ -33,8 +33,8 @@ import { FormattedMessage } from '@kbn/i18n/react'; import { i18n } from '@kbn/i18n'; import { PRIVACY_STATEMENT_URL } from '../../common/constants'; import { OptInExampleFlyout } from './opt_in_example_flyout'; -// @ts-ignore import { Field } from '../../../advanced_settings/public'; +import { ToastsStart } from '../../../../core/public/'; import { TelemetryService } from '../services/telemetry_service'; const SEARCH_TERMS = ['telemetry', 'usage', 'data', 'usage data']; @@ -44,12 +44,14 @@ interface Props { showAppliesSettingMessage: boolean; enableSaving: boolean; query?: any; + toasts: ToastsStart; } interface State { processing: boolean; showExample: boolean; queryMatches: boolean | null; + enabled: boolean; } export class TelemetryManagementSection extends Component<Props, State> { @@ -57,6 +59,7 @@ export class TelemetryManagementSection extends Component<Props, State> { processing: false, showExample: false, queryMatches: null, + enabled: this.props.telemetryService.getIsOptedIn() || false, }; UNSAFE_componentWillReceiveProps(nextProps: Props) { @@ -79,7 +82,7 @@ export class TelemetryManagementSection extends Component<Props, State> { render() { const { telemetryService } = this.props; - const { showExample, queryMatches } = this.state; + const { showExample, queryMatches, enabled, processing } = this.state; if (!telemetryService.getCanChangeOptInStatus()) { return null; @@ -119,7 +122,7 @@ export class TelemetryManagementSection extends Component<Props, State> { displayName: i18n.translate('telemetry.provideUsageStatisticsTitle', { defaultMessage: 'Provide usage statistics', }), - value: telemetryService.getIsOptedIn(), + value: enabled, description: this.renderDescription(), defVal: true, ariaName: i18n.translate('telemetry.provideUsageStatisticsAriaName', { @@ -127,10 +130,10 @@ export class TelemetryManagementSection extends Component<Props, State> { }), } as any } + loading={processing} dockLinks={null as any} toasts={null as any} - save={this.toggleOptIn} - clear={this.toggleOptIn} + handleChange={this.toggleOptIn} enableSaving={this.props.enableSaving} /> </EuiForm> @@ -151,13 +154,13 @@ export class TelemetryManagementSection extends Component<Props, State> { <p> <FormattedMessage id="telemetry.callout.appliesSettingTitle" - defaultMessage="This setting applies to {allOfKibanaText}" + defaultMessage="Changes to this setting apply to {allOfKibanaText} and are saved automatically." values={{ allOfKibanaText: ( <strong> <FormattedMessage id="telemetry.callout.appliesSettingTitle.allOfKibanaText" - defaultMessage="all of Kibana." + defaultMessage="all of Kibana" /> </strong> ), @@ -200,20 +203,35 @@ export class TelemetryManagementSection extends Component<Props, State> { ); toggleOptIn = async (): Promise<boolean> => { - const { telemetryService } = this.props; - const newOptInValue = !telemetryService.getIsOptedIn(); + const { telemetryService, toasts } = this.props; + const newOptInValue = !this.state.enabled; return new Promise((resolve, reject) => { - this.setState({ processing: true }, async () => { - try { - await telemetryService.setOptIn(newOptInValue); - this.setState({ processing: false }); - resolve(true); - } catch (err) { - this.setState({ processing: false }); - reject(err); + this.setState( + { + processing: true, + enabled: newOptInValue, + }, + async () => { + try { + await telemetryService.setOptIn(newOptInValue); + this.setState({ processing: false }); + toasts.addSuccess( + newOptInValue + ? i18n.translate('telemetry.optInSuccessOn', { + defaultMessage: 'Usage data collection turned on.', + }) + : i18n.translate('telemetry.optInSuccessOff', { + defaultMessage: 'Usage data collection turned off.', + }) + ); + resolve(true); + } catch (err) { + this.setState({ processing: false }); + reject(err); + } } - }); + ); }); }; diff --git a/test/functional/page_objects/settings_page.ts b/test/functional/page_objects/settings_page.ts index d7e5064cf7280..ff340c6b0abcd 100644 --- a/test/functional/page_objects/settings_page.ts +++ b/test/functional/page_objects/settings_page.ts @@ -94,7 +94,7 @@ export function SettingsPageProvider({ getService, getPageObjects }: FtrProvider `[data-test-subj="advancedSetting-editField-${propertyName}"] option[value="${propertyValue}"]` ); await PageObjects.header.waitUntilLoadingHasFinished(); - await testSubjects.click(`advancedSetting-saveEditField-${propertyName}`); + await testSubjects.click(`advancedSetting-saveButton`); await PageObjects.header.waitUntilLoadingHasFinished(); } @@ -102,14 +102,14 @@ export function SettingsPageProvider({ getService, getPageObjects }: FtrProvider const input = await testSubjects.find(`advancedSetting-editField-${propertyName}`); await input.clearValue(); await input.type(propertyValue); - await testSubjects.click(`advancedSetting-saveEditField-${propertyName}`); + await testSubjects.click(`advancedSetting-saveButton`); await PageObjects.header.waitUntilLoadingHasFinished(); } async toggleAdvancedSettingCheckbox(propertyName: string) { testSubjects.click(`advancedSetting-editField-${propertyName}`); await PageObjects.header.waitUntilLoadingHasFinished(); - await testSubjects.click(`advancedSetting-saveEditField-${propertyName}`); + await testSubjects.click(`advancedSetting-saveButton`); await PageObjects.header.waitUntilLoadingHasFinished(); } diff --git a/x-pack/plugins/translations/translations/ja-JP.json b/x-pack/plugins/translations/translations/ja-JP.json index 47aa8dd152930..1409d1df1a720 100644 --- a/x-pack/plugins/translations/translations/ja-JP.json +++ b/x-pack/plugins/translations/translations/ja-JP.json @@ -1618,8 +1618,6 @@ "advancedSettings.categoryNames.timelionLabel": "Timelion", "advancedSettings.categoryNames.visualizationsLabel": "ビジュアライゼーション", "advancedSettings.categorySearchLabel": "カテゴリー", - "advancedSettings.field.cancelEditingButtonAriaLabel": "{ariaName} の編集をキャンセル", - "advancedSettings.field.cancelEditingButtonLabel": "キャンセル", "advancedSettings.field.changeImageLinkAriaLabel": "{ariaName} を変更", "advancedSettings.field.changeImageLinkText": "画像を変更", "advancedSettings.field.codeEditorSyntaxErrorMessage": "無効な JSON 構文", @@ -1632,17 +1630,10 @@ "advancedSettings.field.imageTooLargeErrorMessage": "画像が大きすぎます。最大サイズは {maxSizeDescription} です", "advancedSettings.field.offLabel": "オフ", "advancedSettings.field.onLabel": "オン", - "advancedSettings.field.requiresPageReloadToastButtonLabel": "ページを再読み込み", - "advancedSettings.field.requiresPageReloadToastDescription": "「{settingName}」設定を有効にするには、ページを再読み込みしてください。", - "advancedSettings.field.resetFieldErrorMessage": "{name} をリセットできませんでした", "advancedSettings.field.resetToDefaultLinkAriaLabel": "{ariaName} をデフォルトにリセット", "advancedSettings.field.resetToDefaultLinkText": "デフォルトにリセット", - "advancedSettings.field.saveButtonAriaLabel": "{ariaName} を保存", - "advancedSettings.field.saveButtonLabel": "保存", - "advancedSettings.field.saveFieldErrorMessage": "{name} を保存できませんでした", "advancedSettings.form.clearNoSearchResultText": "(検索結果を消去)", "advancedSettings.form.clearSearchResultText": "(検索結果を消去)", - "advancedSettings.form.noSearchResultText": "設定が見つかりませんでした {clearSearch}", "advancedSettings.form.searchResultText": "検索用語により {settingsCount} 件の設定が非表示になっています {clearSearch}", "advancedSettings.pageTitle": "設定", "advancedSettings.searchBar.unableToParseQueryErrorMessage": "クエリをパースできません", @@ -2474,8 +2465,6 @@ "statusPage.statusApp.statusTitle": "プラグインステータス", "statusPage.statusTable.columns.idHeader": "ID", "statusPage.statusTable.columns.statusHeader": "ステータス", - "telemetry.callout.appliesSettingTitle": "この設定は {allOfKibanaText} に適用されます", - "telemetry.callout.appliesSettingTitle.allOfKibanaText": "Kibana のすべて", "telemetry.callout.clusterStatisticsDescription": "これは収集される基本的なクラスター統計の例です。インデックス、シャード、ノードの数が含まれます。監視がオンになっているかどうかなどのハイレベルの使用統計も含まれます。", "telemetry.callout.clusterStatisticsTitle": "クラスター統計", "telemetry.callout.errorLoadingClusterStatisticsDescription": "クラスター統計の取得中に予期せぬエラーが発生しました。Elasticsearch、Kibana、またはネットワークのエラーが原因の可能性があります。Kibana を確認し、ページを再読み込みして再試行してください。", diff --git a/x-pack/plugins/translations/translations/zh-CN.json b/x-pack/plugins/translations/translations/zh-CN.json index e4c2155d7ea7b..ac944c6acaafe 100644 --- a/x-pack/plugins/translations/translations/zh-CN.json +++ b/x-pack/plugins/translations/translations/zh-CN.json @@ -1618,8 +1618,6 @@ "advancedSettings.categoryNames.timelionLabel": "Timelion", "advancedSettings.categoryNames.visualizationsLabel": "可视化", "advancedSettings.categorySearchLabel": "类别", - "advancedSettings.field.cancelEditingButtonAriaLabel": "取消编辑 {ariaName}", - "advancedSettings.field.cancelEditingButtonLabel": "取消", "advancedSettings.field.changeImageLinkAriaLabel": "更改 {ariaName}", "advancedSettings.field.changeImageLinkText": "更改图片", "advancedSettings.field.codeEditorSyntaxErrorMessage": "JSON 语法无效", @@ -1632,14 +1630,8 @@ "advancedSettings.field.imageTooLargeErrorMessage": "图像过大,最大大小为 {maxSizeDescription}", "advancedSettings.field.offLabel": "关闭", "advancedSettings.field.onLabel": "开启", - "advancedSettings.field.requiresPageReloadToastButtonLabel": "重新加载页面", - "advancedSettings.field.requiresPageReloadToastDescription": "请重新加载页面,以使“{settingName}”设置生效。", - "advancedSettings.field.resetFieldErrorMessage": "无法重置 {name}", "advancedSettings.field.resetToDefaultLinkAriaLabel": "将 {ariaName} 重置为默认值", "advancedSettings.field.resetToDefaultLinkText": "重置为默认值", - "advancedSettings.field.saveButtonAriaLabel": "保存 {ariaName}", - "advancedSettings.field.saveButtonLabel": "保存", - "advancedSettings.field.saveFieldErrorMessage": "无法保存 {name}", "advancedSettings.form.clearNoSearchResultText": "(清除搜索)", "advancedSettings.form.clearSearchResultText": "(清除搜索)", "advancedSettings.form.noSearchResultText": "未找到设置{clearSearch}", @@ -2474,8 +2466,6 @@ "statusPage.statusApp.statusTitle": "插件状态", "statusPage.statusTable.columns.idHeader": "ID", "statusPage.statusTable.columns.statusHeader": "状态", - "telemetry.callout.appliesSettingTitle": "此设置适用于{allOfKibanaText}", - "telemetry.callout.appliesSettingTitle.allOfKibanaText": "所有 Kibana。", "telemetry.callout.clusterStatisticsDescription": "这是我们将收集的基本集群统计信息的示例。其包括索引、分片和节点的数目。还包括概括性的使用情况统计信息,例如监测是否打开。", "telemetry.callout.clusterStatisticsTitle": "集群统计信息", "telemetry.callout.errorLoadingClusterStatisticsDescription": "尝试提取集群统计信息时发生意外错误。发生此问题的原因可能是 Elasticsearch 出故障、Kibana 出故障或者有网络错误。检查 Kibana,然后重新加载页面并重试。",