Merge branch 'develop' into feature/open-location
This commit is contained in:
commit
b5712eaba8
@ -244,17 +244,17 @@ public class EmployeeFullDtoHelper : EmployeeDtoHelper
|
||||
|
||||
if (_context.Check("avatarMax"))
|
||||
{
|
||||
result.AvatarMax = await _userPhotoManager.GetMaxPhotoURL(userInfo.Id) + $"?_={cacheKey}";
|
||||
result.AvatarMax = await _userPhotoManager.GetMaxPhotoURL(userInfo.Id) + $"?hash={cacheKey}";
|
||||
}
|
||||
|
||||
if (_context.Check("avatarMedium"))
|
||||
{
|
||||
result.AvatarMedium = await _userPhotoManager.GetMediumPhotoURL(userInfo.Id) + $"?_={cacheKey}";
|
||||
result.AvatarMedium = await _userPhotoManager.GetMediumPhotoURL(userInfo.Id) + $"?hash={cacheKey}";
|
||||
}
|
||||
|
||||
if (_context.Check("avatar"))
|
||||
{
|
||||
result.Avatar = await _userPhotoManager.GetBigPhotoURL(userInfo.Id) + $"?_={cacheKey}";
|
||||
result.Avatar = await _userPhotoManager.GetBigPhotoURL(userInfo.Id) + $"?hash={cacheKey}";
|
||||
}
|
||||
|
||||
if (_context.Check("listAdminModules"))
|
||||
|
@ -5,7 +5,7 @@
|
||||
"DeleteFolder": "You are about to delete this folder. Are you sure you want to continue?",
|
||||
"DeleteFile": "You are about to delete this file. Are you sure you want to continue?",
|
||||
"MoveToTrashButton": "Move to Trash",
|
||||
"MoveToTrashFile": "You are about to delete this file. Please note that if you have shared it with someone, it will become unavailable. Are you sure you want to continue?",
|
||||
"MoveToTrashFile": "You are about to delete this file. Please note that if you have shared it with someone, it will become unavailable. The file will be permanently deleted in 30 days. Are you sure you want to continue?",
|
||||
"MoveToTrashFileFromPersonal": "You are about to delete this file. Are you sure you want to continue?",
|
||||
"MoveToTrashFolder": "You are about to delete this folder. Please note that if you have shared it with someone, it will become unavailable. Are you sure you want to continue?",
|
||||
"MoveToTrashFolderFromPersonal": "You are about to delete this folder. Are you sure you want to continue?",
|
||||
|
@ -13,6 +13,7 @@
|
||||
"BackToParentFolderButton": "Back to parent folder",
|
||||
"ByAuthor": "Author",
|
||||
"ByCreation": "Created",
|
||||
"ByErasure": "Erasure",
|
||||
"ByLastModified": "Modified",
|
||||
"ByOwner": "Owner",
|
||||
"CollaborationRooms": "Collaboration",
|
||||
@ -22,6 +23,7 @@
|
||||
"CopyItems": "<strong>{{qty}}</strong> elements copied",
|
||||
"CreateRoom": "Create room",
|
||||
"CustomRooms": "Custom",
|
||||
"DaysRemaining": "Days remaining: {{daysRemaining}}",
|
||||
"Document": "Document",
|
||||
"EditRoom": "Edit room",
|
||||
"EmptyFile": "Empty file",
|
||||
@ -100,7 +102,8 @@
|
||||
"TooltipElementCopyMessage": "Copy {{element}}",
|
||||
"TooltipElementsCopyMessage": "Copy {{element}} elements",
|
||||
"TooltipElementsMoveMessage": "Move {{element}} elements",
|
||||
"TrashEmptyDescription": "All deleted files are moved to 'Trash'. Restore files deleted by mistake or delete them permanently. Please note, that the files deleted from the 'Trash' cannot be restored any longer.",
|
||||
"TrashErasureWarning": "Items in Trash are automatically deleted after 30 days",
|
||||
"TrashEmptyDescription": "All deleted files are moved to 'Trash'. Restore files deleted by mistake or delete them permanently. Files in 'Trash' are automatically deleted after 30 days. Please note, that the files deleted from the 'Trash' cannot be restored any longer.",
|
||||
"UnarchivedRoomAction": "The room '{{name}}' is unarchived",
|
||||
"UnarchivedRoomsAction": "The rooms are unarchived",
|
||||
"UnblockVersion": "Unblock/Check-in",
|
||||
|
@ -73,7 +73,7 @@
|
||||
"DeleteTheme": "Delete theme",
|
||||
"DeleteThemeForever": "Delete theme forever?",
|
||||
"DeleteThemeNotice": "The theme will be deleted permanently. You will not be able to undo this action.",
|
||||
"DeveloperTools": "Developer",
|
||||
"DeveloperTools": "Developer Tools",
|
||||
"Disabled": "Disabled",
|
||||
"DownloadCopy": "Download copy",
|
||||
"DownloadReportBtnText": "Download report",
|
||||
|
@ -73,7 +73,7 @@
|
||||
"DeleteTheme": "Удалить тему",
|
||||
"DeleteThemeForever": "Удалить тему навсегда?",
|
||||
"DeleteThemeNotice": "Тема будет удалена навсегда. Вы не сможете отменить это действие.",
|
||||
"DeveloperTools": "Разработчик",
|
||||
"DeveloperTools": "Инструменты разработчика",
|
||||
"Disabled": "Отключено",
|
||||
"DownloadCopy": "Скачать копию",
|
||||
"DownloadReportBtn": "Скачать и открыть отчет",
|
||||
|
@ -49,20 +49,17 @@ export default function withContent(WrappedContent) {
|
||||
|
||||
render() {
|
||||
const {
|
||||
element,
|
||||
isDesktop,
|
||||
isTrashFolder,
|
||||
isArchiveFolder,
|
||||
item,
|
||||
onFilesClick,
|
||||
t,
|
||||
|
||||
viewer,
|
||||
|
||||
titleWithoutExt,
|
||||
} = this.props;
|
||||
|
||||
const { access, createdBy, fileExst, fileStatus, href, icon, id } = item;
|
||||
const { access, createdBy, fileStatus, href } = item;
|
||||
|
||||
const updatedDate = this.getStatusByDate(false);
|
||||
const createdDate = this.getStatusByDate(true);
|
||||
|
@ -11,6 +11,7 @@ import {
|
||||
isMobileOnly,
|
||||
isChrome,
|
||||
isTablet,
|
||||
isAndroid,
|
||||
} from "react-device-detect";
|
||||
import { inject, observer } from "mobx-react";
|
||||
|
||||
@ -130,6 +131,10 @@ const Layout = (props) => {
|
||||
}
|
||||
}
|
||||
|
||||
if (isMobileOnly && isAndroid && isChrome) {
|
||||
height = `calc(100vh - ${correctorMobileChrome}px)`;
|
||||
}
|
||||
|
||||
// if (isTablet && isIOS && isSafari) {
|
||||
// if (
|
||||
// window.innerHeight < window.innerWidth &&
|
||||
|
@ -58,9 +58,10 @@ export const CategoryType = Object.freeze({
|
||||
* @readonly
|
||||
*/
|
||||
export const TableVersions = Object.freeze({
|
||||
Files: "2",
|
||||
Rooms: "1",
|
||||
Files: "2",
|
||||
Accounts: "3",
|
||||
Trash: "4",
|
||||
});
|
||||
|
||||
export const BINDING_POST = "urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST";
|
||||
|
@ -13,6 +13,7 @@ import config from "PACKAGE_FILE";
|
||||
import { combineUrl, toUrlParams } from "@docspace/common/utils";
|
||||
import { addFileToRecentlyViewed } from "@docspace/common/api/files";
|
||||
import i18n from "./i18n";
|
||||
import moment from "moment";
|
||||
|
||||
import { request } from "@docspace/common/api/client";
|
||||
|
||||
@ -265,3 +266,12 @@ export const connectedCloudsTypeIcon = (key) => {
|
||||
default:
|
||||
}
|
||||
};
|
||||
|
||||
export const getDaysRemaining = (autoDelete) => {
|
||||
let daysRemaining = moment(autoDelete)
|
||||
.startOf("day")
|
||||
.diff(moment().startOf("day"), "days");
|
||||
|
||||
if (daysRemaining <= 0) return "<1";
|
||||
return "" + daysRemaining;
|
||||
};
|
||||
|
@ -126,7 +126,7 @@ const AboutContent = (props) => {
|
||||
</div>
|
||||
|
||||
<div className="row">
|
||||
<Text className="row-el" fontSize="13px" noSelect>
|
||||
<Text className="row-el" fontSize="13px">
|
||||
{t("DocumentManagement")}:
|
||||
</Text>
|
||||
<ColorTheme
|
||||
@ -138,6 +138,7 @@ const AboutContent = (props) => {
|
||||
fontWeight="600"
|
||||
href={linkRepo}
|
||||
target="_blank"
|
||||
enableUserSelect
|
||||
>
|
||||
ONLYOFFICE DocSpace
|
||||
</ColorTheme>
|
||||
@ -148,7 +149,7 @@ const AboutContent = (props) => {
|
||||
</div>
|
||||
|
||||
<div className="row">
|
||||
<Text className="row-el" fontSize="13px" noSelect>
|
||||
<Text className="row-el" fontSize="13px">
|
||||
{t("OnlineEditors")}:
|
||||
</Text>
|
||||
<ColorTheme
|
||||
@ -160,6 +161,7 @@ const AboutContent = (props) => {
|
||||
fontWeight="600"
|
||||
href={linkDocs}
|
||||
target="_blank"
|
||||
enableUserSelect
|
||||
>
|
||||
ONLYOFFICE Docs
|
||||
</ColorTheme>
|
||||
@ -169,20 +171,20 @@ const AboutContent = (props) => {
|
||||
</div>
|
||||
|
||||
<div className="row">
|
||||
<Text className="row-el" fontSize="13px" noSelect>
|
||||
<Text className="row-el" fontSize="13px">
|
||||
{t("SoftwareLicense")}:{" "}
|
||||
</Text>
|
||||
<Text className="row-el" fontSize="13px" fontWeight="600" noSelect>
|
||||
<Text className="row-el" fontSize="13px" fontWeight="600">
|
||||
{license}
|
||||
</Text>
|
||||
</div>
|
||||
|
||||
<Text className="copyright" fontSize="14px" fontWeight="600" noSelect>
|
||||
<Text className="copyright" fontSize="14px" fontWeight="600">
|
||||
© {companyName}
|
||||
</Text>
|
||||
|
||||
<div className="row">
|
||||
<Text className="address-title" fontSize="13px" noSelect>
|
||||
<Text className="address-title" fontSize="13px">
|
||||
{t("AboutCompanyAddressTitle")}:{" "}
|
||||
</Text>
|
||||
<Text className="address-title select-el" fontSize="13px">
|
||||
@ -191,7 +193,7 @@ const AboutContent = (props) => {
|
||||
</div>
|
||||
|
||||
<div className="row">
|
||||
<Text className="tel-title" fontSize="13px" noSelect>
|
||||
<Text className="tel-title" fontSize="13px">
|
||||
{t("Common:Phone")}:{" "}
|
||||
</Text>
|
||||
<Text className="tel-title select-el" fontSize="13px">
|
||||
@ -200,7 +202,7 @@ const AboutContent = (props) => {
|
||||
</div>
|
||||
|
||||
<div className="row">
|
||||
<Text className="row-el" fontSize="13px" noSelect>
|
||||
<Text className="row-el" fontSize="13px">
|
||||
{t("AboutCompanyEmailTitle")}:
|
||||
</Text>
|
||||
|
||||
@ -212,13 +214,14 @@ const AboutContent = (props) => {
|
||||
fontSize="13px"
|
||||
fontWeight="600"
|
||||
href={`mailto:${companyInfoSettingsData.email}`}
|
||||
enableUserSelect
|
||||
>
|
||||
{email}
|
||||
</ColorTheme>
|
||||
</div>
|
||||
|
||||
<div className="row">
|
||||
<Text className="row-el" fontSize="13px" noSelect>
|
||||
<Text className="row-el" fontSize="13px">
|
||||
{t("Site")}:
|
||||
</Text>
|
||||
|
||||
@ -231,6 +234,7 @@ const AboutContent = (props) => {
|
||||
fontWeight="600"
|
||||
target="_blank"
|
||||
href={site}
|
||||
enableUserSelect
|
||||
>
|
||||
{site.replace(/^https?\:\/\//i, "")}
|
||||
</ColorTheme>
|
||||
|
@ -32,7 +32,6 @@ import { resendInvitesAgain } from "@docspace/common/api/people";
|
||||
const StyledContainer = styled.div`
|
||||
width: 100%;
|
||||
min-height: 33px;
|
||||
height: 69px;
|
||||
|
||||
.group-button-menu-container {
|
||||
margin: 0 0 0 -20px;
|
||||
@ -81,6 +80,7 @@ const StyledContainer = styled.div`
|
||||
|
||||
@media ${tablet} {
|
||||
grid-template-columns: 1fr auto;
|
||||
height: 60px;
|
||||
}
|
||||
|
||||
${isMobile &&
|
||||
|
@ -3,6 +3,7 @@ import styled, { css } from "styled-components";
|
||||
import { isIOS, isFirefox, isMobileOnly } from "react-device-detect";
|
||||
import { inject, observer } from "mobx-react";
|
||||
import { getBgPattern } from "@docspace/common/utils";
|
||||
import { hugeMobile } from "@docspace/components/utils/device";
|
||||
|
||||
const StyledWrapper = styled.div`
|
||||
height: ${isIOS && !isFirefox ? "calc(var(--vh, 1vh) * 100)" : "100vh"};
|
||||
@ -18,17 +19,21 @@ const StyledWrapper = styled.div`
|
||||
min-height: 100%;
|
||||
width: 100%;
|
||||
`}
|
||||
`;
|
||||
|
||||
const BgBlock = styled.div`
|
||||
background-image: ${(props) => props.bgPattern};
|
||||
background-repeat: no-repeat;
|
||||
background-attachment: fixed;
|
||||
background-size: 100% 100%;
|
||||
background-size: cover;
|
||||
position: fixed;
|
||||
top: 0;
|
||||
right: 0;
|
||||
left: 0;
|
||||
bottom: 0;
|
||||
z-index: -1;
|
||||
|
||||
@media (max-width: 1024px) {
|
||||
background-size: cover;
|
||||
}
|
||||
|
||||
@media (max-width: 428px) {
|
||||
@media ${hugeMobile} {
|
||||
background-image: none;
|
||||
}
|
||||
`;
|
||||
@ -37,7 +42,12 @@ const ConfirmWrapper = (props) => {
|
||||
const { children, currentColorScheme } = props;
|
||||
const bgPattern = getBgPattern(currentColorScheme?.id);
|
||||
|
||||
return <StyledWrapper bgPattern={bgPattern}>{children}</StyledWrapper>;
|
||||
return (
|
||||
<StyledWrapper>
|
||||
<BgBlock bgPattern={bgPattern} />
|
||||
{children}
|
||||
</StyledWrapper>
|
||||
);
|
||||
};
|
||||
|
||||
export default inject(({ auth }) => {
|
||||
|
@ -1,12 +1,13 @@
|
||||
import styled from "styled-components";
|
||||
import { mobile, tablet } from "@docspace/components/utils/device";
|
||||
import { hugeMobile, mobile, tablet } from "@docspace/components/utils/device";
|
||||
|
||||
export const StyledPage = styled.div`
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
margin: 56px auto 0 auto;
|
||||
margin: 0 auto;
|
||||
max-width: 960px;
|
||||
box-sizing: border-box;
|
||||
|
||||
@media ${tablet} {
|
||||
padding: 0 16px;
|
||||
@ -30,6 +31,23 @@ export const StyledPage = styled.div`
|
||||
}
|
||||
`;
|
||||
|
||||
export const StyledContent = styled.div`
|
||||
min-height: 100vh;
|
||||
flex: 1 0 auto;
|
||||
flex-direction: column;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
margin: 0 auto;
|
||||
-webkit-box-orient: vertical;
|
||||
-webkit-box-direction: normal;
|
||||
|
||||
@media ${hugeMobile} {
|
||||
justify-content: start;
|
||||
min-height: 100%;
|
||||
}
|
||||
`;
|
||||
|
||||
export const StyledHeader = styled.div`
|
||||
.title {
|
||||
margin-bottom: 32px;
|
||||
@ -44,7 +62,11 @@ export const StyledHeader = styled.div`
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding-bottom: 64px;
|
||||
padding-bottom: 40px;
|
||||
}
|
||||
|
||||
@media ${hugeMobile} {
|
||||
margin-top: 0;
|
||||
}
|
||||
`;
|
||||
|
||||
@ -52,9 +74,27 @@ export const StyledBody = styled.div`
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
margin: 56px auto;
|
||||
|
||||
@media ${mobile} {
|
||||
@media ${hugeMobile} {
|
||||
width: 100%;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
.title {
|
||||
margin-bottom: 32px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.subtitle {
|
||||
margin-bottom: 32px;
|
||||
}
|
||||
|
||||
.docspace-logo {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding-bottom: 40px;
|
||||
}
|
||||
|
||||
.password-field-wrapper {
|
||||
|
@ -5,7 +5,6 @@ import Text from "@docspace/components/text";
|
||||
import TextInput from "@docspace/components/text-input";
|
||||
import PasswordInput from "@docspace/components/password-input";
|
||||
import Button from "@docspace/components/button";
|
||||
import Section from "@docspace/common/components/Section";
|
||||
import FieldContainer from "@docspace/components/field-container";
|
||||
import { inject, observer } from "mobx-react";
|
||||
import { EmployeeActivationStatus } from "@docspace/common/constants";
|
||||
@ -16,7 +15,12 @@ import {
|
||||
} from "@docspace/common/api/people";
|
||||
import { createPasswordHash } from "@docspace/common/utils";
|
||||
import toastr from "@docspace/components/toast/toastr";
|
||||
import { StyledPage, StyledBody, StyledHeader } from "./StyledConfirm";
|
||||
import {
|
||||
StyledPage,
|
||||
StyledContent,
|
||||
StyledBody,
|
||||
StyledHeader,
|
||||
} from "./StyledConfirm";
|
||||
import withLoader from "../withLoader";
|
||||
import { getPasswordErrorMessage } from "SRC_DIR/helpers/utils";
|
||||
|
||||
@ -135,123 +139,115 @@ const ActivateUserForm = (props) => {
|
||||
|
||||
return (
|
||||
<StyledPage>
|
||||
<StyledBody>
|
||||
<StyledHeader>
|
||||
<Text fontSize="23px" fontWeight="700" className="title">
|
||||
{greetingTitle}
|
||||
</Text>
|
||||
<StyledContent>
|
||||
<StyledBody>
|
||||
<StyledHeader>
|
||||
<Text fontSize="23px" fontWeight="700" className="title">
|
||||
{greetingTitle}
|
||||
</Text>
|
||||
|
||||
<Text className="subtitle">{t("InviteTitle")}</Text>
|
||||
</StyledHeader>
|
||||
<Text className="subtitle">{t("InviteTitle")}</Text>
|
||||
</StyledHeader>
|
||||
|
||||
<FieldContainer
|
||||
className="form-field"
|
||||
isVertical={true}
|
||||
labelVisible={false}
|
||||
hasError={!nameValid}
|
||||
errorMessage={t("Common:RequiredField")}
|
||||
>
|
||||
<TextInput
|
||||
id="name"
|
||||
name="name"
|
||||
value={name}
|
||||
placeholder={t("Common:FirstName")}
|
||||
size="large"
|
||||
scale={true}
|
||||
tabIndex={1}
|
||||
isAutoFocussed={true}
|
||||
autoComplete="given-name"
|
||||
onChange={onChangeName}
|
||||
onKeyDown={onKeyPress}
|
||||
/>
|
||||
</FieldContainer>
|
||||
<FieldContainer
|
||||
className="form-field"
|
||||
isVertical={true}
|
||||
labelVisible={false}
|
||||
hasError={!nameValid}
|
||||
errorMessage={t("Common:RequiredField")}
|
||||
>
|
||||
<TextInput
|
||||
id="name"
|
||||
name="name"
|
||||
value={name}
|
||||
placeholder={t("Common:FirstName")}
|
||||
size="large"
|
||||
scale={true}
|
||||
tabIndex={1}
|
||||
isAutoFocussed={true}
|
||||
autoComplete="given-name"
|
||||
onChange={onChangeName}
|
||||
onKeyDown={onKeyPress}
|
||||
/>
|
||||
</FieldContainer>
|
||||
|
||||
<FieldContainer
|
||||
className="form-field"
|
||||
isVertical={true}
|
||||
labelVisible={false}
|
||||
hasError={!surNameValid}
|
||||
errorMessage={t("Common:RequiredField")}
|
||||
>
|
||||
<TextInput
|
||||
id="surname"
|
||||
name="surname"
|
||||
value={surName}
|
||||
placeholder={t("Common:LastName")}
|
||||
size="large"
|
||||
scale={true}
|
||||
tabIndex={2}
|
||||
autoComplete="family-name"
|
||||
onChange={onChangeSurName}
|
||||
onKeyDown={onKeyPress}
|
||||
/>
|
||||
</FieldContainer>
|
||||
<FieldContainer
|
||||
className="form-field"
|
||||
isVertical={true}
|
||||
labelVisible={false}
|
||||
hasError={!surNameValid}
|
||||
errorMessage={t("Common:RequiredField")}
|
||||
>
|
||||
<TextInput
|
||||
id="surname"
|
||||
name="surname"
|
||||
value={surName}
|
||||
placeholder={t("Common:LastName")}
|
||||
size="large"
|
||||
scale={true}
|
||||
tabIndex={2}
|
||||
autoComplete="family-name"
|
||||
onChange={onChangeSurName}
|
||||
onKeyDown={onKeyPress}
|
||||
/>
|
||||
</FieldContainer>
|
||||
|
||||
<FieldContainer
|
||||
className="form-field"
|
||||
isVertical={true}
|
||||
labelVisible={false}
|
||||
hasError={isPasswordErrorShow && !passwordValid}
|
||||
errorMessage={`${t(
|
||||
"Common:PasswordLimitMessage"
|
||||
)}: ${getPasswordErrorMessage(t, settings)}`}
|
||||
>
|
||||
<PasswordInput
|
||||
className="confirm-input"
|
||||
simpleView={false}
|
||||
passwordSettings={settings}
|
||||
id="password"
|
||||
inputName="password"
|
||||
placeholder={t("Common:Password")}
|
||||
type="password"
|
||||
inputValue={password}
|
||||
<FieldContainer
|
||||
className="form-field"
|
||||
isVertical={true}
|
||||
labelVisible={false}
|
||||
hasError={isPasswordErrorShow && !passwordValid}
|
||||
size="large"
|
||||
scale={true}
|
||||
tabIndex={1}
|
||||
autoComplete="current-password"
|
||||
onChange={onChangePassword}
|
||||
onValidateInput={onValidatePassword}
|
||||
onBlur={onBlurPassword}
|
||||
onKeyDown={onKeyPress}
|
||||
tooltipPasswordTitle={`${t("Common:PasswordLimitMessage")}:`}
|
||||
tooltipPasswordLength={`${t("Common:PasswordMinimumLength")}: ${
|
||||
settings ? settings.minLength : 8
|
||||
}`}
|
||||
tooltipPasswordDigits={`${t("Common:PasswordLimitDigits")}`}
|
||||
tooltipPasswordCapital={`${t("Common:PasswordLimitUpperCase")}`}
|
||||
tooltipPasswordSpecial={`${t(
|
||||
"Common:PasswordLimitSpecialSymbols"
|
||||
)}`}
|
||||
generatePasswordTitle={t("Wizard:GeneratePassword")}
|
||||
// If need copy credentials use t("EmailAndPasswordCopiedToClipboard")
|
||||
errorMessage={`${t(
|
||||
"Common:PasswordLimitMessage"
|
||||
)}: ${getPasswordErrorMessage(t, settings)}`}
|
||||
>
|
||||
<PasswordInput
|
||||
className="confirm-input"
|
||||
simpleView={false}
|
||||
passwordSettings={settings}
|
||||
id="password"
|
||||
inputName="password"
|
||||
placeholder={t("Common:Password")}
|
||||
type="password"
|
||||
inputValue={password}
|
||||
hasError={isPasswordErrorShow && !passwordValid}
|
||||
size="large"
|
||||
scale={true}
|
||||
tabIndex={1}
|
||||
autoComplete="current-password"
|
||||
onChange={onChangePassword}
|
||||
onValidateInput={onValidatePassword}
|
||||
onBlur={onBlurPassword}
|
||||
onKeyDown={onKeyPress}
|
||||
tooltipPasswordTitle={`${t("Common:PasswordLimitMessage")}:`}
|
||||
tooltipPasswordLength={`${t("Common:PasswordMinimumLength")}: ${
|
||||
settings ? settings.minLength : 8
|
||||
}`}
|
||||
tooltipPasswordDigits={`${t("Common:PasswordLimitDigits")}`}
|
||||
tooltipPasswordCapital={`${t("Common:PasswordLimitUpperCase")}`}
|
||||
tooltipPasswordSpecial={`${t(
|
||||
"Common:PasswordLimitSpecialSymbols"
|
||||
)}`}
|
||||
generatePasswordTitle={t("Wizard:GeneratePassword")}
|
||||
// If need copy credentials use t("EmailAndPasswordCopiedToClipboard")
|
||||
/>
|
||||
</FieldContainer>
|
||||
|
||||
<Button
|
||||
className="confirm-button"
|
||||
primary
|
||||
size="normal"
|
||||
label={t("LoginRegistryButton")}
|
||||
tabIndex={5}
|
||||
onClick={onSubmit}
|
||||
isDisabled={isLoading}
|
||||
/>
|
||||
</FieldContainer>
|
||||
|
||||
<Button
|
||||
className="confirm-button"
|
||||
primary
|
||||
size="normal"
|
||||
label={t("LoginRegistryButton")}
|
||||
tabIndex={5}
|
||||
onClick={onSubmit}
|
||||
isDisabled={isLoading}
|
||||
/>
|
||||
</StyledBody>
|
||||
</StyledBody>
|
||||
</StyledContent>
|
||||
</StyledPage>
|
||||
);
|
||||
};
|
||||
|
||||
const ActivateUserFormWrapper = (props) => {
|
||||
return (
|
||||
<Section>
|
||||
<Section.SectionBody>
|
||||
<ActivateUserForm {...props} />
|
||||
</Section.SectionBody>
|
||||
</Section>
|
||||
);
|
||||
};
|
||||
|
||||
export default inject(({ auth }) => {
|
||||
const {
|
||||
greetingSettings,
|
||||
@ -272,7 +268,7 @@ export default inject(({ auth }) => {
|
||||
})(
|
||||
withRouter(
|
||||
withTranslation(["Confirm", "Common", "Wizard"])(
|
||||
withLoader(observer(ActivateUserFormWrapper))
|
||||
withLoader(observer(ActivateUserForm))
|
||||
)
|
||||
)
|
||||
);
|
||||
|
@ -3,13 +3,12 @@ import { withRouter } from "react-router";
|
||||
import { withTranslation } from "react-i18next";
|
||||
import Text from "@docspace/components/text";
|
||||
import Button from "@docspace/components/button";
|
||||
import Section from "@docspace/common/components/Section";
|
||||
import { inject, observer } from "mobx-react";
|
||||
import {
|
||||
StyledPage,
|
||||
StyledBody,
|
||||
StyledHeader,
|
||||
ButtonsWrapper,
|
||||
StyledContent,
|
||||
} from "./StyledConfirm";
|
||||
import withLoader from "../withLoader";
|
||||
import FormWrapper from "@docspace/components/form-wrapper";
|
||||
@ -20,60 +19,50 @@ const ChangeOwnerForm = (props) => {
|
||||
console.log(props.linkData);
|
||||
return (
|
||||
<StyledPage>
|
||||
<StyledBody>
|
||||
<StyledHeader>
|
||||
<StyledContent>
|
||||
<StyledBody>
|
||||
<DocspaceLogo className="docspace-logo" />
|
||||
<Text fontSize="23px" fontWeight="700" className="title">
|
||||
{greetingTitle}
|
||||
</Text>
|
||||
</StyledHeader>
|
||||
|
||||
<FormWrapper>
|
||||
<Text className="subtitle">
|
||||
{t("ConfirmOwnerPortalTitle", { newOwner: "NEW OWNER" })}
|
||||
</Text>
|
||||
<ButtonsWrapper>
|
||||
<Button
|
||||
primary
|
||||
scale
|
||||
size="medium"
|
||||
label={t("Common:SaveButton")}
|
||||
tabIndex={2}
|
||||
isDisabled={false}
|
||||
//onClick={this.onAcceptClick} // call toast with t("ConfirmOwnerPortalSuccessMessage")
|
||||
/>
|
||||
<Button
|
||||
scale
|
||||
size="medium"
|
||||
label={t("Common:CancelButton")}
|
||||
tabIndex={2}
|
||||
isDisabled={false}
|
||||
//onClick={this.onCancelClick}
|
||||
/>
|
||||
</ButtonsWrapper>
|
||||
</FormWrapper>
|
||||
</StyledBody>
|
||||
<FormWrapper>
|
||||
<Text className="subtitle">
|
||||
{t("ConfirmOwnerPortalTitle", { newOwner: "NEW OWNER" })}
|
||||
</Text>
|
||||
<ButtonsWrapper>
|
||||
<Button
|
||||
primary
|
||||
scale
|
||||
size="medium"
|
||||
label={t("Common:SaveButton")}
|
||||
tabIndex={2}
|
||||
isDisabled={false}
|
||||
//onClick={this.onAcceptClick} // call toast with t("ConfirmOwnerPortalSuccessMessage")
|
||||
/>
|
||||
<Button
|
||||
scale
|
||||
size="medium"
|
||||
label={t("Common:CancelButton")}
|
||||
tabIndex={2}
|
||||
isDisabled={false}
|
||||
//onClick={this.onCancelClick}
|
||||
/>
|
||||
</ButtonsWrapper>
|
||||
</FormWrapper>
|
||||
</StyledBody>
|
||||
</StyledContent>
|
||||
</StyledPage>
|
||||
);
|
||||
};
|
||||
|
||||
const ChangeOwnerFormWrapper = (props) => {
|
||||
return (
|
||||
<Section>
|
||||
<Section.SectionBody>
|
||||
<ChangeOwnerForm {...props} />
|
||||
</Section.SectionBody>
|
||||
</Section>
|
||||
);
|
||||
};
|
||||
|
||||
export default inject(({ auth }) => ({
|
||||
greetingTitle: auth.settingsStore.greetingSettings,
|
||||
defaultPage: auth.settingsStore.defaultPage,
|
||||
}))(
|
||||
withRouter(
|
||||
withTranslation(["Confirm", "Common"])(
|
||||
withLoader(observer(ChangeOwnerFormWrapper))
|
||||
withLoader(observer(ChangeOwnerForm))
|
||||
)
|
||||
)
|
||||
);
|
||||
|
@ -1,13 +1,12 @@
|
||||
import React, { useState } from "react";
|
||||
import React, { useState, useEffect } from "react";
|
||||
import { withRouter } from "react-router";
|
||||
import { withTranslation } from "react-i18next";
|
||||
import Text from "@docspace/components/text";
|
||||
import PasswordInput from "@docspace/components/password-input";
|
||||
import Button from "@docspace/components/button";
|
||||
import Section from "@docspace/common/components/Section";
|
||||
import FieldContainer from "@docspace/components/field-container";
|
||||
import { inject, observer } from "mobx-react";
|
||||
import { StyledPage, StyledBody, StyledHeader } from "./StyledConfirm";
|
||||
import { StyledPage, StyledBody, StyledContent } from "./StyledConfirm";
|
||||
import withLoader from "../withLoader";
|
||||
import { getPasswordErrorMessage } from "../../../helpers/utils";
|
||||
import { createPasswordHash } from "@docspace/common/utils";
|
||||
@ -26,6 +25,7 @@ const ChangePasswordForm = (props) => {
|
||||
logout,
|
||||
changePassword,
|
||||
linkData,
|
||||
getSettings,
|
||||
} = props;
|
||||
|
||||
const [password, setPassword] = useState("");
|
||||
@ -33,6 +33,10 @@ const ChangePasswordForm = (props) => {
|
||||
const [isPasswordErrorShow, setIsPasswordErrorShow] = useState(false);
|
||||
const [isLoading, setIsLoading] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
if (!hashSettings) getSettings(true);
|
||||
}, []);
|
||||
|
||||
const onChangePassword = (e) => {
|
||||
setPassword(e.target.value);
|
||||
};
|
||||
@ -45,7 +49,7 @@ const ChangePasswordForm = (props) => {
|
||||
setIsPasswordErrorShow(true);
|
||||
};
|
||||
|
||||
const onSubmit = () => {
|
||||
const onSubmit = async () => {
|
||||
setIsLoading(true);
|
||||
|
||||
if (!password.trim()) {
|
||||
@ -57,30 +61,34 @@ const ChangePasswordForm = (props) => {
|
||||
return;
|
||||
}
|
||||
|
||||
const hash = createPasswordHash(password, hashSettings);
|
||||
const { uid, confirmHeader } = linkData;
|
||||
changePassword(uid, hash, confirmHeader)
|
||||
.then(() => logout())
|
||||
.then(() => {
|
||||
setIsLoading(false);
|
||||
toastr.success(t("ChangePasswordSuccess"));
|
||||
tryRedirectTo(defaultPage);
|
||||
})
|
||||
.catch((error) => {
|
||||
let errorMessage = "";
|
||||
if (typeof error === "object") {
|
||||
errorMessage =
|
||||
error?.response?.data?.error?.message ||
|
||||
error?.statusText ||
|
||||
error?.message ||
|
||||
"";
|
||||
} else {
|
||||
errorMessage = error;
|
||||
}
|
||||
try {
|
||||
const hash = createPasswordHash(password, hashSettings);
|
||||
const { uid, confirmHeader } = linkData;
|
||||
await changePassword(uid, hash, confirmHeader);
|
||||
logout();
|
||||
setIsLoading(false);
|
||||
toastr.success(t("ChangePasswordSuccess"));
|
||||
tryRedirectTo(defaultPage);
|
||||
} catch (error) {
|
||||
let errorMessage = "";
|
||||
if (typeof error === "object") {
|
||||
errorMessage =
|
||||
error?.response?.data?.error?.message ||
|
||||
error?.statusText ||
|
||||
error?.message ||
|
||||
"";
|
||||
} else {
|
||||
errorMessage = error;
|
||||
}
|
||||
console.error(errorMessage);
|
||||
|
||||
if (errorMessage === "Invalid params") {
|
||||
toastr.error(t("Common:SomethingWentWrong"));
|
||||
} else {
|
||||
toastr.error(t(`${errorMessage}`));
|
||||
setIsLoading(false);
|
||||
});
|
||||
}
|
||||
setIsLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
const onKeyPress = (event) => {
|
||||
@ -91,83 +99,75 @@ const ChangePasswordForm = (props) => {
|
||||
|
||||
return (
|
||||
<StyledPage>
|
||||
<StyledBody>
|
||||
<StyledHeader>
|
||||
<StyledContent>
|
||||
<StyledBody>
|
||||
<DocspaceLogo className="docspace-logo" />
|
||||
<Text fontSize="23px" fontWeight="700" className="title">
|
||||
{greetingTitle}
|
||||
</Text>
|
||||
</StyledHeader>
|
||||
|
||||
<FormWrapper>
|
||||
<div className="password-form">
|
||||
<Text fontSize="16px" fontWeight="600" className="subtitle">
|
||||
{t("PassworResetTitle")}
|
||||
</Text>
|
||||
<FieldContainer
|
||||
isVertical={true}
|
||||
labelVisible={false}
|
||||
hasError={isPasswordErrorShow && !passwordValid}
|
||||
errorMessage={`${t(
|
||||
"Common:PasswordLimitMessage"
|
||||
)}: ${getPasswordErrorMessage(t, settings)}`}
|
||||
>
|
||||
<PasswordInput
|
||||
simpleView={false}
|
||||
passwordSettings={settings}
|
||||
id="password"
|
||||
inputName="password"
|
||||
placeholder={t("Common:Password")}
|
||||
type="password"
|
||||
inputValue={password}
|
||||
<FormWrapper>
|
||||
<div className="password-form">
|
||||
<Text fontSize="16px" fontWeight="600" className="subtitle">
|
||||
{t("PassworResetTitle")}
|
||||
</Text>
|
||||
<FieldContainer
|
||||
isVertical={true}
|
||||
labelVisible={false}
|
||||
hasError={isPasswordErrorShow && !passwordValid}
|
||||
size="large"
|
||||
scale
|
||||
tabIndex={1}
|
||||
autoComplete="current-password"
|
||||
onChange={onChangePassword}
|
||||
onValidateInput={onValidatePassword}
|
||||
onBlur={onBlurPassword}
|
||||
onKeyDown={onKeyPress}
|
||||
tooltipPasswordTitle={`${t("Common:PasswordLimitMessage")}:`}
|
||||
tooltipPasswordLength={`${t("Common:PasswordMinimumLength")}: ${
|
||||
settings ? settings.minLength : 8
|
||||
}`}
|
||||
tooltipPasswordDigits={`${t("Common:PasswordLimitDigits")}`}
|
||||
tooltipPasswordCapital={`${t("Common:PasswordLimitUpperCase")}`}
|
||||
tooltipPasswordSpecial={`${t(
|
||||
"Common:PasswordLimitSpecialSymbols"
|
||||
)}`}
|
||||
generatePasswordTitle={t("Wizard:GeneratePassword")}
|
||||
/>
|
||||
</FieldContainer>
|
||||
</div>
|
||||
errorMessage={`${t(
|
||||
"Common:PasswordLimitMessage"
|
||||
)}: ${getPasswordErrorMessage(t, settings)}`}
|
||||
>
|
||||
<PasswordInput
|
||||
simpleView={false}
|
||||
passwordSettings={settings}
|
||||
id="password"
|
||||
inputName="password"
|
||||
placeholder={t("Common:Password")}
|
||||
type="password"
|
||||
inputValue={password}
|
||||
hasError={isPasswordErrorShow && !passwordValid}
|
||||
size="large"
|
||||
scale
|
||||
tabIndex={1}
|
||||
autoComplete="current-password"
|
||||
onChange={onChangePassword}
|
||||
onValidateInput={onValidatePassword}
|
||||
onBlur={onBlurPassword}
|
||||
onKeyDown={onKeyPress}
|
||||
tooltipPasswordTitle={`${t("Common:PasswordLimitMessage")}:`}
|
||||
tooltipPasswordLength={`${t(
|
||||
"Common:PasswordMinimumLength"
|
||||
)}: ${settings ? settings.minLength : 8}`}
|
||||
tooltipPasswordDigits={`${t("Common:PasswordLimitDigits")}`}
|
||||
tooltipPasswordCapital={`${t(
|
||||
"Common:PasswordLimitUpperCase"
|
||||
)}`}
|
||||
tooltipPasswordSpecial={`${t(
|
||||
"Common:PasswordLimitSpecialSymbols"
|
||||
)}`}
|
||||
generatePasswordTitle={t("Wizard:GeneratePassword")}
|
||||
/>
|
||||
</FieldContainer>
|
||||
</div>
|
||||
|
||||
<Button
|
||||
primary
|
||||
size="medium"
|
||||
scale
|
||||
label={t("Common:Create")}
|
||||
tabIndex={5}
|
||||
onClick={onSubmit}
|
||||
isDisabled={isLoading}
|
||||
/>
|
||||
</FormWrapper>
|
||||
</StyledBody>
|
||||
<Button
|
||||
primary
|
||||
size="medium"
|
||||
scale
|
||||
label={t("Common:Create")}
|
||||
tabIndex={5}
|
||||
onClick={onSubmit}
|
||||
isDisabled={isLoading}
|
||||
/>
|
||||
</FormWrapper>
|
||||
</StyledBody>
|
||||
</StyledContent>
|
||||
</StyledPage>
|
||||
);
|
||||
};
|
||||
|
||||
const ChangePasswordFormWrapper = (props) => {
|
||||
return (
|
||||
<Section>
|
||||
<Section.SectionBody>
|
||||
<ChangePasswordForm {...props} />
|
||||
</Section.SectionBody>
|
||||
</Section>
|
||||
);
|
||||
};
|
||||
|
||||
export default inject(({ auth, setup }) => {
|
||||
const {
|
||||
greetingSettings,
|
||||
@ -175,6 +175,7 @@ export default inject(({ auth, setup }) => {
|
||||
defaultPage,
|
||||
passwordSettings,
|
||||
theme,
|
||||
getSettings,
|
||||
} = auth.settingsStore;
|
||||
const { changePassword } = setup;
|
||||
|
||||
@ -187,11 +188,12 @@ export default inject(({ auth, setup }) => {
|
||||
logout: auth.logout,
|
||||
changePassword,
|
||||
isAuthenticated: auth.isAuthenticated,
|
||||
getSettings,
|
||||
};
|
||||
})(
|
||||
withRouter(
|
||||
withTranslation(["Confirm", "Common", "Wizard"])(
|
||||
withLoader(observer(ChangePasswordFormWrapper))
|
||||
withLoader(observer(ChangePasswordForm))
|
||||
)
|
||||
)
|
||||
);
|
||||
|
@ -4,9 +4,8 @@ import { withTranslation } from "react-i18next";
|
||||
import Text from "@docspace/components/text";
|
||||
import TextInput from "@docspace/components/text-input";
|
||||
import Button from "@docspace/components/button";
|
||||
import Section from "@docspace/common/components/Section";
|
||||
import { inject, observer } from "mobx-react";
|
||||
import { StyledPage, StyledBody, StyledHeader } from "./StyledConfirm";
|
||||
import { StyledPage, StyledBody, StyledContent } from "./StyledConfirm";
|
||||
import withLoader from "../withLoader";
|
||||
import FormWrapper from "@docspace/components/form-wrapper";
|
||||
import DocspaceLogo from "../../../DocspaceLogo";
|
||||
@ -17,66 +16,54 @@ const ChangePhoneForm = (props) => {
|
||||
|
||||
return (
|
||||
<StyledPage>
|
||||
<StyledBody>
|
||||
<StyledHeader>
|
||||
<StyledContent>
|
||||
<StyledBody>
|
||||
<DocspaceLogo className="docspace-logo" />
|
||||
<Text fontSize="23px" fontWeight="700" className="title">
|
||||
{greetingTitle}
|
||||
</Text>
|
||||
</StyledHeader>
|
||||
|
||||
<FormWrapper>
|
||||
<div className="subtitle">
|
||||
<Text fontSize="16px" fontWeight="600" className="phone-title">
|
||||
{t("EnterPhone")}
|
||||
</Text>
|
||||
<Text>
|
||||
{t("CurrentNumber")}: {currentNumber}
|
||||
</Text>
|
||||
<Text>{t("PhoneSubtitle")}</Text>
|
||||
</div>
|
||||
<FormWrapper>
|
||||
<div className="subtitle">
|
||||
<Text fontSize="16px" fontWeight="600" className="phone-title">
|
||||
{t("EnterPhone")}
|
||||
</Text>
|
||||
<Text>
|
||||
{t("CurrentNumber")}: {currentNumber}
|
||||
</Text>
|
||||
<Text>{t("PhoneSubtitle")}</Text>
|
||||
</div>
|
||||
|
||||
<TextInput
|
||||
className="phone-input"
|
||||
id="phone"
|
||||
name="phone"
|
||||
type="phone"
|
||||
size="large"
|
||||
scale={true}
|
||||
isAutoFocussed={true}
|
||||
tabIndex={1}
|
||||
hasError={false}
|
||||
guide={false}
|
||||
/>
|
||||
<TextInput
|
||||
className="phone-input"
|
||||
id="phone"
|
||||
name="phone"
|
||||
type="phone"
|
||||
size="large"
|
||||
scale={true}
|
||||
isAutoFocussed={true}
|
||||
tabIndex={1}
|
||||
hasError={false}
|
||||
guide={false}
|
||||
/>
|
||||
|
||||
<Button
|
||||
primary
|
||||
scale
|
||||
size="medium"
|
||||
label={t("GetCode")}
|
||||
tabIndex={2}
|
||||
isDisabled={false}
|
||||
/>
|
||||
</FormWrapper>
|
||||
</StyledBody>
|
||||
<Button
|
||||
primary
|
||||
scale
|
||||
size="medium"
|
||||
label={t("GetCode")}
|
||||
tabIndex={2}
|
||||
isDisabled={false}
|
||||
/>
|
||||
</FormWrapper>
|
||||
</StyledBody>
|
||||
</StyledContent>
|
||||
</StyledPage>
|
||||
);
|
||||
};
|
||||
|
||||
const ChangePhoneFormWrapper = (props) => {
|
||||
return (
|
||||
<Section>
|
||||
<Section.SectionBody>
|
||||
<ChangePhoneForm {...props} />
|
||||
</Section.SectionBody>
|
||||
</Section>
|
||||
);
|
||||
};
|
||||
|
||||
export default inject(({ auth }) => ({
|
||||
greetingTitle: auth.settingsStore.greetingSettings,
|
||||
}))(
|
||||
withRouter(
|
||||
withTranslation("Confirm")(withLoader(observer(ChangePhoneFormWrapper)))
|
||||
)
|
||||
withRouter(withTranslation("Confirm")(withLoader(observer(ChangePhoneForm))))
|
||||
);
|
||||
|
@ -2,7 +2,6 @@ import React, { useState } from "react";
|
||||
import { withRouter } from "react-router";
|
||||
import { Trans, withTranslation } from "react-i18next";
|
||||
import { inject, observer } from "mobx-react";
|
||||
import Section from "@docspace/common/components/Section";
|
||||
import Text from "@docspace/components/text";
|
||||
import Button from "@docspace/components/button";
|
||||
import Link from "@docspace/components/link";
|
||||
@ -11,7 +10,7 @@ import { continuePortal } from "@docspace/common/api/portal";
|
||||
import {
|
||||
StyledPage,
|
||||
StyledBody,
|
||||
StyledHeader,
|
||||
StyledContent,
|
||||
ButtonsWrapper,
|
||||
} from "./StyledConfirm";
|
||||
|
||||
@ -40,68 +39,56 @@ const ContinuePortal = (props) => {
|
||||
|
||||
return (
|
||||
<StyledPage>
|
||||
<StyledBody>
|
||||
<StyledHeader>
|
||||
<StyledContent>
|
||||
<StyledBody>
|
||||
<DocspaceLogo className="docspace-logo" />
|
||||
<Text fontSize="23px" fontWeight="700" className="title">
|
||||
{greetingTitle}
|
||||
</Text>
|
||||
</StyledHeader>
|
||||
|
||||
<FormWrapper>
|
||||
{isReactivate ? (
|
||||
<Trans t={t} i18nKey="SuccessReactivate" ns="Confirm">
|
||||
Your account has been successfully reactivated. In 10 seconds you
|
||||
will be redirected to the
|
||||
<Link isHovered href="/">
|
||||
portal
|
||||
</Link>
|
||||
</Trans>
|
||||
) : (
|
||||
<>
|
||||
<Text className="subtitle">{t("PortalContinueTitle")}</Text>
|
||||
<ButtonsWrapper>
|
||||
<Button
|
||||
primary
|
||||
scale
|
||||
size="medium"
|
||||
label={t("Reactivate")}
|
||||
tabIndex={1}
|
||||
onClick={onRestoreClick}
|
||||
/>
|
||||
<Button
|
||||
scale
|
||||
size="medium"
|
||||
label={t("Common:CancelButton")}
|
||||
tabIndex={1}
|
||||
onClick={onCancelClick}
|
||||
/>
|
||||
</ButtonsWrapper>
|
||||
</>
|
||||
)}
|
||||
</FormWrapper>
|
||||
</StyledBody>
|
||||
<FormWrapper>
|
||||
{isReactivate ? (
|
||||
<Trans t={t} i18nKey="SuccessReactivate" ns="Confirm">
|
||||
Your account has been successfully reactivated. In 10 seconds
|
||||
you will be redirected to the
|
||||
<Link isHovered href="/">
|
||||
portal
|
||||
</Link>
|
||||
</Trans>
|
||||
) : (
|
||||
<>
|
||||
<Text className="subtitle">{t("PortalContinueTitle")}</Text>
|
||||
<ButtonsWrapper>
|
||||
<Button
|
||||
primary
|
||||
scale
|
||||
size="medium"
|
||||
label={t("Reactivate")}
|
||||
tabIndex={1}
|
||||
onClick={onRestoreClick}
|
||||
/>
|
||||
<Button
|
||||
scale
|
||||
size="medium"
|
||||
label={t("Common:CancelButton")}
|
||||
tabIndex={1}
|
||||
onClick={onCancelClick}
|
||||
/>
|
||||
</ButtonsWrapper>
|
||||
</>
|
||||
)}
|
||||
</FormWrapper>
|
||||
</StyledBody>
|
||||
</StyledContent>
|
||||
</StyledPage>
|
||||
);
|
||||
};
|
||||
|
||||
const ContinuePortalWrapper = (props) => {
|
||||
return (
|
||||
<Section>
|
||||
<Section.SectionBody>
|
||||
<ContinuePortal {...props} />
|
||||
</Section.SectionBody>
|
||||
</Section>
|
||||
);
|
||||
};
|
||||
|
||||
export default inject(({ auth }) => ({
|
||||
greetingTitle: auth.settingsStore.greetingSettings,
|
||||
theme: auth.settingsStore.theme,
|
||||
}))(
|
||||
withRouter(
|
||||
withTranslation(["Confirm", "Common"])(
|
||||
withLoader(observer(ContinuePortalWrapper))
|
||||
)
|
||||
withTranslation(["Confirm", "Common"])(withLoader(observer(ContinuePortal)))
|
||||
)
|
||||
);
|
||||
|
@ -16,7 +16,6 @@ import FieldContainer from "@docspace/components/field-container";
|
||||
import toastr from "@docspace/components/toast/toastr";
|
||||
import SocialButton from "@docspace/components/social-button";
|
||||
import { getUserFromConfirm } from "@docspace/common/api/people";
|
||||
import Section from "@docspace/common/components/Section";
|
||||
import {
|
||||
createPasswordHash,
|
||||
getProviderTranslation,
|
||||
@ -33,6 +32,7 @@ import FormWrapper from "@docspace/components/form-wrapper";
|
||||
import DocspaceLogo from "../../../DocspaceLogo";
|
||||
import Box from "@docspace/components/box";
|
||||
import DefaultUserPhoto from "PUBLIC_DIR/images/default_user_photo_size_82-82.png";
|
||||
import { StyledPage, StyledContent } from "./StyledConfirm";
|
||||
|
||||
export const ButtonsWrapper = styled.div`
|
||||
display: flex;
|
||||
@ -46,7 +46,7 @@ export const ButtonsWrapper = styled.div`
|
||||
`;
|
||||
|
||||
const ConfirmContainer = styled(Box)`
|
||||
margin-top: 80px;
|
||||
margin: 56px auto;
|
||||
display: flex;
|
||||
flex: 1fr 1fr;
|
||||
gap: 80px;
|
||||
@ -54,7 +54,6 @@ const ConfirmContainer = styled(Box)`
|
||||
justify-content: center;
|
||||
|
||||
@media ${tablet} {
|
||||
margin: 100px auto 0 auto;
|
||||
display: flex;
|
||||
flex: 1fr;
|
||||
flex-direction: column;
|
||||
@ -63,7 +62,7 @@ const ConfirmContainer = styled(Box)`
|
||||
}
|
||||
|
||||
@media ${hugeMobile} {
|
||||
margin-top: 32px;
|
||||
margin: 0 auto;
|
||||
width: 100%;
|
||||
flex: 1fr;
|
||||
flex-direction: column;
|
||||
@ -132,6 +131,7 @@ const GreetingContainer = styled.div`
|
||||
}
|
||||
|
||||
.docspace-logo {
|
||||
width: 100%;
|
||||
padding-bottom: 32px;
|
||||
|
||||
.injected-svg {
|
||||
@ -142,7 +142,7 @@ const GreetingContainer = styled.div`
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding-bottom: 64px;
|
||||
padding-bottom: 40px;
|
||||
}
|
||||
}
|
||||
`;
|
||||
@ -187,12 +187,12 @@ const RegisterContainer = styled.div`
|
||||
//margin-top: 32px;
|
||||
width: 100%;
|
||||
|
||||
@media (max-width: 768px) {
|
||||
margin: 32px 0 0 0;
|
||||
@media ${tablet} {
|
||||
//margin: 32px 0 0 0;
|
||||
width: 100%;
|
||||
}
|
||||
@media (max-width: 375px) {
|
||||
margin: 32px 0 0 0;
|
||||
@media ${hugeMobile} {
|
||||
//margin: 32px 0 0 0;
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
@ -211,10 +211,9 @@ const RegisterContainer = styled.div`
|
||||
.password-field-wrapper {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
`;
|
||||
}`;
|
||||
|
||||
const Confirm = (props) => {
|
||||
const CreateUserForm = (props) => {
|
||||
const { settings, t, greetingTitle, providers, isDesktop, linkData } = props;
|
||||
const inputRef = React.useRef(null);
|
||||
|
||||
@ -553,233 +552,238 @@ const Confirm = (props) => {
|
||||
const userAvatar = user.hasAvatar ? user.avatar : DefaultUserPhoto;
|
||||
|
||||
return (
|
||||
<ConfirmContainer>
|
||||
<GreetingContainer isGreetingMode={isGreetingMode}>
|
||||
<DocspaceLogo className="docspace-logo" />
|
||||
<Text
|
||||
fontSize="23px"
|
||||
fontWeight={700}
|
||||
textAlign="left"
|
||||
className="greeting-title"
|
||||
>
|
||||
{greetingTitle}
|
||||
</Text>
|
||||
|
||||
<div className="greeting-block">
|
||||
<Avatar className="avatar" role="user" source={user.avatar} />
|
||||
<div className="user-info">
|
||||
<Text fontSize="15px" fontWeight={600}>
|
||||
{user.firstName} {user.lastName}
|
||||
<StyledPage>
|
||||
<StyledContent>
|
||||
<ConfirmContainer>
|
||||
<GreetingContainer isGreetingMode={isGreetingMode}>
|
||||
<DocspaceLogo className="docspace-logo" />
|
||||
<Text
|
||||
fontSize="23px"
|
||||
fontWeight={700}
|
||||
textAlign="left"
|
||||
className="greeting-title"
|
||||
>
|
||||
{greetingTitle}
|
||||
</Text>
|
||||
<Text fontSize="12px" fontWeight={600} color="#A3A9AE">
|
||||
{user.department}
|
||||
</Text>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="tooltip">
|
||||
<span className="tooltiptext">{t("WelcomeUser")}</span>
|
||||
</div>
|
||||
</GreetingContainer>
|
||||
<div className="greeting-block">
|
||||
<Avatar className="avatar" role="user" source={user.avatar} />
|
||||
<div className="user-info">
|
||||
<Text fontSize="15px" fontWeight={600}>
|
||||
{user.firstName} {user.lastName}
|
||||
</Text>
|
||||
<Text fontSize="12px" fontWeight={600} color="#A3A9AE">
|
||||
{user.department}
|
||||
</Text>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<FormWrapper>
|
||||
<RegisterContainer isGreetingMode={isGreetingMode}>
|
||||
{ssoExists() && <ButtonsWrapper>{ssoButton()}</ButtonsWrapper>}
|
||||
<div className="tooltip">
|
||||
<span className="tooltiptext">{t("WelcomeUser")}</span>
|
||||
</div>
|
||||
</GreetingContainer>
|
||||
|
||||
{oauthDataExists() && (
|
||||
<>
|
||||
<ButtonsWrapper>{providerButtons()}</ButtonsWrapper>
|
||||
{providers && providers.length > 2 && (
|
||||
<Link
|
||||
isHovered
|
||||
type="action"
|
||||
fontSize="13px"
|
||||
fontWeight="600"
|
||||
color="#3B72A7"
|
||||
className="more-label"
|
||||
onClick={moreAuthOpen}
|
||||
>
|
||||
{t("Common:ShowMore")}
|
||||
</Link>
|
||||
<FormWrapper>
|
||||
<RegisterContainer isGreetingMode={isGreetingMode}>
|
||||
{ssoExists() && <ButtonsWrapper>{ssoButton()}</ButtonsWrapper>}
|
||||
|
||||
{oauthDataExists() && (
|
||||
<>
|
||||
<ButtonsWrapper>{providerButtons()}</ButtonsWrapper>
|
||||
{providers && providers.length > 2 && (
|
||||
<Link
|
||||
isHovered
|
||||
type="action"
|
||||
fontSize="13px"
|
||||
fontWeight="600"
|
||||
color="#3B72A7"
|
||||
className="more-label"
|
||||
onClick={moreAuthOpen}
|
||||
>
|
||||
{t("Common:ShowMore")}
|
||||
</Link>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
|
||||
{(oauthDataExists() || ssoExists()) && (
|
||||
<div className="line">
|
||||
<Text color="#A3A9AE" className="or-label">
|
||||
{t("Common:Or")}
|
||||
</Text>
|
||||
</div>
|
||||
)}
|
||||
{(oauthDataExists() || ssoExists()) && (
|
||||
<div className="line">
|
||||
<Text color="#A3A9AE" className="or-label">
|
||||
{t("Common:Or")}
|
||||
</Text>
|
||||
</div>
|
||||
)}
|
||||
|
||||
<form className="auth-form-container">
|
||||
<div className="auth-form-fields">
|
||||
<FieldContainer
|
||||
className="form-field"
|
||||
isVertical={true}
|
||||
labelVisible={false}
|
||||
hasError={isEmailErrorShow && !emailValid}
|
||||
errorMessage={
|
||||
emailErrorText
|
||||
? t(`Common:${emailErrorText}`)
|
||||
: t("Common:RequiredField")
|
||||
}
|
||||
>
|
||||
<EmailInput
|
||||
id="login"
|
||||
name="login"
|
||||
type="email"
|
||||
hasError={isEmailErrorShow && !emailValid}
|
||||
value={email}
|
||||
placeholder={t("Common:Email")}
|
||||
size="large"
|
||||
scale={true}
|
||||
isAutoFocussed={true}
|
||||
tabIndex={1}
|
||||
isDisabled={isLoading || !!emailFromLink}
|
||||
autoComplete="username"
|
||||
onChange={onChangeEmail}
|
||||
onBlur={onBlurEmail}
|
||||
onValidateInput={onValidateEmail}
|
||||
forwardedRef={inputRef}
|
||||
/>
|
||||
</FieldContainer>
|
||||
<form className="auth-form-container">
|
||||
<div className="auth-form-fields">
|
||||
<FieldContainer
|
||||
className="form-field"
|
||||
isVertical={true}
|
||||
labelVisible={false}
|
||||
hasError={isEmailErrorShow && !emailValid}
|
||||
errorMessage={
|
||||
emailErrorText
|
||||
? t(`Common:${emailErrorText}`)
|
||||
: t("Common:RequiredField")
|
||||
}
|
||||
>
|
||||
<EmailInput
|
||||
id="login"
|
||||
name="login"
|
||||
type="email"
|
||||
hasError={isEmailErrorShow && !emailValid}
|
||||
value={email}
|
||||
placeholder={t("Common:Email")}
|
||||
size="large"
|
||||
scale={true}
|
||||
isAutoFocussed={true}
|
||||
tabIndex={1}
|
||||
isDisabled={isLoading || !!emailFromLink}
|
||||
autoComplete="username"
|
||||
onChange={onChangeEmail}
|
||||
onBlur={onBlurEmail}
|
||||
onValidateInput={onValidateEmail}
|
||||
forwardedRef={inputRef}
|
||||
/>
|
||||
</FieldContainer>
|
||||
|
||||
<FieldContainer
|
||||
className="form-field"
|
||||
isVertical={true}
|
||||
labelVisible={false}
|
||||
hasError={!fnameValid}
|
||||
errorMessage={errorText ? errorText : t("Common:RequiredField")}
|
||||
>
|
||||
<TextInput
|
||||
id="first-name"
|
||||
name="first-name"
|
||||
type="text"
|
||||
hasError={!fnameValid}
|
||||
value={fname}
|
||||
placeholder={t("Common:FirstName")}
|
||||
size="large"
|
||||
scale={true}
|
||||
tabIndex={1}
|
||||
isDisabled={isLoading}
|
||||
onChange={onChangeFname}
|
||||
onKeyDown={onKeyPress}
|
||||
/>
|
||||
</FieldContainer>
|
||||
<FieldContainer
|
||||
className="form-field"
|
||||
isVertical={true}
|
||||
labelVisible={false}
|
||||
hasError={!fnameValid}
|
||||
errorMessage={
|
||||
errorText ? errorText : t("Common:RequiredField")
|
||||
}
|
||||
>
|
||||
<TextInput
|
||||
id="first-name"
|
||||
name="first-name"
|
||||
type="text"
|
||||
hasError={!fnameValid}
|
||||
value={fname}
|
||||
placeholder={t("Common:FirstName")}
|
||||
size="large"
|
||||
scale={true}
|
||||
tabIndex={1}
|
||||
isDisabled={isLoading}
|
||||
onChange={onChangeFname}
|
||||
onKeyDown={onKeyPress}
|
||||
/>
|
||||
</FieldContainer>
|
||||
|
||||
<FieldContainer
|
||||
className="form-field"
|
||||
isVertical={true}
|
||||
labelVisible={false}
|
||||
hasError={!snameValid}
|
||||
errorMessage={errorText ? errorText : t("Common:RequiredField")}
|
||||
>
|
||||
<TextInput
|
||||
id="last-name"
|
||||
name="last-name"
|
||||
type="text"
|
||||
hasError={!snameValid}
|
||||
value={sname}
|
||||
placeholder={t("Common:LastName")}
|
||||
size="large"
|
||||
scale={true}
|
||||
tabIndex={1}
|
||||
isDisabled={isLoading}
|
||||
onChange={onChangeSname}
|
||||
onKeyDown={onKeyPress}
|
||||
/>
|
||||
</FieldContainer>
|
||||
<FieldContainer
|
||||
className="form-field"
|
||||
isVertical={true}
|
||||
labelVisible={false}
|
||||
hasError={!snameValid}
|
||||
errorMessage={
|
||||
errorText ? errorText : t("Common:RequiredField")
|
||||
}
|
||||
>
|
||||
<TextInput
|
||||
id="last-name"
|
||||
name="last-name"
|
||||
type="text"
|
||||
hasError={!snameValid}
|
||||
value={sname}
|
||||
placeholder={t("Common:LastName")}
|
||||
size="large"
|
||||
scale={true}
|
||||
tabIndex={1}
|
||||
isDisabled={isLoading}
|
||||
onChange={onChangeSname}
|
||||
onKeyDown={onKeyPress}
|
||||
/>
|
||||
</FieldContainer>
|
||||
|
||||
<FieldContainer
|
||||
className="form-field"
|
||||
isVertical={true}
|
||||
labelVisible={false}
|
||||
hasError={isPasswordErrorShow && !passwordValid}
|
||||
errorMessage={`${t(
|
||||
"Common:PasswordLimitMessage"
|
||||
)}: ${getPasswordErrorMessage(t, settings)}`}
|
||||
>
|
||||
<PasswordInput
|
||||
simpleView={false}
|
||||
hideNewPasswordButton
|
||||
showCopyLink={false}
|
||||
passwordSettings={settings}
|
||||
id="password"
|
||||
inputName="password"
|
||||
placeholder={t("Common:Password")}
|
||||
type="password"
|
||||
hasError={isPasswordErrorShow && !passwordValid}
|
||||
inputValue={password}
|
||||
size="large"
|
||||
scale={true}
|
||||
tabIndex={1}
|
||||
isDisabled={isLoading}
|
||||
autoComplete="current-password"
|
||||
onChange={onChangePassword}
|
||||
onBlur={onBlurPassword}
|
||||
onKeyDown={onKeyPress}
|
||||
onValidateInput={onValidatePassword}
|
||||
tooltipPasswordTitle={`${t("Common:PasswordLimitMessage")}:`}
|
||||
tooltipPasswordLength={`${t(
|
||||
"Common:PasswordMinimumLength"
|
||||
)}: ${settings ? settings.minLength : 8}`}
|
||||
tooltipPasswordDigits={`${t("Common:PasswordLimitDigits")}`}
|
||||
tooltipPasswordCapital={`${t(
|
||||
"Common:PasswordLimitUpperCase"
|
||||
)}`}
|
||||
tooltipPasswordSpecial={`${t(
|
||||
"Common:PasswordLimitSpecialSymbols"
|
||||
)}`}
|
||||
generatePasswordTitle={t("Wizard:GeneratePassword")}
|
||||
/>
|
||||
</FieldContainer>
|
||||
<FieldContainer
|
||||
className="form-field"
|
||||
isVertical={true}
|
||||
labelVisible={false}
|
||||
hasError={isPasswordErrorShow && !passwordValid}
|
||||
errorMessage={`${t(
|
||||
"Common:PasswordLimitMessage"
|
||||
)}: ${getPasswordErrorMessage(t, settings)}`}
|
||||
>
|
||||
<PasswordInput
|
||||
simpleView={false}
|
||||
hideNewPasswordButton
|
||||
showCopyLink={false}
|
||||
passwordSettings={settings}
|
||||
id="password"
|
||||
inputName="password"
|
||||
placeholder={t("Common:Password")}
|
||||
type="password"
|
||||
hasError={isPasswordErrorShow && !passwordValid}
|
||||
inputValue={password}
|
||||
size="large"
|
||||
scale={true}
|
||||
tabIndex={1}
|
||||
isDisabled={isLoading}
|
||||
autoComplete="current-password"
|
||||
onChange={onChangePassword}
|
||||
onBlur={onBlurPassword}
|
||||
onKeyDown={onKeyPress}
|
||||
onValidateInput={onValidatePassword}
|
||||
tooltipPasswordTitle={`${t(
|
||||
"Common:PasswordLimitMessage"
|
||||
)}:`}
|
||||
tooltipPasswordLength={`${t(
|
||||
"Common:PasswordMinimumLength"
|
||||
)}: ${settings ? settings.minLength : 8}`}
|
||||
tooltipPasswordDigits={`${t(
|
||||
"Common:PasswordLimitDigits"
|
||||
)}`}
|
||||
tooltipPasswordCapital={`${t(
|
||||
"Common:PasswordLimitUpperCase"
|
||||
)}`}
|
||||
tooltipPasswordSpecial={`${t(
|
||||
"Common:PasswordLimitSpecialSymbols"
|
||||
)}`}
|
||||
generatePasswordTitle={t("Wizard:GeneratePassword")}
|
||||
/>
|
||||
</FieldContainer>
|
||||
|
||||
<Button
|
||||
className="login-button"
|
||||
primary
|
||||
size="medium"
|
||||
scale={true}
|
||||
label={
|
||||
isLoading
|
||||
? t("Common:LoadingProcessing")
|
||||
: t("LoginRegistryButton")
|
||||
}
|
||||
tabIndex={1}
|
||||
isDisabled={isLoading}
|
||||
isLoading={isLoading}
|
||||
onClick={onSubmit}
|
||||
<Button
|
||||
className="login-button"
|
||||
primary
|
||||
size="medium"
|
||||
scale={true}
|
||||
label={
|
||||
isLoading
|
||||
? t("Common:LoadingProcessing")
|
||||
: t("LoginRegistryButton")
|
||||
}
|
||||
tabIndex={1}
|
||||
isDisabled={isLoading}
|
||||
isLoading={isLoading}
|
||||
onClick={onSubmit}
|
||||
/>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
<MoreLoginModal
|
||||
t={t}
|
||||
visible={moreAuthVisible}
|
||||
onClose={moreAuthClose}
|
||||
providers={providers}
|
||||
onSocialLoginClick={onSocialButtonClick}
|
||||
ssoLabel={ssoLabel}
|
||||
ssoUrl={ssoUrl}
|
||||
/>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
<MoreLoginModal
|
||||
t={t}
|
||||
visible={moreAuthVisible}
|
||||
onClose={moreAuthClose}
|
||||
providers={providers}
|
||||
onSocialLoginClick={onSocialButtonClick}
|
||||
ssoLabel={ssoLabel}
|
||||
ssoUrl={ssoUrl}
|
||||
/>
|
||||
</RegisterContainer>
|
||||
</FormWrapper>
|
||||
</ConfirmContainer>
|
||||
</RegisterContainer>
|
||||
</FormWrapper>
|
||||
</ConfirmContainer>
|
||||
</StyledContent>
|
||||
</StyledPage>
|
||||
);
|
||||
};
|
||||
|
||||
Confirm.propTypes = {
|
||||
CreateUserForm.propTypes = {
|
||||
location: PropTypes.object.isRequired,
|
||||
history: PropTypes.object.isRequired,
|
||||
};
|
||||
const CreateUserForm = (props) => (
|
||||
<Section>
|
||||
<Section.SectionBody>
|
||||
<Confirm {...props} />
|
||||
</Section.SectionBody>
|
||||
</Section>
|
||||
);
|
||||
|
||||
export default inject(({ auth }) => {
|
||||
const {
|
||||
|
@ -2,7 +2,6 @@ import React, { useState } from "react";
|
||||
import { withRouter } from "react-router";
|
||||
import { Trans, withTranslation } from "react-i18next";
|
||||
import { inject, observer } from "mobx-react";
|
||||
import Section from "@docspace/common/components/Section";
|
||||
import Text from "@docspace/components/text";
|
||||
import Button from "@docspace/components/button";
|
||||
import Link from "@docspace/components/link";
|
||||
@ -11,7 +10,7 @@ import { suspendPortal } from "@docspace/common/api/portal";
|
||||
import {
|
||||
StyledPage,
|
||||
StyledBody,
|
||||
StyledHeader,
|
||||
StyledContent,
|
||||
ButtonsWrapper,
|
||||
} from "./StyledConfirm";
|
||||
|
||||
@ -50,61 +49,51 @@ const DeactivatePortal = (props) => {
|
||||
|
||||
return (
|
||||
<StyledPage>
|
||||
<StyledBody>
|
||||
<StyledHeader>
|
||||
<StyledContent>
|
||||
<StyledBody>
|
||||
<DocspaceLogo className="docspace-logo" />
|
||||
<Text fontSize="23px" fontWeight="700" className="title">
|
||||
{greetingTitle}
|
||||
</Text>
|
||||
</StyledHeader>
|
||||
|
||||
<FormWrapper>
|
||||
{isDeactivate ? (
|
||||
<Trans t={t} i18nKey="SuccessDeactivate" ns="Confirm">
|
||||
Your account has been successfully deactivated. In 10 seconds you
|
||||
will be redirected to the
|
||||
<Link isHovered href={url}>
|
||||
site
|
||||
</Link>
|
||||
</Trans>
|
||||
) : (
|
||||
<>
|
||||
<Text className="subtitle">{t("PortalDeactivateTitle")}</Text>
|
||||
<ButtonsWrapper>
|
||||
<Button
|
||||
scale
|
||||
primary
|
||||
size="medium"
|
||||
label={t("Settings:Deactivate")}
|
||||
tabIndex={1}
|
||||
onClick={onDeactivateClick}
|
||||
/>
|
||||
<Button
|
||||
scale
|
||||
size="medium"
|
||||
label={t("Common:CancelButton")}
|
||||
tabIndex={1}
|
||||
onClick={onCancelClick}
|
||||
/>
|
||||
</ButtonsWrapper>
|
||||
</>
|
||||
)}
|
||||
</FormWrapper>
|
||||
</StyledBody>
|
||||
<FormWrapper>
|
||||
{isDeactivate ? (
|
||||
<Trans t={t} i18nKey="SuccessDeactivate" ns="Confirm">
|
||||
Your account has been successfully deactivated. In 10 seconds
|
||||
you will be redirected to the
|
||||
<Link isHovered href={url}>
|
||||
site
|
||||
</Link>
|
||||
</Trans>
|
||||
) : (
|
||||
<>
|
||||
<Text className="subtitle">{t("PortalDeactivateTitle")}</Text>
|
||||
<ButtonsWrapper>
|
||||
<Button
|
||||
scale
|
||||
primary
|
||||
size="medium"
|
||||
label={t("Settings:Deactivate")}
|
||||
tabIndex={1}
|
||||
onClick={onDeactivateClick}
|
||||
/>
|
||||
<Button
|
||||
scale
|
||||
size="medium"
|
||||
label={t("Common:CancelButton")}
|
||||
tabIndex={1}
|
||||
onClick={onCancelClick}
|
||||
/>
|
||||
</ButtonsWrapper>
|
||||
</>
|
||||
)}
|
||||
</FormWrapper>
|
||||
</StyledBody>
|
||||
</StyledContent>
|
||||
</StyledPage>
|
||||
);
|
||||
};
|
||||
|
||||
const DeactivatePortalWrapper = (props) => {
|
||||
return (
|
||||
<Section>
|
||||
<Section.SectionBody>
|
||||
<DeactivatePortal {...props} />
|
||||
</Section.SectionBody>
|
||||
</Section>
|
||||
);
|
||||
};
|
||||
|
||||
export default inject(({ auth }) => ({
|
||||
greetingTitle: auth.settingsStore.greetingSettings,
|
||||
theme: auth.settingsStore.theme,
|
||||
@ -112,7 +101,7 @@ export default inject(({ auth }) => ({
|
||||
}))(
|
||||
withRouter(
|
||||
withTranslation(["Confirm", "Settings", "Common"])(
|
||||
withLoader(observer(DeactivatePortalWrapper))
|
||||
withLoader(observer(DeactivatePortal))
|
||||
)
|
||||
)
|
||||
);
|
||||
|
@ -7,7 +7,7 @@ import Section from "@docspace/common/components/Section";
|
||||
import { inject, observer } from "mobx-react";
|
||||
import { deleteSelf } from "@docspace/common/api/people";
|
||||
import toastr from "@docspace/components/toast/toastr";
|
||||
import { StyledPage, StyledBody, StyledHeader } from "./StyledConfirm";
|
||||
import { StyledPage, StyledBody, StyledContent } from "./StyledConfirm";
|
||||
import withLoader from "../withLoader";
|
||||
import FormWrapper from "@docspace/components/form-wrapper";
|
||||
import DocspaceLogo from "../../../DocspaceLogo";
|
||||
@ -35,8 +35,8 @@ const ProfileRemoveForm = (props) => {
|
||||
if (isProfileDeleted) {
|
||||
return (
|
||||
<StyledPage>
|
||||
<StyledBody>
|
||||
<StyledHeader>
|
||||
<StyledContent>
|
||||
<StyledBody>
|
||||
<DocspaceLogo className="docspace-logo" />
|
||||
<Text fontSize="23px" fontWeight="700" className="title">
|
||||
{t("DeleteProfileSuccessMessage")}
|
||||
@ -44,65 +44,55 @@ const ProfileRemoveForm = (props) => {
|
||||
<Text fontSize="16px" fontWeight="600" className="confirm-subtitle">
|
||||
{t("DeleteProfileSuccessMessageInfo")}
|
||||
</Text>
|
||||
</StyledHeader>
|
||||
</StyledBody>
|
||||
</StyledBody>
|
||||
</StyledContent>
|
||||
</StyledPage>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<StyledPage>
|
||||
<StyledBody>
|
||||
<StyledHeader>
|
||||
<StyledContent>
|
||||
<StyledBody>
|
||||
<DocspaceLogo className="docspace-logo" />
|
||||
<Text fontSize="23px" fontWeight="700" className="title">
|
||||
{greetingTitle}
|
||||
</Text>
|
||||
</StyledHeader>
|
||||
|
||||
<FormWrapper>
|
||||
<div className="subtitle">
|
||||
<Text
|
||||
fontSize="16px"
|
||||
fontWeight="600"
|
||||
className="delete-profile-confirm"
|
||||
>
|
||||
{t("DeleteProfileConfirmation")}
|
||||
</Text>
|
||||
<Text>{t("DeleteProfileConfirmationInfo")}</Text>
|
||||
</div>
|
||||
<FormWrapper>
|
||||
<div className="subtitle">
|
||||
<Text
|
||||
fontSize="16px"
|
||||
fontWeight="600"
|
||||
className="delete-profile-confirm"
|
||||
>
|
||||
{t("DeleteProfileConfirmation")}
|
||||
</Text>
|
||||
<Text>{t("DeleteProfileConfirmationInfo")}</Text>
|
||||
</div>
|
||||
|
||||
<Button
|
||||
primary
|
||||
scale
|
||||
size="medium"
|
||||
label={t("DeleteProfileBtn")}
|
||||
tabIndex={1}
|
||||
isDisabled={isLoading}
|
||||
onClick={onDeleteProfile}
|
||||
/>
|
||||
</FormWrapper>
|
||||
</StyledBody>
|
||||
<Button
|
||||
primary
|
||||
scale
|
||||
size="medium"
|
||||
label={t("DeleteProfileBtn")}
|
||||
tabIndex={1}
|
||||
isDisabled={isLoading}
|
||||
onClick={onDeleteProfile}
|
||||
/>
|
||||
</FormWrapper>
|
||||
</StyledBody>
|
||||
</StyledContent>
|
||||
</StyledPage>
|
||||
);
|
||||
};
|
||||
|
||||
const ProfileRemoveFormWrapper = (props) => {
|
||||
return (
|
||||
<Section>
|
||||
<Section.SectionBody>
|
||||
<ProfileRemoveForm {...props} />
|
||||
</Section.SectionBody>
|
||||
</Section>
|
||||
);
|
||||
};
|
||||
|
||||
export default inject(({ auth }) => ({
|
||||
greetingTitle: auth.settingsStore.greetingSettings,
|
||||
theme: auth.settingsStore.theme,
|
||||
logout: auth.logout,
|
||||
}))(
|
||||
withRouter(
|
||||
withTranslation("Confirm")(withLoader(observer(ProfileRemoveFormWrapper)))
|
||||
withTranslation("Confirm")(withLoader(observer(ProfileRemoveForm)))
|
||||
)
|
||||
);
|
||||
|
@ -2,7 +2,6 @@ import React, { useState } from "react";
|
||||
import { withRouter } from "react-router";
|
||||
import { withTranslation } from "react-i18next";
|
||||
import { inject, observer } from "mobx-react";
|
||||
import Section from "@docspace/common/components/Section";
|
||||
import Text from "@docspace/components/text";
|
||||
import Button from "@docspace/components/button";
|
||||
import toastr from "@docspace/components/toast/toastr";
|
||||
@ -10,7 +9,7 @@ import { deletePortal } from "@docspace/common/api/portal";
|
||||
import {
|
||||
StyledPage,
|
||||
StyledBody,
|
||||
StyledHeader,
|
||||
StyledContent,
|
||||
ButtonsWrapper,
|
||||
} from "./StyledConfirm";
|
||||
|
||||
@ -36,56 +35,44 @@ const RemovePortal = (props) => {
|
||||
|
||||
return (
|
||||
<StyledPage>
|
||||
<StyledBody>
|
||||
<StyledHeader>
|
||||
<StyledContent>
|
||||
<StyledBody>
|
||||
<DocspaceLogo className="docspace-logo" />
|
||||
<Text fontSize="23px" fontWeight="700" className="title">
|
||||
{greetingTitle}
|
||||
</Text>
|
||||
</StyledHeader>
|
||||
|
||||
<FormWrapper>
|
||||
<Text className="subtitle">{t("PortalRemoveTitle")}</Text>
|
||||
<ButtonsWrapper>
|
||||
<Button
|
||||
primary
|
||||
scale
|
||||
size="medium"
|
||||
label={t("Common:Delete")}
|
||||
tabIndex={1}
|
||||
onClick={onDeleteClick}
|
||||
/>
|
||||
<Button
|
||||
scale
|
||||
size="medium"
|
||||
label={t("Common:CancelButton")}
|
||||
tabIndex={1}
|
||||
onClick={onCancelClick}
|
||||
/>
|
||||
</ButtonsWrapper>
|
||||
</FormWrapper>
|
||||
</StyledBody>
|
||||
<FormWrapper>
|
||||
<Text className="subtitle">{t("PortalRemoveTitle")}</Text>
|
||||
<ButtonsWrapper>
|
||||
<Button
|
||||
primary
|
||||
scale
|
||||
size="medium"
|
||||
label={t("Common:Delete")}
|
||||
tabIndex={1}
|
||||
onClick={onDeleteClick}
|
||||
/>
|
||||
<Button
|
||||
scale
|
||||
size="medium"
|
||||
label={t("Common:CancelButton")}
|
||||
tabIndex={1}
|
||||
onClick={onCancelClick}
|
||||
/>
|
||||
</ButtonsWrapper>
|
||||
</FormWrapper>
|
||||
</StyledBody>
|
||||
</StyledContent>
|
||||
</StyledPage>
|
||||
);
|
||||
};
|
||||
|
||||
const RemovePortalWrapper = (props) => {
|
||||
return (
|
||||
<Section>
|
||||
<Section.SectionBody>
|
||||
<RemovePortal {...props} />
|
||||
</Section.SectionBody>
|
||||
</Section>
|
||||
);
|
||||
};
|
||||
|
||||
export default inject(({ auth }) => ({
|
||||
greetingTitle: auth.settingsStore.greetingSettings,
|
||||
theme: auth.settingsStore.theme,
|
||||
}))(
|
||||
withRouter(
|
||||
withTranslation(["Confirm", "Common"])(
|
||||
withLoader(observer(RemovePortalWrapper))
|
||||
)
|
||||
withTranslation(["Confirm", "Common"])(withLoader(observer(RemovePortal)))
|
||||
)
|
||||
);
|
||||
|
@ -6,7 +6,6 @@ import Button from "@docspace/components/button";
|
||||
import TextInput from "@docspace/components/text-input";
|
||||
import FieldContainer from "@docspace/components/field-container";
|
||||
import Text from "@docspace/components/text";
|
||||
import Section from "@docspace/common/components/Section";
|
||||
import { inject, observer } from "mobx-react";
|
||||
import Box from "@docspace/components/box";
|
||||
import withLoader from "../withLoader";
|
||||
@ -16,9 +15,10 @@ import { hugeMobile, tablet } from "@docspace/components/utils/device";
|
||||
import Link from "@docspace/components/link";
|
||||
import FormWrapper from "@docspace/components/form-wrapper";
|
||||
import DocspaceLogo from "../../../DocspaceLogo";
|
||||
import { StyledPage, StyledContent } from "./StyledConfirm";
|
||||
|
||||
const StyledForm = styled(Box)`
|
||||
margin-top: 63px;
|
||||
margin: 56px auto;
|
||||
display: flex;
|
||||
flex: 1fr 1fr;
|
||||
gap: 80px;
|
||||
@ -26,18 +26,14 @@ const StyledForm = styled(Box)`
|
||||
justify-content: center;
|
||||
|
||||
@media ${tablet} {
|
||||
margin: 100px auto 0 auto;
|
||||
display: flex;
|
||||
flex: 1fr;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
gap: 32px;
|
||||
}
|
||||
|
||||
@media ${hugeMobile} {
|
||||
margin-top: 32px;
|
||||
width: 100%;
|
||||
flex: 1fr;
|
||||
margin: 0 auto;
|
||||
flex-direction: column;
|
||||
gap: 0px;
|
||||
padding-right: 8px;
|
||||
@ -52,7 +48,7 @@ const StyledForm = styled(Box)`
|
||||
}
|
||||
|
||||
.docspace-logo {
|
||||
padding-bottom: 64px;
|
||||
padding-bottom: 40px;
|
||||
|
||||
@media ${tablet} {
|
||||
display: flex;
|
||||
@ -142,97 +138,109 @@ const TfaActivationForm = withLoader((props) => {
|
||||
};
|
||||
|
||||
return (
|
||||
<StyledForm className="set-app-container">
|
||||
<Box className="set-app-description" marginProp="0 0 32px 0">
|
||||
<DocspaceLogo className="docspace-logo" />
|
||||
<Text isBold fontSize="14px" className="set-app-title">
|
||||
{t("SetAppTitle")}
|
||||
</Text>
|
||||
<StyledPage>
|
||||
<StyledContent>
|
||||
<StyledForm className="set-app-container">
|
||||
<Box className="set-app-description" marginProp="0 0 32px 0">
|
||||
<DocspaceLogo className="docspace-logo" />
|
||||
<Text isBold fontSize="14px" className="set-app-title">
|
||||
{t("SetAppTitle")}
|
||||
</Text>
|
||||
|
||||
<Trans t={t} i18nKey="SetAppDescription" ns="Confirm">
|
||||
The two-factor authentication is enabled to provide additional portal
|
||||
security. Configure your authenticator application to continue work on
|
||||
the portal. For example you could use Google Authenticator for
|
||||
<Link isHovered href={props.tfaAndroidAppUrl} target="_blank">
|
||||
Android
|
||||
</Link>
|
||||
and{" "}
|
||||
<Link isHovered href={props.tfaIosAppUrl} target="_blank">
|
||||
iOS
|
||||
</Link>{" "}
|
||||
or Authenticator for{" "}
|
||||
<Link isHovered href={props.tfaWinAppUrl} target="_blank">
|
||||
Windows Phone
|
||||
</Link>{" "}
|
||||
.
|
||||
</Trans>
|
||||
<Trans t={t} i18nKey="SetAppDescription" ns="Confirm">
|
||||
The two-factor authentication is enabled to provide additional
|
||||
portal security. Configure your authenticator application to
|
||||
continue work on the portal. For example you could use Google
|
||||
Authenticator for
|
||||
<Link isHovered href={props.tfaAndroidAppUrl} target="_blank">
|
||||
Android
|
||||
</Link>
|
||||
and{" "}
|
||||
<Link isHovered href={props.tfaIosAppUrl} target="_blank">
|
||||
iOS
|
||||
</Link>{" "}
|
||||
or Authenticator for{" "}
|
||||
<Link isHovered href={props.tfaWinAppUrl} target="_blank">
|
||||
Windows Phone
|
||||
</Link>{" "}
|
||||
.
|
||||
</Trans>
|
||||
|
||||
<Text className="set-app-text">
|
||||
<Trans
|
||||
t={t}
|
||||
i18nKey="SetAppInstallDescription"
|
||||
ns="Confirm"
|
||||
key={secretKey}
|
||||
>
|
||||
To connect your apllication scan the QR code or manually enter your
|
||||
secret key <strong>{{ secretKey }}</strong> then enter 6-digit code
|
||||
from your application in the field below.
|
||||
</Trans>
|
||||
</Text>
|
||||
</Box>
|
||||
<FormWrapper>
|
||||
<Box
|
||||
displayProp="flex"
|
||||
flexDirection="column"
|
||||
className="app-code-wrapper"
|
||||
>
|
||||
<div className="qrcode-wrapper">
|
||||
<img src={qrCode} height="180px" width="180px" alt="QR-code"></img>
|
||||
</div>
|
||||
<Box className="app-code-input">
|
||||
<FieldContainer
|
||||
labelVisible={false}
|
||||
hasError={error ? true : false}
|
||||
errorMessage={error}
|
||||
<Text className="set-app-text">
|
||||
<Trans
|
||||
t={t}
|
||||
i18nKey="SetAppInstallDescription"
|
||||
ns="Confirm"
|
||||
key={secretKey}
|
||||
>
|
||||
To connect your apllication scan the QR code or manually enter
|
||||
your secret key <strong>{{ secretKey }}</strong> then enter
|
||||
6-digit code from your application in the field below.
|
||||
</Trans>
|
||||
</Text>
|
||||
</Box>
|
||||
<FormWrapper>
|
||||
<Box
|
||||
displayProp="flex"
|
||||
flexDirection="column"
|
||||
className="app-code-wrapper"
|
||||
>
|
||||
<TextInput
|
||||
id="code"
|
||||
name="code"
|
||||
type="text"
|
||||
size="large"
|
||||
scale
|
||||
isAutoFocussed
|
||||
tabIndex={1}
|
||||
placeholder={t("EnterCodePlaceholder")}
|
||||
isDisabled={isLoading}
|
||||
maxLength={6}
|
||||
onChange={(e) => {
|
||||
setCode(e.target.value);
|
||||
setError("");
|
||||
}}
|
||||
value={code}
|
||||
hasError={error ? true : false}
|
||||
onKeyDown={onKeyPress}
|
||||
/>
|
||||
</FieldContainer>
|
||||
</Box>
|
||||
<Box className="app-code-continue-btn">
|
||||
<Button
|
||||
scale
|
||||
primary
|
||||
size="medium"
|
||||
tabIndex={3}
|
||||
label={
|
||||
isLoading ? t("Common:LoadingProcessing") : t("SetAppButton")
|
||||
}
|
||||
isDisabled={!code.length || isLoading}
|
||||
isLoading={isLoading}
|
||||
onClick={onSubmit}
|
||||
/>
|
||||
</Box>
|
||||
</Box>
|
||||
</FormWrapper>
|
||||
</StyledForm>
|
||||
<div className="qrcode-wrapper">
|
||||
<img
|
||||
src={qrCode}
|
||||
height="180px"
|
||||
width="180px"
|
||||
alt="QR-code"
|
||||
></img>
|
||||
</div>
|
||||
<Box className="app-code-input">
|
||||
<FieldContainer
|
||||
labelVisible={false}
|
||||
hasError={error ? true : false}
|
||||
errorMessage={error}
|
||||
>
|
||||
<TextInput
|
||||
id="code"
|
||||
name="code"
|
||||
type="text"
|
||||
size="large"
|
||||
scale
|
||||
isAutoFocussed
|
||||
tabIndex={1}
|
||||
placeholder={t("EnterCodePlaceholder")}
|
||||
isDisabled={isLoading}
|
||||
maxLength={6}
|
||||
onChange={(e) => {
|
||||
setCode(e.target.value);
|
||||
setError("");
|
||||
}}
|
||||
value={code}
|
||||
hasError={error ? true : false}
|
||||
onKeyDown={onKeyPress}
|
||||
/>
|
||||
</FieldContainer>
|
||||
</Box>
|
||||
<Box className="app-code-continue-btn">
|
||||
<Button
|
||||
scale
|
||||
primary
|
||||
size="medium"
|
||||
tabIndex={3}
|
||||
label={
|
||||
isLoading
|
||||
? t("Common:LoadingProcessing")
|
||||
: t("SetAppButton")
|
||||
}
|
||||
isDisabled={!code.length || isLoading}
|
||||
isLoading={isLoading}
|
||||
onClick={onSubmit}
|
||||
/>
|
||||
</Box>
|
||||
</Box>
|
||||
</FormWrapper>
|
||||
</StyledForm>
|
||||
</StyledContent>
|
||||
</StyledPage>
|
||||
);
|
||||
});
|
||||
|
||||
@ -264,11 +272,7 @@ const TfaActivationWrapper = (props) => {
|
||||
return error ? (
|
||||
<ErrorContainer bodyText={error} />
|
||||
) : (
|
||||
<Section>
|
||||
<Section.SectionBody>
|
||||
<TfaActivationForm secretKey={secretKey} qrCode={qrCode} {...props} />
|
||||
</Section.SectionBody>
|
||||
</Section>
|
||||
<TfaActivationForm secretKey={secretKey} qrCode={qrCode} {...props} />
|
||||
);
|
||||
};
|
||||
|
||||
|
@ -6,46 +6,32 @@ import Button from "@docspace/components/button";
|
||||
import TextInput from "@docspace/components/text-input";
|
||||
import FieldContainer from "@docspace/components/field-container";
|
||||
import Text from "@docspace/components/text";
|
||||
import Section from "@docspace/common/components/Section";
|
||||
import { inject, observer } from "mobx-react";
|
||||
import Box from "@docspace/components/box";
|
||||
import toastr from "@docspace/components/toast/toastr";
|
||||
import withLoader from "../withLoader";
|
||||
import {
|
||||
hugeMobile,
|
||||
smallTablet,
|
||||
tablet,
|
||||
} from "@docspace/components/utils/device";
|
||||
import { hugeMobile } from "@docspace/components/utils/device";
|
||||
import FormWrapper from "@docspace/components/form-wrapper";
|
||||
import DocspaceLogo from "../../../DocspaceLogo";
|
||||
import { StyledPage, StyledContent } from "./StyledConfirm";
|
||||
|
||||
const StyledForm = styled(Box)`
|
||||
margin: 63px auto;
|
||||
width: 320px;
|
||||
margin: 56px auto;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
flex: 1fr;
|
||||
|
||||
@media ${tablet} {
|
||||
margin: 120px auto;
|
||||
width: 480px;
|
||||
}
|
||||
|
||||
@media ${smallTablet} {
|
||||
width: 400px;
|
||||
}
|
||||
|
||||
@media ${hugeMobile} {
|
||||
margin: 32px 8px auto 8px;
|
||||
padding-left: 8px;
|
||||
margin: 0 auto;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.docspace-logo {
|
||||
width: 100%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding-bottom: 64px;
|
||||
padding-bottom: 40px;
|
||||
}
|
||||
|
||||
.app-code-wrapper {
|
||||
@ -94,66 +80,70 @@ const TfaAuthForm = withLoader((props) => {
|
||||
};
|
||||
|
||||
return (
|
||||
<StyledForm className="app-code-container">
|
||||
<DocspaceLogo className="docspace-logo" />
|
||||
<FormWrapper>
|
||||
<Box className="app-code-description" marginProp="0 0 32px 0">
|
||||
<Text isBold fontSize="14px" className="app-code-text">
|
||||
{t("EnterAppCodeTitle")}
|
||||
</Text>
|
||||
<Text>{t("EnterAppCodeDescription")}</Text>
|
||||
</Box>
|
||||
<Box
|
||||
displayProp="flex"
|
||||
flexDirection="column"
|
||||
className="app-code-wrapper"
|
||||
>
|
||||
<Box className="app-code-input">
|
||||
<FieldContainer
|
||||
labelVisible={false}
|
||||
hasError={error ? true : false}
|
||||
errorMessage={error}
|
||||
<StyledPage>
|
||||
<StyledContent>
|
||||
<StyledForm className="app-code-container">
|
||||
<DocspaceLogo className="docspace-logo" />
|
||||
<FormWrapper>
|
||||
<Box className="app-code-description" marginProp="0 0 32px 0">
|
||||
<Text isBold fontSize="14px" className="app-code-text">
|
||||
{t("EnterAppCodeTitle")}
|
||||
</Text>
|
||||
<Text>{t("EnterAppCodeDescription")}</Text>
|
||||
</Box>
|
||||
<Box
|
||||
displayProp="flex"
|
||||
flexDirection="column"
|
||||
className="app-code-wrapper"
|
||||
>
|
||||
<TextInput
|
||||
id="code"
|
||||
name="code"
|
||||
type="text"
|
||||
size="huge"
|
||||
scale
|
||||
isAutoFocussed
|
||||
tabIndex={1}
|
||||
placeholder={t("EnterCodePlaceholder")}
|
||||
isDisabled={isLoading}
|
||||
maxLength={6}
|
||||
onChange={(e) => {
|
||||
setCode(e.target.value);
|
||||
setError("");
|
||||
}}
|
||||
value={code}
|
||||
hasError={error ? true : false}
|
||||
onKeyDown={onKeyPress}
|
||||
/>
|
||||
</FieldContainer>
|
||||
</Box>
|
||||
<Box className="app-code-continue-btn">
|
||||
<Button
|
||||
scale
|
||||
primary
|
||||
size="medium"
|
||||
tabIndex={3}
|
||||
label={
|
||||
isLoading
|
||||
? t("Common:LoadingProcessing")
|
||||
: t("Common:ContinueButton")
|
||||
}
|
||||
isDisabled={!code.length || isLoading}
|
||||
isLoading={isLoading}
|
||||
onClick={onSubmit}
|
||||
/>
|
||||
</Box>
|
||||
</Box>
|
||||
</FormWrapper>
|
||||
</StyledForm>
|
||||
<Box className="app-code-input">
|
||||
<FieldContainer
|
||||
labelVisible={false}
|
||||
hasError={error ? true : false}
|
||||
errorMessage={error}
|
||||
>
|
||||
<TextInput
|
||||
id="code"
|
||||
name="code"
|
||||
type="text"
|
||||
size="huge"
|
||||
scale
|
||||
isAutoFocussed
|
||||
tabIndex={1}
|
||||
placeholder={t("EnterCodePlaceholder")}
|
||||
isDisabled={isLoading}
|
||||
maxLength={6}
|
||||
onChange={(e) => {
|
||||
setCode(e.target.value);
|
||||
setError("");
|
||||
}}
|
||||
value={code}
|
||||
hasError={error ? true : false}
|
||||
onKeyDown={onKeyPress}
|
||||
/>
|
||||
</FieldContainer>
|
||||
</Box>
|
||||
<Box className="app-code-continue-btn">
|
||||
<Button
|
||||
scale
|
||||
primary
|
||||
size="medium"
|
||||
tabIndex={3}
|
||||
label={
|
||||
isLoading
|
||||
? t("Common:LoadingProcessing")
|
||||
: t("Common:ContinueButton")
|
||||
}
|
||||
isDisabled={!code.length || isLoading}
|
||||
isLoading={isLoading}
|
||||
onClick={onSubmit}
|
||||
/>
|
||||
</Box>
|
||||
</Box>
|
||||
</FormWrapper>
|
||||
</StyledForm>
|
||||
</StyledContent>
|
||||
</StyledPage>
|
||||
);
|
||||
});
|
||||
|
||||
@ -165,13 +155,7 @@ const TfaAuthFormWrapper = (props) => {
|
||||
setIsLoading(false);
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<Section>
|
||||
<Section.SectionBody>
|
||||
<TfaAuthForm {...props} />
|
||||
</Section.SectionBody>
|
||||
</Section>
|
||||
);
|
||||
return <TfaAuthForm {...props} />;
|
||||
};
|
||||
|
||||
export default inject(({ auth, confirm }) => ({
|
||||
|
@ -212,10 +212,6 @@ const paddingCss = css`
|
||||
@media ${desktop} {
|
||||
padding-right: 3px;
|
||||
}
|
||||
|
||||
@media ${tablet} {
|
||||
margin-left: -1px;
|
||||
}
|
||||
`;
|
||||
|
||||
const StyledGridWrapper = styled.div`
|
||||
|
@ -15,7 +15,7 @@ const StyledInfoPanelBody = styled.div`
|
||||
: css`
|
||||
padding: 80px 3px 0 20px;
|
||||
@media ${hugeMobile} {
|
||||
padding: 80px 8px 0 16px;
|
||||
padding: 80px 0 0 16px;
|
||||
}
|
||||
`}
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
import styled from "styled-components";
|
||||
|
||||
import { isMobileOnly } from "react-device-detect";
|
||||
import { Base } from "@docspace/components/themes";
|
||||
|
||||
const StyledThumbnail = styled.div`
|
||||
@ -7,13 +7,14 @@ const StyledThumbnail = styled.div`
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
width: 100%;
|
||||
height: auto;
|
||||
height: ${isMobileOnly ? "188" : "240"}px;
|
||||
img {
|
||||
border: ${(props) => `solid 1px ${props.theme.infoPanel.borderColor}`};
|
||||
border-radius: 6px;
|
||||
width: auto;
|
||||
max-width: 100%;
|
||||
height: auto;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
object-fit: none;
|
||||
object-position: top;
|
||||
}
|
||||
`;
|
||||
|
||||
@ -30,7 +31,8 @@ const StyledNoThumbnail = styled.div`
|
||||
border-radius: 16px;
|
||||
}
|
||||
.custom-logo {
|
||||
outline: 1px solid ${(props) => props.theme.infoPanel.details.customLogoBorderColor};
|
||||
outline: 1px solid ${(props) =>
|
||||
props.theme.infoPanel.details.customLogoBorderColor};
|
||||
`;
|
||||
|
||||
const StyledAccess = styled.div`
|
||||
|
@ -1,11 +1,11 @@
|
||||
import styled from "styled-components";
|
||||
|
||||
import { isMobileOnly } from "react-device-detect";
|
||||
import { Base } from "@docspace/components/themes";
|
||||
|
||||
const StyledGalleryThumbnail = styled.div`
|
||||
box-sizing: border-box;
|
||||
width: 100%;
|
||||
height: 346px;
|
||||
height: ${isMobileOnly ? "335" : "346"}px;
|
||||
overflow: hidden;
|
||||
border: ${(props) =>
|
||||
`solid 1px ${props.theme.infoPanel.gallery.borderColor}`};
|
||||
|
@ -27,6 +27,7 @@ const FilesMediaViewer = (props) => {
|
||||
setToPreviewFile,
|
||||
setScrollToItem,
|
||||
setCurrentId,
|
||||
setAlreadyFetchingRooms,
|
||||
setBufferSelection,
|
||||
isFavoritesFolder,
|
||||
archiveRoomsId,
|
||||
@ -72,6 +73,7 @@ const FilesMediaViewer = (props) => {
|
||||
fetchFiles(previewFile.folderId).finally(() => {
|
||||
setIsLoading(false);
|
||||
setFirstLoad(false);
|
||||
setAlreadyFetchingRooms(false);
|
||||
});
|
||||
}
|
||||
}, [previewFile]);
|
||||
@ -230,6 +232,7 @@ export default inject(
|
||||
isPreview,
|
||||
resetUrl,
|
||||
setSelection,
|
||||
setAlreadyFetchingRooms,
|
||||
} = filesStore;
|
||||
const {
|
||||
visible,
|
||||
@ -286,6 +289,7 @@ export default inject(
|
||||
setScrollToItem,
|
||||
setCurrentId,
|
||||
setBufferSelection,
|
||||
setAlreadyFetchingRooms,
|
||||
isFavoritesFolder,
|
||||
onClickFavorite,
|
||||
onClickDownloadAs,
|
||||
|
@ -81,6 +81,7 @@ const FilesRowContainer = ({
|
||||
fetchMoreFiles,
|
||||
hasMoreFiles,
|
||||
isRooms,
|
||||
isTrashFolder,
|
||||
withPaging,
|
||||
highlightFileId,
|
||||
}) => {
|
||||
@ -110,6 +111,7 @@ const FilesRowContainer = ({
|
||||
itemIndex={index}
|
||||
sectionWidth={sectionWidth}
|
||||
isRooms={isRooms}
|
||||
isTrashFolder={isTrashFolder}
|
||||
isHighlight={highlightFileId === item.id}
|
||||
/>
|
||||
));
|
||||
@ -143,7 +145,7 @@ export default inject(({ filesStore, auth, treeFoldersStore }) => {
|
||||
highlightFileId,
|
||||
} = filesStore;
|
||||
const { isVisible: infoPanelVisible } = auth.infoPanelStore;
|
||||
const { isRoomsFolder, isArchiveFolder } = treeFoldersStore;
|
||||
const { isRoomsFolder, isArchiveFolder, isTrashFolder } = treeFoldersStore;
|
||||
const { withPaging } = auth.settingsStore;
|
||||
|
||||
const isRooms = isRoomsFolder || isArchiveFolder;
|
||||
@ -157,6 +159,7 @@ export default inject(({ filesStore, auth, treeFoldersStore }) => {
|
||||
fetchMoreFiles,
|
||||
hasMoreFiles,
|
||||
isRooms,
|
||||
isTrashFolder,
|
||||
withPaging,
|
||||
highlightFileId,
|
||||
};
|
||||
|
@ -4,6 +4,7 @@ import { withRouter } from "react-router";
|
||||
import { withTranslation } from "react-i18next";
|
||||
import styled from "styled-components";
|
||||
import { isMobile, isTablet, isMobileOnly } from "react-device-detect";
|
||||
import moment from "moment";
|
||||
|
||||
import Link from "@docspace/components/link";
|
||||
import Text from "@docspace/components/text";
|
||||
@ -94,15 +95,18 @@ const FilesRowContent = ({
|
||||
quickButtons,
|
||||
theme,
|
||||
isRooms,
|
||||
isTrashFolder,
|
||||
}) => {
|
||||
const {
|
||||
contentLength,
|
||||
fileExst,
|
||||
filesCount,
|
||||
foldersCount,
|
||||
autoDelete,
|
||||
providerKey,
|
||||
title,
|
||||
isRoom,
|
||||
daysRemaining,
|
||||
} = item;
|
||||
|
||||
return (
|
||||
@ -138,7 +142,11 @@ const FilesRowContent = ({
|
||||
// color={sideColor}
|
||||
className="row_update-text"
|
||||
>
|
||||
{updatedDate && updatedDate}
|
||||
{isTrashFolder
|
||||
? t("Files:DaysRemaining", {
|
||||
daysRemaining,
|
||||
})
|
||||
: updatedDate && updatedDate}
|
||||
</Text>
|
||||
|
||||
<Text
|
||||
@ -166,8 +174,9 @@ const FilesRowContent = ({
|
||||
);
|
||||
};
|
||||
|
||||
export default inject(({ auth }) => {
|
||||
return { theme: auth.settingsStore.theme };
|
||||
export default inject(({ auth, treeFoldersStore }) => {
|
||||
const { isRecycleBinFolder } = treeFoldersStore;
|
||||
return { theme: auth.settingsStore.theme, isTrashFolder: isRecycleBinFolder };
|
||||
})(
|
||||
observer(
|
||||
withRouter(
|
||||
|
@ -116,6 +116,7 @@ const Table = ({
|
||||
hasMoreFiles,
|
||||
filterTotal,
|
||||
isRooms,
|
||||
isTrashFolder,
|
||||
withPaging,
|
||||
columnStorageName,
|
||||
columnInfoPanelStorageName,
|
||||
@ -189,6 +190,7 @@ const Table = ({
|
||||
theme={theme}
|
||||
tagCount={tagCount}
|
||||
isRooms={isRooms}
|
||||
isTrashFolder={isTrashFolder}
|
||||
hideColumns={hideColumns}
|
||||
isHighlight={highlightFileId === item.id}
|
||||
/>
|
||||
@ -233,7 +235,7 @@ const Table = ({
|
||||
export default inject(({ filesStore, treeFoldersStore, auth, tableStore }) => {
|
||||
const { isVisible: infoPanelVisible } = auth.infoPanelStore;
|
||||
|
||||
const { isRoomsFolder, isArchiveFolder } = treeFoldersStore;
|
||||
const { isRoomsFolder, isArchiveFolder, isTrashFolder } = treeFoldersStore;
|
||||
const isRooms = isRoomsFolder || isArchiveFolder;
|
||||
|
||||
const { columnStorageName, columnInfoPanelStorageName } = tableStore;
|
||||
@ -266,6 +268,7 @@ export default inject(({ filesStore, treeFoldersStore, auth, tableStore }) => {
|
||||
hasMoreFiles,
|
||||
filterTotal: isRooms ? roomsFilterTotal : filterTotal,
|
||||
isRooms,
|
||||
isTrashFolder,
|
||||
withPaging,
|
||||
columnStorageName,
|
||||
columnInfoPanelStorageName,
|
||||
|
@ -14,7 +14,7 @@ class FilesTableHeader extends React.Component {
|
||||
}
|
||||
|
||||
getTableColumns = (fromUpdate = false) => {
|
||||
const { t, isRooms, getColumns } = this.props;
|
||||
const { t, isRooms, isTrashFolder, getColumns } = this.props;
|
||||
|
||||
const defaultColumns = [];
|
||||
|
||||
@ -68,7 +68,81 @@ class FilesTableHeader extends React.Component {
|
||||
onClick: this.onRoomsFilter,
|
||||
},
|
||||
];
|
||||
|
||||
defaultColumns.push(...columns);
|
||||
} else if (isTrashFolder) {
|
||||
const columns = [
|
||||
{
|
||||
key: "Name",
|
||||
title: t("Common:Name"),
|
||||
resizable: true,
|
||||
enable: this.props.nameColumnIsEnabled,
|
||||
default: true,
|
||||
sortBy: "AZ",
|
||||
minWidth: 210,
|
||||
onClick: this.onFilter,
|
||||
},
|
||||
{
|
||||
key: "Room",
|
||||
title: t("Common:Room"),
|
||||
enable: this.props.roomColumnIsEnabled,
|
||||
resizable: true,
|
||||
sortBy: "Room",
|
||||
onClick: this.onFilter,
|
||||
onChange: this.onColumnChange,
|
||||
},
|
||||
{
|
||||
key: "AuthorTrash",
|
||||
title: t("ByAuthor"),
|
||||
enable: this.props.authorTrashColumnIsEnabled,
|
||||
resizable: true,
|
||||
sortBy: "Author",
|
||||
onClick: this.onFilter,
|
||||
onChange: this.onColumnChange,
|
||||
},
|
||||
{
|
||||
key: "CreatedTrash",
|
||||
title: t("ByCreation"),
|
||||
enable: this.props.createdTrashColumnIsEnabled,
|
||||
resizable: true,
|
||||
sortBy: "DateAndTimeCreation",
|
||||
onClick: this.onFilter,
|
||||
onChange: this.onColumnChange,
|
||||
},
|
||||
{
|
||||
key: "Erasure",
|
||||
title: t("ByErasure"),
|
||||
enable: this.props.erasureColumnIsEnabled,
|
||||
resizable: true,
|
||||
sortBy: "DateAndTime",
|
||||
onClick: this.onFilter,
|
||||
onChange: this.onColumnChange,
|
||||
},
|
||||
{
|
||||
key: "SizeTrash",
|
||||
title: t("Common:Size"),
|
||||
enable: this.props.sizeTrashColumnIsEnabled,
|
||||
resizable: true,
|
||||
sortBy: "Size",
|
||||
onClick: this.onFilter,
|
||||
onChange: this.onColumnChange,
|
||||
},
|
||||
{
|
||||
key: "TypeTrash",
|
||||
title: t("Common:Type"),
|
||||
enable: this.props.typeTrashColumnIsEnabled,
|
||||
resizable: true,
|
||||
sortBy: "Type",
|
||||
onClick: this.onFilter,
|
||||
onChange: this.onColumnChange,
|
||||
},
|
||||
{
|
||||
key: "QuickButtons",
|
||||
title: "",
|
||||
enable: this.props.quickButtonsColumnIsEnabled,
|
||||
defaultSize: 75,
|
||||
resizable: false,
|
||||
},
|
||||
];
|
||||
defaultColumns.push(...columns);
|
||||
} else {
|
||||
const columns = [
|
||||
@ -135,7 +209,6 @@ class FilesTableHeader extends React.Component {
|
||||
resizable: false,
|
||||
},
|
||||
];
|
||||
|
||||
defaultColumns.push(...columns);
|
||||
}
|
||||
|
||||
@ -194,7 +267,10 @@ class FilesTableHeader extends React.Component {
|
||||
};
|
||||
|
||||
componentDidUpdate(prevProps) {
|
||||
if (this.props.isRooms !== prevProps.isRooms) {
|
||||
if (
|
||||
this.props.isRooms !== prevProps.isRooms ||
|
||||
this.props.isTrashFolder !== prevProps.isTrashFolder
|
||||
) {
|
||||
return this.getTableColumns(true);
|
||||
}
|
||||
|
||||
@ -352,7 +428,12 @@ export default inject(
|
||||
roomsFilter,
|
||||
fetchRooms,
|
||||
} = filesStore;
|
||||
const { isRecentFolder, isRoomsFolder, isArchiveFolder } = treeFoldersStore;
|
||||
const {
|
||||
isRecentFolder,
|
||||
isRoomsFolder,
|
||||
isArchiveFolder,
|
||||
isTrashFolder,
|
||||
} = treeFoldersStore;
|
||||
const isRooms = isRoomsFolder || isArchiveFolder;
|
||||
const withContent = canShare;
|
||||
const sortingVisible = !isRecentFolder;
|
||||
@ -369,10 +450,16 @@ export default inject(
|
||||
|
||||
nameColumnIsEnabled,
|
||||
authorColumnIsEnabled,
|
||||
authorTrashColumnIsEnabled,
|
||||
createdColumnIsEnabled,
|
||||
createdTrashColumnIsEnabled,
|
||||
modifiedColumnIsEnabled,
|
||||
roomColumnIsEnabled,
|
||||
erasureColumnIsEnabled,
|
||||
sizeColumnIsEnabled,
|
||||
sizeTrashColumnIsEnabled,
|
||||
typeColumnIsEnabled,
|
||||
typeTrashColumnIsEnabled,
|
||||
quickButtonsColumnIsEnabled,
|
||||
|
||||
roomColumnNameIsEnabled,
|
||||
@ -414,10 +501,16 @@ export default inject(
|
||||
|
||||
nameColumnIsEnabled,
|
||||
authorColumnIsEnabled,
|
||||
authorTrashColumnIsEnabled,
|
||||
createdColumnIsEnabled,
|
||||
createdTrashColumnIsEnabled,
|
||||
modifiedColumnIsEnabled,
|
||||
roomColumnIsEnabled,
|
||||
erasureColumnIsEnabled,
|
||||
sizeColumnIsEnabled,
|
||||
sizeTrashColumnIsEnabled,
|
||||
typeColumnIsEnabled,
|
||||
typeTrashColumnIsEnabled,
|
||||
quickButtonsColumnIsEnabled,
|
||||
|
||||
roomColumnNameIsEnabled,
|
||||
@ -429,6 +522,7 @@ export default inject(
|
||||
getColumns,
|
||||
setColumnEnable,
|
||||
isRooms,
|
||||
isTrashFolder,
|
||||
};
|
||||
}
|
||||
)(
|
||||
|
@ -8,6 +8,7 @@ import ItemIcon from "../../../../../components/ItemIcon";
|
||||
import { withTranslation } from "react-i18next";
|
||||
import { classNames } from "@docspace/components/utils/classNames";
|
||||
import RoomsRowDataComponent from "./sub-components/RoomsRowData";
|
||||
import TrashRowDataComponent from "./sub-components/TrashRowData";
|
||||
import RowDataComponent from "./sub-components/RowData";
|
||||
import { StyledTableRow, StyledDragAndDrop } from "./StyledTable";
|
||||
|
||||
@ -37,6 +38,7 @@ const FilesTableRow = (props) => {
|
||||
showHotkeyBorder,
|
||||
id,
|
||||
isRooms,
|
||||
isTrashFolder,
|
||||
isHighlight,
|
||||
} = props;
|
||||
const { acceptBackground, background } = theme.dragAndDrop;
|
||||
@ -146,6 +148,12 @@ const FilesTableRow = (props) => {
|
||||
dragStyles={dragStyles}
|
||||
{...props}
|
||||
/>
|
||||
) : isTrashFolder ? (
|
||||
<TrashRowDataComponent
|
||||
element={element}
|
||||
dragStyles={dragStyles}
|
||||
{...props}
|
||||
/>
|
||||
) : (
|
||||
<RowDataComponent
|
||||
element={element}
|
||||
|
@ -0,0 +1,22 @@
|
||||
import React from "react";
|
||||
import { StyledText } from "./CellStyles";
|
||||
|
||||
const ErasureCell = ({ t, sideColor, item }) => {
|
||||
const { daysRemaining } = item;
|
||||
const title = t("Files:DaysRemaining", { daysRemaining });
|
||||
|
||||
return (
|
||||
<StyledText
|
||||
title={title}
|
||||
fontSize="12px"
|
||||
fontWeight={600}
|
||||
color={sideColor}
|
||||
className="row_update-text"
|
||||
truncate
|
||||
>
|
||||
{title}
|
||||
</StyledText>
|
||||
);
|
||||
};
|
||||
|
||||
export default ErasureCell;
|
@ -0,0 +1,66 @@
|
||||
import { Loader, Tooltip } from "@docspace/components";
|
||||
import Text from "@docspace/components/text";
|
||||
import React, { useState } from "react";
|
||||
import { StyledText } from "./CellStyles";
|
||||
import { getFolderPath } from "@docspace/common/api/files";
|
||||
import { CategoryType } from "@docspace/client/src/helpers/constants";
|
||||
|
||||
const RoomCell = ({ sideColor, item }) => {
|
||||
const { originRoomTitle, originId, originTitle } = item;
|
||||
|
||||
const [path, setPath] = useState([]);
|
||||
const [isTooltipLoading, setIsTooltipLoading] = useState(false);
|
||||
|
||||
const getPath = async () => {
|
||||
if (path.length) return;
|
||||
|
||||
setIsTooltipLoading(true);
|
||||
try {
|
||||
const folderPath = await getFolderPath(originId);
|
||||
if (folderPath[0].id === CategoryType.Shared) folderPath.shift();
|
||||
setPath(folderPath);
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
setPath([{ id: 0, title: originRoomTitle || originTitle }]);
|
||||
}
|
||||
setIsTooltipLoading(false);
|
||||
};
|
||||
|
||||
return [
|
||||
<StyledText
|
||||
key="cell"
|
||||
fontSize="12px"
|
||||
fontWeight={600}
|
||||
color={sideColor}
|
||||
className="row_update-text"
|
||||
truncate
|
||||
data-for={"" + item.id}
|
||||
data-tip={""}
|
||||
data-place={"bottom"}
|
||||
>
|
||||
{originRoomTitle || originTitle}
|
||||
</StyledText>,
|
||||
|
||||
<Tooltip
|
||||
id={"" + item.id}
|
||||
key={"tooltip"}
|
||||
effect={"float"}
|
||||
afterShow={getPath}
|
||||
getContent={() => (
|
||||
<span>
|
||||
{isTooltipLoading ? (
|
||||
<Loader color="#333333" size="12px" type="track" />
|
||||
) : (
|
||||
path.map((pathPart, i) => (
|
||||
<Text key={pathPart.id} isBold={i === 0} isInline fontSize="12px">
|
||||
{i === 0 ? pathPart.title : `/${pathPart.title}`}
|
||||
</Text>
|
||||
))
|
||||
)}
|
||||
</span>
|
||||
)}
|
||||
/>,
|
||||
];
|
||||
};
|
||||
|
||||
export default RoomCell;
|
@ -0,0 +1,211 @@
|
||||
import React from "react";
|
||||
import { inject, observer } from "mobx-react";
|
||||
import TableCell from "@docspace/components/table-container/TableCell";
|
||||
import FileNameCell from "./FileNameCell";
|
||||
import TypeCell from "./TypeCell";
|
||||
import AuthorCell from "./AuthorCell";
|
||||
import DateCell from "./DateCell";
|
||||
import SizeCell from "./SizeCell";
|
||||
import { classNames } from "@docspace/components/utils/classNames";
|
||||
import {
|
||||
StyledBadgesContainer,
|
||||
StyledQuickButtonsContainer,
|
||||
} from "../StyledTable";
|
||||
import ErasureCell from "./ErasureCell";
|
||||
import RoomCell from "./RoomCell";
|
||||
|
||||
const TrashRowDataComponent = (props) => {
|
||||
const {
|
||||
authorTrashColumnIsEnabled,
|
||||
createdTrashColumnIsEnabled,
|
||||
roomColumnIsEnabled,
|
||||
erasureColumnIsEnabled,
|
||||
sizeTrashColumnIsEnabled,
|
||||
typeTrashColumnIsEnabled,
|
||||
quickButtonsColumnIsEnabled,
|
||||
|
||||
dragStyles,
|
||||
selectionProp,
|
||||
value,
|
||||
theme,
|
||||
onContentFileSelect,
|
||||
checkedProps,
|
||||
element,
|
||||
inProgress,
|
||||
showHotkeyBorder,
|
||||
badgesComponent,
|
||||
quickButtonsComponent,
|
||||
} = props;
|
||||
|
||||
return (
|
||||
<>
|
||||
<TableCell
|
||||
{...dragStyles}
|
||||
className={classNames(
|
||||
selectionProp?.className,
|
||||
"table-container_file-name-cell"
|
||||
)}
|
||||
value={value}
|
||||
>
|
||||
<FileNameCell
|
||||
theme={theme}
|
||||
onContentSelect={onContentFileSelect}
|
||||
checked={checkedProps}
|
||||
element={element}
|
||||
inProgress={inProgress}
|
||||
{...props}
|
||||
/>
|
||||
<StyledBadgesContainer showHotkeyBorder={showHotkeyBorder}>
|
||||
{badgesComponent}
|
||||
</StyledBadgesContainer>
|
||||
</TableCell>
|
||||
|
||||
{roomColumnIsEnabled ? (
|
||||
<TableCell
|
||||
style={
|
||||
!roomColumnIsEnabled ? { background: "none" } : dragStyles.style
|
||||
}
|
||||
{...selectionProp}
|
||||
>
|
||||
<RoomCell
|
||||
sideColor={theme.filesSection.tableView.row.sideColor}
|
||||
{...props}
|
||||
/>
|
||||
</TableCell>
|
||||
) : (
|
||||
<div />
|
||||
)}
|
||||
|
||||
{authorTrashColumnIsEnabled ? (
|
||||
<TableCell
|
||||
style={
|
||||
!authorTrashColumnIsEnabled
|
||||
? { background: "none" }
|
||||
: dragStyles.style
|
||||
}
|
||||
{...selectionProp}
|
||||
>
|
||||
<AuthorCell
|
||||
sideColor={theme.filesSection.tableView.row.sideColor}
|
||||
{...props}
|
||||
/>
|
||||
</TableCell>
|
||||
) : (
|
||||
<div />
|
||||
)}
|
||||
|
||||
{createdTrashColumnIsEnabled ? (
|
||||
<TableCell
|
||||
style={
|
||||
!createdTrashColumnIsEnabled
|
||||
? { background: "none !important" }
|
||||
: dragStyles.style
|
||||
}
|
||||
{...selectionProp}
|
||||
>
|
||||
<DateCell
|
||||
create
|
||||
sideColor={theme.filesSection.tableView.row.sideColor}
|
||||
{...props}
|
||||
/>
|
||||
</TableCell>
|
||||
) : (
|
||||
<div />
|
||||
)}
|
||||
|
||||
{erasureColumnIsEnabled ? (
|
||||
<TableCell
|
||||
style={
|
||||
!erasureColumnIsEnabled ? { background: "none" } : dragStyles.style
|
||||
}
|
||||
{...selectionProp}
|
||||
>
|
||||
<ErasureCell
|
||||
sideColor={theme.filesSection.tableView.row.sideColor}
|
||||
{...props}
|
||||
/>
|
||||
</TableCell>
|
||||
) : (
|
||||
<div />
|
||||
)}
|
||||
|
||||
{sizeTrashColumnIsEnabled ? (
|
||||
<TableCell
|
||||
style={
|
||||
!sizeTrashColumnIsEnabled
|
||||
? { background: "none" }
|
||||
: dragStyles.style
|
||||
}
|
||||
{...selectionProp}
|
||||
>
|
||||
<SizeCell
|
||||
sideColor={theme.filesSection.tableView.row.sideColor}
|
||||
{...props}
|
||||
/>
|
||||
</TableCell>
|
||||
) : (
|
||||
<div />
|
||||
)}
|
||||
|
||||
{typeTrashColumnIsEnabled ? (
|
||||
<TableCell
|
||||
style={
|
||||
!typeTrashColumnIsEnabled
|
||||
? { background: "none !important" }
|
||||
: dragStyles.style
|
||||
}
|
||||
{...selectionProp}
|
||||
>
|
||||
<TypeCell
|
||||
sideColor={theme.filesSection.tableView.row.sideColor}
|
||||
{...props}
|
||||
/>
|
||||
</TableCell>
|
||||
) : (
|
||||
<div />
|
||||
)}
|
||||
{quickButtonsColumnIsEnabled ? (
|
||||
<TableCell
|
||||
style={
|
||||
!quickButtonsColumnIsEnabled
|
||||
? { background: "none" }
|
||||
: dragStyles.style
|
||||
}
|
||||
{...selectionProp}
|
||||
className={classNames(
|
||||
selectionProp?.className,
|
||||
"table-container_quick-buttons-wrapper"
|
||||
)}
|
||||
>
|
||||
<StyledQuickButtonsContainer>
|
||||
{quickButtonsComponent}
|
||||
</StyledQuickButtonsContainer>
|
||||
</TableCell>
|
||||
) : (
|
||||
<div />
|
||||
)}
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default inject(({ tableStore }) => {
|
||||
const {
|
||||
authorTrashColumnIsEnabled,
|
||||
createdTrashColumnIsEnabled,
|
||||
roomColumnIsEnabled,
|
||||
erasureColumnIsEnabled,
|
||||
sizeTrashColumnIsEnabled,
|
||||
typeTrashColumnIsEnabled,
|
||||
quickButtonsColumnIsEnabled,
|
||||
} = tableStore;
|
||||
|
||||
return {
|
||||
authorTrashColumnIsEnabled,
|
||||
createdTrashColumnIsEnabled,
|
||||
roomColumnIsEnabled,
|
||||
erasureColumnIsEnabled,
|
||||
sizeTrashColumnIsEnabled,
|
||||
typeTrashColumnIsEnabled,
|
||||
quickButtonsColumnIsEnabled,
|
||||
};
|
||||
})(observer(TrashRowDataComponent));
|
@ -267,7 +267,7 @@ const StyledFileTileTop = styled.div`
|
||||
position: absolute;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
object-fit: ${(props) => (props.isMedia ? "cover" : "none")};
|
||||
object-fit: none;
|
||||
object-position: top;
|
||||
z-index: 0;
|
||||
border-radius: 6px 6px 0 0;
|
||||
|
@ -147,6 +147,10 @@ const TABLE_ROOMS_COLUMNS = `roomsTableColumns_ver-${TableVersions.Rooms}`;
|
||||
|
||||
const COLUMNS_ROOMS_SIZE_INFO_PANEL = `roomsColumnsSizeInfoPanel_ver-${TableVersions.Rooms}`;
|
||||
|
||||
const TABLE_TRASH_COLUMNS = `trashTableColumns_ver-${TableVersions.Trash}`;
|
||||
|
||||
const COLUMNS_TRASH_SIZE_INFO_PANEL = `trashColumnsSizeInfoPanel_ver-${TableVersions.Trash}`;
|
||||
|
||||
const SectionFilterContent = ({
|
||||
t,
|
||||
filter,
|
||||
@ -165,6 +169,7 @@ const SectionFilterContent = ({
|
||||
fetchTags,
|
||||
infoPanelVisible,
|
||||
isRooms,
|
||||
isTrash,
|
||||
userId,
|
||||
isPersonalRoom,
|
||||
setCurrentRoomsFilter,
|
||||
@ -1020,13 +1025,13 @@ const SectionFilterContent = ({
|
||||
|
||||
return filterOptions;
|
||||
}, [
|
||||
isFavoritesFolder,
|
||||
isRecentFolder,
|
||||
isRooms,
|
||||
t,
|
||||
personal,
|
||||
isPersonalRoom,
|
||||
providers,
|
||||
isPersonalRoom,
|
||||
isRooms,
|
||||
isFavoritesFolder,
|
||||
isRecentFolder,
|
||||
]);
|
||||
|
||||
const getViewSettingsData = React.useCallback(() => {
|
||||
@ -1064,22 +1069,10 @@ const SectionFilterContent = ({
|
||||
label: t("ByLastModified"),
|
||||
default: true,
|
||||
};
|
||||
const type = {
|
||||
id: "sort-by_type",
|
||||
key: "Type",
|
||||
label: t("Common:Type"),
|
||||
default: true,
|
||||
};
|
||||
const size = {
|
||||
id: "sort-by_size",
|
||||
key: "Size",
|
||||
label: t("Common:Size"),
|
||||
default: true,
|
||||
};
|
||||
const creationDate = {
|
||||
id: "sort-by_created",
|
||||
key: "DateAndTimeCreation",
|
||||
label: t("ByCreation"),
|
||||
const room = {
|
||||
id: "sort-by_room",
|
||||
key: "Room",
|
||||
label: t("Common:Room"),
|
||||
default: true,
|
||||
};
|
||||
const authorOption = {
|
||||
@ -1088,18 +1081,42 @@ const SectionFilterContent = ({
|
||||
label: t("ByAuthor"),
|
||||
default: true,
|
||||
};
|
||||
const creationDate = {
|
||||
id: "sort-by_created",
|
||||
key: "DateAndTimeCreation",
|
||||
label: t("ByCreation"),
|
||||
default: true,
|
||||
};
|
||||
const owner = {
|
||||
id: "sort-by_owner",
|
||||
key: "Author",
|
||||
label: t("Common:Owner"),
|
||||
default: true,
|
||||
};
|
||||
const erasure = {
|
||||
id: "sort-by_erasure",
|
||||
key: "Erasure",
|
||||
label: t("ByErasure"),
|
||||
default: true,
|
||||
};
|
||||
const tags = {
|
||||
id: "sort-by_tags",
|
||||
key: "Tags",
|
||||
label: t("Common:Tags"),
|
||||
default: true,
|
||||
};
|
||||
const size = {
|
||||
id: "sort-by_size",
|
||||
key: "Size",
|
||||
label: t("Common:Size"),
|
||||
default: true,
|
||||
};
|
||||
const type = {
|
||||
id: "sort-by_type",
|
||||
key: "Type",
|
||||
label: t("Common:Type"),
|
||||
default: true,
|
||||
};
|
||||
const roomType = {
|
||||
id: "sort-by_room-type",
|
||||
key: "roomType",
|
||||
@ -1158,6 +1175,69 @@ const SectionFilterContent = ({
|
||||
|
||||
!hide && commonOptions.push(modifiedDate);
|
||||
}
|
||||
} else if (isTrash) {
|
||||
const availableSort = localStorage
|
||||
?.getItem(`${TABLE_TRASH_COLUMNS}=${userId}`)
|
||||
?.split(",");
|
||||
|
||||
const infoPanelColumnsSize = localStorage
|
||||
?.getItem(`${COLUMNS_TRASH_SIZE_INFO_PANEL}=${userId}`)
|
||||
?.split(" ");
|
||||
|
||||
if (availableSort?.includes("Author")) {
|
||||
const idx = availableSort.findIndex((x) => x === "Author");
|
||||
const hide =
|
||||
infoPanelVisible &&
|
||||
infoPanelColumnsSize &&
|
||||
infoPanelColumnsSize[idx] === "0px";
|
||||
|
||||
!hide && commonOptions.push(authorOption);
|
||||
}
|
||||
if (availableSort?.includes("Created")) {
|
||||
const idx = availableSort.findIndex((x) => x === "Created");
|
||||
const hide =
|
||||
infoPanelVisible &&
|
||||
infoPanelColumnsSize &&
|
||||
infoPanelColumnsSize[idx] === "0px";
|
||||
|
||||
!hide && commonOptions.push(creationDate);
|
||||
}
|
||||
if (availableSort?.includes("Room")) {
|
||||
const idx = availableSort.findIndex((x) => x === "Room");
|
||||
const hide =
|
||||
infoPanelVisible &&
|
||||
infoPanelColumnsSize &&
|
||||
infoPanelColumnsSize[idx] === "0px";
|
||||
|
||||
!hide && commonOptions.push(room);
|
||||
}
|
||||
if (availableSort?.includes("Erasure")) {
|
||||
const idx = availableSort.findIndex((x) => x === "Erasure");
|
||||
const hide =
|
||||
infoPanelVisible &&
|
||||
infoPanelColumnsSize &&
|
||||
infoPanelColumnsSize[idx] === "0px";
|
||||
|
||||
!hide && commonOptions.push(erasure);
|
||||
}
|
||||
if (availableSort?.includes("Size")) {
|
||||
const idx = availableSort.findIndex((x) => x === "Size");
|
||||
const hide =
|
||||
infoPanelVisible &&
|
||||
infoPanelColumnsSize &&
|
||||
infoPanelColumnsSize[idx] === "0px";
|
||||
|
||||
!hide && commonOptions.push(size);
|
||||
}
|
||||
if (availableSort?.includes("Type")) {
|
||||
const idx = availableSort.findIndex((x) => x === "Type");
|
||||
const hide =
|
||||
infoPanelVisible &&
|
||||
infoPanelColumnsSize &&
|
||||
infoPanelColumnsSize[idx] === "0px";
|
||||
|
||||
!hide && commonOptions.push(type);
|
||||
}
|
||||
} else {
|
||||
const availableSort = localStorage
|
||||
?.getItem(`${TABLE_COLUMNS}=${userId}`)
|
||||
@ -1219,6 +1299,12 @@ const SectionFilterContent = ({
|
||||
commonOptions.push(tags);
|
||||
commonOptions.push(owner);
|
||||
commonOptions.push(modifiedDate);
|
||||
} else if (isTrash) {
|
||||
commonOptions.push(authorOption);
|
||||
commonOptions.push(creationDate);
|
||||
commonOptions.push(erasure);
|
||||
commonOptions.push(size);
|
||||
commonOptions.push(type);
|
||||
} else {
|
||||
commonOptions.push(authorOption);
|
||||
commonOptions.push(creationDate);
|
||||
@ -1415,6 +1501,7 @@ export default inject(
|
||||
isRoomsFolder,
|
||||
isArchiveFolder,
|
||||
isPersonalRoom,
|
||||
isTrashFolder: isTrash,
|
||||
} = treeFoldersStore;
|
||||
|
||||
const isRooms = isRoomsFolder || isArchiveFolder;
|
||||
@ -1441,6 +1528,7 @@ export default inject(
|
||||
isFavoritesFolder,
|
||||
isRecentFolder,
|
||||
isRooms,
|
||||
isTrash,
|
||||
|
||||
setIsLoading,
|
||||
fetchFiles,
|
||||
|
@ -36,6 +36,7 @@ import { Consumer } from "@docspace/components/utils/context";
|
||||
import { inject, observer } from "mobx-react";
|
||||
import TableGroupMenu from "@docspace/components/table-container/TableGroupMenu";
|
||||
import Navigation from "@docspace/common/components/Navigation";
|
||||
import TrashWarning from "@docspace/common/components/Navigation/sub-components/trash-warning";
|
||||
import { Events } from "@docspace/common/constants";
|
||||
import config from "PACKAGE_FILE";
|
||||
import { combineUrl } from "@docspace/common/utils";
|
||||
@ -685,11 +686,15 @@ class SectionHeaderContent extends React.Component {
|
||||
const menuItems = this.getMenuItems();
|
||||
const isLoading = !title || !tReady;
|
||||
const headerMenu = getHeaderMenu(t);
|
||||
const isEmptyTrash = !![
|
||||
...this.props.activeFiles,
|
||||
...this.props.activeFolders,
|
||||
].length;
|
||||
|
||||
return (
|
||||
<Consumer>
|
||||
return [
|
||||
<Consumer key="header">
|
||||
{(context) => (
|
||||
<StyledContainer>
|
||||
<StyledContainer isRecycleBinFolder={isRecycleBinFolder}>
|
||||
{isHeaderVisible && headerMenu.length ? (
|
||||
<TableGroupMenu
|
||||
checkboxOptions={menuItems}
|
||||
@ -727,6 +732,7 @@ class SectionHeaderContent extends React.Component {
|
||||
getContextOptionsFolder={this.getContextOptionsFolder}
|
||||
onClose={this.onClose}
|
||||
onClickFolder={this.onClickFolder}
|
||||
isTrashFolder={isRecycleBinFolder}
|
||||
isRecycleBinFolder={isRecycleBinFolder || isArchiveFolder}
|
||||
isEmptyFilesList={
|
||||
isArchiveFolder ? isEmptyArchive : isEmptyFilesList
|
||||
@ -737,6 +743,7 @@ class SectionHeaderContent extends React.Component {
|
||||
isInfoPanelVisible={isInfoPanelVisible}
|
||||
titles={{
|
||||
trash: t("EmptyRecycleBin"),
|
||||
trashWarning: t("TrashErasureWarning"),
|
||||
}}
|
||||
withMenu={!isRoomsFolder}
|
||||
onPlusClick={this.onCreateRoom}
|
||||
@ -748,8 +755,15 @@ class SectionHeaderContent extends React.Component {
|
||||
)}
|
||||
</StyledContainer>
|
||||
)}
|
||||
</Consumer>
|
||||
);
|
||||
</Consumer>,
|
||||
isRecycleBinFolder && !isEmptyPage && (
|
||||
<TrashWarning
|
||||
key="trash-warning"
|
||||
title={t("Files:TrashErasureWarning")}
|
||||
isTabletView
|
||||
/>
|
||||
),
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -528,6 +528,7 @@ class PureHome extends React.Component {
|
||||
isHeaderVisible={isHeaderVisible}
|
||||
onOpenUploadPanel={this.showUploadPanel}
|
||||
firstLoad={firstLoad}
|
||||
isEmptyPage={isEmptyPage}
|
||||
>
|
||||
{!isErrorRoomNotAvailable && (
|
||||
<Section.SectionHeader>
|
||||
|
@ -55,6 +55,7 @@ let timeout = null,
|
||||
CancelToken,
|
||||
source;
|
||||
|
||||
const backUrl = window.location.origin;
|
||||
const PriceCalculation = ({
|
||||
t,
|
||||
user,
|
||||
@ -71,13 +72,19 @@ const PriceCalculation = ({
|
||||
currencySymbol,
|
||||
isAlreadyPaid,
|
||||
isFreeAfterPaidPeriod,
|
||||
setStartPaymentLink,
|
||||
managersCount,
|
||||
}) => {
|
||||
useEffect(() => {
|
||||
useEffect(async () => {
|
||||
initializeInfo();
|
||||
|
||||
!isAlreadyPaid && setStartPaymentLink(t);
|
||||
if (isAlreadyPaid) return;
|
||||
|
||||
try {
|
||||
const link = await getPaymentLink(managersCount, source?.token, backUrl);
|
||||
setPaymentLink(link);
|
||||
} catch (e) {
|
||||
toastr.error(t("ErrorNotification"));
|
||||
}
|
||||
|
||||
return () => {
|
||||
timeout && clearTimeout(timeout);
|
||||
@ -103,7 +110,7 @@ const PriceCalculation = ({
|
||||
CancelToken = axios.CancelToken;
|
||||
source = CancelToken.source();
|
||||
|
||||
await getPaymentLink(value, source.token)
|
||||
await getPaymentLink(value, source.token, backUrl)
|
||||
.then((link) => {
|
||||
setPaymentLink(link);
|
||||
setIsLoading(false);
|
||||
@ -207,7 +214,6 @@ export default inject(({ auth, payments }) => {
|
||||
setManagersCount,
|
||||
maxAvailableManagersCount,
|
||||
initializeInfo,
|
||||
setStartPaymentLink,
|
||||
managersCount,
|
||||
} = payments;
|
||||
const { theme } = auth.settingsStore;
|
||||
@ -224,7 +230,7 @@ export default inject(({ auth, payments }) => {
|
||||
|
||||
return {
|
||||
managersCount,
|
||||
setStartPaymentLink,
|
||||
|
||||
isFreeTariff,
|
||||
setManagersCount,
|
||||
tariffsInfo,
|
||||
|
@ -30,6 +30,8 @@ const PersonalSettings = ({
|
||||
showTitle,
|
||||
createWithoutDialog,
|
||||
setCreateWithoutDialog,
|
||||
|
||||
showAdminSettings,
|
||||
}) => {
|
||||
const [isLoadingFavorites, setIsLoadingFavorites] = React.useState(false);
|
||||
const [isLoadingRecent, setIsLoadingRecent] = React.useState(false);
|
||||
@ -75,7 +77,10 @@ const PersonalSettings = ({
|
||||
};
|
||||
|
||||
return (
|
||||
<StyledSettings showTitle={showTitle}>
|
||||
<StyledSettings
|
||||
showTitle={showTitle}
|
||||
hideAdminSettings={!showAdminSettings}
|
||||
>
|
||||
<Box className="settings-section">
|
||||
{showTitle && (
|
||||
<Heading className="heading" level={2} size="xsmall">
|
||||
|
@ -3,10 +3,22 @@ import { tablet } from "@docspace/components/utils/device";
|
||||
import { isMobile } from "react-device-detect";
|
||||
|
||||
const StyledSettings = styled.div`
|
||||
margin-top: ${(props) => (props.showTitle ? 24 : 34)}px;
|
||||
margin-top: ${(props) =>
|
||||
props.hideAdminSettings ? 22 : props.showTitle ? 24 : 34}px;
|
||||
|
||||
${(props) =>
|
||||
props.hideAdminSettings &&
|
||||
css`
|
||||
padding-top: 2px;
|
||||
`}
|
||||
|
||||
@media ${tablet} {
|
||||
margin-top: 8px;
|
||||
margin-top: ${(props) => (props.hideAdminSettings ? 0 : 8)}px;
|
||||
${(props) =>
|
||||
props.hideAdminSettings &&
|
||||
css`
|
||||
padding-top: 8px;
|
||||
`}
|
||||
}
|
||||
|
||||
${isMobile &&
|
||||
|
@ -70,7 +70,11 @@ const SectionBodyContent = ({ isErrorSettings, history, user }) => {
|
||||
) : (
|
||||
<StyledContainer>
|
||||
{!showAdminSettings ? (
|
||||
<PersonalSettings t={t} showTitle={true} />
|
||||
<PersonalSettings
|
||||
t={t}
|
||||
showTitle={true}
|
||||
showAdminSettings={showAdminSettings}
|
||||
/>
|
||||
) : (
|
||||
<Submenu
|
||||
data={data}
|
||||
|
@ -16,7 +16,10 @@ import { isMobile, isMobileOnly } from "react-device-detect";
|
||||
import toastr from "@docspace/components/toast/toastr";
|
||||
import config from "PACKAGE_FILE";
|
||||
import { thumbnailStatuses } from "@docspace/client/src/helpers/filesConstants";
|
||||
import { openDocEditor as openEditor } from "@docspace/client/src/helpers/filesUtils";
|
||||
import {
|
||||
getDaysRemaining,
|
||||
openDocEditor as openEditor,
|
||||
} from "@docspace/client/src/helpers/filesUtils";
|
||||
import { getCategoryUrl } from "SRC_DIR/helpers/utils";
|
||||
import {
|
||||
getCategoryType,
|
||||
@ -2394,6 +2397,8 @@ class FilesStore {
|
||||
const newItem = items.map((item) => {
|
||||
const {
|
||||
access,
|
||||
autoDelete,
|
||||
originTitle,
|
||||
comment,
|
||||
contentLength,
|
||||
created,
|
||||
@ -2408,6 +2413,10 @@ class FilesStore {
|
||||
id,
|
||||
logo,
|
||||
locked,
|
||||
originId,
|
||||
originFolderId,
|
||||
originRoomId,
|
||||
originRoomTitle,
|
||||
parentId,
|
||||
pureContentLength,
|
||||
rootFolderType,
|
||||
@ -2505,6 +2514,8 @@ class FilesStore {
|
||||
|
||||
return {
|
||||
access,
|
||||
daysRemaining: autoDelete && getDaysRemaining(autoDelete),
|
||||
originTitle,
|
||||
//checked,
|
||||
comment,
|
||||
contentLength,
|
||||
@ -2545,6 +2556,10 @@ class FilesStore {
|
||||
canEdit,
|
||||
thumbnailUrl,
|
||||
thumbnailStatus,
|
||||
originId,
|
||||
originFolderId,
|
||||
originRoomId,
|
||||
originRoomTitle,
|
||||
previewUrl,
|
||||
folderUrl,
|
||||
href,
|
||||
|
@ -140,15 +140,6 @@ class PaymentStore {
|
||||
}
|
||||
};
|
||||
|
||||
setStartPaymentLink = async (t) => {
|
||||
try {
|
||||
const link = await api.portal.getPaymentLink(this.managersCount);
|
||||
this.setPaymentLink(link);
|
||||
} catch (e) {
|
||||
toastr.error(t("ErrorNotification"));
|
||||
}
|
||||
};
|
||||
|
||||
setTotalPrice = (value) => {
|
||||
const price = this.getTotalCostByFormula(value);
|
||||
if (price !== this.totalPrice) this.totalPrice = price;
|
||||
|
@ -3,12 +3,15 @@ import { TableVersions } from "SRC_DIR/helpers/constants";
|
||||
|
||||
const TABLE_COLUMNS = `filesTableColumns_ver-${TableVersions.Files}`;
|
||||
const TABLE_ROOMS_COLUMNS = `roomsTableColumns_ver-${TableVersions.Rooms}`;
|
||||
const TABLE_TRASH_COLUMNS = `trashTableColumns_ver-${TableVersions.Trash}`;
|
||||
|
||||
const COLUMNS_SIZE = `filesColumnsSize_ver-${TableVersions.Files}`;
|
||||
const COLUMNS_ROOMS_SIZE = `roomsColumnsSize_ver-${TableVersions.Rooms}`;
|
||||
const COLUMNS_TRASH_SIZE = `trashColumnsSize_ver-${TableVersions.Trash}`;
|
||||
|
||||
const COLUMNS_SIZE_INFO_PANEL = `filesColumnsSizeInfoPanel_ver-${TableVersions.Files}`;
|
||||
const COLUMNS_ROOMS_SIZE_INFO_PANEL = `roomsColumnsSizeInfoPanel_ver-${TableVersions.Rooms}`;
|
||||
const COLUMNS_TRASH_SIZE_INFO_PANEL = `trashColumnsSizeInfoPanel_ver-${TableVersions.Trash}`;
|
||||
|
||||
class TableStore {
|
||||
authStore;
|
||||
@ -22,12 +25,19 @@ class TableStore {
|
||||
|
||||
nameColumnIsEnabled = true; // always true
|
||||
authorColumnIsEnabled = false;
|
||||
roomColumnIsEnabled = true;
|
||||
erasureColumnIsEnabled = true;
|
||||
createdColumnIsEnabled = true;
|
||||
modifiedColumnIsEnabled = true;
|
||||
sizeColumnIsEnabled = true;
|
||||
typeColumnIsEnabled = true;
|
||||
quickButtonsColumnIsEnabled = true;
|
||||
|
||||
authorTrashColumnIsEnabled = true;
|
||||
createdTrashColumnIsEnabled = false;
|
||||
sizeTrashColumnIsEnabled = false;
|
||||
typeTrashColumnIsEnabled = false;
|
||||
|
||||
constructor(authStore, treeFoldersStore) {
|
||||
makeAutoObservable(this);
|
||||
|
||||
@ -54,28 +64,51 @@ class TableStore {
|
||||
setAuthorColumn = (enable) => {
|
||||
this.authorColumnIsEnabled = enable;
|
||||
};
|
||||
|
||||
setCreatedColumn = (enable) => {
|
||||
this.createdColumnIsEnabled = enable;
|
||||
};
|
||||
|
||||
setModifiedColumn = (enable) => {
|
||||
this.modifiedColumnIsEnabled = enable;
|
||||
};
|
||||
|
||||
setRoomColumn = (enable) => {
|
||||
this.roomColumnIsEnabled = enable;
|
||||
};
|
||||
|
||||
setErasureColumn = (enable) => {
|
||||
this.erasureColumnIsEnabled = enable;
|
||||
};
|
||||
|
||||
setSizeColumn = (enable) => {
|
||||
this.sizeColumnIsEnabled = enable;
|
||||
};
|
||||
|
||||
setTypeColumn = (enable) => {
|
||||
this.typeColumnIsEnabled = enable;
|
||||
};
|
||||
|
||||
setQuickButtonsColumn = (enable) => {
|
||||
this.quickButtonsColumnIsEnabled = enable;
|
||||
};
|
||||
|
||||
setAuthorTrashColumn = (enable) => (this.authorTrashColumnIsEnabled = enable);
|
||||
setCreatedTrashColumn = (enable) =>
|
||||
(this.createdTrashColumnIsEnabled = enable);
|
||||
setSizeTrashColumn = (enable) => (this.sizeTrashColumnIsEnabled = enable);
|
||||
setTypeTrashColumn = (enable) => (this.typeTrashColumnIsEnabled = enable);
|
||||
|
||||
setColumnsEnable = () => {
|
||||
const storageColumns = localStorage.getItem(this.tableStorageName);
|
||||
const splitColumns = storageColumns && storageColumns.split(",");
|
||||
|
||||
if (splitColumns) {
|
||||
const { isRoomsFolder, isArchiveFolder } = this.treeFoldersStore;
|
||||
const {
|
||||
isRoomsFolder,
|
||||
isArchiveFolder,
|
||||
isTrashFolder,
|
||||
} = this.treeFoldersStore;
|
||||
const isRooms = isRoomsFolder || isArchiveFolder;
|
||||
|
||||
if (isRooms) {
|
||||
@ -83,51 +116,96 @@ class TableStore {
|
||||
this.setRoomColumnTags(splitColumns.includes("Tags"));
|
||||
this.setRoomColumnOwner(splitColumns.includes("Owner"));
|
||||
this.setRoomColumnActivity(splitColumns.includes("Activity"));
|
||||
} else {
|
||||
this.setAuthorColumn(splitColumns.includes("Author"));
|
||||
this.setCreatedColumn(splitColumns.includes("Created"));
|
||||
this.setModifiedColumn(splitColumns.includes("Modified"));
|
||||
this.setSizeColumn(splitColumns.includes("Size"));
|
||||
this.setTypeColumn(splitColumns.includes("Type"));
|
||||
this.setQuickButtonsColumn(splitColumns.includes("QuickButtons"));
|
||||
return;
|
||||
}
|
||||
|
||||
if (isTrashFolder) {
|
||||
this.setRoomColumn(splitColumns.includes("Room"));
|
||||
this.setAuthorTrashColumn(splitColumns.includes("AuthorTrash"));
|
||||
this.setCreatedTrashColumn(splitColumns.includes("CreatedTrash"));
|
||||
this.setErasureColumn(splitColumns.includes("Erasure"));
|
||||
this.setSizeTrashColumn(splitColumns.includes("SizeTrash"));
|
||||
this.setTypeTrashColumn(splitColumns.includes("TypeTrash"));
|
||||
this.setQuickButtonsColumn(splitColumns.includes("QuickButtons"));
|
||||
return;
|
||||
}
|
||||
|
||||
this.setModifiedColumn(splitColumns.includes("Modified"));
|
||||
this.setAuthorColumn(splitColumns.includes("Author"));
|
||||
this.setCreatedColumn(splitColumns.includes("Created"));
|
||||
this.setSizeColumn(splitColumns.includes("Size"));
|
||||
this.setTypeColumn(splitColumns.includes("Type"));
|
||||
this.setQuickButtonsColumn(splitColumns.includes("QuickButtons"));
|
||||
}
|
||||
};
|
||||
|
||||
setColumnEnable = (key) => {
|
||||
const { isRoomsFolder, isArchiveFolder } = this.treeFoldersStore;
|
||||
const {
|
||||
isRoomsFolder,
|
||||
isArchiveFolder,
|
||||
isTrashFolder,
|
||||
} = this.treeFoldersStore;
|
||||
const isRooms = isRoomsFolder || isArchiveFolder;
|
||||
|
||||
switch (key) {
|
||||
case "Room":
|
||||
this.setRoomColumn(!this.roomColumnIsEnabled);
|
||||
return;
|
||||
|
||||
case "Author":
|
||||
this.setAuthorColumn(!this.authorColumnIsEnabled);
|
||||
return;
|
||||
case "AuthorTrash":
|
||||
this.setAuthorTrashColumn(!this.authorTrashColumnIsEnabled);
|
||||
return;
|
||||
|
||||
case "Created":
|
||||
this.setCreatedColumn(!this.createdColumnIsEnabled);
|
||||
return;
|
||||
case "CreatedTrash":
|
||||
this.setCreatedTrashColumn(!this.createdTrashColumnIsEnabled);
|
||||
return;
|
||||
|
||||
case "Modified":
|
||||
this.setModifiedColumn(!this.modifiedColumnIsEnabled);
|
||||
return;
|
||||
|
||||
case "Erasure":
|
||||
this.setErasureColumn(!this.erasureColumnIsEnabled);
|
||||
return;
|
||||
|
||||
case "Size":
|
||||
this.setSizeColumn(!this.sizeColumnIsEnabled);
|
||||
return;
|
||||
case "SizeTrash":
|
||||
this.setSizeTrashColumn(!this.sizeTrashColumnIsEnabled);
|
||||
return;
|
||||
|
||||
case "Type":
|
||||
isRooms
|
||||
? this.setRoomColumnType(!this.roomColumnTypeIsEnabled)
|
||||
: this.setTypeColumn(!this.typeColumnIsEnabled);
|
||||
return;
|
||||
case "TypeTrash":
|
||||
this.setTypeTrashColumn(!this.typeTrashColumnIsEnabled);
|
||||
return;
|
||||
|
||||
case "QuickButtons":
|
||||
this.setQuickButtonsColumn(!this.quickButtonsColumnIsEnabled);
|
||||
return;
|
||||
|
||||
case "Owner":
|
||||
this.setRoomColumnOwner(!this.roomColumnOwnerIsEnabled);
|
||||
return;
|
||||
|
||||
case "Tags":
|
||||
this.setRoomColumnTags(!this.roomColumnTagsIsEnabled);
|
||||
return;
|
||||
|
||||
case "Activity":
|
||||
this.setRoomColumnActivity(!this.roomColumnActivityIsEnabled);
|
||||
return;
|
||||
|
||||
default:
|
||||
return;
|
||||
}
|
||||
@ -155,32 +233,50 @@ class TableStore {
|
||||
};
|
||||
|
||||
get tableStorageName() {
|
||||
const { isRoomsFolder, isArchiveFolder } = this.treeFoldersStore;
|
||||
const {
|
||||
isRoomsFolder,
|
||||
isArchiveFolder,
|
||||
isTrashFolder,
|
||||
} = this.treeFoldersStore;
|
||||
const isRooms = isRoomsFolder || isArchiveFolder;
|
||||
const userId = this.authStore.userStore.user.id;
|
||||
|
||||
return isRooms
|
||||
? `${TABLE_ROOMS_COLUMNS}=${userId}`
|
||||
: isTrashFolder
|
||||
? `${TABLE_TRASH_COLUMNS}=${userId}`
|
||||
: `${TABLE_COLUMNS}=${userId}`;
|
||||
}
|
||||
|
||||
get columnStorageName() {
|
||||
const { isRoomsFolder, isArchiveFolder } = this.treeFoldersStore;
|
||||
const {
|
||||
isRoomsFolder,
|
||||
isArchiveFolder,
|
||||
isTrashFolder,
|
||||
} = this.treeFoldersStore;
|
||||
const isRooms = isRoomsFolder || isArchiveFolder;
|
||||
const userId = this.authStore.userStore.user.id;
|
||||
|
||||
return isRooms
|
||||
? `${COLUMNS_ROOMS_SIZE}=${userId}`
|
||||
: isTrashFolder
|
||||
? `${COLUMNS_TRASH_SIZE}=${userId}`
|
||||
: `${COLUMNS_SIZE}=${userId}`;
|
||||
}
|
||||
|
||||
get columnInfoPanelStorageName() {
|
||||
const { isRoomsFolder, isArchiveFolder } = this.treeFoldersStore;
|
||||
const {
|
||||
isRoomsFolder,
|
||||
isArchiveFolder,
|
||||
isTrashFolder,
|
||||
} = this.treeFoldersStore;
|
||||
const isRooms = isRoomsFolder || isArchiveFolder;
|
||||
const userId = this.authStore.userStore.user.id;
|
||||
|
||||
return isRooms
|
||||
? `${COLUMNS_ROOMS_SIZE_INFO_PANEL}=${userId}`
|
||||
: isTrashFolder
|
||||
? `${COLUMNS_TRASH_SIZE_INFO_PANEL}=${userId}`
|
||||
: `${COLUMNS_SIZE_INFO_PANEL}=${userId}`;
|
||||
}
|
||||
|
||||
@ -192,6 +288,11 @@ class TableStore {
|
||||
const userId = this.authStore.userStore.user.id;
|
||||
return `${COLUMNS_ROOMS_SIZE}=${userId}`;
|
||||
}
|
||||
get trashColumnStorageName() {
|
||||
const userId = this.authStore.userStore.user.id;
|
||||
return `${COLUMNS_TRASH_SIZE}=${userId}`;
|
||||
}
|
||||
|
||||
get filesColumnInfoPanelStorageName() {
|
||||
const userId = this.authStore.userStore.user.id;
|
||||
return `${COLUMNS_SIZE_INFO_PANEL}=${userId}`;
|
||||
@ -200,6 +301,10 @@ class TableStore {
|
||||
const userId = this.authStore.userStore.user.id;
|
||||
return `${COLUMNS_ROOMS_SIZE_INFO_PANEL}=${userId}`;
|
||||
}
|
||||
get trashColumnInfoPanelStorageName() {
|
||||
const userId = this.authStore.userStore.user.id;
|
||||
return `${COLUMNS_TRASH_SIZE_INFO_PANEL}=${userId}`;
|
||||
}
|
||||
}
|
||||
|
||||
export default TableStore;
|
||||
|
@ -239,12 +239,13 @@ export function getPaymentAccount() {
|
||||
return request({ method: "get", url: "/portal/payment/account" });
|
||||
}
|
||||
|
||||
export function getPaymentLink(adminCount, cancelToken) {
|
||||
export function getPaymentLink(adminCount, cancelToken, backUrl) {
|
||||
return request({
|
||||
method: "put",
|
||||
url: `/portal/payment/url`,
|
||||
data: {
|
||||
quantity: { admin: adminCount },
|
||||
backUrl,
|
||||
},
|
||||
cancelToken,
|
||||
});
|
||||
|
@ -1,10 +1,10 @@
|
||||
import { request } from "../client";
|
||||
import axios from "axios";
|
||||
|
||||
export function getSettings() {
|
||||
export function getSettings(withPassword = false) {
|
||||
return request({
|
||||
method: "get",
|
||||
url: "/settings.json",
|
||||
url: `/settings.json?withPassword=${withPassword}`,
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -6,8 +6,9 @@ const LoginContainer = styled.div`
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
margin: 56px auto 0 auto;
|
||||
margin: 56px auto;
|
||||
max-width: 960px;
|
||||
z-index: 0;
|
||||
|
||||
.remember-wrapper {
|
||||
max-width: 142px;
|
||||
@ -236,7 +237,7 @@ const LoginContainer = styled.div`
|
||||
justify-content: center;
|
||||
width: 100%;
|
||||
height: 46px;
|
||||
padding-bottom: 64px;
|
||||
padding-bottom: 40px;
|
||||
|
||||
svg {
|
||||
path:last-child {
|
||||
|
@ -23,7 +23,7 @@ export interface MediaViewerProps {
|
||||
|
||||
playlistPos: number;
|
||||
|
||||
getIcon: (size: number, ext: string, ...arg: any) => any;
|
||||
getIcon: (size: number, ext: string, ...arg: any) => string;
|
||||
|
||||
onClose: VoidFunction;
|
||||
onError?: VoidFunction;
|
||||
|
@ -0,0 +1,112 @@
|
||||
import React from "react";
|
||||
|
||||
import MediaZoomInIcon from "PUBLIC_DIR/images/media.zoomin.react.svg";
|
||||
import MediaZoomOutIcon from "PUBLIC_DIR/images/media.zoomout.react.svg";
|
||||
import MediaRotateLeftIcon from "PUBLIC_DIR/images/media.rotateleft.react.svg";
|
||||
import MediaRotateRightIcon from "PUBLIC_DIR/images/media.rotateright.react.svg";
|
||||
import MediaDeleteIcon from "PUBLIC_DIR/images/media.delete.react.svg";
|
||||
import MediaDownloadIcon from "PUBLIC_DIR/images/download.react.svg";
|
||||
import MediaFavoriteIcon from "PUBLIC_DIR/images/favorite.react.svg";
|
||||
import ViewerSeparator from "PUBLIC_DIR/images/viewer.separator.react.svg";
|
||||
|
||||
export const getCustomToolbar = (
|
||||
onDeleteClick: VoidFunction,
|
||||
onDownloadClick: VoidFunction
|
||||
) => {
|
||||
return [
|
||||
{
|
||||
key: "zoomOut",
|
||||
percent: true,
|
||||
actionType: 2,
|
||||
render: (
|
||||
<div className="iconContainer zoomOut">
|
||||
<MediaZoomOutIcon size="scale" />
|
||||
</div>
|
||||
),
|
||||
},
|
||||
{
|
||||
key: "percent",
|
||||
actionType: 999,
|
||||
},
|
||||
{
|
||||
key: "zoomIn",
|
||||
actionType: 1,
|
||||
render: (
|
||||
<div className="iconContainer zoomIn">
|
||||
<MediaZoomInIcon size="scale" />
|
||||
</div>
|
||||
),
|
||||
},
|
||||
{
|
||||
key: "rotateLeft",
|
||||
actionType: 5,
|
||||
render: (
|
||||
<div className="iconContainer rotateLeft">
|
||||
<MediaRotateLeftIcon size="scale" />
|
||||
</div>
|
||||
),
|
||||
},
|
||||
{
|
||||
key: "rotateRight",
|
||||
actionType: 6,
|
||||
render: (
|
||||
<div className="iconContainer rotateRight">
|
||||
<MediaRotateRightIcon size="scale" />
|
||||
</div>
|
||||
),
|
||||
},
|
||||
{
|
||||
key: "separator download-separator",
|
||||
actionType: -1,
|
||||
noHover: true,
|
||||
render: (
|
||||
<div className="separator" style={{ height: "16px" }}>
|
||||
<ViewerSeparator size="scale" />
|
||||
</div>
|
||||
),
|
||||
},
|
||||
{
|
||||
key: "download",
|
||||
actionType: 102,
|
||||
render: (
|
||||
<div className="iconContainer download" style={{ height: "16px" }}>
|
||||
<MediaDownloadIcon size="scale" />
|
||||
</div>
|
||||
),
|
||||
onClick: onDownloadClick,
|
||||
},
|
||||
{
|
||||
key: "context-separator",
|
||||
actionType: -1,
|
||||
noHover: true,
|
||||
render: (
|
||||
<div className="separator" style={{ height: "16px" }}>
|
||||
<ViewerSeparator size="scale" />
|
||||
</div>
|
||||
),
|
||||
},
|
||||
{
|
||||
key: "context-menu",
|
||||
actionType: -1,
|
||||
},
|
||||
{
|
||||
key: "delete",
|
||||
actionType: 103,
|
||||
render: (
|
||||
<div className="iconContainer viewer-delete">
|
||||
<MediaDeleteIcon size="scale" />
|
||||
</div>
|
||||
),
|
||||
onClick: onDeleteClick,
|
||||
},
|
||||
{
|
||||
key: "favorite",
|
||||
actionType: 104,
|
||||
render: (
|
||||
<div className="iconContainer viewer-favorite">
|
||||
<MediaFavoriteIcon size="scale" />
|
||||
</div>
|
||||
),
|
||||
},
|
||||
];
|
||||
};
|
@ -1,4 +1,9 @@
|
||||
import { NullOrUndefined, PlaylistType } from "../types";
|
||||
import {
|
||||
ContextMenuModel,
|
||||
NullOrUndefined,
|
||||
PlaylistType,
|
||||
SeparatorType,
|
||||
} from "../types";
|
||||
|
||||
export const mediaTypes = Object.freeze({
|
||||
audio: 1,
|
||||
@ -57,3 +62,7 @@ export const findNearestIndex = (
|
||||
}
|
||||
return found;
|
||||
};
|
||||
|
||||
export const isSeparator = (arg: ContextMenuModel): arg is SeparatorType => {
|
||||
return arg?.isSeparator;
|
||||
};
|
||||
|
@ -1,7 +1,7 @@
|
||||
import { isMobileOnly } from "react-device-detect";
|
||||
import React, { useState, useCallback, useMemo, useEffect } from "react";
|
||||
|
||||
import ImageViewer from "./sub-components/image-viewer";
|
||||
import ViewerWrapper from "./sub-components/ViewerWrapper";
|
||||
|
||||
import { MediaViewerProps } from "./MediaViewer.props";
|
||||
import { FileStatus } from "@docspace/common/constants";
|
||||
@ -267,17 +267,24 @@ function MediaViewer({
|
||||
return 0 <= posExt ? fileTitle.substring(posExt).trim().toLowerCase() : "";
|
||||
}, []);
|
||||
|
||||
let lastRemovedFileId: null | number = null;
|
||||
|
||||
const onDelete = () => {
|
||||
const { playlist, onDelete } = props;
|
||||
|
||||
let currentFileId = playlist.find((file) => file.id === playlistPos)
|
||||
?.fileId;
|
||||
|
||||
if (currentFileId === lastRemovedFileId) return;
|
||||
|
||||
const canDelete = targetFile?.security?.Delete;
|
||||
|
||||
if (!canDelete) return;
|
||||
|
||||
if (!isNullOrUndefined(currentFileId)) onDelete(currentFileId);
|
||||
if (!isNullOrUndefined(currentFileId)) {
|
||||
onDelete(currentFileId);
|
||||
lastRemovedFileId = currentFileId;
|
||||
}
|
||||
};
|
||||
|
||||
const onDownload = () => {
|
||||
@ -425,7 +432,7 @@ function MediaViewer({
|
||||
return (
|
||||
<>
|
||||
{canOpen && (
|
||||
<ImageViewer
|
||||
<ViewerWrapper
|
||||
userAccess={props.userAccess}
|
||||
visible={props.visible}
|
||||
title={title}
|
||||
|
@ -0,0 +1,6 @@
|
||||
import styled from "styled-components";
|
||||
import DropDown from "@docspace/components/drop-down";
|
||||
|
||||
export const StyledDropDown = styled(DropDown)`
|
||||
background: #333;
|
||||
`;
|
@ -0,0 +1,16 @@
|
||||
import styled from "styled-components";
|
||||
import DropDownItem from "@docspace/components/drop-down-item";
|
||||
|
||||
export const StyledDropDownItem = styled(DropDownItem)`
|
||||
color: #fff;
|
||||
|
||||
.drop-down-item_icon svg {
|
||||
path {
|
||||
fill: #fff !important;
|
||||
}
|
||||
}
|
||||
|
||||
&:hover {
|
||||
background: #444;
|
||||
}
|
||||
`;
|
@ -0,0 +1,33 @@
|
||||
import { ContextMenuModel, PlaylistType } from "../../types";
|
||||
|
||||
interface ViewerWrapperProps {
|
||||
userAccess: boolean;
|
||||
visible: boolean;
|
||||
title: string;
|
||||
images: { src: string; alt: string }[];
|
||||
inactive: boolean;
|
||||
playlist: PlaylistType[];
|
||||
playlistPos: number;
|
||||
|
||||
isFavorite: boolean;
|
||||
isImage: boolean;
|
||||
isAudio: boolean;
|
||||
isVideo: boolean;
|
||||
isPreviewFile: boolean;
|
||||
|
||||
archiveRoom: boolean;
|
||||
|
||||
errorTitle: string;
|
||||
headerIcon: string;
|
||||
audioIcon: string;
|
||||
|
||||
onClose: VoidFunction;
|
||||
onPrevClick: VoidFunction;
|
||||
onNextClick: VoidFunction;
|
||||
onDeleteClick: VoidFunction;
|
||||
onDownloadClick: VoidFunction;
|
||||
onSetSelectionFile: VoidFunction;
|
||||
contextModel: () => ContextMenuModel[];
|
||||
}
|
||||
|
||||
export default ViewerWrapperProps;
|
@ -0,0 +1,120 @@
|
||||
import React, { useMemo, memo, useCallback } from "react";
|
||||
import equal from "fast-deep-equal/react";
|
||||
|
||||
import { Viewer } from "@docspace/components/viewer";
|
||||
import { isSeparator } from "../../helpers";
|
||||
import { getCustomToolbar } from "../../helpers/getCustomToolbar";
|
||||
import { ContextMenuModel } from "../../types";
|
||||
|
||||
import { StyledDropDown } from "../StyledDropDown";
|
||||
import { StyledDropDownItem } from "../StyledDropDownItem";
|
||||
import ViewerWrapperProps from "./ViewerWrapper.props";
|
||||
|
||||
const DefaultSpeedZoom = 0.25;
|
||||
|
||||
function ViewerWrapper(props: ViewerWrapperProps) {
|
||||
const onClickContextItem = useCallback(
|
||||
(item: ContextMenuModel) => {
|
||||
if (isSeparator(item)) return;
|
||||
item.onClick();
|
||||
props.onClose();
|
||||
},
|
||||
[props.onClose]
|
||||
);
|
||||
|
||||
const generateContextMenu = (
|
||||
isOpen: boolean,
|
||||
right: string,
|
||||
bottom: string
|
||||
) => {
|
||||
const model = props.contextModel();
|
||||
|
||||
return (
|
||||
<StyledDropDown
|
||||
open={isOpen}
|
||||
isDefaultMode={false}
|
||||
directionY="top"
|
||||
directionX="right"
|
||||
fixedDirection={true}
|
||||
withBackdrop={false}
|
||||
manualY={(bottom || "63") + "px"}
|
||||
manualX={(right || "-31") + "px"}
|
||||
>
|
||||
{model.map((item) => {
|
||||
if (item.disabled) return;
|
||||
const isItemSeparator = isSeparator(item);
|
||||
|
||||
return (
|
||||
<StyledDropDownItem
|
||||
className={`${item.isSeparator ? "is-separator" : ""}`}
|
||||
key={item.key}
|
||||
label={isItemSeparator ? undefined : item.label}
|
||||
icon={!isItemSeparator && item.icon ? item.icon : ""}
|
||||
onClick={() => onClickContextItem(item)}
|
||||
/>
|
||||
);
|
||||
})}
|
||||
</StyledDropDown>
|
||||
);
|
||||
};
|
||||
|
||||
const toolbars = useMemo(() => {
|
||||
const {
|
||||
onDeleteClick,
|
||||
onDownloadClick,
|
||||
playlist,
|
||||
playlistPos,
|
||||
userAccess,
|
||||
} = props;
|
||||
|
||||
const customToolbar = getCustomToolbar(onDeleteClick, onDownloadClick);
|
||||
|
||||
const canShare = playlist[playlistPos].canShare;
|
||||
const toolbars =
|
||||
!canShare && userAccess
|
||||
? customToolbar.filter(
|
||||
(x) => x.key !== "share" && x.key !== "share-separator"
|
||||
)
|
||||
: customToolbar.filter((x) => x.key !== "delete");
|
||||
|
||||
return toolbars;
|
||||
}, [
|
||||
props.onDeleteClick,
|
||||
props.onDownloadClick,
|
||||
props.playlist,
|
||||
props.playlistPos,
|
||||
props.userAccess,
|
||||
]);
|
||||
|
||||
return (
|
||||
<Viewer
|
||||
title={props.title}
|
||||
images={props.images}
|
||||
isAudio={props.isAudio}
|
||||
isVideo={props.isVideo}
|
||||
visible={props.visible}
|
||||
isImage={props.isImage}
|
||||
playlist={props.playlist}
|
||||
inactive={props.inactive}
|
||||
audioIcon={props.audioIcon}
|
||||
zoomSpeed={DefaultSpeedZoom}
|
||||
errorTitle={props.errorTitle}
|
||||
headerIcon={props.headerIcon}
|
||||
customToolbar={() => toolbars}
|
||||
playlistPos={props.playlistPos}
|
||||
archiveRoom={props.archiveRoom}
|
||||
isPreviewFile={props.isPreviewFile}
|
||||
onMaskClick={props.onClose}
|
||||
onNextClick={props.onNextClick}
|
||||
onPrevClick={props.onPrevClick}
|
||||
contextModel={props.contextModel}
|
||||
onDownloadClick={props.onDownloadClick}
|
||||
generateContextMenu={generateContextMenu}
|
||||
onSetSelectionFile={props.onSetSelectionFile}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
export default memo(ViewerWrapper, (prevProps, nextProps) =>
|
||||
equal(prevProps, nextProps)
|
||||
);
|
@ -87,3 +87,21 @@ export interface IFile {
|
||||
viewUrl: string;
|
||||
webUrl: string;
|
||||
}
|
||||
|
||||
export type ContextMenuType = {
|
||||
id?: string;
|
||||
key: string;
|
||||
label: string;
|
||||
icon: string;
|
||||
disabled: boolean;
|
||||
onClick: VoidFunction;
|
||||
isSeparator?: undefined;
|
||||
};
|
||||
|
||||
export type SeparatorType = {
|
||||
key: string;
|
||||
isSeparator: boolean;
|
||||
disabled: boolean;
|
||||
};
|
||||
|
||||
export type ContextMenuModel = ContextMenuType | SeparatorType;
|
||||
|
@ -19,6 +19,7 @@ import {
|
||||
isDesktop as isDesktopUtils,
|
||||
} from "@docspace/components/utils/device";
|
||||
import ToggleInfoPanelButton from "./sub-components/toggle-infopanel-btn";
|
||||
import TrashWarning from "./sub-components/trash-warning";
|
||||
|
||||
const Navigation = ({
|
||||
tReady,
|
||||
@ -33,6 +34,7 @@ const Navigation = ({
|
||||
getContextOptionsPlus,
|
||||
getContextOptionsFolder,
|
||||
onBackToParentFolder,
|
||||
isTrashFolder,
|
||||
isRecycleBinFolder,
|
||||
isEmptyFilesList,
|
||||
clearTrash,
|
||||
@ -168,6 +170,7 @@ const Navigation = ({
|
||||
isRootFolder={isRootFolder}
|
||||
canCreate={canCreate}
|
||||
isTabletView={isTabletView}
|
||||
isTrashFolder={isTrashFolder}
|
||||
isRecycleBinFolder={isRecycleBinFolder}
|
||||
isDesktop={isDesktop}
|
||||
isDesktopClient={isDesktopClient}
|
||||
@ -200,6 +203,9 @@ const Navigation = ({
|
||||
onPlusClick={onPlusClick}
|
||||
/>
|
||||
</StyledContainer>
|
||||
{isTrashFolder && !isEmptyPage && (
|
||||
<TrashWarning title={titles.trashWarning} />
|
||||
)}
|
||||
{infoPanelIsVisible && (
|
||||
<ToggleInfoPanelButton
|
||||
id="info-panel-toggle--open"
|
||||
|
@ -9,7 +9,7 @@ import {
|
||||
|
||||
const StyledContainer = styled.div`
|
||||
${(props) =>
|
||||
!props.isDropBox &&
|
||||
!props.isDropBoxComponent &&
|
||||
props.isDesktop &&
|
||||
css`
|
||||
width: fit-content;
|
||||
@ -26,6 +26,7 @@ const StyledContainer = styled.div`
|
||||
height: 100%;
|
||||
${(props) =>
|
||||
props.isDesktopClient &&
|
||||
props.isDropBoxComponent &&
|
||||
css`
|
||||
max-height: 32px;
|
||||
`}
|
||||
|
@ -90,7 +90,7 @@ StyledInfoPanelToggleWrapper.defaultProps = { theme: Base };
|
||||
|
||||
const ControlButtons = ({
|
||||
personal,
|
||||
isDropBox,
|
||||
isDropBoxComponent,
|
||||
isRootFolder,
|
||||
canCreate,
|
||||
getContextOptionsFolder,
|
||||
@ -112,7 +112,7 @@ const ControlButtons = ({
|
||||
};
|
||||
|
||||
return (
|
||||
<StyledContainer isDropBox={isDropBox}>
|
||||
<StyledContainer isDropBoxComponent={isDropBoxComponent}>
|
||||
{(!isRootFolder && canCreate) ||
|
||||
(isRecycleBinFolder && !isEmptyFilesList) ? (
|
||||
<>
|
||||
|
@ -156,7 +156,7 @@ const DropBox = React.forwardRef(
|
||||
>
|
||||
<StyledContainer
|
||||
canCreate={canCreate}
|
||||
isDropBox={true}
|
||||
isDropBoxComponent={true}
|
||||
isInfoPanelVisible={isInfoPanelVisible}
|
||||
isDesktopClient={isDesktopClient}
|
||||
>
|
||||
@ -169,7 +169,7 @@ const DropBox = React.forwardRef(
|
||||
isDesktop={isDesktop}
|
||||
personal={personal}
|
||||
isRootFolder={isRootFolder}
|
||||
isDropBox={true}
|
||||
isDropBoxComponent={true}
|
||||
canCreate={canCreate}
|
||||
getContextOptionsFolder={getContextOptionsFolder}
|
||||
getContextOptionsPlus={getContextOptionsPlus}
|
||||
|
@ -0,0 +1,47 @@
|
||||
import React from "react";
|
||||
import styled, { css } from "styled-components";
|
||||
import { tablet } from "@docspace/components/utils/device";
|
||||
|
||||
const StyledTrashWarning = styled.div`
|
||||
box-sizing: border-box;
|
||||
height: 32px;
|
||||
padding: 8px 12px;
|
||||
border-radius: 6px;
|
||||
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: left;
|
||||
|
||||
font-weight: 400;
|
||||
font-size: 12px;
|
||||
line-height: 16px;
|
||||
|
||||
color: ${({ theme }) => theme.section.header.trashErasureLabelText};
|
||||
background: ${({ theme }) =>
|
||||
theme.section.header.trashErasureLabelBackground};
|
||||
|
||||
${({ isTabletView }) =>
|
||||
!isTabletView
|
||||
? css`
|
||||
@media ${tablet} {
|
||||
display: none;
|
||||
}
|
||||
`
|
||||
: css`
|
||||
margin-bottom: 16px;
|
||||
display: none;
|
||||
@media ${tablet} {
|
||||
display: flex;
|
||||
}
|
||||
`}
|
||||
`;
|
||||
|
||||
const TrashWarning = ({ title, isTabletView }) => {
|
||||
return (
|
||||
<StyledTrashWarning className="trash-warning" isTabletView={isTabletView}>
|
||||
{title}
|
||||
</StyledTrashWarning>
|
||||
);
|
||||
};
|
||||
|
||||
export default TrashWarning;
|
@ -225,6 +225,7 @@ class Section extends React.Component {
|
||||
isHeaderVisible={isHeaderVisible}
|
||||
viewAs={viewAs}
|
||||
showText={showText}
|
||||
isEmptyPage={this.props.isEmptyPage}
|
||||
>
|
||||
{sectionHeaderContent
|
||||
? sectionHeaderContent.props.children
|
||||
@ -261,6 +262,7 @@ class Section extends React.Component {
|
||||
viewAs={viewAs}
|
||||
showText={showText}
|
||||
settingsStudio={settingsStudio}
|
||||
isEmptyPage={this.props.isEmptyPage}
|
||||
>
|
||||
{sectionHeaderContent
|
||||
? sectionHeaderContent.props.children
|
||||
@ -387,6 +389,7 @@ Section.propTypes = {
|
||||
isHeaderVisible: PropTypes.bool,
|
||||
isInfoPanelAvailable: PropTypes.bool,
|
||||
settingsStudio: PropTypes.bool,
|
||||
isEmptyPage: PropTypes.bool,
|
||||
};
|
||||
|
||||
Section.defaultProps = {
|
||||
|
@ -76,15 +76,22 @@ const StyledSectionContainer = styled.section`
|
||||
.layout-progress-bar {
|
||||
position: fixed;
|
||||
right: ${(props) =>
|
||||
props.isInfoPanelVisible && !isMobile ? "416px" : "15px"};
|
||||
bottom: 21px;
|
||||
props.isInfoPanelVisible && !isMobile ? "424px" : "24px"};
|
||||
bottom: 24px;
|
||||
}
|
||||
|
||||
.layout-progress-bar_close-icon {
|
||||
position: fixed;
|
||||
right: ${(props) =>
|
||||
props.isInfoPanelVisible && !isMobile ? "480px" : "80px"};
|
||||
bottom: 36px;
|
||||
}
|
||||
|
||||
.layout-progress-second-bar {
|
||||
position: fixed;
|
||||
right: ${(props) =>
|
||||
props.isInfoPanelVisible && !isMobile ? "416px" : "15px"};
|
||||
bottom: 83px;
|
||||
props.isInfoPanelVisible && !isMobile ? "424px" : "24px"};
|
||||
bottom: 96px;
|
||||
}
|
||||
|
||||
${(props) =>
|
||||
|
@ -41,6 +41,16 @@ const StyledSectionHeader = styled.div`
|
||||
min-height: 53px;
|
||||
`}
|
||||
|
||||
${({ isTrashFolder, isEmptyPage }) =>
|
||||
isTrashFolder &&
|
||||
!isEmptyPage &&
|
||||
css`
|
||||
@media ${tablet} {
|
||||
height: 109px;
|
||||
min-height: 109px;
|
||||
}
|
||||
`}
|
||||
|
||||
padding-right: 20px;
|
||||
|
||||
box-sizing: border-box;
|
||||
@ -87,13 +97,24 @@ const StyledSectionHeader = styled.div`
|
||||
StyledSectionHeader.defaultProps = { theme: Base };
|
||||
|
||||
const SectionHeader = (props) => {
|
||||
const { viewAs, settingsStudio = false, className, ...rest } = props;
|
||||
const {
|
||||
viewAs,
|
||||
settingsStudio = false,
|
||||
className,
|
||||
isEmptyPage,
|
||||
...rest
|
||||
} = props;
|
||||
|
||||
const pathname = window.location.pathname.toLowerCase();
|
||||
const isTrashFolder = pathname.indexOf("trash") !== -1;
|
||||
|
||||
return (
|
||||
<StyledSectionHeader
|
||||
className={`section-header ${className}`}
|
||||
isEmptyPage={isEmptyPage}
|
||||
viewAs={viewAs}
|
||||
settingsStudio={settingsStudio}
|
||||
isTrashFolder={isTrashFolder}
|
||||
{...rest}
|
||||
/>
|
||||
);
|
||||
|
@ -188,12 +188,12 @@ class SettingsStore {
|
||||
this.greetingSettings = greetingSettings;
|
||||
};
|
||||
|
||||
getSettings = async () => {
|
||||
getSettings = async (withPassword) => {
|
||||
let newSettings = null;
|
||||
|
||||
if (window?.__ASC_INITIAL_EDITOR_STATE__?.portalSettings)
|
||||
newSettings = window.__ASC_INITIAL_EDITOR_STATE__.portalSettings;
|
||||
else newSettings = await api.settings.getSettings();
|
||||
else newSettings = await api.settings.getSettings(withPassword);
|
||||
|
||||
if (window["AscDesktopEditor"] !== undefined || this.personal) {
|
||||
const dp = combineUrl(
|
||||
|
@ -2049,6 +2049,8 @@ const Base = {
|
||||
header: {
|
||||
backgroundColor: white,
|
||||
background: `linear-gradient(180deg,#ffffff 2.81%,rgba(255, 255, 255, 0.91) 63.03%,rgba(255, 255, 255, 0) 100%)`,
|
||||
trashErasureLabelBackground: "#f8f9f9",
|
||||
trashErasureLabelText: "#555f65",
|
||||
},
|
||||
},
|
||||
|
||||
|
@ -2040,6 +2040,8 @@ const Dark = {
|
||||
header: {
|
||||
backgroundColor: black,
|
||||
background: `linear-gradient(180deg, #333333 2.81%, rgba(51, 51, 51, 0.9) 63.03%, rgba(51, 51, 51, 0) 100%);`,
|
||||
trashErasureLabelBackground: "#292929",
|
||||
trashErasureLabelText: "#ADADAD",
|
||||
},
|
||||
},
|
||||
|
||||
|
@ -80,12 +80,12 @@ export const Viewer = (props) => {
|
||||
};
|
||||
}
|
||||
return () => document.removeEventListener("touchstart", onTouch);
|
||||
}, [isPlay, isOpenContextMenu]);
|
||||
}, [isPlay, isOpenContextMenu, isImage]);
|
||||
|
||||
function resetTimer() {
|
||||
setPanelVisible(true);
|
||||
clearTimeout(timer);
|
||||
timer = setTimeout(() => setPanelVisible(false), 5000);
|
||||
timer = setTimeout(() => setPanelVisible(false), 2500);
|
||||
setImageTimer(timer);
|
||||
}
|
||||
|
||||
|
@ -240,6 +240,10 @@ const StyledMobileDetails = styled.div`
|
||||
.title {
|
||||
font-weight: 600;
|
||||
margin-top: 6px;
|
||||
width: calc(100% - 100px);
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
`;
|
||||
|
||||
|
@ -907,7 +907,7 @@ export default function ViewerPlayer(props) {
|
||||
}
|
||||
if (isMobileOnly && videoRef.current && displayUI) {
|
||||
clearTimeout(globalTimer);
|
||||
setGlobalTimer(setTimeout(() => setPanelVisible(false), 5000));
|
||||
setGlobalTimer(setTimeout(() => setPanelVisible(false), 2500));
|
||||
}
|
||||
}, [displayUI, isOpenContextMenu, state.isControlTouch, props.isPlay]);
|
||||
|
||||
|
@ -32,11 +32,17 @@ export default function template(
|
||||
});
|
||||
}
|
||||
|
||||
const initialEditorStateStringify = JSON.stringify(initialEditorState);
|
||||
|
||||
const initialEditorStateString = initialEditorStateStringify.includes(
|
||||
"</script>"
|
||||
)
|
||||
? initialEditorStateStringify.replaceAll("</script>", "<\\/script>")
|
||||
: initialEditorStateStringify;
|
||||
|
||||
const scripts = `
|
||||
<script id="__ASC_INITIAL_EDITOR_STATE__">
|
||||
window.__ASC_INITIAL_EDITOR_STATE__ = ${JSON.stringify(
|
||||
initialEditorState
|
||||
)}
|
||||
window.__ASC_INITIAL_EDITOR_STATE__ = ${initialEditorStateString}
|
||||
</script>
|
||||
<script id="__ASC_INITIAL_EDITOR_I18N__">
|
||||
window.initialI18nStoreASC = ${JSON.stringify(initialI18nStoreASC)}
|
||||
|
@ -1,7 +1,7 @@
|
||||
import React, { useState, useCallback, useEffect } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { inject, observer } from "mobx-react";
|
||||
import { ButtonsWrapper, LoginFormWrapper } from "./StyledLogin";
|
||||
import { ButtonsWrapper, LoginFormWrapper, LoginContent } from "./StyledLogin";
|
||||
import Text from "@docspace/components/text";
|
||||
import SocialButton from "@docspace/components/social-button";
|
||||
import {
|
||||
@ -210,77 +210,80 @@ const Login: React.FC<ILoginProps> = ({
|
||||
isDesktop={isDesktopEditor}
|
||||
bgPattern={bgPattern}
|
||||
>
|
||||
<ColorTheme themeId={ThemeType.LinkForgotPassword} theme={theme}>
|
||||
<img src={logoUrl} className="logo-wrapper" />
|
||||
<Text
|
||||
fontSize="23px"
|
||||
fontWeight={700}
|
||||
textAlign="center"
|
||||
className="greeting-title"
|
||||
>
|
||||
{greetingSettings}
|
||||
</Text>
|
||||
<FormWrapper id="login-form" theme={theme}>
|
||||
{ssoExists() && <ButtonsWrapper>{ssoButton()}</ButtonsWrapper>}
|
||||
{oauthDataExists() && (
|
||||
<>
|
||||
<ButtonsWrapper>{providerButtons()}</ButtonsWrapper>
|
||||
{providers && providers.length > 2 && (
|
||||
<Link
|
||||
isHovered
|
||||
type="action"
|
||||
fontSize="13px"
|
||||
fontWeight="600"
|
||||
color="#3B72A7"
|
||||
className="more-label"
|
||||
onClick={moreAuthOpen}
|
||||
>
|
||||
{t("Common:ShowMore")}
|
||||
</Link>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
{(oauthDataExists() || ssoExists()) && (
|
||||
<div className="line">
|
||||
<Text className="or-label">{t("Or")}</Text>
|
||||
</div>
|
||||
)}
|
||||
<LoginForm
|
||||
isDesktop={!!isDesktopEditor}
|
||||
isLoading={isLoading}
|
||||
hashSettings={portalSettings?.passwordHash}
|
||||
setIsLoading={setIsLoading}
|
||||
onRecoverDialogVisible={onRecoverDialogVisible}
|
||||
match={match}
|
||||
enableAdmMess={enableAdmMess}
|
||||
<div className="bg-cover"></div>
|
||||
<LoginContent>
|
||||
<ColorTheme themeId={ThemeType.LinkForgotPassword} theme={theme}>
|
||||
<img src={logoUrl} className="logo-wrapper" />
|
||||
<Text
|
||||
fontSize="23px"
|
||||
fontWeight={700}
|
||||
textAlign="center"
|
||||
className="greeting-title"
|
||||
>
|
||||
{greetingSettings}
|
||||
</Text>
|
||||
<FormWrapper id="login-form" theme={theme}>
|
||||
{ssoExists() && <ButtonsWrapper>{ssoButton()}</ButtonsWrapper>}
|
||||
{oauthDataExists() && (
|
||||
<>
|
||||
<ButtonsWrapper>{providerButtons()}</ButtonsWrapper>
|
||||
{providers && providers.length > 2 && (
|
||||
<Link
|
||||
isHovered
|
||||
type="action"
|
||||
fontSize="13px"
|
||||
fontWeight="600"
|
||||
color="#3B72A7"
|
||||
className="more-label"
|
||||
onClick={moreAuthOpen}
|
||||
>
|
||||
{t("Common:ShowMore")}
|
||||
</Link>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
{(oauthDataExists() || ssoExists()) && (
|
||||
<div className="line">
|
||||
<Text className="or-label">{t("Or")}</Text>
|
||||
</div>
|
||||
)}
|
||||
<LoginForm
|
||||
isDesktop={!!isDesktopEditor}
|
||||
isLoading={isLoading}
|
||||
hashSettings={portalSettings?.passwordHash}
|
||||
setIsLoading={setIsLoading}
|
||||
onRecoverDialogVisible={onRecoverDialogVisible}
|
||||
match={match}
|
||||
enableAdmMess={enableAdmMess}
|
||||
/>
|
||||
</FormWrapper>
|
||||
<Toast />
|
||||
<MoreLoginModal
|
||||
visible={moreAuthVisible}
|
||||
onClose={moreAuthClose}
|
||||
providers={providers}
|
||||
onSocialLoginClick={onSocialButtonClick}
|
||||
ssoLabel={ssoLabel}
|
||||
ssoUrl={ssoUrl}
|
||||
t={t}
|
||||
/>
|
||||
</FormWrapper>
|
||||
<Toast />
|
||||
<MoreLoginModal
|
||||
visible={moreAuthVisible}
|
||||
onClose={moreAuthClose}
|
||||
providers={providers}
|
||||
onSocialLoginClick={onSocialButtonClick}
|
||||
ssoLabel={ssoLabel}
|
||||
ssoUrl={ssoUrl}
|
||||
t={t}
|
||||
/>
|
||||
|
||||
<RecoverAccessModalDialog
|
||||
visible={recoverDialogVisible}
|
||||
onClose={onRecoverDialogVisible}
|
||||
textBody={t("RecoverTextBody")}
|
||||
emailPlaceholderText={t("RecoverContactEmailPlaceholder")}
|
||||
id="recover-access-modal"
|
||||
/>
|
||||
</ColorTheme>
|
||||
{!checkIsSSR() && enabledJoin && (
|
||||
<Register
|
||||
id="login_register"
|
||||
enabledJoin={enabledJoin}
|
||||
currentColorScheme={currentColorScheme}
|
||||
/>
|
||||
)}
|
||||
<RecoverAccessModalDialog
|
||||
visible={recoverDialogVisible}
|
||||
onClose={onRecoverDialogVisible}
|
||||
textBody={t("RecoverTextBody")}
|
||||
emailPlaceholderText={t("RecoverContactEmailPlaceholder")}
|
||||
id="recover-access-modal"
|
||||
/>
|
||||
</ColorTheme>
|
||||
{!checkIsSSR() && enabledJoin && (
|
||||
<Register
|
||||
id="login_register"
|
||||
enabledJoin={enabledJoin}
|
||||
currentColorScheme={currentColorScheme}
|
||||
/>
|
||||
)}
|
||||
</LoginContent>{" "}
|
||||
</LoginFormWrapper>
|
||||
);
|
||||
};
|
||||
|
@ -1,5 +1,5 @@
|
||||
import styled, { css } from "styled-components";
|
||||
import { tablet } from "@docspace/components/utils/device";
|
||||
import { tablet, hugeMobile } from "@docspace/components/utils/device";
|
||||
|
||||
export const ButtonsWrapper = styled.div`
|
||||
display: flex;
|
||||
@ -12,8 +12,6 @@ export const ButtonsWrapper = styled.div`
|
||||
}
|
||||
`;
|
||||
|
||||
|
||||
|
||||
interface ILoginFormWrapperProps {
|
||||
enabledJoin?: boolean;
|
||||
isDesktop?: boolean;
|
||||
@ -29,20 +27,44 @@ export const LoginFormWrapper = styled.div`
|
||||
: css`1fr 68px`
|
||||
: css`1fr`};
|
||||
width: 100%;
|
||||
height: 100vh;
|
||||
box-sizing: border-box;
|
||||
|
||||
background-image: ${props => props.bgPattern};
|
||||
background-repeat: no-repeat;
|
||||
background-attachment: fixed;
|
||||
background-size: 100% 100%;
|
||||
|
||||
@media (max-width: 1024px) {
|
||||
background-size: cover;
|
||||
}
|
||||
|
||||
@media (max-width: 428px) {
|
||||
background-image: none;
|
||||
@media ${hugeMobile} {
|
||||
height: calc(100vh - 48px);
|
||||
}
|
||||
|
||||
.bg-cover {
|
||||
background-image: ${props => props.bgPattern};
|
||||
background-repeat: no-repeat;
|
||||
background-attachment: fixed;
|
||||
background-size: cover;
|
||||
position: fixed;
|
||||
top: 0;
|
||||
right: 0;
|
||||
left: 0;
|
||||
bottom: 0;
|
||||
|
||||
@media ${hugeMobile} {
|
||||
background-image: none;
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
export const LoginContent = styled.div`
|
||||
min-height: 100vh;
|
||||
flex: 1 0 auto;
|
||||
flex-direction: column;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
margin: 0 auto;
|
||||
-webkit-box-orient: vertical;
|
||||
-webkit-box-direction: normal;
|
||||
|
||||
@media ${hugeMobile} {
|
||||
min-height: 100%;
|
||||
justify-content: start;
|
||||
}
|
||||
|
||||
`;
|
||||
|
||||
|
@ -170,9 +170,11 @@ public class FileDtoHelper : FileEntryDtoHelper
|
||||
|
||||
result.ThumbnailStatus = file.ThumbnailStatus;
|
||||
|
||||
var cacheKey = Math.Abs(result.Updated.GetHashCode());
|
||||
|
||||
if (file.ThumbnailStatus == Thumbnail.Created)
|
||||
{
|
||||
result.ThumbnailUrl = _commonLinkUtility.GetFullAbsolutePath(_filesLinkUtility.GetFileThumbnailUrl(file.Id, file.Version));
|
||||
result.ThumbnailUrl = _commonLinkUtility.GetFullAbsolutePath(_filesLinkUtility.GetFileThumbnailUrl(file.Id, file.Version)) + $"&hash={cacheKey}";
|
||||
}
|
||||
}
|
||||
catch (Exception)
|
||||
|
@ -27,29 +27,29 @@
|
||||
using static ASC.Files.Core.Security.FileSecurity;
|
||||
|
||||
namespace ASC.Files.Core.ApiModels.ResponseDto;
|
||||
|
||||
|
||||
public abstract class FileEntryDto
|
||||
{
|
||||
protected internal abstract FileEntryType EntryType { get; }
|
||||
public string Title { get; set; }
|
||||
public FileShare Access { get; set; }
|
||||
public bool Shared { get; set; }
|
||||
public ApiDateTime Created { get; set; }
|
||||
public string Title { get; set; }
|
||||
public FileShare Access { get; set; }
|
||||
public bool Shared { get; set; }
|
||||
public ApiDateTime Created { get; set; }
|
||||
public EmployeeDto CreatedBy { get; set; }
|
||||
|
||||
private ApiDateTime _updated;
|
||||
private ApiDateTime _updated;
|
||||
public ApiDateTime Updated
|
||||
{
|
||||
get => _updated < Created ? Created : _updated;
|
||||
set => _updated = value;
|
||||
}
|
||||
|
||||
public FolderType RootFolderType { get; set; }
|
||||
public EmployeeDto UpdatedBy { get; set; }
|
||||
public bool? ProviderItem { get; set; }
|
||||
public string ProviderKey { get; set; }
|
||||
public ApiDateTime AutoDelete { get; set; }
|
||||
public FolderType RootFolderType { get; set; }
|
||||
public EmployeeDto UpdatedBy { get; set; }
|
||||
public bool? ProviderItem { get; set; }
|
||||
public string ProviderKey { get; set; }
|
||||
public int? ProviderId { get; set; }
|
||||
|
||||
|
||||
protected FileEntryDto(FileEntry entry)
|
||||
{
|
||||
Title = entry.Title;
|
||||
@ -60,24 +60,32 @@ public abstract class FileEntryDto
|
||||
ProviderKey = entry.ProviderKey;
|
||||
ProviderId = entry.ProviderId.NullIfDefault();
|
||||
}
|
||||
|
||||
|
||||
protected FileEntryDto() { }
|
||||
}
|
||||
|
||||
|
||||
public abstract class FileEntryDto<T> : FileEntryDto
|
||||
{
|
||||
{
|
||||
public T Id { get; set; }
|
||||
public T RootFolderId { get; set; }
|
||||
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
|
||||
public T OriginId { get; set; }
|
||||
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
|
||||
public T OriginRoomId { get; set; }
|
||||
public string OriginTitle { get; set; }
|
||||
public string OriginRoomTitle { get; set; }
|
||||
public bool CanShare { get; set; }
|
||||
public IDictionary<FilesSecurityActions, bool> Security { get; set; }
|
||||
|
||||
|
||||
protected FileEntryDto(FileEntry<T> entry)
|
||||
: base(entry)
|
||||
{
|
||||
Id = entry.Id;
|
||||
RootFolderId = entry.RootId;
|
||||
}
|
||||
|
||||
|
||||
protected FileEntryDto() { }
|
||||
}
|
||||
|
||||
@ -129,7 +137,12 @@ public class FileEntryDtoHelper
|
||||
ProviderKey = entry.ProviderKey,
|
||||
ProviderId = entry.ProviderId.NullIfDefault(),
|
||||
CanShare = await _fileSharingHelper.CanSetAccessAsync(entry),
|
||||
Security = entry.Security
|
||||
Security = entry.Security,
|
||||
OriginId = entry.OriginId,
|
||||
OriginTitle = entry.OriginTitle,
|
||||
OriginRoomId = entry.OriginRoomId,
|
||||
OriginRoomTitle = entry.OriginRoomTitle,
|
||||
AutoDelete = entry.DeletedPermanentlyOn != default ? _apiDateTimeHelper.Get(entry.DeletedPermanentlyOn) : null
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -105,7 +105,7 @@ public class FilesSettings : ISettings<FilesSettings>
|
||||
HideFavoritesSetting = false,
|
||||
HideTemplatesSetting = false,
|
||||
DownloadTarGzSetting = false,
|
||||
AutomaticallyCleanUpSetting = null,
|
||||
AutomaticallyCleanUpSetting = new AutoCleanUpData { IsAutoCleanUp = true, Gap = DateToAutoCleanUp.ThirtyDays },
|
||||
DefaultSharingAccessRightsSetting = null
|
||||
};
|
||||
}
|
||||
@ -457,4 +457,4 @@ public class FilesSettingsHelper
|
||||
{
|
||||
_settingsManager.SaveForCurrentUser(settings);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -29,250 +29,250 @@ namespace ASC.Files.Core;
|
||||
[Scope]
|
||||
public interface IFileDao<T>
|
||||
{
|
||||
/// <summary>
|
||||
/// Clear the application cache for the specific file
|
||||
/// <summary>
|
||||
/// Clear the application cache for the specific file
|
||||
/// </summary>
|
||||
Task InvalidateCacheAsync(T fileId);
|
||||
/// <summary>
|
||||
/// Receive file
|
||||
/// </summary>
|
||||
/// <param name="fileId">file id</param>
|
||||
/// <summary>
|
||||
/// Receive file
|
||||
/// </summary>
|
||||
/// <param name="fileId">file id</param>
|
||||
/// <returns></returns>
|
||||
Task<File<T>> GetFileAsync(T fileId);
|
||||
|
||||
/// <summary>
|
||||
/// Receive file
|
||||
/// </summary>
|
||||
/// <param name="fileId">file id</param>
|
||||
/// <param name="fileVersion">file version</param>
|
||||
/// <summary>
|
||||
/// Receive file
|
||||
/// </summary>
|
||||
/// <param name="fileId">file id</param>
|
||||
/// <param name="fileVersion">file version</param>
|
||||
/// <returns></returns>
|
||||
Task<File<T>> GetFileAsync(T fileId, int fileVersion);
|
||||
|
||||
/// <summary>
|
||||
/// Receive file
|
||||
/// </summary>
|
||||
/// <param name="parentId">folder id</param>
|
||||
/// <param name="title">file name</param>
|
||||
/// <returns>
|
||||
/// file
|
||||
/// <summary>
|
||||
/// Receive file
|
||||
/// </summary>
|
||||
/// <param name="parentId">folder id</param>
|
||||
/// <param name="title">file name</param>
|
||||
/// <returns>
|
||||
/// file
|
||||
/// </returns>
|
||||
Task<File<T>> GetFileAsync(T parentId, string title);
|
||||
/// <summary>
|
||||
/// Receive last file without forcesave
|
||||
/// </summary>
|
||||
/// <param name="fileId">file id</param>
|
||||
/// <param name="fileVersion"></param>
|
||||
/// <returns></returns>
|
||||
/// <summary>
|
||||
/// Receive last file without forcesave
|
||||
/// </summary>
|
||||
/// <param name="fileId">file id</param>
|
||||
/// <param name="fileVersion"></param>
|
||||
/// <returns></returns>
|
||||
Task<File<T>> GetFileStableAsync(T fileId, int fileVersion = -1);
|
||||
/// <summary>
|
||||
/// Returns all versions of the file
|
||||
/// </summary>
|
||||
/// <param name="fileId"></param>
|
||||
/// <summary>
|
||||
/// Returns all versions of the file
|
||||
/// </summary>
|
||||
/// <param name="fileId"></param>
|
||||
/// <returns></returns>
|
||||
IAsyncEnumerable<File<T>> GetFileHistoryAsync(T fileId);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the file (s) by ID (s)
|
||||
/// </summary>
|
||||
/// <param name="fileIds">id file</param>
|
||||
/// <summary>
|
||||
/// Gets the file (s) by ID (s)
|
||||
/// </summary>
|
||||
/// <param name="fileIds">id file</param>
|
||||
/// <returns></returns>
|
||||
IAsyncEnumerable<File<T>> GetFilesAsync(IEnumerable<T> fileIds);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the file (s) by ID (s) for share
|
||||
/// </summary>
|
||||
/// <param name="fileIds">id file</param>
|
||||
/// <param name="filterType"></param>
|
||||
/// <param name="subjectGroup"></param>
|
||||
/// <param name="subjectID"></param>
|
||||
/// <param name="searchText"></param>
|
||||
/// <param name="searchInContent"></param>
|
||||
/// <returns></returns>
|
||||
/// <summary>
|
||||
/// Gets the file (s) by ID (s) for share
|
||||
/// </summary>
|
||||
/// <param name="fileIds">id file</param>
|
||||
/// <param name="filterType"></param>
|
||||
/// <param name="subjectGroup"></param>
|
||||
/// <param name="subjectID"></param>
|
||||
/// <param name="searchText"></param>
|
||||
/// <param name="searchInContent"></param>
|
||||
/// <returns></returns>
|
||||
IAsyncEnumerable<File<T>> GetFilesFilteredAsync(IEnumerable<T> fileIds, FilterType filterType, bool subjectGroup, Guid subjectID, string searchText, bool searchInContent, bool checkShared = false);
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="parentId"></param>
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="parentId"></param>
|
||||
/// <returns></returns>
|
||||
IAsyncEnumerable<T> GetFilesAsync(T parentId);
|
||||
|
||||
/// <summary>
|
||||
/// Get files in folder
|
||||
/// </summary>
|
||||
/// <param name="parentId">folder id</param>
|
||||
/// <param name="orderBy"></param>
|
||||
/// <param name="filterType">filterType type</param>
|
||||
/// <param name="subjectGroup"></param>
|
||||
/// <param name="subjectID"></param>
|
||||
/// <param name="searchText"> </param>
|
||||
/// <param name="searchInContent"></param>
|
||||
/// <param name="withSubfolders"> </param>
|
||||
/// <returns>list of files</returns>
|
||||
/// <remarks>
|
||||
/// Return only the latest versions of files of a folder
|
||||
/// <summary>
|
||||
/// Get files in folder
|
||||
/// </summary>
|
||||
/// <param name="parentId">folder id</param>
|
||||
/// <param name="orderBy"></param>
|
||||
/// <param name="filterType">filterType type</param>
|
||||
/// <param name="subjectGroup"></param>
|
||||
/// <param name="subjectID"></param>
|
||||
/// <param name="searchText"> </param>
|
||||
/// <param name="searchInContent"></param>
|
||||
/// <param name="withSubfolders"> </param>
|
||||
/// <returns>list of files</returns>
|
||||
/// <remarks>
|
||||
/// Return only the latest versions of files of a folder
|
||||
/// </remarks>
|
||||
IAsyncEnumerable<File<T>> GetFilesAsync(T parentId, OrderBy orderBy, FilterType filterType, bool subjectGroup, Guid subjectID, string searchText, bool searchInContent, bool withSubfolders = false, bool exludeSubject = false);
|
||||
|
||||
/// <summary>
|
||||
/// Get stream of file
|
||||
/// </summary>
|
||||
/// <param name="file"></param>
|
||||
/// <summary>
|
||||
/// Get stream of file
|
||||
/// </summary>
|
||||
/// <param name="file"></param>
|
||||
/// <returns>Stream</returns>
|
||||
Task<Stream> GetFileStreamAsync(File<T> file);
|
||||
|
||||
/// <summary>
|
||||
/// Get stream of file
|
||||
/// </summary>
|
||||
/// <param name="file"></param>
|
||||
/// <param name="offset"></param>
|
||||
/// <summary>
|
||||
/// Get stream of file
|
||||
/// </summary>
|
||||
/// <param name="file"></param>
|
||||
/// <param name="offset"></param>
|
||||
/// <returns>Stream</returns>
|
||||
Task<Stream> GetFileStreamAsync(File<T> file, long offset);
|
||||
|
||||
/// <summary>
|
||||
/// Get presigned uri
|
||||
/// </summary>
|
||||
/// <param name="file"></param>
|
||||
/// <param name="expires"></param>
|
||||
/// <summary>
|
||||
/// Get presigned uri
|
||||
/// </summary>
|
||||
/// <param name="file"></param>
|
||||
/// <param name="expires"></param>
|
||||
/// <returns>Stream uri</returns>
|
||||
Task<Uri> GetPreSignedUriAsync(File<T> file, TimeSpan expires);
|
||||
|
||||
/// <summary>
|
||||
/// Check is supported PreSignedUri
|
||||
/// </summary>
|
||||
/// <param name="file"></param>
|
||||
/// <summary>
|
||||
/// Check is supported PreSignedUri
|
||||
/// </summary>
|
||||
/// <param name="file"></param>
|
||||
/// <returns>Stream uri</returns>
|
||||
Task<bool> IsSupportedPreSignedUriAsync(File<T> file);
|
||||
|
||||
/// <summary>
|
||||
/// Saves / updates the version of the file
|
||||
/// and save stream of file
|
||||
/// </summary>
|
||||
/// <param name="file"></param>
|
||||
/// <param name="fileStream"> </param>
|
||||
/// <returns></returns>
|
||||
/// <remarks>
|
||||
/// Updates the file if:
|
||||
/// - The file comes with the given id
|
||||
/// - The file with that name in the folder / container exists
|
||||
///
|
||||
/// Save in all other cases
|
||||
/// </remarks>
|
||||
/// <summary>
|
||||
/// Saves / updates the version of the file
|
||||
/// and save stream of file
|
||||
/// </summary>
|
||||
/// <param name="file"></param>
|
||||
/// <param name="fileStream"> </param>
|
||||
/// <returns></returns>
|
||||
/// <remarks>
|
||||
/// Updates the file if:
|
||||
/// - The file comes with the given id
|
||||
/// - The file with that name in the folder / container exists
|
||||
///
|
||||
/// Save in all other cases
|
||||
/// </remarks>
|
||||
Task<File<T>> SaveFileAsync(File<T> file, Stream fileStream);
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="file"></param>
|
||||
/// <param name="fileStream"></param>
|
||||
/// <returns></returns>
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="file"></param>
|
||||
/// <param name="fileStream"></param>
|
||||
/// <returns></returns>
|
||||
Task<File<T>> ReplaceFileVersionAsync(File<T> file, Stream fileStream);
|
||||
/// <summary>
|
||||
/// Deletes a file including all previous versions
|
||||
/// </summary>
|
||||
/// <param name="fileId">file id</param>
|
||||
/// <summary>
|
||||
/// Deletes a file including all previous versions
|
||||
/// </summary>
|
||||
/// <param name="fileId">file id</param>
|
||||
Task DeleteFileAsync(T fileId);
|
||||
/// <summary>
|
||||
/// Checks whether or not file
|
||||
/// </summary>
|
||||
/// <param name="title">file name</param>
|
||||
/// <param name="folderId">folder id</param>
|
||||
/// <returns>Returns true if the file exists, otherwise false</returns>
|
||||
/// <summary>
|
||||
/// Checks whether or not file
|
||||
/// </summary>
|
||||
/// <param name="title">file name</param>
|
||||
/// <param name="folderId">folder id</param>
|
||||
/// <returns>Returns true if the file exists, otherwise false</returns>
|
||||
Task<bool> IsExistAsync(string title, object folderId);
|
||||
/// <summary>
|
||||
/// Moves a file or set of files in a folder
|
||||
/// </summary>
|
||||
/// <param name="fileId">file id</param>
|
||||
/// <summary>
|
||||
/// Moves a file or set of files in a folder
|
||||
/// </summary>
|
||||
/// <param name="fileId">file id</param>
|
||||
/// <param name="toFolderId">The ID of the destination folder</param>
|
||||
Task<T> MoveFileAsync(T fileId, T toFolderId);
|
||||
Task<TTo> MoveFileAsync<TTo>(T fileId, TTo toFolderId);
|
||||
Task<string> MoveFileAsync(T fileId, string toFolderId);
|
||||
Task<int> MoveFileAsync(T fileId, int toFolderId);
|
||||
|
||||
/// <summary>
|
||||
/// Copy the files in a folder
|
||||
/// </summary>
|
||||
/// <param name="fileId">file id</param>
|
||||
/// <summary>
|
||||
/// Copy the files in a folder
|
||||
/// </summary>
|
||||
/// <param name="fileId">file id</param>
|
||||
/// <param name="toFolderId">The ID of the destination folder</param>
|
||||
Task<File<T>> CopyFileAsync(T fileId, T toFolderId);
|
||||
Task<File<TTo>> CopyFileAsync<TTo>(T fileId, TTo toFolderId);
|
||||
Task<File<string>> CopyFileAsync(T fileId, string toFolderId);
|
||||
Task<File<int>> CopyFileAsync(T fileId, int toFolderId);
|
||||
|
||||
/// <summary>
|
||||
/// Rename file
|
||||
/// </summary>
|
||||
/// <param name="file"></param>
|
||||
/// <summary>
|
||||
/// Rename file
|
||||
/// </summary>
|
||||
/// <param name="file"></param>
|
||||
/// <param name="newTitle">new name</param>
|
||||
Task<T> FileRenameAsync(File<T> file, string newTitle);
|
||||
|
||||
/// <summary>
|
||||
/// Update comment file
|
||||
/// </summary>
|
||||
/// <param name="fileId">file id</param>
|
||||
/// <param name="fileVersion">file version</param>
|
||||
/// <param name="comment">new comment</param>
|
||||
/// <summary>
|
||||
/// Update comment file
|
||||
/// </summary>
|
||||
/// <param name="fileId">file id</param>
|
||||
/// <param name="fileVersion">file version</param>
|
||||
/// <param name="comment">new comment</param>
|
||||
Task<string> UpdateCommentAsync(T fileId, int fileVersion, string comment);
|
||||
/// <summary>
|
||||
/// Complete file version
|
||||
/// </summary>
|
||||
/// <param name="fileId">file id</param>
|
||||
/// <summary>
|
||||
/// Complete file version
|
||||
/// </summary>
|
||||
/// <param name="fileId">file id</param>
|
||||
/// <param name="fileVersion">file version</param>
|
||||
Task CompleteVersionAsync(T fileId, int fileVersion);
|
||||
/// <summary>
|
||||
/// Continue file version
|
||||
/// </summary>
|
||||
/// <param name="fileId">file id</param>
|
||||
/// <summary>
|
||||
/// Continue file version
|
||||
/// </summary>
|
||||
/// <param name="fileId">file id</param>
|
||||
/// <param name="fileVersion">file version</param>
|
||||
Task ContinueVersionAsync(T fileId, int fileVersion);
|
||||
/// <summary>
|
||||
/// Check the need to use the trash before removing
|
||||
/// </summary>
|
||||
/// <param name="file"></param>
|
||||
/// <returns></returns>
|
||||
/// <summary>
|
||||
/// Check the need to use the trash before removing
|
||||
/// </summary>
|
||||
/// <param name="file"></param>
|
||||
/// <returns></returns>
|
||||
bool UseTrashForRemove(File<T> file);
|
||||
string GetUniqFilePath(File<T> file, string fileTitle);
|
||||
|
||||
#region chunking
|
||||
#region chunking
|
||||
|
||||
Task<ChunkedUploadSession<T>> CreateUploadSessionAsync(File<T> file, long contentLength);
|
||||
Task<File<T>> UploadChunkAsync(ChunkedUploadSession<T> uploadSession, Stream chunkStream, long chunkLength);
|
||||
Task<File<T>> FinalizeUploadSessionAsync(ChunkedUploadSession<T> uploadSession);
|
||||
Task AbortUploadSessionAsync(ChunkedUploadSession<T> uploadSession);
|
||||
#endregion
|
||||
#endregion
|
||||
|
||||
#region Only in TMFileDao
|
||||
#region Only in TMFileDao
|
||||
|
||||
/// <summary>
|
||||
/// Set created by
|
||||
/// </summary>
|
||||
/// <param name="fileIds"></param>
|
||||
/// <summary>
|
||||
/// Set created by
|
||||
/// </summary>
|
||||
/// <param name="fileIds"></param>
|
||||
/// <param name="newOwnerId"></param>
|
||||
Task ReassignFilesAsync(T[] fileIds, Guid newOwnerId);
|
||||
|
||||
/// <summary>
|
||||
/// Search files in SharedWithMe & Projects
|
||||
/// </summary>
|
||||
/// <param name="parentIds"></param>
|
||||
/// <param name="filterType"></param>
|
||||
/// <param name="subjectGroup"></param>
|
||||
/// <param name="subjectID"></param>
|
||||
/// <param name="searchText"></param>
|
||||
/// <param name="searchInContent"></param>
|
||||
/// <summary>
|
||||
/// Search files in SharedWithMe & Projects
|
||||
/// </summary>
|
||||
/// <param name="parentIds"></param>
|
||||
/// <param name="filterType"></param>
|
||||
/// <param name="subjectGroup"></param>
|
||||
/// <param name="subjectID"></param>
|
||||
/// <param name="searchText"></param>
|
||||
/// <param name="searchInContent"></param>
|
||||
/// <returns></returns>
|
||||
IAsyncEnumerable<File<T>> GetFilesAsync(IEnumerable<T> parentIds, FilterType filterType, bool subjectGroup, Guid subjectID, string searchText, bool searchInContent);
|
||||
/// <summary>
|
||||
/// Search the list of files containing text
|
||||
/// Only in TMFileDao
|
||||
/// </summary>
|
||||
/// <param name="text">search text</param>
|
||||
/// <param name="bunch"></param>
|
||||
/// <returns>list of files</returns>
|
||||
/// <summary>
|
||||
/// Search the list of files containing text
|
||||
/// Only in TMFileDao
|
||||
/// </summary>
|
||||
/// <param name="text">search text</param>
|
||||
/// <param name="bunch"></param>
|
||||
/// <returns>list of files</returns>
|
||||
IAsyncEnumerable<File<T>> SearchAsync(string text, bool bunch = false);
|
||||
/// <summary>
|
||||
/// Checks whether file exists on storage
|
||||
/// </summary>
|
||||
/// <param name="file">file</param>
|
||||
/// <returns></returns>
|
||||
/// <summary>
|
||||
/// Checks whether file exists on storage
|
||||
/// </summary>
|
||||
/// <param name="file">file</param>
|
||||
/// <returns></returns>
|
||||
|
||||
Task<bool> IsExistOnStorageAsync(File<T> file);
|
||||
|
||||
@ -290,15 +290,15 @@ public interface IFileDao<T>
|
||||
|
||||
Task<Stream> GetThumbnailAsync(File<T> file, int width, int height);
|
||||
|
||||
Task<Stream> GetThumbnailAsync(T fileId, int width, int height);
|
||||
|
||||
Task<Stream> GetThumbnailAsync(T fileId, int width, int height);
|
||||
|
||||
IAsyncEnumerable<FileWithShare> GetFeedsAsync(int tenant, DateTime from, DateTime to);
|
||||
|
||||
IAsyncEnumerable<int> GetTenantsWithFeedsAsync(DateTime fromTime, bool includeSecurity);
|
||||
|
||||
Task<EntryProperties> GetProperties(T fileId);
|
||||
|
||||
Task SaveProperties(T fileId, EntryProperties entryProperties);
|
||||
|
||||
#endregion
|
||||
Task<EntryProperties> GetProperties(T fileId);
|
||||
|
||||
Task SaveProperties(T fileId, EntryProperties entryProperties);
|
||||
|
||||
#endregion
|
||||
}
|
@ -359,6 +359,7 @@ public interface IFolderDao<T>
|
||||
|
||||
IAsyncEnumerable<int> GetTenantsWithFoldersFeedsAsync(DateTime fromTime);
|
||||
IAsyncEnumerable<int> GetTenantsWithRoomsFeedsAsync(DateTime fromTime);
|
||||
IAsyncEnumerable<OriginData> GetOriginsDataAsync(IEnumerable<T> entriesIds);
|
||||
|
||||
#endregion
|
||||
}
|
@ -50,4 +50,5 @@ public interface ITagDao<T>
|
||||
Task RemoveTagsAsync(FileEntry<T> entry, IEnumerable<int> tagsIds);
|
||||
Task RemoveTags(IEnumerable<Tag> tag);
|
||||
Task RemoveTags(Tag tag);
|
||||
}
|
||||
Task<int> RemoveTagLinksAsync(T entryId, FileEntryType entryType, TagType tagType);
|
||||
}
|
||||
|
@ -94,4 +94,4 @@ public static class DaoFactoryExtension
|
||||
|
||||
services.TryAdd<EditHistory>();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -24,8 +24,6 @@
|
||||
// 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
|
||||
|
||||
using Microsoft.OneDrive.Sdk;
|
||||
|
||||
using Document = ASC.ElasticSearch.Document;
|
||||
|
||||
namespace ASC.Files.Core.Data;
|
||||
@ -359,7 +357,7 @@ internal class FileDao : AbstractDao, IFileDao<int>
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
await foreach (var e in FromQuery(filesDbContext, q).AsAsyncEnumerable())
|
||||
{
|
||||
yield return _mapper.Map<DbFileQuery, File<int>>(e);
|
||||
@ -892,11 +890,13 @@ internal class FileDao : AbstractDao, IFileDao<int>
|
||||
|
||||
using (var tx = await filesDbContext.Database.BeginTransactionAsync())
|
||||
{
|
||||
var trashId = await trashIdTask;
|
||||
var oldParentId = toUpdate.FirstOrDefault()?.ParentId;
|
||||
|
||||
foreach (var f in toUpdate)
|
||||
{
|
||||
f.ParentId = toFolderId;
|
||||
|
||||
var trashId = await trashIdTask;
|
||||
|
||||
if (trashId.Equals(toFolderId))
|
||||
{
|
||||
f.ModifiedBy = _authContext.CurrentAccount.ID;
|
||||
@ -904,6 +904,18 @@ internal class FileDao : AbstractDao, IFileDao<int>
|
||||
}
|
||||
}
|
||||
|
||||
var tagDao = _daoFactory.GetTagDao<int>();
|
||||
|
||||
if (toFolderId == trashId && oldParentId.HasValue)
|
||||
{
|
||||
var origin = Tag.Origin(fileId, FileEntryType.File, oldParentId.Value, _authContext.CurrentAccount.ID);
|
||||
await tagDao.SaveTags(origin);
|
||||
}
|
||||
else if (oldParentId == trashId)
|
||||
{
|
||||
await tagDao.RemoveTagLinksAsync(fileId, FileEntryType.File, TagType.Origin);
|
||||
}
|
||||
|
||||
await filesDbContext.SaveChangesAsync();
|
||||
await tx.CommitAsync();
|
||||
|
||||
|
@ -47,6 +47,7 @@ internal class FolderDao : AbstractDao, IFolderDao<int>
|
||||
private readonly ProviderFolderDao _providerFolderDao;
|
||||
private readonly CrossDao _crossDao;
|
||||
private readonly IMapper _mapper;
|
||||
private readonly GlobalFolder _globalFolder;
|
||||
private static readonly SemaphoreSlim _semaphore = new SemaphoreSlim(1);
|
||||
private readonly GlobalStore _globalStore;
|
||||
|
||||
@ -69,7 +70,8 @@ internal class FolderDao : AbstractDao, IFolderDao<int>
|
||||
ProviderFolderDao providerFolderDao,
|
||||
CrossDao crossDao,
|
||||
IMapper mapper,
|
||||
GlobalStore globalStore)
|
||||
GlobalStore globalStore,
|
||||
GlobalFolder globalFolder)
|
||||
: base(
|
||||
dbContextManager,
|
||||
userManager,
|
||||
@ -91,6 +93,7 @@ internal class FolderDao : AbstractDao, IFolderDao<int>
|
||||
_crossDao = crossDao;
|
||||
_mapper = mapper;
|
||||
_globalStore = globalStore;
|
||||
_globalFolder = globalFolder;
|
||||
}
|
||||
|
||||
public async Task<Folder<int>> GetFolderAsync(int folderId)
|
||||
@ -282,7 +285,7 @@ internal class FolderDao : AbstractDao, IFolderDao<int>
|
||||
q = excludeSubject ? q.Where(r => r.CreateBy != subjectID) : q.Where(r => r.CreateBy == subjectID);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
await foreach (var e in FromQueryWithShared(filesDbContext, q).AsAsyncEnumerable())
|
||||
{
|
||||
yield return _mapper.Map<DbFolderQuery, Folder<int>>(e);
|
||||
@ -591,6 +594,16 @@ internal class FolderDao : AbstractDao, IFolderDao<int>
|
||||
.ToListAsync();
|
||||
|
||||
filesDbContext.Tag.RemoveRange(tagsToRemove);
|
||||
|
||||
var originToDelete = await Query(filesDbContext.Tag)
|
||||
.Where(t => t.Name == id.ToString() || subfoldersStrings.Contains(t.Name))
|
||||
.ToListAsync();
|
||||
|
||||
filesDbContext.Tag.RemoveRange(originToDelete);
|
||||
|
||||
await Query(filesDbContext.TagLink)
|
||||
.Where(l => originToDelete.Select(t => t.Id).Contains(l.TagId))
|
||||
.ExecuteDeleteAsync();
|
||||
|
||||
var securityToDelete = await Query(filesDbContext.Security)
|
||||
.Where(r => subfoldersStrings.Contains(r.EntryId))
|
||||
@ -633,6 +646,7 @@ internal class FolderDao : AbstractDao, IFolderDao<int>
|
||||
{
|
||||
using var filesDbContext = _dbContextFactory.CreateDbContext();
|
||||
var strategy = filesDbContext.Database.CreateExecutionStrategy();
|
||||
var trashIdTask = _globalFolder.GetFolderTrashAsync<int>(_daoFactory);
|
||||
|
||||
await strategy.ExecuteAsync(async () =>
|
||||
{
|
||||
@ -640,6 +654,7 @@ internal class FolderDao : AbstractDao, IFolderDao<int>
|
||||
using (var tx = await filesDbContext.Database.BeginTransactionAsync())
|
||||
{
|
||||
var folder = await GetFolderAsync(folderId);
|
||||
var oldParentId = folder.ParentId;
|
||||
|
||||
if (folder.FolderType != FolderType.DEFAULT && !DocSpaceHelper.IsRoom(folder.FolderType))
|
||||
{
|
||||
@ -699,6 +714,19 @@ internal class FolderDao : AbstractDao, IFolderDao<int>
|
||||
}
|
||||
}
|
||||
|
||||
var trashId = await trashIdTask;
|
||||
var tagDao = _daoFactory.GetTagDao<int>();
|
||||
|
||||
if (toFolderId == trashId)
|
||||
{
|
||||
var origin = Tag.Origin(folderId, FileEntryType.Folder, oldParentId, _authContext.CurrentAccount.ID);
|
||||
await tagDao.SaveTags(origin);
|
||||
}
|
||||
else if (oldParentId == trashId)
|
||||
{
|
||||
await tagDao.RemoveTagLinksAsync(folderId, FileEntryType.Folder, TagType.Origin);
|
||||
}
|
||||
|
||||
await filesDbContext.SaveChangesAsync().ConfigureAwait(false);
|
||||
await tx.CommitAsync().ConfigureAwait(false);
|
||||
|
||||
@ -1311,6 +1339,13 @@ internal class FolderDao : AbstractDao, IFolderDao<int>
|
||||
return (this as IFolderDao<int>).GetFolderIDAsync(FileConstant.ModuleId, Archive, null, createIfNotExists);
|
||||
}
|
||||
|
||||
public IAsyncEnumerable<OriginData> GetOriginsDataAsync(IEnumerable<int> entriesIds)
|
||||
{
|
||||
var filesDbContext = _dbContextFactory.CreateDbContext();
|
||||
|
||||
return _getOriginsDataQuery(filesDbContext, entriesIds, TenantID);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
protected internal IQueryable<DbFolder> GetFolderQuery(FilesDbContext filesDbContext, Expression<Func<DbFolder, bool>> where = null)
|
||||
@ -1645,6 +1680,27 @@ internal class FolderDao : AbstractDao, IFolderDao<int>
|
||||
return _globalStore.GetStore().CreateDataWriteOperator(chunkedUploadSession, sessionHolder);
|
||||
}
|
||||
|
||||
private static readonly Func<FilesDbContext, IEnumerable<int>, int, IAsyncEnumerable<OriginData>> _getOriginsDataQuery =
|
||||
Microsoft.EntityFrameworkCore.EF.CompileAsyncQuery((FilesDbContext filesDbContext, IEnumerable<int> entriesIds, int tenantId) =>
|
||||
filesDbContext.TagLink.AsNoTracking()
|
||||
.Where(l => l.TenantId == tenantId)
|
||||
.Where(l => entriesIds.Contains(Convert.ToInt32(l.EntryId)))
|
||||
.Join(filesDbContext.Tag.AsNoTracking()
|
||||
.Where(t => t.Type == TagType.Origin), l => l.TagId, t => t.Id, (l, t) => new { t.Name, t.Type, l.EntryType, l.EntryId })
|
||||
.GroupBy(r => r.Name, r => new { r.EntryId, r.EntryType })
|
||||
.Select(r => new OriginData
|
||||
{
|
||||
OriginRoom = filesDbContext.Folders.AsNoTracking().FirstOrDefault(f => f.TenantId == tenantId &&
|
||||
f.Id == filesDbContext.Tree.AsNoTracking()
|
||||
.Where(t => t.FolderId == Convert.ToInt32(r.Key))
|
||||
.OrderByDescending(t => t.Level)
|
||||
.Select(t => t.ParentId)
|
||||
.Skip(1)
|
||||
.FirstOrDefault()),
|
||||
OriginFolder = filesDbContext.Folders.AsNoTracking().FirstOrDefault(f => f.TenantId == tenantId && f.Id == Convert.ToInt32(r.Key)),
|
||||
Entries = r.Select(e => new KeyValuePair<string, FileEntryType>(e.EntryId, e.EntryType)).ToHashSet()
|
||||
}));
|
||||
|
||||
private string GetProjectTitle(object folderID)
|
||||
{
|
||||
return "";
|
||||
@ -1716,4 +1772,11 @@ public class ParentRoomPair
|
||||
{
|
||||
public int FolderId { get; set; }
|
||||
public int ParentRoomId { get; set; }
|
||||
}
|
||||
|
||||
public class OriginData
|
||||
{
|
||||
public DbFolder OriginRoom { get; set; }
|
||||
public DbFolder OriginFolder { get; set; }
|
||||
public HashSet<KeyValuePair<string, FileEntryType>> Entries { get; set; }
|
||||
}
|
@ -642,6 +642,33 @@ internal class TagDao<T> : AbstractDao, ITagDao<T>
|
||||
});
|
||||
}
|
||||
|
||||
public async Task<int> RemoveTagLinksAsync(T entryId, FileEntryType entryType, TagType tagType)
|
||||
{
|
||||
var count = 0;
|
||||
|
||||
await using var filesDbContext = await _dbContextFactory.CreateDbContextAsync();
|
||||
var strategy = filesDbContext.Database.CreateExecutionStrategy();
|
||||
var mappedId = (await MappingIDAsync(entryId)).ToString();
|
||||
|
||||
await strategy.ExecuteAsync(async () =>
|
||||
{
|
||||
await using var tx = await filesDbContext.Database.BeginTransactionAsync();
|
||||
|
||||
count = await Query(filesDbContext.TagLink)
|
||||
.Where(l => l.EntryId == mappedId && l.EntryType == entryType)
|
||||
.Join(filesDbContext.Tag, l => l.TagId, t => t.Id, (l, t) => new { l, t.Type })
|
||||
.Where(r => r.Type == tagType)
|
||||
.Select(r => r.l)
|
||||
.ExecuteDeleteAsync();
|
||||
|
||||
await filesDbContext.SaveChangesAsync();
|
||||
await tx.CommitAsync();
|
||||
|
||||
});
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
private Task RemoveTagInDbAsync(Tag tag)
|
||||
{
|
||||
if (tag == null)
|
||||
|
@ -24,26 +24,27 @@
|
||||
// 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
|
||||
|
||||
namespace ASC.Files.Core;
|
||||
namespace ASC.Files.Core;
|
||||
|
||||
public enum DateToAutoCleanUp
|
||||
{
|
||||
OneWeek = 1,
|
||||
TwoWeeks,
|
||||
OneMonth,
|
||||
TwoMonths,
|
||||
ThreeMonths
|
||||
}
|
||||
|
||||
public class AutoCleanUpData
|
||||
{
|
||||
public bool IsAutoCleanUp { get; set; }
|
||||
|
||||
public DateToAutoCleanUp Gap { get; set; }
|
||||
}
|
||||
public enum DateToAutoCleanUp
|
||||
{
|
||||
OneWeek = 1,
|
||||
TwoWeeks,
|
||||
OneMonth,
|
||||
ThirtyDays,
|
||||
TwoMonths,
|
||||
ThreeMonths
|
||||
}
|
||||
|
||||
[Scope]
|
||||
public class FileDateTime
|
||||
public class AutoCleanUpData
|
||||
{
|
||||
public bool IsAutoCleanUp { get; set; }
|
||||
|
||||
public DateToAutoCleanUp Gap { get; set; }
|
||||
}
|
||||
|
||||
[Scope]
|
||||
public class FileDateTime
|
||||
{
|
||||
private readonly TenantUtil _tenantUtil;
|
||||
|
||||
@ -51,19 +52,32 @@ public class FileDateTime
|
||||
{
|
||||
_tenantUtil = tenantUtil;
|
||||
}
|
||||
|
||||
public DateTime GetModifiedOnWithAutoCleanUp(DateTime modifiedOn, DateToAutoCleanUp date, bool utc = false)
|
||||
{
|
||||
var dateTime = modifiedOn;
|
||||
switch (date)
|
||||
{
|
||||
case DateToAutoCleanUp.OneWeek: dateTime = dateTime.AddDays(7); break;
|
||||
case DateToAutoCleanUp.TwoWeeks: dateTime = dateTime.AddDays(14); break;
|
||||
case DateToAutoCleanUp.OneMonth: dateTime = dateTime.AddMonths(1); break;
|
||||
case DateToAutoCleanUp.TwoMonths: dateTime = dateTime.AddMonths(2); break;
|
||||
case DateToAutoCleanUp.ThreeMonths: dateTime = dateTime.AddMonths(3); break;
|
||||
default: break;
|
||||
}
|
||||
return utc ? _tenantUtil.DateTimeToUtc(dateTime) : dateTime;
|
||||
}
|
||||
|
||||
public DateTime GetModifiedOnWithAutoCleanUp(DateTime modifiedOn, DateToAutoCleanUp date, bool utc = false)
|
||||
{
|
||||
var dateTime = modifiedOn;
|
||||
switch (date)
|
||||
{
|
||||
case DateToAutoCleanUp.OneWeek:
|
||||
dateTime = dateTime.AddDays(7);
|
||||
break;
|
||||
case DateToAutoCleanUp.TwoWeeks:
|
||||
dateTime = dateTime.AddDays(14);
|
||||
break;
|
||||
case DateToAutoCleanUp.OneMonth:
|
||||
dateTime = dateTime.AddMonths(1);
|
||||
break;
|
||||
case DateToAutoCleanUp.ThirtyDays:
|
||||
dateTime = dateTime.AddDays(30);
|
||||
break;
|
||||
case DateToAutoCleanUp.TwoMonths:
|
||||
dateTime = dateTime.AddMonths(2);
|
||||
break;
|
||||
case DateToAutoCleanUp.ThreeMonths:
|
||||
dateTime = dateTime.AddMonths(3);
|
||||
break;
|
||||
}
|
||||
|
||||
return utc ? _tenantUtil.DateTimeToUtc(dateTime) : dateTime;
|
||||
}
|
||||
}
|
@ -86,6 +86,8 @@ public abstract class FileEntry : ICloneable
|
||||
public abstract bool IsNew { get; set; }
|
||||
public FileEntryType FileEntryType { get; set; }
|
||||
public IEnumerable<Tag> Tags { get; set; }
|
||||
public string OriginTitle { get; set; }
|
||||
public string OriginRoomTitle { get; set; }
|
||||
|
||||
private string _modifiedByString;
|
||||
private string _createByString;
|
||||
@ -112,6 +114,8 @@ public abstract class FileEntry<T> : FileEntry, ICloneable, IFileEntry<T>
|
||||
{
|
||||
public T Id { get; set; }
|
||||
public T ParentId { get; set; }
|
||||
public T OriginId { get; set; }
|
||||
public T OriginRoomId { get; set; }
|
||||
|
||||
public IDictionary<FilesSecurityActions, bool> Security { get; set; }
|
||||
|
||||
@ -137,34 +141,25 @@ public abstract class FileEntry<T> : FileEntry, ICloneable, IFileEntry<T>
|
||||
|
||||
public T FolderIdDisplay
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_folderIdDisplay != null)
|
||||
{
|
||||
return _folderIdDisplay;
|
||||
}
|
||||
|
||||
return ParentId;
|
||||
}
|
||||
get => !EqualityComparer<T>.Default.Equals(_folderIdDisplay, default) ? _folderIdDisplay : ParentId;
|
||||
set => _folderIdDisplay = value;
|
||||
}
|
||||
|
||||
public string DeletedPermanentlyOnString
|
||||
public DateTime DeletedPermanentlyOn
|
||||
{
|
||||
get
|
||||
{
|
||||
if (!ModifiedOn.Equals(default(DateTime)) && Equals(FolderIdDisplay, _globalFolderHelper.FolderTrash) && _filesSettingsHelper.AutomaticallyCleanUp.IsAutoCleanUp)
|
||||
if (!ModifiedOn.Equals(default) && Equals(FolderIdDisplay, _globalFolderHelper.FolderTrash) && _filesSettingsHelper.AutomaticallyCleanUp.IsAutoCleanUp)
|
||||
{
|
||||
var deletedPermanentlyOn = _fileDateTime.GetModifiedOnWithAutoCleanUp(ModifiedOn, _filesSettingsHelper.AutomaticallyCleanUp.Gap);
|
||||
return deletedPermanentlyOn.ToString("g");
|
||||
}
|
||||
else
|
||||
{
|
||||
return null;
|
||||
}
|
||||
return _fileDateTime.GetModifiedOnWithAutoCleanUp(ModifiedOn, _filesSettingsHelper.AutomaticallyCleanUp.Gap);
|
||||
}
|
||||
|
||||
return default;
|
||||
}
|
||||
}
|
||||
|
||||
public string DeletedPermanentlyOnString => DeletedPermanentlyOn != default ? DeletedPermanentlyOn.ToString("g") : null;
|
||||
|
||||
public bool DenyDownload { get; set; }
|
||||
|
||||
public bool DenySharing { get; set; }
|
||||
@ -193,4 +188,4 @@ public abstract class FileEntry<T> : FileEntry, ICloneable, IFileEntry<T>
|
||||
{
|
||||
return Title;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -37,7 +37,8 @@ public enum SortedByType
|
||||
New,
|
||||
DateAndTimeCreation,
|
||||
RoomType,
|
||||
Tags
|
||||
Tags,
|
||||
Room
|
||||
}
|
||||
|
||||
[DebuggerDisplay("{SortedBy} {IsAsc}")]
|
||||
|
@ -23,9 +23,9 @@
|
||||
// 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
|
||||
|
||||
|
||||
using Profile = AutoMapper.Profile;
|
||||
|
||||
|
||||
namespace ASC.Files.Core;
|
||||
|
||||
[Flags]
|
||||
@ -39,6 +39,7 @@ public enum TagType
|
||||
Template = 32,
|
||||
Custom = 64,
|
||||
Pin = 128,
|
||||
Origin = 256
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
@ -114,6 +115,15 @@ public sealed class Tag : IMapFrom<DbFilesTag>
|
||||
return new Tag("pin", TagType.Pin, owner, 0).AddEntry(entry);
|
||||
}
|
||||
|
||||
public static Tag Origin<T>(T entryId, FileEntryType type, T originId, Guid owner)
|
||||
{
|
||||
return new Tag(originId.ToString(), TagType.Origin, owner, 0)
|
||||
{
|
||||
EntryId = entryId,
|
||||
EntryType = type
|
||||
};
|
||||
}
|
||||
|
||||
public override bool Equals(object obj)
|
||||
{
|
||||
return obj is Tag f && Equals(f);
|
||||
@ -134,4 +144,4 @@ public sealed class Tag : IMapFrom<DbFilesTag>
|
||||
profile.CreateMap<DbFilesTag, Tag>();
|
||||
profile.CreateMap<DbFilesTagLink, Tag>();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -276,6 +276,7 @@ public class FileStorageService<T> //: IFileStorageService
|
||||
bool withSubfolders,
|
||||
OrderBy orderBy,
|
||||
SearchArea searchArea = SearchArea.Active,
|
||||
T roomId = default,
|
||||
bool withoutTags = false,
|
||||
IEnumerable<string> tagNames = null,
|
||||
bool excludeSubject = false,
|
||||
@ -329,7 +330,7 @@ public class FileStorageService<T> //: IFileStorageService
|
||||
IEnumerable<FileEntry> entries;
|
||||
try
|
||||
{
|
||||
(entries, total) = await _entryManager.GetEntriesAsync(parent, from, count, filterType, subjectGroup, subjectId, searchText, searchInContent, withSubfolders, orderBy, searchArea,
|
||||
(entries, total) = await _entryManager.GetEntriesAsync(parent, from, count, filterType, subjectGroup, subjectId, searchText, searchInContent, withSubfolders, orderBy, roomId, searchArea,
|
||||
withoutTags, tagNames, excludeSubject, provider, subjectFilter);
|
||||
}
|
||||
catch (Exception e)
|
||||
|
@ -713,9 +713,8 @@ public class FileSecurity : IFileSecurity
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
var folderDao = _daoFactory.GetFolderDao<T>();
|
||||
var mytrashId = await folderDao.GetFolderIDTrashAsync(false, userId);
|
||||
|
||||
var mytrashId = await _globalFolder.GetFolderTrashAsync(_daoFactory);
|
||||
if (!Equals(mytrashId, 0) && Equals(e.RootId, mytrashId))
|
||||
{
|
||||
return folder == null || action != FilesSecurityActions.Delete || !Equals(e.Id, mytrashId);
|
||||
|
@ -575,7 +575,7 @@ internal class BoxFileDao : BoxDaoBase, IFileDao<string>
|
||||
return ProviderInfo.GetThumbnailAsync(boxFileId, width, height);
|
||||
}
|
||||
|
||||
#region chunking
|
||||
#region chunking
|
||||
|
||||
private File<string> RestoreIds(File<string> file)
|
||||
{
|
||||
@ -664,5 +664,5 @@ internal class BoxFileDao : BoxDaoBase, IFileDao<string>
|
||||
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
|
@ -574,7 +574,7 @@ internal class DropboxFileDao : DropboxDaoBase, IFileDao<string>
|
||||
return ProviderInfo.GetThumbnailsAsync(_dropboxDaoSelector.ConvertId(fileId), width, height);
|
||||
}
|
||||
|
||||
#region chunking
|
||||
#region chunking
|
||||
|
||||
private File<string> RestoreIds(File<string> file)
|
||||
{
|
||||
@ -707,5 +707,5 @@ internal class DropboxFileDao : DropboxDaoBase, IFileDao<string>
|
||||
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
|
@ -24,7 +24,7 @@
|
||||
// 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
|
||||
|
||||
using DriveFile = Google.Apis.Drive.v3.Data.File;
|
||||
using DriveFile = Google.Apis.Drive.v3.Data.File;
|
||||
using File = System.IO.File;
|
||||
|
||||
namespace ASC.Files.Thirdparty.GoogleDrive;
|
||||
@ -578,7 +578,7 @@ internal class GoogleDriveFileDao : GoogleDriveDaoBase, IFileDao<string>
|
||||
return ProviderInfo.GetThumbnail(MakeDriveId(_googleDriveDaoSelector.ConvertId(fileId)), width, height);
|
||||
}
|
||||
|
||||
#region chunking
|
||||
#region chunking
|
||||
|
||||
private File<string> RestoreIds(File<string> file)
|
||||
{
|
||||
@ -733,5 +733,5 @@ internal class GoogleDriveFileDao : GoogleDriveDaoBase, IFileDao<string>
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
|
@ -244,6 +244,11 @@ internal abstract class ThirdPartyProviderDao
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public IAsyncEnumerable<OriginData> GetOriginsDataAsync(IEnumerable<string> entriesId)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public IAsyncEnumerable<Folder<string>> GetRoomsAsync(IEnumerable<string> parentsIds, FilterType filterType, IEnumerable<string> tags, Guid subjectId, string searchText,
|
||||
bool withSubfolders, bool withoutTags, bool excludeSubject, ProviderFilter provider, SubjectFilter subjectFilter, IEnumerable<string> subjectEntriesIds)
|
||||
{
|
||||
@ -719,6 +724,11 @@ internal abstract class ThirdPartyProviderDao<T> : ThirdPartyProviderDao, IDispo
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
public Task<int> RemoveTagLinksAsync(string entryId, FileEntryType entryType, TagType tagType)
|
||||
{
|
||||
return Task.FromResult(default(int));
|
||||
}
|
||||
|
||||
public IAsyncEnumerable<Tag> GetTagsAsync(string entryID, FileEntryType entryType, TagType tagType)
|
||||
{
|
||||
return AsyncEnumerable.Empty<Tag>();
|
||||
|
@ -585,7 +585,7 @@ internal class OneDriveFileDao : OneDriveDaoBase, IFileDao<string>
|
||||
return ProviderInfo.GetThumbnailAsync(oneDriveId, width, height);
|
||||
}
|
||||
|
||||
#region chunking
|
||||
#region chunking
|
||||
|
||||
private File<string> RestoreIds(File<string> file)
|
||||
{
|
||||
@ -730,5 +730,5 @@ internal class OneDriveFileDao : OneDriveDaoBase, IFileDao<string>
|
||||
System.IO.File.Delete(uploadSession.GetItemOrDefault<string>("TempPath"));
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
|
@ -181,12 +181,12 @@ internal class ProviderFileDao : ProviderDaoBase, IFileDao<string>
|
||||
return GetFileStreamAsync(file, 0);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get stream of file
|
||||
/// </summary>
|
||||
/// <param name="file"></param>
|
||||
/// <param name="offset"></param>
|
||||
/// <returns>Stream</returns>
|
||||
/// <summary>
|
||||
/// Get stream of file
|
||||
/// </summary>
|
||||
/// <param name="file"></param>
|
||||
/// <param name="offset"></param>
|
||||
/// <returns>Stream</returns>
|
||||
public Task<Stream> GetFileStreamAsync(File<string> file, long offset)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(file);
|
||||
@ -442,10 +442,10 @@ internal class ProviderFileDao : ProviderDaoBase, IFileDao<string>
|
||||
var selector = GetSelector(file.Id);
|
||||
var fileDao = selector.GetFileDao(file.Id);
|
||||
|
||||
return fileDao.UseTrashForRemove(file);
|
||||
return fileDao.UseTrashForRemove(file);
|
||||
}
|
||||
|
||||
#region chunking
|
||||
#region chunking
|
||||
|
||||
public Task<ChunkedUploadSession<string>> CreateUploadSessionAsync(File<string> file, long contentLength)
|
||||
{
|
||||
@ -519,5 +519,5 @@ internal class ProviderFileDao : ProviderDaoBase, IFileDao<string>
|
||||
return fileDao.GetThumbnailAsync(file, width, height);
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
|
@ -56,7 +56,7 @@ internal class ProviderTagDao : ProviderDaoBase, ITagDao<string>
|
||||
.GetNewTagsAsync(subject, parentFolder, deepSearch);
|
||||
}
|
||||
|
||||
#region Only for Teamlab Documents
|
||||
#region Only for Teamlab Documents
|
||||
|
||||
public IAsyncEnumerable<Tag> GetNewTagsAsync(Guid subject, IEnumerable<FileEntry<string>> fileEntries)
|
||||
{
|
||||
@ -118,6 +118,11 @@ internal class ProviderTagDao : ProviderDaoBase, ITagDao<string>
|
||||
await _tagDao.RemoveTags(tag);
|
||||
}
|
||||
|
||||
public async Task<int> RemoveTagLinksAsync(string entryId, FileEntryType entryType, TagType tagType)
|
||||
{
|
||||
return await _tagDao.RemoveTagLinksAsync(entryId, entryType, tagType);
|
||||
}
|
||||
|
||||
public IAsyncEnumerable<Tag> GetTagsAsync(string entryID, FileEntryType entryType, TagType tagType)
|
||||
{
|
||||
return _tagDao.GetTagsAsync(entryID, entryType, tagType);
|
||||
@ -148,5 +153,5 @@ internal class ProviderTagDao : ProviderDaoBase, ITagDao<string>
|
||||
return _tagDao.RemoveTagsAsync(tagsIds);
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user