Merge pull request #509 from ONLYOFFICE/feature/VDR-lifetime
Feature/vdr lifetime
This commit is contained in:
commit
8f2f8defa5
@ -181,6 +181,10 @@
|
||||
"WantToRestoreTheRooms": "All shared links in restored rooms will become active, and their contents will be available to everyone with the room links. Do you want to restore the rooms?",
|
||||
"WithSubfolders": "With subfolders",
|
||||
"YouLeftTheRoom": "You have left the room",
|
||||
"RoomFilesLifetime": "The file lifetime is set to {{days}} {{period}} in this room",
|
||||
"FileWillBeDeleted": "The file will be deleted {{date}}",
|
||||
"LifetimeDialogDescription": "Lifetime countdown begins at the file creation date. Some files in this room exceed the proposed lifetime and will be deleted once you enable the setting.",
|
||||
"LifetimeDialogDescriptionHeader": "Older files with exceeded lifetime will be deleted",
|
||||
"Protected": "protected",
|
||||
"Embed": "Embed"
|
||||
}
|
||||
|
@ -6,6 +6,7 @@
|
||||
"CreationDate": "Creation date",
|
||||
"Data": "Data",
|
||||
"DateModified": "Date modified",
|
||||
"LifetimeEnds": "Lifetime ends",
|
||||
"DeletedRoomTags": "Tags removed.",
|
||||
"ExpectUsers": "Expect users",
|
||||
"FeedLinkWasDeleted": "Link was deleted",
|
||||
|
@ -26,9 +26,12 @@
|
||||
|
||||
import React from "react";
|
||||
import { inject, observer } from "mobx-react";
|
||||
import moment from "moment";
|
||||
import { toastr } from "@docspace/shared/components/toast";
|
||||
import { copyShareLink } from "@docspace/shared/utils/copy";
|
||||
import QuickButtons from "../components/QuickButtons";
|
||||
import { LANGUAGE } from "@docspace/shared/constants";
|
||||
import { getCookie, getCorrectDate } from "@docspace/shared/utils";
|
||||
|
||||
export default function withQuickButtons(WrappedComponent) {
|
||||
class WithQuickButtons extends React.Component {
|
||||
@ -100,6 +103,39 @@ export default function withQuickButtons(WrappedComponent) {
|
||||
}
|
||||
};
|
||||
|
||||
getStartDate = () => {
|
||||
const { period, value } = this.props.roomLifetime;
|
||||
const date = new Date(this.props.item.expired);
|
||||
|
||||
switch (period) {
|
||||
case 0:
|
||||
return new Date(date.setDate(date.getDate() - value));
|
||||
case 1:
|
||||
return new Date(date.setMonth(date.getMonth() - value));
|
||||
case 2:
|
||||
return new Date(date.setFullYear(date.getFullYear() - value));
|
||||
default:
|
||||
break;
|
||||
}
|
||||
};
|
||||
|
||||
getShowLifetimeIcon = () => {
|
||||
const { item } = this.props;
|
||||
|
||||
const startDate = this.getStartDate();
|
||||
const dateDiff = moment(startDate).diff(item.expired) * 0.1;
|
||||
const showDate = moment(item.expired).add(dateDiff, "milliseconds");
|
||||
|
||||
return moment().valueOf() >= showDate.valueOf();
|
||||
};
|
||||
|
||||
getItemExpiredDate = () => {
|
||||
const { culture, item } = this.props;
|
||||
|
||||
const locale = getCookie(LANGUAGE) || culture;
|
||||
return getCorrectDate(locale, item.expired);
|
||||
};
|
||||
|
||||
render() {
|
||||
const { isLoading } = this.state;
|
||||
|
||||
@ -115,8 +151,14 @@ export default function withQuickButtons(WrappedComponent) {
|
||||
isPersonalRoom,
|
||||
isArchiveFolder,
|
||||
currentDeviceType,
|
||||
roomLifetime,
|
||||
} = this.props;
|
||||
|
||||
const showLifetimeIcon =
|
||||
item.expired && roomLifetime ? this.getShowLifetimeIcon() : false;
|
||||
const expiredDate =
|
||||
item.expired && roomLifetime ? this.getItemExpiredDate() : null;
|
||||
|
||||
const quickButtonsComponent = (
|
||||
<QuickButtons
|
||||
t={t}
|
||||
@ -136,6 +178,8 @@ export default function withQuickButtons(WrappedComponent) {
|
||||
onCopyPrimaryLink={this.onCopyPrimaryLink}
|
||||
isArchiveFolder={isArchiveFolder}
|
||||
currentDeviceType={currentDeviceType}
|
||||
showLifetimeIcon={showLifetimeIcon}
|
||||
expiredDate={expiredDate}
|
||||
/>
|
||||
);
|
||||
|
||||
@ -175,10 +219,12 @@ export default function withQuickButtons(WrappedComponent) {
|
||||
isTrashFolder || isArchiveFolderRoot || isPersonalFolderRoot;
|
||||
|
||||
const { isPublicRoom } = publicRoomStore;
|
||||
const { getPrimaryFileLink, setShareChanged } = infoPanelStore;
|
||||
const { getPrimaryFileLink, setShareChanged, infoPanelRoom } =
|
||||
infoPanelStore;
|
||||
|
||||
return {
|
||||
theme: settingsStore.theme,
|
||||
culture: settingsStore.culture,
|
||||
currentDeviceType: settingsStore.currentDeviceType,
|
||||
isAdmin: authStore.isAdmin,
|
||||
lockFileAction,
|
||||
@ -192,6 +238,7 @@ export default function withQuickButtons(WrappedComponent) {
|
||||
isArchiveFolder,
|
||||
getPrimaryFileLink,
|
||||
setShareChanged,
|
||||
roomLifetime: infoPanelRoom?.lifetime,
|
||||
};
|
||||
},
|
||||
)(observer(WithQuickButtons));
|
||||
|
@ -76,6 +76,7 @@ import LeaveRoomDialog from "../dialogs/LeaveRoomDialog";
|
||||
import ChangeRoomOwnerPanel from "../panels/ChangeRoomOwnerPanel";
|
||||
import { CreatedPDFFormDialog } from "../dialogs/CreatedPDFFormDialog";
|
||||
import { PDFFormEditingDialog } from "../dialogs/PDFFormEditingDialog";
|
||||
import LifetimeDialog from "../dialogs/LifetimeDialog";
|
||||
import { SharePDFFormDialog } from "../dialogs/SharePDFFormDialog";
|
||||
|
||||
const Panels = (props) => {
|
||||
@ -90,6 +91,7 @@ const Panels = (props) => {
|
||||
deleteThirdPartyDialogVisible,
|
||||
versionHistoryPanelVisible,
|
||||
deleteDialogVisible,
|
||||
lifetimeDialogVisible,
|
||||
downloadDialogVisible,
|
||||
emptyTrashDialogVisible,
|
||||
newFilesPanelVisible,
|
||||
@ -269,6 +271,7 @@ const Panels = (props) => {
|
||||
<VersionHistoryPanel key="version-history-panel" />
|
||||
),
|
||||
deleteDialogVisible && <DeleteDialog key="delete-dialog" />,
|
||||
lifetimeDialogVisible && <LifetimeDialog key="delete-dialog" />,
|
||||
emptyTrashDialogVisible && <EmptyTrashDialog key="empty-trash-dialog" />,
|
||||
downloadDialogVisible && <DownloadDialog key="download-dialog" />,
|
||||
|
||||
@ -378,6 +381,7 @@ export default inject(
|
||||
connectDialogVisible,
|
||||
deleteThirdPartyDialogVisible,
|
||||
deleteDialogVisible,
|
||||
lifetimeDialogVisible,
|
||||
downloadDialogVisible,
|
||||
emptyTrashDialogVisible,
|
||||
newFilesPanelVisible,
|
||||
@ -442,6 +446,7 @@ export default inject(
|
||||
deleteThirdPartyDialogVisible,
|
||||
versionHistoryPanelVisible,
|
||||
deleteDialogVisible,
|
||||
lifetimeDialogVisible,
|
||||
downloadDialogVisible,
|
||||
emptyTrashDialogVisible,
|
||||
newFilesPanelVisible,
|
||||
|
@ -27,6 +27,7 @@
|
||||
import React, { useState, useEffect, useCallback } from "react";
|
||||
import { inject, observer } from "mobx-react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import isEqual from "lodash/isEqual";
|
||||
import { EditRoomDialog } from "../dialogs";
|
||||
import { Encoder } from "@docspace/shared/utils/encoder";
|
||||
import api from "@docspace/shared/api";
|
||||
@ -75,6 +76,7 @@ const EditRoomEvent = ({
|
||||
|
||||
defaultRoomsQuota,
|
||||
isDefaultRoomsQuotaSet,
|
||||
changeRoomLifetime,
|
||||
}) => {
|
||||
const { t } = useTranslation(["CreateEditRoomDialog", "Common", "Files"]);
|
||||
|
||||
@ -106,6 +108,7 @@ const EditRoomEvent = ({
|
||||
},
|
||||
roomOwner: item.createdBy,
|
||||
indexing: item.indexing,
|
||||
lifetime: item.lifetime,
|
||||
|
||||
...(isDefaultRoomsQuotaSet && {
|
||||
quota: item.quotaLimit,
|
||||
@ -140,6 +143,7 @@ const EditRoomEvent = ({
|
||||
const isTitleChanged = roomParams?.title !== item.title;
|
||||
const isQuotaChanged = quotaLimit !== item.quotaLimit;
|
||||
const isOwnerChanged = roomParams?.roomOwner?.id !== item.createdBy.id;
|
||||
const lifetimeChanged = !isEqual(roomParams.lifetime, item.lifetime);
|
||||
|
||||
const tags = roomParams.tags.map((tag) => tag.name);
|
||||
const newTags = roomParams.tags.filter((t) => t.isNew).map((t) => t.name);
|
||||
@ -176,6 +180,12 @@ const EditRoomEvent = ({
|
||||
displayName: roomParams.roomOwner.label,
|
||||
};
|
||||
}
|
||||
|
||||
if (lifetimeChanged) {
|
||||
actions.push(changeRoomLifetime(room.id, roomParams.lifetime));
|
||||
room.lifetime = roomParams.lifetime;
|
||||
}
|
||||
|
||||
if (tags.length) {
|
||||
actions.push(addTagsToRoom(room.id, newTags));
|
||||
room.tags = tags;
|
||||
@ -238,7 +248,11 @@ const EditRoomEvent = ({
|
||||
if (withPaging) await updateCurrentFolder(null, currentFolderId);
|
||||
|
||||
if (item.id === currentFolderId) {
|
||||
updateEditedSelectedRoom(editRoomParams.title, tags);
|
||||
updateEditedSelectedRoom(
|
||||
editRoomParams.title,
|
||||
tags,
|
||||
roomParams.lifetime,
|
||||
);
|
||||
if (item.logo.original && !roomParams.icon.uploadedFile) {
|
||||
removeLogoPaths();
|
||||
// updateInfoPanelSelection();
|
||||
@ -337,7 +351,8 @@ export default inject(
|
||||
removeLogoPaths,
|
||||
updateLogoPathsCacheBreaker,
|
||||
} = selectedFolderStore;
|
||||
const { updateCurrentFolder, changeRoomOwner } = filesActionsStore;
|
||||
const { updateCurrentFolder, changeRoomOwner, changeRoomLifetime } =
|
||||
filesActionsStore;
|
||||
const { getThirdPartyIcon } = filesSettingsStore.thirdPartyStore;
|
||||
const { setCreateRoomDialogVisible } = dialogsStore;
|
||||
const { withPaging } = settingsStore;
|
||||
@ -381,6 +396,7 @@ export default inject(
|
||||
|
||||
updateInfoPanelSelection,
|
||||
changeRoomOwner,
|
||||
changeRoomLifetime,
|
||||
};
|
||||
},
|
||||
)(observer(EditRoomEvent));
|
||||
|
@ -32,21 +32,38 @@ import LinkReactSvgUrl from "PUBLIC_DIR/images/link.react.svg?url";
|
||||
import LockedReactSvgUrl from "PUBLIC_DIR/images/locked.react.svg?url";
|
||||
import FileActionsFavoriteReactSvgUrl from "PUBLIC_DIR/images/file.actions.favorite.react.svg?url";
|
||||
import FavoriteReactSvgUrl from "PUBLIC_DIR/images/favorite.react.svg?url";
|
||||
import LifetimeReactSvgUrl from "PUBLIC_DIR/images/lifetime.react.svg?url";
|
||||
import LockedReact12SvgUrl from "PUBLIC_DIR/images/icons/12/lock.react.svg?url";
|
||||
|
||||
import React, { useMemo } from "react";
|
||||
import styled from "styled-components";
|
||||
|
||||
import { isTablet, isMobile, commonIconsStyles } from "@docspace/shared/utils";
|
||||
import { isTablet } from "@docspace/shared/utils";
|
||||
import {
|
||||
DeviceType,
|
||||
FileStatus,
|
||||
RoomsType,
|
||||
ShareAccessRights,
|
||||
} from "@docspace/shared/enums";
|
||||
import { Tooltip } from "@docspace/shared/components/tooltip";
|
||||
import { Text } from "@docspace/shared/components/text";
|
||||
|
||||
import { ColorTheme, ThemeId } from "@docspace/shared/components/color-theme";
|
||||
|
||||
const StyledQuickButtons = styled.div`
|
||||
.file-lifetime {
|
||||
svg {
|
||||
rect {
|
||||
fill: ${({ theme }) => theme.filesQuickButtons.lifeTimeColor};
|
||||
}
|
||||
|
||||
circle,
|
||||
path {
|
||||
stroke: ${({ theme }) => theme.filesQuickButtons.lifeTimeColor};
|
||||
}
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
const QuickButtons = (props) => {
|
||||
const {
|
||||
t,
|
||||
@ -65,6 +82,8 @@ const QuickButtons = (props) => {
|
||||
isPersonalRoom,
|
||||
isArchiveFolder,
|
||||
currentDeviceType,
|
||||
showLifetimeIcon,
|
||||
expiredDate,
|
||||
} = props;
|
||||
|
||||
const isMobile = currentDeviceType === DeviceType.mobile;
|
||||
@ -136,8 +155,36 @@ const QuickButtons = (props) => {
|
||||
!isArchiveFolder &&
|
||||
!isTile;
|
||||
|
||||
const getTooltipContent = () => (
|
||||
<Text fontSize="12px" fontWeight={400} noSelect>
|
||||
{t("Files:FileWillBeDeleted", { date: expiredDate })}.
|
||||
</Text>
|
||||
);
|
||||
|
||||
return (
|
||||
<div className="badges additional-badges badges__quickButtons">
|
||||
<StyledQuickButtons className="badges additional-badges badges__quickButtons">
|
||||
{showLifetimeIcon && (
|
||||
<>
|
||||
<ColorTheme
|
||||
themeId={ThemeId.IconButton}
|
||||
iconName={LifetimeReactSvgUrl}
|
||||
className="badge file-lifetime icons-group"
|
||||
size={sizeQuickButton}
|
||||
isClickable
|
||||
isDisabled={isDisabled}
|
||||
data-tooltip-id="lifetimeTooltip"
|
||||
color={theme.filesQuickButtons.lifeTimeColor}
|
||||
/>
|
||||
|
||||
<Tooltip
|
||||
id="lifetimeTooltip"
|
||||
place="bottom"
|
||||
getContent={getTooltipContent}
|
||||
maxWidth="300px"
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
|
||||
{isAvailableLockFile && (
|
||||
<ColorTheme
|
||||
themeId={ThemeId.IconButton}
|
||||
@ -206,7 +253,7 @@ const QuickButtons = (props) => {
|
||||
hoverColor={theme.filesQuickButtons.hoverColor}
|
||||
/>
|
||||
)} */}
|
||||
</div>
|
||||
</StyledQuickButtons>
|
||||
);
|
||||
};
|
||||
|
||||
|
@ -220,13 +220,13 @@ const ConflictResolveDialog = (props: ConflictResolveDialogProps) => {
|
||||
isLoading={!ready}
|
||||
onSubmit={isUploadConflict ? onAcceptUploadType : onAcceptType}
|
||||
onClose={onCloseDialog}
|
||||
cancelButtonLabel={t("Common:CancelButton")}
|
||||
submitButtonLabel={t("Common:OKButton")}
|
||||
cancelButtonLabel={t("CancelButton")}
|
||||
submitButtonLabel={t("OKButton")}
|
||||
messageText={messageText}
|
||||
selectActionText={t("Common:ConflictResolveSelectAction")}
|
||||
overwriteTitle={t("Common:OverwriteTitle")}
|
||||
overwriteDescription={t("Common:OverwriteDescription")}
|
||||
duplicateTitle={t("Common:CreateFileCopy")}
|
||||
duplicateTitle={t("CreateFileCopy")}
|
||||
duplicateDescription={t("Common:CreateDescription")}
|
||||
skipTitle={t("Common:SkipTitle")}
|
||||
skipDescription={t("Common:SkipDescription")}
|
||||
|
@ -25,7 +25,7 @@
|
||||
// International. See the License terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
|
||||
|
||||
import React, { useState, useEffect, useRef, useCallback } from "react";
|
||||
|
||||
import isEqual from "lodash/isEqual";
|
||||
import TagHandler from "./handlers/TagHandler";
|
||||
import SetRoomParams from "./sub-components/SetRoomParams";
|
||||
import DialogHeader from "./sub-components/DialogHeader";
|
||||
@ -76,7 +76,8 @@ const EditRoomDialog = ({
|
||||
currentParams.icon.uploadedFile === undefined)) ||
|
||||
prevParams.icon.uploadedFile === currentParams.icon.uploadedFile) &&
|
||||
prevParams.quota === currentParams.quota &&
|
||||
prevParams.indexing === currentParams.indexing
|
||||
prevParams.indexing === currentParams.indexing &&
|
||||
isEqual(prevParams.lifetime, currentParams.lifetime)
|
||||
);
|
||||
};
|
||||
|
||||
|
@ -1,5 +1,6 @@
|
||||
import React, { useState } from "react";
|
||||
import { useState, useEffect } from "react";
|
||||
import styled from "styled-components";
|
||||
import { capitalize } from "lodash";
|
||||
import { Text } from "@docspace/shared/components/text";
|
||||
import { TextInput } from "@docspace/shared/components/text-input";
|
||||
import { ComboBox } from "@docspace/shared/components/combobox";
|
||||
@ -44,22 +45,28 @@ const StyledFileLifetime = styled.div`
|
||||
}
|
||||
`;
|
||||
|
||||
const FileLifetime = ({ t }) => {
|
||||
const FileLifetime = ({ t, roomParams, setRoomParams }) => {
|
||||
const lifetime = roomParams.lifetime ?? {
|
||||
value: 12,
|
||||
deletePermanently: false,
|
||||
period: 0,
|
||||
};
|
||||
|
||||
const dateOptions = [
|
||||
{
|
||||
key: 1,
|
||||
label: t("Common:Days"),
|
||||
"data-type": 1,
|
||||
label: capitalize(t("Common:Days")),
|
||||
value: 0,
|
||||
},
|
||||
{
|
||||
key: 2,
|
||||
label: t("Common:Months"),
|
||||
"data-type": 2,
|
||||
value: 1,
|
||||
},
|
||||
{
|
||||
key: 3,
|
||||
label: t("Common:Years"),
|
||||
"data-type": 3,
|
||||
value: 2,
|
||||
},
|
||||
];
|
||||
|
||||
@ -67,36 +74,66 @@ const FileLifetime = ({ t }) => {
|
||||
{
|
||||
key: 1,
|
||||
label: t("Common:MoveToTrash"),
|
||||
"data-type": 1,
|
||||
value: false,
|
||||
},
|
||||
{
|
||||
key: 2,
|
||||
label: t("Common:DeletePermanently"),
|
||||
"data-type": 2,
|
||||
value: true,
|
||||
},
|
||||
];
|
||||
|
||||
const [inputValue, setInputValue] = useState("");
|
||||
const [selectedDate, setSelectedDate] = useState(dateOptions[0]);
|
||||
const [selectedDelete, setSelectedDelete] = useState(deleteOptions[0]);
|
||||
const selectedInputValue = lifetime.value + "";
|
||||
const selectedDateOption = dateOptions.find(
|
||||
(o) => o.value === lifetime.period,
|
||||
);
|
||||
const selectedDeleteOptions = lifetime.deletePermanently
|
||||
? deleteOptions[1]
|
||||
: deleteOptions[0];
|
||||
|
||||
const [inputValue, setInputValue] = useState(selectedInputValue);
|
||||
const [selectedDate, setSelectedDate] = useState(selectedDateOption);
|
||||
const [selectedDelete, setSelectedDelete] = useState(selectedDeleteOptions);
|
||||
|
||||
useEffect(() => {
|
||||
if (!roomParams.lifetime) {
|
||||
setRoomParams({
|
||||
...roomParams,
|
||||
lifetime,
|
||||
});
|
||||
}
|
||||
}, [roomParams.lifetime]);
|
||||
|
||||
const onChange = (e) => {
|
||||
// /^(?:[1-9][0-9]*|0)$/
|
||||
if (e.target.value && !/^(?:[1-9][0-9]*)$/.test(e.target.value)) return;
|
||||
|
||||
setInputValue(e.target.value);
|
||||
|
||||
setRoomParams({
|
||||
...roomParams,
|
||||
lifetime: { ...lifetime, value: +e.target.value },
|
||||
});
|
||||
};
|
||||
|
||||
const isLoading = false;
|
||||
|
||||
const onSelectDate = (option) => {
|
||||
setSelectedDate(option);
|
||||
console.log("onDateSelect", option);
|
||||
|
||||
setRoomParams({
|
||||
...roomParams,
|
||||
lifetime: { ...lifetime, period: option.value },
|
||||
});
|
||||
};
|
||||
|
||||
const onSelectDelete = (option) => {
|
||||
setSelectedDelete(option);
|
||||
console.log("onSelectDelete", option);
|
||||
|
||||
setRoomParams({
|
||||
...roomParams,
|
||||
lifetime: { ...lifetime, deletePermanently: option.value },
|
||||
});
|
||||
};
|
||||
|
||||
return (
|
||||
|
@ -67,7 +67,9 @@ const Block = ({
|
||||
const VirtualDataRoomBlock = ({ t, roomParams, setRoomParams }) => {
|
||||
const role = t("Translations:RoleViewer");
|
||||
|
||||
const [fileLifetimeChecked, setFileLifetimeChecked] = useState(false);
|
||||
const [fileLifetimeChecked, setFileLifetimeChecked] = useState(
|
||||
!!roomParams?.lifetime,
|
||||
);
|
||||
const [copyAndDownloadChecked, setCopyAndDownloadChecked] = useState(false);
|
||||
const [watermarksChecked, setWatermarksChecked] = useState(false);
|
||||
|
||||
@ -76,6 +78,7 @@ const VirtualDataRoomBlock = ({ t, roomParams, setRoomParams }) => {
|
||||
};
|
||||
|
||||
const onChangeFileLifetime = () => {
|
||||
if (fileLifetimeChecked) setRoomParams({ ...roomParams, lifetime: null });
|
||||
setFileLifetimeChecked(!fileLifetimeChecked);
|
||||
};
|
||||
|
||||
@ -103,7 +106,11 @@ const VirtualDataRoomBlock = ({ t, roomParams, setRoomParams }) => {
|
||||
isDisabled={false}
|
||||
isChecked={fileLifetimeChecked}
|
||||
>
|
||||
<FileLifetime t={t} />
|
||||
<FileLifetime
|
||||
t={t}
|
||||
roomParams={roomParams}
|
||||
setRoomParams={setRoomParams}
|
||||
/>
|
||||
</Block>
|
||||
<Block
|
||||
headerText={t("RestrictCopyAndDownload")}
|
||||
|
@ -0,0 +1,46 @@
|
||||
import { ModalDialog } from "@docspace/shared/components/modal-dialog";
|
||||
import { tablet } from "@docspace/shared/utils";
|
||||
import styled from "styled-components";
|
||||
import { getCorrectFourValuesStyle } from "@docspace/shared/utils";
|
||||
|
||||
const StyledLifetimeDialog = styled(ModalDialog)`
|
||||
.modal-dialog-content-body {
|
||||
display: grid;
|
||||
gap: 18px;
|
||||
}
|
||||
|
||||
.modal-dialog-aside-header {
|
||||
margin: ${({ theme }) =>
|
||||
getCorrectFourValuesStyle("0 -24px 0 -16px", theme.interfaceDirection)};
|
||||
padding: ${({ theme }) =>
|
||||
getCorrectFourValuesStyle("0 0 0 16px", theme.interfaceDirection)};
|
||||
}
|
||||
|
||||
.modal-dialog-aside-footer {
|
||||
@media ${tablet} {
|
||||
width: 100%;
|
||||
|
||||
${({ theme }) =>
|
||||
theme.interfaceDirection === "rtl"
|
||||
? `padding-left: 32px;`
|
||||
: `padding-right: 32px;`}
|
||||
display: flex;
|
||||
}
|
||||
}
|
||||
|
||||
.button-dialog-accept {
|
||||
@media ${tablet} {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
.button-dialog {
|
||||
@media ${tablet} {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
display: inline-block;
|
||||
}
|
||||
`;
|
||||
|
||||
export { StyledLifetimeDialog };
|
@ -0,0 +1,91 @@
|
||||
import { useEffect } from "react";
|
||||
import { ModalDialog } from "@docspace/shared/components/modal-dialog";
|
||||
import { StyledLifetimeDialog } from "./StyledLifetimeDialog";
|
||||
import { Button } from "@docspace/shared/components/button";
|
||||
import { Text } from "@docspace/shared/components/text";
|
||||
import { withTranslation } from "react-i18next";
|
||||
import { inject, observer } from "mobx-react";
|
||||
|
||||
const LifetimeDialogComponent = (props) => {
|
||||
const { t, setLifetimeDialogVisible, visible, tReady } = props;
|
||||
|
||||
useEffect(() => {
|
||||
document.addEventListener("keyup", onKeyUp, false);
|
||||
|
||||
return () => {
|
||||
document.removeEventListener("keyup", onKeyUp, false);
|
||||
};
|
||||
}, []);
|
||||
|
||||
const onKeyUp = (e) => {
|
||||
if (e.keyCode === 27) onClose();
|
||||
if (e.keyCode === 13 || e.which === 13) onDeleteAction();
|
||||
};
|
||||
|
||||
const onClose = () => {
|
||||
setLifetimeDialogVisible(false);
|
||||
};
|
||||
|
||||
const onAcceptClick = () => {
|
||||
console.log("onAcceptClick");
|
||||
onClose();
|
||||
};
|
||||
|
||||
const onDeleteAction = () => {
|
||||
onAcceptClick();
|
||||
};
|
||||
|
||||
return (
|
||||
<StyledLifetimeDialog
|
||||
isLoading={!tReady}
|
||||
visible={visible}
|
||||
onClose={onClose}
|
||||
>
|
||||
<ModalDialog.Header>{t("Common:Warning")}</ModalDialog.Header>
|
||||
<ModalDialog.Body>
|
||||
<div className="modal-dialog-content-body">
|
||||
<Text fontWeight={600} fontSize="13px" noSelect>
|
||||
{t("Files:LifetimeDialogDescriptionHeader")}
|
||||
</Text>
|
||||
<Text fontSize="13px" noSelect>
|
||||
{t("Files:LifetimeDialogDescription")}
|
||||
</Text>
|
||||
</div>
|
||||
</ModalDialog.Body>
|
||||
<ModalDialog.Footer>
|
||||
<Button
|
||||
id="delete-file-modal_submit"
|
||||
key="OkButton"
|
||||
label={t("Common:OKButton")}
|
||||
size="normal"
|
||||
primary
|
||||
scale
|
||||
onClick={onDeleteAction}
|
||||
// isDisabled={!selection.length}
|
||||
/>
|
||||
<Button
|
||||
id="delete-file-modal_cancel"
|
||||
key="CancelButton"
|
||||
label={t("Common:CancelButton")}
|
||||
size="normal"
|
||||
scale
|
||||
onClick={onClose}
|
||||
/>
|
||||
</ModalDialog.Footer>
|
||||
</StyledLifetimeDialog>
|
||||
);
|
||||
};
|
||||
|
||||
const LifetimeDialog = withTranslation(["Common", "Files"])(
|
||||
LifetimeDialogComponent,
|
||||
);
|
||||
|
||||
export default inject(({ dialogsStore }) => {
|
||||
const { lifetimeDialogVisible: visible, setLifetimeDialogVisible } =
|
||||
dialogsStore;
|
||||
|
||||
return {
|
||||
visible,
|
||||
setLifetimeDialogVisible,
|
||||
};
|
||||
})(observer(LifetimeDialog));
|
@ -144,6 +144,8 @@ class DetailsHelper {
|
||||
return "info_details_comments";
|
||||
case "Tags":
|
||||
return "info_details_tags";
|
||||
case "Lifetime ends":
|
||||
return "info_details_lifetime";
|
||||
case "Storage":
|
||||
return "info_details_storage";
|
||||
}
|
||||
@ -182,6 +184,7 @@ class DetailsHelper {
|
||||
"Date modified",
|
||||
"Last modified by",
|
||||
"Creation date",
|
||||
this.item.expired && "Lifetime ends",
|
||||
"Versions",
|
||||
"Comments",
|
||||
]
|
||||
@ -214,6 +217,8 @@ class DetailsHelper {
|
||||
return this.t("LastModifiedBy");
|
||||
case "Creation date":
|
||||
return this.t("CreationDate");
|
||||
case "Lifetime ends":
|
||||
return this.t("LifetimeEnds");
|
||||
|
||||
case "Versions":
|
||||
return this.t("InfoPanel:Versions");
|
||||
@ -261,6 +266,8 @@ class DetailsHelper {
|
||||
return this.getAuthorDecoration("updatedBy");
|
||||
case "Creation date":
|
||||
return this.getItemCreationDate();
|
||||
case "Lifetime ends":
|
||||
return this.getItemExpiredDate();
|
||||
|
||||
case "Versions":
|
||||
return this.getItemVersions();
|
||||
@ -338,6 +345,10 @@ class DetailsHelper {
|
||||
return text(parseAndFormatDate(this.item.created, this.culture));
|
||||
};
|
||||
|
||||
getItemExpiredDate = () => {
|
||||
return text(parseAndFormatDate(this.item.expired, this.culture));
|
||||
};
|
||||
|
||||
getItemVersions = () => {
|
||||
return text(this.item.version);
|
||||
};
|
||||
|
@ -25,6 +25,7 @@
|
||||
// International. See the License terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
|
||||
|
||||
import PublicRoomIconUrl from "PUBLIC_DIR/images/public-room.react.svg?url";
|
||||
import LifetimeRoomIconUrl from "PUBLIC_DIR/images/lifetime-room.react.svg?url";
|
||||
|
||||
import React from "react";
|
||||
import { inject, observer } from "mobx-react";
|
||||
@ -50,6 +51,7 @@ import {
|
||||
getCategoryUrl,
|
||||
} from "SRC_DIR/helpers/utils";
|
||||
import TariffBar from "SRC_DIR/components/TariffBar";
|
||||
import { getLifetimePeriodTranslation } from "@docspace/shared/utils/common";
|
||||
|
||||
const StyledContainer = styled.div`
|
||||
width: 100%;
|
||||
@ -145,6 +147,21 @@ const StyledContainer = styled.div`
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
${(props) =>
|
||||
props.isVirtualDataRoomType &&
|
||||
css`
|
||||
.title-icon {
|
||||
svg {
|
||||
path {
|
||||
fill: ${({ theme }) =>
|
||||
theme.navigation.lifetimeIconFill} !important;
|
||||
stroke: ${({ theme }) =>
|
||||
theme.navigation.lifetimeIconStroke} !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
`}
|
||||
`;
|
||||
|
||||
const SectionHeaderContent = (props) => {
|
||||
@ -211,6 +228,8 @@ const SectionHeaderContent = (props) => {
|
||||
isPublicRoom,
|
||||
theme,
|
||||
isPublicRoomType,
|
||||
isVirtualDataRoomType,
|
||||
|
||||
moveToPublicRoom,
|
||||
currentDeviceType,
|
||||
isFrame,
|
||||
@ -474,6 +493,17 @@ const SectionHeaderContent = (props) => {
|
||||
const logo = getLogoUrl(WhiteLabelLogoType.LightSmall, !theme.isBase);
|
||||
const burgerLogo = getLogoUrl(WhiteLabelLogoType.LeftMenu, !theme.isBase);
|
||||
|
||||
const titleIcon =
|
||||
(isPublicRoomType && !isPublicRoom && PublicRoomIconUrl) ||
|
||||
(isVirtualDataRoomType && selectedFolder.lifetime && LifetimeRoomIconUrl);
|
||||
|
||||
const titleIconTooltip = selectedFolder.lifetime
|
||||
? t("Files:RoomFilesLifetime", {
|
||||
days: selectedFolder.lifetime.value,
|
||||
period: getLifetimePeriodTranslation(selectedFolder.lifetime.period, t),
|
||||
})
|
||||
: null;
|
||||
|
||||
const navigationButtonLabel = showNavigationButton
|
||||
? t("Files:ShareRoom")
|
||||
: null;
|
||||
@ -481,7 +511,10 @@ const SectionHeaderContent = (props) => {
|
||||
return (
|
||||
<Consumer key="header">
|
||||
{(context) => (
|
||||
<StyledContainer isRecycleBinFolder={isRecycleBinFolder}>
|
||||
<StyledContainer
|
||||
isRecycleBinFolder={isRecycleBinFolder}
|
||||
isVirtualDataRoomType={isVirtualDataRoomType}
|
||||
>
|
||||
{tableGroupMenuVisible ? (
|
||||
<TableGroupMenu {...tableGroupMenuProps} withComboBox />
|
||||
) : (
|
||||
@ -534,9 +567,8 @@ const SectionHeaderContent = (props) => {
|
||||
withLogo={isPublicRoom && logo}
|
||||
burgerLogo={isPublicRoom && burgerLogo}
|
||||
isPublicRoom={isPublicRoom}
|
||||
titleIcon={
|
||||
currentIsPublicRoomType && !isPublicRoom && PublicRoomIconUrl
|
||||
}
|
||||
titleIcon={titleIcon}
|
||||
titleIconTooltip={titleIconTooltip}
|
||||
showRootFolderTitle={insideTheRoom || isInsideGroup}
|
||||
currentDeviceType={currentDeviceType}
|
||||
isFrame={isFrame}
|
||||
@ -663,6 +695,7 @@ export default inject(
|
||||
|
||||
const isRoom = !!roomType;
|
||||
const isPublicRoomType = roomType === RoomsType.PublicRoom;
|
||||
const isVirtualDataRoomType = roomType === RoomsType.VirtualDataRoom;
|
||||
const isCustomRoomType = roomType === RoomsType.CustomRoom;
|
||||
const isFormRoomType = roomType === RoomsType.FormRoom;
|
||||
|
||||
@ -771,6 +804,7 @@ export default inject(
|
||||
moveToRoomsPage,
|
||||
onClickBack,
|
||||
isPublicRoomType,
|
||||
isVirtualDataRoomType,
|
||||
isPublicRoom,
|
||||
|
||||
moveToPublicRoom,
|
||||
|
@ -126,6 +126,7 @@ class CreateEditRoomStore {
|
||||
roomType: roomParams.type,
|
||||
title: roomParams.title || t("Common:NewRoom"),
|
||||
indexing: roomParams.indexing,
|
||||
lifetime: roomParams.lifetime,
|
||||
createAsNewFolder: roomParams.createAsNewFolder ?? true,
|
||||
...(quotaLimit && {
|
||||
quota: +quotaLimit,
|
||||
|
@ -48,6 +48,7 @@ class DialogsStore {
|
||||
connectDialogVisible = false;
|
||||
thirdPartyMoveDialogVisible = false;
|
||||
deleteDialogVisible = false;
|
||||
lifetimeDialogVisible = false;
|
||||
downloadDialogVisible = false;
|
||||
emptyTrashDialogVisible = false;
|
||||
newFilesPanelVisible = false;
|
||||
@ -232,6 +233,10 @@ class DialogsStore {
|
||||
this.deleteDialogVisible = deleteDialogVisible;
|
||||
};
|
||||
|
||||
setLifetimeDialogVisible = (lifetimeDialogVisible) => {
|
||||
this.lifetimeDialogVisible = lifetimeDialogVisible;
|
||||
};
|
||||
|
||||
setEventDialogVisible = (eventDialogVisible) => {
|
||||
this.eventDialogVisible = eventDialogVisible;
|
||||
};
|
||||
|
@ -87,6 +87,7 @@ import {
|
||||
} from "SRC_DIR/helpers/utils";
|
||||
import { MEDIA_VIEW_URL } from "@docspace/shared/constants";
|
||||
import { openingNewTab } from "@docspace/shared/utils/openingNewTab";
|
||||
import { changeRoomLifetime } from "@docspace/shared/api/rooms";
|
||||
|
||||
class FilesActionStore {
|
||||
settingsStore;
|
||||
@ -2718,6 +2719,10 @@ class FilesActionStore {
|
||||
await refreshFiles();
|
||||
};
|
||||
|
||||
changeRoomLifetime = (roomId, lifetime) => {
|
||||
return changeRoomLifetime(roomId, lifetime);
|
||||
};
|
||||
|
||||
copyFromTemplateForm = async (fileInfo, t) => {
|
||||
const selectedItemId = this.selectedFolderStore.id;
|
||||
const fileIds = [fileInfo.id];
|
||||
|
@ -3236,6 +3236,7 @@ class FilesStore {
|
||||
inRoom,
|
||||
requestToken,
|
||||
indexing,
|
||||
lifetime,
|
||||
lastOpened,
|
||||
quotaLimit,
|
||||
usedSpace,
|
||||
@ -3243,6 +3244,7 @@ class FilesStore {
|
||||
providerId,
|
||||
startFilling,
|
||||
draftLocation,
|
||||
expired,
|
||||
} = item;
|
||||
|
||||
const thirdPartyIcon = this.thirdPartyStore.getThirdPartyIcon(
|
||||
@ -3405,6 +3407,7 @@ class FilesStore {
|
||||
...pluginOptions,
|
||||
inRoom,
|
||||
indexing,
|
||||
lifetime,
|
||||
type,
|
||||
hasDraft,
|
||||
isForm,
|
||||
@ -3417,6 +3420,7 @@ class FilesStore {
|
||||
providerId,
|
||||
startFilling,
|
||||
draftLocation,
|
||||
expired,
|
||||
};
|
||||
});
|
||||
};
|
||||
|
@ -40,7 +40,11 @@ import type {
|
||||
TPathParts,
|
||||
} from "@docspace/shared/types";
|
||||
import { TFolder, TFolderSecurity } from "@docspace/shared/api/files/types";
|
||||
import { TLogo, TRoomSecurity } from "@docspace/shared/api/rooms/types";
|
||||
import {
|
||||
TLogo,
|
||||
TRoomLifetime,
|
||||
TRoomSecurity,
|
||||
} from "@docspace/shared/api/rooms/types";
|
||||
|
||||
import { setDocumentTitle } from "../helpers/utils";
|
||||
|
||||
@ -141,6 +145,8 @@ class SelectedFolderStore {
|
||||
|
||||
parentRoomType: Nullable<FolderType> = null;
|
||||
|
||||
lifetime: TRoomLifetime | null = null;
|
||||
|
||||
constructor(settingsStore: SettingsStore) {
|
||||
makeAutoObservable(this);
|
||||
this.settingsStore = settingsStore;
|
||||
@ -185,6 +191,7 @@ class SelectedFolderStore {
|
||||
type: this.type,
|
||||
isRootFolder: this.isRootFolder,
|
||||
parentRoomType: this.parentRoomType,
|
||||
lifetime: this.lifetime,
|
||||
};
|
||||
};
|
||||
|
||||
@ -230,6 +237,7 @@ class SelectedFolderStore {
|
||||
this.type = null;
|
||||
this.inRoom = false;
|
||||
this.parentRoomType = null;
|
||||
this.lifetime = null;
|
||||
};
|
||||
|
||||
setParentId = (parentId: number) => {
|
||||
@ -252,9 +260,14 @@ class SelectedFolderStore {
|
||||
this.shared = shared;
|
||||
};
|
||||
|
||||
updateEditedSelectedRoom = (title = this.title, tags = this.tags) => {
|
||||
updateEditedSelectedRoom = (
|
||||
title = this.title,
|
||||
tags = this.tags,
|
||||
lifetime = this.lifetime,
|
||||
) => {
|
||||
this.title = title;
|
||||
this.tags = tags;
|
||||
this.lifetime = lifetime;
|
||||
};
|
||||
|
||||
setInRoom = (inRoom: boolean) => {
|
||||
|
@ -35,7 +35,7 @@ import {
|
||||
toUrlParams,
|
||||
} from "../../utils/common";
|
||||
import RoomsFilter from "./filter";
|
||||
import { TGetRooms } from "./types";
|
||||
import { TGetRooms, TRoomLifetime } from "./types";
|
||||
|
||||
export async function getRooms(filter: RoomsFilter, signal?: AbortSignal) {
|
||||
let params;
|
||||
@ -478,3 +478,17 @@ export function resetRoomQuota(roomIds) {
|
||||
|
||||
return request(options);
|
||||
}
|
||||
|
||||
export function changeRoomLifetime(
|
||||
roomId: string | number,
|
||||
lifetime: TRoomLifetime | null,
|
||||
) {
|
||||
const data = lifetime ? { ...lifetime } : null;
|
||||
const options = {
|
||||
method: "put",
|
||||
url: `files/rooms/${roomId}/lifetime`,
|
||||
data,
|
||||
};
|
||||
|
||||
return request(options);
|
||||
}
|
||||
|
@ -54,6 +54,12 @@ export type TRoomSecurity = {
|
||||
CopySharedLink: boolean;
|
||||
};
|
||||
|
||||
export type TRoomLifetime = {
|
||||
deletePermanently: boolean;
|
||||
period: number;
|
||||
value: number;
|
||||
};
|
||||
|
||||
export type TRoom = {
|
||||
parentId: number;
|
||||
filesCount: number;
|
||||
@ -79,6 +85,7 @@ export type TRoom = {
|
||||
updatedBy: TCreatedBy;
|
||||
isArchive?: boolean;
|
||||
security: TRoomSecurity;
|
||||
lifetime: TRoomLifetime;
|
||||
};
|
||||
|
||||
export type TGetRooms = {
|
||||
|
@ -26,19 +26,20 @@
|
||||
|
||||
import React, { useCallback } from "react";
|
||||
import { ReactSVG } from "react-svg";
|
||||
import NavigationText from "./sub-components/Text";
|
||||
|
||||
import { Consumer, DomHelpers } from "../../utils";
|
||||
import { DeviceType } from "../../enums";
|
||||
|
||||
import { Backdrop } from "../backdrop";
|
||||
|
||||
import ArrowButton from "./sub-components/ArrowBtn";
|
||||
import Text from "./sub-components/Text";
|
||||
import ControlButtons from "./sub-components/ControlBtn";
|
||||
import ToggleInfoPanelButton from "./sub-components/ToggleInfoPanelBtn";
|
||||
import NavigationLogo from "./sub-components/LogoBlock";
|
||||
import DropBox from "./sub-components/DropBox";
|
||||
|
||||
import { Tooltip } from "../tooltip";
|
||||
import { Text } from "../text";
|
||||
import { DeviceType } from "../../enums";
|
||||
import { StyledContainer } from "./Navigation.styled";
|
||||
import { INavigationProps } from "./Navigation.types";
|
||||
|
||||
@ -75,6 +76,7 @@ const Navigation = ({
|
||||
burgerLogo,
|
||||
isPublicRoom,
|
||||
titleIcon,
|
||||
titleIconTooltip,
|
||||
currentDeviceType,
|
||||
rootRoomTitle,
|
||||
showTitle,
|
||||
@ -168,13 +170,35 @@ const Navigation = ({
|
||||
((navigationItems && navigationItems.length > 1) || rootRoomTitle) &&
|
||||
currentDeviceType !== DeviceType.mobile;
|
||||
|
||||
const getContent = () => (
|
||||
<Text fontSize="12px" fontWeight={400} noSelect>
|
||||
{titleIconTooltip}
|
||||
</Text>
|
||||
);
|
||||
|
||||
const navigationTitleNode = (
|
||||
<div className="title-block">
|
||||
{titleIcon && <ReactSVG className="title-icon" src={titleIcon} />}
|
||||
<Text
|
||||
{titleIcon && (
|
||||
<ReactSVG
|
||||
data-tooltip-id="iconTooltip"
|
||||
className="title-icon"
|
||||
src={titleIcon}
|
||||
/>
|
||||
)}
|
||||
|
||||
{titleIconTooltip && (
|
||||
<Tooltip
|
||||
id="iconTooltip"
|
||||
place="bottom"
|
||||
getContent={getContent}
|
||||
maxWidth="300px"
|
||||
/>
|
||||
)}
|
||||
|
||||
<NavigationText
|
||||
className="title-block-text"
|
||||
title={title}
|
||||
isOpen={isOpen}
|
||||
isOpen={false}
|
||||
isRootFolder={isRootFolder}
|
||||
onClick={toggleDropBox}
|
||||
isRootFolderTitle={false}
|
||||
@ -189,7 +213,7 @@ const Navigation = ({
|
||||
|
||||
const navigationTitleContainerNode = showRootFolderNavigation ? (
|
||||
<div className="title-container">
|
||||
<Text
|
||||
<NavigationText
|
||||
className="room-title"
|
||||
title={
|
||||
rootRoomTitle || navigationItems[navigationItems.length - 2].title
|
||||
@ -241,6 +265,7 @@ const Navigation = ({
|
||||
currentDeviceType={currentDeviceType}
|
||||
navigationTitleContainerNode={navigationTitleContainerNode}
|
||||
onCloseDropBox={onCloseDropBox}
|
||||
titleIconTooltip={titleIconTooltip}
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
|
@ -203,5 +203,6 @@ export interface INavigationProps {
|
||||
onNavigationButtonClick?: () => void;
|
||||
tariffBar: React.ReactElement;
|
||||
showNavigationButton: boolean;
|
||||
titleIconTooltip?: string;
|
||||
onContextOptionsClick?: () => void;
|
||||
}
|
||||
|
@ -269,6 +269,29 @@ const StyledItem = styled.div<{
|
||||
}
|
||||
}`}
|
||||
`}
|
||||
|
||||
.selector-item_name {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
width: 100%;
|
||||
|
||||
.label {
|
||||
width: unset;
|
||||
}
|
||||
|
||||
svg {
|
||||
path {
|
||||
fill: ${({ theme }) => theme.navigation.lifetimeIconFill} !important;
|
||||
stroke: ${({ theme }) =>
|
||||
theme.navigation.lifetimeIconStroke} !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.title-icon {
|
||||
cursor: pointer;
|
||||
}
|
||||
`;
|
||||
|
||||
const StyledEmptyScreen = styled.div<{ withSearch: boolean }>`
|
||||
|
@ -541,6 +541,7 @@ export type TSelectorItem = TSelectorItemType & {
|
||||
isSelected?: boolean;
|
||||
isDisabled?: boolean;
|
||||
disabledText?: string;
|
||||
lifetimeTooltip?: string | null;
|
||||
};
|
||||
|
||||
export type Data = {
|
||||
|
@ -26,12 +26,15 @@
|
||||
|
||||
import React from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { ReactSVG } from "react-svg";
|
||||
import Planet12ReactSvgUrl from "PUBLIC_DIR/images/icons/12/planet.react.svg?url";
|
||||
import LifetimeRoomIconUrl from "PUBLIC_DIR/images/lifetime-room.react.svg?url";
|
||||
import { getUserTypeLabel } from "../../../utils/common";
|
||||
import { Avatar, AvatarRole, AvatarSize } from "../../avatar";
|
||||
import { Text } from "../../text";
|
||||
import { Checkbox } from "../../checkbox";
|
||||
import { RoomIcon } from "../../room-icon";
|
||||
import { Tooltip } from "../../tooltip";
|
||||
|
||||
import { StyledItem } from "../Selector.styled";
|
||||
import { ItemProps, Data, TSelectorItem } from "../Selector.types";
|
||||
@ -106,6 +109,7 @@ const Item = React.memo(({ index, style, data }: ItemProps) => {
|
||||
isGroup,
|
||||
disabledText,
|
||||
dropDownItems,
|
||||
lifetimeTooltip,
|
||||
} = item;
|
||||
|
||||
if (isInputItem) {
|
||||
@ -175,6 +179,12 @@ const Item = React.memo(({ index, style, data }: ItemProps) => {
|
||||
onSelect?.(item, isDoubleClick);
|
||||
};
|
||||
|
||||
const getContent = () => (
|
||||
<Text fontSize="12px" fontWeight={400} noSelect>
|
||||
{lifetimeTooltip}
|
||||
</Text>
|
||||
);
|
||||
|
||||
return (
|
||||
<StyledItem
|
||||
key={`${label}-${avatar}-${role}`}
|
||||
@ -215,16 +225,34 @@ const Item = React.memo(({ index, style, data }: ItemProps) => {
|
||||
{renderCustomItem ? (
|
||||
renderCustomItem(label, typeLabel, email, isGroup)
|
||||
) : (
|
||||
<Text
|
||||
className="label label-disabled"
|
||||
fontWeight={600}
|
||||
fontSize="14px"
|
||||
noSelect
|
||||
truncate
|
||||
dir="auto"
|
||||
>
|
||||
{label}
|
||||
</Text>
|
||||
<div className="selector-item_name">
|
||||
<Text
|
||||
className="label label-disabled"
|
||||
fontWeight={600}
|
||||
fontSize="14px"
|
||||
noSelect
|
||||
truncate
|
||||
dir="auto"
|
||||
>
|
||||
{label}
|
||||
</Text>
|
||||
|
||||
{lifetimeTooltip && (
|
||||
<>
|
||||
<ReactSVG
|
||||
data-tooltip-id={`${item.id}_iconTooltip`}
|
||||
className="title-icon"
|
||||
src={LifetimeRoomIconUrl}
|
||||
/>
|
||||
<Tooltip
|
||||
id={`${item.id}_iconTooltip`}
|
||||
place="bottom"
|
||||
getContent={getContent}
|
||||
maxWidth="300px"
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
|
||||
{isDisabled && disabledText ? (
|
||||
|
@ -27,10 +27,14 @@
|
||||
import { TSelectorItem } from "../../components/selector";
|
||||
import { TFile, TFolder } from "../../api/files/types";
|
||||
import { TRoom } from "../../api/rooms/types";
|
||||
import { getIconPathByFolderType } from "../../utils/common";
|
||||
import {
|
||||
getIconPathByFolderType,
|
||||
getLifetimePeriodTranslation,
|
||||
} from "../../utils/common";
|
||||
import { iconSize32 } from "../../utils/image-helpers";
|
||||
import { DEFAULT_FILE_EXTS } from "./FilesSelector.constants";
|
||||
import { getTitleWithoutExtension } from "../../utils";
|
||||
import { TTranslation } from "../../types";
|
||||
|
||||
const isDisableFolder = (
|
||||
folder: TFolder,
|
||||
@ -118,9 +122,10 @@ export const convertFilesToItems: (
|
||||
return items;
|
||||
};
|
||||
|
||||
export const convertRoomsToItems: (rooms: TRoom[]) => TSelectorItem[] = (
|
||||
export const convertRoomsToItems: (
|
||||
rooms: TRoom[],
|
||||
) => {
|
||||
t: TTranslation,
|
||||
) => TSelectorItem[] = (rooms: TRoom[], t: TTranslation) => {
|
||||
const items = rooms.map((room) => {
|
||||
const {
|
||||
id,
|
||||
@ -133,12 +138,20 @@ export const convertRoomsToItems: (rooms: TRoom[]) => TSelectorItem[] = (
|
||||
parentId,
|
||||
rootFolderType,
|
||||
shared,
|
||||
lifetime,
|
||||
} = room;
|
||||
|
||||
const icon = logo.medium || "";
|
||||
|
||||
const iconProp = icon ? { icon } : { color: logo.color as string };
|
||||
|
||||
const lifetimeTooltip = lifetime
|
||||
? t("Files:RoomFilesLifetime", {
|
||||
days: String(lifetime.value),
|
||||
period: getLifetimePeriodTranslation(lifetime.period, t),
|
||||
})
|
||||
: null;
|
||||
|
||||
return {
|
||||
id,
|
||||
label: title,
|
||||
@ -151,6 +164,7 @@ export const convertRoomsToItems: (rooms: TRoom[]) => TSelectorItem[] = (
|
||||
isFolder: true,
|
||||
roomType,
|
||||
shared,
|
||||
lifetimeTooltip,
|
||||
...iconProp,
|
||||
};
|
||||
});
|
||||
|
@ -142,7 +142,7 @@ const useRoomsHelper = ({
|
||||
|
||||
setIsBreadCrumbsLoading(false);
|
||||
}
|
||||
const itemList: TSelectorItem[] = convertRoomsToItems(folders);
|
||||
const itemList: TSelectorItem[] = convertRoomsToItems(folders, t);
|
||||
|
||||
setHasNextPage(count === PAGE_COUNT);
|
||||
|
||||
|
@ -2004,6 +2004,8 @@ export const getBaseTheme = () => {
|
||||
background: white,
|
||||
rootFolderTitleColor: "#A3A9AE",
|
||||
boxShadow: "0px 8px 16px 0px #040F1B14",
|
||||
lifetimeIconFill: "#f2675a",
|
||||
lifetimeIconStroke: "#f2675a",
|
||||
|
||||
icon: {
|
||||
fill: "#316DAA",
|
||||
|
@ -1976,6 +1976,8 @@ const Dark: TTheme = {
|
||||
background: black,
|
||||
rootFolderTitleColor: "#ADADAD",
|
||||
boxShadow: "0px 8px 16px 0px #040F1B29",
|
||||
lifetimeIconFill: "none",
|
||||
lifetimeIconStroke: "#657077",
|
||||
|
||||
icon: {
|
||||
fill: "#E06A1B",
|
||||
|
@ -411,6 +411,24 @@ export function getProviderLabel(provider: string, t: (key: string) => string) {
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
export const getLifetimePeriodTranslation = (
|
||||
period: number,
|
||||
t: TTranslation,
|
||||
) => {
|
||||
switch (period) {
|
||||
case 0:
|
||||
return t("Common:Days").toLowerCase();
|
||||
case 1:
|
||||
return t("Common:Months").toLowerCase();
|
||||
case 2:
|
||||
return t("Common:Years").toLowerCase();
|
||||
|
||||
default:
|
||||
return t("Common:Days").toLowerCase();
|
||||
}
|
||||
};
|
||||
|
||||
export const isLanguageRtl = (lng: string) => {
|
||||
if (!lng) return;
|
||||
|
||||
|
3
public/images/lifetime-room.react.svg
Normal file
3
public/images/lifetime-room.react.svg
Normal file
@ -0,0 +1,3 @@
|
||||
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M3.29161 8.29084C3.35982 8.64692 3.4449 8.99697 3.55132 9.31623C3.75317 9.92178 4.14601 10.3844 4.6771 10.6278C5.18859 10.8623 5.73524 10.8507 6.19123 10.6987C6.64256 10.5482 7.07413 10.2374 7.33699 9.77739C7.61595 9.28921 7.66898 8.68902 7.41915 8.10608C6.78953 6.63698 6.88202 5.03002 7.37839 3.65122C7.60976 3.00852 7.9148 2.45209 8.24405 2.0037C8.40619 2.60299 8.64385 3.12067 8.94095 3.58119C9.47219 4.4046 10.1678 4.99418 10.7477 5.48566C10.783 5.51561 10.8179 5.54519 10.8524 5.57444C11.4796 6.10764 11.9845 6.56006 12.359 7.19042C12.7212 7.80008 13 8.64846 13 10C13 12.7614 10.7614 15 8 15C5.23858 15 3 12.7614 3 10C3 9.40715 3.11554 8.8279 3.29161 8.29084Z" stroke="#657077" stroke-width="2"/>
|
||||
</svg>
|
After Width: | Height: | Size: 815 B |
5
public/images/lifetime.react.svg
Normal file
5
public/images/lifetime.react.svg
Normal file
@ -0,0 +1,5 @@
|
||||
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<rect x="5" width="6" height="2" rx="1" fill="#F2675A"/>
|
||||
<circle cx="8" cy="9" r="6" stroke="#F2675A" stroke-width="2"/>
|
||||
<path d="M8 5V9L10 11" stroke="#F2675A" stroke-width="2"/>
|
||||
</svg>
|
After Width: | Height: | Size: 283 B |
Loading…
Reference in New Issue
Block a user