Skip to content

Restructuring for Multi-Platform Extensions (Phase 2) #11483

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 8 commits into from
Mar 20, 2025
Merged
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
57 changes: 30 additions & 27 deletions extension/platforms/chrome/background.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,3 @@
import {
AUTH0_CLIENT_DOMAIN,
AUTH0_CLIENT_ID,
DUST_API_AUDIENCE,
} from "@app/shared/lib/config";
import { extractPage } from "@app/shared/lib/extraction";
import type {
Auth0AuthorizeResponse,
AuthBackgroundMessage,
Expand All @@ -13,13 +7,22 @@ import type {
GetActiveTabBackgroundMessage,
GetActiveTabBackgroundResponse,
InputBarStatusMessage,
} from "@app/shared/lib/messages";
import type { PendingUpdate } from "@app/shared/lib/storage";
import { getStoredUser, savePendingUpdate } from "@app/shared/lib/storage";
} from "@app/platforms/chrome/messages";
import type { PendingUpdate } from "@app/platforms/chrome/services/platform";
import { ChromePlatformService } from "@app/platforms/chrome/services/platform";
import {
AUTH0_CLIENT_DOMAIN,
AUTH0_CLIENT_ID,
DUST_API_AUDIENCE,
} from "@app/shared/lib/config";
import { extractPage } from "@app/shared/lib/extraction";
import { generatePKCE } from "@app/shared/lib/utils";

const log = console.error;

// Initialize the platform service.
const platform = new ChromePlatformService();

const state: {
refreshingToken: boolean;
refreshRequests: ((
Expand All @@ -40,14 +43,15 @@ chrome.runtime.onUpdateAvailable.addListener(async (details) => {
version: details.version,
detectedAt: Date.now(),
};
await savePendingUpdate(pendingUpdate);

await platform.savePendingUpdate(pendingUpdate);
});

/**
* Listener to open/close the side panel when the user clicks on the extension icon.
*/
chrome.runtime.onInstalled.addListener(() => {
void chrome.storage.local.set({ extensionReady: false });
void platform.storage.set("extensionReady", false);
void chrome.sidePanel.setPanelBehavior({ openPanelOnActionClick: true });
chrome.contextMenus.create({
id: "add_tab_content",
Expand Down Expand Up @@ -77,7 +81,7 @@ const shouldDisableContextMenuForDomain = async (
return true;
}

const user = await getStoredUser();
const user = await platform.auth.getStoredUser();
if (!user || !user.selectedWorkspace) {
return false;
}
Expand Down Expand Up @@ -117,13 +121,11 @@ chrome.tabs.onActivated.addListener(async (activeInfo) => {
chrome.runtime.onConnect.addListener((port) => {
if (port.name === "sidepanel-connection") {
console.log("Sidepanel is there");
void chrome.storage.local.set({ extensionReady: true });
void platform.storage.set("extensionReady", true);
port.onDisconnect.addListener(async () => {
// This fires when sidepanel closes
console.log("Sidepanel was closed");
await chrome.storage.local.set({
extensionReady: false,
});
await platform.storage.set("extensionReady", false);
state.lastHandler = undefined;
});
}
Expand Down Expand Up @@ -183,17 +185,18 @@ chrome.contextMenus.onClicked.addListener(async (event, tab) => {
return;
}

chrome.storage.local.get(["extensionReady"], ({ extensionReady }) => {
if (!extensionReady && tab) {
// Store the handler for later use when the extension is ready.
state.lastHandler = handler;
void chrome.sidePanel.open({
windowId: tab.windowId,
});
} else {
void handler();
}
});
const isExtensionReady =
await platform.storage.get<boolean>("extensionReady");

if (!isExtensionReady && tab) {
// Store the handler for later use when the extension is ready.
state.lastHandler = handler;
void chrome.sidePanel.open({
windowId: tab.windowId,
});
} else {
void handler();
}
});

function capture(sendResponse: (x: CaptureResponse) => void) {
Expand Down
5 changes: 0 additions & 5 deletions extension/platforms/chrome/index.ts

This file was deleted.

110 changes: 91 additions & 19 deletions extension/platforms/chrome/main.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,24 +7,94 @@ import "../../ui/css/components.css";
// Local custom styles
import "../../ui/css/custom.css";

import { PortProvider } from "@app/platforms/chrome/contextes/PortContext";
import { PortProvider } from "@app/platforms/chrome/context/PortContext";
import { ChromePlatformService } from "@app/platforms/chrome/services/platform";
import {
PlatformProvider,
usePlatform,
} from "@app/shared/context/PlatformContext";
import { AuthProvider } from "@app/ui/components/auth/AuthProvider";
import { routes } from "@app/ui/pages/routes";
import { Notification } from "@dust-tt/sparkle";
import {
Button,
classNames,
DustLogo,
Notification,
Page,
} from "@dust-tt/sparkle";
import React from "react";
import ReactDOM from "react-dom/client";
import { createBrowserRouter, RouterProvider } from "react-router-dom";

const router = createBrowserRouter(routes);

const ChromeExtensionWrapper = () => {
const platform = usePlatform() as ChromePlatformService;
const [isLatestVersion, setIsLatestVersion] = React.useState(true);

const checkIsLatestVersion = async () => {
const pendingUpdate = await platform.getPendingUpdate();
if (!pendingUpdate) {
return null;
}
if (pendingUpdate.version > chrome.runtime.getManifest().version) {
setIsLatestVersion(false);
}
};

React.useEffect(() => {
void checkIsLatestVersion();

const unsub = platform.storage.onChanged((changes) => {
if (changes.pendingUpdate) {
void checkIsLatestVersion();
}
});

return () => unsub();
}, []);

if (!isLatestVersion) {
return (
<div
className={classNames(
"flex h-screen flex-col gap-2 p-4",
"dark:bg-slate-950 dark:text-slate-50"
)}
>
<div className="flex h-full w-full flex-col items-center justify-center gap-4 text-center">
<div className="flex flex-col items-center text-center space-y-4">
<DustLogo className="h-6 w-24" />
<Page.Header title="Update required" />
</div>
<Page.SectionHeader title="Panel closes after update. Click Dust icon in toolbar to return." />
<Button
label="Update now"
onClick={async () => {
chrome.runtime.reload();
}}
/>
</div>
</div>
);
}

return <RouterProvider router={router} />;
};

const platformService = new ChromePlatformService();

const App = () => {
return (
<PortProvider>
<AuthProvider>
<Notification.Area>
<RouterProvider router={router} />
</Notification.Area>
</AuthProvider>
</PortProvider>
<PlatformProvider platformService={platformService}>
<PortProvider>
<AuthProvider>
<Notification.Area>
<ChromeExtensionWrapper />
</Notification.Area>
</AuthProvider>
</PortProvider>
</PlatformProvider>
);
};
const rootElement = document.getElementById("root");
Expand Down Expand Up @@ -57,8 +127,8 @@ const removeSystemTheme = () => {
};

const initializeTheme = async () => {
const { theme } = await chrome.storage.local.get(["theme"]);
if (!theme || theme === "system") {
const theme = await platformService.getTheme();
if (theme === "system") {
setupSystemTheme();
} else {
removeSystemTheme();
Expand All @@ -67,14 +137,16 @@ const initializeTheme = async () => {
};
void initializeTheme();

chrome.storage.onChanged.addListener((changes) => {
if (changes.theme) {
const newTheme = changes.theme.newValue;
if (!newTheme || newTheme === "system") {
setupSystemTheme();
} else {
removeSystemTheme();
updateTheme(newTheme === "dark");
platformService.storage.onChanged((changes) => {
if ("theme" in changes) {
if (changes.theme) {
const newTheme = changes.theme;
if (!newTheme || newTheme === "system") {
setupSystemTheme();
} else {
removeSystemTheme();
updateTheme(newTheme === "dark");
}
}
}
});
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { saveTokens } from "@app/shared/lib/storage";
import type { AuthService } from "@app/shared/services/auth";

export type Auth0AuthorizeResponse = {
accessToken: string;
Expand Down Expand Up @@ -124,6 +124,7 @@ export const sendAuthMessage = (
};

export const sendRefreshTokenMessage = (
authService: AuthService,
refreshToken: string
): Promise<Auth0AuthorizeResponse> => {
return new Promise((resolve, reject) => {
Expand All @@ -147,7 +148,7 @@ export const sendRefreshTokenMessage = (
) {
return reject(new Error("Invalid response received."));
}
void saveTokens(response);
void authService.saveTokens(response);
return resolve(response);
}
);
Expand Down
2 changes: 1 addition & 1 deletion extension/platforms/chrome/page.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
* THE SOFTWARE.
*/

import type { CaptureFullPageMessage } from "@app/shared/lib/messages";
import type { CaptureFullPageMessage } from "@app/platforms/chrome/messages";

declare global {
interface Window {
Expand Down
Loading