mirror of
https://github.com/simstudioai/sim.git
synced 2026-09-24 15:45:35 +08:00
feat(oauth): modified google drive/gmail icons, added credentials selector sub-block to gmail tool
This commit is contained in:
@@ -7,6 +7,7 @@ import { DateInput } from './components/date-input'
|
||||
import { Dropdown } from './components/dropdown'
|
||||
import { EvalInput } from './components/eval-input'
|
||||
import { LongInput } from './components/long-input'
|
||||
import { OAuthInput } from './components/oauth-input'
|
||||
import { ShortInput } from './components/short-input'
|
||||
import { SliderInput } from './components/slider-input'
|
||||
import { Switch } from './components/switch'
|
||||
@@ -107,6 +108,27 @@ export function SubBlock({ blockId, config, isConnecting }: SubBlockProps) {
|
||||
return (
|
||||
<TimeInput blockId={blockId} subBlockId={config.id} placeholder={config.placeholder} />
|
||||
)
|
||||
case 'oauth-input':
|
||||
return (
|
||||
<OAuthInput
|
||||
value={typeof config.value === 'string' ? config.value : ''}
|
||||
onChange={(value) => {
|
||||
// Use the workflow store to update the value
|
||||
const event = new CustomEvent('update-subblock-value', {
|
||||
detail: {
|
||||
blockId,
|
||||
subBlockId: config.id,
|
||||
value,
|
||||
},
|
||||
})
|
||||
window.dispatchEvent(event)
|
||||
}}
|
||||
provider={config.provider as any}
|
||||
requiredScopes={config.requiredScopes || []}
|
||||
label={config.placeholder}
|
||||
serviceId={config.serviceId}
|
||||
/>
|
||||
)
|
||||
default:
|
||||
return null
|
||||
}
|
||||
|
||||
@@ -18,6 +18,7 @@ import { useNotificationStore } from '@/stores/notifications/store'
|
||||
import { useGeneralStore } from '@/stores/settings/general/store'
|
||||
import { getSyncManagers, initializeSyncManagers, isSyncInitialized } from '@/stores/sync-registry'
|
||||
import { useWorkflowRegistry } from '@/stores/workflows/registry/store'
|
||||
import { useSubBlockStore } from '@/stores/workflows/subblock/store'
|
||||
import { useWorkflowStore } from '@/stores/workflows/workflow/store'
|
||||
import { NotificationList } from '@/app/w/[id]/components/notifications/notifications'
|
||||
import { getBlock } from '../../../blocks'
|
||||
@@ -51,6 +52,7 @@ function WorkflowContent() {
|
||||
const { workflows, setActiveWorkflow, createWorkflow } = useWorkflowRegistry()
|
||||
const { blocks, edges, loops, addBlock, updateBlockPosition, addEdge, removeEdge } =
|
||||
useWorkflowStore()
|
||||
const { setValue: setSubBlockValue } = useSubBlockStore()
|
||||
|
||||
// Add OAuth error handling
|
||||
const { modalState, handleOAuthError, closeModal } = useOAuthErrorHandler()
|
||||
@@ -312,6 +314,25 @@ function WorkflowContent() {
|
||||
return () => window.removeEventListener('keydown', handleKeyDown)
|
||||
}, [selectedEdgeId, removeEdge])
|
||||
|
||||
// Handle sub-block value updates from custom events
|
||||
useEffect(() => {
|
||||
const handleSubBlockValueUpdate = (event: CustomEvent) => {
|
||||
const { blockId, subBlockId, value } = event.detail
|
||||
if (blockId && subBlockId) {
|
||||
setSubBlockValue(blockId, subBlockId, value)
|
||||
}
|
||||
}
|
||||
|
||||
window.addEventListener('update-subblock-value', handleSubBlockValueUpdate as EventListener)
|
||||
|
||||
return () => {
|
||||
window.removeEventListener(
|
||||
'update-subblock-value',
|
||||
handleSubBlockValueUpdate as EventListener
|
||||
)
|
||||
}
|
||||
}, [setSubBlockValue])
|
||||
|
||||
if (!isInitialized) return null
|
||||
|
||||
return (
|
||||
|
||||
+15
-11
@@ -3,7 +3,7 @@
|
||||
import { useEffect, useState } from 'react'
|
||||
import { useRouter, useSearchParams } from 'next/navigation'
|
||||
import { Check, ExternalLink, RefreshCw } from 'lucide-react'
|
||||
import { GithubIcon, GoogleIcon, xIcon as XIcon } from '@/components/icons'
|
||||
import { GithubIcon, GoogleDriveIcon, xIcon as XIcon } from '@/components/icons'
|
||||
import { GmailIcon } from '@/components/icons'
|
||||
import { Button } from '@/components/ui/button'
|
||||
import { Card } from '@/components/ui/card'
|
||||
@@ -61,7 +61,7 @@ export function Credentials({ onOpenChange }: CredentialsProps) {
|
||||
description: 'Streamline file organization and document workflows.',
|
||||
provider: 'google',
|
||||
providerId: 'google-drive',
|
||||
icon: <GoogleIcon className="h-5 w-5" />,
|
||||
icon: <GoogleDriveIcon className="h-5 w-5" />,
|
||||
isConnected: false,
|
||||
scopes: [],
|
||||
},
|
||||
@@ -276,6 +276,19 @@ export function Credentials({ onOpenChange }: CredentialsProps) {
|
||||
</p>
|
||||
</div>
|
||||
|
||||
{pendingService && (
|
||||
<div className="mb-6 p-4 bg-primary/10 border border-primary rounded-md text-sm flex items-start gap-2">
|
||||
<div className="min-w-4 mt-0.5">
|
||||
<ExternalLink className="h-4 w-4 text-primary" />
|
||||
</div>
|
||||
<p>
|
||||
<span className="font-medium text-primary">Action Required:</span> Please connect your
|
||||
account to enable the requested features. The required service will be highlighted
|
||||
below.
|
||||
</p>
|
||||
</div>
|
||||
)}
|
||||
|
||||
<div className="space-y-6">
|
||||
{isLoading ? (
|
||||
<>
|
||||
@@ -326,15 +339,6 @@ export function Credentials({ onOpenChange }: CredentialsProps) {
|
||||
))
|
||||
)}
|
||||
</div>
|
||||
|
||||
{pendingService && (
|
||||
<div className="mt-4 p-3 bg-muted rounded-md text-sm">
|
||||
<p>
|
||||
<span className="font-medium">Note:</span> Connect this service to use tools that
|
||||
require this authentication.
|
||||
</p>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
+20
-8
@@ -9,7 +9,7 @@ export const GmailBlock: BlockConfig<GmailToolResponse> = {
|
||||
longDescription:
|
||||
'Integrate Gmail functionality to send, read, and search email messages within your workflow. Automate email communications and process email content using OAuth authentication.',
|
||||
category: 'tools',
|
||||
bgColor: '#F14537',
|
||||
bgColor: '#E0E0E0',
|
||||
icon: GmailIcon,
|
||||
subBlocks: [
|
||||
// Operation selector
|
||||
@@ -24,14 +24,19 @@ export const GmailBlock: BlockConfig<GmailToolResponse> = {
|
||||
{ label: 'Search Emails', id: 'search_gmail' },
|
||||
],
|
||||
},
|
||||
// OAuth Token
|
||||
// Gmail Credentials
|
||||
{
|
||||
id: 'accessToken',
|
||||
title: 'Access Token',
|
||||
type: 'short-input',
|
||||
id: 'credential',
|
||||
title: 'Gmail Account',
|
||||
type: 'oauth-input',
|
||||
layout: 'full',
|
||||
placeholder: 'Enter Gmail OAuth token',
|
||||
password: true,
|
||||
provider: 'google',
|
||||
serviceId: 'gmail',
|
||||
requiredScopes: [
|
||||
'https://www.googleapis.com/auth/gmail.send',
|
||||
'https://www.googleapis.com/auth/gmail.readonly',
|
||||
],
|
||||
placeholder: 'Select Gmail account',
|
||||
},
|
||||
// Send Email Fields
|
||||
{
|
||||
@@ -100,11 +105,18 @@ export const GmailBlock: BlockConfig<GmailToolResponse> = {
|
||||
throw new Error(`Invalid Gmail operation: ${params.operation}`)
|
||||
}
|
||||
},
|
||||
params: (params) => {
|
||||
// Add the credential ID to the params
|
||||
return {
|
||||
...params,
|
||||
_credentialId: params.credential,
|
||||
}
|
||||
},
|
||||
},
|
||||
},
|
||||
inputs: {
|
||||
operation: { type: 'string', required: true },
|
||||
accessToken: { type: 'string', required: true },
|
||||
credential: { type: 'string', required: true },
|
||||
// Send operation inputs
|
||||
to: { type: 'string', required: false },
|
||||
subject: { type: 'string', required: false },
|
||||
|
||||
@@ -25,6 +25,7 @@ export type SubBlockType =
|
||||
| 'eval-input' // Evaluation input
|
||||
| 'date-input' // Date input
|
||||
| 'time-input' // Time input
|
||||
| 'oauth-input' // OAuth credential selector
|
||||
|
||||
// Component width setting
|
||||
export type SubBlockLayout = 'full' | 'half'
|
||||
@@ -95,6 +96,10 @@ export interface SubBlockConfig {
|
||||
value: string | number | boolean
|
||||
}
|
||||
}
|
||||
// OAuth specific properties
|
||||
provider?: string
|
||||
serviceId?: string
|
||||
requiredScopes?: string[]
|
||||
}
|
||||
|
||||
// Main block definition
|
||||
@@ -111,6 +116,7 @@ export interface BlockConfig<T extends ToolResponse = ToolResponse> {
|
||||
access: string[]
|
||||
config?: {
|
||||
tool: (params: Record<string, any>) => string
|
||||
params?: (params: Record<string, any>) => Record<string, any>
|
||||
}
|
||||
}
|
||||
inputs: Record<string, ParamConfig>
|
||||
|
||||
+49
-6
@@ -1169,25 +1169,68 @@ export const NotionIcon = (props: SVGProps<SVGSVGElement>) => {
|
||||
|
||||
export const GmailIcon = (props: SVGProps<SVGSVGElement>) => {
|
||||
return (
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 48 48" width="1em" height="1em" {...props}>
|
||||
<path fill="currentColor" d="M45,16.2l-5,2.75l-5,4.75L35,40h7c1.657,0,3-1.343,3-3V16.2z" />
|
||||
<path fill="currentColor" d="M3,16.2l3.614,1.71L13,23.7V40H6c-1.657,0-3-1.343-3-3V16.2z" />
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
viewBox="0 0 48 48"
|
||||
width="96px"
|
||||
height="96px"
|
||||
{...props}
|
||||
>
|
||||
<path fill="#4caf50" d="M45,16.2l-5,2.75l-5,4.75L35,40h7c1.657,0,3-1.343,3-3V16.2z" />
|
||||
<path fill="#1e88e5" d="M3,16.2l3.614,1.71L13,23.7V40H6c-1.657,0-3-1.343-3-3V16.2z" />
|
||||
<polygon
|
||||
fill="currentColor"
|
||||
fill="#e53935"
|
||||
points="35,11.2 24,19.45 13,11.2 12,17 13,23.7 24,31.95 35,23.7 36,17"
|
||||
/>
|
||||
<path
|
||||
fill="currentColor"
|
||||
fill="#c62828"
|
||||
d="M3,12.298V16.2l10,7.5V11.2L9.876,8.859C9.132,8.301,8.228,8,7.298,8h0C4.924,8,3,9.924,3,12.298z"
|
||||
/>
|
||||
<path
|
||||
fill="currentColor"
|
||||
fill="#fbc02d"
|
||||
d="M45,12.298V16.2l-10,7.5V11.2l3.124-2.341C38.868,8.301,39.772,8,40.702,8h0 C43.076,8,45,9.924,45,12.298z"
|
||||
/>
|
||||
</svg>
|
||||
)
|
||||
}
|
||||
|
||||
export const GoogleDriveIcon = (props: SVGProps<SVGSVGElement>) => {
|
||||
return (
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
viewBox="0 0 87.3 78"
|
||||
width="1em"
|
||||
height="1em"
|
||||
{...props}
|
||||
>
|
||||
<path
|
||||
d="m6.6 66.85 3.85 6.65c.8 1.4 1.95 2.5 3.3 3.3l13.75-23.8h-27.5c0 1.55.4 3.1 1.2 4.5z"
|
||||
fill="#0066da"
|
||||
/>
|
||||
<path
|
||||
d="m43.65 25-13.75-23.8c-1.35.8-2.5 1.9-3.3 3.3l-25.4 44a9.06 9.06 0 0 0 -1.2 4.5h27.5z"
|
||||
fill="#00ac47"
|
||||
/>
|
||||
<path
|
||||
d="m73.55 76.8c1.35-.8 2.5-1.9 3.3-3.3l1.6-2.75 7.65-13.25c.8-1.4 1.2-2.95 1.2-4.5h-27.502l5.852 11.5z"
|
||||
fill="#ea4335"
|
||||
/>
|
||||
<path
|
||||
d="m43.65 25 13.75-23.8c-1.35-.8-2.9-1.2-4.5-1.2h-18.5c-1.6 0-3.15.45-4.5 1.2z"
|
||||
fill="#00832d"
|
||||
/>
|
||||
<path
|
||||
d="m59.8 53h-32.3l-13.75 23.8c1.35.8 2.9 1.2 4.5 1.2h50.8c1.6 0 3.15-.45 4.5-1.2z"
|
||||
fill="#2684fc"
|
||||
/>
|
||||
<path
|
||||
d="m73.4 26.5-12.7-22c-.8-1.4-1.95-2.5-3.3-3.3l-13.75 23.8 16.15 28h27.45c0-1.55-.4-3.1-1.2-4.5z"
|
||||
fill="#ffba00"
|
||||
/>
|
||||
</svg>
|
||||
)
|
||||
}
|
||||
|
||||
export const xAIIcon = (props: SVGProps<SVGSVGElement>) => {
|
||||
return (
|
||||
<svg
|
||||
|
||||
Reference in New Issue
Block a user