Client: EditGroupMembersDialog: Add virtual list
This commit is contained in:
parent
68a7026879
commit
e2de363696
@ -0,0 +1,38 @@
|
|||||||
|
// (c) Copyright Ascensio System SIA 2009-2024
|
||||||
|
//
|
||||||
|
// This program is a free software product.
|
||||||
|
// You can redistribute it and/or modify it under the terms
|
||||||
|
// of the GNU Affero General Public License (AGPL) version 3 as published by the Free Software
|
||||||
|
// Foundation. In accordance with Section 7(a) of the GNU AGPL its Section 15 shall be amended
|
||||||
|
// to the effect that Ascensio System SIA expressly excludes the warranty of non-infringement of
|
||||||
|
// any third-party rights.
|
||||||
|
//
|
||||||
|
// This program is distributed WITHOUT ANY WARRANTY, without even the implied warranty
|
||||||
|
// of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. For details, see
|
||||||
|
// the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html
|
||||||
|
//
|
||||||
|
// You can contact Ascensio System SIA at Lubanas st. 125a-25, Riga, Latvia, EU, LV-1021.
|
||||||
|
//
|
||||||
|
// The interactive user interfaces in modified source and object code versions of the Program must
|
||||||
|
// display Appropriate Legal Notices, as required under Section 5 of the GNU AGPL version 3.
|
||||||
|
//
|
||||||
|
// Pursuant to Section 7(b) of the License you must retain the original Product logo when
|
||||||
|
// distributing the program. Pursuant to Section 7(e) we decline to grant you any rights under
|
||||||
|
// trademark law for use of our trademarks.
|
||||||
|
//
|
||||||
|
// All the Product's GUI elements, including illustrations and icon sets, as well as technical writing
|
||||||
|
// content are licensed under the terms of the Creative Commons Attribution-ShareAlike 4.0
|
||||||
|
// International. See the License terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
|
||||||
|
|
||||||
|
import styled from "styled-components";
|
||||||
|
import { ModalDialog } from "@docspace/shared/components/modal-dialog";
|
||||||
|
|
||||||
|
export const StyledModalDialog = styled(ModalDialog)`
|
||||||
|
.modal-body {
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-input {
|
||||||
|
margin: 16px 16px 12px;
|
||||||
|
}
|
||||||
|
`;
|
@ -34,8 +34,10 @@ import { getGroupMembersInRoom } from "@docspace/shared/api/groups";
|
|||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
import { InputSize } from "@docspace/shared/components/text-input";
|
import { InputSize } from "@docspace/shared/components/text-input";
|
||||||
import { SearchInput } from "@docspace/shared/components/search-input";
|
import { SearchInput } from "@docspace/shared/components/search-input";
|
||||||
import GroupMember from "./GroupMember";
|
import GroupMember from "./sub-components/GroupMember";
|
||||||
import EmptyContainer from "./EmptyContainer";
|
import EmptyContainer from "./EmptyContainer";
|
||||||
|
import GroupMembersList from "./sub-components/GroupMembersList/GroupMembersList";
|
||||||
|
import { StyledModalDialog } from "./EditGroupMembersDialog.styled";
|
||||||
|
|
||||||
interface EditGroupMembersProps {
|
interface EditGroupMembersProps {
|
||||||
visible: boolean;
|
visible: boolean;
|
||||||
@ -87,7 +89,7 @@ const EditGroupMembers = ({
|
|||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ModalDialog
|
<StyledModalDialog
|
||||||
visible={visible}
|
visible={visible}
|
||||||
onClose={onClose}
|
onClose={onClose}
|
||||||
displayType={ModalDialogType.aside}
|
displayType={ModalDialogType.aside}
|
||||||
@ -104,16 +106,15 @@ const EditGroupMembers = ({
|
|||||||
size={InputSize.base}
|
size={InputSize.base}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<div style={{ height: "12px", width: "100%" }} />
|
|
||||||
|
|
||||||
{isSearchListEmpty && <EmptyContainer />}
|
{isSearchListEmpty && <EmptyContainer />}
|
||||||
|
|
||||||
{hasMembers &&
|
{/*{hasMembers &&*/}
|
||||||
filteredGroupMembers.map(({ user, ...rest }) => (
|
{/* filteredGroupMembers.map(({ user, ...rest }) => (*/}
|
||||||
<GroupMember t={t} key={user.id} user={{ ...user, ...rest }} />
|
{/* <GroupMember t={t} key={user.id} user={{ ...user, ...rest }} />*/}
|
||||||
))}
|
{/* ))}*/}
|
||||||
|
{hasMembers && <GroupMembersList members={groupMembers} />}
|
||||||
</ModalDialog.Body>
|
</ModalDialog.Body>
|
||||||
</ModalDialog>
|
</StyledModalDialog>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -31,7 +31,7 @@ export const GroupMember = styled.div<{ isExpect: boolean }>`
|
|||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
gap: 8px;
|
gap: 8px;
|
||||||
padding: 8px 0;
|
padding: 8px 16px;
|
||||||
|
|
||||||
.avatar {
|
.avatar {
|
||||||
min-width: 32px;
|
min-width: 32px;
|
@ -44,19 +44,25 @@ import { HelpButton } from "@docspace/shared/components/help-button";
|
|||||||
import { getUserRoleOptions } from "@docspace/shared/utils/room-members/getUserRoleOptions";
|
import { getUserRoleOptions } from "@docspace/shared/utils/room-members/getUserRoleOptions";
|
||||||
import { ShareAccessRights } from "@docspace/shared/enums";
|
import { ShareAccessRights } from "@docspace/shared/enums";
|
||||||
import { getUserRole, getUserTypeLabel } from "@docspace/shared/utils/common";
|
import { getUserRole, getUserTypeLabel } from "@docspace/shared/utils/common";
|
||||||
|
import { useTranslation } from "react-i18next";
|
||||||
|
|
||||||
interface GroupMemberProps {
|
interface GroupMemberProps {
|
||||||
t: any;
|
member: any;
|
||||||
user: any;
|
|
||||||
infoPanelSelection: any;
|
infoPanelSelection: any;
|
||||||
}
|
}
|
||||||
|
|
||||||
const GroupMember = ({ t, user, infoPanelSelection }: GroupMemberProps) => {
|
const GroupMember = ({ member, infoPanelSelection }: GroupMemberProps) => {
|
||||||
|
const { user } = member;
|
||||||
|
|
||||||
const [isLoading, setIsLoading] = useState(false);
|
const [isLoading, setIsLoading] = useState(false);
|
||||||
|
const { t } = useTranslation("Common");
|
||||||
|
|
||||||
const userRole = user.isOwner
|
const userRole = user.isOwner
|
||||||
? getUserRoleOptions(t).portalAdmin
|
? getUserRoleOptions(t).portalAdmin
|
||||||
: getUserRoleOptionsByUserAccess(t, user.userAccess || user.groupAccess);
|
: getUserRoleOptionsByUserAccess(
|
||||||
|
t,
|
||||||
|
member.userAccess || member.groupAccess,
|
||||||
|
);
|
||||||
|
|
||||||
const fullRoomRoleOptions = getUserRoleOptionsByRoomType(
|
const fullRoomRoleOptions = getUserRoleOptionsByRoomType(
|
||||||
t,
|
t,
|
||||||
@ -86,7 +92,7 @@ const GroupMember = ({ t, user, infoPanelSelection }: GroupMemberProps) => {
|
|||||||
else
|
else
|
||||||
selectedUserRoleCBOption = getUserRoleOptionsByUserAccess(
|
selectedUserRoleCBOption = getUserRoleOptionsByUserAccess(
|
||||||
t,
|
t,
|
||||||
user.userAccess || user.groupAccess,
|
member.userAccess || member.groupAccess,
|
||||||
);
|
);
|
||||||
|
|
||||||
const availableUserRoleCBOptions = filterUserRoleOptions(
|
const availableUserRoleCBOptions = filterUserRoleOptions(
|
||||||
@ -101,7 +107,7 @@ const GroupMember = ({ t, user, infoPanelSelection }: GroupMemberProps) => {
|
|||||||
notify: false,
|
notify: false,
|
||||||
sharingMessage: "",
|
sharingMessage: "",
|
||||||
})
|
})
|
||||||
.then(() => (user.userAccess = userRoleOption.access))
|
.then(() => (member.userAccess = userRoleOption.access))
|
||||||
.catch((err) => toastr.error(err))
|
.catch((err) => toastr.error(err))
|
||||||
.finally(() => setIsLoading(false));
|
.finally(() => setIsLoading(false));
|
||||||
};
|
};
|
||||||
@ -134,8 +140,8 @@ const GroupMember = ({ t, user, infoPanelSelection }: GroupMemberProps) => {
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="individual-rights-tooltip">
|
<div className="individual-rights-tooltip">
|
||||||
{user.userAccess &&
|
{member.userAccess &&
|
||||||
user.userAccess !== user.groupAccess &&
|
member.userAccess !== member.groupAccess &&
|
||||||
!user.isOwner && (
|
!user.isOwner && (
|
||||||
<HelpButton
|
<HelpButton
|
||||||
place="left"
|
place="left"
|
||||||
@ -152,7 +158,7 @@ const GroupMember = ({ t, user, infoPanelSelection }: GroupMemberProps) => {
|
|||||||
|
|
||||||
{userRole && userRoleOptions && (
|
{userRole && userRoleOptions && (
|
||||||
<div className="role-wrapper">
|
<div className="role-wrapper">
|
||||||
{user.canEditAccess && !user.isOwner ? (
|
{member.canEditAccess && !user.isOwner ? (
|
||||||
<ComboBox
|
<ComboBox
|
||||||
className="role-combobox"
|
className="role-combobox"
|
||||||
selectedOption={userRole}
|
selectedOption={userRole}
|
@ -0,0 +1,67 @@
|
|||||||
|
// (c) Copyright Ascensio System SIA 2009-2024
|
||||||
|
//
|
||||||
|
// This program is a free software product.
|
||||||
|
// You can redistribute it and/or modify it under the terms
|
||||||
|
// of the GNU Affero General Public License (AGPL) version 3 as published by the Free Software
|
||||||
|
// Foundation. In accordance with Section 7(a) of the GNU AGPL its Section 15 shall be amended
|
||||||
|
// to the effect that Ascensio System SIA expressly excludes the warranty of non-infringement of
|
||||||
|
// any third-party rights.
|
||||||
|
//
|
||||||
|
// This program is distributed WITHOUT ANY WARRANTY, without even the implied warranty
|
||||||
|
// of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. For details, see
|
||||||
|
// the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html
|
||||||
|
//
|
||||||
|
// You can contact Ascensio System SIA at Lubanas st. 125a-25, Riga, Latvia, EU, LV-1021.
|
||||||
|
//
|
||||||
|
// The interactive user interfaces in modified source and object code versions of the Program must
|
||||||
|
// display Appropriate Legal Notices, as required under Section 5 of the GNU AGPL version 3.
|
||||||
|
//
|
||||||
|
// Pursuant to Section 7(b) of the License you must retain the original Product logo when
|
||||||
|
// distributing the program. Pursuant to Section 7(e) we decline to grant you any rights under
|
||||||
|
// trademark law for use of our trademarks.
|
||||||
|
//
|
||||||
|
// All the Product's GUI elements, including illustrations and icon sets, as well as technical writing
|
||||||
|
// content are licensed under the terms of the Creative Commons Attribution-ShareAlike 4.0
|
||||||
|
// International. See the License terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
|
||||||
|
|
||||||
|
import { memo, useMemo } from "react";
|
||||||
|
import { areEqual, FixedSizeList as List } from "react-window";
|
||||||
|
import AutoSizer from "react-virtualized-auto-sizer";
|
||||||
|
|
||||||
|
import { CustomScrollbarsVirtualListWithAutoFocus } from "@docspace/shared/components/scrollbar";
|
||||||
|
|
||||||
|
import GroupMember from "../GroupMember";
|
||||||
|
|
||||||
|
const ROW_HEIGHT = 48;
|
||||||
|
const SEARCH_WITH_PADDING_HEIGHT = 60;
|
||||||
|
|
||||||
|
const Row = memo(({ data, index, style }) => {
|
||||||
|
const member = data[index];
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div style={style}>
|
||||||
|
<GroupMember member={member} />
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}, areEqual);
|
||||||
|
|
||||||
|
const GroupMembersList = ({ members }) => {
|
||||||
|
return (
|
||||||
|
<AutoSizer>
|
||||||
|
{({ height, width }) => (
|
||||||
|
<List
|
||||||
|
height={height - SEARCH_WITH_PADDING_HEIGHT}
|
||||||
|
width={width}
|
||||||
|
itemCount={members.length}
|
||||||
|
itemSize={ROW_HEIGHT}
|
||||||
|
itemData={members}
|
||||||
|
outerElementType={CustomScrollbarsVirtualListWithAutoFocus}
|
||||||
|
>
|
||||||
|
{Row}
|
||||||
|
</List>
|
||||||
|
)}
|
||||||
|
</AutoSizer>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default GroupMembersList;
|
Loading…
Reference in New Issue
Block a user