Web: Client: Add showing groups in members panel. Add members search/
This commit is contained in:
parent
eaf83a10d4
commit
9b9b20a493
@ -3,6 +3,7 @@ import { inject, observer } from "mobx-react";
|
||||
|
||||
import ViewHelper from "./helpers/ViewHelper";
|
||||
import ItemTitle from "./sub-components/ItemTitle";
|
||||
import Search from "./sub-components/Search";
|
||||
|
||||
import { StyledInfoPanelBody } from "./styles/common";
|
||||
|
||||
@ -18,6 +19,8 @@ const InfoPanelBodyContent = ({
|
||||
getIsGallery,
|
||||
gallerySelected,
|
||||
isRootFolder,
|
||||
showSearchBlock,
|
||||
setShowSearchBlock,
|
||||
...props
|
||||
}) => {
|
||||
const [selectedItems, setSelectedItems] = useState(props.selectedItems);
|
||||
@ -103,7 +106,7 @@ const InfoPanelBodyContent = ({
|
||||
useEffect(() => {
|
||||
const selectedFolderChanged = isItemChanged(
|
||||
selectedFolder,
|
||||
props.selectedFolder
|
||||
props.selectedFolder,
|
||||
);
|
||||
if (selectedFolderChanged) setSelectedFolder(props.selectedFolder);
|
||||
}, [props.selectedFolder]);
|
||||
@ -118,6 +121,8 @@ const InfoPanelBodyContent = ({
|
||||
|
||||
return (
|
||||
<StyledInfoPanelBody>
|
||||
{showSearchBlock && <Search />}
|
||||
|
||||
{!isNoItem && (
|
||||
<ItemTitle
|
||||
{...defaultProps}
|
||||
@ -144,6 +149,8 @@ export default inject(
|
||||
getIsGallery,
|
||||
infoPanelSelectedItems,
|
||||
getInfoPanelSelectedFolder,
|
||||
showSearchBlock,
|
||||
setShowSearchBlock,
|
||||
} = infoPanelStore;
|
||||
|
||||
const { gallerySelected } = oformsStore;
|
||||
@ -166,6 +173,9 @@ export default inject(
|
||||
|
||||
isRootFolder,
|
||||
gallerySelected,
|
||||
|
||||
showSearchBlock,
|
||||
setShowSearchBlock,
|
||||
};
|
||||
}
|
||||
},
|
||||
)(observer(InfoPanelBodyContent));
|
||||
|
@ -181,6 +181,23 @@ const StyledTitle = styled.div`
|
||||
}
|
||||
`;
|
||||
|
||||
const StyledSearchContainer = styled.div`
|
||||
box-sizing: border-box;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
height: 68px;
|
||||
width: 100%;
|
||||
padding: 0 16px;
|
||||
border-radius: 0 0 6px 6px;
|
||||
background-color: ${(props) => props.theme.infoPanel.backgroundColor};
|
||||
z-index: 101;
|
||||
box-shadow: 0px 5px 20px 0px rgba(4, 15, 27, 0.07);
|
||||
`;
|
||||
|
||||
const StyledLink = styled.div`
|
||||
display: flex;
|
||||
padding: 8px 0;
|
||||
@ -309,6 +326,7 @@ StyledTitle.defaultProps = { theme: Base };
|
||||
export {
|
||||
StyledInfoPanelBody,
|
||||
StyledTitle,
|
||||
StyledSearchContainer,
|
||||
StyledSubtitle,
|
||||
StyledProperties,
|
||||
StyledLink,
|
||||
|
@ -5,6 +5,7 @@ import { Text } from "@docspace/shared/components/text";
|
||||
import { inject, observer } from "mobx-react";
|
||||
import PersonPlusReactSvgUrl from "PUBLIC_DIR/images/person+.react.svg?url";
|
||||
import Planet12ReactSvgUrl from "PUBLIC_DIR/images/icons/12/planet.react.svg?url";
|
||||
import SearchIconReactSvgUrl from "PUBLIC_DIR/images/search.react.svg?url";
|
||||
import { IconButton } from "@docspace/shared/components/icon-button";
|
||||
import { StyledTitle } from "../../../styles/common";
|
||||
import { RoomIcon } from "@docspace/shared/components/room-icon";
|
||||
@ -29,6 +30,7 @@ const RoomsItemHeader = ({
|
||||
setBufferSelection,
|
||||
isArchive,
|
||||
hasLinks,
|
||||
setShowSearchBlock,
|
||||
}) => {
|
||||
const itemTitleRef = useRef();
|
||||
|
||||
@ -39,13 +41,13 @@ const RoomsItemHeader = ({
|
||||
const showDefaultRoomIcon = !isLoadedRoomIcon && selection.isRoom;
|
||||
const security = infoPanelSelection ? infoPanelSelection.security : {};
|
||||
const canInviteUserInRoomAbility = security?.EditAccess;
|
||||
const showInviteUserIcon = selection?.isRoom && roomsView === "info_members";
|
||||
const showPlanetIcon =
|
||||
(selection.roomType === RoomsType.PublicRoom ||
|
||||
selection.roomType === RoomsType.CustomRoom) &&
|
||||
hasLinks;
|
||||
|
||||
const badgeUrl = showPlanetIcon ? Planet12ReactSvgUrl : null;
|
||||
const isRoomMembersPanel = selection?.isRoom && roomsView === "info_members";
|
||||
|
||||
const onSelectItem = () => {
|
||||
setSelected("none");
|
||||
@ -71,6 +73,8 @@ const RoomsItemHeader = ({
|
||||
});
|
||||
};
|
||||
|
||||
const onSearchClick = () => setShowSearchBlock(true);
|
||||
|
||||
return (
|
||||
<StyledTitle ref={itemTitleRef}>
|
||||
<div className="item-icon">
|
||||
@ -88,7 +92,18 @@ const RoomsItemHeader = ({
|
||||
<Text className="text">{selection.title}</Text>
|
||||
|
||||
<div className="info_title-icons">
|
||||
{canInviteUserInRoomAbility && showInviteUserIcon && (
|
||||
{isRoomMembersPanel && (
|
||||
<IconButton
|
||||
id="info_search"
|
||||
className="icon"
|
||||
title={t("Common:Search")}
|
||||
iconName={SearchIconReactSvgUrl}
|
||||
onClick={onSearchClick}
|
||||
size={16}
|
||||
/>
|
||||
)}
|
||||
|
||||
{canInviteUserInRoomAbility && isRoomMembersPanel && (
|
||||
<IconButton
|
||||
id="info_add-user"
|
||||
className={"icon"}
|
||||
@ -119,7 +134,12 @@ export default inject(
|
||||
infoPanelStore,
|
||||
publicRoomStore,
|
||||
}) => {
|
||||
const { infoPanelSelection, roomsView, setIsMobileHidden } = infoPanelStore;
|
||||
const {
|
||||
infoPanelSelection,
|
||||
roomsView,
|
||||
setIsMobileHidden,
|
||||
setShowSearchBlock,
|
||||
} = infoPanelStore;
|
||||
const { externalLinks } = publicRoomStore;
|
||||
|
||||
const selection = infoPanelSelection.length > 1 ? null : infoPanelSelection;
|
||||
@ -130,6 +150,7 @@ export default inject(
|
||||
roomsView,
|
||||
infoPanelSelection,
|
||||
setIsMobileHidden,
|
||||
setShowSearchBlock,
|
||||
|
||||
isGracePeriod: currentTariffStatusStore.isGracePeriod,
|
||||
|
||||
@ -146,7 +167,7 @@ export default inject(
|
||||
isArchive,
|
||||
hasLinks: externalLinks.length,
|
||||
};
|
||||
}
|
||||
},
|
||||
)(
|
||||
withTranslation([
|
||||
"Files",
|
||||
@ -154,5 +175,5 @@ export default inject(
|
||||
"Translations",
|
||||
"InfoPanel",
|
||||
"SharingPanel",
|
||||
])(observer(RoomsItemHeader))
|
||||
])(observer(RoomsItemHeader)),
|
||||
);
|
||||
|
@ -0,0 +1,77 @@
|
||||
import { ChangeEvent, useCallback, useEffect, useState } from "react";
|
||||
import debounce from "lodash.debounce";
|
||||
import { inject } from "mobx-react";
|
||||
|
||||
import XIconReactSvgUrl from "PUBLIC_DIR/images/x.react.svg?url";
|
||||
import {
|
||||
InputSize,
|
||||
InputType,
|
||||
TextInput,
|
||||
} from "@docspace/shared/components/text-input";
|
||||
import { IconButton } from "@docspace/shared/components/icon-button";
|
||||
|
||||
import { StyledSearchContainer } from "../styles/common";
|
||||
|
||||
interface SearchProps {
|
||||
setSearchValue: (value: string) => void;
|
||||
resetSearch: () => void;
|
||||
}
|
||||
|
||||
const Search = ({ setSearchValue, resetSearch }: SearchProps) => {
|
||||
const [value, setValue] = useState("");
|
||||
|
||||
const onClose = () => {
|
||||
resetSearch();
|
||||
};
|
||||
|
||||
const onEscapeUp = (e: KeyboardEvent) => {
|
||||
if (e.key === "Esc" || e.key === "Escape") {
|
||||
e.stopPropagation();
|
||||
onClose();
|
||||
}
|
||||
};
|
||||
|
||||
const onChange = (e: ChangeEvent<HTMLInputElement>) => {
|
||||
const newValue = e.currentTarget.value;
|
||||
setValue(newValue);
|
||||
|
||||
debouncedSearch(newValue.trim());
|
||||
};
|
||||
|
||||
const debouncedSearch = useCallback(
|
||||
debounce((value: string) => setSearchValue(value), 300),
|
||||
[],
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
window.addEventListener("keyup", onEscapeUp);
|
||||
|
||||
return () => window.removeEventListener("keyup", onEscapeUp);
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<StyledSearchContainer>
|
||||
<TextInput
|
||||
id="info_panel_search_input"
|
||||
type={InputType.text}
|
||||
size={InputSize.base}
|
||||
scale={true}
|
||||
onChange={onChange}
|
||||
value={value}
|
||||
isAutoFocussed
|
||||
/>
|
||||
<IconButton
|
||||
id="search_close"
|
||||
iconName={XIconReactSvgUrl}
|
||||
size={16}
|
||||
onClick={onClose}
|
||||
isClickable
|
||||
/>
|
||||
</StyledSearchContainer>
|
||||
);
|
||||
};
|
||||
|
||||
export default inject(({ infoPanelStore }) => ({
|
||||
resetSearch: infoPanelStore.resetSearch,
|
||||
setSearchValue: infoPanelStore.setSearchValue,
|
||||
}))(Search);
|
@ -8,7 +8,7 @@ import DefaultUserPhotoUrl from "PUBLIC_DIR/images/default_user_photo_size_82-82
|
||||
import { toastr } from "@docspace/shared/components/toast";
|
||||
import { isMobileOnly, isMobile } from "react-device-detect";
|
||||
import { decode } from "he";
|
||||
import { filterUserRoleOptions } from "SRC_DIR/helpers";
|
||||
import { filterGroupRoleOptions, filterUserRoleOptions } from "SRC_DIR/helpers";
|
||||
|
||||
import { getUserRole, getUserTypeLabel } from "@docspace/shared/utils/common";
|
||||
import { Text } from "@docspace/shared/components/text";
|
||||
@ -16,6 +16,7 @@ import EmailPlusReactSvgUrl from "PUBLIC_DIR/images/e-mail+.react.svg?url";
|
||||
import { StyledUserTypeHeader } from "../../styles/members";
|
||||
import { IconButton } from "@docspace/shared/components/icon-button";
|
||||
import { Tooltip } from "@docspace/shared/components/tooltip";
|
||||
import { Link } from "@docspace/shared/components/link";
|
||||
|
||||
const User = ({
|
||||
t,
|
||||
@ -33,15 +34,17 @@ const User = ({
|
||||
showTooltip,
|
||||
infoPanelMembers,
|
||||
setInfoPanelMembers,
|
||||
searchValue,
|
||||
}) => {
|
||||
if (!infoPanelSelection) return null;
|
||||
if (!user.displayName && !user.email) return null;
|
||||
if (!user.displayName && !user.name && !user.email) return null;
|
||||
|
||||
const security = infoPanelSelection ? infoPanelSelection.security : {};
|
||||
const isExpect = user.isExpect;
|
||||
const canInviteUserInRoomAbility = security?.EditAccess;
|
||||
const showInviteIcon = canInviteUserInRoomAbility && isExpect;
|
||||
const canChangeUserRole = user.canEditAccess;
|
||||
const withoutTitles = !!searchValue;
|
||||
|
||||
const [isLoading, setIsLoading] = useState(false);
|
||||
|
||||
@ -51,7 +54,9 @@ const User = ({
|
||||
);
|
||||
|
||||
const userRole = membersHelper.getOptionByUserAccess(user.access, user);
|
||||
const userRoleOptions = filterUserRoleOptions(fullRoomRoleOptions, user);
|
||||
const userRoleOptions = user.isGroup
|
||||
? filterGroupRoleOptions(fullRoomRoleOptions)
|
||||
: filterUserRoleOptions(fullRoomRoleOptions, user);
|
||||
|
||||
const onRepeatInvitation = async () => {
|
||||
resendEmailInvitations(infoPanelSelection.id, true)
|
||||
@ -81,22 +86,30 @@ const User = ({
|
||||
expected: infoPanelMembers.expected?.filter(
|
||||
(m) => m.id !== user.id,
|
||||
),
|
||||
groups: infoPanelMembers.groups?.filter((m) => m.id !== user.id),
|
||||
};
|
||||
|
||||
const roomId = infoPanelSelection.id;
|
||||
const newUsers = newMembers.users.length > 1 ? newMembers?.users : [];
|
||||
const minItemsCount = withoutTitles ? 0 : 1;
|
||||
const newUsers =
|
||||
newMembers.users.length > minItemsCount ? newMembers?.users : [];
|
||||
const newAdministrators =
|
||||
newMembers.administrators.length > 1
|
||||
newMembers.administrators.length > minItemsCount
|
||||
? newMembers?.administrators
|
||||
: [];
|
||||
const newExpected =
|
||||
newMembers.expected.length > 1 ? newMembers?.expected : [];
|
||||
newMembers.expected.length > minItemsCount
|
||||
? newMembers?.expected
|
||||
: [];
|
||||
const newGroups =
|
||||
newMembers.groups.length > minItemsCount ? newMembers?.groups : [];
|
||||
|
||||
setInfoPanelMembers({
|
||||
roomId,
|
||||
users: newUsers,
|
||||
administrators: newAdministrators,
|
||||
expected: newExpected,
|
||||
groups: newGroups,
|
||||
});
|
||||
|
||||
newMembersFilter.total -= 1;
|
||||
@ -115,6 +128,7 @@ const User = ({
|
||||
],
|
||||
users: [...newUsers, ...fetchedMembers.users],
|
||||
expected: [...newExpected, ...fetchedMembers.expected],
|
||||
groups: [...newGroups, ...fetchedMembers.groups],
|
||||
};
|
||||
|
||||
setInfoPanelMembers({
|
||||
@ -136,6 +150,9 @@ const User = ({
|
||||
expected: infoPanelMembers.expected?.map((m) =>
|
||||
m.id === user.id ? { ...m, access: option.access } : m,
|
||||
),
|
||||
groups: infoPanelMembers.groups?.map((m) =>
|
||||
m.id === user.id ? { ...m, access: option.access } : m,
|
||||
),
|
||||
});
|
||||
}
|
||||
})
|
||||
@ -203,7 +220,15 @@ const User = ({
|
||||
</div>
|
||||
);
|
||||
|
||||
const userAvatar = user.hasAvatar ? user.avatar : DefaultUserPhotoUrl;
|
||||
const onOpenGroup = () => {
|
||||
console.log("Open group: ", user.name);
|
||||
};
|
||||
|
||||
const userAvatar = user.hasAvatar
|
||||
? user.avatar
|
||||
: user.isGroup
|
||||
? ""
|
||||
: DefaultUserPhotoUrl;
|
||||
|
||||
const withTooltip = user.isOwner || user.isAdmin;
|
||||
|
||||
@ -235,16 +260,23 @@ const User = ({
|
||||
className="avatar"
|
||||
size="min"
|
||||
source={isExpect ? AtReactSvgUrl : userAvatar || ""}
|
||||
userName={isExpect ? "" : user.displayName}
|
||||
userName={isExpect ? "" : user.displayName || user.name}
|
||||
withTooltip={withTooltip}
|
||||
tooltipContent={tooltipContent}
|
||||
hideRoleIcon={!withTooltip}
|
||||
isGroup={user.isGroup}
|
||||
/>
|
||||
<div className="user_body-wrapper">
|
||||
<div className="name-wrapper">
|
||||
<Text className="name" data-tooltip-id={uniqueTooltipId}>
|
||||
{decode(user.displayName)}
|
||||
</Text>
|
||||
{user.isGroup ? (
|
||||
<Link className="name" type="action" onClick={onOpenGroup}>
|
||||
{decode(user.name)}
|
||||
</Link>
|
||||
) : (
|
||||
<Text className="name" data-tooltip-id={uniqueTooltipId}>
|
||||
{decode(user.displayName)}
|
||||
</Text>
|
||||
)}
|
||||
{/* TODO: uncomment when information about online statuses appears */}
|
||||
{/* {showTooltip && (
|
||||
<Tooltip
|
||||
@ -258,19 +290,21 @@ const User = ({
|
||||
<div className="me-label"> {`(${t("Common:MeLabel")})`}</div>
|
||||
)}
|
||||
</div>
|
||||
<div className="role-email" style={{ display: "flex" }}>
|
||||
<Text
|
||||
className="label"
|
||||
fontWeight={400}
|
||||
fontSize="12px"
|
||||
noSelect
|
||||
truncate
|
||||
color="#A3A9AE"
|
||||
dir="auto"
|
||||
>
|
||||
{`${typeLabel} | ${user.email}`}
|
||||
</Text>
|
||||
</div>
|
||||
{!user.isGroup && (
|
||||
<div className="role-email" style={{ display: "flex" }}>
|
||||
<Text
|
||||
className="label"
|
||||
fontWeight={400}
|
||||
fontSize="12px"
|
||||
noSelect
|
||||
truncate
|
||||
color="#A3A9AE"
|
||||
dir="auto"
|
||||
>
|
||||
{`${typeLabel} | ${user.email}`}
|
||||
</Text>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{userRole && userRoleOptions && (
|
||||
@ -311,6 +345,7 @@ export default inject(({ infoPanelStore, filesStore, peopleStore }) => {
|
||||
infoPanelMembers,
|
||||
setInfoPanelMembers,
|
||||
fetchMembers,
|
||||
searchValue,
|
||||
} = infoPanelStore;
|
||||
const {
|
||||
updateRoomMemberRole,
|
||||
@ -332,5 +367,6 @@ export default inject(({ infoPanelStore, filesStore, peopleStore }) => {
|
||||
infoPanelMembers,
|
||||
setInfoPanelMembers,
|
||||
fetchMembers,
|
||||
searchValue,
|
||||
};
|
||||
})(observer(User));
|
||||
|
@ -11,6 +11,7 @@ import MembersList from "./sub-components/MembersList";
|
||||
import User from "./User";
|
||||
import PublicRoomBar from "./sub-components/PublicRoomBar";
|
||||
import { LinksBlock, StyledLinkRow } from "./sub-components/StyledPublicRoom";
|
||||
import EmptyContainer from "./sub-components/EmptyContainer";
|
||||
|
||||
import { Text } from "@docspace/shared/components/text";
|
||||
import { Link } from "@docspace/shared/components/link";
|
||||
@ -44,29 +45,33 @@ const Members = ({
|
||||
withPublicRoomBlock,
|
||||
fetchMembers,
|
||||
membersIsLoading,
|
||||
searchValue,
|
||||
searchResultIsLoading,
|
||||
}) => {
|
||||
const withoutTitlesAndLinks = !!searchValue;
|
||||
const membersHelper = new MembersHelper({ t });
|
||||
|
||||
const updateInfoPanelMembers = async () => {
|
||||
if (!infoPanelSelection) return;
|
||||
const fetchedMembers = await fetchMembers(t);
|
||||
const fetchedMembers = await fetchMembers(t, true, withoutTitlesAndLinks);
|
||||
setInfoPanelMembers(fetchedMembers);
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
updateInfoPanelMembers();
|
||||
}, [infoPanelSelection]);
|
||||
}, [infoPanelSelection, searchValue]);
|
||||
|
||||
const loadNextPage = async () => {
|
||||
const roomId = infoPanelSelection.id;
|
||||
const fetchedMembers = await fetchMembers(t, false);
|
||||
const { users, administrators, expected } = fetchedMembers;
|
||||
const fetchedMembers = await fetchMembers(t, false, withoutTitlesAndLinks);
|
||||
const { users, administrators, expected, groups } = fetchedMembers;
|
||||
|
||||
const newMembers = {
|
||||
roomId: roomId,
|
||||
administrators: [...infoPanelMembers.administrators, ...administrators],
|
||||
users: [...infoPanelMembers.users, ...users],
|
||||
expected: [...infoPanelMembers.expected, ...expected],
|
||||
groups: [...infoPanelMembers.groups, ...groups],
|
||||
};
|
||||
|
||||
setInfoPanelMembers(newMembers);
|
||||
@ -76,18 +81,24 @@ const Members = ({
|
||||
else if (!infoPanelMembers) return <></>;
|
||||
|
||||
const [currentMember] = infoPanelMembers.administrators.filter(
|
||||
(member) => member.id === selfId
|
||||
(member) => member.id === selfId,
|
||||
);
|
||||
|
||||
const { administrators, users, expected } = infoPanelMembers;
|
||||
const { administrators, users, expected, groups } = infoPanelMembers;
|
||||
|
||||
const membersList = [...administrators, ...users, ...expected];
|
||||
const membersList = [...administrators, ...groups, ...users, ...expected];
|
||||
|
||||
const adminsTitleCount = administrators.length ? 1 : 0;
|
||||
const usersTitleCount = users.length ? 1 : 0;
|
||||
const expectedTitleCount = expected.length ? 1 : 0;
|
||||
const groupsTitleCount = groups.length ? 1 : 0;
|
||||
|
||||
const headersCount = adminsTitleCount + usersTitleCount + expectedTitleCount;
|
||||
const headersCount = withoutTitlesAndLinks
|
||||
? 0
|
||||
: adminsTitleCount +
|
||||
usersTitleCount +
|
||||
expectedTitleCount +
|
||||
groupsTitleCount;
|
||||
|
||||
const onAddNewLink = async () => {
|
||||
if (isPublicRoom || primaryLink) {
|
||||
@ -104,7 +115,7 @@ const Members = ({
|
||||
|
||||
const publicRoomItems = [];
|
||||
|
||||
if (isPublicRoomType && withPublicRoomBlock) {
|
||||
if (isPublicRoomType && withPublicRoomBlock && !withoutTitlesAndLinks) {
|
||||
if (!isArchiveFolder || primaryLink) {
|
||||
publicRoomItems.push(
|
||||
<LinksBlock key="general-link_header">
|
||||
@ -116,7 +127,7 @@ const Members = ({
|
||||
<div
|
||||
data-tooltip-id="emailTooltip"
|
||||
data-tooltip-content={t(
|
||||
"Files:MaximumNumberOfExternalLinksCreated"
|
||||
"Files:MaximumNumberOfExternalLinksCreated",
|
||||
)}
|
||||
>
|
||||
<IconButton
|
||||
@ -140,31 +151,31 @@ const Members = ({
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
</LinksBlock>
|
||||
</LinksBlock>,
|
||||
);
|
||||
}
|
||||
|
||||
if (primaryLink) {
|
||||
if (primaryLink && !withoutTitlesAndLinks) {
|
||||
publicRoomItems.push(
|
||||
<LinkRow
|
||||
key="general-link"
|
||||
link={primaryLink}
|
||||
setIsScrollLocked={setIsScrollLocked}
|
||||
/>
|
||||
/>,
|
||||
);
|
||||
}
|
||||
|
||||
if (additionalLinks.length) {
|
||||
if (additionalLinks.length && !withoutTitlesAndLinks) {
|
||||
additionalLinks.map((link) => {
|
||||
publicRoomItems.push(
|
||||
<LinkRow
|
||||
link={link}
|
||||
key={link?.sharedTo?.id}
|
||||
setIsScrollLocked={setIsScrollLocked}
|
||||
/>
|
||||
/>,
|
||||
);
|
||||
});
|
||||
} else if (!isArchiveFolder && !primaryLink) {
|
||||
} else if (!isArchiveFolder && !primaryLink && !withoutTitlesAndLinks) {
|
||||
publicRoomItems.push(
|
||||
<StyledLinkRow
|
||||
key="create-additional-link"
|
||||
@ -182,15 +193,21 @@ const Members = ({
|
||||
>
|
||||
{t("Files:CreateNewLink")}
|
||||
</Link>
|
||||
</StyledLinkRow>
|
||||
</StyledLinkRow>,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
const showPublicRoomBar =
|
||||
((primaryLink && !isArchiveFolder) || isPublicRoom) && withPublicRoomBlock;
|
||||
((primaryLink && !isArchiveFolder) || isPublicRoom) &&
|
||||
withPublicRoomBlock &&
|
||||
!withoutTitlesAndLinks;
|
||||
const publicRoomItemsLength = publicRoomItems.length;
|
||||
|
||||
if (!membersList.length) {
|
||||
return <EmptyContainer />;
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
{showPublicRoomBar && (
|
||||
@ -202,7 +219,10 @@ const Members = ({
|
||||
|
||||
<MembersList
|
||||
loadNextPage={loadNextPage}
|
||||
hasNextPage={membersList.length - headersCount < membersFilter.total}
|
||||
hasNextPage={
|
||||
membersList.length - headersCount < membersFilter.total &&
|
||||
!searchResultIsLoading
|
||||
}
|
||||
itemCount={membersFilter.total + headersCount + publicRoomItemsLength}
|
||||
showPublicRoomBar={showPublicRoomBar}
|
||||
linksBlockLength={publicRoomItemsLength}
|
||||
@ -247,6 +267,8 @@ export default inject(
|
||||
fetchMembers,
|
||||
membersIsLoading,
|
||||
withPublicRoomBlock,
|
||||
searchValue,
|
||||
searchResultIsLoading,
|
||||
} = infoPanelStore;
|
||||
const { membersFilter } = filesStore;
|
||||
const { id: selfId, isAdmin } = userStore.user;
|
||||
@ -280,17 +302,17 @@ export default inject(
|
||||
isArchiveFolder: isArchiveFolderRoot,
|
||||
isPublicRoom,
|
||||
additionalLinks: additionalLinks,
|
||||
isArchiveFolder: isArchiveFolderRoot,
|
||||
setLinkParams,
|
||||
setEditLinkPanelIsVisible,
|
||||
primaryLink,
|
||||
getPrimaryLink: filesStore.getPrimaryLink,
|
||||
setExternalLink,
|
||||
withPublicRoomBlock,
|
||||
fetchMembers,
|
||||
membersIsLoading,
|
||||
searchValue,
|
||||
searchResultIsLoading,
|
||||
};
|
||||
}
|
||||
},
|
||||
)(
|
||||
withTranslation([
|
||||
"InfoPanel",
|
||||
@ -300,5 +322,5 @@ export default inject(
|
||||
"PeopleTranslations",
|
||||
"Settings",
|
||||
"CreateEditRoomDialog",
|
||||
])(observer(Members))
|
||||
])(observer(Members)),
|
||||
);
|
||||
|
@ -0,0 +1,32 @@
|
||||
import { useTranslation } from "react-i18next";
|
||||
import styled, { useTheme } from "styled-components";
|
||||
|
||||
import { EmptyScreenContainer } from "@docspace/shared/components/empty-screen-container";
|
||||
import EmptyScreenPersonSvgUrl from "PUBLIC_DIR/images/empty_screen_persons.svg?url";
|
||||
import EmptyScreenPersonSvgDarkUrl from "PUBLIC_DIR/images/empty_screen_persons_dark.svg?url";
|
||||
|
||||
const StyledEmptyScreen = styled(EmptyScreenContainer)`
|
||||
box-sizing: border-box;
|
||||
width: 100%;
|
||||
padding: 45px 3px 0;
|
||||
`;
|
||||
|
||||
const EmptyContainer = () => {
|
||||
const { t } = useTranslation("People");
|
||||
const theme = useTheme();
|
||||
|
||||
const imageSrc = theme.isBase
|
||||
? EmptyScreenPersonSvgUrl
|
||||
: EmptyScreenPersonSvgDarkUrl;
|
||||
|
||||
return (
|
||||
<StyledEmptyScreen
|
||||
imageSrc={imageSrc}
|
||||
imageAlt="Empty screen image"
|
||||
headerText={t("NotFoundUsers")}
|
||||
descriptionText={t("NotFoundUsersDescription")}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
export default EmptyContainer;
|
@ -91,7 +91,12 @@ class FilesStore {
|
||||
|
||||
filter = FilesFilter.getDefault();
|
||||
roomsFilter = RoomsFilter.getDefault();
|
||||
membersFilter = { page: 0, pageCount: 100, total: 0, startIndex: 0 };
|
||||
membersFilter = {
|
||||
page: 0,
|
||||
pageCount: 100,
|
||||
total: 0,
|
||||
startIndex: 0,
|
||||
};
|
||||
|
||||
categoryType = getCategoryType(window.location);
|
||||
|
||||
@ -2534,7 +2539,12 @@ class FilesStore {
|
||||
}
|
||||
|
||||
getDefaultMembersFilter = () => {
|
||||
return { page: 0, pageCount: 100, total: 0, startIndex: 0 };
|
||||
return {
|
||||
page: 0,
|
||||
pageCount: 100,
|
||||
total: 0,
|
||||
startIndex: 0,
|
||||
};
|
||||
};
|
||||
|
||||
setRoomMembersFilter = (roomMembersFilter) => {
|
||||
@ -2557,6 +2567,7 @@ class FilesStore {
|
||||
startIndex: newFilter.startIndex,
|
||||
count: newFilter.pageCount,
|
||||
filterType: 0, // 0 (Members)
|
||||
filterValue: this.infoPanelStore.searchValue,
|
||||
};
|
||||
|
||||
return api.rooms.getRoomMembers(id, membersFilters).then((res) => {
|
||||
|
@ -62,9 +62,13 @@ class InfoPanelStore {
|
||||
infoPanelSelection = null;
|
||||
infoPanelRoom = null;
|
||||
membersIsLoading = false;
|
||||
searchResultIsLoading = false;
|
||||
|
||||
shareChanged = false;
|
||||
|
||||
showSearchBlock = false;
|
||||
searchValue = "";
|
||||
|
||||
constructor(userStore) {
|
||||
this.userStore = userStore;
|
||||
|
||||
@ -81,6 +85,22 @@ class InfoPanelStore {
|
||||
|
||||
setIsMobileHidden = (bool) => (this.isMobileHidden = bool);
|
||||
|
||||
setShowSearchBlock = (bool) => (this.showSearchBlock = bool);
|
||||
|
||||
setSearchResultIsLoading = (isLoading) => {
|
||||
this.searchResultIsLoading = isLoading;
|
||||
};
|
||||
|
||||
setSearchValue = (value) => {
|
||||
this.setSearchResultIsLoading(true);
|
||||
this.searchValue = value;
|
||||
};
|
||||
|
||||
resetSearch = () => {
|
||||
this.setShowSearchBlock(false);
|
||||
this.setSearchValue("");
|
||||
};
|
||||
|
||||
setSelectionHistory = (obj) => (this.selectionHistory = obj);
|
||||
|
||||
setSelectionHistory = (obj) => {
|
||||
@ -184,13 +204,14 @@ class InfoPanelStore {
|
||||
newInfoPanelSelection = this.normalizeSelection(selectedFolder);
|
||||
} else if (selectedItems.length === 1) {
|
||||
newInfoPanelSelection = this.normalizeSelection(
|
||||
this.getViewItem() ?? newInfoPanelSelection
|
||||
this.getViewItem() ?? newInfoPanelSelection,
|
||||
);
|
||||
} else {
|
||||
newInfoPanelSelection = [...Array(selectedItems.length).keys()];
|
||||
}
|
||||
|
||||
this.setInfoPanelSelection(newInfoPanelSelection);
|
||||
this.resetSearch();
|
||||
};
|
||||
|
||||
normalizeSelection = (infoPanelSelection) => {
|
||||
@ -238,7 +259,7 @@ class InfoPanelStore {
|
||||
const newInfoPanelSelection = await getRoomInfo(currentFolderRoomId);
|
||||
|
||||
const roomIndex = this.selectedFolderStore.navigationPath.findIndex(
|
||||
(f) => f.id === currentFolderRoomId
|
||||
(f) => f.id === currentFolderRoomId,
|
||||
);
|
||||
if (roomIndex > -1) {
|
||||
this.selectedFolderStore.navigationPath[roomIndex].title =
|
||||
@ -268,7 +289,7 @@ class InfoPanelStore {
|
||||
null,
|
||||
null,
|
||||
item.roomType,
|
||||
true
|
||||
true,
|
||||
)
|
||||
? item.logo?.medium
|
||||
: item.icon
|
||||
@ -278,7 +299,7 @@ class InfoPanelStore {
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
item.roomType
|
||||
item.roomType,
|
||||
)
|
||||
: item.isFolder && item.folderType
|
||||
? this.filesSettingsStore.getIconByFolderType(item.folderType, size)
|
||||
@ -330,7 +351,7 @@ class InfoPanelStore {
|
||||
false,
|
||||
fetchedUser.isOwner,
|
||||
fetchedUser.statusType,
|
||||
fetchedUser.status
|
||||
fetchedUser.status,
|
||||
);
|
||||
|
||||
return fetchedUser;
|
||||
@ -420,10 +441,10 @@ class InfoPanelStore {
|
||||
: false;
|
||||
};
|
||||
|
||||
addMembersTitle = (t, administrators, users, expectedMembers) => {
|
||||
addMembersTitle = (t, administrators, users, expectedMembers, groups) => {
|
||||
let hasPrevAdminsTitle = this.getHasPrevTitle(
|
||||
administrators,
|
||||
"administration"
|
||||
"administration",
|
||||
);
|
||||
|
||||
if (administrators.length && !hasPrevAdminsTitle) {
|
||||
@ -434,6 +455,16 @@ class InfoPanelStore {
|
||||
});
|
||||
}
|
||||
|
||||
let hasPrevGroupsTitle = this.getHasPrevTitle(groups, "groups");
|
||||
|
||||
if (groups.length && !hasPrevGroupsTitle) {
|
||||
groups.unshift({
|
||||
id: "groups",
|
||||
displayName: t("Common:Groups"),
|
||||
isTitle: true,
|
||||
});
|
||||
}
|
||||
|
||||
let hasPrevUsersTitle = this.getHasPrevTitle(users, "user");
|
||||
|
||||
if (users.length && !hasPrevUsersTitle) {
|
||||
@ -442,7 +473,7 @@ class InfoPanelStore {
|
||||
|
||||
let hasPrevExpectedTitle = this.getHasPrevTitle(
|
||||
expectedMembers,
|
||||
"expected"
|
||||
"expected",
|
||||
);
|
||||
|
||||
if (expectedMembers.length && !hasPrevExpectedTitle) {
|
||||
@ -455,10 +486,11 @@ class InfoPanelStore {
|
||||
}
|
||||
};
|
||||
|
||||
convertMembers = (t, members, clearFilter) => {
|
||||
convertMembers = (t, members, clearFilter, withoutTitles) => {
|
||||
const users = [];
|
||||
const administrators = [];
|
||||
const expectedMembers = [];
|
||||
const groups = [];
|
||||
|
||||
members?.map((fetchedMember) => {
|
||||
const member = {
|
||||
@ -475,19 +507,25 @@ class InfoPanelStore {
|
||||
member.access === ShareAccessRights.RoomManager
|
||||
) {
|
||||
administrators.push(member);
|
||||
} else if (member.isGroup) {
|
||||
groups.push(member);
|
||||
} else {
|
||||
users.push(member);
|
||||
}
|
||||
});
|
||||
|
||||
if (clearFilter) {
|
||||
this.addMembersTitle(t, administrators, users, expectedMembers);
|
||||
if (clearFilter && !withoutTitles) {
|
||||
this.addMembersTitle(t, administrators, users, expectedMembers, groups);
|
||||
}
|
||||
|
||||
return { administrators, users, expectedMembers };
|
||||
return { administrators, users, expectedMembers, groups };
|
||||
};
|
||||
|
||||
fetchMembers = async (t, clearFilter = true) => {
|
||||
fetchMembers = async (
|
||||
t,
|
||||
clearFilter = true,
|
||||
withoutTitlesAndLinks = false,
|
||||
) => {
|
||||
if (this.membersIsLoading) return;
|
||||
const isPublic =
|
||||
this.infoPanelSelection?.roomType ?? this.infoPanelSelection?.roomType;
|
||||
@ -495,7 +533,12 @@ class InfoPanelStore {
|
||||
|
||||
const requests = [this.filesStore.getRoomMembers(roomId, clearFilter)];
|
||||
|
||||
if (isPublic && clearFilter && this.withPublicRoomBlock) {
|
||||
if (
|
||||
isPublic &&
|
||||
clearFilter &&
|
||||
this.withPublicRoomBlock &&
|
||||
!withoutTitlesAndLinks
|
||||
) {
|
||||
requests.push(this.filesStore.getRoomLinks(roomId));
|
||||
}
|
||||
|
||||
@ -506,19 +549,18 @@ class InfoPanelStore {
|
||||
const [data, links] = await Promise.all(requests);
|
||||
clearFilter && this.setMembersIsLoading(false);
|
||||
clearTimeout(timerId);
|
||||
this.setSearchResultIsLoading(false);
|
||||
|
||||
links && this.publicRoomStore.setExternalLinks(links);
|
||||
|
||||
const { administrators, users, expectedMembers } = this.convertMembers(
|
||||
t,
|
||||
data,
|
||||
clearFilter
|
||||
);
|
||||
const { administrators, users, expectedMembers, groups } =
|
||||
this.convertMembers(t, data, clearFilter, withoutTitlesAndLinks);
|
||||
|
||||
return {
|
||||
users,
|
||||
administrators,
|
||||
expected: expectedMembers,
|
||||
groups,
|
||||
roomId,
|
||||
};
|
||||
};
|
||||
@ -527,13 +569,15 @@ class InfoPanelStore {
|
||||
const newMembers = this.convertMembers(t, members, clearFilter);
|
||||
|
||||
if (this.infoPanelMembers) {
|
||||
const { roomId, administrators, users, expected } = this.infoPanelMembers;
|
||||
const { roomId, administrators, users, expected, groups } =
|
||||
this.infoPanelMembers;
|
||||
|
||||
this.setInfoPanelMembers({
|
||||
roomId: roomId,
|
||||
administrators: [...administrators, ...newMembers.administrators],
|
||||
users: [...users, ...newMembers.users],
|
||||
expected: [...expected, ...newMembers.expectedMembers],
|
||||
groups: [...groups, ...newMembers.groups],
|
||||
});
|
||||
}
|
||||
};
|
||||
@ -562,7 +606,7 @@ class InfoPanelStore {
|
||||
access,
|
||||
primary,
|
||||
internal,
|
||||
expirationDate
|
||||
expirationDate,
|
||||
) => {
|
||||
const { getFileInfo } = this.filesStore;
|
||||
|
||||
@ -573,7 +617,7 @@ class InfoPanelStore {
|
||||
access,
|
||||
primary,
|
||||
internal,
|
||||
expDate
|
||||
expDate,
|
||||
);
|
||||
await getFileInfo(fileId);
|
||||
return res;
|
||||
|
@ -64,6 +64,12 @@ export function getRoomMembers(id, filter) {
|
||||
};
|
||||
|
||||
return request(options).then((res) => {
|
||||
res.items.forEach((item) => {
|
||||
if (item.sharedTo.manager) {
|
||||
item.sharedTo.isGroup = true;
|
||||
}
|
||||
});
|
||||
|
||||
return res;
|
||||
});
|
||||
}
|
||||
@ -339,6 +345,12 @@ export const setRoomSecurity = async (id, data) => {
|
||||
|
||||
const res = await request(options);
|
||||
|
||||
res.members.forEach((item) => {
|
||||
if (item.sharedTo.manager) {
|
||||
item.sharedTo.isGroup = true;
|
||||
}
|
||||
});
|
||||
|
||||
return res;
|
||||
};
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user