diff --git a/x-pack/plugins/spaces/public/management/edit_space/roles/component/space_assign_role_privilege_form.test.tsx b/x-pack/plugins/spaces/public/management/edit_space/roles/component/space_assign_role_privilege_form.test.tsx index 1c97b9c4d2bc6..d35bdbee4b8bb 100644 --- a/x-pack/plugins/spaces/public/management/edit_space/roles/component/space_assign_role_privilege_form.test.tsx +++ b/x-pack/plugins/spaces/public/management/edit_space/roles/component/space_assign_role_privilege_form.test.tsx @@ -6,7 +6,7 @@ */ import { EuiThemeProvider } from '@elastic/eui'; -import { render, screen, waitFor, within } from '@testing-library/react'; +import { fireEvent, render, screen, waitFor, within } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; import crypto from 'crypto'; import React from 'react'; @@ -142,6 +142,15 @@ describe('PrivilegesRolesForm', () => { jest.clearAllMocks(); }); + it("would open the 'manage roles' link in a new tab", () => { + getRolesSpy.mockResolvedValue([]); + getAllKibanaPrivilegeSpy.mockResolvedValue(createRawKibanaPrivileges(kibanaFeatures)); + + renderPrivilegeRolesForm(); + + expect(screen.getByText('Manage roles')).toHaveAttribute('target', '_blank'); + }); + it('does not display the privilege selection buttons or customization form when no role is selected', async () => { getRolesSpy.mockResolvedValue([]); getAllKibanaPrivilegeSpy.mockResolvedValue(createRawKibanaPrivileges(kibanaFeatures)); @@ -170,6 +179,23 @@ describe('PrivilegesRolesForm', () => { expect(screen.getByTestId('space-assign-role-create-roles-privilege-button')).toBeDisabled(); }); + it('makes a request to refetch available roles if page transitions back from a user interaction page visibility change', () => { + getRolesSpy.mockResolvedValue([]); + getAllKibanaPrivilegeSpy.mockResolvedValue(createRawKibanaPrivileges(kibanaFeatures)); + + renderPrivilegeRolesForm(); + + expect(getRolesSpy).toHaveBeenCalledTimes(1); + + // trigger click on manage roles link, which is perquisite for page visibility handler to trigger role refetch + fireEvent.click(screen.getByText(/manage roles/i)); + + // trigger page visibility change + fireEvent(document, new Event('visibilitychange')); + + expect(getRolesSpy).toHaveBeenCalledTimes(2); + }); + it('renders with the assign roles button disabled when no base privileges or feature privileges are selected', async () => { getRolesSpy.mockResolvedValue([]); getAllKibanaPrivilegeSpy.mockResolvedValue(createRawKibanaPrivileges(kibanaFeatures)); diff --git a/x-pack/plugins/spaces/public/management/edit_space/roles/component/space_assign_role_privilege_form.tsx b/x-pack/plugins/spaces/public/management/edit_space/roles/component/space_assign_role_privilege_form.tsx index e0f3e8f3714c6..74f2b2fde4667 100644 --- a/x-pack/plugins/spaces/public/management/edit_space/roles/component/space_assign_role_privilege_form.tsx +++ b/x-pack/plugins/spaces/public/management/edit_space/roles/component/space_assign_role_privilege_form.tsx @@ -23,6 +23,7 @@ import { EuiSpacer, EuiText, EuiTitle, + useGeneratedHtmlId, } from '@elastic/eui'; import type { EuiComboBoxOptionOption } from '@elastic/eui'; import type { FC } from 'react'; @@ -81,10 +82,13 @@ export const PrivilegesRolesForm: FC = (props) => { const [selectedRoles, setSelectedRoles] = useState>( createRolesComboBoxOptions(defaultSelected) ); + const manageRoleLinkId = useGeneratedHtmlId(); const isEditOperation = useRef(Boolean(defaultSelected.length)); - useEffect(() => { - async function fetchRequiredData(spaceId: string) { + const userInvokedPageVisibilityChange = useRef(null); + + const fetchRequiredData = useCallback( + async (spaceId: string) => { setFetchingDataDeps(true); const [systemRoles, _kibanaPrivileges] = await invokeClient((clients) => @@ -109,10 +113,28 @@ export const PrivilegesRolesForm: FC = (props) => { ); setKibanaPrivileges(_kibanaPrivileges); - } + }, + [invokeClient] + ); + useEffect(() => { fetchRequiredData(space.id!).finally(() => setFetchingDataDeps(false)); - }, [invokeClient, space.id]); + }, [fetchRequiredData, invokeClient, space.id]); + + useEffect(() => { + async function visibilityChangeHandler() { + // page just transitioned back to visible state from hidden state caused by user interaction + if (userInvokedPageVisibilityChange.current && !document.hidden) { + await fetchRequiredData(space.id!).finally(() => setFetchingDataDeps(false)); + } + } + + document.addEventListener('visibilitychange', visibilityChangeHandler); + + return () => { + document.removeEventListener('visibilitychange', visibilityChangeHandler); + }; + }, [fetchRequiredData, invokeClient, space.id]); const selectedRolesCombinedPrivileges = useMemo(() => { const combinedPrivilege = new Set( @@ -345,12 +367,23 @@ export const PrivilegesRolesForm: FC = (props) => { {!isEditOperation.current && ( ) => { + // leverage event propagation, check if manage role link element was clicked + if ((event.target as HTMLFieldSetElement).id === manageRoleLinkId) { + userInvokedPageVisibilityChange.current = true; + } + }} label={i18n.translate( 'xpack.spaces.management.spaceDetails.roles.selectRolesFormRowLabel', { defaultMessage: 'Select roles' } )} labelAppend={ - + {i18n.translate( 'xpack.spaces.management.spaceDetails.roles.selectRolesFormRowLabelAnchor', { defaultMessage: 'Manage roles' }