Merge branch 'develop' into feature/thumbnails
# Conflicts: # products/ASC.Files/Client/src/Files.jsx # products/ASC.Files/Client/src/components/pages/Home/Section/Body/FilesContent.js # products/ASC.Files/Client/src/components/pages/Home/Section/Body/FilesRow/FilesRowContainer.js # products/ASC.Files/Client/src/components/pages/Home/Section/Body/FilesRow/SimpleFilesRow.js # products/ASC.Files/Client/src/components/pages/Home/Section/Body/FilesTileContent.js # products/ASC.Files/Client/src/components/pages/Home/Section/Body/index.js # products/ASC.Files/Client/src/store/InitFilesStore.js
@ -1,4 +1,4 @@
|
||||
import { action, computed, makeObservable, observable } from "mobx";
|
||||
import { makeAutoObservable } from "mobx";
|
||||
import api from "../api";
|
||||
import { ARTICLE_PINNED_KEY, LANGUAGE } from "../constants";
|
||||
import { combineUrl } from "../utils";
|
||||
@ -69,68 +69,7 @@ class SettingsStore {
|
||||
hasShortenService = false;
|
||||
|
||||
constructor() {
|
||||
makeObservable(this, {
|
||||
currentProductId: observable,
|
||||
culture: observable,
|
||||
cultures: observable,
|
||||
trustedDomains: observable,
|
||||
trustedDomainsType: observable,
|
||||
timezone: observable,
|
||||
timezones: observable,
|
||||
utcOffset: observable,
|
||||
utcHoursOffset: observable,
|
||||
defaultPage: observable,
|
||||
homepage: observable,
|
||||
datePattern: observable,
|
||||
datePatternJQ: observable,
|
||||
dateTimePattern: observable,
|
||||
datepicker: observable,
|
||||
organizationName: observable,
|
||||
greetingSettings: observable,
|
||||
enableAdmMess: observable,
|
||||
urlLicense: observable,
|
||||
urlSupport: observable,
|
||||
urlAuthKeys: computed,
|
||||
logoUrl: observable,
|
||||
customNames: observable,
|
||||
isDesktopClient: observable,
|
||||
isEncryptionSupport: observable,
|
||||
encryptionKeys: observable,
|
||||
isHeaderVisible: observable,
|
||||
isTabletView: observable,
|
||||
isArticlePinned: observable,
|
||||
hashSettings: observable,
|
||||
ownerId: observable,
|
||||
nameSchemaId: observable,
|
||||
wizardToken: observable,
|
||||
wizardCompleted: computed,
|
||||
passwordSettings: observable,
|
||||
hasShortenService: observable,
|
||||
getSettings: action,
|
||||
getCurrentCustomSchema: action,
|
||||
getPortalSettings: action,
|
||||
init: action,
|
||||
isLoaded: observable,
|
||||
isLoading: observable,
|
||||
setIsLoading: action,
|
||||
setIsLoaded: action,
|
||||
getPortalCultures: action,
|
||||
getIsEncryptionSupport: action,
|
||||
updateEncryptionKeys: action,
|
||||
setEncryptionKeys: action,
|
||||
getEncryptionKeys: action,
|
||||
setModuleInfo: action,
|
||||
setCurrentProductId: action,
|
||||
setWizardComplete: action,
|
||||
setPasswordSettings: action,
|
||||
getPortalPasswordSettings: action,
|
||||
setTimezones: action,
|
||||
getPortalTimezones: action,
|
||||
setHeaderVisible: action,
|
||||
setIsTabletView: action,
|
||||
setValue: action,
|
||||
setArticlePinned: action,
|
||||
});
|
||||
makeAutoObservable(this);
|
||||
}
|
||||
|
||||
get urlAuthKeys() {
|
||||
@ -203,8 +142,13 @@ class SettingsStore {
|
||||
this.cultures = await api.settings.getPortalCultures();
|
||||
};
|
||||
|
||||
setIsEncryptionSupport = (isEncryptionSupport) => {
|
||||
this.isEncryptionSupport = isEncryptionSupport;
|
||||
};
|
||||
|
||||
getIsEncryptionSupport = async () => {
|
||||
this.isEncryptionSupport = await api.files.getIsEncryptionSupport();
|
||||
const isEncryptionSupport = await api.files.getIsEncryptionSupport();
|
||||
this.setIsEncryptionSupport(isEncryptionSupport);
|
||||
};
|
||||
|
||||
updateEncryptionKeys = (encryptionKeys) => {
|
||||
|
@ -30,8 +30,6 @@ class ContextMenuButton extends React.Component {
|
||||
isOpen: props.opened,
|
||||
data: props.data,
|
||||
displayType,
|
||||
offsetX: props.manualX,
|
||||
offsetY: props.manualY,
|
||||
};
|
||||
this.throttledResize = throttle(this.resize, 300);
|
||||
}
|
||||
@ -73,10 +71,6 @@ class ContextMenuButton extends React.Component {
|
||||
this.toggle(this.props.opened);
|
||||
}
|
||||
|
||||
if (this.props.manualX !== prevProps.manualX) {
|
||||
this.onContextClick();
|
||||
}
|
||||
|
||||
if (this.props.opened && this.state.displayType === "aside") {
|
||||
window.addEventListener("popstate", this.popstate, false);
|
||||
}
|
||||
@ -86,20 +80,6 @@ class ContextMenuButton extends React.Component {
|
||||
}
|
||||
}
|
||||
|
||||
onContextClick = () => {
|
||||
if (this.props.isDisabled) {
|
||||
this.stopAction;
|
||||
return;
|
||||
}
|
||||
|
||||
this.setState({
|
||||
data: this.props.getData(),
|
||||
isOpen: !this.state.isOpen,
|
||||
offsetX: this.props.manualX,
|
||||
offsetY: this.props.manualY,
|
||||
});
|
||||
};
|
||||
|
||||
onIconButtonClick = () => {
|
||||
if (this.props.isDisabled) {
|
||||
this.stopAction;
|
||||
@ -110,8 +90,6 @@ class ContextMenuButton extends React.Component {
|
||||
{
|
||||
data: this.props.getData(),
|
||||
isOpen: !this.state.isOpen,
|
||||
offsetX: "0px",
|
||||
offsetY: "100%",
|
||||
},
|
||||
() =>
|
||||
!this.props.isDisabled &&
|
||||
@ -194,15 +172,12 @@ class ContextMenuButton extends React.Component {
|
||||
/>
|
||||
{displayType === "dropdown" ? (
|
||||
<DropDown
|
||||
id="contextMenu"
|
||||
manualX={offsetX}
|
||||
manualY={offsetY}
|
||||
directionX={directionX}
|
||||
directionY={directionY}
|
||||
open={isOpen}
|
||||
clickOutsideAction={this.clickOutsideAction}
|
||||
columnCount={columnCount}
|
||||
withBackdrop={isMobile}
|
||||
withBackdrop={!!isMobile}
|
||||
>
|
||||
{this.state.data.map(
|
||||
(item, index) =>
|
||||
@ -299,10 +274,6 @@ ContextMenuButton.propTypes = {
|
||||
directionX: PropTypes.string,
|
||||
/** Direction Y */
|
||||
directionY: PropTypes.string,
|
||||
/** Manual X padding */
|
||||
manualX: PropTypes.string,
|
||||
/** Manual Y padding */
|
||||
manualY: PropTypes.string,
|
||||
/** Accepts class */
|
||||
className: PropTypes.string,
|
||||
/** Accepts id */
|
||||
|
@ -1,14 +1,10 @@
|
||||
import React from "react";
|
||||
import React, { useRef } from "react";
|
||||
|
||||
import RowContainer from "../row-container";
|
||||
import RowContent from "../row-content";
|
||||
import Row from "../row";
|
||||
import ContextMenu from "./index";
|
||||
|
||||
export default {
|
||||
title: "Components/ContextMenu",
|
||||
component: ContextMenu,
|
||||
subcomponents: { RowContainer, Row, RowContent },
|
||||
parameters: {
|
||||
docs: {
|
||||
description: {
|
||||
@ -24,37 +20,112 @@ In particular case, state is created containing options for particular Row eleme
|
||||
},
|
||||
};
|
||||
|
||||
const getRndString = (n) =>
|
||||
Math.random()
|
||||
.toString(36)
|
||||
.substring(2, n + 2);
|
||||
const Template = (args) => {
|
||||
const cm = useRef(null);
|
||||
const items = [
|
||||
{
|
||||
label: "Edit",
|
||||
icon: "/static/images/catalog.folder.react.svg",
|
||||
},
|
||||
{
|
||||
label: "Preview",
|
||||
icon: "/static/images/catalog.folder.react.svg",
|
||||
},
|
||||
{
|
||||
separator: true,
|
||||
},
|
||||
{
|
||||
label: "Sharing settings",
|
||||
icon: "/static/images/catalog.folder.react.svg",
|
||||
},
|
||||
{
|
||||
label: "Link for portal users",
|
||||
icon: "/static/images/catalog.folder.react.svg",
|
||||
},
|
||||
{
|
||||
label: "Copy external link",
|
||||
icon: "/static/images/catalog.folder.react.svg",
|
||||
},
|
||||
{
|
||||
label: "Send by e-mail",
|
||||
icon: "/static/images/catalog.folder.react.svg",
|
||||
},
|
||||
{
|
||||
label: "Version history",
|
||||
icon: "/static/images/catalog.folder.react.svg",
|
||||
items: [
|
||||
{
|
||||
label: "Show version history",
|
||||
},
|
||||
{
|
||||
label: "Finalize version",
|
||||
},
|
||||
{
|
||||
label: "Unblock / Check-in",
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
separator: true,
|
||||
},
|
||||
{
|
||||
label: "Make as favorite",
|
||||
icon: "/static/images/catalog.folder.react.svg",
|
||||
},
|
||||
{
|
||||
label: "Download",
|
||||
icon: "/static/images/catalog.folder.react.svg",
|
||||
},
|
||||
{
|
||||
label: "Download as",
|
||||
icon: "/static/images/catalog.folder.react.svg",
|
||||
},
|
||||
{
|
||||
label: "Move or copy",
|
||||
icon: "/static/images/catalog.folder.react.svg",
|
||||
items: [
|
||||
{
|
||||
label: "Move to",
|
||||
},
|
||||
{
|
||||
label: "Copy",
|
||||
},
|
||||
{
|
||||
label: "Duplicate",
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
label: "Rename",
|
||||
icon: "/static/images/catalog.folder.react.svg",
|
||||
disabled: true,
|
||||
},
|
||||
{
|
||||
separator: true,
|
||||
},
|
||||
{
|
||||
label: "Quit",
|
||||
icon: "/static/images/catalog.folder.react.svg",
|
||||
},
|
||||
];
|
||||
|
||||
const array = Array.from(Array(10).keys());
|
||||
const Template = (args) => (
|
||||
<RowContainer {...args} manualHeight="300px">
|
||||
{array.map((item, index) => {
|
||||
return (
|
||||
<Row
|
||||
key={`${item + 1}`}
|
||||
contextOptions={
|
||||
index !== 3
|
||||
? [
|
||||
{ key: 1, label: getRndString(5) },
|
||||
{ key: 2, label: getRndString(5) },
|
||||
{ key: 3, label: getRndString(5) },
|
||||
{ key: 4, label: getRndString(5) },
|
||||
]
|
||||
: []
|
||||
}
|
||||
>
|
||||
<RowContent>
|
||||
<span>{getRndString(5)}</span>
|
||||
<></>
|
||||
</RowContent>
|
||||
</Row>
|
||||
);
|
||||
})}
|
||||
</RowContainer>
|
||||
);
|
||||
return (
|
||||
<div>
|
||||
<ContextMenu model={items} ref={cm}></ContextMenu>
|
||||
|
||||
<div
|
||||
style={{
|
||||
width: "200px",
|
||||
height: "200px",
|
||||
backgroundColor: "red",
|
||||
display: "inline-block",
|
||||
}}
|
||||
onContextMenu={(e) => cm.current.show(e)}
|
||||
>
|
||||
{""}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export const Default = Template.bind({});
|
||||
|
@ -13,7 +13,7 @@ describe("<ContextMenu />", () => {
|
||||
expect(wrapper).toExist();
|
||||
});
|
||||
|
||||
it("componentWillUnmount() test unmount", () => {
|
||||
/* it("componentWillUnmount() test unmount", () => {
|
||||
const wrapper = mount(<ContextMenu {...baseProps} />);
|
||||
|
||||
wrapper.unmount();
|
||||
@ -82,5 +82,5 @@ describe("<ContextMenu />", () => {
|
||||
wrapper.setState({ visible: true });
|
||||
|
||||
expect(wrapper.getDOMNode().style).toHaveProperty("color", "red");
|
||||
});
|
||||
}); */
|
||||
});
|
||||
|
@ -1,134 +1,589 @@
|
||||
import React from "react";
|
||||
import React, { Component } from "react";
|
||||
import PropTypes from "prop-types";
|
||||
import DropDownItem from "../drop-down-item";
|
||||
import DropDown from "../drop-down";
|
||||
import DomHelpers from "../utils/domHelpers";
|
||||
import ObjectUtils from "../utils/objectUtils";
|
||||
import { classNames } from "../utils/classNames";
|
||||
import { CSSTransition } from "react-transition-group";
|
||||
import { ReactSVG } from "react-svg";
|
||||
import Portal from "../portal";
|
||||
import StyledContextMenu from "./styled-context-menu";
|
||||
import ArrowIcon from "./svg/arrow.right.react.svg";
|
||||
|
||||
class ContextMenu extends React.PureComponent {
|
||||
class ContextMenuSub extends Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.state = {
|
||||
activeItem: null,
|
||||
};
|
||||
|
||||
this.onEnter = this.onEnter.bind(this);
|
||||
|
||||
this.submenuRef = React.createRef();
|
||||
}
|
||||
|
||||
onItemMouseEnter(e, item) {
|
||||
if (item.disabled) {
|
||||
e.preventDefault();
|
||||
return;
|
||||
}
|
||||
|
||||
this.setState({
|
||||
activeItem: item,
|
||||
});
|
||||
}
|
||||
|
||||
onItemClick(e, item) {
|
||||
if (item.disabled) {
|
||||
e.preventDefault();
|
||||
return;
|
||||
}
|
||||
|
||||
if (!item.url) {
|
||||
e.preventDefault();
|
||||
}
|
||||
|
||||
if (item.onClick) {
|
||||
item.onClick({
|
||||
originalEvent: e,
|
||||
});
|
||||
}
|
||||
|
||||
if (!item.items) {
|
||||
this.props.onLeafClick(e);
|
||||
}
|
||||
}
|
||||
|
||||
position() {
|
||||
const parentItem = this.submenuRef.current.parentElement;
|
||||
const containerOffset = DomHelpers.getOffset(
|
||||
this.submenuRef.current.parentElement
|
||||
);
|
||||
const viewport = DomHelpers.getViewport();
|
||||
const sublistWidth = this.submenuRef.current.offsetParent
|
||||
? this.submenuRef.current.offsetWidth
|
||||
: DomHelpers.getHiddenElementOuterWidth(this.submenuRef.current);
|
||||
const itemOuterWidth = DomHelpers.getOuterWidth(parentItem.children[0]);
|
||||
|
||||
this.submenuRef.current.style.top = "0px";
|
||||
|
||||
if (
|
||||
parseInt(containerOffset.left, 10) + itemOuterWidth + sublistWidth >
|
||||
viewport.width - DomHelpers.calculateScrollbarWidth()
|
||||
) {
|
||||
this.submenuRef.current.style.left = -1 * sublistWidth + "px";
|
||||
} else {
|
||||
this.submenuRef.current.style.left = itemOuterWidth + "px";
|
||||
}
|
||||
}
|
||||
|
||||
onEnter() {
|
||||
this.position();
|
||||
}
|
||||
|
||||
isActive() {
|
||||
return this.props.root || !this.props.resetMenu;
|
||||
}
|
||||
|
||||
static getDerivedStateFromProps(nextProps, prevState) {
|
||||
if (nextProps.resetMenu === true) {
|
||||
return {
|
||||
activeItem: null,
|
||||
};
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
componentDidUpdate() {
|
||||
if (this.isActive()) {
|
||||
this.position();
|
||||
}
|
||||
}
|
||||
|
||||
renderSeparator(index) {
|
||||
return (
|
||||
<li
|
||||
key={"separator_" + index}
|
||||
className="p-menu-separator"
|
||||
role="separator"
|
||||
></li>
|
||||
);
|
||||
}
|
||||
|
||||
renderSubmenu(item) {
|
||||
if (item.items) {
|
||||
return (
|
||||
<ContextMenuSub
|
||||
model={item.items}
|
||||
resetMenu={item !== this.state.activeItem}
|
||||
onLeafClick={this.props.onLeafClick}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
renderMenuitem(item, index) {
|
||||
if (item.disabled) return; //TODO: Not render disabled items
|
||||
const active = this.state.activeItem === item;
|
||||
const className = classNames(
|
||||
"p-menuitem",
|
||||
{ "p-menuitem-active": active },
|
||||
item.className
|
||||
);
|
||||
const linkClassName = classNames("p-menuitem-link", {
|
||||
"p-disabled": item.disabled,
|
||||
});
|
||||
const iconClassName = classNames("p-menuitem-icon", {
|
||||
"p-disabled": item.disabled,
|
||||
});
|
||||
const submenuIconClassName = "p-submenu-icon";
|
||||
const icon = item.icon && (
|
||||
<ReactSVG
|
||||
wrapper="span"
|
||||
className={iconClassName}
|
||||
src={item.icon}
|
||||
></ReactSVG>
|
||||
);
|
||||
const label = item.label && (
|
||||
<span className="p-menuitem-text">{item.label}</span>
|
||||
);
|
||||
const submenuIcon = item.items && (
|
||||
<ArrowIcon className={submenuIconClassName} />
|
||||
);
|
||||
const submenu = this.renderSubmenu(item);
|
||||
let content = (
|
||||
<a
|
||||
href={item.url || "#"}
|
||||
className={linkClassName}
|
||||
target={item.target}
|
||||
onClick={(event) => this.onItemClick(event, item, index)}
|
||||
role="menuitem"
|
||||
>
|
||||
{icon}
|
||||
{label}
|
||||
{submenuIcon}
|
||||
</a>
|
||||
);
|
||||
|
||||
if (item.template) {
|
||||
const defaultContentOptions = {
|
||||
onClick: (event) => this.onItemClick(event, item, index),
|
||||
className: linkClassName,
|
||||
labelClassName: "p-menuitem-text",
|
||||
iconClassName,
|
||||
submenuIconClassName,
|
||||
element: content,
|
||||
props: this.props,
|
||||
active,
|
||||
};
|
||||
|
||||
content = ObjectUtils.getJSXElement(
|
||||
item.template,
|
||||
item,
|
||||
defaultContentOptions
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<li
|
||||
key={item.label + "_" + index}
|
||||
role="none"
|
||||
className={className}
|
||||
style={item.style}
|
||||
onMouseEnter={(event) => this.onItemMouseEnter(event, item)}
|
||||
>
|
||||
{content}
|
||||
{submenu}
|
||||
</li>
|
||||
);
|
||||
}
|
||||
|
||||
renderItem(item, index) {
|
||||
if (item.isSeparator) return this.renderSeparator(index);
|
||||
else return this.renderMenuitem(item, index);
|
||||
}
|
||||
|
||||
renderMenu() {
|
||||
if (this.props.model) {
|
||||
return this.props.model.map((item, index) => {
|
||||
return this.renderItem(item, index);
|
||||
});
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
render() {
|
||||
const className = classNames({ "p-submenu-list": !this.props.root });
|
||||
const submenu = this.renderMenu();
|
||||
const isActive = this.isActive();
|
||||
|
||||
return (
|
||||
<CSSTransition
|
||||
nodeRef={this.submenuRef}
|
||||
classNames="p-contextmenusub"
|
||||
in={isActive}
|
||||
timeout={{ enter: 0, exit: 0 }}
|
||||
unmountOnExit={true}
|
||||
onEnter={this.onEnter}
|
||||
>
|
||||
<ul ref={this.submenuRef} className={className}>
|
||||
{submenu}
|
||||
</ul>
|
||||
</CSSTransition>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
ContextMenuSub.propTypes = {
|
||||
model: PropTypes.any,
|
||||
root: PropTypes.bool,
|
||||
className: PropTypes.string,
|
||||
resetMenu: PropTypes.bool,
|
||||
onLeafClick: PropTypes.func,
|
||||
};
|
||||
|
||||
ContextMenuSub.defaultProps = {
|
||||
model: null,
|
||||
root: false,
|
||||
className: null,
|
||||
resetMenu: false,
|
||||
onLeafClick: null,
|
||||
};
|
||||
|
||||
class ContextMenu extends Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
this.state = {
|
||||
visible: false,
|
||||
reshow: false,
|
||||
resetMenu: false,
|
||||
};
|
||||
|
||||
this.onMenuClick = this.onMenuClick.bind(this);
|
||||
this.onLeafClick = this.onLeafClick.bind(this);
|
||||
this.onMenuMouseEnter = this.onMenuMouseEnter.bind(this);
|
||||
this.onEnter = this.onEnter.bind(this);
|
||||
this.onEntered = this.onEntered.bind(this);
|
||||
this.onExit = this.onExit.bind(this);
|
||||
this.onExited = this.onExited.bind(this);
|
||||
|
||||
this.menuRef = React.createRef();
|
||||
}
|
||||
|
||||
onMenuClick() {
|
||||
this.setState({
|
||||
resetMenu: false,
|
||||
});
|
||||
}
|
||||
|
||||
onMenuMouseEnter() {
|
||||
this.setState({
|
||||
resetMenu: false,
|
||||
});
|
||||
}
|
||||
|
||||
show(e) {
|
||||
if (!(e instanceof Event)) {
|
||||
e.persist();
|
||||
}
|
||||
|
||||
e.stopPropagation();
|
||||
e.preventDefault();
|
||||
|
||||
this.currentEvent = e;
|
||||
|
||||
if (this.state.visible) {
|
||||
this.setState({ reshow: true });
|
||||
} else {
|
||||
this.setState({ visible: true }, () => {
|
||||
if (this.props.onShow) {
|
||||
this.props.onShow(this.currentEvent);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
componentDidUpdate(prevProps, prevState) {
|
||||
if (this.state.visible && prevState.reshow !== this.state.reshow) {
|
||||
let event = this.currentEvent;
|
||||
this.setState(
|
||||
{
|
||||
visible: false,
|
||||
reshow: false,
|
||||
rePosition: false,
|
||||
resetMenu: true,
|
||||
},
|
||||
() => this.show(event)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
hide(e) {
|
||||
if (!(e instanceof Event)) {
|
||||
e.persist();
|
||||
}
|
||||
|
||||
this.currentEvent = e;
|
||||
this.setState({ visible: false, reshow: false }, () => {
|
||||
if (this.props.onHide) {
|
||||
this.props.onHide(this.currentEvent);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
onEnter() {
|
||||
if (this.props.autoZIndex) {
|
||||
this.menuRef.current.style.zIndex = String(
|
||||
this.props.baseZIndex + DomHelpers.generateZIndex()
|
||||
);
|
||||
}
|
||||
|
||||
this.position(this.currentEvent);
|
||||
}
|
||||
|
||||
onEntered() {
|
||||
this.bindDocumentListeners();
|
||||
}
|
||||
|
||||
onExit() {
|
||||
this.currentEvent = null;
|
||||
this.unbindDocumentListeners();
|
||||
}
|
||||
|
||||
onExited() {
|
||||
DomHelpers.revertZIndex();
|
||||
}
|
||||
|
||||
position(event) {
|
||||
if (event) {
|
||||
let left = event.pageX + 1;
|
||||
let top = event.pageY + 1;
|
||||
let width = this.menuRef.current.offsetParent
|
||||
? this.menuRef.current.offsetWidth
|
||||
: DomHelpers.getHiddenElementOuterWidth(this.menuRef.current);
|
||||
let height = this.menuRef.current.offsetParent
|
||||
? this.menuRef.current.offsetHeight
|
||||
: DomHelpers.getHiddenElementOuterHeight(this.menuRef.current);
|
||||
let viewport = DomHelpers.getViewport();
|
||||
|
||||
//flip
|
||||
if (left + width - document.body.scrollLeft > viewport.width) {
|
||||
left -= width;
|
||||
}
|
||||
|
||||
//flip
|
||||
if (top + height - document.body.scrollTop > viewport.height) {
|
||||
top -= height;
|
||||
}
|
||||
|
||||
//fit
|
||||
if (left < document.body.scrollLeft) {
|
||||
left = document.body.scrollLeft;
|
||||
}
|
||||
|
||||
//fit
|
||||
if (top < document.body.scrollTop) {
|
||||
top = document.body.scrollTop;
|
||||
}
|
||||
|
||||
this.menuRef.current.style.left = left + "px";
|
||||
this.menuRef.current.style.top = top + "px";
|
||||
}
|
||||
}
|
||||
|
||||
onLeafClick(e) {
|
||||
this.setState({
|
||||
resetMenu: true,
|
||||
});
|
||||
|
||||
this.hide(e);
|
||||
|
||||
e.stopPropagation();
|
||||
}
|
||||
|
||||
isOutsideClicked(e) {
|
||||
return (
|
||||
this.menuRef &&
|
||||
this.menuRef.current &&
|
||||
!(
|
||||
this.menuRef.current.isSameNode(e.target) ||
|
||||
this.menuRef.current.contains(e.target)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
bindDocumentListeners() {
|
||||
this.bindDocumentResizeListener();
|
||||
this.bindDocumentClickListener();
|
||||
}
|
||||
|
||||
unbindDocumentListeners() {
|
||||
this.unbindDocumentResizeListener();
|
||||
this.unbindDocumentClickListener();
|
||||
}
|
||||
|
||||
bindDocumentClickListener() {
|
||||
if (!this.documentClickListener) {
|
||||
this.documentClickListener = (e) => {
|
||||
if (this.isOutsideClicked(e) && e.button !== 2) {
|
||||
this.hide(e);
|
||||
|
||||
this.setState({
|
||||
resetMenu: true,
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
document.addEventListener("click", this.documentClickListener);
|
||||
}
|
||||
}
|
||||
|
||||
bindDocumentContextMenuListener() {
|
||||
if (!this.documentContextMenuListener) {
|
||||
this.documentContextMenuListener = (e) => {
|
||||
this.show(e);
|
||||
};
|
||||
|
||||
document.addEventListener(
|
||||
"contextmenu",
|
||||
this.documentContextMenuListener
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
bindDocumentResizeListener() {
|
||||
if (!this.documentResizeListener) {
|
||||
this.documentResizeListener = (e) => {
|
||||
if (this.state.visible) {
|
||||
this.hide(e);
|
||||
}
|
||||
};
|
||||
|
||||
window.addEventListener("resize", this.documentResizeListener);
|
||||
}
|
||||
}
|
||||
|
||||
unbindDocumentClickListener() {
|
||||
if (this.documentClickListener) {
|
||||
document.removeEventListener("click", this.documentClickListener);
|
||||
this.documentClickListener = null;
|
||||
}
|
||||
}
|
||||
|
||||
unbindDocumentContextMenuListener() {
|
||||
if (this.documentContextMenuListener) {
|
||||
document.removeEventListener(
|
||||
"contextmenu",
|
||||
this.documentContextMenuListener
|
||||
);
|
||||
this.documentContextMenuListener = null;
|
||||
}
|
||||
}
|
||||
|
||||
unbindDocumentResizeListener() {
|
||||
if (this.documentResizeListener) {
|
||||
window.removeEventListener("resize", this.documentResizeListener);
|
||||
this.documentResizeListener = null;
|
||||
}
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
this.container =
|
||||
document.getElementById(this.props.targetAreaId) || document;
|
||||
|
||||
this.container.addEventListener("contextmenu", this.handleContextMenu);
|
||||
if (this.props.global) {
|
||||
this.bindDocumentContextMenuListener();
|
||||
}
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
this.container.removeEventListener("contextmenu", this.handleContextMenu);
|
||||
this.unbindDocumentListeners();
|
||||
this.unbindDocumentContextMenuListener();
|
||||
|
||||
DomHelpers.revertZIndex();
|
||||
}
|
||||
|
||||
moveMenu = (e) => {
|
||||
const menu = document.getElementById(this.props.id);
|
||||
|
||||
const bounds =
|
||||
this.container !== document && this.container.getBoundingClientRect();
|
||||
const clickX = e.clientX - bounds.left;
|
||||
const clickY = e.clientY - bounds.top;
|
||||
const containerWidth = this.container.offsetWidth;
|
||||
const containerHeight = this.container.offsetHeight;
|
||||
const menuWidth = (menu && menu.offsetWidth) || 180;
|
||||
const menuHeight = menu && menu.offsetHeight;
|
||||
|
||||
const right = containerWidth - clickX < menuWidth && clickX > menuWidth;
|
||||
const bottom = containerHeight - clickY < menuHeight && clickY > menuHeight;
|
||||
|
||||
let newTop = `0px`;
|
||||
let newLeft = `0px`;
|
||||
|
||||
newLeft = right ? `${clickX - menuWidth - 8}px` : `${clickX + 8}px`;
|
||||
newTop = bottom ? `${clickY - menuHeight}px` : `${clickY}px`;
|
||||
|
||||
if (menu) {
|
||||
menu.style.top = newTop;
|
||||
menu.style.left = newLeft;
|
||||
}
|
||||
};
|
||||
|
||||
handleContextMenu = (e) => {
|
||||
if (e) {
|
||||
e.preventDefault();
|
||||
this.handleClick(e);
|
||||
}
|
||||
|
||||
this.setState(
|
||||
{
|
||||
visible: true,
|
||||
},
|
||||
() => this.moveMenu(e)
|
||||
renderContextMenu() {
|
||||
const className = classNames(
|
||||
"p-contextmenu p-component",
|
||||
this.props.className
|
||||
);
|
||||
};
|
||||
|
||||
handleClick = (e) => {
|
||||
const { visible } = this.state;
|
||||
const menu = document.getElementById(this.props.id);
|
||||
const wasOutside = e.target ? !(e.target.contains === menu) : true;
|
||||
|
||||
if (wasOutside && visible) this.setState({ visible: false });
|
||||
};
|
||||
|
||||
itemClick = (action, e) => {
|
||||
action && action(e);
|
||||
|
||||
this.setState({ visible: false });
|
||||
};
|
||||
|
||||
render() {
|
||||
//console.log('ContextMenu render', this.props);
|
||||
const { visible } = this.state;
|
||||
const { options, id, className, style, withBackdrop } = this.props;
|
||||
|
||||
return (
|
||||
((visible && options) || null) && (
|
||||
<DropDown
|
||||
id={id}
|
||||
className={className}
|
||||
style={style}
|
||||
open={visible}
|
||||
clickOutsideAction={this.handleClick}
|
||||
withBackdrop={withBackdrop}
|
||||
<StyledContextMenu>
|
||||
<CSSTransition
|
||||
nodeRef={this.menuRef}
|
||||
classNames="p-contextmenu"
|
||||
in={this.state.visible}
|
||||
timeout={{ enter: 250, exit: 0 }}
|
||||
unmountOnExit
|
||||
onEnter={this.onEnter}
|
||||
onEntered={this.onEntered}
|
||||
onExit={this.onExit}
|
||||
onExited={this.onExited}
|
||||
>
|
||||
{options.map((item) => {
|
||||
if (item && item.key !== undefined) {
|
||||
return (
|
||||
<DropDownItem
|
||||
key={item.key}
|
||||
{...item}
|
||||
onClick={this.itemClick.bind(this, item.onClick)}
|
||||
/>
|
||||
);
|
||||
}
|
||||
})}
|
||||
</DropDown>
|
||||
)
|
||||
<div
|
||||
ref={this.menuRef}
|
||||
id={this.props.id}
|
||||
className={className}
|
||||
style={this.props.style}
|
||||
onClick={this.onMenuClick}
|
||||
onMouseEnter={this.onMenuMouseEnter}
|
||||
>
|
||||
<ContextMenuSub
|
||||
model={this.props.model}
|
||||
root
|
||||
resetMenu={this.state.resetMenu}
|
||||
onLeafClick={this.onLeafClick}
|
||||
/>
|
||||
</div>
|
||||
</CSSTransition>
|
||||
</StyledContextMenu>
|
||||
);
|
||||
}
|
||||
|
||||
render() {
|
||||
const element = this.renderContextMenu();
|
||||
|
||||
return <Portal element={element} appendTo={this.props.appendTo} />;
|
||||
}
|
||||
}
|
||||
|
||||
ContextMenu.propTypes = {
|
||||
/** DropDownItems collection */
|
||||
options: PropTypes.array,
|
||||
/** Id of container apply to */
|
||||
targetAreaId: PropTypes.string,
|
||||
/** Accepts class */
|
||||
className: PropTypes.string,
|
||||
/** Accepts id */
|
||||
/** Unique identifier of the element */
|
||||
id: PropTypes.string,
|
||||
/** Accepts css style */
|
||||
style: PropTypes.oneOfType([PropTypes.object, PropTypes.array]),
|
||||
/** Used to display backdrop */
|
||||
withBackdrop: PropTypes.bool,
|
||||
/** An array of menuitems */
|
||||
model: PropTypes.array,
|
||||
/** Inline style of the component */
|
||||
style: PropTypes.object,
|
||||
/** Style class of the component */
|
||||
className: PropTypes.string,
|
||||
/** Attaches the menu to document instead of a particular item */
|
||||
global: PropTypes.bool,
|
||||
/** Base zIndex value to use in layering */
|
||||
autoZIndex: PropTypes.bool,
|
||||
/** Whether to automatically manage layering */
|
||||
baseZIndex: PropTypes.number,
|
||||
/** DOM element instance where the menu should be mounted */
|
||||
appendTo: PropTypes.any,
|
||||
/** Callback to invoke when a popup menu is shown */
|
||||
onShow: PropTypes.func,
|
||||
/** Callback to invoke when a popup menu is hidden */
|
||||
onHide: PropTypes.func,
|
||||
};
|
||||
|
||||
ContextMenu.defaultProps = {
|
||||
options: [],
|
||||
id: "contextMenu",
|
||||
withBackdrop: true,
|
||||
id: null,
|
||||
model: null,
|
||||
style: null,
|
||||
className: null,
|
||||
global: false,
|
||||
autoZIndex: true,
|
||||
baseZIndex: 0,
|
||||
appendTo: null,
|
||||
onShow: null,
|
||||
onHide: null,
|
||||
};
|
||||
|
||||
export default ContextMenu;
|
||||
|
136
packages/asc-web-components/context-menu/styled-context-menu.js
Normal file
@ -0,0 +1,136 @@
|
||||
import styled from "styled-components";
|
||||
import Base from "../themes/base";
|
||||
|
||||
const StyledContextMenu = styled.div`
|
||||
.p-contextmenu {
|
||||
position: absolute;
|
||||
background: ${(props) => props.theme.dropDown.background};
|
||||
border-radius: ${(props) => props.theme.dropDown.borderRadius};
|
||||
-moz-border-radius: ${(props) => props.theme.dropDown.borderRadius};
|
||||
-webkit-border-radius: ${(props) => props.theme.dropDown.borderRadius};
|
||||
box-shadow: ${(props) => props.theme.dropDown.boxShadow};
|
||||
-moz-box-shadow: ${(props) => props.theme.dropDown.boxShadow};
|
||||
-webkit-box-shadow: ${(props) => props.theme.dropDown.boxShadow};
|
||||
padding: 4px 0px;
|
||||
}
|
||||
|
||||
.p-contextmenu ul {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
list-style: none;
|
||||
}
|
||||
|
||||
.p-contextmenu .p-submenu-list {
|
||||
position: absolute;
|
||||
background: ${(props) => props.theme.dropDown.background};
|
||||
border-radius: ${(props) => props.theme.dropDown.borderRadius};
|
||||
-moz-border-radius: ${(props) => props.theme.dropDown.borderRadius};
|
||||
-webkit-border-radius: ${(props) => props.theme.dropDown.borderRadius};
|
||||
box-shadow: ${(props) => props.theme.dropDown.boxShadow};
|
||||
-moz-box-shadow: ${(props) => props.theme.dropDown.boxShadow};
|
||||
-webkit-box-shadow: ${(props) => props.theme.dropDown.boxShadow};
|
||||
padding: 4px 0px;
|
||||
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
margin-left: 8px;
|
||||
margin-top: -4px;
|
||||
}
|
||||
|
||||
.p-contextmenu .p-menuitem-link {
|
||||
cursor: pointer;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
text-decoration: none;
|
||||
overflow: hidden;
|
||||
position: relative;
|
||||
border: ${(props) => props.theme.dropDownItem.border};
|
||||
margin: ${(props) => props.theme.dropDownItem.margin};
|
||||
padding: ${(props) => props.theme.dropDownItem.padding};
|
||||
font-family: ${(props) => props.theme.fontFamily};
|
||||
font-style: normal;
|
||||
background: none;
|
||||
user-select: none;
|
||||
outline: 0 !important;
|
||||
-webkit-tap-highlight-color: rgba(0, 0, 0, 0);
|
||||
|
||||
font-weight: ${(props) => props.theme.dropDownItem.fontWeight};
|
||||
font-size: ${(props) => props.theme.dropDownItem.fontSize};
|
||||
color: ${(props) => props.theme.dropDownItem.color};
|
||||
text-transform: none;
|
||||
|
||||
&:hover {
|
||||
background-color: ${(props) =>
|
||||
props.noHover
|
||||
? props.theme.dropDownItem.backgroundColor
|
||||
: props.theme.dropDownItem.hoverBackgroundColor};
|
||||
}
|
||||
|
||||
&.p-disabled {
|
||||
color: ${(props) => props.theme.dropDownItem.disableColor};
|
||||
|
||||
&:hover {
|
||||
cursor: default;
|
||||
background-color: ${(props) =>
|
||||
props.theme.dropDownItem.hoverDisabledBackgroundColor};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.p-contextmenu .p-menuitem-text {
|
||||
line-height: ${(props) => props.theme.dropDownItem.lineHeight};
|
||||
}
|
||||
|
||||
.p-contextmenu .p-menu-separator {
|
||||
cursor: default;
|
||||
padding: 0px 16px;
|
||||
margin: 4px 16px 4px;
|
||||
border-bottom: 1px solid #eceef1;
|
||||
width: calc(90%-32px);
|
||||
|
||||
&:hover {
|
||||
cursor: default;
|
||||
}
|
||||
}
|
||||
|
||||
.p-contextmenu .p-menuitem {
|
||||
position: relative;
|
||||
margin: ${(props) => props.theme.dropDownItem.margin};
|
||||
}
|
||||
|
||||
.p-menuitem-icon {
|
||||
max-height: ${(props) => props.theme.dropDownItem.lineHeight};
|
||||
|
||||
path {
|
||||
fill: ${(props) => props.theme.dropDownItem.icon.color};
|
||||
}
|
||||
|
||||
&.p-disabled {
|
||||
path {
|
||||
fill: ${(props) => props.theme.dropDownItem.icon.disableColor};
|
||||
}
|
||||
}
|
||||
|
||||
margin-right: 8px;
|
||||
}
|
||||
|
||||
.p-submenu-icon {
|
||||
margin-left: auto;
|
||||
}
|
||||
|
||||
.p-contextmenu-enter {
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
.p-contextmenu-enter-active {
|
||||
opacity: 1;
|
||||
transition: opacity 250ms;
|
||||
}
|
||||
`;
|
||||
|
||||
StyledContextMenu.defaultProps = {
|
||||
theme: Base,
|
||||
};
|
||||
|
||||
export default StyledContextMenu;
|
@ -0,0 +1,3 @@
|
||||
<svg width="5" height="9" viewBox="0 0 5 9" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M3.07786 4.50079L0.468338 1.45635C0.216742 1.16282 0.250735 0.72091 0.544263 0.469314C0.837792 0.217719 1.2797 0.251712 1.5313 0.54524L4.5313 4.04524C4.75599 4.30738 4.75599 4.69421 4.5313 4.95635L1.5313 8.45635C1.2797 8.74988 0.837792 8.78387 0.544263 8.53227C0.250735 8.28068 0.216742 7.83877 0.468338 7.54524L3.07786 4.50079Z" fill="#333333"/>
|
||||
</svg>
|
After Width: | Height: | Size: 455 B |
@ -60,3 +60,4 @@ export { Icons } from "./icons";
|
||||
export { default as SaveCancelButtons } from "./save-cancel-buttons";
|
||||
export { default as DragAndDrop } from "./drag-and-drop";
|
||||
export * as Themes from "./themes";
|
||||
export { default as Portal } from "./portal";
|
||||
|
@ -84,6 +84,7 @@
|
||||
"react-text-mask": "^5.4.3",
|
||||
"react-toastify": "^5.5.0",
|
||||
"react-tooltip": "^3.11.6",
|
||||
"react-transition-group": "^4.4.1",
|
||||
"react-virtualized-auto-sizer": "^1.0.3",
|
||||
"react-window": "^1.8.6",
|
||||
"react-window-infinite-loader": "^1.0.5",
|
||||
|
50
packages/asc-web-components/portal/index.js
Normal file
@ -0,0 +1,50 @@
|
||||
import { Component } from "react";
|
||||
import PropTypes from "prop-types";
|
||||
import ReactDOM from "react-dom";
|
||||
|
||||
class Portal extends Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
this.state = {
|
||||
mounted: props.visible,
|
||||
};
|
||||
}
|
||||
|
||||
domExist() {
|
||||
return !!(
|
||||
typeof window !== undefined &&
|
||||
window.document &&
|
||||
window.document.createElement
|
||||
);
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
if (this.domExist() && !this.state.mounted) {
|
||||
this.setState({ mounted: true });
|
||||
}
|
||||
}
|
||||
|
||||
render() {
|
||||
return this.props.element && this.state.mounted
|
||||
? ReactDOM.createPortal(
|
||||
this.props.element,
|
||||
this.props.appendTo || document.body
|
||||
)
|
||||
: null;
|
||||
}
|
||||
}
|
||||
|
||||
Portal.propTypes = {
|
||||
element: PropTypes.any,
|
||||
appendTo: PropTypes.any,
|
||||
visible: PropTypes.bool,
|
||||
};
|
||||
|
||||
Portal.defaultProps = {
|
||||
element: null,
|
||||
appendTo: null,
|
||||
visible: false,
|
||||
};
|
||||
|
||||
export default Portal;
|
@ -3,6 +3,7 @@ import React from "react";
|
||||
|
||||
import Checkbox from "../checkbox";
|
||||
import ContextMenuButton from "../context-menu-button";
|
||||
import ContextMenu from "../context-menu";
|
||||
import {
|
||||
StyledOptionButton,
|
||||
StyledContentElement,
|
||||
@ -16,58 +17,11 @@ class Row extends React.Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
this.state = {
|
||||
contextX: "0px",
|
||||
contextY: "100%",
|
||||
contextOpened: false,
|
||||
};
|
||||
|
||||
this.rowRef = React.createRef();
|
||||
this.cm = React.createRef();
|
||||
this.row = React.createRef();
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
this.container = this.rowRef.current;
|
||||
this.container.addEventListener("contextmenu", this.onContextMenu);
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
this.container &&
|
||||
this.container.removeEventListener("contextmenu", this.onContextMenu);
|
||||
}
|
||||
|
||||
onContextMenu = (e) => {
|
||||
e.preventDefault();
|
||||
|
||||
const menu = document.getElementById("contextMenu");
|
||||
|
||||
const containerBounds =
|
||||
this.container !== document && this.container.getBoundingClientRect();
|
||||
|
||||
const clickX = containerBounds.right - e.clientX;
|
||||
const clickY = e.clientY - containerBounds.top;
|
||||
const containerWidth = this.container.offsetWidth;
|
||||
const containerHeight = this.container.offsetHeight;
|
||||
const menuWidth = (menu && menu.offsetWidth) || 180;
|
||||
const menuHeight = menu && menu.offsetHeight;
|
||||
|
||||
const left = containerWidth - clickX > menuWidth && clickX < menuWidth;
|
||||
const bottom = containerHeight - clickY < menuHeight && clickY > menuHeight;
|
||||
|
||||
let newTop = `0px`;
|
||||
let newRight = `0px`;
|
||||
|
||||
newRight = !left ? `${clickX - menuWidth - 8}px` : `${clickX + 8}px`;
|
||||
newTop = bottom ? `${clickY - menuHeight}px` : `${clickY}px`;
|
||||
|
||||
this.setState({
|
||||
contextOpened: !this.state.contextOpened,
|
||||
contextX: newRight,
|
||||
contextY: newTop,
|
||||
});
|
||||
};
|
||||
|
||||
render() {
|
||||
//console.log("Row render");
|
||||
const {
|
||||
checked,
|
||||
children,
|
||||
@ -82,8 +36,6 @@ class Row extends React.Component {
|
||||
sectionWidth,
|
||||
} = this.props;
|
||||
|
||||
const { contextOpened, contextX, contextY } = this.state;
|
||||
|
||||
const renderCheckbox = Object.prototype.hasOwnProperty.call(
|
||||
this.props,
|
||||
"checked"
|
||||
@ -111,8 +63,16 @@ class Row extends React.Component {
|
||||
return contextOptions;
|
||||
};
|
||||
|
||||
const onContextMenu = (e) => {
|
||||
rowContextClick && rowContextClick();
|
||||
if (!this.cm.current.menuRef.current) {
|
||||
this.row.current.click(e); //TODO: need fix context menu to global
|
||||
}
|
||||
this.cm.current.show(e);
|
||||
};
|
||||
|
||||
return (
|
||||
<StyledRow ref={this.rowRef} {...this.props}>
|
||||
<StyledRow ref={this.row} {...this.props} onContextMenu={onContextMenu}>
|
||||
{renderCheckbox && (
|
||||
<StyledCheckbox>
|
||||
<Checkbox
|
||||
@ -135,9 +95,6 @@ class Row extends React.Component {
|
||||
)}
|
||||
{renderContext ? (
|
||||
<ContextMenuButton
|
||||
manualX={contextX}
|
||||
manualY={contextY}
|
||||
opened={contextOpened}
|
||||
color="#A3A9AE"
|
||||
hoverColor="#657077"
|
||||
className="expandButton"
|
||||
@ -147,6 +104,7 @@ class Row extends React.Component {
|
||||
) : (
|
||||
<div className="expandButton"> </div>
|
||||
)}
|
||||
<ContextMenu model={contextOptions} ref={this.cm}></ContextMenu>
|
||||
</StyledOptionButton>
|
||||
</StyledRow>
|
||||
);
|
||||
|
@ -87,13 +87,4 @@ describe("<Row />", () => {
|
||||
|
||||
expect(wrapper.getDOMNode().style).toHaveProperty("color", "red");
|
||||
});
|
||||
|
||||
it("componentWillUnmount() props lifecycle test", () => {
|
||||
const wrapper = shallow(<Row {...baseProps} />);
|
||||
const instance = wrapper.instance();
|
||||
|
||||
instance.componentWillUnmount();
|
||||
|
||||
expect(wrapper).toExist(false);
|
||||
});
|
||||
});
|
||||
|
31
packages/asc-web-components/utils/classNames.js
Normal file
@ -0,0 +1,31 @@
|
||||
export function classNames(...args) {
|
||||
if (args) {
|
||||
let classes = [];
|
||||
|
||||
for (let i = 0; i < args.length; i++) {
|
||||
let className = args[i];
|
||||
|
||||
if (!className) continue;
|
||||
|
||||
const type = typeof className;
|
||||
|
||||
if (type === "string" || type === "number") {
|
||||
classes.push(className);
|
||||
} else if (type === "object") {
|
||||
const _classes = Array.isArray(className)
|
||||
? className
|
||||
: Object.entries(className).map(([key, value]) =>
|
||||
!!value ? key : null
|
||||
);
|
||||
|
||||
classes = _classes.length
|
||||
? classes.concat(_classes.filter((c) => !!c))
|
||||
: classes;
|
||||
}
|
||||
}
|
||||
|
||||
return classes.join(" ");
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
117
packages/asc-web-components/utils/domHelpers.js
Normal file
@ -0,0 +1,117 @@
|
||||
export default class DomHelpers {
|
||||
static getViewport() {
|
||||
let win = window,
|
||||
d = document,
|
||||
e = d.documentElement,
|
||||
g = d.getElementsByTagName("body")[0],
|
||||
w = win.innerWidth || e.clientWidth || g.clientWidth,
|
||||
h = win.innerHeight || e.clientHeight || g.clientHeight;
|
||||
|
||||
return { width: w, height: h };
|
||||
}
|
||||
|
||||
static getOffset(el) {
|
||||
if (el) {
|
||||
let rect = el.getBoundingClientRect();
|
||||
|
||||
return {
|
||||
top:
|
||||
rect.top +
|
||||
(window.pageYOffset ||
|
||||
document.documentElement.scrollTop ||
|
||||
document.body.scrollTop ||
|
||||
0),
|
||||
left:
|
||||
rect.left +
|
||||
(window.pageXOffset ||
|
||||
document.documentElement.scrollLeft ||
|
||||
document.body.scrollLeft ||
|
||||
0),
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
top: "auto",
|
||||
left: "auto",
|
||||
};
|
||||
}
|
||||
|
||||
static getOuterWidth(el, margin) {
|
||||
if (el) {
|
||||
let width = el.offsetWidth;
|
||||
|
||||
if (margin) {
|
||||
let style = getComputedStyle(el);
|
||||
width += parseFloat(style.marginLeft) + parseFloat(style.marginRight);
|
||||
}
|
||||
|
||||
return width;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static getHiddenElementOuterWidth(element) {
|
||||
if (element) {
|
||||
element.style.visibility = "hidden";
|
||||
element.style.display = "block";
|
||||
let elementWidth = element.offsetWidth;
|
||||
element.style.display = "none";
|
||||
element.style.visibility = "visible";
|
||||
|
||||
return elementWidth;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static getHiddenElementOuterHeight(element) {
|
||||
if (element) {
|
||||
element.style.visibility = "hidden";
|
||||
element.style.display = "block";
|
||||
let elementHeight = element.offsetHeight;
|
||||
element.style.display = "none";
|
||||
element.style.visibility = "visible";
|
||||
|
||||
return elementHeight;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static calculateScrollbarWidth(el) {
|
||||
if (el) {
|
||||
let style = getComputedStyle(el);
|
||||
return (
|
||||
el.offsetWidth -
|
||||
el.clientWidth -
|
||||
parseFloat(style.borderLeftWidth) -
|
||||
parseFloat(style.borderRightWidth)
|
||||
);
|
||||
} else {
|
||||
if (this.calculatedScrollbarWidth != null)
|
||||
return this.calculatedScrollbarWidth;
|
||||
|
||||
let scrollDiv = document.createElement("div");
|
||||
scrollDiv.className = "p-scrollbar-measure";
|
||||
document.body.appendChild(scrollDiv);
|
||||
|
||||
let scrollbarWidth = scrollDiv.offsetWidth - scrollDiv.clientWidth;
|
||||
document.body.removeChild(scrollDiv);
|
||||
|
||||
this.calculatedScrollbarWidth = scrollbarWidth;
|
||||
|
||||
return scrollbarWidth;
|
||||
}
|
||||
}
|
||||
|
||||
static generateZIndex() {
|
||||
this.zIndex = this.zIndex || 1000;
|
||||
return ++this.zIndex;
|
||||
}
|
||||
|
||||
static revertZIndex() {
|
||||
this.zIndex = 1000 < this.zIndex ? --this.zIndex : 1000;
|
||||
}
|
||||
|
||||
static getCurrentZIndex() {
|
||||
return this.zIndex;
|
||||
}
|
||||
}
|
5
packages/asc-web-components/utils/objectUtils.js
Normal file
@ -0,0 +1,5 @@
|
||||
export default class ObjectUtils {
|
||||
static getJSXElement(obj, ...params) {
|
||||
return this.isFunction(obj) ? obj(...params) : obj;
|
||||
}
|
||||
}
|
@ -1,3 +0,0 @@
|
||||
<svg width="17" height="17" viewBox="0 0 17 17" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M8.5 0C7.67157 0 7 0.671573 7 1.5V7H1.5C0.671573 7 0 7.67157 0 8.5C0 9.32843 0.671573 10 1.5 10H7V15.5C7 16.3284 7.67157 17 8.5 17C9.32843 17 10 16.3284 10 15.5V10H15.5C16.3284 10 17 9.32843 17 8.5C17 7.67157 16.3284 7 15.5 7H10V1.5C10 0.671573 9.32843 0 8.5 0Z" fill="#A3A9AE"/>
|
||||
</svg>
|
Before Width: | Height: | Size: 432 B |
@ -29,5 +29,7 @@
|
||||
|
||||
"ShareEveryone": "Everyone",
|
||||
"ShareEmailSubject": "You have been granted access to the {{itemName}} document",
|
||||
"ShareEmailBody": "You have been granted access to the {{itemName}} document. Click the link below to open the document right now: {{shareLink}}"
|
||||
"ShareEmailBody": "You have been granted access to the {{itemName}} document. Click the link below to open the document right now: {{shareLink}}",
|
||||
|
||||
"LoadingLabel": "Loading... Please wait..."
|
||||
}
|
||||
|
@ -29,5 +29,7 @@
|
||||
|
||||
"ShareEveryone": "Все",
|
||||
"ShareEmailSubject": "Вам предоставлен доступ к документу {{itemName}}",
|
||||
"ShareEmailBody": "Вам предоставлен доступ к документу {{itemName}}. Нажмите на ссылку ниже, чтобы открыть документ прямо сейчас: {{shareLink}}"
|
||||
"ShareEmailBody": "Вам предоставлен доступ к документу {{itemName}}. Нажмите на ссылку ниже, чтобы открыть документ прямо сейчас: {{shareLink}}",
|
||||
|
||||
"LoadingLabel": "Загрузка... Пожалуйста подождите..."
|
||||
}
|
||||
|
@ -7,17 +7,7 @@ import PrivateRoute from "@appserver/common/components/PrivateRoute";
|
||||
import AppLoader from "@appserver/common/components/AppLoader";
|
||||
import toastr from "studio/toastr";
|
||||
import { combineUrl, updateTempContent } from "@appserver/common/utils";
|
||||
import initFilesStore from "./store/InitFilesStore";
|
||||
import filesStore from "./store/FilesStore";
|
||||
import settingsStore from "./store/SettingsStore";
|
||||
import mediaViewerDataStore from "./store/MediaViewerDataStore";
|
||||
import formatsStore from "./store/FormatsStore";
|
||||
import versionHistoryStore from "./store/VersionHistoryStore";
|
||||
import uploadDataStore from "./store/UploadDataStore";
|
||||
import dialogsStore from "./store/DialogsStore";
|
||||
import treeFoldersStore from "./store/TreeFoldersStore";
|
||||
import selectedFolderStore from "./store/SelectedFolderStore";
|
||||
import filesActionsStore from "./store/FilesActionsStore";
|
||||
import stores from "./store/index";
|
||||
import contextOptionsStore from "./store/ContextOptionsStore";
|
||||
import "./custom.scss";
|
||||
import i18n from "./i18n";
|
||||
@ -126,39 +116,26 @@ class FilesContent extends React.Component {
|
||||
}
|
||||
}
|
||||
|
||||
const Files = inject(({ auth, initFilesStore }) => {
|
||||
const Files = inject(({ auth, filesStore }) => {
|
||||
return {
|
||||
isDesktop: auth.settingsStore.isDesktopClient,
|
||||
user: auth.userStore.user,
|
||||
isAuthenticated: auth.isAuthenticated,
|
||||
encryptionKeys: auth.settingsStore.encryptionKeys,
|
||||
isEncryption: auth.settingsStore.isEncryptionSupport,
|
||||
isLoaded: auth.isLoaded && initFilesStore.isLoaded,
|
||||
setIsLoaded: initFilesStore.setIsLoaded,
|
||||
isLoaded: auth.isLoaded && filesStore.isLoaded,
|
||||
setIsLoaded: filesStore.setIsLoaded,
|
||||
setEncryptionKeys: auth.settingsStore.setEncryptionKeys,
|
||||
loadFilesInfo: async () => {
|
||||
//await auth.init();
|
||||
await initFilesStore.initFiles();
|
||||
await filesStore.initFiles();
|
||||
auth.setProductVersion(config.version);
|
||||
},
|
||||
};
|
||||
})(observer(FilesContent));
|
||||
|
||||
export default () => (
|
||||
<FilesProvider
|
||||
initFilesStore={initFilesStore}
|
||||
filesStore={filesStore}
|
||||
settingsStore={settingsStore}
|
||||
mediaViewerDataStore={mediaViewerDataStore}
|
||||
formatsStore={formatsStore}
|
||||
versionHistoryStore={versionHistoryStore}
|
||||
uploadDataStore={uploadDataStore}
|
||||
dialogsStore={dialogsStore}
|
||||
treeFoldersStore={treeFoldersStore}
|
||||
selectedFolderStore={selectedFolderStore}
|
||||
filesActionsStore={filesActionsStore}
|
||||
contextOptionsStore={contextOptionsStore}
|
||||
>
|
||||
<FilesProvider {...stores}>
|
||||
<I18nextProvider i18n={i18n}>
|
||||
<Files />
|
||||
</I18nextProvider>
|
||||
|
@ -213,13 +213,13 @@ const ThirdPartyList = withTranslation("Article")(
|
||||
|
||||
export default inject(
|
||||
({
|
||||
initFilesStore,
|
||||
filesStore,
|
||||
settingsStore,
|
||||
treeFoldersStore,
|
||||
selectedFolderStore,
|
||||
dialogsStore,
|
||||
}) => {
|
||||
const { setIsLoading } = initFilesStore;
|
||||
const { setIsLoading } = filesStore;
|
||||
const { setSelectedFolder } = selectedFolderStore;
|
||||
const { setSelectedNode } = treeFoldersStore;
|
||||
const {
|
||||
|
@ -470,15 +470,15 @@ TreeFolders.defaultProps = {
|
||||
};
|
||||
|
||||
export default inject(
|
||||
({
|
||||
auth,
|
||||
initFilesStore,
|
||||
filesStore,
|
||||
treeFoldersStore,
|
||||
selectedFolderStore,
|
||||
}) => {
|
||||
const { setIsLoading, dragging, setDragging } = initFilesStore;
|
||||
const { filter, setFilter, selection } = filesStore;
|
||||
({ auth, filesStore, treeFoldersStore, selectedFolderStore }) => {
|
||||
const {
|
||||
filter,
|
||||
setFilter,
|
||||
selection,
|
||||
setIsLoading,
|
||||
dragging,
|
||||
setDragging,
|
||||
} = filesStore;
|
||||
|
||||
const {
|
||||
treeFolders,
|
||||
|
@ -209,12 +209,12 @@ const TreeSettings = withTranslation("Settings")(withRouter(PureTreeSettings));
|
||||
export default inject(
|
||||
({
|
||||
auth,
|
||||
initFilesStore,
|
||||
filesStore,
|
||||
settingsStore,
|
||||
treeFoldersStore,
|
||||
selectedFolderStore,
|
||||
}) => {
|
||||
const { setIsLoading, isLoading } = initFilesStore;
|
||||
const { setIsLoading, isLoading } = filesStore;
|
||||
const { setSelectedFolder } = selectedFolderStore;
|
||||
const { selectedTreeNode, setSelectedNode } = treeFoldersStore;
|
||||
const {
|
||||
|
@ -128,9 +128,8 @@ class ArticleBodyContent extends React.Component {
|
||||
}
|
||||
|
||||
export default inject(
|
||||
({ initFilesStore, filesStore, treeFoldersStore, selectedFolderStore }) => {
|
||||
const { setIsLoading } = initFilesStore;
|
||||
const { fetchFiles, filter } = filesStore;
|
||||
({ filesStore, treeFoldersStore, selectedFolderStore }) => {
|
||||
const { fetchFiles, filter, setIsLoading } = filesStore;
|
||||
const { treeFolders, setSelectedNode, setTreeFolders } = treeFoldersStore;
|
||||
const selectedTreeNode =
|
||||
treeFoldersStore.selectedTreeNode.length > 0
|
||||
|
@ -94,9 +94,14 @@ const DragTooltip = (props) => {
|
||||
return <StyledTooltip ref={tooltipRef}>{tooltipLabel}</StyledTooltip>;
|
||||
};
|
||||
|
||||
export default inject(({ initFilesStore, filesStore }) => {
|
||||
const { tooltipValue, tooltipPageX, tooltipPageY } = initFilesStore;
|
||||
const { selection, iconOfDraggedFile } = filesStore;
|
||||
export default inject(({ filesStore }) => {
|
||||
const {
|
||||
selection,
|
||||
iconOfDraggedFile,
|
||||
tooltipValue,
|
||||
tooltipPageX,
|
||||
tooltipPageY,
|
||||
} = filesStore;
|
||||
|
||||
const isSingleItem = selection.length === 1;
|
||||
|
||||
|
@ -4,6 +4,6 @@ import DragTooltip from "./DragTooltip";
|
||||
|
||||
const Tooltip = ({ dragging }) => (dragging ? <DragTooltip /> : <></>);
|
||||
|
||||
export default inject(({ initFilesStore, filesStore }) => ({
|
||||
dragging: initFilesStore.dragging && filesStore.selection[0],
|
||||
export default inject(({ filesStore }) => ({
|
||||
dragging: filesStore.dragging && filesStore.selection[0],
|
||||
}))(observer(Tooltip));
|
||||
|
@ -52,8 +52,7 @@ class DeleteDialogComponent extends React.Component {
|
||||
deleteSelectedElem: t("DeleteSelectedElem"),
|
||||
};
|
||||
|
||||
deleteAction(translations)
|
||||
.catch((err) => toastr.error(err));
|
||||
deleteAction(translations).catch((err) => toastr.error(err));
|
||||
};
|
||||
|
||||
onChange = (event) => {
|
||||
@ -174,7 +173,6 @@ const DeleteDialog = withTranslation("DeleteDialog")(DeleteDialogComponent);
|
||||
|
||||
export default inject(
|
||||
({
|
||||
initFilesStore,
|
||||
filesStore,
|
||||
uploadDataStore,
|
||||
treeFoldersStore,
|
||||
@ -182,9 +180,8 @@ export default inject(
|
||||
dialogsStore,
|
||||
filesActionsStore,
|
||||
}) => {
|
||||
const { isLoading } = initFilesStore;
|
||||
const { secondaryProgressDataStore } = uploadDataStore;
|
||||
const { fetchFiles, selection, filter } = filesStore;
|
||||
const { fetchFiles, selection, filter, isLoading } = filesStore;
|
||||
const { deleteAction } = filesActionsStore;
|
||||
|
||||
const {
|
||||
|
@ -150,16 +150,9 @@ const EmptyTrashDialog = withTranslation("EmptyTrashDialog")(
|
||||
);
|
||||
|
||||
export default inject(
|
||||
({
|
||||
initFilesStore,
|
||||
filesStore,
|
||||
uploadDataStore,
|
||||
selectedFolderStore,
|
||||
dialogsStore,
|
||||
}) => {
|
||||
const { isLoading } = initFilesStore;
|
||||
({ filesStore, uploadDataStore, selectedFolderStore, dialogsStore }) => {
|
||||
const { secondaryProgressDataStore } = uploadDataStore;
|
||||
const { fetchFiles, filter } = filesStore;
|
||||
const { fetchFiles, filter, isLoading } = filesStore;
|
||||
const {
|
||||
setSecondaryProgressBarData,
|
||||
clearSecondaryProgressData,
|
||||
|
@ -52,10 +52,8 @@ const EmptyFilterContainer = ({
|
||||
);
|
||||
};
|
||||
|
||||
export default inject(
|
||||
({ initFilesStore, filesStore, selectedFolderStore }) => ({
|
||||
fetchFiles: filesStore.fetchFiles,
|
||||
selectedFolderId: selectedFolderStore.id,
|
||||
setIsLoading: initFilesStore.setIsLoading,
|
||||
})
|
||||
)(withTranslation("Home")(observer(EmptyFilterContainer)));
|
||||
export default inject(({ filesStore, selectedFolderStore }) => ({
|
||||
fetchFiles: filesStore.fetchFiles,
|
||||
selectedFolderId: selectedFolderStore.id,
|
||||
setIsLoading: filesStore.setIsLoading,
|
||||
}))(withTranslation("Home")(observer(EmptyFilterContainer)));
|
||||
|
@ -79,13 +79,13 @@ const EmptyFolderContainer = ({
|
||||
);
|
||||
};
|
||||
|
||||
export default inject(({ initFilesStore, filesStore, selectedFolderStore }) => {
|
||||
export default inject(({ filesStore, selectedFolderStore }) => {
|
||||
const { filter, fetchFiles } = filesStore;
|
||||
|
||||
return {
|
||||
filter,
|
||||
fetchFiles,
|
||||
setIsLoading: initFilesStore.setIsLoading,
|
||||
setIsLoading: filesStore.setIsLoading,
|
||||
parentId: selectedFolderStore.parentId,
|
||||
};
|
||||
})(withTranslation("Home")(observer(EmptyFolderContainer)));
|
||||
|
@ -188,21 +188,19 @@ const RootFolderContainer = (props) => {
|
||||
};
|
||||
|
||||
export default inject(
|
||||
({
|
||||
auth,
|
||||
initFilesStore,
|
||||
filesStore,
|
||||
treeFoldersStore,
|
||||
selectedFolderStore,
|
||||
}) => {
|
||||
({ auth, filesStore, treeFoldersStore, selectedFolderStore }) => {
|
||||
const {
|
||||
isDesktopClient,
|
||||
isEncryptionSupport,
|
||||
organizationName,
|
||||
} = auth.settingsStore;
|
||||
|
||||
const { privacyInstructions, setIsLoading } = initFilesStore;
|
||||
const { filter, fetchFiles } = filesStore;
|
||||
const {
|
||||
filter,
|
||||
fetchFiles,
|
||||
privacyInstructions,
|
||||
setIsLoading,
|
||||
} = filesStore;
|
||||
const { title, rootFolderType } = selectedFolderStore;
|
||||
const { isPrivacyFolder, myFolderId } = treeFoldersStore;
|
||||
|
||||
|
@ -593,7 +593,7 @@ class FilesContent extends React.Component {
|
||||
{canWebEdit && !isTrashFolder && accessToEdit && (
|
||||
<IconButton
|
||||
onClick={this.onFilesClick}
|
||||
iconName="images/access.edit.react.svg"
|
||||
iconName="/static/images/access.edit.react.svg"
|
||||
className="badge"
|
||||
size="small"
|
||||
isfill={true}
|
||||
@ -732,7 +732,6 @@ export default inject(
|
||||
(
|
||||
{
|
||||
auth,
|
||||
initFilesStore,
|
||||
filesStore,
|
||||
formatsStore,
|
||||
uploadDataStore,
|
||||
@ -750,7 +749,6 @@ export default inject(
|
||||
isDesktopClient: isDesktop,
|
||||
isTabletView,
|
||||
} = auth.settingsStore;
|
||||
const { setIsLoading, isLoading } = initFilesStore;
|
||||
const { secondaryProgressDataStore } = uploadDataStore;
|
||||
const { setIsVerHistoryPanel, fetchFileVersions } = versionHistoryStore;
|
||||
|
||||
@ -784,6 +782,8 @@ export default inject(
|
||||
renameFolder,
|
||||
createFolder,
|
||||
openDocEditor,
|
||||
setIsLoading,
|
||||
isLoading,
|
||||
} = filesStore;
|
||||
|
||||
const {
|
||||
|
@ -0,0 +1,44 @@
|
||||
import React from "react";
|
||||
import { inject, observer } from "mobx-react";
|
||||
import RowContainer from "@appserver/components/row-container";
|
||||
import { Consumer } from "@appserver/components/utils/context";
|
||||
import SimpleFilesRow from "./SimpleFilesRow";
|
||||
import Loaders from "@appserver/common/components/Loaders";
|
||||
import { isMobile } from "react-device-detect";
|
||||
|
||||
const FilesRowContainer = (props) => {
|
||||
const { isLoaded, isLoading } = props;
|
||||
return !isLoaded || (isMobile && isLoading) ? (
|
||||
<Loaders.Rows />
|
||||
) : (
|
||||
<Consumer>
|
||||
{(context) => (
|
||||
<RowContainer
|
||||
className="files-row-container"
|
||||
draggable
|
||||
useReactWindow={false}
|
||||
>
|
||||
{props.filesList.map((item) => {
|
||||
return (
|
||||
<SimpleFilesRow
|
||||
key={item.id}
|
||||
item={item}
|
||||
sectionWidth={context.sectionWidth}
|
||||
/>
|
||||
);
|
||||
})}
|
||||
</RowContainer>
|
||||
)}
|
||||
</Consumer>
|
||||
);
|
||||
};
|
||||
|
||||
export default inject(({ auth, filesStore }) => {
|
||||
const { filesList, isLoading } = filesStore;
|
||||
|
||||
return {
|
||||
filesList,
|
||||
isLoading,
|
||||
isLoaded: auth.isLoaded,
|
||||
};
|
||||
})(observer(FilesRowContainer));
|
@ -0,0 +1,500 @@
|
||||
import React from "react";
|
||||
import { withRouter } from "react-router";
|
||||
import { Trans, withTranslation } from "react-i18next";
|
||||
import styled from "styled-components";
|
||||
import Badge from "@appserver/components/badge";
|
||||
import Link from "@appserver/components/link";
|
||||
import Text from "@appserver/components/text";
|
||||
import { markAsRead } from "@appserver/common/api/files";
|
||||
import { FileAction, AppServerConfig } from "@appserver/common/constants";
|
||||
import toastr from "studio/toastr";
|
||||
import { getTitleWithoutExst } from "../../../../../helpers/files-helpers";
|
||||
import { NewFilesPanel } from "../../../../panels";
|
||||
import EditingWrapperComponent from "./EditingWrapperComponent";
|
||||
import TileContent from "./TileContent";
|
||||
import { isMobile } from "react-device-detect";
|
||||
import { inject, observer } from "mobx-react";
|
||||
import CheckIcon from "../../../../../../public/images/check.react.svg";
|
||||
import CrossIcon from "../../../../../../../../../public/images/cross.react.svg";
|
||||
import config from "../../../../../../package.json";
|
||||
import { combineUrl } from "@appserver/common/utils";
|
||||
|
||||
const SimpleFilesTileContent = styled(TileContent)`
|
||||
.rowMainContainer {
|
||||
height: auto;
|
||||
max-width: 100%;
|
||||
align-self: flex-end;
|
||||
|
||||
a {
|
||||
word-break: break-word;
|
||||
}
|
||||
}
|
||||
|
||||
.mainIcons {
|
||||
align-self: flex-end;
|
||||
}
|
||||
|
||||
.badge-ext {
|
||||
margin-left: -8px;
|
||||
margin-right: 8px;
|
||||
}
|
||||
|
||||
.badge {
|
||||
margin-right: 8px;
|
||||
}
|
||||
|
||||
.badges {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.share-icon {
|
||||
margin-top: -4px;
|
||||
padding-right: 8px;
|
||||
}
|
||||
|
||||
@media (max-width: 1024px) {
|
||||
display: inline-flex;
|
||||
height: auto;
|
||||
|
||||
& > div {
|
||||
margin-top: 0;
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
const okIcon = (
|
||||
<CheckIcon
|
||||
className="edit-ok-icon"
|
||||
size="scale"
|
||||
isfill={true}
|
||||
color="#A3A9AE"
|
||||
/>
|
||||
);
|
||||
|
||||
const cancelIcon = (
|
||||
<CrossIcon
|
||||
className="edit-cancel-icon"
|
||||
size="scale"
|
||||
isfill={true}
|
||||
color="#A3A9AE"
|
||||
/>
|
||||
);
|
||||
|
||||
class FilesTileContent extends React.PureComponent {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
let titleWithoutExt = getTitleWithoutExst(props.item);
|
||||
|
||||
if (props.fileAction.id === -1) {
|
||||
titleWithoutExt = this.getDefaultName(props.fileAction.extension);
|
||||
}
|
||||
|
||||
this.state = {
|
||||
itemTitle: titleWithoutExt,
|
||||
editingId: props.fileAction.id,
|
||||
showNewFilesPanel: false,
|
||||
newFolderId: [],
|
||||
newItems: props.item.new,
|
||||
//loading: false
|
||||
};
|
||||
}
|
||||
|
||||
completeAction = (e) => {
|
||||
//this.setState({ loading: false }, () =>)
|
||||
this.props.onEditComplete(e);
|
||||
};
|
||||
|
||||
updateItem = (e) => {
|
||||
const {
|
||||
fileAction,
|
||||
updateFile,
|
||||
renameFolder,
|
||||
item,
|
||||
setIsLoading,
|
||||
} = this.props;
|
||||
|
||||
const { itemTitle } = this.state;
|
||||
const originalTitle = getTitleWithoutExst(item);
|
||||
|
||||
setIsLoading(true);
|
||||
if (originalTitle === itemTitle) return this.completeAction(e);
|
||||
|
||||
item.fileExst
|
||||
? updateFile(fileAction.id, itemTitle)
|
||||
.then(() => this.completeAction(e))
|
||||
.finally(() => setIsLoading(false))
|
||||
: renameFolder(fileAction.id, itemTitle)
|
||||
.then(() => this.completeAction(e))
|
||||
.finally(() => setIsLoading(false));
|
||||
};
|
||||
|
||||
createItem = (e) => {
|
||||
const { createFile, item, setIsLoading, createFolder } = this.props;
|
||||
const { itemTitle } = this.state;
|
||||
|
||||
setIsLoading(true);
|
||||
|
||||
if (itemTitle.trim() === "") return this.completeAction();
|
||||
|
||||
!item.fileExst
|
||||
? createFolder(item.parentId, itemTitle)
|
||||
.then(() => this.completeAction(e))
|
||||
.finally(() => {
|
||||
toastr.success(
|
||||
<Trans i18nKey="FolderCreated" ns="Home">
|
||||
New folder {{ itemTitle }} is created
|
||||
</Trans>
|
||||
);
|
||||
return setIsLoading(false);
|
||||
})
|
||||
: createFile(item.parentId, `${itemTitle}.${item.fileExst}`)
|
||||
.then(() => this.completeAction(e))
|
||||
.finally(() => {
|
||||
const exst = item.fileExst;
|
||||
toastr.success(
|
||||
<Trans i18nKey="FileCreated" ns="Home">
|
||||
New file {{ itemTitle }}.{{ exst }} is created
|
||||
</Trans>
|
||||
);
|
||||
return setIsLoading(false);
|
||||
});
|
||||
};
|
||||
|
||||
componentDidUpdate(prevProps) {
|
||||
const { fileAction } = this.props;
|
||||
if (fileAction) {
|
||||
if (fileAction.id !== prevProps.fileAction.id) {
|
||||
this.setState({ editingId: fileAction.id });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
renameTitle = (e) => {
|
||||
this.setState({ itemTitle: e.target.value });
|
||||
};
|
||||
|
||||
cancelUpdateItem = (e) => {
|
||||
//this.setState({ loading: false });
|
||||
this.completeAction(e);
|
||||
};
|
||||
|
||||
onClickUpdateItem = () => {
|
||||
this.props.fileAction.type === FileAction.Create
|
||||
? this.createItem()
|
||||
: this.updateItem();
|
||||
};
|
||||
|
||||
onKeyUpUpdateItem = (e) => {
|
||||
if (e.keyCode === 13) {
|
||||
this.props.fileAction.type === FileAction.Create
|
||||
? this.createItem()
|
||||
: this.updateItem();
|
||||
}
|
||||
|
||||
if (e.keyCode === 27) return this.cancelUpdateItem();
|
||||
};
|
||||
|
||||
onFilesClick = () => {
|
||||
const { id, fileExst, viewUrl, providerKey } = this.props.item;
|
||||
const {
|
||||
filter,
|
||||
parentFolder,
|
||||
setIsLoading,
|
||||
onMediaFileClick,
|
||||
fetchFiles,
|
||||
canWebEdit,
|
||||
openDocEditor,
|
||||
isVideo,
|
||||
isImage,
|
||||
isSound,
|
||||
expandedKeys,
|
||||
addExpandedKeys,
|
||||
} = this.props;
|
||||
if (!fileExst) {
|
||||
setIsLoading(true);
|
||||
|
||||
if (!expandedKeys.includes(parentFolder + "")) {
|
||||
addExpandedKeys(parentFolder + "");
|
||||
}
|
||||
|
||||
fetchFiles(id, filter)
|
||||
.catch((err) => {
|
||||
toastr.error(err);
|
||||
setIsLoading(false);
|
||||
})
|
||||
.finally(() => setIsLoading(false));
|
||||
} else {
|
||||
if (canWebEdit) {
|
||||
return openDocEditor(id, providerKey);
|
||||
}
|
||||
|
||||
const isOpenMedia = isImage || isSound || isVideo;
|
||||
|
||||
if (isOpenMedia) {
|
||||
onMediaFileClick(id);
|
||||
return;
|
||||
}
|
||||
|
||||
return window.open(viewUrl, "_blank");
|
||||
}
|
||||
};
|
||||
|
||||
onMobileRowClick = (e) => {
|
||||
if (!isMobile) return;
|
||||
|
||||
this.onFilesClick();
|
||||
};
|
||||
|
||||
getStatusByDate = () => {
|
||||
const { culture, t, item, sectionWidth } = this.props;
|
||||
const { created, updated, version, fileExst } = item;
|
||||
|
||||
const title =
|
||||
version > 1
|
||||
? t("TitleModified")
|
||||
: fileExst
|
||||
? t("TitleUploaded")
|
||||
: t("TitleCreated");
|
||||
|
||||
const date = fileExst ? updated : created;
|
||||
const dateLabel = new Date(date).toLocaleString(culture);
|
||||
const mobile = (sectionWidth && sectionWidth <= 375) || isMobile;
|
||||
|
||||
return mobile ? dateLabel : `${title}: ${dateLabel}`;
|
||||
};
|
||||
|
||||
getDefaultName = (format) => {
|
||||
const { t } = this.props;
|
||||
|
||||
switch (format) {
|
||||
case "docx":
|
||||
return t("NewDocument");
|
||||
case "xlsx":
|
||||
return t("NewSpreadsheet");
|
||||
case "pptx":
|
||||
return t("NewPresentation");
|
||||
default:
|
||||
return t("NewFolder");
|
||||
}
|
||||
};
|
||||
|
||||
onShowVersionHistory = (e) => {
|
||||
const { homepage, history } = this.props;
|
||||
const fileId = e.currentTarget.dataset.id;
|
||||
|
||||
history.push(
|
||||
combineUrl(AppServerConfig.proxyURL, homepage, `/${fileId}/history`)
|
||||
);
|
||||
};
|
||||
|
||||
onBadgeClick = () => {
|
||||
const { showNewFilesPanel } = this.state;
|
||||
const {
|
||||
item,
|
||||
treeFolders,
|
||||
setTreeFolders,
|
||||
rootFolderId,
|
||||
newItems,
|
||||
filter,
|
||||
fetchFiles,
|
||||
} = this.props;
|
||||
if (item.fileExst) {
|
||||
markAsRead([], [item.id])
|
||||
.then(() => {
|
||||
const data = treeFolders;
|
||||
const dataItem = data.find((x) => x.id === rootFolderId);
|
||||
dataItem.newItems = newItems ? dataItem.newItems - 1 : 0; //////newItems
|
||||
setTreeFolders(data);
|
||||
fetchFiles(this.props.selectedFolderId, filter.clone());
|
||||
})
|
||||
.catch((err) => toastr.error(err));
|
||||
} else {
|
||||
const newFolderId = this.props.selectedFolderPathParts;
|
||||
newFolderId.push(item.id);
|
||||
this.setState({
|
||||
showNewFilesPanel: !showNewFilesPanel,
|
||||
newFolderId,
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
onShowNewFilesPanel = () => {
|
||||
const { showNewFilesPanel } = this.state;
|
||||
this.setState({ showNewFilesPanel: !showNewFilesPanel });
|
||||
};
|
||||
|
||||
render() {
|
||||
const { item, fileAction, isTrashFolder, folders } = this.props;
|
||||
const {
|
||||
itemTitle,
|
||||
editingId,
|
||||
showNewFilesPanel,
|
||||
newItems,
|
||||
newFolderId,
|
||||
} = this.state;
|
||||
const { fileExst, id } = item;
|
||||
|
||||
const titleWithoutExt = getTitleWithoutExst(item);
|
||||
|
||||
const isEdit = id === editingId && fileExst === fileAction.extension;
|
||||
const linkStyles = isTrashFolder
|
||||
? { noHover: true }
|
||||
: { onClick: this.onFilesClick };
|
||||
const showNew = item.new && item.new > 0;
|
||||
|
||||
return isEdit ? (
|
||||
<EditingWrapperComponent
|
||||
itemTitle={itemTitle}
|
||||
okIcon={okIcon}
|
||||
cancelIcon={cancelIcon}
|
||||
renameTitle={this.renameTitle}
|
||||
onKeyUpUpdateItem={this.onKeyUpUpdateItem}
|
||||
onClickUpdateItem={this.onClickUpdateItem}
|
||||
cancelUpdateItem={this.cancelUpdateItem}
|
||||
itemId={id}
|
||||
/>
|
||||
) : (
|
||||
<>
|
||||
{showNewFilesPanel && (
|
||||
<NewFilesPanel
|
||||
visible={showNewFilesPanel}
|
||||
onClose={this.onShowNewFilesPanel}
|
||||
folderId={newFolderId}
|
||||
folders={folders}
|
||||
/>
|
||||
)}
|
||||
<SimpleFilesTileContent
|
||||
sideColor="#333"
|
||||
isFile={fileExst}
|
||||
onClick={this.onMobileRowClick}
|
||||
disableSideInfo
|
||||
>
|
||||
<Link
|
||||
containerWidth="100%"
|
||||
type="page"
|
||||
title={titleWithoutExt}
|
||||
fontWeight="bold"
|
||||
fontSize="15px"
|
||||
{...linkStyles}
|
||||
color="#333"
|
||||
isTextOverflow
|
||||
>
|
||||
{titleWithoutExt}
|
||||
</Link>
|
||||
<>
|
||||
{fileExst ? (
|
||||
<div className="badges">
|
||||
<Text
|
||||
className="badge-ext"
|
||||
as="span"
|
||||
color="#A3A9AE"
|
||||
fontSize="15px"
|
||||
fontWeight={600}
|
||||
title={fileExst}
|
||||
truncate={true}
|
||||
>
|
||||
{fileExst}
|
||||
</Text>
|
||||
</div>
|
||||
) : (
|
||||
<div className="badges">
|
||||
{!!showNew && (
|
||||
<Badge
|
||||
className="badge-version"
|
||||
backgroundColor="#ED7309"
|
||||
borderRadius="11px"
|
||||
color="#FFFFFF"
|
||||
fontSize="10px"
|
||||
fontWeight={800}
|
||||
label={newItems}
|
||||
maxWidth="50px"
|
||||
onClick={this.onBadgeClick}
|
||||
padding="0 5px"
|
||||
data-id={id}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
</>
|
||||
</SimpleFilesTileContent>
|
||||
</>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default inject(
|
||||
(
|
||||
{ auth, filesStore, formatsStore, treeFoldersStore, selectedFolderStore },
|
||||
{ item }
|
||||
) => {
|
||||
const { culture } = auth.settingsStore;
|
||||
const {
|
||||
iconFormatsStore,
|
||||
mediaViewersFormatsStore,
|
||||
docserviceStore,
|
||||
} = formatsStore;
|
||||
const {
|
||||
folders,
|
||||
fetchFiles,
|
||||
filter,
|
||||
newRowItems,
|
||||
createFile,
|
||||
updateFile,
|
||||
renameFolder,
|
||||
createFolder,
|
||||
setIsLoading,
|
||||
isLoading,
|
||||
dragging,
|
||||
} = filesStore;
|
||||
|
||||
const {
|
||||
treeFolders,
|
||||
setTreeFolders,
|
||||
isRecycleBinFolder,
|
||||
expandedKeys,
|
||||
addExpandedKeys,
|
||||
} = treeFoldersStore;
|
||||
|
||||
const { type, extension, id } = filesStore.fileActionStore;
|
||||
|
||||
const fileAction = { type, extension, id };
|
||||
|
||||
const canWebEdit = docserviceStore.canWebEdit(item.fileExst);
|
||||
const isVideo = mediaViewersFormatsStore.isVideo(item.fileExst);
|
||||
const isImage = iconFormatsStore.isImage(item.fileExst);
|
||||
const isSound = iconFormatsStore.isSound(item.fileExst);
|
||||
|
||||
return {
|
||||
culture,
|
||||
homepage: config.homepage,
|
||||
fileAction,
|
||||
folders,
|
||||
rootFolderId: selectedFolderStore.pathParts,
|
||||
selectedFolderId: selectedFolderStore.id,
|
||||
selectedFolderPathParts: selectedFolderStore.pathParts,
|
||||
newItems: selectedFolderStore.new,
|
||||
parentFolder: selectedFolderStore.parentId,
|
||||
isLoading,
|
||||
treeFolders,
|
||||
isTrashFolder: isRecycleBinFolder,
|
||||
filter,
|
||||
dragging,
|
||||
canWebEdit,
|
||||
isVideo,
|
||||
isImage,
|
||||
isSound,
|
||||
newRowItems,
|
||||
expandedKeys,
|
||||
|
||||
setIsLoading,
|
||||
fetchFiles,
|
||||
setTreeFolders,
|
||||
createFile,
|
||||
createFolder,
|
||||
updateFile,
|
||||
renameFolder,
|
||||
addExpandedKeys,
|
||||
};
|
||||
}
|
||||
)(withRouter(withTranslation("Home")(observer(FilesTileContent))));
|
@ -22,6 +22,8 @@ const SectionBodyContent = (props) => {
|
||||
startDrag,
|
||||
setStartDrag,
|
||||
setDragging,
|
||||
startDrag,
|
||||
setStartDrag,
|
||||
setTooltipPosition,
|
||||
isRecycleBinFolder,
|
||||
moveDragItems,
|
||||
@ -54,8 +56,8 @@ const SectionBodyContent = (props) => {
|
||||
|
||||
const onMouseMove = (e) => {
|
||||
if (!dragging) {
|
||||
setDragging(true);
|
||||
document.body.classList.add("drag-cursor");
|
||||
setDragging(true);
|
||||
}
|
||||
|
||||
setTooltipPosition(e.pageX, e.pageY);
|
||||
@ -106,6 +108,7 @@ const SectionBodyContent = (props) => {
|
||||
|
||||
const folderId = value ? value.split("_")[1] : treeValue;
|
||||
|
||||
setStartDrag(false);
|
||||
setDragging(false);
|
||||
setStartDrag(false);
|
||||
onMoveTo(folderId);
|
||||
@ -150,15 +153,19 @@ const SectionBodyContent = (props) => {
|
||||
|
||||
export default inject(
|
||||
({
|
||||
initFilesStore,
|
||||
filesStore,
|
||||
selectedFolderStore,
|
||||
treeFoldersStore,
|
||||
filesActionsStore,
|
||||
}) => {
|
||||
const {
|
||||
firstLoad,
|
||||
fileActionStore,
|
||||
filesList,
|
||||
dragging,
|
||||
setDragging,
|
||||
startDrag,
|
||||
setStartDrag,
|
||||
isLoading,
|
||||
viewAs,
|
||||
setTooltipPosition,
|
||||
@ -177,6 +184,8 @@ export default inject(
|
||||
isLoading,
|
||||
isEmptyFilesList: filesList.length <= 0,
|
||||
setDragging,
|
||||
startDrag,
|
||||
setStartDrag,
|
||||
folderId: selectedFolderStore.id,
|
||||
setTooltipPosition,
|
||||
isRecycleBinFolder: treeFoldersStore.isRecycleBinFolder,
|
||||
|
@ -307,29 +307,33 @@ class SectionFilterContent extends React.Component {
|
||||
}
|
||||
}
|
||||
|
||||
export default inject(
|
||||
({ auth, initFilesStore, filesStore, selectedFolderStore }) => {
|
||||
const { setIsLoading, setViewAs, viewAs } = initFilesStore;
|
||||
const { firstLoad, fetchFiles, filter } = filesStore;
|
||||
export default inject(({ auth, filesStore, selectedFolderStore }) => {
|
||||
const {
|
||||
firstLoad,
|
||||
fetchFiles,
|
||||
filter,
|
||||
setIsLoading,
|
||||
setViewAs,
|
||||
viewAs,
|
||||
} = filesStore;
|
||||
|
||||
const { user } = auth.userStore;
|
||||
const { customNames, culture } = auth.settingsStore;
|
||||
const { user } = auth.userStore;
|
||||
const { customNames, culture } = auth.settingsStore;
|
||||
|
||||
return {
|
||||
customNames,
|
||||
user,
|
||||
firstLoad,
|
||||
selectedFolderId: selectedFolderStore.id,
|
||||
selectedItem: filter.selectedItem,
|
||||
filter,
|
||||
viewAs,
|
||||
return {
|
||||
customNames,
|
||||
user,
|
||||
firstLoad,
|
||||
selectedFolderId: selectedFolderStore.id,
|
||||
selectedItem: filter.selectedItem,
|
||||
filter,
|
||||
viewAs,
|
||||
|
||||
setIsLoading,
|
||||
fetchFiles,
|
||||
setViewAs,
|
||||
};
|
||||
}
|
||||
)(
|
||||
setIsLoading,
|
||||
fetchFiles,
|
||||
setViewAs,
|
||||
};
|
||||
})(
|
||||
withRouter(
|
||||
withLayoutSize(withTranslation("Home")(observer(SectionFilterContent)))
|
||||
)
|
||||
|
@ -93,12 +93,10 @@ const StyledContainer = styled.div`
|
||||
-webkit-tap-highlight-color: rgba(0, 0, 0, 0);
|
||||
padding-bottom: 56px;
|
||||
|
||||
${
|
||||
isMobile &&
|
||||
css`
|
||||
position: sticky;
|
||||
`
|
||||
}
|
||||
${isMobile &&
|
||||
css`
|
||||
position: sticky;
|
||||
`}
|
||||
|
||||
${(props) =>
|
||||
!props.isTabletView
|
||||
@ -115,12 +113,10 @@ const StyledContainer = styled.div`
|
||||
|
||||
@media ${tablet} {
|
||||
padding-bottom: 0;
|
||||
${
|
||||
!isMobile &&
|
||||
css`
|
||||
height: 56px;
|
||||
`
|
||||
}
|
||||
${!isMobile &&
|
||||
css`
|
||||
height: 56px;
|
||||
`}
|
||||
& > div:first-child {
|
||||
${(props) =>
|
||||
!isMobile &&
|
||||
@ -557,7 +553,6 @@ class SectionHeaderContent extends React.Component {
|
||||
export default inject(
|
||||
({
|
||||
auth,
|
||||
initFilesStore,
|
||||
filesStore,
|
||||
dialogsStore,
|
||||
treeFoldersStore,
|
||||
@ -565,7 +560,6 @@ export default inject(
|
||||
filesActionsStore,
|
||||
settingsStore,
|
||||
}) => {
|
||||
const { setIsLoading } = initFilesStore;
|
||||
const {
|
||||
setSelected,
|
||||
fileActionStore,
|
||||
@ -581,6 +575,7 @@ export default inject(
|
||||
isOnlyFoldersSelected,
|
||||
isThirdPartySelection,
|
||||
isWebEditSelected,
|
||||
setIsLoading,
|
||||
} = filesStore;
|
||||
const { isRecycleBinFolder, isPrivacyFolder } = treeFoldersStore;
|
||||
const { setAction } = fileActionStore;
|
||||
|
@ -162,9 +162,8 @@ const SectionPagingContent = ({
|
||||
);
|
||||
};
|
||||
|
||||
export default inject(({ initFilesStore, filesStore, selectedFolderStore }) => {
|
||||
const { setIsLoading } = initFilesStore;
|
||||
const { files, folders, fetchFiles, filter } = filesStore;
|
||||
export default inject(({ filesStore, selectedFolderStore }) => {
|
||||
const { files, folders, fetchFiles, filter, setIsLoading } = filesStore;
|
||||
|
||||
return {
|
||||
files,
|
||||
|
@ -294,19 +294,11 @@ const Home = withTranslation("Home")(PureHome);
|
||||
export default inject(
|
||||
({
|
||||
auth,
|
||||
initFilesStore,
|
||||
filesStore,
|
||||
uploadDataStore,
|
||||
dialogsStore,
|
||||
selectedFolderStore,
|
||||
}) => {
|
||||
const {
|
||||
dragging,
|
||||
setDragging,
|
||||
setIsLoading,
|
||||
isLoading,
|
||||
viewAs,
|
||||
} = initFilesStore;
|
||||
const {
|
||||
secondaryProgressDataStore,
|
||||
primaryProgressDataStore,
|
||||
@ -319,6 +311,11 @@ export default inject(
|
||||
fileActionStore,
|
||||
selection,
|
||||
setSelections,
|
||||
dragging,
|
||||
setDragging,
|
||||
setIsLoading,
|
||||
isLoading,
|
||||
viewAs,
|
||||
} = filesStore;
|
||||
|
||||
const { id } = fileActionStore;
|
||||
|
@ -162,8 +162,8 @@ const SectionBodyContent = ({
|
||||
};
|
||||
|
||||
export default inject(
|
||||
({ auth, initFilesStore, settingsStore, treeFoldersStore }) => {
|
||||
const { isLoading } = initFilesStore;
|
||||
({ auth, filesStore, settingsStore, treeFoldersStore }) => {
|
||||
const { isLoading } = filesStore;
|
||||
const { selectedTreeNode } = treeFoldersStore;
|
||||
const {
|
||||
isLoadedSettingsTree,
|
||||
|
@ -99,20 +99,17 @@ const PureSettings = ({
|
||||
|
||||
const Settings = withTranslation("Settings")(PureSettings);
|
||||
|
||||
export default inject(
|
||||
({ initFilesStore, filesStore, settingsStore, treeFoldersStore }) => {
|
||||
const { isLoading } = initFilesStore;
|
||||
const { setFirstLoad } = filesStore;
|
||||
const { setSelectedNode } = treeFoldersStore;
|
||||
const { getFilesSettings, isLoadedSettingsTree } = settingsStore;
|
||||
export default inject(({ filesStore, settingsStore, treeFoldersStore }) => {
|
||||
const { setFirstLoad, isLoading } = filesStore;
|
||||
const { setSelectedNode } = treeFoldersStore;
|
||||
const { getFilesSettings, isLoadedSettingsTree } = settingsStore;
|
||||
|
||||
return {
|
||||
isLoading,
|
||||
isLoadedSettingsTree,
|
||||
return {
|
||||
isLoading,
|
||||
isLoadedSettingsTree,
|
||||
|
||||
setFirstLoad,
|
||||
setSelectedNode,
|
||||
getFilesSettings,
|
||||
};
|
||||
}
|
||||
)(withRouter(observer(Settings)));
|
||||
setFirstLoad,
|
||||
setSelectedNode,
|
||||
getFilesSettings,
|
||||
};
|
||||
})(withRouter(observer(Settings)));
|
||||
|
@ -55,27 +55,24 @@ class SectionBodyContent extends React.Component {
|
||||
}
|
||||
}
|
||||
|
||||
export default inject(
|
||||
({ auth, initFilesStore, filesStore, versionHistoryStore }) => {
|
||||
const { setIsLoading, isLoading } = initFilesStore;
|
||||
const { setFirstLoad } = filesStore;
|
||||
const {
|
||||
versions,
|
||||
fetchFileVersions,
|
||||
fileId,
|
||||
setVerHistoryFileId,
|
||||
} = versionHistoryStore;
|
||||
export default inject(({ auth, filesStore, versionHistoryStore }) => {
|
||||
const { setFirstLoad, setIsLoading, isLoading } = filesStore;
|
||||
const {
|
||||
versions,
|
||||
fetchFileVersions,
|
||||
fileId,
|
||||
setVerHistoryFileId,
|
||||
} = versionHistoryStore;
|
||||
|
||||
return {
|
||||
culture: auth.settingsStore.culture,
|
||||
isLoading,
|
||||
versions,
|
||||
fileId,
|
||||
return {
|
||||
culture: auth.settingsStore.culture,
|
||||
isLoading,
|
||||
versions,
|
||||
fileId,
|
||||
|
||||
setFirstLoad,
|
||||
setIsLoading,
|
||||
fetchFileVersions,
|
||||
setVerHistoryFileId,
|
||||
};
|
||||
}
|
||||
)(withRouter(observer(SectionBodyContent)));
|
||||
setFirstLoad,
|
||||
setIsLoading,
|
||||
fetchFileVersions,
|
||||
setVerHistoryFileId,
|
||||
};
|
||||
})(withRouter(observer(SectionBodyContent)));
|
||||
|
@ -86,20 +86,17 @@ VersionHistory.propTypes = {
|
||||
history: PropTypes.object.isRequired,
|
||||
};
|
||||
|
||||
export default inject(
|
||||
({ auth, initFilesStore, filesStore, versionHistoryStore }) => {
|
||||
const { isLoading } = initFilesStore;
|
||||
const { filter, setFilesFilter } = filesStore;
|
||||
const { setIsVerHistoryPanel, versions } = versionHistoryStore;
|
||||
export default inject(({ auth, filesStore, versionHistoryStore }) => {
|
||||
const { filter, setFilesFilter, isLoading } = filesStore;
|
||||
const { setIsVerHistoryPanel, versions } = versionHistoryStore;
|
||||
|
||||
return {
|
||||
isTabletView: auth.settingsStore.isTabletView,
|
||||
isLoading,
|
||||
filter,
|
||||
versions,
|
||||
return {
|
||||
isTabletView: auth.settingsStore.isTabletView,
|
||||
isLoading,
|
||||
filter,
|
||||
versions,
|
||||
|
||||
setFilesFilter,
|
||||
setIsVerHistoryPanel,
|
||||
};
|
||||
}
|
||||
)(withRouter(observer(VersionHistory)));
|
||||
setFilesFilter,
|
||||
setIsVerHistoryPanel,
|
||||
};
|
||||
})(withRouter(observer(VersionHistory)));
|
||||
|
@ -140,9 +140,15 @@ const ChangeOwnerPanel = withTranslation("ChangeOwnerPanel")(
|
||||
ChangeOwnerComponent
|
||||
);
|
||||
|
||||
export default inject(({ auth, initFilesStore, filesStore, dialogsStore }) => {
|
||||
const { setIsLoading, isLoading } = initFilesStore;
|
||||
const { selection, setFile, setFolder, setFilesOwner } = filesStore;
|
||||
export default inject(({ auth, filesStore, dialogsStore }) => {
|
||||
const {
|
||||
selection,
|
||||
setFile,
|
||||
setFolder,
|
||||
setFilesOwner,
|
||||
setIsLoading,
|
||||
isLoading,
|
||||
} = filesStore;
|
||||
const { ownerPanelVisible, setChangeOwnerPanelVisible } = dialogsStore;
|
||||
|
||||
return {
|
||||
|
@ -0,0 +1,44 @@
|
||||
import i18n from "i18next";
|
||||
import Backend from "i18next-http-backend";
|
||||
import { LANGUAGE } from "@appserver/common/constants";
|
||||
import config from "../../../../package.json";
|
||||
const homepage = config.homepage;
|
||||
|
||||
//import LanguageDetector from "i18next-browser-languagedetector";
|
||||
// not like to use this?
|
||||
// have a look at the Quick start guide
|
||||
// for passing in lng and translations on init
|
||||
|
||||
const languages = ["en", "ru"];
|
||||
|
||||
const newInstance = i18n.createInstance();
|
||||
|
||||
newInstance.use(Backend).init({
|
||||
lng: localStorage.getItem(LANGUAGE) || "en",
|
||||
supportedLngs: languages,
|
||||
whitelist: languages,
|
||||
fallbackLng: "en",
|
||||
load: "languageOnly",
|
||||
//debug: true,
|
||||
|
||||
interpolation: {
|
||||
escapeValue: false, // not needed for react as it escapes by default
|
||||
format: function (value, format) {
|
||||
if (format === "lowercase") return value.toLowerCase();
|
||||
return value;
|
||||
},
|
||||
},
|
||||
|
||||
backend: {
|
||||
loadPath: `${homepage}/locales/{{lng}}/EmbeddingPanel.json`,
|
||||
},
|
||||
|
||||
ns: ["EmbeddingPanel"],
|
||||
defaultNS: "EmbeddingPanel",
|
||||
|
||||
react: {
|
||||
useSuspense: false,
|
||||
},
|
||||
});
|
||||
|
||||
export default newInstance;
|
@ -9,7 +9,7 @@ import Link from "@appserver/components/link";
|
||||
import TextInput from "@appserver/components/text-input";
|
||||
import Textarea from "@appserver/components/textarea";
|
||||
import toastr from "studio/toastr";
|
||||
import { withTranslation } from "react-i18next";
|
||||
import { withTranslation, I18nextProvider } from "react-i18next";
|
||||
import {
|
||||
StyledEmbeddingPanel,
|
||||
StyledContent,
|
||||
@ -17,6 +17,7 @@ import {
|
||||
StyledBody,
|
||||
} from "../StyledPanels";
|
||||
import copy from "copy-to-clipboard";
|
||||
import i18n from "./i18n";
|
||||
|
||||
class EmbeddingPanelComponent extends React.Component {
|
||||
constructor(props) {
|
||||
@ -128,7 +129,7 @@ class EmbeddingPanelComponent extends React.Component {
|
||||
<StyledHeaderContent>
|
||||
<IconButton
|
||||
size="16"
|
||||
iconName="ArrowPathIcon"
|
||||
iconName="/static/images/arrow.path.react.svg"
|
||||
onClick={this.onArrowClick}
|
||||
color="#A3A9AE"
|
||||
/>
|
||||
@ -215,4 +216,12 @@ EmbeddingPanelComponent.propTypes = {
|
||||
onClose: PropTypes.func,
|
||||
};
|
||||
|
||||
export default withTranslation("EmbeddingPanel")(EmbeddingPanelComponent);
|
||||
const EmbeddingPanel = withTranslation("EmbeddingPanel")(
|
||||
EmbeddingPanelComponent
|
||||
);
|
||||
|
||||
export default (props) => (
|
||||
<I18nextProvider i18n={i18n}>
|
||||
<EmbeddingPanel {...props} />
|
||||
</I18nextProvider>
|
||||
);
|
||||
|
@ -282,14 +282,12 @@ const NewFilesPanel = withTranslation("NewFilesPanel")(NewFilesPanelComponent);
|
||||
|
||||
export default inject(
|
||||
({
|
||||
initFilesStore,
|
||||
filesStore,
|
||||
mediaViewerDataStore,
|
||||
treeFoldersStore,
|
||||
formatsStore,
|
||||
filesActionsStore,
|
||||
}) => {
|
||||
const { setIsLoading } = initFilesStore;
|
||||
const {
|
||||
files,
|
||||
folders,
|
||||
@ -297,6 +295,7 @@ export default inject(
|
||||
filter,
|
||||
addFileToRecentlyViewed,
|
||||
setNewRowItems,
|
||||
setIsLoading,
|
||||
} = filesStore;
|
||||
const { treeFolders, setTreeFolders } = treeFoldersStore;
|
||||
const { setMediaViewerData } = mediaViewerDataStore;
|
||||
|
@ -0,0 +1,69 @@
|
||||
import React, { useEffect } from "react";
|
||||
import { Provider as MobxProvider } from "mobx-react";
|
||||
import { inject, observer } from "mobx-react";
|
||||
import { getShareFiles } from "@appserver/common/api/files";
|
||||
import SharingPanel from "../SharingPanel";
|
||||
|
||||
import stores from "../../../store/index";
|
||||
import store from "studio/store";
|
||||
|
||||
const { auth: authStore } = store;
|
||||
|
||||
const SharingDialog = ({
|
||||
sharingObject,
|
||||
onSuccess,
|
||||
isVisible,
|
||||
setSharingPanelVisible,
|
||||
onCancel,
|
||||
setSelection,
|
||||
}) => {
|
||||
useEffect(() => {
|
||||
setSharingPanelVisible(isVisible);
|
||||
}, [isVisible]);
|
||||
|
||||
useEffect(() => {
|
||||
setSelection([sharingObject]);
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<>
|
||||
{isVisible && (
|
||||
<SharingPanel
|
||||
key="sharing-panel"
|
||||
uploadPanelVisible={false}
|
||||
onSuccess={onSuccess}
|
||||
onCancel={onCancel}
|
||||
/>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
const SharingDialogWrapper = inject(({ dialogsStore, filesStore }) => {
|
||||
const { getShareUsers, setSelection, selection } = filesStore;
|
||||
const { setSharingPanelVisible } = dialogsStore;
|
||||
return {
|
||||
setSharingPanelVisible,
|
||||
getShareUsers,
|
||||
setSelection,
|
||||
selection,
|
||||
};
|
||||
})(observer(SharingDialog));
|
||||
|
||||
class SharingModal extends React.Component {
|
||||
static getSharingSettings = (fileId) => {
|
||||
return getShareFiles([+fileId], []).then((users) =>
|
||||
SharingPanel.convertSharingUsers(users)
|
||||
);
|
||||
};
|
||||
|
||||
render() {
|
||||
return (
|
||||
<MobxProvider auth={authStore} {...stores}>
|
||||
<SharingDialogWrapper {...this.props} />
|
||||
</MobxProvider>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default SharingModal;
|
@ -31,7 +31,7 @@ const AccessComboBox = (props) => {
|
||||
{accessOptions.includes("FullAccess") && (
|
||||
<DropDownItem
|
||||
label={t("FullAccess")}
|
||||
icon="images/access.edit.react.svg"
|
||||
icon="/static/images/access.edit.react.svg"
|
||||
data-id={itemId}
|
||||
data-access={FullAccess}
|
||||
onClick={onAccessChange}
|
||||
@ -41,7 +41,7 @@ const AccessComboBox = (props) => {
|
||||
{accessOptions.includes("FilterEditing") && (
|
||||
<DropDownItem
|
||||
label={t("CustomFilter")}
|
||||
icon="images/custom.filter.react.svg"
|
||||
icon="/static/images/custom.filter.react.svg"
|
||||
data-id={itemId}
|
||||
data-access={CustomFilter}
|
||||
onClick={onAccessChange}
|
||||
@ -51,7 +51,7 @@ const AccessComboBox = (props) => {
|
||||
{accessOptions.includes("Review") && (
|
||||
<DropDownItem
|
||||
label={t("Review")}
|
||||
icon="images/access.review.react.svg"
|
||||
icon="/static/images/access.review.react.svg"
|
||||
data-id={itemId}
|
||||
data-access={Review}
|
||||
onClick={onAccessChange}
|
||||
@ -61,7 +61,7 @@ const AccessComboBox = (props) => {
|
||||
{accessOptions.includes("FormFilling") && (
|
||||
<DropDownItem
|
||||
label={t("FormFilling")}
|
||||
icon="images/access.form.react.svg"
|
||||
icon="/static/images/access.form.react.svg"
|
||||
data-id={itemId}
|
||||
data-access={FormFilling}
|
||||
onClick={onAccessChange}
|
||||
@ -71,7 +71,7 @@ const AccessComboBox = (props) => {
|
||||
{accessOptions.includes("Comment") && (
|
||||
<DropDownItem
|
||||
label={t("Comment")}
|
||||
icon="images/access.comment.react.svg"
|
||||
icon="/static/images/access.comment.react.svg"
|
||||
data-id={itemId}
|
||||
data-access={Comment}
|
||||
onClick={onAccessChange}
|
||||
@ -91,7 +91,7 @@ const AccessComboBox = (props) => {
|
||||
{accessOptions.includes("DenyAccess") && (
|
||||
<DropDownItem
|
||||
label={t("DenyAccess")}
|
||||
icon="images/access.none.react.svg"
|
||||
icon="/static/images/access.none.react.svg"
|
||||
data-id={itemId}
|
||||
data-access={DenyAccess}
|
||||
onClick={onAccessChange}
|
||||
|
@ -44,6 +44,7 @@ class SharingRow extends React.Component {
|
||||
onShareEmail = () => {
|
||||
const { selection, item, t } = this.props;
|
||||
const { shareLink } = item.sharedTo;
|
||||
|
||||
const itemName = selection.title ? selection.title : selection[0].title;
|
||||
const subject = t("ShareEmailSubject", { itemName });
|
||||
const body = t("ShareEmailBody", { itemName, shareLink });
|
||||
@ -228,7 +229,7 @@ class SharingRow extends React.Component {
|
||||
!shareLink &&
|
||||
!isLocked && (
|
||||
<IconButton
|
||||
iconName="images/remove.react.svg"
|
||||
iconName="/static/images/remove.react.svg"
|
||||
id={id}
|
||||
{...onRemoveUserProp}
|
||||
className="sharing_panel-remove-icon"
|
||||
|
@ -0,0 +1,44 @@
|
||||
import i18n from "i18next";
|
||||
import Backend from "i18next-http-backend";
|
||||
import { LANGUAGE } from "@appserver/common/constants";
|
||||
import config from "../../../../package.json";
|
||||
const homepage = config.homepage;
|
||||
|
||||
//import LanguageDetector from "i18next-browser-languagedetector";
|
||||
// not like to use this?
|
||||
// have a look at the Quick start guide
|
||||
// for passing in lng and translations on init
|
||||
|
||||
const languages = ["en", "ru"];
|
||||
|
||||
const newInstance = i18n.createInstance();
|
||||
|
||||
newInstance.use(Backend).init({
|
||||
lng: localStorage.getItem(LANGUAGE) || "en",
|
||||
supportedLngs: languages,
|
||||
whitelist: languages,
|
||||
fallbackLng: "en",
|
||||
load: "languageOnly",
|
||||
//debug: true,
|
||||
|
||||
interpolation: {
|
||||
escapeValue: false, // not needed for react as it escapes by default
|
||||
format: function (value, format) {
|
||||
if (format === "lowercase") return value.toLowerCase();
|
||||
return value;
|
||||
},
|
||||
},
|
||||
|
||||
backend: {
|
||||
loadPath: `${homepage}/locales/{{lng}}/SharingPanel.json`,
|
||||
},
|
||||
|
||||
ns: ["SharingPanel"],
|
||||
defaultNS: "SharingPanel",
|
||||
|
||||
react: {
|
||||
useSuspense: false,
|
||||
},
|
||||
});
|
||||
|
||||
export default newInstance;
|
@ -8,6 +8,8 @@ import Button from "@appserver/components/button";
|
||||
import DropDown from "@appserver/components/drop-down";
|
||||
import DropDownItem from "@appserver/components/drop-down-item";
|
||||
import Textarea from "@appserver/components/textarea";
|
||||
import Loader from "@appserver/components/loader";
|
||||
import Text from "@appserver/components/text";
|
||||
import { withRouter } from "react-router";
|
||||
import { withTranslation, Trans } from "react-i18next";
|
||||
import toastr from "studio/toastr";
|
||||
@ -23,13 +25,14 @@ import { AddUsersPanel, AddGroupsPanel, EmbeddingPanel } from "../index";
|
||||
import SharingRow from "./SharingRow";
|
||||
import { inject, observer } from "mobx-react";
|
||||
import config from "../../../../package.json";
|
||||
import i18n from "./i18n";
|
||||
import { I18nextProvider } from "react-i18next";
|
||||
|
||||
const SharingBodyStyle = { height: `calc(100vh - 156px)` };
|
||||
|
||||
class SharingPanelComponent extends React.Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
this.state = {
|
||||
showActionPanel: false,
|
||||
isNotifyUsers: false,
|
||||
@ -104,10 +107,11 @@ class SharingPanelComponent extends React.Component {
|
||||
isDesktop,
|
||||
setEncryptionAccess,
|
||||
setShareFiles,
|
||||
onSuccess,
|
||||
} = this.props;
|
||||
|
||||
const folderIds = [];
|
||||
const fileIds = [];
|
||||
let folderIds = [];
|
||||
let fileIds = [];
|
||||
const share = [];
|
||||
|
||||
let externalAccess = null;
|
||||
@ -150,6 +154,7 @@ class SharingPanelComponent extends React.Component {
|
||||
folderIds.push(item.id);
|
||||
}
|
||||
}
|
||||
|
||||
const owner = shareDataItems.find((x) => x.isOwner);
|
||||
const ownerId =
|
||||
filesOwnerId !== owner.sharedTo.id ? owner.sharedTo.id : null;
|
||||
@ -196,10 +201,10 @@ class SharingPanelComponent extends React.Component {
|
||||
}
|
||||
return Promise.resolve();
|
||||
})
|
||||
.then(() => onSuccess && onSuccess())
|
||||
.catch((err) => toastr.error(err))
|
||||
.finally(() => setIsLoading(false));
|
||||
};
|
||||
|
||||
onNotifyUsersChange = () =>
|
||||
this.setState({ isNotifyUsers: !this.state.isNotifyUsers });
|
||||
|
||||
@ -251,9 +256,6 @@ class SharingPanelComponent extends React.Component {
|
||||
};
|
||||
|
||||
getShareData = () => {
|
||||
const returnValue = this.getData();
|
||||
const folderId = returnValue[0];
|
||||
const fileId = returnValue[1];
|
||||
const {
|
||||
getAccessOption,
|
||||
getExternalAccessOption,
|
||||
@ -262,12 +264,17 @@ class SharingPanelComponent extends React.Component {
|
||||
getShareUsers,
|
||||
} = this.props;
|
||||
|
||||
const returnValue = this.getData();
|
||||
const folderId = returnValue[0];
|
||||
const fileId = returnValue[1];
|
||||
|
||||
if (folderId.length !== 0 || fileId.length !== 0) {
|
||||
setIsLoading(true);
|
||||
getShareUsers(folderId, fileId)
|
||||
.then((shareDataItems) => {
|
||||
const baseShareData = JSON.parse(JSON.stringify(shareDataItems));
|
||||
const accessOptions = getAccessOption(selection);
|
||||
|
||||
const externalAccessOptions = getExternalAccessOption(selection);
|
||||
const filesOwner = shareDataItems.find((x) => x.isOwner);
|
||||
const filesOwnerId = filesOwner ? filesOwner.sharedTo.id : null;
|
||||
@ -277,10 +284,11 @@ class SharingPanelComponent extends React.Component {
|
||||
shareDataItems,
|
||||
accessOptions,
|
||||
externalAccessOptions,
|
||||
showPanel: true,
|
||||
//showPanel: true,
|
||||
filesOwnerId,
|
||||
});
|
||||
})
|
||||
|
||||
.catch((err) => {
|
||||
toastr.error(err);
|
||||
this.onClose();
|
||||
@ -291,6 +299,7 @@ class SharingPanelComponent extends React.Component {
|
||||
|
||||
getInternalLink = () => {
|
||||
const { homepage, selection } = this.props;
|
||||
|
||||
const item = selection[0];
|
||||
const isFile = !!item.fileExst;
|
||||
|
||||
@ -326,8 +335,11 @@ class SharingPanelComponent extends React.Component {
|
||||
setShareDataItems = (shareDataItems) => this.setState({ shareDataItems });
|
||||
|
||||
onClose = () => {
|
||||
this.props.setSharingPanelVisible(false);
|
||||
this.props.selectUploadedFile([]);
|
||||
const { onCancel, setSharingPanelVisible, selectUploadedFile } = this.props;
|
||||
|
||||
setSharingPanelVisible(false);
|
||||
selectUploadedFile([]);
|
||||
onCancel && onCancel();
|
||||
};
|
||||
|
||||
componentDidMount() {
|
||||
@ -382,6 +394,8 @@ class SharingPanelComponent extends React.Component {
|
||||
canShareOwnerChange,
|
||||
isLoading,
|
||||
uploadPanelVisible,
|
||||
documentTitle,
|
||||
sharingPanelVisible,
|
||||
} = this.props;
|
||||
const {
|
||||
showActionPanel,
|
||||
@ -393,12 +407,12 @@ class SharingPanelComponent extends React.Component {
|
||||
showEmbeddingPanel,
|
||||
showChangeOwnerPanel,
|
||||
shareLink,
|
||||
showPanel,
|
||||
//showPanel,
|
||||
accessOptions,
|
||||
externalAccessOptions,
|
||||
} = this.state;
|
||||
|
||||
const visible = showPanel;
|
||||
const visible = sharingPanelVisible;
|
||||
const zIndex = 310;
|
||||
const onPlusClickProp = !isLoading ? { onClick: this.onPlusClick } : {};
|
||||
const internalLink = selection.length === 1 && this.getInternalLink();
|
||||
@ -417,7 +431,7 @@ class SharingPanelComponent extends React.Component {
|
||||
{uploadPanelVisible && (
|
||||
<IconButton
|
||||
size="16"
|
||||
iconName="ArrowPathIcon"
|
||||
iconName="/static/images/arrow.path.react.svg"
|
||||
onClick={this.onClose}
|
||||
color="A3A9AE"
|
||||
/>
|
||||
@ -429,7 +443,7 @@ class SharingPanelComponent extends React.Component {
|
||||
<div ref={this.ref} className="sharing_panel-drop-down-wrapper">
|
||||
<IconButton
|
||||
size="17"
|
||||
iconName="images/actions.header.touch.react.svg"
|
||||
iconName="/static/images/actions.header.touch.react.svg"
|
||||
className="sharing_panel-plus-icon"
|
||||
{...onPlusClickProp}
|
||||
color="A3A9AE"
|
||||
@ -466,26 +480,38 @@ class SharingPanelComponent extends React.Component {
|
||||
stype="mediumBlack"
|
||||
style={SharingBodyStyle}
|
||||
>
|
||||
{shareDataItems.map((item, index) => (
|
||||
<SharingRow
|
||||
t={t}
|
||||
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.onShowEmbeddingPanel}
|
||||
onToggleLink={this.onToggleLink}
|
||||
onShowChangeOwnerPanel={this.onShowChangeOwnerPanel}
|
||||
isLoading={isLoading}
|
||||
/>
|
||||
))}
|
||||
{!isLoading ? (
|
||||
shareDataItems.map((item, index) => (
|
||||
<SharingRow
|
||||
t={t}
|
||||
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.onShowEmbeddingPanel}
|
||||
onToggleLink={this.onToggleLink}
|
||||
onShowChangeOwnerPanel={this.onShowChangeOwnerPanel}
|
||||
isLoading={isLoading}
|
||||
documentTitle={documentTitle}
|
||||
/>
|
||||
))
|
||||
) : (
|
||||
<div key="loader" className="sharing-panel-loader-wrapper">
|
||||
<Loader
|
||||
type="oval"
|
||||
size="16px"
|
||||
className="sharing-panel-loader"
|
||||
/>
|
||||
<Text as="span">{t("LoadingLabel")}</Text>
|
||||
</div>
|
||||
)}
|
||||
{isNotifyUsers && (
|
||||
<div className="sharing_panel-text-area">
|
||||
<Textarea
|
||||
@ -565,23 +591,14 @@ class SharingPanelComponent extends React.Component {
|
||||
}
|
||||
}
|
||||
|
||||
const SharingPanel = withTranslation("SharingPanel")(SharingPanelComponent);
|
||||
|
||||
export default inject(
|
||||
const SharingPanel = inject(
|
||||
(
|
||||
{
|
||||
auth,
|
||||
initFilesStore,
|
||||
filesStore,
|
||||
uploadDataStore,
|
||||
dialogsStore,
|
||||
treeFoldersStore,
|
||||
},
|
||||
{ auth, filesStore, uploadDataStore, dialogsStore, treeFoldersStore },
|
||||
{ uploadPanelVisible }
|
||||
) => {
|
||||
const { replaceFileStream, setEncryptionAccess } = auth;
|
||||
const { customNames, isDesktopClient } = auth.settingsStore;
|
||||
const { setIsLoading, isLoading } = initFilesStore;
|
||||
|
||||
const {
|
||||
selection,
|
||||
canShareOwnerChange,
|
||||
@ -591,28 +608,31 @@ export default inject(
|
||||
setFolder,
|
||||
getShareUsers,
|
||||
setShareFiles,
|
||||
setIsLoading,
|
||||
isLoading,
|
||||
} = filesStore;
|
||||
const { isPrivacyFolder } = treeFoldersStore;
|
||||
const { setSharingPanelVisible } = dialogsStore;
|
||||
const { setSharingPanelVisible, sharingPanelVisible } = dialogsStore;
|
||||
const {
|
||||
uploadSelection,
|
||||
selectedUploadFile,
|
||||
selectUploadedFile,
|
||||
updateUploadedItem,
|
||||
} = uploadDataStore;
|
||||
|
||||
return {
|
||||
isMyId: auth.userStore.user.id,
|
||||
isMyId: auth.userStore.user && auth.userStore.user.id,
|
||||
groupsCaption: customNames.groupsCaption,
|
||||
isDesktop: isDesktopClient,
|
||||
homepage: config.homepage,
|
||||
selection: uploadPanelVisible ? uploadSelection : selection,
|
||||
selection: uploadPanelVisible ? selectedUploadFile : selection,
|
||||
isLoading,
|
||||
isPrivacy: isPrivacyFolder,
|
||||
uploadSelection,
|
||||
selectedUploadFile,
|
||||
canShareOwnerChange,
|
||||
|
||||
setIsLoading,
|
||||
setSharingPanelVisible,
|
||||
sharingPanelVisible,
|
||||
selectUploadedFile,
|
||||
updateUploadedItem,
|
||||
replaceFileStream,
|
||||
@ -625,4 +645,48 @@ export default inject(
|
||||
setShareFiles,
|
||||
};
|
||||
}
|
||||
)(withRouter(observer(SharingPanel)));
|
||||
)(observer(withTranslation("SharingPanel")(SharingPanelComponent)));
|
||||
|
||||
class Panel extends React.Component {
|
||||
static convertSharingUsers = (shareDataItems) => {
|
||||
const t = i18n.getFixedT(null, "SharingPanel");
|
||||
let sharingSettings = [];
|
||||
for (let i = 1; i < shareDataItems.length; i++) {
|
||||
let resultAccess =
|
||||
shareDataItems[i].access === 1
|
||||
? t("FullAccess")
|
||||
: shareDataItems[i].access === 2
|
||||
? t("ReadOnly")
|
||||
: shareDataItems[i].access === 3
|
||||
? t("DenyAccess")
|
||||
: shareDataItems[i].access === 5
|
||||
? t("Review")
|
||||
: shareDataItems[i].access === 6
|
||||
? t("Comment")
|
||||
: shareDataItems[i].access === 7
|
||||
? t("FormFilling")
|
||||
: shareDataItems[i].access === 8
|
||||
? t("CustomFilter")
|
||||
: "";
|
||||
|
||||
let obj = {
|
||||
user:
|
||||
shareDataItems[i].sharedTo.displayName ||
|
||||
shareDataItems[i].sharedTo.name,
|
||||
permissions: resultAccess,
|
||||
};
|
||||
sharingSettings.push(obj);
|
||||
}
|
||||
return sharingSettings;
|
||||
};
|
||||
|
||||
render() {
|
||||
return (
|
||||
<I18nextProvider i18n={i18n}>
|
||||
<SharingPanel {...this.props} />
|
||||
</I18nextProvider>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default Panel;
|
||||
|
@ -6,7 +6,7 @@ import ToggleButton from "@appserver/components/toggle-button";
|
||||
import { StyledLinkRow } from "../StyledPanels";
|
||||
import AccessComboBox from "./AccessComboBox";
|
||||
import { ShareAccessRights } from "@appserver/common/constants";
|
||||
import AccessEditIcon from "../../../../public/images/access.edit.react.svg";
|
||||
import AccessEditIcon from "../../../../../../../public/images/access.edit.react.svg";
|
||||
import commonIconsStyles from "@appserver/components/utils/common-icons-style";
|
||||
|
||||
const StyledAccessEditIcon = styled(AccessEditIcon)`
|
||||
|
@ -195,6 +195,15 @@ const StyledContent = styled.div`
|
||||
min-height: 16px;
|
||||
}
|
||||
}
|
||||
|
||||
.sharing-panel-loader-wrapper {
|
||||
margin-top: 8px;
|
||||
padding-left: 32px;
|
||||
}
|
||||
.sharing-panel-loader {
|
||||
display: inline;
|
||||
margin-right: 10px;
|
||||
}
|
||||
`;
|
||||
|
||||
const StyledHeaderContent = styled.div`
|
||||
|
@ -89,9 +89,9 @@ VersionHistoryPanel.propTypes = {
|
||||
fileId: PropTypes.string,
|
||||
};
|
||||
|
||||
export default inject(({ auth, initFilesStore, versionHistoryStore }) => {
|
||||
export default inject(({ auth, filesStore, versionHistoryStore }) => {
|
||||
const { isTabletView } = auth.settingsStore;
|
||||
const { isLoading } = initFilesStore;
|
||||
const { isLoading } = filesStore;
|
||||
const {
|
||||
fileId,
|
||||
versions,
|
||||
|
@ -7,21 +7,21 @@ export const presentInArray = (array, search, caseInsensitive = false) => {
|
||||
export const getAccessIcon = (access) => {
|
||||
switch (access) {
|
||||
case 1:
|
||||
return "images/access.edit.react.svg";
|
||||
return "/static/images/access.edit.react.svg";
|
||||
case 2:
|
||||
return "/static/images/eye.react.svg";
|
||||
case 3:
|
||||
return "images/access.none.react.svg";
|
||||
return "/static/images/access.none.react.svg";
|
||||
case 4:
|
||||
return "images/catalog.question.react.svg";
|
||||
case 5:
|
||||
return "images/access.review.react.svg";
|
||||
return "/static/images/access.review.react.svg";
|
||||
case 6:
|
||||
return "images/access.comment.react.svg";
|
||||
return "/static/images/access.comment.react.svg";
|
||||
case 7:
|
||||
return "images/access.form.react.svg";
|
||||
return "/static/images/access.form.react.svg";
|
||||
case 8:
|
||||
return "images/custom.filter.react.svg";
|
||||
return "/static/images/custom.filter.react.svg";
|
||||
default:
|
||||
return;
|
||||
}
|
||||
|
@ -10,7 +10,6 @@ import("./bootstrap");
|
||||
// import * as serviceWorker from "./serviceWorker";
|
||||
// import { ErrorBoundary, store as commonStore } from "asc-web-common";
|
||||
// import { Provider as MobxProvider } from "mobx-react";
|
||||
// import initFilesStore from "./store/InitFilesStore";
|
||||
// import filesStore from "./store/FilesStore";
|
||||
// import settingsStore from "./store/SettingsStore";
|
||||
// import mediaViewerDataStore from "./store/MediaViewerDataStore";
|
||||
@ -26,7 +25,6 @@ import("./bootstrap");
|
||||
// ReactDOM.render(
|
||||
// <MobxProvider
|
||||
// auth={authStore}
|
||||
// initFilesStore={initFilesStore}
|
||||
// filesStore={filesStore}
|
||||
// settingsStore={settingsStore}
|
||||
// mediaViewerDataStore={mediaViewerDataStore}
|
||||
|
@ -139,4 +139,4 @@ class DocserviceStore {
|
||||
canWebFilterEditing = (extension) =>
|
||||
presentInArray(this.customfilterDocs, extension);
|
||||
}
|
||||
export default DocserviceStore;
|
||||
export default new DocserviceStore();
|
||||
|
@ -25,4 +25,4 @@ class FileActionStore {
|
||||
};
|
||||
}
|
||||
|
||||
export default FileActionStore;
|
||||
export default new FileActionStore();
|
||||
|
@ -1,12 +1,4 @@
|
||||
import { makeAutoObservable } from "mobx";
|
||||
import store from "studio/store";
|
||||
import uploadDataStore from "./UploadDataStore";
|
||||
import treeFoldersStore from "./TreeFoldersStore";
|
||||
import filesStore from "./FilesStore";
|
||||
import selectedFolderStore from "./SelectedFolderStore";
|
||||
import initFilesStore from "./InitFilesStore";
|
||||
import settingsStore from "./SettingsStore";
|
||||
import dialogsStore from "./DialogsStore";
|
||||
|
||||
import {
|
||||
removeFiles,
|
||||
@ -24,42 +16,41 @@ import { FileAction } from "@appserver/common/constants";
|
||||
import { TIMEOUT } from "../helpers/constants";
|
||||
import { loopTreeFolders } from "../helpers/files-helpers";
|
||||
|
||||
const { auth } = store;
|
||||
|
||||
const {
|
||||
fetchFiles,
|
||||
markItemAsFavorite,
|
||||
removeItemFromFavorite,
|
||||
fetchFavoritesFolder,
|
||||
getFileInfo,
|
||||
setSelected,
|
||||
selectFile,
|
||||
deselectFile,
|
||||
setSelection,
|
||||
setFile,
|
||||
} = filesStore;
|
||||
const { setTreeFolders } = treeFoldersStore;
|
||||
const { setIsLoading } = initFilesStore;
|
||||
const { secondaryProgressDataStore, loopFilesOperations } = uploadDataStore;
|
||||
const {
|
||||
setSecondaryProgressBarData,
|
||||
clearSecondaryProgressData,
|
||||
} = secondaryProgressDataStore;
|
||||
const {
|
||||
setConnectDialogVisible,
|
||||
setConnectItem,
|
||||
setThirdPartyMoveDialogVisible,
|
||||
setDestFolderId,
|
||||
} = dialogsStore;
|
||||
|
||||
class FilesActionStore {
|
||||
constructor() {
|
||||
authStore;
|
||||
uploadDataStore;
|
||||
treeFoldersStore;
|
||||
filesStore;
|
||||
selectedFolderStore;
|
||||
settingsStore;
|
||||
dialogsStore;
|
||||
|
||||
constructor(
|
||||
authStore,
|
||||
uploadDataStore,
|
||||
treeFoldersStore,
|
||||
filesStore,
|
||||
selectedFolderStore,
|
||||
settingsStore,
|
||||
dialogsStore
|
||||
) {
|
||||
makeAutoObservable(this);
|
||||
this.authStore = authStore;
|
||||
this.uploadDataStore = uploadDataStore;
|
||||
this.treeFoldersStore = treeFoldersStore;
|
||||
this.filesStore = filesStore;
|
||||
this.selectedFolderStore = selectedFolderStore;
|
||||
this.settingsStore = settingsStore;
|
||||
this.dialogsStore = dialogsStore;
|
||||
}
|
||||
|
||||
deleteAction = (translations) => {
|
||||
const { isRecycleBinFolder, isPrivacyFolder } = treeFoldersStore;
|
||||
const { selection } = filesStore;
|
||||
const { isRecycleBinFolder, isPrivacyFolder } = this.treeFoldersStore;
|
||||
const { selection } = this.filesStore;
|
||||
const {
|
||||
setSecondaryProgressBarData,
|
||||
clearSecondaryProgressData,
|
||||
} = this.uploadDataStore.secondaryProgressDataStore;
|
||||
|
||||
const deleteAfter = true; //Delete after finished TODO: get from settings
|
||||
const immediately = isRecycleBinFolder || isPrivacyFolder ? true : false; //Don't move to the Recycle Bin
|
||||
@ -102,8 +93,13 @@ class FilesActionStore {
|
||||
};
|
||||
|
||||
loopDeleteOperation = (id, translations) => {
|
||||
const { filter } = filesStore;
|
||||
const { isRecycleBinFolder } = treeFoldersStore;
|
||||
const { filter, fetchFiles } = this.filesStore;
|
||||
const { isRecycleBinFolder, setTreeFolders } = this.treeFoldersStore;
|
||||
const {
|
||||
setSecondaryProgressBarData,
|
||||
clearSecondaryProgressData,
|
||||
} = this.uploadDataStore.secondaryProgressDataStore;
|
||||
|
||||
const successMessage = isRecycleBinFolder
|
||||
? translations.deleteFromTrash
|
||||
: translations.deleteSelectedElem;
|
||||
@ -129,10 +125,10 @@ class FilesActionStore {
|
||||
alert: false,
|
||||
});
|
||||
setTimeout(() => clearSecondaryProgressData(), TIMEOUT);
|
||||
fetchFiles(selectedFolderStore.id, filter).then((data) => {
|
||||
fetchFiles(this.selectedFolderStore.id, filter).then((data) => {
|
||||
if (!isRecycleBinFolder) {
|
||||
const path = data.selectedFolder.pathParts.slice(0);
|
||||
const newTreeFolders = treeFoldersStore.treeFolders;
|
||||
const newTreeFolders = this.treeFoldersStore.treeFolders;
|
||||
const folders = data.selectedFolder.folders;
|
||||
const foldersCount = data.selectedFolder.foldersCount;
|
||||
loopTreeFolders(path, newTreeFolders, folders, foldersCount);
|
||||
@ -151,6 +147,10 @@ class FilesActionStore {
|
||||
};
|
||||
|
||||
getDownloadProgress = (data, label) => {
|
||||
const {
|
||||
setSecondaryProgressBarData,
|
||||
clearSecondaryProgressData,
|
||||
} = this.uploadDataStore.secondaryProgressDataStore;
|
||||
const url = data.url;
|
||||
|
||||
return getProgress()
|
||||
@ -180,7 +180,11 @@ class FilesActionStore {
|
||||
};
|
||||
|
||||
downloadAction = (label) => {
|
||||
const { selection } = filesStore;
|
||||
const {
|
||||
setSecondaryProgressBarData,
|
||||
clearSecondaryProgressData,
|
||||
} = this.uploadDataStore.secondaryProgressDataStore;
|
||||
const { selection } = this.filesStore;
|
||||
const fileIds = [];
|
||||
const folderIds = [];
|
||||
const items = [];
|
||||
@ -222,15 +226,22 @@ class FilesActionStore {
|
||||
};
|
||||
|
||||
editCompleteAction = (id, selectedItem) => {
|
||||
const { filter, folders, files, fileActionStore } = filesStore;
|
||||
const {
|
||||
filter,
|
||||
folders,
|
||||
files,
|
||||
fileActionStore,
|
||||
fetchFiles,
|
||||
setIsLoading,
|
||||
} = this.filesStore;
|
||||
const { type, setAction } = fileActionStore;
|
||||
const { treeFolders } = treeFoldersStore;
|
||||
const { treeFolders, setTreeFolders } = this.treeFoldersStore;
|
||||
|
||||
const items = [...folders, ...files];
|
||||
const item = items.find((o) => o.id === id && !o.fileExst); //TODO: maybe need files find and folders find, not at one function?
|
||||
if (type === FileAction.Create || type === FileAction.Rename) {
|
||||
setIsLoading(true);
|
||||
fetchFiles(selectedFolderStore.id, filter)
|
||||
fetchFiles(this.selectedFolderStore.id, filter)
|
||||
.then((data) => {
|
||||
const newItem = (item && item.id) === -1 ? null : item; //TODO: not add new folders?
|
||||
if (!selectedItem.fileExst) {
|
||||
@ -250,7 +261,8 @@ class FilesActionStore {
|
||||
};
|
||||
|
||||
onSelectItem = (item) => {
|
||||
filesStore.selected === "close" && setSelected("none");
|
||||
const { setSelection, selected, setSelected } = this.filesStore;
|
||||
selected === "close" && setSelected("none");
|
||||
setSelection([item]);
|
||||
};
|
||||
|
||||
@ -261,6 +273,12 @@ class FilesActionStore {
|
||||
conflictResolveType,
|
||||
deleteAfter
|
||||
) => {
|
||||
const { loopFilesOperations } = this.uploadDataStore;
|
||||
const {
|
||||
setSecondaryProgressBarData,
|
||||
clearSecondaryProgressData,
|
||||
} = this.uploadDataStore.secondaryProgressDataStore;
|
||||
|
||||
return copyToFolder(
|
||||
destFolderId,
|
||||
folderIds,
|
||||
@ -289,7 +307,13 @@ class FilesActionStore {
|
||||
conflictResolveType,
|
||||
deleteAfter
|
||||
) => {
|
||||
moveToFolder(
|
||||
const { loopFilesOperations } = this.uploadDataStore;
|
||||
const {
|
||||
setSecondaryProgressBarData,
|
||||
clearSecondaryProgressData,
|
||||
} = this.uploadDataStore.secondaryProgressDataStore;
|
||||
|
||||
return moveToFolder(
|
||||
destFolderId,
|
||||
folderIds,
|
||||
fileIds,
|
||||
@ -311,6 +335,11 @@ class FilesActionStore {
|
||||
};
|
||||
|
||||
deleteFileAction = (fileId, currentFolderId, translations) => {
|
||||
const {
|
||||
setSecondaryProgressBarData,
|
||||
clearSecondaryProgressData,
|
||||
} = this.uploadDataStore.secondaryProgressDataStore;
|
||||
|
||||
setSecondaryProgressBarData({
|
||||
icon: "trash",
|
||||
visible: true,
|
||||
@ -333,6 +362,11 @@ class FilesActionStore {
|
||||
};
|
||||
|
||||
deleteFolderAction = (folderId, currentFolderId, translations) => {
|
||||
const {
|
||||
setSecondaryProgressBarData,
|
||||
clearSecondaryProgressData,
|
||||
} = this.uploadDataStore.secondaryProgressDataStore;
|
||||
|
||||
setSecondaryProgressBarData({
|
||||
icon: "trash",
|
||||
visible: true,
|
||||
@ -355,8 +389,16 @@ class FilesActionStore {
|
||||
};
|
||||
|
||||
loopDeleteProgress = (id, folderId, isFolder, translations) => {
|
||||
const { filter } = filesStore;
|
||||
const { treeFolders, isRecycleBinFolder } = treeFoldersStore;
|
||||
const { filter, fetchFiles } = this.filesStore;
|
||||
const {
|
||||
treeFolders,
|
||||
isRecycleBinFolder,
|
||||
setTreeFolders,
|
||||
} = this.treeFoldersStore;
|
||||
const {
|
||||
setSecondaryProgressBarData,
|
||||
clearSecondaryProgressData,
|
||||
} = this.uploadDataStore.secondaryProgressDataStore;
|
||||
|
||||
getProgress().then((res) => {
|
||||
const deleteProgress = res.find((x) => x.id === id);
|
||||
@ -406,20 +448,28 @@ class FilesActionStore {
|
||||
};
|
||||
|
||||
lockFileAction = (id, locked) => {
|
||||
const { setFile } = this.filesStore;
|
||||
return lockFile(id, locked).then((res) => setFile(res));
|
||||
};
|
||||
|
||||
finalizeVersionAction = (id) => {
|
||||
const { fetchFiles, setIsLoading } = this.filesStore;
|
||||
|
||||
setIsLoading(true);
|
||||
|
||||
return finalizeVersion(id, 0, false)
|
||||
.then(() => {
|
||||
fetchFiles(selectedFolderStore.id, filesStore.filter);
|
||||
fetchFiles(this.selectedFolderStore.id, this.filesStore.filter);
|
||||
})
|
||||
.finally(() => setIsLoading(false));
|
||||
};
|
||||
|
||||
duplicateAction = (item, label) => {
|
||||
const {
|
||||
setSecondaryProgressBarData,
|
||||
clearSecondaryProgressData,
|
||||
} = this.uploadDataStore.secondaryProgressDataStore;
|
||||
|
||||
const folderIds = [];
|
||||
const fileIds = [];
|
||||
item.fileExst ? fileIds.push(item.id) : folderIds.push(item.id);
|
||||
@ -435,7 +485,7 @@ class FilesActionStore {
|
||||
});
|
||||
|
||||
return this.copyToAction(
|
||||
selectedFolderStore.id,
|
||||
this.selectedFolderStore.id,
|
||||
folderIds,
|
||||
fileIds,
|
||||
conflictResolveType,
|
||||
@ -444,6 +494,13 @@ class FilesActionStore {
|
||||
};
|
||||
|
||||
setFavoriteAction = (action, id) => {
|
||||
const {
|
||||
markItemAsFavorite,
|
||||
removeItemFromFavorite,
|
||||
fetchFavoritesFolder,
|
||||
getFileInfo,
|
||||
setSelected,
|
||||
} = this.filesStore;
|
||||
//let data = selection.map(item => item.id)
|
||||
switch (action) {
|
||||
case "mark":
|
||||
@ -452,8 +509,8 @@ class FilesActionStore {
|
||||
case "remove":
|
||||
return removeItemFromFavorite([id])
|
||||
.then(() => {
|
||||
return treeFoldersStore.isFavoritesFolder
|
||||
? fetchFavoritesFolder(selectedFolderStore.id)
|
||||
return this.treeFoldersStore.isFavoritesFolder
|
||||
? fetchFavoritesFolder(this.selectedFolderStore.id)
|
||||
: getFileInfo(id);
|
||||
})
|
||||
.then(() => setSelected("close"));
|
||||
@ -463,7 +520,8 @@ class FilesActionStore {
|
||||
};
|
||||
|
||||
selectRowAction = (checked, file) => {
|
||||
filesStore.selected === "close" && setSelected("none");
|
||||
const { selected, setSelected, selectFile, deselectFile } = this.filesStore;
|
||||
selected === "close" && setSelected("none");
|
||||
if (checked) {
|
||||
selectFile(file);
|
||||
} else {
|
||||
@ -472,16 +530,17 @@ class FilesActionStore {
|
||||
};
|
||||
|
||||
openLocationAction = (locationId, isFolder) => {
|
||||
const locationFilter = isFolder ? filesStore.filter : null;
|
||||
const locationFilter = isFolder ? this.filesStore.filter : null;
|
||||
|
||||
return fetchFiles(locationId, locationFilter).then(() =>
|
||||
return this.filesStore.fetchFiles(locationId, locationFilter).then(() =>
|
||||
//isFolder ? null : this.selectRowAction(!checked, item)
|
||||
isFolder ? null : this.selectRowAction(false, item)
|
||||
);
|
||||
};
|
||||
|
||||
setThirdpartyInfo = (providerKey) => {
|
||||
const { providers, capabilities } = settingsStore.thirdPartyStore;
|
||||
const { setConnectDialogVisible, setConnectItem } = this.dialogsStore;
|
||||
const { providers, capabilities } = this.settingsStore.thirdPartyStore;
|
||||
const provider = providers.find((x) => x.provider_key === providerKey);
|
||||
const capabilityItem = capabilities.find((x) => x[0] === providerKey);
|
||||
const capability = {
|
||||
@ -503,9 +562,18 @@ class FilesActionStore {
|
||||
const conflictResolveType = 0; //Skip = 0, Overwrite = 1, Duplicate = 2 TODO: get from settings
|
||||
const deleteAfter = true;
|
||||
|
||||
const { selection } = filesStore;
|
||||
const { isRootFolder } = selectedFolderStore;
|
||||
const { isShareFolder, isCommonFolder } = treeFoldersStore;
|
||||
const { selection } = this.filesStore;
|
||||
const { isRootFolder } = this.selectedFolderStore;
|
||||
const { isShareFolder, isCommonFolder } = this.treeFoldersStore;
|
||||
const {
|
||||
setThirdPartyMoveDialogVisible,
|
||||
setDestFolderId,
|
||||
} = this.dialogsStore;
|
||||
|
||||
const {
|
||||
setSecondaryProgressBarData,
|
||||
clearSecondaryProgressData,
|
||||
} = this.uploadDataStore.secondaryProgressDataStore;
|
||||
|
||||
for (let item of selection) {
|
||||
if (item.providerKey && !isRootFolder) {
|
||||
@ -531,7 +599,7 @@ class FilesActionStore {
|
||||
alert: false,
|
||||
});
|
||||
|
||||
if (auth.isAdmin) {
|
||||
if (this.authStore.isAdmin) {
|
||||
if (isShareFolder) {
|
||||
this.copyToAction(
|
||||
destFolderId,
|
||||
@ -571,4 +639,4 @@ class FilesActionStore {
|
||||
};
|
||||
}
|
||||
|
||||
export default new FilesActionStore();
|
||||
export default FilesActionStore;
|
||||
|
@ -1,5 +1,4 @@
|
||||
import { makeObservable, action, observable, computed } from "mobx";
|
||||
import store from "studio/store";
|
||||
import { makeAutoObservable } from "mobx";
|
||||
import api from "@appserver/common/api";
|
||||
import {
|
||||
FolderType,
|
||||
@ -9,41 +8,32 @@ import {
|
||||
AppServerConfig,
|
||||
} from "@appserver/common/constants";
|
||||
import history from "@appserver/common/history";
|
||||
import FileActionStore from "./FileActionStore";
|
||||
import selectedFolderStore from "./SelectedFolderStore";
|
||||
import formatsStore from "./FormatsStore";
|
||||
import treeFoldersStore from "./TreeFoldersStore";
|
||||
import { createTreeFolders } from "../helpers/files-helpers";
|
||||
import config from "../../package.json";
|
||||
import { combineUrl } from "@appserver/common/utils";
|
||||
import { updateTempContent } from "@appserver/common/utils";
|
||||
|
||||
const { FilesFilter } = api;
|
||||
|
||||
const { settingsStore, userStore, isAdmin } = store.auth;
|
||||
|
||||
const {
|
||||
iconFormatsStore,
|
||||
mediaViewersFormatsStore,
|
||||
docserviceStore,
|
||||
} = formatsStore;
|
||||
const {
|
||||
isSpreadsheet,
|
||||
isPresentation,
|
||||
getFileIcon,
|
||||
getFolderIcon,
|
||||
getIcon,
|
||||
} = iconFormatsStore;
|
||||
const {
|
||||
canWebEdit,
|
||||
canWebComment,
|
||||
canWebReview,
|
||||
canFormFillingDocs,
|
||||
canWebFilterEditing,
|
||||
} = docserviceStore;
|
||||
const { setExpandedKeys, setSelectedNode } = treeFoldersStore;
|
||||
|
||||
class FilesStore {
|
||||
fileActionStore = null;
|
||||
authStore;
|
||||
settingsStore;
|
||||
userStore;
|
||||
fileActionStore;
|
||||
selectedFolderStore;
|
||||
treeFoldersStore;
|
||||
formatsStore;
|
||||
|
||||
isLoaded = false;
|
||||
isLoading = false;
|
||||
viewAs = "row";
|
||||
dragging = false;
|
||||
privacyInstructions = "https://www.onlyoffice.com/private-rooms.aspx";
|
||||
isInit = false;
|
||||
|
||||
tooltipPageX = 0;
|
||||
tooltipPageY = 0;
|
||||
startDrag = false;
|
||||
|
||||
firstLoad = true;
|
||||
files = [];
|
||||
@ -53,65 +43,119 @@ class FilesStore {
|
||||
filter = FilesFilter.getDefault(); //TODO: FILTER
|
||||
newRowItems = [];
|
||||
|
||||
constructor() {
|
||||
makeObservable(this, {
|
||||
fileActionStore: observable,
|
||||
constructor(
|
||||
authStore,
|
||||
settingsStore,
|
||||
userStore,
|
||||
fileActionStore,
|
||||
selectedFolderStore,
|
||||
treeFoldersStore,
|
||||
formatsStore
|
||||
) {
|
||||
const pathname = window.location.pathname.toLowerCase();
|
||||
this.isEditor = pathname.indexOf("doceditor") !== -1;
|
||||
|
||||
firstLoad: observable,
|
||||
files: observable,
|
||||
folders: observable,
|
||||
selected: observable,
|
||||
filter: observable, //TODO: FILTER
|
||||
selection: observable,
|
||||
newRowItems: observable,
|
||||
|
||||
filesList: computed,
|
||||
sortedFiles: computed,
|
||||
canCreate: computed,
|
||||
isHeaderVisible: computed,
|
||||
isHeaderIndeterminate: computed,
|
||||
isHeaderChecked: computed,
|
||||
userAccess: computed,
|
||||
isAccessedSelected: computed,
|
||||
isOnlyFoldersSelected: computed,
|
||||
isThirdPartySelection: computed,
|
||||
isWebEditSelected: computed,
|
||||
selectionTitle: computed,
|
||||
currentFilesCount: computed,
|
||||
|
||||
canShare: computed,
|
||||
|
||||
setFirstLoad: action,
|
||||
setFiles: action,
|
||||
setFolders: action,
|
||||
setSelected: action,
|
||||
setFilesFilter: action, //TODO: FILTER
|
||||
setSelection: action,
|
||||
setNewRowItems: action,
|
||||
setFilesOwner: action,
|
||||
fetchFiles: action,
|
||||
selectFile: action,
|
||||
deselectFile: action,
|
||||
addFileToRecentlyViewed: action,
|
||||
createFile: action,
|
||||
createFolder: action,
|
||||
updateFile: action,
|
||||
getAccessOption: action,
|
||||
getExternalAccessOption: action,
|
||||
setSelections: action,
|
||||
getShareUsers: action,
|
||||
setShareFiles: action,
|
||||
markItemAsFavorite: action,
|
||||
removeItemFromFavorite: action,
|
||||
fetchFavoritesFolder: action,
|
||||
getFileInfo: action,
|
||||
setFolder: action,
|
||||
setFile: action,
|
||||
});
|
||||
|
||||
this.fileActionStore = new FileActionStore();
|
||||
makeAutoObservable(this);
|
||||
this.authStore = authStore;
|
||||
this.settingsStore = settingsStore;
|
||||
this.userStore = userStore;
|
||||
this.fileActionStore = fileActionStore;
|
||||
this.selectedFolderStore = selectedFolderStore;
|
||||
this.treeFoldersStore = treeFoldersStore;
|
||||
this.formatsStore = formatsStore;
|
||||
}
|
||||
|
||||
setIsLoaded = (isLoaded) => {
|
||||
this.isLoaded = isLoaded;
|
||||
};
|
||||
|
||||
setViewAs = (viewAs) => {
|
||||
this.viewAs = viewAs;
|
||||
};
|
||||
|
||||
setDragging = (dragging) => {
|
||||
this.dragging = dragging;
|
||||
};
|
||||
|
||||
setIsLoading = (isLoading) => {
|
||||
this.isLoading = isLoading;
|
||||
};
|
||||
|
||||
setTooltipPosition = (tooltipPageX, tooltipPageY) => {
|
||||
this.tooltipPageX = tooltipPageX;
|
||||
this.tooltipPageY = tooltipPageY;
|
||||
};
|
||||
|
||||
setStartDrag = (startDrag) => {
|
||||
this.startDrag = startDrag;
|
||||
};
|
||||
|
||||
get tooltipValue() {
|
||||
if (!this.dragging) return null;
|
||||
|
||||
const selectionLength = this.selection.length;
|
||||
const elementTitle = selectionLength && this.selection[0].title;
|
||||
const singleElement = selectionLength === 1;
|
||||
const filesCount = singleElement ? elementTitle : selectionLength;
|
||||
const { isShareFolder, isCommonFolder } = this.treeFoldersStore;
|
||||
|
||||
let operationName;
|
||||
|
||||
if (this.authStore.isAdmin && isShareFolder) {
|
||||
operationName = "copy";
|
||||
} else if (!this.authStore.isAdmin && (isShareFolder || isCommonFolder)) {
|
||||
operationName = "copy";
|
||||
} else {
|
||||
operationName = "move";
|
||||
}
|
||||
|
||||
return operationName === "copy"
|
||||
? singleElement
|
||||
? { label: "TooltipElementCopyMessage", filesCount }
|
||||
: { label: "TooltipElementsCopyMessage", filesCount }
|
||||
: singleElement
|
||||
? { label: "TooltipElementMoveMessage", filesCount }
|
||||
: { label: "TooltipElementsMoveMessage", filesCount };
|
||||
}
|
||||
|
||||
initFiles = () => {
|
||||
if (this.isInit) return;
|
||||
this.isInit = true;
|
||||
|
||||
const { isAuthenticated } = this.authStore;
|
||||
const {
|
||||
getPortalCultures,
|
||||
isDesktopClient,
|
||||
getIsEncryptionSupport,
|
||||
getEncryptionKeys,
|
||||
setModuleInfo,
|
||||
} = this.settingsStore;
|
||||
|
||||
setModuleInfo(config.homepage, config.id);
|
||||
|
||||
const requests = [];
|
||||
|
||||
updateTempContent();
|
||||
if (!isAuthenticated) {
|
||||
return this.setIsLoaded(true);
|
||||
} else {
|
||||
updateTempContent(isAuthenticated);
|
||||
}
|
||||
|
||||
if (!this.isEditor) {
|
||||
requests.push(
|
||||
getPortalCultures(),
|
||||
this.treeFoldersStore.fetchTreeFolders()
|
||||
);
|
||||
|
||||
if (isDesktopClient) {
|
||||
requests.push(getIsEncryptionSupport(), getEncryptionKeys());
|
||||
}
|
||||
}
|
||||
|
||||
return Promise.all(requests);
|
||||
};
|
||||
|
||||
setFirstLoad = (firstLoad) => {
|
||||
this.firstLoad = firstLoad;
|
||||
};
|
||||
@ -214,11 +258,16 @@ class FilesStore {
|
||||
fetchFiles = (folderId, filter, clearFilter = true) => {
|
||||
const filterData = filter ? filter.clone() : FilesFilter.getDefault();
|
||||
filterData.folder = folderId;
|
||||
const { privacyFolder, expandedKeys } = treeFoldersStore;
|
||||
const {
|
||||
privacyFolder,
|
||||
expandedKeys,
|
||||
setExpandedKeys,
|
||||
setSelectedNode,
|
||||
} = this.treeFoldersStore;
|
||||
setSelectedNode([folderId + ""]);
|
||||
|
||||
if (privacyFolder && privacyFolder.id === +folderId) {
|
||||
if (!store.auth.settingsStore.isEncryptionSupport) {
|
||||
if (!this.settingsStore.isEncryptionSupport) {
|
||||
const newExpandedKeys = createTreeFolders(
|
||||
privacyFolder.pathParts,
|
||||
expandedKeys
|
||||
@ -232,7 +281,7 @@ class FilesStore {
|
||||
this.fileActionStore.setAction({ type: null });
|
||||
this.setSelected("close");
|
||||
|
||||
selectedFolderStore.setSelectedFolder({
|
||||
this.selectedFolderStore.setSelectedFolder({
|
||||
folders: [],
|
||||
...privacyFolder,
|
||||
pathParts: privacyFolder.pathParts,
|
||||
@ -252,12 +301,12 @@ class FilesStore {
|
||||
filterData.total = data.total;
|
||||
this.setFilesFilter(filterData); //TODO: FILTER
|
||||
this.setFolders(
|
||||
isPrivacyFolder && !store.auth.settingsStore.isEncryptionSupport
|
||||
isPrivacyFolder && !this.settingsStore.isEncryptionSupport
|
||||
? []
|
||||
: data.folders
|
||||
);
|
||||
this.setFiles(
|
||||
isPrivacyFolder && !store.auth.settingsStore.isEncryptionSupport
|
||||
isPrivacyFolder && !this.settingsStore.isEncryptionSupport
|
||||
? []
|
||||
: data.files
|
||||
);
|
||||
@ -266,7 +315,7 @@ class FilesStore {
|
||||
this.setSelected("close");
|
||||
}
|
||||
|
||||
selectedFolderStore.setSelectedFolder({
|
||||
this.selectedFolderStore.setSelectedFolder({
|
||||
folders: data.folders,
|
||||
...data.current,
|
||||
pathParts: data.pathParts,
|
||||
@ -274,7 +323,7 @@ class FilesStore {
|
||||
});
|
||||
|
||||
const selectedFolder = {
|
||||
selectedFolder: { ...selectedFolderStore },
|
||||
selectedFolder: { ...this.selectedFolderStore },
|
||||
};
|
||||
return Promise.resolve(selectedFolder);
|
||||
});
|
||||
@ -303,13 +352,14 @@ class FilesStore {
|
||||
|
||||
getFilesContextOptions = (item, canOpenPlayer) => {
|
||||
const options = [];
|
||||
const isVisitor = (userStore.user && userStore.user.isVisitor) || false;
|
||||
const isVisitor =
|
||||
(this.userStore.user && this.userStore.user.isVisitor) || false;
|
||||
|
||||
const isFile = !!item.fileExst;
|
||||
const isFavorite = item.fileStatus === 32;
|
||||
const isFullAccess = item.access < 2;
|
||||
const isThirdPartyFolder =
|
||||
item.providerKey && selectedFolderStore.isRootFolder;
|
||||
item.providerKey && this.selectedFolderStore.isRootFolder;
|
||||
|
||||
if (item.id <= 0) return [];
|
||||
|
||||
@ -317,7 +367,7 @@ class FilesStore {
|
||||
isRecycleBinFolder,
|
||||
isPrivacyFolder,
|
||||
isRecentFolder,
|
||||
} = treeFoldersStore;
|
||||
} = this.treeFoldersStore;
|
||||
|
||||
if (isRecycleBinFolder) {
|
||||
options.push("download");
|
||||
@ -418,7 +468,7 @@ class FilesStore {
|
||||
};
|
||||
|
||||
addFileToRecentlyViewed = (fileId) => {
|
||||
if (treeFoldersStore.isPrivacyFolder) return Promise.resolve();
|
||||
if (this.treeFoldersStore.isPrivacyFolder) return Promise.resolve();
|
||||
return api.files.addFileToRecentlyViewed(fileId);
|
||||
};
|
||||
|
||||
@ -455,7 +505,7 @@ class FilesStore {
|
||||
};
|
||||
|
||||
getFilesCount = () => {
|
||||
const { filesCount, foldersCount } = selectedFolderStore;
|
||||
const { filesCount, foldersCount } = this.selectedFolderStore;
|
||||
return filesCount + this.folders ? this.folders.length : foldersCount;
|
||||
};
|
||||
|
||||
@ -466,15 +516,16 @@ class FilesStore {
|
||||
};
|
||||
|
||||
canShareOwnerChange = (item) => {
|
||||
const userId = userStore.user.id;
|
||||
const userId = this.userStore.user.id;
|
||||
const isCommonFolder =
|
||||
treeFoldersStore.commonFolder &&
|
||||
selectedFolderStore.pathParts &&
|
||||
treeFoldersStore.commonFolder.id === selectedFolderStore.pathParts[0];
|
||||
this.treeFoldersStore.commonFolder &&
|
||||
this.selectedFolderStore.pathParts &&
|
||||
this.treeFoldersStore.commonFolder.id ===
|
||||
this.selectedFolderStore.pathParts[0];
|
||||
|
||||
if (item.providerKey || !isCommonFolder) {
|
||||
return false;
|
||||
} else if (isAdmin) {
|
||||
} else if (this.authStore.isAdmin) {
|
||||
return true;
|
||||
} else if (item.createdBy.id === userId) {
|
||||
return true;
|
||||
@ -484,8 +535,9 @@ class FilesStore {
|
||||
};
|
||||
|
||||
get canShare() {
|
||||
const folderType = selectedFolderStore.rootFolderType;
|
||||
const isVisitor = (userStore.user && userStore.user.isVisitor) || false;
|
||||
const folderType = this.selectedFolderStore.rootFolderType;
|
||||
const isVisitor =
|
||||
(this.userStore.user && this.userStore.user.isVisitor) || false;
|
||||
|
||||
if (isVisitor) {
|
||||
return false;
|
||||
@ -497,7 +549,7 @@ class FilesStore {
|
||||
case FolderType.SHARE:
|
||||
return false;
|
||||
case FolderType.COMMON:
|
||||
return isAdmin;
|
||||
return this.authStore.isAdmin;
|
||||
case FolderType.TRASH:
|
||||
return false;
|
||||
case FolderType.Favorites:
|
||||
@ -514,10 +566,14 @@ class FilesStore {
|
||||
get currentFilesCount() {
|
||||
const serviceFilesCount = this.getServiceFilesCount();
|
||||
const filesCount = this.getFilesCount();
|
||||
return selectedFolderStore.providerItem ? serviceFilesCount : filesCount;
|
||||
return this.selectedFolderStore.providerItem
|
||||
? serviceFilesCount
|
||||
: filesCount;
|
||||
}
|
||||
|
||||
get iconOfDraggedFile() {
|
||||
const { getIcon } = this.formatsStore.iconFormatsStore;
|
||||
|
||||
if (this.selection.length === 1) {
|
||||
const icon = getIcon(
|
||||
24,
|
||||
@ -547,19 +603,21 @@ class FilesStore {
|
||||
}
|
||||
|
||||
get canCreate() {
|
||||
switch (selectedFolderStore.rootFolderType) {
|
||||
switch (this.selectedFolderStore.rootFolderType) {
|
||||
case FolderType.USER:
|
||||
return true;
|
||||
case FolderType.SHARE:
|
||||
const canCreateInSharedFolder = selectedFolderStore.access === 1;
|
||||
return !selectedFolderStore.isRootFolder && canCreateInSharedFolder;
|
||||
const canCreateInSharedFolder = this.selectedFolderStore.access === 1;
|
||||
return (
|
||||
!this.selectedFolderStore.isRootFolder && canCreateInSharedFolder
|
||||
);
|
||||
case FolderType.Privacy:
|
||||
return (
|
||||
store.auth.settingsStore.isDesktopClient &&
|
||||
store.auth.settingsStore.isEncryptionSupport
|
||||
this.settingsStore.isDesktopClient &&
|
||||
this.settingsStore.isEncryptionSupport
|
||||
);
|
||||
case FolderType.COMMON:
|
||||
return isAdmin;
|
||||
return this.authStore.isAdmin;
|
||||
case FolderType.TRASH:
|
||||
default:
|
||||
return false;
|
||||
@ -567,6 +625,8 @@ class FilesStore {
|
||||
}
|
||||
|
||||
onCreateAddTempItem = (items) => {
|
||||
const { getFileIcon, getFolderIcon } = this.formatsStore.iconFormatsStore;
|
||||
|
||||
if (items.length && items[0].id === -1) return; //TODO: if change media collection from state remove this;
|
||||
const icon = this.fileActionStore.extension
|
||||
? getFileIcon(`.${this.fileActionStore.extension}`, 24)
|
||||
@ -575,13 +635,15 @@ class FilesStore {
|
||||
items.unshift({
|
||||
id: -1,
|
||||
title: "",
|
||||
parentId: selectedFolderStore.id,
|
||||
parentId: this.selectedFolderStore.id,
|
||||
fileExst: this.fileActionStore.extension,
|
||||
icon,
|
||||
});
|
||||
};
|
||||
|
||||
get filesList() {
|
||||
const { mediaViewersFormatsStore, iconFormatsStore } = this.formatsStore;
|
||||
const { getIcon } = iconFormatsStore;
|
||||
//return [...this.folders, ...this.files];
|
||||
|
||||
const items = [...this.folders, ...this.files];
|
||||
@ -674,6 +736,12 @@ class FilesStore {
|
||||
}
|
||||
|
||||
get sortedFiles() {
|
||||
const {
|
||||
isSpreadsheet,
|
||||
isPresentation,
|
||||
} = this.formatsStore.iconFormatsStore;
|
||||
const { canWebEdit } = this.formatsStore.docserviceStore;
|
||||
|
||||
const formatKeys = Object.freeze({
|
||||
OriginalFormat: 0,
|
||||
});
|
||||
@ -708,14 +776,14 @@ class FilesStore {
|
||||
}
|
||||
|
||||
get userAccess() {
|
||||
switch (selectedFolderStore.rootFolderType) {
|
||||
switch (this.selectedFolderStore.rootFolderType) {
|
||||
case FolderType.USER:
|
||||
return true;
|
||||
case FolderType.SHARE:
|
||||
return false;
|
||||
case FolderType.COMMON:
|
||||
return (
|
||||
isAdmin ||
|
||||
this.authStore.isAdmin ||
|
||||
this.selection.some((x) => x.access === 0 || x.access === 1)
|
||||
);
|
||||
case FolderType.Privacy:
|
||||
@ -731,7 +799,7 @@ class FilesStore {
|
||||
return (
|
||||
(this.selection.length &&
|
||||
this.selection.every((x) => x.access === 1 || x.access === 0)) ||
|
||||
(isAdmin && this.selection.length)
|
||||
(this.authStore.isAdmin && this.selection.length)
|
||||
);
|
||||
}
|
||||
|
||||
@ -741,15 +809,15 @@ class FilesStore {
|
||||
|
||||
get isThirdPartySelection() {
|
||||
const withProvider = this.selection.find((x) => !x.providerKey);
|
||||
return !withProvider && selectedFolderStore.isRootFolder;
|
||||
return !withProvider && this.selectedFolderStore.isRootFolder;
|
||||
}
|
||||
|
||||
get isWebEditSelected() {
|
||||
const { editedDocs } = this.formatsStore.docserviceStore;
|
||||
|
||||
return this.selection.some((selected) => {
|
||||
if (selected.isFolder === true || !selected.fileExst) return false;
|
||||
return docserviceStore.editedDocs.find(
|
||||
(format) => selected.fileExst === format
|
||||
);
|
||||
return editedDocs.find((format) => selected.fileExst === format);
|
||||
});
|
||||
}
|
||||
|
||||
@ -759,24 +827,37 @@ class FilesStore {
|
||||
}
|
||||
|
||||
getOptions = (selection, externalAccess = false) => {
|
||||
const webEdit = selection.find((x) => canWebEdit(x.fileExst));
|
||||
const webComment = selection.find((x) => canWebComment(x.fileExst));
|
||||
const webReview = selection.find((x) => canWebReview(x.fileExst));
|
||||
const formFillingDocs = selection.find((x) =>
|
||||
canFormFillingDocs(x.fileExst)
|
||||
);
|
||||
const webFilter = selection.find((x) => canWebFilterEditing(x.fileExst));
|
||||
const {
|
||||
canWebEdit,
|
||||
canWebComment,
|
||||
canWebReview,
|
||||
canFormFillingDocs,
|
||||
canWebFilterEditing,
|
||||
} = this.formatsStore.docserviceStore;
|
||||
|
||||
let AccessOptions = [];
|
||||
|
||||
if (webEdit || !externalAccess) AccessOptions.push("FullAccess");
|
||||
|
||||
AccessOptions.push("ReadOnly", "DenyAccess");
|
||||
|
||||
const webEdit = selection.find((x) => canWebEdit(x.fileExst));
|
||||
|
||||
const webComment = selection.find((x) => canWebComment(x.fileExst));
|
||||
|
||||
const webReview = selection.find((x) => canWebReview(x.fileExst));
|
||||
|
||||
const formFillingDocs = selection.find((x) =>
|
||||
canFormFillingDocs(x.fileExst)
|
||||
);
|
||||
|
||||
const webFilter = selection.find((x) => canWebFilterEditing(x.fileExst));
|
||||
|
||||
if (webEdit || !externalAccess) AccessOptions.push("FullAccess");
|
||||
|
||||
if (webComment) AccessOptions.push("Comment");
|
||||
if (webReview) AccessOptions.push("Review");
|
||||
if (formFillingDocs) AccessOptions.push("FormFilling");
|
||||
if (webFilter) AccessOptions.push("FilterEditing");
|
||||
|
||||
return AccessOptions;
|
||||
};
|
||||
|
||||
@ -958,7 +1039,7 @@ class FilesStore {
|
||||
this.setFolders(favoritesFolder.folders);
|
||||
this.setFiles(favoritesFolder.files);
|
||||
|
||||
selectedFolderStore.setSelectedFolder({
|
||||
this.selectedFolderStore.setSelectedFolder({
|
||||
folders: favoritesFolder.folders,
|
||||
...favoritesFolder.current,
|
||||
pathParts: favoritesFolder.pathParts,
|
||||
@ -1002,4 +1083,4 @@ class FilesStore {
|
||||
};
|
||||
}
|
||||
|
||||
export default new FilesStore();
|
||||
export default FilesStore;
|
||||
|
@ -1,24 +1,16 @@
|
||||
import { makeObservable, observable } from "mobx";
|
||||
import IconFormatsStore from "./IconFormatsStore";
|
||||
import MediaViewersFormatsStore from "./MediaViewersFormatsStore";
|
||||
import DocserviceStore from "./DocserviceStore";
|
||||
import { makeAutoObservable } from "mobx";
|
||||
|
||||
class FormatsStore {
|
||||
iconFormatsStore = null;
|
||||
mediaViewersFormatsStore = null;
|
||||
docserviceStore = null;
|
||||
iconFormatsStore;
|
||||
mediaViewersFormatsStore;
|
||||
docserviceStore;
|
||||
|
||||
constructor() {
|
||||
makeObservable(this, {
|
||||
iconFormatsStore: observable,
|
||||
mediaViewersFormatsStore: observable,
|
||||
docserviceStore: observable,
|
||||
});
|
||||
|
||||
this.iconFormatsStore = new IconFormatsStore();
|
||||
this.mediaViewersFormatsStore = new MediaViewersFormatsStore();
|
||||
this.docserviceStore = new DocserviceStore();
|
||||
constructor(iconFormatsStore, mediaViewersFormatsStore, docserviceStore) {
|
||||
makeAutoObservable(this);
|
||||
this.iconFormatsStore = iconFormatsStore;
|
||||
this.mediaViewersFormatsStore = mediaViewersFormatsStore;
|
||||
this.docserviceStore = docserviceStore;
|
||||
}
|
||||
}
|
||||
|
||||
export default new FormatsStore();
|
||||
export default FormatsStore;
|
||||
|
@ -395,4 +395,4 @@ class IconFormatsStore {
|
||||
};
|
||||
}
|
||||
|
||||
export default IconFormatsStore;
|
||||
export default new IconFormatsStore();
|
||||
|
@ -1,12 +1,14 @@
|
||||
import { makeAutoObservable } from "mobx";
|
||||
import filesStore from "./FilesStore";
|
||||
|
||||
class MediaViewerDataStore {
|
||||
filesStore;
|
||||
|
||||
id = null;
|
||||
visible = false;
|
||||
|
||||
constructor() {
|
||||
constructor(filesStore) {
|
||||
makeAutoObservable(this);
|
||||
this.filesStore = filesStore;
|
||||
}
|
||||
|
||||
setMediaViewerData = (mediaData) => {
|
||||
@ -18,8 +20,8 @@ class MediaViewerDataStore {
|
||||
const playlist = [];
|
||||
let id = 0;
|
||||
|
||||
if (filesStore.filesList) {
|
||||
filesStore.filesList.forEach((file) => {
|
||||
if (this.filesStore.filesList) {
|
||||
this.filesStore.filesList.forEach((file) => {
|
||||
if (file.canOpenPlayer) {
|
||||
playlist.push({
|
||||
id: id,
|
||||
@ -35,4 +37,4 @@ class MediaViewerDataStore {
|
||||
}
|
||||
}
|
||||
|
||||
export default new MediaViewerDataStore();
|
||||
export default MediaViewerDataStore;
|
||||
|
@ -52,4 +52,4 @@ class MediaViewersFormatsStore {
|
||||
};
|
||||
}
|
||||
|
||||
export default MediaViewersFormatsStore;
|
||||
export default new MediaViewersFormatsStore();
|
||||
|
@ -1,10 +1,9 @@
|
||||
import { makeAutoObservable } from "mobx";
|
||||
import api from "@appserver/common/api";
|
||||
import axios from "axios";
|
||||
import ThirdPartyStore from "./ThirdPartyStore";
|
||||
|
||||
class SettingsStore {
|
||||
thirdPartyStore = null;
|
||||
thirdPartyStore;
|
||||
|
||||
isErrorSettings = null;
|
||||
expandedSetting = null;
|
||||
@ -18,10 +17,10 @@ class SettingsStore {
|
||||
|
||||
settingsIsLoaded = false;
|
||||
|
||||
constructor() {
|
||||
constructor(thirdPartyStore) {
|
||||
makeAutoObservable(this);
|
||||
|
||||
this.thirdPartyStore = new ThirdPartyStore();
|
||||
this.thirdPartyStore = thirdPartyStore;
|
||||
}
|
||||
|
||||
setIsLoaded = (isLoaded) => {
|
||||
@ -116,4 +115,4 @@ class SettingsStore {
|
||||
api.files.forceSave(data).then((res) => this.setFilesSetting(setting, res));
|
||||
}
|
||||
|
||||
export default new SettingsStore();
|
||||
export default SettingsStore;
|
||||
|
@ -167,4 +167,4 @@ class ThirdPartyStore {
|
||||
}
|
||||
}
|
||||
|
||||
export default ThirdPartyStore;
|
||||
export default new ThirdPartyStore();
|
||||
|
@ -1,43 +1,17 @@
|
||||
import { makeObservable, observable, computed, action } from "mobx";
|
||||
import { makeAutoObservable } from "mobx";
|
||||
import { getFoldersTree } from "@appserver/common/api/files";
|
||||
import { FolderType } from "@appserver/common/constants";
|
||||
import selectedFolderStore from "./SelectedFolderStore";
|
||||
|
||||
class TreeFoldersStore {
|
||||
selectedFolderStore;
|
||||
|
||||
treeFolders = [];
|
||||
selectedTreeNode = [];
|
||||
expandedKeys = [];
|
||||
|
||||
constructor() {
|
||||
makeObservable(this, {
|
||||
treeFolders: observable,
|
||||
selectedTreeNode: observable,
|
||||
expandedKeys: observable,
|
||||
|
||||
myFolderId: computed,
|
||||
commonFolderId: computed,
|
||||
|
||||
myFolder: computed,
|
||||
shareFolder: computed,
|
||||
favoritesFolder: computed,
|
||||
recentFolder: computed,
|
||||
privacyFolder: computed,
|
||||
commonFolder: computed,
|
||||
recycleBinFolder: computed,
|
||||
|
||||
isMyFolder: computed,
|
||||
isShareFolder: computed,
|
||||
isFavoritesFolder: computed,
|
||||
isRecentFolder: computed,
|
||||
isPrivacyFolder: computed,
|
||||
isCommonFolder: computed,
|
||||
isRecycleBinFolder: computed,
|
||||
|
||||
fetchTreeFolders: action,
|
||||
setTreeFolders: action,
|
||||
setExpandedKeys: action,
|
||||
setSelectedNode: action,
|
||||
});
|
||||
constructor(selectedFolderStore) {
|
||||
makeAutoObservable(this);
|
||||
this.selectedFolderStore = selectedFolderStore;
|
||||
}
|
||||
|
||||
fetchTreeFolders = async () => {
|
||||
@ -103,38 +77,46 @@ class TreeFoldersStore {
|
||||
}
|
||||
|
||||
get isMyFolder() {
|
||||
return this.myFolder && this.myFolder.id === selectedFolderStore.id;
|
||||
return this.myFolder && this.myFolder.id === this.selectedFolderStore.id;
|
||||
}
|
||||
|
||||
get isShareFolder() {
|
||||
return this.shareFolder && this.shareFolder.id === selectedFolderStore.id;
|
||||
return (
|
||||
this.shareFolder && this.shareFolder.id === this.selectedFolderStore.id
|
||||
);
|
||||
}
|
||||
|
||||
get isFavoritesFolder() {
|
||||
return (
|
||||
this.favoritesFolder && selectedFolderStore.id === this.favoritesFolder.id
|
||||
this.favoritesFolder &&
|
||||
this.selectedFolderStore.id === this.favoritesFolder.id
|
||||
);
|
||||
}
|
||||
|
||||
get isRecentFolder() {
|
||||
return this.recentFolder && selectedFolderStore.id === this.recentFolder.id;
|
||||
return (
|
||||
this.recentFolder && this.selectedFolderStore.id === this.recentFolder.id
|
||||
);
|
||||
}
|
||||
|
||||
get isPrivacyFolder() {
|
||||
return (
|
||||
this.privacyFolder &&
|
||||
this.privacyFolder.rootFolderType === selectedFolderStore.rootFolderType
|
||||
this.privacyFolder.rootFolderType ===
|
||||
this.selectedFolderStore.rootFolderType
|
||||
);
|
||||
}
|
||||
|
||||
get isCommonFolder() {
|
||||
return this.commonFolder && this.commonFolder.id === selectedFolderStore.id;
|
||||
return (
|
||||
this.commonFolder && this.commonFolder.id === this.selectedFolderStore.id
|
||||
);
|
||||
}
|
||||
|
||||
get isRecycleBinFolder() {
|
||||
return (
|
||||
this.recycleBinFolder &&
|
||||
selectedFolderStore.id === this.recycleBinFolder.id
|
||||
this.selectedFolderStore.id === this.recycleBinFolder.id
|
||||
);
|
||||
}
|
||||
|
||||
@ -155,4 +137,4 @@ class TreeFoldersStore {
|
||||
}
|
||||
}
|
||||
|
||||
export default new TreeFoldersStore();
|
||||
export default TreeFoldersStore;
|
||||
|
@ -1,27 +1,20 @@
|
||||
import { makeObservable, action, observable } from "mobx";
|
||||
import { makeAutoObservable } from "mobx";
|
||||
import api from "@appserver/common/api";
|
||||
import { TIMEOUT } from "../helpers/constants";
|
||||
import { loopTreeFolders } from "../helpers/files-helpers";
|
||||
import SecondaryProgressDataStore from "./SecondaryProgressDataStore";
|
||||
import PrimaryProgressDataStore from "./PrimaryProgressDataStore";
|
||||
import formatsStore from "./FormatsStore";
|
||||
import treeFoldersStore from "./TreeFoldersStore";
|
||||
import selectedFolderStore from "./SelectedFolderStore";
|
||||
import filesStore from "./FilesStore";
|
||||
import uniqueid from "lodash/uniqueId";
|
||||
import throttle from "lodash/throttle";
|
||||
import sumBy from "lodash/sumBy";
|
||||
|
||||
const { docserviceStore } = formatsStore;
|
||||
const { canConvert } = docserviceStore;
|
||||
const { setTreeFolders } = treeFoldersStore;
|
||||
const { fetchFiles } = filesStore;
|
||||
|
||||
const chunkSize = 1024 * 1023; //~0.999mb
|
||||
|
||||
class UploadDataStore {
|
||||
secondaryProgressDataStore = null;
|
||||
primaryProgressDataStore = null;
|
||||
formatsStore;
|
||||
treeFoldersStore;
|
||||
selectedFolderStore;
|
||||
filesStore;
|
||||
secondaryProgressDataStore;
|
||||
primaryProgressDataStore;
|
||||
|
||||
files = [];
|
||||
filesSize = 0;
|
||||
@ -38,37 +31,21 @@ class UploadDataStore {
|
||||
|
||||
selectedUploadFile = [];
|
||||
|
||||
constructor() {
|
||||
makeObservable(this, {
|
||||
secondaryProgressDataStore: observable,
|
||||
primaryProgressDataStore: observable,
|
||||
|
||||
files: observable,
|
||||
filesSize: observable,
|
||||
convertFiles: observable,
|
||||
convertFilesSize: observable,
|
||||
uploadStatus: observable,
|
||||
uploadToFolder: observable,
|
||||
uploadedFiles: observable,
|
||||
percent: observable,
|
||||
uploaded: observable,
|
||||
selectedUploadFile: observable,
|
||||
uploadPanelVisible: observable,
|
||||
convertDialogVisible: observable,
|
||||
|
||||
selectUploadedFile: action,
|
||||
setUploadPanelVisible: action,
|
||||
clearUploadData: action,
|
||||
cancelUpload: action,
|
||||
setUploadData: action,
|
||||
updateUploadedItem: action,
|
||||
setConvertDialogVisible: action,
|
||||
startUpload: action,
|
||||
itemOperationToFolder: action,
|
||||
});
|
||||
|
||||
this.secondaryProgressDataStore = new SecondaryProgressDataStore();
|
||||
this.primaryProgressDataStore = new PrimaryProgressDataStore();
|
||||
constructor(
|
||||
formatsStore,
|
||||
treeFoldersStore,
|
||||
selectedFolderStore,
|
||||
filesStore,
|
||||
secondaryProgressDataStore,
|
||||
primaryProgressDataStore
|
||||
) {
|
||||
makeAutoObservable(this);
|
||||
this.formatsStore = formatsStore;
|
||||
this.treeFoldersStore = treeFoldersStore;
|
||||
this.selectedFolderStore = selectedFolderStore;
|
||||
this.filesStore = filesStore;
|
||||
this.secondaryProgressDataStore = secondaryProgressDataStore;
|
||||
this.primaryProgressDataStore = primaryProgressDataStore;
|
||||
}
|
||||
|
||||
selectUploadedFile = (file) => {
|
||||
@ -306,6 +283,8 @@ class UploadDataStore {
|
||||
};
|
||||
|
||||
startUpload = (uploadFiles, folderId, t) => {
|
||||
const { canConvert } = this.formatsStore.docserviceStore;
|
||||
|
||||
let newFiles = this.files;
|
||||
let filesSize = 0;
|
||||
|
||||
@ -347,28 +326,31 @@ class UploadDataStore {
|
||||
};
|
||||
|
||||
refreshFiles = (folderId) => {
|
||||
const { setTreeFolders } = this.treeFoldersStore;
|
||||
if (
|
||||
selectedFolderStore.id === folderId &&
|
||||
this.selectedFolderStore.id === folderId &&
|
||||
window.location.pathname.indexOf("/history") === -1
|
||||
) {
|
||||
return fetchFiles(
|
||||
selectedFolderStore.id,
|
||||
filesStore.filter.clone(),
|
||||
false
|
||||
).then((data) => {
|
||||
const path = data.selectedFolder.pathParts;
|
||||
const newTreeFolders = treeFoldersStore.treeFolders;
|
||||
const folders = data.selectedFolder.folders;
|
||||
const foldersCount = data.selectedFolder.foldersCount;
|
||||
loopTreeFolders(path, newTreeFolders, folders, foldersCount);
|
||||
setTreeFolders(newTreeFolders);
|
||||
});
|
||||
return this.filesStore
|
||||
.fetchFiles(
|
||||
this.selectedFolderStore.id,
|
||||
this.filesStore.filter.clone(),
|
||||
false
|
||||
)
|
||||
.then((data) => {
|
||||
const path = data.selectedFolder.pathParts;
|
||||
const newTreeFolders = this.treeFoldersStore.treeFolders;
|
||||
const folders = data.selectedFolder.folders;
|
||||
const foldersCount = data.selectedFolder.foldersCount;
|
||||
loopTreeFolders(path, newTreeFolders, folders, foldersCount);
|
||||
setTreeFolders(newTreeFolders);
|
||||
});
|
||||
} else {
|
||||
return api.files
|
||||
.getFolder(folderId, filesStore.filter.clone())
|
||||
.getFolder(folderId, this.filesStore.filter.clone())
|
||||
.then((data) => {
|
||||
const path = data.pathParts;
|
||||
const newTreeFolders = treeFoldersStore.treeFolders;
|
||||
const newTreeFolders = this.treeFoldersStore.treeFolders;
|
||||
const folders = data.folders;
|
||||
const foldersCount = data.count;
|
||||
loopTreeFolders(path, newTreeFolders, folders, foldersCount);
|
||||
@ -675,7 +657,7 @@ class UploadDataStore {
|
||||
|
||||
loopFilesOperations = (id, destFolderId, isCopy) => {
|
||||
const label = this.secondaryProgressDataStore.label;
|
||||
const treeFolders = treeFoldersStore.treeFolders;
|
||||
const treeFolders = this.treeFoldersStore.treeFolders;
|
||||
|
||||
const {
|
||||
clearSecondaryProgressData,
|
||||
@ -713,10 +695,14 @@ class UploadDataStore {
|
||||
let foldersCount = data.current.foldersCount;
|
||||
loopTreeFolders(path, newTreeFolders, folders, foldersCount);
|
||||
|
||||
if (!isCopy || destFolderId === selectedFolderStore.id) {
|
||||
fetchFiles(selectedFolderStore.id, filesStore.filter)
|
||||
if (!isCopy || destFolderId === this.selectedFolderStore.id) {
|
||||
this.filesStore
|
||||
.fetchFiles(
|
||||
this.selectedFolderStore.id,
|
||||
this.filesStore.filter
|
||||
)
|
||||
.then((data) => {
|
||||
if (!treeFoldersStore.isRecycleBinFolder) {
|
||||
if (!this.treeFoldersStore.isRecycleBinFolder) {
|
||||
newTreeFolders = treeFolders;
|
||||
path = data.selectedFolder.pathParts.slice(0);
|
||||
folders = data.selectedFolder.folders;
|
||||
@ -727,7 +713,7 @@ class UploadDataStore {
|
||||
folders,
|
||||
foldersCount
|
||||
);
|
||||
setTreeFolders(newTreeFolders);
|
||||
this.treeFoldersStore.setTreeFolders(newTreeFolders);
|
||||
}
|
||||
})
|
||||
.finally(() => {
|
||||
@ -751,7 +737,7 @@ class UploadDataStore {
|
||||
this.secondaryProgressDataStore.clearSecondaryProgressData(),
|
||||
TIMEOUT
|
||||
);
|
||||
setTreeFolders(newTreeFolders);
|
||||
this.treeFoldersStore.setTreeFolders(newTreeFolders);
|
||||
}
|
||||
});
|
||||
}
|
||||
@ -770,4 +756,4 @@ class UploadDataStore {
|
||||
};
|
||||
}
|
||||
|
||||
export default new UploadDataStore();
|
||||
export default UploadDataStore;
|
||||
|
@ -1,4 +1,73 @@
|
||||
import store from "@appserver/common/store";
|
||||
const { moduleStore } = store.moduleStore;
|
||||
import FilesStore from "./FilesStore";
|
||||
import fileActionStore from "./FileActionStore";
|
||||
import selectedFolderStore from "./SelectedFolderStore";
|
||||
import TreeFoldersStore from "./TreeFoldersStore";
|
||||
import thirdPartyStore from "./ThirdPartyStore";
|
||||
import SettingsStore from "./SettingsStore";
|
||||
import FilesActionsStore from "./FilesActionsStore";
|
||||
import FormatsStore from "./FormatsStore";
|
||||
import iconFormatsStore from "./IconFormatsStore";
|
||||
import mediaViewersFormatsStore from "./MediaViewersFormatsStore";
|
||||
import docserviceStore from "./DocserviceStore";
|
||||
import MediaViewerDataStore from "./MediaViewerDataStore";
|
||||
import UploadDataStore from "./UploadDataStore";
|
||||
import SecondaryProgressDataStore from "./SecondaryProgressDataStore";
|
||||
import PrimaryProgressDataStore from "./PrimaryProgressDataStore";
|
||||
|
||||
export default moduleStore;
|
||||
import versionHistoryStore from "./VersionHistoryStore";
|
||||
import dialogsStore from "./DialogsStore";
|
||||
|
||||
import store from "studio/store";
|
||||
|
||||
const formatsStore = new FormatsStore(
|
||||
iconFormatsStore,
|
||||
mediaViewersFormatsStore,
|
||||
docserviceStore
|
||||
);
|
||||
const treeFoldersStore = new TreeFoldersStore(selectedFolderStore);
|
||||
const filesStore = new FilesStore(
|
||||
store.auth,
|
||||
store.auth.settingsStore,
|
||||
store.auth.userStore,
|
||||
fileActionStore,
|
||||
selectedFolderStore,
|
||||
treeFoldersStore,
|
||||
formatsStore
|
||||
);
|
||||
const settingsStore = new SettingsStore(thirdPartyStore);
|
||||
const secondaryProgressDataStore = new SecondaryProgressDataStore();
|
||||
const primaryProgressDataStore = new PrimaryProgressDataStore();
|
||||
const uploadDataStore = new UploadDataStore(
|
||||
formatsStore,
|
||||
treeFoldersStore,
|
||||
selectedFolderStore,
|
||||
filesStore,
|
||||
secondaryProgressDataStore,
|
||||
primaryProgressDataStore
|
||||
);
|
||||
const filesActionsStore = new FilesActionsStore(
|
||||
store.auth,
|
||||
uploadDataStore,
|
||||
treeFoldersStore,
|
||||
filesStore,
|
||||
selectedFolderStore,
|
||||
settingsStore,
|
||||
dialogsStore
|
||||
);
|
||||
|
||||
const mediaViewerDataStore = new MediaViewerDataStore(filesStore);
|
||||
|
||||
const stores = {
|
||||
filesStore,
|
||||
settingsStore,
|
||||
mediaViewerDataStore,
|
||||
formatsStore,
|
||||
versionHistoryStore,
|
||||
uploadDataStore,
|
||||
dialogsStore,
|
||||
treeFoldersStore,
|
||||
selectedFolderStore,
|
||||
filesActionsStore,
|
||||
};
|
||||
|
||||
export default stores;
|
||||
|
@ -144,6 +144,7 @@ var config = {
|
||||
},
|
||||
exposes: {
|
||||
"./app": "./src/Files.jsx",
|
||||
"./SharingDialog": "./src/components/panels/SharingDialog",
|
||||
},
|
||||
shared: {
|
||||
...deps,
|
||||
|
Before Width: | Height: | Size: 428 B After Width: | Height: | Size: 428 B |
Before Width: | Height: | Size: 520 B After Width: | Height: | Size: 520 B |
Before Width: | Height: | Size: 443 B After Width: | Height: | Size: 443 B |
Before Width: | Height: | Size: 608 B After Width: | Height: | Size: 608 B |
Before Width: | Height: | Size: 839 B After Width: | Height: | Size: 839 B |
Before Width: | Height: | Size: 157 B After Width: | Height: | Size: 157 B |
Before Width: | Height: | Size: 723 B After Width: | Height: | Size: 723 B |
3
web/ASC.Web.Editor/public/locales/en/Editor.json
Normal file
@ -0,0 +1,3 @@
|
||||
{
|
||||
"FileLocation": "Open file location"
|
||||
}
|
3
web/ASC.Web.Editor/public/locales/ru/Editor.json
Normal file
@ -0,0 +1,3 @@
|
||||
{
|
||||
"FileLocation": "Открыть расположение файла"
|
||||
}
|
@ -1,6 +1,9 @@
|
||||
import React, { useEffect, useState } from "react";
|
||||
|
||||
import Toast from "@appserver/components/toast";
|
||||
import toastr from "@appserver/components/toast/toastr";
|
||||
import toastr from "studio/toastr";
|
||||
import { toast } from "react-toastify";
|
||||
|
||||
import Box from "@appserver/components/box";
|
||||
import { regDesktop } from "@appserver/common/desktop";
|
||||
import Loaders from "@appserver/common/components/Loaders";
|
||||
@ -16,21 +19,34 @@ import {
|
||||
openEdit,
|
||||
setEncryptionKeys,
|
||||
getEncryptionAccess,
|
||||
getFileInfo,
|
||||
} from "@appserver/common/api/files";
|
||||
import { checkIsAuthenticated } from "@appserver/common/api/user";
|
||||
import { getUser } from "@appserver/common/api/people";
|
||||
import FilesFilter from "@appserver/common/api/files/filter";
|
||||
|
||||
import throttle from "lodash/throttle";
|
||||
import { isIOS, deviceType } from "react-device-detect";
|
||||
import { homepage } from "../package.json";
|
||||
|
||||
import "./custom.scss";
|
||||
import { AppServerConfig } from "@appserver/common/constants";
|
||||
import SharingDialog from "files/SharingDialog";
|
||||
|
||||
import i18n from "./i18n";
|
||||
|
||||
let documentIsReady = false;
|
||||
|
||||
let docTitle = null;
|
||||
let fileType = null;
|
||||
|
||||
let config;
|
||||
let docSaved = null;
|
||||
let docEditor;
|
||||
let fileInfo;
|
||||
const url = window.location.href;
|
||||
const filesUrl = url.substring(0, url.indexOf("/doceditor"));
|
||||
|
||||
toast.configure();
|
||||
|
||||
const Editor = () => {
|
||||
const urlParams = getObjectByLocation(window.location);
|
||||
@ -48,6 +64,18 @@ const Editor = () => {
|
||||
500
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
init();
|
||||
}, []);
|
||||
|
||||
const updateUsersRightsList = () => {
|
||||
SharingDialog.getSharingSettings(fileId).then((sharingSettings) => {
|
||||
docEditor.setSharingSettings({
|
||||
sharingSettings,
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
const init = async () => {
|
||||
try {
|
||||
if (!fileId) return;
|
||||
@ -72,8 +100,9 @@ const Editor = () => {
|
||||
setIsAuthenticated(success);
|
||||
}
|
||||
}
|
||||
fileInfo = await getFileInfo(fileId);
|
||||
|
||||
const config = await openEdit(fileId, doc);
|
||||
config = await openEdit(fileId, doc);
|
||||
|
||||
if (isDesktop) {
|
||||
const isEncryption =
|
||||
@ -110,6 +139,18 @@ const Editor = () => {
|
||||
);
|
||||
}
|
||||
|
||||
if (
|
||||
config &&
|
||||
config.document.permissions.edit &&
|
||||
config.document.permissions.modifyFilter
|
||||
) {
|
||||
const sharingSettings = await SharingDialog.getSharingSettings(fileId);
|
||||
config.document.info = {
|
||||
...config.document.info,
|
||||
sharingSettings,
|
||||
};
|
||||
}
|
||||
|
||||
setIsLoading(false);
|
||||
|
||||
loadDocApi(docApiUrl, () => onLoad(config));
|
||||
@ -124,10 +165,6 @@ const Editor = () => {
|
||||
}
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
init();
|
||||
}, []);
|
||||
|
||||
const isIPad = () => {
|
||||
return isIOS && deviceType === "tablet";
|
||||
};
|
||||
@ -195,6 +232,7 @@ const Editor = () => {
|
||||
|
||||
const onLoad = (config) => {
|
||||
console.log("Editor config: ", config);
|
||||
|
||||
try {
|
||||
console.log(config);
|
||||
|
||||
@ -208,6 +246,20 @@ const Editor = () => {
|
||||
config.type = "mobile";
|
||||
}
|
||||
|
||||
const filterObj = FilesFilter.getDefault();
|
||||
filterObj.folder = fileInfo.folderId;
|
||||
const urlFilter = filterObj.toUrlParams();
|
||||
|
||||
config.editorConfig.customization = {
|
||||
...config.editorConfig.customization,
|
||||
goback: {
|
||||
blank: true,
|
||||
requestClose: false,
|
||||
text: i18n.t("FileLocation"),
|
||||
url: `${combineUrl(filesUrl, `/filter?${urlFilter}`)}`,
|
||||
},
|
||||
};
|
||||
|
||||
const events = {
|
||||
events: {
|
||||
onAppReady: onSDKAppReady,
|
||||
@ -217,6 +269,10 @@ const Editor = () => {
|
||||
onInfo: onSDKInfo,
|
||||
onWarning: onSDKWarning,
|
||||
onError: onSDKError,
|
||||
...(config.document.permissions.edit &&
|
||||
config.document.permissions.modifyFilter && {
|
||||
onRequestSharingSettings: onSDKRequestSharingSettings,
|
||||
}),
|
||||
},
|
||||
};
|
||||
|
||||
@ -224,9 +280,7 @@ const Editor = () => {
|
||||
|
||||
if (!window.DocsAPI) throw new Error("DocsAPI is not defined");
|
||||
|
||||
//hideLoader();
|
||||
|
||||
window.DocsAPI.DocEditor("editor", newConfig);
|
||||
docEditor = window.DocsAPI.DocEditor("editor", newConfig);
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
toastr.error(error.message, null, 0, true);
|
||||
@ -243,6 +297,16 @@ const Editor = () => {
|
||||
);
|
||||
};
|
||||
|
||||
const [isVisible, setIsVisible] = useState(false);
|
||||
|
||||
const onSDKRequestSharingSettings = () => {
|
||||
setIsVisible(true);
|
||||
};
|
||||
|
||||
const onCancel = () => {
|
||||
setIsVisible(false);
|
||||
};
|
||||
|
||||
const onSDKWarning = (event) => {
|
||||
console.log(
|
||||
"ONLYOFFICE Document Editor reports a warning: code " +
|
||||
@ -288,7 +352,16 @@ const Editor = () => {
|
||||
<Toast />
|
||||
|
||||
{!isLoading ? (
|
||||
<div id="editor"></div>
|
||||
<>
|
||||
<div id="editor"></div>
|
||||
|
||||
<SharingDialog
|
||||
isVisible={isVisible}
|
||||
sharingObject={fileInfo}
|
||||
onCancel={onCancel}
|
||||
onSuccess={updateUsersRightsList}
|
||||
/>
|
||||
</>
|
||||
) : (
|
||||
<Box paddingProp="16px">
|
||||
<Loaders.Rectangle height="96vh" />
|
||||
|
@ -14,10 +14,10 @@ newInstance
|
||||
.use(initReactI18next)
|
||||
.use(Backend)
|
||||
.init({
|
||||
lng: "ru",
|
||||
lng: lng,
|
||||
supportedLngs: languages,
|
||||
//whitelist: languages,
|
||||
fallbackLng: "ru",
|
||||
fallbackLng: "en",
|
||||
load: "languageOnly",
|
||||
debug: true,
|
||||
|
||||
@ -35,8 +35,8 @@ newInstance
|
||||
crossDomain: false,
|
||||
},
|
||||
|
||||
ns: ["Login"],
|
||||
defaultNS: "Login",
|
||||
ns: ["Editor"],
|
||||
defaultNS: "Editor",
|
||||
|
||||
react: {
|
||||
useSuspense: true,
|
||||
|
@ -5,8 +5,8 @@ const ModuleFederationPlugin = require("webpack").container
|
||||
.ModuleFederationPlugin;
|
||||
const TerserPlugin = require("terser-webpack-plugin");
|
||||
const { InjectManifest } = require("workbox-webpack-plugin");
|
||||
//const combineUrl = require("@appserver/common/utils/combineUrl");
|
||||
//const AppServerConfig = require("@appserver/common/constants/AppServerConfig");
|
||||
const combineUrl = require("@appserver/common/utils/combineUrl");
|
||||
const AppServerConfig = require("@appserver/common/constants/AppServerConfig");
|
||||
|
||||
const path = require("path");
|
||||
const pkg = require("./package.json");
|
||||
@ -133,7 +133,16 @@ const config = {
|
||||
new ModuleFederationPlugin({
|
||||
name: "editor",
|
||||
filename: "remoteEntry.js",
|
||||
remotes: {},
|
||||
remotes: {
|
||||
studio: `studio@${combineUrl(
|
||||
AppServerConfig.proxyURL,
|
||||
"/remoteEntry.js"
|
||||
)}`,
|
||||
files: `files@${combineUrl(
|
||||
AppServerConfig.proxyURL,
|
||||
"/products/files/remoteEntry.js"
|
||||
)}`,
|
||||
},
|
||||
exposes: {
|
||||
"./app": "./src/Editor.jsx",
|
||||
},
|
||||
|