Skip to content

Commit

Permalink
[Fleet] allow clearing version combo (#175322)
Browse files Browse the repository at this point in the history
## Summary

Closes #175294

Allow clearing upgrade version combo, added validation to highlight that
version is required.
Clearing is allowed with backspace or clear button.
Invalid state goes away when selecting a version from the list or typing
a custom version.

Single agent upgrade:
<img width="819" alt="image"
src="https://github.com/elastic/kibana/assets/90178898/434301d8-ee2b-4641-8405-a4a673c2eeb6">

Bulk agent upgrade:
<img width="782" alt="image"
src="https://github.com/elastic/kibana/assets/90178898/08a12742-2093-42e6-b6cf-8ed5467a7e70">


### Checklist

- [x] Any text added follows [EUI's writing
guidelines](https://elastic.github.io/eui/#/guidelines/writing), uses
sentence case text and includes [i18n
support](https://github.com/elastic/kibana/blob/main/packages/kbn-i18n/README.md)
- [x] [Unit or functional
tests](https://www.elastic.co/guide/en/kibana/master/development-tests.html)
were updated or added to match the most common scenarios
  • Loading branch information
juliaElastic authored Jan 24, 2024
1 parent 4d33d44 commit 4704007
Show file tree
Hide file tree
Showing 2 changed files with 63 additions and 9 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,38 @@ describe('AgentUpgradeAgentModal', () => {
});
});

it('should make combo invalid on clearing version', async () => {
const { utils } = renderAgentUpgradeAgentModal({
agents: [{ id: 'agent1', local_metadata: { host: 'abc' } }] as any,
agentCount: 1,
});

await waitFor(() => {
fireEvent.click(utils.getByTestId('comboBoxClearButton'));
const container = utils.getByTestId('agentUpgradeModal.VersionCombobox');
const input = within(container).getByRole<HTMLInputElement>('combobox');
expect(input?.value).toEqual('');
expect(utils.getByText('Version is required')).toBeInTheDocument();
expect(utils.getByTestId('confirmModalConfirmButton')).toBeDisabled();
});
});

it('should make combo invalid on clearing version - bulk action', async () => {
const { utils } = renderAgentUpgradeAgentModal({
agents: '*',
agentCount: 1,
});

await waitFor(() => {
fireEvent.click(utils.getByTestId('comboBoxClearButton'));
const container = utils.getByTestId('agentUpgradeModal.VersionCombobox');
const input = within(container).getByRole<HTMLInputElement>('combobox');
expect(input?.value).toEqual('');
expect(utils.getByText('Version is required')).toBeInTheDocument();
expect(utils.getByTestId('confirmModalConfirmButton')).toBeDisabled();
});
});

it('should display the custom version text input if no versions', async () => {
const { utils } = renderAgentUpgradeAgentModal({
agents: [
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,8 @@ export const AgentUpgradeAgentModal: React.FunctionComponent<AgentUpgradeAgentMo
const [updatingQuery, setUpdatingQuery] = useState<Agent[] | string>('');

const QUERY_STUCK_UPDATING = `status:updating AND upgrade_started_at:* AND NOT upgraded_at:* AND upgrade_started_at < now-${AGENT_UPDATING_TIMEOUT_HOURS}h`;
const EMPTY_VALUE = useMemo(() => ({ label: '', value: '' }), []);
const [isInvalid, setIsInvalid] = useState(false);

useEffect(() => {
const getStuckUpdatingAgentCount = async (agentsOrQuery: Agent[] | string) => {
Expand Down Expand Up @@ -179,10 +181,10 @@ export const AgentUpgradeAgentModal: React.FunctionComponent<AgentUpgradeAgentMo
value: option,
}));
if (options.length === 0) {
return [{ label: '', value: '' }];
return [EMPTY_VALUE];
}
return options;
}, [availableVersions, minVersion]);
}, [availableVersions, minVersion, EMPTY_VALUE]);
const noVersions = !availableVersions || versionOptions[0]?.value === '';

const maintenanceOptions: Array<EuiComboBoxOptionOption<number>> = MAINTENANCE_VALUES.map(
Expand Down Expand Up @@ -292,6 +294,7 @@ export const AgentUpgradeAgentModal: React.FunctionComponent<AgentUpgradeAgentMo
value: normalizedSearchValue,
};
setSelectedVersion([newOption]);
setIsInvalid(!normalizedSearchValue);
};

return (
Expand Down Expand Up @@ -343,6 +346,7 @@ export const AgentUpgradeAgentModal: React.FunctionComponent<AgentUpgradeAgentMo
confirmButtonDisabled={
isSubmitting ||
(isUpdating && updatingAgents === 0) ||
!selectedVersion[0].value ||
(isSingleAgent && !isAgentUpgradeableToVersion(agents[0], selectedVersion[0].value))
}
confirmButtonText={
Expand Down Expand Up @@ -378,6 +382,7 @@ export const AgentUpgradeAgentModal: React.FunctionComponent<AgentUpgradeAgentMo
defaultMessage="No newer versions found to upgrade to. You may type in a custom version."
/>
) : isSingleAgent ? (
selectedVersion[0].value &&
!isAgentUpgradeableToVersion(agents[0], selectedVersion[0].value) ? (
<EuiCallOut
data-test-subj="agentUpgradeModal.notUpgradeableCallout"
Expand Down Expand Up @@ -407,10 +412,12 @@ export const AgentUpgradeAgentModal: React.FunctionComponent<AgentUpgradeAgentMo
<p>
<FormattedMessage
id="xpack.fleet.upgradeAgents.upgradeSingleDescription"
defaultMessage="This action will upgrade the agent running on '{hostName}' to version {version}. This action can not be undone. Are you sure you wish to continue?"
defaultMessage="This action will upgrade the agent running on '{hostName}'{version}. This action can not be undone. Are you sure you wish to continue?"
values={{
hostName: ((agents[0] as Agent).local_metadata.host as any).hostname,
version: getVersion(selectedVersion),
version: selectedVersion[0].value
? ' to version ' + getVersion(selectedVersion)
: '',
}}
/>
</p>
Expand All @@ -433,8 +440,10 @@ export const AgentUpgradeAgentModal: React.FunctionComponent<AgentUpgradeAgentMo
) : (
<FormattedMessage
id="xpack.fleet.upgradeAgents.upgradeMultipleDescription"
defaultMessage="This action will upgrade multiple agents to version {version}. This action can not be undone. Are you sure you wish to continue?"
values={{ version: getVersion(selectedVersion) }}
defaultMessage="This action will upgrade multiple agents{version}. This action can not be undone. Are you sure you wish to continue?"
values={{
version: selectedVersion[0].value ? ' to version ' + getVersion(selectedVersion) : '',
}}
/>
)}
</p>
Expand All @@ -443,6 +452,15 @@ export const AgentUpgradeAgentModal: React.FunctionComponent<AgentUpgradeAgentMo
defaultMessage: 'Upgrade version',
})}
fullWidth
isInvalid={isInvalid}
error={
isInvalid ? (
<FormattedMessage
id="xpack.fleet.upgradeAgents.versionRequiredText"
defaultMessage="Version is required"
/>
) : undefined
}
>
{noVersions ? (
<EuiFieldText
Expand All @@ -462,18 +480,22 @@ export const AgentUpgradeAgentModal: React.FunctionComponent<AgentUpgradeAgentMo
fullWidth
singleSelection={{ asPlainText: true }}
options={versionOptions}
isClearable={false}
isClearable={true}
selectedOptions={selectedVersion}
onChange={(selected: Array<EuiComboBoxOptionOption<string>>) => {
if (!selected.length) {
return;
setSelectedVersion([EMPTY_VALUE]);
setIsInvalid(true);
} else {
setSelectedVersion(selected);
setIsInvalid(false);
}
setSelectedVersion(selected);
}}
onCreateOption={
config?.internal?.onlyAllowAgentUpgradeToKnownVersions ? undefined : onCreateOption
}
customOptionText="Use custom agent version {searchValue} (not recommended)"
isInvalid={isInvalid}
/>
)}
</EuiFormRow>
Expand Down

0 comments on commit 4704007

Please sign in to comment.