Skip to content

🪟 🎉 Connector Builder Landing Page #22122

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 23 commits into from
Feb 6, 2023

Conversation

lmossman
Copy link
Contributor

@lmossman lmossman commented Jan 31, 2023

What

Resolves #21490

Adds a landing page for the connector builder, which is shown if the user doesn't have any connector builder changes saved to browser local storage.

Screen Shot 2023-01-31 at 5 49 54 PM

To return to this page after making changes, click the Reset All button in the bottom-left corner of the Builder.

How

As described in the issue, this PR only adds tiles for importing a YAML and starting from scratch. Start from scratch just opens a blank connector builder UI as normal.

The Import a YAML button only allows users to select a single .yaml file from their computer to upload. A few outcomes can occur here:

  1. The uploaded file contains invalid YAML. In this case, we just show a Toast with the YAML validation error message and line number, which is auto-dismissed if they click the import button again.
  2. The uploaded file contains valid YAML, but it can't be converted to Builder UI. In this case, we open the YAML in the YAML editor view of the connector builder.
  3. The uploaded file contains valid YAML and can be converted to Builder UI. In this case, we open the Builder UI with the values filled in from the YAML.
    • In this case, the Connector Name is set to the titleCase version of the file name (minus the extension), e.g. poke_api.yaml would result in the connector name set to Poke Api

@octavia-squidington-iv octavia-squidington-iv added the area/frontend Related to the Airbyte webapp label Jan 31, 2023
@lmossman lmossman changed the title onnector builder landing page 🪟 🎉 Connector Builder Landing Page Jan 31, 2023
@lmossman lmossman requested a review from flash1293 January 31, 2023 01:11
@@ -62,7 +62,7 @@ export const ConfigMenu: React.FC<ConfigMenuProps> = ({ className, testInputJson
onClick={() => setIsOpen(true)}
disabled={
!jsonManifest.spec ||
Object.keys(jsonManifest.spec.connection_specification.properties || {}).length === 0
Object.keys(jsonManifest.spec.connection_specification?.properties || {}).length === 0
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Small bugfix - the page would crash if the spec did not contain connection_specification, and this change prevents that crash from occurring

@@ -99,7 +99,7 @@ export interface BuilderStream {

export const DEFAULT_BUILDER_FORM_VALUES: BuilderFormValues = {
global: {
connectorName: "",
connectorName: "Untitled",
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We want this eventually anyway, and this prevents us from showing a Required error on Reset All

@@ -60,7 +61,7 @@ export const convertToBuilderFormValues = async (
}
const resolvedManifest = resolveResult.manifest as ConnectorManifest;

const builderFormValues = DEFAULT_BUILDER_FORM_VALUES;
const builderFormValues = cloneDeep(DEFAULT_BUILDER_FORM_VALUES);
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixes a bug where the lines below this one were actually updating the DEFAULT_BUILDER_FORM_VALUES constant's fields, causing issues like Reset All not behaving properly

Comment on lines 115 to 131
<input
type="file"
accept=".yml,.yaml"
ref={fileInputRef}
style={{ display: "none" }}
onChange={(uploadEvent) => {
setImportYamlLoading(true);
const file = uploadEvent.target.files?.[0];
const reader = new FileReader();
reader.onload = (readerEvent) => {
handleYamlUpload(readerEvent.target?.result as string);
};
if (file) {
reader.readAsText(file);
}
}}
/>
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Open to suggestions here, but this seemed like the simplest and most standard way to handle file uploads without using a library. And I couldn't find any libraries that were well supported and lightweight

Copy link
Contributor

@flash1293 flash1293 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks mostly good besides some nits and one question about the code structure. Works like a charm!

@@ -47,6 +50,11 @@ const ConnectorBuilderPageInner: React.FC = React.memo(() => {
validationSchema={builderFormValidationSchema}
>
{(props) => {
if (showLandingPage) {
return (
<LandingPage hideLandingPage={hideLandingPage} switchToUI={switchToUI} switchToYaml={switchToYaml} />
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As this is part of the regular ConnectorBuilderPage, it initializes the form and test state services and tries to do a first fetch which fails with a 400.

I wonder whether we should split out the landing page into its own page with its own path - it seems easier to understand in the code (no "page in a page") and we can better control what side effects are triggered and avoid state leaking from one connector to another in case the user switches (also I think we won't get around that for having multiple builder projects anyway).

This is what I could imagine as interim state:

  • connector-builder/edit shows the actual connector builder UI (redirects to connector-builder on reset)
  • connector-builder shows the landing page (for now redirects automatically to connector-builder/edit if there is a non-default state in localstorage)

I think we can have a separate service for the landing page wiring up with local storage (and later on with the APIs to save and load connectors).

Doesn't absolutely need to happen on this PR as this is a meaningful increment, but it seems like a better step towards the targeted feature scope - your call how to go with this.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I like your suggestions here - I went ahead and added those changes now. I moved the local storage handling to its own ConnectorBuilderLocalStorage service/context, and moved the landing page into its own page / updated the routes and used redirects to go between.

I also found and fixed the issue with Reset All not always working properly - this was because it wasn't updating local storage properly, so I made sure it does that before navigating back to the landing page.

ref={fileInputRef}
style={{ display: "none" }}
onChange={(uploadEvent) => {
setImportYamlLoading(true);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: Why not moving all of this into the callback? Isolates a bit better the raw API access

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've moved this into the callback. The callback is now pretty long but I agree that keeping the logic together is probably better encapsulation

type="file"
accept=".yml,.yaml"
ref={fileInputRef}
style={{ display: "none" }}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: the prop hidden should work as well here and is slightly more "correct" (not a big deal though)

@@ -73,6 +73,7 @@ export const BuilderSidebar: React.FC<BuilderSidebarProps> = React.memo(({ class
onSubmit: () => {
setValues(DEFAULT_BUILDER_FORM_VALUES);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Doesn't need to be fixed on this PR, but it seems like this doesn't work reliably - after hidden "Reset all", then reloading the page I'm getting back to the previous state (there is probably another render-cycle of some kind putting it back). A separate page with a separate context for state management (see comment above) might help with this automatically.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See earlier comment, after the refactor and making this properly update local storage, this should now be fixed.

@@ -100,6 +95,11 @@ export const ConnectorBuilderFormStateProvider: React.FC<React.PropsWithChildren
const manifestRef = useRef(derivedJsonManifest);
manifestRef.current = derivedJsonManifest;

const [showLandingPage, setShowLandingPage] = useState(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: isEqual isn't super cheap, would be nice to wrap it into an initializer function

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Moved this into the landing page component since we now only need to do this once on page load. I put it in a useEffect which should only run a single time since I'm using refs for the local storage values

@octavia-squidington-iv octavia-squidington-iv added the area/documentation Improvements or additions to documentation label Feb 1, 2023
@lmossman lmossman requested a review from flash1293 February 1, 2023 02:06
Copy link
Contributor

@flash1293 flash1293 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks great, just left to nits but LGTM otherwise. No need for another round of review

buttonText="connectorBuilder.landingPage.importYaml.button"
buttonProps={{ isLoading: importYamlLoading }}
onClick={() => {
unregisterNotificationById(YAML_UPLOAD_ERROR_ID);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should always unregister this when navigating away from the page, otherwise the user could try to upload a yaml, give up and go with the "from scratch" option:
Screenshot 2023-02-02 at 15 35 27

Can be done via return value of an effect hook


useEffect(() => {
  return () => unregisterNotificationById(YAML_UPLOAD_ERROR_ID);
}, [unregisterNotificationById]);

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch! Fixed

}

if (fileName) {
convertedFormValues.global.connectorName = startCase(fileName.split(".")[0]);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This used to work really well until #21771 - now it will default to "Manifest" which is not super helpful. I think the next best thing is the url base, but no strong opinion on this.

My suggestion:

  • If the file name is not "manifest", use the current logic
  • If we can turn into form values, use the base url

} catch (e) {
setStoredEditorView("yaml");
setStoredManifest(json);
navigate(ConnectorBuilderRoutePaths.Edit);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Probably out of scope for this PR, but I think it would be very nice to have telemetry for the landing page as well. Wdyt?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I will put up a separate PR for that 👍

@lmossman lmossman enabled auto-merge (squash) February 2, 2023 23:33
@lmossman lmossman merged commit 0cef7b0 into master Feb 6, 2023
@lmossman lmossman deleted the lmossman/connector-builder-landing-page branch February 6, 2023 17:19
letiescanciano added a commit that referenced this pull request Feb 6, 2023
* master:
  Discover worker starts to use API to write schema result (#21875)
  🪟 🎉  Connector Builder Landing Page (#22122)
  Fix pnpm cache path (#22418)
  Add additional shorter setup guides (#22318)
  Source Amazon Ads: fix reports stream records primary keys (#21677)
  Connector acceptance test: Fix discovered catalog caching for different configs (#22301)
  🪟🐛 Make modal scrollable (#21973)
  only compute diff if the schema discovery actually succeeded (#22377)
  Source Klaviyo: fix schema (#22071)
  🪟 🔧 Switch to `pnpm` for package managing (#22053)
  Source Sentry: turn on default availability strategy (#22303)
  Source freshdesk: deduplicate table names (#22164)
letiescanciano added a commit that referenced this pull request Feb 6, 2023
* master: (86 commits)
  Discover worker starts to use API to write schema result (#21875)
  🪟 🎉  Connector Builder Landing Page (#22122)
  Fix pnpm cache path (#22418)
  Add additional shorter setup guides (#22318)
  Source Amazon Ads: fix reports stream records primary keys (#21677)
  Connector acceptance test: Fix discovered catalog caching for different configs (#22301)
  🪟🐛 Make modal scrollable (#21973)
  only compute diff if the schema discovery actually succeeded (#22377)
  Source Klaviyo: fix schema (#22071)
  🪟 🔧 Switch to `pnpm` for package managing (#22053)
  Source Sentry: turn on default availability strategy (#22303)
  Source freshdesk: deduplicate table names (#22164)
  Update connector-acceptance-tests-reference.md (#22370)
  Update the default security groups for the EC2 runner (#22347)
  Trace refresh schema operations (#22326)
  Remove manual docker upgrades from workflows (#22344)
  Update CODEOWNERS for connector acceptance tests to connector ops (#22341)
  🐛 source: airtable - handle singleSelect types (#22311)
  Source tiktok: chunk advertiser IDs (#22309)
  🪟 🧪 E2E Tests for auto-detect schema changes (#20682)
  ...
letiescanciano added a commit that referenced this pull request Feb 6, 2023
* master: (24 commits)
  Discover worker starts to use API to write schema result (#21875)
  🪟 🎉  Connector Builder Landing Page (#22122)
  Fix pnpm cache path (#22418)
  Add additional shorter setup guides (#22318)
  Source Amazon Ads: fix reports stream records primary keys (#21677)
  Connector acceptance test: Fix discovered catalog caching for different configs (#22301)
  🪟🐛 Make modal scrollable (#21973)
  only compute diff if the schema discovery actually succeeded (#22377)
  Source Klaviyo: fix schema (#22071)
  🪟 🔧 Switch to `pnpm` for package managing (#22053)
  Source Sentry: turn on default availability strategy (#22303)
  Source freshdesk: deduplicate table names (#22164)
  Update connector-acceptance-tests-reference.md (#22370)
  Update the default security groups for the EC2 runner (#22347)
  Trace refresh schema operations (#22326)
  Remove manual docker upgrades from workflows (#22344)
  Update CODEOWNERS for connector acceptance tests to connector ops (#22341)
  🐛 source: airtable - handle singleSelect types (#22311)
  Source tiktok: chunk advertiser IDs (#22309)
  🪟 🧪 E2E Tests for auto-detect schema changes (#20682)
  ...
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area/documentation Improvements or additions to documentation area/frontend Related to the Airbyte webapp
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Connector Builder Landing Page
3 participants