Fix #4746. UI: Connection Arguments and Connection Options should support inner dicts (#4779)

This commit is contained in:
Vivek Ratnavel Subramanian 2022-05-07 14:51:40 -07:00 committed by GitHub
parent 2730d13bcc
commit ae51a49ce1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 87 additions and 9 deletions

View File

@ -8,7 +8,7 @@
"javaType": "org.openmetadata.catalog.services.connections.database.ConnectionOptions",
"description": "Additional connection options that can be sent to service during the connection.",
"type": "object",
"patternProperties": {
"additionalProperties": {
".{1,}": { "type": "string" }
}
},
@ -16,7 +16,7 @@
"javaType": "org.openmetadata.catalog.services.connections.database.ConnectionArguments",
"description": "Additional connection arguments such as security or protocol configs that can be sent to service during connection.",
"type": "object",
"patternProperties": {
"additionalProperties": {
".{1,}": { "type": "string" }
}
},

View File

@ -125,7 +125,6 @@ database:
migrationConfiguration:
path: "./bootstrap/sql"
# Authorizer Configuration
# Authorizer Configuration
authorizerConfiguration:
className: ${AUTHORIZER_CLASS_NAME:-org.openmetadata.catalog.security.NoopAuthorizer}

View File

@ -35,7 +35,7 @@ import { ConfigData } from '../../interface/service.interface';
import jsonData from '../../jsons/en';
import { getDashboardConfig } from '../../utils/DashboardServiceUtils';
import { getDatabaseConfig } from '../../utils/DatabaseServiceUtils';
import { escapeBackwardSlashChar } from '../../utils/JSONSchemaFormUtils';
import { formatFormDataForSubmit } from '../../utils/JSONSchemaFormUtils';
import { getMessagingConfig } from '../../utils/MessagingServiceUtils';
import { getPipelineConfig } from '../../utils/PipelineServiceUtils';
import { showErrorToast } from '../../utils/ToastUtils';
@ -71,12 +71,12 @@ const ConnectionConfigForm: FunctionComponent<Props> = ({
: ({} as ConfigData);
const handleSave = (data: ISubmitEvent<ConfigData>) => {
const updatedFormData = escapeBackwardSlashChar(data.formData);
const updatedFormData = formatFormDataForSubmit(data.formData);
onSave({ ...data, formData: updatedFormData });
};
const handleTestConnection = (formData: ConfigData) => {
const updatedFormData = escapeBackwardSlashChar(formData);
const updatedFormData = formatFormDataForSubmit(formData);
return new Promise<void>((resolve, reject) => {
TestConnection(updatedFormData, 'Database')

View File

@ -18,6 +18,7 @@ import { debounce, isEmpty } from 'lodash';
import { LoadingState } from 'Models';
import React, { FunctionComponent, useCallback, useState } from 'react';
import { ConfigData } from '../../../interface/service.interface';
import { formatFormDataForRender } from '../../../utils/JSONSchemaFormUtils';
import SVGIcons, { Icons } from '../../../utils/SvgUtils';
import { Button } from '../../buttons/Button/Button';
import { ArrayFieldTemplate } from '../../JSONSchemaTemplate/ArrayFieldTemplate';
@ -43,18 +44,19 @@ const FormBuilder: FunctionComponent<Props> = ({
onCancel,
onSubmit,
onTestConnection,
uiSchema,
...props
}: Props) => {
let oForm: Form<ConfigData> | null;
const [localFormData, setLocalFormData] = useState<ConfigData | undefined>(
formData
formatFormDataForRender(formData)
);
const [connectionTesting, setConnectionTesting] = useState<boolean>(false);
const [connectionTestingState, setConnectionTestingState] =
useState<LoadingState>('initial');
const handleCancel = () => {
setLocalFormData(formData);
setLocalFormData(formatFormDataForRender(formData));
if (onCancel) {
onCancel();
}
@ -137,6 +139,7 @@ const FormBuilder: FunctionComponent<Props> = ({
oForm = form;
}}
schema={schema}
uiSchema={uiSchema}
onChange={(e) => {
handleChange(e.formData);
props.onChange && props.onChange(e);

View File

@ -11,7 +11,7 @@
* limitations under the License.
*/
import { isString } from 'lodash';
import { cloneDeep, isString } from 'lodash';
export function escapeBackwardSlashChar<T>(formData: T): T {
for (const key in formData) {
@ -30,3 +30,79 @@ export function escapeBackwardSlashChar<T>(formData: T): T {
return formData;
}
function formatConnectionFields<T>(formData: T, field: string): T {
if (formData && formData[field as keyof T]) {
// Since connection options support value of type string or object
// try to parse the string value as object
const options = formData[field as keyof T];
for (const key in options) {
const value = options[key];
try {
// eslint-disable-next-line @typescript-eslint/ban-ts-ignore
// @ts-ignore
formData[field as keyof T][key] = JSON.parse(value);
} catch (_) {
// ignore exception
}
}
}
return formData;
}
function formatAdditionalProperties<T>(formData: T): T {
for (const key in formData) {
if (typeof formData[key as keyof T] === 'object') {
formatAdditionalProperties(formData[key as keyof T]);
} else {
const data = formData[key as keyof T];
if (
key.startsWith('newKey') &&
data === ('New Value' as unknown as T[keyof T])
) {
delete formData[key];
}
}
}
return formData;
}
export function formatFormDataForSubmit<T>(formData: T): T {
formData = cloneDeep(formData);
formData = escapeBackwardSlashChar(formData);
formData = formatAdditionalProperties(formData);
formData = formatConnectionFields(formData, 'connectionOptions');
formData = formatConnectionFields(formData, 'connectionArguments');
return formData;
}
function formatConnectionFieldsForRender<T>(formData: T, field: string): T {
if (formData && formData[field as keyof T]) {
// Since connection options support value of type string or object
// convert object into string
const options = formData[field as keyof T];
for (const key in options) {
const value = options[key];
if (typeof value === 'object') {
// eslint-disable-next-line @typescript-eslint/ban-ts-ignore
// @ts-ignore
formData[field as keyof T][key] = JSON.stringify(value);
}
}
}
return formData;
}
export function formatFormDataForRender<T>(formData: T): T {
formData = cloneDeep(formData);
formData = formatConnectionFieldsForRender(formData, 'connectionOptions');
formData = formatConnectionFieldsForRender(formData, 'connectionArguments');
return formData;
}