diff --git a/docs/ai-agents/embedded/widget/README.md b/docs/ai-agents/embedded/widget/README.md index d696e4f1ff1..0ebf2af1a90 100644 --- a/docs/ai-agents/embedded/widget/README.md +++ b/docs/ai-agents/embedded/widget/README.md @@ -6,4 +6,4 @@ products: embedded The [Airbyte Embedded Widget](https://github.com/airbytehq/airbyte-embedded-widget) is a Javascript library you can use in your application to allow your users to sync their data integrations to your data lake. -You can follow the [step by step guide](./prerequisites-setup.md) to build your first application with the Widget. \ No newline at end of file +You can follow the [step by step guide](./tutorials/prerequisites-setup.md) to build your first application with the Widget. diff --git a/docs/ai-agents/embedded/widget/quickstart.md b/docs/ai-agents/embedded/widget/quickstart.md new file mode 100644 index 00000000000..9efc2408643 --- /dev/null +++ b/docs/ai-agents/embedded/widget/quickstart.md @@ -0,0 +1,145 @@ +--- +products: embedded +--- + +# Get started with the Airbyte Embedded Widget + +This guide walks you through implementing the Airbyte Embedded Widget into your existing web application. You'll learn how to set up connection templates, authenticate your application, and embed the widget to allow your users to sync their data. This should take approximately 30 minutes to complete. + +## Prerequisites + +Before getting started with this guide, make sure you have access to Airbyte Embedded. Reach out to teo@airbyte.io if you need access! + +## Prepare your organization + +:::info +Steps 1 and 2, connection template and source template creation, can also be managed via API. View the API docs at https://api.airbyte.ai/api/v1/docs for more information. +::: + +**1. Create your connection template:** visit https://app.airbyte.ai and visit the "Connection templates" page to create at least one connection template for your organization. Connection templates create one connection for each source that your end users create, so that their data ends up in your bucket or data lake. + +By default, the system applies _all_ connection templates to each new source your users set up. This means if you have two templates for two separate S3 buckets, every source created syncs to both. To manage this more precisely, you can use tags. + +For example, you might tag by product tier such as `free`, `standard`, or `enterprise`; by use case such as `sales`, `retail`, or `crm`; or by whatever else makes sense for your organization. These tags are used later on when the widget loads. + +**2. Add integrations:** next, visit the "Integrations" page to clone source templates into your organization or create custom ones. + +By default, the system shows all of your organization's integrations to all of your users. You can also manage these via tags. + +**3. Gather your credentials:** on the "Embed Code" page, you find the credentials you need to request a widget token. + +:::warning +Never store your `client_id` and `client_secret` in client-side code. +::: + +### Implement in your backend + +Your backend should implement the token fetching implementation for your widget. This requires two steps: first, fetch an app token, and then use that to fetch a widget token. + +**1. Request an app token:** an app token is a JSON Web Token (JWT) associated with you, the organization administrator, that you use to request a widget token, the token for your end user. + +```bash title="Request an application token" +curl -X POST https://api.airbyte.ai/account/applications/token \ + -H "Content-Type: application/json" \ + -d '{ + "client_id": "your_client_id", + "client_secret": "your_client_secret" + }' +``` + +**2. Add a way to request a widget token:** a widget token is a string that contains an encoded version of both a JWT and the URL the widget uses to open. To request a widget token, make a request like the following: + +```bash title="Request a widget token" +curl -X POST https://api.airbyte.ai/embedded/widget_token \ + -H "Content-Type: application/json" \ + -H "Authorization: Bearer YOUR_APPLICATION_TOKEN" \ + -d '{ + "workspace_name": "unique_user_identifier", + "allowed_origin": "your_url", + "selected_source_template_tags": ["pro"], + "selected_source_template_tags_mode": "all", + "selected_connection_template_tags": ["pro"], + "selected_connection_template_tags_mode": "all" + }' +``` + +Parameters: + +- `workspace_name`: a unique identifier for each of your end users, for example, user ID +- `allowed_origin`: the URL where you are embedding the widget, used for authentication +- `selected_source_template_tags`: optional - filter source templates by tags configured earlier +- `selected_source_template_tags_mode`: optional - whether to match "any" or "all" tags when listing +- `selected_connection_template_tags`: optional - filter connection templates by tags configured earlier +- `selected_connection_template_tags_mode`: optional - whether to match "any" or "all" tags when listing + +### Implement in your frontend + +**1. Add the widget package to your project:** the Airbyte Embedded widget is available as an npm package at https://www.npmjs.com/package/@airbyte-embedded/airbyte-embedded-widget. + +```bash npm2yarn +npm install @airbyte-embedded/airbyte-embedded-widget +``` + +**2. Add the widget to your page:** embed the widget. + +```ts title="EmbeddedSection.tsx" +import { AirbyteEmbeddedWidget } from "@airbyte-embedded/airbyte-embedded-widget"; + +export const EmbeddedSection: React.FC = () => { + const handleConnectData = async () => { + try { + // Fetch the widget token via your backend implementation + const { data } = await apiClient.getAirbyteWidgetToken({ + workspace_name: "unique_user_identifier", + allowed_origin: "your_url", + selected_source_template_tags: ["pro"], + selected_source_template_tags_mode: "all", + selected_connection_template_tags: ["pro"], + selected_connection_template_tags_mode: "all" + }); + + const widget = new AirbyteEmbeddedWidget({ + token: data.token, + }); + + widget.open(); + } catch (error) { + console.error("Error connecting data:", error); + } + }; + + return ; +}; +``` + +### Event callbacks + +You can pass an `onEvent` callback to the widget to receive messages when the user completes actions in the widget: + +```ts title="Success callback" +{ + type: "end_user_action_result"; + message: "source_created" | "source_updated"; + data: SourceRead; // The sanitized configuration info of the created source +} +``` + +Or, in case of error: + +```ts title="Error callback" +{ + type: "end_user_action_result"; + message: "source_create_error" | "source_update_error"; + error: Error; +} +``` + +You can use this to trigger actions within your own app. + +## Next steps + +As users begin setting up integrations in the widget, the following happens: + +1. Airbyte checks the user's configuration such as credentials prior to saving the source. +2. Once Airbyte creates the source, Airbyte Embedded kicks off a job to create the destinations and connections you configured. +3. Airbyte begins syncing data to your destinations according to the sync preferences you set up in your connection templates. diff --git a/docs/ai-agents/embedded/widget/develop-your-app.md b/docs/ai-agents/embedded/widget/tutorials/develop-your-app.md similarity index 98% rename from docs/ai-agents/embedded/widget/develop-your-app.md rename to docs/ai-agents/embedded/widget/tutorials/develop-your-app.md index 77ef91c8528..7cb43d21d76 100644 --- a/docs/ai-agents/embedded/widget/develop-your-app.md +++ b/docs/ai-agents/embedded/widget/tutorials/develop-your-app.md @@ -68,7 +68,7 @@ Your app will now be running on http://localhost:5173 The application is designed to run unchanged on Vercel, with the only configuration change required is setting environment keys via Settings > Environment Variables. It is recommended to use the Import .env button to avoid typo errors. Remember to change the SONAR_ALLOWED_ORIGIN to point to the vercel url. -![Vercel environment variables.](./assets/vercel-env.png) +![Vercel environment variables.](../assets/vercel-env.png) ## Widget Implementation diff --git a/docs/ai-agents/embedded/widget/prerequisites-setup.md b/docs/ai-agents/embedded/widget/tutorials/prerequisites-setup.md similarity index 100% rename from docs/ai-agents/embedded/widget/prerequisites-setup.md rename to docs/ai-agents/embedded/widget/tutorials/prerequisites-setup.md diff --git a/docs/ai-agents/embedded/widget/use-embedded.md b/docs/ai-agents/embedded/widget/tutorials/use-embedded.md similarity index 88% rename from docs/ai-agents/embedded/widget/use-embedded.md rename to docs/ai-agents/embedded/widget/tutorials/use-embedded.md index fb23f282f34..1ad08e4d0aa 100644 --- a/docs/ai-agents/embedded/widget/use-embedded.md +++ b/docs/ai-agents/embedded/widget/tutorials/use-embedded.md @@ -6,15 +6,15 @@ products: embedded With your app up and running, you will be prompted to enter your web password before continuing. After authentication, you will be presented with a screen to allow customers to onboard by adding their email address. -![Embedded Sample Web app home screen.](./assets/embedded-webapp-home.png) +![Embedded Sample Web app home screen.](../assets/embedded-webapp-home.png) Once a user record is created, the customer can tap Connect Data to configure which source they wish to connect. -![Embedded Sample Web app connect screen.](./assets/embedded-webapp-connect.png) +![Embedded Sample Web app connect screen.](../assets/embedded-webapp-connect.png) This will render the Airbyte Embedded widget. This widget displays a list of available connectors. -![Embedded Sample Web app widget.](./assets/embedded-webapp-widget.png) +![Embedded Sample Web app widget.](../assets/embedded-webapp-widget.png) Customers can select a source and input their configuration. Upon save, a customer workspace will be created via Airbyte Embedded with the customer’s source configuration and a data pipeline created to sync data to your AI destination store. In this instance, S3. diff --git a/docusaurus/docusaurus.config.js b/docusaurus/docusaurus.config.js index fe0acaa6e95..66b4948a58f 100644 --- a/docusaurus/docusaurus.config.js +++ b/docusaurus/docusaurus.config.js @@ -5,6 +5,7 @@ import "dotenv/config.js"; const { themes } = require("prism-react-renderer"); const lightCodeTheme = themes.github; const darkCodeTheme = themes.dracula; +const npm2yarn = require("@docusaurus/remark-plugin-npm2yarn"); const docsHeaderDecoration = require("./src/remark/docsHeaderDecoration"); const enterpriseDocsHeaderInformation = require("./src/remark/enterpriseDocsHeaderInformation"); @@ -81,7 +82,7 @@ const config = { attributes: { name: "segment-script", }, - innerHTML: ` + innerHTML: ` !function(){var i="analytics",analytics=window[i]=window[i]||[];if(!analytics.initialize)if(analytics.invoked)window.console&&console.error&&console.error("Segment snippet included twice.");else{analytics.invoked=!0;analytics.methods=["trackSubmit","trackClick","trackLink","trackForm","pageview","identify","reset","group","track","ready","alias","debug","page","screen","once","off","on","addSourceMiddleware","addIntegrationMiddleware","setAnonymousId","addDestinationMiddleware","register"];analytics.factory=function(e){return function(){if(window[i].initialized)return window[i][e].apply(window[i],arguments);var n=Array.prototype.slice.call(arguments);if(["track","screen","alias","group","page","identify"].indexOf(e)>-1){var c=document.querySelector("link[rel='canonical']");n.push({__t:"bpc",c:c&&c.getAttribute("href")||void 0,p:location.pathname,u:location.href,s:location.search,t:document.title,r:document.referrer})}n.unshift(e);analytics.push(n);return analytics}};for(var n=0;n=20.0'} + '@docusaurus/theme-classic@3.7.0': resolution: {integrity: sha512-MnLxG39WcvLCl4eUzHr0gNcpHQfWoGqzADCly54aqCofQX6UozOS9Th4RK3ARbM9m7zIRv3qbhggI53dQtx/hQ==} engines: {node: '>=18.0'} @@ -6098,9 +6105,6 @@ packages: mdast-util-from-markdown@1.3.1: resolution: {integrity: sha512-4xTO/M8c82qBcnQc1tgpNtubGUW/Y1tBQ1B0i5CtSoelOLKFYlElIr3bvgREYYO5iRqbMY1YuqZng0GVOI8Qww==} - mdast-util-from-markdown@2.0.0: - resolution: {integrity: sha512-n7MTOr/z+8NAX/wmhhDji8O3bRvPTV/U0oTCaZJkjhPSKTPhS3xufVhKGF8s1pJ7Ox4QgoIU7KHseh09S+9rTA==} - mdast-util-from-markdown@2.0.2: resolution: {integrity: sha512-uZhTV/8NBuw0WHkPTrCqDOl0zVe1BIng5ZtHoDk49ME1qqcjYmmLmOf0gELgcRMxN4w2iuIeVso5/6QymSrgmA==} @@ -6598,6 +6602,10 @@ packages: resolution: {integrity: sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==} engines: {node: '>=8'} + npm-to-yarn@3.0.1: + resolution: {integrity: sha512-tt6PvKu4WyzPwWUzy/hvPFqn+uwXO0K1ZHka8az3NnrhWJDmSqI8ncWq0fkL0k/lmmi5tAC11FXwXuh0rFbt1A==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + nprogress@0.2.0: resolution: {integrity: sha512-I19aIingLgR1fmhftnbWWO3dXc0hSxqHQHQb3H8m+K3TnEn/iSeTZZOyvKXWqQESMwuUVnatlCnZdLBZZt2VSA==} @@ -11814,6 +11822,16 @@ snapshots: '@types/react': 18.2.46 react: 18.2.0 + '@docusaurus/remark-plugin-npm2yarn@3.9.1': + dependencies: + mdast-util-mdx: 3.0.0 + npm-to-yarn: 3.0.1 + tslib: 2.6.2 + unified: 11.0.4 + unist-util-visit: 5.0.0 + transitivePeerDependencies: + - supports-color + '@docusaurus/theme-classic@3.7.0(@docusaurus/faster@3.8.1(@docusaurus/types@3.7.0(@swc/core@1.12.7(@swc/helpers@0.5.13))(react-dom@18.2.0(react@18.2.0))(react@18.2.0))(@swc/helpers@0.5.13))(@rspack/core@1.4.1(@swc/helpers@0.5.13))(@swc/core@1.12.7(@swc/helpers@0.5.13))(@types/react@18.2.46)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(typescript@5.3.3)': dependencies: '@docusaurus/core': 3.7.0(@docusaurus/faster@3.8.1(@docusaurus/types@3.7.0(@swc/core@1.12.7(@swc/helpers@0.5.13))(react-dom@18.2.0(react@18.2.0))(react@18.2.0))(@swc/helpers@0.5.13))(@mdx-js/react@3.0.0(@types/react@18.2.46)(react@18.2.0))(@rspack/core@1.4.1(@swc/helpers@0.5.13))(@swc/core@1.12.7(@swc/helpers@0.5.13))(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(typescript@5.3.3) @@ -16282,7 +16300,7 @@ snapshots: '@types/mdast': 4.0.3 '@types/unist': 3.0.2 devlop: 1.1.0 - mdast-util-from-markdown: 2.0.0 + mdast-util-from-markdown: 2.0.2 mdast-util-to-markdown: 2.1.0 parse-entities: 4.0.1 stringify-entities: 4.0.3 @@ -16321,23 +16339,6 @@ snapshots: transitivePeerDependencies: - supports-color - mdast-util-from-markdown@2.0.0: - dependencies: - '@types/mdast': 4.0.3 - '@types/unist': 3.0.2 - decode-named-character-reference: 1.0.2 - devlop: 1.1.0 - mdast-util-to-string: 4.0.0 - micromark: 4.0.0 - micromark-util-decode-numeric-character-reference: 2.0.1 - micromark-util-decode-string: 2.0.0 - micromark-util-normalize-identifier: 2.0.0 - micromark-util-symbol: 2.0.0 - micromark-util-types: 2.0.0 - unist-util-stringify-position: 4.0.0 - transitivePeerDependencies: - - supports-color - mdast-util-from-markdown@2.0.2: dependencies: '@types/mdast': 4.0.3 @@ -16360,7 +16361,7 @@ snapshots: '@types/mdast': 4.0.3 devlop: 1.1.0 escape-string-regexp: 5.0.0 - mdast-util-from-markdown: 2.0.0 + mdast-util-from-markdown: 2.0.2 mdast-util-to-markdown: 2.1.0 micromark-extension-frontmatter: 2.0.0 transitivePeerDependencies: @@ -16473,7 +16474,7 @@ snapshots: '@types/hast': 3.0.3 '@types/mdast': 4.0.3 devlop: 1.1.0 - mdast-util-from-markdown: 2.0.0 + mdast-util-from-markdown: 2.0.2 mdast-util-to-markdown: 2.1.0 transitivePeerDependencies: - supports-color @@ -16486,7 +16487,7 @@ snapshots: '@types/unist': 3.0.2 ccount: 2.0.1 devlop: 1.1.0 - mdast-util-from-markdown: 2.0.0 + mdast-util-from-markdown: 2.0.2 mdast-util-to-markdown: 2.1.0 parse-entities: 4.0.1 stringify-entities: 4.0.3 @@ -16498,7 +16499,7 @@ snapshots: mdast-util-mdx@3.0.0: dependencies: - mdast-util-from-markdown: 2.0.0 + mdast-util-from-markdown: 2.0.2 mdast-util-mdx-expression: 2.0.0 mdast-util-mdx-jsx: 3.0.0 mdast-util-mdxjs-esm: 2.0.1 @@ -16512,7 +16513,7 @@ snapshots: '@types/hast': 3.0.3 '@types/mdast': 4.0.3 devlop: 1.1.0 - mdast-util-from-markdown: 2.0.0 + mdast-util-from-markdown: 2.0.2 mdast-util-to-markdown: 2.1.0 transitivePeerDependencies: - supports-color @@ -17244,6 +17245,8 @@ snapshots: dependencies: path-key: 3.1.1 + npm-to-yarn@3.0.1: {} + nprogress@0.2.0: {} nth-check@2.0.1: @@ -18652,7 +18655,7 @@ snapshots: react-loadable-ssr-addon-v5-slorber@1.0.1(@docusaurus/react-loadable@6.0.0(react@18.2.0))(webpack@5.95.0(@swc/core@1.12.7(@swc/helpers@0.5.13))): dependencies: - '@babel/runtime': 7.23.7 + '@babel/runtime': 7.26.10 react-loadable: '@docusaurus/react-loadable@6.0.0(react@18.2.0)' webpack: 5.95.0(@swc/core@1.12.7(@swc/helpers@0.5.13)) @@ -18742,13 +18745,13 @@ snapshots: react-router-config@5.1.1(react-router@5.3.4(react@18.2.0))(react@18.2.0): dependencies: - '@babel/runtime': 7.23.7 + '@babel/runtime': 7.26.10 react: 18.2.0 react-router: 5.3.4(react@18.2.0) react-router-dom@5.3.4(react@18.2.0): dependencies: - '@babel/runtime': 7.23.7 + '@babel/runtime': 7.26.10 history: 4.10.1 loose-envify: 1.4.0 prop-types: 15.8.1 @@ -18773,7 +18776,7 @@ snapshots: react-router@5.3.4(react@18.2.0): dependencies: - '@babel/runtime': 7.23.7 + '@babel/runtime': 7.26.10 history: 4.10.1 hoist-non-react-statics: 3.3.2 loose-envify: 1.4.0 @@ -18996,7 +18999,7 @@ snapshots: remark-parse@11.0.0: dependencies: '@types/mdast': 4.0.3 - mdast-util-from-markdown: 2.0.0 + mdast-util-from-markdown: 2.0.2 micromark-util-types: 2.0.0 unified: 11.0.4 transitivePeerDependencies: diff --git a/docusaurus/sidebar-ai-agents.js b/docusaurus/sidebar-ai-agents.js index 523bd6632c2..a05ee938af1 100644 --- a/docusaurus/sidebar-ai-agents.js +++ b/docusaurus/sidebar-ai-agents.js @@ -17,10 +17,18 @@ export default { type: "category", label: "Widget", items: [ - "embedded/widget/prerequisites-setup", - "embedded/widget/develop-your-app", - "embedded/widget/use-embedded", + "embedded/widget/quickstart", + { + type: "category", + label: "Tutorials", + items: [ + "embedded/widget/tutorials/prerequisites-setup", + "embedded/widget/tutorials/develop-your-app", + "embedded/widget/tutorials/use-embedded", + ] + }, "embedded/widget/managing-embedded", + "embedded/widget/template-tags", ] }, {