Merge branch 'develop' into feature/custom-theme

This commit is contained in:
Alexey Safronov 2022-11-22 17:03:12 +03:00
commit ff53dc882e
13 changed files with 233 additions and 108 deletions

View File

@ -12,6 +12,12 @@ import config from "PACKAGE_FILE";
export default function withBadges(WrappedComponent) { export default function withBadges(WrappedComponent) {
class WithBadges extends React.Component { class WithBadges extends React.Component {
constructor(props) {
super(props);
this.state = { disableBadgeClick: false, disableUnpinClick: false };
}
onShowVersionHistory = () => { onShowVersionHistory = () => {
const { const {
homepage, homepage,
@ -28,22 +34,42 @@ export default function withBadges(WrappedComponent) {
}; };
onBadgeClick = () => { onBadgeClick = () => {
if (this.state.disableBadgeClick) return;
const { item, markAsRead, setNewFilesPanelVisible } = this.props; const { item, markAsRead, setNewFilesPanelVisible } = this.props;
this.setState(() => ({
disableBadgeClick: true,
}));
const enableBadgeClick = () => {
this.setState({ disableBadgeClick: false });
};
if (item.fileExst) { if (item.fileExst) {
markAsRead([], [item.id], item); markAsRead([], [item.id], item).then(() => {
enableBadgeClick();
});
} else { } else {
setNewFilesPanelVisible(true, null, item); setNewFilesPanelVisible(true, null, item).then(() => {
enableBadgeClick();
});
} }
}; };
onUnpinClick = (e) => { onUnpinClick = (e) => {
if (this.state.disableUnpinClick) return;
this.setState({ disableUnpinClick: true });
const { t, setPinAction } = this.props; const { t, setPinAction } = this.props;
const { action, id } = e.target.closest(".is-pinned").dataset; const { action, id } = e.target.closest(".is-pinned").dataset;
if (!action && !id) return; if (!action && !id) return;
setPinAction(action, id, t); setPinAction(action, id, t).then(() => {
this.setState({ disableUnpinClick: false });
});
}; };
setConvertDialogVisible = () => { setConvertDialogVisible = () => {

View File

@ -49,6 +49,8 @@ const ArticleBodyContent = (props) => {
archiveFolderId, archiveFolderId,
} = props; } = props;
const [disableBadgeClick, setDisableBadgeClick] = React.useState(false);
const campaigns = (localStorage.getItem("campaigns") || "") const campaigns = (localStorage.getItem("campaigns") || "")
.split(",") .split(",")
.filter((campaign) => campaign.length > 0); .filter((campaign) => campaign.length > 0);
@ -148,9 +150,18 @@ const ArticleBodyContent = (props) => {
[categoryType, roomsFolderId, archiveFolderId] [categoryType, roomsFolderId, archiveFolderId]
); );
const onShowNewFilesPanel = React.useCallback((folderId) => { const onShowNewFilesPanel = React.useCallback(
props.setNewFilesPanelVisible(true, [`${folderId}`]); async (folderId) => {
}, []); if (disableBadgeClick) return;
setDisableBadgeClick(true);
await props.setNewFilesPanelVisible(true, [`${folderId}`]);
setDisableBadgeClick(false);
},
[disableBadgeClick]
);
return ( return (
<> <>

View File

@ -14,21 +14,23 @@ const StyledLink = styled(Link)`
color: #316daa; color: #316daa;
`; `;
const ConfirmEmailBar = ({ t, onClick, onClose, onLoad }) => { const ConfirmEmailBar = ({ t, tReady, onClick, onClose, onLoad }) => {
return ( return (
<SnackBar tReady && (
headerText={t("ConfirmEmailHeader")} <SnackBar
text={ headerText={t("ConfirmEmailHeader")}
<> text={
{t("ConfirmEmailDescription")}{" "} <>
<StyledLink onClick={onClick}>{t("RequestActivation")}</StyledLink> {t("ConfirmEmailDescription")}{" "}
</> <StyledLink onClick={onClick}>{t("RequestActivation")}</StyledLink>
} </>
isCampaigns={false} }
opacity={1} isCampaigns={false}
onLoad={onLoad} opacity={1}
clickAction={onClose} onLoad={onLoad}
/> clickAction={onClose}
/>
)
); );
}; };

View File

@ -16,6 +16,7 @@ const StyledLink = styled(Link)`
const QuotasBar = ({ const QuotasBar = ({
t, t,
tReady,
isRoomQuota, isRoomQuota,
currentValue, currentValue,
maxValue, maxValue,
@ -57,24 +58,28 @@ const QuotasBar = ({
), ),
}; };
return isRoomQuota ? ( return tReady ? (
<SnackBar isRoomQuota ? (
headerText={roomQuota.header} <SnackBar
text={roomQuota.description} headerText={roomQuota.header}
isCampaigns={false} text={roomQuota.description}
opacity={1} isCampaigns={false}
onLoad={onLoad} opacity={1}
clickAction={onCloseAction} onLoad={onLoad}
/> clickAction={onCloseAction}
/>
) : (
<SnackBar
headerText={storageQuota.header}
text={storageQuota.description}
isCampaigns={false}
opacity={1}
onLoad={onLoad}
clickAction={onCloseAction}
/>
)
) : ( ) : (
<SnackBar <></>
headerText={storageQuota.header}
text={storageQuota.description}
isCampaigns={false}
opacity={1}
onLoad={onLoad}
clickAction={onCloseAction}
/>
); );
}; };

View File

@ -11,8 +11,8 @@ const StyledContainer = styled.div`
${isMobileOnly && ${isMobileOnly &&
css` css`
width: calc(100% + 8px); width: calc(100% + 16px);
max-width: calc(100% + 8px); max-width: calc(100% + 16px);
margin-right: -16px; margin-right: -16px;
margin-top: 48px; margin-top: 48px;

View File

@ -33,6 +33,7 @@ class NewFilesPanel extends React.Component {
state = { readingFiles: [], inProgress: false }; state = { readingFiles: [], inProgress: false };
onClose = () => { onClose = () => {
if (this.state.inProgress) return;
this.props.setNewFilesPanelVisible(false); this.props.setNewFilesPanelVisible(false);
}; };
@ -52,16 +53,27 @@ class NewFilesPanel extends React.Component {
}; };
onMarkAsRead = () => { onMarkAsRead = () => {
const fileIds = []; const { inProgress, readingFiles } = this.state;
const folderIds = []; if (inProgress) return;
for (let item of this.props.newFiles) {
if (item.fileExst) fileIds.push(item.id);
else folderIds.push(item.id);
}
this.setState({ inProgress: true }); this.setState({ inProgress: true });
const files = [];
const folders = [];
for (let item of this.props.newFiles) {
if (item.fileExst) files.push(item);
else folders.push(item);
}
const fileIds = files
.filter((f) => !readingFiles.includes(f.id.toString()))
.map((f) => f.id);
const folderIds = folders
.filter((f) => !readingFiles.includes(f.id.toString()))
.map((f) => f.id);
this.props this.props
.markAsRead(folderIds, fileIds) .markAsRead(folderIds, fileIds)
.then(() => this.setNewBadgeCount()) .then(() => this.setNewBadgeCount())
@ -78,6 +90,10 @@ class NewFilesPanel extends React.Component {
}; };
onNewFileClick = (e) => { onNewFileClick = (e) => {
if (this.state.inProgress) return;
this.setState({ inProgress: true });
const { id, extension: fileExst } = e.target.dataset; const { id, extension: fileExst } = e.target.dataset;
const { const {
@ -92,16 +108,23 @@ class NewFilesPanel extends React.Component {
const item = newFiles.find((file) => file.id.toString() === id); const item = newFiles.find((file) => file.id.toString() === id);
if (readingFiles.includes(id)) return this.onFileClick(item); if (readingFiles.includes(id)) {
this.setState({ inProgress: false });
return this.onFileClick(item);
}
markAsRead(folderIds, fileIds, item) markAsRead(folderIds, fileIds, item)
.then(() => { .then(() => {
//updateFolderBadge(folderId, 1); //updateFolderBadge(folderId, 1);
readingFiles.push(id); readingFiles.push(id);
this.setState({ readingFiles }); this.setState({ readingFiles, inProgress: false });
this.onFileClick(item); this.onFileClick(item);
}) })
.then(() => refreshFiles()) .then(() => {
refreshFiles();
})
.catch((err) => toastr.error(err)); .catch((err) => toastr.error(err));
}; };
@ -159,7 +182,11 @@ class NewFilesPanel extends React.Component {
newFiles, newFiles,
} = this.props; } = this.props;
const filesCount = newFiles.length; const { readingFiles } = this.state;
const filesCount = newFiles.filter(
(f) => !readingFiles.includes(f.id.toString())
).length;
updateRootBadge(+newFilesIds[0], filesCount); updateRootBadge(+newFilesIds[0], filesCount);
if (newFilesIds.length <= 1) { if (newFilesIds.length <= 1) {
@ -175,6 +202,7 @@ class NewFilesPanel extends React.Component {
render() { render() {
//console.log("NewFiles panel render"); //console.log("NewFiles panel render");
const { t, visible, isLoading, newFiles, theme } = this.props; const { t, visible, isLoading, newFiles, theme } = this.props;
const { inProgress } = this.state;
const zIndex = 310; const zIndex = 310;
return ( return (
@ -244,12 +272,13 @@ class NewFilesPanel extends React.Component {
size="normal" size="normal"
primary primary
onClick={this.onMarkAsRead} onClick={this.onMarkAsRead}
isLoading={this.state.inProgress} isLoading={inProgress}
/> />
<Button <Button
className="new_files_panel-button" className="new_files_panel-button"
label={t("Common:CloseButton")} label={t("Common:CloseButton")}
size="normal" size="normal"
isDisabled={inProgress}
onClick={this.onClose} onClick={this.onClose}
/> />
</StyledFooter> </StyledFooter>

View File

@ -13,7 +13,11 @@ const DialogAsideLoader = ({
const renderClearDialogAsideLoader = () => { const renderClearDialogAsideLoader = () => {
return ( return (
<StyledDialogAsideLoader withFooterBorder={withFooterBorder} visible> <StyledDialogAsideLoader
withFooterBorder={withFooterBorder}
isPanel={isPanel}
visible
>
<div className="dialog-loader-header"> <div className="dialog-loader-header">
<Loaders.Rectangle height="29px" /> <Loaders.Rectangle height="29px" />
</div> </div>
@ -23,6 +27,7 @@ const DialogAsideLoader = ({
<div className="dialog-loader-footer"> <div className="dialog-loader-footer">
<Loaders.Rectangle height="40px" /> <Loaders.Rectangle height="40px" />
<Loaders.Rectangle height="40px" />
</div> </div>
</StyledDialogAsideLoader> </StyledDialogAsideLoader>
); );
@ -32,7 +37,7 @@ const DialogAsideLoader = ({
renderClearDialogAsideLoader() renderClearDialogAsideLoader()
) : ( ) : (
<> <>
<Backdrop visible isAside /> <Backdrop visible isAside zIndex={zIndex} />
<StyledDialogAsideLoader visible isPanel={isPanel}> <StyledDialogAsideLoader visible isPanel={isPanel}>
<Aside className="dialog-aside-loader" visible zIndex={zIndex}> <Aside className="dialog-aside-loader" visible zIndex={zIndex}>
{renderClearDialogAsideLoader()} {renderClearDialogAsideLoader()}

View File

@ -1,41 +1,43 @@
import styled, { css } from "styled-components"; import styled, { css } from "styled-components";
const StyledDialogAsideLoader = styled.div` const StyledDialogAsideLoader = styled.div`
${(props) =>
props.isPanel &&
css`
.dialog-aside-loader {
padding: 0;
transform: translateX(${(props) => (props.visible ? "0" : "500px")});
width: 500px;
@media (max-width: 550px) {
width: 320px;
transform: translateX(${(props) => (props.visible ? "0" : "320px")});
}
}
`}
${(props) => ${(props) =>
props.isPanel props.isPanel
? css` ? css`
.dialog-loader-header { .dialog-loader-header {
padding: 12px 16px; padding: 12px 16px;
height: 53px;
border-bottom: ${(props) =>
`1px solid ${props.theme.modalDialog.headerBorderColor}`};
box-sizing: border-box;
margin-right: -16px;
} }
.dialog-loader-body { .dialog-loader-body {
padding: 16px; padding: 16px;
margin-right: -16px;
} }
.dialog-loader-footer { .dialog-loader-footer {
padding: 12px 16px; padding: 12px 16px;
position: fixed; position: fixed;
bottom: 0; bottom: 0;
width: 468px;
@media (max-width: 550px) { height: 71px;
width: 288px;
} display: flex;
align-items: center;
justify-content: space-between;
gap: 8px;
box-sizing: border-box;
border-top: ${(props) =>
`1px solid ${props.theme.modalDialog.headerBorderColor}`};
} }
` `
: css` : css`

View File

@ -2,38 +2,37 @@ import React from "react";
import PropTypes from "prop-types"; import PropTypes from "prop-types";
import styled, { keyframes } from "styled-components"; import styled, { keyframes } from "styled-components";
export const keyFrameBlue = keyframes` export const keyFrameBlue = (props) => keyframes`
0% { top:120px; background: #de7a59; } 0% { background: #de7a59; top: 120px; }
10% { top:120px; background: #F2CBBF; } 10% { background: ${props.colorStep_1}; top: 120px; }
14% { background: #fff; top: 120px; } 14% { background: ${props.colorStep_2}; top: 120px; }
15% { background: #fff; top: 0; } 15% { background: ${props.colorStep_2}; top: 0; }
20% { background: #E6E4E4; } 20% { background: ${props.colorStep_3}; }
30% { background: #D2D2D2; } 30% { background: ${props.colorStep_4}; }
40% { top: 120px; } 40% { top: 120px; }
100% { top: 120px; background: #de7a59; } 100% { background: #de7a59; top: 120px; }
`; `;
export const keyFrameRed = keyframes` export const keyFrameRed = (props) => keyframes`
0% { top:100px; background: #55bce6; opacity: 1; } 0% { background: #55bce6; top: 100px; opacity: 1; }
10% { top:100px; background: #BFE8F8; opacity: 1; } 10% { background: ${props.colorStep_1}; top: 100px; opacity: 1; }
14% { background: #fff; top: 100px; opacity: 1; } 14% { background: ${props.colorStep_2}; top: 100px; opacity: 1; }
15% { background: #fff; top: 0; opacity: 1; } 15% { background: ${props.colorStep_2}; top: 0; opacity: 1; }
20% { background: #ffffff; top: 0; opacity: 0; } 20% { background: ${props.colorStep_2}; top: 0; opacity: 0; }
25% { background: #ffffff; top: 0; opacity: 0; } 45% { background: ${props.colorStep_3}; top: 0; }
45% { background: #EFEFEF; top: 0; opacity: 0,2; } 100% { background: #55bce6; top: 100px; }
100% { top: 100px; background: #55bce6; }
`; `;
export const keyFrameGreen = keyframes` export const keyFrameGreen = (props) => keyframes`
0% { top:110px; background: #a1cb5c; opacity: 1; } 0% { background: #a1cb5c; top: 110px; opacity: 1; }
10% { top:110px; background: #CBE0AC; opacity: 1; } 10% { background: ${props.colorStep_1}; top: 110px; opacity: 1; }
14% { background: #fff; top: 110px; opacity: 1; } 14% { background: ${props.colorStep_2}; top: 110px; opacity: 1; }
15% { background: #fff; top: 0; opacity: 1; } 15% { background: ${props.colorStep_2}; top: 0; opacity: 1; }
20% { background: #ffffff; top: 0; opacity: 0; } 20% { background: ${props.colorStep_2}; top: 0; opacity: 0; }
25% { background: #EFEFEF; top: 0; opacity: 1; } 25% { background: ${props.colorStep_3}; top: 0; opacity: 1; }
30% { background: #E6E4E4; } 30% { background: ${props.colorStep_4}; }
70% { top: 110px; } 70% { top: 110px; }
100% { top: 110px; background: #a1cb5c; } 100% { background: #a1cb5c; top: 110px; }
`; `;
const Romb = styled.div` const Romb = styled.div`
@ -63,9 +62,9 @@ const Romb = styled.div`
(props.color === "green" && "2")}; (props.color === "green" && "2")};
animation: ${(props) => animation: ${(props) =>
(props.color === "blue" && keyFrameBlue) || (props.color === "blue" && keyFrameBlue(props.theme.rombsLoader.blue)) ||
(props.color === "red" && keyFrameRed) || (props.color === "red" && keyFrameRed(props.theme.rombsLoader.red)) ||
(props.color === "green" && keyFrameGreen)} (props.color === "green" && keyFrameGreen(props.theme.rombsLoader.green))}
2s ease-in-out 0s infinite; 2s ease-in-out 0s infinite;
`; `;

View File

@ -1497,6 +1497,26 @@ const Base = {
borderRadius: "50%", borderRadius: "50%",
}, },
rombsLoader: {
blue: {
colorStep_1: "#F2CBBF",
colorStep_2: "#fff",
colorStep_3: "#E6E4E4",
colorStep_4: "#D2D2D2",
},
red: {
colorStep_1: "#BFE8F8",
colorStep_2: "#fff",
colorStep_3: "#EFEFEF",
},
green: {
colorStep_1: "#CBE0AC",
colorStep_2: "#fff",
colorStep_3: "#EFEFEF",
colorStep_4: "#E6E4E4",
},
},
dialogLoader: { dialogLoader: {
borderBottom: "1px solid rgb(222, 226, 230)", borderBottom: "1px solid rgb(222, 226, 230)",
}, },

View File

@ -1487,7 +1487,26 @@ const Dark = {
marginRight: "2px", marginRight: "2px",
borderRadius: "50%", borderRadius: "50%",
}, },
rombsLoader: {
blue: {
colorStep_1: "#333",
colorStep_2: "#333",
colorStep_3: "#323032",
colorStep_4: "#323032",
},
red: {
colorStep_1: "#333",
colorStep_2: "#333",
colorStep_3: "#323032",
colorStep_4: "#323032",
},
green: {
colorStep_1: "#333",
colorStep_2: "#333",
colorStep_3: "#323032",
colorStep_4: "#323032",
},
},
dialogLoader: { dialogLoader: {
borderBottom: "1px solid #292929", borderBottom: "1px solid #292929",
}, },

View File

@ -73,6 +73,8 @@ internal class FileMoveCopyOperationData<T> : FileOperationData<T>
class FileMoveCopyOperation<T> : FileOperation<FileMoveCopyOperationData<T>, T> class FileMoveCopyOperation<T> : FileOperation<FileMoveCopyOperationData<T>, T>
{ {
private static readonly SemaphoreSlim _semaphore = new SemaphoreSlim(1);
private readonly int _daoFolderId; private readonly int _daoFolderId;
private readonly string _thirdpartyFolderId; private readonly string _thirdpartyFolderId;
private readonly bool _copy; private readonly bool _copy;
@ -382,10 +384,15 @@ class FileMoveCopyOperation<T> : FileOperation<FileMoveCopyOperationData<T>, T>
{ {
if (isRoom && toFolder.FolderType == FolderType.VirtualRooms) if (isRoom && toFolder.FolderType == FolderType.VirtualRooms)
{ {
await _semaphore.WaitAsync();
await countRoomChecker.CheckAppend(); await countRoomChecker.CheckAppend();
newFolderId = await FolderDao.MoveFolderAsync(folder.Id, toFolderId, CancellationToken);
_semaphore.Release();
}
else
{
newFolderId = await FolderDao.MoveFolderAsync(folder.Id, toFolderId, CancellationToken);
} }
newFolderId = await FolderDao.MoveFolderAsync(folder.Id, toFolderId, CancellationToken);
} }
newFolder = await folderDao.GetFolderAsync(newFolderId); newFolder = await folderDao.GetFolderAsync(newFolderId);

View File

@ -50,13 +50,12 @@ public abstract class FileOperation : DistributedTaskProgress
_culture = Thread.CurrentThread.CurrentCulture.Name; _culture = Thread.CurrentThread.CurrentCulture.Name;
this[Owner] = ((IAccount)(_principal ?? Thread.CurrentPrincipal).Identity).ID.ToString(); this[Owner] = ((IAccount)(_principal ?? Thread.CurrentPrincipal).Identity).ID.ToString();
this[Src] = ""; this[Src] = _props.ContainsValue(Src) ? this[Src] : "";
this[Progress] = 0; this[Progress] = 0;
this[Res] = ""; this[Res] = "";
this[Err] = ""; this[Err] = "";
this[Process] = 0; this[Process] = 0;
this[Finish] = false; this[Finish] = false;
this[Hold] = false;
} }
protected void IncrementProgress() protected void IncrementProgress()
@ -84,6 +83,7 @@ internal class ComposeFileOperation<T1, T2> : FileOperation
{ {
ThirdPartyOperation = thirdPartyOperation; ThirdPartyOperation = thirdPartyOperation;
DaoOperation = daoOperation; DaoOperation = daoOperation;
this[Hold] = ThirdPartyOperation[Hold] || DaoOperation[Hold];
} }
public override async Task RunJob(DistributedTask _, CancellationToken cancellationToken) public override async Task RunJob(DistributedTask _, CancellationToken cancellationToken)