Web:Files: move logic from virtual room page to home page

This commit is contained in:
TimofeyBoyko 2022-07-16 09:50:32 +03:00
parent 5074451a98
commit 8832aece23
33 changed files with 1618 additions and 538 deletions

View File

@ -12,8 +12,6 @@ export function getRooms(filter) {
res.files = decodeDisplayName(res.files);
res.folders = decodeDisplayName(res.folders);
res.folders.forEach((room) => (room.isRoom = !!room.roomType));
if (res.current.rootFolderType === FolderType.Archive) {
res.folders.forEach((room) => (room.isArchive = true));
}
@ -22,7 +20,7 @@ export function getRooms(filter) {
});
}
export function getRoom(id) {
export function getRoomInfo(id) {
const options = {
method: "get",
url: `/files/rooms/${id}`,
@ -59,10 +57,13 @@ export function unpinRoom(id) {
});
}
export function deleteRoom(id) {
export function deleteRoom(id, deleteAfter = true) {
const data = { deleteAfter };
const options = {
method: "delete",
url: `/files/rooms/${id}`,
data,
};
return request(options).then((res) => {
@ -70,10 +71,13 @@ export function deleteRoom(id) {
});
}
export function archiveRoom(id) {
export function archiveRoom(id, deleteAfter = true) {
const data = { deleteAfter };
const options = {
method: "put",
url: `/files/rooms/${id}/archive`,
data,
};
return request(options).then((res) => {
@ -81,10 +85,12 @@ export function archiveRoom(id) {
});
}
export function unarchiveRoom(id) {
export function unarchiveRoom(id, deleteAfter = true) {
const data = { deleteAfter };
const options = {
method: "put",
url: `/files/rooms/${id}/unarchive`,
data,
};
return request(options).then((res) => {

View File

@ -29,43 +29,28 @@ const Tags = ({ id, className, style, tags, columnCount, onSelectTag }) => {
newTags.push(tag);
}
} else {
if (tags.length === columnCount + 1 && columnCount !== 0) {
const currentTagMaxWidth =
(containerWidth - tags.length * 4) / tags.length;
const tagWithDropdown = {
key: "selector",
advancedOptions: tags.slice(columnCount, tags.length),
};
const maxWidthPercent = Math.ceil(
(currentTagMaxWidth / containerWidth) * 100
);
const currentTagMaxWidth =
(containerWidth - columnCount * 4 - 35) / columnCount;
for (let i = 0; i < tags.length; i++) {
const maxWidthPercent = Math.ceil(
(currentTagMaxWidth / containerWidth) * 100
);
if (columnCount !== 0) {
for (let i = 0; i < columnCount; i++) {
const tag = { name: tags[i], maxWidth: `${maxWidthPercent}%` };
newTags.push(tag);
}
} else {
const tagWithDropdown = {
key: "selector",
advancedOptions: tags.slice(columnCount, tags.length),
};
const currentTagMaxWidth =
(containerWidth - columnCount * 4 - 35) / columnCount;
const maxWidthPercent = Math.ceil(
(currentTagMaxWidth / containerWidth) * 100
);
if (columnCount !== 0) {
for (let i = 0; i < columnCount; i++) {
const tag = { name: tags[i], maxWidth: `${maxWidthPercent}%` };
newTags.push(tag);
}
}
newTags.push(tagWithDropdown);
newTags[newTags.length - 1].maxWidth = `35px`;
}
newTags.push(tagWithDropdown);
newTags[newTags.length - 1].maxWidth = `35px`;
}
setRenderedTags(newTags);

View File

@ -60,7 +60,7 @@ const Tag = ({
{!!advancedOptions ? (
<StyledTag
id={id}
className={`tag${className ? ` ${className}` : ""}`}
className={`tag advanced-tag ${className ? ` ${className}` : ""}`}
style={style}
ref={tagRef}
onClick={toggleDropdown}

View File

@ -96,8 +96,9 @@ const FilesSection = React.memo(() => {
<PrivateRoute exact path={HOME_URL} component={Home} />
<PrivateRoute path={FILTER_URL} component={Home} />
<PrivateRoute path={MEDIA_VIEW_URL} component={Home} />
<PrivateRoute path={ROOMS_URL} component={Home} />
<PrivateRoute path={FORM_GALLERY_URL} component={FormGallery} />
<PrivateRoute path={ROOMS_URL} component={VirtualRooms} />
{/* <PrivateRoute path={ROOMS_URL} component={VirtualRooms} /> */}
<PrivateRoute component={Error404Route} />
</Switch>
);

View File

@ -36,6 +36,16 @@ export default function withBadges(WrappedComponent) {
}
};
onUnpinClick = (e) => {
const { setPinAction } = this.props;
const { action, id } = e.target.closest(".is-pinned").dataset;
if (!action && !id) return;
setPinAction(action, id);
};
setConvertDialogVisible = () => {
this.props.setConvertItem(this.props.item);
this.props.setConvertDialogVisible(true);
@ -83,6 +93,7 @@ export default function withBadges(WrappedComponent) {
accessToEdit={accessToEdit}
onShowVersionHistory={this.onShowVersionHistory}
onBadgeClick={this.onBadgeClick}
onUnpinClick={this.onUnpinClick}
setConvertDialogVisible={this.setConvertDialogVisible}
onFilesClick={onFilesClick}
viewAs={viewAs}
@ -109,7 +120,7 @@ export default function withBadges(WrappedComponent) {
{ item }
) => {
const { isRecycleBinFolder, isPrivacyFolder } = treeFoldersStore;
const { markAsRead } = filesActionsStore;
const { markAsRead, setPinAction } = filesActionsStore;
const { isTabletView, isDesktopClient, theme } = auth.settingsStore;
const { setIsVerHistoryPanel, fetchFileVersions } = versionHistoryStore;
const {
@ -139,6 +150,7 @@ export default function withBadges(WrappedComponent) {
setConvertDialogVisible,
setConvertItem,
isDesktopClient,
setPinAction,
};
}
)(observer(WithBadges));

View File

@ -52,6 +52,7 @@ export default function withContent(WrappedContent) {
element,
isDesktop,
isTrashFolder,
isArchiveFolder,
item,
onFilesClick,
t,
@ -99,6 +100,7 @@ export default function withContent(WrappedContent) {
showNew={showNew}
isTrashFolder={isTrashFolder}
onFilesClick={onFilesClick}
isArchiveFolder={isArchiveFolder}
{...this.props}
/>
);
@ -134,7 +136,11 @@ export default function withContent(WrappedContent) {
setCreatedItem,
} = filesStore;
const { clearActiveOperations, fileCopyAs } = uploadDataStore;
const { isRecycleBinFolder, isPrivacyFolder } = treeFoldersStore;
const {
isRecycleBinFolder,
isPrivacyFolder,
isArchiveFolder,
} = treeFoldersStore;
const { replaceFileStream, setEncryptionAccess } = auth;
@ -164,6 +170,7 @@ export default function withContent(WrappedContent) {
isDesktop: isDesktopClient,
isPrivacy: isPrivacyFolder,
isTrashFolder: isRecycleBinFolder,
isArchiveFolder,
openDocEditor,
renameFolder,
replaceFileStream,

View File

@ -125,7 +125,8 @@ export default function withFileActions(WrappedFileItem) {
e.target.closest(".expandButton") ||
e.target.querySelector(".expandButton") ||
e.target.closest(".badges") ||
e.target.closest(".not-selectable")
e.target.closest(".not-selectable") ||
e.target.closest(".tag")
)
return;
@ -137,12 +138,21 @@ export default function withFileActions(WrappedFileItem) {
};
onFilesClick = (e) => {
const { item, openFileAction, setParentId, isTrashFolder } = this.props;
const {
item,
openFileAction,
setParentId,
isTrashFolder,
isArchiveFolder,
} = this.props;
if (
(e && e.target.tagName === "INPUT") ||
!!e.target.closest(".lock-file") ||
!!e.target.closest(".additional-badges") ||
isTrashFolder
e.target.closest(".tag") ||
isTrashFolder ||
isArchiveFolder
)
return;
@ -160,6 +170,10 @@ export default function withFileActions(WrappedFileItem) {
openFileAction(item);
};
onSelectTag = (tag) => {
this.props.selectTag(tag);
};
getContextModel = () => {
const { getModel, item, t } = this.props;
return getModel(item, t);
@ -220,6 +234,7 @@ export default function withFileActions(WrappedFileItem) {
onFilesClick={this.onFilesClick}
onMouseClick={this.onMouseClick}
onHideContextMenu={this.onHideContextMenu}
onSelectTag={this.onSelectTag}
getClassName={this.getClassName}
className={className}
isDragging={isDragging}
@ -253,6 +268,7 @@ export default function withFileActions(WrappedFileItem) {
) => {
const {
selectRowAction,
selectTag,
onSelectItem,
setNewBadgeCount,
openFileAction,
@ -262,6 +278,8 @@ export default function withFileActions(WrappedFileItem) {
const {
isPrivacyFolder,
isRecycleBinFolder,
isRoomsFolder,
isArchiveFolder,
//addExpandedKeys,
} = treeFoldersStore;
const {
@ -318,8 +336,11 @@ export default function withFileActions(WrappedFileItem) {
item,
selectRowAction,
onSelectItem,
selectTag,
setSharingPanelVisible,
isPrivacy: isPrivacyFolder,
isRoomsFolder,
isArchiveFolder,
dragging,
setDragging,
startUpload,

View File

@ -54,6 +54,7 @@ const ArticleBodyContent = (props) => {
fetchFiles,
fetchRooms,
setAlreadyFetchingRooms,
homepage,
history,
@ -69,7 +70,10 @@ const ArticleBodyContent = (props) => {
showLoader();
}
console.log(data, roomsFolderId,archiveFolderId, data === roomsFolderId, data === archiveFolderId )
if (data === roomsFolderId || data === archiveFolderId) {
setAlreadyFetchingRooms(true);
fetchRooms(data, null)
.then(() => {
if (filesSection) {
@ -169,6 +173,7 @@ export default inject(
const {
fetchFiles,
fetchRooms,
setAlreadyFetchingRooms,
setIsLoading,
setFirstLoad,
firstLoad,
@ -215,6 +220,7 @@ export default inject(
homepage: config.homepage,
fetchRooms,
setAlreadyFetchingRooms,
personal,
docSpace,

View File

@ -21,10 +21,29 @@ const StyledEditIcon = styled(IconButton)`
}
`;
const StyledPinIcon = styled(IconButton)`
${commonIconsStyles}
svg {
path {
fill: ${(props) => props.theme.filesSection.rowView.editingIconColor};
}
}
:hover {
svg {
path {
fill: ${(props) => props.theme.filesSection.rowView.editingIconColor};
}
}
}
`;
const StyledWrapper = styled.div`
display: flex;
justify-content: center;
align-items: center;
background: ${(props) => props.theme.filesBadges.color};
padding: 6px;
border-radius: 4px;
@ -77,8 +96,18 @@ const Badges = ({
onBadgeClick,
setConvertDialogVisible,
viewAs,
onUnpinClick,
}) => {
const { id, locked, version, versionGroup, fileExst, isEditing } = item;
const {
id,
locked,
version,
versionGroup,
fileExst,
isEditing,
isRoom,
pinned,
} = item;
const showEditBadge = !locked || item.access === 0;
const isPrivacy = isPrivacyFolder && isDesktopClient;
@ -111,6 +140,13 @@ const Badges = ({
const iconRefresh = "/static/images/refresh.react.svg";
const iconPin = "images/unpin.react.svg";
const unpinIconProps = {
"data-id": id,
"data-action": "unpin",
};
const commonBadgeProps = {
borderRadius: "11px",
color: theme.filesBadges.color,
@ -179,15 +215,26 @@ const Badges = ({
)}
</div>
) : (
showNew && (
<Badge
{...commonBadgeProps}
className="new-items tablet-badge"
backgroundColor={theme.filesBadges.badgeBackgroundColor}
label={contentNewItems}
onClick={onBadgeClick}
/>
)
<>
{isRoom && pinned && (
<StyledPinIcon
onClick={onUnpinClick}
className="badge icons-group is-pinned tablet-badge tablet-pinned"
iconName={iconPin}
size={sizeBadge}
{...unpinIconProps}
/>
)}
{showNew && (
<Badge
{...commonBadgeProps}
className="new-items tablet-badge"
backgroundColor={theme.filesBadges.badgeBackgroundColor}
label={contentNewItems}
onClick={onBadgeClick}
/>
)}
</>
);
};

View File

@ -14,12 +14,15 @@ const RootFolderContainer = (props) => {
theme,
isPrivacyFolder,
isRecycleBinFolder,
isRoomsFolder,
isArchiveFolder,
isDesktop,
isEncryptionSupport,
organizationName,
privacyInstructions,
title,
onCreate,
onCreateRoom,
myFolderId,
filter,
fetchFiles,
@ -37,6 +40,8 @@ const RootFolderContainer = (props) => {
const trashDescription = t("TrashEmptyDescription");
const favoritesDescription = t("FavoritesEmptyContainerDescription");
const recentDescription = t("RecentEmptyContainerDescription");
const roomsDescription = "Please create the first room.";
const archiveRoomsDescription = "Archive rooms empty";
const privateRoomHeader = t("PrivateRoomHeader");
const privacyIcon = <img alt="" src="images/privacy.svg" />;
@ -101,6 +106,18 @@ const RootFolderContainer = (props) => {
: "images/empty_screen_trash_alt.png",
buttons: trashButtons,
};
case FolderType.Rooms:
return {
headerText: "Welcome to DocSpace!",
descriptionText: roomsDescription,
imageSrc: "images/empty_screen_corporate.png",
buttons: roomsButtons,
};
case FolderType.Archive:
return {
descriptionText: archiveRoomsDescription,
imageSrc: "images/empty_screen_corporate.png",
};
default:
break;
}
@ -195,9 +212,25 @@ const RootFolderContainer = (props) => {
</div>
);
const roomsButtons = (
<div className="empty-folder_container-links">
<img
className="empty-folder_container_plus-image"
src="images/plus.svg"
onClick={onCreateRoom}
alt="plus_icon"
/>
<Link onClick={onCreateRoom} {...linkStyles}>
Create room
</Link>
</div>
);
const headerText = isPrivacyFolder ? privateRoomHeader : title;
const subheadingTextProp =
isPrivacyFolder || isRecycleBinFolder ? {} : { subheadingText };
isPrivacyFolder || isRecycleBinFolder || isRoomsFolder || isArchiveFolder
? {}
: { subheadingText };
const emptyFolderProps = getEmptyFolderProps();
React.useEffect(() => {
@ -253,12 +286,16 @@ export default inject(
isPrivacyFolder,
myFolderId,
isRecycleBinFolder,
isRoomsFolder,
isArchiveFolder,
} = treeFoldersStore;
return {
theme,
isPrivacyFolder,
isRecycleBinFolder,
isRoomsFolder,
isArchiveFolder,
isDesktop: isDesktopClient,
isEncryptionSupport,
organizationName,

View File

@ -15,13 +15,7 @@ const linkStyles = {
display: "flex",
};
const EmptyContainer = ({
isFiltered,
isPrivacyFolder,
parentId,
isEncryptionSupport,
theme,
}) => {
const EmptyContainer = ({ isFiltered, parentId, theme }) => {
linkStyles.color = theme.filesEmptyContainer.linkColor;
const onCreate = (e) => {
@ -38,12 +32,20 @@ const EmptyContainer = ({
window.dispatchEvent(event);
};
const onCreateRoom = (e) => {
console.log("create room");
};
return isFiltered ? (
<EmptyFilterContainer linkStyles={linkStyles} />
) : parentId === 0 ? (
<RootFolderContainer onCreate={onCreate} linkStyles={linkStyles} />
) : (
<EmptyFolderContainer onCreate={onCreate} linkStyles={linkStyles} />
<EmptyFolderContainer
onCreate={onCreate}
onCreateRoom={onCreateRoom}
linkStyles={linkStyles}
/>
);
};
@ -55,16 +57,16 @@ export default inject(
withSubfolders,
filterType,
} = filesStore.filter;
const isPrivacyFolder = treeFoldersStore.isPrivacyFolder;
const { isPrivacyFolder } = treeFoldersStore;
const isFiltered =
(authorType || search || !withSubfolders || filterType) &&
!(isPrivacyFolder && isMobile);
return {
isEncryptionSupport: auth.settingsStore.isEncryptionSupport,
theme: auth.settingsStore.theme,
isFiltered,
isPrivacyFolder,
parentId: selectedFolderStore.parentId,
};
}

View File

@ -1,11 +1,17 @@
import React from "react";
import { inject, observer } from "mobx-react";
import styled from "styled-components";
import styled, { css } from "styled-components";
const StyledIcon = styled.img`
/* width: 24px;
height: 24px;
margin-top: 4px; */
${(props) =>
props.isRoom &&
css`
border-radius: 6px;
`}
`;
const EncryptedFileIcon = styled.div`
@ -23,6 +29,7 @@ const ItemIcon = ({
fileExst,
isPrivacy,
viewAs,
isRoom,
// actionType,
// actionExtension,
// actionId,
@ -45,7 +52,7 @@ const ItemIcon = ({
return (
<>
<StyledIcon className={`react-svg-icon`} src={icon} />
<StyledIcon className={`react-svg-icon`} isRoom={isRoom} src={icon} />
{isPrivacy && fileExst && <EncryptedFileIcon isEdit={false} />}
</>
);

View File

@ -95,8 +95,15 @@ const FilesRowContent = ({
foldersCount,
providerKey,
title,
isRoom,
} = item;
let tags = null;
if (isRoom && item.tags.length > 0) {
tags = item?.tags.join(" | ");
}
return (
<>
<SimpleFilesRowContent
@ -119,20 +126,20 @@ const FilesRowContent = ({
</Link>
<div className="badges">
{badgesComponent}
{quickButtons}
{!isRoom && quickButtons}
</div>
<Text
containerMinWidth="200px"
containerWidth="15%"
fontSize="12px"
fontWeight={400}
// color={sideColor}
className="row_update-text"
>
{updatedDate && updatedDate}
</Text>
{!isRoom && (
<Text
containerMinWidth="200px"
containerWidth="15%"
fontSize="12px"
fontWeight={400}
// color={sideColor}
className="row_update-text"
>
{updatedDate && updatedDate}
</Text>
)}
<Text
containerMinWidth="90px"
containerWidth="10%"
@ -143,7 +150,9 @@ const FilesRowContent = ({
title=""
truncate={true}
>
{!fileExst && !contentLength && !providerKey && !isMobileOnly
{isRoom && tags
? tags
: !fileExst && !contentLength && !providerKey && !isMobileOnly
? `${foldersCount} ${t("Folders")} | ${filesCount} ${t("Files")}`
: fileExst
? `${fileExst.toUpperCase().replace(/^\./, "")}`

View File

@ -228,7 +228,12 @@ const SimpleFilesRow = (props) => {
const isSmallContainer = sectionWidth <= 500;
const element = (
<ItemIcon id={item.id} icon={item.icon} fileExst={item.fileExst} />
<ItemIcon
id={item.id}
icon={item.icon}
fileExst={item.fileExst}
isRoom={item.isRoom}
/>
);
return (

View File

@ -1,4 +1,5 @@
import React, { useEffect, useRef } from "react";
import elementResizeDetectorMaker from "element-resize-detector";
import TableContainer from "@appserver/components/table-container";
import { inject, observer } from "mobx-react";
import TableRow from "./TableRow";
@ -103,6 +104,11 @@ const TABLE_COLUMNS = `filesTableColumns_ver-${TABLE_VERSION}`;
const COLUMNS_SIZE = `filesColumnsSize_ver-${TABLE_VERSION}`;
const COLUMNS_SIZE_INFO_PANEL = `filesColumnsSizeInfoPanel_ver-${TABLE_VERSION}`;
const TABLE_ROOMS_VERSION = "1";
const TABLE_ROOMS_COLUMNS = `roomsTableColumns_ver-${TABLE_ROOMS_VERSION}`;
const COLUMNS_ROOMS_SIZE = `roomsColumnsSize_ver-${TABLE_ROOMS_VERSION}`;
const COLUMNS_ROOMS_SIZE_INFO_PANEL = `roomsColumnsSizeInfoPanel_ver-${TABLE_ROOMS_VERSION}`;
const Table = ({
filesList,
sectionWidth,
@ -113,8 +119,12 @@ const Table = ({
theme,
infoPanelVisible,
userId,
isRooms,
}) => {
const [tagCount, setTagCount] = React.useState(null);
const ref = useRef(null);
const tagRef = useRef(null);
useEffect(() => {
if ((viewAs !== "table" && viewAs !== "row") || !setViewAs) return;
@ -131,9 +141,44 @@ const Table = ({
}
}, [sectionWidth]);
const tableColumns = `${TABLE_COLUMNS}=${userId}`;
const columnStorageName = `${COLUMNS_SIZE}=${userId}`;
const columnInfoPanelStorageName = `${COLUMNS_SIZE_INFO_PANEL}=${userId}`;
React.useEffect(() => {
if (!tagRef?.current) return;
onResize();
const elementResizeDetector = elementResizeDetectorMaker({
strategy: "scroll",
callOnAdd: false,
});
elementResizeDetector.listenTo(tagRef.current, onResize);
return () => {
if (!tagRef?.current) return;
elementResizeDetector.uninstall(tagRef.current);
};
}, [tagRef, filesList]);
const onResize = React.useCallback(() => {
if (tagRef?.current) {
const { width } = tagRef.current.getBoundingClientRect();
const columns = Math.floor(width / 100);
if (columns != tagCount) setTagCount(columns);
}
}, [tagRef, tagCount]);
const tableColumns = isRooms
? `${TABLE_ROOMS_COLUMNS}=${userId}`
: `${TABLE_COLUMNS}=${userId}`;
const columnStorageName = isRooms
? `${COLUMNS_ROOMS_SIZE}=${userId}`
: `${COLUMNS_SIZE}=${userId}`;
const columnInfoPanelStorageName = isRooms
? `${COLUMNS_ROOMS_SIZE_INFO_PANEL}=${userId}`
: `${COLUMNS_SIZE_INFO_PANEL}=${userId}`;
return (
<StyledTableContainer forwardedRef={ref}>
@ -143,30 +188,53 @@ const Table = ({
tableStorageName={tableColumns}
columnStorageName={columnStorageName}
columnInfoPanelStorageName={columnInfoPanelStorageName}
isRooms={isRooms}
/>
<TableBody>
{filesList.map((item, index) => (
<TableRow
id={`${item?.isFolder ? "folder" : "file"}_${item.id}`}
key={`${item.id}_${index}`}
item={item}
index={index}
setFirsElemChecked={setFirsElemChecked}
setHeaderBorder={setHeaderBorder}
theme={theme}
tableColumns={tableColumns}
columnStorageName={columnStorageName}
columnInfoPanelStorageName={columnInfoPanelStorageName}
/>
))}
{filesList.map((item, index) => {
return index === 0 && item.isRoom ? (
<TableRow
id={`${item?.isFolder ? "folder" : "file"}_${item.id}`}
key={`${item.id}_${index}`}
item={item}
index={index}
setFirsElemChecked={setFirsElemChecked}
setHeaderBorder={setHeaderBorder}
theme={theme}
tableColumns={tableColumns}
columnStorageName={columnStorageName}
columnInfoPanelStorageName={columnInfoPanelStorageName}
tagRef={tagRef}
tagCount={tagCount}
/>
) : (
<TableRow
id={`${item?.isFolder ? "folder" : "file"}_${item.id}`}
key={`${item.id}_${index}`}
item={item}
index={index}
setFirsElemChecked={setFirsElemChecked}
setHeaderBorder={setHeaderBorder}
theme={theme}
tableColumns={tableColumns}
columnStorageName={columnStorageName}
columnInfoPanelStorageName={columnInfoPanelStorageName}
tagCount={tagCount}
/>
);
})}
</TableBody>
</StyledTableContainer>
);
};
export default inject(({ filesStore, auth }) => {
export default inject(({ filesStore, treeFoldersStore, auth }) => {
const { isVisible: infoPanelVisible } = auth.infoPanelStore;
const { isRoomsFolder, isArchiveFolder } = treeFoldersStore;
const isRooms = isRoomsFolder || isArchiveFolder;
const {
filesList,
viewAs,
@ -184,5 +252,7 @@ export default inject(({ filesStore, auth }) => {
theme: auth.settingsStore.theme,
userId: auth.userStore.user.id,
infoPanelVisible,
isRooms,
};
})(observer(Table));

View File

@ -7,80 +7,139 @@ class FilesTableHeader extends React.Component {
constructor(props) {
super(props);
const { t, personal, tableStorageName } = props;
const { t, personal, tableStorageName, isRooms } = props;
const defaultColumns = [
{
key: "Name",
title: t("Common:Name"),
resizable: true,
enable: true,
default: true,
sortBy: "AZ",
minWidth: 210,
onClick: this.onFilter,
},
{
key: "Author",
title: t("ByAuthor"),
enable: false,
resizable: true,
sortBy: "Author",
onClick: this.onFilter,
onChange: this.onColumnChange,
},
{
key: "Created",
title: t("ByCreationDate"),
enable: true,
resizable: true,
sortBy: "DateAndTimeCreation",
onClick: this.onFilter,
onChange: this.onColumnChange,
},
{
key: "Modified",
title: t("ByLastModifiedDate"),
enable: true,
resizable: true,
sortBy: "DateAndTime",
onClick: this.onFilter,
onChange: this.onColumnChange,
},
{
key: "Size",
title: t("Common:Size"),
enable: true,
resizable: true,
sortBy: "Size",
onClick: this.onFilter,
onChange: this.onColumnChange,
},
{
key: "Type",
title: t("Common:Type"),
enable: true,
resizable: true,
sortBy: "Type",
onClick: this.onFilter,
onChange: this.onColumnChange,
},
{
key: "QuickButtons",
title: "",
enable: true,
defaultSize: 75,
resizable: false,
},
];
const defaultColumns = [];
if (isRooms) {
const columns = [
{
key: "Name",
title: "Name",
resizable: true,
enable: true,
default: true,
sortBy: "AZ",
minWidth: 210,
onClick: this.onRoomsFilter,
},
{
key: "Type",
title: "Type",
enable: false,
resizable: true,
sortBy: "Type",
onChange: this.onColumnChange,
onClick: this.onRoomsFilter,
},
{
key: "Tags",
title: "Tags",
enable: true,
resizable: true,
sortBy: "Tags",
onChange: this.onColumnChange,
onClick: this.onRoomsFilter,
},
{
key: "Owner",
title: "Owner",
enable: false,
resizable: true,
sortBy: "Author",
onChange: this.onColumnChange,
onClick: this.onRoomsFilter,
},
{
key: "Activity",
title: "Last activity",
enable: true,
resizable: true,
sortBy: "DateAndTime",
onChange: this.onColumnChange,
onClick: this.onRoomsFilter,
},
];
personal && defaultColumns.splice(1, 1);
defaultColumns.push(...columns);
} else {
const columns = [
{
key: "Name",
title: t("Common:Name"),
resizable: true,
enable: true,
default: true,
sortBy: "AZ",
minWidth: 210,
onClick: this.onFilter,
},
{
key: "Author",
title: t("ByAuthor"),
enable: false,
resizable: true,
sortBy: "Author",
onClick: this.onFilter,
onChange: this.onColumnChange,
},
{
key: "Created",
title: t("ByCreationDate"),
enable: true,
resizable: true,
sortBy: "DateAndTimeCreation",
onClick: this.onFilter,
onChange: this.onColumnChange,
},
{
key: "Modified",
title: t("ByLastModifiedDate"),
enable: true,
resizable: true,
sortBy: "DateAndTime",
onClick: this.onFilter,
onChange: this.onColumnChange,
},
{
key: "Size",
title: t("Common:Size"),
enable: true,
resizable: true,
sortBy: "Size",
onClick: this.onFilter,
onChange: this.onColumnChange,
},
{
key: "Type",
title: t("Common:Type"),
enable: true,
resizable: true,
sortBy: "Type",
onClick: this.onFilter,
onChange: this.onColumnChange,
},
{
key: "QuickButtons",
title: "",
enable: true,
defaultSize: 75,
resizable: false,
},
];
personal && columns.splice(1, 1);
defaultColumns.push(...columns);
}
const storageColumns = localStorage.getItem(tableStorageName);
const splitColumns = storageColumns && storageColumns.split(",");
const columns = this.getColumns(defaultColumns, splitColumns);
const resetColumnsSize =
(splitColumns && splitColumns.length !== columns.length) || !splitColumns;
(splitColumns && splitColumns.length !== columns.length) ||
!splitColumns ||
isRooms;
const tableColumns = columns.map((c) => c.enable && c.key);
this.setTableColumns(tableColumns);
@ -191,11 +250,33 @@ class FilesTableHeader extends React.Component {
fetchFiles(selectedFolderId, newFilter).finally(() => setIsLoading(false));
};
onRoomsFilter = (sortBy) => {
const {
roomsFilter,
selectedFolderId,
setIsLoading,
fetchRooms,
} = this.props;
const newFilter = roomsFilter.clone();
if (newFilter.sortBy !== sortBy) {
newFilter.sortBy = sortBy;
} else {
newFilter.sortOrder =
newFilter.sortOrder === "ascending" ? "descending" : "ascending";
}
setIsLoading(true);
fetchRooms(selectedFolderId, newFilter).finally(() => setIsLoading(false));
};
render() {
const {
containerRef,
isHeaderChecked,
filter,
roomsFilter,
isRooms,
sectionWidth,
firstElemChecked,
sortingVisible,
@ -204,9 +285,12 @@ class FilesTableHeader extends React.Component {
columnInfoPanelStorageName,
} = this.props;
const { sortBy, sortOrder } = filter;
// const { sortBy, sortOrder } = filter;
const { columns, resetColumnsSize } = this.state;
const sortBy = isRooms ? roomsFilter.sortBy : filter.sortBy;
const sortOrder = isRooms ? roomsFilter.sortOrder : filter.sortOrder;
return (
<TableHeader
isLengthenHeader={firstElemChecked || isHeaderChecked}
@ -238,6 +322,9 @@ export default inject(
canShare,
firstElemChecked,
headerBorder,
roomsFilter,
fetchRooms,
} = filesStore;
const { isPrivacyFolder, isRecentFolder } = treeFoldersStore;
@ -256,6 +343,9 @@ export default inject(
setIsLoading,
fetchFiles,
roomsFilter,
fetchRooms,
firstElemChecked,
headerBorder,

View File

@ -14,6 +14,7 @@ import SizeCell from "./sub-components/SizeCell";
import AuthorCell from "./sub-components/AuthorCell";
import DateCell from "./sub-components/DateCell";
import TypeCell from "./sub-components/TypeCell";
import TagsCell from "./sub-components/TagsCell";
import styled, { css } from "styled-components";
import Base from "@appserver/components/themes/base";
@ -44,6 +45,18 @@ const contextMenuWrapperDraggingStyle = css`
`;
const StyledTableRow = styled(TableRow)`
${(props) =>
props.isRoom &&
css`
.table-container_cell {
height: 48px;
max-height: 48px;
}
.table-container_row-checkbox {
padding-left: 20px !important;
}
`}
${(props) =>
!props.isDragging &&
css`
@ -71,7 +84,6 @@ const StyledTableRow = styled(TableRow)`
}
}
`}
.table-container_cell {
background: ${(props) =>
(props.checked || props.isActive) &&
@ -98,7 +110,7 @@ const StyledTableRow = styled(TableRow)`
.table-container_element-wrapper,
.table-container_row-loader {
min-width: 36px;
min-width: ${(props) => (props.isRoom ? "40px" : "36px")};
}
.table-container_row-loader {
@ -108,7 +120,7 @@ const StyledTableRow = styled(TableRow)`
}
.table-container_row-checkbox {
padding-left: 16px;
padding-left: ${(props) => (props.isRoom ? "20px" : "16px")};
width: 16px;
}
@ -273,11 +285,17 @@ const FilesTableRow = (props) => {
showHotkeyBorder,
tableColumns,
id,
tagRef,
} = props;
const { acceptBackground, background } = theme.dragAndDrop;
const element = (
<ItemIcon id={item.id} icon={item.icon} fileExst={item.fileExst} />
<ItemIcon
id={item.id}
icon={item.icon}
fileExst={item.fileExst}
isRoom={item.isRoom}
/>
);
const selectionProp = {
@ -384,6 +402,7 @@ const FilesTableRow = (props) => {
? t("Translations:TitleShowFolderActions")
: t("Translations:TitleShowActions")
}
isRoom={item.isRoom}
>
<TableCell
{...dragStyles}
@ -400,6 +419,38 @@ const FilesTableRow = (props) => {
/>
<StyledBadgesContainer>{badgesComponent}</StyledBadgesContainer>
</TableCell>
{item.isRoom && (
<TableCell
style={
!typeAvailableDrag
? { background: "none !important" }
: dragStyles.style
}
{...selectionProp}
>
<TypeCell
sideColor={theme.filesSection.tableView.row.sideColor}
{...props}
/>
</TableCell>
)}
{item.isRoom && (
<TableCell
style={
!typeAvailableDrag
? { background: "none !important" }
: dragStyles.style
}
{...selectionProp}
>
<TagsCell
sideColor={theme.filesSection.tableView.row.sideColor}
ref={tagRef}
{...props}
/>
</TableCell>
)}
{!personal && (
<TableCell
style={
@ -413,20 +464,24 @@ const FilesTableRow = (props) => {
/>
</TableCell>
)}
<TableCell
style={
!createdAvailableDrag
? { background: "none !important" }
: dragStyles.style
}
{...selectionProp}
>
<DateCell
create
sideColor={theme.filesSection.tableView.row.sideColor}
{...props}
/>
</TableCell>
{!item.isRoom && (
<TableCell
style={
!createdAvailableDrag
? { background: "none !important" }
: dragStyles.style
}
{...selectionProp}
>
<DateCell
create
sideColor={theme.filesSection.tableView.row.sideColor}
{...props}
/>
</TableCell>
)}
<TableCell
style={
!modifiedAvailableDrag ? { background: "none" } : dragStyles.style
@ -438,41 +493,49 @@ const FilesTableRow = (props) => {
{...props}
/>
</TableCell>
<TableCell
style={!sizeAvailableDrag ? { background: "none" } : dragStyles.style}
{...selectionProp}
>
<SizeCell
sideColor={theme.filesSection.tableView.row.sideColor}
{...props}
/>
</TableCell>
<TableCell
style={
!typeAvailableDrag
? { background: "none !important" }
: dragStyles.style
}
{...selectionProp}
>
<TypeCell
sideColor={theme.filesSection.tableView.row.sideColor}
{...props}
/>
</TableCell>
{!item.isRoom && (
<TableCell
style={
!sizeAvailableDrag ? { background: "none" } : dragStyles.style
}
{...selectionProp}
>
<SizeCell
sideColor={theme.filesSection.tableView.row.sideColor}
{...props}
/>
</TableCell>
)}
<TableCell
style={
!buttonsAvailableDrag ? { background: "none" } : dragStyles.style
}
{...selectionProp}
className={`${selectionProp?.className} table-container_quick-buttons-wrapper`}
>
<StyledQuickButtonsContainer>
{quickButtonsComponent}
</StyledQuickButtonsContainer>
</TableCell>
{!item.isRoom && (
<TableCell
style={
!typeAvailableDrag
? { background: "none !important" }
: dragStyles.style
}
{...selectionProp}
>
<TypeCell
sideColor={theme.filesSection.tableView.row.sideColor}
{...props}
/>
</TableCell>
)}
{!item.isRoom && (
<TableCell
style={
!buttonsAvailableDrag ? { background: "none" } : dragStyles.style
}
{...selectionProp}
className={`${selectionProp?.className} table-container_quick-buttons-wrapper`}
>
<StyledQuickButtonsContainer>
{quickButtonsComponent}
</StyledQuickButtonsContainer>
</TableCell>
)}
</StyledTableRow>
</StyledDragAndDrop>
);

View File

@ -0,0 +1,13 @@
import React from "react";
import Tags from "@appserver/common/components/Tags";
const TagsCell = React.forwardRef(({ item, tagCount, onSelectTag }, ref) => {
return (
<div style={{ width: "100%" }} ref={ref}>
<Tags tags={item.tags} columnCount={tagCount} onSelectTag={onSelectTag} />
</div>
);
});
export default React.memo(TagsCell);

View File

@ -1,9 +1,9 @@
import React from "react";
import { StyledText } from "./CellStyles";
import { FileType } from "@appserver/common/constants";
import { FileType, RoomsType } from "@appserver/common/constants";
const TypeCell = ({ t, item, sideColor }) => {
const { fileExst, fileType } = item;
const { fileExst, fileType, roomType } = item;
const getItemType = () => {
switch (fileType) {
case FileType.Unknown:
@ -28,7 +28,24 @@ const TypeCell = ({ t, item, sideColor }) => {
}
};
const type = getItemType();
const getRoomType = () => {
switch (roomType) {
case RoomsType.CustomRoom:
return `Custom`;
case RoomsType.FillingFormsRoom:
return `Filling form`;
case RoomsType.EditingRoom:
return `Collaboration`;
case RoomsType.ReadOnlyRoom:
return `View-only`;
case RoomsType.ReviewRoom:
return `Review`;
default:
return ``;
}
};
const type = item.isRoom ? getRoomType() : getItemType();
const Exst = fileExst ? fileExst.slice(1).toUpperCase() : "";
return (

View File

@ -42,6 +42,8 @@ const FileTile = (props) => {
thumbSize,
setSelection,
id,
onSelectTag,
columnCount,
} = props;
const temporaryExtension =
@ -55,8 +57,14 @@ const FileTile = (props) => {
);
const { thumbnailUrl } = item;
const element = (
<ItemIcon id={item.id} icon={item.icon} fileExst={item.fileExst} />
<ItemIcon
id={item.id}
icon={item.icon}
fileExst={item.fileExst}
isRoom={item.isRoom}
/>
);
return (
@ -101,6 +109,8 @@ const FileTile = (props) => {
t={t}
showHotkeyBorder={showHotkeyBorder}
setSelection={setSelection}
selectTag={onSelectTag}
columnCount={columnCount}
>
<FilesTileContent
item={item}

View File

@ -31,6 +31,7 @@ const getThumbSize = (width) => {
const FilesTileContainer = ({ filesList, t, sectionWidth }) => {
const firstRef = useRef();
const [thumbSize, setThumbSize] = useState("");
const [columnCount, setColumnCount] = useState(null);
useEffect(() => {
if (!firstRef?.current) return;
@ -57,6 +58,12 @@ const FilesTileContainer = ({ filesList, t, sectionWidth }) => {
const size = getThumbSize(width);
const widthWithoutPadding = width - 32;
const columns = Math.floor(widthWithoutPadding / 80);
if (columns != columnCount) setColumnCount(columns);
// console.log(
// `Body width: ${document.body.clientWidth} Tile width: ${width} ThumbSize: ${size}`
// );
@ -83,6 +90,7 @@ const FilesTileContainer = ({ filesList, t, sectionWidth }) => {
sectionWidth={sectionWidth}
selectableRef={firstRef}
thumbSize={thumbSize}
columnCount={columnCount}
/>
) : (
<FileTile
@ -91,6 +99,7 @@ const FilesTileContainer = ({ filesList, t, sectionWidth }) => {
item={item}
sectionWidth={sectionWidth}
thumbSize={thumbSize}
columnCount={columnCount}
/>
);
})}

View File

@ -11,6 +11,7 @@ import { isDesktop, isMobile } from "react-device-detect";
import Link from "@appserver/components/link";
import Loader from "@appserver/components/loader";
import { Base } from "@appserver/components/themes";
import Tags from "@appserver/common/components/Tags";
const svgLoader = () => <div style={{ width: "96px" }} />;
@ -24,8 +25,44 @@ const FlexBoxStyles = css`
align-content: center;
`;
const roomsStyles = css`
display: flex;
flex-direction: column;
flex-wrap: nowrap;
justify-content: flex-start;
align-items: center;
align-content: center;
.room-tile_top-content {
width: 100%;
height: 64px;
box-sizing: border-box;
display: flex;
flex-direction: row;
flex-wrap: nowrap;
justify-content: flex-start;
align-items: center;
align-content: center;
border-bottom: ${(props) => props.theme.filesSection.tilesView.tile.border};
}
.room-tile_bottom-content {
width: 100%;
height: 56px;
box-sizing: border-box;
padding: 16px;
}
`;
const FolderStyles = css`
height: 64px;
height: ${(props) => (props.isRoom ? "120px" : "64px")};
`;
const FileStyles = css`
@ -43,7 +80,8 @@ const bottomFileBorder = css`
`;
const StyledTile = styled.div`
cursor: ${(props) => (!props.isRecycleBin ? "pointer" : "default")};
cursor: ${(props) =>
!props.isRecycleBin && !props.isArchiveFolder ? "pointer" : "default"};
${(props) =>
props.inProgress &&
css`
@ -58,7 +96,7 @@ const StyledTile = styled.div`
${(props) => props.isFolder && "border-top-left-radius: 6px;"}
-webkit-tap-highlight-color: rgba(0, 0, 0, 0);
${(props) => props.isFolder && FlexBoxStyles};
${(props) => props.isFolder && (props.isRoom ? roomsStyles : FlexBoxStyles)};
${(props) => (props.isFolder ? FolderStyles : FileStyles)};
${(props) =>
!props.isEdit &&
@ -134,8 +172,10 @@ const StyledTile = styled.div`
.file-icon_container {
width: 32px;
height: 32px;
margin-left: ${(props) => (props.isFolder ? "15px" : "16px")};
margin-right: ${(props) => (props.isFolder ? "7px" : "8px")};
margin-left: ${(props) =>
props.isFolder ? (props.isRoom ? "16px" : "15px") : "16px"};
margin-right: ${(props) =>
props.isFolder ? (props.isRoom ? "12px" : "7px") : "8px"};
}
.tile-folder-loader {
@ -250,7 +290,7 @@ const StyledContent = styled.div`
const StyledElement = styled.div`
flex: 0 0 auto;
display: flex;
margin-right: 4px;
margin-right: ${(props) => (props.isRoom ? "8px" : "4px")};
user-select: none;
margin-top: 3px;
@ -382,7 +422,8 @@ class Tile extends React.PureComponent {
if (
e.detail === 1 &&
!e.target.closest(".badge") &&
!e.target.closest(".item-file-name")
!e.target.closest(".item-file-name") &&
!e.target.closest(".tag")
) {
if (
e.target.nodeName !== "IMG" &&
@ -410,6 +451,7 @@ class Tile extends React.PureComponent {
dragging,
isDragging,
isRecycleBin,
isArchiveFolder,
item,
isActive,
inProgress,
@ -419,8 +461,10 @@ class Tile extends React.PureComponent {
showHotkeyBorder,
hideContextMenu,
t,
columnCount,
selectTag,
} = this.props;
const { isFolder, id, fileExst } = item;
const { isFolder, isRoom, id, fileExst } = item;
const renderElement = Object.prototype.hasOwnProperty.call(
this.props,
@ -471,70 +515,142 @@ class Tile extends React.PureComponent {
dragging={dragging && isFolder}
isFolder={(isFolder && !fileExst) || (!fileExst && id === -1)}
isRecycleBin={isRecycleBin}
isArchiveFolder={isArchiveFolder}
checked={checked}
isActive={isActive}
isRoom={isRoom}
inProgress={inProgress}
isDesktop={isDesktop}
showHotkeyBorder={showHotkeyBorder}
onClick={this.onFileClick}
>
{isFolder || (!fileExst && id === -1) ? (
<>
{renderElement && !(!fileExst && id === -1) && !isEdit && (
<>
{!inProgress ? (
<div className="file-icon_container">
<StyledElement
className="file-icon"
onClick={this.onFileIconClick}
>
{element}
</StyledElement>
isRoom ? (
<>
<div className="room-tile_top-content">
{renderElement && !(!fileExst && id === -1) && !isEdit && (
<>
{!inProgress ? (
<div className="file-icon_container">
<StyledElement
className="file-icon"
isRoom={isRoom}
onClick={this.onFileIconClick}
>
{element}
</StyledElement>
<Checkbox
className="checkbox file-checkbox"
isChecked={checked}
isIndeterminate={indeterminate}
onChange={this.changeCheckbox}
/>
</div>
) : (
<Loader
className="tile-folder-loader"
type="oval"
size="16px"
/>
<Checkbox
className="checkbox file-checkbox"
isChecked={checked}
isIndeterminate={indeterminate}
onChange={this.changeCheckbox}
/>
</div>
) : (
<Loader
className="tile-folder-loader"
type="oval"
size="16px"
/>
)}
</>
)}
</>
)}
<StyledContent
isFolder={(isFolder && !fileExst) || (!fileExst && id === -1)}
>
{FilesTileContent}
{badges}
</StyledContent>
<StyledOptionButton spacerWidth={contextButtonSpacerWidth}>
{renderContext ? (
<ContextMenuButton
className="expandButton"
directionX="right"
getData={getOptions}
isNew={true}
onClick={onContextMenu}
title={title}
<StyledContent
isFolder={(isFolder && !fileExst) || (!fileExst && id === -1)}
>
{FilesTileContent}
{badges}
</StyledContent>
<StyledOptionButton spacerWidth={contextButtonSpacerWidth}>
{renderContext ? (
<ContextMenuButton
className="expandButton"
directionX="right"
getData={getOptions}
isNew={true}
onClick={onContextMenu}
title={title}
/>
) : (
<div className="expandButton" />
)}
<ContextMenu
onHide={hideContextMenu}
getContextModel={getContextModel}
ref={this.cm}
header={contextMenuHeader}
withBackdrop={true}
/>
</StyledOptionButton>
</div>
<div className="room-tile_bottom-content">
<Tags
columnCount={columnCount}
onSelectTag={selectTag}
tags={item.tags}
/>
) : (
<div className="expandButton" />
</div>
</>
) : (
<>
{renderElement && !(!fileExst && id === -1) && !isEdit && (
<>
{!inProgress ? (
<div className="file-icon_container">
<StyledElement
className="file-icon"
isRoom={isRoom}
onClick={this.onFileIconClick}
>
{element}
</StyledElement>
<Checkbox
className="checkbox file-checkbox"
isChecked={checked}
isIndeterminate={indeterminate}
onChange={this.changeCheckbox}
/>
</div>
) : (
<Loader
className="tile-folder-loader"
type="oval"
size="16px"
/>
)}
</>
)}
<ContextMenu
onHide={hideContextMenu}
getContextModel={getContextModel}
ref={this.cm}
header={contextMenuHeader}
withBackdrop={true}
/>
</StyledOptionButton>
</>
<StyledContent
isFolder={(isFolder && !fileExst) || (!fileExst && id === -1)}
>
{FilesTileContent}
{badges}
</StyledContent>
<StyledOptionButton spacerWidth={contextButtonSpacerWidth}>
{renderContext ? (
<ContextMenuButton
className="expandButton"
directionX="right"
getData={getOptions}
isNew={true}
onClick={onContextMenu}
title={title}
/>
) : (
<div className="expandButton" />
)}
<ContextMenu
onHide={hideContextMenu}
getContextModel={getContextModel}
ref={this.cm}
header={contextMenuHeader}
withBackdrop={true}
/>
</StyledOptionButton>
</>
)
) : (
<>
<StyledFileTileTop

View File

@ -16,13 +16,8 @@ import {
isTablet,
isMobile as isMobileUtils,
} from "@appserver/components/utils/device";
import DropDownItem from "@appserver/components/drop-down-item";
import Text from "@appserver/components/text";
import IconButton from "@appserver/components/icon-button";
import ComboBox from "@appserver/components/combobox";
import { Base } from "@appserver/components/themes";
import SortDesc from "../../../../../../../../../../public/images/sort.desc.react.svg";
import { Base } from "@appserver/components/themes";
const paddingCss = css`
@media ${desktop} {
@ -37,7 +32,10 @@ const paddingCss = css`
const StyledGridWrapper = styled.div`
display: grid;
grid-template-columns: repeat(auto-fill, minmax(216px, 1fr));
grid-template-columns: ${(props) =>
props.isRooms
? "repeat(auto-fill, minmax(274px, 1fr))"
: "repeat(auto-fill, minmax(216px, 1fr))"};
width: 100%;
margin-bottom: ${(props) => (props.isFolders ? "23px" : 0)};
box-sizing: border-box;
@ -233,12 +231,13 @@ class TileContainer extends React.PureComponent {
headingFiles,
} = this.props;
const Rooms = [];
const Folders = [];
const Files = [];
React.Children.map(children, (item, index) => {
const { isFolder, fileExst, id } = item.props.item;
if ((isFolder || id === -1) && !fileExst) {
const { isFolder, isRoom, fileExst, id } = item.props.item;
if ((isFolder || id === -1) && !fileExst && !isRoom) {
Folders.push(
<div
className="tile-item-wrapper folder"
@ -251,6 +250,19 @@ class TileContainer extends React.PureComponent {
{item}
</div>
);
} else if (isRoom) {
Rooms.push(
<div
className="tile-item-wrapper folder"
key={index}
onContextMenu={this.onRowContextClick.bind(
this,
item.props.contextOptions
)}
>
{item}
</div>
);
} else {
Files.push(
<div
@ -289,24 +301,39 @@ class TileContainer extends React.PureComponent {
useReactWindow={useReactWindow}
isDesc={this.state.selectedFilterData.sortDirection === "desc"}
>
<>
<Heading
size="xsmall"
id={"folder-tile-heading"}
className="tile-items-heading"
>
{Folders.length > 0 && headingFolders}
</Heading>
{Folders.length > 0 && (
<>
{useReactWindow ? (
<AutoSizer>{renderList}</AutoSizer>
) : (
<StyledGridWrapper isFolders>{Folders}</StyledGridWrapper>
)}
</>
)}
</>
{Rooms.length > 0 && (
<>
<Heading
size="xsmall"
id={"room-tile-heading"}
className="tile-items-heading"
>
{"Rooms"}
</Heading>
{useReactWindow ? (
<AutoSizer>{renderList}</AutoSizer>
) : (
<StyledGridWrapper isRooms>{Rooms}</StyledGridWrapper>
)}
</>
)}
{Folders.length > 0 && (
<>
<Heading
size="xsmall"
id={"folder-tile-heading"}
className="tile-items-heading"
>
{headingFolders}
</Heading>
{useReactWindow ? (
<AutoSizer>{renderList}</AutoSizer>
) : (
<StyledGridWrapper isFolders>{Folders}</StyledGridWrapper>
)}
</>
)}
{Files.length > 0 && (
<>

View File

@ -494,7 +494,7 @@ export default inject(
({
auth,
filesStore,
roomsStore,
dialogsStore,
selectedFolderStore,
treeFoldersStore,
@ -518,10 +518,10 @@ export default inject(
viewAs,
setIsLoading,
fetchFiles,
fetchRooms,
activeFiles,
activeFolders,
} = filesStore;
const { fetchRooms } = roomsStore;
const {
setSharingPanelVisible,

View File

@ -24,8 +24,6 @@ import {
} from "./Section";
import { InfoPanelBodyContent, InfoPanelHeaderContent } from "./InfoPanel";
import { ArticleMainButtonContent } from "../../components/Article";
import { createTreeFolders } from "../../helpers/files-helpers";
import MediaViewer from "./MediaViewer";
import DragTooltip from "../../components/DragTooltip";
@ -33,11 +31,15 @@ import { observer, inject } from "mobx-react";
import config from "../../../package.json";
import { Consumer } from "@appserver/components/utils/context";
import { Events } from "../../helpers/constants";
import RoomsFilter from "@appserver/common/api/rooms/filter";
class PureHome extends React.Component {
componentDidMount() {
const {
fetchFiles,
fetchRooms,
alreadyFetchingRooms,
setAlreadyFetchingRooms,
homepage,
setIsLoading,
setFirstLoad,
@ -56,8 +58,13 @@ class PureHome extends React.Component {
}
const reg = new RegExp(`${homepage}((/?)$|/filter)`, "gmi"); //TODO: Always find?
const roomsReg = new RegExp(`${homepage}((/?)$|/rooms)`, "gmi");
const match = window.location.pathname.match(reg);
const roomsMatch = window.location.pathname.match(roomsReg);
let filterObj = null;
let isRooms = false;
if (
window.location.href.indexOf("/files/#preview") > 1 &&
@ -97,8 +104,27 @@ class PureHome extends React.Component {
}
}
if (roomsMatch && roomsMatch.length > 0) {
if (window.location.href.includes("#preview")) {
return;
}
isRooms = true;
filterObj = RoomsFilter.getFilter(window.location);
if (!filterObj) {
setIsLoading(true);
this.fetchDefaultRooms();
return;
}
}
if (!filterObj) return;
if (isRooms && alreadyFetchingRooms) return setAlreadyFetchingRooms(false);
let dataObj = { filter: filterObj };
if (filterObj && filterObj.authorType) {
@ -119,10 +145,30 @@ class PureHome extends React.Component {
}
}
if (filterObj && filterObj.subjectId) {
const type = "user";
const itemId = filterObj.subjectId;
if (itemId) {
dataObj = {
type,
itemId,
filter: filterObj,
};
} else {
filterObj.subjectId = null;
dataObj = { filter: filterObj };
}
}
if (!dataObj) return;
const { filter, itemId, type } = dataObj;
const newFilter = filter ? filter.clone() : FilesFilter.getDefault();
const newFilter = filter
? filter.clone()
: isRooms
? RoomsFilter.getDefault()
: FilesFilter.getDefault();
const requests = [Promise.resolve(newFilter)];
if (type === "group") {
@ -136,7 +182,12 @@ class PureHome extends React.Component {
axios
.all(requests)
.catch((err) => {
Promise.resolve(FilesFilter.getDefault());
if (isRooms) {
Promise.resolve(RoomsFilter.getDefault());
} else {
Promise.resolve(FilesFilter.getDefault());
}
//console.warn("Filter restored by default", err);
})
.then((data) => {
@ -149,18 +200,33 @@ class PureHome extends React.Component {
label: type === "user" ? result.displayName : result.name,
type,
};
filter.selectedItem = selectedItem;
if (!isRooms) {
filter.selectedItem = selectedItem;
}
}
if (filter) {
const folderId = filter.folder;
//console.log("filter", filter);
if (isRooms) {
return fetchRooms(null, filter).then((data) => {
const pathParts = data.selectedFolder.pathParts;
const newExpandedKeys = createTreeFolders(
pathParts,
expandedKeys
);
setExpandedKeys(newExpandedKeys);
});
} else {
const folderId = filter.folder;
return fetchFiles(folderId, filter).then((data) => {
const pathParts = data.selectedFolder.pathParts;
const newExpandedKeys = createTreeFolders(pathParts, expandedKeys);
setExpandedKeys(newExpandedKeys);
});
return fetchFiles(folderId, filter).then((data) => {
const pathParts = data.selectedFolder.pathParts;
const newExpandedKeys = createTreeFolders(
pathParts,
expandedKeys
);
setExpandedKeys(newExpandedKeys);
});
}
}
return Promise.resolve();
@ -186,6 +252,7 @@ class PureHome extends React.Component {
.finally(() => {
setIsLoading(false);
setFirstLoad(false);
setAlreadyFetchingRooms(false);
});
}
@ -200,6 +267,15 @@ class PureHome extends React.Component {
});
};
fetchDefaultRooms = () => {
const { fetchRooms, setIsLoading, setFirstLoad } = this.props;
fetchRooms().finally(() => {
setIsLoading(false);
setFirstLoad(false);
});
};
onDrop = (files, uploadToFolder) => {
const {
t,
@ -415,6 +491,9 @@ export default inject(
firstLoad,
setFirstLoad,
fetchFiles,
fetchRooms,
alreadyFetchingRooms,
setAlreadyFetchingRooms,
selection,
setSelections,
dragging,
@ -515,6 +594,9 @@ export default inject(
setDragging,
setIsLoading,
fetchFiles,
fetchRooms,
alreadyFetchingRooms,
setAlreadyFetchingRooms,
setUploadPanelVisible,
setSelections,
startUpload,

View File

@ -27,7 +27,6 @@ class ContextOptionsStore {
versionHistoryStore;
settingsStore;
filesSettingsStore;
roomsStore;
constructor(
authStore,
@ -38,8 +37,7 @@ class ContextOptionsStore {
treeFoldersStore,
uploadDataStore,
versionHistoryStore,
settingsStore,
roomsStore
settingsStore
) {
makeAutoObservable(this);
this.authStore = authStore;
@ -51,7 +49,6 @@ class ContextOptionsStore {
this.uploadDataStore = uploadDataStore;
this.versionHistoryStore = versionHistoryStore;
this.settingsStore = settingsStore;
this.roomsStore = roomsStore;
}
onOpenFolder = (item) => {
@ -276,7 +273,7 @@ class ContextOptionsStore {
setDeleteThirdPartyDialogVisible,
} = this.dialogsStore;
const { id, title, providerKey, rootFolderId, isFolder } = item;
const { id, title, providerKey, rootFolderId, isFolder, isRoom } = item;
const isRootThirdPartyFolder = providerKey && id === rootFolderId;
@ -291,13 +288,15 @@ class ContextOptionsStore {
deleteOperation: t("Translations:DeleteOperation"),
successRemoveFile: t("FileRemoved"),
successRemoveFolder: t("FolderRemoved"),
successRemoveRoom: "Remove room",
};
this.filesActionsStore.deleteItemAction(
id,
translations,
!isFolder,
providerKey
providerKey,
isRoom
);
};
@ -346,112 +345,28 @@ class ContextOptionsStore {
setIsVisible(true);
};
onClickEditRoom = (room) => {
onClickEditRoom = () => {
console.log("edit room");
};
onClickInviteUsers = (room) => {
onClickInviteUsers = () => {
console.log("invite users");
};
onClickInfo = (room) => {
console.log("click info");
onClickPin = (e, id, t) => {
const data = (e.currentTarget && e.currentTarget.dataset) || e;
const { action } = data;
this.filesActionsStore.setPinAction(action, id);
};
onClickPinRoom = () => {
this.roomsStore.pinRoom();
};
onClickArchive = (e, id, t) => {
const data = (e.currentTarget && e.currentTarget.dataset) || e;
const { action } = data;
onClickUnpinRoom = () => {
this.roomsStore.unpinRoom();
};
onClickMoveRoomToArchive = () => {
console.log("1", this.roomsStore);
this.roomsStore.moveToArchive();
};
onClickMoveRoomFromArchive = () => {
this.roomsStore.moveFromArchive();
};
onClickDeleteRoom = () => {
this.roomsStore.deleteRoom();
};
getRoomsContextOptions = (room, t) => {
const pin = !room.pinned
? {
key: "pin",
label: "Pin to top",
icon: "/static/images/pin.react.svg",
onClick: this.onClickPinRoom,
disabled: false,
}
: {
key: "unpin",
label: "Unpin",
icon: "/static/images/unpin.react.svg",
onClick: this.onClickUnpinRoom,
disabled: false,
};
const archive =
FolderType.Archive === room.rootFolderType
? {
key: "archive",
label: "Move from archive",
icon: "/static/images/room.archive.svg",
onClick: () => this.onClickMoveRoomToArchive(room),
disabled: false,
}
: {
key: "archive",
label: "Move to archive",
icon: "/static/images/room.archive.svg",
onClick: () => this.onClickMoveRoomToArchive(room),
disabled: false,
};
const contextOptions = [
{
key: "edit",
label: "Edit room",
icon: "images/settings.react.svg",
onClick: () => this.onClickEditRoom(room),
disabled: false,
},
{
key: "users",
label: "Invite users",
icon: "/static/images/person.react.svg",
onClick: () => this.onClickInviteUsers(room),
disabled: false,
},
{
key: "info",
label: "Info",
icon: "/static/images/info.react.svg",
onClick: () => this.onClickInfo(room),
disabled: false,
},
{
...pin,
},
{ key: "separator", isSeparator: true },
{
...archive,
},
{
key: "delete",
label: "Delete",
icon: "images/trash.react.svg",
onClick: this.onClickDeleteRoom,
disabled: false,
},
];
return contextOptions;
this.filesActionsStore
.setArchiveAction(action, id)
.catch((err) => toastr.error(err));
};
getFilesContextOptions = (item, t) => {
@ -616,6 +531,45 @@ class ContextOptionsStore {
onClick: () => this.onClickMakeForm(item, t),
disabled: false,
},
{
key: "edit-room",
label: "Edit room",
icon: "images/settings.react.svg",
onClick: () => this.onClickEditRoom(),
disabled: false,
},
{
key: "invite-users-to-room",
label: "Invite users",
icon: "/static/images/person.react.svg",
onClick: () => this.onClickInviteUsers(),
disabled: false,
},
{
key: "room-info",
label: "Info",
icon: "/static/images/info.react.svg",
onClick: this.onShowInfoPanel,
disabled: false,
},
{
key: "pin-room",
label: "Pin to top",
icon: "/static/images/pin.react.svg",
onClick: (e) => this.onClickPin(e, item.id, t),
disabled: false,
"data-action": "pin",
action: "pin",
},
{
key: "unpin-room",
label: "Unpin",
icon: "/static/images/unpin.react.svg",
onClick: (e) => this.onClickPin(e, item.id, t),
disabled: false,
"data-action": "unpin",
action: "unpin",
},
{
key: "separator0",
isSeparator: true,
@ -739,6 +693,24 @@ class ContextOptionsStore {
onClick: () => this.onChangeThirdPartyInfo(item.providerKey),
disabled: false,
},
{
key: "archive-room",
label: "Move to archive",
icon: "/static/images/room.archive.svg",
onClick: (e) => this.onClickArchive(e, item.id, t),
disabled: false,
"data-action": "archive",
action: "archive",
},
{
key: "unarchive-room",
label: "Move to archive",
icon: "/static/images/room.archive.svg",
onClick: (e) => this.onClickArchive(e, item.id, t),
disabled: false,
"data-action": "unarchive",
action: "unarchive",
},
{
key: "delete",
label: isRootThirdPartyFolder

View File

@ -12,6 +12,7 @@ import {
removeShareFiles,
createFolder,
} from "@appserver/common/api/files";
import { deleteRoom } from "@appserver/common/api/rooms";
import {
ConflictResolveType,
FileAction,
@ -78,9 +79,14 @@ class FilesActionStore {
const {
filter,
fetchFiles,
roomsFilter,
fetchRooms,
isEmptyLastPageAfterOperation,
resetFilterPage,
} = this.filesStore;
const { isRoomsFolder, isArchiveFolder } = this.treeFoldersStore;
let newFilter;
const selectionFilesLength =
@ -101,16 +107,26 @@ class FilesActionStore {
updatedFolder = this.selectedFolderStore.parentId;
}
fetchFiles(
updatedFolder,
newFilter ? newFilter : filter,
true,
true,
clearSelection
).finally(() => {
this.dialogsStore.setIsFolderActions(false);
return setTimeout(() => clearSecondaryProgressData(), TIMEOUT);
});
if (isRoomsFolder || isArchiveFolder) {
fetchRooms(
updatedFolder,
newFilter ? newFilter : roomsFilter.clone()
).finally(() => {
this.dialogsStore.setIsFolderActions(false);
return setTimeout(() => clearSecondaryProgressData(), TIMEOUT);
});
} else {
fetchFiles(
updatedFolder,
newFilter ? newFilter : filter,
true,
true,
clearSelection
).finally(() => {
this.dialogsStore.setIsFolderActions(false);
return setTimeout(() => clearSecondaryProgressData(), TIMEOUT);
});
}
};
convertToTree = (folders) => {
@ -547,7 +563,13 @@ class FilesActionStore {
}
};
deleteItemAction = async (itemId, translations, isFile, isThirdParty) => {
deleteItemAction = async (
itemId,
translations,
isFile,
isThirdParty,
isRoom
) => {
const {
secondaryProgressDataStore,
clearActiveOperations,
@ -557,9 +579,10 @@ class FilesActionStore {
clearSecondaryProgressData,
} = secondaryProgressDataStore;
if (
this.settingsStore.confirmDelete ||
this.treeFoldersStore.isPrivacyFolder ||
isThirdParty
(this.settingsStore.confirmDelete ||
this.treeFoldersStore.isPrivacyFolder ||
isThirdParty) &&
!isRoom
) {
this.dialogsStore.setDeleteDialogVisible(true);
} else {
@ -572,7 +595,7 @@ class FilesActionStore {
});
try {
await this.deleteItemOperation(isFile, itemId, translations);
await this.deleteItemOperation(isFile, itemId, translations, isRoom);
} catch (err) {
clearActiveOperations(isFile && [itemId], !isFile && [itemId]);
setSecondaryProgressBarData({
@ -585,7 +608,7 @@ class FilesActionStore {
}
};
deleteItemOperation = (isFile, itemId, translations) => {
deleteItemOperation = (isFile, itemId, translations, isRoom) => {
const { addActiveItems, getIsEmptyTrash } = this.filesStore;
const pbData = {
@ -593,8 +616,6 @@ class FilesActionStore {
label: translations.deleteOperation,
};
const selectionFilesLength = 1;
if (isFile) {
addActiveItems([itemId]);
this.isMediaOpen();
@ -606,6 +627,16 @@ class FilesActionStore {
this.updateCurrentFolder([itemId]);
})
.then(() => toastr.success(translations.successRemoveFile));
} else if (isRoom) {
addActiveItems(null, [itemId]);
return deleteRoom(itemId)
.then(async (res) => {
if (res[0]?.error) return Promise.reject(res[0].error);
const data = res ? res : null;
await this.uploadDataStore.loopFilesOperations(data, pbData);
this.updateCurrentFolder(null, [itemId]);
})
.then(() => toastr.success(translations.successRemoveRoom));
} else {
addActiveItems(null, [itemId]);
return deleteFolder(itemId)
@ -724,6 +755,137 @@ class FilesActionStore {
}
};
setPinAction = (action, id) => {
const { pinRoom, unpinRoom, setSelected } = this.filesStore;
const items = Array.isArray(id) ? id : [id];
switch (action) {
case "pin":
return pinRoom(items)
.then(() => {
this.updateCurrentFolder(null, items);
})
.then(() => setSelected("close"))
.finally(() => toastr.success("Room pinned"));
case "unpin":
return unpinRoom(items)
.then(() => {
this.updateCurrentFolder(null, items);
})
.then(() => setSelected("close"))
.finally(() => toastr.success("Room unpinned"));
default:
return;
}
};
setArchiveAction = async (action, itemId) => {
const {
addActiveItems,
moveRoomToArchive,
removeRoomFromArchive,
setSelected,
} = this.filesStore;
const {
secondaryProgressDataStore,
clearActiveOperations,
} = this.uploadDataStore;
const {
setSecondaryProgressBarData,
clearSecondaryProgressData,
} = secondaryProgressDataStore;
const items = Array.isArray(itemId) ? itemId : [itemId];
setSecondaryProgressBarData({
icon: "trash",
visible: true,
percent: 0,
label: "Archive room",
alert: false,
});
const pbData = {
icon: "trash",
label: "Archive room operation",
};
addActiveItems(null, items);
switch (action) {
case "archive":
return moveRoomToArchive(items)
.then(async (res) => {
if (res[0]?.error) return Promise.reject(res[0].error);
const data = res ? res : null;
await this.uploadDataStore.loopFilesOperations(data, pbData);
this.updateCurrentFolder(null, items);
})
.then(() => toastr.success("Room moved to archive"))
.then(() => setSelected("close"))
.catch((err) => {
clearActiveOperations(null, items);
setSecondaryProgressBarData({
visible: true,
alert: true,
});
setTimeout(() => clearSecondaryProgressData(), TIMEOUT);
return toastr.error(err.message ? err.message : err);
})
.finally(() => clearActiveOperations(null, items));
case "unarchive":
return removeRoomFromArchive(items)
.then(async (res) => {
if (res[0]?.error) return Promise.reject(res[0].error);
const data = res ? res : null;
await this.uploadDataStore.loopFilesOperations(data, pbData);
this.updateCurrentFolder(null, [items]);
})
.then(() => toastr.success("Room removed from archive"))
.then(() => setSelected("close"))
.catch((err) => {
clearActiveOperations(null, items);
setSecondaryProgressBarData({
visible: true,
alert: true,
});
setTimeout(() => clearSecondaryProgressData(), TIMEOUT);
return toastr.error(err.message ? err.message : err);
})
.finally(() => clearActiveOperations(null, items));
default:
return;
}
};
selectTag = (tag) => {
const { roomsFilter, fetchRooms, setIsLoading } = this.filesStore;
const { id } = this.selectedFolderStore;
const newFilter = roomsFilter.clone();
const tags = newFilter.tags ? [...newFilter.tags] : [];
if (tags.length > 0) {
const idx = tags.findIndex((item) => item === tag);
if (idx > -1) {
//TODO: remove tag here if already selected
return;
}
}
tags.push(tag);
newFilter.tags = [...tags];
setIsLoading(true);
fetchRooms(id, newFilter).finally(() => setIsLoading(false));
};
selectRowAction = (checked, file) => {
const {
selected,
@ -1039,6 +1201,40 @@ class FilesActionStore {
onClick: () => setMoveToPanelVisible(true),
iconUrl: "/static/images/move.react.svg",
};
case "pin":
return {
key: "pin",
label: "Pin to top",
iconUrl: "/static/images/pin.react.svg",
onClick: (e) => {
console.log(e.target);
},
disabled: false,
};
case "unpin":
return {
key: "unpin",
label: "Unpin",
iconUrl: "/static/images/unpin.react.svg",
onClick: () => console.log("unpin"),
disabled: false,
};
case "archive":
return {
key: "archive",
label: "Move to archive",
iconUrl: "/static/images/room.archive.svg",
onClick: () => console.log("to archive"),
disabled: false,
};
case "unarchive":
return {
key: "unarchive",
label: "Move from archive",
iconUrl: "/static/images/room.archive.svg",
onClick: () => console.log("from archive"),
disabled: false,
};
case "delete":
if (!this.isAvailableOption("delete")) return null;
@ -1067,6 +1263,22 @@ class FilesActionStore {
}
};
getRoomsFolderOptions = (itemsCollection, t) => {
const pin = this.getOption("pin", t);
const archive = this.getOption("archive", t);
itemsCollection.set("pin", pin).set("archive", archive);
return this.convertToArray(itemsCollection);
};
getArchiveRoomsFolderOptions = (itemsCollection, t) => {
const pin = this.getOption("pin", t);
const archive = this.getOption("unarchive", t);
itemsCollection.set("pin", pin).set("unarchive", archive);
return this.convertToArray(itemsCollection);
};
getAnotherFolderOptions = (itemsCollection, t) => {
const share = this.getOption("share", t);
const download = this.getOption("download", t);
@ -1209,6 +1421,8 @@ class FilesActionStore {
isRecycleBinFolder,
isPrivacyFolder,
isShareFolder,
isRoomsFolder,
isArchiveFolder,
} = this.treeFoldersStore;
let itemsCollection = new Map();
@ -1225,6 +1439,11 @@ class FilesActionStore {
if (isRecentFolder) return this.getRecentFolderOptions(itemsCollection, t);
if (isArchiveFolder)
return this.getArchiveRoomsFolderOptions(itemsCollection, t);
if (isRoomsFolder) return this.getRoomsFolderOptions(itemsCollection, t);
return this.getAnotherFolderOptions(itemsCollection, t);
};

View File

@ -2,11 +2,12 @@ import { makeAutoObservable, runInAction } from "mobx";
import api from "@appserver/common/api";
import {
AppServerConfig,
FileAction,
FileType,
FilterType,
FolderType,
FileStatus,
RoomSearchArea,
RoomsType,
} from "@appserver/common/constants";
import history from "@appserver/common/history";
import { combineUrl } from "@appserver/common/utils";
@ -19,7 +20,7 @@ import { thumbnailStatuses } from "../helpers/constants";
import { loopTreeFolders } from "../helpers/files-helpers";
import { openDocEditor as openEditor } from "../helpers/utils";
const { FilesFilter } = api;
const { FilesFilter, RoomsFilter } = api;
const storageViewAs = localStorage.getItem("viewAs");
class FilesStore {
@ -33,10 +34,13 @@ class FilesStore {
isLoaded = false;
isLoading = false;
viewAs =
isMobile && storageViewAs !== "tile" ? "row" : storageViewAs || "table";
dragging = false;
privacyInstructions = "https://www.onlyoffice.com/private-rooms.aspx";
isInit = false;
isUpdatingRowItem = false;
passwordEntryProcess = false;
@ -46,13 +50,18 @@ class FilesStore {
startDrag = false;
firstLoad = true;
alreadyFetchingRooms = false;
files = [];
folders = [];
selection = [];
bufferSelection = null;
selected = "close";
filter = FilesFilter.getDefault(); //TODO: FILTER
roomsFilter = RoomsFilter.getDefault();
loadTimeout = null;
hotkeyCaret = null;
hotkeyCaretStart = null;
@ -444,6 +453,8 @@ class FilesStore {
}
const type = file.fileType;
const roomType = file.roomType;
switch (selected) {
case "all":
return true;
@ -463,6 +474,16 @@ class FilesStore {
return type === FileType.Archive;
case FilterType.FilesOnly.toString():
return type || !file.parentId;
case `room-${RoomsType.FillingFormsRoom}`:
return roomType === RoomsType.FillingFormsRoom;
case `room-${RoomsType.CustomRoom}`:
return roomType === RoomsType.CustomRoom;
case `room-${RoomsType.EditingRoom}`:
return roomType === RoomsType.EditingRoom;
case `room-${RoomsType.ReviewRoom}`:
return roomType === RoomsType.ReviewRoom;
case `room-${RoomsType.ReadOnlyRoom}`:
return roomType === RoomsType.ReadOnlyRoom;
default:
return false;
}
@ -533,6 +554,27 @@ class FilesStore {
});
};
setRoomsFilter = (filter) => {
const key = `UserRoomsFilter=${this.userStore.user.id}`;
const value = `${filter.sortBy},${filter.pageCount},${filter.sortOrder}`;
localStorage.setItem(key, value);
this.setFilterUrl(filter, true);
this.roomsFilter = filter;
runInAction(() => {
if (filter && this.isHidePagination) {
this.isHidePagination = false;
}
});
runInAction(() => {
if (filter && this.isLoadingFilesFind) {
this.isLoadingFilesFind = false;
}
});
};
setFilter = (filter) => {
this.filter = filter;
};
@ -541,32 +583,41 @@ class FilesStore {
return api.files.setFileOwner(folderIds, fileIds, ownerId);
};
setFilterUrl = (filter) => {
setFilterUrl = (filter, isRooms = false) => {
const urlFilter = filter.toUrlParams();
history.push(
combineUrl(
AppServerConfig.proxyURL,
config.homepage,
`/filter?${urlFilter}`
)
);
const str = isRooms ? `/rooms?${urlFilter}` : `/filter?${urlFilter}`;
history.push(combineUrl(AppServerConfig.proxyURL, config.homepage, str));
};
isEmptyLastPageAfterOperation = (newSelection) => {
const { isRoomsFolder, isArchiveFolder } = this.treeFoldersStore;
const selection =
newSelection || this.selection?.length || [this.bufferSelection].length;
const filter =
isRoomsFolder || isArchiveFolder ? this.roomsFilter : this.filter;
return (
selection &&
this.filter.page > 0 &&
!this.filter.hasNext() &&
filter.page > 0 &&
!filter.hasNext() &&
selection === this.files.length + this.folders.length
);
};
resetFilterPage = () => {
const { isRoomsFolder, isArchiveFolder } = this.treeFoldersStore;
let newFilter;
newFilter = this.filter.clone();
newFilter =
isRoomsFolder || isArchiveFolder
? this.roomsFilter.clone()
: this.filter.clone();
newFilter.page--;
return newFilter;
@ -733,6 +784,115 @@ class FilesStore {
return request();
};
fetchRooms = (
folderId,
filter,
clearFilter = true,
withSubfolders = false,
clearSelection = true
) => {
const { setSelectedNode, roomsFolderId } = this.treeFoldersStore;
const filterData = !!filter ? filter.clone() : RoomsFilter.getDefault();
const filterStorageItem = localStorage.getItem(
`UserRoomsFilter=${this.userStore.user.id}`
);
if (filterStorageItem && !filter) {
const splitFilter = filterStorageItem.split(",");
filterData.sortBy = splitFilter[0];
filterData.pageCount = +splitFilter[1];
filterData.sortOrder = splitFilter[2];
}
if (folderId) setSelectedNode([folderId + ""]);
const searchArea = folderId
? folderId === roomsFolderId
? RoomSearchArea.Active
: RoomSearchArea.Archive
: RoomSearchArea.Active;
if (filterData.searchArea !== searchArea) {
filterData.searchArea = searchArea;
}
const request = () =>
api.rooms
.getRooms(filterData)
.then(async (data) => {
if (!folderId) setSelectedNode([data.current.id + ""]);
filterData.total = data.total;
if (data.total > 0) {
const lastPage = filterData.getLastPage();
if (filterData.page > lastPage) {
filterData.page = lastPage;
return this.fetchRooms(folderId, filterData);
}
}
this.setRoomsFilter(filterData);
runInAction(() => {
this.setFolders(data.folders);
this.setFiles(data.files);
});
if (clearFilter) {
if (clearSelection) {
this.setSelected("close");
}
}
this.selectedFolderStore.setSelectedFolder({
folders: data.folders,
...data.current,
pathParts: data.pathParts,
navigationPath: [],
...{ new: data.new },
});
const selectedFolder = {
selectedFolder: { ...this.selectedFolderStore },
};
this.viewAs === "tile" && this.createThumbnails();
if (this.createdItem) {
const newItem = this.filesList.find(
(item) => item.id === this.createdItem.id
);
if (newItem) {
this.setBufferSelection(newItem);
this.setScrollToItem({
id: newItem.id,
type: this.createdItem.type,
});
}
this.setCreatedItem(null);
}
return Promise.resolve(selectedFolder);
})
.catch((err) => {
toastr.error(err);
});
return request();
};
setAlreadyFetchingRooms = (alreadyFetchingRooms) => {
this.alreadyFetchingRooms = alreadyFetchingRooms;
};
checkUpdateNode = async (data, folderId) => {
const { treeFolders, getSubfolders } = this.treeFoldersStore;
const { pathParts, current } = data;
@ -801,6 +961,7 @@ class FilesStore {
const isVisitor =
(this.userStore.user && this.userStore.user.isVisitor) || false;
const isFile = !!item.fileExst || item.contentLength;
const isRoom = !!item.roomType;
const isFavorite =
(item.fileStatus & FileStatus.IsFavorite) === FileStatus.IsFavorite;
const isFullAccess = item.access < 2;
@ -824,6 +985,7 @@ class FilesStore {
isFavoritesFolder,
isShareFolder,
isMy,
isArchiveFolder,
} = this.treeFoldersStore;
const {
@ -1146,6 +1308,38 @@ class FilesStore {
}
return fileOptions;
} else if (isRoom) {
let roomOptions = [
"edit-room",
"invite-users-to-room",
"room-info",
"pin-room",
"unpin-room",
"separator0",
"archive-room",
"unarchive-room",
"delete",
];
if (item.pinned) {
roomOptions = this.removeOptions(roomOptions, ["pin-room"]);
} else {
roomOptions = this.removeOptions(roomOptions, ["unpin-room"]);
}
if (isArchiveFolder) {
roomOptions = this.removeOptions(roomOptions, [
"edit-room",
"invite-users-to-room",
"pin-room",
"unpin-room",
"archive-room",
]);
} else {
roomOptions = this.removeOptions(roomOptions, ["unarchive-room"]);
}
return roomOptions;
} else {
let folderOptions = [
"open",
@ -1504,14 +1698,6 @@ class FilesStore {
}
}
get filterType() {
return this.filter.filterType;
}
get filterSearch() {
return this.filter.search;
}
onCreateAddTempItem = (items) => {
const { getFileIcon, getFolderIcon } = this.filesSettingsStore;
const { extension, title } = this.fileActionStore;
@ -1578,6 +1764,10 @@ class FilesStore {
thumbnailStatus,
canShare,
canEdit,
roomType,
isArchive,
tags,
pinned,
} = item;
const { canConvert, isMediaOrImage } = this.filesSettingsStore;
@ -1595,7 +1785,14 @@ class FilesStore {
const isThirdPartyFolder = providerKey && id === rootFolderId;
const iconSize = this.viewAs === "table" ? 24 : 32;
const icon = getIcon(iconSize, fileExst, providerKey, contentLength);
const icon = getIcon(
iconSize,
fileExst,
providerKey,
contentLength,
roomType,
isArchive
);
let isFolder = false;
this.folders.map((x) => {
@ -1630,6 +1827,8 @@ class FilesStore {
? docUrl
: folderUrl;
const isRoom = !!roomType;
return {
access,
//checked,
@ -1675,6 +1874,11 @@ class FilesStore {
href,
isThirdPartyFolder,
isEditing,
roomType,
isRoom,
isArchive,
tags,
pinned,
};
});
@ -1694,7 +1898,30 @@ class FilesStore {
let cbMenu = ["all"];
const filesItems = [...this.files, ...this.folders];
if (this.folders.length) cbMenu.push(FilterType.FoldersOnly);
if (this.folders.length) {
for (const item of this.folders) {
switch (item.roomType) {
case RoomsType.FillingFormsRoom:
cbMenu.push(`room-${RoomsType.FillingFormsRoom}`);
break;
case RoomsType.CustomRoom:
cbMenu.push(`room-${RoomsType.CustomRoom}`);
break;
case RoomsType.EditingRoom:
cbMenu.push(`room-${RoomsType.EditingRoom}`);
break;
case RoomsType.ReviewRoom:
cbMenu.push(`room-${RoomsType.ReviewRoom}`);
break;
case RoomsType.ReadOnlyRoom:
cbMenu.push(`room-${RoomsType.ReadOnlyRoom}`);
break;
default:
cbMenu.push(FilterType.FoldersOnly);
}
}
}
for (let item of filesItems) {
if (isDocument(item.fileExst)) cbMenu.push(FilterType.DocumentsOnly);
else if (isPresentation(item.fileExst))
@ -1707,7 +1934,14 @@ class FilesStore {
}
const hasFiles = cbMenu.some(
(elem) => elem !== "all" && elem !== FilterType.FoldersOnly
(elem) =>
elem !== "all" &&
elem !== `room-${FilterType.FoldersOnly}` &&
elem !== `room-${RoomsType.FillingFormsRoom}` &&
elem !== `room-${RoomsType.CustomRoom}` &&
elem !== `room-${RoomsType.EditingRoom}` &&
elem !== `room-${RoomsType.ReviewRoom}` &&
elem !== `room-${RoomsType.ReadOnlyRoom}`
);
if (hasFiles) cbMenu.push(FilterType.FilesOnly);
@ -1737,6 +1971,16 @@ class FilesStore {
return t("Archives");
case FilterType.FilesOnly:
return t("AllFiles");
case `room-${RoomsType.FillingFormsRoom}`:
return "Filling forms";
case `room-${RoomsType.CustomRoom}`:
return "Custom";
case `room-${RoomsType.EditingRoom}`:
return "Editing";
case `room-${RoomsType.ReviewRoom}`:
return "Review";
case `room-${RoomsType.ReadOnlyRoom}`:
return "View-only";
default:
return "";
@ -2054,6 +2298,14 @@ class FilesStore {
});
};
moveRoomToArchive = (id) => api.rooms.archiveRoom(id);
removeRoomFromArchive = (id) => api.rooms.unarchiveRoom(id);
pinRoom = (id) => api.rooms.pinRoom(id);
unpinRoom = (id) => api.rooms.unpinRoom(id);
getFileInfo = async (id) => {
const fileInfo = await api.files.getFileInfo(id);
this.setFile(fileInfo);

View File

@ -83,38 +83,6 @@ class RoomsActionsStore {
getOption = (option, t) => {
switch (option) {
case "pin":
return {
key: "pin",
label: "Pin to top",
iconUrl: "/static/images/pin.react.svg",
onClick: () => console.log("pin"),
disabled: false,
};
case "unpin":
return {
key: "unpin",
label: "Unpin",
iconUrl: "/static/images/unpin.react.svg",
onClick: () => console.log("unpin"),
disabled: false,
};
case "archive":
return {
key: "archive",
label: "Move to archive",
iconUrl: "/static/images/room.archive.svg",
onClick: () => console.log("to archive"),
disabled: false,
};
case "unarchive":
return {
key: "unarchive",
label: "Move from archive",
iconUrl: "/static/images/room.archive.svg",
onClick: () => console.log("from archive"),
disabled: false,
};
}
};

View File

@ -228,24 +228,12 @@ class RoomsStore {
return api.rooms.deleteRoom(selectedRoom.id);
};
pinRoom = (room) => {
const selectedRoom = room
? room
: this.selection.length > 0
? this.selection[0]
: this.bufferSelection;
return api.rooms.pinRoom(selectedRoom.id);
pinRoom = (id) => {
return api.rooms.pinRoom(id);
};
unpinRoom = (room) => {
const selectedRoom = room
? room
: this.selection.length > 0
? this.selection[0]
: this.bufferSelection;
return api.rooms.unpinRoom(selectedRoom.id);
unpinRoom = (id) => {
return api.rooms.unpinRoom(id);
};
moveToArchive = (room) => {

View File

@ -3,7 +3,7 @@ import {
setFavoritesSetting,
setRecentSetting,
} from "@appserver/common/api/files";
import { FolderType } from "@appserver/common/constants";
import { FolderType, RoomsType } from "@appserver/common/constants";
import axios from "axios";
import { makeAutoObservable } from "mobx";
import { presentInArray } from "../helpers/files-helpers";
@ -267,7 +267,9 @@ class SettingsStore {
size = 24,
fileExst = null,
providerKey = null,
contentLength = null
contentLength = null,
roomType = null,
isArchive = null
) => {
if (fileExst || contentLength) {
const isArchiveItem = this.isArchive(fileExst);
@ -284,11 +286,32 @@ class SettingsStore {
isHtmlItem
);
return icon;
} else if (roomType) {
return this.getRoomsIcon(roomType, isArchive, 32);
} else {
return this.getFolderIcon(providerKey, size);
}
};
getRoomsIcon = (roomType, isArchive, size = 32) => {
const reviewPath = `images/icons/${size}`;
if (isArchive) return `${reviewPath}/room/archive.svg`;
switch (roomType) {
case RoomsType.CustomRoom:
return `${reviewPath}/room/custom.svg`;
case RoomsType.FillingFormsRoom:
return `${reviewPath}/room/filling.form.svg`;
case RoomsType.EditingRoom:
return `${reviewPath}/room/editing.svg`;
case RoomsType.ReadOnlyRoom:
return `${reviewPath}/room/view.only.svg`;
case RoomsType.ReviewRoom:
return `${reviewPath}/room/review.svg`;
}
};
getFolderIcon = (providerKey, size = 32) => {
const folderPath = `images/icons/${size}`;

View File

@ -101,6 +101,16 @@ class TreeFoldersStore {
return this.treeFolders.find((x) => x.rootFolderType === FolderType.Recent);
}
get roomsFolder() {
return this.treeFolders.find((x) => x.rootFolderType === FolderType.Rooms);
}
get archiveFolder() {
return this.treeFolders.find(
(x) => x.rootFolderType === FolderType.Archive
);
}
get privacyFolder() {
return this.treeFolders.find(
(x) => x.rootFolderType === FolderType.Privacy
@ -123,6 +133,14 @@ class TreeFoldersStore {
return this.commonFolder ? this.commonFolder.id : null;
}
get roomsFolderId() {
return this.roomsFolder ? this.roomsFolder.id : null;
}
get archiveFolderId() {
return this.archiveFolder ? this.archiveFolder.id : null;
}
get isMyFolder() {
return this.myFolder && this.myFolder.id === this.selectedFolderStore.id;
}
@ -174,6 +192,19 @@ class TreeFoldersStore {
);
}
get isRoomsFolder() {
return (
this.roomsFolder && this.selectedFolderStore.id === this.roomsFolder.id
);
}
get isArchiveFolder() {
return (
this.archiveFolder &&
this.selectedFolderStore.id === this.archiveFolder.id
);
}
get operationsFolders() {
if (this.isPrivacyFolder) {
return this.treeFolders.filter(
@ -185,7 +216,8 @@ class TreeFoldersStore {
(folder.rootFolderType === FolderType.USER ||
folder.rootFolderType === FolderType.COMMON ||
folder.rootFolderType === FolderType.Projects ||
folder.rootFolderType === FolderType.SHARE) &&
folder.rootFolderType === FolderType.SHARE ||
folder.rootFolderType === FolderType.Rooms) &&
folder
);
}

View File

@ -16,8 +16,6 @@ import ContextOptionsStore from "./ContextOptionsStore";
import HotkeyStore from "./HotkeyStore";
import store from "studio/store";
import selectFileDialogStore from "./SelectFileDialogStore";
import RoomsStore from "./RoomsStore";
import RoomsActionsStore from "./RoomsActionsStore";
const selectedFolderStore = new SelectedFolderStore(store.auth.settingsStore);
@ -34,18 +32,6 @@ const filesStore = new FilesStore(
selectFileDialogStore
);
const roomsStore = new RoomsStore(
store.auth,
store.auth.settingsStore,
store.auth.userStore,
filesStore,
selectedFolderStore,
treeFoldersStore,
settingsStore
);
const roomsActionsStore = new RoomsActionsStore(roomsStore, filesStore);
const mediaViewerDataStore = new MediaViewerDataStore(
filesStore,
settingsStore
@ -90,8 +76,7 @@ const contextOptionsStore = new ContextOptionsStore(
treeFoldersStore,
uploadDataStore,
versionHistoryStore,
settingsStore,
roomsStore
settingsStore
);
const hotkeyStore = new HotkeyStore(
@ -105,8 +90,7 @@ const hotkeyStore = new HotkeyStore(
const stores = {
filesStore,
roomsStore,
roomsActionsStore,
settingsStore,
mediaViewerDataStore,
versionHistoryStore,