Skip to content

Commit

Permalink
🪟 🎉 Add /connector-builder page with embedded YAML editor (#17482)
Browse files Browse the repository at this point in the history
* [SPIKE] add Builder page with editor

* add YamlEditor component

* export colors from CSS

* move template into dedicated file

* fix initial load from local storage

* move download button into separate component

* fix stylelint

* remove console log

* add todo

* make monaco background transparent and apply gradient to parent div background

* clarify comment

* remove unnecessary 180deg

* lock the builder UI behind a feature

* use rgb instead of hex to fix stylelint

* use _colors.scss and disable hex length stylelint rule

* disable rule in file

* add darker gradient color to _colors.scss and use in gradient

* move /builder to /connector-builder

* restructure folders

* remove Feature for connector builder to simplify development process
  • Loading branch information
lmossman authored Oct 13, 2022
1 parent 3bcf15b commit fc59658
Show file tree
Hide file tree
Showing 10 changed files with 190 additions and 4 deletions.
26 changes: 26 additions & 0 deletions airbyte-webapp/src/components/YamlEditor/DownloadYamlButton.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import { useIntl } from "react-intl";

import { Button } from "components/ui/Button";

import { downloadFile } from "utils/file";

interface DownloadYamlButtonProps {
yaml: string;
className?: string;
}

export const DownloadYamlButton: React.FC<DownloadYamlButtonProps> = ({ yaml, className }) => {
const { formatMessage } = useIntl();

const downloadYaml = () => {
const file = new Blob([yaml], { type: "text/plain;charset=utf-8" });
// TODO: pull name from connector name input or generate from yaml contents
downloadFile(file, "connector_builder.yaml");
};

return (
<Button className={className} onClick={downloadYaml}>
{formatMessage({ id: "builder.downloadYaml" })}
</Button>
);
};
34 changes: 34 additions & 0 deletions airbyte-webapp/src/components/YamlEditor/YamlEditor.module.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
@use "scss/colors";

.container {
display: flex;
flex-flow: column;
height: 100%;
}

.control {
flex: 0 0 auto;
background-color: colors.$dark-blue;
display: flex;
padding: 10px;
}

.editorContainer {
flex: 1 1 0;
background-image: linear-gradient(colors.$dark-blue-900, colors.$dark-blue-1000);
}

.downloadButton {
margin-left: auto;
}

// Export colors to be used in monaco editor
:export {
// Monaco editor requires 6-character hex values for theme colors
/* stylelint-disable-next-line color-hex-length, color-no-hex */
tokenString: colors.$white;
tokenType: colors.$blue-300;
tokenNumber: colors.$orange-300;
tokenDelimiter: colors.$yellow-300;
tokenKeyword: colors.$green-300;
}
67 changes: 67 additions & 0 deletions airbyte-webapp/src/components/YamlEditor/YamlEditor.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
import Editor, { Monaco } from "@monaco-editor/react";
import { useState } from "react";
import { useDebounce, useLocalStorage } from "react-use";

import { DownloadYamlButton } from "./DownloadYamlButton";
import styles from "./YamlEditor.module.scss";
import { template } from "./YamlTemplate";

export const YamlEditor: React.FC = () => {
const [locallyStoredEditorValue, setLocallyStoredEditorValue] = useLocalStorage<string>(
"connectorBuilderEditorContent",
template
);
const [editorValue, setEditorValue] = useState(locallyStoredEditorValue ?? "");
useDebounce(() => setLocallyStoredEditorValue(editorValue), 500, [editorValue]);

const handleEditorChange = (value: string | undefined) => {
setEditorValue(value ?? "");
};

const setEditorTheme = (monaco: Monaco) => {
monaco.editor.defineTheme("airbyte", {
base: "vs-dark",
inherit: true,
rules: [
{ token: "string", foreground: styles.tokenString },
{ token: "type", foreground: styles.tokenType },
{ token: "number", foreground: styles.tokenNumber },
{ token: "delimiter", foreground: styles.tokenDelimiter },
{ token: "keyword", foreground: styles.tokenKeyword },
],
colors: {
"editor.background": "#00000000", // transparent, so that parent background is shown instead
},
});

monaco.editor.setTheme("airbyte");
};

return (
<div className={styles.container}>
<div className={styles.control}>
<DownloadYamlButton className={styles.downloadButton} yaml={editorValue} />
</div>
<div className={styles.editorContainer}>
<Editor
beforeMount={setEditorTheme}
value={editorValue}
language="yaml"
theme="airbyte"
onChange={handleEditorChange}
options={{
lineNumbersMinChars: 6,
matchBrackets: "always",
minimap: {
enabled: false,
},
padding: {
top: 20,
bottom: 20,
},
}}
/>
</div>
</div>
);
};
46 changes: 46 additions & 0 deletions airbyte-webapp/src/components/YamlEditor/YamlTemplate.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
// TODO: replace with API call to get starting contents
export const template = `version: "0.1.0"
definitions:
schema_loader:
type: JsonSchema
file_path: "./source/schemas/{{ options['name'] }}.json"
selector:
type: RecordSelector
extractor:
type: DpathExtractor
field_pointer: []
requester:
type: HttpRequester
name: "{{ options['name'] }}"
http_method: "GET"
authenticator:
type: BearerAuthenticator
api_token: "{{ config['api_key'] }}"
retriever:
type: SimpleRetriever
$options:
url_base: TODO "your_api_base_url"
name: "{{ options['name'] }}"
primary_key: "{{ options['primary_key'] }}"
record_selector:
$ref: "*ref(definitions.selector)"
paginator:
type: NoPagination
streams:
- type: DeclarativeStream
$options:
name: "customers"
primary_key: "id"
schema_loader:
$ref: "*ref(definitions.schema_loader)"
retriever:
$ref: "*ref(definitions.retriever)"
requester:
$ref: "*ref(definitions.requester)"
path: TODO "your_endpoint_path"
check:
type: CheckStream
stream_names: ["customers"]
`;
1 change: 1 addition & 0 deletions airbyte-webapp/src/components/YamlEditor/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from "./YamlEditor";
4 changes: 3 additions & 1 deletion airbyte-webapp/src/locales/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -564,5 +564,7 @@
"airbyte.datatype.untyped": "Untyped",
"airbyte.datatype.union": "Union",
"airbyte.datatype.unknown": "Unknown",
"airbyte.datatype.boolean": "Boolean"
"airbyte.datatype.boolean": "Boolean",

"builder.downloadYaml": "Download YAML"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import { YamlEditor } from "components/YamlEditor";

export const ConnectorBuilderPage: React.FC = () => {
return <YamlEditor />;
};
2 changes: 2 additions & 0 deletions airbyte-webapp/src/pages/routePaths.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,4 +14,6 @@ export enum RoutePaths {
ConnectionNew = "new-connection",
SourceNew = "new-source",
DestinationNew = "new-destination",

ConnectorBuilder = "connector-builder",
}
2 changes: 2 additions & 0 deletions airbyte-webapp/src/pages/routes.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import MainView from "views/layout/MainView";

import { WorkspaceRead } from "../core/request/AirbyteClient";
import ConnectionPage from "./ConnectionPage";
import { ConnectorBuilderPage } from "./connector-builder/ConnectorBuilderPage";
import DestinationPage from "./DestinationPage";
import OnboardingPage from "./OnboardingPage";
import PreferencesPage from "./PreferencesPage";
Expand Down Expand Up @@ -43,6 +44,7 @@ const MainViewRoutes: React.FC<{ workspace: WorkspaceRead }> = ({ workspace }) =
<Route path={`${RoutePaths.Source}/*`} element={<SourcesPage />} />
<Route path={`${RoutePaths.Connections}/*`} element={<ConnectionPage />} />
<Route path={`${RoutePaths.Settings}/*`} element={<SettingsPage />} />
<Route path={`${RoutePaths.ConnectorBuilder}/*`} element={<ConnectorBuilderPage />} />
{workspace.displaySetupWizard ? (
<Route path={`${RoutePaths.Onboarding}/*`} element={<OnboardingPage />} />
) : null}
Expand Down
7 changes: 4 additions & 3 deletions airbyte-webapp/src/scss/_colors.scss
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
/* stylelint-disable color-no-hex */
/* stylelint-disable color-no-hex, color-hex-length */
$blue-50: #eae9ff;
$blue-100: #cbc8ff;
$blue-200: #a6a4ff;
Expand All @@ -22,6 +22,7 @@ $dark-blue-600: #353b7b;
$dark-blue-700: #2d3270;
$dark-blue-800: #262963;
$dark-blue-900: #1a194d;
$dark-blue-1000: #0a0a23;
$dark-blue: $dark-blue-900;

$grey-30: #fcfcfd;
Expand Down Expand Up @@ -77,8 +78,8 @@ $beige-50: #fef9f4;
$beige-100: #ffebd7;
$beige: $beige-50;

$black: #000;
$white: #fff;
$black: #000000;
$white: #ffffff;

$yellow-50: #fdf8e1;
$yellow-100: #fbecb3;
Expand Down

0 comments on commit fc59658

Please sign in to comment.