Merge branch 'develop' into bugfix/rows-jump-styles

This commit is contained in:
Vlada Gazizova 2024-01-26 14:34:59 +03:00
commit f3a8316a7d
215 changed files with 3817 additions and 3616 deletions

View File

@ -1,6 +1,6 @@
{
"name": "docspace",
"version": "2.0.1",
"version": "2.0.2",
"private": true,
"workspaces": {
"packages": [

View File

@ -1,6 +1,6 @@
{
"name": "@docspace/client",
"version": "2.0.1",
"version": "2.0.2",
"private": true,
"homepage": "",
"scripts": {

View File

@ -3,7 +3,7 @@ import { inject, observer } from "mobx-react";
import { useLocation, Outlet } from "react-router-dom";
import { withTranslation } from "react-i18next";
import Article from "@docspace/common/components/Article";
import Article from "@docspace/shared/components/article";
import {
updateTempContent,
showLoader,
@ -20,6 +20,7 @@ import {
ArticleHeaderContent,
ArticleMainButtonContent,
} from "./components/Article";
import ArticleWrapper from "./components/ArticleWrapper";
const ClientArticle = React.memo(
({
@ -29,7 +30,7 @@ const ClientArticle = React.memo(
showArticleLoader,
}) => {
return (
<Article
<ArticleWrapper
withMainButton={withMainButton}
onLogoClickAction={() => {
setIsFilterLoading(true, false);
@ -48,7 +49,7 @@ const ClientArticle = React.memo(
<Article.Body>
<ArticleBodyContent />
</Article.Body>
</Article>
</ArticleWrapper>
);
}
);

View File

@ -15,10 +15,10 @@ import AccountsFilter from "@docspace/shared/api/people/filter";
import Banner from "./Banner";
import Loaders from "@docspace/common/components/Loaders";
import { getCategoryUrl } from "SRC_DIR/helpers/utils";
import { CategoryType } from "SRC_DIR/helpers/constants";
import { ArticleFolderLoader } from "@docspace/shared/skeletons/article";
import { MEDIA_VIEW_URL } from "@docspace/shared/constants";
const StyledBlock = styled.div`
padding: 0 20px;
@ -221,7 +221,7 @@ const ArticleBodyContent = (props) => {
return setActiveItemId(rootFolderId || roomsFolderId);
}
if (location.pathname.includes("/products/files/#preview")) {
if (location.pathname.includes(MEDIA_VIEW_URL)) {
setActiveItemId(rootFolderId);
}
}, [
@ -239,7 +239,7 @@ const ArticleBodyContent = (props) => {
setIsBurgerLoading(showArticleLoader);
}, [showArticleLoader]);
if (showArticleLoader) return <Loaders.ArticleFolder />;
if (showArticleLoader) return <ArticleFolderLoader />;
return (
<>

View File

@ -1,8 +1,9 @@
import React from "react";
import Loaders from "@docspace/common/components/Loaders";
import { inject, observer } from "mobx-react";
import { withTranslation } from "react-i18next";
import withLoader from "../../../HOCs/withLoader";
import { ArticleHeaderLoader } from "@docspace/shared/skeletons/article";
const ArticleHeaderContent = ({ currentModuleName }) => {
return <>{currentModuleName}</>;
@ -14,6 +15,6 @@ export default inject(({ auth }) => {
};
})(
withTranslation([])(
withLoader(observer(ArticleHeaderContent))(<Loaders.ArticleHeader />)
withLoader(observer(ArticleHeaderContent))(<ArticleHeaderLoader />)
)
);

View File

@ -22,7 +22,6 @@ import { toastr } from "@docspace/shared/components/toast";
import { Button } from "@docspace/shared/components/button";
import { withTranslation } from "react-i18next";
import Loaders from "@docspace/common/components/Loaders";
import { encryptionUploadDialog } from "../../../helpers/desktop";
import { useNavigate, useLocation } from "react-router-dom";
@ -34,6 +33,7 @@ import styled, { css } from "styled-components";
import { resendInvitesAgain } from "@docspace/shared/api/people";
import { getCorrectFourValuesStyle } from "@docspace/shared/utils";
import { ArticleButtonLoader } from "@docspace/shared/skeletons/article";
const StyledButton = styled(Button)`
font-weight: 700;
@ -512,7 +512,7 @@ const ArticleMainButtonContent = (props) => {
}
if (showArticleLoader)
return isMobileArticle ? null : <Loaders.ArticleButton height="32px" />;
return isMobileArticle ? null : <ArticleButtonLoader height="32px" />;
return (
<>

View File

@ -0,0 +1,141 @@
import { inject, observer } from "mobx-react";
import Article from "@docspace/shared/components/article";
import { ArticleProps } from "@docspace/shared/components/article/Article.types";
const ArticleWrapper = (props: ArticleProps) => {
return <Article {...props} />;
};
export default inject(
({ auth, uploadDataStore, profileActionsStore, dialogsStore }: any) => {
const {
settingsStore,
userStore,
isLiveChatAvailable,
bannerStore,
currentQuotaStore,
isPaymentPageAvailable,
isTeamTrainingAlertAvailable,
isSubmitToGalleryAlertAvailable,
currentTariffStatusStore,
isEnterprise,
} = auth;
const { getActions, getUserRole, onProfileClick } = profileActionsStore;
const { withSendAgain, user } = userStore;
const { isBannerVisible } = bannerStore;
const { primaryProgressDataStore, secondaryProgressDataStore } =
uploadDataStore;
const { email, displayName } = user;
const isAdmin = user?.isAdmin;
const { visible: primaryProgressDataVisible } = primaryProgressDataStore;
const { visible: secondaryProgressDataStoreVisible } =
secondaryProgressDataStore;
const showProgress =
primaryProgressDataVisible || secondaryProgressDataStoreVisible;
const {
showText,
setShowText,
articleOpen,
setIsMobileArticle,
toggleShowText,
toggleArticleOpen,
currentColorScheme,
setArticleOpen,
mainBarVisible,
zendeskKey,
isMobileArticle,
currentDeviceType,
standalone,
articleAlertsData,
incrementIndexOfArticleAlertsData,
isBurgerLoading,
whiteLabelLogoUrls,
removeAlertFromArticleAlertsData,
bookTrainingEmail,
} = settingsStore;
const { setSubmitToGalleryDialogVisible } = dialogsStore;
const { isFreeTariff, isNonProfit, isTrial, currentTariffPlanTitle } =
currentQuotaStore;
const {
isGracePeriod,
isLicenseExpiring,
isLicenseDateExpired,
trialDaysLeft,
paymentDate,
} = currentTariffStatusStore;
return {
bookTrainingEmail,
onProfileClick,
user,
getUserRole,
getActions,
currentTariffPlanTitle,
email,
displayName,
zendeskKey,
isMobileArticle,
showProgress,
isBurgerLoading,
whiteLabelLogoUrls,
isEnterprise,
isTrial,
isLicenseDateExpired,
trialDaysLeft,
paymentDate,
toggleArticleOpen,
articleAlertsData,
incrementIndexOfArticleAlertsData,
showText,
isNonProfit,
isGracePeriod,
isFreeTariff,
isPaymentPageAvailable,
isTeamTrainingAlertAvailable,
isSubmitToGalleryAlertAvailable,
isLicenseExpiring,
standalone,
setShowText,
articleOpen,
setIsMobileArticle,
toggleShowText,
removeAlertFromArticleAlertsData,
setSubmitToGalleryDialogVisible,
currentColorScheme,
setArticleOpen,
withSendAgain,
mainBarVisible,
isBannerVisible,
isLiveChatAvailable,
currentDeviceType,
isAdmin,
};
}
)(observer(Article));

View File

@ -29,6 +29,7 @@ export type Item = {
security: Security;
roomType: number;
fileExst?: string;
shared: boolean;
};
export type BreadCrumb = {

View File

@ -226,6 +226,7 @@ const FilesSelector = ({
isRoom:
item.parentId === 0 && item.rootFolderType === FolderType.Rooms,
roomType: item.roomType,
shared: item.shared,
},
]);
setSelectedItemId(item.id);
@ -365,7 +366,7 @@ const FilesSelector = ({
onCloseAction();
};
const onSearchAction = (value: string) => {
const onSearchAction = (value: string, callback?: Function) => {
setIsFirstLoad(true);
setItems(null);
if (selectedItemType === "rooms") {
@ -375,9 +376,10 @@ const FilesSelector = ({
}
setSearchValue(value);
callback?.();
};
const onClearSearchAction = () => {
const onClearSearchAction = (callback?: Function) => {
setIsFirstLoad(true);
setItems(null);
if (selectedItemType === "rooms") {
@ -387,6 +389,7 @@ const FilesSelector = ({
}
setSearchValue("");
callback?.();
};
const onAcceptAction = (

View File

@ -19,7 +19,7 @@ const ChangeUserTypeEvent = ({
onClose,
setSelected,
getPeopleListItem,
setSelection,
setInfoPanelSelection,
needResetUserSelection,
isRoomAdmin,
}) => {
@ -70,7 +70,7 @@ const ChangeUserTypeEvent = ({
if (!needResetUserSelection) {
const user = getPeopleListItem(users[0]);
setSelection(user);
setInfoPanelSelection(user);
}
successCallback && successCallback(users);
@ -144,7 +144,7 @@ export default inject(({ auth, dialogsStore, peopleStore }) => {
setChangeUserTypeDialogVisible: setVisible,
} = dialogsStore;
const { isRoomAdmin, infoPanelStore } = auth;
const { setSelection } = infoPanelStore;
const { setInfoPanelSelection } = infoPanelStore;
const { dialogStore, filterStore, usersStore } = peopleStore;
const { data: peopleDialogData } = dialogStore;
@ -160,7 +160,7 @@ export default inject(({ auth, dialogsStore, peopleStore }) => {
isRoomAdmin,
needResetUserSelection,
getPeopleListItem,
setSelection,
setInfoPanelSelection,
setSelected,
visible,

View File

@ -44,9 +44,8 @@ const EditRoomEvent = ({
updateLogoPathsCacheBreaker,
removeLogoPaths,
reloadInfoPanelSelection,
updateInfoPanelSelection,
changeRoomOwner,
reloadSelectionParentRoom,
}) => {
const { t } = useTranslation(["CreateEditRoomDialog", "Common", "Files"]);
@ -108,6 +107,8 @@ const EditRoomEvent = ({
const uploadLogoData = new FormData();
uploadLogoData.append(0, roomParams.icon.uploadedFile);
let room = null;
try {
setIsLoading(true);
@ -115,7 +116,7 @@ const EditRoomEvent = ({
await changeRoomOwner(t, roomParams?.roomOwner?.id);
}
let room = await editRoom(item.id, editRoomParams);
room = await editRoom(item.id, editRoomParams);
room.isLogoLoading = true;
@ -154,15 +155,14 @@ const EditRoomEvent = ({
}
!withPaging && updateRoom(item, room);
reloadSelectionParentRoom();
reloadInfoPanelSelection();
// updateInfoPanelSelection();
URL.revokeObjectURL(img.src);
setActiveFolders([]);
};
img.src = url;
} else {
!withPaging && updateRoom(item, room);
reloadInfoPanelSelection();
// updateInfoPanelSelection();
}
} catch (err) {
console.log(err);
@ -173,14 +173,14 @@ const EditRoomEvent = ({
updateEditedSelectedRoom(editRoomParams.title, tags);
if (item.logo.original && !roomParams.icon.uploadedFile) {
removeLogoPaths();
reloadInfoPanelSelection();
// updateInfoPanelSelection();
} else if (!item.logo.original && roomParams.icon.uploadedFile)
addDefaultLogoPaths();
else if (item.logo.original && roomParams.icon.uploadedFile)
updateLogoPathsCacheBreaker();
}
reloadSelectionParentRoom();
updateInfoPanelSelection(room);
setIsLoading(false);
onClose();
}
@ -272,10 +272,7 @@ export default inject(
const { getThirdPartyIcon } = settingsStore.thirdPartyStore;
const { setCreateRoomDialogVisible } = dialogsStore;
const { withPaging } = auth.settingsStore;
const {
reloadSelection: reloadInfoPanelSelection,
reloadSelectionParentRoom,
} = auth.infoPanelStore;
const { updateInfoPanelSelection } = auth.infoPanelStore;
return {
addActiveItems,
setActiveFolders,
@ -308,9 +305,8 @@ export default inject(
updateLogoPathsCacheBreaker,
removeLogoPaths,
reloadInfoPanelSelection,
updateInfoPanelSelection,
changeRoomOwner,
reloadSelectionParentRoom,
};
}
)(observer(EditRoomEvent));

View File

@ -3,7 +3,6 @@ import CatalogFolderReactSvgUrl from "PUBLIC_DIR/images/catalog.folder.react.svg
import React from "react";
import { withTranslation } from "react-i18next";
import Filter from "@docspace/shared/api/people/filter";
import Loaders from "@docspace/common/components/Loaders";
import { inject, observer } from "mobx-react";
import { getSelectedGroup } from "../../../helpers/people-helpers";
import { useNavigate } from "react-router-dom";
@ -13,6 +12,7 @@ import config from "PACKAGE_FILE";
import { combineUrl } from "@docspace/shared/utils/combineUrl";
import { ArticleItem } from "@docspace/shared/components/article-item";
import withLoader from "../../../HOCs/withLoader";
import { ArticleFolderLoader } from "@docspace/shared/skeletons/article";
const departmentsIcon = DepartmentsGroupReactSvgUrl;
const groupIcon = CatalogFolderReactSvgUrl;
@ -128,7 +128,7 @@ const ArticleBodyContent = ({
};
const BodyContent = withTranslation(["Article"])(
withLoader(ArticleBodyContent)(<Loaders.ArticleFolder />)
withLoader(ArticleBodyContent)(<ArticleFolderLoader />)
);
export default inject(({ auth, peopleStore }) => {

View File

@ -23,6 +23,7 @@ import {
import MobileView from "./MobileView";
import withLoader from "../../../HOCs/withLoader";
import { ArticleButtonLoader } from "@docspace/shared/skeletons/article";
const ArticleMainButtonContent = (props) => {
const [dialogVisible, setDialogVisible] = React.useState(false);
@ -128,6 +129,6 @@ export default inject(({ auth }) => {
};
})(
withTranslation(["Article", "Common", "PeopleTranslations"])(
withLoader(observer(ArticleMainButtonContent))(<Loaders.ArticleButton />)
withLoader(observer(ArticleMainButtonContent))(<ArticleButtonLoader />)
)
);

View File

@ -40,7 +40,7 @@ class ChangeUserStatusDialogComponent extends React.Component {
onClose,
userIDs,
getPeopleListItem,
setSelection,
setInfoPanelSelection,
infoPanelVisible,
needResetUserSelection,
} = this.props;
@ -51,7 +51,7 @@ class ChangeUserStatusDialogComponent extends React.Component {
if (users.length === 1 && infoPanelVisible) {
const user = getPeopleListItem(users[0]);
setSelection(user);
setInfoPanelSelection(user);
}
toastr.success(t("PeopleTranslations:SuccessChangeUserStatus"));
@ -176,7 +176,8 @@ export default inject(({ peopleStore, auth }) => {
const { getPeopleListItem, updateUserStatus, needResetUserSelection } =
peopleStore.usersStore;
const { setSelection, isVisible: infoPanelVisible } = auth.infoPanelStore;
const { setInfoPanelSelection, isVisible: infoPanelVisible } =
auth.infoPanelStore;
return {
needResetUserSelection,
@ -186,7 +187,7 @@ export default inject(({ peopleStore, auth }) => {
getPeopleListItem,
setSelection,
setInfoPanelSelection,
infoPanelVisible,
};
})(observer(ChangeUserStatusDialog));

View File

@ -42,7 +42,7 @@ const DropdownDesktop = ({ t, open, chooseRoomType }) => {
return (
<StyledDropdownDesktop className="dropdown-content-wrapper" isOpen={open}>
<div className="dropdown-content">
{Object.values(RoomsTypeValues).map((roomType) => (
{RoomsTypeValues.map((roomType) => (
<RoomType
id={roomType}
t={t}

View File

@ -31,7 +31,7 @@ const DropdownMobile = ({ t, open, onClose, chooseRoomType }) => {
<>
<Backdrop visible={open} onClick={onClose} zIndex={450} />
<StyledDropdownMobile className="dropdown-mobile" isOpen={open}>
{Object.values(RoomsTypeValues).map((roomType) => (
{RoomsTypeValues.map((roomType) => (
<RoomType
id={roomType}
t={t}

View File

@ -19,7 +19,7 @@ const StyledRoomTypeList = styled.div`
const RoomTypeList = ({ t, setRoomType }) => {
return (
<StyledRoomTypeList>
{Object.values(RoomsTypeValues).map((roomType) => (
{RoomsTypeValues.map((roomType) => (
<RoomType
id={roomType}
t={t}

View File

@ -121,7 +121,7 @@ const DeleteLinkDialog = withTranslation(["Common", "Files"])(
);
export default inject(({ auth, dialogsStore, publicRoomStore, filesStore }) => {
const { selectionParentRoom } = auth.infoPanelStore;
const { infoPanelSelection } = auth.infoPanelStore;
const {
deleteLinkDialogVisible: visible,
setDeleteLinkDialogVisible: setIsVisible,
@ -132,11 +132,11 @@ export default inject(({ auth, dialogsStore, publicRoomStore, filesStore }) => {
return {
visible,
setIsVisible,
roomId: selectionParentRoom.id,
roomId: infoPanelSelection.id,
link: linkParams.link,
editExternalLink,
deleteExternalLink,
isPublicRoomType: selectionParentRoom.roomType === RoomsType.PublicRoom,
isPublicRoomType: infoPanelSelection.roomType === RoomsType.PublicRoom,
setRoomShared: filesStore.setRoomShared,
};
})(observer(DeleteLinkDialog));

View File

@ -46,6 +46,7 @@ const ChangeRoomOwner = (props) => {
roomOwnerId,
changeRoomOwner,
userId,
updateInfoPanelSelection,
} = props;
const [isLoading, setIsLoading] = useState(false);
@ -71,6 +72,7 @@ const ChangeRoomOwner = (props) => {
setIsLoading(true);
await changeRoomOwner(t, user[0]?.id, isChecked);
updateInfoPanelSelection();
setIsLoading(false);
}
onClose();
@ -147,9 +149,10 @@ export default inject(
setChangeRoomOwnerIsVisible,
changeRoomOwnerData,
} = dialogsStore;
const { settingsStore, userStore } = auth;
const { settingsStore, userStore, infoPanelStore } = auth;
const { selection, bufferSelection } = filesStore;
const { currentDeviceType } = settingsStore;
const { updateInfoPanelSelection } = infoPanelStore;
const room = selection.length
? selection[0]
@ -157,8 +160,6 @@ export default inject(
? bufferSelection
: selectedFolderStore;
const { currentDeviceType } = settingsStore;
const { id } = userStore.user;
return {
@ -170,6 +171,7 @@ export default inject(
currentDeviceType,
changeRoomOwner: filesActionsStore.changeRoomOwner,
userId: id,
updateInfoPanelSelection,
};
}
)(observer(withTranslation(["Files"])(ChangeRoomOwner)));

View File

@ -271,7 +271,7 @@ const EditLinkPanel = (props) => {
};
export default inject(({ auth, dialogsStore, publicRoomStore }) => {
const { selectionParentRoom } = auth.infoPanelStore;
const { infoPanelSelection } = auth.infoPanelStore;
const {
editLinkPanelIsVisible,
setEditLinkPanelIsVisible,
@ -286,7 +286,7 @@ export default inject(({ auth, dialogsStore, publicRoomStore }) => {
const link = externalLinks.find((l) => l?.sharedTo?.id === linkId);
const shareLink = link?.sharedTo?.shareLink;
const isPublic = selectionParentRoom?.roomType === RoomsType.PublicRoom;
const isPublic = infoPanelSelection?.roomType === RoomsType.PublicRoom;
return {
visible: editLinkPanelIsVisible,
@ -294,7 +294,7 @@ export default inject(({ auth, dialogsStore, publicRoomStore }) => {
isEdit,
linkId: link?.sharedTo?.id,
editExternalLink,
roomId: selectionParentRoom.id,
roomId: infoPanelSelection.id,
setExternalLink,
isLocked: !!link?.sharedTo?.password,
password: link?.sharedTo?.password ?? "",

View File

@ -54,9 +54,8 @@ const InvitePanel = ({
defaultAccess,
inviteUsers,
setInfoPanelIsMobileHidden,
reloadSelectionParentRoom,
setUpdateRoomMembers,
roomsView,
updateInfoPanelSelection,
addInfoPanelMembers,
setInviteLanguage,
getUsersList,
filter,
@ -277,15 +276,15 @@ const InvitePanel = ({
try {
setIsLoading(true);
const result =
roomId === -1
? await inviteUsers(data)
: await setRoomSecurity(roomId, data);
const isRooms = roomId !== -1;
const result = !isRooms
? await inviteUsers(data)
: await setRoomSecurity(roomId, data);
setIsLoading(false);
if (roomsView === "info_members") {
setUpdateRoomMembers(true);
if (isRooms) {
addInfoPanelMembers(t, result.members, true);
}
onClose();
@ -295,7 +294,7 @@ const InvitePanel = ({
toastr.warning(result?.warning);
}
reloadSelectionParentRoom();
updateInfoPanelSelection();
} catch (err) {
toastr.error(err);
setIsLoading(false);
@ -471,10 +470,8 @@ export default inject(({ auth, peopleStore, filesStore, dialogsStore }) => {
const { filter } = peopleStore.filterStore;
const {
setIsMobileHidden: setInfoPanelIsMobileHidden,
reloadSelectionParentRoom,
setUpdateRoomMembers,
roomsView,
filesView,
updateInfoPanelSelection,
addInfoPanelMembers,
} = auth.infoPanelStore;
const {
@ -517,9 +514,8 @@ export default inject(({ auth, peopleStore, filesStore, dialogsStore }) => {
collaboratorLink,
inviteUsers,
setInfoPanelIsMobileHidden,
reloadSelectionParentRoom,
setUpdateRoomMembers,
roomsView,
updateInfoPanelSelection,
addInfoPanelMembers,
getUsersList,
filter,
currentDeviceType,

View File

@ -3,7 +3,7 @@ import PropTypes from "prop-types";
import { Backdrop } from "@docspace/shared/components/backdrop";
import { Heading } from "@docspace/shared/components/heading";
import { Aside } from "@docspace/shared/components/aside";
import Loaders from "@docspace/common/components/Loaders";
import { FloatingButton } from "@docspace/shared/components/floating-button";
import { Portal } from "@docspace/shared/components/portal";
import { DeviceType } from "@docspace/shared/enums";
@ -17,6 +17,7 @@ import {
import { SectionBodyContent } from "../../../pages/VersionHistory/Section/";
import { inject, observer } from "mobx-react";
import config from "PACKAGE_FILE";
import { ArticleHeaderLoader } from "@docspace/shared/skeletons/article";
class PureVersionHistoryPanel extends React.Component {
onClose = () => {
@ -70,7 +71,7 @@ class PureVersionHistoryPanel extends React.Component {
{versions[0].title}
</Heading>
) : (
<Loaders.ArticleHeader
<ArticleHeaderLoader
className="loader-version-history"
height="28"
width="688"

View File

@ -150,11 +150,6 @@ export const LinkType = Object.freeze({
export const SSO_LABEL = "SSO";
export const ARTICLE_ALERTS = Object.freeze({
TeamTraining: "TeamTraining",
SubmitToFormGallery: "SubmitToFormGallery",
});
export const AuthenticatedAction = Object.freeze({
None: 0,
Logout: 1,

View File

@ -5,7 +5,7 @@ import { I18nextProvider, useTranslation } from "react-i18next";
import ErrorContainer from "@docspace/common/components/ErrorContainer";
import { useParams } from "react-router-dom";
import { Link } from "@docspace/shared/components/link";
import { ZendeskAPI } from "@docspace/common/components/Zendesk";
import { ZendeskAPI } from "@docspace/shared/components/zendesk";
import { ReportDialog } from "SRC_DIR/components/dialogs";
import DocspaceLogo from "SRC_DIR/DocspaceLogo";

View File

@ -5,7 +5,7 @@ import { useState, useRef } from "react";
import { inject, observer } from "mobx-react";
import { withTranslation } from "react-i18next";
import { Scrollbar } from "@docspace/shared/components/scrollbar";
import { ComboButton } from "@docspace/shared/components/combobox";
import { ComboButton } from "@docspace/shared/components/combobox/sub-components/ComboButton";
import { Backdrop } from "@docspace/shared/components/backdrop";
import { isMobile } from "@docspace/shared/utils";

View File

@ -6,9 +6,11 @@ import FilesFilter from "@docspace/shared/api/files/filter";
import RoomsFilter from "@docspace/shared/api/rooms/filter";
import { getGroup } from "@docspace/shared/api/groups";
import { getUserById } from "@docspace/shared/api/people";
import { MEDIA_VIEW_URL } from "@docspace/shared/constants";
import { Events, RoomSearchArea } from "@docspace/shared/enums";
import { getObjectByLocation } from "@docspace/shared/utils/common";
import { useParams } from "react-router-dom";
import { getCategoryType, getCategoryUrl } from "SRC_DIR/helpers/utils";
import { CategoryType } from "SRC_DIR/helpers/constants";
@ -44,6 +46,7 @@ const useFiles = ({
folderSecurity,
}) => {
const navigate = useNavigate();
const { id } = useParams();
const fetchDefaultFiles = () => {
const filter = FilesFilter.getDefault();
@ -98,7 +101,7 @@ const useFiles = ({
if (location.pathname === "/") setIsLoading(true, true, true);
else setIsLoading(true, false, false);
if (!window.location.href.includes("#preview")) {
if (!window.location.href.includes(MEDIA_VIEW_URL)) {
// localStorage.removeItem("isFirstUrl");
// Media viewer
removeFirstUrl();
@ -109,12 +112,12 @@ const useFiles = ({
let filterObj = null;
let isRooms = false;
if (window.location.href.indexOf("/#preview") > 1 && playlist.length < 1) {
const pathname = window.location.href;
const fileId = pathname.slice(pathname.indexOf("#preview") + 9);
if (
window.location.href.indexOf(MEDIA_VIEW_URL) > 1 &&
playlist.length < 1
) {
setTimeout(() => {
getFileInfo(fileId)
getFileInfo(id)
.then((data) => {
const canOpenPlayer =
data.viewAccessibility.ImageView ||
@ -132,7 +135,7 @@ const useFiles = ({
return setIsLoading(false);
}
if (window.location.href.indexOf("/#preview") > 1)
if (window.location.href.indexOf(MEDIA_VIEW_URL) > 1)
return setIsLoading(false);
const isRoomFolder = getObjectByLocation(window.location)?.folder;

View File

@ -1,7 +1,5 @@
const excludeGeneralOptions = ["select", "show-info"];
const excludeRoomOptions = ["separator0", "room-info"];
const excludeOptionsIntoRoom = ["pin-room", "unpin-room"];
const excludeOptionsIntoFolder = ["open", "separator0", "separator1"];
class ContextHelper {
constructor(props) {
@ -38,20 +36,7 @@ class ContextHelper {
if (idx !== -1) options.splice(idx, 1);
});
if (this.selection.isSelectedFolder) {
excludeOptionsIntoRoom.forEach((excludeOption) => {
const idx = options.findIndex((o) => o === excludeOption);
if (idx !== -1) options.splice(idx, 1);
});
}
}
if (this.selection?.isSelectedFolder && !this.selection?.isRoom) {
excludeOptionsIntoFolder.forEach((excludeOption) => {
const idx = options.findIndex((o) => o === excludeOption);
if (idx !== -1) options.splice(idx, 1);
});
}
const length = options.length;

View File

@ -1,20 +1,15 @@
import React, { useState, useEffect, useCallback } from "react";
import { useState, useEffect } from "react";
import { inject, observer } from "mobx-react";
import ViewHelper from "./helpers/ViewHelper";
import ItemTitle from "./sub-components/ItemTitle";
import { StyledInfoPanelBody } from "./styles/common";
import { getRoomInfo } from "@docspace/shared/api/rooms";
const InfoPanelBodyContent = ({
selection,
setSelection,
calculateSelection,
normalizeSelection,
infoPanelSelection,
setNewInfoPanelSelection,
isItemChanged,
selectionParentRoom,
setSelectionParentRoom,
roomsView,
fileView,
getIsFiles,
@ -36,13 +31,15 @@ const InfoPanelBodyContent = ({
const isSeveralItems = props.selectedItems?.length > 1;
const isNoItemGallery = isGallery && !gallerySelected;
const itemIsRoot =
selection?.isSelectedFolder && selection?.id === selection?.rootFolderId;
const isRoot =
infoPanelSelection?.isFolder &&
infoPanelSelection?.id === infoPanelSelection?.rootFolderId;
const isNoItem =
!isSeveralItems && (isNoItemGallery || (itemIsRoot && !isGallery));
!infoPanelSelection ||
(!isSeveralItems && (isNoItemGallery || (isRoot && !isGallery)));
const defaultProps = {
selection,
infoPanelSelection,
isFiles,
isRooms,
isAccounts,
@ -111,45 +108,14 @@ const InfoPanelBodyContent = ({
if (selectedFolderChanged) setSelectedFolder(props.selectedFolder);
}, [props.selectedFolder]);
// Updating selectionParentRoom after selectFolder change
// Updating infoPanelSelection after selectFolder change
// if it is located in another room
const updateSelectionParentRoomAction = useCallback(async () => {
if (!isRooms) return;
if (selection?.isRoom && roomsView === "members") return;
const currentFolderRoomId =
selectedFolder?.pathParts &&
selectedFolder?.pathParts?.length > 1 &&
selectedFolder.pathParts[1].id;
const storeRoomId = selectionParentRoom?.id;
if (!currentFolderRoomId || currentFolderRoomId === storeRoomId) return;
const newSelectionParentRoom = await getRoomInfo(currentFolderRoomId);
if (storeRoomId === newSelectionParentRoom.id) return;
setSelectionParentRoom(normalizeSelection(newSelectionParentRoom));
}, [selectedFolder]);
// Setting infoPanelSelection after selectedItems or selectedFolder update
useEffect(() => {
updateSelectionParentRoomAction();
}, [selectedFolder, updateSelectionParentRoomAction]);
// Setting selection after selectedItems or selectedFolder update
useEffect(() => {
setSelection(calculateSelection());
setNewInfoPanelSelection();
}, [selectedItems, selectedFolder]);
// * DEV-ONLY - Logs selection change
// useEffect(() => {
// console.log("\nfor-dev Selected items: ", selectedItems);
// console.log("\nfor-dev Selected folder: ", selectedFolder);
// }, [selectedItems, selectedFolder]);
if (!selection && !isGallery) return null;
return (
<StyledInfoPanelBody>
{!isNoItem && (
@ -166,38 +132,27 @@ const InfoPanelBodyContent = ({
export default inject(({ auth, selectedFolderStore, oformsStore }) => {
const {
selection,
setSelection,
calculateSelection,
normalizeSelection,
infoPanelSelection,
setNewInfoPanelSelection,
isItemChanged,
selectionParentRoom,
setSelectionParentRoom,
roomsView,
fileView,
getIsFiles,
getIsRooms,
getIsAccounts,
getIsGallery,
infoPanelSelectedItems,
getInfoPanelSelectedFolder,
} = auth.infoPanelStore;
const { gallerySelected } = oformsStore;
const { isRootFolder } = selectedFolderStore;
const selectedItems = auth.infoPanelStore.getSelectedItems();
const selectedFolder = auth.infoPanelStore.getSelectedFolder();
return {
selection,
setSelection,
calculateSelection,
normalizeSelection,
infoPanelSelection,
setNewInfoPanelSelection,
isItemChanged,
selectionParentRoom,
setSelectionParentRoom,
roomsView,
fileView,
getIsFiles,
@ -205,8 +160,8 @@ export default inject(({ auth, selectedFolderStore, oformsStore }) => {
getIsAccounts,
getIsGallery,
selectedItems,
selectedFolder,
selectedItems: infoPanelSelectedItems,
selectedFolder: getInfoPanelSelectedFolder(),
isRootFolder,
gallerySelected,

View File

@ -15,7 +15,7 @@ const CommentEditor = ({
t,
item,
editing,
setSelection,
setInfoPanelSelection,
fetchFileVersions,
updateCommentVersion,
@ -61,7 +61,7 @@ const CommentEditor = ({
setIsLoading(false);
});
setSelection({ ...item, comment: inputValue });
setInfoPanelSelection({ ...item, comment: inputValue });
setIsEdit(false);
setIsLoading(false);
};
@ -121,7 +121,7 @@ const CommentEditor = ({
};
export default inject(({ auth, versionHistoryStore }) => {
const { setSelection } = auth.infoPanelStore;
const { setInfoPanelSelection } = auth.infoPanelStore;
const {
fetchFileVersions,
@ -136,7 +136,7 @@ export default inject(({ auth, versionHistoryStore }) => {
const editing = isEditingVersion || isEditing;
return {
setSelection,
setInfoPanelSelection,
fetchFileVersions,
updateCommentVersion,

View File

@ -16,7 +16,7 @@ import { decode } from "he";
const AccountsItemTitle = ({
t,
isSeveralItems,
selection,
infoPanelSelection,
getUserContextOptions,
}) => {
if (isSeveralItems) {
@ -26,20 +26,23 @@ const AccountsItemTitle = ({
const itemTitleRef = useRef();
const isPending =
selection.statusType === "pending" || selection.statusType === "disabled";
infoPanelSelection.statusType === "pending" ||
infoPanelSelection.statusType === "disabled";
const getData = () => {
const newOptions = selection.options?.filter(
const newOptions = infoPanelSelection.options?.filter(
(option) => option !== "details"
);
return getUserContextOptions(t, newOptions || [], selection);
return getUserContextOptions(t, newOptions || [], infoPanelSelection);
};
const contextOptions = getData();
const userAvatar = selection.hasAvatar ? selection.avatar : DefaultUserPhoto;
const isSSO = selection.isSSO || false;
const displayName = selection.displayName
? decode(selection.displayName).trim()
const userAvatar = infoPanelSelection.hasAvatar
? infoPanelSelection.avatar
: DefaultUserPhoto;
const isSSO = infoPanelSelection.isSSO || false;
const displayName = infoPanelSelection.displayName
? decode(infoPanelSelection.displayName).trim()
: "";
return (
@ -50,7 +53,7 @@ const AccountsItemTitle = ({
>
<Avatar
className="avatar"
role={selection.role ? selection.role : "user"}
role={infoPanelSelection.role ? infoPanelSelection.role : "user"}
size={"big"}
source={userAvatar}
/>
@ -62,15 +65,18 @@ const AccountsItemTitle = ({
title={displayName}
truncate
>
{isPending || !displayName ? selection.email : displayName}
{isPending || !displayName ? infoPanelSelection.email : displayName}
</Text>
{isPending && (
<Badges withoutPaid={true} statusType={selection.statusType} />
<Badges
withoutPaid={true}
statusType={infoPanelSelection.statusType}
/>
)}
</div>
{!isPending && !!displayName && (
<Text className={"info-text__email"} title={selection.email}>
{selection.email}
<Text className={"info-text__email"} title={infoPanelSelection.email}>
{infoPanelSelection.email}
</Text>
)}
{isSSO && (

View File

@ -7,8 +7,6 @@ import { ContextMenuButton } from "@docspace/shared/components/context-menu-butt
const generalKeys = ["select", "show-info"];
const roomKeys = ["separator0", "room-info"];
const currentRoomKeys = ["pin-room", "unpin-room"];
const currentFolderKeys = ["open", "separator0", "separator1"];
const StyledItemContextOptions = styled.div`
height: 16px;
@ -23,7 +21,6 @@ const RoomsContextBtn = ({
getItemContextOptionsKeys,
getItemContextOptionsActions,
onSelectItem,
}) => {
const contextMenuRef = useRef();
@ -54,10 +51,6 @@ const RoomsContextBtn = ({
generalKeys.forEach((key) => removeOptionByKey(key));
if (selection.isRoom) roomKeys.forEach((key) => removeOptionByKey(key));
if (selection.isSelectedFolder && selection.isRoom)
currentRoomKeys.forEach((key) => removeOptionByKey(key));
if (selection.isSelectedFolder && !selection.isRoom)
currentFolderKeys.forEach((key) => removeOptionByKey(key));
options.forEach((item, index) => {
const isSeparator = item.key.includes("separator");
@ -76,10 +69,6 @@ const RoomsContextBtn = ({
return options;
};
// useEffect(() => {
// contextMenuRef?.current.hide();
// }, [selection]);
return (
<StyledItemContextOptions>
<ContextMenuButton

View File

@ -8,12 +8,16 @@ import { IconButton } from "@docspace/shared/components/icon-button";
import { StyledTitle } from "../../../styles/common";
import { RoomIcon } from "@docspace/shared/components/room-icon";
import RoomsContextBtn from "./context-btn";
import { RoomsType, ShareAccessRights } from "@docspace/shared/enums";
import {
FolderType,
RoomsType,
ShareAccessRights,
} from "@docspace/shared/enums";
const RoomsItemHeader = ({
t,
selection,
selectionParentRoom,
infoPanelSelection,
setIsMobileHidden,
isGracePeriod,
setInvitePanelOptions,
@ -22,6 +26,7 @@ const RoomsItemHeader = ({
roomsView,
setSelected,
setBufferSelection,
isArchive,
}) => {
const itemTitleRef = useRef();
@ -30,7 +35,7 @@ const RoomsItemHeader = ({
const icon = selection.icon;
const isLoadedRoomIcon = !!selection.logo?.medium;
const showDefaultRoomIcon = !isLoadedRoomIcon && selection.isRoom;
const security = selectionParentRoom ? selectionParentRoom.security : {};
const security = infoPanelSelection ? infoPanelSelection.security : {};
const canInviteUserInRoomAbility = security?.EditAccess;
const showInviteUserIcon = selection?.isRoom && roomsView === "info_members";
@ -41,7 +46,7 @@ const RoomsItemHeader = ({
const onClickInviteUsers = () => {
setIsMobileHidden(true);
const parentRoomId = selectionParentRoom.id;
const parentRoomId = infoPanelSelection.id;
if (isGracePeriod) {
setInviteUsersWarningDialogVisible(true);
@ -65,7 +70,7 @@ const RoomsItemHeader = ({
<RoomIcon
color={selection.logo.color}
title={selection.title}
isArchive={selection.isArchive}
isArchive={isArchive}
/>
) : (
<img
@ -103,30 +108,15 @@ const RoomsItemHeader = ({
export default inject(
({ auth, dialogsStore, selectedFolderStore, filesStore }) => {
const {
selection: selectionItem,
selectionParentRoom,
getIsRooms,
roomsView,
} = auth.infoPanelStore;
const { infoPanelSelection, roomsView } = auth.infoPanelStore;
const isShowParentRoom =
getIsRooms() &&
roomsView === "info_members" &&
!selectionItem.isRoom &&
!!selectionParentRoom;
const selection =
selectionItem.length > 1
? null
: isShowParentRoom
? selectionParentRoom
: selectionItem;
const selection = infoPanelSelection.length > 1 ? null : infoPanelSelection;
const isArchive = selection?.rootFolderType === FolderType.Archive;
return {
selection,
roomsView,
selectionParentRoom: auth.infoPanelStore.selectionParentRoom,
infoPanelSelection: auth.infoPanelStore.infoPanelSelection,
setIsMobileHidden: auth.infoPanelStore.setIsMobileHidden,
isGracePeriod: auth.currentTariffStatusStore.isGracePeriod,
@ -137,11 +127,12 @@ export default inject(
isPublicRoomType:
(selectedFolderStore.roomType ??
auth.infoPanelStore.selectionParentRoom?.roomType) ===
auth.infoPanelStore.infoPanelSelection?.roomType) ===
RoomsType.PublicRoom,
setSelected: filesStore.setSelected,
setBufferSelection: filesStore.setBufferSelection,
isArchive,
};
}
)(

View File

@ -5,7 +5,7 @@ import GalleryItemTitle from "./GalleryItemTitle";
import RoomsItemHeader from "./Rooms";
const ItemTitle = ({
selection,
infoPanelSelection,
gallerySelected,
isNoItem,
isAccounts,
@ -16,13 +16,13 @@ const ItemTitle = ({
getIcon,
getUserContextOptions,
}) => {
if (!selection) return null;
if (!infoPanelSelection) return null;
if (isNoItem) return null;
if (isAccounts)
return (
<AccountsItemTitle
selection={selection}
infoPanelSelection={infoPanelSelection}
isSeveralItems={isSeveralItems}
getUserContextOptions={getUserContextOptions}
selectionLength={selectionLength}

View File

@ -11,27 +11,29 @@ import { ComboBox } from "@docspace/shared/components/combobox";
import { getUserStatus } from "SRC_DIR/helpers/people-helpers";
import { StyledAccountContent } from "../../styles/accounts";
const Accounts = ({
t,
selection,
isOwner,
isAdmin,
changeUserType,
canChangeUserType,
setSelection,
getPeopleListItem,
}) => {
const Accounts = (props) => {
const {
t,
infoPanelSelection,
isOwner,
isAdmin,
changeUserType,
canChangeUserType,
setInfoPanelSelection,
getPeopleListItem,
} = props;
const [statusLabel, setStatusLabel] = React.useState("");
const [isLoading, setIsLoading] = React.useState(false);
const { role, id, isVisitor, isCollaborator } = selection;
const { role, id, isVisitor, isCollaborator } = infoPanelSelection;
React.useEffect(() => {
getStatusLabel();
}, [selection, getStatusLabel]);
}, [infoPanelSelection, getStatusLabel]);
const getStatusLabel = React.useCallback(() => {
const status = getUserStatus(selection);
const status = getUserStatus(infoPanelSelection);
switch (status) {
case "active":
return setStatusLabel(t("Common:Active"));
@ -42,7 +44,7 @@ const Accounts = ({
default:
return setStatusLabel(t("Common:Active"));
}
}, [selection]);
}, [infoPanelSelection]);
const getUserTypeLabel = React.useCallback((role) => {
switch (role) {
@ -111,9 +113,9 @@ const Accounts = ({
const items = [];
users.map((u) => items.push(getPeopleListItem(u)));
if (items.length === 1) {
setSelection(getPeopleListItem(items[0]));
setInfoPanelSelection(getPeopleListItem(items[0]));
} else {
setSelection(items);
setInfoPanelSelection(items);
}
}
setIsLoading(false);
@ -122,11 +124,11 @@ const Accounts = ({
const onTypeChange = React.useCallback(
({ action }) => {
setIsLoading(true);
if (!changeUserType(action, [selection], onSuccess, onAbort)) {
if (!changeUserType(action, [infoPanelSelection], onSuccess, onAbort)) {
setIsLoading(false);
}
},
[selection, changeUserType, t]
[infoPanelSelection, changeUserType, t]
);
const typeLabel = getUserTypeLabel(role);
@ -165,9 +167,12 @@ const Accounts = ({
</Text>
);
const status = getUserStatus(selection);
const status = getUserStatus(infoPanelSelection);
const canChange = canChangeUserType({ ...selection, statusType: status });
const canChange = canChangeUserType({
...infoPanelSelection,
statusType: status,
});
return canChange ? combobox : text;
};
@ -230,7 +235,7 @@ export default inject(({ auth, peopleStore, accessRightsStore }) => {
const { changeType: changeUserType, usersStore } = peopleStore;
const { canChangeUserType } = accessRightsStore;
const { setSelection } = auth.infoPanelStore;
const { setInfoPanelSelection } = auth.infoPanelStore;
return {
isOwner,
@ -240,7 +245,7 @@ export default inject(({ auth, peopleStore, accessRightsStore }) => {
canChangeUserType,
loading: usersStore.operationRunning,
getPeopleListItem: usersStore.getPeopleListItem,
setSelection,
setInfoPanelSelection,
};
})(
withTranslation([

View File

@ -3,7 +3,7 @@ import { useNavigate } from "react-router-dom";
import { inject } from "mobx-react";
import { withTranslation } from "react-i18next";
import { FileType } from "@docspace/shared/enums";
import { FileType, FolderType } from "@docspace/shared/enums";
import { Text } from "@docspace/shared/components/text";
import DetailsHelper from "../../helpers/DetailsHelper.js";
@ -21,6 +21,7 @@ const Details = ({
isVisitor,
isCollaborator,
selectTag,
isArchive,
}) => {
const [itemProperties, setItemProperties] = useState([]);
@ -61,7 +62,7 @@ const Details = ({
}, [selection, createThumbnailAction]);
const currentIcon =
!selection.isArchive && selection?.logo?.large
!isArchive && selection?.logo?.large
? selection?.logo?.large
: getInfoPanelItemIcon(selection, 96);
@ -93,7 +94,7 @@ const Details = ({
<RoomIcon
color={selection.logo.color}
title={selection.title}
isArchive={selection.isArchive}
isArchive={isArchive}
size="96px"
radius="16px"
/>
@ -101,7 +102,7 @@ const Details = ({
<img
className={`no-thumbnail-img ${selection.isRoom && "is-room"} ${
selection.isRoom &&
!selection.isArchive &&
!isArchive &&
selection.logo?.large &&
"custom-logo"
}`}
@ -138,7 +139,8 @@ const Details = ({
export default inject(({ auth, filesStore, filesActionsStore }) => {
const { userStore } = auth;
const { selection, getInfoPanelItemIcon, openUser } = auth.infoPanelStore;
const { infoPanelSelection, getInfoPanelItemIcon, openUser } =
auth.infoPanelStore;
const { createThumbnail } = filesStore;
const { personal, culture } = auth.settingsStore;
const { user } = userStore;
@ -148,15 +150,18 @@ export default inject(({ auth, filesStore, filesActionsStore }) => {
const isVisitor = user.isVisitor;
const isCollaborator = user.isCollaborator;
const isArchive = infoPanelSelection?.rootFolderType === FolderType.Archive;
return {
personal,
culture,
selection,
selection: infoPanelSelection,
createThumbnail,
getInfoPanelItemIcon,
openUser,
isVisitor,
isCollaborator,
selectTag,
isArchive,
};
})(withTranslation(["InfoPanel", "Common", "Translations", "Files"])(Details));

View File

@ -13,11 +13,10 @@ import { decode } from "he";
const HistoryBlock = ({
t,
selection,
selectionIsFile,
feed,
selectedFolder,
selectionParentRoom,
infoPanelSelection,
getInfoPanelItemIcon,
checkAndOpenLocationAction,
openUser,
@ -72,9 +71,8 @@ const HistoryBlock = ({
className="message"
action={json}
groupedActions={groupedFeeds}
selection={selection}
selectedFolder={selectedFolder}
selectionParentRoom={selectionParentRoom}
infoPanelSelection={infoPanelSelection}
/>
{isItemAction && withFileList && (

View File

@ -10,9 +10,8 @@ const HistoryBlockMessage = ({
t,
action,
groupedActions,
selection,
selectedFolder,
selectionParentRoom,
infoPanelSelection,
}) => {
const message = getBlockMessageTranslation(
t,
@ -31,7 +30,7 @@ const HistoryBlockMessage = ({
const itemLocationId = +action.ExtraLocation;
if (selectedFolder?.id === itemLocationId) return "";
if (selection?.isRoom && selectionParentRoom?.id === itemLocationId)
if (infoPanelSelection?.isRoom && infoPanelSelection?.id === itemLocationId)
return "";
const folderTitle = action.ExtraLocationTitle;

View File

@ -11,12 +11,11 @@ import NoHistory from "../NoItem/NoHistory";
const History = ({
t,
selection,
historyWithFileList,
selectedFolder,
selectionHistory,
setSelectionHistory,
selectionParentRoom,
infoPanelSelection,
getInfoPanelItemIcon,
getHistory,
checkAndOpenLocationAction,
@ -32,14 +31,15 @@ const History = ({
const [isLoading, setIsLoading] = useState(false);
const fetchHistory = async (item) => {
if (!item?.id) return;
if (isLoading) {
abortControllerRef.current?.abort();
abortControllerRef.current = new AbortController();
} else setIsLoading(true);
let module = "files";
if (selection.isRoom) module = "rooms";
else if (selection.isFolder) module = "folders";
if (infoPanelSelection.isRoom) module = "rooms";
else if (infoPanelSelection.isFolder) module = "folders";
getHistory(
module,
@ -64,8 +64,8 @@ const History = ({
useEffect(() => {
if (!isMount.current) return;
fetchHistory(selection);
}, [selection.id]);
fetchHistory(infoPanelSelection);
}, [infoPanelSelection.id]);
useEffect(() => {
return () => {
@ -86,9 +86,8 @@ const History = ({
key={feed.json.Id}
t={t}
feed={feed}
selection={selection}
selectedFolder={selectedFolder}
selectionParentRoom={selectionParentRoom}
infoPanelSelection={infoPanelSelection}
getInfoPanelItemIcon={getInfoPanelItemIcon}
checkAndOpenLocationAction={checkAndOpenLocationAction}
openUser={openUser}
@ -106,11 +105,10 @@ const History = ({
export default inject(({ auth, filesStore, filesActionsStore }) => {
const { userStore } = auth;
const {
selection,
infoPanelSelection,
selectionHistory,
setSelectionHistory,
historyWithFileList,
selectionParentRoom,
getInfoPanelItemIcon,
openUser,
} = auth.infoPanelStore;
@ -126,11 +124,10 @@ export default inject(({ auth, filesStore, filesActionsStore }) => {
return {
personal,
culture,
selection,
selectionHistory,
setSelectionHistory,
historyWithFileList,
selectionParentRoom,
infoPanelSelection,
getInfoPanelItemIcon,
getHistory,
checkAndOpenLocationAction,

View File

@ -1,4 +1,5 @@
import React, { useState } from "react";
import { useState } from "react";
import { inject, observer } from "mobx-react";
import AtReactSvgUrl from "PUBLIC_DIR/images/@.react.svg?url";
import { StyledUser } from "../../styles/members";
import { Avatar } from "@docspace/shared/components/avatar";
@ -17,62 +18,69 @@ import { IconButton } from "@docspace/shared/components/icon-button";
const User = ({
t,
user,
setMembers,
isExpect,
membersHelper,
currentMember,
updateRoomMemberRole,
selectionParentRoom,
setSelectionParentRoom,
infoPanelSelection,
changeUserType,
setIsScrollLocked,
isTitle,
onRepeatInvitation,
showInviteIcon,
membersFilter,
setMembersFilter,
fetchMembers,
hasNextPage,
infoPanelMembers,
setInfoPanelMembers,
}) => {
if (!selectionParentRoom) return null;
if (!infoPanelSelection) return null;
if (!user.displayName && !user.email) return null;
//const [userIsRemoved, setUserIsRemoved] = useState(false);
const [isLoading, setIsLoading] = useState(false);
//if (userIsRemoved) return null;
const security = infoPanelSelection ? infoPanelSelection.security : {};
const isExpect = user.isExpect;
const canInviteUserInRoomAbility = security?.EditAccess;
const showInviteIcon = canInviteUserInRoomAbility && isExpect;
const canChangeUserRole = user.canEditAccess;
const [isLoading, setIsLoading] = useState(false);
const fullRoomRoleOptions = membersHelper.getOptionsByRoomType(
selectionParentRoom.roomType,
infoPanelSelection.roomType,
canChangeUserRole
);
const userRole = membersHelper.getOptionByUserAccess(user.access, user);
const userRoleOptions = filterUserRoleOptions(fullRoomRoleOptions, user);
const onRepeatInvitation = async () => {
resendEmailInvitations(infoPanelSelection.id, true)
.then(() =>
toastr.success(t("PeopleTranslations:SuccessSentMultipleInvitatios"))
)
.catch((err) => toastr.error(err));
};
const updateRole = (option) => {
return updateRoomMemberRole(selectionParentRoom.id, {
return updateRoomMemberRole(infoPanelSelection.id, {
invitations: [{ id: user.id, access: option.access }],
notify: false,
sharingMessage: "",
})
.then(async () => {
setIsLoading(false);
const users = selectionParentRoom.members.users;
const administrators = selectionParentRoom.members.administrators;
const expectedMembers = selectionParentRoom.members.expected;
if (option.key === "remove") {
const newMembersFilter = JSON.parse(JSON.stringify(membersFilter));
const newMembers = {
users: users?.filter((m) => m.id !== user.id),
administrators: administrators?.filter((m) => m.id !== user.id),
expected: expectedMembers?.filter((m) => m.id !== user.id),
users: infoPanelMembers.users?.filter((m) => m.id !== user.id),
administrators: infoPanelMembers.administrators?.filter(
(m) => m.id !== user.id
),
expected: infoPanelMembers.expected?.filter(
(m) => m.id !== user.id
),
};
const roomId = selectionParentRoom.id;
const roomId = infoPanelSelection.id;
const newUsers = newMembers.users.length > 1 ? newMembers?.users : [];
const newAdministrators =
newMembers.administrators.length > 1
@ -81,7 +89,7 @@ const User = ({
const newExpected =
newMembers.expected.length > 1 ? newMembers?.expected : [];
setMembers({
setInfoPanelMembers({
roomId,
users: newUsers,
administrators: newAdministrators,
@ -90,25 +98,12 @@ const User = ({
newMembersFilter.total -= 1;
setSelectionParentRoom({
...selectionParentRoom,
members: {
users: newUsers,
administrators: newAdministrators,
expected: newExpected,
},
});
if (hasNextPage) {
newMembersFilter.startIndex =
(newMembersFilter.page + 1) * newMembersFilter.pageCount - 1;
newMembersFilter.pageCount = 1;
const fetchedMembers = await fetchMembers(
selectionParentRoom.id,
false,
newMembersFilter
);
const fetchedMembers = await fetchMembers(t, false);
const newMembers = {
administrators: [
@ -119,48 +114,26 @@ const User = ({
expected: [...newExpected, ...fetchedMembers.expected],
};
setMembers({
roomId: selectionParentRoom.id,
setInfoPanelMembers({
roomId: infoPanelSelection.id,
...newMembers,
});
setSelectionParentRoom({
...selectionParentRoom,
members: newMembers,
});
}
setMembersFilter(newMembersFilter);
//setUserIsRemoved(true);
} else {
setMembers({
roomId: selectionParentRoom.id,
users: users?.map((m) =>
setInfoPanelMembers({
roomId: infoPanelSelection.id,
users: infoPanelMembers.users?.map((m) =>
m.id === user.id ? { ...m, access: option.access } : m
),
administrators: administrators?.map((m) =>
administrators: infoPanelMembers.administrators?.map((m) =>
m.id === user.id ? { ...m, access: option.access } : m
),
expected: expectedMembers?.map((m) =>
expected: infoPanelMembers.expected?.map((m) =>
m.id === user.id ? { ...m, access: option.access } : m
),
});
setSelectionParentRoom({
...selectionParentRoom,
members: {
users: users?.map((m) =>
m.id === user.id ? { ...m, access: option.access } : m
),
administrators: administrators?.map((m) =>
m.id === user.id ? { ...m, access: option.access } : m
),
expected: expectedMembers?.map((m) =>
m.id === user.id ? { ...m, access: option.access } : m
),
},
});
}
})
.catch((err) => {
@ -203,7 +176,7 @@ const User = ({
};
const onToggle = (e, isOpen) => {
setIsScrollLocked(isOpen);
// setIsScrollLocked(isOpen);
};
const userAvatar = user.hasAvatar ? user.avatar : DefaultUserPhotoUrl;
@ -216,7 +189,7 @@ const User = ({
user.isOwner ? t("Common:DocSpaceOwner") : t("Common:DocSpaceAdmin")
}. ${t("Common:HasFullAccess")}`;
return isTitle ? (
return user.isTitle ? (
<StyledUserTypeHeader isExpect={isExpect}>
<Text className="title">{user.displayName}</Text>
@ -282,4 +255,33 @@ const User = ({
);
};
export default User;
export default inject(({ auth, filesStore, peopleStore }) => {
const {
infoPanelSelection,
setIsScrollLocked,
infoPanelMembers,
setInfoPanelMembers,
fetchMembers,
} = auth.infoPanelStore;
const {
updateRoomMemberRole,
resendEmailInvitations,
membersFilter,
setMembersFilter,
} = filesStore;
const { changeType: changeUserType } = peopleStore;
return {
infoPanelSelection,
setIsScrollLocked,
updateRoomMemberRole,
resendEmailInvitations,
changeUserType,
membersFilter,
setMembersFilter,
infoPanelMembers,
setInfoPanelMembers,
fetchMembers,
};
})(observer(User));

View File

@ -1,13 +1,9 @@
import React, { useState, useEffect, useCallback } from "react";
import { useEffect } from "react";
import { inject, observer } from "mobx-react";
import { withTranslation } from "react-i18next";
import { toastr } from "@docspace/shared/components/toast";
import {
EmployeeActivationStatus,
RoomsType,
ShareAccessRights,
} from "@docspace/shared/enums";
import { RoomsType, ShareAccessRights } from "@docspace/shared/enums";
import { LINKS_LIMIT_COUNT } from "@docspace/shared/constants";
import Loaders from "@docspace/common/components/Loaders";
import MembersHelper from "../../helpers/MembersHelper";
@ -30,214 +26,60 @@ import LinkRow from "./sub-components/LinkRow";
const Members = ({
t,
selfId,
selection,
updateRoomMembers,
setUpdateRoomMembers,
selectionParentRoom,
setSelectionParentRoom,
infoPanelSelection,
setIsScrollLocked,
getRoomMembers,
getRoomLinks,
updateRoomMemberRole,
setView,
roomsView,
resendEmailInvitations,
changeUserType,
isPublicRoomType,
setExternalLinks,
membersFilter,
setMembersFilter,
externalLinks,
members,
setMembersList,
roomType,
infoPanelMembers,
setInfoPanelMembers,
primaryLink,
isArchiveFolder,
isPublicRoom,
additionalLinks,
setLinkParams,
setEditLinkPanelIsVisible,
getPrimaryLink,
setExternalLink,
withPublicRoomBlock,
fetchMembers,
membersIsLoading,
}) => {
const [isLoading, setIsLoading] = useState(false);
const membersHelper = new MembersHelper({ t });
const security = selectionParentRoom ? selectionParentRoom.security : {};
const fetchMembers = async (roomId, clearFilter = true) => {
if (isLoading) return;
const isPublic = selection?.roomType ?? selectionParentRoom?.roomType;
const requests = [getRoomMembers(roomId, clearFilter)];
if (isPublic && clearFilter && withPublicRoomBlock) {
requests.push(getRoomLinks(roomId));
}
let timerId;
if (clearFilter) timerId = setTimeout(() => setIsLoading(true), 300);
const [data, links] = await Promise.all(requests);
clearFilter && setIsLoading(false);
clearTimeout(timerId);
links && setExternalLinks(links);
const users = [];
const administrators = [];
const expectedMembers = [];
data?.map((fetchedMember) => {
const member = {
access: fetchedMember.access,
canEditAccess: fetchedMember.canEditAccess,
...fetchedMember.sharedTo,
};
if (member.activationStatus === EmployeeActivationStatus.Pending) {
member.isExpect = true;
expectedMembers.push(member);
} else if (
member.access === ShareAccessRights.FullAccess ||
member.access === ShareAccessRights.RoomManager
) {
administrators.push(member);
} else {
users.push(member);
}
});
let hasPrevAdminsTitle =
members?.roomId === roomId && !clearFilter
? getHasPrevTitle(members?.administrators, "administration")
: false;
if (administrators.length && !hasPrevAdminsTitle) {
administrators.unshift({
id: "administration",
displayName: t("Administration"),
isTitle: true,
});
}
let hasPrevUsersTitle =
members?.roomId === roomId && !clearFilter
? getHasPrevTitle(members?.users, "user")
: false;
if (users.length && !hasPrevUsersTitle) {
users.unshift({ id: "user", displayName: t("Users"), isTitle: true });
}
let hasPrevExpectedTitle =
members?.roomId === roomId && !clearFilter
? getHasPrevTitle(members?.expected, "expected")
: false;
if (expectedMembers.length && !hasPrevExpectedTitle) {
expectedMembers.unshift({
id: "expected",
displayName: t("ExpectUsers"),
isTitle: true,
isExpect: true,
});
}
setUpdateRoomMembers(false);
return {
users,
administrators,
expected: expectedMembers,
roomId,
};
const updateInfoPanelMembers = async () => {
if (!infoPanelSelection) return;
const fetchedMembers = await fetchMembers(t);
setInfoPanelMembers(fetchedMembers);
};
const getHasPrevTitle = (array, type) => {
return array.findIndex((x) => x.id === type) > -1;
};
const updateSelectionParentRoomActionSelection = useCallback(async () => {
if (!selection?.isRoom || selection.id === members?.roomId) return;
const fetchedMembers = await fetchMembers(selection.id);
setMembersList(fetchedMembers);
setSelectionParentRoom({
...selection,
members: fetchedMembers,
});
if (roomsView === "info_members" && !selection?.security?.Read)
setView("info_details");
}, [selection]);
useEffect(() => {
updateSelectionParentRoomActionSelection();
}, [selection, updateSelectionParentRoomActionSelection]);
const updateMembersAction = useCallback(async () => {
if (!updateRoomMembers) return;
const fetchedMembers = await fetchMembers(selection.id);
setSelectionParentRoom({
...selectionParentRoom,
members: fetchedMembers,
});
setMembersList(fetchedMembers);
}, [selectionParentRoom, selection?.id, updateRoomMembers]);
useEffect(() => {
updateMembersAction();
}, [
selectionParentRoom,
selection?.id,
updateRoomMembers,
updateMembersAction,
]);
const onRepeatInvitation = async () => {
resendEmailInvitations(selectionParentRoom.id, true)
.then(() =>
toastr.success(t("PeopleTranslations:SuccessSentMultipleInvitatios"))
)
.catch((err) => toastr.error(err));
};
updateInfoPanelMembers();
}, [infoPanelSelection]);
const loadNextPage = async () => {
const roomId = selectionParentRoom.id;
const fetchedMembers = await fetchMembers(roomId, false);
const roomId = infoPanelSelection.id;
const fetchedMembers = await fetchMembers(t, false);
const { users, administrators, expected } = fetchedMembers;
const newMembers = {
roomId: roomId,
administrators: [...members.administrators, ...administrators],
users: [...members.users, ...users],
expected: [...members.expected, ...expected],
administrators: [...infoPanelMembers.administrators, ...administrators],
users: [...infoPanelMembers.users, ...users],
expected: [...infoPanelMembers.expected, ...expected],
};
setMembersList(newMembers);
setSelectionParentRoom({
...selectionParentRoom,
members: newMembers,
});
setInfoPanelMembers(newMembers);
};
if (isLoading) return <Loaders.InfoPanelViewLoader view="members" />;
else if (!members) return <></>;
if (membersIsLoading) return <Loaders.InfoPanelViewLoader view="members" />;
else if (!infoPanelMembers) return <></>;
const [currentMember] = members.administrators.filter(
const [currentMember] = infoPanelMembers.administrators.filter(
(member) => member.id === selfId
);
const { administrators, users, expected } = members;
const { administrators, users, expected } = infoPanelMembers;
const membersList = [...administrators, ...users, ...expected];
const adminsTitleCount = administrators.length ? 1 : 0;
@ -245,18 +87,13 @@ const Members = ({
const expectedTitleCount = expected.length ? 1 : 0;
const headersCount = adminsTitleCount + usersTitleCount + expectedTitleCount;
const dataReadyMembersList = selection?.id === selectionParentRoom?.id;
if (!dataReadyMembersList) return <></>;
const canInviteUserInRoomAbility = security?.EditAccess;
const onAddNewLink = async () => {
if (isPublicRoom || primaryLink) {
setLinkParams({ isEdit: false });
setEditLinkPanelIsVisible(true);
} else {
getPrimaryLink(selectionParentRoom.id).then((link) => {
getPrimaryLink(infoPanelSelection.id).then((link) => {
setExternalLink(link);
copy(link.sharedTo.shareLink);
toastr.success(t("Files:LinkSuccessfullyCreatedAndCopied"));
@ -402,24 +239,8 @@ const Members = ({
user={user}
key={user.id}
index={index + publicRoomItemsLength}
security={security}
membersHelper={membersHelper}
currentMember={currentMember}
updateRoomMemberRole={updateRoomMemberRole}
roomId={selectionParentRoom.id}
roomType={selectionParentRoom.roomType}
selectionParentRoom={selectionParentRoom}
setSelectionParentRoom={setSelectionParentRoom}
changeUserType={changeUserType}
setIsScrollLocked={setIsScrollLocked}
isTitle={user.isTitle}
isExpect={user.isExpect}
showInviteIcon={canInviteUserInRoomAbility && user.isExpect}
onRepeatInvitation={onRepeatInvitation}
setMembers={setMembersList}
membersFilter={membersFilter}
setMembersFilter={setMembersFilter}
fetchMembers={fetchMembers}
hasNextPage={
membersList.length - headersCount < membersFilter.total
}
@ -435,115 +256,50 @@ export default inject(
({
auth,
filesStore,
peopleStore,
selectedFolderStore,
publicRoomStore,
treeFoldersStore,
dialogsStore,
}) => {
const {
selectionParentRoom,
setSelectionParentRoom,
setView,
roomsView,
updateRoomMembers,
setUpdateRoomMembers,
infoPanelSelection,
setIsScrollLocked,
membersList,
setMembersList,
selection: selectionItem,
getIsRooms,
infoPanelMembers,
setInfoPanelMembers,
fetchMembers,
membersIsLoading,
withPublicRoomBlock,
} = auth.infoPanelStore;
const {
getRoomMembers,
getRoomLinks,
updateRoomMemberRole,
resendEmailInvitations,
membersFilter,
setMembersFilter,
selection,
bufferSelection,
} = filesStore;
const { membersFilter } = filesStore;
const { id: selfId } = auth.userStore.user;
const { changeType: changeUserType } = peopleStore;
const {
roomLinks,
setExternalLinks,
primaryLink,
additionalLinks,
setExternalLink,
} = publicRoomStore;
const { primaryLink, additionalLinks, setExternalLink } = publicRoomStore;
const { isArchiveFolderRoot } = treeFoldersStore;
const { setLinkParams, setEditLinkPanelIsVisible } = dialogsStore;
const roomType =
selectedFolderStore.roomType ?? selectionParentRoom?.roomType;
selectedFolderStore.roomType ?? infoPanelSelection?.roomType;
const isPublicRoomType =
roomType === RoomsType.PublicRoom || roomType === RoomsType.CustomRoom;
const isPublicRoom = roomType === RoomsType.PublicRoom;
const room = selectionParentRoom
? selectionParentRoom
: selection.length
? selection[0]
: bufferSelection
? bufferSelection
: null;
const withPublicRoomBlock =
room?.access === ShareAccessRights.RoomManager ||
room?.access === ShareAccessRights.None;
const isShowParentRoom =
getIsRooms() &&
roomsView === "info_members" &&
!selectionItem?.isRoom &&
!!selectionParentRoom;
const infoSelection =
selectionItem?.length > 1
? null
: isShowParentRoom
? selectionParentRoom
: selectionItem;
infoPanelSelection?.length > 1 ? null : infoPanelSelection;
return {
setView,
roomsView,
selection: infoSelection,
selectionParentRoom,
setSelectionParentRoom,
infoPanelSelection: infoSelection,
setIsScrollLocked,
getRoomMembers,
getRoomLinks,
updateRoomMemberRole,
updateRoomMembers,
setUpdateRoomMembers,
selfId,
resendEmailInvitations,
changeUserType,
isPublicRoomType,
setExternalLinks,
membersFilter,
setMembersFilter,
externalLinks: roomLinks,
members: membersList,
setMembersList,
infoPanelMembers,
setInfoPanelMembers,
roomType,
primaryLink,
isArchiveFolder: isArchiveFolderRoot,
isPublicRoom,
additionalLinks: additionalLinks,
isArchiveFolder: isArchiveFolderRoot,
setLinkParams,
@ -552,6 +308,8 @@ export default inject(
getPrimaryLink: filesStore.getPrimaryLink,
setExternalLink,
withPublicRoomBlock,
fetchMembers,
membersIsLoading,
};
}
)(

View File

@ -259,7 +259,7 @@ const LinkRow = (props) => {
export default inject(
({ auth, dialogsStore, publicRoomStore, treeFoldersStore }) => {
const { selectionParentRoom } = auth.infoPanelStore;
const { infoPanelSelection } = auth.infoPanelStore;
const { theme } = auth.settingsStore;
const {
@ -274,14 +274,14 @@ export default inject(
return {
setLinkParams,
editExternalLink,
roomId: selectionParentRoom.id,
roomId: infoPanelSelection.id,
setExternalLink,
setEditLinkPanelIsVisible,
setDeleteLinkDialogVisible,
setEmbeddingPanelIsVisible,
isArchiveFolder: isArchiveFolderRoot,
theme,
isPublicRoomType: selectionParentRoom.roomType === RoomsType.PublicRoom,
isPublicRoomType: infoPanelSelection.roomType === RoomsType.PublicRoom,
};
}
)(

View File

@ -2,7 +2,8 @@ import React, { useState, useCallback, useEffect, useRef, memo } from "react";
import styled, { useTheme } from "styled-components";
import { FixedSizeList as List, areEqual } from "react-window";
import InfiniteLoader from "react-window-infinite-loader";
import Loaders from "@docspace/common/components/Loaders";
import { RowLoader } from "@docspace/shared/skeletons/selector";
import { CustomScrollbarsVirtualList } from "@docspace/shared/components/scrollbar";
import { isMobile } from "@docspace/shared/utils";
import { Text } from "@docspace/shared/components/text";
@ -31,11 +32,7 @@ const Item = memo(({ data, index, style }) => {
if (!item) {
return (
<div style={{ ...style, width: "calc(100% - 20px)", margin: "0 -16px" }}>
<Loaders.SelectorRowLoader
isMultiSelect={false}
isContainer={true}
isUser={true}
/>
<RowLoader isMultiSelect={false} isContainer={true} isUser={true} />
</div>
);
}

View File

@ -1,21 +1,15 @@
import InfoPanelRoomEmptyScreenSvgUrl from "PUBLIC_DIR/images/empty_screen_corporate.svg?url";
import InfoPanelRoomEmptyScreenDarkSvgUrl from "PUBLIC_DIR/images/empty_screen_corporate_dark.svg?url";
import React, { useEffect } from "react";
import { inject, observer } from "mobx-react";
import { Text } from "@docspace/shared/components/text";
import { StyledNoItemContainer } from "../../styles/noItem";
const NoRoomItem = ({ t, theme, setMembersList }) => {
const NoRoomItem = ({ t, theme }) => {
const imageSrc = theme.isBase
? InfoPanelRoomEmptyScreenSvgUrl
: InfoPanelRoomEmptyScreenDarkSvgUrl;
useEffect(() => {
setMembersList(null);
}, []);
return (
<StyledNoItemContainer className="info-panel_gallery-empty-screen">
<div className="no-thumbnail-img-wrapper">
@ -31,6 +25,5 @@ const NoRoomItem = ({ t, theme, setMembersList }) => {
export default inject(({ auth }) => {
return {
theme: auth.settingsStore.theme,
setMembersList: auth.infoPanelStore.setMembersList,
};
})(observer(NoRoomItem));

View File

@ -40,7 +40,7 @@ const SeveralItems = ({ isAccounts, theme, selectedItems }) => {
};
export default inject(({ auth }) => {
const selectedItems = auth.infoPanelStore.getSelectedItems();
const selectedItems = auth.infoPanelStore.infoPanelSelectedItems;
return {
theme: auth.settingsStore.theme,

View File

@ -21,7 +21,7 @@ const Share = (props) => {
const {
isRooms,
setView,
selection,
infoPanelSelection,
getPrimaryFileLink,
getFileLinks,
editFileLink,
@ -35,14 +35,14 @@ const Share = (props) => {
const [isLoading, setIsLoading] = useState(true);
const [loadingLinks, setLoadingLinks] = useState([]);
const hideSharePanel = isRooms || !selection?.canShare;
const hideSharePanel = isRooms || !infoPanelSelection?.canShare;
useEffect(() => {
if (hideSharePanel) {
setView("info_details");
}
fetchLinks();
}, [selection]);
}, [infoPanelSelection]);
useEffect(() => {
fetchLinks();
@ -50,7 +50,7 @@ const Share = (props) => {
}, [shareChanged]);
const fetchLinks = async () => {
const res = await getFileLinks(selection.id);
const res = await getFileLinks(infoPanelSelection.id);
const primaryLink = res.items.filter(
(item) => item.sharedTo.primary === true
);
@ -65,7 +65,7 @@ const Share = (props) => {
const addGeneralLink = async () => {
addLoaderLink(true);
const link = await getPrimaryFileLink(selection.id);
const link = await getPrimaryFileLink(infoPanelSelection.id);
setPrimaryFileLink([link]);
copy(link.sharedTo.shareLink);
toastr.success(t("SharingPanel:GeneralAccessLinkCopied"));
@ -74,7 +74,7 @@ const Share = (props) => {
const addAdditionalLinks = async () => {
addLoaderLink(false);
const newLink = await addFileLink(
selection.id,
infoPanelSelection.id,
ShareAccessRights.ReadOnly,
false,
false
@ -96,7 +96,7 @@ const Share = (props) => {
setLoadingLinks([...loadingLinks, link.sharedTo.id]);
const res = await editFileLink(
selection.id,
infoPanelSelection.id,
link.sharedTo.id,
link.access,
link.sharedTo.primary,
@ -117,7 +117,7 @@ const Share = (props) => {
setLoadingLinks([...loadingLinks, link.sharedTo.id]);
const res = await editFileLink(
selection.id,
infoPanelSelection.id,
link.sharedTo.id,
item.access,
link.sharedTo.primary,
@ -150,7 +150,7 @@ const Share = (props) => {
setLoadingLinks([...loadingLinks, link.sharedTo.id]);
const res = await editFileLink(
selection.id,
infoPanelSelection.id,
link.sharedTo.id,
link.access,
link.sharedTo.primary,
@ -218,7 +218,9 @@ const Share = (props) => {
changeShareOption={changeShareOption}
changeAccessOption={changeAccessOption}
changeExpirationOption={changeExpirationOption}
availableExternalRights={selection.availableExternalRights}
availableExternalRights={
infoPanelSelection.availableExternalRights
}
loadingLinks={loadingLinks}
/>
</StyledLinks>
@ -242,7 +244,9 @@ const Share = (props) => {
changeShareOption={changeShareOption}
changeAccessOption={changeAccessOption}
changeExpirationOption={changeExpirationOption}
availableExternalRights={selection.availableExternalRights}
availableExternalRights={
infoPanelSelection.availableExternalRights
}
loadingLinks={loadingLinks}
/>
</StyledLinks>

View File

@ -43,12 +43,12 @@ const InfoPanelHeaderContent = (props) => {
const isAccounts = getIsAccounts();
const isTrash = getIsTrash();
const isNoItem =
selection?.isSelectedFolder && selection?.id === selection?.rootFolderId;
const isRoot =
selection?.isFolder && selection?.id === selection?.rootFolderId;
const isSeveralItems = selection && Array.isArray(selection);
const withSubmenu =
!isNoItem && !isSeveralItems && !isGallery && !isAccounts && !isTrash;
!isRoot && !isSeveralItems && !isGallery && !isAccounts && !isTrash;
useEffect(() => {
checkWidth();
@ -94,9 +94,6 @@ const InfoPanelHeaderContent = (props) => {
content: null,
},
];
// const selectionRoomRights = selectionParentRoom
// ? selectionParentRoom.security?.Read
// : selection?.security?.Read;
const roomsSubmenu = [...submenuData];
@ -211,7 +208,7 @@ export default inject(({ auth, treeFoldersStore, pluginStore }) => {
const { infoPanelItemsList } = pluginStore;
const {
selection,
infoPanelSelection,
setIsVisible,
roomsView,
fileView,
@ -222,7 +219,6 @@ export default inject(({ auth, treeFoldersStore, pluginStore }) => {
getIsAccounts,
getIsTrash,
resetView,
//selectionParentRoom,
} = auth.infoPanelStore;
const { myRoomsId, archiveRoomsId } = treeFoldersStore;
@ -230,7 +226,7 @@ export default inject(({ auth, treeFoldersStore, pluginStore }) => {
const { enablePlugins } = auth.settingsStore;
return {
selection,
selection: infoPanelSelection,
setIsVisible,
roomsView,
fileView,
@ -247,10 +243,6 @@ export default inject(({ auth, treeFoldersStore, pluginStore }) => {
archiveRoomsId,
enablePlugins,
// rootFolderType,
//selectionParentRoom,
};
})(
withTranslation(["Common", "InfoPanel"])(

View File

@ -5,6 +5,8 @@ import { useNavigate, useLocation } from "react-router-dom";
import queryString from "query-string";
import MediaViewer from "@docspace/common/components/MediaViewer";
import { PluginFileType } from "SRC_DIR/helpers/plugins/constants";
import { MEDIA_VIEW_URL } from "@docspace/shared/constants";
import { combineUrl } from "@docspace/shared/utils/combineUrl";
const FilesMediaViewer = (props) => {
const {
@ -106,7 +108,8 @@ const FilesMediaViewer = (props) => {
};
const onChangeUrl = (id) => {
const url = "/products/files/#preview/" + id;
const url = combineUrl(MEDIA_VIEW_URL, id);
setCurrentId(id);
navigate(url);
};

View File

@ -242,8 +242,6 @@ class FilesTableHeader extends React.Component {
!splitColumns ||
isFrame;
const tableColumns = columns.map((c) => c.enable && c.key);
if (isFrame && frameTableColumns) {
const frameTableArray = frameTableColumns.split(",");
@ -253,6 +251,8 @@ class FilesTableHeader extends React.Component {
});
}
const tableColumns = columns.map((c) => c.enable && c.key);
this.setTableColumns(tableColumns);
if (fromUpdate) {
this.setState({

View File

@ -1202,7 +1202,7 @@ const SectionFilterContent = ({
isHeader: true,
isLast: isLastTypeOptionsRooms,
},
...Object.values(RoomsTypeValues).map((roomType) => {
...RoomsTypeValues.map((roomType) => {
switch (roomType) {
case RoomsType.FillingFormsRoom:
return {

View File

@ -930,6 +930,7 @@ const SectionHeaderContent = (props) => {
: "",
};
setSelected("none");
setIsLoading(true);
window.DocSpace.navigate(`${path}?${filter.toUrlParams()}`, { state });

View File

@ -1,5 +1,5 @@
import React, { useEffect } from "react";
import Article from "@docspace/common/components/Article";
import Article from "@docspace/shared/components/article";
import { ArticleHeaderContent, ArticleBodyContent } from "./Article";
import { SectionHeaderContent, SectionPagingContent } from "./Section";
import { inject, observer } from "mobx-react";
@ -11,10 +11,11 @@ import SectionWrapper from "SRC_DIR/components/Section";
import { useParams } from "react-router-dom";
import HistoryHeader from "../categories/developer-tools/Webhooks/WebhookHistory/sub-components/HistoryHeader";
import DetailsNavigationHeader from "../categories/developer-tools/Webhooks/WebhookEventDetails/sub-components/DetailsNavigationHeader";
import ArticleWrapper from "SRC_DIR/components/ArticleWrapper";
const ArticleSettings = React.memo(({ showArticleLoader }) => {
return (
<Article showArticleLoader={showArticleLoader}>
<ArticleWrapper showArticleLoader={showArticleLoader}>
<Article.Header>
<ArticleHeaderContent />
</Article.Header>
@ -22,7 +23,7 @@ const ArticleSettings = React.memo(({ showArticleLoader }) => {
<Article.Body>
<ArticleBodyContent />
</Article.Body>
</Article>
</ArticleWrapper>
);
});

View File

@ -14,8 +14,6 @@ import { setDocumentTitle } from "SRC_DIR/helpers/utils";
import { DropDownItem } from "@docspace/shared/components/drop-down-item";
import { DropDown } from "@docspace/shared/components/drop-down";
import HexColorPickerComponent from "./sub-components/hexColorPicker";
import Loader from "./sub-components/loaderAppearance";
import { StyledComponent, StyledTheme } from "./Appearance/StyledApperance.js";
@ -25,6 +23,8 @@ import hexToRgba from "hex-to-rgba";
import { isMobile } from "@docspace/shared/utils";
import { DeviceType } from "@docspace/shared/enums";
import { ColorPicker } from "@docspace/shared/components/color-picker";
const Appearance = (props) => {
const {
appearanceTheme,
@ -594,11 +594,13 @@ const Appearance = (props) => {
clickOutsideAction={onCloseHexColorPickerButtons}
>
<DropDownItem className="drop-down-item-hex">
<HexColorPickerComponent
<ColorPicker
id="buttons-hex"
onCloseHexColorPicker={onCloseHexColorPickerButtons}
onAppliedColor={onAppliedColorButtons}
onClose={onCloseHexColorPickerButtons}
onApply={onAppliedColorButtons}
appliedColor={appliedColorButtons}
applyButtonLabel={t("Common:ApplyButton")}
cancelButtonLabel={t("Common:CancelButton")}
/>
</DropDownItem>
</DropDown>
@ -614,11 +616,13 @@ const Appearance = (props) => {
clickOutsideAction={onCloseHexColorPickerAccent}
>
<DropDownItem className="drop-down-item-hex">
<HexColorPickerComponent
<ColorPicker
id="accent-hex"
onCloseHexColorPicker={onCloseHexColorPickerAccent}
onAppliedColor={onAppliedColorAccent}
onClose={onCloseHexColorPickerAccent}
onApply={onAppliedColorAccent}
appliedColor={appliedColorAccent}
applyButtonLabel={t("Common:ApplyButton")}
cancelButtonLabel={t("Common:CancelButton")}
/>
</DropDownItem>
</DropDown>

View File

@ -29,7 +29,12 @@ const AuditContent = ({ sectionWidth, item, isSettingNotPaid, locale }) => {
isSettingNotPaid={isSettingNotPaid}
>
<div className="user-container-wrapper">
<Text fontWeight={600} fontSize="14px" isTextOverflow={true}>
<Text
fontWeight={600}
fontSize="14px"
isTextOverflow={true}
className="settings_unavailable"
>
{item.user}
</Text>
</div>

View File

@ -25,9 +25,7 @@ const AuditTrail = (props) => {
useEffect(() => {
setDocumentTitle(t("AuditTrailNav"));
if (isAuditAvailable) {
getAuditTrail();
}
getAuditTrail();
getLifetimeAuditSettings();
}, []);
@ -73,7 +71,7 @@ const AuditTrail = (props) => {
securityLifetime={securityLifetime}
lifetime={securityLifetime.auditTrailLifeTime}
setLifetimeAuditSettings={setLifetimeAuditSettings}
content={isAuditAvailable && getContent()}
content={getContent()}
downloadReport={t("DownloadReportBtnText")}
downloadReportDescription={t("DownloadReportDescription")}
getReport={getAuditTrailReport}

View File

@ -25,7 +25,12 @@ const HistoryContent = ({ sectionWidth, item, locale }) => {
sectionWidth={sectionWidth}
>
<div className="user-container-wrapper">
<Text fontWeight={600} fontSize="14px" isTextOverflow={true}>
<Text
fontWeight={600}
fontSize="14px"
isTextOverflow={true}
className="settings_unavailable"
>
{item.user}
</Text>
</div>
@ -36,10 +41,16 @@ const HistoryContent = ({ sectionWidth, item, locale }) => {
fontWeight={600}
truncate={true}
color="#A3A9AE"
className="settings_unavailable"
>
{dateStr}
</Text>
<Text fontSize="12px" as="div" fontWeight={600}>
<Text
fontSize="12px"
as="div"
fontWeight={600}
className="settings_unavailable"
>
{item.action}
</Text>
</StyledRowContent>

View File

@ -46,6 +46,7 @@ const PeopleTableRow = (props) => {
fontSize="12px"
fontWeight={600}
truncate
className="settings_unavailable"
>
{item.user}
</Text>
@ -57,6 +58,7 @@ const PeopleTableRow = (props) => {
fontSize="12px"
fontWeight={600}
truncate
className="settings_unavailable"
>
{dateStr}
</Text>
@ -70,6 +72,7 @@ const PeopleTableRow = (props) => {
fontWeight={600}
onClick={onEmailClick}
isTextOverflow
className="settings_unavailable"
>
{item.action}
</Text>

View File

@ -25,9 +25,7 @@ const LoginHistory = (props) => {
useEffect(() => {
setDocumentTitle(t("LoginHistoryTitle"));
if (isAuditAvailable) {
getLoginHistory();
}
getLoginHistory();
getLifetimeAuditSettings();
}, []);
@ -73,7 +71,7 @@ const LoginHistory = (props) => {
lifetime={securityLifetime.loginHistoryLifeTime}
securityLifetime={securityLifetime}
setLifetimeAuditSettings={setLifetimeAuditSettings}
content={isAuditAvailable && getContent()}
content={getContent()}
downloadReport={t("DownloadReportBtnText")}
downloadReportDescription={t("DownloadReportDescription")}
getReport={getLoginHistoryReport}

View File

@ -27,7 +27,7 @@ const Sdk = ({
user,
updateProfileCulture,
getRoomsIcon,
getPrimaryLink,
fetchExternalLinks,
}) => {
useEffect(() => {
window.addEventListener("message", handleMessage, false);
@ -128,9 +128,23 @@ const Sdk = ({
data[0].icon = await getRoomsIcon(data[0].roomType, false, 32);
}
if (data[0].roomType === RoomsType.PublicRoom) {
const { sharedTo } = await getPrimaryLink(data[0].id);
data[0].requestToken = sharedTo?.requestToken;
if (
data[0].roomType === RoomsType.PublicRoom ||
(data[0].roomType === RoomsType.CustomRoom && data[0].shared)
) {
const links = await fetchExternalLinks(data[0].id);
const requestTokens = links.map((link) => {
const { id, title, requestToken } = link.sharedTo;
return {
id,
title,
requestToken,
};
});
data[0].requestTokens = requestTokens;
}
frameCallEvent({ event: "onSelectCallback", data });
@ -193,28 +207,30 @@ const Sdk = ({
return component;
};
export default inject(({ auth, settingsStore, peopleStore, filesStore }) => {
const { login, logout, userStore } = auth;
const { theme, setFrameConfig, frameConfig, getSettings, isLoaded } =
auth.settingsStore;
const { loadCurrentUser, user } = userStore;
const { updateProfileCulture } = peopleStore.targetUserStore;
const { getIcon, getRoomsIcon } = settingsStore;
const { getPrimaryLink } = filesStore;
export default inject(
({ auth, settingsStore, peopleStore, publicRoomStore }) => {
const { login, logout, userStore } = auth;
const { theme, setFrameConfig, frameConfig, getSettings, isLoaded } =
auth.settingsStore;
const { loadCurrentUser, user } = userStore;
const { updateProfileCulture } = peopleStore.targetUserStore;
const { getIcon, getRoomsIcon } = settingsStore;
const { fetchExternalLinks } = publicRoomStore;
return {
theme,
setFrameConfig,
frameConfig,
login,
logout,
getSettings,
loadCurrentUser,
getIcon,
getRoomsIcon,
isLoaded,
updateProfileCulture,
user,
getPrimaryLink,
};
})(observer(Sdk));
return {
theme,
setFrameConfig,
frameConfig,
login,
logout,
getSettings,
loadCurrentUser,
getIcon,
getRoomsIcon,
isLoaded,
updateProfileCulture,
user,
fetchExternalLinks,
};
}
)(observer(Sdk));

View File

@ -18,8 +18,12 @@ import { inject, observer } from "mobx-react";
import { toastr } from "@docspace/shared/components/toast";
import { Encoder } from "@docspace/shared/utils/encoder";
import { Base } from "@docspace/shared/themes";
import { MAX_FILE_COMMENT_LENGTH } from "@docspace/shared/constants";
import {
MAX_FILE_COMMENT_LENGTH,
MEDIA_VIEW_URL,
} from "@docspace/shared/constants";
import moment from "moment-timezone";
import { combineUrl } from "@docspace/shared/utils/combineUrl";
const StyledExternalLinkIcon = styled(ExternalLinkIcon)`
${commonIconsStyles}
@ -110,7 +114,7 @@ const VersionRow = (props) => {
if (MediaView || ImageView) {
return window.open(
"/products/files/#preview/" + info.id,
combineUrl(MEDIA_VIEW_URL, info.id),
window.DocSpaceConfig?.editor?.openOnNewPage ? "_blank" : "_self"
);
}

View File

@ -26,8 +26,8 @@ const Wizard = loadable(() => import("../pages/Wizard"));
const PreparationPortal = loadable(() => import("../pages/PreparationPortal"));
const PortalUnavailable = loadable(() => import("../pages/PortalUnavailable"));
const ErrorUnavailable = loadable(() => import("../pages/Errors/Unavailable"));
const AccessRestricted = loadable(() =>
import("../pages/Errors/AccessRestricted")
const AccessRestricted = loadable(
() => import("../pages/Errors/AccessRestricted")
);
const Error401 = loadable(() => import("client/Error401"));
@ -169,7 +169,7 @@ const ClientRoutes = [
),
},
{
path: "products/files",
path: "media/view/:id",
element: (
<PrivateRoute>
<FilesView />

View File

@ -285,7 +285,7 @@ class ContextOptionsStore {
lockFile = (item, t) => {
const { id, locked } = item;
const { setSelection: setInfoPanelSelection } =
const { setInfoPanelSelection: setInfoPanelSelection } =
this.authStore.infoPanelStore;
this.filesActionsStore
@ -620,10 +620,8 @@ class ContextOptionsStore {
};
onShowInfoPanel = (item, view) => {
const { setSelection, setIsVisible, setView } =
this.authStore.infoPanelStore;
const { setIsVisible, setView } = this.authStore.infoPanelStore;
setSelection(item);
setIsVisible(true);
view && setView(view);
};
@ -1166,6 +1164,8 @@ class ContextOptionsStore {
) === -1;
}
const isArchive = item.rootFolderType === FolderType.Archive;
const optionsModel = [
{
id: "option_select",
@ -1286,9 +1286,7 @@ class ContextOptionsStore {
icon: InvitationLinkReactSvgUrl,
onClick: () => this.onCopyLink(item, t),
disabled:
(isPublicRoomType &&
item.canCopyPublicLink &&
!this.treeFoldersStore.isArchiveFolder) ||
(isPublicRoomType && item.canCopyPublicLink && !isArchive) ||
this.publicRoomStore.isPublicRoom,
},
{
@ -1298,7 +1296,7 @@ class ContextOptionsStore {
icon: TabletLinkReactSvgUrl,
disabled:
this.publicRoomStore.isPublicRoom ||
this.treeFoldersStore.isArchiveFolder ||
isArchive ||
!item.canCopyPublicLink ||
!isPublicRoomType,
onClick: async () => {
@ -1482,9 +1480,7 @@ class ContextOptionsStore {
icon: LeaveRoomSvgUrl,
onClick: this.onLeaveRoom,
disabled:
this.treeFoldersStore.isArchiveFolder ||
!item.inRoom ||
this.publicRoomStore.isPublicRoom,
isArchive || !item.inRoom || this.publicRoomStore.isPublicRoom,
},
{
id: "option_unarchive-room",

View File

@ -131,7 +131,7 @@ class DialogsStore {
visible &&
!this.filesStore.hasSelection &&
!this.filesStore.hasBufferSelection &&
!this.authStore.infoPanelStore.selection
!this.authStore.infoPanelStore.infoPanelSelection
)
return;
@ -160,7 +160,7 @@ class DialogsStore {
visible &&
!this.filesStore.hasSelection &&
!this.filesStore.hasBufferSelection &&
!this.authStore.infoPanelStore.selection
!this.authStore.infoPanelStore.infoPanelSelection
) {
console.log("No files selected");
return;

View File

@ -55,6 +55,7 @@ import {
getCategoryTypeByFolderType,
getCategoryUrl,
} from "SRC_DIR/helpers/utils";
import { MEDIA_VIEW_URL } from "@docspace/shared/constants";
class FilesActionStore {
authStore;
@ -289,8 +290,8 @@ class FilesActionStore {
let selection = newSelection
? newSelection
: this.filesStore.selection.length
? this.filesStore.selection
: [bufferSelection];
? this.filesStore.selection
: [bufferSelection];
selection = selection.filter((item) => item.security.Delete);
@ -996,7 +997,8 @@ class FilesActionStore {
setPinAction = (action, id, t) => {
const { pinRoom, unpinRoom, updateRoomPin, setSelected } = this.filesStore;
const { selection, setSelection } = this.authStore.infoPanelStore;
const { infoPanelSelection, setInfoPanelSelection } =
this.authStore.infoPanelStore;
const items = Array.isArray(id) ? id : [id];
@ -1013,8 +1015,8 @@ class FilesActionStore {
return Promise.all(actions)
.then(() => {
this.updateCurrentFolder(null, items, null, operationId);
if (selection) {
setSelection({ ...selection, pinned: true });
if (infoPanelSelection) {
setInfoPanelSelection({ ...infoPanelSelection, pinned: true });
}
})
.then(() => setSelected("close"))
@ -1035,7 +1037,7 @@ class FilesActionStore {
.then(() => {
this.updateCurrentFolder(null, items, null, operationId);
if (selection) {
setSelection({ ...selection, pinned: false });
setInfoPanelSelection({ ...selection, pinned: false });
}
})
.then(() => setSelected("close"))
@ -1731,9 +1733,10 @@ class FilesActionStore {
onShowInfoPanel = () => {
const { selection } = this.filesStore;
const { setSelection, setIsVisible } = this.authStore.infoPanelStore;
const { setInfoPanelSelection, setIsVisible } =
this.authStore.infoPanelStore;
setSelection([selection]);
setInfoPanelSelection([selection]);
setIsVisible(true);
};
@ -2200,7 +2203,7 @@ class FilesActionStore {
);
setMediaViewerData({ visible: true, id });
const url = "/products/files/#preview/" + id;
const url = combineUrl(MEDIA_VIEW_URL, id);
if (this.publicRoomStore.isPublicRoom) return;
@ -2230,7 +2233,9 @@ class FilesActionStore {
onClickBack = () => {
const { roomType, ...rest } = this.selectedFolderStore;
const { setSelectedNode } = this.treeFoldersStore;
const { clearFiles } = this.filesStore;
const { clearFiles, setBufferSelection } = this.filesStore;
setBufferSelection(null);
const categoryType = getCategoryType(window.DocSpace.location);

View File

@ -11,7 +11,7 @@ import {
ShareAccessRights,
} from "@docspace/shared/enums";
import { RoomsTypeValues } from "@docspace/shared/utils";
import { RoomsTypes } from "@docspace/shared/utils";
import { combineUrl } from "@docspace/shared/utils/combineUrl";
import { updateTempContent } from "@docspace/shared/utils/common";
@ -219,7 +219,7 @@ class FilesStore {
} else if (opt.cmd === "delete") {
this.selectedFolderStore[opt.type + "sCount"]--;
}
this.authStore.infoPanelStore.reloadSelection();
// this.authStore.infoPanelStore.updateInfoPanelSelection();
});
}
@ -1455,9 +1455,12 @@ class FilesStore {
// Clear all selections
this.setSelected("close");
// Restore not processed
tempSelection.length && this.setSelection(tempSelection);
tempBuffer && this.setBufferSelection(tempBuffer);
// TODO: see bug 63479
if (this.selectedFolderStore?.id === folderId) {
// Restore not processed
tempSelection.length && this.setSelection(tempSelection);
tempBuffer && this.setBufferSelection(tempBuffer);
}
}
}
@ -1498,6 +1501,9 @@ class FilesStore {
canCopyPublicLink =
room.access === ShareAccessRights.RoomManager ||
room.access === ShareAccessRights.None;
room.canCopyPublicLink = canCopyPublicLink;
this.authStore.infoPanelStore.setInfoPanelRoom(room);
}
const { mute } = room;
@ -1712,6 +1718,7 @@ class FilesStore {
}
}
this.authStore.infoPanelStore.setInfoPanelRoom(null);
this.selectedFolderStore.setSelectedFolder({
folders: data.folders,
...data.current,
@ -2952,7 +2959,7 @@ class FilesStore {
const url = getCategoryUrl(this.categoryType, id);
if (canOpenPlayer) {
return combineUrl(proxyURL, config.homepage, `${url}/#preview/${id}`);
return combineUrl(proxyURL, config.homepage, url, id);
}
if (isFolder) {
@ -3227,8 +3234,8 @@ class FilesStore {
if (this.folders.length) {
for (const item of this.folders) {
if (item.roomType && RoomsTypeValues[item.roomType]) {
cbMenu.push(`room-${RoomsTypeValues[item.roomType]}`);
if (item.roomType && RoomsTypes[item.roomType]) {
cbMenu.push(`room-${RoomsTypes[item.roomType]}`);
} else {
cbMenu.push(FilterType.FoldersOnly);
}

View File

@ -5,6 +5,8 @@ import {
isVideo,
} from "@docspace/common/components/MediaViewer/helpers";
import { thumbnailStatuses } from "SRC_DIR/helpers/filesConstants";
import { MEDIA_VIEW_URL } from "@docspace/shared/constants";
import { combineUrl } from "@docspace/shared/utils/combineUrl";
const FirstUrlKey = "isFirstUrl";
@ -76,7 +78,7 @@ class MediaViewerDataStore {
changeUrl = (id) => {
if (this.publicRoomStore.isPublicRoom) return;
const url = "/products/files/#preview/" + id;
const url = combineUrl(MEDIA_VIEW_URL, id);
window.DocSpace.navigate(url);
};

View File

@ -75,7 +75,7 @@ class OformsStore {
setGallerySelected = (gallerySelected) => {
this.gallerySelected = gallerySelected;
this.authStore.infoPanelStore.setSelection(gallerySelected);
this.authStore.infoPanelStore.setInfoPanelSelection(gallerySelected);
};
setOformLocales = (oformLocales) => (this.oformLocales = oformLocales);

View File

@ -15,7 +15,7 @@ import { combineUrl } from "@docspace/shared/utils/combineUrl";
import { isMobile } from "react-device-detect";
import { ZendeskAPI } from "@docspace/common/components/Zendesk";
import { ZendeskAPI } from "@docspace/shared/components/zendesk";
import { LIVE_CHAT_LOCAL_STORAGE_KEY } from "@docspace/shared/constants";
import { toastr } from "@docspace/shared/components/toast";
import { isDesktop, isTablet } from "@docspace/shared/utils";

View File

@ -34,6 +34,7 @@ class SelectedFolderStore {
security = null;
type = null;
inRoom = false;
isFolder = true;
constructor(settingsStore) {
makeAutoObservable(this);
@ -70,6 +71,7 @@ class SelectedFolderStore {
rootFolderId: this.rootFolderId,
security: this.security,
inRoom: this.inRoom,
isFolder: this.isFolder,
};
};

View File

@ -36,6 +36,7 @@ class SettingsStore {
keepNewFileName = null;
thumbnails1280x720 = window.DocSpaceConfig?.thumbnails1280x720 || false;
chunkUploadSize = 1024 * 1023; // 1024 * 1023; //~0.999mb
chunkUploadCount = 5;
settingsIsLoaded = false;

View File

@ -31,8 +31,6 @@ import {
getCategoryUrl,
} from "SRC_DIR/helpers/utils";
const UPLOAD_LIMIT_AT_ONCE = 5;
class UploadDataStore {
authStore;
treeFoldersStore;
@ -69,6 +67,7 @@ class UploadDataStore {
uploadedFilesSize = 0;
isParallel = true;
asyncUploadObj = {};
constructor(
authStore,
@ -147,6 +146,7 @@ class UploadDataStore {
this.isUploadingAndConversion = false;
this.isUploading = false;
this.asyncUploadObj = {};
};
removeFileFromList = (id) => {
@ -704,6 +704,7 @@ class UploadDataStore {
this.files = [];
this.filesToConversion = [];
this.uploadedFilesSize = 0;
this.asyncUploadObj = {};
}
let newFiles = this.files;
@ -904,100 +905,90 @@ class UploadDataStore {
}
};
uploadFileChunks = async (
location,
requestsDataArray,
checkChunkUpload = (
t,
res,
fileSize,
index,
indexOfFile,
file,
path,
t
length,
resolve,
reject,
isAsyncUpload = false
) => {
const length = requestsDataArray.length;
for (let index = 0; index < length; index++) {
if (
this.uploaded ||
!this.files.some((f) => f.file === file) ||
this.files[indexOfFile].cancel
) {
return Promise.resolve();
}
if (!res.data.data && res.data.message) {
return reject(res.data.message);
}
const res = await uploadFile(location, requestsDataArray[index]);
const { uploaded, id: fileId, file: fileInfo } = res.data.data;
//console.log(`Uploaded chunk ${index}/${length}`, res);
let uploadedSize, newPercent;
//let isLatestFile = indexOfFile === newFilesLength - 1;
if (!this.isParallel) {
uploadedSize = uploaded
? fileSize
: index * this.settingsStore.chunkUploadSize;
if (!res.data.data && res.data.message) {
return Promise.reject(res.data.message);
}
const { uploaded, id: fileId, file: fileInfo } = res.data.data;
let uploadedSize, newPercent;
if (!this.isParallel) {
uploadedSize = uploaded
? fileSize
: index * this.settingsStore.chunkUploadSize;
newPercent = this.getNewPercent(uploadedSize, indexOfFile);
newPercent = this.getNewPercent(uploadedSize, indexOfFile);
} else {
if (!uploaded) {
uploadedSize =
fileSize <= this.settingsStore.chunkUploadSize
? fileSize
: this.settingsStore.chunkUploadSize;
} else {
if (!uploaded) {
uploadedSize =
fileSize <= this.settingsStore.chunkUploadSize
? fileSize
: this.settingsStore.chunkUploadSize;
} else {
uploadedSize = fileSize - index * this.settingsStore.chunkUploadSize;
}
newPercent = this.getFilesPercent(uploadedSize);
uploadedSize = fileSize - index * this.settingsStore.chunkUploadSize;
}
newPercent = this.getFilesPercent(uploadedSize);
}
const percentCurrentFile = ((index + 1) / length) * 100;
if (isAsyncUpload && !uploaded && newPercent >= 100) {
newPercent = 99;
}
const fileIndex = this.uploadedFilesHistory.findIndex(
(f) => f.uniqueId === this.files[indexOfFile].uniqueId
);
if (fileIndex > -1)
this.uploadedFilesHistory[fileIndex].percent = percentCurrentFile;
const percentCurrentFile = ((index + 1) / length) * 100;
this.primaryProgressDataStore.setPrimaryProgressBarData({
icon: "upload",
percent: newPercent,
visible: true,
loadingFile: {
uniqueId: this.files[indexOfFile].uniqueId,
percent: percentCurrentFile,
},
const fileIndex = this.uploadedFilesHistory.findIndex(
(f) => f.uniqueId === this.files[indexOfFile].uniqueId
);
if (fileIndex > -1)
this.uploadedFilesHistory[fileIndex].percent = percentCurrentFile;
this.primaryProgressDataStore.setPrimaryProgressBarData({
icon: "upload",
percent: newPercent,
visible: true,
loadingFile: {
uniqueId: this.files[indexOfFile].uniqueId,
percent: percentCurrentFile,
},
});
if (uploaded) {
runInAction(() => {
this.files[indexOfFile].action = "uploaded";
this.files[indexOfFile].fileId = fileId;
this.files[indexOfFile].fileInfo = fileInfo;
if (!this.isParallel) this.percent = newPercent;
if (this.isParallel) {
this.currentUploadNumber -= 1;
const nextFileIndex = this.files.findIndex((f) => !f.inAction);
if (nextFileIndex !== -1) {
this.startSessionFunc(nextFileIndex, t);
}
}
});
if (uploaded) {
runInAction(() => {
this.files[indexOfFile].action = "uploaded";
this.files[indexOfFile].fileId = fileId;
this.files[indexOfFile].fileInfo = fileInfo;
if (!this.isParallel) this.percent = newPercent;
if (this.isParallel) {
this.currentUploadNumber -= 1;
const nextFileIndex = this.files.findIndex((f) => !f.inAction);
if (nextFileIndex !== -1) {
this.startSessionFunc(nextFileIndex, t);
}
}
if (fileInfo.version > 2) {
this.filesStore.setHighlightFile({
highlightFileId: fileInfo.id,
isFileHasExst: !fileInfo.fileExst,
});
if (fileInfo.version > 2) {
this.filesStore.setHighlightFile({
highlightFileId: fileInfo.id,
isFileHasExst: !fileInfo.fileExst,
});
}
}
}
@ -1005,7 +996,7 @@ class UploadDataStore {
const currentFile = this.files[indexOfFile];
currentFile.path = path;
if (!currentFile) return Promise.resolve();
if (!currentFile) return resolve();
const { needConvert } = currentFile;
if (needConvert) {
@ -1019,12 +1010,195 @@ class UploadDataStore {
} else {
this.filesToConversion.push(currentFile);
}
return Promise.resolve();
return resolve();
} else {
if (currentFile.action === "uploaded") {
this.refreshFiles(currentFile);
}
return Promise.resolve();
if (!isAsyncUpload || res.status === 201) {
return resolve();
}
}
};
asyncUpload = async (t, chunkData, resolve, reject) => {
const { operationId, file, fileSize, indexOfFile, path, length } =
chunkData;
if (
this.uploaded ||
!this.files.some((f) => f.file === file) ||
this.files[indexOfFile].cancel
) {
return resolve();
}
if (!this.asyncUploadObj[operationId]) {
return reject();
}
const chunkObjIndex = this.asyncUploadObj[
operationId
].chunksArray.findIndex((x) => !x.isActive && !x.isFinalize);
if (chunkObjIndex !== -1) {
this.asyncUploadObj[operationId].chunksArray[
chunkObjIndex
].isActive = true;
try {
const res = await this.asyncUploadObj[operationId].chunksArray[
chunkObjIndex
].onUpload();
this.asyncUploadObj[operationId].chunksArray[
chunkObjIndex
].isFinished = true;
if (!res.data.data && res.data.message) {
delete this.asyncUploadObj[operationId];
return reject(res.data.message);
} else this.asyncUpload(t, chunkData, resolve, reject);
const activeLength = this.asyncUploadObj[operationId]
? this.asyncUploadObj[operationId].chunksArray.filter(
(x) => x.isActive
).length - 1
: 0;
this.checkChunkUpload(
t,
res,
fileSize,
activeLength,
indexOfFile,
path,
length,
resolve,
reject,
true
);
const finalizeChunk = this.asyncUploadObj[
operationId
].chunksArray.findIndex((x) => !x.isFinished && !x.isFinalize);
if (finalizeChunk === -1) {
const finalizeChunkIndex = this.asyncUploadObj[
operationId
].chunksArray.findIndex((x) => x.isFinalize);
if (finalizeChunkIndex > -1) {
const finalizeRes = await this.asyncUploadObj[
operationId
].chunksArray[finalizeChunkIndex].onUpload();
const finalizeIndex =
this.asyncUploadObj[operationId].chunksArray.length - 1;
this.checkChunkUpload(
t,
finalizeRes,
fileSize,
finalizeIndex,
indexOfFile,
path,
length,
resolve,
reject,
true
);
}
}
} catch (error) {
return reject(error);
}
}
};
uploadFileChunks = async (
location,
requestsDataArray,
fileSize,
indexOfFile,
file,
path,
t,
operationId,
toFolderId
) => {
const { chunkUploadCount: asyncChunkUploadCount } = this.settingsStore;
const length = requestsDataArray.length;
const isThirdPartyFolder = typeof toFolderId === "string";
if (!isThirdPartyFolder) {
const chunksArray = [];
for (let index = 0; index < length; index++) {
chunksArray.push({
isActive: false,
isFinished: false,
isFinalize: false,
onUpload: () =>
uploadFile(
location + `&chunkNumber=${index + 1}&upload=true`,
requestsDataArray[index]
),
});
}
chunksArray.push({
isActive: false,
isFinished: false,
isFinalize: true,
onUpload: () => uploadFile(location + "&finalize=true"),
});
if (!this.asyncUploadObj[operationId]) {
this.asyncUploadObj[operationId] = { chunksArray: [] };
this.asyncUploadObj[operationId].chunksArray = chunksArray;
}
const promise = new Promise((resolve, reject) => {
let i =
length <= asyncChunkUploadCount ? length : asyncChunkUploadCount;
while (i !== 0) {
this.asyncUpload(
t,
{ operationId, file, fileSize, indexOfFile, path, length },
resolve,
reject
);
i--;
}
});
await promise;
} else {
for (let index = 0; index < length; index++) {
if (
this.uploaded ||
!this.files.some((f) => f.file === file) ||
this.files[indexOfFile].cancel
) {
return Promise.resolve();
}
const res = await uploadFile(location, requestsDataArray[index]);
const resolve = (res) => Promise.resolve(res);
const reject = (err) => Promise.reject(err);
this.checkChunkUpload(
t,
res,
fileSize,
index,
indexOfFile,
path,
length,
resolve,
reject
);
//console.log(`Uploaded chunk ${index}/${length}`, res);
}
}
};
@ -1048,13 +1222,15 @@ class UploadDataStore {
// console.log("IS PARALLEL");
const notUploadedFiles = this.files.filter((f) => !f.inAction);
const { chunkUploadCount } = this.settingsStore;
const countFiles =
notUploadedFiles.length >= UPLOAD_LIMIT_AT_ONCE
? UPLOAD_LIMIT_AT_ONCE
notUploadedFiles.length >= chunkUploadCount
? chunkUploadCount
: notUploadedFiles.length;
for (let i = 0; i < countFiles; i++) {
if (this.currentUploadNumber <= UPLOAD_LIMIT_AT_ONCE) {
if (this.currentUploadNumber <= chunkUploadCount) {
const fileIndex = this.files.findIndex(
(f) => f.uniqueId === notUploadedFiles[i].uniqueId
);
@ -1082,6 +1258,7 @@ class UploadDataStore {
runInAction(() => {
this.uploaded = true;
this.isParallel = true;
this.asyncUploadObj = {};
});
const uploadedFiles = this.files.filter((x) => x.action === "uploaded");
const totalErrorsCount = sumBy(uploadedFiles, (f) => (f.error ? 1 : 0));
@ -1103,6 +1280,7 @@ class UploadDataStore {
if (!this.uploaded && this.files.length === 0) {
this.uploaded = true;
this.isParallel = true;
this.asyncUploadObj = {};
//setUploadData(uploadData);
return;
}
@ -1145,6 +1323,7 @@ class UploadDataStore {
.then((res) => {
const location = res.data.location;
const path = res.data.path;
const operationId = res.data.id;
const requestsDataArray = [];
@ -1158,37 +1337,56 @@ class UploadDataStore {
chunk++;
}
return { location, requestsDataArray, fileSize, path };
})
.then(({ location, requestsDataArray, fileSize, path }) => {
const fileIndex = this.uploadedFilesHistory.findIndex(
(f) => f.uniqueId === this.files[indexOfFile].uniqueId
);
if (fileIndex > -1)
this.uploadedFilesHistory[fileIndex].percent = chunks < 2 ? 50 : 0;
if (!this.isParallel) {
this.primaryProgressDataStore.setPrimaryProgressBarData({
icon: "upload",
visible: true,
percent: this.percent,
loadingFile: {
uniqueId: this.files[indexOfFile].uniqueId,
percent: chunks < 2 ? 50 : 0,
},
});
}
return this.uploadFileChunks(
return {
location,
requestsDataArray,
fileSize,
indexOfFile,
file,
path,
t
);
operationId,
toFolderId,
};
})
.then(
({
location,
requestsDataArray,
fileSize,
path,
t,
operationId,
toFolderId,
}) => {
const fileIndex = this.uploadedFilesHistory.findIndex(
(f) => f.uniqueId === this.files[indexOfFile].uniqueId
);
if (fileIndex > -1)
this.uploadedFilesHistory[fileIndex].percent = chunks < 2 ? 50 : 0;
if (!this.isParallel) {
this.primaryProgressDataStore.setPrimaryProgressBarData({
icon: "upload",
visible: true,
percent: this.percent,
loadingFile: {
uniqueId: this.files[indexOfFile].uniqueId,
percent: chunks < 2 ? 50 : 0,
},
});
}
return this.uploadFileChunks(
location,
requestsDataArray,
fileSize,
indexOfFile,
file,
path,
t,
operationId,
toFolderId
);
}
)
.catch((error) => {
if (this.files[indexOfFile] === undefined) {
this.primaryProgressDataStore.setPrimaryProgressBarData({
@ -1254,6 +1452,7 @@ class UploadDataStore {
runInAction(() => {
this.uploaded = true;
this.isParallel = true;
this.asyncUploadObj = {};
});
const uploadedFiles = this.files.filter(
(x) => x.action === "uploaded"
@ -1287,6 +1486,7 @@ class UploadDataStore {
this.isParallel = true;
this.converted = true;
this.uploadedFilesSize = 0;
this.asyncUploadObj = {};
for (let item of this.tempFiles) {
const { uploadFiles, folderId, t } = item;
@ -1314,6 +1514,7 @@ class UploadDataStore {
this.isParallel = true;
this.converted = true;
this.uploadedFilesSize = 0;
this.asyncUploadObj = {};
const uploadData = {
filesSize: 0,

View File

@ -136,7 +136,8 @@ class UsersStore {
throw new Error(e);
}
await this.getUsersList(filter, true);
// await this.getUsersList(filter, true); // accounts loader
await this.getUsersList(filter); // rooms
if (users && !this.needResetUserSelection) {
this.peopleStore.selectionStore.updateSelection(this.peopleList);

View File

@ -185,6 +185,7 @@ authStore.infoPanelStore.filesStore = filesStore;
authStore.infoPanelStore.peopleStore = peopleStore;
authStore.infoPanelStore.selectedFolderStore = selectedFolderStore;
authStore.infoPanelStore.treeFoldersStore = treeFoldersStore;
authStore.infoPanelStore.publicRoomStore = publicRoomStore;
const createEditRoomStore = new CreateEditRoomStore(
filesStore,

View File

@ -1,31 +0,0 @@
import styled, { css } from "styled-components";
const StyledAlertComponent = styled.div`
width: 100%;
position: relative;
border: ${(props) => `1px solid ${props.borderColor}`};
border-radius: 6px;
padding: 12px;
${(props) => !!props.onClick && "cursor:pointer"};
display: grid;
grid-template-columns: ${(props) =>
props.needArrowIcon ? "1fr 16px" : "1fr"};
.main-content {
display: flex;
flex-direction: column;
align-items: start;
justify-content: center;
gap: 4px;
}
.alert-component_title {
color: ${(props) => props.titleColor};
}
.alert-component_icons {
margin: auto 0;
}
`;
export { StyledAlertComponent };

View File

@ -1,122 +0,0 @@
import React from "react";
import { inject, observer } from "mobx-react";
import styled, { css } from "styled-components";
import { Text } from "@docspace/shared/components/text";
import { commonIconsStyles } from "@docspace/shared/utils";
import ArrowRightIcon from "PUBLIC_DIR/images/arrow.right.react.svg";
import CrossReactSvg from "PUBLIC_DIR/images/cross.react.svg";
import Loaders from "../Loaders";
import { StyledAlertComponent } from "./StyledComponent";
import { Link } from "@docspace/shared/components/link";
const StyledArrowRightIcon = styled(ArrowRightIcon)`
margin: auto 0;
${({ theme }) =>
theme.interfaceDirection === "rtl" && "transform: scaleX(-1);"}
path {
fill: ${(props) => props.theme.alertComponent.iconColor};
}
`;
const StyledCrossIcon = styled(CrossReactSvg)`
position: absolute;
${({ theme }) =>
theme.interfaceDirection === "rtl"
? css`
left: 0px;
margin-left: 8px;
`
: css`
right: 0px;
margin-right: 8px;
`}
margin-top: 8px;
cursor: pointer;
${commonIconsStyles}
path {
fill: ${(props) => props.color};
}
`;
const AlertComponent = (props) => {
const {
id,
description,
title,
titleFontSize,
additionalDescription,
needArrowIcon = false,
needCloseIcon = false,
link,
onLinkClick,
linkColor,
linkTitle,
onAlertClick,
onCloseClick,
titleColor,
borderColor,
theme,
} = props;
return (
<StyledAlertComponent
theme={theme}
titleColor={titleColor}
borderColor={borderColor}
onClick={onAlertClick}
needArrowIcon={needArrowIcon}
id={id}
>
<div className="main-content">
<Text
className="alert-component_title"
fontSize={titleFontSize ?? "12px"}
fontWeight={600}
>
{title}
</Text>
{additionalDescription && (
<Text fontWeight={600}>{additionalDescription}</Text>
)}
<Text
noSelect
fontSize="12px"
color={theme.alertComponent.descriptionColor}
>
{description}
</Text>
{(link || onLinkClick) && (
<Link
type="page"
href={link}
onClick={onLinkClick}
noHover
color={linkColor}
>
{linkTitle}
</Link>
)}
</div>
{needCloseIcon && (
<StyledCrossIcon size="extraSmall" onClick={onCloseClick} />
)}
{needArrowIcon && (
<StyledArrowRightIcon className="alert-component_arrow" />
)}
</StyledAlertComponent>
);
};
export default inject(({ auth }) => {
const { settingsStore } = auth;
const { theme } = settingsStore;
return {
theme,
};
})(observer(AlertComponent));

View File

@ -1,20 +0,0 @@
import React, { useEffect } from "react";
import { Provider as MobxProvider } from "mobx-react";
import store from "client/store";
import Article from "./";
const { auth: authStore } = store;
const ArticleWrapper = (props) => {
useEffect(() => {
authStore.init();
}, []);
return (
<MobxProvider {...store}>
<Article {...props} />
</MobxProvider>
);
};
export default ArticleWrapper;

View File

@ -1,367 +0,0 @@
import React from "react";
import { inject, observer } from "mobx-react";
import PropTypes from "prop-types";
import { isMobile, isMobileOnly, isIOS } from "react-device-detect";
import SubArticleBackdrop from "./sub-components/article-backdrop";
import SubArticleHeader from "./sub-components/article-header";
import SubArticleMainButton from "./sub-components/article-main-button";
import SubArticleBody from "./sub-components/article-body";
import ArticleProfile from "./sub-components/article-profile";
import ArticleAlerts from "./sub-components/article-alerts";
import ArticleLiveChat from "./sub-components/article-live-chat";
import ArticleApps from "./sub-components/article-apps";
import ArticleDevToolsBar from "./sub-components/article-dev-tools-bar";
import { StyledArticle } from "./styled-article";
import HideArticleMenuButton from "./sub-components/article-hide-menu-button";
import { Portal } from "@docspace/shared/components/portal";
import { DeviceType } from "@docspace/shared/enums";
import ArticleProfileLoader from "../Loaders/ArticleProfileLoader/ArticleProfileLoader";
const Article = ({
showText,
setShowText,
articleOpen,
toggleShowText,
toggleArticleOpen,
setIsMobileArticle,
children,
withMainButton,
hideProfileBlock,
hideAppsBlock,
currentColorScheme,
setArticleOpen,
withSendAgain,
mainBarVisible,
isBannerVisible,
isLiveChatAvailable,
onLogoClickAction,
theme,
currentDeviceType,
showArticleLoader,
isAdmin,
withCustomArticleHeader,
hideAlerts,
...rest
}) => {
const [articleHeaderContent, setArticleHeaderContent] = React.useState(null);
const [articleMainButtonContent, setArticleMainButtonContent] =
React.useState(null);
const [articleBodyContent, setArticleBodyContent] = React.useState(null);
const [correctTabletHeight, setCorrectTabletHeight] = React.useState(null);
const [isVirtualKeyboardOpen, setIsVirtualKeyboardOpen] =
React.useState(false);
const updateSizeRef = React.useRef(null);
React.useEffect(() => {
window.addEventListener("popstate", onMobileBack);
return () => window.removeEventListener("popstate", onMobileBack);
}, [onMobileBack]);
React.useEffect(() => {
const showArticle = JSON.parse(localStorage.getItem("showArticle"));
if (currentDeviceType === DeviceType.mobile) {
setShowText(true);
setIsMobileArticle(true);
return;
}
if (currentDeviceType === DeviceType.tablet) {
setIsMobileArticle(true);
if (showArticle) return;
setShowText(false);
return;
}
setShowText(true);
setIsMobileArticle(false);
}, [setShowText, setIsMobileArticle, currentDeviceType]);
React.useEffect(() => {
React.Children.forEach(children, (child) => {
const childType =
child && child.type && (child.type.displayName || child.type.name);
switch (childType) {
case Article.Header.displayName:
setArticleHeaderContent(child);
break;
case Article.MainButton.displayName:
setArticleMainButtonContent(child);
break;
case Article.Body.displayName:
setArticleBodyContent(child);
break;
default:
break;
}
});
}, [children]);
const onMobileBack = React.useCallback(() => {
//close article
if (currentDeviceType !== DeviceType.mobile) return;
setArticleOpen(false);
}, [setArticleOpen, currentDeviceType]);
// TODO: make some better
const onResize = React.useCallback(
(e) => {
let correctTabletHeight = window.innerHeight;
if (mainBarVisible) {
const mainBar = document.getElementById("main-bar");
if (!mainBar.offsetHeight)
return (updateSizeRef.current = setTimeout(() => onResize(), 0));
correctTabletHeight -= mainBar.offsetHeight;
}
const isTouchDevice =
"ontouchstart" in window ||
navigator.maxTouchPoints > 0 ||
navigator.msMaxTouchPoints > 0;
const path = window.location.pathname.toLowerCase();
if (
isBannerVisible &&
isMobile &&
isTouchDevice &&
(path.includes("rooms") || path.includes("files"))
) {
correctTabletHeight -= 80;
if (e?.target?.height) {
const diff = window.innerHeight - e.target.height;
setIsVirtualKeyboardOpen(true);
correctTabletHeight -= diff;
} else {
setIsVirtualKeyboardOpen(false);
}
}
setCorrectTabletHeight(correctTabletHeight);
},
[mainBarVisible, isBannerVisible]
);
React.useEffect(() => {
onResize();
window.addEventListener("resize", onResize);
if (isMobile && !isMobileOnly && isIOS) {
window?.visualViewport?.addEventListener("resize", onResize);
}
return () => {
window.removeEventListener("resize", onResize);
window?.visualViewport?.removeEventListener("resize", onResize);
clearTimeout(updateSizeRef.current);
};
}, [onResize]);
const withDevTools =
!window.location.pathname.includes("portal-settings") &&
!window.location.pathname.includes("management") &&
isAdmin;
const articleComponent = (
<>
<StyledArticle
id={"article-container"}
showText={showText}
articleOpen={articleOpen}
$withMainButton={withMainButton}
correctTabletHeight={correctTabletHeight}
isMobile={currentDeviceType === DeviceType.mobile}
{...rest}
>
<SubArticleHeader
showText={showText}
onLogoClickAction={onLogoClickAction}
currentDeviceType={currentDeviceType}
withCustomArticleHeader={withCustomArticleHeader}
>
{articleHeaderContent ? articleHeaderContent.props.children : null}
</SubArticleHeader>
{articleMainButtonContent &&
withMainButton &&
currentDeviceType !== DeviceType.mobile ? (
<SubArticleMainButton showText={showText}>
{articleMainButtonContent.props.children}
</SubArticleMainButton>
) : null}
<SubArticleBody showText={showText}>
{articleBodyContent ? articleBodyContent.props.children : null}
{!showArticleLoader && (
<>
{!hideAlerts && <ArticleAlerts />}
{withDevTools && (
<ArticleDevToolsBar
articleOpen={articleOpen}
currentDeviceType={currentDeviceType}
toggleArticleOpen={toggleArticleOpen}
showText={showText}
theme={theme}
/>
)}
{!hideAppsBlock && (
<ArticleApps
withDevTools={withDevTools}
showText={showText}
theme={theme}
/>
)}
{!isMobile && isLiveChatAvailable && (
<ArticleLiveChat
currentColorScheme={currentColorScheme}
withMainButton={withMainButton && !!articleMainButtonContent}
/>
)}
</>
)}
</SubArticleBody>
{!showArticleLoader && (
<HideArticleMenuButton
showText={showText}
toggleShowText={toggleShowText}
currentColorScheme={currentColorScheme}
hideProfileBlock={hideProfileBlock}
isVirtualKeyboardOpen={isVirtualKeyboardOpen}
/>
)}
{!hideProfileBlock && currentDeviceType !== DeviceType.mobile && (
<>
{showArticleLoader ? (
<ArticleProfileLoader />
) : (
<ArticleProfile
showText={showText}
currentDeviceType={currentDeviceType}
isVirtualKeyboardOpen={isVirtualKeyboardOpen}
/>
)}
</>
)}
</StyledArticle>
{articleOpen && currentDeviceType === DeviceType.mobile && (
<>
<SubArticleBackdrop onClick={toggleArticleOpen} />
</>
)}
{articleMainButtonContent && currentDeviceType === DeviceType.mobile ? (
<SubArticleMainButton showText={showText}>
{articleMainButtonContent.props.children}
</SubArticleMainButton>
) : null}
</>
);
const renderPortalArticle = () => {
const rootElement = document.getElementById("root");
return (
<Portal
element={articleComponent}
appendTo={rootElement}
visible={true}
/>
);
};
// console.log("Article render", {
// articleMainButton: !!articleMainButtonContent,
// withMainButton,
// });
return currentDeviceType === DeviceType.mobile
? renderPortalArticle()
: articleComponent;
};
Article.propTypes = {
showText: PropTypes.bool,
setShowText: PropTypes.func,
articleOpen: PropTypes.bool,
toggleArticleOpen: PropTypes.func,
setIsMobileArticle: PropTypes.func,
children: PropTypes.any,
hideProfileBlock: PropTypes.bool,
};
Article.Header = () => {
return null;
};
Article.Header.displayName = "Header";
Article.MainButton = () => {
return null;
};
Article.MainButton.displayName = "MainButton";
Article.Body = () => {
return null;
};
Article.Body.displayName = "Body";
export default inject(({ auth }) => {
const { settingsStore, userStore, isLiveChatAvailable, bannerStore } = auth;
const { withSendAgain, user } = userStore;
const { isBannerVisible } = bannerStore;
const isAdmin = user?.isAdmin;
const {
showText,
setShowText,
articleOpen,
setIsMobileArticle,
toggleShowText,
toggleArticleOpen,
currentColorScheme,
setArticleOpen,
mainBarVisible,
theme,
currentDeviceType,
} = settingsStore;
return {
showText,
setShowText,
articleOpen,
setIsMobileArticle,
toggleShowText,
toggleArticleOpen,
currentColorScheme,
setArticleOpen,
withSendAgain,
mainBarVisible,
isBannerVisible,
isLiveChatAvailable,
theme,
currentDeviceType,
isAdmin,
};
})(observer(Article));

View File

@ -1,113 +0,0 @@
import React, { useEffect, useState } from "react";
import { inject, observer } from "mobx-react";
import ArticleTeamTrainingAlert from "./article-team-training";
import ArticleSubmitToFormGalleryAlert from "./article-submit-to-form-gallery";
import ArticlePaymentAlert from "./article-payment-alert";
import ArticleEnterpriseAlert from "./article-enterprise-alert";
import { StyledArticleAlertsComponent } from "../styled-article";
import { ARTICLE_ALERTS } from "@docspace/client/src/helpers/constants";
const ArticleAlerts = ({
articleAlertsData,
incrementIndexOfArticleAlertsData,
showText,
isNonProfit,
isGracePeriod,
isFreeTariff,
isPaymentPageAvailable,
isTeamTrainingAlertAvailable,
isSubmitToGalleryAlertAvailable,
isLicenseExpiring,
isLicenseDateExpired,
isEnterprise,
isTrial,
standalone,
}) => {
const currentAlert = articleAlertsData.current;
const availableAlerts = articleAlertsData.available;
useEffect(() => {
incrementIndexOfArticleAlertsData();
}, []);
const paymentsAlertsComponent = () => {
if (!standalone) {
return (
isPaymentPageAvailable &&
!isNonProfit &&
(isFreeTariff || isGracePeriod) &&
showText && <ArticlePaymentAlert isFreeTariff={isFreeTariff} />
);
}
const isVisibleStandaloneAlert =
isTrial || isLicenseExpiring || isLicenseDateExpired;
return (
isPaymentPageAvailable &&
isEnterprise &&
isVisibleStandaloneAlert &&
showText && <ArticleEnterpriseAlert />
);
};
return (
<StyledArticleAlertsComponent>
{paymentsAlertsComponent()}
{isTeamTrainingAlertAvailable &&
showText &&
availableAlerts.includes(ARTICLE_ALERTS.TeamTraining) &&
currentAlert === ARTICLE_ALERTS.TeamTraining && (
<ArticleTeamTrainingAlert />
)}
{isSubmitToGalleryAlertAvailable &&
showText &&
availableAlerts.includes(ARTICLE_ALERTS.SubmitToFormGallery) &&
currentAlert === ARTICLE_ALERTS.SubmitToFormGallery && (
<ArticleSubmitToFormGalleryAlert />
)}
</StyledArticleAlertsComponent>
);
};
export default inject(({ auth }) => {
const {
currentQuotaStore,
settingsStore,
isPaymentPageAvailable,
isTeamTrainingAlertAvailable,
isSubmitToGalleryAlertAvailable,
currentTariffStatusStore,
isEnterprise,
} = auth;
const { isFreeTariff, isNonProfit, isTrial } = currentQuotaStore;
const { isGracePeriod, isLicenseExpiring, isLicenseDateExpired } =
currentTariffStatusStore;
const {
showText,
standalone,
articleAlertsData,
incrementIndexOfArticleAlertsData,
} = settingsStore;
return {
articleAlertsData,
incrementIndexOfArticleAlertsData,
isEnterprise,
showText,
isNonProfit,
isGracePeriod,
isFreeTariff,
isPaymentPageAvailable,
isTeamTrainingAlertAvailable,
isSubmitToGalleryAlertAvailable,
isLicenseExpiring,
isLicenseDateExpired,
isTrial,
standalone,
};
})(observer(ArticleAlerts));

View File

@ -1,115 +0,0 @@
import WindowsReactSvgUrl from "PUBLIC_DIR/images/windows.react.svg?url";
import MacOSReactSvgUrl from "PUBLIC_DIR/images/macOS.react.svg?url";
import LinuxReactSvgUrl from "PUBLIC_DIR/images/linux.react.svg?url";
import AndroidReactSvgUrl from "PUBLIC_DIR/images/android.react.svg?url";
import IOSReactSvgUrl from "PUBLIC_DIR/images/iOS.react.svg?url";
import React from "react";
import styled, { css } from "styled-components";
import { useTranslation } from "react-i18next";
import { Text } from "@docspace/shared/components/text";
import { IconButton } from "@docspace/shared/components/icon-button";
import { Base } from "@docspace/shared/themes";
import { tablet, mobile } from "@docspace/shared/utils";
const StyledArticleApps = styled.div`
display: flex;
flex-direction: column;
gap: 8px;
position: relative;
margin-top: ${(props) => (props.withDevTools ? "0" : "auto")};
margin-bottom: 16px;
@media ${tablet} {
${(props) =>
props.showText &&
css`
${({ theme }) =>
theme.interfaceDirection === "rtl"
? `margin-right: 8px;`
: `margin-left: 8px;`}
`}
}
@media ${mobile} {
position: relative;
bottom: 0px;
margin-top: ${(props) => (props.withDevTools ? "16px" : "32px")};
}
.download-app-text {
color: ${(props) => props.theme.filesArticleBody.downloadAppList.textColor};
}
.download-app-list {
display: flex;
gap: 8px;
}
`;
StyledArticleApps.defaultProps = { theme: Base };
const ArticleApps = React.memo(({ theme, showText, withDevTools }) => {
const { t } = useTranslation(["Translations"]);
const desktopLink = "https://www.onlyoffice.com/desktop.aspx";
const androidLink = "https://www.onlyoffice.com/office-for-android.aspx";
const iosLink = "https://www.onlyoffice.com/office-for-ios.aspx";
if (!showText) return <></>;
return (
<StyledArticleApps showText={showText} withDevTools={withDevTools}>
<Text className="download-app-text" fontSize="14px" noSelect={true}>
{t("Translations:DownloadApps")}
</Text>
<div className="download-app-list">
<IconButton
onClick={() => window.open(desktopLink)}
iconName={WindowsReactSvgUrl}
size="32"
isFill={true}
hoverColor={theme.filesArticleBody.downloadAppList.winHoverColor}
title={t("Translations:MobileWin")}
/>
<IconButton
onClick={() => window.open(desktopLink)}
iconName={MacOSReactSvgUrl}
size="32"
isFill={true}
hoverColor={theme.filesArticleBody.downloadAppList.macHoverColor}
title={t("Translations:MobileMac")}
/>
<IconButton
onClick={() => window.open(desktopLink)}
iconName={LinuxReactSvgUrl}
size="32"
isFill={true}
hoverColor={theme.filesArticleBody.downloadAppList.linuxHoverColor}
title={t("Translations:MobileLinux")}
/>
<IconButton
onClick={() => window.open(androidLink)}
iconName={AndroidReactSvgUrl}
size="32"
isFill={true}
hoverColor={theme.filesArticleBody.downloadAppList.androidHoverColor}
title={t("Translations:MobileAndroid")}
/>
<IconButton
onClick={() => window.open(iosLink)}
iconName={IOSReactSvgUrl}
size="32"
isFill={true}
hoverColor={theme.filesArticleBody.downloadAppList.iosHoverColor}
title={t("Translations:MobileIos")}
/>
</div>
</StyledArticleApps>
);
});
ArticleApps.defaultProps = { theme: Base };
export default ArticleApps;

View File

@ -1,29 +0,0 @@
import React from "react";
import PropTypes from "prop-types";
import { Backdrop } from "@docspace/shared/components/backdrop";
import { StyledControlContainer, StyledCrossIcon } from "../styled-article";
const ArticleBackdrop = ({ onClick, ...rest }) => {
return (
<>
<StyledControlContainer onClick={onClick} {...rest}>
<StyledCrossIcon />
</StyledControlContainer>
<Backdrop
onClick={onClick}
visible={true}
zIndex={210}
withBackground={true}
/>
</>
);
};
ArticleBackdrop.propTypes = {
showText: PropTypes.bool,
onClick: PropTypes.func,
};
export default React.memo(ArticleBackdrop);

View File

@ -1,86 +0,0 @@
import DeveloperReactSvgUrl from "PUBLIC_DIR/images/catalog.developer.react.svg?url";
import ArrowReactSvgUrl from "PUBLIC_DIR/images/arrow.right.react.svg?url";
import React from "react";
import styled from "styled-components";
import { useTranslation } from "react-i18next";
import { useNavigate } from "react-router-dom";
import { ReactSVG } from "react-svg";
import { Text } from "@docspace/shared/components/text";
import { mobile } from "@docspace/shared/utils";
import { DeviceType } from "@docspace/shared/enums";
const StyledWrapper = styled.div`
cursor: pointer;
position: relative;
margin-top: auto;
margin-bottom: 16px;
padding: 12px 16px;
display: flex;
gap: 8px;
align-items: center;
border: ${(props) => props.theme.filesArticleBody.devTools.border};
border-radius: 6px;
@media ${mobile} {
bottom: 0px;
margin-top: 32px;
}
.icon {
height: 16px;
}
.arrow {
height: 16px;
margin-inline-start: auto;
svg {
${({ theme }) =>
theme.interfaceDirection === "rtl" && "transform: scaleX(-1);"}
}
}
.label {
color: ${(props) => props.theme.filesArticleBody.devTools.color};
}
svg {
path {
fill: ${(props) => props.theme.filesArticleBody.devTools.color};
}
}
`;
const ArticleDevToolsBar = ({
showText,
articleOpen,
currentDeviceType,
toggleArticleOpen,
}) => {
const { t } = useTranslation(["Settings"]);
const navigate = useNavigate();
const onClick = () => {
navigate("/portal-settings/developer-tools");
articleOpen &&
currentDeviceType === DeviceType.mobile &&
toggleArticleOpen();
};
if (!showText) return <></>;
return (
<StyledWrapper onClick={onClick}>
<ReactSVG src={DeveloperReactSvgUrl} className="icon" />
<Text fontWeight={600} fontSize="12px" className="label">
{t("DeveloperTools")}
</Text>
<ReactSVG src={ArrowReactSvgUrl} className="arrow" />
</StyledWrapper>
);
};
export default ArticleDevToolsBar;

View File

@ -1,163 +0,0 @@
import React from "react";
import styled, { css } from "styled-components";
import { Text } from "@docspace/shared/components/text";
import { ReactSVG } from "react-svg";
import { desktop, mobile, tablet } from "@docspace/shared/utils";
import { useTranslation } from "react-i18next";
import Base from "@docspace/shared/themes/base";
import ArticleHideMenuReactSvgUrl from "PUBLIC_DIR/images/article-hide-menu.react.svg?url";
import ArticleShowMenuReactSvgUrl from "PUBLIC_DIR/images/article-show-menu.react.svg?url";
const StyledHideArticleMenuButton = styled.div`
display: flex;
align-items: center;
position: ${(props) => (props.isVirtualKeyboardOpen ? "absolute" : "fixed")};
height: 44px;
z-index: 209;
bottom: ${(props) => (props.hideProfileBlock ? "16px" : "89px")};
${(props) =>
props.theme.interfaceDirection === "rtl"
? css`
right: 0;
`
: css`
left: 0;
`}
cursor: pointer;
-webkit-tap-highlight-color: rgba(0, 0, 0, 0);
min-width: ${({ showText }) => (showText ? "243px" : "60px")};
max-width: ${({ showText }) => (showText ? "243px" : "60px")};
@media ${desktop} {
display: none;
}
@media ${mobile} {
display: none;
}
.article-hide-menu-container {
align-items: center;
${(props) =>
props.theme.interfaceDirection === "rtl"
? css`
margin-right: 16px;
`
: css`
margin-left: 16px;
`}
.article-hide-menu-text {
${(props) =>
props.theme.interfaceDirection === "rtl"
? css`
margin-right: 8px;
`
: css`
margin-left: 8px;
`}
color: ${({ currentColorScheme }) => currentColorScheme?.main?.accent};
}
@media ${tablet} {
display: ${({ showText }) => (showText ? "flex" : "none")};
}
}
.article-show-menu-container {
justify-content: center;
width: 100%;
@media ${tablet} {
display: ${({ showText }) => (showText ? "none" : "flex")};
}
}
.article-hide-menu-icon_svg,
.article-show-menu-icon_svg {
height: 20px;
${(props) =>
props.theme.interfaceDirection === "rtl" &&
css`
transform: scaleX(-1);
`}
}
.article-hide-menu-icon_svg {
${(props) =>
props.theme.interfaceDirection === "rtl" &&
css`
transform: scaleX(-1);
`}
svg {
path {
fill: ${({ currentColorScheme }) => currentColorScheme?.main?.accent};
}
}
}
.article-show-menu-icon_svg {
svg {
path {
fill: ${(props) => props.theme.article.catalogShowText};
}
}
}
`;
StyledHideArticleMenuButton.defaultProps = { theme: Base };
const HideArticleMenuButton = ({
showText,
toggleShowText,
currentColorScheme,
isVirtualKeyboardOpen,
hideProfileBlock,
}) => {
const { t } = useTranslation("Common");
return (
<StyledHideArticleMenuButton
showText={showText}
onClick={toggleShowText}
currentColorScheme={currentColorScheme}
isVirtualKeyboardOpen={isVirtualKeyboardOpen}
hideProfileBlock={hideProfileBlock}
>
{showText ? (
<div
className="article-hide-menu-container"
id="document_catalog-hide-menu"
>
<ReactSVG
className="article-hide-menu-icon_svg"
src={ArticleHideMenuReactSvgUrl}
/>
<Text
className="article-hide-menu-text"
fontWeight={600}
fontSize="12px"
noSelect
truncate
>
{t("Common:HideArticleMenu")}
</Text>
</div>
) : (
<div
className="article-show-menu-container"
id="document_catalog-show-menu"
>
<ReactSVG
className="article-show-menu-icon_svg"
src={ArticleShowMenuReactSvgUrl}
/>
</div>
)}
</StyledHideArticleMenuButton>
);
};
export default HideArticleMenuButton;

View File

@ -1,49 +0,0 @@
import React, { useState } from "react";
import { inject, observer } from "mobx-react";
import { useTranslation } from "react-i18next";
import AlertComponent from "../../AlertComponent";
import { RectangleSkeleton } from "@docspace/shared/skeletons";
import { ARTICLE_ALERTS } from "@docspace/client/src/helpers/constants";
const ArticleTeamTrainingAlert = ({
theme,
bookTrainingEmail,
removeAlertFromArticleAlertsData,
}) => {
const { t, ready } = useTranslation("Common");
const isShowLoader = !ready;
const onClose = () =>
removeAlertFromArticleAlertsData(ARTICLE_ALERTS.TeamTraining);
return isShowLoader ? (
<RectangleSkeleton width="210px" height="88px" />
) : (
<AlertComponent
titleColor={theme.catalog.teamTrainingAlert.titleColor}
linkColor={theme.catalog.teamTrainingAlert.linkColor}
borderColor={theme.catalog.teamTrainingAlert.borderColor}
title={t("Common:UseLikePro")}
description={t("Common:BookTeamTraining")}
link={`mailto:${bookTrainingEmail}`}
linkTitle={t("Common:BookNow")}
onCloseClick={onClose}
needCloseIcon
/>
);
};
export default inject(({ auth }) => {
const { settingsStore } = auth;
const { theme, bookTrainingEmail, removeAlertFromArticleAlertsData } =
settingsStore;
return {
theme,
bookTrainingEmail,
removeAlertFromArticleAlertsData,
};
})(observer(ArticleTeamTrainingAlert));

View File

@ -1,42 +0,0 @@
import React from "react";
import { storiesOf } from "@storybook/react";
import {
withKnobs,
boolean,
text,
color,
number,
} from "@storybook/addon-knobs/react";
import Section from "../../../../.storybook/decorators/section";
import Loaders from "..";
import { LOADER_STYLE } from "@docspace/shared/constants";
import withReadme from "storybook-readme/with-readme";
import Readme from "./README.md";
storiesOf("Components|Loaders", module)
.addDecorator(withKnobs)
.addDecorator(withReadme(Readme))
.add("main button loader", () => (
<Section>
<h1>Main Button Loader</h1>
<Loaders.MainButton
title={text("title", LOADER_STYLE.title)}
width={text("width", "100%")}
height={text("height", "32px")}
borderRadius={text("border radius", "3")}
backgroundColor={color("backgroundColor", LOADER_STYLE.backgroundColor)}
foregroundColor={color("foregroundColor", LOADER_STYLE.foregroundColor)}
backgroundOpacity={number(
"backgroundOpacity",
LOADER_STYLE.backgroundOpacity
)}
foregroundOpacity={number(
"foregroundOpacity",
LOADER_STYLE.foregroundOpacity
)}
speed={number("speed", LOADER_STYLE.speed)}
animate={boolean("animate", LOADER_STYLE.animate)}
/>
</Section>
));

View File

@ -1,28 +0,0 @@
# Main Button Loader
Component that displays main button loader
### Usage
```js
import Loaders from "@docspace/common/components/Loaders";
```
```jsx
<Loaders.ArticleButton />
```
### Properties
| Props | Type | Required | Values | Default | Description |
| ------------------- | :------: | :------: | :----: | :-------: | ------------------------------------------------ |
| `title` | `string` | - | - | `` | It's used to describe what element it is. |
| `width` | `string` | - | - | `100%` | Sets the width |
| `height` | `string` | - | - | `32` | Sets the height |
| `borderRadius` | `string` | - | - | `3` | Sets the corners rounding |
| `backgroundColor` | `string` | - | - | `#000000` | Used as background of animation |
| `foregroundColor` | `string` | - | - | `#000000` | Used as the foreground of animation |
| `backgroundOpacity` | `number` | - | - | 0.2 | Background opacity (0 = transparent, 1 = opaque) |
| `foregroundOpacity` | `number` | - | - | 0.15 | Animation opacity (0 = transparent, 1 = opaque) |
| `speed` | `number` | - | - | 2 | Animation speed in seconds |
| `animate` | `bool` | - | - | true | Opt-out of animations |

View File

@ -1 +0,0 @@
export default from "./ArticleButtonLoader";

View File

@ -1 +0,0 @@
export default from "./ArticleFolderLoader";

View File

@ -1,44 +0,0 @@
import React from "react";
import PropTypes from "prop-types";
import {
StyledContainer,
StyledRectangleLoader,
} from "./StyledArticleGroupsLoader";
import { inject, observer } from "mobx-react";
const ArticleGroupsLoader = ({ id, className, style, showText, ...rest }) => {
return (
<StyledContainer
id={id}
className={className}
style={style}
showText={showText}
>
<StyledRectangleLoader {...rest} />
<StyledRectangleLoader {...rest} />
<StyledRectangleLoader {...rest} />
<StyledRectangleLoader {...rest} />
<StyledRectangleLoader {...rest} />
<StyledRectangleLoader {...rest} />
<StyledRectangleLoader {...rest} />
<StyledRectangleLoader {...rest} />
</StyledContainer>
);
};
ArticleGroupsLoader.propTypes = {
id: PropTypes.string,
className: PropTypes.string,
style: PropTypes.object,
showText: PropTypes.bool,
};
ArticleGroupsLoader.defaultProps = {
id: undefined,
className: undefined,
style: undefined,
};
export default inject(({ auth }) => ({
showText: auth.settingsStore.showText,
}))(observer(ArticleGroupsLoader));

View File

@ -1 +0,0 @@
export default from "./ArticleGroupsLoader";

View File

@ -1,42 +0,0 @@
import React from "react";
import { storiesOf } from "@storybook/react";
import {
withKnobs,
boolean,
text,
color,
number,
} from "@storybook/addon-knobs/react";
import Section from "../../../../.storybook/decorators/section";
import Loaders from "..";
import { LOADER_STYLE } from "@docspace/shared/constants";
import withReadme from "storybook-readme/with-readme";
import Readme from "./README.md";
storiesOf("Components|Loaders", module)
.addDecorator(withKnobs)
.addDecorator(withReadme(Readme))
.add("article header loader", () => (
<Section>
<h1>Article Header Loader</h1>
<Loaders.ArticleHeader
title={text("title", LOADER_STYLE.title)}
width={text("width", "100%")}
height={text("height", "32px")}
borderRadius={text("border radius", "3")}
backgroundColor={color("backgroundColor", LOADER_STYLE.backgroundColor)}
foregroundColor={color("foregroundColor", LOADER_STYLE.foregroundColor)}
backgroundOpacity={number(
"backgroundOpacity",
LOADER_STYLE.backgroundOpacity
)}
foregroundOpacity={number(
"foregroundOpacity",
LOADER_STYLE.foregroundOpacity
)}
speed={number("speed", LOADER_STYLE.speed)}
animate={boolean("animate", LOADER_STYLE.animate)}
/>
</Section>
));

View File

@ -1,28 +0,0 @@
# Article Header Loader
Component that displays article header loader
### Usage
```js
import Loaders from "@docspace/common/components/Loaders";
```
```jsx
<Loaders.ArticleHeader />
```
### Properties
| Props | Type | Required | Values | Default | Description |
| ------------------- | :------: | :------: | :----: | :-------: | ------------------------------------------------ |
| `title` | `string` | - | - | `` | It's used to describe what element it is. |
| `width` | `string` | - | - | `100%` | Sets the width |
| `height` | `string` | - | - | `32` | Sets the height |
| `borderRadius` | `string` | - | - | `3` | Sets the corners rounding |
| `backgroundColor` | `string` | - | - | `#000000` | Used as background of animation |
| `foregroundColor` | `string` | - | - | `#000000` | Used as the foreground of animation |
| `backgroundOpacity` | `number` | - | - | 0.2 | Background opacity (0 = transparent, 1 = opaque) |
| `foregroundOpacity` | `number` | - | - | 0.15 | Animation opacity (0 = transparent, 1 = opaque) |
| `speed` | `number` | - | - | 2 | Animation speed in seconds |
| `animate` | `bool` | - | - | true | Opt-out of animations |

View File

@ -1 +0,0 @@
export default from "./ArticleHeaderLoader";

View File

@ -1,71 +0,0 @@
import React from "react";
import PropTypes from "prop-types";
import { StyledContainer, StyledBlock } from "./StyledArticleProfileLoader";
import { inject, observer } from "mobx-react";
import { RectangleSkeleton } from "@docspace/shared/skeletons";
const ArticleProfileLoader = ({
id,
className,
style,
showText,
isVisitor,
...rest
}) => {
return (
<StyledContainer
id={id}
className={className}
style={style}
showText={showText}
>
<StyledBlock showText={showText}>
{showText ? (
<>
<RectangleSkeleton
width={"40px"}
height={"40px"}
borderRadius={"50%"}
/>
<RectangleSkeleton
width={"131px"}
height={"18px"}
className={"title"}
/>
<RectangleSkeleton
width={"16px"}
height={"16px"}
className={"option-button"}
/>
</>
) : (
<RectangleSkeleton
width={"32px"}
height={"32px"}
borderRadius={"50%"}
/>
)}
</StyledBlock>
</StyledContainer>
);
};
ArticleProfileLoader.propTypes = {
id: PropTypes.string,
className: PropTypes.string,
style: PropTypes.object,
showText: PropTypes.bool,
};
ArticleProfileLoader.defaultProps = {
id: undefined,
className: undefined,
style: undefined,
};
export default inject(({ auth }) => {
return {
showText: auth.settingsStore.showText,
isVisitor: auth.userStore.user.isVisitor,
};
})(observer(ArticleProfileLoader));

View File

@ -1 +0,0 @@
export default from "./ArticleProfileLoader";

View File

@ -1,28 +0,0 @@
import React from "react";
import { storiesOf } from "@storybook/react";
import Section from "../../../.storybook/decorators/section";
import Loaders from ".";
storiesOf("Components|TTT", module)
.addParameters({ options: { showAddonPanel: false } })
.add("all", () => (
<Section>
<h1>Base loader</h1>
<h1>Article Header Loader</h1>
<Loaders.ArticleHeader />
<h1>Filter loader</h1>
<Loaders.Filter />
<h1>Section Header loader</h1>
<Loaders.SectionHeader />
<h1>Tree Folders loader</h1>
<Loaders.TreeFolders />
<h1>Main Button loader</h1>
<Loaders.MainButton />
</Section>
));

View File

@ -1,10 +1,6 @@
import Header from "./HeaderLoader";
import SectionHeader from "./SectionHeaderLoader";
import ArticleHeader from "./ArticleHeaderLoader";
import ArticleButton from "./ArticleButtonLoader";
import ArticleProfileLoader from "./ArticleProfileLoader";
import ArticleFolder from "./ArticleFolderLoader";
import ArticleGroup from "./ArticleGroupsLoader";
import TreeFolders from "./TreeFolderLoader";
import NewTreeFolders from "./NewTreeFolderLoader";
import TreeSettingsLoader from "./TreeSettingsLoader";
@ -52,8 +48,7 @@ import SectionSubmenuLoader from "./SectionSubmenuLoader";
export default {
Header,
SectionHeader,
ArticleHeader,
ArticleProfileLoader,
TreeFolders,
TreeSettingsLoader,
@ -69,9 +64,7 @@ export default {
DialogLoader,
DialogAsideLoader,
ArticleButton,
ArticleFolder,
ArticleGroup,
ListLoader,
NewTreeFolders,
SharingPanelLoader,

View File

@ -1,6 +1,6 @@
{
"name": "@docspace/common",
"version": "2.0.1",
"version": "2.0.2",
"private": true,
"scripts": {
"build": "echo 'skip it'",

View File

@ -4,7 +4,11 @@ import moment from "moment";
import { getUserById } from "@docspace/shared/api/people";
import { getUserRole } from "@docspace/shared/utils/common";
import { combineUrl } from "@docspace/shared/utils/combineUrl";
import { FolderType, ShareAccessRights } from "@docspace/shared/enums";
import {
EmployeeActivationStatus,
FolderType,
ShareAccessRights,
} from "@docspace/shared/enums";
import config from "PACKAGE_FILE";
import Filter from "@docspace/shared/api/people/filter";
import { getRoomInfo } from "@docspace/shared/api/rooms";
@ -14,6 +18,7 @@ import {
editExternalLink,
addExternalLink,
} from "@docspace/shared/api/files";
import isEqual from "lodash/isEqual";
const observedKeys = [
"id",
@ -34,15 +39,13 @@ class InfoPanelStore {
isVisible = false;
isMobileHidden = false;
selection = null;
infoPanelSelection = null;
selectionHistory = null;
selectionParentRoom = null;
selectionHistory = null;
roomsView = infoMembers;
fileView = infoHistory;
updateRoomMembers = null;
isScrollLocked = false;
historyWithFileList = false;
@ -52,7 +55,12 @@ class InfoPanelStore {
filesStore = null;
selectedFolderStore = null;
treeFoldersStore = null;
membersList = null;
publicRoomStore = null;
infoPanelMembers = null;
infoPanelSelection = null;
infoPanelRoom = null;
membersIsLoading = false;
shareChanged = false;
@ -70,23 +78,12 @@ class InfoPanelStore {
setIsMobileHidden = (bool) => (this.isMobileHidden = bool);
setSelection = (selection) => {
if (this.getIsAccounts() && (!selection.email || !selection.displayName)) {
this.selection = selection.length
? selection
: { isSelectedFolder: true };
return;
}
this.selection = selection;
this.isScrollLocked = false;
};
setSelectionParentRoom = (obj) => (this.selectionParentRoom = obj);
setSelectionHistory = (obj) => (this.selectionHistory = obj);
setSelectionHistory = (obj) => {
this.selectionHistory = obj;
this.historyWithFileList = this.selection.isFolder || this.selection.isRoom;
this.historyWithFileList =
this.infoPanelSelection.isFolder || this.infoPanelSelection.isRoom;
};
resetView = () => {
@ -98,12 +95,9 @@ class InfoPanelStore {
this.roomsView = view;
this.fileView = view === infoMembers ? infoHistory : view;
this.isScrollLocked = false;
if (view !== infoMembers) this.setMembersList(null);
};
if (view !== infoMembers) this.setInfoPanelMembers(null);
setUpdateRoomMembers = (updateRoomMembers) => {
this.setMembersList(null);
this.updateRoomMembers = updateRoomMembers;
this.setNewInfoPanelSelection();
};
setIsScrollLocked = (isScrollLocked) => {
@ -112,87 +106,105 @@ class InfoPanelStore {
// Selection helpers //
getSelectedItems = () => {
const {
selection: filesStoreSelection,
bufferSelection: filesStoreBufferSelection,
} = this.filesStore;
get infoPanelSelectedItems() {
const { selection: filesSelection, bufferSelection: filesBufferSelection } =
this.filesStore;
const {
selection: peopleStoreSelection,
bufferSelection: peopleStoreBufferSelection,
selection: peopleSelection,
bufferSelection: peopleBufferSelection,
} = this.peopleStore.selectionStore;
return this.getIsAccounts()
? peopleStoreSelection.length
? [...peopleStoreSelection]
: peopleStoreBufferSelection
? [peopleStoreBufferSelection]
? peopleSelection.length
? [...peopleSelection]
: peopleBufferSelection
? [peopleBufferSelection]
: []
: filesStoreSelection?.length > 0
? [...filesStoreSelection]
: filesStoreBufferSelection
? [filesStoreBufferSelection]
: filesSelection?.length > 0
? [...filesSelection]
: filesBufferSelection
? [filesBufferSelection]
: [];
}
getInfoPanelSelectedFolder = () => {
const isRooms = this.getIsRooms();
return this.roomsView === infoMembers && this.infoPanelRoom && isRooms
? this.infoPanelRoom
: this.selectedFolderStore.getSelectedFolder();
};
getSelectedFolder = () => {
const selectedFolderStore = { ...this.selectedFolderStore };
get infoPanelCurrentSelection() {
const { selection, bufferSelection } = this.filesStore;
return this.infoPanelSelection
? this.infoPanelSelection
: selection.length
? selection[0]
: bufferSelection
? bufferSelection
: null;
}
get withPublicRoomBlock() {
return (
this.infoPanelCurrentSelection?.access ===
ShareAccessRights.RoomManager ||
this.infoPanelCurrentSelection?.access === ShareAccessRights.None
);
}
getViewItem = () => {
const isRooms = this.getIsRooms();
if (
isRooms &&
this.roomsView === infoMembers &&
!this.infoPanelSelectedItems[0]?.isRoom
) {
// if (!this.infoPanelSelection?.id) {
return this.getInfoPanelSelectedFolder();
// }
} else {
return this.infoPanelSelectedItems[0];
}
};
setNewInfoPanelSelection = () => {
const selectedItems = this.infoPanelSelectedItems; //files list
const selectedFolder = this.getInfoPanelSelectedFolder(); // root or current folder
let newInfoPanelSelection = this.infoPanelSelection;
if (!selectedItems.length) {
newInfoPanelSelection = this.normalizeSelection(selectedFolder);
} else if (selectedItems.length === 1) {
newInfoPanelSelection = this.normalizeSelection(
this.getViewItem() ?? newInfoPanelSelection
);
} else {
newInfoPanelSelection = [...Array(selectedItems.length).keys()];
}
this.setInfoPanelSelection(newInfoPanelSelection);
};
normalizeSelection = (infoPanelSelection) => {
return {
...selectedFolderStore,
isFolder: true,
isRoom: !!this.selectedFolderStore.roomType,
};
};
calculateSelection = (
props = { selectedItems: [], selectedFolder: null }
) => {
const selectedItems = props.selectedItems.length
? props.selectedItems
: this.getSelectedItems();
const selectedFolder = props.selectedFolder
? props.selectedFolder
: this.getSelectedFolder();
return selectedItems.length === 0
? this.normalizeSelection({
...selectedFolder,
isSelectedFolder: true,
isSelectedItem: false,
})
: selectedItems.length === 1
? this.normalizeSelection({
...selectedItems[0],
isSelectedFolder: false,
isSelectedItem: true,
})
: [...Array(selectedItems.length).keys()];
};
normalizeSelection = (selection) => {
const isContextMenuSelection = selection.isContextMenuSelection;
return {
...selection,
isRoom: selection.isRoom || !!selection.roomType,
icon: this.getInfoPanelItemIcon(selection, 32),
isContextMenuSelection: false,
wasContextMenuSelection: !!isContextMenuSelection,
...infoPanelSelection,
isRoom: infoPanelSelection.isRoom || !!infoPanelSelection.roomType,
icon: this.getInfoPanelItemIcon(infoPanelSelection, 32),
canCopyPublicLink:
selection.access === ShareAccessRights.RoomManager ||
selection.access === ShareAccessRights.None,
infoPanelSelection.access === ShareAccessRights.RoomManager ||
infoPanelSelection.access === ShareAccessRights.None,
};
};
reloadSelection = () => {
this.setSelection(this.calculateSelection());
};
updateRoomLogoCacheBreaker = () => {
const logo = this.selection.logo;
this.setSelection({
...this.selection,
const logo = this.infoPanelSelection.logo;
this.setInfoPanelSelection({
...this.infoPanelSelection,
logo: {
small: logo.small.split("?")[0] + "?" + new Date().getTime(),
medium: logo.medium.split("?")[0] + "?" + new Date().getTime(),
@ -202,32 +214,35 @@ class InfoPanelStore {
});
};
reloadSelectionParentRoom = async () => {
updateInfoPanelSelection = async (room) => {
if (room) {
this.setInfoPanelSelection(this.normalizeSelection(room));
if (this.infoPanelRoom?.id === room?.id) {
this.setInfoPanelRoom(this.normalizeSelection(room));
}
} else {
this.setNewInfoPanelSelection();
}
if (!this.getIsRooms) return;
const currentFolderRoomId =
this.selectedFolderStore.pathParts &&
this.selectedFolderStore.pathParts[1]?.id;
// const prevRoomId = this.selectionParentRoom?.id;
// if (!currentFolderRoomId || currentFolderRoomId === prevRoomId) return;
if (!currentFolderRoomId) return;
const newSelectionParentRoom = await getRoomInfo(currentFolderRoomId);
// if (prevRoomId === newSelectionParentRoom.id) return;
const newInfoPanelSelection = await getRoomInfo(currentFolderRoomId);
const roomIndex = this.selectedFolderStore.navigationPath.findIndex(
(f) => f.id === currentFolderRoomId
);
if (roomIndex > -1) {
this.selectedFolderStore.navigationPath[roomIndex].title =
newSelectionParentRoom.title;
newInfoPanelSelection.title;
}
this.setSelectionParentRoom(
this.normalizeSelection(newSelectionParentRoom)
);
this.setInfoPanelSelection(this.normalizeSelection(newInfoPanelSelection));
};
isItemChanged = (oldItem, newItem) => {
@ -354,8 +369,159 @@ class InfoPanelStore {
return pathname.indexOf("files/trash") !== -1;
};
setMembersList = (membersList) => {
this.membersList = membersList;
setInfoPanelMembers = (infoPanelMembers) => {
this.infoPanelMembers = infoPanelMembers;
};
setInfoPanelSelection = (infoPanelSelection) => {
if (isEqual(infoPanelSelection, this.infoPanelSelection)) {
return;
}
if (
this.getIsAccounts() &&
(!infoPanelSelection.email || !infoPanelSelection.displayName)
) {
this.infoPanelSelection = infoPanelSelection.length
? infoPanelSelection
: null;
return;
}
this.setInfoPanelMembers(null);
this.infoPanelSelection = infoPanelSelection;
this.isScrollLocked = false;
};
setInfoPanelRoom = (infoPanelRoom) => {
this.infoPanelRoom = infoPanelRoom
? this.normalizeSelection(infoPanelRoom)
: infoPanelRoom;
};
setMembersIsLoading = (membersIsLoading) => {
this.membersIsLoading = membersIsLoading;
};
getHasPrevTitle = (array, type) => {
return this.infoPanelMembers?.roomId === this.infoPanelSelection.id
? array.findIndex((x) => x.id === type) > -1
: false;
};
addMembersTitle = (t, administrators, users, expectedMembers) => {
let hasPrevAdminsTitle = this.getHasPrevTitle(
administrators,
"administration"
);
if (administrators.length && !hasPrevAdminsTitle) {
administrators.unshift({
id: "administration",
displayName: t("Administration"),
isTitle: true,
});
}
let hasPrevUsersTitle = this.getHasPrevTitle(users, "user");
if (users.length && !hasPrevUsersTitle) {
users.unshift({ id: "user", displayName: t("Users"), isTitle: true });
}
let hasPrevExpectedTitle = this.getHasPrevTitle(
expectedMembers,
"expected"
);
if (expectedMembers.length && !hasPrevExpectedTitle) {
expectedMembers.unshift({
id: "expected",
displayName: t("ExpectUsers"),
isTitle: true,
isExpect: true,
});
}
};
convertMembers = (t, members, clearFilter) => {
const users = [];
const administrators = [];
const expectedMembers = [];
members?.map((fetchedMember) => {
const member = {
access: fetchedMember.access,
canEditAccess: fetchedMember.canEditAccess,
...fetchedMember.sharedTo,
};
if (member.activationStatus === EmployeeActivationStatus.Pending) {
member.isExpect = true;
expectedMembers.push(member);
} else if (
member.access === ShareAccessRights.FullAccess ||
member.access === ShareAccessRights.RoomManager
) {
administrators.push(member);
} else {
users.push(member);
}
});
if (clearFilter) {
this.addMembersTitle(t, administrators, users, expectedMembers);
}
return { administrators, users, expectedMembers };
};
fetchMembers = async (t, clearFilter = true) => {
if (this.membersIsLoading) return;
const isPublic =
this.infoPanelSelection?.roomType ?? this.infoPanelSelection?.roomType;
const roomId = this.infoPanelSelection.id;
const requests = [this.filesStore.getRoomMembers(roomId, clearFilter)];
if (isPublic && clearFilter && this.withPublicRoomBlock) {
requests.push(this.filesStore.getRoomLinks(roomId));
}
let timerId;
if (clearFilter)
timerId = setTimeout(() => this.setMembersIsLoading(true), 300);
const [data, links] = await Promise.all(requests);
clearFilter && this.setMembersIsLoading(false);
clearTimeout(timerId);
links && this.publicRoomStore.setExternalLinks(links);
const { administrators, users, expectedMembers } = this.convertMembers(
t,
data,
clearFilter
);
return {
users,
administrators,
expected: expectedMembers,
roomId,
};
};
addInfoPanelMembers = (t, members, clearFilter) => {
const newMembers = this.convertMembers(t, members, clearFilter);
const { roomId, administrators, users, expected } = this.infoPanelMembers;
this.setInfoPanelMembers({
roomId: roomId,
administrators: [...administrators, ...newMembers.administrators],
users: [...users, ...newMembers.users],
expected: [...expected, ...newMembers.expectedMembers],
});
};
openShareTab = () => {

View File

@ -7,9 +7,18 @@ import { frameCallEvent } from "@docspace/shared/utils/common";
import { setCookie } from "@docspace/shared/utils/cookie";
import { combineUrl } from "@docspace/shared/utils/combineUrl";
import FirebaseHelper from "@docspace/shared/utils/firebase";
import { ThemeKeys, TenantStatus, DeviceType } from "@docspace/shared/enums";
import {
ThemeKeys,
TenantStatus,
DeviceType,
ArticleAlerts,
} from "@docspace/shared/enums";
import { LANGUAGE, COOKIE_EXPIRATION_YEAR } from "@docspace/shared/constants";
import {
LANGUAGE,
COOKIE_EXPIRATION_YEAR,
MEDIA_VIEW_URL,
} from "@docspace/shared/constants";
import { version } from "../package.json";
import SocketIOHelper from "@docspace/shared/utils/socket";
import { Dark, Base } from "@docspace/shared/themes";
@ -20,7 +29,6 @@ import {
getCookie,
} from "@docspace/shared/utils";
import { WRONG_PORTAL_NAME_URL } from "@docspace/shared/constants";
import { ARTICLE_ALERTS } from "@docspace/client/src/helpers/constants";
import { toastr } from "@docspace/shared/components/toast";
//import { getFromLocalStorage } from "@docspace/client/src/pages/PortalSettings/utils";
@ -36,7 +44,9 @@ const initArticleAlertsData = () => {
const savedArticleAlertsData = localStorage.getItem("articleAlertsData");
if (savedArticleAlertsData) return JSON.parse(savedArticleAlertsData);
const articleAlertsArray = Object.values(ARTICLE_ALERTS);
const articleAlertsArray = Object.values(ArticleAlerts).filter(
(item, index) => Object.values(ArticleAlerts).indexOf(item) === index
);
const defaultArticleAlertsData = {
current: articleAlertsArray[0],
available: articleAlertsArray,
@ -428,10 +438,7 @@ class SettingsStore {
else newSettings = await api.settings.getSettings(true);
if (window["AscDesktopEditor"] !== undefined || this.personal) {
const dp = combineUrl(
window.DocSpaceConfig?.proxy?.url,
"/products/files/"
);
const dp = combineUrl(window.DocSpaceConfig?.proxy?.url, MEDIA_VIEW_URL);
this.setDefaultPage(dp);
}

View File

@ -111,11 +111,13 @@ class UserStore {
return email;
};
updateUser = (newUser) => {
this.user = { ...this.user, newUser };
};
updateAvatarInfo = (avatar, avatarSmall, avatarMedium, avatarMax) => {
this.user.avatar = avatar;
this.user.avatarSmall = avatarSmall;
this.user.avatarMedium = avatarMedium;
this.user.avatarMax = avatarMax;
this.updateUser({ avatar, avatarSmall, avatarMedium, avatarMax });
};
get withActivationBar() {

View File

@ -1,6 +1,6 @@
{
"name": "@docspace/editor",
"version": "2.0.1",
"version": "2.0.2",
"private": true,
"homepage": "/doceditor",
"scripts": {

Some files were not shown because too many files have changed in this diff Show More