diff --git a/common/ASC.Core.Common/Context/Impl/TenantManager.cs b/common/ASC.Core.Common/Context/Impl/TenantManager.cs index 2b4151261a..e2b29ff5a7 100644 --- a/common/ASC.Core.Common/Context/Impl/TenantManager.cs +++ b/common/ASC.Core.Common/Context/Impl/TenantManager.cs @@ -45,6 +45,8 @@ public class TenantManager internal CoreBaseSettings CoreBaseSettings { get; set; } internal CoreSettings CoreSettings { get; set; } + private readonly static object _lock = new object(); + static TenantManager() { _thisCompAddresses.Add("localhost"); @@ -333,7 +335,10 @@ public class TenantManager public void SetTenantQuotaRow(TenantQuotaRow row, bool exchange) { - QuotaService.SetTenantQuotaRow(row, exchange); + lock (_lock) + { + QuotaService.SetTenantQuotaRow(row, exchange); + } } public List FindTenantQuotaRows(int tenantId) diff --git a/common/ASC.Data.Storage/ZipOperators/S3ZipWriteOperator.cs b/common/ASC.Data.Storage/ZipOperators/S3ZipWriteOperator.cs index b918beb0d1..f0b6fa1d04 100644 --- a/common/ASC.Data.Storage/ZipOperators/S3ZipWriteOperator.cs +++ b/common/ASC.Data.Storage/ZipOperators/S3ZipWriteOperator.cs @@ -99,7 +99,7 @@ public class S3ZipWriteOperator : IDataWriteOperator stream.Position = 0; var buffer = new byte[_sessionHolder.MaxChunkUploadSize]; int bytesRead; - while ((bytesRead = _fileStream.Read(buffer, 0, (int)_sessionHolder.MaxChunkUploadSize)) > 0) + while ((bytesRead = stream.Read(buffer, 0, (int)_sessionHolder.MaxChunkUploadSize)) > 0) { _sha.TransformBlock(buffer, 0, bytesRead, buffer, 0); } diff --git a/packages/client/src/components/Article/Body/Items.js b/packages/client/src/components/Article/Body/Items.js index c0c7861d44..0ce4db2296 100644 --- a/packages/client/src/components/Article/Body/Items.js +++ b/packages/client/src/components/Article/Body/Items.js @@ -171,6 +171,7 @@ const Items = ({ onHide, firstLoad, deleteAction, + startDrag, }) => { useEffect(() => { data.forEach((elem) => { @@ -265,7 +266,12 @@ const Items = ({ return false; } - if (!draggableItems || draggableItems.find((x) => x.id === item.id)) + if ( + !draggableItems || + draggableItems.find( + (x) => x.id === item.id && x.isFolder === item.isFolder + ) + ) return false; if ( @@ -281,7 +287,7 @@ const Items = ({ (item.pathParts[0] === myId || item.pathParts[0] === commonId)) || item.rootFolderType === FolderType.USER || item.rootFolderType === FolderType.COMMON || - item.rootFolderType === FolderType.TRASH + (item.rootFolderType === FolderType.TRASH && startDrag) ) { return true; } @@ -417,9 +423,9 @@ export default inject( selection, dragging, setDragging, - setStartDrag, trashIsEmpty, firstLoad, + startDrag, } = filesStore; const { startUpload } = uploadDataStore; @@ -456,7 +462,6 @@ export default inject( draggableItems: dragging ? selection : null, dragging, setDragging, - setStartDrag, moveDragItems, deleteAction, startUpload, @@ -465,6 +470,7 @@ export default inject( trashIsEmpty, rootFolderType, firstLoad, + startDrag, }; } )(withTranslation(["Files", "Common", "Translations"])(observer(Items))); diff --git a/packages/client/src/components/GlobalEvents/ChangeUserTypeEvent.js b/packages/client/src/components/GlobalEvents/ChangeUserTypeEvent.js index ce42f744b1..f84920b3db 100644 --- a/packages/client/src/components/GlobalEvents/ChangeUserTypeEvent.js +++ b/packages/client/src/components/GlobalEvents/ChangeUserTypeEvent.js @@ -15,6 +15,7 @@ const ChangeUserTypeEvent = ({ peopleFilter, updateUserType, getUsersList, + onClose, }) => { const { toType, @@ -58,7 +59,7 @@ const ChangeUserTypeEvent = ({ }; const onChangeUserType = () => { - onClose(); + onClosePanel(); updateUserType(toType, userIDs, peopleFilter, fromType) .then(() => { toastr.success(t("SuccessChangeUserType")); @@ -83,14 +84,15 @@ const ChangeUserTypeEvent = ({ }); }; - const onClose = () => { + const onClosePanel = () => { setVisible(false); + onClose(); }; const onCloseAction = async () => { await getUsersList(peopleFilter); abortCallback && abortCallback(); - onClose(); + onClosePanel(); }; const getType = (type) => { @@ -99,6 +101,8 @@ const ChangeUserTypeEvent = ({ return t("Common:DocSpaceAdmin"); case "manager": return t("Common:RoomAdmin"); + case "collaborator": + return t("Common:Collaborator"); case "user": default: return t("Common:User"); diff --git a/packages/client/src/components/panels/InvitePanel/index.js b/packages/client/src/components/panels/InvitePanel/index.js index 9e3591221a..955424ecbb 100644 --- a/packages/client/src/components/panels/InvitePanel/index.js +++ b/packages/client/src/components/panels/InvitePanel/index.js @@ -42,6 +42,8 @@ const InvitePanel = ({ reloadSelectionParentRoom, setUpdateRoomMembers, roomsView, + getUsersList, + filter, }) => { const [selectedRoom, setSelectedRoom] = useState(null); const [hasErrors, setHasErrors] = useState(false); @@ -186,6 +188,10 @@ const InvitePanel = ({ } catch (err) { toastr.error(err); setIsLoading(false); + } finally { + if (roomId === -1) { + await getUsersList(filter , false); + } } }; @@ -269,7 +275,8 @@ const InvitePanel = ({ export default inject(({ auth, peopleStore, filesStore, dialogsStore }) => { const { theme } = auth.settingsStore; - const { getUsersByQuery, inviteUsers } = peopleStore.usersStore; + const { getUsersByQuery, inviteUsers, getUsersList } = peopleStore.usersStore; + const { filter } = peopleStore.filterStore; const { setIsMobileHidden: setInfoPanelIsMobileHidden, reloadSelectionParentRoom, @@ -323,6 +330,8 @@ export default inject(({ auth, peopleStore, filesStore, dialogsStore }) => { reloadSelectionParentRoom, setUpdateRoomMembers, roomsView, + getUsersList, + filter, }; })( withTranslation([ diff --git a/packages/client/src/components/panels/UploadPanel/SubComponents/LoadingButton.js b/packages/client/src/components/panels/UploadPanel/SubComponents/LoadingButton.js index c82292e2ba..5380fdb132 100644 --- a/packages/client/src/components/panels/UploadPanel/SubComponents/LoadingButton.js +++ b/packages/client/src/components/panels/UploadPanel/SubComponents/LoadingButton.js @@ -67,7 +67,9 @@ export default inject(({ uploadDataStore }, { item }) => { const loadingFile = !file || !file.uniqueId ? null : file; const currentFileUploadProgress = - file && loadingFile.uniqueId === item.uniqueId ? loadingFile.percent : null; + file && loadingFile?.uniqueId === item?.uniqueId + ? loadingFile.percent + : null; return { percent: isParallel diff --git a/packages/client/src/pages/Home/InfoPanel/Body/views/History/HistoryBlock.js b/packages/client/src/pages/Home/InfoPanel/Body/views/History/HistoryBlock.js index e3e7864983..969376e29c 100644 --- a/packages/client/src/pages/Home/InfoPanel/Body/views/History/HistoryBlock.js +++ b/packages/client/src/pages/Home/InfoPanel/Body/views/History/HistoryBlock.js @@ -39,6 +39,8 @@ const HistoryBlock = ({ ? initiator.avatarSmall : DefaultUserAvatarSmall; + const isSelectedFile = !selection.isFolder && !selection.isRoom; + return ( - {isItemAction && ( + {isItemAction && !isSelectedFile && ( setIsShowMore(true); const parsedItems = items.map((item) => { + const indexPoint = item.Title.lastIndexOf("."); const splitTitle = item.Title.split("."); + const splitTitleLength = splitTitle.length; + + const fileExst = + splitTitleLength != 1 ? `.${splitTitle[splitTitleLength - 1]}` : null; + + const title = + splitTitleLength <= 2 ? splitTitle[0] : item.Title.slice(0, indexPoint); + return { ...item, isRoom: item.Item === "room", isFolder: item.Item === "folder", roomType: RoomsType[item.AdditionalInfo], - title: splitTitle[0], - fileExst: splitTitle[1] ? `.${splitTitle[1]}` : null, + title, + fileExst, id: item.ItemId.split("_")[0], viewUrl: item.itemId, }; diff --git a/packages/client/src/pages/Home/InfoPanel/Body/views/History/index.js b/packages/client/src/pages/Home/InfoPanel/Body/views/History/index.js index 564f1e115e..9333f619bf 100644 --- a/packages/client/src/pages/Home/InfoPanel/Body/views/History/index.js +++ b/packages/client/src/pages/Home/InfoPanel/Body/views/History/index.js @@ -20,12 +20,6 @@ const History = ({ openUser, isVisitor, isCollaborator, - searchTitleOpenLocation, - itemOpenLocation, - isLoadedSearchFiles, - getFolderInfo, - getFileInfo, - setSelectionFiles, }) => { const [history, setHistory] = useState(null); const [showLoader, setShowLoader] = useState(false); @@ -36,27 +30,6 @@ const History = ({ return () => (isMount.current = false); }, []); - useEffect(() => { - if (!(searchTitleOpenLocation && isLoadedSearchFiles && itemOpenLocation)) - return; - - const requestInfo = itemOpenLocation.isFolder ? getFolderInfo : getFileInfo; - - requestInfo(+itemOpenLocation.id).then((res) => { - if (itemOpenLocation.isFolder) res.isFolder = true; - - setSelectionFiles([res]); - setSelection(res); - }); - }, [ - searchTitleOpenLocation, - isLoadedSearchFiles, - itemOpenLocation, - getFolderInfo, - getFileInfo, - setSelectionFiles, - ]); - const fetchHistory = async (itemId) => { let module = "files"; if (selection.isRoom) module = "rooms"; @@ -167,18 +140,8 @@ export default inject(({ auth, filesStore, filesActionsStore }) => { } = auth.infoPanelStore; const { personal, culture } = auth.settingsStore; - const { - getHistory, - getFolderInfo, - getFileInfo, - setSelection: setSelectionFiles, - } = filesStore; - const { - checkAndOpenLocationAction, - searchTitleOpenLocation, - itemOpenLocation, - isLoadedSearchFiles, - } = filesActionsStore; + const { getHistory } = filesStore; + const { checkAndOpenLocationAction } = filesActionsStore; const { user } = userStore; const isVisitor = user.isVisitor; @@ -196,11 +159,5 @@ export default inject(({ auth, filesStore, filesActionsStore }) => { openUser, isVisitor, isCollaborator, - searchTitleOpenLocation, - itemOpenLocation, - isLoadedSearchFiles, - getFolderInfo, - getFileInfo, - setSelectionFiles, }; })(withTranslation(["InfoPanel", "Common", "Translations"])(observer(History))); diff --git a/packages/client/src/pages/Home/InfoPanel/Body/views/Members/User.js b/packages/client/src/pages/Home/InfoPanel/Body/views/Members/User.js index efad941d78..1a4a8e5e13 100644 --- a/packages/client/src/pages/Home/InfoPanel/Body/views/Members/User.js +++ b/packages/client/src/pages/Home/InfoPanel/Body/views/Members/User.js @@ -90,6 +90,8 @@ const User = ({ ? "admin" : option.key === "roomAdmin" ? "manager" + : option.key === "collaborator" + ? "collaborator" : "user"; const successCallback = () => { @@ -98,7 +100,13 @@ const User = ({ setIsLoading(true); - if (!changeUserType(userType, [user], successCallback, abortCallback)) { + const needChangeUserType = + ((user.isVisitor || user.isCollaborator) && userType === "manager") || + (user.isVisitor && userType === "collaborator"); + + if (needChangeUserType) { + changeUserType(userType, [user], successCallback, abortCallback); + } else { updateRole(option); } }; @@ -110,7 +118,7 @@ const User = ({ const withTooltip = user.isOwner || user.isAdmin; const tooltipContent = `${ - user.isAdmin ? t("Common:DocSpaceAdmin") : t("Common:Owner") + user.isOwner ? t("Common:DocSpaceOwner") : t("Common:DocSpaceAdmin") }. ${t("Common:HasFullAccess")}`; return ( diff --git a/packages/client/src/pages/Home/Section/Body/RowsView/FilesRowContainer.js b/packages/client/src/pages/Home/Section/Body/RowsView/FilesRowContainer.js index 4277ef38ce..4d561c7294 100644 --- a/packages/client/src/pages/Home/Section/Body/RowsView/FilesRowContainer.js +++ b/packages/client/src/pages/Home/Section/Body/RowsView/FilesRowContainer.js @@ -1,4 +1,4 @@ -import React, { useEffect } from "react"; +import React, { useEffect, useMemo } from "react"; import { inject, observer } from "mobx-react"; import RowContainer from "@docspace/components/row-container"; import SimpleFilesRow from "./SimpleFilesRow"; @@ -83,7 +83,7 @@ const FilesRowContainer = ({ isRooms, isTrashFolder, withPaging, - setUploadedFileIdWithVersion, + highlightFile, }) => { useEffect(() => { if ((viewAs !== "table" && viewAs !== "row") || !sectionWidth) return; @@ -100,6 +100,32 @@ const FilesRowContainer = ({ } }, [sectionWidth]); + const filesListNode = useMemo(() => { + return filesList.map((item, index) => ( + + )); + }, [ + filesList, + sectionWidth, + isRooms, + highlightFile.id, + highlightFile.isExst, + isTrashFolder, + ]); + return ( - {filesList.map((item, index) => ( - - ))} + {filesListNode} ); }; @@ -136,7 +151,7 @@ export default inject(({ filesStore, auth, treeFoldersStore }) => { fetchMoreFiles, hasMoreFiles, roomsFilterTotal, - setUploadedFileIdWithVersion, + highlightFile, } = filesStore; const { isVisible: infoPanelVisible } = auth.infoPanelStore; const { isRoomsFolder, isArchiveFolder, isTrashFolder } = treeFoldersStore; @@ -155,6 +170,6 @@ export default inject(({ filesStore, auth, treeFoldersStore }) => { isRooms, isTrashFolder, withPaging, - setUploadedFileIdWithVersion, + highlightFile, }; })(observer(FilesRowContainer)); diff --git a/packages/client/src/pages/Home/Section/Body/RowsView/SimpleFilesRow.js b/packages/client/src/pages/Home/Section/Body/RowsView/SimpleFilesRow.js index 9b00d519ad..df0874cd27 100644 --- a/packages/client/src/pages/Home/Section/Body/RowsView/SimpleFilesRow.js +++ b/packages/client/src/pages/Home/Section/Body/RowsView/SimpleFilesRow.js @@ -78,7 +78,7 @@ const StyledSimpleFilesRow = styled(Row)` ${(props) => props.isHighlight && css` - ${checkedStyle} + ${marginStyles} margin-top: -2px; padding-top: 1px; @@ -251,14 +251,11 @@ const SimpleFilesRow = (props) => { isRooms, folderCategory, - setUploadedFileIdWithVersion, + isHighlight, } = props; const [isDragOver, setIsDragOver] = React.useState(false); - const [isHighlight, setIsHighlight] = React.useState(false); - let timeoutRef = React.useRef(null); - let isMounted; const withAccess = item.security?.Lock; const isSmallContainer = sectionWidth <= 500; @@ -272,28 +269,6 @@ const SimpleFilesRow = (props) => { /> ); - useEffect(() => { - setIsHighlight(false); - return () => { - if (timeoutRef.current) { - clearTimeout(timeoutRef.current); - timeoutRef.current = null; - } - }; - }, []); - - useEffect(() => { - if (!item.upgradeVersion) return; - - isMounted = true; - setIsHighlight(true); - setUploadedFileIdWithVersion(null); - - timeoutRef.current = setTimeout(() => { - isMounted && setIsHighlight(false); - }, 2000); - }, [item]); - const onDragOver = (dragOver) => { if (dragOver !== isDragOver) { setIsDragOver(dragOver); diff --git a/packages/client/src/pages/Home/Section/Body/TableView/StyledTable.js b/packages/client/src/pages/Home/Section/Body/TableView/StyledTable.js index 71e5027eb3..75c0dea4a1 100644 --- a/packages/client/src/pages/Home/Section/Body/TableView/StyledTable.js +++ b/packages/client/src/pages/Home/Section/Body/TableView/StyledTable.js @@ -193,6 +193,10 @@ const StyledTableRow = styled(TableRow)` } } + .table-container_cell:not(.table-container_element-wrapper, .table-container_file-name-cell) { + padding-right: ${(props) => props.hideColumns && `0px`}; + } + .table-container_file-name-cell { margin-left: -24px; padding-left: 24px; diff --git a/packages/client/src/pages/Home/Section/Body/TableView/TableContainer.js b/packages/client/src/pages/Home/Section/Body/TableView/TableContainer.js index 80c21d4b5a..aebb6574ee 100644 --- a/packages/client/src/pages/Home/Section/Body/TableView/TableContainer.js +++ b/packages/client/src/pages/Home/Section/Body/TableView/TableContainer.js @@ -1,4 +1,4 @@ -import React, { useEffect, useRef, useCallback } from "react"; +import React, { useEffect, useRef, useCallback, useMemo } from "react"; import elementResizeDetectorMaker from "element-resize-detector"; import TableContainer from "@docspace/components/table-container"; import { inject, observer } from "mobx-react"; @@ -120,7 +120,7 @@ const Table = ({ withPaging, columnStorageName, columnInfoPanelStorageName, - setUploadedFileIdWithVersion, + highlightFile, }) => { const [tagCount, setTagCount] = React.useState(null); const [hideColumns, setHideColumns] = React.useState(false); @@ -175,6 +175,41 @@ const Table = ({ } }, []); + const filesListNode = useMemo(() => { + return filesList.map((item, index) => ( + + )); + }, [ + filesList, + setFirsElemChecked, + setHeaderBorder, + theme, + tagCount, + isRooms, + hideColumns, + highlightFile.id, + highlightFile.isExst, + isTrashFolder, + ]); + return ( - {filesList.map((item, index) => ( - - ))} + {filesListNode} ); @@ -235,7 +254,7 @@ export default inject(({ filesStore, treeFoldersStore, auth, tableStore }) => { hasMoreFiles, filterTotal, roomsFilterTotal, - setUploadedFileIdWithVersion, + highlightFile, } = filesStore; const { withPaging, theme } = auth.settingsStore; @@ -257,6 +276,6 @@ export default inject(({ filesStore, treeFoldersStore, auth, tableStore }) => { withPaging, columnStorageName, columnInfoPanelStorageName, - setUploadedFileIdWithVersion, + highlightFile, }; })(observer(Table)); diff --git a/packages/client/src/pages/Home/Section/Body/TableView/TableRow.js b/packages/client/src/pages/Home/Section/Body/TableView/TableRow.js index a965897d77..1cdafbb0bb 100644 --- a/packages/client/src/pages/Home/Section/Body/TableView/TableRow.js +++ b/packages/client/src/pages/Home/Section/Body/TableView/TableRow.js @@ -39,14 +39,11 @@ const FilesTableRow = (props) => { id, isRooms, isTrashFolder, - setUploadedFileIdWithVersion, + isHighlight, + hideColumns, } = props; - const [isHighlight, setIsHighlight] = React.useState(false); const { acceptBackground, background } = theme.dragAndDrop; - let timeoutRef = React.useRef(null); - let isMounted; - const element = ( { } }, [checkedProps, isActive, showHotkeyBorder]); - React.useEffect(() => { - setIsHighlight(false); - - return () => { - if (timeoutRef.current) { - clearTimeout(timeoutRef.current); - timeoutRef.current = null; - } - }; - }, []); - - React.useEffect(() => { - if (!item.upgradeVersion) return; - - isMounted = true; - setIsHighlight(true); - setUploadedFileIdWithVersion(null); - - timeoutRef.current = setTimeout(() => { - isMounted && setIsHighlight(false); - }, 2000); - }, [item]); - const idWithFileExst = item.fileExst ? `${item.id}_${item.fileExst}` : item.id ?? ""; @@ -168,6 +142,7 @@ const FilesTableRow = (props) => { } isRoom={item.isRoom} isHighlight={isHighlight} + hideColumns={hideColumns} > {isRooms ? ( { isRooms, withCtrlSelect, withShiftSelect, - setUploadedFileIdWithVersion, + isHighlight, } = props; - const [isHighlight, setIsHighlight] = React.useState(false); - - useEffect(() => { - setIsHighlight(false); - }, []); - - useEffect(() => { - if (!item.upgradeVersion) return; - - setIsHighlight(true); - - return () => { - if (isHighlight) setUploadedFileIdWithVersion(null); - }; - }, [item, isHighlight]); - const temporaryExtension = item.id === -1 ? `.${item.fileExst}` : item.fileExst; @@ -159,28 +143,33 @@ const FileTile = (props) => { ); }; -export default inject(({ settingsStore, filesStore, treeFoldersStore }) => { - const { getIcon } = settingsStore; - const { - setSelection, - withCtrlSelect, - withShiftSelect, - setUploadedFileIdWithVersion, - } = filesStore; +export default inject( + ({ settingsStore, filesStore, treeFoldersStore }, { item }) => { + const { getIcon } = settingsStore; + const { + setSelection, + withCtrlSelect, + withShiftSelect, + highlightFile, + } = filesStore; - const { isRoomsFolder, isArchiveFolder } = treeFoldersStore; + const isHighlight = + highlightFile.id == item?.id && highlightFile.isExst === !item?.fileExst; - const isRooms = isRoomsFolder || isArchiveFolder; + const { isRoomsFolder, isArchiveFolder } = treeFoldersStore; - return { - getIcon, - setSelection, - isRooms, - withCtrlSelect, - withShiftSelect, - setUploadedFileIdWithVersion, - }; -})( + const isRooms = isRoomsFolder || isArchiveFolder; + + return { + getIcon, + setSelection, + isRooms, + withCtrlSelect, + withShiftSelect, + isHighlight, + }; + } +)( withTranslation(["Files", "InfoPanel"])( withRouter( withFileActions(withBadges(withQuickButtons(observer(FileTile)))) diff --git a/packages/client/src/pages/Home/Section/Body/TilesView/FilesTileContainer.js b/packages/client/src/pages/Home/Section/Body/TilesView/FilesTileContainer.js index 62d7a2aece..d4195283f3 100644 --- a/packages/client/src/pages/Home/Section/Body/TilesView/FilesTileContainer.js +++ b/packages/client/src/pages/Home/Section/Body/TilesView/FilesTileContainer.js @@ -1,4 +1,10 @@ -import React, { useEffect, useRef, useCallback, useState } from "react"; +import React, { + useEffect, + useRef, + useCallback, + useState, + useMemo, +} from "react"; import { inject, observer } from "mobx-react"; import elementResizeDetectorMaker from "element-resize-detector"; import TileContainer from "./sub-components/TileContainer"; @@ -89,6 +95,38 @@ const FilesTileContainer = ({ filesList, t, sectionWidth, withPaging }) => { } }, []); + const filesListNode = useMemo(() => { + return filesList.map((item, index) => { + return index % 11 == 0 ? ( + + ) : ( + + ); + }); + }, [filesList, sectionWidth, onSetTileRef, thumbSize, columnCount]); + return ( { headingFolders={t("Translations:Folders")} headingFiles={t("Translations:Files")} > - {filesList.map((item, index) => { - return index % 11 == 0 ? ( - - ) : ( - - ); - })} + {filesListNode} ); }; diff --git a/packages/client/src/pages/Home/Section/Body/TilesView/sub-components/Tile.js b/packages/client/src/pages/Home/Section/Body/TilesView/sub-components/Tile.js index c3d58a14b4..9533132212 100644 --- a/packages/client/src/pages/Home/Section/Body/TilesView/sub-components/Tile.js +++ b/packages/client/src/pages/Home/Section/Body/TilesView/sub-components/Tile.js @@ -244,6 +244,12 @@ const StyledTile = styled.div` .new-items { min-width: 16px; } + + ${(props) => + props.isHighlight && + css` + ${animationStyles} + `} `; const StyledFileTileTop = styled.div` diff --git a/packages/client/src/pages/Home/Section/Body/TilesView/sub-components/TileContainer.js b/packages/client/src/pages/Home/Section/Body/TilesView/sub-components/TileContainer.js index 6e5a01dfe4..d053e2c406 100644 --- a/packages/client/src/pages/Home/Section/Body/TilesView/sub-components/TileContainer.js +++ b/packages/client/src/pages/Home/Section/Body/TilesView/sub-components/TileContainer.js @@ -163,13 +163,6 @@ StyledTileContainer.defaultProps = { theme: Base }; class TileContainer extends React.PureComponent { constructor(props) { super(props); - - this.state = { - selectedFilterData: { - sortId: props.filter.sortBy, - sortDirection: props.filter.sortOrder, - }, - }; } render() { @@ -181,10 +174,9 @@ class TileContainer extends React.PureComponent { style, headingFolders, headingFiles, + isDesc, } = this.props; - const { selectedFilterData } = this.state; - const Rooms = []; const Folders = []; const Files = []; @@ -260,7 +252,7 @@ class TileContainer extends React.PureComponent { className={`${className} files-tile-container`} style={style} useReactWindow={useReactWindow} - isDesc={selectedFilterData.sortDirection === "desc"} + isDesc={isDesc} > {useReactWindow ? ( {renderTile} @@ -284,20 +276,19 @@ TileContainer.defaultProps = { id: "tileContainer", }; -export default inject( - ({ auth, filesStore, treeFoldersStore, selectedFolderStore }) => { - const { personal } = auth.settingsStore; - const { fetchFiles, filter, setIsLoading } = filesStore; - const { isFavoritesFolder, isRecentFolder } = treeFoldersStore; +export default inject(({ auth, filesStore, treeFoldersStore }) => { + const { personal } = auth.settingsStore; + const { fetchFiles, filter, setIsLoading } = filesStore; + const { isFavoritesFolder, isRecentFolder } = treeFoldersStore; - return { - personal, - fetchFiles, - filter, - setIsLoading, - isFavoritesFolder, - isRecentFolder, - selectedFolderId: selectedFolderStore.id, - }; - } -)(observer(withTranslation(["Files", "Common"])(TileContainer))); + const isDesc = filter?.sortOrder === "desc"; + + return { + personal, + fetchFiles, + setIsLoading, + isFavoritesFolder, + isRecentFolder, + isDesc, + }; +})(observer(withTranslation(["Files", "Common"])(TileContainer))); diff --git a/packages/client/src/pages/Home/Section/Body/index.js b/packages/client/src/pages/Home/Section/Body/index.js index 315fcb702e..90cb5bba1b 100644 --- a/packages/client/src/pages/Home/Section/Body/index.js +++ b/packages/client/src/pages/Home/Section/Body/index.js @@ -40,7 +40,6 @@ const SectionBodyContent = (props) => { setScrollToItem, filesList, uploaded, - setSearchTitleOpenLocation, } = props; useEffect(() => { @@ -117,7 +116,6 @@ const SectionBodyContent = (props) => { e.target.closest(".search-input-block") ) { setSelection([]); - setSearchTitleOpenLocation(null); setBufferSelection(null); setHotkeyCaretStart(null); setHotkeyCaret(null); @@ -315,7 +313,6 @@ export default inject( setScrollToItem, filesList, uploaded: uploadDataStore.uploaded, - setSearchTitleOpenLocation: filesActionsStore.setSearchTitleOpenLocation, }; } )( diff --git a/packages/client/src/pages/Home/Section/Filter/index.js b/packages/client/src/pages/Home/Section/Filter/index.js index efcf55f844..6b9a60465f 100644 --- a/packages/client/src/pages/Home/Section/Filter/index.js +++ b/packages/client/src/pages/Home/Section/Filter/index.js @@ -174,9 +174,6 @@ const SectionFilterContent = ({ isPersonalRoom, setCurrentRoomsFilter, providers, - searchTitleOpenLocation, - isLoadedLocationFiles, - setIsLoadedSearchFiles, isLoadedEmptyPage, isEmptyPage, clearSearch, @@ -196,12 +193,6 @@ const SectionFilterContent = ({ } }, [isLoadedEmptyPage, isEmptyPage]); - React.useEffect(() => { - if (!(searchTitleOpenLocation && isLoadedLocationFiles)) return; - - onSearch(searchTitleOpenLocation); - }, [searchTitleOpenLocation, isLoadedLocationFiles, onSearch]); - const onFilter = React.useCallback( (data) => { if (isRooms) { @@ -316,7 +307,6 @@ const SectionFilterContent = ({ setIsLoading(false) ); } else { - setIsLoadedSearchFiles(false); const newFilter = filter.clone(); newFilter.page = 0; newFilter.search = data; @@ -325,7 +315,6 @@ const SectionFilterContent = ({ fetchFiles(selectedFolderId, newFilter).finally(() => { setIsLoading(false); - setIsLoadedSearchFiles(true); }); } }, @@ -337,7 +326,6 @@ const SectionFilterContent = ({ selectedFolderId, filter, roomsFilter, - setIsLoadedSearchFiles, ] ); @@ -394,21 +382,14 @@ const SectionFilterContent = ({ ); const getSelectedInputValue = React.useCallback(() => { - return searchTitleOpenLocation - ? searchTitleOpenLocation - : isRooms + return isRooms ? roomsFilter.filterValue ? roomsFilter.filterValue : "" : filter.search ? filter.search : ""; - }, [ - isRooms, - roomsFilter.filterValue, - filter.search, - searchTitleOpenLocation, - ]); + }, [isRooms, roomsFilter.filterValue, filter.search]); const getSelectedSortData = React.useCallback(() => { const currentFilter = isRooms ? roomsFilter : filter; @@ -1506,13 +1487,6 @@ export default inject( const { isVisible: infoPanelVisible } = auth.infoPanelStore; - const { - searchTitleOpenLocation, - setSearchTitleOpenLocation, - isLoadedLocationFiles, - setIsLoadedSearchFiles, - } = filesActionsStore; - return { user, userId: user.id, @@ -1540,11 +1514,6 @@ export default inject( setCurrentRoomsFilter, providers, - searchTitleOpenLocation, - setSearchTitleOpenLocation, - isLoadedLocationFiles, - setIsLoadedSearchFiles, - isLoadedEmptyPage, isEmptyPage, diff --git a/packages/client/src/store/AccessRightsStore.js b/packages/client/src/store/AccessRightsStore.js index 9ee406deb7..9f8de7432f 100644 --- a/packages/client/src/store/AccessRightsStore.js +++ b/packages/client/src/store/AccessRightsStore.js @@ -38,7 +38,7 @@ class AccessRightsStore { const { id: userId, statusType, role } = user; - if (userId === id || statusType === EmployeeStatus.Disabled) return false; + if (userId === id || statusType === "disabled") return false; switch (role) { case "owner": diff --git a/packages/client/src/store/FilesActionsStore.js b/packages/client/src/store/FilesActionsStore.js index d6be659c1d..11079a7ba9 100644 --- a/packages/client/src/store/FilesActionsStore.js +++ b/packages/client/src/store/FilesActionsStore.js @@ -51,9 +51,6 @@ class FilesActionStore { accessRightsStore; isBulkDownload = false; - searchTitleOpenLocation = null; - itemOpenLocation = null; - isLoadedLocationFiles = false; isLoadedSearchFiles = false; isGroupMenuBlocked = false; @@ -1160,48 +1157,26 @@ class FilesActionStore { } }; - setSearchTitleOpenLocation = (searchTitleOpenLocation) => { - this.searchTitleOpenLocation = searchTitleOpenLocation; - }; - - setItemOpenLocation = (itemOpenLocation) => { - this.itemOpenLocation = itemOpenLocation; - }; - - setIsLoadedLocationFiles = (isLoadedLocationFiles) => { - this.isLoadedLocationFiles = isLoadedLocationFiles; - }; - - setIsLoadedSearchFiles = (isLoadedSearchFiles) => { - this.isLoadedSearchFiles = isLoadedSearchFiles; - }; - openLocationAction = async (locationId) => { - this.setIsLoadedLocationFiles(false); this.filesStore.setBufferSelection(null); const files = await this.filesStore.fetchFiles(locationId, null); - this.setIsLoadedLocationFiles(true); return files; }; checkAndOpenLocationAction = async (item) => { - const filterData = FilesFilter.getDefault(); + const { filter, setHighlightFile, fetchFiles } = this.filesStore; + const newFilter = filter.clone(); - this.setIsLoadedSearchFiles(false); + newFilter.page = 0; + newFilter.search = item.title; - if (this.itemOpenLocation?.title !== item.title) { - this.setSearchTitleOpenLocation(null); - } - - this.setItemOpenLocation(null); - - api.files - .getFolder(item.ExtraLocation, filterData) + fetchFiles(item.ExtraLocation, newFilter) .then(() => { - this.openLocationAction(item.ExtraLocation); - this.setSearchTitleOpenLocation(item.title); - this.setItemOpenLocation(item); + setHighlightFile({ + highlightFileId: item.id, + isFileHasExst: !item.fileExst, + }); }) .catch((err) => toastr.error(err)); }; diff --git a/packages/client/src/store/FilesStore.js b/packages/client/src/store/FilesStore.js index 8f5bf7b9b5..353e56d4cd 100644 --- a/packages/client/src/store/FilesStore.js +++ b/packages/client/src/store/FilesStore.js @@ -42,6 +42,7 @@ const PaymentRequiredHttpCode = 402; const UnauthorizedHttpCode = 401; const THUMBNAILS_CACHE = 500; +let timerId; class FilesStore { authStore; @@ -126,7 +127,8 @@ class FilesStore { isLoadedEmptyPage = false; isPreview = false; tempFilter = null; - uploadedFileIdWithVersion = null; + + highlightFile = {}; thumbnails = new Set(); constructor( @@ -476,8 +478,28 @@ class FilesStore { this.tempFilter = filser; }; - setUploadedFileIdWithVersion = (uploadedFileIdWithVersion) => { - this.uploadedFileIdWithVersion = uploadedFileIdWithVersion; + setHighlightFile = (highlightFile) => { + const { highlightFileId, isFileHasExst } = highlightFile; + + runInAction(() => { + this.highlightFile = { + id: highlightFileId, + isExst: isFileHasExst, + }; + }); + + if (timerId) { + clearTimeout(timerId); + timerId = null; + } + + if (Object.keys(highlightFile).length === 0) return; + + timerId = setTimeout(() => { + runInAction(() => { + this.highlightFile = {}; + }); + }, 1000); }; checkSelection = (file) => { @@ -2450,8 +2472,6 @@ class FilesStore { viewAccessability, } = item; - const upgradeVersion = id === this.uploadedFileIdWithVersion; - const thirdPartyIcon = this.thirdPartyStore.getThirdPartyIcon( item.providerKey, "small" @@ -2530,7 +2550,6 @@ class FilesStore { comment, contentLength, contextOptions, - upgradeVersion, created, createdBy, encrypted, diff --git a/packages/client/src/store/UploadDataStore.js b/packages/client/src/store/UploadDataStore.js index b935f8cc6a..a0fdc4563a 100644 --- a/packages/client/src/store/UploadDataStore.js +++ b/packages/client/src/store/UploadDataStore.js @@ -367,6 +367,8 @@ class UploadDataStore { isShareFolder, } = this.treeFoldersStore; + if (!this.converted) return; + const { storeOriginalFiles } = this.settingsStore; const isSortedFolder = isRecentFolder || isFavoritesFolder || isShareFolder; @@ -513,7 +515,7 @@ class UploadDataStore { } }); - storeOriginalFiles && this.refreshFiles(file); + storeOriginalFiles && fileInfo && this.refreshFiles(file); if (fileInfo && fileInfo !== "password") { file.fileInfo = fileInfo; @@ -540,8 +542,11 @@ class UploadDataStore { const percent = this.getConversationPercent(index + 1); this.setConversionPercent(percent, !!error); - if (file.fileInfo.version > 2) { - this.filesStore.setUploadedFileIdWithVersion(file.fileInfo.id); + if (!file.error && file.fileInfo.version > 2) { + this.filesStore.setHighlightFile({ + highlightFileId: file.fileInfo.id, + isFileHasExst: !file.fileInfo.fileExst, + }); } } } @@ -623,8 +628,9 @@ class UploadDataStore { }) > -1; if (hasFolder) { - if (this.uploaded) this.isParallel = false; - else { + if (this.uploaded) { + this.isParallel = false; + } else if (this.isParallel) { this.tempFiles.push({ uploadFiles, folderId, t }); return; } @@ -850,7 +856,7 @@ class UploadDataStore { newPercent = this.getFilesPercent(uploadedSize); } - const percentCurrentFile = (index / length) * 100; + const percentCurrentFile = ((index + 1) / length) * 100; const fileIndex = this.uploadedFilesHistory.findIndex( (f) => f.uniqueId === this.files[indexOfFile].uniqueId @@ -888,7 +894,10 @@ class UploadDataStore { }); if (fileInfo.version > 2) { - this.filesStore.setUploadedFileIdWithVersion(fileInfo.id); + this.filesStore.setHighlightFile({ + highlightFileId: fileInfo.id, + isFileHasExst: !fileInfo.fileExst, + }); } } } @@ -1130,8 +1139,9 @@ class UploadDataStore { if (!this.isParallel) return; const allFilesIsUploaded = - this.files.findIndex((f) => f.action !== "uploaded" && !f.error) === - -1; + this.files.findIndex( + (f) => f.action !== "uploaded" && f.action !== "convert" && !f.error + ) === -1; if (allFilesIsUploaded) { if (!this.filesToConversion.length) { diff --git a/packages/common/utils/combineUrl.js b/packages/common/utils/combineUrl.js index 2fc3d9193f..be855792b4 100644 --- a/packages/common/utils/combineUrl.js +++ b/packages/common/utils/combineUrl.js @@ -2,6 +2,7 @@ const combineUrl = (host = "", ...params) => { let url = host.replace(/\/+$/, ""); params.forEach((part) => { + if (!part) return; const newPart = part.trim().replace(/^\/+/, ""); url += newPart ? url.length > 0 && url[url.length - 1] === "/" diff --git a/packages/components/link/styled-link.js b/packages/components/link/styled-link.js index 370c6c02e0..cfe698807c 100644 --- a/packages/components/link/styled-link.js +++ b/packages/components/link/styled-link.js @@ -22,7 +22,12 @@ const PureText = ({ type, color, ...props }) => ; const StyledText = styled(PureText)` text-decoration: ${(props) => props.theme.link.textDecoration}; - ${(props) => !props.enableUserSelect && NoUserSelect} + ${(props) => + props.enableUserSelect + ? css` + user-select: text; + ` + : NoUserSelect} cursor: ${(props) => props.theme.link.cursor}; -webkit-tap-highlight-color: rgba(0, 0, 0, 0); diff --git a/packages/components/viewer/sub-components/viewer-player.js b/packages/components/viewer/sub-components/viewer-player.js index 40dde73de9..18876cbd7f 100644 --- a/packages/components/viewer/sub-components/viewer-player.js +++ b/packages/components/viewer/sub-components/viewer-player.js @@ -472,6 +472,7 @@ export default function ViewerPlayer(props) { } if (displayUI && props.isPlay && state.isFirstTap) { props.setIsPlay(false); + videoRef.current.pause(); return dispatch( createAction(ACTION_TYPES.update, { isFirstTap: false, @@ -535,6 +536,12 @@ export default function ViewerPlayer(props) { isFirstStart: false, }) ); + + if (!state.isPlaying) { + videoRef.current.play(); + } else { + videoRef.current.pause(); + } }; const handleVolumeUpdate = (e) => { @@ -734,6 +741,12 @@ export default function ViewerPlayer(props) { const lasting = `${currentTime} / ${duration}`; + if (progress === 100 || !state.isPlaying) { + videoRef.current.stop(); + } else { + videoRef.current.play(); + } + dispatch( createAction(ACTION_TYPES.update, { duration: lasting, @@ -827,10 +840,6 @@ export default function ViewerPlayer(props) { return () => window.removeEventListener("resize", handleResize); }, [videoRef.current, state.isFullScreen]); - React.useEffect(() => { - state.isPlaying ? videoRef.current.play() : videoRef.current.pause(); - }, [state.isPlaying, videoRef.current]); - React.useEffect(() => { if (videoRef && videoRef.current) { videoRef.current.addEventListener("error", (event) => { diff --git a/products/ASC.People/Server/Api/PhotoController.cs b/products/ASC.People/Server/Api/PhotoController.cs index 9f6fe265c5..2db22e9543 100644 --- a/products/ASC.People/Server/Api/PhotoController.cs +++ b/products/ASC.People/Server/Api/PhotoController.cs @@ -76,11 +76,22 @@ public class PhotoController : PeopleControllerBase if (!string.IsNullOrEmpty(inDto.TmpFile)) { var fileName = Path.GetFileName(inDto.TmpFile); - var data = await _userPhotoManager.GetTempPhotoData(fileName); + var data = await _userPhotoManager.GetTempPhotoData(fileName); + + UserPhotoThumbnailSettings settings = null; + + if (inDto.Width == 0 && inDto.Height == 0) + { + using var img = Image.Load(data, out var format); + settings = new UserPhotoThumbnailSettings(inDto.X, inDto.Y, img.Width, img.Height); + } + else + { + settings = new UserPhotoThumbnailSettings(inDto.X, inDto.Y, inDto.Width, inDto.Height); + } + + _settingsManager.Save(settings, user.Id); - var settings = new UserPhotoThumbnailSettings(inDto.X, inDto.Y, inDto.Width, inDto.Height); - - _settingsManager.Save(settings, user.Id); await _userPhotoManager.RemovePhoto(user.Id); await _userPhotoManager.SaveOrUpdatePhoto(user.Id, data); await _userPhotoManager.RemoveTempPhoto(fileName); diff --git a/products/ASC.People/Server/Api/UserController.cs b/products/ASC.People/Server/Api/UserController.cs index 352f4e6c0e..3769114ad6 100644 --- a/products/ASC.People/Server/Api/UserController.cs +++ b/products/ASC.People/Server/Api/UserController.cs @@ -186,7 +186,7 @@ public class UserController : PeopleControllerBase UpdateContacts(inDto.Contacts, user); _cache.Insert("REWRITE_URL" + _tenantManager.GetCurrentTenant().Id, HttpContext.Request.GetUrlRewriter().ToString(), TimeSpan.FromMinutes(5)); - user = await _userManagerWrapper.AddUser(user, inDto.PasswordHash, true, false, inDto.Type, + user = await _userManagerWrapper.AddUser(user, inDto.PasswordHash, true, false, inDto.Type, false, true, true); user.ActivationStatus = EmployeeActivationStatus.Activated; @@ -272,10 +272,10 @@ public class UserController : PeopleControllerBase user.WorkFromDate = inDto.Worksfrom != null && inDto.Worksfrom != DateTime.MinValue ? _tenantUtil.DateTimeFromUtc(inDto.Worksfrom) : DateTime.UtcNow.Date; UpdateContacts(inDto.Contacts, user, !inDto.FromInviteLink); - + _cache.Insert("REWRITE_URL" + _tenantManager.GetCurrentTenant().Id, HttpContext.Request.GetUrlRewriter().ToString(), TimeSpan.FromMinutes(5)); - - user = await _userManagerWrapper.AddUser(user, inDto.PasswordHash, inDto.FromInviteLink, true, inDto.Type, + + user = await _userManagerWrapper.AddUser(user, inDto.PasswordHash, inDto.FromInviteLink, true, inDto.Type, inDto.FromInviteLink && options is { IsCorrect: true }, true, true, byEmail); await UpdateDepartments(inDto.Department, user); @@ -308,7 +308,7 @@ public class UserController : PeopleControllerBase } [HttpPost("invite")] - public async IAsyncEnumerable InviteUsersAsync(InviteUsersRequestDto inDto) + public async Task> InviteUsersAsync(InviteUsersRequestDto inDto) { foreach (var invite in inDto.Invitations) { @@ -324,12 +324,16 @@ public class UserController : PeopleControllerBase _logger.Debug(link); } + var result = new List(); + var users = _userManager.GetUsers().Where(u => u.ActivationStatus == EmployeeActivationStatus.Pending); foreach (var user in users) { - yield return await _employeeDtoHelper.Get(user); + result.Add(await _employeeDtoHelper.Get(user)); } + + return result; } [HttpPut("{userid}/password")] @@ -1097,16 +1101,16 @@ public class UserController : PeopleControllerBase updatedUsers.Add(user); } } - - _messageService.Send(MessageAction.UsersUpdatedType, _messageTarget.Create(updatedUsers.Select(x => x.Id)), + + _messageService.Send(MessageAction.UsersUpdatedType, _messageTarget.Create(updatedUsers.Select(x => x.Id)), updatedUsers.Select(x => x.DisplayUserName(false, _displayUserSettingsHelper))); - + foreach (var user in users) { yield return await _employeeFullDtoHelper.GetFull(user); } } - + [HttpGet("recalculatequota")] public void RecalculateQuota() { @@ -1323,7 +1327,7 @@ public class UserController : PeopleControllerBase includeGroups.Add(new List { Constants.GroupAdmin.ID }); break; case EmployeeType.RoomAdmin: - excludeGroups.Add(Constants.GroupUser.ID); + excludeGroups.Add(Constants.GroupUser.ID); excludeGroups.Add(Constants.GroupAdmin.ID); excludeGroups.Add(Constants.GroupCollaborator.ID); break; diff --git a/public/locales/en/Common.json b/public/locales/en/Common.json index 844966ed78..415e3799ad 100644 --- a/public/locales/en/Common.json +++ b/public/locales/en/Common.json @@ -75,6 +75,7 @@ "Delete": "Delete", "Disconnect": "Disconnect", "DocSpaceAdmin": "DocSpace admin", + "DocSpaceOwner": "DocSpace owner", "Documents": "Documents", "DomainIpAddress": "Domains as IP addresses are not supported", "Done": "Done", diff --git a/public/locales/ru/Common.json b/public/locales/ru/Common.json index 5d590d0100..9ff011da66 100644 --- a/public/locales/ru/Common.json +++ b/public/locales/ru/Common.json @@ -75,6 +75,7 @@ "Delete": "Удалить", "Disconnect": "Отключить", "DocSpaceAdmin": "DocSpace администратор", + "DocSpaceOwner": "DocSpace владелец", "Documents": "Документы", "DomainIpAddress": "IP адрес в качестве домена не поддерживается", "Done": "Успешно", @@ -99,6 +100,7 @@ "FirstName": "Имя", "FullAccess": "Полный доступ", "Gigabyte": "Гб", + "HasFullAccess": "У него есть полный доступ в комнату", "HelpCenter": "Справочный центр", "HideArticleMenu": "Скрыть меню", "Hotkeys": "Горячие клавиши", diff --git a/public/scripts/browserDetector.js b/public/scripts/browserDetector.js index ec73a051e0..28c5546e6d 100644 --- a/public/scripts/browserDetector.js +++ b/public/scripts/browserDetector.js @@ -9,6 +9,7 @@ Edge: 107, Opera: 93, Safari: 13, + SafariMobile: 12, AscDesktopEditor: 6, SamsungBrowser: 3, }; @@ -47,6 +48,10 @@ match.splice(1, 1, temp[1]); } + if ((temp = agent.match(/mobile\/(\d+)/i)) != null) { + match[0] += "Mobile"; + } + return { name: match[0], version: match[1] }; })(); } diff --git a/web/ASC.Web.Core/Users/UserPhotoThumbnailManager.cs b/web/ASC.Web.Core/Users/UserPhotoThumbnailManager.cs index f2b35d58fe..b67d8f90f8 100644 --- a/web/ASC.Web.Core/Users/UserPhotoThumbnailManager.cs +++ b/web/ASC.Web.Core/Users/UserPhotoThumbnailManager.cs @@ -39,12 +39,7 @@ public static class UserPhotoThumbnailManager } public static async Task> SaveThumbnails(UserPhotoManager userPhotoManager, SettingsManager settingsManager, UserPhotoThumbnailSettings thumbnailSettings, Guid userId) - { - if (thumbnailSettings.Size.IsEmpty) - { - return null; - } - + { var thumbnailsData = new ThumbnailsData(userId, userPhotoManager); var resultBitmaps = new List(); @@ -55,6 +50,11 @@ public static class UserPhotoThumbnailManager { return null; } + + if (thumbnailSettings.Size.IsEmpty) + { + thumbnailSettings.Size = new Size(img.Width, img.Height); + } foreach (var thumbnail in await thumbnailsData.ThumbnailList()) {