[Fleet] Fix space selector space color,label for readonly spaces (#212941)

This commit is contained in:
Nicolas Chaulet 2025-03-04 10:08:25 -05:00 committed by GitHub
parent 52bbc24387
commit 601e4de6b8
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 103 additions and 14 deletions

View file

@ -6,18 +6,47 @@
*/
import React from 'react';
import { fireEvent } from '@testing-library/react';
import { fireEvent, waitFor } from '@testing-library/react';
import { useAgentPoliciesSpaces } from '../../../../../../hooks/use_request/spaces';
import { useStartServices } from '../../../../../../hooks/use_core';
import { createFleetTestRendererMock } from '../../../../../../mock';
import { SpaceSelector } from './space_selector';
import { SpaceSelectorComponent as SpaceSelector, type SpaceSelectorProps } from './space_selector';
jest.mock('../../../../../../hooks/use_request/spaces');
jest.mock('../../../../../../hooks/use_core', () => ({
...jest.requireActual('../../../../../../hooks/use_core'),
useStartServices: jest.fn(),
}));
describe('Space Selector', () => {
beforeEach(() => {
jest.mocked(useStartServices).mockImplementation(
() =>
({
...jest.requireActual('../../../../../../hooks/use_core').useStartServices(),
spaces: {
getActiveSpace: () => ({
id: 'default',
}),
ui: {
useSpaces: () => ({
spacesManager: {
getSpaces: async () => [
{
id: 'test2',
name: 'Test2Name',
color: 'blue',
},
],
},
}),
},
},
} as any)
);
jest.mocked(useAgentPoliciesSpaces).mockReturnValue({
data: {
items: [
@ -33,12 +62,16 @@ describe('Space Selector', () => {
},
} as any);
});
function render() {
function render(defaultValue = [] as SpaceSelectorProps['value']) {
const renderer = createFleetTestRendererMock();
const onChange = jest.fn();
const setInvalidSpaceError = jest.fn();
const result = renderer.render(
<SpaceSelector setInvalidSpaceError={setInvalidSpaceError} onChange={onChange} value={[]} />
<SpaceSelector
setInvalidSpaceError={setInvalidSpaceError}
onChange={onChange}
value={defaultValue}
/>
);
return {
@ -87,4 +120,11 @@ describe('Space Selector', () => {
expect(onChange).toBeCalledWith(['test']);
expect(setInvalidSpaceError).not.toBeCalledWith(true);
});
it('render spaces with readonly access', async () => {
const { result } = render(['test2']);
await waitFor(() => new Promise((resolve) => resolve(null)));
const res = result.queryByText('Test2Name');
expect(res).not.toBeNull();
});
});

View file

@ -9,8 +9,9 @@ import { type EuiComboBoxOptionOption, EuiHealth, EuiFormRow } from '@elastic/eu
import { EuiComboBox } from '@elastic/eui';
import { i18n } from '@kbn/i18n';
import React, { useMemo } from 'react';
import { useQuery } from '@tanstack/react-query';
import { useAgentPoliciesSpaces } from '../../../../../../hooks';
import { useAgentPoliciesSpaces, useStartServices } from '../../../../../../hooks';
export interface SpaceSelectorProps {
value: string[];
@ -19,22 +20,62 @@ export interface SpaceSelectorProps {
setInvalidSpaceError?: (hasError: boolean) => void;
}
export const SpaceSelector: React.FC<SpaceSelectorProps> = ({
const useSpacesContextWrapper = () => {
const { spaces } = useStartServices();
return useMemo(
() =>
spaces ? spaces.ui.components.getSpacesContextProvider : ({ children }: any) => children,
[spaces]
);
};
function useAllSpaces() {
const start = useStartServices();
const useSpace = start.spaces?.ui.useSpaces;
const spacesManager = useSpace?.()?.spacesManager;
const { data } = useQuery(
['get-all-spaces'],
() =>
spacesManager?.getSpaces({
purpose: 'any',
}) ?? []
);
const allSpaces = useMemo(() => data ?? [], [data]);
return { allSpaces };
}
export const SpaceSelector: React.FC<SpaceSelectorProps> = (props) => {
const Wrapper = useSpacesContextWrapper();
return (
<Wrapper>
<SpaceSelectorComponent {...props} />
</Wrapper>
);
};
export const SpaceSelectorComponent: React.FC<SpaceSelectorProps> = ({
setInvalidSpaceError,
value,
onChange,
isDisabled,
}) => {
const res = useAgentPoliciesSpaces();
const { allSpaces } = useAllSpaces();
const [error, setError] = React.useState<string>();
const renderOption = React.useCallback(
(option: any, searchValue: string, contentClassName: string) => (
<EuiHealth color={option.color}>
<span className={contentClassName}>{option.label}</span>
</EuiHealth>
),
(option: any, searchValue: string, contentClassName: string) => {
return (
<EuiHealth color={option.color}>
<span className={contentClassName}>{option.label}</span>
</EuiHealth>
);
},
[]
);
@ -43,7 +84,7 @@ export const SpaceSelector: React.FC<SpaceSelectorProps> = ({
res.data?.items.map((item: any) => ({
label: item.name,
key: item.id,
...item,
color: item.color,
})) ?? []
);
}, [res.data]);
@ -55,14 +96,22 @@ export const SpaceSelector: React.FC<SpaceSelectorProps> = ({
return value.map((v) => {
const existingOption = options.find((opt) => opt.key === v);
if (existingOption) {
return existingOption;
}
const existingSpace = allSpaces.find((space) => space.id === v);
const color = existingSpace?.color;
const label = existingSpace?.name ?? v;
return existingOption
? existingOption
: {
label: v,
label,
key: v,
color,
};
});
}, [options, value, res.isInitialLoading]);
}, [options, value, res.isInitialLoading, allSpaces]);
return (
<EuiFormRow