Merge branch 'develop' into refactoring/global-colors

This commit is contained in:
Viktor Fomin 2024-06-20 18:00:59 +03:00
commit cb4a36feee
45 changed files with 1577 additions and 1076 deletions

View File

@ -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"
}

View File

@ -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;

View File

@ -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 },

View File

@ -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 = () => {

View File

@ -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"

View File

@ -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>
);
};

View File

@ -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,
};

View File

@ -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;"}

View File

@ -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>
);
}
}

View File

@ -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] }],
});
}

View File

@ -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;

View File

@ -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,
};

View File

@ -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)! || {};
};

View File

@ -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>
);

View File

@ -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)));

View File

@ -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),
),
);

View File

@ -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)));

View File

@ -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),
),
);

View File

@ -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)));

View File

@ -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;

View File

@ -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;

View File

@ -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)));

View File

@ -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));

View File

@ -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;

View File

@ -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;

View File

@ -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,

View File

@ -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;
}
};

View File

@ -509,6 +509,7 @@ const InsideGroupTableRow = (props) => {
className="table-cell_username"
noHover
dir="auto"
truncate={true}
>
{statusType === "pending"
? email

View File

@ -512,6 +512,7 @@ const PeopleTableRow = (props) => {
className="table-cell_username"
noHover
dir="auto"
truncate={true}
>
{statusType === "pending"
? email

View File

@ -880,7 +880,7 @@ const SectionHeaderContent = (props) => {
: isRootFolder || isAccountsPage || isSettingsPage;
const getInsideGroupTitle = () => {
return isLoading || !currentGroup?.name
return isLoading && insideGroupTempTitle
? insideGroupTempTitle
: currentGroup?.name;
};

View File

@ -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}
/>

View File

@ -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];

View File

@ -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()}` ||

View File

@ -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) {

View File

@ -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) {

View File

@ -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;

View File

@ -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,

View File

@ -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) => {

View File

@ -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) => {

View File

@ -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) {

View File

@ -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};
}
`}
`;

View File

@ -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}

View File

@ -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 */

View File

@ -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: {

View File

@ -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: {