Merge pull request #1156 from ONLYOFFICE/feature/new-user-type-change

Feature/new user type change
This commit is contained in:
Alexey Safronov 2023-01-31 01:01:46 +03:00 committed by GitHub
commit 6f3146ac3d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
17 changed files with 420 additions and 217 deletions

View File

@ -23,6 +23,7 @@ import {
CreateRoomDialog,
InviteUsersWarningDialog,
CreateRoomConfirmDialog,
ChangeUserTypeDialog,
} from "../dialogs";
import ConvertPasswordDialog from "../dialogs/ConvertPasswordDialog";
import ArchiveDialog from "../dialogs/ArchiveDialog";
@ -58,6 +59,7 @@ const Panels = (props) => {
archiveDialogVisible,
inviteUsersWarningDialogVisible,
preparationPortalDialogVisible,
changeUserTypeDialogVisible,
} = props;
const { t } = useTranslation(["Translations", "Common"]);
@ -98,6 +100,9 @@ const Panels = (props) => {
<ConflictResolveDialog key="conflict-resolve-dialog" />
),
convertDialogVisible && <ConvertDialog key="convert-dialog" />,
changeUserTypeDialogVisible && (
<ChangeUserTypeDialog key="change-user-type-dialog" />
),
createRoomDialogVisible && <CreateRoomDialog key="create-room-dialog" />,
(createRoomConfirmDialogVisible || confirmDialogIsLoading) && (
<CreateRoomConfirmDialog key="create-room-confirm-dialog" />
@ -168,6 +173,7 @@ export default inject(
setSelectFileDialogVisible,
invitePanelOptions,
inviteUsersWarningDialogVisible,
changeUserTypeDialogVisible,
} = dialogsStore;
const { preparationPortalDialogVisible } = backup;
@ -206,6 +212,7 @@ export default inject(
archiveDialogVisible,
inviteUsersWarningDialogVisible,
confirmDialogIsLoading,
changeUserTypeDialogVisible,
};
}
)(observer(Panels));

View File

@ -0,0 +1,104 @@
import React, { useState, useEffect } from "react";
import { inject, observer } from "mobx-react";
import { useTranslation } from "react-i18next";
import { ChangeUserTypeDialog } from "../dialogs";
import toastr from "@docspace/components/toast/toastr";
const ChangeUserTypeEvent = ({
setVisible,
visible,
peopleDialogData,
peopleFilter,
updateUserType,
getUsersList,
}) => {
const {
toType,
fromType,
userIDs,
successCallback,
abortCallback,
} = peopleDialogData;
const { t } = useTranslation(["ChangeUserTypeDialog", "Common"]);
useEffect(() => {
setVisible(true);
return () => {
setVisible(false);
};
}, [peopleDialogData]);
const onChangeUserType = () => {
onClose();
updateUserType(toType, userIDs, peopleFilter, fromType)
.then(() => {
toastr.success(t("SuccessChangeUserType"));
successCallback && successCallback();
})
.catch((err) => {
abortCallback && abortCallback();
toastr.error(err);
});
};
const onClose = () => {
setVisible(false);
};
const onCloseAction = async () => {
await getUsersList(peopleFilter);
abortCallback && abortCallback();
onClose();
};
const getType = (type) => {
switch (type) {
case "admin":
return t("Common:DocSpaceAdmin");
case "manager":
return t("Common:RoomAdmin");
case "user":
default:
return t("Common:User");
}
};
const firstType =
fromType.length === 1 && fromType[0] ? getType(fromType[0]) : null;
const secondType = getType(toType);
return (
<ChangeUserTypeDialog
visible={visible}
firstType={firstType}
secondType={secondType}
onCloseAction={onCloseAction}
onChangeUserType={onChangeUserType}
/>
);
};
export default inject(({ dialogsStore, peopleStore }) => {
const {
changeUserTypeDialogVisible: visible,
setChangeUserTypeDialogVisible: setVisible,
} = dialogsStore;
const { dialogStore, filterStore, usersStore } = peopleStore;
const { data: peopleDialogData } = dialogStore;
const { filter: peopleFilter } = filterStore;
const { updateUserType, getUsersList } = usersStore;
return {
visible,
setVisible,
peopleDialogData,
peopleFilter,
updateUserType,
getUsersList,
};
})(observer(ChangeUserTypeEvent));

View File

@ -7,6 +7,7 @@ import CreateEvent from "./CreateEvent";
import RenameEvent from "./RenameEvent";
import CreateRoomEvent from "./CreateRoomEvent";
import EditRoomEvent from "./EditRoomEvent";
import ChangeUserTypeEvent from "./ChangeUserTypeEvent";
const GlobalEvents = () => {
const [createDialogProps, setCreateDialogProps] = useState({
@ -37,6 +38,11 @@ const GlobalEvents = () => {
onClose: null,
});
const [changeUserTypeDialog, setChangeUserTypeDialogProps] = useState({
visible: false,
onClose: null,
});
const onCreate = useCallback((e) => {
const { payload } = e;
@ -106,19 +112,29 @@ const GlobalEvents = () => {
});
}, []);
const onChangeUserType = useCallback((e) => {
setChangeUserTypeDialogProps({
visible: true,
onClose: () =>
setChangeUserTypeDialogProps({ visible: false, onClose: null }),
});
}, []);
useEffect(() => {
window.addEventListener(Events.CREATE, onCreate);
window.addEventListener(Events.RENAME, onRename);
window.addEventListener(Events.ROOM_CREATE, onCreateRoom);
window.addEventListener(Events.ROOM_EDIT, onEditRoom);
window.addEventListener(Events.CHANGE_USER_TYPE, onChangeUserType);
return () => {
window.removeEventListener(Events.CREATE, onCreate);
window.removeEventListener(Events.RENAME, onRename);
window.removeEventListener(Events.ROOM_CREATE, onCreateRoom);
window.removeEventListener(Events.ROOM_EDIT, onEditRoom);
window.removeEventListener(Events.CHANGE_USER_TYPE, onChangeUserType);
};
}, [onRename, onCreate, onCreateRoom, onEditRoom]);
}, [onRename, onCreate, onCreateRoom, onEditRoom, onChangeUserType]);
return [
createDialogProps.visible && (
@ -133,6 +149,12 @@ const GlobalEvents = () => {
editRoomDialogProps.visible && (
<EditRoomEvent key={Events.ROOM_EDIT} {...editRoomDialogProps} />
),
changeUserTypeDialog.visible && (
<ChangeUserTypeEvent
key={Events.CHANGE_USER_TYPE}
{...changeUserTypeDialog}
/>
),
];
};

View File

@ -1,155 +1,74 @@
import React, { memo } from "react";
import { withRouter } from "react-router";
import PropTypes from "prop-types";
import React from "react";
import Text from "@docspace/components/text";
import Button from "@docspace/components/button";
import ModalDialog from "@docspace/components/modal-dialog";
import Text from "@docspace/components/text";
import { withTranslation, Trans } from "react-i18next";
import toastr from "@docspace/components/toast/toastr";
import ModalDialogContainer from "../ModalDialogContainer";
import { inject, observer } from "mobx-react";
class ChangeUserTypeDialogComponent extends React.Component {
constructor(props) {
super(props);
const { userIDs } = props;
this.state = { isRequestRunning: false, userIDs };
}
onChangeUserType = () => {
const {
onClose,
t,
toType,
fromType,
updateUserType,
filter,
} = this.props;
const { userIDs } = this.state;
this.setState({ isRequestRunning: true }, () => {
updateUserType(toType, userIDs, filter, fromType)
.then(() => toastr.success(t("SuccessChangeUserType")))
.catch((error) => toastr.error(error))
.finally(() => {
this.setState({ isRequestRunning: false }, () => {
onClose();
});
});
});
};
onCloseAction = async () => {
const { isRequestRunning } = this.state;
const { onClose, getUsersList, filter } = this.props;
if (!isRequestRunning) {
await getUsersList(filter);
onClose();
}
};
getType = (type) => {
const { t } = this.props;
switch (type) {
case "admin":
return t("Common:DocSpaceAdmin");
case "manager":
return t("Common:RoomAdmin");
case "user":
default:
return t("Common:User");
}
};
render() {
const { visible, t, tReady, toType, fromType } = this.props;
const { isRequestRunning, userIDs } = this.state;
const firstType = fromType.length === 1 ? this.getType(fromType[0]) : null;
const secondType = this.getType(toType);
const changeUserTypeMessage = firstType ? (
<Trans i18nKey="ChangeUserTypeMessage" ns="ChangeUserTypeDialog" t={t}>
Users with the <b>'{{ firstType }}'</b> type will be moved to{" "}
<b>'{{ secondType }}'</b> type.
</Trans>
) : (
<Trans
i18nKey="ChangeUserTypeMessageMulti"
ns="ChangeUserTypeDialog"
t={t}
>
The selected users will be moved to <b>'{{ secondType }}'</b> type.
</Trans>
);
return (
<ModalDialogContainer
isLoading={!tReady}
visible={visible}
onClose={this.onCloseAction}
autoMaxHeight
>
<ModalDialog.Header>{t("ChangeUserTypeHeader")}</ModalDialog.Header>
<ModalDialog.Body>
<Text fontWeight={600}>
{changeUserTypeMessage} {t("ChangeUserTypeMessageWarning")}
</Text>
</ModalDialog.Body>
<ModalDialog.Footer>
<Button
id="change-user-type-modal_submit"
label={t("ChangeUserTypeButton")}
size="normal"
scale
primary
onClick={this.onChangeUserType}
isLoading={isRequestRunning}
isDisabled={!userIDs.length}
/>
<Button
id="change-user-type-modal_cancel"
label={t("Common:CancelButton")}
size="normal"
scale
onClick={this.onCloseAction}
isDisabled={isRequestRunning}
/>
</ModalDialog.Footer>
</ModalDialogContainer>
);
}
}
const ChangeUserTypeDialog = withTranslation([
"ChangeUserTypeDialog",
"People",
"Common",
])(ChangeUserTypeDialogComponent);
ChangeUserTypeDialog.propTypes = {
visible: PropTypes.bool.isRequired,
onClose: PropTypes.func.isRequired,
userIDs: PropTypes.arrayOf(PropTypes.string).isRequired,
const ChangeUserTypeDialog = ({
t,
visible,
firstType,
secondType,
onCloseAction,
onChangeUserType,
isRequestRunning,
}) => {
return (
<ModalDialog
visible={visible}
onClose={onCloseAction}
displayType="modal"
autoMaxHeight
>
<ModalDialog.Header>{t("ChangeUserTypeHeader")}</ModalDialog.Header>
<ModalDialog.Body>
<Text>
{firstType ? (
<Trans
i18nKey="ChangeUserTypeMessage"
ns="ChangeUserTypeDialog"
t={t}
>
Users with the <b>'{{ firstType }}'</b> type will be moved to{" "}
<b>'{{ secondType }}'</b> type.
</Trans>
) : (
<Trans
i18nKey="ChangeUserTypeMessageMulti"
ns="ChangeUserTypeDialog"
t={t}
>
The selected users will be moved to <b>'{{ secondType }}'</b>{" "}
type.
</Trans>
)}{" "}
{t("ChangeUserTypeMessageWarning")}
</Text>
</ModalDialog.Body>
<ModalDialog.Footer>
<Button
id="change-user-type-modal_submit"
label={t("ChangeUserTypeButton")}
size="normal"
scale
primary
onClick={onChangeUserType}
isLoading={isRequestRunning}
//isDisabled={!userIDs.length}
/>
<Button
id="change-user-type-modal_cancel"
label={t("Common:CancelButton")}
size="normal"
scale
onClick={onCloseAction}
isDisabled={isRequestRunning}
/>
</ModalDialog.Footer>
</ModalDialog>
);
};
export default withRouter(
inject(({ peopleStore }) => {
return {
filter: peopleStore.filterStore.filter,
updateUserType: peopleStore.usersStore.updateUserType,
getUsersList: peopleStore.usersStore.getUsersList,
};
})(observer(ChangeUserTypeDialog))
export default withTranslation(["ChangeUserTypeDialog", "People", "Common"])(
ChangeUserTypeDialog
);

View File

@ -46,6 +46,7 @@ const InvitePanel = ({
const [hasErrors, setHasErrors] = useState(false);
const [shareLinks, setShareLinks] = useState([]);
const [roomUsers, setRoomUsers] = useState([]);
const [isLoading, setIsLoading] = useState(false);
const selectRoom = () => {
const room = folders.find((folder) => folder.id === roomId);
@ -161,16 +162,22 @@ const InvitePanel = ({
}
try {
setIsLoading(true);
roomId === -1
? await inviteUsers(data)
: await setRoomSecurity(roomId, data);
if (roomsView === "info_members") setUpdateRoomMembers(true);
setIsLoading(false);
if (roomsView === "info_members") {
setUpdateRoomMembers(true);
}
onClose();
toastr.success(t("Common:UsersInvited"));
reloadSelectionParentRoom();
} catch (err) {
toastr.error(err);
setIsLoading(false);
}
};
@ -217,12 +224,14 @@ const InvitePanel = ({
primary
onClick={onClickSend}
label={t("SendInvitation")}
isLoading={isLoading}
/>
<Button
scale={true}
size={"normal"}
onClick={onClose}
label={t("Common:CancelButton")}
isDisabled={isLoading}
/>
</StyledButtons>
</>

View File

@ -145,6 +145,8 @@ const PeopleTableRow = (props) => {
const isPending = statusType === "pending" || statusType === "disabled";
const [isLoading, setIsLoading] = React.useState(false);
const nameColor = isPending
? theme.peopleTableRow.pendingNameColor
: theme.peopleTableRow.nameColor;
@ -181,11 +183,22 @@ const PeopleTableRow = (props) => {
return options;
}, [t, isOwner, isVisitor]);
const onAbort = () => {
setIsLoading(false);
};
const onSuccess = () => {
setIsLoading(false);
};
const onTypeChange = React.useCallback(
({ action }) => {
changeUserType(action, [item], t, true);
setIsLoading(true);
if (!changeUserType(action, [item], onSuccess, onAbort)) {
setIsLoading(false);
}
},
[item, changeUserType, t]
[item, changeUserType]
);
const getRoomsOptions = React.useCallback(() => {
@ -246,6 +259,7 @@ const PeopleTableRow = (props) => {
displaySelectedOption
modernView
manualWidth={"fit-content"}
isLoading={isLoading}
/>
);

View File

@ -20,6 +20,7 @@ const Accounts = ({
canChangeUserType,
}) => {
const [statusLabel, setStatusLabel] = React.useState("");
const [isLoading, setIsLoading] = React.useState(false);
const { role, id, isVisitor } = selection;
@ -88,9 +89,20 @@ const Accounts = ({
return options;
}, [t, isAdmin, isOwner, isVisitor]);
const onAbort = () => {
setIsLoading(false);
};
const onSuccess = () => {
setIsLoading(false);
};
const onTypeChange = React.useCallback(
({ action }) => {
changeUserType(action, [selection], t, false);
setIsLoading(true);
if (!changeUserType(action, [selection], onSuccess, onAbort)) {
setIsLoading(false);
}
},
[selection, changeUserType, t]
);
@ -114,6 +126,7 @@ const Accounts = ({
displaySelectedOption
modernView
manualWidth={"fit-content"}
isLoading={isLoading}
/>
);
@ -192,7 +205,7 @@ const Accounts = ({
export default inject(({ auth, peopleStore, accessRightsStore }) => {
const { isOwner, isAdmin, id: selfId } = auth.userStore.user;
const { changeType: changeUserType } = peopleStore;
const { changeType: changeUserType, usersStore } = peopleStore;
const { canChangeUserType } = accessRightsStore;
return {
@ -201,6 +214,7 @@ export default inject(({ auth, peopleStore, accessRightsStore }) => {
changeUserType,
selfId,
canChangeUserType,
loading: usersStore.operationRunning,
};
})(
withTranslation([

View File

@ -3,7 +3,8 @@ import AtReactSvgUrl from "PUBLIC_DIR/images/@.react.svg?url";
import { StyledUser } from "../../styles/members";
import Avatar from "@docspace/components/avatar";
import { ComboBox } from "@docspace/components";
import DefaultUserPhotoUrl from "PUBLIC_DIR/images/default_user_photo_size_82-82.png?url";
import DefaultUserPhotoUrl from "PUBLIC_DIR/images/default_user_photo_size_82-82.png";
import toastr from "@docspace/components/toast/toastr";
const User = ({
t,
user,
@ -13,12 +14,14 @@ const User = ({
updateRoomMemberRole,
selectionParentRoom,
setSelectionParentRoom,
changeUserType,
}) => {
if (!selectionParentRoom) return null;
if (!user.displayName && !user.email) return null;
const [userIsRemoved, setUserIsRemoved] = useState(false);
if (userIsRemoved) return null;
//const [userIsRemoved, setUserIsRemoved] = useState(false);
const [isLoading, setIsLoading] = useState(false);
//if (userIsRemoved) return null;
const canChangeUserRole = user.canEditAccess;
@ -32,36 +35,65 @@ const User = ({
(role) => role.key !== userRole.key
);
const onOptionClick = (option) => {
updateRoomMemberRole(selectionParentRoom.id, {
const updateRole = (option) => {
return updateRoomMemberRole(selectionParentRoom.id, {
invitations: [{ id: user.id, access: option.access }],
notify: false,
sharingMessage: "",
});
})
.then(() => {
setIsLoading(false);
const inRoomMembers = selectionParentRoom.members.inRoom;
const expectedMembers = selectionParentRoom.members.expected;
if (option.key === "remove") {
setSelectionParentRoom({
...selectionParentRoom,
members: {
inRoom: inRoomMembers?.filter((m) => m.id !== user.id),
expected: expectedMembers?.filter((m) => m.id !== user.id),
},
});
//setUserIsRemoved(true);
} else {
setSelectionParentRoom({
...selectionParentRoom,
members: {
inRoom: inRoomMembers?.map((m) =>
m.id === user.id ? { ...m, access: option.access } : m
),
expected: expectedMembers?.map((m) =>
m.id === user.id ? { ...m, access: option.access } : m
),
},
});
}
})
.catch((err) => {
toastr.error(err);
setIsLoading(false);
});
};
const inRoomMembers = selectionParentRoom.members.inRoom;
const expectedMembers = selectionParentRoom.members.expected;
if (option.key === "remove") {
setUserIsRemoved(true);
setSelectionParentRoom({
...selectionParentRoom,
members: {
inRoom: inRoomMembers?.filter((m) => m.id !== user.id),
expected: expectedMembers?.filter((m) => m.id !== user.id),
},
});
} else {
setSelectionParentRoom({
...selectionParentRoom,
members: {
inRoom: inRoomMembers?.map((m) =>
m.id === user.id ? { ...m, access: option.access } : m
),
expected: expectedMembers?.map((m) =>
m.id === user.id ? { ...m, access: option.access } : m
),
},
});
const abortCallback = () => {
setIsLoading(false);
};
const onOptionClick = (option) => {
const userType =
option.key === "owner"
? "admin"
: option.key === "roomAdmin"
? "manager"
: "user";
const successCallback = () => {
updateRole(option);
};
setIsLoading(true);
if (!changeUserType(userType, [user], successCallback, abortCallback)) {
updateRole(option);
}
};
@ -98,6 +130,7 @@ const User = ({
modernView
title={t("Common:Role")}
manualWidth={"fit-content"}
isLoading={isLoading}
/>
) : (
<div className="disabled-role-combobox" title={t("Common:Role")}>

View File

@ -20,8 +20,6 @@ import MembersHelper from "../../helpers/MembersHelper";
const Members = ({
t,
selfId,
isOwner,
isAdmin,
selection,
setIsMobileHidden,
@ -37,6 +35,7 @@ const Members = ({
roomsView,
resendEmailInvitations,
setInvitePanelOptions,
changeUserType,
}) => {
const membersHelper = new MembersHelper({ t });
@ -175,6 +174,7 @@ const Members = ({
roomType={selectionParentRoom.roomType}
selectionParentRoom={selectionParentRoom}
setSelectionParentRoom={setSelectionParentRoom}
changeUserType={changeUserType}
/>
))}
</StyledUserList>
@ -210,6 +210,7 @@ const Members = ({
roomType={selectionParentRoom.roomType}
selectionParentRoom={selectionParentRoom}
setSelectionParentRoom={setSelectionParentRoom}
changeUserType={changeUserType}
/>
))}
</StyledUserList>
@ -218,7 +219,14 @@ const Members = ({
};
export default inject(
({ auth, filesStore, peopleStore, dialogsStore, accessRightsStore }) => {
({
auth,
filesStore,
peopleStore,
dialogStore,
dialogsStore,
accessRightsStore,
}) => {
const {
setIsMobileHidden,
selectionParentRoom,
@ -235,9 +243,11 @@ export default inject(
updateRoomMemberRole,
resendEmailInvitations,
} = filesStore;
const { isOwner, isAdmin, id: selfId } = auth.userStore.user;
const { id: selfId } = auth.userStore.user;
const { setInvitePanelOptions } = dialogsStore;
const { changeType: changeUserType } = peopleStore;
return {
setView,
roomsView,
@ -251,12 +261,11 @@ export default inject(
updateRoomMembers,
setUpdateRoomMembers,
isOwner,
isAdmin,
selfId,
setInvitePanelOptions,
resendEmailInvitations,
changeUserType,
};
}
)(

View File

@ -57,6 +57,7 @@ class DialogsStore {
saveAfterReconnectOAuth = false;
createRoomDialogVisible = false;
createRoomConfirmDialogVisible = false;
changeUserTypeDialogVisible = false;
constructor(
authStore,
@ -307,6 +308,10 @@ class DialogsStore {
this.createRoomConfirmDialogVisible = createRoomConfirmDialogVisible;
};
setChangeUserTypeDialogVisible = (changeUserTypeDialogVisible) => {
this.changeUserTypeDialogVisible = changeUserTypeDialogVisible;
};
get someDialogIsOpen() {
return (
this.sharingPanelVisible ||
@ -331,7 +336,8 @@ class DialogsStore {
this.restoreAllPanelVisible ||
this.inviteUsersWarningDialogVisible ||
this.createRoomDialogVisible ||
this.createRoomConfirmDialogVisible
this.createRoomConfirmDialogVisible ||
this.changeUserTypeDialogVisible
);
}

View File

@ -26,12 +26,13 @@ import {
import { isMobileRDD } from "react-device-detect";
import toastr from "@docspace/components/toast/toastr";
import { EmployeeStatus } from "@docspace/common/constants";
import { EmployeeStatus, Events } from "@docspace/common/constants";
import Filter from "@docspace/common/api/people/filter";
class PeopleStore {
contextOptionsStore = null;
authStore = null;
dialogsStore = null;
groupsStore = null;
usersStore = null;
targetUserStore = null;
@ -50,7 +51,13 @@ class PeopleStore {
isInit = false;
viewAs = isMobileRDD ? "row" : "table";
constructor(authStore, infoPanelStore, setupStore, accessRightsStore) {
constructor(
authStore,
infoPanelStore,
setupStore,
accessRightsStore,
dialogsStore
) {
this.authStore = authStore;
this.groupsStore = new GroupsStore(this);
this.usersStore = new UsersStore(this, authStore);
@ -67,6 +74,7 @@ class PeopleStore {
this.infoPanelStore = infoPanelStore;
this.setupStore = setupStore;
this.accessRightsStore = accessRightsStore;
this.dialogsStore = dialogsStore;
this.contextOptionsStore = new AccountsContextOptionsStore(this);
@ -109,11 +117,15 @@ class PeopleStore {
this.changeType(action, getUsersToMakeEmployees);
};
changeType = (type, users) => {
const { setChangeUserTypeDialogVisible, setDialogData } = this.dialogStore;
changeType = (type, users, successCallback, abortCallback) => {
const { setDialogData } = this.dialogStore;
const { getUserRole } = this.usersStore;
const event = new Event(Events.CHANGE_USER_TYPE);
let fromType =
users.length === 1 ? [users[0].role] : users.map((u) => u.role);
users.length === 1
? [users[0].role ? users[0].role : getUserRole(users[0])]
: users.map((u) => (u.role ? u.role : getUserRole(u)));
if (users.length > 1) {
fromType = fromType.filter(
@ -123,7 +135,7 @@ class PeopleStore {
if (fromType.length === 0) fromType = [fromType[0]];
}
if (fromType.length === 1 && fromType[0] === type) return;
if (fromType.length === 1 && fromType[0] === type) return false;
const userIDs = users
.filter((u) => u.role !== type)
@ -131,9 +143,17 @@ class PeopleStore {
return user?.id ? user.id : user;
});
setDialogData({ toType: type, fromType, userIDs });
setDialogData({
toType: type,
fromType,
userIDs,
successCallback,
abortCallback,
});
setChangeUserTypeDialogVisible(true);
window.dispatchEvent(event);
return true;
};
onChangeStatus = (status) => {

View File

@ -17,6 +17,7 @@ class UsersStore {
users = [];
providers = [];
accountsIsIsLoading = false;
operationRunning = false;
constructor(peopleStore, authStore) {
this.peopleStore = peopleStore;
@ -64,6 +65,10 @@ class UsersStore {
this.providers = providers;
};
setOperationRunning = (operationRunning) => {
this.operationRunning = operationRunning;
};
employeeWrapperToMemberModel = (profile) => {
const comment = profile.notes;
const department = profile.groups

View File

@ -55,13 +55,6 @@ const settingsStore = new SettingsStore(thirdPartyStore, treeFoldersStore);
const accessRightsStore = new AccessRightsStore(authStore, selectedFolderStore);
const peopleStore = new PeopleStore(
authStore,
authStore.infoPanelStore,
setupStore,
accessRightsStore
);
const filesStore = new FilesStore(
authStore,
selectedFolderStore,
@ -78,6 +71,7 @@ const mediaViewerDataStore = new MediaViewerDataStore(
const secondaryProgressDataStore = new SecondaryProgressDataStore();
const primaryProgressDataStore = new PrimaryProgressDataStore();
const versionHistoryStore = new VersionHistoryStore(filesStore);
const dialogsStore = new DialogsStore(
authStore,
treeFoldersStore,
@ -85,6 +79,15 @@ const dialogsStore = new DialogsStore(
selectedFolderStore,
versionHistoryStore
);
const peopleStore = new PeopleStore(
authStore,
authStore.infoPanelStore,
setupStore,
accessRightsStore,
dialogsStore
);
const uploadDataStore = new UploadDataStore(
authStore,
treeFoldersStore,

View File

@ -327,6 +327,7 @@ export const Events = Object.freeze({
ROOM_CREATE: "create_room",
ROOM_EDIT: "edit_room",
CHANGE_COLUMN: "change_column",
CHANGE_USER_TYPE: "change_user_type",
});
/**

View File

@ -44,11 +44,13 @@ class ComboBox extends React.Component {
disableItemClick,
isDisabled,
toggleAction,
isLoading,
} = this.props;
if (
isDisabled ||
disableItemClick ||
isLoading ||
(disableIconClick && e && e.target.closest(".optionalBlock"))
)
return;
@ -114,6 +116,7 @@ class ComboBox extends React.Component {
advancedOptionsCount,
isMobileView,
withoutPadding,
isLoading,
} = this.props;
const { tabIndex, ...props } = this.props;
@ -188,6 +191,7 @@ class ComboBox extends React.Component {
modernView={modernView}
fillIcon={fillIcon}
tabIndex={tabIndex}
isLoading={isLoading}
/>
{displayType !== "toggle" && (
<DropDown
@ -298,26 +302,26 @@ ComboBox.propTypes = {
comboIcon: PropTypes.string,
manualY: PropTypes.string,
manualX: PropTypes.string,
//** Dropdown manual width */
/** Dropdown manual width */
manualWidth: PropTypes.string,
displaySelectedOption: PropTypes.bool,
fixedDirection: PropTypes.bool,
/** Disable clicking on the item */
disableItemClick: PropTypes.bool,
/** Indicates that component will fill selected item icon */
fillIcon: PropTypes.bool,
isExternalLink: PropTypes.bool,
isPersonal: PropTypes.bool,
offsetLeft: PropTypes.number,
/**Tell when combo-box should displaying at modern view */
/** Tell when combo-box should displaying at modern view */
modernView: PropTypes.bool,
/**Count of advanced options */
/** Count of advanced options */
advancedOptionsCount: PropTypes.number,
/** Accepts css tab-index style */
tabIndex: PropTypes.number,
withoutPadding: PropTypes.bool,
/** Tells when a component is loading */
isLoading: PropTypes.bool,
};
ComboBox.defaultProps = {
@ -339,6 +343,7 @@ ComboBox.defaultProps = {
modernView: false,
tabIndex: -1,
withoutPadding: false,
isLoading: false,
};
export default ComboBox;

View File

@ -2,14 +2,16 @@ import React from "react";
import PropTypes from "prop-types";
import { ReactSVG } from "react-svg";
import Text from "../../text";
import {
StyledArrowIcon,
StyledIcon,
StyledOptionalItem,
StyledTriangleDownIcon,
StyledLoader,
} from "./styled-combobutton";
import Text from "../../text";
import { ColorTheme, ThemeType } from "@docspace/common/components/ColorTheme";
const ComboButton = (props) => {
@ -30,6 +32,7 @@ const ComboButton = (props) => {
fillIcon,
modernView,
tabIndex,
isLoading,
} = props;
const defaultOption = selectedOption?.default;
@ -52,12 +55,14 @@ const ComboButton = (props) => {
themeId={ThemeType.ComboButton}
tabIndex={tabIndex}
displayArrow={displayArrow}
isLoading={isLoading}
>
{innerContainer && (
<StyledOptionalItem
className={innerContainerClassName}
isDisabled={isDisabled}
defaultOption={defaultOption}
isLoading={isLoading}
>
{innerContainer}
</StyledOptionalItem>
@ -68,6 +73,7 @@ const ComboButton = (props) => {
isDisabled={isDisabled}
defaultOption={defaultOption}
isSelected={isSelected}
isLoading={isLoading}
>
<ReactSVG
src={selectedOption.icon}
@ -75,7 +81,6 @@ const ComboButton = (props) => {
/>
</StyledIcon>
)}
<Text
noBorder={noBorder}
title={selectedOption?.label}
@ -93,6 +98,7 @@ const ComboButton = (props) => {
isOpen={isOpen}
modernView={modernView}
className="combo-buttons_arrow-icon"
isLoading={isLoading}
>
{displayArrow &&
(comboIcon ? (
@ -104,6 +110,10 @@ const ComboButton = (props) => {
/>
))}
</StyledArrowIcon>
{isLoading && (
<StyledLoader displaySize={size} type="track" size="20px" />
)}
</ColorTheme>
);
};
@ -131,6 +141,7 @@ ComboButton.propTypes = {
fillIcon: PropTypes.bool,
modernView: PropTypes.bool,
tabIndex: PropTypes.number,
isLoading: PropTypes.bool,
};
ComboButton.defaultProps = {
@ -144,6 +155,7 @@ ComboButton.defaultProps = {
scaled: false,
modernView: false,
tabIndex: -1,
isLoading: false,
};
export default ComboButton;

View File

@ -6,6 +6,8 @@ import NoUserSelect from "../../utils/commonStyles";
import TriangleDownIcon from "PUBLIC_DIR/images/triangle.down.react.svg";
import commonIconsStyles from "../../utils/common-icons-style";
import Loader from "../../loader";
const StyledTriangleDownIcon = styled(TriangleDownIcon)`
${commonIconsStyles}
`;
@ -13,7 +15,7 @@ const StyledTriangleDownIcon = styled(TriangleDownIcon)`
const modernViewButton = css`
height: ${(props) => props.theme.comboBox.button.heightModernView};
background: ${(props) =>
props.isOpen
props.isOpen || props.isLoading
? props.theme.comboBox.button.focusBackgroundModernView
: props.theme.comboBox.button.backgroundModernView};
@ -23,7 +25,7 @@ const modernViewButton = css`
const hoverModernViewButton = css`
background: ${(props) =>
props.isOpen
props.isOpen || props.isLoading
? props.theme.comboBox.button.focusBackgroundModernView
: props.theme.comboBox.button.hoverBackgroundModernView} !important;
`;
@ -117,7 +119,9 @@ const StyledComboButton = styled.div`
? props.theme.comboBox.button.hoverBorderColorOpen
: props.theme.comboBox.button.hoverBorderColor};
cursor: ${(props) =>
props.isDisabled || (!props.containOptions && !props.withAdvancedOptions)
props.isDisabled ||
(!props.containOptions && !props.withAdvancedOptions) ||
props.isLoading
? "default"
: "pointer"};
@ -138,6 +142,7 @@ const StyledComboButton = styled.div`
}
}
.combo-button-label {
visibility: ${(props) => (props.isLoading ? "hidden" : "visible")};
margin-right: ${(props) =>
props.noBorder
? props.theme.comboBox.label.marginRight
@ -182,6 +187,8 @@ StyledComboButton.defaultProps = { theme: Base };
const StyledOptionalItem = styled.div`
margin-right: ${(props) => props.theme.comboBox.childrenButton.marginRight};
visibility: ${(props) => (props.isLoading ? "hidden" : "visible")};
path {
fill: ${(props) =>
props.defaultOption
@ -200,6 +207,8 @@ const StyledIcon = styled.div`
width: ${(props) => props.theme.comboBox.childrenButton.width};
height: ${(props) => props.theme.comboBox.childrenButton.height};
visibility: ${(props) => (props.isLoading ? "hidden" : "visible")};
.combo-button_selected-icon {
path {
fill: ${(props) =>
@ -227,6 +236,8 @@ const StyledArrowIcon = styled.div`
display: flex;
align-self: center;
visibility: ${(props) => (props.isLoading ? "hidden" : "visible")};
.combo-buttons_expander-icon {
path {
fill: ${(props) => props.theme.comboBox.label.selectedColor};
@ -253,12 +264,21 @@ const StyledArrowIcon = styled.div`
margin-left: auto;
`}
`;
StyledArrowIcon.defaultProps = { theme: Base };
const StyledLoader = styled(Loader)`
position: absolute;
margin-left: ${(props) =>
props.displaySize === "content" ? "-16px" : "-8px"};
margin-top: 2px;
`;
export {
StyledArrowIcon,
StyledIcon,
StyledOptionalItem,
StyledComboButton,
StyledTriangleDownIcon,
StyledLoader,
};