Merge branch 'hotfix/v2.6.1' into bugfix/huge-group-issues

This commit is contained in:
Alexey Safronov 2024-08-12 13:07:44 +04:00
commit c9661b2745
46 changed files with 287 additions and 360 deletions

View File

@ -350,7 +350,9 @@ export const getOptions = (
t("EmptyView:UploadFromPortalTitle", {
productName: t("Common:ProductName"),
}),
t("EmptyView:UploadPDFFormOptionDescription"),
t("EmptyView:UploadPDFFormOptionDescription", {
productName: t("Common:ProductName"),
}),
FilterType.PDFForm,
);

View File

@ -145,7 +145,9 @@ const SimulatePassword = memo(
}, [isDisabled]);
useEffect(() => {
setPassword(inputValue);
if (inputValue !== undefined) {
setPassword(inputValue);
}
}, [inputValue]);
return (

View File

@ -588,6 +588,7 @@ const AddUsersPanel = ({
isSearchLoading={isInit}
rowLoader={
<RowLoader
style={{ paddingInlineEnd: 0 }}
isUser
count={15}
isContainer={isLoading}

View File

@ -52,6 +52,7 @@ import { StyledNewFilesBody, StyledLink } from "../StyledPanels";
import withLoader from "../../../HOCs/withLoader";
import config from "PACKAGE_FILE";
import { MEDIA_VIEW_URL } from "@docspace/shared/constants";
const NewFilesPanel = (props) => {
const {
@ -60,8 +61,6 @@ const NewFilesPanel = (props) => {
getFolderIcon,
newFiles,
markAsRead,
setMediaViewerData,
currentFolderId,
setIsLoading,
t,
visible,
@ -203,40 +202,10 @@ const NewFilesPanel = (props) => {
}
if (isMedia) {
if (currentFolderId !== item.folderId) {
const categoryType = getCategoryTypeByFolderType(
rootFolderType,
item.folderId,
);
const state = {
title: "",
rootFolderType,
isRoot: false,
};
setIsLoading(true);
const url = getCategoryUrl(categoryType, item.folderId);
const filter = FilesFilter.getDefault();
filter.folder = item.folderId;
window.DocSpace.navigate(`${url}?${filter.toUrlParams()}`, { state });
const mediaItem = { visible: true, id };
setMediaViewerData(mediaItem);
setInProgress(false);
onClose();
} else {
const mediaItem = { visible: true, id };
setMediaViewerData(mediaItem);
return onClose();
}
return;
return window.open(
combineUrl(MEDIA_VIEW_URL, id),
openOnNewPage ? "_blank" : "_self",
);
}
if (fileItemsList && enablePlugins) {
@ -335,7 +304,6 @@ export default inject(
filesStore,
mediaViewerDataStore,
filesActionsStore,
selectedFolderStore,
dialogsStore,
filesSettingsStore,
clientLoadingStore,
@ -349,10 +317,9 @@ export default inject(
setIsSectionFilterLoading(param);
};
const { setMediaViewerData, setCurrentItem } = mediaViewerDataStore;
const { setCurrentItem } = mediaViewerDataStore;
const { getIcon, getFolderIcon, openOnNewPage } = filesSettingsStore;
const { markAsRead } = filesActionsStore;
const { id: currentFolderId } = selectedFolderStore;
const {
setNewFilesPanelVisible,
@ -371,8 +338,6 @@ export default inject(
newFilesIds,
isLoading,
setCurrentItem,
currentFolderId,
setMediaViewerData,
getIcon,
getFolderIcon,
markAsRead,

View File

@ -52,6 +52,7 @@ import {
} from "./StyledCreateUser";
import PortalLogo from "@docspace/shared/components/portal-logo/PortalLogo";
import GreetingUserContainer from "./GreetingUserContainer";
import { ALLOWED_PASSWORD_CHARACTERS } from "@docspace/shared/constants";
const ActivateUserForm = (props) => {
const { t, settings, linkData, hashSettings, defaultPage, login } = props;

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
import SsoReactSvgUrl from "PUBLIC_DIR/images/sso.react.svg?url";
import SsoReactSvg from "PUBLIC_DIR/images/sso.react.svg";
import React, { useEffect, useState, useCallback } from "react";
import { withTranslation, Trans } from "react-i18next";
@ -469,7 +469,7 @@ const CreateUserForm = (props) => {
? {
ssoUrl: capabilities?.ssoUrl,
ssoLabel: capabilities?.ssoLabel,
ssoSVG: SsoReactSvgUrl,
ssoSVG: SsoReactSvg,
}
: {};

View File

@ -52,7 +52,7 @@ const RoomsItemHeader = ({
setSelection,
setBufferSelection,
isArchive,
hasLinks,
isShared,
showSearchBlock,
setShowSearchBlock,
roomType,
@ -70,7 +70,7 @@ const RoomsItemHeader = ({
(selection.roomType === RoomsType.PublicRoom ||
selection.roomType === RoomsType.FormRoom ||
selection.roomType === RoomsType.CustomRoom) &&
hasLinks;
isShared;
const badgeUrl = showPlanetIcon ? Planet12ReactSvgUrl : null;
const isRoomMembersPanel = selection?.isRoom && roomsView === "info_members";
@ -161,7 +161,6 @@ export default inject(
selectedFolderStore,
filesStore,
infoPanelStore,
publicRoomStore,
}) => {
const {
infoPanelSelection,
@ -170,7 +169,6 @@ export default inject(
showSearchBlock,
setShowSearchBlock,
} = infoPanelStore;
const { externalLinks } = publicRoomStore;
const selection = infoPanelSelection.length > 1 ? null : infoPanelSelection;
const isArchive = selection?.rootFolderType === FolderType.Archive;
@ -196,7 +194,7 @@ export default inject(
setSelection: filesStore.setSelection,
setBufferSelection: filesStore.setBufferSelection,
isArchive,
hasLinks: externalLinks.length,
isShared: selection?.shared,
roomType,
};
},

View File

@ -187,12 +187,14 @@ const AdditionalResources = (props) => {
const onSave = useCallback(async () => {
setIsLoading(true);
const settings = JSON.parse(JSON.stringify(additionalResourcesData));
settings.feedbackAndSupportEnabled = feedbackAndSupportEnabled;
settings.videoGuidesEnabled = videoGuidesEnabled;
settings.helpCenterEnabled = helpCenterEnabled;
await api.settings
.setAdditionalResources(
feedbackAndSupportEnabled,
videoGuidesEnabled,
helpCenterEnabled,
)
.setAdditionalResources(settings)
.then(() => {
toastr.success(t("Settings:SuccessfullySaveSettingsMessage"));
})

View File

@ -142,7 +142,7 @@ const SocialNetworks = (props) => {
return (
<div key={`${item.provider}ProviderItem`}>
<SocialButton
iconName={icon}
IconComponent={icon}
label={getProviderTranslation(label, t, item.linked)}
$iconOptions={iconOptions}
onClick={onClick}

View File

@ -246,6 +246,11 @@ const Sdk = ({
if (!frameConfig) return;
const selectorOpenRoot =
selectorType !== "userFolderOnly" &&
selectorType !== "roomsOnly" &&
!frameConfig?.id;
switch (mode) {
case "room-selector":
const cancelButtonProps = frameConfig?.showSelectorCancel
@ -294,7 +299,7 @@ const Sdk = ({
acceptButtonLabel={frameConfig?.acceptButtonLabel}
cancelButtonLabel={frameConfig?.cancelButtonLabel}
currentFolderId={frameConfig?.id}
openRoot={!frameConfig?.id}
openRoot={selectorOpenRoot}
descriptionText={formatsDescription[frameConfig?.filterParam] || ""}
/>
);

View File

@ -155,13 +155,6 @@ class FilesActionStore {
this.isBulkDownload = isBulkDownload;
};
isMediaOpen = () => {
const { visible, setMediaViewerData, playlist } = this.mediaViewerDataStore;
if (visible && playlist.length === 1) {
setMediaViewerData({ visible: false, id: null });
}
};
updateCurrentFolder = (fileIds, folderIds, clearSelection, operationId) => {
const { clearSecondaryProgressData } =
this.uploadDataStore.secondaryProgressDataStore;
@ -390,8 +383,6 @@ class FilesActionStore {
addActiveItems(null, folderIds, destFolderId);
if (folderIds.length || fileIds.length) {
this.isMediaOpen();
try {
this.filesStore.setOperationAction(true);
this.setGroupMenuBlocked(true);
@ -852,7 +843,6 @@ class FilesActionStore {
if (isFile) {
addActiveItems([itemId], null, destFolderId);
this.isMediaOpen();
return deleteFile(itemId)
.then(async (res) => {
if (res[0]?.error) return Promise.reject(res[0].error);

View File

@ -24,11 +24,8 @@
// 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 { cookies } from "next/headers";
import dynamic from "next/dynamic";
import { SYSTEM_THEME_KEY } from "@docspace/shared/constants";
import { ThemeKeys, WhiteLabelLogoType } from "@docspace/shared/enums";
import { getBgPattern, getLogoUrl } from "@docspace/shared/utils/common";
import { Scrollbar } from "@docspace/shared/components/scrollbar";
import { ColorTheme, ThemeId } from "@docspace/shared/components/color-theme";
@ -56,10 +53,6 @@ export default async function Layout({
getColorTheme(),
]);
const cookieStore = cookies();
const systemTheme = cookieStore.get(SYSTEM_THEME_KEY)?.value as ThemeKeys;
const bgPattern = getBgPattern(colorTheme?.selected);
const objectSettings = typeof settings === "string" ? undefined : settings;
@ -68,8 +61,7 @@ export default async function Layout({
return (
<div style={{ width: "100%", height: "100%" }}>
<SimpleNav systemTheme={systemTheme} />
<SimpleNav />
<LoginFormWrapper id="login-page" bgPattern={bgPattern}>
<div className="bg-cover" />
<Scrollbar id="customScrollBar">

View File

@ -24,7 +24,14 @@
// 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 { getSettings } from "@/utils/actions";
import { PROVIDERS_DATA } from "@docspace/shared/constants";
import {
getCapabilities,
getSettings,
getSSO,
getThirdPartyProviders,
} from "@/utils/actions";
import Login from "@/components/Login";
import LoginForm from "@/components/LoginForm";
import ThirdParty from "@/components/ThirdParty";
@ -32,7 +39,26 @@ import RecoverAccess from "@/components/RecoverAccess";
import Register from "@/components/Register";
async function Page() {
const settings = await getSettings();
const [settings, thirdParty, capabilities, ssoSettings] = await Promise.all([
getSettings(),
getThirdPartyProviders(),
getCapabilities(),
getSSO(),
]);
const ssoUrl = capabilities ? capabilities.ssoUrl : "";
const hideAuthPage = ssoSettings ? ssoSettings.hideAuthPage : false;
const ssoExists = !!ssoUrl;
const oauthDataExists =
!capabilities?.oauthEnabled || !thirdParty || thirdParty.length === 0
? false
: thirdParty
.map((item) => {
if (!(item.provider in PROVIDERS_DATA)) return undefined;
return item;
})
.some((item) => !!item);
return (
<Login>
@ -43,8 +69,17 @@ async function Page() {
cookieSettingsEnabled={settings?.cookieSettingsEnabled}
reCaptchaPublicKey={settings?.recaptchaPublicKey}
reCaptchaType={settings?.recaptchaType}
ldapDomain={capabilities?.ldapDomain}
ldapEnabled={capabilities?.ldapEnabled}
/>
<ThirdParty
thirdParty={thirdParty}
capabilities={capabilities}
ssoExists={ssoExists}
ssoUrl={ssoUrl}
hideAuthPage={hideAuthPage}
oauthDataExists={oauthDataExists}
/>
<ThirdParty />
{settings.enableAdmMess && <RecoverAccess />}
{settings.enabledJoin && (
<Register

View File

@ -36,11 +36,11 @@ import type {
TFirebaseSettings,
TSettings,
} from "@docspace/shared/api/settings/types";
import FirebaseHelper from "@docspace/shared/utils/firebase";
import useTheme from "@/hooks/useTheme";
import useDeviceType from "@/hooks/useDeviceType";
import useI18N from "@/hooks/useI18N";
import FirebaseHelper from "@docspace/shared/utils/firebase";
import pkg from "../../package.json";

View File

@ -26,6 +26,7 @@
import { cookies, headers } from "next/headers";
import { redirect } from "next/navigation";
import { Toast } from "@docspace/shared/components/toast";
import { getBaseUrl } from "@docspace/shared/utils/next-ssr-helper";
import { TenantStatus, ThemeKeys } from "@docspace/shared/enums";
@ -58,18 +59,11 @@ export default async function RootLayout({
let redirectUrl = "";
const timers = { otherOperations: 0 };
const startOtherOperationsDate = new Date();
const [settings, colorTheme] = await Promise.all([
getSettings(),
getColorTheme(),
]);
timers.otherOperations =
new Date().getTime() - startOtherOperationsDate.getTime();
if (settings === "access-restricted") redirectUrl = `/${settings}`;
if (settings === "portal-not-found") {
@ -132,7 +126,6 @@ export default async function RootLayout({
systemTheme: systemTheme?.value as ThemeKeys,
}}
redirectURL={redirectUrl}
timers={timers}
>
<Toast isSSR />
{children}

View File

@ -33,7 +33,6 @@ import { useSearchParams } from "next/navigation";
import { useTheme } from "styled-components";
import { Text } from "@docspace/shared/components/text";
import { WhiteLabelLogoType } from "@docspace/shared/enums";
import { getLogoUrl } from "@docspace/shared/utils/common";

View File

@ -33,10 +33,10 @@ import { setLanguageForUnauthorized } from "@docspace/shared/utils/common";
import { LanguageCombobox } from "@docspace/shared/components/language-combobox";
import { DeviceType } from "@docspace/shared/enums";
import { Nullable } from "@docspace/shared/types";
import { getPortalCultures } from "@docspace/shared/api/settings";
import { TPortalCultures } from "@docspace/shared/api/settings/types";
import useDeviceType from "@/hooks/useDeviceType";
import { getPortalCultures } from "@/utils/actions";
const LanguageComboboxWrapper = () => {
const { i18n } = useTranslation(["Login", "Common"]);

View File

@ -31,27 +31,20 @@ import React, { createContext, useState } from "react";
export const LoginValueContext = createContext({
isLoading: false,
isModalOpen: false,
ldapDomain: "",
});
export const LoginDispatchContext = createContext({
setIsLoading: (value: boolean) => {},
setIsModalOpen: (value: boolean) => {},
setLdapDomain: (value: string) => {},
});
export const LoginContext = ({ children }: { children: React.ReactNode }) => {
const [isLoading, setIsLoading] = useState(false);
const [isModalOpen, setIsModalOpen] = useState(false);
const [ldapDomain, setLdapDomain] = useState("");
return (
<LoginDispatchContext.Provider
value={{ setIsLoading, setIsModalOpen, setLdapDomain }}
>
<LoginValueContext.Provider
value={{ isLoading, isModalOpen, ldapDomain }}
>
<LoginDispatchContext.Provider value={{ setIsLoading, setIsModalOpen }}>
<LoginValueContext.Provider value={{ isLoading, isModalOpen }}>
{children}
</LoginValueContext.Provider>
</LoginDispatchContext.Provider>

View File

@ -38,6 +38,7 @@ import { useTranslation } from "react-i18next";
import ReCAPTCHA from "react-google-recaptcha";
import HCaptcha from "@hcaptcha/react-hcaptcha";
import { useTheme } from "styled-components";
import { Id } from "react-toastify";
import { useSearchParams } from "next/navigation";
import { Text } from "@docspace/shared/components/text";
@ -52,6 +53,7 @@ import { toastr } from "@docspace/shared/components/toast";
import { thirdPartyLogin, checkConfirmLink } from "@docspace/shared/api/user";
import { setWithCredentialsStatus } from "@docspace/shared/api/client";
import { TValidate } from "@docspace/shared/components/email-input/EmailInput.types";
import { RecaptchaType } from "@docspace/shared/enums";
import { LoginFormProps } from "@/types";
import { getEmailFromInvitation, getConfirmDataFromInvitation } from "@/utils";
@ -59,11 +61,11 @@ import { getEmailFromInvitation, getConfirmDataFromInvitation } from "@/utils";
import EmailContainer from "./sub-components/EmailContainer";
import PasswordContainer from "./sub-components/PasswordContainer";
import ForgotContainer from "./sub-components/ForgotContainer";
import LDAPContainer from "./sub-components/LDAPContainer";
import { LoginDispatchContext, LoginValueContext } from "../Login";
import { StyledCaptcha } from "./LoginForm.styled";
import { LoginDispatchContext, LoginValueContext } from "../Login";
import LDAPContainer from "./sub-components/LDAPContainer";
import { RecaptchaType } from "@docspace/shared/enums";
let showToastr = true;
@ -72,10 +74,12 @@ const LoginForm = ({
cookieSettingsEnabled,
reCaptchaPublicKey,
reCaptchaType,
ldapDomain,
ldapEnabled,
}: LoginFormProps) => {
const { isLoading, isModalOpen, ldapDomain } = useContext(LoginValueContext);
const { isLoading, isModalOpen } = useContext(LoginValueContext);
const { setIsLoading } = useContext(LoginDispatchContext);
const toastId = useRef(null);
const toastId = useRef<Id>();
const searchParams = useSearchParams();
@ -417,7 +421,7 @@ const LoginForm = ({
onChangeCheckbox={onChangeCheckbox}
/>
{ldapDomain && (
{ldapDomain && ldapEnabled && (
<LDAPContainer
ldapDomain={ldapDomain}
isLdapLoginChecked={isLdapLoginChecked}

View File

@ -54,7 +54,7 @@ interface IEmailContainer {
onBlurEmail: () => void;
onValidateEmail: (res: TValidate) => undefined;
isLdapLogin: boolean;
ldapDomain: string;
ldapDomain?: string;
}
const EmailContainer = ({

View File

@ -49,7 +49,7 @@ const ForgotPasswordModalDialog = ({
userEmail,
onDialogClose,
}: ForgotPasswordModalDialogProps) => {
const [email, setEmail] = useState(userEmail);
const [email, setEmail] = useState(userEmail ?? "");
const [emailError, setEmailError] = useState(false);
const [isLoading, setIsLoading] = useState(false);
const [errorText, setErrorText] = useState("");

View File

@ -34,6 +34,7 @@ import { mobile } from "@docspace/shared/utils/device";
import { getLogoUrl } from "@docspace/shared/utils/common";
import { Base, Dark } from "@docspace/shared/themes";
import { ThemeKeys, WhiteLabelLogoType } from "@docspace/shared/enums";
import LanguageComboboxWrapper from "./LanguageCombobox";
const StyledSimpleNav = styled.div`
@ -60,13 +61,13 @@ const StyledSimpleNav = styled.div`
StyledSimpleNav.defaultProps = { theme: Base };
interface SimpleNavProps {
systemTheme: ThemeKeys;
}
interface SimpleNavProps {}
const SimpleNav = ({ systemTheme }: SimpleNavProps) => {
const SimpleNav = ({}: SimpleNavProps) => {
const theme = useTheme();
const isDark = !theme.isBase;
const logoUrl = getLogoUrl(WhiteLabelLogoType.LightSmall, isDark);
return (

View File

@ -33,22 +33,13 @@ import styled from "styled-components";
import { SocialButtonsGroup } from "@docspace/shared/components/social-buttons-group";
import { Text } from "@docspace/shared/components/text";
import { PROVIDERS_DATA } from "@docspace/shared/constants";
import { getOAuthToken, getLoginLink } from "@docspace/shared/utils/common";
import {
TCapabilities,
TGetSsoSettings,
TThirdPartyProvider,
} from "@docspace/shared/api/settings/types";
import { Nullable } from "@docspace/shared/types";
import SSOIcon from "PUBLIC_DIR/images/sso.react.svg?url";
import {
getCapabilities,
getSSO,
getThirdPartyProviders,
} from "@/utils/actions";
import SSOIcon from "PUBLIC_DIR/images/sso.react.svg";
import { LoginDispatchContext, LoginValueContext } from "./Login";
@ -57,44 +48,31 @@ const StyledThirdParty = styled.div<{ isVisible: boolean }>`
height: auto;
`;
const ThirdParty = () => {
type ThirdPartyProps = {
thirdParty?: TThirdPartyProvider[];
capabilities?: TCapabilities;
ssoUrl?: string;
ssoExists?: boolean;
oauthDataExists?: boolean;
hideAuthPage?: boolean;
};
const ThirdParty = ({
thirdParty,
capabilities,
ssoUrl,
ssoExists,
oauthDataExists,
hideAuthPage,
}: ThirdPartyProps) => {
const { isLoading } = useContext(LoginValueContext);
const { setIsModalOpen, setLdapDomain } = useContext(LoginDispatchContext);
const { setIsModalOpen } = useContext(LoginDispatchContext);
const searchParams = useSearchParams();
const { t } = useTranslation(["Login", "Common"]);
const [capabilities, setCapabilities] =
React.useState<Nullable<TCapabilities>>(null);
const [thirdPartyProvider, setThirdPartyProvider] =
React.useState<Nullable<TThirdPartyProvider[]>>(null);
const [ssoSettings, setSsoSettings] =
React.useState<Nullable<TGetSsoSettings>>(null);
const getData = useCallback(async () => {
const [thirdParty, capabilities, ssoSettings] = await Promise.all([
getThirdPartyProviders(),
getCapabilities(),
getSSO(),
]);
if (thirdParty) setThirdPartyProvider(thirdParty);
if (capabilities) setCapabilities(capabilities);
if (ssoSettings) setSsoSettings(ssoSettings);
}, []);
useEffect(() => {
getData();
}, [getData]);
useEffect(() => {
const ssoUrl = capabilities ? capabilities.ssoUrl : "";
const hideAuthPage = ssoSettings ? ssoSettings.hideAuthPage : false;
if (capabilities?.ldapEnabled && capabilities.ldapDomain)
setLdapDomain(capabilities.ldapDomain);
if (
ssoUrl &&
hideAuthPage &&
@ -102,25 +80,7 @@ const ThirdParty = () => {
) {
window.location.replace(ssoUrl);
}
}, [capabilities, searchParams, ssoSettings, setLdapDomain]);
const ssoExists = () => {
if (capabilities?.ssoUrl) return true;
else return false;
};
const oauthDataExists = () => {
if (!capabilities?.oauthEnabled) return false;
let existProviders = 0;
if (thirdPartyProvider && thirdPartyProvider.length > 0)
thirdPartyProvider?.map((item) => {
if (!(item.provider in PROVIDERS_DATA)) return;
existProviders++;
});
return !!existProviders;
};
}, [capabilities, searchParams, ssoUrl, hideAuthPage]);
const onSocialButtonClick = useCallback(
(e: React.MouseEvent<Element, MouseEvent>) => {
@ -171,7 +131,7 @@ const ThirdParty = () => {
[],
);
const ssoProps = ssoExists()
const ssoProps = ssoExists
? {
ssoUrl: capabilities?.ssoUrl,
ssoLabel: capabilities?.ssoLabel,
@ -179,7 +139,7 @@ const ThirdParty = () => {
}
: {};
const isVisible = oauthDataExists() || ssoExists();
const isVisible = oauthDataExists || ssoExists;
return (
isVisible && (
@ -188,7 +148,7 @@ const ThirdParty = () => {
<Text className="or-label">{t("Common:orContinueWith")}</Text>
</div>
<SocialButtonsGroup
providers={thirdPartyProvider ?? undefined}
providers={thirdParty ?? undefined}
onClick={onSocialButtonClick}
onMoreAuthToggle={setIsModalOpen}
t={t}

View File

@ -25,14 +25,12 @@
// International. See the License terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
import React from "react";
import { i18n } from "i18next";
import { getCookie, getLanguage } from "@docspace/shared/utils";
import { getCookie } from "@docspace/shared/utils";
import { LANGUAGE } from "@docspace/shared/constants";
import { TSettings } from "@docspace/shared/api/settings/types";
import { getI18NInstance } from "@/utils/i18n";
import { setCookie } from "@docspace/shared/utils/cookie";
interface UseI18NProps {
settings?: TSettings;

View File

@ -24,8 +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 useDeviceType from "@/hooks/useDeviceType";
import ErrorBoundary from "@docspace/shared/components/error-boundary/ErrorBoundary";
import useDeviceType from "@/hooks/useDeviceType";
import { ErrorBoundaryProps } from "./ErrorBoundary.types";
const ErrorBoundaryWrapper = (props: ErrorBoundaryProps) => {

View File

@ -33,20 +33,18 @@ import { ThemeProvider } from "@docspace/shared/components/theme-provider";
import { TFirebaseSettings } from "@docspace/shared/api/settings/types";
import FirebaseHelper from "@docspace/shared/utils/firebase";
import { TUser } from "@docspace/shared/api/people/types";
import { ThemeKeys } from "@docspace/shared/enums";
import { Base, Dark } from "@docspace/shared/themes";
import { TDataContext } from "@/types";
import useI18N from "@/hooks/useI18N";
import useTheme from "@/hooks/useTheme";
import pkgFile from "../../package.json";
import ErrorBoundaryWrapper from "./ErrorBoundary";
export const Providers = ({
children,
value,
timers,
redirectURL,
}: {
children: React.ReactNode;
@ -61,10 +59,6 @@ export const Providers = ({
if (redirectURL) window.location.replace(redirectURL);
}, [redirectURL]);
React.useEffect(() => {
console.log("Timers:", { ...timers });
}, [timers]);
const { i18n } = useI18N({
settings: value.settings,
});

View File

@ -86,6 +86,8 @@ export type LoginFormProps = {
reCaptchaPublicKey?: string;
reCaptchaType?: RecaptchaType;
cookieSettingsEnabled: boolean;
ldapDomain?: string;
ldapEnabled?: boolean;
};
export type ForgotPasswordModalDialogProps = {

View File

@ -144,18 +144,3 @@ export async function getSSO() {
return sso.response as TGetSsoSettings;
}
export async function getPortalCultures() {
const [getPortalCultures] = createRequest(
[`/settings/cultures`],
[["", ""]],
"GET",
);
const res = await fetch(getPortalCultures);
if (!res.ok) return;
const cultures = await res.json();
return cultures.response as TPortalCultures;
}

View File

@ -407,16 +407,10 @@ export async function getCustomSchemaList() {
}
export function setAdditionalResources(
feedbackAndSupportEnabled,
videoGuidesEnabled,
helpCenterEnabled,
additionalResources: TAdditionalResources,
) {
const data = {
settings: {
helpCenterEnabled,
feedbackAndSupportEnabled,
videoGuidesEnabled,
},
settings: additionalResources,
};
return request({

View File

@ -29,12 +29,15 @@ import { BoxProps } from "./Box.types";
import { StyledBox } from "./Box.styled";
function Box(props: BoxProps) {
const { as } = props;
return <StyledBox {...props} as={as || "div"} data-testid="box" />;
const { as, displayProp = "block" } = props;
return (
<StyledBox
{...props}
displayProp={displayProp}
as={as || "div"}
data-testid="box"
/>
);
}
Box.defaultProps = {
displayProp: "block",
};
export { Box };

View File

@ -37,6 +37,8 @@ const StyledLabel = styled.label<{
position: relative;
margin: 0;
line-height: 16px;
user-select: none;
-o-user-select: none;
-moz-user-select: none;

View File

@ -142,6 +142,7 @@ const CheckboxPure = ({
title={title}
truncate={truncate}
className="checkbox-text"
lineHeight="16px"
>
{label}
</Text>

View File

@ -49,25 +49,29 @@ import type { ComboButtonProps } from "../Combobox.types";
const ComboButton = (props: ComboButtonProps) => {
const {
noBorder,
onClick,
isDisabled,
innerContainer,
innerContainerClassName = "innerContainer",
selectedOption,
optionsLength = 0,
withOptions = true,
withAdvancedOptions = false,
isOpen,
scaled = false,
size,
comboIcon,
fillIcon,
modernView = false,
tabIndex,
isLoading,
type,
plusBadgeValue,
noBorder = false,
isDisabled = false,
withOptions = true,
withAdvancedOptions = false,
innerContainerClassName = "innerContainer",
isOpen = false,
size = ComboBoxSize.content,
scaled = false,
modernView = false,
tabIndex = -1,
isLoading = false,
} = props;
const defaultOption = selectedOption?.default;
@ -174,18 +178,4 @@ const ComboButton = (props: ComboButtonProps) => {
);
};
ComboButton.defaultProps = {
noBorder: false,
isDisabled: false,
withOptions: true,
withAdvancedOptions: false,
innerContainerClassName: "innerContainer",
isOpen: false,
size: ComboBoxSize.content,
scaled: false,
modernView: false,
tabIndex: -1,
isLoading: false,
};
export { ComboButton };

View File

@ -46,21 +46,21 @@ import { DropDownItemProps } from "./DropDownItem.types";
const DropDownItem = (props: DropDownItemProps) => {
const {
isSeparator,
isHeader,
isSeparator = false,
isHeader = false,
withHeaderArrow,
headerArrowAction,
icon,
children,
disabled,
disabled = false,
className,
fillIcon = true,
isSubMenu,
isActive,
withoutIcon,
noHover,
isSubMenu = false,
isActive = false,
withoutIcon = false,
noHover = false,
isSelected,
isActiveDescendant,
@ -72,8 +72,17 @@ const DropDownItem = (props: DropDownItemProps) => {
const { t } = useTranslation(["Common"]);
const theme = useTheme();
const { withToggle, checked, onClick, onClickSelectedItem, label, ...rest } =
props;
const {
withToggle,
checked,
onClick,
onClickSelectedItem,
label = "",
tabIndex = -1,
textOverflow = false,
...rest
} = props;
const onClickAction = (
e: React.MouseEvent | React.ChangeEvent<HTMLInputElement>,
@ -97,6 +106,8 @@ const DropDownItem = (props: DropDownItemProps) => {
return (
<StyledDropdownItem
{...rest}
tabIndex={tabIndex}
textOverflow={textOverflow}
noHover={noHover}
className={className}
onClick={onClickAction}
@ -184,17 +195,6 @@ const DropDownItem = (props: DropDownItemProps) => {
};
DropDownItem.defaultProps = {
isSeparator: false,
isHeader: false,
tabIndex: -1,
label: "",
disabled: false,
noHover: false,
textOverflow: false,
fillIcon: true,
isSubMenu: false,
isActive: false,
withoutIcon: false,
height: 32,
heightTablet: 36,
};

View File

@ -75,4 +75,6 @@ export interface DropDownItemProps {
isBeta?: boolean;
additionalElement?: React.ReactNode;
setOpen?: (open: boolean) => void;
height?: number;
heightTablet?: number;
}

View File

@ -45,6 +45,12 @@ const DropDown = (props: DropDownProps) => {
eventTypes,
forceCloseClickOutside,
withoutBackground,
showDisabledItems = false,
isDefaultMode = true,
fixedDirection = false,
offsetLeft = 0,
enableKeyboardEvents = true,
} = props;
const toggleDropDown = () => {
@ -72,17 +78,17 @@ const DropDown = (props: DropDownProps) => {
withoutBackground={withoutBackground}
/>
) : null}
<EnhancedComponent {...eventTypesProp} {...props} />
<EnhancedComponent
{...eventTypesProp}
showDisabledItems={showDisabledItems}
isDefaultMode={isDefaultMode}
fixedDirection={fixedDirection}
offsetLeft={offsetLeft}
enableKeyboardEvents={enableKeyboardEvents}
{...props}
/>
</>
);
};
DropDown.defaultProps = {
withBackdrop: true,
showDisabledItems: false,
isDefaultMode: true,
fixedDirection: false,
offsetLeft: 0,
enableKeyboardEvents: true,
};
export { DropDown };

View File

@ -39,19 +39,33 @@ const TextInputWrapper = ({
emailSettings,
customValidate,
...props
}: EmailInputProps & TextInputProps & { isValidEmail?: boolean }) => (
<StyledEmailInput {...props} data-testid="email-input" />
);
}: EmailInputProps & TextInputProps & { isValidEmail?: boolean }) => {
return <StyledEmailInput {...props} data-testid="email-input" />;
};
const EmailInput = ({
value,
onValidateInput,
customValidate,
emailSettings,
onBlur,
onChange,
hasError,
isAutoFocussed,
autoComplete = "email",
className = "",
hasError = undefined,
id = "",
isDisabled = false,
isReadOnly = false,
maxLength = 255,
name = "",
placeholder = "",
scale = false,
size = InputSize.base,
title = "",
withBorder = true,
value = "",
emailSettings,
...rest
}: EmailInputProps) => {
const [inputValue, setInputValue] = React.useState(value);
@ -65,7 +79,7 @@ const EmailInput = ({
return customValidate(v);
}
const emailObj = parseAddress(v, emailSettings);
const emailObj = parseAddress(v, emailSettings ?? new EmailSettings());
const isValid = emailObj.isValid();
const parsedErrors = emailObj.parseErrors;
const errors = parsedErrors
@ -124,6 +138,18 @@ const EmailInput = ({
return (
<TextInputWrapper
{...rest}
className={className}
autoComplete={autoComplete}
id={id}
isDisabled={isDisabled}
isReadOnly={isReadOnly}
maxLength={maxLength}
name={name}
placeholder={placeholder}
scale={scale}
size={size}
title={title}
withBorder={withBorder}
isAutoFocussed={isMobile && isIOS ? false : isAutoFocussed}
hasError={isError}
value={inputValue}
@ -135,22 +161,4 @@ const EmailInput = ({
);
};
EmailInput.defaultProps = {
autoComplete: "email",
className: "",
hasError: undefined,
id: "",
isDisabled: false,
isReadOnly: false,
maxLength: 255,
name: "",
placeholder: "",
scale: false,
size: InputSize.base,
title: "",
value: "",
withBorder: true,
emailSettings: new EmailSettings(),
};
export { EmailInput };

View File

@ -72,4 +72,8 @@ export interface EmailInputProps {
type: InputType;
/** Used as HTML `tabindex` property */
tabIndex?: number;
withBorder?: boolean;
maxLength?: number;
title?: string;
}

View File

@ -38,9 +38,9 @@ import { HelpButtonProps } from "./HelpButton.types";
const HelpButton = (props: HelpButtonProps) => {
const {
id,
className,
className = "icon-button",
iconName,
size,
size = 12,
color,
dataTip,
getContent,
@ -65,7 +65,7 @@ const HelpButton = (props: HelpButtonProps) => {
id={currentId}
className={classNames([className], "help-icon") || "help-icon"}
isClickable
iconName={iconName || InfoReactSvgUrl}
iconName={iconName ?? InfoReactSvgUrl}
size={size}
color={color}
data-for={currentId}
@ -102,11 +102,4 @@ const HelpButton = (props: HelpButtonProps) => {
);
};
HelpButton.defaultProps = {
iconName: InfoReactSvgUrl,
// place: "top",
className: "icon-button",
size: 12,
};
export { HelpButton };

View File

@ -23,8 +23,7 @@
// 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 { useMemo } from "react";
import React, { useMemo } from "react";
import { useTranslation } from "react-i18next";
import { mapCulturesToArray } from "../../utils/common";
@ -58,7 +57,7 @@ const LanguageCombobox = (props: ComboboxProps) => {
onSelectLanguage(culture);
};
if (!currentCulture) return <></>;
if (!currentCulture) return null;
return (
<StyledComboBox

View File

@ -23,4 +23,5 @@
// 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
export { LanguageCombobox } from "./LanguageCombobox";

View File

@ -35,16 +35,34 @@ export { LinkType, LinkTarget };
const Link = ({
isTextOverflow,
children,
noHover,
enableUserSelect,
className = "",
fontSize = "13px",
href = undefined,
isBold = false,
isHovered = false,
isSemitransparent = false,
noHover = false,
rel = "noopener noreferrer",
tabIndex = -1,
type = LinkType.page,
enableUserSelect = false,
...rest
}: LinkProps) => {
return (
<StyledText
className={className}
fontSize={fontSize}
href={href}
isBold={isBold}
isHovered={isHovered}
isSemitransparent={isSemitransparent}
rel={rel}
tabIndex={tabIndex}
type={type}
tag="a"
isTextOverflow={isTextOverflow}
noHover={noHover}
truncate={isTextOverflow || false}
truncate={isTextOverflow ?? false}
enableUserSelect={enableUserSelect}
data-testid="link"
{...rest}
@ -54,19 +72,4 @@ const Link = ({
);
};
Link.defaultProps = {
className: "",
fontSize: "13px",
href: undefined,
isBold: false,
isHovered: false,
isSemitransparent: false,
isTextOverflow: false,
noHover: false,
rel: "noopener noreferrer",
tabIndex: -1,
type: LinkType.page,
enableUserSelect: false,
};
export { Link };

View File

@ -65,23 +65,28 @@ const ModalDialog = ({
children,
visible,
onClose,
isLarge,
zIndex,
className,
displayType = ModalDialogType.modal,
displayTypeDetailed,
isLoading,
autoMaxHeight,
autoMaxWidth,
withBodyScroll,
withFooterBorder,
isScrollLocked,
containerVisible,
isDoubleFooterLine,
isCloseable,
embedded,
withForm,
blur,
zIndex = 310,
isLarge = false,
isLoading = false,
isCloseable = true,
withBodyScroll = false,
withFooterBorder = false,
containerVisible = false,
}: ModalDialogProps) => {
const onCloseEvent = React.useCallback(() => {
if (embedded) return;
@ -174,16 +179,6 @@ const ModalDialog = ({
);
};
ModalDialog.defaultProps = {
zIndex: 310,
isLarge: false,
isLoading: false,
isCloseable: true,
withBodyScroll: false,
withFooterBorder: false,
containerVisible: false,
};
ModalDialog.Header = Header;
ModalDialog.Body = Body;
ModalDialog.Footer = Footer;

View File

@ -89,9 +89,11 @@ const MoreLoginModal: React.FC<MoreLoginModalProps> = (props) => {
const { icon, label } =
PROVIDERS_DATA[item.provider as keyof ProvidersDataType];
const IconComponent = icon;
return (
<ProviderRow key={`ProviderItem${label}`}>
<ReactSVG src={icon} />
<IconComponent />
<Text
fontSize="14px"
fontWeight="600"

View File

@ -29,7 +29,7 @@ import equal from "fast-deep-equal/react";
import { getProviderLabel } from "@docspace/shared/utils/common";
import VerticalDotsReactSvgUrl from "PUBLIC_DIR/images/vertical-dots.react.svg?url";
import VerticalDotsReactSvg from "PUBLIC_DIR/images/vertical-dots.react.svg";
import { SocialButton } from "../social-button";
import StyledSocialButtonsGroup from "./SocialButtonsGroup.styled";
@ -80,11 +80,11 @@ export const SocialButtonsGroup = memo(
<div className="buttonWrapper" key={`${provider}ProviderItem`}>
<SocialButton
isDisabled={isDisabled}
iconName={icon}
label={length >= 2 ? "" : getProviderLabel(label, t)}
$iconOptions={iconOptions}
data-url={url}
data-providername={provider}
IconComponent={icon}
onClick={onClick}
className="social-button"
/>
@ -97,7 +97,7 @@ export const SocialButtonsGroup = memo(
{ssoUrl && (
<SocialButton
isDisabled={isDisabled}
iconName={ssoSVG}
IconComponent={ssoSVG}
className="sso-button social-button"
label={ssoLabel || getProviderLabel("sso", t)}
onClick={() => (window.location.href = ssoUrl)}
@ -108,7 +108,7 @@ export const SocialButtonsGroup = memo(
{elements}
{length > 2 && (
<SocialButton
iconName={VerticalDotsReactSvgUrl}
IconComponent={VerticalDotsReactSvg}
onClick={moreAuthOpen}
className="show-more-button"
/>

View File

@ -24,13 +24,13 @@
// 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 ShareAppleReactSvgUrl from "PUBLIC_DIR/images/share.apple.react.svg?url";
import ShareGoogleReactSvgUrl from "PUBLIC_DIR/images/share.google.react.svg?url";
import ShareFacebookReactSvgUrl from "PUBLIC_DIR/images/share.facebook.react.svg?url";
import ShareTwitterReactSvgUrl from "PUBLIC_DIR/images/share.twitter.react.svg?url";
import ShareLinkedinReactSvgUrl from "PUBLIC_DIR/images/share.linkedin.react.svg?url";
import ShareMicrosoftReactSvgUrl from "PUBLIC_DIR/images/share.microsoft.react.svg?url";
import ShareZoomReactSvgUrl from "PUBLIC_DIR/images/share.zoom.react.svg?url";
import ShareAppleReactSvg from "PUBLIC_DIR/images/share.apple.react.svg";
import ShareGoogleReactSvg from "PUBLIC_DIR/images/share.google.react.svg";
import ShareFacebookReactSvg from "PUBLIC_DIR/images/share.facebook.react.svg";
import ShareTwitterReactSvg from "PUBLIC_DIR/images/share.twitter.react.svg";
import ShareLinkedinReactSvg from "PUBLIC_DIR/images/share.linkedin.react.svg";
import ShareMicrosoftReactSvg from "PUBLIC_DIR/images/share.microsoft.react.svg";
import ShareZoomReactSvg from "PUBLIC_DIR/images/share.zoom.react.svg";
export const LOADER_STYLE = Object.freeze({
title: "",
@ -100,37 +100,37 @@ export const FOLDER_NAMES = Object.freeze({
export const PROVIDERS_DATA = Object.freeze({
appleid: {
label: "apple",
icon: ShareAppleReactSvgUrl,
icon: ShareAppleReactSvg,
iconOptions: undefined,
},
google: {
label: "google",
icon: ShareGoogleReactSvgUrl,
icon: ShareGoogleReactSvg,
iconOptions: undefined,
},
facebook: {
label: "facebook",
icon: ShareFacebookReactSvgUrl,
icon: ShareFacebookReactSvg,
iconOptions: undefined,
},
twitter: {
label: "twitter",
icon: ShareTwitterReactSvgUrl,
icon: ShareTwitterReactSvg,
iconOptions: { color: "#2AA3EF" },
},
linkedin: {
label: "linkedin",
icon: ShareLinkedinReactSvgUrl,
icon: ShareLinkedinReactSvg,
iconOptions: undefined,
},
microsoft: {
label: "microsoft",
icon: ShareMicrosoftReactSvgUrl,
icon: ShareMicrosoftReactSvg,
iconOptions: undefined,
},
zoom: {
label: "zoom",
icon: ShareZoomReactSvgUrl,
icon: ShareZoomReactSvg,
iconOptions: undefined,
},
});