diff --git a/src/js/IAMClient.ts b/src/js/IAMClient.ts index 5037c08b7..6f7c213bd 100644 --- a/src/js/IAMClient.ts +++ b/src/js/IAMClient.ts @@ -189,6 +189,14 @@ export default class IAMClient implements IAMClientInterface { .promise(); } + getRole(roleName: string) { + return notFalsyTypeGuard(this.client) + .getRole({ + RoleName: roleName, + }) + .promise(); + } + listOwnAccessKeys() { return notFalsyTypeGuard(this.client).listAccessKeys().promise(); } diff --git a/src/react/DataServiceRoleProvider.tsx b/src/react/DataServiceRoleProvider.tsx index b31ec9256..143d3742c 100644 --- a/src/react/DataServiceRoleProvider.tsx +++ b/src/react/DataServiceRoleProvider.tsx @@ -97,6 +97,7 @@ export const useCurrentAccount = () => { const DataServiceRoleProvider = ({ children, + inlineLoader = false, /** * DoNotChangePropsWithRedux is a static props. * When set, it must not be changed, otherwise it will break the hook rules. @@ -105,6 +106,7 @@ const DataServiceRoleProvider = ({ DoNotChangePropsWithRedux = true, }: { children: JSX.Element; + inlineLoader?: boolean; DoNotChangePropsWithRedux?: boolean; }) => { const [role, setRoleState] = useState<{ roleArn: string }>({ @@ -181,7 +183,7 @@ const DataServiceRoleProvider = ({ if (role.roleArn && !assumedRole) { //@ts-expect-error fix this when you are working on it - return Loading...; + return inlineLoader ?
loading...
: Loading...; } if (DoNotChangePropsWithRedux) { diff --git a/src/react/ui-elements/SelectAccountIAMRole.tsx b/src/react/ui-elements/SelectAccountIAMRole.tsx index d813b750c..e81d5d840 100644 --- a/src/react/ui-elements/SelectAccountIAMRole.tsx +++ b/src/react/ui-elements/SelectAccountIAMRole.tsx @@ -1,9 +1,9 @@ -import { Stack } from '@scality/core-ui'; +import { Form, FormGroup, FormSection, Stack } from '@scality/core-ui'; import { Select } from '@scality/core-ui/dist/next'; import { IAM } from 'aws-sdk'; import { Bucket } from 'aws-sdk/clients/s3'; import { PropsWithChildren, useState } from 'react'; -import { useQuery, useQueryClient } from 'react-query'; +import { useMutation, useQuery, useQueryClient } from 'react-query'; import { MemoryRouter, Route, useHistory, useParams } from 'react-router-dom'; import DataServiceRoleProvider, { useAssumedRole, @@ -20,7 +20,7 @@ import { } from '../next-architecture/ui/AccessibleAccountsAdapterProvider'; import { AccountsLocationsEndpointsAdapterProvider } from '../next-architecture/ui/AccountsLocationsEndpointsAdapterProvider'; import { getListRolesQuery } from '../queries'; -import { regexArn } from '../utils/hooks'; +import { SCALITY_INTERNAL_ROLES, regexArn } from '../utils/hooks'; class NoOpMetricsAdapter implements IMetricsAdapter { async listBucketsLatestUsedCapacity( @@ -128,7 +128,7 @@ const InternalProvider = ({ ]} > - + void; + onChange: ( + account: Account, + role: IAM.Role, + keycloakRoleName: string, + ) => void; defaultValue?: { accountName: string; roleName: string }; hideAccountRoles?: { accountName: string; roleName: string }[]; + menuPosition?: 'absolute' | 'fixed'; + identityProviderUrl?: string; + filterOutInternalRoles?: boolean; }; type SelectAccountIAMRoleWithAccountProps = SelectAccountIAMRoleProps & { @@ -169,6 +176,12 @@ const SelectAccountIAMRoleWithAccount = ( const [role, setRole] = useState(null); const assumedRole = useAssumedRole(); + const getIAMRoleMutation = useMutation({ + mutationFn: (roleName: string) => { + return IAMClient.getRole(roleName); + }, + }); + const accountName = account ? account.name : ''; const rolesQuery = getListRolesQuery(accountName, IAMClient); const queryClient = useQueryClient(); @@ -197,66 +210,132 @@ const SelectAccountIAMRoleWithAccount = ( }; const roleQueryData = useQuery(listRolesQuery); - const roles = filterRoles( + const allRolesExceptHiddenOnes = filterRoles( accountName, roleQueryData?.data?.Roles ?? [], hideAccountRoles, ); + const roles = props.filterOutInternalRoles + ? allRolesExceptHiddenOnes.filter((role) => { + return ( + SCALITY_INTERNAL_ROLES.includes(role.RoleName) || + !role.Arn.includes('role/scality-internal') + ); + }) + : allRolesExceptHiddenOnes; const isDefaultAccountSelected = account?.name === defaultValue?.accountName; const defaultRole = isDefaultAccountSelected ? defaultValue?.roleName : null; return ( - - + setAccount(selectedAccount); + setRole(null); + queryClient.invalidateQueries(rolesQuery.queryKey); + }} + menuPosition={props.menuPosition} + placeholder="Select Account" + > + {accounts.map((account) => ( + + {account.name} + + ))} + + } + /> - {roles.length > 0 ? ( - - ) : null} - + content={ + roles.length > 0 ? ( + + ) : ( + + ) + } + /> + + ); }; @@ -282,6 +361,9 @@ export const _SelectAccountIAMRole = (props: SelectAccountIAMRoleProps) => { defaultValue={defaultValue} hideAccountRoles={hideAccountRoles} onChange={onChange} + menuPosition={props.menuPosition} + filterOutInternalRoles={props.filterOutInternalRoles} + identityProviderUrl={props.identityProviderUrl} /> ); } else { diff --git a/src/react/utils/hooks.ts b/src/react/utils/hooks.ts index 175971c26..700fc4fd6 100644 --- a/src/react/utils/hooks.ts +++ b/src/react/utils/hooks.ts @@ -154,10 +154,12 @@ export const regexArn = export const STORAGE_MANAGER_ROLE = 'storage-manager-role'; export const STORAGE_ACCOUNT_OWNER_ROLE = 'storage-account-owner-role'; const DATA_CONSUMER_ROLE = 'data-consumer-role'; +const DATA_ACCESSOR_ROLE = 'data-accessor-role'; export const SCALITY_INTERNAL_ROLES = [ STORAGE_MANAGER_ROLE, STORAGE_ACCOUNT_OWNER_ROLE, DATA_CONSUMER_ROLE, + DATA_ACCESSOR_ROLE, ]; const reduxBasedEventDispatcher = () => {