fixing issue (#709)
* fixing issue fixing: #680 * added kebab on row * added more clear group seperation
This commit is contained in:
parent
c3809a32e6
commit
a964abed8d
4 changed files with 97 additions and 5 deletions
48
src/components/group/GroupPath.tsx
Normal file
48
src/components/group/GroupPath.tsx
Normal file
|
@ -0,0 +1,48 @@
|
|||
import React from "react";
|
||||
import { Tooltip } from "@patternfly/react-core";
|
||||
import type { TableTextProps } from "@patternfly/react-table";
|
||||
|
||||
import type GroupRepresentation from "keycloak-admin/lib/defs/groupRepresentation";
|
||||
|
||||
type GroupPathProps = TableTextProps & {
|
||||
group: GroupRepresentation;
|
||||
};
|
||||
|
||||
const MAX_LENGTH = 20;
|
||||
const PART = 10;
|
||||
|
||||
const truncatePath = (path?: string) => {
|
||||
if (path && path.length >= MAX_LENGTH) {
|
||||
return (
|
||||
path.substr(0, PART) +
|
||||
"..." +
|
||||
path.substr(path.length - PART, path.length)
|
||||
);
|
||||
}
|
||||
return path;
|
||||
};
|
||||
|
||||
export const GroupPath = ({
|
||||
group: { path },
|
||||
onMouseEnter: onMouseEnterProp = () => {},
|
||||
...props
|
||||
}: GroupPathProps) => {
|
||||
const [tooltip, setTooltip] = React.useState("");
|
||||
const onMouseEnter = (event: any) => {
|
||||
setTooltip(path!);
|
||||
onMouseEnterProp(event);
|
||||
};
|
||||
const text = (
|
||||
<span onMouseEnter={onMouseEnter} {...props}>
|
||||
{truncatePath(path)}
|
||||
</span>
|
||||
);
|
||||
|
||||
return tooltip !== "" ? (
|
||||
<Tooltip content={tooltip} isVisible>
|
||||
{text}
|
||||
</Tooltip>
|
||||
) : (
|
||||
text
|
||||
);
|
||||
};
|
|
@ -1,5 +1,5 @@
|
|||
import React, { useState } from "react";
|
||||
import { useLocation } from "react-router-dom";
|
||||
import { Link, useLocation } from "react-router-dom";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import _ from "lodash";
|
||||
import {
|
||||
|
@ -16,6 +16,7 @@ import type GroupRepresentation from "keycloak-admin/lib/defs/groupRepresentatio
|
|||
import type UserRepresentation from "keycloak-admin/lib/defs/userRepresentation";
|
||||
import { KeycloakDataTable } from "../components/table-toolbar/KeycloakDataTable";
|
||||
import { useAdminClient } from "../context/auth/AdminClient";
|
||||
import { useRealm } from "../context/realm-context/RealmContext";
|
||||
import { useAlerts } from "../components/alert/Alerts";
|
||||
import { emptyFormatter } from "../util";
|
||||
|
||||
|
@ -23,6 +24,7 @@ import { getLastId } from "./groupIdUtils";
|
|||
import { useSubGroups } from "./SubGroupsContext";
|
||||
import { MemberModal } from "./MembersModal";
|
||||
import { ListEmptyState } from "../components/list-empty-state/ListEmptyState";
|
||||
import { GroupPath } from "../components/group/GroupPath";
|
||||
|
||||
type MembersOf = UserRepresentation & {
|
||||
membership: GroupRepresentation[];
|
||||
|
@ -31,6 +33,7 @@ type MembersOf = UserRepresentation & {
|
|||
export const Members = () => {
|
||||
const { t } = useTranslation("groups");
|
||||
const adminClient = useAdminClient();
|
||||
const { realm } = useRealm();
|
||||
const { addAlert } = useAlerts();
|
||||
const location = useLocation();
|
||||
const id = getLastId(location.pathname);
|
||||
|
@ -84,13 +87,23 @@ export const Members = () => {
|
|||
const MemberOfRenderer = (member: MembersOf) => {
|
||||
return (
|
||||
<>
|
||||
{member.membership.map((group) => (
|
||||
<>{group.path} </>
|
||||
{member.membership.map((group, index) => (
|
||||
<>
|
||||
<GroupPath key={group.id} group={group} />
|
||||
{member.membership[index + 1] ? ", " : ""}
|
||||
</>
|
||||
))}
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
const UserDetailLink = (user: MembersOf) => (
|
||||
<>
|
||||
<Link key={user.id} to={`/${realm}/users/${user.id}/settings`}>
|
||||
{user.username}
|
||||
</Link>
|
||||
</>
|
||||
);
|
||||
return (
|
||||
<>
|
||||
{addMembers && (
|
||||
|
@ -132,7 +145,10 @@ export const Members = () => {
|
|||
<ToolbarItem>
|
||||
<Dropdown
|
||||
toggle={
|
||||
<KebabToggle onToggle={() => setIsKebabOpen(!isKebabOpen)} />
|
||||
<KebabToggle
|
||||
onToggle={() => setIsKebabOpen(!isKebabOpen)}
|
||||
isDisabled={selectedRows.length === 0}
|
||||
/>
|
||||
}
|
||||
isOpen={isKebabOpen}
|
||||
isPlain
|
||||
|
@ -169,10 +185,29 @@ export const Members = () => {
|
|||
</ToolbarItem>
|
||||
</>
|
||||
}
|
||||
actions={[
|
||||
{
|
||||
title: t("leave"),
|
||||
onRowClick: async (user) => {
|
||||
try {
|
||||
await adminClient.users.delFromGroup({
|
||||
id: user.id!,
|
||||
groupId: id!,
|
||||
});
|
||||
addAlert(t("usersLeft", { count: 1 }), AlertVariant.success);
|
||||
} catch (error) {
|
||||
addAlert(t("usersLeftError"), AlertVariant.danger);
|
||||
}
|
||||
|
||||
return true;
|
||||
},
|
||||
},
|
||||
]}
|
||||
columns={[
|
||||
{
|
||||
name: "username",
|
||||
displayKey: "common:name",
|
||||
cellRenderer: UserDetailLink,
|
||||
},
|
||||
{
|
||||
name: "email",
|
||||
|
|
|
@ -21,6 +21,7 @@ import { KeycloakDataTable } from "../components/table-toolbar/KeycloakDataTable
|
|||
import { useAdminClient } from "../context/auth/AdminClient";
|
||||
import { useRealm } from "../context/realm-context/RealmContext";
|
||||
import { ListEmptyState } from "../components/list-empty-state/ListEmptyState";
|
||||
import { GroupPath } from "../components/group/GroupPath";
|
||||
import { useSubGroups } from "./SubGroupsContext";
|
||||
|
||||
type SearchGroup = GroupRepresentation & {
|
||||
|
@ -101,6 +102,8 @@ export const SearchGroups = () => {
|
|||
return result;
|
||||
};
|
||||
|
||||
const Path = (group: GroupRepresentation) => <GroupPath group={group} />;
|
||||
|
||||
return (
|
||||
<>
|
||||
<PageSection variant={PageSectionVariants.light}>
|
||||
|
@ -155,6 +158,7 @@ export const SearchGroups = () => {
|
|||
{
|
||||
name: "path",
|
||||
displayKey: "groups:path",
|
||||
cellRenderer: Path,
|
||||
},
|
||||
]}
|
||||
emptyState={
|
||||
|
|
|
@ -22,6 +22,7 @@ import type UserRepresentation from "keycloak-admin/lib/defs/userRepresentation"
|
|||
import { GroupPickerDialog } from "../components/group/GroupPickerDialog";
|
||||
import { HelpContext } from "../components/help-enabler/HelpHeader";
|
||||
import { QuestionCircleIcon } from "@patternfly/react-icons";
|
||||
import { GroupPath } from "../components/group/GroupPath";
|
||||
|
||||
type GroupTableData = GroupRepresentation & {
|
||||
membersLength?: number;
|
||||
|
@ -271,6 +272,8 @@ export const UserGroups = () => {
|
|||
});
|
||||
};
|
||||
|
||||
const Path = (group: GroupRepresentation) => <GroupPath group={group} />;
|
||||
|
||||
return (
|
||||
<>
|
||||
<PageSection variant="light">
|
||||
|
@ -345,7 +348,7 @@ export const UserGroups = () => {
|
|||
{
|
||||
name: "path",
|
||||
displayKey: "users:path",
|
||||
cellFormatters: [emptyFormatter()],
|
||||
cellRenderer: Path,
|
||||
transforms: [cellWidth(45)],
|
||||
},
|
||||
|
||||
|
@ -362,6 +365,8 @@ export const UserGroups = () => {
|
|||
hasIcon={true}
|
||||
message={t("noGroups")}
|
||||
instructions={t("noGroupsText")}
|
||||
primaryActionText={t("joinGroup")}
|
||||
onPrimaryAction={toggleModal}
|
||||
/>
|
||||
) : (
|
||||
""
|
||||
|
|
Loading…
Reference in a new issue