Client: fix editing client form
This commit is contained in:
parent
fe29d4f897
commit
147779cb13
@ -15,6 +15,8 @@ interface BasicBlockProps {
|
||||
descriptionValue: string;
|
||||
|
||||
changeValue: (name: string, value: string) => void;
|
||||
|
||||
isEdit: boolean;
|
||||
}
|
||||
|
||||
const BasicBlock = ({
|
||||
@ -24,6 +26,8 @@ const BasicBlock = ({
|
||||
logoValue,
|
||||
descriptionValue,
|
||||
changeValue,
|
||||
|
||||
isEdit,
|
||||
}: BasicBlockProps) => {
|
||||
const [error, setError] = React.useState({
|
||||
name: "",
|
||||
@ -73,6 +77,7 @@ const BasicBlock = ({
|
||||
value={websiteUrlValue}
|
||||
error={error.websiteUrl}
|
||||
onChange={onChange}
|
||||
disabled={isEdit}
|
||||
/>
|
||||
<SelectGroup
|
||||
label={"App icon"}
|
||||
|
@ -9,9 +9,16 @@ interface ClientBlockProps {
|
||||
|
||||
idValue: string;
|
||||
secretValue: string;
|
||||
|
||||
onResetClick: () => void;
|
||||
}
|
||||
|
||||
const ClientBlock = ({ t, idValue, secretValue }: ClientBlockProps) => {
|
||||
const ClientBlock = ({
|
||||
t,
|
||||
idValue,
|
||||
secretValue,
|
||||
onResetClick,
|
||||
}: ClientBlockProps) => {
|
||||
const [value, setValue] = React.useState<{ [key: string]: string }>({
|
||||
id: idValue,
|
||||
secret: secretValue,
|
||||
@ -46,6 +53,7 @@ Note: Any enterprise admin who knows the app's client ID will be able to retriev
|
||||
withCopy
|
||||
isPassword
|
||||
buttonLabel={"Reset"}
|
||||
onButtonClick={onResetClick}
|
||||
/>
|
||||
</StyledInputBlock>
|
||||
</StyledBlock>
|
||||
|
@ -33,6 +33,8 @@ interface InputGroupProps {
|
||||
withCopy?: boolean;
|
||||
onCopyClick?: (name: string) => void;
|
||||
isPassword?: boolean;
|
||||
|
||||
disabled?: boolean;
|
||||
}
|
||||
|
||||
const InputGroup = ({
|
||||
@ -54,6 +56,7 @@ const InputGroup = ({
|
||||
withCopy,
|
||||
onCopyClick,
|
||||
isPassword,
|
||||
disabled,
|
||||
}: InputGroupProps) => {
|
||||
return (
|
||||
<StyledInputGroup>
|
||||
@ -82,7 +85,7 @@ const InputGroup = ({
|
||||
tabIndex={0}
|
||||
maxLength={255}
|
||||
isReadOnly={withCopy}
|
||||
isDisabled={withCopy}
|
||||
isDisabled={withCopy || disabled}
|
||||
iconName={withCopy ? CopyReactSvgUrl : null}
|
||||
onIconClick={withCopy && onCopyClick}
|
||||
type={isPassword ? "password" : "text"}
|
||||
|
@ -26,6 +26,8 @@ interface MultiInputGroupProps {
|
||||
onAdd: (name: string, value: string, remove?: boolean) => void;
|
||||
|
||||
helpButtonText?: string;
|
||||
|
||||
isDisabled?: boolean;
|
||||
}
|
||||
|
||||
const MultiInputGroup = ({
|
||||
@ -36,6 +38,7 @@ const MultiInputGroup = ({
|
||||
onAdd,
|
||||
|
||||
helpButtonText,
|
||||
isDisabled,
|
||||
}: MultiInputGroupProps) => {
|
||||
const [value, setValue] = React.useState("");
|
||||
|
||||
@ -71,12 +74,15 @@ const MultiInputGroup = ({
|
||||
scale
|
||||
tabIndex={0}
|
||||
maxLength={255}
|
||||
isDisabled={isDisabled}
|
||||
/>
|
||||
<SelectorAddButton
|
||||
onClick={() => {
|
||||
if (isDisabled) return;
|
||||
onAdd(name, value);
|
||||
setValue("");
|
||||
}}
|
||||
isDisabled={isDisabled}
|
||||
/>
|
||||
</StyledInputRow>
|
||||
<StyledChipsContainer>
|
||||
@ -85,7 +91,9 @@ const MultiInputGroup = ({
|
||||
key={`${v}-${index}`}
|
||||
isInline
|
||||
label={v}
|
||||
onClose={() => onAdd(name, v)}
|
||||
onClose={() => {
|
||||
!isDisabled && onAdd(name, v);
|
||||
}}
|
||||
/>
|
||||
))}
|
||||
</StyledChipsContainer>
|
||||
|
@ -11,6 +11,8 @@ interface OAuthBlockProps {
|
||||
allowedOriginsValue: string[];
|
||||
|
||||
changeValue: (name: string, value: string) => void;
|
||||
|
||||
isEdit: boolean;
|
||||
}
|
||||
|
||||
const OAuthBlock = ({
|
||||
@ -19,6 +21,8 @@ const OAuthBlock = ({
|
||||
allowedOriginsValue,
|
||||
|
||||
changeValue,
|
||||
|
||||
isEdit,
|
||||
}: OAuthBlockProps) => {
|
||||
return (
|
||||
<StyledBlock>
|
||||
@ -31,6 +35,7 @@ const OAuthBlock = ({
|
||||
onAdd={changeValue}
|
||||
currentValue={redirectUrisValue}
|
||||
helpButtonText={"Redirect uris"}
|
||||
isDisabled={isEdit}
|
||||
/>
|
||||
<MultiInputGroup
|
||||
label={"Allowed origins"}
|
||||
@ -39,6 +44,7 @@ const OAuthBlock = ({
|
||||
onAdd={changeValue}
|
||||
currentValue={allowedOriginsValue}
|
||||
helpButtonText={"Allowed origins"}
|
||||
isDisabled={isEdit}
|
||||
/>
|
||||
</StyledInputBlock>
|
||||
</StyledBlock>
|
||||
|
@ -26,6 +26,7 @@ interface IScopesBlockProps {
|
||||
selectedScopes: string[];
|
||||
onAddScope: (name: string, scope: string) => void;
|
||||
t: any;
|
||||
isEdit: boolean;
|
||||
}
|
||||
|
||||
const ScopesBlock = ({
|
||||
@ -33,6 +34,7 @@ const ScopesBlock = ({
|
||||
selectedScopes,
|
||||
onAddScope,
|
||||
t,
|
||||
isEdit,
|
||||
}: IScopesBlockProps) => {
|
||||
const [checkedScopes, setCheckedScopes] = React.useState<string[]>([]);
|
||||
const [filteredScopes, setFilteredScopes] = React.useState<IFilteredScopes>(
|
||||
@ -152,7 +154,7 @@ const ScopesBlock = ({
|
||||
<Checkbox
|
||||
className="checkbox-read"
|
||||
isChecked={isReadChecked}
|
||||
isDisabled={isReadDisabled}
|
||||
isDisabled={isReadDisabled || isEdit}
|
||||
onChange={() =>
|
||||
onAddCheckedScope(
|
||||
key as ScopeGroup,
|
||||
@ -165,6 +167,7 @@ const ScopesBlock = ({
|
||||
<StyledScopesCheckbox>
|
||||
<Checkbox
|
||||
isChecked={isReadDisabled}
|
||||
isDisabled={isEdit}
|
||||
onChange={() =>
|
||||
onAddCheckedScope(
|
||||
key as ScopeGroup,
|
||||
|
@ -11,6 +11,8 @@ interface SupportBlockProps {
|
||||
termsUrlValue: string;
|
||||
|
||||
changeValue: (name: string, value: string) => void;
|
||||
|
||||
isEdit: boolean;
|
||||
}
|
||||
|
||||
const SupportBlock = ({
|
||||
@ -19,6 +21,8 @@ const SupportBlock = ({
|
||||
termsUrlValue,
|
||||
|
||||
changeValue,
|
||||
|
||||
isEdit,
|
||||
}: SupportBlockProps) => {
|
||||
const [error, setError] = React.useState({
|
||||
policyUrl: "",
|
||||
@ -45,6 +49,7 @@ const SupportBlock = ({
|
||||
helpButtonText={
|
||||
"Provide a URL link to your Privacy Policy that must comply with applicable laws and regulations and that make clear how you collect, use, share, retain and otherwise process personal information."
|
||||
}
|
||||
disabled={isEdit}
|
||||
/>
|
||||
<InputGroup
|
||||
label={"Terms of Service URL"}
|
||||
@ -54,6 +59,7 @@ const SupportBlock = ({
|
||||
error={error.termsUrl}
|
||||
onChange={onChange}
|
||||
helpButtonText={"Terms of service help"}
|
||||
disabled={isEdit}
|
||||
/>
|
||||
</StyledInputBlock>
|
||||
</StyledBlock>
|
||||
|
@ -44,8 +44,9 @@ const ClientForm = ({
|
||||
const [isRequestRunning, setIsRequestRunning] =
|
||||
React.useState<boolean>(false);
|
||||
|
||||
const [initClient, setInitClient] = React.useState<IClientProps | null>(null);
|
||||
|
||||
const [initialClient, setInitialClient] = React.useState<IClientProps>(
|
||||
{} as IClientProps
|
||||
);
|
||||
const [form, setForm] = React.useState<IClientReqDTO>({
|
||||
name: "",
|
||||
logo: "",
|
||||
@ -67,7 +68,7 @@ const ClientForm = ({
|
||||
const [clientId, setClientId] = React.useState<string>("");
|
||||
const [clientSecret, setClientSecret] = React.useState<string>("");
|
||||
|
||||
const isEdit = !!id || !!client;
|
||||
const isEdit = !!id;
|
||||
|
||||
// const onInputChange = React.useCallback(
|
||||
// (e: React.ChangeEvent<HTMLInputElement>) => {
|
||||
@ -98,6 +99,7 @@ const ClientForm = ({
|
||||
const onSaveClick = async () => {
|
||||
if (!id) {
|
||||
if (!saveClient) return;
|
||||
setIsRequestRunning(true);
|
||||
|
||||
await saveClient(form);
|
||||
|
||||
@ -115,47 +117,12 @@ const ClientForm = ({
|
||||
navigate("/portal-settings/developer-tools/oauth");
|
||||
};
|
||||
|
||||
// const onResetClick = React.useCallback(async () => {
|
||||
// if (!regenerateSecret) return;
|
||||
// const newSecret = await regenerateSecret(clientId);
|
||||
const onResetClick = React.useCallback(async () => {
|
||||
if (!regenerateSecret) return;
|
||||
const newSecret = await regenerateSecret(clientId);
|
||||
|
||||
// setSecret(newSecret);
|
||||
// }, [clientId, regenerateSecret]);
|
||||
|
||||
// const getClient = React.useCallback(async () => {
|
||||
// if (!fetchClient || !id) return;
|
||||
|
||||
// const client = await fetchClient(id);
|
||||
|
||||
// setClient(client);
|
||||
// }, [id, fetchClient]);
|
||||
|
||||
// const setClient = React.useCallback(async (client: ClientProps) => {
|
||||
// setForm({
|
||||
// appName: client.name,
|
||||
// appIcon: client.logoUrl || "",
|
||||
// description: client.description,
|
||||
|
||||
// redirectUrl: client.redirectUri,
|
||||
// privacyURL: client.policyUrl,
|
||||
// termsUrl: client.termsUrl,
|
||||
// logoutRedirectUrl: client.logoutRedirectUri,
|
||||
|
||||
// authenticationMethod: client.authenticationMethod,
|
||||
// });
|
||||
|
||||
// setSecret(client.secret);
|
||||
|
||||
// setCheckedScopes([...client.scopes]);
|
||||
|
||||
// setInitClient({ ...client, scopes: [...client.scopes] });
|
||||
|
||||
// setIsLoading(false);
|
||||
// }, []);
|
||||
|
||||
// React.useEffect(() => {
|
||||
// setIsLoading(true);
|
||||
// }, []);
|
||||
setClientSecret(newSecret);
|
||||
}, [clientId, regenerateSecret]);
|
||||
|
||||
const onChangeForm = (name: string, value: string) => {
|
||||
setForm((val) => {
|
||||
@ -180,35 +147,64 @@ const ClientForm = ({
|
||||
});
|
||||
};
|
||||
|
||||
const getScopeList = React.useCallback(async () => {
|
||||
if (!fetchScopes) return;
|
||||
const getClientData = React.useCallback(async () => {
|
||||
if (!fetchScopes || !fetchClient) return;
|
||||
|
||||
const actions = [];
|
||||
|
||||
if (id && !client) {
|
||||
actions.push(fetchClient(id));
|
||||
}
|
||||
|
||||
actions.push(fetchScopes());
|
||||
|
||||
const [fetchedClient, ...rest] = await Promise.all(actions);
|
||||
|
||||
if (id && fetchedClient) {
|
||||
setForm({
|
||||
name: fetchedClient.name,
|
||||
logo: fetchedClient.logo,
|
||||
website_url: fetchedClient.websiteUrl,
|
||||
description: fetchedClient.description,
|
||||
|
||||
redirect_uris: fetchedClient.redirectUris,
|
||||
allowed_origins: fetchedClient.allowedOrigins,
|
||||
logout_redirect_uri: fetchedClient.logoutRedirectUri,
|
||||
|
||||
terms_url: fetchedClient.termsUrl,
|
||||
policy_url: fetchedClient.policyUrl,
|
||||
|
||||
authentication_method: fetchedClient.authenticationMethod,
|
||||
|
||||
scopes: fetchedClient.scopes,
|
||||
});
|
||||
setClientId(fetchedClient.clientId);
|
||||
setClientSecret(fetchedClient.clientSecret);
|
||||
|
||||
setInitialClient(fetchedClient);
|
||||
}
|
||||
|
||||
await fetchScopes();
|
||||
setIsLoading(false);
|
||||
}, [fetchScopes]);
|
||||
}, [id, client, fetchScopes]);
|
||||
|
||||
React.useEffect(() => {
|
||||
if (scopeList && scopeList?.length !== 0) return;
|
||||
|
||||
setIsLoading(true);
|
||||
getScopeList();
|
||||
}, [id, scopeList, getScopeList, fetchScopes]);
|
||||
|
||||
// React.useEffect(() => {
|
||||
|
||||
// if (id) {
|
||||
// setClientId(id);
|
||||
// if (!client) {
|
||||
// getClient();
|
||||
// } else {
|
||||
// setClient(client);
|
||||
// }
|
||||
// }
|
||||
// }, [id, client, fetchClient, getClient, setClient]);
|
||||
getClientData();
|
||||
}, [id, scopeList, client, getClientData, fetchScopes]);
|
||||
|
||||
const compareAndValidate = () => {
|
||||
let isValid = true;
|
||||
|
||||
if (isEdit) {
|
||||
return (
|
||||
form.name !== initialClient.name ||
|
||||
form.logo !== initialClient.logo ||
|
||||
form.description !== initialClient.description
|
||||
);
|
||||
}
|
||||
|
||||
for (let key in form) {
|
||||
switch (key) {
|
||||
case "name":
|
||||
@ -272,27 +268,36 @@ const ClientForm = ({
|
||||
descriptionValue={form.description}
|
||||
logoValue={form.logo}
|
||||
changeValue={onChangeForm}
|
||||
isEdit={isEdit}
|
||||
/>
|
||||
{isEdit && (
|
||||
<ClientBlock t={t} idValue={clientId} secretValue={clientSecret} />
|
||||
<ClientBlock
|
||||
t={t}
|
||||
idValue={clientId}
|
||||
secretValue={clientSecret}
|
||||
onResetClick={onResetClick}
|
||||
/>
|
||||
)}
|
||||
<OAuthBlock
|
||||
t={t}
|
||||
redirectUrisValue={form.redirect_uris}
|
||||
allowedOriginsValue={form.allowed_origins}
|
||||
changeValue={onChangeForm}
|
||||
isEdit={isEdit}
|
||||
/>
|
||||
<ScopesBlock
|
||||
t={t}
|
||||
scopes={scopeList || []}
|
||||
selectedScopes={[]}
|
||||
selectedScopes={form.scopes}
|
||||
onAddScope={onChangeForm}
|
||||
isEdit={isEdit}
|
||||
/>
|
||||
<SupportBlock
|
||||
t={t}
|
||||
policyUrlValue={form.policy_url}
|
||||
termsUrlValue={form.terms_url}
|
||||
changeValue={onChangeForm}
|
||||
isEdit={isEdit}
|
||||
/>
|
||||
<ButtonsBlock
|
||||
saveLabel={"Save"}
|
||||
|
@ -24,6 +24,8 @@ import SettingsIcon from "PUBLIC_DIR/images/catalog.settings.react.svg?url";
|
||||
import DeleteIcon from "PUBLIC_DIR/images/delete.react.svg?url";
|
||||
import EnableReactSvgUrl from "PUBLIC_DIR/images/enable.react.svg?url";
|
||||
import RemoveReactSvgUrl from "PUBLIC_DIR/images/remove.react.svg?url";
|
||||
import PencilReactSvgUrl from "PUBLIC_DIR/images/pencil.react.svg?url";
|
||||
import CodeReactSvgUrl from "PUBLIC_DIR/images/code.react.svg?url";
|
||||
|
||||
const PAGE_LIMIT = 100;
|
||||
|
||||
@ -235,7 +237,7 @@ class OAuthStore implements OAuthStoreProps {
|
||||
}
|
||||
};
|
||||
|
||||
updateClient = async (clientId: string, client: ClientProps) => {
|
||||
updateClient = async (clientId: string, client: IClientProps) => {
|
||||
try {
|
||||
const newClient = await updateClient(clientId, client);
|
||||
|
||||
@ -269,9 +271,9 @@ class OAuthStore implements OAuthStoreProps {
|
||||
|
||||
regenerateSecret = async (clientId: string) => {
|
||||
try {
|
||||
const secret = await regenerateSecret(clientId);
|
||||
const { client_secret } = await regenerateSecret(clientId);
|
||||
|
||||
return secret;
|
||||
return client_secret;
|
||||
} catch (e) {
|
||||
console.log(e);
|
||||
}
|
||||
@ -336,8 +338,6 @@ class OAuthStore implements OAuthStoreProps {
|
||||
this.activeClients = [];
|
||||
this.selection = [];
|
||||
});
|
||||
|
||||
//TODO OAuth, show toast
|
||||
} catch (e) {}
|
||||
} else {
|
||||
this.setActiveClient(clientId);
|
||||
@ -348,13 +348,27 @@ class OAuthStore implements OAuthStoreProps {
|
||||
}
|
||||
};
|
||||
|
||||
const settingsOption = {
|
||||
key: "settings",
|
||||
icon: SettingsIcon,
|
||||
label: t("Settings"),
|
||||
const editOption = {
|
||||
key: "edit",
|
||||
icon: PencilReactSvgUrl,
|
||||
label: t("Edit"),
|
||||
onClick: () => this.editClient(clientId),
|
||||
};
|
||||
|
||||
const authButtonOption = {
|
||||
key: "auth-button",
|
||||
icon: CodeReactSvgUrl,
|
||||
label: "Auth button",
|
||||
onClick: () => console.log(clientId),
|
||||
};
|
||||
|
||||
const infoOption = {
|
||||
key: "info",
|
||||
icon: SettingsIcon,
|
||||
label: "Info",
|
||||
onClick: () => console.log(clientId),
|
||||
};
|
||||
|
||||
const enableOption = {
|
||||
key: "enable",
|
||||
icon: EnableReactSvgUrl,
|
||||
@ -404,7 +418,9 @@ class OAuthStore implements OAuthStoreProps {
|
||||
contextOptions.unshift(enableOption);
|
||||
}
|
||||
|
||||
contextOptions.unshift(settingsOption);
|
||||
contextOptions.unshift(infoOption);
|
||||
contextOptions.unshift(authButtonOption);
|
||||
contextOptions.unshift(editOption);
|
||||
}
|
||||
|
||||
return contextOptions;
|
||||
|
@ -82,28 +82,27 @@ export const updateClient = async (
|
||||
data: transformToClientReqDTO(data),
|
||||
});
|
||||
|
||||
// TODO: OAuth, get it from request
|
||||
client.enabled = true;
|
||||
|
||||
return transformToClientProps(client);
|
||||
};
|
||||
|
||||
export const changeClientStatus = async (
|
||||
clientId: string,
|
||||
status: boolean
|
||||
): Promise<boolean> => {
|
||||
console.log(`Change client:${clientId} status to ${status}`);
|
||||
|
||||
return !status;
|
||||
};
|
||||
|
||||
export const regenerateSecret = async (clientId: string): Promise<string> => {
|
||||
const clientSecret: string = (
|
||||
): Promise<void> => {
|
||||
await request({
|
||||
method: "patch",
|
||||
url: `/clients/${clientId}`,
|
||||
})
|
||||
).client_secret;
|
||||
url: `/clients/${clientId}/activation`,
|
||||
data: { body: status },
|
||||
});
|
||||
};
|
||||
|
||||
export const regenerateSecret = async (
|
||||
clientId: string
|
||||
): Promise<{ client_secret: string }> => {
|
||||
const clientSecret: { client_secret: string } = await request({
|
||||
method: "patch",
|
||||
url: `/clients/${clientId}/regenerate`,
|
||||
});
|
||||
|
||||
return clientSecret;
|
||||
};
|
||||
|
@ -63,8 +63,10 @@ const ScopeList = ({ selectedScopes, scopes, t }: IScopeListProps) => {
|
||||
for (let key in filteredScopes) {
|
||||
if (filteredScopes[key].isChecked) {
|
||||
if (filteredScopes[key].checkedType === ScopeType.read) {
|
||||
//@ts-ignore
|
||||
result.push(filteredScopes[key].read.tKey || "");
|
||||
} else {
|
||||
//@ts-ignore
|
||||
result.push(filteredScopes[key].write.tKey || "");
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user