Skip to content

Commit

Permalink
🪟🧹 Improve connector form types (airbytehq#20057)
Browse files Browse the repository at this point in the history
* improve some types
  • Loading branch information
Joe Reuter authored Dec 7, 2022
1 parent 08c0ba2 commit e12d366
Show file tree
Hide file tree
Showing 3 changed files with 74 additions and 22 deletions.
22 changes: 12 additions & 10 deletions airbyte-webapp/src/core/form/types.ts
Original file line number Diff line number Diff line change
@@ -1,31 +1,33 @@
import { JSONSchema7Type, JSONSchema7TypeName } from "json-schema";
import { JSONSchema7TypeName } from "json-schema";

import { AirbyteJSONSchema } from "core/jsonSchema";

interface FormItem {
/**
* When turning the JSON schema into `FormBlock`s,
* some often used props are copied over for easy access.
*/
type FormRelevantJSONSchema = Pick<
AirbyteJSONSchema,
"default" | "examples" | "description" | "pattern" | "order" | "const" | "title" | "airbyte_hidden" | "enum"
>;

interface FormItem extends FormRelevantJSONSchema {
fieldKey: string;
path: string;
isRequired: boolean;
order?: number;
title?: string;
description?: string;
airbyte_hidden?: boolean;
}

export interface FormBaseItem extends FormItem, AirbyteJSONSchema {
export interface FormBaseItem extends FormItem {
_type: "formItem";
type: JSONSchema7TypeName;
isSecret?: boolean;
multiline?: boolean;
default?: JSONSchema7Type;
}

export interface FormGroupItem extends FormItem {
_type: "formGroup";
jsonSchema: AirbyteJSONSchema;
properties: FormBlock[];
isLoading?: boolean;
examples?: JSONSchema7Type;
}

export interface FormConditionItem extends FormItem {
Expand Down
51 changes: 51 additions & 0 deletions airbyte-webapp/src/core/jsonSchema/schemaToUiWidget.test.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import { FormGroupItem } from "core/form/types";

import { jsonSchemaToUiWidget } from "./schemaToUiWidget";
import { AirbyteJSONSchemaDefinition } from "./types";

Expand Down Expand Up @@ -115,6 +117,55 @@ it("should reformat jsonSchema to internal widget representation", () => {
expect(builtSchema).toEqual(expected);
});

it("should turn single enum into const but keep multi value enum", () => {
const schema: AirbyteJSONSchemaDefinition = {
type: "object",
required: ["a", "b", "c"],
properties: {
a: { type: "string", enum: ["val1", "val2"] },
b: { type: "string", enum: ["val1"], default: "val1" },
c: { type: "string", const: "val3" },
},
};

const builtSchema = jsonSchemaToUiWidget(schema, "key");

const expectedProperties = [
{
_type: "formItem",
enum: ["val1", "val2"],
fieldKey: "a",
isRequired: true,
isSecret: false,
multiline: false,
path: "key.a",
type: "string",
},
{
_type: "formItem",
const: "val1",
default: "val1",
fieldKey: "b",
isRequired: true,
isSecret: false,
multiline: false,
path: "key.b",
type: "string",
},
{
_type: "formItem",
const: "val3",
fieldKey: "c",
isRequired: true,
isSecret: false,
multiline: false,
path: "key.c",
type: "string",
},
];
expect((builtSchema as FormGroupItem).properties).toEqual(expectedProperties);
});

it("should reformat jsonSchema to internal widget representation with parent schema", () => {
const schema: AirbyteJSONSchemaDefinition = {
type: "object",
Expand Down
23 changes: 11 additions & 12 deletions airbyte-webapp/src/core/jsonSchema/schemaToUiWidget.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import pick from "lodash/pick";

import { FormBlock } from "core/form/types";
import { isDefined } from "utils/common";

Expand Down Expand Up @@ -109,32 +111,29 @@ function isKeyRequired(key: string, parentSchema?: AirbyteJSONSchemaDefinition):
return isRequired;
}

const defaultFields: Array<keyof AirbyteJSONSchema> = [
const defaultFields = [
"default",
"examples",
"description",
"pattern",
"order",
"const",
"title",
"enum",

// airbyte specific fields
"airbyte_hidden",
];
] as const;

const pickDefaultFields = (schema: AirbyteJSONSchema): Partial<AirbyteJSONSchema> => {
const partialSchema: Partial<AirbyteJSONSchema> = {
...Object.fromEntries(Object.entries(schema).filter(([k]) => defaultFields.includes(k as keyof AirbyteJSONSchema))),
};
const pickDefaultFields = (schema: AirbyteJSONSchema) => {
const partialSchema = pick(schema, defaultFields);

if (typeof schema.items === "object" && !Array.isArray(schema.items) && schema.items.enum) {
partialSchema.enum = schema.items.enum;
} else if (schema.enum) {
if (schema.enum?.length === 1 && isDefined(schema.default)) {
partialSchema.const = schema.default;
} else {
partialSchema.enum = schema.enum;
}
} else if (schema.enum && schema.enum?.length === 1 && isDefined(schema.default)) {
partialSchema.const = schema.default;
// remove enum key as it has been "picked" already above
delete partialSchema.enum;
}

return partialSchema;
Expand Down

0 comments on commit e12d366

Please sign in to comment.