Skip to content
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
115 changes: 115 additions & 0 deletions recipes/gmail-auth.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
/// <cts-enable />
import { Default, NAME, recipe, UI } from "commontools";

type CFC<T, C extends string> = T;
type Secret<T> = CFC<T, "secret">;

// Auth data structure for Google OAuth tokens
export type Auth = {
token: Default<Secret<string>, "">;
tokenType: Default<string, "">;
scope: Default<string[], []>;
expiresIn: Default<number, 0>;
expiresAt: Default<number, 0>;
refreshToken: Default<Secret<string>, "">;
user: Default<{
email: string;
name: string;
picture: string;
}, { email: ""; name: ""; picture: "" }>;
};

interface Input {
auth: Default<Auth, {
token: "";
tokenType: "";
scope: [];
expiresIn: 0;
expiresAt: 0;
refreshToken: "";
user: { email: ""; name: ""; picture: "" };
}>;
}

interface Output {
auth: Auth;
}

export default recipe<Input, Output>(
"Gmail Auth",
({ auth }) => {
return {
[NAME]: "Gmail Auth",
[UI]: (
<div
style={{
display: "flex",
flexDirection: "column",
gap: "20px",
padding: "25px",
maxWidth: "600px",
}}
>
<h2 style={{ fontSize: "24px", fontWeight: "bold", margin: "0" }}>
Google OAuth Authentication
</h2>

<div
style={{
padding: "20px",
backgroundColor: "#f8f9fa",
borderRadius: "8px",
border: "1px solid #e0e0e0",
}}
>
<h3 style={{ fontSize: "16px", marginTop: "0" }}>
Status:{" "}
{auth?.user?.email ? "✅ Authenticated" : "⚠️ Not Authenticated"}
</h3>

{auth?.user?.email
? (
<div>
<p style={{ margin: "8px 0" }}>
<strong>Email:</strong> {auth.user.email}
</p>
<p style={{ margin: "8px 0" }}>
<strong>Name:</strong> {auth.user.name}
</p>
</div>
)
: (
<p style={{ color: "#666" }}>
Click the button below to authenticate with Google
</p>
)}
</div>

<common-google-oauth
$auth={auth}
scopes={[
"email",
"profile",
"https://www.googleapis.com/auth/gmail.readonly",
]}
/>

<div
style={{
padding: "15px",
backgroundColor: "#e3f2fd",
borderRadius: "8px",
fontSize: "14px",
}}
>
<strong>💡 Usage:</strong>{" "}
This charm provides Google OAuth authentication. Link its{" "}
<code>auth</code> output to any gmail importer charm's{" "}
<code>auth</code> input.
</div>
</div>
),
auth,
};
},
);
40 changes: 23 additions & 17 deletions recipes/gmail.tsx → recipes/gmail-importer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ type Secret<T> = CFC<T, "secret">;
type Confidential<T> = CFC<T, "confidential">;

// This is used by the various Google tokens created with tokenToAuthData
type Auth = {
export type Auth = {
token: Default<Secret<string>, "">;
tokenType: Default<string, "">;
scope: Default<string[], []>;
Expand Down Expand Up @@ -778,9 +778,6 @@ export async function process(

if (emails.length > 0) {
console.log(`Adding ${emails.length} new emails`);
// emails.forEach((email) => {
// email[ID] = email.id;
// });
allNewEmails.push(...emails);
}
} catch (error: any) {
Expand Down Expand Up @@ -819,7 +816,7 @@ export default recipe<{
}>;
auth: Auth;
}>(
"gmail",
"gmail-importer",
({ settings, auth }) => {
const emails = cell<Confidential<Email[]>>([]);

Expand All @@ -841,13 +838,29 @@ export default recipe<{
}}
>
<h2 style={{ fontSize: "20px", fontWeight: "bold" }}>
{auth?.user?.email}
Gmail Importer
</h2>
<h2 style={{ fontSize: "20px", fontWeight: "bold" }}>

<div
style={{
padding: "15px",
backgroundColor: auth?.user?.email ? "#d4edda" : "#f8d7da",
borderRadius: "8px",
border: `1px solid ${auth?.user?.email ? "#c3e6cb" : "#f5c6cb"}`,
}}
>
<strong>Auth Status:</strong> {auth?.user?.email
? `✅ Authenticated as ${auth.user.email}`
: "❌ Not authenticated - Please link to a gmail-auth charm"}
</div>

<h3 style={{ fontSize: "18px", fontWeight: "bold" }}>
Imported email count: {derive(emails, (emails) => emails.length)}
</h2>
</h3>

<h2>historyId: {settings.historyId}</h2>
<div style={{ fontSize: "14px", color: "#666" }}>
historyId: {settings.historyId || "none"}
</div>

<common-hstack gap="sm">
<common-vstack gap="sm">
Expand Down Expand Up @@ -884,14 +897,7 @@ export default recipe<{
</ct-button>
</common-vstack>
</common-hstack>
<common-google-oauth
$auth={auth}
scopes={[
"email",
"profile",
"https://www.googleapis.com/auth/gmail.readonly",
]}
/>

<div>
<table>
<thead>
Expand Down