Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
84 changes: 78 additions & 6 deletions demo/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -14,29 +14,101 @@
color: red;
margin-top: 1rem;
}
#app {
min-height: 200px;
.code {
font-family: monospace;
font-weight: 600;
}
</style>
</head>
<body>
<h1>Airbyte Widget Demo</h1>
<div id="app">
<h1>Airbyte Widget Demo</h1>
<p>
This is a demo application of the Airbyte Embedded widget. Make sure you have the following environment variables
set in <span class="code">/demo/.env</span> before running it:
<ul>
<li><span class="code">VITE_AB_ORGANIZATION_ID</span> - Your Airbyte organization ID</li>
<li><span class="code">VITE_AB_WORKSPACE_ID</span> - Your Airbyte workspace ID</li>
<li><span class="code">VITE_AB_CLIENT_ID</span> - Your Airbyte client_id</li>
<li><span class="code">VITE_AB_CLIENT_SECRET</span> - Your Airbyte client_secret</li>
</ul>
</p>
<p>This demo uses these environment variables to fetch and refresh a scoped access token for the widget. In a
production application, the <span class="code">client_id</span> and <span class="code">client_secret</span> should not be exposed to your web application.</p>
<div id="loading" class="loading">Loading widget...</div>
<div id="error" class="error"></div>
</div>
<script type="module">
import { EmbeddedWidget } from "@airbyte-embedded/airbyte-embedded-widget";
import { EmbeddedWidget } from "../src/EmbeddedWidget.ts";
Copy link
Collaborator

Choose a reason for hiding this comment

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

I don't have a strong opinion on how we import this... Evan had suggested changing this from directly importing the file to importing it using @airbyte-embedded originally... I am guessing so it's more production-like.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yeah I guess this is the tension between "the demo is for dev work" and "the demo is a demo". I find it annoying to have to remember to go change the import path every time I want to work on the EmbeddedWidget.

What if we just move the current demo app into a dev directory, and we keep a more polished demo in the demo directory? That would also allow us to keep all our dev niceties (client side token refreshing, import path, overrides) separate from the actual "demo" that operators might spin up.

Copy link
Collaborator

Choose a reason for hiding this comment

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

I have a pr introducing a version with a server that solves the token fetching also. Let's do that instead?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

sounds good, I split out the .updateToken() method into this PR since your PR does not seem to do that yet: #13


const loadingEl = document.getElementById("loading");
const errorEl = document.getElementById("error");

async function getAdminToken() {
const response = await fetch("https://local.airbyte.dev/api/public/v1/applications/token", {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
client_id: import.meta.env.VITE_AB_CLIENT_ID,
client_secret: import.meta.env.VITE_AB_CLIENT_SECRET,
"grant-type": "client_credentials",
}),
});
const { access_token } = await response.json();

return access_token;
}

async function getScopedToken() {
const access_token = await getAdminToken();
const response = await fetch("https://local.airbyte.dev/api/public/v1/embedded/widget?debug", {
method: "POST",
headers: {
"Content-Type": "application/json",
authorization: `Bearer ${access_token}`,
},
body: JSON.stringify({
workspaceId: import.meta.env.VITE_AB_WORKSPACE_ID,
organizationId: import.meta.env.VITE_AB_ORGANIZATION_ID,
allowedOrigin: window.location.origin,
}),
});
const token = await response.json();
return token;
}

async function initializeWidget() {
try {
new EmbeddedWidget({
token: import.meta.env.VITE_AB_EMBEDDED_TOKEN,
const overriddenToken = await getScopedTokenWithOverrides();
const widget = new EmbeddedWidget({
token: overriddenToken,
});

async function getScopedTokenWithOverrides() {
const { widgetUrl, token } = await getScopedToken();
const originalWidgetUrl = new URL(widgetUrl);
const newWidgetUrl = new URL(
`${import.meta.env.VITE_AB_WEBAPP_URL}${originalWidgetUrl.pathname.toString()}?${originalWidgetUrl.searchParams.toString()}`
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Need to update this to conditionally use VITE_AB_WEBAPP_URL only if it's set.

);
const newEncodedToken = btoa(
JSON.stringify({
widgetUrl: newWidgetUrl.toString(),
token,
})
);
return newEncodedToken;
}

async function refreshToken() {
const token = await getScopedTokenWithOverrides();
widget.updateToken(token);
console.log("Token refreshed:", token);
}

window.setInterval(getScopedTokenWithOverrides, 60_000);

// Hide loading state on success
loadingEl.style.display = "none";
} catch (error) {
Expand Down
3 changes: 1 addition & 2 deletions demo/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,7 @@
"name": "airbyte-embedded-widget-demo",
"private": true,
"scripts": {
"dev": "vite",
"dev:local": "node scripts/dev.js",
"start": "vite",
"test": "playwright test",
"test:ui": "playwright test --ui"
},
Expand Down
106 changes: 0 additions & 106 deletions demo/scripts/dev.js

This file was deleted.

3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -45,5 +45,6 @@
"onlyBuiltDependencies": [
"esbuild"
]
}
},
"packageManager": "[email protected]+sha512.1336b80b948efd7979218a33ba96d9e4d380e6578144f6319979977deec6e3fe2e0a444b864b3ce2b077dda8adc4d654fee32b9c31868f0acb92da0abcf8ea1c"
}
13 changes: 13 additions & 0 deletions src/EmbeddedWidget.ts
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@ export class EmbeddedWidget {
height: 800px;
background: white;
font-family: Inter, Helvetica, Arial, sans-serif;
font-size: 0;
}

.airbyte-widget-dialog::backdrop {
Expand Down Expand Up @@ -211,4 +212,16 @@ export class EmbeddedWidget {
public open(): void {
this.dialog.showModal();
}

public updateToken(token: string): void {
this.decodedToken = this.decodeToken(token);
const iframeOrigin = new URL(this.decodedToken.widgetUrl).origin;
const message = { scopedAuthToken: this.decodedToken.token };

try {
this.iframe.contentWindow?.postMessage(message, iframeOrigin);
} catch (error) {
console.debug("Error sending updated token to iframe:", error);
}
}
}