Merge branch 'feature/virtual-rooms-1.2' of github.com:ONLYOFFICE/AppServer into feature/ip-security
This commit is contained in:
commit
3ab0bdd11f
@ -1,5 +1,5 @@
|
||||
REM echo ######## Set variables ########
|
||||
set "msbuild4="C:\Windows\Microsoft.NET\Framework\v4.0.30319\MSBuild.exe""
|
||||
set "publisher="Ascensio System SIA""
|
||||
|
||||
REM echo ######## Extracting and preparing files to build ########
|
||||
%sevenzip% x build\install\win\nginx-1.21.1.zip -o"build\install\win\Files" -y
|
||||
@ -29,7 +29,7 @@ del /f /q "build\install\win\kafka-zookeeper\zookeeper\conf\zoo_sample.cfg"
|
||||
rmdir build\install\win\publish /s /q
|
||||
|
||||
REM echo ######## Build Utils ########
|
||||
%msbuild4% build\install\win\CustomActions\C#\Utils\Utils.csproj
|
||||
%msbuild% build\install\win\CustomActions\C#\Utils\Utils.csproj
|
||||
copy build\install\win\CustomActions\C#\Utils\bin\Debug\Utils.CA.dll build\install\win\Utils.CA.dll /y
|
||||
rmdir build\install\win\CustomActions\C#\Utils\bin /s /q
|
||||
rmdir build\install\win\CustomActions\C#\Utils\obj /s /q
|
||||
@ -80,7 +80,7 @@ copy "build\install\win\publish\Apache ZooKeeper.msi" "build\install\win\Apache
|
||||
copy "build\install\win\publish\Apache Kafka.msi" "build\install\win\Apache Kafka.msi" /y
|
||||
|
||||
REM echo ######## Build MySQL Server Installer ########
|
||||
iscc "build\install\win\MySQL Server Installer Runner.iss"
|
||||
iscc /Qp /S"byparam="signtool" sign /a /n "%publisher%" /t http://timestamp.digicert.com $f" "build\install\win\MySQL Server Installer Runner.iss"
|
||||
|
||||
REM echo ######## Build AppServer package ########
|
||||
%AdvancedInstaller% /edit build\install\win\AppServer.aip /SetVersion %BUILD_VERSION%.%BUILD_NUMBER%
|
||||
|
@ -175,7 +175,7 @@ namespace ASC.Core
|
||||
public UserInfo GetUserBySid(string sid)
|
||||
{
|
||||
return GetUsersInternal()
|
||||
.FirstOrDefault(u => u.Sid != null && string.Equals(u.Sid , sid, StringComparison.CurrentCultureIgnoreCase)) ?? Constants.LostUser;
|
||||
.FirstOrDefault(u => u.Sid != null && string.Equals(u.Sid, sid, StringComparison.CurrentCultureIgnoreCase)) ?? Constants.LostUser;
|
||||
}
|
||||
|
||||
public UserInfo GetSsoUserByNameId(string nameId)
|
||||
@ -518,6 +518,11 @@ namespace ASC.Core
|
||||
{
|
||||
var group = UserService.GetGroup(Tenant.TenantId, groupID);
|
||||
|
||||
if (group == null)
|
||||
{
|
||||
group = ToGroup(Constants.BuildinGroups.FirstOrDefault(r => r.ID == groupID));
|
||||
}
|
||||
|
||||
return new GroupInfo
|
||||
{
|
||||
ID = group.Id,
|
||||
|
@ -275,6 +275,7 @@ namespace ASC.Security.Cryptography
|
||||
case ConfirmType.PhoneAuth:
|
||||
case ConfirmType.TfaActivation:
|
||||
case ConfirmType.TfaAuth:
|
||||
case ConfirmType.Auth:
|
||||
checkKeyResult = Provider.ValidateEmailKey(email + type, key, Provider.ValidAuthKeyInterval);
|
||||
break;
|
||||
|
||||
|
@ -43,7 +43,7 @@ namespace ASC.IPSecurity
|
||||
public IPRestrictionsServiceCache(ICacheNotify<IPRestrictionItem> notify, ICache cache)
|
||||
{
|
||||
Cache = cache;
|
||||
notify.Subscribe((r) => Cache.Remove(GetCacheKey(r.TenantId)), CacheNotifyAction.Any);
|
||||
notify.Subscribe((r) => Cache.Remove(GetCacheKey(r.TenantId)), CacheNotifyAction.InsertOrUpdate);
|
||||
Notify = notify;
|
||||
}
|
||||
|
||||
|
@ -554,7 +554,8 @@ namespace ASC.ElasticSearch
|
||||
|
||||
while (!string.IsNullOrEmpty(name = TryGetName(expression, out var member)))
|
||||
{
|
||||
sourceExprText = "." + name + sourceExprText;
|
||||
sourceExprText = "." + name + sourceExprText;
|
||||
expression = member.Expression;
|
||||
}
|
||||
|
||||
if (isList)
|
||||
|
@ -3,6 +3,7 @@ import axios from "axios";
|
||||
import FilesFilter from "./filter";
|
||||
import { FolderType } from "../../constants";
|
||||
import find from "lodash/find";
|
||||
import { getFolderOptions } from "../../utils";
|
||||
|
||||
export function openEdit(fileId, version, doc, view) {
|
||||
const params = []; // doc ? `?doc=${doc}` : "";
|
||||
@ -48,19 +49,7 @@ export function getFolderPath(folderId) {
|
||||
}
|
||||
|
||||
export function getFolder(folderId, filter) {
|
||||
if (folderId && typeof folderId === "string") {
|
||||
folderId = encodeURIComponent(folderId.replace(/\\\\/g, "\\"));
|
||||
}
|
||||
|
||||
const params =
|
||||
filter && filter instanceof FilesFilter
|
||||
? `${folderId}?${filter.toApiUrlParams()}`
|
||||
: folderId;
|
||||
const options = {
|
||||
method: "get",
|
||||
url: `/files/${params}`,
|
||||
};
|
||||
|
||||
const options = getFolderOptions(folderId, filter);
|
||||
return request(options);
|
||||
}
|
||||
|
||||
@ -181,6 +170,38 @@ export function getFoldersTree() {
|
||||
);
|
||||
}
|
||||
|
||||
export function getCommonFoldersTree() {
|
||||
const index = 1;
|
||||
return request({ method: "get", url: "/files/@common" }).then(
|
||||
(commonFolders) => {
|
||||
return [
|
||||
{
|
||||
id: commonFolders.current.id,
|
||||
key: `0-${index}`,
|
||||
parentId: commonFolders.current.parentId,
|
||||
title: commonFolders.current.title,
|
||||
rootFolderType: +commonFolders.current.rootFolderType,
|
||||
rootFolderName: "@common",
|
||||
pathParts: commonFolders.pathParts,
|
||||
foldersCount: commonFolders.current.foldersCount,
|
||||
newItems: commonFolders.new,
|
||||
},
|
||||
];
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
export function getThirdPartyCommonFolderTree() {
|
||||
return request({ method: "get", url: "/files/thirdparty/common" }).then(
|
||||
(commonThirdPartyArray) => {
|
||||
commonThirdPartyArray.map((currentValue, index) => {
|
||||
commonThirdPartyArray[index].key = `0-${index}`;
|
||||
});
|
||||
return commonThirdPartyArray;
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
export function getMyFolderList(filter = FilesFilter.getDefault()) {
|
||||
const options = {
|
||||
method: "get",
|
||||
|
@ -429,13 +429,6 @@ export function validateTfaCode(code) {
|
||||
});
|
||||
}
|
||||
|
||||
export function getCommonThirdPartyList() {
|
||||
const options = {
|
||||
method: "get",
|
||||
url: "/files/thirdparty/common",
|
||||
};
|
||||
return request(options);
|
||||
}
|
||||
export function getBackupStorage() {
|
||||
const options = {
|
||||
method: "get",
|
||||
|
@ -3,7 +3,14 @@ import PropTypes from "prop-types";
|
||||
import { StyledRow } from "./StyledListLoader";
|
||||
import RectangleLoader from "../RectangleLoader";
|
||||
|
||||
const ListItemLoader = ({ id, className, style, isRectangle, ...rest }) => {
|
||||
const ListItemLoader = ({
|
||||
id,
|
||||
className,
|
||||
style,
|
||||
withoutFirstRectangle,
|
||||
withoutLastRectangle,
|
||||
...rest
|
||||
}) => {
|
||||
const {
|
||||
title,
|
||||
borderRadius,
|
||||
@ -16,8 +23,14 @@ const ListItemLoader = ({ id, className, style, isRectangle, ...rest }) => {
|
||||
} = rest;
|
||||
|
||||
return (
|
||||
<StyledRow id={id} className={className} style={style}>
|
||||
{isRectangle && (
|
||||
<StyledRow
|
||||
id={id}
|
||||
className={className}
|
||||
style={style}
|
||||
withoutFirstRectangle={withoutFirstRectangle}
|
||||
withoutLastRectangle={withoutLastRectangle}
|
||||
>
|
||||
{!withoutFirstRectangle && (
|
||||
<RectangleLoader
|
||||
title={title}
|
||||
width="16"
|
||||
@ -60,18 +73,20 @@ const ListItemLoader = ({ id, className, style, isRectangle, ...rest }) => {
|
||||
animate={animate}
|
||||
/>
|
||||
|
||||
<RectangleLoader
|
||||
title={title}
|
||||
width="16"
|
||||
height="16"
|
||||
borderRadius={borderRadius}
|
||||
backgroundColor={backgroundColor}
|
||||
foregroundColor={foregroundColor}
|
||||
backgroundOpacity={backgroundOpacity}
|
||||
foregroundOpacity={foregroundOpacity}
|
||||
speed={speed}
|
||||
animate={animate}
|
||||
/>
|
||||
{!withoutLastRectangle && (
|
||||
<RectangleLoader
|
||||
title={title}
|
||||
width="16"
|
||||
height="16"
|
||||
borderRadius={borderRadius}
|
||||
backgroundColor={backgroundColor}
|
||||
foregroundColor={foregroundColor}
|
||||
backgroundOpacity={backgroundOpacity}
|
||||
foregroundOpacity={foregroundOpacity}
|
||||
speed={speed}
|
||||
animate={animate}
|
||||
/>
|
||||
)}
|
||||
</StyledRow>
|
||||
);
|
||||
};
|
||||
@ -80,14 +95,16 @@ ListItemLoader.propTypes = {
|
||||
id: PropTypes.string,
|
||||
className: PropTypes.string,
|
||||
style: PropTypes.object,
|
||||
isRectangle: PropTypes.bool,
|
||||
withoutFirstRectangle: PropTypes.bool,
|
||||
withoutLastRectangle: PropTypes.bool,
|
||||
};
|
||||
|
||||
ListItemLoader.defaultProps = {
|
||||
id: undefined,
|
||||
className: undefined,
|
||||
style: undefined,
|
||||
isRectangle: true,
|
||||
withoutFirstRectangle: false,
|
||||
withoutLastRectangle: false,
|
||||
};
|
||||
|
||||
export default ListItemLoader;
|
||||
|
@ -9,21 +9,26 @@ const StyledRow = styled.div`
|
||||
width: 100%;
|
||||
display: grid;
|
||||
grid-template-columns: 16px 32px 1fr 16px;
|
||||
${(props) =>
|
||||
props.withoutFirstRectangle &&
|
||||
props.withoutLastRectangle &&
|
||||
"grid-template-columns: 32px 1fr"};
|
||||
${(props) =>
|
||||
props.withoutFirstRectangle &&
|
||||
!props.withoutLastRectangle &&
|
||||
"grid-template-columns: 32px 1fr 16px"};
|
||||
grid-template-rows: 1fr;
|
||||
grid-column-gap: 8px;
|
||||
margin-bottom: 16px;
|
||||
justify-items: center;
|
||||
align-items: center;
|
||||
|
||||
.list-loader_rectangle {
|
||||
padding-right: 4px;
|
||||
}
|
||||
|
||||
.list-loader_rectangle-content {
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
}
|
||||
|
||||
.list-loader_rectangle-row {
|
||||
margin-right: auto;
|
||||
max-width: 167px;
|
||||
|
@ -0,0 +1,24 @@
|
||||
import styled from "styled-components";
|
||||
import { desktop } from "@appserver/components/utils/device";
|
||||
|
||||
const StyledTreeFolder = styled.div`
|
||||
padding-right: 16px;
|
||||
`;
|
||||
|
||||
const StyledLoader = styled.div`
|
||||
width: 100%;
|
||||
display: grid;
|
||||
grid-template-columns: 8px 16px 1fr;
|
||||
grid-template-rows: 1fr;
|
||||
grid-column-gap: 6px;
|
||||
margin-bottom: 8px;
|
||||
box-sizing: border-box;
|
||||
|
||||
.tree-node-loader_additional-rectangle {
|
||||
padding-top: 4px;
|
||||
}
|
||||
|
||||
${(props) => props.paddingLeft && `padding-left: ${props.paddingLeft}`};
|
||||
`;
|
||||
|
||||
export { StyledLoader, StyledTreeFolder };
|
@ -0,0 +1,51 @@
|
||||
import React from "react";
|
||||
import PropTypes from "prop-types";
|
||||
import { StyledTreeFolder, StyledLoader } from "./StyledTreeFolder";
|
||||
import TreeNodeLoader from "../TreeNodeLoader";
|
||||
|
||||
const NewTreeFolderLoader = ({ id, className, style, ...rest }) => {
|
||||
return (
|
||||
<StyledTreeFolder id={id} className={className} style={style}>
|
||||
<StyledLoader>
|
||||
<TreeNodeLoader {...rest} withRectangle />
|
||||
</StyledLoader>
|
||||
<StyledLoader paddingLeft={"16px"}>
|
||||
<TreeNodeLoader {...rest} withRectangle />
|
||||
</StyledLoader>
|
||||
|
||||
<StyledLoader paddingLeft={"32px"}>
|
||||
<TreeNodeLoader {...rest} withRectangle />
|
||||
</StyledLoader>
|
||||
<StyledLoader paddingLeft={"32px"}>
|
||||
<TreeNodeLoader {...rest} withRectangle />
|
||||
</StyledLoader>
|
||||
<StyledLoader paddingLeft={"32px"}>
|
||||
<TreeNodeLoader {...rest} withRectangle />
|
||||
</StyledLoader>
|
||||
|
||||
<StyledLoader>
|
||||
<TreeNodeLoader {...rest} withRectangle />
|
||||
</StyledLoader>
|
||||
<StyledLoader paddingLeft={"16px"}>
|
||||
<TreeNodeLoader {...rest} withRectangle />
|
||||
</StyledLoader>
|
||||
<StyledLoader paddingLeft={"16px"}>
|
||||
<TreeNodeLoader {...rest} withRectangle />
|
||||
</StyledLoader>
|
||||
</StyledTreeFolder>
|
||||
);
|
||||
};
|
||||
|
||||
NewTreeFolderLoader.propTypes = {
|
||||
id: PropTypes.string,
|
||||
className: PropTypes.string,
|
||||
style: PropTypes.object,
|
||||
};
|
||||
|
||||
NewTreeFolderLoader.defaultProps = {
|
||||
id: undefined,
|
||||
className: undefined,
|
||||
style: undefined,
|
||||
};
|
||||
|
||||
export default NewTreeFolderLoader;
|
@ -11,6 +11,7 @@ const TreeNodeLoader = ({
|
||||
foregroundOpacity,
|
||||
speed,
|
||||
animate,
|
||||
withRectangle = false,
|
||||
}) => {
|
||||
return (
|
||||
<>
|
||||
@ -25,6 +26,23 @@ const TreeNodeLoader = ({
|
||||
speed={speed}
|
||||
animate={animate}
|
||||
/>
|
||||
|
||||
{withRectangle && (
|
||||
<RectangleLoader
|
||||
title={title}
|
||||
width="16"
|
||||
height="16"
|
||||
borderRadius={borderRadius}
|
||||
backgroundColor={backgroundColor}
|
||||
foregroundColor={foregroundColor}
|
||||
backgroundOpacity={backgroundOpacity}
|
||||
foregroundOpacity={foregroundOpacity}
|
||||
speed={speed}
|
||||
animate={animate}
|
||||
className="tree-node-loader_additional-rectangle"
|
||||
/>
|
||||
)}
|
||||
|
||||
<RectangleLoader
|
||||
title={title}
|
||||
width="100%"
|
||||
|
@ -7,6 +7,7 @@ import ArticleButton from "./ArticleButtonLoader";
|
||||
import ArticleFolder from "./ArticleFolderLoader";
|
||||
import ArticleGroup from "./ArticleGroupsLoader";
|
||||
import TreeFolders from "./TreeFolderLoader";
|
||||
import NewTreeFolders from "./NewTreeFolderLoader";
|
||||
import TreeSettingsLoader from "./TreeSettingsLoader";
|
||||
import Row from "./RowLoader";
|
||||
import Rows from "./RowsLoader";
|
||||
@ -46,4 +47,5 @@ export default {
|
||||
ArticleFolder,
|
||||
ArticleGroup,
|
||||
ListLoader,
|
||||
NewTreeFolders,
|
||||
};
|
||||
|
@ -324,3 +324,22 @@ export function convertLanguage(key) {
|
||||
|
||||
return key;
|
||||
}
|
||||
|
||||
import FilesFilter from "../api/files/filter";
|
||||
export function getFolderOptions(folderId, filter) {
|
||||
if (folderId && typeof folderId === "string") {
|
||||
folderId = encodeURIComponent(folderId.replace(/\\\\/g, "\\"));
|
||||
}
|
||||
|
||||
const params =
|
||||
filter && filter instanceof FilesFilter
|
||||
? `${folderId}?${filter.toApiUrlParams()}`
|
||||
: folderId;
|
||||
|
||||
const options = {
|
||||
method: "get",
|
||||
url: `/files/${params}`,
|
||||
};
|
||||
|
||||
return options;
|
||||
}
|
||||
|
@ -37,7 +37,14 @@ Button.propTypes = {
|
||||
/** Size of button.
|
||||
|
||||
The normal size equals 36px and 40px in height on the Desktop and Touchcreen devices. */
|
||||
size: PropTypes.oneOf(["extraSmall", "small", "normal", "medium"]),
|
||||
size: PropTypes.oneOf([
|
||||
"extraSmall",
|
||||
"small",
|
||||
"normal",
|
||||
"medium",
|
||||
"normalDesktop",
|
||||
"normalTouchscreen",
|
||||
]),
|
||||
/** Scale width of button to 100% */
|
||||
scale: PropTypes.bool,
|
||||
/** Icon node element */
|
||||
|
@ -177,7 +177,9 @@ class ModalDialog extends React.Component {
|
||||
<BodyBox paddingProp={modalBodyPadding}>
|
||||
{body ? body.props.children : null}
|
||||
</BodyBox>
|
||||
<Box>{footer ? footer.props.children : null}</Box>
|
||||
<Box className="modal-dialog-modal-footer">
|
||||
{footer ? footer.props.children : null}
|
||||
</Box>
|
||||
</>
|
||||
)}
|
||||
</Content>
|
||||
|
@ -519,6 +519,7 @@ const Base = {
|
||||
minHeight: "47px",
|
||||
width: "100%",
|
||||
borderBottom: globalColors.grayLightMid,
|
||||
backgroundColor: globalColors.lightHover,
|
||||
minWidth: "160px",
|
||||
overflow: "hidden",
|
||||
textOverflow: "ellipsis",
|
||||
@ -1930,7 +1931,6 @@ const Base = {
|
||||
|
||||
menuContainer: {
|
||||
background: "linear-gradient(200.71deg, #2274aa 0%, #0f4071 100%)",
|
||||
arrowTop: "#206FA4",
|
||||
color: white,
|
||||
},
|
||||
|
||||
|
@ -517,6 +517,7 @@ const Dark = {
|
||||
minHeight: "47px",
|
||||
width: "100%",
|
||||
borderBottom: "#474747",
|
||||
backgroundColor: globalColors.veryDarkGrey,
|
||||
minWidth: "160px",
|
||||
overflow: "hidden",
|
||||
textOverflow: "ellipsis",
|
||||
@ -1930,10 +1931,8 @@ const Dark = {
|
||||
},
|
||||
|
||||
menuContainer: {
|
||||
background:
|
||||
"linear-gradient(226.22deg, #EBB67A 0.24%, #E9AC6B 11.61%, #E8A25D 22.98%, #E69850 34.34%, #E58D42 45.71%, #E38235 57.08%, #E27628 68.44%, #E06A1B 79.81%)",
|
||||
arrowTop: "#EAB274",
|
||||
color: "#22221f",
|
||||
background: "linear-gradient(226.22deg, #606060 0.24%, #1F1F1F 79.81%)",
|
||||
color: "rgba(255, 255, 255, 0.92)",
|
||||
},
|
||||
|
||||
article: {
|
||||
|
@ -22,6 +22,7 @@ const StyledTreeMenu = styled(Tree)`
|
||||
|
||||
.rc-tree-switcher {
|
||||
margin-left: 0 !important;
|
||||
padding-left: 16px;
|
||||
margin-top: 1px;
|
||||
}
|
||||
|
||||
@ -30,7 +31,7 @@ const StyledTreeMenu = styled(Tree)`
|
||||
width: 18px;
|
||||
height: 16px;
|
||||
padding: 0;
|
||||
margin-top: 4px;
|
||||
margin-top: -4px;
|
||||
}
|
||||
|
||||
${(props) =>
|
||||
@ -44,22 +45,22 @@ const StyledTreeMenu = styled(Tree)`
|
||||
margin-right: 6px !important;
|
||||
}
|
||||
.rc-tree-node-content-wrapper {
|
||||
position: static !important;
|
||||
margin-bottom: ${(props) => +props.gapBetweenNodes - 16 + "px;"};
|
||||
padding-top: 4px;
|
||||
}
|
||||
|
||||
${(props) =>
|
||||
!props.isFullFillSelection &&
|
||||
css`
|
||||
span.rc-tree-node-selected {
|
||||
width: min-content !important;
|
||||
padding-right: 4px;
|
||||
// width: min-content !important;
|
||||
// padding-right: 4px;
|
||||
max-width: 98%;
|
||||
}
|
||||
`}
|
||||
|
||||
& .rc-tree-node-selected .rc-tree-title {
|
||||
${(props) => !props.isFullFillSelection && "width: calc(100% - 26px);"}
|
||||
${(props) => !props.isFullFillSelection && "width: calc(100% - 16px);"}
|
||||
margin-top: 2px;
|
||||
}
|
||||
|
||||
&:not(.rc-tree-show-line) .rc-tree-switcher-noop {
|
||||
@ -84,12 +85,34 @@ const StyledTreeMenu = styled(Tree)`
|
||||
.rc-tree-child-tree-open {
|
||||
display: block;
|
||||
${(props) => props.disableSwitch && "margin: 0 0 25px 0;"}
|
||||
margin-left: ${(props) => (props.disableSwitch ? "27px" : "8px")};
|
||||
li:first-child {
|
||||
margin-top: ${(props) => (props.disableSwitch ? "10px" : "6px")};
|
||||
margin-top: ${(props) => (props.disableSwitch ? "10px" : "8px")};
|
||||
margin-bottom: 8px;
|
||||
margin-left: 0;
|
||||
}
|
||||
li {
|
||||
padding-left: 16px;
|
||||
}
|
||||
}
|
||||
|
||||
.rc-tree-treenode-selected {
|
||||
::after {
|
||||
position: absolute;
|
||||
display: block;
|
||||
top: 0px;
|
||||
|
||||
width: 100%;
|
||||
width: ${(props) => props.widthAdditional};
|
||||
height: 36px;
|
||||
background-color: #f3f4f4;
|
||||
content: "";
|
||||
z-index: 1;
|
||||
right: -${(props) => props.multiplicationFactor - 4}px;
|
||||
}
|
||||
.span.rc-tree-node-selected {
|
||||
}
|
||||
}
|
||||
|
||||
.rc-tree-treenode-disabled > span:not(.rc-tree-switcher),
|
||||
.rc-tree-treenode-disabled > a,
|
||||
.rc-tree-treenode-disabled > a span {
|
||||
@ -136,12 +159,12 @@ const StyledTreeMenu = styled(Tree)`
|
||||
: ``}
|
||||
@media (max-width: 1024px) {
|
||||
margin-top: 20px !important;
|
||||
.rc-tree-node-content-wrapper {
|
||||
/* .rc-tree-node-content-wrapper {
|
||||
margin-bottom: ${(props) =>
|
||||
props.gapBetweenNodesTablet
|
||||
? +props.gapBetweenNodesTablet - 16 + "px;"
|
||||
: +props.gapBetweenNodes - 16 + "px;"};
|
||||
}
|
||||
props.gapBetweenNodesTablet
|
||||
? +props.gapBetweenNodesTablet - 16 + "px;"
|
||||
: +props.gapBetweenNodes - 16 + "px;"};
|
||||
} */
|
||||
& > li > .rc-tree-child-tree {
|
||||
margin-left: 4px;
|
||||
}
|
||||
@ -151,7 +174,6 @@ const StyledTreeMenu = styled(Tree)`
|
||||
StyledTreeMenu.defaultProps = { theme: Base };
|
||||
|
||||
const TreeMenu = React.forwardRef((props, ref) => {
|
||||
//console.log("TreeMenu render");
|
||||
const {
|
||||
defaultExpandAll,
|
||||
defaultExpandParent,
|
||||
@ -193,6 +215,7 @@ const TreeMenu = React.forwardRef((props, ref) => {
|
||||
gapBetweenNodesTablet,
|
||||
isEmptyRootNode,
|
||||
theme,
|
||||
childrenCount,
|
||||
} = props;
|
||||
const expandedKeysProp = expandedKeys ? { expandedKeys: expandedKeys } : {};
|
||||
|
||||
@ -277,6 +300,10 @@ const TreeMenu = React.forwardRef((props, ref) => {
|
||||
gapBetweenNodes={gapBetweenNodes}
|
||||
gapBetweenNodesTablet={gapBetweenNodesTablet}
|
||||
isEmptyRootNode={isEmptyRootNode}
|
||||
widthAdditional={`calc(100% + ${
|
||||
(childrenCount ? childrenCount : 1) * 32
|
||||
}px)`}
|
||||
multiplicationFactor={32}
|
||||
>
|
||||
{modifiedChildren}
|
||||
</StyledTreeMenu>
|
||||
|
@ -123,7 +123,8 @@ const TreeNodeMenu = styled(TreeNode)`
|
||||
${NoUserSelect}
|
||||
|
||||
.rc-tree-node-selected {
|
||||
max-width: ${(props) => (props.newItems > 999 ? "71%" : "102%")} !important;
|
||||
max-width: ${(props) => (props.newItems > 999 ? "71%" : "87%")} !important;
|
||||
width: calc(100% - 10px) !important;
|
||||
}
|
||||
|
||||
${(props) =>
|
||||
@ -182,9 +183,12 @@ const TreeNodeMenu = styled(TreeNode)`
|
||||
padding: 0;
|
||||
}
|
||||
.rc-tree-node-content-wrapper {
|
||||
width: ${(props) => (props.disableSwitch ? "90%" : "108%")};
|
||||
// width: ${(props) => (props.disableSwitch ? "90%" : "108%")};
|
||||
width: calc(100% - 16px);
|
||||
max-width: 87%;
|
||||
display: inline-block;
|
||||
position: relative;
|
||||
z-index: 2;
|
||||
/*min-width: ${(props) => (props.disableSwitch ? "160px" : "190px")};*/
|
||||
// overflow: hidden;
|
||||
|
||||
@ -220,6 +224,7 @@ const TreeNodeMenu = styled(TreeNode)`
|
||||
|
||||
svg {
|
||||
height: 16px;
|
||||
margin-top: 10px;
|
||||
}
|
||||
}
|
||||
span.rc-tree-iconEle {
|
||||
@ -242,6 +247,8 @@ const TreeNodeMenu = styled(TreeNode)`
|
||||
vertical-align: 1px;
|
||||
height: 24px;
|
||||
width: 8px;
|
||||
z-index: 2;
|
||||
position: relative;
|
||||
}
|
||||
span.rc-tree-switcher.rc-tree-icon__customize,
|
||||
span.rc-tree-checkbox.rc-tree-icon__customize,
|
||||
@ -324,7 +331,7 @@ const TreeNodeMenu = styled(TreeNode)`
|
||||
? props.icon
|
||||
? props.newItems > 999
|
||||
? "calc(100% - 104px)"
|
||||
: "calc(100% - 44px)"
|
||||
: "calc(100% - 16px)"
|
||||
: "calc(100% - 20px)"
|
||||
: "100%"};
|
||||
white-space: nowrap;
|
||||
@ -333,13 +340,14 @@ const TreeNodeMenu = styled(TreeNode)`
|
||||
color: ${(props) => props.theme.treeNode.title.color};
|
||||
padding-left: ${(props) =>
|
||||
props.icon || props.disableSwitch ? "0" : "20px"};
|
||||
margin-top: 2px;
|
||||
}
|
||||
span.rc-tree-title:first-child {
|
||||
max-width: 100%;
|
||||
}
|
||||
|
||||
.rc-tree-node-selected {
|
||||
background: ${(props) => props.theme.treeNode.selected.background};
|
||||
//background: ${(props) => props.theme.treeNode.selected.background};
|
||||
mix-blend-mode: normal;
|
||||
border-radius: ${(props) => props.theme.treeNode.selected.borderRadius};
|
||||
z-index: 0;
|
||||
@ -354,6 +362,9 @@ const TreeNodeMenu = styled(TreeNode)`
|
||||
props.theme.treeNode.selected.hoverBackgroundColor};
|
||||
}
|
||||
overflow: visible;
|
||||
z-index: 2;
|
||||
position: relative;
|
||||
padding-top: 4px;
|
||||
}
|
||||
|
||||
.newItem {
|
||||
|
@ -14,6 +14,8 @@ const globalColors = {
|
||||
veryLightGrey: "#CACACA",
|
||||
darkSilver: "#bbb",
|
||||
silver: "#CCCCCC",
|
||||
lightHover: "#F3F4F4",
|
||||
veryDarkGrey: "#3D3D3D",
|
||||
|
||||
blueMain: "#2DA7DB",
|
||||
blueHover: "#3DB8EC",
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"ConflictResolveDescription": "{{file}} adlı fayl artıq {{folder}} qovluğunda mövcuddur. ",
|
||||
"ConflictResolveDescriptionFiles": "{{filesCount}} sənəd sayı artıq '{{folder}}' qovluğunda mövcuddur.",
|
||||
"ConflictResolveDescription": "<1>{{file}}</1> adlı fayl artıq <1>{{folder}}</1> qovluğunda mövcuddur. ",
|
||||
"ConflictResolveDescriptionFiles": "{{filesCount}} sənəd sayı artıq <1>{{folder}}<1> qovluğunda mövcuddur.",
|
||||
"ConflictResolveSelectAction": "Xahiş edirik əməliyyatı seçin:",
|
||||
"ConflictResolveTitle": "Üzərinə yazmanın təsdiqlənməsi",
|
||||
"CreateDescription": "Qovluqda iki fərqli fayl olacaq. ",
|
||||
@ -9,4 +9,4 @@
|
||||
"OverwriteTitle": "Versiya yenilənməsi ilə üzərinə yazma",
|
||||
"SkipDescription": "Heç bir fayl köçürülmədi. Orijinal fayl köçürülən yerdə dəyişikliksiz qaldı.",
|
||||
"SkipTitle": "Atlamaq"
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"ConflictResolveDescription": "Файл с име {{file}} вече съществува в папка {{folder}}.",
|
||||
"ConflictResolveDescriptionFiles": "{{filesCount}} документа с едно и също име вече съществуват в папката '{{folder}}'.",
|
||||
"ConflictResolveDescription": "Файл с име <1>{{file}}</1> вече съществува в папка <1>{{folder}}</1>.",
|
||||
"ConflictResolveDescriptionFiles": "{{filesCount}} документа с едно и също име вече съществуват в папката <1>{{folder}}<1>.",
|
||||
"ConflictResolveSelectAction": "Моля, изберете действие:",
|
||||
"ConflictResolveTitle": "Потвърждение за презаписване",
|
||||
"CreateDescription": "Ще има два различни файла в папката.",
|
||||
@ -9,4 +9,4 @@
|
||||
"OverwriteTitle": "Препишете с актуализацията на версията",
|
||||
"SkipDescription": "Никой файл няма да бъде копиран. Оригиналният файл ще бъде задържан в целевата папка.",
|
||||
"SkipTitle": "Пропусни"
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"ConflictResolveDescription": "Soubor s názvem {{file}} již existuje ve složce {{folder}}.",
|
||||
"ConflictResolveDescriptionFiles": "Ve složce '{{folder}}' již existuje {{filesCount}} dokumentů se stejným názvem.",
|
||||
"ConflictResolveDescription": "Soubor s názvem <1>{{file}}</1> již existuje ve složce <1>{{folder}}</1>.",
|
||||
"ConflictResolveDescriptionFiles": "Ve složce <1>{{folder}}<1> již existuje {{filesCount}} dokumentů se stejným názvem.",
|
||||
"ConflictResolveSelectAction": "Prosím, vyberte akci:",
|
||||
"ConflictResolveTitle": "Potvrzení o přepsání",
|
||||
"CreateDescription": "Ve složce budou dva různé soubory.",
|
||||
@ -9,4 +9,4 @@
|
||||
"OverwriteTitle": "Přepsat aktualizací verze",
|
||||
"SkipDescription": "Žádný soubor nebude zkopírován. Původní soubor bude zachován v cílové složce.",
|
||||
"SkipTitle": "Přeskočit"
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"ConflictResolveDescription": "Die Datei {{file}} existiert bereits im Ordner {{folder}}",
|
||||
"ConflictResolveDescriptionFiles": "im Ordner '{{folder}}' sind bereits {{filesCount}} Dokumente mit dem gleichen Namen vorhanden",
|
||||
"ConflictResolveDescription": "Die Datei <1>{{file}}</1> existiert bereits im Ordner <1>{{folder}}</1>",
|
||||
"ConflictResolveDescriptionFiles": "im Ordner <1>{{folder}}</1> sind bereits {{filesCount}} Dokumente mit dem gleichen Namen vorhanden",
|
||||
"ConflictResolveSelectAction": "Bitte wählen Sie die Aktion aus:",
|
||||
"ConflictResolveTitle": "Bestätigung überschreiben",
|
||||
"CreateDescription": "Es werden zwei verschiedene Dateien in dem Ordner vorhanden sein.",
|
||||
@ -9,4 +9,4 @@
|
||||
"OverwriteTitle": "Überschreiben mit Versions-Update",
|
||||
"SkipDescription": "Es wird keine Datei kopiert. Die Originaldatei wird im Zielordner beibehalten.",
|
||||
"SkipTitle": "Überspringen"
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"ConflictResolveDescription": "Το αρχείο με το όνομα {{file}} υπάρχει ήδη στον φάκελο {{folder}}.",
|
||||
"ConflictResolveDescriptionFiles": "{{filesCount}} έγγραφα με το ίδιο όνομα υπάρχουν ήδη στον φάκελο {{folder}}",
|
||||
"ConflictResolveDescription": "Το αρχείο με το όνομα <1>{{file}}</1> υπάρχει ήδη στον φάκελο <1>{{folder}}</1>.",
|
||||
"ConflictResolveDescriptionFiles": "{{filesCount}} έγγραφα με το ίδιο όνομα υπάρχουν ήδη στον φάκελο <1>{{folder}}</1>",
|
||||
"ConflictResolveSelectAction": "Επιλέξτε την ενέργεια",
|
||||
"ConflictResolveTitle": "Επιβεβαίωση αντικατάστασης",
|
||||
"CreateDescription": "Θα υπάρχουν δύο διαφορετικά αρχεία στον φάκελο.",
|
||||
@ -9,4 +9,4 @@
|
||||
"OverwriteTitle": "Αντικατάσταση με ενημέρωση έκδοσης",
|
||||
"SkipDescription": "Δεν θα αντιγραφεί κανένα αρχείο. Το αρχικό αρχείο θα διατηρηθεί στον φάκελο προορισμού.",
|
||||
"SkipTitle": "Παράλειψη"
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"ConflictResolveDescription": "The file with the name {{file}} already exists in the folder {{folder}}.",
|
||||
"ConflictResolveDescriptionFiles": "{{filesCount}} documents with the same name already exist in the folder '{{folder}}'.",
|
||||
"ConflictResolveDescription": "The file with the name <1>{{file}}</1> already exists in the folder <1>{{folder}}</1>.",
|
||||
"ConflictResolveDescriptionFiles": "{{filesCount}} documents with the same name already exist in the folder <1>{{folder}}</1>.",
|
||||
"ConflictResolveSelectAction": "Please select the action:",
|
||||
"ConflictResolveTitle": "Overwrite confirmation",
|
||||
"CreateDescription": "There will be two different files in the folder.",
|
||||
@ -9,4 +9,4 @@
|
||||
"OverwriteTitle": "Overwrite with version update",
|
||||
"SkipDescription": "No file will be copied. The original file will be retained in the destination folder.",
|
||||
"SkipTitle": "Skip"
|
||||
}
|
||||
}
|
||||
|
@ -1,3 +1,4 @@
|
||||
{
|
||||
"NotAvailableFolder": "No folders available"
|
||||
}
|
||||
"NotAvailableFolder": "No folders available",
|
||||
"FolderContents": "The contents of the '{{folderTitle}}' folder"
|
||||
}
|
||||
|
@ -4,6 +4,7 @@
|
||||
"ButtonShareAccess": "Sharing Settings",
|
||||
"ConnectingAccount": "Connecting account",
|
||||
"Copy": "Copy",
|
||||
"CopyHere": "Copy here",
|
||||
"CreateMasterFormFromFile": "Create Form Template from file",
|
||||
"DeleteFromTrash": "Selected elements were successfully deleted from Trash",
|
||||
"DeleteOperation": "Deleting",
|
||||
@ -11,6 +12,7 @@
|
||||
"DeleteThirdParty": "Delete third-party",
|
||||
"DownloadApps": "Download applications",
|
||||
"DownloadAs": "Download as",
|
||||
"Documents": "Documents",
|
||||
"EncryptedFileSaving": "Saving encrypted file",
|
||||
"Files": "Files",
|
||||
"FileProtected": "The file is password protected",
|
||||
@ -33,6 +35,7 @@
|
||||
"MobileMac": "Download ONLYOFFICE Desktop Editors for Mac OS",
|
||||
"MobileWin": "Download ONLYOFFICE Desktop Editors for Windows",
|
||||
"Move": "Move",
|
||||
"MoveHere": "Move here",
|
||||
"MoveToOperation": "Moving",
|
||||
"NewForm": "Form template",
|
||||
"NewFormFile": "Form from text file",
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"ConflictResolveDescription": "El archivo con el nombre {{file}} ya existe en la carpeta {{folder}}.",
|
||||
"ConflictResolveDescriptionFiles": "{{filesCount}} documentos con el mismo nombre ya existen en la carpeta '{{folder}}'.",
|
||||
"ConflictResolveDescription": "El archivo con el nombre <1>{{file}}</1> ya existe en la carpeta <1>{{folder}}</1>.",
|
||||
"ConflictResolveDescriptionFiles": "{{filesCount}} documentos con el mismo nombre ya existen en la carpeta <1>{{folder}}</1>.",
|
||||
"ConflictResolveSelectAction": "Por favor, seleccione la acción:",
|
||||
"ConflictResolveTitle": "Confirmación de sobrescritura",
|
||||
"CreateDescription": "Habrá dos archivos diferentes en la carpeta.",
|
||||
@ -9,4 +9,4 @@
|
||||
"OverwriteTitle": "Sobrescribir con la actualización de la versión",
|
||||
"SkipDescription": "No se copiará ningún archivo. El archivo original se conservará en la carpeta de destino.",
|
||||
"SkipTitle": "Omitir"
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"ConflictResolveDescription": "Tiedosto, jonka nimi on {{file}}, on jo kansiossa {{folder}}.",
|
||||
"ConflictResolveDescriptionFiles": "{{filesCount}} samannimistä asiakirjaa on jo olemassa kansiossa {{folder}}.",
|
||||
"ConflictResolveDescription": "Tiedosto, jonka nimi on <1>{{file}}</1>, on jo kansiossa <1>{{folder}}</1>.",
|
||||
"ConflictResolveDescriptionFiles": "{{filesCount}} samannimistä asiakirjaa on jo olemassa kansiossa <1>{{folder}}</1>.",
|
||||
"ConflictResolveSelectAction": "Valitse toiminto:",
|
||||
"ConflictResolveTitle": "Korvaamisen vahvistus",
|
||||
"CreateDescription": "Kansiossa tulee olemaan kaksi eri tiedostoa.",
|
||||
@ -9,4 +9,4 @@
|
||||
"OverwriteTitle": "Korvaa versiopäivityksellä",
|
||||
"SkipDescription": "Mitään tiedostoa ei kopioida. Alkuperäinen tiedosto säilytetään kohdekansiossa.",
|
||||
"SkipTitle": "Ohita"
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"ConflictResolveDescription": "Le fichier portant le nom {{file}} existe déjà dans le dossier {{folder}}.",
|
||||
"ConflictResolveDescriptionFiles": "{{filesCount}} les documents portant le même nom existent déjà dans le dossier '{{folder}}'.",
|
||||
"ConflictResolveDescription": "Le fichier portant le nom <1>{{file}}</1> existe déjà dans le dossier <1>{{folder}}</1>.",
|
||||
"ConflictResolveDescriptionFiles": "{{filesCount}} les documents portant le même nom existent déjà dans le dossier <1>{{folder}}</1>.",
|
||||
"ConflictResolveSelectAction": "Veuillez sélectionner une action :",
|
||||
"ConflictResolveTitle": "Confirmation de l'écrasement",
|
||||
"CreateDescription": "Il y aura deux fichiers différents dans le dossier.",
|
||||
@ -9,4 +9,4 @@
|
||||
"OverwriteTitle": "Écraser avec la mise à jour de la version",
|
||||
"SkipDescription": "Aucun fichier ne sera copié. Le fichier d'origine sera conservé dans le dossier de destination.",
|
||||
"SkipTitle": "Sauter"
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"ConflictResolveDescription": "Il file con il nome {{file}} già esiste nella cartella {{folder}}.",
|
||||
"ConflictResolveDescriptionFiles": "{{filesCount}} documenti con lo stesso nome esistono già nella cartella '{{folder}}'.",
|
||||
"ConflictResolveDescription": "Il file con il nome <1>{{file}}</1> già esiste nella cartella <1>{{folder}}</1>.",
|
||||
"ConflictResolveDescriptionFiles": "{{filesCount}} documenti con lo stesso nome esistono già nella cartella <1>{{folder}}</1>.",
|
||||
"ConflictResolveSelectAction": "Ti preghiamo di selezionare l'azione:",
|
||||
"ConflictResolveTitle": "Confermare sovrascrittura",
|
||||
"CreateDescription": "Ci saranno due file diversi nella cartella.",
|
||||
@ -9,4 +9,4 @@
|
||||
"OverwriteTitle": "Sovrascrivere con l'aggiornamento della versione",
|
||||
"SkipDescription": "Nessun file verrà copiato. Il file originale verrà conservato nella cartella di destinazione.",
|
||||
"SkipTitle": "Saltare"
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"ConflictResolveDescription": "フォルダ{{folder}}内に{{file}}という名前のファイルがすでに存在しています。",
|
||||
"ConflictResolveDescriptionFiles": "{{filesCount}}フォルダ'{{folder}}'に同名のドキュメントがすでに存在しています。",
|
||||
"ConflictResolveDescription": "フォルダ<1>{{folder}}</1>内に<1>{{file}}</1>という名前のファイルがすでに存在しています。",
|
||||
"ConflictResolveDescriptionFiles": "{{filesCount}}フォルダ<1>{{folder}}</1>に同名のドキュメントがすでに存在しています。",
|
||||
"ConflictResolveSelectAction": "アクションをお選びください:",
|
||||
"ConflictResolveTitle": "上書き確認",
|
||||
"CreateDescription": "フォルダ内には2種類のファイルが存在します。",
|
||||
@ -9,4 +9,4 @@
|
||||
"OverwriteTitle": "バージョンアップによる上書き",
|
||||
"SkipDescription": "ファイルはコピーされません。元のファイルはコピー先のフォルダーに保持されます。",
|
||||
"SkipTitle": "スキップ"
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"ConflictResolveDescription": "{{file}} 이름의 파일이 {{folder}} 폴더에 이미 존재합니다.",
|
||||
"ConflictResolveDescriptionFiles": "같은 이름의 문서 {{filesCount}}개가 '{{folder}}' 폴더에 이미 존재합니다.",
|
||||
"ConflictResolveDescription": "<1>{{file}}</1> 이름의 파일이 <1>{{folder}}</1> 폴더에 이미 존재합니다.",
|
||||
"ConflictResolveDescriptionFiles": "같은 이름의 문서 {{filesCount}}개가 <1>{{folder}}</1> 폴더에 이미 존재합니다.",
|
||||
"ConflictResolveSelectAction": "작업 선택:",
|
||||
"ConflictResolveTitle": "덮어쓰기",
|
||||
"CreateDescription": "폴더에 두 개의 다른 파일이 저장됩니다.",
|
||||
@ -9,4 +9,4 @@
|
||||
"OverwriteTitle": "버전 업데이트로 덮어쓰기",
|
||||
"SkipDescription": "파일이 복사되지 않습니다. 원본 파일이 대상 폴더에 유지됩니다.",
|
||||
"SkipTitle": "건너뛰기"
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"ConflictResolveDescription": "ຊື່ໄຟລ໌ {{file}} ມີຢູ່ໃນໂຟນເດີ {{folder}} ແລ້ວ.",
|
||||
"ConflictResolveDescriptionFiles": "{{filesCount}} ມີເອກະສານຊື່ດ່ຽວກັນໃນໂໄນເດີ້ແລ້ວ '{{folder}}'.",
|
||||
"ConflictResolveDescription": "ຊື່ໄຟລ໌ <1>{{file}}</1> ມີຢູ່ໃນໂຟນເດີ <1>{{folder}}</1> ແລ້ວ.",
|
||||
"ConflictResolveDescriptionFiles": "{{filesCount}} ມີເອກະສານຊື່ດ່ຽວກັນໃນໂໄນເດີ້ແລ້ວ <1>{{folder}}</1>.",
|
||||
"ConflictResolveSelectAction": "ກະລຸນາເລືອກການດຳເນີນການ",
|
||||
"ConflictResolveTitle": "ຢືນຢັນການທັບ",
|
||||
"CreateDescription": "ໃນໂຟນເດີ້ຈະມີ 2 ໄຟລ໌ແຕກຕ່າງກັນ.",
|
||||
@ -9,4 +9,4 @@
|
||||
"OverwriteTitle": "ອັບເດດທັບເວີຊັ່ນເກົ່າ",
|
||||
"SkipDescription": "ໄຟລ໌ຈະບໍ່ຖືກສຳເນົາ ໄຟລ໌ຕົ້ນສະບັບຈະຖືກເກັບໄວ້ໃນໂຟນເດີ້.",
|
||||
"SkipTitle": "ຂ້າມ"
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"ConflictResolveDescription": "Fails ar nosaukumu {{file}} jau pastāv mapē {{folder}}.",
|
||||
"ConflictResolveDescriptionFiles": "{{filesCount}} dokumenti ar tādu pašu nosaukumu jau pastāv mapē '{{folder}}'.",
|
||||
"ConflictResolveDescription": "Fails ar nosaukumu <1>{{file}}</1> jau pastāv mapē <1>{{folder}}</1>.",
|
||||
"ConflictResolveDescriptionFiles": "{{filesCount}} dokumenti ar tādu pašu nosaukumu jau pastāv mapē <1>{{folder}}</1>.",
|
||||
"ConflictResolveSelectAction": "Lūdzu, atlasiet darbību:",
|
||||
"ConflictResolveTitle": "Pārrakstiet apstiprinājumu",
|
||||
"CreateDescription": "Mapē būs divi dažādi faili.",
|
||||
@ -9,4 +9,4 @@
|
||||
"OverwriteTitle": "Overwrite with version update",
|
||||
"SkipDescription": "Fails tiks pievienots failam ar tādu pašu nosaukumu kā versijai.",
|
||||
"SkipTitle": "Izlaist"
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"ConflictResolveDescription": "Het bestand met de naam {{file}} bestaat al in de map {{folder}}.",
|
||||
"ConflictResolveDescriptionFiles": "{{filesCount}} documenten met dezelfde naam al bestaan in de map '{{folder}}'.",
|
||||
"ConflictResolveDescription": "Het bestand met de naam <1>{{file}}</1> bestaat al in de map <1>{{folder}}</1>.",
|
||||
"ConflictResolveDescriptionFiles": "{{filesCount}} documenten met dezelfde naam al bestaan in de map <1>{{folder}}</1>.",
|
||||
"ConflictResolveSelectAction": "Kies de actie:",
|
||||
"ConflictResolveTitle": "Overschrijf bevestiging",
|
||||
"CreateDescription": "Er zullen twee verschillende bestanden in de map staan.",
|
||||
@ -9,4 +9,4 @@
|
||||
"OverwriteTitle": "Overschrijven met versie update",
|
||||
"SkipDescription": "Er wordt geen bestand gekopieerd. Het originele bestand blijft bewaard in de doelmap.",
|
||||
"SkipTitle": "Overslaan"
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"ConflictResolveDescription": "Plik o nazwie {{file}} istnieje już w folderze {{folder}}.",
|
||||
"ConflictResolveDescriptionFiles": "{{filesCount}} dokument(y/ów) o tej samej nazwie istnieje(-ją) już w folderze '{{folder}}'.",
|
||||
"ConflictResolveDescription": "Plik o nazwie <1>{{file}}</1> istnieje już w folderze <1>{{folder}}</1>.",
|
||||
"ConflictResolveDescriptionFiles": "{{filesCount}} dokument(y/ów) o tej samej nazwie istnieje(-ją) już w folderze <1>{{folder}}</1>.",
|
||||
"ConflictResolveSelectAction": "Wybierz działanie:",
|
||||
"ConflictResolveTitle": "Potwierdź zastąpienie",
|
||||
"CreateDescription": "W folderze będą dwa różne pliki.",
|
||||
@ -9,4 +9,4 @@
|
||||
"OverwriteTitle": "Zastąp i zaktualizuj wersję",
|
||||
"SkipDescription": "Żaden plik nie zostanie skopiowany. Oryginalny plik zostanie zachowany w folderze docelowym.",
|
||||
"SkipTitle": "Pomiń"
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"ConflictResolveDescription": "O arquivo com o nome {{file}} já existe na pasta {{folder}}.",
|
||||
"ConflictResolveDescriptionFiles": "{{filesCount}} Os documentos com o mesmo nome já existem na pasta '{{folder}}.",
|
||||
"ConflictResolveDescription": "O arquivo com o nome <1>{{file}}</1> já existe na pasta <1>{{folder}}</1>.",
|
||||
"ConflictResolveDescriptionFiles": "{{filesCount}} Os documentos com o mesmo nome já existem na pasta <1>{{folder}}</1>.",
|
||||
"ConflictResolveSelectAction": "Selecione a ação:",
|
||||
"ConflictResolveTitle": "Confirmação de substituição",
|
||||
"CreateDescription": "Haverão dois arquivos diferentes na pasta.",
|
||||
@ -9,4 +9,4 @@
|
||||
"OverwriteTitle": "Substituir por versão atualizada",
|
||||
"SkipDescription": "Nenhum arquivo será copiado. O arquivo original será mantido na pasta de destino.",
|
||||
"SkipTitle": "Pular"
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"ConflictResolveDescription": "O ficheiro com o nome {{file}} já existe na pasta {{folder}}.",
|
||||
"ConflictResolveDescriptionFiles": "{{filesCount}} documentos com o mesmo nome já existem na pasta '{{folder}}.",
|
||||
"ConflictResolveDescription": "O ficheiro com o nome <1>{{file}}</1> já existe na pasta <1>{{folder}}</1>.",
|
||||
"ConflictResolveDescriptionFiles": "{{filesCount}} documentos com o mesmo nome já existem na pasta <1>{{folder}}</1>.",
|
||||
"ConflictResolveSelectAction": "Selecione a ação:",
|
||||
"ConflictResolveTitle": "Confirmação de substituição",
|
||||
"CreateDescription": "Haverá dois ficheiros diferentes na pasta.",
|
||||
@ -9,4 +9,4 @@
|
||||
"OverwriteTitle": "Substituir por versão atualizada",
|
||||
"SkipDescription": "Nenhum ficheiro será copiado. O ficheiro original será mantido na pasta de destino.",
|
||||
"SkipTitle": "Ignorar"
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"ConflictResolveDescription": "Fișierul cu numele {{file}} există deja în dosarul {{folder}}.",
|
||||
"ConflictResolveDescriptionFiles": "{{filesCount}} fișiere cu același nume exista deja în folderul'{{folder}}'.",
|
||||
"ConflictResolveDescription": "Fișierul cu numele <1>{{file}}</1> există deja în dosarul <1>{{folder}}</1>.",
|
||||
"ConflictResolveDescriptionFiles": "{{filesCount}} fișiere cu același nume exista deja în folderul<1>{{folder}}</1>.",
|
||||
"ConflictResolveSelectAction": "Selectați acțiune:",
|
||||
"ConflictResolveTitle": "Confirmarea suprascrierii",
|
||||
"CreateDescription": "Două fișiere diferite vor fi salvate în dosarul.",
|
||||
@ -9,4 +9,4 @@
|
||||
"OverwriteTitle": "Suprascriere la o versiune actualizată",
|
||||
"SkipDescription": "Niciun fișier n-o să fie copiat. Fișierul de origine rămâne în dosarul de destinație.",
|
||||
"SkipTitle": "Treci mai departe"
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"ConflictResolveDescription": "Файл с именем {{file}} уже существует в папке {{folder}}.",
|
||||
"ConflictResolveDescriptionFiles": "{{filesCount}} документов с одинаковыми именами уже существуют в папке '{{folder}}'.",
|
||||
"ConflictResolveDescription": "Файл с именем <1>{{file}}</1> уже существует в папке <1>{{folder}}</1>.",
|
||||
"ConflictResolveDescriptionFiles": "{{filesCount}} документов с одинаковыми именами уже существуют в папке <1>{{folder}}</1>.",
|
||||
"ConflictResolveSelectAction": "Пожалуйста, выберите действие:",
|
||||
"ConflictResolveTitle": "Подтверждение перезаписи",
|
||||
"CreateDescription": "В папке будет два разных файла.",
|
||||
@ -9,4 +9,4 @@
|
||||
"OverwriteTitle": "Перезаписать с обновлением версии",
|
||||
"SkipDescription": "Файл не будет скопирован. В папке назначения останется исходный файл.",
|
||||
"SkipTitle": "Пропустить"
|
||||
}
|
||||
}
|
||||
|
@ -1,3 +1,4 @@
|
||||
{
|
||||
"NotAvailableFolder": "Нет доступных папок"
|
||||
}
|
||||
"NotAvailableFolder": "Нет доступных папок",
|
||||
"FolderContents": "Содержимое папки '{{folderTitle}}'"
|
||||
}
|
||||
|
@ -4,6 +4,7 @@
|
||||
"ButtonShareAccess": "Настройка доступа",
|
||||
"ConnectingAccount": "Подключение аккаунта",
|
||||
"Copy": "Копировать",
|
||||
"CopyHere": "Копировать сюда",
|
||||
"CreateMasterFormFromFile": "Создать шаблон формы из файла",
|
||||
"DeleteFromTrash": "Выбранные элементы успешно удалены из корзины",
|
||||
"DeleteOperation": "Удаление",
|
||||
@ -11,6 +12,7 @@
|
||||
"DeleteThirdParty": "Отключить сторонний ресурс",
|
||||
"DownloadApps": "Скачать приложения",
|
||||
"DownloadAs": "Скачать как",
|
||||
"Documents": "Документы",
|
||||
"EncryptedFileSaving": "Сохранение зашифрованного файла",
|
||||
"Files": "Файлы",
|
||||
"FileProtected": "Файл защищен с помощью пароля",
|
||||
@ -33,6 +35,7 @@
|
||||
"MobileMac": "Скачать десктопные редакторы ONLYOFFICE для Mac OS",
|
||||
"MobileWin": "Скачать десктопные редакторы ONLYOFFICE для Windows",
|
||||
"Move": "Переместить",
|
||||
"MoveHere": "Переместить сюда",
|
||||
"MoveToOperation": "Перемещение",
|
||||
"NewForm": "Шаблон формы",
|
||||
"NewFormFile": "Форма из текстового файла",
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"ConflictResolveDescription": "Súbor s názvom {{file}} už v priečinku {{folder}} existuje.",
|
||||
"ConflictResolveDescriptionFiles": "Dokumenty {{filesCount}} s rovnakými názvami už v priečinku '{{folder}}' existujú.",
|
||||
"ConflictResolveDescription": "Súbor s názvom <1>{{file}}</1> už v priečinku <1>{{folder}}</1> existuje.",
|
||||
"ConflictResolveDescriptionFiles": "Dokumenty {{filesCount}} s rovnakými názvami už v priečinku <1>{{folder}}</1> existujú.",
|
||||
"ConflictResolveSelectAction": "Vyberte akciu:",
|
||||
"ConflictResolveTitle": "Potvrdenie prepísania",
|
||||
"CreateDescription": "V priečinku budú dva rôzne súbory.",
|
||||
@ -9,4 +9,4 @@
|
||||
"OverwriteTitle": "Prepísať a aktualizovať verziu",
|
||||
"SkipDescription": "Žiadny súbor nebude skopírovaný. Pôvodný súbor zostane v cieľovom priečinku.",
|
||||
"SkipTitle": "Preskočiť"
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"ConflictResolveDescription": "Datoteka z imenom {{file}} že obstaja v mapi {{folder}}.",
|
||||
"ConflictResolveDescriptionFiles": "{{filesCount}} dokumentov z enakim imenom že obstaja v mapi '{{folder}}'.",
|
||||
"ConflictResolveDescription": "Datoteka z imenom <1>{{file}}</1> že obstaja v mapi <1>{{folder}}</1>.",
|
||||
"ConflictResolveDescriptionFiles": "{{filesCount}} dokumentov z enakim imenom že obstaja v mapi <1>{{folder}}</1>.",
|
||||
"ConflictResolveSelectAction": "Prosim, izberite akcijo:",
|
||||
"ConflictResolveTitle": "Prepišite potrditev",
|
||||
"CreateDescription": "V mapi bosta dve različni datoteki.",
|
||||
@ -9,4 +9,4 @@
|
||||
"OverwriteTitle": "Prepišite s posodobitvijo različice",
|
||||
"SkipDescription": "Nobena datoteka ne bo kopirana. Izvirna datoteka bo shranjena v ciljni mapi.",
|
||||
"SkipTitle": "Preskoči"
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"ConflictResolveDescription": "{{file}} isimli dosya {{folder}} klasöründe zaten mevcut.",
|
||||
"ConflictResolveDescriptionFiles": "{{filesCount}} belgeleri, '{{folder}}' klasöründe aynı isimle zaten mevcut.",
|
||||
"ConflictResolveDescription": "<1>{{file}}</1> isimli dosya <1>{{folder}}</1> klasöründe zaten mevcut.",
|
||||
"ConflictResolveDescriptionFiles": "{{filesCount}} belgeleri, <1>{{folder}}</1> klasöründe aynı isimle zaten mevcut.",
|
||||
"ConflictResolveSelectAction": "Lütfen işlemi seçin:",
|
||||
"ConflictResolveTitle": "Üstüne yazma onayı",
|
||||
"CreateDescription": "Klasörde iki farklı dosya olacaktır.",
|
||||
@ -9,4 +9,4 @@
|
||||
"OverwriteTitle": "Sürüm güncellemesiyle üstüne yaz",
|
||||
"SkipDescription": "Hiçbir dosya kopyalanmayacaktır. Orijinal dosya hedef klasörde tutulacaktır.",
|
||||
"SkipTitle": "Atla"
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"ConflictResolveDescription": "Файл із іменем {{file}} уже існує в папці {{folder}}.",
|
||||
"ConflictResolveDescriptionFiles": "Документи ({{filesCount}}) з таким ім'ям вже існують у папці {{folder}}.",
|
||||
"ConflictResolveDescription": "Файл із іменем <1>{{file}}<1> уже існує в папці <1>{{folder}}</1>.",
|
||||
"ConflictResolveDescriptionFiles": "Документи ({{filesCount}}) з таким ім'ям вже існують у папці <1>{{folder}}</1>.",
|
||||
"ConflictResolveSelectAction": "Оберіть дію:",
|
||||
"ConflictResolveTitle": "Підтвердження перезапису",
|
||||
"CreateDescription": "У папці буде два різних файли.",
|
||||
@ -9,4 +9,4 @@
|
||||
"OverwriteTitle": "Перезапис з оновленням версії",
|
||||
"SkipDescription": "Жоден файл не буде скопійовано. Оригінальний файл буде збережено у папці призначення.",
|
||||
"SkipTitle": "Пропустити"
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"ConflictResolveDescription": " Tệp có tên {{file}} đã tồn tại trong thư mục {{folder}}.",
|
||||
"ConflictResolveDescriptionFiles": " {{filesCount}} tài liệu có cùng tên đã tồn tại trong thư mục '{{folder}}.",
|
||||
"ConflictResolveDescription": " Tệp có tên <1>{{file}}</1> đã tồn tại trong thư mục <1>{{folder}}</1>.",
|
||||
"ConflictResolveDescriptionFiles": " {{filesCount}} tài liệu có cùng tên đã tồn tại trong thư mục <1>{{folder}}</1>.",
|
||||
"ConflictResolveSelectAction": "Vui lòng chọn hành động:",
|
||||
"ConflictResolveTitle": "Xác nhận ghi đè",
|
||||
"CreateDescription": "Sẽ có hai tệp khác nhau trong thư mục.",
|
||||
@ -9,4 +9,4 @@
|
||||
"OverwriteTitle": " Ghi đè bằng cập nhật phiên bản",
|
||||
"SkipDescription": "Không có tệp nào được sao chép. Tệp gốc sẽ được giữ lại trong thư mục đích.",
|
||||
"SkipTitle": "Bỏ qua"
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"ConflictResolveDescription": "{{folder}}文件夹中已有名称为{{file}}的文件。",
|
||||
"ConflictResolveDescriptionFiles": "‘{{folder}}’文件夹中已有{{filesCount}}个名称相同的文档。",
|
||||
"ConflictResolveDescription": "<1>{{folder}}</1>文件夹中已有名称为<1>{{file}}</1>的文件。",
|
||||
"ConflictResolveDescriptionFiles": "<1>{{folder}}</1>文件夹中已有{{filesCount}}个名称相同的文档。",
|
||||
"ConflictResolveSelectAction": "请选择操作:",
|
||||
"ConflictResolveTitle": "覆盖确认",
|
||||
"CreateDescription": "文件夹中将有两种不同文件。",
|
||||
@ -9,4 +9,4 @@
|
||||
"OverwriteTitle": "使用版本更新覆盖",
|
||||
"SkipDescription": "不会复制任何文件。原始文件将在目标文件夹中保留。",
|
||||
"SkipTitle": "跳过"
|
||||
}
|
||||
}
|
||||
|
@ -89,15 +89,15 @@ const Panels = (props) => {
|
||||
selectFileDialogVisible && (
|
||||
<SelectFileDialog
|
||||
key="select-file-dialog"
|
||||
resetTreeFolders
|
||||
//resetTreeFolders
|
||||
onSelectFile={createMasterForm}
|
||||
isPanelVisible={selectFileDialogVisible}
|
||||
onClose={onClose}
|
||||
foldersType="exceptPrivacyTrashFolders"
|
||||
ByExtension
|
||||
searchParam={".docx"}
|
||||
headerName={t("Translations:CreateMasterFormFromFile")}
|
||||
titleFilesList={t("SelectFile:SelectDOCXFormat")}
|
||||
dialogName={t("Translations:CreateMasterFormFromFile")}
|
||||
filesListTitle={t("SelectFile:SelectDOCXFormat")}
|
||||
creationButtonPrimary
|
||||
withSubfolders={false}
|
||||
/>
|
||||
|
@ -26,12 +26,12 @@ const StyledTreeMenu = styled(TreeMenu)`
|
||||
background: ${(props) => !props.dragging && "none !important"};
|
||||
}
|
||||
|
||||
.rc-tree-node-selected {
|
||||
/* .rc-tree-node-selected {
|
||||
background: ${(props) =>
|
||||
!props.isPanel
|
||||
? props.theme.filesArticleBody.background
|
||||
: props.theme.filesArticleBody.panelBackground} !important;
|
||||
}
|
||||
!props.isPanel
|
||||
? props.theme.filesArticleBody.background
|
||||
: props.theme.filesArticleBody.panelBackground} !important;
|
||||
} */
|
||||
|
||||
.rc-tree-treenode-disabled > span:not(.rc-tree-switcher),
|
||||
.rc-tree-treenode-disabled > a,
|
||||
@ -453,7 +453,7 @@ class TreeFolders extends React.Component {
|
||||
isLoading,
|
||||
onSelect,
|
||||
dragging,
|
||||
expandedKeys,
|
||||
|
||||
expandedPanelKeys,
|
||||
treeFolders,
|
||||
data,
|
||||
@ -475,7 +475,7 @@ class TreeFolders extends React.Component {
|
||||
onSelect={onSelect}
|
||||
selectedKeys={selectedKeys}
|
||||
loadData={this.onLoadData}
|
||||
expandedKeys={expandedPanelKeys ? expandedPanelKeys : expandedKeys}
|
||||
expandedKeys={expandedPanelKeys}
|
||||
onExpand={this.onExpand}
|
||||
onDragOver={this.onDragOver}
|
||||
onDragLeave={this.onDragLeave}
|
||||
@ -484,6 +484,7 @@ class TreeFolders extends React.Component {
|
||||
gapBetweenNodes="22"
|
||||
gapBetweenNodesTablet="26"
|
||||
isFullFillSelection={false}
|
||||
childrenCount={expandedPanelKeys?.length}
|
||||
>
|
||||
{this.getItems(data || treeFolders)}
|
||||
</StyledTreeMenu>
|
||||
@ -515,7 +516,6 @@ export default inject(
|
||||
myFolderId,
|
||||
commonFolderId,
|
||||
isPrivacyFolder,
|
||||
expandedKeys,
|
||||
setExpandedKeys,
|
||||
setExpandedPanelKeys,
|
||||
getSubfolders,
|
||||
@ -532,7 +532,6 @@ export default inject(
|
||||
commonId: commonFolderId,
|
||||
isPrivacy: isPrivacyFolder,
|
||||
draggableItems: dragging ? selection : null,
|
||||
expandedKeys,
|
||||
treeFolders,
|
||||
isLoading,
|
||||
selectedKeys: useDefaultSelectedKeys
|
||||
@ -547,8 +546,4 @@ export default inject(
|
||||
getSubfolders,
|
||||
};
|
||||
}
|
||||
)(
|
||||
withTranslation(["Home", "Common"])(
|
||||
withLoader(observer(TreeFolders))(<Loaders.TreeFolders />)
|
||||
)
|
||||
);
|
||||
)(withTranslation(["Home", "Common"])(observer(TreeFolders)));
|
||||
|
@ -1,79 +1,50 @@
|
||||
import React from "react";
|
||||
import { inject, observer } from "mobx-react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import Loader from "@appserver/components/loader";
|
||||
import Text from "@appserver/components/text";
|
||||
import Scrollbar from "@appserver/components/scrollbar";
|
||||
import TreeFolders from "./TreeFolders";
|
||||
import { StyledSelectFolderPanel } from "../panels/StyledPanels";
|
||||
import { StyledTree } from "../panels/SelectionPanel/StyledSelectionPanel";
|
||||
const FolderTreeBody = ({
|
||||
isLoadingData,
|
||||
expandedKeys,
|
||||
folderList,
|
||||
folderTree,
|
||||
onSelect,
|
||||
withoutProvider,
|
||||
certainFolders,
|
||||
isAvailable,
|
||||
filter,
|
||||
selectedKeys,
|
||||
heightContent,
|
||||
displayType,
|
||||
isHeaderChildren,
|
||||
theme,
|
||||
isDisableTree,
|
||||
}) => {
|
||||
const { t } = useTranslation(["SelectFolder", "Common"]);
|
||||
return (
|
||||
<>
|
||||
{!isLoadingData ? (
|
||||
isAvailable ? (
|
||||
<StyledSelectFolderPanel
|
||||
heightContent={heightContent}
|
||||
displayType={displayType}
|
||||
isHeaderChildren={isHeaderChildren}
|
||||
>
|
||||
<div className="select-folder-dialog_tree-folder">
|
||||
<Scrollbar id="folder-tree-scroll-bar">
|
||||
<TreeFolders
|
||||
isPanel={true}
|
||||
expandedPanelKeys={expandedKeys}
|
||||
data={folderList}
|
||||
filter={filter}
|
||||
onSelect={onSelect}
|
||||
withoutProvider={withoutProvider}
|
||||
certainFolders={certainFolders}
|
||||
selectedKeys={selectedKeys}
|
||||
needUpdate={false}
|
||||
/>
|
||||
</Scrollbar>
|
||||
</div>
|
||||
</StyledSelectFolderPanel>
|
||||
) : (
|
||||
<StyledSelectFolderPanel
|
||||
heightContent={heightContent}
|
||||
isHeaderChildren={isHeaderChildren}
|
||||
>
|
||||
<div className="tree-folder-empty-list select-folder-dialog_tree-folder">
|
||||
<Text as="span">{t("NotAvailableFolder")}</Text>
|
||||
</div>
|
||||
</StyledSelectFolderPanel>
|
||||
)
|
||||
) : (
|
||||
<StyledSelectFolderPanel heightContent={heightContent}>
|
||||
<div className="tree-folder-Loader" key="loader">
|
||||
<Loader
|
||||
type="oval"
|
||||
size="16px"
|
||||
style={{
|
||||
display: "inline",
|
||||
marginRight: "10px",
|
||||
marginTop: "16px",
|
||||
}}
|
||||
/>
|
||||
<Text as="span">{`${t("Common:LoadingProcessing")} ${t(
|
||||
"Common:LoadingDescription"
|
||||
)}`}</Text>
|
||||
{isAvailable ? (
|
||||
<StyledTree theme={theme}>
|
||||
<div className="selection-panel_tree-folder">
|
||||
<Scrollbar id="folder-tree-scroll-bar">
|
||||
<TreeFolders
|
||||
isPanel={true}
|
||||
expandedPanelKeys={expandedKeys}
|
||||
data={folderTree}
|
||||
filter={filter}
|
||||
onSelect={onSelect}
|
||||
withoutProvider={withoutProvider}
|
||||
certainFolders={certainFolders}
|
||||
selectedKeys={selectedKeys}
|
||||
disabled={isDisableTree}
|
||||
needUpdate={false}
|
||||
/>
|
||||
</Scrollbar>
|
||||
</div>
|
||||
</StyledSelectFolderPanel>
|
||||
</StyledTree>
|
||||
) : (
|
||||
<StyledTree>
|
||||
<div className="selection-panel_empty-folder">
|
||||
<Text as="span">{t("NotAvailableFolder")}</Text>
|
||||
</div>
|
||||
</StyledTree>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
@ -88,8 +59,15 @@ export default inject(
|
||||
({ filesStore, treeFoldersStore, selectedFolderStore }) => {
|
||||
const { filter, isLoading } = filesStore;
|
||||
const { expandedPanelKeys } = treeFoldersStore;
|
||||
|
||||
const expandedKeysProp = expandedPanelKeys
|
||||
? expandedPanelKeys
|
||||
: selectedFolderStore.pathParts;
|
||||
const expandedKeys = expandedKeysProp?.map((item) => item.toString());
|
||||
!expandedPanelKeys && expandedKeys?.pop();
|
||||
return {
|
||||
expandedKeys: expandedPanelKeys ? expandedPanelKeys : null,
|
||||
expandedKeys: expandedKeys,
|
||||
|
||||
filter,
|
||||
isLoading,
|
||||
};
|
||||
|
@ -4,7 +4,7 @@ import ModalDialog from "@appserver/components/modal-dialog";
|
||||
import RadioButtonGroup from "@appserver/components/radio-button-group";
|
||||
import Button from "@appserver/components/button";
|
||||
import Text from "@appserver/components/text";
|
||||
import { withTranslation } from "react-i18next";
|
||||
import { withTranslation, Trans } from "react-i18next";
|
||||
import { inject, observer } from "mobx-react";
|
||||
import { ConflictResolveType } from "@appserver/common/constants";
|
||||
import toastr from "studio/toastr";
|
||||
@ -12,12 +12,21 @@ import styled from "styled-components";
|
||||
|
||||
const StyledModalDialog = styled(ModalDialog)`
|
||||
.conflict-resolve-dialog-text {
|
||||
padding-bottom: 8px;
|
||||
padding-bottom: 12px;
|
||||
}
|
||||
.conflict-resolve-dialog-text-description {
|
||||
padding-bottom: 16px;
|
||||
}
|
||||
|
||||
.conflict-resolve-radio-button {
|
||||
label{
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
}
|
||||
svg {
|
||||
overflow: visible;
|
||||
margin-right: 8px;
|
||||
margin-top: 3px
|
||||
}
|
||||
}
|
||||
|
||||
@ -25,7 +34,20 @@ const StyledModalDialog = styled(ModalDialog)`
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1fr;
|
||||
grid-gap: 10px;
|
||||
width: 90%;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.button-dialog-accept {
|
||||
margin-right: 8px;
|
||||
}
|
||||
.modal-dialog-aside-footer, .modal-dialog-modal-footer {
|
||||
border-top: ${(props) => props.theme.button.border.baseDisabled};
|
||||
margin-left: -16px;
|
||||
margin-right: -16px;
|
||||
padding-left: 16px;
|
||||
padding-right: 16px;
|
||||
padding-top: 16px;
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
@ -43,6 +65,7 @@ const ConflictResolveDialog = (props) => {
|
||||
setMoveToPanelVisible,
|
||||
setCopyPanelVisible,
|
||||
setThirdPartyMoveDialogVisible,
|
||||
theme,
|
||||
} = props;
|
||||
|
||||
const {
|
||||
@ -127,8 +150,12 @@ const ConflictResolveDialog = (props) => {
|
||||
{
|
||||
label: (
|
||||
<div>
|
||||
<Text>{t("OverwriteTitle")}</Text>
|
||||
<Text>{t("OverwriteDescription")}</Text>
|
||||
<Text fontWeight={600} fontSize={"14px"}>
|
||||
{t("OverwriteTitle")}
|
||||
</Text>
|
||||
<Text color={theme.text.disableColor} fontSize={"12px"}>
|
||||
{t("OverwriteDescription")}
|
||||
</Text>
|
||||
</div>
|
||||
),
|
||||
value: "overwrite",
|
||||
@ -136,8 +163,12 @@ const ConflictResolveDialog = (props) => {
|
||||
{
|
||||
label: (
|
||||
<div>
|
||||
<Text>{t("CreateTitle")}</Text>
|
||||
<Text>{t("CreateDescription")}</Text>
|
||||
<Text fontWeight={600} fontSize={"14px"}>
|
||||
{t("CreateTitle")}
|
||||
</Text>
|
||||
<Text color={theme.text.disableColor} fontSize={"12px"}>
|
||||
{t("CreateDescription")}
|
||||
</Text>
|
||||
</div>
|
||||
),
|
||||
|
||||
@ -146,8 +177,12 @@ const ConflictResolveDialog = (props) => {
|
||||
{
|
||||
label: (
|
||||
<div>
|
||||
<Text>{t("SkipTitle")}</Text>
|
||||
<Text>{t("SkipDescription")}</Text>
|
||||
<Text fontWeight={600} fontSize={"14px"}>
|
||||
{t("SkipTitle")}
|
||||
</Text>
|
||||
<Text color={theme.text.disableColor} fontSize={"12px"}>
|
||||
{t("SkipDescription")}
|
||||
</Text>
|
||||
</div>
|
||||
),
|
||||
value: "skip",
|
||||
@ -163,17 +198,36 @@ const ConflictResolveDialog = (props) => {
|
||||
isLoading={!tReady}
|
||||
visible={visible}
|
||||
onClose={onCloseDialog}
|
||||
displayType="aside"
|
||||
theme={theme}
|
||||
style={{ maxWidth: "520px" }}
|
||||
>
|
||||
<ModalDialog.Header>{t("ConflictResolveTitle")}</ModalDialog.Header>
|
||||
<ModalDialog.Body>
|
||||
<Text className="conflict-resolve-dialog-text">
|
||||
{singleFile
|
||||
? t("ConflictResolveDescription", { file, folder: folderTitle })
|
||||
: t("ConflictResolveDescriptionFiles", {
|
||||
filesCount,
|
||||
folder: folderTitle,
|
||||
})}
|
||||
<Text className="conflict-resolve-dialog-text-description">
|
||||
{singleFile ? (
|
||||
<Trans
|
||||
t={t}
|
||||
file={filesCount}
|
||||
folder={folderTitle}
|
||||
i18nKey="ConflictResolveDescription"
|
||||
ns="ConflictResolveDialog"
|
||||
>
|
||||
The file with the name <strong>{{ file }}</strong> already exists
|
||||
in the folder
|
||||
<strong>{{ folder: folderTitle }}</strong>.
|
||||
</Trans>
|
||||
) : (
|
||||
<Trans
|
||||
t={t}
|
||||
filesCount={filesCount}
|
||||
folder={folderTitle}
|
||||
i18nKey="ConflictResolveDescriptionFiles"
|
||||
ns="ConflictResolveDialog"
|
||||
>
|
||||
{{ filesCount }} documents with the same name already exist in the
|
||||
folder <strong>{{ folder: folderTitle }}</strong>.
|
||||
</Trans>
|
||||
)}
|
||||
</Text>
|
||||
<Text className="conflict-resolve-dialog-text">
|
||||
{t("ConflictResolveSelectAction")}
|
||||
@ -194,9 +248,8 @@ const ConflictResolveDialog = (props) => {
|
||||
className="button-dialog-accept"
|
||||
key="OkButton"
|
||||
label={t("Common:OKButton")}
|
||||
size="small"
|
||||
size="normalTouchscreen"
|
||||
primary
|
||||
scale
|
||||
onClick={onAcceptType}
|
||||
//isLoading={isLoading}
|
||||
/>
|
||||
@ -204,8 +257,7 @@ const ConflictResolveDialog = (props) => {
|
||||
className="button-dialog"
|
||||
key="CancelButton"
|
||||
label={t("Common:CancelButton")}
|
||||
size="small"
|
||||
scale
|
||||
size="normalTouchscreen"
|
||||
onClick={onCloseDialog}
|
||||
//isLoading={isLoading}
|
||||
/>
|
||||
@ -214,7 +266,7 @@ const ConflictResolveDialog = (props) => {
|
||||
);
|
||||
};
|
||||
|
||||
export default inject(({ dialogsStore, uploadDataStore, filesStore }) => {
|
||||
export default inject(({ auth, dialogsStore, uploadDataStore, filesStore }) => {
|
||||
const {
|
||||
conflictResolveDialogVisible: visible,
|
||||
setConflictResolveDialogVisible,
|
||||
@ -227,8 +279,10 @@ export default inject(({ dialogsStore, uploadDataStore, filesStore }) => {
|
||||
|
||||
const { itemOperationToFolder } = uploadDataStore;
|
||||
const { activeFiles, setActiveFiles } = filesStore;
|
||||
|
||||
const { settingsStore } = auth;
|
||||
const { theme } = settingsStore;
|
||||
return {
|
||||
theme,
|
||||
items,
|
||||
visible,
|
||||
conflictResolveDialogData,
|
||||
|
@ -1,19 +1,11 @@
|
||||
import React, { useState } from "react";
|
||||
import React, { useState, useEffect } from "react";
|
||||
import { withRouter } from "react-router";
|
||||
import ModalDialog from "@appserver/components/modal-dialog";
|
||||
import { withTranslation } from "react-i18next";
|
||||
import TreeFolders from "../../FolderTreeBody/TreeFolders";
|
||||
import { inject, observer } from "mobx-react";
|
||||
import toastr from "studio/toastr";
|
||||
import Button from "@appserver/components/button";
|
||||
import styled from "styled-components";
|
||||
|
||||
const StyledModalDialog = styled(ModalDialog)`
|
||||
.modal-dialog-aside-footer {
|
||||
width: 90%;
|
||||
}
|
||||
`;
|
||||
import SelectFolderDialog from "../SelectFolderDialog";
|
||||
|
||||
let operationData, fileWithConflicts, timerId;
|
||||
const OperationsPanelComponent = (props) => {
|
||||
const {
|
||||
t,
|
||||
@ -37,18 +29,34 @@ const OperationsPanelComponent = (props) => {
|
||||
checkFileConflicts,
|
||||
setThirdPartyMoveDialogVisible,
|
||||
parentFolderId,
|
||||
conflictResolveDialogVisible,
|
||||
clearActiveOperations,
|
||||
} = props;
|
||||
|
||||
const zIndex = 310;
|
||||
const deleteAfter = false; // TODO: get from settings
|
||||
|
||||
const expandedKeys = props.expandedKeys.map((item) => item.toString());
|
||||
|
||||
const [isLoading, setIsLoading] = useState(false);
|
||||
const [selectedFolder, setSelectedFolder] = useState(null);
|
||||
const [folderTitle, setFolderTitle] = useState(null);
|
||||
const [providerKey, setProviderKey] = useState(null);
|
||||
const [intermediateHidden, setIntermediateHidden] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
if (conflictResolveDialogVisible === false) {
|
||||
intermediateHidden && setIntermediateHidden(false);
|
||||
} else {
|
||||
isLoading && setIsLoading(false);
|
||||
}
|
||||
}, [conflictResolveDialogVisible]);
|
||||
|
||||
useEffect(() => {
|
||||
intermediateHidden &&
|
||||
setConflictDialogData(fileWithConflicts, operationData);
|
||||
}, [intermediateHidden]);
|
||||
|
||||
useEffect(() => {
|
||||
return () => {
|
||||
clearTimeout(timerId);
|
||||
timerId = null;
|
||||
};
|
||||
});
|
||||
const onClose = () => {
|
||||
if (isCopy) {
|
||||
setCopyPanelVisible(false);
|
||||
@ -59,7 +67,7 @@ const OperationsPanelComponent = (props) => {
|
||||
setExpandedPanelKeys(null);
|
||||
};
|
||||
|
||||
const onSubmit = () => {
|
||||
const onSubmit = (selectedFolder, folderTitle, providerKey) => {
|
||||
if (currentFolderId === selectedFolder) {
|
||||
return;
|
||||
}
|
||||
@ -76,12 +84,6 @@ const OperationsPanelComponent = (props) => {
|
||||
}
|
||||
};
|
||||
|
||||
const onSelect = (folder, treeNode) => {
|
||||
setProviderKey(treeNode.node.props.providerKey);
|
||||
setFolderTitle(treeNode.node.props.title);
|
||||
setSelectedFolder(isNaN(+folder[0]) ? folder[0] : +folder[0]);
|
||||
};
|
||||
|
||||
const startOperation = async (isCopy, destFolderId, folderTitle) => {
|
||||
const isProviderFolder = selection.find((x) => !x.providerKey);
|
||||
const items =
|
||||
@ -111,7 +113,7 @@ const OperationsPanelComponent = (props) => {
|
||||
|
||||
if (!folderIds.length && !fileIds.length) return;
|
||||
|
||||
const operationData = {
|
||||
operationData = {
|
||||
destFolderId,
|
||||
folderIds,
|
||||
fileIds,
|
||||
@ -124,69 +126,60 @@ const OperationsPanelComponent = (props) => {
|
||||
},
|
||||
};
|
||||
|
||||
setIsLoading(true);
|
||||
checkFileConflicts(destFolderId, folderIds, fileIds).then(
|
||||
async (conflicts) => {
|
||||
if (!timerId)
|
||||
timerId = setTimeout(() => {
|
||||
setIsLoading(true);
|
||||
}, 500);
|
||||
|
||||
checkFileConflicts(destFolderId, folderIds, fileIds)
|
||||
.then(async (conflicts) => {
|
||||
if (conflicts.length) {
|
||||
setConflictDialogData(conflicts, operationData);
|
||||
fileWithConflicts = conflicts;
|
||||
setIntermediateHidden(true);
|
||||
setIsLoading(false);
|
||||
} else {
|
||||
setIsLoading(false);
|
||||
onClose();
|
||||
await itemOperationToFolder(operationData);
|
||||
}
|
||||
}
|
||||
);
|
||||
})
|
||||
.catch((e) => {
|
||||
toastr.error(e);
|
||||
setIsLoading(false);
|
||||
clearActiveOperations(fileIds, folderIds);
|
||||
})
|
||||
.finally(() => {
|
||||
clearTimeout(timerId);
|
||||
timerId = null;
|
||||
});
|
||||
};
|
||||
|
||||
//console.log("Operations panel render");
|
||||
// console.log("Operations panel render", expandedKeys);
|
||||
const isVisible = intermediateHidden ? false : visible;
|
||||
return (
|
||||
<StyledModalDialog
|
||||
visible={visible}
|
||||
displayType="aside"
|
||||
zIndex={zIndex}
|
||||
<SelectFolderDialog
|
||||
isDisableTree={isLoading}
|
||||
foldersType="exceptSortedByTags"
|
||||
isPanelVisible={isVisible}
|
||||
onSubmit={onSubmit}
|
||||
onClose={onClose}
|
||||
isLoading={!tReady}
|
||||
className="operations-panel-dialog"
|
||||
>
|
||||
<ModalDialog.Header>
|
||||
{isRecycleBin
|
||||
? t("Translations:Restore")
|
||||
id={isRecycleBin ? null : currentFolderId}
|
||||
withoutImmediatelyClose
|
||||
dialogName={
|
||||
isRecycleBin
|
||||
? t("Common:Restore")
|
||||
: isCopy
|
||||
? t("Translations:Copy")
|
||||
: t("Translations:Move")}
|
||||
</ModalDialog.Header>
|
||||
<ModalDialog.Body>
|
||||
<TreeFolders
|
||||
isPanel={true}
|
||||
expandedPanelKeys={expandedKeys}
|
||||
data={operationsFolders}
|
||||
filter={filter}
|
||||
onSelect={onSelect}
|
||||
needUpdate={false}
|
||||
disabled={isLoading || isLoading}
|
||||
selectedKeys={[selectedFolder + ""]}
|
||||
/>
|
||||
</ModalDialog.Body>
|
||||
<ModalDialog.Footer>
|
||||
<Button
|
||||
scale
|
||||
key="OkButton"
|
||||
label={
|
||||
isRecycleBin
|
||||
? t("Translations:Restore")
|
||||
: isCopy
|
||||
? t("Translations:Copy")
|
||||
: t("Translations:Move")
|
||||
}
|
||||
size="small"
|
||||
primary
|
||||
onClick={onSubmit}
|
||||
isLoading={isLoading}
|
||||
isDisabled={!selectedFolder || isLoading}
|
||||
/>
|
||||
</ModalDialog.Footer>
|
||||
</StyledModalDialog>
|
||||
: t("Home:MoveTo")
|
||||
}
|
||||
buttonName={
|
||||
isRecycleBin
|
||||
? t("Common:RestoreHere")
|
||||
: isCopy
|
||||
? t("Translations:CopyHere")
|
||||
: t("Translations:MoveHere")
|
||||
}
|
||||
></SelectFolderDialog>
|
||||
);
|
||||
};
|
||||
|
||||
@ -194,6 +187,7 @@ const OperationsPanel = withTranslation([
|
||||
"OperationsPanel",
|
||||
"Translations",
|
||||
"Common",
|
||||
"Home",
|
||||
])(OperationsPanelComponent);
|
||||
|
||||
export default inject(
|
||||
@ -213,10 +207,9 @@ export default inject(
|
||||
isRecycleBinFolder,
|
||||
operationsFolders,
|
||||
setExpandedPanelKeys,
|
||||
expandedPanelKeys,
|
||||
} = treeFoldersStore;
|
||||
const { setConflictDialogData, checkFileConflicts } = filesActionsStore;
|
||||
const { itemOperationToFolder } = uploadDataStore;
|
||||
const { itemOperationToFolder, clearActiveOperations } = uploadDataStore;
|
||||
|
||||
const {
|
||||
moveToPanelVisible,
|
||||
@ -227,6 +220,7 @@ export default inject(
|
||||
setDestFolderId,
|
||||
setThirdPartyMoveDialogVisible,
|
||||
setIsFolderActions,
|
||||
conflictResolveDialogVisible,
|
||||
} = dialogsStore;
|
||||
|
||||
const selections = selection.length ? selection : [bufferSelection];
|
||||
@ -237,9 +231,6 @@ export default inject(
|
||||
const provider = selections.find((x) => x.providerKey);
|
||||
|
||||
return {
|
||||
expandedKeys: expandedPanelKeys
|
||||
? expandedPanelKeys
|
||||
: selectedFolderStore.pathParts,
|
||||
currentFolderId: selectedFolderStore.id,
|
||||
parentFolderId: selectedFolderStore.parentId,
|
||||
isRecycleBin: isRecycleBinFolder,
|
||||
@ -259,6 +250,8 @@ export default inject(
|
||||
setExpandedPanelKeys,
|
||||
itemOperationToFolder,
|
||||
checkFileConflicts,
|
||||
conflictResolveDialogVisible,
|
||||
clearActiveOperations,
|
||||
};
|
||||
}
|
||||
)(withRouter(observer(OperationsPanel)));
|
||||
|
@ -1,170 +1,124 @@
|
||||
import React, { useState } from "react";
|
||||
import { StyledAsidePanel, StyledSelectFilePanel } from "../StyledPanels";
|
||||
import React from "react";
|
||||
import { StyledAsideBody } from "../SelectionPanel/StyledSelectionPanel";
|
||||
import Text from "@appserver/components/text";
|
||||
import SelectFolderInput from "../SelectFolderInput";
|
||||
import FilesListBody from "./FilesListBody";
|
||||
import Button from "@appserver/components/button";
|
||||
import Loaders from "@appserver/common/components/Loaders";
|
||||
import EmptyContainer from "../../EmptyContainer/EmptyContainer";
|
||||
import ModalDialog from "@appserver/components/modal-dialog";
|
||||
const DISPLAY_TYPE = "aside";
|
||||
import FilesListWrapper from "../SelectionPanel/FilesListWrapper";
|
||||
|
||||
const SelectFileDialogAsideView = ({
|
||||
t,
|
||||
theme,
|
||||
isPanelVisible,
|
||||
zIndex,
|
||||
onClose,
|
||||
isVisible,
|
||||
withoutProvider,
|
||||
foldersType,
|
||||
onSelectFile,
|
||||
onClickInput,
|
||||
onCloseSelectFolderDialog,
|
||||
onSelectFolder,
|
||||
filesList,
|
||||
files,
|
||||
hasNextPage,
|
||||
isNextPageLoading,
|
||||
loadNextPage,
|
||||
selectedFolder,
|
||||
titleFilesList,
|
||||
loadingText,
|
||||
selectedFile,
|
||||
onClickSave,
|
||||
onSetFileName,
|
||||
fileName,
|
||||
displayType,
|
||||
isTranslationsReady,
|
||||
passedId,
|
||||
headerName,
|
||||
isAvailableFolderList,
|
||||
filesListTitle,
|
||||
dialogName,
|
||||
primaryButtonName,
|
||||
theme,
|
||||
onButtonClick,
|
||||
folderId,
|
||||
onSelectFolder,
|
||||
resultingFolderTree,
|
||||
footer,
|
||||
fileId,
|
||||
foldersType,
|
||||
onCloseSelectFolderDialog,
|
||||
onClickInput,
|
||||
isFolderPanelVisible,
|
||||
maxInputWidth,
|
||||
newFilter,
|
||||
}) => {
|
||||
const [isLoadingData, setIsLoadingData] = useState(false);
|
||||
const onSetLoadingData = (loading) => {
|
||||
setIsLoadingData(loading);
|
||||
};
|
||||
const isHeaderChildren = !!titleFilesList;
|
||||
|
||||
const onMouseEvent = (event) => {
|
||||
event.stopPropagation();
|
||||
};
|
||||
|
||||
return (
|
||||
<StyledAsidePanel
|
||||
visible={isPanelVisible}
|
||||
onMouseUp={onMouseEvent}
|
||||
onMouseDown={onMouseEvent}
|
||||
>
|
||||
<div onMouseUp={onMouseEvent} onMouseDown={onMouseEvent}>
|
||||
<ModalDialog
|
||||
visible={isPanelVisible}
|
||||
zIndex={zIndex}
|
||||
onClose={onClose}
|
||||
contentHeight="100%"
|
||||
displayType={DISPLAY_TYPE}
|
||||
contentPaddingBottom="0px"
|
||||
displayType="aside"
|
||||
withoutBodyScroll
|
||||
>
|
||||
<ModalDialog.Header>
|
||||
{headerName ? headerName : t("SelectFile")}
|
||||
</ModalDialog.Header>
|
||||
<ModalDialog.Header>{dialogName}</ModalDialog.Header>
|
||||
<ModalDialog.Body className="select-file_body-modal-dialog">
|
||||
<StyledSelectFilePanel
|
||||
theme={theme}
|
||||
isHeaderChildren={isHeaderChildren}
|
||||
displayType={DISPLAY_TYPE}
|
||||
>
|
||||
<div className="select-file-dialog_aside-body_wrapper">
|
||||
<div className="select-file-dialog_aside-children"></div>
|
||||
<div className="select-file-dialog_aside_body">
|
||||
<StyledAsideBody theme={theme}>
|
||||
<div className="selection-panel_aside-body">
|
||||
<div className="selection-panel_folder-info">
|
||||
<Text
|
||||
className="selection-panel_folder-selection-title"
|
||||
fontWeight={600}
|
||||
>
|
||||
{t("Translations:FolderSelection")}
|
||||
</Text>
|
||||
|
||||
<SelectFolderInput
|
||||
theme={theme}
|
||||
onClickInput={onClickInput}
|
||||
onClose={onCloseSelectFolderDialog}
|
||||
onSelectFolder={onSelectFolder}
|
||||
onSetLoadingData={onSetLoadingData}
|
||||
isPanelVisible={isVisible}
|
||||
isPanelVisible={isFolderPanelVisible}
|
||||
foldersType={foldersType}
|
||||
isNeedArrowIcon
|
||||
withoutProvider={withoutProvider}
|
||||
isSetFolderImmediately
|
||||
selectedFolderId={selectedFolder}
|
||||
id={passedId}
|
||||
onSetFileName={onSetFileName}
|
||||
fileName={fileName}
|
||||
displayType={displayType}
|
||||
dialogWithFiles
|
||||
showButtons
|
||||
selectionButtonPrimary
|
||||
id={folderId}
|
||||
onSelectFile={onSelectFile}
|
||||
displayType="aside"
|
||||
hasNextPage={hasNextPage}
|
||||
isNextPageLoading={isNextPageLoading}
|
||||
loadNextPage={loadNextPage}
|
||||
files={files}
|
||||
folderTree={resultingFolderTree}
|
||||
isFolderTreeLoading={!!!resultingFolderTree}
|
||||
isNeedArrowIcon
|
||||
maxInputWidth={maxInputWidth}
|
||||
/>
|
||||
{titleFilesList && (
|
||||
<Text className="modal-dialog-filter-title">
|
||||
{titleFilesList}
|
||||
</Text>
|
||||
)}
|
||||
<div className="select-file-dialog_aside_body-files_list">
|
||||
{selectedFolder && !isLoadingData ? (
|
||||
<FilesListBody
|
||||
theme={theme}
|
||||
filesList={filesList}
|
||||
onSelectFile={onSelectFile}
|
||||
hasNextPage={hasNextPage}
|
||||
isNextPageLoading={isNextPageLoading}
|
||||
loadNextPage={loadNextPage}
|
||||
selectedFolder={selectedFolder}
|
||||
displayType={DISPLAY_TYPE}
|
||||
loadingText={loadingText}
|
||||
selectedFile={selectedFile}
|
||||
/>
|
||||
) : isAvailableFolderList ? (
|
||||
<div key="loader" className="panel-loader-wrapper">
|
||||
<Loaders.Rows
|
||||
theme={theme}
|
||||
style={{
|
||||
marginBottom: "24px",
|
||||
marginTop: "20px",
|
||||
}}
|
||||
count={12}
|
||||
/>
|
||||
</div>
|
||||
) : (
|
||||
<div className="select-file-dialog_empty-container">
|
||||
<EmptyContainer
|
||||
theme={theme}
|
||||
headerText={t("Home:EmptyFolderHeader")}
|
||||
imageSrc="/static/images/empty_screen.png"
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
|
||||
<Text color="#A3A9AE" className="selection-panel_aside-title">
|
||||
{filesListTitle}
|
||||
</Text>
|
||||
</div>
|
||||
<div className="selection-panel_files">
|
||||
<FilesListWrapper
|
||||
theme={theme}
|
||||
onSelectFile={onSelectFile}
|
||||
folderId={folderId}
|
||||
displayType="aside"
|
||||
folderSelection={false}
|
||||
fileId={fileId}
|
||||
newFilter={newFilter}
|
||||
/>
|
||||
</div>
|
||||
<div className="selection-panel_aside-footer">
|
||||
{footer}
|
||||
<div className="selection-panel_aside-buttons">
|
||||
<Button
|
||||
theme={theme}
|
||||
primary
|
||||
size="normalTouchscreen"
|
||||
label={primaryButtonName}
|
||||
onClick={onButtonClick}
|
||||
isDisabled={!fileId}
|
||||
/>
|
||||
<Button
|
||||
theme={theme}
|
||||
size="normalTouchscreen"
|
||||
label={t("Common:CancelButton")}
|
||||
onClick={onClose}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</StyledSelectFilePanel>
|
||||
</StyledAsideBody>
|
||||
</ModalDialog.Body>
|
||||
<ModalDialog.Footer theme={theme}>
|
||||
<StyledSelectFilePanel
|
||||
theme={theme}
|
||||
isHeaderChildren={isHeaderChildren}
|
||||
>
|
||||
<div className="select-file-dialog-aside_buttons">
|
||||
<Button
|
||||
theme={theme}
|
||||
className="select-file-dialog-buttons-save"
|
||||
primary
|
||||
size="normal"
|
||||
label={primaryButtonName}
|
||||
onClick={onClickSave}
|
||||
isDisabled={selectedFile.length === 0}
|
||||
/>
|
||||
<Button
|
||||
size="normal"
|
||||
theme={theme}
|
||||
label={t("Common:CancelButton")}
|
||||
onClick={onClose}
|
||||
/>
|
||||
</div>
|
||||
</StyledSelectFilePanel>
|
||||
</ModalDialog.Footer>
|
||||
</ModalDialog>
|
||||
</StyledAsidePanel>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
export default SelectFileDialogAsideView;
|
||||
|
@ -1,85 +0,0 @@
|
||||
import React from "react";
|
||||
import { StyledFilesList } from "../StyledPanels";
|
||||
import { ReactSVG } from "react-svg";
|
||||
import { inject, observer } from "mobx-react";
|
||||
import Text from "@appserver/components/text";
|
||||
import Checkbox from "@appserver/components/checkbox";
|
||||
import RadioButton from "@appserver/components/radio-button";
|
||||
const FilesListRow = ({
|
||||
displayType,
|
||||
needRowSelection,
|
||||
index,
|
||||
onSelectFile,
|
||||
fileName,
|
||||
children,
|
||||
fileExst,
|
||||
iconSrc,
|
||||
isMultiSelect, // it will be needed
|
||||
isChecked,
|
||||
noCheckBox,
|
||||
theme,
|
||||
}) => {
|
||||
return (
|
||||
<StyledFilesList
|
||||
displayType={displayType}
|
||||
theme={theme}
|
||||
needRowSelection={needRowSelection}
|
||||
isChecked={isChecked}
|
||||
noCheckBox={noCheckBox}
|
||||
>
|
||||
<div
|
||||
data-index={index}
|
||||
className="modal-dialog_file-name"
|
||||
onClick={onSelectFile}
|
||||
>
|
||||
{isMultiSelect ? ( // it will be needed
|
||||
<Checkbox
|
||||
theme={theme}
|
||||
label=""
|
||||
isChecked={isChecked}
|
||||
className="select-file-dialog_checked"
|
||||
/>
|
||||
) : (
|
||||
<RadioButton
|
||||
theme={theme}
|
||||
fontSize="13px"
|
||||
fontWeight="400"
|
||||
name={`${index}`}
|
||||
label=""
|
||||
isChecked={isChecked}
|
||||
onClick={onSelectFile}
|
||||
value=""
|
||||
className="select-file-dialog_checked"
|
||||
/>
|
||||
)}
|
||||
|
||||
<ReactSVG src={iconSrc} className="select-file-dialog_icon" />
|
||||
<div data-index={index} className="files-list_full-name">
|
||||
<Text theme={theme} data-index={index} className="entry-title">
|
||||
{fileName}
|
||||
<Text
|
||||
theme={theme}
|
||||
data-index={index}
|
||||
className="file-exst"
|
||||
as="span"
|
||||
>
|
||||
{fileExst}
|
||||
</Text>
|
||||
</Text>
|
||||
</div>
|
||||
<div className="files-list_file-children_wrapper">{children}</div>
|
||||
</div>
|
||||
</StyledFilesList>
|
||||
);
|
||||
};
|
||||
|
||||
FilesListRow.defaultProps = {
|
||||
isMultiSelect: false,
|
||||
};
|
||||
|
||||
export default inject(({ settingsStore }, { fileExst }) => {
|
||||
const iconSrc = settingsStore.getIconSrc(fileExst, 24);
|
||||
return {
|
||||
iconSrc,
|
||||
};
|
||||
})(observer(FilesListRow));
|
@ -1,286 +0,0 @@
|
||||
import React from "react";
|
||||
import { StyledAsidePanel, StyledSelectFilePanel } from "../StyledPanels";
|
||||
import ModalDialog from "@appserver/components/modal-dialog";
|
||||
import SelectFolderDialog from "../SelectFolderDialog";
|
||||
import FolderTreeBody from "../../FolderTreeBody";
|
||||
import FilesListBody from "./FilesListBody";
|
||||
import Button from "@appserver/components/button";
|
||||
import Text from "@appserver/components/text";
|
||||
import { isArrayEqual } from "@appserver/components/utils/array";
|
||||
import { getFoldersTree } from "@appserver/common/api/files";
|
||||
import {
|
||||
exceptSortedByTagsFolders,
|
||||
exceptPrivacyTrashFolders,
|
||||
} from "../SelectFolderDialog/ExceptionFoldersConstants";
|
||||
|
||||
class SelectFileDialogModalView extends React.Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.state = {
|
||||
isLoading: true,
|
||||
isAvailable: true,
|
||||
};
|
||||
this.folderList = "";
|
||||
this.noTreeSwitcher = false;
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
const { onSetLoadingData } = this.props;
|
||||
this.setState({ isLoadingData: true }, function () {
|
||||
onSetLoadingData && onSetLoadingData(true);
|
||||
|
||||
this.trySwitch();
|
||||
});
|
||||
}
|
||||
trySwitch = async () => {
|
||||
const {
|
||||
foldersType,
|
||||
onSelectFolder,
|
||||
selectedFolder,
|
||||
passedId,
|
||||
foldersList,
|
||||
} = this.props;
|
||||
switch (foldersType) {
|
||||
case "exceptSortedByTags":
|
||||
try {
|
||||
const foldersTree = await getFoldersTree();
|
||||
[
|
||||
this.folderList,
|
||||
this.noTreeSwitcher,
|
||||
] = SelectFolderDialog.convertFolders(
|
||||
foldersTree,
|
||||
exceptSortedByTagsFolders
|
||||
);
|
||||
this.onSetSelectedFolder();
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
}
|
||||
|
||||
this.loadersCompletes();
|
||||
break;
|
||||
case "exceptPrivacyTrashFolders":
|
||||
try {
|
||||
const foldersTree = await getFoldersTree();
|
||||
[
|
||||
this.folderList,
|
||||
this.noTreeSwitcher,
|
||||
] = SelectFolderDialog.convertFolders(
|
||||
foldersTree,
|
||||
exceptPrivacyTrashFolders
|
||||
);
|
||||
this.onSetSelectedFolder();
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
}
|
||||
this.loadersCompletes();
|
||||
break;
|
||||
case "common":
|
||||
try {
|
||||
this.folderList = await SelectFolderDialog.getCommonFolders();
|
||||
|
||||
!selectedFolder &&
|
||||
onSelectFolder &&
|
||||
onSelectFolder(
|
||||
`${
|
||||
selectedFolder
|
||||
? selectedFolder
|
||||
: passedId
|
||||
? passedId
|
||||
: this.folderList[0].id
|
||||
}`
|
||||
);
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
}
|
||||
|
||||
this.loadersCompletes();
|
||||
break;
|
||||
case "third-party":
|
||||
try {
|
||||
this.folderList = foldersList
|
||||
? foldersList
|
||||
: await SelectFolderDialog.getCommonThirdPartyList();
|
||||
this.folderList.length !== 0
|
||||
? this.onSetSelectedFolder()
|
||||
: this.setState({ isAvailable: false });
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
}
|
||||
|
||||
this.loadersCompletes();
|
||||
break;
|
||||
}
|
||||
};
|
||||
|
||||
loadersCompletes = () => {
|
||||
const { onSetLoadingData } = this.props;
|
||||
onSetLoadingData && onSetLoadingData(false);
|
||||
|
||||
this.setState({
|
||||
isLoading: false,
|
||||
});
|
||||
};
|
||||
|
||||
onSetSelectedFolder = () => {
|
||||
const { onSelectFolder, selectedFolder, passedId } = this.props;
|
||||
|
||||
onSelectFolder &&
|
||||
onSelectFolder(
|
||||
`${
|
||||
selectedFolder
|
||||
? selectedFolder
|
||||
: passedId
|
||||
? passedId
|
||||
: this.folderList[0].id
|
||||
}`
|
||||
);
|
||||
};
|
||||
onSelect = (folder) => {
|
||||
const { onSelectFolder, selectedFolder } = this.props;
|
||||
|
||||
if (isArrayEqual([folder[0]], [selectedFolder])) {
|
||||
return;
|
||||
}
|
||||
|
||||
onSelectFolder && onSelectFolder(folder[0]);
|
||||
};
|
||||
|
||||
onMouseEvent = (event) => {
|
||||
event.stopPropagation();
|
||||
};
|
||||
render() {
|
||||
const {
|
||||
t,
|
||||
isPanelVisible,
|
||||
onClose,
|
||||
zIndex,
|
||||
withoutProvider,
|
||||
expandedKeys,
|
||||
filter,
|
||||
onSelectFile,
|
||||
filesList,
|
||||
hasNextPage,
|
||||
isNextPageLoading,
|
||||
loadNextPage,
|
||||
selectedFolder,
|
||||
titleFilesList,
|
||||
loadingText,
|
||||
selectedFile,
|
||||
onClickSave,
|
||||
headerName,
|
||||
primaryButtonName,
|
||||
theme,
|
||||
} = this.props;
|
||||
|
||||
const { isLoading, isAvailable } = this.state;
|
||||
|
||||
const isHeaderChildren = !!titleFilesList;
|
||||
|
||||
return (
|
||||
<StyledAsidePanel
|
||||
theme={theme}
|
||||
visible={isPanelVisible}
|
||||
onMouseUp={this.onMouseEvent}
|
||||
onMouseDown={this.onMouseEvent}
|
||||
>
|
||||
<ModalDialog
|
||||
theme={theme}
|
||||
visible={isPanelVisible}
|
||||
zIndex={zIndex}
|
||||
onClose={onClose}
|
||||
className="select-file-modal-dialog"
|
||||
style={{ maxWidth: "725px" }}
|
||||
displayType="modal"
|
||||
modalBodyPadding="0px"
|
||||
isLoading={isLoading}
|
||||
modalLoaderBodyHeight="277px"
|
||||
>
|
||||
<ModalDialog.Header theme={theme}>
|
||||
{headerName ? headerName : t("SelectFile")}
|
||||
</ModalDialog.Header>
|
||||
<ModalDialog.Body
|
||||
theme={theme}
|
||||
className="select-file_body-modal-dialog"
|
||||
>
|
||||
<StyledSelectFilePanel
|
||||
isHeaderChildren={isHeaderChildren}
|
||||
theme={theme}
|
||||
displayType="modal"
|
||||
noTreeSwitcher={this.noTreeSwitcher}
|
||||
>
|
||||
<div className="modal-dialog_body">
|
||||
<div className="modal-dialog_tree-body">
|
||||
<FolderTreeBody
|
||||
theme={theme}
|
||||
expandedKeys={expandedKeys}
|
||||
folderList={this.folderList}
|
||||
onSelect={this.onSelect}
|
||||
withoutProvider={withoutProvider}
|
||||
certainFolders
|
||||
isAvailable={isAvailable}
|
||||
filter={filter}
|
||||
selectedKeys={[selectedFolder]}
|
||||
isHeaderChildren={isHeaderChildren}
|
||||
displayType="modal"
|
||||
/>
|
||||
</div>
|
||||
<div className="modal-dialog_files-body">
|
||||
<>
|
||||
{titleFilesList && (
|
||||
<Text theme={theme} className="modal-dialog-filter-title">
|
||||
{titleFilesList}
|
||||
</Text>
|
||||
)}
|
||||
{selectedFolder && (
|
||||
<FilesListBody
|
||||
theme={theme}
|
||||
filesList={filesList}
|
||||
onSelectFile={onSelectFile}
|
||||
hasNextPage={hasNextPage}
|
||||
isNextPageLoading={isNextPageLoading}
|
||||
loadNextPage={loadNextPage}
|
||||
selectedFolder={selectedFolder}
|
||||
loadingText={loadingText}
|
||||
selectedFile={selectedFile}
|
||||
listHeight={isHeaderChildren ? 260 : 303}
|
||||
onSetLoadingData={this.onSetLoadingData}
|
||||
displayType={"modal"}
|
||||
/>
|
||||
)}
|
||||
</>
|
||||
</div>
|
||||
</div>
|
||||
</StyledSelectFilePanel>
|
||||
</ModalDialog.Body>
|
||||
<ModalDialog.Footer theme={theme}>
|
||||
<StyledSelectFilePanel
|
||||
theme={theme}
|
||||
isHeaderChildren={isHeaderChildren}
|
||||
>
|
||||
<div className="select-file-dialog-modal_buttons">
|
||||
<Button
|
||||
theme={theme}
|
||||
className="select-file-modal-dialog-buttons-save"
|
||||
primary
|
||||
size="small"
|
||||
label={primaryButtonName}
|
||||
onClick={onClickSave}
|
||||
isDisabled={selectedFile.length === 0}
|
||||
/>
|
||||
<Button
|
||||
theme={theme}
|
||||
className="modal-dialog-button"
|
||||
size="small"
|
||||
label={t("Common:CancelButton")}
|
||||
onClick={onClose}
|
||||
/>
|
||||
</div>
|
||||
</StyledSelectFilePanel>
|
||||
</ModalDialog.Footer>
|
||||
</ModalDialog>
|
||||
</StyledAsidePanel>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default SelectFileDialogModalView;
|
@ -0,0 +1,44 @@
|
||||
import React from "react";
|
||||
import { Provider as MobxProvider, inject, observer } from "mobx-react";
|
||||
import { I18nextProvider } from "react-i18next";
|
||||
import SelectFileDialog from "./index";
|
||||
import stores from "../../../store/index";
|
||||
import store from "studio/store";
|
||||
import i18n from "./i18n";
|
||||
const { auth: authStore } = store;
|
||||
|
||||
class SelectFileDialogBody extends React.Component {
|
||||
componentDidMount() {
|
||||
const { settings, setFilesSettings } = this.props;
|
||||
settings && setFilesSettings(settings);
|
||||
}
|
||||
|
||||
render() {
|
||||
return <SelectFileDialog {...this.props} />;
|
||||
}
|
||||
}
|
||||
const SelectFileWrapper = inject(({ settingsStore }) => {
|
||||
const { setFilesSettings } = settingsStore;
|
||||
|
||||
return {
|
||||
setFilesSettings,
|
||||
};
|
||||
})(observer(SelectFileDialogBody));
|
||||
|
||||
class SelectFileDialogWrapper extends React.Component {
|
||||
componentDidMount() {
|
||||
authStore.init(true);
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<MobxProvider auth={authStore} {...stores}>
|
||||
<I18nextProvider i18n={i18n}>
|
||||
<SelectFileWrapper {...this.props} />
|
||||
</I18nextProvider>
|
||||
</MobxProvider>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default SelectFileDialogWrapper;
|
@ -1,59 +1,28 @@
|
||||
import React from "react";
|
||||
import { inject, observer, Provider as MobxProvider } from "mobx-react";
|
||||
import { I18nextProvider } from "react-i18next";
|
||||
import { inject, observer } from "mobx-react";
|
||||
import { withTranslation } from "react-i18next";
|
||||
import PropTypes from "prop-types";
|
||||
import throttle from "lodash/throttle";
|
||||
|
||||
import stores from "../../../store/index";
|
||||
import i18n from "./i18n";
|
||||
import SelectFileDialogModalView from "./ModalView";
|
||||
import SelectFileDialogAsideView from "./AsideView";
|
||||
|
||||
import utils from "@appserver/components/utils";
|
||||
//import SelectFolderDialog from "../SelectFolderDialog";
|
||||
import { getFolder } from "@appserver/common/api/files";
|
||||
import { FilterType } from "@appserver/common/constants";
|
||||
import SelectionPanel from "../SelectionPanel/SelectionPanelBody";
|
||||
import toastr from "studio/toastr";
|
||||
|
||||
const { desktop } = utils.device;
|
||||
|
||||
import store from "studio/store";
|
||||
|
||||
const { auth: authStore } = store;
|
||||
|
||||
class SelectFileDialogBody extends React.Component {
|
||||
class SelectFileDialog extends React.Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
const {
|
||||
folderId,
|
||||
storeFolderId,
|
||||
fileInfo,
|
||||
filter,
|
||||
creationButtonPrimary,
|
||||
t,
|
||||
} = props;
|
||||
|
||||
this.buttonName = creationButtonPrimary
|
||||
? t("Common:Create")
|
||||
: t("Common:SaveButton");
|
||||
const { filter } = props;
|
||||
|
||||
this.state = {
|
||||
isVisible: false,
|
||||
selectedFolder: storeFolderId || "",
|
||||
passedId: folderId,
|
||||
selectedFile: fileInfo || "",
|
||||
fileName: (fileInfo && fileInfo.title) || "",
|
||||
filesList: [],
|
||||
hasNextPage: true,
|
||||
isNextPageLoading: false,
|
||||
files: [],
|
||||
displayType: this.getDisplayType(),
|
||||
page: 0,
|
||||
filterParams: this.getFilterParameters(),
|
||||
isAvailableFolderList: true,
|
||||
};
|
||||
this.throttledResize = throttle(this.setDisplayType, 300);
|
||||
this.newFilter = filter.clone();
|
||||
this._isLoadNextPage = false;
|
||||
}
|
||||
|
||||
getFilterParameters = () => {
|
||||
@ -101,36 +70,79 @@ class SelectFileDialogBody extends React.Component {
|
||||
};
|
||||
|
||||
setFilter = () => {
|
||||
const { filterParams } = this.state;
|
||||
const { withSubfolders = true } = this.props;
|
||||
|
||||
const filterParams = this.getFilterParameters();
|
||||
this.newFilter.filterType = filterParams.filterType;
|
||||
this.newFilter.search = filterParams.filterValue;
|
||||
this.newFilter.withSubfolders = withSubfolders;
|
||||
};
|
||||
|
||||
componentDidMount() {
|
||||
authStore.init(true); // it will work if authStore is not initialized
|
||||
async componentDidMount() {
|
||||
const {
|
||||
treeFolders,
|
||||
foldersType,
|
||||
id,
|
||||
onSetBaseFolderPath,
|
||||
onSelectFolder,
|
||||
foldersList,
|
||||
treeFromInput,
|
||||
displayType,
|
||||
setFolderId,
|
||||
folderId,
|
||||
} = this.props;
|
||||
|
||||
!displayType && window.addEventListener("resize", this.throttledResize);
|
||||
|
||||
window.addEventListener("resize", this.throttledResize);
|
||||
this.setFilter();
|
||||
|
||||
let resultingFolderTree, resultingId;
|
||||
|
||||
try {
|
||||
[
|
||||
resultingFolderTree,
|
||||
resultingId,
|
||||
] = await SelectionPanel.getBasicFolderInfo(
|
||||
treeFolders,
|
||||
foldersType,
|
||||
folderId,
|
||||
onSetBaseFolderPath,
|
||||
onSelectFolder,
|
||||
foldersList,
|
||||
true
|
||||
);
|
||||
} catch (e) {
|
||||
toastr.error(e);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
const tree = treeFromInput ? treeFromInput : resultingFolderTree;
|
||||
|
||||
if (tree.length === 0) {
|
||||
this.setState({ isAvailable: false });
|
||||
onSelectFolder(null);
|
||||
return;
|
||||
}
|
||||
|
||||
setFolderId(resultingId);
|
||||
|
||||
this.setState({
|
||||
resultingFolderTree: tree,
|
||||
});
|
||||
}
|
||||
componentWillUnmount() {
|
||||
const {
|
||||
resetTreeFolders,
|
||||
setExpandedPanelKeys,
|
||||
setDefaultSelectedFolder,
|
||||
setSelectedFolder,
|
||||
setFolderId,
|
||||
setFile,
|
||||
setExpandedPanelKeys,
|
||||
withoutResetFolderTree,
|
||||
} = this.props;
|
||||
this.throttledResize && this.throttledResize.cancel();
|
||||
window.removeEventListener("resize", this.throttledResize);
|
||||
|
||||
if (resetTreeFolders) {
|
||||
if (!withoutResetFolderTree) {
|
||||
setExpandedPanelKeys(null);
|
||||
//setSelectedFolder(null);
|
||||
|
||||
setFolderId(null);
|
||||
setFile(null);
|
||||
}
|
||||
@ -161,192 +173,123 @@ class SelectFileDialogBody extends React.Component {
|
||||
});
|
||||
};
|
||||
|
||||
onSelectFolder = (id) => {
|
||||
const { setFolderId } = this.props;
|
||||
onSelectFolder = (folder) => {
|
||||
const { displayType } = this.state;
|
||||
const { setFolderId, setFile, folderId } = this.props;
|
||||
const id = displayType === "aside" ? folder : folder[0];
|
||||
|
||||
if (id) {
|
||||
if (id !== folderId) {
|
||||
setFolderId(id);
|
||||
|
||||
this.setState({
|
||||
selectedFolder: id,
|
||||
hasNextPage: true,
|
||||
filesList: [],
|
||||
page: 0,
|
||||
});
|
||||
} else
|
||||
this.setState({
|
||||
isAvailableFolderList: false,
|
||||
});
|
||||
setFile(null);
|
||||
}
|
||||
};
|
||||
|
||||
onSelectFile = (e) => {
|
||||
const { filesList } = this.state;
|
||||
onSelectFile = (item, index) => {
|
||||
const { setFile } = this.props;
|
||||
const index = e.target.dataset.index || e.target.name;
|
||||
|
||||
if (!index) return;
|
||||
setFile(filesList[+index]);
|
||||
this.setState({
|
||||
selectedFile: filesList[+index],
|
||||
fileName: filesList[+index].title,
|
||||
});
|
||||
setFile(item);
|
||||
};
|
||||
|
||||
onClickSave = () => {
|
||||
const { onSetFileName, onClose, onSelectFile } = this.props;
|
||||
const { fileName, selectedFile } = this.state;
|
||||
const {
|
||||
onSetFileNameAndLocation,
|
||||
onClose,
|
||||
onSelectFile,
|
||||
fileInfo,
|
||||
folderId,
|
||||
} = this.props;
|
||||
|
||||
onSetFileName && onSetFileName(fileName);
|
||||
onSelectFile && onSelectFile(selectedFile);
|
||||
const fileName = fileInfo.title;
|
||||
|
||||
onSetFileNameAndLocation && onSetFileNameAndLocation(fileName, folderId);
|
||||
onSelectFile && onSelectFile(fileInfo);
|
||||
onClose && onClose();
|
||||
};
|
||||
|
||||
loadNextPage = () => {
|
||||
// const {
|
||||
// setSelectedNode,
|
||||
// setSelectedFolder,
|
||||
// setExpandedPanelKeys,
|
||||
// } = this.props;
|
||||
const { selectedFolder, page } = this.state;
|
||||
|
||||
if (this._isLoadNextPage) return;
|
||||
|
||||
this._isLoadNextPage = true;
|
||||
|
||||
const pageCount = 30;
|
||||
this.newFilter.page = page;
|
||||
this.newFilter.pageCount = pageCount;
|
||||
|
||||
this.setState({ isNextPageLoading: true }, () => {
|
||||
getFolder(selectedFolder, this.newFilter)
|
||||
.then((data) => {
|
||||
let newFilesList = page
|
||||
? this.state.filesList.concat(data.files)
|
||||
: data.files;
|
||||
|
||||
//TODO: it will need if passed the folder id - need to come up with a different solution.
|
||||
|
||||
// const newPathParts = SelectFolderDialog.convertPathParts(
|
||||
//
|
||||
// data.pathParts
|
||||
// );
|
||||
|
||||
//setExpandedPanelKeys(newPathParts);
|
||||
|
||||
// setSelectedNode([selectedFolder + ""]);
|
||||
// setSelectedFolder({
|
||||
// folders: data.folders,
|
||||
// ...data.current,
|
||||
// pathParts: newPathParts,
|
||||
// ...{ new: data.new },
|
||||
// });
|
||||
this.setState({
|
||||
hasNextPage: newFilesList.length < data.total,
|
||||
isNextPageLoading: false,
|
||||
filesList: newFilesList,
|
||||
page: page + 1,
|
||||
});
|
||||
})
|
||||
.catch((error) => console.log(error))
|
||||
.finally(() => (this._isLoadNextPage = false));
|
||||
});
|
||||
};
|
||||
render() {
|
||||
const {
|
||||
t,
|
||||
isPanelVisible,
|
||||
onClose,
|
||||
zIndex,
|
||||
foldersType,
|
||||
withoutProvider,
|
||||
titleFilesList,
|
||||
loadingLabel,
|
||||
folderId,
|
||||
onSetFileName,
|
||||
tReady,
|
||||
headerName,
|
||||
foldersList,
|
||||
filesListTitle,
|
||||
theme,
|
||||
header,
|
||||
footer,
|
||||
dialogName,
|
||||
creationButtonPrimary,
|
||||
maxInputWidth,
|
||||
folderId,
|
||||
fileInfo,
|
||||
} = this.props;
|
||||
const {
|
||||
isVisible,
|
||||
filesList,
|
||||
hasNextPage,
|
||||
isNextPageLoading,
|
||||
selectedFolder,
|
||||
displayType,
|
||||
selectedFile,
|
||||
fileName,
|
||||
passedId,
|
||||
isAvailableFolderList,
|
||||
resultingFolderTree,
|
||||
isLoadingData,
|
||||
} = this.state;
|
||||
|
||||
const loadingText = loadingLabel
|
||||
? loadingLabel
|
||||
: `${t("Common:LoadingProcessing")} ${t("Common:LoadingDescription")}`;
|
||||
const buttonName = creationButtonPrimary
|
||||
? t("Common:Create")
|
||||
: t("Common:SaveButton");
|
||||
const name = dialogName ? dialogName : t("Common:SelectFile");
|
||||
|
||||
// console.log("Render file-component");
|
||||
return displayType === "aside" ? (
|
||||
<SelectFileDialogAsideView
|
||||
theme={theme}
|
||||
t={t}
|
||||
theme={theme}
|
||||
isPanelVisible={isPanelVisible}
|
||||
zIndex={zIndex}
|
||||
isFolderPanelVisible={isVisible}
|
||||
onClose={onClose}
|
||||
isVisible={isVisible}
|
||||
withoutProvider={withoutProvider}
|
||||
foldersType={foldersType}
|
||||
filesList={filesList}
|
||||
onSelectFile={this.onSelectFile}
|
||||
onClickInput={this.onClickInput}
|
||||
onClickSave={this.onClickSave}
|
||||
onCloseSelectFolderDialog={this.onCloseSelectFolderDialog}
|
||||
onSelectFolder={this.onSelectFolder}
|
||||
hasNextPage={hasNextPage}
|
||||
isNextPageLoading={isNextPageLoading}
|
||||
loadNextPage={this.loadNextPage}
|
||||
selectedFolder={selectedFolder}
|
||||
headerName={headerName}
|
||||
loadingText={loadingText}
|
||||
selectedFile={selectedFile}
|
||||
folderId={folderId}
|
||||
onSetFileName={onSetFileName}
|
||||
fileName={fileName}
|
||||
displayType={displayType}
|
||||
isTranslationsReady={tReady}
|
||||
passedId={passedId}
|
||||
titleFilesList={titleFilesList}
|
||||
isAvailableFolderList={isAvailableFolderList}
|
||||
primaryButtonName={this.buttonName}
|
||||
resultingFolderTree={resultingFolderTree}
|
||||
onButtonClick={this.onClickSave}
|
||||
header={header}
|
||||
dialogName={name}
|
||||
footer={footer}
|
||||
isLoadingData={isLoadingData}
|
||||
primaryButtonName={buttonName}
|
||||
isAvailable={isAvailableFolderList}
|
||||
onSelectFolder={this.onSelectFolder}
|
||||
onSelectFile={this.onSelectFile}
|
||||
filesListTitle={filesListTitle}
|
||||
fileId={fileInfo?.id}
|
||||
newFilter={this.newFilter}
|
||||
foldersType={foldersType}
|
||||
onClickInput={this.onClickInput}
|
||||
onCloseSelectFolderDialog={this.onCloseSelectFolderDialog}
|
||||
maxInputWidth={maxInputWidth}
|
||||
/>
|
||||
) : (
|
||||
<SelectFileDialogModalView
|
||||
theme={theme}
|
||||
<SelectionPanel
|
||||
t={t}
|
||||
theme={theme}
|
||||
isPanelVisible={isPanelVisible}
|
||||
onClose={onClose}
|
||||
withoutProvider={withoutProvider}
|
||||
folderId={folderId}
|
||||
resultingFolderTree={resultingFolderTree}
|
||||
onButtonClick={this.onClickSave}
|
||||
header={header}
|
||||
dialogName={name}
|
||||
footer={footer}
|
||||
isLoadingData={isLoadingData}
|
||||
primaryButtonName={buttonName}
|
||||
isAvailable={isAvailableFolderList}
|
||||
onSelectFolder={this.onSelectFolder}
|
||||
onSelectFile={this.onSelectFile}
|
||||
foldersType={foldersType}
|
||||
onClickSave={this.onClickSave}
|
||||
filesList={filesList}
|
||||
hasNextPage={hasNextPage}
|
||||
isNextPageLoading={isNextPageLoading}
|
||||
loadNextPage={this.loadNextPage}
|
||||
selectedFolder={selectedFolder}
|
||||
withoutProvider={withoutProvider}
|
||||
headerName={headerName}
|
||||
loadingText={loadingText}
|
||||
selectedFile={selectedFile}
|
||||
folderId={folderId}
|
||||
passedId={passedId}
|
||||
titleFilesList={titleFilesList}
|
||||
primaryButtonName={this.buttonName}
|
||||
foldersList={foldersList}
|
||||
filesListTitle={filesListTitle}
|
||||
fileId={fileInfo?.id}
|
||||
newFilter={this.newFilter}
|
||||
/>
|
||||
);
|
||||
}
|
||||
}
|
||||
SelectFileDialogBody.propTypes = {
|
||||
SelectFileDialog.propTypes = {
|
||||
onClose: PropTypes.func.isRequired,
|
||||
isPanelVisible: PropTypes.bool.isRequired,
|
||||
onSelectFile: PropTypes.func.isRequired,
|
||||
@ -356,67 +299,59 @@ SelectFileDialogBody.propTypes = {
|
||||
"exceptSortedByTags",
|
||||
"exceptPrivacyTrashFolders",
|
||||
]),
|
||||
folderId: PropTypes.string,
|
||||
id: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
|
||||
withoutProvider: PropTypes.bool,
|
||||
creationButtonPrimary: PropTypes.bool,
|
||||
ignoreSelectedFolderTree: PropTypes.bool,
|
||||
headerName: PropTypes.string,
|
||||
titleFilesList: PropTypes.oneOfType([PropTypes.string, PropTypes.object]),
|
||||
zIndex: PropTypes.number,
|
||||
filesListTitle: PropTypes.oneOfType([PropTypes.string, PropTypes.object]),
|
||||
withoutResetFolderTree: PropTypes.bool,
|
||||
};
|
||||
|
||||
SelectFileDialogBody.defaultProps = {
|
||||
folderId: "",
|
||||
titleFilesList: "",
|
||||
SelectFileDialog.defaultProps = {
|
||||
id: "",
|
||||
filesListTitle: "",
|
||||
withoutProvider: false,
|
||||
zIndex: 310,
|
||||
creationButtonPrimary: false,
|
||||
ignoreSelectedFolderTree: false,
|
||||
withoutResetFolderTree: false,
|
||||
};
|
||||
|
||||
const SelectFileDialogWrapper = inject(
|
||||
export default inject(
|
||||
({
|
||||
auth,
|
||||
filesStore,
|
||||
selectedFilesStore,
|
||||
treeFoldersStore,
|
||||
selectedFolderStore,
|
||||
selectFileDialogStore,
|
||||
}) => {
|
||||
const {
|
||||
folderId: storeFolderId,
|
||||
folderId: id,
|
||||
fileInfo,
|
||||
setFolderId,
|
||||
setFile,
|
||||
} = selectedFilesStore;
|
||||
} = selectFileDialogStore;
|
||||
|
||||
const { setSelectedNode, setExpandedPanelKeys } = treeFoldersStore;
|
||||
const { treeFolders, setExpandedPanelKeys } = treeFoldersStore;
|
||||
const { filter } = filesStore;
|
||||
const { setSelectedFolder, id } = selectedFolderStore;
|
||||
const { id: storeFolderId } = selectedFolderStore;
|
||||
|
||||
const { settingsStore } = auth;
|
||||
const { theme } = settingsStore;
|
||||
const folderId = id ? id : storeFolderId;
|
||||
|
||||
return {
|
||||
storeFolderId: storeFolderId || id,
|
||||
fileInfo,
|
||||
setFile,
|
||||
setFolderId,
|
||||
setSelectedFolder,
|
||||
setSelectedNode,
|
||||
filter,
|
||||
treeFolders,
|
||||
storeFolderId,
|
||||
folderId,
|
||||
theme: theme,
|
||||
setExpandedPanelKeys,
|
||||
};
|
||||
}
|
||||
)(
|
||||
observer(
|
||||
withTranslation(["SelectFile", "Common", "Translations"])(
|
||||
SelectFileDialogBody
|
||||
)
|
||||
withTranslation(["SelectFile", "Common", "Translations"])(SelectFileDialog)
|
||||
)
|
||||
);
|
||||
class SelectFileDialog extends React.Component {
|
||||
render() {
|
||||
return (
|
||||
<MobxProvider auth={authStore} {...stores}>
|
||||
<I18nextProvider i18n={i18n}>
|
||||
<SelectFileDialogWrapper {...this.props} />
|
||||
</I18nextProvider>
|
||||
</MobxProvider>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default SelectFileDialog;
|
||||
|
@ -0,0 +1,28 @@
|
||||
import React from "react";
|
||||
import { Provider as MobxProvider } from "mobx-react";
|
||||
import { I18nextProvider } from "react-i18next";
|
||||
import stores from "../../../store/index";
|
||||
import store from "studio/store";
|
||||
import SelectFileInput from "./index";
|
||||
import i18n from "./i18n";
|
||||
const { auth: authStore } = store;
|
||||
|
||||
const SelectFileModalWrapper = (props) => <SelectFileInput {...props} />;
|
||||
|
||||
class SelectFileInputWrapper extends React.Component {
|
||||
componentDidMount() {
|
||||
authStore.init(true);
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<MobxProvider auth={authStore} {...stores}>
|
||||
<I18nextProvider i18n={i18n}>
|
||||
<SelectFileModalWrapper {...this.props} />
|
||||
</I18nextProvider>
|
||||
</MobxProvider>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default SelectFileInputWrapper;
|
@ -0,0 +1,35 @@
|
||||
import i18n from "i18next";
|
||||
import Backend from "i18next-http-backend";
|
||||
import { LANGUAGE } from "@appserver/common/constants";
|
||||
import config from "../../../../package.json";
|
||||
import { loadLanguagePath } from "@appserver/common/utils";
|
||||
|
||||
const newInstance = i18n.createInstance();
|
||||
|
||||
newInstance.use(Backend).init({
|
||||
lng: localStorage.getItem(LANGUAGE) || "en",
|
||||
fallbackLng: "en",
|
||||
load: "currentOnly",
|
||||
//debug: true,
|
||||
|
||||
interpolation: {
|
||||
escapeValue: false, // not needed for react as it escapes by default
|
||||
format: function (value, format) {
|
||||
if (format === "lowercase") return value.toLowerCase();
|
||||
return value;
|
||||
},
|
||||
},
|
||||
|
||||
backend: {
|
||||
loadPath: loadLanguagePath(config.homepage),
|
||||
},
|
||||
|
||||
ns: ["SelectFile"],
|
||||
defaultNS: "SelectFile",
|
||||
|
||||
react: {
|
||||
useSuspense: false,
|
||||
},
|
||||
});
|
||||
|
||||
export default newInstance;
|
@ -1,7 +1,6 @@
|
||||
import React from "react";
|
||||
import { Provider as MobxProvider, inject, observer } from "mobx-react";
|
||||
import PropTypes from "prop-types";
|
||||
|
||||
import stores from "../../../store/index";
|
||||
import SelectFileDialog from "../SelectFileDialog";
|
||||
import StyledComponent from "./StyledSelectFileInput";
|
||||
@ -13,6 +12,7 @@ class SelectFileInputBody extends React.PureComponent {
|
||||
|
||||
this.state = {
|
||||
fileName: "",
|
||||
folderId: "",
|
||||
};
|
||||
}
|
||||
|
||||
@ -20,76 +20,46 @@ class SelectFileInputBody extends React.PureComponent {
|
||||
this.props.setFirstLoad(false);
|
||||
}
|
||||
|
||||
onSetFileName = (fileName) => {
|
||||
onSetFileNameAndLocation = (fileName, id) => {
|
||||
this.setState({
|
||||
fileName: fileName,
|
||||
folderId: id,
|
||||
});
|
||||
};
|
||||
|
||||
render() {
|
||||
const {
|
||||
name,
|
||||
onClickInput,
|
||||
isPanelVisible,
|
||||
withoutProvider,
|
||||
onClose,
|
||||
isError,
|
||||
isDisabled,
|
||||
foldersType,
|
||||
withSubfolders,
|
||||
onSelectFile,
|
||||
folderId,
|
||||
headerName,
|
||||
isImageOnly,
|
||||
isArchiveOnly,
|
||||
isDocumentsOnly,
|
||||
searchParam,
|
||||
isPresentationOnly,
|
||||
isTablesOnly,
|
||||
isMediaOnly,
|
||||
loadingLabel,
|
||||
titleFilesList,
|
||||
zIndex,
|
||||
fontSizeInput,
|
||||
hasError,
|
||||
t,
|
||||
placeholder,
|
||||
maxInputWidth,
|
||||
foldersList,
|
||||
maxFolderInputWidth,
|
||||
isPanelVisible,
|
||||
isDisabled,
|
||||
isError,
|
||||
...rest
|
||||
} = this.props;
|
||||
const { fileName } = this.state;
|
||||
|
||||
const { fileName, folderId } = this.state;
|
||||
|
||||
return (
|
||||
<StyledComponent maxInputWidth={maxInputWidth}>
|
||||
<SimpleFileInput
|
||||
name={name}
|
||||
className="select-file_file-input"
|
||||
textField={fileName}
|
||||
isDisabled={isDisabled}
|
||||
isError={isError}
|
||||
onClickInput={onClickInput}
|
||||
fontSizeInput={fontSizeInput}
|
||||
maxInputWidth={maxInputWidth}
|
||||
/>
|
||||
|
||||
{isPanelVisible && (
|
||||
<SelectFileDialog
|
||||
zIndex={zIndex}
|
||||
onClose={onClose}
|
||||
{...rest}
|
||||
id={folderId}
|
||||
isPanelVisible={isPanelVisible}
|
||||
foldersType={foldersType}
|
||||
onSetFileName={this.onSetFileName}
|
||||
withoutProvider={withoutProvider}
|
||||
withSubfolders={withSubfolders}
|
||||
onSelectFile={onSelectFile}
|
||||
folderId={folderId}
|
||||
headerName={headerName}
|
||||
searchParam={searchParam}
|
||||
isImageOnly={isImageOnly}
|
||||
isArchiveOnly={isArchiveOnly}
|
||||
isDocumentsOnly={isDocumentsOnly}
|
||||
isPresentation={isPresentationOnly}
|
||||
isTables={isTablesOnly}
|
||||
isMediaOnly={isMediaOnly}
|
||||
loadingLabel={loadingLabel}
|
||||
titleFilesList={titleFilesList}
|
||||
foldersList={foldersList}
|
||||
onSetFileNameAndLocation={this.onSetFileNameAndLocation}
|
||||
maxInputWidth={maxFolderInputWidth}
|
||||
/>
|
||||
)}
|
||||
</StyledComponent>
|
||||
@ -99,13 +69,13 @@ class SelectFileInputBody extends React.PureComponent {
|
||||
|
||||
SelectFileInputBody.propTypes = {
|
||||
onClickInput: PropTypes.func.isRequired,
|
||||
onClose: PropTypes.func.isRequired,
|
||||
hasError: PropTypes.bool,
|
||||
placeholder: PropTypes.string,
|
||||
};
|
||||
|
||||
SelectFileInputBody.defaultProps = {
|
||||
withoutProvider: false,
|
||||
isDisabled: false,
|
||||
zIndex: 310,
|
||||
hasError: false,
|
||||
placeholder: "",
|
||||
};
|
||||
|
||||
const SelectFileInputBodyWrapper = inject(({ filesStore }) => {
|
||||
|
@ -1,118 +1,122 @@
|
||||
import React from "react";
|
||||
|
||||
import IconButton from "@appserver/components/icon-button";
|
||||
import FolderTreeBody from "../../FolderTreeBody";
|
||||
import { StyledAsidePanel, StyledSelectFolderPanel } from "../StyledPanels";
|
||||
import Button from "@appserver/components/button";
|
||||
import ModalDialog from "@appserver/components/modal-dialog";
|
||||
import {
|
||||
StyledAsideBody,
|
||||
StyledAsideHeader,
|
||||
} from "../SelectionPanel/StyledSelectionPanel";
|
||||
import Text from "@appserver/components/text";
|
||||
import Loaders from "@appserver/common/components/Loaders";
|
||||
import styled, { css } from "styled-components";
|
||||
|
||||
const DISPLAY_TYPE = "aside";
|
||||
const StyledModalDialog = styled(ModalDialog)`
|
||||
.modal-dialog-aside-body {
|
||||
padding-top: 12px;
|
||||
}
|
||||
`;
|
||||
const SelectFolderDialogAsideView = ({
|
||||
theme,
|
||||
t,
|
||||
isPanelVisible,
|
||||
zIndex,
|
||||
onClose,
|
||||
withoutProvider,
|
||||
isNeedArrowIcon,
|
||||
asideHeightContent,
|
||||
isAvailable,
|
||||
certainFolders,
|
||||
folderId,
|
||||
isLoadingData,
|
||||
folderList,
|
||||
onSelect,
|
||||
resultingFolderTree,
|
||||
onSelectFolder,
|
||||
footer,
|
||||
showButtons,
|
||||
onSave,
|
||||
headerName,
|
||||
onButtonClick,
|
||||
dialogName,
|
||||
header,
|
||||
canCreate,
|
||||
isLoading,
|
||||
primaryButtonName,
|
||||
noTreeSwitcher,
|
||||
isDisableTree,
|
||||
isDisableButton,
|
||||
}) => {
|
||||
return (
|
||||
<StyledAsidePanel theme={theme} visible={isPanelVisible}>
|
||||
<ModalDialog
|
||||
theme={theme}
|
||||
visible={isPanelVisible}
|
||||
zIndex={zIndex}
|
||||
contentHeight="100%"
|
||||
contentPaddingBottom={footer && showButtons ? "100px" : "40px"}
|
||||
onClose={onClose}
|
||||
withoutBodyScroll
|
||||
displayType="aside"
|
||||
>
|
||||
<ModalDialog.Header theme={theme}>
|
||||
<StyledSelectFolderPanel theme={theme}>
|
||||
<div className="select-folder-dialog_header">
|
||||
{isNeedArrowIcon && (
|
||||
<IconButton
|
||||
theme={theme}
|
||||
className="select-folder-dialog_header-icon"
|
||||
size="16"
|
||||
iconName="/static/images/arrow.path.react.svg"
|
||||
onClick={onClose}
|
||||
// color={theme.filesPanels.selectFolder.color}
|
||||
/>
|
||||
)}
|
||||
{headerName ? headerName : t("Translations:FolderSelection")}
|
||||
<StyledModalDialog
|
||||
theme={theme}
|
||||
visible={isPanelVisible}
|
||||
contentHeight="100%"
|
||||
contentPaddingBottom="0px"
|
||||
onClose={onClose}
|
||||
withoutBodyScroll
|
||||
displayType="aside"
|
||||
>
|
||||
<ModalDialog.Header theme={theme}>
|
||||
<StyledAsideHeader>
|
||||
{isNeedArrowIcon && (
|
||||
<IconButton
|
||||
theme={theme}
|
||||
className="selection-panel_aside-header-icon"
|
||||
size="16"
|
||||
iconName="/static/images/arrow.path.react.svg"
|
||||
onClick={onClose}
|
||||
/>
|
||||
)}
|
||||
{dialogName ? dialogName : t("Translations:FolderSelection")}
|
||||
</StyledAsideHeader>
|
||||
</ModalDialog.Header>
|
||||
<ModalDialog.Body theme={theme}>
|
||||
<StyledAsideBody theme={theme} header={!!header} footer={!!footer}>
|
||||
<div className="selection-panel_aside-body">
|
||||
<div className="selection-panel_aside-header">
|
||||
<div>{header}</div>
|
||||
<Text fontWeight="700" fontSize="18px">
|
||||
{t("Translations:Documents")}
|
||||
</Text>
|
||||
</div>
|
||||
</StyledSelectFolderPanel>
|
||||
</ModalDialog.Header>
|
||||
<ModalDialog.Body theme={theme}>
|
||||
<StyledSelectFolderPanel
|
||||
theme={theme}
|
||||
displayType={DISPLAY_TYPE}
|
||||
showButtons={showButtons}
|
||||
isFooter={!!footer}
|
||||
noTreeSwitcher={noTreeSwitcher}
|
||||
>
|
||||
<div className="select-folder-dialog_aside_body">
|
||||
<div>{header} </div>
|
||||
|
||||
<FolderTreeBody
|
||||
theme={theme}
|
||||
isLoadingData={isLoadingData}
|
||||
folderList={folderList}
|
||||
onSelect={onSelect}
|
||||
withoutProvider={withoutProvider}
|
||||
certainFolders={certainFolders}
|
||||
isAvailable={isAvailable}
|
||||
selectedKeys={[folderId]}
|
||||
heightContent={asideHeightContent}
|
||||
displayType={DISPLAY_TYPE}
|
||||
/>
|
||||
<div className="selection-panel_aside-tree">
|
||||
{folderId && resultingFolderTree ? (
|
||||
<FolderTreeBody
|
||||
theme={theme}
|
||||
folderTree={resultingFolderTree}
|
||||
onSelect={onSelectFolder}
|
||||
withoutProvider={withoutProvider}
|
||||
certainFolders
|
||||
isAvailable={isAvailable}
|
||||
selectedKeys={[`${folderId}`]}
|
||||
isDisableTree={isDisableTree}
|
||||
displayType="aside"
|
||||
/>
|
||||
) : (
|
||||
<Loaders.NewTreeFolders />
|
||||
)}
|
||||
</div>
|
||||
</StyledSelectFolderPanel>
|
||||
</ModalDialog.Body>
|
||||
<ModalDialog.Footer theme={theme}>
|
||||
<StyledSelectFolderPanel theme={theme}>
|
||||
{footer}
|
||||
{showButtons && (
|
||||
<div className="select-folder-dialog-modal_buttons">
|
||||
|
||||
<div className="selection-panel_aside-footer">
|
||||
<div>{footer}</div>
|
||||
<div className="selection-panel_aside-buttons">
|
||||
<Button
|
||||
theme={theme}
|
||||
className="select-folder-dialog-buttons-save"
|
||||
primary
|
||||
size="normal"
|
||||
size="normalTouchscreen"
|
||||
label={primaryButtonName}
|
||||
onClick={onSave}
|
||||
isDisabled={isLoadingData || !isAvailable || !canCreate}
|
||||
onClick={onButtonClick}
|
||||
isDisabled={
|
||||
isDisableButton ||
|
||||
isDisableTree ||
|
||||
isLoadingData ||
|
||||
!isAvailable
|
||||
}
|
||||
/>
|
||||
<Button
|
||||
size="normal"
|
||||
size="normalTouchscreen"
|
||||
label={t("Common:CancelButton")}
|
||||
onClick={onClose}
|
||||
isDisabled={isLoadingData || isLoading}
|
||||
isDisabled={isLoadingData}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
</StyledSelectFolderPanel>
|
||||
</ModalDialog.Footer>
|
||||
</ModalDialog>
|
||||
</StyledAsidePanel>
|
||||
</div>
|
||||
</div>
|
||||
</StyledAsideBody>
|
||||
</ModalDialog.Body>
|
||||
</StyledModalDialog>
|
||||
);
|
||||
};
|
||||
export default SelectFolderDialogAsideView;
|
||||
|
@ -1,95 +0,0 @@
|
||||
import React from "react";
|
||||
|
||||
import ModalDialog from "@appserver/components/modal-dialog";
|
||||
import { StyledAsidePanel, StyledSelectFolderPanel } from "../StyledPanels";
|
||||
import FolderTreeBody from "../../FolderTreeBody";
|
||||
import Button from "@appserver/components/button";
|
||||
|
||||
const SelectFolderDialogModalView = ({
|
||||
t,
|
||||
theme,
|
||||
isPanelVisible,
|
||||
zIndex,
|
||||
onClose,
|
||||
withoutProvider,
|
||||
isNeedArrowIcon,
|
||||
modalHeightContent,
|
||||
isAvailable,
|
||||
certainFolders,
|
||||
folderId,
|
||||
isLoadingData,
|
||||
folderList,
|
||||
onSelect,
|
||||
header,
|
||||
footer,
|
||||
headerName,
|
||||
showButtons,
|
||||
onSave,
|
||||
canCreate,
|
||||
isLoading,
|
||||
primaryButtonName,
|
||||
noTreeSwitcher,
|
||||
}) => {
|
||||
return (
|
||||
<StyledAsidePanel theme={theme} visible={isPanelVisible}>
|
||||
<ModalDialog
|
||||
theme={theme}
|
||||
visible={isPanelVisible}
|
||||
zIndex={zIndex}
|
||||
onClose={onClose}
|
||||
displayType="modal"
|
||||
{...(!header && !footer && !showButtons && { contentHeight: "416px" })}
|
||||
>
|
||||
<ModalDialog.Header theme={theme}>
|
||||
{headerName ? headerName : t("Translations:FolderSelection")}
|
||||
</ModalDialog.Header>
|
||||
|
||||
<ModalDialog.Body theme={theme}>
|
||||
<StyledSelectFolderPanel
|
||||
theme={theme}
|
||||
isNeedArrowIcon={isNeedArrowIcon}
|
||||
noTreeSwitcher={noTreeSwitcher}
|
||||
>
|
||||
<div className="select-folder-modal-dialog-header">{header} </div>
|
||||
<FolderTreeBody
|
||||
theme={theme}
|
||||
isLoadingData={isLoadingData}
|
||||
folderList={folderList}
|
||||
onSelect={onSelect}
|
||||
withoutProvider={withoutProvider}
|
||||
certainFolders={certainFolders}
|
||||
isAvailable={isAvailable}
|
||||
selectedKeys={[folderId]}
|
||||
heightContent={modalHeightContent}
|
||||
/>
|
||||
</StyledSelectFolderPanel>
|
||||
</ModalDialog.Body>
|
||||
<ModalDialog.Footer theme={theme}>
|
||||
<StyledSelectFolderPanel theme={theme}>
|
||||
{footer}
|
||||
{showButtons && (
|
||||
<div className="select-folder-dialog-modal_buttons">
|
||||
<Button
|
||||
theme={theme}
|
||||
className="select-folder-dialog-buttons-save"
|
||||
primary
|
||||
size="small"
|
||||
label={primaryButtonName}
|
||||
onClick={onSave}
|
||||
isDisabled={isLoadingData || !isAvailable || !canCreate}
|
||||
/>
|
||||
<Button
|
||||
size="small"
|
||||
label={t("Common:CancelButton")}
|
||||
onClick={onClose}
|
||||
isDisabled={isLoadingData || isLoading}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
</StyledSelectFolderPanel>
|
||||
</ModalDialog.Footer>
|
||||
</ModalDialog>
|
||||
</StyledAsidePanel>
|
||||
);
|
||||
};
|
||||
export default SelectFolderDialogModalView;
|
@ -0,0 +1,28 @@
|
||||
import React from "react";
|
||||
import { Provider as MobxProvider } from "mobx-react";
|
||||
import { I18nextProvider } from "react-i18next";
|
||||
import stores from "../../../store/index";
|
||||
import store from "studio/store";
|
||||
import SelectFolderDialog from "./index";
|
||||
import i18n from "./i18n";
|
||||
const { auth: authStore } = store;
|
||||
|
||||
const SelectFolderModalWrapper = (props) => <SelectFolderDialog {...props} />;
|
||||
|
||||
class SelectFolderModal extends React.Component {
|
||||
componentDidMount() {
|
||||
authStore.init(true);
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<MobxProvider auth={authStore} {...stores}>
|
||||
<I18nextProvider i18n={i18n}>
|
||||
<SelectFolderModalWrapper {...this.props} />
|
||||
</I18nextProvider>
|
||||
</MobxProvider>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default SelectFolderModal;
|
@ -24,7 +24,7 @@ newInstance.use(Backend).init({
|
||||
loadPath: loadLanguagePath(config.homepage),
|
||||
},
|
||||
|
||||
ns: ["SelectFolder", "Common", "Translations"],
|
||||
ns: ["SelectFolder"],
|
||||
defaultNS: "SelectFolder",
|
||||
|
||||
react: {
|
||||
@ -32,4 +32,4 @@ newInstance.use(Backend).init({
|
||||
},
|
||||
});
|
||||
|
||||
export default newInstance;
|
||||
export default newInstance;
|
@ -1,377 +1,113 @@
|
||||
import React from "react";
|
||||
import { inject, observer, Provider as MobxProvider } from "mobx-react";
|
||||
import { I18nextProvider } from "react-i18next";
|
||||
import { inject, observer } from "mobx-react";
|
||||
import { withTranslation } from "react-i18next";
|
||||
import PropTypes from "prop-types";
|
||||
import throttle from "lodash/throttle";
|
||||
|
||||
import { getCommonThirdPartyList } from "@appserver/common/api/settings";
|
||||
import {
|
||||
getCommonFolderList,
|
||||
getFolder,
|
||||
getFolderPath,
|
||||
getFoldersTree,
|
||||
} from "@appserver/common/api/files";
|
||||
|
||||
import SelectFolderInput from "../SelectFolderInput";
|
||||
import i18n from "./i18n";
|
||||
import SelectFolderDialogAsideView from "./AsideView";
|
||||
import SelectFolderDialogModalView from "./ModalView";
|
||||
import stores from "../../../store/index";
|
||||
import utils from "@appserver/components/utils";
|
||||
import { FolderType } from "@appserver/common/constants";
|
||||
import { isArrayEqual } from "@appserver/components/utils/array";
|
||||
import store from "studio/store";
|
||||
import toastr from "studio/toastr";
|
||||
import {
|
||||
exceptSortedByTagsFolders,
|
||||
exceptPrivacyTrashFolders,
|
||||
} from "./ExceptionFoldersConstants";
|
||||
|
||||
const { auth: authStore } = store;
|
||||
import SelectionPanel from "../SelectionPanel/SelectionPanelBody";
|
||||
import { FilterType } from "@appserver/common/constants";
|
||||
|
||||
const { desktop } = utils.device;
|
||||
|
||||
let pathName = "";
|
||||
let folderList;
|
||||
|
||||
class SelectFolderModalDialog extends React.Component {
|
||||
class SelectFolderDialog extends React.Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
const {
|
||||
isSetFolderImmediately,
|
||||
id,
|
||||
displayType,
|
||||
selectionButtonPrimary,
|
||||
t,
|
||||
} = this.props;
|
||||
|
||||
const isNeedFolder = id ? true : isSetFolderImmediately;
|
||||
this.buttonName = selectionButtonPrimary
|
||||
? t("Common:Select")
|
||||
: t("Common:SaveButton");
|
||||
|
||||
const { id, displayType, filter } = this.props;
|
||||
this.newFilter = filter.clone();
|
||||
this.newFilter.filterType = FilterType.FilesOnly;
|
||||
this.newFilter.withSubfolders = false;
|
||||
this.state = {
|
||||
isLoadingData: false,
|
||||
isLoading: false,
|
||||
isAvailable: true,
|
||||
certainFolders: true,
|
||||
folderId: "",
|
||||
displayType: displayType || this.getDisplayType(),
|
||||
isSetFolderImmediately: isNeedFolder,
|
||||
canCreate: true,
|
||||
isAvailable: true,
|
||||
};
|
||||
this.throttledResize = throttle(this.setDisplayType, 300);
|
||||
this.folderTitle = "";
|
||||
this.noTreeSwitcher = false;
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
const { onSetLoadingData, onSetLoadingInput, displayType } = this.props;
|
||||
|
||||
authStore.init(true); // it will work if authStore is not initialized
|
||||
async componentDidMount() {
|
||||
const {
|
||||
treeFolders,
|
||||
foldersType,
|
||||
onSetBaseFolderPath,
|
||||
onSelectFolder,
|
||||
foldersList,
|
||||
displayType,
|
||||
isNeedArrowIcon = false,
|
||||
folderTree,
|
||||
setFolderId,
|
||||
withInput,
|
||||
id,
|
||||
storeFolderId,
|
||||
} = this.props;
|
||||
|
||||
!displayType && window.addEventListener("resize", this.throttledResize);
|
||||
this.setState({ isLoadingData: true }, function () {
|
||||
onSetLoadingData && onSetLoadingData(true);
|
||||
onSetLoadingInput && onSetLoadingInput(true);
|
||||
this.trySwitch();
|
||||
|
||||
const initialFolderId = withInput ? id : storeFolderId;
|
||||
|
||||
let resultingFolderTree, resultingId;
|
||||
|
||||
if (!withInput && !isNeedArrowIcon) {
|
||||
try {
|
||||
[
|
||||
resultingFolderTree,
|
||||
resultingId,
|
||||
] = await SelectionPanel.getBasicFolderInfo(
|
||||
treeFolders,
|
||||
foldersType,
|
||||
initialFolderId,
|
||||
onSetBaseFolderPath,
|
||||
onSelectFolder,
|
||||
foldersList
|
||||
);
|
||||
} catch (e) {
|
||||
toastr.error(e);
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
const tree =
|
||||
isNeedArrowIcon || withInput ? folderTree : resultingFolderTree;
|
||||
|
||||
if (tree.length === 0) {
|
||||
this.setState({ isAvailable: false });
|
||||
onSelectFolder(null);
|
||||
return;
|
||||
}
|
||||
const resId = isNeedArrowIcon || withInput ? id : resultingId;
|
||||
|
||||
onSelectFolder && onSelectFolder(resId);
|
||||
isNeedArrowIcon && onSetBaseFolderPath(resId);
|
||||
|
||||
setFolderId(resId);
|
||||
|
||||
this.setState({
|
||||
resultingFolderTree: tree,
|
||||
});
|
||||
}
|
||||
|
||||
componentDidUpdate(prevProps) {
|
||||
const {
|
||||
storeFolderId,
|
||||
canCreate,
|
||||
showButtons,
|
||||
selectionButtonPrimary,
|
||||
isReset,
|
||||
} = this.props;
|
||||
|
||||
if (
|
||||
showButtons &&
|
||||
!selectionButtonPrimary &&
|
||||
storeFolderId !== prevProps.storeFolderId
|
||||
) {
|
||||
this.setState({
|
||||
canCreate: canCreate,
|
||||
isLoading: false,
|
||||
});
|
||||
}
|
||||
const { isReset } = this.props;
|
||||
|
||||
if (isReset && isReset !== prevProps.isReset) {
|
||||
this.onResetInfo();
|
||||
}
|
||||
}
|
||||
trySwitch = async () => {
|
||||
const {
|
||||
folderPath,
|
||||
onSelectFolder,
|
||||
onSetBaseFolderPath,
|
||||
foldersType,
|
||||
id,
|
||||
selectedFolderId,
|
||||
foldersList,
|
||||
} = this.props;
|
||||
|
||||
switch (foldersType) {
|
||||
case "exceptSortedByTags":
|
||||
try {
|
||||
const foldersTree = await getFoldersTree();
|
||||
|
||||
[folderList, this.noTreeSwitcher] = SelectFolderDialog.convertFolders(
|
||||
foldersTree,
|
||||
exceptSortedByTagsFolders
|
||||
);
|
||||
this.setBaseSettings();
|
||||
} catch (err) {
|
||||
console.error("error", err);
|
||||
this.loadersCompletes();
|
||||
}
|
||||
break;
|
||||
case "exceptPrivacyTrashFolders":
|
||||
try {
|
||||
const foldersTree = await getFoldersTree();
|
||||
[folderList, this.noTreeSwitcher] = SelectFolderDialog.convertFolders(
|
||||
foldersTree,
|
||||
exceptPrivacyTrashFolders
|
||||
);
|
||||
this.setBaseSettings();
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
this.loadersCompletes();
|
||||
}
|
||||
break;
|
||||
|
||||
case "common":
|
||||
try {
|
||||
folderList = await SelectFolderDialog.getCommonFolders();
|
||||
folderPath.length === 0 &&
|
||||
!selectedFolderId &&
|
||||
onSelectFolder &&
|
||||
onSelectFolder(`${id ? id : folderList[0].id}`);
|
||||
|
||||
this.setState({
|
||||
folderId: `${
|
||||
selectedFolderId ? selectedFolderId : id ? id : folderList[0].id
|
||||
}`,
|
||||
});
|
||||
|
||||
!id &&
|
||||
!selectedFolderId &&
|
||||
onSetBaseFolderPath &&
|
||||
onSetBaseFolderPath(folderList[0].title);
|
||||
|
||||
this.setFolderInfo();
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
this.loadersCompletes();
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case "third-party":
|
||||
try {
|
||||
folderList = foldersList
|
||||
? foldersList
|
||||
: await SelectFolderDialog.getCommonThirdPartyList();
|
||||
|
||||
this.setBaseSettings();
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
|
||||
this.loadersCompletes();
|
||||
}
|
||||
break;
|
||||
}
|
||||
};
|
||||
|
||||
loadersCompletes = () => {
|
||||
const {
|
||||
onSetLoadingData,
|
||||
|
||||
onSetLoadingInput,
|
||||
} = this.props;
|
||||
|
||||
onSetLoadingData && onSetLoadingData(false);
|
||||
onSetLoadingInput && onSetLoadingInput(false);
|
||||
|
||||
this.setState({
|
||||
isLoadingData: false,
|
||||
});
|
||||
};
|
||||
setBaseSettings = async () => {
|
||||
const { isSetFolderImmediately } = this.state;
|
||||
const {
|
||||
onSelectFolder,
|
||||
onSetBaseFolderPath,
|
||||
id,
|
||||
selectedFolderId,
|
||||
showButtons,
|
||||
} = this.props;
|
||||
|
||||
if (folderList.length === 0) {
|
||||
this.setState({ isAvailable: false });
|
||||
onSelectFolder(null);
|
||||
this.loadersCompletes();
|
||||
return;
|
||||
}
|
||||
|
||||
!id && showButtons && this.setFolderToTree(folderList[0].id);
|
||||
|
||||
isSetFolderImmediately &&
|
||||
!selectedFolderId &&
|
||||
onSelectFolder &&
|
||||
onSelectFolder(
|
||||
`${selectedFolderId ? selectedFolderId : id ? id : folderList[0].id}`
|
||||
);
|
||||
|
||||
isSetFolderImmediately &&
|
||||
this.setState({
|
||||
folderId: `${
|
||||
selectedFolderId ? selectedFolderId : id ? id : folderList[0].id
|
||||
}`,
|
||||
});
|
||||
|
||||
if (onSetBaseFolderPath) {
|
||||
try {
|
||||
this.folderTitle = await SelectFolderDialog.getFolderPath(
|
||||
id ? id : folderList[0].id
|
||||
);
|
||||
|
||||
!id &&
|
||||
!selectedFolderId &&
|
||||
isSetFolderImmediately &&
|
||||
onSetBaseFolderPath(this.folderTitle);
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
}
|
||||
}
|
||||
|
||||
this.setFolderInfo();
|
||||
};
|
||||
|
||||
setFolderInfo = () => {
|
||||
const {
|
||||
id,
|
||||
onSetFileName,
|
||||
fileName,
|
||||
selectedFolderId,
|
||||
dialogWithFiles,
|
||||
onSetBaseFolderPath,
|
||||
} = this.props;
|
||||
|
||||
fileName && onSetFileName && onSetFileName(fileName);
|
||||
|
||||
if (!id && !selectedFolderId) {
|
||||
this.loadersCompletes();
|
||||
return;
|
||||
}
|
||||
|
||||
if (selectedFolderId) {
|
||||
onSetBaseFolderPath
|
||||
? this.setBaseFolderPath(selectedFolderId)
|
||||
: this.loadersCompletes();
|
||||
}
|
||||
|
||||
if (id && !selectedFolderId) {
|
||||
if (!dialogWithFiles) this.setSelectedFolder(id);
|
||||
else {
|
||||
this.setBaseFolderPath(id);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
setBaseFolderPath = () => {
|
||||
const { onSetBaseFolderPath, selectedFolderId } = this.props;
|
||||
|
||||
SelectFolderDialog.getFolderPath(selectedFolderId)
|
||||
.then((folderPath) => (this.folderTitle = folderPath))
|
||||
.then(() => onSetBaseFolderPath(this.folderTitle))
|
||||
.catch((error) => console.log("error", error))
|
||||
.finally(() => {
|
||||
this.loadersCompletes();
|
||||
});
|
||||
};
|
||||
setSelectedFolder = async (id) => {
|
||||
const { onSetBaseFolderPath } = this.props;
|
||||
|
||||
let folder,
|
||||
folderPath,
|
||||
requests = [];
|
||||
|
||||
requests.push(getFolder(id));
|
||||
|
||||
if (onSetBaseFolderPath) {
|
||||
requests.push(getFolderPath(id));
|
||||
}
|
||||
|
||||
try {
|
||||
[folder, folderPath] = await Promise.all(requests);
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
}
|
||||
|
||||
folder && this.setFolderObjectToTree(id, folder);
|
||||
|
||||
if (onSetBaseFolderPath && folderPath) {
|
||||
this.folderTitle = SelectFolderInput.setFullFolderPath(folderPath);
|
||||
onSetBaseFolderPath(this.folderTitle);
|
||||
}
|
||||
|
||||
this.loadersCompletes();
|
||||
};
|
||||
|
||||
setFolderToTree = (id) => {
|
||||
getFolder(id)
|
||||
.then((data) => {
|
||||
this.setFolderObjectToTree(id, data);
|
||||
})
|
||||
.catch((error) => console.log("error", error));
|
||||
};
|
||||
|
||||
setFolderObjectToTree = (id, data) => {
|
||||
const {
|
||||
setSelectedNode,
|
||||
setSelectedFolder,
|
||||
selectionButtonPrimary,
|
||||
setExpandedPanelKeys,
|
||||
onSetBaseFolderPath,
|
||||
} = this.props;
|
||||
const isInput = !!onSetBaseFolderPath;
|
||||
|
||||
if (!selectionButtonPrimary || isInput) {
|
||||
//TODO: it need for canCreate function now, will need when passed the folder id - need to come up with a different solution.
|
||||
setSelectedNode([id + ""]);
|
||||
const newPathParts = SelectFolderDialog.convertPathParts(data.pathParts);
|
||||
|
||||
isInput && setExpandedPanelKeys(newPathParts);
|
||||
|
||||
setSelectedFolder({
|
||||
folders: data.folders,
|
||||
...data.current,
|
||||
pathParts: newPathParts,
|
||||
...{ new: data.new },
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
componentWillUnmount() {
|
||||
const {
|
||||
setExpandedPanelKeys,
|
||||
resetTreeFolders,
|
||||
setSelectedFolder,
|
||||
dialogWithFiles,
|
||||
} = this.props;
|
||||
const { setFolderTitle, setProviderKey, setFolderId } = this.props;
|
||||
console.log("componentWillUnmount");
|
||||
|
||||
if (this.throttledResize) {
|
||||
this.throttledResize && this.throttledResize.cancel();
|
||||
window.removeEventListener("resize", this.throttledResize);
|
||||
}
|
||||
|
||||
if (resetTreeFolders && !dialogWithFiles) {
|
||||
setExpandedPanelKeys(null);
|
||||
setSelectedFolder(null);
|
||||
}
|
||||
setFolderTitle("");
|
||||
setProviderKey(null);
|
||||
setFolderId(null);
|
||||
}
|
||||
getDisplayType = () => {
|
||||
const displayType =
|
||||
@ -386,132 +122,52 @@ class SelectFolderModalDialog extends React.Component {
|
||||
this.setState({ displayType: displayType });
|
||||
};
|
||||
|
||||
onSelect = async (folder) => {
|
||||
const {
|
||||
onSelectFolder,
|
||||
onClose,
|
||||
showButtons,
|
||||
onSetFullPath,
|
||||
selectionButtonPrimary,
|
||||
onSetLoadingData,
|
||||
onSetLoadingInput,
|
||||
} = this.props;
|
||||
const { folderId } = this.state;
|
||||
onSelect = async (folder, treeNode) => {
|
||||
const { setFolderId, folderId } = this.props;
|
||||
|
||||
let requests = [];
|
||||
if (+folderId === +folder[0]) return;
|
||||
|
||||
if (isArrayEqual([folder[0]], [folderId])) {
|
||||
return;
|
||||
}
|
||||
|
||||
onSetLoadingData && onSetLoadingData(true);
|
||||
onSetLoadingInput && onSetLoadingInput(true);
|
||||
|
||||
this.setState({
|
||||
folderId: folder[0],
|
||||
});
|
||||
|
||||
let folderInfo, folderPath;
|
||||
|
||||
if (showButtons && !selectionButtonPrimary) {
|
||||
this.setState({
|
||||
isLoading: true,
|
||||
canCreate: false,
|
||||
});
|
||||
}
|
||||
|
||||
try {
|
||||
if (showButtons && onSetFullPath) {
|
||||
requests.push(getFolder(folder[0]), getFolderPath(folder));
|
||||
|
||||
[folderInfo, folderPath] = await Promise.all(requests);
|
||||
} else {
|
||||
showButtons
|
||||
? (folderInfo = await getFolder(folder[0]))
|
||||
: (folderPath = await getFolderPath(folder));
|
||||
}
|
||||
|
||||
if (folderInfo) {
|
||||
this.setFolderObjectToTree(folder[0], folderInfo);
|
||||
}
|
||||
|
||||
if (folderPath) {
|
||||
pathName = SelectFolderInput.setFullFolderPath(folderPath);
|
||||
onSetFullPath && onSetFullPath(pathName);
|
||||
}
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
toastr.error();
|
||||
|
||||
if (showButtons) {
|
||||
this.setState({
|
||||
isLoading: false,
|
||||
canCreate: true,
|
||||
});
|
||||
|
||||
onClose && onClose();
|
||||
}
|
||||
}
|
||||
|
||||
onSelectFolder && onSelectFolder(folder[0]);
|
||||
!showButtons && onClose && onClose();
|
||||
|
||||
this.loadersCompletes();
|
||||
setFolderId(folder[0]);
|
||||
};
|
||||
onSave = (e) => {
|
||||
const { onClose, onSave } = this.props;
|
||||
const { folderId } = this.state;
|
||||
|
||||
onSave && onSave(e, folderId);
|
||||
onClose = () => {
|
||||
const { setExpandedPanelKeys, onClose, treeFolders } = this.props;
|
||||
|
||||
if (!treeFolders.length) {
|
||||
setExpandedPanelKeys(null);
|
||||
}
|
||||
onClose && onClose();
|
||||
};
|
||||
|
||||
onCloseAside = () => {
|
||||
const { onClose } = this.props;
|
||||
onClose && onClose();
|
||||
};
|
||||
|
||||
onButtonClick = (e) => {
|
||||
const {
|
||||
onSave,
|
||||
onSetNewFolderPath,
|
||||
onSelectFolder,
|
||||
withoutImmediatelyClose,
|
||||
onSubmit,
|
||||
|
||||
providerKey,
|
||||
folderTitle,
|
||||
folderId,
|
||||
} = this.props;
|
||||
|
||||
onSubmit && onSubmit(folderId, folderTitle, providerKey);
|
||||
onSave && onSave(e, folderId);
|
||||
onSetNewFolderPath && onSetNewFolderPath(folderId);
|
||||
onSelectFolder && onSelectFolder(folderId);
|
||||
|
||||
!withoutImmediatelyClose && this.onClose();
|
||||
};
|
||||
|
||||
onResetInfo = async () => {
|
||||
const { id, foldersType, onSelectFolder } = this.props;
|
||||
switch (foldersType) {
|
||||
case "common":
|
||||
try {
|
||||
if (!id) {
|
||||
folderList = await SelectFolderDialog.getCommonFolders();
|
||||
}
|
||||
|
||||
onSelectFolder && onSelectFolder(`${id ? id : folderList[0].id}`);
|
||||
|
||||
this.setState({
|
||||
folderId: `${id ? id : folderList[0].id}`,
|
||||
});
|
||||
|
||||
this.setFolderToTree(id ? id : folderList[0].id);
|
||||
|
||||
this.loadersCompletes();
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
this.loadersCompletes();
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case "third-party":
|
||||
try {
|
||||
if (!id) {
|
||||
folderList = await SelectFolderDialog.getCommonThirdPartyList();
|
||||
}
|
||||
|
||||
onSelectFolder && onSelectFolder(`${id ? id : folderList[0].id}`);
|
||||
|
||||
this.setState({
|
||||
folderId: `${id ? id : folderList[0].id}`,
|
||||
});
|
||||
|
||||
this.setFolderToTree(id ? id : folderList[0].id);
|
||||
this.loadersCompletes();
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
|
||||
this.loadersCompletes();
|
||||
}
|
||||
break;
|
||||
}
|
||||
const { id, setFolderId } = this.props;
|
||||
setFolderId(id);
|
||||
};
|
||||
|
||||
render() {
|
||||
@ -520,84 +176,88 @@ class SelectFolderModalDialog extends React.Component {
|
||||
theme,
|
||||
isPanelVisible,
|
||||
zIndex,
|
||||
onClose,
|
||||
withoutProvider,
|
||||
isNeedArrowIcon,
|
||||
modalHeightContent,
|
||||
asideHeightContent,
|
||||
isNeedArrowIcon, //for aside view when selected file
|
||||
header,
|
||||
headerName,
|
||||
dialogName,
|
||||
footer,
|
||||
showButtons,
|
||||
buttonName,
|
||||
isDisableTree,
|
||||
folderId,
|
||||
folderTitle,
|
||||
expandedKeys,
|
||||
isDisableButton,
|
||||
} = this.props;
|
||||
const {
|
||||
isAvailable,
|
||||
certainFolders,
|
||||
folderId,
|
||||
displayType,
|
||||
isLoadingData,
|
||||
canCreate,
|
||||
isLoading,
|
||||
isAvailable,
|
||||
resultingFolderTree,
|
||||
} = this.state;
|
||||
|
||||
const primaryButtonName = buttonName
|
||||
? buttonName
|
||||
: t("Common:SaveHereButton");
|
||||
const name = dialogName ? dialogName : t("Common:SaveButton");
|
||||
|
||||
//console.log("Render Folder Component?", this.state);
|
||||
|
||||
return displayType === "aside" ? (
|
||||
<SelectFolderDialogAsideView
|
||||
theme={theme}
|
||||
t={t}
|
||||
isPanelVisible={isPanelVisible}
|
||||
zIndex={zIndex}
|
||||
onClose={onClose}
|
||||
onClose={this.onCloseAside}
|
||||
withoutProvider={withoutProvider}
|
||||
isNeedArrowIcon={isNeedArrowIcon}
|
||||
asideHeightContent={asideHeightContent}
|
||||
isAvailable={isAvailable}
|
||||
certainFolders={certainFolders}
|
||||
certainFolders={true}
|
||||
folderId={folderId}
|
||||
folderList={folderList}
|
||||
onSelect={this.onSelect}
|
||||
onSave={this.onSave}
|
||||
resultingFolderTree={resultingFolderTree}
|
||||
onSelectFolder={this.onSelect}
|
||||
onButtonClick={this.onButtonClick}
|
||||
header={header}
|
||||
headerName={headerName}
|
||||
dialogName={isNeedArrowIcon ? t("Translations:FolderSelection") : name}
|
||||
footer={footer}
|
||||
showButtons={showButtons}
|
||||
isLoadingData={isLoadingData}
|
||||
canCreate={canCreate}
|
||||
isLoading={isLoading}
|
||||
primaryButtonName={this.buttonName}
|
||||
noTreeSwitcher={this.noTreeSwitcher}
|
||||
primaryButtonName={
|
||||
isNeedArrowIcon ? t("Common:Select") : primaryButtonName
|
||||
}
|
||||
isAvailable={isAvailable}
|
||||
isDisableTree={isDisableTree}
|
||||
isDisableButton={isDisableButton}
|
||||
/>
|
||||
) : (
|
||||
<SelectFolderDialogModalView
|
||||
<SelectionPanel
|
||||
t={t}
|
||||
theme={theme}
|
||||
isPanelVisible={isPanelVisible}
|
||||
zIndex={zIndex}
|
||||
onClose={onClose}
|
||||
onClose={this.onClose}
|
||||
withoutProvider={withoutProvider}
|
||||
modalHeightContent={modalHeightContent}
|
||||
isAvailable={isAvailable}
|
||||
certainFolders={certainFolders}
|
||||
folderId={folderId}
|
||||
folderList={folderList}
|
||||
onSelect={this.onSelect}
|
||||
onSave={this.onSave}
|
||||
resultingFolderTree={resultingFolderTree}
|
||||
onButtonClick={this.onButtonClick}
|
||||
header={header}
|
||||
headerName={headerName}
|
||||
dialogName={name}
|
||||
footer={footer}
|
||||
showButtons={showButtons}
|
||||
canCreate={canCreate}
|
||||
isLoadingData={isLoadingData}
|
||||
isLoading={isLoading}
|
||||
primaryButtonName={this.buttonName}
|
||||
noTreeSwitcher={this.noTreeSwitcher}
|
||||
primaryButtonName={primaryButtonName}
|
||||
isAvailable={isAvailable}
|
||||
onSelectFolder={this.onSelect}
|
||||
folderTitle={folderTitle}
|
||||
expandedKeys={expandedKeys}
|
||||
isDisableTree={isDisableTree}
|
||||
folderSelection
|
||||
newFilter={this.newFilter}
|
||||
isDisableButton={isDisableButton}
|
||||
/>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
SelectFolderModalDialog.propTypes = {
|
||||
SelectFolderDialog.propTypes = {
|
||||
onSelectFolder: PropTypes.func,
|
||||
onClose: PropTypes.func.isRequired,
|
||||
onClose: PropTypes.func,
|
||||
isPanelVisible: PropTypes.bool.isRequired,
|
||||
foldersType: PropTypes.oneOf([
|
||||
"common",
|
||||
@ -606,153 +266,60 @@ SelectFolderModalDialog.propTypes = {
|
||||
"exceptPrivacyTrashFolders",
|
||||
]),
|
||||
displayType: PropTypes.oneOf(["aside", "modal"]),
|
||||
id: PropTypes.string,
|
||||
zIndex: PropTypes.number,
|
||||
id: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
|
||||
withoutProvider: PropTypes.bool,
|
||||
isNeedArrowIcon: PropTypes.bool,
|
||||
dialogWithFiles: PropTypes.bool,
|
||||
showButtons: PropTypes.bool,
|
||||
selectionButtonPrimary: PropTypes.bool,
|
||||
modalHeightContent: PropTypes.string,
|
||||
asideHeightContent: PropTypes.string,
|
||||
withoutImmediatelyClose: PropTypes.bool,
|
||||
isDisableTree: PropTypes.bool,
|
||||
};
|
||||
SelectFolderModalDialog.defaultProps = {
|
||||
isSetFolderImmediately: false,
|
||||
dialogWithFiles: false,
|
||||
isNeedArrowIcon: false,
|
||||
SelectFolderDialog.defaultProps = {
|
||||
id: "",
|
||||
modalHeightContent: "291px",
|
||||
asideHeightContent: "100%",
|
||||
zIndex: 310,
|
||||
withoutProvider: false,
|
||||
folderPath: "",
|
||||
showButtons: false,
|
||||
selectionButtonPrimary: false,
|
||||
withoutImmediatelyClose: false,
|
||||
isDisableTree: false,
|
||||
};
|
||||
|
||||
const SelectFolderDialogWrapper = inject(
|
||||
export default inject(
|
||||
({
|
||||
treeFoldersStore,
|
||||
selectedFolderStore,
|
||||
selectedFilesStore,
|
||||
selectFolderDialogStore,
|
||||
filesStore,
|
||||
auth,
|
||||
}) => {
|
||||
const { setSelectedNode, setExpandedPanelKeys } = treeFoldersStore;
|
||||
const { canCreate } = filesStore;
|
||||
const { setSelectedFolder, id } = selectedFolderStore;
|
||||
const { setFolderId, setFile } = selectedFilesStore;
|
||||
const { treeFolders, setExpandedPanelKeys } = treeFoldersStore;
|
||||
|
||||
const { filter } = filesStore;
|
||||
const { id } = selectedFolderStore;
|
||||
const {
|
||||
setFolderId,
|
||||
setFolderTitle,
|
||||
setProviderKey,
|
||||
providerKey,
|
||||
folderTitle,
|
||||
folderId,
|
||||
} = selectFolderDialogStore;
|
||||
|
||||
const { settingsStore } = auth;
|
||||
const { theme } = settingsStore;
|
||||
|
||||
return {
|
||||
theme: auth.settingsStore.theme,
|
||||
setSelectedFolder,
|
||||
setSelectedNode,
|
||||
canCreate,
|
||||
theme: theme,
|
||||
storeFolderId: id,
|
||||
providerKey,
|
||||
folderTitle,
|
||||
folderId,
|
||||
setExpandedPanelKeys,
|
||||
setFolderId,
|
||||
setFile,
|
||||
setFolderTitle,
|
||||
setProviderKey,
|
||||
treeFolders,
|
||||
filter,
|
||||
};
|
||||
}
|
||||
)(
|
||||
observer(
|
||||
withTranslation(["SelectFolder", "Common", "Translations"])(
|
||||
SelectFolderModalDialog
|
||||
SelectFolderDialog
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
class SelectFolderDialog extends React.Component {
|
||||
static getCommonThirdPartyList = async () => {
|
||||
const commonThirdPartyArray = await getCommonThirdPartyList();
|
||||
|
||||
commonThirdPartyArray.map((currentValue, index) => {
|
||||
commonThirdPartyArray[index].key = `0-${index}`;
|
||||
});
|
||||
|
||||
return commonThirdPartyArray;
|
||||
};
|
||||
|
||||
static getCommonFolders = async () => {
|
||||
const commonFolders = await getCommonFolderList();
|
||||
|
||||
const convertedData = {
|
||||
id: commonFolders.current.id,
|
||||
key: 0 - 1,
|
||||
parentId: commonFolders.current.parentId,
|
||||
title: commonFolders.current.title,
|
||||
rootFolderType: +commonFolders.current.rootFolderType,
|
||||
rootFolderName: "@common",
|
||||
folders: commonFolders.folders.map((folder) => {
|
||||
return {
|
||||
id: folder.id,
|
||||
title: folder.title,
|
||||
access: folder.access,
|
||||
foldersCount: folder.foldersCount,
|
||||
rootFolderType: folder.rootFolderType,
|
||||
providerKey: folder.providerKey,
|
||||
newItems: folder.new,
|
||||
};
|
||||
}),
|
||||
pathParts: commonFolders.pathParts,
|
||||
foldersCount: commonFolders.current.foldersCount,
|
||||
newItems: commonFolders.new,
|
||||
};
|
||||
|
||||
return [convertedData];
|
||||
};
|
||||
|
||||
static getFolderPath = async (folderId) => {
|
||||
const foldersArray = await getFolderPath(folderId);
|
||||
const convertFoldersArray = SelectFolderInput.setFullFolderPath(
|
||||
foldersArray
|
||||
);
|
||||
|
||||
return convertFoldersArray;
|
||||
};
|
||||
static convertPathParts = (pathParts) => {
|
||||
let newPathParts = [];
|
||||
for (let i = 0; i < pathParts.length - 1; i++) {
|
||||
if (typeof pathParts[i] === "number") {
|
||||
newPathParts.push(String(pathParts[i]));
|
||||
} else {
|
||||
newPathParts.push(pathParts[i]);
|
||||
}
|
||||
}
|
||||
return newPathParts;
|
||||
};
|
||||
static convertFolders = (folders, arrayOfExceptions) => {
|
||||
let newArray = [];
|
||||
|
||||
let noSubfoldersCount = 0;
|
||||
let needHideSwitcher = false;
|
||||
for (let i = 0; i < folders.length; i++) {
|
||||
if (!arrayOfExceptions.includes(folders[i].rootFolderType)) {
|
||||
newArray.push(folders[i]);
|
||||
|
||||
if (
|
||||
folders[i].foldersCount === 0 ||
|
||||
folders[i].rootFolderType === FolderType.Privacy
|
||||
) {
|
||||
noSubfoldersCount += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (newArray.length === noSubfoldersCount) {
|
||||
needHideSwitcher = true;
|
||||
}
|
||||
return [newArray, needHideSwitcher];
|
||||
};
|
||||
|
||||
render() {
|
||||
return (
|
||||
<MobxProvider auth={authStore} {...stores}>
|
||||
<I18nextProvider i18n={i18n}>
|
||||
<SelectFolderDialogWrapper {...this.props} />
|
||||
</I18nextProvider>
|
||||
</MobxProvider>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default SelectFolderDialog;
|
||||
|
@ -0,0 +1,28 @@
|
||||
import React from "react";
|
||||
import { Provider as MobxProvider } from "mobx-react";
|
||||
import { I18nextProvider } from "react-i18next";
|
||||
import stores from "../../../store/index";
|
||||
import store from "studio/store";
|
||||
import SelectFolderInput from "./index";
|
||||
import i18n from "./i18n";
|
||||
const { auth: authStore } = store;
|
||||
|
||||
const SelectFolderModalWrapper = (props) => <SelectFolderInput {...props} />;
|
||||
|
||||
class SelectFolderInputWrapper extends React.Component {
|
||||
componentDidMount() {
|
||||
authStore.init(true);
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<MobxProvider auth={authStore} {...stores}>
|
||||
<I18nextProvider i18n={i18n}>
|
||||
<SelectFolderModalWrapper {...this.props} />
|
||||
</I18nextProvider>
|
||||
</MobxProvider>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default SelectFolderInputWrapper;
|
@ -0,0 +1,35 @@
|
||||
import i18n from "i18next";
|
||||
import Backend from "i18next-http-backend";
|
||||
import { LANGUAGE } from "@appserver/common/constants";
|
||||
import config from "../../../../package.json";
|
||||
import { loadLanguagePath } from "@appserver/common/utils";
|
||||
|
||||
const newInstance = i18n.createInstance();
|
||||
|
||||
newInstance.use(Backend).init({
|
||||
lng: localStorage.getItem(LANGUAGE) || "en",
|
||||
fallbackLng: "en",
|
||||
load: "currentOnly",
|
||||
//debug: true,
|
||||
|
||||
interpolation: {
|
||||
escapeValue: false, // not needed for react as it escapes by default
|
||||
format: function (value, format) {
|
||||
if (format === "lowercase") return value.toLowerCase();
|
||||
return value;
|
||||
},
|
||||
},
|
||||
|
||||
backend: {
|
||||
loadPath: loadLanguagePath(config.homepage),
|
||||
},
|
||||
|
||||
ns: ["SelectFolder"],
|
||||
defaultNS: "SelectFolder",
|
||||
|
||||
react: {
|
||||
useSuspense: false,
|
||||
},
|
||||
});
|
||||
|
||||
export default newInstance;
|
@ -1,204 +1,229 @@
|
||||
import React from "react";
|
||||
import { Provider as MobxProvider, inject, observer } from "mobx-react";
|
||||
|
||||
import { inject, observer } from "mobx-react";
|
||||
import PropTypes from "prop-types";
|
||||
|
||||
import stores from "../../../store/index";
|
||||
import SelectFolderDialog from "../SelectFolderDialog/index";
|
||||
import StyledComponent from "./StyledSelectFolderInput";
|
||||
import { getFolderPath } from "@appserver/common/api/files";
|
||||
import toastr from "@appserver/components/toast/toastr";
|
||||
import SelectFolderDialog from "../SelectFolderDialog";
|
||||
import SimpleFileInput from "../../SimpleFileInput";
|
||||
|
||||
let path = "";
|
||||
|
||||
class SelectFolderInputBody extends React.PureComponent {
|
||||
import { withTranslation } from "react-i18next";
|
||||
import SelectionPanel from "../SelectionPanel/SelectionPanelBody";
|
||||
class SelectFolderInput extends React.PureComponent {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
const { id, foldersType } = this.props;
|
||||
|
||||
const isNeedLoader =
|
||||
!!id || foldersType !== "third-party" || foldersType === "common";
|
||||
|
||||
this.state = {
|
||||
isLoading: false,
|
||||
isLoading: isNeedLoader,
|
||||
baseFolderPath: "",
|
||||
fullFolderPath: "",
|
||||
newFolderPath: "",
|
||||
resultingFolderTree: [],
|
||||
baseId: "",
|
||||
};
|
||||
}
|
||||
componentDidMount() {
|
||||
const { folderPath, setFirstLoad } = this.props;
|
||||
|
||||
if (folderPath.length !== 0) {
|
||||
this.setState({
|
||||
fullFolderPath: folderPath,
|
||||
});
|
||||
}
|
||||
async componentDidMount() {
|
||||
const {
|
||||
setFirstLoad,
|
||||
treeFolders,
|
||||
foldersType,
|
||||
id,
|
||||
onSelectFolder,
|
||||
foldersList,
|
||||
} = this.props;
|
||||
|
||||
setFirstLoad(false);
|
||||
|
||||
let resultingFolderTree, resultingId;
|
||||
|
||||
try {
|
||||
[
|
||||
resultingFolderTree,
|
||||
resultingId,
|
||||
] = await SelectionPanel.getBasicFolderInfo(
|
||||
treeFolders,
|
||||
foldersType,
|
||||
id,
|
||||
this.onSetBaseFolderPath,
|
||||
onSelectFolder,
|
||||
foldersList
|
||||
);
|
||||
} catch (e) {
|
||||
toastr.error(e);
|
||||
return;
|
||||
}
|
||||
|
||||
this.setState({
|
||||
resultingFolderTree,
|
||||
baseId: resultingId,
|
||||
});
|
||||
}
|
||||
|
||||
componentDidUpdate(prevProps) {
|
||||
const { isSuccessSave, isReset } = this.props;
|
||||
const { fullFolderPath, baseFolderPath } = this.state;
|
||||
const { isSuccessSave, isReset, setFolderId, id } = this.props;
|
||||
const { newFolderPath, baseFolderPath, baseId } = this.state;
|
||||
|
||||
if (isSuccessSave && isSuccessSave !== prevProps.isSuccessSave) {
|
||||
fullFolderPath &&
|
||||
newFolderPath &&
|
||||
this.setState({
|
||||
baseFolderPath: fullFolderPath,
|
||||
baseFolderPath: newFolderPath,
|
||||
});
|
||||
}
|
||||
|
||||
if (isReset && isReset !== prevProps.isReset) {
|
||||
setFolderId(baseId !== id && id ? id : baseId);
|
||||
|
||||
this.setState({
|
||||
fullFolderPath: baseFolderPath,
|
||||
newFolderPath: baseFolderPath,
|
||||
});
|
||||
}
|
||||
}
|
||||
setFolderPath = async (folderId) => {
|
||||
const foldersArray = await getFolderPath(folderId);
|
||||
|
||||
onSetFullPath = (pathName) => {
|
||||
const convertFolderPath = (foldersArray) => {
|
||||
let path = "";
|
||||
if (foldersArray.length > 1) {
|
||||
for (let item of foldersArray) {
|
||||
if (!path) {
|
||||
path = path + `${item.title}`;
|
||||
} else path = path + " " + "/" + " " + `${item.title}`;
|
||||
}
|
||||
} else {
|
||||
for (let item of foldersArray) {
|
||||
path = `${item.title}`;
|
||||
}
|
||||
}
|
||||
return path;
|
||||
};
|
||||
|
||||
const convertFoldersArray = convertFolderPath(foldersArray);
|
||||
|
||||
return convertFoldersArray;
|
||||
};
|
||||
onSetNewFolderPath = async (folderId) => {
|
||||
let timerId = setTimeout(() => {
|
||||
this.setState({ isLoading: true });
|
||||
}, 500);
|
||||
|
||||
try {
|
||||
const convertFoldersArray = await this.setFolderPath(folderId);
|
||||
clearTimeout(timerId);
|
||||
timerId = null;
|
||||
|
||||
this.setState({
|
||||
newFolderPath: convertFoldersArray,
|
||||
isLoading: false,
|
||||
});
|
||||
} catch (e) {
|
||||
toastr.error(e);
|
||||
clearTimeout(timerId);
|
||||
timerId = null;
|
||||
|
||||
this.setState({
|
||||
isLoading: false,
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
onSetBaseFolderPath = async (folderId) => {
|
||||
try {
|
||||
const convertFoldersArray = await this.setFolderPath(folderId);
|
||||
|
||||
this.setState({
|
||||
baseFolderPath: convertFoldersArray,
|
||||
isLoading: false,
|
||||
});
|
||||
} catch (e) {
|
||||
toastr.error(e);
|
||||
this.setState({
|
||||
isLoading: false,
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
onSetLoadingInput = (isLoading) => {
|
||||
this.setState({
|
||||
fullFolderPath: pathName,
|
||||
isLoading,
|
||||
});
|
||||
};
|
||||
|
||||
onSetBaseFolderPath = (pathName) => {
|
||||
this.setState({
|
||||
baseFolderPath: pathName,
|
||||
});
|
||||
};
|
||||
|
||||
onSetLoadingInput = (loading) => {
|
||||
this.setState({
|
||||
isLoading: loading,
|
||||
});
|
||||
};
|
||||
render() {
|
||||
const {
|
||||
name,
|
||||
isLoading,
|
||||
baseFolderPath,
|
||||
newFolderPath,
|
||||
baseId,
|
||||
resultingFolderTree,
|
||||
} = this.state;
|
||||
const {
|
||||
onClickInput,
|
||||
isPanelVisible,
|
||||
withoutProvider,
|
||||
onClose,
|
||||
isError,
|
||||
isSavingProcess,
|
||||
isDisabled,
|
||||
onSelectFolder,
|
||||
onSetLoadingData,
|
||||
foldersType,
|
||||
folderPath,
|
||||
isNeedArrowIcon,
|
||||
isSetFolderImmediately,
|
||||
id,
|
||||
selectedFolderId,
|
||||
displayType,
|
||||
dialogWithFiles,
|
||||
modalHeightContent,
|
||||
asideHeightContent,
|
||||
zIndex,
|
||||
showButtons,
|
||||
header,
|
||||
headerName,
|
||||
footer,
|
||||
selectionButtonPrimary,
|
||||
fontSizeInput,
|
||||
t,
|
||||
placeholder,
|
||||
maxInputWidth,
|
||||
isReset,
|
||||
foldersList,
|
||||
isDisabled,
|
||||
isPanelVisible,
|
||||
id,
|
||||
theme,
|
||||
isFolderTreeLoading = false,
|
||||
...rest
|
||||
} = this.props;
|
||||
const { isLoading, baseFolderPath, fullFolderPath } = this.state;
|
||||
|
||||
const passedId = baseId !== id && id ? id : baseId;
|
||||
|
||||
return (
|
||||
<StyledComponent maxInputWidth={maxInputWidth} theme={theme}>
|
||||
<StyledComponent maxWidth={maxInputWidth}>
|
||||
<SimpleFileInput
|
||||
theme={theme}
|
||||
name={name}
|
||||
className="select-folder_file-input"
|
||||
textField={fullFolderPath || baseFolderPath}
|
||||
isDisabled={isLoading || isSavingProcess || isDisabled}
|
||||
textField={newFolderPath || baseFolderPath}
|
||||
isError={isError}
|
||||
onClickInput={onClickInput}
|
||||
fontSizeInput={fontSizeInput}
|
||||
maxInputWidth={maxInputWidth}
|
||||
placeholder={placeholder}
|
||||
isDisabled={isFolderTreeLoading || isDisabled || isLoading}
|
||||
/>
|
||||
|
||||
<SelectFolderDialog
|
||||
theme={theme}
|
||||
zIndex={zIndex}
|
||||
isPanelVisible={isPanelVisible}
|
||||
onClose={onClose}
|
||||
folderPath={folderPath}
|
||||
onSelectFolder={onSelectFolder}
|
||||
onSetLoadingData={onSetLoadingData}
|
||||
foldersType={foldersType}
|
||||
withoutProvider={withoutProvider}
|
||||
onSetFullPath={this.onSetFullPath}
|
||||
onSetBaseFolderPath={this.onSetBaseFolderPath}
|
||||
onSetLoadingInput={this.onSetLoadingInput}
|
||||
isNeedArrowIcon={isNeedArrowIcon}
|
||||
isSetFolderImmediately={isSetFolderImmediately}
|
||||
id={id}
|
||||
selectedFolderId={selectedFolderId}
|
||||
displayType={displayType}
|
||||
dialogWithFiles={dialogWithFiles}
|
||||
modalHeightContent={modalHeightContent}
|
||||
asideHeightContent={asideHeightContent}
|
||||
showButtons={showButtons}
|
||||
header={header}
|
||||
headerName={headerName}
|
||||
footer={footer}
|
||||
selectionButtonPrimary={selectionButtonPrimary}
|
||||
isReset={isReset}
|
||||
foldersList={foldersList}
|
||||
/>
|
||||
{!isFolderTreeLoading && isPanelVisible && (
|
||||
<SelectFolderDialog
|
||||
{...rest}
|
||||
withInput={true}
|
||||
folderTree={resultingFolderTree}
|
||||
id={passedId}
|
||||
isPanelVisible={isPanelVisible}
|
||||
onSetBaseFolderPath={this.onSetBaseFolderPath}
|
||||
onSetNewFolderPath={this.onSetNewFolderPath}
|
||||
/>
|
||||
)}
|
||||
</StyledComponent>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
SelectFolderInputBody.propTypes = {
|
||||
SelectFolderInput.propTypes = {
|
||||
onClickInput: PropTypes.func.isRequired,
|
||||
onClose: PropTypes.func.isRequired,
|
||||
onSelectFolder: PropTypes.func.isRequired,
|
||||
onSetLoadingData: PropTypes.func,
|
||||
isPanelVisible: PropTypes.bool.isRequired,
|
||||
name: PropTypes.string,
|
||||
withoutProvider: PropTypes.bool,
|
||||
isError: PropTypes.bool,
|
||||
isSavingProcess: PropTypes.bool,
|
||||
hasError: PropTypes.bool,
|
||||
isDisabled: PropTypes.bool,
|
||||
placeholder: PropTypes.string,
|
||||
};
|
||||
|
||||
SelectFolderInputBody.defaultProps = {
|
||||
withoutProvider: false,
|
||||
SelectFolderInput.defaultProps = {
|
||||
hasError: false,
|
||||
isDisabled: false,
|
||||
isError: false,
|
||||
folderPath: "",
|
||||
placeholder: "",
|
||||
};
|
||||
|
||||
const SelectFolderInputBodyWrapper = inject(({ filesStore }) => {
|
||||
const { setFirstLoad } = filesStore;
|
||||
return {
|
||||
setFirstLoad,
|
||||
};
|
||||
})(observer(SelectFolderInputBody));
|
||||
class SelectFolderInput extends React.Component {
|
||||
static setFullFolderPath = (foldersArray) => {
|
||||
path = "";
|
||||
if (foldersArray.length > 1) {
|
||||
for (let item of foldersArray) {
|
||||
if (!path) {
|
||||
path = path + `${item.title}`;
|
||||
} else path = path + " " + "/" + " " + `${item.title}`;
|
||||
}
|
||||
} else {
|
||||
for (let item of foldersArray) {
|
||||
path = `${item.title}`;
|
||||
}
|
||||
}
|
||||
return path;
|
||||
};
|
||||
render() {
|
||||
return (
|
||||
<MobxProvider {...stores}>
|
||||
<SelectFolderInputBodyWrapper {...this.props} />
|
||||
</MobxProvider>
|
||||
);
|
||||
export default inject(
|
||||
({ filesStore, treeFoldersStore, selectFolderDialogStore }) => {
|
||||
const { setFirstLoad } = filesStore;
|
||||
const { treeFolders } = treeFoldersStore;
|
||||
const { setFolderId } = selectFolderDialogStore;
|
||||
return {
|
||||
setFirstLoad,
|
||||
treeFolders,
|
||||
setFolderId,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
export default SelectFolderInput;
|
||||
)(observer(withTranslation("Translations")(SelectFolderInput)));
|
||||
|
@ -1,4 +1,4 @@
|
||||
import React, { useCallback, useEffect, useRef } from "react";
|
||||
import React, { useCallback, useEffect, useRef, useState } from "react";
|
||||
import Loader from "@appserver/components/loader";
|
||||
import Text from "@appserver/components/text";
|
||||
import { useTranslation, withTranslation } from "react-i18next";
|
||||
@ -9,152 +9,163 @@ import { FixedSizeList as List } from "react-window";
|
||||
import { inject, observer } from "mobx-react";
|
||||
import FilesListRow from "./FilesListRow";
|
||||
import EmptyContainer from "../../EmptyContainer/EmptyContainer";
|
||||
import i18n from "./i18n";
|
||||
import { StyledItemsLoader } from "../SelectionPanel/StyledSelectionPanel";
|
||||
import Loaders from "@appserver/common/components/Loaders";
|
||||
import { I18nextProvider } from "react-i18next";
|
||||
let countLoad;
|
||||
|
||||
let countLoad, timerId;
|
||||
const FilesListBody = ({
|
||||
filesList,
|
||||
files,
|
||||
onSelectFile,
|
||||
loadNextPage,
|
||||
hasNextPage,
|
||||
isNextPageLoading,
|
||||
displayType,
|
||||
viewer,
|
||||
listHeight,
|
||||
needRowSelection,
|
||||
loadingText,
|
||||
selectedFolder,
|
||||
isMultiSelect,
|
||||
selectedFile,
|
||||
folderId,
|
||||
fileId,
|
||||
theme,
|
||||
page,
|
||||
folderSelection,
|
||||
getIcon,
|
||||
}) => {
|
||||
const { t } = useTranslation(["SelectFile", "Common"]);
|
||||
const [isLoading, setIsLoading] = useState(false);
|
||||
|
||||
const filesListRef = useRef(null);
|
||||
if (page === 0) {
|
||||
countLoad = 0;
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
countLoad = 0;
|
||||
return () => {
|
||||
clearTimeout(timerId);
|
||||
timerId = null;
|
||||
};
|
||||
}, []);
|
||||
useEffect(() => {
|
||||
if (filesListRef && filesListRef.current) {
|
||||
filesListRef.current.resetloadMoreItemsCache(true);
|
||||
}
|
||||
}, [selectedFolder, displayType]);
|
||||
}, [folderId, page, displayType]);
|
||||
|
||||
useEffect(() => {
|
||||
if (isNextPageLoading) {
|
||||
timerId = setTimeout(() => {
|
||||
setIsLoading(true);
|
||||
}, 500);
|
||||
} else {
|
||||
isLoading && setIsLoading(false);
|
||||
clearTimeout(timerId);
|
||||
timerId = null;
|
||||
}
|
||||
}, [isNextPageLoading]);
|
||||
|
||||
// If there are more items to be loaded then add an extra row to hold a loading indicator.
|
||||
const itemCount = hasNextPage ? files.length + 1 : files.length;
|
||||
|
||||
// Every row is loaded except for our loading indicator row.
|
||||
const isItemLoaded = useCallback(
|
||||
(index) => {
|
||||
return !hasNextPage || index < filesList.length;
|
||||
const isLoaded = !hasNextPage || index < files.length;
|
||||
if (isLoaded) {
|
||||
clearTimeout(timerId);
|
||||
timerId = null;
|
||||
}
|
||||
return isLoaded;
|
||||
},
|
||||
[filesList, hasNextPage]
|
||||
[files, hasNextPage]
|
||||
);
|
||||
// If there are more items to be loaded then add an extra row to hold a loading indicator.
|
||||
const itemCount = hasNextPage ? filesList.length + 1 : filesList.length;
|
||||
|
||||
const loadMoreItems = useCallback(() => {
|
||||
if (folderId && page == 0 && isNextPageLoading) {
|
||||
|
||||
loadNextPage && loadNextPage();
|
||||
return;
|
||||
}
|
||||
|
||||
if (isNextPageLoading) return;
|
||||
countLoad++;
|
||||
loadNextPage && loadNextPage();
|
||||
}, [isNextPageLoading, filesList, displayType]);
|
||||
|
||||
const renderPageLoader = useCallback(
|
||||
(style) => {
|
||||
return (
|
||||
<div style={style}>
|
||||
<div
|
||||
key="loader"
|
||||
className="panel-loader-wrapper loader-wrapper_margin"
|
||||
>
|
||||
<Loader
|
||||
theme={theme}
|
||||
type="oval"
|
||||
size="16px"
|
||||
className="panel-loader"
|
||||
/>
|
||||
<Text theme={theme} as="span">
|
||||
{loadingText}
|
||||
</Text>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
},
|
||||
[loadingText]
|
||||
);
|
||||
folderId && loadNextPage && loadNextPage();
|
||||
}, [isNextPageLoading, files, displayType, folderId]);
|
||||
|
||||
const renderPageLoader = (style) => {
|
||||
return (
|
||||
<div style={style}>
|
||||
<StyledItemsLoader key="loader">
|
||||
<Loader
|
||||
theme={theme}
|
||||
type="oval"
|
||||
size="16px"
|
||||
className="panel-loader"
|
||||
/>
|
||||
<Text theme={theme} as="span">
|
||||
{t("Common:LoadingProcessing")} {t("Common:LoadingDescription")}
|
||||
</Text>
|
||||
</StyledItemsLoader>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
const renderFirstLoader = useCallback(
|
||||
(style) => {
|
||||
return (
|
||||
<div style={style}>
|
||||
<div
|
||||
key="loader"
|
||||
className="panel-loader-wrapper loader-wrapper_margin"
|
||||
>
|
||||
<Loaders.Rows
|
||||
theme={theme}
|
||||
style={{
|
||||
marginBottom: displayType === "aside" ? "24px" : "26px",
|
||||
marginTop: displayType === "aside" ? "8px" : "10px",
|
||||
}}
|
||||
count={displayType === "aside" ? 12 : 5}
|
||||
/>
|
||||
<div className="selection-panel_loader" key="loader">
|
||||
{isLoading ? <Loaders.ListLoader withoutFirstRectangle /> : <></>}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
},
|
||||
[loadingText]
|
||||
[isLoading]
|
||||
);
|
||||
|
||||
const isFileChecked = useCallback(
|
||||
(file) => {
|
||||
const checked = selectedFile ? file.id === selectedFile.id : false;
|
||||
(id) => {
|
||||
const checked = fileId ? id === fileId : false;
|
||||
return checked;
|
||||
},
|
||||
[selectedFile]
|
||||
[fileId]
|
||||
);
|
||||
|
||||
const Item = useCallback(
|
||||
({ index, style }) => {
|
||||
const isLoaded = isItemLoaded(index);
|
||||
|
||||
if (!isLoaded) {
|
||||
if (countLoad >= 1) return renderPageLoader(style);
|
||||
if (!isLoaded || !folderId) {
|
||||
if (countLoad >= 1) {
|
||||
return renderPageLoader(style);
|
||||
}
|
||||
|
||||
return renderFirstLoader(style);
|
||||
}
|
||||
|
||||
const file = filesList[index];
|
||||
const fileName = file.title;
|
||||
const fileExst = file.fileExst;
|
||||
const modifyFileName = fileName.substring(
|
||||
0,
|
||||
fileName.indexOf(`${fileExst}`)
|
||||
);
|
||||
|
||||
const fileOwner =
|
||||
file.createdBy &&
|
||||
((viewer.id === file.createdBy.id && t("Common:MeLabel")) ||
|
||||
file.createdBy.displayName);
|
||||
|
||||
const isChecked = isFileChecked(file);
|
||||
const item = files[index];
|
||||
const isChecked = folderSelection ? false : isFileChecked(item.id);
|
||||
|
||||
return (
|
||||
<div style={style}>
|
||||
<FilesListRow
|
||||
theme={theme}
|
||||
displayType={displayType}
|
||||
needRowSelection={needRowSelection}
|
||||
index={index}
|
||||
onSelectFile={onSelectFile}
|
||||
fileName={modifyFileName}
|
||||
fileExst={fileExst}
|
||||
isMultiSelect={isMultiSelect}
|
||||
item={item}
|
||||
isChecked={isChecked}
|
||||
>
|
||||
<Text data-index={index} className="files-list_file-owner">
|
||||
{fileOwner}
|
||||
</Text>
|
||||
</FilesListRow>
|
||||
folderSelection={folderSelection}
|
||||
icon={getIcon(
|
||||
32,
|
||||
item.fileExst,
|
||||
item.providerKey,
|
||||
item.contentLength
|
||||
)}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
},
|
||||
[filesList, selectedFile, displayType, renderFirstLoader, renderPageLoader]
|
||||
[files, fileId, displayType, renderFirstLoader, renderPageLoader]
|
||||
);
|
||||
return (
|
||||
<div className="files-list-body">
|
||||
<div className="selection-panel_files-list-body">
|
||||
<AutoSizer>
|
||||
{({ width, height }) => (
|
||||
<InfiniteLoader
|
||||
@ -167,9 +178,9 @@ const FilesListBody = ({
|
||||
{({ onItemsRendered, ref }) => (
|
||||
<List
|
||||
theme={theme}
|
||||
height={displayType === "aside" ? height : listHeight}
|
||||
height={height}
|
||||
itemCount={itemCount}
|
||||
itemSize={displayType === "aside" ? 56 : 50}
|
||||
itemSize={48}
|
||||
onItemsRendered={onItemsRendered}
|
||||
ref={ref}
|
||||
width={width + 8}
|
||||
@ -187,7 +198,7 @@ const FilesListBody = ({
|
||||
<EmptyContainer
|
||||
theme={theme}
|
||||
headerText={t("Home:EmptyFolderHeader")}
|
||||
imageSrc="/static/images/empty_screen.png"
|
||||
imageSrc="/static/images/empty.screen.react.svg"
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
@ -198,21 +209,12 @@ FilesListBody.defaultProps = {
|
||||
listHeight: 300,
|
||||
isMultiSelect: false,
|
||||
};
|
||||
const FilesListBodyWrapper = inject(({ auth }) => {
|
||||
|
||||
export default inject(({ auth, settingsStore }) => {
|
||||
const { user } = auth.userStore;
|
||||
const { getIcon } = settingsStore;
|
||||
return {
|
||||
viewer: user,
|
||||
getIcon,
|
||||
};
|
||||
})(observer(withTranslation(["Common", "Home"])(FilesListBody)));
|
||||
|
||||
class FilesList extends React.Component {
|
||||
render() {
|
||||
return (
|
||||
<I18nextProvider i18n={i18n}>
|
||||
<FilesListBodyWrapper {...this.props} />
|
||||
</I18nextProvider>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default FilesList;
|
@ -0,0 +1,54 @@
|
||||
import React from "react";
|
||||
import { StyledRow } from "./StyledSelectionPanel";
|
||||
import Text from "@appserver/components/text";
|
||||
import RadioButton from "@appserver/components/radio-button";
|
||||
import ItemIcon from "../../ItemIcon";
|
||||
const FilesListRow = ({
|
||||
displayType,
|
||||
index,
|
||||
onSelectFile,
|
||||
isChecked,
|
||||
theme,
|
||||
folderSelection,
|
||||
icon,
|
||||
item,
|
||||
}) => {
|
||||
const { id, fileExst, title } = item;
|
||||
const element = <ItemIcon id={id} icon={icon} fileExst={fileExst} />;
|
||||
|
||||
const onFileClick = () => {
|
||||
onSelectFile && onSelectFile(item, index);
|
||||
};
|
||||
return (
|
||||
<StyledRow
|
||||
displayType={displayType}
|
||||
theme={theme}
|
||||
isChecked={isChecked}
|
||||
folderSelection={folderSelection}
|
||||
>
|
||||
<div className="selection-panel_icon">{element}</div>
|
||||
<div className="selection-panel_text">
|
||||
<Text fontSize="14px" fontWeight={600}>
|
||||
{title}
|
||||
</Text>
|
||||
</div>
|
||||
<div className="selection-panel_checkbox">
|
||||
{!folderSelection && (
|
||||
<RadioButton
|
||||
//theme={theme}
|
||||
fontSize="13px"
|
||||
fontWeight="400"
|
||||
name={`${index}`}
|
||||
label=""
|
||||
isChecked={isChecked}
|
||||
onClick={onFileClick}
|
||||
value=""
|
||||
className="select-file-dialog_checked"
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
</StyledRow>
|
||||
);
|
||||
};
|
||||
|
||||
export default FilesListRow;
|
@ -0,0 +1,151 @@
|
||||
import React from "react";
|
||||
import { inject, observer } from "mobx-react";
|
||||
import toastr from "studio/toastr";
|
||||
import FilesListBody from "./FilesListBody";
|
||||
import axios from "axios";
|
||||
import { combineUrl, getFolderOptions } from "@appserver/common/utils";
|
||||
import AppServerConfig from "@appserver/common/constants/AppServerConfig";
|
||||
|
||||
class FilesListWrapper extends React.Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
const { newFilter } = this.props;
|
||||
this.newFilter = newFilter;
|
||||
|
||||
this.state = {
|
||||
isNextPageLoading: false,
|
||||
page: 0,
|
||||
hasNextPage: true,
|
||||
files: [],
|
||||
};
|
||||
}
|
||||
|
||||
componentDidUpdate(prevProps) {
|
||||
const { folderId } = this.props;
|
||||
const { isNextPageLoading } = this.state;
|
||||
|
||||
if (folderId !== prevProps.folderId) {
|
||||
if (isNextPageLoading) {
|
||||
this.source.cancel();
|
||||
|
||||
this._isLoadNextPage = false;
|
||||
this.setState({
|
||||
isNextPageLoading: false,
|
||||
});
|
||||
}
|
||||
this.setState({
|
||||
page: 0,
|
||||
files: [],
|
||||
hasNextPage: true,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
_loadNextPage = () => {
|
||||
const { files, page } = this.state;
|
||||
const {
|
||||
folderId,
|
||||
setFolderTitle,
|
||||
setProviderKey,
|
||||
setFolderId,
|
||||
folderSelection,
|
||||
} = this.props;
|
||||
|
||||
if (this._isLoadNextPage) return;
|
||||
|
||||
const pageCount = 30;
|
||||
this.newFilter.page = page;
|
||||
this.newFilter.pageCount = pageCount;
|
||||
this._isLoadNextPage = true;
|
||||
this.setState({ isNextPageLoading: true }, async () => {
|
||||
try {
|
||||
this.CancelToken = axios.CancelToken;
|
||||
this.source = this.CancelToken.source();
|
||||
const options = getFolderOptions(folderId, this.newFilter);
|
||||
|
||||
const response = await axios
|
||||
.get(combineUrl(AppServerConfig.apiPrefixURL, options.url), {
|
||||
cancelToken: this.source.token,
|
||||
})
|
||||
.catch((thrown) => {
|
||||
if (axios.isCancel(thrown)) {
|
||||
console.log("Request canceled", thrown.message);
|
||||
} else {
|
||||
console.error(thrown);
|
||||
}
|
||||
return;
|
||||
});
|
||||
if (!response) return;
|
||||
const data = response.data.response;
|
||||
|
||||
if (page === 0 && folderSelection) {
|
||||
setFolderTitle(data.current.title);
|
||||
setProviderKey(data.current.providerKey);
|
||||
setFolderId(folderId);
|
||||
}
|
||||
|
||||
const finalData = [...data.files];
|
||||
const newFilesList = [...files].concat(finalData);
|
||||
const hasNextPage = newFilesList.length < data.total - 1;
|
||||
this._isLoadNextPage = false;
|
||||
this.setState((state) => ({
|
||||
hasNextPage: hasNextPage,
|
||||
isNextPageLoading: false,
|
||||
page: state.page + 1,
|
||||
files: newFilesList,
|
||||
}));
|
||||
} catch (e) {
|
||||
toastr.error(e);
|
||||
}
|
||||
});
|
||||
};
|
||||
render() {
|
||||
const {
|
||||
t,
|
||||
theme,
|
||||
onSelectFile,
|
||||
folderSelection = false,
|
||||
fileId,
|
||||
folderId,
|
||||
} = this.props;
|
||||
const { hasNextPage, isNextPageLoading, files, page } = this.state;
|
||||
|
||||
return (
|
||||
<FilesListBody
|
||||
theme={theme}
|
||||
files={files}
|
||||
onSelectFile={onSelectFile}
|
||||
hasNextPage={hasNextPage}
|
||||
isNextPageLoading={isNextPageLoading}
|
||||
loadNextPage={this._loadNextPage}
|
||||
folderId={folderId}
|
||||
displayType={"modal"}
|
||||
folderSelection={folderSelection}
|
||||
fileId={fileId}
|
||||
page={page}
|
||||
/>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default inject(
|
||||
({ selectedFolderStore, selectFolderDialogStore, auth }) => {
|
||||
const { id } = selectedFolderStore;
|
||||
const {
|
||||
setFolderId,
|
||||
setFolderTitle,
|
||||
setProviderKey,
|
||||
} = selectFolderDialogStore;
|
||||
|
||||
const { settingsStore } = auth;
|
||||
const { theme } = settingsStore;
|
||||
|
||||
return {
|
||||
theme: theme,
|
||||
storeFolderId: id,
|
||||
setFolderId,
|
||||
setFolderTitle,
|
||||
setProviderKey,
|
||||
};
|
||||
}
|
||||
)(observer(FilesListWrapper));
|
@ -0,0 +1,278 @@
|
||||
import React from "react";
|
||||
import ModalDialog from "@appserver/components/modal-dialog";
|
||||
import FolderTreeBody from "../../FolderTreeBody";
|
||||
import Button from "@appserver/components/button";
|
||||
import FilesListWrapper from "./FilesListWrapper";
|
||||
import {
|
||||
getCommonFoldersTree,
|
||||
getFolder,
|
||||
getFoldersTree,
|
||||
getThirdPartyCommonFolderTree,
|
||||
} from "@appserver/common/api/files";
|
||||
import toastr from "studio/toastr";
|
||||
import {
|
||||
exceptSortedByTagsFolders,
|
||||
exceptPrivacyTrashFolders,
|
||||
} from "./ExceptionFoldersConstants";
|
||||
import { StyledBody, StyledModalDialog } from "./StyledSelectionPanel";
|
||||
import Text from "@appserver/components/text";
|
||||
import Loaders from "@appserver/common/components/Loaders";
|
||||
const SelectionPanelBody = ({
|
||||
t,
|
||||
isPanelVisible,
|
||||
onClose,
|
||||
withoutProvider,
|
||||
onSelectFile,
|
||||
filesListTitle,
|
||||
dialogName,
|
||||
primaryButtonName,
|
||||
theme,
|
||||
isLoading,
|
||||
onButtonClick,
|
||||
folderId,
|
||||
onSelectFolder,
|
||||
resultingFolderTree,
|
||||
isAvailable,
|
||||
footer,
|
||||
header,
|
||||
folderSelection = false,
|
||||
folderTitle,
|
||||
fileId,
|
||||
canCreate = true,
|
||||
isLoadingData,
|
||||
expandedKeys,
|
||||
isDisableTree,
|
||||
page,
|
||||
newFilter,
|
||||
isDisableButton,
|
||||
}) => {
|
||||
const onMouseEvent = (event) => {
|
||||
event.stopPropagation();
|
||||
};
|
||||
|
||||
return (
|
||||
<div onMouseUp={onMouseEvent} onMouseDown={onMouseEvent}>
|
||||
<StyledModalDialog
|
||||
theme={theme}
|
||||
visible={isPanelVisible}
|
||||
onClose={onClose}
|
||||
className="select-file-modal-dialog"
|
||||
style={{ maxWidth: "773px" }}
|
||||
displayType="modal"
|
||||
modalBodyPadding="0px"
|
||||
isLoading={isLoading}
|
||||
>
|
||||
<ModalDialog.Header theme={theme}>{dialogName}</ModalDialog.Header>
|
||||
<ModalDialog.Body
|
||||
theme={theme}
|
||||
className="select-file_body-modal-dialog"
|
||||
>
|
||||
<StyledBody header={!!header} footer={!!footer}>
|
||||
<div className="selection-panel_body">
|
||||
<div className="selection-panel_tree-body">
|
||||
<Text
|
||||
fontWeight="700"
|
||||
fontSize="18px"
|
||||
className="selection-panel_folder-title"
|
||||
>
|
||||
{t("Translations:Documents")}
|
||||
</Text>
|
||||
|
||||
{folderId && resultingFolderTree ? (
|
||||
<FolderTreeBody
|
||||
theme={theme}
|
||||
folderTree={resultingFolderTree}
|
||||
onSelect={onSelectFolder}
|
||||
withoutProvider={withoutProvider}
|
||||
certainFolders
|
||||
isAvailable={isAvailable}
|
||||
selectedKeys={[`${folderId}`]}
|
||||
expandedKeys={expandedKeys}
|
||||
isDisableTree={isDisableTree}
|
||||
displayType="modal"
|
||||
/>
|
||||
) : (
|
||||
<Loaders.NewTreeFolders />
|
||||
)}
|
||||
</div>
|
||||
<div className="selection-panel_files-body">
|
||||
<>
|
||||
<div className="selection-panel_files-header">
|
||||
{header}
|
||||
|
||||
<Text
|
||||
color="#A3A9AE"
|
||||
theme={theme}
|
||||
className="selection-panel_title"
|
||||
>
|
||||
{folderSelection
|
||||
? t("FolderContents", { folderTitle })
|
||||
: filesListTitle}
|
||||
</Text>
|
||||
</div>
|
||||
|
||||
<FilesListWrapper
|
||||
theme={theme}
|
||||
onSelectFile={onSelectFile}
|
||||
folderId={folderId}
|
||||
displayType={"modal"}
|
||||
folderSelection={folderSelection}
|
||||
newFilter={newFilter}
|
||||
fileId={fileId}
|
||||
/>
|
||||
</>
|
||||
</div>
|
||||
|
||||
<div className="selection-panel_footer">
|
||||
<div>{footer}</div>
|
||||
|
||||
<div className="selection-panel_buttons">
|
||||
<Button
|
||||
theme={theme}
|
||||
className="select-file-modal-dialog-buttons-save"
|
||||
primary
|
||||
size="normalTouchscreen"
|
||||
label={primaryButtonName}
|
||||
onClick={onButtonClick}
|
||||
isDisabled={
|
||||
isDisableButton ||
|
||||
isDisableTree ||
|
||||
isLoadingData ||
|
||||
(!fileId && !folderSelection) ||
|
||||
!canCreate
|
||||
}
|
||||
isLoading={isDisableTree}
|
||||
/>
|
||||
<Button
|
||||
theme={theme}
|
||||
className="modal-dialog-button"
|
||||
size="normalTouchscreen"
|
||||
label={t("Common:CancelButton")}
|
||||
onClick={onClose}
|
||||
isDisabled={isLoadingData}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</StyledBody>
|
||||
</ModalDialog.Body>
|
||||
</StyledModalDialog>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
class SelectionPanel extends React.Component {
|
||||
static getFolderPath = async (id) => {
|
||||
try {
|
||||
const data = await getFolder(id);
|
||||
const newPathParts = data.pathParts.map((item) => item.toString());
|
||||
|
||||
+newPathParts[newPathParts.length - 1] === +id && newPathParts.pop();
|
||||
|
||||
return newPathParts;
|
||||
} catch (e) {
|
||||
toastr.error(e);
|
||||
return null;
|
||||
}
|
||||
};
|
||||
static getBasicFolderInfo = async (
|
||||
treeFolders,
|
||||
foldersType,
|
||||
id,
|
||||
onSetBaseFolderPath,
|
||||
onSelectFolder,
|
||||
foldersList,
|
||||
isFilesPanel = false
|
||||
) => {
|
||||
const getRequestFolderTree = () => {
|
||||
switch (foldersType) {
|
||||
case "exceptSortedByTags":
|
||||
case "exceptPrivacyTrashFolders":
|
||||
try {
|
||||
return getFoldersTree();
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
}
|
||||
break;
|
||||
case "common":
|
||||
try {
|
||||
return getCommonFoldersTree();
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
}
|
||||
break;
|
||||
|
||||
case "third-party":
|
||||
try {
|
||||
return getThirdPartyCommonFolderTree();
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
}
|
||||
break;
|
||||
}
|
||||
};
|
||||
|
||||
const filterFoldersTree = (folders, arrayOfExceptions) => {
|
||||
let newArray = [];
|
||||
|
||||
for (let i = 0; i < folders.length; i++) {
|
||||
if (!arrayOfExceptions.includes(folders[i].rootFolderType)) {
|
||||
newArray.push(folders[i]);
|
||||
}
|
||||
}
|
||||
|
||||
return newArray;
|
||||
};
|
||||
|
||||
const getExceptionsFolders = (treeFolders) => {
|
||||
switch (foldersType) {
|
||||
case "exceptSortedByTags":
|
||||
return filterFoldersTree(treeFolders, exceptSortedByTagsFolders);
|
||||
case "exceptPrivacyTrashFolders":
|
||||
return filterFoldersTree(treeFolders, exceptPrivacyTrashFolders);
|
||||
}
|
||||
};
|
||||
|
||||
let requestedTreeFolders, filteredTreeFolders;
|
||||
|
||||
const treeFoldersLength = treeFolders.length;
|
||||
|
||||
if (treeFoldersLength === 0) {
|
||||
try {
|
||||
requestedTreeFolders = foldersList
|
||||
? foldersList
|
||||
: await getRequestFolderTree();
|
||||
} catch (e) {
|
||||
toastr.error(e);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
const foldersTree =
|
||||
treeFoldersLength > 0 ? treeFolders : requestedTreeFolders;
|
||||
|
||||
const passedId = id ? id : foldersTree[0].id;
|
||||
|
||||
if (foldersType === "third-party") {
|
||||
isFilesPanel && onSetBaseFolderPath && onSetBaseFolderPath(passedId);
|
||||
} else {
|
||||
onSetBaseFolderPath && onSetBaseFolderPath(passedId);
|
||||
}
|
||||
|
||||
onSelectFolder && onSelectFolder(passedId);
|
||||
|
||||
if (
|
||||
foldersType === "exceptSortedByTags" ||
|
||||
foldersType === "exceptPrivacyTrashFolders"
|
||||
) {
|
||||
filteredTreeFolders = getExceptionsFolders(foldersTree);
|
||||
}
|
||||
|
||||
return [filteredTreeFolders || foldersTree, passedId];
|
||||
};
|
||||
render() {
|
||||
return <SelectionPanelBody {...this.props} />;
|
||||
}
|
||||
}
|
||||
|
||||
export default SelectionPanel;
|
@ -0,0 +1,284 @@
|
||||
import styled, { css } from "styled-components";
|
||||
import ModalDialog from "@appserver/components/modal-dialog";
|
||||
const commonStyles = css`
|
||||
.empty-folder_container {
|
||||
grid-template-areas:
|
||||
"img img"
|
||||
"headerText headerText";
|
||||
grid-template-rows: 72px 1fr;
|
||||
|
||||
padding-bottom: 0;
|
||||
|
||||
.ec-image {
|
||||
margin: auto;
|
||||
}
|
||||
.ec-header {
|
||||
margin: auto;
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
const StyledModalDialog = styled(ModalDialog)`
|
||||
.heading {
|
||||
line-height: 52px;
|
||||
font-size: 21px;
|
||||
}
|
||||
.modal-dialog-aside-header {
|
||||
height: 53px;
|
||||
}
|
||||
`;
|
||||
|
||||
const StyledBody = styled.div`
|
||||
.selection-panel_body {
|
||||
height: 495px;
|
||||
display: grid;
|
||||
grid-template-columns: 245px 1fr;
|
||||
grid-template-areas: "tree files" "footer footer";
|
||||
grid-template-rows: auto max-content;
|
||||
margin-right: -4px;
|
||||
|
||||
.selection-panel_files-body {
|
||||
grid-area: files;
|
||||
display: grid;
|
||||
grid-template-rows: max-content auto;
|
||||
}
|
||||
.selection-panel_files-list-body {
|
||||
height: 100%;
|
||||
}
|
||||
.selection-panel_tree-body {
|
||||
grid-area: tree;
|
||||
height: 100%;
|
||||
border-right: 1px solid #eceef1;
|
||||
|
||||
display: grid;
|
||||
grid-template-rows: max-content auto;
|
||||
|
||||
.selection-panel_folder-title {
|
||||
padding: 12px 20px 14px 0px;
|
||||
}
|
||||
.selection-panel_tree-folder {
|
||||
margin-left: -12px;
|
||||
}
|
||||
|
||||
.span.rc-tree-switcher {
|
||||
padding-left: 16px;
|
||||
}
|
||||
}
|
||||
|
||||
.selection-panel_files-header {
|
||||
padding: 16px;
|
||||
word-break: break-word;
|
||||
.selection-panel_title {
|
||||
${(props) => props.header && "padding-top: 16px"};
|
||||
}
|
||||
}
|
||||
.selection-panel_footer {
|
||||
grid-area: footer;
|
||||
border-top: 1px solid ${(props) => props.theme.row.borderBottom};
|
||||
margin-left: -13px;
|
||||
margin-right: -7px;
|
||||
padding-left: 16px;
|
||||
|
||||
padding-top: 16px;
|
||||
|
||||
.selection-panel_buttons {
|
||||
${(props) => props.footer && "margin-top:16px"};
|
||||
button:first-child {
|
||||
margin-right: 8px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
${commonStyles}
|
||||
`;
|
||||
|
||||
const StyledRow = styled.div`
|
||||
display: grid;
|
||||
grid-template-columns: 32px auto 32px;
|
||||
grid-gap: 8px;
|
||||
position: relative;
|
||||
height: 48px;
|
||||
width: calc(100% - 16px);
|
||||
|
||||
padding-left: 16px;
|
||||
|
||||
${(props) =>
|
||||
props.isChecked && `background: ${props.theme.row.backgroundColor}`};
|
||||
|
||||
.selection-panel_clicked-area {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
cursor: pointer;
|
||||
}
|
||||
.selection-panel_text {
|
||||
margin-top: auto;
|
||||
margin-bottom: 16px;
|
||||
overflow: hidden;
|
||||
p {
|
||||
text-overflow: ellipsis;
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
}
|
||||
}
|
||||
.selection-panel_icon,
|
||||
.selection-panel_checkbox {
|
||||
margin: auto 0;
|
||||
}
|
||||
|
||||
.selection-panel_icon {
|
||||
svg {
|
||||
path {
|
||||
fill: #a3a9ae;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
${(props) =>
|
||||
props.folderSelection &&
|
||||
css`
|
||||
.selection-panel_icon {
|
||||
::after {
|
||||
position: absolute;
|
||||
display: block;
|
||||
background-color: #f3f4f4;
|
||||
border-top-right-radius: 50%;
|
||||
left: 18px;
|
||||
top: 6px;
|
||||
width: 27px;
|
||||
height: 32px;
|
||||
content: "";
|
||||
opacity: 0.7;
|
||||
}
|
||||
}
|
||||
.selection-panel_text p {
|
||||
color: ${(props) => props.theme.text.disableColor};
|
||||
}
|
||||
`}
|
||||
`;
|
||||
|
||||
const StyledAsideBody = styled.div`
|
||||
height: 100%;
|
||||
|
||||
.selection-panel_aside-body {
|
||||
height: calc(100% - 32px);
|
||||
display: grid;
|
||||
grid-template-rows: max-content auto max-content;
|
||||
}
|
||||
.selection-panel_files-list-body {
|
||||
height: 100%;
|
||||
margin-left: -16px;
|
||||
margin-right: -6px;
|
||||
}
|
||||
.selection-panel_files {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.selection-panel_aside-header {
|
||||
div:first-child {
|
||||
${(props) => props.header && " margin-bottom: 12px;"}
|
||||
}
|
||||
}
|
||||
.selection-panel_aside-folder-title {
|
||||
margin-top: 12px;
|
||||
}
|
||||
.selection-panel_folder-selection-title {
|
||||
margin-bottom: 4px;
|
||||
}
|
||||
.selection-panel_aside-tree {
|
||||
margin-top: 12px;
|
||||
margin-left: -16px;
|
||||
margin-right: -16px;
|
||||
}
|
||||
|
||||
.selection-panel_aside-title {
|
||||
padding-bottom: 16px;
|
||||
}
|
||||
|
||||
.selection-panel_aside-footer {
|
||||
border-top: 1px solid ${(props) => props.theme.row.borderBottom};
|
||||
margin-left: -13px;
|
||||
margin-right: -13px;
|
||||
padding-left: 16px;
|
||||
padding-right: 16px;
|
||||
padding-top: 16px;
|
||||
padding-bottom: 12px;
|
||||
|
||||
.selection-panel_aside-buttons {
|
||||
${(props) => props.footer && "margin-top:16px"};
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1fr;
|
||||
|
||||
button:first-child {
|
||||
margin-right: 8px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
${commonStyles}
|
||||
`;
|
||||
|
||||
const StyledAsideHeader = styled.div`
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
.selection-panel_aside-header-icon {
|
||||
margin-right: 16px;
|
||||
}
|
||||
`;
|
||||
|
||||
const StyledTree = styled.div`
|
||||
height: 100%;
|
||||
|
||||
.files-tree-menu {
|
||||
margin-top: 0 !important;
|
||||
margin-bottom: 22px;
|
||||
}
|
||||
.selection-panel_tree-folder {
|
||||
height: 100%;
|
||||
}
|
||||
#folder-tree-scroll-bar {
|
||||
.nav-thumb-horizontal {
|
||||
height: 0px !important;
|
||||
}
|
||||
|
||||
${(props) =>
|
||||
props.displayType === "modal" &&
|
||||
css`
|
||||
.nav-thumb-vertical {
|
||||
margin-left: 4px !important;
|
||||
width: 4px !important;
|
||||
}
|
||||
`}
|
||||
|
||||
.scroll-body {
|
||||
overflow-x: hidden !important;
|
||||
}
|
||||
}
|
||||
|
||||
.selection-panel_empty-folder {
|
||||
margin-top: 12px;
|
||||
margin-left: 12px;
|
||||
}
|
||||
`;
|
||||
|
||||
const StyledItemsLoader = styled.div`
|
||||
display: flex;
|
||||
.panel-loader {
|
||||
margin-left: 16px;
|
||||
margin-right: 8px;
|
||||
}
|
||||
`;
|
||||
|
||||
export {
|
||||
StyledBody,
|
||||
StyledRow,
|
||||
StyledAsideBody,
|
||||
StyledAsideHeader,
|
||||
StyledTree,
|
||||
StyledModalDialog,
|
||||
StyledItemsLoader,
|
||||
};
|
@ -649,350 +649,6 @@ const StyledLinkRow = styled.div`
|
||||
|
||||
StyledLinkRow.defaultProps = { theme: Base };
|
||||
|
||||
const StyledSelectFolderPanel = styled.div`
|
||||
${(props) =>
|
||||
props.displayType === "aside" &&
|
||||
css`
|
||||
height: 100%;
|
||||
`}
|
||||
|
||||
${(props) =>
|
||||
props.noTreeSwitcher &&
|
||||
css`
|
||||
span.rc-tree-switcher.rc-tree-switcher-noop {
|
||||
display: none;
|
||||
}
|
||||
`}
|
||||
|
||||
|
||||
|
||||
.modal-dialog_header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
.select-folder-modal-dialog-header {
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
.modal-dialog_header-title {
|
||||
${(props) => props.isNeedArrowIcon && `margin-left:16px;`}
|
||||
}
|
||||
.select-folder-dialog_tree-folder {
|
||||
margin-top: 12px;
|
||||
height: ${(props) => (props.displayType === "aside" ? "100%" : "291px")};
|
||||
}
|
||||
|
||||
.select-folder-dialog-buttons-save {
|
||||
margin-right: 8px;
|
||||
}
|
||||
.select-folder-dialog-modal_buttons {
|
||||
margin-top: 16px;
|
||||
}
|
||||
|
||||
.select-folder-dialog_header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
.select-folder-dialog_header-icon {
|
||||
margin-right: 16px;
|
||||
}
|
||||
.select-folder-dialog_aside_body {
|
||||
height: ${(props) =>
|
||||
props.isFooter ? "calc(100% - 110px)" : "calc(100% - 64px)"};
|
||||
width: 296px;
|
||||
}
|
||||
#folder-tree-scroll-bar {
|
||||
.nav-thumb-horizontal {
|
||||
height: 0px !important;
|
||||
}
|
||||
|
||||
${(props) =>
|
||||
props.displayType === "modal" &&
|
||||
css`
|
||||
.nav-thumb-vertical {
|
||||
margin-left: 4px !important;
|
||||
width: 4px !important;
|
||||
}
|
||||
`}
|
||||
|
||||
.scroll-body {
|
||||
overflow-x: hidden !important;
|
||||
}
|
||||
}
|
||||
.tree-folder-Loader {
|
||||
${(props) =>
|
||||
props.displayType === "aside"
|
||||
? css`
|
||||
margin-top: 16px;
|
||||
`
|
||||
: css`
|
||||
height: ${props.heightContent};
|
||||
`}
|
||||
}
|
||||
|
||||
.files-tree-menu {
|
||||
margin-top: 0 !important;
|
||||
}
|
||||
`;
|
||||
|
||||
const StyledSelectFilePanel = styled.div`
|
||||
height: 100%;
|
||||
${(props) =>
|
||||
props.noTreeSwitcher &&
|
||||
css`
|
||||
span.rc-tree-switcher.rc-tree-switcher-noop {
|
||||
display: none;
|
||||
}
|
||||
`}
|
||||
|
||||
.files-list-body {
|
||||
height: 100%;
|
||||
${(props) =>
|
||||
props.displayType === "aside" &&
|
||||
css`
|
||||
margin-left: -16px;
|
||||
margin-right: -16px;
|
||||
.nav-thumb-vertical {
|
||||
margin-left: -7px !important;
|
||||
}
|
||||
`}
|
||||
|
||||
${(props) =>
|
||||
props.displayType === "modal" &&
|
||||
css`
|
||||
.nav-thumb-vertical {
|
||||
margin-left: 4px !important;
|
||||
width: 4px !important;
|
||||
}
|
||||
`}
|
||||
}
|
||||
.select-file-dialog_aside_body-files_list {
|
||||
height: 100%;
|
||||
}
|
||||
.select-file-dialog_empty-container {
|
||||
.ec-header {
|
||||
word-break: break-word;
|
||||
}
|
||||
}
|
||||
|
||||
.modal-dialog-filter-title {
|
||||
margin-top: 12px;
|
||||
${(props) => props.displayType === "modal" && `margin-left: 12px`};
|
||||
margin-bottom: 12px;
|
||||
font-size: 12px;
|
||||
line-height: 16px;
|
||||
color: ${(props) => props.theme.filesPanels.selectFile.borderRight};
|
||||
}
|
||||
.select-file-dialog-modal_buttons {
|
||||
${(props) =>
|
||||
props.isHeaderChildren ? "margin-top: 20px" : "margin-top:20px"};
|
||||
}
|
||||
.select-file-dialog_aside-body_wrapper {
|
||||
height: calc(100% - 109px);
|
||||
}
|
||||
|
||||
.select-folder-dialog_aside-body_wrapper {
|
||||
width: 320px;
|
||||
box-sizing: border-box;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.select-file-dialog_aside_body,
|
||||
.select-file-dialog_aside_body_files-list {
|
||||
height: 100%;
|
||||
width: 293px;
|
||||
}
|
||||
.select-file-dialog_aside_body_files-list {
|
||||
margin-left: -17px;
|
||||
padding-left: 16px;
|
||||
${(props) =>
|
||||
props.isChecked &&
|
||||
`background: ${(props) => props.theme.filesPanels.selectFile.background}`}
|
||||
}
|
||||
|
||||
.file-name {
|
||||
border-bottom: ${(props) =>
|
||||
props.theme.filesPanels.selectFile.borderBottom};
|
||||
}
|
||||
.file-name {
|
||||
display: flex;
|
||||
padding: 7px 0px;
|
||||
}
|
||||
.panel-loader-wrapper {
|
||||
.first-row-content__mobile {
|
||||
width: ${(props) => (props.displayType === "aside" ? "147px" : "234px")};
|
||||
height: ${(props) => (props.displayType === "aside" ? "16px" : "10px")};
|
||||
}
|
||||
|
||||
@media ${desktop} {
|
||||
.second-row-content__mobile {
|
||||
max-width: 185px;
|
||||
height: 8px;
|
||||
display: block;
|
||||
}
|
||||
.row-content {
|
||||
grid-template-rows: 10px;
|
||||
grid-row-gap: 6px;
|
||||
margin-top: -3px;
|
||||
}
|
||||
}
|
||||
|
||||
.second-row-content__mobile {
|
||||
width: 229px;
|
||||
}
|
||||
}
|
||||
.loader-wrapper_margin {
|
||||
margin-left: ${(props) =>
|
||||
props.displayType === "aside" ? "16px" : "12px"};
|
||||
}
|
||||
.select-file-dialog_modal-loader {
|
||||
height: 290px;
|
||||
padding-top: 16px;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
.panel-loader {
|
||||
display: inline;
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
.modal-dialog_tree-body {
|
||||
grid-area: tree;
|
||||
}
|
||||
.modal-dialog_files-body {
|
||||
grid-area: files-list;
|
||||
}
|
||||
|
||||
.modal-dialog_body {
|
||||
display: grid;
|
||||
grid-template-columns: 228px 477px;
|
||||
height: 295px;
|
||||
grid-template-areas: "tree files-list";
|
||||
.modal-dialog_tree-body {
|
||||
padding-top: 0;
|
||||
border-right: ${(props) =>
|
||||
props.theme.filesPanels.selectFile.borderRight};
|
||||
|
||||
span.rc-tree-title {
|
||||
max-width: ${(props) =>
|
||||
props.displayType === "aside" ? "243px" : "181px"};
|
||||
}
|
||||
}
|
||||
}
|
||||
.select-file-dialog-aside_buttons {
|
||||
position: fixed;
|
||||
bottom: 0;
|
||||
padding-top: 8px;
|
||||
background-color: ${(props) =>
|
||||
props.theme.filesPanels.selectFile.buttonsBackground};
|
||||
height: 40px;
|
||||
width: 100%;
|
||||
}
|
||||
.select-file-dialog-buttons-save {
|
||||
margin-right: 8px;
|
||||
}
|
||||
.select-file-modal-dialog-buttons-save {
|
||||
margin-right: 8px;
|
||||
}
|
||||
.select-folder-dialog-buttons-save {
|
||||
margin-right: 8px;
|
||||
}
|
||||
.select-folder-dialog-modal_buttons {
|
||||
margin-top: 8px;
|
||||
}
|
||||
`;
|
||||
|
||||
StyledSelectFilePanel.defaultProps = { theme: Base };
|
||||
|
||||
const StyledFilesList = styled.div`
|
||||
.select-file-dialog_icon {
|
||||
margin-right: 8px;
|
||||
}
|
||||
|
||||
.radio-button_text{
|
||||
${(props) => props.displayType === "aside" && "margin: 0 !important;"};
|
||||
}
|
||||
|
||||
.entry-title {
|
||||
font-weight: 600;
|
||||
max-width: 100%;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
.files-list_file-owner {
|
||||
max-width: ${(props) =>
|
||||
props.displayType === "aside" ? "213px" : "406px"};
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
text-overflow: ellipsis;
|
||||
color: ${(props) => props.theme.filesPanels.filesList.color};
|
||||
font-weight: 600;
|
||||
|
||||
${(props) => props.displayType === "modal" && ` font-size: 11px;`}
|
||||
|
||||
height: ${(props) => (props.displayType === "aside" ? "16px" : "12px")};
|
||||
padding-bottom: ${(props) =>
|
||||
props.displayType === "aside" ? "10px" : "11px"};
|
||||
}
|
||||
.file-exst {
|
||||
color: ${(props) => props.theme.filesPanels.filesList.color};
|
||||
font-weight: 600;
|
||||
}
|
||||
.modal-dialog_file-name:hover {
|
||||
background-color: ${(props) =>
|
||||
props.theme.filesPanels.filesList.backgroundColor};
|
||||
}
|
||||
.files-list_full-name {
|
||||
white-space: nowrap;
|
||||
text-overflow: ellipsis;
|
||||
overflow: hidden;
|
||||
max-width: ${(props) => props.displayType === "aside" && "213px"};
|
||||
|
||||
grid-area: full-name;
|
||||
display: flex;
|
||||
padding-top: 10px;
|
||||
}
|
||||
.select-file-dialog_icon {
|
||||
grid-area: icon-name;
|
||||
padding-top: 12px;
|
||||
}
|
||||
.select-file-dialog_checked {
|
||||
grid-area: checked-button;
|
||||
}
|
||||
.files-list_file-children_wrapper {
|
||||
grid-area: owner-name;
|
||||
margin-top: ${(props) => props.displayType === "modal" && "-8px"};
|
||||
}
|
||||
.modal-dialog_file-name {
|
||||
border-radius: 3px;
|
||||
padding-right: 12px;
|
||||
${(props) =>
|
||||
props.isChecked &&
|
||||
`background: ${props.theme.filesPanels.filesList.backgroundColor};`}
|
||||
cursor: pointer;
|
||||
border-bottom: ${(props) => props.theme.filesPanels.filesList.borderBottom};
|
||||
display: grid;
|
||||
|
||||
${(props) =>
|
||||
props.displayType === "aside"
|
||||
? css`
|
||||
height: 56px;
|
||||
grid-template-areas: "checked-button icon-name full-name" "checked-button icon-name owner-name";
|
||||
`
|
||||
: css`
|
||||
height: 49px;
|
||||
grid-template-areas: "checked-button icon-name full-name" "checked-button icon-name owner-name";
|
||||
`}
|
||||
grid-template-columns: 22px 33px 1fr;
|
||||
${(props) => props.displayType === "modal" && ` grid-row-gap: 4px;`}
|
||||
|
||||
padding-left: ${(props) =>
|
||||
props.displayType === "aside" ? "16px" : "12px"};
|
||||
box-sizing: border-box;
|
||||
}
|
||||
`;
|
||||
|
||||
StyledFilesList.defaultProps = { theme: Base };
|
||||
|
||||
const StyledModalRowContainer = styled.div`
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
@ -1132,8 +788,5 @@ export {
|
||||
StyledSharingBody,
|
||||
StyledFooter,
|
||||
StyledLinkRow,
|
||||
StyledSelectFolderPanel,
|
||||
StyledSelectFilePanel,
|
||||
StyledFilesList,
|
||||
StyledModalRowContainer,
|
||||
};
|
||||
|
@ -76,7 +76,7 @@ const Table = ({
|
||||
<TableBody>
|
||||
{filesList.map((item, index) => (
|
||||
<TableRow
|
||||
key={item.id}
|
||||
key={`${item.id}_${index}`}
|
||||
item={item}
|
||||
index={index}
|
||||
setFirsElemChecked={setFirsElemChecked}
|
||||
|
@ -168,8 +168,8 @@ class FilesActionStore {
|
||||
this.isMediaOpen();
|
||||
|
||||
try {
|
||||
await removeFiles(folderIds, fileIds, deleteAfter, immediately).then(
|
||||
async (res) => {
|
||||
await removeFiles(folderIds, fileIds, deleteAfter, immediately)
|
||||
.then(async (res) => {
|
||||
if (res[0]?.error) return Promise.reject(res[0].error);
|
||||
const data = res[0] ? res[0] : null;
|
||||
const pbData = {
|
||||
@ -199,8 +199,10 @@ class FilesActionStore {
|
||||
return toastr.success(translations.FileRemoved);
|
||||
}
|
||||
return toastr.success(translations.FolderRemoved);
|
||||
}
|
||||
);
|
||||
})
|
||||
.finally(() => {
|
||||
clearActiveOperations(fileIds, folderIds);
|
||||
});
|
||||
} catch (err) {
|
||||
clearActiveOperations(fileIds, folderIds);
|
||||
setSecondaryProgressBarData({
|
||||
|
@ -461,8 +461,12 @@ class FilesStore {
|
||||
clearFilter = true,
|
||||
withSubfolders = false
|
||||
) => {
|
||||
const { treeFolders, setSelectedNode, getSubfolders, selectedTreeNode } =
|
||||
this.treeFoldersStore;
|
||||
const {
|
||||
treeFolders,
|
||||
setSelectedNode,
|
||||
getSubfolders,
|
||||
selectedTreeNode,
|
||||
} = this.treeFoldersStore;
|
||||
const { id } = this.selectedFolderStore;
|
||||
|
||||
const isPrefSettings = isNaN(+selectedTreeNode) && !id;
|
||||
@ -629,8 +633,17 @@ class FilesStore {
|
||||
deselectFile = (file) => {
|
||||
const { id, parentId } = file;
|
||||
const isFileSelected = this.isFileSelected(id, parentId);
|
||||
if (isFileSelected)
|
||||
this.selection = this.selection.filter((x) => x.id !== id);
|
||||
if (isFileSelected) {
|
||||
let selectionIndex = this.selection.findIndex(
|
||||
(x) => x.parentId === parentId && x.id === id
|
||||
);
|
||||
|
||||
if (selectionIndex !== -1) {
|
||||
this.selection = this.selection.filter(
|
||||
(x, index) => index !== selectionIndex
|
||||
);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
removeOptions = (options, toRemoveArray) =>
|
||||
@ -665,8 +678,11 @@ class FilesStore {
|
||||
isMy,
|
||||
} = this.treeFoldersStore;
|
||||
|
||||
const { canWebEdit, canViewedDocs, canFormFillingDocs } =
|
||||
this.filesSettingsStore;
|
||||
const {
|
||||
canWebEdit,
|
||||
canViewedDocs,
|
||||
canFormFillingDocs,
|
||||
} = this.filesSettingsStore;
|
||||
|
||||
const isThirdPartyFolder =
|
||||
item.providerKey && item.id === item.rootFolderId;
|
||||
@ -1433,7 +1449,7 @@ class FilesStore {
|
||||
|
||||
let isFolder = false;
|
||||
this.folders.map((x) => {
|
||||
if (x.id === item.id) isFolder = true;
|
||||
if (x.id === item.id && x.parentId === item.parentId) isFolder = true;
|
||||
});
|
||||
|
||||
const { isRecycleBinFolder } = this.treeFoldersStore;
|
||||
@ -1582,8 +1598,12 @@ class FilesStore {
|
||||
};
|
||||
|
||||
get sortedFiles() {
|
||||
const { extsConvertible, isSpreadsheet, isPresentation, isDocument } =
|
||||
this.filesSettingsStore;
|
||||
const {
|
||||
extsConvertible,
|
||||
isSpreadsheet,
|
||||
isPresentation,
|
||||
isDocument,
|
||||
} = this.filesSettingsStore;
|
||||
|
||||
let sortedFiles = {
|
||||
documents: [],
|
||||
|
@ -1,6 +1,6 @@
|
||||
import { makeObservable, action, observable } from "mobx";
|
||||
|
||||
class SelectedFilesStore {
|
||||
class SelectFileDialogStore {
|
||||
folderId = null;
|
||||
fileInfo = null;
|
||||
|
||||
@ -22,4 +22,4 @@ class SelectedFilesStore {
|
||||
};
|
||||
}
|
||||
|
||||
export default new SelectedFilesStore();
|
||||
export default new SelectFileDialogStore();
|
@ -0,0 +1,36 @@
|
||||
import { makeObservable, action, observable } from "mobx";
|
||||
|
||||
class SelectFolderDialogStore {
|
||||
folderId = null;
|
||||
fileInfo = null;
|
||||
folderTitle = "";
|
||||
providerKey = null;
|
||||
baseFolderPath = "";
|
||||
|
||||
constructor() {
|
||||
makeObservable(this, {
|
||||
fileInfo: observable,
|
||||
folderId: observable,
|
||||
folderTitle: observable,
|
||||
providerKey: observable,
|
||||
|
||||
setFolderId: action,
|
||||
setProviderKey: action,
|
||||
setFolderTitle: action,
|
||||
});
|
||||
}
|
||||
|
||||
setFolderId = (id) => {
|
||||
this.folderId = id;
|
||||
};
|
||||
|
||||
setFolderTitle = (title) => {
|
||||
this.folderTitle = title;
|
||||
};
|
||||
|
||||
setProviderKey = (providerKey) => {
|
||||
this.providerKey = providerKey;
|
||||
};
|
||||
}
|
||||
|
||||
export default new SelectFolderDialogStore();
|
@ -12,11 +12,12 @@ import PrimaryProgressDataStore from "./PrimaryProgressDataStore";
|
||||
|
||||
import VersionHistoryStore from "./VersionHistoryStore";
|
||||
import DialogsStore from "./DialogsStore";
|
||||
import selectedFilesStore from "./SelectedFilesStore";
|
||||
import selectFolderDialogStore from "./SelectFolderDialogStore";
|
||||
import ContextOptionsStore from "./ContextOptionsStore";
|
||||
import HotkeyStore from "./HotkeyStore";
|
||||
import store from "studio/store";
|
||||
import InfoPanelStore from "./InfoPanelStore";
|
||||
import selectFileDialogStore from "./SelectFileDialogStore";
|
||||
|
||||
const selectedFolderStore = new SelectedFolderStore(store.auth.settingsStore);
|
||||
|
||||
@ -30,7 +31,8 @@ const filesStore = new FilesStore(
|
||||
selectedFolderStore,
|
||||
treeFoldersStore,
|
||||
settingsStore,
|
||||
selectedFilesStore
|
||||
selectFolderDialogStore,
|
||||
selectFileDialogStore
|
||||
);
|
||||
const mediaViewerDataStore = new MediaViewerDataStore(
|
||||
filesStore,
|
||||
@ -91,7 +93,6 @@ const hotkeyStore = new HotkeyStore(
|
||||
uploadDataStore
|
||||
);
|
||||
|
||||
//const selectedFilesStore = new SelectedFilesStore(selectedFilesStore);
|
||||
const stores = {
|
||||
filesStore,
|
||||
settingsStore,
|
||||
@ -102,10 +103,11 @@ const stores = {
|
||||
treeFoldersStore,
|
||||
selectedFolderStore,
|
||||
filesActionsStore,
|
||||
selectedFilesStore,
|
||||
selectFolderDialogStore,
|
||||
contextOptionsStore,
|
||||
hotkeyStore,
|
||||
infoPanelStore,
|
||||
selectFileDialogStore,
|
||||
};
|
||||
|
||||
export default stores;
|
||||
|
@ -169,10 +169,14 @@ var config = {
|
||||
"./app": "./src/Files.jsx",
|
||||
"./SharingDialog": "./src/components/panels/SharingDialog",
|
||||
"./utils": "./src/helpers/utils.js",
|
||||
"./SelectFileDialog": "./src/components/panels/SelectFileDialog",
|
||||
"./SelectFolderDialog": "./src/components/panels/SelectFolderDialog",
|
||||
"./SelectFolderInput": "./src/components/panels/SelectFolderInput",
|
||||
"./SelectFileInput": "./src/components/panels/SelectFileInput",
|
||||
"./SelectFileDialog":
|
||||
"./src/components/panels/SelectFileDialog/SelectFileDialogWrapper",
|
||||
"./SelectFileInput":
|
||||
"./src/components/panels/SelectFileInput/SelectFileInputWrapper",
|
||||
"./SelectFolderDialog":
|
||||
"./src/components/panels/SelectFolderDialog/SelectFolderDialogWrapper",
|
||||
"./SelectFolderInput":
|
||||
"./src/components/panels/SelectFolderInput/SelectFolderInputWrapper",
|
||||
},
|
||||
shared: {
|
||||
...deps,
|
||||
|
@ -1401,11 +1401,11 @@ namespace ASC.Files.Core.Data
|
||||
{
|
||||
if (withSubfolders)
|
||||
{
|
||||
result.In(a => a.Folders.Select(r => r.ParentId), new[] { parentId });
|
||||
result.In(a => a.Folders.Select(r => r.FolderId), new[] { parentId });
|
||||
}
|
||||
else
|
||||
{
|
||||
result.InAll(a => a.Folders.Select(r => r.ParentId), new[] { parentId });
|
||||
result.InAll(a => a.Folders.Select(r => r.FolderId), new[] { parentId });
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -777,7 +777,7 @@ ctx.Tag
|
||||
}
|
||||
|
||||
monitorFolderIds = monitorFolderIds.Concat(tempTags.Where(x => x.EntryType == FileEntryType.Folder).Select(x => x.EntryId));
|
||||
result.Concat(tempTags);
|
||||
result = result.Concat(tempTags);
|
||||
}
|
||||
|
||||
var monitorFolderIdsInt = await monitorFolderIds.OfType<int>().ToListAsync();
|
||||
@ -787,13 +787,13 @@ ctx.Tag
|
||||
|
||||
var monitorFolderIdsStrings = await monitorFolderIds.Select(r => r.ToString()).ToListAsync();
|
||||
|
||||
result.Concat(FromQueryAsync(newTagsForFoldersQuery(FilesDbContext, tenantId, subject, monitorFolderIdsStrings)));
|
||||
result = result.Concat(FromQueryAsync(newTagsForFoldersQuery(FilesDbContext, tenantId, subject, monitorFolderIdsStrings)));
|
||||
|
||||
var where = (deepSearch ? await monitorFolderIds.ToArrayAsync().ConfigureAwait(false) : new object[] { parentFolder.ID })
|
||||
.Select(r => r.ToString())
|
||||
.ToList();
|
||||
|
||||
result.Concat(FromQueryAsync(newTagsForFilesQuery(FilesDbContext, tenantId, subject, where)));
|
||||
result = result.Concat(FromQueryAsync(newTagsForFilesQuery(FilesDbContext, tenantId, subject, where)));
|
||||
|
||||
if (parentFolder.FolderType == FolderType.USER || parentFolder.FolderType == FolderType.COMMON)
|
||||
{
|
||||
@ -809,7 +809,7 @@ ctx.Tag
|
||||
|
||||
if (thirdpartyFolderIds.Count > 0)
|
||||
{
|
||||
result.Concat(FromQueryAsync(newTagsForSBoxQuery(FilesDbContext, tenantId, subject, thirdpartyFolderIds)));
|
||||
result = result.Concat(FromQueryAsync(newTagsForSBoxQuery(FilesDbContext, tenantId, subject, thirdpartyFolderIds)));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1601,7 +1601,7 @@ namespace ASC.Web.Files.Services.WCFService
|
||||
{
|
||||
if (sync)
|
||||
{
|
||||
results.Append(await FileConverter.ExecSynchronouslyAsync(file, fileInfo.Password));
|
||||
results = results.Append(await FileConverter.ExecSynchronouslyAsync(file, fileInfo.Password));
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -1999,8 +1999,8 @@ namespace ASC.Web.Files.Services.WCFService
|
||||
|
||||
var fileDao = GetFileDao();
|
||||
var folderDao = GetFolderDao();
|
||||
entries.Concat(filesId.ToAsyncEnumerable().SelectAwait(async fileId => await fileDao.GetFileAsync(fileId)));
|
||||
entries.Concat(foldersId.ToAsyncEnumerable().SelectAwait(async e => await folderDao.GetFolderAsync(e)));
|
||||
entries = entries.Concat(filesId.ToAsyncEnumerable().SelectAwait(async fileId => await fileDao.GetFileAsync(fileId)));
|
||||
entries = entries.Concat(foldersId.ToAsyncEnumerable().SelectAwait(async e => await folderDao.GetFolderAsync(e)));
|
||||
|
||||
|
||||
return FileSharingAceHelper.RemoveAceAsync(entries);
|
||||
@ -2234,16 +2234,16 @@ namespace ASC.Web.Files.Services.WCFService
|
||||
//return new List<string>(accounts);
|
||||
}
|
||||
|
||||
public async IAsyncEnumerable<FileEntry> ChangeOwnerAsync(IEnumerable<T> foldersId, IEnumerable<T> filesId, Guid userId)
|
||||
public async Task<IEnumerable<FileEntry>> ChangeOwnerAsync(IEnumerable<T> foldersId, IEnumerable<T> filesId, Guid userId)
|
||||
{
|
||||
var userInfo = UserManager.GetUsers(userId);
|
||||
ErrorIf(Equals(userInfo, Constants.LostUser) || userInfo.IsVisitor(UserManager), FilesCommonResource.ErrorMassage_ChangeOwner);
|
||||
|
||||
var entries = AsyncEnumerable.Empty<FileEntry>();
|
||||
var entries = new List<FileEntry>();
|
||||
|
||||
var folderDao = GetFolderDao();
|
||||
var folders = folderDao.GetFoldersAsync(foldersId);
|
||||
await foreach (var folder in folders)
|
||||
var folders = await folderDao.GetFoldersAsync(foldersId).ToListAsync();
|
||||
foreach (var folder in folders)
|
||||
{
|
||||
ErrorIf(!await FileSecurity.CanEditAsync(folder), FilesCommonResource.ErrorMassage_SecurityException);
|
||||
ErrorIf(folder.RootFolderType != FolderType.COMMON, FilesCommonResource.ErrorMassage_SecurityException);
|
||||
@ -2262,13 +2262,13 @@ namespace ASC.Web.Files.Services.WCFService
|
||||
|
||||
FilesMessageService.Send(newFolder, GetHttpHeaders(), MessageAction.FileChangeOwner, new[] { newFolder.Title, userInfo.DisplayUserName(false, DisplayUserSettingsHelper) });
|
||||
}
|
||||
entries.Append(newFolder);
|
||||
entries.Add(newFolder);
|
||||
}
|
||||
|
||||
var fileDao = GetFileDao();
|
||||
var files = fileDao.GetFilesAsync(filesId);
|
||||
var files = await fileDao.GetFilesAsync(filesId).ToListAsync();
|
||||
|
||||
await foreach (var file in files)
|
||||
foreach (var file in files)
|
||||
{
|
||||
ErrorIf(!await FileSecurity.CanEditAsync(file), FilesCommonResource.ErrorMassage_SecurityException);
|
||||
ErrorIf(await EntryManager.FileLockedForMeAsync(file.ID), FilesCommonResource.ErrorMassage_LockedFile);
|
||||
@ -2313,13 +2313,10 @@ namespace ASC.Web.Files.Services.WCFService
|
||||
|
||||
FilesMessageService.Send(newFile, GetHttpHeaders(), MessageAction.FileChangeOwner, new[] { newFile.Title, userInfo.DisplayUserName(false, DisplayUserSettingsHelper) });
|
||||
}
|
||||
entries.Append(newFile);
|
||||
entries.Add(newFile);
|
||||
}
|
||||
|
||||
await foreach (var entrie in entries)
|
||||
{
|
||||
yield return entrie;
|
||||
}
|
||||
return entries;
|
||||
}
|
||||
|
||||
public bool StoreOriginal(bool set)
|
||||
|
@ -124,7 +124,7 @@ namespace ASC.Files.Thirdparty.ProviderDao
|
||||
var selectorLocal = selector;
|
||||
var matchedIds = folderIds.Where(selectorLocal.IsMatch).ToList();
|
||||
|
||||
if (matchedIds.Count > 0) continue;
|
||||
if (matchedIds.Count == 0) continue;
|
||||
|
||||
result = result.Concat(matchedIds.GroupBy(selectorLocal.GetIdCode)
|
||||
.ToAsyncEnumerable()
|
||||
|
@ -75,17 +75,13 @@ namespace ASC.Web.Files
|
||||
{
|
||||
public class FileHandler
|
||||
{
|
||||
private IServiceProvider ServiceProvider { get; }
|
||||
|
||||
public FileHandler(RequestDelegate next, IServiceProvider serviceProvider)
|
||||
public FileHandler(RequestDelegate next)
|
||||
{
|
||||
ServiceProvider = serviceProvider;
|
||||
}
|
||||
|
||||
public async Task Invoke(HttpContext context)
|
||||
public async Task Invoke(HttpContext context, FileHandlerService fileHandlerService)
|
||||
{
|
||||
using var scope = ServiceProvider.CreateScope();
|
||||
var fileHandlerService = scope.ServiceProvider.GetService<FileHandlerService>();
|
||||
await fileHandlerService.Invoke(context).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
|
@ -663,7 +663,7 @@ namespace ASC.Web.Files.Utils
|
||||
public Task<Stream> ExecAsync<T>(File<T> file)
|
||||
{
|
||||
return ExecAsync(file, FileUtility.GetInternalExtension(file.Title));
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<Stream> ExecAsync<T>(File<T> file, string toExtension, string password = null)
|
||||
{
|
||||
@ -687,8 +687,8 @@ namespace ASC.Web.Files.Utils
|
||||
var request = new HttpRequestMessage();
|
||||
request.RequestUri = new Uri(convertUri);
|
||||
|
||||
using var httpClient = ClientFactory.CreateClient();
|
||||
using var response = await httpClient.SendAsync(request);
|
||||
var httpClient = ClientFactory.CreateClient();
|
||||
var response = await httpClient.SendAsync(request);
|
||||
return new ResponseStream(response);
|
||||
}
|
||||
|
||||
|
@ -151,29 +151,29 @@ namespace ASC.Web.Files.Utils
|
||||
if (obj.FileEntry.RootFolderType == FolderType.BUNCH)
|
||||
{
|
||||
if (userIDs.Count == 0) return;
|
||||
|
||||
|
||||
var projectsFolder = await GlobalFolder.GetFolderProjectsAsync<T>(DaoFactory);
|
||||
parentFolders.Add(await folderDao.GetFolderAsync(projectsFolder));
|
||||
|
||||
var entries = new List<FileEntry> { obj.FileEntry };
|
||||
entries = entries.Concat(parentFolders).ToList();
|
||||
|
||||
userIDs.ForEach(userID =>
|
||||
userIDs.ForEach(userID =>
|
||||
{
|
||||
if (userEntriesData.TryGetValue(userID, out var value))
|
||||
value.AddRange(entries);
|
||||
else
|
||||
userEntriesData.Add(userID, entries);
|
||||
|
||||
RemoveFromCahce(projectsFolder, userID);
|
||||
userEntriesData.Add(userID, entries);
|
||||
|
||||
RemoveFromCahce(projectsFolder, userID);
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
var filesSecurity = FileSecurity;
|
||||
|
||||
|
||||
if (userIDs.Count == 0)
|
||||
{
|
||||
{
|
||||
var guids = await filesSecurity.WhoCanReadAsync(obj.FileEntry);
|
||||
userIDs = guids.Where(x => x != obj.CurrentAccountId).ToList();
|
||||
}
|
||||
@ -183,7 +183,7 @@ namespace ASC.Web.Files.Utils
|
||||
}
|
||||
|
||||
foreach (var parentFolder in parentFolders)
|
||||
{
|
||||
{
|
||||
var whoCanRead = await filesSecurity.WhoCanReadAsync(parentFolder);
|
||||
var ids = whoCanRead
|
||||
.Where(userID => userIDs.Contains(userID) && userID != obj.CurrentAccountId);
|
||||
@ -199,7 +199,7 @@ namespace ASC.Web.Files.Utils
|
||||
|
||||
if (obj.FileEntry.RootFolderType == FolderType.USER)
|
||||
{
|
||||
var folderDaoInt = DaoFactory.GetFolderDao<int>();
|
||||
var folderDaoInt = DaoFactory.GetFolderDao<int>();
|
||||
var folderShare = await folderDaoInt.GetFolderAsync(await GlobalFolder.GetFolderShareAsync(DaoFactory));
|
||||
|
||||
foreach (var userID in userIDs)
|
||||
@ -232,46 +232,46 @@ namespace ASC.Web.Files.Utils
|
||||
|
||||
RemoveFromCahce(rootFolder.ID, userID);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (obj.FileEntry.RootFolderType == FolderType.COMMON)
|
||||
{
|
||||
{
|
||||
var commonFolderId = await GlobalFolder.GetFolderCommonAsync(this, DaoFactory);
|
||||
userIDs.ForEach(userID => RemoveFromCahce(commonFolderId, userID));
|
||||
|
||||
if (obj.FileEntry.ProviderEntry)
|
||||
{
|
||||
var commonFolder = await folderDao.GetFolderAsync(await GlobalFolder.GetFolderCommonAsync<T>(this, DaoFactory));
|
||||
userIDs.ForEach(userID =>
|
||||
userIDs.ForEach(userID =>
|
||||
{
|
||||
if (userEntriesData.TryGetValue(userID, out var value))
|
||||
value.Add(commonFolder);
|
||||
else
|
||||
userEntriesData.Add(userID, new List<FileEntry> { commonFolder });
|
||||
|
||||
RemoveFromCahce(commonFolderId, userID);
|
||||
userEntriesData.Add(userID, new List<FileEntry> { commonFolder });
|
||||
|
||||
RemoveFromCahce(commonFolderId, userID);
|
||||
});
|
||||
}
|
||||
}
|
||||
else if (obj.FileEntry.RootFolderType == FolderType.Privacy)
|
||||
{
|
||||
foreach (var userID in userIDs)
|
||||
{
|
||||
var privacyFolderId = await folderDao.GetFolderIDPrivacyAsync(false, userID);
|
||||
if (Equals(privacyFolderId, 0)) continue;
|
||||
|
||||
var rootFolder = await folderDao.GetFolderAsync(privacyFolderId);
|
||||
if (rootFolder == null) continue;
|
||||
|
||||
if (userEntriesData.TryGetValue(userID, out var value))
|
||||
value.Add(rootFolder);
|
||||
else
|
||||
userEntriesData.Add(userID, new List<FileEntry> { rootFolder });
|
||||
|
||||
RemoveFromCahce(rootFolder.ID, userID);
|
||||
}
|
||||
}
|
||||
else if (obj.FileEntry.RootFolderType == FolderType.Privacy)
|
||||
{
|
||||
foreach (var userID in userIDs)
|
||||
{
|
||||
var privacyFolderId = await folderDao.GetFolderIDPrivacyAsync(false, userID);
|
||||
if (Equals(privacyFolderId, 0)) continue;
|
||||
|
||||
var rootFolder = await folderDao.GetFolderAsync(privacyFolderId);
|
||||
if (rootFolder == null) continue;
|
||||
|
||||
if (userEntriesData.TryGetValue(userID, out var value))
|
||||
value.Add(rootFolder);
|
||||
else
|
||||
userEntriesData.Add(userID, new List<FileEntry> { rootFolder });
|
||||
|
||||
RemoveFromCahce(rootFolder.ID, userID);
|
||||
}
|
||||
}
|
||||
|
||||
userIDs.ForEach(userID =>
|
||||
userIDs.ForEach(userID =>
|
||||
{
|
||||
if (userEntriesData.TryGetValue(userID, out var value))
|
||||
value.Add(obj.FileEntry);
|
||||
@ -291,49 +291,49 @@ namespace ASC.Web.Files.Utils
|
||||
|
||||
var entries = userEntriesData[userID].Distinct().ToList();
|
||||
|
||||
await GetNewTagsAsync(userID, entries.OfType<FileEntry<int>>().ToList());
|
||||
await GetNewTagsAsync(userID, entries.OfType<FileEntry<int>>().ToList());
|
||||
await GetNewTagsAsync(userID, entries.OfType<FileEntry<string>>().ToList());
|
||||
}
|
||||
|
||||
if (updateTags.Count > 0)
|
||||
{
|
||||
tagDao.UpdateNewTags(updateTags);
|
||||
}
|
||||
if (updateTags.Count > 0)
|
||||
{
|
||||
tagDao.UpdateNewTags(updateTags);
|
||||
}
|
||||
|
||||
if (newTags.Count > 0)
|
||||
{
|
||||
tagDao.SaveTags(newTags);
|
||||
}
|
||||
|
||||
async Task GetNewTagsAsync<T1>(Guid userID, List<FileEntry<T1>> entries)
|
||||
{
|
||||
var tagDao1 = DaoFactory.GetTagDao<T1>();
|
||||
if (newTags.Count > 0)
|
||||
{
|
||||
tagDao.SaveTags(newTags);
|
||||
}
|
||||
|
||||
async Task GetNewTagsAsync<T1>(Guid userID, List<FileEntry<T1>> entries)
|
||||
{
|
||||
var tagDao1 = DaoFactory.GetTagDao<T1>();
|
||||
var exist = await tagDao1.GetNewTagsAsync(userID, entries).ToListAsync();
|
||||
var update = exist.Where(t => t.EntryType == FileEntryType.Folder).ToList();
|
||||
update.ForEach(t => t.Count++);
|
||||
updateTags.AddRange(update);
|
||||
|
||||
entries.ForEach(entry =>
|
||||
{
|
||||
if (entry != null && exist.All(tag => tag != null && !tag.EntryId.Equals(entry.ID)))
|
||||
{
|
||||
newTags.Add(Tag.New(userID, entry));
|
||||
}
|
||||
entries.ForEach(entry =>
|
||||
{
|
||||
if (entry != null && exist.All(tag => tag != null && !tag.EntryId.Equals(entry.ID)))
|
||||
{
|
||||
newTags.Add(Tag.New(userID, entry));
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public Task MarkAsNewAsync<T>(FileEntry<T> fileEntry, List<Guid> userIDs = null)
|
||||
{
|
||||
if (CoreBaseSettings.Personal) return Task.CompletedTask;
|
||||
|
||||
if (fileEntry == null) return Task.CompletedTask;
|
||||
|
||||
if (fileEntry == null) return Task.CompletedTask;
|
||||
|
||||
return InternalMarkAsNewAsync(fileEntry, userIDs);
|
||||
}
|
||||
|
||||
private async Task InternalMarkAsNewAsync<T>(FileEntry<T> fileEntry, List<Guid> userIDs = null)
|
||||
{
|
||||
}
|
||||
|
||||
private async Task InternalMarkAsNewAsync<T>(FileEntry<T> fileEntry, List<Guid> userIDs = null)
|
||||
{
|
||||
userIDs ??= new List<Guid>();
|
||||
|
||||
var taskData = ServiceProvider.GetService<AsyncTaskData<T>>();
|
||||
@ -347,7 +347,7 @@ namespace ASC.Web.Files.Utils
|
||||
|
||||
var projectID = path.Split('/').Last();
|
||||
if (string.IsNullOrEmpty(projectID)) return;
|
||||
|
||||
|
||||
var whoCanRead = await FileSecurity.WhoCanReadAsync(fileEntry);
|
||||
var projectTeam = whoCanRead.Where(x => x != AuthContext.CurrentAccount.ID).ToList();
|
||||
|
||||
@ -356,33 +356,32 @@ namespace ASC.Web.Files.Utils
|
||||
taskData.UserIDs = projectTeam;
|
||||
}
|
||||
|
||||
ServiceProvider.GetService<FileMarkerHelper<T>>().Add(taskData);
|
||||
}
|
||||
|
||||
ServiceProvider.GetService<FileMarkerHelper<T>>().Add(taskData);
|
||||
}
|
||||
|
||||
public Task RemoveMarkAsNewAsync<T>(FileEntry<T> fileEntry, Guid userID = default)
|
||||
{
|
||||
if (CoreBaseSettings.Personal) return Task.CompletedTask;
|
||||
|
||||
if (fileEntry == null) return Task.CompletedTask;
|
||||
|
||||
if (fileEntry == null) return Task.CompletedTask;
|
||||
|
||||
return InternalRemoveMarkAsNewAsync(fileEntry, userID);
|
||||
}
|
||||
|
||||
public async Task InternalRemoveMarkAsNewAsync<T>(FileEntry<T> fileEntry, Guid userID = default)
|
||||
{
|
||||
userID = userID.Equals(default) ? AuthContext.CurrentAccount.ID : userID;
|
||||
}
|
||||
|
||||
public async Task InternalRemoveMarkAsNewAsync<T>(FileEntry<T> fileEntry, Guid userID = default)
|
||||
{
|
||||
userID = userID.Equals(default) ? AuthContext.CurrentAccount.ID : userID;
|
||||
|
||||
var tagDao = DaoFactory.GetTagDao<T>();
|
||||
var internalFolderDao = DaoFactory.GetFolderDao<int>();
|
||||
var folderDao = DaoFactory.GetFolderDao<T>();
|
||||
var internalFolderDao = DaoFactory.GetFolderDao<int>();
|
||||
var folderDao = DaoFactory.GetFolderDao<T>();
|
||||
|
||||
if (!await tagDao.GetNewTagsAsync(userID, fileEntry).AnyAsync()) return;
|
||||
|
||||
|
||||
T folderID;
|
||||
int valueNew;
|
||||
var userFolderIdTask = internalFolderDao.GetFolderIDUserAsync(false, userID);
|
||||
var privacyFolderIdTask = internalFolderDao.GetFolderIDPrivacyAsync(false, userID);
|
||||
var userFolderId = await userFolderIdTask;
|
||||
var userFolderId = await internalFolderDao.GetFolderIDUserAsync(false, userID);
|
||||
var privacyFolderId = await internalFolderDao.GetFolderIDPrivacyAsync(false, userID);
|
||||
|
||||
var removeTags = new List<Tag>();
|
||||
|
||||
@ -417,8 +416,6 @@ namespace ASC.Web.Files.Utils
|
||||
|
||||
removeTags.AddRange(listTags);
|
||||
}
|
||||
|
||||
var privacyFolderId = await privacyFolderIdTask;
|
||||
|
||||
var parentFolders = await folderDao.GetParentFoldersAsync(folderID);
|
||||
parentFolders.Reverse();
|
||||
@ -449,20 +446,20 @@ namespace ASC.Web.Files.Utils
|
||||
cacheFolderId = rootFolderId = await GlobalFolder.GetFolderShareAsync(DaoFactory);
|
||||
else
|
||||
cacheFolderId = userFolderId;
|
||||
}
|
||||
else if (rootFolder.RootFolderType == FolderType.Privacy)
|
||||
{
|
||||
if (!Equals(privacyFolderId, 0))
|
||||
{
|
||||
cacheFolderId = rootFolderId = privacyFolderId;
|
||||
}
|
||||
}
|
||||
else if (rootFolder.RootFolderType == FolderType.Privacy)
|
||||
{
|
||||
if (!Equals(privacyFolderId, 0))
|
||||
{
|
||||
cacheFolderId = rootFolderId = privacyFolderId;
|
||||
}
|
||||
}
|
||||
else if (rootFolder.RootFolderType == FolderType.SHARE)
|
||||
{
|
||||
cacheFolderId = await GlobalFolder.GetFolderShareAsync(DaoFactory);
|
||||
}
|
||||
|
||||
var updateTags = new List<Tag>();
|
||||
var updateTags = new List<Tag>();
|
||||
|
||||
if (!rootFolderId.Equals(default))
|
||||
{
|
||||
@ -482,12 +479,12 @@ namespace ASC.Web.Files.Utils
|
||||
if (updateTags.Count > 0)
|
||||
tagDao.UpdateNewTags(updateTags);
|
||||
if (removeTags.Count > 0)
|
||||
tagDao.RemoveTags(removeTags);
|
||||
|
||||
async Task UpdateRemoveTags<TFolder>(Folder<TFolder> folder)
|
||||
{
|
||||
var tagDao = DaoFactory.GetTagDao<TFolder>();
|
||||
var newTags = tagDao.GetNewTagsAsync(userID, folder);
|
||||
tagDao.RemoveTags(removeTags);
|
||||
|
||||
async Task UpdateRemoveTags<TFolder>(Folder<TFolder> folder)
|
||||
{
|
||||
var tagDao = DaoFactory.GetTagDao<TFolder>();
|
||||
var newTags = tagDao.GetNewTagsAsync(userID, folder);
|
||||
var parentTag = await newTags.FirstOrDefaultAsync();
|
||||
|
||||
if (parentTag != null)
|
||||
@ -503,9 +500,9 @@ namespace ASC.Web.Files.Utils
|
||||
removeTags.Add(parentTag);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
public async Task RemoveMarkAsNewForAllAsync<T>(FileEntry<T> fileEntry)
|
||||
{
|
||||
IAsyncEnumerable<Guid> userIDs;
|
||||
@ -518,9 +515,9 @@ namespace ASC.Web.Files.Utils
|
||||
{
|
||||
await RemoveMarkAsNewAsync(fileEntry, userID);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
public async Task<int> GetRootFoldersIdMarkedAsNewAsync<T>(T rootId)
|
||||
{
|
||||
var fromCache = GetCountFromCahce(rootId);
|
||||
@ -541,118 +538,126 @@ namespace ASC.Web.Files.Utils
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public Task<List<FileEntry>> MarkedItemsAsync<T>(Folder<T> folder)
|
||||
{
|
||||
if (folder == null) throw new ArgumentNullException(nameof(folder), FilesCommonResource.ErrorMassage_FolderNotFound);
|
||||
|
||||
return InternalMarkedItemsAsync(folder);
|
||||
}
|
||||
|
||||
private async Task<List<FileEntry>> InternalMarkedItemsAsync<T>(Folder<T> folder)
|
||||
{
|
||||
}
|
||||
|
||||
private async Task<List<FileEntry>> InternalMarkedItemsAsync<T>(Folder<T> folder)
|
||||
{
|
||||
if (!await FileSecurity.CanReadAsync(folder)) throw new SecurityException(FilesCommonResource.ErrorMassage_SecurityException_ViewFolder);
|
||||
if (folder.RootFolderType == FolderType.TRASH && !Equals(folder.ID, await GlobalFolder.GetFolderTrashAsync<T>(DaoFactory))) throw new SecurityException(FilesCommonResource.ErrorMassage_ViewTrashItem);
|
||||
|
||||
if (folder.RootFolderType == FolderType.TRASH && !Equals(folder.ID, await GlobalFolder.GetFolderTrashAsync<T>(DaoFactory))) throw new SecurityException(FilesCommonResource.ErrorMassage_ViewTrashItem);
|
||||
|
||||
var tagDao = DaoFactory.GetTagDao<T>();
|
||||
var providerFolderDao = DaoFactory.GetFolderDao<string>();
|
||||
var providerFolderDao = DaoFactory.GetFolderDao<string>();
|
||||
var providerTagDao = DaoFactory.GetTagDao<string>();
|
||||
var tags = (tagDao.GetNewTagsAsync(AuthContext.CurrentAccount.ID, folder, true) ?? AsyncEnumerable.Empty<Tag>());
|
||||
var tags = await (tagDao.GetNewTagsAsync(AuthContext.CurrentAccount.ID, folder, true) ?? AsyncEnumerable.Empty<Tag>()).ToListAsync();
|
||||
|
||||
if (!(await tags.CountAsync() == 0)) return new List<FileEntry>();
|
||||
if (!tags.Any()) return new List<FileEntry>();
|
||||
|
||||
if (Equals(folder.ID, GlobalFolder.GetFolderMy(this, DaoFactory)) ||
|
||||
Equals(folder.ID, await GlobalFolder.GetFolderCommonAsync(this, DaoFactory)) ||
|
||||
if (Equals(folder.ID, GlobalFolder.GetFolderMy(this, DaoFactory)) ||
|
||||
Equals(folder.ID, await GlobalFolder.GetFolderCommonAsync(this, DaoFactory)) ||
|
||||
Equals(folder.ID, await GlobalFolder.GetFolderShareAsync(DaoFactory)))
|
||||
{
|
||||
var folderTags = tags.Where(tag => tag.EntryType == FileEntryType.Folder && (tag.EntryId is string));
|
||||
|
||||
var providerFolderTags = folderTags
|
||||
.SelectAwait(async tag => new KeyValuePair<Tag, Folder<string>>(tag, await providerFolderDao.GetFolderAsync(tag.EntryId.ToString())))
|
||||
.Where(pair => pair.Value != null && pair.Value.ProviderEntry);
|
||||
var providerFolderTags = new List<KeyValuePair<Tag, Folder<string>>>();
|
||||
|
||||
providerFolderTags = providerFolderTags.Reverse();
|
||||
|
||||
await foreach (var providerFolderTag in providerFolderTags)
|
||||
foreach (var tag in folderTags)
|
||||
{
|
||||
tags.Concat(providerTagDao.GetNewTagsAsync(AuthContext.CurrentAccount.ID, providerFolderTag.Value, true));
|
||||
var pair = new KeyValuePair<Tag, Folder<string>>(tag, await providerFolderDao.GetFolderAsync(tag.EntryId.ToString()));
|
||||
if (pair.Value != null && pair.Value.ProviderEntry)
|
||||
{
|
||||
providerFolderTags.Add(pair);
|
||||
}
|
||||
}
|
||||
|
||||
providerFolderTags.Reverse();
|
||||
|
||||
foreach (var providerFolderTag in providerFolderTags)
|
||||
{
|
||||
tags.AddRange(await providerTagDao.GetNewTagsAsync(AuthContext.CurrentAccount.ID, providerFolderTag.Value, true).ToListAsync());
|
||||
}
|
||||
}
|
||||
|
||||
tags = tags
|
||||
.Where(r => !Equals(r.EntryId, folder.ID))
|
||||
.Distinct();
|
||||
tags = tags
|
||||
.Where(r => !Equals(r.EntryId, folder.ID))
|
||||
.Distinct()
|
||||
.ToList();
|
||||
|
||||
//TODO: refactoring
|
||||
var entryTagsProvider = await GetEntryTagsAsync<string>(tags.Where(r => r.EntryId is string));
|
||||
var entryTagsInternal = await GetEntryTagsAsync<int>(tags.Where(r => r.EntryId is int));
|
||||
//TODO: refactoring
|
||||
var entryTagsProvider = await GetEntryTagsAsync<string>(tags.Where(r => r.EntryId is string).ToAsyncEnumerable());
|
||||
var entryTagsInternal = await GetEntryTagsAsync<int>(tags.Where(r => r.EntryId is int).ToAsyncEnumerable());
|
||||
|
||||
foreach (var entryTag in entryTagsInternal)
|
||||
{
|
||||
var parentEntry = entryTagsInternal.Keys
|
||||
.FirstOrDefault(entryCountTag => Equals(entryCountTag.ID, entryTag.Key.FolderID));
|
||||
|
||||
if (parentEntry != null)
|
||||
{
|
||||
entryTagsInternal[parentEntry].Count -= entryTag.Value.Count;
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var entryTag in entryTagsProvider)
|
||||
{
|
||||
if (int.TryParse(entryTag.Key.FolderID, out var fId))
|
||||
{
|
||||
var parentEntryInt = entryTagsInternal.Keys
|
||||
.FirstOrDefault(entryCountTag => Equals(entryCountTag.ID, fId));
|
||||
|
||||
if (parentEntryInt != null)
|
||||
{
|
||||
entryTagsInternal[parentEntryInt].Count -= entryTag.Value.Count;
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
var parentEntry = entryTagsProvider.Keys
|
||||
.FirstOrDefault(entryCountTag => Equals(entryCountTag.ID, entryTag.Key.FolderID));
|
||||
var parentEntry = entryTagsInternal.Keys
|
||||
.FirstOrDefault(entryCountTag => Equals(entryCountTag.ID, entryTag.Key.FolderID));
|
||||
|
||||
if (parentEntry != null)
|
||||
{
|
||||
entryTagsProvider[parentEntry].Count -= entryTag.Value.Count;
|
||||
{
|
||||
entryTagsInternal[parentEntry].Count -= entryTag.Value.Count;
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var entryTag in entryTagsProvider)
|
||||
{
|
||||
if (int.TryParse(entryTag.Key.FolderID, out var fId))
|
||||
{
|
||||
var parentEntryInt = entryTagsInternal.Keys
|
||||
.FirstOrDefault(entryCountTag => Equals(entryCountTag.ID, fId));
|
||||
|
||||
if (parentEntryInt != null)
|
||||
{
|
||||
entryTagsInternal[parentEntryInt].Count -= entryTag.Value.Count;
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
var parentEntry = entryTagsProvider.Keys
|
||||
.FirstOrDefault(entryCountTag => Equals(entryCountTag.ID, entryTag.Key.FolderID));
|
||||
|
||||
if (parentEntry != null)
|
||||
{
|
||||
entryTagsProvider[parentEntry].Count -= entryTag.Value.Count;
|
||||
}
|
||||
}
|
||||
|
||||
var result = new List<FileEntry>();
|
||||
|
||||
await GetResultAsync(entryTagsInternal);
|
||||
await GetResultAsync(entryTagsInternal);
|
||||
await GetResultAsync(entryTagsProvider);
|
||||
|
||||
return result;
|
||||
|
||||
async Task GetResultAsync<TEntry>(Dictionary<FileEntry<TEntry>, Tag> entryTags)
|
||||
{
|
||||
foreach (var entryTag in entryTags)
|
||||
{
|
||||
if (!string.IsNullOrEmpty(entryTag.Key.Error))
|
||||
{
|
||||
await RemoveMarkAsNewAsync(entryTag.Key);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (entryTag.Value.Count > 0)
|
||||
{
|
||||
result.Add(entryTag.Key);
|
||||
}
|
||||
|
||||
return result;
|
||||
|
||||
async Task GetResultAsync<TEntry>(Dictionary<FileEntry<TEntry>, Tag> entryTags)
|
||||
{
|
||||
foreach (var entryTag in entryTags)
|
||||
{
|
||||
if (!string.IsNullOrEmpty(entryTag.Key.Error))
|
||||
{
|
||||
await RemoveMarkAsNewAsync(entryTag.Key);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (entryTag.Value.Count > 0)
|
||||
{
|
||||
result.Add(entryTag.Key);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private async Task<Dictionary<FileEntry<T>, Tag>> GetEntryTagsAsync<T>(IAsyncEnumerable<Tag> tags)
|
||||
}
|
||||
}
|
||||
|
||||
private async Task<Dictionary<FileEntry<T>, Tag>> GetEntryTagsAsync<T>(IAsyncEnumerable<Tag> tags)
|
||||
{
|
||||
var fileDao = DaoFactory.GetFileDao<T>();
|
||||
var folderDao = DaoFactory.GetFolderDao<T>();
|
||||
var entryTags = new Dictionary<FileEntry<T>, Tag>();
|
||||
var folderDao = DaoFactory.GetFolderDao<T>();
|
||||
var entryTags = new Dictionary<FileEntry<T>, Tag>();
|
||||
|
||||
await foreach (var tag in tags)
|
||||
{
|
||||
@ -667,11 +672,11 @@ namespace ASC.Web.Files.Utils
|
||||
{
|
||||
//todo: RemoveMarkAsNew(tag);
|
||||
}
|
||||
}
|
||||
|
||||
return entryTags;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return entryTags;
|
||||
}
|
||||
|
||||
public async Task<IEnumerable<FileEntry>> SetTagsNewAsync<T>(Folder<T> parent, IEnumerable<FileEntry> entries)
|
||||
{
|
||||
var tagDao = DaoFactory.GetTagDao<T>();
|
||||
|
@ -184,8 +184,11 @@ namespace ASC.Web.Files.Utils
|
||||
await NotifyClient.SendShareNoticeAsync(entry, recipients, message);
|
||||
}
|
||||
}
|
||||
|
||||
await usersWithoutRight.ToAsyncEnumerable().ForEachAwaitAsync(async userId => await FileMarker.RemoveMarkAsNewAsync(entry, userId));
|
||||
|
||||
foreach (var userId in usersWithoutRight)
|
||||
{
|
||||
await FileMarker.RemoveMarkAsNewAsync(entry, userId);
|
||||
}
|
||||
|
||||
return changed;
|
||||
}
|
||||
@ -199,9 +202,9 @@ namespace ASC.Web.Files.Utils
|
||||
{
|
||||
if (entry.RootFolderType != FolderType.USER && entry.RootFolderType != FolderType.Privacy
|
||||
|| Equals(entry.RootFolderId, GlobalFolderHelper.FolderMy)
|
||||
|| Equals(entry.RootFolderId, await GlobalFolderHelper.FolderPrivacyAsync))
|
||||
|| Equals(entry.RootFolderId, await GlobalFolderHelper.FolderPrivacyAsync))
|
||||
return;
|
||||
|
||||
|
||||
var entryType = entry.FileEntryType;
|
||||
await fileSecurity.ShareAsync(entry.ID, entryType, AuthContext.CurrentAccount.ID,
|
||||
entry.RootFolderType == FolderType.USER
|
||||
@ -335,11 +338,11 @@ namespace ASC.Web.Files.Utils
|
||||
isgroup = true;
|
||||
title = g.Name;
|
||||
|
||||
if (g.ID == Constants.GroupAdmin.ID)
|
||||
if (g.ID == Constants.GroupAdmin.ID)
|
||||
title = FilesCommonResource.Admin;
|
||||
if (g.ID == Constants.GroupEveryone.ID)
|
||||
title = FilesCommonResource.Everyone;
|
||||
|
||||
|
||||
if (g.ID == Constants.LostGroupInfo.ID)
|
||||
{
|
||||
await fileSecurity.RemoveSubjectAsync<T>(r.Subject);
|
||||
|
@ -168,7 +168,7 @@ namespace ASC.Api.Documents
|
||||
}
|
||||
|
||||
[Read("@root")]
|
||||
public async Task<IEnumerable<FolderContentWrapper<int>>> GetRootFoldersAsync(Guid userIdOrGroupId, FilterType filterType, bool withsubfolders, bool withoutTrash, bool withoutAdditionalFolder)
|
||||
public async Task<IEnumerable<FolderContentWrapper<int>>> GetRootFoldersAsync(Guid userIdOrGroupId, FilterType filterType, bool searchInContent, bool withsubfolders, bool withoutTrash, bool withoutAdditionalFolder)
|
||||
{
|
||||
var IsVisitor = UserManager.GetUsers(SecurityContext.CurrentAccount.ID).IsVisitor(UserManager);
|
||||
var IsOutsider = UserManager.GetUsers(SecurityContext.CurrentAccount.ID).IsOutsider(UserManager);
|
||||
@ -229,22 +229,22 @@ namespace ASC.Api.Documents
|
||||
var result = new List<FolderContentWrapper<int>>();
|
||||
foreach (var folder in folders)
|
||||
{
|
||||
result.Add(await FilesControllerHelperInt.GetFolderAsync(folder, userIdOrGroupId, filterType, withsubfolders));
|
||||
result.Add(await FilesControllerHelperInt.GetFolderAsync(folder, userIdOrGroupId, filterType, searchInContent, withsubfolders));
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
[Read("@privacy")]
|
||||
public Task<FolderContentWrapper<int>> GetPrivacyFolderAsync(Guid userIdOrGroupId, FilterType filterType, bool withsubfolders)
|
||||
public Task<FolderContentWrapper<int>> GetPrivacyFolderAsync(Guid userIdOrGroupId, FilterType filterType, bool searchInContent, bool withsubfolders)
|
||||
{
|
||||
if (!IsAvailablePrivacyRoomSettings()) throw new System.Security.SecurityException();
|
||||
return InternalGetPrivacyFolderAsync(userIdOrGroupId, filterType, withsubfolders);
|
||||
return InternalGetPrivacyFolderAsync(userIdOrGroupId, filterType, searchInContent, withsubfolders);
|
||||
}
|
||||
|
||||
private async Task<FolderContentWrapper<int>> InternalGetPrivacyFolderAsync(Guid userIdOrGroupId, FilterType filterType, bool withsubfolders)
|
||||
private async Task<FolderContentWrapper<int>> InternalGetPrivacyFolderAsync(Guid userIdOrGroupId, FilterType filterType, bool searchInContent, bool withsubfolders)
|
||||
{
|
||||
return await FilesControllerHelperInt.GetFolderAsync(await GlobalFolderHelper.FolderPrivacyAsync, userIdOrGroupId, filterType, withsubfolders);
|
||||
return await FilesControllerHelperInt.GetFolderAsync(await GlobalFolderHelper.FolderPrivacyAsync, userIdOrGroupId, filterType, searchInContent, withsubfolders);
|
||||
}
|
||||
|
||||
[Read("@privacy/available")]
|
||||
@ -262,9 +262,9 @@ namespace ASC.Api.Documents
|
||||
/// <category>Folders</category>
|
||||
/// <returns>My folder contents</returns>
|
||||
[Read("@my")]
|
||||
public Task<FolderContentWrapper<int>> GetMyFolderAsync(Guid userIdOrGroupId, FilterType filterType, bool withsubfolders)
|
||||
public Task<FolderContentWrapper<int>> GetMyFolderAsync(Guid userIdOrGroupId, FilterType filterType, bool searchInContent, bool withsubfolders)
|
||||
{
|
||||
return FilesControllerHelperInt.GetFolderAsync(GlobalFolderHelper.FolderMy, userIdOrGroupId, filterType, withsubfolders);
|
||||
return FilesControllerHelperInt.GetFolderAsync(GlobalFolderHelper.FolderMy, userIdOrGroupId, filterType, searchInContent, withsubfolders);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -276,9 +276,9 @@ namespace ASC.Api.Documents
|
||||
/// <category>Folders</category>
|
||||
/// <returns>Projects folder contents</returns>
|
||||
[Read("@projects")]
|
||||
public async Task<FolderContentWrapper<string>> GetProjectsFolderAsync(Guid userIdOrGroupId, FilterType filterType, bool withsubfolders)
|
||||
public async Task<FolderContentWrapper<string>> GetProjectsFolderAsync(Guid userIdOrGroupId, FilterType filterType, bool searchInContent, bool withsubfolders)
|
||||
{
|
||||
return await FilesControllerHelperString.GetFolderAsync(await GlobalFolderHelper.GetFolderProjectsAsync<string>(), userIdOrGroupId, filterType, withsubfolders);
|
||||
return await FilesControllerHelperString.GetFolderAsync(await GlobalFolderHelper.GetFolderProjectsAsync<string>(), userIdOrGroupId, filterType, searchInContent, withsubfolders);
|
||||
}
|
||||
|
||||
|
||||
@ -291,9 +291,9 @@ namespace ASC.Api.Documents
|
||||
/// <category>Folders</category>
|
||||
/// <returns>Common folder contents</returns>
|
||||
[Read("@common")]
|
||||
public async Task<FolderContentWrapper<int>> GetCommonFolderAsync(Guid userIdOrGroupId, FilterType filterType, bool withsubfolders)
|
||||
public async Task<FolderContentWrapper<int>> GetCommonFolderAsync(Guid userIdOrGroupId, FilterType filterType, bool searchInContent, bool withsubfolders)
|
||||
{
|
||||
return await FilesControllerHelperInt.GetFolderAsync(await GlobalFolderHelper.FolderCommonAsync, userIdOrGroupId, filterType, withsubfolders);
|
||||
return await FilesControllerHelperInt.GetFolderAsync(await GlobalFolderHelper.FolderCommonAsync, userIdOrGroupId, filterType, searchInContent, withsubfolders);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -305,9 +305,9 @@ namespace ASC.Api.Documents
|
||||
/// <category>Folders</category>
|
||||
/// <returns>Shared folder contents</returns>
|
||||
[Read("@share")]
|
||||
public async Task<FolderContentWrapper<int>> GetShareFolderAsync(Guid userIdOrGroupId, FilterType filterType, bool withsubfolders)
|
||||
public async Task<FolderContentWrapper<int>> GetShareFolderAsync(Guid userIdOrGroupId, FilterType filterType, bool searchInContent, bool withsubfolders)
|
||||
{
|
||||
return await FilesControllerHelperInt.GetFolderAsync(await GlobalFolderHelper.FolderShareAsync, userIdOrGroupId, filterType, withsubfolders);
|
||||
return await FilesControllerHelperInt.GetFolderAsync(await GlobalFolderHelper.FolderShareAsync, userIdOrGroupId, filterType, searchInContent, withsubfolders);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -317,9 +317,9 @@ namespace ASC.Api.Documents
|
||||
/// <category>Folders</category>
|
||||
/// <returns>Recent contents</returns>
|
||||
[Read("@recent")]
|
||||
public async Task<FolderContentWrapper<int>> GetRecentFolderAsync(Guid userIdOrGroupId, FilterType filterType, bool withsubfolders)
|
||||
public async Task<FolderContentWrapper<int>> GetRecentFolderAsync(Guid userIdOrGroupId, FilterType filterType, bool searchInContent, bool withsubfolders)
|
||||
{
|
||||
return await FilesControllerHelperInt.GetFolderAsync(await GlobalFolderHelper.FolderRecentAsync, userIdOrGroupId, filterType, withsubfolders);
|
||||
return await FilesControllerHelperInt.GetFolderAsync(await GlobalFolderHelper.FolderRecentAsync, userIdOrGroupId, filterType, searchInContent, withsubfolders);
|
||||
}
|
||||
|
||||
[Create("file/{fileId}/recent", order: int.MaxValue)]
|
||||
@ -341,9 +341,9 @@ namespace ASC.Api.Documents
|
||||
/// <category>Folders</category>
|
||||
/// <returns>Favorites contents</returns>
|
||||
[Read("@favorites")]
|
||||
public async Task<FolderContentWrapper<int>> GetFavoritesFolderAsync(Guid userIdOrGroupId, FilterType filterType, bool withsubfolders)
|
||||
public async Task<FolderContentWrapper<int>> GetFavoritesFolderAsync(Guid userIdOrGroupId, FilterType filterType, bool searchInContent, bool withsubfolders)
|
||||
{
|
||||
return await FilesControllerHelperInt.GetFolderAsync(await GlobalFolderHelper.FolderFavoritesAsync, userIdOrGroupId, filterType, withsubfolders);
|
||||
return await FilesControllerHelperInt.GetFolderAsync(await GlobalFolderHelper.FolderFavoritesAsync, userIdOrGroupId, filterType, searchInContent, withsubfolders);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -353,9 +353,9 @@ namespace ASC.Api.Documents
|
||||
/// <category>Folders</category>
|
||||
/// <returns>Templates contents</returns>
|
||||
[Read("@templates")]
|
||||
public async Task<FolderContentWrapper<int>> GetTemplatesFolderAsync(Guid userIdOrGroupId, FilterType filterType, bool withsubfolders)
|
||||
public async Task<FolderContentWrapper<int>> GetTemplatesFolderAsync(Guid userIdOrGroupId, FilterType filterType, bool searchInContent, bool withsubfolders)
|
||||
{
|
||||
return await FilesControllerHelperInt.GetFolderAsync(await GlobalFolderHelper.FolderTemplatesAsync, userIdOrGroupId, filterType, withsubfolders);
|
||||
return await FilesControllerHelperInt.GetFolderAsync(await GlobalFolderHelper.FolderTemplatesAsync, userIdOrGroupId, filterType, searchInContent, withsubfolders);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -367,9 +367,9 @@ namespace ASC.Api.Documents
|
||||
/// <category>Folders</category>
|
||||
/// <returns>Trash folder contents</returns>
|
||||
[Read("@trash")]
|
||||
public Task<FolderContentWrapper<int>> GetTrashFolderAsync(Guid userIdOrGroupId, FilterType filterType, bool withsubfolders)
|
||||
public Task<FolderContentWrapper<int>> GetTrashFolderAsync(Guid userIdOrGroupId, FilterType filterType, bool searchInContent, bool withsubfolders)
|
||||
{
|
||||
return FilesControllerHelperInt.GetFolderAsync(Convert.ToInt32(GlobalFolderHelper.FolderTrash), userIdOrGroupId, filterType, withsubfolders);
|
||||
return FilesControllerHelperInt.GetFolderAsync(Convert.ToInt32(GlobalFolderHelper.FolderTrash), userIdOrGroupId, filterType, searchInContent, withsubfolders);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -384,16 +384,16 @@ namespace ASC.Api.Documents
|
||||
/// <param name="filterType" optional="true" remark="Allowed values: None (0), FilesOnly (1), FoldersOnly (2), DocumentsOnly (3), PresentationsOnly (4), SpreadsheetsOnly (5) or ImagesOnly (7)">Filter type</param>
|
||||
/// <returns>Folder contents</returns>
|
||||
[Read("{folderId}", order: int.MaxValue, DisableFormat = true)]
|
||||
public async Task<FolderContentWrapper<string>> GetFolderAsync(string folderId, Guid userIdOrGroupId, FilterType filterType, bool withsubfolders)
|
||||
public async Task<FolderContentWrapper<string>> GetFolderAsync(string folderId, Guid userIdOrGroupId, FilterType filterType, bool searchInContent, bool withsubfolders)
|
||||
{
|
||||
var folder = await FilesControllerHelperString.GetFolderAsync(folderId, userIdOrGroupId, filterType, withsubfolders);
|
||||
var folder = await FilesControllerHelperString.GetFolderAsync(folderId, userIdOrGroupId, filterType, searchInContent, withsubfolders);
|
||||
return folder.NotFoundIfNull();
|
||||
}
|
||||
|
||||
[Read("{folderId:int}", order: int.MaxValue - 1, DisableFormat = true)]
|
||||
public Task<FolderContentWrapper<int>> GetFolderAsync(int folderId, Guid userIdOrGroupId, FilterType filterType, bool withsubfolders)
|
||||
public Task<FolderContentWrapper<int>> GetFolderAsync(int folderId, Guid userIdOrGroupId, FilterType filterType, bool searchInContent, bool withsubfolders)
|
||||
{
|
||||
return FilesControllerHelperInt.GetFolderAsync(folderId, userIdOrGroupId, filterType, withsubfolders);
|
||||
return FilesControllerHelperInt.GetFolderAsync(folderId, userIdOrGroupId, filterType, searchInContent, withsubfolders);
|
||||
}
|
||||
|
||||
[Read("{folderId}/subfolders")]
|
||||
@ -1058,31 +1058,35 @@ namespace ASC.Api.Documents
|
||||
}
|
||||
|
||||
[Create("owner")]
|
||||
public IAsyncEnumerable<FileEntryWrapper> ChangeOwnerFromBodyAsync([FromBody] ChangeOwnerModel model)
|
||||
public async Task<IEnumerable<FileEntryWrapper>> ChangeOwnerFromBodyAsync([FromBody] ChangeOwnerModel model)
|
||||
{
|
||||
return ChangeOwnerAsync(model);
|
||||
return await ChangeOwnerAsync(model);
|
||||
}
|
||||
|
||||
[Create("owner")]
|
||||
[Consumes("application/x-www-form-urlencoded")]
|
||||
public IAsyncEnumerable<FileEntryWrapper> ChangeOwnerFromFormAsync([FromForm] ChangeOwnerModel model)
|
||||
public async Task<IEnumerable<FileEntryWrapper>> ChangeOwnerFromFormAsync([FromForm] ChangeOwnerModel model)
|
||||
{
|
||||
return ChangeOwnerAsync(model);
|
||||
return await ChangeOwnerAsync(model);
|
||||
}
|
||||
|
||||
public async IAsyncEnumerable<FileEntryWrapper> ChangeOwnerAsync(ChangeOwnerModel model)
|
||||
public async Task<IEnumerable<FileEntryWrapper>> ChangeOwnerAsync(ChangeOwnerModel model)
|
||||
{
|
||||
var (folderIntIds, folderStringIds) = FileOperationsManager.GetIds(model.FolderIds);
|
||||
var (fileIntIds, fileStringIds) = FileOperationsManager.GetIds(model.FileIds);
|
||||
|
||||
var result = AsyncEnumerable.Empty<FileEntry>();
|
||||
result.Concat(FileStorageServiceInt.ChangeOwnerAsync(folderIntIds, fileIntIds, model.UserId));
|
||||
result.Concat(FileStorageService.ChangeOwnerAsync(folderStringIds, fileStringIds, model.UserId));
|
||||
var data = Enumerable.Empty<FileEntry>();
|
||||
data = data.Concat(await FileStorageServiceInt.ChangeOwnerAsync(folderIntIds, fileIntIds, model.UserId));
|
||||
data = data.Concat(await FileStorageService.ChangeOwnerAsync(folderStringIds, fileStringIds, model.UserId));
|
||||
|
||||
await foreach (var e in result)
|
||||
var result = new List<FileEntryWrapper>();
|
||||
|
||||
foreach (var e in data)
|
||||
{
|
||||
yield return await FilesControllerHelperInt.GetFileEntryWrapperAsync(e);
|
||||
result.Add(await FilesControllerHelperInt.GetFileEntryWrapperAsync(e));
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -1144,41 +1148,41 @@ namespace ASC.Api.Documents
|
||||
}
|
||||
|
||||
[Create("file/{fileId:int}/copyas", order: int.MaxValue - 1)]
|
||||
public object CopyFileAsFromBody(int fileId, [FromBody] CopyAsModel<JsonElement> model)
|
||||
public Task<FileEntryWrapper> CopyFileAsFromBody(int fileId, [FromBody] CopyAsModel<JsonElement> model)
|
||||
{
|
||||
return CopyFile(fileId, model);
|
||||
}
|
||||
|
||||
[Create("file/{fileId:int}/copyas", order: int.MaxValue - 1)]
|
||||
[Consumes("application/x-www-form-urlencoded")]
|
||||
public object CopyFileAsFromForm(int fileId, [FromForm] CopyAsModel<JsonElement> model)
|
||||
public Task<FileEntryWrapper> CopyFileAsFromForm(int fileId, [FromForm] CopyAsModel<JsonElement> model)
|
||||
{
|
||||
return CopyFile(fileId, model);
|
||||
}
|
||||
|
||||
[Create("file/{fileId}/copyas", order: int.MaxValue)]
|
||||
public object CopyFileAsFromBody(string fileId, [FromBody] CopyAsModel<JsonElement> model)
|
||||
public Task<FileEntryWrapper> CopyFileAsFromBody(string fileId, [FromBody] CopyAsModel<JsonElement> model)
|
||||
{
|
||||
return CopyFile(fileId, model);
|
||||
}
|
||||
|
||||
[Create("file/{fileId}/copyas", order: int.MaxValue)]
|
||||
[Consumes("application/x-www-form-urlencoded")]
|
||||
public object CopyFileAsFromForm(string fileId, [FromForm] CopyAsModel<JsonElement> model)
|
||||
public Task<FileEntryWrapper> CopyFileAsFromForm(string fileId, [FromForm] CopyAsModel<JsonElement> model)
|
||||
{
|
||||
return CopyFile(fileId, model);
|
||||
}
|
||||
|
||||
private object CopyFile<T>(T fileId, CopyAsModel<JsonElement> model)
|
||||
private async Task<FileEntryWrapper> CopyFile<T>(T fileId, CopyAsModel<JsonElement> model)
|
||||
{
|
||||
var helper = ServiceProvider.GetService<FilesControllerHelper<T>>();
|
||||
if (model.DestFolderId.ValueKind == JsonValueKind.Number)
|
||||
{
|
||||
return helper.CopyFileAsAsync(fileId, model.DestFolderId.GetInt32(), model.DestTitle, model.Password);
|
||||
return await helper.CopyFileAsAsync(fileId, model.DestFolderId.GetInt32(), model.DestTitle, model.Password);
|
||||
}
|
||||
else if (model.DestFolderId.ValueKind == JsonValueKind.String)
|
||||
{
|
||||
return helper.CopyFileAsAsync(fileId, model.DestFolderId.GetString(), model.DestTitle, model.Password);
|
||||
return await helper.CopyFileAsAsync(fileId, model.DestFolderId.GetString(), model.DestTitle, model.Password);
|
||||
}
|
||||
|
||||
return null;
|
||||
|
@ -141,9 +141,9 @@ namespace ASC.Files.Helpers
|
||||
ClientFactory = clientFactory;
|
||||
}
|
||||
|
||||
public async Task<FolderContentWrapper<T>> GetFolderAsync(T folderId, Guid userIdOrGroupId, FilterType filterType, bool withSubFolders)
|
||||
public async Task<FolderContentWrapper<T>> GetFolderAsync(T folderId, Guid userIdOrGroupId, FilterType filterType, bool searchInContent, bool withSubFolders)
|
||||
{
|
||||
var folderContentWrapper = await ToFolderContentWrapperAsync(folderId, userIdOrGroupId, filterType, withSubFolders);
|
||||
var folderContentWrapper = await ToFolderContentWrapperAsync(folderId, userIdOrGroupId, filterType, searchInContent, withSubFolders);
|
||||
return folderContentWrapper.NotFoundIfNull();
|
||||
}
|
||||
|
||||
@ -402,7 +402,6 @@ namespace ASC.Files.Helpers
|
||||
public async Task<FileWrapper<TTemplate>> CopyFileAsAsync<TTemplate>(T fileId, TTemplate destFolderId, string destTitle, string password = null)
|
||||
{
|
||||
var service = ServiceProvider.GetService<FileStorageService<TTemplate>>();
|
||||
var controller = ServiceProvider.GetService<FilesControllerHelper<TTemplate>>();
|
||||
var file = await FileStorageService.GetFileAsync(fileId, -1);
|
||||
var ext = FileUtility.GetFileExtension(file.Title);
|
||||
var destExt = FileUtility.GetFileExtension(destTitle);
|
||||
@ -415,6 +414,7 @@ namespace ASC.Files.Helpers
|
||||
|
||||
using (var fileStream = await FileConverter.ExecAsync(file, destExt, password))
|
||||
{
|
||||
var controller = ServiceProvider.GetService<FilesControllerHelper<TTemplate>>();
|
||||
return await controller.InsertFileAsync(destFolderId, fileStream, destTitle, true);
|
||||
}
|
||||
}
|
||||
@ -823,7 +823,7 @@ namespace ASC.Files.Helpers
|
||||
// return files.Concat(folders);
|
||||
//}
|
||||
|
||||
private async Task<FolderContentWrapper<T>> ToFolderContentWrapperAsync(T folderId, Guid userIdOrGroupId, FilterType filterType, bool withSubFolders)
|
||||
private async Task<FolderContentWrapper<T>> ToFolderContentWrapperAsync(T folderId, Guid userIdOrGroupId, FilterType filterType, bool searchInContent, bool withSubFolders)
|
||||
{
|
||||
OrderBy orderBy = null;
|
||||
if (Enum.TryParse(ApiContext.SortBy, true, out SortedByType sortBy))
|
||||
@ -839,7 +839,7 @@ namespace ASC.Files.Helpers
|
||||
filterType == FilterType.ByUser,
|
||||
userIdOrGroupId.ToString(),
|
||||
ApiContext.FilterValue,
|
||||
false,
|
||||
searchInContent,
|
||||
withSubFolders,
|
||||
orderBy);
|
||||
return await FolderContentWrapperHelper.GetAsync(items, startIndex);
|
||||
|
32
public/images/empty.screen.react.svg
Normal file
32
public/images/empty.screen.react.svg
Normal file
@ -0,0 +1,32 @@
|
||||
<svg width="72" height="72" viewBox="0 0 72 72" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<g clip-path="url(#clip0_23674_260133)">
|
||||
<path d="M11.9999 39.86H12.4999V39.36V22.08V21.58H11.9999H7.67986C6.22513 21.58 5.0186 22.2346 4.18295 23.1248C3.35539 24.0064 2.85986 25.1531 2.85986 26.1949V39.36V39.86H3.35986H11.9999Z" fill="#BDECFF" stroke="#333333"/>
|
||||
<path d="M58.5596 21.58H58.0596V22.08V33.6V34.1H58.5596H67.1996H67.6996V33.6V25.8309C67.6996 23.1962 65.5055 21.58 63.3596 21.58H58.5596Z" fill="#BDECFF" stroke="#333333"/>
|
||||
<path d="M53.7598 1.42H54.2598V1.92V40.32V40.82H53.7598H7.67976H7.17976V40.32V10.8808V10.6719L7.32834 10.5251L16.3976 1.56432L16.5437 1.42H16.749H53.7598Z" fill="white" stroke="#333333"/>
|
||||
<path d="M15.9658 1.56644C16.1088 1.42345 16.3238 1.38067 16.5107 1.45806C16.6975 1.53545 16.8193 1.71777 16.8193 1.92V10.56C16.8193 10.8361 16.5955 11.06 16.3193 11.06H7.67934C7.47711 11.06 7.29479 10.9382 7.2174 10.7513C7.14001 10.5645 7.18278 10.3494 7.32578 10.2064L15.9658 1.56644Z" fill="url(#paint0_linear_23674_260133)" stroke="#333333" stroke-linejoin="round"/>
|
||||
<path d="M62.8799 9.1H63.3799V9.6V48V48.5H62.8799H16.7999H16.2999V48V18.5608V18.3519L16.4485 18.2051L25.5177 9.24432L25.6638 9.1H25.8692H62.8799Z" fill="white" stroke="#333333"/>
|
||||
<path d="M25.0859 9.24645C25.2289 9.10345 25.444 9.06067 25.6308 9.13806C25.8176 9.21545 25.9395 9.39777 25.9395 9.6V18.24C25.9395 18.5161 25.7156 18.74 25.4395 18.74H16.7994C16.5972 18.74 16.4149 18.6182 16.3375 18.4313C16.2601 18.2445 16.3029 18.0294 16.4459 17.8864L25.0859 9.24645Z" fill="#BDECFF" stroke="#333333" stroke-linejoin="round"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M57.1201 23.74C57.3963 23.74 57.6201 23.9639 57.6201 24.24C57.6201 24.5161 57.3963 24.74 57.1201 24.74H29.7601C29.484 24.74 29.2601 24.5161 29.2601 24.24C29.2601 23.9639 29.484 23.74 29.7601 23.74H57.1201ZM56.1601 35.3H56.8801C57.1563 35.3 57.3801 35.0761 57.3801 34.8C57.3801 34.5239 57.1563 34.3 56.8801 34.3H56.1601H42.9601H22.0801C21.804 34.3 21.5801 34.5239 21.5801 34.8C21.5801 35.0761 21.804 35.3 22.0801 35.3H42.9601H56.1601ZM57.6201 29.52C57.6201 29.2439 57.3963 29.02 57.1201 29.02H22.0801C21.804 29.02 21.5801 29.2439 21.5801 29.52C21.5801 29.7961 21.804 30.02 22.0801 30.02H57.1201C57.3963 30.02 57.6201 29.7961 57.6201 29.52Z" fill="#333333"/>
|
||||
<path d="M49.2002 17.52H33.3602" stroke="url(#paint1_linear_23674_260133)" stroke-width="2" stroke-linecap="round"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M33.7591 34.3721L29.3935 39.2564H4.1498C2.06437 39.2564 0.271579 41.1315 0.499599 42.6561L4.56436 67.4328C4.79713 68.9574 6.42415 70.56 8.50958 70.56H64.3404C66.4258 70.56 67.5691 69.2027 67.6878 67.6734L71.4964 35.4188C71.6864 34.4582 70.7173 33.12 69.0119 33.12H36.7281C35.5928 33.12 34.5714 33.5501 33.7591 34.3721Z" fill="url(#paint2_linear_23674_260133)" stroke="#333333"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M30.7209 42.24V46.1261C30.7209 46.6436 30.5112 47.1121 30.1722 47.4512C29.8331 47.7903 29.3646 48 28.847 48H24.9609V47.3977H28.847C29.1951 47.3977 29.5163 47.2549 29.7438 47.0229C29.9758 46.7909 30.1186 46.4741 30.1186 46.1261V42.24H30.7209Z" fill="white"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M46.9062 43.648V43.5754C46.9062 43.2623 46.7707 42.9718 46.5539 42.7585C46.3326 42.5406 46.0254 42.3954 45.7002 42.3727H30.4426L25.1083 47.7373L26.3865 63.8311C26.4182 64.2078 26.5717 64.5482 26.8111 64.7887C27.0324 65.0111 27.3351 65.1518 27.6783 65.1518H44.3045C44.6478 65.1518 44.9549 65.0111 45.1808 64.7842C45.4202 64.5437 45.5737 64.2078 45.5963 63.8356L46.9062 43.648ZM47.5205 43.5754L46.2061 63.8719C46.1699 64.3939 45.9531 64.8704 45.6144 65.2154C45.2801 65.5512 44.824 65.76 44.309 65.76H27.6783C27.1634 65.76 26.7163 65.5512 26.382 65.2199C26.0433 64.8795 25.8219 64.3984 25.7813 63.881L24.4805 47.5058L30.1942 41.76H45.6189L45.7409 41.7645C46.2151 41.7963 46.6578 42.0051 46.983 42.3228C47.3082 42.6496 47.5205 43.0853 47.5205 43.5754Z" fill="white"/>
|
||||
</g>
|
||||
<defs>
|
||||
<linearGradient id="paint0_linear_23674_260133" x1="18.1808" y1="1.45762" x2="13.3027" y2="9.34641" gradientUnits="userSpaceOnUse">
|
||||
<stop stop-color="#FFC671"/>
|
||||
<stop offset="1" stop-color="#FF6F3D"/>
|
||||
</linearGradient>
|
||||
<linearGradient id="paint1_linear_23674_260133" x1="49.2002" y1="17.4809" x2="49.079" y2="19.475" gradientUnits="userSpaceOnUse">
|
||||
<stop stop-color="#FF8E3D"/>
|
||||
<stop offset="1" stop-color="#FF6F3D"/>
|
||||
</linearGradient>
|
||||
<linearGradient id="paint2_linear_23674_260133" x1="18.2942" y1="20.7558" x2="44.1579" y2="60.4266" gradientUnits="userSpaceOnUse">
|
||||
<stop stop-color="#FFC671"/>
|
||||
<stop offset="1" stop-color="#FF6F3D"/>
|
||||
</linearGradient>
|
||||
<clipPath id="clip0_23674_260133">
|
||||
<rect width="72" height="72" fill="white"/>
|
||||
</clipPath>
|
||||
</defs>
|
||||
</svg>
|
After Width: | Height: | Size: 4.6 KiB |
@ -121,12 +121,15 @@
|
||||
"RequiredField": "Required field",
|
||||
"ResetApplication": "Reset application",
|
||||
"Restore": "Restore",
|
||||
"RestoreHere": "Restore here",
|
||||
"Review": "Review",
|
||||
"Role": "Role",
|
||||
"SameEmail": "You can't use the same email",
|
||||
"SaveButton": "Save",
|
||||
"SaveHereButton": "Save here",
|
||||
"Search": "Search",
|
||||
"Select": "Select",
|
||||
"SelectFile": "Select file",
|
||||
"SelectAll": "Select all",
|
||||
"SendButton": "Send",
|
||||
"Sending": "Sending...",
|
||||
|
@ -121,12 +121,15 @@
|
||||
"RequiredField": "Обязательное поле",
|
||||
"ResetApplication": "Сбросить приложение",
|
||||
"Restore": "Восстановить",
|
||||
"RestoreHere": "Восстановить сюда",
|
||||
"Review": "Рецензирование",
|
||||
"Role": "Позиция",
|
||||
"SameEmail": "Email совпадает с текущим",
|
||||
"SaveButton": "Сохранить",
|
||||
"SaveHereButton": "Сохранить сюда",
|
||||
"Search": "Поиск",
|
||||
"Select": "Выберите",
|
||||
"SelectFile": "Выберите файл",
|
||||
"SelectAll": "Выбрать все",
|
||||
"SendButton": "Отправить",
|
||||
"Sending": "Отправка...",
|
||||
|
@ -40,6 +40,10 @@ namespace ASC.Web.Api.Controllers
|
||||
[ApiController]
|
||||
public class PortalController : ControllerBase
|
||||
{
|
||||
private readonly ApiSystemHelper _apiSystemHelper;
|
||||
private readonly CoreSettings _coreSettings;
|
||||
private readonly StudioNotifyService _studioNotifyService;
|
||||
private readonly PermissionContext _permissionContext;
|
||||
|
||||
private Tenant Tenant { get { return ApiContext.Tenant; } }
|
||||
|
||||
@ -87,11 +91,11 @@ namespace ASC.Web.Api.Controllers
|
||||
LicenseReader licenseReader,
|
||||
SetupInfo setupInfo,
|
||||
DocumentServiceLicense documentServiceLicense,
|
||||
IHttpClientFactory clientFactory,
|
||||
ApiSystemHelper apiSystemHelper,
|
||||
CoreSettings coreSettings,
|
||||
PermissionContext permissionContext,
|
||||
ApiSystemHelper apiSystemHelper,
|
||||
StudioNotifyService studioNotifyService,
|
||||
IHttpClientFactory clientFactory
|
||||
StudioNotifyService studioNotifyService
|
||||
)
|
||||
{
|
||||
Log = options.CurrentValue;
|
||||
@ -117,6 +121,10 @@ namespace ASC.Web.Api.Controllers
|
||||
StudioNotifyService = studioNotifyService;
|
||||
TenantExtra = tenantExtra;
|
||||
ClientFactory = clientFactory;
|
||||
_apiSystemHelper = apiSystemHelper;
|
||||
_coreSettings = coreSettings;
|
||||
_studioNotifyService = studioNotifyService;
|
||||
_permissionContext = permissionContext;
|
||||
}
|
||||
|
||||
[Read("")]
|
||||
@ -296,38 +304,35 @@ namespace ASC.Web.Api.Controllers
|
||||
MobileAppInstallRegistrator.RegisterInstall(currentUser.Email, type);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Updates a portal name with a new one specified in the request.
|
||||
/// </summary>
|
||||
/// <short>Update a portal name</short>
|
||||
/// <param name="alias">New portal name</param>
|
||||
/// <returns>Message about renaming a portal</returns>
|
||||
///<visible>false</visible>
|
||||
[Update("portalrename")]
|
||||
public object UpdatePortalNameFromObject([FromBody] PortalRenameModel model)
|
||||
public async Task<object> UpdatePortalName(PortalRenameModel model)
|
||||
{
|
||||
return UpdatePortalNameAsync(model);
|
||||
}
|
||||
|
||||
[Update("portalrename")]
|
||||
[Consumes("application/x-www-form-urlencoded")]
|
||||
public object UpdatePortalNameFromForm([FromForm] PortalRenameModel model)
|
||||
{
|
||||
return UpdatePortalNameAsync(model);
|
||||
}
|
||||
|
||||
public async Task<object> UpdatePortalNameAsync(PortalRenameModel model)
|
||||
{
|
||||
var enabled = SetupInfo.IsVisibleSettings("PortalRename");
|
||||
|
||||
if (!enabled)
|
||||
throw new SecurityException(Resource.PortalAccessSettingsTariffException);
|
||||
if (!SetupInfo.IsVisibleSettings(nameof(ManagementType.PortalSecurity)))
|
||||
{
|
||||
throw new BillingException(Resource.ErrorNotAllowedOption);
|
||||
}
|
||||
|
||||
if (CoreBaseSettings.Personal)
|
||||
{
|
||||
throw new Exception(Resource.ErrorAccessDenied);
|
||||
}
|
||||
|
||||
PermissionContext.DemandPermissions(SecutiryConstants.EditPortalSettings);
|
||||
_permissionContext.DemandPermissions(SecutiryConstants.EditPortalSettings);
|
||||
|
||||
var alias = model.Alias;
|
||||
if (string.IsNullOrEmpty(alias)) throw new ArgumentException();
|
||||
if (string.IsNullOrEmpty(alias)) throw new ArgumentException(nameof(alias));
|
||||
|
||||
var tenant = TenantManager.GetCurrentTenant();
|
||||
var user = UserManager.GetUsers(SecurityContext.CurrentAccount.ID);
|
||||
|
||||
var localhost = CoreSettings.BaseDomain == "localhost" || tenant.TenantAlias == "localhost";
|
||||
var localhost = _coreSettings.BaseDomain == "localhost" || tenant.TenantAlias == "localhost";
|
||||
|
||||
var newAlias = alias.ToLowerInvariant();
|
||||
var oldAlias = tenant.TenantAlias;
|
||||
@ -335,51 +340,40 @@ namespace ASC.Web.Api.Controllers
|
||||
|
||||
if (!string.Equals(newAlias, oldAlias, StringComparison.InvariantCultureIgnoreCase))
|
||||
{
|
||||
if (!string.IsNullOrEmpty(ApiSystemHelper.ApiSystemUrl))
|
||||
if (!string.IsNullOrEmpty(_apiSystemHelper.ApiSystemUrl))
|
||||
{
|
||||
await ApiSystemHelper.ValidatePortalNameAsync(newAlias, user.ID);
|
||||
await _apiSystemHelper.ValidatePortalNameAsync(newAlias, user.ID);
|
||||
}
|
||||
else
|
||||
{
|
||||
TenantManager.CheckTenantAddress(newAlias.Trim());
|
||||
}
|
||||
|
||||
|
||||
if (!string.IsNullOrEmpty(ApiSystemHelper.ApiCacheUrl))
|
||||
if (!string.IsNullOrEmpty(_apiSystemHelper.ApiCacheUrl))
|
||||
{
|
||||
await ApiSystemHelper.AddTenantToCacheAsync(newAlias, user.ID);
|
||||
await _apiSystemHelper.AddTenantToCacheAsync(newAlias, user.ID);
|
||||
}
|
||||
|
||||
tenant.TenantAlias = alias;
|
||||
tenant = TenantManager.SaveTenant(tenant);
|
||||
|
||||
|
||||
if (!string.IsNullOrEmpty(ApiSystemHelper.ApiCacheUrl))
|
||||
if (!string.IsNullOrEmpty(_apiSystemHelper.ApiCacheUrl))
|
||||
{
|
||||
await ApiSystemHelper.RemoveTenantFromCacheAsync(oldAlias, user.ID);
|
||||
await _apiSystemHelper.RemoveTenantFromCacheAsync(oldAlias, user.ID);
|
||||
}
|
||||
|
||||
if (!localhost || string.IsNullOrEmpty(tenant.MappedDomain))
|
||||
{
|
||||
StudioNotifyService.PortalRenameNotify(tenant, oldVirtualRootPath);
|
||||
_studioNotifyService.PortalRenameNotify(tenant, oldVirtualRootPath);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return null;
|
||||
return string.Empty;
|
||||
}
|
||||
|
||||
var reference = string.Format("{0}{1}{2}/{3}",
|
||||
ApiContext.HttpContextAccessor.HttpContext.Request?.Scheme ?? Uri.UriSchemeHttp,
|
||||
Uri.SchemeDelimiter,
|
||||
tenant.GetTenantDomain(CoreSettings),
|
||||
CommonLinkUtility.GetConfirmationUrlRelative(tenant.TenantId, user.Email, ConfirmType.Auth));
|
||||
|
||||
return new
|
||||
{
|
||||
message = Resource.SuccessfullyPortalRenameMessage,
|
||||
reference = reference
|
||||
};
|
||||
return CommonLinkUtility.GetConfirmationUrl(user.Email, ConfirmType.Auth);
|
||||
}
|
||||
}
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user