Skip to content

Commit

Permalink
chore(Groups): now we can rename group via UI [#634]
Browse files Browse the repository at this point in the history
  • Loading branch information
vrozaev committed Nov 20, 2024
1 parent d99d049 commit a782aab
Show file tree
Hide file tree
Showing 6 changed files with 156 additions and 71 deletions.
14 changes: 13 additions & 1 deletion packages/ui/src/shared/yt-types.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -236,6 +236,16 @@ export interface RemoveMaintenanceParams extends AddMaintenanceParams {
mine: boolean;
}

export interface AddMembersParams {
group: string;
member: string;
}

export interface RemoveMembersParams {
group: string;
member: string;
}

export type BatchSubRequest =
| SubRequest<'transfer_pool_resources', TransferPoolQuotaParams>
| SubRequest<'mount_table' | 'unmount_table' | 'freeze_table' | 'unfreeze_table', PathParams>
Expand All @@ -251,7 +261,9 @@ export type BatchSubRequest =
| SubRequest<'get_query', GetQueryParams>
| SubRequest<'get_query_result', GetQueryResultParams>
| SubRequest<'add_maintenance', AddMaintenanceParams>
| SubRequest<'remove_maintenance', RemoveMaintenanceParams>;
| SubRequest<'remove_maintenance', RemoveMaintenanceParams>
| SubRequest<'add_member', AddMembersParams>
| SubRequest<'remove_member', RemoveMembersParams>;

export type OutputFormat =
| {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ export const DeleteGroupModal: React.FC = () => {
const dispatch = useDispatch();
const [error, setError] = React.useState<YTError | undefined>(undefined);
const groupNameToDelete = useSelector(
(state: RootState) => state.groups.deleteGroup.groupNameToDelete
(state: RootState) => state.groups.deleteGroup.groupNameToDelete,
);

const onClose = useCallback(() => {
Expand Down
8 changes: 2 additions & 6 deletions packages/ui/src/ui/pages/groups/GroupActions/GroupActions.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,7 @@ import ClickableAttributesButton from '../../../components/AttributesButton/Clic
import Icon from '../../../components/Icon/Icon';
import Button from '../../../components/Button/Button';

import {
openGroupEditorModal,
showGroupDeleteModal,
} from '../../../store/actions/groups';

import {openGroupEditorModal, showGroupDeleteModal} from '../../../store/actions/groups';

type GroupActionsProps = {
className?: string;
Expand Down Expand Up @@ -43,4 +39,4 @@ export function GroupActions({className, groupname, allowDelete}: GroupActionsPr
)}
</div>
);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import React from 'react';
import cn from 'bem-cn-lite';
import {ConnectedProps, connect} from 'react-redux';

import {closeGroupEditorModal, createGroup, fetchGroups, saveGroupData} from '../../../store/actions/groups';
import {closeGroupEditorModal, fetchGroups, saveGroupData} from '../../../store/actions/groups';
import {
getGroupEditorGroupIdm,
getGroupEditorGroupName,
Expand Down Expand Up @@ -52,8 +52,8 @@ type FormValues = {
};

class GroupEditorDialog extends React.Component<GroupsPageTableProps> {
onSubmit = (form: FormApi<FormValues, Partial<FormValues>>) => {
const {groupName, saveGroupData, fetchGroups} = this.props;
onSubmit = async (form: FormApi<FormValues, Partial<FormValues>>) => {
const {groupName: initialGroupName} = this.props;
const {values} = form.getState();
const {members, membersComment} = values.members;
const {added: membersToAdd, removed: membersToRemove} = extractChangedSubjects(members);
Expand All @@ -62,6 +62,8 @@ class GroupEditorDialog extends React.Component<GroupsPageTableProps> {
const {added: responsiblesToAdd, removed: responsiblesToRemove} =
extractChangedSubjects(responsibles);

const {groupName} = values.general;

let comment = '';
if (membersComment) {
comment += responsiblesComment ? '**COMMENT FOR MEMBERS**\n' : '';
Expand All @@ -72,23 +74,20 @@ class GroupEditorDialog extends React.Component<GroupsPageTableProps> {
comment += `${responsiblesComment}`;
}

if (this.isNewGroup()) {
return this.props
.createGroup({ groupname: values.general.groupName })
.then(() => fetchGroups())
.then(() => {});
}

return saveGroupData(
groupName,
membersToAdd,
membersToRemove,
responsiblesToAdd,
responsiblesToRemove,
comment,
).then(() => {
return fetchGroups();
}).then(() => {});
return this.props
.saveGroupData({
initialGroupName,
groupName,
membersToAdd,
membersToRemove,
responsiblesToAdd,
responsiblesToRemove,
comment,
})
.then(() => {
return this.props.fetchGroups();
})
.then(() => {});
};

render() {
Expand All @@ -106,6 +105,9 @@ class GroupEditorDialog extends React.Component<GroupsPageTableProps> {
onClose={closeGroupEditorModal}
onAdd={this.onSubmit}
initialValues={{
general: {
groupName,
},
details: {
idm: String(idm || '-'),
size: String(members.length),
Expand Down Expand Up @@ -223,7 +225,6 @@ const mapStateToProps = (state: RootState) => {
const mapDispatchToProps = {
closeGroupEditorModal,
saveGroupData,
createGroup,
fetchGroups,
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,7 @@ import {Tooltip} from '../../../components/Tooltip/Tooltip';

import LoadDataHandler from '../../../components/LoadDataHandler/LoadDataHandler';

import {
fetchGroups,
setGroupsPageSorting,
toggleGroupExpand,
} from '../../../store/actions/groups';
import {fetchGroups, setGroupsPageSorting, toggleGroupExpand} from '../../../store/actions/groups';
import {STICKY_TOOLBAR_BOTTOM} from '../../../components/WithStickyToolbar/WithStickyToolbar';
import GroupEditorDialog from '../../../pages/groups/GroupEditorDialog/GroupEditorDialog';
import {
Expand All @@ -34,8 +30,8 @@ import './GroupsPageTable.scss';
import {isIdmAclAvailable} from '../../../config';
import type {RootState} from '../../../store/reducers';
import type {OrderType} from '../../../utils/sort-helpers';
import { GroupActions } from '../GroupActions/GroupActions';
import { DeleteGroupModal } from '../DeleteGroupModal/DeleteUserModal';
import {GroupActions} from '../GroupActions/GroupActions';
import {DeleteGroupModal} from '../DeleteGroupModal/DeleteUserModal';

const block = cn('groups-page-table');

Expand Down
150 changes: 115 additions & 35 deletions packages/ui/src/ui/store/actions/groups.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,8 @@ import type {Group} from '../../store/reducers/groups/table';
import type {OrderType} from '../../utils/sort-helpers';
import type {RootState} from '../../store/reducers';
import type {Subject} from '../../utils/acl/acl-types';
import { deleteGroupModalSlice } from '../../store/reducers/groups/delete-group';
import {deleteGroupModalSlice} from '../../store/reducers/groups/delete-group';
import type {WithAttrs} from '../../utils/cypress-attributes';

// Table

Expand Down Expand Up @@ -127,7 +128,7 @@ export function closeGroupEditorModal() {
};
}

export function createGroup({groupname}: {groupname: string;}) {
export function createGroup({groupname}: {groupname: string}) {
return () => {
return ytApiV3.create({
type: 'group',
Expand All @@ -136,43 +137,77 @@ export function createGroup({groupname}: {groupname: string;}) {
};
}

export function deleteGroup({groupname}: {groupname: string;}) {
export function deleteGroup({groupname}: {groupname: string}) {
return () => {
return ytApiV3.remove({
path: '//sys/groups/' + groupname,
});
};
}

export function saveGroupData(
groupName: string,
usersToAdd: Subject[],
usersToRemove: Subject[],
responsiblesToAdd: Subject[],
responsiblesToRemove: Subject[],
comment: string,
) {
return (_dispatch: Dispatch, getState: () => RootState) => {
const state = getState();
const {members, responsible} = getGroupEditorSubjects(state);
const version = getGroupEditorIdmDataVersion(state);
const newMembers = calculateMembers(members, usersToAdd, usersToRemove);
const newResponsibles = calculateMembers(
responsible,
responsiblesToAdd,
responsiblesToRemove,
);

const cluster = getCluster(state);
return UIFactory.getAclApi().updateGroup({
cluster,
groupName,
version,
groupDiff: {
members: newMembers,
responsible: newResponsibles,
},
comment,
type SaveGroupDataPayload = {
initialGroupName: string;
groupName: string;
membersToAdd: Subject[];
membersToRemove: Subject[];
responsiblesToAdd: Subject[];
responsiblesToRemove: Subject[];
comment: string;
};

export function saveGroupData({
initialGroupName,
groupName,
membersToAdd,
membersToRemove,
responsiblesToAdd,
responsiblesToRemove,
comment,
}: SaveGroupDataPayload) {
return async (_dispatch: Dispatch, getState: () => RootState) => {
const isNewGroup = !initialGroupName;

if (isNewGroup) {
await createGroup({groupname: groupName});
}

const groupNameChanged = initialGroupName !== groupName;

if (!isNewGroup && groupNameChanged) {
await renameGroup({
oldGroupname: initialGroupName,
newGroupName: groupName,
});
}

if (UIFactory.getAclApi().isAllowed) {
const state = getState();
const {members, responsible} = getGroupEditorSubjects(state);
const version = getGroupEditorIdmDataVersion(state);
const newMembers = calculateMembers(members, membersToAdd, membersToRemove);
const newResponsibles = calculateMembers(
responsible,
responsiblesToAdd,
responsiblesToRemove,
);

const cluster = getCluster(state);
return UIFactory.getAclApi().updateGroup({
cluster,
groupName,
version,
groupDiff: {
members: newMembers,
responsible: newResponsibles,
},
comment,
});
}

return changeGroupMembers({
groupname: groupName,
usersToAdd: membersToAdd,
usersToRemove: membersToRemove,
});
};
}
Expand Down Expand Up @@ -215,12 +250,57 @@ function mapsByNameFromSubjects(subjects: Subject[]) {

export function showGroupDeleteModal(groupNameToDelete: string) {
return (dispatch: Dispatch) => {
dispatch(deleteGroupModalSlice.actions.setModalState({ groupNameToDelete}));
dispatch(deleteGroupModalSlice.actions.setModalState({groupNameToDelete}));
};
}

export function closeGroupDeleteModal() {
return (dispatch: Dispatch) => {
dispatch(deleteGroupModalSlice.actions.setModalState({ groupNameToDelete: '' }));
dispatch(deleteGroupModalSlice.actions.setModalState({groupNameToDelete: ''}));
};
}
}

type RenameGroupPayload = {
oldGroupname: string;
newGroupName: string;
};

function renameGroup({oldGroupname, newGroupName}: RenameGroupPayload) {
return ytApiV3.set({path: `//sys/groups/${oldGroupname}/@name`}, newGroupName);
}

type ChangeGroupMembersPayload = {
groupname: string;
usersToAdd: Subject[];
usersToRemove: Subject[];
};

function changeGroupMembers({groupname, usersToAdd, usersToRemove}: ChangeGroupMembersPayload) {
const requestsToAdd = usersToAdd.map((user) => {
return {
command: 'add_member' as const,
parameters: {
group: groupname,
// @ts-ignore
member: user.user || user.group,
},
};
});

const requestsToRemove = usersToRemove.map((user) => {
return {
command: 'remove_member' as const,
parameters: {
group: groupname,
// @ts-ignore
member: user.user || user.group,
},
};
});

const requests = [...requestsToAdd, ...requestsToRemove];

return ytApiV3.executeBatch<WithAttrs<{compression_codec?: string; erasure_codec?: string}>>({
requests,
});
}

0 comments on commit a782aab

Please sign in to comment.