import React from 'react'; import {Flex} from '@gravity-ui/uikit'; import {LoaderWrapper} from '../../../components/LoaderWrapper/LoaderWrapper'; import {SubjectWithAvatar} from '../../../components/SubjectWithAvatar/SubjectWithAvatar'; import {useNonDefaultAclInheritanceRevocationAvailable} from '../../../store/reducers/capabilities/hooks'; import {useClusterWithProxy} from '../../../store/reducers/cluster/cluster'; import { schemaAclApi, selectAvailablePermissions, selectSubjectExplicitAllowAces, selectSubjectInheritedRights, } from '../../../store/reducers/schemaAcl/schemaAcl'; import {prepareAccessRightsUpdateRequest} from '../../../store/reducers/schemaAcl/utils'; import createToast from '../../../utils/createToast'; import {useAclSyntax, useTypedSelector} from '../../../utils/hooks'; import {prepareErrorMessage} from '../../../utils/prepareErrorMessage'; import {useCurrentSchema} from '../TenantContext'; import {useTenantQueryParams} from '../useTenantQueryParams'; import {Footer} from './components/Footer'; import {Rights} from './components/Rights'; import {RightsSectionSelector} from './components/RightsSectionSelector'; import {SubjectInput} from './components/SubjectInput'; import i18n from './i18n'; import type {RightsView} from './shared'; import {block} from './shared'; import {useRights} from './utils'; import './GrantAccess.scss'; interface GrantAccessProps { handleCloseDrawer: () => void; } export function GrantAccess({handleCloseDrawer}: GrantAccessProps) { const {aclSubject} = useTenantQueryParams(); const [newSubjects, setNewSubjects] = React.useState([]); const [rightView, setRightsView] = React.useState('Groups'); const {path, database, databaseFullPath} = useCurrentSchema(); const useMetaProxy = useClusterWithProxy(); const supportsNonDefaultInheritanceRevocation = useNonDefaultAclInheritanceRevocationAvailable(); const dialect = useAclSyntax(); const {currentRightsMap, setExplicitRightsChanges, rightsToGrant, rightsToRevoke, hasChanges} = useRights({aclSubject: aclSubject ?? undefined, path, database, databaseFullPath}); const subjectExplicitAces = useTypedSelector((state) => selectSubjectExplicitAllowAces( state, aclSubject ?? undefined, path, database, databaseFullPath, dialect, useMetaProxy, ), ); const {isFetching: aclIsFetching} = schemaAclApi.useGetSchemaAclQuery( { path, database, databaseFullPath, dialect, useMetaProxy, }, {skip: !aclSubject}, ); const {isFetching: availableRightsAreFetching} = schemaAclApi.useGetAvailablePermissionsQuery({ database, databaseFullPath, dialect, useMetaProxy, }); const [updateRights, updateRightsResponse] = schemaAclApi.useUpdateAccessMutation(); const [updateRightsError, setUpdateRightsError] = React.useState(''); const inheritedRightsSet = useTypedSelector((state) => selectSubjectInheritedRights( state, aclSubject ?? undefined, path, database, databaseFullPath, dialect, useMetaProxy, ), ); const handleDiscardRightsChanges = React.useCallback(() => { setExplicitRightsChanges(new Map()); }, [setExplicitRightsChanges]); const handleSaveRightsChanges = React.useCallback(() => { const subjects = aclSubject ? [aclSubject] : newSubjects; if (!subjects.length) { return; } const newRights = prepareAccessRightsUpdateRequest({ subjects, rightsToGrant, rightsToRevoke, subjectExplicitAces, supportsNonDefaultInheritanceRevocation, }); updateRights({ path, database, databaseFullPath, dialect, rights: newRights, }) .unwrap() .then(() => { handleCloseDrawer(); createToast({ name: 'updateAcl', content: i18n('label_rights-updated'), autoHiding: 1000, isClosable: false, }); }) .catch((e) => { setUpdateRightsError(prepareErrorMessage(e)); }); }, [ updateRights, path, database, dialect, rightsToGrant, aclSubject, rightsToRevoke, subjectExplicitAces, supportsNonDefaultInheritanceRevocation, newSubjects, handleCloseDrawer, databaseFullPath, ]); const availablePermissions = useTypedSelector((state) => selectAvailablePermissions(state, database, databaseFullPath, dialect, useMetaProxy), ); const handleChangeRightGetter = React.useCallback( (right: string) => { return (value: boolean) => { setUpdateRightsError(''); setExplicitRightsChanges((prev) => new Map(prev).set(right, value)); }; }, [setExplicitRightsChanges], ); const rightsLoading = aclIsFetching || availableRightsAreFetching; const renderSubject = () => { if (aclSubject) { return ; } return ; }; const subjectSelected = Boolean(aclSubject || newSubjects.length > 0); return ( {renderSubject()} {/* wrapper to prevent radio button stretch */} {subjectSelected && ( )} {subjectSelected && ( )} {subjectSelected && (