Merge branch 'feature/virtual-rooms-1.2' into feature/modal-redesign
This commit is contained in:
commit
0cafa97440
@ -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,
|
||||
|
@ -321,11 +321,11 @@ namespace ASC.Core.Notify.Signalr
|
||||
}
|
||||
}
|
||||
|
||||
public void StopEdit<T>(T fileId, string room, string data)
|
||||
public void StopEdit<T>(T fileId, string room)
|
||||
{
|
||||
try
|
||||
{
|
||||
MakeRequest("stop-edit", new { room, fileId, data });
|
||||
MakeRequest("stop-edit", new { room, fileId });
|
||||
}
|
||||
catch (Exception error)
|
||||
{
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -101,9 +101,9 @@
|
||||
filesIO.to(room).emit("s:start-edit-file", fileId);
|
||||
}
|
||||
|
||||
function stopEdit({ fileId, room, data } = {}) {
|
||||
function stopEdit({ fileId, room } = {}) {
|
||||
logger.info(`stop edit file ${fileId} in room ${room}`);
|
||||
filesIO.to(room).emit("s:stop-edit-file", fileId, data);
|
||||
filesIO.to(room).emit("s:stop-edit-file", fileId);
|
||||
}
|
||||
|
||||
function modifyFolder(room, cmd, id, type, data) {
|
||||
|
@ -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",
|
||||
|
@ -415,13 +415,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",
|
||||
|
@ -31,7 +31,7 @@ const Article = ({
|
||||
toggleShowText,
|
||||
toggleArticleOpen,
|
||||
setIsMobileArticle,
|
||||
isLoading,
|
||||
isLoadedPage,
|
||||
children,
|
||||
...rest
|
||||
}) => {
|
||||
@ -117,7 +117,7 @@ const Article = ({
|
||||
handleWrapperClass="resizable-border not-selectable"
|
||||
>
|
||||
<SubArticleHeader
|
||||
isLoading={isLoading}
|
||||
isLoadedPage={isLoadedPage}
|
||||
showText={showText}
|
||||
onClick={toggleShowText}
|
||||
>
|
||||
@ -128,7 +128,7 @@ const Article = ({
|
||||
{articleMainButtonContent.props.children}
|
||||
</SubArticleMainButton>
|
||||
) : null}
|
||||
<SubArticleBody isLoading={isLoading} showText={showText}>
|
||||
<SubArticleBody showText={showText}>
|
||||
{articleBodyContent ? articleBodyContent.props.children : null}
|
||||
</SubArticleBody>
|
||||
</Resizable>
|
||||
|
@ -1,10 +1,8 @@
|
||||
import React from "react";
|
||||
import Scrollbar from "@appserver/components/scrollbar";
|
||||
import LoaderArticleBody from "./article-body-loader";
|
||||
const ArticleBody = ({ children, isLoading = false }) => {
|
||||
return isLoading ? (
|
||||
<LoaderArticleBody />
|
||||
) : (
|
||||
|
||||
const ArticleBody = ({ children }) => {
|
||||
return (
|
||||
<Scrollbar className="article-body__scrollbar" stype="mediumBlack">
|
||||
{children}
|
||||
</Scrollbar>
|
||||
|
@ -1,9 +1,9 @@
|
||||
import React from "react";
|
||||
import React, { useEffect } from "react";
|
||||
import PropTypes from "prop-types";
|
||||
import Loaders from "@appserver/common/components/Loaders";
|
||||
import { isTablet as isTabletUtils } from "@appserver/components/utils/device";
|
||||
import { isTablet } from "react-device-detect";
|
||||
|
||||
import { inject, observer } from "mobx-react";
|
||||
import {
|
||||
StyledArticleHeader,
|
||||
StyledHeading,
|
||||
@ -15,12 +15,22 @@ const ArticleHeader = ({
|
||||
showText,
|
||||
children,
|
||||
onClick,
|
||||
isLoading = false,
|
||||
isLoadedPage,
|
||||
isLoaded,
|
||||
tReady,
|
||||
setIsLoadedArticleHeader,
|
||||
...rest
|
||||
}) => {
|
||||
const heightLoader = isTabletUtils() || isTablet ? "20px" : "32px";
|
||||
const isLoadedSetting = isLoaded;
|
||||
const commonSettings = location.pathname.includes("common");
|
||||
|
||||
return isLoading ? (
|
||||
useEffect(() => {
|
||||
if (isLoadedSetting) setIsLoadedArticleHeader(isLoadedSetting);
|
||||
}, [isLoadedSetting]);
|
||||
|
||||
const heightLoader = isTabletUtils() || isTablet ? "20px" : "32px";
|
||||
const showLoader = commonSettings ? !isLoadedPage : false;
|
||||
return showLoader ? (
|
||||
<StyledArticleHeader>
|
||||
<Loaders.ArticleHeader height={heightLoader} className="loader" />
|
||||
</StyledArticleHeader>
|
||||
@ -45,4 +55,11 @@ ArticleHeader.propTypes = {
|
||||
|
||||
ArticleHeader.displayName = "Header";
|
||||
|
||||
export default React.memo(ArticleHeader);
|
||||
export default inject(({ common }) => {
|
||||
const { isLoaded, setIsLoadedArticleHeader } = common;
|
||||
|
||||
return {
|
||||
isLoaded,
|
||||
setIsLoadedArticleHeader,
|
||||
};
|
||||
})(observer(ArticleHeader));
|
||||
|
@ -9,10 +9,10 @@ const StyledFilter = styled.div`
|
||||
grid-template-rows: 1fr;
|
||||
grid-column-gap: 8px;
|
||||
|
||||
${isMobile &&
|
||||
/* ${isMobile &&
|
||||
css`
|
||||
margin-top: -22px;
|
||||
`}
|
||||
`} */
|
||||
|
||||
@media ${mobile} {
|
||||
grid-template-columns: 1fr 50px;
|
||||
|
@ -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,
|
||||
};
|
||||
|
@ -250,8 +250,13 @@ class SettingsStore {
|
||||
this.isLoaded = isLoaded;
|
||||
};
|
||||
|
||||
setCultures = (cultures) => {
|
||||
this.cultures = cultures;
|
||||
};
|
||||
|
||||
getPortalCultures = async () => {
|
||||
this.cultures = await api.settings.getPortalCultures();
|
||||
const cultures = await api.settings.getPortalCultures();
|
||||
this.setCultures(cultures);
|
||||
};
|
||||
|
||||
setIsEncryptionSupport = (isEncryptionSupport) => {
|
||||
|
@ -42,10 +42,8 @@ class TfaStore {
|
||||
this.backupCodes = codes;
|
||||
};
|
||||
|
||||
getTfaConfirmLink = async (res) => {
|
||||
if (res) {
|
||||
return await api.settings.getTfaConfirmLink();
|
||||
}
|
||||
getTfaConfirmLink = async () => {
|
||||
return await api.settings.getTfaConfirmLink();
|
||||
};
|
||||
|
||||
getSecretKeyAndQR = async (confirmKey) => {
|
||||
|
@ -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 */
|
||||
|
@ -156,8 +156,7 @@ const StyledButton = styled(ButtonWrapper).attrs((props) => ({
|
||||
: props.theme.button.border.base};
|
||||
|
||||
${(props) => props.scale && `width: 100%;`};
|
||||
min-width: ${(props) =>
|
||||
props.minwidth ? props.minwidth : props.theme.button.minWidth[props.size]};
|
||||
min-width: ${(props) => props.minwidth && props.minwidth};
|
||||
|
||||
padding: ${(props) => `${props.theme.button.padding[props.size]}`};
|
||||
|
||||
@ -214,6 +213,8 @@ const StyledButton = styled(ButtonWrapper).attrs((props) => ({
|
||||
}
|
||||
|
||||
.button-content {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
|
@ -127,7 +127,6 @@ const MainButtonMobile = (props) => {
|
||||
};
|
||||
|
||||
const onMainButtonClick = (e) => {
|
||||
if (isOpen && ref.current.contains(e.target)) return;
|
||||
toggle(!isOpen);
|
||||
};
|
||||
|
||||
@ -191,8 +190,8 @@ const MainButtonMobile = (props) => {
|
||||
/>
|
||||
))}
|
||||
</StyledProgressContainer>
|
||||
<StyledButtonOptions isOpenButton={isOpenButton}>
|
||||
{isOpenButton && buttonOptions
|
||||
<StyledButtonOptions>
|
||||
{buttonOptions
|
||||
? buttonOptions.map((option) =>
|
||||
option.isSeparator ? (
|
||||
<div key={option.key} className="separator-wrapper">
|
||||
@ -213,20 +212,6 @@ const MainButtonMobile = (props) => {
|
||||
)
|
||||
: ""}
|
||||
</StyledButtonOptions>
|
||||
{withButton && (
|
||||
<StyledButtonWrapper
|
||||
isUploading={isUploading}
|
||||
isOpenButton={isOpenButton}
|
||||
>
|
||||
<Button
|
||||
label={title}
|
||||
className="action-mobile-button"
|
||||
primary
|
||||
size="medium"
|
||||
onClick={onUploadClick}
|
||||
/>
|
||||
</StyledButtonWrapper>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
@ -134,7 +134,6 @@ const StyledDropDownItem = styled(DropDownItem)`
|
||||
`;
|
||||
|
||||
const StyledButtonOptions = styled.div`
|
||||
display: ${(props) => !props.isOpenButton && "none"};
|
||||
padding: 16px 0;
|
||||
background-color: ${(props) =>
|
||||
props.theme.mainButtonMobile.buttonOptions.backgroundColor};
|
||||
|
@ -162,6 +162,7 @@ class ModalDialog extends React.Component {
|
||||
className={className}
|
||||
isLarge={isLarge}
|
||||
zIndex={zIndex}
|
||||
<<<<<<< HEAD
|
||||
autoMaxHeight={autoMaxHeight}
|
||||
autoMaxWidth={autoMaxWidth}
|
||||
fadeType={this.state.fadeType}
|
||||
@ -174,6 +175,48 @@ class ModalDialog extends React.Component {
|
||||
visible={visible}
|
||||
modalSwipeOffset={this.state.modalSwipeOffset}
|
||||
/>
|
||||
=======
|
||||
withBackground={true}
|
||||
isModalDialog
|
||||
>
|
||||
<Dialog
|
||||
width={width}
|
||||
className={`${className} not-selectable`}
|
||||
id={id}
|
||||
style={style}
|
||||
>
|
||||
<Content
|
||||
contentHeight={contentHeight}
|
||||
contentWidth={contentWidth}
|
||||
displayType={this.state.displayType}
|
||||
>
|
||||
{isLoading ? (
|
||||
<Loaders.DialogLoader bodyHeight={modalLoaderBodyHeight} />
|
||||
) : (
|
||||
<>
|
||||
<StyledHeader>
|
||||
<Heading className="heading" size="medium" truncate={true}>
|
||||
{header ? header.props.children : null}
|
||||
</Heading>
|
||||
{!withoutCloseButton && (
|
||||
<CloseButton
|
||||
className="modal-dialog-button_close"
|
||||
onClick={onClose}
|
||||
></CloseButton>
|
||||
)}
|
||||
</StyledHeader>
|
||||
<BodyBox paddingProp={modalBodyPadding}>
|
||||
{body ? body.props.children : null}
|
||||
</BodyBox>
|
||||
<Box className="modal-dialog-modal-footer">
|
||||
{footer ? footer.props.children : null}
|
||||
</Box>
|
||||
</>
|
||||
)}
|
||||
</Content>
|
||||
</Dialog>
|
||||
</Backdrop>
|
||||
>>>>>>> feature/virtual-rooms-1.2
|
||||
) : (
|
||||
<ModalAside
|
||||
id={id}
|
||||
|
@ -108,7 +108,6 @@ RadioButtonGroup.defaultProps = {
|
||||
selected: undefined,
|
||||
spacing: "15px",
|
||||
orientation: "horizontal",
|
||||
width: "100%",
|
||||
};
|
||||
|
||||
export default RadioButtonGroup;
|
||||
|
@ -17,7 +17,7 @@ const StyledDiv = styled(ClearDiv)`
|
||||
`) ||
|
||||
(props.orientation === "vertical" &&
|
||||
css`
|
||||
display: block;
|
||||
display: inline-block;
|
||||
`)};
|
||||
|
||||
width: ${(props) => props.width};
|
||||
|
@ -47,6 +47,7 @@ class SaveCancelButtons extends React.Component {
|
||||
isFirstWelcomePageSettings,
|
||||
className,
|
||||
id,
|
||||
isSaving,
|
||||
} = this.props;
|
||||
|
||||
const cancelButtonDisabled =
|
||||
@ -69,11 +70,12 @@ class SaveCancelButtons extends React.Component {
|
||||
onClick={onSaveClick}
|
||||
label={saveButtonLabel}
|
||||
minwidth={displaySettings && "auto"}
|
||||
isLoading={isSaving}
|
||||
/>
|
||||
<Button
|
||||
className="cancel-button"
|
||||
size="normal"
|
||||
isDisabled={cancelButtonDisabled}
|
||||
isDisabled={cancelButtonDisabled || isSaving}
|
||||
onClick={onCancelClick}
|
||||
label={cancelButtonLabel}
|
||||
minwidth={displaySettings && "auto"}
|
||||
@ -109,6 +111,7 @@ SaveCancelButtons.propTypes = {
|
||||
hasScroll: PropTypes.bool,
|
||||
minwidth: PropTypes.string,
|
||||
isFirstWelcomePageSettings: PropTypes.string,
|
||||
isSaving: PropTypes.bool,
|
||||
};
|
||||
|
||||
SaveCancelButtons.defaultProps = {
|
||||
|
@ -5,7 +5,7 @@ import StyledButton from "./styled-selector-add-button";
|
||||
import IconButton from "../icon-button";
|
||||
|
||||
const SelectorAddButton = (props) => {
|
||||
const { isDisabled, title, className, id, style } = props;
|
||||
const { isDisabled, title, className, id, style, iconName } = props;
|
||||
|
||||
const onClick = (e) => {
|
||||
!isDisabled && props.onClick && props.onClick(e);
|
||||
@ -22,7 +22,7 @@ const SelectorAddButton = (props) => {
|
||||
>
|
||||
<IconButton
|
||||
size={14}
|
||||
iconName="/static/images/actions.header.touch.react.svg"
|
||||
iconName={iconName}
|
||||
isFill={true}
|
||||
isDisabled={isDisabled}
|
||||
isClickable={!isDisabled}
|
||||
@ -44,10 +44,13 @@ SelectorAddButton.propTypes = {
|
||||
id: PropTypes.string,
|
||||
/** Accepts css style */
|
||||
style: PropTypes.oneOfType([PropTypes.object, PropTypes.array]),
|
||||
/** Specifies the icon name */
|
||||
iconName: PropTypes.string,
|
||||
};
|
||||
|
||||
SelectorAddButton.defaultProps = {
|
||||
isDisabled: false,
|
||||
iconName: "/static/images/actions.header.touch.react.svg",
|
||||
};
|
||||
|
||||
export default SelectorAddButton;
|
||||
|
@ -12,8 +12,9 @@ import {
|
||||
StyledSubmenuItems,
|
||||
StyledSubmenuItemText,
|
||||
} from "./styled-submenu";
|
||||
import LoaderSubmenu from "./loader";
|
||||
|
||||
const Submenu = ({ data, startSelect = 0, onSelect, ...rest }) => {
|
||||
const Submenu = ({ data, startSelect = 0, onSelect, isLoading, ...rest }) => {
|
||||
if (!data) return null;
|
||||
|
||||
const [currentItem, setCurrentItem] = useState(
|
||||
@ -74,29 +75,40 @@ const Submenu = ({ data, startSelect = 0, onSelect, ...rest }) => {
|
||||
|
||||
return (
|
||||
<StyledSubmenu {...rest}>
|
||||
<StyledSubmenuItems ref={submenuItemsRef} role="list">
|
||||
{data.map((d) => {
|
||||
const isActive = d.id === currentItem.id;
|
||||
{isLoading ? (
|
||||
<LoaderSubmenu />
|
||||
) : (
|
||||
<>
|
||||
<StyledSubmenuItems ref={submenuItemsRef} role="list">
|
||||
{data.map((d) => {
|
||||
const isActive = d.id === currentItem.id;
|
||||
|
||||
return (
|
||||
<StyledSubmenuItem key={d.id} id={d.id} onClick={selectSubmenuItem}>
|
||||
<StyledSubmenuItemText>
|
||||
<Text
|
||||
color={isActive ? "#316DAA" : "#657077"}
|
||||
fontSize="13px"
|
||||
fontWeight="600"
|
||||
truncate={false}
|
||||
return (
|
||||
<StyledSubmenuItem
|
||||
key={d.id}
|
||||
id={d.id}
|
||||
onClick={selectSubmenuItem}
|
||||
>
|
||||
{d.name}
|
||||
</Text>
|
||||
</StyledSubmenuItemText>
|
||||
<StyledSubmenuItemLabel color={isActive ? "#316DAA" : "none"} />
|
||||
</StyledSubmenuItem>
|
||||
);
|
||||
})}
|
||||
</StyledSubmenuItems>
|
||||
<StyledSubmenuBottomLine />
|
||||
|
||||
<StyledSubmenuItemText>
|
||||
<Text
|
||||
color={isActive ? "#316DAA" : "#657077"}
|
||||
fontSize="13px"
|
||||
fontWeight="600"
|
||||
truncate={false}
|
||||
>
|
||||
{d.name}
|
||||
</Text>
|
||||
</StyledSubmenuItemText>
|
||||
<StyledSubmenuItemLabel
|
||||
color={isActive ? "#316DAA" : "none"}
|
||||
/>
|
||||
</StyledSubmenuItem>
|
||||
);
|
||||
})}
|
||||
</StyledSubmenuItems>
|
||||
<StyledSubmenuBottomLine />
|
||||
</>
|
||||
)}
|
||||
<StyledSubmenuContentWrapper>
|
||||
{currentItem.content}
|
||||
</StyledSubmenuContentWrapper>
|
||||
@ -108,6 +120,7 @@ Submenu.propTypes = {
|
||||
data: PropTypes.arrayOf(PropTypes.object.isRequired).isRequired,
|
||||
startSelect: PropTypes.oneOfType([PropTypes.object, PropTypes.number]),
|
||||
onSelect: PropTypes.func,
|
||||
isLoading: PropTypes.bool,
|
||||
};
|
||||
|
||||
export default Submenu;
|
||||
|
@ -1,5 +1,5 @@
|
||||
import React from "react";
|
||||
import styled from "styled-components";
|
||||
import styled, { css } from "styled-components";
|
||||
import Loaders from "@appserver/common/components/Loaders";
|
||||
import { isTablet } from "react-device-detect";
|
||||
|
@ -168,7 +168,7 @@ class TabContainer extends Component {
|
||||
selected={activeTab === index}
|
||||
isDisabled={isDisabled}
|
||||
>
|
||||
<Text className="title_style" fontSize="13px">
|
||||
<Text fontWeight={600} className="title_style" fontSize="13px">
|
||||
{item.title}
|
||||
</Text>
|
||||
</Label>
|
||||
|
@ -128,14 +128,6 @@ const Base = {
|
||||
medium: "0 32px",
|
||||
},
|
||||
|
||||
minWidth: {
|
||||
extraSmall: "none",
|
||||
small: "100px",
|
||||
normalDesktop: "100px",
|
||||
normalTouchscreen: "100px",
|
||||
medium: "100px",
|
||||
},
|
||||
|
||||
color: {
|
||||
base: black,
|
||||
baseHover: black,
|
||||
@ -520,6 +512,7 @@ const Base = {
|
||||
minHeight: "47px",
|
||||
width: "100%",
|
||||
borderBottom: globalColors.grayLightMid,
|
||||
backgroundColor: globalColors.lightHover,
|
||||
minWidth: "160px",
|
||||
overflow: "hidden",
|
||||
textOverflow: "ellipsis",
|
||||
@ -1904,7 +1897,6 @@ const Base = {
|
||||
|
||||
menuContainer: {
|
||||
background: "linear-gradient(200.71deg, #2274aa 0%, #0f4071 100%)",
|
||||
arrowTop: "#206FA4",
|
||||
color: white,
|
||||
},
|
||||
|
||||
@ -2416,6 +2408,13 @@ const Base = {
|
||||
border: `1px solid ${grayMid}`,
|
||||
borderBottom: `1px solid ${grayLightMid}`,
|
||||
|
||||
tile: {
|
||||
background: globalColors.lightHover,
|
||||
itemBackground: white,
|
||||
itemBorder: grayMid,
|
||||
itemActiveBorder: blueMain,
|
||||
},
|
||||
|
||||
fill: gray,
|
||||
hoverFill: grayMain,
|
||||
},
|
||||
|
@ -127,14 +127,6 @@ const Dark = {
|
||||
medium: "0 32px",
|
||||
},
|
||||
|
||||
minWidth: {
|
||||
extraSmall: "none",
|
||||
small: "100px",
|
||||
normalDesktop: "100px",
|
||||
normalTouchscreen: "100px",
|
||||
medium: "100px",
|
||||
},
|
||||
|
||||
color: {
|
||||
base: "#CCCCCC",
|
||||
baseHover: "#FAFAFA",
|
||||
@ -517,6 +509,7 @@ const Dark = {
|
||||
minHeight: "47px",
|
||||
width: "100%",
|
||||
borderBottom: "#474747",
|
||||
backgroundColor: globalColors.veryDarkGrey,
|
||||
minWidth: "160px",
|
||||
overflow: "hidden",
|
||||
textOverflow: "ellipsis",
|
||||
@ -1902,10 +1895,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: {
|
||||
@ -2426,6 +2417,13 @@ const Dark = {
|
||||
border: "1px solid #474747",
|
||||
borderBottom: "1px solid #474747",
|
||||
|
||||
tile: {
|
||||
background: globalColors.black,
|
||||
itemBackground: "#242424",
|
||||
itemBorder: gray,
|
||||
itemActiveBorder: "#eeeeee",
|
||||
},
|
||||
|
||||
fill: "#858585",
|
||||
hoverFill: "#eeeeee",
|
||||
},
|
||||
|
@ -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"
|
||||
}
|
||||
|
@ -19,5 +19,6 @@
|
||||
"StoringFileVersion": "Storing file versions",
|
||||
"ThirdPartyBtn": "Allow users to connect third-party storages",
|
||||
"ThirdPartySettings": "Connected clouds",
|
||||
"UpdateOrCreate": "Update the file version for the existing file with the same name. Otherwise, a copy of the file will be created."
|
||||
"UpdateOrCreate": "Update the file version for the existing file with the same name. Otherwise, a copy of the file will be created.",
|
||||
"Clouds": "Clouds"
|
||||
}
|
||||
|
@ -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": "В папке будет два разных файла.",
|
||||
|
@ -1,3 +1,4 @@
|
||||
{
|
||||
"NotAvailableFolder": "Нет доступных папок"
|
||||
}
|
||||
"NotAvailableFolder": "Нет доступных папок",
|
||||
"FolderContents": "Содержимое папки '{{folderTitle}}'"
|
||||
}
|
||||
|
@ -19,5 +19,6 @@
|
||||
"StoringFileVersion": "Хранение версий файлов",
|
||||
"ThirdPartyBtn": "Разрешить пользователям подключать сторонние хранилища",
|
||||
"ThirdPartySettings": "Подключенные облака",
|
||||
"UpdateOrCreate": "Обновлять версию файла для существующего файла с таким же именем. В противном случае будет создаваться копия файла."
|
||||
"UpdateOrCreate": "Обновлять версию файла для существующего файла с таким же именем. В противном случае будет создаваться копия файла.",
|
||||
"Clouds": "Облака"
|
||||
}
|
||||
|
@ -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": "跳过"
|
||||
}
|
||||
}
|
||||
|
@ -11,6 +11,16 @@ export const StyledIcon = styled(IconButton)`
|
||||
${commonIconsStyles}
|
||||
`;
|
||||
|
||||
const StyledEditIcon = styled(IconButton)`
|
||||
${commonIconsStyles}
|
||||
|
||||
svg {
|
||||
path {
|
||||
fill: ${(props) => props.theme.filesSection.rowView.editingIconColor};
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
const StyledWrapper = styled.div`
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
@ -129,7 +139,7 @@ const Badges = ({
|
||||
/>
|
||||
)}
|
||||
{isEditing && (
|
||||
<StyledIcon
|
||||
<StyledEditIcon
|
||||
iconName={iconEdit}
|
||||
className="badge icons-group is-editing tablet-badge tablet-edit"
|
||||
size={sizeBadge}
|
||||
|
@ -53,15 +53,30 @@ const EditingWrapper = styled.div`
|
||||
border-bottom: ${(props) => props.theme.filesEditingWrapper.borderBottom};
|
||||
padding-bottom: 4px;
|
||||
margin-top: 4px;
|
||||
|
||||
/* margin-left: -4px; */
|
||||
`}
|
||||
|
||||
${(props) =>
|
||||
props.viewAs === "tile" &&
|
||||
`margin-right: 10px !important; margin-left: 8px;`}
|
||||
|
||||
|
||||
css`
|
||||
position: absolute;
|
||||
width: calc(100% - 18px);
|
||||
z-index: 1;
|
||||
gap: 4px;
|
||||
|
||||
background-color: ${(props) =>
|
||||
props.theme.filesEditingWrapper.tile.background};
|
||||
|
||||
border: ${(props) => props.theme.filesEditingWrapper.border};
|
||||
border-radius: 0 0 6px 6px;
|
||||
|
||||
height: 43px;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
padding: 9px 8px 9px 8px;
|
||||
`}
|
||||
|
||||
|
||||
@media ${tablet} {
|
||||
height: 56px;
|
||||
}
|
||||
@ -96,26 +111,37 @@ const EditingWrapper = styled.div`
|
||||
`}
|
||||
|
||||
${(props) => props.viewAs === "table" && `padding-left: 12px`}
|
||||
|
||||
${(props) =>
|
||||
props.viewAs === "tile" &&
|
||||
css`
|
||||
background: #fff;
|
||||
border: ${(props) =>
|
||||
`1px solid ${props.theme.filesEditingWrapper.tile.itemBorder}`};
|
||||
|
||||
&:focus {
|
||||
border: ${(props) =>
|
||||
`1px solid ${props.theme.filesEditingWrapper.tile.itemActiveBorder}`};
|
||||
}
|
||||
`};
|
||||
}
|
||||
|
||||
.edit-button {
|
||||
margin-left: 8px;
|
||||
height: 32px;
|
||||
padding: 8px 7px 7px 7px;
|
||||
padding: 0px 7px 0px 7px;
|
||||
|
||||
${(props) =>
|
||||
props.viewAs === "tile" &&
|
||||
css`
|
||||
margin-left: 0px;
|
||||
background: none;
|
||||
border: 1px solid transparent;
|
||||
background: #fff;
|
||||
border: ${(props) =>
|
||||
`1px solid ${props.theme.filesEditingWrapper.tile.itemBorder}`};
|
||||
|
||||
:hover {
|
||||
border: ${(props) => props.theme.filesEditingWrapper.border};
|
||||
}
|
||||
|
||||
&:last-child {
|
||||
margin-left: 2px;
|
||||
&:hover {
|
||||
border: ${(props) =>
|
||||
`1px solid ${props.theme.filesEditingWrapper.tile.itemActiveBorder}`};
|
||||
}
|
||||
`};
|
||||
|
||||
@ -125,22 +151,23 @@ const EditingWrapper = styled.div`
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
border: 1px transparent;
|
||||
padding: 4px 0 0 0;
|
||||
padding: 0;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
|
||||
:hover {
|
||||
&:hover {
|
||||
border: ${(props) => props.theme.filesEditingWrapper.border};
|
||||
}
|
||||
`}
|
||||
}
|
||||
|
||||
.edit-ok-icon {
|
||||
margin-top: -6px;
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
}
|
||||
|
||||
.edit-cancel-icon {
|
||||
margin-top: -6px;
|
||||
width: 14px;
|
||||
height: 14px;
|
||||
padding: 1px;
|
||||
|
@ -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";
|
||||
@ -30,6 +30,8 @@ const StyledModalDialog = styled(ModalDialog)`
|
||||
|
||||
svg {
|
||||
overflow: visible;
|
||||
margin-right: 8px;
|
||||
margin-top: 3px
|
||||
}
|
||||
|
||||
.radio-option-title {
|
||||
@ -49,7 +51,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;
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
@ -67,6 +82,7 @@ const ConflictResolveDialog = (props) => {
|
||||
setMoveToPanelVisible,
|
||||
setCopyPanelVisible,
|
||||
setThirdPartyMoveDialogVisible,
|
||||
theme,
|
||||
} = props;
|
||||
|
||||
const {
|
||||
@ -242,7 +258,7 @@ const ConflictResolveDialog = (props) => {
|
||||
);
|
||||
};
|
||||
|
||||
export default inject(({ dialogsStore, uploadDataStore, filesStore }) => {
|
||||
export default inject(({ auth, dialogsStore, uploadDataStore, filesStore }) => {
|
||||
const {
|
||||
conflictResolveDialogVisible: visible,
|
||||
setConflictResolveDialogVisible,
|
||||
@ -255,8 +271,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,
|
||||
|
@ -8,88 +8,78 @@ import ModalDialog from "@appserver/components/modal-dialog";
|
||||
import Text from "@appserver/components/text";
|
||||
import Link from "@appserver/components/link";
|
||||
import { connectedCloudsTitleTranslation } from "../../../helpers/utils";
|
||||
import NoUserSelect from "@appserver/components/utils/commonStyles";
|
||||
import { Base } from "@appserver/components/themes";
|
||||
import Button from "@appserver/components/button";
|
||||
import SelectorAddButton from "@appserver/components/selector-add-button";
|
||||
import { isMobile } from "react-device-detect";
|
||||
|
||||
const StyledServicesBlock = styled.div`
|
||||
display: grid;
|
||||
column-gap: 55px;
|
||||
row-gap: 20px;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
grid-template-columns: repeat(auto-fill, 158px);
|
||||
padding-top: 24px;
|
||||
|
||||
.service-item {
|
||||
border: ${(props) => props.theme.filesThirdPartyDialog.border};
|
||||
width: 158px;
|
||||
height: 40px;
|
||||
|
||||
:hover {
|
||||
cursor: pointer;
|
||||
}
|
||||
const StyledModalDialog = styled(ModalDialog)`
|
||||
.modal-dialog-aside-body {
|
||||
margin-right: -16px;
|
||||
}
|
||||
|
||||
.service-item__svg {
|
||||
${NoUserSelect}
|
||||
border: ${(props) => props.theme.filesThirdPartyDialog.border};
|
||||
width: 158px;
|
||||
height: 40px;
|
||||
.service-block {
|
||||
padding-top: 20px;
|
||||
display: grid;
|
||||
grid-gap: 16px;
|
||||
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-item: center;
|
||||
.service-item-container {
|
||||
display: flex;
|
||||
|
||||
:hover {
|
||||
cursor: pointer;
|
||||
}
|
||||
.service-name-container {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
${(props) =>
|
||||
!props.theme.isBase &&
|
||||
css`
|
||||
svg {
|
||||
rect {
|
||||
fill: #333333;
|
||||
}
|
||||
path {
|
||||
fill: #ffffff;
|
||||
opacity: 0.16;
|
||||
.service-item__svg {
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
margin-right: 8px;
|
||||
}
|
||||
.kDrive {
|
||||
svg {
|
||||
path:nth-child(7) {
|
||||
opacity: 0.5 !important;
|
||||
}
|
||||
path:nth-child(8) {
|
||||
opacity: 0.8 !important;
|
||||
}
|
||||
path:nth-child(9) {
|
||||
opacity: 0.8 !important;
|
||||
}
|
||||
path:nth-child(10) {
|
||||
opacity: 0.16 !important;
|
||||
}
|
||||
path:nth-child(11) {
|
||||
opacity: 0.16 !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
`}
|
||||
}
|
||||
}
|
||||
|
||||
.kDrive {
|
||||
svg {
|
||||
path:nth-child(7) {
|
||||
opacity: 0.5 !important;
|
||||
}
|
||||
path:nth-child(8) {
|
||||
opacity: 0.8 !important;
|
||||
}
|
||||
path:nth-child(9) {
|
||||
opacity: 0.8 !important;
|
||||
}
|
||||
path:nth-child(10) {
|
||||
opacity: 0.16 !important;
|
||||
}
|
||||
path:nth-child(11) {
|
||||
opacity: 0.16 !important;
|
||||
.service-btn {
|
||||
margin-left: auto;
|
||||
|
||||
svg {
|
||||
path {
|
||||
fill: #333;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.service-text {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
`;
|
||||
|
||||
StyledServicesBlock.defaultProps = { theme: Base };
|
||||
StyledModalDialog.defaultProps = { theme: Base };
|
||||
|
||||
const ServiceItem = (props) => {
|
||||
const { capability, t, className, ...rest } = props;
|
||||
const {
|
||||
t,
|
||||
capability,
|
||||
className,
|
||||
getThirdPartyIcon,
|
||||
serviceName,
|
||||
onClick,
|
||||
} = props;
|
||||
|
||||
const capabilityName = capability[0];
|
||||
const capabilityLink = capability.length > 1 ? capability[1] : "";
|
||||
@ -100,13 +90,38 @@ const ServiceItem = (props) => {
|
||||
"data-key": capabilityName,
|
||||
};
|
||||
|
||||
const src = getThirdPartyIcon(capabilityName);
|
||||
|
||||
return (
|
||||
<ReactSVG
|
||||
{...dataProps}
|
||||
{...rest}
|
||||
className={`service-item__svg ${className}`}
|
||||
alt=""
|
||||
/>
|
||||
<div className="service-item-container">
|
||||
<div className="service-name-container">
|
||||
<ReactSVG
|
||||
src={src}
|
||||
className={`service-item__svg ${className}`}
|
||||
alt=""
|
||||
/>
|
||||
<Text fontWeight={600} fontSize="14px">
|
||||
{serviceName ? serviceName : capabilityName}
|
||||
</Text>
|
||||
</div>
|
||||
{isMobile ? (
|
||||
<SelectorAddButton
|
||||
onClick={onClick}
|
||||
iconName="/static/images/actions.plus.icon.react.svg"
|
||||
className="service-btn"
|
||||
title={t("Common:Connect")}
|
||||
{...dataProps}
|
||||
/>
|
||||
) : (
|
||||
<Button
|
||||
size="small"
|
||||
className="service-btn"
|
||||
label={t("Common:Connect")}
|
||||
onClick={onClick}
|
||||
{...dataProps}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
@ -133,6 +148,7 @@ const ThirdPartyDialog = (props) => {
|
||||
getOAuthToken,
|
||||
setConnectDialogVisible,
|
||||
setConnectItem,
|
||||
getThirdPartyIcon,
|
||||
} = props;
|
||||
|
||||
const onClose = () => {
|
||||
@ -178,13 +194,8 @@ const ThirdPartyDialog = (props) => {
|
||||
setThirdPartyDialogVisible(false);
|
||||
};
|
||||
|
||||
const yandexLogoUrl =
|
||||
i18n && i18n.language === "ru-RU"
|
||||
? "images/services/logo_yandex_ru.svg"
|
||||
: "images/services/logo_yandex_en.svg";
|
||||
|
||||
return (
|
||||
<ModalDialog
|
||||
<StyledModalDialog
|
||||
isLoading={!tReady}
|
||||
visible={visible}
|
||||
scale={false}
|
||||
@ -209,100 +220,110 @@ const ThirdPartyDialog = (props) => {
|
||||
</Trans>
|
||||
)}
|
||||
</Text>
|
||||
<StyledServicesBlock>
|
||||
<div className="service-block">
|
||||
{googleConnectItem && (
|
||||
<ServiceItem
|
||||
t={t}
|
||||
capability={googleConnectItem}
|
||||
onClick={onShowService}
|
||||
src="images/services/logo_google-drive.svg"
|
||||
getThirdPartyIcon={getThirdPartyIcon}
|
||||
/>
|
||||
)}
|
||||
|
||||
{boxConnectItem && (
|
||||
<ServiceItem
|
||||
t={t}
|
||||
capability={boxConnectItem}
|
||||
onClick={onShowService}
|
||||
src="images/services/logo_box.svg"
|
||||
getThirdPartyIcon={getThirdPartyIcon}
|
||||
/>
|
||||
)}
|
||||
|
||||
{dropboxConnectItem && (
|
||||
<ServiceItem
|
||||
t={t}
|
||||
capability={dropboxConnectItem}
|
||||
onClick={onShowService}
|
||||
src="images/services/logo_dropbox.svg"
|
||||
getThirdPartyIcon={getThirdPartyIcon}
|
||||
/>
|
||||
)}
|
||||
|
||||
{sharePointConnectItem && (
|
||||
<ServiceItem
|
||||
t={t}
|
||||
capability={sharePointConnectItem}
|
||||
onClick={onShowService}
|
||||
src={"images/services/logo_sharepoint.svg"}
|
||||
getThirdPartyIcon={getThirdPartyIcon}
|
||||
/>
|
||||
)}
|
||||
|
||||
{oneDriveConnectItem && (
|
||||
<ServiceItem
|
||||
t={t}
|
||||
capability={oneDriveConnectItem}
|
||||
onClick={onShowService}
|
||||
src="images/services/logo_onedrive.svg"
|
||||
getThirdPartyIcon={getThirdPartyIcon}
|
||||
/>
|
||||
)}
|
||||
|
||||
{sharePointConnectItem && (
|
||||
{/* {sharePointConnectItem && (
|
||||
<ServiceItem
|
||||
t={t}
|
||||
capability={sharePointConnectItem}
|
||||
onClick={onShowService}
|
||||
src={"images/services/logo_onedrive-for-business.svg"}
|
||||
getThirdPartyIcon={getThirdPartyIcon}
|
||||
/>
|
||||
)}
|
||||
)} */}
|
||||
|
||||
{nextCloudConnectItem && (
|
||||
<ServiceItem
|
||||
t={t}
|
||||
serviceName="Nextcloud"
|
||||
capability={webDavConnectItem}
|
||||
onClick={onShowService}
|
||||
src="images/services/logo_nextcloud.svg"
|
||||
getThirdPartyIcon={getThirdPartyIcon}
|
||||
/>
|
||||
)}
|
||||
|
||||
{ownCloudConnectItem && (
|
||||
<ServiceItem
|
||||
t={t}
|
||||
serviceName="ownCloud"
|
||||
capability={webDavConnectItem}
|
||||
onClick={onShowService}
|
||||
src="images/services/logo_owncloud.svg"
|
||||
getThirdPartyIcon={getThirdPartyIcon}
|
||||
/>
|
||||
)}
|
||||
|
||||
{kDriveConnectItem && (
|
||||
<ServiceItem
|
||||
t={t}
|
||||
capability={kDriveConnectItem}
|
||||
onClick={onShowService}
|
||||
className={"kDrive"}
|
||||
src="images/services/logo_kdrive.svg"
|
||||
getThirdPartyIcon={getThirdPartyIcon}
|
||||
/>
|
||||
)}
|
||||
{yandexConnectItem && (
|
||||
<ServiceItem
|
||||
t={t}
|
||||
capability={yandexConnectItem}
|
||||
onClick={onShowService}
|
||||
src={yandexLogoUrl}
|
||||
getThirdPartyIcon={getThirdPartyIcon}
|
||||
/>
|
||||
)}
|
||||
{webDavConnectItem && (
|
||||
<Text
|
||||
<ServiceItem
|
||||
t={t}
|
||||
serviceName={t("ConnextOtherAccount")}
|
||||
capability={webDavConnectItem}
|
||||
onClick={onShowService}
|
||||
className="service-item service-text"
|
||||
data-title={webDavConnectItem[0]}
|
||||
data-key={webDavConnectItem[0]}
|
||||
noSelect
|
||||
>
|
||||
{t("ConnextOtherAccount")}
|
||||
</Text>
|
||||
getThirdPartyIcon={getThirdPartyIcon}
|
||||
/>
|
||||
)}
|
||||
</StyledServicesBlock>
|
||||
</div>
|
||||
</ModalDialog.Body>
|
||||
</ModalDialog>
|
||||
</StyledModalDialog>
|
||||
);
|
||||
};
|
||||
|
||||
@ -319,6 +340,7 @@ export default inject(({ auth, settingsStore, dialogsStore }) => {
|
||||
webDavConnectItem,
|
||||
sharePointConnectItem,
|
||||
openConnectWindow,
|
||||
getThirdPartyIcon,
|
||||
} = settingsStore.thirdPartyStore;
|
||||
const {
|
||||
setThirdPartyDialogVisible,
|
||||
@ -348,5 +370,10 @@ export default inject(({ auth, settingsStore, dialogsStore }) => {
|
||||
setThirdPartyDialogVisible,
|
||||
getOAuthToken,
|
||||
openConnectWindow,
|
||||
getThirdPartyIcon,
|
||||
};
|
||||
})(withTranslation(["Settings", "Translations"])(observer(ThirdPartyDialog)));
|
||||
})(
|
||||
withTranslation(["Settings", "Translations, Common"])(
|
||||
observer(ThirdPartyDialog)
|
||||
)
|
||||
);
|
||||
|
@ -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));
|
@ -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,
|
||||
};
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user