-
Notifications
You must be signed in to change notification settings - Fork 4.5k
🪟 🎉 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
Conversation
@@ -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 |
There was a problem hiding this comment.
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", |
There was a problem hiding this comment.
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); |
There was a problem hiding this comment.
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
<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); | ||
} | ||
}} | ||
/> |
There was a problem hiding this comment.
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
There was a problem hiding this 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} /> |
There was a problem hiding this comment.
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 toconnector-builder
on reset)connector-builder
shows the landing page (for now redirects automatically toconnector-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.
There was a problem hiding this comment.
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); |
There was a problem hiding this comment.
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
There was a problem hiding this comment.
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" }} |
There was a problem hiding this comment.
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); |
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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( |
There was a problem hiding this comment.
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
There was a problem hiding this comment.
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
There was a problem hiding this 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); |
There was a problem hiding this comment.
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:
Can be done via return value of an effect hook
useEffect(() => {
return () => unregisterNotificationById(YAML_UPLOAD_ERROR_ID);
}, [unregisterNotificationById]);
There was a problem hiding this comment.
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]); |
There was a problem hiding this comment.
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); |
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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 👍
* 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)
* 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) ...
* 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) ...
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.
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:poke_api.yaml
would result in the connector name set toPoke Api