Merge branch 'feature/workspaces' of github.com:ONLYOFFICE/AppServer into feature/workspaces

This commit is contained in:
Artem Tarasov 2021-03-18 13:40:16 +03:00
commit 66c346b40d
22 changed files with 178 additions and 148 deletions

View File

@ -8,6 +8,4 @@ export { default as ErrorContainer } from "./ErrorContainer";
export { default as ErrorBoundary } from "./ErrorBoundary";
export { default as FilterInput } from "./FilterInput";
export { default as MediaViewer } from "./MediaViewer";
export { default as toastr } from "./Toast";
export { default as NavMenu } from "./NavMenu";
export { default as Loaders } from "./Loaders";

View File

@ -4,5 +4,4 @@ export { default as history } from "./history";
export * from "./components";
export * as constants from "./constants";
export * as utils from "./utils";
export * from "./pages";
export * from "./desktop";

View File

@ -96,6 +96,7 @@ class SettingsStore {
ownerId: observable,
nameSchemaId: observable,
wizardCompleted: observable,
passwordSettings: observable,
getSettings: action,
getCurrentCustomSchema: action,
getPortalSettings: action,

View File

@ -3,9 +3,14 @@ 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) => {
return (
const { isLoaded, isLoading } = props;
return !isLoaded || (isMobile && isLoading) ? (
<Loaders.Rows />
) : (
<Consumer>
{(context) => (
<RowContainer
@ -28,10 +33,13 @@ const FilesRowContainer = (props) => {
);
};
export default inject(({ filesStore }) => {
export default inject(({ auth, initFilesStore, filesStore }) => {
const { filesList } = filesStore;
const { isLoading } = initFilesStore;
return {
filesList,
isLoading,
isLoaded: auth.isLoaded,
};
})(observer(FilesRowContainer));

View File

@ -344,6 +344,7 @@ const StyledSharingBody = styled(Scrollbar)`
padding: 16px 0;
.row_content {
overflow: visible;
height: auto;
}
.sharing-row {

View File

@ -10,6 +10,7 @@ import { resendUserInvites } from "@appserver/common/api/people";
import toastr from "studio/toastr";
import Loaders from "@appserver/common/components/Loaders";
import { inject, observer } from "mobx-react";
import { showLoader, hideLoader } from "@appserver/common/utils";
const InfoContainer = styled.div`
margin-bottom: 24px;
@ -86,6 +87,12 @@ class ProfileInfo extends React.PureComponent {
};
}
componentDidUpdate() {
const { isLoading } = this.props;
isLoading ? showLoader() : hideLoader();
}
onGroupClick = (e) => {
const group = e.currentTarget.dataset.id;
const { filter, setIsLoading, fetchPeople } = this.props;
@ -134,19 +141,27 @@ class ProfileInfo extends React.PureComponent {
onLanguageSelect = (language) => {
console.log("onLanguageSelect", language);
const { profile, updateProfileCulture, i18n } = this.props;
const {
profile,
updateProfileCulture,
//i18n,
setIsLoading,
} = this.props;
if (profile.cultureName === language.key) return;
setIsLoading(true);
updateProfileCulture(profile.id, language.key)
.then(() => {
console.log("changeLanguage to", language.key);
i18n && i18n.changeLanguage(language.key);
})
.then(() => document.location.reload())
.catch((error) =>
toastr.error(error && error.message ? error.message : error)
);
// .then(() => {
// console.log("changeLanguage to", language.key);
// i18n && i18n.changeLanguage(language.key);
// })
.then(() => setIsLoading(false))
.then(() => location.reload())
.catch((error) => {
toastr.error(error && error.message ? error.message : error);
setIsLoading(false);
});
};
getLanguages = () => {
@ -215,6 +230,7 @@ class ProfileInfo extends React.PureComponent {
</Link>
</Text>
);
return (
<InfoContainer>
<InfoItem>
@ -340,5 +356,6 @@ export default inject(({ auth, peopleStore }) => ({
fetchPeople: peopleStore.usersStore.getUsersList,
filter: peopleStore.filterStore.filter,
setIsLoading: peopleStore.setIsLoading,
isLoading: peopleStore.isLoading,
updateProfileCulture: peopleStore.targetUserStore.updateProfileCulture,
}))(observer(withTranslation("Profile")(ProfileInfo)));

View File

@ -1,6 +1,8 @@
import api from "@appserver/common/api";
import { LANGUAGE } from "@appserver/common/constants";
import { makeAutoObservable } from "mobx";
import store from "studio/store";
const { auth: authStore } = store;
class TargetUserStore {
@ -68,10 +70,13 @@ class TargetUserStore {
updateProfileCulture = async (id, culture) => {
const res = await api.people.updateUserCulture(id, culture);
authStore.userStore.setUser(res);
this.setTargetUser(res);
//caches.delete("api-cache");
await authStore.settingsStore.init();
//await authStore.settingsStore.init();
localStorage.setItem(LANGUAGE, culture);
};
getUserPhoto = async (id) => {

View File

@ -1,5 +1,5 @@
import React, { useEffect } from "react";
import { Router, Switch /*, Route*/ } from "react-router-dom";
import { Router, Switch, Route } from "react-router-dom";
import { inject, observer } from "mobx-react";
import NavMenu from "./components/NavMenu";
import Main from "./components/Main";
@ -37,6 +37,7 @@ const ComingSoon = React.lazy(() => import("./components/pages/ComingSoon"));
const ThirdPartyResponse = React.lazy(() =>
import("./components/pages/ThirdParty")
);
const Confirm = React.lazy(() => import("./components/pages/Confirm"));
const SettingsRoute = (props) => (
<React.Suspense fallback={<AppLoader />}>
@ -76,6 +77,14 @@ const HomeRoute = (props) => (
</React.Suspense>
);
const ConfirmRoute = (props) => (
<React.Suspense fallback={<AppLoader />}>
<ErrorBoundary>
<Confirm {...props} />
</ErrorBoundary>
</React.Suspense>
);
const LoginRoute = (props) => (
<React.Suspense fallback={<AppLoader />}>
<ErrorBoundary>
@ -234,6 +243,7 @@ const Shell = ({ items = [], page = "home", ...rest }) => {
]}
component={LoginRoute}
/>
<Route path={`${homepage}/confirm`} component={ConfirmRoute} />
<PrivateRoute
path={[
`${homepage}/coming-soon`,

View File

@ -165,6 +165,7 @@ class NavMenu extends React.Component {
onNavMouseEnter={this.handleNavMouseEnter}
onNavMouseLeave={this.handleNavMouseLeave}
toggleAside={this.toggleAside}
backdropClick={this.backdropClick}
/>
</>
) : !isLoaded && isAuthenticated ? (

View File

@ -104,6 +104,7 @@ const HeaderComponent = ({
version,
isAuthenticated,
isAdmin,
backdropClick,
...props
}) => {
const { t } = useTranslation();
@ -132,6 +133,7 @@ const HeaderComponent = ({
if (!e) return;
const link = e.currentTarget.dataset.link;
history.push(link);
backdropClick();
e.preventDefault();
};

View File

@ -17,58 +17,50 @@ const ChangeOwnerForm = lazy(() => import("./sub-components/changeOwner"));
const Confirm = ({ match, isLoaded }) => {
//console.log("Confirm render");
return !isLoaded ? (
<PageLayout>
<PageLayout.SectionBody>
<Loaders.Rectangle height="90vh" />
</PageLayout.SectionBody>
</PageLayout>
) : (
<Suspense fallback={null}>
<Switch>
<ConfirmRoute
forUnauthorized
path={`${match.path}/LinkInvite`}
component={CreateUserForm}
/>
<ConfirmRoute
forUnauthorized
path={`${match.path}/Activation`}
component={ActivateUserForm}
/>
<ConfirmRoute
exact
path={`${match.path}/EmailActivation`}
component={ActivateEmailForm}
/>
<ConfirmRoute
exact
path={`${match.path}/EmailChange`}
component={ChangeEmailForm}
/>
<ConfirmRoute
forUnauthorized
path={`${match.path}/PasswordChange`}
component={ChangePasswordForm}
/>
<ConfirmRoute
exact
path={`${match.path}/ProfileRemove`}
component={ProfileRemoveForm}
/>
<Route
exact
path={`${match.path}/PhoneActivation`}
component={ChangePhoneForm}
/>
<Route
exact
path={`${match.path}/ownerchange`}
component={ChangeOwnerForm}
/>
{/* <Route component={Error404} /> */}
</Switch>
</Suspense>
return (
<Switch>
<ConfirmRoute
forUnauthorized
path={`${match.path}/LinkInvite`}
component={CreateUserForm}
/>
<ConfirmRoute
forUnauthorized
path={`${match.path}/Activation`}
component={ActivateUserForm}
/>
<ConfirmRoute
exact
path={`${match.path}/EmailActivation`}
component={ActivateEmailForm}
/>
<ConfirmRoute
exact
path={`${match.path}/EmailChange`}
component={ChangeEmailForm}
/>
<ConfirmRoute
forUnauthorized
path={`${match.path}/PasswordChange`}
component={ChangePasswordForm}
/>
<ConfirmRoute
exact
path={`${match.path}/ProfileRemove`}
component={ProfileRemoveForm}
/>
<Route
exact
path={`${match.path}/PhoneActivation`}
component={ChangePhoneForm}
/>
<Route
exact
path={`${match.path}/ownerchange`}
component={ChangeOwnerForm}
/>
{/* <Route component={Error404} /> */}
</Switch>
);
};

View File

@ -17,9 +17,8 @@ import PasswordInput from "@appserver/components/password-input";
import toastr from "@appserver/components/toast/toastr";
import Loader from "@appserver/components/loader";
import PageLayout from "@appserver/common/components/PageLayout";
import constants from "@appserver/common/constants";
import { EmployeeActivationStatus } from "@appserver/common/constants";
import { createPasswordHash } from "@appserver/common/utils";
const { EmployeeActivationStatus } = constants;
const inputWidth = "400px";
@ -65,7 +64,6 @@ class Confirm extends React.PureComponent {
super(props);
this.state = {
isConfirmLoaded: false,
email: props.linkData.email,
firstName: props.linkData.firstname,
firstNameValid: true,
@ -192,16 +190,10 @@ class Confirm extends React.PureComponent {
const { getSettings, getPortalPasswordSettings, history } = this.props;
const requests = [getSettings(), getPortalPasswordSettings(this.state.key)];
axios
.all(requests)
.then(() => {
this.setState({ isConfirmLoaded: true });
console.log("get settings success");
})
.catch((e) => {
console.error("get settings error", e);
history.push(`/login/error=${e}`);
});
axios.all(requests).catch((e) => {
console.error("get settings error", e);
history.push(`/login/error=${e}`);
});
window.addEventListener("keydown", this.onKeyPress);
window.addEventListener("keyup", this.onKeyPress);
@ -235,8 +227,8 @@ class Confirm extends React.PureComponent {
render() {
console.log("ActivateUser render");
const { settings, isConfirmLoaded, t, greetingTitle } = this.props;
return !isConfirmLoaded ? (
const { settings, t, greetingTitle } = this.props;
return !settings ? (
<Loader className="pageLoader" type="rombs" size="40px" />
) : (
<ConfirmContainer>
@ -364,8 +356,6 @@ class Confirm extends React.PureComponent {
}
Confirm.propTypes = {
getConfirmationInfo: PropTypes.func.isRequired,
activateConfirmUser: PropTypes.func.isRequired,
location: PropTypes.object.isRequired,
history: PropTypes.object.isRequired,
};

View File

@ -14,13 +14,11 @@ class ChangeEmail extends React.PureComponent {
changeEmail(userId, email, key)
.then((res) => {
console.log("change client email success", res);
tryRedirectTo(
`${window.location.origin}/products/people/view/@self?email_change=success`
);
tryRedirectTo(`/products/people/view/@self?email_change=success`);
})
.catch((e) => {
console.log("change client email error", e);
tryRedirectTo(`${window.location.origin}/error=${e}`);
tryRedirectTo(`/error=${e}`);
});
}
}
@ -32,13 +30,9 @@ class ChangeEmail extends React.PureComponent {
changeEmail(userId, email, key)
.then((res) => {
console.log("change client email success", res);
tryRedirectTo(
`${window.location.origin}/products/people/view/@self?email_change=success`
);
tryRedirectTo(`/products/people/view/@self?email_change=success`);
})
.catch((e) => {
console.log("change client email error", e);
});
.catch((e) => console.log("change client email error", e));
} else {
tryRedirectTo(defaultPage);
}

View File

@ -43,7 +43,6 @@ class Form extends React.PureComponent {
const { linkData } = props;
this.state = {
isConfirmLoaded: false,
password: "",
passwordValid: true,
// isValidConfirmLink: false,
@ -68,9 +67,16 @@ class Form extends React.PureComponent {
};
onSubmit = (e) => {
debugger;
this.setState({ isLoading: true }, function () {
const { userId, password, key } = this.state;
const { hashSettings, defaultPage } = this.props;
const {
t,
hashSettings,
defaultPage,
logout,
changePassword,
} = this.props;
let hasError = false;
if (!this.state.passwordValid) {
@ -86,15 +92,14 @@ class Form extends React.PureComponent {
}
const hash = createPasswordHash(password, hashSettings);
api.people
.changePassword(userId, hash, key)
.then(() => this.props.logout())
changePassword(userId, hash, key)
.then(() => logout())
.then(() => {
toastr.success(this.props.t("ChangePasswordSuccess"));
toastr.success(t("ChangePasswordSuccess"));
tryRedirectTo(defaultPage);
})
.catch((error) => {
toastr.error(this.props.t(`${error}`));
toastr.error(t(`${error}`));
this.setState({ isLoading: false });
});
});
@ -105,16 +110,10 @@ class Form extends React.PureComponent {
const requests = [getSettings(), getPortalPasswordSettings(this.state.key)];
axios
.all(requests)
.then(() => {
this.setState({ isConfirmLoaded: true });
console.log("get settings success");
})
.catch((error) => {
toastr.error(this.props.t(`${error}`));
tryRedirectTo(defaultPage);
});
axios.all(requests).catch((error) => {
toastr.error(this.props.t(`${error}`));
tryRedirectTo(defaultPage);
});
window.addEventListener("keydown", this.onKeyPress);
window.addEventListener("keyup", this.onKeyPress);
@ -128,10 +127,10 @@ class Form extends React.PureComponent {
validatePassword = (value) => this.setState({ passwordValid: value });
render() {
const { settings, isConfirmLoaded, t, greetingTitle } = this.props;
const { settings, t, greetingTitle } = this.props;
const { isLoading, password, passwordEmpty } = this.state;
return !isConfirmLoaded ? (
return !settings ? (
<Loader className="pageLoader" type="rombs" size="40px" />
) : (
<BodyStyle>
@ -196,7 +195,6 @@ class Form extends React.PureComponent {
Form.propTypes = {
history: PropTypes.object.isRequired,
changePassword: PropTypes.func.isRequired,
logout: PropTypes.func.isRequired,
linkData: PropTypes.object.isRequired,
};
@ -213,7 +211,7 @@ const ChangePasswordForm = (props) => (
</PageLayout>
);
export default inject(({ auth }) => {
export default inject(({ auth, setup }) => {
const { settingsStore, logout, isAuthenticated } = auth;
const {
greetingSettings,
@ -223,6 +221,8 @@ export default inject(({ auth }) => {
getSettings,
getPortalPasswordSettings,
} = settingsStore;
const { changePassword } = setup;
return {
settings: passwordSettings,
hashSettings,
@ -232,5 +232,6 @@ export default inject(({ auth }) => {
isAuthenticated,
getSettings,
getPortalPasswordSettings,
changePassword,
};
})(withRouter(withTranslation("Confirm")(observer(ChangePasswordForm))));

View File

@ -60,7 +60,6 @@ class Confirm extends React.PureComponent {
super(props);
this.state = {
isConfirmLoaded: false,
email: "",
emailValid: true,
firstName: "",
@ -184,16 +183,10 @@ class Confirm extends React.PureComponent {
const requests = [getSettings(), getPortalPasswordSettings(this.state.key)];
axios
.all(requests)
.then(() => {
this.setState({ isConfirmLoaded: true });
console.log("get settings success");
})
.catch((e) => {
console.error("get settings error", e);
history.push(`/login/error=${e}`);
});
axios.all(requests).catch((e) => {
console.error("get settings error", e);
history.push(`/login/error=${e}`);
});
window.addEventListener("keydown", this.onKeyPress);
window.addEventListener("keyup", this.onKeyPress);
@ -234,9 +227,11 @@ class Confirm extends React.PureComponent {
};
render() {
console.log("createUser render");
const { settings, isConfirmLoaded, t, greetingTitle } = this.props;
return !isConfirmLoaded ? (
const { settings, t, greetingTitle } = this.props;
//console.log("createUser render");
return !settings ? (
<Loader className="pageLoader" type="rombs" size="40px" />
) : (
<ConfirmContainer>

View File

@ -1,5 +1,5 @@
import React, { useEffect } from "react";
import styled from "styled-components";
import styled, { css } from "styled-components";
import { withRouter } from "react-router";
import { withTranslation } from "react-i18next";
import PropTypes from "prop-types";
@ -12,6 +12,7 @@ import ButtonContainer from "./sub-components/buttonContainer";
import ContactContainer from "./sub-components/contactContainer";
import { setDocumentTitle } from "../../../helpers/utils";
import { inject, observer } from "mobx-react";
import { isMobile } from "react-device-detect";
const StyledBody = styled.div`
margin: 0 auto;
@ -21,13 +22,22 @@ const StyledBody = styled.div`
grid-template-rows: repeat(4, min-content);
overflow-wrap: anywhere;
margin-top: 40px;
${
isMobile &&
`
margin-top: 56px;
`
}
@media ${tablet} {
max-width: ${size.smallTablet}px;
}
@media (max-width: 632px) {
min-width: 343px;
margin-top: 0;
${!isMobile && `margin-top: 0;`}
}
`;
class Body extends React.Component {

View File

@ -6,6 +6,7 @@ import { inject, observer } from "mobx-react";
import Button from "@appserver/components/button";
import { tablet } from "@appserver/components/utils/device";
import toastr from "@appserver/components/toast/toastr";
import { withRouter } from "react-router";
const StyledButtonContainer = styled.div`
background: #edf2f7;

View File

@ -109,7 +109,7 @@ class SectionHeaderContent extends React.Component {
<HeaderContainer>
{!isCategoryOrHeader && arrayOfParams[0] && (
<IconButton
iconName="static/images/arrow.path.react.svg"
iconName="/static/images/arrow.path.react.svg"
size="17"
color="#A3A9AE"
hoverColor="#657077"

View File

@ -119,7 +119,7 @@ class LanguageAndTimeZone extends React.Component {
});
}
if (!timezones.length && !languages.length) {
if (!timezones.length || !languages.length) {
let languages;
getPortalCultures()
.then(() => {
@ -177,6 +177,7 @@ class LanguageAndTimeZone extends React.Component {
languageDefault,
} = this.state;
const { i18n, language, nameSchemaId, getCurrentCustomSchema } = this.props;
if (timezones.length && languages.length && !prevState.isLoadedData) {
this.setState({ isLoadedData: true });
}

View File

@ -93,11 +93,11 @@ class PureAccessRights extends Component {
title: t("OwnerSettings"),
content: <OwnerSettings />,
},
{
key: "1",
title: t("AdminsSettings"),
content: <AdminsSettings />,
},
// {
// key: "1",
// title: t("AdminsSettings"),
// content: <AdminsSettings />,
// },
// {
// key: "2",
// title: "Portals settings",

View File

@ -165,6 +165,10 @@ class SettingsSetupStore {
console.log("updateConsumerProps", res);
await this.getConsumers();
};
changePassword = (userId, hash, key) => {
return api.people.changePassword(userId, hash, key);
};
}
export default SettingsSetupStore;

View File

@ -7166,9 +7166,9 @@ detect-node-es@^1.0.0:
integrity sha512-S4AHriUkTX9FoFvL4G8hXDcx6t3gp2HpfCza3Q0v6S78gul2hKWifLQbeW+ZF89+hSm2ZIc/uF3J97ZgytgTRg==
detect-node@^2.0.4:
version "2.0.4"
resolved "https://registry.yarnpkg.com/detect-node/-/detect-node-2.0.4.tgz#014ee8f8f669c5c58023da64b8179c083a28c46c"
integrity sha512-ZIzRpLJrOj7jjP2miAtgqIfmzbxa4ZOr5jJc601zklsfEx9oTzmmj2nVpIPRpNlRTIh8lc1kyViIY7BWSGNmKw==
version "2.0.5"
resolved "https://registry.yarnpkg.com/detect-node/-/detect-node-2.0.5.tgz#9d270aa7eaa5af0b72c4c9d9b814e7f4ce738b79"
integrity sha512-qi86tE6hRcFHy8jI1m2VG+LaPUR1LhqDa5G8tVjuUXmOrpuAgqsA1pN0+ldgr3aKUH+QLI9hCY/OcRYisERejw==
detect-port-alt@1.1.6:
version "1.1.6"
@ -7479,9 +7479,9 @@ ejs@^3.1.2:
jake "^10.6.1"
electron-to-chromium@^1.3.564, electron-to-chromium@^1.3.649:
version "1.3.689"
resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.689.tgz#0f4082467c109844b79a7b32a2649c9ab6a6c822"
integrity sha512-WCn+ZaU3V8WttlLNSOGOAlR2XpxibGre7slwGrYBB6oTjYPgP29LNDGG6wLvLTMseLdE+G1vno7PfY7JyDV48g==
version "1.3.690"
resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.690.tgz#54df63ec42fba6b8e9e05fe4be52caeeedb6e634"
integrity sha512-zPbaSv1c8LUKqQ+scNxJKv01RYFkVVF1xli+b+3Ty8ONujHjAMg+t/COmdZqrtnS1gT+g4hbSodHillymt1Lww==
element-resize-detector@^1.2.1:
version "1.2.2"
@ -14784,9 +14784,9 @@ rollup-pluginutils@^2.8.2:
estree-walker "^0.6.1"
rollup@^2.25.0:
version "2.41.3"
resolved "https://registry.yarnpkg.com/rollup/-/rollup-2.41.3.tgz#b224f3863a1660e9d5233ffd2fa0800d90f66433"
integrity sha512-swrSUfX3UK7LGd5exBJNUC7kykdxemUTRuyO9hUFJsmQUsUovHcki9vl5MAWFbB6oI47HpeZHtbmuzdm1SRUZw==
version "2.41.4"
resolved "https://registry.yarnpkg.com/rollup/-/rollup-2.41.4.tgz#2a674d64db4322482d440699acb060dc6dd9e65f"
integrity sha512-f9IHfMO8p2Y8OdisI7Oj3oKkPuaQ6cgSwYqAi0TDvP3w2p+oX1VejX/w28a1h8WTnrapzfO5d4Uqhww+gL0b0g==
optionalDependencies:
fsevents "~2.3.1"