Merge branch 'hotfix/v2.6.1' into feature/terms-condition

This commit is contained in:
Tatiana Lopaeva 2024-08-27 11:03:01 +03:00
commit 4643144e83
92 changed files with 694 additions and 1011 deletions

View File

@ -73,6 +73,7 @@
"@babel/preset-react": "^7.18.6",
"@babel/preset-typescript": "^7.21.0",
"@svgr/webpack": "^5.5.0",
"@types/element-resize-detector": "^1.1.6",
"@types/eslint": "^8.44.7",
"@types/he": "^1.2.3",
"@typescript-eslint/eslint-plugin": "^6.12.0",

View File

@ -23,10 +23,12 @@
// All the Product's GUI elements, including illustrations and icon sets, as well as technical writing
// content are licensed under the terms of the Creative Commons Attribution-ShareAlike 4.0
// International. See the License terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
import { useContext } from "react";
import { observer, inject } from "mobx-react";
//import { useLocation } from "react-router-dom";
import { Context } from "@docspace/shared/utils";
import { Events, FileExtensions } from "@docspace/shared/enums";
import RootFolderContainer from "./RootFolderContainer";
@ -49,7 +51,6 @@ const EmptyContainer = ({
theme,
type,
sectionWidth,
isRoomNotFoundOrMoved,
isGracePeriod,
setQuotaWarningDialogVisible,
@ -60,6 +61,8 @@ const EmptyContainer = ({
}) => {
//const location = useLocation();
const { sectionWidth } = useContext(Context);
linkStyles.color = theme.filesEmptyContainer.linkColor;
const onCreate = (e) => {

View File

@ -29,12 +29,15 @@ import {
TFilesSettings,
TFolder,
} from "@docspace/shared/api/files/types";
import { TBreadCrumb } from "@docspace/shared/components/selector/Selector.types";
import {
TBreadCrumb,
TSelectorHeader,
} from "@docspace/shared/components/selector/Selector.types";
import { DeviceType } from "@docspace/shared/enums";
import { TTheme } from "@docspace/shared/themes";
import SocketIOHelper from "@docspace/shared/utils/socket";
export type FilesSelectorProps = {
export type FilesSelectorProps = TSelectorHeader & {
isPanelVisible: boolean;
// withoutImmediatelyClose: boolean;
isThirdParty: boolean;

View File

@ -140,6 +140,7 @@ const FilesSelectorWrapper = ({
openRoot,
filesSettings,
headerProps,
}: FilesSelectorProps) => {
const { t }: { t: TTranslation } = useTranslation([
"Files",
@ -392,6 +393,7 @@ const FilesSelectorWrapper = ({
getFilesArchiveError={getFilesArchiveError}
withCreate={(isMove || isCopy || isRestore || isRestoreAll) ?? false}
filesSettings={filesSettings}
headerProps={headerProps}
/>
);
};

View File

@ -76,10 +76,12 @@ const Main = (props) => {
if (mainBarVisible && isMobileUtils()) {
const mainBar = document.getElementById("main-bar");
if (!mainBar.offsetHeight)
return (updateSizeRef.current = setTimeout(() => onResize(), 0));
if (mainBar) {
if (!mainBar?.offsetHeight)
return (updateSizeRef.current = setTimeout(() => onResize(), 0));
correctHeight -= mainBar.offsetHeight;
correctHeight -= mainBar?.offsetHeight;
}
}
const isTouchDevice =

View File

@ -105,7 +105,7 @@ const RoomsSelectorInput = (props) => {
submitButtonLabel={submitButtonLabel}
onSubmit={handleOnSubmit}
withHeader={withHeader}
headerProps={headerProps}
headerProps={{ ...headerProps, onCloseClick: onClose }}
setIsDataReady={setIsDataReady}
roomType={roomType}
/>
@ -137,6 +137,7 @@ const RoomsSelectorInput = (props) => {
withoutBodyScroll
zIndex={310}
onClose={onClose}
withoutHeader
>
{SelectorBody}
</Aside>

View File

@ -154,6 +154,7 @@ const ChangePortalOwnerDialog = ({
disableSubmitButton={false}
withHeader
headerProps={{
onCloseClick: onCloseAction,
onBackClick,
withoutBackButton: false,
headerLabel: "",

View File

@ -97,11 +97,7 @@ const ChangePricingPlanDialog = ({
isLarge
isLoading={!ready}
>
<ModalDialog.Header>
<Text isBold fontSize="21px">
{t("ChangePricingPlan")}
</Text>
</ModalDialog.Header>
<ModalDialog.Header>{t("ChangePricingPlan")}</ModalDialog.Header>
<ModalDialog.Body>
<Text fontSize="13px" isBold className="cannot-downgrade-plan">
{t("CannotChangePlan")}

View File

@ -1,36 +0,0 @@
// (c) Copyright Ascensio System SIA 2009-2024
//
// This program is a free software product.
// You can redistribute it and/or modify it under the terms
// of the GNU Affero General Public License (AGPL) version 3 as published by the Free Software
// Foundation. In accordance with Section 7(a) of the GNU AGPL its Section 15 shall be amended
// to the effect that Ascensio System SIA expressly excludes the warranty of non-infringement of
// any third-party rights.
//
// This program is distributed WITHOUT ANY WARRANTY, without even the implied warranty
// of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. For details, see
// the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html
//
// You can contact Ascensio System SIA at Lubanas st. 125a-25, Riga, Latvia, EU, LV-1021.
//
// The interactive user interfaces in modified source and object code versions of the Program must
// display Appropriate Legal Notices, as required under Section 5 of the GNU AGPL version 3.
//
// Pursuant to Section 7(b) of the License you must retain the original Product logo when
// distributing the program. Pursuant to Section 7(e) we decline to grant you any rights under
// trademark law for use of our trademarks.
//
// All the Product's GUI elements, including illustrations and icon sets, as well as technical writing
// content are licensed under the terms of the Creative Commons Attribution-ShareAlike 4.0
// International. See the License terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
import styled from "styled-components";
import { ModalDialog } from "@docspace/shared/components/modal-dialog";
const StyledModalDialog = styled(ModalDialog)`
p {
margin-bottom: 16px;
}
`;
export default StyledModalDialog;

View File

@ -34,7 +34,6 @@ import { toastr } from "@docspace/shared/components/toast";
import { setTenantQuotaSettings } from "@docspace/shared/api/settings";
import QuotaForm from "../../../components/QuotaForm";
import StyledModalDialog from "./StyledComponent";
const ChangeStorageQuotaDialog = (props) => {
const {
@ -115,7 +114,7 @@ const ChangeStorageQuotaDialog = (props) => {
};
return (
<StyledModalDialog visible={isVisible} onClose={onCloseClick}>
<ModalDialog visible={isVisible} onClose={onCloseClick}>
<ModalDialog.Header>
{isDisableQuota
? t("Common:DisableStorageQuota")
@ -159,7 +158,7 @@ const ChangeStorageQuotaDialog = (props) => {
scale
/>
</ModalDialog.Footer>
</StyledModalDialog>
</ModalDialog>
);
};

View File

@ -33,7 +33,6 @@ import TagHandler from "./handlers/TagHandler";
import SetRoomParams from "./sub-components/SetRoomParams";
import RoomTypeList from "./sub-components/RoomTypeList";
import DialogHeader from "./sub-components/DialogHeader";
const StyledModalDialog = styled(ModalDialog)`
.header-with-button {
@ -161,6 +160,10 @@ const CreateRoomDialog = ({
onClose();
};
const dialogHeader = roomParams.type
? t("ChooseRoomType")
: t("Files:CreateRoom");
return (
<StyledModalDialog
displayType="aside"
@ -170,14 +173,10 @@ const CreateRoomDialog = ({
isScrollLocked={isScrollLocked}
withFooterBorder
isOauthWindowOpen={isOauthWindowOpen}
isBackButton={roomParams.type}
onBackClick={goBack}
>
<ModalDialog.Header>
<DialogHeader
disabledIcon={Boolean(startRoomType)}
isChooseRoomType={!roomParams.type}
onArrowClick={goBack}
/>
</ModalDialog.Header>
<ModalDialog.Header>{dialogHeader}</ModalDialog.Header>
<ModalDialog.Body>
{!roomParams.type ? (

View File

@ -28,7 +28,6 @@ import React, { useState, useEffect, useRef, useCallback } from "react";
import TagHandler from "./handlers/TagHandler";
import SetRoomParams from "./sub-components/SetRoomParams";
import DialogHeader from "./sub-components/DialogHeader";
import { ModalDialog } from "@docspace/shared/components/modal-dialog";
import { Button } from "@docspace/shared/components/button";
@ -132,9 +131,7 @@ const EditRoomDialog = ({
isScrollLocked={isScrollLocked}
withFooterBorder
>
<ModalDialog.Header>
<DialogHeader isEdit />
</ModalDialog.Header>
<ModalDialog.Header>{t("RoomEditing")}</ModalDialog.Header>
<ModalDialog.Body>
<SetRoomParams

View File

@ -1,67 +0,0 @@
// (c) Copyright Ascensio System SIA 2009-2024
//
// This program is a free software product.
// You can redistribute it and/or modify it under the terms
// of the GNU Affero General Public License (AGPL) version 3 as published by the Free Software
// Foundation. In accordance with Section 7(a) of the GNU AGPL its Section 15 shall be amended
// to the effect that Ascensio System SIA expressly excludes the warranty of non-infringement of
// any third-party rights.
//
// This program is distributed WITHOUT ANY WARRANTY, without even the implied warranty
// of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. For details, see
// the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html
//
// You can contact Ascensio System SIA at Lubanas st. 125a-25, Riga, Latvia, EU, LV-1021.
//
// The interactive user interfaces in modified source and object code versions of the Program must
// display Appropriate Legal Notices, as required under Section 5 of the GNU AGPL version 3.
//
// Pursuant to Section 7(b) of the License you must retain the original Product logo when
// distributing the program. Pursuant to Section 7(e) we decline to grant you any rights under
// trademark law for use of our trademarks.
//
// All the Product's GUI elements, including illustrations and icon sets, as well as technical writing
// content are licensed under the terms of the Creative Commons Attribution-ShareAlike 4.0
// International. See the License terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
import ArrowPathReactSvgUrl from "PUBLIC_DIR/images/arrow.path.react.svg?url";
import React from "react";
import { withTranslation } from "react-i18next";
import withLoader from "@docspace/client/src/HOCs/withLoader";
import { IconButton } from "@docspace/shared/components/icon-button";
import CreateEditRoomDilogHeaderLoader from "@docspace/shared/skeletons/create-edit-room/DilogHeader";
const DialogHeader = ({
t,
isEdit,
isChooseRoomType,
onArrowClick,
disabledIcon,
}) => {
return (
<>
{isEdit ? (
<span>{t("RoomEditing")}</span>
) : isChooseRoomType ? (
<span>{t("ChooseRoomType")}</span>
) : (
<div className="header-with-button">
{!disabledIcon && (
<IconButton
size={17}
iconName={ArrowPathReactSvgUrl}
className="sharing_panel-arrow"
onClick={onArrowClick}
/>
)}
<div>{t("Files:CreateRoom")}</div>
</div>
)}
</>
);
};
export default withTranslation(["CreateEditRoomDialog", "Files"])(
withLoader(DialogHeader)(<CreateEditRoomDilogHeaderLoader />),
);

View File

@ -227,6 +227,7 @@ const DataReassignmentDialog = ({
withCancelButton
cancelButtonLabel=""
headerProps={{
onCloseClick: onClose,
onBackClick: onClosePeopleSelector,
withoutBackButton: false,
headerLabel: "",

View File

@ -43,7 +43,7 @@ import { toastr } from "@docspace/shared/components/toast";
import { HelpButton } from "@docspace/shared/components/help-button";
import { getUserRoleOptions } from "@docspace/shared/utils/room-members/getUserRoleOptions";
import { ShareAccessRights } from "@docspace/shared/enums";
import { getUserRole } from "@docspace/shared/utils/common";
import { getUserRole, getUserTypeLabel } from "@docspace/shared/utils/common";
import { TGroupMemberInvitedInRoom } from "@docspace/shared/api/groups/types";
import * as Styled from "./index.styled";
@ -59,7 +59,7 @@ const GroupMember = ({ member, infoPanelSelection }: GroupMemberProps) => {
const [isLoading, setIsLoading] = useState(false);
const { t } = useTranslation("Common");
const userRole = user.isOwner
const userRole = member.owner
? getUserRoleOptions(t).portalAdmin
: getUserRoleOptionsByUserAccess(
t,
@ -74,6 +74,10 @@ const GroupMember = ({ member, infoPanelSelection }: GroupMemberProps) => {
const userRoleOptions = filterUserRoleOptions(fullRoomRoleOptions, user);
const hasIndividualRightsInRoom =
member.owner ||
(member.userAccess && member.userAccess !== member.groupAccess);
let type;
if (user.isOwner) type = "owner";
else if (user.isAdmin) type = "admin";
@ -83,6 +87,11 @@ const GroupMember = ({ member, infoPanelSelection }: GroupMemberProps) => {
const role = getUserRole(user, userRole?.type);
const typeLabel = getUserTypeLabel(
role as "owner" | "admin" | "user" | "collaborator" | "manager",
t,
);
let selectedUserRoleCBOption;
if (user.isOwner)
selectedUserRoleCBOption = {
@ -140,26 +149,25 @@ const GroupMember = ({ member, infoPanelSelection }: GroupMemberProps) => {
{decode(user.displayName)}
</Text>
<Text className="email" noSelect>
{user.email}
<span dir="auto">{typeLabel}</span> |{" "}
<span dir="ltr">{user.email}</span>
</Text>
</div>
</div>
<div className="individual-rights-tooltip">
{member.userAccess &&
member.userAccess !== member.groupAccess &&
!user.isOwner && (
<HelpButton
place="left"
offsetRight={0}
openOnClick={false}
tooltipContent={
<Text fontSize="12px" fontWeight={600}>
{t("PeopleTranslations:IndividualRights")}
</Text>
}
/>
)}
{hasIndividualRightsInRoom && (
<HelpButton
place="left"
offsetRight={0}
openOnClick={false}
tooltipContent={
<Text fontSize="12px" fontWeight={600}>
{t("PeopleTranslations:IndividualRights")}
</Text>
}
/>
)}
</div>
{userRole && userRoleOptions && (

View File

@ -529,6 +529,7 @@ const AddUsersPanel = ({
visible={visible}
onClose={onClosePanels}
withoutBodyScroll
withoutHeader
>
<Selector
withHeader
@ -539,6 +540,7 @@ const AddUsersPanel = ({
withoutBackButton: false,
withoutBorder: true,
onBackClick,
onCloseClick: onClosePanels,
}}
onSelect={onSelect}
renderCustomItem={renderCustomItem}

View File

@ -26,7 +26,6 @@
import React from "react";
import { Backdrop } from "@docspace/shared/components/backdrop";
import { Heading } from "@docspace/shared/components/heading";
import { Aside } from "@docspace/shared/components/aside";
import { Button } from "@docspace/shared/components/button";
import { Text } from "@docspace/shared/components/text";
@ -38,7 +37,6 @@ import {
StyledAsidePanel,
StyledContent,
StyledFooter,
StyledHeaderContent,
StyledBody,
} from "../StyledPanels";
import { inject, observer } from "mobx-react";
@ -116,13 +114,9 @@ class ChangeOwnerComponent extends React.Component {
className="header_aside-panel"
visible={visible}
onClose={this.onClose}
header={t("ChangeOwner", { fileName })}
>
<StyledContent>
<StyledHeaderContent>
<Heading className="sharing_panel-header" size="medium" truncate>
{t("ChangeOwner", { fileName })}
</Heading>
</StyledHeaderContent>
<StyledBody>
<div className="change-owner_body">
<Link

View File

@ -120,6 +120,7 @@ const ChangeRoomOwner = (props) => {
className="header_aside-panel"
visible={visible}
onClose={onClose}
withoutHeader
withoutBodyScroll
>
<PeopleSelector
@ -133,6 +134,7 @@ const ChangeRoomOwner = (props) => {
disableSubmitButton={false}
withHeader
headerProps={{
onCloseClick: onClose,
onBackClick,
withoutBackButton: !showBackButton,
headerLabel: t("Files:ChangeTheRoomOwner"),

View File

@ -28,10 +28,6 @@ import styled, { css } from "styled-components";
import { ModalDialog } from "@docspace/shared/components/modal-dialog";
const StyledModalDialog = styled(ModalDialog)`
.modal-header {
margin: 0;
}
.modal-body {
padding: 0;
}

View File

@ -43,16 +43,6 @@ const StyledHotkeysPanel = styled.div`
}
}
.hotkeys_header {
padding: 0 16px;
border-bottom: ${(props) => props.theme.filesPanels.sharing.borderBottom};
.hotkeys_heading {
font-weight: 700;
font-size: 18px;
}
}
.hotkeys_sub-header {
font-weight: 700;
font-size: 16px;

View File

@ -90,10 +90,8 @@ const HotkeyPanel = ({
visible={visible}
onClose={onClose}
withoutBodyScroll={true}
header={t("Common:Hotkeys")}
>
<div className="hotkeys_header">
<Heading className="hotkeys_heading">{t("Common:Hotkeys")}</Heading>
</div>
<StyledScrollbar ref={scrollRef}>
<Heading className="hotkeys_sub-header">
{t("HotkeysNavigation")}

View File

@ -38,7 +38,6 @@ import { ToggleButton } from "@docspace/shared/components/toggle-button";
import { mobile, commonIconsStyles } from "@docspace/shared/utils";
import CheckIcon from "PUBLIC_DIR/images/check.edit.react.svg";
import CrossIcon from "PUBLIC_DIR/images/cross.edit.react.svg";
import CrossIconMobile from "PUBLIC_DIR/images/cross.react.svg";
import DeleteIcon from "PUBLIC_DIR/images/mobile.actions.remove.react.svg";
import { isMobile, desktop, commonInputStyles } from "@docspace/shared/utils";
import Base from "@docspace/shared/themes/base";
@ -124,24 +123,15 @@ const ScrollList = styled.div`
}
`;
const StyledBlock = styled.div`
padding: ${(props) => (props.noPadding ? "0px" : "0 16px")};
const StyledExternalLink = styled.div`
border-bottom: ${(props) => props.theme.filesPanels.sharing.borderBottom};
`;
StyledBlock.defaultProps = { theme: Base };
const StyledInviteUserBody = styled.div`
display: flex;
flex-direction: column;
overflow: auto;
`;
const StyledHeading = styled(Heading)`
font-weight: 700;
font-size: 18px;
`;
const StyledSubHeader = styled(Heading)`
font-weight: 700;
font-size: 16px;
@ -440,14 +430,6 @@ StyledCrossIcon.defaultProps = { theme: Base };
const StyledDeleteIcon = styled(DeleteIcon)`
cursor: pointer;
${(props) =>
props.theme.interfaceDirection === "rtl"
? css`
margin-right: auto;
`
: css`
margin-left: auto;
`}
${iconStyles}
`;
@ -501,25 +483,6 @@ const StyledToggleButton = styled(ToggleButton)`
margin-top: -4px;
`;
const StyledControlContainer = styled.div`
width: 17px;
height: 17px;
position: absolute;
cursor: pointer;
align-items: center;
justify-content: center;
z-index: 450;
@media ${mobile} {
display: flex;
top: -27px;
right: 10px;
left: unset;
}
`;
const StyledInviteLanguage = styled.div`
padding-left: 16px;
padding-right: 16px;
@ -574,19 +537,17 @@ const StyledInviteLanguage = styled.div`
gap: 2px;
}
`;
const StyledCrossIconMobile = styled(CrossIconMobile)`
width: 17px;
height: 17px;
z-index: 455;
path {
fill: ${(props) => props.theme.catalog.control.fill};
}
`;
StyledCrossIcon.defaultProps = { theme: Base };
const ErrorWrapper = styled.div`
display: flex;
flex-wrap: nowrap;
gap: 12px;
margin-inline-start: auto;
`;
export {
StyledBlock,
StyledHeading,
StyledInvitePanel,
StyledRow,
StyledSubHeader,
@ -608,7 +569,7 @@ export {
StyledToggleButton,
StyledDescription,
StyledInviteLanguage,
StyledControlContainer,
StyledCrossIconMobile,
StyledInviteUserBody,
StyledExternalLink,
ErrorWrapper,
};

View File

@ -38,20 +38,13 @@ import { DeviceType, EmployeeType } from "@docspace/shared/enums";
import { LOADER_TIMEOUT } from "@docspace/shared/constants";
import { Backdrop } from "@docspace/shared/components/backdrop";
import { Aside } from "@docspace/shared/components/aside";
import { Aside, AsideHeader } from "@docspace/shared/components/aside";
import { Button } from "@docspace/shared/components/button";
import { toastr } from "@docspace/shared/components/toast";
import { Portal } from "@docspace/shared/components/portal";
import { isDesktop, isMobile, size } from "@docspace/shared/utils";
import {
StyledBlock,
StyledHeading,
StyledInvitePanel,
StyledButtons,
StyledControlContainer,
StyledCrossIconMobile,
} from "./StyledInvitePanel";
import { StyledInvitePanel, StyledButtons } from "./StyledInvitePanel";
import ItemsList from "./sub-components/ItemsList";
import InviteInput from "./sub-components/InviteInput";
@ -60,7 +53,7 @@ import { Scrollbar } from "@docspace/shared/components/scrollbar";
import InfoBar from "./sub-components/InfoBar";
import InvitePanelLoader from "./sub-components/InvitePanelLoader";
import { Link } from "@docspace/shared/components/link";
import { Text } from "@docspace/shared/components/text";
import { combineUrl } from "@docspace/shared/utils/combineUrl";
import { ColorTheme, ThemeId } from "@docspace/shared/components/color-theme";
@ -429,9 +422,6 @@ const InvitePanel = ({
const invitePanelNode = (
<>
<StyledBlock>
<StyledHeading>{t("Common:InviteUsers")}</StyledHeading>
</StyledBlock>
{invitePanelIsLoding ? (
<InvitePanelLoader />
) : (
@ -479,9 +469,11 @@ const InvitePanel = ({
>
{isMobileView ? (
<div className="invite_panel" ref={invitePanelRef}>
<StyledControlContainer onClick={onClose}>
<StyledCrossIconMobile />
</StyledControlContainer>
<AsideHeader
header={t("Common:InviteUsers")}
onCloseClick={onClose}
/>
{invitePanelNode}
</div>
) : (
@ -498,6 +490,7 @@ const InvitePanel = ({
onClose={onClose}
withoutBodyScroll
zIndex={310}
header={t("Common:InviteUsers")}
>
{invitePanelNode}
</Aside>

View File

@ -45,12 +45,12 @@ import { Text } from "@docspace/shared/components/text";
import AccessSelector from "../../../AccessSelector";
import PaidQuotaLimitError from "../../../PaidQuotaLimitError";
import {
StyledBlock,
StyledSubHeader,
StyledInviteInput,
StyledInviteInputContainer,
StyledToggleButton,
StyledDescription,
StyledExternalLink,
} from "../StyledInvitePanel";
import { getFreeUsersRoleArray, getFreeUsersTypeArray } from "../utils";
@ -212,7 +212,7 @@ const ExternalLinks = ({
roomId === -1 ? getFreeUsersTypeArray() : getFreeUsersRoleArray();
return (
<StyledBlock noPadding ref={inputsRef}>
<StyledExternalLink noPadding ref={inputsRef}>
<StyledSubHeader inline>
{t("InviteViaLink")}
{false && ( //TODO: Change to linksVisible after added link information from backend
@ -285,7 +285,7 @@ const ExternalLinks = ({
/>
</StyledInviteInputContainer>
)}
</StyledBlock>
</StyledExternalLink>
);
};

View File

@ -49,6 +49,7 @@ import {
StyledHelpButton,
StyledDeleteIcon,
StyledInviteUserBody,
ErrorWrapper,
} from "../StyledInvitePanel";
import { filterGroupRoleOptions, filterUserRoleOptions } from "SRC_DIR/helpers";
import AccessSelector from "../../../AccessSelector";
@ -229,7 +230,7 @@ const Item = ({
</StyledInviteUserBody>
{hasError ? (
<>
<ErrorWrapper>
<StyledHelpButton
iconName={InfoEditReactSvgUrl}
displayType="auto"
@ -244,7 +245,7 @@ const Item = ({
size="medium"
onClick={removeItem}
/>
</>
</ErrorWrapper>
) : (
<>
{warning && (

View File

@ -256,39 +256,6 @@ const StyledContent = styled.div`
StyledContent.defaultProps = { theme: Base };
const StyledHeaderContent = styled.div`
display: flex;
align-items: center;
padding: 0 16px;
${(props) =>
props.theme.interfaceDirection === "rtl"
? css`
margin-left: -16px;
`
: css`
margin-right: -16px;
`}
border-bottom: ${(props) => props.theme.filesPanels.sharing.borderBottom};
.files-operations-header,
.sharing_panel-header {
font-weight: 700;
margin: 14px 0;
}
@media ${desktop} {
.files-operations-header,
.sharing_panel-header {
margin: 12px 0;
font-size: 18px;
}
}
`;
StyledHeaderContent.defaultProps = { theme: Base };
const StyledBody = styled.div`
&.files-operations-body {
${(props) =>
@ -711,13 +678,6 @@ const StyledLink = styled(Link)`
StyledModalRowContainer.defaultProps = { theme: Base };
const StyledUploadHeader = styled.div`
width: 100%;
display: flex;
align-items: center;
justify-content: space-between;
`;
const StyledUploadBody = styled.div`
width: calc(100% + 16px);
height: 100%;
@ -732,13 +692,11 @@ export {
StyledEmbeddingPanel,
StyledVersionHistoryPanel,
StyledContent,
StyledHeaderContent,
StyledBody,
StyledFooter,
StyledLinkRow,
StyledModalRowContainer,
StyledLink,
StyledNewFilesBody,
StyledUploadHeader,
StyledUploadBody,
};

View File

@ -39,9 +39,10 @@ import {
} from "@docspace/shared/components/modal-dialog";
import { DialogAsideSkeleton } from "@docspace/shared/skeletons/dialog";
import { StyledUploadHeader, StyledUploadBody } from "../StyledPanels";
import { StyledUploadBody } from "../StyledPanels";
import FileList from "./FileList";
import withLoader from "../../../HOCs/withLoader";
import { AsideHeader } from "@docspace/shared/components/aside";
const StyledModal = styled(ModalDialog)`
.heading {
@ -124,34 +125,24 @@ class UploadPanelComponent extends React.Component {
? t("UploadAndConvert")
: t("Files:Convert");
const url =
uploaded && converted ? ClearReactSvgUrl : ButtonCancelReactSvgUrl;
const clickEvent =
uploaded && converted
? this.clearUploadPanel
: uploaded
? cancelConversion
: this.onCancelUpload;
return (
<StyledModal
visible={visible}
onClose={this.onClose}
displayType={ModalDialogType.aside}
headerIcons={[{ key: "upload-panel", url, onClick: clickEvent }]}
>
<ModalDialog.Header>
<StyledUploadHeader>
<div>{title}</div>
<div>
{uploaded && converted ? (
<IconButton
size={17}
iconName={ClearReactSvgUrl}
isClickable
onClick={this.clearUploadPanel}
/>
) : (
<IconButton
size="20"
iconName={ButtonCancelReactSvgUrl}
isClickable
onClick={uploaded ? cancelConversion : this.onCancelUpload}
/>
)}
</div>
</StyledUploadHeader>
</ModalDialog.Header>
<ModalDialog.Header>{title}</ModalDialog.Header>
<ModalDialog.Body>
<StyledUploadBody>
<FileList />

View File

@ -27,7 +27,6 @@
import React from "react";
import PropTypes from "prop-types";
import { Backdrop } from "@docspace/shared/components/backdrop";
import { Heading } from "@docspace/shared/components/heading";
import { Aside } from "@docspace/shared/components/aside";
import { FloatingButton } from "@docspace/shared/components/floating-button";
@ -37,13 +36,11 @@ import { withTranslation } from "react-i18next";
import {
StyledVersionHistoryPanel,
StyledContent,
StyledHeaderContent,
StyledBody,
} from "../StyledPanels";
import { SectionBodyContent } from "../../../pages/VersionHistory/Section/";
import { inject, observer } from "mobx-react";
import config from "PACKAGE_FILE";
import { ArticleHeaderLoader } from "@docspace/shared/skeletons/article";
class PureVersionHistoryPanel extends React.Component {
onClose = () => {
@ -85,26 +82,10 @@ class PureVersionHistoryPanel extends React.Component {
visible={visible}
onClose={this.onClose}
withoutBodyScroll
isLoading={!versions && !isLoading}
header={versions ? versions[0].title : ""}
>
<StyledContent>
<StyledHeaderContent className="version-history-panel-header">
{versions && !isLoading ? (
<Heading
className="version-history-panel-heading"
size="medium"
truncate
>
{versions[0].title}
</Heading>
) : (
<ArticleHeaderLoader
className="loader-version-history"
height="28"
width="688"
/>
)}
</StyledHeaderContent>
<StyledBody className="version-history-panel-body">
<SectionBodyContent onClose={this.onClose} />
</StyledBody>

View File

@ -98,6 +98,7 @@ const SortFilter = ({ t, oformsFilter, sortOforms }) => {
fillIcon={false}
options={[]}
selectedOption={{}}
manualWidth={"auto"}
advancedOptions={
<>
{sortData?.map((item) => (

View File

@ -24,14 +24,10 @@
// content are licensed under the terms of the Creative Commons Attribution-ShareAlike 4.0
// International. See the License terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
import CrossReactSvgUrl from "PUBLIC_DIR/images/icons/17/cross.react.svg?url";
import React, { useState, useEffect } from "react";
import { inject, observer } from "mobx-react";
import { withTranslation } from "react-i18next";
import { IconButton } from "@docspace/shared/components/icon-button";
import { Text } from "@docspace/shared/components/text";
import { Tabs } from "@docspace/shared/components/tabs";
import {
isDesktop as isDesktopUtils,
@ -43,6 +39,7 @@ import { StyledInfoPanelHeader } from "./styles/common";
import { PluginFileType } from "SRC_DIR/helpers/plugins/enums";
import { FolderType } from "@docspace/shared/enums";
import { AsideHeader } from "@docspace/shared/components/aside";
const InfoPanelHeaderContent = (props) => {
const {
@ -194,25 +191,12 @@ const InfoPanelHeaderContent = (props) => {
return (
<StyledInfoPanelHeader isTablet={isTablet} withTabs={withTabs}>
<div className="main">
<Text className="header-text" fontSize="21px" fontWeight="700">
{t("Common:Info")}
</Text>
{!isTablet && (
<div className="info-panel-toggle-bg">
<IconButton
isStroke
size="17"
onClick={closeInfoPanel}
iconName={CrossReactSvgUrl}
title={t("Common:InfoPanel")}
className="info-panel-toggle"
id="info-panel-toggle--close"
/>
</div>
)}
</div>
<AsideHeader
header={t("Common:Info")}
onCloseClick={closeInfoPanel}
withoutBorder
className="header-text"
/>
{withTabs && (
<div className="tabs">

View File

@ -28,11 +28,11 @@ import styled, { css } from "styled-components";
import { Base } from "@docspace/shared/themes";
import { tablet } from "@docspace/shared/utils";
const getHeaderHeight = ({ withTabs, isTablet }) => {
let res = isTablet ? 53 : 69;
if (withTabs) res += 32;
return `${res}px`;
};
// const getHeaderHeight = ({ withTabs, isTablet }) => {
// let res = isTablet ? 54 : 70;
// if (withTabs) res += 32;
// return `${res}px`;
// };
const getMainHeight = ({ isTablet }) => {
let res = isTablet ? 52 : 68;
@ -43,52 +43,17 @@ const StyledInfoPanelHeader = styled.div`
width: 100%;
max-width: 100%;
height: ${(props) => getHeaderHeight(props)};
min-height: ${(props) => getHeaderHeight(props)};
@media ${tablet} {
height: ${(props) => getHeaderHeight({ ...props, isTablet: true })};
min-height: ${(props) => getHeaderHeight({ ...props, isTablet: true })};
}
display: flex;
flex-direction: column;
border-bottom: ${(props) =>
props.withTabs ? "none" : `1px solid ${props.theme.infoPanel.borderColor}`};
.main {
.header-text {
height: ${(props) => getMainHeight(props)};
min-height: ${(props) => getMainHeight(props)};
@media ${tablet} {
height: ${(props) => getMainHeight({ ...props, isTablet: true })};
min-height: ${(props) => getMainHeight({ ...props, isTablet: true })};
}
display: flex;
flex-direction: row;
align-items: center;
justify-content: space-between;
.header-text {
${(props) =>
props.theme.interfaceDirection === "rtl"
? css`
margin-right: 20px;
`
: css`
margin-left: 20px;
`}
}
}
.info-panel-toggle-bg {
${(props) =>
props.theme.interfaceDirection === "rtl"
? css`
margin-left: 20px;
`
: css`
margin-right: 20px;
`}
}
.tabs {
display: flex;
width: 100%;

View File

@ -25,12 +25,13 @@
// International. See the License terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
import styled from "styled-components";
import { useMemo } from "react";
import { useMemo, useContext } from "react";
import { inject, observer } from "mobx-react";
import useViewEffect from "SRC_DIR/Hooks/useViewEffect";
import { Base } from "@docspace/shared/themes";
import { Context } from "@docspace/shared/utils";
import { RowContainer } from "@docspace/shared/components/row-container";
import SimpleFilesRow from "./SimpleFilesRow";
@ -62,7 +63,6 @@ StyledRowContainer.defaultProps = { theme: Base };
const FilesRowContainer = ({
filesList,
sectionWidth,
viewAs,
setViewAs,
infoPanelVisible,
@ -75,6 +75,8 @@ const FilesRowContainer = ({
highlightFile,
currentDeviceType,
}) => {
const { sectionWidth } = useContext(Context);
useViewEffect({
view: viewAs,
setView: setViewAs,

View File

@ -28,13 +28,20 @@ import { inject, observer } from "mobx-react";
import styled, { css } from "styled-components";
import { useNavigate, useLocation } from "react-router-dom";
import elementResizeDetectorMaker from "element-resize-detector";
import React, { useEffect, useRef, useCallback, useMemo } from "react";
import React, {
useEffect,
useRef,
useCallback,
useMemo,
useContext,
} from "react";
import useViewEffect from "SRC_DIR/Hooks/useViewEffect";
import { Base } from "@docspace/shared/themes";
import { TableContainer } from "@docspace/shared/components/table";
import { TableBody } from "@docspace/shared/components/table";
import { Context } from "@docspace/shared/utils";
import TableRow from "./TableRow";
import TableHeader from "./TableHeader";
@ -121,7 +128,6 @@ const elementResizeDetector = elementResizeDetectorMaker({
const Table = ({
filesList,
sectionWidth,
viewAs,
setViewAs,
setFirsElemChecked,
@ -142,6 +148,8 @@ const Table = ({
const [tagCount, setTagCount] = React.useState(null);
const [hideColumns, setHideColumns] = React.useState(false);
const { sectionWidth } = useContext(Context);
const ref = useRef(null);
const tagRef = useRef(null);

View File

@ -24,14 +24,17 @@
// content are licensed under the terms of the Creative Commons Attribution-ShareAlike 4.0
// International. See the License terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
import React, { useEffect } from "react";
import React, { useEffect, useContext } from "react";
import styled from "styled-components";
import { inject, observer } from "mobx-react";
import { withTranslation } from "react-i18next";
import DragAndDrop from "@docspace/shared/components/drag-and-drop/DragAndDrop";
// import { Context } from "@docspace/shared/utils";
import Tile from "./sub-components/Tile";
import FilesTileContent from "./FilesTileContent";
import { FileTileContext } from "./FileTile.provider";
import withFileActions from "../../../../../HOCs/withFileActions";
import withQuickButtons from "../../../../../HOCs/withQuickButtons";
@ -45,7 +48,6 @@ const StyledDragAndDrop = styled(DragAndDrop)`
const FileTile = (props) => {
const {
item,
sectionWidth,
dragging,
onContentFileSelect,
fileContextClick,
@ -70,12 +72,12 @@ const FileTile = (props) => {
t,
getContextModel,
onHideContextMenu,
thumbSize,
// thumbSize,
setSelection,
id,
onSelectTag,
onSelectOption,
columnCount,
// columnCount,
isRooms,
withCtrlSelect,
withShiftSelect,
@ -86,6 +88,10 @@ const FileTile = (props) => {
badgeUrl,
} = props;
// const { sectionWidth } = useContext(Context);
const { columnCount, thumbSize } = useContext(FileTileContext);
const temporaryExtension =
item.id === -1 ? `.${item.fileExst}` : item.fileExst;
@ -145,7 +151,7 @@ const FileTile = (props) => {
: thumbnailUrl
}
element={element}
sectionWidth={sectionWidth}
// sectionWidth={sectionWidth}
contentElement={quickButtonsComponent}
onSelect={onContentFileSelect}
tileContextClick={fileContextClick}
@ -177,7 +183,7 @@ const FileTile = (props) => {
>
<FilesTileContent
item={item}
sectionWidth={sectionWidth}
// sectionWidth={sectionWidth}
onFilesClick={onFilesClick}
/>
{badgesComponent}

View File

@ -0,0 +1,28 @@
import { createContext, PropsWithChildren, useMemo } from "react";
type FileTileContextType = {
thumbSize: string;
columnCount: null | number;
};
export const FileTileContext = createContext<FileTileContextType>({
columnCount: null,
thumbSize: "",
});
export const FileTileProvider = ({
children,
columnCount,
thumbSize,
}: PropsWithChildren<FileTileContextType>) => {
const value = useMemo(
() => ({ columnCount, thumbSize }),
[thumbSize, columnCount],
);
return (
<FileTileContext.Provider value={value}>
{children}
</FileTileContext.Provider>
);
};

View File

@ -0,0 +1,30 @@
import elementResizeDetectorMaker from "element-resize-detector";
export const getThumbSize = (width: number): string => {
let imgWidth = 216;
if (width >= 240 && width < 264) {
imgWidth = 240;
} else if (width >= 264 && width < 288) {
imgWidth = 264;
} else if (width >= 288 && width < 312) {
imgWidth = 288;
} else if (width >= 312 && width < 336) {
imgWidth = 312;
} else if (width >= 336 && width < 360) {
imgWidth = 336;
} else if (width >= 360 && width < 400) {
imgWidth = 360;
} else if (width >= 400 && width < 440) {
imgWidth = 400;
} else if (width >= 440) {
imgWidth = 440;
}
return `${imgWidth}x156`;
};
export const elementResizeDetector = elementResizeDetectorMaker({
strategy: "scroll",
callOnAdd: false,
});

View File

@ -30,45 +30,21 @@ import React, {
useCallback,
useState,
useMemo,
useContext,
} from "react";
import { inject, observer } from "mobx-react";
import elementResizeDetectorMaker from "element-resize-detector";
import TileContainer from "./sub-components/TileContainer";
import { Context } from "@docspace/shared/utils";
import FileTile from "./FileTile";
import { FileTileProvider } from "./FileTile.provider";
import { elementResizeDetector, getThumbSize } from "./FileTile.utils";
const getThumbSize = (width) => {
let imgWidth = 216;
if (width >= 240 && width < 264) {
imgWidth = 240;
} else if (width >= 264 && width < 288) {
imgWidth = 264;
} else if (width >= 288 && width < 312) {
imgWidth = 288;
} else if (width >= 312 && width < 336) {
imgWidth = 312;
} else if (width >= 336 && width < 360) {
imgWidth = 336;
} else if (width >= 360 && width < 400) {
imgWidth = 360;
} else if (width >= 400 && width < 440) {
imgWidth = 400;
} else if (width >= 440) {
imgWidth = 440;
}
return `${imgWidth}x156`;
};
const elementResizeDetector = elementResizeDetectorMaker({
strategy: "scroll",
callOnAdd: false,
});
import TileContainer from "./sub-components/TileContainer";
const FilesTileContainer = ({
filesList,
t,
sectionWidth,
withPaging,
thumbnails1280x720,
}) => {
@ -78,6 +54,8 @@ const FilesTileContainer = ({
const [thumbSize, setThumbSize] = useState("");
const [columnCount, setColumnCount] = useState(null);
const { sectionWidth } = useContext(Context);
useEffect(() => {
return () => {
isMountedRef.current = false;
@ -139,10 +117,7 @@ const FilesTileContainer = ({
}
item={item}
itemIndex={index}
sectionWidth={sectionWidth}
selectableRef={onSetTileRef}
thumbSize={thumbSize}
columnCount={columnCount}
withRef={true}
/>
) : (
@ -153,24 +128,23 @@ const FilesTileContainer = ({
}
item={item}
itemIndex={index}
sectionWidth={sectionWidth}
thumbSize={thumbSize}
columnCount={columnCount}
/>
);
});
}, [filesList, sectionWidth, onSetTileRef, thumbSize, columnCount]);
}, [filesList, onSetTileRef, sectionWidth]);
return (
<TileContainer
className="tile-container"
draggable
useReactWindow={!withPaging}
headingFolders={t("Translations:Folders")}
headingFiles={t("Translations:Files")}
>
{filesListNode}
</TileContainer>
<FileTileProvider columnCount={columnCount} thumbSize={thumbSize}>
<TileContainer
className="tile-container"
draggable
useReactWindow={!withPaging}
headingFolders={t("Translations:Folders")}
headingFiles={t("Translations:Files")}
>
{filesListNode}
</TileContainer>
</FileTileProvider>
);
};

View File

@ -26,9 +26,8 @@
import React, { useEffect } from "react";
import { withTranslation } from "react-i18next";
import { useLocation } from "react-router-dom";
import { observer, inject } from "mobx-react";
import FilesRowContainer from "./RowsView/FilesRowContainer";
import FilesTileContainer from "./TilesView/FilesTileContainer";
import EmptyContainer from "../../../../components/EmptyContainer";
@ -37,7 +36,6 @@ import TableView from "./TableView/TableContainer";
import withHotkeys from "../../../../HOCs/withHotkeys";
import {
clearEdgeScrollingTimer,
Consumer,
isMobile,
isTablet,
onEdgeScrolling,
@ -307,36 +305,18 @@ const SectionBodyContent = (props) => {
if (isEmptyFilesList && movingInProgress) return <></>;
const showEmptyPage = isEmptyFilesList;
if (isEmptyFilesList) return <EmptyContainer isEmptyPage={isEmptyPage} />;
return (
<Consumer>
{(context) =>
showEmptyPage ? (
<>
<EmptyContainer
sectionWidth={context.sectionWidth}
isEmptyPage={isEmptyPage}
/>
</>
) : viewAs === "tile" ? (
<>
<FilesTileContainer sectionWidth={context.sectionWidth} t={t} />
</>
) : viewAs === "table" ? (
<>
<TableView sectionWidth={context.sectionWidth} tReady={tReady} />
</>
) : (
<>
<FilesRowContainer
sectionWidth={context.sectionWidth}
tReady={tReady}
/>
</>
)
}
</Consumer>
<>
{viewAs === "tile" ? (
<FilesTileContainer t={t} />
) : viewAs === "table" ? (
<TableView tReady={tReady} />
) : (
<FilesRowContainer tReady={tReady} />
)}
</>
);
};

View File

@ -54,6 +54,7 @@ const DataImport = ({
getMigrationStatus,
isMigrationInit,
setIsMigrationInit,
tReady,
}) => {
const navigate = useNavigate();
@ -109,10 +110,13 @@ const DataImport = ({
};
useEffect(() => {
setDocumentTitle(t("DataImport"));
handleMigrationCheck();
}, []);
useEffect(() => {
if (tReady) setDocumentTitle(t("DataImport"));
}, [tReady]);
const redirectToWorkspace = (title) => {
switch (title) {
case "GoogleWorkspace":

View File

@ -66,7 +66,7 @@ const { EveryDayType, EveryWeekType, EveryMonthType } = AutoBackupPeriod;
class AutomaticBackup extends React.PureComponent {
constructor(props) {
super(props);
const { t, language } = props;
const { t, tReady, language } = props;
moment.locale(language);
this.state = {
@ -96,7 +96,7 @@ class AutomaticBackup extends React.PureComponent {
this.maxNumberCopiesArray = [];
this.weekdaysLabelArray = [];
setDocumentTitle(t("AutoBackup"));
if (tReady) setDocumentTitle(t("AutoBackup"));
this.getTime();
this.getMonthNumbers();
@ -170,6 +170,12 @@ class AutomaticBackup extends React.PureComponent {
this.setBasicSettings();
}
componentDidUpdate(prevProps) {
const { t, tReady } = this.props;
if (prevProps.tReady !== tReady && tReady)
setDocumentTitle(t("AutoBackup"));
}
componentWillUnmount() {
const { clearProgressInterval } = this.props;
clearTimeout(this.timerId);

View File

@ -70,9 +70,9 @@ class ManualBackup extends React.Component {
this.timerId = null;
const { t } = props;
const { t, tReady } = props;
setDocumentTitle(t("DataBackup"));
if (tReady) setDocumentTitle(t("DataBackup"));
this.state = {
selectedFolder: "",
@ -150,6 +150,13 @@ class ManualBackup extends React.Component {
this.setBasicSettings();
}
componentDidUpdate(prevProps) {
const { t, tReady } = this.props;
if (prevProps.tReady !== tReady && tReady)
setDocumentTitle(t("DataBackup"));
}
componentWillUnmount() {
const { clearProgressInterval } = this.props;
clearTimeout(this.timerId);

View File

@ -230,11 +230,7 @@ const BackupListModalDialog = (props) => {
onClose={onModalClose}
withFooterBorder
>
<ModalDialog.Header>
<Text fontSize="21px" fontWeight={700}>
{t("BackupList")}
</Text>
</ModalDialog.Header>
<ModalDialog.Header>{t("BackupList")}</ModalDialog.Header>
<ModalDialog.Body>
<StyledBackupList
isCopyingToLocal={isCopyingToLocal}

View File

@ -118,7 +118,7 @@ const PresetsContainer = styled.div`
`;
const PortalIntegration = (props) => {
const { t, currentColorScheme, sdkLink, theme } = props;
const { t, currentColorScheme, sdkLink, theme, tReady } = props;
const isSmall = useRef(
(() => {
@ -130,8 +130,6 @@ const PortalIntegration = (props) => {
const [isFlex, setIsFlex] = useState(isSmall.current);
setDocumentTitle(t("JavascriptSdk"));
const navigate = useNavigate();
const navigateToPortal = () => navigate("docspace");
@ -191,6 +189,10 @@ const PortalIntegration = (props) => {
},
];
useEffect(() => {
if (tReady) setDocumentTitle(t("JavascriptSdk"));
}, [tReady]);
const onResize = (entries) => {
const belowThreshold = entries[0].contentRect.width <= 600;
if (belowThreshold !== isSmall.current) {

View File

@ -47,11 +47,15 @@ const PluginSDK = ({
isEmptyList,
theme,
}) => {
const { t } = useTranslation(["WebPlugins", "VersionHistory", "Common"]);
const { t, ready } = useTranslation([
"WebPlugins",
"VersionHistory",
"Common",
]);
React.useEffect(() => {
setDocumentTitle(t("WebPlugins:PluginSDK"));
}, []);
if (ready) setDocumentTitle(t("WebPlugins:PluginSDK"));
}, [ready]);
const isMobile = currentDeviceType === "mobile";

View File

@ -57,8 +57,6 @@ const SMTPSettings = (props) => {
setIsInit(true);
};
useEffect(() => {
setDocumentTitle(t("Settings:SMTPSettings"));
timerId = setTimeout(() => {
setIsLoading(true);
}, 400);
@ -71,6 +69,10 @@ const SMTPSettings = (props) => {
};
}, []);
useEffect(() => {
if (ready) setDocumentTitle(t("Settings:SMTPSettings"));
}, [ready]);
const isLoadingContent = isLoading || !ready;
if (!isLoading && !isInit) return <></>;

View File

@ -55,14 +55,17 @@ const SingleSignOn = (props) => {
isInit,
currentDeviceType,
} = props;
const { t } = useTranslation(["SingleSignOn", "Settings"]);
const { t, ready } = useTranslation(["SingleSignOn", "Settings"]);
const isMobileView = currentDeviceType === DeviceType.mobile;
useEffect(() => {
isSSOAvailable && !isInit && init();
setDocumentTitle(t("Settings:SingleSignOn"));
}, []);
useEffect(() => {
if (ready) setDocumentTitle(t("Settings:SingleSignOn"));
}, [ready]);
if (!isInit && !isMobileView && isSSOAvailable) return <SSOLoader />;
return (

View File

@ -111,9 +111,9 @@ const RootContainer = styled(Box)`
class ThirdPartyServices extends React.Component {
constructor(props) {
super(props);
const { t } = props;
const { t, tReady } = props;
setDocumentTitle(`${t("ThirdPartyAuthorization")}`);
if (tReady) setDocumentTitle(`${t("ThirdPartyAuthorization")}`);
this.state = {
dialogVisible: false,
@ -135,6 +135,12 @@ class ThirdPartyServices extends React.Component {
}
}
componentDidUpdate(prevProps) {
const { t, tReady } = this.props;
if (prevProps.tReady !== tReady && tReady)
setDocumentTitle(t("ThirdPartyAuthorization"));
}
onChangeLoading = (status) => {
this.setState({
isLoading: status,

View File

@ -30,7 +30,9 @@ import ImageReactSvgUrl from "PUBLIC_DIR/images/image.react.svg?url";
import CatalogTrashReactSvgUrl from "PUBLIC_DIR/images/catalog.trash.react.svg?url";
import ArrowPathReactSvgUrl from "PUBLIC_DIR/images/arrow.path.react.svg?url";
import VerticalDotsReactSvgUrl from "PUBLIC_DIR/images/vertical-dots.react.svg?url";
import { useState } from "react";
import { useHotkeys } from "react-hotkeys-hook";
import { withTranslation } from "react-i18next";
import { useNavigate, useLocation } from "react-router-dom";
import { inject, observer } from "mobx-react";
@ -39,6 +41,7 @@ import { IconButton } from "@docspace/shared/components/icon-button";
import { ContextMenuButton } from "@docspace/shared/components/context-menu-button";
import Headline from "@docspace/shared/components/headline/Headline";
import { SectionHeaderSkeleton } from "@docspace/shared/skeletons/sections";
import { checkDialogsOpen } from "@docspace/shared/utils/checkDialogsOpen";
import { DeleteSelfProfileDialog } from "SRC_DIR/components/dialogs";
import { DeleteOwnerProfileDialog } from "SRC_DIR/components/dialogs";
@ -72,6 +75,7 @@ const Header = (props) => {
showProfileLoader,
setIsLoading,
userId,
enabledHotkeys,
} = props;
const navigate = useNavigate();
@ -152,6 +156,11 @@ const Header = (props) => {
// setFilter(filter);
};
useHotkeys("Backspace", onClickBack, {
filter: () => !checkDialogsOpen() && enabledHotkeys,
filterPreventDefault: false,
});
if (showProfileLoader) return <SectionHeaderSkeleton />;
return (
@ -219,6 +228,8 @@ export default inject(
peopleStore,
clientLoadingStore,
profileActionsStore,
filesStore,
mediaViewerDataStore,
}) => {
const { isAdmin } = authStore;
@ -234,6 +245,9 @@ export default inject(
const { profileClicked } = profileActionsStore;
const { enabledHotkeys } = filesStore;
const { visible: mediaViewerIsVisible } = mediaViewerDataStore;
const { setChangePasswordVisible, setChangeAvatarVisible } =
targetUserStore;
@ -258,6 +272,8 @@ export default inject(
showProfileLoader,
profileClicked,
enabledHotkeys:
enabledHotkeys && !mediaViewerIsVisible && !showProfileLoader,
};
},
)(

View File

@ -262,7 +262,10 @@ const Sdk = ({
: {};
const headerProps = frameConfig?.showSelectorHeader
? { withHeader: true, headerProps: { headerLabel: "" } }
? {
withHeader: true,
headerProps: { headerLabel: "", isCloseable: false },
}
: {};
component = (
@ -301,6 +304,7 @@ const Sdk = ({
currentFolderId={frameConfig?.id}
openRoot={selectorOpenRoot}
descriptionText={formatsDescription[frameConfig?.filterParam] || ""}
headerProps={{ isCloseable: false }}
/>
);
break;

View File

@ -692,7 +692,7 @@ class HotkeyStore {
const files = await getFilesFromEvent(event);
createFoldersTree(files, uploadToFolder).then((f) => {
createFoldersTree(files).then((f) => {
if (f.length > 0) startUpload(f, null, t);
});
};

View File

@ -25,13 +25,19 @@
// International. See the License terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
import { permanentRedirect, redirect } from "next/navigation";
import dynamic from "next/dynamic";
import { getBaseUrl } from "@docspace/shared/utils/next-ssr-helper";
import { EditorConfigErrorType } from "@docspace/shared/enums";
import { createFile, fileCopyAs, getEditorUrl } from "@/utils/actions";
import CreateFileError from "@/components/CreateFileError";
import Editor from "@/components/Editor";
import { EditorConfigErrorType } from "@docspace/shared/enums";
const Editor = dynamic(() => import("@/components/Editor"), {
ssr: false,
});
const CreateFileError = dynamic(() => import("@/components/CreateFileError"), {
ssr: false,
});
type TSearchParams = {
parentId: string;

View File

@ -55,18 +55,14 @@ export default async function RootLayout({
return <></>;
}
const startDate = new Date();
const [user, settings, colorTheme] = await Promise.all([
getUser(),
getSettings(),
getColorTheme(),
]);
const timer = new Date().getTime() - startDate.getTime();
if (settings === "access-restricted") redirect(`${getBaseUrl()}/${settings}`);
const api_host = process.env.API_HOST?.trim();
return (
<html lang="en" translate="no">
<head>
@ -82,11 +78,7 @@ export default async function RootLayout({
</head>
<body>
<StyledComponentsRegistry>
<Providers
contextData={{ user, settings, systemTheme, colorTheme }}
api_host={api_host}
timer={timer}
>
<Providers contextData={{ user, settings, systemTheme, colorTheme }}>
{children}
</Providers>
</StyledComponentsRegistry>

View File

@ -26,6 +26,7 @@
import { headers } from "next/headers";
import Script from "next/script";
import dynamic from "next/dynamic";
import { getSelectorsByUserAgent } from "react-device-detect";
@ -34,7 +35,10 @@ import { ValidationStatus } from "@docspace/shared/enums";
import { getData, validatePublicRoomKey } from "@/utils/actions";
import { RootPageProps } from "@/types";
import Root from "@/components/Root";
import FilePassword from "@/components/file-password";
const FilePassword = dynamic(() => import("@/components/file-password"), {
ssr: false,
});
const initialSearchParams: RootPageProps["searchParams"] = {
fileId: undefined,

View File

@ -27,7 +27,7 @@
"use client";
import React from "react";
import { useRouter, useSearchParams } from "next/navigation";
import { useSearchParams } from "next/navigation";
import { useTranslation } from "react-i18next";
import { DocumentEditor } from "@onlyoffice/document-editor-react";
@ -51,7 +51,6 @@ import {
} from "@/utils/events";
import useInit from "@/hooks/useInit";
import useEditorEvents from "@/hooks/useEditorEvents";
import useFilesSettings from "@/hooks/useFilesSettings";
type IConfigType = IConfig & {
events?: {
@ -77,6 +76,8 @@ const Editor = ({
errorMessage,
isSkipError,
filesSettings,
onDownloadAs,
onSDKRequestSharingSettings,
onSDKRequestSaveAs,
@ -88,9 +89,7 @@ const Editor = ({
}: EditorProps) => {
const { t, i18n } = useTranslation(["Common", "Editor", "DeepLink"]);
const router = useRouter();
const searchParams = useSearchParams();
const { filesSettings } = useFilesSettings({});
const openOnNewPage = IS_ZOOM ? false : !filesSettings?.openEditorInSameTab;

View File

@ -9,7 +9,6 @@ import type { TFirebaseSettings } from "@docspace/shared/api/settings/types";
import useI18N from "@/hooks/useI18N";
import useTheme from "@/hooks/useTheme";
import useDeviceType from "@/hooks/useDeviceType";
import useWhiteLabel from "@/hooks/useWhiteLabel";
import pkg from "../../../package.json";
@ -18,7 +17,7 @@ import { ErrorProps } from "./Error.types";
const Error = ({ settings, user, error }: ErrorProps) => {
const { i18n } = useI18N({ settings, user });
const { currentDeviceType } = useDeviceType();
const { logoUrls } = useWhiteLabel();
const { theme } = useTheme({ user });
const firebaseHelper = useMemo(() => {
@ -32,7 +31,6 @@ const Error = ({ settings, user, error }: ErrorProps) => {
errorLog={error}
version={pkg.version}
user={user ?? ({} as TUser)}
whiteLabelLogoUrls={logoUrls}
firebaseHelper={firebaseHelper}
currentDeviceType={currentDeviceType}
/>

View File

@ -25,15 +25,21 @@
// International. See the License terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
"use client";
import dynamic from "next/dynamic";
import React, { useEffect } from "react";
import React from "react";
import { useTranslation } from "react-i18next";
import ErrorContainer from "@docspace/shared/components/error-container/ErrorContainer";
const ErrorContainer = dynamic(
() => import("@docspace/shared/components/error-container/ErrorContainer"),
{
ssr: false,
},
);
import { TResponse } from "@/types";
import useError from "@/hooks/useError";
import useError from "@/hooks/useError";
import useRootInit from "@/hooks/useRootInit";
import useDeepLink from "@/hooks/useDeepLink";
import useSelectFileDialog from "@/hooks/useSelectFileDialog";
@ -44,14 +50,31 @@ import useFilesSettings from "@/hooks/useFilesSettings";
import useUpdateSearchParamId from "@/hooks/useUpdateSearchParamId";
import useStartFillingSelectDialog from "@/hooks/useStartFillingSelectDialog";
import DeepLink from "./deep-link";
import Editor from "./Editor";
import SelectFileDialog from "./SelectFileDialog";
import SelectFolderDialog from "./SelectFolderDialog";
import SharingDialog from "./ShareDialog";
const DeepLink = dynamic(() => import("./deep-link"), {
ssr: false,
});
const SelectFileDialog = dynamic(() => import("./SelectFileDialog"), {
ssr: false,
});
const SelectFolderDialog = dynamic(() => import("./SelectFolderDialog"), {
ssr: false,
});
const SharingDialog = dynamic(() => import("./ShareDialog"), {
ssr: false,
});
const StartFillingSelectorDialog = dynamic(
() => import("./StartFillingSelectDialog"),
{
ssr: false,
},
);
const ConflictResolveDialog = dynamic(() => import("./ConflictResolveDialog"), {
ssr: false,
});
import { calculateAsideHeight } from "@/utils";
import StartFillingSelectorDialog from "./StartFillingSelectDialog";
import ConflictResolveDialog from "./ConflictResolveDialog";
const Root = ({
settings,
@ -64,7 +87,6 @@ const Root = ({
doc,
fileId,
hash,
timer,
}: TResponse) => {
const editorRef = React.useRef<null | HTMLElement>(null);
@ -81,11 +103,6 @@ const Root = ({
const { t } = useTranslation(["Editor", "Common"]);
useEffect(() => {
console.log("editor timer: ", timer);
console.log("openEdit timer: ", config?.timer);
}, [config?.timer, timer]);
useRootInit({
documentType: config?.documentType,
});
@ -214,6 +231,7 @@ const Root = ({
errorMessage={error?.message}
isSkipError={!!isSkipError}
onDownloadAs={onDownloadAs}
filesSettings={filesSettings}
onSDKRequestSharingSettings={onSDKRequestSharingSettings}
onSDKRequestSaveAs={onSDKRequestSaveAs}
onSDKRequestInsertImage={onSDKRequestInsertImage}

View File

@ -37,7 +37,7 @@ const Scripts = () => {
<>
<Script
id="browser-detector"
strategy="beforeInteractive"
// strategy="beforeInteractive"
src={`/static/scripts/browserDetector.js?hash=${runtime?.checksums?.["browserDetector.js"] ?? hashDate}`}
/>

View File

@ -178,7 +178,7 @@ const FilePassword = ({ shareKey, title, entryTitle }: FilePasswordProps) => {
id="password"
inputName="password"
placeholder={t("Common:Password")}
type={InputType.password}
inputType={InputType.password}
inputValue={password}
hasError={!!errorMessage}
size={InputSize.large}

View File

@ -30,28 +30,21 @@ import { getSettingsFiles } from "@docspace/shared/api/files";
import { TFilesSettings } from "@docspace/shared/api/files/types";
const useFilesSettings = ({}) => {
const [settings, setSettings] = React.useState({} as TFilesSettings);
const requestRunning = React.useRef(false);
const initSettings = React.useCallback(async () => {
if (requestRunning.current) return;
requestRunning.current = true;
const res = await getSettingsFiles();
setSettings(res);
requestRunning.current = false;
}, []);
const [settings, setSettings] = React.useState<TFilesSettings>(
{} as TFilesSettings,
);
React.useEffect(() => {
if (settings.extsArchive) return;
const initSettings = async () => {
const res = await getSettingsFiles();
setSettings(res);
};
initSettings();
}, [initSettings, settings.extsArchive]);
}, []);
return { filesSettings: settings };
};
export default useFilesSettings;

View File

@ -95,7 +95,7 @@ const useSocketHelper = ({ socketUrl, user }: UseSocketHelperProps) => {
});
setSocketHelper(socketIOHelper);
}, [socketHelper, socketUrl]);
}, [socketHelper, socketUrl, user?.id, user?.loginEventId]);
return { socketHelper };
};

View File

@ -90,17 +90,17 @@ const useTheme = ({
const isRequestRunning = React.useRef(false);
const getCurrentColorTheme = React.useCallback(async () => {
if (isRequestRunning.current) return;
if (isRequestRunning.current || colorTheme) return;
isRequestRunning.current = true;
const colorThemes = await getAppearanceTheme();
const colorTheme = colorThemes.themes.find(
const curColorTheme = colorThemes.themes.find(
(t) => t.id === colorThemes.selected,
);
isRequestRunning.current = false;
if (colorTheme) setCurrentColorTheme(colorTheme);
}, []);
if (curColorTheme) setCurrentColorTheme(curColorTheme);
}, [colorTheme]);
const getUserTheme = React.useCallback(() => {
const SYSTEM_THEME = getSystemTheme();

View File

@ -44,16 +44,9 @@ const TranslationProvider = ({
children,
settings,
user,
api_host,
timer,
}: TTranslationProvider) => {
const { i18n } = useI18N({ settings, user });
React.useEffect(() => {
console.log("API_HOST: ", api_host);
console.log("LAYOUT API timer:", timer);
}, [api_host, timer]);
return <I18nextProvider i18n={i18n}>{children}</I18nextProvider>;
};

View File

@ -48,9 +48,9 @@ export type TProviders = {
contextData: TContextData;
};
const Providers = ({ children, contextData, api_host, timer }: TProviders) => {
const Providers = ({ children, contextData }: TProviders) => {
return (
<TranslationProvider {...contextData} api_host={api_host} timer={timer}>
<TranslationProvider {...contextData}>
<ThemeProvider {...contextData}>
<ErrorProvider {...contextData}>
{children}

View File

@ -229,6 +229,7 @@ export type EditorProps = {
isSharingAccess?: boolean;
errorMessage?: string;
isSkipError?: boolean;
filesSettings: TFilesSettings;
onDownloadAs?: (obj: object) => void;
onSDKRequestSharingSettings?: () => void;

View File

@ -65,8 +65,6 @@ export async function getFillingSession(
);
try {
console.log({ request });
const response = await fetch(request);
if (response.ok) return await response.json();

View File

@ -37,6 +37,7 @@ import { Providers } from "@/providers";
import { getColorTheme, getSettings } from "@/utils/actions";
import "../styles/globals.scss";
import Scripts from "@/components/Scripts";
export default async function RootLayout({
children,
@ -136,6 +137,7 @@ export default async function RootLayout({
{children}
</Providers>
</StyledComponentsRegistry>
<Scripts />
</body>
</html>
);

View File

@ -118,11 +118,7 @@ const ForgotPasswordModalDialog = ({
onClose={onDialogClose}
id="forgot-password-modal"
>
<ModalDialog.Header>
<Text isBold fontSize="21px">
{t("PasswordRecoveryTitle")}
</Text>
</ModalDialog.Header>
<ModalDialog.Header>{t("PasswordRecoveryTitle")}</ModalDialog.Header>
<ModalDialog.Body>
<Text
key="text-body"

View File

@ -97,11 +97,7 @@ const RegisterModalDialog = ({
onClose={onRegisterModalClose}
isLarge
>
<ModalDialog.Header>
<Text isBold fontSize="21px">
{t("RegisterTitle")}
</Text>
</ModalDialog.Header>
<ModalDialog.Header>{t("RegisterTitle")}</ModalDialog.Header>
<ModalDialog.Body>
<Text key="text-body" isBold={false} fontSize="13px" noSelect>
{getDomainsBlock()}

View File

@ -27,8 +27,6 @@
import React from "react";
import styled, { css } from "styled-components";
import CrossReactSvg from "PUBLIC_DIR/images/cross.react.svg";
import { Base } from "../../themes";
import { MOBILE_FOOTER_HEIGHT } from "../../constants";
import { tablet, mobile } from "../../utils";
@ -114,66 +112,57 @@ const StyledAside = styled(Container)`
`;
StyledAside.defaultProps = { theme: Base };
const StyledControlContainer = styled.div`
const StyledHeaderContainer = styled.div<{ withoutBorder?: boolean }>`
display: flex;
width: 17px;
height: 17px;
position: absolute;
cursor: pointer;
align-items: center;
justify-content: center;
z-index: 450;
justify-content: space-between;
margin: 0 16px;
height: 53px;
min-height: 53px;
position: relative;
top: 18px;
.additional-icons-container {
display: flex;
margin-inline: 16px 16px;
gap: 16px;
}
.heading {
font-family: ${(props) => props.theme.fontFamily};
color: ${(props) => props.theme.modalDialog.textColor};
font-weight: 700;
font-size: 21px;
}
.arrow-button {
margin-inline: 0 12px;
svg {
${({ theme }) =>
theme.interfaceDirection === "rtl" && `transform: scaleX(-1);`}
}
}
.close-button {
margin-inline: auto 0;
min-width: 17px;
}
.header-component {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
${(props) =>
props.theme.interfaceDirection === "rtl" ? `right: -27px;` : `left: -27px;`}
@media ${tablet} {
display: flex;
top: 18px;
${(props) =>
props.theme.interfaceDirection === "rtl"
? `right: -27px;`
: `left: -27px;`}
}
@media ${mobile} {
display: flex;
top: -27px;
right: 10px;
left: unset;
${(props) =>
props.theme.interfaceDirection === "rtl"
? css`
right: unset;
left: 10px;
`
: css`
right: 10px;
left: unset;
`}
}
!props.withoutBorder &&
css`
::after {
content: "";
border-bottom: ${(props) =>
`1px solid ${props.theme.modalDialog.headerBorderColor}`};
width: calc(100% + 32px);
position: absolute;
inset-inline-end: -16px;
bottom: 0;
}
`}
`;
StyledControlContainer.defaultProps = { theme: Base };
const StyledCrossIcon = styled(CrossReactSvg)`
width: 17px;
height: 17px;
z-index: 455;
path {
fill: ${(props) => props.theme.catalog.control.fill};
}
`;
StyledCrossIcon.defaultProps = { theme: Base };
export { StyledAside, StyledControlContainer, StyledCrossIcon };
export { StyledAside, StyledHeaderContainer };

View File

@ -27,13 +27,9 @@
import React from "react";
import { Scrollbar } from "../scrollbar";
import {
StyledAside,
StyledControlContainer,
StyledCrossIcon,
} from "./Aside.styled";
import { StyledAside } from "./Aside.styled";
import { AsideProps } from "./Aside.types";
import { AsideHeader } from "./AsideHeader";
const AsidePure = (props: AsideProps) => {
const {
@ -45,6 +41,8 @@ const AsidePure = (props: AsideProps) => {
contentPaddingBottom,
withoutBodyScroll = false,
onClose,
withoutHeader = false,
...rest
} = props;
const contentRef = React.useRef<HTMLElement | null>(null);
@ -58,14 +56,8 @@ const AsidePure = (props: AsideProps) => {
forwardRef={contentRef}
data-testid="aside"
>
{/* <CloseButton displayType="aside" zIndex={zIndex}/> */}
{!withoutHeader && <AsideHeader onCloseClick={onClose} {...rest} />}
{withoutBodyScroll ? children : <Scrollbar>{children}</Scrollbar>}
{visible && (
<StyledControlContainer className="close-button" onClick={onClose}>
<StyledCrossIcon />
</StyledControlContainer>
)}
</StyledAside>
);
};

View File

@ -24,7 +24,7 @@
// content are licensed under the terms of the Creative Commons Attribution-ShareAlike 4.0
// International. See the License terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
export interface AsideProps {
export type AsideProps = AsideHeaderProps & {
visible: boolean;
scale?: boolean;
className?: string;
@ -33,8 +33,22 @@ export interface AsideProps {
children: React.ReactNode;
withoutBodyScroll?: boolean;
onClose: () => void;
}
withoutHeader: boolean;
};
export interface AsideHeaderProps {
header: string | React.ReactNode;
className?: string;
id?: string;
isBackButton?: boolean;
isCloseable?: boolean;
headerIcons?: { key: string; url: string; onClick: () => void }[];
onBackClick?: () => void;
onCloseClick?: () => void;
style?: React.CSSProperties;
isLoading?: boolean;
withoutBorder?: boolean;
}
export interface StyledAsideProps {
visible: boolean;
scale?: boolean;

View File

@ -0,0 +1,117 @@
// (c) Copyright Ascensio System SIA 2009-2024
//
// This program is a free software product.
// You can redistribute it and/or modify it under the terms
// of the GNU Affero General Public License (AGPL) version 3 as published by the Free Software
// Foundation. In accordance with Section 7(a) of the GNU AGPL its Section 15 shall be amended
// to the effect that Ascensio System SIA expressly excludes the warranty of non-infringement of
// any third-party rights.
//
// This program is distributed WITHOUT ANY WARRANTY, without even the implied warranty
// of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. For details, see
// the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html
//
// You can contact Ascensio System SIA at Lubanas st. 125a-25, Riga, Latvia, EU, LV-1021.
//
// The interactive user interfaces in modified source and object code versions of the Program must
// display Appropriate Legal Notices, as required under Section 5 of the GNU AGPL version 3.
//
// Pursuant to Section 7(b) of the License you must retain the original Product logo when
// distributing the program. Pursuant to Section 7(e) we decline to grant you any rights under
// trademark law for use of our trademarks.
//
// All the Product's GUI elements, including illustrations and icon sets, as well as technical writing
// content are licensed under the terms of the Creative Commons Attribution-ShareAlike 4.0
// International. See the License terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
import ArrowPathReactSvgUrl from "PUBLIC_DIR/images/arrow.path.react.svg?url";
import CrossReactSvgUrl from "PUBLIC_DIR/images/icons/17/cross.react.svg?url";
import { IconButton } from "../icon-button";
import { Text } from "../text";
import { AsideHeaderProps } from "./Aside.types";
import { StyledHeaderContainer } from "./Aside.styled";
import { RectangleSkeleton } from "../../skeletons/rectangle";
import { Heading, HeadingSize } from "../heading";
const AsideHeader = (props: AsideHeaderProps) => {
const {
isBackButton = false,
onBackClick,
onCloseClick,
header,
headerIcons = [],
isCloseable = true,
className,
id,
style,
isLoading,
withoutBorder = false,
} = props;
const backButtonRender = (
<IconButton
className="arrow-button"
iconName={ArrowPathReactSvgUrl}
size={17}
onClick={onBackClick}
/>
);
const closeIconRender = (
<IconButton
size={17}
className="close-button"
iconName={CrossReactSvgUrl}
onClick={onCloseClick}
isClickable
/>
);
// TODO: Heading is temporary until all dialogues are checked
const mainComponent = (
<>
{isBackButton && backButtonRender}
{typeof header === "string" ? (
<Text fontSize="21px" fontWeight={700} className="header-component">
{header}
</Text>
) : (
<Heading className="heading" size={HeadingSize.medium} truncate>
{header}
</Heading>
)}
{headerIcons.length > 0 && (
<div className="additional-icons-container">
{headerIcons.map((item) => (
<IconButton
key={item.key}
size={17}
className="close-button"
iconName={item.url}
onClick={item.onClick}
isClickable
/>
))}
</div>
)}
{isCloseable && closeIconRender}
</>
);
const loaderComponent = <RectangleSkeleton height="28" width="100%" />;
return (
<StyledHeaderContainer
id={id}
className={className}
style={style}
withoutBorder={withoutBorder}
>
{isLoading ? loaderComponent : mainComponent}
</StyledHeaderContainer>
);
};
export { AsideHeader };

View File

@ -25,3 +25,4 @@
// International. See the License terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
export { Aside } from "./Aside";
export { AsideHeader } from "./AsideHeader";

View File

@ -73,13 +73,13 @@ const StyledContent = styled.div`
`;
StyledContent.defaultProps = { theme: Base };
const StyledHeaderContent = styled.div`
display: flex;
align-items: center;
border-bottom: ${(props) =>
props.theme.contextMenuButton.headerContent.borderBottom};
`;
StyledHeaderContent.defaultProps = { theme: Base };
// const StyledHeaderContent = styled.div`
// display: flex;
// align-items: center;
// border-bottom: ${(props) =>
// props.theme.contextMenuButton.headerContent.borderBottom};
// `;
// StyledHeaderContent.defaultProps = { theme: Base };
const StyledBodyContent = styled.div`
position: relative;
@ -101,4 +101,4 @@ const StyledBodyContent = styled.div`
`;
StyledBodyContent.defaultProps = { theme: Base };
export { StyledBodyContent, StyledHeaderContent, StyledContent, StyledOuter };
export { StyledBodyContent, StyledContent, StyledOuter };

View File

@ -38,13 +38,11 @@ import { DropDown } from "../drop-down";
import { IconButton } from "../icon-button";
import { Backdrop } from "../backdrop";
import { Aside } from "../aside";
import { Heading, HeadingLevel, HeadingSize } from "../heading";
import { Link } from "../link";
import { ContextMenuModel } from "../context-menu";
import {
StyledBodyContent,
StyledHeaderContent,
StyledContent,
StyledOuter,
} from "./ContextMenuButton.styled";
@ -297,9 +295,10 @@ const ContextMenuButtonPure = ({
scale={false}
zIndex={310}
onClose={onCloseAction}
header={asideHeader}
>
<StyledContent>
<StyledHeaderContent>
{/* <StyledHeaderContent>
<Heading
className="header"
size={HeadingSize.medium}
@ -308,7 +307,7 @@ const ContextMenuButtonPure = ({
>
{asideHeader}
</Heading>
</StyledHeaderContent>
</StyledHeaderContent> */}
<StyledBodyContent>
{state.data.map(
(item: ContextMenuModel, index: number) =>

View File

@ -54,6 +54,7 @@ const StyledDropdown = styled.div<{
`}
height: fit-content;
position: absolute;
overflow: hidden;
${(props) => props.manualWidth && `width: ${props.manualWidth};`}
${(props) =>

View File

@ -26,8 +26,6 @@
import styled, { css } from "styled-components";
import CrossIcon from "PUBLIC_DIR/images/cross.react.svg";
import { tablet, mobile } from "../../utils";
import { Base } from "../../themes";
import { TViewAs } from "../../types";
@ -218,44 +216,6 @@ const StyledFilterBlock = styled.div`
StyledFilterBlock.defaultProps = { theme: Base };
const StyledFilterBlockHeader = styled.div<{ isSelector?: boolean }>`
height: 53px;
min-height: 53px;
padding: 0 16px;
margin: 0;
box-sizing: border-box;
border-bottom: ${(props) =>
props.isSelector ? "none" : props.theme.filterInput.filter.border};
display: flex;
align-items: center;
justify-content: ${(props) => (props.isSelector ? "start" : "space-between")};
h1 {
font-weight: 700;
}
.arrow-button {
${(props) =>
props.theme.interfaceDirection === "rtl"
? css`
margin-left: 12px;
`
: css`
margin-right: 12px;
`}
}
svg {
cursor: pointer;
}
`;
StyledFilterBlockHeader.defaultProps = { theme: Base };
const StyledFilterBlockItem = styled.div<{
withoutHeader: boolean;
isFirst?: boolean;
@ -490,59 +450,6 @@ const StyledFilterBlockFooter = styled.div`
StyledFilterBlockFooter.defaultProps = { theme: Base };
const StyledControlContainer = styled.div`
display: flex;
width: 24px;
height: 24px;
position: absolute;
border-radius: 100px;
cursor: pointer;
align-items: center;
justify-content: center;
z-index: 450;
top: 14px;
${(props) =>
props.theme.interfaceDirection === "rtl"
? css`
right: -34px;
`
: css`
left: -34px;
`}
@media ${mobile} {
top: -34px;
${(props) =>
props.theme.interfaceDirection === "rtl"
? css`
left: 10px;
right: unset;
`
: css`
right: 10px;
left: unset;
`}
}
`;
StyledControlContainer.defaultProps = { theme: Base };
const StyledCrossIcon = styled(CrossIcon)`
width: 17px;
height: 17px;
z-index: 455;
path {
fill: ${(props) => props.theme.catalog.control.fill};
}
`;
StyledCrossIcon.defaultProps = { theme: Base };
const selectedViewIcon = css`
svg {
path {
@ -712,7 +619,6 @@ StyledSortButton.defaultProps = { theme: Base };
export {
StyledSortButton,
StyledFilterBlock,
StyledFilterBlockHeader,
StyledFilterBlockItem,
StyledFilterBlockItemHeader,
StyledFilterBlockItemContent,
@ -726,8 +632,6 @@ export {
StyledFilterBlockItemCheckboxContainer,
StyledFilterBlockItemSeparator,
StyledFilterBlockFooter,
StyledControlContainer,
StyledCrossIcon,
};
export { StyledFilterInput, StyledSearchInput, StyledButton };

View File

@ -37,19 +37,11 @@ import { FilterBlockLoader } from "../../../skeletons/filter";
import { Backdrop } from "../../backdrop";
import { Button, ButtonSize } from "../../button";
import { Heading, HeadingLevel, HeadingSize } from "../../heading";
import { IconButton } from "../../icon-button";
import { Scrollbar } from "../../scrollbar";
import { Portal } from "../../portal";
import { TSelectorItem } from "../../selector";
import {
StyledControlContainer,
StyledCrossIcon,
StyledFilterBlock,
StyledFilterBlockFooter,
StyledFilterBlockHeader,
} from "../Filter.styled";
import { StyledFilterBlock, StyledFilterBlockFooter } from "../Filter.styled";
import { FilterBlockProps, TGroupItem, TItem } from "../Filter.types";
import {
@ -58,6 +50,7 @@ import {
} from "../Filter.utils";
import FilterBlockItem from "./FilterBlockItem";
import { AsideHeader } from "../../aside";
const FilterBlock = ({
selectedFilterValue,
@ -496,10 +489,12 @@ const FilterBlock = ({
withHeader
headerProps={{
onBackClick: onArrowClick,
onCloseClick: hideFilterBlock,
headerLabel: selectorLabel,
withoutBackButton: false,
}}
currentUserId={userId}
onClose={hideFilterBlock}
/>
) : showSelector.type === FilterSelectorTypes.groups ? (
<GroupsSelector
@ -508,9 +503,11 @@ const FilterBlock = ({
withHeader
headerProps={{
onBackClick: onArrowClick,
onCloseClick: hideFilterBlock,
headerLabel: selectorLabel,
withoutBackButton: false,
}}
onClose={hideFilterBlock}
/>
) : (
<RoomSelector
@ -519,34 +516,33 @@ const FilterBlock = ({
withHeader
headerProps={{
onBackClick: onArrowClick,
onCloseClick: hideFilterBlock,
headerLabel: selectorLabel,
withoutBackButton: false,
}}
isMultiSelect={false}
withSearch
disableThirdParty={disableThirdParty}
onClose={hideFilterBlock}
/>
)}
<StyledControlContainer onClick={hideFilterBlock}>
<StyledCrossIcon />
</StyledControlContainer>
</StyledFilterBlock>
) : (
<StyledFilterBlock>
<StyledFilterBlockHeader>
<Heading size={HeadingSize.medium} level={HeadingLevel.h1}>
{filterHeader}
</Heading>
{showClearFilterBtn && (
<IconButton
id="filter_search-options-clear"
iconName={ClearReactSvgUrl}
isFill
onClick={onClearFilter}
size={17}
/>
)}
</StyledFilterBlockHeader>
<AsideHeader
header={filterHeader}
onCloseClick={hideFilterBlock}
{...(showClearFilterBtn && {
headerIcons: [
{
key: "filter-icon",
url: ClearReactSvgUrl,
onClick: onClearFilter,
},
],
})}
/>
<div className="filter-body">
{isLoading ? (
<FilterBlockLoader
@ -598,10 +594,6 @@ const FilterBlock = ({
isDisabled={isLoading}
/>
</StyledFilterBlockFooter>
<StyledControlContainer id="filter_close" onClick={hideFilterBlock}>
<StyledCrossIcon />
</StyledControlContainer>
</StyledFilterBlock>
)}

View File

@ -147,24 +147,6 @@ const Content = styled.div.attrs((props: { modalSwipeOffset?: number }) => ({
`}
`;
const StyledHeader = styled.div<{ currentDisplayType?: ModalDialogType }>`
display: flex;
align-items: center;
border-bottom: ${(props) =>
`1px solid ${props.theme.modalDialog.headerBorderColor}`};
height: 52px;
margin-bottom: ${(props) =>
props.currentDisplayType === "aside" ? "0px" : "16px"};
padding: 0 16px 0;
.heading {
font-family: ${(props) => props.theme.fontFamily};
color: ${(props) => props.theme.modalDialog.textColor};
font-weight: 700;
font-size: 21px;
}
`;
const StyledBody = styled(Box)<{
currentDisplayType?: ModalDialogType;
hasFooter?: boolean;
@ -241,7 +223,6 @@ const StyledFooter = styled.div<{
`;
Dialog.defaultProps = { theme: Base };
StyledHeader.defaultProps = { theme: Base };
Content.defaultProps = { theme: Base };
export { StyledModal, StyledHeader, Content, Dialog, StyledBody, StyledFooter };
export { StyledModal, Content, Dialog, StyledBody, StyledFooter };

View File

@ -87,6 +87,8 @@ const ModalDialog = ({
withBodyScroll = false,
withFooterBorder = false,
containerVisible = false,
...rest
}: ModalDialogProps) => {
const onCloseEvent = React.useCallback(() => {
if (embedded) return;
@ -173,6 +175,7 @@ const ModalDialog = ({
isCloseable={isCloseable && !embedded}
embedded={embedded}
blur={blur}
{...rest}
/>
}
/>

View File

@ -24,6 +24,7 @@
// content are licensed under the terms of the Creative Commons Attribution-ShareAlike 4.0
// International. See the License terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
import { AsideHeaderProps } from "../aside/Aside.types";
import { ModalDialogType } from "./ModalDialog.enums";
export type ModalDialogTypeDetailed = {
@ -134,7 +135,7 @@ export interface ModalDialogBackdropProps {
modalSwipeOffset?: number;
}
export interface ModalSubComponentsProps {
export type ModalSubComponentsProps = AsideHeaderProps & {
id?: string;
style?: React.CSSProperties;
className?: string;
@ -160,4 +161,4 @@ export interface ModalSubComponentsProps {
embedded?: boolean;
withForm?: boolean;
blur?: number;
}
};

View File

@ -1,117 +0,0 @@
// (c) Copyright Ascensio System SIA 2009-2024
//
// This program is a free software product.
// You can redistribute it and/or modify it under the terms
// of the GNU Affero General Public License (AGPL) version 3 as published by the Free Software
// Foundation. In accordance with Section 7(a) of the GNU AGPL its Section 15 shall be amended
// to the effect that Ascensio System SIA expressly excludes the warranty of non-infringement of
// any third-party rights.
//
// This program is distributed WITHOUT ANY WARRANTY, without even the implied warranty
// of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. For details, see
// the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html
//
// You can contact Ascensio System SIA at Lubanas st. 125a-25, Riga, Latvia, EU, LV-1021.
//
// The interactive user interfaces in modified source and object code versions of the Program must
// display Appropriate Legal Notices, as required under Section 5 of the GNU AGPL version 3.
//
// Pursuant to Section 7(b) of the License you must retain the original Product logo when
// distributing the program. Pursuant to Section 7(e) we decline to grant you any rights under
// trademark law for use of our trademarks.
//
// All the Product's GUI elements, including illustrations and icon sets, as well as technical writing
// content are licensed under the terms of the Creative Commons Attribution-ShareAlike 4.0
// International. See the License terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
import React from "react";
import styled, { css } from "styled-components";
import CrossIconReactSvgUrl from "PUBLIC_DIR/images/icons/17/cross.react.svg?url";
import { IconButton } from "../../icon-button";
import { mobile } from "../../../utils";
import { Base } from "../../../themes";
import { ModalDialogCloseButtonProps } from "../ModalDialog.types";
import { ModalDialogType } from "../ModalDialog.enums";
const StyledCloseButtonWrapper = styled.div<{
currentDisplayType: ModalDialogType;
}>`
width: 17px;
height: 17px;
display: flex;
align-items: center;
justify-content: center;
cursor: pointer;
position: absolute;
${(props) =>
props.currentDisplayType === "modal"
? css`
top: 18px;
${props.theme.interfaceDirection === "rtl"
? `left: -30px;`
: `right: -30px;`}
@media ${mobile} {
${props.theme.interfaceDirection === "rtl"
? `left: 10px;`
: `right: 10px;`}
top: -27px;
}
`
: css`
top: 18px;
${props.theme.interfaceDirection === "rtl"
? `right: -27px;`
: `left: -27px;`}
@media ${mobile} {
top: -27px;
${props.theme.interfaceDirection === "rtl"
? css`
right: auto;
left: 10px;
`
: css`
left: auto;
right: 10px;
`}
}
`}
.close-button, .close-button:hover {
cursor: pointer;
path {
stroke: ${(props) => props.theme.modalDialog.closeButton.fillColor};
}
}
`;
StyledCloseButtonWrapper.defaultProps = { theme: Base };
const CloseButton = ({
currentDisplayType,
onClick,
}: ModalDialogCloseButtonProps) => {
return (
<StyledCloseButtonWrapper
onClick={onClick}
currentDisplayType={currentDisplayType}
className="modal-close"
>
<IconButton
size={17}
className="close-button"
iconName={CrossIconReactSvgUrl}
/>
</StyledCloseButtonWrapper>
);
};
export { CloseButton };

View File

@ -30,18 +30,15 @@ import { isIOS, isMobileOnly, isSafari } from "react-device-detect";
import { classNames } from "../../../utils";
import { DialogSkeleton, DialogAsideSkeleton } from "../../../skeletons";
import { Heading, HeadingSize } from "../../heading";
import { Scrollbar } from "../../scrollbar";
import { AsideHeader } from "../../aside";
import {
StyledModal,
StyledHeader,
Content,
Dialog,
StyledBody,
StyledFooter,
} from "../ModalDialog.styled";
import { CloseButton } from "./CloseButton";
import { ModalBackdrop } from "./ModalBackdrop";
import { FormWrapper } from "./FormWrapper";
import { ModalSubComponentsProps } from "../ModalDialog.types";
@ -68,10 +65,12 @@ const Modal = ({
modalSwipeOffset,
containerVisible,
isDoubleFooterLine,
isCloseable,
embedded,
withForm,
blur,
...rest
}: ModalSubComponentsProps) => {
const contentRef = React.useRef<null | HTMLDivElement>(null);
@ -158,12 +157,6 @@ const Modal = ({
embedded={embedded}
ref={contentRef}
>
{isCloseable && (
<CloseButton
currentDisplayType={currentDisplayType}
onClick={onClose}
/>
)}
{isLoading ? (
currentDisplayType === "modal" ? (
<DialogSkeleton
@ -184,25 +177,21 @@ const Modal = ({
) : (
<FormWrapper withForm={withForm || false}>
{header && (
<StyledHeader
<AsideHeader
id="modal-header-swipe"
className={
classNames(["modal-header", headerProps.className]) ||
"modal-header"
}
{...headerProps}
currentDisplayType={currentDisplayType}
>
<Heading
level={1}
className="heading"
size={HeadingSize.medium}
truncate
>
{headerComponent}
</Heading>
</StyledHeader>
header={headerComponent}
onCloseClick={onClose}
{...(currentDisplayType === "modal" && {
style: { marginBottom: "16px" },
})}
{...rest}
/>
)}
{body && (
<StyledBody
className={

View File

@ -127,11 +127,7 @@ const RecoverAccessModalDialog: React.FC<IRecoverAccessModalDialogProps> = ({
onClose={onRecoverModalClose}
displayType={ModalDialogType.modal}
>
<ModalDialog.Header>
<Text isBold fontSize="21px">
{t("Common:RecoverTitle")}
</Text>
</ModalDialog.Header>
<ModalDialog.Header>{t("Common:RecoverTitle")}</ModalDialog.Header>
<ModalDialog.Body>
<Text
key="text-body"

View File

@ -25,7 +25,7 @@
// International. See the License terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
/* eslint-disable @typescript-eslint/no-unused-vars */
import React from "react";
import React, { useEffect, useMemo } from "react";
import { Provider } from "../../utils";
import { DeviceType } from "../../enums";
@ -153,6 +153,16 @@ const Section = (props: SectionProps) => {
isSectionBodyAvailable ||
isSectionPagingAvailable;
useEffect(() => {
if (!containerRef.current) return;
const computedStyles = window.getComputedStyle(containerRef.current, null);
const width = +computedStyles.getPropertyValue("width").replace("px", "");
const height = +computedStyles.getPropertyValue("height").replace("px", "");
setSectionSize(() => ({ width, height }));
}, [isInfoPanelVisible]);
const onResize = React.useCallback(() => {
if (timerRef.current) clearTimeout(timerRef.current);
@ -188,14 +198,17 @@ const Section = (props: SectionProps) => {
const showTwoProgress = showPrimaryProgressBar && showSecondaryProgressBar;
const providerValue = useMemo(
() => ({
sectionWidth: sectionSize.width,
sectionHeight: sectionSize.height,
}),
[sectionSize.width, sectionSize.height],
);
return (
isSectionAvailable && (
<Provider
value={{
sectionWidth: sectionSize.width,
sectionHeight: sectionSize.height,
}}
>
<Provider value={providerValue}>
<SectionContainer
viewAs={viewAs}
ref={containerRef}

View File

@ -29,12 +29,7 @@ import React, { useEffect, useRef } from "react";
import { DeviceType } from "../../../enums";
import { Portal } from "../../portal";
import {
StyledInfoPanelWrapper,
StyledInfoPanel,
StyledControlContainer,
StyledCrossIcon,
} from "../Section.styled";
import { StyledInfoPanelWrapper, StyledInfoPanel } from "../Section.styled";
import { InfoPanelProps } from "../Section.types";
const InfoPanel = ({
@ -49,8 +44,6 @@ const InfoPanel = ({
}: InfoPanelProps) => {
const infoPanelRef = useRef<null | HTMLDivElement>(null);
const closeInfoPanel = () => setIsVisible?.(false);
useEffect(() => {
const onMouseDown = (e: MouseEvent) => {
const target = e.target as HTMLElement;
@ -74,13 +67,7 @@ const InfoPanel = ({
id="InfoPanelWrapper"
ref={infoPanelRef}
>
<StyledInfoPanel>
<StyledControlContainer onClick={closeInfoPanel}>
<StyledCrossIcon />
</StyledControlContainer>
{children}
</StyledInfoPanel>
<StyledInfoPanel>{children}</StyledInfoPanel>
</StyledInfoPanelWrapper>
);

View File

@ -63,8 +63,11 @@ const StyledSelector = styled.div`
overflow: hidden;
`;
const StyledHeader = styled.div<{ withoutBorder?: boolean }>`
width: calc(100% - 32px);
const StyledHeader = styled.div<{
withoutBorder?: boolean;
withoutIcon: boolean;
}>`
width: calc(100% - 53px);
min-height: 53px;
height: 53px;
max-height: 53px;
@ -82,6 +85,7 @@ const StyledHeader = styled.div<{ withoutBorder?: boolean }>`
.arrow-button {
cursor: pointer;
margin-right: 12px;
min-width: 17px;
${(props) =>
props.theme.interfaceDirection === "rtl" &&
css`

View File

@ -73,6 +73,8 @@ export type BreadCrumbsProps = {
export type HeaderProps = {
headerLabel: string;
onCloseClick: () => void;
isCloseable?: boolean;
} & THeaderBackButton;
export type TSelectorHeader =

View File

@ -26,34 +26,29 @@
import React from "react";
import ArrowPathReactSvgUrl from "PUBLIC_DIR/images/arrow.path.react.svg?url";
import { IconButton } from "../../icon-button";
import { Heading } from "../../heading";
import { StyledHeader } from "../Selector.styled";
import { HeaderProps } from "../Selector.types";
import { AsideHeader } from "../../aside";
const Header = React.memo(
({
onBackClick,
onCloseClick,
withoutBackButton,
headerLabel,
withoutBorder,
isCloseable,
}: HeaderProps) => {
return (
<StyledHeader withoutBorder={withoutBorder}>
{!withoutBackButton && typeof withoutBackButton === "boolean" && (
<IconButton
className="arrow-button"
iconName={ArrowPathReactSvgUrl}
size={17}
onClick={onBackClick}
/>
)}
<Heading className="heading-text">{headerLabel}</Heading>
</StyledHeader>
<AsideHeader
header={headerLabel}
isBackButton={
!withoutBackButton && typeof withoutBackButton === "boolean"
}
onBackClick={onBackClick}
onCloseClick={onCloseClick}
withoutBorder={withoutBorder}
isCloseable={isCloseable}
/>
);
},
);

View File

@ -28,6 +28,7 @@ import { TSelectorItem } from "../../components/selector";
import {
TBreadCrumb,
TInfoBar,
TSelectorHeader,
} from "../../components/selector/Selector.types";
import {
TFileSecurity,
@ -143,7 +144,8 @@ export type TSelectedFileInfo = {
export type TGetIcon = (size: number, fileExst: string) => string;
export type FilesSelectorProps = TInfoBar &
export type FilesSelectorProps = TSelectorHeader &
TInfoBar &
(
| {
getIcon: TGetIcon;

View File

@ -114,6 +114,7 @@ const FilesSelectorComponent = ({
createDefineRoomType,
withInfoBar,
infoBarData,
headerProps,
}: FilesSelectorProps) => {
const theme = useTheme();
const { t } = useTranslation(["Common"]);
@ -475,8 +476,15 @@ const FilesSelectorComponent = ({
openRoot,
]);
const headerProps: TSelectorHeader = withHeader
? { withHeader, headerProps: { headerLabel } }
const headerSelectorProps: TSelectorHeader = withHeader
? {
withHeader,
headerProps: {
...headerProps,
headerLabel,
onCloseClick: onCancel,
},
}
: {};
const withSearch = withSearchProp
@ -553,7 +561,7 @@ const FilesSelectorComponent = ({
const SelectorBody = (
<Selector
{...headerProps}
{...headerSelectorProps}
{...searchProps}
{...submitButtonProps}
{...cancelButtonProps}
@ -617,6 +625,7 @@ const FilesSelectorComponent = ({
withoutBodyScroll
zIndex={310}
onClose={onCancel}
withoutHeader
>
{SelectorBody}
</Aside>

View File

@ -2580,6 +2580,7 @@ __metadata:
"@babel/preset-typescript": "npm:^7.21.0"
"@codemirror/lang-javascript": "npm:^6.2.2"
"@svgr/webpack": "npm:^5.5.0"
"@types/element-resize-detector": "npm:^1.1.6"
"@types/eslint": "npm:^8.44.7"
"@types/he": "npm:^1.2.3"
"@typescript-eslint/eslint-plugin": "npm:^6.12.0"
@ -7627,6 +7628,13 @@ __metadata:
languageName: node
linkType: hard
"@types/element-resize-detector@npm:^1.1.6":
version: 1.1.6
resolution: "@types/element-resize-detector@npm:1.1.6"
checksum: 10/62967c4933ce6dc717608aa498bfbbf2567c3778958203621b1981f5804eb519cf16b8f677d3c92c9b2a9d791191b514dd60298e276fcbf6b1660542209dd299
languageName: node
linkType: hard
"@types/emscripten@npm:^1.39.6":
version: 1.39.10
resolution: "@types/emscripten@npm:1.39.10"