diff --git a/packages/client/public/locales/en/Files.json b/packages/client/public/locales/en/Files.json
index 1597d2ab33..3d8601db58 100644
--- a/packages/client/public/locales/en/Files.json
+++ b/packages/client/public/locales/en/Files.json
@@ -117,6 +117,7 @@
"OpenLocation": "Open location",
"PasswordAccess": "Password access",
"PasswordLink": "Add a password to protect your link.",
+ "PasswordProtectedFiles": "Please <0>enter a password0> for the protected files to continue",
"PasswordSuccessfullyCopied": "Password successfully copied",
"Pin": "Pin",
"PinToTop": "Pin to top",
diff --git a/packages/client/src/HOCs/withFileActions.js b/packages/client/src/HOCs/withFileActions.js
index a6aea017c0..105767bbaa 100644
--- a/packages/client/src/HOCs/withFileActions.js
+++ b/packages/client/src/HOCs/withFileActions.js
@@ -62,21 +62,14 @@ export default function withFileActions(WrappedFileItem) {
};
onDropZoneUpload = (files, uploadToFolder) => {
- const { t, dragging, setDragging, startUpload, uploadEmptyFolders } =
+ const { t, dragging, setDragging, startUpload, createFoldersTree } =
this.props;
dragging && setDragging(false);
- const emptyFolders = files.filter((f) => f.isEmptyDirectory);
-
- if (emptyFolders.length > 0) {
- uploadEmptyFolders(emptyFolders, uploadToFolder).then(() => {
- const onlyFiles = files.filter((f) => !f.isEmptyDirectory);
- if (onlyFiles.length > 0) startUpload(onlyFiles, uploadToFolder, t);
- });
- } else {
- startUpload(files, uploadToFolder, t);
- }
+ createFoldersTree(files, uploadToFolder).then((f) => {
+ if (f.length > 0) startUpload(f, null, t);
+ });
};
onDrop = (items) => {
@@ -371,7 +364,7 @@ export default function withFileActions(WrappedFileItem) {
onSelectItem,
//setNewBadgeCount,
openFileAction,
- uploadEmptyFolders,
+ createFoldersTree,
} = filesActionsStore;
const { setSharingPanelVisible } = dialogsStore;
const {
@@ -475,7 +468,7 @@ export default function withFileActions(WrappedFileItem) {
dragging,
setDragging,
startUpload,
- uploadEmptyFolders,
+ createFoldersTree,
draggable,
setTooltipPosition,
setStartDrag,
diff --git a/packages/client/src/components/Article/Body/Items.js b/packages/client/src/components/Article/Body/Items.js
index f4b212e4fa..e06439b783 100644
--- a/packages/client/src/components/Article/Body/Items.js
+++ b/packages/client/src/components/Article/Body/Items.js
@@ -68,7 +68,7 @@ const Item = ({
onBadgeClick,
showDragItems,
startUpload,
- uploadEmptyFolders,
+ createFoldersTree,
setDragging,
showBadge,
labelBadge,
@@ -86,18 +86,12 @@ const Item = ({
const onDropZoneUpload = React.useCallback(
(files, uploadToFolder) => {
dragging && setDragging(false);
- const emptyFolders = files.filter((f) => f.isEmptyDirectory);
- if (emptyFolders.length > 0) {
- uploadEmptyFolders(emptyFolders, uploadToFolder).then(() => {
- const onlyFiles = files.filter((f) => !f.isEmptyDirectory);
- if (onlyFiles.length > 0) startUpload(onlyFiles, uploadToFolder, t);
- });
- } else {
- startUpload(files, uploadToFolder, t);
- }
+ createFoldersTree(files, uploadToFolder).then((f) => {
+ if (f.length > 0) startUpload(f, null, t);
+ });
},
- [t, dragging, setDragging, startUpload, uploadEmptyFolders],
+ [t, dragging, setDragging, startUpload, createFoldersTree],
);
const onDrop = React.useCallback(
@@ -193,7 +187,7 @@ const Items = ({
dragging,
setDragging,
startUpload,
- uploadEmptyFolders,
+ createFoldersTree,
isVisitor,
isCollaborator,
isAdmin,
@@ -326,7 +320,7 @@ const Items = ({
t={t}
setDragging={setDragging}
startUpload={startUpload}
- uploadEmptyFolders={uploadEmptyFolders}
+ createFoldersTree={createFoldersTree}
item={item}
setBufferSelection={setBufferSelection}
dragging={dragging}
@@ -388,7 +382,7 @@ const Items = ({
showText,
setDragging,
startUpload,
- uploadEmptyFolders,
+ createFoldersTree,
trashIsEmpty,
isAdmin,
isVisitor,
@@ -449,7 +443,7 @@ export default inject(
const { id, access: folderAccess } = selectedFolderStore;
const {
moveDragItems,
- uploadEmptyFolders,
+ createFoldersTree,
deleteAction,
emptyTrashInProgress,
} = filesActionsStore;
@@ -478,7 +472,7 @@ export default inject(
setBufferSelection,
deleteAction,
startUpload,
- uploadEmptyFolders,
+ createFoldersTree,
setEmptyTrashDialogVisible,
trashIsEmpty,
diff --git a/packages/client/src/components/Article/MainButton/index.js b/packages/client/src/components/Article/MainButton/index.js
index 6f1f4e0afb..a92377d711 100644
--- a/packages/client/src/components/Article/MainButton/index.js
+++ b/packages/client/src/components/Article/MainButton/index.js
@@ -70,6 +70,7 @@ import { resendInvitesAgain } from "@docspace/shared/api/people";
import { getCorrectFourValuesStyle } from "@docspace/shared/utils";
import { ArticleButtonLoader } from "@docspace/shared/skeletons/article";
import { isMobile, isTablet } from "react-device-detect";
+import getFilesFromEvent from "@docspace/shared/components/drag-and-drop/get-files-from-event";
const StyledButton = styled(Button)`
font-weight: 700;
@@ -180,6 +181,7 @@ const ArticleMainButtonContent = (props) => {
parentRoomType,
isFolder,
+ createFoldersTree,
} = props;
const navigate = useNavigate();
@@ -239,8 +241,12 @@ const ArticleMainButtonContent = (props) => {
);
const onFileChange = React.useCallback(
- (e) => {
- startUpload(e.target.files, null, t);
+ async (e) => {
+ const files = await getFilesFromEvent(e);
+
+ createFoldersTree(files).then((f) => {
+ if (f.length > 0) startUpload(f, null, t);
+ });
},
[startUpload, t],
);
@@ -249,7 +255,7 @@ const ArticleMainButtonContent = (props) => {
if (isPrivacy) {
encryptionUploadDialog((encryptedFile, encrypted) => {
encryptedFile.encrypted = encrypted;
- startUpload([encryptedFile], null, t);
+ startUpload([encryptedFile], null, t); // TODO: createFoldersTree
});
} else {
inputFilesElement.current.click();
@@ -901,6 +907,7 @@ export default inject(
versionHistoryStore,
userStore,
currentTariffStatusStore,
+ filesActionsStore,
}) => {
const { showArticleLoader } = clientLoadingStore;
const { mainButtonMobileVisible } = filesStore;
@@ -945,6 +952,8 @@ export default inject(
const { frameConfig, isFrame } = settingsStore;
+ const { createFoldersTree } = filesActionsStore;
+
return {
isGracePeriod,
setInviteUsersWarningDialogVisible,
@@ -997,6 +1006,7 @@ export default inject(
isFolder,
selectFileFormRoomDialogVisible,
setSelectFileFormRoomDialogVisible,
+ createFoldersTree,
};
},
)(
diff --git a/packages/client/src/components/EmptyContainer/RoomNoAccessContainer.js b/packages/client/src/components/EmptyContainer/RoomNoAccessContainer.js
index e02dc9a77f..61df1e840f 100644
--- a/packages/client/src/components/EmptyContainer/RoomNoAccessContainer.js
+++ b/packages/client/src/components/EmptyContainer/RoomNoAccessContainer.js
@@ -38,6 +38,7 @@ import { IconButton } from "@docspace/shared/components/icon-button";
import RoomsFilter from "@docspace/shared/api/rooms/filter";
import { RoomSearchArea } from "@docspace/shared/enums";
+import { frameCallEvent } from "@docspace/shared/utils/common";
import { getCategoryUrl } from "SRC_DIR/helpers/utils";
import { CategoryType } from "SRC_DIR/helpers/constants";
@@ -60,6 +61,8 @@ const RoomNoAccessContainer = (props) => {
const navigate = useNavigate();
React.useEffect(() => {
+ frameCallEvent({ event: "onNoAccess" });
+
const timer = setTimeout(onGoToShared, 5000);
return () => clearTimeout(timer);
}, []);
diff --git a/packages/client/src/components/panels/InvitePanel/sub-components/ExternalLinks.js b/packages/client/src/components/panels/InvitePanel/sub-components/ExternalLinks.js
index a247277c03..93c53609fe 100644
--- a/packages/client/src/components/panels/InvitePanel/sub-components/ExternalLinks.js
+++ b/packages/client/src/components/panels/InvitePanel/sub-components/ExternalLinks.js
@@ -88,7 +88,7 @@ const ExternalLinks = ({
copyLink(link.shareLink);
}
} else {
- !externalLinksVisible ? editLink() : disableLink();
+ !externalLinksVisible ? await editLink() : await disableLink();
}
onChangeExternalLinksVisible(!externalLinksVisible);
} catch (error) {
@@ -98,9 +98,10 @@ const ExternalLinks = ({
}
};
- const disableLink = () => {
- setInvitationLinks(roomId, "Invite", 0, shareLinks[0].id);
- setShareLinks([]);
+ const disableLink = async () => {
+ shareLinks?.length &&
+ (await setInvitationLinks(roomId, "Invite", 0, shareLinks[0].id));
+ return setShareLinks([]);
};
const editLink = async () => {
@@ -120,7 +121,7 @@ const ExternalLinks = ({
copyLink(shareLink);
setShareLinks([activeLink]);
- setActiveLink(activeLink);
+ return setActiveLink(activeLink);
};
const onSelectAccess = async (access) => {
diff --git a/packages/client/src/pages/Confirm/sub-components/StyledCreateUser.js b/packages/client/src/pages/Confirm/sub-components/StyledCreateUser.js
index a8d6aa98bf..8ff8d3adf4 100644
--- a/packages/client/src/pages/Confirm/sub-components/StyledCreateUser.js
+++ b/packages/client/src/pages/Confirm/sub-components/StyledCreateUser.js
@@ -54,7 +54,10 @@ export const GreetingContainer = styled.div`
}
.tooltip {
- p {
+ .invitation-text {
+ display: flex;
+ flex-direction: column;
+ align-items: center;
text-align: center;
}
@@ -65,15 +68,13 @@ export const GreetingContainer = styled.div`
.portal-logo {
width: 100%;
+ max-width: 386px;
+ height: 44px;
+ margin: 0 auto;
padding-bottom: 16px;
- height: 26.56px;
display: flex;
align-items: center;
justify-content: center;
-
- .injected-svg {
- height: 26.56px;
- }
}
`;
diff --git a/packages/client/src/pages/Confirm/sub-components/createUser.js b/packages/client/src/pages/Confirm/sub-components/createUser.js
index 99eb5e95f6..fcd1292fea 100644
--- a/packages/client/src/pages/Confirm/sub-components/createUser.js
+++ b/packages/client/src/pages/Confirm/sub-components/createUser.js
@@ -485,7 +485,7 @@ const CreateUserForm = (props) => {
{linkData.type === "LinkInvite" && (
-
+
{roomName ? (
f.isEmptyDirectory);
-
- if (emptyFolders.length > 0) {
- uploadEmptyFolders(emptyFolders, uploadToFolder).then(() => {
- const onlyFiles = files.filter((f) => !f.isEmptyDirectory);
- if (onlyFiles.length > 0) startUpload(onlyFiles, uploadToFolder, t);
- });
- } else {
- startUpload(files, uploadToFolder, t);
- }
+ createFoldersTree(files, uploadToFolder).then((f) => {
+ if (f.length > 0) startUpload(f, null, t);
+ });
};
React.useEffect(() => {
diff --git a/packages/client/src/pages/Home/InfoPanel/Body/styles/common.js b/packages/client/src/pages/Home/InfoPanel/Body/styles/common.js
index 2332db4d55..fb45cf0d15 100644
--- a/packages/client/src/pages/Home/InfoPanel/Body/styles/common.js
+++ b/packages/client/src/pages/Home/InfoPanel/Body/styles/common.js
@@ -264,8 +264,8 @@ const StyledProperties = styled.div`
grid-template-columns: 120px 1fr;
grid-column-gap: 24px;
- -webkit-box-align: center;
- align-items: center;
+ -webkit-box-align: baseline;
+ align-items: baseline;
.property-title {
font-size: 13px;
diff --git a/packages/client/src/pages/Home/Section/AccountsBody/InsideGroup/TableView/TableHeader.js b/packages/client/src/pages/Home/Section/AccountsBody/InsideGroup/TableView/TableHeader.js
index 94df06e920..5783767e86 100644
--- a/packages/client/src/pages/Home/Section/AccountsBody/InsideGroup/TableView/TableHeader.js
+++ b/packages/client/src/pages/Home/Section/AccountsBody/InsideGroup/TableView/TableHeader.js
@@ -138,15 +138,8 @@ class InsideGroupTableHeader extends React.Component {
newFilter.sortBy = sortBy;
if (sortBy === "AZ") {
- if (
- newFilter.sortBy !== "lastname" &&
- newFilter.sortBy !== "firstname"
- ) {
- newFilter.sortBy = "firstname";
- } else if (newFilter.sortBy === "lastname") {
- newFilter.sortBy = "firstname";
- } else {
- newFilter.sortBy = "lastname";
+ if (newFilter.sortBy !== "displayname") {
+ newFilter.sortBy = "displayname";
}
newFilter.sortOrder =
newFilter.sortOrder === "ascending" ? "descending" : "ascending";
@@ -176,10 +169,7 @@ class InsideGroupTableHeader extends React.Component {
} = this.props;
const { sortOrder } = filter;
- const sortBy =
- filter.sortBy === "firstname" || filter.sortBy === "lastname"
- ? "AZ"
- : filter.sortBy;
+ const sortBy = filter.sortBy === "displayname" ? "AZ" : filter.sortBy;
return (
{
getHeaderOptions,
setBufferSelection,
setGroupsBufferSelection,
+ createFoldersTree,
} = props;
const location = useLocation();
@@ -239,8 +241,12 @@ const SectionHeaderContent = (props) => {
const isSettingsPage = location.pathname.includes("/settings");
const onFileChange = React.useCallback(
- (e) => {
- startUpload(e.target.files, null, t);
+ async (e) => {
+ const files = await getFilesFromEvent(e);
+
+ createFoldersTree(files).then((f) => {
+ if (f.length > 0) startUpload(f, null, t);
+ });
},
[startUpload, t],
);
@@ -639,6 +645,7 @@ export default inject(
moveToRoomsPage,
onClickBack,
moveToPublicRoom,
+ createFoldersTree,
} = filesActionsStore;
const { setIsVisible, isVisible } = infoPanelStore;
@@ -802,6 +809,7 @@ export default inject(
getHeaderOptions,
setBufferSelection,
setGroupsBufferSelection,
+ createFoldersTree,
};
},
)(
diff --git a/packages/client/src/pages/Home/index.js b/packages/client/src/pages/Home/index.js
index 197ad6b00a..d9015a5320 100644
--- a/packages/client/src/pages/Home/index.js
+++ b/packages/client/src/pages/Home/index.js
@@ -82,7 +82,7 @@ const PureHome = (props) => {
startUpload,
setDragging,
dragging,
- uploadEmptyFolders,
+ createFoldersTree,
disableDrag,
uploaded,
converted,
@@ -182,7 +182,7 @@ const PureHome = (props) => {
dragging,
setDragging,
disableDrag,
- uploadEmptyFolders,
+ createFoldersTree,
startUpload,
fetchFiles,
fetchRooms,
@@ -543,7 +543,7 @@ export default inject(
const { setUploadPanelVisible, startUpload, uploaded, converted } =
uploadDataStore;
- const { uploadEmptyFolders, onClickBack } = filesActionsStore;
+ const { createFoldersTree, onClickBack } = filesActionsStore;
const selectionLength = isProgressFinished ? selection.length : null;
const selectionTitle = isProgressFinished
@@ -635,7 +635,7 @@ export default inject(
setUploadPanelVisible,
startUpload,
- uploadEmptyFolders,
+ createFoldersTree,
setToPreviewFile,
setIsPreview,
diff --git a/packages/client/src/pages/PortalSettings/categories/developer-tools/JavascriptSDK/presets/Manager.js b/packages/client/src/pages/PortalSettings/categories/developer-tools/JavascriptSDK/presets/Manager.js
index 7c7e509520..a3c1c572bb 100644
--- a/packages/client/src/pages/PortalSettings/categories/developer-tools/JavascriptSDK/presets/Manager.js
+++ b/packages/client/src/pages/PortalSettings/categories/developer-tools/JavascriptSDK/presets/Manager.js
@@ -130,6 +130,7 @@ const Manager = (props) => {
);
const [selectedColumns, setSelectedColumns] = useState([
{ key: "Name", label: t("Common:Name") },
+ { key: "Size", label: t("Common:Size") },
{ key: "Type", label: t("Common:Type") },
{ key: "Tags", label: t("Common:Tags") },
]);
diff --git a/packages/client/src/store/EditGroupStore.ts b/packages/client/src/store/EditGroupStore.ts
index 541ace92c8..570113fd75 100644
--- a/packages/client/src/store/EditGroupStore.ts
+++ b/packages/client/src/store/EditGroupStore.ts
@@ -125,6 +125,17 @@ class EditGroupStore {
const addedIds = Array.from(this.addedMembersMap.keys());
const removedIds = Array.from(this.removedMembersMap.keys());
+ const oldManager = this.group.manager;
+ const oldManagerRemovedButRemainsAsMember =
+ oldManager &&
+ oldManager.id !== this.manager?.id &&
+ !this.removedMembersMap.has(oldManager.id);
+
+ // Requires when new group is without manager and old manager moved to members. updateGroup api method doesn't provide possibility to do it without setting new manager
+ if (this.manager === null && oldManagerRemovedButRemainsAsMember) {
+ await api.groups.removeGroupMembers(this.group.id, [oldManager.id]);
+ addedIds.push(oldManager.id);
+ }
await updateGroup(
this.group?.id,
diff --git a/packages/client/src/store/FilesActionsStore.js b/packages/client/src/store/FilesActionsStore.js
index 1349a9ec62..0cb008057d 100644
--- a/packages/client/src/store/FilesActionsStore.js
+++ b/packages/client/src/store/FilesActionsStore.js
@@ -229,17 +229,21 @@ class FilesActionStore {
let level = { result };
try {
folders.forEach((folder) => {
- folder.path
- .split("/")
- .filter((name) => name !== "")
- .reduce((r, name, i, a) => {
- if (!r[name]) {
- r[name] = { result: [] };
- r.result.push({ name, children: r[name].result });
- }
+ const folderPath = folder.path.split("/").filter((name) => name !== "");
- return r[name];
- }, level);
+ folderPath.reduce((r, name, i, a) => {
+ if (!r[name]) {
+ r[name] = { result: [] };
+ r.result.push({
+ name,
+ children: r[name].result,
+ isFile: folderPath.length - 1 === i && !folder.isEmptyDirectory,
+ file: folder,
+ });
+ }
+
+ return r[name];
+ }, level);
});
} catch (e) {
console.error("convertToTree", e);
@@ -247,52 +251,67 @@ class FilesActionStore {
return result;
};
- createFolderTree = async (treeList, parentFolderId) => {
+ createFolderTree = async (treeList, parentFolderId, filesList) => {
if (!treeList || !treeList.length) return;
for (let i = 0; i < treeList.length; i++) {
const treeNode = treeList[i];
+ const isFile = treeList[i].isFile;
// console.log(
// `createFolderTree parent id = ${parentFolderId} name '${treeNode.name}': `,
// treeNode.children
// );
+ if (isFile) {
+ treeList[i].file.parentFolderId = parentFolderId;
+ filesList.push(treeList[i].file);
+ continue;
+ }
+
const folder = await createFolder(parentFolderId, treeNode.name);
const parentId = folder.id;
if (treeNode.children.length == 0) continue;
- await this.createFolderTree(treeNode.children, parentId);
+ await this.createFolderTree(treeNode.children, parentId, filesList);
}
+
+ return treeList;
};
- uploadEmptyFolders = async (emptyFolders, folderId) => {
- //console.log("uploadEmptyFolders", emptyFolders, folderId);
+ createFoldersTree = async (files, folderId) => {
+ //console.log("createFoldersTree", files, folderId);
- const { secondaryProgressDataStore } = this.uploadDataStore;
- const { setSecondaryProgressBarData, clearSecondaryProgressData } =
- secondaryProgressDataStore;
+ const { primaryProgressDataStore } = this.uploadDataStore;
+
+ const { setPrimaryProgressBarData, clearPrimaryProgressData } =
+ primaryProgressDataStore;
const operationId = uniqueid("operation_");
const toFolderId = folderId ? folderId : this.selectedFolderStore.id;
- setSecondaryProgressBarData({
- icon: "file",
+ setPrimaryProgressBarData({
+ icon: "upload",
visible: true,
percent: 0,
label: "",
alert: false,
- operationId,
});
- const tree = this.convertToTree(emptyFolders);
- await this.createFolderTree(tree, toFolderId);
+ const tree = this.convertToTree(files);
+
+ const filesList = [];
+ await this.createFolderTree(tree, toFolderId, filesList);
this.updateCurrentFolder(null, [folderId], null, operationId);
- setTimeout(() => clearSecondaryProgressData(operationId), TIMEOUT);
+ if (!filesList.length) {
+ setTimeout(() => clearPrimaryProgressData(), TIMEOUT);
+ }
+
+ return filesList;
};
updateFilesAfterDelete = (operationId) => {
diff --git a/packages/client/src/store/HotkeyStore.js b/packages/client/src/store/HotkeyStore.js
index 46ed343cdb..559ed6d98d 100644
--- a/packages/client/src/store/HotkeyStore.js
+++ b/packages/client/src/store/HotkeyStore.js
@@ -683,9 +683,8 @@ class HotkeyStore {
};
uploadClipboardFiles = async (t, event) => {
- const { uploadEmptyFolders } = this.filesActionsStore;
+ const { createFoldersTree } = this.filesActionsStore;
const { startUpload } = this.uploadDataStore;
- const currentFolderId = this.selectedFolderStore.id;
if (this.filesStore.hotkeysClipboard.length) {
return this.moveFilesFromClipboard(t);
@@ -693,16 +692,9 @@ class HotkeyStore {
const files = await getFilesFromEvent(event);
- const emptyFolders = files.filter((f) => f.isEmptyDirectory);
-
- if (emptyFolders.length > 0) {
- uploadEmptyFolders(emptyFolders, currentFolderId).then(() => {
- const onlyFiles = files.filter((f) => !f.isEmptyDirectory);
- if (onlyFiles.length > 0) startUpload(onlyFiles, currentFolderId, t);
- });
- } else {
- startUpload(files, currentFolderId, t);
- }
+ createFoldersTree(files, uploadToFolder).then((f) => {
+ if (f.length > 0) startUpload(f, null, t);
+ });
};
get countTilesInRow() {
diff --git a/packages/client/src/store/LdapFormStore.js b/packages/client/src/store/LdapFormStore.js
index c725630f72..17a374eb53 100644
--- a/packages/client/src/store/LdapFormStore.js
+++ b/packages/client/src/store/LdapFormStore.js
@@ -489,7 +489,7 @@ class LdapFormStore {
completed: true,
percents: 100,
certificateConfirmRequest: null,
- error: "",
+ error: t("Common:UnexpectedError"),
};
}
@@ -518,7 +518,6 @@ class LdapFormStore {
toastr.success(t("Common:SuccessfullyCompletedOperation"));
}
} catch (error) {
- console.error(error);
toastr.error(error);
this.endProcess();
}
diff --git a/packages/client/src/store/ProfileActionsStore.js b/packages/client/src/store/ProfileActionsStore.js
index ef6ed373b4..6c620bed1d 100644
--- a/packages/client/src/store/ProfileActionsStore.js
+++ b/packages/client/src/store/ProfileActionsStore.js
@@ -347,7 +347,7 @@ class ProfileActionsStore {
let bookTraining = null;
- if (!isMobile && this.isTeamTrainingAlertAvailable) {
+ if (!isMobile && this.authStore.isTeamTrainingAlertAvailable) {
bookTraining = {
key: "user-menu-book-training",
icon: BookTrainingReactSvgUrl,
diff --git a/packages/client/src/store/UploadDataStore.js b/packages/client/src/store/UploadDataStore.js
index 34f3cdb11b..50c4ed7f0e 100644
--- a/packages/client/src/store/UploadDataStore.js
+++ b/packages/client/src/store/UploadDataStore.js
@@ -25,9 +25,11 @@
// International. See the License terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
import { makeAutoObservable, runInAction } from "mobx";
+import { Trans } from "react-i18next";
import { TIMEOUT } from "@docspace/client/src/helpers/filesConstants";
import uniqueid from "lodash/uniqueId";
import sumBy from "lodash/sumBy";
+import uniqBy from "lodash/uniqBy";
import { ConflictResolveType } from "@docspace/shared/enums";
import {
getFileInfo,
@@ -57,6 +59,8 @@ import {
getCategoryTypeByFolderType,
getCategoryUrl,
} from "SRC_DIR/helpers/utils";
+import { Link } from "@docspace/shared/components/link";
+import { globalColors } from "@docspace/shared/themes";
class UploadDataStore {
settingsStore;
@@ -636,7 +640,7 @@ class UploadDataStore {
if (this.uploaded || (this.isParallel && allFilesIsUploaded)) {
this.setConversionPercent(100);
- this.finishUploadFiles();
+ this.finishUploadFiles(t);
} else {
runInAction(() => {
this.converted = true;
@@ -773,7 +777,8 @@ class UploadDataStore {
file: file,
uniqueId: uniqueid("download_row-key_"),
fileId: null,
- toFolderId,
+ // toFolderId,
+ toFolderId: file.parentFolderId,
action: "upload",
error: file.size ? null : t("Files:EmptyFile"),
fileInfo: null,
@@ -1263,7 +1268,7 @@ class UploadDataStore {
let files = this.files;
if (files.length === 0 || this.filesSize === 0) {
- return this.finishUploadFiles();
+ return this.finishUploadFiles(t);
}
const progressData = {
@@ -1310,7 +1315,7 @@ class UploadDataStore {
}
if (!this.filesToConversion.length) {
- this.finishUploadFiles();
+ this.finishUploadFiles(t);
} else {
runInAction(() => {
this.uploaded = true;
@@ -1372,7 +1377,7 @@ class UploadDataStore {
toFolderId,
fileName,
fileSize,
- relativePath,
+ "", // relativePath,
file.encrypted,
file.lastModifiedDate,
createNewIfExist,
@@ -1512,7 +1517,7 @@ class UploadDataStore {
if (allFilesIsUploaded) {
if (!this.filesToConversion.length) {
- this.finishUploadFiles();
+ this.finishUploadFiles(t);
} else {
runInAction(() => {
this.uploaded = true;
@@ -1542,7 +1547,7 @@ class UploadDataStore {
});
};
- finishUploadFiles = () => {
+ finishUploadFiles = (t) => {
const { fetchFiles, filter } = this.filesStore;
const { withPaging } = this.settingsStore;
@@ -1554,7 +1559,7 @@ class UploadDataStore {
this.asyncUploadObj = {};
for (let item of this.tempFiles) {
- const { uploadFiles, folderId, t } = item;
+ const { uploadFiles, folderId } = item;
this.startUpload(uploadFiles, folderId, t);
}
this.tempFiles = [];
@@ -1562,12 +1567,36 @@ class UploadDataStore {
return;
}
- const totalErrorsCount = sumBy(this.files, (f) => {
- f.error && toastr.error(f.error);
- return f.error ? 1 : 0;
- });
+ const filesWithErrors = this.files.filter((f) => f.error);
+
+ const totalErrorsCount = filesWithErrors.length;
if (totalErrorsCount > 0) {
+ const uniqErrors = uniqBy(filesWithErrors, "error");
+ uniqErrors.forEach((f) =>
+ f.error.indexOf("password") > -1
+ ? toastr.warning(
+ {
+ toastr.clear();
+ this.setUploadPanelVisible(true);
+ }}
+ />,
+ ]}
+ />,
+ null,
+ 60000,
+ true,
+ )
+ : toastr.error(f.error),
+ );
+
this.primaryProgressDataStore.setPrimaryProgressBarShowError(true); // for empty file
this.primaryProgressDataStore.setPrimaryProgressBarErrors(
totalErrorsCount,
diff --git a/packages/shared/api/groups/index.ts b/packages/shared/api/groups/index.ts
index 3b54cba3b1..36b1987c68 100644
--- a/packages/shared/api/groups/index.ts
+++ b/packages/shared/api/groups/index.ts
@@ -146,6 +146,14 @@ export const addGroupMembers = (groupId: string, members: string) => {
});
};
+export const removeGroupMembers = (groupId: string, membersIds: string[]) => {
+ return request({
+ method: "delete",
+ url: `/group/${groupId}/members`,
+ data: { id: groupId, members: membersIds },
+ }) as Promise;
+};
+
// * Delete
export const deleteGroup = (groupId: string) => {
diff --git a/packages/shared/api/people/filter.js b/packages/shared/api/people/filter.js
index 926e9e7b6c..086224fd9a 100644
--- a/packages/shared/api/people/filter.js
+++ b/packages/shared/api/people/filter.js
@@ -29,7 +29,7 @@ import { getObjectByLocation, toUrlParams } from "../../utils/common";
const DEFAULT_PAGE = 0;
const DEFAULT_PAGE_COUNT = 25;
const DEFAULT_TOTAL = 0;
-const DEFAULT_SORT_BY = "firstname";
+const DEFAULT_SORT_BY = "displayname";
const DEFAULT_SORT_ORDER = "ascending";
const DEFAULT_EMPLOYEE_STATUS = null;
const DEFAULT_ACTIVATION_STATUS = null;
diff --git a/packages/shared/components/calendar/utils/getCalendarYears.ts b/packages/shared/components/calendar/utils/getCalendarYears.ts
index 8e0630cf57..82a2538044 100644
--- a/packages/shared/components/calendar/utils/getCalendarYears.ts
+++ b/packages/shared/components/calendar/utils/getCalendarYears.ts
@@ -29,7 +29,7 @@ import moment from "moment";
export const getCalendarYears = (observedDate: moment.Moment) => {
const years = [];
const selectedYear = observedDate.year();
- const firstYear = selectedYear - (selectedYear % 10) - 1;
+ const firstYear = selectedYear - 1;
for (let i = firstYear; i <= firstYear + 15; i += 1) {
years.push(moment(i, "YYYY").format("YYYY"));
diff --git a/packages/shared/components/error-container/ErrorContainer.styled.ts b/packages/shared/components/error-container/ErrorContainer.styled.ts
index b0b3556f97..8a987d39a2 100644
--- a/packages/shared/components/error-container/ErrorContainer.styled.ts
+++ b/packages/shared/components/error-container/ErrorContainer.styled.ts
@@ -40,7 +40,7 @@ const StyledErrorContainer = styled.div<{ isEditor: boolean }>`
css`
position: absolute;
`}
- overflow-x: hidden;
+ overflow: hidden;
display: flex;
flex-direction: column;
align-items: center;
diff --git a/packages/shared/components/media-viewer/sub-components/ImageViewer/index.tsx b/packages/shared/components/media-viewer/sub-components/ImageViewer/index.tsx
index 1bbd458427..9f33ad2172 100644
--- a/packages/shared/components/media-viewer/sub-components/ImageViewer/index.tsx
+++ b/packages/shared/components/media-viewer/sub-components/ImageViewer/index.tsx
@@ -996,6 +996,7 @@ export const ImageViewer = ({
onDoubleClick={handleDoubleTapOrClick}
onLoad={imageLoaded}
onError={onError}
+ onContextMenu={(event) => event.preventDefault()}
/>
diff --git a/packages/shared/components/media-viewer/sub-components/PlayerBigPlayButton/index.tsx b/packages/shared/components/media-viewer/sub-components/PlayerBigPlayButton/index.tsx
index 67c79059f9..8876178cc4 100644
--- a/packages/shared/components/media-viewer/sub-components/PlayerBigPlayButton/index.tsx
+++ b/packages/shared/components/media-viewer/sub-components/PlayerBigPlayButton/index.tsx
@@ -36,7 +36,9 @@ export const PlayerBigPlayButton = ({
if (!visible) return;
return (
-
+ event.preventDefault()}
+ >
);
diff --git a/packages/shared/components/media-viewer/sub-components/ViewerPlayer/index.tsx b/packages/shared/components/media-viewer/sub-components/ViewerPlayer/index.tsx
index e908d44628..2845b7db6d 100644
--- a/packages/shared/components/media-viewer/sub-components/ViewerPlayer/index.tsx
+++ b/packages/shared/components/media-viewer/sub-components/ViewerPlayer/index.tsx
@@ -406,6 +406,10 @@ export const ViewerPlayer = ({
const percent = Number(event.target.value);
const newCurrentTime = (percent / 100) * videoRef.current.duration;
+ const videoCurrentTime = videoRef.current.currentTime;
+
+ if (Math.abs(newCurrentTime - videoCurrentTime) <= 0.1) return;
+
handleProgress();
setTimeline(percent);
setCurrentTime(newCurrentTime);
@@ -653,6 +657,7 @@ export const ViewerPlayer = ({
onDurationChange={handleDurationChange}
onLoadedMetadata={handleLoadedMetaDataVideo}
onPlay={() => setIsPlaying(true)}
+ onContextMenu={(event) => event.preventDefault()}
/>
) : null;
- const children = tariffBar ? React.cloneElement(tariffBar, { title }) : null;
+ const children =
+ tariffBar && !isFrame ? React.cloneElement(tariffBar, { title }) : null;
const isTabletView = isTablet();
const contextOptionsFolder = getContextOptionsFolder();
diff --git a/packages/shared/components/section/Section.types.ts b/packages/shared/components/section/Section.types.ts
index 061b602129..90ad52348f 100644
--- a/packages/shared/components/section/Section.types.ts
+++ b/packages/shared/components/section/Section.types.ts
@@ -145,3 +145,7 @@ export interface SectionProps {
isDesktop?: boolean;
getContextModel?: () => ContextMenuModel[];
}
+
+export interface SectionContextMenuProps {
+ getContextModel: () => ContextMenuModel[];
+}
diff --git a/packages/shared/components/section/sub-components/SectionBody.tsx b/packages/shared/components/section/sub-components/SectionBody.tsx
index 914a2e92c6..eba713e65f 100644
--- a/packages/shared/components/section/sub-components/SectionBody.tsx
+++ b/packages/shared/components/section/sub-components/SectionBody.tsx
@@ -29,14 +29,13 @@ import { useLocation } from "react-router-dom";
// import { inject, observer } from "mobx-react";
-import { ContextMenu } from "@docspace/shared/components/context-menu";
-
import {
StyledDropZoneBody,
StyledSpacer,
StyledSectionBody,
} from "../Section.styled";
import { SectionBodyProps } from "../Section.types";
+import SectionContextMenu from "./SectionContextMenu";
const SectionBody = React.memo(
({
@@ -53,49 +52,9 @@ const SectionBody = React.memo(
getContextModel,
}: SectionBodyProps) => {
const focusRef = React.useRef(null);
- const cmRef = React.useRef void;
- hide: (e: React.MouseEvent | MouseEvent) => void;
- toggle: (e: React.MouseEvent | MouseEvent) => boolean;
- getVisible: () => boolean;
- }>(null);
+
const location = useLocation();
- const [isOpen, setIsOpen] = React.useState(false);
-
- const onContextMenu = React.useCallback(
- (e: MouseEvent | React.MouseEvent) => {
- const bodyElem = document.getElementsByClassName(
- "section-body",
- )[0] as HTMLDivElement;
-
- const target = e.target as Node;
-
- if (
- !getContextModel ||
- !getContextModel() ||
- !bodyElem ||
- !bodyElem.contains(target)
- )
- return;
-
- e.stopPropagation();
- e.preventDefault();
-
- // if (cmRef.current) cmRef.current.toggle(e);
- if (cmRef.current) {
- if (!isOpen) cmRef?.current?.show(e);
- else cmRef?.current?.hide(e);
- setIsOpen(!isOpen);
- }
- },
- [getContextModel, isOpen],
- );
-
- const onHide = () => {
- setIsOpen(false);
- };
-
const focusSectionBody = React.useCallback(() => {
if (focusRef.current) focusRef.current.focus({ preventScroll: true });
}, []);
@@ -108,14 +67,6 @@ const SectionBody = React.memo(
[focusSectionBody],
);
- React.useEffect(() => {
- document.addEventListener("contextmenu", onContextMenu);
-
- return () => {
- document.removeEventListener("contextmenu", onContextMenu);
- };
- }, [onContextMenu]);
-
React.useEffect(() => {
if (!autoFocus) return;
@@ -145,16 +96,6 @@ const SectionBody = React.memo(
}
: {};
- const contextBlock = (
-
- );
-
return uploadFiles ? (
)}
- {contextBlock}
+
) : (
{children}
)}
- {contextBlock}
+
);
},
diff --git a/packages/shared/components/section/sub-components/SectionContextMenu.tsx b/packages/shared/components/section/sub-components/SectionContextMenu.tsx
new file mode 100644
index 0000000000..7dafb4b03a
--- /dev/null
+++ b/packages/shared/components/section/sub-components/SectionContextMenu.tsx
@@ -0,0 +1,80 @@
+import React from "react";
+import { ContextMenu } from "@docspace/shared/components/context-menu";
+import isEqual from "lodash/isEqual";
+import { SectionContextMenuProps } from "../Section.types";
+
+const areEqual = (
+ prevProps: SectionContextMenuProps,
+ nextProps: SectionContextMenuProps,
+) => {
+ if (!isEqual(prevProps, nextProps)) return true;
+ return false;
+};
+
+const SectionContextMenu = React.memo(
+ ({ getContextModel }: SectionContextMenuProps) => {
+ const [isOpen, setIsOpen] = React.useState(false);
+
+ const cmRef = React.useRef void;
+ hide: (e: React.MouseEvent | MouseEvent) => void;
+ toggle: (e: React.MouseEvent | MouseEvent) => boolean;
+ getVisible: () => boolean;
+ }>(null);
+
+ const onHide = () => {
+ setIsOpen(false);
+ };
+
+ const onContextMenu = React.useCallback(
+ (e: MouseEvent | React.MouseEvent) => {
+ const bodyElem = document.getElementsByClassName(
+ "section-body",
+ )[0] as HTMLDivElement;
+
+ const target = e.target as Node;
+
+ if (
+ !getContextModel ||
+ !getContextModel() ||
+ !bodyElem ||
+ !bodyElem.contains(target)
+ )
+ return;
+
+ e.stopPropagation();
+ e.preventDefault();
+
+ // if (cmRef.current) cmRef.current.toggle(e);
+ if (cmRef.current) {
+ if (!isOpen) cmRef?.current?.show(e);
+ else cmRef?.current?.hide(e);
+ setIsOpen(!isOpen);
+ }
+ },
+ [getContextModel, isOpen],
+ );
+
+ React.useEffect(() => {
+ document.addEventListener("contextmenu", onContextMenu);
+
+ return () => {
+ document.removeEventListener("contextmenu", onContextMenu);
+ };
+ }, [onContextMenu]);
+
+ return (
+
+ );
+ },
+ areEqual,
+);
+SectionContextMenu.displayName = "SectionContextMenu";
+
+export default SectionContextMenu;
diff --git a/packages/shared/types/Frame.ts b/packages/shared/types/Frame.ts
index 1dd42178ad..469ff145df 100644
--- a/packages/shared/types/Frame.ts
+++ b/packages/shared/types/Frame.ts
@@ -75,6 +75,7 @@ export type TFrameEvents = {
onAuthSuccess: null | ((e: Event) => void);
onSignOut: null | ((e: Event) => void);
onDownload: null | ((e: Event) => void);
+ onNoAccess: null | ((e: Event) => void);
};
export type TFrameConfig = {
@@ -96,6 +97,7 @@ export type TFrameConfig = {
showSelectorCancel: boolean;
showSelectorHeader: boolean;
showHeader: boolean;
+ showHeaderBanner: string;
showTitle: boolean;
showMenu: boolean;
showFilter: boolean;
diff --git a/packages/shared/utils/axiosClient.ts b/packages/shared/utils/axiosClient.ts
index c035f9e298..cec4503331 100644
--- a/packages/shared/utils/axiosClient.ts
+++ b/packages/shared/utils/axiosClient.ts
@@ -220,10 +220,12 @@ class AxiosClient {
}
const loginURL = combineUrl(proxyURL, "/login");
+
if (!this.isSSR) {
switch (error.response?.status) {
case 401: {
- if (options.skipUnauthorized) return Promise.resolve();
+ if (options.skipUnauthorized || window?.ClientConfig?.isFrame)
+ return Promise.resolve();
if (options.skipLogout) return Promise.reject(error);
const opt: AxiosRequestConfig = {
@@ -244,14 +246,13 @@ class AxiosClient {
break;
case 403: {
const pathname = window.location.pathname;
- const isFrame = window?.ClientConfig?.isFrame;
const isArchived = pathname.indexOf("/rooms/archived") !== -1;
const isRooms =
pathname.indexOf("/rooms/shared") !== -1 || isArchived;
- if (isRooms && !skipRedirect && !isFrame) {
+ if (isRooms && !skipRedirect && !window?.ClientConfig?.isFrame) {
setTimeout(() => {
window.DocSpace.navigate(isArchived ? "/archived" : "/");
}, 1000);
diff --git a/public/scripts/sdk/1.0.1/api.js b/public/scripts/sdk/1.0.1/api.js
index ae265191e0..a5247f8a0f 100644
--- a/public/scripts/sdk/1.0.1/api.js
+++ b/public/scripts/sdk/1.0.1/api.js
@@ -53,7 +53,7 @@
showSignOut: true,
destroyText: "",
viewAs: "row", //TODO: ["row", "table", "tile"]
- viewTableColumns: "Name,Type,Tags",
+ viewTableColumns: "Name,Size,Type,Tags",
checkCSP: true,
disableActionButton: false,
showSettings: false,
@@ -97,6 +97,8 @@
onAuthSuccess: null,
onSignOut: null,
onDownload: null,
+ onNoAccess: null,
+ onContentReady: null,
},
};
@@ -813,7 +815,10 @@
targetFrame.style.height = this.config.height;
targetFrame.parentNode.style.height = "inherit";
- if (loader) loader.remove();
+ if (loader) {
+ loader.remove();
+ this.config.events.onContentReady();
+ }
}
}