mirror of
https://github.com/MODSetter/SurfSense.git
synced 2026-04-25 16:56:22 +02:00
feat: enhance permission handling and user feedback for Gmail and Google Calendar tools
- Implemented logic to persist authentication expiration status for connectors when insufficient permissions are detected, improving error handling and user experience. - Updated messages to guide users to re-authenticate in connector settings for Gmail, Google Calendar, and Google Drive tools. - Added InsufficientPermissionsResult type and corresponding UI components to display permission-related messages consistently across Gmail and Google Calendar tools.
This commit is contained in:
parent
f4c0c8c945
commit
283b4194cc
18 changed files with 423 additions and 123 deletions
|
|
@ -3,8 +3,6 @@
|
|||
import { makeAssistantToolUI } from "@assistant-ui/react";
|
||||
import {
|
||||
CornerDownLeftIcon,
|
||||
FileEditIcon,
|
||||
MailIcon,
|
||||
Pen,
|
||||
UserIcon,
|
||||
UsersIcon,
|
||||
|
|
@ -66,10 +64,17 @@ interface AuthErrorResult {
|
|||
connector_type?: string;
|
||||
}
|
||||
|
||||
interface InsufficientPermissionsResult {
|
||||
status: "insufficient_permissions";
|
||||
connector_id: number;
|
||||
message: string;
|
||||
}
|
||||
|
||||
type CreateGmailDraftResult =
|
||||
| InterruptResult
|
||||
| SuccessResult
|
||||
| ErrorResult
|
||||
| InsufficientPermissionsResult
|
||||
| AuthErrorResult;
|
||||
|
||||
function isInterruptResult(result: unknown): result is InterruptResult {
|
||||
|
|
@ -99,6 +104,15 @@ function isAuthErrorResult(result: unknown): result is AuthErrorResult {
|
|||
);
|
||||
}
|
||||
|
||||
function isInsufficientPermissionsResult(result: unknown): result is InsufficientPermissionsResult {
|
||||
return (
|
||||
typeof result === "object" &&
|
||||
result !== null &&
|
||||
"status" in result &&
|
||||
(result as InsufficientPermissionsResult).status === "insufficient_permissions"
|
||||
);
|
||||
}
|
||||
|
||||
function ApprovalCard({
|
||||
args,
|
||||
interruptData,
|
||||
|
|
@ -168,7 +182,6 @@ function ApprovalCard({
|
|||
{/* Header */}
|
||||
<div className="flex items-start justify-between px-5 pt-5 pb-4 select-none">
|
||||
<div className="flex items-center gap-2">
|
||||
<FileEditIcon className="size-4 text-muted-foreground shrink-0" />
|
||||
<div>
|
||||
<p className="text-sm font-semibold text-foreground">
|
||||
{decided === "reject"
|
||||
|
|
@ -388,12 +401,27 @@ function AuthErrorCard({ result }: { result: AuthErrorResult }) {
|
|||
);
|
||||
}
|
||||
|
||||
function InsufficientPermissionsCard({ result }: { result: InsufficientPermissionsResult }) {
|
||||
return (
|
||||
<div className="my-4 max-w-lg overflow-hidden rounded-2xl border bg-muted/30 select-none">
|
||||
<div className="px-5 pt-5 pb-4">
|
||||
<p className="text-sm font-semibold text-destructive">
|
||||
Additional Gmail permissions required
|
||||
</p>
|
||||
</div>
|
||||
<div className="mx-5 h-px bg-border/50" />
|
||||
<div className="px-5 py-4">
|
||||
<p className="text-sm text-muted-foreground">{result.message}</p>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
function SuccessCard({ result }: { result: SuccessResult }) {
|
||||
return (
|
||||
<div className="my-4 max-w-lg overflow-hidden rounded-2xl border bg-muted/30 select-none">
|
||||
<div className="px-5 pt-5 pb-4">
|
||||
<div className="flex items-center gap-2">
|
||||
<MailIcon className="size-4 text-muted-foreground shrink-0" />
|
||||
<p className="text-sm font-semibold text-foreground">
|
||||
{result.message || "Gmail draft created successfully"}
|
||||
</p>
|
||||
|
|
@ -443,6 +471,8 @@ export const CreateGmailDraftToolUI = makeAssistantToolUI<
|
|||
}
|
||||
|
||||
if (isAuthErrorResult(result)) return <AuthErrorCard result={result} />;
|
||||
if (isInsufficientPermissionsResult(result))
|
||||
return <InsufficientPermissionsCard result={result} />;
|
||||
if (isErrorResult(result)) return <ErrorCard result={result} />;
|
||||
|
||||
return <SuccessCard result={result as SuccessResult} />;
|
||||
|
|
|
|||
|
|
@ -65,10 +65,17 @@ interface AuthErrorResult {
|
|||
connector_type?: string;
|
||||
}
|
||||
|
||||
interface InsufficientPermissionsResult {
|
||||
status: "insufficient_permissions";
|
||||
connector_id: number;
|
||||
message: string;
|
||||
}
|
||||
|
||||
type SendGmailEmailResult =
|
||||
| InterruptResult
|
||||
| SuccessResult
|
||||
| ErrorResult
|
||||
| InsufficientPermissionsResult
|
||||
| AuthErrorResult;
|
||||
|
||||
function isInterruptResult(result: unknown): result is InterruptResult {
|
||||
|
|
@ -98,6 +105,15 @@ function isAuthErrorResult(result: unknown): result is AuthErrorResult {
|
|||
);
|
||||
}
|
||||
|
||||
function isInsufficientPermissionsResult(result: unknown): result is InsufficientPermissionsResult {
|
||||
return (
|
||||
typeof result === "object" &&
|
||||
result !== null &&
|
||||
"status" in result &&
|
||||
(result as InsufficientPermissionsResult).status === "insufficient_permissions"
|
||||
);
|
||||
}
|
||||
|
||||
function ApprovalCard({
|
||||
args,
|
||||
interruptData,
|
||||
|
|
@ -387,6 +403,22 @@ function AuthErrorCard({ result }: { result: AuthErrorResult }) {
|
|||
);
|
||||
}
|
||||
|
||||
function InsufficientPermissionsCard({ result }: { result: InsufficientPermissionsResult }) {
|
||||
return (
|
||||
<div className="my-4 max-w-lg overflow-hidden rounded-2xl border bg-muted/30 select-none">
|
||||
<div className="px-5 pt-5 pb-4">
|
||||
<p className="text-sm font-semibold text-destructive">
|
||||
Additional Gmail permissions required
|
||||
</p>
|
||||
</div>
|
||||
<div className="mx-5 h-px bg-border/50" />
|
||||
<div className="px-5 py-4">
|
||||
<p className="text-sm text-muted-foreground">{result.message}</p>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
function SuccessCard({ result }: { result: SuccessResult }) {
|
||||
return (
|
||||
<div className="my-4 max-w-lg overflow-hidden rounded-2xl border bg-muted/30 select-none">
|
||||
|
|
@ -442,6 +474,8 @@ export const SendGmailEmailToolUI = makeAssistantToolUI<
|
|||
}
|
||||
|
||||
if (isAuthErrorResult(result)) return <AuthErrorCard result={result} />;
|
||||
if (isInsufficientPermissionsResult(result))
|
||||
return <InsufficientPermissionsCard result={result} />;
|
||||
if (isErrorResult(result)) return <ErrorCard result={result} />;
|
||||
|
||||
return <SuccessCard result={result as SuccessResult} />;
|
||||
|
|
|
|||
|
|
@ -72,11 +72,18 @@ interface AuthErrorResult {
|
|||
connector_type?: string;
|
||||
}
|
||||
|
||||
interface InsufficientPermissionsResult {
|
||||
status: "insufficient_permissions";
|
||||
connector_id: number;
|
||||
message: string;
|
||||
}
|
||||
|
||||
type TrashGmailEmailResult =
|
||||
| InterruptResult
|
||||
| SuccessResult
|
||||
| ErrorResult
|
||||
| NotFoundResult
|
||||
| InsufficientPermissionsResult
|
||||
| AuthErrorResult;
|
||||
|
||||
function isInterruptResult(result: unknown): result is InterruptResult {
|
||||
|
|
@ -115,6 +122,15 @@ function isAuthErrorResult(result: unknown): result is AuthErrorResult {
|
|||
);
|
||||
}
|
||||
|
||||
function isInsufficientPermissionsResult(result: unknown): result is InsufficientPermissionsResult {
|
||||
return (
|
||||
typeof result === "object" &&
|
||||
result !== null &&
|
||||
"status" in result &&
|
||||
(result as InsufficientPermissionsResult).status === "insufficient_permissions"
|
||||
);
|
||||
}
|
||||
|
||||
function formatDate(dateStr: string): string {
|
||||
return new Date(dateStr).toLocaleDateString(undefined, { dateStyle: "medium" });
|
||||
}
|
||||
|
|
@ -318,6 +334,22 @@ function AuthErrorCard({ result }: { result: AuthErrorResult }) {
|
|||
);
|
||||
}
|
||||
|
||||
function InsufficientPermissionsCard({ result }: { result: InsufficientPermissionsResult }) {
|
||||
return (
|
||||
<div className="my-4 max-w-lg overflow-hidden rounded-2xl border bg-muted/30 select-none">
|
||||
<div className="px-5 pt-5 pb-4">
|
||||
<p className="text-sm font-semibold text-destructive">
|
||||
Additional Gmail permissions required
|
||||
</p>
|
||||
</div>
|
||||
<div className="mx-5 h-px bg-border/50" />
|
||||
<div className="px-5 py-4">
|
||||
<p className="text-sm text-muted-foreground">{result.message}</p>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
function NotFoundCard({ result }: { result: NotFoundResult }) {
|
||||
return (
|
||||
<div className="my-4 max-w-lg overflow-hidden rounded-2xl border border-amber-500/50 bg-muted/30 select-none">
|
||||
|
|
@ -398,6 +430,8 @@ export const TrashGmailEmailToolUI = makeAssistantToolUI<
|
|||
}
|
||||
|
||||
if (isAuthErrorResult(result)) return <AuthErrorCard result={result} />;
|
||||
if (isInsufficientPermissionsResult(result))
|
||||
return <InsufficientPermissionsCard result={result} />;
|
||||
if (isNotFoundResult(result)) return <NotFoundCard result={result} />;
|
||||
if (isErrorResult(result)) return <ErrorCard result={result} />;
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue