Web: Files: EditLinkPanel: added password settings
This commit is contained in:
parent
153bae389c
commit
c3e7777667
@ -24,6 +24,7 @@
|
|||||||
// content are licensed under the terms of the Creative Commons Attribution-ShareAlike 4.0
|
// 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
|
// International. See the License terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
|
||||||
|
|
||||||
|
import { useRef } from "react";
|
||||||
import ToggleBlock from "./ToggleBlock";
|
import ToggleBlock from "./ToggleBlock";
|
||||||
import { IconButton } from "@docspace/shared/components/icon-button";
|
import { IconButton } from "@docspace/shared/components/icon-button";
|
||||||
import { Link } from "@docspace/shared/components/link";
|
import { Link } from "@docspace/shared/components/link";
|
||||||
@ -31,8 +32,8 @@ import RefreshReactSvgUrl from "PUBLIC_DIR/images/refresh.react.svg?url";
|
|||||||
import { FieldContainer } from "@docspace/shared/components/field-container";
|
import { FieldContainer } from "@docspace/shared/components/field-container";
|
||||||
import copy from "copy-to-clipboard";
|
import copy from "copy-to-clipboard";
|
||||||
import { toastr } from "@docspace/shared/components/toast";
|
import { toastr } from "@docspace/shared/components/toast";
|
||||||
import SimulatePassword from "../../../components/SimulatePassword";
|
import { ALLOWED_PASSWORD_CHARACTERS } from "@docspace/shared/constants";
|
||||||
import { getNewPassword } from "@docspace/shared/utils";
|
import { PasswordInput } from "@docspace/shared/components/password-input";
|
||||||
|
|
||||||
const PasswordAccessBlock = (props) => {
|
const PasswordAccessBlock = (props) => {
|
||||||
const {
|
const {
|
||||||
@ -43,15 +44,21 @@ const PasswordAccessBlock = (props) => {
|
|||||||
setPasswordValue,
|
setPasswordValue,
|
||||||
isPasswordValid,
|
isPasswordValid,
|
||||||
setIsPasswordValid,
|
setIsPasswordValid,
|
||||||
|
passwordSettings,
|
||||||
|
isPasswordErrorShow,
|
||||||
|
setIsPasswordErrorShow,
|
||||||
} = props;
|
} = props;
|
||||||
|
|
||||||
|
const passwordInputRef = useRef(null);
|
||||||
|
|
||||||
const onGeneratePasswordClick = () => {
|
const onGeneratePasswordClick = () => {
|
||||||
const password = getNewPassword();
|
passwordInputRef.current.onGeneratePassword();
|
||||||
setPasswordValue(password);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const onCleanClick = () => {
|
const onCleanClick = (e) => {
|
||||||
|
e.stopPropagation();
|
||||||
setPasswordValue("");
|
setPasswordValue("");
|
||||||
|
setIsPasswordValid(false);
|
||||||
};
|
};
|
||||||
|
|
||||||
const onCopyClick = () => {
|
const onCopyClick = () => {
|
||||||
@ -62,9 +69,36 @@ const PasswordAccessBlock = (props) => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const onChangePassword = (password) => {
|
const onChangePassword = (e, value) => {
|
||||||
setPasswordValue(password);
|
setPasswordValue(value);
|
||||||
setIsPasswordValid(true);
|
setIsPasswordValid(true);
|
||||||
|
setIsPasswordErrorShow(false);
|
||||||
|
};
|
||||||
|
|
||||||
|
// const onBlurPassword = () => {
|
||||||
|
// setIsPasswordErrorShow(true);
|
||||||
|
// };
|
||||||
|
|
||||||
|
const onValidatePassword = (isValidate) => {
|
||||||
|
setIsPasswordValid(isValidate);
|
||||||
|
};
|
||||||
|
|
||||||
|
const errorMessage = !passwordValue
|
||||||
|
? t("Common:RequiredField")
|
||||||
|
: t("Common:IncorrectPassword");
|
||||||
|
|
||||||
|
const hasError = isPasswordErrorShow && !isPasswordValid;
|
||||||
|
|
||||||
|
const tooltipData = {
|
||||||
|
tooltipPasswordTitle: `${t("Common:PasswordLimitMessage")}:`,
|
||||||
|
tooltipPasswordLength: `${t("Common:PasswordMinimumLength")}: ${
|
||||||
|
passwordSettings ? passwordSettings.minLength : 8
|
||||||
|
}`,
|
||||||
|
tooltipPasswordDigits: `${t("Common:PasswordLimitDigits")}`,
|
||||||
|
tooltipPasswordCapital: `${t("Common:PasswordLimitUpperCase")}`,
|
||||||
|
tooltipPasswordSpecial: `${t("Common:PasswordLimitSpecialSymbols")}`,
|
||||||
|
generatePasswordTitle: t("Wizard:GeneratePassword"),
|
||||||
|
tooltipAllowedCharacters: `${t("Common:AllowedCharacters")}: ${ALLOWED_PASSWORD_CHARACTERS}`,
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@ -74,17 +108,26 @@ const PasswordAccessBlock = (props) => {
|
|||||||
<div className="edit-link_password-block">
|
<div className="edit-link_password-block">
|
||||||
<FieldContainer
|
<FieldContainer
|
||||||
isVertical
|
isVertical
|
||||||
hasError={!isPasswordValid}
|
hasError={hasError}
|
||||||
errorMessage={t("Common:RequiredField")}
|
errorMessage={errorMessage}
|
||||||
className="edit-link_password-block"
|
className="edit-link_password-block"
|
||||||
>
|
>
|
||||||
<SimulatePassword
|
<PasswordInput
|
||||||
|
id="conversion-password"
|
||||||
className="edit-link_password-input"
|
className="edit-link_password-input"
|
||||||
|
ref={passwordInputRef}
|
||||||
isDisabled={isLoading}
|
isDisabled={isLoading}
|
||||||
hasError={!isPasswordValid}
|
|
||||||
inputValue={passwordValue}
|
inputValue={passwordValue}
|
||||||
onChange={onChangePassword}
|
onChange={onChangePassword}
|
||||||
inputMaxWidth="100%"
|
passwordSettings={passwordSettings}
|
||||||
|
simpleView={false}
|
||||||
|
placeholder={t("Common:Password")}
|
||||||
|
hasError={hasError}
|
||||||
|
// onBlur={onBlurPassword}
|
||||||
|
onValidateInput={onValidatePassword}
|
||||||
|
isSimulateType
|
||||||
|
simulateSymbol="•"
|
||||||
|
{...tooltipData}
|
||||||
/>
|
/>
|
||||||
</FieldContainer>
|
</FieldContainer>
|
||||||
|
|
||||||
|
@ -65,6 +65,8 @@ const EditLinkPanel = (props) => {
|
|||||||
isFormRoom,
|
isFormRoom,
|
||||||
currentDeviceType,
|
currentDeviceType,
|
||||||
setLinkParams,
|
setLinkParams,
|
||||||
|
passwordSettings,
|
||||||
|
getPortalPasswordSettings,
|
||||||
} = props;
|
} = props;
|
||||||
|
|
||||||
const [isLoading, setIsLoading] = useState(false);
|
const [isLoading, setIsLoading] = useState(false);
|
||||||
@ -80,6 +82,7 @@ const EditLinkPanel = (props) => {
|
|||||||
const [isExpired, setIsExpired] = useState(isExpiredDate);
|
const [isExpired, setIsExpired] = useState(isExpiredDate);
|
||||||
|
|
||||||
const [isPasswordValid, setIsPasswordValid] = useState(true);
|
const [isPasswordValid, setIsPasswordValid] = useState(true);
|
||||||
|
const [isPasswordErrorShow, setIsPasswordErrorShow] = useState(false);
|
||||||
|
|
||||||
const [linkValue, setLinkValue] = useState(shareLink);
|
const [linkValue, setLinkValue] = useState(shareLink);
|
||||||
const [hasChanges, setHasChanges] = useState(false);
|
const [hasChanges, setHasChanges] = useState(false);
|
||||||
@ -101,10 +104,12 @@ const EditLinkPanel = (props) => {
|
|||||||
|
|
||||||
const onClose = () => setIsVisible(false);
|
const onClose = () => setIsVisible(false);
|
||||||
const onSave = () => {
|
const onSave = () => {
|
||||||
const isPasswordValid = !!passwordValue.trim();
|
if (
|
||||||
|
(!passwordValue.trim() || !isPasswordValid) &&
|
||||||
if (!isPasswordValid && passwordAccessIsChecked) {
|
passwordAccessIsChecked
|
||||||
|
) {
|
||||||
setIsPasswordValid(false);
|
setIsPasswordValid(false);
|
||||||
|
setIsPasswordErrorShow(true);
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -140,11 +145,14 @@ const EditLinkPanel = (props) => {
|
|||||||
|
|
||||||
toastr.success(t("Files:LinkSuccessfullyCreatedAndCopied"));
|
toastr.success(t("Files:LinkSuccessfullyCreatedAndCopied"));
|
||||||
}
|
}
|
||||||
|
onClose();
|
||||||
|
})
|
||||||
|
.catch((err) => {
|
||||||
|
const error = err?.response?.data?.error?.message ?? err?.message;
|
||||||
|
toastr.error(error);
|
||||||
})
|
})
|
||||||
.catch((err) => toastr.error(err?.message))
|
|
||||||
.finally(() => {
|
.finally(() => {
|
||||||
setIsLoading(false);
|
setIsLoading(false);
|
||||||
onClose();
|
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -183,6 +191,18 @@ const EditLinkPanel = (props) => {
|
|||||||
return () => window.removeEventListener("keydown", onKeyPress);
|
return () => window.removeEventListener("keydown", onKeyPress);
|
||||||
}, [onKeyPress]);
|
}, [onKeyPress]);
|
||||||
|
|
||||||
|
const getPasswordSettings = async () => {
|
||||||
|
setIsLoading(true);
|
||||||
|
await getPortalPasswordSettings();
|
||||||
|
setIsLoading(false);
|
||||||
|
};
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (!passwordSettings) {
|
||||||
|
getPasswordSettings();
|
||||||
|
}
|
||||||
|
}, [passwordSettings]);
|
||||||
|
|
||||||
const linkNameIsValid = !!linkNameValue.trim();
|
const linkNameIsValid = !!linkNameValue.trim();
|
||||||
|
|
||||||
const expiredLinkText = isExpired
|
const expiredLinkText = isExpired
|
||||||
@ -239,6 +259,9 @@ const EditLinkPanel = (props) => {
|
|||||||
setPasswordValue={setPasswordValue}
|
setPasswordValue={setPasswordValue}
|
||||||
setIsPasswordValid={setIsPasswordValid}
|
setIsPasswordValid={setIsPasswordValid}
|
||||||
onChange={onPasswordAccessChange}
|
onChange={onPasswordAccessChange}
|
||||||
|
passwordSettings={passwordSettings}
|
||||||
|
isPasswordErrorShow={isPasswordErrorShow}
|
||||||
|
setIsPasswordErrorShow={setIsPasswordErrorShow}
|
||||||
/>
|
/>
|
||||||
{!isFormRoom && (
|
{!isFormRoom && (
|
||||||
<ToggleBlock
|
<ToggleBlock
|
||||||
@ -313,11 +336,13 @@ export default inject(
|
|||||||
} = dialogsStore;
|
} = dialogsStore;
|
||||||
const { externalLinks, editExternalLink, setExternalLink } =
|
const { externalLinks, editExternalLink, setExternalLink } =
|
||||||
publicRoomStore;
|
publicRoomStore;
|
||||||
|
const { currentDeviceType, passwordSettings, getPortalPasswordSettings } =
|
||||||
|
settingsStore;
|
||||||
|
|
||||||
const { isEdit, roomId, isPublic, isFormRoom } = linkParams;
|
const { isEdit, roomId, isPublic, isFormRoom } = linkParams;
|
||||||
|
|
||||||
const linkId = linkParams?.link?.sharedTo?.id;
|
const linkId = linkParams?.link?.sharedTo?.id;
|
||||||
const link = externalLinks.find((l) => l?.sharedTo?.id === linkId);
|
const link = externalLinks.find((l) => l?.sharedTo?.id === linkId);
|
||||||
|
|
||||||
const shareLink = link?.sharedTo?.shareLink;
|
const shareLink = link?.sharedTo?.shareLink;
|
||||||
|
|
||||||
return {
|
return {
|
||||||
@ -340,10 +365,14 @@ export default inject(
|
|||||||
language: authStore.language,
|
language: authStore.language,
|
||||||
isPublic,
|
isPublic,
|
||||||
isFormRoom,
|
isFormRoom,
|
||||||
currentDeviceType: settingsStore.currentDeviceType,
|
currentDeviceType,
|
||||||
setLinkParams,
|
setLinkParams,
|
||||||
|
passwordSettings,
|
||||||
|
getPortalPasswordSettings,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
)(
|
)(
|
||||||
withTranslation(["SharingPanel", "Common", "Files"])(observer(EditLinkPanel)),
|
withTranslation(["SharingPanel", "Common", "Files", "Wizard"])(
|
||||||
|
observer(EditLinkPanel),
|
||||||
|
),
|
||||||
);
|
);
|
||||||
|
@ -32,6 +32,7 @@ import React, {
|
|||||||
ChangeEvent,
|
ChangeEvent,
|
||||||
FocusEvent,
|
FocusEvent,
|
||||||
MouseEvent,
|
MouseEvent,
|
||||||
|
useEffect,
|
||||||
} from "react";
|
} from "react";
|
||||||
import { TooltipRefProps } from "react-tooltip";
|
import { TooltipRefProps } from "react-tooltip";
|
||||||
|
|
||||||
@ -109,6 +110,16 @@ const PasswordInput = React.forwardRef(
|
|||||||
}: PasswordInputProps,
|
}: PasswordInputProps,
|
||||||
ref,
|
ref,
|
||||||
) => {
|
) => {
|
||||||
|
const usePrevious = (value: string) => {
|
||||||
|
const inputValueRef = useRef<string>();
|
||||||
|
useEffect(() => {
|
||||||
|
inputValueRef.current = value;
|
||||||
|
});
|
||||||
|
return inputValueRef.current;
|
||||||
|
};
|
||||||
|
|
||||||
|
const prevInputValue = usePrevious(inputValue ?? "");
|
||||||
|
|
||||||
const [state, setState] = useState({
|
const [state, setState] = useState({
|
||||||
type: inputType,
|
type: inputType,
|
||||||
value: inputValue,
|
value: inputValue,
|
||||||
@ -276,6 +287,8 @@ const PasswordInput = React.forwardRef(
|
|||||||
(newPassword: string) => {
|
(newPassword: string) => {
|
||||||
let newValue;
|
let newValue;
|
||||||
|
|
||||||
|
if (!state.value) return newPassword;
|
||||||
|
|
||||||
const oldPassword = state.value ?? "";
|
const oldPassword = state.value ?? "";
|
||||||
const oldPasswordLength = oldPassword.length;
|
const oldPasswordLength = oldPassword.length;
|
||||||
const newCaretPosition = document.getElementById(
|
const newCaretPosition = document.getElementById(
|
||||||
@ -465,6 +478,14 @@ const PasswordInput = React.forwardRef(
|
|||||||
}
|
}
|
||||||
}, [caretPosition, state.type, state.value, isSimulateType]);
|
}, [caretPosition, state.type, state.value, isSimulateType]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (inputValue !== prevInputValue) {
|
||||||
|
onChangeAction?.({
|
||||||
|
target: { value: inputValue },
|
||||||
|
} as ChangeEvent<HTMLInputElement>);
|
||||||
|
}
|
||||||
|
}, [inputValue, prevInputValue, onChangeAction]);
|
||||||
|
|
||||||
React.useImperativeHandle(
|
React.useImperativeHandle(
|
||||||
ref,
|
ref,
|
||||||
() => {
|
() => {
|
||||||
|
Loading…
Reference in New Issue
Block a user