Merge pull request #1156 from ONLYOFFICE/feature/new-user-type-change
Feature/new user type change
This commit is contained in:
commit
6f3146ac3d
@ -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));
|
||||
|
@ -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));
|
@ -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}
|
||||
/>
|
||||
),
|
||||
];
|
||||
};
|
||||
|
||||
|
@ -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
|
||||
);
|
||||
|
@ -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>
|
||||
</>
|
||||
|
@ -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}
|
||||
/>
|
||||
);
|
||||
|
||||
|
@ -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([
|
||||
|
@ -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")}>
|
||||
|
@ -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,
|
||||
};
|
||||
}
|
||||
)(
|
||||
|
@ -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
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -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) => {
|
||||
|
@ -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
|
||||
|
@ -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,
|
||||
|
@ -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",
|
||||
});
|
||||
|
||||
/**
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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,
|
||||
};
|
||||
|
Loading…
Reference in New Issue
Block a user