Merge branch 'develop' into bugfix/smart-banner

This commit is contained in:
Viktor Fomin 2022-11-07 15:09:16 +05:00
commit 1cb56a31fe
51 changed files with 1041 additions and 654 deletions

View File

@ -44,14 +44,16 @@ public static class CustomHealthCheck
{
hcBuilder.AddMySql(connectionString.ConnectionString,
name: "mysqldb",
tags: new string[] { "mysqldb" });
tags: new string[] { "mysqldb" },
timeout: new TimeSpan(0, 0, 15));
}
if (string.Equals(connectionString.ProviderName, "Npgsql"))
{
hcBuilder.AddNpgSql(connectionString.ConnectionString,
name: "postgredb",
tags: new string[] { "postgredb" });
tags: new string[] { "postgredb" },
timeout: new TimeSpan(0, 0, 15));
}
var kafkaSettings = configurationExtension.GetSetting<KafkaSettings>("kafka");
@ -61,7 +63,9 @@ public static class CustomHealthCheck
hcBuilder.AddKafka(new ProducerConfig(clientConfig),
name: "kafka",
tags: new string[] { "kafka" });
tags: new string[] { "kafka" },
timeout: new TimeSpan(0,0,15)
);
}
@ -88,7 +92,8 @@ public static class CustomHealthCheck
{
hcBuilder.AddRedis(redisConfiguration.ConfigurationOptions.ToString(),
name: "redis",
tags: new string[] { "redis" });
tags: new string[] { "redis" },
timeout: new TimeSpan(0, 0, 15));
}
var rabbitMQConfiguration = configuration.GetSection("RabbitMQ").Get<RabbitMQSettings>();
@ -97,7 +102,8 @@ public static class CustomHealthCheck
{
hcBuilder.AddRabbitMQ(x => rabbitMQConfiguration.GetConnectionFactory(),
name: "rabbitMQ",
tags: new string[] { "rabbitMQ" });
tags: new string[] { "rabbitMQ" },
timeout: new TimeSpan(0, 0, 15));
}
return services;

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 9.4 KiB

After

Width:  |  Height:  |  Size: 9.5 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 12 KiB

After

Width:  |  Height:  |  Size: 9.4 KiB

View File

@ -9,8 +9,9 @@
"SubmenuHistory": "History",
"SubmenuDetails": "Details",
"RecentActivities": "Recent activities",
"UsersInRoom": "Users in room",
"ExpectPeople": "Expect people",
"RecentActivities": "Recent activities",
"Properties": "Properties",
"Data": "Data",

View File

@ -38,7 +38,7 @@
"SendRequest": "Send request",
"TotalPricePerMonth": "<1>{{currencySymbol}}</1><2>{{price}}</2><3>/month</3>",
"UpgradeNow": "Upgrade now",
"UserNotFound": "User <1>«{{email}}»</1> is not found",
"UserNotFound": "User <1>{{email}}</1> is not found",
"YourPrice": "Your price",
"PaymentOverdue": "Cannot add new users.",
"BusinessPlanPaymentOverdue": "Cannot add new users. Business plan payment overdue",

View File

@ -25,6 +25,7 @@
"SuccessChangeUserStatus": "The user status was successfully changed",
"SuccessDeletePersonalData": "Personal data has been successfully deleted",
"SuccessSentInvitation": "The invitation was successfully sent",
"SuccessSentMultipleInvitatios": "Invitations were successfully sent",
"maxSizeFileError": "Maximum file size exceeded",
"orDropFileHereLabel": "or drop a file here",
"selectNewPhotoLabel": "Select new photo"

View File

@ -9,8 +9,9 @@
"SubmenuHistory": "История",
"SubmenuDetails": "Детали",
"RecentActivities": "Недавние действия",
"UsersInRoom": "Пользователей в комнате",
"ExpectPeople": "Приглашенные люди",
"RecentActivities": "Недавние действия",
"Properties": "Cвойства",
"Data": "Данные",

View File

@ -3,7 +3,7 @@
"ActivateBusinessPlan": "Активировать {{planName}} план?",
"AdministratorDescription": "Настройка DocSpace, создание и администрирование комнат, возможность приглашать пользователей и управлять ими в DocSpace и в виртуальных комнатах, возможность управлять правами доступа.",
"Benefits": "Преимущества",
"PlanTitle": "Вы используете {{planName}} план",
"BusinessTitle": "Вы используете {{planName}} план",
"BusinessSuggestion": "Настройте свой {{planName}} план",
"BusinessFinalDateInfo": "Подписка будет автоматически продлена {{finalDate}} с обновленными ценами и техническими характеристиками. Вы можете отменить его или изменить свою платежную информацию на клиентский портал Stripe.",
"BusinessRequestDescription": "Тарифные планы с более чем {{peopleNumber}} менеджерами доступны только по запросу",
@ -37,6 +37,6 @@
"SendRequest": "Отправить запрос",
"TotalPricePerMonth": "<1>{{currencySymbol}}</1><2>{{price}}</2><3>/месяц</3>",
"UpgradeNow": "Обновить прямо сейчас",
"UserNotFound": "Пользователь <1>«{{email}}»</1> не найден",
"UserNotFound": "Пользователь <1>{{email}}</1> не найден",
"YourPrice": "Ваша стоимость"
}

View File

@ -23,6 +23,7 @@
"SuccessChangeUserStatus": "Статус пользователя успешно изменен",
"SuccessDeletePersonalData": "Персональные данные успешно удалены",
"SuccessSentInvitation": "Приглашение было успешно отправлено",
"SuccessSentMultipleInvitatios": "Приглашения были успешно отправлены",
"maxSizeFileError": "Превышен максимальный размер файла",
"orDropFileHereLabel": "или перетащите файл сюда",
"selectNewPhotoLabel": "Выбрать новое фото"

View File

@ -104,7 +104,6 @@ const RenameEvent = ({
clearTimeout(timerId);
timerId = null;
clearActiveOperations(null, [item.id]);
onClose();
});
}, []);

View File

@ -28,6 +28,7 @@ import { getLink, checkIfModuleOld, onItemClick } from "SRC_DIR/helpers/utils";
import StyledExternalLinkIcon from "@docspace/client/src/components/StyledExternalLinkIcon";
import HeaderCatalogBurger from "./header-catalog-burger";
import { Base } from "@docspace/components/themes";
import { ReactSVG } from "react-svg";
const { proxyURL } = AppServerConfig;
@ -57,6 +58,12 @@ const Header = styled.header`
transform: translateX(50%);
height: 24px;
cursor: pointer;
svg {
path:last-child {
fill: ${(props) => props.theme.client.home.logoColor};
}
}
}
.mobile-short-logo {
width: 146px;
@ -225,7 +232,15 @@ const HeaderComponent = ({
!isFormGallery && <HeaderCatalogBurger onClick={toggleArticleOpen} />}
<LinkWithoutRedirect className="header-logo-wrapper" to={defaultPage}>
{!isPersonal ? (
<img alt="logo" src={props.logoUrl} className="header-logo-icon" />
props.logoUrl.includes(".svg") ? (
<ReactSVG src={props.logoUrl} className="header-logo-icon" />
) : (
<img
alt="logo"
src={props.logoUrl}
className="header-logo-icon"
/>
)
) : (
<img
alt="logo"

View File

@ -35,6 +35,7 @@ const InvitePanel = ({
adminLink,
defaultAccess,
inviteUsers,
reloadSelectionParentRoom,
}) => {
const [selectedRoom, setSelectedRoom] = useState(null);
const [hasErrors, setHasErrors] = useState(false);
@ -159,6 +160,7 @@ const InvitePanel = ({
: await setRoomSecurity(roomId, data);
onClose();
toastr.success(`Users invited`);
reloadSelectionParentRoom();
} catch (err) {
toastr.error(err);
}
@ -225,6 +227,7 @@ export default inject(({ auth, peopleStore, filesStore, dialogsStore }) => {
const { theme } = auth.settingsStore;
const { getUsersByQuery, inviteUsers } = peopleStore.usersStore;
const { reloadSelectionParentRoom } = auth.infoPanelStore;
const {
getPortalInviteLinks,
@ -265,6 +268,7 @@ export default inject(({ auth, peopleStore, filesStore, dialogsStore }) => {
guestLink,
adminLink,
inviteUsers,
reloadSelectionParentRoom,
};
})(
withTranslation([

View File

@ -57,6 +57,9 @@ const StyledAboutBody = styled.div`
}
.logo-docspace-theme {
height: 24px;
width: 211px;
svg {
path:nth-child(4) {
fill: ${(props) => props.theme.client.about.logoColor};
@ -107,7 +110,7 @@ const AboutContent = (props) => {
className="logo-theme no-select"
/>
) : (
<ReactSVG
<img
src={docSpaceLogo}
alt="Logo"
className="logo-docspace-theme no-select"

View File

@ -6,46 +6,51 @@ const excludeOptionsIntoFolder = ["open", "separator0", "separator1"];
class ContextHelper {
constructor(props) {
this.t = props.t;
this.selection = { ...props.selection };
this.isUser = props.isUser;
this.selection = props.selection;
this.getContextOptions = props.getContextOptions;
this.getUserContextOptions = props.getUserContextOptions;
this.getContextOptionActions = props.getContextOptionActions;
this.selectedFolderId = props.selectedFolderId;
if (this.selection) this.fixItemContextOptions();
}
fixItemContextOptions = () => {
if (this.isUser) {
if (!this.selection?.options) return;
const newOptions = this.selection.options.filter(
(option) => option !== "details"
);
this.selection.options = newOptions;
return;
}
const options = this.getContextOptions(this.selection, false);
excludeGeneralOptions.forEach((excludeOption) => {
const idx = options.findIndex((o) => o === excludeOption);
if (idx !== -1) options.splice(idx, 1);
});
if (this.selection?.isRoom) {
excludeRoomOptions.forEach((excludeOption) => {
const idx = options.findIndex((o) => o === excludeOption);
if (idx !== -1) options.splice(idx, 1);
});
if (this.selection.id === this.selectedFolderId) {
if (this.selection.isSelectedFolder) {
excludeOptionsIntoRoom.forEach((excludeOption) => {
const idx = options.findIndex((o) => o === excludeOption);
if (idx !== -1) options.splice(idx, 1);
});
}
} else if (this.selection?.isFolder) {
if (this.selection.id === this.selectedFolderId) {
excludeOptionsIntoFolder.forEach((excludeOption) => {
const idx = options.findIndex((o) => o === excludeOption);
}
if (idx !== -1) options.splice(idx, 1);
});
}
if (this.selection?.isSelectedFolder) {
excludeOptionsIntoFolder.forEach((excludeOption) => {
const idx = options.findIndex((o) => o === excludeOption);
if (idx !== -1) options.splice(idx, 1);
});
}
const length = options.length;
@ -76,7 +81,13 @@ class ContextHelper {
};
getItemContextOptions = () => {
return this.getContextOptionActions(this.selection, this.t);
return this.isUser
? this.getUserContextOptions(
this.t,
this.selection.options || [],
this.selection
)
: this.getContextOptionActions(this.selection, this.t);
};
}

View File

@ -0,0 +1,118 @@
import {
ShareAccessRights,
EmployeeType,
RoomsType,
} from "@docspace/common/constants";
class MembersHelper {
constructor(props) {
this.t = props.t;
}
getOptions = () => {
return {
docSpaceAdmin: {
key: "docSpaceAdmin",
label: this.t("Common:DocSpaceAdmin"),
access: ShareAccessRights.FullAccess,
},
roomAdmin: {
key: "roomAdmin",
label: this.t("Common:RoomAdmin"),
access: ShareAccessRights.RoomManager,
},
viewer: {
key: "viewer",
label: this.t("Translations:RoleViewer"),
access: ShareAccessRights.ReadOnly,
},
editor: {
key: "editor",
label: this.t("Translations:RoleEditor"),
access: ShareAccessRights.Editing,
},
formFiller: {
key: "formFiller",
label: this.t("Translations:RoleFormFiller"),
access: ShareAccessRights.FormFilling,
},
reviewer: {
key: "reviewer",
label: this.t("Translations:RoleReviewer"),
access: ShareAccessRights.Review,
},
commentator: {
key: "commentator",
label: this.t("Translations:RoleCommentator"),
access: ShareAccessRights.Comment,
},
};
};
getOptionsByRoomType = (roomType, withDeleteOption = false) => {
if (!roomType) return;
const options = this.getOptions();
const deleteOption = withDeleteOption
? [
{ key: "s2", isSeparator: true },
{
key: "remove",
label: this.t("Translations:Remove"),
access: ShareAccessRights.None,
},
]
: [];
switch (roomType) {
case RoomsType.FillingFormsRoom:
return [
options.roomAdmin,
options.formFiller,
options.viewer,
...deleteOption,
];
case RoomsType.EditingRoom:
return [
options.roomAdmin,
options.editor,
options.viewer,
...deleteOption,
];
case RoomsType.ReviewRoom:
return [
options.roomAdmin,
options.reviewer,
options.commentator,
options.viewer,
...deleteOption,
];
case RoomsType.ReadOnlyRoom:
return [options.roomAdmin, options.viewer, ...deleteOption];
case RoomsType.CustomRoom:
return [
options.roomAdmin,
options.editor,
options.formFiller,
options.reviewer,
options.commentator,
options.viewer,
...deleteOption,
];
}
};
getOptionByUserAccess = (access) => {
if (!access) return;
const options = this.getOptions();
const [userOption] = Object.values(options).filter(
(opt) => opt.access === access
);
return userOption;
};
}
export default MembersHelper;

View File

@ -9,12 +9,11 @@ import { StyledInfoPanelBody } from "./styles/common";
import { getRoomInfo } from "@docspace/common/api/rooms";
const InfoPanelBodyContent = ({
t,
selection,
setSelection,
updateSelection,
setUpdateSelection,
calculateSelection,
normalizeSelection,
isItemChanged,
selectionParentRoom,
setSelectionParentRoom,
roomsView,
@ -24,10 +23,7 @@ const InfoPanelBodyContent = ({
getIsAccounts,
getIsGallery,
gallerySelected,
setBufferSelection,
isRootFolder,
getIcon,
getFolderIcon,
...props
}) => {
const [selectedItems, setSelectedItems] = useState(props.selectedItems);
@ -37,9 +33,7 @@ const InfoPanelBodyContent = ({
const isRooms = getIsRooms();
const isAccounts = getIsAccounts();
const isGallery = getIsGallery();
const isSeveralItems = props.selectedItems.length > 1;
const isNoItem =
(isGallery && !gallerySelected) ||
(!selection?.title && !isSeveralItems && !isAccounts) ||
@ -47,61 +41,25 @@ const InfoPanelBodyContent = ({
selection?.isSelectedFolder &&
!selection?.wasContextMenuSelection);
const viewHelper = new ViewHelper({
defaultProps: {
selection,
isFiles,
isRooms,
isAccounts,
isGallery,
isRootFolder,
personal: props.personal,
culture: props.culture,
},
detailsProps: {},
membersProps: {
selectionParentRoom,
setSelectionParentRoom,
selfId: props.selfId,
isOwner: props.isOwner,
isAdmin: props.isAdmin,
getRoomMembers: props.getRoomMembers,
changeUserType: props.changeUserType,
setInvitePanelOptions: props.setInvitePanelOptions,
canInviteUserInRoom: props.canInviteUserInRoom,
},
historyProps: {
selectedFolder: selectedFolder,
},
accountsProps: {
selfId: props.selfId,
isOwner: props.isOwner,
isAdmin: props.isAdmin,
changeUserType: props.changeUserType,
canChangeUserType: props.canChangeUserType,
},
galleryProps: {
getIcon,
gallerySelected,
},
});
const getSelection = () => {
return selectedItems.length === 0
? normalizeSelection({
...selectedFolder,
isSelectedFolder: true,
isSelectedItem: false,
})
: selectedItems.length === 1
? normalizeSelection({
...selectedItems[0],
isSelectedFolder: false,
isSelectedItem: true,
})
: [...Array(props.selectedItems.length).keys()];
const defaultProps = {
selection,
isFiles,
isRooms,
isAccounts,
isGallery,
isRootFolder,
isSeveralItems,
};
const viewHelper = new ViewHelper({
defaultProps: defaultProps,
detailsProps: {},
membersProps: {},
historyProps: { selectedFolder },
accountsProps: {},
galleryProps: {},
});
const getView = () => {
if (isNoItem) return viewHelper.NoItemView();
if (isSeveralItems) return viewHelper.SeveralItemsView();
@ -123,39 +81,18 @@ const InfoPanelBodyContent = ({
//////////////////////////////////////////////////////////
// Removing mark set with choosing item from context menu
// for it to updated after selctedItems or selectedFolder change
// (only for non-oforms items)
useEffect(() => {
if (selection && selection.isContextMenuSelection)
setSelection({ ...selection, isContextMenuSelection: false });
}, [selection]);
// Setting selection after selectedItems or selectedFolder update
useEffect(() => {
if (selection?.isContextMenuSelection) return;
const newSelection = getSelection();
if (
selection?.id === newSelection.id &&
selection?.isFolder === newSelection.isFolder &&
!newSelection.length
)
return;
setSelection(normalizeSelection(newSelection));
}, [selectedItems, selectedFolder]);
//////////////////////////////////////////////////////////
// Updating SelectedItems only if
// a) Length of an array changed
// b) Single chosen item changed
useEffect(() => {
const selectedItemsLengthChanged =
selectedItems.length !== props.selectedItems.length;
const singleSelectedItemChanged =
selectedItems[0]?.id !== props.selectedItems[0]?.id;
selectedItems[0] &&
props.selectedItems[0] &&
isItemChanged(selectedItems[0], props.selectedItems[0]);
if (selectedItemsLengthChanged || singleSelectedItemChanged)
setSelectedItems(props.selectedItems);
}, [props.selectedItems]);
@ -163,29 +100,39 @@ const InfoPanelBodyContent = ({
// Updating SelectedFolder only if
// a) Selected folder changed
useEffect(() => {
if (selectedFolder.id !== props.selectedFolder.id)
setSelectedFolder(props.selectedFolder);
const selectedFolderChanged = isItemChanged(
selectedFolder,
props.selectedFolder
);
if (selectedFolderChanged) setSelectedFolder(props.selectedFolder);
}, [props.selectedFolder]);
// Updating selectionParentRoom after selectFolder change
// if it is located in another room
useEffect(async () => {
if (!isRooms) return;
if (selection?.isRoom && roomsView === "members") return;
const currentFolderRoomId =
selectedFolder?.pathParts && selectedFolder.pathParts[1];
const storeRoomId = selectionParentRoom?.id;
if (!currentFolderRoomId) return;
if (currentFolderRoomId === storeRoomId) return;
if (!currentFolderRoomId || currentFolderRoomId === storeRoomId) return;
const newSelectionParentRoom = await getRoomInfo(currentFolderRoomId);
if (storeRoomId !== newSelectionParentRoom.id)
setSelectionParentRoom(normalizeSelection(newSelectionParentRoom));
if (storeRoomId === newSelectionParentRoom.id) return;
setSelectionParentRoom(normalizeSelection(newSelectionParentRoom));
}, [selectedFolder]);
//////////////////////////////////////////////////////////
// Setting selection after selectedItems or selectedFolder update
useEffect(() => {
setSelection(calculateSelection());
}, [selectedItems, selectedFolder]);
//////////////////////////////////////////////////////////
// useEffect(() => {
// console.log("\nfor-dev Selected items: ", selectedItems);
// console.log("\nfor-dev Selected folder: ", selectedFolder);
@ -198,156 +145,52 @@ const InfoPanelBodyContent = ({
return (
<StyledInfoPanelBody>
{!isNoItem && (
<ItemTitle
selection={selection}
selectionParentRoom={selectionParentRoom}
roomsView={roomsView}
isRooms={isRooms}
isAccounts={isAccounts}
isSeveralItems={isSeveralItems}
severalItemsLength={selectedItems.length}
isGallery={isGallery}
getIcon={getIcon}
setBufferSelection={setBufferSelection}
getContextOptions={props.getContextOptions}
getContextOptionActions={props.getContextOptionActions}
getUserContextOptions={props.getUserContextOptions}
selectedFolderId={selectedFolder.id}
/>
<ItemTitle {...defaultProps} selectionLength={selectedItems.length} />
)}
{getView()}
</StyledInfoPanelBody>
);
};
export default inject(
({
auth,
filesStore,
settingsStore,
filesActionsStore,
dialogsStore,
selectedFolderStore,
oformsStore,
contextOptionsStore,
peopleStore,
accessRightsStore,
}) => {
const { isOwner, isAdmin, id: selfId } = auth.userStore.user;
const { personal, culture } = auth.settingsStore;
const { getIcon, getFolderIcon } = settingsStore;
const { onSelectItem, openLocationAction } = filesActionsStore;
const { changeType: changeUserType } = peopleStore;
const { setSharingPanelVisible, setInvitePanelOptions } = dialogsStore;
const { isRootFolder } = selectedFolderStore;
const { gallerySelected } = oformsStore;
const {
getFilesContextOptions: getContextOptionActions,
} = contextOptionsStore;
const { canChangeUserType, canInviteUserInRoom } = accessRightsStore;
export default inject(({ auth, selectedFolderStore }) => {
const {
selection,
setSelection,
calculateSelection,
normalizeSelection,
isItemChanged,
selectionParentRoom,
setSelectionParentRoom,
roomsView,
fileView,
getIsFiles,
getIsRooms,
getIsAccounts,
getIsGallery,
} = auth.infoPanelStore;
const {
selection,
setSelection,
updateSelection,
setUpdateSelection,
selectionParentRoom,
setSelectionParentRoom,
normalizeSelection,
roomsView,
fileView,
getItemIcon,
getIsFiles,
getIsRooms,
getIsAccounts,
getIsGallery,
} = auth.infoPanelStore;
const { isRootFolder } = selectedFolderStore;
const {
selection: filesStoreSelection,
getFilesContextOptions: getContextOptions,
setBufferSelection,
getFolderInfo,
getShareUsers,
getRoomMembers,
getHistory,
getRoomHistory,
getFileHistory,
createThumbnail,
} = filesStore;
const selectedItems = auth.infoPanelStore.getSelectedItems();
const selectedFolder = auth.infoPanelStore.getSelectedFolder();
const {
selection: peopleStoreSelection,
bufferSelection: peopleStoreBufferSelection,
} = peopleStore.selectionStore;
const { getUserContextOptions } = peopleStore.contextOptionsStore;
return {
selection,
setSelection,
calculateSelection,
normalizeSelection,
isItemChanged,
setSelectionParentRoom,
roomsView,
fileView,
getIsFiles,
getIsRooms,
getIsAccounts,
getIsGallery,
const selectedFiles =
filesStoreSelection?.length > 0 ? [...filesStoreSelection] : [];
const selectedUsers = peopleStoreSelection.length
? [...peopleStoreSelection]
: peopleStoreBufferSelection
? [peopleStoreBufferSelection]
: [];
selectedItems,
selectedFolder,
const selectedItems = getIsAccounts() ? selectedUsers : selectedFiles;
const selectedFolder = {
...selectedFolderStore,
isFolder: true,
isRoom: !!selectedFolderStore.roomType,
};
return {
selfId,
isOwner,
isAdmin,
personal,
culture,
selection,
setSelection,
updateSelection,
setUpdateSelection,
selectionParentRoom,
setSelectionParentRoom,
normalizeSelection,
roomsView,
fileView,
getItemIcon,
getIsFiles,
getIsRooms,
getIsAccounts,
getIsGallery,
selectedItems,
selectedFolder,
setBufferSelection,
getContextOptions,
getContextOptionActions,
getUserContextOptions,
getFolderInfo,
onSelectItem,
getShareUsers,
getRoomMembers,
changeUserType,
getHistory,
getRoomHistory,
getFileHistory,
setSharingPanelVisible,
setInvitePanelOptions,
getIcon,
getFolderIcon,
createThumbnail,
openLocationAction,
gallerySelected,
isRootFolder,
canChangeUserType,
canInviteUserInRoom,
};
}
)(withRouter(observer(InfoPanelBodyContent)));
isRootFolder,
};
})(withRouter(observer(InfoPanelBodyContent)));

View File

@ -6,7 +6,8 @@ const StyledUserTypeHeader = styled.div`
display: flex;
align-items: center;
justify-content: space-between;
padding: 8px 0 12px;
padding-top: ${(props) => (props.isExpect ? "20px" : "8px")};
padding-bottom: 12px;
.title {
font-weight: 600;
@ -20,6 +21,13 @@ const StyledUserTypeHeader = styled.div`
rect {
fill: ${(props) => props.theme.infoPanel.members.iconColor};
}
&:hover {
path,
rect {
fill: ${(props) => props.theme.infoPanel.members.iconHoverColor};
}
}
}
`;
@ -35,15 +43,17 @@ const StyledUser = styled.div`
padding: 8px 0;
.avatar {
opacity: ${(props) => (props.isExpect ? 0.5 : 1)};
min-width: 32px;
min-height: 32px;
}
.name {
opacity: ${(props) => (props.isExpect ? 0.5 : 1)};
${(props) =>
props.isExpect && `color: ${props.theme.infoPanel.members.isExpectName}`};
font-weight: 600;
font-size: 14px;
line-height: 16px;
white-space: nowrap;
overflow: hidden;
@ -53,6 +63,7 @@ const StyledUser = styled.div`
.me-label {
font-weight: 600;
font-size: 14px;
line-height: 16px;
color: ${(props) => props.theme.infoPanel.members.meLabelColor};
margin-left: -8px;
}

View File

@ -1,44 +1,47 @@
import React from "react";
import React, { useRef } from "react";
import { withTranslation } from "react-i18next";
import Text from "@docspace/components/text";
import ContextMenuButton from "@docspace/components/context-menu-button";
import { Avatar } from "@docspace/components";
import { Avatar, ContextMenuButton } from "@docspace/components";
import Badges from "@docspace/client/src/pages/AccountsHome/Section/Body/Badges";
import { StyledAccountsItemTitle } from "../../styles/accounts";
import { StyledTitle } from "../../styles/common";
import ItemContextOptions from "./ItemContextOptions";
const AccountsItemTitle = ({
t,
isSeveralItems,
selection,
getUserContextOptions,
severalItemsLength,
selectionLength,
}) => {
const isPending =
selection.statusType === "pending" || selection.statusType === "disabled";
const getData = () => {
const newOptions = selection.options.filter(
(option) => option !== "details"
);
return getUserContextOptions(t, newOptions, selection);
};
if (isSeveralItems) {
return (
<StyledTitle>
<Avatar size={"min"} role={"user"} />
<Text className="text" fontWeight={600} fontSize="16px">
{`${t("InfoPanel:SelectedUsers")}: ${severalItemsLength}`}
{`${t("InfoPanel:SelectedUsers")}: ${selectionLength}`}
</Text>
</StyledTitle>
);
}
const itemTitleRef = useRef();
const isPending =
selection.statusType === "pending" || selection.statusType === "disabled";
const getData = () => {
const newOptions = selection.options?.filter(
(option) => option !== "details"
);
return getUserContextOptions(t, newOptions || [], selection);
};
const contextOptions = getData();
return (
<StyledAccountsItemTitle isPending={isPending}>
<StyledAccountsItemTitle isPending={isPending} ref={itemTitleRef}>
<Avatar
className="avatar"
role={selection.role ? selection.role : "user"}
@ -67,7 +70,9 @@ const AccountsItemTitle = ({
<Badges withoutPaid={true} statusType={selection.statusType} />
)}
</div>
<ContextMenuButton className="context-button" getData={getData} />
{!!contextOptions.length && (
<ContextMenuButton className="context-button" getData={getData} />
)}
</StyledAccountsItemTitle>
);
};

View File

@ -1,4 +1,5 @@
import React, { useRef } from "react";
import { inject, observer } from "mobx-react";
import { withTranslation } from "react-i18next";
import { ReactSVG } from "react-svg";
@ -10,19 +11,13 @@ import { StyledTitle } from "../../styles/common";
const FilesItemTitle = ({
t,
selection,
isSeveralItems,
setBufferSelection,
getIcon,
getContextOptions,
getContextOptionActions,
severalItemsLength,
selectedFolderId,
selectionLength,
}) => {
const itemTitleRef = useRef();
if (isSeveralItems)
return (
<StyledTitle>
@ -30,13 +25,11 @@ const FilesItemTitle = ({
<ReactSVG className="icon" src={getIcon(32, ".file")} />
</div>
<Text className="text">
{`${t("InfoPanel:ItemsSelected")}: ${severalItemsLength}`}
{`${t("InfoPanel:ItemsSelected")}: ${selectionLength}`}
</Text>
</StyledTitle>
);
const itemTitleRef = useRef();
return (
<StyledTitle ref={itemTitleRef}>
<div className="item-icon">
@ -52,10 +45,6 @@ const FilesItemTitle = ({
t={t}
itemTitleRef={itemTitleRef}
selection={selection}
setBufferSelection={setBufferSelection}
getContextOptions={getContextOptions}
getContextOptionActions={getContextOptionActions}
selectedFolderId={selectedFolderId}
/>
)}
</StyledTitle>
@ -68,4 +57,4 @@ export default withTranslation([
"Translations",
"InfoPanel",
"SharingPanel",
])(FilesItemTitle);
])(observer(FilesItemTitle));

View File

@ -1,11 +1,8 @@
import React, { useRef, useEffect } from "react";
import { inject, observer } from "mobx-react";
import styled from "styled-components";
import {
ContextMenu,
ContextMenuButton,
IconButton,
} from "@docspace/components";
import { ContextMenu, ContextMenuButton } from "@docspace/components";
import ContextHelper from "../../helpers/ContextHelper";
@ -14,23 +11,30 @@ const StyledItemContextOptions = styled.div`
`;
const ItemContextOptions = ({
t,
selection,
getContextOptions,
getContextOptionActions,
getUserContextOptions,
setBufferSelection,
isUser = false,
itemTitleRef,
selectedFolderId,
...props
}) => {
if (!selection) return null;
const contextMenuRef = useRef();
const contextHelper = new ContextHelper({
t,
isUser,
selection,
selectedFolderId,
...props,
getContextOptions,
getContextOptionActions,
getUserContextOptions,
});
const setItemAsBufferSelection = () => setBufferSelection(selection);
if (!selection) return null;
const onContextMenu = (e) => {
e.button === 2;
@ -43,12 +47,13 @@ const ItemContextOptions = ({
}, [selection]);
const options = contextHelper.getItemContextOptions();
const getData = () => options;
return (
<StyledItemContextOptions onClick={setItemAsBufferSelection}>
<StyledItemContextOptions onClick={() => setBufferSelection(selection)}>
<ContextMenu
ref={contextMenuRef}
getContextModel={contextHelper.getItemContextOptions}
getContextModel={getData}
withBackdrop={false}
/>
{options.length > 0 && (
@ -56,7 +61,7 @@ const ItemContextOptions = ({
className="expandButton"
title={"Show item actions"}
onClick={onContextMenu}
getData={contextHelper.getItemContextOptions}
getData={getData}
directionX="right"
isNew={true}
/>
@ -65,4 +70,20 @@ const ItemContextOptions = ({
);
};
export default ItemContextOptions;
export default inject(({ filesStore, peopleStore, contextOptionsStore }) => {
const { getUserContextOptions } = peopleStore.contextOptionsStore;
const {
setBufferSelection,
getFilesContextOptions: getContextOptions,
} = filesStore;
const {
getFilesContextOptions: getContextOptionActions,
} = contextOptionsStore;
return {
setBufferSelection,
getContextOptions,
getContextOptionActions,
getUserContextOptions,
};
})(observer(ItemContextOptions));

View File

@ -1,4 +1,5 @@
import React from "react";
import { inject, observer } from "mobx-react";
import AccountsItemTitle from "./AccountsItemTitle";
import FilesItemTitle from "./FilesItemTitle";
@ -6,23 +7,15 @@ import GalleryItemTitle from "./GalleryItemTitle";
const ItemTitle = ({
selection,
selectionParentRoom,
roomsView,
isRooms,
isAccounts,
isGallery,
isSeveralItems,
selectedFolderId,
setBufferSelection,
selectionLength,
selectionParentRoom,
roomsView,
getIcon,
getContextOptions,
getContextOptionActions,
getUserContextOptions,
severalItemsLength,
}) => {
if (!selection) return null;
@ -32,7 +25,7 @@ const ItemTitle = ({
selection={selection}
isSeveralItems={isSeveralItems}
getUserContextOptions={getUserContextOptions}
severalItemsLength={severalItemsLength}
selectionLength={selectionLength}
/>
);
@ -50,16 +43,23 @@ const ItemTitle = ({
return (
<FilesItemTitle
severalItemsLength={severalItemsLength}
selectionLength={selectionLength}
selection={filesItemSelection}
isSeveralItems={isSeveralItems}
setBufferSelection={setBufferSelection}
getIcon={getIcon}
getContextOptions={getContextOptions}
getContextOptionActions={getContextOptionActions}
selectedFolderId={selectedFolderId}
/>
);
};
export default ItemTitle;
export default inject(({ auth, settingsStore, peopleStore }) => {
const { selectionParentRoom, roomsView } = auth.infoPanelStore;
const { getIcon } = settingsStore;
const { getUserContextOptions } = peopleStore.contextOptionsStore;
return {
getUserContextOptions,
selectionParentRoom,
roomsView,
getIcon,
};
})(observer(ItemTitle));

View File

@ -1,4 +1,5 @@
import React from "react";
import { inject, observer } from "mobx-react";
import { withTranslation } from "react-i18next";
import withLoader from "@docspace/client/src/HOCs/withLoader";
@ -17,7 +18,6 @@ const Accounts = ({
isAdmin,
changeUserType,
canChangeUserType,
selfId,
}) => {
const [statusLabel, setStatusLabel] = React.useState("");
@ -185,15 +185,33 @@ const Accounts = ({
);
};
export default withTranslation([
"People",
"InfoPanel",
"ConnectDialog",
"Common",
"PeopleTranslations",
"People",
"Settings",
"SmartBanner",
"DeleteProfileEverDialog",
"Translations",
])(withLoader(Accounts)(<Loaders.InfoPanelViewLoader view="accounts" />));
export default inject(({ auth, peopleStore, accessRightsStore }) => {
const { isOwner, isAdmin, id: selfId } = auth.userStore.user;
const { changeType: changeUserType } = peopleStore;
const { canChangeUserType } = accessRightsStore;
return {
isOwner,
isAdmin,
changeUserType,
selfId,
canChangeUserType,
};
})(
withTranslation([
"People",
"InfoPanel",
"ConnectDialog",
"Common",
"PeopleTranslations",
"People",
"Settings",
"SmartBanner",
"DeleteProfileEverDialog",
"Translations",
])(
withLoader(observer(Accounts))(
<Loaders.InfoPanelViewLoader view="accounts" />
)
)
);

View File

@ -16,7 +16,7 @@ const Details = ({
personal,
culture,
createThumbnail,
getItemIcon,
getInfoPanelItemIcon,
openUser,
}) => {
const [itemProperties, setItemProperties] = useState([]);
@ -68,7 +68,7 @@ const Details = ({
className={`no-thumbnail-img ${selection.isRoom && "is-room"} ${
selection.isRoom && selection.logo?.large && "custom-logo"
}`}
src={getItemIcon(selection, 96)}
src={getInfoPanelItemIcon(selection, 96)}
alt="thumbnail-icon-big"
/>
</StyledNoThumbnail>
@ -95,7 +95,7 @@ const Details = ({
};
export default inject(({ auth, filesStore }) => {
const { selection, getItemIcon, openUser } = auth.infoPanelStore;
const { selection, getInfoPanelItemIcon, openUser } = auth.infoPanelStore;
const { createThumbnail } = filesStore;
const { personal, culture } = auth.settingsStore;
@ -104,7 +104,7 @@ export default inject(({ auth, filesStore }) => {
culture,
selection,
createThumbnail,
getItemIcon,
getInfoPanelItemIcon,
openUser,
};
})(withTranslation(["InfoPanel", "Common", "Translations"])(Details));

View File

@ -1,4 +1,5 @@
import React from "react";
import { inject, observer } from "mobx-react";
import { withTranslation } from "react-i18next";
import { ReactSVG } from "react-svg";
@ -63,9 +64,20 @@ const Gallery = ({ t, gallerySelected, getIcon, culture, personal }) => {
);
};
export default withTranslation([
"InfoPanel",
"FormGallery",
"Common",
"Translations",
])(withLoader(Gallery)(<Loaders.InfoPanelViewLoader view="gallery" />));
export default inject(({ auth, settingsStore, oformsStore }) => {
const { personal, culture } = auth.settingsStore;
const { gallerySelected } = oformsStore;
const { getIcon } = settingsStore;
return {
getIcon,
gallerySelected,
personal,
culture,
};
})(
withTranslation(["InfoPanel", "FormGallery", "Common", "Translations"])(
withLoader(observer(Gallery))(
<Loaders.InfoPanelViewLoader view="gallery" />
)
)
);

View File

@ -13,7 +13,7 @@ import { RoomsType } from "@docspace/common/constants";
export const HistoryBlockItemList = ({
t,
items,
getItemIcon,
getInfoPanelItemIcon,
checkAndOpenLocationAction,
}) => {
const [isShowMore, setIsShowMore] = useState(items.length <= 3);
@ -39,7 +39,7 @@ export const HistoryBlockItemList = ({
if (!isShowMore && i > 2) return null;
return (
<StyledHistoryBlockFile isRoom={item.isRoom} key={i}>
<ReactSVG className="icon" src={getItemIcon(item, 24)} />
<ReactSVG className="icon" src={getInfoPanelItemIcon(item, 24)} />
<div className="item-title">
<span className="name">{item.title}</span>
{item.fileExst && <span className="exst">{item.fileExst}</span>}

View File

@ -5,11 +5,11 @@ import Link from "@docspace/components/link";
import { StyledUserNameLink } from "../../styles/history";
const HistoryBlockUser = ({ user, withComma, openUser }) => {
const username = user.displayName || user.email;
const username = user.displayName;
const history = useHistory();
const onUserClick = () => {
openUser(user.id, history);
openUser(user, history);
};
return (

View File

@ -1,5 +1,5 @@
import React, { useState, useEffect } from "react";
import { inject } from "mobx-react";
import { inject, observer } from "mobx-react";
import { withTranslation } from "react-i18next";
import {
@ -15,6 +15,7 @@ import HistoryBlockMessage from "./HistoryBlockMessage";
import HistoryBlockItemList from "./HistoryBlockItemList";
import Loaders from "@docspace/common/components/Loaders";
import HistoryBlockUser from "./HistoryBlockUser";
import { FeedItemTypes } from "@docspace/common/constants";
const History = ({
t,
@ -24,7 +25,7 @@ const History = ({
selectedFolder,
selectionParentRoom,
setSelection,
getItemIcon,
getInfoPanelItemIcon,
getHistory,
checkAndOpenLocationAction,
openUser,
@ -32,6 +33,21 @@ const History = ({
const [history, setHistory] = useState(null);
const [showLoader, setShowLoader] = useState(false);
const fetchHistory = async (itemId) => {
let module = "files";
if (selection.isRoom) module = "rooms";
else if (selection.isFolder) module = "folders";
let timerId = setTimeout(() => setShowLoader(true), 1500);
let fetchedHistory = await getHistory(module, itemId);
fetchedHistory = parseHistoryJSON(fetchedHistory);
clearTimeout(timerId);
setHistory(fetchedHistory);
setSelection({ ...selection, history: fetchedHistory });
setShowLoader(false);
};
const parseHistoryJSON = (fetchedHistory) => {
let feeds = fetchedHistory.feeds;
let newFeeds = [];
@ -59,21 +75,6 @@ const History = ({
return { ...fetchedHistory, feeds: newFeeds };
};
const fetchHistory = async (itemId) => {
let module = "files";
if (selection.isRoom) module = "rooms";
else if (selection.isFolder) module = "folders";
let timerId = setTimeout(() => setShowLoader(true), 1500);
let fetchedHistory = await getHistory(module, itemId);
fetchedHistory = parseHistoryJSON(fetchedHistory);
clearTimeout(timerId);
setHistory(fetchedHistory);
setSelection({ ...selection, history: fetchedHistory });
setShowLoader(false);
};
useEffect(async () => {
if (selection.history) {
setHistory(selection.history);
@ -93,7 +94,7 @@ const History = ({
{history.feeds.map((feed) => (
<StyledHistoryBlock
key={feed.json.Id}
isUserAction={feed.json.Item === "sharedRoom" && feed.target}
isUserAction={feed.json.Item === FeedItemTypes.User && feed.target}
>
<Avatar
role="user"
@ -134,16 +135,17 @@ const History = ({
selectionParentRoom={selectionParentRoom}
/>
{(feed.json.Item === "file" || feed.json.Item === "folder") && (
{(feed.json.Item === FeedItemTypes.File ||
feed.json.Item === FeedItemTypes.Folder) && (
<HistoryBlockItemList
t={t}
items={[feed.json, ...feed.groupedFeeds]}
getItemIcon={getItemIcon}
getInfoPanelItemIcon={getInfoPanelItemIcon}
checkAndOpenLocationAction={checkAndOpenLocationAction}
/>
)}
{feed.json.Item === "sharedRoom" &&
{feed.json.Item === FeedItemTypes.User &&
feed.target &&
[feed.target, ...feed.groupedFeeds].map((user, i) => (
<HistoryBlockUser
@ -166,7 +168,7 @@ export default inject(({ auth, filesStore, filesActionsStore }) => {
selection,
selectionParentRoom,
setSelection,
getItemIcon,
getInfoPanelItemIcon,
openUser,
} = auth.infoPanelStore;
const { personal, culture } = auth.settingsStore;
@ -180,9 +182,9 @@ export default inject(({ auth, filesStore, filesActionsStore }) => {
selection,
selectionParentRoom,
setSelection,
getItemIcon,
getInfoPanelItemIcon,
getHistory,
checkAndOpenLocationAction,
openUser,
};
})(withTranslation(["InfoPanel", "Common", "Translations"])(History));
})(withTranslation(["InfoPanel", "Common", "Translations"])(observer(History)));

View File

@ -1,111 +1,111 @@
import React from "react";
import React, { useState } from "react";
import { StyledUser } from "../../styles/members";
import Avatar from "@docspace/components/avatar";
import { ComboBox } from "@docspace/components";
import { ShareAccessRights } from "@docspace/common/constants";
const User = ({
t,
user,
isOwner,
isAdmin,
selfId,
isExpect,
changeUserType,
membersHelper,
currentMember,
updateRoomMemberRole,
selectionParentRoom,
setSelectionParentRoom,
}) => {
if (!selectionParentRoom) return null;
if (!user.displayName && !user.email) return null;
const roles = {
admin: {
key: "admin",
title: t("People:Administrator"),
label: t("People:Administrator"),
action: "admin",
},
manager: {
key: "manager",
title: t("People:Manager"),
label: t("People:Manager"),
action: "manager",
},
user: {
key: "user",
title: t("Common:User"),
label: t("Common:User"),
action: "user",
},
};
const [userIsRemoved, setUserIsRemoved] = useState(false);
if (userIsRemoved) return null;
const getUserRole = () => {
if (user.isOwner) return roles.admin;
if (user.isAdmin) return roles.manager;
return roles.user;
};
const currCanEditUsers =
currentMember.isOwner ||
currentMember.isAdmin ||
currentMember?.access === ShareAccessRights.FullAccess ||
currentMember?.access === ShareAccessRights.RoomManager;
const getUserOptions = () => {
let options = [];
if (isOwner) options.push(roles.admin);
if (isAdmin) options.push(roles.manager);
options.push(roles.user);
return options;
};
const getNotAuthorizedToEdit = () => {
if (selfId === user.id) return true;
if (isOwner) return false;
if (!isAdmin) return true;
};
const userRole = getUserRole();
const userOptions = getUserOptions();
const userNotAuthorizedToEdit = getNotAuthorizedToEdit();
const onTypeChange = React.useCallback(
({ action }) => {
changeUserType(action, [user], t, false, false);
},
[user, changeUserType, t]
const fullRoomRoleOptions = membersHelper.getOptionsByRoomType(
selectionParentRoom.roomType,
currCanEditUsers
);
const userRole = membersHelper.getOptionByUserAccess(user.access);
const userRoleOptions = fullRoomRoleOptions?.filter(
(role) => role.key !== userRole.key
);
const onOptionClick = (option) => {
updateRoomMemberRole(selectionParentRoom.id, {
invitations: [{ id: user.id, access: option.access }],
notify: false,
sharingMessage: "",
});
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
),
},
});
}
};
return (
<StyledUser
isExpect={isExpect}
key={user.id}
canEditRole={user.role !== "Owner"}
>
<StyledUser isExpect={isExpect} key={user.id}>
<Avatar
role="user"
className="avatar"
size="min"
source={
user.avatar ||
(user.displayName ? "" : user.email && "/static/images/@.react.svg")
}
userName={user.displayName}
source={isExpect ? "/static/images/@.react.svg" : user.avatar || ""}
userName={isExpect ? "" : user.displayName}
/>
<div className="name">{user.displayName || user.email}</div>
{selfId === user.id && (
<div className="name">
{isExpect ? user.email : user.displayName || user.email}
</div>
{currentMember.id === user.id && (
<div className="me-label">&nbsp;{`(${t("Common:MeLabel")})`}</div>
)}
<div className="role-wrapper">
{userNotAuthorizedToEdit ? (
<div className="disabled-role-combobox">{userRole.label}</div>
) : (
<ComboBox
className="role-combobox"
selectedOption={userRole}
options={userOptions}
onSelect={onTypeChange}
scaled={false}
withBackdrop={false}
size="content"
displaySelectedOption
modernView
/>
)}
</div>
{userRole && userRoleOptions && (
<div className="role-wrapper">
{currCanEditUsers && currentMember.id !== user.id ? (
<ComboBox
className="role-combobox"
selectedOption={userRole}
options={userRoleOptions}
onSelect={onOptionClick}
scaled={false}
withBackdrop={false}
size="content"
modernView
/>
) : (
<div className="disabled-role-combobox">{userRole.label}</div>
)}
</div>
)}
</StyledUser>
);
};

View File

@ -1,4 +1,5 @@
import React, { useState, useEffect } from "react";
import { inject, observer } from "mobx-react";
import { withTranslation } from "react-i18next";
import toastr from "@docspace/components/toast/toastr";
@ -11,6 +12,7 @@ import { ShareAccessRights } from "@docspace/common/constants";
import IconButton from "@docspace/components/icon-button";
import Text from "@docspace/components/text";
import User from "./User";
import MembersHelper from "../../helpers/MembersHelper";
const Members = ({
t,
@ -24,34 +26,54 @@ const Members = ({
setSelectionParentRoom,
getRoomMembers,
changeUserType,
updateRoomMemberRole,
resendEmailInvitations,
setInvitePanelOptions,
changeUserType,
canInviteUserInRoom,
}) => {
const membersHelper = new MembersHelper({ t });
const [members, setMembers] = useState(null);
const [showLoader, setShowLoader] = useState(false);
const isDisabledInvite = !canInviteUserInRoom({ access: selection.access });
const fetchMembers = async (roomId) => {
let timerId;
if (members) timerId = setTimeout(() => setShowLoader(true), 1500);
let fetchedMembers = await getRoomMembers(roomId);
fetchedMembers = fetchedMembers.filter(
(m) => m.sharedTo.email || m.sharedTo.displayName
);
if (members) timerId = setTimeout(() => setShowLoader(true), 1000);
let data = await getRoomMembers(roomId);
data = data.filter((m) => m.sharedTo.email || m.sharedTo.displayName);
clearTimeout(timerId);
setMembers(fetchedMembers);
let inRoomMembers = [];
let expectedMembers = [];
data.map((fetchedMember) => {
const member = {
access: fetchedMember.access,
...fetchedMember.sharedTo,
};
if (member.activationStatus !== 2) inRoomMembers.push(member);
else expectedMembers.push(member);
});
setShowLoader(false);
return fetchedMembers;
return {
inRoom: inRoomMembers,
expected: expectedMembers,
};
};
useEffect(async () => {
if (!selectionParentRoom) return;
if (selectionParentRoom.members) {
setMembers(selectionParentRoom.members);
return;
}
const fetchedMembers = await fetchMembers(selection.id);
const fetchedMembers = await fetchMembers(selectionParentRoom.id);
setSelectionParentRoom({
...selectionParentRoom,
members: fetchedMembers,
@ -60,8 +82,7 @@ const Members = ({
useEffect(async () => {
if (!selection.isRoom) return;
if (selectionParentRoom && selectionParentRoom.id === selection.id) return;
setMembers(null);
const fetchedMembers = await fetchMembers(selection.id);
setSelectionParentRoom({
...selection,
@ -69,72 +90,140 @@ const Members = ({
});
}, [selection]);
const onAddUsers = () => {
if (isDisabledInvite) return;
const onClickInviteUsers = () => {
const parentRoomId = selectionParentRoom.id;
setInvitePanelOptions({
visible: true,
roomId: selection.id,
roomId: parentRoomId,
hideSelector: false,
defaultAccess: ShareAccessRights.ReadOnly,
});
};
const onRepeatInvitation = async () => {
const userIds = members.expected.map((user) => user.id);
resendEmailInvitations(selectionParentRoom.id, userIds)
.then(() =>
toastr.success(t("PeopleTranslations:SuccessSentMultipleInvitatios"))
)
.catch((err) => toastr.error(err));
};
if (showLoader) return <Loaders.InfoPanelViewLoader view="members" />;
if (!members) return null;
if (!selectionParentRoom || !members) return null;
const [currentMember] = members.inRoom.filter(
(member) => member.id === selfId
);
return (
<>
<StyledUserTypeHeader>
<Text className="title">
{t("UsersInRoom")} : {members.length}
{t("UsersInRoom")} : {members.inRoom.length}
</Text>
<IconButton
className={"icon"}
title={t("Common:AddUsers")}
iconName="/static/images/person+.react.svg"
isFill={true}
onClick={onAddUsers}
onClick={onClickInviteUsers}
size={16}
isDisabled={isDisabledInvite}
/>
</StyledUserTypeHeader>
<StyledUserList>
{Object.values(members).map((user) => (
{Object.values(members.inRoom).map((user) => (
<User
key={user.sharedTo.id}
key={user.id}
t={t}
user={user.sharedTo}
isOwner={isOwner}
isAdmin={isAdmin}
selfId={selfId}
changeUserType={changeUserType}
user={user}
membersHelper={membersHelper}
currentMember={currentMember}
updateRoomMemberRole={updateRoomMemberRole}
roomId={selectionParentRoom.id}
roomType={selectionParentRoom.roomType}
selectionParentRoom={selectionParentRoom}
setSelectionParentRoom={setSelectionParentRoom}
/>
))}
</StyledUserList>
{/* <StyledUserTypeHeader>
<Text className="title">{`${t("Expect people")}:`}</Text>
<IconButton
className={"icon"}
title={t("Repeat invitation")}
iconName="/static/images/e-mail+.react.svg"
isFill={true}
onClick={() => {}}
size={16}
/>
</StyledUserTypeHeader>
{!!members.expected.length && (
<StyledUserTypeHeader isExpect>
<Text className="title">{t("ExpectPeople")}</Text>
<IconButton
className={"icon"}
title={t("Repeat invitation")}
iconName="/static/images/e-mail+.react.svg"
isFill={true}
onClick={onRepeatInvitation}
size={16}
/>
</StyledUserTypeHeader>
)}
<UserList t={t} users={data.members.expect} isExpect /> */}
<StyledUserList>
{Object.values(members.expected).map((user) => (
<User
isExpect
key={user.id}
t={t}
user={user}
membersHelper={membersHelper}
currentMember={currentMember}
updateRoomMemberRole={updateRoomMemberRole}
roomId={selectionParentRoom.id}
roomType={selectionParentRoom.roomType}
selectionParentRoom={selectionParentRoom}
setSelectionParentRoom={setSelectionParentRoom}
/>
))}
</StyledUserList>
</>
);
};
export default withTranslation([
"InfoPanel",
"Common",
"Translations",
"People",
"PeopleTranslations",
"Settings",
])(Members);
export default inject(
({ auth, filesStore, peopleStore, dialogsStore, accessRightsStore }) => {
const { selectionParentRoom, setSelectionParentRoom } = auth.infoPanelStore;
const {
getRoomMembers,
updateRoomMemberRole,
resendEmailInvitations,
} = filesStore;
const { isOwner, isAdmin, id: selfId } = auth.userStore.user;
const { setInvitePanelOptions } = dialogsStore;
const { changeType: changeUserType } = peopleStore;
const { canInviteUserInRoom } = accessRightsStore;
return {
selectionParentRoom,
setSelectionParentRoom,
getRoomMembers,
updateRoomMemberRole,
isOwner,
isAdmin,
selfId,
setInvitePanelOptions,
resendEmailInvitations,
changeUserType,
canInviteUserInRoom,
};
}
)(
withTranslation([
"InfoPanel",
"Common",
"Translations",
"People",
"PeopleTranslations",
"Settings",
])(observer(Members))
);

View File

@ -11,6 +11,7 @@ import TextInput from "@docspace/components/text-input";
import HelpButton from "@docspace/components/help-button";
import SaveCancelButtons from "@docspace/components/save-cancel-buttons";
import Badge from "@docspace/components/badge";
import toastr from "@docspace/components/toast/toastr";
import { Base } from "@docspace/components/themes";
import LoaderWhiteLabel from "../sub-components/loaderWhiteLabel";
@ -67,9 +68,9 @@ const StyledComponent = styled.div`
}
.logo-header {
width: 142px;
height: 23px;
padding: 10px;
width: 211px;
height: 24px;
padding: 12px 20px;
background-color: ${(props) =>
props.theme.client.settings.common.whiteLabel.backgroundColor};
}
@ -163,6 +164,8 @@ const WhiteLabel = (props) => {
const [editorsHeaderLabel, setEditorsHeaderLabel] = useState();
const [logoEditorsEmbeddedLabel, setLogoEditorsEmbeddedLabel] = useState();
const [isSaving, setIsSaving] = useState(false);
useEffect(() => {
if (logoText) {
setLogoTextWhiteLabel(logoText);
@ -175,6 +178,10 @@ const WhiteLabel = (props) => {
}
}, [logoUrls]);
useEffect(() => {
setLogoSizes(mapSizesToArray(logoSizes));
}, [logoSizes]);
useEffect(() => {
if (
logoTextWhiteLabel &&
@ -285,6 +292,26 @@ const WhiteLabel = (props) => {
setIsUseTextAsLogo(false);
}, [isCanvasProcessing, isUseTextAsLogo]);
useEffect(() => {
if (isCanvasProcessing) {
let logosArr = [];
for (let i = 0; i < 7; i++) {
const id = String(i + 1);
const canvas =
id === "4"
? document.getElementById(`canvas_logo_${id}_1`)
: document.getElementById(`canvas_logo_${id}`);
const changeImg = {
id,
src: canvas.toDataURL(),
};
logosArr.push(changeImg);
}
setLogoUrlsChange(logosArr);
}
}, [isCanvasProcessing]);
const onUseTextAsLogo = () => {
setIsCanvasProcessing(true);
setIsUseTextAsLogo(true);
@ -297,27 +324,43 @@ const WhiteLabel = (props) => {
};
const onRestoreLogo = () => {
restoreWhiteLabelSettings(true);
setIsCanvasProcessing(false);
try {
restoreWhiteLabelSettings(true);
setIsCanvasProcessing(false);
setLogoUrlsChange([]);
getWhiteLabelLogoUrls();
toastr.success(t("Settings:SuccessfullySaveSettingsMessage"));
} catch (error) {
toastr.error(error);
}
};
const onSave = () => {
let fd = new FormData();
fd.append("logoText", logoTextWhiteLabel);
const onSave = async () => {
let logoArr = [];
for (let i = 0; i < 7; i++) {
fd.append(`logo[${i}][key]`, i + 1);
fd.append(`logo[${i}][value]`, logoUrlsWhiteLabel[i]);
}
logoUrlsChange.map((item) => {
logoArr.push({ key: item.id, value: item.src });
});
const data = new URLSearchParams(fd);
console.log(data);
const data = {
logoText: logoTextWhiteLabel,
logo: logoArr,
};
setWhiteLabelSettings(data).finally(() => {
setIsSaving(true);
try {
await setWhiteLabelSettings(data);
setLogoUrlsChange([]);
getWhiteLabelLogoText();
getWhiteLabelLogoSizes();
getWhiteLabelLogoUrls();
});
toastr.success(t("Settings:SuccessfullySaveSettingsMessage"));
} catch (error) {
toastr.error(error);
} finally {
setIsSaving(false);
}
};
const onChangeLogo = (e) => {
@ -414,19 +457,19 @@ const WhiteLabel = (props) => {
!logoUrlsChange.some((obj) => obj.id === "1") ? (
<canvas
id="canvas_logo_1"
className="border-img logo-header"
className="logo-header"
width="251"
height="48"
data-fontsize="36"
data-fontcolor={
theme.client.settings.common.whiteLabel.dataFontColor
theme.client.settings.common.whiteLabel.dataFontColorBlack
}
>
{t("BrowserNoCanvasSupport")}
</canvas>
) : (
<img
className="border-img logo-header"
className="logo-header"
src={
logoUrlsChange &&
logoUrlsChange.some((obj) => obj.id === "1")
@ -474,7 +517,7 @@ const WhiteLabel = (props) => {
height="56"
data-fontsize="36"
data-fontcolor={
theme.client.settings.common.whiteLabel.dataFontColor
theme.client.settings.common.whiteLabel.dataFontColorBlack
}
>
{t("BrowserNoCanvasSupport")}
@ -838,34 +881,36 @@ const WhiteLabel = (props) => {
</div>
</div>
{isSettingPaid && (
<SaveCancelButtons
tabIndex={3}
className="save-cancel-buttons"
onSaveClick={onSave}
onCancelClick={onRestoreLogo}
saveButtonLabel={t("Common:SaveButton")}
cancelButtonLabel={t("RestoreDefaultButton")}
displaySettings={true}
showReminder={true}
/>
)}
<SaveCancelButtons
tabIndex={3}
className="save-cancel-buttons"
onSaveClick={onSave}
onCancelClick={onRestoreLogo}
saveButtonLabel={t("Common:SaveButton")}
cancelButtonLabel={t("RestoreDefaultButton")}
displaySettings={true}
showReminder={isSettingPaid}
saveButtonDisabled={logoUrlsChange.length === 0}
isSaving={isSaving}
/>
</div>
</StyledComponent>
);
};
export default inject(({ setup, auth, common }) => {
const { setWhiteLabelSettings, restoreWhiteLabelSettings } = setup;
const { whiteLabelLogoSizes, whiteLabelLogoText } = common;
const { setWhiteLabelSettings } = setup;
const {
whiteLabelLogoUrls,
whiteLabelLogoSizes,
whiteLabelLogoText,
getWhiteLabelLogoText,
getWhiteLabelLogoSizes,
getWhiteLabelLogoUrls,
} = auth.settingsStore;
whiteLabelLogoUrls,
restoreWhiteLabelSettings,
} = common;
const { getWhiteLabelLogoUrls } = auth.settingsStore;
return {
theme: auth.settingsStore.theme,

View File

@ -130,25 +130,31 @@ const PayerInformationContainer = ({
</>
);
const payerName = (
<Text as="span" fontWeight={600} noSelect fontSize={"14px"}>
{payerInfo ? (
payerInfo.displayName
) : (
<Trans t={t} i18nKey="UserNotFound" ns="Payments">
User
<Text
as="span"
color={theme.client.settings.payment.warningColor}
fontWeight={600}
>
{{ email }}
</Text>
is not found
</Trans>
)}
</Text>
);
const payerName = () => {
let emailUnfoundedUser = email;
if (email) emailUnfoundedUser = "«" + emailUnfoundedUser + "»";
return (
<Text as="span" fontWeight={600} noSelect fontSize={"14px"}>
{payerInfo ? (
payerInfo.displayName
) : (
<Trans t={t} i18nKey="UserNotFound" ns="Payments">
User
<Text
as="span"
color={theme.client.settings.payment.warningColor}
fontWeight={600}
>
{{ email: emailUnfoundedUser }}
</Text>
is not found
</Trans>
)}
</Text>
);
};
const avatarUrl = payerInfo ? { source: payerInfo.avatar } : {};
@ -165,7 +171,7 @@ const PayerInformationContainer = ({
<div className="payer-info_wrapper">
<div className="payer-info_description">
{payerName}
{payerName()}
<Text as="span" className="payer-info">
{" (" + t("Payer") + ") "}

View File

@ -36,7 +36,9 @@ const StyledBody = styled.div`
@media (max-width: ${size.smallTablet + 40}px) {
grid-template-columns: 1fr;
grid-template-rows: 1fr 1fr;
grid-template-rows: ${(props) =>
props.isHideBenefitsInfo ? "1fr" : "1fr max-content"};
.price-calculation-container,
.benefits-container {
@ -51,7 +53,8 @@ const StyledBody = styled.div`
props.isChangeView &&
css`
grid-template-columns: 1fr;
grid-template-rows: 1fr 1fr;
grid-template-rows: ${(props) =>
props.isHideBenefitsInfo ? "1fr" : "1fr max-content"};
.price-calculation-container,
.benefits-container {
@ -304,6 +307,9 @@ const PaymentsPage = ({
const isFreeAfterPaidPeriod = isFreeTariff && payerEmail.length !== 0;
const isHideBenefitsInfo =
isGracePeriod || isNotPaidPeriod || isFreeAfterPaidPeriod;
return isInitialLoading || !ready ? (
<Loaders.PaymentsLoader />
) : (
@ -314,6 +320,7 @@ const PaymentsPage = ({
isChangeView={
context.sectionWidth < size.smallTablet && expandArticle
}
isHideBenefitsInfo={isHideBenefitsInfo}
>
{isNotPaidPeriod && isValidDelayDueDate
? expiredTitleSubscriptionWarning()
@ -382,11 +389,7 @@ const PaymentsPage = ({
isFreeAfterPaidPeriod={isFreeAfterPaidPeriod}
/>
{isGracePeriod || isNotPaidPeriod || isFreeAfterPaidPeriod ? (
<></>
) : (
<BenefitsContainer t={t} />
)}
{isHideBenefitsInfo ? <></> : <BenefitsContainer t={t} />}
</div>
<ContactContainer t={t} />
</StyledBody>

View File

@ -3,6 +3,7 @@ import authStore from "@docspace/common/store/AuthStore";
import api from "@docspace/common/api";
class CommonStore {
whiteLabelLogoUrls = [];
whiteLabelLogoSizes = [];
whiteLabelLogoText = null;
@ -35,6 +36,7 @@ class CommonStore {
requests.push(
authStore.settingsStore.getPortalTimezones(),
authStore.settingsStore.getPortalCultures(),
this.getWhiteLabelLogoUrls(),
this.getWhiteLabelLogoText(),
this.getWhiteLabelLogoSizes(),
this.getGreetingSettingsIsDefault()
@ -43,6 +45,10 @@ class CommonStore {
return Promise.all(requests).finally(() => this.setIsLoaded(true));
};
setLogoUrls = (urls) => {
this.whiteLabelLogoUrls = urls;
};
setLogoText = (text) => {
this.whiteLabelLogoText = text;
};
@ -51,10 +57,20 @@ class CommonStore {
this.whiteLabelLogoSizes = sizes;
};
restoreWhiteLabelSettings = async (isDefault) => {
const res = await api.settings.restoreWhiteLabelSettings(isDefault);
this.getWhiteLabelLogoUrls();
};
getGreetingSettingsIsDefault = async () => {
this.greetingSettingsIsDefault = await api.settings.getGreetingSettingsIsDefault();
};
getWhiteLabelLogoUrls = async () => {
const res = await api.settings.getLogoUrls();
this.setLogoUrls(Object.values(res));
};
getWhiteLabelLogoText = async () => {
const res = await api.settings.getLogoText();
this.setLogoText(res);

View File

@ -401,7 +401,7 @@ class ContextOptionsStore {
onShowInfoPanel = (item) => {
const { setSelection, setIsVisible } = this.authStore.infoPanelStore;
setSelection({ ...item, isContextMenuSelection: true });
setSelection(item);
setIsVisible(true);
};

View File

@ -1666,6 +1666,10 @@ class FilesStore {
return api.rooms.getRoomMembers(id);
}
updateRoomMemberRole(id, data) {
return api.rooms.updateRoomMemberRole(id, data);
}
getHistory(module, id) {
return api.rooms.getHistory(module, id);
}

View File

@ -218,10 +218,6 @@ class SettingsSetupStore {
return Promise.resolve(response);
};
restoreWhiteLabelSettings = async (isDefault) => {
const res = await api.settings.restoreWhiteLabelSettings(isDefault);
};
setLanguageAndTime = async (lng, timeZoneID) => {
return api.settings.setLanguageAndTime(lng, timeZoneID);
};

View File

@ -137,6 +137,7 @@ const profileActionsStore = new ProfileActionsStore(
authStore.infoPanelStore.authStore = authStore;
authStore.infoPanelStore.settingsStore = settingsStore;
authStore.infoPanelStore.filesStore = filesStore;
authStore.infoPanelStore.peopleStore = peopleStore;
authStore.infoPanelStore.selectedFolderStore = selectedFolderStore;
authStore.infoPanelStore.treeFoldersStore = treeFoldersStore;

View File

@ -42,6 +42,18 @@ export function getRoomMembers(id) {
});
}
export function updateRoomMemberRole(id, data) {
const options = {
method: "put",
url: `/files/rooms/${id}/share`,
data,
};
return request(options).then((res) => {
return res;
});
}
export function getHistory(module, id) {
const options = {
method: "get",
@ -263,7 +275,7 @@ export const setInvitationLinks = async (roomId, linkId, title, access) => {
export const resendEmailInvitations = async (id, usersIds) => {
const options = {
method: "put",
method: "post",
url: `/files/rooms/${id}/resend`,
data: {
usersIds,

View File

@ -164,6 +164,11 @@ const StyledHeading = styled.div`
padding: 0;
cursor: pointer;
img.logo-icon_svg {
height: 24px;
width: 211px;
}
.logo-icon_svg {
svg {
path:last-child {
@ -199,6 +204,10 @@ const StyledIconBox = styled.div`
align-items: center;
height: 20px;
img {
height: 24px;
}
@media ${tablet} {
display: ${(props) => (props.showText ? "none" : "flex")};
}

View File

@ -18,6 +18,7 @@ const ArticleHeader = ({
children,
onClick,
isBurgerLoading,
whiteLabelLogoUrls,
...rest
}) => {
const history = useHistory();
@ -25,6 +26,8 @@ const ArticleHeader = ({
const isTabletView = (isTabletUtils() || isTablet) && !isMobileOnly;
const onLogoClick = () => history.push("/");
const isSvgLogo = whiteLabelLogoUrls[0].includes(".svg");
if (isMobileOnly) return <></>;
return (
<StyledArticleHeader showText={showText} {...rest}>
@ -32,7 +35,7 @@ const ArticleHeader = ({
<Loaders.ArticleHeader height="28px" width="28px" />
) : (
<StyledIconBox name="article-burger" showText={showText}>
<img src="/static/images/logo.icon.react.svg" onClick={onLogoClick} />
<img src={whiteLabelLogoUrls[5]} onClick={onLogoClick} />
</StyledIconBox>
)}
@ -41,17 +44,30 @@ const ArticleHeader = ({
) : (
<StyledHeading showText={showText} size="large">
{isTabletView ? (
<ReactSVG
className="logo-icon_svg"
src="/static/images/logo.docspace.react.svg"
onClick={onLogoClick}
/>
) : (
<Link to="/">
isSvgLogo ? (
<ReactSVG
className="logo-icon_svg"
src="/static/images/logo.docspace.react.svg"
src={whiteLabelLogoUrls[0]}
onClick={onLogoClick}
/>
) : (
<img
className="logo-icon_svg"
src={whiteLabelLogoUrls[0]}
onClick={onLogoClick}
/>
)
) : (
<Link to="/">
{isSvgLogo ? (
<ReactSVG
className="logo-icon_svg"
src={whiteLabelLogoUrls[0]}
onClick={onLogoClick}
/>
) : (
<img className="logo-icon_svg" src={whiteLabelLogoUrls[0]} />
)}
</Link>
)}
</StyledHeading>
@ -70,8 +86,9 @@ ArticleHeader.displayName = "Header";
export default inject(({ auth }) => {
const { settingsStore } = auth;
const { isBurgerLoading } = settingsStore;
const { isBurgerLoading, whiteLabelLogoUrls } = settingsStore;
return {
isBurgerLoading,
whiteLabelLogoUrls,
};
})(observer(ArticleHeader));

View File

@ -6,6 +6,16 @@ import { combineUrl } from "@docspace/common/utils";
import { AppServerConfig } from "@docspace/common/constants";
import config from "PACKAGE_FILE";
import Filter from "../api/people/filter";
import { getRoomInfo } from "../api/rooms";
const observedKeys = [
"id",
"title",
"thumbnailStatus",
"thumbnailUrl",
"version",
"comment",
];
class InfoPanelStore {
isVisible = false;
@ -19,6 +29,7 @@ class InfoPanelStore {
authStore = null;
settingsStore = null;
peopleStore = null;
filesStore = null;
selectedFolderStore = null;
treeFoldersStore = null;
@ -26,9 +37,19 @@ class InfoPanelStore {
makeAutoObservable(this);
}
// Setters
setIsVisible = (bool) => (this.isVisible = bool);
setSelection = (selection) => (this.selection = selection);
setSelection = (selection) => {
if (this.getIsAccounts() && (!selection.email || !selection.displayName)) {
this.selection = selection.length
? selection
: { isSelectedFolder: true };
return;
}
this.selection = selection;
};
setSelectionParentRoom = (obj) => (this.selectionParentRoom = obj);
setView = (view) => {
@ -36,18 +57,109 @@ class InfoPanelStore {
this.fileView = view === "members" ? "history" : view;
};
// Selection helpers //
getSelectedItems = () => {
const {
selection: filesStoreSelection,
bufferSelection: filesStoreBufferSelection,
} = this.filesStore;
const {
selection: peopleStoreSelection,
bufferSelection: peopleStoreBufferSelection,
} = this.peopleStore.selectionStore;
return this.getIsAccounts()
? peopleStoreSelection.length
? [...peopleStoreSelection]
: peopleStoreBufferSelection
? [peopleStoreBufferSelection]
: []
: filesStoreSelection?.length > 0
? [...filesStoreSelection]
: filesStoreBufferSelection
? [filesStoreBufferSelection]
: [];
};
getSelectedFolder = () => {
const selectedFolderStore = { ...this.selectedFolderStore };
return {
...selectedFolderStore,
isFolder: true,
isRoom: !!this.selectedFolderStore.roomType,
};
};
calculateSelection = (
props = { selectedItems: [], selectedFolder: null }
) => {
const selectedItems = props.selectedItems.length
? props.selectedItems
: this.getSelectedItems();
const selectedFolder = props.selectedFolder
? props.selectedFolder
: this.getSelectedFolder();
return selectedItems.length === 0
? this.normalizeSelection({
...selectedFolder,
isSelectedFolder: true,
isSelectedItem: false,
})
: selectedItems.length === 1
? this.normalizeSelection({
...selectedItems[0],
isSelectedFolder: false,
isSelectedItem: true,
})
: [...Array(selectedItems.length).keys()];
};
normalizeSelection = (selection) => {
const isContextMenuSelection = selection.isContextMenuSelection;
return {
...selection,
isRoom: selection.isRoom || !!selection.roomType,
icon: this.getItemIcon(selection, 32),
icon: this.getInfoPanelItemIcon(selection, 32),
isContextMenuSelection: false,
wasContextMenuSelection: !!isContextMenuSelection,
};
};
getItemIcon = (item, size) => {
reloadSelection = () => {
this.setSelection(this.calculateSelection());
};
reloadSelectionParentRoom = async () => {
if (!this.getIsRooms) return;
const currentFolderRoomId = this.selectedFolderStore.pathParts[1];
const prevRoomId = selectionParentRoom?.id;
if (!currentFolderRoomId || currentFolderRoomId === prevRoomId) return;
const newSelectionParentRoom = await getRoomInfo(currentFolderRoomId);
if (prevRoomId === newSelectionParentRoom.id) return;
this.setSelectionParentRoom(
this.normalizeSelection(newSelectionParentRoom)
);
};
isItemChanged = (oldItem, newItem) => {
for (let i = 0; i < observedKeys.length; i++) {
const value = observedKeys[i];
if (oldItem[value] !== newItem[value]) return true;
}
return false;
};
// Icon helpers //
getInfoPanelItemIcon = (item, size) => {
return item.isRoom || !!item.roomType
? item.logo && item.logo.medium
? item.logo.medium
@ -59,6 +171,18 @@ class InfoPanelStore {
: this.settingsStore.getIcon(size, item.fileExst || ".file");
};
// User link actions //
openUser = async (user, history) => {
if (user.id === this.authStore.userStore.user.id) {
this.openSelfProfile(history);
return;
}
const fetchedUser = await this.fetchUser(user.id);
this.openAccountsWithSelectedUser(fetchedUser, history);
};
openSelfProfile = (history) => {
const path = [
AppServerConfig.proxyURL,
@ -73,21 +197,20 @@ class InfoPanelStore {
openAccountsWithSelectedUser = async (user, history) => {
const { getUsersList } = this.peopleStore.usersStore;
const { selectUser } = this.peopleStore.selectionStore;
const { setSelection } = this.peopleStore.selectionStore;
const path = [AppServerConfig.proxyURL, config.homepage, "/accounts"];
const newFilter = Filter.getDefault();
newFilter.page = 0;
newFilter.search = user.email;
await getUsersList(newFilter);
path.push(`filter?${newFilter.toUrlParams()}`);
const userList = await getUsersList(newFilter);
history.push(combineUrl(...path));
this.selectedFolderStore.setSelectedFolder(null);
this.treeFoldersStore.setSelectedNode(["accounts"]);
history.push(combineUrl(...path));
selectUser(user);
setSelection([user]);
};
fetchUser = async (userId) => {
@ -109,18 +232,15 @@ class InfoPanelStore {
return fetchedUser;
};
openUser = async (userId, history) => {
if (userId === this.authStore.userStore.user.id) {
this.openSelfProfile(history);
return;
}
// Routing helpers //
const fetchedUser = await this.fetchUser(userId);
this.openAccountsWithSelectedUser(fetchedUser, history);
};
getItemNoThumbnail = (item) => {
this.getItemIcon(item, 96);
getCanDisplay = () => {
const pathname = window.location.pathname.toLowerCase();
const isFiles = this.getIsFiles(pathname);
const isRooms = this.getIsRooms(pathname);
const isAccounts = this.getIsAccounts(pathname);
const isGallery = this.getIsGallery(pathname);
return isRooms || isFiles || isGallery || isAccounts;
};
getIsFiles = (givenPathName) => {
@ -148,15 +268,6 @@ class InfoPanelStore {
const pathname = givenPathName || window.location.pathname.toLowerCase();
return pathname.indexOf("form-gallery") !== -1;
};
getCanDisplay = () => {
const pathname = window.location.pathname.toLowerCase();
const isFiles = this.getIsFiles(pathname);
const isRooms = this.getIsRooms(pathname);
const isAccounts = this.getIsAccounts(pathname);
const isGallery = this.getIsGallery(pathname);
return isRooms || isFiles || isGallery || isAccounts;
};
}
export default InfoPanelStore;

View File

@ -70,7 +70,7 @@ class SettingsStore {
urlSupport = "https://helpdesk.onlyoffice.com/";
urlOforms = "https://cmsoforms.onlyoffice.com/api/oforms";
logoUrl = combineUrl(proxyURL, "/static/images/logo.docspace.react.svg");
logoUrl = "";
customNames = {
id: "Common",
userCaption: "User",
@ -388,7 +388,11 @@ class SettingsStore {
};
setDocSpaceLogo = (urls) => {
this.docSpaceLogo = urls[1];
this.docSpaceLogo = urls[6];
};
setLogoUrl = (url) => {
this.logoUrl = url[0];
};
setLogoUrls = (urls) => {
@ -407,6 +411,7 @@ class SettingsStore {
this.setLogoUrls(Object.values(res));
this.setDocSpaceLogo(Object.values(res));
this.setLogoUrl(Object.values(res));
};
restoreCompanyInfoSettings = async () => {

View File

@ -16,6 +16,7 @@ const StyledLabel = styled.label`
.checkbox {
margin-right: 12px;
overflow: visible;
outline: none;
}
/* ${(props) =>

View File

@ -23,10 +23,10 @@ const StyledWrapper = styled.div`
@media ${hugeMobile} {
padding: 0;
border-radius: 0;
box-shadow: none;
box-shadow: none !important;
max-width: 343px;
min-width: 343px;
background: transparent;
background: transparent !important;
}
`;

View File

@ -52,6 +52,7 @@ class SaveCancelButtons extends React.Component {
isSaving,
cancelEnable,
tabIndex,
saveButtonDisabled,
} = this.props;
const cancelButtonDisabled = cancelEnable
@ -76,7 +77,7 @@ class SaveCancelButtons extends React.Component {
tabIndex={tabIndexSaveButton}
className="save-button"
size="normal"
isDisabled={!showReminder}
isDisabled={!showReminder || saveButtonDisabled}
primary
onClick={onSaveClick}
label={saveButtonLabel}

View File

@ -2027,6 +2027,8 @@ const Base = {
members: {
iconColor: "#A3A9AE",
iconHoverColor: "#657077",
isExpectName: "#A3A9AE",
subtitleColor: "#a3a9ae",
meLabelColor: "#a3a9ae",
roleSelectorColor: "#a3a9ae",
@ -2877,7 +2879,7 @@ const Base = {
whiteLabel: {
borderImg: "1px solid #d1d1d1",
backgroundColor: "#0f4071",
backgroundColor: "#ECEEF1",
greenBackgroundColor: "#7e983f",
blueBackgroundColor: "#5170b5",
orangeBackgroundColor: "#e86e2e",

View File

@ -2023,6 +2023,8 @@ const Dark = {
members: {
iconColor: "#A3A9AE",
iconHoverColor: "#ffffff",
isExpectName: "#A3A9AE",
subtitleColor: "#a3a9ae",
meLabelColor: "#a3a9ae",
roleSelectorColor: "#a3a9ae",
@ -2883,13 +2885,13 @@ const Dark = {
whiteLabel: {
borderImg: "1px solid #d1d1d1",
backgroundColor: "#0f4071",
backgroundColor: "#282828",
greenBackgroundColor: "#7e983f",
blueBackgroundColor: "#5170b5",
orangeBackgroundColor: "#e86e2e",
dataFontColor: white,
dataFontColorBlack: black,
dataFontColorBlack: white,
},
},

View File

@ -97,6 +97,7 @@ declare global {
match: MatchType;
currentColorScheme: ITheme;
isAuth: boolean;
logoUrls: any;
}
interface DevRequest {

View File

@ -2,7 +2,6 @@ import React, { useEffect, useState, useCallback } from "react";
import { useTranslation } from "react-i18next";
import { inject, observer } from "mobx-react";
import { ButtonsWrapper, LoginFormWrapper } from "./StyledLogin";
import Logo from "../../../../../public/images/docspace.big.react.svg";
import Text from "@docspace/components/text";
import SocialButton from "@docspace/components/social-button";
import {
@ -24,6 +23,7 @@ import SSOIcon from "../../../../../public/images/sso.react.svg";
import { Dark, Base } from "@docspace/components/themes";
import { useMounted } from "../helpers/useMounted";
import { getBgPattern } from "@docspace/common/utils";
import { ReactSVG } from "react-svg";
interface ILoginProps extends IInitialState {
isDesktopEditor?: boolean;
@ -38,6 +38,7 @@ const Login: React.FC<ILoginProps> = ({
currentColorScheme,
theme,
setTheme,
logoUrls,
}) => {
const [isLoading, setIsLoading] = useState(false);
const [moreAuthVisible, setMoreAuthVisible] = useState(false);
@ -174,6 +175,9 @@ const Login: React.FC<ILoginProps> = ({
const bgPattern = getBgPattern(currentColorScheme.id);
const loginLogo = Object.values(logoUrls)[1];
const isSvgLogo = loginLogo.includes(".svg");
if (!mounted) return <></>;
return (
@ -185,7 +189,11 @@ const Login: React.FC<ILoginProps> = ({
bgPattern={bgPattern}
>
<ColorTheme themeId={ThemeType.LinkForgotPassword} theme={theme}>
<Logo className="logo-wrapper" />
{isSvgLogo ? (
<ReactSVG src={loginLogo} className="logo-wrapper" />
) : (
<img src={loginLogo} className="logo-wrapper" />
)}
<Text
fontSize="23px"
fontWeight={700}

View File

@ -238,10 +238,12 @@ export const LoginContainer = styled.div`
height: 46px;
padding-bottom: 64px;
path:last-child {
fill: ${(props) => props.theme.client.home.logoColor};
svg {
path:last-child {
fill: ${(props) => props.theme.client.home.logoColor};
}
}
@media ${hugeMobile} {
display: none;
}

View File

@ -6,6 +6,7 @@ import {
getAuthProviders,
getCapabilities,
getAppearanceTheme,
getLogoUrls
} from "@docspace/common/api/settings";
import { checkIsAuthenticated } from "@docspace/common/api/user";
@ -57,7 +58,8 @@ export const getInitialState = async (
providers: ProvidersType,
capabilities: ICapabilities,
availableThemes: IThemes,
isAuth: any;
isAuth: any,
logoUrls: any;
[
portalSettings,
@ -66,13 +68,15 @@ export const getInitialState = async (
capabilities,
availableThemes,
isAuth,
logoUrls
] = await Promise.all([
getSettings(),
getBuildVersion(),
getAuthProviders(),
getCapabilities(),
getAppearanceTheme(),
checkIsAuthenticated()
checkIsAuthenticated(),
getLogoUrls()
]);
const currentColorScheme = availableThemes.themes.find((theme) => {
@ -86,7 +90,8 @@ export const getInitialState = async (
capabilities,
match: query,
currentColorScheme,
isAuth
isAuth,
logoUrls
};
return initialState;