8000 add description to groups by edewit · Pull Request #39174 · keycloak/keycloak · GitHub
[go: up one dir, main page]
More Web Proxy on the site http://driver.im/
Skip to content

add description to groups #39174

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 8 commits into from
May 14, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ public class GroupRepresentation {
// to identify a group and operate on it in a basic way
protected String id;
protected String name;
protected String description;
protected String path;
protected String parentId;
protected Long subGroupCount;
Expand Down Expand Up @@ -62,6 +63,14 @@ public void setName(String name) {
this.name = name;
}

public String getDescription() {
return description;
}

public void setDescription(String description) {
this.description = description;
}

public String getPath() {
return path;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -526,7 +526,6 @@ showRemaining=Show ${remaining}
searchProfile=Search profile
eventTypes.UPDATE_EMAIL_ERROR.name=Update email error
removeConfirm_other=Are you sure you want to remove these groups?
renameGroup=Rename group
configure=Configure
searchScopeHelp=For one level, the search applies only for users in the DNs specified by User DNs. For subtree, the search applies to the whole subtree. See LDAP documentation for more details.
jumpToSection=Jump to section
Expand Down Expand Up @@ -2101,7 +2100,7 @@ tableView=Table view
addClientProfile=Add client profile
maxFailureWaitSeconds=Max wait
userEventsRegistered=User events registered
renameAGroup=Rename group
editGroup=Edit group
eventConfigError=Could not save event configuration\: {{error}}
confirmAccessTokenTitle=Regenerate registration access token?
target=Target
Expand Down
2 changes: 1 addition & 1 deletion js/apps/admin-ui/src/groups/GroupTable.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -159,7 +159,7 @@ export const GroupTable = ({ refresh: viewRefresh }: GroupTableProps) => {
? []
: [
{
title: t("rename"),
title: t("edit"),
onRowClick: async (group) => {
setRename(group);
return false;
Expand Down
16 changes: 10 additions & 6 deletions js/apps/admin-ui/src/groups/GroupsModal.tsx
6D47
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,10 @@ export const GroupsModal = ({
useState<GroupRepresentation | null>(null);

const form = useForm({
defaultValues: { name: "" },
defaultValues: {
name: rename?.name || "",
description: rename?.description || "",
},
});
const { handleSubmit, formState } = form;

Expand Down Expand Up @@ -235,13 +238,13 @@ export const GroupsModal = ({
} else if (rename) {
await adminClient.groups.update(
{ id },
{ ...rename, name: group.name },
{ ...rename, name: group.name, description: group.description },
);
} else {
await adminClient.groups.updateChildGroup({ id }, group);
}

refresh(rename ? { ...rename, name: group.name } : undefined);
refresh(rename ? { ...rename, ...group } : undefined);
handleModalToggle();
addAlert(
t(
Expand All @@ -263,12 +266,12 @@ export const GroupsModal = ({
variant={ModalVariant.small}
title={
rename
? t("renameAGroup")
? t("editGroup")
: duplicateId
? t("duplicateAGroup")
: t("createAGroup")
}
isOpen={true}
isOpen
>
actions={[
<FormSubmitButton
Expand All @@ -279,7 +282,7 @@ export const GroupsModal = ({
allowInvalid
allowNonDirty
>
{t(rename ? "rename" : duplicateId ? "duplicate" : "create")}
{t(rename ? "edit" : duplicateId ? "duplicate" : "create")}
</FormSubmitButton>,
<Button
id="modal-cancel"
Expand Down Expand Up @@ -308,6 +311,7 @@ export const GroupsModal = ({
rules={{ required: t("required") }}
autoFocus
/>
<TextControl name="description" label={t("description")} />
</Form>
</FormProvider>
</Modal>
Expand Down
5 changes: 4 additions & 1 deletion js/apps/admin-ui/src/groups/GroupsSection.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -169,7 +169,7 @@ export default function GroupsSection() {
key="renameGroup"
=> setRename(currentGroup())}
>
{t("renameGroup")}
{t("edit")}
</DropdownItem>,
<DropdownItem
data-testid="deleteGroup"
Expand All @@ -182,6 +182,9 @@ export default function GroupsSection() {
: undefined
}
/>
<PageSection className="pf-v5-u-pt-0">
{currentGroup()?.description}
</PageSection>
{subGroups.length > 0 && (
<Tabs
inset={{
Expand Down
2 changes: 1 addition & 1 deletion js/apps/admin-ui/src/groups/components/GroupTree.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,7 @@ const GroupTreeContextMenu = ({
>
<DropdownList>
<DropdownItem key="rename" >
{t("rename")}
{t("edit")}
</DropdownItem>
<DropdownItem key="move" >
{t("moveTo")}
Expand Down
25 changes: 15 additions & 10 deletions js/apps/admin-ui/test/groups/list.spec.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { test } from "@playwright/test";
import { expect, test } from "@playwright/test";
import { v4 as uuid } from "uuid";
import adminClient from "../utils/AdminClient";
import { login } from "../utils/login";
Expand All @@ -14,10 +14,11 @@ import {
assertRowExists,
clickRowKebabItem,
clickSelectRow,
clickTableRowItem,
clickTableToolbarItem,
searchItem,
} from "../utils/table";
import { createGroup, renameGroup, searchGroup } from "./list";
import { createGroup, editGroup, searchGroup } from "./list";
import { goToGroupDetails } from "./util";

test.describe("Group test", () => {
Expand Down Expand Up @@ -48,32 +49,35 @@ test.describe("Group test", () => {
});

test("Create group test", async ({ page }) => {
await createGroup(page, groupName, true);
await createGroup(page, groupName, "", true);
await assertNotificationMessage(page, "Group created");
await searchGroup(page, groupName);
await assertRowExists(page, groupName, true);

// create group from search bar
const secondGroupName = `group-second-${uuid()}`;
await createGroup(page, secondGroupName, false);
await createGroup(page, secondGroupName, "some sort of description", false);
await assertNotificationMessage(page, "Group created");
await clickTableRowItem(page, secondGroupName);
await expect(page.getByText("some sort of description")).toBeVisible();
await page.goBack();

await searchGroup(page, secondGroupName);
await assertRowExists(page, secondGroupName, true);
await adminClient.deleteGroups();
});

test("Fail to create group with empty name", async ({ page }) => {
await createGroup(page, " ", true);
await createGroup(page, " ", "", true);
await assertNotificationMessage(
page,
"Could not create group Group name is missing",
);
});

test("Fail to create group with duplicated name", async ({ page }) => {
await createGroup(page, groupName, true);
await createGroup(page, groupName, false);
await createGroup(page, groupName, "", true);
await createGroup(page, groupName, "", false);
await assertNotificationMessage(
page,
`Could not create group Top level group named '${groupName}' already exists.`,
Expand Down Expand Up @@ -130,10 +134,11 @@ test.describe("Search group under current group", () => {
await assertRowExists(page, predefinedGroups[2], false);
});

test("Rename group", async ({ page }) => {
test("Edit group", async ({ page }) => {
const newGroupName = "new_group_name";
await clickRowKebabItem(page, predefinedGroups[3], "Rename");
await renameGroup(page, newGroupName);
const description = "new description";
await clickRowKebabItem(page, predefinedGroups[3], "Edit");
await editGroup(page, newGroupName, description);
await assertNotificationMessage(page, "Group updated");
await assertRowExists(page, newGroupName);
await assertRowExists(page, predefinedGroups[3], false);
Expand Down
5 changes: 4 additions & 1 deletion js/apps/admin-ui/test/groups/list.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { Page } from "@playwright/test";
export async function createGroup(
page: Page,
name: string,
description: string,
fromEmptyState = false,
) {
if (fromEmptyState) {
Expand All @@ -11,6 +12,7 @@ export async function createGroup(
await page.getByTestId("openCreateGroupModal").click();
}
await page.getByTestId("name").fill(name);
await page.getByTestId("description").fill(description);
await page.getByTestId("createGroup").click();
}

Expand All @@ -22,7 +24,8 @@ export async function searchGroup(page: Page, name: string) {
.click();
}

export async function renameGroup(page: Page, name: string) {
export async function editGroup(page: Page, name: string, description: string) {
await page.getByTestId("name").fill(name);
await page.getByTestId("description").fill(description);
await page.getByTestId("renameGroup").click();
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
export default interface GroupRepresentation {
id?: string;
name?: string;
description?: string;
path?: string;
subGroupCount?: number;
subGroups?: GroupRepresentation[];
Expand Down
2 changes: 1 addition & 1 deletion js/libs/keycloak-admin-client/test/groups.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ describe("Groups", () => {
const groupId = currentGroup.id;
await kcAdminClient.groups.update(
{ id: groupId! },
{ name: "another-group-name" },
{ name: "another-group-name", description: "another-group-description" },
);

const group = await kcAdminClient.groups.findOne({
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,18 @@ public void setName(String name) {

}

@Override
public String getDescription() {
if (isUpdated()) return updated.getDescription();
return cached.getDescription();
}

@Override
public void setDescription(String description) {
getDelegateForUpdate();
updated.setDescription(description);
}

@Override
public void setSingleAttribute(String name, String value) {
getDelegateForUpdate();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ public class CachedGroup extends AbstractRevisioned implements InRealm {

private final String realm;
private final String name;
private final String description;
private final String parentId;
private final LazyLoader<GroupModel, MultivaluedHashMap<String, String>> attributes;
private final LazyLoader<GroupModel, Set<String>> roleMappings;
Expand All @@ -49,6 +50,7 @@ public CachedGroup(Long revision, RealmModel realm, GroupModel group) {
super(revision, group.getId());
this.realm = realm.getId();
this.name = group.getName();
this.description = group.getDescription();
this.parentId = group.getParentId();
this.attributes = new DefaultLazyLoader<>(source -> new MultivaluedHashMap<>(source.getAttributes()), MultivaluedHashMap::new);
this.roleMappings = new DefaultLazyLoader<>(source -> source.getRoleMappingsStream().map(RoleModel::getId).collect(Collectors.toSet()), Collections::emptySet);
Expand Down Expand Up @@ -76,6 +78,10 @@ public String getName() {
return name;
}

public String getDescription() {
return description;
}

public String getParentId() {
return parentId;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,17 @@ public void setName(String name) {
fireGroupUpdatedEvent();
}

@Override
public String getDescription() {
return group.getDescription();
}

@Override
public void setDescription(String description) {
group.setDescription(description);
fireGroupUpdatedEvent();
}

@Override
public GroupModel getParent() {
String parentId = this.getParentId();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,10 @@ public class GroupEntity {
@Column(name = "NAME")
protected String name;

@Nationalized
@Column(name = "DESCRIPTION")
protected String description;

@Column(name = "PARENT_GROUP")
private String parentId;

Expand Down Expand Up @@ -92,6 +96,14 @@ public void setName(String name) {
this.name = name;
}

public String getDescription() {
return description;
}

public void setDescription(String description) {
this.description = description;
}

public String getRealm() {
return realm;
}
Expand Down
26 changes: 26 additions & 0 deletions model/jpa/src/main/resources/META-INF/jpa-changelog-26.3.0.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!--
~ * Copyright 2024 Red Hat, Inc. and/or its affiliates
~ * and other contributors as indicated by the @author tags.
~ *
~ * Licensed under the Apache License, Version 2.0 (the "License");
~ * you may not use this file except in compliance with the License.
~ * You may obtain a copy of the License at
~ *
~ * http://www.apache.org/licenses/LICENSE-2.0
~ *
~ * Unless required by applicable law or agreed to in writing, software
~ * distributed under the License is distributed on an "AS IS" BASIS,
~ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
~ * See the License for the specific language governing permissions and
~ * limitations under the License.
-->
<databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-3.1.xsd">

<changeSet author="keycloak" id="26.3.0-groups-description">
<addColumn tableName="KEYCLOAK_GROUP">
<column name="DESCRIPTION" type="NVARCHAR(255)" />
</addColumn>
</changeSet>

</databaseChangeLog>
Original file line number Diff line number Diff line change
Expand Up @@ -86,5 +86,6 @@
<include file="META-INF/jpa-changelog-26.0.0.xml"/>
<include file="META-INF/jpa-changelog-26.1.0.xml"/>
<include file="META-INF/jpa-changelog-26.2.0.xml"/>
<include file="META-INF/jpa-changelog-26.3.0.xml"/>

</databaseChangeLog>
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,7 @@ public static GroupRepresentation toRepresentation(GroupModel group, boolean ful
GroupRepresentation rep = new GroupRepresentation();
rep.setId(group.getId());
rep.setName(group.getName());
rep.setDescription(group.getDescription());
rep.setPath(buildGroupPath(group));
rep.setParentId(group.getParentId());
if (!full) return rep;
Expand Down
Loading
Loading
0