Merge pull request #207 from ONLYOFFICE/feature/EditorIntegration

Feature/editor integration
This commit is contained in:
Alexey Safronov 2021-04-02 12:16:15 +03:00 committed by GitHub
commit 32d1d13856
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
30 changed files with 1394 additions and 1150 deletions

View File

@ -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

View File

@ -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..."
}

View File

@ -29,5 +29,7 @@
"ShareEveryone": "Все",
"ShareEmailSubject": "Вам предоставлен доступ к документу {{itemName}}",
"ShareEmailBody": "Вам предоставлен доступ к документу {{itemName}}. Нажмите на ссылку ниже, чтобы открыть документ прямо сейчас: {{shareLink}}"
"ShareEmailBody": "Вам предоставлен доступ к документу {{itemName}}. Нажмите на ссылку ниже, чтобы открыть документ прямо сейчас: {{shareLink}}",
"LoadingLabel": "Загрузка... Пожалуйста подождите..."
}

View File

@ -649,7 +649,7 @@ class FilesRowContent extends React.PureComponent {
{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}

View File

@ -367,7 +367,7 @@ const SimpleFilesRow = (props) => {
return {
key: option,
label: t("Edit"),
icon: "images/access.edit.react.svg",
icon: "/static/images/access.edit.react.svg",
onClick: onClickLinkEdit,
disabled: false,
};
@ -431,7 +431,7 @@ const SimpleFilesRow = (props) => {
return {
key: option,
label: t("ThirdPartyInfo"),
icon: "images/access.edit.react.svg",
icon: "/static/images/access.edit.react.svg",
onClick: onChangeThirdPartyInfo,
disabled: false,
};

View File

@ -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;

View File

@ -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>
);

View File

@ -0,0 +1,80 @@
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 initFilesStore from "../../../store/InitFilesStore";
import filesStore from "../../../store/FilesStore";
import uploadDataStore from "../../../store/UploadDataStore";
import dialogsStore from "../../../store/DialogsStore";
import treeFoldersStore from "../../../store/TreeFoldersStore";
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}
initFilesStore={initFilesStore}
filesStore={filesStore}
dialogsStore={dialogsStore}
treeFoldersStore={treeFoldersStore}
uploadDataStore={uploadDataStore}
>
<SharingDialogWrapper {...this.props} />
</MobxProvider>
);
}
}
export default SharingModal;

View File

@ -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}

View File

@ -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"

View File

@ -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;

View File

@ -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,9 +591,7 @@ class SharingPanelComponent extends React.Component {
}
}
const SharingPanel = withTranslation("SharingPanel")(SharingPanelComponent);
export default inject(
const SharingPanel = inject(
(
{
auth,
@ -581,6 +605,7 @@ export default inject(
) => {
const { replaceFileStream, setEncryptionAccess } = auth;
const { customNames, isDesktopClient } = auth.settingsStore;
const { setIsLoading, isLoading } = initFilesStore;
const {
selection,
@ -593,26 +618,27 @@ export default inject(
setShareFiles,
} = 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 +651,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;

View File

@ -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)`

View File

@ -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`

View File

@ -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;
}

View File

@ -753,24 +753,29 @@ class FilesStore {
}
getOptions = (selection, externalAccess = false) => {
let AccessOptions = [];
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));
let AccessOptions = [];
if (webEdit || !externalAccess) AccessOptions.push("FullAccess");
AccessOptions.push("ReadOnly", "DenyAccess");
if (webComment) AccessOptions.push("Comment");
if (webReview) AccessOptions.push("Review");
if (formFillingDocs) AccessOptions.push("FormFilling");
if (webFilter) AccessOptions.push("FilterEditing");
return AccessOptions;
};

View File

@ -144,6 +144,7 @@ var config = {
},
exposes: {
"./app": "./src/Files.jsx",
"./SharingDialog": "./src/components/panels/SharingDialog",
},
shared: {
...deps,

View File

Before

Width:  |  Height:  |  Size: 428 B

After

Width:  |  Height:  |  Size: 428 B

View File

Before

Width:  |  Height:  |  Size: 520 B

After

Width:  |  Height:  |  Size: 520 B

View File

Before

Width:  |  Height:  |  Size: 443 B

After

Width:  |  Height:  |  Size: 443 B

View File

Before

Width:  |  Height:  |  Size: 608 B

After

Width:  |  Height:  |  Size: 608 B

View File

Before

Width:  |  Height:  |  Size: 839 B

After

Width:  |  Height:  |  Size: 839 B

View File

Before

Width:  |  Height:  |  Size: 157 B

After

Width:  |  Height:  |  Size: 157 B

View File

Before

Width:  |  Height:  |  Size: 723 B

After

Width:  |  Height:  |  Size: 723 B

View File

@ -0,0 +1,3 @@
{
"FileLocation": "Open file location"
}

View File

@ -0,0 +1,3 @@
{
"FileLocation": "Открыть расположение файла"
}

View File

@ -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" />

View File

@ -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,

View File

@ -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",
},

2012
yarn.lock

File diff suppressed because it is too large Load Diff