Skip to content

Commit

Permalink
fix(ui) Followups to recent changes to UI ingestion forms (#5602)
Browse files Browse the repository at this point in the history
  • Loading branch information
chriscollins3456 authored Aug 10, 2022
1 parent 39c9194 commit 626196d
Show file tree
Hide file tree
Showing 8 changed files with 74 additions and 56 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import { YamlEditor } from './YamlEditor';
import { ANTD_GRAY } from '../../../entity/shared/constants';
import { IngestionSourceBuilderStep } from './steps';
import RecipeBuilder from './RecipeBuilder';
import { CONNECTORS_WITH_FORM } from './RecipeForm/utils';
import { CONNECTORS_WITH_FORM } from './RecipeForm/constants';
import { getRecipeJson } from './RecipeForm/TestConnection/TestConnectionButton';

const LOOKML_DOC_LINK = 'https://datahubproject.io/docs/generated/ingestion/sources/looker#module-lookml';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { MinusCircleOutlined, PlusOutlined, QuestionCircleOutlined } from '@ant-
import { ANTD_GRAY } from '../../../../entity/shared/constants';
import { RecipeField, FieldType } from './common';
import { Secret } from '../../../../../types.generated';
import SecretField from './SecretField/SecretField';
import SecretField, { StyledFormItem } from './SecretField/SecretField';

const Label = styled.div`
font-weight: bold;
Expand All @@ -27,24 +27,6 @@ const StyledRemoveIcon = styled(MinusCircleOutlined)`
margin-left: 10px;
`;

const StyledFormItem = styled(Form.Item)<{ alignLeft?: boolean; removeMargin: boolean }>`
margin-bottom: ${(props) => (props.removeMargin ? '0' : '16px')};
${(props) =>
props.alignLeft &&
`
.ant-form-item {
flex-direction: row;
}
.ant-form-item-label {
padding: 0;
margin-right: 10px;
}
`}
`;

const ListWrapper = styled.div<{ removeMargin: boolean }>`
margin-bottom: ${(props) => (props.removeMargin ? '0' : '16px')};
`;
Expand Down Expand Up @@ -116,7 +98,9 @@ function FormField(props: Props) {
if (field.type === FieldType.SELECT) return <SelectField field={field} removeMargin={removeMargin} />;

if (field.type === FieldType.SECRET)
return <SecretField field={field} secrets={secrets} refetchSecrets={refetchSecrets} />;
return (
<SecretField field={field} secrets={secrets} removeMargin={removeMargin} refetchSecrets={refetchSecrets} />
);

const isBoolean = field.type === FieldType.BOOLEAN;
const input = isBoolean ? <Checkbox /> : <Input placeholder={field.placeholder} />;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import YAML from 'yamljs';
import { ApiOutlined, FilterOutlined, QuestionCircleOutlined, SettingOutlined } from '@ant-design/icons';
import styled from 'styled-components/macro';
import { jsonToYaml } from '../../utils';
import { RECIPE_FIELDS } from './utils';
import { RECIPE_FIELDS } from './constants';
import FormField from './FormField';
import TestConnectionButton from './TestConnection/TestConnectionButton';
import { SNOWFLAKE } from '../../conf/snowflake/snowflake';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,15 +9,34 @@ const StyledDivider = styled(Divider)`
margin: 0;
`;

export const StyledFormItem = styled(Form.Item)<{ alignLeft?: boolean; removeMargin: boolean }>`
margin-bottom: ${(props) => (props.removeMargin ? '0' : '16px')};
${(props) =>
props.alignLeft &&
`
.ant-form-item {
flex-direction: row;
}
.ant-form-item-label {
padding: 0;
margin-right: 10px;
}
`}
`;

interface SecretFieldProps {
field: RecipeField;
secrets: Secret[];
removeMargin?: boolean;
refetchSecrets: () => void;
}

function SecretField({ field, secrets, refetchSecrets }: SecretFieldProps) {
function SecretField({ field, secrets, removeMargin, refetchSecrets }: SecretFieldProps) {
return (
<Form.Item name={field.name} label={field.label} tooltip={field.tooltip}>
<StyledFormItem name={field.name} label={field.label} tooltip={field.tooltip} removeMargin={!!removeMargin}>
<Select
showSearch
filterOption={(input, option) => !!option?.children.toLowerCase().includes(input.toLowerCase())}
Expand All @@ -35,7 +54,7 @@ function SecretField({ field, secrets, refetchSecrets }: SecretFieldProps) {
</Select.Option>
))}
</Select>
</Form.Item>
</StyledFormItem>
);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { setFieldValueOnRecipe, setListValuesOnRecipe } from '../common';
describe('setFieldValueOnRecipe', () => {
const accountIdFieldPath = 'source.config.account_id';
const profilingEnabledFieldPath = 'source.config.profiling.enabled';
const dottedFieldPath = ['source', 'config', 'profiling', 'enabled.test'];

it('should set the field value on a recipe object when it was not defined', () => {
const recipe = { source: { config: {} } };
Expand Down Expand Up @@ -63,6 +64,28 @@ describe('setFieldValueOnRecipe', () => {
const updatedRecipe = setFieldValueOnRecipe(recipe, null, 'source.config.profiling.testing');
expect(updatedRecipe).toMatchObject({ source: { config: { test: 'test', profiling: { enabled: true } } } });
});

it('should set the field when the key is a dotted value', () => {
const recipe = { source: { config: { test: 'test', profiling: { 'enabled.test': true } } } };
const updatedRecipe = setFieldValueOnRecipe(recipe, false, dottedFieldPath);
expect(updatedRecipe).toMatchObject({
source: { config: { test: 'test', profiling: { 'enabled.test': false } } },
});
});

it('should clear the dotted field and its parent when passing in null and field is only child of parent', () => {
const recipe = { source: { config: { test: 'test', profiling: { 'enabled.test': true } } } };
const updatedRecipe = setFieldValueOnRecipe(recipe, null, dottedFieldPath);
expect(updatedRecipe).toMatchObject({
source: { config: { test: 'test' } },
});
});

it('should clear the dotted field but not its parent when passing in null and parent has other children', () => {
const recipe = { source: { config: { test: 'test', profiling: { 'enabled.test': true, testing: 'this' } } } };
const updatedRecipe = setFieldValueOnRecipe(recipe, null, dottedFieldPath);
expect(updatedRecipe).toMatchObject({ source: { config: { test: 'test', profiling: { testing: 'this' } } } });
});
});

describe('setListValuesOnRecipe', () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,10 +29,14 @@ export interface RecipeField {
placeholder?: string;
}

function clearFieldAndParents(recipe: any, fieldPath: string) {
function clearFieldAndParents(recipe: any, fieldPath: string | string[]) {
set(recipe, fieldPath, undefined);

const updatedFieldPath = fieldPath.split('.').slice(0, -1).join('.'); // remove last item from fieldPath
// remove last item from fieldPath
const updatedFieldPath = Array.isArray(fieldPath)
? fieldPath.slice(0, -1).join('.')
: fieldPath.split('.').slice(0, -1).join('.');

if (updatedFieldPath) {
const parentKeys = Object.keys(get(recipe, updatedFieldPath));

Expand All @@ -43,8 +47,7 @@ function clearFieldAndParents(recipe: any, fieldPath: string) {
}
return recipe;
}

export function setFieldValueOnRecipe(recipe: any, value: any, fieldPath: string) {
export function setFieldValueOnRecipe(recipe: any, value: any, fieldPath: string | string[]) {
const updatedRecipe = { ...recipe };
if (value !== undefined) {
if (value === null) {
Expand All @@ -67,19 +70,6 @@ export function setListValuesOnRecipe(recipe: any, values: string[] | undefined,
return updatedRecipe;
}

export function setDottedFieldValuesOnRecipe(recipe: any, value: any, fieldPath: string[]) {
const updatedRecipe = { ...recipe };
if (value !== undefined) {
if (value === null) {
set(recipe, fieldPath, undefined);
clearFieldAndParents(updatedRecipe, fieldPath.slice(0, -1).join('.'));
return updatedRecipe;
}
set(updatedRecipe, fieldPath, value);
}
return updatedRecipe;
}

/* ---------------------------------------------------- Filter Section ---------------------------------------------------- */
const databaseAllowFieldPath = 'source.config.database_pattern.allow';
export const DATABASE_ALLOW: RecipeField = {
Expand Down Expand Up @@ -254,7 +244,7 @@ export const PROFILING_ENABLED: RecipeField = {
export const STATEFUL_INGESTION_ENABLED: RecipeField = {
name: 'stateful_ingestion.enabled',
label: 'Enable Stateful Ingestion',
tooltip: 'Enable the type of the ingestion state provider registered with datahub.',
tooltip: 'Remove stale datasets from datahub once they have been deleted in the source.',
type: FieldType.BOOLEAN,
fieldPath: 'source.config.stateful_ingestion.enabled',
rules: null,
Expand All @@ -263,7 +253,7 @@ export const STATEFUL_INGESTION_ENABLED: RecipeField = {
export const UPSTREAM_LINEAGE_IN_REPORT: RecipeField = {
name: 'upstream_lineage_in_report',
label: 'Include Upstream Lineage In Report.',
tooltip: 'Remove stale datasets from datahub once they have been deleted in the source.',
tooltip: 'Useful for debugging lineage information. Set to True to see the raw lineage created internally.',
type: FieldType.BOOLEAN,
fieldPath: 'source.config.upstream_lineage_in_report',
rules: null,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import {
EXTRACT_USAGE_HISTORY,
EXTRACT_OWNERS,
SKIP_PERSONAL_FOLDERS,
RecipeField,
} from './common';
import {
SNOWFLAKE_ACCOUNT_ID,
Expand Down Expand Up @@ -74,7 +75,18 @@ import {
TOPIC_DENY,
} from './kafka';

export const RECIPE_FIELDS = {
interface RecipeFields {
[key: string]: {
fields: RecipeField[];
filterFields: RecipeField[];
advancedFields: RecipeField[];
connectionSectionTooltip?: string;
filterSectionTooltip?: string;
advancedSectionTooltip?: string;
};
}

export const RECIPE_FIELDS: RecipeFields = {
[SNOWFLAKE]: {
fields: [SNOWFLAKE_ACCOUNT_ID, SNOWFLAKE_WAREHOUSE, SNOWFLAKE_USERNAME, SNOWFLAKE_PASSWORD, SNOWFLAKE_ROLE],
advancedFields: [INCLUDE_LINEAGE, PROFILING_ENABLED, STATEFUL_INGESTION_ENABLED],
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { RecipeField, FieldType, setDottedFieldValuesOnRecipe, setListValuesOnRecipe } from './common';
import { RecipeField, FieldType, setListValuesOnRecipe } from './common';

const saslUsernameFieldPath = ['source', 'config', 'connection', 'consumer_config', 'sasl.username'];
export const KAFKA_SASL_USERNAME: RecipeField = {
Expand All @@ -8,8 +8,6 @@ export const KAFKA_SASL_USERNAME: RecipeField = {
type: FieldType.TEXT,
fieldPath: saslUsernameFieldPath,
rules: null,
setValueOnRecipeOverride: (recipe: any, values: string[]) =>
setDottedFieldValuesOnRecipe(recipe, values, saslUsernameFieldPath),
};

const saslPasswordFieldPath = ['source', 'config', 'connection', 'consumer_config', 'sasl.password'];
Expand All @@ -20,8 +18,6 @@ export const KAFKA_SASL_PASSWORD: RecipeField = {
type: FieldType.TEXT,
fieldPath: saslPasswordFieldPath,
rules: null,
setValueOnRecipeOverride: (recipe: any, values: string[]) =>
setDottedFieldValuesOnRecipe(recipe, values, saslPasswordFieldPath),
};

export const KAFKA_BOOTSTRAP: RecipeField = {
Expand Down Expand Up @@ -61,8 +57,6 @@ export const KAFKA_SCHEMA_REGISTRY_USER_CREDENTIAL: RecipeField = {
type: FieldType.TEXT,
fieldPath: registryCredentialsFieldPath,
rules: null,
setValueOnRecipeOverride: (recipe: any, values: string[]) =>
setDottedFieldValuesOnRecipe(recipe, values, registryCredentialsFieldPath),
};

const securityProtocolFieldPath = ['source', 'config', 'connection', 'consumer_config', 'security.protocol'];
Expand All @@ -77,8 +71,6 @@ export const KAFKA_SECURITY_PROTOCOL: RecipeField = {
{ label: 'SASL_SSL', value: 'SASL_SSL' },
{ label: 'SASL_PLAINTEXT', value: 'SASL_PLAINTEXT' },
],
setValueOnRecipeOverride: (recipe: any, values: string[]) =>
setDottedFieldValuesOnRecipe(recipe, values, securityProtocolFieldPath),
};

const saslMechanismFieldPath = ['source', 'config', 'connection', 'consumer_config', 'sasl.mechanism'];
Expand All @@ -94,8 +86,6 @@ export const KAFKA_SASL_MECHANISM: RecipeField = {
{ label: 'SCRAM-SHA-256', value: 'SCRAM-SHA-256' },
{ label: 'SCRAM-SHA-512', value: 'SCRAM-SHA-512' },
],
setValueOnRecipeOverride: (recipe: any, values: string[]) =>
setDottedFieldValuesOnRecipe(recipe, values, saslMechanismFieldPath),
};

const topicAllowFieldPath = 'source.config.topic_patterns.allow';
Expand Down

0 comments on commit 626196d

Please sign in to comment.