Merge branch 'release/v1.1.0' of github.com:ONLYOFFICE/AppServer into release/v1.1.0

This commit is contained in:
Tatiana Lopaeva 2021-11-19 18:18:13 +03:00
commit 56ecbc95ea
9 changed files with 263 additions and 308 deletions

View File

@ -369,8 +369,10 @@ class ContextMenu extends Component {
position(event) {
if (event) {
let left = event.pageX + 1;
let top = event.pageY + 1;
const rects = this.props.containerRef?.current.getBoundingClientRect();
let left = rects ? rects.left : event.pageX + 1;
let top = rects ? rects.top : event.pageY + 1;
let width = this.menuRef.current.offsetParent
? this.menuRef.current.offsetWidth
: DomHelpers.getHiddenElementOuterWidth(this.menuRef.current);
@ -399,6 +401,14 @@ class ContextMenu extends Component {
top = document.body.scrollTop;
}
if (this.props.containerRef) {
top += rects.height + 4;
if (this.props.scaled) {
this.menuRef.current.style.width = rects.width + "px";
}
}
this.menuRef.current.style.left = left + "px";
this.menuRef.current.style.top = top + "px";
}
@ -583,6 +593,10 @@ ContextMenu.propTypes = {
onShow: PropTypes.func,
/** Callback to invoke when a popup menu is hidden */
onHide: PropTypes.func,
/** If you want to display relative to another component */
containerRef: PropTypes.any,
/** Scale with by container component*/
scaled: PropTypes.bool,
};
ContextMenu.defaultProps = {
@ -596,6 +610,8 @@ ContextMenu.defaultProps = {
appendTo: null,
onShow: null,
onHide: null,
scaled: false,
containerRef: null,
};
export default ContextMenu;

View File

@ -34,7 +34,7 @@ const StyledContextMenu = styled.div`
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
margin-left: 8px;
margin-left: 4px;
margin-top: -4px;
}

View File

@ -1,104 +1,85 @@
import React from "react";
import React, { useRef, useState } from "react";
import PropTypes from "prop-types";
import { ReactSVG } from "react-svg";
import { handleAnyClick } from "../utils/event";
import Text from "../text";
import {
StyledSecondaryButton,
StyledMainButton,
StyledDropDown,
GroupMainButton,
} from "./styled-main-button";
import ContextMenu from "../context-menu";
class MainButton extends React.PureComponent {
constructor(props) {
super(props);
const MainButton = (props) => {
const {
text,
model,
iconName,
isDropdown,
isDisabled,
clickAction,
clickActionSecondary,
} = props;
this.ref = React.createRef();
const ref = useRef();
const menuRef = useRef(null);
this.state = {
isOpen: props.opened,
};
const [isOpen, setIsOpen] = useState(props.opened);
if (props.opened) handleAnyClick(true, this.handleClick);
}
const stopAction = (e) => e.preventDefault();
handleClick = (e) => {
if (this.state.isOpen && this.ref.current.contains(e.target)) return;
this.toggle(false);
const toggle = (e, isOpen) => {
isOpen ? menuRef.current.show(e) : menuRef.current.hide(e);
setIsOpen(isOpen);
};
stopAction = (e) => e.preventDefault();
const onHide = () => {
setIsOpen(false);
};
toggle = (isOpen) => this.setState({ isOpen: isOpen });
componentWillUnmount() {
handleAnyClick(false, this.handleClick);
}
componentDidUpdate(prevProps, prevState) {
// Store prevId in state so we can compare when props change.
// Clear out previously-loaded data (so we don't render stale stuff).
if (this.props.opened !== prevProps.opened) {
this.toggle(this.props.opened);
}
if (this.state.isOpen !== prevState.isOpen) {
handleAnyClick(this.state.isOpen, this.handleClick);
}
}
onMainButtonClick = (e) => {
if (!this.props.isDisabled) {
if (!this.props.isDropdown) {
this.props.clickAction && this.props.clickAction();
const onMainButtonClick = (e) => {
if (!isDisabled) {
if (!isDropdown) {
clickAction && clickAction(e);
} else {
this.toggle(!this.state.isOpen);
toggle(e, !isOpen);
}
} else {
this.stopAction(e);
stopAction(e);
}
};
onDropDownClick = () => {
this.props.onClick && this.props.onClick();
this.toggle(!this.state.isOpen);
};
onSecondaryButtonClick = (e) => {
if (!this.props.isDisabled) {
this.props.clickActionSecondary && this.props.clickActionSecondary();
const onSecondaryButtonClick = (e) => {
if (!isDisabled) {
clickActionSecondary && clickActionSecondary();
} else {
this.stopAction(e);
stopAction(e);
}
};
render() {
//console.log("MainButton render");
return (
<GroupMainButton {...this.props} ref={this.ref}>
<StyledMainButton {...this.props} onClick={this.onMainButtonClick}>
<Text className="main-button_text">{this.props.text}</Text>
</StyledMainButton>
{this.props.isDropdown ? (
<StyledDropDown
open={this.state.isOpen}
clickOutsideAction={this.handleClick}
{...this.props}
onClick={this.onDropDownClick}
/>
) : (
<StyledSecondaryButton
{...this.props}
onClick={this.onSecondaryButtonClick}
>
{this.props.iconName && <ReactSVG src={this.props.iconName} />}
</StyledSecondaryButton>
)}
</GroupMainButton>
);
}
}
const sideIcon = <ReactSVG src={iconName} width="16px" height="16px" />;
return (
<GroupMainButton {...props} ref={ref}>
<StyledMainButton {...props} onClick={onMainButtonClick}>
<Text className="main-button_text">{text}</Text>
</StyledMainButton>
{isDropdown ? (
<ContextMenu
model={model}
containerRef={ref}
ref={menuRef}
onHide={onHide}
scaled={true}
/>
) : (
<StyledSecondaryButton {...props} onClick={onSecondaryButtonClick}>
{iconName && sideIcon}
</StyledSecondaryButton>
)}
</GroupMainButton>
);
};
MainButton.propTypes = {
/** Button text */
@ -115,14 +96,14 @@ MainButton.propTypes = {
iconName: PropTypes.string,
/** Open DropDown */
opened: PropTypes.bool, //TODO: Make us whole
/** DropDown component click action */
onClick: PropTypes.func,
/** Accepts class */
className: PropTypes.string,
/** Accepts id */
id: PropTypes.string,
/** Accepts css style */
style: PropTypes.oneOfType([PropTypes.object, PropTypes.array]),
/** Menu data model */
model: PropTypes.oneOfType([PropTypes.object, PropTypes.array]),
};
MainButton.defaultProps = {

View File

@ -1,11 +1,9 @@
import React from "react";
import MainButton from ".";
import DropDownItem from "../drop-down-item";
export default {
title: "Components/MainButton",
component: MainButton,
subcomponents: { DropDownItem },
parameters: { docs: { description: { component: "Components/MainButton" } } },
clickAction: { action: "clickAction" },
clickActionSecondary: { action: "clickActionSecondary" },
@ -26,37 +24,51 @@ const Template = ({
clickActionSecondary(e, credentials);
};
let icon = !args.isDropdown
? {
iconName: "static/images/people.react.svg",
}
: {};
const itemsModel = [
{
label: "New document",
icon: "/static/images/catalog.folder.react.svg",
},
{
label: "New spreadsheet",
icon: "/static/images/catalog.folder.react.svg",
},
{
label: "New presentation",
icon: "/static/images/catalog.folder.react.svg",
},
{
label: "Master form",
icon: "/static/images/catalog.folder.react.svg",
items: [
{
label: "From blank",
},
{
label: "From an existing text file",
},
],
},
{
label: "New folder",
icon: "/static/images/catalog.folder.react.svg",
},
{ separator: true },
{
label: "Upload",
icon: "/static/images/catalog.folder.react.svg",
},
];
return (
<div style={{ width: "280px" }}>
<MainButton
{...args}
clickAction={clickMainButtonHandler}
clickActionSecondary={clickSecondaryButtonHandler}
model={itemsModel}
iconName
{...icon}
>
<DropDownItem
icon="static/images/catalog.employee.react.svg"
label="New employee"
onClick={() => clickItem("New employee clicked")}
/>
<DropDownItem
icon="static/images/catalog.departments.react.svg"
label="New department"
onClick={() => clickItem("New department clicked")}
/>
<DropDownItem isSeparator />
<DropDownItem
icon="static/images/invitation.link.react.svg"
label="Invitation link"
onClick={() => clickItem("Invitation link clicked")}
/>
</MainButton>
></MainButton>
</div>
);
};
@ -68,86 +80,3 @@ Default.args = {
text: "Actions",
iconName: "static/images/people.react.svg",
};
/*
import { storiesOf } from "@storybook/react";
import { action } from "@storybook/addon-actions";
import { text, boolean, withKnobs, select } from "@storybook/addon-knobs/react";
import Section from "../../../.storybook/decorators/section";
import withReadme from "storybook-readme/with-readme";
import Readme from "./README.md";
const iconNames = Object.keys(Icons);
function ClickMainButton(e, credentials) {
console.log("ClickMainButton", e, credentials);
}
function ClickSecondaryButton(e, credentials) {
console.log("ClickSecondaryButton", e, credentials);
}
storiesOf("Components|MainButton", module)
.addDecorator(withKnobs)
.addDecorator(withReadme(Readme))
.add("base", () => {
let isDropdown = boolean("isDropdown", true);
let icon = !isDropdown
? {
iconName: `${select(
"iconName",
iconNames,
"static/images/people.react.svg"
)}`,
}
: {};
return (
<Section>
<MainButton
isDisabled={boolean("isDisabled", false)}
isDropdown={isDropdown}
text={text("text", "Actions")}
clickAction={ClickMainButton}
clickActionSecondary={ClickSecondaryButton}
{...icon}
>
<DropDownItem
icon="static/images/catalog.employee.react.svg"
label="New employee"
onClick={() => action("New employee clicked")}
/>
<DropDownItem
icon="CatalogGuestIcon"
label="New quest"
onClick={() => action("New quest clicked")}
/>
<DropDownItem
icon="static/images/catalog.departments.react.svg"
label="New department"
onClick={() => action("New department clicked")}
/>
<DropDownItem isSeparator />
<DropDownItem
icon="static/images/invitation.link.react.svg"
label="Invitation link"
onClick={() => action("Invitation link clicked")}
/>
<DropDownItem
icon="PlaneIcon"
label="Invite again"
onClick={() => action("Invite again clicked")}
/>
<DropDownItem
icon="ImportIcon"
label="Import people"
onClick={() => action("Import people clicked")}
/>
</MainButton>
</Section>
);
});
*/

View File

@ -7,5 +7,7 @@
"UploadFolder": "Upload folder",
"NewForm": "Master form",
"NewFormFile": "Master form from file",
"CreateMasterFormFromFile": "Create Master Form from file"
"CreateMasterFormFromFile": "Create Master Form from file",
"SubNewForm": "From blank",
"SubNewFormFile": "From an existing text file"
}

View File

@ -372,7 +372,7 @@ export default function withContextOptions(WrappedComponent) {
return {
key: option,
label: t("Common:FillFormButton"),
icon: "/static/images/access.edit.form.react.svg",
icon: "/static/images/form.fill.rect.svg",
onClick: this.onClickLinkFillForm,
disabled: false,
};

View File

@ -16,7 +16,7 @@ import withLoader from "../../../HOCs/withLoader";
class ArticleMainButtonContent extends React.Component {
onCreate = (e) => {
// this.goToHomePage();
const format = e.currentTarget.dataset.format || null;
const format = e.action || null;
this.props.setAction({
type: FileAction.Create,
extension: format,
@ -79,68 +79,104 @@ class ArticleMainButtonContent extends React.Component {
isPrivacy,
} = this.props;
const folderUpload = !isMobile
? [
{
className: "main-button_drop-down",
icon: "images/actions.upload.react.svg",
label: t("UploadFolder"),
disabled: isPrivacy,
onClick: this.onUploadFolderClick,
},
]
: [];
const formActions = !isMobile
? [
{
className: "main-button_drop-down",
icon: "images/form.react.svg",
label: t("NewForm"),
items: [
{
className: "main-button_drop-down_sub",
label: t("SubNewForm"),
onClick: this.onCreate,
action: "docxf",
},
{
className: "main-button_drop-down_sub",
label: t("SubNewFormFile"),
onClick: this.onShowSelectFileDialog,
},
],
},
]
: [
{
className: "main-button_drop-down_sub",
icon: "images/form.react.svg",
label: t("SubNewForm"),
onClick: this.onCreate,
action: "docxf",
},
{
className: "main-button_drop-down_sub",
icon: "images/form.file.react.svg",
label: t("SubNewFormFile"),
onClick: this.onShowSelectFileDialog,
},
];
const menuModel = [
{
className: "main-button_drop-down",
icon: "images/actions.documents.react.svg",
label: t("NewDocument"),
onClick: this.onCreate,
action: "docx",
},
{
className: "main-button_drop-down",
icon: "images/spreadsheet.react.svg",
label: t("NewSpreadsheet"),
onClick: this.onCreate,
action: "xlsx",
},
{
className: "main-button_drop-down",
icon: "images/actions.presentation.react.svg",
label: t("NewPresentation"),
onClick: this.onCreate,
action: "pptx",
},
...formActions,
{
className: "main-button_drop-down",
icon: "images/catalog.folder.react.svg",
label: t("NewFolder"),
onClick: this.onCreate,
},
{
isSeparator: true,
},
{
className: "main-button_drop-down",
icon: "images/actions.upload.react.svg",
label: t("UploadFiles"),
onClick: this.onUploadFileClick,
},
...folderUpload,
];
return (
<MainButton
isDisabled={isDisabled ? isDisabled : !canCreate}
isDropdown={true}
text={t("Common:Actions")}
>
<DropDownItem
className="main-button_drop-down"
icon="images/actions.documents.react.svg"
label={t("NewDocument")}
onClick={this.onCreate}
data-format="docx"
<>
<MainButton
isDisabled={isDisabled ? isDisabled : !canCreate}
isDropdown={true}
text={t("Common:Actions")}
model={menuModel}
/>
<DropDownItem
className="main-button_drop-down"
icon="images/spreadsheet.react.svg"
label={t("NewSpreadsheet")}
onClick={this.onCreate}
data-format="xlsx"
/>
<DropDownItem
className="main-button_drop-down"
icon="images/actions.presentation.react.svg"
label={t("NewPresentation")}
onClick={this.onCreate}
data-format="pptx"
/>
<DropDownItem
className="main-button_drop-down"
icon="images/form.react.svg"
label={t("NewForm")}
onClick={this.onCreate}
data-format="docxf"
/>
<DropDownItem
className="main-button_drop-down"
icon="images/form.file.react.svg"
label={t("NewFormFile")}
onClick={this.onShowSelectFileDialog}
/>
<DropDownItem
className="main-button_drop-down"
icon="images/catalog.folder.react.svg"
label={t("NewFolder")}
onClick={this.onCreate}
/>
<DropDownItem isSeparator />
<DropDownItem
className="main-button_drop-down"
icon="images/actions.upload.react.svg"
label={t("UploadFiles")}
onClick={this.onUploadFileClick}
/>
{!isMobile && (
<DropDownItem
className="main-button_drop-down"
icon="images/actions.upload.react.svg"
label={t("UploadFolder")}
disabled={isPrivacy}
onClick={this.onUploadFolderClick}
/>
)}
<input
id="customFileInput"
className="custom-file-input"
@ -162,7 +198,7 @@ class ArticleMainButtonContent extends React.Component {
ref={(input) => (this.inputFolderElement = input)}
style={{ display: "none" }}
/>
</MainButton>
</>
);
}
}

View File

@ -69,67 +69,55 @@ class ArticleMainButtonContent extends React.Component {
const { dialogVisible } = this.state;
const menuModel = [
{
icon: combineUrl(
AppServerConfig.proxyURL,
homepage,
"/images/add.employee.react.svg"
),
label: userCaption,
onClick: this.goToEmployeeCreate,
},
{
icon: combineUrl(
AppServerConfig.proxyURL,
homepage,
"/images/add.guest.react.svg"
),
label: guestCaption,
onClick: this.goToGuestCreate,
},
{
icon: combineUrl(
AppServerConfig.proxyURL,
homepage,
"/images/add.department.react.svg"
),
label: groupCaption,
onClick: this.goToGroupCreate,
},
{
isSeparator: true,
},
{
icon: combineUrl(
AppServerConfig.proxyURL,
"/static/images/invitation.link.react.svg"
),
label: t("Translations:InviteLinkTitle"),
onClick: this.onInvitationDialogClick,
},
];
return isAdmin ? (
<>
<MainButton
isDisabled={false}
isDropdown={true}
text={t("Common:Actions")}
>
<DropDownItem
icon={combineUrl(
AppServerConfig.proxyURL,
homepage,
"/images/add.employee.react.svg"
)}
label={userCaption}
onClick={this.goToEmployeeCreate}
/>
<DropDownItem
icon={combineUrl(
AppServerConfig.proxyURL,
homepage,
"/images/add.guest.react.svg"
)}
label={guestCaption}
onClick={this.goToGuestCreate}
/>
<DropDownItem
icon={combineUrl(
AppServerConfig.proxyURL,
homepage,
"/images/add.department.react.svg"
)}
label={groupCaption}
onClick={this.goToGroupCreate}
/>
<DropDownItem isSeparator />
<DropDownItem
icon={combineUrl(
AppServerConfig.proxyURL,
"/static/images/invitation.link.react.svg"
)}
label={t("Translations:InviteLinkTitle")}
onClick={this.onInvitationDialogClick}
/>
{/* <DropDownItem
icon="images/plane.react.svg"
label={t("SendInvitesAgain")}
onClick={this.onNotImplementedClick.bind(this, t("SendInvitesAgain"))}
/> */}
{false && (
<DropDownItem
icon={combineUrl(
AppServerConfig.proxyURL,
homepage,
"/images/import.react.svg"
)}
label={t("ImportPeople")}
onClick={this.onImportClick}
/>
)}
</MainButton>
model={menuModel}
/>
{dialogVisible && (
<InviteDialog
visible={dialogVisible}

View File

@ -0,0 +1,3 @@
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M1 1C0.447715 1 0 1.44772 0 2V6C0 6.55228 0.447715 7 1 7H15C15.5523 7 16 6.55228 16 6V2C16 1.44772 15.5523 1 15 1H1ZM1 9C0.447715 9 0 9.44771 0 10C0 10.5523 0.447715 11 1 11H15C15.5523 11 16 10.5523 16 10C16 9.44771 15.5523 9 15 9H1ZM6 14C6 13.4477 6.44772 13 7 13H15C15.5523 13 16 13.4477 16 14C16 14.5523 15.5523 15 15 15H7C6.44772 15 6 14.5523 6 14ZM2.5 3C2.22386 3 2 3.22386 2 3.5V4.5C2 4.77614 2.22386 5 2.5 5H13.5C13.7761 5 14 4.77614 14 4.5V3.5C14 3.22386 13.7761 3 13.5 3H2.5Z" fill="#657077"/>
</svg>

After

Width:  |  Height:  |  Size: 655 B