-
Notifications
You must be signed in to change notification settings - Fork 8.3k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[Fleet] implements new design for outputs UI (#118910)
- Loading branch information
1 parent
8d96d32
commit 6b2838a
Showing
36 changed files
with
1,627 additions
and
672 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
229 changes: 229 additions & 0 deletions
229
...fleet/public/applications/fleet/sections/settings/components/edit_output_flyout/index.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,229 @@ | ||
/* | ||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one | ||
* or more contributor license agreements. Licensed under the Elastic License | ||
* 2.0; you may not use this file except in compliance with the Elastic License | ||
* 2.0. | ||
*/ | ||
|
||
import React from 'react'; | ||
import { FormattedMessage } from '@kbn/i18n/react'; | ||
import { | ||
EuiFlyout, | ||
EuiFlyoutBody, | ||
EuiFlyoutHeader, | ||
EuiTitle, | ||
EuiFlyoutFooter, | ||
EuiFlexGroup, | ||
EuiFlexItem, | ||
EuiButtonEmpty, | ||
EuiButton, | ||
EuiForm, | ||
EuiFormRow, | ||
EuiFieldText, | ||
EuiSelect, | ||
EuiSwitch, | ||
EuiCallOut, | ||
EuiSpacer, | ||
} from '@elastic/eui'; | ||
import { i18n } from '@kbn/i18n'; | ||
|
||
import { HostsInput } from '../hosts_input'; | ||
import type { Output } from '../../../../types'; | ||
import { FLYOUT_MAX_WIDTH } from '../../constants'; | ||
|
||
import { YamlCodeEditorWithPlaceholder } from './yaml_code_editor_with_placeholder'; | ||
import { useOutputForm } from './use_output_form'; | ||
|
||
export interface EditOutputFlyoutProps { | ||
output?: Output; | ||
onClose: () => void; | ||
} | ||
|
||
export const EditOutputFlyout: React.FunctionComponent<EditOutputFlyoutProps> = ({ | ||
onClose, | ||
output, | ||
}) => { | ||
const form = useOutputForm(onClose, output); | ||
const inputs = form.inputs; | ||
|
||
return ( | ||
<EuiFlyout maxWidth={FLYOUT_MAX_WIDTH} onClose={onClose}> | ||
<EuiFlyoutHeader hasBorder={true}> | ||
<EuiTitle size="m"> | ||
<h2 id="FleetEditOutputFlyoutTitle"> | ||
{!output ? ( | ||
<FormattedMessage | ||
id="xpack.fleet.settings.editOutputFlyout.createTitle" | ||
defaultMessage="Add new output" | ||
/> | ||
) : ( | ||
<FormattedMessage | ||
id="xpack.fleet.settings.editOutputFlyout.editTitle" | ||
defaultMessage="Edit output" | ||
/> | ||
)} | ||
</h2> | ||
</EuiTitle> | ||
</EuiFlyoutHeader> | ||
<EuiFlyoutBody> | ||
{output?.is_preconfigured && ( | ||
<> | ||
<EuiCallOut | ||
iconType="lock" | ||
title={ | ||
<FormattedMessage | ||
id="xpack.fleet.settings.editOutputFlyout.preconfiguredOutputCalloutTitle" | ||
defaultMessage="This output is managed outside of Fleet" | ||
/> | ||
} | ||
> | ||
<FormattedMessage | ||
id="xpack.fleet.settings.editOutputFlyout.preconfiguredOutputCalloutDescription" | ||
defaultMessage="Most actions related to this output are unavailable. Refer to your kibana config for more | ||
detail." | ||
/> | ||
</EuiCallOut> | ||
<EuiSpacer size="m" /> | ||
</> | ||
)} | ||
<EuiForm> | ||
<EuiFormRow | ||
fullWidth | ||
label={ | ||
<FormattedMessage | ||
id="xpack.fleet.settings.editOutputFlyout.nameInputLabel" | ||
defaultMessage="Name" | ||
/> | ||
} | ||
{...inputs.nameInput.formRowProps} | ||
> | ||
<EuiFieldText | ||
fullWidth | ||
{...inputs.nameInput.props} | ||
placeholder={i18n.translate( | ||
'xpack.fleet.settings.editOutputFlyout.nameInputPlaceholder', | ||
{ | ||
defaultMessage: 'Specify name', | ||
} | ||
)} | ||
/> | ||
</EuiFormRow> | ||
<EuiFormRow | ||
fullWidth | ||
label={ | ||
<FormattedMessage | ||
id="xpack.fleet.settings.editOutputFlyout.typeInputLabel" | ||
defaultMessage="Type" | ||
/> | ||
} | ||
> | ||
<EuiSelect | ||
fullWidth | ||
{...inputs.typeInput.props} | ||
options={[{ value: 'elasticsearch', text: 'Elasticsearch' }]} | ||
placeholder={i18n.translate( | ||
'xpack.fleet.settings.editOutputFlyout.typeInputPlaceholder', | ||
{ | ||
defaultMessage: 'Specify type', | ||
} | ||
)} | ||
/> | ||
</EuiFormRow> | ||
<HostsInput | ||
label={i18n.translate('xpack.fleet.settings.editOutputFlyout.hostsInputLabel', { | ||
defaultMessage: 'Hosts', | ||
})} | ||
{...inputs.elasticsearchUrlInput.props} | ||
/> | ||
<EuiFormRow | ||
label={i18n.translate('xpack.fleet.settings.editOutputFlyout.yamlConfigInputLabel', { | ||
defaultMessage: 'Advanced YAML configuration', | ||
})} | ||
{...inputs.additionalYamlConfigInput.formRowProps} | ||
fullWidth | ||
> | ||
<YamlCodeEditorWithPlaceholder | ||
value={inputs.additionalYamlConfigInput.value} | ||
onChange={inputs.additionalYamlConfigInput.setValue} | ||
disabled={inputs.additionalYamlConfigInput.props.disabled} | ||
placeholder={i18n.translate( | ||
'xpack.fleet.settings.editOutputFlyout.yamlConfigInputPlaceholder', | ||
{ | ||
defaultMessage: | ||
'# YAML settings here will be added to the Elasticsearch output section of each agent policy.', | ||
} | ||
)} | ||
/> | ||
</EuiFormRow> | ||
<EuiFormRow fullWidth {...inputs.defaultOutputInput.formRowProps}> | ||
<EuiSwitch | ||
{...inputs.defaultOutputInput.props} | ||
label={ | ||
<FormattedMessage | ||
id="xpack.fleet.settings.editOutputFlyout.defaultOutputSwitchLabel" | ||
defaultMessage="Make this output the default for {boldAgentIntegrations}." | ||
values={{ | ||
boldAgentIntegrations: ( | ||
<strong> | ||
<FormattedMessage | ||
id="xpack.fleet.settings.editOutputFlyout.agentIntegrationsBold" | ||
defaultMessage="agent integrations" | ||
/> | ||
</strong> | ||
), | ||
}} | ||
/> | ||
} | ||
/> | ||
</EuiFormRow> | ||
<EuiFormRow fullWidth {...inputs.defaultMonitoringOutputInput.formRowProps}> | ||
<EuiSwitch | ||
{...inputs.defaultMonitoringOutputInput.props} | ||
label={ | ||
<FormattedMessage | ||
id="xpack.fleet.settings.editOutputFlyout.defaultMontoringOutputSwitchLabel" | ||
defaultMessage="Make this output the default for {boldAgentMonitoring}." | ||
values={{ | ||
boldAgentMonitoring: ( | ||
<strong> | ||
<FormattedMessage | ||
id="xpack.fleet.settings.editOutputFlyout.agentMonitoringBold" | ||
defaultMessage="agent monitoring" | ||
/> | ||
</strong> | ||
), | ||
}} | ||
/> | ||
} | ||
/> | ||
</EuiFormRow> | ||
</EuiForm> | ||
</EuiFlyoutBody> | ||
<EuiFlyoutFooter> | ||
<EuiFlexGroup justifyContent="spaceBetween"> | ||
<EuiFlexItem grow={false}> | ||
<EuiButtonEmpty onClick={onClose} flush="left"> | ||
<FormattedMessage | ||
id="xpack.fleet.settings.fleetServerHostsFlyout.cancelButtonLabel" | ||
defaultMessage="Cancel" | ||
/> | ||
</EuiButtonEmpty> | ||
</EuiFlexItem> | ||
<EuiFlexItem grow={false}> | ||
<EuiButton | ||
fill | ||
isLoading={form.isLoading} | ||
isDisabled={form.isDisabled} | ||
onClick={form.submit} | ||
> | ||
<FormattedMessage | ||
id="xpack.fleet.settings.fleetServerHostsFlyout.saveButton" | ||
defaultMessage="Save and apply settings" | ||
/> | ||
</EuiButton> | ||
</EuiFlexItem> | ||
</EuiFlexGroup> | ||
</EuiFlyoutFooter> | ||
</EuiFlyout> | ||
); | ||
}; |
75 changes: 75 additions & 0 deletions
75
...ons/fleet/sections/settings/components/edit_output_flyout/output_form_validators.test.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,75 @@ | ||
/* | ||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one | ||
* or more contributor license agreements. Licensed under the Elastic License | ||
* 2.0; you may not use this file except in compliance with the Elastic License | ||
* 2.0. | ||
*/ | ||
|
||
import { validateHosts, validateYamlConfig } from './output_form_validators'; | ||
|
||
describe('Output form validation', () => { | ||
describe('validateHosts', () => { | ||
it('should work without any urls', () => { | ||
const res = validateHosts([]); | ||
|
||
expect(res).toBeUndefined(); | ||
}); | ||
|
||
it('should work with valid url', () => { | ||
const res = validateHosts(['https://test.fr:9200']); | ||
|
||
expect(res).toBeUndefined(); | ||
}); | ||
|
||
it('should return an error with invalid url', () => { | ||
const res = validateHosts(['toto']); | ||
|
||
expect(res).toEqual([{ index: 0, message: 'Invalid URL' }]); | ||
}); | ||
|
||
it('should return an error with url with invalid port', () => { | ||
const res = validateHosts(['https://test.fr:qwerty9200']); | ||
|
||
expect(res).toEqual([{ index: 0, message: 'Invalid URL' }]); | ||
}); | ||
|
||
it('should return an error with multiple invalid urls', () => { | ||
const res = validateHosts(['toto', 'tata']); | ||
|
||
expect(res).toEqual([ | ||
{ index: 0, message: 'Invalid URL' }, | ||
{ index: 1, message: 'Invalid URL' }, | ||
]); | ||
}); | ||
it('should return an error with duplicate urls', () => { | ||
const res = validateHosts(['http://test.fr', 'http://test.fr']); | ||
|
||
expect(res).toEqual([ | ||
{ index: 0, message: 'Duplicate URL' }, | ||
{ index: 1, message: 'Duplicate URL' }, | ||
]); | ||
}); | ||
}); | ||
describe('validateYamlConfig', () => { | ||
it('should work with an empty yaml', () => { | ||
const res = validateYamlConfig(``); | ||
|
||
expect(res).toBeUndefined(); | ||
}); | ||
|
||
it('should work with valid yaml', () => { | ||
const res = validateYamlConfig(`test: 123`); | ||
|
||
expect(res).toBeUndefined(); | ||
}); | ||
|
||
it('should return an error with invalid yaml', () => { | ||
const res = validateYamlConfig(`{}}`); | ||
|
||
expect(res).toBeDefined(); | ||
if (typeof res !== 'undefined') { | ||
expect(res[0]).toContain('Invalid YAML: '); | ||
} | ||
}); | ||
}); | ||
}); |
Oops, something went wrong.