Client:OAuth2: enable save button and throw error after click
This commit is contained in:
parent
06da361ba3
commit
fbd5335167
@ -63,6 +63,7 @@
|
||||
"TermsOfService": "Terms of Service",
|
||||
"TermsOfServiceURL": "Terms of Service URL",
|
||||
"TermsOfServiceURLHelpButton": "Terms and conditions that users must comply with when using this application.",
|
||||
"ThisRequiredField": "This is a required field",
|
||||
"WebsiteUrl": "Website URL",
|
||||
"Write": "Write"
|
||||
}
|
||||
|
@ -34,6 +34,10 @@ const StyledBlock = styled.div`
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 12px;
|
||||
|
||||
.icon-field {
|
||||
margin: 0;
|
||||
}
|
||||
`;
|
||||
|
||||
const StyledHeaderRow = styled.div`
|
||||
|
@ -1,8 +1,10 @@
|
||||
import React from "react";
|
||||
import { Trans } from "react-i18next";
|
||||
|
||||
//@ts-ignore
|
||||
// @ts-ignore
|
||||
import HelpButton from "@docspace/components/help-button";
|
||||
// @ts-ignore
|
||||
import FieldContainer from "@docspace/components/field-container";
|
||||
|
||||
import { StyledBlock, StyledInputBlock } from "../ClientForm.styled";
|
||||
|
||||
@ -26,6 +28,7 @@ interface BasicBlockProps {
|
||||
|
||||
isEdit: boolean;
|
||||
errorFields: string[];
|
||||
requiredErrorFields: string[];
|
||||
onBlur: (name: string) => void;
|
||||
}
|
||||
|
||||
@ -75,6 +78,7 @@ const BasicBlock = ({
|
||||
|
||||
isEdit,
|
||||
errorFields,
|
||||
requiredErrorFields,
|
||||
onBlur,
|
||||
}: BasicBlockProps) => {
|
||||
const onChange = (e: React.ChangeEvent<HTMLInputElement>) => {
|
||||
@ -133,6 +137,12 @@ const BasicBlock = ({
|
||||
<Trans t={t} i18nKey="AllowPKCEHelpButton" ns="OAuth" />
|
||||
);
|
||||
|
||||
const isNameRequiredError = requiredErrorFields.includes("name");
|
||||
const isWebsiteRequiredError = requiredErrorFields.includes("website_url");
|
||||
const isNameError = errorFields.includes("name");
|
||||
const isWebsiteError = errorFields.includes("website_url");
|
||||
const isLogoRequiredError = requiredErrorFields.includes("logo");
|
||||
|
||||
return (
|
||||
<StyledBlock>
|
||||
<BlockHeader header={"Basic info"} />
|
||||
@ -142,10 +152,10 @@ const BasicBlock = ({
|
||||
name={"name"}
|
||||
placeholder={t("Common:EnterName")}
|
||||
value={nameValue}
|
||||
error={`${t("ErrorName")} 3`}
|
||||
error={isNameError ? `${t("ErrorName")} 3` : t("ThisRequiredField")}
|
||||
onChange={onChange}
|
||||
isRequired
|
||||
isError={errorFields.includes("name")}
|
||||
isError={isNameRequiredError || isNameError}
|
||||
onBlur={onBlur}
|
||||
/>
|
||||
<InputGroup
|
||||
@ -153,26 +163,40 @@ const BasicBlock = ({
|
||||
name={"website_url"}
|
||||
placeholder={t("EnterURL")}
|
||||
value={websiteUrlValue}
|
||||
error={`${t("ErrorWrongURL")}: ${window.location.origin}`}
|
||||
error={
|
||||
isWebsiteError
|
||||
? `${t("ErrorWrongURL")}: ${window.location.origin}`
|
||||
: t("ThisRequiredField")
|
||||
}
|
||||
onChange={onChange}
|
||||
disabled={isEdit}
|
||||
isRequired
|
||||
isError={errorFields.includes("website_url")}
|
||||
isError={isWebsiteRequiredError || isWebsiteError}
|
||||
onBlur={onBlur}
|
||||
/>
|
||||
<SelectGroup
|
||||
label={t("AppIcon")}
|
||||
value={logoValue}
|
||||
selectLabel={t("SelectNewImage")}
|
||||
description={t("IconDescription")}
|
||||
onSelect={onSelect}
|
||||
/>
|
||||
<FieldContainer
|
||||
isVertical
|
||||
labelVisible={false}
|
||||
errorMessage={t("ThisRequiredField")}
|
||||
hasError={isLogoRequiredError}
|
||||
className="icon-field"
|
||||
>
|
||||
<SelectGroup
|
||||
label={t("AppIcon")}
|
||||
value={logoValue}
|
||||
selectLabel={t("SelectNewImage")}
|
||||
description={t("IconDescription")}
|
||||
onSelect={onSelect}
|
||||
/>
|
||||
</FieldContainer>
|
||||
|
||||
<TextAreaGroup
|
||||
label={t("Common:Description")}
|
||||
name={"description"}
|
||||
placeholder={t("EnterDescription")}
|
||||
value={descriptionValue}
|
||||
onChange={onChange}
|
||||
increaseHeight={isLogoRequiredError}
|
||||
/>
|
||||
<InputGroup
|
||||
label={t("AuthenticationMethod")}
|
||||
|
@ -114,6 +114,7 @@ const InputGroup = ({
|
||||
onIconClick={withCopy && onCopyClick}
|
||||
type={isPassword ? "password" : "text"}
|
||||
onBlur={() => onBlur?.(name)}
|
||||
hasError={isError}
|
||||
/>
|
||||
)}
|
||||
{buttonLabel && (
|
||||
|
@ -24,7 +24,7 @@ interface MultiInputGroupProps {
|
||||
name: string;
|
||||
placeholder: string;
|
||||
currentValue: string[];
|
||||
|
||||
hasError?: boolean;
|
||||
onAdd: (name: string, value: string, remove?: boolean) => void;
|
||||
|
||||
helpButtonText?: string;
|
||||
@ -39,7 +39,7 @@ const MultiInputGroup = ({
|
||||
placeholder,
|
||||
currentValue,
|
||||
onAdd,
|
||||
|
||||
hasError,
|
||||
helpButtonText,
|
||||
isDisabled,
|
||||
}: MultiInputGroupProps) => {
|
||||
@ -74,9 +74,13 @@ const MultiInputGroup = ({
|
||||
value={value}
|
||||
placeholder={placeholder}
|
||||
onChange={onChange}
|
||||
error={`${t("ErrorWrongURL")}: ${window.location.origin}`}
|
||||
error={
|
||||
isError
|
||||
? `${t("ErrorWrongURL")}: ${window.location.origin}`
|
||||
: t("ThisRequiredField")
|
||||
}
|
||||
isRequired
|
||||
isError={isError}
|
||||
isError={isError || hasError}
|
||||
>
|
||||
<StyledInputRow>
|
||||
<InputBlock
|
||||
@ -89,6 +93,7 @@ const MultiInputGroup = ({
|
||||
maxLength={255}
|
||||
isDisabled={isDisabled}
|
||||
onBlur={onBlur}
|
||||
hasError={isError || hasError}
|
||||
/>
|
||||
<SelectorAddButton
|
||||
onClick={() => {
|
||||
|
@ -11,6 +11,7 @@ interface OAuthBlockProps {
|
||||
allowedOriginsValue: string[];
|
||||
|
||||
changeValue: (name: string, value: string) => void;
|
||||
requiredErrorFields: string[];
|
||||
|
||||
isEdit: boolean;
|
||||
}
|
||||
@ -21,7 +22,7 @@ const OAuthBlock = ({
|
||||
allowedOriginsValue,
|
||||
|
||||
changeValue,
|
||||
|
||||
requiredErrorFields,
|
||||
isEdit,
|
||||
}: OAuthBlockProps) => {
|
||||
return (
|
||||
@ -37,6 +38,7 @@ const OAuthBlock = ({
|
||||
currentValue={redirectUrisValue}
|
||||
helpButtonText={t("RedirectsURLSHelpButton")}
|
||||
isDisabled={isEdit}
|
||||
hasError={requiredErrorFields.includes("redirect_uris")}
|
||||
/>
|
||||
<MultiInputGroup
|
||||
t={t}
|
||||
@ -46,6 +48,7 @@ const OAuthBlock = ({
|
||||
onAdd={changeValue}
|
||||
currentValue={allowedOriginsValue}
|
||||
helpButtonText={t("AllowedOriginsHelpButton")}
|
||||
hasError={requiredErrorFields.includes("allowed_origins")}
|
||||
/>
|
||||
</StyledInputBlock>
|
||||
</StyledBlock>
|
||||
|
@ -15,6 +15,7 @@ interface SupportBlockProps {
|
||||
isEdit: boolean;
|
||||
errorFields: string[];
|
||||
onBlur?: (name: string) => void;
|
||||
requiredErrorFields: string[];
|
||||
}
|
||||
|
||||
const SupportBlock = ({
|
||||
@ -27,6 +28,7 @@ const SupportBlock = ({
|
||||
isEdit,
|
||||
errorFields,
|
||||
onBlur,
|
||||
requiredErrorFields,
|
||||
}: SupportBlockProps) => {
|
||||
const onChange = (e: React.ChangeEvent<HTMLInputElement>) => {
|
||||
const target = e.target;
|
||||
@ -34,6 +36,11 @@ const SupportBlock = ({
|
||||
changeValue(target.name, target.value);
|
||||
};
|
||||
|
||||
const policyRequiredError = requiredErrorFields.includes("policy_url");
|
||||
const termsRequiredError = requiredErrorFields.includes("terms_url");
|
||||
const policyError = errorFields.includes("policy_url");
|
||||
const termsError = errorFields.includes("terms_url");
|
||||
|
||||
return (
|
||||
<StyledBlock>
|
||||
<BlockHeader header={t("SupportAndLegalInfo")} />
|
||||
@ -43,12 +50,16 @@ const SupportBlock = ({
|
||||
name={"policy_url"}
|
||||
placeholder={t("EnterURL")}
|
||||
value={policyUrlValue}
|
||||
error={`${t("ErrorWrongURL")}: ${window.location.origin}`}
|
||||
error={
|
||||
policyError
|
||||
? `${t("ErrorWrongURL")}: ${window.location.origin}`
|
||||
: t("ThisRequiredField")
|
||||
}
|
||||
onChange={onChange}
|
||||
helpButtonText={t("PrivacyPolicyURLHelpButton")}
|
||||
disabled={isEdit}
|
||||
isRequired
|
||||
isError={errorFields.includes("policy_url")}
|
||||
isError={policyError || policyRequiredError}
|
||||
onBlur={onBlur}
|
||||
/>
|
||||
<InputGroup
|
||||
@ -56,12 +67,16 @@ const SupportBlock = ({
|
||||
name={"terms_url"}
|
||||
placeholder={t("EnterURL")}
|
||||
value={termsUrlValue}
|
||||
error={`${t("ErrorWrongURL")}: ${window.location.origin}`}
|
||||
error={
|
||||
termsError
|
||||
? `${t("ErrorWrongURL")}: ${window.location.origin}`
|
||||
: t("ThisRequiredField")
|
||||
}
|
||||
onChange={onChange}
|
||||
helpButtonText={t("TermsOfServiceURLHelpButton")}
|
||||
helpButtonText={t("TermsOfServiceURLHelpButton")}
|
||||
disabled={isEdit}
|
||||
isRequired
|
||||
isError={errorFields.includes("terms_url")}
|
||||
isError={termsError || termsRequiredError}
|
||||
onBlur={onBlur}
|
||||
/>
|
||||
</StyledInputBlock>
|
||||
|
@ -12,7 +12,7 @@ interface TextAreaProps {
|
||||
name: string;
|
||||
value: string;
|
||||
placeholder: string;
|
||||
|
||||
increaseHeight: boolean;
|
||||
onChange: (e: React.ChangeEvent<HTMLInputElement>) => void;
|
||||
}
|
||||
|
||||
@ -22,6 +22,7 @@ const TextAreaGroup = ({
|
||||
name,
|
||||
value,
|
||||
placeholder,
|
||||
increaseHeight,
|
||||
|
||||
onChange,
|
||||
}: TextAreaProps) => {
|
||||
@ -48,7 +49,7 @@ const TextAreaGroup = ({
|
||||
onChange={onChange}
|
||||
scale
|
||||
tabIndex={0}
|
||||
heightTextArea={60}
|
||||
heightTextArea={increaseHeight ? 81 : 60}
|
||||
maxLength={255}
|
||||
/>
|
||||
</StyledInputGroup>
|
||||
|
@ -81,6 +81,9 @@ const ClientForm = ({
|
||||
});
|
||||
|
||||
const [errorFields, setErrorFields] = React.useState<string[]>([]);
|
||||
const [requiredErrorFields, setRequiredErrorFields] = React.useState<
|
||||
string[]
|
||||
>([]);
|
||||
|
||||
const { t } = useTranslation(["OAuth", "Common"]);
|
||||
|
||||
@ -99,6 +102,41 @@ const ClientForm = ({
|
||||
const onSaveClick = async () => {
|
||||
try {
|
||||
if (!id) {
|
||||
let isValid = true;
|
||||
for (let key in form) {
|
||||
switch (key) {
|
||||
case "name":
|
||||
case "logo":
|
||||
case "website_url":
|
||||
case "terms_url":
|
||||
case "policy_url":
|
||||
if (form[key] === "") {
|
||||
if (!requiredErrorFields.includes(key))
|
||||
setRequiredErrorFields((s) => [...s, key]);
|
||||
|
||||
isValid = false;
|
||||
}
|
||||
isValid = isValid && !errorFields.includes(key);
|
||||
|
||||
break;
|
||||
|
||||
case "redirect_uris":
|
||||
case "allowed_origins":
|
||||
case "scopes":
|
||||
if (form[key].length === 0) {
|
||||
if (!requiredErrorFields.includes(key))
|
||||
setRequiredErrorFields((s) => [...s, key]);
|
||||
|
||||
isValid = false;
|
||||
}
|
||||
isValid = isValid && !errorFields.includes(key);
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!isValid) return;
|
||||
|
||||
setIsRequestRunning(true);
|
||||
|
||||
await saveClient?.(form);
|
||||
@ -299,8 +337,10 @@ const ClientForm = ({
|
||||
for (let key in form) {
|
||||
switch (key) {
|
||||
case "name":
|
||||
isValid = isValid && !!form[key];
|
||||
|
||||
case "logo":
|
||||
case "website_url":
|
||||
case "terms_url":
|
||||
case "policy_url":
|
||||
if (
|
||||
errorFields.includes(key) &&
|
||||
(!form[key] || (form[key].length > 2 && form[key].length < 256))
|
||||
@ -310,73 +350,17 @@ const ClientForm = ({
|
||||
});
|
||||
}
|
||||
|
||||
isValid = isValid && !errorFields.includes(key);
|
||||
if (requiredErrorFields.includes(key) && form[key] !== "")
|
||||
setRequiredErrorFields((value) => value.filter((v) => v !== key));
|
||||
|
||||
break;
|
||||
case "logo":
|
||||
isValid = isValid && !!form[key];
|
||||
|
||||
break;
|
||||
case "description":
|
||||
// isValid = isValid && !!form[key];
|
||||
|
||||
break;
|
||||
case "website_url":
|
||||
isValid = isValid && !!form[key];
|
||||
|
||||
if (
|
||||
errorFields.includes(key) &&
|
||||
(!form[key] || isValidUrl(form[key]))
|
||||
) {
|
||||
setErrorFields((value) => {
|
||||
return value.filter((n) => n !== key);
|
||||
});
|
||||
}
|
||||
|
||||
break;
|
||||
case "redirect_uris":
|
||||
isValid = isValid && form[key].length > 0;
|
||||
|
||||
break;
|
||||
case "allowed_origins":
|
||||
isValid = isValid && form[key].length > 0;
|
||||
|
||||
break;
|
||||
case "logout_redirect_uris":
|
||||
isValid = isValid;
|
||||
|
||||
break;
|
||||
case "terms_url":
|
||||
isValid = isValid && !!form[key];
|
||||
|
||||
if (
|
||||
errorFields.includes(key) &&
|
||||
(!form[key] || isValidUrl(form[key]))
|
||||
) {
|
||||
setErrorFields((value) => {
|
||||
return value.filter((n) => n !== key);
|
||||
});
|
||||
}
|
||||
|
||||
break;
|
||||
case "policy_url":
|
||||
isValid = isValid && !!form[key];
|
||||
|
||||
if (
|
||||
errorFields.includes(key) &&
|
||||
(!form[key] || isValidUrl(form[key]))
|
||||
) {
|
||||
setErrorFields((value) => {
|
||||
return value.filter((n) => n !== key);
|
||||
});
|
||||
}
|
||||
|
||||
break;
|
||||
case "authentication_method":
|
||||
isValid = isValid;
|
||||
break;
|
||||
case "scopes":
|
||||
isValid = isValid && form[key].length > 0;
|
||||
if (requiredErrorFields.includes(key) && form[key].length > 0)
|
||||
setRequiredErrorFields((value) => value.filter((v) => v !== key));
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -406,6 +390,7 @@ const ClientForm = ({
|
||||
changeValue={onChangeForm}
|
||||
isEdit={isEdit}
|
||||
errorFields={errorFields}
|
||||
requiredErrorFields={requiredErrorFields}
|
||||
onBlur={onBlur}
|
||||
/>
|
||||
{isEdit && (
|
||||
@ -422,6 +407,7 @@ const ClientForm = ({
|
||||
allowedOriginsValue={form.allowed_origins}
|
||||
changeValue={onChangeForm}
|
||||
isEdit={isEdit}
|
||||
requiredErrorFields={requiredErrorFields}
|
||||
/>
|
||||
<ScopesBlock
|
||||
t={t}
|
||||
@ -437,6 +423,7 @@ const ClientForm = ({
|
||||
changeValue={onChangeForm}
|
||||
isEdit={isEdit}
|
||||
errorFields={errorFields}
|
||||
requiredErrorFields={requiredErrorFields}
|
||||
onBlur={onBlur}
|
||||
/>
|
||||
<ButtonsBlock
|
||||
@ -445,7 +432,7 @@ const ClientForm = ({
|
||||
onSaveClick={onSaveClick}
|
||||
onCancelClick={onCancelClick}
|
||||
isRequestRunning={isRequestRunning}
|
||||
saveButtonDisabled={!isValid}
|
||||
saveButtonDisabled={isEdit ? !isValid : false}
|
||||
cancelButtonDisabled={isRequestRunning}
|
||||
currentDeviceType={currentDeviceType || ""}
|
||||
/>
|
||||
|
@ -1,10 +1,10 @@
|
||||
{
|
||||
"date": "20231115_15376",
|
||||
"date": "20231215_102541",
|
||||
"checksums": {
|
||||
"api.js": "47b1c3ac53feb3667b3f0b42cacf8038",
|
||||
"api.js": "47725bc876523672712707c384e3cab2",
|
||||
"api.poly.js": "586ce6831fa68f6bc33486e2cebc856e",
|
||||
"browserDetector.js": "965560573181ee0d643d9a91d3014f39",
|
||||
"config.json": "1a5613e4029a95b738179f30501700b6",
|
||||
"browserDetector.js": "9e853f32d806dd83652ccc2d67510a84",
|
||||
"config.json": "3f54595a6ea8207c37f1197069a2db86",
|
||||
"tiff.min.js": "90496a3b99551fee464b40e26523e84d"
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user