Merge branch 'develop' into bugfix/rc-2.5.0

This commit is contained in:
Alexey Safronov 2024-03-04 14:44:21 +04:00
commit 8e05353ea4
9 changed files with 126 additions and 85 deletions

View File

@ -199,6 +199,7 @@
"SuccessfullySaveGreetingSettingsMessage": "Welcome Page settings have been successfully saved",
"SuccessfullySavePortalNameMessage": "Space has been renamed successfully",
"SuccessfullySaveSettingsMessage": "Settings have been successfully updated",
"DNSSettingsHint": "Enter domain name like this:",
"TemporaryStorage": "Temporary storage",
"TemporaryStorageDescription": "Backup is stored in the 'Backup' section, you will be able to download it within 24 hours after creating.",
"ThirdPartyAuthorization": "Third-party Authorization",

View File

@ -183,6 +183,7 @@
"SuccessfullySaveGreetingSettingsMessage": "Настройки страницы приветствия успешно сохранены",
"SuccessfullySavePortalNameMessage": "Портал успешно переименован",
"SuccessfullySaveSettingsMessage": "Настройки успешно обновлены",
"DNSSettingsHint": "Введите доменное имя следующим образом:",
"TemporaryStorage": "Временное хранилище",
"TemporaryStorageDescription": "Резервная копия будет храниться в разделе 'Резервное копирование', вы сможете скачать её в течение 24 часов с момента создания.",
"ThirdPartyAuthorization": "Сторонние сервисы",

View File

@ -20,7 +20,7 @@ import { ToggleButton } from "@docspace/shared/components/toggle-button";
import { Text } from "@docspace/shared/components/text";
import { Link } from "@docspace/shared/components/link";
import { DeviceType } from "@docspace/shared/enums";
import { validatePortalName } from "@docspace/shared/utils/common";
import { parseDomain } from "@docspace/shared/utils/common";
const toggleStyle = {
position: "static",
@ -61,7 +61,7 @@ const DNSSettings = (props) => {
isDefaultDNS,
dnsSettingsUrl,
currentDeviceType,
domainValidator,
portalName,
} = props;
const [hasScroll, setHasScroll] = useState(false);
const isLoadedSetting = isLoaded && tReady;
@ -110,19 +110,8 @@ const DNSSettings = (props) => {
setIsLoading(true);
}, [200]);
const isValidPortalName = validatePortalName(
dnsName || "",
domainValidator,
setErrorText,
t,
);
if (isValidPortalName) {
await saveDNSSettings();
toastr.success(t("Settings:SuccessfullySaveSettingsMessage"));
} else {
setIsError(true);
}
await saveDNSSettings();
toastr.success(t("Settings:SuccessfullySaveSettingsMessage"));
} catch (e) {
setIsError(true);
toastr.error(e);
@ -131,6 +120,8 @@ const DNSSettings = (props) => {
clearTimeout(timerId);
timerId = null;
setIsLoading(false);
setIsError(false);
};
const onClickToggle = (e) => {
const checked = e.currentTarget.checked;
@ -138,10 +129,18 @@ const DNSSettings = (props) => {
};
const onChangeTextInput = (e) => {
const { value } = e.target;
isError && setIsError(false);
errorText && setErrorText("");
setDNSName(value);
setErrorText("");
const { value } = e.target;
const dns = portalName ? value.slice(portalName.length + 1) : value;
const isValidDomain = parseDomain(dns || "", setErrorText, t);
if (!isValidDomain) {
setIsError(true);
}
setDNSName(dns);
};
const checkInnerWidth = useCallback(() => {
if (!isMobile()) {
@ -162,6 +161,8 @@ const DNSSettings = (props) => {
}
}, [isMobile, setIsCustomizationView]);
const domainExampleText = " team.ourcompany.com";
const settingsBlock = (
<div className="settings-block">
{standalone ? (
@ -177,13 +178,33 @@ const DNSSettings = (props) => {
<TextInput
{...textInputProps}
isDisabled={isLoading || !enable}
value={dnsName?.trim()}
value={
portalName ? `${portalName}.${dnsName?.trim()}` : dnsName?.trim()
}
onChange={onChangeTextInput}
hasError={isError}
/>
<div style={{ marginTop: "5px" }}>
<Text fontSize="12px" fontWeight="400" color="#F24724">
{errorText}
{errorText &&
errorText.map((err, index) => (
<Text
key={index}
fontSize="12px"
fontWeight="400"
color="#F24724"
>
{err}
</Text>
))}
</div>
<div style={{ marginTop: "3px" }}>
<Text
key="dns-hint"
fontSize="12px"
fontWeight="400"
color="#A3A9AE"
>
{`${t("Settings:DNSSettingsHint")}${domainExampleText}`}
</Text>
</div>
</>
@ -215,7 +236,7 @@ const DNSSettings = (props) => {
size={currentDeviceType === DeviceType.desktop ? "small" : "normal"}
label={t("Common:SaveButton")}
onClick={onSaveSettings}
isDisabled={isLoading || isDefaultDNS}
isDisabled={isLoading || isDefaultDNS || isError}
isLoading={isLoading}
/>
) : (
@ -224,7 +245,7 @@ const DNSSettings = (props) => {
size={currentDeviceType === DeviceType.desktop ? "small" : "normal"}
label={t("Common:SendRequest")}
onClick={onSendRequest}
isDisabled={!isSettingPaid}
isDisabled={!isSettingPaid || isError}
/>
);
@ -278,7 +299,6 @@ export default inject(({ settingsStore, common, currentQuotaStore }) => {
standalone,
dnsSettingsUrl,
currentDeviceType,
domainValidator,
} = settingsStore;
const {
isLoaded,
@ -290,6 +310,7 @@ export default inject(({ settingsStore, common, currentQuotaStore }) => {
setDNSName,
saveDNSSettings,
isDefaultDNS,
portalName,
} = common;
const { isBrandingAndCustomizationAvailable } = currentQuotaStore;
@ -313,6 +334,6 @@ export default inject(({ settingsStore, common, currentQuotaStore }) => {
saveDNSSettings,
dnsSettingsUrl,
currentDeviceType,
domainValidator,
portalName,
};
})(withLoading(withTranslation(["Settings", "Common"])(observer(DNSSettings))));

View File

@ -33,6 +33,8 @@ const PortalRenaming = (props) => {
currentColorScheme,
renamingSettingsUrl,
domainValidator,
setPortalName,
portalName,
} = props;
const navigate = useNavigate();
@ -54,10 +56,8 @@ const PortalRenaming = (props) => {
? tenantAlias
: portalNameDefaultFromSessionStorage;
const [portalName, setPortalName] = useState(portalNameInitially);
const [portalNameDefault, setPortalNameDefault] = useState(
portalNameDefaultInitially
portalNameDefaultInitially,
);
const [isLoadingPortalNameSave, setIsLoadingPortalNameSave] = useState(false);
@ -78,6 +78,7 @@ const PortalRenaming = (props) => {
useEffect(() => {
setDocumentTitle(t("PortalRenaming"));
setPortalName(portalNameInitially);
const page = isMobileView ? "language-and-time-zone" : "general";
if (!isLoaded) initSettings(page).then(() => setIsLoaded(true));
@ -193,14 +194,14 @@ const PortalRenaming = (props) => {
t("PortalNameLength", {
minLength: domainValidator.minLength,
maxLength: domainValidator.maxLength,
})
}),
);
saveToSessionStorage(
"errorValue",
t("PortalNameLength", {
minLength: domainValidator.minLength,
maxLength: domainValidator.maxLength,
})
}),
);
break;
case !validDomain.test(value):
@ -242,7 +243,7 @@ const PortalRenaming = (props) => {
const currentUrl = window.location.href.replace(
window.location.origin,
""
"",
);
const newUrl = "/portal-settings/customization/general";
@ -353,8 +354,14 @@ export default inject(({ settingsStore, setup, common }) => {
domainValidator,
} = settingsStore;
const { setPortalRename } = setup;
const { isLoaded, setIsLoadedPortalRenaming, initSettings, setIsLoaded } =
common;
const {
isLoaded,
setIsLoadedPortalRenaming,
initSettings,
setIsLoaded,
setPortalName,
portalName,
} = common;
return {
theme,
@ -368,7 +375,11 @@ export default inject(({ settingsStore, setup, common }) => {
currentColorScheme,
renamingSettingsUrl,
domainValidator,
portalName,
setPortalName,
};
})(
withLoading(withTranslation(["Settings", "Common"])(observer(PortalRenaming)))
withLoading(
withTranslation(["Settings", "Common"])(observer(PortalRenaming)),
),
);

View File

@ -13,6 +13,7 @@ class CommonStore {
whiteLabelLogoText = null;
defaultLogoTextWhiteLabel = null;
portalName = null;
dnsSettings = {
defaultObj: {},
customObj: {},
@ -63,14 +64,14 @@ class CommonStore {
requests.push(
this.getWhiteLabelLogoUrls(),
this.getWhiteLabelLogoText(),
this.getIsDefaultWhiteLabel()
this.getIsDefaultWhiteLabel(),
);
break;
}
case "language-and-time-zone":
requests.push(
this.settingsStore.getPortalTimezones(),
this.settingsStore.getPortalCultures()
this.settingsStore.getPortalCultures(),
);
break;
case "dns-settings":
@ -88,7 +89,7 @@ class CommonStore {
{
requests.push(
this.settingsStore.getPortalTimezones(),
this.settingsStore.getPortalCultures()
this.settingsStore.getPortalCultures(),
);
if (standalone) {
@ -100,7 +101,7 @@ class CommonStore {
requests.push(
this.getWhiteLabelLogoUrls(),
this.getWhiteLabelLogoText(),
this.getIsDefaultWhiteLabel()
this.getIsDefaultWhiteLabel(),
);
break;
@ -123,7 +124,7 @@ class CommonStore {
setWhiteLabelSettings = async (data) => {
const response = await api.settings.setWhiteLabelSettings(
data,
isManagement()
isManagement(),
);
return Promise.resolve(response);
};
@ -187,6 +188,10 @@ class CommonStore {
this.dnsSettings.customObj.dnsName = value;
};
setPortalName = (value) => {
this.portalName = value;
};
setDNSSettings = (data) => {
this.dnsSettings = { defaultObj: data, customObj: data };
};

View File

@ -5,11 +5,10 @@ import { TextInput } from "@docspace/shared/components/text-input";
import { Text } from "@docspace/shared/components/text";
import { ConfigurationWrapper } from "../StyledSpaces";
import { useStore } from "SRC_DIR/store";
import { parseDomain } from "SRC_DIR/utils";
import { isMobile } from "react-device-detect";
import { toastr } from "@docspace/shared/components/toast";
import { TranslationType } from "SRC_DIR/types/spaces";
import { validatePortalName } from "@docspace/shared/utils/common";
import { parseDomain, validatePortalName } from "@docspace/shared/utils/common";
type TConfigurationSection = {
t: TranslationType;

View File

@ -8,8 +8,8 @@ import { useTranslation } from "react-i18next";
import { observer } from "mobx-react";
import { TextInput } from "@docspace/shared/components/text-input";
import { useStore } from "SRC_DIR/store";
import { parseDomain } from "SRC_DIR/utils";
import { toastr } from "@docspace/shared/components/toast";
import { parseDomain } from "@docspace/shared/utils/common";
const StyledModal = styled(ModalDialogContainer)`
.create-docspace-input-block {

View File

@ -1,8 +1,5 @@
import { settingsTree } from "./settingsTree";
import { translations } from "../autoGeneratedTranslations";
import { parseAddress } from "@docspace/shared/utils";
import { ErrorKeys } from "@docspace/shared/enums";
import { TranslationType } from "SRC_DIR/types/spaces";
export const getItemByLink = (path: string) => {
const resultPath = path.split("/")[1];
@ -63,41 +60,3 @@ export function loadLanguagePath(homepage: string, fixedNS = null) {
return path;
};
}
export const parseDomain = (
domain: string,
setError: Function,
t: TranslationType
) => {
let parsedDomain = parseAddress("test@" + domain);
if (parsedDomain?.parseErrors.length > 0) {
const translatedErrors = parsedDomain.parseErrors.map((error) => {
switch (error.errorKey) {
case ErrorKeys.LocalDomain:
return t("Common:LocalDomain");
case ErrorKeys.IncorrectDomain:
case ErrorKeys.IncorrectEmail:
return t("Common:IncorrectDomain");
case ErrorKeys.DomainIpAddress:
return t("Common:DomainIpAddress");
case ErrorKeys.PunycodeDomain:
return t("Common:PunycodeDomain");
case ErrorKeys.PunycodeLocalPart:
return t("Common:PunycodeLocalPart");
case ErrorKeys.IncorrectLocalPart:
return t("Common:IncorrectLocalPart");
case ErrorKeys.SpacesInLocalPart:
return t("Common:SpacesInLocalPart");
case ErrorKeys.MaxLengthExceeded:
return t("Common:MaxLengthExceeded");
default:
throw new Error("Unknown translation key");
}
});
setError(translatedErrors);
}
return parsedDomain.isValid();
};

View File

@ -23,8 +23,14 @@ import BackgroundPatternRedReactSvgUrl from "PUBLIC_DIR/images/background.patter
import BackgroundPatternPurpleReactSvgUrl from "PUBLIC_DIR/images/background.pattern.purple.react.svg?url";
import BackgroundPatternLightBlueReactSvgUrl from "PUBLIC_DIR/images/background.pattern.lightBlue.react.svg?url";
import BackgroundPatternBlackReactSvgUrl from "PUBLIC_DIR/images/background.pattern.black.react.svg?url";
import { FolderType, RoomsType, ShareAccessRights, ThemeKeys } from "../enums";
import { parseAddress } from "@docspace/shared/utils";
import {
FolderType,
RoomsType,
ShareAccessRights,
ThemeKeys,
ErrorKeys,
} from "../enums";
import { LANGUAGE, RTL_LANGUAGES } from "../constants";
import { TI18n } from "../types";
@ -106,6 +112,44 @@ export const getUserTypeLabel = (
}
};
export const parseDomain = (
domain: string,
setError: Function,
t: (key: string) => string,
) => {
const parsedDomain = parseAddress("test@" + domain);
if (parsedDomain?.parseErrors.length > 0) {
const translatedErrors = parsedDomain.parseErrors.map((error) => {
switch (error.errorKey) {
case ErrorKeys.LocalDomain:
return t("Common:LocalDomain");
case ErrorKeys.IncorrectDomain:
case ErrorKeys.IncorrectEmail:
return t("Common:IncorrectDomain");
case ErrorKeys.DomainIpAddress:
return t("Common:DomainIpAddress");
case ErrorKeys.PunycodeDomain:
return t("Common:PunycodeDomain");
case ErrorKeys.PunycodeLocalPart:
return t("Common:PunycodeLocalPart");
case ErrorKeys.IncorrectLocalPart:
return t("Common:IncorrectLocalPart");
case ErrorKeys.SpacesInLocalPart:
return t("Common:SpacesInLocalPart");
case ErrorKeys.MaxLengthExceeded:
return t("Common:MaxLengthExceeded");
default:
return t("Common:IncorrectDomain");
}
});
setError(translatedErrors);
}
return parsedDomain.isValid();
};
export const validatePortalName = (
value: string,
nameValidator: { minLength: number; maxLength: number; regex: RegExp },