bump(ui): rjsf to v5 (#11549)

* bump(ui): rjsf to v5
It will fix validation and extra parameter issues

* address comments
fix code smells
fix cypress failure

* revert schema files

* bigquery fix
sonar cloud fix

* fix big query

* fix superset

* fix cypress

* fix cypress for big query

* fix failures

* fix java issue

* revert connectionBasicType.json
create custom SupersetConnection.json

* fix Tableau service issues #11637
This commit is contained in:
Chirag Madlani 2023-05-18 20:33:54 +05:30 committed by GitHub
parent 2b7ee97d52
commit 763b96b8fe
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
21 changed files with 579 additions and 167 deletions

View File

@ -30,7 +30,7 @@ from metadata.generated.schema.entity.services.connections.database.postgresConn
PostgresConnection, PostgresConnection,
) )
from metadata.generated.schema.entity.utils.supersetApiConnection import ( from metadata.generated.schema.entity.utils.supersetApiConnection import (
SupersetAPIConnection, SupersetApiConnection,
) )
from metadata.ingestion.connections.test_connections import ( from metadata.ingestion.connections.test_connections import (
test_connection_engine_step, test_connection_engine_step,
@ -55,7 +55,7 @@ def get_connection(connection: SupersetConnection) -> SupersetAPIClient:
""" """
Create connection Create connection
""" """
if isinstance(connection.connection, SupersetAPIConnection): if isinstance(connection.connection, SupersetApiConnection):
return SupersetAPIClient(connection) return SupersetAPIClient(connection)
if isinstance(connection.connection, PostgresConnection): if isinstance(connection.connection, PostgresConnection):
return pg_get_connection(connection=connection.connection) return pg_get_connection(connection=connection.connection)

View File

@ -18,7 +18,7 @@ from metadata.generated.schema.entity.services.connections.metadata.openMetadata
OpenMetadataConnection, OpenMetadataConnection,
) )
from metadata.generated.schema.entity.utils.supersetApiConnection import ( from metadata.generated.schema.entity.utils.supersetApiConnection import (
SupersetAPIConnection, SupersetApiConnection,
) )
from metadata.generated.schema.metadataIngestion.workflow import ( from metadata.generated.schema.metadataIngestion.workflow import (
Source as WorkflowSource, Source as WorkflowSource,
@ -41,6 +41,6 @@ class SupersetSource:
raise InvalidSourceException( raise InvalidSourceException(
f"Expected SupersetConnection, but got {connection}" f"Expected SupersetConnection, but got {connection}"
) )
if isinstance(connection.connection, SupersetAPIConnection): if isinstance(connection.connection, SupersetApiConnection):
return SupersetAPISource(config, metadata_config) return SupersetAPISource(config, metadata_config)
return SupersetDBSource(config, metadata_config) return SupersetDBSource(config, metadata_config)

View File

@ -1,7 +1,7 @@
{ {
"$id": "https://open-metadata.org/schema/entity/services/connections/dashboard/supersetConnection.json", "$id": "https://open-metadata.org/schema/entity/services/connections/dashboard/supersetApiConnection.json",
"$schema": "http://json-schema.org/draft-07/schema#", "$schema": "http://json-schema.org/draft-07/schema#",
"title": "SupersetAPIConnection", "title": "SupersetApiConnection",
"description": "Superset API Connection Config", "description": "Superset API Connection Config",
"type": "object", "type": "object",
"definitions": { "definitions": {

View File

@ -37,29 +37,31 @@ describe('BigQuery Ingestion', () => {
goToAddNewServicePage(SERVICE_TYPE.Database); goToAddNewServicePage(SERVICE_TYPE.Database);
const connectionInput = () => { const connectionInput = () => {
const clientEmail = Cypress.env('bigqueryClientEmail'); const clientEmail = Cypress.env('bigqueryClientEmail');
cy.get('.form-group > #root\\/type') cy.get('.form-group > #root\\/credentials\\/gcsConfig\\/type')
.scrollIntoView() .scrollIntoView()
.type('service_account'); .type('service_account');
checkServiceFieldSectionHighlighting('type'); checkServiceFieldSectionHighlighting('type');
cy.get('#root\\/projectId') cy.get('#root\\/credentials\\/gcsConfig\\/projectId')
.scrollIntoView() .scrollIntoView()
.type(Cypress.env('bigqueryProjectId')); .type(Cypress.env('bigqueryProjectId'));
checkServiceFieldSectionHighlighting('projectId'); checkServiceFieldSectionHighlighting('projectId');
cy.get('#root\\/privateKeyId') cy.get('#root\\/credentials\\/gcsConfig\\/privateKeyId')
.scrollIntoView() .scrollIntoView()
.type(Cypress.env('bigqueryPrivateKeyId')); .type(Cypress.env('bigqueryPrivateKeyId'));
checkServiceFieldSectionHighlighting('privateKeyId'); checkServiceFieldSectionHighlighting('privateKeyId');
cy.get('#root\\/privateKey') cy.get('#root\\/credentials\\/gcsConfig\\/privateKey')
.scrollIntoView() .scrollIntoView()
.type(Cypress.env('bigqueryPrivateKey')); .type(Cypress.env('bigqueryPrivateKey'));
checkServiceFieldSectionHighlighting('privateKey'); checkServiceFieldSectionHighlighting('privateKey');
cy.get('#root\\/clientEmail').scrollIntoView().type(clientEmail); cy.get('#root\\/credentials\\/gcsConfig\\/clientEmail')
.scrollIntoView()
.type(clientEmail);
checkServiceFieldSectionHighlighting('clientEmail'); checkServiceFieldSectionHighlighting('clientEmail');
cy.get('#root\\/clientId') cy.get('#root\\/credentials\\/gcsConfig\\/clientId')
.scrollIntoView() .scrollIntoView()
.type(Cypress.env('bigqueryClientId')); .type(Cypress.env('bigqueryClientId'));
checkServiceFieldSectionHighlighting('clientId'); checkServiceFieldSectionHighlighting('clientId');
cy.get('#root\\/clientX509CertUrl') cy.get('#root\\/credentials\\/gcsConfig\\/clientX509CertUrl')
.scrollIntoView() .scrollIntoView()
.type( .type(
`https://www.googleapis.com/robot/v1/metadata/x509/${encodeURIComponent( `https://www.googleapis.com/robot/v1/metadata/x509/${encodeURIComponent(
@ -71,10 +73,10 @@ describe('BigQuery Ingestion', () => {
.scrollIntoView() .scrollIntoView()
.click(); .click();
checkServiceFieldSectionHighlighting('taxonomyProjectID'); checkServiceFieldSectionHighlighting('taxonomyProjectID');
cy.get('#root\\/taxonomyProjectID_0') cy.get('#root\\/taxonomyProjectID\\/0')
.scrollIntoView() .scrollIntoView()
.type(Cypress.env('bigqueryProjectIdTaxonomy')); .type(Cypress.env('bigqueryProjectIdTaxonomy'));
checkServiceFieldSectionHighlighting('taxonomyProjectID'); // checkServiceFieldSectionHighlighting('taxonomyProjectID');
}; };
const addIngestionInput = () => { const addIngestionInput = () => {

View File

@ -41,10 +41,10 @@ describe('Superset Ingestion', () => {
.click(); .click();
const connectionInput = () => { const connectionInput = () => {
cy.get('#root\\/username') cy.get('#root\\/connection\\/username')
.scrollIntoView() .scrollIntoView()
.type(Cypress.env('supersetUsername')); .type(Cypress.env('supersetUsername'));
cy.get('#root\\/password') cy.get('#root\\/connection\\/password')
.scrollIntoView() .scrollIntoView()
.type(Cypress.env('supersetPassword')); .type(Cypress.env('supersetPassword'));
cy.get('#root\\/hostPort') cy.get('#root\\/hostPort')

View File

@ -23,9 +23,10 @@
"@github/g-emoji-element": "^1.1.5", "@github/g-emoji-element": "^1.1.5",
"@okta/okta-auth-js": "^6.4.0", "@okta/okta-auth-js": "^6.4.0",
"@okta/okta-react": "^6.4.3", "@okta/okta-react": "^6.4.3",
"@rjsf/antd": "^5.0.0-beta.12", "@rjsf/antd": "5.4.0",
"@rjsf/core": "^4.1.1", "@rjsf/core": "5.4.0",
"@rjsf/utils": "^5.0.0-beta.12", "@rjsf/utils": "5.4.0",
"@rjsf/validator-ajv8": "5.4.0",
"@toast-ui/react-editor": "^3.1.8", "@toast-ui/react-editor": "^3.1.8",
"analytics": "^0.8.1", "analytics": "^0.8.1",
"antd": "4.24.0", "antd": "4.24.0",

View File

@ -15,6 +15,7 @@ const $RefParser = require('@apidevtools/json-schema-ref-parser');
const path = require('path'); const path = require('path');
const fs = require('fs'); const fs = require('fs');
const fse = require('fs-extra'); const fse = require('fs-extra');
const process = require('process');
const cwd = process.cwd(); const cwd = process.cwd();
@ -34,13 +35,15 @@ const globalParserOptions = {
}, },
}; };
const parser = new $RefParser(globalParserOptions);
async function parseSchema(filePath, destPath) { async function parseSchema(filePath, destPath) {
try { try {
const fileDir = `${cwd}/${path.dirname(filePath)}`; const fileDir = `${cwd}/${path.dirname(filePath)}`;
const fileName = path.basename(filePath); const fileName = path.basename(filePath);
process.chdir(fileDir); process.chdir(fileDir);
const parser = new $RefParser(globalParserOptions); const parsedSchema = await parser.parse(fileName);
const schema = await parser.parse(fileName); const schema = await parser.dereference(parsedSchema);
const api = await parser.bundle(schema); const api = await parser.bundle(schema);
const dirname = `${cwd}/${path.dirname(destPath)}`; const dirname = `${cwd}/${path.dirname(destPath)}`;
if (!fs.existsSync(dirname)) { if (!fs.existsSync(dirname)) {

View File

@ -12,7 +12,9 @@
*/ */
import { Card, Space, Typography } from 'antd'; import { Card, Space, Typography } from 'antd';
import { AxiosError } from 'axios';
import ResizablePanels from 'components/common/ResizablePanels/ResizablePanels'; import ResizablePanels from 'components/common/ResizablePanels/ResizablePanels';
import { HTTP_STATUS_CODE } from 'constants/auth.constants';
import { import {
SERVICE_DEFAULT_ERROR_MAP, SERVICE_DEFAULT_ERROR_MAP,
STEPS_FOR_ADD_SERVICE, STEPS_FOR_ADD_SERVICE,
@ -23,6 +25,7 @@ import { capitalize, isEmpty, isUndefined } from 'lodash';
import { LoadingState } from 'Models'; import { LoadingState } from 'Models';
import React, { useEffect, useState } from 'react'; import React, { useEffect, useState } from 'react';
import { useHistory } from 'react-router-dom'; import { useHistory } from 'react-router-dom';
import { showErrorToast } from 'utils/ToastUtils';
import { getServiceDetailsPath } from '../../constants/constants'; import { getServiceDetailsPath } from '../../constants/constants';
import { GlobalSettingsMenuCategory } from '../../constants/GlobalSettings.constants'; import { GlobalSettingsMenuCategory } from '../../constants/GlobalSettings.constants';
import { delimiterRegex, nameWithSpace } from '../../constants/regex.constants'; import { delimiterRegex, nameWithSpace } from '../../constants/regex.constants';
@ -174,6 +177,19 @@ const AddService = ({
await fetchAirflowStatus(); await fetchAirflowStatus();
} catch (error) { } catch (error) {
if (
(error as AxiosError).response?.status === HTTP_STATUS_CODE.CONFLICT
) {
showErrorToast(
t('server.entity-already-exist', {
entity: t('label.service'),
name: serviceName,
})
);
return;
}
return error; return error;
} finally { } finally {
setSaveServiceState('initial'); setSaveServiceState('initial');
@ -276,8 +292,8 @@ const AddService = ({
status={saveServiceState} status={saveServiceState}
onCancel={handleConnectionDetailsBackClick} onCancel={handleConnectionDetailsBackClick}
onFocus={handleFieldFocus} onFocus={handleFieldFocus}
onSave={(e) => { onSave={async (e) => {
handleConfigUpdate(e.formData); e.formData && (await handleConfigUpdate(e.formData));
}} }}
/> />
)} )}

View File

@ -12,7 +12,7 @@
*/ */
import { PlusOutlined } from '@ant-design/icons'; import { PlusOutlined } from '@ant-design/icons';
import { ArrayFieldTemplateProps } from '@rjsf/core'; import { ArrayFieldTemplateProps } from '@rjsf/utils';
import { Button } from 'antd'; import { Button } from 'antd';
import classNames from 'classnames'; import classNames from 'classnames';
import { t } from 'i18next'; import { t } from 'i18next';

View File

@ -1,3 +1,5 @@
import { RegistryFieldsType } from '@rjsf/utils';
/* /*
* Copyright 2023 Collate. * Copyright 2023 Collate.
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
@ -14,6 +16,6 @@ const CustomDescriptionField = () => {
return null; return null;
}; };
export const customFields = { export const customFields: RegistryFieldsType = {
DescriptionField: CustomDescriptionField, DescriptionField: CustomDescriptionField,
}; };

View File

@ -12,7 +12,7 @@
*/ */
import { PlusOutlined } from '@ant-design/icons'; import { PlusOutlined } from '@ant-design/icons';
import { ObjectFieldTemplateProps } from '@rjsf/core'; import { ObjectFieldTemplateProps } from '@rjsf/utils';
import { Button, Space } from 'antd'; import { Button, Space } from 'antd';
import classNames from 'classnames'; import classNames from 'classnames';
import { isUndefined } from 'lodash'; import { isUndefined } from 'lodash';

View File

@ -11,7 +11,8 @@
* limitations under the License. * limitations under the License.
*/ */
import { ISubmitEvent } from '@rjsf/core'; import { IChangeEvent } from '@rjsf/core';
import validator from '@rjsf/validator-ajv8';
import { StorageServiceType } from 'generated/entity/data/container'; import { StorageServiceType } from 'generated/entity/data/container';
import { cloneDeep, isNil } from 'lodash'; import { cloneDeep, isNil } from 'lodash';
import { LoadingState } from 'Models'; import { LoadingState } from 'Models';
@ -41,8 +42,8 @@ interface Props {
serviceType: string; serviceType: string;
serviceCategory: ServiceCategory; serviceCategory: ServiceCategory;
status: LoadingState; status: LoadingState;
onFocus: (fieldName: string) => void; onFocus: (id: string) => void;
onSave: (data: ISubmitEvent<ConfigData>) => void; onSave: (data: IChangeEvent<ConfigData>) => Promise<void>;
disableTestConnection?: boolean; disableTestConnection?: boolean;
onCancel?: () => void; onCancel?: () => void;
} }
@ -63,9 +64,10 @@ const ConnectionConfigForm: FunctionComponent<Props> = ({
? ((data as ServicesType).connection?.config as ConfigData) ? ((data as ServicesType).connection?.config as ConfigData)
: ({} as ConfigData); : ({} as ConfigData);
const handleSave = (data: ISubmitEvent<ConfigData>) => { const handleSave = async (data: IChangeEvent<ConfigData>) => {
const updatedFormData = formatFormDataForSubmit(data.formData); const updatedFormData = formatFormDataForSubmit(data.formData);
onSave({ ...data, formData: updatedFormData });
await onSave({ ...data, formData: updatedFormData });
}; };
const getConfigFields = () => { const getConfigFields = () => {
@ -132,6 +134,7 @@ const ConnectionConfigForm: FunctionComponent<Props> = ({
serviceType={serviceType} serviceType={serviceType}
status={status} status={status}
uiSchema={connSch.uiSchema} uiSchema={connSch.uiSchema}
validator={validator}
onCancel={onCancel} onCancel={onCancel}
onFocus={onFocus} onFocus={onFocus}
onSubmit={handleSave} onSubmit={handleSave}

View File

@ -11,7 +11,7 @@
* limitations under the License. * limitations under the License.
*/ */
import { ISubmitEvent } from '@rjsf/core'; import { IChangeEvent } from '@rjsf/core';
import { LoadingState, ServicesData } from 'Models'; import { LoadingState, ServicesData } from 'Models';
import React, { useState } from 'react'; import React, { useState } from 'react';
import { useHistory } from 'react-router-dom'; import { useHistory } from 'react-router-dom';
@ -34,7 +34,7 @@ interface ServiceConfigProps {
serviceCategory: ServiceCategory serviceCategory: ServiceCategory
) => Promise<void>; ) => Promise<void>;
disableTestConnection: boolean; disableTestConnection: boolean;
onFocus: (fieldName: string) => void; onFocus: (id: string) => void;
} }
export const Field = ({ children }: { children: React.ReactNode }) => { export const Field = ({ children }: { children: React.ReactNode }) => {
@ -53,21 +53,24 @@ const ServiceConfig = ({
const history = useHistory(); const history = useHistory();
const [status, setStatus] = useState<LoadingState>('initial'); const [status, setStatus] = useState<LoadingState>('initial');
const handleOnSaveClick = (e: ISubmitEvent<ConfigData>) => { const handleOnSaveClick = async (e: IChangeEvent<ConfigData>) => {
if (!e.formData) {
return;
}
setStatus('waiting'); setStatus('waiting');
try {
handleUpdate(e.formData, serviceCategory) await handleUpdate(e.formData, serviceCategory);
.then(() => {
setTimeout(() => { setTimeout(() => {
setStatus('success'); setStatus('success');
history.push(getPathByServiceFQN(serviceCategory, serviceFQN)); history.push(getPathByServiceFQN(serviceCategory, serviceFQN));
}, 200); }, 200);
}) } catch (err) {
.finally(() => { // Nothing here
} finally {
setTimeout(() => { setTimeout(() => {
setStatus('initial'); setStatus('initial');
}, 500); }, 500);
}); }
}; };
const onCancel = () => { const onCancel = () => {

View File

@ -169,7 +169,7 @@ const ServiceConnectionDetails = ({
: {}; : {};
return ( return (
<Col span={12}> <Col key={key} span={12}>
<Row> <Row>
<Col span={8}> <Col span={8}>
<Space size={0}> <Space size={0}>

View File

@ -15,7 +15,6 @@ import React from 'react';
import { LabelCountSkeletonProps } from '../../Skeleton.interfaces'; import { LabelCountSkeletonProps } from '../../Skeleton.interfaces';
const LabelCountSkeleton = ({ const LabelCountSkeleton = ({
key,
isSelect, isSelect,
isLabel, isLabel,
isCount, isCount,
@ -27,7 +26,7 @@ const LabelCountSkeleton = ({
...props ...props
}: LabelCountSkeletonProps) => { }: LabelCountSkeletonProps) => {
return ( return (
<Row justify="space-between" key={key}> <Row justify="space-between">
{isSelect || isLabel ? ( {isSelect || isLabel ? (
<Col span={firstColSize}> <Col span={firstColSize}>
<div className="w-48 flex"> <div className="w-48 flex">

View File

@ -12,27 +12,26 @@
*/ */
import { CheckOutlined } from '@ant-design/icons'; import { CheckOutlined } from '@ant-design/icons';
import Form from '@rjsf/antd'; import Form, { FormProps, IChangeEvent } from '@rjsf/core';
import CoreForm, { AjvError, FormProps, IChangeEvent } from '@rjsf/core'; import { Button } from 'antd';
import validateFormData from '@rjsf/core/lib/validate';
import { Button as AntDButton } from 'antd';
import classNames from 'classnames'; import classNames from 'classnames';
import { ArrayFieldTemplate } from 'components/JSONSchemaTemplate/ArrayFieldTemplate';
import { customFields } from 'components/JSONSchemaTemplate/CustomFields'; import { customFields } from 'components/JSONSchemaTemplate/CustomFields';
import { ObjectFieldTemplate } from 'components/JSONSchemaTemplate/ObjectFieldTemplate';
import { ServiceCategory } from 'enums/service.enum'; import { ServiceCategory } from 'enums/service.enum';
import { useAirflowStatus } from 'hooks/useAirflowStatus'; import { useAirflowStatus } from 'hooks/useAirflowStatus';
import { t } from 'i18next'; import { t } from 'i18next';
import { isEmpty, isUndefined, startCase } from 'lodash'; import { isEmpty, isUndefined } from 'lodash';
import { LoadingState } from 'Models'; import { LoadingState } from 'Models';
import React, { FunctionComponent, useEffect, useRef, useState } from 'react'; import React, { FunctionComponent, useEffect, useRef, useState } from 'react';
import { getPipelineServiceHostIp } from 'rest/ingestionPipelineAPI'; import { getPipelineServiceHostIp } from 'rest/ingestionPipelineAPI';
import { transformErrors } from 'utils/formUtils';
import { ConfigData } from '../../../interface/service.interface'; import { ConfigData } from '../../../interface/service.interface';
import { formatFormDataForRender } from '../../../utils/JSONSchemaFormUtils'; import { formatFormDataForRender } from '../../../utils/JSONSchemaFormUtils';
import { ArrayFieldTemplate } from '../../JSONSchemaTemplate/ArrayFieldTemplate';
import { ObjectFieldTemplate } from '../../JSONSchemaTemplate/ObjectFieldTemplate';
import Loader from '../../Loader/Loader'; import Loader from '../../Loader/Loader';
import TestConnection from '../TestConnection/TestConnection'; import TestConnection from '../TestConnection/TestConnection';
interface Props extends FormProps<ConfigData> { interface Props extends FormProps {
okText: string; okText: string;
cancelText: string; cancelText: string;
disableTestConnection: boolean; disableTestConnection: boolean;
@ -42,7 +41,6 @@ interface Props extends FormProps<ConfigData> {
showFormHeader?: boolean; showFormHeader?: boolean;
status?: LoadingState; status?: LoadingState;
onCancel?: () => void; onCancel?: () => void;
onFocus: (fieldName: string) => void;
} }
const FormBuilder: FunctionComponent<Props> = ({ const FormBuilder: FunctionComponent<Props> = ({
@ -64,7 +62,7 @@ const FormBuilder: FunctionComponent<Props> = ({
}: Props) => { }: Props) => {
const { isAirflowAvailable } = useAirflowStatus(); const { isAirflowAvailable } = useAirflowStatus();
const formRef = useRef<CoreForm<ConfigData>>(); const formRef = useRef<Form<ConfigData>>(null);
const [localFormData, setLocalFormData] = useState<ConfigData | undefined>( const [localFormData, setLocalFormData] = useState<ConfigData | undefined>(
formatFormDataForRender(formData ?? {}) formatFormDataForRender(formData ?? {})
); );
@ -97,39 +95,20 @@ const FormBuilder: FunctionComponent<Props> = ({
} }
}; };
const handleSubmit = () => {
if (formRef.current) {
formRef.current.submit();
}
};
const handleChange = (updatedData: ConfigData) => {
setLocalFormData(updatedData);
};
const transformErrors = (errors: AjvError[]) =>
errors.map((error) => {
const fieldName = error.params.missingProperty;
const customMessage = `${startCase(fieldName)} is required`;
error.message = customMessage;
return error;
});
const handleRequiredFieldsValidation = () => { const handleRequiredFieldsValidation = () => {
const validationObject = validateFormData(localFormData, schema); return Boolean(formRef.current?.validateForm());
const isFormValid = isEmpty(validationObject.errors); };
if (!isFormValid) {
formRef.current?.submit();
}
return isFormValid; const handleFormChange = (e: IChangeEvent<ConfigData>) => {
setLocalFormData(e.formData);
props.onChange && props.onChange(e);
}; };
return ( return (
<Form <Form
ArrayFieldTemplate={ArrayFieldTemplate} focusOnFirstError
ObjectFieldTemplate={ObjectFieldTemplate} noHtml5Validate
omitExtraData
className={classNames('rjsf', props.className, { className={classNames('rjsf', props.className, {
'no-header': !showFormHeader, 'no-header': !showFormHeader,
})} })}
@ -140,12 +119,13 @@ const FormBuilder: FunctionComponent<Props> = ({
ref={formRef} ref={formRef}
schema={schema} schema={schema}
showErrorList={false} showErrorList={false}
templates={{
ArrayFieldTemplate: ArrayFieldTemplate,
ObjectFieldTemplate: ObjectFieldTemplate,
}}
transformErrors={transformErrors} transformErrors={transformErrors}
uiSchema={uiSchema} uiSchema={uiSchema}
onChange={(e: IChangeEvent) => { onChange={handleFormChange}
handleChange(e.formData);
props.onChange && props.onChange(e);
}}
onFocus={onFocus} onFocus={onFocus}
onSubmit={onSubmit} onSubmit={onSubmit}
{...props}> {...props}>
@ -176,31 +156,31 @@ const FormBuilder: FunctionComponent<Props> = ({
<div className="tw-mt-6 tw-flex tw-justify-between"> <div className="tw-mt-6 tw-flex tw-justify-between">
<div /> <div />
<div className="tw-text-right" data-testid="buttons"> <div className="tw-text-right" data-testid="buttons">
<AntDButton type="link" onClick={handleCancel}> <Button type="link" onClick={handleCancel}>
{cancelText} {cancelText}
</AntDButton> </Button>
{status === 'waiting' ? ( {status === 'waiting' ? (
<AntDButton <Button
disabled disabled
className="p-x-md p-y-xxs h-auto rounded-6" className="p-x-md p-y-xxs h-auto rounded-6"
type="primary"> type="primary">
<Loader size="small" type="white" /> <Loader size="small" type="white" />
</AntDButton> </Button>
) : status === 'success' ? ( ) : status === 'success' ? (
<AntDButton <Button
disabled disabled
className="p-x-md p-y-xxs h-auto rounded-6" className="p-x-md p-y-xxs h-auto rounded-6"
type="primary"> type="primary">
<CheckOutlined /> <CheckOutlined />
</AntDButton> </Button>
) : ( ) : (
<AntDButton <Button
className="font-medium p-x-md p-y-xxs h-auto rounded-6" className="font-medium p-x-md p-y-xxs h-auto rounded-6"
data-testid="submit-btn" data-testid="submit-btn"
type="primary" htmlType="submit"
onClick={handleSubmit}> type="primary">
{okText} {okText}
</AntDButton> </Button>
)} )}
</div> </div>
</div> </div>

View File

@ -61,28 +61,9 @@ const AddServicePage = () => {
setAddIngestion(value); setAddIngestion(value);
}; };
const onAddServiceSave = (data: DataObj) => { const onAddServiceSave = async (data: DataObj) => {
return new Promise<void>((resolve, reject) => { const res = await postService(serviceCategory, data);
postService(serviceCategory, data)
.then((res) => {
if (res) {
setNewServiceData(res); setNewServiceData(res);
resolve();
} else {
showErrorToast(
t('server.create-entity-error', { entity: t('label.service') })
);
reject();
}
})
.catch((err: AxiosError) => {
showErrorToast(
err,
t('server.create-entity-error', { entity: t('label.service') })
);
reject();
});
});
}; };
const onIngestionDeploy = (id?: string) => { const onIngestionDeploy = (id?: string) => {

View File

@ -0,0 +1,371 @@
{
"$id": "https://open-metadata.org/schema/entity/services/connections/dashboard/supersetConnection.json",
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "SupersetConnection",
"description": "Superset Connection Config",
"type": "object",
"javaType": "org.openmetadata.schema.services.connections.dashboard.SupersetConnection",
"definitions": {
"supersetType": {
"description": "Superset service type",
"type": "string",
"enum": ["Superset"],
"default": "Superset"
}
},
"properties": {
"type": {
"title": "Service Type",
"description": "Service Type",
"default": "Superset",
"type": "string",
"enum": ["Superset"]
},
"hostPort": {
"expose": true,
"title": "Host and Port",
"description": "URL for the superset instance.",
"type": "string",
"format": "uri",
"default": "http://localhost:8088"
},
"connection": {
"title": "Superset Connection",
"description": "Choose between API or database connection fetch metadata from superset.",
"oneOf": [
{
"$id": "https://open-metadata.org/schema/entity/services/connections/dashboard/supersetApiConnection.json",
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "SupersetApiConnection",
"description": "Superset API Connection Config",
"type": "object",
"definitions": {
"apiProvider": {
"title": "Provider",
"description": "Authentication provider for the Superset service. For basic user/password authentication, the default value `db` can be used. This parameter is used internally to connect to Superset's REST API.",
"type": "string",
"enum": ["db", "ldap"],
"default": "db"
}
},
"properties": {
"provider": {
"title": "Provider",
"description": "Authentication provider for the Superset service. For basic user/password authentication, the default value `db` can be used. This parameter is used internally to connect to Superset's REST API.",
"default": "db",
"type": "string",
"enum": ["db", "ldap"]
},
"username": {
"title": "Username",
"description": "Username for Superset.",
"type": "string"
},
"password": {
"title": "Password",
"description": "Password for Superset.",
"type": "string",
"format": "password"
}
},
"additionalProperties": false,
"required": ["provider", "password", "username"]
},
{
"$id": "https://open-metadata.org/schema/entity/services/connections/database/postgresConnection.json",
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "PostgresConnection",
"description": "Postgres Database Connection Config",
"type": "object",
"javaType": "org.openmetadata.schema.services.connections.database.PostgresConnection",
"definitions": {
"postgresType": {
"description": "Service type.",
"type": "string",
"enum": ["Postgres"],
"default": "Postgres"
},
"postgresScheme": {
"description": "SQLAlchemy driver scheme options.",
"type": "string",
"enum": ["postgresql+psycopg2"],
"default": "postgresql+psycopg2"
}
},
"properties": {
"type": {
"title": "Service Type",
"description": "Service Type",
"default": "Postgres",
"type": "string",
"enum": ["Postgres"]
},
"scheme": {
"title": "Connection Scheme",
"description": "SQLAlchemy driver scheme options.",
"default": "postgresql+psycopg2",
"type": "string",
"enum": ["postgresql+psycopg2"]
},
"username": {
"title": "Username",
"description": "Username to connect to Postgres. This user should have privileges to read all the metadata in Postgres.",
"type": "string"
},
"password": {
"title": "Password",
"description": "Password to connect to Postgres.",
"type": "string",
"format": "password"
},
"hostPort": {
"title": "Host and Port",
"description": "Host and port of the Postgres service.",
"type": "string"
},
"database": {
"title": "Database",
"description": "Database of the data source. This is optional parameter, if you would like to restrict the metadata reading to a single database. When left blank, OpenMetadata Ingestion attempts to scan all the databases.",
"type": "string"
},
"sslMode": {
"title": "SSL Mode",
"description": "SSL Mode to connect to postgres database.",
"enum": [
"disable",
"allow",
"prefer",
"require",
"verify-ca",
"verify-full"
],
"default": "disable"
},
"sslConfig": {
"description": "Client SSL configuration",
"javaType": "org.openmetadata.schema.security.ssl.SSLConfig",
"oneOf": [
{
"$id": "https://open-metadata.org/schema/security/ssl/validateSSLClientConfig.json",
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "ValidateSSLClientConfig",
"description": "OpenMetadata Client configured to validate SSL certificates.",
"type": "object",
"javaType": "org.openmetadata.schema.security.ssl.ValidateSSLClientConfig",
"properties": {
"certificatePath": {
"description": "CA certificate path. E.g., /path/to/public.cert. Will be used if Verify SSL is set to `validate`.",
"type": "string"
}
},
"additionalProperties": false
}
]
},
"classificationName": {
"title": "Classification Name",
"description": "Custom OpenMetadata Classification name for Postgres policy tags.",
"type": "string",
"default": "PostgresPolicyTags"
},
"ingestAllDatabases": {
"title": "Ingest All Databases",
"description": "Ingest data from all databases in Postgres. You can use databaseFilterPattern on top of this.",
"type": "boolean",
"default": false
},
"connectionOptions": {
"title": "Connection Options",
"javaType": "org.openmetadata.schema.services.connections.database.ConnectionOptions",
"description": "Additional connection options to build the URL that can be sent to service during the connection.",
"additionalProperties": {
"type": "string"
}
},
"connectionArguments": {
"title": "Connection Arguments",
"javaType": "org.openmetadata.schema.services.connections.database.ConnectionArguments",
"description": "Additional connection arguments such as security or protocol configs that can be sent to service during connection.",
"additionalProperties": {
".{1,}": {
"type": "string"
}
}
},
"supportsMetadataExtraction": {
"title": "Supports Metadata Extraction",
"description": "Supports Metadata Extraction.",
"type": "boolean",
"default": true
},
"supportsUsageExtraction": {
"description": "Supports Usage Extraction.",
"type": "boolean",
"default": true
},
"supportsLineageExtraction": {
"description": "Supports Lineage Extraction.",
"type": "boolean",
"default": true
},
"supportsDBTExtraction": {
"description": "Supports DBT Extraction.",
"type": "boolean",
"default": true
},
"supportsProfiler": {
"title": "Supports Profiler",
"description": "Supports Profiler",
"type": "boolean",
"default": true
},
"supportsDatabase": {
"title": "Supports Database",
"description": "The source service supports the database concept in its hierarchy",
"type": "boolean",
"default": true
},
"supportsQueryComment": {
"title": "Supports Query Comment",
"description": "For Database Services using SQLAlchemy, True to enable running a comment for all queries run from OpenMetadata.",
"type": "boolean",
"default": true
}
},
"additionalProperties": false,
"required": ["hostPort", "username", "database"]
},
{
"$id": "https://open-metadata.org/schema/entity/services/connections/database/mysqlConnection.json",
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "MysqlConnection",
"description": "Mysql Database Connection Config",
"type": "object",
"javaType": "org.openmetadata.schema.services.connections.database.MysqlConnection",
"definitions": {
"mySQLType": {
"description": "Service type.",
"type": "string",
"enum": ["Mysql"],
"default": "Mysql"
},
"mySQLScheme": {
"description": "SQLAlchemy driver scheme options.",
"type": "string",
"enum": ["mysql+pymysql"],
"default": "mysql+pymysql"
}
},
"properties": {
"type": {
"title": "Service Type",
"description": "Service Type",
"default": "Mysql",
"type": "string",
"enum": ["Mysql"]
},
"scheme": {
"title": "Connection Scheme",
"description": "SQLAlchemy driver scheme options.",
"default": "mysql+pymysql",
"type": "string",
"enum": ["mysql+pymysql"]
},
"username": {
"title": "Username",
"description": "Username to connect to MySQL. This user should have privileges to read all the metadata in Mysql.",
"type": "string"
},
"password": {
"title": "Password",
"description": "Password to connect to MySQL.",
"type": "string",
"format": "password"
},
"hostPort": {
"title": "Host and Port",
"description": "Host and port of the MySQL service.",
"type": "string"
},
"databaseName": {
"title": "Database Name",
"description": "Optional name to give to the database in OpenMetadata. If left blank, we will use default as the database name.",
"type": "string"
},
"databaseSchema": {
"title": "Database Schema",
"description": "Database Schema of the data source. This is optional parameter, if you would like to restrict the metadata reading to a single schema. When left blank, OpenMetadata Ingestion attempts to scan all the schemas.",
"type": "string"
},
"sslCA": {
"title": "SSL CA",
"description": "Provide the path to ssl ca file",
"type": "string"
},
"sslCert": {
"title": "SSL Client Certificate File",
"description": "Provide the path to ssl client certificate file (ssl_cert)",
"type": "string"
},
"sslKey": {
"title": "SSL Client Key File",
"description": "Provide the path to ssl client certificate file (ssl_key)",
"type": "string"
},
"connectionOptions": {
"title": "Connection Options",
"javaType": "org.openmetadata.schema.services.connections.database.ConnectionOptions",
"description": "Additional connection options to build the URL that can be sent to service during the connection.",
"additionalProperties": {
"type": "string"
}
},
"connectionArguments": {
"title": "Connection Arguments",
"javaType": "org.openmetadata.schema.services.connections.database.ConnectionArguments",
"description": "Additional connection arguments such as security or protocol configs that can be sent to service during connection.",
"additionalProperties": {
".{1,}": {
"type": "string"
}
}
},
"supportsMetadataExtraction": {
"title": "Supports Metadata Extraction",
"description": "Supports Metadata Extraction.",
"type": "boolean",
"default": true
},
"supportsDBTExtraction": {
"description": "Supports DBT Extraction.",
"type": "boolean",
"default": true
},
"supportsProfiler": {
"title": "Supports Profiler",
"description": "Supports Profiler",
"type": "boolean",
"default": true
},
"supportsQueryComment": {
"title": "Supports Query Comment",
"description": "For Database Services using SQLAlchemy, True to enable running a comment for all queries run from OpenMetadata.",
"type": "boolean",
"default": true
}
},
"additionalProperties": false,
"required": ["hostPort", "username"]
}
]
},
"supportsMetadataExtraction": {
"title": "Supports Metadata Extraction",
"description": "Supports Metadata Extraction.",
"type": "boolean",
"default": true
}
},
"additionalProperties": false,
"required": ["hostPort", "connection"]
}

View File

@ -25,8 +25,8 @@ import modeConnection from '../jsons/connectionSchemas/connections/dashboard/mod
import powerBIConnection from '../jsons/connectionSchemas/connections/dashboard/powerBIConnection.json'; import powerBIConnection from '../jsons/connectionSchemas/connections/dashboard/powerBIConnection.json';
import quicksightConnection from '../jsons/connectionSchemas/connections/dashboard/quickSightConnection.json'; import quicksightConnection from '../jsons/connectionSchemas/connections/dashboard/quickSightConnection.json';
import redashConnection from '../jsons/connectionSchemas/connections/dashboard/redashConnection.json'; import redashConnection from '../jsons/connectionSchemas/connections/dashboard/redashConnection.json';
import supersetConnection from '../jsons/connectionSchemas/connections/dashboard/supersetConnection.json';
import tableauConnection from '../jsons/connectionSchemas/connections/dashboard/tableauConnection.json'; import tableauConnection from '../jsons/connectionSchemas/connections/dashboard/tableauConnection.json';
import supersetConnection from './ConnectionSchemas/SupersetConnection.json';
export const getDashboardURL = (config: DashboardConnection['config']) => { export const getDashboardURL = (config: DashboardConnection['config']) => {
return !isUndefined(config) && !isEmpty(config.hostPort) return !isUndefined(config) && !isEmpty(config.hostPort)

View File

@ -10,6 +10,7 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
import { ErrorTransformer } from '@rjsf/utils';
import { import {
Divider, Divider,
Form, Form,
@ -27,6 +28,7 @@ import RichTextEditor from 'components/common/rich-text-editor/RichTextEditor';
import { RichTextEditorProp } from 'components/common/rich-text-editor/RichTextEditor.interface'; import { RichTextEditorProp } from 'components/common/rich-text-editor/RichTextEditor.interface';
import SliderWithInput from 'components/SliderWithInput/SliderWithInput'; import SliderWithInput from 'components/SliderWithInput/SliderWithInput';
import { SliderWithInputProps } from 'components/SliderWithInput/SliderWithInput.interface'; import { SliderWithInputProps } from 'components/SliderWithInput/SliderWithInput.interface';
import { compact, startCase } from 'lodash';
import React, { Fragment, ReactNode } from 'react'; import React, { Fragment, ReactNode } from 'react';
import i18n from './i18next/LocalUtil'; import i18n from './i18next/LocalUtil';
@ -164,3 +166,26 @@ export const getField = (field: FieldProp) => {
export const generateFormFields = (fields: FieldProp[]) => { export const generateFormFields = (fields: FieldProp[]) => {
return <>{fields.map((field) => getField(field))}</>; return <>{fields.map((field) => getField(field))}</>;
}; };
export const transformErrors: ErrorTransformer = (errors) => {
const errorRet = errors.map((error) => {
const { property } = error;
const id = 'root' + property?.replaceAll('.', '/');
// If element is not present in DOM, ignore error
if (document.getElementById(id)) {
const fieldName = error.params?.missingProperty;
if (fieldName) {
const customMessage = i18n.t('message.field-text-is-required', {
fieldText: startCase(fieldName),
});
error.message = customMessage;
return error;
}
}
return null;
});
return compact(errorRet);
};

View File

@ -108,9 +108,9 @@
resize-observer-polyfill "^1.5.1" resize-observer-polyfill "^1.5.1"
"@apidevtools/json-schema-ref-parser@^9.0.9": "@apidevtools/json-schema-ref-parser@^9.0.9":
version "9.0.9" version "9.1.2"
resolved "https://registry.yarnpkg.com/@apidevtools/json-schema-ref-parser/-/json-schema-ref-parser-9.0.9.tgz#d720f9256e3609621280584f2b47ae165359268b" resolved "https://registry.yarnpkg.com/@apidevtools/json-schema-ref-parser/-/json-schema-ref-parser-9.1.2.tgz#8ff5386b365d4c9faa7c8b566ff16a46a577d9b8"
integrity sha512-GBD2Le9w2+lVFoc4vswGI/TjkNIZSVp7+9xPf+X3uidBfWnAeUWmquteSyt0+VCrhNMWj/FTABISQrD3Z/YA+w== integrity sha512-r1w81DpR+KyRWd3f+rk6TNqMgedmAxZP5v5KWlXQWlgMUUtyEJch0DKEci1SorPMiSeM8XPl7MZ3miJ60JIpQg==
dependencies: dependencies:
"@jsdevtools/ono" "^7.1.3" "@jsdevtools/ono" "^7.1.3"
"@types/json-schema" "^7.0.6" "@types/json-schema" "^7.0.6"
@ -2883,30 +2883,31 @@
classcat "^5.0.3" classcat "^5.0.3"
zustand "^4.1.1" zustand "^4.1.1"
"@rjsf/antd@^5.0.0-beta.12": "@rjsf/antd@5.4.0":
version "5.0.0-beta.12" version "5.4.0"
resolved "https://registry.yarnpkg.com/@rjsf/antd/-/antd-5.0.0-beta.12.tgz#357579a120af186a18b894c9f5c4b2c111f6b536" resolved "https://registry.yarnpkg.com/@rjsf/antd/-/antd-5.4.0.tgz#194a784272a5782aeea35d80e25ee5a5b076bfa4"
integrity sha512-2U5x4DV3TeVQFjX6YJgLBw1ND/sJoZlUyePTyygOPqltto4wPUdXdJS7m5+zRinowlCZrcr9l2u7RCwA4Bnpwg== integrity sha512-mC96NITW/CFfPtF/J8EdxStaP/Jc/EfEaIB00GyUWbZUYjXFJ+cAeltfXFQPOrrlC6gFCDRbkZexRW+Hazv6eA==
"@rjsf/core@^4.1.1":
version "4.1.1"
resolved "https://registry.yarnpkg.com/@rjsf/core/-/core-4.1.1.tgz#6ba23585b0fc891247e795bed1ab2c6ce44755fa"
integrity sha512-/R37fLwnhAavQVlYoILwYIha0ymgKtMWdtehgiODcf++rl4/jq38RjXhqF5wQT9uOYAHmtutokJsTFei1VY4bw==
dependencies: dependencies:
"@types/json-schema" "^7.0.7" classnames "^2.3.2"
ajv "^6.7.0"
core-js-pure "^3.6.5"
json-schema-merge-allof "^0.6.0"
jsonpointer "^5.0.0"
lodash "^4.17.15" lodash "^4.17.15"
nanoid "^3.1.23" lodash-es "^4.17.15"
prop-types "^15.7.2" rc-picker "^2.6.11"
react-is "^16.9.0"
"@rjsf/utils@^5.0.0-beta.12": "@rjsf/core@5.4.0":
version "5.0.0-beta.12" version "5.4.0"
resolved "https://registry.yarnpkg.com/@rjsf/utils/-/utils-5.0.0-beta.12.tgz#a03f9da784896744a1908e8fd4dec0a36e90704b" resolved "https://registry.yarnpkg.com/@rjsf/core/-/core-5.4.0.tgz#d75e42a5b8fe9af7b62b04fd8b93629f4e1fa5a7"
integrity sha512-RH965WMGp3Z25iQ2PTn+BFkQusJuvG0e2fl8V+wx1N21EkrZnW2+twouWUmqNqHwke2Z0OOimF5picZVgobl7g== integrity sha512-0DmEmTCkpnGYju3HycEJb0MoYCp7Swd/R1abllmUg0sqCeffdtYSI4pWL3M1gwyMFT+JWgZWDYQ2CqJUZ9n0NA==
dependencies:
lodash "^4.17.15"
lodash-es "^4.17.15"
markdown-to-jsx "^7.2.0"
nanoid "^3.3.4"
prop-types "^15.7.2"
"@rjsf/utils@5.4.0":
version "5.4.0"
resolved "https://registry.yarnpkg.com/@rjsf/utils/-/utils-5.4.0.tgz#ce9d54882e3214c0fdc9f278dfd8570f1743d50c"
integrity sha512-R9vgwqFrPV7+6JzTzHzYeULIH4FEdp10zixTxhgh4WSEbTP9L9leei9O4fa924EFGHuBFgtZeH2cwL20pr5cUw==
dependencies: dependencies:
json-schema-merge-allof "^0.8.1" json-schema-merge-allof "^0.8.1"
jsonpointer "^5.0.1" jsonpointer "^5.0.1"
@ -2914,6 +2915,16 @@
lodash-es "^4.17.15" lodash-es "^4.17.15"
react-is "^18.2.0" react-is "^18.2.0"
"@rjsf/validator-ajv8@5.4.0":
version "5.4.0"
resolved "https://registry.yarnpkg.com/@rjsf/validator-ajv8/-/validator-ajv8-5.4.0.tgz#e26ac6f7dff47ae5ca00bd02b49e0fc1e78d54da"
integrity sha512-OjWPQGU2tu+KzOgZqqsyhdiamyZPLXsChgdIQJ2sz4gMuedL2LgfNfOc6STcf01kXMXft2MoDZ9lHGlAHlv2Vw==
dependencies:
ajv "^8.12.0"
ajv-formats "^2.1.1"
lodash "^4.17.15"
lodash-es "^4.17.15"
"@sheerun/mutationobserver-shim@^0.3.2": "@sheerun/mutationobserver-shim@^0.3.2":
version "0.3.3" version "0.3.3"
resolved "https://registry.yarnpkg.com/@sheerun/mutationobserver-shim/-/mutationobserver-shim-0.3.3.tgz#5405ee8e444ed212db44e79351f0c70a582aae25" resolved "https://registry.yarnpkg.com/@sheerun/mutationobserver-shim/-/mutationobserver-shim-0.3.3.tgz#5405ee8e444ed212db44e79351f0c70a582aae25"
@ -4352,7 +4363,7 @@ ajv-keywords@^5.0.0:
dependencies: dependencies:
fast-deep-equal "^3.1.3" fast-deep-equal "^3.1.3"
ajv@^6.10.0, ajv@^6.12.2, ajv@^6.12.4, ajv@^6.12.5, ajv@^6.4.0, ajv@^6.7.0: ajv@^6.10.0, ajv@^6.12.2, ajv@^6.12.4, ajv@^6.12.5, ajv@^6.4.0:
version "6.12.6" version "6.12.6"
resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.12.6.tgz#baf5a62e802b07d977034586f8c3baf5adf26df4" resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.12.6.tgz#baf5a62e802b07d977034586f8c3baf5adf26df4"
integrity sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g== integrity sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==
@ -4382,6 +4393,16 @@ ajv@^8.0.1:
require-from-string "^2.0.2" require-from-string "^2.0.2"
uri-js "^4.2.2" uri-js "^4.2.2"
ajv@^8.12.0:
version "8.12.0"
resolved "https://registry.yarnpkg.com/ajv/-/ajv-8.12.0.tgz#d1a0527323e22f53562c567c00991577dfbe19d1"
integrity sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==
dependencies:
fast-deep-equal "^3.1.1"
json-schema-traverse "^1.0.0"
require-from-string "^2.0.2"
uri-js "^4.2.2"
amdefine@>=0.0.4: amdefine@>=0.0.4:
version "1.0.1" version "1.0.1"
resolved "https://registry.yarnpkg.com/amdefine/-/amdefine-1.0.1.tgz#4a5282ac164729e93619bcfd3ad151f817ce91f5" resolved "https://registry.yarnpkg.com/amdefine/-/amdefine-1.0.1.tgz#4a5282ac164729e93619bcfd3ad151f817ce91f5"
@ -5660,7 +5681,7 @@ compute-gcd@^1.2.1:
validate.io-function "^1.0.2" validate.io-function "^1.0.2"
validate.io-integer-array "^1.0.0" validate.io-integer-array "^1.0.0"
compute-lcm@^1.1.0, compute-lcm@^1.1.2: compute-lcm@^1.1.2:
version "1.1.2" version "1.1.2"
resolved "https://registry.yarnpkg.com/compute-lcm/-/compute-lcm-1.1.2.tgz#9107c66b9dca28cefb22b4ab4545caac4034af23" resolved "https://registry.yarnpkg.com/compute-lcm/-/compute-lcm-1.1.2.tgz#9107c66b9dca28cefb22b4ab4545caac4034af23"
integrity sha512-OFNPdQAXnQhDSKioX8/XYT6sdUlXwpeMjfd6ApxMJfyZ4GxmLR1xvMERctlYhlHwIiz6CSpBc2+qYKjHGZw4TQ== integrity sha512-OFNPdQAXnQhDSKioX8/XYT6sdUlXwpeMjfd6ApxMJfyZ4GxmLR1xvMERctlYhlHwIiz6CSpBc2+qYKjHGZw4TQ==
@ -5777,7 +5798,7 @@ core-js-pure@^3.16.0:
resolved "https://registry.yarnpkg.com/core-js-pure/-/core-js-pure-3.16.1.tgz#b997df2669c957a5b29f06e95813a171f993592e" resolved "https://registry.yarnpkg.com/core-js-pure/-/core-js-pure-3.16.1.tgz#b997df2669c957a5b29f06e95813a171f993592e"
integrity sha512-TyofCdMzx0KMhi84mVRS8rL1XsRk2SPUNz2azmth53iRN0/08Uim9fdhQTaZTG1LqaXHYVci4RDHka6WrXfnvg== integrity sha512-TyofCdMzx0KMhi84mVRS8rL1XsRk2SPUNz2azmth53iRN0/08Uim9fdhQTaZTG1LqaXHYVci4RDHka6WrXfnvg==
core-js-pure@^3.20.2, core-js-pure@^3.6.5: core-js-pure@^3.20.2:
version "3.21.1" version "3.21.1"
resolved "https://registry.yarnpkg.com/core-js-pure/-/core-js-pure-3.21.1.tgz#8c4d1e78839f5f46208de7230cebfb72bc3bdb51" resolved "https://registry.yarnpkg.com/core-js-pure/-/core-js-pure-3.21.1.tgz#8c4d1e78839f5f46208de7230cebfb72bc3bdb51"
integrity sha512-12VZfFIu+wyVbBebyHmRTuEE/tZrB4tJToWcwAMcsp3h4+sHR+fMJWbKpYiCRWlhFBq+KNyO8rIV9rTkeVmznQ== integrity sha512-12VZfFIu+wyVbBebyHmRTuEE/tZrB4tJToWcwAMcsp3h4+sHR+fMJWbKpYiCRWlhFBq+KNyO8rIV9rTkeVmznQ==
@ -9455,15 +9476,6 @@ json-schema-compare@^0.2.2:
dependencies: dependencies:
lodash "^4.17.4" lodash "^4.17.4"
json-schema-merge-allof@^0.6.0:
version "0.6.0"
resolved "https://registry.yarnpkg.com/json-schema-merge-allof/-/json-schema-merge-allof-0.6.0.tgz#64d48820fec26b228db837475ce3338936bf59a5"
integrity sha512-LEw4VMQVRceOPLuGRWcxW5orTTiR9ZAtqTAe4rQUjNADTeR81bezBVFa0MqIwp0YmHIM1KkhSjZM7o+IQhaPbQ==
dependencies:
compute-lcm "^1.1.0"
json-schema-compare "^0.2.2"
lodash "^4.17.4"
json-schema-merge-allof@^0.8.1: json-schema-merge-allof@^0.8.1:
version "0.8.1" version "0.8.1"
resolved "https://registry.yarnpkg.com/json-schema-merge-allof/-/json-schema-merge-allof-0.8.1.tgz#ed2828cdd958616ff74f932830a26291789eaaf2" resolved "https://registry.yarnpkg.com/json-schema-merge-allof/-/json-schema-merge-allof-0.8.1.tgz#ed2828cdd958616ff74f932830a26291789eaaf2"
@ -9562,11 +9574,6 @@ jsonpath-plus@^6.0.1:
resolved "https://registry.yarnpkg.com/jsonpath-plus/-/jsonpath-plus-6.0.1.tgz#9a3e16cedadfab07a3d8dc4e8cd5df4ed8f49c4d" resolved "https://registry.yarnpkg.com/jsonpath-plus/-/jsonpath-plus-6.0.1.tgz#9a3e16cedadfab07a3d8dc4e8cd5df4ed8f49c4d"
integrity sha512-EvGovdvau6FyLexFH2OeXfIITlgIbgZoAZe3usiySeaIDm5QS+A10DKNpaPBBqqRSZr2HN6HVNXxtwUAr2apEw== integrity sha512-EvGovdvau6FyLexFH2OeXfIITlgIbgZoAZe3usiySeaIDm5QS+A10DKNpaPBBqqRSZr2HN6HVNXxtwUAr2apEw==
jsonpointer@^5.0.0:
version "5.0.0"
resolved "https://registry.yarnpkg.com/jsonpointer/-/jsonpointer-5.0.0.tgz#f802669a524ec4805fa7389eadbc9921d5dc8072"
integrity sha512-PNYZIdMjVIvVgDSYKTT63Y+KZ6IZvGRNNWcxwD+GNnUz1MKPfv30J8ueCjdwcN0nDx2SlshgyB7Oy0epAzVRRg==
jsonpointer@^5.0.1: jsonpointer@^5.0.1:
version "5.0.1" version "5.0.1"
resolved "https://registry.yarnpkg.com/jsonpointer/-/jsonpointer-5.0.1.tgz#2110e0af0900fd37467b5907ecd13a7884a1b559" resolved "https://registry.yarnpkg.com/jsonpointer/-/jsonpointer-5.0.1.tgz#2110e0af0900fd37467b5907ecd13a7884a1b559"
@ -9958,6 +9965,11 @@ mark.js@^8.11.1:
resolved "https://registry.yarnpkg.com/mark.js/-/mark.js-8.11.1.tgz#180f1f9ebef8b0e638e4166ad52db879beb2ffc5" resolved "https://registry.yarnpkg.com/mark.js/-/mark.js-8.11.1.tgz#180f1f9ebef8b0e638e4166ad52db879beb2ffc5"
integrity sha1-GA8fnr74sOY45BZq1S24eb6y/8U= integrity sha1-GA8fnr74sOY45BZq1S24eb6y/8U=
markdown-to-jsx@^7.2.0:
version "7.2.0"
resolved "https://registry.yarnpkg.com/markdown-to-jsx/-/markdown-to-jsx-7.2.0.tgz#e7b46b65955f6a04d48a753acd55874a14bdda4b"
integrity sha512-3l4/Bigjm4bEqjCR6Xr+d4DtM1X6vvtGsMGSjJYyep8RjjIvcWtrXBS8Wbfe1/P+atKNMccpsraESIaWVplzVg==
marked@^0.7.0: marked@^0.7.0:
version "0.7.0" version "0.7.0"
resolved "https://registry.yarnpkg.com/marked/-/marked-0.7.0.tgz#b64201f051d271b1edc10a04d1ae9b74bb8e5c0e" resolved "https://registry.yarnpkg.com/marked/-/marked-0.7.0.tgz#b64201f051d271b1edc10a04d1ae9b74bb8e5c0e"
@ -11786,6 +11798,20 @@ rc-pagination@~3.1.17:
"@babel/runtime" "^7.10.1" "@babel/runtime" "^7.10.1"
classnames "^2.2.1" classnames "^2.2.1"
rc-picker@^2.6.11:
version "2.7.2"
resolved "https://registry.yarnpkg.com/rc-picker/-/rc-picker-2.7.2.tgz#bf656ca274228c84b955dfaa7705738908cb900f"
integrity sha512-KbUKgbzgWVN5L+V9xhZDKSmseHIyFneBlmuMtMrZ9fU7Oypw6D+owS5kuUicIEV08Y17oXt8dUqauMeC5IFBPg==
dependencies:
"@babel/runtime" "^7.10.1"
classnames "^2.2.1"
date-fns "2.x"
dayjs "1.x"
moment "^2.24.0"
rc-trigger "^5.0.4"
rc-util "^5.4.0"
shallowequal "^1.1.0"
rc-picker@~2.6.11: rc-picker@~2.6.11:
version "2.6.11" version "2.6.11"
resolved "https://registry.yarnpkg.com/rc-picker/-/rc-picker-2.6.11.tgz#d4a55e46480517cd1bfea5f5acd28b1d6be232d2" resolved "https://registry.yarnpkg.com/rc-picker/-/rc-picker-2.6.11.tgz#d4a55e46480517cd1bfea5f5acd28b1d6be232d2"
@ -12110,7 +12136,7 @@ react-is@16.10.2:
resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.10.2.tgz#984120fd4d16800e9a738208ab1fba422d23b5ab" resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.10.2.tgz#984120fd4d16800e9a738208ab1fba422d23b5ab"
integrity sha512-INBT1QEgtcCCgvccr5/86CfD71fw9EPmDxgiJX4I2Ddr6ZsV6iFXsuby+qWJPtmNuMY0zByTsG4468P7nHuNWA== integrity sha512-INBT1QEgtcCCgvccr5/86CfD71fw9EPmDxgiJX4I2Ddr6ZsV6iFXsuby+qWJPtmNuMY0zByTsG4468P7nHuNWA==
react-is@^16.12.0, react-is@^16.13.1, react-is@^16.6.0, react-is@^16.7.0, react-is@^16.8.1, react-is@^16.8.4, react-is@^16.8.6, react-is@^16.9.0: react-is@^16.12.0, react-is@^16.13.1, react-is@^16.6.0, react-is@^16.7.0, react-is@^16.8.1, react-is@^16.8.4, react-is@^16.8.6:
version "16.13.1" version "16.13.1"
resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.13.1.tgz#789729a4dc36de2999dc156dd6c1d9c18cea56a4" resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.13.1.tgz#789729a4dc36de2999dc156dd6c1d9c18cea56a4"
integrity sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ== integrity sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==