Duplicating groups (#32454)
* Duplicating groups - wip Signed-off-by: Agnieszka Gancarczyk <agagancarczyk@gmail.com> * Duplicating groups - wip Signed-off-by: Agnieszka Gancarczyk <agagancarczyk@gmail.com> * Duplicating groups - wip Signed-off-by: Agnieszka Gancarczyk <agagancarczyk@gmail.com> * Duplicating groups - wip Signed-off-by: Agnieszka Gancarczyk <agagancarczyk@gmail.com> * Duplicating groups - wip Signed-off-by: Agnieszka Gancarczyk <agagancarczyk@gmail.com> * Duplicating groups - wip Signed-off-by: Agnieszka Gancarczyk <agagancarczyk@gmail.com> * Duplicating groups - wip Signed-off-by: Agnieszka Gancarczyk <agagancarczyk@gmail.com> * Duplicating groups - enhancement Signed-off-by: Agnieszka Gancarczyk <agagancarczyk@gmail.com> * Duplicating groups - enhancement Signed-off-by: Agnieszka Gancarczyk <agagancarczyk@gmail.com> * Enhancements Signed-off-by: Agnieszka Gancarczyk <agagancarczyk@gmail.com> * Enhancements Signed-off-by: Agnieszka Gancarczyk <agagancarczyk@gmail.com> * Enhancements Signed-off-by: Agnieszka Gancarczyk <agagancarczyk@gmail.com> * Enhancements Signed-off-by: Agnieszka Gancarczyk <agagancarczyk@gmail.com> * improvements Signed-off-by: Agnieszka Gancarczyk <agagancarczyk@gmail.com> * improvements Signed-off-by: Agnieszka Gancarczyk <agagancarczyk@gmail.com> * improvements Signed-off-by: Agnieszka Gancarczyk <agagancarczyk@gmail.com> --------- Signed-off-by: Agnieszka Gancarczyk <agagancarczyk@gmail.com>
This commit is contained in:
parent
022ab4d263
commit
805a92adbf
8 changed files with 292 additions and 22 deletions
|
@ -119,6 +119,12 @@ describe("Group test", () => {
|
||||||
.assertNoSearchResultsMessageExist(true);
|
.assertNoSearchResultsMessageExist(true);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("Duplicate group", () => {
|
||||||
|
groupPage
|
||||||
|
.duplicateGroupItem(groupNames[0], true)
|
||||||
|
.assertNotificationGroupDuplicated();
|
||||||
|
});
|
||||||
|
|
||||||
it("Delete group from item bar", () => {
|
it("Delete group from item bar", () => {
|
||||||
groupPage
|
groupPage
|
||||||
.searchGroup(groupNames[0], true)
|
.searchGroup(groupNames[0], true)
|
||||||
|
|
|
@ -198,6 +198,14 @@ export default class ListingPage extends CommonElements {
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
clickMenuDuplicate() {
|
||||||
|
cy.get(this.#menuContent)
|
||||||
|
.find(this.#menuItemText)
|
||||||
|
.contains("Duplicate")
|
||||||
|
.click({ force: true });
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
clickItemCheckbox(itemName: string) {
|
clickItemCheckbox(itemName: string) {
|
||||||
cy.get(this.#itemsRows)
|
cy.get(this.#itemsRows)
|
||||||
.contains(itemName)
|
.contains(itemName)
|
||||||
|
@ -261,6 +269,13 @@ export default class ListingPage extends CommonElements {
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
duplicateItem(itemName: string) {
|
||||||
|
this.clickRowDetails(itemName);
|
||||||
|
this.clickMenuDuplicate();
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
removeItem(itemName: string) {
|
removeItem(itemName: string) {
|
||||||
this.clickRowDetails(itemName);
|
this.clickRowDetails(itemName);
|
||||||
this.clickDetailMenu("Unassign");
|
this.clickDetailMenu("Unassign");
|
||||||
|
|
|
@ -5,6 +5,7 @@ export default class GroupModal extends ModalUtils {
|
||||||
#groupNameInput = "name";
|
#groupNameInput = "name";
|
||||||
#createGroupBnt = "createGroup";
|
#createGroupBnt = "createGroup";
|
||||||
#renameButton = "renameGroup";
|
#renameButton = "renameGroup";
|
||||||
|
#duplicateGroup = "duplicateGroup";
|
||||||
|
|
||||||
public setGroupNameInput(name: string) {
|
public setGroupNameInput(name: string) {
|
||||||
cy.findByTestId(this.#groupNameInput).clear().type(name);
|
cy.findByTestId(this.#groupNameInput).clear().type(name);
|
||||||
|
@ -21,6 +22,11 @@ export default class GroupModal extends ModalUtils {
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public duplicate() {
|
||||||
|
cy.findByTestId(this.#duplicateGroup).click();
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
public assertCreateGroupModalVisible(isVisible: boolean) {
|
public assertCreateGroupModalVisible(isVisible: boolean) {
|
||||||
super
|
super
|
||||||
.assertModalVisible(isVisible)
|
.assertModalVisible(isVisible)
|
||||||
|
|
|
@ -113,6 +113,14 @@ export default class GroupPage extends PageObject {
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
duplicateGroupItem(groupName: string, confirmModal = true) {
|
||||||
|
listingPage.duplicateItem(groupName);
|
||||||
|
if (confirmModal) {
|
||||||
|
groupModal.confirmDuplicateModal();
|
||||||
|
}
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
moveGroupItemAction(groupName: string, destinationGroupName: string[]) {
|
moveGroupItemAction(groupName: string, destinationGroupName: string[]) {
|
||||||
listingPage.clickRowDetails(groupName);
|
listingPage.clickRowDetails(groupName);
|
||||||
listingPage.clickDetailMenu("Move to");
|
listingPage.clickDetailMenu("Move to");
|
||||||
|
@ -202,6 +210,11 @@ export default class GroupPage extends PageObject {
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
assertNotificationGroupDuplicated() {
|
||||||
|
masthead.checkNotificationMessage("Group duplicated");
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
goToGroupActions(groupName: string) {
|
goToGroupActions(groupName: string) {
|
||||||
listingPage.clickRowDetails(groupName);
|
listingPage.clickRowDetails(groupName);
|
||||||
|
|
||||||
|
|
|
@ -13,6 +13,7 @@ export default class ModalUtils extends PageObject {
|
||||||
#addModalDropdownItem = ".pf-v5-c-modal-box__footer .pf-v5-c-menu__content";
|
#addModalDropdownItem = ".pf-v5-c-modal-box__footer .pf-v5-c-menu__content";
|
||||||
#addBtn = "add";
|
#addBtn = "add";
|
||||||
#tablePage = new TablePage(TablePage.tableSelector);
|
#tablePage = new TablePage(TablePage.tableSelector);
|
||||||
|
#confirmDuplicateModalBtn = "duplicateGroup";
|
||||||
|
|
||||||
table() {
|
table() {
|
||||||
return this.#tablePage;
|
return this.#tablePage;
|
||||||
|
@ -29,6 +30,12 @@ export default class ModalUtils extends PageObject {
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
confirmDuplicateModal() {
|
||||||
|
cy.findByTestId(this.#confirmDuplicateModalBtn).click({ force: true });
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
checkConfirmButtonText(text: string) {
|
checkConfirmButtonText(text: string) {
|
||||||
cy.findByTestId(this.#confirmModalBtn).contains(text);
|
cy.findByTestId(this.#confirmModalBtn).contains(text);
|
||||||
|
|
||||||
|
|
|
@ -3256,3 +3256,8 @@ eventTypes.REMOVE_CREDENTIAL.name=Remove credential
|
||||||
eventTypes.REMOVE_CREDENTIAL.description=Remove credential
|
eventTypes.REMOVE_CREDENTIAL.description=Remove credential
|
||||||
eventTypes.REMOVE_CREDENTIAL_ERROR.name=Remove credential error
|
eventTypes.REMOVE_CREDENTIAL_ERROR.name=Remove credential error
|
||||||
eventTypes.REMOVE_CREDENTIAL_ERROR.description=Remove credential error
|
eventTypes.REMOVE_CREDENTIAL_ERROR.description=Remove credential error
|
||||||
|
groupDuplicated=Group duplicated
|
||||||
|
duplicateAGroup=Duplicate group
|
||||||
|
duplicate=Duplicate
|
||||||
|
couldNotFetchClientRoleMappings=Could not fetch client role mappings\: {{error}}
|
||||||
|
duplicateGroupWarning=Duplication of groups with a large number of subgroups is not supported. Please ensure that the group you are duplicating does not have a large number of subgroups.
|
|
@ -25,25 +25,19 @@ type GroupTableProps = {
|
||||||
|
|
||||||
export const GroupTable = ({ refresh: viewRefresh }: GroupTableProps) => {
|
export const GroupTable = ({ refresh: viewRefresh }: GroupTableProps) => {
|
||||||
const { adminClient } = useAdminClient();
|
const { adminClient } = useAdminClient();
|
||||||
|
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
|
|
||||||
const [selectedRows, setSelectedRows] = useState<GroupRepresentation[]>([]);
|
const [selectedRows, setSelectedRows] = useState<GroupRepresentation[]>([]);
|
||||||
|
|
||||||
const [rename, setRename] = useState<GroupRepresentation>();
|
const [rename, setRename] = useState<GroupRepresentation>();
|
||||||
const [isCreateModalOpen, toggleCreateOpen] = useToggle();
|
const [isCreateModalOpen, toggleCreateOpen] = useToggle();
|
||||||
|
const [duplicateId, setDuplicateId] = useState<string>();
|
||||||
const [showDelete, toggleShowDelete] = useToggle();
|
const [showDelete, toggleShowDelete] = useToggle();
|
||||||
const [move, setMove] = useState<GroupRepresentation>();
|
const [move, setMove] = useState<GroupRepresentation>();
|
||||||
|
|
||||||
const { currentGroup } = useSubGroups();
|
const { currentGroup } = useSubGroups();
|
||||||
|
|
||||||
const [key, setKey] = useState(0);
|
const [key, setKey] = useState(0);
|
||||||
const refresh = () => setKey(key + 1);
|
const refresh = () => setKey(key + 1);
|
||||||
const [search, setSearch] = useState<string>();
|
const [search, setSearch] = useState<string>();
|
||||||
|
|
||||||
const location = useLocation();
|
const location = useLocation();
|
||||||
const id = getLastId(location.pathname);
|
const id = getLastId(location.pathname);
|
||||||
|
|
||||||
const { hasAccess } = useAccess();
|
const { hasAccess } = useAccess();
|
||||||
const isManager = hasAccess("manage-users") || currentGroup()?.access?.manage;
|
const isManager = hasAccess("manage-users") || currentGroup()?.access?.manage;
|
||||||
|
|
||||||
|
@ -103,6 +97,17 @@ export const GroupTable = ({ refresh: viewRefresh }: GroupTableProps) => {
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
{duplicateId && (
|
||||||
|
<GroupsModal
|
||||||
|
id={duplicateId}
|
||||||
|
duplicateId={duplicateId}
|
||||||
|
refresh={() => {
|
||||||
|
refresh();
|
||||||
|
viewRefresh();
|
||||||
|
}}
|
||||||
|
handleModalToggle={() => setDuplicateId(undefined)}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
{move && (
|
{move && (
|
||||||
<MoveDialog
|
<MoveDialog
|
||||||
source={move}
|
source={move}
|
||||||
|
@ -172,6 +177,17 @@ export const GroupTable = ({ refresh: viewRefresh }: GroupTableProps) => {
|
||||||
return false;
|
return false;
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
...(!id
|
||||||
|
? [
|
||||||
|
{
|
||||||
|
title: t("duplicate"),
|
||||||
|
onRowClick: async (group: GroupRepresentation) => {
|
||||||
|
setDuplicateId(group.id);
|
||||||
|
return false;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
]
|
||||||
|
: []),
|
||||||
{
|
{
|
||||||
isSeparator: true,
|
isSeparator: true,
|
||||||
},
|
},
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
import type GroupRepresentation from "@keycloak/keycloak-admin-client/lib/defs/groupRepresentation";
|
import type GroupRepresentation from "@keycloak/keycloak-admin-client/lib/defs/groupRepresentation";
|
||||||
import {
|
import {
|
||||||
|
Alert,
|
||||||
AlertVariant,
|
AlertVariant,
|
||||||
Button,
|
Button,
|
||||||
ButtonVariant,
|
ButtonVariant,
|
||||||
|
@ -9,38 +10,223 @@ import {
|
||||||
} from "@patternfly/react-core";
|
} from "@patternfly/react-core";
|
||||||
import { FormProvider, useForm } from "react-hook-form";
|
import { FormProvider, useForm } from "react-hook-form";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
import { FormSubmitButton, TextControl } from "@keycloak/keycloak-ui-shared";
|
import {
|
||||||
|
FormSubmitButton,
|
||||||
|
TextControl,
|
||||||
|
useFetch,
|
||||||
|
} from "@keycloak/keycloak-ui-shared";
|
||||||
import { useAdminClient } from "../admin-client";
|
import { useAdminClient } from "../admin-client";
|
||||||
import { useAlerts } from "@keycloak/keycloak-ui-shared";
|
import { useAlerts } from "@keycloak/keycloak-ui-shared";
|
||||||
|
import { useState } from "react";
|
||||||
|
|
||||||
type GroupsModalProps = {
|
type GroupsModalProps = {
|
||||||
id?: string;
|
id?: string;
|
||||||
rename?: GroupRepresentation;
|
rename?: GroupRepresentation;
|
||||||
|
duplicateId?: string;
|
||||||
handleModalToggle: () => void;
|
handleModalToggle: () => void;
|
||||||
refresh: (group?: GroupRepresentation) => void;
|
refresh: (group?: GroupRepresentation) => void;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
type RoleMappingPayload = {
|
||||||
|
id: string;
|
||||||
|
name?: string;
|
||||||
|
clientUniqueId?: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
type ClientRoleMapping = {
|
||||||
|
clientId: string;
|
||||||
|
roles: RoleMappingPayload[];
|
||||||
|
};
|
||||||
|
|
||||||
export const GroupsModal = ({
|
export const GroupsModal = ({
|
||||||
id,
|
id,
|
||||||
rename,
|
rename,
|
||||||
|
duplicateId,
|
||||||
handleModalToggle,
|
handleModalToggle,
|
||||||
refresh,
|
refresh,
|
||||||
}: GroupsModalProps) => {
|
}: GroupsModalProps) => {
|
||||||
const { adminClient } = useAdminClient();
|
const { adminClient } = useAdminClient();
|
||||||
|
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const { addAlert, addError } = useAlerts();
|
const { addAlert, addError } = useAlerts();
|
||||||
|
const [duplicateGroupDetails, setDuplicateGroupDetails] =
|
||||||
|
useState<GroupRepresentation | null>(null);
|
||||||
|
|
||||||
const form = useForm({
|
const form = useForm({
|
||||||
defaultValues: { name: rename?.name },
|
defaultValues: { name: "" },
|
||||||
});
|
});
|
||||||
const { handleSubmit, formState } = form;
|
const { handleSubmit, formState } = form;
|
||||||
|
|
||||||
|
useFetch(
|
||||||
|
async () => {
|
||||||
|
if (duplicateId) {
|
||||||
|
return adminClient.groups.findOne({ id: duplicateId });
|
||||||
|
}
|
||||||
|
},
|
||||||
|
(group) => {
|
||||||
|
if (group) {
|
||||||
|
setDuplicateGroupDetails(group);
|
||||||
|
form.reset({ name: t("copyOf", { name: group.name }) });
|
||||||
|
}
|
||||||
|
},
|
||||||
|
[duplicateId],
|
||||||
|
);
|
||||||
|
|
||||||
|
const fetchClientRoleMappings = async (groupId: string) => {
|
||||||
|
try {
|
||||||
|
const clientRoleMappings: ClientRoleMapping[] = [];
|
||||||
|
const clients = await adminClient.clients.find();
|
||||||
|
|
||||||
|
for (const client of clients) {
|
||||||
|
const roles = await adminClient.groups.listClientRoleMappings({
|
||||||
|
id: groupId,
|
||||||
|
clientUniqueId: client.id!,
|
||||||
|
});
|
||||||
|
|
||||||
|
const clientRoles = roles
|
||||||
|
.filter((role) => role.id && role.name)
|
||||||
|
.map((role) => ({
|
||||||
|
id: role.id!,
|
||||||
|
name: role.name!,
|
||||||
|
}));
|
||||||
|
|
||||||
|
if (clientRoles.length > 0) {
|
||||||
|
clientRoleMappings.push({ clientId: client.id!, roles: clientRoles });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return clientRoleMappings;
|
||||||
|
} catch (error) {
|
||||||
|
addError("couldNotFetchClientRoleMappings", error);
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const duplicateGroup = async (
|
||||||
|
sourceGroup: GroupRepresentation,
|
||||||
|
parentId?: string,
|
||||||
|
isSubGroup: boolean = false,
|
||||||
|
) => {
|
||||||
|
try {
|
||||||
|
const newGroup: GroupRepresentation = {
|
||||||
|
...sourceGroup,
|
||||||
|
name: isSubGroup
|
||||||
|
? sourceGroup.name
|
||||||
|
: t("copyOf", { name: sourceGroup.name }),
|
||||||
|
...(parentId ? {} : { attributes: duplicateGroupDetails?.attributes }),
|
||||||
|
};
|
||||||
|
|
||||||
|
delete newGroup.id;
|
||||||
|
|
||||||
|
const createdGroup = parentId
|
||||||
|
? await adminClient.groups.createChildGroup({ id: parentId }, newGroup)
|
||||||
|
: await adminClient.groups.create(newGroup);
|
||||||
|
|
||||||
|
const members = await adminClient.groups.listMembers({
|
||||||
|
id: sourceGroup.id!,
|
||||||
|
});
|
||||||
|
|
||||||
|
for (const member of members) {
|
||||||
|
await adminClient.users.addToGroup({
|
||||||
|
id: member.id!,
|
||||||
|
groupId: createdGroup.id,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const permissions = await adminClient.groups.listPermissions({
|
||||||
|
id: sourceGroup.id!,
|
||||||
|
});
|
||||||
|
|
||||||
|
if (permissions) {
|
||||||
|
await adminClient.groups.updatePermission(
|
||||||
|
{ id: createdGroup.id },
|
||||||
|
permissions,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const realmRoles = await adminClient.groups.listRealmRoleMappings({
|
||||||
|
id: sourceGroup.id!,
|
||||||
|
});
|
||||||
|
|
||||||
|
const realmRolesPayload: RoleMappingPayload[] = realmRoles.map(
|
||||||
|
(role) => ({ id: role.id!, name: role.name! }),
|
||||||
|
);
|
||||||
|
|
||||||
|
const clientRoleMappings = await fetchClientRoleMappings(sourceGroup.id!);
|
||||||
|
|
||||||
|
const clientRolesPayload: RoleMappingPayload[] =
|
||||||
|
clientRoleMappings?.flatMap((clientRoleMapping) =>
|
||||||
|
clientRoleMapping.roles.map((role) => ({
|
||||||
|
id: role.id!,
|
||||||
|
name: role.name!,
|
||||||
|
clientUniqueId: clientRoleMapping.clientId,
|
||||||
|
})),
|
||||||
|
);
|
||||||
|
|
||||||
|
const rolesToAssign: RoleMappingPayload[] = [
|
||||||
|
...realmRolesPayload,
|
||||||
|
...clientRolesPayload,
|
||||||
|
];
|
||||||
|
|
||||||
|
await assignRoles(rolesToAssign, createdGroup.id);
|
||||||
|
|
||||||
|
const subGroups = await adminClient.groups.listSubGroups({
|
||||||
|
parentId: sourceGroup.id!,
|
||||||
|
});
|
||||||
|
|
||||||
|
for (const childGroup of subGroups) {
|
||||||
|
const childAttributes = childGroup.attributes;
|
||||||
|
await duplicateGroup(
|
||||||
|
{ ...childGroup, attributes: childAttributes },
|
||||||
|
createdGroup.id,
|
||||||
|
true,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return createdGroup;
|
||||||
|
} catch (error) {
|
||||||
|
addError("couldNotDuplicateGroup", error);
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const assignRoles = async (roles: RoleMappingPayload[], groupId: string) => {
|
||||||
|
try {
|
||||||
|
const realmRoles = roles.filter(
|
||||||
|
(role) => !role.clientUniqueId && role.name,
|
||||||
|
);
|
||||||
|
const clientRoles = roles.filter(
|
||||||
|
(role) => role.clientUniqueId && role.name,
|
||||||
|
);
|
||||||
|
|
||||||
|
await adminClient.groups.addRealmRoleMappings({
|
||||||
|
id: groupId,
|
||||||
|
roles: realmRoles.map(({ id, name }) => ({ id, name: name! })),
|
||||||
|
});
|
||||||
|
|
||||||
|
await Promise.all(
|
||||||
|
clientRoles.map((clientRole) => {
|
||||||
|
if (clientRole.clientUniqueId && clientRole.name) {
|
||||||
|
return adminClient.groups.addClientRoleMappings({
|
||||||
|
id: groupId,
|
||||||
|
clientUniqueId: clientRole.clientUniqueId,
|
||||||
|
roles: [{ id: clientRole.id, name: clientRole.name }],
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return Promise.resolve();
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
} catch (error) {
|
||||||
|
addError("roleMappingUpdatedError", error);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
const submitForm = async (group: GroupRepresentation) => {
|
const submitForm = async (group: GroupRepresentation) => {
|
||||||
group.name = group.name?.trim();
|
group.name = group.name?.trim();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
if (!id) {
|
if (duplicateId && duplicateGroupDetails) {
|
||||||
|
await duplicateGroup(duplicateGroupDetails);
|
||||||
|
} else if (!id) {
|
||||||
await adminClient.groups.create(group);
|
await adminClient.groups.create(group);
|
||||||
} else if (rename) {
|
} else if (rename) {
|
||||||
await adminClient.groups.update(
|
await adminClient.groups.update(
|
||||||
|
@ -48,15 +234,19 @@ export const GroupsModal = ({
|
||||||
{ ...rename, name: group.name },
|
{ ...rename, name: group.name },
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
await (group.id
|
await adminClient.groups.updateChildGroup({ id }, group);
|
||||||
? adminClient.groups.updateChildGroup({ id }, group)
|
|
||||||
: adminClient.groups.createChildGroup({ id }, group));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
refresh(rename ? { ...rename, name: group.name } : undefined);
|
refresh(rename ? { ...rename, name: group.name } : undefined);
|
||||||
handleModalToggle();
|
handleModalToggle();
|
||||||
addAlert(
|
addAlert(
|
||||||
t(rename ? "groupUpdated" : "groupCreated"),
|
t(
|
||||||
|
rename
|
||||||
|
? "groupUpdated"
|
||||||
|
: duplicateId
|
||||||
|
? "groupDuplicated"
|
||||||
|
: "groupCreated",
|
||||||
|
),
|
||||||
AlertVariant.success,
|
AlertVariant.success,
|
||||||
);
|
);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
@ -67,28 +257,32 @@ export const GroupsModal = ({
|
||||||
return (
|
return (
|
||||||
<Modal
|
<Modal
|
||||||
variant={ModalVariant.small}
|
variant={ModalVariant.small}
|
||||||
title={t(rename ? "renameAGroup" : "createAGroup")}
|
title={
|
||||||
|
rename
|
||||||
|
? t("renameAGroup")
|
||||||
|
: duplicateId
|
||||||
|
? t("duplicateAGroup")
|
||||||
|
: t("createAGroup")
|
||||||
|
}
|
||||||
isOpen={true}
|
isOpen={true}
|
||||||
onClose={handleModalToggle}
|
onClose={handleModalToggle}
|
||||||
actions={[
|
actions={[
|
||||||
<FormSubmitButton
|
<FormSubmitButton
|
||||||
formState={formState}
|
formState={formState}
|
||||||
data-testid={`${rename ? "rename" : "create"}Group`}
|
data-testid={`${rename ? "rename" : duplicateId ? "duplicate" : "create"}Group`}
|
||||||
key="confirm"
|
key="confirm"
|
||||||
form="group-form"
|
form="group-form"
|
||||||
allowInvalid
|
allowInvalid
|
||||||
allowNonDirty
|
allowNonDirty
|
||||||
>
|
>
|
||||||
{t(rename ? "rename" : "create")}
|
{t(rename ? "rename" : duplicateId ? "duplicate" : "create")}
|
||||||
</FormSubmitButton>,
|
</FormSubmitButton>,
|
||||||
<Button
|
<Button
|
||||||
id="modal-cancel"
|
id="modal-cancel"
|
||||||
data-testid="cancel"
|
data-testid="cancel"
|
||||||
key="cancel"
|
key="cancel"
|
||||||
variant={ButtonVariant.link}
|
variant={ButtonVariant.link}
|
||||||
onClick={() => {
|
onClick={handleModalToggle}
|
||||||
handleModalToggle();
|
|
||||||
}}
|
|
||||||
>
|
>
|
||||||
{t("cancel")}
|
{t("cancel")}
|
||||||
</Button>,
|
</Button>,
|
||||||
|
@ -96,6 +290,14 @@ export const GroupsModal = ({
|
||||||
>
|
>
|
||||||
<FormProvider {...form}>
|
<FormProvider {...form}>
|
||||||
<Form id="group-form" isHorizontal onSubmit={handleSubmit(submitForm)}>
|
<Form id="group-form" isHorizontal onSubmit={handleSubmit(submitForm)}>
|
||||||
|
{duplicateId && (
|
||||||
|
<Alert
|
||||||
|
variant="warning"
|
||||||
|
component="h2"
|
||||||
|
isInline
|
||||||
|
title={t("duplicateGroupWarning")}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
<TextControl
|
<TextControl
|
||||||
name="name"
|
name="name"
|
||||||
label={t("name")}
|
label={t("name")}
|
||||||
|
|
Loading…
Reference in a new issue