From 763b96b8fe9f9d583e299b48c0692c255ced621a Mon Sep 17 00:00:00 2001 From: Chirag Madlani <12962843+chirag-madlani@users.noreply.github.com> Date: Thu, 18 May 2023 20:33:54 +0530 Subject: [PATCH] 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 --- .../source/dashboard/superset/connection.py | 4 +- .../source/dashboard/superset/metadata.py | 4 +- .../entity/utils/supersetApiConnection.json | 4 +- .../e2e/AddNewService/bigquery.spec.js | 20 +- .../e2e/AddNewService/superset.spec.js | 4 +- .../src/main/resources/ui/package.json | 7 +- .../resources/ui/parseConnectionSchema.js | 7 +- .../AddService/AddService.component.tsx | 20 +- .../JSONSchemaTemplate/ArrayFieldTemplate.tsx | 2 +- .../JSONSchemaTemplate/CustomFields.tsx | 4 +- .../ObjectFieldTemplate.tsx | 2 +- .../ServiceConfig/ConnectionConfigForm.tsx | 13 +- .../ServiceConfig/ServiceConfig.tsx | 35 +- .../ServiceConnectionDetails.component.tsx | 2 +- .../LabelCountSkeleton.component.tsx | 3 +- .../common/FormBuilder/FormBuilder.tsx | 82 ++-- .../AddServicePage.component.tsx | 25 +- .../ConnectionSchemas/SupersetConnection.json | 371 ++++++++++++++++++ .../ui/src/utils/DashboardServiceUtils.ts | 2 +- .../main/resources/ui/src/utils/formUtils.tsx | 25 ++ .../src/main/resources/ui/yarn.lock | 110 ++++-- 21 files changed, 579 insertions(+), 167 deletions(-) create mode 100644 openmetadata-ui/src/main/resources/ui/src/utils/ConnectionSchemas/SupersetConnection.json diff --git a/ingestion/src/metadata/ingestion/source/dashboard/superset/connection.py b/ingestion/src/metadata/ingestion/source/dashboard/superset/connection.py index 816836a2f32..dfe63afe560 100644 --- a/ingestion/src/metadata/ingestion/source/dashboard/superset/connection.py +++ b/ingestion/src/metadata/ingestion/source/dashboard/superset/connection.py @@ -30,7 +30,7 @@ from metadata.generated.schema.entity.services.connections.database.postgresConn PostgresConnection, ) from metadata.generated.schema.entity.utils.supersetApiConnection import ( - SupersetAPIConnection, + SupersetApiConnection, ) from metadata.ingestion.connections.test_connections import ( test_connection_engine_step, @@ -55,7 +55,7 @@ def get_connection(connection: SupersetConnection) -> SupersetAPIClient: """ Create connection """ - if isinstance(connection.connection, SupersetAPIConnection): + if isinstance(connection.connection, SupersetApiConnection): return SupersetAPIClient(connection) if isinstance(connection.connection, PostgresConnection): return pg_get_connection(connection=connection.connection) diff --git a/ingestion/src/metadata/ingestion/source/dashboard/superset/metadata.py b/ingestion/src/metadata/ingestion/source/dashboard/superset/metadata.py index cd893f6cbd2..e91cabb3af8 100644 --- a/ingestion/src/metadata/ingestion/source/dashboard/superset/metadata.py +++ b/ingestion/src/metadata/ingestion/source/dashboard/superset/metadata.py @@ -18,7 +18,7 @@ from metadata.generated.schema.entity.services.connections.metadata.openMetadata OpenMetadataConnection, ) from metadata.generated.schema.entity.utils.supersetApiConnection import ( - SupersetAPIConnection, + SupersetApiConnection, ) from metadata.generated.schema.metadataIngestion.workflow import ( Source as WorkflowSource, @@ -41,6 +41,6 @@ class SupersetSource: raise InvalidSourceException( f"Expected SupersetConnection, but got {connection}" ) - if isinstance(connection.connection, SupersetAPIConnection): + if isinstance(connection.connection, SupersetApiConnection): return SupersetAPISource(config, metadata_config) return SupersetDBSource(config, metadata_config) diff --git a/openmetadata-spec/src/main/resources/json/schema/entity/utils/supersetApiConnection.json b/openmetadata-spec/src/main/resources/json/schema/entity/utils/supersetApiConnection.json index 4252fdc77e4..b1777391993 100644 --- a/openmetadata-spec/src/main/resources/json/schema/entity/utils/supersetApiConnection.json +++ b/openmetadata-spec/src/main/resources/json/schema/entity/utils/supersetApiConnection.json @@ -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#", - "title": "SupersetAPIConnection", + "title": "SupersetApiConnection", "description": "Superset API Connection Config", "type": "object", "definitions": { diff --git a/openmetadata-ui/src/main/resources/ui/cypress/e2e/AddNewService/bigquery.spec.js b/openmetadata-ui/src/main/resources/ui/cypress/e2e/AddNewService/bigquery.spec.js index d524823d791..bbcedc69a02 100644 --- a/openmetadata-ui/src/main/resources/ui/cypress/e2e/AddNewService/bigquery.spec.js +++ b/openmetadata-ui/src/main/resources/ui/cypress/e2e/AddNewService/bigquery.spec.js @@ -37,29 +37,31 @@ describe('BigQuery Ingestion', () => { goToAddNewServicePage(SERVICE_TYPE.Database); const connectionInput = () => { const clientEmail = Cypress.env('bigqueryClientEmail'); - cy.get('.form-group > #root\\/type') + cy.get('.form-group > #root\\/credentials\\/gcsConfig\\/type') .scrollIntoView() .type('service_account'); checkServiceFieldSectionHighlighting('type'); - cy.get('#root\\/projectId') + cy.get('#root\\/credentials\\/gcsConfig\\/projectId') .scrollIntoView() .type(Cypress.env('bigqueryProjectId')); checkServiceFieldSectionHighlighting('projectId'); - cy.get('#root\\/privateKeyId') + cy.get('#root\\/credentials\\/gcsConfig\\/privateKeyId') .scrollIntoView() .type(Cypress.env('bigqueryPrivateKeyId')); checkServiceFieldSectionHighlighting('privateKeyId'); - cy.get('#root\\/privateKey') + cy.get('#root\\/credentials\\/gcsConfig\\/privateKey') .scrollIntoView() .type(Cypress.env('bigqueryPrivateKey')); checkServiceFieldSectionHighlighting('privateKey'); - cy.get('#root\\/clientEmail').scrollIntoView().type(clientEmail); + cy.get('#root\\/credentials\\/gcsConfig\\/clientEmail') + .scrollIntoView() + .type(clientEmail); checkServiceFieldSectionHighlighting('clientEmail'); - cy.get('#root\\/clientId') + cy.get('#root\\/credentials\\/gcsConfig\\/clientId') .scrollIntoView() .type(Cypress.env('bigqueryClientId')); checkServiceFieldSectionHighlighting('clientId'); - cy.get('#root\\/clientX509CertUrl') + cy.get('#root\\/credentials\\/gcsConfig\\/clientX509CertUrl') .scrollIntoView() .type( `https://www.googleapis.com/robot/v1/metadata/x509/${encodeURIComponent( @@ -71,10 +73,10 @@ describe('BigQuery Ingestion', () => { .scrollIntoView() .click(); checkServiceFieldSectionHighlighting('taxonomyProjectID'); - cy.get('#root\\/taxonomyProjectID_0') + cy.get('#root\\/taxonomyProjectID\\/0') .scrollIntoView() .type(Cypress.env('bigqueryProjectIdTaxonomy')); - checkServiceFieldSectionHighlighting('taxonomyProjectID'); + // checkServiceFieldSectionHighlighting('taxonomyProjectID'); }; const addIngestionInput = () => { diff --git a/openmetadata-ui/src/main/resources/ui/cypress/e2e/AddNewService/superset.spec.js b/openmetadata-ui/src/main/resources/ui/cypress/e2e/AddNewService/superset.spec.js index c14c172742a..c32dc440e84 100644 --- a/openmetadata-ui/src/main/resources/ui/cypress/e2e/AddNewService/superset.spec.js +++ b/openmetadata-ui/src/main/resources/ui/cypress/e2e/AddNewService/superset.spec.js @@ -41,10 +41,10 @@ describe('Superset Ingestion', () => { .click(); const connectionInput = () => { - cy.get('#root\\/username') + cy.get('#root\\/connection\\/username') .scrollIntoView() .type(Cypress.env('supersetUsername')); - cy.get('#root\\/password') + cy.get('#root\\/connection\\/password') .scrollIntoView() .type(Cypress.env('supersetPassword')); cy.get('#root\\/hostPort') diff --git a/openmetadata-ui/src/main/resources/ui/package.json b/openmetadata-ui/src/main/resources/ui/package.json index 827bcf42ade..76c4563cb97 100644 --- a/openmetadata-ui/src/main/resources/ui/package.json +++ b/openmetadata-ui/src/main/resources/ui/package.json @@ -23,9 +23,10 @@ "@github/g-emoji-element": "^1.1.5", "@okta/okta-auth-js": "^6.4.0", "@okta/okta-react": "^6.4.3", - "@rjsf/antd": "^5.0.0-beta.12", - "@rjsf/core": "^4.1.1", - "@rjsf/utils": "^5.0.0-beta.12", + "@rjsf/antd": "5.4.0", + "@rjsf/core": "5.4.0", + "@rjsf/utils": "5.4.0", + "@rjsf/validator-ajv8": "5.4.0", "@toast-ui/react-editor": "^3.1.8", "analytics": "^0.8.1", "antd": "4.24.0", diff --git a/openmetadata-ui/src/main/resources/ui/parseConnectionSchema.js b/openmetadata-ui/src/main/resources/ui/parseConnectionSchema.js index deb7f2e53a6..55114cd1046 100644 --- a/openmetadata-ui/src/main/resources/ui/parseConnectionSchema.js +++ b/openmetadata-ui/src/main/resources/ui/parseConnectionSchema.js @@ -15,6 +15,7 @@ const $RefParser = require('@apidevtools/json-schema-ref-parser'); const path = require('path'); const fs = require('fs'); const fse = require('fs-extra'); +const process = require('process'); const cwd = process.cwd(); @@ -34,13 +35,15 @@ const globalParserOptions = { }, }; +const parser = new $RefParser(globalParserOptions); + async function parseSchema(filePath, destPath) { try { const fileDir = `${cwd}/${path.dirname(filePath)}`; const fileName = path.basename(filePath); process.chdir(fileDir); - const parser = new $RefParser(globalParserOptions); - const schema = await parser.parse(fileName); + const parsedSchema = await parser.parse(fileName); + const schema = await parser.dereference(parsedSchema); const api = await parser.bundle(schema); const dirname = `${cwd}/${path.dirname(destPath)}`; if (!fs.existsSync(dirname)) { diff --git a/openmetadata-ui/src/main/resources/ui/src/components/AddService/AddService.component.tsx b/openmetadata-ui/src/main/resources/ui/src/components/AddService/AddService.component.tsx index e58b57d915c..e16f9704995 100644 --- a/openmetadata-ui/src/main/resources/ui/src/components/AddService/AddService.component.tsx +++ b/openmetadata-ui/src/main/resources/ui/src/components/AddService/AddService.component.tsx @@ -12,7 +12,9 @@ */ import { Card, Space, Typography } from 'antd'; +import { AxiosError } from 'axios'; import ResizablePanels from 'components/common/ResizablePanels/ResizablePanels'; +import { HTTP_STATUS_CODE } from 'constants/auth.constants'; import { SERVICE_DEFAULT_ERROR_MAP, STEPS_FOR_ADD_SERVICE, @@ -23,6 +25,7 @@ import { capitalize, isEmpty, isUndefined } from 'lodash'; import { LoadingState } from 'Models'; import React, { useEffect, useState } from 'react'; import { useHistory } from 'react-router-dom'; +import { showErrorToast } from 'utils/ToastUtils'; import { getServiceDetailsPath } from '../../constants/constants'; import { GlobalSettingsMenuCategory } from '../../constants/GlobalSettings.constants'; import { delimiterRegex, nameWithSpace } from '../../constants/regex.constants'; @@ -174,6 +177,19 @@ const AddService = ({ await fetchAirflowStatus(); } 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; } finally { setSaveServiceState('initial'); @@ -276,8 +292,8 @@ const AddService = ({ status={saveServiceState} onCancel={handleConnectionDetailsBackClick} onFocus={handleFieldFocus} - onSave={(e) => { - handleConfigUpdate(e.formData); + onSave={async (e) => { + e.formData && (await handleConfigUpdate(e.formData)); }} /> )} diff --git a/openmetadata-ui/src/main/resources/ui/src/components/JSONSchemaTemplate/ArrayFieldTemplate.tsx b/openmetadata-ui/src/main/resources/ui/src/components/JSONSchemaTemplate/ArrayFieldTemplate.tsx index 1084c668738..35c78f5dee5 100644 --- a/openmetadata-ui/src/main/resources/ui/src/components/JSONSchemaTemplate/ArrayFieldTemplate.tsx +++ b/openmetadata-ui/src/main/resources/ui/src/components/JSONSchemaTemplate/ArrayFieldTemplate.tsx @@ -12,7 +12,7 @@ */ import { PlusOutlined } from '@ant-design/icons'; -import { ArrayFieldTemplateProps } from '@rjsf/core'; +import { ArrayFieldTemplateProps } from '@rjsf/utils'; import { Button } from 'antd'; import classNames from 'classnames'; import { t } from 'i18next'; diff --git a/openmetadata-ui/src/main/resources/ui/src/components/JSONSchemaTemplate/CustomFields.tsx b/openmetadata-ui/src/main/resources/ui/src/components/JSONSchemaTemplate/CustomFields.tsx index 0ae31c09258..2ac688c8b59 100644 --- a/openmetadata-ui/src/main/resources/ui/src/components/JSONSchemaTemplate/CustomFields.tsx +++ b/openmetadata-ui/src/main/resources/ui/src/components/JSONSchemaTemplate/CustomFields.tsx @@ -1,3 +1,5 @@ +import { RegistryFieldsType } from '@rjsf/utils'; + /* * Copyright 2023 Collate. * Licensed under the Apache License, Version 2.0 (the "License"); @@ -14,6 +16,6 @@ const CustomDescriptionField = () => { return null; }; -export const customFields = { +export const customFields: RegistryFieldsType = { DescriptionField: CustomDescriptionField, }; diff --git a/openmetadata-ui/src/main/resources/ui/src/components/JSONSchemaTemplate/ObjectFieldTemplate.tsx b/openmetadata-ui/src/main/resources/ui/src/components/JSONSchemaTemplate/ObjectFieldTemplate.tsx index 012b4486577..57fba2bfda9 100644 --- a/openmetadata-ui/src/main/resources/ui/src/components/JSONSchemaTemplate/ObjectFieldTemplate.tsx +++ b/openmetadata-ui/src/main/resources/ui/src/components/JSONSchemaTemplate/ObjectFieldTemplate.tsx @@ -12,7 +12,7 @@ */ import { PlusOutlined } from '@ant-design/icons'; -import { ObjectFieldTemplateProps } from '@rjsf/core'; +import { ObjectFieldTemplateProps } from '@rjsf/utils'; import { Button, Space } from 'antd'; import classNames from 'classnames'; import { isUndefined } from 'lodash'; diff --git a/openmetadata-ui/src/main/resources/ui/src/components/ServiceConfig/ConnectionConfigForm.tsx b/openmetadata-ui/src/main/resources/ui/src/components/ServiceConfig/ConnectionConfigForm.tsx index bac688b7a18..6ebd643a5ae 100644 --- a/openmetadata-ui/src/main/resources/ui/src/components/ServiceConfig/ConnectionConfigForm.tsx +++ b/openmetadata-ui/src/main/resources/ui/src/components/ServiceConfig/ConnectionConfigForm.tsx @@ -11,7 +11,8 @@ * 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 { cloneDeep, isNil } from 'lodash'; import { LoadingState } from 'Models'; @@ -41,8 +42,8 @@ interface Props { serviceType: string; serviceCategory: ServiceCategory; status: LoadingState; - onFocus: (fieldName: string) => void; - onSave: (data: ISubmitEvent) => void; + onFocus: (id: string) => void; + onSave: (data: IChangeEvent) => Promise; disableTestConnection?: boolean; onCancel?: () => void; } @@ -63,9 +64,10 @@ const ConnectionConfigForm: FunctionComponent = ({ ? ((data as ServicesType).connection?.config as ConfigData) : ({} as ConfigData); - const handleSave = (data: ISubmitEvent) => { + const handleSave = async (data: IChangeEvent) => { const updatedFormData = formatFormDataForSubmit(data.formData); - onSave({ ...data, formData: updatedFormData }); + + await onSave({ ...data, formData: updatedFormData }); }; const getConfigFields = () => { @@ -132,6 +134,7 @@ const ConnectionConfigForm: FunctionComponent = ({ serviceType={serviceType} status={status} uiSchema={connSch.uiSchema} + validator={validator} onCancel={onCancel} onFocus={onFocus} onSubmit={handleSave} diff --git a/openmetadata-ui/src/main/resources/ui/src/components/ServiceConfig/ServiceConfig.tsx b/openmetadata-ui/src/main/resources/ui/src/components/ServiceConfig/ServiceConfig.tsx index fdab92a8465..1dded46989d 100644 --- a/openmetadata-ui/src/main/resources/ui/src/components/ServiceConfig/ServiceConfig.tsx +++ b/openmetadata-ui/src/main/resources/ui/src/components/ServiceConfig/ServiceConfig.tsx @@ -11,7 +11,7 @@ * limitations under the License. */ -import { ISubmitEvent } from '@rjsf/core'; +import { IChangeEvent } from '@rjsf/core'; import { LoadingState, ServicesData } from 'Models'; import React, { useState } from 'react'; import { useHistory } from 'react-router-dom'; @@ -34,7 +34,7 @@ interface ServiceConfigProps { serviceCategory: ServiceCategory ) => Promise; disableTestConnection: boolean; - onFocus: (fieldName: string) => void; + onFocus: (id: string) => void; } export const Field = ({ children }: { children: React.ReactNode }) => { @@ -53,21 +53,24 @@ const ServiceConfig = ({ const history = useHistory(); const [status, setStatus] = useState('initial'); - const handleOnSaveClick = (e: ISubmitEvent) => { + const handleOnSaveClick = async (e: IChangeEvent) => { + if (!e.formData) { + return; + } setStatus('waiting'); - - handleUpdate(e.formData, serviceCategory) - .then(() => { - setTimeout(() => { - setStatus('success'); - history.push(getPathByServiceFQN(serviceCategory, serviceFQN)); - }, 200); - }) - .finally(() => { - setTimeout(() => { - setStatus('initial'); - }, 500); - }); + try { + await handleUpdate(e.formData, serviceCategory); + setTimeout(() => { + setStatus('success'); + history.push(getPathByServiceFQN(serviceCategory, serviceFQN)); + }, 200); + } catch (err) { + // Nothing here + } finally { + setTimeout(() => { + setStatus('initial'); + }, 500); + } }; const onCancel = () => { diff --git a/openmetadata-ui/src/main/resources/ui/src/components/ServiceConnectionDetails/ServiceConnectionDetails.component.tsx b/openmetadata-ui/src/main/resources/ui/src/components/ServiceConnectionDetails/ServiceConnectionDetails.component.tsx index 4238d664543..00afb704f7e 100644 --- a/openmetadata-ui/src/main/resources/ui/src/components/ServiceConnectionDetails/ServiceConnectionDetails.component.tsx +++ b/openmetadata-ui/src/main/resources/ui/src/components/ServiceConnectionDetails/ServiceConnectionDetails.component.tsx @@ -169,7 +169,7 @@ const ServiceConnectionDetails = ({ : {}; return ( - + diff --git a/openmetadata-ui/src/main/resources/ui/src/components/Skeleton/CommonSkeletons/LabelCountSkeleton/LabelCountSkeleton.component.tsx b/openmetadata-ui/src/main/resources/ui/src/components/Skeleton/CommonSkeletons/LabelCountSkeleton/LabelCountSkeleton.component.tsx index 651c8151427..6735fe87f4a 100644 --- a/openmetadata-ui/src/main/resources/ui/src/components/Skeleton/CommonSkeletons/LabelCountSkeleton/LabelCountSkeleton.component.tsx +++ b/openmetadata-ui/src/main/resources/ui/src/components/Skeleton/CommonSkeletons/LabelCountSkeleton/LabelCountSkeleton.component.tsx @@ -15,7 +15,6 @@ import React from 'react'; import { LabelCountSkeletonProps } from '../../Skeleton.interfaces'; const LabelCountSkeleton = ({ - key, isSelect, isLabel, isCount, @@ -27,7 +26,7 @@ const LabelCountSkeleton = ({ ...props }: LabelCountSkeletonProps) => { return ( - + {isSelect || isLabel ? (
diff --git a/openmetadata-ui/src/main/resources/ui/src/components/common/FormBuilder/FormBuilder.tsx b/openmetadata-ui/src/main/resources/ui/src/components/common/FormBuilder/FormBuilder.tsx index e918c52e11a..ae58f50ba97 100644 --- a/openmetadata-ui/src/main/resources/ui/src/components/common/FormBuilder/FormBuilder.tsx +++ b/openmetadata-ui/src/main/resources/ui/src/components/common/FormBuilder/FormBuilder.tsx @@ -12,27 +12,26 @@ */ import { CheckOutlined } from '@ant-design/icons'; -import Form from '@rjsf/antd'; -import CoreForm, { AjvError, FormProps, IChangeEvent } from '@rjsf/core'; -import validateFormData from '@rjsf/core/lib/validate'; -import { Button as AntDButton } from 'antd'; +import Form, { FormProps, IChangeEvent } from '@rjsf/core'; +import { Button } from 'antd'; import classNames from 'classnames'; +import { ArrayFieldTemplate } from 'components/JSONSchemaTemplate/ArrayFieldTemplate'; import { customFields } from 'components/JSONSchemaTemplate/CustomFields'; +import { ObjectFieldTemplate } from 'components/JSONSchemaTemplate/ObjectFieldTemplate'; import { ServiceCategory } from 'enums/service.enum'; import { useAirflowStatus } from 'hooks/useAirflowStatus'; import { t } from 'i18next'; -import { isEmpty, isUndefined, startCase } from 'lodash'; +import { isEmpty, isUndefined } from 'lodash'; import { LoadingState } from 'Models'; import React, { FunctionComponent, useEffect, useRef, useState } from 'react'; import { getPipelineServiceHostIp } from 'rest/ingestionPipelineAPI'; +import { transformErrors } from 'utils/formUtils'; import { ConfigData } from '../../../interface/service.interface'; import { formatFormDataForRender } from '../../../utils/JSONSchemaFormUtils'; -import { ArrayFieldTemplate } from '../../JSONSchemaTemplate/ArrayFieldTemplate'; -import { ObjectFieldTemplate } from '../../JSONSchemaTemplate/ObjectFieldTemplate'; import Loader from '../../Loader/Loader'; import TestConnection from '../TestConnection/TestConnection'; -interface Props extends FormProps { +interface Props extends FormProps { okText: string; cancelText: string; disableTestConnection: boolean; @@ -42,7 +41,6 @@ interface Props extends FormProps { showFormHeader?: boolean; status?: LoadingState; onCancel?: () => void; - onFocus: (fieldName: string) => void; } const FormBuilder: FunctionComponent = ({ @@ -64,7 +62,7 @@ const FormBuilder: FunctionComponent = ({ }: Props) => { const { isAirflowAvailable } = useAirflowStatus(); - const formRef = useRef>(); + const formRef = useRef>(null); const [localFormData, setLocalFormData] = useState( formatFormDataForRender(formData ?? {}) ); @@ -97,39 +95,20 @@ const FormBuilder: FunctionComponent = ({ } }; - 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 validationObject = validateFormData(localFormData, schema); - const isFormValid = isEmpty(validationObject.errors); - if (!isFormValid) { - formRef.current?.submit(); - } + return Boolean(formRef.current?.validateForm()); + }; - return isFormValid; + const handleFormChange = (e: IChangeEvent) => { + setLocalFormData(e.formData); + props.onChange && props.onChange(e); }; return (
= ({ ref={formRef} schema={schema} showErrorList={false} + templates={{ + ArrayFieldTemplate: ArrayFieldTemplate, + ObjectFieldTemplate: ObjectFieldTemplate, + }} transformErrors={transformErrors} uiSchema={uiSchema} - onChange={(e: IChangeEvent) => { - handleChange(e.formData); - props.onChange && props.onChange(e); - }} + onChange={handleFormChange} onFocus={onFocus} onSubmit={onSubmit} {...props}> @@ -176,31 +156,31 @@ const FormBuilder: FunctionComponent = ({
- + {status === 'waiting' ? ( - - + ) : status === 'success' ? ( - - + ) : ( - + htmlType="submit" + type="primary"> {okText} - + )}
diff --git a/openmetadata-ui/src/main/resources/ui/src/pages/AddServicePage/AddServicePage.component.tsx b/openmetadata-ui/src/main/resources/ui/src/pages/AddServicePage/AddServicePage.component.tsx index 3fe558d13da..7d036d1dc52 100644 --- a/openmetadata-ui/src/main/resources/ui/src/pages/AddServicePage/AddServicePage.component.tsx +++ b/openmetadata-ui/src/main/resources/ui/src/pages/AddServicePage/AddServicePage.component.tsx @@ -61,28 +61,9 @@ const AddServicePage = () => { setAddIngestion(value); }; - const onAddServiceSave = (data: DataObj) => { - return new Promise((resolve, reject) => { - postService(serviceCategory, data) - .then((res) => { - if (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 onAddServiceSave = async (data: DataObj) => { + const res = await postService(serviceCategory, data); + setNewServiceData(res); }; const onIngestionDeploy = (id?: string) => { diff --git a/openmetadata-ui/src/main/resources/ui/src/utils/ConnectionSchemas/SupersetConnection.json b/openmetadata-ui/src/main/resources/ui/src/utils/ConnectionSchemas/SupersetConnection.json new file mode 100644 index 00000000000..65077f8e485 --- /dev/null +++ b/openmetadata-ui/src/main/resources/ui/src/utils/ConnectionSchemas/SupersetConnection.json @@ -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"] +} diff --git a/openmetadata-ui/src/main/resources/ui/src/utils/DashboardServiceUtils.ts b/openmetadata-ui/src/main/resources/ui/src/utils/DashboardServiceUtils.ts index 570ff1ccae0..f927798f51f 100644 --- a/openmetadata-ui/src/main/resources/ui/src/utils/DashboardServiceUtils.ts +++ b/openmetadata-ui/src/main/resources/ui/src/utils/DashboardServiceUtils.ts @@ -25,8 +25,8 @@ import modeConnection from '../jsons/connectionSchemas/connections/dashboard/mod import powerBIConnection from '../jsons/connectionSchemas/connections/dashboard/powerBIConnection.json'; import quicksightConnection from '../jsons/connectionSchemas/connections/dashboard/quickSightConnection.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 supersetConnection from './ConnectionSchemas/SupersetConnection.json'; export const getDashboardURL = (config: DashboardConnection['config']) => { return !isUndefined(config) && !isEmpty(config.hostPort) diff --git a/openmetadata-ui/src/main/resources/ui/src/utils/formUtils.tsx b/openmetadata-ui/src/main/resources/ui/src/utils/formUtils.tsx index f428410797d..f6192ab55e0 100644 --- a/openmetadata-ui/src/main/resources/ui/src/utils/formUtils.tsx +++ b/openmetadata-ui/src/main/resources/ui/src/utils/formUtils.tsx @@ -10,6 +10,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ +import { ErrorTransformer } from '@rjsf/utils'; import { Divider, 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 SliderWithInput from 'components/SliderWithInput/SliderWithInput'; import { SliderWithInputProps } from 'components/SliderWithInput/SliderWithInput.interface'; +import { compact, startCase } from 'lodash'; import React, { Fragment, ReactNode } from 'react'; import i18n from './i18next/LocalUtil'; @@ -164,3 +166,26 @@ export const getField = (field: FieldProp) => { export const generateFormFields = (fields: FieldProp[]) => { 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); +}; diff --git a/openmetadata-ui/src/main/resources/ui/yarn.lock b/openmetadata-ui/src/main/resources/ui/yarn.lock index d8ea1cfe90b..2e5464b94b9 100644 --- a/openmetadata-ui/src/main/resources/ui/yarn.lock +++ b/openmetadata-ui/src/main/resources/ui/yarn.lock @@ -108,9 +108,9 @@ resize-observer-polyfill "^1.5.1" "@apidevtools/json-schema-ref-parser@^9.0.9": - version "9.0.9" - resolved "https://registry.yarnpkg.com/@apidevtools/json-schema-ref-parser/-/json-schema-ref-parser-9.0.9.tgz#d720f9256e3609621280584f2b47ae165359268b" - integrity sha512-GBD2Le9w2+lVFoc4vswGI/TjkNIZSVp7+9xPf+X3uidBfWnAeUWmquteSyt0+VCrhNMWj/FTABISQrD3Z/YA+w== + version "9.1.2" + resolved "https://registry.yarnpkg.com/@apidevtools/json-schema-ref-parser/-/json-schema-ref-parser-9.1.2.tgz#8ff5386b365d4c9faa7c8b566ff16a46a577d9b8" + integrity sha512-r1w81DpR+KyRWd3f+rk6TNqMgedmAxZP5v5KWlXQWlgMUUtyEJch0DKEci1SorPMiSeM8XPl7MZ3miJ60JIpQg== dependencies: "@jsdevtools/ono" "^7.1.3" "@types/json-schema" "^7.0.6" @@ -2883,30 +2883,31 @@ classcat "^5.0.3" zustand "^4.1.1" -"@rjsf/antd@^5.0.0-beta.12": - version "5.0.0-beta.12" - resolved "https://registry.yarnpkg.com/@rjsf/antd/-/antd-5.0.0-beta.12.tgz#357579a120af186a18b894c9f5c4b2c111f6b536" - integrity sha512-2U5x4DV3TeVQFjX6YJgLBw1ND/sJoZlUyePTyygOPqltto4wPUdXdJS7m5+zRinowlCZrcr9l2u7RCwA4Bnpwg== - -"@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== +"@rjsf/antd@5.4.0": + version "5.4.0" + resolved "https://registry.yarnpkg.com/@rjsf/antd/-/antd-5.4.0.tgz#194a784272a5782aeea35d80e25ee5a5b076bfa4" + integrity sha512-mC96NITW/CFfPtF/J8EdxStaP/Jc/EfEaIB00GyUWbZUYjXFJ+cAeltfXFQPOrrlC6gFCDRbkZexRW+Hazv6eA== dependencies: - "@types/json-schema" "^7.0.7" - ajv "^6.7.0" - core-js-pure "^3.6.5" - json-schema-merge-allof "^0.6.0" - jsonpointer "^5.0.0" + classnames "^2.3.2" lodash "^4.17.15" - nanoid "^3.1.23" - prop-types "^15.7.2" - react-is "^16.9.0" + lodash-es "^4.17.15" + rc-picker "^2.6.11" -"@rjsf/utils@^5.0.0-beta.12": - version "5.0.0-beta.12" - resolved "https://registry.yarnpkg.com/@rjsf/utils/-/utils-5.0.0-beta.12.tgz#a03f9da784896744a1908e8fd4dec0a36e90704b" - integrity sha512-RH965WMGp3Z25iQ2PTn+BFkQusJuvG0e2fl8V+wx1N21EkrZnW2+twouWUmqNqHwke2Z0OOimF5picZVgobl7g== +"@rjsf/core@5.4.0": + version "5.4.0" + resolved "https://registry.yarnpkg.com/@rjsf/core/-/core-5.4.0.tgz#d75e42a5b8fe9af7b62b04fd8b93629f4e1fa5a7" + 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: json-schema-merge-allof "^0.8.1" jsonpointer "^5.0.1" @@ -2914,6 +2915,16 @@ lodash-es "^4.17.15" 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": version "0.3.3" 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: 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" resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.12.6.tgz#baf5a62e802b07d977034586f8c3baf5adf26df4" integrity sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g== @@ -4382,6 +4393,16 @@ ajv@^8.0.1: require-from-string "^2.0.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: version "1.0.1" 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-integer-array "^1.0.0" -compute-lcm@^1.1.0, compute-lcm@^1.1.2: +compute-lcm@^1.1.2: version "1.1.2" resolved "https://registry.yarnpkg.com/compute-lcm/-/compute-lcm-1.1.2.tgz#9107c66b9dca28cefb22b4ab4545caac4034af23" 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" 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" resolved "https://registry.yarnpkg.com/core-js-pure/-/core-js-pure-3.21.1.tgz#8c4d1e78839f5f46208de7230cebfb72bc3bdb51" integrity sha512-12VZfFIu+wyVbBebyHmRTuEE/tZrB4tJToWcwAMcsp3h4+sHR+fMJWbKpYiCRWlhFBq+KNyO8rIV9rTkeVmznQ== @@ -9455,15 +9476,6 @@ json-schema-compare@^0.2.2: dependencies: 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: version "0.8.1" 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" 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: version "5.0.1" 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" 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: version "0.7.0" 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" 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: version "2.6.11" 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" 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" resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.13.1.tgz#789729a4dc36de2999dc156dd6c1d9c18cea56a4" integrity sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==