mirror of
https://github.com/open-metadata/OpenMetadata.git
synced 2025-10-14 18:27:35 +00:00
This commit is contained in:
parent
819188cfc1
commit
c27657ea5e
@ -65,14 +65,9 @@ describe('Bots Page should work properly', () => {
|
|||||||
cy.get('[data-testid="displayName"]').should('exist').type(botName);
|
cy.get('[data-testid="displayName"]').should('exist').type(botName);
|
||||||
//Enter description
|
//Enter description
|
||||||
cy.get(descriptionBox).type(description);
|
cy.get(descriptionBox).type(description);
|
||||||
//Generate Password
|
|
||||||
interceptURL('GET', ' /api/v1/users/generateRandomPwd', 'generatePassword');
|
|
||||||
cy.get('[data-testid="password-generator"]').should('be.visible').click();
|
|
||||||
verifyResponseStatusCode('@generatePassword', 200);
|
|
||||||
cy.wait(1000);
|
|
||||||
//Click on save button
|
//Click on save button
|
||||||
cy.wait(1000);
|
cy.wait(1000);
|
||||||
interceptURL('POST', '/api/v1/bots', 'createBot');
|
interceptURL('PUT', '/api/v1/bots', 'createBot');
|
||||||
cy.get('[data-testid="save-user"]')
|
cy.get('[data-testid="save-user"]')
|
||||||
.scrollIntoView()
|
.scrollIntoView()
|
||||||
.should('be.visible')
|
.should('be.visible')
|
||||||
@ -97,9 +92,8 @@ describe('Bots Page should work properly', () => {
|
|||||||
.type(updatedBotName);
|
.type(updatedBotName);
|
||||||
//Save the updated display name
|
//Save the updated display name
|
||||||
|
|
||||||
interceptURL('GET', '/api/v1/users/auth-mechanism/*', 'getBotDetails');
|
|
||||||
cy.get('[data-testid="save-displayName"]').should('be.visible').click();
|
cy.get('[data-testid="save-displayName"]').should('be.visible').click();
|
||||||
verifyResponseStatusCode('@getBotDetails', 200);
|
|
||||||
//Verify the display name is updated on bot details page
|
//Verify the display name is updated on bot details page
|
||||||
cy.get('[data-testid="container"]').should('contain', updatedBotName);
|
cy.get('[data-testid="container"]').should('contain', updatedBotName);
|
||||||
cy.wait(1000);
|
cy.wait(1000);
|
||||||
|
@ -63,3 +63,12 @@ export const deleteBot = async (id: string, hardDelete?: boolean) => {
|
|||||||
|
|
||||||
return response.data;
|
return response.data;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const createBotWithPut = async (data: CreateBot) => {
|
||||||
|
const response = await axiosClient.put<CreateBot, AxiosResponse<Bot>>(
|
||||||
|
BASE_URL,
|
||||||
|
data
|
||||||
|
);
|
||||||
|
|
||||||
|
return response.data;
|
||||||
|
};
|
||||||
|
@ -19,6 +19,7 @@ import {
|
|||||||
AuthenticationMechanism,
|
AuthenticationMechanism,
|
||||||
CreateUser,
|
CreateUser,
|
||||||
} from '../generated/api/teams/createUser';
|
} from '../generated/api/teams/createUser';
|
||||||
|
import { Bot } from '../generated/entity/bot';
|
||||||
import { JwtAuth } from '../generated/entity/teams/authN/jwtAuth';
|
import { JwtAuth } from '../generated/entity/teams/authN/jwtAuth';
|
||||||
import { User } from '../generated/entity/teams/user';
|
import { User } from '../generated/entity/teams/user';
|
||||||
import { EntityReference } from '../generated/type/entityReference';
|
import { EntityReference } from '../generated/type/entityReference';
|
||||||
@ -196,3 +197,34 @@ export const getAuthMechanismForBotUser = async (botId: string) => {
|
|||||||
|
|
||||||
return response.data;
|
return response.data;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const getBotByName = async (name: string, arrQueryFields?: string) => {
|
||||||
|
const url = getURLWithQueryFields(`/bots/name/${name}`, arrQueryFields);
|
||||||
|
|
||||||
|
const response = await APIClient.get<Bot>(url);
|
||||||
|
|
||||||
|
return response.data;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const updateBotDetail = async (id: string, data: Operation[]) => {
|
||||||
|
const configOptions = {
|
||||||
|
headers: { 'Content-type': 'application/json-patch+json' },
|
||||||
|
};
|
||||||
|
|
||||||
|
const response = await APIClient.patch<Operation[], AxiosResponse<Bot>>(
|
||||||
|
`/bots/${id}`,
|
||||||
|
data,
|
||||||
|
configOptions
|
||||||
|
);
|
||||||
|
|
||||||
|
return response.data;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const createUserWithPut = async (userDetails: CreateUser) => {
|
||||||
|
const response = await APIClient.put<CreateUser, AxiosResponse<User>>(
|
||||||
|
`/users`,
|
||||||
|
userDetails
|
||||||
|
);
|
||||||
|
|
||||||
|
return response.data;
|
||||||
|
};
|
||||||
|
@ -15,13 +15,17 @@ import { Button, Divider, Input, Space, Typography } from 'antd';
|
|||||||
import { capitalize } from 'lodash';
|
import { capitalize } from 'lodash';
|
||||||
import React, { FC } from 'react';
|
import React, { FC } from 'react';
|
||||||
import { AuthType } from '../../generated/api/teams/createUser';
|
import { AuthType } from '../../generated/api/teams/createUser';
|
||||||
import { AuthenticationMechanism } from '../../generated/entity/teams/user';
|
import {
|
||||||
|
AuthenticationMechanism,
|
||||||
|
User,
|
||||||
|
} from '../../generated/entity/teams/user';
|
||||||
import { getTokenExpiry } from '../../utils/BotsUtils';
|
import { getTokenExpiry } from '../../utils/BotsUtils';
|
||||||
import SVGIcons from '../../utils/SvgUtils';
|
import SVGIcons from '../../utils/SvgUtils';
|
||||||
import CopyToClipboardButton from '../buttons/CopyToClipboardButton/CopyToClipboardButton';
|
import CopyToClipboardButton from '../buttons/CopyToClipboardButton/CopyToClipboardButton';
|
||||||
import './AuthMechanism.less';
|
import './AuthMechanism.less';
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
|
botUser: User;
|
||||||
authenticationMechanism: AuthenticationMechanism;
|
authenticationMechanism: AuthenticationMechanism;
|
||||||
hasPermission: boolean;
|
hasPermission: boolean;
|
||||||
onEdit: () => void;
|
onEdit: () => void;
|
||||||
@ -33,6 +37,7 @@ const AuthMechanism: FC<Props> = ({
|
|||||||
hasPermission,
|
hasPermission,
|
||||||
onEdit,
|
onEdit,
|
||||||
onTokenRevoke,
|
onTokenRevoke,
|
||||||
|
botUser,
|
||||||
}: Props) => {
|
}: Props) => {
|
||||||
if (authenticationMechanism.authType === AuthType.Jwt) {
|
if (authenticationMechanism.authType === AuthType.Jwt) {
|
||||||
const JWTToken = authenticationMechanism.config?.JWTToken;
|
const JWTToken = authenticationMechanism.config?.JWTToken;
|
||||||
@ -137,6 +142,18 @@ const AuthMechanism: FC<Props> = ({
|
|||||||
<Divider style={{ margin: '8px 0px' }} />
|
<Divider style={{ margin: '8px 0px' }} />
|
||||||
|
|
||||||
<Space className="w-full" direction="vertical">
|
<Space className="w-full" direction="vertical">
|
||||||
|
<>
|
||||||
|
<Typography.Text>Account Email</Typography.Text>
|
||||||
|
<Space className="w-full tw-justify-between ant-space-authMechanism">
|
||||||
|
<Input
|
||||||
|
contentEditable={false}
|
||||||
|
data-testid="botUser-email"
|
||||||
|
value={botUser.email}
|
||||||
|
/>
|
||||||
|
<CopyToClipboardButton copyText={botUser.email} />
|
||||||
|
</Space>
|
||||||
|
</>
|
||||||
|
|
||||||
{authConfig?.secretKey && (
|
{authConfig?.secretKey && (
|
||||||
<>
|
<>
|
||||||
<Typography.Text>SecretKey</Typography.Text>
|
<Typography.Text>SecretKey</Typography.Text>
|
||||||
|
@ -11,35 +11,51 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { Button, Form, Input, Select, Space } from 'antd';
|
import { Button, Form, Input, Modal, Select, Space, Typography } from 'antd';
|
||||||
|
import { AxiosError } from 'axios';
|
||||||
import { isEmpty } from 'lodash';
|
import { isEmpty } from 'lodash';
|
||||||
import React, { FC, useEffect, useState } from 'react';
|
import React, { FC, useEffect, useState } from 'react';
|
||||||
import { useAuthContext } from '../../authentication/auth-provider/AuthProvider';
|
import { useAuthContext } from '../../authentication/auth-provider/AuthProvider';
|
||||||
|
import { checkEmailInUse } from '../../axiosAPIs/auth-API';
|
||||||
|
import { createBotWithPut } from '../../axiosAPIs/botsAPI';
|
||||||
|
import { createUserWithPut, getUserByName } from '../../axiosAPIs/userAPI';
|
||||||
|
import { BOT_ACCOUNT_EMAIL_CHANGE_CONFIRMATION } from '../../constants/HelperTextUtil';
|
||||||
|
import { validEmailRegEx } from '../../constants/regex.constants';
|
||||||
|
import { EntityType } from '../../enums/entity.enum';
|
||||||
|
import { Bot } from '../../generated/entity/bot';
|
||||||
import { SsoServiceType } from '../../generated/entity/teams/authN/ssoAuth';
|
import { SsoServiceType } from '../../generated/entity/teams/authN/ssoAuth';
|
||||||
import {
|
import {
|
||||||
AuthenticationMechanism,
|
AuthenticationMechanism,
|
||||||
AuthType,
|
AuthType,
|
||||||
JWTTokenExpiry,
|
JWTTokenExpiry,
|
||||||
|
User,
|
||||||
} from '../../generated/entity/teams/user';
|
} from '../../generated/entity/teams/user';
|
||||||
import { Auth0SSOClientConfig } from '../../generated/security/client/auth0SSOClientConfig';
|
import { Auth0SSOClientConfig } from '../../generated/security/client/auth0SSOClientConfig';
|
||||||
import { AzureSSOClientConfig } from '../../generated/security/client/azureSSOClientConfig';
|
import { AzureSSOClientConfig } from '../../generated/security/client/azureSSOClientConfig';
|
||||||
import { CustomOidcSSOClientConfig } from '../../generated/security/client/customOidcSSOClientConfig';
|
import { CustomOidcSSOClientConfig } from '../../generated/security/client/customOidcSSOClientConfig';
|
||||||
import { GoogleSSOClientConfig } from '../../generated/security/client/googleSSOClientConfig';
|
import { GoogleSSOClientConfig } from '../../generated/security/client/googleSSOClientConfig';
|
||||||
import { OktaSSOClientConfig } from '../../generated/security/client/oktaSSOClientConfig';
|
import { OktaSSOClientConfig } from '../../generated/security/client/oktaSSOClientConfig';
|
||||||
|
import jsonData from '../../jsons/en';
|
||||||
|
import { getNameFromEmail } from '../../utils/AuthProvider.util';
|
||||||
import {
|
import {
|
||||||
|
getAuthMechanismFormInitialValues,
|
||||||
getAuthMechanismTypeOptions,
|
getAuthMechanismTypeOptions,
|
||||||
getJWTTokenExpiryOptions,
|
getJWTTokenExpiryOptions,
|
||||||
} from '../../utils/BotsUtils';
|
} from '../../utils/BotsUtils';
|
||||||
|
import { showErrorToast } from '../../utils/ToastUtils';
|
||||||
import { SSOClientConfig } from '../CreateUser/CreateUser.interface';
|
import { SSOClientConfig } from '../CreateUser/CreateUser.interface';
|
||||||
import Loader from '../Loader/Loader';
|
import Loader from '../Loader/Loader';
|
||||||
|
|
||||||
const { Option } = Select;
|
const { Option } = Select;
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
|
botUser: User;
|
||||||
|
botData: Bot;
|
||||||
isUpdating: boolean;
|
isUpdating: boolean;
|
||||||
authenticationMechanism: AuthenticationMechanism;
|
authenticationMechanism: AuthenticationMechanism;
|
||||||
onSave: (updatedAuthMechanism: AuthenticationMechanism) => void;
|
onSave: (updatedAuthMechanism: AuthenticationMechanism) => void;
|
||||||
onCancel: () => void;
|
onCancel: () => void;
|
||||||
|
onEmailChange: () => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
const AuthMechanismForm: FC<Props> = ({
|
const AuthMechanismForm: FC<Props> = ({
|
||||||
@ -47,6 +63,9 @@ const AuthMechanismForm: FC<Props> = ({
|
|||||||
onSave,
|
onSave,
|
||||||
onCancel,
|
onCancel,
|
||||||
authenticationMechanism,
|
authenticationMechanism,
|
||||||
|
botUser,
|
||||||
|
botData,
|
||||||
|
onEmailChange,
|
||||||
}) => {
|
}) => {
|
||||||
const { authConfig } = useAuthContext();
|
const { authConfig } = useAuthContext();
|
||||||
|
|
||||||
@ -62,6 +81,11 @@ const AuthMechanismForm: FC<Props> = ({
|
|||||||
({} as SSOClientConfig)
|
({} as SSOClientConfig)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const [accountEmail, setAccountEmail] = useState<string>(botUser.email);
|
||||||
|
|
||||||
|
const [isConfirmationModalOpen, setIsConfirmationModalOpen] =
|
||||||
|
useState<boolean>(false);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const authType = authenticationMechanism.authType;
|
const authType = authenticationMechanism.authType;
|
||||||
const authConfig = authenticationMechanism.config?.authConfig;
|
const authConfig = authenticationMechanism.config?.authConfig;
|
||||||
@ -114,6 +138,10 @@ const AuthMechanismForm: FC<Props> = ({
|
|||||||
email: value,
|
email: value,
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
break;
|
||||||
|
case 'email':
|
||||||
|
setAccountEmail(value);
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
@ -122,22 +150,80 @@ const AuthMechanismForm: FC<Props> = ({
|
|||||||
};
|
};
|
||||||
|
|
||||||
const handleSave = () => {
|
const handleSave = () => {
|
||||||
const updatedAuthMechanism: AuthenticationMechanism = {
|
if (accountEmail !== botUser.email) {
|
||||||
authType: authMechanism,
|
setIsConfirmationModalOpen(true);
|
||||||
config:
|
} else {
|
||||||
authMechanism === AuthType.Jwt
|
const updatedAuthMechanism: AuthenticationMechanism = {
|
||||||
? {
|
authType: authMechanism,
|
||||||
JWTTokenExpiry: tokenExpiry,
|
config:
|
||||||
}
|
authMechanism === AuthType.Jwt
|
||||||
: {
|
? {
|
||||||
ssoServiceType: authConfig?.provider as SsoServiceType,
|
JWTTokenExpiry: tokenExpiry,
|
||||||
authConfig: {
|
}
|
||||||
...ssoClientConfig,
|
: {
|
||||||
|
ssoServiceType: authConfig?.provider as SsoServiceType,
|
||||||
|
authConfig: {
|
||||||
|
...ssoClientConfig,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
};
|
||||||
};
|
|
||||||
|
|
||||||
onSave(updatedAuthMechanism);
|
onSave(updatedAuthMechanism);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleBotUpdate = async (response: User) => {
|
||||||
|
try {
|
||||||
|
await createBotWithPut({
|
||||||
|
name: botData.name,
|
||||||
|
description: botData.description,
|
||||||
|
displayName: botData.displayName,
|
||||||
|
botUser: { id: response.id, type: EntityType.USER },
|
||||||
|
});
|
||||||
|
} catch (error) {
|
||||||
|
showErrorToast(error as AxiosError);
|
||||||
|
} finally {
|
||||||
|
onEmailChange();
|
||||||
|
setIsConfirmationModalOpen(false);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleAccountEmailChange = async () => {
|
||||||
|
try {
|
||||||
|
const isUserExists = await checkEmailInUse(accountEmail);
|
||||||
|
if (isUserExists) {
|
||||||
|
const userResponse = await getUserByName(
|
||||||
|
getNameFromEmail(accountEmail)
|
||||||
|
);
|
||||||
|
handleBotUpdate(userResponse);
|
||||||
|
} else {
|
||||||
|
const userResponse = await createUserWithPut({
|
||||||
|
email: accountEmail,
|
||||||
|
name: getNameFromEmail(accountEmail),
|
||||||
|
botName: botData.name,
|
||||||
|
isBot: true,
|
||||||
|
authenticationMechanism: {
|
||||||
|
authType: authMechanism,
|
||||||
|
config:
|
||||||
|
authMechanism === AuthType.Jwt
|
||||||
|
? {
|
||||||
|
JWTTokenExpiry: tokenExpiry,
|
||||||
|
}
|
||||||
|
: {
|
||||||
|
ssoServiceType: authConfig?.provider as SsoServiceType,
|
||||||
|
authConfig: {
|
||||||
|
...ssoClientConfig,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
handleBotUpdate(userResponse);
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
showErrorToast(error as AxiosError);
|
||||||
|
} finally {
|
||||||
|
setIsConfirmationModalOpen(false);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const getSSOConfig = () => {
|
const getSSOConfig = () => {
|
||||||
@ -464,47 +550,24 @@ const AuthMechanismForm: FC<Props> = ({
|
|||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Form
|
<>
|
||||||
id="update-auth-mechanism-form"
|
<Form
|
||||||
layout="vertical"
|
id="update-auth-mechanism-form"
|
||||||
onFinish={handleSave}>
|
initialValues={getAuthMechanismFormInitialValues(
|
||||||
<Form.Item
|
authenticationMechanism,
|
||||||
label="Auth Mechanism"
|
botUser
|
||||||
name="auth-mechanism"
|
)}
|
||||||
rules={[
|
layout="vertical"
|
||||||
{
|
onFinish={handleSave}>
|
||||||
required: true,
|
|
||||||
validator: () => {
|
|
||||||
if (!authMechanism) {
|
|
||||||
return Promise.reject('Auth Mechanism is required');
|
|
||||||
}
|
|
||||||
|
|
||||||
return Promise.resolve();
|
|
||||||
},
|
|
||||||
},
|
|
||||||
]}>
|
|
||||||
<Select
|
|
||||||
className="w-full"
|
|
||||||
data-testid="auth-mechanism"
|
|
||||||
defaultValue={authMechanism}
|
|
||||||
placeholder="Select Auth Mechanism"
|
|
||||||
onChange={(value) => setAuthMechanism(value)}>
|
|
||||||
{getAuthMechanismTypeOptions(authConfig).map((option) => (
|
|
||||||
<Option key={option.value}>{option.label}</Option>
|
|
||||||
))}
|
|
||||||
</Select>
|
|
||||||
</Form.Item>
|
|
||||||
|
|
||||||
{authMechanism === AuthType.Jwt && (
|
|
||||||
<Form.Item
|
<Form.Item
|
||||||
label="Token Expiration"
|
label="Auth Mechanism"
|
||||||
name="token-expiration"
|
name="auth-mechanism"
|
||||||
rules={[
|
rules={[
|
||||||
{
|
{
|
||||||
required: true,
|
required: true,
|
||||||
validator: () => {
|
validator: () => {
|
||||||
if (!tokenExpiry) {
|
if (!authMechanism) {
|
||||||
return Promise.reject('Token Expiration is required');
|
return Promise.reject('Auth Mechanism is required');
|
||||||
}
|
}
|
||||||
|
|
||||||
return Promise.resolve();
|
return Promise.resolve();
|
||||||
@ -513,32 +576,98 @@ const AuthMechanismForm: FC<Props> = ({
|
|||||||
]}>
|
]}>
|
||||||
<Select
|
<Select
|
||||||
className="w-full"
|
className="w-full"
|
||||||
data-testid="token-expiry"
|
data-testid="auth-mechanism"
|
||||||
defaultValue={tokenExpiry}
|
defaultValue={authMechanism}
|
||||||
placeholder="Select Token Expiration"
|
placeholder="Select Auth Mechanism"
|
||||||
onChange={(value) => setTokenExpiry(value)}>
|
onChange={(value) => setAuthMechanism(value)}>
|
||||||
{getJWTTokenExpiryOptions().map((option) => (
|
{getAuthMechanismTypeOptions(authConfig).map((option) => (
|
||||||
<Option key={option.value}>{option.label}</Option>
|
<Option key={option.value}>{option.label}</Option>
|
||||||
))}
|
))}
|
||||||
</Select>
|
</Select>
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
)}
|
|
||||||
{authMechanism === AuthType.Sso && <>{getSSOConfig()}</>}
|
{authMechanism === AuthType.Jwt && (
|
||||||
<Space className="w-full tw-justify-end" size={4}>
|
<Form.Item
|
||||||
{!isEmpty(authenticationMechanism) && (
|
label="Token Expiration"
|
||||||
<Button data-testid="cancel-edit" type="link" onClick={onCancel}>
|
name="token-expiration"
|
||||||
Cancel
|
rules={[
|
||||||
</Button>
|
{
|
||||||
|
required: true,
|
||||||
|
validator: () => {
|
||||||
|
if (!tokenExpiry) {
|
||||||
|
return Promise.reject('Token Expiration is required');
|
||||||
|
}
|
||||||
|
|
||||||
|
return Promise.resolve();
|
||||||
|
},
|
||||||
|
},
|
||||||
|
]}>
|
||||||
|
<Select
|
||||||
|
className="w-full"
|
||||||
|
data-testid="token-expiry"
|
||||||
|
defaultValue={tokenExpiry}
|
||||||
|
placeholder="Select Token Expiration"
|
||||||
|
onChange={(value) => setTokenExpiry(value)}>
|
||||||
|
{getJWTTokenExpiryOptions().map((option) => (
|
||||||
|
<Option key={option.value}>{option.label}</Option>
|
||||||
|
))}
|
||||||
|
</Select>
|
||||||
|
</Form.Item>
|
||||||
)}
|
)}
|
||||||
<Button
|
{authMechanism === AuthType.Sso && (
|
||||||
data-testid="save-edit"
|
<>
|
||||||
form="update-auth-mechanism-form"
|
<Form.Item
|
||||||
htmlType="submit"
|
label="Email"
|
||||||
type="primary">
|
name="email"
|
||||||
{isUpdating ? <Loader size="small" /> : 'Save'}
|
rules={[
|
||||||
</Button>
|
{
|
||||||
</Space>
|
pattern: validEmailRegEx,
|
||||||
</Form>
|
required: true,
|
||||||
|
type: 'email',
|
||||||
|
message: jsonData['form-error-messages']['invalid-email'],
|
||||||
|
},
|
||||||
|
]}>
|
||||||
|
<Input
|
||||||
|
data-testid="email"
|
||||||
|
name="email"
|
||||||
|
placeholder="email"
|
||||||
|
value={accountEmail}
|
||||||
|
onChange={handleOnChange}
|
||||||
|
/>
|
||||||
|
</Form.Item>
|
||||||
|
{getSSOConfig()}
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
<Space className="w-full tw-justify-end" size={4}>
|
||||||
|
{!isEmpty(authenticationMechanism) && (
|
||||||
|
<Button data-testid="cancel-edit" type="link" onClick={onCancel}>
|
||||||
|
Cancel
|
||||||
|
</Button>
|
||||||
|
)}
|
||||||
|
<Button
|
||||||
|
data-testid="save-edit"
|
||||||
|
form="update-auth-mechanism-form"
|
||||||
|
htmlType="submit"
|
||||||
|
type="primary">
|
||||||
|
{isUpdating ? <Loader size="small" /> : 'Save'}
|
||||||
|
</Button>
|
||||||
|
</Space>
|
||||||
|
</Form>
|
||||||
|
{isConfirmationModalOpen && (
|
||||||
|
<Modal
|
||||||
|
centered
|
||||||
|
destroyOnClose
|
||||||
|
okText="Confirm"
|
||||||
|
title="Are you sure?"
|
||||||
|
visible={isConfirmationModalOpen}
|
||||||
|
onCancel={() => setIsConfirmationModalOpen(false)}
|
||||||
|
onOk={handleAccountEmailChange}>
|
||||||
|
<Typography.Text>
|
||||||
|
{BOT_ACCOUNT_EMAIL_CHANGE_CONFIRMATION} for {botData.name} bot.
|
||||||
|
</Typography.Text>
|
||||||
|
</Modal>
|
||||||
|
)}
|
||||||
|
</>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -22,20 +22,22 @@ import React, {
|
|||||||
useMemo,
|
useMemo,
|
||||||
useState,
|
useState,
|
||||||
} from 'react';
|
} from 'react';
|
||||||
|
import { createBotWithPut } from '../../axiosAPIs/botsAPI';
|
||||||
import {
|
import {
|
||||||
|
createUserWithPut,
|
||||||
getAuthMechanismForBotUser,
|
getAuthMechanismForBotUser,
|
||||||
updateUser,
|
|
||||||
} from '../../axiosAPIs/userAPI';
|
} from '../../axiosAPIs/userAPI';
|
||||||
import {
|
import {
|
||||||
GlobalSettingOptions,
|
GlobalSettingOptions,
|
||||||
GlobalSettingsMenuCategory,
|
GlobalSettingsMenuCategory,
|
||||||
} from '../../constants/globalSettings.constants';
|
} from '../../constants/globalSettings.constants';
|
||||||
|
import { EntityType } from '../../enums/entity.enum';
|
||||||
|
import { Bot } from '../../generated/entity/bot';
|
||||||
import {
|
import {
|
||||||
AuthenticationMechanism,
|
AuthenticationMechanism,
|
||||||
AuthType,
|
AuthType,
|
||||||
User,
|
User,
|
||||||
} from '../../generated/entity/teams/user';
|
} from '../../generated/entity/teams/user';
|
||||||
import { EntityReference } from '../../generated/type/entityReference';
|
|
||||||
import { getEntityName } from '../../utils/CommonUtils';
|
import { getEntityName } from '../../utils/CommonUtils';
|
||||||
import { getSettingPath } from '../../utils/RouterUtils';
|
import { getSettingPath } from '../../utils/RouterUtils';
|
||||||
import SVGIcons, { Icons } from '../../utils/SvgUtils';
|
import SVGIcons, { Icons } from '../../utils/SvgUtils';
|
||||||
@ -51,19 +53,23 @@ import AuthMechanism from './AuthMechanism';
|
|||||||
import AuthMechanismForm from './AuthMechanismForm';
|
import AuthMechanismForm from './AuthMechanismForm';
|
||||||
|
|
||||||
interface BotsDetailProp extends HTMLAttributes<HTMLDivElement> {
|
interface BotsDetailProp extends HTMLAttributes<HTMLDivElement> {
|
||||||
botsData: User;
|
botUserData: User;
|
||||||
|
botData: Bot;
|
||||||
botPermission: OperationPermission;
|
botPermission: OperationPermission;
|
||||||
updateBotsDetails: (data: UserDetails) => Promise<void>;
|
updateBotsDetails: (data: UserDetails) => Promise<void>;
|
||||||
revokeTokenHandler: () => void;
|
revokeTokenHandler: () => void;
|
||||||
|
onEmailChange: () => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
const BotDetails: FC<BotsDetailProp> = ({
|
const BotDetails: FC<BotsDetailProp> = ({
|
||||||
botsData,
|
botData,
|
||||||
|
botUserData,
|
||||||
updateBotsDetails,
|
updateBotsDetails,
|
||||||
revokeTokenHandler,
|
revokeTokenHandler,
|
||||||
botPermission,
|
botPermission,
|
||||||
|
onEmailChange,
|
||||||
}) => {
|
}) => {
|
||||||
const [displayName, setDisplayName] = useState(botsData.displayName);
|
const [displayName, setDisplayName] = useState(botData.displayName);
|
||||||
const [isDisplayNameEdit, setIsDisplayNameEdit] = useState(false);
|
const [isDisplayNameEdit, setIsDisplayNameEdit] = useState(false);
|
||||||
const [isDescriptionEdit, setIsDescriptionEdit] = useState(false);
|
const [isDescriptionEdit, setIsDescriptionEdit] = useState(false);
|
||||||
const [isRevokingToken, setIsRevokingToken] = useState<boolean>(false);
|
const [isRevokingToken, setIsRevokingToken] = useState<boolean>(false);
|
||||||
@ -92,7 +98,7 @@ const BotDetails: FC<BotsDetailProp> = ({
|
|||||||
|
|
||||||
const fetchAuthMechanismForBot = async () => {
|
const fetchAuthMechanismForBot = async () => {
|
||||||
try {
|
try {
|
||||||
const response = await getAuthMechanismForBotUser(botsData.id);
|
const response = await getAuthMechanismForBotUser(botUserData.id);
|
||||||
setAuthenticationMechanism(response);
|
setAuthenticationMechanism(response);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
showErrorToast(error as AxiosError);
|
showErrorToast(error as AxiosError);
|
||||||
@ -106,7 +112,6 @@ const BotDetails: FC<BotsDetailProp> = ({
|
|||||||
try {
|
try {
|
||||||
const {
|
const {
|
||||||
isAdmin,
|
isAdmin,
|
||||||
teams,
|
|
||||||
timezone,
|
timezone,
|
||||||
name,
|
name,
|
||||||
description,
|
description,
|
||||||
@ -114,11 +119,9 @@ const BotDetails: FC<BotsDetailProp> = ({
|
|||||||
profile,
|
profile,
|
||||||
email,
|
email,
|
||||||
isBot,
|
isBot,
|
||||||
roles,
|
} = botUserData;
|
||||||
} = botsData;
|
const response = await createUserWithPut({
|
||||||
const response = await updateUser({
|
|
||||||
isAdmin,
|
isAdmin,
|
||||||
teams,
|
|
||||||
timezone,
|
timezone,
|
||||||
name,
|
name,
|
||||||
description,
|
description,
|
||||||
@ -126,9 +129,8 @@ const BotDetails: FC<BotsDetailProp> = ({
|
|||||||
profile,
|
profile,
|
||||||
email,
|
email,
|
||||||
isBot,
|
isBot,
|
||||||
roles,
|
|
||||||
authenticationMechanism: {
|
authenticationMechanism: {
|
||||||
...botsData.authenticationMechanism,
|
...botUserData.authenticationMechanism,
|
||||||
authType: updatedAuthMechanism.authType,
|
authType: updatedAuthMechanism.authType,
|
||||||
config:
|
config:
|
||||||
updatedAuthMechanism.authType === AuthType.Jwt
|
updatedAuthMechanism.authType === AuthType.Jwt
|
||||||
@ -140,8 +142,15 @@ const BotDetails: FC<BotsDetailProp> = ({
|
|||||||
authConfig: updatedAuthMechanism.config?.authConfig,
|
authConfig: updatedAuthMechanism.config?.authConfig,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
} as User);
|
botName: botData.name,
|
||||||
if (response.data) {
|
});
|
||||||
|
if (response) {
|
||||||
|
await createBotWithPut({
|
||||||
|
name: botData.name,
|
||||||
|
description: botData.description,
|
||||||
|
displayName: botData.displayName,
|
||||||
|
botUser: { id: response.id, type: EntityType.USER },
|
||||||
|
});
|
||||||
fetchAuthMechanismForBot();
|
fetchAuthMechanismForBot();
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
@ -159,7 +168,7 @@ const BotDetails: FC<BotsDetailProp> = ({
|
|||||||
};
|
};
|
||||||
|
|
||||||
const handleDisplayNameChange = () => {
|
const handleDisplayNameChange = () => {
|
||||||
if (displayName !== botsData.displayName) {
|
if (displayName !== botData.displayName) {
|
||||||
updateBotsDetails({ displayName: displayName || '' });
|
updateBotsDetails({ displayName: displayName || '' });
|
||||||
}
|
}
|
||||||
setIsDisplayNameEdit(false);
|
setIsDisplayNameEdit(false);
|
||||||
@ -243,8 +252,8 @@ const BotDetails: FC<BotsDetailProp> = ({
|
|||||||
return (
|
return (
|
||||||
<div className="tw--ml-5">
|
<div className="tw--ml-5">
|
||||||
<Description
|
<Description
|
||||||
description={botsData.description || ''}
|
description={botData.description || ''}
|
||||||
entityName={getEntityName(botsData as unknown as EntityReference)}
|
entityName={getEntityName(botData)}
|
||||||
hasEditAccess={descriptionPermission || editAllPermission}
|
hasEditAccess={descriptionPermission || editAllPermission}
|
||||||
isEdit={isDescriptionEdit}
|
isEdit={isDescriptionEdit}
|
||||||
onCancel={() => setIsDescriptionEdit(false)}
|
onCancel={() => setIsDescriptionEdit(false)}
|
||||||
@ -303,10 +312,10 @@ const BotDetails: FC<BotsDetailProp> = ({
|
|||||||
);
|
);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (botsData.id) {
|
if (botUserData.id) {
|
||||||
fetchAuthMechanismForBot();
|
fetchAuthMechanismForBot();
|
||||||
}
|
}
|
||||||
}, [botsData]);
|
}, [botUserData]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<PageLayout
|
<PageLayout
|
||||||
@ -322,7 +331,7 @@ const BotDetails: FC<BotsDetailProp> = ({
|
|||||||
GlobalSettingOptions.BOTS
|
GlobalSettingOptions.BOTS
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
{ name: botsData.name || '', url: '', activeTitle: true },
|
{ name: botData.name || '', url: '', activeTitle: true },
|
||||||
]}
|
]}
|
||||||
/>
|
/>
|
||||||
}
|
}
|
||||||
@ -339,13 +348,17 @@ const BotDetails: FC<BotsDetailProp> = ({
|
|||||||
{isAuthMechanismEdit ? (
|
{isAuthMechanismEdit ? (
|
||||||
<AuthMechanismForm
|
<AuthMechanismForm
|
||||||
authenticationMechanism={authenticationMechanism}
|
authenticationMechanism={authenticationMechanism}
|
||||||
|
botData={botData}
|
||||||
|
botUser={botUserData}
|
||||||
isUpdating={isUpdating}
|
isUpdating={isUpdating}
|
||||||
onCancel={() => setIsAuthMechanismEdit(false)}
|
onCancel={() => setIsAuthMechanismEdit(false)}
|
||||||
|
onEmailChange={onEmailChange}
|
||||||
onSave={handleAuthMechanismUpdate}
|
onSave={handleAuthMechanismUpdate}
|
||||||
/>
|
/>
|
||||||
) : (
|
) : (
|
||||||
<AuthMechanism
|
<AuthMechanism
|
||||||
authenticationMechanism={authenticationMechanism}
|
authenticationMechanism={authenticationMechanism}
|
||||||
|
botUser={botUserData}
|
||||||
hasPermission={editAllPermission}
|
hasPermission={editAllPermission}
|
||||||
onEdit={handleAuthMechanismEdit}
|
onEdit={handleAuthMechanismEdit}
|
||||||
onTokenRevoke={() => setIsRevokingToken(true)}
|
onTokenRevoke={() => setIsRevokingToken(true)}
|
||||||
@ -355,8 +368,11 @@ const BotDetails: FC<BotsDetailProp> = ({
|
|||||||
) : (
|
) : (
|
||||||
<AuthMechanismForm
|
<AuthMechanismForm
|
||||||
authenticationMechanism={{} as AuthenticationMechanism}
|
authenticationMechanism={{} as AuthenticationMechanism}
|
||||||
|
botData={botData}
|
||||||
|
botUser={botUserData}
|
||||||
isUpdating={isUpdating}
|
isUpdating={isUpdating}
|
||||||
onCancel={() => setIsAuthMechanismEdit(false)}
|
onCancel={() => setIsAuthMechanismEdit(false)}
|
||||||
|
onEmailChange={onEmailChange}
|
||||||
onSave={handleAuthMechanismUpdate}
|
onSave={handleAuthMechanismUpdate}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
@ -20,8 +20,9 @@ import BotDetails from './BotDetails.component';
|
|||||||
|
|
||||||
const revokeTokenHandler = jest.fn();
|
const revokeTokenHandler = jest.fn();
|
||||||
const updateBotsDetails = jest.fn();
|
const updateBotsDetails = jest.fn();
|
||||||
|
const onEmailChange = jest.fn();
|
||||||
|
|
||||||
const botsData = {
|
const botUserData = {
|
||||||
id: 'ea09aed1-0251-4a75-b92a-b65641610c53',
|
id: 'ea09aed1-0251-4a75-b92a-b65641610c53',
|
||||||
name: 'sachinchaurasiyachotey87',
|
name: 'sachinchaurasiyachotey87',
|
||||||
fullyQualifiedName: 'sachinchaurasiyachotey87',
|
fullyQualifiedName: 'sachinchaurasiyachotey87',
|
||||||
@ -36,6 +37,26 @@ const botsData = {
|
|||||||
deleted: false,
|
deleted: false,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const botData = {
|
||||||
|
id: '4755f87d-2a53-4376-97e6-fc072f29cf5a',
|
||||||
|
name: 'ingestion-bot',
|
||||||
|
fullyQualifiedName: 'ingestion-bot',
|
||||||
|
displayName: 'ingestion-bot',
|
||||||
|
botUser: {
|
||||||
|
id: 'b91d42cb-2a02-4364-ae80-db08b77f1b0c',
|
||||||
|
type: 'user',
|
||||||
|
name: 'ingestion-bot',
|
||||||
|
fullyQualifiedName: 'ingestion-bot',
|
||||||
|
deleted: false,
|
||||||
|
href: 'http://localhost:8585/api/v1/users/b91d42cb-2a02-4364-ae80-db08b77f1b0c',
|
||||||
|
},
|
||||||
|
version: 0.1,
|
||||||
|
updatedAt: 1664267598781,
|
||||||
|
updatedBy: 'ingestion-bot',
|
||||||
|
href: 'http://localhost:8585/api/v1/bots/4755f87d-2a53-4376-97e6-fc072f29cf5a',
|
||||||
|
deleted: false,
|
||||||
|
};
|
||||||
|
|
||||||
const mockAuthMechanism = {
|
const mockAuthMechanism = {
|
||||||
config: {
|
config: {
|
||||||
JWTToken:
|
JWTToken:
|
||||||
@ -48,7 +69,8 @@ const mockAuthMechanism = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const mockProp = {
|
const mockProp = {
|
||||||
botsData,
|
botUserData,
|
||||||
|
botData,
|
||||||
botPermission: {
|
botPermission: {
|
||||||
Create: true,
|
Create: true,
|
||||||
Delete: true,
|
Delete: true,
|
||||||
@ -60,6 +82,7 @@ const mockProp = {
|
|||||||
} as OperationPermission,
|
} as OperationPermission,
|
||||||
revokeTokenHandler,
|
revokeTokenHandler,
|
||||||
updateBotsDetails,
|
updateBotsDetails,
|
||||||
|
onEmailChange,
|
||||||
};
|
};
|
||||||
|
|
||||||
jest.mock('../../utils/PermissionsUtils', () => ({
|
jest.mock('../../utils/PermissionsUtils', () => ({
|
||||||
@ -68,7 +91,9 @@ jest.mock('../../utils/PermissionsUtils', () => ({
|
|||||||
|
|
||||||
jest.mock('../../axiosAPIs/userAPI', () => {
|
jest.mock('../../axiosAPIs/userAPI', () => {
|
||||||
return {
|
return {
|
||||||
updateUser: jest.fn().mockImplementation(() => Promise.resolve(botsData)),
|
createUserWithPut: jest
|
||||||
|
.fn()
|
||||||
|
.mockImplementation(() => Promise.resolve(botUserData)),
|
||||||
getAuthMechanismForBotUser: jest
|
getAuthMechanismForBotUser: jest
|
||||||
.fn()
|
.fn()
|
||||||
.mockImplementation(() => Promise.resolve(mockAuthMechanism)),
|
.mockImplementation(() => Promise.resolve(mockAuthMechanism)),
|
||||||
|
@ -24,9 +24,12 @@ import {
|
|||||||
PAGE_SIZE_LARGE,
|
PAGE_SIZE_LARGE,
|
||||||
} from '../../constants/constants';
|
} from '../../constants/constants';
|
||||||
import { BOTS_DOCS } from '../../constants/docs.constants';
|
import { BOTS_DOCS } from '../../constants/docs.constants';
|
||||||
import { NO_PERMISSION_FOR_ACTION } from '../../constants/HelperTextUtil';
|
import {
|
||||||
|
INGESTION_BOT_CANT_BE_DELETED,
|
||||||
|
NO_PERMISSION_FOR_ACTION,
|
||||||
|
} from '../../constants/HelperTextUtil';
|
||||||
import { EntityType } from '../../enums/entity.enum';
|
import { EntityType } from '../../enums/entity.enum';
|
||||||
import { Bot } from '../../generated/entity/bot';
|
import { Bot, BotType } from '../../generated/entity/bot';
|
||||||
import { Operation } from '../../generated/entity/policies/accessControl/rule';
|
import { Operation } from '../../generated/entity/policies/accessControl/rule';
|
||||||
import { Include } from '../../generated/type/include';
|
import { Include } from '../../generated/type/include';
|
||||||
import { Paging } from '../../generated/type/paging';
|
import { Paging } from '../../generated/type/paging';
|
||||||
@ -114,11 +117,9 @@ const BotListV1 = ({
|
|||||||
render: (_, record) => (
|
render: (_, record) => (
|
||||||
<Link
|
<Link
|
||||||
className="hover:tw-underline tw-cursor-pointer"
|
className="hover:tw-underline tw-cursor-pointer"
|
||||||
data-testid={`bot-link-${getEntityName(record?.botUser)}`}
|
data-testid={`bot-link-${getEntityName(record)}`}
|
||||||
to={getBotsPath(
|
to={getBotsPath(record?.fullyQualifiedName || record?.name || '')}>
|
||||||
record?.botUser?.fullyQualifiedName || record?.botUser?.name || ''
|
{getEntityName(record)}
|
||||||
)}>
|
|
||||||
{getEntityName(record?.botUser)}
|
|
||||||
</Link>
|
</Link>
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
@ -127,10 +128,8 @@ const BotListV1 = ({
|
|||||||
dataIndex: 'description',
|
dataIndex: 'description',
|
||||||
key: 'description',
|
key: 'description',
|
||||||
render: (_, record) =>
|
render: (_, record) =>
|
||||||
record?.botUser?.description ? (
|
record?.description ? (
|
||||||
<RichTextEditorPreviewer
|
<RichTextEditorPreviewer markdown={record?.description || ''} />
|
||||||
markdown={record?.botUser?.description || ''}
|
|
||||||
/>
|
|
||||||
) : (
|
) : (
|
||||||
<span data-testid="no-description">No Description</span>
|
<span data-testid="no-description">No Description</span>
|
||||||
),
|
),
|
||||||
@ -140,27 +139,35 @@ const BotListV1 = ({
|
|||||||
dataIndex: 'id',
|
dataIndex: 'id',
|
||||||
key: 'id',
|
key: 'id',
|
||||||
width: 90,
|
width: 90,
|
||||||
render: (_, record) => (
|
render: (_, record) => {
|
||||||
<Space align="center" size={8}>
|
const isIngestionBot = record.botType === BotType.IngestionBot;
|
||||||
<Tooltip
|
const title = isIngestionBot
|
||||||
placement="bottom"
|
? INGESTION_BOT_CANT_BE_DELETED
|
||||||
title={deletePermission ? 'Delete' : NO_PERMISSION_FOR_ACTION}>
|
: deletePermission
|
||||||
<Button
|
? 'Delete'
|
||||||
data-testid={`bot-delete-${getEntityName(record?.botUser)}`}
|
: NO_PERMISSION_FOR_ACTION;
|
||||||
disabled={!deletePermission}
|
const isDisabled = !deletePermission || isIngestionBot;
|
||||||
icon={
|
|
||||||
<SVGIcons
|
return (
|
||||||
alt="Delete"
|
<Space align="center" size={8}>
|
||||||
className="tw-w-4"
|
<Tooltip placement="bottom" title={title}>
|
||||||
icon={Icons.DELETE}
|
<Button
|
||||||
/>
|
data-testid={`bot-delete-${getEntityName(record)}`}
|
||||||
}
|
disabled={isDisabled}
|
||||||
type="text"
|
icon={
|
||||||
onClick={() => setSelectedUser(record)}
|
<SVGIcons
|
||||||
/>
|
alt="Delete"
|
||||||
</Tooltip>
|
className="tw-w-4"
|
||||||
</Space>
|
icon={Icons.DELETE}
|
||||||
),
|
/>
|
||||||
|
}
|
||||||
|
type="text"
|
||||||
|
onClick={() => setSelectedUser(record)}
|
||||||
|
/>
|
||||||
|
</Tooltip>
|
||||||
|
</Space>
|
||||||
|
);
|
||||||
|
},
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
[]
|
[]
|
||||||
|
@ -28,7 +28,7 @@ import { isUndefined } from 'lodash';
|
|||||||
import { EditorContentRef } from 'Models';
|
import { EditorContentRef } from 'Models';
|
||||||
import React, { useMemo, useRef, useState } from 'react';
|
import React, { useMemo, useRef, useState } from 'react';
|
||||||
import { useAuthContext } from '../../authentication/auth-provider/AuthProvider';
|
import { useAuthContext } from '../../authentication/auth-provider/AuthProvider';
|
||||||
import { generateRandomPwd } from '../../axiosAPIs/auth-API';
|
import { checkEmailInUse, generateRandomPwd } from '../../axiosAPIs/auth-API';
|
||||||
import { getBotsPagePath, getUsersPagePath } from '../../constants/constants';
|
import { getBotsPagePath, getUsersPagePath } from '../../constants/constants';
|
||||||
import { passwordErrorMessage } from '../../constants/error-message';
|
import { passwordErrorMessage } from '../../constants/error-message';
|
||||||
import {
|
import {
|
||||||
@ -321,11 +321,6 @@ const CreateUser = ({
|
|||||||
email: email,
|
email: email,
|
||||||
isAdmin: isAdmin,
|
isAdmin: isAdmin,
|
||||||
isBot: isBot,
|
isBot: isBot,
|
||||||
password: isPasswordGenerated ? generatedPassword : password,
|
|
||||||
confirmPassword: isPasswordGenerated
|
|
||||||
? generatedPassword
|
|
||||||
: confirmPassword,
|
|
||||||
createPasswordType: CreatePasswordType.Admincreate,
|
|
||||||
...(forceBot
|
...(forceBot
|
||||||
? {
|
? {
|
||||||
authenticationMechanism: {
|
authenticationMechanism: {
|
||||||
@ -343,7 +338,13 @@ const CreateUser = ({
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
: {}),
|
: {
|
||||||
|
password: isPasswordGenerated ? generatedPassword : password,
|
||||||
|
confirmPassword: isPasswordGenerated
|
||||||
|
? generatedPassword
|
||||||
|
: confirmPassword,
|
||||||
|
createPasswordType: CreatePasswordType.Admincreate,
|
||||||
|
}),
|
||||||
};
|
};
|
||||||
onSave(userProfile);
|
onSave(userProfile);
|
||||||
};
|
};
|
||||||
@ -691,14 +692,26 @@ const CreateUser = ({
|
|||||||
name="email"
|
name="email"
|
||||||
rules={[
|
rules={[
|
||||||
{
|
{
|
||||||
|
pattern: validEmailRegEx,
|
||||||
required: true,
|
required: true,
|
||||||
type: 'email',
|
type: 'email',
|
||||||
message: jsonData['form-error-messages']['empty-email'],
|
message: jsonData['form-error-messages']['invalid-email'],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
pattern: validEmailRegEx,
|
|
||||||
type: 'email',
|
type: 'email',
|
||||||
message: jsonData['form-error-messages']['invalid-email'],
|
required: true,
|
||||||
|
validator: async (_, value) => {
|
||||||
|
if (validEmailRegEx.test(value) && !forceBot) {
|
||||||
|
const isEmailAlreadyExists = await checkEmailInUse(value);
|
||||||
|
if (isEmailAlreadyExists) {
|
||||||
|
return Promise.reject(
|
||||||
|
jsonData['form-error-messages']['email-is-in-use']
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return Promise.resolve();
|
||||||
|
}
|
||||||
|
},
|
||||||
},
|
},
|
||||||
]}>
|
]}>
|
||||||
<Input
|
<Input
|
||||||
@ -781,111 +794,111 @@ const CreateUser = ({
|
|||||||
<RichTextEditor initialValue={description} ref={markdownRef} />
|
<RichTextEditor initialValue={description} ref={markdownRef} />
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
|
|
||||||
{isAuthProviderBasic && (
|
|
||||||
<>
|
|
||||||
<Radio.Group
|
|
||||||
name="passwordGenerator"
|
|
||||||
value={passwordGenerator}
|
|
||||||
onChange={handleOnChange}>
|
|
||||||
<Radio value={CreatePasswordGenerator.AutomatciGenerate}>
|
|
||||||
Automatic Generate
|
|
||||||
</Radio>
|
|
||||||
<Radio value={CreatePasswordGenerator.CreatePassword}>
|
|
||||||
Create Password
|
|
||||||
</Radio>
|
|
||||||
</Radio.Group>
|
|
||||||
|
|
||||||
{passwordGenerator === CreatePasswordGenerator.CreatePassword ? (
|
|
||||||
<div className="m-t-sm">
|
|
||||||
<Form.Item
|
|
||||||
label="Password"
|
|
||||||
name="password"
|
|
||||||
rules={[
|
|
||||||
{
|
|
||||||
required: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
pattern: passwordRegex,
|
|
||||||
message: passwordErrorMessage,
|
|
||||||
},
|
|
||||||
]}>
|
|
||||||
<Input.Password
|
|
||||||
name="password"
|
|
||||||
placeholder="Enter a Password"
|
|
||||||
value={password}
|
|
||||||
onChange={handleOnChange}
|
|
||||||
/>
|
|
||||||
</Form.Item>
|
|
||||||
|
|
||||||
<Form.Item
|
|
||||||
label="Confirm Password"
|
|
||||||
name="confirmPassword"
|
|
||||||
rules={[
|
|
||||||
{
|
|
||||||
validator: (_, value) => {
|
|
||||||
if (value !== password) {
|
|
||||||
return Promise.reject("Password doesn't match");
|
|
||||||
}
|
|
||||||
|
|
||||||
return Promise.resolve();
|
|
||||||
},
|
|
||||||
},
|
|
||||||
]}>
|
|
||||||
<Input.Password
|
|
||||||
name="confirmPassword"
|
|
||||||
placeholder="Confirm Password"
|
|
||||||
value={confirmPassword}
|
|
||||||
onChange={handleOnChange}
|
|
||||||
/>
|
|
||||||
</Form.Item>
|
|
||||||
</div>
|
|
||||||
) : (
|
|
||||||
<div className="m-t-sm">
|
|
||||||
<Form.Item
|
|
||||||
label="Generated Password"
|
|
||||||
name="generatedPassword"
|
|
||||||
rules={[
|
|
||||||
{
|
|
||||||
required: true,
|
|
||||||
},
|
|
||||||
]}>
|
|
||||||
<Input
|
|
||||||
readOnly
|
|
||||||
addonAfter={
|
|
||||||
<div className="flex-center w-16">
|
|
||||||
<div
|
|
||||||
className="w-8 h-7 flex-center cursor-pointer"
|
|
||||||
data-testid="password-generator"
|
|
||||||
onClick={generateRandomPassword}>
|
|
||||||
{isPasswordGenerating ? (
|
|
||||||
<Loader size="small" type="default" />
|
|
||||||
) : (
|
|
||||||
<SVGIcons
|
|
||||||
alt="generate"
|
|
||||||
icon={Icons.SYNC}
|
|
||||||
width="16"
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="w-8 h-7 flex-center">
|
|
||||||
<CopyToClipboardButton
|
|
||||||
copyText={generatedPassword}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
}
|
|
||||||
name="generatedPassword"
|
|
||||||
value={generatedPassword}
|
|
||||||
/>
|
|
||||||
</Form.Item>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</>
|
|
||||||
)}
|
|
||||||
|
|
||||||
{!forceBot && (
|
{!forceBot && (
|
||||||
<>
|
<>
|
||||||
|
{isAuthProviderBasic && (
|
||||||
|
<>
|
||||||
|
<Radio.Group
|
||||||
|
name="passwordGenerator"
|
||||||
|
value={passwordGenerator}
|
||||||
|
onChange={handleOnChange}>
|
||||||
|
<Radio value={CreatePasswordGenerator.AutomatciGenerate}>
|
||||||
|
Automatic Generate
|
||||||
|
</Radio>
|
||||||
|
<Radio value={CreatePasswordGenerator.CreatePassword}>
|
||||||
|
Create Password
|
||||||
|
</Radio>
|
||||||
|
</Radio.Group>
|
||||||
|
|
||||||
|
{passwordGenerator ===
|
||||||
|
CreatePasswordGenerator.CreatePassword ? (
|
||||||
|
<div className="m-t-sm">
|
||||||
|
<Form.Item
|
||||||
|
label="Password"
|
||||||
|
name="password"
|
||||||
|
rules={[
|
||||||
|
{
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
pattern: passwordRegex,
|
||||||
|
message: passwordErrorMessage,
|
||||||
|
},
|
||||||
|
]}>
|
||||||
|
<Input.Password
|
||||||
|
name="password"
|
||||||
|
placeholder="Enter a Password"
|
||||||
|
value={password}
|
||||||
|
onChange={handleOnChange}
|
||||||
|
/>
|
||||||
|
</Form.Item>
|
||||||
|
|
||||||
|
<Form.Item
|
||||||
|
label="Confirm Password"
|
||||||
|
name="confirmPassword"
|
||||||
|
rules={[
|
||||||
|
{
|
||||||
|
validator: (_, value) => {
|
||||||
|
if (value !== password) {
|
||||||
|
return Promise.reject("Password doesn't match");
|
||||||
|
}
|
||||||
|
|
||||||
|
return Promise.resolve();
|
||||||
|
},
|
||||||
|
},
|
||||||
|
]}>
|
||||||
|
<Input.Password
|
||||||
|
name="confirmPassword"
|
||||||
|
placeholder="Confirm Password"
|
||||||
|
value={confirmPassword}
|
||||||
|
onChange={handleOnChange}
|
||||||
|
/>
|
||||||
|
</Form.Item>
|
||||||
|
</div>
|
||||||
|
) : (
|
||||||
|
<div className="m-t-sm">
|
||||||
|
<Form.Item
|
||||||
|
label="Generated Password"
|
||||||
|
name="generatedPassword"
|
||||||
|
rules={[
|
||||||
|
{
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
]}>
|
||||||
|
<Input.Password
|
||||||
|
readOnly
|
||||||
|
addonAfter={
|
||||||
|
<div className="flex-center w-16">
|
||||||
|
<div
|
||||||
|
className="w-8 h-7 flex-center cursor-pointer"
|
||||||
|
data-testid="password-generator"
|
||||||
|
onClick={generateRandomPassword}>
|
||||||
|
{isPasswordGenerating ? (
|
||||||
|
<Loader size="small" type="default" />
|
||||||
|
) : (
|
||||||
|
<SVGIcons
|
||||||
|
alt="generate"
|
||||||
|
icon={Icons.SYNC}
|
||||||
|
width="16"
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="w-8 h-7 flex-center">
|
||||||
|
<CopyToClipboardButton
|
||||||
|
copyText={generatedPassword}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
name="generatedPassword"
|
||||||
|
value={generatedPassword}
|
||||||
|
/>
|
||||||
|
</Form.Item>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</>
|
||||||
|
)}
|
||||||
<Form.Item label="Teams" name="teams">
|
<Form.Item label="Teams" name="teams">
|
||||||
<TeamsSelectable onSelectionChange={setSelectedTeams} />
|
<TeamsSelectable onSelectionChange={setSelectedTeams} />
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
|
@ -63,7 +63,7 @@ describe('Test manage button component', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('Should render delete modal component on click of delete option', async () => {
|
it('Should render delete modal component on click of delete option', async () => {
|
||||||
render(<ManageButton {...mockProps} />);
|
render(<ManageButton {...mockProps} canDelete />);
|
||||||
|
|
||||||
const manageButton = await screen.findByTestId('manage-button');
|
const manageButton = await screen.findByTestId('manage-button');
|
||||||
|
|
||||||
|
@ -51,3 +51,9 @@ export const NO_PERMISSION_TO_VIEW =
|
|||||||
|
|
||||||
export const GROUP_TEAM_TYPE_CHANGE_MSG =
|
export const GROUP_TEAM_TYPE_CHANGE_MSG =
|
||||||
"The team type 'Group' cannot be changed. Please create a new team with the preferred type.";
|
"The team type 'Group' cannot be changed. Please create a new team with the preferred type.";
|
||||||
|
|
||||||
|
export const INGESTION_BOT_CANT_BE_DELETED =
|
||||||
|
'You can not delete the ingestion bot.';
|
||||||
|
|
||||||
|
export const BOT_ACCOUNT_EMAIL_CHANGE_CONFIRMATION =
|
||||||
|
'Changing account email will update or create a new bot user';
|
||||||
|
@ -193,6 +193,7 @@ const jsonData = {
|
|||||||
'invalid-email': 'Email is invalid.',
|
'invalid-email': 'Email is invalid.',
|
||||||
'invalid-url': 'Url is invalid.',
|
'invalid-url': 'Url is invalid.',
|
||||||
'is-required': 'is required',
|
'is-required': 'is required',
|
||||||
|
'email-is-in-use': 'Email is already in use!',
|
||||||
},
|
},
|
||||||
label: {
|
label: {
|
||||||
'delete-entity-text':
|
'delete-entity-text':
|
||||||
|
@ -31,6 +31,26 @@ const mockUserDetail = {
|
|||||||
deleted: false,
|
deleted: false,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const botData = {
|
||||||
|
id: '4755f87d-2a53-4376-97e6-fc072f29cf5a',
|
||||||
|
name: 'ingestion-bot',
|
||||||
|
fullyQualifiedName: 'ingestion-bot',
|
||||||
|
displayName: 'ingestion-bot',
|
||||||
|
botUser: {
|
||||||
|
id: 'b91d42cb-2a02-4364-ae80-db08b77f1b0c',
|
||||||
|
type: 'user',
|
||||||
|
name: 'ingestion-bot',
|
||||||
|
fullyQualifiedName: 'ingestion-bot',
|
||||||
|
deleted: false,
|
||||||
|
href: 'http://localhost:8585/api/v1/users/b91d42cb-2a02-4364-ae80-db08b77f1b0c',
|
||||||
|
},
|
||||||
|
version: 0.1,
|
||||||
|
updatedAt: 1664267598781,
|
||||||
|
updatedBy: 'ingestion-bot',
|
||||||
|
href: 'http://localhost:8585/api/v1/bots/4755f87d-2a53-4376-97e6-fc072f29cf5a',
|
||||||
|
deleted: false,
|
||||||
|
};
|
||||||
|
|
||||||
jest.mock('../../components/BotDetails/BotDetails.component', () => {
|
jest.mock('../../components/BotDetails/BotDetails.component', () => {
|
||||||
return jest
|
return jest
|
||||||
.fn()
|
.fn()
|
||||||
@ -38,6 +58,7 @@ jest.mock('../../components/BotDetails/BotDetails.component', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
jest.mock('../../axiosAPIs/userAPI', () => ({
|
jest.mock('../../axiosAPIs/userAPI', () => ({
|
||||||
|
getBotByName: jest.fn().mockImplementation(() => Promise.resolve(botData)),
|
||||||
getUserByName: jest.fn().mockImplementation(() => Promise.resolve()),
|
getUserByName: jest.fn().mockImplementation(() => Promise.resolve()),
|
||||||
revokeUserToken: jest.fn().mockImplementation(() => Promise.resolve()),
|
revokeUserToken: jest.fn().mockImplementation(() => Promise.resolve()),
|
||||||
updateUserDetail: jest.fn().mockImplementation(() => Promise.resolve()),
|
updateUserDetail: jest.fn().mockImplementation(() => Promise.resolve()),
|
||||||
|
@ -17,9 +17,10 @@ import { compare } from 'fast-json-patch';
|
|||||||
import React, { useEffect, useState } from 'react';
|
import React, { useEffect, useState } from 'react';
|
||||||
import { useParams } from 'react-router-dom';
|
import { useParams } from 'react-router-dom';
|
||||||
import {
|
import {
|
||||||
|
getBotByName,
|
||||||
getUserByName,
|
getUserByName,
|
||||||
revokeUserToken,
|
revokeUserToken,
|
||||||
updateUserDetail,
|
updateBotDetail,
|
||||||
} from '../../axiosAPIs/userAPI';
|
} from '../../axiosAPIs/userAPI';
|
||||||
import BotDetails from '../../components/BotDetails/BotDetails.component';
|
import BotDetails from '../../components/BotDetails/BotDetails.component';
|
||||||
import ErrorPlaceHolder from '../../components/common/error-with-placeholder/ErrorPlaceHolder';
|
import ErrorPlaceHolder from '../../components/common/error-with-placeholder/ErrorPlaceHolder';
|
||||||
@ -32,6 +33,7 @@ import {
|
|||||||
} from '../../components/PermissionProvider/PermissionProvider.interface';
|
} from '../../components/PermissionProvider/PermissionProvider.interface';
|
||||||
import { UserDetails } from '../../components/Users/Users.interface';
|
import { UserDetails } from '../../components/Users/Users.interface';
|
||||||
import { NO_PERMISSION_TO_VIEW } from '../../constants/HelperTextUtil';
|
import { NO_PERMISSION_TO_VIEW } from '../../constants/HelperTextUtil';
|
||||||
|
import { Bot } from '../../generated/entity/bot';
|
||||||
import { User } from '../../generated/entity/teams/user';
|
import { User } from '../../generated/entity/teams/user';
|
||||||
import jsonData from '../../jsons/en';
|
import jsonData from '../../jsons/en';
|
||||||
import { DEFAULT_ENTITY_PERMISSION } from '../../utils/PermissionsUtils';
|
import { DEFAULT_ENTITY_PERMISSION } from '../../utils/PermissionsUtils';
|
||||||
@ -40,7 +42,8 @@ import { showErrorToast } from '../../utils/ToastUtils';
|
|||||||
const BotDetailsPage = () => {
|
const BotDetailsPage = () => {
|
||||||
const { botsName } = useParams<{ [key: string]: string }>();
|
const { botsName } = useParams<{ [key: string]: string }>();
|
||||||
const { getEntityPermissionByFqn } = usePermissionProvider();
|
const { getEntityPermissionByFqn } = usePermissionProvider();
|
||||||
const [botsData, setBotsData] = useState<User>({} as User);
|
const [botUserData, setBotUserData] = useState<User>({} as User);
|
||||||
|
const [botData, setBotData] = useState<Bot>({} as Bot);
|
||||||
const [isLoading, setIsLoading] = useState(false);
|
const [isLoading, setIsLoading] = useState(false);
|
||||||
const [isError, setIsError] = useState(false);
|
const [isError, setIsError] = useState(false);
|
||||||
const [botPermission, setBotPermission] = useState<OperationPermission>(
|
const [botPermission, setBotPermission] = useState<OperationPermission>(
|
||||||
@ -62,34 +65,32 @@ const BotDetailsPage = () => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const fetchBotsData = () => {
|
const fetchBotsData = async () => {
|
||||||
setIsLoading(true);
|
try {
|
||||||
getUserByName(botsName)
|
setIsLoading(true);
|
||||||
.then((res) => {
|
const botResponse = await getBotByName(botsName);
|
||||||
if (res) {
|
|
||||||
setBotsData(res);
|
const botUserResponse = await getUserByName(
|
||||||
} else {
|
botResponse.botUser.fullyQualifiedName || ''
|
||||||
throw jsonData['api-error-messages']['unexpected-server-response'];
|
);
|
||||||
}
|
setBotUserData(botUserResponse);
|
||||||
})
|
setBotData(botResponse);
|
||||||
.catch((err: AxiosError) => {
|
} catch (error) {
|
||||||
showErrorToast(
|
showErrorToast(error as AxiosError);
|
||||||
err,
|
setIsError(true);
|
||||||
jsonData['api-error-messages']['fetch-user-details-error']
|
} finally {
|
||||||
);
|
setIsLoading(false);
|
||||||
setIsError(true);
|
}
|
||||||
})
|
|
||||||
.finally(() => setIsLoading(false));
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const updateBotsDetails = async (data: UserDetails) => {
|
const updateBotsDetails = async (data: UserDetails) => {
|
||||||
const updatedDetails = { ...botsData, ...data };
|
const updatedDetails = { ...botData, ...data };
|
||||||
const jsonPatch = compare(botsData, updatedDetails);
|
const jsonPatch = compare(botData, updatedDetails);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const response = await updateUserDetail(botsData.id, jsonPatch);
|
const response = await updateBotDetail(botData.id, jsonPatch);
|
||||||
if (response) {
|
if (response) {
|
||||||
setBotsData((prevData) => ({
|
setBotData((prevData) => ({
|
||||||
...prevData,
|
...prevData,
|
||||||
...response,
|
...response,
|
||||||
}));
|
}));
|
||||||
@ -102,10 +103,10 @@ const BotDetailsPage = () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const revokeBotsToken = () => {
|
const revokeBotsToken = () => {
|
||||||
revokeUserToken(botsData.id)
|
revokeUserToken(botUserData.id)
|
||||||
.then((res) => {
|
.then((res) => {
|
||||||
const data = res;
|
const data = res;
|
||||||
setBotsData(data);
|
setBotUserData(data);
|
||||||
})
|
})
|
||||||
.catch((err: AxiosError) => {
|
.catch((err: AxiosError) => {
|
||||||
showErrorToast(err);
|
showErrorToast(err);
|
||||||
@ -129,10 +130,12 @@ const BotDetailsPage = () => {
|
|||||||
} else {
|
} else {
|
||||||
return (
|
return (
|
||||||
<BotDetails
|
<BotDetails
|
||||||
|
botData={botData}
|
||||||
botPermission={botPermission}
|
botPermission={botPermission}
|
||||||
botsData={botsData}
|
botUserData={botUserData}
|
||||||
revokeTokenHandler={revokeBotsToken}
|
revokeTokenHandler={revokeBotsToken}
|
||||||
updateBotsDetails={updateBotsDetails}
|
updateBotsDetails={updateBotsDetails}
|
||||||
|
onEmailChange={fetchBotsData}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -16,9 +16,13 @@ import { observer } from 'mobx-react';
|
|||||||
import { LoadingState } from 'Models';
|
import { LoadingState } from 'Models';
|
||||||
import React, { useEffect, useState } from 'react';
|
import React, { useEffect, useState } from 'react';
|
||||||
import { useHistory, useParams } from 'react-router-dom';
|
import { useHistory, useParams } from 'react-router-dom';
|
||||||
import { createBot } from '../../axiosAPIs/botsAPI';
|
import { createBotWithPut } from '../../axiosAPIs/botsAPI';
|
||||||
import { getRoles } from '../../axiosAPIs/rolesAPIV1';
|
import { getRoles } from '../../axiosAPIs/rolesAPIV1';
|
||||||
import { createUser } from '../../axiosAPIs/userAPI';
|
import {
|
||||||
|
createUser,
|
||||||
|
createUserWithPut,
|
||||||
|
getBotByName,
|
||||||
|
} from '../../axiosAPIs/userAPI';
|
||||||
import PageContainerV1 from '../../components/containers/PageContainerV1';
|
import PageContainerV1 from '../../components/containers/PageContainerV1';
|
||||||
import CreateUserComponent from '../../components/CreateUser/CreateUser.component';
|
import CreateUserComponent from '../../components/CreateUser/CreateUser.component';
|
||||||
import { PAGE_SIZE_LARGE } from '../../constants/constants';
|
import { PAGE_SIZE_LARGE } from '../../constants/constants';
|
||||||
@ -72,56 +76,86 @@ const CreateUserPage = () => {
|
|||||||
setStatus('initial');
|
setStatus('initial');
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const checkBotInUse = async (name: string) => {
|
||||||
|
try {
|
||||||
|
const response = await getBotByName(name);
|
||||||
|
|
||||||
|
return Boolean(response);
|
||||||
|
} catch (_error) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Submit handler for new user form.
|
* Submit handler for new user form.
|
||||||
* @param userData Data for creating new user
|
* @param userData Data for creating new user
|
||||||
*/
|
*/
|
||||||
const handleAddUserSave = (userData: CreateUser) => {
|
const handleAddUserSave = async (userData: CreateUser) => {
|
||||||
setStatus('waiting');
|
if (bot) {
|
||||||
createUser(userData)
|
const isBotExists = await checkBotInUse(userData.name);
|
||||||
.then((res) => {
|
if (isBotExists) {
|
||||||
if (res) {
|
showErrorToast(`${userData.name} bot already exists.`);
|
||||||
if (bot) {
|
} else {
|
||||||
createBot({
|
try {
|
||||||
botUser: { id: res.id, type: EntityType.USER },
|
setStatus('waiting');
|
||||||
name: res.name,
|
// Create a user with isBot:true
|
||||||
displayName: res.displayName,
|
const userResponse = await createUserWithPut({
|
||||||
description: res.description,
|
...userData,
|
||||||
} as Bot)
|
botName: userData.name,
|
||||||
.then((res) => {
|
});
|
||||||
setStatus('success');
|
|
||||||
res && showSuccessToast(`Bot created successfully`);
|
|
||||||
setTimeout(() => {
|
|
||||||
setStatus('initial');
|
|
||||||
|
|
||||||
goToUserListPage();
|
// Create a bot entity with botUser data
|
||||||
}, 500);
|
const botResponse = await createBotWithPut({
|
||||||
})
|
botUser: { id: userResponse.id, type: EntityType.USER },
|
||||||
.catch((err: AxiosError) => {
|
name: userResponse.name,
|
||||||
handleSaveFailure(
|
displayName: userResponse.displayName,
|
||||||
err,
|
description: userResponse.description,
|
||||||
jsonData['api-error-messages']['create-bot-error']
|
} as Bot);
|
||||||
);
|
|
||||||
});
|
if (botResponse) {
|
||||||
} else {
|
|
||||||
setStatus('success');
|
setStatus('success');
|
||||||
|
showSuccessToast(`Bot created successfully`);
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
setStatus('initial');
|
setStatus('initial');
|
||||||
|
|
||||||
goToUserListPage();
|
goToUserListPage();
|
||||||
}, 500);
|
}, 500);
|
||||||
|
} else {
|
||||||
|
handleSaveFailure(
|
||||||
|
jsonData['api-error-messages']['create-bot-error']
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
} catch (error) {
|
||||||
|
handleSaveFailure(
|
||||||
|
error as AxiosError,
|
||||||
|
jsonData['api-error-messages']['create-bot-error']
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
try {
|
||||||
|
setStatus('waiting');
|
||||||
|
|
||||||
|
const response = await createUser(userData);
|
||||||
|
|
||||||
|
if (response) {
|
||||||
|
setStatus('success');
|
||||||
|
setTimeout(() => {
|
||||||
|
setStatus('initial');
|
||||||
|
goToUserListPage();
|
||||||
|
}, 500);
|
||||||
} else {
|
} else {
|
||||||
handleSaveFailure(
|
handleSaveFailure(
|
||||||
jsonData['api-error-messages']['create-user-error']
|
jsonData['api-error-messages']['create-user-error']
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
})
|
} catch (error) {
|
||||||
.catch((err: AxiosError) => {
|
|
||||||
handleSaveFailure(
|
handleSaveFailure(
|
||||||
err,
|
error as AxiosError,
|
||||||
jsonData['api-error-messages']['create-user-error']
|
jsonData['api-error-messages']['create-user-error']
|
||||||
);
|
);
|
||||||
});
|
}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const fetchRoles = async () => {
|
const fetchRoles = async () => {
|
||||||
|
@ -14,8 +14,9 @@
|
|||||||
import { isUndefined } from 'lodash';
|
import { isUndefined } from 'lodash';
|
||||||
import moment from 'moment';
|
import moment from 'moment';
|
||||||
import { AuthTypes } from '../enums/signin.enum';
|
import { AuthTypes } from '../enums/signin.enum';
|
||||||
|
import { AuthenticationMechanism } from '../generated/api/teams/createUser';
|
||||||
import { SsoServiceType } from '../generated/entity/teams/authN/ssoAuth';
|
import { SsoServiceType } from '../generated/entity/teams/authN/ssoAuth';
|
||||||
import { AuthType, JWTTokenExpiry } from '../generated/entity/teams/user';
|
import { AuthType, JWTTokenExpiry, User } from '../generated/entity/teams/user';
|
||||||
|
|
||||||
export const getJWTTokenExpiryOptions = () => {
|
export const getJWTTokenExpiryOptions = () => {
|
||||||
return Object.keys(JWTTokenExpiry).map((expiry) => {
|
return Object.keys(JWTTokenExpiry).map((expiry) => {
|
||||||
@ -114,9 +115,34 @@ export const getTokenExpiry = (expiry: number) => {
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
export const DEFAULT_GOOGLE_SSO_CLIENT_CONFIG = {
|
export const getAuthMechanismFormInitialValues = (
|
||||||
secretKey: '',
|
authMechanism: AuthenticationMechanism,
|
||||||
audience: 'https://www.googleapis.com/oauth2/v4/token',
|
botUser: User
|
||||||
};
|
) => {
|
||||||
|
const authConfig = authMechanism.config?.authConfig;
|
||||||
|
const email = botUser.email;
|
||||||
|
|
||||||
export const SECRET_KEY_ERROR_MSG = 'SecretKey is required!';
|
return {
|
||||||
|
audience: authConfig?.audience,
|
||||||
|
secretKey: authConfig?.secretKey,
|
||||||
|
|
||||||
|
clientId: authConfig?.clientId,
|
||||||
|
|
||||||
|
oktaEmail: authConfig?.email,
|
||||||
|
|
||||||
|
orgURL: authConfig?.orgURL,
|
||||||
|
|
||||||
|
privateKey: authConfig?.privateKey,
|
||||||
|
|
||||||
|
scopes: authConfig?.scopes?.join(','),
|
||||||
|
|
||||||
|
domain: authConfig?.domain,
|
||||||
|
|
||||||
|
authority: authConfig?.authority,
|
||||||
|
|
||||||
|
clientSecret: authConfig?.clientSecret,
|
||||||
|
|
||||||
|
tokenEndpoint: authConfig?.tokenEndpoint,
|
||||||
|
email,
|
||||||
|
};
|
||||||
|
};
|
||||||
|
Loading…
x
Reference in New Issue
Block a user