Skip to content

Commit

Permalink
[Ingest Manager] Convert select agent config step to use combo box (#…
Browse files Browse the repository at this point in the history
…73172) (#73394)

* 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>

Co-authored-by: Elastic Machine <elasticmachine@users.noreply.github.com>
  • Loading branch information
jen-huang and elasticmachine authored Jul 28, 2020
1 parent db26c01 commit 6187fa6
Show file tree
Hide file tree
Showing 4 changed files with 145 additions and 86 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand All @@ -23,16 +25,39 @@ 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;
agentConfig: AgentConfig | undefined;
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
Expand Down Expand Up @@ -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 (
Expand Down Expand Up @@ -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',
}
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
}
>
<EuiComboBox
placeholder={i18n.translate(
'xpack.ingestManager.createPackageConfig.StepSelectConfig.agentConfigPlaceholderText',
{
defaultMessage: 'Search for agent configurations',
defaultMessage: 'Select an agent configuration to add this integration to',
}
),
}}
height={180}
onChange={(options) => {
const selectedOption = options.find((option) => option.checked === 'on');
if (selectedOption) {
if (selectedOption.key !== selectedConfigId) {
setSelectedConfigId(selectedOption.key);
)}
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);
}
} else {
setSelectedConfigId(undefined);
}
}}
>
{(list, search) => (
<Fragment>
{search}
<EuiSpacer size="m" />
{list}
</Fragment>
)}
</EuiSelectable>
}}
/>
</AgentConfigWrapper>
</EuiFlexItem>
{/* Display selected agent config error if there is one */}
{selectedConfigError ? (
Expand All @@ -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>
</>
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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}
Expand Down
1 change: 0 additions & 1 deletion x-pack/plugins/translations/translations/ja-JP.json
Original file line number Diff line number Diff line change
Expand Up @@ -8125,7 +8125,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": "選択した統合の読み込みエラー",
Expand Down
1 change: 0 additions & 1 deletion x-pack/plugins/translations/translations/zh-CN.json
Original file line number Diff line number Diff line change
Expand Up @@ -8129,7 +8129,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": "加载选定集成时出错",
Expand Down

0 comments on commit 6187fa6

Please sign in to comment.