Merge branch 'develop' into refactoring/global-colors
This commit is contained in:
commit
cb4a36feee
@ -1,33 +1,29 @@
|
||||
{
|
||||
"AccountsEmptyScreenText": "See users details here",
|
||||
"AddedRoomTags": "Tags added.",
|
||||
"Administration": "Administration",
|
||||
"AndMoreLabel": "and <strong>{{count}} more</strong>",
|
||||
"AndMoreLabel": "and <1>{{count}} more</1>",
|
||||
"CreationDate": "Creation date",
|
||||
"Data": "Data",
|
||||
"DateModified": "Date modified",
|
||||
"DeletedRoomTags": "Tags removed.",
|
||||
"ExpectUsers": "Expect users",
|
||||
"FeedCreateFileSeveral": "Files added",
|
||||
"FeedCreateFileSingle": "File created",
|
||||
"FeedCreateFolderSeveral": "Folders added",
|
||||
"FeedCreateFolderSingle": "Folder created",
|
||||
"FeedCreateRoom": "<strong>«{{roomTitle}}»</strong> room created",
|
||||
"FeedCreateRoomTag": "Tags added",
|
||||
"FeedCreateUser": "Users added",
|
||||
"FeedDeleteFile": "Files removed",
|
||||
"FeedDeleteFolder": "Folders removed",
|
||||
"FeedDeleteRoomTag": "Tags removed",
|
||||
"FeedDeleteUser": "User removed",
|
||||
"FeedLinkWasDeleted": "Link was deleted",
|
||||
"FeedLocationLabel": "Folder «{{folderTitle}}»",
|
||||
"FeedMoveFile": "Files moved",
|
||||
"FeedMoveFolder": "Folders moved",
|
||||
"FeedRenameFile": "File renamed",
|
||||
"FeedRenameFolder": "Folder renamed",
|
||||
"FeedRenameRoom": "Room <strong>«{{oldRoomTitle}}»</strong> renamed to <strong>«{{roomTitle}}»</strong>.",
|
||||
"FeedUpdateFile": "File updated",
|
||||
"FeedUpdateRoom": "Icon changed",
|
||||
"FeedUpdateUser": "has been assigned role {{role}}",
|
||||
"FileConverted": "File converted.",
|
||||
"FileCopied": "Files copied.",
|
||||
"FileCreated": "File created.",
|
||||
"FileDeleted": "Files removed.",
|
||||
"FileExtension": "File extension",
|
||||
"FileMoved": "Files moved.",
|
||||
"FileRenamed": "File renamed.",
|
||||
"FilesEmptyScreenText": "See file and folder details here",
|
||||
"FileUploaded": "Files added.",
|
||||
"FolderCopied": "Folders copied.",
|
||||
"FolderCreated": "Folder created.",
|
||||
"FolderDeleted": "Folders removed.",
|
||||
"FolderMoved": "Folders moved.",
|
||||
"FolderRenamed": "Folder renamed.",
|
||||
"GalleryEmptyScreenText": "See form template details here",
|
||||
"GroupsEmptyScreenText": "See group details here",
|
||||
"HistoryEmptyScreenText": "Activity history will be shown here",
|
||||
@ -35,11 +31,25 @@
|
||||
"ItemsSelected": "Items selected",
|
||||
"LastModifiedBy": "Last modified by",
|
||||
"Properties": "Properties",
|
||||
"RoomCreated": "<1>«{{roomTitle}}»</1> room created",
|
||||
"RoomCreateUser": "Users added.",
|
||||
"RoomExternalLinkCreated": "Link created.",
|
||||
"RoomExternalLinkDeleted": "Link <1>«{{linkTitle}}»</1> deleted.",
|
||||
"RoomExternalLinkRenamed": "Link <1>«{{oldLinkTitle}}»</1> renamed to <1>«{{linkTitle}}»</1>",
|
||||
"RoomGroupAdded": "Groups added.",
|
||||
"RoomGroupRemove": "Group removed",
|
||||
"RoomLogoCreated": "Icon changed",
|
||||
"RoomLogoDeleted": "Icon changed",
|
||||
"RoomRemoveUser": "User removed.",
|
||||
"RoomRenamed": "Room <1>«{{oldRoomTitle}}»</1> renamed to <1>«{{roomTitle}}»</1>",
|
||||
"RoomsEmptyScreenTent": "See rooms details here",
|
||||
"RoomUpdateAccessForGroup": "has been assigned role",
|
||||
"RoomUpdateAccessForUser": "has been assigned role",
|
||||
"SelectedUsers": "Selected accounts",
|
||||
"StorageType": "Storage type",
|
||||
"SubmenuDetails": "Details",
|
||||
"SubmenuHistory": "History",
|
||||
"UserFileUpdated": "File updated.",
|
||||
"Users": "Users",
|
||||
"Versions": "Versions"
|
||||
}
|
||||
|
@ -109,28 +109,20 @@ const ArticleBodyContent = (props) => {
|
||||
|
||||
path = getCategoryUrl(CategoryType.Personal);
|
||||
|
||||
if (activeItemId === myFolderId && folderId === selectedFolderId)
|
||||
return;
|
||||
|
||||
break;
|
||||
case archiveFolderId:
|
||||
const archiveFilter = RoomsFilter.getDefault(userId);
|
||||
archiveFilter.searchArea = RoomSearchArea.Archive;
|
||||
params = archiveFilter.toUrlParams(userId, true);
|
||||
path = getCategoryUrl(CategoryType.Archive);
|
||||
if (activeItemId === archiveFolderId && folderId === selectedFolderId)
|
||||
return;
|
||||
|
||||
break;
|
||||
case recycleBinFolderId:
|
||||
const recycleBinFilter = FilesFilter.getDefault();
|
||||
recycleBinFilter.folder = folderId;
|
||||
params = recycleBinFilter.toUrlParams();
|
||||
path = getCategoryUrl(CategoryType.Trash);
|
||||
if (
|
||||
activeItemId === recycleBinFolderId &&
|
||||
folderId === selectedFolderId
|
||||
)
|
||||
return;
|
||||
|
||||
break;
|
||||
case "accounts":
|
||||
const accountsFilter = AccountsFilter.getDefault();
|
||||
@ -138,7 +130,6 @@ const ArticleBodyContent = (props) => {
|
||||
path = getCategoryUrl(CategoryType.Accounts);
|
||||
|
||||
withTimer = false;
|
||||
if (activeItemId === "accounts" && isAccounts) return;
|
||||
|
||||
break;
|
||||
case "settings":
|
||||
@ -155,12 +146,11 @@ const ArticleBodyContent = (props) => {
|
||||
roomsFilter.searchArea = RoomSearchArea.Active;
|
||||
params = roomsFilter.toUrlParams(userId, true);
|
||||
path = getCategoryUrl(CategoryType.Shared);
|
||||
if (activeItemId === roomsFolderId && folderId === selectedFolderId)
|
||||
return;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
path += `?${params}`;
|
||||
path += `?${params}&date=${new Date().getTime()}`;
|
||||
|
||||
if (openingNewTab(path, e)) return;
|
||||
|
||||
|
@ -156,7 +156,6 @@ const EditRoomEvent = ({
|
||||
isTitleChanged || isQuotaChanged
|
||||
? await editRoom(item.id, editRoomParams)
|
||||
: item;
|
||||
|
||||
room.isLogoLoading = true;
|
||||
|
||||
const createTagActions = [];
|
||||
@ -177,7 +176,7 @@ const EditRoomEvent = ({
|
||||
};
|
||||
}
|
||||
if (tags.length) {
|
||||
actions.push(addTagsToRoom(room.id, tags));
|
||||
actions.push(addTagsToRoom(room.id, newTags));
|
||||
room.tags = tags;
|
||||
}
|
||||
if (removedTags.length)
|
||||
@ -189,7 +188,7 @@ const EditRoomEvent = ({
|
||||
room = await removeLogoFromRoom(room.id);
|
||||
}
|
||||
|
||||
if (roomParams.icon.uploadedFile) {
|
||||
if (roomParams.iconWasUpdated && roomParams.icon.uploadedFile) {
|
||||
updateRoom(item, {
|
||||
...room,
|
||||
logo: { big: item.logo.original },
|
||||
|
@ -129,7 +129,7 @@ const SetRoomParams = ({
|
||||
if (!icon.uploadedFile !== disableImageRescaling)
|
||||
setDisableImageRescaling(!icon.uploadedFile);
|
||||
|
||||
setRoomParams({ ...roomParams, icon: icon });
|
||||
setRoomParams({ ...roomParams, icon: icon, iconWasUpdated: true });
|
||||
};
|
||||
|
||||
const onOwnerChange = () => {
|
||||
|
@ -37,16 +37,10 @@ const StyledTagList = styled.div`
|
||||
width: 100%;
|
||||
|
||||
.set_room_params-tag_input-tag {
|
||||
background: ${(props) =>
|
||||
props.theme.createEditRoomDialog.tagInput.tagBackground};
|
||||
padding: 6px 8px;
|
||||
border-radius: 3px;
|
||||
margin: 0;
|
||||
|
||||
:hover {
|
||||
background: ${(props) =>
|
||||
props.theme.createEditRoomDialog.tagInput.tagHoverBackground};
|
||||
}
|
||||
.tag-icon {
|
||||
${({ theme }) =>
|
||||
theme.interfaceDirection === "rtl"
|
||||
|
@ -24,41 +24,34 @@
|
||||
// content are licensed under the terms of the Creative Commons Attribution-ShareAlike 4.0
|
||||
// International. See the License terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
|
||||
|
||||
import { useState, useEffect, useMemo } from "react";
|
||||
import { Backdrop } from "@docspace/shared/components/backdrop";
|
||||
import { useState, useMemo } from "react";
|
||||
import { inject, observer } from "mobx-react";
|
||||
import { withTranslation } from "react-i18next";
|
||||
import { ReactSVG } from "react-svg";
|
||||
|
||||
import { Loader } from "@docspace/shared/components/loader";
|
||||
import { Text } from "@docspace/shared/components/text";
|
||||
import { Heading } from "@docspace/shared/components/heading";
|
||||
import { Aside } from "@docspace/shared/components/aside";
|
||||
import { Row } from "@docspace/shared/components/row";
|
||||
import { Button } from "@docspace/shared/components/button";
|
||||
import { withTranslation } from "react-i18next";
|
||||
import { toastr } from "@docspace/shared/components/toast";
|
||||
import { Portal } from "@docspace/shared/components/portal";
|
||||
|
||||
import { ReactSVG } from "react-svg";
|
||||
import {
|
||||
StyledAsidePanel,
|
||||
StyledContent,
|
||||
StyledHeaderContent,
|
||||
StyledBody,
|
||||
StyledFooter,
|
||||
StyledSharingBody,
|
||||
StyledLink,
|
||||
} from "../StyledPanels";
|
||||
import { inject, observer } from "mobx-react";
|
||||
import { combineUrl } from "@docspace/shared/utils/combineUrl";
|
||||
import config from "PACKAGE_FILE";
|
||||
ModalDialog,
|
||||
ModalDialogType,
|
||||
} from "@docspace/shared/components/modal-dialog";
|
||||
import { DialogAsideSkeleton } from "@docspace/shared/skeletons/dialog";
|
||||
import withLoader from "../../../HOCs/withLoader";
|
||||
|
||||
import FilesFilter from "@docspace/shared/api/files/filter";
|
||||
import { combineUrl } from "@docspace/shared/utils/combineUrl";
|
||||
|
||||
import {
|
||||
getCategoryTypeByFolderType,
|
||||
getCategoryUrl,
|
||||
} from "SRC_DIR/helpers/utils";
|
||||
import FilesFilter from "@docspace/shared/api/files/filter";
|
||||
import { DeviceType } from "@docspace/shared/enums";
|
||||
|
||||
const SharingBodyStyle = { height: `calc(100vh - 156px)` };
|
||||
import { StyledNewFilesBody, StyledLink } from "../StyledPanels";
|
||||
import withLoader from "../../../HOCs/withLoader";
|
||||
|
||||
import config from "PACKAGE_FILE";
|
||||
|
||||
const NewFilesPanel = (props) => {
|
||||
const {
|
||||
@ -295,61 +288,44 @@ const NewFilesPanel = (props) => {
|
||||
});
|
||||
}, [onNewFileClick, getItemIcon, currentOpenFileId]);
|
||||
|
||||
const element = (
|
||||
<StyledAsidePanel visible={visible}>
|
||||
<Backdrop
|
||||
onClick={onClose}
|
||||
visible={visible}
|
||||
zIndex={310}
|
||||
isAside={true}
|
||||
/>
|
||||
<Aside className="header_aside-panel" visible={visible} onClose={onClose}>
|
||||
<StyledContent>
|
||||
<StyledHeaderContent>
|
||||
<Heading className="files-operations-header" size="medium" truncate>
|
||||
{t("NewFiles")}
|
||||
</Heading>
|
||||
</StyledHeaderContent>
|
||||
{!isLoading ? (
|
||||
<StyledBody className="files-operations-body">
|
||||
<StyledSharingBody style={SharingBodyStyle}>
|
||||
{filesListNode}
|
||||
</StyledSharingBody>
|
||||
</StyledBody>
|
||||
) : (
|
||||
<div key="loader" className="panel-loader-wrapper">
|
||||
<Loader type="oval" size="16px" className="panel-loader" />
|
||||
<Text as="span">{`${t("Common:LoadingProcessing")} ${t(
|
||||
"Common:LoadingDescription",
|
||||
)}`}</Text>
|
||||
</div>
|
||||
)}
|
||||
<StyledFooter>
|
||||
<Button
|
||||
className="new_files_panel-button new_file_panel-first-button"
|
||||
label={t("Viewed")}
|
||||
size="normal"
|
||||
primary
|
||||
onClick={onMarkAsRead}
|
||||
isLoading={inProgress}
|
||||
/>
|
||||
<Button
|
||||
className="new_files_panel-button"
|
||||
label={t("Common:CloseButton")}
|
||||
size="normal"
|
||||
isDisabled={inProgress}
|
||||
onClick={onClose}
|
||||
/>
|
||||
</StyledFooter>
|
||||
</StyledContent>
|
||||
</Aside>
|
||||
</StyledAsidePanel>
|
||||
);
|
||||
|
||||
return currentDeviceType === DeviceType.mobile ? (
|
||||
<Portal element={element} />
|
||||
) : (
|
||||
element
|
||||
return (
|
||||
<ModalDialog
|
||||
visible={visible}
|
||||
onClose={onClose}
|
||||
displayType={ModalDialogType.aside}
|
||||
withBodyScroll
|
||||
>
|
||||
<ModalDialog.Header>{t("NewFiles")}</ModalDialog.Header>
|
||||
<ModalDialog.Body>
|
||||
{!isLoading ? (
|
||||
<StyledNewFilesBody>{filesListNode}</StyledNewFilesBody>
|
||||
) : (
|
||||
<div key="loader" className="panel-loader-wrapper">
|
||||
<Loader type="oval" size="16px" className="panel-loader" />
|
||||
<Text as="span">{`${t("Common:LoadingProcessing")} ${t(
|
||||
"Common:LoadingDescription",
|
||||
)}`}</Text>
|
||||
</div>
|
||||
)}
|
||||
</ModalDialog.Body>
|
||||
<ModalDialog.Footer>
|
||||
<Button
|
||||
scale
|
||||
label={t("Viewed")}
|
||||
size="normal"
|
||||
primary
|
||||
onClick={onMarkAsRead}
|
||||
isLoading={inProgress}
|
||||
/>
|
||||
<Button
|
||||
scale
|
||||
label={t("Common:CloseButton")}
|
||||
size="normal"
|
||||
isDisabled={inProgress}
|
||||
onClick={onClose}
|
||||
/>
|
||||
</ModalDialog.Footer>
|
||||
</ModalDialog>
|
||||
);
|
||||
};
|
||||
|
||||
|
@ -89,40 +89,6 @@ const StyledAsidePanel = styled.div`
|
||||
padding-right: 10px;
|
||||
`}
|
||||
}
|
||||
.upload_panel-header {
|
||||
font-weight: 700;
|
||||
${(props) =>
|
||||
props.theme.interfaceDirection === "rtl"
|
||||
? css`
|
||||
padding: 19px 17px 19px auto;
|
||||
`
|
||||
: css`
|
||||
padding: 19px auto 19px 17px;
|
||||
`}
|
||||
}
|
||||
.upload-panel_header-content {
|
||||
z-index: 320;
|
||||
position: fixed;
|
||||
left: 0;
|
||||
right: 0;
|
||||
background-color: ${(props) =>
|
||||
props.theme.filesPanels.aside.backgroundColor};
|
||||
height: ${isMobile ? "55px" : "48px"};
|
||||
}
|
||||
.upload-panel_header-content::after {
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
max-width: 468px;
|
||||
height: 1px;
|
||||
background: ${(props) => props.theme.filesPanels.sharing.borderBottom};
|
||||
content: "";
|
||||
top: 48px;
|
||||
width: calc(100% - 32px);
|
||||
}
|
||||
.upload-panel_body {
|
||||
padding-top: ${isMobile ? "67px" : "60px"};
|
||||
height: ${isMobile ? "calc(100vh - 67px)" : "calc(100vh - 60px)"};
|
||||
}
|
||||
|
||||
.modal-dialog-aside {
|
||||
padding: 0;
|
||||
@ -219,17 +185,6 @@ const StyledContent = styled.div`
|
||||
background-color: ${(props) =>
|
||||
props.theme.filesPanels.content.backgroundColor};
|
||||
|
||||
.upload-panel_header-content {
|
||||
${(props) =>
|
||||
props.theme.interfaceDirection === "rtl"
|
||||
? css`
|
||||
margin-left: 0 !important;
|
||||
`
|
||||
: css`
|
||||
margin-right: 0 !important;
|
||||
`}
|
||||
}
|
||||
|
||||
.header_aside-panel-plus-icon {
|
||||
${(props) =>
|
||||
props.theme.interfaceDirection === "rtl"
|
||||
@ -316,19 +271,6 @@ const StyledHeaderContent = styled.div`
|
||||
`}
|
||||
|
||||
border-bottom: ${(props) => props.theme.filesPanels.sharing.borderBottom};
|
||||
|
||||
.upload_panel-icons-container {
|
||||
display: flex;
|
||||
${(props) =>
|
||||
props.theme.interfaceDirection === "rtl"
|
||||
? css`
|
||||
margin-right: auto;
|
||||
`
|
||||
: css`
|
||||
margin-left: auto;
|
||||
`}
|
||||
.upload_panel-vertical-dots-icon {
|
||||
}
|
||||
}
|
||||
|
||||
.files-operations-header,
|
||||
@ -427,181 +369,15 @@ const StyledBody = styled.div`
|
||||
|
||||
StyledBody.defaultProps = { theme: Base };
|
||||
|
||||
const StyledSharingBody = styled(Scrollbar)`
|
||||
position: relative;
|
||||
padding: 16px 0;
|
||||
|
||||
width: calc(100% + 16px) !important;
|
||||
|
||||
.link-row__container {
|
||||
height: 47px;
|
||||
}
|
||||
|
||||
.link-row__container,
|
||||
.sharing-row {
|
||||
.styled-element {
|
||||
margin-right: 0;
|
||||
margin-left: 0;
|
||||
}
|
||||
}
|
||||
const StyledNewFilesBody = styled.div`
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
box-sizing: border-box;
|
||||
|
||||
.row_content {
|
||||
overflow: visible;
|
||||
height: auto;
|
||||
}
|
||||
|
||||
.sharing-row {
|
||||
${(props) =>
|
||||
props.theme.interfaceDirection === "rtl"
|
||||
? css`
|
||||
padding-right: 16px;
|
||||
`
|
||||
: css`
|
||||
padding-left: 16px;
|
||||
`}
|
||||
//width: calc(100% - 16px);
|
||||
box-sizing: border-box;
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
.nav-thumb-vertical {
|
||||
opacity: 0;
|
||||
transition: opacity 200ms ease;
|
||||
}
|
||||
|
||||
:hover {
|
||||
.nav-thumb-vertical {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
.sharing_panel-text {
|
||||
line-height: 24px;
|
||||
font-weight: 600;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.sharing_panel-link {
|
||||
a {
|
||||
text-decoration: none !important;
|
||||
|
||||
span {
|
||||
font-weight: 600;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.sharing_panel-link-combo-box {
|
||||
${(props) =>
|
||||
props.theme.interfaceDirection === "rtl"
|
||||
? css`
|
||||
margin-right: auto;
|
||||
`
|
||||
: css`
|
||||
margin-left: auto;
|
||||
`}
|
||||
.combo-button {
|
||||
height: 24px;
|
||||
width: 94px;
|
||||
|
||||
svg {
|
||||
bottom: 6px;
|
||||
position: absolute;
|
||||
height: 8px;
|
||||
width: 8px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.sharing_panel-owner-icon {
|
||||
${(props) =>
|
||||
props.theme.interfaceDirection === "rtl"
|
||||
? css`
|
||||
padding-left: 19px;
|
||||
`
|
||||
: css`
|
||||
padding-right: 19px;
|
||||
`}
|
||||
}
|
||||
|
||||
.sharing_panel-remove-icon {
|
||||
${(props) =>
|
||||
props.theme.interfaceDirection === "rtl"
|
||||
? css`
|
||||
margin-right: auto;
|
||||
`
|
||||
: css`
|
||||
margin-left: auto;
|
||||
`}
|
||||
line-height: 24px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
flex-direction: row-reverse;
|
||||
|
||||
svg {
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
}
|
||||
}
|
||||
|
||||
.panel_combo-box {
|
||||
${(props) =>
|
||||
props.theme.interfaceDirection === "rtl"
|
||||
? css`
|
||||
margin-right: 0px;
|
||||
`
|
||||
: css`
|
||||
margin-left: 0px;
|
||||
`}
|
||||
|
||||
.combo-button {
|
||||
height: 30px;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
border: none;
|
||||
}
|
||||
|
||||
.combo-button-label {
|
||||
margin: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.sharing_panel-text-area {
|
||||
position: fixed;
|
||||
bottom: 70px;
|
||||
width: 94%;
|
||||
left: 0;
|
||||
right: 0;
|
||||
margin: auto;
|
||||
}
|
||||
|
||||
@media ${desktop} {
|
||||
.link-row__container {
|
||||
height: 41px;
|
||||
|
||||
.link-row {
|
||||
min-height: 41px;
|
||||
}
|
||||
}
|
||||
|
||||
.sharing-row {
|
||||
min-height: 41px;
|
||||
//padding-right: 15px;
|
||||
|
||||
.sharing_panel-remove-icon {
|
||||
font-size: 12px;
|
||||
}
|
||||
}
|
||||
|
||||
.sharing_panel-text,
|
||||
.sharing_panel-link span {
|
||||
font-size: 13px;
|
||||
}
|
||||
}
|
||||
|
||||
.row-loader {
|
||||
margin-left: 4px;
|
||||
}
|
||||
`;
|
||||
|
||||
const StyledFooter = styled.div`
|
||||
@ -936,6 +712,22 @@ const StyledLink = styled(Link)`
|
||||
|
||||
StyledModalRowContainer.defaultProps = { theme: Base };
|
||||
|
||||
const StyledUploadHeader = styled.div`
|
||||
width: 100%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
`;
|
||||
|
||||
const StyledUploadBody = styled.div`
|
||||
width: calc(100% + 16px);
|
||||
height: 100%;
|
||||
|
||||
.scroll-body {
|
||||
padding-inline-end: 0px !important;
|
||||
}
|
||||
`;
|
||||
|
||||
export {
|
||||
StyledAsidePanel,
|
||||
StyledEmbeddingPanel,
|
||||
@ -943,9 +735,11 @@ export {
|
||||
StyledContent,
|
||||
StyledHeaderContent,
|
||||
StyledBody,
|
||||
StyledSharingBody,
|
||||
StyledFooter,
|
||||
StyledLinkRow,
|
||||
StyledModalRowContainer,
|
||||
StyledLink,
|
||||
StyledNewFilesBody,
|
||||
StyledUploadHeader,
|
||||
StyledUploadBody,
|
||||
};
|
||||
|
@ -41,26 +41,13 @@ import { Button } from "@docspace/shared/components/button";
|
||||
import { tablet } from "@docspace/shared/utils";
|
||||
|
||||
const StyledFileRow = styled(Row)`
|
||||
width: calc(100% - 16px);
|
||||
width: 100%;
|
||||
box-sizing: border-box;
|
||||
${(props) =>
|
||||
props.theme.interfaceDirection === "rtl"
|
||||
? css`
|
||||
padding-right: 16px;
|
||||
`
|
||||
: css`
|
||||
padding-left: 16px;
|
||||
`}
|
||||
max-width: 484px;
|
||||
|
||||
.row_context-menu-wrapper {
|
||||
width: auto;
|
||||
display: none;
|
||||
}
|
||||
::after {
|
||||
max-width: 468px;
|
||||
width: calc(100% - 16px);
|
||||
}
|
||||
|
||||
${!isMobile && "min-height: 48px;"}
|
||||
|
||||
|
@ -24,26 +24,31 @@
|
||||
// content are licensed under the terms of the Creative Commons Attribution-ShareAlike 4.0
|
||||
// International. See the License terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
|
||||
|
||||
import VerticalDotsReactSvgUrl from "PUBLIC_DIR/images/vertical-dots.react.svg?url";
|
||||
import ClearActiveReactSvgUrl from "PUBLIC_DIR/images/clear.active.react.svg?url";
|
||||
import ButtonCancelReactSvgUrl from "PUBLIC_DIR/images/button.cancel.react.svg?url";
|
||||
|
||||
import React from "react";
|
||||
import { IconButton } from "@docspace/shared/components/icon-button";
|
||||
import { Backdrop } from "@docspace/shared/components/backdrop";
|
||||
import { Heading } from "@docspace/shared/components/heading";
|
||||
import { Aside } from "@docspace/shared/components/aside";
|
||||
import styled from "styled-components";
|
||||
import { withTranslation } from "react-i18next";
|
||||
import {
|
||||
StyledAsidePanel,
|
||||
StyledContent,
|
||||
StyledHeaderContent,
|
||||
StyledBody,
|
||||
} from "../StyledPanels";
|
||||
import FileList from "./FileList";
|
||||
import { inject, observer } from "mobx-react";
|
||||
|
||||
import { IconButton } from "@docspace/shared/components/icon-button";
|
||||
import {
|
||||
ModalDialog,
|
||||
ModalDialogType,
|
||||
} from "@docspace/shared/components/modal-dialog";
|
||||
import { DialogAsideSkeleton } from "@docspace/shared/skeletons/dialog";
|
||||
|
||||
import { StyledUploadHeader, StyledUploadBody } from "../StyledPanels";
|
||||
import FileList from "./FileList";
|
||||
import withLoader from "../../../HOCs/withLoader";
|
||||
|
||||
const StyledModal = styled(ModalDialog)`
|
||||
.heading {
|
||||
width: 100%;
|
||||
}
|
||||
`;
|
||||
|
||||
class UploadPanelComponent extends React.Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
@ -120,54 +125,39 @@ class UploadPanelComponent extends React.Component {
|
||||
: t("Files:Convert");
|
||||
|
||||
return (
|
||||
<StyledAsidePanel visible={visible}>
|
||||
<Backdrop
|
||||
onClick={this.onClose}
|
||||
visible={visible}
|
||||
zIndex={zIndex}
|
||||
isAside={true}
|
||||
/>
|
||||
<Aside
|
||||
className="header_aside-panel"
|
||||
visible={visible}
|
||||
withoutBodyScroll
|
||||
onClose={this.onClose}
|
||||
>
|
||||
<StyledContent>
|
||||
<StyledHeaderContent className="upload-panel_header-content">
|
||||
<Heading className="upload_panel-header" size="medium" truncate>
|
||||
{title}
|
||||
</Heading>
|
||||
<div className="upload_panel-icons-container">
|
||||
<div className="upload_panel-remove-icon">
|
||||
{uploaded && converted ? (
|
||||
<IconButton
|
||||
size="20"
|
||||
iconName={ClearActiveReactSvgUrl}
|
||||
// color={theme.filesPanels.upload.color}
|
||||
isClickable
|
||||
onClick={this.clearUploadPanel}
|
||||
/>
|
||||
) : (
|
||||
<IconButton
|
||||
size="20"
|
||||
iconName={ButtonCancelReactSvgUrl}
|
||||
// color={theme.filesPanels.upload.color}
|
||||
isClickable
|
||||
onClick={
|
||||
uploaded ? cancelConversion : this.onCancelUpload
|
||||
}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</StyledHeaderContent>
|
||||
<StyledBody className="upload-panel_body">
|
||||
<FileList />
|
||||
</StyledBody>
|
||||
</StyledContent>
|
||||
</Aside>
|
||||
</StyledAsidePanel>
|
||||
<StyledModal
|
||||
visible={visible}
|
||||
onClose={this.onClose}
|
||||
displayType={ModalDialogType.aside}
|
||||
>
|
||||
<ModalDialog.Header>
|
||||
<StyledUploadHeader>
|
||||
<div>{title}</div>
|
||||
<div>
|
||||
{uploaded && converted ? (
|
||||
<IconButton
|
||||
size="20"
|
||||
iconName={ClearActiveReactSvgUrl}
|
||||
isClickable
|
||||
onClick={this.clearUploadPanel}
|
||||
/>
|
||||
) : (
|
||||
<IconButton
|
||||
size="20"
|
||||
iconName={ButtonCancelReactSvgUrl}
|
||||
isClickable
|
||||
onClick={uploaded ? cancelConversion : this.onCancelUpload}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
</StyledUploadHeader>
|
||||
</ModalDialog.Header>
|
||||
<ModalDialog.Body>
|
||||
<StyledUploadBody>
|
||||
<FileList />
|
||||
</StyledUploadBody>
|
||||
</ModalDialog.Body>
|
||||
</StyledModal>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -28,6 +28,7 @@ import moment from "moment-timezone";
|
||||
|
||||
import { LANGUAGE } from "@docspace/shared/constants";
|
||||
import { getCookie } from "@docspace/shared/utils";
|
||||
import { getFeedInfo } from "../views/History/FeedInfo";
|
||||
|
||||
export const getRelativeDateDay = (t, date) => {
|
||||
moment.locale(getCookie(LANGUAGE));
|
||||
@ -62,44 +63,39 @@ export const getDateTime = (date) => {
|
||||
return given.format("LT");
|
||||
};
|
||||
|
||||
// from { response: { feeds: groupedFeeds: [{ json: "" }], json: "" }}
|
||||
// to [{ day: "", feeds: [ groupedFeeds: [{ json: {} }], json: {} ]}]
|
||||
export const addLinksToHistory = (fetchedHistory, links) => {
|
||||
if (!fetchedHistory) return null;
|
||||
if (!links) return fetchedHistory;
|
||||
|
||||
export const parseHistory = (t, fetchedHistory) => {
|
||||
let feeds = fetchedHistory.feeds;
|
||||
const historyWithLinks = fetchedHistory?.items.map((feed) => {
|
||||
const { actionType, targetType } = getFeedInfo(feed);
|
||||
if (targetType !== "roomExternalLink") return feed;
|
||||
if (actionType === "rename" || actionType === "delete") return feed;
|
||||
|
||||
const link = links.find((link) => link.sharedTo.id === feed.data.id);
|
||||
if (!link) return feed;
|
||||
|
||||
return { ...feed, data: link };
|
||||
});
|
||||
|
||||
return { ...fetchedHistory, items: historyWithLinks };
|
||||
};
|
||||
|
||||
export const parseHistory = (fetchedHistory) => {
|
||||
if (!fetchedHistory) return null;
|
||||
|
||||
let feeds = fetchedHistory?.items;
|
||||
let parsedFeeds = [];
|
||||
|
||||
for (let i = 0; i < feeds.length; i++) {
|
||||
const feedsJSON = JSON.parse(feeds[i].json);
|
||||
const feedDay = getRelativeDateDay(t, feeds[i].modifiedDate);
|
||||
|
||||
let newGroupedFeeds = [];
|
||||
if (feeds[i].groupedFeeds) {
|
||||
let groupFeeds = feeds[i].groupedFeeds;
|
||||
for (let j = 0; j < groupFeeds.length; j++)
|
||||
newGroupedFeeds.push(
|
||||
!!groupFeeds[j].target
|
||||
? groupFeeds[j].target
|
||||
: JSON.parse(groupFeeds[j].json),
|
||||
);
|
||||
}
|
||||
const feedDay = moment(feeds[i].date).format("YYYY-MM-DD");
|
||||
|
||||
if (parsedFeeds.length && parsedFeeds.at(-1).day === feedDay)
|
||||
parsedFeeds.at(-1).feeds.push({
|
||||
...feeds[i],
|
||||
json: feedsJSON,
|
||||
groupedFeeds: newGroupedFeeds,
|
||||
});
|
||||
parsedFeeds.at(-1).feeds.push({ ...feeds[i] });
|
||||
else
|
||||
parsedFeeds.push({
|
||||
day: feedDay,
|
||||
feeds: [
|
||||
{
|
||||
...feeds[i],
|
||||
json: feedsJSON,
|
||||
groupedFeeds: newGroupedFeeds,
|
||||
},
|
||||
],
|
||||
feeds: [{ ...feeds[i] }],
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -62,10 +62,18 @@ const InfoPanelBodyContent = ({
|
||||
const isInsideGroup = getIsGroups() && groupId;
|
||||
const isGroups =
|
||||
getIsGroups() ||
|
||||
(isInsideGroup && (!selectedItems.length || !!selectedItems[0].manager));
|
||||
(isInsideGroup &&
|
||||
(!selectedItems.length ||
|
||||
(selectedItems[0]?.membersCount !== null &&
|
||||
selectedItems[0]?.membersCount !== undefined)));
|
||||
const isPeople =
|
||||
getIsPeople() ||
|
||||
(getIsGroups() && !isInsideGroup && !selectedItems[0]?.manager) ||
|
||||
(getIsGroups() &&
|
||||
!isInsideGroup &&
|
||||
!(
|
||||
selectedItems[0]?.membersCount !== null &&
|
||||
selectedItems[0]?.membersCount !== undefined
|
||||
)) ||
|
||||
(isInsideGroup && selectedItems.length && !selectedItems[0].manager);
|
||||
|
||||
const isSeveralItems = props.selectedItems?.length > 1;
|
||||
|
@ -46,31 +46,6 @@ const StyledHistorySubtitle = styled.div`
|
||||
color: ${(props) => props.theme.infoPanel.history.subtitleColor};
|
||||
`;
|
||||
|
||||
const StyledUserNameLink = styled.span`
|
||||
display: inline-block;
|
||||
|
||||
white-space: normal;
|
||||
margin: 1px 0;
|
||||
|
||||
.username {
|
||||
font-size: 13px;
|
||||
font-weight: 600;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.link {
|
||||
text-decoration: underline;
|
||||
text-decoration-style: dashed;
|
||||
text-underline-offset: 2px;
|
||||
}
|
||||
|
||||
.space {
|
||||
display: inline-block;
|
||||
width: 4px;
|
||||
height: 15px;
|
||||
}
|
||||
`;
|
||||
|
||||
const StyledHistoryBlock = styled.div`
|
||||
width: 100%;
|
||||
display: flex;
|
||||
@ -121,26 +96,6 @@ const StyledHistoryBlock = styled.div`
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
${(props) =>
|
||||
props.isUserAction &&
|
||||
css`
|
||||
.info {
|
||||
flex-direction: row;
|
||||
flex-wrap: wrap;
|
||||
.message {
|
||||
display: inline-block;
|
||||
${(props) =>
|
||||
props.theme.interfaceDirection === "rtl"
|
||||
? css`
|
||||
margin-left: 4px;
|
||||
`
|
||||
: css`
|
||||
margin-right: 4px;
|
||||
`}
|
||||
}
|
||||
}
|
||||
`}
|
||||
`;
|
||||
|
||||
const StyledHistoryBlockMessage = styled.div`
|
||||
@ -148,13 +103,14 @@ const StyledHistoryBlockMessage = styled.div`
|
||||
font-size: 13px;
|
||||
line-height: 20px;
|
||||
|
||||
display: flex;
|
||||
display: inline-flex;
|
||||
gap: 4px;
|
||||
|
||||
.main-message {
|
||||
width: max-content;
|
||||
max-width: 100%;
|
||||
min-width: max-content;
|
||||
padding-inline-end: 4px;
|
||||
}
|
||||
|
||||
strong {
|
||||
@ -174,6 +130,44 @@ const StyledHistoryBlockMessage = styled.div`
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.old-role {
|
||||
color: ${(props) => props.theme.infoPanel.history.oldRoleColor};
|
||||
font-weight: 600;
|
||||
text-decoration: line-through;
|
||||
}
|
||||
`;
|
||||
|
||||
const StyledHistoryLink = styled.span`
|
||||
display: inline-block;
|
||||
|
||||
white-space: normal;
|
||||
margin: 1px 0;
|
||||
|
||||
.text {
|
||||
font-size: 13px;
|
||||
font-weight: 600;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.link {
|
||||
text-decoration: underline;
|
||||
text-decoration-style: dashed;
|
||||
text-underline-offset: 2px;
|
||||
}
|
||||
|
||||
.space {
|
||||
display: inline-block;
|
||||
width: 4px;
|
||||
height: 15px;
|
||||
}
|
||||
`;
|
||||
|
||||
const StyledHistoryBlockTagList = styled.div`
|
||||
margin-top: 8px;
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 4px;
|
||||
`;
|
||||
|
||||
const StyledHistoryBlockFilesList = styled.div`
|
||||
@ -183,28 +177,6 @@ const StyledHistoryBlockFilesList = styled.div`
|
||||
padding: 8px 0;
|
||||
background: ${(props) => props.theme.infoPanel.history.fileBlockBg};
|
||||
border-radius: 3px;
|
||||
|
||||
.show_more-link {
|
||||
cursor: pointer;
|
||||
${(props) =>
|
||||
props.theme.interfaceDirection === "rtl"
|
||||
? css`
|
||||
margin: 10px 20px 3px 0;
|
||||
`
|
||||
: css`
|
||||
margin: 10px 0 3px 20px;
|
||||
`}
|
||||
font-weight: 400;
|
||||
font-size: 13px;
|
||||
line-height: 15px;
|
||||
|
||||
strong {
|
||||
font-weight: 600;
|
||||
text-decoration: underline;
|
||||
text-decoration-style: dashed;
|
||||
text-underline-offset: 2px;
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
const StyledHistoryBlockFile = styled.div`
|
||||
@ -241,6 +213,17 @@ const StyledHistoryBlockFile = styled.div`
|
||||
flex-shrink: 0;
|
||||
color: ${(props) => props.theme.infoPanel.history.fileExstColor};
|
||||
}
|
||||
|
||||
&.old-item-title {
|
||||
.name {
|
||||
color: ${(props) => props.theme.infoPanel.history.renamedItemColor};
|
||||
text-decoration: line-through;
|
||||
}
|
||||
.exst {
|
||||
color: ${(props) => props.theme.infoPanel.history.renamedItemColor};
|
||||
text-decoration: line-through;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.location-btn {
|
||||
@ -256,6 +239,29 @@ const StyledHistoryBlockFile = styled.div`
|
||||
}
|
||||
`;
|
||||
|
||||
const StyledHistoryBlockExpandLink = styled.div`
|
||||
cursor: pointer;
|
||||
font-weight: 400;
|
||||
font-size: 13px;
|
||||
line-height: 20px;
|
||||
|
||||
&.files-list-expand-link {
|
||||
margin-top: 8px;
|
||||
margin-inline-start: 20px;
|
||||
}
|
||||
|
||||
&.user-list-expand-link {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
strong {
|
||||
font-weight: 600;
|
||||
text-decoration: underline;
|
||||
text-decoration-style: dashed;
|
||||
text-underline-offset: 2px;
|
||||
}
|
||||
`;
|
||||
|
||||
StyledHistorySubtitle.defaultProps = { theme: Base };
|
||||
StyledHistoryBlock.defaultProps = { theme: Base };
|
||||
StyledHistoryBlockMessage.defaultProps = { theme: Base };
|
||||
@ -265,9 +271,11 @@ StyledHistoryBlockFile.defaultProps = { theme: Base };
|
||||
export {
|
||||
StyledHistoryList,
|
||||
StyledHistorySubtitle,
|
||||
StyledUserNameLink,
|
||||
StyledHistoryLink,
|
||||
StyledHistoryBlock,
|
||||
StyledHistoryBlockMessage,
|
||||
StyledHistoryBlockFilesList,
|
||||
StyledHistoryBlockFile,
|
||||
StyledHistoryBlockTagList,
|
||||
StyledHistoryBlockExpandLink,
|
||||
};
|
||||
|
@ -0,0 +1,188 @@
|
||||
enum FeedAction {
|
||||
Create = "create",
|
||||
Upload = "upload",
|
||||
Update = "update",
|
||||
Convert = "convert",
|
||||
Delete = "delete",
|
||||
Rename = "rename",
|
||||
Move = "move",
|
||||
Copy = "copy",
|
||||
}
|
||||
|
||||
enum FeedTarget {
|
||||
File = "file",
|
||||
Folder = "folder",
|
||||
Room = "room",
|
||||
RoomTag = "roomTag",
|
||||
RoomLogo = "roomLogo",
|
||||
RoomExternalLink = "roomExternalLink",
|
||||
User = "user",
|
||||
Group = "group",
|
||||
}
|
||||
|
||||
export type AnyFeedInfo = (typeof feedInfo)[number];
|
||||
|
||||
export type ActionByTarget<T extends `${FeedTarget}`> = Extract<
|
||||
AnyFeedInfo,
|
||||
{ targetType: T }
|
||||
>["actionType"];
|
||||
|
||||
export const feedInfo = [
|
||||
//
|
||||
// FILE
|
||||
{
|
||||
key: "FileCreated",
|
||||
targetType: `${FeedTarget.File}`,
|
||||
actionType: `${FeedAction.Create}`,
|
||||
},
|
||||
{
|
||||
key: "FileUploaded",
|
||||
targetType: `${FeedTarget.File}`,
|
||||
actionType: `${FeedAction.Upload}`,
|
||||
},
|
||||
{
|
||||
key: "UserFileUpdated",
|
||||
targetType: `${FeedTarget.File}`,
|
||||
actionType: `${FeedAction.Update}`,
|
||||
},
|
||||
{
|
||||
key: "FileConverted",
|
||||
targetType: `${FeedTarget.File}`,
|
||||
actionType: `${FeedAction.Convert}`,
|
||||
},
|
||||
{
|
||||
key: "FileRenamed",
|
||||
targetType: `${FeedTarget.File}`,
|
||||
actionType: `${FeedAction.Rename}`,
|
||||
},
|
||||
{
|
||||
key: "FileMoved",
|
||||
targetType: `${FeedTarget.File}`,
|
||||
actionType: `${FeedAction.Move}`,
|
||||
},
|
||||
{
|
||||
key: "FileCopied",
|
||||
targetType: `${FeedTarget.File}`,
|
||||
actionType: `${FeedAction.Copy}`,
|
||||
},
|
||||
{
|
||||
key: "FileDeleted",
|
||||
targetType: `${FeedTarget.File}`,
|
||||
actionType: `${FeedAction.Delete}`,
|
||||
},
|
||||
//
|
||||
// FOLDER
|
||||
{
|
||||
key: "FolderCreated",
|
||||
targetType: `${FeedTarget.Folder}`,
|
||||
actionType: `${FeedAction.Create}`,
|
||||
},
|
||||
{
|
||||
key: "FolderRenamed",
|
||||
targetType: `${FeedTarget.Folder}`,
|
||||
actionType: `${FeedAction.Rename}`,
|
||||
},
|
||||
{
|
||||
key: "FolderMoved",
|
||||
targetType: `${FeedTarget.Folder}`,
|
||||
actionType: `${FeedAction.Move}`,
|
||||
},
|
||||
{
|
||||
key: "FolderCopied",
|
||||
targetType: `${FeedTarget.Folder}`,
|
||||
actionType: `${FeedAction.Copy}`,
|
||||
},
|
||||
{
|
||||
key: "FolderDeleted",
|
||||
targetType: `${FeedTarget.Folder}`,
|
||||
actionType: `${FeedAction.Delete}`,
|
||||
},
|
||||
//
|
||||
// ROOM
|
||||
{
|
||||
key: "RoomCreated",
|
||||
targetType: `${FeedTarget.Room}`,
|
||||
actionType: `${FeedAction.Create}`,
|
||||
},
|
||||
{
|
||||
key: "RoomRenamed",
|
||||
targetType: `${FeedTarget.Room}`,
|
||||
actionType: `${FeedAction.Rename}`,
|
||||
},
|
||||
// ROOM TAGS
|
||||
{
|
||||
key: "AddedRoomTags",
|
||||
targetType: `${FeedTarget.RoomTag}`,
|
||||
actionType: `${FeedAction.Create}`,
|
||||
},
|
||||
{
|
||||
key: "DeletedRoomTags",
|
||||
targetType: `${FeedTarget.RoomTag}`,
|
||||
actionType: `${FeedAction.Delete}`,
|
||||
},
|
||||
// ROOM LOGO
|
||||
{
|
||||
key: "RoomLogoCreated",
|
||||
targetType: `${FeedTarget.RoomLogo}`,
|
||||
actionType: `${FeedAction.Create}`,
|
||||
},
|
||||
{
|
||||
key: "RoomLogoDeleted",
|
||||
targetType: `${FeedTarget.RoomLogo}`,
|
||||
actionType: `${FeedAction.Delete}`,
|
||||
},
|
||||
// ROOM EXTERNAL LINK
|
||||
{
|
||||
key: "RoomExternalLinkCreated",
|
||||
targetType: `${FeedTarget.RoomExternalLink}`,
|
||||
actionType: `${FeedAction.Create}`,
|
||||
},
|
||||
{
|
||||
key: "RoomExternalLinkRenamed",
|
||||
targetType: `${FeedTarget.RoomExternalLink}`,
|
||||
actionType: `${FeedAction.Rename}`,
|
||||
},
|
||||
{
|
||||
key: "RoomExternalLinkDeleted",
|
||||
targetType: `${FeedTarget.RoomExternalLink}`,
|
||||
actionType: `${FeedAction.Delete}`,
|
||||
},
|
||||
//
|
||||
// USER
|
||||
{
|
||||
key: "RoomCreateUser",
|
||||
targetType: `${FeedTarget.User}`,
|
||||
actionType: `${FeedAction.Create}`,
|
||||
},
|
||||
{
|
||||
key: "RoomUpdateAccessForUser",
|
||||
targetType: `${FeedTarget.User}`,
|
||||
actionType: `${FeedAction.Update}`,
|
||||
},
|
||||
{
|
||||
key: "RoomRemoveUser",
|
||||
targetType: `${FeedTarget.User}`,
|
||||
actionType: `${FeedAction.Delete}`,
|
||||
},
|
||||
//
|
||||
// GROUP
|
||||
{
|
||||
key: "RoomGroupAdded",
|
||||
targetType: `${FeedTarget.Group}`,
|
||||
actionType: `${FeedAction.Create}`,
|
||||
},
|
||||
{
|
||||
key: "RoomUpdateAccessForGroup",
|
||||
targetType: `${FeedTarget.Group}`,
|
||||
actionType: `${FeedAction.Update}`,
|
||||
},
|
||||
{
|
||||
key: "RoomGroupRemove",
|
||||
targetType: `${FeedTarget.Group}`,
|
||||
actionType: `${FeedAction.Delete}`,
|
||||
},
|
||||
] as const;
|
||||
|
||||
export const getFeedInfo = (feed: { action: { key: AnyFeedInfo["key"] } }) => {
|
||||
return feedInfo.find((info) => info.key === feed.action.key)! || {};
|
||||
};
|
@ -24,47 +24,23 @@
|
||||
// content are licensed under the terms of the Creative Commons Attribution-ShareAlike 4.0
|
||||
// International. See the License terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
|
||||
|
||||
import React from "react";
|
||||
import AtReactSvgUrl from "PUBLIC_DIR/images/@.react.svg?url";
|
||||
import { Avatar } from "@docspace/shared/components/avatar";
|
||||
import { Text } from "@docspace/shared/components/text";
|
||||
import HistoryBlockMessage from "./HistoryBlockMessage";
|
||||
import HistoryBlockItemList from "./HistoryBlockItemList";
|
||||
import HistoryBlockUser from "./HistoryBlockUser";
|
||||
import { FeedItemTypes } from "@docspace/shared/enums";
|
||||
import DefaultUserAvatarSmall from "PUBLIC_DIR/images/default_user_photo_size_32-32.png";
|
||||
import { StyledHistoryBlock } from "../../styles/history";
|
||||
import { getDateTime } from "../../helpers/HistoryHelper";
|
||||
import { decode } from "he";
|
||||
|
||||
const HistoryBlock = ({
|
||||
t,
|
||||
selectionIsFile,
|
||||
feed,
|
||||
selectedFolder,
|
||||
infoPanelSelection,
|
||||
getInfoPanelItemIcon,
|
||||
checkAndOpenLocationAction,
|
||||
openUser,
|
||||
isVisitor,
|
||||
isCollaborator,
|
||||
withFileList,
|
||||
isLastEntity,
|
||||
}) => {
|
||||
const { target, initiator, json, groupedFeeds } = feed;
|
||||
import HistoryBlockContent from "./HistoryBlockContent";
|
||||
|
||||
const users = [target, ...groupedFeeds].filter(
|
||||
(user, index, self) =>
|
||||
self.findIndex((user2) => user2?.id === user?.id) === index,
|
||||
);
|
||||
const HistoryBlock = ({ t, feed, isLastEntity }) => {
|
||||
const { action, initiator, date } = feed;
|
||||
|
||||
const isUserAction = json.Item === FeedItemTypes.User && target;
|
||||
const isItemAction =
|
||||
json.Item === FeedItemTypes.File || json.Item === FeedItemTypes.Folder;
|
||||
|
||||
const userAvatar = initiator.hasAvatar
|
||||
? initiator.avatarSmall
|
||||
: DefaultUserAvatarSmall;
|
||||
const isUserAction =
|
||||
action.key === "RoomCreateUser" ||
|
||||
action.key === "RoomUpdateAccessForUser" ||
|
||||
action.key === "RoomRemoveUser";
|
||||
|
||||
return (
|
||||
<StyledHistoryBlock
|
||||
@ -75,11 +51,13 @@ const HistoryBlock = ({
|
||||
role="user"
|
||||
className="avatar"
|
||||
size="min"
|
||||
source={
|
||||
userAvatar ||
|
||||
(initiator.displayName ? "" : initiator.email && AtReactSvgUrl)
|
||||
}
|
||||
userName={initiator.displayName}
|
||||
source={
|
||||
initiator.hasAvatar
|
||||
? initiator.avatarSmall
|
||||
: DefaultUserAvatarSmall ||
|
||||
(initiator.displayName ? "" : initiator.email && AtReactSvgUrl)
|
||||
}
|
||||
/>
|
||||
<div className="info">
|
||||
<div className="title">
|
||||
@ -93,38 +71,10 @@ const HistoryBlock = ({
|
||||
{t("Common:Owner").toLowerCase()}
|
||||
</Text>
|
||||
)}
|
||||
<Text className="date">{getDateTime(json.ModifiedDate)}</Text>
|
||||
<Text className="date">{getDateTime(date)}</Text>
|
||||
</div>
|
||||
|
||||
<HistoryBlockMessage
|
||||
t={t}
|
||||
className="message"
|
||||
action={json}
|
||||
groupedActions={groupedFeeds}
|
||||
selectedFolder={selectedFolder}
|
||||
infoPanelSelection={infoPanelSelection}
|
||||
/>
|
||||
|
||||
{isItemAction && withFileList && (
|
||||
<HistoryBlockItemList
|
||||
t={t}
|
||||
items={[json, ...groupedFeeds]}
|
||||
getInfoPanelItemIcon={getInfoPanelItemIcon}
|
||||
checkAndOpenLocationAction={checkAndOpenLocationAction}
|
||||
/>
|
||||
)}
|
||||
|
||||
{isUserAction &&
|
||||
users.map((user, i) => (
|
||||
<HistoryBlockUser
|
||||
isVisitor={isVisitor}
|
||||
isCollaborator={isCollaborator}
|
||||
key={user.id}
|
||||
user={user}
|
||||
withComma={i < users.length - 1}
|
||||
openUser={openUser}
|
||||
/>
|
||||
))}
|
||||
<HistoryBlockContent feed={feed} />
|
||||
</div>
|
||||
</StyledHistoryBlock>
|
||||
);
|
||||
|
@ -0,0 +1,136 @@
|
||||
// (c) Copyright Ascensio System SIA 2009-2024
|
||||
//
|
||||
// This program is a free software product.
|
||||
// You can redistribute it and/or modify it under the terms
|
||||
// of the GNU Affero General Public License (AGPL) version 3 as published by the Free Software
|
||||
// Foundation. In accordance with Section 7(a) of the GNU AGPL its Section 15 shall be amended
|
||||
// to the effect that Ascensio System SIA expressly excludes the warranty of non-infringement of
|
||||
// any third-party rights.
|
||||
//
|
||||
// This program is distributed WITHOUT ANY WARRANTY, without even the implied warranty
|
||||
// of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. For details, see
|
||||
// the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html
|
||||
//
|
||||
// You can contact Ascensio System SIA at Lubanas st. 125a-25, Riga, Latvia, EU, LV-1021.
|
||||
//
|
||||
// The interactive user interfaces in modified source and object code versions of the Program must
|
||||
// display Appropriate Legal Notices, as required under Section 5 of the GNU AGPL version 3.
|
||||
//
|
||||
// Pursuant to Section 7(b) of the License you must retain the original Product logo when
|
||||
// distributing the program. Pursuant to Section 7(e) we decline to grant you any rights under
|
||||
// trademark law for use of our trademarks.
|
||||
//
|
||||
// All the Product's GUI elements, including illustrations and icon sets, as well as technical writing
|
||||
// content are licensed under the terms of the Creative Commons Attribution-ShareAlike 4.0
|
||||
// International. See the License terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
|
||||
|
||||
import { useState } from "react";
|
||||
import { useNavigate, NavigateFunction } from "react-router-dom";
|
||||
import { decode } from "he";
|
||||
import { inject, observer } from "mobx-react";
|
||||
import { Link } from "@docspace/shared/components/link";
|
||||
import { Text } from "@docspace/shared/components/text";
|
||||
import { Trans, withTranslation } from "react-i18next";
|
||||
import { TTranslation } from "@docspace/shared/types";
|
||||
import {
|
||||
StyledHistoryBlockExpandLink,
|
||||
StyledHistoryLink,
|
||||
} from "../../../styles/history";
|
||||
|
||||
const EXPANSION_THRESHOLD = 8;
|
||||
|
||||
interface HistoryGroupListProps {
|
||||
t: TTranslation;
|
||||
feed: any;
|
||||
isVisitor?: boolean;
|
||||
isCollaborator?: boolean;
|
||||
setPeopleSelection?: (newSelection: any[]) => void;
|
||||
setPeopleBufferSelection?: (newBufferSelection: any) => void;
|
||||
setFilesSelection?: (newSelection: any[]) => void;
|
||||
setFilesBufferSelection?: (newBufferSelection: any) => void;
|
||||
}
|
||||
|
||||
const HistoryGroupList = ({
|
||||
t,
|
||||
feed,
|
||||
isVisitor,
|
||||
isCollaborator,
|
||||
setPeopleSelection,
|
||||
setPeopleBufferSelection,
|
||||
setFilesSelection,
|
||||
setFilesBufferSelection,
|
||||
}: HistoryGroupListProps) => {
|
||||
const navigate = useNavigate();
|
||||
|
||||
const [isExpanded, setIsExpanded] = useState(
|
||||
1 + feed.related.length <= EXPANSION_THRESHOLD,
|
||||
);
|
||||
const onExpand = () => setIsExpanded(true);
|
||||
|
||||
const groupsData = [
|
||||
feed.data,
|
||||
...feed.related.map((relatedFeed: any) => relatedFeed.data),
|
||||
];
|
||||
|
||||
const onGroupClick = (groupId: string) => {
|
||||
setPeopleSelection?.([]);
|
||||
setPeopleBufferSelection?.(null);
|
||||
setFilesSelection?.([]);
|
||||
setFilesBufferSelection?.(null);
|
||||
navigate(`/accounts/groups/${groupId}/filter`);
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
{groupsData.map(({ group }, i) => {
|
||||
if (!isExpanded && i > EXPANSION_THRESHOLD - 1) return null;
|
||||
const withComma = !isExpanded
|
||||
? i < EXPANSION_THRESHOLD - 1
|
||||
: i < groupsData.length - 1;
|
||||
return (
|
||||
<StyledHistoryLink key={group.id}>
|
||||
{isVisitor || isCollaborator ? (
|
||||
<Text as="span" className="text" fontWeight={600}>
|
||||
{decode(group.name)}
|
||||
</Text>
|
||||
) : (
|
||||
<Link
|
||||
className="text link"
|
||||
onClick={() => onGroupClick(group.id)}
|
||||
>
|
||||
{decode(group.name)}
|
||||
</Link>
|
||||
)}
|
||||
|
||||
{withComma && ","}
|
||||
<div className="space" />
|
||||
</StyledHistoryLink>
|
||||
);
|
||||
})}
|
||||
|
||||
{!isExpanded && (
|
||||
<StyledHistoryBlockExpandLink
|
||||
className="user-list-expand-link"
|
||||
onClick={onExpand}
|
||||
>
|
||||
<Trans
|
||||
t={t}
|
||||
ns="InfoPanel"
|
||||
i18nKey="AndMoreLabel"
|
||||
values={{ count: groupsData.length - EXPANSION_THRESHOLD }}
|
||||
components={{ 1: <strong /> }}
|
||||
/>
|
||||
</StyledHistoryBlockExpandLink>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default inject(({ userStore, peopleStore, filesStore }) => ({
|
||||
isVisitor: userStore.user.isVisitor,
|
||||
isCollaborator: userStore.user.isCollaborator,
|
||||
setPeopleSelection: peopleStore.selectionStore.setSelection,
|
||||
setPeopleBufferSelection: peopleStore.selectionStore.setBufferSelection,
|
||||
setFilesSelection: filesStore.setSelection,
|
||||
setFilesBufferSelection: filesStore.setBufferSelection,
|
||||
}))(withTranslation(["InfoPanel"])(observer(HistoryGroupList)));
|
@ -0,0 +1,186 @@
|
||||
// (c) Copyright Ascensio System SIA 2009-2024
|
||||
//
|
||||
// This program is a free software product.
|
||||
// You can redistribute it and/or modify it under the terms
|
||||
// of the GNU Affero General Public License (AGPL) version 3 as published by the Free Software
|
||||
// Foundation. In accordance with Section 7(a) of the GNU AGPL its Section 15 shall be amended
|
||||
// to the effect that Ascensio System SIA expressly excludes the warranty of non-infringement of
|
||||
// any third-party rights.
|
||||
//
|
||||
// This program is distributed WITHOUT ANY WARRANTY, without even the implied warranty
|
||||
// of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. For details, see
|
||||
// the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html
|
||||
//
|
||||
// You can contact Ascensio System SIA at Lubanas st. 125a-25, Riga, Latvia, EU, LV-1021.
|
||||
//
|
||||
// The interactive user interfaces in modified source and object code versions of the Program must
|
||||
// display Appropriate Legal Notices, as required under Section 5 of the GNU AGPL version 3.
|
||||
//
|
||||
// Pursuant to Section 7(b) of the License you must retain the original Product logo when
|
||||
// distributing the program. Pursuant to Section 7(e) we decline to grant you any rights under
|
||||
// trademark law for use of our trademarks.
|
||||
//
|
||||
// All the Product's GUI elements, including illustrations and icon sets, as well as technical writing
|
||||
// content are licensed under the terms of the Creative Commons Attribution-ShareAlike 4.0
|
||||
// International. See the License terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
|
||||
|
||||
import FolderLocationReactSvgUrl from "PUBLIC_DIR/images/folder-location.react.svg?url";
|
||||
import { useState } from "react";
|
||||
import { Trans, withTranslation } from "react-i18next";
|
||||
import { inject, observer } from "mobx-react";
|
||||
|
||||
import { IconButton } from "@docspace/shared/components/icon-button";
|
||||
import { ReactSVG } from "react-svg";
|
||||
import { TTranslation } from "@docspace/shared/types";
|
||||
import { getFileExtension } from "@docspace/shared/utils/common";
|
||||
import {
|
||||
StyledHistoryBlockExpandLink,
|
||||
StyledHistoryBlockFile,
|
||||
StyledHistoryBlockFilesList,
|
||||
} from "../../../styles/history";
|
||||
|
||||
import { ActionByTarget } from "../FeedInfo";
|
||||
|
||||
const EXPANSION_THRESHOLD = 3;
|
||||
|
||||
type HistoryItemListProps = {
|
||||
t: TTranslation;
|
||||
feed: any;
|
||||
nameWithoutExtension?: (title: string) => string;
|
||||
getInfoPanelItemIcon?: (item: any, size: number) => string;
|
||||
checkAndOpenLocationAction?: (item: any) => void;
|
||||
} & (
|
||||
| {
|
||||
actionType: ActionByTarget<"file">;
|
||||
targetType: "file";
|
||||
}
|
||||
| {
|
||||
actionType: ActionByTarget<"folder">;
|
||||
targetType: "folder";
|
||||
}
|
||||
);
|
||||
|
||||
export const HistoryItemList = ({
|
||||
t,
|
||||
feed,
|
||||
actionType,
|
||||
targetType,
|
||||
nameWithoutExtension,
|
||||
getInfoPanelItemIcon,
|
||||
checkAndOpenLocationAction,
|
||||
}: HistoryItemListProps) => {
|
||||
const [isExpanded, setIsExpanded] = useState(
|
||||
1 + feed.related.length <= EXPANSION_THRESHOLD,
|
||||
);
|
||||
const onExpand = () => setIsExpanded(true);
|
||||
|
||||
const items = [
|
||||
feed.data,
|
||||
...feed.related.map((relatedFeeds) => relatedFeeds.data),
|
||||
].map((item) => {
|
||||
return {
|
||||
...item,
|
||||
title: nameWithoutExtension!(item.title || item.newTitle),
|
||||
fileExst: getFileExtension(item.title || item.newTitle),
|
||||
isFolder: targetType === "folder",
|
||||
};
|
||||
});
|
||||
|
||||
const oldItem = actionType === "rename" && {
|
||||
title: nameWithoutExtension!(feed.data.oldTitle),
|
||||
fileExst: getFileExtension(feed.data.oldTitle),
|
||||
};
|
||||
|
||||
return (
|
||||
<StyledHistoryBlockFilesList>
|
||||
{items.map((item, i) => {
|
||||
if (!isExpanded && i > EXPANSION_THRESHOLD - 1) return null;
|
||||
return (
|
||||
<StyledHistoryBlockFile
|
||||
isRoom={false}
|
||||
key={`${feed.action.id}_${item.id}`}
|
||||
>
|
||||
<ReactSVG className="icon" src={getInfoPanelItemIcon!(item, 24)} />
|
||||
<div className="item-title">
|
||||
{item.title ? (
|
||||
<>
|
||||
<span className="name" key="hbil-item-name">
|
||||
{item.title}
|
||||
</span>
|
||||
{item.fileExst && (
|
||||
<span className="exst" key="hbil-item-exst">
|
||||
{item.fileExst}
|
||||
</span>
|
||||
)}
|
||||
</>
|
||||
) : (
|
||||
<span className="name">{item.fileExst}</span>
|
||||
)}
|
||||
</div>
|
||||
<IconButton
|
||||
className="location-btn"
|
||||
iconName={FolderLocationReactSvgUrl}
|
||||
size="16"
|
||||
isFill
|
||||
onClick={() => checkAndOpenLocationAction!(item)}
|
||||
title={t("Files:OpenLocation")}
|
||||
/>
|
||||
</StyledHistoryBlockFile>
|
||||
);
|
||||
})}
|
||||
|
||||
{actionType === "rename" && oldItem && (
|
||||
<StyledHistoryBlockFile>
|
||||
<div style={{ width: "24px", height: "24px" }} />
|
||||
<div className="item-title old-item-title">
|
||||
{oldItem.title ? (
|
||||
<>
|
||||
<span className="name" key="hbil-item-name">
|
||||
{oldItem.title}
|
||||
</span>
|
||||
{oldItem.fileExst && (
|
||||
<span className="exst" key="hbil-item-exst">
|
||||
{oldItem.fileExst}
|
||||
</span>
|
||||
)}
|
||||
</>
|
||||
) : (
|
||||
<span className="name">{oldItem.fileExst}</span>
|
||||
)}
|
||||
</div>
|
||||
</StyledHistoryBlockFile>
|
||||
)}
|
||||
|
||||
{!isExpanded && (
|
||||
<StyledHistoryBlockExpandLink
|
||||
className="files-list-expand-link"
|
||||
onClick={onExpand}
|
||||
>
|
||||
<Trans
|
||||
t={t}
|
||||
ns="InfoPanel"
|
||||
i18nKey="AndMoreLabel"
|
||||
values={{ count: items.length - EXPANSION_THRESHOLD }}
|
||||
components={{ 1: <strong /> }}
|
||||
/>
|
||||
</StyledHistoryBlockExpandLink>
|
||||
)}
|
||||
</StyledHistoryBlockFilesList>
|
||||
);
|
||||
};
|
||||
|
||||
export default inject(({ infoPanelStore, filesActionsStore }) => {
|
||||
const { getInfoPanelItemIcon } = infoPanelStore;
|
||||
const { nameWithoutExtension, checkAndOpenLocationAction } =
|
||||
filesActionsStore;
|
||||
|
||||
return {
|
||||
getInfoPanelItemIcon,
|
||||
nameWithoutExtension,
|
||||
checkAndOpenLocationAction,
|
||||
};
|
||||
})(
|
||||
withTranslation(["InfoPanel", "Common", "Translations"])(
|
||||
observer(HistoryItemList),
|
||||
),
|
||||
);
|
@ -24,42 +24,28 @@
|
||||
// content are licensed under the terms of the Creative Commons Attribution-ShareAlike 4.0
|
||||
// International. See the License terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
|
||||
|
||||
import React from "react";
|
||||
import { useNavigate } from "react-router-dom";
|
||||
import { decode } from "he";
|
||||
import { withTranslation } from "react-i18next";
|
||||
import { inject, observer } from "mobx-react";
|
||||
import { TTranslation } from "@docspace/shared/types";
|
||||
import { StyledHistoryBlockMessage } from "../../../styles/history";
|
||||
import { useFeedTranslation } from "../useFeedTranslation";
|
||||
|
||||
import { Link } from "@docspace/shared/components/link";
|
||||
import { StyledUserNameLink } from "../../styles/history";
|
||||
import { Text } from "@docspace/shared/components/text";
|
||||
const HistoryBlockUser = ({
|
||||
user,
|
||||
withComma,
|
||||
openUser,
|
||||
isVisitor,
|
||||
isCollaborator,
|
||||
}) => {
|
||||
const username = user.displayName;
|
||||
const navigate = useNavigate();
|
||||
|
||||
const onUserClick = () => {
|
||||
openUser(user, navigate);
|
||||
};
|
||||
interface HistoryMainTextProps {
|
||||
t: TTranslation;
|
||||
feed: any;
|
||||
}
|
||||
|
||||
const HistoryMainText = ({ t, feed }: HistoryMainTextProps) => {
|
||||
return (
|
||||
<StyledUserNameLink key={user.id} className="user">
|
||||
{isVisitor || isCollaborator ? (
|
||||
<Text as="span" fontWeight={600}>
|
||||
{decode(username)}
|
||||
</Text>
|
||||
) : (
|
||||
<Link className="username link" onClick={onUserClick}>
|
||||
{decode(username)}
|
||||
</Link>
|
||||
)}
|
||||
{withComma ? "," : ""}
|
||||
{withComma && <div className="space"></div>}
|
||||
</StyledUserNameLink>
|
||||
<StyledHistoryBlockMessage className="message">
|
||||
<span className="main-message">{useFeedTranslation(t, feed)}</span>{" "}
|
||||
</StyledHistoryBlockMessage>
|
||||
);
|
||||
};
|
||||
|
||||
export default HistoryBlockUser;
|
||||
export default inject(({ infoPanelStore }) => {
|
||||
const { infoPanelSelection } = infoPanelStore;
|
||||
return {
|
||||
infoPanelSelection,
|
||||
};
|
||||
})(withTranslation(["InfoPanel"])(observer(HistoryMainText)));
|
@ -24,57 +24,41 @@
|
||||
// content are licensed under the terms of the Creative Commons Attribution-ShareAlike 4.0
|
||||
// International. See the License terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
|
||||
|
||||
import React from "react";
|
||||
import { Trans } from "react-i18next";
|
||||
import { withTranslation } from "react-i18next";
|
||||
import { inject, observer } from "mobx-react";
|
||||
import { TTranslation } from "@docspace/shared/types";
|
||||
import { StyledHistoryBlockMessage } from "../../../styles/history";
|
||||
|
||||
import { FeedActionTypes, FeedItemTypes } from "@docspace/shared/enums";
|
||||
type HistoryMainTextFolderInfoProps = {
|
||||
t: TTranslation;
|
||||
feed: any;
|
||||
selectedFolderId?: number;
|
||||
};
|
||||
|
||||
import { StyledHistoryBlockMessage } from "../../styles/history";
|
||||
import getBlockMessageTranslation from "./HistroryBlockMessageTranslations";
|
||||
|
||||
const HistoryBlockMessage = ({
|
||||
const HistoryMainTextFolderInfo = ({
|
||||
t,
|
||||
action,
|
||||
groupedActions,
|
||||
selectedFolder,
|
||||
infoPanelSelection,
|
||||
}) => {
|
||||
const message = getBlockMessageTranslation(
|
||||
t,
|
||||
action.hasOwnProperty("Action") ? action.Action : action.Actions,
|
||||
action.Item,
|
||||
action.Item === FeedItemTypes.File || action.Item === FeedItemTypes.Folder
|
||||
? !!groupedActions.length
|
||||
: false,
|
||||
action.Item === FeedItemTypes.Room
|
||||
? { roomTitle: action.Title, oldRoomTitle: "" }
|
||||
: {},
|
||||
);
|
||||
|
||||
const getFolderLabel = () => {
|
||||
if (action.Item !== "file" && action.Item !== "folder") return "";
|
||||
|
||||
const itemLocationId = +action.ExtraLocation;
|
||||
if (selectedFolder?.id === itemLocationId) return "";
|
||||
if (infoPanelSelection?.isRoom && infoPanelSelection?.id === itemLocationId)
|
||||
return "";
|
||||
|
||||
const folderTitle = action.ExtraLocationTitle;
|
||||
if (!folderTitle) return "";
|
||||
|
||||
return (
|
||||
<span className="folder-label">
|
||||
{` ${t("FeedLocationLabel", { folderTitle })}`}
|
||||
</span>
|
||||
);
|
||||
};
|
||||
feed,
|
||||
selectedFolderId,
|
||||
}: HistoryMainTextFolderInfoProps) => {
|
||||
if (
|
||||
feed.data.parentId === selectedFolderId ||
|
||||
feed.data.toFolderId === selectedFolderId
|
||||
)
|
||||
return null;
|
||||
|
||||
return (
|
||||
<StyledHistoryBlockMessage className="message">
|
||||
<span className="main-message">{message}</span>
|
||||
{getFolderLabel()}
|
||||
<span className="folder-label">
|
||||
{` ${t("FeedLocationLabel", { folderTitle: feed.data.parentTitle || feed.data.toFolderTitle })}`}
|
||||
</span>
|
||||
</StyledHistoryBlockMessage>
|
||||
);
|
||||
};
|
||||
|
||||
export default HistoryBlockMessage;
|
||||
export default inject(({ selectedFolderStore }) => ({
|
||||
selectedFolderId: selectedFolderStore.id,
|
||||
}))(
|
||||
withTranslation(["InfoPanel", "Common", "Translations"])(
|
||||
observer(HistoryMainTextFolderInfo),
|
||||
),
|
||||
);
|
@ -0,0 +1,79 @@
|
||||
// (c) Copyright Ascensio System SIA 2009-2024
|
||||
//
|
||||
// This program is a free software product.
|
||||
// You can redistribute it and/or modify it under the terms
|
||||
// of the GNU Affero General Public License (AGPL) version 3 as published by the Free Software
|
||||
// Foundation. In accordance with Section 7(a) of the GNU AGPL its Section 15 shall be amended
|
||||
// to the effect that Ascensio System SIA expressly excludes the warranty of non-infringement of
|
||||
// any third-party rights.
|
||||
//
|
||||
// This program is distributed WITHOUT ANY WARRANTY, without even the implied warranty
|
||||
// of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. For details, see
|
||||
// the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html
|
||||
//
|
||||
// You can contact Ascensio System SIA at Lubanas st. 125a-25, Riga, Latvia, EU, LV-1021.
|
||||
//
|
||||
// The interactive user interfaces in modified source and object code versions of the Program must
|
||||
// display Appropriate Legal Notices, as required under Section 5 of the GNU AGPL version 3.
|
||||
//
|
||||
// Pursuant to Section 7(b) of the License you must retain the original Product logo when
|
||||
// distributing the program. Pursuant to Section 7(e) we decline to grant you any rights under
|
||||
// trademark law for use of our trademarks.
|
||||
//
|
||||
// All the Product's GUI elements, including illustrations and icon sets, as well as technical writing
|
||||
// content are licensed under the terms of the Creative Commons Attribution-ShareAlike 4.0
|
||||
// International. See the License terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
|
||||
|
||||
import { inject, observer } from "mobx-react";
|
||||
import { StyledHistoryLink } from "../../../styles/history";
|
||||
import { ActionByTarget } from "../FeedInfo";
|
||||
import { decode } from "he";
|
||||
import { Link } from "@docspace/shared/components/link";
|
||||
import { toastr } from "@docspace/shared/components/toast";
|
||||
import { withTranslation } from "react-i18next";
|
||||
import { Text } from "@docspace/shared/components/text";
|
||||
|
||||
interface HistoryRoomExternalLinkProps {
|
||||
feed: any;
|
||||
actionType: ActionByTarget<"roomTag">;
|
||||
}
|
||||
|
||||
const HistoryRoomExternalLink = ({
|
||||
t,
|
||||
feed,
|
||||
actionType,
|
||||
canEditLink,
|
||||
setEditLinkPanelIsVisible,
|
||||
setLinkParams,
|
||||
}: HistoryRoomExternalLinkProps) => {
|
||||
const onEditLink = () => {
|
||||
if (!feed.data.sharedTo) {
|
||||
toastr.error(t("FeedLinkWasDeleted"));
|
||||
return;
|
||||
}
|
||||
|
||||
setLinkParams({ isEdit: true, link: feed.data });
|
||||
setEditLinkPanelIsVisible(true);
|
||||
};
|
||||
|
||||
if (actionType === "create")
|
||||
return (
|
||||
<StyledHistoryLink>
|
||||
{canEditLink ? (
|
||||
<Link className="text link" onClick={onEditLink}>
|
||||
{decode(feed.data.title || feed.data.sharedTo?.title)}
|
||||
</Link>
|
||||
) : (
|
||||
<Text as="span" className="text">
|
||||
{decode(feed.data.title || feed.data.sharedTo?.title)}
|
||||
</Text>
|
||||
)}
|
||||
</StyledHistoryLink>
|
||||
);
|
||||
};
|
||||
|
||||
export default inject(({ userStore, dialogsStore }) => ({
|
||||
canEditLink: !(userStore.user.isVisitor || userStore.user.isCollaborator),
|
||||
setEditLinkPanelIsVisible: dialogsStore.setEditLinkPanelIsVisible,
|
||||
setLinkParams: dialogsStore.setLinkParams,
|
||||
}))(withTranslation(["InfoPanel"])(observer(HistoryRoomExternalLink)));
|
@ -0,0 +1,69 @@
|
||||
// (c) Copyright Ascensio System SIA 2009-2024
|
||||
//
|
||||
// This program is a free software product.
|
||||
// You can redistribute it and/or modify it under the terms
|
||||
// of the GNU Affero General Public License (AGPL) version 3 as published by the Free Software
|
||||
// Foundation. In accordance with Section 7(a) of the GNU AGPL its Section 15 shall be amended
|
||||
// to the effect that Ascensio System SIA expressly excludes the warranty of non-infringement of
|
||||
// any third-party rights.
|
||||
//
|
||||
// This program is distributed WITHOUT ANY WARRANTY, without even the implied warranty
|
||||
// of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. For details, see
|
||||
// the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html
|
||||
//
|
||||
// You can contact Ascensio System SIA at Lubanas st. 125a-25, Riga, Latvia, EU, LV-1021.
|
||||
//
|
||||
// The interactive user interfaces in modified source and object code versions of the Program must
|
||||
// display Appropriate Legal Notices, as required under Section 5 of the GNU AGPL version 3.
|
||||
//
|
||||
// Pursuant to Section 7(b) of the License you must retain the original Product logo when
|
||||
// distributing the program. Pursuant to Section 7(e) we decline to grant you any rights under
|
||||
// trademark law for use of our trademarks.
|
||||
//
|
||||
// All the Product's GUI elements, including illustrations and icon sets, as well as technical writing
|
||||
// content are licensed under the terms of the Creative Commons Attribution-ShareAlike 4.0
|
||||
// International. See the License terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
|
||||
|
||||
import { StyledHistoryBlockTagList } from "../../../styles/history";
|
||||
import { ActionByTarget } from "../FeedInfo";
|
||||
import { Tag } from "@docspace/shared/components/tag";
|
||||
|
||||
interface HistoryRoomTagListProps {
|
||||
feed: any;
|
||||
actionType: ActionByTarget<"roomTag">;
|
||||
}
|
||||
|
||||
const HistoryRoomTagList = ({ feed, actionType }: HistoryRoomTagListProps) => {
|
||||
if (actionType === "create")
|
||||
return (
|
||||
<StyledHistoryBlockTagList>
|
||||
{feed.data.tags.map((tag: string) => (
|
||||
<Tag
|
||||
className="history-tag"
|
||||
key={tag}
|
||||
label={tag}
|
||||
tag={tag}
|
||||
isNewTag
|
||||
/>
|
||||
))}
|
||||
</StyledHistoryBlockTagList>
|
||||
);
|
||||
|
||||
if (actionType === "delete") {
|
||||
return (
|
||||
<StyledHistoryBlockTagList>
|
||||
{feed.data.tags.map((tag: string) => (
|
||||
<Tag
|
||||
className="history-tag deleted-tag"
|
||||
key={tag}
|
||||
label={tag}
|
||||
tag={tag}
|
||||
isDeleted
|
||||
/>
|
||||
))}
|
||||
</StyledHistoryBlockTagList>
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
export default HistoryRoomTagList;
|
@ -0,0 +1,44 @@
|
||||
// (c) Copyright Ascensio System SIA 2009-2024
|
||||
//
|
||||
// This program is a free software product.
|
||||
// You can redistribute it and/or modify it under the terms
|
||||
// of the GNU Affero General Public License (AGPL) version 3 as published by the Free Software
|
||||
// Foundation. In accordance with Section 7(a) of the GNU AGPL its Section 15 shall be amended
|
||||
// to the effect that Ascensio System SIA expressly excludes the warranty of non-infringement of
|
||||
// any third-party rights.
|
||||
//
|
||||
// This program is distributed WITHOUT ANY WARRANTY, without even the implied warranty
|
||||
// of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. For details, see
|
||||
// the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html
|
||||
//
|
||||
// You can contact Ascensio System SIA at Lubanas st. 125a-25, Riga, Latvia, EU, LV-1021.
|
||||
//
|
||||
// The interactive user interfaces in modified source and object code versions of the Program must
|
||||
// display Appropriate Legal Notices, as required under Section 5 of the GNU AGPL version 3.
|
||||
//
|
||||
// Pursuant to Section 7(b) of the License you must retain the original Product logo when
|
||||
// distributing the program. Pursuant to Section 7(e) we decline to grant you any rights under
|
||||
// trademark law for use of our trademarks.
|
||||
//
|
||||
// All the Product's GUI elements, including illustrations and icon sets, as well as technical writing
|
||||
// content are licensed under the terms of the Creative Commons Attribution-ShareAlike 4.0
|
||||
// International. See the License terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
|
||||
|
||||
import { StyledHistoryBlockMessage } from "../../../styles/history";
|
||||
|
||||
interface HistoryUserRoleChangeProps {
|
||||
feed: any;
|
||||
}
|
||||
|
||||
const HistoryUserGroupRoleChange = ({ feed }: HistoryUserRoleChangeProps) => {
|
||||
return (
|
||||
<StyledHistoryBlockMessage className="message">
|
||||
<span className="main-message">
|
||||
<strong>«{feed.data.access}»</strong>
|
||||
</span>{" "}
|
||||
<span className="old-role">«{feed.data.oldAccess}»</span>
|
||||
</StyledHistoryBlockMessage>
|
||||
);
|
||||
};
|
||||
|
||||
export default HistoryUserGroupRoleChange;
|
@ -0,0 +1,118 @@
|
||||
// (c) Copyright Ascensio System SIA 2009-2024
|
||||
//
|
||||
// This program is a free software product.
|
||||
// You can redistribute it and/or modify it under the terms
|
||||
// of the GNU Affero General Public License (AGPL) version 3 as published by the Free Software
|
||||
// Foundation. In accordance with Section 7(a) of the GNU AGPL its Section 15 shall be amended
|
||||
// to the effect that Ascensio System SIA expressly excludes the warranty of non-infringement of
|
||||
// any third-party rights.
|
||||
//
|
||||
// This program is distributed WITHOUT ANY WARRANTY, without even the implied warranty
|
||||
// of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. For details, see
|
||||
// the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html
|
||||
//
|
||||
// You can contact Ascensio System SIA at Lubanas st. 125a-25, Riga, Latvia, EU, LV-1021.
|
||||
//
|
||||
// The interactive user interfaces in modified source and object code versions of the Program must
|
||||
// display Appropriate Legal Notices, as required under Section 5 of the GNU AGPL version 3.
|
||||
//
|
||||
// Pursuant to Section 7(b) of the License you must retain the original Product logo when
|
||||
// distributing the program. Pursuant to Section 7(e) we decline to grant you any rights under
|
||||
// trademark law for use of our trademarks.
|
||||
//
|
||||
// All the Product's GUI elements, including illustrations and icon sets, as well as technical writing
|
||||
// content are licensed under the terms of the Creative Commons Attribution-ShareAlike 4.0
|
||||
// International. See the License terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
|
||||
|
||||
import { useState } from "react";
|
||||
import { useNavigate, NavigateFunction } from "react-router-dom";
|
||||
import { decode } from "he";
|
||||
import { inject, observer } from "mobx-react";
|
||||
import { Link } from "@docspace/shared/components/link";
|
||||
import { Text } from "@docspace/shared/components/text";
|
||||
import {
|
||||
StyledHistoryBlockExpandLink,
|
||||
StyledHistoryLink,
|
||||
} from "../../../styles/history";
|
||||
import { Trans, withTranslation } from "react-i18next";
|
||||
|
||||
const EXPANSION_THRESHOLD = 8;
|
||||
|
||||
interface HistoryUserListProps {
|
||||
t;
|
||||
feed: any;
|
||||
openUser?: (user: any, navigate: NavigateFunction) => void;
|
||||
isVisitor?: boolean;
|
||||
isCollaborator?: boolean;
|
||||
}
|
||||
|
||||
const HistoryUserList = ({
|
||||
t,
|
||||
feed,
|
||||
openUser,
|
||||
isVisitor,
|
||||
isCollaborator,
|
||||
}: HistoryUserListProps) => {
|
||||
const navigate = useNavigate();
|
||||
|
||||
const [isExpanded, setIsExpanded] = useState(
|
||||
feed.related.length + 1 <= EXPANSION_THRESHOLD,
|
||||
);
|
||||
const onExpand = () => setIsExpanded(true);
|
||||
|
||||
const usersData = [
|
||||
feed.data,
|
||||
...feed.related.map((relatedFeed: any) => relatedFeed.data),
|
||||
];
|
||||
|
||||
return (
|
||||
<>
|
||||
{usersData.map(({ user }, i) => {
|
||||
if (!isExpanded && i > EXPANSION_THRESHOLD - 1) return null;
|
||||
const withComma = !isExpanded
|
||||
? i < EXPANSION_THRESHOLD - 1
|
||||
: i < usersData.length - 1;
|
||||
return (
|
||||
<StyledHistoryLink key={user.id}>
|
||||
{isVisitor || isCollaborator ? (
|
||||
<Text as="span" className="text">
|
||||
{decode(user.displayName)}
|
||||
</Text>
|
||||
) : (
|
||||
<Link
|
||||
className="text link"
|
||||
onClick={() => openUser!(user, navigate)}
|
||||
>
|
||||
{decode(user.displayName)}
|
||||
</Link>
|
||||
)}
|
||||
|
||||
{withComma && ","}
|
||||
<div className="space" />
|
||||
</StyledHistoryLink>
|
||||
);
|
||||
})}
|
||||
|
||||
{!isExpanded && (
|
||||
<StyledHistoryBlockExpandLink
|
||||
className="user-list-expand-link"
|
||||
onClick={onExpand}
|
||||
>
|
||||
<Trans
|
||||
t={t}
|
||||
ns="InfoPanel"
|
||||
i18nKey="AndMoreLabel"
|
||||
values={{ count: usersData.length - EXPANSION_THRESHOLD }}
|
||||
components={{ 1: <strong /> }}
|
||||
/>
|
||||
</StyledHistoryBlockExpandLink>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default inject(({ infoPanelStore, userStore }) => ({
|
||||
openUser: infoPanelStore.openUser,
|
||||
isVisitor: userStore.user.isVisitor,
|
||||
isCollaborator: userStore.user.isCollaborator,
|
||||
}))(withTranslation(["InfoPanel"])(observer(HistoryUserList)));
|
@ -0,0 +1,98 @@
|
||||
// (c) Copyright Ascensio System SIA 2009-2024
|
||||
//
|
||||
// This program is a free software product.
|
||||
// You can redistribute it and/or modify it under the terms
|
||||
// of the GNU Affero General Public License (AGPL) version 3 as published by the Free Software
|
||||
// Foundation. In accordance with Section 7(a) of the GNU AGPL its Section 15 shall be amended
|
||||
// to the effect that Ascensio System SIA expressly excludes the warranty of non-infringement of
|
||||
// any third-party rights.
|
||||
//
|
||||
// This program is distributed WITHOUT ANY WARRANTY, without even the implied warranty
|
||||
// of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. For details, see
|
||||
// the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html
|
||||
//
|
||||
// You can contact Ascensio System SIA at Lubanas st. 125a-25, Riga, Latvia, EU, LV-1021.
|
||||
//
|
||||
// The interactive user interfaces in modified source and object code versions of the Program must
|
||||
// display Appropriate Legal Notices, as required under Section 5 of the GNU AGPL version 3.
|
||||
//
|
||||
// Pursuant to Section 7(b) of the License you must retain the original Product logo when
|
||||
// distributing the program. Pursuant to Section 7(e) we decline to grant you any rights under
|
||||
// trademark law for use of our trademarks.
|
||||
//
|
||||
// All the Product's GUI elements, including illustrations and icon sets, as well as technical writing
|
||||
// content are licensed under the terms of the Creative Commons Attribution-ShareAlike 4.0
|
||||
// International. See the License terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
|
||||
|
||||
import { inject, observer } from "mobx-react";
|
||||
|
||||
import HistoryUserList from "./UserList";
|
||||
import HistoryMainText from "./MainText";
|
||||
import HistoryItemList from "./ItemList";
|
||||
import HistoryMainTextFolderInfo from "./MainTextFolderInfo";
|
||||
import HistoryRoomExternalLink from "./RoomExternalLink";
|
||||
import HistoryGroupList from "./GroupList";
|
||||
import HistoryUserGroupRoleChange from "./UserGroupRoleChange";
|
||||
import HistoryRoomTagList from "./RoomTagList";
|
||||
import { getFeedInfo } from "../FeedInfo";
|
||||
|
||||
interface HistoryBlockContentProps {
|
||||
feed: any;
|
||||
}
|
||||
|
||||
const HistoryBlockContent = ({
|
||||
feed,
|
||||
historyWithFileList,
|
||||
}: HistoryBlockContentProps) => {
|
||||
const { actionType, targetType } = getFeedInfo(feed);
|
||||
|
||||
return (
|
||||
<>
|
||||
{targetType === "user" && actionType === "update" && (
|
||||
<HistoryUserList feed={feed} />
|
||||
)}
|
||||
|
||||
{targetType === "group" && actionType === "update" && (
|
||||
<HistoryGroupList feed={feed} />
|
||||
)}
|
||||
|
||||
<HistoryMainText feed={feed} />
|
||||
|
||||
{(targetType === "file" || targetType === "folder") &&
|
||||
actionType !== "delete" && <HistoryMainTextFolderInfo feed={feed} />}
|
||||
|
||||
{(targetType === "file" || targetType === "folder") &&
|
||||
(actionType === "rename" || historyWithFileList) && (
|
||||
<HistoryItemList
|
||||
feed={feed}
|
||||
actionType={actionType}
|
||||
targetType={targetType}
|
||||
/>
|
||||
)}
|
||||
|
||||
{targetType === "roomTag" && (
|
||||
<HistoryRoomTagList feed={feed} actionType={actionType} />
|
||||
)}
|
||||
|
||||
{targetType === "roomExternalLink" && actionType === "create" && (
|
||||
<HistoryRoomExternalLink feed={feed} actionType={actionType} />
|
||||
)}
|
||||
|
||||
{targetType === "user" && actionType !== "update" && (
|
||||
<HistoryUserList feed={feed} />
|
||||
)}
|
||||
|
||||
{targetType === "group" && actionType !== "update" && (
|
||||
<HistoryGroupList feed={feed} />
|
||||
)}
|
||||
|
||||
{(targetType === "user" || targetType === "group") &&
|
||||
actionType === "update" && <HistoryUserGroupRoleChange feed={feed} />}
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default inject(({ infoPanelStore }) => {
|
||||
const { historyWithFileList } = infoPanelStore;
|
||||
return { historyWithFileList };
|
||||
})(observer(HistoryBlockContent));
|
@ -1,130 +0,0 @@
|
||||
// (c) Copyright Ascensio System SIA 2009-2024
|
||||
//
|
||||
// This program is a free software product.
|
||||
// You can redistribute it and/or modify it under the terms
|
||||
// of the GNU Affero General Public License (AGPL) version 3 as published by the Free Software
|
||||
// Foundation. In accordance with Section 7(a) of the GNU AGPL its Section 15 shall be amended
|
||||
// to the effect that Ascensio System SIA expressly excludes the warranty of non-infringement of
|
||||
// any third-party rights.
|
||||
//
|
||||
// This program is distributed WITHOUT ANY WARRANTY, without even the implied warranty
|
||||
// of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. For details, see
|
||||
// the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html
|
||||
//
|
||||
// You can contact Ascensio System SIA at Lubanas st. 125a-25, Riga, Latvia, EU, LV-1021.
|
||||
//
|
||||
// The interactive user interfaces in modified source and object code versions of the Program must
|
||||
// display Appropriate Legal Notices, as required under Section 5 of the GNU AGPL version 3.
|
||||
//
|
||||
// Pursuant to Section 7(b) of the License you must retain the original Product logo when
|
||||
// distributing the program. Pursuant to Section 7(e) we decline to grant you any rights under
|
||||
// trademark law for use of our trademarks.
|
||||
//
|
||||
// All the Product's GUI elements, including illustrations and icon sets, as well as technical writing
|
||||
// content are licensed under the terms of the Creative Commons Attribution-ShareAlike 4.0
|
||||
// International. See the License terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
|
||||
|
||||
import FolderLocationReactSvgUrl from "PUBLIC_DIR/images/folder-location.react.svg?url";
|
||||
import React, { useState } from "react";
|
||||
import { Trans } from "react-i18next";
|
||||
|
||||
import { Text } from "@docspace/shared/components/text";
|
||||
import { IconButton } from "@docspace/shared/components/icon-button";
|
||||
import { ReactSVG } from "react-svg";
|
||||
import {
|
||||
StyledHistoryBlockFile,
|
||||
StyledHistoryBlockFilesList,
|
||||
} from "../../styles/history";
|
||||
import { RoomsType } from "@docspace/shared/enums";
|
||||
|
||||
export const HistoryBlockItemList = ({
|
||||
t,
|
||||
items,
|
||||
getInfoPanelItemIcon,
|
||||
checkAndOpenLocationAction,
|
||||
}) => {
|
||||
const [isShowMore, setIsShowMore] = useState(items.length <= 3);
|
||||
const onShowMore = () => 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,
|
||||
fileExst,
|
||||
id: item.ItemId.split("_")[0],
|
||||
viewUrl: item.itemId,
|
||||
};
|
||||
});
|
||||
|
||||
// If server returns two instances of the same item by mistake filters it out
|
||||
const includedIds = [];
|
||||
const filteredParsedItems = parsedItems.filter((item) => {
|
||||
if (includedIds.indexOf(item.id) > -1) return false;
|
||||
includedIds.push(item.id);
|
||||
return true;
|
||||
});
|
||||
|
||||
return (
|
||||
<StyledHistoryBlockFilesList>
|
||||
{filteredParsedItems.map((item, i) => {
|
||||
includedIds.push(item);
|
||||
if (!isShowMore && i > 2) return null;
|
||||
return (
|
||||
<StyledHistoryBlockFile isRoom={item.isRoom} key={item.id + "__" + i}>
|
||||
<ReactSVG className="icon" src={getInfoPanelItemIcon(item, 24)} />
|
||||
<div className="item-title">
|
||||
{item.title ? (
|
||||
[
|
||||
<span className="name" key="hbil-item-name">
|
||||
{item.title}
|
||||
</span>,
|
||||
item.fileExst && (
|
||||
<span className="exst" key="hbil-item-exst">
|
||||
{item.fileExst}
|
||||
</span>
|
||||
),
|
||||
]
|
||||
) : (
|
||||
<span className="name">{item.fileExst}</span>
|
||||
)}
|
||||
</div>
|
||||
<IconButton
|
||||
className="location-btn"
|
||||
iconName={FolderLocationReactSvgUrl}
|
||||
size="16"
|
||||
isFill={true}
|
||||
onClick={() => checkAndOpenLocationAction(item)}
|
||||
title={t("Files:OpenLocation")}
|
||||
/>
|
||||
</StyledHistoryBlockFile>
|
||||
);
|
||||
})}
|
||||
{!isShowMore && (
|
||||
<Text className="show_more-link" onClick={onShowMore}>
|
||||
<Trans
|
||||
t={t}
|
||||
ns="InfoPanel"
|
||||
i18nKey="AndMoreLabel"
|
||||
values={{ count: items.length - 3 }}
|
||||
components={{ bold: <strong /> }}
|
||||
/>
|
||||
</Text>
|
||||
)}
|
||||
</StyledHistoryBlockFilesList>
|
||||
);
|
||||
};
|
||||
|
||||
export default HistoryBlockItemList;
|
@ -1,164 +0,0 @@
|
||||
// (c) Copyright Ascensio System SIA 2009-2024
|
||||
//
|
||||
// This program is a free software product.
|
||||
// You can redistribute it and/or modify it under the terms
|
||||
// of the GNU Affero General Public License (AGPL) version 3 as published by the Free Software
|
||||
// Foundation. In accordance with Section 7(a) of the GNU AGPL its Section 15 shall be amended
|
||||
// to the effect that Ascensio System SIA expressly excludes the warranty of non-infringement of
|
||||
// any third-party rights.
|
||||
//
|
||||
// This program is distributed WITHOUT ANY WARRANTY, without even the implied warranty
|
||||
// of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. For details, see
|
||||
// the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html
|
||||
//
|
||||
// You can contact Ascensio System SIA at Lubanas st. 125a-25, Riga, Latvia, EU, LV-1021.
|
||||
//
|
||||
// The interactive user interfaces in modified source and object code versions of the Program must
|
||||
// display Appropriate Legal Notices, as required under Section 5 of the GNU AGPL version 3.
|
||||
//
|
||||
// Pursuant to Section 7(b) of the License you must retain the original Product logo when
|
||||
// distributing the program. Pursuant to Section 7(e) we decline to grant you any rights under
|
||||
// trademark law for use of our trademarks.
|
||||
//
|
||||
// All the Product's GUI elements, including illustrations and icon sets, as well as technical writing
|
||||
// content are licensed under the terms of the Creative Commons Attribution-ShareAlike 4.0
|
||||
// International. See the License terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
|
||||
|
||||
import React from "react";
|
||||
import { Trans } from "react-i18next";
|
||||
|
||||
const { FeedActionTypes, FeedItemTypes } = require("@docspace/shared/enums");
|
||||
|
||||
const getBlockMessageTranslation = (
|
||||
t,
|
||||
actionType,
|
||||
itemType,
|
||||
isSeveral,
|
||||
data,
|
||||
) => {
|
||||
const keys = [
|
||||
// FILE //
|
||||
{
|
||||
key: t("FeedCreateFileSingle", data),
|
||||
actionType: FeedActionTypes.Create,
|
||||
itemType: FeedItemTypes.File,
|
||||
isSeveral: false,
|
||||
},
|
||||
{
|
||||
key: t("FeedCreateFileSeveral", data),
|
||||
actionType: FeedActionTypes.Create,
|
||||
itemType: FeedItemTypes.File,
|
||||
isSeveral: true,
|
||||
},
|
||||
{
|
||||
key: t("FeedUpdateFile", data),
|
||||
actionType: FeedActionTypes.Update,
|
||||
itemType: FeedItemTypes.File,
|
||||
},
|
||||
{
|
||||
key: t("FeedRenameFile", data),
|
||||
actionType: FeedActionTypes.Rename,
|
||||
itemType: FeedItemTypes.File,
|
||||
},
|
||||
{
|
||||
key: t("FeedMoveFile", data),
|
||||
actionType: FeedActionTypes.Move,
|
||||
itemType: FeedItemTypes.File,
|
||||
},
|
||||
{
|
||||
key: t("FeedDeleteFile", data),
|
||||
actionType: FeedActionTypes.Delete,
|
||||
itemType: FeedItemTypes.File,
|
||||
},
|
||||
// FOLDER //
|
||||
{
|
||||
key: t("FeedCreateFolderSingle", data),
|
||||
actionType: FeedActionTypes.Create,
|
||||
itemType: FeedItemTypes.Folder,
|
||||
isSeveral: false,
|
||||
},
|
||||
{
|
||||
key: t("FeedCreateFolderSeveral", data),
|
||||
actionType: FeedActionTypes.Create,
|
||||
itemType: FeedItemTypes.Folder,
|
||||
isSeveral: true,
|
||||
},
|
||||
{
|
||||
key: t("FeedRenameFolder", data),
|
||||
actionType: FeedActionTypes.Rename,
|
||||
itemType: FeedItemTypes.Folder,
|
||||
},
|
||||
{
|
||||
key: t("FeedMoveFolder", data),
|
||||
actionType: FeedActionTypes.Move,
|
||||
itemType: FeedItemTypes.Folder,
|
||||
},
|
||||
{
|
||||
key: t("FeedDeleteFolder", data),
|
||||
actionType: FeedActionTypes.Delete,
|
||||
itemType: FeedItemTypes.Folder,
|
||||
},
|
||||
// ROOM //
|
||||
{
|
||||
key: t("FeedCreateRoom", data),
|
||||
actionType: FeedActionTypes.Create,
|
||||
itemType: FeedItemTypes.Room,
|
||||
},
|
||||
{
|
||||
key: t("FeedRenameRoom", data),
|
||||
actionType: FeedActionTypes.Rename,
|
||||
itemType: FeedItemTypes.Room,
|
||||
},
|
||||
{
|
||||
key: t("FeedUpdateRoom", data),
|
||||
actionType: FeedActionTypes.Update,
|
||||
itemType: FeedItemTypes.Room,
|
||||
},
|
||||
// TAG //
|
||||
{
|
||||
key: t("FeedCreateRoomTag", data),
|
||||
actionType: FeedActionTypes.Create,
|
||||
itemType: FeedItemTypes.Tag,
|
||||
},
|
||||
{
|
||||
key: t("FeedDeleteRoomTag", data),
|
||||
actionType: FeedActionTypes.Delete,
|
||||
itemType: FeedItemTypes.Tag,
|
||||
},
|
||||
// USER //
|
||||
{
|
||||
key: t("FeedCreateUser", data),
|
||||
actionType: FeedActionTypes.Create,
|
||||
itemType: FeedItemTypes.User,
|
||||
},
|
||||
{
|
||||
key: t("FeedUpdateUser", data),
|
||||
actionType: FeedActionTypes.Update,
|
||||
itemType: FeedItemTypes.User,
|
||||
},
|
||||
{
|
||||
key: t("FeedDeleteUser", data),
|
||||
actionType: FeedActionTypes.Delete,
|
||||
itemType: FeedItemTypes.User,
|
||||
},
|
||||
];
|
||||
|
||||
const [result] = keys.filter(
|
||||
(key) =>
|
||||
key.actionType === actionType &&
|
||||
key.itemType === itemType &&
|
||||
!!key.isSeveral === isSeveral,
|
||||
);
|
||||
|
||||
if (!result) return `${actionType} ${itemType}`;
|
||||
return (
|
||||
<Trans
|
||||
t={t}
|
||||
ns="InfoPanel"
|
||||
i18nKey={result.key}
|
||||
components={{ bold: <strong /> }}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
export default getBlockMessageTranslation;
|
@ -31,7 +31,7 @@ import { withTranslation } from "react-i18next";
|
||||
import { StyledHistoryList, StyledHistorySubtitle } from "../../styles/history";
|
||||
|
||||
import InfoPanelViewLoader from "@docspace/shared/skeletons/info-panel/body";
|
||||
import { parseHistory } from "./../../helpers/HistoryHelper";
|
||||
import { getRelativeDateDay } from "./../../helpers/HistoryHelper";
|
||||
import HistoryBlock from "./HistoryBlock";
|
||||
import NoHistory from "../NoItem/NoHistory";
|
||||
|
||||
@ -40,10 +40,9 @@ const History = ({
|
||||
historyWithFileList,
|
||||
selectedFolder,
|
||||
selectionHistory,
|
||||
setSelectionHistory,
|
||||
infoPanelSelection,
|
||||
getInfoPanelItemIcon,
|
||||
getHistory,
|
||||
fetchHistory,
|
||||
checkAndOpenLocationAction,
|
||||
openUser,
|
||||
isVisitor,
|
||||
@ -52,46 +51,30 @@ const History = ({
|
||||
const isMount = useRef(true);
|
||||
const abortControllerRef = useRef(new AbortController());
|
||||
|
||||
const [isPending, startTransition] = useTransition();
|
||||
const [isLoading, setIsLoading] = useState(false);
|
||||
const [isShowLoader, setIsShowLoader] = useState(false);
|
||||
|
||||
const fetchHistory = async (item) => {
|
||||
const getHistory = async (item) => {
|
||||
if (!item?.id) return;
|
||||
if (isLoading) {
|
||||
abortControllerRef.current?.abort();
|
||||
abortControllerRef.current = new AbortController();
|
||||
} else setIsLoading(true);
|
||||
|
||||
let module = "files";
|
||||
if (infoPanelSelection.isRoom) module = "rooms";
|
||||
else if (infoPanelSelection.isFolder) module = "folders";
|
||||
|
||||
getHistory(
|
||||
module,
|
||||
item.id,
|
||||
abortControllerRef.current?.signal,
|
||||
item?.requestToken,
|
||||
)
|
||||
.then((data) => {
|
||||
if (isMount.current)
|
||||
startTransition(() => {
|
||||
const parsedHistory = parseHistory(t, data);
|
||||
setSelectionHistory(parsedHistory);
|
||||
});
|
||||
})
|
||||
.catch((err) => {
|
||||
if (err.message !== "canceled") console.error(err);
|
||||
})
|
||||
.finally(() => {
|
||||
if (isMount.current) {
|
||||
fetchHistory(abortControllerRef.current?.signal).finally(() => {
|
||||
if (isMount.current) setIsLoading(false);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
if (!isMount.current) return;
|
||||
fetchHistory(infoPanelSelection);
|
||||
}, [infoPanelSelection.id]);
|
||||
getHistory(infoPanelSelection);
|
||||
}, [
|
||||
infoPanelSelection.id,
|
||||
infoPanelSelection.isFolder || infoPanelSelection.isRoom,
|
||||
]);
|
||||
|
||||
useEffect(() => {
|
||||
const showLoaderTimer = setTimeout(() => setIsShowLoader(true), 500);
|
||||
@ -111,10 +94,12 @@ const History = ({
|
||||
return (
|
||||
<StyledHistoryList>
|
||||
{selectionHistory.map(({ day, feeds }) => [
|
||||
<StyledHistorySubtitle key={day}>{day}</StyledHistorySubtitle>,
|
||||
<StyledHistorySubtitle key={day}>
|
||||
{getRelativeDateDay(t, feeds[0].date)}
|
||||
</StyledHistorySubtitle>,
|
||||
...feeds.map((feed, i) => (
|
||||
<HistoryBlock
|
||||
key={feed.json.Id}
|
||||
key={`${feed.action.id}_${feed.date}`}
|
||||
t={t}
|
||||
feed={feed}
|
||||
selectedFolder={selectedFolder}
|
||||
@ -134,24 +119,17 @@ const History = ({
|
||||
};
|
||||
|
||||
export default inject(
|
||||
({
|
||||
settingsStore,
|
||||
filesStore,
|
||||
filesActionsStore,
|
||||
infoPanelStore,
|
||||
userStore,
|
||||
}) => {
|
||||
({ settingsStore, filesActionsStore, infoPanelStore, userStore }) => {
|
||||
const {
|
||||
infoPanelSelection,
|
||||
fetchHistory,
|
||||
selectionHistory,
|
||||
setSelectionHistory,
|
||||
historyWithFileList,
|
||||
getInfoPanelItemIcon,
|
||||
openUser,
|
||||
} = infoPanelStore;
|
||||
const { culture } = settingsStore;
|
||||
|
||||
const { getHistory } = filesStore;
|
||||
const { checkAndOpenLocationAction } = filesActionsStore;
|
||||
|
||||
const { user } = userStore;
|
||||
@ -161,11 +139,10 @@ export default inject(
|
||||
return {
|
||||
culture,
|
||||
selectionHistory,
|
||||
setSelectionHistory,
|
||||
historyWithFileList,
|
||||
infoPanelSelection,
|
||||
getInfoPanelItemIcon,
|
||||
getHistory,
|
||||
fetchHistory,
|
||||
checkAndOpenLocationAction,
|
||||
openUser,
|
||||
isVisitor,
|
||||
|
@ -0,0 +1,109 @@
|
||||
import { TTranslation } from "@docspace/shared/types";
|
||||
import { Trans } from "react-i18next";
|
||||
import { AnyFeedInfo } from "./FeedInfo";
|
||||
|
||||
export const useFeedTranslation = (
|
||||
t: TTranslation,
|
||||
feed: { action: { key: AnyFeedInfo["key"] }; data: any },
|
||||
) => {
|
||||
switch (feed.action.key) {
|
||||
case "FileCreated":
|
||||
return t("InfoPanel:FileCreated");
|
||||
case "FileUploaded":
|
||||
return t("InfoPanel:FileUploaded");
|
||||
case "UserFileUpdated":
|
||||
return t("InfoPanel:UserFileUpdated");
|
||||
case "FileConverted":
|
||||
return t("InfoPanel:FileConverted");
|
||||
case "FileRenamed":
|
||||
return t("InfoPanel:FileRenamed");
|
||||
case "FileMoved":
|
||||
return t("InfoPanel:FileMoved");
|
||||
case "FileCopied":
|
||||
return t("InfoPanel:FileCopied");
|
||||
case "FileDeleted":
|
||||
return t("InfoPanel:FileDeleted");
|
||||
case "FolderCreated":
|
||||
return t("InfoPanel:FolderCreated");
|
||||
case "FolderRenamed":
|
||||
return t("InfoPanel:FolderRenamed");
|
||||
case "FolderMoved":
|
||||
return t("InfoPanel:FolderMoved");
|
||||
case "FolderCopied":
|
||||
return t("InfoPanel:FolderCopied");
|
||||
case "FolderDeleted":
|
||||
return t("InfoPanel:FolderDeleted");
|
||||
case "RoomCreated":
|
||||
return (
|
||||
<Trans
|
||||
t={t}
|
||||
ns="InfoPanel"
|
||||
i18nKey="RoomCreated"
|
||||
values={{ roomTitle: feed.data.title }}
|
||||
components={{ 1: <strong /> }}
|
||||
/>
|
||||
);
|
||||
case "RoomRenamed":
|
||||
return (
|
||||
<Trans
|
||||
t={t}
|
||||
ns="InfoPanel"
|
||||
i18nKey="RoomRenamed"
|
||||
values={{
|
||||
roomTitle: feed.data.newTitle,
|
||||
oldRoomTitle: feed.data.oldTitle,
|
||||
}}
|
||||
components={{ 1: <strong /> }}
|
||||
/>
|
||||
);
|
||||
case "AddedRoomTags":
|
||||
return t("InfoPanel:AddedRoomTags");
|
||||
case "DeletedRoomTags":
|
||||
return t("InfoPanel:DeletedRoomTags");
|
||||
case "RoomLogoCreated":
|
||||
return t("InfoPanel:RoomLogoCreated");
|
||||
case "RoomLogoDeleted":
|
||||
return t("InfoPanel:RoomLogoDeleted");
|
||||
case "RoomExternalLinkCreated":
|
||||
return t("InfoPanel:RoomExternalLinkCreated");
|
||||
case "RoomExternalLinkRenamed":
|
||||
return (
|
||||
<Trans
|
||||
t={t}
|
||||
ns="InfoPanel"
|
||||
i18nKey="RoomExternalLinkRenamed"
|
||||
values={{
|
||||
linkTitle: feed.data.title,
|
||||
oldLinkTitle: feed.data.oldTitle,
|
||||
}}
|
||||
components={{ 1: <strong /> }}
|
||||
/>
|
||||
);
|
||||
case "RoomExternalLinkDeleted":
|
||||
return (
|
||||
<Trans
|
||||
t={t}
|
||||
ns="InfoPanel"
|
||||
i18nKey="RoomExternalLinkDeleted"
|
||||
values={{
|
||||
linkTitle: feed.data.title,
|
||||
}}
|
||||
components={{ 1: <strong /> }}
|
||||
/>
|
||||
);
|
||||
case "RoomCreateUser":
|
||||
return t("InfoPanel:RoomCreateUser");
|
||||
case "RoomUpdateAccessForUser":
|
||||
return t("InfoPanel:RoomUpdateAccessForUser");
|
||||
case "RoomRemoveUser":
|
||||
return t("InfoPanel:RoomRemoveUser");
|
||||
case "RoomGroupAdded":
|
||||
return t("InfoPanel:RoomGroupAdded");
|
||||
case "RoomUpdateAccessForGroup":
|
||||
return t("InfoPanel:RoomUpdateAccessForGroup");
|
||||
case "RoomGroupRemove":
|
||||
return t("InfoPanel:RoomGroupRemove");
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
};
|
@ -509,6 +509,7 @@ const InsideGroupTableRow = (props) => {
|
||||
className="table-cell_username"
|
||||
noHover
|
||||
dir="auto"
|
||||
truncate={true}
|
||||
>
|
||||
{statusType === "pending"
|
||||
? email
|
||||
|
@ -512,6 +512,7 @@ const PeopleTableRow = (props) => {
|
||||
className="table-cell_username"
|
||||
noHover
|
||||
dir="auto"
|
||||
truncate={true}
|
||||
>
|
||||
{statusType === "pending"
|
||||
? email
|
||||
|
@ -880,7 +880,7 @@ const SectionHeaderContent = (props) => {
|
||||
: isRootFolder || isAccountsPage || isSettingsPage;
|
||||
|
||||
const getInsideGroupTitle = () => {
|
||||
return isLoading || !currentGroup?.name
|
||||
return isLoading && insideGroupTempTitle
|
||||
? insideGroupTempTitle
|
||||
: currentGroup?.name;
|
||||
};
|
||||
|
@ -27,6 +27,7 @@ import { useState, useEffect } from "react";
|
||||
import { withTranslation } from "react-i18next";
|
||||
import { inject, observer } from "mobx-react";
|
||||
import { useNavigate, useLocation } from "react-router-dom";
|
||||
import { isMobile } from "react-device-detect";
|
||||
|
||||
import { Text } from "@docspace/shared/components/text";
|
||||
import { HelpButton } from "@docspace/shared/components/help-button";
|
||||
@ -309,7 +310,7 @@ const WhiteLabel = (props) => {
|
||||
isDisabled={!isSettingPaid}
|
||||
isReadOnly={!isSettingPaid}
|
||||
scale={true}
|
||||
isAutoFocussed={true}
|
||||
isAutoFocussed={!isMobile}
|
||||
tabIndex={1}
|
||||
maxLength={30}
|
||||
/>
|
||||
|
@ -172,12 +172,7 @@ class CommonStore {
|
||||
};
|
||||
|
||||
applyNewLogos = (logos) => {
|
||||
const theme =
|
||||
typeof window !== "undefined" &&
|
||||
window.matchMedia &&
|
||||
window.matchMedia("(prefers-color-scheme: dark)").matches
|
||||
? "dark"
|
||||
: "light";
|
||||
const theme = this.settingsStore.theme.isBase ? "light" : "dark";
|
||||
|
||||
const favicon = document.getElementById("favicon");
|
||||
const logo = document.getElementsByClassName("logo-icon_svg")?.[0];
|
||||
|
@ -1443,17 +1443,19 @@ class FilesActionStore {
|
||||
setIsSectionFilterLoading(param);
|
||||
};
|
||||
|
||||
const { ExtraLocationTitle, ExtraLocation, fileExst, folderId } = item;
|
||||
const { title, fileExst } = item;
|
||||
const parentId = item.parentId || item.toFolderId || recycleBinFolderId;
|
||||
const parentTitle = item.parentTitle || item.toFolderTitle;
|
||||
|
||||
const isRoot =
|
||||
ExtraLocation === myRoomsId ||
|
||||
ExtraLocation === myFolderId ||
|
||||
ExtraLocation === archiveRoomsId ||
|
||||
ExtraLocation === recycleBinFolderId;
|
||||
const isRoot = [
|
||||
myRoomsId,
|
||||
myFolderId,
|
||||
archiveRoomsId,
|
||||
recycleBinFolderId,
|
||||
].includes(parentId);
|
||||
|
||||
const state = {
|
||||
title: ExtraLocationTitle,
|
||||
|
||||
title: parentTitle,
|
||||
isRoot,
|
||||
fileExst,
|
||||
highlightFileId: item.id,
|
||||
@ -1461,14 +1463,12 @@ class FilesActionStore {
|
||||
rootFolderType,
|
||||
};
|
||||
|
||||
const url = getCategoryUrl(categoryType, ExtraLocation);
|
||||
const url = getCategoryUrl(categoryType, parentId);
|
||||
|
||||
const newFilter = FilesFilter.getDefault();
|
||||
|
||||
const title = this.nameWithoutExtension(item.title);
|
||||
|
||||
newFilter.search = title;
|
||||
newFilter.folder = ExtraLocation || folderId;
|
||||
newFilter.folder = parentId;
|
||||
|
||||
setIsLoading(
|
||||
window.DocSpace.location.search !== `?${newFilter.toUrlParams()}` ||
|
||||
|
@ -67,6 +67,7 @@ import { CategoryType } from "SRC_DIR/helpers/constants";
|
||||
import debounce from "lodash.debounce";
|
||||
import clone from "lodash/clone";
|
||||
import Queue from "queue-promise";
|
||||
import { parseHistory } from "SRC_DIR/pages/Home/InfoPanel/Body/helpers/HistoryHelper";
|
||||
|
||||
const { FilesFilter, RoomsFilter } = api;
|
||||
const storageViewAs = localStorage.getItem("viewAs");
|
||||
@ -274,6 +275,19 @@ class FilesStore {
|
||||
this.treeFoldersStore.updateTreeFoldersItem(opt);
|
||||
});
|
||||
|
||||
socketHelper.on("s:update-history", ({ id, type }) => {
|
||||
const { infoPanelSelection, fetchHistory } = this.infoPanelStore;
|
||||
|
||||
let infoPanelSelectionType = "file";
|
||||
if (infoPanelSelection?.isRoom || infoPanelSelection?.isFolder)
|
||||
infoPanelSelectionType = "folder";
|
||||
|
||||
if (id === infoPanelSelection?.id && type === infoPanelSelectionType) {
|
||||
console.log("[WS] s:update-history", id);
|
||||
fetchHistory();
|
||||
}
|
||||
});
|
||||
|
||||
socketHelper.on("refresh-folder", (id) => {
|
||||
const { socketSubscribers } = socketHelper;
|
||||
const pathParts = `DIR-${id}`;
|
||||
@ -1397,6 +1411,13 @@ class FilesStore {
|
||||
return res;
|
||||
};
|
||||
|
||||
abortAllFetch = () => {
|
||||
this.filesController.abort();
|
||||
this.roomsController.abort();
|
||||
this.filesController = new AbortController();
|
||||
this.roomsController = new AbortController();
|
||||
};
|
||||
|
||||
fetchFiles = (
|
||||
folderId,
|
||||
filter,
|
||||
@ -1405,9 +1426,9 @@ class FilesStore {
|
||||
clearSelection = true,
|
||||
) => {
|
||||
const { setSelectedNode } = this.treeFoldersStore;
|
||||
|
||||
if (this.clientLoadingStore.isLoading) {
|
||||
this.roomsController.abort();
|
||||
this.roomsController = new AbortController();
|
||||
this.abortAllFetch();
|
||||
}
|
||||
|
||||
const filterData = filter ? filter.clone() : FilesFilter.getDefault();
|
||||
@ -1728,8 +1749,7 @@ class FilesStore {
|
||||
const { setSelectedNode, roomsFolderId } = this.treeFoldersStore;
|
||||
|
||||
if (this.clientLoadingStore.isLoading) {
|
||||
this.filesController.abort();
|
||||
this.filesController = new AbortController();
|
||||
this.abortAllFetch();
|
||||
}
|
||||
|
||||
const filterData = !!filter
|
||||
@ -2723,8 +2743,8 @@ class FilesStore {
|
||||
return api.rooms.updateRoomMemberRole(id, data);
|
||||
}
|
||||
|
||||
getHistory(module, id, signal = null, requestToken) {
|
||||
return api.rooms.getHistory(module, id, signal, requestToken);
|
||||
getHistory(selectionType, id, signal = null, requestToken) {
|
||||
return api.rooms.getHistory(selectionType, id, signal, requestToken);
|
||||
}
|
||||
|
||||
getRoomHistory(id) {
|
||||
|
@ -546,11 +546,17 @@ class GroupsStore {
|
||||
withBackURL: boolean,
|
||||
tempTitle: string,
|
||||
) => {
|
||||
const { setIsSectionBodyLoading, setIsSectionFilterLoading } =
|
||||
this.clientLoadingStore;
|
||||
|
||||
this.setSelection([]);
|
||||
this.setBufferSelection(null);
|
||||
this.setCurrentGroup(null);
|
||||
this.setInsideGroupTempTitle(tempTitle);
|
||||
|
||||
setIsSectionFilterLoading(true);
|
||||
setIsSectionBodyLoading(true);
|
||||
|
||||
if (withBackURL) {
|
||||
const url = `${window.location.pathname}${window.location.search}`;
|
||||
this.setInsideGroupBackUrl(url);
|
||||
@ -592,6 +598,7 @@ class GroupsStore {
|
||||
this.insideGroupFilter.clone(),
|
||||
);
|
||||
this.peopleStore.usersStore.setUsers(members.items);
|
||||
this.setInsideGroupTempTitle(res.name);
|
||||
}
|
||||
|
||||
if (infoPanelSelection?.id === res.id) {
|
||||
|
@ -50,6 +50,10 @@ import {
|
||||
} from "@docspace/shared/api/files";
|
||||
import isEqual from "lodash/isEqual";
|
||||
import { getUserStatus } from "SRC_DIR/helpers/people-helpers";
|
||||
import {
|
||||
addLinksToHistory,
|
||||
parseHistory,
|
||||
} from "SRC_DIR/pages/Home/InfoPanel/Body/helpers/HistoryHelper";
|
||||
|
||||
const observedKeys = [
|
||||
"id",
|
||||
@ -715,6 +719,45 @@ class InfoPanelStore {
|
||||
this.setIsMembersPanelUpdating(false);
|
||||
};
|
||||
|
||||
fetchHistory = async (abortControllerSignal = null) => {
|
||||
const { getHistory, getRoomLinks } = this.filesStore;
|
||||
const { setExternalLinks } = this.publicRoomStore;
|
||||
|
||||
let selectionType = "file";
|
||||
if (this.infoPanelSelection.isRoom || this.infoPanelSelection.isFolder)
|
||||
selectionType = "folder";
|
||||
|
||||
const withLinks =
|
||||
this.infoPanelSelection.isRoom &&
|
||||
[RoomsType.FormRoom, RoomsType.CustomRoom, RoomsType.PublicRoom].includes(
|
||||
this.infoPanelSelection.roomType,
|
||||
);
|
||||
|
||||
return getHistory(
|
||||
selectionType,
|
||||
this.infoPanelSelection.id,
|
||||
abortControllerSignal,
|
||||
this.infoPanelSelection?.requestToken,
|
||||
)
|
||||
.then(async (data) => {
|
||||
if (withLinks) {
|
||||
const links = await getRoomLinks(this.infoPanelSelection.id);
|
||||
const historyWithLinks = addLinksToHistory(data, links);
|
||||
setExternalLinks(links);
|
||||
return historyWithLinks;
|
||||
}
|
||||
return data;
|
||||
})
|
||||
.then((data) => {
|
||||
const parsedSelectionHistory = parseHistory(data);
|
||||
this.setSelectionHistory(parsedSelectionHistory);
|
||||
return parsedSelectionHistory;
|
||||
})
|
||||
.catch((err) => {
|
||||
if (err.message !== "canceled") console.error(err);
|
||||
});
|
||||
};
|
||||
|
||||
openShareTab = () => {
|
||||
this.setView("info_share");
|
||||
this.isVisible = true;
|
||||
|
@ -46,8 +46,15 @@ class SelectionStore {
|
||||
}
|
||||
|
||||
updateSelection = (peopleList) => {
|
||||
const hasSelection = !!this.selection.length;
|
||||
const hasBufferSelection = !!this.bufferSelection;
|
||||
|
||||
peopleList.some((el) => {
|
||||
if (el.id === this.selection[0].id) this.setSelection([el]);
|
||||
if (hasSelection && this.selection[0].id === el.id)
|
||||
this.setSelection([el]);
|
||||
|
||||
if (hasBufferSelection && this.bufferSelection.id === el.id)
|
||||
this.setBufferSelection(el);
|
||||
});
|
||||
};
|
||||
|
||||
@ -303,6 +310,10 @@ class SelectionStore {
|
||||
return this.selection.length > 0 && this.selection.length === 1;
|
||||
}
|
||||
|
||||
get isOnlyBufferSelection() {
|
||||
return !this.selection.length && !!this.bufferSelection;
|
||||
}
|
||||
|
||||
get hasFreeUsers() {
|
||||
const users = this.selection.filter(
|
||||
(x) => x.status !== EmployeeStatus.Disabled && x.isVisitor,
|
||||
|
@ -47,6 +47,8 @@ class UsersStore {
|
||||
providers = [];
|
||||
accountsIsIsLoading = false;
|
||||
operationRunning = false;
|
||||
abortController = new AbortController();
|
||||
requestRunning = false;
|
||||
|
||||
constructor(peopleStore, settingsStore, infoPanelStore, userStore) {
|
||||
this.peopleStore = peopleStore;
|
||||
@ -63,6 +65,12 @@ class UsersStore {
|
||||
) => {
|
||||
const filterData = filter ? filter.clone() : Filter.getDefault();
|
||||
|
||||
if (this.requestRunning) {
|
||||
this.abortController.abort();
|
||||
|
||||
this.abortController = new AbortController();
|
||||
}
|
||||
|
||||
const filterStorageItem = localStorage.getItem(
|
||||
`PeopleFilter=${this.userStore.user?.id}`,
|
||||
);
|
||||
@ -88,9 +96,16 @@ class UsersStore {
|
||||
if (filterData.group && filterData.group === "root")
|
||||
filterData.group = undefined;
|
||||
|
||||
const res = await api.people.getUserList(filterData);
|
||||
this.requestRunning = true;
|
||||
|
||||
const res = await api.people.getUserList(
|
||||
filterData,
|
||||
this.abortController.signal,
|
||||
);
|
||||
filterData.total = res.total;
|
||||
|
||||
this.requestRunning = false;
|
||||
|
||||
if (updateFilter) {
|
||||
this.peopleStore.filterStore.setFilterParams(filterData);
|
||||
}
|
||||
@ -141,9 +156,10 @@ class UsersStore {
|
||||
|
||||
get needResetUserSelection() {
|
||||
const { isVisible: infoPanelVisible } = this.infoPanelStore;
|
||||
const { isOneUserSelection } = this.peopleStore.selectionStore;
|
||||
const { isOneUserSelection, isOnlyBufferSelection } =
|
||||
this.peopleStore.selectionStore;
|
||||
|
||||
return !infoPanelVisible || !isOneUserSelection;
|
||||
return !infoPanelVisible || (!isOneUserSelection && !isOnlyBufferSelection);
|
||||
}
|
||||
updateUserStatus = async (status, userIds) => {
|
||||
return api.people.updateUserStatus(status, userIds).then((users) => {
|
||||
|
@ -40,7 +40,10 @@ import { TReqOption } from "../../utils/axiosClient";
|
||||
import { EmployeeActivationStatus, ThemeKeys } from "../../enums";
|
||||
import { TGroup } from "../groups/types";
|
||||
|
||||
export async function getUserList(filter = Filter.getDefault()) {
|
||||
export async function getUserList(
|
||||
filter = Filter.getDefault(),
|
||||
signal?: AbortSignal,
|
||||
) {
|
||||
let params = "";
|
||||
// if (fake) {
|
||||
// return fakePeople.getUserList(filter);
|
||||
@ -57,6 +60,7 @@ export async function getUserList(filter = Filter.getDefault()) {
|
||||
const res = (await request({
|
||||
method: "get",
|
||||
url: `/people${params}`,
|
||||
signal,
|
||||
})) as TGetUserList;
|
||||
|
||||
res.items = res.items.map((user) => {
|
||||
|
@ -113,20 +113,21 @@ export function updateRoomMemberRole(id, data) {
|
||||
});
|
||||
}
|
||||
|
||||
export function getHistory(module, id, signal = null, requestToken) {
|
||||
export function getHistory(
|
||||
selectionType: "file" | "folder",
|
||||
id,
|
||||
signal = null,
|
||||
requestToken,
|
||||
) {
|
||||
const options = {
|
||||
method: "get",
|
||||
url: `/feed/filter?module=${module}&withRelated=true&id=${id}`,
|
||||
url: `/files/${selectionType}/${id}/log`,
|
||||
signal,
|
||||
};
|
||||
|
||||
if (requestToken) {
|
||||
options.headers = { "Request-Token": requestToken };
|
||||
}
|
||||
if (requestToken) options.headers = { "Request-Token": requestToken };
|
||||
|
||||
return request(options).then((res) => {
|
||||
return res;
|
||||
});
|
||||
return request(options).then((res) => res);
|
||||
}
|
||||
|
||||
export function getRoomHistory(id) {
|
||||
|
@ -34,6 +34,7 @@ const StyledTag = styled.div<{
|
||||
tagMaxWidth?: string;
|
||||
isLast?: boolean;
|
||||
isDisabled?: boolean;
|
||||
isDeleted?: boolean;
|
||||
isNewTag?: boolean;
|
||||
isDefault?: boolean;
|
||||
isClickable?: boolean;
|
||||
@ -76,6 +77,16 @@ const StyledTag = styled.div<{
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
${({ isDeleted, theme }) =>
|
||||
isDeleted &&
|
||||
css`
|
||||
background: ${theme.tag.deletedBackground};
|
||||
.tag-text {
|
||||
text-decoration: line-through;
|
||||
color: ${theme.tag.deletedColor};
|
||||
}
|
||||
`}
|
||||
|
||||
.tag-icon {
|
||||
${(props) =>
|
||||
props.theme.interfaceDirection === "rtl"
|
||||
@ -98,10 +109,13 @@ const StyledTag = styled.div<{
|
||||
${(props) =>
|
||||
props.isClickable &&
|
||||
!props.isDisabled &&
|
||||
!props.isDeleted &&
|
||||
css`
|
||||
cursor: pointer;
|
||||
&:hover {
|
||||
background: ${props.theme.tag.hoverBackground};
|
||||
background: ${!props.isNewTag
|
||||
? props.theme.tag.hoverBackground
|
||||
: props.theme.tag.newTagHoverBackground};
|
||||
}
|
||||
`}
|
||||
`;
|
||||
|
@ -42,6 +42,7 @@ export const TagPure = ({
|
||||
label,
|
||||
isNewTag,
|
||||
isDisabled,
|
||||
isDeleted,
|
||||
isDefault,
|
||||
isLast,
|
||||
onDelete,
|
||||
@ -99,12 +100,12 @@ export const TagPure = ({
|
||||
|
||||
const onClickAction = React.useCallback(
|
||||
(e: React.MouseEvent | React.ChangeEvent) => {
|
||||
if (onClick && !isDisabled) {
|
||||
if (onClick && !isDisabled && !isDeleted) {
|
||||
const target = e.target as HTMLDivElement;
|
||||
onClick({ roomType, label: target.dataset.tag, providerType });
|
||||
}
|
||||
},
|
||||
[onClick, isDisabled, roomType, providerType],
|
||||
[onClick, isDisabled, isDeleted, roomType, providerType],
|
||||
);
|
||||
|
||||
const onDeleteAction = React.useCallback(
|
||||
@ -125,6 +126,7 @@ export const TagPure = ({
|
||||
ref={tagRef}
|
||||
onClick={openDropdownAction}
|
||||
isDisabled={isDisabled}
|
||||
isDeleted={isDeleted}
|
||||
isDefault={isDefault}
|
||||
isLast={isLast}
|
||||
tagMaxWidth={tagMaxWidth}
|
||||
@ -167,6 +169,7 @@ export const TagPure = ({
|
||||
onClick={onClickAction}
|
||||
isNewTag={isNewTag}
|
||||
isDisabled={isDisabled}
|
||||
isDeleted={isDeleted}
|
||||
isDefault={isDefault}
|
||||
tagMaxWidth={tagMaxWidth}
|
||||
data-tag={label}
|
||||
@ -190,7 +193,7 @@ export const TagPure = ({
|
||||
>
|
||||
{label}
|
||||
</Text>
|
||||
{isNewTag && (
|
||||
{isNewTag && !!onDelete && (
|
||||
<IconButton
|
||||
className="tag-icon"
|
||||
iconName={CrossIconReactSvgUrl}
|
||||
|
@ -39,8 +39,10 @@ export interface TagProps {
|
||||
isNewTag?: boolean;
|
||||
/** Accepts the tag styles as disabled and disables clicking */
|
||||
isDisabled?: boolean;
|
||||
/** Accepts the tag styles as deleted and disables clicking */
|
||||
isDeleted?: boolean;
|
||||
/** Accepts the function that is called when the tag is clicked */
|
||||
onClick: (tag?: object) => void;
|
||||
onClick?: (tag?: object) => void;
|
||||
/** Accepts the function that ist called when the tag delete button is clicked */
|
||||
onDelete?: (tag?: string) => void;
|
||||
/** Accepts the max width of the tag */
|
||||
|
@ -1872,12 +1872,14 @@ export const getBaseTheme = () => {
|
||||
},
|
||||
|
||||
history: {
|
||||
subtitleColor: gray,
|
||||
fileBlockBg: grayLight,
|
||||
dateColor: gray,
|
||||
fileExstColor: gray,
|
||||
locationIconColor: gray,
|
||||
folderLabelColor: gray,
|
||||
subtitleColor: "#a3a9ae",
|
||||
fileBlockBg: "#f8f9f9",
|
||||
dateColor: "#A3A9AE",
|
||||
fileExstColor: "#A3A9AE",
|
||||
locationIconColor: "#A3A9AE",
|
||||
folderLabelColor: "#A3A9AE",
|
||||
renamedItemColor: "#A3A9AE",
|
||||
oldRoleColor: "#657077",
|
||||
},
|
||||
|
||||
details: {
|
||||
@ -2248,11 +2250,6 @@ export const getBaseTheme = () => {
|
||||
descriptionColor: grayText,
|
||||
},
|
||||
|
||||
tagInput: {
|
||||
tagBackground: grayLightMid,
|
||||
tagHoverBackground: lightGrayHover,
|
||||
},
|
||||
|
||||
dropdown: {
|
||||
background: white,
|
||||
borderColor: grayStrong,
|
||||
@ -3009,11 +3006,14 @@ export const getBaseTheme = () => {
|
||||
|
||||
tag: {
|
||||
color: black,
|
||||
background: lightGrayHover,
|
||||
hoverBackground: grayLightMid,
|
||||
disabledBackground: grayLight,
|
||||
deletedColor: "#A3A9AE",
|
||||
background: "#f3f4f4",
|
||||
hoverBackground: "#eceef1",
|
||||
disabledBackground: "#f8f9f9",
|
||||
deletedBackground: "#F8F9F9",
|
||||
defaultTagColor: black,
|
||||
newTagBackground: grayLightMid,
|
||||
newTagBackground: "#eceef1",
|
||||
newTagHoverBackground: "#F3F4F4",
|
||||
},
|
||||
|
||||
profile: {
|
||||
|
@ -1856,12 +1856,14 @@ const Dark: TTheme = {
|
||||
},
|
||||
|
||||
history: {
|
||||
subtitleColor: gray,
|
||||
fileBlockBg: black,
|
||||
dateColor: gray,
|
||||
fileExstColor: gray,
|
||||
locationIconColor: gray,
|
||||
folderLabelColor: gray,
|
||||
subtitleColor: "#A3A9AE",
|
||||
fileBlockBg: "#292929",
|
||||
dateColor: "#A3A9AE",
|
||||
fileExstColor: "#A3A9AE",
|
||||
locationIconColor: "#A3A9AE",
|
||||
folderLabelColor: "#A3A9AE",
|
||||
renamedItemColor: "#A3A9AE",
|
||||
oldRoleColor: "#A3A9AE",
|
||||
},
|
||||
|
||||
details: {
|
||||
@ -2231,11 +2233,6 @@ const Dark: TTheme = {
|
||||
descriptionColor: gray,
|
||||
},
|
||||
|
||||
tagInput: {
|
||||
tagBackground: grayDarkMid,
|
||||
tagHoverBackground: lightDarkGrayHover,
|
||||
},
|
||||
|
||||
dropdown: {
|
||||
background: black,
|
||||
borderColor: grayDarkStrong,
|
||||
@ -2990,11 +2987,14 @@ const Dark: TTheme = {
|
||||
|
||||
tag: {
|
||||
color: white,
|
||||
background: grayDarkStrong,
|
||||
hoverBackground: darkGrayLight,
|
||||
disabledBackground: grayDark,
|
||||
deletedColor: "#A3A9AE",
|
||||
background: "#474747",
|
||||
hoverBackground: "#282828",
|
||||
disabledBackground: "#858585",
|
||||
deletedBackground: "#282828",
|
||||
defaultTagColor: white,
|
||||
newTagBackground: black,
|
||||
newTagBackground: "#242424",
|
||||
newTagHoverBackground: "#3D3D3D",
|
||||
},
|
||||
|
||||
profile: {
|
||||
|
Loading…
Reference in New Issue
Block a user