Skip to content
Open
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
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -39,4 +39,5 @@ keys.json
.tsbuildinfo

# Windows Zone.Identifier files
*:Zone.Identifier
*:Zone.Identifier
package-lock.json
Binary file added assets/drive.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
16 changes: 13 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,14 @@
"acorn": "^8.14.0",
"acorn-walk": "^8.3.4",
"d3-array": "^3.2.4",
"dotenv": "^16.5.0",
"escodegen": "^2.1.0",
"fs": "^0.0.1-security",
"plasmo": "0.89.4",
"react": "18.2.0",
"react-dom": "18.2.0",
"tailwindcss": "3.4.1"
"tailwindcss": "3.4.1",
"uuid": "^11.1.0"
},
"devDependencies": {
"@babel/preset-env": "^7.26.9",
Expand Down Expand Up @@ -52,12 +55,19 @@
"manifest": {
"permissions": [
"storage",
"cookies"
"cookies",
"identity"
],
"host_permissions": [
"https://*/*",
"http://*/*"
]
],
"oauth2": {
"client_id": "393216054869-8km195hvrk1og9lkeiucl27mbj6ht01t.apps.googleusercontent.com",
"scopes": [
"https://www.googleapis.com/auth/drive.readonly"
]
}
},
"type": "module"
}
14 changes: 7 additions & 7 deletions plasmo.config.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
export default {
import { defineConfig } from "@plasmohq/config"

export default defineConfig({
name: "Mantis connection",
version: "0.0.1",
manifest: {
permissions: [
"storage",
"cookies",
"webRequest"
]
permissions: ["storage", "cookies", "identity"],
}
}
})
83 changes: 83 additions & 0 deletions src/background.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ chrome.runtime.onMessage.addListener((request, sender, sendResponse) => {
}
});


const communications = {};

// This is used to register communication channels between the background script and the injected Mantis
Expand Down Expand Up @@ -78,4 +79,86 @@ chrome.runtime.onMessage.addListener((request, _sender, sendResponse) => {
return true;
}
}
});

// Retrieve access tokens
async function initiateSignIn(): Promise<string | undefined> {
try {
const result = await chrome.identity.getAuthToken({
interactive: true
});
if (result && result.token) {
console.log("Access retrieved");
return result.token; // Return the token string from the result object
} else {
console.log("Interactive sign-in failed or was cancelled.");
return undefined; // Return undefined if no token in the result
}
} catch (error: unknown) {
console.error("Error during interactive sign-in:", error);
console.error("Error details:", JSON.stringify(error, null, 2));
return undefined; // Return undefined if an error occurred
}
}

chrome.runtime.onMessage.addListener((request, sender, sendResponse) => {
if (request.action === "initiateOAuth") {
(async () => {
try {
const token = await initiateSignIn();
if (!token) {
sendResponse({ success: false, error: "Failed to retrieve access token." });
return;
}

const allFiles: DriveFile[] = [];
let nextPageToken: string | undefined = undefined;

do {
const url = new URL("https://www.googleapis.com/drive/v3/files");
url.searchParams.set("pageSize", "1000"); // max per API page
url.searchParams.set("fields", "nextPageToken, files(id, name)");
if (nextPageToken) {
url.searchParams.set("pageToken", nextPageToken);
}

const res = await fetch(url.toString(), {
headers: {
Authorization: `Bearer ${token}`,
},
});

if (!res.ok) {
const errorData = await res.json();
sendResponse({
success: false,
error: `Drive API error: ${errorData.error?.message || res.statusText}`,
});
return;
}

const data = await res.json();
allFiles.push(...data.files);

// Stop at 2000 files (maximum allowed by MantisAPI by default)

if (allFiles.length >= 2000) {
allFiles.length = 2000; // truncate if over
break;
}

nextPageToken = data.nextPageToken;
} while (nextPageToken);

console.log("✅ Fetched Drive Files (max 2000):", allFiles);
sendResponse({ success: true, token, driveFiles: allFiles });
} catch (err) {
sendResponse({
success: false,
error: err instanceof Error ? err.message : String(err) || "Failed to fetch Google Drive metadata",
});
}
})();
return true;
}
});
8 changes: 3 additions & 5 deletions src/connection_manager.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,12 @@ import { PubmedConnection } from "./connections/pubmed/connection";
import { GoogleDocsConnection } from "./connections/googleDocs/connection";
import { GoogleScholarConnection } from "./connections/googleScholar/connection";
import { WikipediaSegmentConnection } from "./connections/wikipediaSegment/connection";
import { GmailConnection } from "./connections/Gmail/connection";
import { GoogleDriveConnection } from "./connections/googleDrive/connection"
import { LinkedInConnection } from "./connections/Linkedin/connection";


export const CONNECTIONS = [GmailConnection, WikipediaSegmentConnection, WikipediaReferencesConnection, GoogleConnection, PubmedConnection, GoogleDocsConnection, GoogleScholarConnection,LinkedInConnection];
import { GmailConnection } from "./connections/Gmail/connection";
export const CONNECTIONS = [WikipediaSegmentConnection, WikipediaReferencesConnection, GoogleConnection, PubmedConnection, GoogleDocsConnection, GoogleScholarConnection, LinkedInConnection, GoogleDriveConnection, GmailConnection];

export const searchConnections = (url: string, ) => {
const connections = CONNECTIONS.filter(connection => connection.trigger(url));

return connections;
};
81 changes: 81 additions & 0 deletions src/connections/googleDrive/connection.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
import type { MantisConnection, injectUIType, onMessageType, registerListenersType, setProgressType, establishLogSocketType } from "../types";
import { GenerationProgress } from "../types";

import driveIcon from "data-base64:../../../assets/drive.png";
import { getSpacePortal, reqSpaceCreation} from "../../driver";

const trigger = (url: string) => {
return url.includes("drive.google.com");
}

const getDriveFiles = async () => {
try {
const response = await new Promise<{
success: boolean;
token?: string;
driveFiles?: any[];
error?: string;
}>((resolve, reject) => {
chrome.runtime.sendMessage({ action: "initiateOAuth" }, (response) => {
if (chrome.runtime.lastError) {
return reject(new Error("Runtime error: " + chrome.runtime.lastError.message));
}
resolve(response);
});
});

if (response.success && response.driveFiles) {
console.log("Token:", response.token);
console.log("Drive files:", response.driveFiles);
return response.driveFiles;
} else {
console.error("OAuth failed:", response.error);
}
} catch (err) {
console.error("Error during Drive file fetch:", err);
}
};

const createSpace = async (injectUI: injectUIType, setProgress: setProgressType, onMessage: onMessageType, registerListeners: registerListenersType, establishLogSocket: establishLogSocketType) => {
setProgress(GenerationProgress.GATHERING_DATA);
const fileMetadata = await getDriveFiles();
if (!fileMetadata) {
console.error("Failed to retrieve file metadata from Google Drive.");
return;
}

setProgress(GenerationProgress.CREATING_SPACE);

const spaceData = await reqSpaceCreation(fileMetadata, {
"name": "semantic",
}, establishLogSocket);

setProgress(GenerationProgress.INJECTING_UI);

const spaceId = spaceData.space_id;
const createdWidget = await injectUI(spaceId, onMessage, registerListeners);

setProgress(GenerationProgress.COMPLETED);

return { spaceId, createdWidget };
};

const injectUI = async (space_id: string, onMessage: onMessageType, registerListeners: registerListenersType) => {

const iframeScalerParent = await getSpacePortal (space_id, onMessage, registerListeners);

document.body.prepend (iframeScalerParent);

return iframeScalerParent;
}



export const GoogleDriveConnection: MantisConnection = {
name: "Google Drive",
description: "Builds spaces based on the content of an entire Google Drive",
icon: driveIcon,
trigger: trigger,
createSpace: createSpace,
injectUI: injectUI,
}
Loading