Skip to content
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

Google Workspace: Add file path information #14888

Merged
merged 7 commits into from
Oct 21, 2024
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
4 changes: 4 additions & 0 deletions extensions/google-workspace/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
# Google Workspace Changelog

## [Add file path info to the file list] - 2024-10-21

- Adds the file path information to the list of accessories.

## [Log out the user if re-authentication fails] - 2024-07-11

- Automatically log out users if re-authentication fails, instead of displaying an error message.
Expand Down
13 changes: 12 additions & 1 deletion extensions/google-workspace/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,23 @@
"mathieudutour",
"marcmagn1",
"meganpearson",
"jbjanot"
"jbjanot",
"ridemountainpig"
],
"categories": [
"Productivity"
],
"license": "MIT",
"preferences": [
{
"name": "displayFilePath",
"type": "checkbox",
"required": false,
"default": false,
"description": "Display the file path in the search results. ⚠️ This may slow down your search results.",
"label": "Display file path in search results"
}
],
"commands": [
{
"name": "create-google-document",
Expand Down
66 changes: 62 additions & 4 deletions extensions/google-workspace/src/api/getFiles.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
import { getOAuthToken } from "./googleAuth";
import { getPreferenceValues } from "@raycast/api";
import fetch from "node-fetch";

export enum QueryTypes {
fileName = "fileName",
fullText = "fullText",
Expand All @@ -19,11 +23,18 @@ export type File = {
modifiedTime: string;
starred: boolean;
parents?: string[];
filePath?: string;
capabilities?: {
canTrash: boolean;
};
};

type FileData = {
id: string;
name: string;
parents: string[];
};

function getParams(queryType: QueryTypes, scope: ScopeTypes, queryText = "") {
const params = new URLSearchParams();

Expand Down Expand Up @@ -57,10 +68,57 @@ function getParams(queryType: QueryTypes, scope: ScopeTypes, queryText = "") {
return params.toString();
}

export function getFilesURL(queryType: QueryTypes, scope: ScopeTypes, queryText = "") {
return `https://www.googleapis.com/drive/v3/files?${getParams(queryType, scope, queryText)}`;
export async function getFiles(queryType: QueryTypes, scope: ScopeTypes, queryText = "") {
const url = `https://www.googleapis.com/drive/v3/files?${getParams(queryType, scope, queryText)}`;
const response = await fetch(url, {
headers: {
"Content-Type": "application/json",
Authorization: `Bearer ${getOAuthToken()}`,
},
});
const data = (await response.json()) as { files: File[] };

const { displayFilePath } = getPreferenceValues<Preferences>();
if (displayFilePath) {
await Promise.all(
data.files.map(async (file) => {
file.filePath = await getFilePath(file.id);
}),
);
}

return data;
}

async function getFilePath(fileId: string): Promise<string> {
const getFileParents = async (fileId: string) => {
const getFileUrl = `https://www.googleapis.com/drive/v3/files/${fileId}?fields=name,parents`;
const response = await fetch(getFileUrl, {
headers: {
"Content-Type": "application/json",
Authorization: `Bearer ${getOAuthToken()}`,
},
});

return await response.json();
};

const getParentPath = async (fileId: string): Promise<string> => {
const fileData = (await getFileParents(fileId)) as FileData;

if (!fileData.parents || fileData.parents.length === 0) {
return fileData.name;
}

const parentId = fileData.parents[0];
const parentPath = await getParentPath(parentId);

return `${parentPath}/${fileData.name}`;
};

return await getParentPath(fileId);
}

export function getStarredFilesURL() {
return getFilesURL(QueryTypes.starred, ScopeTypes.allDrives);
export function getStarredFiles() {
return getFiles(QueryTypes.starred, ScopeTypes.allDrives);
}
10 changes: 9 additions & 1 deletion extensions/google-workspace/src/components/FileListItem.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Action, ActionPanel, Color, Icon, List } from "@raycast/api";
import { Action, ActionPanel, Color, Icon, List, getPreferenceValues } from "@raycast/api";
import { format } from "date-fns";
import { File } from "../api/getFiles";
import { getFileIconLink, humanFileSize } from "../helpers/files";
Expand All @@ -9,6 +9,7 @@ type FileListItemProps = {
};

export default function FileListItem({ file, email }: FileListItemProps) {
const { displayFilePath } = getPreferenceValues();
const modifiedTime = new Date(file.modifiedTime);

const accessories: List.Item.Accessory[] = [
Expand All @@ -18,6 +19,13 @@ export default function FileListItem({ file, email }: FileListItemProps) {
},
];

if (displayFilePath && file.filePath) {
accessories.unshift({
icon: { source: Icon.Folder, tintColor: Color.SecondaryText },
tooltip: file.filePath,
});
}

if (file.starred) {
accessories.unshift({
icon: { source: Icon.Star, tintColor: Color.Yellow },
Expand Down
24 changes: 9 additions & 15 deletions extensions/google-workspace/src/search-google-drive-files.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
import { Action, ActionPanel, List, showToast, Toast } from "@raycast/api";
import { useFetch, useCachedState } from "@raycast/utils";
import { Action, ActionPanel, List } from "@raycast/api";
import { useCachedPromise, useCachedState } from "@raycast/utils";
import { useState } from "react";

import { QueryTypes, getFilesURL, File, ScopeTypes } from "./api/getFiles";
import { QueryTypes, getFiles, ScopeTypes } from "./api/getFiles";
import FileListItem from "./components/FileListItem";

import { withGoogleAuth } from "./components/withGoogleAuth";
import { getOAuthToken, getUserEmail } from "./api/googleAuth";
import { getUserEmail } from "./api/googleAuth";

function SearchGoogleDriveFiles() {
const [query, setQuery] = useState("");
Expand All @@ -15,17 +15,11 @@ function SearchGoogleDriveFiles() {

const email = getUserEmail();

const { data, isLoading } = useFetch<{ files: File[] }>(getFilesURL(queryType, scopeType, query), {
keepPreviousData: true,
headers: {
"Content-Type": "application/json",
Authorization: `Bearer ${getOAuthToken()}`,
},
onError(error) {
console.error(error);
showToast({ style: Toast.Style.Failure, title: "Failed to retrieve files" });
},
});
const { data, isLoading } = useCachedPromise(
async (queryType: QueryTypes, scopeType: ScopeTypes, query: string) => await getFiles(queryType, scopeType, query),
[queryType, scopeType, query],
{ failureToastOptions: { title: "Failed to retrieve files" } },
);

return (
<List
Expand Down
Original file line number Diff line number Diff line change
@@ -1,17 +1,18 @@
import { Icon, LaunchType, MenuBarExtra, launchCommand, open } from "@raycast/api";
import { useFetch } from "@raycast/utils";
import { File, getStarredFilesURL } from "./api/getFiles";
import { useCachedPromise } from "@raycast/utils";
import { getStarredFiles } from "./api/getFiles";
import { withGoogleAuth } from "./components/withGoogleAuth";
import { getFileIconLink } from "./helpers/files";
import { createDocFromUrl } from "./helpers/docs";
import { getOAuthToken } from "./api/googleAuth";

function StarredFiles() {
const { data, isLoading } = useFetch<{ files: File[] }>(getStarredFilesURL(), {
headers: {
"Content-Type": "application/json",
Authorization: `Bearer ${getOAuthToken()}`,
},
const { data, isLoading } = useCachedPromise(async () => {
try {
return await getStarredFiles();
} catch (error) {
console.error(error);
throw error;
}
});

const MAX_ITEMS = 40;
Expand Down
19 changes: 6 additions & 13 deletions extensions/google-workspace/src/starred-google-drive-files.tsx
Original file line number Diff line number Diff line change
@@ -1,23 +1,16 @@
import { Action, ActionPanel, List, showToast, Toast } from "@raycast/api";
import { useFetch } from "@raycast/utils";
import { Action, ActionPanel, List } from "@raycast/api";
import { useCachedPromise } from "@raycast/utils";

import { getStarredFilesURL, File } from "./api/getFiles";
import { getStarredFiles } from "./api/getFiles";
import FileListItem from "./components/FileListItem";
import { withGoogleAuth } from "./components/withGoogleAuth";
import { getOAuthToken, getUserEmail } from "./api/googleAuth";
import { getUserEmail } from "./api/googleAuth";

function StarredGoogleDriveFiles() {
const email = getUserEmail();

const { data, isLoading } = useFetch<{ files: File[] }>(getStarredFilesURL(), {
headers: {
"Content-Type": "application/json",
Authorization: `Bearer ${getOAuthToken()}`,
},
onError(error) {
console.error(error);
showToast({ style: Toast.Style.Failure, title: "Failed to retrieve starred files" });
},
const { data, isLoading } = useCachedPromise(() => getStarredFiles(), [], {
failureToastOptions: { title: "Failed to retrieve starred files" },
});

return (
Expand Down