[Ingest Manager] Convert select agent config step to use combo box (#73172)

* Initial pass at using combo box instead of selectable for agent configs

* Hide agent count messaging if fleet isn't set up

* Fix types

* Fix i18n

* Fix i18n again

* Add comment explaining styling

Co-authored-by: Elastic Machine <elasticmachine@users.noreply.github.com>
This commit is contained in:
Jen Huang 2020-07-27 19:21:41 -07:00 committed by GitHub
parent 5af2c1080a
commit 82d7e7db69
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 147 additions and 88 deletions

View file

@ -3,17 +3,19 @@
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/
import React, { useEffect, useState, Fragment } from 'react';
import React, { useEffect, useState } from 'react';
import styled from 'styled-components';
import { i18n } from '@kbn/i18n';
import { FormattedMessage } from '@kbn/i18n/react';
import {
EuiFlexGroup,
EuiFlexItem,
EuiSelectable,
EuiSpacer,
EuiComboBox,
EuiComboBoxOptionOption,
EuiTextColor,
EuiPortal,
EuiButtonEmpty,
EuiFormRow,
EuiLink,
} from '@elastic/eui';
import { Error } from '../../../components';
import { AgentConfig, PackageInfo, GetAgentConfigsResponseItem } from '../../../types';
@ -23,9 +25,30 @@ import {
useGetAgentConfigs,
sendGetOneAgentConfig,
useCapabilities,
useFleetStatus,
} from '../../../hooks';
import { CreateAgentConfigFlyout } from '../list_page/components';
const AgentConfigWrapper = styled(EuiFormRow)`
.euiFormRow__label {
width: 100%;
}
`;
// Custom styling for drop down list items due to:
// 1) the max-width and overflow properties is added to prevent long config
// names/descriptions from overflowing the flex items
// 2) max-width is built from the grow property on the flex items because the value
// changes based on if Fleet is enabled/setup or not
const AgentConfigNameColumn = styled(EuiFlexItem)`
max-width: ${(props) => `${((props.grow as number) / 9) * 100}%`};
overflow: hidden;
`;
const AgentConfigDescriptionColumn = styled(EuiFlexItem)`
max-width: ${(props) => `${((props.grow as number) / 9) * 100}%`};
overflow: hidden;
`;
export const StepSelectConfig: React.FunctionComponent<{
pkgkey: string;
updatePackageInfo: (packageInfo: PackageInfo | undefined) => void;
@ -33,6 +56,8 @@ export const StepSelectConfig: React.FunctionComponent<{
updateAgentConfig: (config: AgentConfig | undefined) => void;
setIsLoadingSecondStep: (isLoading: boolean) => void;
}> = ({ pkgkey, updatePackageInfo, agentConfig, updateAgentConfig, setIsLoadingSecondStep }) => {
const { isReady: isFleetReady } = useFleetStatus();
// Selected config state
const [selectedConfigId, setSelectedConfigId] = useState<string | undefined>(
agentConfig ? agentConfig.id : undefined
@ -106,6 +131,40 @@ export const StepSelectConfig: React.FunctionComponent<{
}
}, [selectedConfigId, agentConfig, updateAgentConfig, setIsLoadingSecondStep]);
const agentConfigOptions: Array<EuiComboBoxOptionOption<string>> = packageInfoData
? agentConfigs.map((agentConf) => {
const alreadyHasLimitedPackage =
(isLimitedPackage &&
doesAgentConfigAlreadyIncludePackage(agentConf, packageInfoData.response.name)) ||
false;
return {
label: agentConf.name,
value: agentConf.id,
disabled: alreadyHasLimitedPackage,
'data-test-subj': 'agentConfigItem',
};
})
: [];
const selectedConfigOption = agentConfigOptions.find(
(option) => option.value === selectedConfigId
);
// Try to select default agent config
useEffect(() => {
if (!selectedConfigId && agentConfigs.length && agentConfigOptions.length) {
const defaultAgentConfig = agentConfigs.find((config) => config.is_default);
if (defaultAgentConfig) {
const defaultAgentConfigOption = agentConfigOptions.find(
(option) => option.value === defaultAgentConfig.id
);
if (defaultAgentConfigOption && !defaultAgentConfigOption.disabled) {
setSelectedConfigId(defaultAgentConfig.id);
}
}
}
}, [agentConfigs, agentConfigOptions, selectedConfigId]);
// Display package error if there is one
if (packageInfoError) {
return (
@ -154,77 +213,95 @@ export const StepSelectConfig: React.FunctionComponent<{
) : null}
<EuiFlexGroup direction="column" gutterSize="m">
<EuiFlexItem>
<EuiSelectable
searchable
allowExclusions={false}
singleSelection={true}
isLoading={isAgentConfigsLoading || isPackageInfoLoading}
options={agentConfigs.map((agentConf) => {
const alreadyHasLimitedPackage =
(isLimitedPackage &&
packageInfoData &&
doesAgentConfigAlreadyIncludePackage(agentConf, packageInfoData.response.name)) ||
false;
return {
label: agentConf.name,
key: agentConf.id,
checked: selectedConfigId === agentConf.id ? 'on' : undefined,
disabled: alreadyHasLimitedPackage,
'data-test-subj': 'agentConfigItem',
};
})}
renderOption={(option) => (
<EuiFlexGroup>
<EuiFlexItem grow={false}>{option.label}</EuiFlexItem>
<AgentConfigWrapper
fullWidth={true}
label={
<EuiFlexGroup justifyContent="spaceBetween">
<EuiFlexItem>
<EuiTextColor color="subdued">
{agentConfigsById[option.key!].description}
</EuiTextColor>
<FormattedMessage
id="xpack.ingestManager.createPackageConfig.StepSelectConfig.agentConfigLabel"
defaultMessage="Agent configuration"
/>
</EuiFlexItem>
<EuiFlexItem grow={false}>
<EuiTextColor color="subdued">
<FormattedMessage
id="xpack.ingestManager.createPackageConfig.StepSelectConfig.agentConfigAgentsCountText"
defaultMessage="{count, plural, one {# agent} other {# agents}}"
values={{
count: agentConfigsById[option.key!].agents || 0,
}}
/>
</EuiTextColor>
<div>
<EuiLink
disabled={!hasWriteCapabilites}
onClick={() => setIsCreateAgentConfigFlyoutOpen(true)}
>
<FormattedMessage
id="xpack.ingestManager.createPackageConfig.StepSelectConfig.addButton"
defaultMessage="Create agent configuration"
/>
</EuiLink>
</div>
</EuiFlexItem>
</EuiFlexGroup>
)}
listProps={{
bordered: true,
}}
searchProps={{
placeholder: i18n.translate(
'xpack.ingestManager.createPackageConfig.StepSelectConfig.filterAgentConfigsInputPlaceholder',
{
defaultMessage: 'Search for agent configurations',
}
),
}}
height={180}
onChange={(options) => {
const selectedOption = options.find((option) => option.checked === 'on');
if (selectedOption) {
if (selectedOption.key !== selectedConfigId) {
setSelectedConfigId(selectedOption.key);
}
} else {
setSelectedConfigId(undefined);
}
}}
}
helpText={
isFleetReady && selectedConfigId ? (
<FormattedMessage
id="xpack.ingestManager.createPackageConfig.StepSelectConfig.agentConfigAgentsDescriptionText"
defaultMessage="{count, plural, one {# agent} other {# agents}} are enrolled with the selected agent configuration."
values={{
count: agentConfigsById[selectedConfigId].agents || 0,
}}
/>
) : null
}
>
{(list, search) => (
<Fragment>
{search}
<EuiSpacer size="m" />
{list}
</Fragment>
)}
</EuiSelectable>
<EuiComboBox
placeholder={i18n.translate(
'xpack.ingestManager.createPackageConfig.StepSelectConfig.agentConfigPlaceholderText',
{
defaultMessage: 'Select an agent configuration to add this integration to',
}
)}
singleSelection={{ asPlainText: true }}
isClearable={false}
fullWidth={true}
isLoading={isAgentConfigsLoading || isPackageInfoLoading}
options={agentConfigOptions}
renderOption={(option: EuiComboBoxOptionOption<string>) => {
return (
<EuiFlexGroup>
<AgentConfigNameColumn grow={2}>
<span className="eui-textTruncate">{option.label}</span>
</AgentConfigNameColumn>
<AgentConfigDescriptionColumn grow={isFleetReady ? 5 : 7}>
<EuiTextColor className="eui-textTruncate" color="subdued">
{agentConfigsById[option.value!].description}
</EuiTextColor>
</AgentConfigDescriptionColumn>
{isFleetReady ? (
<EuiFlexItem grow={2} className="eui-textRight">
<EuiTextColor color="subdued">
<FormattedMessage
id="xpack.ingestManager.createPackageConfig.StepSelectConfig.agentConfigAgentsCountText"
defaultMessage="{count, plural, one {# agent} other {# agents}} enrolled"
values={{
count: agentConfigsById[option.value!].agents || 0,
}}
/>
</EuiTextColor>
</EuiFlexItem>
) : null}
</EuiFlexGroup>
);
}}
selectedOptions={selectedConfigOption ? [selectedConfigOption] : []}
onChange={(options) => {
const selectedOption = options[0] || undefined;
if (selectedOption) {
if (selectedOption.value !== selectedConfigId) {
setSelectedConfigId(selectedOption.value);
}
} else {
setSelectedConfigId(undefined);
}
}}
/>
</AgentConfigWrapper>
</EuiFlexItem>
{/* Display selected agent config error if there is one */}
{selectedConfigError ? (
@ -240,22 +317,6 @@ export const StepSelectConfig: React.FunctionComponent<{
/>
</EuiFlexItem>
) : null}
<EuiFlexItem>
<div>
<EuiButtonEmpty
iconType="plusInCircle"
isDisabled={!hasWriteCapabilites}
onClick={() => setIsCreateAgentConfigFlyoutOpen(true)}
flush="left"
size="s"
>
<FormattedMessage
id="xpack.ingestManager.createPackageConfig.StepSelectConfig.addButton"
defaultMessage="New agent configuration"
/>
</EuiButtonEmpty>
</div>
</EuiFlexItem>
</EuiFlexGroup>
</>
);

View file

@ -160,7 +160,7 @@ export const CreateAgentConfigFlyout: React.FunctionComponent<Props> = ({
);
return (
<FlyoutWithHigherZIndex onClose={onClose} size="l" maxWidth={400} {...restOfProps}>
<FlyoutWithHigherZIndex onClose={() => onClose()} size="l" maxWidth={400} {...restOfProps}>
{header}
{body}
{footer}

View file

@ -8108,7 +8108,6 @@
"xpack.ingestManager.createPackageConfig.StepSelectConfig.errorLoadingAgentConfigsTitle": "エージェント構成の読み込みエラー",
"xpack.ingestManager.createPackageConfig.StepSelectConfig.errorLoadingPackageTitle": "パッケージ情報の読み込みエラー",
"xpack.ingestManager.createPackageConfig.StepSelectConfig.errorLoadingSelectedAgentConfigTitle": "選択したエージェント構成の読み込みエラー",
"xpack.ingestManager.createPackageConfig.StepSelectConfig.filterAgentConfigsInputPlaceholder": "エージェント構成の検索",
"xpack.ingestManager.createPackageConfig.stepSelectPackage.errorLoadingConfigTitle": "エージェント構成情報の読み込みエラー",
"xpack.ingestManager.createPackageConfig.stepSelectPackage.errorLoadingPackagesTitle": "統合の読み込みエラー",
"xpack.ingestManager.createPackageConfig.stepSelectPackage.errorLoadingSelectedPackageTitle": "選択した統合の読み込みエラー",

View file

@ -8113,7 +8113,6 @@
"xpack.ingestManager.createPackageConfig.StepSelectConfig.errorLoadingAgentConfigsTitle": "加载代理配置时出错",
"xpack.ingestManager.createPackageConfig.StepSelectConfig.errorLoadingPackageTitle": "加载软件包信息时出错",
"xpack.ingestManager.createPackageConfig.StepSelectConfig.errorLoadingSelectedAgentConfigTitle": "加载选定代理配置时出错",
"xpack.ingestManager.createPackageConfig.StepSelectConfig.filterAgentConfigsInputPlaceholder": "搜索代理配置",
"xpack.ingestManager.createPackageConfig.stepSelectPackage.errorLoadingConfigTitle": "加载代理配置信息时出错",
"xpack.ingestManager.createPackageConfig.stepSelectPackage.errorLoadingPackagesTitle": "加载集成时出错",
"xpack.ingestManager.createPackageConfig.stepSelectPackage.errorLoadingSelectedPackageTitle": "加载选定集成时出错",