Merge branch 'develop' into feature/catalog

This commit is contained in:
Timofey Boyko 2021-10-22 15:43:23 +08:00
commit 94cbac3c02
61 changed files with 1198 additions and 516 deletions

View File

@ -26,6 +26,7 @@
"deploy:personal": "shx rm -rf build/deploy/products && shx rm -rf build/deploy/public && shx rm -rf build/deploy/studio && lerna run deploy --parallel --scope {@appserver/studio,@appserver/people,@appserver/files,@appserver/editor} && shx cp -r public build/deploy", "deploy:personal": "shx rm -rf build/deploy/products && shx rm -rf build/deploy/public && shx rm -rf build/deploy/studio && lerna run deploy --parallel --scope {@appserver/studio,@appserver/people,@appserver/files,@appserver/editor} && shx cp -r public build/deploy",
"serve": "lerna run serve --parallel --ignore @appserver/common --ignore @appserver/components --ignore @appserver/browserslist-config-asc --ignore @appserver/debug-info", "serve": "lerna run serve --parallel --ignore @appserver/common --ignore @appserver/components --ignore @appserver/browserslist-config-asc --ignore @appserver/debug-info",
"start": "lerna run start --parallel --ignore @appserver/common --ignore @appserver/components --ignore @appserver/browserslist-config-asc --ignore @appserver/debug-info", "start": "lerna run start --parallel --ignore @appserver/common --ignore @appserver/components --ignore @appserver/browserslist-config-asc --ignore @appserver/debug-info",
"start:personal": "lerna run start --parallel --scope {@appserver/studio,@appserver/people,@appserver/files,@appserver/editor}",
"start-prod": "lerna run start-prod --parallel --ignore @appserver/common --ignore @appserver/components --ignore @appserver/browserslist-config-asc --ignore @appserver/debug-info", "start-prod": "lerna run start-prod --parallel --ignore @appserver/common --ignore @appserver/components --ignore @appserver/browserslist-config-asc --ignore @appserver/debug-info",
"storybook": "yarn workspace @appserver/components storybook", "storybook": "yarn workspace @appserver/components storybook",
"storybook-build": "yarn workspace @appserver/components run storybook-build", "storybook-build": "yarn workspace @appserver/components run storybook-build",

View File

@ -36,7 +36,7 @@ RectangleLoader.propTypes = {
backgroundOpacity: PropTypes.number, backgroundOpacity: PropTypes.number,
foregroundOpacity: PropTypes.number, foregroundOpacity: PropTypes.number,
speed: PropTypes.number, speed: PropTypes.number,
animate: PropTypes.bool, animate: PropTypes.oneOfType([PropTypes.bool, PropTypes.number]),
}; };
RectangleLoader.defaultProps = { RectangleLoader.defaultProps = {

View File

@ -13,6 +13,7 @@ import equal from "fast-deep-equal/react";
import Hammer from "hammerjs"; import Hammer from "hammerjs";
import IconButton from "@appserver/components/icon-button"; import IconButton from "@appserver/components/icon-button";
import commonIconsStyles from "@appserver/components/utils/common-icons-style"; import commonIconsStyles from "@appserver/components/utils/common-icons-style";
import { isDesktop } from "react-device-detect";
const StyledVideoViewer = styled(VideoViewer)` const StyledVideoViewer = styled(VideoViewer)`
z-index: 301; z-index: 301;
@ -104,7 +105,7 @@ class MediaViewer extends React.Component {
document.getElementsByClassName("videoViewerOverlay")[0] document.getElementsByClassName("videoViewerOverlay")[0]
); );
} }
if (_this.hammer) { if (_this.hammer && !isDesktop) {
_this.hammer.on("swipeleft", _this.nextMedia); _this.hammer.on("swipeleft", _this.nextMedia);
_this.hammer.on("swiperight", _this.prevMedia); _this.hammer.on("swiperight", _this.prevMedia);
} }

View File

@ -394,7 +394,7 @@ class PageLayout extends React.Component {
display: 'grid', display: 'grid',
paddingRight: '20px', paddingRight: '20px',
}}></div> }}></div>
<SubSectionFilter className="section-header_filter"> <SubSectionFilter className="section-header_filter" viewAs={viewAs}>
{sectionFilterContent ? sectionFilterContent.props.children : null} {sectionFilterContent ? sectionFilterContent.props.children : null}
</SubSectionFilter> </SubSectionFilter>
</> </>

View File

@ -10,22 +10,37 @@ import Scrollbar from "@appserver/components/scrollbar";
import DragAndDrop from "@appserver/components/drag-and-drop"; import DragAndDrop from "@appserver/components/drag-and-drop";
import { tablet } from "@appserver/components/utils/device"; import { tablet } from "@appserver/components/utils/device";
const paddingStyles = css`
padding: 17px 7px 16px 24px;
@media ${tablet} {
padding: 16px 0 16px 24px;
}
`;
const commonStyles = css` const commonStyles = css`
flex-grow: 1; flex-grow: 1;
height: 100%; ${(props) => !props.withScroll && `height: 100%;`}
border-left: none; border-left: none;
-webkit-user-select: none; -webkit-user-select: none;
.section-wrapper-content { .section-wrapper {
flex: 1 0 auto; ${(props) =>
padding: 17px 7px 16px 24px; !props.withScroll &&
outline: none; `display: flex; height: 100%; box-sizing:border-box`};
${(props) => props.viewAs == "tile" && "padding-right:0;"} ${(props) => !props.withScroll && paddingStyles}
}
@media ${tablet} { .section-wrapper-content {
padding: 16px 0 16px 24px; ${paddingStyles}
} flex: 1 0 auto;
outline: none;
${(props) =>
props.viewAs == "tile" &&
css`
padding-right: 0;
padding-left: 20px;
`}
.section-wrapper { .section-wrapper {
display: flex; display: flex;
@ -48,7 +63,16 @@ const StyledSectionBody = styled.div`
` `
margin-left: -24px; margin-left: -24px;
`} `}
.additional-scroll-height {
${(props) =>
!props.withScroll &&
!props.pinned &&
` height: 64px;
`}
}
`; `;
const StyledDropZoneBody = styled(DragAndDrop)` const StyledDropZoneBody = styled(DragAndDrop)`
@ -87,8 +111,9 @@ class SectionBody extends React.Component {
// } // }
componentDidMount() { componentDidMount() {
const { withScroll } = this.props;
if (!this.props.autoFocus) return; if (!this.props.autoFocus) return;
this.focusRef.current.focus(); if (withScroll) this.focusRef.current.focus();
} }
componentWillUnmount() { componentWillUnmount() {
@ -176,10 +201,7 @@ class SectionBody extends React.Component {
</div> </div>
) )
) : ( ) : (
<div className="section-wrapper"> <div className="section-wrapper">{children}</div>
{children}
<StyledSpacer pinned={pinned} />
</div>
)} )}
</StyledSectionBody> </StyledSectionBody>
); );

View File

@ -1,11 +1,20 @@
import React from "react"; import React from "react";
import styled from "styled-components"; import styled, { css } from "styled-components";
import equal from "fast-deep-equal/react"; import equal from "fast-deep-equal/react";
import { tablet } from "@appserver/components/utils/device"; import { tablet, desktop } from "@appserver/components/utils/device";
const StyledSectionFilter = styled.div` const StyledSectionFilter = styled.div`
margin: 11px 24px 9px 0; margin: 11px 24px 9px 0;
@media ${desktop} {
${(props) =>
(props.viewAs === "table" || props.viewAs === "tile") &&
css`
margin-left: -4px;
margin-right: 20px;
`};
}
@media ${tablet} { @media ${tablet} {
margin-left: -4px; margin-left: -4px;
} }

View File

@ -25,7 +25,12 @@ const StyledSectionHeader = styled.div`
} */ } */
`} `}
@media ${desktop} {
${(props) =>
(props.viewAs === "table" || props.viewAs === "tile") &&
"margin-left: -4px"};
}
@media ${tablet} { @media ${tablet} {
${(props) => ${(props) =>
props.viewAs !== "tablet" && props.viewAs !== "tablet" &&

View File

@ -53,8 +53,8 @@ class FirebaseHelper {
this.config["projectId"] && this.config["projectId"] &&
this.config["storageBucket"] && this.config["storageBucket"] &&
this.config["messagingSenderId"] && this.config["messagingSenderId"] &&
this.config["appId"] && this.config["appId"] /*&&
this.config["measurementId"] this.config["measurementId"]*/
); );
} }

View File

@ -13,6 +13,7 @@ const Aside = React.memo((props) => {
zIndex, zIndex,
className, className,
contentPaddingBottom, contentPaddingBottom,
withoutBodyScroll,
} = props; } = props;
return ( return (
@ -23,7 +24,11 @@ const Aside = React.memo((props) => {
contentPaddingBottom={contentPaddingBottom} contentPaddingBottom={contentPaddingBottom}
className={`${className} not-selectable aside`} className={`${className} not-selectable aside`}
> >
<Scrollbar>{children}</Scrollbar> {withoutBodyScroll ? (
children
) : (
<Scrollbar stype="mediumBlack">{children}</Scrollbar>
)}
</StyledAside> </StyledAside>
); );
}); });
@ -40,10 +45,12 @@ Aside.propTypes = {
PropTypes.arrayOf(PropTypes.node), PropTypes.arrayOf(PropTypes.node),
PropTypes.node, PropTypes.node,
]), ]),
withoutBodyScroll: PropTypes.bool,
}; };
Aside.defaultProps = { Aside.defaultProps = {
scale: false, scale: false,
zIndex: 400, zIndex: 400,
withoutBodyScroll: false,
}; };
export default Aside; export default Aside;

View File

@ -311,7 +311,13 @@ class AvatarEditorBody extends React.Component {
const desktopMode = isDesktop(); const desktopMode = isDesktop();
return ( return (
<Text as="span"> <Text as="span">
<Link type="action" isHovered color="#316DAA" onClick={this.openDialog}> <Link
type="action"
fontWeight={600}
isHovered
color="#316DAA"
onClick={this.openDialog}
>
{selectNewPhotoLabel} {selectNewPhotoLabel}
</Link>{" "} </Link>{" "}
{desktopMode && orDropFileHereLabel} {desktopMode && orDropFileHereLabel}

View File

@ -27,5 +27,4 @@ Default.args = {
source: "", source: "",
userName: "", userName: "",
editing: false, editing: false,
editLabel: "Edit photo",
}; };

View File

@ -4,7 +4,6 @@ import styled from "styled-components";
import { GuestIcon, AdministratorIcon, OwnerIcon } from "./svg"; import { GuestIcon, AdministratorIcon, OwnerIcon } from "./svg";
import { import {
EditLink,
EmptyIcon, EmptyIcon,
EditContainer, EditContainer,
AvatarWrapper, AvatarWrapper,
@ -13,7 +12,7 @@ import {
StyledImage, StyledImage,
StyledAvatar, StyledAvatar,
} from "./styled-avatar"; } from "./styled-avatar";
import Link from "../link"; import IconButton from "../icon-button";
import commonIconsStyles from "../utils/common-icons-style"; import commonIconsStyles from "../utils/common-icons-style";
const whiteColor = "#FFFFFF"; const whiteColor = "#FFFFFF";
@ -57,15 +56,7 @@ Initials.propTypes = {
// eslint-disable-next-line react/display-name // eslint-disable-next-line react/display-name
const Avatar = (props) => { const Avatar = (props) => {
//console.log("Avatar render"); //console.log("Avatar render");
const { const { size, source, userName, role, editing, editAction } = props;
size,
source,
userName,
role,
editing,
editLabel,
editAction,
} = props;
const avatarContent = source ? ( const avatarContent = source ? (
<StyledImage src={source} /> <StyledImage src={source} />
@ -83,21 +74,13 @@ const Avatar = (props) => {
{avatarContent} {avatarContent}
</AvatarWrapper> </AvatarWrapper>
{editing && size === "max" && ( {editing && size === "max" && (
<EditContainer gradient={!!source}> <EditContainer>
<EditLink> <IconButton
<Link color={whiteColor}
type="action" iconName="/static/images/pencil.react.svg"
title={editLabel} onClick={editAction}
isTextOverflow={true} size={16}
isHovered={true} />
fontSize="14px"
fontWeight={600}
color={whiteColor}
onClick={editAction}
>
{editLabel}
</Link>
</EditLink>
</EditContainer> </EditContainer>
)} )}
<RoleWrapper size={size}>{roleIcon}</RoleWrapper> <RoleWrapper size={size}>{roleIcon}</RoleWrapper>
@ -112,8 +95,6 @@ Avatar.propTypes = {
role: PropTypes.oneOf(["owner", "admin", "guest", "user"]), role: PropTypes.oneOf(["owner", "admin", "guest", "user"]),
/** The address of the image for an image avatar */ /** The address of the image for an image avatar */
source: PropTypes.string, source: PropTypes.string,
/** Displays avatar edit layer */
editLabel: PropTypes.string,
userName: PropTypes.string, userName: PropTypes.string,
editing: PropTypes.bool, editing: PropTypes.bool,
/** Function called when the avatar change button is pressed */ /** Function called when the avatar change button is pressed */
@ -130,7 +111,6 @@ Avatar.defaultProps = {
size: "medium", size: "medium",
role: "", role: "",
source: "", source: "",
editLabel: "Edit photo",
userName: "", userName: "",
editing: false, editing: false,
}; };

View File

@ -5,23 +5,6 @@ import NoUserSelect from "../utils/commonStyles";
import { CameraIcon } from "./svg"; import { CameraIcon } from "./svg";
import commonIconsStyles from "../utils/common-icons-style"; import commonIconsStyles from "../utils/common-icons-style";
const EditLink = styled.div`
padding-left: ${(props) => props.theme.avatar.editLink.paddingLeft};
padding-right: ${(props) => props.theme.avatar.editLink.paddingRight};
a:hover {
border-bottom: ${(props) => props.theme.avatar.editLink.borderBottom};
}
span {
display: ${(props) => props.theme.avatar.editLink.display};
max-width: ${(props) => props.theme.avatar.editLink.maxWidth};
text-decoration: ${(props) => props.theme.avatar.editLink.textDecoration};
}
`;
EditLink.defaultProps = { theme: Base };
const EmptyIcon = styled(CameraIcon)` const EmptyIcon = styled(CameraIcon)`
${commonIconsStyles} ${commonIconsStyles}
border-radius: ${(props) => props.theme.avatar.image.borderRadius}; border-radius: ${(props) => props.theme.avatar.image.borderRadius};
@ -29,21 +12,17 @@ const EmptyIcon = styled(CameraIcon)`
EmptyIcon.defaultProps = { theme: Base }; EmptyIcon.defaultProps = { theme: Base };
const EditContainer = styled.div` const EditContainer = styled.div`
box-sizing: ${(props) => props.theme.avatar.editContainer.boxSizing};
position: absolute; position: absolute;
width: ${(props) => props.theme.avatar.editContainer.width}; display: flex;
height: ${(props) => props.theme.avatar.editContainer.height}; right: ${(props) => props.theme.avatar.editContainer.right};
top: ${(props) => props.theme.avatar.editContainer.top}; bottom: ${(props) => props.theme.avatar.editContainer.bottom};
left: ${(props) => props.theme.avatar.editContainer.left}; background-color: ${(props) =>
transform: ${(props) => props.theme.avatar.editContainer.transform}; props.theme.avatar.editContainer.backgroundColor};
padding: ${(props) => props.theme.avatar.editContainer.padding};
text-align: ${(props) => props.theme.avatar.editContainer.textAlign};
line-height: ${(props) => props.theme.avatar.editContainer.lineHeight};
border-radius: ${(props) => props.theme.avatar.editContainer.borderRadius}; border-radius: ${(props) => props.theme.avatar.editContainer.borderRadius};
background: ${(props) => height: ${(props) => props.theme.avatar.editContainer.height};
props.gradient width: ${(props) => props.theme.avatar.editContainer.width};
? props.theme.avatar.editContainer.linearGradient align-items: center;
: props.theme.avatar.editContainer.transparent}; justify-content: center;
`; `;
EditContainer.defaultProps = { theme: Base }; EditContainer.defaultProps = { theme: Base };
@ -129,7 +108,6 @@ const StyledAvatar = styled.div`
StyledAvatar.defaultProps = { theme: Base }; StyledAvatar.defaultProps = { theme: Base };
export { export {
EditLink,
EmptyIcon, EmptyIcon,
EditContainer, EditContainer,
AvatarWrapper, AvatarWrapper,

View File

@ -32,7 +32,7 @@ class ContextMenuSub extends Component {
}); });
} }
onItemClick(e, item) { onItemClick(item, e) {
if (item.disabled) { if (item.disabled) {
e.preventDefault(); e.preventDefault();
return; return;
@ -157,13 +157,16 @@ class ContextMenuSub extends Component {
const dataKeys = Object.fromEntries( const dataKeys = Object.fromEntries(
Object.entries(item).filter((el) => el[0].indexOf("data-") === 0) Object.entries(item).filter((el) => el[0].indexOf("data-") === 0)
); );
const onClick = (e) => {
this.onItemClick(item, e);
};
let content = ( let content = (
<a <a
href={item.url || "#"} href={item.url || "#"}
className={linkClassName} className={linkClassName}
target={item.target} target={item.target}
{...dataKeys} {...dataKeys}
onClick={(event) => this.onItemClick(event, item, index)} onClick={onClick}
role="menuitem" role="menuitem"
> >
{icon} {icon}
@ -174,7 +177,7 @@ class ContextMenuSub extends Component {
if (item.template) { if (item.template) {
const defaultContentOptions = { const defaultContentOptions = {
onClick: (event) => this.onItemClick(event, item, index), onClick,
className: linkClassName, className: linkClassName,
labelClassName: "p-menuitem-text", labelClassName: "p-menuitem-text",
iconClassName, iconClassName,

View File

@ -80,7 +80,7 @@ class DropDown extends React.PureComponent {
const left = rects.left < 0 && rects.width < container.width; const left = rects.left < 0 && rects.width < container.width;
const right = const right =
rects.width && rects.width &&
rects.left < 250 && rects.left < (rects.width || 250) &&
rects.left > rects.width && rects.left > rects.width &&
rects.width < container.width; rects.width < container.width;
const top = rects.bottom > container.height && rects.top > rects.height; const top = rects.bottom > container.height && rects.top > rects.height;

View File

@ -2,7 +2,7 @@
import React from "react"; import React from "react";
import Scrollbar from "../scrollbar"; import Scrollbar from "../scrollbar";
class CustomScrollbars extends React.Component { export class CustomScrollbars extends React.Component {
refSetter = (scrollbarsRef, forwardedRef) => { refSetter = (scrollbarsRef, forwardedRef) => {
if (scrollbarsRef) { if (scrollbarsRef) {
forwardedRef(scrollbarsRef.view); forwardedRef(scrollbarsRef.view);
@ -32,6 +32,7 @@ class CustomScrollbars extends React.Component {
className={className} className={className}
> >
{children} {children}
<div className="additional-scroll-height"></div>
</Scrollbar> </Scrollbar>
); );
} }

View File

@ -16,6 +16,11 @@ const StyledScrollbar = styled(Scrollbars)`
? props.color ? props.color
: props.theme.scrollbar.backgroundColorHorizontal}; : props.theme.scrollbar.backgroundColorHorizontal};
} }
.nav-thumb-vertical:hover {
background-color: ${(props) =>
props.theme.scrollbar.hoverBackgroundColorVertical};
}
`; `;
StyledScrollbar.defaultProps = { StyledScrollbar.defaultProps = {

View File

@ -478,8 +478,9 @@ const Base = {
}, },
scrollbar: { scrollbar: {
backgroundColorVertical: "#e5e5e5", backgroundColorVertical: "rgba(208, 213, 218, 1)",
backgroundColorHorizontal: "rgba(0, 0, 0, 0.1)", backgroundColorHorizontal: "rgba(0, 0, 0, 0.1)",
hoverBackgroundColorVertical: "rgba(163, 169, 174, 1)",
}, },
modalDialog: { modalDialog: {
@ -917,28 +918,12 @@ const Base = {
}, },
editContainer: { editContainer: {
boxSizing: "border-box", right: "0px",
width: "100%", bottom: "0px",
height: "100%", backgroundColor: "#265a8f",
top: "50%",
left: "50%",
transform: "translate(-50%, -50%)",
padding: "75% 16px 5px",
textAlign: "center",
lineHeight: "19px",
borderRadius: "50%", borderRadius: "50%",
linearGradient: height: "32px",
"linear-gradient(180deg, rgba(6, 22, 38, 0) 24.48%, rgba(6, 22, 38, 0.75) 100%)", width: "32px",
transparent: "transparent",
},
editLink: {
paddingLeft: "10px",
paddingRight: "10px",
borderBottom: "none",
display: "inline-block",
maxWidth: "100%",
textDecoration: "underline dashed",
}, },
image: { image: {
@ -1403,7 +1388,7 @@ const Base = {
maxWidth: "175px", maxWidth: "175px",
lineHeightWithoutBorder: "16px", lineHeightWithoutBorder: "16px",
lineHeightTextDecoration: "underline dashed transparent", lineHeightTextDecoration: "underline dashed",
}, },
childrenButton: { childrenButton: {

View File

@ -444,8 +444,9 @@ const Dark = {
}, },
scrollbar: { scrollbar: {
backgroundColorVertical: "rgba(255, 255, 255, 0.5)", backgroundColorVertical: "rgba(208, 213, 218, 1)",
backgroundColorHorizontal: "rgba(255, 255, 255, 0.5)", backgroundColorHorizontal: "rgba(255, 255, 255, 0.5)",
hoverBackgroundColorVertical: "rgba(163, 169, 174, 1)",
}, },
modalDialog: { modalDialog: {
@ -880,29 +881,14 @@ const Dark = {
}, },
}, },
editContainer: { editContainer: {
boxSizing: "border-box", right: "0px",
width: "100%", bottom: "0px",
height: "100%", backgroundColor: "#265a8f",
top: "50%",
left: "50%",
transform: "translate(-50%, -50%)",
padding: "75% 16px 5px",
textAlign: "center",
lineHeight: "19px",
borderRadius: "50%", borderRadius: "50%",
linearGradient: height: "32px",
"linear-gradient(180deg, rgba(6, 22, 38, 0) 24.48%, rgba(6, 22, 38, 0.75) 100%)", width: "32px",
transparent: "transparent",
}, },
editLink: {
paddingLeft: "10px",
paddingRight: "10px",
borderBottom: "none",
display: "inline-block",
maxWidth: "100%",
textDecoration: "underline dashed",
},
image: { image: {
width: "100%", width: "100%",
height: "100%", height: "100%",
@ -1194,7 +1180,7 @@ const Dark = {
maxWidth: "175px", maxWidth: "175px",
lineHeightWithoutBorder: "16px", lineHeightWithoutBorder: "16px",
lineHeightTextDecoration: "underline dashed transparent", lineHeightTextDecoration: "underline dashed",
}, },
childrenButton: { childrenButton: {

View File

@ -109,18 +109,19 @@ export default function withContent(WrappedContent) {
return this.completeAction(e); return this.completeAction(e);
}; };
onClickUpdateItem = (e) => { onClickUpdateItem = (e, open = true) => {
const { fileActionType } = this.props; const { fileActionType } = this.props;
fileActionType === FileAction.Create fileActionType === FileAction.Create
? this.createItem(e) ? this.createItem(e, open)
: this.updateItem(e); : this.updateItem(e);
}; };
createItem = (e) => { createItem = (e, open) => {
const { const {
createFile, createFile,
item, item,
setIsLoading, setIsLoading,
isLoading,
openDocEditor, openDocEditor,
isPrivacy, isPrivacy,
isDesktop, isDesktop,
@ -131,6 +132,8 @@ export default function withContent(WrappedContent) {
} = this.props; } = this.props;
const { itemTitle } = this.state; const { itemTitle } = this.state;
if (isLoading) return;
setIsLoading(true); setIsLoading(true);
const itemId = e.currentTarget.dataset.itemid; const itemId = e.currentTarget.dataset.itemid;
@ -141,7 +144,7 @@ export default function withContent(WrappedContent) {
} }
let tab = let tab =
!isDesktop && item.fileExst !isDesktop && item.fileExst && open
? window.open( ? window.open(
combineUrl( combineUrl(
AppServerConfig.proxyURL, AppServerConfig.proxyURL,
@ -170,10 +173,12 @@ export default function withContent(WrappedContent) {
encryptedFile, encryptedFile,
true, true,
false false
).then(() => openDocEditor(file.id, file.providerKey, tab)); ).then(
() => open && openDocEditor(file.id, file.providerKey, tab)
);
}); });
} }
return openDocEditor(file.id, file.providerKey, tab); return open && openDocEditor(file.id, file.providerKey, tab);
}) })
.then(() => this.completeAction(itemId)) .then(() => this.completeAction(itemId))
.catch((e) => toastr.error(e)) .catch((e) => toastr.error(e))
@ -315,6 +320,7 @@ export default function withContent(WrappedContent) {
const { editCompleteAction } = filesActionsStore; const { editCompleteAction } = filesActionsStore;
const { const {
setIsLoading, setIsLoading,
isLoading,
openDocEditor, openDocEditor,
updateFile, updateFile,
renameFolder, renameFolder,
@ -338,6 +344,7 @@ export default function withContent(WrappedContent) {
return { return {
setIsLoading, setIsLoading,
isLoading,
isTrashFolder: isRecycleBinFolder, isTrashFolder: isRecycleBinFolder,
openDocEditor, openDocEditor,
updateFile, updateFile,

View File

@ -248,9 +248,10 @@ export default function withContextOptions(WrappedComponent) {
}; };
onClickShare = () => { onClickShare = () => {
const { onSelectItem, setSharingPanelVisible, id, isFolder } = this.props; const { setSharingPanelVisible } = this.props;
onSelectItem({ id, isFolder }); setTimeout(() => {
setSharingPanelVisible(true); setSharingPanelVisible(true);
}, 10); //TODO: remove delay after fix context menu callback
}; };
onClickMarkRead = () => { onClickMarkRead = () => {

View File

@ -96,7 +96,7 @@ export default function withFileActions(WrappedFileItem) {
} }
e.preventDefault(); e.preventDefault();
setTooltipPosition(e.pageX, e.pageY); setTooltipPosition(e.pageX, e.pageY);
setStartDrag(true); !isFileName && setStartDrag(true);
!isActive && setBufferSelection(null); !isActive && setBufferSelection(null);
}; };

View File

@ -46,6 +46,8 @@ const EditingWrapper = styled.div`
border-bottom: 1px solid #eceef1; border-bottom: 1px solid #eceef1;
padding-bottom: 4px; padding-bottom: 4px;
margin-top: 4px; margin-top: 4px;
margin-left: -4px;
`} `}
${(props) => ${(props) =>
@ -149,6 +151,7 @@ const EditingWrapperComponent = (props) => {
}; };
const onFocus = (e) => e.target.select(); const onFocus = (e) => e.target.select();
const onBlur = (e) => onClickUpdateItem(e, false);
return ( return (
<EditingWrapper viewAs={viewAs}> <EditingWrapper viewAs={viewAs}>
@ -164,6 +167,7 @@ const EditingWrapperComponent = (props) => {
onKeyUp={onKeyUpUpdateItem} onKeyUp={onKeyUpUpdateItem}
onKeyDown={onEscapeKeyPress} onKeyDown={onEscapeKeyPress}
onFocus={onFocus} onFocus={onFocus}
onBlur={onBlur}
isDisabled={isLoading} isDisabled={isLoading}
data-itemid={itemId} data-itemid={itemId}
withBorder={!isTable} withBorder={!isTable}

View File

@ -0,0 +1,131 @@
import React, { useEffect, useState, useCallback } from "react";
import Text from "@appserver/components/text";
import Link from "@appserver/components/link";
import TextInput from "@appserver/components/text-input";
import Textarea from "@appserver/components/textarea";
import copy from "copy-to-clipboard";
import toastr from "@appserver/components/toast/toastr";
import IconButton from "@appserver/components/icon-button";
import i18n from "./i18n";
import { withTranslation, I18nextProvider } from "react-i18next";
const EmbeddingBody = ({ embeddingLink, t }) => {
const [size, setSize] = useState("auto");
const [widthValue, setWidthValue] = useState("100%");
const [heightValue, setHeightValue] = useState("100%");
const getIframe = useCallback(
() =>
`<iframe src="${embeddingLink}" width="${widthValue}" height="${heightValue}" frameborder="0" scrolling="no" allowtransparency> </iframe>`,
[embeddingLink, widthValue, heightValue]
);
const [link, setLink] = useState(getIframe());
useEffect(() => {
const link = getIframe();
setLink(link);
}, [embeddingLink, widthValue, heightValue]);
const onSelectSizeMiddle = () => {
if (size === "600x800") return;
setSize("600x800");
setWidthValue("600");
setHeightValue("800");
};
const onSelectSizeSmall = () => {
if (size === "400x600") return;
setSize("400x600");
setWidthValue("400");
setHeightValue("600");
};
const onSelectSizeAuto = () => {
if (size === "auto") return;
setSize("auto");
setWidthValue("100%");
setHeightValue("100%");
};
const onChangeWidth = (e) => {
setWidthValue(e.target.value);
};
const onChangeHeight = (e) => {
setHeightValue(e.target.value);
};
const onCopyLink = () => {
copy(link);
toastr.success(t("CodeCopySuccess"));
};
return (
<div className="embedding-panel_body">
<Text className="embedding-panel_text">{t("Common:Size")}:</Text>
<div className="embedding-panel_links-container">
<Link
isHovered
type="action"
className="embedding-panel_link"
onClick={onSelectSizeMiddle}
>
600 x 800 px
</Link>
<Link
isHovered
type="action"
className="embedding-panel_link"
onClick={onSelectSizeSmall}
>
400 x 600 px
</Link>
<Link
isHovered
type="action"
className="embedding-panel_link"
onClick={onSelectSizeAuto}
>
{t("Auto")}
</Link>
</div>
<div className="embedding-panel_inputs-container">
<div>
<Text className="embedding-panel_text">{t("Width")}:</Text>
<TextInput
className="embedding-panel_input"
value={widthValue}
onChange={onChangeWidth}
/>
</div>
<div>
<Text className="embedding-panel_text">{t("Height")}:</Text>
<TextInput
className="embedding-panel_input"
value={heightValue}
onChange={onChangeHeight}
/>
</div>
</div>
<div className="embedding-panel_code-container">
<Text className="embedding-panel_text">{t("EmbedCode")}:</Text>
<IconButton
className="embedding-panel_copy-icon"
size="16"
iconName="/static/images/copy.react.svg"
color="#333"
onClick={onCopyLink}
/>
<Textarea color="#AEAEAE" isReadOnly value={link} />
</div>
</div>
);
};
const EmbeddingBodyWrapper = withTranslation("EmbeddingPanel")(EmbeddingBody);
export default (props) => (
<I18nextProvider i18n={i18n}>
<EmbeddingBodyWrapper {...props} />
</I18nextProvider>
);

View File

@ -4,33 +4,18 @@ import Backdrop from "@appserver/components/backdrop";
import Heading from "@appserver/components/heading"; import Heading from "@appserver/components/heading";
import Aside from "@appserver/components/aside"; import Aside from "@appserver/components/aside";
import IconButton from "@appserver/components/icon-button"; import IconButton from "@appserver/components/icon-button";
import Text from "@appserver/components/text";
import Link from "@appserver/components/link";
import TextInput from "@appserver/components/text-input";
import Textarea from "@appserver/components/textarea";
import toastr from "@appserver/components/toast/toastr";
import { withTranslation, I18nextProvider } from "react-i18next"; import { withTranslation, I18nextProvider } from "react-i18next";
import i18n from "./i18n";
import { import {
StyledEmbeddingPanel, StyledEmbeddingPanel,
StyledContent, StyledContent,
StyledHeaderContent, StyledHeaderContent,
StyledBody, StyledBody,
} from "../StyledPanels"; } from "../StyledPanels";
import copy from "copy-to-clipboard";
import i18n from "./i18n"; import EmbeddingBody from "./EmbeddingBody";
class EmbeddingPanelComponent extends React.Component { class EmbeddingPanelComponent extends React.Component {
constructor(props) {
super(props);
this.state = {
size: "auto",
widthValue: "100%",
heightValue: "100%",
link: `<iframe src="${props.embeddingLink}" width="100%" height="100%" frameborder="0" scrolling="no" allowtransparency> </iframe>`,
};
}
onArrowClick = () => this.props.onClose(); onArrowClick = () => this.props.onClose();
onClosePanels = () => { onClosePanels = () => {
@ -38,81 +23,8 @@ class EmbeddingPanelComponent extends React.Component {
this.props.onSharingPanelClose(); this.props.onSharingPanelClose();
}; };
onSelectSizeMiddle = () => {
this.state.size !== "600x800" &&
this.setState({ size: "600x800", widthValue: "600", heightValue: "800" });
};
onSelectSizeSmall = () => {
this.state.size !== "400x600" &&
this.setState({ size: "400x600", widthValue: "400", heightValue: "600" });
};
onSelectSizeAuto = () => {
this.state.size !== "auto" &&
this.setState({ size: "auto", widthValue: "100%", heightValue: "100%" });
};
onChangeWidth = (e) => {
this.setState({ widthValue: e.target.value });
};
onChangeHeight = (e) => {
this.setState({ heightValue: e.target.value });
};
onCopyLink = () => {
copy(this.state.link);
toastr.success(this.props.t("CodeCopySuccess"));
};
// shouldComponentUpdate(nextProps, nextState) {
// const { size, widthValue, heightValue, link } = this.state;
// const { visible, embeddingLink } = this.props;
// if (size !== nextState.size) {
// return true;
// }
// if (widthValue !== nextState.widthValue) {
// return true;
// }
// if (heightValue !== nextState.heightValue) {
// return true;
// }
// if (visible !== nextProps.visible) {
// return true;
// }
// if (embeddingLink !== nextProps.embeddingLink) {
// return true;
// }
// if (link !== nextState.link) {
// return true;
// }
// return false;
// }
componentDidUpdate(prevProps, prevState) {
const { embeddingLink } = this.props;
const { widthValue, heightValue } = this.state;
if (
prevProps.embeddingLink !== embeddingLink ||
widthValue !== prevState.widthValue ||
heightValue !== prevState.heightValue
) {
const link = `<iframe src="${embeddingLink}" width="${widthValue}" height="${heightValue}" frameborder="0" scrolling="no" allowtransparency> </iframe>`;
this.setState({ link });
}
}
render() { render() {
const { visible, t } = this.props; const { visible, t } = this.props;
const { size, widthValue, heightValue, link } = this.state;
const zIndex = 310; const zIndex = 310;
//console.log("EmbeddingPanel render"); //console.log("EmbeddingPanel render");
@ -141,69 +53,8 @@ class EmbeddingPanelComponent extends React.Component {
{t("EmbeddingDocument")} {t("EmbeddingDocument")}
</Heading> </Heading>
</StyledHeaderContent> </StyledHeaderContent>
<StyledBody size={size}> <StyledBody>
<div className="embedding-panel_body"> <EmbeddingBody />
<Text className="embedding-panel_text">
{t("Common:Size")}:
</Text>
<div className="embedding-panel_links-container">
<Link
isHovered
type="action"
className="embedding-panel_link"
onClick={this.onSelectSizeMiddle}
>
600 x 800 px
</Link>
<Link
isHovered
type="action"
className="embedding-panel_link"
onClick={this.onSelectSizeSmall}
>
400 x 600 px
</Link>
<Link
isHovered
type="action"
className="embedding-panel_link"
onClick={this.onSelectSizeAuto}
>
{t("Auto")}
</Link>
</div>
<div className="embedding-panel_inputs-container">
<div>
<Text className="embedding-panel_text">{t("Width")}:</Text>
<TextInput
className="embedding-panel_input"
value={widthValue}
onChange={this.onChangeWidth}
/>
</div>
<div>
<Text className="embedding-panel_text">{t("Height")}:</Text>
<TextInput
className="embedding-panel_input"
value={heightValue}
onChange={this.onChangeHeight}
/>
</div>
</div>
<div className="embedding-panel_code-container">
<Text className="embedding-panel_text">
{t("EmbedCode")}:
</Text>
<IconButton
className="embedding-panel_copy-icon"
size="16"
iconName="/static/images/copy.react.svg"
color="#333"
onClick={this.onCopyLink}
/>
<Textarea color="#AEAEAE" isReadOnly value={link} />
</div>
</div>
</StyledBody> </StyledBody>
</StyledContent> </StyledContent>
</Aside> </Aside>
@ -218,12 +69,12 @@ EmbeddingPanelComponent.propTypes = {
onClose: PropTypes.func, onClose: PropTypes.func,
}; };
const EmbeddingPanel = withTranslation("EmbeddingPanel")( const EmbeddingBodyWrapper = withTranslation("EmbeddingPanel")(
EmbeddingPanelComponent EmbeddingPanelComponent
); );
export default (props) => ( export default (props) => (
<I18nextProvider i18n={i18n}> <I18nextProvider i18n={i18n}>
<EmbeddingPanel {...props} /> <EmbeddingBodyWrapper {...props} />
</I18nextProvider> </I18nextProvider>
); );

View File

@ -16,8 +16,10 @@ const OperationsPanelComponent = (props) => {
visible, visible,
provider, provider,
selection, selection,
isFolderActions,
isRecycleBin, isRecycleBin,
setDestFolderId, setDestFolderId,
setIsFolderActions,
currentFolderId, currentFolderId,
operationsFolders, operationsFolders,
setCopyPanelVisible, setCopyPanelVisible,
@ -25,6 +27,7 @@ const OperationsPanelComponent = (props) => {
setMoveToPanelVisible, setMoveToPanelVisible,
checkOperationConflict, checkOperationConflict,
setThirdPartyMoveDialogVisible, setThirdPartyMoveDialogVisible,
parentFolderId,
} = props; } = props;
const zIndex = 310; const zIndex = 310;
@ -33,7 +36,12 @@ const OperationsPanelComponent = (props) => {
const expandedKeys = props.expandedKeys.map((item) => item.toString()); const expandedKeys = props.expandedKeys.map((item) => item.toString());
const onClose = () => { const onClose = () => {
isCopy ? setCopyPanelVisible(false) : setMoveToPanelVisible(false); if (isCopy) {
setCopyPanelVisible(false);
setIsFolderActions(false);
} else {
setMoveToPanelVisible(false);
}
setExpandedPanelKeys(null); setExpandedPanelKeys(null);
}; };
@ -41,6 +49,10 @@ const OperationsPanelComponent = (props) => {
const folderTitle = treeNode.node.props.title; const folderTitle = treeNode.node.props.title;
const destFolderId = isNaN(+folder[0]) ? folder[0] : +folder[0]; const destFolderId = isNaN(+folder[0]) ? folder[0] : +folder[0];
if (isFolderActions && destFolderId === parentFolderId) {
return onClose();
}
if (currentFolderId === destFolderId) { if (currentFolderId === destFolderId) {
return onClose(); return onClose();
} }
@ -68,8 +80,9 @@ const OperationsPanelComponent = (props) => {
? selection.filter((x) => !x.providerKey) ? selection.filter((x) => !x.providerKey)
: selection; : selection;
const fileIds = []; let fileIds = [];
const folderIds = []; let folderIds = [];
for (let item of items) { for (let item of items) {
if (item.fileExst || item.contentLength) { if (item.fileExst || item.contentLength) {
@ -81,6 +94,13 @@ const OperationsPanelComponent = (props) => {
} }
} }
if (isFolderActions) {
fileIds = [];
folderIds = [];
folderIds.push(currentFolderId);
}
if (!folderIds.length && !fileIds.length) return; if (!folderIds.length && !fileIds.length) return;
checkOperationConflict({ checkOperationConflict({
@ -152,10 +172,12 @@ export default inject(
const { const {
moveToPanelVisible, moveToPanelVisible,
copyPanelVisible, copyPanelVisible,
isFolderActions,
setCopyPanelVisible, setCopyPanelVisible,
setMoveToPanelVisible, setMoveToPanelVisible,
setDestFolderId, setDestFolderId,
setThirdPartyMoveDialogVisible, setThirdPartyMoveDialogVisible,
setIsFolderActions,
} = dialogsStore; } = dialogsStore;
const selections = selection.length ? selection : [bufferSelection]; const selections = selection.length ? selection : [bufferSelection];
@ -167,16 +189,19 @@ export default inject(
? expandedPanelKeys ? expandedPanelKeys
: selectedFolderStore.pathParts, : selectedFolderStore.pathParts,
currentFolderId: selectedFolderStore.id, currentFolderId: selectedFolderStore.id,
parentFolderId: selectedFolderStore.parentId,
isRecycleBin: isRecycleBinFolder, isRecycleBin: isRecycleBinFolder,
filter, filter,
operationsFolders, operationsFolders,
visible: copyPanelVisible || moveToPanelVisible, visible: copyPanelVisible || moveToPanelVisible,
provider, provider,
selection: selections, selection: selections,
isFolderActions,
setCopyPanelVisible, setCopyPanelVisible,
setMoveToPanelVisible, setMoveToPanelVisible,
setDestFolderId, setDestFolderId,
setIsFolderActions,
setThirdPartyMoveDialogVisible, setThirdPartyMoveDialogVisible,
checkOperationConflict, checkOperationConflict,
setExpandedPanelKeys, setExpandedPanelKeys,

View File

@ -19,6 +19,7 @@ import {
StyledFooter, StyledFooter,
StyledHeaderContent, StyledHeaderContent,
StyledSharingBody, StyledSharingBody,
StyledModalRowContainer,
} from "../StyledPanels"; } from "../StyledPanels";
import { AddUsersPanel, AddGroupsPanel, EmbeddingPanel } from "../index"; import { AddUsersPanel, AddGroupsPanel, EmbeddingPanel } from "../index";
import SharingRow from "./SharingRow"; import SharingRow from "./SharingRow";
@ -26,9 +27,12 @@ import { inject, observer } from "mobx-react";
import config from "../../../../package.json"; import config from "../../../../package.json";
import i18n from "./i18n"; import i18n from "./i18n";
import { I18nextProvider } from "react-i18next"; import { I18nextProvider } from "react-i18next";
import { isMobile } from "react-device-detect"; import { isMobile, isMobileOnly } from "react-device-detect";
import Loaders from "@appserver/common/components/Loaders"; import Loaders from "@appserver/common/components/Loaders";
import withLoader from "../../../HOCs/withLoader"; import withLoader from "../../../HOCs/withLoader";
import ModalDialogContainer from "../../dialogs/ModalDialogContainer";
import ModalDialog from "@appserver/components/modal-dialog";
import EmbeddingBody from "../EmbeddingPanel/EmbeddingBody";
const SharingBodyStyle = { height: `calc(100vh - 156px)` }; const SharingBodyStyle = { height: `calc(100vh - 156px)` };
@ -50,6 +54,7 @@ class SharingPanelComponent extends React.Component {
showPanel: false, showPanel: false,
accessOptions: [], accessOptions: [],
filesOwnerId: null, filesOwnerId: null,
showEmbeddingContent: false,
}; };
this.ref = React.createRef(); this.ref = React.createRef();
@ -74,11 +79,16 @@ class SharingPanelComponent extends React.Component {
newDataItems[0].access = rights; newDataItems[0].access = rights;
this.setState({ this.setState({
shareDataItems: newDataItems, shareDataItems: newDataItems,
showEmbeddingContent: false,
}); });
}; };
updateRowData = (newRowData) => { updateRowData = (newRowData) => {
const { getFileInfo, getFolderInfo } = this.props; const { getFileInfo, getFolderInfo, isFolderActions, id } = this.props;
if (isFolderActions) {
return getFolderInfo(id);
}
for (let item of newRowData) { for (let item of newRowData) {
!item.fileExst ? getFolderInfo(item.id) : getFileInfo(item.id); !item.fileExst ? getFolderInfo(item.id) : getFileInfo(item.id);
@ -105,7 +115,9 @@ class SharingPanelComponent extends React.Component {
isDesktop, isDesktop,
setEncryptionAccess, setEncryptionAccess,
setShareFiles, setShareFiles,
setIsFolderActions,
onSuccess, onSuccess,
isFolderActions,
} = this.props; } = this.props;
let folderIds = []; let folderIds = [];
@ -153,6 +165,13 @@ class SharingPanelComponent extends React.Component {
} }
} }
if (isFolderActions) {
folderIds = [];
fileIds = [];
folderIds.push(selection[0]);
}
const owner = shareDataItems.find((x) => x.isOwner); const owner = shareDataItems.find((x) => x.isOwner);
const ownerId = const ownerId =
filesOwnerId !== owner.sharedTo.id ? owner.sharedTo.id : null; filesOwnerId !== owner.sharedTo.id ? owner.sharedTo.id : null;
@ -205,7 +224,10 @@ class SharingPanelComponent extends React.Component {
}) })
.then(() => onSuccess && onSuccess()) .then(() => onSuccess && onSuccess())
.catch((err) => toastr.error(err)) .catch((err) => toastr.error(err))
.finally(() => setIsLoading(false)); .finally(() => {
setIsFolderActions(false);
setIsLoading(false);
});
}; };
onNotifyUsersChange = () => onNotifyUsersChange = () =>
this.setState({ isNotifyUsers: !this.state.isNotifyUsers }); this.setState({ isNotifyUsers: !this.state.isNotifyUsers });
@ -240,9 +262,10 @@ class SharingPanelComponent extends React.Component {
}; };
getData = () => { getData = () => {
const { selection } = this.props; const { selection, id, access } = this.props;
const folderId = [];
const fileId = []; let folderId = [];
let fileId = [];
for (let item of selection) { for (let item of selection) {
if (item.access === 1 || item.access === 0) { if (item.access === 1 || item.access === 0) {
@ -254,6 +277,13 @@ class SharingPanelComponent extends React.Component {
} }
} }
if (this.props.isFolderActions) {
folderId = [];
fileId = [];
folderId = access === 1 || access === 0 ? [id] : [];
}
return [folderId, fileId]; return [folderId, fileId];
}; };
@ -269,7 +299,6 @@ class SharingPanelComponent extends React.Component {
const returnValue = this.getData(); const returnValue = this.getData();
const folderId = returnValue[0]; const folderId = returnValue[0];
const fileId = returnValue[1]; const fileId = returnValue[1];
if (folderId.length !== 0 || fileId.length !== 0) { if (folderId.length !== 0 || fileId.length !== 0) {
!isMobile && setIsLoading(true); !isMobile && setIsLoading(true);
getShareUsers(folderId, fileId) getShareUsers(folderId, fileId)
@ -320,6 +349,12 @@ class SharingPanelComponent extends React.Component {
shareLink: link, shareLink: link,
}); });
onShowEmbeddingContainer = (link) =>
this.setState({
showEmbeddingContent: !this.state.showEmbeddingContent,
shareLink: link,
});
onShowGroupsPanel = () => onShowGroupsPanel = () =>
this.setState({ this.setState({
showAddGroupsPanel: !this.state.showAddGroupsPanel, showAddGroupsPanel: !this.state.showAddGroupsPanel,
@ -341,10 +376,14 @@ class SharingPanelComponent extends React.Component {
onCancel, onCancel,
setSharingPanelVisible, setSharingPanelVisible,
selectUploadedFile, selectUploadedFile,
setIsFolderActions,
setSelection,
setBufferSelection, setBufferSelection,
} = this.props; } = this.props;
setSharingPanelVisible(false); setSharingPanelVisible(false);
setSelection([]);
selectUploadedFile([]); selectUploadedFile([]);
setBufferSelection(null); setBufferSelection(null);
onCancel && onCancel(); onCancel && onCancel();
@ -421,6 +460,7 @@ class SharingPanelComponent extends React.Component {
//showPanel, //showPanel,
accessOptions, accessOptions,
externalAccessOptions, externalAccessOptions,
showEmbeddingContent,
} = this.state; } = this.state;
const visible = sharingPanelVisible; const visible = sharingPanelVisible;
@ -433,7 +473,66 @@ class SharingPanelComponent extends React.Component {
const internalLink = const internalLink =
selection.length === 1 && !isEncrypted && this.getInternalLink(); selection.length === 1 && !isEncrypted && this.getInternalLink();
return ( return isPersonal && !isMobileOnly ? (
<ModalDialog
isLoading={!tReady}
visible={visible}
displayType="modal"
onClose={this.onClose}
>
<ModalDialog.Header>{t("SharingSettingsTitle")}</ModalDialog.Header>
<ModalDialog.Body>
<StyledModalRowContainer>
{!isLoading ? (
shareDataItems.map((item, index) => (
<SharingRow
t={t}
isPersonal={isPersonal}
index={index}
key={`${item.sharedTo.id}_${index}`}
selection={selection}
item={item}
isMyId={isMyId}
accessOptions={accessOptions}
externalAccessOptions={externalAccessOptions}
canShareOwnerChange={canShareOwnerChange}
onChangeItemAccess={this.onChangeItemAccess}
internalLink={internalLink}
onRemoveUserClick={this.onRemoveUserItemClick}
onShowEmbeddingPanel={this.onShowEmbeddingContainer}
onToggleLink={this.onToggleLink}
onShowChangeOwnerPanel={this.onShowChangeOwnerPanel}
isLoading={isLoading}
documentTitle={documentTitle}
/>
))
) : (
<Loaders.Rectangle
height="47px"
animate={0}
foregroundColor="#f8f9f9"
backgroundColor="#f8f9f9"
backgroundOpacity={1}
foregroundOpacity={1}
/>
)}
{showEmbeddingContent && (
<EmbeddingBody embeddingLink={shareLink} />
)}
</StyledModalRowContainer>
</ModalDialog.Body>
<ModalDialog.Footer>
<Button
className="sharing_panel-button"
label={t("Common:SaveButton")}
size="big"
primary
onClick={this.onSaveClick}
isDisabled={isLoading}
/>
</ModalDialog.Footer>
</ModalDialog>
) : (
<StyledAsidePanel visible={visible}> <StyledAsidePanel visible={visible}>
<Backdrop <Backdrop
onClick={this.onClose} onClick={this.onClose}
@ -618,12 +717,21 @@ class SharingPanelComponent extends React.Component {
const SharingPanel = inject( const SharingPanel = inject(
( (
{ auth, filesStore, uploadDataStore, dialogsStore, treeFoldersStore }, {
auth,
filesStore,
uploadDataStore,
dialogsStore,
treeFoldersStore,
selectedFolderStore,
},
{ uploadPanelVisible } { uploadPanelVisible }
) => { ) => {
const { replaceFileStream, setEncryptionAccess } = auth; const { replaceFileStream, setEncryptionAccess } = auth;
const { personal, customNames, isDesktopClient } = auth.settingsStore; const { personal, customNames, isDesktopClient } = auth.settingsStore;
const { id, access } = selectedFolderStore;
const { const {
selection, selection,
bufferSelection, bufferSelection,
@ -635,13 +743,19 @@ const SharingPanel = inject(
getShareUsers, getShareUsers,
setShareFiles, setShareFiles,
setIsLoading, setIsLoading,
setSelection,
getFileInfo, getFileInfo,
getFolderInfo, getFolderInfo,
isLoading, isLoading,
setBufferSelection, setBufferSelection,
} = filesStore; } = filesStore;
const { isPrivacyFolder } = treeFoldersStore; const { isPrivacyFolder } = treeFoldersStore;
const { setSharingPanelVisible, sharingPanelVisible } = dialogsStore; const {
setSharingPanelVisible,
sharingPanelVisible,
setIsFolderActions,
isFolderActions,
} = dialogsStore;
const { const {
selectedUploadFile, selectedUploadFile,
selectUploadedFile, selectUploadedFile,
@ -661,11 +775,14 @@ const SharingPanel = inject(
: [bufferSelection], : [bufferSelection],
isLoading, isLoading,
isPrivacy: isPrivacyFolder, isPrivacy: isPrivacyFolder,
isFolderActions,
selectedUploadFile, selectedUploadFile,
canShareOwnerChange, canShareOwnerChange,
setIsLoading, setIsLoading,
setSharingPanelVisible, setSharingPanelVisible,
setIsFolderActions,
setSelection,
sharingPanelVisible, sharingPanelVisible,
selectUploadedFile, selectUploadedFile,
updateUploadedItem, updateUploadedItem,
@ -679,7 +796,9 @@ const SharingPanel = inject(
setShareFiles, setShareFiles,
getFileInfo, getFileInfo,
getFolderInfo, getFolderInfo,
id,
setBufferSelection, setBufferSelection,
access,
}; };
} }
)( )(

View File

@ -41,7 +41,11 @@ class LinkRow extends React.Component {
const isDisabled = isLoading || disableLink; const isDisabled = isLoading || disableLink;
return ( return (
<StyledLinkRow withToggle={withToggle} isDisabled={isDisabled}> <StyledLinkRow
withToggle={withToggle}
isDisabled={isDisabled}
className="link-row__container"
>
<Row <Row
className="link-row" className="link-row"
key={`${linkText.replace(" ", "-")}-key_${index}`} key={`${linkText.replace(" ", "-")}-key_${index}`}

View File

@ -92,11 +92,11 @@ const StyledVersionHistoryPanel = styled.div`
${PanelStyles} ${PanelStyles}
.version-history-modal-dialog { .version-history-modal-dialog {
transform: translateX(${(props) => (props.visible ? "0" : "720px")}); transform: translateX(${(props) => (props.visible ? "0" : "720px")});
width: 720px; width: 500px;
} }
.version-history-aside-panel { .version-history-aside-panel {
transform: translateX(${(props) => (props.visible ? "0" : "720px")}); transform: translateX(${(props) => (props.visible ? "0" : "720px")});
width: 720px; width: 500px;
} }
.version-history-panel-header { .version-history-panel-header {
height: 53px; height: 53px;
@ -108,10 +108,14 @@ const StyledVersionHistoryPanel = styled.div`
} }
} }
.version-history-panel-body { .version-history-panel-body {
padding: ${(props) => (props.isLoading ? "16px 0" : null)}; padding-top: ${(props) => (props.isLoading ? "16px" : null)};
margin: 0 16px; padding-bottom: ${(props) => (props.isLoading ? "0px" : null)};
margin-left: 16px;
border-top: 1px solid #eceef1; border-top: 1px solid #eceef1;
height: calc(100% - 53px);
box-sizing: border-box;
.version-comment-wrapper { .version-comment-wrapper {
margin-left: 79px; margin-left: 79px;
} }
@ -170,6 +174,7 @@ const StyledContent = styled.div`
box-sizing: border-box; box-sizing: border-box;
position: relative; position: relative;
width: 100%; width: 100%;
height: 100%;
background-color: #fff; background-color: #fff;
.header_aside-panel-header { .header_aside-panel-header {
@ -775,6 +780,125 @@ const StyledFilesList = styled.div`
grid-template-columns: 22px 32px 1fr; grid-template-columns: 22px 32px 1fr;
} }
`; `;
const StyledModalRowContainer = styled.div`
display: flex;
flex-direction: column;
min-height: 47px;
.link-row__container {
width: 100%;
.link-row {
border-bottom: none;
}
.link-row::after {
height: 0;
}
}
.panel_combo-box {
margin-left: 0px;
.combo-button {
height: 30px;
margin: 0;
padding: 0;
border: none;
}
.optionalBlock {
margin-right: 4px;
display: flex;
}
.combo-button-label {
margin: 0;
}
.sharing-access-combo-box-icon {
height: 16px;
path {
fill: ${(props) => (props.isDisabled ? "#D0D5DA" : "#A3A9AE")};
}
svg {
width: 16px;
min-width: 16px;
height: 16px;
min-height: 16px;
}
}
}
.embedding-panel_code-container {
-webkit-tap-highlight-color: rgba(0, 0, 0, 0);
}
.embedding-panel_text {
padding: 8px 0 4px 0;
}
.embedding-panel_copy-icon {
position: absolute;
z-index: 1;
margin: 8px;
right: 0px;
}
.embedding-panel_links-container {
display: flex;
.embedding-panel_link {
margin-right: 8px;
height: 32px;
background-color: #eceef1;
line-height: 30px;
padding: 0px 8px;
}
}
.embedding-panel_inputs-container {
display: flex;
.embedding-panel_input {
margin-right: 8px;
width: 94px;
}
}
.embedding-panel_code-container {
-webkit-tap-highlight-color: rgba(0, 0, 0, 0);
}
.embedding-panel_text {
padding: 8px 0 4px 0;
}
.embedding-panel_copy-icon {
position: absolute;
z-index: 1;
margin: 8px;
right: 0;
}
.panel-loader-wrapper {
margin-top: 8px;
padding-left: 32px;
}
.panel-loader {
display: inline;
margin-right: 10px;
}
@media (max-width: 1024px) {
.row_content {
height: 19px;
overflow: initial;
}
}
`;
export { export {
StyledAsidePanel, StyledAsidePanel,
StyledAddGroupsPanel, StyledAddGroupsPanel,
@ -790,4 +914,5 @@ export {
StyledSelectFolderPanel, StyledSelectFolderPanel,
StyledSelectFilePanel, StyledSelectFilePanel,
StyledFilesList, StyledFilesList,
StyledModalRowContainer,
}; };

View File

@ -1,10 +1,14 @@
import React from "react"; import React from "react";
import CustomScrollbarsVirtualList from "@appserver/components/scrollbar/custom-scrollbars-virtual-list"; import CustomScrollbars from "@appserver/components/scrollbar/custom-scrollbars-virtual-list";
import AutoSizer from "react-virtualized-auto-sizer"; import AutoSizer from "react-virtualized-auto-sizer";
import { FixedSizeList as List } from "react-window"; import { FixedSizeList as List } from "react-window";
import RowWrapper from "./RowWrapper"; import RowWrapper from "./RowWrapper";
import { inject, observer } from "mobx-react"; import { inject, observer } from "mobx-react";
const CustomScrollbarsVirtualList = React.forwardRef((props, ref) => (
<CustomScrollbars stype="mediumBlack" {...props} forwardedRef={ref} />
));
const FileList = ({ uploadDataFiles }) => { const FileList = ({ uploadDataFiles }) => {
//console.log("FileList render"); //console.log("FileList render");

View File

@ -87,7 +87,11 @@ class UploadPanelComponent extends React.Component {
zIndex={zIndex} zIndex={zIndex}
isAside={true} isAside={true}
/> />
<Aside className="header_aside-panel" visible={visible}> <Aside
className="header_aside-panel"
visible={visible}
withoutBodyScroll
>
<StyledContent> <StyledContent>
<StyledHeaderContent className="upload-panel_header-content"> <StyledHeaderContent className="upload-panel_header-content">
<Heading className="upload_panel-header" size="medium" truncate> <Heading className="upload_panel-header" size="medium" truncate>

View File

@ -51,7 +51,7 @@ class PureVersionHistoryPanel extends React.Component {
zIndex={zIndex} zIndex={zIndex}
isAside={true} isAside={true}
/> />
<Aside className="version-history-aside-panel"> <Aside className="version-history-aside-panel" withoutBodyScroll>
<StyledContent> <StyledContent>
<StyledHeaderContent className="version-history-panel-header"> <StyledHeaderContent className="version-history-panel-header">
{versions && !isLoading ? ( {versions && !isLoading ? (

View File

@ -63,6 +63,10 @@ const StyledTableRow = styled(TableRow)`
"url(images/cursor.palm.svg), auto"}; "url(images/cursor.palm.svg), auto"};
} }
.table-container_element {
margin-left: ${(props) => (props.item.isFolder ? "-3px" : "-4px")};
}
&:hover { &:hover {
.table-container_row-checkbox-wrapper { .table-container_row-checkbox-wrapper {
${(props) => props.dragging && rowCheckboxDraggingHoverStyle} ${(props) => props.dragging && rowCheckboxDraggingHoverStyle}

View File

@ -9,6 +9,7 @@ import Text from "@appserver/components/text";
import TileContent from "./sub-components/TileContent"; import TileContent from "./sub-components/TileContent";
import withContent from "../../../../../HOCs/withContent"; import withContent from "../../../../../HOCs/withContent";
import withBadges from "../../../../../HOCs/withBadges"; import withBadges from "../../../../../HOCs/withBadges";
import { isMobile } from "react-device-detect";
const SimpleFilesTileContent = styled(TileContent)` const SimpleFilesTileContent = styled(TileContent)`
.row-main-container { .row-main-container {
@ -54,7 +55,8 @@ const SimpleFilesTileContent = styled(TileContent)`
} }
.title-link { .title-link {
font-size: 14px; font-size: ${isMobile ? "15px" : "13px"};
margin-top: 2px;
} }
.favorite, .favorite,
@ -83,18 +85,14 @@ const FilesTileContent = ({
return ( return (
<> <>
<SimpleFilesTileContent <SimpleFilesTileContent sideColor="#333" isFile={fileExst}>
sideColor="#333"
isFile={fileExst}
//disableSideInfo
>
<Link <Link
className="title-link item-file-name" className="title-link item-file-name"
containerWidth="100%" containerWidth="100%"
type="page" type="page"
title={title} title={title}
fontWeight="600" fontWeight="600"
fontSize="14px" fontSize={isMobile ? "15px" : "13px"}
target="_blank" target="_blank"
{...linkStyles} {...linkStyles}
color="#333" color="#333"
@ -106,7 +104,7 @@ const FilesTileContent = ({
className="badge-ext" className="badge-ext"
as="span" as="span"
color="#A3A9AE" color="#A3A9AE"
fontSize="14px" fontSize={isMobile ? "15px" : "13px"}
fontWeight={600} fontWeight={600}
truncate={true} truncate={true}
> >

View File

@ -6,6 +6,7 @@ import { ReactSVG } from "react-svg";
import styled, { css } from "styled-components"; import styled, { css } from "styled-components";
import ContextMenu from "@appserver/components/context-menu"; import ContextMenu from "@appserver/components/context-menu";
import { tablet } from "@appserver/components/utils/device"; import { tablet } from "@appserver/components/utils/device";
import { isDesktop, isMobile } from "react-device-detect";
import Link from "@appserver/components/link"; import Link from "@appserver/components/link";
@ -100,9 +101,11 @@ const StyledTile = styled.div`
} }
.checkbox { .checkbox {
display: flex;
opacity: ${(props) => (props.checked ? 1 : 0)}; opacity: ${(props) => (props.checked ? 1 : 0)};
flex: 0 0 16px; flex: 0 0 16px;
margin-right: 4px; margin-right: 4px;
justify-content: center;
@media ${tablet} { @media ${tablet} {
opacity: 1; opacity: 1;
@ -112,11 +115,18 @@ const StyledTile = styled.div`
.file-checkbox { .file-checkbox {
display: ${(props) => (props.checked ? "flex" : "none")}; display: ${(props) => (props.checked ? "flex" : "none")};
flex: 0 0 16px; flex: 0 0 16px;
margin-right: ${(props) => (props.isFolder ? "8px" : "4px")};
margin-top: 3px; margin-top: 3px;
margin-left: ${(props) =>
isMobile
? css`
${props.isFolder ? "6px" : "12px"};
`
: css`
${props.isFolder ? "5px" : "8px"}
`};
@media ${tablet} { @media ${tablet} {
display: flex;
margin-top: 2px; margin-top: 2px;
} }
} }
@ -126,33 +136,47 @@ const StyledTile = styled.div`
flex: 0 0 auto; flex: 0 0 auto;
margin-right: 4px; margin-right: 4px;
user-select: none; user-select: none;
margin-top: 3px; margin-top: ${(props) => (props.isFolder ? "-8px" : "-6px")};
margin-top: ${(props) => (props.isFolder ? "-6px" : "-4px")};
height: 32px; height: ${isMobile ? "32px" : "24px"};
width: 32px; width: ${isMobile ? "32px" : "24px"};
img { img {
height: 32px; height: ${isMobile ? "32px" : "24px"};
width: 32px; width: ${isMobile ? "32px" : "24px"};
} }
@media ${tablet} { margin-left: ${(props) =>
display: none; isMobile
} ? css`
${props.isFolder ? "2px" : "4px"};
`
: css`
${props.isFolder ? "2px" : "4px"}
`};
} }
.file-icon_container { .file-icon_container {
min-width: 36px; min-width: ${isMobile ? "36px" : "28px"};
}
@media ${tablet} { .styled-content {
min-width: 28px; padding-left: 10px;
}
padding-left: ${(props) =>
isMobile
? css`
${props.isFolder ? "8px" : "12px"};
`
: css`
${props.isFolder ? "10px" : "13px"}
`};
} }
:hover { :hover {
${(props) => ${(props) =>
!props.dragging && !props.dragging &&
props.isDesktop &&
css` css`
.checkbox { .checkbox {
opacity: 1; opacity: 1;
@ -173,8 +197,12 @@ const StyledFileTileTop = styled.div`
align-items: baseline; align-items: baseline;
background-color: #f8f9f9; background-color: #f8f9f9;
padding: 13px; padding: 13px;
height: 157px; height: ${(props) => (props.checked || props.isActive ? "156px" : "156px")};
position: relative; position: relative;
border-bottom: ${(props) =>
props.checked || props.isActive
? "1px solid #D0D5DA"
: "1px solid transparent"};
.thumbnail-image, .thumbnail-image,
.temporary-icon > .injected-svg { .temporary-icon > .injected-svg {
@ -195,8 +223,6 @@ const StyledFileTileBottom = styled.div`
padding-right: 0; padding-right: 0;
min-height: 56px; min-height: 56px;
box-sizing: border-box; box-sizing: border-box;
border-top: ${(props) =>
(props.checked || props.isActive) && "1px solid #D0D5DA"};
`; `;
const StyledContent = styled.div` const StyledContent = styled.div`
@ -292,6 +318,13 @@ class Tile extends React.PureComponent {
onSelect && onSelect(e.target.checked, item); onSelect && onSelect(e.target.checked, item);
}; };
onFileIconClick = () => {
if (isDesktop) return;
const { onSelect, item } = this.props;
onSelect && onSelect(true, item);
};
render() { render() {
const { const {
checked, checked,
@ -348,12 +381,18 @@ class Tile extends React.PureComponent {
isRecycleBin={isRecycleBin} isRecycleBin={isRecycleBin}
checked={checked} checked={checked}
isActive={isActive} isActive={isActive}
isDesktop={isDesktop}
> >
{isFolder || (!fileExst && id === -1) ? ( {isFolder || (!fileExst && id === -1) ? (
<> <>
{renderElement && !(!fileExst && id === -1) && !isEdit && ( {renderElement && !(!fileExst && id === -1) && !isEdit && (
<div className="file-icon_container"> <div className="file-icon_container">
<StyledElement className="file-icon">{element}</StyledElement> <StyledElement
className="file-icon"
onClick={this.onFileIconClick}
>
{element}
</StyledElement>
<Checkbox <Checkbox
className="checkbox file-checkbox" className="checkbox file-checkbox"
isChecked={checked} isChecked={checked}
@ -363,6 +402,7 @@ class Tile extends React.PureComponent {
</div> </div>
)} )}
<StyledContent <StyledContent
className="styled-content"
isFolder={(isFolder && !fileExst) || (!fileExst && id === -1)} isFolder={(isFolder && !fileExst) || (!fileExst && id === -1)}
> >
{children} {children}
@ -386,11 +426,15 @@ class Tile extends React.PureComponent {
</> </>
) : ( ) : (
<> <>
<StyledFileTileTop>{icon}</StyledFileTileTop> <StyledFileTileTop checked={checked} isActive={isActive}>
<StyledFileTileBottom checked={checked} isActive={isActive}> {icon}
</StyledFileTileTop>
<StyledFileTileBottom>
{id !== -1 && !isEdit && ( {id !== -1 && !isEdit && (
<div className="file-icon_container"> <div className="file-icon_container">
<div className="file-icon">{element}</div> <div className="file-icon" onClick={this.onFileIconClick}>
{element}
</div>
<Checkbox <Checkbox
className="file-checkbox" className="file-checkbox"
isChecked={checked} isChecked={checked}

View File

@ -1,35 +1,50 @@
/* eslint-disable react/display-name */ /* eslint-disable react/display-name */
import React, { memo } from "react"; import React, { memo } from "react";
import styled from "styled-components"; import styled, { css } from "styled-components";
import PropTypes from "prop-types"; import PropTypes from "prop-types";
import { FixedSizeList as List, areEqual } from "react-window"; import { FixedSizeList as List, areEqual } from "react-window";
import AutoSizer from "react-virtualized-auto-sizer"; import AutoSizer from "react-virtualized-auto-sizer";
import Heading from "@appserver/components/heading"; import Heading from "@appserver/components/heading";
import ContextMenu from "@appserver/components/context-menu"; import ContextMenu from "@appserver/components/context-menu";
import CustomScrollbarsVirtualList from "@appserver/components/scrollbar"; import CustomScrollbarsVirtualList from "@appserver/components/scrollbar";
import { tablet } from "@appserver/components/utils/device";
import { tablet, desktop } from "@appserver/components/utils/device";
const foldersStyle = css`
grid-gap: 19px 14px;
@media ${desktop} {
margin-left: -1px;
padding-right: 1px;
}
@media ${tablet} {
grid-gap: 17px 12px;
margin-left: -1px;
}
`;
const filesStyle = css`
grid-gap: 14px 18px;
@media ${desktop} {
padding-right: 5px;
}
@media ${tablet} {
grid-gap: 12px 14px;
margin-left: -1px;
padding-right: 2px;
}
`;
const StyledGridWrapper = styled.div` const StyledGridWrapper = styled.div`
display: grid; display: grid;
grid-template-columns: repeat(auto-fill, minmax(220px, 1fr)); grid-template-columns: repeat(auto-fill, minmax(220px, 1fr));
width: 100%; width: 100%;
grid-gap: ${(props) => (props.isFolders ? "13px 14px" : "16px 18px")};
padding-bottom: 24px; padding-bottom: 24px;
padding-right: 2px;
box-sizing: border-box; box-sizing: border-box;
padding-left: 1px; ${(props) => (props.isFolders ? foldersStyle : filesStyle)};
@media ${tablet} {
margin-left: -6px !important;
}
@media (min-width: 1024px) {
margin-left: -2px;
}
@media (max-width: 1024px) {
margin-left: -2px;
}
`; `;
const StyledTileContainer = styled.div` const StyledTileContainer = styled.div`
@ -59,6 +74,8 @@ const StyledTileContainer = styled.div`
&.files { &.files {
padding-top: 8px; padding-top: 8px;
} }
margin-left: -1px;
} }
@media (min-width: 1024px) { @media (min-width: 1024px) {
@ -68,6 +85,10 @@ const StyledTileContainer = styled.div`
} }
} }
} }
@media ${tablet} {
margin-right: -3px;
}
`; `;
class TileContainer extends React.PureComponent { class TileContainer extends React.PureComponent {

View File

@ -208,15 +208,32 @@ class SectionHeaderContent extends React.Component {
toastr.success(t("Translations:LinkCopySuccess")); toastr.success(t("Translations:LinkCopySuccess"));
}; };
onMoveAction = () => this.props.setMoveToPanelVisible(true); onMoveAction = () => {
onCopyAction = () => this.props.setCopyPanelVisible(true); this.props.setIsFolderActions(true);
downloadAction = () => this.props.setBufferSelection(this.props.currentFolderId);
return this.props.setMoveToPanelVisible(true);
};
onCopyAction = () => {
this.props.setIsFolderActions(true);
this.props.setBufferSelection(this.props.currentFolderId);
return this.props.setCopyPanelVisible(true);
};
downloadAction = () => {
this.props.setBufferSelection(this.props.currentFolderId);
this.props.setIsFolderActions(true);
this.props this.props
.downloadAction(this.props.t("Translations:ArchivingData")) .downloadAction(this.props.t("Translations:ArchivingData"), [
this.props.currentFolderId,
])
.catch((err) => toastr.error(err)); .catch((err) => toastr.error(err));
};
renameAction = () => console.log("renameAction click"); renameAction = () => console.log("renameAction click");
onOpenSharingPanel = () => this.props.setSharingPanelVisible(true); onOpenSharingPanel = () => {
this.props.setBufferSelection(this.props.currentFolderId);
this.props.setIsFolderActions(true);
return this.props.setSharingPanelVisible(true);
};
onDeleteAction = () => { onDeleteAction = () => {
const { const {
@ -225,10 +242,18 @@ class SectionHeaderContent extends React.Component {
confirmDelete, confirmDelete,
setDeleteDialogVisible, setDeleteDialogVisible,
isThirdPartySelection, isThirdPartySelection,
currentFolderId,
getFolderInfo,
setBufferSelection,
} = this.props; } = this.props;
this.props.setIsFolderActions(true);
if (confirmDelete || isThirdPartySelection) { if (confirmDelete || isThirdPartySelection) {
setDeleteDialogVisible(true); getFolderInfo(currentFolderId).then((data) => {
setBufferSelection(data);
setDeleteDialogVisible(true);
});
} else { } else {
const translations = { const translations = {
deleteOperation: t("Translations:DeleteOperation"), deleteOperation: t("Translations:DeleteOperation"),
@ -236,45 +261,48 @@ class SectionHeaderContent extends React.Component {
deleteSelectedElem: t("Translations:DeleteSelectedElem"), deleteSelectedElem: t("Translations:DeleteSelectedElem"),
}; };
deleteAction(translations); deleteAction(translations, [currentFolderId], true).catch((err) =>
toastr.error(err)
);
} }
}; };
onEmptyTrashAction = () => this.props.setEmptyTrashDialogVisible(true); onEmptyTrashAction = () => this.props.setEmptyTrashDialogVisible(true);
getContextOptionsFolder = () => { getContextOptionsFolder = () => {
const { t } = this.props; const { t, personal } = this.props;
return [ return [
{ {
key: "sharing-settings", key: "sharing-settings",
label: t("SharingSettings"), label: t("SharingSettings"),
onClick: this.onOpenSharingPanel, onClick: this.onOpenSharingPanel,
disabled: true, disabled: personal ? true : false,
}, },
{ {
key: "link-portal-users", key: "link-portal-users",
label: t("LinkForPortalUsers"), label: t("LinkForPortalUsers"),
onClick: this.createLinkForPortalUsers, onClick: this.createLinkForPortalUsers,
disabled: false, disabled: personal ? true : false,
}, },
{ key: "separator-2", isSeparator: true }, { key: "separator-2", isSeparator: true },
{ {
key: "move-to", key: "move-to",
label: t("MoveTo"), label: t("MoveTo"),
onClick: this.onMoveAction, onClick: this.onMoveAction,
disabled: true, disabled: false,
}, },
{ {
key: "copy", key: "copy",
label: t("Translations:Copy"), label: t("Translations:Copy"),
onClick: this.onCopyAction, onClick: this.onCopyAction,
disabled: true, disabled: false,
}, },
{ {
key: "download", key: "download",
label: t("Common:Download"), label: t("Common:Download"),
onClick: this.downloadAction, onClick: this.downloadAction,
disabled: true, disabled: false,
}, },
{ {
key: "rename", key: "rename",
@ -286,7 +314,7 @@ class SectionHeaderContent extends React.Component {
key: "delete", key: "delete",
label: t("Common:Delete"), label: t("Common:Delete"),
onClick: this.onDeleteAction, onClick: this.onDeleteAction,
disabled: true, disabled: false,
}, },
]; ];
}; };
@ -418,19 +446,18 @@ class SectionHeaderContent extends React.Component {
getData={this.getContextOptionsPlus} getData={this.getContextOptionsPlus}
isDisabled={false} isDisabled={false}
/> />
{!personal && (
<ContextMenuButton <ContextMenuButton
className="option-button" className="option-button"
directionX="right" directionX="right"
iconName="images/vertical-dots.react.svg" iconName="images/vertical-dots.react.svg"
size={17} size={17}
color="#A3A9AE" color="#A3A9AE"
hoverColor="#657077" hoverColor="#657077"
isFill isFill
getData={this.getContextOptionsFolder} getData={this.getContextOptionsFolder}
isDisabled={false} isDisabled={false}
/> />
)}
</> </>
) : ( ) : (
canCreate && ( canCreate && (
@ -469,6 +496,7 @@ export default inject(
}) => { }) => {
const { const {
setSelected, setSelected,
setSelection,
fileActionStore, fileActionStore,
fetchFiles, fetchFiles,
filter, filter,
@ -481,6 +509,8 @@ export default inject(
viewAs, viewAs,
cbMenuItems, cbMenuItems,
getCheckboxItemLabel, getCheckboxItemLabel,
getFolderInfo,
setBufferSelection,
} = filesStore; } = filesStore;
const { setAction } = fileActionStore; const { setAction } = fileActionStore;
const { const {
@ -488,6 +518,7 @@ export default inject(
setMoveToPanelVisible, setMoveToPanelVisible,
setCopyPanelVisible, setCopyPanelVisible,
setDeleteDialogVisible, setDeleteDialogVisible,
setIsFolderActions,
} = dialogsStore; } = dialogsStore;
const { deleteAction, downloadAction, getHeaderMenu } = filesActionsStore; const { deleteAction, downloadAction, getHeaderMenu } = filesActionsStore;
@ -509,14 +540,18 @@ export default inject(
personal: auth.settingsStore.personal, personal: auth.settingsStore.personal,
viewAs, viewAs,
cbMenuItems, cbMenuItems,
getFolderInfo,
setSelected, setSelected,
setSelection,
setAction, setAction,
setIsLoading, setIsLoading,
fetchFiles, fetchFiles,
setSharingPanelVisible, setSharingPanelVisible,
setMoveToPanelVisible, setMoveToPanelVisible,
setCopyPanelVisible, setCopyPanelVisible,
setBufferSelection,
setIsFolderActions,
deleteAction, deleteAction,
setDeleteDialogVisible, setDeleteDialogVisible,
downloadAction, downloadAction,

View File

@ -1,19 +1,124 @@
import styled, { css } from "styled-components"; import styled from "styled-components";
import Row from "@appserver/components/row"; import Row from "@appserver/components/row";
import { tablet } from "@appserver/components/utils/device"; import { tablet } from "@appserver/components/utils/device";
const StyledVersionRow = styled(Row)` const StyledBody = styled.div`
min-height: 70px; height: 100%;
width: 100%;
.version-list {
height: 100%;
width: 100%;
}
.loader-history-rows {
padding-right: 16px;
}
`;
const StyledVersionList = styled.div`
.row_context-menu-wrapper {
.expandButton {
${(props) =>
props.isRestoreProcess &&
`
touch-action: none;
pointer-events: none;
`}
svg {
path {
${(props) =>
props.isRestoreProcess &&
`
fill: #d0d5da;
`};
}
}
}
}
.row_content {
.version_link,
.version-link-file,
.version_content-length,
.version_link-action,
.row_context-menu-wrapper,
.version_text {
${(props) =>
props.isRestoreProcess &&
`
color: #d0d5da;
touch-action: none;
pointer-events: none;
`}
}
.versioned, .not-versioned {
${(props) =>
props.isRestoreProcess &&
`
touch-action: none;
pointer-events: none;
`}
}
.versioned {
svg {
path {
${(props) =>
props.isRestoreProcess &&
`
fill: #d0d5da;
`};
}
}
}
.not-versioned{
svg {
path {
${(props) =>
props.isRestoreProcess &&
`
stroke: #d0d5da;
`};
}
}
}
}
.icon-link {
${(props) =>
props.isRestoreProcess &&
`
touch-action: none;
pointer-events: none;
`}
svg {
path {
${(props) => props.isRestoreProcess && " fill: #d0d5da"}
}
}
}
}
`;
const StyledVersionRow = styled(Row)`
@media ${tablet} { @media ${tablet} {
min-height: 69px; box-sizing: border-box;
position: relative; position: relative;
} }
.row_content { .row_content {
position: relative; position: relative;
padding-top: 14px; padding-top: 12px;
padding-bottom: 14px; padding-bottom: 12px;
${(props) => props.isTabletView && "height: auto"};
${(props) => !props.isTabletView && "padding-right:16px"};
} }
.version_badge { .version_badge {
@ -133,6 +238,26 @@ const StyledVersionRow = styled(Row)`
.row_context-menu-wrapper { .row_context-menu-wrapper {
display: none; display: none;
right: 16px !important;
.expandButton {
${(props) =>
props.isSavingComment &&
`
touch-action: none;
pointer-events: none;
`}
svg {
path {
${(props) =>
props.isSavingComment &&
`
fill: #d0d5da;
`};
}
}
}
@media ${tablet} { @media ${tablet} {
display: block; display: block;
position: absolute; position: absolute;
@ -143,6 +268,16 @@ const StyledVersionRow = styled(Row)`
.row_content { .row_content {
display: block; display: block;
.version_link-action {
${(props) =>
props.isSavingComment &&
`
color: #d0d5da;
touch-action: none;
pointer-events: none;
`}
}
} }
.modal-dialog-aside-footer { .modal-dialog-aside-footer {
@ -168,4 +303,4 @@ const StyledVersionRow = styled(Row)`
} }
`; `;
export default StyledVersionRow; export { StyledBody, StyledVersionRow, StyledVersionList };

View File

@ -1,4 +1,4 @@
import React, { useState } from "react"; import React, { useState, useEffect } from "react";
import styled from "styled-components"; import styled from "styled-components";
import Link from "@appserver/components/link"; import Link from "@appserver/components/link";
import Text from "@appserver/components/text"; import Text from "@appserver/components/text";
@ -9,7 +9,7 @@ import ModalDialog from "@appserver/components/modal-dialog";
import { withTranslation } from "react-i18next"; import { withTranslation } from "react-i18next";
import { withRouter } from "react-router"; import { withRouter } from "react-router";
import VersionBadge from "./VersionBadge"; import VersionBadge from "./VersionBadge";
import StyledVersionRow from "./StyledVersionRow"; import { StyledVersionRow } from "./StyledVersionHistory";
import ExternalLinkIcon from "../../../../../public/images/external.link.react.svg"; import ExternalLinkIcon from "../../../../../public/images/external.link.react.svg";
import commonIconsStyles from "@appserver/components/utils/common-icons-style"; import commonIconsStyles from "@appserver/components/utils/common-icons-style";
import { inject, observer } from "mobx-react"; import { inject, observer } from "mobx-react";
@ -31,11 +31,14 @@ const VersionRow = (props) => {
markAsVersion, markAsVersion,
restoreVersion, restoreVersion,
updateCommentVersion, updateCommentVersion,
onSetRestoreProcess,
isTabletView,
onUpdateHeight,
versionsListLength,
} = props; } = props;
const [showEditPanel, setShowEditPanel] = useState(false); const [showEditPanel, setShowEditPanel] = useState(false);
const [commentValue, setCommentValue] = useState(info.comment); const [commentValue, setCommentValue] = useState(info.comment);
const [isSavingComment, setIsSavingComment] = useState(false);
const [isRestoring, setIsRestoring] = useState(false);
const canEdit = info.access === 1 || info.access === 0; const canEdit = info.access === 1 || info.access === 0;
@ -52,10 +55,12 @@ const VersionRow = (props) => {
const onChange = (e) => setCommentValue(e.target.value); const onChange = (e) => setCommentValue(e.target.value);
const onSaveClick = () => { const onSaveClick = () => {
setIsSavingComment(true);
updateCommentVersion(info.id, commentValue, info.version) updateCommentVersion(info.id, commentValue, info.version)
.catch((err) => toastr.error(err)) .catch((err) => toastr.error(err))
.finally(() => { .finally(() => {
onEditComment(); onEditComment();
setIsSavingComment(false);
}); });
}; };
@ -66,11 +71,12 @@ const VersionRow = (props) => {
const onOpenFile = () => window.open(info.webUrl); const onOpenFile = () => window.open(info.webUrl);
const onRestoreClick = () => { const onRestoreClick = () => {
setIsRestoring(true); onSetRestoreProcess(true);
restoreVersion(info.id, info.version) restoreVersion(info.id, info.version)
.catch((err) => toastr.error(err)) .catch((err) => toastr.error(err))
.finally(() => setIsRestoring(false)); .finally(() => {
onSetRestoreProcess(false);
});
}; };
const onVersionClick = () => { const onVersionClick = () => {
@ -94,17 +100,29 @@ const VersionRow = (props) => {
]; ];
const onClickProp = canEdit ? { onClick: onVersionClick } : {}; const onClickProp = canEdit ? { onClick: onVersionClick } : {};
useEffect(() => {
const newRowHeight = document.getElementsByClassName(
`version-row_${index}`
)[0]?.clientHeight;
newRowHeight && onUpdateHeight(index, newRowHeight);
}, [showEditPanel, versionsListLength]);
return ( return (
<StyledVersionRow <StyledVersionRow
showEditPanel={showEditPanel} showEditPanel={showEditPanel}
contextOptions={contextOptions} contextOptions={contextOptions}
canEdit={canEdit} canEdit={canEdit}
isRestoring={isRestoring} isTabletView={isTabletView}
isSavingComment={isSavingComment}
> >
<> <div className={`version-row_${index}`}>
<Box displayProp="flex"> <Box displayProp="flex">
<VersionBadge <VersionBadge
className="version_badge" className={`version_badge ${
isVersion ? "versioned" : "not-versioned"
}`}
isVersion={isVersion} isVersion={isVersion}
index={index} index={index}
versionGroup={info.versionGroup} versionGroup={info.versionGroup}
@ -147,6 +165,7 @@ const VersionRow = (props) => {
fontSize={12} fontSize={12}
heightTextArea={54} heightTextArea={54}
value={commentValue} value={commentValue}
isDisabled={isSavingComment}
/> />
<Box className="version_modal-dialog"> <Box className="version_modal-dialog">
<ModalDialog <ModalDialog
@ -165,10 +184,12 @@ const VersionRow = (props) => {
onChange={onChange} onChange={onChange}
heightTextArea={298} heightTextArea={298}
value={commentValue} value={commentValue}
isDisabled={isSavingComment}
/> />
</ModalDialog.Body> </ModalDialog.Body>
<ModalDialog.Footer> <ModalDialog.Footer>
<Button <Button
isDisabled={isSavingComment}
className="version_save-button" className="version_save-button"
label={t("Common:SaveButton")} label={t("Common:SaveButton")}
size="big" size="big"
@ -195,7 +216,7 @@ const VersionRow = (props) => {
<div className="version_links-container"> <div className="version_links-container">
{canEdit && ( {canEdit && (
<Link <Link
{...(!isRestoring && { onClick: onRestoreClick })} onClick={onRestoreClick}
{...linkStyles} {...linkStyles}
className="version_link-action" className="version_link-action"
> >
@ -218,6 +239,7 @@ const VersionRow = (props) => {
displayProp="inline-block" displayProp="inline-block"
> >
<Button <Button
isDisabled={isSavingComment}
size="base" size="base"
scale={true} scale={true}
primary primary
@ -230,6 +252,7 @@ const VersionRow = (props) => {
displayProp="inline-block" displayProp="inline-block"
> >
<Button <Button
isDisabled={isSavingComment}
size="base" size="base"
scale={true} scale={true}
onClick={onCancelClick} onClick={onCancelClick}
@ -238,14 +261,14 @@ const VersionRow = (props) => {
</Box> </Box>
</Box> </Box>
)} )}
</> </div>
</StyledVersionRow> </StyledVersionRow>
); );
}; };
export default inject(({ auth, versionHistoryStore }) => { export default inject(({ auth, versionHistoryStore }) => {
const { user } = auth.userStore; const { user } = auth.userStore;
const { culture } = auth.settingsStore; const { culture, isTabletView } = auth.settingsStore;
const language = (user && user.cultureName) || culture || "en-US"; const language = (user && user.cultureName) || culture || "en-US";
const { const {
@ -256,7 +279,7 @@ export default inject(({ auth, versionHistoryStore }) => {
return { return {
culture: language, culture: language,
isTabletView,
markAsVersion, markAsVersion,
restoreVersion, restoreVersion,
updateCommentVersion, updateCommentVersion,

View File

@ -1,13 +1,26 @@
import React from "react"; import React, { memo } from "react";
import { withRouter } from "react-router"; import { withRouter } from "react-router";
import RowContainer from "@appserver/components/row-container";
import Loaders from "@appserver/common/components/Loaders"; import Loaders from "@appserver/common/components/Loaders";
import VersionRow from "./VersionRow"; import VersionRow from "./VersionRow";
import { inject, observer } from "mobx-react"; import { inject, observer } from "mobx-react";
import { VariableSizeList as List, areEqual } from "react-window";
import AutoSizer from "react-virtualized-auto-sizer";
import CustomScrollbarsVirtualList from "@appserver/components/scrollbar/custom-scrollbars-virtual-list";
import { StyledBody, StyledVersionList } from "./StyledVersionHistory";
class SectionBodyContent extends React.Component { class SectionBodyContent extends React.Component {
constructor(props) {
super(props);
this.state = {
isRestoreProcess: false,
rowSizes: {},
};
this.listKey = 0;
this.listRef = React.createRef();
this.timerId = null;
}
componentDidMount() { componentDidMount() {
const { match, setFirstLoad } = this.props; const { match, setFirstLoad, versions } = this.props;
const fileId = match.params.fileId || this.props.fileId; const fileId = match.params.fileId || this.props.fileId;
if (fileId && fileId !== this.props.fileId) { if (fileId && fileId !== this.props.fileId) {
@ -21,36 +34,104 @@ class SectionBodyContent extends React.Component {
setIsLoading(true); setIsLoading(true);
fetchFileVersions(fileId).then(() => setIsLoading(false)); fetchFileVersions(fileId).then(() => setIsLoading(false));
}; };
onSetRestoreProcess = (restoring) => {
const { isRestoreProcess } = this.state;
if (restoring) {
this.timerId = setTimeout(
() =>
this.setState({
isRestoreProcess: restoring,
}),
100
);
} else {
clearTimeout(this.timerId);
this.timerId = null;
restoring !== isRestoreProcess &&
this.setState({
isRestoreProcess: restoring,
});
}
};
onUpdateHeight = (i, itemHeight) => {
if (this.listRef.current) {
this.listRef.current.resetAfterIndex(i);
}
this.setState((prevState) => ({
rowSizes: {
...prevState.rowSizes,
[i]: itemHeight + 24, //composed of itemHeight = clientHeight of div and padding-top = 12px and padding-bottom = 12px
},
}));
};
getSize = (i) => {
return this.state.rowSizes[i] ? this.state.rowSizes[i] : 66;
};
renderRow = memo(({ index, style }) => {
const { versions, culture } = this.props;
const prevVersion = versions[index > 0 ? index - 1 : index].versionGroup;
let isVersion = true;
if (index > 0 && prevVersion === versions[index].versionGroup) {
isVersion = false;
}
return (
<div style={style}>
<VersionRow
getFileVersions={this.getFileVersions}
isVersion={isVersion}
key={`${versions[index].id}-${index}`}
info={versions[index]}
versionsListLength={versions.length}
index={index}
culture={culture}
onSetRestoreProcess={this.onSetRestoreProcess}
onUpdateHeight={this.onUpdateHeight}
/>
</div>
);
}, areEqual);
render() { render() {
const { versions, culture, isLoading } = this.props; const { versions, isLoading } = this.props;
//console.log("VersionHistory SectionBodyContent render()", versions);
let itemVersion = null; const renderList = ({ height, width }) => {
return (
<StyledVersionList isRestoreProcess={this.state.isRestoreProcess}>
<List
ref={this.listRef}
className="List"
height={height}
width={width}
itemSize={this.getSize}
itemCount={versions.length}
itemData={versions}
outerElementType={CustomScrollbarsVirtualList}
>
{this.renderRow}
</List>
</StyledVersionList>
);
};
return versions && !isLoading ? ( return (
<RowContainer useReactWindow={false}> <StyledBody>
{versions.map((info, index) => { {versions && !isLoading ? (
let isVersion = true; <div className="version-list">
if (itemVersion === info.versionGroup) { <AutoSizer>{renderList}</AutoSizer>
isVersion = false; </div>
} else { ) : (
itemVersion = info.versionGroup; <div className="loader-history-rows">
} <Loaders.HistoryRows title="version-history-body-loader" />
</div>
return ( )}
<VersionRow </StyledBody>
getFileVersions={this.getFileVersions}
isVersion={isVersion}
key={`${info.id}-${index}`}
info={info}
index={index}
culture={culture}
/>
);
})}
</RowContainer>
) : (
<Loaders.HistoryRows title="version-history-body-loader" />
); );
} }
} }

View File

@ -50,12 +50,12 @@ class PureVersionHistory extends React.Component {
return ( return (
<PageLayout <PageLayout
withBodyScroll={true}
withBodyAutoFocus={true} withBodyAutoFocus={true}
headerBorderBottom={true} headerBorderBottom={true}
showSecondaryProgressBar={showProgressBar} showSecondaryProgressBar={showProgressBar}
secondaryProgressBarIcon="file" secondaryProgressBarIcon="file"
showSecondaryButtonAlert={false}> showSecondaryButtonAlert={false}
withBodyScroll={false}>
<PageLayout.ArticleHeader> <PageLayout.ArticleHeader>
<ArticleHeaderContent /> <ArticleHeaderContent />
</PageLayout.ArticleHeader> </PageLayout.ArticleHeader>

View File

@ -20,6 +20,7 @@ class DialogsStore {
newFilesPanelVisible = false; newFilesPanelVisible = false;
conflictResolveDialogVisible = false; conflictResolveDialogVisible = false;
convertDialogVisible = false; convertDialogVisible = false;
isFolderActions = false;
removeItem = null; removeItem = null;
connectItem = null; connectItem = null;
@ -44,6 +45,10 @@ class DialogsStore {
this.sharingPanelVisible = sharingPanelVisible; this.sharingPanelVisible = sharingPanelVisible;
}; };
setIsFolderActions = (isFolderActions) => {
this.isFolderActions = isFolderActions;
};
setChangeOwnerPanelVisible = (ownerPanelVisible) => { setChangeOwnerPanelVisible = (ownerPanelVisible) => {
this.ownerPanelVisible = ownerPanelVisible; this.ownerPanelVisible = ownerPanelVisible;
}; };

View File

@ -61,13 +61,24 @@ class FilesActionStore {
clearSecondaryProgressData, clearSecondaryProgressData,
} = this.uploadDataStore.secondaryProgressDataStore; } = this.uploadDataStore.secondaryProgressDataStore;
let updatedFolder = this.selectedFolderStore.id;
if (this.dialogsStore.isFolderActions) {
updatedFolder = this.selectedFolderStore.parentId;
}
const { filter, fetchFiles } = this.filesStore; const { filter, fetchFiles } = this.filesStore;
fetchFiles(this.selectedFolderStore.id, filter, true, true).finally(() => fetchFiles(updatedFolder, filter, true, true).finally(() => {
setTimeout(() => clearSecondaryProgressData(), TIMEOUT) this.dialogsStore.setIsFolderActions(false);
); return setTimeout(() => clearSecondaryProgressData(), TIMEOUT);
});
}; };
deleteAction = async (translations, newSelection = null) => { deleteAction = async (
translations,
newSelection = null,
withoutDialog = false
) => {
const { isRecycleBinFolder, isPrivacyFolder } = this.treeFoldersStore; const { isRecycleBinFolder, isPrivacyFolder } = this.treeFoldersStore;
const selection = newSelection ? newSelection : this.filesStore.selection; const selection = newSelection ? newSelection : this.filesStore.selection;
@ -88,8 +99,8 @@ class FilesActionStore {
const deleteAfter = false; //Delete after finished TODO: get from settings const deleteAfter = false; //Delete after finished TODO: get from settings
const immediately = isRecycleBinFolder || isPrivacyFolder ? true : false; //Don't move to the Recycle Bin const immediately = isRecycleBinFolder || isPrivacyFolder ? true : false; //Don't move to the Recycle Bin
const folderIds = []; let folderIds = [];
const fileIds = []; let fileIds = [];
let i = 0; let i = 0;
while (selection.length !== i) { while (selection.length !== i) {
@ -101,6 +112,13 @@ class FilesActionStore {
i++; i++;
} }
if (this.dialogsStore.isFolderActions && withoutDialog) {
folderIds = [];
fileIds = [];
folderIds.push(selection[0]);
}
if (folderIds.length || fileIds.length) { if (folderIds.length || fileIds.length) {
this.isMediaOpen(); this.isMediaOpen();
@ -211,18 +229,18 @@ class FilesActionStore {
} }
}; };
downloadAction = (label) => { downloadAction = (label, folderId) => {
const { bufferSelection } = this.filesStore; const { bufferSelection } = this.filesStore;
const selection = this.filesStore.selection.length const selection = this.filesStore.selection.length
? this.filesStore.selection ? this.filesStore.selection
: [bufferSelection]; : [bufferSelection];
const fileIds = []; let fileIds = [];
const folderIds = []; let folderIds = [];
const items = []; const items = [];
if (selection.length === 1 && selection[0].fileExst) { if (selection.length === 1 && selection[0].fileExst && !folderId) {
window.open(selection[0].viewUrl, "_self"); window.open(selection[0].viewUrl, "_self");
return Promise.resolve(); return Promise.resolve();
} }
@ -237,6 +255,14 @@ class FilesActionStore {
} }
} }
if (this.dialogsStore.isFolderActions) {
fileIds = [];
folderIds = [];
folderIds.push(bufferSelection);
this.dialogsStore.setIsFolderActions(false);
}
return this.downloadFiles(fileIds, folderIds, label); return this.downloadFiles(fileIds, folderIds, label);
}; };

View File

@ -1062,7 +1062,7 @@ class FilesStore {
const { getFileIcon, getFolderIcon } = this.formatsStore.iconFormatsStore; const { getFileIcon, getFolderIcon } = this.formatsStore.iconFormatsStore;
if (items.length && items[0].id === -1) return; //TODO: if change media collection from state remove this; if (items.length && items[0].id === -1) return; //TODO: if change media collection from state remove this;
const iconSize = this.viewAs === "tile" ? 32 : 24; const iconSize = this.viewAs === "tile" && isMobile ? 32 : 24;
const icon = this.fileActionStore.extension const icon = this.fileActionStore.extension
? getFileIcon(`.${this.fileActionStore.extension}`, iconSize) ? getFileIcon(`.${this.fileActionStore.extension}`, iconSize)
: getFolderIcon(null, iconSize); : getFolderIcon(null, iconSize);
@ -1134,7 +1134,7 @@ class FilesStore {
const isThirdPartyFolder = providerKey && id === rootFolderId; const isThirdPartyFolder = providerKey && id === rootFolderId;
//const isCanWebEdit = canWebEdit(item.fileExst); //const isCanWebEdit = canWebEdit(item.fileExst);
const iconSize = this.viewAs === "tile" ? 32 : 24; const iconSize = this.viewAs === "tile" && isMobile ? 32 : 24;
const icon = getIcon(iconSize, fileExst, providerKey, contentLength); const icon = getIcon(iconSize, fileExst, providerKey, contentLength);
let isFolder = false; let isFolder = false;
@ -1573,6 +1573,7 @@ class FilesStore {
getFolderInfo = async (id) => { getFolderInfo = async (id) => {
const folderInfo = await api.files.getFolderInfo(id); const folderInfo = await api.files.getFolderInfo(id);
this.setFolder(folderInfo); this.setFolder(folderInfo);
return folderInfo;
}; };
openDocEditor = (id, providerKey = null, tab = null, url = null) => { openDocEditor = (id, providerKey = null, tab = null, url = null) => {

View File

@ -389,7 +389,7 @@ class UploadDataStore {
this.uploadToFolder = null; this.uploadToFolder = null;
this.percent = 0; this.percent = 0;
} }
if (this.converted) { if (this.uploaded && this.converted) {
this.files = []; this.files = [];
this.filesToConversion = []; this.filesToConversion = [];
} }
@ -874,25 +874,25 @@ class UploadDataStore {
return; return;
} }
let operationItem = null; let operationItem = data;
let finished = data.finished;
while (progress !== 100) { while (!finished) {
await this.getOperationProgress(data.id) const item = await this.getOperationProgress(data.id);
.then((item) => { operationItem = item;
operationItem = item; progress = item ? item.progress : 100;
progress = item ? item.progress : 100; finished = item.finished;
setSecondaryProgressBarData({ setSecondaryProgressBarData({
icon: pbData.icon, icon: pbData.icon,
label: pbData.label || label, label: pbData.label || label,
percent: progress, percent: progress,
visible: true, visible: true,
alert: false, alert: false,
}); });
})
.catch((err) => Promise.reject(err));
} }
return Promise.resolve(operationItem);
return operationItem;
}; };
moveToCopyTo = (destFolderId, pbData, isCopy) => { moveToCopyTo = (destFolderId, pbData, isCopy) => {
@ -904,7 +904,15 @@ class UploadDataStore {
label, label,
} = this.secondaryProgressDataStore; } = this.secondaryProgressDataStore;
getFolder(destFolderId).then((data) => { let receivedFolder = destFolderId;
let updatedFolder = this.selectedFolderStore.id;
if (this.dialogsStore.isFolderActions) {
receivedFolder = this.selectedFolderStore.parentId;
updatedFolder = destFolderId;
}
getFolder(receivedFolder).then((data) => {
let newTreeFolders = treeFolders; let newTreeFolders = treeFolders;
let path = data.pathParts.slice(0); let path = data.pathParts.slice(0);
let folders = data.folders; let folders = data.folders;
@ -912,11 +920,12 @@ class UploadDataStore {
loopTreeFolders(path, newTreeFolders, folders, foldersCount); loopTreeFolders(path, newTreeFolders, folders, foldersCount);
if (!isCopy || destFolderId === this.selectedFolderStore.id) { if (!isCopy || destFolderId === this.selectedFolderStore.id) {
fetchFiles(this.selectedFolderStore.id, filter, true, true).finally( this.filesStore
() => { .fetchFiles(updatedFolder, this.filesStore.filter, true, true)
.finally(() => {
setTimeout(() => clearSecondaryProgressData(), TIMEOUT); setTimeout(() => clearSecondaryProgressData(), TIMEOUT);
} this.dialogsStore.setIsFolderActions(false);
); });
} else { } else {
setSecondaryProgressBarData({ setSecondaryProgressBarData({
icon: pbData.icon, icon: pbData.icon,

View File

@ -7,6 +7,7 @@ class VersionHistoryStore {
versions = null; versions = null;
filesStore = null; filesStore = null;
showProgressBar = false; showProgressBar = false;
timerId = null;
constructor(filesStore) { constructor(filesStore) {
makeObservable(this, { makeObservable(this, {
@ -79,7 +80,7 @@ class VersionHistoryStore {
}; };
restoreVersion = (id, version) => { restoreVersion = (id, version) => {
this.setShowProgressBar(true); this.timerId = setTimeout(() => this.setShowProgressBar(true), 100);
return api.files return api.files
.versionRestore(id, version) .versionRestore(id, version)
@ -87,9 +88,13 @@ class VersionHistoryStore {
const updatedVersions = this.versions.slice(); const updatedVersions = this.versions.slice();
updatedVersions.splice(1, 0, newVersion); updatedVersions.splice(1, 0, newVersion);
this.setVerHistoryFileVersions(updatedVersions); this.setVerHistoryFileVersions(updatedVersions);
this.setShowProgressBar(false);
}) })
.catch(() => this.setShowProgressBar(false)); .catch((e) => console.error(e))
.finally(() => {
clearTimeout(this.timerId);
this.timerId = null;
this.setShowProgressBar(false);
});
}; };
updateCommentVersion = (id, comment, version) => { updateCommentVersion = (id, comment, version) => {

View File

@ -515,6 +515,7 @@ namespace ASC.Files.Core.Data
var toInsert = FilesDbContext.Tree var toInsert = FilesDbContext.Tree
.Where(r => r.FolderId == toFolderId) .Where(r => r.FolderId == toFolderId)
.OrderBy(r => r.Level)
.ToList(); .ToList();
foreach (var subfolder in subfolders) foreach (var subfolder in subfolders)
@ -525,7 +526,7 @@ namespace ASC.Files.Core.Data
{ {
FolderId = subfolder.Key, FolderId = subfolder.Key,
ParentId = f.ParentId, ParentId = f.ParentId,
Level = f.Level + 1 Level = subfolder.Value + 1 + f.Level
}; };
FilesDbContext.AddOrUpdate(r => r.Tree, newTree); FilesDbContext.AddOrUpdate(r => r.Tree, newTree);
} }

View File

@ -36,6 +36,7 @@ using ASC.Common.Threading;
using ASC.Common.Web; using ASC.Common.Web;
using ASC.Core.Tenants; using ASC.Core.Tenants;
using ASC.Files.Core; using ASC.Files.Core;
using ASC.Files.Core.EF;
using ASC.Files.Core.Resources; using ASC.Files.Core.Resources;
using ASC.MessagingSystem; using ASC.MessagingSystem;
using ASC.Web.Core.Files; using ASC.Web.Core.Files;
@ -116,11 +117,44 @@ namespace ASC.Web.Files.Services.WCFService.FileOperations
stream, stream,
MimeMapping.GetMimeMapping(path), MimeMapping.GetMimeMapping(path),
"attachment; filename=\"" + fileName + "\""); "attachment; filename=\"" + fileName + "\"");
Result = string.Format("{0}?{1}=bulk&ext={2}", filesLinkUtility.FileHandlerPath, FilesLinkUtility.Action, archiveExtension); Result = string.Format("{0}?{1}=bulk&ext={2}", filesLinkUtility.FileHandlerPath, FilesLinkUtility.Action, archiveExtension);
TaskInfo.SetProperty(PROGRESS, 100);
TaskInfo.SetProperty(RESULT, Result);
TaskInfo.SetProperty(FINISHED, true);
} }
FillDistributedTask();
TaskInfo.PublishChanges(); TaskInfo.PublishChanges();
}
public override void PublishChanges(DistributedTask task)
{
var thirdpartyTask = ThirdPartyOperation.GetDistributedTask();
var daoTask = DaoOperation.GetDistributedTask();
var error1 = thirdpartyTask.GetProperty<string>(ERROR);
var error2 = daoTask.GetProperty<string>(ERROR);
if (!string.IsNullOrEmpty(error1))
{
Error = error1;
}
else if (!string.IsNullOrEmpty(error2))
{
Error = error2;
}
successProcessed = thirdpartyTask.GetProperty<int>(PROCESSED) + daoTask.GetProperty<int>(PROCESSED);
var progressSteps = ThirdPartyOperation.Total + DaoOperation.Total + 1;
var progress = (int)(successProcessed / (double)progressSteps * 100);
base.FillDistributedTask();
TaskInfo.SetProperty(PROGRESS, progress < 100 ? progress : progress);
TaskInfo.PublishChanges();
} }
} }
@ -145,7 +179,8 @@ namespace ASC.Web.Files.Services.WCFService.FileOperations
{ {
if (!Files.Any() && !Folders.Any()) return; if (!Files.Any() && !Folders.Any()) return;
entriesPathId = GetEntriesPathId(scope); entriesPathId = GetEntriesPathId(scope);
if (entriesPathId == null || entriesPathId.Count == 0) if (entriesPathId == null || entriesPathId.Count == 0)
{ {
if (Files.Count > 0) if (Files.Count > 0)
@ -156,7 +191,11 @@ namespace ASC.Web.Files.Services.WCFService.FileOperations
throw new DirectoryNotFoundException(FilesCommonResource.ErrorMassage_FolderNotFound); throw new DirectoryNotFoundException(FilesCommonResource.ErrorMassage_FolderNotFound);
} }
ReplaceLongPath(entriesPathId); ReplaceLongPath(entriesPathId);
Total = entriesPathId.Count;
TaskInfo.PublishChanges();
} }
private ItemNameValueCollection<T> ExecPathFromFile(IServiceScope scope, File<T> file, string path) private ItemNameValueCollection<T> ExecPathFromFile(IServiceScope scope, File<T> file, string path)
@ -236,7 +275,7 @@ namespace ASC.Web.Files.Services.WCFService.FileOperations
} }
return entriesPathId; return entriesPathId;
} }
internal void CompressToZip(Stream stream, IServiceScope scope) internal void CompressToZip(Stream stream, IServiceScope scope)
{ {
if (entriesPathId == null) return; if (entriesPathId == null) return;
@ -345,6 +384,15 @@ namespace ASC.Web.Files.Services.WCFService.FileOperations
} }
compressTo.CloseEntry(); compressTo.CloseEntry();
counter++; counter++;
if (!Equals(entryId, default(T)) && file != null)
{
ProcessedFile(entryId);
}
else
{
ProcessedFolder(default(T));
}
} }
ProgressStep(); ProgressStep();

View File

@ -149,7 +149,7 @@ namespace ASC.Web.Files.Services.WCFService.FileOperations
base.FillDistributedTask(); base.FillDistributedTask();
} }
public void PublishChanges(DistributedTask task) public virtual void PublishChanges(DistributedTask task)
{ {
var thirdpartyTask = ThirdPartyOperation.GetDistributedTask(); var thirdpartyTask = ThirdPartyOperation.GetDistributedTask();
var daoTask = DaoOperation.GetDistributedTask(); var daoTask = DaoOperation.GetDistributedTask();

View File

@ -11,7 +11,7 @@
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="AppLimit.CloudComputing.SharpBox" Version="1.1.0.456" /> <PackageReference Include="AppLimit.CloudComputing.SharpBox" Version="1.1.0.457" />
<PackageReference Include="Autofac" Version="6.0.0" /> <PackageReference Include="Autofac" Version="6.0.0" />
<PackageReference Include="Autofac.Configuration" Version="6.0.0" /> <PackageReference Include="Autofac.Configuration" Version="6.0.0" />
<PackageReference Include="Autofac.Extensions.DependencyInjection" Version="7.1.0" /> <PackageReference Include="Autofac.Extensions.DependencyInjection" Version="7.1.0" />

View File

@ -21,8 +21,6 @@ class ContactField extends React.Component {
} }
render() { render() {
console.log("ContactField render");
const { const {
isDisabled, isDisabled,

View File

@ -66,8 +66,6 @@ class ContactsField extends React.Component {
} }
render() { render() {
console.log("ContactsField render");
const { const {
pattern, pattern,
contacts, contacts,

View File

@ -9,8 +9,6 @@ class DateField extends React.Component {
} }
render() { render() {
console.log("DateField render");
const { const {
isRequired, isRequired,
hasError, hasError,

View File

@ -16,8 +16,6 @@ class DepartmentField extends React.Component {
}; };
render() { render() {
console.log("DepartmentField render");
const { const {
isRequired, isRequired,
isDisabled, isDisabled,

View File

@ -9,8 +9,6 @@ class EmailField extends React.Component {
} }
render() { render() {
console.log("EmailField render");
const { const {
isRequired, isRequired,
hasError, hasError,

View File

@ -11,8 +11,6 @@ class PasswordField extends React.Component {
} }
render() { render() {
console.log("PasswordField render");
const { const {
isRequired, isRequired,
hasError, hasError,

View File

@ -9,8 +9,6 @@ class RadioField extends React.Component {
} }
render() { render() {
//console.log("RadioField render");
const { const {
isRequired, isRequired,
hasError, hasError,

View File

@ -18,8 +18,6 @@ class TextChangeField extends React.Component {
} }
render() { render() {
console.log("TextChangeField render");
const { const {
isRequired, isRequired,
hasError, hasError,

View File

@ -9,8 +9,6 @@ class TextField extends React.Component {
} }
render() { render() {
console.log("TextField render");
const { const {
isRequired, isRequired,
hasError, hasError,

View File

@ -499,7 +499,6 @@ class UpdateUserForm extends React.Component {
this.setState({ isLoading: true }); this.setState({ isLoading: true });
const { profile, setAvatarMax, personal } = this.props; const { profile, setAvatarMax, personal } = this.props;
console.log("profile", profile);
if (isUpdate) { if (isUpdate) {
createThumbnailsAvatar(profile.id, { createThumbnailsAvatar(profile.id, {
x: Math.round(result.x * avatar.defaultWidth - result.width / 2), x: Math.round(result.x * avatar.defaultWidth - result.width / 2),
@ -727,7 +726,6 @@ class UpdateUserForm extends React.Component {
source={this.props.avatarMax || profile.avatarMax} source={this.props.avatarMax || profile.avatarMax}
userName={profile.displayName} userName={profile.displayName}
editing={true} editing={true}
editLabel={t("Common:EditAvatar")}
editAction={ editAction={
isMobile ? this.openAvatarEditorPage : this.openAvatarEditor isMobile ? this.openAvatarEditorPage : this.openAvatarEditor
} }

View File

@ -0,0 +1,3 @@
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M1.35866 11.0127L0.366956 14.6494C0.204108 15.2466 0.752062 15.7945 1.34924 15.6317L4.98595 14.64C5.32177 14.5484 5.62787 14.3708 5.87399 14.1247L12.7918 7.20689L8.79177 3.20689L1.87399 10.1247C1.62787 10.3708 1.45024 10.6769 1.35866 11.0127ZM10.2059 1.79264L14.2059 5.79264L14.9985 4.99999C16.103 3.89541 16.103 2.1046 14.9985 1.00006C13.8939 -0.104537 12.103 -0.104507 10.9984 1.00012L10.2059 1.79264Z" fill="white"/>
</svg>

After

Width:  |  Height:  |  Size: 572 B