mirror of
https://github.com/simstudioai/sim.git
synced 2026-01-31 09:48:06 -05:00
Compare commits
57 Commits
feat/copil
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
31fdd2be13 | ||
|
|
2c4eb9fecb | ||
|
|
aec0de046b | ||
|
|
51565a6e28 | ||
|
|
a280a53034 | ||
|
|
478a53521e | ||
|
|
6cf9841b99 | ||
|
|
656beb8383 | ||
|
|
f7c3de0591 | ||
|
|
2ec9b7f47e | ||
|
|
b0fbf3648d | ||
|
|
f718079593 | ||
|
|
dd2f0c6a6a | ||
|
|
f99518b837 | ||
|
|
028bc652c2 | ||
|
|
c6bf5cd58c | ||
|
|
11dc18a80d | ||
|
|
ab4e9dc72f | ||
|
|
1c58c35bd8 | ||
|
|
d63a5cb504 | ||
|
|
8bd5d41723 | ||
|
|
c12931bc50 | ||
|
|
e9c4251c1c | ||
|
|
cc2be33d6b | ||
|
|
45371e521e | ||
|
|
0ce0f98aa5 | ||
|
|
dff1c9d083 | ||
|
|
b09f683072 | ||
|
|
a8bb0db660 | ||
|
|
af82820a28 | ||
|
|
4372841797 | ||
|
|
5e8c843241 | ||
|
|
7bf3d73ee6 | ||
|
|
7ffc11a738 | ||
|
|
be578e2ed7 | ||
|
|
f415e5edc4 | ||
|
|
13a6e6c3fa | ||
|
|
f5ab7f21ae | ||
|
|
bfb6fffe38 | ||
|
|
4fbec0a43f | ||
|
|
585f5e365b | ||
|
|
3792bdd252 | ||
|
|
eb5d1f3e5b | ||
|
|
54ab82c8dd | ||
|
|
f895bf469b | ||
|
|
dd3209af06 | ||
|
|
b6ba3b50a7 | ||
|
|
b304233062 | ||
|
|
57e4b49bd6 | ||
|
|
e12dd204ed | ||
|
|
3d9d9cbc54 | ||
|
|
0f4ec962ad | ||
|
|
4827866f9a | ||
|
|
3e697d9ed9 | ||
|
|
4431a1a484 | ||
|
|
4d1a9a3f22 | ||
|
|
eb07a080fb |
7
.cursor/commands/council.md
Normal file
7
.cursor/commands/council.md
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
Based on the given area of interest, please:
|
||||||
|
|
||||||
|
1. Dig around the codebase in terms of that given area of interest, gather general information such as keywords and architecture overview.
|
||||||
|
2. Spawn off n=10 (unless specified otherwise) task agents to dig deeper into the codebase in terms of that given area of interest, some of them should be out of the box for variance.
|
||||||
|
3. Once the task agents are done, use the information to do what the user wants.
|
||||||
|
|
||||||
|
If user is in plan mode, use the information to create the plan.
|
||||||
@@ -1,5 +1,6 @@
|
|||||||
import type React from 'react'
|
import type React from 'react'
|
||||||
import { findNeighbour } from 'fumadocs-core/page-tree'
|
import { findNeighbour } from 'fumadocs-core/page-tree'
|
||||||
|
import { Pre } from 'fumadocs-ui/components/codeblock'
|
||||||
import defaultMdxComponents from 'fumadocs-ui/mdx'
|
import defaultMdxComponents from 'fumadocs-ui/mdx'
|
||||||
import { DocsBody, DocsDescription, DocsPage, DocsTitle } from 'fumadocs-ui/page'
|
import { DocsBody, DocsDescription, DocsPage, DocsTitle } from 'fumadocs-ui/page'
|
||||||
import { ChevronLeft, ChevronRight } from 'lucide-react'
|
import { ChevronLeft, ChevronRight } from 'lucide-react'
|
||||||
@@ -21,6 +22,7 @@ export default async function Page(props: { params: Promise<{ slug?: string[]; l
|
|||||||
const data = page.data as PageData
|
const data = page.data as PageData
|
||||||
const MDX = data.body
|
const MDX = data.body
|
||||||
const baseUrl = 'https://docs.sim.ai'
|
const baseUrl = 'https://docs.sim.ai'
|
||||||
|
const markdownContent = await data.getText('processed')
|
||||||
|
|
||||||
const pageTreeRecord = source.pageTree as Record<string, any>
|
const pageTreeRecord = source.pageTree as Record<string, any>
|
||||||
const pageTree =
|
const pageTree =
|
||||||
@@ -200,7 +202,7 @@ export default async function Page(props: { params: Promise<{ slug?: string[]; l
|
|||||||
<div className='relative mt-6 sm:mt-0'>
|
<div className='relative mt-6 sm:mt-0'>
|
||||||
<div className='absolute top-1 right-0 flex items-center gap-2'>
|
<div className='absolute top-1 right-0 flex items-center gap-2'>
|
||||||
<div className='hidden sm:flex'>
|
<div className='hidden sm:flex'>
|
||||||
<LLMCopyButton markdownUrl={`${page.url}.mdx`} />
|
<LLMCopyButton content={markdownContent} />
|
||||||
</div>
|
</div>
|
||||||
<PageNavigationArrows previous={neighbours?.previous} next={neighbours?.next} />
|
<PageNavigationArrows previous={neighbours?.previous} next={neighbours?.next} />
|
||||||
</div>
|
</div>
|
||||||
@@ -211,7 +213,11 @@ export default async function Page(props: { params: Promise<{ slug?: string[]; l
|
|||||||
<MDX
|
<MDX
|
||||||
components={{
|
components={{
|
||||||
...defaultMdxComponents,
|
...defaultMdxComponents,
|
||||||
CodeBlock,
|
pre: (props: React.HTMLAttributes<HTMLPreElement>) => (
|
||||||
|
<CodeBlock {...props}>
|
||||||
|
<Pre>{props.children}</Pre>
|
||||||
|
</CodeBlock>
|
||||||
|
),
|
||||||
h1: (props: React.HTMLAttributes<HTMLHeadingElement>) => (
|
h1: (props: React.HTMLAttributes<HTMLHeadingElement>) => (
|
||||||
<Heading as='h1' {...props} />
|
<Heading as='h1' {...props} />
|
||||||
),
|
),
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ import { defineI18nUI } from 'fumadocs-ui/i18n'
|
|||||||
import { DocsLayout } from 'fumadocs-ui/layouts/docs'
|
import { DocsLayout } from 'fumadocs-ui/layouts/docs'
|
||||||
import { RootProvider } from 'fumadocs-ui/provider/next'
|
import { RootProvider } from 'fumadocs-ui/provider/next'
|
||||||
import { Geist_Mono, Inter } from 'next/font/google'
|
import { Geist_Mono, Inter } from 'next/font/google'
|
||||||
|
import Script from 'next/script'
|
||||||
import {
|
import {
|
||||||
SidebarFolder,
|
SidebarFolder,
|
||||||
SidebarItem,
|
SidebarItem,
|
||||||
@@ -17,11 +18,13 @@ import '../global.css'
|
|||||||
const inter = Inter({
|
const inter = Inter({
|
||||||
subsets: ['latin'],
|
subsets: ['latin'],
|
||||||
variable: '--font-geist-sans',
|
variable: '--font-geist-sans',
|
||||||
|
display: 'swap',
|
||||||
})
|
})
|
||||||
|
|
||||||
const geistMono = Geist_Mono({
|
const geistMono = Geist_Mono({
|
||||||
subsets: ['latin'],
|
subsets: ['latin'],
|
||||||
variable: '--font-geist-mono',
|
variable: '--font-geist-mono',
|
||||||
|
display: 'swap',
|
||||||
})
|
})
|
||||||
|
|
||||||
const { provider } = defineI18nUI(i18n, {
|
const { provider } = defineI18nUI(i18n, {
|
||||||
@@ -93,10 +96,9 @@ export default async function Layout({ children, params }: LayoutProps) {
|
|||||||
type='application/ld+json'
|
type='application/ld+json'
|
||||||
dangerouslySetInnerHTML={{ __html: JSON.stringify(structuredData) }}
|
dangerouslySetInnerHTML={{ __html: JSON.stringify(structuredData) }}
|
||||||
/>
|
/>
|
||||||
{/* OneDollarStats Analytics - CDN script handles everything automatically */}
|
|
||||||
<script defer src='https://assets.onedollarstats.com/stonks.js' />
|
|
||||||
</head>
|
</head>
|
||||||
<body className='flex min-h-screen flex-col font-sans'>
|
<body className='flex min-h-screen flex-col font-sans'>
|
||||||
|
<Script src='https://assets.onedollarstats.com/stonks.js' strategy='lazyOnload' />
|
||||||
<RootProvider i18n={provider(lang)}>
|
<RootProvider i18n={provider(lang)}>
|
||||||
<Navbar />
|
<Navbar />
|
||||||
<DocsLayout
|
<DocsLayout
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ export default function NotFound() {
|
|||||||
<DocsPage>
|
<DocsPage>
|
||||||
<DocsBody>
|
<DocsBody>
|
||||||
<div className='flex min-h-[60vh] flex-col items-center justify-center text-center'>
|
<div className='flex min-h-[60vh] flex-col items-center justify-center text-center'>
|
||||||
<h1 className='mb-4 bg-gradient-to-b from-[#8357FF] to-[#6F3DFA] bg-clip-text font-bold text-8xl text-transparent'>
|
<h1 className='mb-4 bg-gradient-to-b from-[#47d991] to-[#33c482] bg-clip-text font-bold text-8xl text-transparent'>
|
||||||
404
|
404
|
||||||
</h1>
|
</h1>
|
||||||
<h2 className='mb-2 font-semibold text-2xl text-foreground'>Page Not Found</h2>
|
<h2 className='mb-2 font-semibold text-2xl text-foreground'>Page Not Found</h2>
|
||||||
|
|||||||
@@ -5113,3 +5113,60 @@ export function PulseIcon(props: SVGProps<SVGSVGElement>) {
|
|||||||
</svg>
|
</svg>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function SimilarwebIcon(props: SVGProps<SVGSVGElement>) {
|
||||||
|
return (
|
||||||
|
<svg
|
||||||
|
{...props}
|
||||||
|
role='img'
|
||||||
|
viewBox='0 0 24 24'
|
||||||
|
xmlns='http://www.w3.org/2000/svg'
|
||||||
|
height='24'
|
||||||
|
width='24'
|
||||||
|
>
|
||||||
|
<path
|
||||||
|
d='M22.099 5.781c-1.283 -2 -3.14 -3.67 -5.27 -4.52l-0.63 -0.213a7.433 7.433 0 0 0 -2.15 -0.331c-2.307 0.01 -4.175 1.92 -4.175 4.275a4.3 4.3 0 0 0 0.867 2.602l-0.26 -0.342c0.124 0.186 0.26 0.37 0.417 0.556 0.663 0.802 1.604 1.635 2.822 2.58 2.999 2.32 4.943 4.378 5.104 6.93 0.038 0.344 0.062 0.696 0.062 1.051 0 1.297 -0.283 2.67 -0.764 3.635h0.005s-0.207 0.377 -0.077 0.487c0.066 0.057 0.21 0.1 0.46 -0.053a12.104 12.104 0 0 0 3.4 -3.33 12.111 12.111 0 0 0 2.088 -6.635 12.098 12.098 0 0 0 -1.9 -6.692zm-9.096 8.718 -1.878 -1.55c-3.934 -2.87 -5.98 -5.966 -4.859 -9.783a8.73 8.73 0 0 1 0.37 -1.016v-0.004s0.278 -0.583 -0.327 -0.295a12.067 12.067 0 0 0 -6.292 9.975 12.11 12.11 0 0 0 2.053 7.421 9.394 9.394 0 0 0 2.154 2.168H4.22c4.148 3.053 7.706 1.446 7.706 1.446h0.003a4.847 4.847 0 0 0 2.962 -4.492 4.855 4.855 0 0 0 -1.889 -3.87z'
|
||||||
|
fill='currentColor'
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export function CalComIcon(props: SVGProps<SVGSVGElement>) {
|
||||||
|
return (
|
||||||
|
<svg
|
||||||
|
{...props}
|
||||||
|
width='101'
|
||||||
|
height='22'
|
||||||
|
viewBox='0 0 101 22'
|
||||||
|
fill='currentColor'
|
||||||
|
xmlns='http://www.w3.org/2000/svg'
|
||||||
|
>
|
||||||
|
<path
|
||||||
|
d='M10.0582 20.817C4.32115 20.817 0 16.2763 0 10.6704C0 5.04589 4.1005 0.467773 10.0582 0.467773C13.2209 0.467773 15.409 1.43945 17.1191 3.66311L14.3609 5.96151C13.2025 4.72822 11.805 4.11158 10.0582 4.11158C6.17833 4.11158 4.04533 7.08268 4.04533 10.6704C4.04533 14.2582 6.38059 17.1732 10.0582 17.1732C11.7866 17.1732 13.2577 16.5566 14.4161 15.3233L17.1375 17.7151C15.501 19.8453 13.2577 20.817 10.0582 20.817Z'
|
||||||
|
fill='#292929'
|
||||||
|
/>
|
||||||
|
<path
|
||||||
|
d='M29.0161 5.88601H32.7304V20.4612H29.0161V18.331C28.2438 19.8446 26.9566 20.8536 24.4927 20.8536C20.5577 20.8536 17.4133 17.4341 17.4133 13.2297C17.4133 9.02528 20.5577 5.60571 24.4927 5.60571C26.9383 5.60571 28.2438 6.61477 29.0161 8.12835V5.88601ZM29.1264 13.2297C29.1264 10.95 27.5634 9.06266 25.0995 9.06266C22.7274 9.06266 21.1828 10.9686 21.1828 13.2297C21.1828 15.4346 22.7274 17.3967 25.0995 17.3967C27.5451 17.3967 29.1264 15.4907 29.1264 13.2297Z'
|
||||||
|
fill='#292929'
|
||||||
|
/>
|
||||||
|
<path d='M35.3599 0H39.0742V20.4427H35.3599V0Z' fill='#292929' />
|
||||||
|
<path
|
||||||
|
d='M40.7291 18.5182C40.7291 17.3223 41.6853 16.3132 42.9908 16.3132C44.2964 16.3132 45.2158 17.3223 45.2158 18.5182C45.2158 19.7515 44.278 20.7605 42.9908 20.7605C41.7037 20.7605 40.7291 19.7515 40.7291 18.5182Z'
|
||||||
|
fill='#292929'
|
||||||
|
/>
|
||||||
|
<path
|
||||||
|
d='M59.4296 18.1068C58.0505 19.7885 55.9543 20.8536 53.4719 20.8536C49.0404 20.8536 45.7858 17.4341 45.7858 13.2297C45.7858 9.02528 49.0404 5.60571 53.4719 5.60571C55.8623 5.60571 57.9402 6.61477 59.3193 8.20309L56.4508 10.6136C55.7336 9.71667 54.7958 9.04397 53.4719 9.04397C51.0999 9.04397 49.5553 10.95 49.5553 13.211C49.5553 15.472 51.0999 17.378 53.4719 17.378C54.9062 17.378 55.8991 16.6306 56.6346 15.6215L59.4296 18.1068Z'
|
||||||
|
fill='#292929'
|
||||||
|
/>
|
||||||
|
<path
|
||||||
|
d='M59.7422 13.2297C59.7422 9.02528 62.9968 5.60571 67.4283 5.60571C71.8598 5.60571 75.1144 9.02528 75.1144 13.2297C75.1144 17.4341 71.8598 20.8536 67.4283 20.8536C62.9968 20.8349 59.7422 17.4341 59.7422 13.2297ZM71.3449 13.2297C71.3449 10.95 69.8003 9.06266 67.4283 9.06266C65.0563 9.04397 63.5117 10.95 63.5117 13.2297C63.5117 15.4907 65.0563 17.3967 67.4283 17.3967C69.8003 17.3967 71.3449 15.4907 71.3449 13.2297Z'
|
||||||
|
fill='#292929'
|
||||||
|
/>
|
||||||
|
<path
|
||||||
|
d='M100.232 11.5482V20.4428H96.518V12.4638C96.518 9.94119 95.3412 8.85739 93.576 8.85739C91.921 8.85739 90.7442 9.67958 90.7442 12.4638V20.4428H87.0299V12.4638C87.0299 9.94119 85.8346 8.85739 84.0878 8.85739C82.4329 8.85739 80.9802 9.67958 80.9802 12.4638V20.4428H77.2659V5.8676H80.9802V7.88571C81.7525 6.31607 83.15 5.53125 85.3014 5.53125C87.3425 5.53125 89.0525 6.5403 89.9903 8.24074C90.9281 6.50293 92.3072 5.53125 94.8079 5.53125C97.8603 5.54994 100.232 7.86702 100.232 11.5482Z'
|
||||||
|
fill='#292929'
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|||||||
@@ -8,13 +8,7 @@ import { ThemeToggle } from '@/components/ui/theme-toggle'
|
|||||||
|
|
||||||
export function Navbar() {
|
export function Navbar() {
|
||||||
return (
|
return (
|
||||||
<nav
|
<nav className='sticky top-0 z-50 border-border/50 border-b bg-background/80 backdrop-blur-md backdrop-saturate-150'>
|
||||||
className='sticky top-0 z-50 border-border/50 border-b'
|
|
||||||
style={{
|
|
||||||
backdropFilter: 'blur(25px) saturate(180%)',
|
|
||||||
WebkitBackdropFilter: 'blur(25px) saturate(180%)',
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{/* Desktop: Single row layout */}
|
{/* Desktop: Single row layout */}
|
||||||
<div className='hidden h-16 w-full items-center lg:flex'>
|
<div className='hidden h-16 w-full items-center lg:flex'>
|
||||||
<div
|
<div
|
||||||
|
|||||||
@@ -1,45 +1,13 @@
|
|||||||
'use client'
|
'use client'
|
||||||
|
|
||||||
import { useState } from 'react'
|
|
||||||
import { useCopyButton } from 'fumadocs-ui/utils/use-copy-button'
|
import { useCopyButton } from 'fumadocs-ui/utils/use-copy-button'
|
||||||
import { Check, Copy } from 'lucide-react'
|
import { Check, Copy } from 'lucide-react'
|
||||||
|
|
||||||
const cache = new Map<string, string>()
|
export function LLMCopyButton({ content }: { content: string }) {
|
||||||
|
const [checked, onClick] = useCopyButton(() => navigator.clipboard.writeText(content))
|
||||||
export function LLMCopyButton({
|
|
||||||
markdownUrl,
|
|
||||||
}: {
|
|
||||||
/**
|
|
||||||
* A URL to fetch the raw Markdown/MDX content of page
|
|
||||||
*/
|
|
||||||
markdownUrl: string
|
|
||||||
}) {
|
|
||||||
const [isLoading, setLoading] = useState(false)
|
|
||||||
const [checked, onClick] = useCopyButton(async () => {
|
|
||||||
const cached = cache.get(markdownUrl)
|
|
||||||
if (cached) return navigator.clipboard.writeText(cached)
|
|
||||||
|
|
||||||
setLoading(true)
|
|
||||||
|
|
||||||
try {
|
|
||||||
await navigator.clipboard.write([
|
|
||||||
new ClipboardItem({
|
|
||||||
'text/plain': fetch(markdownUrl).then(async (res) => {
|
|
||||||
const content = await res.text()
|
|
||||||
cache.set(markdownUrl, content)
|
|
||||||
|
|
||||||
return content
|
|
||||||
}),
|
|
||||||
}),
|
|
||||||
])
|
|
||||||
} finally {
|
|
||||||
setLoading(false)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<button
|
<button
|
||||||
disabled={isLoading}
|
|
||||||
onClick={onClick}
|
onClick={onClick}
|
||||||
className='flex cursor-pointer items-center gap-1.5 rounded-lg border border-border/40 bg-background px-2.5 py-2 text-muted-foreground/60 text-sm leading-none transition-all hover:border-border hover:bg-accent/50 hover:text-muted-foreground'
|
className='flex cursor-pointer items-center gap-1.5 rounded-lg border border-border/40 bg-background px-2.5 py-2 text-muted-foreground/60 text-sm leading-none transition-all hover:border-border hover:bg-accent/50 hover:text-muted-foreground'
|
||||||
aria-label={checked ? 'Copied to clipboard' : 'Copy page content'}
|
aria-label={checked ? 'Copied to clipboard' : 'Copy page content'}
|
||||||
|
|||||||
@@ -17,23 +17,16 @@ export function CodeBlock(props: React.ComponentProps<typeof FumadocsCodeBlock>)
|
|||||||
return (
|
return (
|
||||||
<FumadocsCodeBlock
|
<FumadocsCodeBlock
|
||||||
{...props}
|
{...props}
|
||||||
Actions={({ children, className }) => (
|
Actions={({ className }) => (
|
||||||
<div className={cn('empty:hidden', className)}>
|
<div className={cn('empty:hidden', className)}>
|
||||||
{/* Custom copy button */}
|
|
||||||
<button
|
<button
|
||||||
type='button'
|
type='button'
|
||||||
aria-label={copied ? 'Copied Text' : 'Copy Text'}
|
aria-label={copied ? 'Copied Text' : 'Copy Text'}
|
||||||
onClick={(e) => {
|
onClick={(e) => {
|
||||||
const pre = (e.currentTarget as HTMLElement)
|
const pre = (e.currentTarget as HTMLElement).closest('figure')?.querySelector('pre')
|
||||||
.closest('.nd-codeblock')
|
|
||||||
?.querySelector('pre')
|
|
||||||
if (pre) handleCopy(pre.textContent || '')
|
if (pre) handleCopy(pre.textContent || '')
|
||||||
}}
|
}}
|
||||||
className={cn(
|
className='cursor-pointer rounded-md p-2 text-muted-foreground transition-colors hover:text-foreground'
|
||||||
'cursor-pointer rounded-md p-2 transition-all',
|
|
||||||
'border border-border bg-background/80 hover:bg-muted',
|
|
||||||
'backdrop-blur-sm'
|
|
||||||
)}
|
|
||||||
>
|
>
|
||||||
<span className='flex items-center justify-center'>
|
<span className='flex items-center justify-center'>
|
||||||
{copied ? (
|
{copied ? (
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ import {
|
|||||||
AsanaIcon,
|
AsanaIcon,
|
||||||
BrainIcon,
|
BrainIcon,
|
||||||
BrowserUseIcon,
|
BrowserUseIcon,
|
||||||
|
CalComIcon,
|
||||||
CalendlyIcon,
|
CalendlyIcon,
|
||||||
CirclebackIcon,
|
CirclebackIcon,
|
||||||
ClayIcon,
|
ClayIcon,
|
||||||
@@ -100,6 +101,7 @@ import {
|
|||||||
ServiceNowIcon,
|
ServiceNowIcon,
|
||||||
SftpIcon,
|
SftpIcon,
|
||||||
ShopifyIcon,
|
ShopifyIcon,
|
||||||
|
SimilarwebIcon,
|
||||||
SlackIcon,
|
SlackIcon,
|
||||||
SmtpIcon,
|
SmtpIcon,
|
||||||
SQSIcon,
|
SQSIcon,
|
||||||
@@ -141,6 +143,7 @@ export const blockTypeToIconMap: Record<string, IconComponent> = {
|
|||||||
arxiv: ArxivIcon,
|
arxiv: ArxivIcon,
|
||||||
asana: AsanaIcon,
|
asana: AsanaIcon,
|
||||||
browser_use: BrowserUseIcon,
|
browser_use: BrowserUseIcon,
|
||||||
|
calcom: CalComIcon,
|
||||||
calendly: CalendlyIcon,
|
calendly: CalendlyIcon,
|
||||||
circleback: CirclebackIcon,
|
circleback: CirclebackIcon,
|
||||||
clay: ClayIcon,
|
clay: ClayIcon,
|
||||||
@@ -228,6 +231,7 @@ export const blockTypeToIconMap: Record<string, IconComponent> = {
|
|||||||
sftp: SftpIcon,
|
sftp: SftpIcon,
|
||||||
sharepoint: MicrosoftSharepointIcon,
|
sharepoint: MicrosoftSharepointIcon,
|
||||||
shopify: ShopifyIcon,
|
shopify: ShopifyIcon,
|
||||||
|
similarweb: SimilarwebIcon,
|
||||||
slack: SlackIcon,
|
slack: SlackIcon,
|
||||||
smtp: SmtpIcon,
|
smtp: SmtpIcon,
|
||||||
sqs: SQSIcon,
|
sqs: SQSIcon,
|
||||||
|
|||||||
@@ -58,7 +58,7 @@ Controls response randomness and creativity:
|
|||||||
|
|
||||||
### Max Output Tokens
|
### Max Output Tokens
|
||||||
|
|
||||||
Controls the maximum length of the model's response. For Anthropic models, Sim uses reliable defaults: streaming executions use the model's full capacity (e.g. 64,000 tokens for Claude 4.5), while non-streaming executions default to 8,192 to avoid timeout issues. For long-form content generation via API, explicitly set a higher value.
|
Controls the maximum length of the model's response. For Anthropic models, Sim uses reliable defaults: streaming executions use the model's full capacity (e.g. 64,000 tokens for Claude 4.5), while non-streaming executions default to 8,192 to avoid timeout issues. When using tools with Anthropic models, intermediate tool-calling requests use a capped limit of 8,192 tokens to avoid SDK timeout errors, regardless of your configured max tokens—the final streaming response uses your full configured limit. This only affects Anthropic's direct API; AWS Bedrock handles this automatically. For long-form content generation via API, explicitly set a higher value.
|
||||||
|
|
||||||
### API Key
|
### API Key
|
||||||
|
|
||||||
|
|||||||
@@ -52,12 +52,12 @@ Send a message to an external A2A-compatible agent.
|
|||||||
|
|
||||||
| Parameter | Type | Description |
|
| Parameter | Type | Description |
|
||||||
| --------- | ---- | ----------- |
|
| --------- | ---- | ----------- |
|
||||||
| `content` | string | The text response from the agent |
|
| `content` | string | Text response content from the agent |
|
||||||
| `taskId` | string | Task ID for follow-up interactions |
|
| `taskId` | string | Unique task identifier |
|
||||||
| `contextId` | string | Context ID for conversation continuity |
|
| `contextId` | string | Groups related tasks/messages |
|
||||||
| `state` | string | Task state |
|
| `state` | string | Current lifecycle state \(working, completed, failed, canceled, rejected, input_required, auth_required\) |
|
||||||
| `artifacts` | array | Structured output artifacts |
|
| `artifacts` | array | Task output artifacts |
|
||||||
| `history` | array | Full message history |
|
| `history` | array | Conversation history \(Message array\) |
|
||||||
|
|
||||||
### `a2a_get_task`
|
### `a2a_get_task`
|
||||||
|
|
||||||
@@ -76,11 +76,11 @@ Query the status of an existing A2A task.
|
|||||||
|
|
||||||
| Parameter | Type | Description |
|
| Parameter | Type | Description |
|
||||||
| --------- | ---- | ----------- |
|
| --------- | ---- | ----------- |
|
||||||
| `taskId` | string | Task ID |
|
| `taskId` | string | Unique task identifier |
|
||||||
| `contextId` | string | Context ID |
|
| `contextId` | string | Groups related tasks/messages |
|
||||||
| `state` | string | Task state |
|
| `state` | string | Current lifecycle state \(working, completed, failed, canceled, rejected, input_required, auth_required\) |
|
||||||
| `artifacts` | array | Output artifacts |
|
| `artifacts` | array | Task output artifacts |
|
||||||
| `history` | array | Message history |
|
| `history` | array | Conversation history \(Message array\) |
|
||||||
|
|
||||||
### `a2a_cancel_task`
|
### `a2a_cancel_task`
|
||||||
|
|
||||||
@@ -99,7 +99,7 @@ Cancel a running A2A task.
|
|||||||
| Parameter | Type | Description |
|
| Parameter | Type | Description |
|
||||||
| --------- | ---- | ----------- |
|
| --------- | ---- | ----------- |
|
||||||
| `cancelled` | boolean | Whether cancellation was successful |
|
| `cancelled` | boolean | Whether cancellation was successful |
|
||||||
| `state` | string | Task state after cancellation |
|
| `state` | string | Current lifecycle state \(working, completed, failed, canceled, rejected, input_required, auth_required\) |
|
||||||
|
|
||||||
### `a2a_get_agent_card`
|
### `a2a_get_agent_card`
|
||||||
|
|
||||||
@@ -116,14 +116,15 @@ Fetch the Agent Card (discovery document) for an A2A agent.
|
|||||||
|
|
||||||
| Parameter | Type | Description |
|
| Parameter | Type | Description |
|
||||||
| --------- | ---- | ----------- |
|
| --------- | ---- | ----------- |
|
||||||
| `name` | string | Agent name |
|
| `name` | string | Agent display name |
|
||||||
| `description` | string | Agent description |
|
| `description` | string | Agent purpose/capabilities |
|
||||||
| `url` | string | Agent endpoint URL |
|
| `url` | string | Service endpoint URL |
|
||||||
| `version` | string | Agent version |
|
| `provider` | object | Creator organization details |
|
||||||
| `capabilities` | object | Agent capabilities \(streaming, pushNotifications, etc.\) |
|
| `capabilities` | object | Feature support matrix |
|
||||||
| `skills` | array | Skills the agent can perform |
|
| `skills` | array | Available operations |
|
||||||
| `defaultInputModes` | array | Default input modes \(text, file, data\) |
|
| `version` | string | A2A protocol version supported by the agent |
|
||||||
| `defaultOutputModes` | array | Default output modes \(text, file, data\) |
|
| `defaultInputModes` | array | Default input content types accepted by the agent |
|
||||||
|
| `defaultOutputModes` | array | Default output content types produced by the agent |
|
||||||
|
|
||||||
### `a2a_resubscribe`
|
### `a2a_resubscribe`
|
||||||
|
|
||||||
@@ -141,12 +142,12 @@ Reconnect to an ongoing A2A task stream after connection interruption.
|
|||||||
|
|
||||||
| Parameter | Type | Description |
|
| Parameter | Type | Description |
|
||||||
| --------- | ---- | ----------- |
|
| --------- | ---- | ----------- |
|
||||||
| `taskId` | string | Task ID |
|
| `taskId` | string | Unique task identifier |
|
||||||
| `contextId` | string | Context ID |
|
| `contextId` | string | Groups related tasks/messages |
|
||||||
| `state` | string | Current task state |
|
| `state` | string | Current lifecycle state \(working, completed, failed, canceled, rejected, input_required, auth_required\) |
|
||||||
| `isRunning` | boolean | Whether the task is still running |
|
| `isRunning` | boolean | Whether the task is still running |
|
||||||
| `artifacts` | array | Output artifacts |
|
| `artifacts` | array | Task output artifacts |
|
||||||
| `history` | array | Message history |
|
| `history` | array | Conversation history \(Message array\) |
|
||||||
|
|
||||||
### `a2a_set_push_notification`
|
### `a2a_set_push_notification`
|
||||||
|
|
||||||
@@ -166,9 +167,9 @@ Configure a webhook to receive task update notifications.
|
|||||||
|
|
||||||
| Parameter | Type | Description |
|
| Parameter | Type | Description |
|
||||||
| --------- | ---- | ----------- |
|
| --------- | ---- | ----------- |
|
||||||
| `url` | string | Configured webhook URL |
|
| `url` | string | HTTPS webhook URL for notifications |
|
||||||
| `token` | string | Token for webhook validation |
|
| `token` | string | Authentication token for webhook validation |
|
||||||
| `success` | boolean | Whether configuration was successful |
|
| `success` | boolean | Whether the operation was successful |
|
||||||
|
|
||||||
### `a2a_get_push_notification`
|
### `a2a_get_push_notification`
|
||||||
|
|
||||||
@@ -186,9 +187,8 @@ Get the push notification webhook configuration for a task.
|
|||||||
|
|
||||||
| Parameter | Type | Description |
|
| Parameter | Type | Description |
|
||||||
| --------- | ---- | ----------- |
|
| --------- | ---- | ----------- |
|
||||||
| `url` | string | Configured webhook URL |
|
| `token` | string | Authentication token for webhook validation |
|
||||||
| `token` | string | Token for webhook validation |
|
| `exists` | boolean | Whether the resource exists |
|
||||||
| `exists` | boolean | Whether a push notification config exists |
|
|
||||||
|
|
||||||
### `a2a_delete_push_notification`
|
### `a2a_delete_push_notification`
|
||||||
|
|
||||||
@@ -207,6 +207,6 @@ Delete the push notification webhook configuration for a task.
|
|||||||
|
|
||||||
| Parameter | Type | Description |
|
| Parameter | Type | Description |
|
||||||
| --------- | ---- | ----------- |
|
| --------- | ---- | ----------- |
|
||||||
| `success` | boolean | Whether deletion was successful |
|
| `success` | boolean | Whether the operation was successful |
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
789
apps/docs/content/docs/en/tools/calcom.mdx
Normal file
789
apps/docs/content/docs/en/tools/calcom.mdx
Normal file
@@ -0,0 +1,789 @@
|
|||||||
|
---
|
||||||
|
title: CalCom
|
||||||
|
description: Manage Cal.com bookings, event types, schedules, and availability
|
||||||
|
---
|
||||||
|
|
||||||
|
import { BlockInfoCard } from "@/components/ui/block-info-card"
|
||||||
|
|
||||||
|
<BlockInfoCard
|
||||||
|
type="calcom"
|
||||||
|
color="#FFFFFE"
|
||||||
|
/>
|
||||||
|
|
||||||
|
{/* MANUAL-CONTENT-START:intro */}
|
||||||
|
[Cal.com](https://cal.com/) is a flexible and open-source scheduling platform that makes it easy to manage appointments, bookings, event types, and team availabilities.
|
||||||
|
|
||||||
|
With Cal.com, you can:
|
||||||
|
|
||||||
|
- **Automate scheduling**: Allow users to view your available time slots and book meetings automatically, without back-and-forth emails.
|
||||||
|
- **Manage events**: Create and customize event types, durations, and rules for one-on-one or group meetings.
|
||||||
|
- **Integrate calendars**: Seamlessly connect with Google, Outlook, Apple, or other calendar providers to avoid double bookings.
|
||||||
|
- **Handle attendees and guests**: Collect attendee information, manage guests, and send invitations or reminders.
|
||||||
|
- **Control availability**: Define custom working hours, buffer times, and cancellation/rebooking rules.
|
||||||
|
- **Power workflows**: Trigger custom actions via webhooks when a booking is created, cancelled, or rescheduled.
|
||||||
|
|
||||||
|
In Sim, the Cal.com integration enables your agents to book meetings, check availabilities, manage event types, and automate scheduling tasks programmatically. This helps agents coordinate meetings, send bookings on behalf of users, check schedules, or respond to booking events—all without manual intervention. By connecting Sim with Cal.com, you unlock highly automated and intelligent scheduling workflows that can integrate seamlessly with your broader automation needs.
|
||||||
|
{/* MANUAL-CONTENT-END */}
|
||||||
|
|
||||||
|
|
||||||
|
## Usage Instructions
|
||||||
|
|
||||||
|
Integrate Cal.com into your workflow. Create and manage bookings, event types, schedules, and check availability slots. Supports creating, listing, rescheduling, and canceling bookings, as well as managing event types and schedules. Can also trigger workflows based on Cal.com webhook events (booking created, cancelled, rescheduled). Connect your Cal.com account via OAuth.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## Tools
|
||||||
|
|
||||||
|
### `calcom_create_booking`
|
||||||
|
|
||||||
|
Create a new booking on Cal.com
|
||||||
|
|
||||||
|
#### Input
|
||||||
|
|
||||||
|
| Parameter | Type | Required | Description |
|
||||||
|
| --------- | ---- | -------- | ----------- |
|
||||||
|
| `eventTypeId` | number | Yes | The ID of the event type to book |
|
||||||
|
| `start` | string | Yes | Start time in UTC ISO 8601 format \(e.g., 2024-01-15T09:00:00Z\) |
|
||||||
|
| `attendee` | object | Yes | Attendee information object with name, email, timeZone, and optional phoneNumber \(constructed from individual attendee fields\) |
|
||||||
|
| `guests` | array | No | Array of guest email addresses |
|
||||||
|
| `items` | string | No | Guest email address |
|
||||||
|
| `lengthInMinutes` | number | No | Duration of the booking in minutes \(overrides event type default\) |
|
||||||
|
| `metadata` | object | No | Custom metadata to attach to the booking |
|
||||||
|
|
||||||
|
#### Output
|
||||||
|
|
||||||
|
| Parameter | Type | Description |
|
||||||
|
| --------- | ---- | ----------- |
|
||||||
|
| `status` | string | Response status |
|
||||||
|
| `data` | object | Created booking details |
|
||||||
|
| ↳ `eventType` | object | Event type details |
|
||||||
|
| ↳ `id` | number | Event type ID |
|
||||||
|
| ↳ `slug` | string | Event type slug |
|
||||||
|
| ↳ `attendees` | array | List of attendees |
|
||||||
|
| ↳ `name` | string | Attendee name |
|
||||||
|
| ↳ `email` | string | Attendee actual email address |
|
||||||
|
| ↳ `displayEmail` | string | Email shown publicly \(may differ from actual email\) |
|
||||||
|
| ↳ `timeZone` | string | Attendee timezone \(IANA format\) |
|
||||||
|
| ↳ `phoneNumber` | string | Attendee phone number |
|
||||||
|
| ↳ `language` | string | Attendee language preference \(ISO code\) |
|
||||||
|
| ↳ `absent` | boolean | Whether attendee was absent |
|
||||||
|
| ↳ `hosts` | array | List of hosts |
|
||||||
|
| ↳ `id` | number | Host user ID |
|
||||||
|
| ↳ `name` | string | Host display name |
|
||||||
|
| ↳ `email` | string | Host actual email address |
|
||||||
|
| ↳ `displayEmail` | string | Email shown publicly \(may differ from actual email\) |
|
||||||
|
| ↳ `username` | string | Host Cal.com username |
|
||||||
|
| ↳ `timeZone` | string | Host timezone \(IANA format\) |
|
||||||
|
| ↳ `id` | number | Numeric booking ID |
|
||||||
|
| ↳ `uid` | string | Unique identifier for the booking |
|
||||||
|
| ↳ `title` | string | Title of the booking |
|
||||||
|
| ↳ `status` | string | Booking status \(e.g., accepted, pending, cancelled\) |
|
||||||
|
| ↳ `start` | string | Start time in ISO 8601 format |
|
||||||
|
| ↳ `end` | string | End time in ISO 8601 format |
|
||||||
|
| ↳ `duration` | number | Duration in minutes |
|
||||||
|
| ↳ `eventTypeId` | number | Event type ID |
|
||||||
|
| ↳ `meetingUrl` | string | URL to join the meeting |
|
||||||
|
| ↳ `location` | string | Location of the booking |
|
||||||
|
| ↳ `absentHost` | boolean | Whether the host was absent |
|
||||||
|
| ↳ `guests` | array | Guest email addresses |
|
||||||
|
| ↳ `bookingFieldsResponses` | json | Custom booking field responses \(dynamic keys based on event type configuration\) |
|
||||||
|
| ↳ `metadata` | json | Custom metadata attached to the booking \(dynamic key-value pairs\) |
|
||||||
|
| ↳ `icsUid` | string | ICS calendar UID |
|
||||||
|
| ↳ `createdAt` | string | When the booking was created |
|
||||||
|
|
||||||
|
### `calcom_get_booking`
|
||||||
|
|
||||||
|
Get details of a specific booking by its UID
|
||||||
|
|
||||||
|
#### Input
|
||||||
|
|
||||||
|
| Parameter | Type | Required | Description |
|
||||||
|
| --------- | ---- | -------- | ----------- |
|
||||||
|
| `bookingUid` | string | Yes | Unique identifier \(UID\) of the booking |
|
||||||
|
|
||||||
|
#### Output
|
||||||
|
|
||||||
|
| Parameter | Type | Description |
|
||||||
|
| --------- | ---- | ----------- |
|
||||||
|
| `status` | string | Response status |
|
||||||
|
| `data` | object | Booking details |
|
||||||
|
| ↳ `eventType` | object | Event type details |
|
||||||
|
| ↳ `id` | number | Event type ID |
|
||||||
|
| ↳ `slug` | string | Event type slug |
|
||||||
|
| ↳ `attendees` | array | List of attendees |
|
||||||
|
| ↳ `name` | string | Attendee name |
|
||||||
|
| ↳ `email` | string | Attendee actual email address |
|
||||||
|
| ↳ `displayEmail` | string | Email shown publicly \(may differ from actual email\) |
|
||||||
|
| ↳ `timeZone` | string | Attendee timezone \(IANA format\) |
|
||||||
|
| ↳ `phoneNumber` | string | Attendee phone number |
|
||||||
|
| ↳ `language` | string | Attendee language preference \(ISO code\) |
|
||||||
|
| ↳ `absent` | boolean | Whether attendee was absent |
|
||||||
|
| ↳ `hosts` | array | List of hosts |
|
||||||
|
| ↳ `id` | number | Host user ID |
|
||||||
|
| ↳ `name` | string | Host display name |
|
||||||
|
| ↳ `email` | string | Host actual email address |
|
||||||
|
| ↳ `displayEmail` | string | Email shown publicly \(may differ from actual email\) |
|
||||||
|
| ↳ `username` | string | Host Cal.com username |
|
||||||
|
| ↳ `timeZone` | string | Host timezone \(IANA format\) |
|
||||||
|
| ↳ `id` | number | Numeric booking ID |
|
||||||
|
| ↳ `uid` | string | Unique identifier for the booking |
|
||||||
|
| ↳ `title` | string | Title of the booking |
|
||||||
|
| ↳ `description` | string | Description of the booking |
|
||||||
|
| ↳ `status` | string | Booking status \(e.g., accepted, pending, cancelled\) |
|
||||||
|
| ↳ `start` | string | Start time in ISO 8601 format |
|
||||||
|
| ↳ `end` | string | End time in ISO 8601 format |
|
||||||
|
| ↳ `duration` | number | Duration in minutes |
|
||||||
|
| ↳ `eventTypeId` | number | Event type ID |
|
||||||
|
| ↳ `meetingUrl` | string | URL to join the meeting |
|
||||||
|
| ↳ `location` | string | Location of the booking |
|
||||||
|
| ↳ `absentHost` | boolean | Whether the host was absent |
|
||||||
|
| ↳ `guests` | array | Guest email addresses |
|
||||||
|
| ↳ `bookingFieldsResponses` | json | Custom booking field responses \(dynamic keys based on event type configuration\) |
|
||||||
|
| ↳ `metadata` | json | Custom metadata attached to the booking \(dynamic key-value pairs\) |
|
||||||
|
| ↳ `rating` | number | Booking rating |
|
||||||
|
| ↳ `icsUid` | string | ICS calendar UID |
|
||||||
|
| ↳ `cancellationReason` | string | Reason for cancellation if cancelled |
|
||||||
|
| ↳ `reschedulingReason` | string | Reason for rescheduling if rescheduled |
|
||||||
|
| ↳ `rescheduledFromUid` | string | Original booking UID if this booking was rescheduled |
|
||||||
|
| ↳ `rescheduledToUid` | string | New booking UID after reschedule |
|
||||||
|
| ↳ `cancelledByEmail` | string | Email of person who cancelled the booking |
|
||||||
|
| ↳ `rescheduledByEmail` | string | Email of person who rescheduled the booking |
|
||||||
|
| ↳ `createdAt` | string | When the booking was created |
|
||||||
|
| ↳ `updatedAt` | string | When the booking was last updated |
|
||||||
|
|
||||||
|
### `calcom_list_bookings`
|
||||||
|
|
||||||
|
List all bookings with optional status filter
|
||||||
|
|
||||||
|
#### Input
|
||||||
|
|
||||||
|
| Parameter | Type | Required | Description |
|
||||||
|
| --------- | ---- | -------- | ----------- |
|
||||||
|
| `status` | string | No | Filter bookings by status: upcoming, recurring, past, cancelled, or unconfirmed |
|
||||||
|
| `take` | number | No | Number of bookings to return \(pagination limit\) |
|
||||||
|
| `skip` | number | No | Number of bookings to skip \(pagination offset\) |
|
||||||
|
|
||||||
|
#### Output
|
||||||
|
|
||||||
|
| Parameter | Type | Description |
|
||||||
|
| --------- | ---- | ----------- |
|
||||||
|
| `status` | string | Response status |
|
||||||
|
| `data` | array | Array of bookings |
|
||||||
|
| ↳ `eventType` | object | Event type details |
|
||||||
|
| ↳ `id` | number | Event type ID |
|
||||||
|
| ↳ `slug` | string | Event type slug |
|
||||||
|
| ↳ `attendees` | array | List of attendees |
|
||||||
|
| ↳ `name` | string | Attendee name |
|
||||||
|
| ↳ `email` | string | Attendee actual email address |
|
||||||
|
| ↳ `displayEmail` | string | Email shown publicly \(may differ from actual email\) |
|
||||||
|
| ↳ `timeZone` | string | Attendee timezone \(IANA format\) |
|
||||||
|
| ↳ `phoneNumber` | string | Attendee phone number |
|
||||||
|
| ↳ `language` | string | Attendee language preference \(ISO code\) |
|
||||||
|
| ↳ `absent` | boolean | Whether attendee was absent |
|
||||||
|
| ↳ `hosts` | array | List of hosts |
|
||||||
|
| ↳ `id` | number | Host user ID |
|
||||||
|
| ↳ `name` | string | Host display name |
|
||||||
|
| ↳ `email` | string | Host actual email address |
|
||||||
|
| ↳ `displayEmail` | string | Email shown publicly \(may differ from actual email\) |
|
||||||
|
| ↳ `username` | string | Host Cal.com username |
|
||||||
|
| ↳ `timeZone` | string | Host timezone \(IANA format\) |
|
||||||
|
| ↳ `id` | number | Numeric booking ID |
|
||||||
|
| ↳ `uid` | string | Unique identifier for the booking |
|
||||||
|
| ↳ `title` | string | Title of the booking |
|
||||||
|
| ↳ `description` | string | Description of the booking |
|
||||||
|
| ↳ `status` | string | Booking status \(e.g., accepted, pending, cancelled\) |
|
||||||
|
| ↳ `start` | string | Start time in ISO 8601 format |
|
||||||
|
| ↳ `end` | string | End time in ISO 8601 format |
|
||||||
|
| ↳ `duration` | number | Duration in minutes |
|
||||||
|
| ↳ `eventTypeId` | number | Event type ID |
|
||||||
|
| ↳ `meetingUrl` | string | URL to join the meeting |
|
||||||
|
| ↳ `location` | string | Location of the booking |
|
||||||
|
| ↳ `absentHost` | boolean | Whether the host was absent |
|
||||||
|
| ↳ `guests` | array | Guest email addresses |
|
||||||
|
| ↳ `bookingFieldsResponses` | json | Custom booking field responses \(dynamic keys based on event type configuration\) |
|
||||||
|
| ↳ `metadata` | json | Custom metadata attached to the booking \(dynamic key-value pairs\) |
|
||||||
|
| ↳ `rating` | number | Booking rating |
|
||||||
|
| ↳ `icsUid` | string | ICS calendar UID |
|
||||||
|
| ↳ `cancellationReason` | string | Reason for cancellation if cancelled |
|
||||||
|
| ↳ `cancelledByEmail` | string | Email of person who cancelled the booking |
|
||||||
|
| ↳ `reschedulingReason` | string | Reason for rescheduling if rescheduled |
|
||||||
|
| ↳ `rescheduledByEmail` | string | Email of person who rescheduled the booking |
|
||||||
|
| ↳ `rescheduledFromUid` | string | Original booking UID if this booking was rescheduled |
|
||||||
|
| ↳ `rescheduledToUid` | string | New booking UID after reschedule |
|
||||||
|
| ↳ `createdAt` | string | When the booking was created |
|
||||||
|
| ↳ `updatedAt` | string | When the booking was last updated |
|
||||||
|
| `pagination` | object | Pagination metadata |
|
||||||
|
| ↳ `totalItems` | number | Total number of items |
|
||||||
|
| ↳ `remainingItems` | number | Remaining items after current page |
|
||||||
|
| ↳ `returnedItems` | number | Number of items returned in this response |
|
||||||
|
| ↳ `itemsPerPage` | number | Items per page |
|
||||||
|
| ↳ `currentPage` | number | Current page number |
|
||||||
|
| ↳ `totalPages` | number | Total number of pages |
|
||||||
|
| ↳ `hasNextPage` | boolean | Whether there is a next page |
|
||||||
|
| ↳ `hasPreviousPage` | boolean | Whether there is a previous page |
|
||||||
|
|
||||||
|
### `calcom_cancel_booking`
|
||||||
|
|
||||||
|
Cancel an existing booking
|
||||||
|
|
||||||
|
#### Input
|
||||||
|
|
||||||
|
| Parameter | Type | Required | Description |
|
||||||
|
| --------- | ---- | -------- | ----------- |
|
||||||
|
| `bookingUid` | string | Yes | Unique identifier \(UID\) of the booking to cancel |
|
||||||
|
| `cancellationReason` | string | No | Reason for cancelling the booking |
|
||||||
|
|
||||||
|
#### Output
|
||||||
|
|
||||||
|
| Parameter | Type | Description |
|
||||||
|
| --------- | ---- | ----------- |
|
||||||
|
| `status` | string | Response status |
|
||||||
|
| `data` | object | Cancelled booking details |
|
||||||
|
| ↳ `eventType` | object | Event type details |
|
||||||
|
| ↳ `id` | number | Event type ID |
|
||||||
|
| ↳ `slug` | string | Event type slug |
|
||||||
|
| ↳ `attendees` | array | List of attendees |
|
||||||
|
| ↳ `name` | string | Attendee name |
|
||||||
|
| ↳ `email` | string | Attendee actual email address |
|
||||||
|
| ↳ `displayEmail` | string | Email shown publicly \(may differ from actual email\) |
|
||||||
|
| ↳ `timeZone` | string | Attendee timezone \(IANA format\) |
|
||||||
|
| ↳ `phoneNumber` | string | Attendee phone number |
|
||||||
|
| ↳ `language` | string | Attendee language preference \(ISO code\) |
|
||||||
|
| ↳ `absent` | boolean | Whether attendee was absent |
|
||||||
|
| ↳ `hosts` | array | List of hosts |
|
||||||
|
| ↳ `id` | number | Host user ID |
|
||||||
|
| ↳ `name` | string | Host display name |
|
||||||
|
| ↳ `email` | string | Host actual email address |
|
||||||
|
| ↳ `displayEmail` | string | Email shown publicly \(may differ from actual email\) |
|
||||||
|
| ↳ `username` | string | Host Cal.com username |
|
||||||
|
| ↳ `timeZone` | string | Host timezone \(IANA format\) |
|
||||||
|
| ↳ `id` | number | Numeric booking ID |
|
||||||
|
| ↳ `uid` | string | Unique identifier for the booking |
|
||||||
|
| ↳ `title` | string | Title of the booking |
|
||||||
|
| ↳ `cancellationReason` | string | Reason for cancellation if cancelled |
|
||||||
|
| ↳ `cancelledByEmail` | string | Email of person who cancelled the booking |
|
||||||
|
| ↳ `start` | string | Start time in ISO 8601 format |
|
||||||
|
| ↳ `end` | string | End time in ISO 8601 format |
|
||||||
|
| ↳ `duration` | number | Duration in minutes |
|
||||||
|
| ↳ `eventTypeId` | number | Event type ID |
|
||||||
|
| ↳ `location` | string | Location of the booking |
|
||||||
|
| ↳ `metadata` | json | Custom metadata attached to the booking \(dynamic key-value pairs\) |
|
||||||
|
| ↳ `createdAt` | string | When the booking was created |
|
||||||
|
| ↳ `status` | string | Booking status \(should be cancelled\) |
|
||||||
|
|
||||||
|
### `calcom_reschedule_booking`
|
||||||
|
|
||||||
|
Reschedule an existing booking to a new time
|
||||||
|
|
||||||
|
#### Input
|
||||||
|
|
||||||
|
| Parameter | Type | Required | Description |
|
||||||
|
| --------- | ---- | -------- | ----------- |
|
||||||
|
| `bookingUid` | string | Yes | Unique identifier \(UID\) of the booking to reschedule |
|
||||||
|
| `start` | string | Yes | New start time in UTC ISO 8601 format \(e.g., 2024-01-15T09:00:00Z\) |
|
||||||
|
| `reschedulingReason` | string | No | Reason for rescheduling the booking |
|
||||||
|
|
||||||
|
#### Output
|
||||||
|
|
||||||
|
| Parameter | Type | Description |
|
||||||
|
| --------- | ---- | ----------- |
|
||||||
|
| `status` | string | Response status |
|
||||||
|
| `data` | object | Rescheduled booking details |
|
||||||
|
| ↳ `eventType` | object | Event type details |
|
||||||
|
| ↳ `id` | number | Event type ID |
|
||||||
|
| ↳ `slug` | string | Event type slug |
|
||||||
|
| ↳ `attendees` | array | List of attendees |
|
||||||
|
| ↳ `name` | string | Attendee name |
|
||||||
|
| ↳ `email` | string | Attendee actual email address |
|
||||||
|
| ↳ `displayEmail` | string | Email shown publicly \(may differ from actual email\) |
|
||||||
|
| ↳ `timeZone` | string | Attendee timezone \(IANA format\) |
|
||||||
|
| ↳ `phoneNumber` | string | Attendee phone number |
|
||||||
|
| ↳ `language` | string | Attendee language preference \(ISO code\) |
|
||||||
|
| ↳ `absent` | boolean | Whether attendee was absent |
|
||||||
|
| ↳ `hosts` | array | List of hosts |
|
||||||
|
| ↳ `id` | number | Host user ID |
|
||||||
|
| ↳ `name` | string | Host display name |
|
||||||
|
| ↳ `email` | string | Host actual email address |
|
||||||
|
| ↳ `displayEmail` | string | Email shown publicly \(may differ from actual email\) |
|
||||||
|
| ↳ `username` | string | Host Cal.com username |
|
||||||
|
| ↳ `timeZone` | string | Host timezone \(IANA format\) |
|
||||||
|
| ↳ `id` | number | Numeric booking ID |
|
||||||
|
| ↳ `title` | string | Title of the booking |
|
||||||
|
| ↳ `status` | string | Booking status \(e.g., accepted, pending, cancelled\) |
|
||||||
|
| ↳ `reschedulingReason` | string | Reason for rescheduling if rescheduled |
|
||||||
|
| ↳ `rescheduledFromUid` | string | Original booking UID if this booking was rescheduled |
|
||||||
|
| ↳ `rescheduledByEmail` | string | Email of person who rescheduled the booking |
|
||||||
|
| ↳ `duration` | number | Duration in minutes |
|
||||||
|
| ↳ `eventTypeId` | number | Event type ID |
|
||||||
|
| ↳ `meetingUrl` | string | URL to join the meeting |
|
||||||
|
| ↳ `location` | string | Location of the booking |
|
||||||
|
| ↳ `guests` | array | Guest email addresses |
|
||||||
|
| ↳ `metadata` | json | Custom metadata attached to the booking \(dynamic key-value pairs\) |
|
||||||
|
| ↳ `icsUid` | string | ICS calendar UID |
|
||||||
|
| ↳ `createdAt` | string | When the booking was created |
|
||||||
|
| ↳ `uid` | string | Unique identifier for the new booking |
|
||||||
|
| ↳ `start` | string | New start time in ISO 8601 format |
|
||||||
|
| ↳ `end` | string | New end time in ISO 8601 format |
|
||||||
|
|
||||||
|
### `calcom_confirm_booking`
|
||||||
|
|
||||||
|
Confirm a pending booking that requires confirmation
|
||||||
|
|
||||||
|
#### Input
|
||||||
|
|
||||||
|
| Parameter | Type | Required | Description |
|
||||||
|
| --------- | ---- | -------- | ----------- |
|
||||||
|
| `bookingUid` | string | Yes | Unique identifier \(UID\) of the booking to confirm |
|
||||||
|
|
||||||
|
#### Output
|
||||||
|
|
||||||
|
| Parameter | Type | Description |
|
||||||
|
| --------- | ---- | ----------- |
|
||||||
|
| `status` | string | Response status |
|
||||||
|
| `data` | object | Confirmed booking details |
|
||||||
|
| ↳ `eventType` | object | Event type details |
|
||||||
|
| ↳ `id` | number | Event type ID |
|
||||||
|
| ↳ `slug` | string | Event type slug |
|
||||||
|
| ↳ `attendees` | array | List of attendees |
|
||||||
|
| ↳ `name` | string | Attendee name |
|
||||||
|
| ↳ `email` | string | Attendee actual email address |
|
||||||
|
| ↳ `displayEmail` | string | Email shown publicly \(may differ from actual email\) |
|
||||||
|
| ↳ `timeZone` | string | Attendee timezone \(IANA format\) |
|
||||||
|
| ↳ `phoneNumber` | string | Attendee phone number |
|
||||||
|
| ↳ `language` | string | Attendee language preference \(ISO code\) |
|
||||||
|
| ↳ `absent` | boolean | Whether attendee was absent |
|
||||||
|
| ↳ `hosts` | array | List of hosts |
|
||||||
|
| ↳ `id` | number | Host user ID |
|
||||||
|
| ↳ `name` | string | Host display name |
|
||||||
|
| ↳ `email` | string | Host actual email address |
|
||||||
|
| ↳ `displayEmail` | string | Email shown publicly \(may differ from actual email\) |
|
||||||
|
| ↳ `username` | string | Host Cal.com username |
|
||||||
|
| ↳ `timeZone` | string | Host timezone \(IANA format\) |
|
||||||
|
| ↳ `id` | number | Numeric booking ID |
|
||||||
|
| ↳ `uid` | string | Unique identifier for the booking |
|
||||||
|
| ↳ `title` | string | Title of the booking |
|
||||||
|
| ↳ `start` | string | Start time in ISO 8601 format |
|
||||||
|
| ↳ `end` | string | End time in ISO 8601 format |
|
||||||
|
| ↳ `duration` | number | Duration in minutes |
|
||||||
|
| ↳ `eventTypeId` | number | Event type ID |
|
||||||
|
| ↳ `meetingUrl` | string | URL to join the meeting |
|
||||||
|
| ↳ `location` | string | Location of the booking |
|
||||||
|
| ↳ `guests` | array | Guest email addresses |
|
||||||
|
| ↳ `metadata` | json | Custom metadata attached to the booking \(dynamic key-value pairs\) |
|
||||||
|
| ↳ `icsUid` | string | ICS calendar UID |
|
||||||
|
| ↳ `createdAt` | string | When the booking was created |
|
||||||
|
| ↳ `status` | string | Booking status \(should be accepted/confirmed\) |
|
||||||
|
|
||||||
|
### `calcom_decline_booking`
|
||||||
|
|
||||||
|
Decline a pending booking request
|
||||||
|
|
||||||
|
#### Input
|
||||||
|
|
||||||
|
| Parameter | Type | Required | Description |
|
||||||
|
| --------- | ---- | -------- | ----------- |
|
||||||
|
| `bookingUid` | string | Yes | Unique identifier \(UID\) of the booking to decline |
|
||||||
|
| `reason` | string | No | Reason for declining the booking |
|
||||||
|
|
||||||
|
#### Output
|
||||||
|
|
||||||
|
| Parameter | Type | Description |
|
||||||
|
| --------- | ---- | ----------- |
|
||||||
|
| `status` | string | Response status |
|
||||||
|
| `data` | object | Declined booking details |
|
||||||
|
| ↳ `eventType` | object | Event type details |
|
||||||
|
| ↳ `id` | number | Event type ID |
|
||||||
|
| ↳ `slug` | string | Event type slug |
|
||||||
|
| ↳ `attendees` | array | List of attendees |
|
||||||
|
| ↳ `name` | string | Attendee name |
|
||||||
|
| ↳ `email` | string | Attendee actual email address |
|
||||||
|
| ↳ `displayEmail` | string | Email shown publicly \(may differ from actual email\) |
|
||||||
|
| ↳ `timeZone` | string | Attendee timezone \(IANA format\) |
|
||||||
|
| ↳ `phoneNumber` | string | Attendee phone number |
|
||||||
|
| ↳ `language` | string | Attendee language preference \(ISO code\) |
|
||||||
|
| ↳ `absent` | boolean | Whether attendee was absent |
|
||||||
|
| ↳ `hosts` | array | List of hosts |
|
||||||
|
| ↳ `id` | number | Host user ID |
|
||||||
|
| ↳ `name` | string | Host display name |
|
||||||
|
| ↳ `email` | string | Host actual email address |
|
||||||
|
| ↳ `displayEmail` | string | Email shown publicly \(may differ from actual email\) |
|
||||||
|
| ↳ `username` | string | Host Cal.com username |
|
||||||
|
| ↳ `timeZone` | string | Host timezone \(IANA format\) |
|
||||||
|
| ↳ `id` | number | Numeric booking ID |
|
||||||
|
| ↳ `uid` | string | Unique identifier for the booking |
|
||||||
|
| ↳ `title` | string | Title of the booking |
|
||||||
|
| ↳ `cancellationReason` | string | Reason for cancellation if cancelled |
|
||||||
|
| ↳ `start` | string | Start time in ISO 8601 format |
|
||||||
|
| ↳ `end` | string | End time in ISO 8601 format |
|
||||||
|
| ↳ `duration` | number | Duration in minutes |
|
||||||
|
| ↳ `eventTypeId` | number | Event type ID |
|
||||||
|
| ↳ `location` | string | Location of the booking |
|
||||||
|
| ↳ `metadata` | json | Custom metadata attached to the booking \(dynamic key-value pairs\) |
|
||||||
|
| ↳ `createdAt` | string | When the booking was created |
|
||||||
|
| ↳ `status` | string | Booking status \(should be cancelled/rejected\) |
|
||||||
|
|
||||||
|
### `calcom_create_event_type`
|
||||||
|
|
||||||
|
Create a new event type in Cal.com
|
||||||
|
|
||||||
|
#### Input
|
||||||
|
|
||||||
|
| Parameter | Type | Required | Description |
|
||||||
|
| --------- | ---- | -------- | ----------- |
|
||||||
|
| `title` | string | Yes | Title of the event type |
|
||||||
|
| `slug` | string | Yes | Unique slug for the event type URL |
|
||||||
|
| `lengthInMinutes` | number | Yes | Duration of the event in minutes |
|
||||||
|
| `description` | string | No | Description of the event type |
|
||||||
|
| `slotInterval` | number | No | Interval between available booking slots in minutes |
|
||||||
|
| `minimumBookingNotice` | number | No | Minimum notice required before booking in minutes |
|
||||||
|
| `beforeEventBuffer` | number | No | Buffer time before the event in minutes |
|
||||||
|
| `afterEventBuffer` | number | No | Buffer time after the event in minutes |
|
||||||
|
| `scheduleId` | number | No | ID of the schedule to use for availability |
|
||||||
|
| `disableGuests` | boolean | No | Whether to disable guests from being added to bookings |
|
||||||
|
|
||||||
|
#### Output
|
||||||
|
|
||||||
|
| Parameter | Type | Description |
|
||||||
|
| --------- | ---- | ----------- |
|
||||||
|
| `status` | string | Response status |
|
||||||
|
| `data` | object | Created event type details |
|
||||||
|
| ↳ `id` | number | Event type ID |
|
||||||
|
| ↳ `title` | string | Event type title |
|
||||||
|
| ↳ `slug` | string | Event type slug |
|
||||||
|
| ↳ `description` | string | Event type description |
|
||||||
|
| ↳ `lengthInMinutes` | number | Duration in minutes |
|
||||||
|
| ↳ `slotInterval` | number | Slot interval in minutes |
|
||||||
|
| ↳ `minimumBookingNotice` | number | Minimum booking notice in minutes |
|
||||||
|
| ↳ `beforeEventBuffer` | number | Buffer before event in minutes |
|
||||||
|
| ↳ `afterEventBuffer` | number | Buffer after event in minutes |
|
||||||
|
| ↳ `scheduleId` | number | Schedule ID |
|
||||||
|
| ↳ `disableGuests` | boolean | Whether guests are disabled |
|
||||||
|
| ↳ `createdAt` | string | ISO timestamp of creation |
|
||||||
|
| ↳ `updatedAt` | string | ISO timestamp of last update |
|
||||||
|
|
||||||
|
### `calcom_get_event_type`
|
||||||
|
|
||||||
|
Get detailed information about a specific event type
|
||||||
|
|
||||||
|
#### Input
|
||||||
|
|
||||||
|
| Parameter | Type | Required | Description |
|
||||||
|
| --------- | ---- | -------- | ----------- |
|
||||||
|
| `eventTypeId` | number | Yes | Event type ID to retrieve |
|
||||||
|
|
||||||
|
#### Output
|
||||||
|
|
||||||
|
| Parameter | Type | Description |
|
||||||
|
| --------- | ---- | ----------- |
|
||||||
|
| `status` | string | Response status |
|
||||||
|
| `data` | object | Event type details |
|
||||||
|
| ↳ `id` | number | Event type ID |
|
||||||
|
| ↳ `title` | string | Event type title |
|
||||||
|
| ↳ `slug` | string | Event type slug |
|
||||||
|
| ↳ `description` | string | Event type description |
|
||||||
|
| ↳ `lengthInMinutes` | number | Duration in minutes |
|
||||||
|
| ↳ `slotInterval` | number | Slot interval in minutes |
|
||||||
|
| ↳ `minimumBookingNotice` | number | Minimum booking notice in minutes |
|
||||||
|
| ↳ `beforeEventBuffer` | number | Buffer before event in minutes |
|
||||||
|
| ↳ `afterEventBuffer` | number | Buffer after event in minutes |
|
||||||
|
| ↳ `scheduleId` | number | Schedule ID |
|
||||||
|
| ↳ `disableGuests` | boolean | Whether guests are disabled |
|
||||||
|
| ↳ `createdAt` | string | ISO timestamp of creation |
|
||||||
|
| ↳ `updatedAt` | string | ISO timestamp of last update |
|
||||||
|
|
||||||
|
### `calcom_list_event_types`
|
||||||
|
|
||||||
|
Retrieve a list of all event types
|
||||||
|
|
||||||
|
#### Input
|
||||||
|
|
||||||
|
| Parameter | Type | Required | Description |
|
||||||
|
| --------- | ---- | -------- | ----------- |
|
||||||
|
| `sortCreatedAt` | string | No | Sort by creation date: "asc" or "desc" |
|
||||||
|
|
||||||
|
#### Output
|
||||||
|
|
||||||
|
| Parameter | Type | Description |
|
||||||
|
| --------- | ---- | ----------- |
|
||||||
|
| `status` | string | Response status |
|
||||||
|
| `data` | array | Array of event types |
|
||||||
|
| ↳ `id` | number | Event type ID |
|
||||||
|
| ↳ `title` | string | Event type title |
|
||||||
|
| ↳ `slug` | string | Event type slug |
|
||||||
|
| ↳ `description` | string | Event type description |
|
||||||
|
| ↳ `lengthInMinutes` | number | Duration in minutes |
|
||||||
|
| ↳ `slotInterval` | number | Slot interval in minutes |
|
||||||
|
| ↳ `minimumBookingNotice` | number | Minimum booking notice in minutes |
|
||||||
|
| ↳ `beforeEventBuffer` | number | Buffer before event in minutes |
|
||||||
|
| ↳ `afterEventBuffer` | number | Buffer after event in minutes |
|
||||||
|
| ↳ `scheduleId` | number | Schedule ID |
|
||||||
|
| ↳ `disableGuests` | boolean | Whether guests are disabled |
|
||||||
|
| ↳ `createdAt` | string | ISO timestamp of creation |
|
||||||
|
| ↳ `updatedAt` | string | ISO timestamp of last update |
|
||||||
|
|
||||||
|
### `calcom_update_event_type`
|
||||||
|
|
||||||
|
Update an existing event type in Cal.com
|
||||||
|
|
||||||
|
#### Input
|
||||||
|
|
||||||
|
| Parameter | Type | Required | Description |
|
||||||
|
| --------- | ---- | -------- | ----------- |
|
||||||
|
| `eventTypeId` | number | Yes | Event type ID to update |
|
||||||
|
| `title` | string | No | Title of the event type |
|
||||||
|
| `slug` | string | No | Unique slug for the event type URL |
|
||||||
|
| `lengthInMinutes` | number | No | Duration of the event in minutes |
|
||||||
|
| `description` | string | No | Description of the event type |
|
||||||
|
| `slotInterval` | number | No | Interval between available booking slots in minutes |
|
||||||
|
| `minimumBookingNotice` | number | No | Minimum notice required before booking in minutes |
|
||||||
|
| `beforeEventBuffer` | number | No | Buffer time before the event in minutes |
|
||||||
|
| `afterEventBuffer` | number | No | Buffer time after the event in minutes |
|
||||||
|
| `scheduleId` | number | No | ID of the schedule to use for availability |
|
||||||
|
| `disableGuests` | boolean | No | Whether to disable guests from being added to bookings |
|
||||||
|
|
||||||
|
#### Output
|
||||||
|
|
||||||
|
| Parameter | Type | Description |
|
||||||
|
| --------- | ---- | ----------- |
|
||||||
|
| `status` | string | Response status |
|
||||||
|
| `data` | object | Updated event type details |
|
||||||
|
| ↳ `id` | number | Event type ID |
|
||||||
|
| ↳ `title` | string | Event type title |
|
||||||
|
| ↳ `slug` | string | Event type slug |
|
||||||
|
| ↳ `description` | string | Event type description |
|
||||||
|
| ↳ `lengthInMinutes` | number | Duration in minutes |
|
||||||
|
| ↳ `slotInterval` | number | Slot interval in minutes |
|
||||||
|
| ↳ `minimumBookingNotice` | number | Minimum booking notice in minutes |
|
||||||
|
| ↳ `beforeEventBuffer` | number | Buffer before event in minutes |
|
||||||
|
| ↳ `afterEventBuffer` | number | Buffer after event in minutes |
|
||||||
|
| ↳ `scheduleId` | number | Schedule ID |
|
||||||
|
| ↳ `disableGuests` | boolean | Whether guests are disabled |
|
||||||
|
| ↳ `createdAt` | string | ISO timestamp of creation |
|
||||||
|
| ↳ `updatedAt` | string | ISO timestamp of last update |
|
||||||
|
|
||||||
|
### `calcom_delete_event_type`
|
||||||
|
|
||||||
|
Delete an event type from Cal.com
|
||||||
|
|
||||||
|
#### Input
|
||||||
|
|
||||||
|
| Parameter | Type | Required | Description |
|
||||||
|
| --------- | ---- | -------- | ----------- |
|
||||||
|
| `eventTypeId` | number | Yes | Event type ID to delete |
|
||||||
|
|
||||||
|
#### Output
|
||||||
|
|
||||||
|
| Parameter | Type | Description |
|
||||||
|
| --------- | ---- | ----------- |
|
||||||
|
| `status` | string | Response status |
|
||||||
|
| `data` | object | Deleted event type details |
|
||||||
|
| ↳ `id` | number | Event type ID |
|
||||||
|
| ↳ `lengthInMinutes` | number | Duration in minutes |
|
||||||
|
| ↳ `title` | string | Event type title |
|
||||||
|
| ↳ `slug` | string | Event type slug |
|
||||||
|
|
||||||
|
### `calcom_create_schedule`
|
||||||
|
|
||||||
|
Create a new availability schedule in Cal.com
|
||||||
|
|
||||||
|
#### Input
|
||||||
|
|
||||||
|
| Parameter | Type | Required | Description |
|
||||||
|
| --------- | ---- | -------- | ----------- |
|
||||||
|
| `name` | string | Yes | Name of the schedule |
|
||||||
|
| `timeZone` | string | Yes | Timezone for the schedule \(e.g., America/New_York\) |
|
||||||
|
| `isDefault` | boolean | Yes | Whether this schedule should be the default |
|
||||||
|
| `availability` | array | No | Availability intervals for the schedule |
|
||||||
|
| `items` | object | No | Availability interval |
|
||||||
|
| `properties` | array | No | Days of the week \(Monday, Tuesday, Wednesday, Thursday, Friday, Saturday, Sunday\) |
|
||||||
|
| `days` | array | No | Days of the week \(Monday, Tuesday, Wednesday, Thursday, Friday, Saturday, Sunday\) |
|
||||||
|
| `startTime` | string | No | Start time in HH:MM format |
|
||||||
|
| `endTime` | string | No | End time in HH:MM format |
|
||||||
|
|
||||||
|
#### Output
|
||||||
|
|
||||||
|
| Parameter | Type | Description |
|
||||||
|
| --------- | ---- | ----------- |
|
||||||
|
| `status` | string | Response status |
|
||||||
|
| `data` | object | Created schedule data |
|
||||||
|
| ↳ `id` | number | Schedule ID |
|
||||||
|
| ↳ `ownerId` | number | Owner user ID |
|
||||||
|
| ↳ `name` | string | Schedule name |
|
||||||
|
| ↳ `timeZone` | string | Timezone \(e.g., America/New_York\) |
|
||||||
|
| ↳ `isDefault` | boolean | Whether this is the default schedule |
|
||||||
|
| ↳ `availability` | array | Availability windows |
|
||||||
|
| ↳ `days` | array | Days of the week \(Monday, Tuesday, etc.\) |
|
||||||
|
| ↳ `startTime` | string | Start time in HH:MM format |
|
||||||
|
| ↳ `endTime` | string | End time in HH:MM format |
|
||||||
|
| ↳ `overrides` | array | Date-specific availability overrides |
|
||||||
|
| ↳ `date` | string | Date in YYYY-MM-DD format |
|
||||||
|
| ↳ `startTime` | string | Start time in HH:MM format |
|
||||||
|
| ↳ `endTime` | string | End time in HH:MM format |
|
||||||
|
|
||||||
|
### `calcom_get_schedule`
|
||||||
|
|
||||||
|
Get a specific schedule by ID from Cal.com
|
||||||
|
|
||||||
|
#### Input
|
||||||
|
|
||||||
|
| Parameter | Type | Required | Description |
|
||||||
|
| --------- | ---- | -------- | ----------- |
|
||||||
|
| `scheduleId` | string | Yes | ID of the schedule to retrieve |
|
||||||
|
|
||||||
|
#### Output
|
||||||
|
|
||||||
|
| Parameter | Type | Description |
|
||||||
|
| --------- | ---- | ----------- |
|
||||||
|
| `status` | string | Response status |
|
||||||
|
| `data` | object | Schedule data |
|
||||||
|
| ↳ `id` | number | Schedule ID |
|
||||||
|
| ↳ `ownerId` | number | Owner user ID |
|
||||||
|
| ↳ `name` | string | Schedule name |
|
||||||
|
| ↳ `timeZone` | string | Timezone \(e.g., America/New_York\) |
|
||||||
|
| ↳ `isDefault` | boolean | Whether this is the default schedule |
|
||||||
|
| ↳ `availability` | array | Availability windows |
|
||||||
|
| ↳ `days` | array | Days of the week \(Monday, Tuesday, etc.\) |
|
||||||
|
| ↳ `startTime` | string | Start time in HH:MM format |
|
||||||
|
| ↳ `endTime` | string | End time in HH:MM format |
|
||||||
|
| ↳ `overrides` | array | Date-specific availability overrides |
|
||||||
|
| ↳ `date` | string | Date in YYYY-MM-DD format |
|
||||||
|
| ↳ `startTime` | string | Start time in HH:MM format |
|
||||||
|
| ↳ `endTime` | string | End time in HH:MM format |
|
||||||
|
|
||||||
|
### `calcom_list_schedules`
|
||||||
|
|
||||||
|
List all availability schedules from Cal.com
|
||||||
|
|
||||||
|
#### Input
|
||||||
|
|
||||||
|
| Parameter | Type | Required | Description |
|
||||||
|
| --------- | ---- | -------- | ----------- |
|
||||||
|
|
||||||
|
#### Output
|
||||||
|
|
||||||
|
| Parameter | Type | Description |
|
||||||
|
| --------- | ---- | ----------- |
|
||||||
|
| `status` | string | Response status |
|
||||||
|
| `data` | array | Array of schedule objects |
|
||||||
|
| ↳ `id` | number | Schedule ID |
|
||||||
|
| ↳ `ownerId` | number | Owner user ID |
|
||||||
|
| ↳ `name` | string | Schedule name |
|
||||||
|
| ↳ `timeZone` | string | Timezone \(e.g., America/New_York\) |
|
||||||
|
| ↳ `isDefault` | boolean | Whether this is the default schedule |
|
||||||
|
| ↳ `availability` | array | Availability windows |
|
||||||
|
| ↳ `days` | array | Days of the week \(Monday, Tuesday, etc.\) |
|
||||||
|
| ↳ `startTime` | string | Start time in HH:MM format |
|
||||||
|
| ↳ `endTime` | string | End time in HH:MM format |
|
||||||
|
| ↳ `overrides` | array | Date-specific availability overrides |
|
||||||
|
| ↳ `date` | string | Date in YYYY-MM-DD format |
|
||||||
|
| ↳ `startTime` | string | Start time in HH:MM format |
|
||||||
|
| ↳ `endTime` | string | End time in HH:MM format |
|
||||||
|
|
||||||
|
### `calcom_update_schedule`
|
||||||
|
|
||||||
|
Update an existing schedule in Cal.com
|
||||||
|
|
||||||
|
#### Input
|
||||||
|
|
||||||
|
| Parameter | Type | Required | Description |
|
||||||
|
| --------- | ---- | -------- | ----------- |
|
||||||
|
| `scheduleId` | string | Yes | ID of the schedule to update |
|
||||||
|
| `name` | string | No | New name for the schedule |
|
||||||
|
| `timeZone` | string | No | New timezone for the schedule \(e.g., America/New_York\) |
|
||||||
|
| `isDefault` | boolean | No | Whether this schedule should be the default |
|
||||||
|
| `availability` | array | No | New availability intervals for the schedule |
|
||||||
|
| `items` | object | No | Availability interval |
|
||||||
|
| `properties` | array | No | Days of the week \(Monday, Tuesday, Wednesday, Thursday, Friday, Saturday, Sunday\) |
|
||||||
|
| `days` | array | No | Days of the week \(Monday, Tuesday, Wednesday, Thursday, Friday, Saturday, Sunday\) |
|
||||||
|
| `startTime` | string | No | Start time in HH:MM format |
|
||||||
|
| `endTime` | string | No | End time in HH:MM format |
|
||||||
|
|
||||||
|
#### Output
|
||||||
|
|
||||||
|
| Parameter | Type | Description |
|
||||||
|
| --------- | ---- | ----------- |
|
||||||
|
| `status` | string | Response status |
|
||||||
|
| `data` | object | Updated schedule data |
|
||||||
|
| ↳ `id` | number | Schedule ID |
|
||||||
|
| ↳ `ownerId` | number | Owner user ID |
|
||||||
|
| ↳ `name` | string | Schedule name |
|
||||||
|
| ↳ `timeZone` | string | Timezone \(e.g., America/New_York\) |
|
||||||
|
| ↳ `isDefault` | boolean | Whether this is the default schedule |
|
||||||
|
| ↳ `availability` | array | Availability windows |
|
||||||
|
| ↳ `days` | array | Days of the week \(Monday, Tuesday, etc.\) |
|
||||||
|
| ↳ `startTime` | string | Start time in HH:MM format |
|
||||||
|
| ↳ `endTime` | string | End time in HH:MM format |
|
||||||
|
| ↳ `overrides` | array | Date-specific availability overrides |
|
||||||
|
| ↳ `date` | string | Date in YYYY-MM-DD format |
|
||||||
|
| ↳ `startTime` | string | Start time in HH:MM format |
|
||||||
|
| ↳ `endTime` | string | End time in HH:MM format |
|
||||||
|
|
||||||
|
### `calcom_delete_schedule`
|
||||||
|
|
||||||
|
Delete a schedule from Cal.com
|
||||||
|
|
||||||
|
#### Input
|
||||||
|
|
||||||
|
| Parameter | Type | Required | Description |
|
||||||
|
| --------- | ---- | -------- | ----------- |
|
||||||
|
| `scheduleId` | string | Yes | ID of the schedule to delete |
|
||||||
|
|
||||||
|
#### Output
|
||||||
|
|
||||||
|
| Parameter | Type | Description |
|
||||||
|
| --------- | ---- | ----------- |
|
||||||
|
| `status` | string | Response status \(success or error\) |
|
||||||
|
|
||||||
|
### `calcom_get_default_schedule`
|
||||||
|
|
||||||
|
Get the default availability schedule from Cal.com
|
||||||
|
|
||||||
|
#### Input
|
||||||
|
|
||||||
|
| Parameter | Type | Required | Description |
|
||||||
|
| --------- | ---- | -------- | ----------- |
|
||||||
|
|
||||||
|
#### Output
|
||||||
|
|
||||||
|
| Parameter | Type | Description |
|
||||||
|
| --------- | ---- | ----------- |
|
||||||
|
| `status` | string | Response status |
|
||||||
|
| `data` | object | Default schedule data |
|
||||||
|
| ↳ `id` | number | Schedule ID |
|
||||||
|
| ↳ `ownerId` | number | Owner user ID |
|
||||||
|
| ↳ `name` | string | Schedule name |
|
||||||
|
| ↳ `timeZone` | string | Timezone \(e.g., America/New_York\) |
|
||||||
|
| ↳ `isDefault` | boolean | Whether this is the default schedule |
|
||||||
|
| ↳ `availability` | array | Availability windows |
|
||||||
|
| ↳ `days` | array | Days of the week \(Monday, Tuesday, etc.\) |
|
||||||
|
| ↳ `startTime` | string | Start time in HH:MM format |
|
||||||
|
| ↳ `endTime` | string | End time in HH:MM format |
|
||||||
|
| ↳ `overrides` | array | Date-specific availability overrides |
|
||||||
|
| ↳ `date` | string | Date in YYYY-MM-DD format |
|
||||||
|
| ↳ `startTime` | string | Start time in HH:MM format |
|
||||||
|
| ↳ `endTime` | string | End time in HH:MM format |
|
||||||
|
|
||||||
|
### `calcom_get_slots`
|
||||||
|
|
||||||
|
Get available booking slots for a Cal.com event type within a time range
|
||||||
|
|
||||||
|
#### Input
|
||||||
|
|
||||||
|
| Parameter | Type | Required | Description |
|
||||||
|
| --------- | ---- | -------- | ----------- |
|
||||||
|
| `start` | string | Yes | Start of time range in UTC ISO 8601 format \(e.g., 2024-01-15T00:00:00Z\) |
|
||||||
|
| `end` | string | Yes | End of time range in UTC ISO 8601 format \(e.g., 2024-01-22T00:00:00Z\) |
|
||||||
|
| `eventTypeId` | number | No | Event type ID for direct lookup |
|
||||||
|
| `eventTypeSlug` | string | No | Event type slug \(requires username to be set\) |
|
||||||
|
| `username` | string | No | Username for personal event types \(required when using eventTypeSlug\) |
|
||||||
|
| `timeZone` | string | No | Timezone for returned slots \(defaults to UTC\) |
|
||||||
|
| `duration` | number | No | Slot length in minutes |
|
||||||
|
|
||||||
|
#### Output
|
||||||
|
|
||||||
|
| Parameter | Type | Description |
|
||||||
|
| --------- | ---- | ----------- |
|
||||||
|
| `status` | string | Response status |
|
||||||
|
| `data` | json | Available time slots grouped by date \(YYYY-MM-DD keys\). Each date maps to an array of slot objects with start time, optional end time, and seated event info. |
|
||||||
|
|
||||||
|
|
||||||
@@ -51,7 +51,7 @@ Get information about the currently authenticated Calendly user
|
|||||||
| ↳ `name` | string | User full name |
|
| ↳ `name` | string | User full name |
|
||||||
| ↳ `slug` | string | Unique identifier for the user in URLs |
|
| ↳ `slug` | string | Unique identifier for the user in URLs |
|
||||||
| ↳ `email` | string | User email address |
|
| ↳ `email` | string | User email address |
|
||||||
| ↳ `scheduling_url` | string | URL to the user |
|
| ↳ `scheduling_url` | string | URL to the user's scheduling page |
|
||||||
| ↳ `timezone` | string | User timezone |
|
| ↳ `timezone` | string | User timezone |
|
||||||
| ↳ `avatar_url` | string | URL to user avatar image |
|
| ↳ `avatar_url` | string | URL to user avatar image |
|
||||||
| ↳ `created_at` | string | ISO timestamp when user was created |
|
| ↳ `created_at` | string | ISO timestamp when user was created |
|
||||||
@@ -82,7 +82,7 @@ Retrieve a list of all event types for a user or organization
|
|||||||
| ↳ `uri` | string | Canonical reference to the event type |
|
| ↳ `uri` | string | Canonical reference to the event type |
|
||||||
| ↳ `name` | string | Event type name |
|
| ↳ `name` | string | Event type name |
|
||||||
| ↳ `active` | boolean | Whether the event type is active |
|
| ↳ `active` | boolean | Whether the event type is active |
|
||||||
| ↳ `booking_method` | string | Booking method \(e.g., |
|
| ↳ `booking_method` | string | Booking method \(e.g., "round_robin_or_collect", "collective"\) |
|
||||||
| ↳ `color` | string | Hex color code |
|
| ↳ `color` | string | Hex color code |
|
||||||
| ↳ `created_at` | string | ISO timestamp of creation |
|
| ↳ `created_at` | string | ISO timestamp of creation |
|
||||||
| ↳ `description_html` | string | HTML formatted description |
|
| ↳ `description_html` | string | HTML formatted description |
|
||||||
@@ -167,7 +167,7 @@ Retrieve a list of scheduled events for a user or organization
|
|||||||
| ↳ `end_time` | string | ISO timestamp of event end |
|
| ↳ `end_time` | string | ISO timestamp of event end |
|
||||||
| ↳ `event_type` | string | URI of the event type |
|
| ↳ `event_type` | string | URI of the event type |
|
||||||
| ↳ `location` | object | Event location details |
|
| ↳ `location` | object | Event location details |
|
||||||
| ↳ `type` | string | Location type \(e.g., |
|
| ↳ `type` | string | Location type \(e.g., "zoom", "google_meet", "physical"\) |
|
||||||
| ↳ `location` | string | Location description |
|
| ↳ `location` | string | Location description |
|
||||||
| ↳ `join_url` | string | URL to join online meeting \(if applicable\) |
|
| ↳ `join_url` | string | URL to join online meeting \(if applicable\) |
|
||||||
| ↳ `invitees_counter` | object | Invitee count information |
|
| ↳ `invitees_counter` | object | Invitee count information |
|
||||||
|
|||||||
@@ -140,7 +140,20 @@ Search for content across Confluence pages, blog posts, and other content.
|
|||||||
| Parameter | Type | Description |
|
| Parameter | Type | Description |
|
||||||
| --------- | ---- | ----------- |
|
| --------- | ---- | ----------- |
|
||||||
| `ts` | string | Timestamp of search |
|
| `ts` | string | Timestamp of search |
|
||||||
| `results` | array | Search results |
|
| `results` | array | Array of search results |
|
||||||
|
| ↳ `id` | string | Unique content identifier |
|
||||||
|
| ↳ `title` | string | Content title |
|
||||||
|
| ↳ `type` | string | Content type \(e.g., page, blogpost, attachment, comment\) |
|
||||||
|
| ↳ `status` | string | Content status \(e.g., current\) |
|
||||||
|
| ↳ `url` | string | URL to view the content in Confluence |
|
||||||
|
| ↳ `excerpt` | string | Text excerpt matching the search query |
|
||||||
|
| ↳ `spaceKey` | string | Key of the space containing the content |
|
||||||
|
| ↳ `space` | object | Space information for the content |
|
||||||
|
| ↳ `id` | string | Space identifier |
|
||||||
|
| ↳ `key` | string | Space key |
|
||||||
|
| ↳ `name` | string | Space name |
|
||||||
|
| ↳ `lastModified` | string | ISO 8601 timestamp of last modification |
|
||||||
|
| ↳ `entityType` | string | Entity type identifier \(e.g., content, space\) |
|
||||||
|
|
||||||
### `confluence_create_comment`
|
### `confluence_create_comment`
|
||||||
|
|
||||||
@@ -180,8 +193,25 @@ List all comments on a Confluence page.
|
|||||||
|
|
||||||
| Parameter | Type | Description |
|
| Parameter | Type | Description |
|
||||||
| --------- | ---- | ----------- |
|
| --------- | ---- | ----------- |
|
||||||
| `ts` | string | Timestamp of retrieval |
|
| `ts` | string | ISO 8601 timestamp of the operation |
|
||||||
| `comments` | array | List of comments |
|
| `comments` | array | Array of Confluence comments |
|
||||||
|
| ↳ `id` | string | Unique comment identifier |
|
||||||
|
| ↳ `status` | string | Comment status \(e.g., current\) |
|
||||||
|
| ↳ `title` | string | Comment title |
|
||||||
|
| ↳ `pageId` | string | ID of the page the comment belongs to |
|
||||||
|
| ↳ `blogPostId` | string | ID of the blog post the comment belongs to |
|
||||||
|
| ↳ `parentCommentId` | string | ID of the parent comment |
|
||||||
|
| ↳ `body` | object | Comment body content |
|
||||||
|
| ↳ `value` | string | Comment body content |
|
||||||
|
| ↳ `representation` | string | Content representation format \(e.g., storage, view\) |
|
||||||
|
| ↳ `createdAt` | string | ISO 8601 timestamp when the comment was created |
|
||||||
|
| ↳ `authorId` | string | Account ID of the comment author |
|
||||||
|
| ↳ `version` | object | Comment version information |
|
||||||
|
| ↳ `number` | number | Version number |
|
||||||
|
| ↳ `message` | string | Version message |
|
||||||
|
| ↳ `minorEdit` | boolean | Whether this is a minor edit |
|
||||||
|
| ↳ `authorId` | string | Account ID of the version author |
|
||||||
|
| ↳ `createdAt` | string | ISO 8601 timestamp of version creation |
|
||||||
|
|
||||||
### `confluence_update_comment`
|
### `confluence_update_comment`
|
||||||
|
|
||||||
@@ -268,8 +298,24 @@ List all attachments on a Confluence page.
|
|||||||
|
|
||||||
| Parameter | Type | Description |
|
| Parameter | Type | Description |
|
||||||
| --------- | ---- | ----------- |
|
| --------- | ---- | ----------- |
|
||||||
| `ts` | string | Timestamp of retrieval |
|
| `ts` | string | ISO 8601 timestamp of the operation |
|
||||||
| `attachments` | array | List of attachments |
|
| `attachments` | array | Array of Confluence attachments |
|
||||||
|
| ↳ `id` | string | Unique attachment identifier \(prefixed with "att"\) |
|
||||||
|
| ↳ `title` | string | Attachment file name |
|
||||||
|
| ↳ `status` | string | Attachment status \(e.g., current, archived, trashed\) |
|
||||||
|
| ↳ `mediaType` | string | MIME type of the attachment |
|
||||||
|
| ↳ `fileSize` | number | File size in bytes |
|
||||||
|
| ↳ `downloadUrl` | string | URL to download the attachment |
|
||||||
|
| ↳ `webuiUrl` | string | URL to view the attachment in Confluence UI |
|
||||||
|
| ↳ `pageId` | string | ID of the page the attachment belongs to |
|
||||||
|
| ↳ `blogPostId` | string | ID of the blog post the attachment belongs to |
|
||||||
|
| ↳ `comment` | string | Comment/description of the attachment |
|
||||||
|
| ↳ `version` | object | Attachment version information |
|
||||||
|
| ↳ `number` | number | Version number |
|
||||||
|
| ↳ `message` | string | Version message |
|
||||||
|
| ↳ `minorEdit` | boolean | Whether this is a minor edit |
|
||||||
|
| ↳ `authorId` | string | Account ID of the version author |
|
||||||
|
| ↳ `createdAt` | string | ISO 8601 timestamp of version creation |
|
||||||
|
|
||||||
### `confluence_delete_attachment`
|
### `confluence_delete_attachment`
|
||||||
|
|
||||||
@@ -308,7 +354,10 @@ List all labels on a Confluence page.
|
|||||||
| Parameter | Type | Description |
|
| Parameter | Type | Description |
|
||||||
| --------- | ---- | ----------- |
|
| --------- | ---- | ----------- |
|
||||||
| `ts` | string | Timestamp of retrieval |
|
| `ts` | string | Timestamp of retrieval |
|
||||||
| `labels` | array | List of labels |
|
| `labels` | array | Array of labels on the page |
|
||||||
|
| ↳ `id` | string | Unique label identifier |
|
||||||
|
| ↳ `name` | string | Label name |
|
||||||
|
| ↳ `prefix` | string | Label prefix/type \(e.g., global, my, team\) |
|
||||||
|
|
||||||
### `confluence_get_space`
|
### `confluence_get_space`
|
||||||
|
|
||||||
@@ -350,7 +399,18 @@ List all Confluence spaces accessible to the user.
|
|||||||
|
|
||||||
| Parameter | Type | Description |
|
| Parameter | Type | Description |
|
||||||
| --------- | ---- | ----------- |
|
| --------- | ---- | ----------- |
|
||||||
| `ts` | string | Timestamp of retrieval |
|
| `ts` | string | ISO 8601 timestamp of the operation |
|
||||||
| `spaces` | array | List of spaces |
|
| `spaces` | array | Array of Confluence spaces |
|
||||||
|
| ↳ `id` | string | Unique space identifier |
|
||||||
|
| ↳ `key` | string | Space key \(short identifier used in URLs\) |
|
||||||
|
| ↳ `name` | string | Space name |
|
||||||
|
| ↳ `type` | string | Space type \(e.g., global, personal\) |
|
||||||
|
| ↳ `status` | string | Space status \(e.g., current, archived\) |
|
||||||
|
| ↳ `authorId` | string | Account ID of the space creator |
|
||||||
|
| ↳ `createdAt` | string | ISO 8601 timestamp when the space was created |
|
||||||
|
| ↳ `homepageId` | string | ID of the space homepage |
|
||||||
|
| ↳ `description` | object | Space description |
|
||||||
|
| ↳ `value` | string | Description text content |
|
||||||
|
| ↳ `representation` | string | Content representation format \(e.g., plain, view, storage\) |
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -66,7 +66,7 @@ Search the web using Exa AI. Returns relevant search results with titles, URLs,
|
|||||||
| ↳ `publishedDate` | string | Date when the content was published |
|
| ↳ `publishedDate` | string | Date when the content was published |
|
||||||
| ↳ `author` | string | The author of the content |
|
| ↳ `author` | string | The author of the content |
|
||||||
| ↳ `summary` | string | A brief summary of the content |
|
| ↳ `summary` | string | A brief summary of the content |
|
||||||
| ↳ `favicon` | string | URL of the site |
|
| ↳ `favicon` | string | URL of the site's favicon |
|
||||||
| ↳ `image` | string | URL of a representative image from the page |
|
| ↳ `image` | string | URL of a representative image from the page |
|
||||||
| ↳ `text` | string | Text snippet or full content from the page |
|
| ↳ `text` | string | Text snippet or full content from the page |
|
||||||
| ↳ `score` | number | Relevance score for the search result |
|
| ↳ `score` | number | Relevance score for the search result |
|
||||||
|
|||||||
@@ -61,6 +61,20 @@ Extract structured content from web pages with comprehensive metadata support. C
|
|||||||
| `markdown` | string | Page content in markdown format |
|
| `markdown` | string | Page content in markdown format |
|
||||||
| `html` | string | Raw HTML content of the page |
|
| `html` | string | Raw HTML content of the page |
|
||||||
| `metadata` | object | Page metadata including SEO and Open Graph information |
|
| `metadata` | object | Page metadata including SEO and Open Graph information |
|
||||||
|
| ↳ `title` | string | Page title |
|
||||||
|
| ↳ `description` | string | Page meta description |
|
||||||
|
| ↳ `language` | string | Page language code \(e.g., "en"\) |
|
||||||
|
| ↳ `sourceURL` | string | Original source URL that was scraped |
|
||||||
|
| ↳ `statusCode` | number | HTTP status code of the response |
|
||||||
|
| ↳ `keywords` | string | Page meta keywords |
|
||||||
|
| ↳ `robots` | string | Robots meta directive \(e.g., "follow, index"\) |
|
||||||
|
| ↳ `ogTitle` | string | Open Graph title |
|
||||||
|
| ↳ `ogDescription` | string | Open Graph description |
|
||||||
|
| ↳ `ogUrl` | string | Open Graph URL |
|
||||||
|
| ↳ `ogImage` | string | Open Graph image URL |
|
||||||
|
| ↳ `ogLocaleAlternate` | array | Alternate locale versions for Open Graph |
|
||||||
|
| ↳ `ogSiteName` | string | Open Graph site name |
|
||||||
|
| ↳ `error` | string | Error message if scrape failed |
|
||||||
|
|
||||||
### `firecrawl_search`
|
### `firecrawl_search`
|
||||||
|
|
||||||
@@ -77,7 +91,21 @@ Search for information on the web using Firecrawl
|
|||||||
|
|
||||||
| Parameter | Type | Description |
|
| Parameter | Type | Description |
|
||||||
| --------- | ---- | ----------- |
|
| --------- | ---- | ----------- |
|
||||||
| `data` | array | Search results data |
|
| `data` | array | Search results data with scraped content and metadata |
|
||||||
|
| ↳ `title` | string | Search result title from search engine |
|
||||||
|
| ↳ `description` | string | Search result description/snippet from search engine |
|
||||||
|
| ↳ `url` | string | URL of the search result |
|
||||||
|
| ↳ `markdown` | string | Page content in markdown \(when scrapeOptions.formats includes "markdown"\) |
|
||||||
|
| ↳ `html` | string | Processed HTML content \(when scrapeOptions.formats includes "html"\) |
|
||||||
|
| ↳ `rawHtml` | string | Unprocessed raw HTML \(when scrapeOptions.formats includes "rawHtml"\) |
|
||||||
|
| ↳ `links` | array | Links found on the page \(when scrapeOptions.formats includes "links"\) |
|
||||||
|
| ↳ `screenshot` | string | Screenshot URL \(expires after 24 hours, when scrapeOptions.formats includes "screenshot"\) |
|
||||||
|
| ↳ `metadata` | object | Metadata about the search result page |
|
||||||
|
| ↳ `title` | string | Page title |
|
||||||
|
| ↳ `description` | string | Page meta description |
|
||||||
|
| ↳ `sourceURL` | string | Original source URL |
|
||||||
|
| ↳ `statusCode` | number | HTTP status code |
|
||||||
|
| ↳ `error` | string | Error message if scrape failed |
|
||||||
|
|
||||||
### `firecrawl_crawl`
|
### `firecrawl_crawl`
|
||||||
|
|
||||||
@@ -98,13 +126,17 @@ Crawl entire websites and extract structured content from all accessible pages
|
|||||||
| --------- | ---- | ----------- |
|
| --------- | ---- | ----------- |
|
||||||
| `pages` | array | Array of crawled pages with their content and metadata |
|
| `pages` | array | Array of crawled pages with their content and metadata |
|
||||||
| ↳ `markdown` | string | Page content in markdown format |
|
| ↳ `markdown` | string | Page content in markdown format |
|
||||||
| ↳ `html` | string | Page HTML content |
|
| ↳ `html` | string | Processed HTML content of the page |
|
||||||
| ↳ `metadata` | object | Page metadata |
|
| ↳ `rawHtml` | string | Unprocessed raw HTML content |
|
||||||
|
| ↳ `links` | array | Array of links found on the page |
|
||||||
|
| ↳ `screenshot` | string | Screenshot URL \(expires after 24 hours\) |
|
||||||
|
| ↳ `metadata` | object | Page metadata from crawl operation |
|
||||||
| ↳ `title` | string | Page title |
|
| ↳ `title` | string | Page title |
|
||||||
| ↳ `description` | string | Page description |
|
| ↳ `description` | string | Page meta description |
|
||||||
| ↳ `language` | string | Page language |
|
| ↳ `language` | string | Page language code |
|
||||||
| ↳ `sourceURL` | string | Source URL of the page |
|
| ↳ `sourceURL` | string | Original source URL |
|
||||||
| ↳ `statusCode` | number | HTTP status code |
|
| ↳ `statusCode` | number | HTTP status code |
|
||||||
|
| ↳ `ogLocaleAlternate` | array | Alternate locale versions |
|
||||||
| `total` | number | Total number of pages found during crawl |
|
| `total` | number | Total number of pages found during crawl |
|
||||||
| `creditsUsed` | number | Number of credits consumed by the crawl operation |
|
| `creditsUsed` | number | Number of credits consumed by the crawl operation |
|
||||||
|
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -231,7 +231,7 @@ List all email aliases for a Google Group
|
|||||||
| --------- | ---- | ----------- |
|
| --------- | ---- | ----------- |
|
||||||
| `aliases` | array | List of email aliases for the group |
|
| `aliases` | array | List of email aliases for the group |
|
||||||
| ↳ `id` | string | Unique group identifier |
|
| ↳ `id` | string | Unique group identifier |
|
||||||
| ↳ `primaryEmail` | string | Group |
|
| ↳ `primaryEmail` | string | Group's primary email address |
|
||||||
| ↳ `alias` | string | Alias email address |
|
| ↳ `alias` | string | Alias email address |
|
||||||
| ↳ `kind` | string | API resource type |
|
| ↳ `kind` | string | API resource type |
|
||||||
| ↳ `etag` | string | Resource version identifier |
|
| ↳ `etag` | string | Resource version identifier |
|
||||||
@@ -252,7 +252,7 @@ Add an email alias to a Google Group
|
|||||||
| Parameter | Type | Description |
|
| Parameter | Type | Description |
|
||||||
| --------- | ---- | ----------- |
|
| --------- | ---- | ----------- |
|
||||||
| `id` | string | Unique group identifier |
|
| `id` | string | Unique group identifier |
|
||||||
| `primaryEmail` | string | Group |
|
| `primaryEmail` | string | Group's primary email address |
|
||||||
| `alias` | string | The alias that was added |
|
| `alias` | string | The alias that was added |
|
||||||
| `kind` | string | API resource type |
|
| `kind` | string | API resource type |
|
||||||
| `etag` | string | Resource version identifier |
|
| `etag` | string | Resource version identifier |
|
||||||
@@ -288,7 +288,7 @@ Get the settings for a Google Group including access permissions, moderation, an
|
|||||||
|
|
||||||
| Parameter | Type | Description |
|
| Parameter | Type | Description |
|
||||||
| --------- | ---- | ----------- |
|
| --------- | ---- | ----------- |
|
||||||
| `email` | string | The group |
|
| `email` | string | The group's email address |
|
||||||
| `name` | string | The group name \(max 75 characters\) |
|
| `name` | string | The group name \(max 75 characters\) |
|
||||||
| `description` | string | The group description \(max 4096 characters\) |
|
| `description` | string | The group description \(max 4096 characters\) |
|
||||||
| `whoCanJoin` | string | Who can join the group \(ANYONE_CAN_JOIN, ALL_IN_DOMAIN_CAN_JOIN, INVITED_CAN_JOIN, CAN_REQUEST_TO_JOIN\) |
|
| `whoCanJoin` | string | Who can join the group \(ANYONE_CAN_JOIN, ALL_IN_DOMAIN_CAN_JOIN, INVITED_CAN_JOIN, CAN_REQUEST_TO_JOIN\) |
|
||||||
@@ -297,7 +297,7 @@ Get the settings for a Google Group including access permissions, moderation, an
|
|||||||
| `whoCanPostMessage` | string | Who can post messages to the group |
|
| `whoCanPostMessage` | string | Who can post messages to the group |
|
||||||
| `allowExternalMembers` | string | Whether external users can be members |
|
| `allowExternalMembers` | string | Whether external users can be members |
|
||||||
| `allowWebPosting` | string | Whether web posting is allowed |
|
| `allowWebPosting` | string | Whether web posting is allowed |
|
||||||
| `primaryLanguage` | string | The group |
|
| `primaryLanguage` | string | The group's primary language |
|
||||||
| `isArchived` | string | Whether messages are archived |
|
| `isArchived` | string | Whether messages are archived |
|
||||||
| `archiveOnly` | string | Whether the group is archive-only \(inactive\) |
|
| `archiveOnly` | string | Whether the group is archive-only \(inactive\) |
|
||||||
| `messageModerationLevel` | string | Message moderation level |
|
| `messageModerationLevel` | string | Message moderation level |
|
||||||
@@ -368,7 +368,7 @@ Update the settings for a Google Group including access permissions, moderation,
|
|||||||
|
|
||||||
| Parameter | Type | Description |
|
| Parameter | Type | Description |
|
||||||
| --------- | ---- | ----------- |
|
| --------- | ---- | ----------- |
|
||||||
| `email` | string | The group |
|
| `email` | string | The group's email address |
|
||||||
| `name` | string | The group name |
|
| `name` | string | The group name |
|
||||||
| `description` | string | The group description |
|
| `description` | string | The group description |
|
||||||
| `whoCanJoin` | string | Who can join the group |
|
| `whoCanJoin` | string | Who can join the group |
|
||||||
@@ -377,7 +377,7 @@ Update the settings for a Google Group including access permissions, moderation,
|
|||||||
| `whoCanPostMessage` | string | Who can post messages to the group |
|
| `whoCanPostMessage` | string | Who can post messages to the group |
|
||||||
| `allowExternalMembers` | string | Whether external users can be members |
|
| `allowExternalMembers` | string | Whether external users can be members |
|
||||||
| `allowWebPosting` | string | Whether web posting is allowed |
|
| `allowWebPosting` | string | Whether web posting is allowed |
|
||||||
| `primaryLanguage` | string | The group |
|
| `primaryLanguage` | string | The group's primary language |
|
||||||
| `isArchived` | string | Whether messages are archived |
|
| `isArchived` | string | Whether messages are archived |
|
||||||
| `archiveOnly` | string | Whether the group is archive-only |
|
| `archiveOnly` | string | Whether the group is archive-only |
|
||||||
| `messageModerationLevel` | string | Message moderation level |
|
| `messageModerationLevel` | string | Message moderation level |
|
||||||
|
|||||||
@@ -66,8 +66,8 @@ Search the web with the Custom Search API
|
|||||||
| ↳ `title` | string | Title of the search result |
|
| ↳ `title` | string | Title of the search result |
|
||||||
| ↳ `link` | string | URL of the search result |
|
| ↳ `link` | string | URL of the search result |
|
||||||
| ↳ `snippet` | string | Snippet or description of the search result |
|
| ↳ `snippet` | string | Snippet or description of the search result |
|
||||||
| ↳ `displayLink` | string | Display URL |
|
| ↳ `displayLink` | string | Display URL \(abbreviated form\) |
|
||||||
| ↳ `pagemap` | object | Additional page metadata |
|
| ↳ `pagemap` | object | PageMap information for the result \(structured data\) |
|
||||||
| `searchInformation` | object | Information about the search query and results |
|
| `searchInformation` | object | Information about the search query and results |
|
||||||
| ↳ `totalResults` | string | Total number of search results available |
|
| ↳ `totalResults` | string | Total number of search results available |
|
||||||
| ↳ `searchTime` | number | Time taken to perform the search in seconds |
|
| ↳ `searchTime` | number | Time taken to perform the search in seconds |
|
||||||
|
|||||||
@@ -51,6 +51,12 @@ Retrieve all users from HubSpot account
|
|||||||
| Parameter | Type | Description |
|
| Parameter | Type | Description |
|
||||||
| --------- | ---- | ----------- |
|
| --------- | ---- | ----------- |
|
||||||
| `users` | array | Array of HubSpot user objects |
|
| `users` | array | Array of HubSpot user objects |
|
||||||
|
| ↳ `id` | string | User ID |
|
||||||
|
| ↳ `email` | string | User email address |
|
||||||
|
| ↳ `roleId` | string | User role ID |
|
||||||
|
| ↳ `primaryTeamId` | string | Primary team ID |
|
||||||
|
| ↳ `secondaryTeamIds` | array | Secondary team IDs |
|
||||||
|
| ↳ `superAdmin` | boolean | Whether user is a super admin |
|
||||||
| `totalItems` | number | Total number of users returned |
|
| `totalItems` | number | Total number of users returned |
|
||||||
| `success` | boolean | Operation success status |
|
| `success` | boolean | Operation success status |
|
||||||
|
|
||||||
@@ -71,9 +77,33 @@ Retrieve all contacts from HubSpot account with pagination support
|
|||||||
|
|
||||||
| Parameter | Type | Description |
|
| Parameter | Type | Description |
|
||||||
| --------- | ---- | ----------- |
|
| --------- | ---- | ----------- |
|
||||||
| `contacts` | array | Array of HubSpot contact objects |
|
| `contacts` | array | Array of HubSpot contact records |
|
||||||
| `paging` | object | Pagination information |
|
| ↳ `email` | string | Contact email address |
|
||||||
| `metadata` | object | Metadata with totalReturned and hasMore |
|
| ↳ `firstname` | string | Contact first name |
|
||||||
|
| ↳ `lastname` | string | Contact last name |
|
||||||
|
| ↳ `phone` | string | Contact phone number |
|
||||||
|
| ↳ `mobilephone` | string | Contact mobile phone number |
|
||||||
|
| ↳ `company` | string | Associated company name |
|
||||||
|
| ↳ `website` | string | Contact website URL |
|
||||||
|
| ↳ `jobtitle` | string | Contact job title |
|
||||||
|
| ↳ `lifecyclestage` | string | Lifecycle stage \(subscriber, lead, marketingqualifiedlead, salesqualifiedlead, opportunity, customer\) |
|
||||||
|
| ↳ `hubspot_owner_id` | string | HubSpot owner ID |
|
||||||
|
| ↳ `hs_object_id` | string | HubSpot object ID \(same as record ID\) |
|
||||||
|
| ↳ `createdate` | string | Contact creation date \(ISO 8601\) |
|
||||||
|
| ↳ `lastmodifieddate` | string | Last modified date \(ISO 8601\) |
|
||||||
|
| ↳ `address` | string | Street address |
|
||||||
|
| ↳ `city` | string | City |
|
||||||
|
| ↳ `state` | string | State/Region |
|
||||||
|
| ↳ `zip` | string | Postal/ZIP code |
|
||||||
|
| ↳ `country` | string | Country |
|
||||||
|
| ↳ `fax` | string | Fax number |
|
||||||
|
| ↳ `hs_timezone` | string | Contact timezone |
|
||||||
|
| `paging` | object | Pagination information for fetching more results |
|
||||||
|
| ↳ `after` | string | Cursor for next page of results |
|
||||||
|
| ↳ `link` | string | Link to next page |
|
||||||
|
| `metadata` | object | Response metadata |
|
||||||
|
| ↳ `totalReturned` | number | Number of records returned in this response |
|
||||||
|
| ↳ `hasMore` | boolean | Whether more records are available |
|
||||||
| `success` | boolean | Operation success status |
|
| `success` | boolean | Operation success status |
|
||||||
|
|
||||||
### `hubspot_get_contact`
|
### `hubspot_get_contact`
|
||||||
@@ -93,7 +123,27 @@ Retrieve a single contact by ID or email from HubSpot
|
|||||||
|
|
||||||
| Parameter | Type | Description |
|
| Parameter | Type | Description |
|
||||||
| --------- | ---- | ----------- |
|
| --------- | ---- | ----------- |
|
||||||
| `contact` | object | HubSpot contact object with properties |
|
| `contact` | object | HubSpot contact record |
|
||||||
|
| ↳ `email` | string | Contact email address |
|
||||||
|
| ↳ `firstname` | string | Contact first name |
|
||||||
|
| ↳ `lastname` | string | Contact last name |
|
||||||
|
| ↳ `phone` | string | Contact phone number |
|
||||||
|
| ↳ `mobilephone` | string | Contact mobile phone number |
|
||||||
|
| ↳ `company` | string | Associated company name |
|
||||||
|
| ↳ `website` | string | Contact website URL |
|
||||||
|
| ↳ `jobtitle` | string | Contact job title |
|
||||||
|
| ↳ `lifecyclestage` | string | Lifecycle stage \(subscriber, lead, marketingqualifiedlead, salesqualifiedlead, opportunity, customer\) |
|
||||||
|
| ↳ `hubspot_owner_id` | string | HubSpot owner ID |
|
||||||
|
| ↳ `hs_object_id` | string | HubSpot object ID \(same as record ID\) |
|
||||||
|
| ↳ `createdate` | string | Contact creation date \(ISO 8601\) |
|
||||||
|
| ↳ `lastmodifieddate` | string | Last modified date \(ISO 8601\) |
|
||||||
|
| ↳ `address` | string | Street address |
|
||||||
|
| ↳ `city` | string | City |
|
||||||
|
| ↳ `state` | string | State/Region |
|
||||||
|
| ↳ `zip` | string | Postal/ZIP code |
|
||||||
|
| ↳ `country` | string | Country |
|
||||||
|
| ↳ `fax` | string | Fax number |
|
||||||
|
| ↳ `hs_timezone` | string | Contact timezone |
|
||||||
| `contactId` | string | The retrieved contact ID |
|
| `contactId` | string | The retrieved contact ID |
|
||||||
| `success` | boolean | Operation success status |
|
| `success` | boolean | Operation success status |
|
||||||
|
|
||||||
@@ -112,7 +162,27 @@ Create a new contact in HubSpot. Requires at least one of: email, firstname, or
|
|||||||
|
|
||||||
| Parameter | Type | Description |
|
| Parameter | Type | Description |
|
||||||
| --------- | ---- | ----------- |
|
| --------- | ---- | ----------- |
|
||||||
| `contact` | object | Created HubSpot contact object |
|
| `contact` | object | HubSpot contact record |
|
||||||
|
| ↳ `email` | string | Contact email address |
|
||||||
|
| ↳ `firstname` | string | Contact first name |
|
||||||
|
| ↳ `lastname` | string | Contact last name |
|
||||||
|
| ↳ `phone` | string | Contact phone number |
|
||||||
|
| ↳ `mobilephone` | string | Contact mobile phone number |
|
||||||
|
| ↳ `company` | string | Associated company name |
|
||||||
|
| ↳ `website` | string | Contact website URL |
|
||||||
|
| ↳ `jobtitle` | string | Contact job title |
|
||||||
|
| ↳ `lifecyclestage` | string | Lifecycle stage \(subscriber, lead, marketingqualifiedlead, salesqualifiedlead, opportunity, customer\) |
|
||||||
|
| ↳ `hubspot_owner_id` | string | HubSpot owner ID |
|
||||||
|
| ↳ `hs_object_id` | string | HubSpot object ID \(same as record ID\) |
|
||||||
|
| ↳ `createdate` | string | Contact creation date \(ISO 8601\) |
|
||||||
|
| ↳ `lastmodifieddate` | string | Last modified date \(ISO 8601\) |
|
||||||
|
| ↳ `address` | string | Street address |
|
||||||
|
| ↳ `city` | string | City |
|
||||||
|
| ↳ `state` | string | State/Region |
|
||||||
|
| ↳ `zip` | string | Postal/ZIP code |
|
||||||
|
| ↳ `country` | string | Country |
|
||||||
|
| ↳ `fax` | string | Fax number |
|
||||||
|
| ↳ `hs_timezone` | string | Contact timezone |
|
||||||
| `contactId` | string | The created contact ID |
|
| `contactId` | string | The created contact ID |
|
||||||
| `success` | boolean | Operation success status |
|
| `success` | boolean | Operation success status |
|
||||||
|
|
||||||
@@ -132,7 +202,27 @@ Update an existing contact in HubSpot by ID or email
|
|||||||
|
|
||||||
| Parameter | Type | Description |
|
| Parameter | Type | Description |
|
||||||
| --------- | ---- | ----------- |
|
| --------- | ---- | ----------- |
|
||||||
| `contact` | object | Updated HubSpot contact object |
|
| `contact` | object | HubSpot contact record |
|
||||||
|
| ↳ `email` | string | Contact email address |
|
||||||
|
| ↳ `firstname` | string | Contact first name |
|
||||||
|
| ↳ `lastname` | string | Contact last name |
|
||||||
|
| ↳ `phone` | string | Contact phone number |
|
||||||
|
| ↳ `mobilephone` | string | Contact mobile phone number |
|
||||||
|
| ↳ `company` | string | Associated company name |
|
||||||
|
| ↳ `website` | string | Contact website URL |
|
||||||
|
| ↳ `jobtitle` | string | Contact job title |
|
||||||
|
| ↳ `lifecyclestage` | string | Lifecycle stage \(subscriber, lead, marketingqualifiedlead, salesqualifiedlead, opportunity, customer\) |
|
||||||
|
| ↳ `hubspot_owner_id` | string | HubSpot owner ID |
|
||||||
|
| ↳ `hs_object_id` | string | HubSpot object ID \(same as record ID\) |
|
||||||
|
| ↳ `createdate` | string | Contact creation date \(ISO 8601\) |
|
||||||
|
| ↳ `lastmodifieddate` | string | Last modified date \(ISO 8601\) |
|
||||||
|
| ↳ `address` | string | Street address |
|
||||||
|
| ↳ `city` | string | City |
|
||||||
|
| ↳ `state` | string | State/Region |
|
||||||
|
| ↳ `zip` | string | Postal/ZIP code |
|
||||||
|
| ↳ `country` | string | Country |
|
||||||
|
| ↳ `fax` | string | Fax number |
|
||||||
|
| ↳ `hs_timezone` | string | Contact timezone |
|
||||||
| `contactId` | string | The updated contact ID |
|
| `contactId` | string | The updated contact ID |
|
||||||
| `success` | boolean | Operation success status |
|
| `success` | boolean | Operation success status |
|
||||||
|
|
||||||
@@ -155,10 +245,34 @@ Search for contacts in HubSpot using filters, sorting, and queries
|
|||||||
|
|
||||||
| Parameter | Type | Description |
|
| Parameter | Type | Description |
|
||||||
| --------- | ---- | ----------- |
|
| --------- | ---- | ----------- |
|
||||||
| `contacts` | array | Array of matching HubSpot contact objects |
|
| `contacts` | array | Array of HubSpot contact records |
|
||||||
|
| ↳ `email` | string | Contact email address |
|
||||||
|
| ↳ `firstname` | string | Contact first name |
|
||||||
|
| ↳ `lastname` | string | Contact last name |
|
||||||
|
| ↳ `phone` | string | Contact phone number |
|
||||||
|
| ↳ `mobilephone` | string | Contact mobile phone number |
|
||||||
|
| ↳ `company` | string | Associated company name |
|
||||||
|
| ↳ `website` | string | Contact website URL |
|
||||||
|
| ↳ `jobtitle` | string | Contact job title |
|
||||||
|
| ↳ `lifecyclestage` | string | Lifecycle stage \(subscriber, lead, marketingqualifiedlead, salesqualifiedlead, opportunity, customer\) |
|
||||||
|
| ↳ `hubspot_owner_id` | string | HubSpot owner ID |
|
||||||
|
| ↳ `hs_object_id` | string | HubSpot object ID \(same as record ID\) |
|
||||||
|
| ↳ `createdate` | string | Contact creation date \(ISO 8601\) |
|
||||||
|
| ↳ `lastmodifieddate` | string | Last modified date \(ISO 8601\) |
|
||||||
|
| ↳ `address` | string | Street address |
|
||||||
|
| ↳ `city` | string | City |
|
||||||
|
| ↳ `state` | string | State/Region |
|
||||||
|
| ↳ `zip` | string | Postal/ZIP code |
|
||||||
|
| ↳ `country` | string | Country |
|
||||||
|
| ↳ `fax` | string | Fax number |
|
||||||
|
| ↳ `hs_timezone` | string | Contact timezone |
|
||||||
|
| `paging` | object | Pagination information for fetching more results |
|
||||||
|
| ↳ `after` | string | Cursor for next page of results |
|
||||||
|
| ↳ `link` | string | Link to next page |
|
||||||
|
| `metadata` | object | Response metadata |
|
||||||
|
| ↳ `totalReturned` | number | Number of records returned in this response |
|
||||||
|
| ↳ `hasMore` | boolean | Whether more records are available |
|
||||||
| `total` | number | Total number of matching contacts |
|
| `total` | number | Total number of matching contacts |
|
||||||
| `paging` | object | Pagination information |
|
|
||||||
| `metadata` | object | Metadata with totalReturned and hasMore |
|
|
||||||
| `success` | boolean | Operation success status |
|
| `success` | boolean | Operation success status |
|
||||||
|
|
||||||
### `hubspot_list_companies`
|
### `hubspot_list_companies`
|
||||||
@@ -178,9 +292,34 @@ Retrieve all companies from HubSpot account with pagination support
|
|||||||
|
|
||||||
| Parameter | Type | Description |
|
| Parameter | Type | Description |
|
||||||
| --------- | ---- | ----------- |
|
| --------- | ---- | ----------- |
|
||||||
| `companies` | array | Array of HubSpot company objects |
|
| `companies` | array | Array of HubSpot company records |
|
||||||
| `paging` | object | Pagination information |
|
| ↳ `name` | string | Company name |
|
||||||
| `metadata` | object | Metadata with totalReturned and hasMore |
|
| ↳ `domain` | string | Company website domain \(unique identifier\) |
|
||||||
|
| ↳ `description` | string | Company description |
|
||||||
|
| ↳ `industry` | string | Industry type \(e.g., Airlines/Aviation\) |
|
||||||
|
| ↳ `phone` | string | Company phone number |
|
||||||
|
| ↳ `city` | string | City |
|
||||||
|
| ↳ `state` | string | State/Region |
|
||||||
|
| ↳ `zip` | string | Postal/ZIP code |
|
||||||
|
| ↳ `country` | string | Country |
|
||||||
|
| ↳ `address` | string | Street address |
|
||||||
|
| ↳ `numberofemployees` | string | Total number of employees |
|
||||||
|
| ↳ `annualrevenue` | string | Annual revenue estimate |
|
||||||
|
| ↳ `lifecyclestage` | string | Lifecycle stage |
|
||||||
|
| ↳ `hubspot_owner_id` | string | HubSpot owner ID |
|
||||||
|
| ↳ `hs_object_id` | string | HubSpot object ID \(same as record ID\) |
|
||||||
|
| ↳ `hs_createdate` | string | Company creation date \(ISO 8601\) |
|
||||||
|
| ↳ `hs_lastmodifieddate` | string | Last modified date \(ISO 8601\) |
|
||||||
|
| ↳ `hs_additional_domains` | string | Additional domains \(semicolon-separated\) |
|
||||||
|
| ↳ `num_associated_contacts` | string | Number of associated contacts \(auto-updated\) |
|
||||||
|
| ↳ `num_associated_deals` | string | Number of associated deals \(auto-updated\) |
|
||||||
|
| ↳ `website` | string | Company website URL |
|
||||||
|
| `paging` | object | Pagination information for fetching more results |
|
||||||
|
| ↳ `after` | string | Cursor for next page of results |
|
||||||
|
| ↳ `link` | string | Link to next page |
|
||||||
|
| `metadata` | object | Response metadata |
|
||||||
|
| ↳ `totalReturned` | number | Number of records returned in this response |
|
||||||
|
| ↳ `hasMore` | boolean | Whether more records are available |
|
||||||
| `success` | boolean | Operation success status |
|
| `success` | boolean | Operation success status |
|
||||||
|
|
||||||
### `hubspot_get_company`
|
### `hubspot_get_company`
|
||||||
@@ -200,7 +339,28 @@ Retrieve a single company by ID or domain from HubSpot
|
|||||||
|
|
||||||
| Parameter | Type | Description |
|
| Parameter | Type | Description |
|
||||||
| --------- | ---- | ----------- |
|
| --------- | ---- | ----------- |
|
||||||
| `company` | object | HubSpot company object with properties |
|
| `company` | object | HubSpot company record |
|
||||||
|
| ↳ `name` | string | Company name |
|
||||||
|
| ↳ `domain` | string | Company website domain \(unique identifier\) |
|
||||||
|
| ↳ `description` | string | Company description |
|
||||||
|
| ↳ `industry` | string | Industry type \(e.g., Airlines/Aviation\) |
|
||||||
|
| ↳ `phone` | string | Company phone number |
|
||||||
|
| ↳ `city` | string | City |
|
||||||
|
| ↳ `state` | string | State/Region |
|
||||||
|
| ↳ `zip` | string | Postal/ZIP code |
|
||||||
|
| ↳ `country` | string | Country |
|
||||||
|
| ↳ `address` | string | Street address |
|
||||||
|
| ↳ `numberofemployees` | string | Total number of employees |
|
||||||
|
| ↳ `annualrevenue` | string | Annual revenue estimate |
|
||||||
|
| ↳ `lifecyclestage` | string | Lifecycle stage |
|
||||||
|
| ↳ `hubspot_owner_id` | string | HubSpot owner ID |
|
||||||
|
| ↳ `hs_object_id` | string | HubSpot object ID \(same as record ID\) |
|
||||||
|
| ↳ `hs_createdate` | string | Company creation date \(ISO 8601\) |
|
||||||
|
| ↳ `hs_lastmodifieddate` | string | Last modified date \(ISO 8601\) |
|
||||||
|
| ↳ `hs_additional_domains` | string | Additional domains \(semicolon-separated\) |
|
||||||
|
| ↳ `num_associated_contacts` | string | Number of associated contacts \(auto-updated\) |
|
||||||
|
| ↳ `num_associated_deals` | string | Number of associated deals \(auto-updated\) |
|
||||||
|
| ↳ `website` | string | Company website URL |
|
||||||
| `companyId` | string | The retrieved company ID |
|
| `companyId` | string | The retrieved company ID |
|
||||||
| `success` | boolean | Operation success status |
|
| `success` | boolean | Operation success status |
|
||||||
|
|
||||||
@@ -219,7 +379,28 @@ Create a new company in HubSpot
|
|||||||
|
|
||||||
| Parameter | Type | Description |
|
| Parameter | Type | Description |
|
||||||
| --------- | ---- | ----------- |
|
| --------- | ---- | ----------- |
|
||||||
| `company` | object | Created HubSpot company object |
|
| `company` | object | HubSpot company record |
|
||||||
|
| ↳ `name` | string | Company name |
|
||||||
|
| ↳ `domain` | string | Company website domain \(unique identifier\) |
|
||||||
|
| ↳ `description` | string | Company description |
|
||||||
|
| ↳ `industry` | string | Industry type \(e.g., Airlines/Aviation\) |
|
||||||
|
| ↳ `phone` | string | Company phone number |
|
||||||
|
| ↳ `city` | string | City |
|
||||||
|
| ↳ `state` | string | State/Region |
|
||||||
|
| ↳ `zip` | string | Postal/ZIP code |
|
||||||
|
| ↳ `country` | string | Country |
|
||||||
|
| ↳ `address` | string | Street address |
|
||||||
|
| ↳ `numberofemployees` | string | Total number of employees |
|
||||||
|
| ↳ `annualrevenue` | string | Annual revenue estimate |
|
||||||
|
| ↳ `lifecyclestage` | string | Lifecycle stage |
|
||||||
|
| ↳ `hubspot_owner_id` | string | HubSpot owner ID |
|
||||||
|
| ↳ `hs_object_id` | string | HubSpot object ID \(same as record ID\) |
|
||||||
|
| ↳ `hs_createdate` | string | Company creation date \(ISO 8601\) |
|
||||||
|
| ↳ `hs_lastmodifieddate` | string | Last modified date \(ISO 8601\) |
|
||||||
|
| ↳ `hs_additional_domains` | string | Additional domains \(semicolon-separated\) |
|
||||||
|
| ↳ `num_associated_contacts` | string | Number of associated contacts \(auto-updated\) |
|
||||||
|
| ↳ `num_associated_deals` | string | Number of associated deals \(auto-updated\) |
|
||||||
|
| ↳ `website` | string | Company website URL |
|
||||||
| `companyId` | string | The created company ID |
|
| `companyId` | string | The created company ID |
|
||||||
| `success` | boolean | Operation success status |
|
| `success` | boolean | Operation success status |
|
||||||
|
|
||||||
@@ -239,7 +420,28 @@ Update an existing company in HubSpot by ID or domain
|
|||||||
|
|
||||||
| Parameter | Type | Description |
|
| Parameter | Type | Description |
|
||||||
| --------- | ---- | ----------- |
|
| --------- | ---- | ----------- |
|
||||||
| `company` | object | Updated HubSpot company object |
|
| `company` | object | HubSpot company record |
|
||||||
|
| ↳ `name` | string | Company name |
|
||||||
|
| ↳ `domain` | string | Company website domain \(unique identifier\) |
|
||||||
|
| ↳ `description` | string | Company description |
|
||||||
|
| ↳ `industry` | string | Industry type \(e.g., Airlines/Aviation\) |
|
||||||
|
| ↳ `phone` | string | Company phone number |
|
||||||
|
| ↳ `city` | string | City |
|
||||||
|
| ↳ `state` | string | State/Region |
|
||||||
|
| ↳ `zip` | string | Postal/ZIP code |
|
||||||
|
| ↳ `country` | string | Country |
|
||||||
|
| ↳ `address` | string | Street address |
|
||||||
|
| ↳ `numberofemployees` | string | Total number of employees |
|
||||||
|
| ↳ `annualrevenue` | string | Annual revenue estimate |
|
||||||
|
| ↳ `lifecyclestage` | string | Lifecycle stage |
|
||||||
|
| ↳ `hubspot_owner_id` | string | HubSpot owner ID |
|
||||||
|
| ↳ `hs_object_id` | string | HubSpot object ID \(same as record ID\) |
|
||||||
|
| ↳ `hs_createdate` | string | Company creation date \(ISO 8601\) |
|
||||||
|
| ↳ `hs_lastmodifieddate` | string | Last modified date \(ISO 8601\) |
|
||||||
|
| ↳ `hs_additional_domains` | string | Additional domains \(semicolon-separated\) |
|
||||||
|
| ↳ `num_associated_contacts` | string | Number of associated contacts \(auto-updated\) |
|
||||||
|
| ↳ `num_associated_deals` | string | Number of associated deals \(auto-updated\) |
|
||||||
|
| ↳ `website` | string | Company website URL |
|
||||||
| `companyId` | string | The updated company ID |
|
| `companyId` | string | The updated company ID |
|
||||||
| `success` | boolean | Operation success status |
|
| `success` | boolean | Operation success status |
|
||||||
|
|
||||||
@@ -262,10 +464,35 @@ Search for companies in HubSpot using filters, sorting, and queries
|
|||||||
|
|
||||||
| Parameter | Type | Description |
|
| Parameter | Type | Description |
|
||||||
| --------- | ---- | ----------- |
|
| --------- | ---- | ----------- |
|
||||||
| `companies` | array | Array of matching HubSpot company objects |
|
| `companies` | array | Array of HubSpot company records |
|
||||||
|
| ↳ `name` | string | Company name |
|
||||||
|
| ↳ `domain` | string | Company website domain \(unique identifier\) |
|
||||||
|
| ↳ `description` | string | Company description |
|
||||||
|
| ↳ `industry` | string | Industry type \(e.g., Airlines/Aviation\) |
|
||||||
|
| ↳ `phone` | string | Company phone number |
|
||||||
|
| ↳ `city` | string | City |
|
||||||
|
| ↳ `state` | string | State/Region |
|
||||||
|
| ↳ `zip` | string | Postal/ZIP code |
|
||||||
|
| ↳ `country` | string | Country |
|
||||||
|
| ↳ `address` | string | Street address |
|
||||||
|
| ↳ `numberofemployees` | string | Total number of employees |
|
||||||
|
| ↳ `annualrevenue` | string | Annual revenue estimate |
|
||||||
|
| ↳ `lifecyclestage` | string | Lifecycle stage |
|
||||||
|
| ↳ `hubspot_owner_id` | string | HubSpot owner ID |
|
||||||
|
| ↳ `hs_object_id` | string | HubSpot object ID \(same as record ID\) |
|
||||||
|
| ↳ `hs_createdate` | string | Company creation date \(ISO 8601\) |
|
||||||
|
| ↳ `hs_lastmodifieddate` | string | Last modified date \(ISO 8601\) |
|
||||||
|
| ↳ `hs_additional_domains` | string | Additional domains \(semicolon-separated\) |
|
||||||
|
| ↳ `num_associated_contacts` | string | Number of associated contacts \(auto-updated\) |
|
||||||
|
| ↳ `num_associated_deals` | string | Number of associated deals \(auto-updated\) |
|
||||||
|
| ↳ `website` | string | Company website URL |
|
||||||
|
| `paging` | object | Pagination information for fetching more results |
|
||||||
|
| ↳ `after` | string | Cursor for next page of results |
|
||||||
|
| ↳ `link` | string | Link to next page |
|
||||||
|
| `metadata` | object | Response metadata |
|
||||||
|
| ↳ `totalReturned` | number | Number of records returned in this response |
|
||||||
|
| ↳ `hasMore` | boolean | Whether more records are available |
|
||||||
| `total` | number | Total number of matching companies |
|
| `total` | number | Total number of matching companies |
|
||||||
| `paging` | object | Pagination information |
|
|
||||||
| `metadata` | object | Metadata with totalReturned and hasMore |
|
|
||||||
| `success` | boolean | Operation success status |
|
| `success` | boolean | Operation success status |
|
||||||
|
|
||||||
### `hubspot_list_deals`
|
### `hubspot_list_deals`
|
||||||
@@ -285,9 +512,25 @@ Retrieve all deals from HubSpot account with pagination support
|
|||||||
|
|
||||||
| Parameter | Type | Description |
|
| Parameter | Type | Description |
|
||||||
| --------- | ---- | ----------- |
|
| --------- | ---- | ----------- |
|
||||||
| `deals` | array | Array of HubSpot deal objects |
|
| `deals` | array | Array of HubSpot deal records |
|
||||||
| `paging` | object | Pagination information |
|
| ↳ `dealname` | string | Deal name |
|
||||||
| `metadata` | object | Metadata with totalReturned and hasMore |
|
| ↳ `amount` | string | Deal amount |
|
||||||
|
| ↳ `dealstage` | string | Current deal stage |
|
||||||
|
| ↳ `pipeline` | string | Pipeline the deal is in |
|
||||||
|
| ↳ `closedate` | string | Expected close date \(ISO 8601\) |
|
||||||
|
| ↳ `dealtype` | string | Deal type \(New Business, Existing Business, etc.\) |
|
||||||
|
| ↳ `description` | string | Deal description |
|
||||||
|
| ↳ `hubspot_owner_id` | string | HubSpot owner ID |
|
||||||
|
| ↳ `hs_object_id` | string | HubSpot object ID \(same as record ID\) |
|
||||||
|
| ↳ `createdate` | string | Deal creation date \(ISO 8601\) |
|
||||||
|
| ↳ `hs_lastmodifieddate` | string | Last modified date \(ISO 8601\) |
|
||||||
|
| ↳ `num_associated_contacts` | string | Number of associated contacts |
|
||||||
|
| `paging` | object | Pagination information for fetching more results |
|
||||||
|
| ↳ `after` | string | Cursor for next page of results |
|
||||||
|
| ↳ `link` | string | Link to next page |
|
||||||
|
| `metadata` | object | Response metadata |
|
||||||
|
| ↳ `totalReturned` | number | Number of records returned in this response |
|
||||||
|
| ↳ `hasMore` | boolean | Whether more records are available |
|
||||||
| `success` | boolean | Operation success status |
|
| `success` | boolean | Operation success status |
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -52,7 +52,12 @@ Returns companies matching a set of criteria using Hunter.io AI-powered search.
|
|||||||
|
|
||||||
| Parameter | Type | Description |
|
| Parameter | Type | Description |
|
||||||
| --------- | ---- | ----------- |
|
| --------- | ---- | ----------- |
|
||||||
| `results` | array | Array of companies matching the search criteria, each containing domain, name, headcount, technologies, and email_count |
|
| `results` | array | List of companies matching the search criteria |
|
||||||
|
| ↳ `domain` | string | Company domain |
|
||||||
|
| ↳ `name` | string | Company/organization name |
|
||||||
|
| ↳ `headcount` | number | Company size/headcount |
|
||||||
|
| ↳ `technologies` | array | Technologies used by the company |
|
||||||
|
| ↳ `email_count` | number | Total number of email addresses found |
|
||||||
|
|
||||||
### `hunter_domain_search`
|
### `hunter_domain_search`
|
||||||
|
|
||||||
@@ -74,26 +79,46 @@ Returns all the email addresses found using one given domain name, with sources.
|
|||||||
|
|
||||||
| Parameter | Type | Description |
|
| Parameter | Type | Description |
|
||||||
| --------- | ---- | ----------- |
|
| --------- | ---- | ----------- |
|
||||||
|
| `emails` | array | List of email addresses found for the domain \(up to 100 per request\) |
|
||||||
|
| ↳ `value` | string | The email address |
|
||||||
|
| ↳ `type` | string | Email type: personal or generic \(role-based\) |
|
||||||
|
| ↳ `confidence` | number | Probability score \(0-100\) that the email is correct |
|
||||||
|
| ↳ `first_name` | string | Person's first name |
|
||||||
|
| ↳ `last_name` | string | Person's last name |
|
||||||
|
| ↳ `position` | string | Job title/position |
|
||||||
|
| ↳ `seniority` | string | Seniority level \(junior, senior, executive\) |
|
||||||
|
| ↳ `department` | string | Department \(executive, it, finance, management, sales, legal, support, hr, marketing, communication\) |
|
||||||
|
| ↳ `linkedin` | string | LinkedIn profile URL |
|
||||||
|
| ↳ `twitter` | string | Twitter handle |
|
||||||
|
| ↳ `phone_number` | string | Phone number |
|
||||||
|
| ↳ `sources` | array | List of sources where the email was found \(limited to 20\) |
|
||||||
|
| ↳ `domain` | string | Domain where the email was found |
|
||||||
|
| ↳ `uri` | string | Full URL of the source page |
|
||||||
|
| ↳ `extracted_on` | string | Date when the email was first extracted \(YYYY-MM-DD\) |
|
||||||
|
| ↳ `last_seen_on` | string | Date when the email was last seen \(YYYY-MM-DD\) |
|
||||||
|
| ↳ `still_on_page` | boolean | Whether the email is still present on the source page |
|
||||||
|
| ↳ `verification` | object | Email verification information |
|
||||||
|
| ↳ `date` | string | Date when the email was verified \(YYYY-MM-DD\) |
|
||||||
|
| ↳ `status` | string | Verification status \(valid, invalid, accept_all, webmail, disposable, unknown\) |
|
||||||
| `domain` | string | The searched domain name |
|
| `domain` | string | The searched domain name |
|
||||||
| `disposable` | boolean | Whether the domain accepts disposable email addresses |
|
| `disposable` | boolean | Whether the domain is a disposable email service |
|
||||||
| `webmail` | boolean | Whether the domain is a webmail provider |
|
| `webmail` | boolean | Whether the domain is a webmail provider \(e.g., Gmail\) |
|
||||||
| `accept_all` | boolean | Whether the domain accepts all email addresses |
|
| `accept_all` | boolean | Whether the server accepts all email addresses \(may cause false positives\) |
|
||||||
| `pattern` | string | The email pattern used by the organization |
|
| `pattern` | string | The email pattern used by the organization \(e.g., \{first\}, \{first\}.\{last\}\) |
|
||||||
| `organization` | string | The organization name |
|
| `organization` | string | The organization/company name |
|
||||||
| `description` | string | Description of the organization |
|
| `description` | string | Description of the organization |
|
||||||
| `industry` | string | Industry of the organization |
|
| `industry` | string | Industry classification of the organization |
|
||||||
| `twitter` | string | Twitter profile of the organization |
|
| `twitter` | string | Twitter handle of the organization |
|
||||||
| `facebook` | string | Facebook profile of the organization |
|
| `facebook` | string | Facebook page URL of the organization |
|
||||||
| `linkedin` | string | LinkedIn profile of the organization |
|
| `linkedin` | string | LinkedIn company page URL |
|
||||||
| `instagram` | string | Instagram profile of the organization |
|
| `instagram` | string | Instagram profile of the organization |
|
||||||
| `youtube` | string | YouTube channel of the organization |
|
| `youtube` | string | YouTube channel of the organization |
|
||||||
| `technologies` | array | Array of technologies used by the organization |
|
| `technologies` | array | Technologies used by the organization |
|
||||||
| `country` | string | Country where the organization is located |
|
| `country` | string | Country where the organization is headquartered |
|
||||||
| `state` | string | State where the organization is located |
|
| `state` | string | State/province where the organization is located |
|
||||||
| `city` | string | City where the organization is located |
|
| `city` | string | City where the organization is located |
|
||||||
| `postal_code` | string | Postal code of the organization |
|
| `postal_code` | string | Postal code of the organization |
|
||||||
| `street` | string | Street address of the organization |
|
| `street` | string | Street address of the organization |
|
||||||
| `emails` | array | Array of email addresses found for the domain, each containing value, type, confidence, sources, and person details |
|
|
||||||
|
|
||||||
### `hunter_email_finder`
|
### `hunter_email_finder`
|
||||||
|
|
||||||
@@ -113,10 +138,17 @@ Finds the most likely email address for a person given their name and company do
|
|||||||
|
|
||||||
| Parameter | Type | Description |
|
| Parameter | Type | Description |
|
||||||
| --------- | ---- | ----------- |
|
| --------- | ---- | ----------- |
|
||||||
|
| `sources` | array | List of sources where the email was found \(limited to 20\) |
|
||||||
|
| ↳ `domain` | string | Domain where the email was found |
|
||||||
|
| ↳ `uri` | string | Full URL of the source page |
|
||||||
|
| ↳ `extracted_on` | string | Date when the email was first extracted \(YYYY-MM-DD\) |
|
||||||
|
| ↳ `last_seen_on` | string | Date when the email was last seen \(YYYY-MM-DD\) |
|
||||||
|
| ↳ `still_on_page` | boolean | Whether the email is still present on the source page |
|
||||||
|
| `verification` | object | Email verification information |
|
||||||
|
| ↳ `date` | string | Date when the email was verified \(YYYY-MM-DD\) |
|
||||||
|
| ↳ `status` | string | Verification status \(valid, invalid, accept_all, webmail, disposable, unknown\) |
|
||||||
| `email` | string | The found email address |
|
| `email` | string | The found email address |
|
||||||
| `score` | number | Confidence score for the found email address |
|
| `score` | number | Confidence score \(0-100\) for the found email address |
|
||||||
| `sources` | array | Array of sources where the email was found, each containing domain, uri, extracted_on, last_seen_on, and still_on_page |
|
|
||||||
| `verification` | object | Verification information containing date and status |
|
|
||||||
|
|
||||||
### `hunter_email_verifier`
|
### `hunter_email_verifier`
|
||||||
|
|
||||||
@@ -133,20 +165,25 @@ Verifies the deliverability of an email address and provides detailed verificati
|
|||||||
|
|
||||||
| Parameter | Type | Description |
|
| Parameter | Type | Description |
|
||||||
| --------- | ---- | ----------- |
|
| --------- | ---- | ----------- |
|
||||||
|
| `sources` | array | List of sources where the email was found \(limited to 20\) |
|
||||||
|
| ↳ `domain` | string | Domain where the email was found |
|
||||||
|
| ↳ `uri` | string | Full URL of the source page |
|
||||||
|
| ↳ `extracted_on` | string | Date when the email was first extracted \(YYYY-MM-DD\) |
|
||||||
|
| ↳ `last_seen_on` | string | Date when the email was last seen \(YYYY-MM-DD\) |
|
||||||
|
| ↳ `still_on_page` | boolean | Whether the email is still present on the source page |
|
||||||
| `result` | string | Deliverability result: deliverable, undeliverable, or risky |
|
| `result` | string | Deliverability result: deliverable, undeliverable, or risky |
|
||||||
| `score` | number | Confidence score for the verification result |
|
| `score` | number | Deliverability score \(0-100\). Webmail and disposable emails receive an arbitrary score of 50. |
|
||||||
| `email` | string | The verified email address |
|
| `email` | string | The verified email address |
|
||||||
| `regexp` | boolean | Whether the email follows a valid regex pattern |
|
| `regexp` | boolean | Whether the email passes regular expression validation |
|
||||||
| `gibberish` | boolean | Whether the email appears to be gibberish |
|
| `gibberish` | boolean | Whether the email appears to be auto-generated \(e.g., e65rc109q@company.com\) |
|
||||||
| `disposable` | boolean | Whether the email is from a disposable email provider |
|
| `disposable` | boolean | Whether the email is from a disposable email service |
|
||||||
| `webmail` | boolean | Whether the email is from a webmail provider |
|
| `webmail` | boolean | Whether the email is from a webmail provider \(e.g., Gmail\) |
|
||||||
| `mx_records` | boolean | Whether MX records exist for the domain |
|
| `mx_records` | boolean | Whether MX records exist for the domain |
|
||||||
| `smtp_server` | boolean | Whether the SMTP server is reachable |
|
| `smtp_server` | boolean | Whether connection to the SMTP server was successful |
|
||||||
| `smtp_check` | boolean | Whether the SMTP check was successful |
|
| `smtp_check` | boolean | Whether the email address doesn't bounce |
|
||||||
| `accept_all` | boolean | Whether the domain accepts all email addresses |
|
| `accept_all` | boolean | Whether the server accepts all email addresses \(may cause false positives\) |
|
||||||
| `block` | boolean | Whether the email is blocked |
|
| `block` | boolean | Whether the domain is blocking verification \(validity could not be determined\) |
|
||||||
| `status` | string | Verification status: valid, invalid, accept_all, webmail, disposable, or unknown |
|
| `status` | string | Verification status: valid, invalid, accept_all, webmail, disposable, unknown, or blocked |
|
||||||
| `sources` | array | Array of sources where the email was found |
|
|
||||||
|
|
||||||
### `hunter_companies_find`
|
### `hunter_companies_find`
|
||||||
|
|
||||||
@@ -163,8 +200,15 @@ Enriches company data using domain name.
|
|||||||
|
|
||||||
| Parameter | Type | Description |
|
| Parameter | Type | Description |
|
||||||
| --------- | ---- | ----------- |
|
| --------- | ---- | ----------- |
|
||||||
|
| `company` | object | Company information |
|
||||||
|
| ↳ `name` | string | Company name |
|
||||||
|
| ↳ `domain` | string | Company domain |
|
||||||
|
| ↳ `industry` | string | Industry classification |
|
||||||
|
| ↳ `size` | string | Company size/headcount range |
|
||||||
|
| ↳ `country` | string | Country where the company is located |
|
||||||
|
| ↳ `linkedin` | string | LinkedIn company page URL |
|
||||||
|
| ↳ `twitter` | string | Twitter handle |
|
||||||
| `person` | object | Person information \(undefined for companies_find tool\) |
|
| `person` | object | Person information \(undefined for companies_find tool\) |
|
||||||
| `company` | object | Company information including name, domain, industry, size, country, linkedin, and twitter |
|
|
||||||
|
|
||||||
### `hunter_email_count`
|
### `hunter_email_count`
|
||||||
|
|
||||||
@@ -183,10 +227,27 @@ Returns the total number of email addresses found for a domain or company.
|
|||||||
|
|
||||||
| Parameter | Type | Description |
|
| Parameter | Type | Description |
|
||||||
| --------- | ---- | ----------- |
|
| --------- | ---- | ----------- |
|
||||||
|
| `department` | object | Email count breakdown by department |
|
||||||
|
| ↳ `executive` | number | Number of executive department emails |
|
||||||
|
| ↳ `it` | number | Number of IT department emails |
|
||||||
|
| ↳ `finance` | number | Number of finance department emails |
|
||||||
|
| ↳ `management` | number | Number of management department emails |
|
||||||
|
| ↳ `sales` | number | Number of sales department emails |
|
||||||
|
| ↳ `legal` | number | Number of legal department emails |
|
||||||
|
| ↳ `support` | number | Number of support department emails |
|
||||||
|
| ↳ `hr` | number | Number of HR department emails |
|
||||||
|
| ↳ `marketing` | number | Number of marketing department emails |
|
||||||
|
| ↳ `communication` | number | Number of communication department emails |
|
||||||
|
| ↳ `education` | number | Number of education department emails |
|
||||||
|
| ↳ `design` | number | Number of design department emails |
|
||||||
|
| ↳ `health` | number | Number of health department emails |
|
||||||
|
| ↳ `operations` | number | Number of operations department emails |
|
||||||
|
| `seniority` | object | Email count breakdown by seniority level |
|
||||||
|
| ↳ `junior` | number | Number of junior-level emails |
|
||||||
|
| ↳ `senior` | number | Number of senior-level emails |
|
||||||
|
| ↳ `executive` | number | Number of executive-level emails |
|
||||||
| `total` | number | Total number of email addresses found |
|
| `total` | number | Total number of email addresses found |
|
||||||
| `personal_emails` | number | Number of personal email addresses found |
|
| `personal_emails` | number | Number of personal email addresses \(individual employees\) |
|
||||||
| `generic_emails` | number | Number of generic email addresses found |
|
| `generic_emails` | number | Number of generic/role-based email addresses \(e.g., contact@, info@\) |
|
||||||
| `department` | object | Breakdown of email addresses by department \(executive, it, finance, management, sales, legal, support, hr, marketing, communication\) |
|
|
||||||
| `seniority` | object | Breakdown of email addresses by seniority level \(junior, senior, executive\) |
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -58,32 +58,36 @@ List incidents from incident.io. Returns a list of incidents with their details
|
|||||||
| --------- | ---- | ----------- |
|
| --------- | ---- | ----------- |
|
||||||
| `incidents` | array | List of incidents |
|
| `incidents` | array | List of incidents |
|
||||||
| ↳ `id` | string | Incident ID |
|
| ↳ `id` | string | Incident ID |
|
||||||
| ↳ `name` | string | Incident name |
|
| ↳ `name` | string | Incident name/title |
|
||||||
| ↳ `summary` | string | Brief summary of the incident |
|
| ↳ `summary` | string | Incident summary |
|
||||||
| ↳ `description` | string | Detailed description of the incident |
|
| ↳ `description` | string | Incident description |
|
||||||
| ↳ `mode` | string | Incident mode \(e.g., standard, retrospective\) |
|
| ↳ `mode` | string | Incident mode \(standard, retrospective, test\) |
|
||||||
| ↳ `call_url` | string | URL for the incident call/bridge |
|
| ↳ `call_url` | string | Video call URL |
|
||||||
| ↳ `severity` | object | Severity of the incident |
|
| ↳ `severity` | object | Incident severity |
|
||||||
| ↳ `id` | string | Severity ID |
|
| ↳ `id` | string | Severity ID |
|
||||||
| ↳ `name` | string | Severity name |
|
| ↳ `name` | string | Severity name \(e.g., Critical, Major, Minor\) |
|
||||||
| ↳ `rank` | number | Severity rank |
|
| ↳ `description` | string | Severity description |
|
||||||
| ↳ `status` | object | Current status of the incident |
|
| ↳ `rank` | number | Severity rank \(lower = more severe\) |
|
||||||
|
| ↳ `status` | object | Current incident status |
|
||||||
| ↳ `id` | string | Status ID |
|
| ↳ `id` | string | Status ID |
|
||||||
| ↳ `name` | string | Status name |
|
| ↳ `name` | string | Status name |
|
||||||
| ↳ `category` | string | Status category |
|
| ↳ `description` | string | Status description |
|
||||||
| ↳ `incident_type` | object | Type of the incident |
|
| ↳ `category` | string | Status category \(triage, active, post-incident, closed\) |
|
||||||
| ↳ `id` | string | Type ID |
|
| ↳ `incident_type` | object | Incident type |
|
||||||
| ↳ `name` | string | Type name |
|
| ↳ `id` | string | Incident type ID |
|
||||||
| ↳ `created_at` | string | Creation timestamp |
|
| ↳ `name` | string | Incident type name |
|
||||||
| ↳ `updated_at` | string | Last update timestamp |
|
| ↳ `description` | string | Incident type description |
|
||||||
| ↳ `incident_url` | string | URL to the incident |
|
| ↳ `is_default` | boolean | Whether this is the default incident type |
|
||||||
| ↳ `slack_channel_id` | string | Associated Slack channel ID |
|
| ↳ `created_at` | string | When the incident was created \(ISO 8601\) |
|
||||||
| ↳ `slack_channel_name` | string | Associated Slack channel name |
|
| ↳ `updated_at` | string | When the incident was last updated \(ISO 8601\) |
|
||||||
| ↳ `visibility` | string | Incident visibility |
|
| ↳ `incident_url` | string | URL to the incident page |
|
||||||
|
| ↳ `slack_channel_id` | string | Slack channel ID |
|
||||||
|
| ↳ `slack_channel_name` | string | Slack channel name |
|
||||||
|
| ↳ `visibility` | string | Incident visibility \(public, private\) |
|
||||||
| `pagination_meta` | object | Pagination metadata |
|
| `pagination_meta` | object | Pagination metadata |
|
||||||
| ↳ `after` | string | Cursor for the next page |
|
| ↳ `after` | string | Cursor for next page |
|
||||||
| ↳ `page_size` | number | Number of items per page |
|
| ↳ `page_size` | number | Number of items per page |
|
||||||
| ↳ `total_record_count` | number | Total number of records available |
|
| ↳ `total_record_count` | number | Total number of records |
|
||||||
|
|
||||||
### `incidentio_incidents_create`
|
### `incidentio_incidents_create`
|
||||||
|
|
||||||
|
|||||||
@@ -126,21 +126,61 @@ Get a single contact by ID from Intercom. Returns API-aligned fields only.
|
|||||||
| ↳ `type` | string | Object type \(contact\) |
|
| ↳ `type` | string | Object type \(contact\) |
|
||||||
| ↳ `role` | string | Role of the contact \(user or lead\) |
|
| ↳ `role` | string | Role of the contact \(user or lead\) |
|
||||||
| ↳ `email` | string | Email address of the contact |
|
| ↳ `email` | string | Email address of the contact |
|
||||||
|
| ↳ `email_domain` | string | Email domain of the contact |
|
||||||
| ↳ `phone` | string | Phone number of the contact |
|
| ↳ `phone` | string | Phone number of the contact |
|
||||||
| ↳ `name` | string | Name of the contact |
|
| ↳ `name` | string | Name of the contact |
|
||||||
| ↳ `avatar` | string | Avatar URL of the contact |
|
| ↳ `avatar` | string | Avatar URL of the contact |
|
||||||
| ↳ `owner_id` | string | ID of the admin assigned to this contact |
|
| ↳ `owner_id` | string | ID of the admin assigned account ownership |
|
||||||
| ↳ `external_id` | string | External identifier for the contact |
|
| ↳ `external_id` | string | External identifier provided by the client |
|
||||||
|
| ↳ `workspace_id` | string | Workspace ID the contact belongs to |
|
||||||
| ↳ `created_at` | number | Unix timestamp when contact was created |
|
| ↳ `created_at` | number | Unix timestamp when contact was created |
|
||||||
| ↳ `updated_at` | number | Unix timestamp when contact was last updated |
|
| ↳ `updated_at` | number | Unix timestamp when contact was last updated |
|
||||||
| ↳ `workspace_id` | string | Workspace ID the contact belongs to |
|
| ↳ `signed_up_at` | number | Unix timestamp when user signed up |
|
||||||
| ↳ `custom_attributes` | object | Custom attributes set on the contact |
|
| ↳ `last_seen_at` | number | Unix timestamp when user was last seen |
|
||||||
| ↳ `tags` | object | Tags associated with the contact |
|
| ↳ `last_contacted_at` | number | Unix timestamp when contact was last contacted |
|
||||||
| ↳ `notes` | object | Notes associated with the contact |
|
| ↳ `last_replied_at` | number | Unix timestamp when contact last replied |
|
||||||
| ↳ `companies` | object | Companies associated with the contact |
|
| ↳ `last_email_opened_at` | number | Unix timestamp when contact last opened an email |
|
||||||
| ↳ `location` | object | Location information for the contact |
|
| ↳ `last_email_clicked_at` | number | Unix timestamp when contact last clicked an email link |
|
||||||
| ↳ `social_profiles` | object | Social profiles of the contact |
|
| ↳ `has_hard_bounced` | boolean | Whether email to this contact has hard bounced |
|
||||||
|
| ↳ `marked_email_as_spam` | boolean | Whether contact marked email as spam |
|
||||||
| ↳ `unsubscribed_from_emails` | boolean | Whether contact is unsubscribed from emails |
|
| ↳ `unsubscribed_from_emails` | boolean | Whether contact is unsubscribed from emails |
|
||||||
|
| ↳ `browser` | string | Browser used by contact |
|
||||||
|
| ↳ `browser_version` | string | Browser version |
|
||||||
|
| ↳ `browser_language` | string | Browser language setting |
|
||||||
|
| ↳ `os` | string | Operating system |
|
||||||
|
| ↳ `language_override` | string | Language override setting |
|
||||||
|
| ↳ `custom_attributes` | object | Custom attributes set on the contact |
|
||||||
|
| ↳ `tags` | object | Tags associated with the contact \(up to 10 displayed\) |
|
||||||
|
| ↳ `type` | string | List type identifier |
|
||||||
|
| ↳ `url` | string | URL to fetch full list |
|
||||||
|
| ↳ `data` | array | Array of objects \(up to 10\) |
|
||||||
|
| ↳ `has_more` | boolean | Whether there are more items beyond this list |
|
||||||
|
| ↳ `total_count` | number | Total number of items |
|
||||||
|
| ↳ `notes` | object | Notes associated with the contact \(up to 10 displayed\) |
|
||||||
|
| ↳ `type` | string | List type identifier |
|
||||||
|
| ↳ `url` | string | URL to fetch full list |
|
||||||
|
| ↳ `data` | array | Array of objects \(up to 10\) |
|
||||||
|
| ↳ `has_more` | boolean | Whether there are more items beyond this list |
|
||||||
|
| ↳ `total_count` | number | Total number of items |
|
||||||
|
| ↳ `companies` | object | Companies associated with the contact \(up to 10 displayed\) |
|
||||||
|
| ↳ `type` | string | List type identifier |
|
||||||
|
| ↳ `url` | string | URL to fetch full list |
|
||||||
|
| ↳ `data` | array | Array of objects \(up to 10\) |
|
||||||
|
| ↳ `has_more` | boolean | Whether there are more items beyond this list |
|
||||||
|
| ↳ `total_count` | number | Total number of items |
|
||||||
|
| ↳ `location` | object | Location information for the contact |
|
||||||
|
| ↳ `type` | string | Object type \(location\) |
|
||||||
|
| ↳ `city` | string | City name |
|
||||||
|
| ↳ `region` | string | Region or state name |
|
||||||
|
| ↳ `country` | string | Country name |
|
||||||
|
| ↳ `country_code` | string | ISO country code |
|
||||||
|
| ↳ `continent_code` | string | Continent code |
|
||||||
|
| ↳ `social_profiles` | object | Social profiles of the contact |
|
||||||
|
| ↳ `type` | string | Social network type \(e.g., twitter, facebook\) |
|
||||||
|
| ↳ `name` | string | Social network name |
|
||||||
|
| ↳ `url` | string | Profile URL |
|
||||||
|
| ↳ `username` | string | Username on the social network |
|
||||||
|
| ↳ `id` | string | User ID on the social network |
|
||||||
|
|
||||||
### `intercom_update_contact`
|
### `intercom_update_contact`
|
||||||
|
|
||||||
|
|||||||
@@ -91,5 +91,11 @@ Search the web and return top 5 results with LLM-friendly content. Each result i
|
|||||||
| Parameter | Type | Description |
|
| Parameter | Type | Description |
|
||||||
| --------- | ---- | ----------- |
|
| --------- | ---- | ----------- |
|
||||||
| `results` | array | Array of search results, each containing title, description, url, and LLM-friendly content |
|
| `results` | array | Array of search results, each containing title, description, url, and LLM-friendly content |
|
||||||
|
| ↳ `title` | string | Page title |
|
||||||
|
| ↳ `description` | string | Page description or meta description |
|
||||||
|
| ↳ `url` | string | Page URL |
|
||||||
|
| ↳ `content` | string | LLM-friendly extracted content |
|
||||||
|
| ↳ `usage` | object | Token usage information |
|
||||||
|
| ↳ `tokens` | number | Number of tokens consumed by this request |
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -53,6 +53,33 @@ Retrieve a list of prediction markets from Kalshi with all filtering options (V2
|
|||||||
| Parameter | Type | Description |
|
| Parameter | Type | Description |
|
||||||
| --------- | ---- | ----------- |
|
| --------- | ---- | ----------- |
|
||||||
| `markets` | array | Array of market objects with all API fields |
|
| `markets` | array | Array of market objects with all API fields |
|
||||||
|
| ↳ `ticker` | string | Unique market ticker identifier |
|
||||||
|
| ↳ `event_ticker` | string | Parent event ticker |
|
||||||
|
| ↳ `market_type` | string | Market type \(binary, etc.\) |
|
||||||
|
| ↳ `title` | string | Market title/question |
|
||||||
|
| ↳ `subtitle` | string | Market subtitle |
|
||||||
|
| ↳ `yes_sub_title` | string | Yes outcome subtitle |
|
||||||
|
| ↳ `no_sub_title` | string | No outcome subtitle |
|
||||||
|
| ↳ `open_time` | string | Market open time \(ISO 8601\) |
|
||||||
|
| ↳ `close_time` | string | Market close time \(ISO 8601\) |
|
||||||
|
| ↳ `expiration_time` | string | Contract expiration time |
|
||||||
|
| ↳ `status` | string | Market status \(open, closed, settled, etc.\) |
|
||||||
|
| ↳ `yes_bid` | number | Current best yes bid price in cents |
|
||||||
|
| ↳ `yes_ask` | number | Current best yes ask price in cents |
|
||||||
|
| ↳ `no_bid` | number | Current best no bid price in cents |
|
||||||
|
| ↳ `no_ask` | number | Current best no ask price in cents |
|
||||||
|
| ↳ `last_price` | number | Last trade price in cents |
|
||||||
|
| ↳ `previous_yes_bid` | number | Previous yes bid |
|
||||||
|
| ↳ `previous_yes_ask` | number | Previous yes ask |
|
||||||
|
| ↳ `previous_price` | number | Previous last price |
|
||||||
|
| ↳ `volume` | number | Total volume \(contracts traded\) |
|
||||||
|
| ↳ `volume_24h` | number | 24-hour trading volume |
|
||||||
|
| ↳ `liquidity` | number | Market liquidity measure |
|
||||||
|
| ↳ `open_interest` | number | Open interest \(outstanding contracts\) |
|
||||||
|
| ↳ `result` | string | Settlement result \(yes, no, null\) |
|
||||||
|
| ↳ `cap_strike` | number | Cap strike for ranged markets |
|
||||||
|
| ↳ `floor_strike` | number | Floor strike for ranged markets |
|
||||||
|
| ↳ `category` | string | Market category |
|
||||||
| `cursor` | string | Pagination cursor for fetching more results |
|
| `cursor` | string | Pagination cursor for fetching more results |
|
||||||
|
|
||||||
### `kalshi_get_market`
|
### `kalshi_get_market`
|
||||||
@@ -141,7 +168,19 @@ Retrieve a list of events from Kalshi with optional filtering (V2 - exact API re
|
|||||||
| Parameter | Type | Description |
|
| Parameter | Type | Description |
|
||||||
| --------- | ---- | ----------- |
|
| --------- | ---- | ----------- |
|
||||||
| `events` | array | Array of event objects |
|
| `events` | array | Array of event objects |
|
||||||
|
| ↳ `event_ticker` | string | Unique event ticker identifier |
|
||||||
|
| ↳ `series_ticker` | string | Parent series ticker |
|
||||||
|
| ↳ `title` | string | Event title |
|
||||||
|
| ↳ `sub_title` | string | Event subtitle |
|
||||||
|
| ↳ `mutually_exclusive` | boolean | Whether markets are mutually exclusive |
|
||||||
|
| ↳ `category` | string | Event category |
|
||||||
|
| ↳ `strike_date` | string | Strike/settlement date |
|
||||||
|
| ↳ `status` | string | Event status |
|
||||||
| `milestones` | array | Array of milestone objects \(if requested\) |
|
| `milestones` | array | Array of milestone objects \(if requested\) |
|
||||||
|
| ↳ `event_ticker` | string | Event ticker |
|
||||||
|
| ↳ `milestone_type` | string | Milestone type |
|
||||||
|
| ↳ `milestone_date` | string | Milestone date |
|
||||||
|
| ↳ `milestone_title` | string | Milestone title |
|
||||||
| `cursor` | string | Pagination cursor for fetching more results |
|
| `cursor` | string | Pagination cursor for fetching more results |
|
||||||
|
|
||||||
### `kalshi_get_event`
|
### `kalshi_get_event`
|
||||||
@@ -213,7 +252,21 @@ Retrieve your open positions from Kalshi (V2 - exact API response)
|
|||||||
| Parameter | Type | Description |
|
| Parameter | Type | Description |
|
||||||
| --------- | ---- | ----------- |
|
| --------- | ---- | ----------- |
|
||||||
| `market_positions` | array | Array of market position objects |
|
| `market_positions` | array | Array of market position objects |
|
||||||
|
| ↳ `ticker` | string | Market ticker |
|
||||||
|
| ↳ `event_ticker` | string | Event ticker |
|
||||||
|
| ↳ `event_title` | string | Event title |
|
||||||
|
| ↳ `market_title` | string | Market title |
|
||||||
|
| ↳ `position` | number | Net position \(positive=yes, negative=no\) |
|
||||||
|
| ↳ `market_exposure` | number | Maximum potential loss in cents |
|
||||||
|
| ↳ `realized_pnl` | number | Realized profit/loss in cents |
|
||||||
|
| ↳ `total_traded` | number | Total contracts traded |
|
||||||
|
| ↳ `resting_orders_count` | number | Number of resting orders |
|
||||||
|
| ↳ `fees_paid` | number | Total fees paid in cents |
|
||||||
| `event_positions` | array | Array of event position objects |
|
| `event_positions` | array | Array of event position objects |
|
||||||
|
| ↳ `event_ticker` | string | Event ticker |
|
||||||
|
| ↳ `event_exposure` | number | Event-level exposure in cents |
|
||||||
|
| ↳ `realized_pnl` | number | Realized P&L in cents |
|
||||||
|
| ↳ `total_cost` | number | Total cost basis in cents |
|
||||||
| `cursor` | string | Pagination cursor for fetching more results |
|
| `cursor` | string | Pagination cursor for fetching more results |
|
||||||
|
|
||||||
### `kalshi_get_orders`
|
### `kalshi_get_orders`
|
||||||
@@ -237,6 +290,24 @@ Retrieve your orders from Kalshi with optional filtering (V2 with full API respo
|
|||||||
| Parameter | Type | Description |
|
| Parameter | Type | Description |
|
||||||
| --------- | ---- | ----------- |
|
| --------- | ---- | ----------- |
|
||||||
| `orders` | array | Array of order objects with full API response fields |
|
| `orders` | array | Array of order objects with full API response fields |
|
||||||
|
| ↳ `order_id` | string | Unique order identifier |
|
||||||
|
| ↳ `user_id` | string | User ID |
|
||||||
|
| ↳ `client_order_id` | string | Client-provided order ID |
|
||||||
|
| ↳ `ticker` | string | Market ticker |
|
||||||
|
| ↳ `side` | string | Order side \(yes/no\) |
|
||||||
|
| ↳ `action` | string | Order action \(buy/sell\) |
|
||||||
|
| ↳ `type` | string | Order type \(limit/market\) |
|
||||||
|
| ↳ `status` | string | Order status \(resting, canceled, executed\) |
|
||||||
|
| ↳ `yes_price` | number | Yes price in cents |
|
||||||
|
| ↳ `no_price` | number | No price in cents |
|
||||||
|
| ↳ `fill_count` | number | Number of contracts filled |
|
||||||
|
| ↳ `remaining_count` | number | Remaining contracts to fill |
|
||||||
|
| ↳ `initial_count` | number | Initial order size |
|
||||||
|
| ↳ `taker_fees` | number | Taker fees paid in cents |
|
||||||
|
| ↳ `maker_fees` | number | Maker fees paid in cents |
|
||||||
|
| ↳ `created_time` | string | Order creation time \(ISO 8601\) |
|
||||||
|
| ↳ `expiration_time` | string | Order expiration time |
|
||||||
|
| ↳ `last_update_time` | string | Last order update time |
|
||||||
| `cursor` | string | Pagination cursor for fetching more results |
|
| `cursor` | string | Pagination cursor for fetching more results |
|
||||||
|
|
||||||
### `kalshi_get_order`
|
### `kalshi_get_order`
|
||||||
@@ -329,6 +400,12 @@ Retrieve recent trades with additional filtering options (V2 - includes trade_id
|
|||||||
| Parameter | Type | Description |
|
| Parameter | Type | Description |
|
||||||
| --------- | ---- | ----------- |
|
| --------- | ---- | ----------- |
|
||||||
| `trades` | array | Array of trade objects with trade_id and count_fp |
|
| `trades` | array | Array of trade objects with trade_id and count_fp |
|
||||||
|
| ↳ `ticker` | string | Market ticker |
|
||||||
|
| ↳ `yes_price` | number | Trade price for yes in cents |
|
||||||
|
| ↳ `no_price` | number | Trade price for no in cents |
|
||||||
|
| ↳ `count` | number | Number of contracts traded |
|
||||||
|
| ↳ `taker_side` | string | Taker side \(yes/no\) |
|
||||||
|
| ↳ `created_time` | string | Trade time \(ISO 8601\) |
|
||||||
| `cursor` | string | Pagination cursor for fetching more results |
|
| `cursor` | string | Pagination cursor for fetching more results |
|
||||||
|
|
||||||
### `kalshi_get_candlesticks`
|
### `kalshi_get_candlesticks`
|
||||||
@@ -374,6 +451,16 @@ Retrieve your portfolio
|
|||||||
| Parameter | Type | Description |
|
| Parameter | Type | Description |
|
||||||
| --------- | ---- | ----------- |
|
| --------- | ---- | ----------- |
|
||||||
| `fills` | array | Array of fill/trade objects with all API fields |
|
| `fills` | array | Array of fill/trade objects with all API fields |
|
||||||
|
| ↳ `trade_id` | string | Unique trade identifier |
|
||||||
|
| ↳ `order_id` | string | Associated order ID |
|
||||||
|
| ↳ `ticker` | string | Market ticker |
|
||||||
|
| ↳ `side` | string | Trade side \(yes/no\) |
|
||||||
|
| ↳ `action` | string | Trade action \(buy/sell\) |
|
||||||
|
| ↳ `count` | number | Number of contracts |
|
||||||
|
| ↳ `yes_price` | number | Yes price in cents |
|
||||||
|
| ↳ `no_price` | number | No price in cents |
|
||||||
|
| ↳ `is_taker` | boolean | Whether this was a taker trade |
|
||||||
|
| ↳ `created_time` | string | Trade execution time \(ISO 8601\) |
|
||||||
| `cursor` | string | Pagination cursor for fetching more results |
|
| `cursor` | string | Pagination cursor for fetching more results |
|
||||||
|
|
||||||
### `kalshi_get_series_by_ticker`
|
### `kalshi_get_series_by_ticker`
|
||||||
|
|||||||
@@ -59,18 +59,27 @@ Fetch and filter issues from Linear
|
|||||||
|
|
||||||
| Parameter | Type | Description |
|
| Parameter | Type | Description |
|
||||||
| --------- | ---- | ----------- |
|
| --------- | ---- | ----------- |
|
||||||
|
| `hasNextPage` | boolean | Whether there are more results |
|
||||||
|
| `endCursor` | string | Cursor for the next page |
|
||||||
| `issues` | array | Array of filtered issues from Linear |
|
| `issues` | array | Array of filtered issues from Linear |
|
||||||
| ↳ `id` | string | Issue ID |
|
| ↳ `id` | string | Issue ID |
|
||||||
| ↳ `title` | string | Issue title |
|
| ↳ `title` | string | Issue title |
|
||||||
| ↳ `description` | string | Issue description |
|
| ↳ `description` | string | Issue description |
|
||||||
| ↳ `priority` | number | Issue priority |
|
| ↳ `priority` | number | Priority \(0=No priority, 1=Urgent, 2=High, 3=Normal, 4=Low\) |
|
||||||
| ↳ `estimate` | number | Issue estimate |
|
| ↳ `estimate` | number | Estimate in points |
|
||||||
| ↳ `url` | string | Issue URL |
|
| ↳ `url` | string | Issue URL |
|
||||||
| ↳ `dueDate` | string | Due date \(YYYY-MM-DD\) |
|
| ↳ `dueDate` | string | Due date \(YYYY-MM-DD\) |
|
||||||
| ↳ `createdAt` | string | Creation timestamp |
|
| ↳ `createdAt` | string | Creation timestamp \(ISO 8601\) |
|
||||||
| ↳ `updatedAt` | string | Last update timestamp |
|
| ↳ `updatedAt` | string | Last update timestamp \(ISO 8601\) |
|
||||||
| ↳ `state` | object | Issue state |
|
| ↳ `archivedAt` | string | Archive timestamp \(ISO 8601\) |
|
||||||
| ↳ `assignee` | object | Assigned user |
|
| ↳ `state` | object | Workflow state/status |
|
||||||
|
| ↳ `id` | string | State ID |
|
||||||
|
| ↳ `name` | string | State name \(e.g., "Todo", "In Progress"\) |
|
||||||
|
| ↳ `type` | string | State type \(unstarted, started, completed, canceled\) |
|
||||||
|
| ↳ `assignee` | object | User object |
|
||||||
|
| ↳ `id` | string | User ID |
|
||||||
|
| ↳ `name` | string | User name |
|
||||||
|
| ↳ `email` | string | User email |
|
||||||
| ↳ `teamId` | string | Team ID |
|
| ↳ `teamId` | string | Team ID |
|
||||||
| ↳ `teamName` | string | Team name |
|
| ↳ `teamName` | string | Team name |
|
||||||
| ↳ `projectId` | string | Project ID |
|
| ↳ `projectId` | string | Project ID |
|
||||||
@@ -79,8 +88,9 @@ Fetch and filter issues from Linear
|
|||||||
| ↳ `cycleNumber` | number | Cycle number |
|
| ↳ `cycleNumber` | number | Cycle number |
|
||||||
| ↳ `cycleName` | string | Cycle name |
|
| ↳ `cycleName` | string | Cycle name |
|
||||||
| ↳ `labels` | array | Issue labels |
|
| ↳ `labels` | array | Issue labels |
|
||||||
| `hasNextPage` | boolean | Whether there are more results available |
|
| ↳ `id` | string | Label ID |
|
||||||
| `endCursor` | string | Cursor for fetching the next page \(use as |
|
| ↳ `name` | string | Label name |
|
||||||
|
| ↳ `color` | string | Label color \(hex\) |
|
||||||
|
|
||||||
### `linear_get_issue`
|
### `linear_get_issue`
|
||||||
|
|
||||||
@@ -100,14 +110,29 @@ Get a single issue by ID from Linear with full details
|
|||||||
| ↳ `id` | string | Issue ID |
|
| ↳ `id` | string | Issue ID |
|
||||||
| ↳ `title` | string | Issue title |
|
| ↳ `title` | string | Issue title |
|
||||||
| ↳ `description` | string | Issue description |
|
| ↳ `description` | string | Issue description |
|
||||||
| ↳ `priority` | number | Issue priority \(0-4\) |
|
| ↳ `priority` | number | Priority \(0=No priority, 1=Urgent, 2=High, 3=Normal, 4=Low\) |
|
||||||
| ↳ `estimate` | number | Issue estimate in points |
|
| ↳ `estimate` | number | Estimate in points |
|
||||||
| ↳ `url` | string | Issue URL |
|
| ↳ `url` | string | Issue URL |
|
||||||
| ↳ `state` | object | Issue state/status |
|
| ↳ `dueDate` | string | Due date \(YYYY-MM-DD\) |
|
||||||
| ↳ `assignee` | object | Assigned user |
|
| ↳ `createdAt` | string | Creation timestamp \(ISO 8601\) |
|
||||||
|
| ↳ `updatedAt` | string | Last update timestamp \(ISO 8601\) |
|
||||||
|
| ↳ `completedAt` | string | Completion timestamp \(ISO 8601\) |
|
||||||
|
| ↳ `canceledAt` | string | Cancellation timestamp \(ISO 8601\) |
|
||||||
|
| ↳ `archivedAt` | string | Archive timestamp \(ISO 8601\) |
|
||||||
|
| ↳ `state` | object | Workflow state/status |
|
||||||
|
| ↳ `id` | string | State ID |
|
||||||
|
| ↳ `name` | string | State name \(e.g., "Todo", "In Progress"\) |
|
||||||
|
| ↳ `type` | string | State type \(unstarted, started, completed, canceled\) |
|
||||||
|
| ↳ `assignee` | object | User object |
|
||||||
|
| ↳ `id` | string | User ID |
|
||||||
|
| ↳ `name` | string | User name |
|
||||||
|
| ↳ `email` | string | User email |
|
||||||
|
| ↳ `teamId` | string | Team ID |
|
||||||
|
| ↳ `projectId` | string | Project ID |
|
||||||
| ↳ `labels` | array | Issue labels |
|
| ↳ `labels` | array | Issue labels |
|
||||||
| ↳ `createdAt` | string | Creation timestamp |
|
| ↳ `id` | string | Label ID |
|
||||||
| ↳ `updatedAt` | string | Last update timestamp |
|
| ↳ `name` | string | Label name |
|
||||||
|
| ↳ `color` | string | Label color \(hex\) |
|
||||||
|
|
||||||
### `linear_create_issue`
|
### `linear_create_issue`
|
||||||
|
|
||||||
@@ -140,14 +165,29 @@ Create a new issue in Linear
|
|||||||
| ↳ `id` | string | Issue ID |
|
| ↳ `id` | string | Issue ID |
|
||||||
| ↳ `title` | string | Issue title |
|
| ↳ `title` | string | Issue title |
|
||||||
| ↳ `description` | string | Issue description |
|
| ↳ `description` | string | Issue description |
|
||||||
| ↳ `priority` | number | Issue priority |
|
| ↳ `priority` | number | Priority \(0=No priority, 1=Urgent, 2=High, 3=Normal, 4=Low\) |
|
||||||
| ↳ `estimate` | number | Issue estimate |
|
| ↳ `estimate` | number | Estimate in points |
|
||||||
| ↳ `url` | string | Issue URL |
|
| ↳ `url` | string | Issue URL |
|
||||||
| ↳ `dueDate` | string | Due date \(YYYY-MM-DD\) |
|
| ↳ `dueDate` | string | Due date \(YYYY-MM-DD\) |
|
||||||
| ↳ `state` | object | Issue state |
|
| ↳ `createdAt` | string | Creation timestamp \(ISO 8601\) |
|
||||||
| ↳ `assignee` | object | Assigned user |
|
| ↳ `updatedAt` | string | Last update timestamp \(ISO 8601\) |
|
||||||
|
| ↳ `completedAt` | string | Completion timestamp \(ISO 8601\) |
|
||||||
|
| ↳ `canceledAt` | string | Cancellation timestamp \(ISO 8601\) |
|
||||||
|
| ↳ `archivedAt` | string | Archive timestamp \(ISO 8601\) |
|
||||||
|
| ↳ `state` | object | Workflow state/status |
|
||||||
|
| ↳ `id` | string | State ID |
|
||||||
|
| ↳ `name` | string | State name \(e.g., "Todo", "In Progress"\) |
|
||||||
|
| ↳ `type` | string | State type \(unstarted, started, completed, canceled\) |
|
||||||
|
| ↳ `assignee` | object | User object |
|
||||||
|
| ↳ `id` | string | User ID |
|
||||||
|
| ↳ `name` | string | User name |
|
||||||
|
| ↳ `email` | string | User email |
|
||||||
| ↳ `teamId` | string | Team ID |
|
| ↳ `teamId` | string | Team ID |
|
||||||
| ↳ `projectId` | string | Project ID |
|
| ↳ `projectId` | string | Project ID |
|
||||||
|
| ↳ `labels` | array | Issue labels |
|
||||||
|
| ↳ `id` | string | Label ID |
|
||||||
|
| ↳ `name` | string | Label name |
|
||||||
|
| ↳ `color` | string | Label color \(hex\) |
|
||||||
| ↳ `cycleId` | string | Cycle ID |
|
| ↳ `cycleId` | string | Cycle ID |
|
||||||
| ↳ `cycleNumber` | number | Cycle number |
|
| ↳ `cycleNumber` | number | Cycle number |
|
||||||
| ↳ `cycleName` | string | Cycle name |
|
| ↳ `cycleName` | string | Cycle name |
|
||||||
@@ -155,7 +195,6 @@ Create a new issue in Linear
|
|||||||
| ↳ `parentTitle` | string | Parent issue title |
|
| ↳ `parentTitle` | string | Parent issue title |
|
||||||
| ↳ `projectMilestoneId` | string | Project milestone ID |
|
| ↳ `projectMilestoneId` | string | Project milestone ID |
|
||||||
| ↳ `projectMilestoneName` | string | Project milestone name |
|
| ↳ `projectMilestoneName` | string | Project milestone name |
|
||||||
| ↳ `labels` | array | Issue labels |
|
|
||||||
|
|
||||||
### `linear_update_issue`
|
### `linear_update_issue`
|
||||||
|
|
||||||
@@ -188,19 +227,36 @@ Update an existing issue in Linear
|
|||||||
| ↳ `id` | string | Issue ID |
|
| ↳ `id` | string | Issue ID |
|
||||||
| ↳ `title` | string | Issue title |
|
| ↳ `title` | string | Issue title |
|
||||||
| ↳ `description` | string | Issue description |
|
| ↳ `description` | string | Issue description |
|
||||||
| ↳ `priority` | number | Issue priority |
|
| ↳ `priority` | number | Priority \(0=No priority, 1=Urgent, 2=High, 3=Normal, 4=Low\) |
|
||||||
| ↳ `estimate` | number | Issue estimate |
|
| ↳ `estimate` | number | Estimate in points |
|
||||||
| ↳ `state` | object | Issue state |
|
| ↳ `url` | string | Issue URL |
|
||||||
| ↳ `assignee` | object | Assigned user |
|
|
||||||
| ↳ `labels` | array | Issue labels |
|
|
||||||
| ↳ `updatedAt` | string | Last update timestamp |
|
|
||||||
| ↳ `dueDate` | string | Due date \(YYYY-MM-DD\) |
|
| ↳ `dueDate` | string | Due date \(YYYY-MM-DD\) |
|
||||||
|
| ↳ `createdAt` | string | Creation timestamp \(ISO 8601\) |
|
||||||
|
| ↳ `updatedAt` | string | Last update timestamp \(ISO 8601\) |
|
||||||
|
| ↳ `completedAt` | string | Completion timestamp \(ISO 8601\) |
|
||||||
|
| ↳ `canceledAt` | string | Cancellation timestamp \(ISO 8601\) |
|
||||||
|
| ↳ `archivedAt` | string | Archive timestamp \(ISO 8601\) |
|
||||||
|
| ↳ `state` | object | Workflow state/status |
|
||||||
|
| ↳ `id` | string | State ID |
|
||||||
|
| ↳ `name` | string | State name \(e.g., "Todo", "In Progress"\) |
|
||||||
|
| ↳ `type` | string | State type \(unstarted, started, completed, canceled\) |
|
||||||
|
| ↳ `assignee` | object | User object |
|
||||||
|
| ↳ `id` | string | User ID |
|
||||||
|
| ↳ `name` | string | User name |
|
||||||
|
| ↳ `email` | string | User email |
|
||||||
|
| ↳ `teamId` | string | Team ID |
|
||||||
| ↳ `projectId` | string | Project ID |
|
| ↳ `projectId` | string | Project ID |
|
||||||
|
| ↳ `labels` | array | Issue labels |
|
||||||
|
| ↳ `id` | string | Label ID |
|
||||||
|
| ↳ `name` | string | Label name |
|
||||||
|
| ↳ `color` | string | Label color \(hex\) |
|
||||||
| ↳ `cycleId` | string | Cycle ID |
|
| ↳ `cycleId` | string | Cycle ID |
|
||||||
| ↳ `cycleNumber` | number | Cycle number |
|
| ↳ `cycleNumber` | number | Cycle number |
|
||||||
| ↳ `cycleName` | string | Cycle name |
|
| ↳ `cycleName` | string | Cycle name |
|
||||||
| ↳ `parentId` | string | Parent issue ID |
|
| ↳ `parentId` | string | Parent issue ID |
|
||||||
| ↳ `parentTitle` | string | Parent issue title |
|
| ↳ `parentTitle` | string | Parent issue title |
|
||||||
|
| ↳ `projectMilestoneId` | string | Project milestone ID |
|
||||||
|
| ↳ `projectMilestoneName` | string | Project milestone name |
|
||||||
|
|
||||||
### `linear_archive_issue`
|
### `linear_archive_issue`
|
||||||
|
|
||||||
@@ -269,17 +325,36 @@ Search for issues in Linear using full-text search
|
|||||||
|
|
||||||
| Parameter | Type | Description |
|
| Parameter | Type | Description |
|
||||||
| --------- | ---- | ----------- |
|
| --------- | ---- | ----------- |
|
||||||
|
| `pageInfo` | object | Pagination information |
|
||||||
|
| ↳ `hasNextPage` | boolean | Whether there are more results |
|
||||||
|
| ↳ `endCursor` | string | Cursor for the next page |
|
||||||
| `issues` | array | Array of matching issues |
|
| `issues` | array | Array of matching issues |
|
||||||
| ↳ `id` | string | Issue ID |
|
| ↳ `id` | string | Issue ID |
|
||||||
| ↳ `title` | string | Issue title |
|
| ↳ `title` | string | Issue title |
|
||||||
| ↳ `description` | string | Issue description |
|
| ↳ `description` | string | Issue description |
|
||||||
| ↳ `priority` | number | Issue priority |
|
| ↳ `priority` | number | Priority \(0=No priority, 1=Urgent, 2=High, 3=Normal, 4=Low\) |
|
||||||
| ↳ `state` | object | Issue state |
|
| ↳ `estimate` | number | Estimate in points |
|
||||||
| ↳ `assignee` | object | Assigned user |
|
| ↳ `url` | string | Issue URL |
|
||||||
|
| ↳ `dueDate` | string | Due date \(YYYY-MM-DD\) |
|
||||||
|
| ↳ `createdAt` | string | Creation timestamp \(ISO 8601\) |
|
||||||
|
| ↳ `updatedAt` | string | Last update timestamp \(ISO 8601\) |
|
||||||
|
| ↳ `completedAt` | string | Completion timestamp \(ISO 8601\) |
|
||||||
|
| ↳ `canceledAt` | string | Cancellation timestamp \(ISO 8601\) |
|
||||||
|
| ↳ `archivedAt` | string | Archive timestamp \(ISO 8601\) |
|
||||||
|
| ↳ `state` | object | Workflow state/status |
|
||||||
|
| ↳ `id` | string | State ID |
|
||||||
|
| ↳ `name` | string | State name \(e.g., "Todo", "In Progress"\) |
|
||||||
|
| ↳ `type` | string | State type \(unstarted, started, completed, canceled\) |
|
||||||
|
| ↳ `assignee` | object | User object |
|
||||||
|
| ↳ `id` | string | User ID |
|
||||||
|
| ↳ `name` | string | User name |
|
||||||
|
| ↳ `email` | string | User email |
|
||||||
|
| ↳ `teamId` | string | Team ID |
|
||||||
|
| ↳ `projectId` | string | Project ID |
|
||||||
| ↳ `labels` | array | Issue labels |
|
| ↳ `labels` | array | Issue labels |
|
||||||
| `pageInfo` | object | Pagination information |
|
| ↳ `id` | string | Label ID |
|
||||||
| ↳ `hasNextPage` | boolean | Whether there are more results |
|
| ↳ `name` | string | Label name |
|
||||||
| ↳ `endCursor` | string | Cursor for next page |
|
| ↳ `color` | string | Label color \(hex\) |
|
||||||
|
|
||||||
### `linear_add_label_to_issue`
|
### `linear_add_label_to_issue`
|
||||||
|
|
||||||
@@ -334,10 +409,16 @@ Add a comment to an issue in Linear
|
|||||||
| --------- | ---- | ----------- |
|
| --------- | ---- | ----------- |
|
||||||
| `comment` | object | The created comment |
|
| `comment` | object | The created comment |
|
||||||
| ↳ `id` | string | Comment ID |
|
| ↳ `id` | string | Comment ID |
|
||||||
| ↳ `body` | string | Comment text |
|
| ↳ `body` | string | Comment text \(Markdown\) |
|
||||||
| ↳ `createdAt` | string | Creation timestamp |
|
| ↳ `createdAt` | string | Creation timestamp \(ISO 8601\) |
|
||||||
| ↳ `user` | object | User who created the comment |
|
| ↳ `updatedAt` | string | Last update timestamp \(ISO 8601\) |
|
||||||
| ↳ `issue` | object | Associated issue |
|
| ↳ `user` | object | User object |
|
||||||
|
| ↳ `id` | string | User ID |
|
||||||
|
| ↳ `name` | string | User name |
|
||||||
|
| ↳ `email` | string | User email |
|
||||||
|
| ↳ `issue` | object | Issue object |
|
||||||
|
| ↳ `id` | string | Issue ID |
|
||||||
|
| ↳ `title` | string | Issue title |
|
||||||
|
|
||||||
### `linear_update_comment`
|
### `linear_update_comment`
|
||||||
|
|
||||||
@@ -356,9 +437,16 @@ Edit a comment in Linear
|
|||||||
| --------- | ---- | ----------- |
|
| --------- | ---- | ----------- |
|
||||||
| `comment` | object | The updated comment |
|
| `comment` | object | The updated comment |
|
||||||
| ↳ `id` | string | Comment ID |
|
| ↳ `id` | string | Comment ID |
|
||||||
| ↳ `body` | string | Comment text |
|
| ↳ `body` | string | Comment text \(Markdown\) |
|
||||||
| ↳ `updatedAt` | string | Last update timestamp |
|
| ↳ `createdAt` | string | Creation timestamp \(ISO 8601\) |
|
||||||
| ↳ `user` | object | User who created the comment |
|
| ↳ `updatedAt` | string | Last update timestamp \(ISO 8601\) |
|
||||||
|
| ↳ `user` | object | User object |
|
||||||
|
| ↳ `id` | string | User ID |
|
||||||
|
| ↳ `name` | string | User name |
|
||||||
|
| ↳ `email` | string | User email |
|
||||||
|
| ↳ `issue` | object | Issue object |
|
||||||
|
| ↳ `id` | string | Issue ID |
|
||||||
|
| ↳ `title` | string | Issue title |
|
||||||
|
|
||||||
### `linear_delete_comment`
|
### `linear_delete_comment`
|
||||||
|
|
||||||
@@ -392,15 +480,21 @@ List all comments on an issue in Linear
|
|||||||
|
|
||||||
| Parameter | Type | Description |
|
| Parameter | Type | Description |
|
||||||
| --------- | ---- | ----------- |
|
| --------- | ---- | ----------- |
|
||||||
| `comments` | array | Array of comments on the issue |
|
|
||||||
| ↳ `id` | string | Comment ID |
|
|
||||||
| ↳ `body` | string | Comment text |
|
|
||||||
| ↳ `createdAt` | string | Creation timestamp |
|
|
||||||
| ↳ `updatedAt` | string | Last update timestamp |
|
|
||||||
| ↳ `user` | object | User who created the comment |
|
|
||||||
| `pageInfo` | object | Pagination information |
|
| `pageInfo` | object | Pagination information |
|
||||||
| ↳ `hasNextPage` | boolean | Whether there are more results |
|
| ↳ `hasNextPage` | boolean | Whether there are more results |
|
||||||
| ↳ `endCursor` | string | Cursor for next page |
|
| ↳ `endCursor` | string | Cursor for the next page |
|
||||||
|
| `comments` | array | Array of comments on the issue |
|
||||||
|
| ↳ `id` | string | Comment ID |
|
||||||
|
| ↳ `body` | string | Comment text \(Markdown\) |
|
||||||
|
| ↳ `createdAt` | string | Creation timestamp \(ISO 8601\) |
|
||||||
|
| ↳ `updatedAt` | string | Last update timestamp \(ISO 8601\) |
|
||||||
|
| ↳ `user` | object | User object |
|
||||||
|
| ↳ `id` | string | User ID |
|
||||||
|
| ↳ `name` | string | User name |
|
||||||
|
| ↳ `email` | string | User email |
|
||||||
|
| ↳ `issue` | object | Issue object |
|
||||||
|
| ↳ `id` | string | Issue ID |
|
||||||
|
| ↳ `title` | string | Issue title |
|
||||||
|
|
||||||
### `linear_list_projects`
|
### `linear_list_projects`
|
||||||
|
|
||||||
@@ -419,15 +513,25 @@ List projects in Linear with optional filtering
|
|||||||
|
|
||||||
| Parameter | Type | Description |
|
| Parameter | Type | Description |
|
||||||
| --------- | ---- | ----------- |
|
| --------- | ---- | ----------- |
|
||||||
|
| `pageInfo` | object | Pagination information |
|
||||||
|
| ↳ `hasNextPage` | boolean | Whether there are more results |
|
||||||
|
| ↳ `endCursor` | string | Cursor for the next page |
|
||||||
| `projects` | array | Array of projects |
|
| `projects` | array | Array of projects |
|
||||||
| ↳ `id` | string | Project ID |
|
| ↳ `id` | string | Project ID |
|
||||||
| ↳ `name` | string | Project name |
|
| ↳ `name` | string | Project name |
|
||||||
| ↳ `description` | string | Project description |
|
| ↳ `description` | string | Project description |
|
||||||
| ↳ `state` | string | Project state |
|
| ↳ `state` | string | Project state \(planned, started, paused, completed, canceled\) |
|
||||||
| ↳ `priority` | number | Project priority |
|
| ↳ `priority` | number | Project priority \(0-4\) |
|
||||||
| ↳ `lead` | object | Project lead |
|
| ↳ `startDate` | string | Start date \(YYYY-MM-DD\) |
|
||||||
| ↳ `teams` | array | Teams associated with project |
|
| ↳ `targetDate` | string | Target date \(YYYY-MM-DD\) |
|
||||||
| `pageInfo` | object | Pagination information |
|
| ↳ `url` | string | Project URL |
|
||||||
|
| ↳ `lead` | object | User object |
|
||||||
|
| ↳ `id` | string | User ID |
|
||||||
|
| ↳ `name` | string | User name |
|
||||||
|
| ↳ `email` | string | User email |
|
||||||
|
| ↳ `teams` | array | Associated teams |
|
||||||
|
| ↳ `id` | string | Team ID |
|
||||||
|
| ↳ `name` | string | Team name |
|
||||||
|
|
||||||
### `linear_get_project`
|
### `linear_get_project`
|
||||||
|
|
||||||
@@ -447,12 +551,18 @@ Get a single project by ID from Linear
|
|||||||
| ↳ `id` | string | Project ID |
|
| ↳ `id` | string | Project ID |
|
||||||
| ↳ `name` | string | Project name |
|
| ↳ `name` | string | Project name |
|
||||||
| ↳ `description` | string | Project description |
|
| ↳ `description` | string | Project description |
|
||||||
| ↳ `state` | string | Project state |
|
| ↳ `state` | string | Project state \(planned, started, paused, completed, canceled\) |
|
||||||
| ↳ `priority` | number | Project priority |
|
| ↳ `priority` | number | Project priority \(0-4\) |
|
||||||
| ↳ `startDate` | string | Start date |
|
| ↳ `startDate` | string | Start date \(YYYY-MM-DD\) |
|
||||||
| ↳ `targetDate` | string | Target completion date |
|
| ↳ `targetDate` | string | Target date \(YYYY-MM-DD\) |
|
||||||
| ↳ `lead` | object | Project lead |
|
| ↳ `url` | string | Project URL |
|
||||||
|
| ↳ `lead` | object | User object |
|
||||||
|
| ↳ `id` | string | User ID |
|
||||||
|
| ↳ `name` | string | User name |
|
||||||
|
| ↳ `email` | string | User email |
|
||||||
| ↳ `teams` | array | Associated teams |
|
| ↳ `teams` | array | Associated teams |
|
||||||
|
| ↳ `id` | string | Team ID |
|
||||||
|
| ↳ `name` | string | Team name |
|
||||||
|
|
||||||
### `linear_create_project`
|
### `linear_create_project`
|
||||||
|
|
||||||
@@ -478,10 +588,18 @@ Create a new project in Linear
|
|||||||
| ↳ `id` | string | Project ID |
|
| ↳ `id` | string | Project ID |
|
||||||
| ↳ `name` | string | Project name |
|
| ↳ `name` | string | Project name |
|
||||||
| ↳ `description` | string | Project description |
|
| ↳ `description` | string | Project description |
|
||||||
| ↳ `state` | string | Project state |
|
| ↳ `state` | string | Project state \(planned, started, paused, completed, canceled\) |
|
||||||
| ↳ `priority` | number | Project priority |
|
| ↳ `priority` | number | Project priority \(0-4\) |
|
||||||
| ↳ `lead` | object | Project lead |
|
| ↳ `startDate` | string | Start date \(YYYY-MM-DD\) |
|
||||||
|
| ↳ `targetDate` | string | Target date \(YYYY-MM-DD\) |
|
||||||
|
| ↳ `url` | string | Project URL |
|
||||||
|
| ↳ `lead` | object | User object |
|
||||||
|
| ↳ `id` | string | User ID |
|
||||||
|
| ↳ `name` | string | User name |
|
||||||
|
| ↳ `email` | string | User email |
|
||||||
| ↳ `teams` | array | Associated teams |
|
| ↳ `teams` | array | Associated teams |
|
||||||
|
| ↳ `id` | string | Team ID |
|
||||||
|
| ↳ `name` | string | Team name |
|
||||||
|
|
||||||
### `linear_update_project`
|
### `linear_update_project`
|
||||||
|
|
||||||
@@ -508,12 +626,18 @@ Update an existing project in Linear
|
|||||||
| ↳ `id` | string | Project ID |
|
| ↳ `id` | string | Project ID |
|
||||||
| ↳ `name` | string | Project name |
|
| ↳ `name` | string | Project name |
|
||||||
| ↳ `description` | string | Project description |
|
| ↳ `description` | string | Project description |
|
||||||
| ↳ `state` | string | Project state |
|
| ↳ `state` | string | Project state \(planned, started, paused, completed, canceled\) |
|
||||||
| ↳ `priority` | number | Project priority |
|
| ↳ `priority` | number | Project priority \(0-4\) |
|
||||||
| ↳ `startDate` | string | Project start date |
|
| ↳ `startDate` | string | Start date \(YYYY-MM-DD\) |
|
||||||
| ↳ `targetDate` | string | Project target date |
|
| ↳ `targetDate` | string | Target date \(YYYY-MM-DD\) |
|
||||||
| ↳ `lead` | object | Project lead |
|
| ↳ `url` | string | Project URL |
|
||||||
|
| ↳ `lead` | object | User object |
|
||||||
|
| ↳ `id` | string | User ID |
|
||||||
|
| ↳ `name` | string | User name |
|
||||||
|
| ↳ `email` | string | User email |
|
||||||
| ↳ `teams` | array | Associated teams |
|
| ↳ `teams` | array | Associated teams |
|
||||||
|
| ↳ `id` | string | Team ID |
|
||||||
|
| ↳ `name` | string | Team name |
|
||||||
|
|
||||||
### `linear_archive_project`
|
### `linear_archive_project`
|
||||||
|
|
||||||
@@ -548,6 +672,9 @@ List all users in the Linear workspace
|
|||||||
|
|
||||||
| Parameter | Type | Description |
|
| Parameter | Type | Description |
|
||||||
| --------- | ---- | ----------- |
|
| --------- | ---- | ----------- |
|
||||||
|
| `pageInfo` | object | Pagination information |
|
||||||
|
| ↳ `hasNextPage` | boolean | Whether there are more results |
|
||||||
|
| ↳ `endCursor` | string | Cursor for the next page |
|
||||||
| `users` | array | Array of workspace users |
|
| `users` | array | Array of workspace users |
|
||||||
| ↳ `id` | string | User ID |
|
| ↳ `id` | string | User ID |
|
||||||
| ↳ `name` | string | User name |
|
| ↳ `name` | string | User name |
|
||||||
@@ -556,7 +683,6 @@ List all users in the Linear workspace
|
|||||||
| ↳ `active` | boolean | Whether user is active |
|
| ↳ `active` | boolean | Whether user is active |
|
||||||
| ↳ `admin` | boolean | Whether user is admin |
|
| ↳ `admin` | boolean | Whether user is admin |
|
||||||
| ↳ `avatarUrl` | string | Avatar URL |
|
| ↳ `avatarUrl` | string | Avatar URL |
|
||||||
| `pageInfo` | object | Pagination information |
|
|
||||||
|
|
||||||
### `linear_list_teams`
|
### `linear_list_teams`
|
||||||
|
|
||||||
@@ -573,12 +699,14 @@ List all teams in the Linear workspace
|
|||||||
|
|
||||||
| Parameter | Type | Description |
|
| Parameter | Type | Description |
|
||||||
| --------- | ---- | ----------- |
|
| --------- | ---- | ----------- |
|
||||||
|
| `pageInfo` | object | Pagination information |
|
||||||
|
| ↳ `hasNextPage` | boolean | Whether there are more results |
|
||||||
|
| ↳ `endCursor` | string | Cursor for the next page |
|
||||||
| `teams` | array | Array of teams |
|
| `teams` | array | Array of teams |
|
||||||
| ↳ `id` | string | Team ID |
|
| ↳ `id` | string | Team ID |
|
||||||
| ↳ `name` | string | Team name |
|
| ↳ `name` | string | Team name |
|
||||||
| ↳ `key` | string | Team key \(used in issue identifiers\) |
|
| ↳ `key` | string | Team key \(used in issue identifiers\) |
|
||||||
| ↳ `description` | string | Team description |
|
| ↳ `description` | string | Team description |
|
||||||
| `pageInfo` | object | Pagination information |
|
|
||||||
|
|
||||||
### `linear_get_viewer`
|
### `linear_get_viewer`
|
||||||
|
|
||||||
@@ -618,13 +746,17 @@ List all labels in Linear workspace or team
|
|||||||
|
|
||||||
| Parameter | Type | Description |
|
| Parameter | Type | Description |
|
||||||
| --------- | ---- | ----------- |
|
| --------- | ---- | ----------- |
|
||||||
|
| `pageInfo` | object | Pagination information |
|
||||||
|
| ↳ `hasNextPage` | boolean | Whether there are more results |
|
||||||
|
| ↳ `endCursor` | string | Cursor for the next page |
|
||||||
| `labels` | array | Array of labels |
|
| `labels` | array | Array of labels |
|
||||||
| ↳ `id` | string | Label ID |
|
| ↳ `id` | string | Label ID |
|
||||||
| ↳ `name` | string | Label name |
|
| ↳ `name` | string | Label name |
|
||||||
| ↳ `color` | string | Label color \(hex\) |
|
| ↳ `color` | string | Label color \(hex\) |
|
||||||
| ↳ `description` | string | Label description |
|
| ↳ `description` | string | Label description |
|
||||||
| ↳ `team` | object | Team this label belongs to |
|
| ↳ `team` | object | Team object |
|
||||||
| `pageInfo` | object | Pagination information |
|
| ↳ `id` | string | Team ID |
|
||||||
|
| ↳ `name` | string | Team name |
|
||||||
|
|
||||||
### `linear_create_label`
|
### `linear_create_label`
|
||||||
|
|
||||||
@@ -646,9 +778,11 @@ Create a new label in Linear
|
|||||||
| `label` | object | The created label |
|
| `label` | object | The created label |
|
||||||
| ↳ `id` | string | Label ID |
|
| ↳ `id` | string | Label ID |
|
||||||
| ↳ `name` | string | Label name |
|
| ↳ `name` | string | Label name |
|
||||||
| ↳ `color` | string | Label color |
|
| ↳ `color` | string | Label color \(hex\) |
|
||||||
| ↳ `description` | string | Label description |
|
| ↳ `description` | string | Label description |
|
||||||
| ↳ `team` | object | Team this label belongs to |
|
| ↳ `team` | object | Team object |
|
||||||
|
| ↳ `id` | string | Team ID |
|
||||||
|
| ↳ `name` | string | Team name |
|
||||||
|
|
||||||
### `linear_update_label`
|
### `linear_update_label`
|
||||||
|
|
||||||
@@ -670,8 +804,11 @@ Update an existing label in Linear
|
|||||||
| `label` | object | The updated label |
|
| `label` | object | The updated label |
|
||||||
| ↳ `id` | string | Label ID |
|
| ↳ `id` | string | Label ID |
|
||||||
| ↳ `name` | string | Label name |
|
| ↳ `name` | string | Label name |
|
||||||
| ↳ `color` | string | Label color |
|
| ↳ `color` | string | Label color \(hex\) |
|
||||||
| ↳ `description` | string | Label description |
|
| ↳ `description` | string | Label description |
|
||||||
|
| ↳ `team` | object | Team object |
|
||||||
|
| ↳ `id` | string | Team ID |
|
||||||
|
| ↳ `name` | string | Team name |
|
||||||
|
|
||||||
### `linear_archive_label`
|
### `linear_archive_label`
|
||||||
|
|
||||||
@@ -706,14 +843,18 @@ List all workflow states (statuses) in Linear
|
|||||||
|
|
||||||
| Parameter | Type | Description |
|
| Parameter | Type | Description |
|
||||||
| --------- | ---- | ----------- |
|
| --------- | ---- | ----------- |
|
||||||
|
| `pageInfo` | object | Pagination information |
|
||||||
|
| ↳ `hasNextPage` | boolean | Whether there are more results |
|
||||||
|
| ↳ `endCursor` | string | Cursor for the next page |
|
||||||
| `states` | array | Array of workflow states |
|
| `states` | array | Array of workflow states |
|
||||||
| ↳ `id` | string | State ID |
|
| ↳ `id` | string | State ID |
|
||||||
| ↳ `name` | string | State name \(e.g., |
|
| ↳ `name` | string | State name \(e.g., "Todo", "In Progress"\) |
|
||||||
| ↳ `type` | string | State type \(e.g., |
|
| ↳ `type` | string | State type \(unstarted, started, completed, canceled\) |
|
||||||
| ↳ `color` | string | State color |
|
| ↳ `color` | string | State color \(hex\) |
|
||||||
| ↳ `position` | number | State position in workflow |
|
| ↳ `position` | number | State position in workflow |
|
||||||
| ↳ `team` | object | Team this state belongs to |
|
| ↳ `team` | object | Team object |
|
||||||
| `pageInfo` | object | Pagination information |
|
| ↳ `id` | string | Team ID |
|
||||||
|
| ↳ `name` | string | Team name |
|
||||||
|
|
||||||
### `linear_create_workflow_state`
|
### `linear_create_workflow_state`
|
||||||
|
|
||||||
@@ -783,16 +924,20 @@ List cycles (sprints/iterations) in Linear
|
|||||||
|
|
||||||
| Parameter | Type | Description |
|
| Parameter | Type | Description |
|
||||||
| --------- | ---- | ----------- |
|
| --------- | ---- | ----------- |
|
||||||
|
| `pageInfo` | object | Pagination information |
|
||||||
|
| ↳ `hasNextPage` | boolean | Whether there are more results |
|
||||||
|
| ↳ `endCursor` | string | Cursor for the next page |
|
||||||
| `cycles` | array | Array of cycles |
|
| `cycles` | array | Array of cycles |
|
||||||
| ↳ `id` | string | Cycle ID |
|
| ↳ `id` | string | Cycle ID |
|
||||||
| ↳ `number` | number | Cycle number |
|
| ↳ `number` | number | Cycle number |
|
||||||
| ↳ `name` | string | Cycle name |
|
| ↳ `name` | string | Cycle name |
|
||||||
| ↳ `startsAt` | string | Start date |
|
| ↳ `startsAt` | string | Start date \(ISO 8601\) |
|
||||||
| ↳ `endsAt` | string | End date |
|
| ↳ `endsAt` | string | End date \(ISO 8601\) |
|
||||||
| ↳ `completedAt` | string | Completion date |
|
| ↳ `completedAt` | string | Completion date \(ISO 8601\) |
|
||||||
| ↳ `progress` | number | Progress percentage \(0-1\) |
|
| ↳ `progress` | number | Progress percentage \(0-1\) |
|
||||||
| ↳ `team` | object | Team this cycle belongs to |
|
| ↳ `team` | object | Team object |
|
||||||
| `pageInfo` | object | Pagination information |
|
| ↳ `id` | string | Team ID |
|
||||||
|
| ↳ `name` | string | Team name |
|
||||||
|
|
||||||
### `linear_get_cycle`
|
### `linear_get_cycle`
|
||||||
|
|
||||||
@@ -812,10 +957,13 @@ Get a single cycle by ID from Linear
|
|||||||
| ↳ `id` | string | Cycle ID |
|
| ↳ `id` | string | Cycle ID |
|
||||||
| ↳ `number` | number | Cycle number |
|
| ↳ `number` | number | Cycle number |
|
||||||
| ↳ `name` | string | Cycle name |
|
| ↳ `name` | string | Cycle name |
|
||||||
| ↳ `startsAt` | string | Start date |
|
| ↳ `startsAt` | string | Start date \(ISO 8601\) |
|
||||||
| ↳ `endsAt` | string | End date |
|
| ↳ `endsAt` | string | End date \(ISO 8601\) |
|
||||||
| ↳ `progress` | number | Progress percentage |
|
| ↳ `completedAt` | string | Completion date \(ISO 8601\) |
|
||||||
| ↳ `team` | object | Team this cycle belongs to |
|
| ↳ `progress` | number | Progress percentage \(0-1\) |
|
||||||
|
| ↳ `team` | object | Team object |
|
||||||
|
| ↳ `id` | string | Team ID |
|
||||||
|
| ↳ `name` | string | Team name |
|
||||||
|
|
||||||
### `linear_create_cycle`
|
### `linear_create_cycle`
|
||||||
|
|
||||||
@@ -887,7 +1035,8 @@ Add an attachment to an issue in Linear
|
|||||||
| ↳ `title` | string | Attachment title |
|
| ↳ `title` | string | Attachment title |
|
||||||
| ↳ `subtitle` | string | Attachment subtitle |
|
| ↳ `subtitle` | string | Attachment subtitle |
|
||||||
| ↳ `url` | string | Attachment URL |
|
| ↳ `url` | string | Attachment URL |
|
||||||
| ↳ `createdAt` | string | Creation timestamp |
|
| ↳ `createdAt` | string | Creation timestamp \(ISO 8601\) |
|
||||||
|
| ↳ `updatedAt` | string | Last update timestamp \(ISO 8601\) |
|
||||||
|
|
||||||
### `linear_list_attachments`
|
### `linear_list_attachments`
|
||||||
|
|
||||||
@@ -905,13 +1054,16 @@ List all attachments on an issue in Linear
|
|||||||
|
|
||||||
| Parameter | Type | Description |
|
| Parameter | Type | Description |
|
||||||
| --------- | ---- | ----------- |
|
| --------- | ---- | ----------- |
|
||||||
|
| `pageInfo` | object | Pagination information |
|
||||||
|
| ↳ `hasNextPage` | boolean | Whether there are more results |
|
||||||
|
| ↳ `endCursor` | string | Cursor for the next page |
|
||||||
| `attachments` | array | Array of attachments |
|
| `attachments` | array | Array of attachments |
|
||||||
| ↳ `id` | string | Attachment ID |
|
| ↳ `id` | string | Attachment ID |
|
||||||
| ↳ `title` | string | Attachment title |
|
| ↳ `title` | string | Attachment title |
|
||||||
| ↳ `subtitle` | string | Attachment subtitle |
|
| ↳ `subtitle` | string | Attachment subtitle |
|
||||||
| ↳ `url` | string | Attachment URL |
|
| ↳ `url` | string | Attachment URL |
|
||||||
| ↳ `createdAt` | string | Creation timestamp |
|
| ↳ `createdAt` | string | Creation timestamp \(ISO 8601\) |
|
||||||
| `pageInfo` | object | Pagination information |
|
| ↳ `updatedAt` | string | Last update timestamp \(ISO 8601\) |
|
||||||
|
|
||||||
### `linear_update_attachment`
|
### `linear_update_attachment`
|
||||||
|
|
||||||
@@ -934,7 +1086,8 @@ Update an attachment metadata in Linear
|
|||||||
| ↳ `title` | string | Attachment title |
|
| ↳ `title` | string | Attachment title |
|
||||||
| ↳ `subtitle` | string | Attachment subtitle |
|
| ↳ `subtitle` | string | Attachment subtitle |
|
||||||
| ↳ `url` | string | Attachment URL |
|
| ↳ `url` | string | Attachment URL |
|
||||||
| ↳ `updatedAt` | string | Last update timestamp |
|
| ↳ `createdAt` | string | Creation timestamp \(ISO 8601\) |
|
||||||
|
| ↳ `updatedAt` | string | Last update timestamp \(ISO 8601\) |
|
||||||
|
|
||||||
### `linear_delete_attachment`
|
### `linear_delete_attachment`
|
||||||
|
|
||||||
@@ -1178,11 +1331,11 @@ Create a new customer in Linear
|
|||||||
| ↳ `id` | string | Customer ID |
|
| ↳ `id` | string | Customer ID |
|
||||||
| ↳ `name` | string | Customer name |
|
| ↳ `name` | string | Customer name |
|
||||||
| ↳ `domains` | array | Associated domains |
|
| ↳ `domains` | array | Associated domains |
|
||||||
| ↳ `externalIds` | array | External IDs |
|
| ↳ `externalIds` | array | External IDs from other systems |
|
||||||
| ↳ `logoUrl` | string | Logo URL |
|
| ↳ `logoUrl` | string | Logo URL |
|
||||||
| ↳ `approximateNeedCount` | number | Number of customer needs |
|
| ↳ `approximateNeedCount` | number | Number of customer needs |
|
||||||
| ↳ `createdAt` | string | Creation timestamp |
|
| ↳ `createdAt` | string | Creation timestamp \(ISO 8601\) |
|
||||||
| ↳ `archivedAt` | string | Archive timestamp \(null if not archived\) |
|
| ↳ `archivedAt` | string | Archive timestamp \(ISO 8601\) |
|
||||||
|
|
||||||
### `linear_list_customers`
|
### `linear_list_customers`
|
||||||
|
|
||||||
@@ -1200,16 +1353,18 @@ List all customers in Linear
|
|||||||
|
|
||||||
| Parameter | Type | Description |
|
| Parameter | Type | Description |
|
||||||
| --------- | ---- | ----------- |
|
| --------- | ---- | ----------- |
|
||||||
|
| `pageInfo` | object | Pagination information |
|
||||||
|
| ↳ `hasNextPage` | boolean | Whether there are more results |
|
||||||
|
| ↳ `endCursor` | string | Cursor for the next page |
|
||||||
| `customers` | array | Array of customers |
|
| `customers` | array | Array of customers |
|
||||||
| ↳ `id` | string | Customer ID |
|
| ↳ `id` | string | Customer ID |
|
||||||
| ↳ `name` | string | Customer name |
|
| ↳ `name` | string | Customer name |
|
||||||
| ↳ `domains` | array | Associated domains |
|
| ↳ `domains` | array | Associated domains |
|
||||||
| ↳ `externalIds` | array | External IDs |
|
| ↳ `externalIds` | array | External IDs from other systems |
|
||||||
| ↳ `logoUrl` | string | Logo URL |
|
| ↳ `logoUrl` | string | Logo URL |
|
||||||
| ↳ `approximateNeedCount` | number | Number of customer needs |
|
| ↳ `approximateNeedCount` | number | Number of customer needs |
|
||||||
| ↳ `createdAt` | string | Creation timestamp |
|
| ↳ `createdAt` | string | Creation timestamp \(ISO 8601\) |
|
||||||
| ↳ `archivedAt` | string | Archive timestamp \(null if not archived\) |
|
| ↳ `archivedAt` | string | Archive timestamp \(ISO 8601\) |
|
||||||
| `pageInfo` | object | Pagination information |
|
|
||||||
|
|
||||||
### `linear_create_customer_request`
|
### `linear_create_customer_request`
|
||||||
|
|
||||||
@@ -1322,11 +1477,11 @@ Get a single customer by ID in Linear
|
|||||||
| ↳ `id` | string | Customer ID |
|
| ↳ `id` | string | Customer ID |
|
||||||
| ↳ `name` | string | Customer name |
|
| ↳ `name` | string | Customer name |
|
||||||
| ↳ `domains` | array | Associated domains |
|
| ↳ `domains` | array | Associated domains |
|
||||||
| ↳ `externalIds` | array | External IDs |
|
| ↳ `externalIds` | array | External IDs from other systems |
|
||||||
| ↳ `logoUrl` | string | Logo URL |
|
| ↳ `logoUrl` | string | Logo URL |
|
||||||
| ↳ `approximateNeedCount` | number | Number of customer needs |
|
| ↳ `approximateNeedCount` | number | Number of customer needs |
|
||||||
| ↳ `createdAt` | string | Creation timestamp |
|
| ↳ `createdAt` | string | Creation timestamp \(ISO 8601\) |
|
||||||
| ↳ `archivedAt` | string | Archive timestamp \(null if not archived\) |
|
| ↳ `archivedAt` | string | Archive timestamp \(ISO 8601\) |
|
||||||
|
|
||||||
### `linear_update_customer`
|
### `linear_update_customer`
|
||||||
|
|
||||||
@@ -1352,6 +1507,14 @@ Update a customer in Linear
|
|||||||
| Parameter | Type | Description |
|
| Parameter | Type | Description |
|
||||||
| --------- | ---- | ----------- |
|
| --------- | ---- | ----------- |
|
||||||
| `customer` | object | The updated customer |
|
| `customer` | object | The updated customer |
|
||||||
|
| ↳ `id` | string | Customer ID |
|
||||||
|
| ↳ `name` | string | Customer name |
|
||||||
|
| ↳ `domains` | array | Associated domains |
|
||||||
|
| ↳ `externalIds` | array | External IDs from other systems |
|
||||||
|
| ↳ `logoUrl` | string | Logo URL |
|
||||||
|
| ↳ `approximateNeedCount` | number | Number of customer needs |
|
||||||
|
| ↳ `createdAt` | string | Creation timestamp \(ISO 8601\) |
|
||||||
|
| ↳ `archivedAt` | string | Archive timestamp \(ISO 8601\) |
|
||||||
|
|
||||||
### `linear_delete_customer`
|
### `linear_delete_customer`
|
||||||
|
|
||||||
@@ -1405,6 +1568,14 @@ Create a new customer status in Linear
|
|||||||
| Parameter | Type | Description |
|
| Parameter | Type | Description |
|
||||||
| --------- | ---- | ----------- |
|
| --------- | ---- | ----------- |
|
||||||
| `customerStatus` | object | The created customer status |
|
| `customerStatus` | object | The created customer status |
|
||||||
|
| ↳ `id` | string | Customer status ID |
|
||||||
|
| ↳ `name` | string | Status name |
|
||||||
|
| ↳ `displayName` | string | Display name |
|
||||||
|
| ↳ `description` | string | Status description |
|
||||||
|
| ↳ `color` | string | Status color \(hex\) |
|
||||||
|
| ↳ `position` | number | Position in list |
|
||||||
|
| ↳ `createdAt` | string | Creation timestamp \(ISO 8601\) |
|
||||||
|
| ↳ `archivedAt` | string | Archive timestamp \(ISO 8601\) |
|
||||||
|
|
||||||
### `linear_update_customer_status`
|
### `linear_update_customer_status`
|
||||||
|
|
||||||
@@ -1457,6 +1628,14 @@ List all customer statuses in Linear
|
|||||||
| Parameter | Type | Description |
|
| Parameter | Type | Description |
|
||||||
| --------- | ---- | ----------- |
|
| --------- | ---- | ----------- |
|
||||||
| `customerStatuses` | array | List of customer statuses |
|
| `customerStatuses` | array | List of customer statuses |
|
||||||
|
| ↳ `id` | string | Customer status ID |
|
||||||
|
| ↳ `name` | string | Status name |
|
||||||
|
| ↳ `displayName` | string | Display name |
|
||||||
|
| ↳ `description` | string | Status description |
|
||||||
|
| ↳ `color` | string | Status color \(hex\) |
|
||||||
|
| ↳ `position` | number | Position in list |
|
||||||
|
| ↳ `createdAt` | string | Creation timestamp \(ISO 8601\) |
|
||||||
|
| ↳ `archivedAt` | string | Archive timestamp \(ISO 8601\) |
|
||||||
|
|
||||||
### `linear_create_customer_tier`
|
### `linear_create_customer_tier`
|
||||||
|
|
||||||
@@ -1477,6 +1656,14 @@ Create a new customer tier in Linear
|
|||||||
| Parameter | Type | Description |
|
| Parameter | Type | Description |
|
||||||
| --------- | ---- | ----------- |
|
| --------- | ---- | ----------- |
|
||||||
| `customerTier` | object | The created customer tier |
|
| `customerTier` | object | The created customer tier |
|
||||||
|
| ↳ `id` | string | Customer tier ID |
|
||||||
|
| ↳ `name` | string | Tier name |
|
||||||
|
| ↳ `displayName` | string | Display name |
|
||||||
|
| ↳ `description` | string | Tier description |
|
||||||
|
| ↳ `color` | string | Tier color \(hex\) |
|
||||||
|
| ↳ `position` | number | Position in list |
|
||||||
|
| ↳ `createdAt` | string | Creation timestamp \(ISO 8601\) |
|
||||||
|
| ↳ `archivedAt` | string | Archive timestamp \(ISO 8601\) |
|
||||||
|
|
||||||
### `linear_update_customer_tier`
|
### `linear_update_customer_tier`
|
||||||
|
|
||||||
@@ -1529,6 +1716,14 @@ List all customer tiers in Linear
|
|||||||
| Parameter | Type | Description |
|
| Parameter | Type | Description |
|
||||||
| --------- | ---- | ----------- |
|
| --------- | ---- | ----------- |
|
||||||
| `customerTiers` | array | List of customer tiers |
|
| `customerTiers` | array | List of customer tiers |
|
||||||
|
| ↳ `id` | string | Customer tier ID |
|
||||||
|
| ↳ `name` | string | Tier name |
|
||||||
|
| ↳ `displayName` | string | Display name |
|
||||||
|
| ↳ `description` | string | Tier description |
|
||||||
|
| ↳ `color` | string | Tier color \(hex\) |
|
||||||
|
| ↳ `position` | number | Position in list |
|
||||||
|
| ↳ `createdAt` | string | Creation timestamp \(ISO 8601\) |
|
||||||
|
| ↳ `archivedAt` | string | Archive timestamp \(ISO 8601\) |
|
||||||
|
|
||||||
### `linear_delete_project`
|
### `linear_delete_project`
|
||||||
|
|
||||||
|
|||||||
@@ -52,6 +52,10 @@ Add memories to Mem0 for persistent storage and retrieval
|
|||||||
| --------- | ---- | ----------- |
|
| --------- | ---- | ----------- |
|
||||||
| `ids` | array | Array of memory IDs that were created |
|
| `ids` | array | Array of memory IDs that were created |
|
||||||
| `memories` | array | Array of memory objects that were created |
|
| `memories` | array | Array of memory objects that were created |
|
||||||
|
| ↳ `id` | string | Unique identifier for the memory |
|
||||||
|
| ↳ `memory` | string | The content of the memory |
|
||||||
|
| ↳ `event` | string | Event type indicating operation performed \(ADD, UPDATE, DELETE, NOOP\) |
|
||||||
|
| ↳ `metadata` | json | Custom metadata associated with the memory |
|
||||||
|
|
||||||
### `mem0_search_memories`
|
### `mem0_search_memories`
|
||||||
|
|
||||||
@@ -70,7 +74,19 @@ Search for memories in Mem0 using semantic search
|
|||||||
|
|
||||||
| Parameter | Type | Description |
|
| Parameter | Type | Description |
|
||||||
| --------- | ---- | ----------- |
|
| --------- | ---- | ----------- |
|
||||||
| `searchResults` | array | Array of search results with memory data, each containing id, data, and score |
|
| `searchResults` | array | Array of search results with memory data and similarity scores |
|
||||||
|
| ↳ `id` | string | Unique identifier for the memory |
|
||||||
|
| ↳ `memory` | string | The content of the memory |
|
||||||
|
| ↳ `user_id` | string | User ID associated with this memory |
|
||||||
|
| ↳ `agent_id` | string | Agent ID associated with this memory |
|
||||||
|
| ↳ `app_id` | string | App ID associated with this memory |
|
||||||
|
| ↳ `run_id` | string | Run/session ID associated with this memory |
|
||||||
|
| ↳ `hash` | string | Hash of the memory content |
|
||||||
|
| ↳ `metadata` | json | Custom metadata associated with the memory |
|
||||||
|
| ↳ `categories` | json | Auto-assigned categories for the memory |
|
||||||
|
| ↳ `created_at` | string | ISO 8601 timestamp when the memory was created |
|
||||||
|
| ↳ `updated_at` | string | ISO 8601 timestamp when the memory was last updated |
|
||||||
|
| ↳ `score` | number | Similarity score from vector search |
|
||||||
| `ids` | array | Array of memory IDs found in the search results |
|
| `ids` | array | Array of memory IDs found in the search results |
|
||||||
|
|
||||||
### `mem0_get_memories`
|
### `mem0_get_memories`
|
||||||
@@ -93,6 +109,21 @@ Retrieve memories from Mem0 by ID or filter criteria
|
|||||||
| Parameter | Type | Description |
|
| Parameter | Type | Description |
|
||||||
| --------- | ---- | ----------- |
|
| --------- | ---- | ----------- |
|
||||||
| `memories` | array | Array of retrieved memory objects |
|
| `memories` | array | Array of retrieved memory objects |
|
||||||
|
| ↳ `id` | string | Unique identifier for the memory |
|
||||||
|
| ↳ `memory` | string | The content of the memory |
|
||||||
|
| ↳ `user_id` | string | User ID associated with this memory |
|
||||||
|
| ↳ `agent_id` | string | Agent ID associated with this memory |
|
||||||
|
| ↳ `app_id` | string | App ID associated with this memory |
|
||||||
|
| ↳ `run_id` | string | Run/session ID associated with this memory |
|
||||||
|
| ↳ `hash` | string | Hash of the memory content |
|
||||||
|
| ↳ `metadata` | json | Custom metadata associated with the memory |
|
||||||
|
| ↳ `categories` | json | Auto-assigned categories for the memory |
|
||||||
|
| ↳ `created_at` | string | ISO 8601 timestamp when the memory was created |
|
||||||
|
| ↳ `updated_at` | string | ISO 8601 timestamp when the memory was last updated |
|
||||||
|
| ↳ `owner` | string | Owner of the memory |
|
||||||
|
| ↳ `organization` | string | Organization associated with the memory |
|
||||||
|
| ↳ `immutable` | boolean | Whether the memory can be modified |
|
||||||
|
| ↳ `expiration_date` | string | Expiration date after which memory is not retrieved |
|
||||||
| `ids` | array | Array of memory IDs that were retrieved |
|
| `ids` | array | Array of memory IDs that were retrieved |
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -9,6 +9,7 @@
|
|||||||
"arxiv",
|
"arxiv",
|
||||||
"asana",
|
"asana",
|
||||||
"browser_use",
|
"browser_use",
|
||||||
|
"calcom",
|
||||||
"calendly",
|
"calendly",
|
||||||
"circleback",
|
"circleback",
|
||||||
"clay",
|
"clay",
|
||||||
@@ -96,6 +97,7 @@
|
|||||||
"sftp",
|
"sftp",
|
||||||
"sharepoint",
|
"sharepoint",
|
||||||
"shopify",
|
"shopify",
|
||||||
|
"similarweb",
|
||||||
"slack",
|
"slack",
|
||||||
"smtp",
|
"smtp",
|
||||||
"sqs",
|
"sqs",
|
||||||
|
|||||||
@@ -69,7 +69,7 @@ Parse PDF documents using Mistral OCR API
|
|||||||
| ↳ `height` | number | Page height in pixels |
|
| ↳ `height` | number | Page height in pixels |
|
||||||
| ↳ `width` | number | Page width in pixels |
|
| ↳ `width` | number | Page width in pixels |
|
||||||
| ↳ `tables` | array | Extracted tables as HTML/markdown \(when table_format is set\). Referenced via placeholders like \[tbl-0.html\] |
|
| ↳ `tables` | array | Extracted tables as HTML/markdown \(when table_format is set\). Referenced via placeholders like \[tbl-0.html\] |
|
||||||
| ↳ `hyperlinks` | array | Array of URL strings detected in the page \(e.g., \[ |
|
| ↳ `hyperlinks` | array | Array of URL strings detected in the page \(e.g., \["https://...", "mailto:..."\]\) |
|
||||||
| ↳ `header` | string | Page header content \(when extract_header=true\) |
|
| ↳ `header` | string | Page header content \(when extract_header=true\) |
|
||||||
| ↳ `footer` | string | Page footer content \(when extract_footer=true\) |
|
| ↳ `footer` | string | Page footer content \(when extract_footer=true\) |
|
||||||
| `model` | string | Mistral OCR model identifier \(e.g., mistral-ocr-latest\) |
|
| `model` | string | Mistral OCR model identifier \(e.g., mistral-ocr-latest\) |
|
||||||
|
|||||||
@@ -32,11 +32,11 @@ Read content from a Notion page
|
|||||||
|
|
||||||
| Parameter | Type | Description |
|
| Parameter | Type | Description |
|
||||||
| --------- | ---- | ----------- |
|
| --------- | ---- | ----------- |
|
||||||
|
| `url` | string | Notion page URL |
|
||||||
|
| `created_time` | string | ISO 8601 creation timestamp |
|
||||||
|
| `last_edited_time` | string | ISO 8601 last edit timestamp |
|
||||||
| `content` | string | Page content in markdown format |
|
| `content` | string | Page content in markdown format |
|
||||||
| `title` | string | Page title |
|
| `title` | string | Page title |
|
||||||
| `url` | string | Page URL |
|
|
||||||
| `created_time` | string | Creation timestamp |
|
|
||||||
| `last_edited_time` | string | Last edit timestamp |
|
|
||||||
|
|
||||||
### `notion_read_database`
|
### `notion_read_database`
|
||||||
|
|
||||||
@@ -52,12 +52,12 @@ Read database information and structure from Notion
|
|||||||
|
|
||||||
| Parameter | Type | Description |
|
| Parameter | Type | Description |
|
||||||
| --------- | ---- | ----------- |
|
| --------- | ---- | ----------- |
|
||||||
| `id` | string | Database ID |
|
| `id` | string | Database UUID |
|
||||||
| `title` | string | Database title |
|
| `url` | string | Notion database URL |
|
||||||
| `url` | string | Database URL |
|
| `created_time` | string | ISO 8601 creation timestamp |
|
||||||
| `created_time` | string | Creation timestamp |
|
| `last_edited_time` | string | ISO 8601 last edit timestamp |
|
||||||
| `last_edited_time` | string | Last edit timestamp |
|
|
||||||
| `properties` | object | Database properties schema |
|
| `properties` | object | Database properties schema |
|
||||||
|
| `title` | string | Database title |
|
||||||
|
|
||||||
### `notion_write`
|
### `notion_write`
|
||||||
|
|
||||||
@@ -92,11 +92,11 @@ Create a new page in Notion
|
|||||||
|
|
||||||
| Parameter | Type | Description |
|
| Parameter | Type | Description |
|
||||||
| --------- | ---- | ----------- |
|
| --------- | ---- | ----------- |
|
||||||
| `id` | string | Page ID |
|
| `id` | string | Page UUID |
|
||||||
|
| `url` | string | Notion page URL |
|
||||||
|
| `created_time` | string | ISO 8601 creation timestamp |
|
||||||
|
| `last_edited_time` | string | ISO 8601 last edit timestamp |
|
||||||
| `title` | string | Page title |
|
| `title` | string | Page title |
|
||||||
| `url` | string | Page URL |
|
|
||||||
| `created_time` | string | Creation timestamp |
|
|
||||||
| `last_edited_time` | string | Last edit timestamp |
|
|
||||||
|
|
||||||
### `notion_query_database`
|
### `notion_query_database`
|
||||||
|
|
||||||
@@ -115,13 +115,43 @@ Query and filter Notion database entries with advanced filtering
|
|||||||
|
|
||||||
| Parameter | Type | Description |
|
| Parameter | Type | Description |
|
||||||
| --------- | ---- | ----------- |
|
| --------- | ---- | ----------- |
|
||||||
| `results` | array | Array of Notion page objects from the database |
|
| `results` | array | Array of page objects from the database |
|
||||||
| ↳ `id` | string | Page ID |
|
| ↳ `object` | string | Always "page" |
|
||||||
| ↳ `created_time` | string | Creation timestamp |
|
| ↳ `id` | string | Page UUID |
|
||||||
| ↳ `last_edited_time` | string | Last edit timestamp |
|
| ↳ `created_time` | string | ISO 8601 creation timestamp |
|
||||||
| ↳ `url` | string | Page URL |
|
| ↳ `last_edited_time` | string | ISO 8601 last edit timestamp |
|
||||||
|
| ↳ `created_by` | object | Partial user object |
|
||||||
|
| ↳ `object` | string | Always "user" |
|
||||||
|
| ↳ `id` | string | User UUID |
|
||||||
|
| ↳ `last_edited_by` | object | Partial user object |
|
||||||
|
| ↳ `object` | string | Always "user" |
|
||||||
|
| ↳ `id` | string | User UUID |
|
||||||
|
| ↳ `archived` | boolean | Whether the page is archived |
|
||||||
|
| ↳ `in_trash` | boolean | Whether the page is in trash |
|
||||||
|
| ↳ `url` | string | Notion page URL |
|
||||||
|
| ↳ `public_url` | string | Public web URL if shared, null otherwise |
|
||||||
|
| ↳ `parent` | object | Parent object specifying hierarchical relationship |
|
||||||
|
| ↳ `type` | string | Parent type: "database_id", "data_source_id", "page_id", "workspace", or "block_id" |
|
||||||
|
| ↳ `database_id` | string | Parent database UUID \(if type is database_id\) |
|
||||||
|
| ↳ `data_source_id` | string | Parent data source UUID \(if type is data_source_id\) |
|
||||||
|
| ↳ `page_id` | string | Parent page UUID \(if type is page_id\) |
|
||||||
|
| ↳ `workspace` | boolean | True if parent is workspace \(if type is workspace\) |
|
||||||
|
| ↳ `block_id` | string | Parent block UUID \(if type is block_id\) |
|
||||||
|
| ↳ `icon` | object | Page/database icon \(emoji, custom_emoji, or file\) |
|
||||||
|
| ↳ `url` | string | Authenticated URL valid for one hour |
|
||||||
|
| ↳ `expiry_time` | string | ISO 8601 timestamp when URL expires |
|
||||||
|
| ↳ `cover` | object | Page/database cover image |
|
||||||
|
| ↳ `type` | string | File type: "file", "file_upload", or "external" |
|
||||||
|
| ↳ `file` | object | Notion-hosted file object \(when type is "file"\) |
|
||||||
|
| ↳ `url` | string | Authenticated URL valid for one hour |
|
||||||
|
| ↳ `expiry_time` | string | ISO 8601 timestamp when URL expires |
|
||||||
|
| ↳ `file_upload` | object | API-uploaded file object \(when type is "file_upload"\) |
|
||||||
|
| ↳ `id` | string | File upload UUID |
|
||||||
|
| ↳ `external` | object | External file object \(when type is "external"\) |
|
||||||
|
| ↳ `url` | string | External file URL \(never expires\) |
|
||||||
|
| ↳ `properties` | object | Page property values \(structure depends on parent type - database properties or title only\) |
|
||||||
| `has_more` | boolean | Whether more results are available |
|
| `has_more` | boolean | Whether more results are available |
|
||||||
| `next_cursor` | string | Cursor for pagination |
|
| `next_cursor` | string | Cursor for next page of results |
|
||||||
| `total_results` | number | Number of results returned |
|
| `total_results` | number | Number of results returned |
|
||||||
|
|
||||||
### `notion_search`
|
### `notion_search`
|
||||||
@@ -140,14 +170,31 @@ Search across all pages and databases in Notion workspace
|
|||||||
|
|
||||||
| Parameter | Type | Description |
|
| Parameter | Type | Description |
|
||||||
| --------- | ---- | ----------- |
|
| --------- | ---- | ----------- |
|
||||||
| `results` | array | Array of search results \(pages and databases\) |
|
| `results` | array | Array of search results \(pages and/or databases\) |
|
||||||
| ↳ `id` | string | Object ID |
|
| ↳ `object` | string | Object type: "page" or "database" |
|
||||||
| ↳ `object` | string | Object type \(page or database\) |
|
| ↳ `id` | string | Object UUID |
|
||||||
|
| ↳ `created_time` | string | ISO 8601 creation timestamp |
|
||||||
|
| ↳ `last_edited_time` | string | ISO 8601 last edit timestamp |
|
||||||
|
| ↳ `created_by` | object | Partial user object |
|
||||||
|
| ↳ `object` | string | Always "user" |
|
||||||
|
| ↳ `id` | string | User UUID |
|
||||||
|
| ↳ `last_edited_by` | object | Partial user object |
|
||||||
|
| ↳ `object` | string | Always "user" |
|
||||||
|
| ↳ `id` | string | User UUID |
|
||||||
|
| ↳ `archived` | boolean | Whether the object is archived |
|
||||||
|
| ↳ `in_trash` | boolean | Whether the object is in trash |
|
||||||
| ↳ `url` | string | Object URL |
|
| ↳ `url` | string | Object URL |
|
||||||
| ↳ `created_time` | string | Creation timestamp |
|
| ↳ `public_url` | string | Public web URL if shared |
|
||||||
| ↳ `last_edited_time` | string | Last edit timestamp |
|
| ↳ `parent` | object | Parent object specifying hierarchical relationship |
|
||||||
|
| ↳ `type` | string | Parent type: "database_id", "data_source_id", "page_id", "workspace", or "block_id" |
|
||||||
|
| ↳ `database_id` | string | Parent database UUID \(if type is database_id\) |
|
||||||
|
| ↳ `data_source_id` | string | Parent data source UUID \(if type is data_source_id\) |
|
||||||
|
| ↳ `page_id` | string | Parent page UUID \(if type is page_id\) |
|
||||||
|
| ↳ `workspace` | boolean | True if parent is workspace \(if type is workspace\) |
|
||||||
|
| ↳ `block_id` | string | Parent block UUID \(if type is block_id\) |
|
||||||
|
| ↳ `properties` | object | Object properties |
|
||||||
| `has_more` | boolean | Whether more results are available |
|
| `has_more` | boolean | Whether more results are available |
|
||||||
| `next_cursor` | string | Cursor for pagination |
|
| `next_cursor` | string | Cursor for next page of results |
|
||||||
| `total_results` | number | Number of results returned |
|
| `total_results` | number | Number of results returned |
|
||||||
|
|
||||||
### `notion_create_database`
|
### `notion_create_database`
|
||||||
@@ -166,11 +213,11 @@ Create a new database in Notion with custom properties
|
|||||||
|
|
||||||
| Parameter | Type | Description |
|
| Parameter | Type | Description |
|
||||||
| --------- | ---- | ----------- |
|
| --------- | ---- | ----------- |
|
||||||
| `id` | string | Database ID |
|
| `id` | string | Database UUID |
|
||||||
| `title` | string | Database title |
|
| `url` | string | Notion database URL |
|
||||||
| `url` | string | Database URL |
|
| `created_time` | string | ISO 8601 creation timestamp |
|
||||||
| `created_time` | string | Creation timestamp |
|
|
||||||
| `properties` | object | Database properties schema |
|
| `properties` | object | Database properties schema |
|
||||||
|
| `title` | string | Database title |
|
||||||
|
|
||||||
### `notion_add_database_row`
|
### `notion_add_database_row`
|
||||||
|
|
||||||
@@ -187,10 +234,10 @@ Add a new row to a Notion database with specified properties
|
|||||||
|
|
||||||
| Parameter | Type | Description |
|
| Parameter | Type | Description |
|
||||||
| --------- | ---- | ----------- |
|
| --------- | ---- | ----------- |
|
||||||
| `id` | string | Page/row ID |
|
| `id` | string | Page UUID |
|
||||||
| `url` | string | Page/row URL |
|
| `url` | string | Notion page URL |
|
||||||
|
| `created_time` | string | ISO 8601 creation timestamp |
|
||||||
|
| `last_edited_time` | string | ISO 8601 last edit timestamp |
|
||||||
| `title` | string | Row title |
|
| `title` | string | Row title |
|
||||||
| `created_time` | string | Creation timestamp |
|
|
||||||
| `last_edited_time` | string | Last edit timestamp |
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -115,6 +115,29 @@ Read emails from Outlook
|
|||||||
| --------- | ---- | ----------- |
|
| --------- | ---- | ----------- |
|
||||||
| `message` | string | Success or status message |
|
| `message` | string | Success or status message |
|
||||||
| `results` | array | Array of email message objects |
|
| `results` | array | Array of email message objects |
|
||||||
|
| ↳ `id` | string | Unique message identifier |
|
||||||
|
| ↳ `subject` | string | Email subject |
|
||||||
|
| ↳ `bodyPreview` | string | Preview of the message body |
|
||||||
|
| ↳ `body` | object | Message body |
|
||||||
|
| ↳ `contentType` | string | Body content type \(text or html\) |
|
||||||
|
| ↳ `content` | string | Body content |
|
||||||
|
| ↳ `sender` | object | Sender information |
|
||||||
|
| ↳ `name` | string | Display name of the person or entity |
|
||||||
|
| ↳ `address` | string | Email address |
|
||||||
|
| ↳ `from` | object | From address information |
|
||||||
|
| ↳ `name` | string | Display name of the person or entity |
|
||||||
|
| ↳ `address` | string | Email address |
|
||||||
|
| ↳ `toRecipients` | array | To recipients |
|
||||||
|
| ↳ `name` | string | Display name of the person or entity |
|
||||||
|
| ↳ `address` | string | Email address |
|
||||||
|
| ↳ `ccRecipients` | array | CC recipients |
|
||||||
|
| ↳ `name` | string | Display name of the person or entity |
|
||||||
|
| ↳ `address` | string | Email address |
|
||||||
|
| ↳ `receivedDateTime` | string | When the message was received \(ISO 8601\) |
|
||||||
|
| ↳ `sentDateTime` | string | When the message was sent \(ISO 8601\) |
|
||||||
|
| ↳ `hasAttachments` | boolean | Whether the message has attachments |
|
||||||
|
| ↳ `isRead` | boolean | Whether the message has been read |
|
||||||
|
| ↳ `importance` | string | Message importance \(low, normal, high\) |
|
||||||
| `attachments` | file[] | All email attachments flattened from all emails |
|
| `attachments` | file[] | All email attachments flattened from all emails |
|
||||||
|
|
||||||
### `outlook_forward`
|
### `outlook_forward`
|
||||||
|
|||||||
@@ -87,7 +87,7 @@ Get ranked search results from Perplexity
|
|||||||
| ↳ `title` | string | Title of the search result |
|
| ↳ `title` | string | Title of the search result |
|
||||||
| ↳ `url` | string | URL of the search result |
|
| ↳ `url` | string | URL of the search result |
|
||||||
| ↳ `snippet` | string | Brief excerpt or summary of the content |
|
| ↳ `snippet` | string | Brief excerpt or summary of the content |
|
||||||
| ↳ `date` | string | Date the page was crawled and added to Perplexity |
|
| ↳ `date` | string | Date the page was crawled and added to Perplexity's index |
|
||||||
| ↳ `last_updated` | string | Date the page was last updated in Perplexity |
|
| ↳ `last_updated` | string | Date the page was last updated in Perplexity's index |
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -55,7 +55,25 @@ Retrieve all deals from Pipedrive with optional filters
|
|||||||
| Parameter | Type | Description |
|
| Parameter | Type | Description |
|
||||||
| --------- | ---- | ----------- |
|
| --------- | ---- | ----------- |
|
||||||
| `deals` | array | Array of deal objects from Pipedrive |
|
| `deals` | array | Array of deal objects from Pipedrive |
|
||||||
|
| ↳ `id` | number | Deal ID |
|
||||||
|
| ↳ `title` | string | Deal title |
|
||||||
|
| ↳ `value` | number | Deal value |
|
||||||
|
| ↳ `currency` | string | Currency code |
|
||||||
|
| ↳ `status` | string | Deal status \(open, won, lost, deleted\) |
|
||||||
|
| ↳ `stage_id` | number | Pipeline stage ID |
|
||||||
|
| ↳ `pipeline_id` | number | Pipeline ID |
|
||||||
|
| ↳ `person_id` | number | Associated person ID |
|
||||||
|
| ↳ `org_id` | number | Associated organization ID |
|
||||||
|
| ↳ `owner_id` | number | Deal owner user ID |
|
||||||
|
| ↳ `add_time` | string | When the deal was created \(ISO 8601\) |
|
||||||
|
| ↳ `update_time` | string | When the deal was last updated \(ISO 8601\) |
|
||||||
|
| ↳ `won_time` | string | When the deal was won |
|
||||||
|
| ↳ `lost_time` | string | When the deal was lost |
|
||||||
|
| ↳ `close_time` | string | When the deal was closed |
|
||||||
|
| ↳ `expected_close_date` | string | Expected close date |
|
||||||
| `metadata` | object | Pagination metadata for the response |
|
| `metadata` | object | Pagination metadata for the response |
|
||||||
|
| ↳ `total_items` | number | Total number of items |
|
||||||
|
| ↳ `has_more` | boolean | Whether more items are available |
|
||||||
| `success` | boolean | Operation success status |
|
| `success` | boolean | Operation success status |
|
||||||
|
|
||||||
### `pipedrive_get_deal`
|
### `pipedrive_get_deal`
|
||||||
@@ -140,6 +158,16 @@ Retrieve files from Pipedrive with optional filters
|
|||||||
| Parameter | Type | Description |
|
| Parameter | Type | Description |
|
||||||
| --------- | ---- | ----------- |
|
| --------- | ---- | ----------- |
|
||||||
| `files` | array | Array of file objects from Pipedrive |
|
| `files` | array | Array of file objects from Pipedrive |
|
||||||
|
| ↳ `id` | number | File ID |
|
||||||
|
| ↳ `name` | string | File name |
|
||||||
|
| ↳ `file_type` | string | File type/extension |
|
||||||
|
| ↳ `file_size` | number | File size in bytes |
|
||||||
|
| ↳ `add_time` | string | When the file was uploaded |
|
||||||
|
| ↳ `update_time` | string | When the file was last updated |
|
||||||
|
| ↳ `deal_id` | number | Associated deal ID |
|
||||||
|
| ↳ `person_id` | number | Associated person ID |
|
||||||
|
| ↳ `org_id` | number | Associated organization ID |
|
||||||
|
| ↳ `url` | string | File download URL |
|
||||||
| `total_items` | number | Total number of files returned |
|
| `total_items` | number | Total number of files returned |
|
||||||
| `success` | boolean | Operation success status |
|
| `success` | boolean | Operation success status |
|
||||||
|
|
||||||
@@ -198,6 +226,14 @@ Retrieve all pipelines from Pipedrive
|
|||||||
| Parameter | Type | Description |
|
| Parameter | Type | Description |
|
||||||
| --------- | ---- | ----------- |
|
| --------- | ---- | ----------- |
|
||||||
| `pipelines` | array | Array of pipeline objects from Pipedrive |
|
| `pipelines` | array | Array of pipeline objects from Pipedrive |
|
||||||
|
| ↳ `id` | number | Pipeline ID |
|
||||||
|
| ↳ `name` | string | Pipeline name |
|
||||||
|
| ↳ `url_title` | string | URL-friendly title |
|
||||||
|
| ↳ `order_nr` | number | Pipeline order number |
|
||||||
|
| ↳ `active` | boolean | Whether the pipeline is active |
|
||||||
|
| ↳ `deal_probability` | boolean | Whether deal probability is enabled |
|
||||||
|
| ↳ `add_time` | string | When the pipeline was created |
|
||||||
|
| ↳ `update_time` | string | When the pipeline was last updated |
|
||||||
| `total_items` | number | Total number of pipelines returned |
|
| `total_items` | number | Total number of pipelines returned |
|
||||||
| `success` | boolean | Operation success status |
|
| `success` | boolean | Operation success status |
|
||||||
|
|
||||||
@@ -283,6 +319,19 @@ Retrieve activities (tasks) from Pipedrive with optional filters
|
|||||||
| Parameter | Type | Description |
|
| Parameter | Type | Description |
|
||||||
| --------- | ---- | ----------- |
|
| --------- | ---- | ----------- |
|
||||||
| `activities` | array | Array of activity objects from Pipedrive |
|
| `activities` | array | Array of activity objects from Pipedrive |
|
||||||
|
| ↳ `id` | number | Activity ID |
|
||||||
|
| ↳ `subject` | string | Activity subject |
|
||||||
|
| ↳ `type` | string | Activity type \(call, meeting, task, etc.\) |
|
||||||
|
| ↳ `due_date` | string | Due date \(YYYY-MM-DD\) |
|
||||||
|
| ↳ `due_time` | string | Due time \(HH:MM\) |
|
||||||
|
| ↳ `duration` | string | Duration \(HH:MM\) |
|
||||||
|
| ↳ `deal_id` | number | Associated deal ID |
|
||||||
|
| ↳ `person_id` | number | Associated person ID |
|
||||||
|
| ↳ `org_id` | number | Associated organization ID |
|
||||||
|
| ↳ `done` | boolean | Whether the activity is done |
|
||||||
|
| ↳ `note` | string | Activity note |
|
||||||
|
| ↳ `add_time` | string | When the activity was created |
|
||||||
|
| ↳ `update_time` | string | When the activity was last updated |
|
||||||
| `total_items` | number | Total number of activities returned |
|
| `total_items` | number | Total number of activities returned |
|
||||||
| `success` | boolean | Operation success status |
|
| `success` | boolean | Operation success status |
|
||||||
|
|
||||||
@@ -354,7 +403,33 @@ Retrieve all leads or a specific lead from Pipedrive
|
|||||||
| Parameter | Type | Description |
|
| Parameter | Type | Description |
|
||||||
| --------- | ---- | ----------- |
|
| --------- | ---- | ----------- |
|
||||||
| `leads` | array | Array of lead objects \(when listing all\) |
|
| `leads` | array | Array of lead objects \(when listing all\) |
|
||||||
|
| ↳ `id` | string | Lead ID \(UUID\) |
|
||||||
|
| ↳ `title` | string | Lead title |
|
||||||
|
| ↳ `person_id` | number | ID of the associated person |
|
||||||
|
| ↳ `organization_id` | number | ID of the associated organization |
|
||||||
|
| ↳ `owner_id` | number | ID of the lead owner |
|
||||||
|
| ↳ `value` | object | Lead value |
|
||||||
|
| ↳ `amount` | number | Value amount |
|
||||||
|
| ↳ `currency` | string | Currency code \(e.g., USD, EUR\) |
|
||||||
|
| ↳ `expected_close_date` | string | Expected close date \(YYYY-MM-DD\) |
|
||||||
|
| ↳ `is_archived` | boolean | Whether the lead is archived |
|
||||||
|
| ↳ `was_seen` | boolean | Whether the lead was seen |
|
||||||
|
| ↳ `add_time` | string | When the lead was created \(ISO 8601\) |
|
||||||
|
| ↳ `update_time` | string | When the lead was last updated \(ISO 8601\) |
|
||||||
| `lead` | object | Single lead object \(when lead_id is provided\) |
|
| `lead` | object | Single lead object \(when lead_id is provided\) |
|
||||||
|
| ↳ `id` | string | Lead ID \(UUID\) |
|
||||||
|
| ↳ `title` | string | Lead title |
|
||||||
|
| ↳ `person_id` | number | ID of the associated person |
|
||||||
|
| ↳ `organization_id` | number | ID of the associated organization |
|
||||||
|
| ↳ `owner_id` | number | ID of the lead owner |
|
||||||
|
| ↳ `value` | object | Lead value |
|
||||||
|
| ↳ `amount` | number | Value amount |
|
||||||
|
| ↳ `currency` | string | Currency code \(e.g., USD, EUR\) |
|
||||||
|
| ↳ `expected_close_date` | string | Expected close date \(YYYY-MM-DD\) |
|
||||||
|
| ↳ `is_archived` | boolean | Whether the lead is archived |
|
||||||
|
| ↳ `was_seen` | boolean | Whether the lead was seen |
|
||||||
|
| ↳ `add_time` | string | When the lead was created \(ISO 8601\) |
|
||||||
|
| ↳ `update_time` | string | When the lead was last updated \(ISO 8601\) |
|
||||||
| `total_items` | number | Total number of leads returned |
|
| `total_items` | number | Total number of leads returned |
|
||||||
| `success` | boolean | Operation success status |
|
| `success` | boolean | Operation success status |
|
||||||
|
|
||||||
|
|||||||
@@ -179,6 +179,27 @@ Introspect PostgreSQL database schema to retrieve table structures, columns, and
|
|||||||
| --------- | ---- | ----------- |
|
| --------- | ---- | ----------- |
|
||||||
| `message` | string | Operation status message |
|
| `message` | string | Operation status message |
|
||||||
| `tables` | array | Array of table schemas with columns, keys, and indexes |
|
| `tables` | array | Array of table schemas with columns, keys, and indexes |
|
||||||
|
| ↳ `name` | string | Table name |
|
||||||
|
| ↳ `schema` | string | Schema name \(e.g., public\) |
|
||||||
|
| ↳ `columns` | array | Table columns |
|
||||||
|
| ↳ `name` | string | Column name |
|
||||||
|
| ↳ `type` | string | Data type \(e.g., integer, varchar, timestamp\) |
|
||||||
|
| ↳ `nullable` | boolean | Whether the column allows NULL values |
|
||||||
|
| ↳ `default` | string | Default value expression |
|
||||||
|
| ↳ `isPrimaryKey` | boolean | Whether the column is part of the primary key |
|
||||||
|
| ↳ `isForeignKey` | boolean | Whether the column is a foreign key |
|
||||||
|
| ↳ `references` | object | Foreign key reference information |
|
||||||
|
| ↳ `table` | string | Referenced table name |
|
||||||
|
| ↳ `column` | string | Referenced column name |
|
||||||
|
| ↳ `primaryKey` | array | Primary key column names |
|
||||||
|
| ↳ `foreignKeys` | array | Foreign key constraints |
|
||||||
|
| ↳ `column` | string | Local column name |
|
||||||
|
| ↳ `referencesTable` | string | Referenced table name |
|
||||||
|
| ↳ `referencesColumn` | string | Referenced column name |
|
||||||
|
| ↳ `indexes` | array | Table indexes |
|
||||||
|
| ↳ `name` | string | Index name |
|
||||||
|
| ↳ `columns` | array | Columns included in the index |
|
||||||
|
| ↳ `unique` | boolean | Whether the index enforces uniqueness |
|
||||||
| `schemas` | array | List of available schemas in the database |
|
| `schemas` | array | List of available schemas in the database |
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -56,8 +56,10 @@ Insert or update points in a Qdrant collection
|
|||||||
|
|
||||||
| Parameter | Type | Description |
|
| Parameter | Type | Description |
|
||||||
| --------- | ---- | ----------- |
|
| --------- | ---- | ----------- |
|
||||||
| `status` | string | Status of the upsert operation |
|
| `status` | string | Operation status \(ok, error\) |
|
||||||
| `data` | object | Result data from the upsert operation |
|
| `data` | object | Result data from the upsert operation |
|
||||||
|
| ↳ `operation_id` | number | Operation ID for async tracking |
|
||||||
|
| ↳ `status` | string | Operation status \(acknowledged, completed\) |
|
||||||
|
|
||||||
### `qdrant_search_vector`
|
### `qdrant_search_vector`
|
||||||
|
|
||||||
@@ -81,8 +83,15 @@ Search for similar vectors in a Qdrant collection
|
|||||||
|
|
||||||
| Parameter | Type | Description |
|
| Parameter | Type | Description |
|
||||||
| --------- | ---- | ----------- |
|
| --------- | ---- | ----------- |
|
||||||
|
| `status` | string | Operation status \(ok, error\) |
|
||||||
| `data` | array | Vector search results with ID, score, payload, and optional vector data |
|
| `data` | array | Vector search results with ID, score, payload, and optional vector data |
|
||||||
| `status` | string | Status of the search operation |
|
| ↳ `id` | string | Point ID \(integer or UUID string\) |
|
||||||
|
| ↳ `version` | number | Point version number |
|
||||||
|
| ↳ `score` | number | Similarity score |
|
||||||
|
| ↳ `payload` | json | Point payload data \(key-value pairs\) |
|
||||||
|
| ↳ `vector` | json | Point vector\(s\) - single array or named vectors object |
|
||||||
|
| ↳ `shard_key` | string | Shard key for routing |
|
||||||
|
| ↳ `order_value` | number | Order value for sorting |
|
||||||
|
|
||||||
### `qdrant_fetch_points`
|
### `qdrant_fetch_points`
|
||||||
|
|
||||||
@@ -104,7 +113,12 @@ Fetch points by ID from a Qdrant collection
|
|||||||
|
|
||||||
| Parameter | Type | Description |
|
| Parameter | Type | Description |
|
||||||
| --------- | ---- | ----------- |
|
| --------- | ---- | ----------- |
|
||||||
|
| `status` | string | Operation status \(ok, error\) |
|
||||||
| `data` | array | Fetched points with ID, payload, and optional vector data |
|
| `data` | array | Fetched points with ID, payload, and optional vector data |
|
||||||
| `status` | string | Status of the fetch operation |
|
| ↳ `id` | string | Point ID \(integer or UUID string\) |
|
||||||
|
| ↳ `payload` | json | Point payload data \(key-value pairs\) |
|
||||||
|
| ↳ `vector` | json | Point vector\(s\) - single array or named vectors object |
|
||||||
|
| ↳ `shard_key` | string | Shard key for routing |
|
||||||
|
| ↳ `order_value` | number | Order value for sorting |
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -208,6 +208,10 @@ Submit a new post to a subreddit (text or link)
|
|||||||
| `success` | boolean | Whether the post was submitted successfully |
|
| `success` | boolean | Whether the post was submitted successfully |
|
||||||
| `message` | string | Success or error message |
|
| `message` | string | Success or error message |
|
||||||
| `data` | object | Post data including ID, name, URL, and permalink |
|
| `data` | object | Post data including ID, name, URL, and permalink |
|
||||||
|
| ↳ `id` | string | New post ID |
|
||||||
|
| ↳ `name` | string | Thing fullname \(t3_xxxxx\) |
|
||||||
|
| ↳ `url` | string | Post URL from API response |
|
||||||
|
| ↳ `permalink` | string | Full Reddit permalink |
|
||||||
|
|
||||||
### `reddit_vote`
|
### `reddit_vote`
|
||||||
|
|
||||||
@@ -279,6 +283,10 @@ Add a comment reply to a Reddit post or comment
|
|||||||
| `success` | boolean | Whether the reply was posted successfully |
|
| `success` | boolean | Whether the reply was posted successfully |
|
||||||
| `message` | string | Success or error message |
|
| `message` | string | Success or error message |
|
||||||
| `data` | object | Comment data including ID, name, permalink, and body |
|
| `data` | object | Comment data including ID, name, permalink, and body |
|
||||||
|
| ↳ `id` | string | New comment ID |
|
||||||
|
| ↳ `name` | string | Thing fullname \(t1_xxxxx\) |
|
||||||
|
| ↳ `permalink` | string | Comment permalink |
|
||||||
|
| ↳ `body` | string | Comment body text |
|
||||||
|
|
||||||
### `reddit_edit`
|
### `reddit_edit`
|
||||||
|
|
||||||
@@ -298,6 +306,9 @@ Edit the text of your own Reddit post or comment
|
|||||||
| `success` | boolean | Whether the edit was successful |
|
| `success` | boolean | Whether the edit was successful |
|
||||||
| `message` | string | Success or error message |
|
| `message` | string | Success or error message |
|
||||||
| `data` | object | Updated content data |
|
| `data` | object | Updated content data |
|
||||||
|
| ↳ `id` | string | Edited thing ID |
|
||||||
|
| ↳ `body` | string | Updated comment body \(for comments\) |
|
||||||
|
| ↳ `selftext` | string | Updated post text \(for self posts\) |
|
||||||
|
|
||||||
### `reddit_delete`
|
### `reddit_delete`
|
||||||
|
|
||||||
|
|||||||
@@ -53,14 +53,14 @@ Retrieve accounts from Salesforce CRM
|
|||||||
| --------- | ---- | ----------- |
|
| --------- | ---- | ----------- |
|
||||||
| `success` | boolean | Operation success status |
|
| `success` | boolean | Operation success status |
|
||||||
| `output` | object | Accounts data |
|
| `output` | object | Accounts data |
|
||||||
| ↳ `accounts` | array | Array of account objects |
|
| ↳ `paging` | object | Pagination information from Salesforce API |
|
||||||
| ↳ `paging` | object | Pagination information |
|
| ↳ `nextRecordsUrl` | string | URL to fetch the next batch of records \(present when done is false\) |
|
||||||
| ↳ `nextRecordsUrl` | string | URL for next page of results |
|
| ↳ `totalSize` | number | Total number of records matching the query \(may exceed records returned\) |
|
||||||
| ↳ `totalSize` | number | Total number of records |
|
| ↳ `done` | boolean | Whether all records have been returned \(false if more batches exist\) |
|
||||||
| ↳ `done` | boolean | Whether all records returned |
|
|
||||||
| ↳ `metadata` | object | Response metadata |
|
| ↳ `metadata` | object | Response metadata |
|
||||||
| ↳ `totalReturned` | number | Number of accounts returned |
|
| ↳ `totalReturned` | number | Number of records returned in this response |
|
||||||
| ↳ `hasMore` | boolean | Whether more records exist |
|
| ↳ `hasMore` | boolean | Whether more records exist \(inverse of done\) |
|
||||||
|
| ↳ `accounts` | array | Array of account objects |
|
||||||
| ↳ `success` | boolean | Salesforce operation success |
|
| ↳ `success` | boolean | Salesforce operation success |
|
||||||
|
|
||||||
### `salesforce_create_account`
|
### `salesforce_create_account`
|
||||||
@@ -93,9 +93,9 @@ Create a new account in Salesforce CRM
|
|||||||
| --------- | ---- | ----------- |
|
| --------- | ---- | ----------- |
|
||||||
| `success` | boolean | Operation success status |
|
| `success` | boolean | Operation success status |
|
||||||
| `output` | object | Created account data |
|
| `output` | object | Created account data |
|
||||||
| ↳ `id` | string | Created account ID |
|
| ↳ `id` | string | The Salesforce ID of the newly created record |
|
||||||
| ↳ `success` | boolean | Salesforce operation success |
|
| ↳ `success` | boolean | Whether the create operation was successful |
|
||||||
| ↳ `created` | boolean | Whether account was created |
|
| ↳ `created` | boolean | Whether the record was created \(always true on success\) |
|
||||||
|
|
||||||
### `salesforce_update_account`
|
### `salesforce_update_account`
|
||||||
|
|
||||||
@@ -128,8 +128,8 @@ Update an existing account in Salesforce CRM
|
|||||||
| --------- | ---- | ----------- |
|
| --------- | ---- | ----------- |
|
||||||
| `success` | boolean | Operation success status |
|
| `success` | boolean | Operation success status |
|
||||||
| `output` | object | Updated account data |
|
| `output` | object | Updated account data |
|
||||||
| ↳ `id` | string | Updated account ID |
|
| ↳ `id` | string | The Salesforce ID of the updated record |
|
||||||
| ↳ `updated` | boolean | Whether account was updated |
|
| ↳ `updated` | boolean | Whether the record was updated \(always true on success\) |
|
||||||
|
|
||||||
### `salesforce_delete_account`
|
### `salesforce_delete_account`
|
||||||
|
|
||||||
@@ -149,8 +149,8 @@ Delete an account from Salesforce CRM
|
|||||||
| --------- | ---- | ----------- |
|
| --------- | ---- | ----------- |
|
||||||
| `success` | boolean | Operation success status |
|
| `success` | boolean | Operation success status |
|
||||||
| `output` | object | Deleted account data |
|
| `output` | object | Deleted account data |
|
||||||
| ↳ `id` | string | Deleted account ID |
|
| ↳ `id` | string | The Salesforce ID of the deleted record |
|
||||||
| ↳ `deleted` | boolean | Whether account was deleted |
|
| ↳ `deleted` | boolean | Whether the record was deleted \(always true on success\) |
|
||||||
|
|
||||||
### `salesforce_get_contacts`
|
### `salesforce_get_contacts`
|
||||||
|
|
||||||
@@ -173,15 +173,15 @@ Get contact(s) from Salesforce - single contact if ID provided, or list if not
|
|||||||
| --------- | ---- | ----------- |
|
| --------- | ---- | ----------- |
|
||||||
| `success` | boolean | Operation success status |
|
| `success` | boolean | Operation success status |
|
||||||
| `output` | object | Contact\(s\) data |
|
| `output` | object | Contact\(s\) data |
|
||||||
|
| ↳ `paging` | object | Pagination information from Salesforce API |
|
||||||
|
| ↳ `nextRecordsUrl` | string | URL to fetch the next batch of records \(present when done is false\) |
|
||||||
|
| ↳ `totalSize` | number | Total number of records matching the query \(may exceed records returned\) |
|
||||||
|
| ↳ `done` | boolean | Whether all records have been returned \(false if more batches exist\) |
|
||||||
|
| ↳ `metadata` | object | Response metadata |
|
||||||
|
| ↳ `totalReturned` | number | Number of records returned in this response |
|
||||||
|
| ↳ `hasMore` | boolean | Whether more records exist \(inverse of done\) |
|
||||||
| ↳ `contacts` | array | Array of contacts \(list query\) |
|
| ↳ `contacts` | array | Array of contacts \(list query\) |
|
||||||
| ↳ `contact` | object | Single contact \(by ID\) |
|
| ↳ `contact` | object | Single contact \(by ID\) |
|
||||||
| ↳ `paging` | object | Pagination information |
|
|
||||||
| ↳ `nextRecordsUrl` | string | URL for next page of results |
|
|
||||||
| ↳ `totalSize` | number | Total number of records |
|
|
||||||
| ↳ `done` | boolean | Whether all records returned |
|
|
||||||
| ↳ `metadata` | object | Response metadata |
|
|
||||||
| ↳ `totalReturned` | number | Number of contacts returned |
|
|
||||||
| ↳ `hasMore` | boolean | Whether more records exist |
|
|
||||||
| ↳ `singleContact` | boolean | Whether single contact was returned |
|
| ↳ `singleContact` | boolean | Whether single contact was returned |
|
||||||
| ↳ `success` | boolean | Salesforce operation success |
|
| ↳ `success` | boolean | Salesforce operation success |
|
||||||
|
|
||||||
@@ -215,9 +215,9 @@ Create a new contact in Salesforce CRM
|
|||||||
| --------- | ---- | ----------- |
|
| --------- | ---- | ----------- |
|
||||||
| `success` | boolean | Operation success status |
|
| `success` | boolean | Operation success status |
|
||||||
| `output` | object | Created contact data |
|
| `output` | object | Created contact data |
|
||||||
| ↳ `id` | string | Created contact ID |
|
| ↳ `id` | string | The Salesforce ID of the newly created record |
|
||||||
| ↳ `success` | boolean | Salesforce operation success |
|
| ↳ `success` | boolean | Whether the create operation was successful |
|
||||||
| ↳ `created` | boolean | Whether contact was created |
|
| ↳ `created` | boolean | Whether the record was created \(always true on success\) |
|
||||||
|
|
||||||
### `salesforce_update_contact`
|
### `salesforce_update_contact`
|
||||||
|
|
||||||
@@ -250,8 +250,8 @@ Update an existing contact in Salesforce CRM
|
|||||||
| --------- | ---- | ----------- |
|
| --------- | ---- | ----------- |
|
||||||
| `success` | boolean | Operation success status |
|
| `success` | boolean | Operation success status |
|
||||||
| `output` | object | Updated contact data |
|
| `output` | object | Updated contact data |
|
||||||
| ↳ `id` | string | Updated contact ID |
|
| ↳ `id` | string | The Salesforce ID of the updated record |
|
||||||
| ↳ `updated` | boolean | Whether contact was updated |
|
| ↳ `updated` | boolean | Whether the record was updated \(always true on success\) |
|
||||||
|
|
||||||
### `salesforce_delete_contact`
|
### `salesforce_delete_contact`
|
||||||
|
|
||||||
@@ -271,8 +271,8 @@ Delete a contact from Salesforce CRM
|
|||||||
| --------- | ---- | ----------- |
|
| --------- | ---- | ----------- |
|
||||||
| `success` | boolean | Operation success status |
|
| `success` | boolean | Operation success status |
|
||||||
| `output` | object | Deleted contact data |
|
| `output` | object | Deleted contact data |
|
||||||
| ↳ `id` | string | Deleted contact ID |
|
| ↳ `id` | string | The Salesforce ID of the deleted record |
|
||||||
| ↳ `deleted` | boolean | Whether contact was deleted |
|
| ↳ `deleted` | boolean | Whether the record was deleted \(always true on success\) |
|
||||||
|
|
||||||
### `salesforce_get_leads`
|
### `salesforce_get_leads`
|
||||||
|
|
||||||
@@ -295,15 +295,15 @@ Get lead(s) from Salesforce
|
|||||||
| --------- | ---- | ----------- |
|
| --------- | ---- | ----------- |
|
||||||
| `success` | boolean | Operation success status |
|
| `success` | boolean | Operation success status |
|
||||||
| `output` | object | Lead data |
|
| `output` | object | Lead data |
|
||||||
|
| ↳ `paging` | object | Pagination information from Salesforce API |
|
||||||
|
| ↳ `nextRecordsUrl` | string | URL to fetch the next batch of records \(present when done is false\) |
|
||||||
|
| ↳ `totalSize` | number | Total number of records matching the query \(may exceed records returned\) |
|
||||||
|
| ↳ `done` | boolean | Whether all records have been returned \(false if more batches exist\) |
|
||||||
|
| ↳ `metadata` | object | Response metadata |
|
||||||
|
| ↳ `totalReturned` | number | Number of records returned in this response |
|
||||||
|
| ↳ `hasMore` | boolean | Whether more records exist \(inverse of done\) |
|
||||||
| ↳ `lead` | object | Single lead object \(when leadId provided\) |
|
| ↳ `lead` | object | Single lead object \(when leadId provided\) |
|
||||||
| ↳ `leads` | array | Array of lead objects \(when listing\) |
|
| ↳ `leads` | array | Array of lead objects \(when listing\) |
|
||||||
| ↳ `paging` | object | Pagination information |
|
|
||||||
| ↳ `nextRecordsUrl` | string | URL for next page of results |
|
|
||||||
| ↳ `totalSize` | number | Total number of records |
|
|
||||||
| ↳ `done` | boolean | Whether all records returned |
|
|
||||||
| ↳ `metadata` | object | Response metadata |
|
|
||||||
| ↳ `totalReturned` | number | Number of leads returned |
|
|
||||||
| ↳ `hasMore` | boolean | Whether more records exist |
|
|
||||||
| ↳ `singleLead` | boolean | Whether single lead was returned |
|
| ↳ `singleLead` | boolean | Whether single lead was returned |
|
||||||
| ↳ `success` | boolean | Operation success status |
|
| ↳ `success` | boolean | Operation success status |
|
||||||
|
|
||||||
@@ -333,9 +333,9 @@ Create a new lead
|
|||||||
| --------- | ---- | ----------- |
|
| --------- | ---- | ----------- |
|
||||||
| `success` | boolean | Operation success status |
|
| `success` | boolean | Operation success status |
|
||||||
| `output` | object | Created lead data |
|
| `output` | object | Created lead data |
|
||||||
| ↳ `id` | string | Created lead ID |
|
| ↳ `id` | string | The Salesforce ID of the newly created record |
|
||||||
| ↳ `success` | boolean | Salesforce operation success |
|
| ↳ `success` | boolean | Whether the create operation was successful |
|
||||||
| ↳ `created` | boolean | Whether lead was created |
|
| ↳ `created` | boolean | Whether the record was created \(always true on success\) |
|
||||||
|
|
||||||
### `salesforce_update_lead`
|
### `salesforce_update_lead`
|
||||||
|
|
||||||
@@ -364,8 +364,8 @@ Update an existing lead
|
|||||||
| --------- | ---- | ----------- |
|
| --------- | ---- | ----------- |
|
||||||
| `success` | boolean | Operation success status |
|
| `success` | boolean | Operation success status |
|
||||||
| `output` | object | Updated lead data |
|
| `output` | object | Updated lead data |
|
||||||
| ↳ `id` | string | Updated lead ID |
|
| ↳ `id` | string | The Salesforce ID of the updated record |
|
||||||
| ↳ `updated` | boolean | Whether lead was updated |
|
| ↳ `updated` | boolean | Whether the record was updated \(always true on success\) |
|
||||||
|
|
||||||
### `salesforce_delete_lead`
|
### `salesforce_delete_lead`
|
||||||
|
|
||||||
@@ -385,8 +385,8 @@ Delete a lead
|
|||||||
| --------- | ---- | ----------- |
|
| --------- | ---- | ----------- |
|
||||||
| `success` | boolean | Operation success status |
|
| `success` | boolean | Operation success status |
|
||||||
| `output` | object | Deleted lead data |
|
| `output` | object | Deleted lead data |
|
||||||
| ↳ `id` | string | Deleted lead ID |
|
| ↳ `id` | string | The Salesforce ID of the deleted record |
|
||||||
| ↳ `deleted` | boolean | Whether lead was deleted |
|
| ↳ `deleted` | boolean | Whether the record was deleted \(always true on success\) |
|
||||||
|
|
||||||
### `salesforce_get_opportunities`
|
### `salesforce_get_opportunities`
|
||||||
|
|
||||||
@@ -409,15 +409,15 @@ Get opportunity(ies) from Salesforce
|
|||||||
| --------- | ---- | ----------- |
|
| --------- | ---- | ----------- |
|
||||||
| `success` | boolean | Operation success status |
|
| `success` | boolean | Operation success status |
|
||||||
| `output` | object | Opportunity data |
|
| `output` | object | Opportunity data |
|
||||||
|
| ↳ `paging` | object | Pagination information from Salesforce API |
|
||||||
|
| ↳ `nextRecordsUrl` | string | URL to fetch the next batch of records \(present when done is false\) |
|
||||||
|
| ↳ `totalSize` | number | Total number of records matching the query \(may exceed records returned\) |
|
||||||
|
| ↳ `done` | boolean | Whether all records have been returned \(false if more batches exist\) |
|
||||||
|
| ↳ `metadata` | object | Response metadata |
|
||||||
|
| ↳ `totalReturned` | number | Number of records returned in this response |
|
||||||
|
| ↳ `hasMore` | boolean | Whether more records exist \(inverse of done\) |
|
||||||
| ↳ `opportunity` | object | Single opportunity object \(when opportunityId provided\) |
|
| ↳ `opportunity` | object | Single opportunity object \(when opportunityId provided\) |
|
||||||
| ↳ `opportunities` | array | Array of opportunity objects \(when listing\) |
|
| ↳ `opportunities` | array | Array of opportunity objects \(when listing\) |
|
||||||
| ↳ `paging` | object | Pagination information |
|
|
||||||
| ↳ `nextRecordsUrl` | string | URL for next page of results |
|
|
||||||
| ↳ `totalSize` | number | Total number of records |
|
|
||||||
| ↳ `done` | boolean | Whether all records returned |
|
|
||||||
| ↳ `metadata` | object | Response metadata |
|
|
||||||
| ↳ `totalReturned` | number | Number of opportunities returned |
|
|
||||||
| ↳ `hasMore` | boolean | Whether more records exist |
|
|
||||||
| ↳ `success` | boolean | Operation success status |
|
| ↳ `success` | boolean | Operation success status |
|
||||||
|
|
||||||
### `salesforce_create_opportunity`
|
### `salesforce_create_opportunity`
|
||||||
@@ -444,9 +444,9 @@ Create a new opportunity
|
|||||||
| --------- | ---- | ----------- |
|
| --------- | ---- | ----------- |
|
||||||
| `success` | boolean | Operation success status |
|
| `success` | boolean | Operation success status |
|
||||||
| `output` | object | Created opportunity data |
|
| `output` | object | Created opportunity data |
|
||||||
| ↳ `id` | string | Created opportunity ID |
|
| ↳ `id` | string | The Salesforce ID of the newly created record |
|
||||||
| ↳ `success` | boolean | Salesforce operation success |
|
| ↳ `success` | boolean | Whether the create operation was successful |
|
||||||
| ↳ `created` | boolean | Whether opportunity was created |
|
| ↳ `created` | boolean | Whether the record was created \(always true on success\) |
|
||||||
|
|
||||||
### `salesforce_update_opportunity`
|
### `salesforce_update_opportunity`
|
||||||
|
|
||||||
@@ -473,8 +473,8 @@ Update an existing opportunity
|
|||||||
| --------- | ---- | ----------- |
|
| --------- | ---- | ----------- |
|
||||||
| `success` | boolean | Operation success status |
|
| `success` | boolean | Operation success status |
|
||||||
| `output` | object | Updated opportunity data |
|
| `output` | object | Updated opportunity data |
|
||||||
| ↳ `id` | string | Updated opportunity ID |
|
| ↳ `id` | string | The Salesforce ID of the updated record |
|
||||||
| ↳ `updated` | boolean | Whether opportunity was updated |
|
| ↳ `updated` | boolean | Whether the record was updated \(always true on success\) |
|
||||||
|
|
||||||
### `salesforce_delete_opportunity`
|
### `salesforce_delete_opportunity`
|
||||||
|
|
||||||
@@ -494,8 +494,8 @@ Delete an opportunity
|
|||||||
| --------- | ---- | ----------- |
|
| --------- | ---- | ----------- |
|
||||||
| `success` | boolean | Operation success status |
|
| `success` | boolean | Operation success status |
|
||||||
| `output` | object | Deleted opportunity data |
|
| `output` | object | Deleted opportunity data |
|
||||||
| ↳ `id` | string | Deleted opportunity ID |
|
| ↳ `id` | string | The Salesforce ID of the deleted record |
|
||||||
| ↳ `deleted` | boolean | Whether opportunity was deleted |
|
| ↳ `deleted` | boolean | Whether the record was deleted \(always true on success\) |
|
||||||
|
|
||||||
### `salesforce_get_cases`
|
### `salesforce_get_cases`
|
||||||
|
|
||||||
@@ -518,15 +518,15 @@ Get case(s) from Salesforce
|
|||||||
| --------- | ---- | ----------- |
|
| --------- | ---- | ----------- |
|
||||||
| `success` | boolean | Operation success status |
|
| `success` | boolean | Operation success status |
|
||||||
| `output` | object | Case data |
|
| `output` | object | Case data |
|
||||||
|
| ↳ `paging` | object | Pagination information from Salesforce API |
|
||||||
|
| ↳ `nextRecordsUrl` | string | URL to fetch the next batch of records \(present when done is false\) |
|
||||||
|
| ↳ `totalSize` | number | Total number of records matching the query \(may exceed records returned\) |
|
||||||
|
| ↳ `done` | boolean | Whether all records have been returned \(false if more batches exist\) |
|
||||||
|
| ↳ `metadata` | object | Response metadata |
|
||||||
|
| ↳ `totalReturned` | number | Number of records returned in this response |
|
||||||
|
| ↳ `hasMore` | boolean | Whether more records exist \(inverse of done\) |
|
||||||
| ↳ `case` | object | Single case object \(when caseId provided\) |
|
| ↳ `case` | object | Single case object \(when caseId provided\) |
|
||||||
| ↳ `cases` | array | Array of case objects \(when listing\) |
|
| ↳ `cases` | array | Array of case objects \(when listing\) |
|
||||||
| ↳ `paging` | object | Pagination information |
|
|
||||||
| ↳ `nextRecordsUrl` | string | URL for next page of results |
|
|
||||||
| ↳ `totalSize` | number | Total number of records |
|
|
||||||
| ↳ `done` | boolean | Whether all records returned |
|
|
||||||
| ↳ `metadata` | object | Response metadata |
|
|
||||||
| ↳ `totalReturned` | number | Number of cases returned |
|
|
||||||
| ↳ `hasMore` | boolean | Whether more records exist |
|
|
||||||
| ↳ `success` | boolean | Operation success status |
|
| ↳ `success` | boolean | Operation success status |
|
||||||
|
|
||||||
### `salesforce_create_case`
|
### `salesforce_create_case`
|
||||||
@@ -553,9 +553,9 @@ Create a new case
|
|||||||
| --------- | ---- | ----------- |
|
| --------- | ---- | ----------- |
|
||||||
| `success` | boolean | Operation success status |
|
| `success` | boolean | Operation success status |
|
||||||
| `output` | object | Created case data |
|
| `output` | object | Created case data |
|
||||||
| ↳ `id` | string | Created case ID |
|
| ↳ `id` | string | The Salesforce ID of the newly created record |
|
||||||
| ↳ `success` | boolean | Salesforce operation success |
|
| ↳ `success` | boolean | Whether the create operation was successful |
|
||||||
| ↳ `created` | boolean | Whether case was created |
|
| ↳ `created` | boolean | Whether the record was created \(always true on success\) |
|
||||||
|
|
||||||
### `salesforce_update_case`
|
### `salesforce_update_case`
|
||||||
|
|
||||||
@@ -579,8 +579,8 @@ Update an existing case
|
|||||||
| --------- | ---- | ----------- |
|
| --------- | ---- | ----------- |
|
||||||
| `success` | boolean | Operation success status |
|
| `success` | boolean | Operation success status |
|
||||||
| `output` | object | Updated case data |
|
| `output` | object | Updated case data |
|
||||||
| ↳ `id` | string | Updated case ID |
|
| ↳ `id` | string | The Salesforce ID of the updated record |
|
||||||
| ↳ `updated` | boolean | Whether case was updated |
|
| ↳ `updated` | boolean | Whether the record was updated \(always true on success\) |
|
||||||
|
|
||||||
### `salesforce_delete_case`
|
### `salesforce_delete_case`
|
||||||
|
|
||||||
@@ -600,8 +600,8 @@ Delete a case
|
|||||||
| --------- | ---- | ----------- |
|
| --------- | ---- | ----------- |
|
||||||
| `success` | boolean | Operation success status |
|
| `success` | boolean | Operation success status |
|
||||||
| `output` | object | Deleted case data |
|
| `output` | object | Deleted case data |
|
||||||
| ↳ `id` | string | Deleted case ID |
|
| ↳ `id` | string | The Salesforce ID of the deleted record |
|
||||||
| ↳ `deleted` | boolean | Whether case was deleted |
|
| ↳ `deleted` | boolean | Whether the record was deleted \(always true on success\) |
|
||||||
|
|
||||||
### `salesforce_get_tasks`
|
### `salesforce_get_tasks`
|
||||||
|
|
||||||
@@ -624,15 +624,15 @@ Get task(s) from Salesforce
|
|||||||
| --------- | ---- | ----------- |
|
| --------- | ---- | ----------- |
|
||||||
| `success` | boolean | Operation success status |
|
| `success` | boolean | Operation success status |
|
||||||
| `output` | object | Task data |
|
| `output` | object | Task data |
|
||||||
|
| ↳ `paging` | object | Pagination information from Salesforce API |
|
||||||
|
| ↳ `nextRecordsUrl` | string | URL to fetch the next batch of records \(present when done is false\) |
|
||||||
|
| ↳ `totalSize` | number | Total number of records matching the query \(may exceed records returned\) |
|
||||||
|
| ↳ `done` | boolean | Whether all records have been returned \(false if more batches exist\) |
|
||||||
|
| ↳ `metadata` | object | Response metadata |
|
||||||
|
| ↳ `totalReturned` | number | Number of records returned in this response |
|
||||||
|
| ↳ `hasMore` | boolean | Whether more records exist \(inverse of done\) |
|
||||||
| ↳ `task` | object | Single task object \(when taskId provided\) |
|
| ↳ `task` | object | Single task object \(when taskId provided\) |
|
||||||
| ↳ `tasks` | array | Array of task objects \(when listing\) |
|
| ↳ `tasks` | array | Array of task objects \(when listing\) |
|
||||||
| ↳ `paging` | object | Pagination information |
|
|
||||||
| ↳ `nextRecordsUrl` | string | URL for next page of results |
|
|
||||||
| ↳ `totalSize` | number | Total number of records |
|
|
||||||
| ↳ `done` | boolean | Whether all records returned |
|
|
||||||
| ↳ `metadata` | object | Response metadata |
|
|
||||||
| ↳ `totalReturned` | number | Number of tasks returned |
|
|
||||||
| ↳ `hasMore` | boolean | Whether more records exist |
|
|
||||||
| ↳ `success` | boolean | Operation success status |
|
| ↳ `success` | boolean | Operation success status |
|
||||||
|
|
||||||
### `salesforce_create_task`
|
### `salesforce_create_task`
|
||||||
@@ -659,9 +659,9 @@ Create a new task
|
|||||||
| --------- | ---- | ----------- |
|
| --------- | ---- | ----------- |
|
||||||
| `success` | boolean | Operation success status |
|
| `success` | boolean | Operation success status |
|
||||||
| `output` | object | Created task data |
|
| `output` | object | Created task data |
|
||||||
| ↳ `id` | string | Created task ID |
|
| ↳ `id` | string | The Salesforce ID of the newly created record |
|
||||||
| ↳ `success` | boolean | Salesforce operation success |
|
| ↳ `success` | boolean | Whether the create operation was successful |
|
||||||
| ↳ `created` | boolean | Whether task was created |
|
| ↳ `created` | boolean | Whether the record was created \(always true on success\) |
|
||||||
|
|
||||||
### `salesforce_update_task`
|
### `salesforce_update_task`
|
||||||
|
|
||||||
@@ -686,8 +686,8 @@ Update an existing task
|
|||||||
| --------- | ---- | ----------- |
|
| --------- | ---- | ----------- |
|
||||||
| `success` | boolean | Operation success status |
|
| `success` | boolean | Operation success status |
|
||||||
| `output` | object | Updated task data |
|
| `output` | object | Updated task data |
|
||||||
| ↳ `id` | string | Updated task ID |
|
| ↳ `id` | string | The Salesforce ID of the updated record |
|
||||||
| ↳ `updated` | boolean | Whether task was updated |
|
| ↳ `updated` | boolean | Whether the record was updated \(always true on success\) |
|
||||||
|
|
||||||
### `salesforce_delete_task`
|
### `salesforce_delete_task`
|
||||||
|
|
||||||
@@ -707,8 +707,8 @@ Delete a task
|
|||||||
| --------- | ---- | ----------- |
|
| --------- | ---- | ----------- |
|
||||||
| `success` | boolean | Operation success status |
|
| `success` | boolean | Operation success status |
|
||||||
| `output` | object | Deleted task data |
|
| `output` | object | Deleted task data |
|
||||||
| ↳ `id` | string | Deleted task ID |
|
| ↳ `id` | string | The Salesforce ID of the deleted record |
|
||||||
| ↳ `deleted` | boolean | Whether task was deleted |
|
| ↳ `deleted` | boolean | Whether the record was deleted \(always true on success\) |
|
||||||
|
|
||||||
### `salesforce_list_reports`
|
### `salesforce_list_reports`
|
||||||
|
|
||||||
@@ -729,9 +729,9 @@ Get a list of reports accessible by the current user
|
|||||||
| --------- | ---- | ----------- |
|
| --------- | ---- | ----------- |
|
||||||
| `success` | boolean | Operation success status |
|
| `success` | boolean | Operation success status |
|
||||||
| `output` | object | Reports data |
|
| `output` | object | Reports data |
|
||||||
| ↳ `reports` | array | Array of report objects |
|
| ↳ `totalReturned` | number | Number of items returned |
|
||||||
| ↳ `totalReturned` | number | Number of reports returned |
|
|
||||||
| ↳ `success` | boolean | Salesforce operation success |
|
| ↳ `success` | boolean | Salesforce operation success |
|
||||||
|
| ↳ `reports` | array | Array of report objects |
|
||||||
|
|
||||||
### `salesforce_get_report`
|
### `salesforce_get_report`
|
||||||
|
|
||||||
@@ -776,15 +776,15 @@ Execute a report and retrieve the results
|
|||||||
| `success` | boolean | Operation success status |
|
| `success` | boolean | Operation success status |
|
||||||
| `output` | object | Report results |
|
| `output` | object | Report results |
|
||||||
| ↳ `reportId` | string | Report ID |
|
| ↳ `reportId` | string | Report ID |
|
||||||
| ↳ `reportMetadata` | object | Report metadata |
|
| ↳ `reportMetadata` | object | Report metadata including name, format, and filter definitions |
|
||||||
| ↳ `reportExtendedMetadata` | object | Extended metadata |
|
| ↳ `reportExtendedMetadata` | object | Extended metadata for aggregate columns and groupings |
|
||||||
| ↳ `factMap` | object | Report data organized by groupings |
|
| ↳ `factMap` | object | Report data organized by groupings with aggregates and row data |
|
||||||
| ↳ `groupingsDown` | object | Row groupings |
|
| ↳ `groupingsDown` | object | Row grouping hierarchy and values |
|
||||||
| ↳ `groupingsAcross` | object | Column groupings |
|
| ↳ `groupingsAcross` | object | Column grouping hierarchy and values |
|
||||||
| ↳ `hasDetailRows` | boolean | Whether report has detail rows |
|
| ↳ `hasDetailRows` | boolean | Whether the report includes detail-level row data |
|
||||||
| ↳ `allData` | boolean | Whether all data is returned |
|
| ↳ `allData` | boolean | Whether all data is returned \(false if truncated due to size limits\) |
|
||||||
| ↳ `reportName` | string | Report name |
|
| ↳ `reportName` | string | Display name of the report |
|
||||||
| ↳ `reportFormat` | string | Report format type |
|
| ↳ `reportFormat` | string | Report format type \(TABULAR, SUMMARY, MATRIX, JOINED\) |
|
||||||
| ↳ `success` | boolean | Salesforce operation success |
|
| ↳ `success` | boolean | Salesforce operation success |
|
||||||
|
|
||||||
### `salesforce_list_report_types`
|
### `salesforce_list_report_types`
|
||||||
@@ -804,9 +804,9 @@ Get a list of available report types
|
|||||||
| --------- | ---- | ----------- |
|
| --------- | ---- | ----------- |
|
||||||
| `success` | boolean | Operation success status |
|
| `success` | boolean | Operation success status |
|
||||||
| `output` | object | Report types data |
|
| `output` | object | Report types data |
|
||||||
| ↳ `reportTypes` | array | Array of report type objects |
|
| ↳ `totalReturned` | number | Number of items returned |
|
||||||
| ↳ `totalReturned` | number | Number of report types returned |
|
|
||||||
| ↳ `success` | boolean | Salesforce operation success |
|
| ↳ `success` | boolean | Salesforce operation success |
|
||||||
|
| ↳ `reportTypes` | array | Array of report type objects |
|
||||||
|
|
||||||
### `salesforce_list_dashboards`
|
### `salesforce_list_dashboards`
|
||||||
|
|
||||||
@@ -826,9 +826,9 @@ Get a list of dashboards accessible by the current user
|
|||||||
| --------- | ---- | ----------- |
|
| --------- | ---- | ----------- |
|
||||||
| `success` | boolean | Operation success status |
|
| `success` | boolean | Operation success status |
|
||||||
| `output` | object | Dashboards data |
|
| `output` | object | Dashboards data |
|
||||||
| ↳ `dashboards` | array | Array of dashboard objects |
|
| ↳ `totalReturned` | number | Number of items returned |
|
||||||
| ↳ `totalReturned` | number | Number of dashboards returned |
|
|
||||||
| ↳ `success` | boolean | Salesforce operation success |
|
| ↳ `success` | boolean | Salesforce operation success |
|
||||||
|
| ↳ `dashboards` | array | Array of dashboard objects |
|
||||||
|
|
||||||
### `salesforce_get_dashboard`
|
### `salesforce_get_dashboard`
|
||||||
|
|
||||||
@@ -848,12 +848,12 @@ Get details and results for a specific dashboard
|
|||||||
| --------- | ---- | ----------- |
|
| --------- | ---- | ----------- |
|
||||||
| `success` | boolean | Operation success status |
|
| `success` | boolean | Operation success status |
|
||||||
| `output` | object | Dashboard data |
|
| `output` | object | Dashboard data |
|
||||||
| ↳ `dashboard` | object | Dashboard details |
|
| ↳ `dashboard` | object | Full dashboard details object |
|
||||||
| ↳ `dashboardId` | string | Dashboard ID |
|
| ↳ `dashboardId` | string | Dashboard ID |
|
||||||
| ↳ `components` | array | Dashboard component data |
|
| ↳ `components` | array | Array of dashboard component data with visualizations and filters |
|
||||||
| ↳ `dashboardName` | string | Dashboard name |
|
| ↳ `dashboardName` | string | Display name of the dashboard |
|
||||||
| ↳ `folderId` | string | Folder ID containing the dashboard |
|
| ↳ `folderId` | string | ID of the folder containing the dashboard |
|
||||||
| ↳ `runningUser` | object | Running user information |
|
| ↳ `runningUser` | object | User context under which the dashboard data was retrieved |
|
||||||
| ↳ `success` | boolean | Salesforce operation success |
|
| ↳ `success` | boolean | Salesforce operation success |
|
||||||
|
|
||||||
### `salesforce_refresh_dashboard`
|
### `salesforce_refresh_dashboard`
|
||||||
@@ -874,12 +874,12 @@ Refresh a dashboard to get the latest data
|
|||||||
| --------- | ---- | ----------- |
|
| --------- | ---- | ----------- |
|
||||||
| `success` | boolean | Operation success status |
|
| `success` | boolean | Operation success status |
|
||||||
| `output` | object | Refreshed dashboard data |
|
| `output` | object | Refreshed dashboard data |
|
||||||
| ↳ `dashboard` | object | Dashboard details |
|
| ↳ `dashboard` | object | Full dashboard details object |
|
||||||
| ↳ `dashboardId` | string | Dashboard ID |
|
| ↳ `dashboardId` | string | Dashboard ID |
|
||||||
| ↳ `components` | array | Dashboard component data |
|
| ↳ `components` | array | Array of dashboard component data with fresh visualizations |
|
||||||
| ↳ `status` | object | Dashboard status |
|
| ↳ `status` | object | Dashboard refresh status information |
|
||||||
| ↳ `dashboardName` | string | Dashboard name |
|
| ↳ `dashboardName` | string | Display name of the dashboard |
|
||||||
| ↳ `refreshDate` | string | Date when dashboard was refreshed |
|
| ↳ `refreshDate` | string | ISO 8601 timestamp when the dashboard was last refreshed |
|
||||||
| ↳ `success` | boolean | Salesforce operation success |
|
| ↳ `success` | boolean | Salesforce operation success |
|
||||||
|
|
||||||
### `salesforce_query`
|
### `salesforce_query`
|
||||||
@@ -900,14 +900,11 @@ Execute a custom SOQL query to retrieve data from Salesforce
|
|||||||
| --------- | ---- | ----------- |
|
| --------- | ---- | ----------- |
|
||||||
| `success` | boolean | Operation success status |
|
| `success` | boolean | Operation success status |
|
||||||
| `output` | object | Query results |
|
| `output` | object | Query results |
|
||||||
| ↳ `records` | array | Array of record objects |
|
| ↳ `records` | array | Array of sObject records matching the query |
|
||||||
| ↳ `totalSize` | number | Total number of records matching query |
|
|
||||||
| ↳ `done` | boolean | Whether all records have been returned |
|
|
||||||
| ↳ `nextRecordsUrl` | string | URL to fetch next batch of records |
|
|
||||||
| ↳ `query` | string | The executed SOQL query |
|
| ↳ `query` | string | The executed SOQL query |
|
||||||
| ↳ `metadata` | object | Response metadata |
|
| ↳ `metadata` | object | Response metadata |
|
||||||
| ↳ `totalReturned` | number | Number of records returned in this response |
|
| ↳ `totalReturned` | number | Number of records returned in this response |
|
||||||
| ↳ `hasMore` | boolean | Whether more records exist |
|
| ↳ `hasMore` | boolean | Whether more records exist \(inverse of done\) |
|
||||||
| ↳ `success` | boolean | Salesforce operation success |
|
| ↳ `success` | boolean | Salesforce operation success |
|
||||||
|
|
||||||
### `salesforce_query_more`
|
### `salesforce_query_more`
|
||||||
@@ -928,13 +925,10 @@ Retrieve additional query results using the nextRecordsUrl from a previous query
|
|||||||
| --------- | ---- | ----------- |
|
| --------- | ---- | ----------- |
|
||||||
| `success` | boolean | Operation success status |
|
| `success` | boolean | Operation success status |
|
||||||
| `output` | object | Query results |
|
| `output` | object | Query results |
|
||||||
| ↳ `records` | array | Array of record objects |
|
| ↳ `records` | array | Array of sObject records matching the query |
|
||||||
| ↳ `totalSize` | number | Total number of records matching query |
|
|
||||||
| ↳ `done` | boolean | Whether all records have been returned |
|
|
||||||
| ↳ `nextRecordsUrl` | string | URL to fetch next batch of records |
|
|
||||||
| ↳ `metadata` | object | Response metadata |
|
| ↳ `metadata` | object | Response metadata |
|
||||||
| ↳ `totalReturned` | number | Number of records returned in this response |
|
| ↳ `totalReturned` | number | Number of records returned in this response |
|
||||||
| ↳ `hasMore` | boolean | Whether more records exist |
|
| ↳ `hasMore` | boolean | Whether more records exist \(inverse of done\) |
|
||||||
| ↳ `success` | boolean | Salesforce operation success |
|
| ↳ `success` | boolean | Salesforce operation success |
|
||||||
|
|
||||||
### `salesforce_describe_object`
|
### `salesforce_describe_object`
|
||||||
@@ -955,18 +949,41 @@ Get metadata and field information for a Salesforce object
|
|||||||
| --------- | ---- | ----------- |
|
| --------- | ---- | ----------- |
|
||||||
| `success` | boolean | Operation success status |
|
| `success` | boolean | Operation success status |
|
||||||
| `output` | object | Object metadata |
|
| `output` | object | Object metadata |
|
||||||
| ↳ `objectName` | string | API name of the object |
|
| ↳ `objectName` | string | API name of the object \(e.g., Account, Contact\) |
|
||||||
| ↳ `label` | string | Display label |
|
| ↳ `label` | string | Human-readable singular label for the object |
|
||||||
| ↳ `labelPlural` | string | Plural display label |
|
| ↳ `labelPlural` | string | Human-readable plural label for the object |
|
||||||
| ↳ `fields` | array | Array of field definitions |
|
| ↳ `fields` | array | Array of field metadata objects |
|
||||||
| ↳ `keyPrefix` | string | ID prefix for this object type |
|
| ↳ `name` | string | API name of the field |
|
||||||
| ↳ `queryable` | boolean | Whether object can be queried |
|
| ↳ `label` | string | Display label of the field |
|
||||||
| ↳ `createable` | boolean | Whether records can be created |
|
| ↳ `type` | string | Field data type \(string, boolean, int, double, date, etc.\) |
|
||||||
| ↳ `updateable` | boolean | Whether records can be updated |
|
| ↳ `length` | number | Maximum length for text fields |
|
||||||
| ↳ `deletable` | boolean | Whether records can be deleted |
|
| ↳ `precision` | number | Precision for numeric fields |
|
||||||
| ↳ `childRelationships` | array | Child relationship definitions |
|
| ↳ `scale` | number | Scale for numeric fields |
|
||||||
| ↳ `recordTypeInfos` | array | Record type information |
|
| ↳ `nillable` | boolean | Whether the field can be null |
|
||||||
| ↳ `fieldCount` | number | Number of fields in the object |
|
| ↳ `unique` | boolean | Whether values must be unique |
|
||||||
|
| ↳ `createable` | boolean | Whether field can be set on create |
|
||||||
|
| ↳ `updateable` | boolean | Whether field can be updated |
|
||||||
|
| ↳ `defaultedOnCreate` | boolean | Whether field has default value on create |
|
||||||
|
| ↳ `calculated` | boolean | Whether field is a formula field |
|
||||||
|
| ↳ `autoNumber` | boolean | Whether field is auto-number |
|
||||||
|
| ↳ `externalId` | boolean | Whether field is an external ID |
|
||||||
|
| ↳ `idLookup` | boolean | Whether field can be used in ID lookup |
|
||||||
|
| ↳ `inlineHelpText` | string | Help text for the field |
|
||||||
|
| ↳ `picklistValues` | array | Available picklist values for picklist fields |
|
||||||
|
| ↳ `referenceTo` | array | Objects this field can reference \(for lookup fields\) |
|
||||||
|
| ↳ `relationshipName` | string | Relationship name for lookup fields |
|
||||||
|
| ↳ `custom` | boolean | Whether this is a custom field |
|
||||||
|
| ↳ `filterable` | boolean | Whether field can be used in SOQL filter |
|
||||||
|
| ↳ `groupable` | boolean | Whether field can be used in GROUP BY |
|
||||||
|
| ↳ `sortable` | boolean | Whether field can be used in ORDER BY |
|
||||||
|
| ↳ `keyPrefix` | string | Three-character prefix used in record IDs \(e.g., "001" for Account\) |
|
||||||
|
| ↳ `queryable` | boolean | Whether the object can be queried via SOQL |
|
||||||
|
| ↳ `createable` | boolean | Whether records can be created for this object |
|
||||||
|
| ↳ `updateable` | boolean | Whether records can be updated for this object |
|
||||||
|
| ↳ `deletable` | boolean | Whether records can be deleted for this object |
|
||||||
|
| ↳ `childRelationships` | array | Array of child relationship metadata for related objects |
|
||||||
|
| ↳ `recordTypeInfos` | array | Array of record type information for the object |
|
||||||
|
| ↳ `fieldCount` | number | Total number of fields on the object |
|
||||||
| ↳ `success` | boolean | Salesforce operation success |
|
| ↳ `success` | boolean | Salesforce operation success |
|
||||||
|
|
||||||
### `salesforce_list_objects`
|
### `salesforce_list_objects`
|
||||||
@@ -986,9 +1003,25 @@ Get a list of all available Salesforce objects
|
|||||||
| --------- | ---- | ----------- |
|
| --------- | ---- | ----------- |
|
||||||
| `success` | boolean | Operation success status |
|
| `success` | boolean | Operation success status |
|
||||||
| `output` | object | Objects list |
|
| `output` | object | Objects list |
|
||||||
| ↳ `objects` | array | Array of available Salesforce objects |
|
| ↳ `objects` | array | Array of sObject metadata |
|
||||||
| ↳ `encoding` | string | Encoding used |
|
| ↳ `name` | string | API name of the object |
|
||||||
| ↳ `maxBatchSize` | number | Maximum batch size |
|
| ↳ `label` | string | Display label of the object |
|
||||||
|
| ↳ `labelPlural` | string | Plural display label |
|
||||||
|
| ↳ `keyPrefix` | string | Three-character ID prefix |
|
||||||
|
| ↳ `custom` | boolean | Whether this is a custom object |
|
||||||
|
| ↳ `queryable` | boolean | Whether object can be queried |
|
||||||
|
| ↳ `createable` | boolean | Whether records can be created |
|
||||||
|
| ↳ `updateable` | boolean | Whether records can be updated |
|
||||||
|
| ↳ `deletable` | boolean | Whether records can be deleted |
|
||||||
|
| ↳ `searchable` | boolean | Whether object is searchable |
|
||||||
|
| ↳ `triggerable` | boolean | Whether triggers are supported |
|
||||||
|
| ↳ `layoutable` | boolean | Whether page layouts are supported |
|
||||||
|
| ↳ `replicateable` | boolean | Whether object can be replicated |
|
||||||
|
| ↳ `retrieveable` | boolean | Whether records can be retrieved |
|
||||||
|
| ↳ `undeletable` | boolean | Whether records can be undeleted |
|
||||||
|
| ↳ `urls` | object | URLs for accessing object resources |
|
||||||
|
| ↳ `encoding` | string | Character encoding for the organization \(e.g., UTF-8\) |
|
||||||
|
| ↳ `maxBatchSize` | number | Maximum number of records that can be returned in a single query batch \(typically 200\) |
|
||||||
| ↳ `totalReturned` | number | Number of objects returned |
|
| ↳ `totalReturned` | number | Number of objects returned |
|
||||||
| ↳ `success` | boolean | Salesforce operation success |
|
| ↳ `success` | boolean | Salesforce operation success |
|
||||||
|
|
||||||
|
|||||||
@@ -35,7 +35,7 @@ Integrate Serper into the workflow. Can search the web.
|
|||||||
|
|
||||||
### `serper_search`
|
### `serper_search`
|
||||||
|
|
||||||
A powerful web search tool that provides access to Google search results through Serper.dev API. Supports different types of searches including regular web search, news, places, and images, with each result containing relevant metadata like titles, URLs, snippets, and type-specific information.
|
A powerful web search tool that provides access to Google search results through Serper.dev API. Supports different types of searches including regular web search, news, places, images, videos, and shopping. Returns comprehensive results including organic results, knowledge graph, answer box, people also ask, related searches, and top stories.
|
||||||
|
|
||||||
#### Input
|
#### Input
|
||||||
|
|
||||||
@@ -53,5 +53,17 @@ A powerful web search tool that provides access to Google search results through
|
|||||||
| Parameter | Type | Description |
|
| Parameter | Type | Description |
|
||||||
| --------- | ---- | ----------- |
|
| --------- | ---- | ----------- |
|
||||||
| `searchResults` | array | Search results with titles, links, snippets, and type-specific metadata \(date for news, rating for places, imageUrl for images\) |
|
| `searchResults` | array | Search results with titles, links, snippets, and type-specific metadata \(date for news, rating for places, imageUrl for images\) |
|
||||||
|
| ↳ `title` | string | Result title |
|
||||||
|
| ↳ `link` | string | Result URL |
|
||||||
|
| ↳ `snippet` | string | Result description/snippet |
|
||||||
|
| ↳ `position` | number | Position in search results |
|
||||||
|
| ↳ `date` | string | Publication date \(news/videos\) |
|
||||||
|
| ↳ `imageUrl` | string | Image URL \(images/news/shopping\) |
|
||||||
|
| ↳ `source` | string | Source name \(news/videos/shopping\) |
|
||||||
|
| ↳ `rating` | number | Rating \(places\) |
|
||||||
|
| ↳ `ratingCount` | number | Number of reviews \(places\) |
|
||||||
|
| ↳ `address` | string | Address \(places\) |
|
||||||
|
| ↳ `price` | string | Price \(shopping\) |
|
||||||
|
| ↳ `duration` | string | Duration \(videos\) |
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -53,6 +53,18 @@ Create a new product in your Shopify store
|
|||||||
| Parameter | Type | Description |
|
| Parameter | Type | Description |
|
||||||
| --------- | ---- | ----------- |
|
| --------- | ---- | ----------- |
|
||||||
| `product` | object | The created product |
|
| `product` | object | The created product |
|
||||||
|
| ↳ `id` | string | Unique product identifier \(GID\) |
|
||||||
|
| ↳ `title` | string | Product title |
|
||||||
|
| ↳ `handle` | string | URL-friendly product identifier |
|
||||||
|
| ↳ `descriptionHtml` | string | Product description in HTML format |
|
||||||
|
| ↳ `vendor` | string | Product vendor or manufacturer |
|
||||||
|
| ↳ `productType` | string | Product type classification |
|
||||||
|
| ↳ `tags` | array | Product tags for categorization |
|
||||||
|
| ↳ `status` | string | Product status \(ACTIVE, DRAFT, ARCHIVED\) |
|
||||||
|
| ↳ `createdAt` | string | Creation timestamp \(ISO 8601\) |
|
||||||
|
| ↳ `updatedAt` | string | Last modification timestamp \(ISO 8601\) |
|
||||||
|
| ↳ `variants` | object | Product variants with edges/nodes structure |
|
||||||
|
| ↳ `images` | object | Product images with edges/nodes structure |
|
||||||
|
|
||||||
### `shopify_get_product`
|
### `shopify_get_product`
|
||||||
|
|
||||||
@@ -70,6 +82,18 @@ Get a single product by ID from your Shopify store
|
|||||||
| Parameter | Type | Description |
|
| Parameter | Type | Description |
|
||||||
| --------- | ---- | ----------- |
|
| --------- | ---- | ----------- |
|
||||||
| `product` | object | The product details |
|
| `product` | object | The product details |
|
||||||
|
| ↳ `id` | string | Unique product identifier \(GID\) |
|
||||||
|
| ↳ `title` | string | Product title |
|
||||||
|
| ↳ `handle` | string | URL-friendly product identifier |
|
||||||
|
| ↳ `descriptionHtml` | string | Product description in HTML format |
|
||||||
|
| ↳ `vendor` | string | Product vendor or manufacturer |
|
||||||
|
| ↳ `productType` | string | Product type classification |
|
||||||
|
| ↳ `tags` | array | Product tags for categorization |
|
||||||
|
| ↳ `status` | string | Product status \(ACTIVE, DRAFT, ARCHIVED\) |
|
||||||
|
| ↳ `createdAt` | string | Creation timestamp \(ISO 8601\) |
|
||||||
|
| ↳ `updatedAt` | string | Last modification timestamp \(ISO 8601\) |
|
||||||
|
| ↳ `variants` | object | Product variants with edges/nodes structure |
|
||||||
|
| ↳ `images` | object | Product images with edges/nodes structure |
|
||||||
|
|
||||||
### `shopify_list_products`
|
### `shopify_list_products`
|
||||||
|
|
||||||
@@ -88,7 +112,21 @@ List products from your Shopify store with optional filtering
|
|||||||
| Parameter | Type | Description |
|
| Parameter | Type | Description |
|
||||||
| --------- | ---- | ----------- |
|
| --------- | ---- | ----------- |
|
||||||
| `products` | array | List of products |
|
| `products` | array | List of products |
|
||||||
|
| ↳ `id` | string | Unique product identifier \(GID\) |
|
||||||
|
| ↳ `title` | string | Product title |
|
||||||
|
| ↳ `handle` | string | URL-friendly product identifier |
|
||||||
|
| ↳ `descriptionHtml` | string | Product description in HTML format |
|
||||||
|
| ↳ `vendor` | string | Product vendor or manufacturer |
|
||||||
|
| ↳ `productType` | string | Product type classification |
|
||||||
|
| ↳ `tags` | array | Product tags for categorization |
|
||||||
|
| ↳ `status` | string | Product status \(ACTIVE, DRAFT, ARCHIVED\) |
|
||||||
|
| ↳ `createdAt` | string | Creation timestamp \(ISO 8601\) |
|
||||||
|
| ↳ `updatedAt` | string | Last modification timestamp \(ISO 8601\) |
|
||||||
|
| ↳ `variants` | object | Product variants with edges/nodes structure |
|
||||||
|
| ↳ `images` | object | Product images with edges/nodes structure |
|
||||||
| `pageInfo` | object | Pagination information |
|
| `pageInfo` | object | Pagination information |
|
||||||
|
| ↳ `hasNextPage` | boolean | Whether there are more results after this page |
|
||||||
|
| ↳ `hasPreviousPage` | boolean | Whether there are results before this page |
|
||||||
|
|
||||||
### `shopify_update_product`
|
### `shopify_update_product`
|
||||||
|
|
||||||
@@ -112,6 +150,18 @@ Update an existing product in your Shopify store
|
|||||||
| Parameter | Type | Description |
|
| Parameter | Type | Description |
|
||||||
| --------- | ---- | ----------- |
|
| --------- | ---- | ----------- |
|
||||||
| `product` | object | The updated product |
|
| `product` | object | The updated product |
|
||||||
|
| ↳ `id` | string | Unique product identifier \(GID\) |
|
||||||
|
| ↳ `title` | string | Product title |
|
||||||
|
| ↳ `handle` | string | URL-friendly product identifier |
|
||||||
|
| ↳ `descriptionHtml` | string | Product description in HTML format |
|
||||||
|
| ↳ `vendor` | string | Product vendor or manufacturer |
|
||||||
|
| ↳ `productType` | string | Product type classification |
|
||||||
|
| ↳ `tags` | array | Product tags for categorization |
|
||||||
|
| ↳ `status` | string | Product status \(ACTIVE, DRAFT, ARCHIVED\) |
|
||||||
|
| ↳ `createdAt` | string | Creation timestamp \(ISO 8601\) |
|
||||||
|
| ↳ `updatedAt` | string | Last modification timestamp \(ISO 8601\) |
|
||||||
|
| ↳ `variants` | object | Product variants with edges/nodes structure |
|
||||||
|
| ↳ `images` | object | Product images with edges/nodes structure |
|
||||||
|
|
||||||
### `shopify_delete_product`
|
### `shopify_delete_product`
|
||||||
|
|
||||||
@@ -146,6 +196,27 @@ Get a single order by ID from your Shopify store
|
|||||||
| Parameter | Type | Description |
|
| Parameter | Type | Description |
|
||||||
| --------- | ---- | ----------- |
|
| --------- | ---- | ----------- |
|
||||||
| `order` | object | The order details |
|
| `order` | object | The order details |
|
||||||
|
| ↳ `id` | string | Unique order identifier \(GID\) |
|
||||||
|
| ↳ `name` | string | Order name \(e.g., #1001\) |
|
||||||
|
| ↳ `email` | string | Customer email for the order |
|
||||||
|
| ↳ `phone` | string | Customer phone for the order |
|
||||||
|
| ↳ `createdAt` | string | Order creation timestamp \(ISO 8601\) |
|
||||||
|
| ↳ `updatedAt` | string | Last modification timestamp \(ISO 8601\) |
|
||||||
|
| ↳ `cancelledAt` | string | Cancellation timestamp \(ISO 8601\) |
|
||||||
|
| ↳ `closedAt` | string | Closure timestamp \(ISO 8601\) |
|
||||||
|
| ↳ `displayFinancialStatus` | string | Financial status \(PENDING, AUTHORIZED, PARTIALLY_PAID, PAID, PARTIALLY_REFUNDED, REFUNDED, VOIDED\) |
|
||||||
|
| ↳ `displayFulfillmentStatus` | string | Fulfillment status \(UNFULFILLED, PARTIALLY_FULFILLED, FULFILLED, RESTOCKED, PENDING_FULFILLMENT, OPEN, IN_PROGRESS, ON_HOLD, SCHEDULED\) |
|
||||||
|
| ↳ `totalPriceSet` | object | Total order price |
|
||||||
|
| ↳ `subtotalPriceSet` | object | Order subtotal \(before shipping and taxes\) |
|
||||||
|
| ↳ `totalTaxSet` | object | Total tax amount |
|
||||||
|
| ↳ `totalShippingPriceSet` | object | Total shipping price |
|
||||||
|
| ↳ `note` | string | Order note |
|
||||||
|
| ↳ `tags` | array | Order tags |
|
||||||
|
| ↳ `customer` | object | Customer who placed the order |
|
||||||
|
| ↳ `lineItems` | object | Order line items with edges/nodes structure |
|
||||||
|
| ↳ `shippingAddress` | object | Shipping address |
|
||||||
|
| ↳ `billingAddress` | object | Billing address |
|
||||||
|
| ↳ `fulfillments` | array | Order fulfillments |
|
||||||
|
|
||||||
### `shopify_list_orders`
|
### `shopify_list_orders`
|
||||||
|
|
||||||
@@ -165,7 +236,30 @@ List orders from your Shopify store with optional filtering
|
|||||||
| Parameter | Type | Description |
|
| Parameter | Type | Description |
|
||||||
| --------- | ---- | ----------- |
|
| --------- | ---- | ----------- |
|
||||||
| `orders` | array | List of orders |
|
| `orders` | array | List of orders |
|
||||||
|
| ↳ `id` | string | Unique order identifier \(GID\) |
|
||||||
|
| ↳ `name` | string | Order name \(e.g., #1001\) |
|
||||||
|
| ↳ `email` | string | Customer email for the order |
|
||||||
|
| ↳ `phone` | string | Customer phone for the order |
|
||||||
|
| ↳ `createdAt` | string | Order creation timestamp \(ISO 8601\) |
|
||||||
|
| ↳ `updatedAt` | string | Last modification timestamp \(ISO 8601\) |
|
||||||
|
| ↳ `cancelledAt` | string | Cancellation timestamp \(ISO 8601\) |
|
||||||
|
| ↳ `closedAt` | string | Closure timestamp \(ISO 8601\) |
|
||||||
|
| ↳ `displayFinancialStatus` | string | Financial status \(PENDING, AUTHORIZED, PARTIALLY_PAID, PAID, PARTIALLY_REFUNDED, REFUNDED, VOIDED\) |
|
||||||
|
| ↳ `displayFulfillmentStatus` | string | Fulfillment status \(UNFULFILLED, PARTIALLY_FULFILLED, FULFILLED, RESTOCKED, PENDING_FULFILLMENT, OPEN, IN_PROGRESS, ON_HOLD, SCHEDULED\) |
|
||||||
|
| ↳ `totalPriceSet` | object | Total order price |
|
||||||
|
| ↳ `subtotalPriceSet` | object | Order subtotal \(before shipping and taxes\) |
|
||||||
|
| ↳ `totalTaxSet` | object | Total tax amount |
|
||||||
|
| ↳ `totalShippingPriceSet` | object | Total shipping price |
|
||||||
|
| ↳ `note` | string | Order note |
|
||||||
|
| ↳ `tags` | array | Order tags |
|
||||||
|
| ↳ `customer` | object | Customer who placed the order |
|
||||||
|
| ↳ `lineItems` | object | Order line items with edges/nodes structure |
|
||||||
|
| ↳ `shippingAddress` | object | Shipping address |
|
||||||
|
| ↳ `billingAddress` | object | Billing address |
|
||||||
|
| ↳ `fulfillments` | array | Order fulfillments |
|
||||||
| `pageInfo` | object | Pagination information |
|
| `pageInfo` | object | Pagination information |
|
||||||
|
| ↳ `hasNextPage` | boolean | Whether there are more results after this page |
|
||||||
|
| ↳ `hasPreviousPage` | boolean | Whether there are results before this page |
|
||||||
|
|
||||||
### `shopify_update_order`
|
### `shopify_update_order`
|
||||||
|
|
||||||
@@ -186,6 +280,27 @@ Update an existing order in your Shopify store (note, tags, email)
|
|||||||
| Parameter | Type | Description |
|
| Parameter | Type | Description |
|
||||||
| --------- | ---- | ----------- |
|
| --------- | ---- | ----------- |
|
||||||
| `order` | object | The updated order |
|
| `order` | object | The updated order |
|
||||||
|
| ↳ `id` | string | Unique order identifier \(GID\) |
|
||||||
|
| ↳ `name` | string | Order name \(e.g., #1001\) |
|
||||||
|
| ↳ `email` | string | Customer email for the order |
|
||||||
|
| ↳ `phone` | string | Customer phone for the order |
|
||||||
|
| ↳ `createdAt` | string | Order creation timestamp \(ISO 8601\) |
|
||||||
|
| ↳ `updatedAt` | string | Last modification timestamp \(ISO 8601\) |
|
||||||
|
| ↳ `cancelledAt` | string | Cancellation timestamp \(ISO 8601\) |
|
||||||
|
| ↳ `closedAt` | string | Closure timestamp \(ISO 8601\) |
|
||||||
|
| ↳ `displayFinancialStatus` | string | Financial status \(PENDING, AUTHORIZED, PARTIALLY_PAID, PAID, PARTIALLY_REFUNDED, REFUNDED, VOIDED\) |
|
||||||
|
| ↳ `displayFulfillmentStatus` | string | Fulfillment status \(UNFULFILLED, PARTIALLY_FULFILLED, FULFILLED, RESTOCKED, PENDING_FULFILLMENT, OPEN, IN_PROGRESS, ON_HOLD, SCHEDULED\) |
|
||||||
|
| ↳ `totalPriceSet` | object | Total order price |
|
||||||
|
| ↳ `subtotalPriceSet` | object | Order subtotal \(before shipping and taxes\) |
|
||||||
|
| ↳ `totalTaxSet` | object | Total tax amount |
|
||||||
|
| ↳ `totalShippingPriceSet` | object | Total shipping price |
|
||||||
|
| ↳ `note` | string | Order note |
|
||||||
|
| ↳ `tags` | array | Order tags |
|
||||||
|
| ↳ `customer` | object | Customer who placed the order |
|
||||||
|
| ↳ `lineItems` | object | Order line items with edges/nodes structure |
|
||||||
|
| ↳ `shippingAddress` | object | Shipping address |
|
||||||
|
| ↳ `billingAddress` | object | Billing address |
|
||||||
|
| ↳ `fulfillments` | array | Order fulfillments |
|
||||||
|
|
||||||
### `shopify_cancel_order`
|
### `shopify_cancel_order`
|
||||||
|
|
||||||
@@ -208,6 +323,9 @@ Cancel an order in your Shopify store
|
|||||||
| Parameter | Type | Description |
|
| Parameter | Type | Description |
|
||||||
| --------- | ---- | ----------- |
|
| --------- | ---- | ----------- |
|
||||||
| `order` | object | The cancellation result |
|
| `order` | object | The cancellation result |
|
||||||
|
| ↳ `id` | string | Job identifier for the cancellation |
|
||||||
|
| ↳ `cancelled` | boolean | Whether the cancellation completed |
|
||||||
|
| ↳ `message` | string | Status message |
|
||||||
|
|
||||||
### `shopify_create_customer`
|
### `shopify_create_customer`
|
||||||
|
|
||||||
@@ -231,6 +349,18 @@ Create a new customer in your Shopify store
|
|||||||
| Parameter | Type | Description |
|
| Parameter | Type | Description |
|
||||||
| --------- | ---- | ----------- |
|
| --------- | ---- | ----------- |
|
||||||
| `customer` | object | The created customer |
|
| `customer` | object | The created customer |
|
||||||
|
| ↳ `id` | string | Unique customer identifier \(GID\) |
|
||||||
|
| ↳ `email` | string | Customer email address |
|
||||||
|
| ↳ `firstName` | string | Customer first name |
|
||||||
|
| ↳ `lastName` | string | Customer last name |
|
||||||
|
| ↳ `phone` | string | Customer phone number |
|
||||||
|
| ↳ `createdAt` | string | Account creation timestamp \(ISO 8601\) |
|
||||||
|
| ↳ `updatedAt` | string | Last modification timestamp \(ISO 8601\) |
|
||||||
|
| ↳ `note` | string | Internal notes about the customer |
|
||||||
|
| ↳ `tags` | array | Customer tags for categorization |
|
||||||
|
| ↳ `amountSpent` | object | Total amount spent by customer |
|
||||||
|
| ↳ `addresses` | array | Customer addresses |
|
||||||
|
| ↳ `defaultAddress` | object | Customer default address |
|
||||||
|
|
||||||
### `shopify_get_customer`
|
### `shopify_get_customer`
|
||||||
|
|
||||||
@@ -248,6 +378,18 @@ Get a single customer by ID from your Shopify store
|
|||||||
| Parameter | Type | Description |
|
| Parameter | Type | Description |
|
||||||
| --------- | ---- | ----------- |
|
| --------- | ---- | ----------- |
|
||||||
| `customer` | object | The customer details |
|
| `customer` | object | The customer details |
|
||||||
|
| ↳ `id` | string | Unique customer identifier \(GID\) |
|
||||||
|
| ↳ `email` | string | Customer email address |
|
||||||
|
| ↳ `firstName` | string | Customer first name |
|
||||||
|
| ↳ `lastName` | string | Customer last name |
|
||||||
|
| ↳ `phone` | string | Customer phone number |
|
||||||
|
| ↳ `createdAt` | string | Account creation timestamp \(ISO 8601\) |
|
||||||
|
| ↳ `updatedAt` | string | Last modification timestamp \(ISO 8601\) |
|
||||||
|
| ↳ `note` | string | Internal notes about the customer |
|
||||||
|
| ↳ `tags` | array | Customer tags for categorization |
|
||||||
|
| ↳ `amountSpent` | object | Total amount spent by customer |
|
||||||
|
| ↳ `addresses` | array | Customer addresses |
|
||||||
|
| ↳ `defaultAddress` | object | Customer default address |
|
||||||
|
|
||||||
### `shopify_list_customers`
|
### `shopify_list_customers`
|
||||||
|
|
||||||
@@ -266,7 +408,21 @@ List customers from your Shopify store with optional filtering
|
|||||||
| Parameter | Type | Description |
|
| Parameter | Type | Description |
|
||||||
| --------- | ---- | ----------- |
|
| --------- | ---- | ----------- |
|
||||||
| `customers` | array | List of customers |
|
| `customers` | array | List of customers |
|
||||||
|
| ↳ `id` | string | Unique customer identifier \(GID\) |
|
||||||
|
| ↳ `email` | string | Customer email address |
|
||||||
|
| ↳ `firstName` | string | Customer first name |
|
||||||
|
| ↳ `lastName` | string | Customer last name |
|
||||||
|
| ↳ `phone` | string | Customer phone number |
|
||||||
|
| ↳ `createdAt` | string | Account creation timestamp \(ISO 8601\) |
|
||||||
|
| ↳ `updatedAt` | string | Last modification timestamp \(ISO 8601\) |
|
||||||
|
| ↳ `note` | string | Internal notes about the customer |
|
||||||
|
| ↳ `tags` | array | Customer tags for categorization |
|
||||||
|
| ↳ `amountSpent` | object | Total amount spent by customer |
|
||||||
|
| ↳ `addresses` | array | Customer addresses |
|
||||||
|
| ↳ `defaultAddress` | object | Customer default address |
|
||||||
| `pageInfo` | object | Pagination information |
|
| `pageInfo` | object | Pagination information |
|
||||||
|
| ↳ `hasNextPage` | boolean | Whether there are more results after this page |
|
||||||
|
| ↳ `hasPreviousPage` | boolean | Whether there are results before this page |
|
||||||
|
|
||||||
### `shopify_update_customer`
|
### `shopify_update_customer`
|
||||||
|
|
||||||
@@ -290,6 +446,18 @@ Update an existing customer in your Shopify store
|
|||||||
| Parameter | Type | Description |
|
| Parameter | Type | Description |
|
||||||
| --------- | ---- | ----------- |
|
| --------- | ---- | ----------- |
|
||||||
| `customer` | object | The updated customer |
|
| `customer` | object | The updated customer |
|
||||||
|
| ↳ `id` | string | Unique customer identifier \(GID\) |
|
||||||
|
| ↳ `email` | string | Customer email address |
|
||||||
|
| ↳ `firstName` | string | Customer first name |
|
||||||
|
| ↳ `lastName` | string | Customer last name |
|
||||||
|
| ↳ `phone` | string | Customer phone number |
|
||||||
|
| ↳ `createdAt` | string | Account creation timestamp \(ISO 8601\) |
|
||||||
|
| ↳ `updatedAt` | string | Last modification timestamp \(ISO 8601\) |
|
||||||
|
| ↳ `note` | string | Internal notes about the customer |
|
||||||
|
| ↳ `tags` | array | Customer tags for categorization |
|
||||||
|
| ↳ `amountSpent` | object | Total amount spent by customer |
|
||||||
|
| ↳ `addresses` | array | Customer addresses |
|
||||||
|
| ↳ `defaultAddress` | object | Customer default address |
|
||||||
|
|
||||||
### `shopify_delete_customer`
|
### `shopify_delete_customer`
|
||||||
|
|
||||||
@@ -325,7 +493,26 @@ List inventory items from your Shopify store. Use this to find inventory item ID
|
|||||||
| Parameter | Type | Description |
|
| Parameter | Type | Description |
|
||||||
| --------- | ---- | ----------- |
|
| --------- | ---- | ----------- |
|
||||||
| `inventoryItems` | array | List of inventory items with their IDs, SKUs, and stock levels |
|
| `inventoryItems` | array | List of inventory items with their IDs, SKUs, and stock levels |
|
||||||
|
| ↳ `id` | string | Unique inventory item identifier \(GID\) |
|
||||||
|
| ↳ `sku` | string | Stock keeping unit |
|
||||||
|
| ↳ `tracked` | boolean | Whether inventory is tracked |
|
||||||
|
| ↳ `createdAt` | string | Creation timestamp \(ISO 8601\) |
|
||||||
|
| ↳ `updatedAt` | string | Last modification timestamp \(ISO 8601\) |
|
||||||
|
| ↳ `variant` | object | Associated product variant |
|
||||||
|
| ↳ `id` | string | Variant identifier \(GID\) |
|
||||||
|
| ↳ `title` | string | Variant title |
|
||||||
|
| ↳ `product` | object | Associated product |
|
||||||
|
| ↳ `id` | string | Product identifier \(GID\) |
|
||||||
|
| ↳ `title` | string | Product title |
|
||||||
|
| ↳ `inventoryLevels` | array | Inventory levels at different locations |
|
||||||
|
| ↳ `id` | string | Inventory level identifier \(GID\) |
|
||||||
|
| ↳ `available` | number | Available quantity |
|
||||||
|
| ↳ `location` | object | Location for this inventory level |
|
||||||
|
| ↳ `id` | string | Location identifier \(GID\) |
|
||||||
|
| ↳ `name` | string | Location name |
|
||||||
| `pageInfo` | object | Pagination information |
|
| `pageInfo` | object | Pagination information |
|
||||||
|
| ↳ `hasNextPage` | boolean | Whether there are more results after this page |
|
||||||
|
| ↳ `hasPreviousPage` | boolean | Whether there are results before this page |
|
||||||
|
|
||||||
### `shopify_get_inventory_level`
|
### `shopify_get_inventory_level`
|
||||||
|
|
||||||
@@ -344,6 +531,19 @@ Get inventory level for a product variant at a specific location
|
|||||||
| Parameter | Type | Description |
|
| Parameter | Type | Description |
|
||||||
| --------- | ---- | ----------- |
|
| --------- | ---- | ----------- |
|
||||||
| `inventoryLevel` | object | The inventory level details |
|
| `inventoryLevel` | object | The inventory level details |
|
||||||
|
| ↳ `id` | string | Inventory item identifier \(GID\) |
|
||||||
|
| ↳ `sku` | string | Stock keeping unit |
|
||||||
|
| ↳ `tracked` | boolean | Whether inventory is tracked |
|
||||||
|
| ↳ `levels` | array | Inventory levels at different locations |
|
||||||
|
| ↳ `id` | string | Inventory level identifier \(GID\) |
|
||||||
|
| ↳ `available` | number | Available quantity |
|
||||||
|
| ↳ `onHand` | number | On-hand quantity |
|
||||||
|
| ↳ `committed` | number | Committed quantity |
|
||||||
|
| ↳ `incoming` | number | Incoming quantity |
|
||||||
|
| ↳ `reserved` | number | Reserved quantity |
|
||||||
|
| ↳ `location` | object | Location for this inventory level |
|
||||||
|
| ↳ `id` | string | Location identifier \(GID\) |
|
||||||
|
| ↳ `name` | string | Location name |
|
||||||
|
|
||||||
### `shopify_adjust_inventory`
|
### `shopify_adjust_inventory`
|
||||||
|
|
||||||
@@ -363,6 +563,19 @@ Adjust inventory quantity for a product variant at a specific location
|
|||||||
| Parameter | Type | Description |
|
| Parameter | Type | Description |
|
||||||
| --------- | ---- | ----------- |
|
| --------- | ---- | ----------- |
|
||||||
| `inventoryLevel` | object | The inventory adjustment result |
|
| `inventoryLevel` | object | The inventory adjustment result |
|
||||||
|
| ↳ `adjustmentGroup` | object | Inventory adjustment group details |
|
||||||
|
| ↳ `createdAt` | string | Adjustment timestamp \(ISO 8601\) |
|
||||||
|
| ↳ `reason` | string | Adjustment reason |
|
||||||
|
| ↳ `changes` | array | Inventory changes applied |
|
||||||
|
| ↳ `name` | string | Quantity name \(e.g., available\) |
|
||||||
|
| ↳ `delta` | number | Quantity change amount |
|
||||||
|
| ↳ `quantityAfterChange` | number | Quantity after adjustment |
|
||||||
|
| ↳ `item` | object | Inventory item |
|
||||||
|
| ↳ `id` | string | Inventory item identifier \(GID\) |
|
||||||
|
| ↳ `sku` | string | Stock keeping unit |
|
||||||
|
| ↳ `location` | object | Location of the adjustment |
|
||||||
|
| ↳ `id` | string | Location identifier \(GID\) |
|
||||||
|
| ↳ `name` | string | Location name |
|
||||||
|
|
||||||
### `shopify_list_locations`
|
### `shopify_list_locations`
|
||||||
|
|
||||||
@@ -381,7 +594,14 @@ List inventory locations from your Shopify store. Use this to find location IDs
|
|||||||
| Parameter | Type | Description |
|
| Parameter | Type | Description |
|
||||||
| --------- | ---- | ----------- |
|
| --------- | ---- | ----------- |
|
||||||
| `locations` | array | List of locations with their IDs, names, and addresses |
|
| `locations` | array | List of locations with their IDs, names, and addresses |
|
||||||
|
| ↳ `id` | string | Unique location identifier \(GID\) |
|
||||||
|
| ↳ `name` | string | Location name |
|
||||||
|
| ↳ `isActive` | boolean | Whether the location is active |
|
||||||
|
| ↳ `fulfillsOnlineOrders` | boolean | Whether the location fulfills online orders |
|
||||||
|
| ↳ `address` | object | Location address |
|
||||||
| `pageInfo` | object | Pagination information |
|
| `pageInfo` | object | Pagination information |
|
||||||
|
| ↳ `hasNextPage` | boolean | Whether there are more results after this page |
|
||||||
|
| ↳ `hasPreviousPage` | boolean | Whether there are results before this page |
|
||||||
|
|
||||||
### `shopify_create_fulfillment`
|
### `shopify_create_fulfillment`
|
||||||
|
|
||||||
@@ -403,6 +623,16 @@ Create a fulfillment to mark order items as shipped. Requires a fulfillment orde
|
|||||||
| Parameter | Type | Description |
|
| Parameter | Type | Description |
|
||||||
| --------- | ---- | ----------- |
|
| --------- | ---- | ----------- |
|
||||||
| `fulfillment` | object | The created fulfillment with tracking info and fulfilled items |
|
| `fulfillment` | object | The created fulfillment with tracking info and fulfilled items |
|
||||||
|
| ↳ `id` | string | Unique fulfillment identifier \(GID\) |
|
||||||
|
| ↳ `status` | string | Fulfillment status \(pending, open, success, cancelled, error, failure\) |
|
||||||
|
| ↳ `createdAt` | string | Creation timestamp \(ISO 8601\) |
|
||||||
|
| ↳ `updatedAt` | string | Last modification timestamp \(ISO 8601\) |
|
||||||
|
| ↳ `trackingInfo` | array | Tracking information for shipments |
|
||||||
|
| ↳ `fulfillmentLineItems` | array | Fulfilled line items |
|
||||||
|
| ↳ `id` | string | Fulfillment line item identifier \(GID\) |
|
||||||
|
| ↳ `quantity` | number | Quantity fulfilled |
|
||||||
|
| ↳ `lineItem` | object | Associated order line item |
|
||||||
|
| ↳ `title` | string | Product title |
|
||||||
|
|
||||||
### `shopify_list_collections`
|
### `shopify_list_collections`
|
||||||
|
|
||||||
@@ -421,7 +651,18 @@ List product collections from your Shopify store. Filter by title, type (custom/
|
|||||||
| Parameter | Type | Description |
|
| Parameter | Type | Description |
|
||||||
| --------- | ---- | ----------- |
|
| --------- | ---- | ----------- |
|
||||||
| `collections` | array | List of collections with their IDs, titles, and product counts |
|
| `collections` | array | List of collections with their IDs, titles, and product counts |
|
||||||
|
| ↳ `id` | string | Unique collection identifier \(GID\) |
|
||||||
|
| ↳ `title` | string | Collection title |
|
||||||
|
| ↳ `handle` | string | URL-friendly collection identifier |
|
||||||
|
| ↳ `description` | string | Plain text description |
|
||||||
|
| ↳ `descriptionHtml` | string | HTML-formatted description |
|
||||||
|
| ↳ `productsCount` | number | Number of products in the collection |
|
||||||
|
| ↳ `sortOrder` | string | Product sort order in the collection |
|
||||||
|
| ↳ `updatedAt` | string | Last modification timestamp \(ISO 8601\) |
|
||||||
|
| ↳ `image` | object | Collection image |
|
||||||
| `pageInfo` | object | Pagination information |
|
| `pageInfo` | object | Pagination information |
|
||||||
|
| ↳ `hasNextPage` | boolean | Whether there are more results after this page |
|
||||||
|
| ↳ `hasPreviousPage` | boolean | Whether there are results before this page |
|
||||||
|
|
||||||
### `shopify_get_collection`
|
### `shopify_get_collection`
|
||||||
|
|
||||||
@@ -440,5 +681,15 @@ Get a specific collection by ID, including its products. Use this to retrieve pr
|
|||||||
| Parameter | Type | Description |
|
| Parameter | Type | Description |
|
||||||
| --------- | ---- | ----------- |
|
| --------- | ---- | ----------- |
|
||||||
| `collection` | object | The collection details including its products |
|
| `collection` | object | The collection details including its products |
|
||||||
|
| ↳ `id` | string | Unique collection identifier \(GID\) |
|
||||||
|
| ↳ `title` | string | Collection title |
|
||||||
|
| ↳ `handle` | string | URL-friendly collection identifier |
|
||||||
|
| ↳ `description` | string | Plain text description |
|
||||||
|
| ↳ `descriptionHtml` | string | HTML-formatted description |
|
||||||
|
| ↳ `productsCount` | number | Number of products in the collection |
|
||||||
|
| ↳ `sortOrder` | string | Product sort order in the collection |
|
||||||
|
| ↳ `updatedAt` | string | Last modification timestamp \(ISO 8601\) |
|
||||||
|
| ↳ `image` | object | Collection image |
|
||||||
|
| ↳ `products` | array | Products in the collection |
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
183
apps/docs/content/docs/en/tools/similarweb.mdx
Normal file
183
apps/docs/content/docs/en/tools/similarweb.mdx
Normal file
@@ -0,0 +1,183 @@
|
|||||||
|
---
|
||||||
|
title: Similarweb
|
||||||
|
description: Website traffic and analytics data
|
||||||
|
---
|
||||||
|
|
||||||
|
import { BlockInfoCard } from "@/components/ui/block-info-card"
|
||||||
|
|
||||||
|
<BlockInfoCard
|
||||||
|
type="similarweb"
|
||||||
|
color="#000922"
|
||||||
|
/>
|
||||||
|
|
||||||
|
{/* MANUAL-CONTENT-START:intro */}
|
||||||
|
[Similarweb](https://www.similarweb.com/) is a leading platform for web analytics that provides in-depth traffic and engagement data for millions of websites. Similarweb gives you insights into website visits, traffic sources, audience behavior, and competitive benchmarks.
|
||||||
|
|
||||||
|
With Similarweb in Sim, your agents can:
|
||||||
|
|
||||||
|
- **Analyze website traffic**: Retrieve key metrics such as monthly visits, average duration, bounce rates, and top countries.
|
||||||
|
- **Understand audience engagement**: Gain insights into how users interact with websites, including pages per visit and engagement duration.
|
||||||
|
- **Track rankings and performance**: Access global, country, and category ranks to benchmark sites against competitors.
|
||||||
|
- **Discover traffic sources**: Break down traffic by channels like direct, search, social, referrals, and more.
|
||||||
|
|
||||||
|
Use Sim's Similarweb integration to automate the monitoring of competitors, track your site’s performance, or surface actionable market research—all integrated directly into your workflows and automations. Empower your agents to access and utilize reliable web analytics data easily and programmatically.
|
||||||
|
{/* MANUAL-CONTENT-END */}
|
||||||
|
|
||||||
|
|
||||||
|
## Usage Instructions
|
||||||
|
|
||||||
|
Access comprehensive website analytics including traffic estimates, engagement metrics, rankings, and traffic sources using the Similarweb API.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## Tools
|
||||||
|
|
||||||
|
### `similarweb_website_overview`
|
||||||
|
|
||||||
|
Get comprehensive website analytics including traffic, rankings, engagement, and traffic sources
|
||||||
|
|
||||||
|
#### Input
|
||||||
|
|
||||||
|
| Parameter | Type | Required | Description |
|
||||||
|
| --------- | ---- | -------- | ----------- |
|
||||||
|
| `apiKey` | string | Yes | SimilarWeb API key |
|
||||||
|
| `domain` | string | Yes | Website domain to analyze \(without www or protocol\) |
|
||||||
|
|
||||||
|
#### Output
|
||||||
|
|
||||||
|
| Parameter | Type | Description |
|
||||||
|
| --------- | ---- | ----------- |
|
||||||
|
| `siteName` | string | Website name |
|
||||||
|
| `description` | string | Website description |
|
||||||
|
| `globalRank` | number | Global traffic rank |
|
||||||
|
| `countryRank` | number | Country traffic rank |
|
||||||
|
| `categoryRank` | number | Category traffic rank |
|
||||||
|
| `category` | string | Website category |
|
||||||
|
| `monthlyVisits` | number | Estimated monthly visits |
|
||||||
|
| `engagementVisitDuration` | number | Average visit duration in seconds |
|
||||||
|
| `engagementPagesPerVisit` | number | Average pages per visit |
|
||||||
|
| `engagementBounceRate` | number | Bounce rate \(0-1\) |
|
||||||
|
| `topCountries` | array | Top countries by traffic share |
|
||||||
|
| ↳ `country` | string | Country code |
|
||||||
|
| ↳ `share` | number | Traffic share \(0-1\) |
|
||||||
|
| `trafficSources` | json | Traffic source breakdown |
|
||||||
|
| ↳ `direct` | number | Direct traffic share |
|
||||||
|
| ↳ `referrals` | number | Referral traffic share |
|
||||||
|
| ↳ `search` | number | Search traffic share |
|
||||||
|
| ↳ `social` | number | Social traffic share |
|
||||||
|
| ↳ `mail` | number | Email traffic share |
|
||||||
|
| ↳ `paidReferrals` | number | Paid referral traffic share |
|
||||||
|
|
||||||
|
### `similarweb_traffic_visits`
|
||||||
|
|
||||||
|
Get total website visits over time (desktop and mobile combined)
|
||||||
|
|
||||||
|
#### Input
|
||||||
|
|
||||||
|
| Parameter | Type | Required | Description |
|
||||||
|
| --------- | ---- | -------- | ----------- |
|
||||||
|
| `apiKey` | string | Yes | SimilarWeb API key |
|
||||||
|
| `domain` | string | Yes | Website domain to analyze \(without www or protocol\) |
|
||||||
|
| `country` | string | Yes | 2-letter ISO country code or "world" for worldwide data |
|
||||||
|
| `granularity` | string | Yes | Data granularity: daily, weekly, or monthly |
|
||||||
|
| `startDate` | string | No | Start date in YYYY-MM format |
|
||||||
|
| `endDate` | string | No | End date in YYYY-MM format |
|
||||||
|
| `mainDomainOnly` | boolean | No | Exclude subdomains from results |
|
||||||
|
|
||||||
|
#### Output
|
||||||
|
|
||||||
|
| Parameter | Type | Description |
|
||||||
|
| --------- | ---- | ----------- |
|
||||||
|
| `domain` | string | Analyzed domain |
|
||||||
|
| `country` | string | Country filter applied |
|
||||||
|
| `granularity` | string | Data granularity |
|
||||||
|
| `lastUpdated` | string | Data last updated timestamp |
|
||||||
|
| `visits` | array | Visit data over time |
|
||||||
|
| ↳ `date` | string | Date \(YYYY-MM-DD\) |
|
||||||
|
| ↳ `visits` | number | Number of visits |
|
||||||
|
|
||||||
|
### `similarweb_bounce_rate`
|
||||||
|
|
||||||
|
Get website bounce rate over time (desktop and mobile combined)
|
||||||
|
|
||||||
|
#### Input
|
||||||
|
|
||||||
|
| Parameter | Type | Required | Description |
|
||||||
|
| --------- | ---- | -------- | ----------- |
|
||||||
|
| `apiKey` | string | Yes | SimilarWeb API key |
|
||||||
|
| `domain` | string | Yes | Website domain to analyze \(without www or protocol\) |
|
||||||
|
| `country` | string | Yes | 2-letter ISO country code or "world" for worldwide data |
|
||||||
|
| `granularity` | string | Yes | Data granularity: daily, weekly, or monthly |
|
||||||
|
| `startDate` | string | No | Start date in YYYY-MM format |
|
||||||
|
| `endDate` | string | No | End date in YYYY-MM format |
|
||||||
|
| `mainDomainOnly` | boolean | No | Exclude subdomains from results |
|
||||||
|
|
||||||
|
#### Output
|
||||||
|
|
||||||
|
| Parameter | Type | Description |
|
||||||
|
| --------- | ---- | ----------- |
|
||||||
|
| `domain` | string | Analyzed domain |
|
||||||
|
| `country` | string | Country filter applied |
|
||||||
|
| `granularity` | string | Data granularity |
|
||||||
|
| `lastUpdated` | string | Data last updated timestamp |
|
||||||
|
| `bounceRate` | array | Bounce rate data over time |
|
||||||
|
| ↳ `date` | string | Date \(YYYY-MM-DD\) |
|
||||||
|
| ↳ `bounceRate` | number | Bounce rate \(0-1\) |
|
||||||
|
|
||||||
|
### `similarweb_pages_per_visit`
|
||||||
|
|
||||||
|
Get average pages per visit over time (desktop and mobile combined)
|
||||||
|
|
||||||
|
#### Input
|
||||||
|
|
||||||
|
| Parameter | Type | Required | Description |
|
||||||
|
| --------- | ---- | -------- | ----------- |
|
||||||
|
| `apiKey` | string | Yes | SimilarWeb API key |
|
||||||
|
| `domain` | string | Yes | Website domain to analyze \(without www or protocol\) |
|
||||||
|
| `country` | string | Yes | 2-letter ISO country code or "world" for worldwide data |
|
||||||
|
| `granularity` | string | Yes | Data granularity: daily, weekly, or monthly |
|
||||||
|
| `startDate` | string | No | Start date in YYYY-MM format |
|
||||||
|
| `endDate` | string | No | End date in YYYY-MM format |
|
||||||
|
| `mainDomainOnly` | boolean | No | Exclude subdomains from results |
|
||||||
|
|
||||||
|
#### Output
|
||||||
|
|
||||||
|
| Parameter | Type | Description |
|
||||||
|
| --------- | ---- | ----------- |
|
||||||
|
| `domain` | string | Analyzed domain |
|
||||||
|
| `country` | string | Country filter applied |
|
||||||
|
| `granularity` | string | Data granularity |
|
||||||
|
| `lastUpdated` | string | Data last updated timestamp |
|
||||||
|
| `pagesPerVisit` | array | Pages per visit data over time |
|
||||||
|
| ↳ `date` | string | Date \(YYYY-MM-DD\) |
|
||||||
|
| ↳ `pagesPerVisit` | number | Average pages per visit |
|
||||||
|
|
||||||
|
### `similarweb_visit_duration`
|
||||||
|
|
||||||
|
Get average desktop visit duration over time (in seconds)
|
||||||
|
|
||||||
|
#### Input
|
||||||
|
|
||||||
|
| Parameter | Type | Required | Description |
|
||||||
|
| --------- | ---- | -------- | ----------- |
|
||||||
|
| `apiKey` | string | Yes | SimilarWeb API key |
|
||||||
|
| `domain` | string | Yes | Website domain to analyze \(without www or protocol\) |
|
||||||
|
| `country` | string | Yes | 2-letter ISO country code or "world" for worldwide data |
|
||||||
|
| `granularity` | string | Yes | Data granularity: daily, weekly, or monthly |
|
||||||
|
| `startDate` | string | No | Start date in YYYY-MM format |
|
||||||
|
| `endDate` | string | No | End date in YYYY-MM format |
|
||||||
|
| `mainDomainOnly` | boolean | No | Exclude subdomains from results |
|
||||||
|
|
||||||
|
#### Output
|
||||||
|
|
||||||
|
| Parameter | Type | Description |
|
||||||
|
| --------- | ---- | ----------- |
|
||||||
|
| `domain` | string | Analyzed domain |
|
||||||
|
| `country` | string | Country filter applied |
|
||||||
|
| `granularity` | string | Data granularity |
|
||||||
|
| `lastUpdated` | string | Data last updated timestamp |
|
||||||
|
| `averageVisitDuration` | array | Desktop visit duration data over time |
|
||||||
|
| ↳ `date` | string | Date \(YYYY-MM-DD\) |
|
||||||
|
| ↳ `durationSeconds` | number | Average visit duration in seconds |
|
||||||
|
|
||||||
|
|
||||||
@@ -97,6 +97,60 @@ Send messages to Slack channels or direct messages. Supports Slack mrkdwn format
|
|||||||
| Parameter | Type | Description |
|
| Parameter | Type | Description |
|
||||||
| --------- | ---- | ----------- |
|
| --------- | ---- | ----------- |
|
||||||
| `message` | object | Complete message object with all properties returned by Slack |
|
| `message` | object | Complete message object with all properties returned by Slack |
|
||||||
|
| ↳ `type` | string | Message type \(usually "message"\) |
|
||||||
|
| ↳ `ts` | string | Message timestamp \(unique identifier\) |
|
||||||
|
| ↳ `text` | string | Message text content |
|
||||||
|
| ↳ `user` | string | User ID who sent the message |
|
||||||
|
| ↳ `bot_id` | string | Bot ID if sent by a bot |
|
||||||
|
| ↳ `username` | string | Display username |
|
||||||
|
| ↳ `channel` | string | Channel ID |
|
||||||
|
| ↳ `team` | string | Team/workspace ID |
|
||||||
|
| ↳ `thread_ts` | string | Parent message timestamp \(for threaded replies\) |
|
||||||
|
| ↳ `parent_user_id` | string | User ID of thread parent message author |
|
||||||
|
| ↳ `reply_count` | number | Total number of replies in thread |
|
||||||
|
| ↳ `reply_users_count` | number | Number of unique users who replied |
|
||||||
|
| ↳ `latest_reply` | string | Timestamp of most recent reply |
|
||||||
|
| ↳ `subscribed` | boolean | Whether user is subscribed to thread |
|
||||||
|
| ↳ `last_read` | string | Timestamp of last read message |
|
||||||
|
| ↳ `unread_count` | number | Number of unread messages in thread |
|
||||||
|
| ↳ `subtype` | string | Message subtype \(bot_message, file_share, etc.\) |
|
||||||
|
| ↳ `is_starred` | boolean | Whether message is starred by user |
|
||||||
|
| ↳ `pinned_to` | array | Channel IDs where message is pinned |
|
||||||
|
| ↳ `permalink` | string | Permanent URL to the message |
|
||||||
|
| ↳ `reactions` | array | Reactions on this message |
|
||||||
|
| ↳ `name` | string | Emoji name \(without colons\) |
|
||||||
|
| ↳ `count` | number | Number of times this reaction was added |
|
||||||
|
| ↳ `users` | array | Array of user IDs who reacted |
|
||||||
|
| ↳ `files` | array | Files attached to the message |
|
||||||
|
| ↳ `id` | string | Unique file identifier |
|
||||||
|
| ↳ `name` | string | File name |
|
||||||
|
| ↳ `mimetype` | string | MIME type of the file |
|
||||||
|
| ↳ `size` | number | File size in bytes |
|
||||||
|
| ↳ `url_private` | string | Private download URL \(requires auth\) |
|
||||||
|
| ↳ `permalink` | string | Permanent link to the file |
|
||||||
|
| ↳ `mode` | string | File mode \(hosted, external, etc.\) |
|
||||||
|
| ↳ `attachments` | array | Legacy attachments on the message |
|
||||||
|
| ↳ `id` | number | Attachment ID |
|
||||||
|
| ↳ `fallback` | string | Plain text summary |
|
||||||
|
| ↳ `text` | string | Main attachment text |
|
||||||
|
| ↳ `pretext` | string | Text shown before attachment |
|
||||||
|
| ↳ `color` | string | Color bar hex code or preset |
|
||||||
|
| ↳ `author_name` | string | Author display name |
|
||||||
|
| ↳ `author_link` | string | Author link URL |
|
||||||
|
| ↳ `author_icon` | string | Author icon URL |
|
||||||
|
| ↳ `title` | string | Attachment title |
|
||||||
|
| ↳ `title_link` | string | Title link URL |
|
||||||
|
| ↳ `image_url` | string | Image URL |
|
||||||
|
| ↳ `thumb_url` | string | Thumbnail URL |
|
||||||
|
| ↳ `footer` | string | Footer text |
|
||||||
|
| ↳ `footer_icon` | string | Footer icon URL |
|
||||||
|
| ↳ `ts` | string | Timestamp shown in footer |
|
||||||
|
| ↳ `blocks` | array | Block Kit blocks in the message |
|
||||||
|
| ↳ `type` | string | Block type \(section, divider, image, actions, etc.\) |
|
||||||
|
| ↳ `block_id` | string | Unique block identifier |
|
||||||
|
| ↳ `edited` | object | Edit information if message was edited |
|
||||||
|
| ↳ `user` | string | User ID who edited the message |
|
||||||
|
| ↳ `ts` | string | Timestamp of the edit |
|
||||||
| `ts` | string | Message timestamp |
|
| `ts` | string | Message timestamp |
|
||||||
| `channel` | string | Channel ID where message was sent |
|
| `channel` | string | Channel ID where message was sent |
|
||||||
| `fileCount` | number | Number of files uploaded \(when files are attached\) |
|
| `fileCount` | number | Number of files uploaded \(when files are attached\) |
|
||||||
@@ -120,9 +174,9 @@ Create and share Slack canvases in channels. Canvases are collaborative document
|
|||||||
|
|
||||||
| Parameter | Type | Description |
|
| Parameter | Type | Description |
|
||||||
| --------- | ---- | ----------- |
|
| --------- | ---- | ----------- |
|
||||||
| `canvas_id` | string | ID of the created canvas |
|
| `canvas_id` | string | Unique canvas identifier |
|
||||||
| `channel` | string | Channel where canvas was created |
|
| `channel` | string | Channel where canvas was created |
|
||||||
| `title` | string | Title of the canvas |
|
| `title` | string | Canvas title |
|
||||||
|
|
||||||
### `slack_message_reader`
|
### `slack_message_reader`
|
||||||
|
|
||||||
@@ -146,43 +200,60 @@ Read the latest messages from Slack channels. Retrieve conversation history with
|
|||||||
| Parameter | Type | Description |
|
| Parameter | Type | Description |
|
||||||
| --------- | ---- | ----------- |
|
| --------- | ---- | ----------- |
|
||||||
| `messages` | array | Array of message objects from the channel |
|
| `messages` | array | Array of message objects from the channel |
|
||||||
| ↳ `type` | string | Message type |
|
| ↳ `type` | string | Message type \(usually "message"\) |
|
||||||
| ↳ `ts` | string | Message timestamp |
|
| ↳ `ts` | string | Message timestamp \(unique identifier\) |
|
||||||
| ↳ `text` | string | Message text content |
|
| ↳ `text` | string | Message text content |
|
||||||
| ↳ `user` | string | User ID who sent the message |
|
| ↳ `user` | string | User ID who sent the message |
|
||||||
| ↳ `bot_id` | string | Bot ID if sent by a bot |
|
| ↳ `bot_id` | string | Bot ID if sent by a bot |
|
||||||
| ↳ `username` | string | Display username |
|
| ↳ `username` | string | Display username |
|
||||||
| ↳ `channel` | string | Channel ID |
|
| ↳ `channel` | string | Channel ID |
|
||||||
| ↳ `team` | string | Team ID |
|
| ↳ `team` | string | Team/workspace ID |
|
||||||
| ↳ `thread_ts` | string | Thread parent message timestamp |
|
| ↳ `thread_ts` | string | Parent message timestamp \(for threaded replies\) |
|
||||||
| ↳ `parent_user_id` | string | User ID of thread parent |
|
| ↳ `parent_user_id` | string | User ID of thread parent message author |
|
||||||
| ↳ `reply_count` | number | Number of thread replies |
|
| ↳ `reply_count` | number | Total number of replies in thread |
|
||||||
| ↳ `reply_users_count` | number | Number of users who replied |
|
| ↳ `reply_users_count` | number | Number of unique users who replied |
|
||||||
| ↳ `latest_reply` | string | Timestamp of latest reply |
|
| ↳ `latest_reply` | string | Timestamp of most recent reply |
|
||||||
| ↳ `subscribed` | boolean | Whether user is subscribed to thread |
|
| ↳ `subscribed` | boolean | Whether user is subscribed to thread |
|
||||||
| ↳ `last_read` | string | Last read timestamp |
|
| ↳ `last_read` | string | Timestamp of last read message |
|
||||||
| ↳ `unread_count` | number | Number of unread messages |
|
| ↳ `unread_count` | number | Number of unread messages in thread |
|
||||||
| ↳ `subtype` | string | Message subtype |
|
| ↳ `subtype` | string | Message subtype \(bot_message, file_share, etc.\) |
|
||||||
| ↳ `reactions` | array | Array of reactions on this message |
|
| ↳ `is_starred` | boolean | Whether message is starred by user |
|
||||||
| ↳ `name` | string | Emoji name |
|
| ↳ `pinned_to` | array | Channel IDs where message is pinned |
|
||||||
| ↳ `count` | number | Number of reactions |
|
| ↳ `permalink` | string | Permanent URL to the message |
|
||||||
|
| ↳ `reactions` | array | Reactions on this message |
|
||||||
|
| ↳ `name` | string | Emoji name \(without colons\) |
|
||||||
|
| ↳ `count` | number | Number of times this reaction was added |
|
||||||
| ↳ `users` | array | Array of user IDs who reacted |
|
| ↳ `users` | array | Array of user IDs who reacted |
|
||||||
| ↳ `is_starred` | boolean | Whether message is starred |
|
| ↳ `files` | array | Files attached to the message |
|
||||||
| ↳ `pinned_to` | array | Array of channel IDs where message is pinned |
|
| ↳ `id` | string | Unique file identifier |
|
||||||
| ↳ `files` | array | Array of files attached to message |
|
|
||||||
| ↳ `id` | string | File ID |
|
|
||||||
| ↳ `name` | string | File name |
|
| ↳ `name` | string | File name |
|
||||||
| ↳ `mimetype` | string | MIME type |
|
| ↳ `mimetype` | string | MIME type of the file |
|
||||||
| ↳ `size` | number | File size in bytes |
|
| ↳ `size` | number | File size in bytes |
|
||||||
| ↳ `url_private` | string | Private download URL |
|
| ↳ `url_private` | string | Private download URL \(requires auth\) |
|
||||||
| ↳ `permalink` | string | Permanent link to file |
|
| ↳ `permalink` | string | Permanent link to the file |
|
||||||
| ↳ `mode` | string | File mode |
|
| ↳ `mode` | string | File mode \(hosted, external, etc.\) |
|
||||||
| ↳ `attachments` | array | Array of legacy attachments |
|
| ↳ `attachments` | array | Legacy attachments on the message |
|
||||||
| ↳ `blocks` | array | Array of Block Kit blocks |
|
| ↳ `id` | number | Attachment ID |
|
||||||
|
| ↳ `fallback` | string | Plain text summary |
|
||||||
|
| ↳ `text` | string | Main attachment text |
|
||||||
|
| ↳ `pretext` | string | Text shown before attachment |
|
||||||
|
| ↳ `color` | string | Color bar hex code or preset |
|
||||||
|
| ↳ `author_name` | string | Author display name |
|
||||||
|
| ↳ `author_link` | string | Author link URL |
|
||||||
|
| ↳ `author_icon` | string | Author icon URL |
|
||||||
|
| ↳ `title` | string | Attachment title |
|
||||||
|
| ↳ `title_link` | string | Title link URL |
|
||||||
|
| ↳ `image_url` | string | Image URL |
|
||||||
|
| ↳ `thumb_url` | string | Thumbnail URL |
|
||||||
|
| ↳ `footer` | string | Footer text |
|
||||||
|
| ↳ `footer_icon` | string | Footer icon URL |
|
||||||
|
| ↳ `ts` | string | Timestamp shown in footer |
|
||||||
|
| ↳ `blocks` | array | Block Kit blocks in the message |
|
||||||
|
| ↳ `type` | string | Block type \(section, divider, image, actions, etc.\) |
|
||||||
|
| ↳ `block_id` | string | Unique block identifier |
|
||||||
| ↳ `edited` | object | Edit information if message was edited |
|
| ↳ `edited` | object | Edit information if message was edited |
|
||||||
| ↳ `user` | string | User ID who edited |
|
| ↳ `user` | string | User ID who edited the message |
|
||||||
| ↳ `ts` | string | Edit timestamp |
|
| ↳ `ts` | string | Timestamp of the edit |
|
||||||
| ↳ `permalink` | string | Permanent link to message |
|
|
||||||
|
|
||||||
### `slack_get_message`
|
### `slack_get_message`
|
||||||
|
|
||||||
@@ -202,39 +273,60 @@ Retrieve a specific message by its timestamp. Useful for getting a thread parent
|
|||||||
| Parameter | Type | Description |
|
| Parameter | Type | Description |
|
||||||
| --------- | ---- | ----------- |
|
| --------- | ---- | ----------- |
|
||||||
| `message` | object | The retrieved message object |
|
| `message` | object | The retrieved message object |
|
||||||
| ↳ `type` | string | Message type |
|
| ↳ `type` | string | Message type \(usually "message"\) |
|
||||||
| ↳ `ts` | string | Message timestamp |
|
| ↳ `ts` | string | Message timestamp \(unique identifier\) |
|
||||||
| ↳ `text` | string | Message text content |
|
| ↳ `text` | string | Message text content |
|
||||||
| ↳ `user` | string | User ID who sent the message |
|
| ↳ `user` | string | User ID who sent the message |
|
||||||
| ↳ `bot_id` | string | Bot ID if sent by a bot |
|
| ↳ `bot_id` | string | Bot ID if sent by a bot |
|
||||||
| ↳ `username` | string | Display username |
|
| ↳ `username` | string | Display username |
|
||||||
| ↳ `channel` | string | Channel ID |
|
| ↳ `channel` | string | Channel ID |
|
||||||
| ↳ `team` | string | Team ID |
|
| ↳ `team` | string | Team/workspace ID |
|
||||||
| ↳ `thread_ts` | string | Thread parent timestamp |
|
| ↳ `thread_ts` | string | Parent message timestamp \(for threaded replies\) |
|
||||||
| ↳ `parent_user_id` | string | User ID of thread parent |
|
| ↳ `parent_user_id` | string | User ID of thread parent message author |
|
||||||
| ↳ `reply_count` | number | Number of thread replies |
|
| ↳ `reply_count` | number | Total number of replies in thread |
|
||||||
| ↳ `reply_users_count` | number | Number of users who replied |
|
| ↳ `reply_users_count` | number | Number of unique users who replied |
|
||||||
| ↳ `latest_reply` | string | Timestamp of latest reply |
|
| ↳ `latest_reply` | string | Timestamp of most recent reply |
|
||||||
| ↳ `subtype` | string | Message subtype |
|
| ↳ `subscribed` | boolean | Whether user is subscribed to thread |
|
||||||
| ↳ `reactions` | array | Array of reactions on this message |
|
| ↳ `last_read` | string | Timestamp of last read message |
|
||||||
| ↳ `name` | string | Emoji name |
|
| ↳ `unread_count` | number | Number of unread messages in thread |
|
||||||
| ↳ `count` | number | Number of reactions |
|
| ↳ `subtype` | string | Message subtype \(bot_message, file_share, etc.\) |
|
||||||
| ↳ `users` | array | User IDs who reacted |
|
| ↳ `is_starred` | boolean | Whether message is starred by user |
|
||||||
| ↳ `is_starred` | boolean | Whether message is starred |
|
|
||||||
| ↳ `pinned_to` | array | Channel IDs where message is pinned |
|
| ↳ `pinned_to` | array | Channel IDs where message is pinned |
|
||||||
| ↳ `files` | array | Files attached to message |
|
| ↳ `permalink` | string | Permanent URL to the message |
|
||||||
| ↳ `id` | string | File ID |
|
| ↳ `reactions` | array | Reactions on this message |
|
||||||
|
| ↳ `name` | string | Emoji name \(without colons\) |
|
||||||
|
| ↳ `count` | number | Number of times this reaction was added |
|
||||||
|
| ↳ `users` | array | Array of user IDs who reacted |
|
||||||
|
| ↳ `files` | array | Files attached to the message |
|
||||||
|
| ↳ `id` | string | Unique file identifier |
|
||||||
| ↳ `name` | string | File name |
|
| ↳ `name` | string | File name |
|
||||||
| ↳ `mimetype` | string | MIME type |
|
| ↳ `mimetype` | string | MIME type of the file |
|
||||||
| ↳ `size` | number | File size in bytes |
|
| ↳ `size` | number | File size in bytes |
|
||||||
| ↳ `url_private` | string | Private download URL |
|
| ↳ `url_private` | string | Private download URL \(requires auth\) |
|
||||||
| ↳ `permalink` | string | Permanent link to file |
|
| ↳ `permalink` | string | Permanent link to the file |
|
||||||
| ↳ `attachments` | array | Legacy attachments |
|
| ↳ `mode` | string | File mode \(hosted, external, etc.\) |
|
||||||
| ↳ `blocks` | array | Block Kit blocks |
|
| ↳ `attachments` | array | Legacy attachments on the message |
|
||||||
|
| ↳ `id` | number | Attachment ID |
|
||||||
|
| ↳ `fallback` | string | Plain text summary |
|
||||||
|
| ↳ `text` | string | Main attachment text |
|
||||||
|
| ↳ `pretext` | string | Text shown before attachment |
|
||||||
|
| ↳ `color` | string | Color bar hex code or preset |
|
||||||
|
| ↳ `author_name` | string | Author display name |
|
||||||
|
| ↳ `author_link` | string | Author link URL |
|
||||||
|
| ↳ `author_icon` | string | Author icon URL |
|
||||||
|
| ↳ `title` | string | Attachment title |
|
||||||
|
| ↳ `title_link` | string | Title link URL |
|
||||||
|
| ↳ `image_url` | string | Image URL |
|
||||||
|
| ↳ `thumb_url` | string | Thumbnail URL |
|
||||||
|
| ↳ `footer` | string | Footer text |
|
||||||
|
| ↳ `footer_icon` | string | Footer icon URL |
|
||||||
|
| ↳ `ts` | string | Timestamp shown in footer |
|
||||||
|
| ↳ `blocks` | array | Block Kit blocks in the message |
|
||||||
|
| ↳ `type` | string | Block type \(section, divider, image, actions, etc.\) |
|
||||||
|
| ↳ `block_id` | string | Unique block identifier |
|
||||||
| ↳ `edited` | object | Edit information if message was edited |
|
| ↳ `edited` | object | Edit information if message was edited |
|
||||||
| ↳ `user` | string | User ID who edited |
|
| ↳ `user` | string | User ID who edited the message |
|
||||||
| ↳ `ts` | string | Edit timestamp |
|
| ↳ `ts` | string | Timestamp of the edit |
|
||||||
| ↳ `permalink` | string | Permanent link to message |
|
|
||||||
|
|
||||||
### `slack_get_thread`
|
### `slack_get_thread`
|
||||||
|
|
||||||
@@ -255,31 +347,170 @@ Retrieve an entire thread including the parent message and all replies. Useful f
|
|||||||
| Parameter | Type | Description |
|
| Parameter | Type | Description |
|
||||||
| --------- | ---- | ----------- |
|
| --------- | ---- | ----------- |
|
||||||
| `parentMessage` | object | The thread parent message |
|
| `parentMessage` | object | The thread parent message |
|
||||||
| ↳ `type` | string | Message type |
|
| ↳ `type` | string | Message type \(usually "message"\) |
|
||||||
| ↳ `ts` | string | Message timestamp |
|
| ↳ `ts` | string | Message timestamp \(unique identifier\) |
|
||||||
| ↳ `text` | string | Message text content |
|
| ↳ `text` | string | Message text content |
|
||||||
| ↳ `user` | string | User ID who sent the message |
|
| ↳ `user` | string | User ID who sent the message |
|
||||||
| ↳ `bot_id` | string | Bot ID if sent by a bot |
|
| ↳ `bot_id` | string | Bot ID if sent by a bot |
|
||||||
| ↳ `username` | string | Display username |
|
| ↳ `username` | string | Display username |
|
||||||
| ↳ `reply_count` | number | Total number of thread replies |
|
| ↳ `channel` | string | Channel ID |
|
||||||
| ↳ `reply_users_count` | number | Number of users who replied |
|
| ↳ `team` | string | Team/workspace ID |
|
||||||
| ↳ `latest_reply` | string | Timestamp of latest reply |
|
| ↳ `thread_ts` | string | Parent message timestamp \(for threaded replies\) |
|
||||||
| ↳ `reactions` | array | Array of reactions on the parent message |
|
| ↳ `parent_user_id` | string | User ID of thread parent message author |
|
||||||
| ↳ `name` | string | Emoji name |
|
| ↳ `reply_count` | number | Total number of replies in thread |
|
||||||
| ↳ `count` | number | Number of reactions |
|
| ↳ `reply_users_count` | number | Number of unique users who replied |
|
||||||
| ↳ `users` | array | User IDs who reacted |
|
| ↳ `latest_reply` | string | Timestamp of most recent reply |
|
||||||
| ↳ `files` | array | Files attached to the parent message |
|
| ↳ `subscribed` | boolean | Whether user is subscribed to thread |
|
||||||
| ↳ `id` | string | File ID |
|
| ↳ `last_read` | string | Timestamp of last read message |
|
||||||
|
| ↳ `unread_count` | number | Number of unread messages in thread |
|
||||||
|
| ↳ `subtype` | string | Message subtype \(bot_message, file_share, etc.\) |
|
||||||
|
| ↳ `is_starred` | boolean | Whether message is starred by user |
|
||||||
|
| ↳ `pinned_to` | array | Channel IDs where message is pinned |
|
||||||
|
| ↳ `permalink` | string | Permanent URL to the message |
|
||||||
|
| ↳ `reactions` | array | Reactions on this message |
|
||||||
|
| ↳ `name` | string | Emoji name \(without colons\) |
|
||||||
|
| ↳ `count` | number | Number of times this reaction was added |
|
||||||
|
| ↳ `users` | array | Array of user IDs who reacted |
|
||||||
|
| ↳ `files` | array | Files attached to the message |
|
||||||
|
| ↳ `id` | string | Unique file identifier |
|
||||||
| ↳ `name` | string | File name |
|
| ↳ `name` | string | File name |
|
||||||
| ↳ `mimetype` | string | MIME type |
|
| ↳ `mimetype` | string | MIME type of the file |
|
||||||
| ↳ `size` | number | File size in bytes |
|
| ↳ `size` | number | File size in bytes |
|
||||||
|
| ↳ `url_private` | string | Private download URL \(requires auth\) |
|
||||||
|
| ↳ `permalink` | string | Permanent link to the file |
|
||||||
|
| ↳ `mode` | string | File mode \(hosted, external, etc.\) |
|
||||||
|
| ↳ `attachments` | array | Legacy attachments on the message |
|
||||||
|
| ↳ `id` | number | Attachment ID |
|
||||||
|
| ↳ `fallback` | string | Plain text summary |
|
||||||
|
| ↳ `text` | string | Main attachment text |
|
||||||
|
| ↳ `pretext` | string | Text shown before attachment |
|
||||||
|
| ↳ `color` | string | Color bar hex code or preset |
|
||||||
|
| ↳ `author_name` | string | Author display name |
|
||||||
|
| ↳ `author_link` | string | Author link URL |
|
||||||
|
| ↳ `author_icon` | string | Author icon URL |
|
||||||
|
| ↳ `title` | string | Attachment title |
|
||||||
|
| ↳ `title_link` | string | Title link URL |
|
||||||
|
| ↳ `image_url` | string | Image URL |
|
||||||
|
| ↳ `thumb_url` | string | Thumbnail URL |
|
||||||
|
| ↳ `footer` | string | Footer text |
|
||||||
|
| ↳ `footer_icon` | string | Footer icon URL |
|
||||||
|
| ↳ `ts` | string | Timestamp shown in footer |
|
||||||
|
| ↳ `blocks` | array | Block Kit blocks in the message |
|
||||||
|
| ↳ `type` | string | Block type \(section, divider, image, actions, etc.\) |
|
||||||
|
| ↳ `block_id` | string | Unique block identifier |
|
||||||
|
| ↳ `edited` | object | Edit information if message was edited |
|
||||||
|
| ↳ `user` | string | User ID who edited the message |
|
||||||
|
| ↳ `ts` | string | Timestamp of the edit |
|
||||||
| `replies` | array | Array of reply messages in the thread \(excluding the parent\) |
|
| `replies` | array | Array of reply messages in the thread \(excluding the parent\) |
|
||||||
| ↳ `ts` | string | Message timestamp |
|
| ↳ `type` | string | Message type \(usually "message"\) |
|
||||||
|
| ↳ `ts` | string | Message timestamp \(unique identifier\) |
|
||||||
| ↳ `text` | string | Message text content |
|
| ↳ `text` | string | Message text content |
|
||||||
| ↳ `user` | string | User ID who sent the reply |
|
| ↳ `user` | string | User ID who sent the message |
|
||||||
| ↳ `reactions` | array | Reactions on the reply |
|
| ↳ `bot_id` | string | Bot ID if sent by a bot |
|
||||||
| ↳ `files` | array | Files attached to the reply |
|
| ↳ `username` | string | Display username |
|
||||||
|
| ↳ `channel` | string | Channel ID |
|
||||||
|
| ↳ `team` | string | Team/workspace ID |
|
||||||
|
| ↳ `thread_ts` | string | Parent message timestamp \(for threaded replies\) |
|
||||||
|
| ↳ `parent_user_id` | string | User ID of thread parent message author |
|
||||||
|
| ↳ `reply_count` | number | Total number of replies in thread |
|
||||||
|
| ↳ `reply_users_count` | number | Number of unique users who replied |
|
||||||
|
| ↳ `latest_reply` | string | Timestamp of most recent reply |
|
||||||
|
| ↳ `subscribed` | boolean | Whether user is subscribed to thread |
|
||||||
|
| ↳ `last_read` | string | Timestamp of last read message |
|
||||||
|
| ↳ `unread_count` | number | Number of unread messages in thread |
|
||||||
|
| ↳ `subtype` | string | Message subtype \(bot_message, file_share, etc.\) |
|
||||||
|
| ↳ `is_starred` | boolean | Whether message is starred by user |
|
||||||
|
| ↳ `pinned_to` | array | Channel IDs where message is pinned |
|
||||||
|
| ↳ `permalink` | string | Permanent URL to the message |
|
||||||
|
| ↳ `reactions` | array | Reactions on this message |
|
||||||
|
| ↳ `name` | string | Emoji name \(without colons\) |
|
||||||
|
| ↳ `count` | number | Number of times this reaction was added |
|
||||||
|
| ↳ `users` | array | Array of user IDs who reacted |
|
||||||
|
| ↳ `files` | array | Files attached to the message |
|
||||||
|
| ↳ `id` | string | Unique file identifier |
|
||||||
|
| ↳ `name` | string | File name |
|
||||||
|
| ↳ `mimetype` | string | MIME type of the file |
|
||||||
|
| ↳ `size` | number | File size in bytes |
|
||||||
|
| ↳ `url_private` | string | Private download URL \(requires auth\) |
|
||||||
|
| ↳ `permalink` | string | Permanent link to the file |
|
||||||
|
| ↳ `mode` | string | File mode \(hosted, external, etc.\) |
|
||||||
|
| ↳ `attachments` | array | Legacy attachments on the message |
|
||||||
|
| ↳ `id` | number | Attachment ID |
|
||||||
|
| ↳ `fallback` | string | Plain text summary |
|
||||||
|
| ↳ `text` | string | Main attachment text |
|
||||||
|
| ↳ `pretext` | string | Text shown before attachment |
|
||||||
|
| ↳ `color` | string | Color bar hex code or preset |
|
||||||
|
| ↳ `author_name` | string | Author display name |
|
||||||
|
| ↳ `author_link` | string | Author link URL |
|
||||||
|
| ↳ `author_icon` | string | Author icon URL |
|
||||||
|
| ↳ `title` | string | Attachment title |
|
||||||
|
| ↳ `title_link` | string | Title link URL |
|
||||||
|
| ↳ `image_url` | string | Image URL |
|
||||||
|
| ↳ `thumb_url` | string | Thumbnail URL |
|
||||||
|
| ↳ `footer` | string | Footer text |
|
||||||
|
| ↳ `footer_icon` | string | Footer icon URL |
|
||||||
|
| ↳ `ts` | string | Timestamp shown in footer |
|
||||||
|
| ↳ `blocks` | array | Block Kit blocks in the message |
|
||||||
|
| ↳ `type` | string | Block type \(section, divider, image, actions, etc.\) |
|
||||||
|
| ↳ `block_id` | string | Unique block identifier |
|
||||||
|
| ↳ `edited` | object | Edit information if message was edited |
|
||||||
|
| ↳ `user` | string | User ID who edited the message |
|
||||||
|
| ↳ `ts` | string | Timestamp of the edit |
|
||||||
| `messages` | array | All messages in the thread \(parent + replies\) in chronological order |
|
| `messages` | array | All messages in the thread \(parent + replies\) in chronological order |
|
||||||
|
| ↳ `type` | string | Message type \(usually "message"\) |
|
||||||
|
| ↳ `ts` | string | Message timestamp \(unique identifier\) |
|
||||||
|
| ↳ `text` | string | Message text content |
|
||||||
|
| ↳ `user` | string | User ID who sent the message |
|
||||||
|
| ↳ `bot_id` | string | Bot ID if sent by a bot |
|
||||||
|
| ↳ `username` | string | Display username |
|
||||||
|
| ↳ `channel` | string | Channel ID |
|
||||||
|
| ↳ `team` | string | Team/workspace ID |
|
||||||
|
| ↳ `thread_ts` | string | Parent message timestamp \(for threaded replies\) |
|
||||||
|
| ↳ `parent_user_id` | string | User ID of thread parent message author |
|
||||||
|
| ↳ `reply_count` | number | Total number of replies in thread |
|
||||||
|
| ↳ `reply_users_count` | number | Number of unique users who replied |
|
||||||
|
| ↳ `latest_reply` | string | Timestamp of most recent reply |
|
||||||
|
| ↳ `subscribed` | boolean | Whether user is subscribed to thread |
|
||||||
|
| ↳ `last_read` | string | Timestamp of last read message |
|
||||||
|
| ↳ `unread_count` | number | Number of unread messages in thread |
|
||||||
|
| ↳ `subtype` | string | Message subtype \(bot_message, file_share, etc.\) |
|
||||||
|
| ↳ `is_starred` | boolean | Whether message is starred by user |
|
||||||
|
| ↳ `pinned_to` | array | Channel IDs where message is pinned |
|
||||||
|
| ↳ `permalink` | string | Permanent URL to the message |
|
||||||
|
| ↳ `reactions` | array | Reactions on this message |
|
||||||
|
| ↳ `name` | string | Emoji name \(without colons\) |
|
||||||
|
| ↳ `count` | number | Number of times this reaction was added |
|
||||||
|
| ↳ `users` | array | Array of user IDs who reacted |
|
||||||
|
| ↳ `files` | array | Files attached to the message |
|
||||||
|
| ↳ `id` | string | Unique file identifier |
|
||||||
|
| ↳ `name` | string | File name |
|
||||||
|
| ↳ `mimetype` | string | MIME type of the file |
|
||||||
|
| ↳ `size` | number | File size in bytes |
|
||||||
|
| ↳ `url_private` | string | Private download URL \(requires auth\) |
|
||||||
|
| ↳ `permalink` | string | Permanent link to the file |
|
||||||
|
| ↳ `mode` | string | File mode \(hosted, external, etc.\) |
|
||||||
|
| ↳ `attachments` | array | Legacy attachments on the message |
|
||||||
|
| ↳ `id` | number | Attachment ID |
|
||||||
|
| ↳ `fallback` | string | Plain text summary |
|
||||||
|
| ↳ `text` | string | Main attachment text |
|
||||||
|
| ↳ `pretext` | string | Text shown before attachment |
|
||||||
|
| ↳ `color` | string | Color bar hex code or preset |
|
||||||
|
| ↳ `author_name` | string | Author display name |
|
||||||
|
| ↳ `author_link` | string | Author link URL |
|
||||||
|
| ↳ `author_icon` | string | Author icon URL |
|
||||||
|
| ↳ `title` | string | Attachment title |
|
||||||
|
| ↳ `title_link` | string | Title link URL |
|
||||||
|
| ↳ `image_url` | string | Image URL |
|
||||||
|
| ↳ `thumb_url` | string | Thumbnail URL |
|
||||||
|
| ↳ `footer` | string | Footer text |
|
||||||
|
| ↳ `footer_icon` | string | Footer icon URL |
|
||||||
|
| ↳ `ts` | string | Timestamp shown in footer |
|
||||||
|
| ↳ `blocks` | array | Block Kit blocks in the message |
|
||||||
|
| ↳ `type` | string | Block type \(section, divider, image, actions, etc.\) |
|
||||||
|
| ↳ `block_id` | string | Unique block identifier |
|
||||||
|
| ↳ `edited` | object | Edit information if message was edited |
|
||||||
|
| ↳ `user` | string | User ID who edited the message |
|
||||||
|
| ↳ `ts` | string | Timestamp of the edit |
|
||||||
| `replyCount` | number | Number of replies returned in this response |
|
| `replyCount` | number | Number of replies returned in this response |
|
||||||
| `hasMore` | boolean | Whether there are more messages in the thread \(pagination needed\) |
|
| `hasMore` | boolean | Whether there are more messages in the thread \(pagination needed\) |
|
||||||
|
|
||||||
@@ -304,14 +535,20 @@ List all channels in a Slack workspace. Returns public and private channels the
|
|||||||
| `channels` | array | Array of channel objects from the workspace |
|
| `channels` | array | Array of channel objects from the workspace |
|
||||||
| ↳ `id` | string | Channel ID \(e.g., C1234567890\) |
|
| ↳ `id` | string | Channel ID \(e.g., C1234567890\) |
|
||||||
| ↳ `name` | string | Channel name without # prefix |
|
| ↳ `name` | string | Channel name without # prefix |
|
||||||
| ↳ `is_private` | boolean | Whether the channel is private |
|
| ↳ `is_channel` | boolean | Whether this is a channel |
|
||||||
| ↳ `is_archived` | boolean | Whether the channel is archived |
|
| ↳ `is_private` | boolean | Whether channel is private |
|
||||||
| ↳ `is_member` | boolean | Whether the bot is a member of the channel |
|
| ↳ `is_archived` | boolean | Whether channel is archived |
|
||||||
|
| ↳ `is_general` | boolean | Whether this is the general channel |
|
||||||
|
| ↳ `is_member` | boolean | Whether the bot/user is a member |
|
||||||
|
| ↳ `is_shared` | boolean | Whether channel is shared across workspaces |
|
||||||
|
| ↳ `is_ext_shared` | boolean | Whether channel is externally shared |
|
||||||
|
| ↳ `is_org_shared` | boolean | Whether channel is org-wide shared |
|
||||||
| ↳ `num_members` | number | Number of members in the channel |
|
| ↳ `num_members` | number | Number of members in the channel |
|
||||||
| ↳ `topic` | string | Channel topic |
|
| ↳ `topic` | string | Channel topic |
|
||||||
| ↳ `purpose` | string | Channel purpose/description |
|
| ↳ `purpose` | string | Channel purpose/description |
|
||||||
| ↳ `created` | number | Unix timestamp when channel was created |
|
| ↳ `created` | number | Unix timestamp when channel was created |
|
||||||
| ↳ `creator` | string | User ID of channel creator |
|
| ↳ `creator` | string | User ID of channel creator |
|
||||||
|
| ↳ `updated` | number | Unix timestamp of last update |
|
||||||
| `ids` | array | Array of channel IDs for easy access |
|
| `ids` | array | Array of channel IDs for easy access |
|
||||||
| `names` | array | Array of channel names for easy access |
|
| `names` | array | Array of channel names for easy access |
|
||||||
| `count` | number | Total number of channels returned |
|
| `count` | number | Total number of channels returned |
|
||||||
@@ -387,7 +624,8 @@ Get detailed information about a specific Slack user by their user ID.
|
|||||||
| Parameter | Type | Description |
|
| Parameter | Type | Description |
|
||||||
| --------- | ---- | ----------- |
|
| --------- | ---- | ----------- |
|
||||||
| `user` | object | Detailed user information |
|
| `user` | object | Detailed user information |
|
||||||
| ↳ `id` | string | User ID |
|
| ↳ `id` | string | User ID \(e.g., U1234567890\) |
|
||||||
|
| ↳ `team_id` | string | Workspace/team ID |
|
||||||
| ↳ `name` | string | Username \(handle\) |
|
| ↳ `name` | string | Username \(handle\) |
|
||||||
| ↳ `real_name` | string | Full real name |
|
| ↳ `real_name` | string | Full real name |
|
||||||
| ↳ `display_name` | string | Display name shown in Slack |
|
| ↳ `display_name` | string | Display name shown in Slack |
|
||||||
@@ -402,10 +640,14 @@ Get detailed information about a specific Slack user by their user ID.
|
|||||||
| ↳ `is_primary_owner` | boolean | Whether the user is the primary owner |
|
| ↳ `is_primary_owner` | boolean | Whether the user is the primary owner |
|
||||||
| ↳ `is_restricted` | boolean | Whether the user is a guest \(restricted\) |
|
| ↳ `is_restricted` | boolean | Whether the user is a guest \(restricted\) |
|
||||||
| ↳ `is_ultra_restricted` | boolean | Whether the user is a single-channel guest |
|
| ↳ `is_ultra_restricted` | boolean | Whether the user is a single-channel guest |
|
||||||
|
| ↳ `is_app_user` | boolean | Whether user is an app user |
|
||||||
|
| ↳ `is_stranger` | boolean | Whether user is from different workspace |
|
||||||
| ↳ `deleted` | boolean | Whether the user is deactivated |
|
| ↳ `deleted` | boolean | Whether the user is deactivated |
|
||||||
|
| ↳ `color` | string | User color for display |
|
||||||
| ↳ `timezone` | string | Timezone identifier \(e.g., America/Los_Angeles\) |
|
| ↳ `timezone` | string | Timezone identifier \(e.g., America/Los_Angeles\) |
|
||||||
| ↳ `timezone_label` | string | Human-readable timezone label |
|
| ↳ `timezone_label` | string | Human-readable timezone label |
|
||||||
| ↳ `timezone_offset` | number | Timezone offset in seconds from UTC |
|
| ↳ `timezone_offset` | number | Timezone offset in seconds from UTC |
|
||||||
|
| ↳ `avatar` | string | URL to user avatar image |
|
||||||
| ↳ `avatar_24` | string | URL to 24px avatar |
|
| ↳ `avatar_24` | string | URL to 24px avatar |
|
||||||
| ↳ `avatar_48` | string | URL to 48px avatar |
|
| ↳ `avatar_48` | string | URL to 48px avatar |
|
||||||
| ↳ `avatar_72` | string | URL to 72px avatar |
|
| ↳ `avatar_72` | string | URL to 72px avatar |
|
||||||
@@ -415,6 +657,7 @@ Get detailed information about a specific Slack user by their user ID.
|
|||||||
| ↳ `status_emoji` | string | Custom status emoji |
|
| ↳ `status_emoji` | string | Custom status emoji |
|
||||||
| ↳ `status_expiration` | number | Unix timestamp when status expires |
|
| ↳ `status_expiration` | number | Unix timestamp when status expires |
|
||||||
| ↳ `updated` | number | Unix timestamp of last profile update |
|
| ↳ `updated` | number | Unix timestamp of last profile update |
|
||||||
|
| ↳ `has_2fa` | boolean | Whether two-factor auth is enabled |
|
||||||
|
|
||||||
### `slack_download`
|
### `slack_download`
|
||||||
|
|
||||||
@@ -454,6 +697,60 @@ Update a message previously sent by the bot in Slack
|
|||||||
| Parameter | Type | Description |
|
| Parameter | Type | Description |
|
||||||
| --------- | ---- | ----------- |
|
| --------- | ---- | ----------- |
|
||||||
| `message` | object | Complete updated message object with all properties returned by Slack |
|
| `message` | object | Complete updated message object with all properties returned by Slack |
|
||||||
|
| ↳ `type` | string | Message type \(usually "message"\) |
|
||||||
|
| ↳ `ts` | string | Message timestamp \(unique identifier\) |
|
||||||
|
| ↳ `text` | string | Message text content |
|
||||||
|
| ↳ `user` | string | User ID who sent the message |
|
||||||
|
| ↳ `bot_id` | string | Bot ID if sent by a bot |
|
||||||
|
| ↳ `username` | string | Display username |
|
||||||
|
| ↳ `channel` | string | Channel ID |
|
||||||
|
| ↳ `team` | string | Team/workspace ID |
|
||||||
|
| ↳ `thread_ts` | string | Parent message timestamp \(for threaded replies\) |
|
||||||
|
| ↳ `parent_user_id` | string | User ID of thread parent message author |
|
||||||
|
| ↳ `reply_count` | number | Total number of replies in thread |
|
||||||
|
| ↳ `reply_users_count` | number | Number of unique users who replied |
|
||||||
|
| ↳ `latest_reply` | string | Timestamp of most recent reply |
|
||||||
|
| ↳ `subscribed` | boolean | Whether user is subscribed to thread |
|
||||||
|
| ↳ `last_read` | string | Timestamp of last read message |
|
||||||
|
| ↳ `unread_count` | number | Number of unread messages in thread |
|
||||||
|
| ↳ `subtype` | string | Message subtype \(bot_message, file_share, etc.\) |
|
||||||
|
| ↳ `is_starred` | boolean | Whether message is starred by user |
|
||||||
|
| ↳ `pinned_to` | array | Channel IDs where message is pinned |
|
||||||
|
| ↳ `permalink` | string | Permanent URL to the message |
|
||||||
|
| ↳ `reactions` | array | Reactions on this message |
|
||||||
|
| ↳ `name` | string | Emoji name \(without colons\) |
|
||||||
|
| ↳ `count` | number | Number of times this reaction was added |
|
||||||
|
| ↳ `users` | array | Array of user IDs who reacted |
|
||||||
|
| ↳ `files` | array | Files attached to the message |
|
||||||
|
| ↳ `id` | string | Unique file identifier |
|
||||||
|
| ↳ `name` | string | File name |
|
||||||
|
| ↳ `mimetype` | string | MIME type of the file |
|
||||||
|
| ↳ `size` | number | File size in bytes |
|
||||||
|
| ↳ `url_private` | string | Private download URL \(requires auth\) |
|
||||||
|
| ↳ `permalink` | string | Permanent link to the file |
|
||||||
|
| ↳ `mode` | string | File mode \(hosted, external, etc.\) |
|
||||||
|
| ↳ `attachments` | array | Legacy attachments on the message |
|
||||||
|
| ↳ `id` | number | Attachment ID |
|
||||||
|
| ↳ `fallback` | string | Plain text summary |
|
||||||
|
| ↳ `text` | string | Main attachment text |
|
||||||
|
| ↳ `pretext` | string | Text shown before attachment |
|
||||||
|
| ↳ `color` | string | Color bar hex code or preset |
|
||||||
|
| ↳ `author_name` | string | Author display name |
|
||||||
|
| ↳ `author_link` | string | Author link URL |
|
||||||
|
| ↳ `author_icon` | string | Author icon URL |
|
||||||
|
| ↳ `title` | string | Attachment title |
|
||||||
|
| ↳ `title_link` | string | Title link URL |
|
||||||
|
| ↳ `image_url` | string | Image URL |
|
||||||
|
| ↳ `thumb_url` | string | Thumbnail URL |
|
||||||
|
| ↳ `footer` | string | Footer text |
|
||||||
|
| ↳ `footer_icon` | string | Footer icon URL |
|
||||||
|
| ↳ `ts` | string | Timestamp shown in footer |
|
||||||
|
| ↳ `blocks` | array | Block Kit blocks in the message |
|
||||||
|
| ↳ `type` | string | Block type \(section, divider, image, actions, etc.\) |
|
||||||
|
| ↳ `block_id` | string | Unique block identifier |
|
||||||
|
| ↳ `edited` | object | Edit information if message was edited |
|
||||||
|
| ↳ `user` | string | User ID who edited the message |
|
||||||
|
| ↳ `ts` | string | Timestamp of the edit |
|
||||||
| `content` | string | Success message |
|
| `content` | string | Success message |
|
||||||
| `metadata` | object | Updated message metadata |
|
| `metadata` | object | Updated message metadata |
|
||||||
| ↳ `channel` | string | Channel ID |
|
| ↳ `channel` | string | Channel ID |
|
||||||
|
|||||||
@@ -79,13 +79,19 @@ Run an autonomous web agent to complete tasks and extract structured data
|
|||||||
| Parameter | Type | Description |
|
| Parameter | Type | Description |
|
||||||
| --------- | ---- | ----------- |
|
| --------- | ---- | ----------- |
|
||||||
| `agentResult` | object | Result from the Stagehand agent execution |
|
| `agentResult` | object | Result from the Stagehand agent execution |
|
||||||
| ↳ `success` | boolean | Whether the agent task completed successfully |
|
| ↳ `success` | boolean | Whether the agent task completed successfully without errors |
|
||||||
| ↳ `completed` | boolean | Whether the task was fully completed |
|
| ↳ `completed` | boolean | Whether the agent finished executing \(may be false if max steps reached\) |
|
||||||
| ↳ `message` | string | Status message or final result |
|
| ↳ `message` | string | Final status message or result summary from the agent |
|
||||||
| ↳ `actions` | array | Type of action performed |
|
| ↳ `actions` | array | List of all actions performed by the agent during task execution |
|
||||||
| ↳ `type` | string | Type of action performed |
|
| ↳ `type` | string | Type of action performed \(e.g., "act", "observe", "ariaTree", "close", "wait", "navigate"\) |
|
||||||
| ↳ `params` | object | Parameters used for the action |
|
| ↳ `reasoning` | string | AI reasoning for why this action was taken |
|
||||||
| ↳ `result` | object | Result of the action |
|
| ↳ `taskCompleted` | boolean | Whether the task was completed after this action |
|
||||||
|
| ↳ `action` | string | Description of the action taken \(e.g., "click the submit button"\) |
|
||||||
|
| ↳ `instruction` | string | Instruction that triggered this action |
|
||||||
|
| ↳ `pageUrl` | string | URL of the page when this action was performed |
|
||||||
|
| ↳ `pageText` | string | Page text content \(for ariaTree actions\) |
|
||||||
|
| ↳ `timestamp` | number | Unix timestamp when the action was performed |
|
||||||
|
| ↳ `timeMs` | number | Time in milliseconds \(for wait actions\) |
|
||||||
| `structuredOutput` | object | Extracted data matching the provided output schema |
|
| `structuredOutput` | object | Extracted data matching the provided output schema |
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -74,6 +74,11 @@ Transcribe audio to text using OpenAI Whisper
|
|||||||
| --------- | ---- | ----------- |
|
| --------- | ---- | ----------- |
|
||||||
| `transcript` | string | Full transcribed text |
|
| `transcript` | string | Full transcribed text |
|
||||||
| `segments` | array | Timestamped segments |
|
| `segments` | array | Timestamped segments |
|
||||||
|
| ↳ `text` | string | Transcribed text for this segment |
|
||||||
|
| ↳ `start` | number | Start time in seconds |
|
||||||
|
| ↳ `end` | number | End time in seconds |
|
||||||
|
| ↳ `speaker` | string | Speaker identifier \(if diarization enabled\) |
|
||||||
|
| ↳ `confidence` | number | Confidence score \(0-1\) |
|
||||||
| `language` | string | Detected or specified language |
|
| `language` | string | Detected or specified language |
|
||||||
| `duration` | number | Audio duration in seconds |
|
| `duration` | number | Audio duration in seconds |
|
||||||
|
|
||||||
@@ -101,6 +106,11 @@ Transcribe audio to text using Deepgram
|
|||||||
| --------- | ---- | ----------- |
|
| --------- | ---- | ----------- |
|
||||||
| `transcript` | string | Full transcribed text |
|
| `transcript` | string | Full transcribed text |
|
||||||
| `segments` | array | Timestamped segments with speaker labels |
|
| `segments` | array | Timestamped segments with speaker labels |
|
||||||
|
| ↳ `text` | string | Transcribed text for this segment |
|
||||||
|
| ↳ `start` | number | Start time in seconds |
|
||||||
|
| ↳ `end` | number | End time in seconds |
|
||||||
|
| ↳ `speaker` | string | Speaker identifier \(if diarization enabled\) |
|
||||||
|
| ↳ `confidence` | number | Confidence score \(0-1\) |
|
||||||
| `language` | string | Detected or specified language |
|
| `language` | string | Detected or specified language |
|
||||||
| `duration` | number | Audio duration in seconds |
|
| `duration` | number | Audio duration in seconds |
|
||||||
| `confidence` | number | Overall confidence score |
|
| `confidence` | number | Overall confidence score |
|
||||||
@@ -160,11 +170,25 @@ Transcribe audio to text using AssemblyAI with advanced NLP features
|
|||||||
| --------- | ---- | ----------- |
|
| --------- | ---- | ----------- |
|
||||||
| `transcript` | string | Full transcribed text |
|
| `transcript` | string | Full transcribed text |
|
||||||
| `segments` | array | Timestamped segments with speaker labels |
|
| `segments` | array | Timestamped segments with speaker labels |
|
||||||
|
| ↳ `text` | string | Transcribed text for this segment |
|
||||||
|
| ↳ `start` | number | Start time in seconds |
|
||||||
|
| ↳ `end` | number | End time in seconds |
|
||||||
|
| ↳ `speaker` | string | Speaker identifier \(if diarization enabled\) |
|
||||||
|
| ↳ `confidence` | number | Confidence score \(0-1\) |
|
||||||
| `language` | string | Detected or specified language |
|
| `language` | string | Detected or specified language |
|
||||||
| `duration` | number | Audio duration in seconds |
|
| `duration` | number | Audio duration in seconds |
|
||||||
| `confidence` | number | Overall confidence score |
|
| `confidence` | number | Overall confidence score |
|
||||||
| `sentiment` | array | Sentiment analysis results |
|
| `sentiment` | array | Sentiment analysis results |
|
||||||
|
| ↳ `text` | string | Text that was analyzed |
|
||||||
|
| ↳ `sentiment` | string | Sentiment \(POSITIVE, NEGATIVE, NEUTRAL\) |
|
||||||
|
| ↳ `confidence` | number | Confidence score |
|
||||||
|
| ↳ `start` | number | Start time in milliseconds |
|
||||||
|
| ↳ `end` | number | End time in milliseconds |
|
||||||
| `entities` | array | Detected entities |
|
| `entities` | array | Detected entities |
|
||||||
|
| ↳ `entity_type` | string | Entity type \(e.g., person_name, location, organization\) |
|
||||||
|
| ↳ `text` | string | Entity text |
|
||||||
|
| ↳ `start` | number | Start time in milliseconds |
|
||||||
|
| ↳ `end` | number | End time in milliseconds |
|
||||||
| `summary` | string | Auto-generated summary |
|
| `summary` | string | Auto-generated summary |
|
||||||
|
|
||||||
### `stt_gemini`
|
### `stt_gemini`
|
||||||
|
|||||||
@@ -282,9 +282,24 @@ Introspect Supabase database schema to get table structures, columns, and relati
|
|||||||
| ↳ `name` | string | Table name |
|
| ↳ `name` | string | Table name |
|
||||||
| ↳ `schema` | string | Database schema name |
|
| ↳ `schema` | string | Database schema name |
|
||||||
| ↳ `columns` | array | Array of column definitions |
|
| ↳ `columns` | array | Array of column definitions |
|
||||||
|
| ↳ `name` | string | Column name |
|
||||||
|
| ↳ `type` | string | Column data type |
|
||||||
|
| ↳ `nullable` | boolean | Whether the column allows null values |
|
||||||
|
| ↳ `default` | string | Default value for the column |
|
||||||
|
| ↳ `isPrimaryKey` | boolean | Whether the column is a primary key |
|
||||||
|
| ↳ `isForeignKey` | boolean | Whether the column is a foreign key |
|
||||||
|
| ↳ `references` | object | Foreign key reference details |
|
||||||
|
| ↳ `table` | string | Referenced table name |
|
||||||
|
| ↳ `column` | string | Referenced column name |
|
||||||
| ↳ `primaryKey` | array | Array of primary key column names |
|
| ↳ `primaryKey` | array | Array of primary key column names |
|
||||||
| ↳ `foreignKeys` | array | Array of foreign key relationships |
|
| ↳ `foreignKeys` | array | Array of foreign key relationships |
|
||||||
|
| ↳ `column` | string | Local column name |
|
||||||
|
| ↳ `referencesTable` | string | Referenced table name |
|
||||||
|
| ↳ `referencesColumn` | string | Referenced column name |
|
||||||
| ↳ `indexes` | array | Array of index definitions |
|
| ↳ `indexes` | array | Array of index definitions |
|
||||||
|
| ↳ `name` | string | Index name |
|
||||||
|
| ↳ `columns` | array | Columns included in the index |
|
||||||
|
| ↳ `unique` | boolean | Whether the index enforces uniqueness |
|
||||||
| `schemas` | array | List of schemas found in the database |
|
| `schemas` | array | List of schemas found in the database |
|
||||||
|
|
||||||
### `supabase_storage_upload`
|
### `supabase_storage_upload`
|
||||||
@@ -310,6 +325,9 @@ Upload a file to a Supabase storage bucket
|
|||||||
| --------- | ---- | ----------- |
|
| --------- | ---- | ----------- |
|
||||||
| `message` | string | Operation status message |
|
| `message` | string | Operation status message |
|
||||||
| `results` | object | Upload result including file path, bucket, and public URL |
|
| `results` | object | Upload result including file path, bucket, and public URL |
|
||||||
|
| ↳ `id` | string | Unique identifier for the uploaded file |
|
||||||
|
| ↳ `path` | string | Path to the uploaded file within the bucket |
|
||||||
|
| ↳ `fullPath` | string | Full path including bucket name |
|
||||||
|
|
||||||
### `supabase_storage_download`
|
### `supabase_storage_download`
|
||||||
|
|
||||||
@@ -355,6 +373,19 @@ List files in a Supabase storage bucket
|
|||||||
| --------- | ---- | ----------- |
|
| --------- | ---- | ----------- |
|
||||||
| `message` | string | Operation status message |
|
| `message` | string | Operation status message |
|
||||||
| `results` | array | Array of file objects with metadata |
|
| `results` | array | Array of file objects with metadata |
|
||||||
|
| ↳ `id` | string | Unique file identifier |
|
||||||
|
| ↳ `name` | string | File name |
|
||||||
|
| ↳ `bucket_id` | string | Bucket identifier the file belongs to |
|
||||||
|
| ↳ `owner` | string | Owner identifier |
|
||||||
|
| ↳ `created_at` | string | File creation timestamp |
|
||||||
|
| ↳ `updated_at` | string | Last update timestamp |
|
||||||
|
| ↳ `last_accessed_at` | string | Last access timestamp |
|
||||||
|
| ↳ `metadata` | object | File metadata including size and MIME type |
|
||||||
|
| ↳ `size` | number | File size in bytes |
|
||||||
|
| ↳ `mimetype` | string | MIME type of the file |
|
||||||
|
| ↳ `cacheControl` | string | Cache control header value |
|
||||||
|
| ↳ `lastModified` | string | Last modified timestamp |
|
||||||
|
| ↳ `eTag` | string | Entity tag for caching |
|
||||||
|
|
||||||
### `supabase_storage_delete`
|
### `supabase_storage_delete`
|
||||||
|
|
||||||
@@ -375,6 +406,13 @@ Delete files from a Supabase storage bucket
|
|||||||
| --------- | ---- | ----------- |
|
| --------- | ---- | ----------- |
|
||||||
| `message` | string | Operation status message |
|
| `message` | string | Operation status message |
|
||||||
| `results` | array | Array of deleted file objects |
|
| `results` | array | Array of deleted file objects |
|
||||||
|
| ↳ `name` | string | Name of the deleted file |
|
||||||
|
| ↳ `bucket_id` | string | Bucket identifier |
|
||||||
|
| ↳ `owner` | string | Owner identifier |
|
||||||
|
| ↳ `id` | string | Unique file identifier |
|
||||||
|
| ↳ `updated_at` | string | Last update timestamp |
|
||||||
|
| ↳ `created_at` | string | File creation timestamp |
|
||||||
|
| ↳ `last_accessed_at` | string | Last access timestamp |
|
||||||
|
|
||||||
### `supabase_storage_move`
|
### `supabase_storage_move`
|
||||||
|
|
||||||
@@ -396,6 +434,7 @@ Move a file within a Supabase storage bucket
|
|||||||
| --------- | ---- | ----------- |
|
| --------- | ---- | ----------- |
|
||||||
| `message` | string | Operation status message |
|
| `message` | string | Operation status message |
|
||||||
| `results` | object | Move operation result |
|
| `results` | object | Move operation result |
|
||||||
|
| ↳ `message` | string | Operation status message |
|
||||||
|
|
||||||
### `supabase_storage_copy`
|
### `supabase_storage_copy`
|
||||||
|
|
||||||
@@ -417,6 +456,7 @@ Copy a file within a Supabase storage bucket
|
|||||||
| --------- | ---- | ----------- |
|
| --------- | ---- | ----------- |
|
||||||
| `message` | string | Operation status message |
|
| `message` | string | Operation status message |
|
||||||
| `results` | object | Copy operation result |
|
| `results` | object | Copy operation result |
|
||||||
|
| ↳ `message` | string | Operation status message |
|
||||||
|
|
||||||
### `supabase_storage_create_bucket`
|
### `supabase_storage_create_bucket`
|
||||||
|
|
||||||
@@ -439,6 +479,7 @@ Create a new storage bucket in Supabase
|
|||||||
| --------- | ---- | ----------- |
|
| --------- | ---- | ----------- |
|
||||||
| `message` | string | Operation status message |
|
| `message` | string | Operation status message |
|
||||||
| `results` | object | Created bucket information |
|
| `results` | object | Created bucket information |
|
||||||
|
| ↳ `name` | string | Created bucket name |
|
||||||
|
|
||||||
### `supabase_storage_list_buckets`
|
### `supabase_storage_list_buckets`
|
||||||
|
|
||||||
@@ -457,6 +498,14 @@ List all storage buckets in Supabase
|
|||||||
| --------- | ---- | ----------- |
|
| --------- | ---- | ----------- |
|
||||||
| `message` | string | Operation status message |
|
| `message` | string | Operation status message |
|
||||||
| `results` | array | Array of bucket objects |
|
| `results` | array | Array of bucket objects |
|
||||||
|
| ↳ `id` | string | Unique bucket identifier |
|
||||||
|
| ↳ `name` | string | Bucket name |
|
||||||
|
| ↳ `owner` | string | Owner identifier |
|
||||||
|
| ↳ `public` | boolean | Whether the bucket is publicly accessible |
|
||||||
|
| ↳ `created_at` | string | Bucket creation timestamp |
|
||||||
|
| ↳ `updated_at` | string | Last update timestamp |
|
||||||
|
| ↳ `file_size_limit` | number | Maximum file size allowed in bytes |
|
||||||
|
| ↳ `allowed_mime_types` | array | List of allowed MIME types for uploads |
|
||||||
|
|
||||||
### `supabase_storage_delete_bucket`
|
### `supabase_storage_delete_bucket`
|
||||||
|
|
||||||
@@ -476,6 +525,7 @@ Delete a storage bucket in Supabase
|
|||||||
| --------- | ---- | ----------- |
|
| --------- | ---- | ----------- |
|
||||||
| `message` | string | Operation status message |
|
| `message` | string | Operation status message |
|
||||||
| `results` | object | Delete operation result |
|
| `results` | object | Delete operation result |
|
||||||
|
| ↳ `message` | string | Operation status message |
|
||||||
|
|
||||||
### `supabase_storage_get_public_url`
|
### `supabase_storage_get_public_url`
|
||||||
|
|
||||||
|
|||||||
@@ -65,9 +65,17 @@ Perform AI-powered web searches using Tavily
|
|||||||
| Parameter | Type | Description |
|
| Parameter | Type | Description |
|
||||||
| --------- | ---- | ----------- |
|
| --------- | ---- | ----------- |
|
||||||
| `query` | string | The search query that was executed |
|
| `query` | string | The search query that was executed |
|
||||||
| `results` | array | Search results with titles, URLs, content snippets, and optional metadata |
|
| `results` | array | Ranked search results with titles, URLs, content snippets, and optional metadata |
|
||||||
|
| ↳ `title` | string | Result title |
|
||||||
|
| ↳ `url` | string | Result URL |
|
||||||
|
| ↳ `content` | string | Brief description or content snippet |
|
||||||
|
| ↳ `score` | number | Relevance score |
|
||||||
|
| ↳ `raw_content` | string | Full parsed HTML content \(if requested\) |
|
||||||
|
| ↳ `favicon` | string | Favicon URL for the domain |
|
||||||
| `answer` | string | LLM-generated answer to the query \(if requested\) |
|
| `answer` | string | LLM-generated answer to the query \(if requested\) |
|
||||||
| `images` | array | Query-related images \(if requested\) |
|
| `images` | array | Query-related images \(if requested\) |
|
||||||
|
| ↳ `url` | string | Image URL |
|
||||||
|
| ↳ `description` | string | Image description |
|
||||||
| `auto_parameters` | object | Automatically selected parameters based on query intent \(if enabled\) |
|
| `auto_parameters` | object | Automatically selected parameters based on query intent \(if enabled\) |
|
||||||
| `response_time` | number | Time taken for the search request in seconds |
|
| `response_time` | number | Time taken for the search request in seconds |
|
||||||
|
|
||||||
@@ -90,13 +98,14 @@ Extract raw content from multiple web pages simultaneously using Tavily
|
|||||||
|
|
||||||
| Parameter | Type | Description |
|
| Parameter | Type | Description |
|
||||||
| --------- | ---- | ----------- |
|
| --------- | ---- | ----------- |
|
||||||
| `results` | array | The URL that was extracted |
|
| `results` | array | Successfully extracted content from URLs |
|
||||||
| ↳ `url` | string | The URL that was extracted |
|
| ↳ `url` | string | The source URL |
|
||||||
| ↳ `raw_content` | string | The raw text content from the webpage |
|
| ↳ `raw_content` | string | Full extracted content from the page |
|
||||||
| ↳ `favicon` | string | Favicon URL \(if requested\) |
|
| ↳ `images` | array | Image URLs \(when include_images is true\) |
|
||||||
| `failed_results` | array | The URL that failed extraction |
|
| ↳ `favicon` | string | Favicon URL for the result |
|
||||||
|
| `failed_results` | array | URLs that failed to extract content |
|
||||||
| ↳ `url` | string | The URL that failed extraction |
|
| ↳ `url` | string | The URL that failed extraction |
|
||||||
| ↳ `error` | string | Error message for the failed extraction |
|
| ↳ `error` | string | Error message describing why extraction failed |
|
||||||
| `response_time` | number | Time taken for the extraction request in seconds |
|
| `response_time` | number | Time taken for the extraction request in seconds |
|
||||||
|
|
||||||
### `tavily_crawl`
|
### `tavily_crawl`
|
||||||
@@ -128,10 +137,10 @@ Systematically crawl and extract content from websites using Tavily
|
|||||||
| Parameter | Type | Description |
|
| Parameter | Type | Description |
|
||||||
| --------- | ---- | ----------- |
|
| --------- | ---- | ----------- |
|
||||||
| `base_url` | string | The base URL that was crawled |
|
| `base_url` | string | The base URL that was crawled |
|
||||||
| `results` | array | The crawled page URL |
|
| `results` | array | Array of crawled pages with extracted content |
|
||||||
| ↳ `url` | string | The crawled page URL |
|
| ↳ `url` | string | The crawled page URL |
|
||||||
| ↳ `raw_content` | string | Extracted content from the page |
|
| ↳ `raw_content` | string | Full extracted page content |
|
||||||
| ↳ `favicon` | string | Favicon URL \(if requested\) |
|
| ↳ `favicon` | string | Favicon URL for the result |
|
||||||
| `response_time` | number | Time taken for the crawl request in seconds |
|
| `response_time` | number | Time taken for the crawl request in seconds |
|
||||||
| `request_id` | string | Unique identifier for support reference |
|
| `request_id` | string | Unique identifier for support reference |
|
||||||
|
|
||||||
@@ -160,7 +169,7 @@ Discover and visualize website structure using Tavily
|
|||||||
| Parameter | Type | Description |
|
| Parameter | Type | Description |
|
||||||
| --------- | ---- | ----------- |
|
| --------- | ---- | ----------- |
|
||||||
| `base_url` | string | The base URL that was mapped |
|
| `base_url` | string | The base URL that was mapped |
|
||||||
| `results` | array | Discovered URL |
|
| `results` | array | Array of discovered URLs during mapping |
|
||||||
| ↳ `url` | string | Discovered URL |
|
| ↳ `url` | string | Discovered URL |
|
||||||
| `response_time` | number | Time taken for the map request in seconds |
|
| `response_time` | number | Time taken for the map request in seconds |
|
||||||
| `request_id` | string | Unique identifier for support reference |
|
| `request_id` | string | Unique identifier for support reference |
|
||||||
|
|||||||
@@ -173,8 +173,8 @@ Send videos to Telegram channels or users through the Telegram Bot API.
|
|||||||
| ↳ `from` | object | Information about the sender |
|
| ↳ `from` | object | Information about the sender |
|
||||||
| ↳ `id` | number | Sender ID |
|
| ↳ `id` | number | Sender ID |
|
||||||
| ↳ `is_bot` | boolean | Whether the chat is a bot or not |
|
| ↳ `is_bot` | boolean | Whether the chat is a bot or not |
|
||||||
| ↳ `first_name` | string | Sender |
|
| ↳ `first_name` | string | Sender's first name \(if available\) |
|
||||||
| ↳ `username` | string | Sender |
|
| ↳ `username` | string | Sender's username \(if available\) |
|
||||||
| ↳ `chat` | object | Information about the chat where message was sent |
|
| ↳ `chat` | object | Information about the chat where message was sent |
|
||||||
| ↳ `id` | number | Chat ID |
|
| ↳ `id` | number | Chat ID |
|
||||||
| ↳ `first_name` | string | Chat first name \(if private chat\) |
|
| ↳ `first_name` | string | Chat first name \(if private chat\) |
|
||||||
@@ -245,8 +245,8 @@ Send audio files to Telegram channels or users through the Telegram Bot API.
|
|||||||
| ↳ `from` | object | Information about the sender |
|
| ↳ `from` | object | Information about the sender |
|
||||||
| ↳ `id` | number | Sender ID |
|
| ↳ `id` | number | Sender ID |
|
||||||
| ↳ `is_bot` | boolean | Whether the chat is a bot or not |
|
| ↳ `is_bot` | boolean | Whether the chat is a bot or not |
|
||||||
| ↳ `first_name` | string | Sender |
|
| ↳ `first_name` | string | Sender's first name \(if available\) |
|
||||||
| ↳ `username` | string | Sender |
|
| ↳ `username` | string | Sender's username \(if available\) |
|
||||||
| ↳ `chat` | object | Information about the chat where the message was sent |
|
| ↳ `chat` | object | Information about the chat where the message was sent |
|
||||||
| ↳ `id` | number | Chat ID |
|
| ↳ `id` | number | Chat ID |
|
||||||
| ↳ `first_name` | string | Chat first name \(if private chat\) |
|
| ↳ `first_name` | string | Chat first name \(if private chat\) |
|
||||||
@@ -287,8 +287,8 @@ Send animations (GIFs) to Telegram channels or users through the Telegram Bot AP
|
|||||||
| ↳ `from` | object | Information about the sender |
|
| ↳ `from` | object | Information about the sender |
|
||||||
| ↳ `id` | number | Sender ID |
|
| ↳ `id` | number | Sender ID |
|
||||||
| ↳ `is_bot` | boolean | Whether the chat is a bot or not |
|
| ↳ `is_bot` | boolean | Whether the chat is a bot or not |
|
||||||
| ↳ `first_name` | string | Sender |
|
| ↳ `first_name` | string | Sender's first name \(if available\) |
|
||||||
| ↳ `username` | string | Sender |
|
| ↳ `username` | string | Sender's username \(if available\) |
|
||||||
| ↳ `chat` | object | Information about the chat where message was sent |
|
| ↳ `chat` | object | Information about the chat where message was sent |
|
||||||
| ↳ `id` | number | Chat ID |
|
| ↳ `id` | number | Chat ID |
|
||||||
| ↳ `first_name` | string | Chat first name \(if private chat\) |
|
| ↳ `first_name` | string | Chat first name \(if private chat\) |
|
||||||
@@ -359,8 +359,8 @@ Send documents (PDF, ZIP, DOC, etc.) to Telegram channels or users through the T
|
|||||||
| ↳ `from` | object | Information about the sender |
|
| ↳ `from` | object | Information about the sender |
|
||||||
| ↳ `id` | number | Sender ID |
|
| ↳ `id` | number | Sender ID |
|
||||||
| ↳ `is_bot` | boolean | Whether the chat is a bot or not |
|
| ↳ `is_bot` | boolean | Whether the chat is a bot or not |
|
||||||
| ↳ `first_name` | string | Sender |
|
| ↳ `first_name` | string | Sender's first name \(if available\) |
|
||||||
| ↳ `username` | string | Sender |
|
| ↳ `username` | string | Sender's username \(if available\) |
|
||||||
| ↳ `chat` | object | Information about the chat where message was sent |
|
| ↳ `chat` | object | Information about the chat where message was sent |
|
||||||
| ↳ `id` | number | Chat ID |
|
| ↳ `id` | number | Chat ID |
|
||||||
| ↳ `first_name` | string | Chat first name \(if private chat\) |
|
| ↳ `first_name` | string | Chat first name \(if private chat\) |
|
||||||
|
|||||||
@@ -51,8 +51,19 @@ List all items from a Webflow CMS collection
|
|||||||
|
|
||||||
| Parameter | Type | Description |
|
| Parameter | Type | Description |
|
||||||
| --------- | ---- | ----------- |
|
| --------- | ---- | ----------- |
|
||||||
| `items` | json | Array of collection items |
|
| `items` | array | Array of collection items |
|
||||||
| `metadata` | json | Metadata about the query |
|
| ↳ `id` | string | Unique item ID |
|
||||||
|
| ↳ `cmsLocaleId` | string | CMS locale ID |
|
||||||
|
| ↳ `lastPublished` | string | Last published date \(ISO 8601\) |
|
||||||
|
| ↳ `lastUpdated` | string | Last updated date \(ISO 8601\) |
|
||||||
|
| ↳ `createdOn` | string | Creation date \(ISO 8601\) |
|
||||||
|
| ↳ `isArchived` | boolean | Whether the item is archived |
|
||||||
|
| ↳ `isDraft` | boolean | Whether the item is a draft |
|
||||||
|
| ↳ `fieldData` | object | Collection-specific field data \(varies by collection schema\) |
|
||||||
|
| `metadata` | object | Metadata about the query |
|
||||||
|
| ↳ `itemCount` | number | Number of items returned |
|
||||||
|
| ↳ `offset` | number | Pagination offset |
|
||||||
|
| ↳ `limit` | number | Maximum items per page |
|
||||||
|
|
||||||
### `webflow_get_item`
|
### `webflow_get_item`
|
||||||
|
|
||||||
|
|||||||
@@ -47,12 +47,39 @@ Get a summary and metadata for a specific Wikipedia page.
|
|||||||
| Parameter | Type | Description |
|
| Parameter | Type | Description |
|
||||||
| --------- | ---- | ----------- |
|
| --------- | ---- | ----------- |
|
||||||
| `summary` | object | Wikipedia page summary and metadata |
|
| `summary` | object | Wikipedia page summary and metadata |
|
||||||
|
| ↳ `type` | string | Page type \(standard, disambiguation, etc.\) |
|
||||||
| ↳ `title` | string | Page title |
|
| ↳ `title` | string | Page title |
|
||||||
| ↳ `extract` | string | Page extract/summary text |
|
| ↳ `displaytitle` | string | Display title with formatting |
|
||||||
| ↳ `description` | string | Short page description |
|
| ↳ `description` | string | Short page description |
|
||||||
|
| ↳ `extract` | string | Page extract/summary text |
|
||||||
|
| ↳ `extract_html` | string | Extract in HTML format |
|
||||||
| ↳ `thumbnail` | object | Thumbnail image data |
|
| ↳ `thumbnail` | object | Thumbnail image data |
|
||||||
|
| ↳ `source` | string | Thumbnail image URL |
|
||||||
|
| ↳ `width` | number | Thumbnail width in pixels |
|
||||||
|
| ↳ `height` | number | Thumbnail height in pixels |
|
||||||
|
| ↳ `originalimage` | object | Original image data |
|
||||||
|
| ↳ `source` | string | Thumbnail image URL |
|
||||||
|
| ↳ `width` | number | Thumbnail width in pixels |
|
||||||
|
| ↳ `height` | number | Thumbnail height in pixels |
|
||||||
| ↳ `content_urls` | object | URLs to access the page |
|
| ↳ `content_urls` | object | URLs to access the page |
|
||||||
|
| ↳ `desktop` | object | Desktop URLs |
|
||||||
|
| ↳ `page` | string | Page URL |
|
||||||
|
| ↳ `revisions` | string | Revisions URL |
|
||||||
|
| ↳ `edit` | string | Edit URL |
|
||||||
|
| ↳ `talk` | string | Talk page URL |
|
||||||
|
| ↳ `mobile` | object | Mobile URLs |
|
||||||
|
| ↳ `page` | string | Page URL |
|
||||||
|
| ↳ `revisions` | string | Revisions URL |
|
||||||
|
| ↳ `edit` | string | Edit URL |
|
||||||
|
| ↳ `talk` | string | Talk page URL |
|
||||||
|
| ↳ `lang` | string | Page language code |
|
||||||
|
| ↳ `dir` | string | Text direction \(ltr or rtl\) |
|
||||||
|
| ↳ `timestamp` | string | Last modification timestamp |
|
||||||
| ↳ `pageid` | number | Wikipedia page ID |
|
| ↳ `pageid` | number | Wikipedia page ID |
|
||||||
|
| ↳ `wikibase_item` | string | Wikidata item ID |
|
||||||
|
| ↳ `coordinates` | object | Geographic coordinates |
|
||||||
|
| ↳ `lat` | number | Latitude |
|
||||||
|
| ↳ `lon` | number | Longitude |
|
||||||
|
|
||||||
### `wikipedia_search`
|
### `wikipedia_search`
|
||||||
|
|
||||||
@@ -70,6 +97,20 @@ Search for Wikipedia pages by title or content.
|
|||||||
| Parameter | Type | Description |
|
| Parameter | Type | Description |
|
||||||
| --------- | ---- | ----------- |
|
| --------- | ---- | ----------- |
|
||||||
| `searchResults` | array | Array of matching Wikipedia pages |
|
| `searchResults` | array | Array of matching Wikipedia pages |
|
||||||
|
| ↳ `id` | number | Result index |
|
||||||
|
| ↳ `key` | string | URL-friendly page key |
|
||||||
|
| ↳ `title` | string | Page title |
|
||||||
|
| ↳ `excerpt` | string | Search result excerpt |
|
||||||
|
| ↳ `matched_title` | string | Matched title variant |
|
||||||
|
| ↳ `description` | string | Page description |
|
||||||
|
| ↳ `thumbnail` | object | Thumbnail data |
|
||||||
|
| ↳ `mimetype` | string | Image MIME type |
|
||||||
|
| ↳ `size` | number | File size in bytes |
|
||||||
|
| ↳ `width` | number | Width in pixels |
|
||||||
|
| ↳ `height` | number | Height in pixels |
|
||||||
|
| ↳ `duration` | number | Duration for video |
|
||||||
|
| ↳ `url` | string | Thumbnail URL |
|
||||||
|
| ↳ `url` | string | Page URL |
|
||||||
| `totalHits` | number | Total number of search results found |
|
| `totalHits` | number | Total number of search results found |
|
||||||
| `query` | string | The search query that was executed |
|
| `query` | string | The search query that was executed |
|
||||||
|
|
||||||
@@ -92,7 +133,10 @@ Get the full HTML content of a Wikipedia page.
|
|||||||
| ↳ `pageid` | number | Wikipedia page ID |
|
| ↳ `pageid` | number | Wikipedia page ID |
|
||||||
| ↳ `html` | string | Full HTML content of the page |
|
| ↳ `html` | string | Full HTML content of the page |
|
||||||
| ↳ `revision` | number | Page revision number |
|
| ↳ `revision` | number | Page revision number |
|
||||||
|
| ↳ `tid` | string | Transaction ID \(ETag\) |
|
||||||
| ↳ `timestamp` | string | Last modified timestamp |
|
| ↳ `timestamp` | string | Last modified timestamp |
|
||||||
|
| ↳ `content_model` | string | Content model \(wikitext\) |
|
||||||
|
| ↳ `content_format` | string | Content format \(text/html\) |
|
||||||
|
|
||||||
### `wikipedia_random`
|
### `wikipedia_random`
|
||||||
|
|
||||||
@@ -108,10 +152,22 @@ Get a random Wikipedia page.
|
|||||||
| Parameter | Type | Description |
|
| Parameter | Type | Description |
|
||||||
| --------- | ---- | ----------- |
|
| --------- | ---- | ----------- |
|
||||||
| `randomPage` | object | Random Wikipedia page data |
|
| `randomPage` | object | Random Wikipedia page data |
|
||||||
|
| ↳ `type` | string | Page type |
|
||||||
| ↳ `title` | string | Page title |
|
| ↳ `title` | string | Page title |
|
||||||
| ↳ `extract` | string | Page extract/summary |
|
| ↳ `displaytitle` | string | Display title |
|
||||||
| ↳ `description` | string | Page description |
|
| ↳ `description` | string | Page description |
|
||||||
|
| ↳ `extract` | string | Page extract/summary |
|
||||||
| ↳ `thumbnail` | object | Thumbnail image data |
|
| ↳ `thumbnail` | object | Thumbnail image data |
|
||||||
|
| ↳ `source` | string | Thumbnail image URL |
|
||||||
|
| ↳ `width` | number | Thumbnail width in pixels |
|
||||||
|
| ↳ `height` | number | Thumbnail height in pixels |
|
||||||
| ↳ `content_urls` | object | URLs to access the page |
|
| ↳ `content_urls` | object | URLs to access the page |
|
||||||
|
| ↳ `desktop` | object | Desktop URL |
|
||||||
|
| ↳ `page` | string | Page URL |
|
||||||
|
| ↳ `mobile` | object | Mobile URL |
|
||||||
|
| ↳ `page` | string | Page URL |
|
||||||
|
| ↳ `lang` | string | Language code |
|
||||||
|
| ↳ `timestamp` | string | Timestamp |
|
||||||
|
| ↳ `pageid` | number | Page ID |
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -26,38 +26,12 @@ In Sim, the YouTube integration enables your agents to programmatically search a
|
|||||||
|
|
||||||
## Usage Instructions
|
## Usage Instructions
|
||||||
|
|
||||||
Integrate YouTube into the workflow. Can search for videos, get trending videos, get video details, get video captions, get video categories, get channel information, get all videos from a channel, get channel playlists, get playlist items, and get video comments.
|
Integrate YouTube into the workflow. Can search for videos, get trending videos, get video details, get video categories, get channel information, get all videos from a channel, get channel playlists, get playlist items, and get video comments.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## Tools
|
## Tools
|
||||||
|
|
||||||
### `youtube_captions`
|
|
||||||
|
|
||||||
List available caption tracks (subtitles/transcripts) for a YouTube video. Returns information about each caption including language, type, and whether it is auto-generated.
|
|
||||||
|
|
||||||
#### Input
|
|
||||||
|
|
||||||
| Parameter | Type | Required | Description |
|
|
||||||
| --------- | ---- | -------- | ----------- |
|
|
||||||
| `videoId` | string | Yes | YouTube video ID to get captions for |
|
|
||||||
| `apiKey` | string | Yes | YouTube API Key |
|
|
||||||
|
|
||||||
#### Output
|
|
||||||
|
|
||||||
| Parameter | Type | Description |
|
|
||||||
| --------- | ---- | ----------- |
|
|
||||||
| `items` | array | Array of available caption tracks for the video |
|
|
||||||
| ↳ `captionId` | string | Caption track ID |
|
|
||||||
| ↳ `language` | string | Language code of the caption \(e.g., |
|
|
||||||
| ↳ `name` | string | Name/label of the caption track |
|
|
||||||
| ↳ `trackKind` | string | Type of caption track: |
|
|
||||||
| ↳ `lastUpdated` | string | When the caption was last updated |
|
|
||||||
| ↳ `isCC` | boolean | Whether this is a closed caption track |
|
|
||||||
| ↳ `isAutoSynced` | boolean | Whether the caption timing was automatically synced |
|
|
||||||
| ↳ `audioTrackType` | string | Type of audio track this caption is for |
|
|
||||||
| `totalResults` | number | Total number of caption tracks available |
|
|
||||||
|
|
||||||
### `youtube_channel_info`
|
### `youtube_channel_info`
|
||||||
|
|
||||||
Get detailed information about a YouTube channel including statistics, branding, and content details.
|
Get detailed information about a YouTube channel including statistics, branding, and content details.
|
||||||
|
|||||||
@@ -77,13 +77,65 @@ Retrieve a list of tickets from Zendesk with optional filtering
|
|||||||
| Parameter | Type | Description |
|
| Parameter | Type | Description |
|
||||||
| --------- | ---- | ----------- |
|
| --------- | ---- | ----------- |
|
||||||
| `tickets` | array | Array of ticket objects |
|
| `tickets` | array | Array of ticket objects |
|
||||||
|
| ↳ `id` | number | Automatically assigned ticket ID |
|
||||||
|
| ↳ `url` | string | API URL of the ticket |
|
||||||
|
| ↳ `external_id` | string | External ID for linking to external records |
|
||||||
|
| ↳ `via` | object | How the ticket was created |
|
||||||
|
| ↳ `channel` | string | Channel through which the ticket was created \(e.g., email, web, api\) |
|
||||||
|
| ↳ `source` | object | Source details for the channel |
|
||||||
|
| ↳ `from` | object | Information about the source sender |
|
||||||
|
| ↳ `address` | string | Email address or other identifier |
|
||||||
|
| ↳ `name` | string | Name of the sender |
|
||||||
|
| ↳ `to` | object | Information about the recipient |
|
||||||
|
| ↳ `address` | string | Email address or other identifier |
|
||||||
|
| ↳ `name` | string | Name of the recipient |
|
||||||
|
| ↳ `rel` | string | Relationship type |
|
||||||
|
| ↳ `created_at` | string | When the ticket was created \(ISO 8601 format\) |
|
||||||
|
| ↳ `updated_at` | string | When the ticket was last updated \(ISO 8601 format\) |
|
||||||
|
| ↳ `type` | string | Ticket type \(problem, incident, question, task\) |
|
||||||
|
| ↳ `subject` | string | Subject of the ticket |
|
||||||
|
| ↳ `raw_subject` | string | Subject of the ticket as entered by the requester |
|
||||||
|
| ↳ `description` | string | Read-only first comment on the ticket |
|
||||||
|
| ↳ `priority` | string | Priority level \(low, normal, high, urgent\) |
|
||||||
|
| ↳ `status` | string | Ticket status \(new, open, pending, hold, solved, closed\) |
|
||||||
|
| ↳ `recipient` | string | Original recipient email address |
|
||||||
|
| ↳ `requester_id` | number | User ID of the ticket requester |
|
||||||
|
| ↳ `submitter_id` | number | User ID of the ticket submitter |
|
||||||
|
| ↳ `assignee_id` | number | User ID of the agent assigned to the ticket |
|
||||||
|
| ↳ `organization_id` | number | Organization ID of the requester |
|
||||||
|
| ↳ `group_id` | number | Group ID assigned to the ticket |
|
||||||
|
| ↳ `collaborator_ids` | array | User IDs of collaborators \(CC\) |
|
||||||
|
| ↳ `follower_ids` | array | User IDs of followers |
|
||||||
|
| ↳ `email_cc_ids` | array | User IDs of email CCs |
|
||||||
|
| ↳ `forum_topic_id` | number | Topic ID in the community forum |
|
||||||
|
| ↳ `problem_id` | number | For incident tickets, the ID of the associated problem ticket |
|
||||||
|
| ↳ `has_incidents` | boolean | Whether the ticket has incident tickets linked |
|
||||||
|
| ↳ `is_public` | boolean | Whether the first comment is public |
|
||||||
|
| ↳ `due_at` | string | Due date for task tickets \(ISO 8601 format\) |
|
||||||
|
| ↳ `tags` | array | Tags associated with the ticket |
|
||||||
|
| ↳ `custom_fields` | array | Custom ticket fields |
|
||||||
|
| ↳ `id` | number | Custom field ID |
|
||||||
|
| ↳ `value` | string | Custom field value |
|
||||||
|
| ↳ `custom_status_id` | number | Custom status ID |
|
||||||
|
| ↳ `satisfaction_rating` | object | Customer satisfaction rating |
|
||||||
|
| ↳ `id` | number | Satisfaction rating ID |
|
||||||
|
| ↳ `score` | string | Rating score \(e.g., good, bad, offered, unoffered\) |
|
||||||
|
| ↳ `comment` | string | Comment left with the rating |
|
||||||
|
| ↳ `sharing_agreement_ids` | array | Sharing agreement IDs |
|
||||||
|
| ↳ `followup_ids` | array | IDs of follow-up tickets |
|
||||||
|
| ↳ `brand_id` | number | Brand ID the ticket belongs to |
|
||||||
|
| ↳ `allow_attachments` | boolean | Whether attachments are allowed |
|
||||||
|
| ↳ `allow_channelback` | boolean | Whether channelback is enabled |
|
||||||
|
| ↳ `from_messaging_channel` | boolean | Whether the ticket originated from a messaging channel |
|
||||||
|
| ↳ `ticket_form_id` | number | Ticket form ID |
|
||||||
|
| ↳ `generated_timestamp` | number | Unix timestamp of the ticket generation |
|
||||||
| `paging` | object | Pagination information |
|
| `paging` | object | Pagination information |
|
||||||
| ↳ `next_page` | string | URL for next page of results |
|
| ↳ `next_page` | string | URL for next page of results |
|
||||||
| ↳ `previous_page` | string | URL for previous page of results |
|
| ↳ `previous_page` | string | URL for previous page of results |
|
||||||
| ↳ `count` | number | Total count of tickets |
|
| ↳ `count` | number | Total count of items |
|
||||||
| `metadata` | object | Response metadata |
|
| `metadata` | object | Response metadata |
|
||||||
| ↳ `total_returned` | number | Number of tickets returned in this response |
|
| ↳ `total_returned` | number | Number of items returned in this response |
|
||||||
| ↳ `has_more` | boolean | Whether more tickets are available |
|
| ↳ `has_more` | boolean | Whether more items are available |
|
||||||
|
|
||||||
### `zendesk_get_ticket`
|
### `zendesk_get_ticket`
|
||||||
|
|
||||||
@@ -103,6 +155,58 @@ Get a single ticket by ID from Zendesk
|
|||||||
| Parameter | Type | Description |
|
| Parameter | Type | Description |
|
||||||
| --------- | ---- | ----------- |
|
| --------- | ---- | ----------- |
|
||||||
| `ticket` | object | Ticket object |
|
| `ticket` | object | Ticket object |
|
||||||
|
| ↳ `id` | number | Automatically assigned ticket ID |
|
||||||
|
| ↳ `url` | string | API URL of the ticket |
|
||||||
|
| ↳ `external_id` | string | External ID for linking to external records |
|
||||||
|
| ↳ `via` | object | How the ticket was created |
|
||||||
|
| ↳ `channel` | string | Channel through which the ticket was created \(e.g., email, web, api\) |
|
||||||
|
| ↳ `source` | object | Source details for the channel |
|
||||||
|
| ↳ `from` | object | Information about the source sender |
|
||||||
|
| ↳ `address` | string | Email address or other identifier |
|
||||||
|
| ↳ `name` | string | Name of the sender |
|
||||||
|
| ↳ `to` | object | Information about the recipient |
|
||||||
|
| ↳ `address` | string | Email address or other identifier |
|
||||||
|
| ↳ `name` | string | Name of the recipient |
|
||||||
|
| ↳ `rel` | string | Relationship type |
|
||||||
|
| ↳ `created_at` | string | When the ticket was created \(ISO 8601 format\) |
|
||||||
|
| ↳ `updated_at` | string | When the ticket was last updated \(ISO 8601 format\) |
|
||||||
|
| ↳ `type` | string | Ticket type \(problem, incident, question, task\) |
|
||||||
|
| ↳ `subject` | string | Subject of the ticket |
|
||||||
|
| ↳ `raw_subject` | string | Subject of the ticket as entered by the requester |
|
||||||
|
| ↳ `description` | string | Read-only first comment on the ticket |
|
||||||
|
| ↳ `priority` | string | Priority level \(low, normal, high, urgent\) |
|
||||||
|
| ↳ `status` | string | Ticket status \(new, open, pending, hold, solved, closed\) |
|
||||||
|
| ↳ `recipient` | string | Original recipient email address |
|
||||||
|
| ↳ `requester_id` | number | User ID of the ticket requester |
|
||||||
|
| ↳ `submitter_id` | number | User ID of the ticket submitter |
|
||||||
|
| ↳ `assignee_id` | number | User ID of the agent assigned to the ticket |
|
||||||
|
| ↳ `organization_id` | number | Organization ID of the requester |
|
||||||
|
| ↳ `group_id` | number | Group ID assigned to the ticket |
|
||||||
|
| ↳ `collaborator_ids` | array | User IDs of collaborators \(CC\) |
|
||||||
|
| ↳ `follower_ids` | array | User IDs of followers |
|
||||||
|
| ↳ `email_cc_ids` | array | User IDs of email CCs |
|
||||||
|
| ↳ `forum_topic_id` | number | Topic ID in the community forum |
|
||||||
|
| ↳ `problem_id` | number | For incident tickets, the ID of the associated problem ticket |
|
||||||
|
| ↳ `has_incidents` | boolean | Whether the ticket has incident tickets linked |
|
||||||
|
| ↳ `is_public` | boolean | Whether the first comment is public |
|
||||||
|
| ↳ `due_at` | string | Due date for task tickets \(ISO 8601 format\) |
|
||||||
|
| ↳ `tags` | array | Tags associated with the ticket |
|
||||||
|
| ↳ `custom_fields` | array | Custom ticket fields |
|
||||||
|
| ↳ `id` | number | Custom field ID |
|
||||||
|
| ↳ `value` | string | Custom field value |
|
||||||
|
| ↳ `custom_status_id` | number | Custom status ID |
|
||||||
|
| ↳ `satisfaction_rating` | object | Customer satisfaction rating |
|
||||||
|
| ↳ `id` | number | Satisfaction rating ID |
|
||||||
|
| ↳ `score` | string | Rating score \(e.g., good, bad, offered, unoffered\) |
|
||||||
|
| ↳ `comment` | string | Comment left with the rating |
|
||||||
|
| ↳ `sharing_agreement_ids` | array | Sharing agreement IDs |
|
||||||
|
| ↳ `followup_ids` | array | IDs of follow-up tickets |
|
||||||
|
| ↳ `brand_id` | number | Brand ID the ticket belongs to |
|
||||||
|
| ↳ `allow_attachments` | boolean | Whether attachments are allowed |
|
||||||
|
| ↳ `allow_channelback` | boolean | Whether channelback is enabled |
|
||||||
|
| ↳ `from_messaging_channel` | boolean | Whether the ticket originated from a messaging channel |
|
||||||
|
| ↳ `ticket_form_id` | number | Ticket form ID |
|
||||||
|
| ↳ `generated_timestamp` | number | Unix timestamp of the ticket generation |
|
||||||
| `ticket_id` | number | The ticket ID |
|
| `ticket_id` | number | The ticket ID |
|
||||||
|
|
||||||
### `zendesk_create_ticket`
|
### `zendesk_create_ticket`
|
||||||
@@ -132,6 +236,58 @@ Create a new ticket in Zendesk with support for custom fields
|
|||||||
| Parameter | Type | Description |
|
| Parameter | Type | Description |
|
||||||
| --------- | ---- | ----------- |
|
| --------- | ---- | ----------- |
|
||||||
| `ticket` | object | Created ticket object |
|
| `ticket` | object | Created ticket object |
|
||||||
|
| ↳ `id` | number | Automatically assigned ticket ID |
|
||||||
|
| ↳ `url` | string | API URL of the ticket |
|
||||||
|
| ↳ `external_id` | string | External ID for linking to external records |
|
||||||
|
| ↳ `via` | object | How the ticket was created |
|
||||||
|
| ↳ `channel` | string | Channel through which the ticket was created \(e.g., email, web, api\) |
|
||||||
|
| ↳ `source` | object | Source details for the channel |
|
||||||
|
| ↳ `from` | object | Information about the source sender |
|
||||||
|
| ↳ `address` | string | Email address or other identifier |
|
||||||
|
| ↳ `name` | string | Name of the sender |
|
||||||
|
| ↳ `to` | object | Information about the recipient |
|
||||||
|
| ↳ `address` | string | Email address or other identifier |
|
||||||
|
| ↳ `name` | string | Name of the recipient |
|
||||||
|
| ↳ `rel` | string | Relationship type |
|
||||||
|
| ↳ `created_at` | string | When the ticket was created \(ISO 8601 format\) |
|
||||||
|
| ↳ `updated_at` | string | When the ticket was last updated \(ISO 8601 format\) |
|
||||||
|
| ↳ `type` | string | Ticket type \(problem, incident, question, task\) |
|
||||||
|
| ↳ `subject` | string | Subject of the ticket |
|
||||||
|
| ↳ `raw_subject` | string | Subject of the ticket as entered by the requester |
|
||||||
|
| ↳ `description` | string | Read-only first comment on the ticket |
|
||||||
|
| ↳ `priority` | string | Priority level \(low, normal, high, urgent\) |
|
||||||
|
| ↳ `status` | string | Ticket status \(new, open, pending, hold, solved, closed\) |
|
||||||
|
| ↳ `recipient` | string | Original recipient email address |
|
||||||
|
| ↳ `requester_id` | number | User ID of the ticket requester |
|
||||||
|
| ↳ `submitter_id` | number | User ID of the ticket submitter |
|
||||||
|
| ↳ `assignee_id` | number | User ID of the agent assigned to the ticket |
|
||||||
|
| ↳ `organization_id` | number | Organization ID of the requester |
|
||||||
|
| ↳ `group_id` | number | Group ID assigned to the ticket |
|
||||||
|
| ↳ `collaborator_ids` | array | User IDs of collaborators \(CC\) |
|
||||||
|
| ↳ `follower_ids` | array | User IDs of followers |
|
||||||
|
| ↳ `email_cc_ids` | array | User IDs of email CCs |
|
||||||
|
| ↳ `forum_topic_id` | number | Topic ID in the community forum |
|
||||||
|
| ↳ `problem_id` | number | For incident tickets, the ID of the associated problem ticket |
|
||||||
|
| ↳ `has_incidents` | boolean | Whether the ticket has incident tickets linked |
|
||||||
|
| ↳ `is_public` | boolean | Whether the first comment is public |
|
||||||
|
| ↳ `due_at` | string | Due date for task tickets \(ISO 8601 format\) |
|
||||||
|
| ↳ `tags` | array | Tags associated with the ticket |
|
||||||
|
| ↳ `custom_fields` | array | Custom ticket fields |
|
||||||
|
| ↳ `id` | number | Custom field ID |
|
||||||
|
| ↳ `value` | string | Custom field value |
|
||||||
|
| ↳ `custom_status_id` | number | Custom status ID |
|
||||||
|
| ↳ `satisfaction_rating` | object | Customer satisfaction rating |
|
||||||
|
| ↳ `id` | number | Satisfaction rating ID |
|
||||||
|
| ↳ `score` | string | Rating score \(e.g., good, bad, offered, unoffered\) |
|
||||||
|
| ↳ `comment` | string | Comment left with the rating |
|
||||||
|
| ↳ `sharing_agreement_ids` | array | Sharing agreement IDs |
|
||||||
|
| ↳ `followup_ids` | array | IDs of follow-up tickets |
|
||||||
|
| ↳ `brand_id` | number | Brand ID the ticket belongs to |
|
||||||
|
| ↳ `allow_attachments` | boolean | Whether attachments are allowed |
|
||||||
|
| ↳ `allow_channelback` | boolean | Whether channelback is enabled |
|
||||||
|
| ↳ `from_messaging_channel` | boolean | Whether the ticket originated from a messaging channel |
|
||||||
|
| ↳ `ticket_form_id` | number | Ticket form ID |
|
||||||
|
| ↳ `generated_timestamp` | number | Unix timestamp of the ticket generation |
|
||||||
| `ticket_id` | number | The created ticket ID |
|
| `ticket_id` | number | The created ticket ID |
|
||||||
|
|
||||||
### `zendesk_create_tickets_bulk`
|
### `zendesk_create_tickets_bulk`
|
||||||
@@ -151,7 +307,21 @@ Create multiple tickets in Zendesk at once (max 100)
|
|||||||
|
|
||||||
| Parameter | Type | Description |
|
| Parameter | Type | Description |
|
||||||
| --------- | ---- | ----------- |
|
| --------- | ---- | ----------- |
|
||||||
| `job_status` | object | Job status object |
|
| `job_status` | object | Job status object for bulk operations |
|
||||||
|
| ↳ `id` | string | Automatically assigned job ID |
|
||||||
|
| ↳ `url` | string | URL to poll for status updates |
|
||||||
|
| ↳ `status` | string | Current job status \(queued, working, failed, completed\) |
|
||||||
|
| ↳ `job_type` | string | Category of background task |
|
||||||
|
| ↳ `total` | number | Total number of tasks in this job |
|
||||||
|
| ↳ `progress` | number | Number of tasks already completed |
|
||||||
|
| ↳ `message` | string | Message from the job worker |
|
||||||
|
| ↳ `results` | array | Array of result objects from the job |
|
||||||
|
| ↳ `id` | number | ID of the created or updated resource |
|
||||||
|
| ↳ `index` | number | Position of the result in the batch |
|
||||||
|
| ↳ `action` | string | Action performed \(e.g., create, update\) |
|
||||||
|
| ↳ `success` | boolean | Whether the operation succeeded |
|
||||||
|
| ↳ `status` | string | Status message \(e.g., Updated, Created\) |
|
||||||
|
| ↳ `error` | string | Error message if operation failed |
|
||||||
| `job_id` | string | The bulk operation job ID |
|
| `job_id` | string | The bulk operation job ID |
|
||||||
|
|
||||||
### `zendesk_update_ticket`
|
### `zendesk_update_ticket`
|
||||||
@@ -181,6 +351,58 @@ Update an existing ticket in Zendesk with support for custom fields
|
|||||||
| Parameter | Type | Description |
|
| Parameter | Type | Description |
|
||||||
| --------- | ---- | ----------- |
|
| --------- | ---- | ----------- |
|
||||||
| `ticket` | object | Updated ticket object |
|
| `ticket` | object | Updated ticket object |
|
||||||
|
| ↳ `id` | number | Automatically assigned ticket ID |
|
||||||
|
| ↳ `url` | string | API URL of the ticket |
|
||||||
|
| ↳ `external_id` | string | External ID for linking to external records |
|
||||||
|
| ↳ `via` | object | How the ticket was created |
|
||||||
|
| ↳ `channel` | string | Channel through which the ticket was created \(e.g., email, web, api\) |
|
||||||
|
| ↳ `source` | object | Source details for the channel |
|
||||||
|
| ↳ `from` | object | Information about the source sender |
|
||||||
|
| ↳ `address` | string | Email address or other identifier |
|
||||||
|
| ↳ `name` | string | Name of the sender |
|
||||||
|
| ↳ `to` | object | Information about the recipient |
|
||||||
|
| ↳ `address` | string | Email address or other identifier |
|
||||||
|
| ↳ `name` | string | Name of the recipient |
|
||||||
|
| ↳ `rel` | string | Relationship type |
|
||||||
|
| ↳ `created_at` | string | When the ticket was created \(ISO 8601 format\) |
|
||||||
|
| ↳ `updated_at` | string | When the ticket was last updated \(ISO 8601 format\) |
|
||||||
|
| ↳ `type` | string | Ticket type \(problem, incident, question, task\) |
|
||||||
|
| ↳ `subject` | string | Subject of the ticket |
|
||||||
|
| ↳ `raw_subject` | string | Subject of the ticket as entered by the requester |
|
||||||
|
| ↳ `description` | string | Read-only first comment on the ticket |
|
||||||
|
| ↳ `priority` | string | Priority level \(low, normal, high, urgent\) |
|
||||||
|
| ↳ `status` | string | Ticket status \(new, open, pending, hold, solved, closed\) |
|
||||||
|
| ↳ `recipient` | string | Original recipient email address |
|
||||||
|
| ↳ `requester_id` | number | User ID of the ticket requester |
|
||||||
|
| ↳ `submitter_id` | number | User ID of the ticket submitter |
|
||||||
|
| ↳ `assignee_id` | number | User ID of the agent assigned to the ticket |
|
||||||
|
| ↳ `organization_id` | number | Organization ID of the requester |
|
||||||
|
| ↳ `group_id` | number | Group ID assigned to the ticket |
|
||||||
|
| ↳ `collaborator_ids` | array | User IDs of collaborators \(CC\) |
|
||||||
|
| ↳ `follower_ids` | array | User IDs of followers |
|
||||||
|
| ↳ `email_cc_ids` | array | User IDs of email CCs |
|
||||||
|
| ↳ `forum_topic_id` | number | Topic ID in the community forum |
|
||||||
|
| ↳ `problem_id` | number | For incident tickets, the ID of the associated problem ticket |
|
||||||
|
| ↳ `has_incidents` | boolean | Whether the ticket has incident tickets linked |
|
||||||
|
| ↳ `is_public` | boolean | Whether the first comment is public |
|
||||||
|
| ↳ `due_at` | string | Due date for task tickets \(ISO 8601 format\) |
|
||||||
|
| ↳ `tags` | array | Tags associated with the ticket |
|
||||||
|
| ↳ `custom_fields` | array | Custom ticket fields |
|
||||||
|
| ↳ `id` | number | Custom field ID |
|
||||||
|
| ↳ `value` | string | Custom field value |
|
||||||
|
| ↳ `custom_status_id` | number | Custom status ID |
|
||||||
|
| ↳ `satisfaction_rating` | object | Customer satisfaction rating |
|
||||||
|
| ↳ `id` | number | Satisfaction rating ID |
|
||||||
|
| ↳ `score` | string | Rating score \(e.g., good, bad, offered, unoffered\) |
|
||||||
|
| ↳ `comment` | string | Comment left with the rating |
|
||||||
|
| ↳ `sharing_agreement_ids` | array | Sharing agreement IDs |
|
||||||
|
| ↳ `followup_ids` | array | IDs of follow-up tickets |
|
||||||
|
| ↳ `brand_id` | number | Brand ID the ticket belongs to |
|
||||||
|
| ↳ `allow_attachments` | boolean | Whether attachments are allowed |
|
||||||
|
| ↳ `allow_channelback` | boolean | Whether channelback is enabled |
|
||||||
|
| ↳ `from_messaging_channel` | boolean | Whether the ticket originated from a messaging channel |
|
||||||
|
| ↳ `ticket_form_id` | number | Ticket form ID |
|
||||||
|
| ↳ `generated_timestamp` | number | Unix timestamp of the ticket generation |
|
||||||
| `ticket_id` | number | The updated ticket ID |
|
| `ticket_id` | number | The updated ticket ID |
|
||||||
|
|
||||||
### `zendesk_update_tickets_bulk`
|
### `zendesk_update_tickets_bulk`
|
||||||
@@ -205,7 +427,21 @@ Update multiple tickets in Zendesk at once (max 100)
|
|||||||
|
|
||||||
| Parameter | Type | Description |
|
| Parameter | Type | Description |
|
||||||
| --------- | ---- | ----------- |
|
| --------- | ---- | ----------- |
|
||||||
| `job_status` | object | Job status object |
|
| `job_status` | object | Job status object for bulk operations |
|
||||||
|
| ↳ `id` | string | Automatically assigned job ID |
|
||||||
|
| ↳ `url` | string | URL to poll for status updates |
|
||||||
|
| ↳ `status` | string | Current job status \(queued, working, failed, completed\) |
|
||||||
|
| ↳ `job_type` | string | Category of background task |
|
||||||
|
| ↳ `total` | number | Total number of tasks in this job |
|
||||||
|
| ↳ `progress` | number | Number of tasks already completed |
|
||||||
|
| ↳ `message` | string | Message from the job worker |
|
||||||
|
| ↳ `results` | array | Array of result objects from the job |
|
||||||
|
| ↳ `id` | number | ID of the created or updated resource |
|
||||||
|
| ↳ `index` | number | Position of the result in the batch |
|
||||||
|
| ↳ `action` | string | Action performed \(e.g., create, update\) |
|
||||||
|
| ↳ `success` | boolean | Whether the operation succeeded |
|
||||||
|
| ↳ `status` | string | Status message \(e.g., Updated, Created\) |
|
||||||
|
| ↳ `error` | string | Error message if operation failed |
|
||||||
| `job_id` | string | The bulk operation job ID |
|
| `job_id` | string | The bulk operation job ID |
|
||||||
|
|
||||||
### `zendesk_delete_ticket`
|
### `zendesk_delete_ticket`
|
||||||
@@ -247,7 +483,21 @@ Merge multiple tickets into a target ticket
|
|||||||
|
|
||||||
| Parameter | Type | Description |
|
| Parameter | Type | Description |
|
||||||
| --------- | ---- | ----------- |
|
| --------- | ---- | ----------- |
|
||||||
| `job_status` | object | Job status object |
|
| `job_status` | object | Job status object for bulk operations |
|
||||||
|
| ↳ `id` | string | Automatically assigned job ID |
|
||||||
|
| ↳ `url` | string | URL to poll for status updates |
|
||||||
|
| ↳ `status` | string | Current job status \(queued, working, failed, completed\) |
|
||||||
|
| ↳ `job_type` | string | Category of background task |
|
||||||
|
| ↳ `total` | number | Total number of tasks in this job |
|
||||||
|
| ↳ `progress` | number | Number of tasks already completed |
|
||||||
|
| ↳ `message` | string | Message from the job worker |
|
||||||
|
| ↳ `results` | array | Array of result objects from the job |
|
||||||
|
| ↳ `id` | number | ID of the created or updated resource |
|
||||||
|
| ↳ `index` | number | Position of the result in the batch |
|
||||||
|
| ↳ `action` | string | Action performed \(e.g., create, update\) |
|
||||||
|
| ↳ `success` | boolean | Whether the operation succeeded |
|
||||||
|
| ↳ `status` | string | Status message \(e.g., Updated, Created\) |
|
||||||
|
| ↳ `error` | string | Error message if operation failed |
|
||||||
| `job_id` | string | The merge job ID |
|
| `job_id` | string | The merge job ID |
|
||||||
| `target_ticket_id` | string | The target ticket ID that tickets were merged into |
|
| `target_ticket_id` | string | The target ticket ID that tickets were merged into |
|
||||||
|
|
||||||
@@ -272,13 +522,54 @@ Retrieve a list of users from Zendesk with optional filtering
|
|||||||
| Parameter | Type | Description |
|
| Parameter | Type | Description |
|
||||||
| --------- | ---- | ----------- |
|
| --------- | ---- | ----------- |
|
||||||
| `users` | array | Array of user objects |
|
| `users` | array | Array of user objects |
|
||||||
|
| ↳ `id` | number | Automatically assigned user ID |
|
||||||
|
| ↳ `url` | string | API URL of the user |
|
||||||
|
| ↳ `name` | string | User name |
|
||||||
|
| ↳ `email` | string | Primary email address |
|
||||||
|
| ↳ `created_at` | string | When the user was created \(ISO 8601 format\) |
|
||||||
|
| ↳ `updated_at` | string | When the user was last updated \(ISO 8601 format\) |
|
||||||
|
| ↳ `time_zone` | string | Time zone \(e.g., Eastern Time \(US & Canada\)\) |
|
||||||
|
| ↳ `iana_time_zone` | string | IANA time zone \(e.g., America/New_York\) |
|
||||||
|
| ↳ `phone` | string | Phone number |
|
||||||
|
| ↳ `shared_phone_number` | boolean | Whether the phone number is shared |
|
||||||
|
| ↳ `photo` | object | User photo details |
|
||||||
|
| ↳ `content_url` | string | URL to the photo |
|
||||||
|
| ↳ `file_name` | string | Photo file name |
|
||||||
|
| ↳ `size` | number | File size in bytes |
|
||||||
|
| ↳ `locale` | string | Locale \(e.g., en-US\) |
|
||||||
|
| ↳ `locale_id` | number | Locale ID |
|
||||||
|
| ↳ `organization_id` | number | Primary organization ID |
|
||||||
|
| ↳ `role` | string | User role \(end-user, agent, admin\) |
|
||||||
|
| ↳ `role_type` | number | Role type identifier |
|
||||||
|
| ↳ `custom_role_id` | number | Custom role ID |
|
||||||
|
| ↳ `active` | boolean | Whether the user is active \(false if deleted\) |
|
||||||
|
| ↳ `verified` | boolean | Whether any user identity has been verified |
|
||||||
|
| ↳ `alias` | string | Alias displayed to end users |
|
||||||
|
| ↳ `details` | string | Details about the user |
|
||||||
|
| ↳ `notes` | string | Notes about the user |
|
||||||
|
| ↳ `signature` | string | User signature for email replies |
|
||||||
|
| ↳ `default_group_id` | number | Default group ID for the user |
|
||||||
|
| ↳ `tags` | array | Tags associated with the user |
|
||||||
|
| ↳ `external_id` | string | External ID for linking to external records |
|
||||||
|
| ↳ `restricted_agent` | boolean | Whether the agent has restrictions |
|
||||||
|
| ↳ `suspended` | boolean | Whether the user is suspended |
|
||||||
|
| ↳ `moderator` | boolean | Whether the user has moderator permissions |
|
||||||
|
| ↳ `chat_only` | boolean | Whether the user is a chat-only agent |
|
||||||
|
| ↳ `only_private_comments` | boolean | Whether the user can only create private comments |
|
||||||
|
| ↳ `two_factor_auth_enabled` | boolean | Whether two-factor auth is enabled |
|
||||||
|
| ↳ `last_login_at` | string | Last login time \(ISO 8601 format\) |
|
||||||
|
| ↳ `ticket_restriction` | string | Ticket access restriction \(organization, groups, assigned, requested\) |
|
||||||
|
| ↳ `user_fields` | json | Custom user fields \(dynamic key-value pairs\) |
|
||||||
|
| ↳ `shared` | boolean | Whether the user is shared from a different Zendesk |
|
||||||
|
| ↳ `shared_agent` | boolean | Whether the agent is shared from a different Zendesk |
|
||||||
|
| ↳ `remote_photo_url` | string | URL to a remote photo |
|
||||||
| `paging` | object | Pagination information |
|
| `paging` | object | Pagination information |
|
||||||
| ↳ `next_page` | string | URL for next page of results |
|
| ↳ `next_page` | string | URL for next page of results |
|
||||||
| ↳ `previous_page` | string | URL for previous page of results |
|
| ↳ `previous_page` | string | URL for previous page of results |
|
||||||
| ↳ `count` | number | Total count of users |
|
| ↳ `count` | number | Total count of items |
|
||||||
| `metadata` | object | Response metadata |
|
| `metadata` | object | Response metadata |
|
||||||
| ↳ `total_returned` | number | Number of users returned in this response |
|
| ↳ `total_returned` | number | Number of items returned in this response |
|
||||||
| ↳ `has_more` | boolean | Whether more users are available |
|
| ↳ `has_more` | boolean | Whether more items are available |
|
||||||
|
|
||||||
### `zendesk_get_user`
|
### `zendesk_get_user`
|
||||||
|
|
||||||
@@ -298,6 +589,47 @@ Get a single user by ID from Zendesk
|
|||||||
| Parameter | Type | Description |
|
| Parameter | Type | Description |
|
||||||
| --------- | ---- | ----------- |
|
| --------- | ---- | ----------- |
|
||||||
| `user` | object | User object |
|
| `user` | object | User object |
|
||||||
|
| ↳ `id` | number | Automatically assigned user ID |
|
||||||
|
| ↳ `url` | string | API URL of the user |
|
||||||
|
| ↳ `name` | string | User name |
|
||||||
|
| ↳ `email` | string | Primary email address |
|
||||||
|
| ↳ `created_at` | string | When the user was created \(ISO 8601 format\) |
|
||||||
|
| ↳ `updated_at` | string | When the user was last updated \(ISO 8601 format\) |
|
||||||
|
| ↳ `time_zone` | string | Time zone \(e.g., Eastern Time \(US & Canada\)\) |
|
||||||
|
| ↳ `iana_time_zone` | string | IANA time zone \(e.g., America/New_York\) |
|
||||||
|
| ↳ `phone` | string | Phone number |
|
||||||
|
| ↳ `shared_phone_number` | boolean | Whether the phone number is shared |
|
||||||
|
| ↳ `photo` | object | User photo details |
|
||||||
|
| ↳ `content_url` | string | URL to the photo |
|
||||||
|
| ↳ `file_name` | string | Photo file name |
|
||||||
|
| ↳ `size` | number | File size in bytes |
|
||||||
|
| ↳ `locale` | string | Locale \(e.g., en-US\) |
|
||||||
|
| ↳ `locale_id` | number | Locale ID |
|
||||||
|
| ↳ `organization_id` | number | Primary organization ID |
|
||||||
|
| ↳ `role` | string | User role \(end-user, agent, admin\) |
|
||||||
|
| ↳ `role_type` | number | Role type identifier |
|
||||||
|
| ↳ `custom_role_id` | number | Custom role ID |
|
||||||
|
| ↳ `active` | boolean | Whether the user is active \(false if deleted\) |
|
||||||
|
| ↳ `verified` | boolean | Whether any user identity has been verified |
|
||||||
|
| ↳ `alias` | string | Alias displayed to end users |
|
||||||
|
| ↳ `details` | string | Details about the user |
|
||||||
|
| ↳ `notes` | string | Notes about the user |
|
||||||
|
| ↳ `signature` | string | User signature for email replies |
|
||||||
|
| ↳ `default_group_id` | number | Default group ID for the user |
|
||||||
|
| ↳ `tags` | array | Tags associated with the user |
|
||||||
|
| ↳ `external_id` | string | External ID for linking to external records |
|
||||||
|
| ↳ `restricted_agent` | boolean | Whether the agent has restrictions |
|
||||||
|
| ↳ `suspended` | boolean | Whether the user is suspended |
|
||||||
|
| ↳ `moderator` | boolean | Whether the user has moderator permissions |
|
||||||
|
| ↳ `chat_only` | boolean | Whether the user is a chat-only agent |
|
||||||
|
| ↳ `only_private_comments` | boolean | Whether the user can only create private comments |
|
||||||
|
| ↳ `two_factor_auth_enabled` | boolean | Whether two-factor auth is enabled |
|
||||||
|
| ↳ `last_login_at` | string | Last login time \(ISO 8601 format\) |
|
||||||
|
| ↳ `ticket_restriction` | string | Ticket access restriction \(organization, groups, assigned, requested\) |
|
||||||
|
| ↳ `user_fields` | json | Custom user fields \(dynamic key-value pairs\) |
|
||||||
|
| ↳ `shared` | boolean | Whether the user is shared from a different Zendesk |
|
||||||
|
| ↳ `shared_agent` | boolean | Whether the agent is shared from a different Zendesk |
|
||||||
|
| ↳ `remote_photo_url` | string | URL to a remote photo |
|
||||||
| `user_id` | number | The user ID |
|
| `user_id` | number | The user ID |
|
||||||
|
|
||||||
### `zendesk_get_current_user`
|
### `zendesk_get_current_user`
|
||||||
@@ -317,6 +649,47 @@ Get the currently authenticated user from Zendesk
|
|||||||
| Parameter | Type | Description |
|
| Parameter | Type | Description |
|
||||||
| --------- | ---- | ----------- |
|
| --------- | ---- | ----------- |
|
||||||
| `user` | object | Current user object |
|
| `user` | object | Current user object |
|
||||||
|
| ↳ `id` | number | Automatically assigned user ID |
|
||||||
|
| ↳ `url` | string | API URL of the user |
|
||||||
|
| ↳ `name` | string | User name |
|
||||||
|
| ↳ `email` | string | Primary email address |
|
||||||
|
| ↳ `created_at` | string | When the user was created \(ISO 8601 format\) |
|
||||||
|
| ↳ `updated_at` | string | When the user was last updated \(ISO 8601 format\) |
|
||||||
|
| ↳ `time_zone` | string | Time zone \(e.g., Eastern Time \(US & Canada\)\) |
|
||||||
|
| ↳ `iana_time_zone` | string | IANA time zone \(e.g., America/New_York\) |
|
||||||
|
| ↳ `phone` | string | Phone number |
|
||||||
|
| ↳ `shared_phone_number` | boolean | Whether the phone number is shared |
|
||||||
|
| ↳ `photo` | object | User photo details |
|
||||||
|
| ↳ `content_url` | string | URL to the photo |
|
||||||
|
| ↳ `file_name` | string | Photo file name |
|
||||||
|
| ↳ `size` | number | File size in bytes |
|
||||||
|
| ↳ `locale` | string | Locale \(e.g., en-US\) |
|
||||||
|
| ↳ `locale_id` | number | Locale ID |
|
||||||
|
| ↳ `organization_id` | number | Primary organization ID |
|
||||||
|
| ↳ `role` | string | User role \(end-user, agent, admin\) |
|
||||||
|
| ↳ `role_type` | number | Role type identifier |
|
||||||
|
| ↳ `custom_role_id` | number | Custom role ID |
|
||||||
|
| ↳ `active` | boolean | Whether the user is active \(false if deleted\) |
|
||||||
|
| ↳ `verified` | boolean | Whether any user identity has been verified |
|
||||||
|
| ↳ `alias` | string | Alias displayed to end users |
|
||||||
|
| ↳ `details` | string | Details about the user |
|
||||||
|
| ↳ `notes` | string | Notes about the user |
|
||||||
|
| ↳ `signature` | string | User signature for email replies |
|
||||||
|
| ↳ `default_group_id` | number | Default group ID for the user |
|
||||||
|
| ↳ `tags` | array | Tags associated with the user |
|
||||||
|
| ↳ `external_id` | string | External ID for linking to external records |
|
||||||
|
| ↳ `restricted_agent` | boolean | Whether the agent has restrictions |
|
||||||
|
| ↳ `suspended` | boolean | Whether the user is suspended |
|
||||||
|
| ↳ `moderator` | boolean | Whether the user has moderator permissions |
|
||||||
|
| ↳ `chat_only` | boolean | Whether the user is a chat-only agent |
|
||||||
|
| ↳ `only_private_comments` | boolean | Whether the user can only create private comments |
|
||||||
|
| ↳ `two_factor_auth_enabled` | boolean | Whether two-factor auth is enabled |
|
||||||
|
| ↳ `last_login_at` | string | Last login time \(ISO 8601 format\) |
|
||||||
|
| ↳ `ticket_restriction` | string | Ticket access restriction \(organization, groups, assigned, requested\) |
|
||||||
|
| ↳ `user_fields` | json | Custom user fields \(dynamic key-value pairs\) |
|
||||||
|
| ↳ `shared` | boolean | Whether the user is shared from a different Zendesk |
|
||||||
|
| ↳ `shared_agent` | boolean | Whether the agent is shared from a different Zendesk |
|
||||||
|
| ↳ `remote_photo_url` | string | URL to a remote photo |
|
||||||
| `user_id` | number | The current user ID |
|
| `user_id` | number | The current user ID |
|
||||||
|
|
||||||
### `zendesk_search_users`
|
### `zendesk_search_users`
|
||||||
@@ -340,13 +713,54 @@ Search for users in Zendesk using a query string
|
|||||||
| Parameter | Type | Description |
|
| Parameter | Type | Description |
|
||||||
| --------- | ---- | ----------- |
|
| --------- | ---- | ----------- |
|
||||||
| `users` | array | Array of user objects |
|
| `users` | array | Array of user objects |
|
||||||
|
| ↳ `id` | number | Automatically assigned user ID |
|
||||||
|
| ↳ `url` | string | API URL of the user |
|
||||||
|
| ↳ `name` | string | User name |
|
||||||
|
| ↳ `email` | string | Primary email address |
|
||||||
|
| ↳ `created_at` | string | When the user was created \(ISO 8601 format\) |
|
||||||
|
| ↳ `updated_at` | string | When the user was last updated \(ISO 8601 format\) |
|
||||||
|
| ↳ `time_zone` | string | Time zone \(e.g., Eastern Time \(US & Canada\)\) |
|
||||||
|
| ↳ `iana_time_zone` | string | IANA time zone \(e.g., America/New_York\) |
|
||||||
|
| ↳ `phone` | string | Phone number |
|
||||||
|
| ↳ `shared_phone_number` | boolean | Whether the phone number is shared |
|
||||||
|
| ↳ `photo` | object | User photo details |
|
||||||
|
| ↳ `content_url` | string | URL to the photo |
|
||||||
|
| ↳ `file_name` | string | Photo file name |
|
||||||
|
| ↳ `size` | number | File size in bytes |
|
||||||
|
| ↳ `locale` | string | Locale \(e.g., en-US\) |
|
||||||
|
| ↳ `locale_id` | number | Locale ID |
|
||||||
|
| ↳ `organization_id` | number | Primary organization ID |
|
||||||
|
| ↳ `role` | string | User role \(end-user, agent, admin\) |
|
||||||
|
| ↳ `role_type` | number | Role type identifier |
|
||||||
|
| ↳ `custom_role_id` | number | Custom role ID |
|
||||||
|
| ↳ `active` | boolean | Whether the user is active \(false if deleted\) |
|
||||||
|
| ↳ `verified` | boolean | Whether any user identity has been verified |
|
||||||
|
| ↳ `alias` | string | Alias displayed to end users |
|
||||||
|
| ↳ `details` | string | Details about the user |
|
||||||
|
| ↳ `notes` | string | Notes about the user |
|
||||||
|
| ↳ `signature` | string | User signature for email replies |
|
||||||
|
| ↳ `default_group_id` | number | Default group ID for the user |
|
||||||
|
| ↳ `tags` | array | Tags associated with the user |
|
||||||
|
| ↳ `external_id` | string | External ID for linking to external records |
|
||||||
|
| ↳ `restricted_agent` | boolean | Whether the agent has restrictions |
|
||||||
|
| ↳ `suspended` | boolean | Whether the user is suspended |
|
||||||
|
| ↳ `moderator` | boolean | Whether the user has moderator permissions |
|
||||||
|
| ↳ `chat_only` | boolean | Whether the user is a chat-only agent |
|
||||||
|
| ↳ `only_private_comments` | boolean | Whether the user can only create private comments |
|
||||||
|
| ↳ `two_factor_auth_enabled` | boolean | Whether two-factor auth is enabled |
|
||||||
|
| ↳ `last_login_at` | string | Last login time \(ISO 8601 format\) |
|
||||||
|
| ↳ `ticket_restriction` | string | Ticket access restriction \(organization, groups, assigned, requested\) |
|
||||||
|
| ↳ `user_fields` | json | Custom user fields \(dynamic key-value pairs\) |
|
||||||
|
| ↳ `shared` | boolean | Whether the user is shared from a different Zendesk |
|
||||||
|
| ↳ `shared_agent` | boolean | Whether the agent is shared from a different Zendesk |
|
||||||
|
| ↳ `remote_photo_url` | string | URL to a remote photo |
|
||||||
| `paging` | object | Pagination information |
|
| `paging` | object | Pagination information |
|
||||||
| ↳ `next_page` | string | URL for next page of results |
|
| ↳ `next_page` | string | URL for next page of results |
|
||||||
| ↳ `previous_page` | string | URL for previous page of results |
|
| ↳ `previous_page` | string | URL for previous page of results |
|
||||||
| ↳ `count` | number | Total count of users |
|
| ↳ `count` | number | Total count of items |
|
||||||
| `metadata` | object | Response metadata |
|
| `metadata` | object | Response metadata |
|
||||||
| ↳ `total_returned` | number | Number of users returned in this response |
|
| ↳ `total_returned` | number | Number of items returned in this response |
|
||||||
| ↳ `has_more` | boolean | Whether more users are available |
|
| ↳ `has_more` | boolean | Whether more items are available |
|
||||||
|
|
||||||
### `zendesk_create_user`
|
### `zendesk_create_user`
|
||||||
|
|
||||||
@@ -373,6 +787,47 @@ Create a new user in Zendesk
|
|||||||
| Parameter | Type | Description |
|
| Parameter | Type | Description |
|
||||||
| --------- | ---- | ----------- |
|
| --------- | ---- | ----------- |
|
||||||
| `user` | object | Created user object |
|
| `user` | object | Created user object |
|
||||||
|
| ↳ `id` | number | Automatically assigned user ID |
|
||||||
|
| ↳ `url` | string | API URL of the user |
|
||||||
|
| ↳ `name` | string | User name |
|
||||||
|
| ↳ `email` | string | Primary email address |
|
||||||
|
| ↳ `created_at` | string | When the user was created \(ISO 8601 format\) |
|
||||||
|
| ↳ `updated_at` | string | When the user was last updated \(ISO 8601 format\) |
|
||||||
|
| ↳ `time_zone` | string | Time zone \(e.g., Eastern Time \(US & Canada\)\) |
|
||||||
|
| ↳ `iana_time_zone` | string | IANA time zone \(e.g., America/New_York\) |
|
||||||
|
| ↳ `phone` | string | Phone number |
|
||||||
|
| ↳ `shared_phone_number` | boolean | Whether the phone number is shared |
|
||||||
|
| ↳ `photo` | object | User photo details |
|
||||||
|
| ↳ `content_url` | string | URL to the photo |
|
||||||
|
| ↳ `file_name` | string | Photo file name |
|
||||||
|
| ↳ `size` | number | File size in bytes |
|
||||||
|
| ↳ `locale` | string | Locale \(e.g., en-US\) |
|
||||||
|
| ↳ `locale_id` | number | Locale ID |
|
||||||
|
| ↳ `organization_id` | number | Primary organization ID |
|
||||||
|
| ↳ `role` | string | User role \(end-user, agent, admin\) |
|
||||||
|
| ↳ `role_type` | number | Role type identifier |
|
||||||
|
| ↳ `custom_role_id` | number | Custom role ID |
|
||||||
|
| ↳ `active` | boolean | Whether the user is active \(false if deleted\) |
|
||||||
|
| ↳ `verified` | boolean | Whether any user identity has been verified |
|
||||||
|
| ↳ `alias` | string | Alias displayed to end users |
|
||||||
|
| ↳ `details` | string | Details about the user |
|
||||||
|
| ↳ `notes` | string | Notes about the user |
|
||||||
|
| ↳ `signature` | string | User signature for email replies |
|
||||||
|
| ↳ `default_group_id` | number | Default group ID for the user |
|
||||||
|
| ↳ `tags` | array | Tags associated with the user |
|
||||||
|
| ↳ `external_id` | string | External ID for linking to external records |
|
||||||
|
| ↳ `restricted_agent` | boolean | Whether the agent has restrictions |
|
||||||
|
| ↳ `suspended` | boolean | Whether the user is suspended |
|
||||||
|
| ↳ `moderator` | boolean | Whether the user has moderator permissions |
|
||||||
|
| ↳ `chat_only` | boolean | Whether the user is a chat-only agent |
|
||||||
|
| ↳ `only_private_comments` | boolean | Whether the user can only create private comments |
|
||||||
|
| ↳ `two_factor_auth_enabled` | boolean | Whether two-factor auth is enabled |
|
||||||
|
| ↳ `last_login_at` | string | Last login time \(ISO 8601 format\) |
|
||||||
|
| ↳ `ticket_restriction` | string | Ticket access restriction \(organization, groups, assigned, requested\) |
|
||||||
|
| ↳ `user_fields` | json | Custom user fields \(dynamic key-value pairs\) |
|
||||||
|
| ↳ `shared` | boolean | Whether the user is shared from a different Zendesk |
|
||||||
|
| ↳ `shared_agent` | boolean | Whether the agent is shared from a different Zendesk |
|
||||||
|
| ↳ `remote_photo_url` | string | URL to a remote photo |
|
||||||
| `user_id` | number | The created user ID |
|
| `user_id` | number | The created user ID |
|
||||||
|
|
||||||
### `zendesk_create_users_bulk`
|
### `zendesk_create_users_bulk`
|
||||||
@@ -392,7 +847,21 @@ Create multiple users in Zendesk using bulk import
|
|||||||
|
|
||||||
| Parameter | Type | Description |
|
| Parameter | Type | Description |
|
||||||
| --------- | ---- | ----------- |
|
| --------- | ---- | ----------- |
|
||||||
| `job_status` | object | Job status object |
|
| `job_status` | object | Job status object for bulk operations |
|
||||||
|
| ↳ `id` | string | Automatically assigned job ID |
|
||||||
|
| ↳ `url` | string | URL to poll for status updates |
|
||||||
|
| ↳ `status` | string | Current job status \(queued, working, failed, completed\) |
|
||||||
|
| ↳ `job_type` | string | Category of background task |
|
||||||
|
| ↳ `total` | number | Total number of tasks in this job |
|
||||||
|
| ↳ `progress` | number | Number of tasks already completed |
|
||||||
|
| ↳ `message` | string | Message from the job worker |
|
||||||
|
| ↳ `results` | array | Array of result objects from the job |
|
||||||
|
| ↳ `id` | number | ID of the created or updated resource |
|
||||||
|
| ↳ `index` | number | Position of the result in the batch |
|
||||||
|
| ↳ `action` | string | Action performed \(e.g., create, update\) |
|
||||||
|
| ↳ `success` | boolean | Whether the operation succeeded |
|
||||||
|
| ↳ `status` | string | Status message \(e.g., Updated, Created\) |
|
||||||
|
| ↳ `error` | string | Error message if operation failed |
|
||||||
| `job_id` | string | The bulk operation job ID |
|
| `job_id` | string | The bulk operation job ID |
|
||||||
|
|
||||||
### `zendesk_update_user`
|
### `zendesk_update_user`
|
||||||
@@ -420,7 +889,48 @@ Update an existing user in Zendesk
|
|||||||
|
|
||||||
| Parameter | Type | Description |
|
| Parameter | Type | Description |
|
||||||
| --------- | ---- | ----------- |
|
| --------- | ---- | ----------- |
|
||||||
| `user` | json | Updated user object |
|
| `user` | object | Updated user object |
|
||||||
|
| ↳ `id` | number | Automatically assigned user ID |
|
||||||
|
| ↳ `url` | string | API URL of the user |
|
||||||
|
| ↳ `name` | string | User name |
|
||||||
|
| ↳ `email` | string | Primary email address |
|
||||||
|
| ↳ `created_at` | string | When the user was created \(ISO 8601 format\) |
|
||||||
|
| ↳ `updated_at` | string | When the user was last updated \(ISO 8601 format\) |
|
||||||
|
| ↳ `time_zone` | string | Time zone \(e.g., Eastern Time \(US & Canada\)\) |
|
||||||
|
| ↳ `iana_time_zone` | string | IANA time zone \(e.g., America/New_York\) |
|
||||||
|
| ↳ `phone` | string | Phone number |
|
||||||
|
| ↳ `shared_phone_number` | boolean | Whether the phone number is shared |
|
||||||
|
| ↳ `photo` | object | User photo details |
|
||||||
|
| ↳ `content_url` | string | URL to the photo |
|
||||||
|
| ↳ `file_name` | string | Photo file name |
|
||||||
|
| ↳ `size` | number | File size in bytes |
|
||||||
|
| ↳ `locale` | string | Locale \(e.g., en-US\) |
|
||||||
|
| ↳ `locale_id` | number | Locale ID |
|
||||||
|
| ↳ `organization_id` | number | Primary organization ID |
|
||||||
|
| ↳ `role` | string | User role \(end-user, agent, admin\) |
|
||||||
|
| ↳ `role_type` | number | Role type identifier |
|
||||||
|
| ↳ `custom_role_id` | number | Custom role ID |
|
||||||
|
| ↳ `active` | boolean | Whether the user is active \(false if deleted\) |
|
||||||
|
| ↳ `verified` | boolean | Whether any user identity has been verified |
|
||||||
|
| ↳ `alias` | string | Alias displayed to end users |
|
||||||
|
| ↳ `details` | string | Details about the user |
|
||||||
|
| ↳ `notes` | string | Notes about the user |
|
||||||
|
| ↳ `signature` | string | User signature for email replies |
|
||||||
|
| ↳ `default_group_id` | number | Default group ID for the user |
|
||||||
|
| ↳ `tags` | array | Tags associated with the user |
|
||||||
|
| ↳ `external_id` | string | External ID for linking to external records |
|
||||||
|
| ↳ `restricted_agent` | boolean | Whether the agent has restrictions |
|
||||||
|
| ↳ `suspended` | boolean | Whether the user is suspended |
|
||||||
|
| ↳ `moderator` | boolean | Whether the user has moderator permissions |
|
||||||
|
| ↳ `chat_only` | boolean | Whether the user is a chat-only agent |
|
||||||
|
| ↳ `only_private_comments` | boolean | Whether the user can only create private comments |
|
||||||
|
| ↳ `two_factor_auth_enabled` | boolean | Whether two-factor auth is enabled |
|
||||||
|
| ↳ `last_login_at` | string | Last login time \(ISO 8601 format\) |
|
||||||
|
| ↳ `ticket_restriction` | string | Ticket access restriction \(organization, groups, assigned, requested\) |
|
||||||
|
| ↳ `user_fields` | json | Custom user fields \(dynamic key-value pairs\) |
|
||||||
|
| ↳ `shared` | boolean | Whether the user is shared from a different Zendesk |
|
||||||
|
| ↳ `shared_agent` | boolean | Whether the agent is shared from a different Zendesk |
|
||||||
|
| ↳ `remote_photo_url` | string | URL to a remote photo |
|
||||||
| `user_id` | number | The updated user ID |
|
| `user_id` | number | The updated user ID |
|
||||||
|
|
||||||
### `zendesk_update_users_bulk`
|
### `zendesk_update_users_bulk`
|
||||||
@@ -440,7 +950,21 @@ Update multiple users in Zendesk using bulk update
|
|||||||
|
|
||||||
| Parameter | Type | Description |
|
| Parameter | Type | Description |
|
||||||
| --------- | ---- | ----------- |
|
| --------- | ---- | ----------- |
|
||||||
| `job_status` | object | Job status object |
|
| `job_status` | object | Job status object for bulk operations |
|
||||||
|
| ↳ `id` | string | Automatically assigned job ID |
|
||||||
|
| ↳ `url` | string | URL to poll for status updates |
|
||||||
|
| ↳ `status` | string | Current job status \(queued, working, failed, completed\) |
|
||||||
|
| ↳ `job_type` | string | Category of background task |
|
||||||
|
| ↳ `total` | number | Total number of tasks in this job |
|
||||||
|
| ↳ `progress` | number | Number of tasks already completed |
|
||||||
|
| ↳ `message` | string | Message from the job worker |
|
||||||
|
| ↳ `results` | array | Array of result objects from the job |
|
||||||
|
| ↳ `id` | number | ID of the created or updated resource |
|
||||||
|
| ↳ `index` | number | Position of the result in the batch |
|
||||||
|
| ↳ `action` | string | Action performed \(e.g., create, update\) |
|
||||||
|
| ↳ `success` | boolean | Whether the operation succeeded |
|
||||||
|
| ↳ `status` | string | Status message \(e.g., Updated, Created\) |
|
||||||
|
| ↳ `error` | string | Error message if operation failed |
|
||||||
| `job_id` | string | The bulk operation job ID |
|
| `job_id` | string | The bulk operation job ID |
|
||||||
|
|
||||||
### `zendesk_delete_user`
|
### `zendesk_delete_user`
|
||||||
@@ -482,13 +1006,27 @@ Retrieve a list of organizations from Zendesk
|
|||||||
| Parameter | Type | Description |
|
| Parameter | Type | Description |
|
||||||
| --------- | ---- | ----------- |
|
| --------- | ---- | ----------- |
|
||||||
| `organizations` | array | Array of organization objects |
|
| `organizations` | array | Array of organization objects |
|
||||||
|
| ↳ `id` | number | Automatically assigned organization ID |
|
||||||
|
| ↳ `url` | string | API URL of the organization |
|
||||||
|
| ↳ `name` | string | Unique organization name |
|
||||||
|
| ↳ `domain_names` | array | Domain names for automatic user assignment |
|
||||||
|
| ↳ `details` | string | Details about the organization |
|
||||||
|
| ↳ `notes` | string | Notes about the organization |
|
||||||
|
| ↳ `group_id` | number | Group ID for auto-routing new tickets |
|
||||||
|
| ↳ `shared_tickets` | boolean | Whether end users can see each others tickets |
|
||||||
|
| ↳ `shared_comments` | boolean | Whether end users can see each others comments |
|
||||||
|
| ↳ `tags` | array | Tags associated with the organization |
|
||||||
|
| ↳ `organization_fields` | json | Custom organization fields \(dynamic key-value pairs\) |
|
||||||
|
| ↳ `created_at` | string | When the organization was created \(ISO 8601 format\) |
|
||||||
|
| ↳ `updated_at` | string | When the organization was last updated \(ISO 8601 format\) |
|
||||||
|
| ↳ `external_id` | string | External ID for linking to external records |
|
||||||
| `paging` | object | Pagination information |
|
| `paging` | object | Pagination information |
|
||||||
| ↳ `next_page` | string | URL for next page of results |
|
| ↳ `next_page` | string | URL for next page of results |
|
||||||
| ↳ `previous_page` | string | URL for previous page of results |
|
| ↳ `previous_page` | string | URL for previous page of results |
|
||||||
| ↳ `count` | number | Total count of organizations |
|
| ↳ `count` | number | Total count of items |
|
||||||
| `metadata` | object | Response metadata |
|
| `metadata` | object | Response metadata |
|
||||||
| ↳ `total_returned` | number | Number of organizations returned in this response |
|
| ↳ `total_returned` | number | Number of items returned in this response |
|
||||||
| ↳ `has_more` | boolean | Whether more organizations are available |
|
| ↳ `has_more` | boolean | Whether more items are available |
|
||||||
|
|
||||||
### `zendesk_get_organization`
|
### `zendesk_get_organization`
|
||||||
|
|
||||||
@@ -507,7 +1045,21 @@ Get a single organization by ID from Zendesk
|
|||||||
|
|
||||||
| Parameter | Type | Description |
|
| Parameter | Type | Description |
|
||||||
| --------- | ---- | ----------- |
|
| --------- | ---- | ----------- |
|
||||||
| `organization` | json | Organization object |
|
| `organization` | object | Organization object |
|
||||||
|
| ↳ `id` | number | Automatically assigned organization ID |
|
||||||
|
| ↳ `url` | string | API URL of the organization |
|
||||||
|
| ↳ `name` | string | Unique organization name |
|
||||||
|
| ↳ `domain_names` | array | Domain names for automatic user assignment |
|
||||||
|
| ↳ `details` | string | Details about the organization |
|
||||||
|
| ↳ `notes` | string | Notes about the organization |
|
||||||
|
| ↳ `group_id` | number | Group ID for auto-routing new tickets |
|
||||||
|
| ↳ `shared_tickets` | boolean | Whether end users can see each others tickets |
|
||||||
|
| ↳ `shared_comments` | boolean | Whether end users can see each others comments |
|
||||||
|
| ↳ `tags` | array | Tags associated with the organization |
|
||||||
|
| ↳ `organization_fields` | json | Custom organization fields \(dynamic key-value pairs\) |
|
||||||
|
| ↳ `created_at` | string | When the organization was created \(ISO 8601 format\) |
|
||||||
|
| ↳ `updated_at` | string | When the organization was last updated \(ISO 8601 format\) |
|
||||||
|
| ↳ `external_id` | string | External ID for linking to external records |
|
||||||
| `organization_id` | number | The organization ID |
|
| `organization_id` | number | The organization ID |
|
||||||
|
|
||||||
### `zendesk_autocomplete_organizations`
|
### `zendesk_autocomplete_organizations`
|
||||||
@@ -530,13 +1082,27 @@ Autocomplete organizations in Zendesk by name prefix (for name matching/autocomp
|
|||||||
| Parameter | Type | Description |
|
| Parameter | Type | Description |
|
||||||
| --------- | ---- | ----------- |
|
| --------- | ---- | ----------- |
|
||||||
| `organizations` | array | Array of organization objects |
|
| `organizations` | array | Array of organization objects |
|
||||||
|
| ↳ `id` | number | Automatically assigned organization ID |
|
||||||
|
| ↳ `url` | string | API URL of the organization |
|
||||||
|
| ↳ `name` | string | Unique organization name |
|
||||||
|
| ↳ `domain_names` | array | Domain names for automatic user assignment |
|
||||||
|
| ↳ `details` | string | Details about the organization |
|
||||||
|
| ↳ `notes` | string | Notes about the organization |
|
||||||
|
| ↳ `group_id` | number | Group ID for auto-routing new tickets |
|
||||||
|
| ↳ `shared_tickets` | boolean | Whether end users can see each others tickets |
|
||||||
|
| ↳ `shared_comments` | boolean | Whether end users can see each others comments |
|
||||||
|
| ↳ `tags` | array | Tags associated with the organization |
|
||||||
|
| ↳ `organization_fields` | json | Custom organization fields \(dynamic key-value pairs\) |
|
||||||
|
| ↳ `created_at` | string | When the organization was created \(ISO 8601 format\) |
|
||||||
|
| ↳ `updated_at` | string | When the organization was last updated \(ISO 8601 format\) |
|
||||||
|
| ↳ `external_id` | string | External ID for linking to external records |
|
||||||
| `paging` | object | Pagination information |
|
| `paging` | object | Pagination information |
|
||||||
| ↳ `next_page` | string | URL for next page of results |
|
| ↳ `next_page` | string | URL for next page of results |
|
||||||
| ↳ `previous_page` | string | URL for previous page of results |
|
| ↳ `previous_page` | string | URL for previous page of results |
|
||||||
| ↳ `count` | number | Total count of organizations |
|
| ↳ `count` | number | Total count of items |
|
||||||
| `metadata` | object | Response metadata |
|
| `metadata` | object | Response metadata |
|
||||||
| ↳ `total_returned` | number | Number of organizations returned in this response |
|
| ↳ `total_returned` | number | Number of items returned in this response |
|
||||||
| ↳ `has_more` | boolean | Whether more organizations are available |
|
| ↳ `has_more` | boolean | Whether more items are available |
|
||||||
|
|
||||||
### `zendesk_create_organization`
|
### `zendesk_create_organization`
|
||||||
|
|
||||||
@@ -560,7 +1126,21 @@ Create a new organization in Zendesk
|
|||||||
|
|
||||||
| Parameter | Type | Description |
|
| Parameter | Type | Description |
|
||||||
| --------- | ---- | ----------- |
|
| --------- | ---- | ----------- |
|
||||||
| `organization` | json | Created organization object |
|
| `organization` | object | Created organization object |
|
||||||
|
| ↳ `id` | number | Automatically assigned organization ID |
|
||||||
|
| ↳ `url` | string | API URL of the organization |
|
||||||
|
| ↳ `name` | string | Unique organization name |
|
||||||
|
| ↳ `domain_names` | array | Domain names for automatic user assignment |
|
||||||
|
| ↳ `details` | string | Details about the organization |
|
||||||
|
| ↳ `notes` | string | Notes about the organization |
|
||||||
|
| ↳ `group_id` | number | Group ID for auto-routing new tickets |
|
||||||
|
| ↳ `shared_tickets` | boolean | Whether end users can see each others tickets |
|
||||||
|
| ↳ `shared_comments` | boolean | Whether end users can see each others comments |
|
||||||
|
| ↳ `tags` | array | Tags associated with the organization |
|
||||||
|
| ↳ `organization_fields` | json | Custom organization fields \(dynamic key-value pairs\) |
|
||||||
|
| ↳ `created_at` | string | When the organization was created \(ISO 8601 format\) |
|
||||||
|
| ↳ `updated_at` | string | When the organization was last updated \(ISO 8601 format\) |
|
||||||
|
| ↳ `external_id` | string | External ID for linking to external records |
|
||||||
| `organization_id` | number | The created organization ID |
|
| `organization_id` | number | The created organization ID |
|
||||||
|
|
||||||
### `zendesk_create_organizations_bulk`
|
### `zendesk_create_organizations_bulk`
|
||||||
@@ -580,7 +1160,21 @@ Create multiple organizations in Zendesk using bulk import
|
|||||||
|
|
||||||
| Parameter | Type | Description |
|
| Parameter | Type | Description |
|
||||||
| --------- | ---- | ----------- |
|
| --------- | ---- | ----------- |
|
||||||
| `job_status` | object | Job status object |
|
| `job_status` | object | Job status object for bulk operations |
|
||||||
|
| ↳ `id` | string | Automatically assigned job ID |
|
||||||
|
| ↳ `url` | string | URL to poll for status updates |
|
||||||
|
| ↳ `status` | string | Current job status \(queued, working, failed, completed\) |
|
||||||
|
| ↳ `job_type` | string | Category of background task |
|
||||||
|
| ↳ `total` | number | Total number of tasks in this job |
|
||||||
|
| ↳ `progress` | number | Number of tasks already completed |
|
||||||
|
| ↳ `message` | string | Message from the job worker |
|
||||||
|
| ↳ `results` | array | Array of result objects from the job |
|
||||||
|
| ↳ `id` | number | ID of the created or updated resource |
|
||||||
|
| ↳ `index` | number | Position of the result in the batch |
|
||||||
|
| ↳ `action` | string | Action performed \(e.g., create, update\) |
|
||||||
|
| ↳ `success` | boolean | Whether the operation succeeded |
|
||||||
|
| ↳ `status` | string | Status message \(e.g., Updated, Created\) |
|
||||||
|
| ↳ `error` | string | Error message if operation failed |
|
||||||
| `job_id` | string | The bulk operation job ID |
|
| `job_id` | string | The bulk operation job ID |
|
||||||
|
|
||||||
### `zendesk_update_organization`
|
### `zendesk_update_organization`
|
||||||
@@ -606,7 +1200,21 @@ Update an existing organization in Zendesk
|
|||||||
|
|
||||||
| Parameter | Type | Description |
|
| Parameter | Type | Description |
|
||||||
| --------- | ---- | ----------- |
|
| --------- | ---- | ----------- |
|
||||||
| `organization` | json | Updated organization object |
|
| `organization` | object | Updated organization object |
|
||||||
|
| ↳ `id` | number | Automatically assigned organization ID |
|
||||||
|
| ↳ `url` | string | API URL of the organization |
|
||||||
|
| ↳ `name` | string | Unique organization name |
|
||||||
|
| ↳ `domain_names` | array | Domain names for automatic user assignment |
|
||||||
|
| ↳ `details` | string | Details about the organization |
|
||||||
|
| ↳ `notes` | string | Notes about the organization |
|
||||||
|
| ↳ `group_id` | number | Group ID for auto-routing new tickets |
|
||||||
|
| ↳ `shared_tickets` | boolean | Whether end users can see each others tickets |
|
||||||
|
| ↳ `shared_comments` | boolean | Whether end users can see each others comments |
|
||||||
|
| ↳ `tags` | array | Tags associated with the organization |
|
||||||
|
| ↳ `organization_fields` | json | Custom organization fields \(dynamic key-value pairs\) |
|
||||||
|
| ↳ `created_at` | string | When the organization was created \(ISO 8601 format\) |
|
||||||
|
| ↳ `updated_at` | string | When the organization was last updated \(ISO 8601 format\) |
|
||||||
|
| ↳ `external_id` | string | External ID for linking to external records |
|
||||||
| `organization_id` | number | The updated organization ID |
|
| `organization_id` | number | The updated organization ID |
|
||||||
|
|
||||||
### `zendesk_delete_organization`
|
### `zendesk_delete_organization`
|
||||||
@@ -650,14 +1258,14 @@ Unified search across tickets, users, and organizations in Zendesk
|
|||||||
|
|
||||||
| Parameter | Type | Description |
|
| Parameter | Type | Description |
|
||||||
| --------- | ---- | ----------- |
|
| --------- | ---- | ----------- |
|
||||||
| `results` | array | Array of result objects |
|
|
||||||
| `paging` | object | Pagination information |
|
| `paging` | object | Pagination information |
|
||||||
| ↳ `next_page` | string | URL for next page of results |
|
| ↳ `next_page` | string | URL for next page of results |
|
||||||
| ↳ `previous_page` | string | URL for previous page of results |
|
| ↳ `previous_page` | string | URL for previous page of results |
|
||||||
| ↳ `count` | number | Total count of results |
|
| ↳ `count` | number | Total count of items |
|
||||||
| `metadata` | object | Response metadata |
|
| `metadata` | object | Response metadata |
|
||||||
| ↳ `total_returned` | number | Number of results returned in this response |
|
| ↳ `total_returned` | number | Number of items returned in this response |
|
||||||
| ↳ `has_more` | boolean | Whether more results are available |
|
| ↳ `has_more` | boolean | Whether more items are available |
|
||||||
|
| `results` | array | Array of result objects \(tickets, users, or organizations depending on search query\) |
|
||||||
|
|
||||||
### `zendesk_search_count`
|
### `zendesk_search_count`
|
||||||
|
|
||||||
|
|||||||
@@ -52,10 +52,10 @@ Start a new conversation thread in Zep
|
|||||||
|
|
||||||
| Parameter | Type | Description |
|
| Parameter | Type | Description |
|
||||||
| --------- | ---- | ----------- |
|
| --------- | ---- | ----------- |
|
||||||
| `threadId` | string | The thread ID |
|
| `threadId` | string | Thread identifier |
|
||||||
| `userId` | string | The user ID |
|
| `userId` | string | Associated user ID |
|
||||||
| `uuid` | string | Internal UUID |
|
| `uuid` | string | Internal UUID |
|
||||||
| `createdAt` | string | Creation timestamp |
|
| `createdAt` | string | Creation timestamp \(ISO 8601\) |
|
||||||
| `projectUuid` | string | Project UUID |
|
| `projectUuid` | string | Project UUID |
|
||||||
|
|
||||||
### `zep_get_threads`
|
### `zep_get_threads`
|
||||||
@@ -77,8 +77,15 @@ List all conversation threads
|
|||||||
| Parameter | Type | Description |
|
| Parameter | Type | Description |
|
||||||
| --------- | ---- | ----------- |
|
| --------- | ---- | ----------- |
|
||||||
| `threads` | array | Array of thread objects |
|
| `threads` | array | Array of thread objects |
|
||||||
| `responseCount` | number | Number of threads in this response |
|
| ↳ `threadId` | string | Thread identifier |
|
||||||
| `totalCount` | number | Total number of threads available |
|
| ↳ `userId` | string | Associated user ID |
|
||||||
|
| ↳ `uuid` | string | Internal UUID |
|
||||||
|
| ↳ `createdAt` | string | Creation timestamp \(ISO 8601\) |
|
||||||
|
| ↳ `updatedAt` | string | Last update timestamp \(ISO 8601\) |
|
||||||
|
| ↳ `projectUuid` | string | Project UUID |
|
||||||
|
| ↳ `metadata` | object | Custom metadata \(dynamic key-value pairs\) |
|
||||||
|
| `responseCount` | number | Number of items in this response |
|
||||||
|
| `totalCount` | number | Total number of items available |
|
||||||
|
|
||||||
### `zep_delete_thread`
|
### `zep_delete_thread`
|
||||||
|
|
||||||
@@ -135,8 +142,16 @@ Retrieve messages from a thread
|
|||||||
| Parameter | Type | Description |
|
| Parameter | Type | Description |
|
||||||
| --------- | ---- | ----------- |
|
| --------- | ---- | ----------- |
|
||||||
| `messages` | array | Array of message objects |
|
| `messages` | array | Array of message objects |
|
||||||
| `rowCount` | number | Number of messages in this response |
|
| ↳ `uuid` | string | Message UUID |
|
||||||
| `totalCount` | number | Total number of messages in the thread |
|
| ↳ `role` | string | Message role \(user, assistant, system, tool\) |
|
||||||
|
| ↳ `roleType` | string | Role type \(AI, human, tool\) |
|
||||||
|
| ↳ `content` | string | Message content |
|
||||||
|
| ↳ `name` | string | Sender name |
|
||||||
|
| ↳ `createdAt` | string | Timestamp \(RFC3339 format\) |
|
||||||
|
| ↳ `metadata` | object | Message metadata \(dynamic key-value pairs\) |
|
||||||
|
| ↳ `processed` | boolean | Whether message has been processed |
|
||||||
|
| `rowCount` | number | Number of rows returned |
|
||||||
|
| `totalCount` | number | Total number of items available |
|
||||||
|
|
||||||
### `zep_add_messages`
|
### `zep_add_messages`
|
||||||
|
|
||||||
@@ -154,7 +169,7 @@ Add messages to an existing thread
|
|||||||
|
|
||||||
| Parameter | Type | Description |
|
| Parameter | Type | Description |
|
||||||
| --------- | ---- | ----------- |
|
| --------- | ---- | ----------- |
|
||||||
| `threadId` | string | The thread ID |
|
| `threadId` | string | Thread identifier |
|
||||||
| `added` | boolean | Whether messages were added successfully |
|
| `added` | boolean | Whether messages were added successfully |
|
||||||
| `messageIds` | array | Array of added message UUIDs |
|
| `messageIds` | array | Array of added message UUIDs |
|
||||||
|
|
||||||
@@ -177,13 +192,13 @@ Create a new user in Zep
|
|||||||
|
|
||||||
| Parameter | Type | Description |
|
| Parameter | Type | Description |
|
||||||
| --------- | ---- | ----------- |
|
| --------- | ---- | ----------- |
|
||||||
| `userId` | string | The user ID |
|
| `userId` | string | User identifier |
|
||||||
| `email` | string | User email |
|
| `email` | string | User email address |
|
||||||
| `firstName` | string | User first name |
|
| `firstName` | string | User first name |
|
||||||
| `lastName` | string | User last name |
|
| `lastName` | string | User last name |
|
||||||
| `uuid` | string | Internal UUID |
|
| `uuid` | string | Internal UUID |
|
||||||
| `createdAt` | string | Creation timestamp |
|
| `createdAt` | string | Creation timestamp \(ISO 8601\) |
|
||||||
| `metadata` | object | User metadata |
|
| `metadata` | object | User metadata \(dynamic key-value pairs\) |
|
||||||
|
|
||||||
### `zep_get_user`
|
### `zep_get_user`
|
||||||
|
|
||||||
@@ -200,14 +215,14 @@ Retrieve user information from Zep
|
|||||||
|
|
||||||
| Parameter | Type | Description |
|
| Parameter | Type | Description |
|
||||||
| --------- | ---- | ----------- |
|
| --------- | ---- | ----------- |
|
||||||
| `userId` | string | The user ID |
|
| `userId` | string | User identifier |
|
||||||
| `email` | string | User email |
|
| `email` | string | User email address |
|
||||||
| `firstName` | string | User first name |
|
| `firstName` | string | User first name |
|
||||||
| `lastName` | string | User last name |
|
| `lastName` | string | User last name |
|
||||||
| `uuid` | string | Internal UUID |
|
| `uuid` | string | Internal UUID |
|
||||||
| `createdAt` | string | Creation timestamp |
|
| `createdAt` | string | Creation timestamp \(ISO 8601\) |
|
||||||
| `updatedAt` | string | Last update timestamp |
|
| `updatedAt` | string | Last update timestamp \(ISO 8601\) |
|
||||||
| `metadata` | object | User metadata |
|
| `metadata` | object | User metadata \(dynamic key-value pairs\) |
|
||||||
|
|
||||||
### `zep_get_user_threads`
|
### `zep_get_user_threads`
|
||||||
|
|
||||||
@@ -225,7 +240,14 @@ List all conversation threads for a specific user
|
|||||||
|
|
||||||
| Parameter | Type | Description |
|
| Parameter | Type | Description |
|
||||||
| --------- | ---- | ----------- |
|
| --------- | ---- | ----------- |
|
||||||
| `threads` | array | Array of thread objects for this user |
|
| `threads` | array | Array of thread objects |
|
||||||
| `totalCount` | number | Total number of threads returned |
|
| ↳ `threadId` | string | Thread identifier |
|
||||||
|
| ↳ `userId` | string | Associated user ID |
|
||||||
|
| ↳ `uuid` | string | Internal UUID |
|
||||||
|
| ↳ `createdAt` | string | Creation timestamp \(ISO 8601\) |
|
||||||
|
| ↳ `updatedAt` | string | Last update timestamp \(ISO 8601\) |
|
||||||
|
| ↳ `projectUuid` | string | Project UUID |
|
||||||
|
| ↳ `metadata` | object | Custom metadata \(dynamic key-value pairs\) |
|
||||||
|
| `totalCount` | number | Total number of items available |
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -72,19 +72,46 @@ Create a new Zoom meeting
|
|||||||
| ↳ `id` | number | Meeting ID |
|
| ↳ `id` | number | Meeting ID |
|
||||||
| ↳ `uuid` | string | Meeting UUID |
|
| ↳ `uuid` | string | Meeting UUID |
|
||||||
| ↳ `host_id` | string | Host user ID |
|
| ↳ `host_id` | string | Host user ID |
|
||||||
| ↳ `host_email` | string | Host email |
|
| ↳ `host_email` | string | Host email address |
|
||||||
| ↳ `topic` | string | Meeting topic |
|
| ↳ `topic` | string | Meeting topic |
|
||||||
| ↳ `type` | number | Meeting type |
|
| ↳ `type` | number | Meeting type: 1=instant, 2=scheduled, 3=recurring no fixed time, 8=recurring fixed time |
|
||||||
| ↳ `status` | string | Meeting status |
|
| ↳ `status` | string | Meeting status \(e.g., waiting, started\) |
|
||||||
| ↳ `start_time` | string | Start time |
|
| ↳ `start_time` | string | Start time in ISO 8601 format |
|
||||||
| ↳ `duration` | number | Duration in minutes |
|
| ↳ `duration` | number | Duration in minutes |
|
||||||
| ↳ `timezone` | string | Timezone |
|
| ↳ `timezone` | string | Timezone \(e.g., America/Los_Angeles\) |
|
||||||
| ↳ `agenda` | string | Meeting agenda |
|
| ↳ `agenda` | string | Meeting agenda |
|
||||||
| ↳ `created_at` | string | Creation timestamp |
|
| ↳ `created_at` | string | Creation timestamp in ISO 8601 format |
|
||||||
| ↳ `start_url` | string | Host start URL |
|
| ↳ `start_url` | string | URL for host to start the meeting |
|
||||||
| ↳ `join_url` | string | Participant join URL |
|
| ↳ `join_url` | string | URL for participants to join the meeting |
|
||||||
| ↳ `password` | string | Meeting password |
|
| ↳ `password` | string | Meeting password |
|
||||||
|
| ↳ `h323_password` | string | H.323/SIP room system password |
|
||||||
|
| ↳ `pstn_password` | string | PSTN password for phone dial-in |
|
||||||
|
| ↳ `encrypted_password` | string | Encrypted password for joining |
|
||||||
| ↳ `settings` | object | Meeting settings |
|
| ↳ `settings` | object | Meeting settings |
|
||||||
|
| ↳ `host_video` | boolean | Start with host video on |
|
||||||
|
| ↳ `participant_video` | boolean | Start with participant video on |
|
||||||
|
| ↳ `join_before_host` | boolean | Allow participants to join before host |
|
||||||
|
| ↳ `mute_upon_entry` | boolean | Mute participants upon entry |
|
||||||
|
| ↳ `watermark` | boolean | Add watermark when viewing shared screen |
|
||||||
|
| ↳ `audio` | string | Audio options: both, telephony, or voip |
|
||||||
|
| ↳ `auto_recording` | string | Auto recording: local, cloud, or none |
|
||||||
|
| ↳ `waiting_room` | boolean | Enable waiting room |
|
||||||
|
| ↳ `meeting_authentication` | boolean | Require meeting authentication |
|
||||||
|
| ↳ `approval_type` | number | Approval type: 0=auto, 1=manual, 2=none |
|
||||||
|
| ↳ `recurrence` | object | Recurrence settings for recurring meetings |
|
||||||
|
| ↳ `type` | number | Recurrence type: 1=daily, 2=weekly, 3=monthly |
|
||||||
|
| ↳ `repeat_interval` | number | Interval between recurring meetings |
|
||||||
|
| ↳ `weekly_days` | string | Days of week for weekly recurrence \(1-7, comma-separated\) |
|
||||||
|
| ↳ `monthly_day` | number | Day of month for monthly recurrence |
|
||||||
|
| ↳ `monthly_week` | number | Week of month for monthly recurrence |
|
||||||
|
| ↳ `monthly_week_day` | number | Day of week for monthly recurrence |
|
||||||
|
| ↳ `end_times` | number | Number of occurrences |
|
||||||
|
| ↳ `end_date_time` | string | End date time in ISO 8601 format |
|
||||||
|
| ↳ `occurrences` | array | Meeting occurrences for recurring meetings |
|
||||||
|
| ↳ `occurrence_id` | string | Occurrence ID |
|
||||||
|
| ↳ `start_time` | string | Start time in ISO 8601 format |
|
||||||
|
| ↳ `duration` | number | Duration in minutes |
|
||||||
|
| ↳ `status` | string | Occurrence status |
|
||||||
|
|
||||||
### `zoom_list_meetings`
|
### `zoom_list_meetings`
|
||||||
|
|
||||||
@@ -104,12 +131,23 @@ List all meetings for a Zoom user
|
|||||||
| Parameter | Type | Description |
|
| Parameter | Type | Description |
|
||||||
| --------- | ---- | ----------- |
|
| --------- | ---- | ----------- |
|
||||||
| `meetings` | array | List of meetings |
|
| `meetings` | array | List of meetings |
|
||||||
|
| ↳ `id` | number | Meeting ID |
|
||||||
|
| ↳ `uuid` | string | Meeting UUID |
|
||||||
|
| ↳ `host_id` | string | Host user ID |
|
||||||
|
| ↳ `topic` | string | Meeting topic |
|
||||||
|
| ↳ `type` | number | Meeting type |
|
||||||
|
| ↳ `start_time` | string | Start time in ISO 8601 format |
|
||||||
|
| ↳ `duration` | number | Duration in minutes |
|
||||||
|
| ↳ `timezone` | string | Timezone |
|
||||||
|
| ↳ `agenda` | string | Meeting agenda |
|
||||||
|
| ↳ `created_at` | string | Creation timestamp |
|
||||||
|
| ↳ `join_url` | string | URL for participants to join |
|
||||||
| `pageInfo` | object | Pagination information |
|
| `pageInfo` | object | Pagination information |
|
||||||
| ↳ `pageCount` | number | Total number of pages |
|
| ↳ `pageCount` | number | Total number of pages |
|
||||||
| ↳ `pageNumber` | number | Current page number |
|
| ↳ `pageNumber` | number | Current page number |
|
||||||
| ↳ `pageSize` | number | Number of records per page |
|
| ↳ `pageSize` | number | Number of records per page |
|
||||||
| ↳ `totalRecords` | number | Total number of records |
|
| ↳ `totalRecords` | number | Total number of records |
|
||||||
| ↳ `nextPageToken` | string | Token for next page |
|
| ↳ `nextPageToken` | string | Token for next page of results |
|
||||||
|
|
||||||
### `zoom_get_meeting`
|
### `zoom_get_meeting`
|
||||||
|
|
||||||
@@ -131,21 +169,46 @@ Get details of a specific Zoom meeting
|
|||||||
| ↳ `id` | number | Meeting ID |
|
| ↳ `id` | number | Meeting ID |
|
||||||
| ↳ `uuid` | string | Meeting UUID |
|
| ↳ `uuid` | string | Meeting UUID |
|
||||||
| ↳ `host_id` | string | Host user ID |
|
| ↳ `host_id` | string | Host user ID |
|
||||||
| ↳ `host_email` | string | Host email |
|
| ↳ `host_email` | string | Host email address |
|
||||||
| ↳ `topic` | string | Meeting topic |
|
| ↳ `topic` | string | Meeting topic |
|
||||||
| ↳ `type` | number | Meeting type |
|
| ↳ `type` | number | Meeting type: 1=instant, 2=scheduled, 3=recurring no fixed time, 8=recurring fixed time |
|
||||||
| ↳ `status` | string | Meeting status |
|
| ↳ `status` | string | Meeting status \(e.g., waiting, started\) |
|
||||||
| ↳ `start_time` | string | Start time |
|
| ↳ `start_time` | string | Start time in ISO 8601 format |
|
||||||
| ↳ `duration` | number | Duration in minutes |
|
| ↳ `duration` | number | Duration in minutes |
|
||||||
| ↳ `timezone` | string | Timezone |
|
| ↳ `timezone` | string | Timezone \(e.g., America/Los_Angeles\) |
|
||||||
| ↳ `agenda` | string | Meeting agenda |
|
| ↳ `agenda` | string | Meeting agenda |
|
||||||
| ↳ `created_at` | string | Creation timestamp |
|
| ↳ `created_at` | string | Creation timestamp in ISO 8601 format |
|
||||||
| ↳ `start_url` | string | Host start URL |
|
| ↳ `start_url` | string | URL for host to start the meeting |
|
||||||
| ↳ `join_url` | string | Participant join URL |
|
| ↳ `join_url` | string | URL for participants to join the meeting |
|
||||||
| ↳ `password` | string | Meeting password |
|
| ↳ `password` | string | Meeting password |
|
||||||
|
| ↳ `h323_password` | string | H.323/SIP room system password |
|
||||||
|
| ↳ `pstn_password` | string | PSTN password for phone dial-in |
|
||||||
|
| ↳ `encrypted_password` | string | Encrypted password for joining |
|
||||||
| ↳ `settings` | object | Meeting settings |
|
| ↳ `settings` | object | Meeting settings |
|
||||||
| ↳ `recurrence` | object | Recurrence settings |
|
| ↳ `host_video` | boolean | Start with host video on |
|
||||||
| ↳ `occurrences` | array | Meeting occurrences |
|
| ↳ `participant_video` | boolean | Start with participant video on |
|
||||||
|
| ↳ `join_before_host` | boolean | Allow participants to join before host |
|
||||||
|
| ↳ `mute_upon_entry` | boolean | Mute participants upon entry |
|
||||||
|
| ↳ `watermark` | boolean | Add watermark when viewing shared screen |
|
||||||
|
| ↳ `audio` | string | Audio options: both, telephony, or voip |
|
||||||
|
| ↳ `auto_recording` | string | Auto recording: local, cloud, or none |
|
||||||
|
| ↳ `waiting_room` | boolean | Enable waiting room |
|
||||||
|
| ↳ `meeting_authentication` | boolean | Require meeting authentication |
|
||||||
|
| ↳ `approval_type` | number | Approval type: 0=auto, 1=manual, 2=none |
|
||||||
|
| ↳ `recurrence` | object | Recurrence settings for recurring meetings |
|
||||||
|
| ↳ `type` | number | Recurrence type: 1=daily, 2=weekly, 3=monthly |
|
||||||
|
| ↳ `repeat_interval` | number | Interval between recurring meetings |
|
||||||
|
| ↳ `weekly_days` | string | Days of week for weekly recurrence \(1-7, comma-separated\) |
|
||||||
|
| ↳ `monthly_day` | number | Day of month for monthly recurrence |
|
||||||
|
| ↳ `monthly_week` | number | Week of month for monthly recurrence |
|
||||||
|
| ↳ `monthly_week_day` | number | Day of week for monthly recurrence |
|
||||||
|
| ↳ `end_times` | number | Number of occurrences |
|
||||||
|
| ↳ `end_date_time` | string | End date time in ISO 8601 format |
|
||||||
|
| ↳ `occurrences` | array | Meeting occurrences for recurring meetings |
|
||||||
|
| ↳ `occurrence_id` | string | Occurrence ID |
|
||||||
|
| ↳ `start_time` | string | Start time in ISO 8601 format |
|
||||||
|
| ↳ `duration` | number | Duration in minutes |
|
||||||
|
| ↳ `status` | string | Occurrence status |
|
||||||
|
|
||||||
### `zoom_update_meeting`
|
### `zoom_update_meeting`
|
||||||
|
|
||||||
@@ -231,12 +294,35 @@ List all cloud recordings for a Zoom user
|
|||||||
| Parameter | Type | Description |
|
| Parameter | Type | Description |
|
||||||
| --------- | ---- | ----------- |
|
| --------- | ---- | ----------- |
|
||||||
| `recordings` | array | List of recordings |
|
| `recordings` | array | List of recordings |
|
||||||
|
| ↳ `uuid` | string | Meeting UUID |
|
||||||
|
| ↳ `id` | number | Meeting ID |
|
||||||
|
| ↳ `account_id` | string | Account ID |
|
||||||
|
| ↳ `host_id` | string | Host user ID |
|
||||||
|
| ↳ `topic` | string | Meeting topic |
|
||||||
|
| ↳ `type` | number | Meeting type |
|
||||||
|
| ↳ `start_time` | string | Meeting start time |
|
||||||
|
| ↳ `duration` | number | Meeting duration in minutes |
|
||||||
|
| ↳ `total_size` | number | Total size of all recordings in bytes |
|
||||||
|
| ↳ `recording_count` | number | Number of recording files |
|
||||||
|
| ↳ `share_url` | string | URL to share recordings |
|
||||||
|
| ↳ `recording_files` | array | List of recording files |
|
||||||
|
| ↳ `id` | string | Recording file ID |
|
||||||
|
| ↳ `meeting_id` | string | Meeting ID associated with the recording |
|
||||||
|
| ↳ `recording_start` | string | Start time of the recording |
|
||||||
|
| ↳ `recording_end` | string | End time of the recording |
|
||||||
|
| ↳ `file_type` | string | Type of recording file \(MP4, M4A, etc.\) |
|
||||||
|
| ↳ `file_extension` | string | File extension |
|
||||||
|
| ↳ `file_size` | number | File size in bytes |
|
||||||
|
| ↳ `play_url` | string | URL to play the recording |
|
||||||
|
| ↳ `download_url` | string | URL to download the recording |
|
||||||
|
| ↳ `status` | string | Recording status |
|
||||||
|
| ↳ `recording_type` | string | Type of recording \(shared_screen, audio_only, etc.\) |
|
||||||
| `pageInfo` | object | Pagination information |
|
| `pageInfo` | object | Pagination information |
|
||||||
| ↳ `from` | string | Start date of query range |
|
| ↳ `from` | string | Start date of query range |
|
||||||
| ↳ `to` | string | End date of query range |
|
| ↳ `to` | string | End date of query range |
|
||||||
| ↳ `pageSize` | number | Number of records per page |
|
| ↳ `pageSize` | number | Number of records per page |
|
||||||
| ↳ `totalRecords` | number | Total number of records |
|
| ↳ `totalRecords` | number | Total number of records |
|
||||||
| ↳ `nextPageToken` | string | Token for next page |
|
| ↳ `nextPageToken` | string | Token for next page of results |
|
||||||
|
|
||||||
### `zoom_get_meeting_recordings`
|
### `zoom_get_meeting_recordings`
|
||||||
|
|
||||||
@@ -257,12 +343,27 @@ Get all recordings for a specific Zoom meeting
|
|||||||
| `recording` | object | The meeting recording with all files |
|
| `recording` | object | The meeting recording with all files |
|
||||||
| ↳ `uuid` | string | Meeting UUID |
|
| ↳ `uuid` | string | Meeting UUID |
|
||||||
| ↳ `id` | number | Meeting ID |
|
| ↳ `id` | number | Meeting ID |
|
||||||
|
| ↳ `account_id` | string | Account ID |
|
||||||
|
| ↳ `host_id` | string | Host user ID |
|
||||||
| ↳ `topic` | string | Meeting topic |
|
| ↳ `topic` | string | Meeting topic |
|
||||||
|
| ↳ `type` | number | Meeting type |
|
||||||
| ↳ `start_time` | string | Meeting start time |
|
| ↳ `start_time` | string | Meeting start time |
|
||||||
| ↳ `duration` | number | Meeting duration in minutes |
|
| ↳ `duration` | number | Meeting duration in minutes |
|
||||||
| ↳ `total_size` | number | Total size of recordings in bytes |
|
| ↳ `total_size` | number | Total size of all recordings in bytes |
|
||||||
|
| ↳ `recording_count` | number | Number of recording files |
|
||||||
| ↳ `share_url` | string | URL to share recordings |
|
| ↳ `share_url` | string | URL to share recordings |
|
||||||
| ↳ `recording_files` | array | List of recording files |
|
| ↳ `recording_files` | array | List of recording files |
|
||||||
|
| ↳ `id` | string | Recording file ID |
|
||||||
|
| ↳ `meeting_id` | string | Meeting ID associated with the recording |
|
||||||
|
| ↳ `recording_start` | string | Start time of the recording |
|
||||||
|
| ↳ `recording_end` | string | End time of the recording |
|
||||||
|
| ↳ `file_type` | string | Type of recording file \(MP4, M4A, etc.\) |
|
||||||
|
| ↳ `file_extension` | string | File extension |
|
||||||
|
| ↳ `file_size` | number | File size in bytes |
|
||||||
|
| ↳ `play_url` | string | URL to play the recording |
|
||||||
|
| ↳ `download_url` | string | URL to download the recording |
|
||||||
|
| ↳ `status` | string | Recording status |
|
||||||
|
| ↳ `recording_type` | string | Type of recording \(shared_screen, audio_only, etc.\) |
|
||||||
|
|
||||||
### `zoom_delete_recording`
|
### `zoom_delete_recording`
|
||||||
|
|
||||||
@@ -299,9 +400,19 @@ List participants from a past Zoom meeting
|
|||||||
| Parameter | Type | Description |
|
| Parameter | Type | Description |
|
||||||
| --------- | ---- | ----------- |
|
| --------- | ---- | ----------- |
|
||||||
| `participants` | array | List of meeting participants |
|
| `participants` | array | List of meeting participants |
|
||||||
|
| ↳ `id` | string | Participant unique identifier |
|
||||||
|
| ↳ `user_id` | string | User ID if registered Zoom user |
|
||||||
|
| ↳ `name` | string | Participant display name |
|
||||||
|
| ↳ `user_email` | string | Participant email address |
|
||||||
|
| ↳ `join_time` | string | Time when participant joined \(ISO 8601\) |
|
||||||
|
| ↳ `leave_time` | string | Time when participant left \(ISO 8601\) |
|
||||||
|
| ↳ `duration` | number | Duration in seconds participant was in meeting |
|
||||||
|
| ↳ `attentiveness_score` | string | Attentiveness score \(deprecated\) |
|
||||||
|
| ↳ `failover` | boolean | Whether participant failed over to another data center |
|
||||||
|
| ↳ `status` | string | Participant status |
|
||||||
| `pageInfo` | object | Pagination information |
|
| `pageInfo` | object | Pagination information |
|
||||||
| ↳ `pageSize` | number | Number of records per page |
|
| ↳ `pageSize` | number | Number of records per page |
|
||||||
| ↳ `totalRecords` | number | Total number of records |
|
| ↳ `totalRecords` | number | Total number of records |
|
||||||
| ↳ `nextPageToken` | string | Token for next page |
|
| ↳ `nextPageToken` | string | Token for next page of results |
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -4,22 +4,22 @@ import { auth } from '@/lib/auth'
|
|||||||
import { isAuthDisabled } from '@/lib/core/config/feature-flags'
|
import { isAuthDisabled } from '@/lib/core/config/feature-flags'
|
||||||
|
|
||||||
export async function POST() {
|
export async function POST() {
|
||||||
try {
|
|
||||||
if (isAuthDisabled) {
|
if (isAuthDisabled) {
|
||||||
return NextResponse.json({ token: 'anonymous-socket-token' })
|
return NextResponse.json({ token: 'anonymous-socket-token' })
|
||||||
}
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
const hdrs = await headers()
|
const hdrs = await headers()
|
||||||
const response = await auth.api.generateOneTimeToken({
|
const response = await auth.api.generateOneTimeToken({
|
||||||
headers: hdrs,
|
headers: hdrs,
|
||||||
})
|
})
|
||||||
|
|
||||||
if (!response) {
|
if (!response?.token) {
|
||||||
return NextResponse.json({ error: 'Failed to generate token' }, { status: 500 })
|
return NextResponse.json({ error: 'Authentication required' }, { status: 401 })
|
||||||
}
|
}
|
||||||
|
|
||||||
return NextResponse.json({ token: response.token })
|
return NextResponse.json({ token: response.token })
|
||||||
} catch (error) {
|
} catch {
|
||||||
return NextResponse.json({ error: 'Failed to generate token' }, { status: 500 })
|
return NextResponse.json({ error: 'Failed to generate token' }, { status: 500 })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -97,7 +97,10 @@ export async function POST(
|
|||||||
const socketServerUrl = env.SOCKET_SERVER_URL || 'http://localhost:3002'
|
const socketServerUrl = env.SOCKET_SERVER_URL || 'http://localhost:3002'
|
||||||
await fetch(`${socketServerUrl}/api/workflow-reverted`, {
|
await fetch(`${socketServerUrl}/api/workflow-reverted`, {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
headers: { 'Content-Type': 'application/json' },
|
headers: {
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
'x-api-key': env.INTERNAL_API_SECRET,
|
||||||
|
},
|
||||||
body: JSON.stringify({ workflowId: id, timestamp: Date.now() }),
|
body: JSON.stringify({ workflowId: id, timestamp: Date.now() }),
|
||||||
})
|
})
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
|
|||||||
@@ -616,6 +616,8 @@ export async function POST(req: NextRequest, { params }: { params: Promise<{ id:
|
|||||||
input: callbackData.input,
|
input: callbackData.input,
|
||||||
error: callbackData.output.error,
|
error: callbackData.output.error,
|
||||||
durationMs: callbackData.executionTime || 0,
|
durationMs: callbackData.executionTime || 0,
|
||||||
|
startedAt: callbackData.startedAt,
|
||||||
|
endedAt: callbackData.endedAt,
|
||||||
...(iterationContext && {
|
...(iterationContext && {
|
||||||
iterationCurrent: iterationContext.iterationCurrent,
|
iterationCurrent: iterationContext.iterationCurrent,
|
||||||
iterationTotal: iterationContext.iterationTotal,
|
iterationTotal: iterationContext.iterationTotal,
|
||||||
@@ -641,6 +643,8 @@ export async function POST(req: NextRequest, { params }: { params: Promise<{ id:
|
|||||||
input: callbackData.input,
|
input: callbackData.input,
|
||||||
output: callbackData.output,
|
output: callbackData.output,
|
||||||
durationMs: callbackData.executionTime || 0,
|
durationMs: callbackData.executionTime || 0,
|
||||||
|
startedAt: callbackData.startedAt,
|
||||||
|
endedAt: callbackData.endedAt,
|
||||||
...(iterationContext && {
|
...(iterationContext && {
|
||||||
iterationCurrent: iterationContext.iterationCurrent,
|
iterationCurrent: iterationContext.iterationCurrent,
|
||||||
iterationTotal: iterationContext.iterationTotal,
|
iterationTotal: iterationContext.iterationTotal,
|
||||||
|
|||||||
@@ -361,7 +361,10 @@ export async function DELETE(
|
|||||||
const socketUrl = env.SOCKET_SERVER_URL || 'http://localhost:3002'
|
const socketUrl = env.SOCKET_SERVER_URL || 'http://localhost:3002'
|
||||||
const socketResponse = await fetch(`${socketUrl}/api/workflow-deleted`, {
|
const socketResponse = await fetch(`${socketUrl}/api/workflow-deleted`, {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
headers: { 'Content-Type': 'application/json' },
|
headers: {
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
'x-api-key': env.INTERNAL_API_SECRET,
|
||||||
|
},
|
||||||
body: JSON.stringify({ workflowId }),
|
body: JSON.stringify({ workflowId }),
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|||||||
@@ -254,7 +254,10 @@ export async function PUT(request: NextRequest, { params }: { params: Promise<{
|
|||||||
const socketUrl = env.SOCKET_SERVER_URL || 'http://localhost:3002'
|
const socketUrl = env.SOCKET_SERVER_URL || 'http://localhost:3002'
|
||||||
const notifyResponse = await fetch(`${socketUrl}/api/workflow-updated`, {
|
const notifyResponse = await fetch(`${socketUrl}/api/workflow-updated`, {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
headers: { 'Content-Type': 'application/json' },
|
headers: {
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
'x-api-key': env.INTERNAL_API_SECRET,
|
||||||
|
},
|
||||||
body: JSON.stringify({ workflowId }),
|
body: JSON.stringify({ workflowId }),
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|||||||
@@ -24,6 +24,7 @@ import {
|
|||||||
Cursor,
|
Cursor,
|
||||||
DatePicker,
|
DatePicker,
|
||||||
DocumentAttachment,
|
DocumentAttachment,
|
||||||
|
Download,
|
||||||
Duplicate,
|
Duplicate,
|
||||||
Expand,
|
Expand,
|
||||||
Eye,
|
Eye,
|
||||||
@@ -51,6 +52,7 @@ import {
|
|||||||
NoWrap,
|
NoWrap,
|
||||||
PanelLeft,
|
PanelLeft,
|
||||||
Play,
|
Play,
|
||||||
|
PlayOutline,
|
||||||
Popover,
|
Popover,
|
||||||
PopoverBackButton,
|
PopoverBackButton,
|
||||||
PopoverContent,
|
PopoverContent,
|
||||||
@@ -214,6 +216,9 @@ export default function PlaygroundPage() {
|
|||||||
<VariantRow label='primary'>
|
<VariantRow label='primary'>
|
||||||
<Button variant='primary'>Primary</Button>
|
<Button variant='primary'>Primary</Button>
|
||||||
</VariantRow>
|
</VariantRow>
|
||||||
|
<VariantRow label='destructive'>
|
||||||
|
<Button variant='destructive'>Destructive</Button>
|
||||||
|
</VariantRow>
|
||||||
<VariantRow label='secondary'>
|
<VariantRow label='secondary'>
|
||||||
<Button variant='secondary'>Secondary</Button>
|
<Button variant='secondary'>Secondary</Button>
|
||||||
</VariantRow>
|
</VariantRow>
|
||||||
@@ -290,6 +295,9 @@ export default function PlaygroundPage() {
|
|||||||
<VariantRow label='outline'>
|
<VariantRow label='outline'>
|
||||||
<Badge variant='outline'>Outline</Badge>
|
<Badge variant='outline'>Outline</Badge>
|
||||||
</VariantRow>
|
</VariantRow>
|
||||||
|
<VariantRow label='type'>
|
||||||
|
<Badge variant='type'>Type</Badge>
|
||||||
|
</VariantRow>
|
||||||
<VariantRow label='green'>
|
<VariantRow label='green'>
|
||||||
<Badge variant='green'>Green</Badge>
|
<Badge variant='green'>Green</Badge>
|
||||||
<Badge variant='green' dot>
|
<Badge variant='green' dot>
|
||||||
@@ -323,6 +331,9 @@ export default function PlaygroundPage() {
|
|||||||
<VariantRow label='teal'>
|
<VariantRow label='teal'>
|
||||||
<Badge variant='teal'>Teal</Badge>
|
<Badge variant='teal'>Teal</Badge>
|
||||||
</VariantRow>
|
</VariantRow>
|
||||||
|
<VariantRow label='cyan'>
|
||||||
|
<Badge variant='cyan'>Cyan</Badge>
|
||||||
|
</VariantRow>
|
||||||
<VariantRow label='gray'>
|
<VariantRow label='gray'>
|
||||||
<Badge variant='gray'>Gray</Badge>
|
<Badge variant='gray'>Gray</Badge>
|
||||||
</VariantRow>
|
</VariantRow>
|
||||||
@@ -996,6 +1007,7 @@ export default function PlaygroundPage() {
|
|||||||
{ Icon: Copy, name: 'Copy' },
|
{ Icon: Copy, name: 'Copy' },
|
||||||
{ Icon: Cursor, name: 'Cursor' },
|
{ Icon: Cursor, name: 'Cursor' },
|
||||||
{ Icon: DocumentAttachment, name: 'DocumentAttachment' },
|
{ Icon: DocumentAttachment, name: 'DocumentAttachment' },
|
||||||
|
{ Icon: Download, name: 'Download' },
|
||||||
{ Icon: Duplicate, name: 'Duplicate' },
|
{ Icon: Duplicate, name: 'Duplicate' },
|
||||||
{ Icon: Expand, name: 'Expand' },
|
{ Icon: Expand, name: 'Expand' },
|
||||||
{ Icon: Eye, name: 'Eye' },
|
{ Icon: Eye, name: 'Eye' },
|
||||||
@@ -1011,6 +1023,7 @@ export default function PlaygroundPage() {
|
|||||||
{ Icon: NoWrap, name: 'NoWrap' },
|
{ Icon: NoWrap, name: 'NoWrap' },
|
||||||
{ Icon: PanelLeft, name: 'PanelLeft' },
|
{ Icon: PanelLeft, name: 'PanelLeft' },
|
||||||
{ Icon: Play, name: 'Play' },
|
{ Icon: Play, name: 'Play' },
|
||||||
|
{ Icon: PlayOutline, name: 'PlayOutline' },
|
||||||
{ Icon: Redo, name: 'Redo' },
|
{ Icon: Redo, name: 'Redo' },
|
||||||
{ Icon: Rocket, name: 'Rocket' },
|
{ Icon: Rocket, name: 'Rocket' },
|
||||||
{ Icon: Trash, name: 'Trash' },
|
{ Icon: Trash, name: 'Trash' },
|
||||||
|
|||||||
@@ -530,18 +530,13 @@ export const NoteBlock = memo(function NoteBlock({
|
|||||||
<div className='group relative'>
|
<div className='group relative'>
|
||||||
<div
|
<div
|
||||||
className={cn(
|
className={cn(
|
||||||
'relative z-[20] w-[250px] cursor-default select-none rounded-[8px] border border-[var(--border)] bg-[var(--surface-2)]'
|
'note-drag-handle relative z-[20] w-[250px] cursor-grab select-none rounded-[8px] border border-[var(--border)] bg-[var(--surface-2)] [&:active]:cursor-grabbing'
|
||||||
)}
|
)}
|
||||||
onClick={handleClick}
|
onClick={handleClick}
|
||||||
>
|
>
|
||||||
<ActionBar blockId={id} blockType={type} disabled={!userPermissions.canEdit} />
|
<ActionBar blockId={id} blockType={type} disabled={!userPermissions.canEdit} />
|
||||||
|
|
||||||
<div
|
<div className='flex items-center justify-between border-[var(--divider)] border-b p-[8px]'>
|
||||||
className='note-drag-handle flex cursor-grab items-center justify-between border-[var(--divider)] border-b p-[8px] [&:active]:cursor-grabbing'
|
|
||||||
onMouseDown={(event) => {
|
|
||||||
event.stopPropagation()
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<div className='flex min-w-0 flex-1 items-center'>
|
<div className='flex min-w-0 flex-1 items-center'>
|
||||||
<span
|
<span
|
||||||
className={cn(
|
className={cn(
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { memo, useCallback, useEffect, useImperativeHandle, useMemo, useRef, useState } from 'react'
|
import { memo, useCallback, useEffect, useImperativeHandle, useMemo, useRef, useState } from 'react'
|
||||||
import { Check, Copy, Wand2 } from 'lucide-react'
|
import { Wand2 } from 'lucide-react'
|
||||||
import { useReactFlow } from 'reactflow'
|
import { useReactFlow } from 'reactflow'
|
||||||
import { Input } from '@/components/emcn'
|
import { Input } from '@/components/emcn'
|
||||||
import { Button } from '@/components/ui/button'
|
import { Button } from '@/components/ui/button'
|
||||||
@@ -40,8 +40,6 @@ interface ShortInputProps {
|
|||||||
disabled?: boolean
|
disabled?: boolean
|
||||||
/** Whether the input is read-only */
|
/** Whether the input is read-only */
|
||||||
readOnly?: boolean
|
readOnly?: boolean
|
||||||
/** Whether to show a copy button */
|
|
||||||
showCopyButton?: boolean
|
|
||||||
/** Whether to use webhook URL as value */
|
/** Whether to use webhook URL as value */
|
||||||
useWebhookUrl?: boolean
|
useWebhookUrl?: boolean
|
||||||
/** Ref to expose wand control handlers to parent */
|
/** Ref to expose wand control handlers to parent */
|
||||||
@@ -59,7 +57,6 @@ interface ShortInputProps {
|
|||||||
* - Handles drag-and-drop for connections and variable references
|
* - Handles drag-and-drop for connections and variable references
|
||||||
* - Provides environment variable and tag autocomplete
|
* - Provides environment variable and tag autocomplete
|
||||||
* - Password masking with reveal on focus
|
* - Password masking with reveal on focus
|
||||||
* - Copy to clipboard functionality
|
|
||||||
* - Integrates with ReactFlow for zoom control
|
* - Integrates with ReactFlow for zoom control
|
||||||
*/
|
*/
|
||||||
export const ShortInput = memo(function ShortInput({
|
export const ShortInput = memo(function ShortInput({
|
||||||
@@ -74,14 +71,12 @@ export const ShortInput = memo(function ShortInput({
|
|||||||
previewValue,
|
previewValue,
|
||||||
disabled = false,
|
disabled = false,
|
||||||
readOnly = false,
|
readOnly = false,
|
||||||
showCopyButton = false,
|
|
||||||
useWebhookUrl = false,
|
useWebhookUrl = false,
|
||||||
wandControlRef,
|
wandControlRef,
|
||||||
hideInternalWand = false,
|
hideInternalWand = false,
|
||||||
}: ShortInputProps) {
|
}: ShortInputProps) {
|
||||||
const [localContent, setLocalContent] = useState<string>('')
|
const [localContent, setLocalContent] = useState<string>('')
|
||||||
const [isFocused, setIsFocused] = useState(false)
|
const [isFocused, setIsFocused] = useState(false)
|
||||||
const [copied, setCopied] = useState(false)
|
|
||||||
const persistSubBlockValueRef = useRef<(value: string) => void>(() => {})
|
const persistSubBlockValueRef = useRef<(value: string) => void>(() => {})
|
||||||
|
|
||||||
const justPastedRef = useRef(false)
|
const justPastedRef = useRef(false)
|
||||||
@@ -278,18 +273,6 @@ export const ShortInput = memo(function ShortInput({
|
|||||||
[reactFlowInstance]
|
[reactFlowInstance]
|
||||||
)
|
)
|
||||||
|
|
||||||
/**
|
|
||||||
* Handles copying the value to the clipboard.
|
|
||||||
*/
|
|
||||||
const handleCopy = useCallback(() => {
|
|
||||||
const textToCopy = useWebhookUrl ? webhookManagement?.webhookUrl : value?.toString()
|
|
||||||
if (textToCopy) {
|
|
||||||
navigator.clipboard.writeText(textToCopy)
|
|
||||||
setCopied(true)
|
|
||||||
setTimeout(() => setCopied(false), 2000)
|
|
||||||
}
|
|
||||||
}, [useWebhookUrl, webhookManagement?.webhookUrl, value])
|
|
||||||
|
|
||||||
const handleBlur = useCallback(() => {
|
const handleBlur = useCallback(() => {
|
||||||
setIsFocused(false)
|
setIsFocused(false)
|
||||||
}, [])
|
}, [])
|
||||||
@@ -366,10 +349,7 @@ export const ShortInput = memo(function ShortInput({
|
|||||||
<>
|
<>
|
||||||
<Input
|
<Input
|
||||||
ref={ref as React.RefObject<HTMLInputElement>}
|
ref={ref as React.RefObject<HTMLInputElement>}
|
||||||
className={cn(
|
className='allow-scroll w-full overflow-auto text-transparent caret-foreground [-ms-overflow-style:none] [scrollbar-width:none] placeholder:text-muted-foreground/50 [&::-webkit-scrollbar]:hidden'
|
||||||
'allow-scroll w-full overflow-auto text-transparent caret-foreground [-ms-overflow-style:none] [scrollbar-width:none] placeholder:text-muted-foreground/50 [&::-webkit-scrollbar]:hidden',
|
|
||||||
showCopyButton && 'pr-14'
|
|
||||||
)}
|
|
||||||
readOnly={readOnly}
|
readOnly={readOnly}
|
||||||
placeholder={placeholder ?? ''}
|
placeholder={placeholder ?? ''}
|
||||||
type='text'
|
type='text'
|
||||||
@@ -392,8 +372,7 @@ export const ShortInput = memo(function ShortInput({
|
|||||||
<div
|
<div
|
||||||
ref={overlayRef}
|
ref={overlayRef}
|
||||||
className={cn(
|
className={cn(
|
||||||
'pointer-events-none absolute inset-0 flex items-center overflow-x-auto bg-transparent px-[8px] py-[6px] font-medium font-sans text-foreground text-sm [-ms-overflow-style:none] [scrollbar-width:none] [&::-webkit-scrollbar]:hidden',
|
'pointer-events-none absolute inset-0 flex items-center overflow-x-auto bg-transparent px-[8px] py-[6px] pr-3 font-medium font-sans text-foreground text-sm [-ms-overflow-style:none] [scrollbar-width:none] [&::-webkit-scrollbar]:hidden',
|
||||||
showCopyButton ? 'pr-14' : 'pr-3',
|
|
||||||
(isPreview || disabled) && 'opacity-50'
|
(isPreview || disabled) && 'opacity-50'
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
@@ -404,27 +383,6 @@ export const ShortInput = memo(function ShortInput({
|
|||||||
}}
|
}}
|
||||||
</SubBlockInputController>
|
</SubBlockInputController>
|
||||||
|
|
||||||
{/* Copy Button */}
|
|
||||||
{showCopyButton && value && (
|
|
||||||
<div className='pointer-events-none absolute top-0 right-0 bottom-0 z-10 flex w-14 items-center justify-end pr-2 opacity-0 transition-opacity group-hover:opacity-100'>
|
|
||||||
<Button
|
|
||||||
type='button'
|
|
||||||
variant='ghost'
|
|
||||||
size='icon'
|
|
||||||
onClick={handleCopy}
|
|
||||||
disabled={!value}
|
|
||||||
className='pointer-events-auto h-6 w-6 p-0'
|
|
||||||
aria-label='Copy value'
|
|
||||||
>
|
|
||||||
{copied ? (
|
|
||||||
<Check className='h-3.5 w-3.5 text-green-500' />
|
|
||||||
) : (
|
|
||||||
<Copy className='h-3.5 w-3.5 text-muted-foreground' />
|
|
||||||
)}
|
|
||||||
</Button>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
|
|
||||||
{/* Wand Button - only show if not hidden by parent */}
|
{/* Wand Button - only show if not hidden by parent */}
|
||||||
{isWandEnabled && !isPreview && !wandHook.isStreaming && !hideInternalWand && (
|
{isWandEnabled && !isPreview && !wandHook.isStreaming && !hideInternalWand && (
|
||||||
<div className='-translate-y-1/2 absolute top-1/2 right-3 z-10 flex items-center gap-1 opacity-0 transition-opacity group-hover:opacity-100'>
|
<div className='-translate-y-1/2 absolute top-1/2 right-3 z-10 flex items-center gap-1 opacity-0 transition-opacity group-hover:opacity-100'>
|
||||||
|
|||||||
@@ -14,6 +14,8 @@ interface KeyboardNavigationHandlerProps {
|
|||||||
flatTagList: Array<{ tag: string; group?: BlockTagGroup }>
|
flatTagList: Array<{ tag: string; group?: BlockTagGroup }>
|
||||||
nestedBlockTagGroups: NestedBlockTagGroup[]
|
nestedBlockTagGroups: NestedBlockTagGroup[]
|
||||||
handleTagSelect: (tag: string, group?: BlockTagGroup) => void
|
handleTagSelect: (tag: string, group?: BlockTagGroup) => void
|
||||||
|
/** Called when entering a folder from root level via keyboard navigation */
|
||||||
|
onFolderEnter?: () => void
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -107,6 +109,7 @@ export const KeyboardNavigationHandler: React.FC<KeyboardNavigationHandlerProps>
|
|||||||
flatTagList,
|
flatTagList,
|
||||||
nestedBlockTagGroups,
|
nestedBlockTagGroups,
|
||||||
handleTagSelect,
|
handleTagSelect,
|
||||||
|
onFolderEnter,
|
||||||
}) => {
|
}) => {
|
||||||
const { openFolder, closeFolder, isInFolder, currentFolder, setKeyboardNav } = usePopoverContext()
|
const { openFolder, closeFolder, isInFolder, currentFolder, setKeyboardNav } = usePopoverContext()
|
||||||
const nestedNav = useNestedNavigation()
|
const nestedNav = useNestedNavigation()
|
||||||
@@ -251,7 +254,7 @@ export const KeyboardNavigationHandler: React.FC<KeyboardNavigationHandlerProps>
|
|||||||
} else if (currentVisibleIndex < visibleIndices.length - 1) {
|
} else if (currentVisibleIndex < visibleIndices.length - 1) {
|
||||||
newIndex = visibleIndices[currentVisibleIndex + 1]
|
newIndex = visibleIndices[currentVisibleIndex + 1]
|
||||||
} else {
|
} else {
|
||||||
newIndex = visibleIndices[0]
|
newIndex = selectedIndex
|
||||||
}
|
}
|
||||||
setSelectedIndex(newIndex)
|
setSelectedIndex(newIndex)
|
||||||
scrollIntoView()
|
scrollIntoView()
|
||||||
@@ -269,7 +272,7 @@ export const KeyboardNavigationHandler: React.FC<KeyboardNavigationHandlerProps>
|
|||||||
} else if (currentVisibleIndex > 0) {
|
} else if (currentVisibleIndex > 0) {
|
||||||
newIndex = visibleIndices[currentVisibleIndex - 1]
|
newIndex = visibleIndices[currentVisibleIndex - 1]
|
||||||
} else {
|
} else {
|
||||||
newIndex = visibleIndices[visibleIndices.length - 1]
|
newIndex = selectedIndex
|
||||||
}
|
}
|
||||||
setSelectedIndex(newIndex)
|
setSelectedIndex(newIndex)
|
||||||
scrollIntoView()
|
scrollIntoView()
|
||||||
@@ -295,6 +298,7 @@ export const KeyboardNavigationHandler: React.FC<KeyboardNavigationHandlerProps>
|
|||||||
currentFolderInfo.parentTag,
|
currentFolderInfo.parentTag,
|
||||||
currentFolderInfo.group
|
currentFolderInfo.group
|
||||||
)
|
)
|
||||||
|
onFolderEnter?.()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break
|
break
|
||||||
@@ -346,6 +350,7 @@ export const KeyboardNavigationHandler: React.FC<KeyboardNavigationHandlerProps>
|
|||||||
handleTagSelect,
|
handleTagSelect,
|
||||||
nestedNav,
|
nestedNav,
|
||||||
setKeyboardNav,
|
setKeyboardNav,
|
||||||
|
onFolderEnter,
|
||||||
])
|
])
|
||||||
|
|
||||||
return null
|
return null
|
||||||
|
|||||||
@@ -444,10 +444,12 @@ interface NestedTagRendererProps {
|
|||||||
nestedTag: NestedTag
|
nestedTag: NestedTag
|
||||||
group: NestedBlockTagGroup
|
group: NestedBlockTagGroup
|
||||||
flatTagList: Array<{ tag: string; group?: BlockTagGroup }>
|
flatTagList: Array<{ tag: string; group?: BlockTagGroup }>
|
||||||
|
/** Map from tag string to index for O(1) lookups */
|
||||||
|
flatTagIndexMap: Map<string, number>
|
||||||
selectedIndex: number
|
selectedIndex: number
|
||||||
setSelectedIndex: (index: number) => void
|
setSelectedIndex: (index: number) => void
|
||||||
handleTagSelect: (tag: string, blockGroup?: BlockTagGroup) => void
|
handleTagSelect: (tag: string, blockGroup?: BlockTagGroup) => void
|
||||||
itemRefs: React.RefObject<Map<number, HTMLElement>>
|
itemRefs: React.RefObject<Map<string, HTMLElement>>
|
||||||
blocks: Record<string, BlockState>
|
blocks: Record<string, BlockState>
|
||||||
getMergedSubBlocks: (blockId: string) => Record<string, any>
|
getMergedSubBlocks: (blockId: string) => Record<string, any>
|
||||||
}
|
}
|
||||||
@@ -469,6 +471,7 @@ interface FolderContentsProps extends NestedTagRendererProps {
|
|||||||
const FolderContentsInner: React.FC<FolderContentsProps> = ({
|
const FolderContentsInner: React.FC<FolderContentsProps> = ({
|
||||||
group,
|
group,
|
||||||
flatTagList,
|
flatTagList,
|
||||||
|
flatTagIndexMap,
|
||||||
selectedIndex,
|
selectedIndex,
|
||||||
setSelectedIndex,
|
setSelectedIndex,
|
||||||
handleTagSelect,
|
handleTagSelect,
|
||||||
@@ -483,7 +486,7 @@ const FolderContentsInner: React.FC<FolderContentsProps> = ({
|
|||||||
const currentNestedTag = nestedPath.length > 0 ? nestedPath[nestedPath.length - 1] : nestedTag
|
const currentNestedTag = nestedPath.length > 0 ? nestedPath[nestedPath.length - 1] : nestedTag
|
||||||
|
|
||||||
const parentTagIndex = currentNestedTag.parentTag
|
const parentTagIndex = currentNestedTag.parentTag
|
||||||
? flatTagList.findIndex((item) => item.tag === currentNestedTag.parentTag)
|
? (flatTagIndexMap.get(currentNestedTag.parentTag) ?? -1)
|
||||||
: -1
|
: -1
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@@ -493,7 +496,6 @@ const FolderContentsInner: React.FC<FolderContentsProps> = ({
|
|||||||
<PopoverItem
|
<PopoverItem
|
||||||
active={parentTagIndex === selectedIndex && parentTagIndex >= 0}
|
active={parentTagIndex === selectedIndex && parentTagIndex >= 0}
|
||||||
onMouseEnter={() => {
|
onMouseEnter={() => {
|
||||||
// Skip selection update during keyboard navigation to prevent scroll-triggered selection changes
|
|
||||||
if (isKeyboardNav) return
|
if (isKeyboardNav) return
|
||||||
setKeyboardNav(false)
|
setKeyboardNav(false)
|
||||||
if (parentTagIndex >= 0) setSelectedIndex(parentTagIndex)
|
if (parentTagIndex >= 0) setSelectedIndex(parentTagIndex)
|
||||||
@@ -504,8 +506,8 @@ const FolderContentsInner: React.FC<FolderContentsProps> = ({
|
|||||||
handleTagSelect(currentNestedTag.parentTag!, group)
|
handleTagSelect(currentNestedTag.parentTag!, group)
|
||||||
}}
|
}}
|
||||||
ref={(el) => {
|
ref={(el) => {
|
||||||
if (el && parentTagIndex >= 0) {
|
if (el && currentNestedTag.parentTag) {
|
||||||
itemRefs.current?.set(parentTagIndex, el)
|
itemRefs.current?.set(currentNestedTag.parentTag, el)
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
@@ -515,7 +517,7 @@ const FolderContentsInner: React.FC<FolderContentsProps> = ({
|
|||||||
|
|
||||||
{/* Render leaf children as PopoverItems */}
|
{/* Render leaf children as PopoverItems */}
|
||||||
{currentNestedTag.children?.map((child) => {
|
{currentNestedTag.children?.map((child) => {
|
||||||
const childGlobalIndex = flatTagList.findIndex((item) => item.tag === child.fullTag)
|
const childGlobalIndex = flatTagIndexMap.get(child.fullTag) ?? -1
|
||||||
|
|
||||||
const tagParts = child.fullTag.split('.')
|
const tagParts = child.fullTag.split('.')
|
||||||
const outputPath = tagParts.slice(1).join('.')
|
const outputPath = tagParts.slice(1).join('.')
|
||||||
@@ -550,8 +552,8 @@ const FolderContentsInner: React.FC<FolderContentsProps> = ({
|
|||||||
handleTagSelect(child.fullTag, group)
|
handleTagSelect(child.fullTag, group)
|
||||||
}}
|
}}
|
||||||
ref={(el) => {
|
ref={(el) => {
|
||||||
if (el && childGlobalIndex >= 0) {
|
if (el) {
|
||||||
itemRefs.current?.set(childGlobalIndex, el)
|
itemRefs.current?.set(child.fullTag, el)
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
@@ -568,7 +570,7 @@ const FolderContentsInner: React.FC<FolderContentsProps> = ({
|
|||||||
{/* Render nested children as clickable folder items */}
|
{/* Render nested children as clickable folder items */}
|
||||||
{currentNestedTag.nestedChildren?.map((nestedChild) => {
|
{currentNestedTag.nestedChildren?.map((nestedChild) => {
|
||||||
const parentGlobalIndex = nestedChild.parentTag
|
const parentGlobalIndex = nestedChild.parentTag
|
||||||
? flatTagList.findIndex((item) => item.tag === nestedChild.parentTag)
|
? (flatTagIndexMap.get(nestedChild.parentTag) ?? -1)
|
||||||
: -1
|
: -1
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@@ -583,12 +585,11 @@ const FolderContentsInner: React.FC<FolderContentsProps> = ({
|
|||||||
onMouseDown={(e) => {
|
onMouseDown={(e) => {
|
||||||
e.preventDefault()
|
e.preventDefault()
|
||||||
e.stopPropagation()
|
e.stopPropagation()
|
||||||
// Navigate into the subfolder on click
|
|
||||||
onNavigateIn(nestedChild)
|
onNavigateIn(nestedChild)
|
||||||
}}
|
}}
|
||||||
ref={(el) => {
|
ref={(el) => {
|
||||||
if (el && parentGlobalIndex >= 0) {
|
if (el && nestedChild.parentTag) {
|
||||||
itemRefs.current?.set(parentGlobalIndex, el)
|
itemRefs.current?.set(nestedChild.parentTag, el)
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
@@ -605,7 +606,7 @@ const FolderContentsInner: React.FC<FolderContentsProps> = ({
|
|||||||
* Wrapper component that uses shared nested navigation state from context.
|
* Wrapper component that uses shared nested navigation state from context.
|
||||||
* Handles registration of the base folder and navigation callbacks.
|
* Handles registration of the base folder and navigation callbacks.
|
||||||
*/
|
*/
|
||||||
const FolderContents: React.FC<NestedTagRendererProps> = (props) => {
|
const FolderContents: React.FC<Omit<NestedTagRendererProps, never>> = (props) => {
|
||||||
const nestedNav = useNestedNavigation()
|
const nestedNav = useNestedNavigation()
|
||||||
const { currentFolder } = usePopoverContext()
|
const { currentFolder } = usePopoverContext()
|
||||||
|
|
||||||
@@ -638,6 +639,7 @@ const NestedTagRenderer: React.FC<NestedTagRendererProps> = ({
|
|||||||
nestedTag,
|
nestedTag,
|
||||||
group,
|
group,
|
||||||
flatTagList,
|
flatTagList,
|
||||||
|
flatTagIndexMap,
|
||||||
selectedIndex,
|
selectedIndex,
|
||||||
setSelectedIndex,
|
setSelectedIndex,
|
||||||
handleTagSelect,
|
handleTagSelect,
|
||||||
@@ -653,7 +655,7 @@ const NestedTagRenderer: React.FC<NestedTagRendererProps> = ({
|
|||||||
const folderId = `${group.blockId}-${nestedTag.key}`
|
const folderId = `${group.blockId}-${nestedTag.key}`
|
||||||
|
|
||||||
const parentGlobalIndex = nestedTag.parentTag
|
const parentGlobalIndex = nestedTag.parentTag
|
||||||
? flatTagList.findIndex((item) => item.tag === nestedTag.parentTag)
|
? (flatTagIndexMap.get(nestedTag.parentTag) ?? -1)
|
||||||
: -1
|
: -1
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@@ -675,8 +677,8 @@ const NestedTagRenderer: React.FC<NestedTagRendererProps> = ({
|
|||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
ref={(el) => {
|
ref={(el) => {
|
||||||
if (el && parentGlobalIndex >= 0) {
|
if (el && nestedTag.parentTag) {
|
||||||
itemRefs.current?.set(parentGlobalIndex, el)
|
itemRefs.current?.set(nestedTag.parentTag, el)
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
@@ -684,6 +686,7 @@ const NestedTagRenderer: React.FC<NestedTagRendererProps> = ({
|
|||||||
nestedTag={nestedTag}
|
nestedTag={nestedTag}
|
||||||
group={group}
|
group={group}
|
||||||
flatTagList={flatTagList}
|
flatTagList={flatTagList}
|
||||||
|
flatTagIndexMap={flatTagIndexMap}
|
||||||
selectedIndex={selectedIndex}
|
selectedIndex={selectedIndex}
|
||||||
setSelectedIndex={setSelectedIndex}
|
setSelectedIndex={setSelectedIndex}
|
||||||
handleTagSelect={handleTagSelect}
|
handleTagSelect={handleTagSelect}
|
||||||
@@ -695,10 +698,7 @@ const NestedTagRenderer: React.FC<NestedTagRendererProps> = ({
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Leaf tag - render as a simple PopoverItem
|
const globalIndex = nestedTag.fullTag ? (flatTagIndexMap.get(nestedTag.fullTag) ?? -1) : -1
|
||||||
const globalIndex = nestedTag.fullTag
|
|
||||||
? flatTagList.findIndex((item) => item.tag === nestedTag.fullTag)
|
|
||||||
: -1
|
|
||||||
|
|
||||||
let tagDescription = ''
|
let tagDescription = ''
|
||||||
|
|
||||||
@@ -751,8 +751,8 @@ const NestedTagRenderer: React.FC<NestedTagRendererProps> = ({
|
|||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
ref={(el) => {
|
ref={(el) => {
|
||||||
if (el && globalIndex >= 0) {
|
if (el && nestedTag.fullTag) {
|
||||||
itemRefs.current?.set(globalIndex, el)
|
itemRefs.current?.set(nestedTag.fullTag, el)
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
@@ -767,7 +767,7 @@ const NestedTagRenderer: React.FC<NestedTagRendererProps> = ({
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Hook to get mouse enter handler that respects keyboard navigation mode.
|
* Hook to get mouse enter handler that respects keyboard navigation state.
|
||||||
* Returns a handler that only updates selection if not in keyboard mode.
|
* Returns a handler that only updates selection if not in keyboard mode.
|
||||||
*/
|
*/
|
||||||
const useKeyboardAwareMouseEnter = (
|
const useKeyboardAwareMouseEnter = (
|
||||||
@@ -794,7 +794,7 @@ const VariableTagItem: React.FC<{
|
|||||||
selectedIndex: number
|
selectedIndex: number
|
||||||
setSelectedIndex: (index: number) => void
|
setSelectedIndex: (index: number) => void
|
||||||
handleTagSelect: (tag: string) => void
|
handleTagSelect: (tag: string) => void
|
||||||
itemRefs: React.RefObject<Map<number, HTMLElement>>
|
itemRefs: React.RefObject<Map<string, HTMLElement>>
|
||||||
variableInfo: { type: string; id: string } | null
|
variableInfo: { type: string; id: string } | null
|
||||||
}> = ({
|
}> = ({
|
||||||
tag,
|
tag,
|
||||||
@@ -819,8 +819,8 @@ const VariableTagItem: React.FC<{
|
|||||||
handleTagSelect(tag)
|
handleTagSelect(tag)
|
||||||
}}
|
}}
|
||||||
ref={(el) => {
|
ref={(el) => {
|
||||||
if (el && globalIndex >= 0) {
|
if (el) {
|
||||||
itemRefs.current?.set(globalIndex, el)
|
itemRefs.current?.set(tag, el)
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
@@ -845,7 +845,7 @@ const BlockRootTagItem: React.FC<{
|
|||||||
selectedIndex: number
|
selectedIndex: number
|
||||||
setSelectedIndex: (index: number) => void
|
setSelectedIndex: (index: number) => void
|
||||||
handleTagSelect: (tag: string, group?: BlockTagGroup) => void
|
handleTagSelect: (tag: string, group?: BlockTagGroup) => void
|
||||||
itemRefs: React.RefObject<Map<number, HTMLElement>>
|
itemRefs: React.RefObject<Map<string, HTMLElement>>
|
||||||
group: BlockTagGroup
|
group: BlockTagGroup
|
||||||
tagIcon: string | React.ComponentType<{ className?: string }>
|
tagIcon: string | React.ComponentType<{ className?: string }>
|
||||||
blockColor: string
|
blockColor: string
|
||||||
@@ -875,8 +875,8 @@ const BlockRootTagItem: React.FC<{
|
|||||||
handleTagSelect(rootTag, group)
|
handleTagSelect(rootTag, group)
|
||||||
}}
|
}}
|
||||||
ref={(el) => {
|
ref={(el) => {
|
||||||
if (el && rootTagGlobalIndex >= 0) {
|
if (el) {
|
||||||
itemRefs.current?.set(rootTagGlobalIndex, el)
|
itemRefs.current?.set(rootTag, el)
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
@@ -916,16 +916,12 @@ const TagDropdownBackButton: React.FC = () => {
|
|||||||
|
|
||||||
const handleBackClick = (e: React.MouseEvent) => {
|
const handleBackClick = (e: React.MouseEvent) => {
|
||||||
e.stopPropagation()
|
e.stopPropagation()
|
||||||
// Try to navigate back in nested path first
|
|
||||||
if (nestedNav?.navigateBack()) {
|
if (nestedNav?.navigateBack()) {
|
||||||
// Successfully navigated back one level
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
// At root folder level, close the folder
|
|
||||||
closeFolder()
|
closeFolder()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Just render the back button - the parent tag is rendered as the first item in FolderContentsInner
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
className={cn(
|
className={cn(
|
||||||
@@ -986,7 +982,7 @@ export const TagDropdown: React.FC<TagDropdownProps> = ({
|
|||||||
inputRef,
|
inputRef,
|
||||||
}) => {
|
}) => {
|
||||||
const [selectedIndex, setSelectedIndex] = useState(0)
|
const [selectedIndex, setSelectedIndex] = useState(0)
|
||||||
const itemRefs = useRef<Map<number, HTMLElement>>(new Map())
|
const itemRefs = useRef<Map<string, HTMLElement>>(new Map())
|
||||||
|
|
||||||
const [nestedPath, setNestedPath] = useState<NestedTag[]>([])
|
const [nestedPath, setNestedPath] = useState<NestedTag[]>([])
|
||||||
const baseFolderRef = useRef<{
|
const baseFolderRef = useRef<{
|
||||||
@@ -998,6 +994,11 @@ export const TagDropdown: React.FC<TagDropdownProps> = ({
|
|||||||
const handleTagSelectRef = useRef<((tag: string, group?: BlockTagGroup) => void) | null>(null)
|
const handleTagSelectRef = useRef<((tag: string, group?: BlockTagGroup) => void) | null>(null)
|
||||||
const scrollAreaRef = useRef<HTMLDivElement>(null)
|
const scrollAreaRef = useRef<HTMLDivElement>(null)
|
||||||
|
|
||||||
|
const inputValueRef = useRef(inputValue)
|
||||||
|
const cursorPositionRef = useRef(cursorPosition)
|
||||||
|
inputValueRef.current = inputValue
|
||||||
|
cursorPositionRef.current = cursorPosition
|
||||||
|
|
||||||
const { blocks, edges, loops, parallels } = useWorkflowStore(
|
const { blocks, edges, loops, parallels } = useWorkflowStore(
|
||||||
useShallow((state) => ({
|
useShallow((state) => ({
|
||||||
blocks: state.blocks,
|
blocks: state.blocks,
|
||||||
@@ -1700,27 +1701,23 @@ export const TagDropdown: React.FC<TagDropdownProps> = ({
|
|||||||
return list
|
return list
|
||||||
}, [variableTags, nestedBlockTagGroups])
|
}, [variableTags, nestedBlockTagGroups])
|
||||||
|
|
||||||
useEffect(() => {
|
const flatTagIndexMap = useMemo(() => {
|
||||||
if (!visible || selectedIndex < 0) return
|
const map = new Map<string, number>()
|
||||||
|
flatTagList.forEach((item, index) => {
|
||||||
const element = itemRefs.current.get(selectedIndex)
|
map.set(item.tag, index)
|
||||||
if (element) {
|
|
||||||
element.scrollIntoView({
|
|
||||||
behavior: 'auto',
|
|
||||||
block: 'nearest',
|
|
||||||
})
|
})
|
||||||
}
|
return map
|
||||||
}, [selectedIndex, visible])
|
}, [flatTagList])
|
||||||
|
|
||||||
const handleTagSelect = useCallback(
|
const handleTagSelect = useCallback(
|
||||||
(tag: string, blockGroup?: BlockTagGroup) => {
|
(tag: string, blockGroup?: BlockTagGroup) => {
|
||||||
let liveCursor = cursorPosition
|
let liveCursor = cursorPositionRef.current
|
||||||
let liveValue = inputValue
|
let liveValue = inputValueRef.current
|
||||||
|
|
||||||
if (typeof window !== 'undefined' && document?.activeElement) {
|
if (typeof window !== 'undefined' && document?.activeElement) {
|
||||||
const activeEl = document.activeElement as HTMLInputElement | HTMLTextAreaElement | null
|
const activeEl = document.activeElement as HTMLInputElement | HTMLTextAreaElement | null
|
||||||
if (activeEl && typeof activeEl.selectionStart === 'number') {
|
if (activeEl && typeof activeEl.selectionStart === 'number') {
|
||||||
liveCursor = activeEl.selectionStart ?? cursorPosition
|
liveCursor = activeEl.selectionStart ?? cursorPositionRef.current
|
||||||
if ('value' in activeEl && typeof activeEl.value === 'string') {
|
if ('value' in activeEl && typeof activeEl.value === 'string') {
|
||||||
liveValue = activeEl.value
|
liveValue = activeEl.value
|
||||||
}
|
}
|
||||||
@@ -1805,7 +1802,7 @@ export const TagDropdown: React.FC<TagDropdownProps> = ({
|
|||||||
onSelect(newValue)
|
onSelect(newValue)
|
||||||
onClose?.()
|
onClose?.()
|
||||||
},
|
},
|
||||||
[inputValue, cursorPosition, workflowVariables, onSelect, onClose, getMergedSubBlocks]
|
[workflowVariables, onSelect, onClose, getMergedSubBlocks]
|
||||||
)
|
)
|
||||||
|
|
||||||
handleTagSelectRef.current = handleTagSelect
|
handleTagSelectRef.current = handleTagSelect
|
||||||
@@ -1877,9 +1874,6 @@ export const TagDropdown: React.FC<TagDropdownProps> = ({
|
|||||||
},
|
},
|
||||||
registerFolder: (folderId, folderTitle, baseTag, group) => {
|
registerFolder: (folderId, folderTitle, baseTag, group) => {
|
||||||
baseFolderRef.current = { id: folderId, title: folderTitle, baseTag, group }
|
baseFolderRef.current = { id: folderId, title: folderTitle, baseTag, group }
|
||||||
if (scrollAreaRef.current) {
|
|
||||||
scrollAreaRef.current.scrollTop = 0
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
[nestedPath]
|
[nestedPath]
|
||||||
@@ -1892,13 +1886,9 @@ export const TagDropdown: React.FC<TagDropdownProps> = ({
|
|||||||
}
|
}
|
||||||
}, [visible])
|
}, [visible])
|
||||||
|
|
||||||
useEffect(() => setSelectedIndex(0), [searchTerm])
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (selectedIndex >= flatTagList.length) {
|
setSelectedIndex(0)
|
||||||
setSelectedIndex(Math.max(0, flatTagList.length - 1))
|
}, [flatTagList.length])
|
||||||
}
|
|
||||||
}, [flatTagList.length, selectedIndex])
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (visible) {
|
if (visible) {
|
||||||
@@ -1956,6 +1946,11 @@ export const TagDropdown: React.FC<TagDropdownProps> = ({
|
|||||||
flatTagList={flatTagList}
|
flatTagList={flatTagList}
|
||||||
nestedBlockTagGroups={nestedBlockTagGroups}
|
nestedBlockTagGroups={nestedBlockTagGroups}
|
||||||
handleTagSelect={handleTagSelect}
|
handleTagSelect={handleTagSelect}
|
||||||
|
onFolderEnter={() => {
|
||||||
|
if (scrollAreaRef.current) {
|
||||||
|
scrollAreaRef.current.scrollTop = 0
|
||||||
|
}
|
||||||
|
}}
|
||||||
/>
|
/>
|
||||||
<PopoverContent
|
<PopoverContent
|
||||||
maxHeight={240}
|
maxHeight={240}
|
||||||
@@ -1984,7 +1979,7 @@ export const TagDropdown: React.FC<TagDropdownProps> = ({
|
|||||||
</PopoverSection>
|
</PopoverSection>
|
||||||
{variableTags.map((tag: string) => {
|
{variableTags.map((tag: string) => {
|
||||||
const variableInfo = variableInfoMap?.[tag] || null
|
const variableInfo = variableInfoMap?.[tag] || null
|
||||||
const globalIndex = flatTagList.findIndex((item) => item.tag === tag)
|
const globalIndex = flatTagIndexMap.get(tag) ?? -1
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<VariableTagItem
|
<VariableTagItem
|
||||||
@@ -2027,7 +2022,7 @@ export const TagDropdown: React.FC<TagDropdownProps> = ({
|
|||||||
const rootTagFromTags = group.tags.find((tag) => tag === normalizedBlockName)
|
const rootTagFromTags = group.tags.find((tag) => tag === normalizedBlockName)
|
||||||
const rootTag = rootTagFromTags || normalizedBlockName
|
const rootTag = rootTagFromTags || normalizedBlockName
|
||||||
|
|
||||||
const rootTagGlobalIndex = flatTagList.findIndex((item) => item.tag === rootTag)
|
const rootTagGlobalIndex = flatTagIndexMap.get(rootTag) ?? -1
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div key={group.blockId}>
|
<div key={group.blockId}>
|
||||||
@@ -2054,6 +2049,7 @@ export const TagDropdown: React.FC<TagDropdownProps> = ({
|
|||||||
nestedTag={nestedTag}
|
nestedTag={nestedTag}
|
||||||
group={group}
|
group={group}
|
||||||
flatTagList={flatTagList}
|
flatTagList={flatTagList}
|
||||||
|
flatTagIndexMap={flatTagIndexMap}
|
||||||
selectedIndex={selectedIndex}
|
selectedIndex={selectedIndex}
|
||||||
setSelectedIndex={setSelectedIndex}
|
setSelectedIndex={setSelectedIndex}
|
||||||
handleTagSelect={handleTagSelect}
|
handleTagSelect={handleTagSelect}
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ interface TextProps {
|
|||||||
*
|
*
|
||||||
* @remarks
|
* @remarks
|
||||||
* - Automatically detects and renders HTML content safely
|
* - Automatically detects and renders HTML content safely
|
||||||
* - Applies prose styling for HTML content (links, code, lists, etc.)
|
* - Applies consistent styling for HTML content (links, code, lists, etc.)
|
||||||
* - Falls back to plain text rendering for non-HTML content
|
* - Falls back to plain text rendering for non-HTML content
|
||||||
*
|
*
|
||||||
* Note: This component renders trusted, internally-defined content only
|
* Note: This component renders trusted, internally-defined content only
|
||||||
@@ -33,7 +33,7 @@ export function Text({ blockId, subBlockId, content, className }: TextProps) {
|
|||||||
className={`rounded-md border bg-[var(--surface-2)] p-4 shadow-sm ${className || ''}`}
|
className={`rounded-md border bg-[var(--surface-2)] p-4 shadow-sm ${className || ''}`}
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
className='prose prose-sm dark:prose-invert max-w-none break-words text-sm [&_a]:text-blue-600 [&_a]:underline [&_a]:hover:text-blue-700 [&_a]:dark:text-blue-400 [&_a]:dark:hover:text-blue-300 [&_code]:rounded [&_code]:bg-muted [&_code]:px-1 [&_code]:py-0.5 [&_code]:text-xs [&_strong]:font-semibold [&_ul]:ml-5 [&_ul]:list-disc'
|
className='max-w-none break-words text-[var(--text-secondary)] text-sm [&_a]:text-[var(--brand-secondary)] [&_a]:underline [&_a]:underline-offset-2 [&_a]:hover:brightness-110 [&_code]:rounded [&_code]:bg-[var(--surface-5)] [&_code]:px-1 [&_code]:py-0.5 [&_code]:text-[var(--text-tertiary)] [&_code]:text-xs [&_strong]:font-medium [&_strong]:text-[var(--text-primary)] [&_ul]:ml-5 [&_ul]:list-disc [&_ul]:marker:text-[var(--text-muted)]'
|
||||||
dangerouslySetInnerHTML={{ __html: content }}
|
dangerouslySetInnerHTML={{ __html: content }}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
@@ -43,7 +43,7 @@ export function Text({ blockId, subBlockId, content, className }: TextProps) {
|
|||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
id={`${blockId}-${subBlockId}`}
|
id={`${blockId}-${subBlockId}`}
|
||||||
className={`whitespace-pre-wrap break-words rounded-md border bg-[var(--surface-2)] p-4 text-muted-foreground text-sm shadow-sm ${className || ''}`}
|
className={`whitespace-pre-wrap break-words rounded-md border bg-[var(--surface-2)] p-4 text-[var(--text-secondary)] text-sm shadow-sm ${className || ''}`}
|
||||||
>
|
>
|
||||||
{content}
|
{content}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -0,0 +1,261 @@
|
|||||||
|
/**
|
||||||
|
* @vitest-environment node
|
||||||
|
*/
|
||||||
|
import { describe, expect, it } from 'vitest'
|
||||||
|
import type { SubBlockConfig } from '@/blocks/types'
|
||||||
|
|
||||||
|
const isFieldRequired = (config: SubBlockConfig, subBlockValues?: Record<string, any>): boolean => {
|
||||||
|
if (!config.required) return false
|
||||||
|
if (typeof config.required === 'boolean') return config.required
|
||||||
|
|
||||||
|
const evalCond = (
|
||||||
|
cond: {
|
||||||
|
field: string
|
||||||
|
value: string | number | boolean | Array<string | number | boolean>
|
||||||
|
not?: boolean
|
||||||
|
and?: {
|
||||||
|
field: string
|
||||||
|
value: string | number | boolean | Array<string | number | boolean> | undefined
|
||||||
|
not?: boolean
|
||||||
|
}
|
||||||
|
},
|
||||||
|
values: Record<string, any>
|
||||||
|
): boolean => {
|
||||||
|
const fieldValue = values[cond.field]?.value
|
||||||
|
const condValue = cond.value
|
||||||
|
|
||||||
|
let match: boolean
|
||||||
|
if (Array.isArray(condValue)) {
|
||||||
|
match = condValue.includes(fieldValue)
|
||||||
|
} else {
|
||||||
|
match = fieldValue === condValue
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cond.not) match = !match
|
||||||
|
|
||||||
|
if (cond.and) {
|
||||||
|
const andFieldValue = values[cond.and.field]?.value
|
||||||
|
const andCondValue = cond.and.value
|
||||||
|
let andMatch: boolean
|
||||||
|
if (Array.isArray(andCondValue)) {
|
||||||
|
andMatch = andCondValue.includes(andFieldValue)
|
||||||
|
} else {
|
||||||
|
andMatch = andFieldValue === andCondValue
|
||||||
|
}
|
||||||
|
if (cond.and.not) andMatch = !andMatch
|
||||||
|
match = match && andMatch
|
||||||
|
}
|
||||||
|
|
||||||
|
return match
|
||||||
|
}
|
||||||
|
|
||||||
|
const condition = typeof config.required === 'function' ? config.required() : config.required
|
||||||
|
return evalCond(condition, subBlockValues || {})
|
||||||
|
}
|
||||||
|
|
||||||
|
describe('isFieldRequired', () => {
|
||||||
|
describe('boolean required', () => {
|
||||||
|
it.concurrent('returns false when required is not set', () => {
|
||||||
|
const config = { id: 'test', type: 'short-input' } as SubBlockConfig
|
||||||
|
expect(isFieldRequired(config, {})).toBe(false)
|
||||||
|
})
|
||||||
|
|
||||||
|
it.concurrent('returns false when required is false', () => {
|
||||||
|
const config = { id: 'test', type: 'short-input', required: false } as SubBlockConfig
|
||||||
|
expect(isFieldRequired(config, {})).toBe(false)
|
||||||
|
})
|
||||||
|
|
||||||
|
it.concurrent('returns true when required is true', () => {
|
||||||
|
const config = { id: 'test', type: 'short-input', required: true } as SubBlockConfig
|
||||||
|
expect(isFieldRequired(config, {})).toBe(true)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('conditional required - simple value matching', () => {
|
||||||
|
it.concurrent('returns true when field value matches condition value', () => {
|
||||||
|
const config = {
|
||||||
|
id: 'test',
|
||||||
|
type: 'short-input',
|
||||||
|
required: { field: 'operation', value: 'create_booking' },
|
||||||
|
} as SubBlockConfig
|
||||||
|
const values = { operation: { value: 'create_booking' } }
|
||||||
|
expect(isFieldRequired(config, values)).toBe(true)
|
||||||
|
})
|
||||||
|
|
||||||
|
it.concurrent('returns false when field value does not match condition value', () => {
|
||||||
|
const config = {
|
||||||
|
id: 'test',
|
||||||
|
type: 'short-input',
|
||||||
|
required: { field: 'operation', value: 'create_booking' },
|
||||||
|
} as SubBlockConfig
|
||||||
|
const values = { operation: { value: 'cancel_booking' } }
|
||||||
|
expect(isFieldRequired(config, values)).toBe(false)
|
||||||
|
})
|
||||||
|
|
||||||
|
it.concurrent('returns false when field is missing', () => {
|
||||||
|
const config = {
|
||||||
|
id: 'test',
|
||||||
|
type: 'short-input',
|
||||||
|
required: { field: 'operation', value: 'create_booking' },
|
||||||
|
} as SubBlockConfig
|
||||||
|
expect(isFieldRequired(config, {})).toBe(false)
|
||||||
|
})
|
||||||
|
|
||||||
|
it.concurrent('returns false when field value is undefined', () => {
|
||||||
|
const config = {
|
||||||
|
id: 'test',
|
||||||
|
type: 'short-input',
|
||||||
|
required: { field: 'operation', value: 'create_booking' },
|
||||||
|
} as SubBlockConfig
|
||||||
|
const values = { operation: { value: undefined } }
|
||||||
|
expect(isFieldRequired(config, values)).toBe(false)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('conditional required - array value matching', () => {
|
||||||
|
it.concurrent('returns true when field value is in condition array', () => {
|
||||||
|
const config = {
|
||||||
|
id: 'test',
|
||||||
|
type: 'short-input',
|
||||||
|
required: { field: 'operation', value: ['create_booking', 'update_booking'] },
|
||||||
|
} as SubBlockConfig
|
||||||
|
const values = { operation: { value: 'create_booking' } }
|
||||||
|
expect(isFieldRequired(config, values)).toBe(true)
|
||||||
|
})
|
||||||
|
|
||||||
|
it.concurrent('returns false when field value is not in condition array', () => {
|
||||||
|
const config = {
|
||||||
|
id: 'test',
|
||||||
|
type: 'short-input',
|
||||||
|
required: { field: 'operation', value: ['create_booking', 'update_booking'] },
|
||||||
|
} as SubBlockConfig
|
||||||
|
const values = { operation: { value: 'cancel_booking' } }
|
||||||
|
expect(isFieldRequired(config, values)).toBe(false)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('conditional required - negation', () => {
|
||||||
|
it.concurrent('returns false when field matches but not is true', () => {
|
||||||
|
const config = {
|
||||||
|
id: 'test',
|
||||||
|
type: 'short-input',
|
||||||
|
required: { field: 'operation', value: 'create_booking', not: true },
|
||||||
|
} as SubBlockConfig
|
||||||
|
const values = { operation: { value: 'create_booking' } }
|
||||||
|
expect(isFieldRequired(config, values)).toBe(false)
|
||||||
|
})
|
||||||
|
|
||||||
|
it.concurrent('returns true when field does not match and not is true', () => {
|
||||||
|
const config = {
|
||||||
|
id: 'test',
|
||||||
|
type: 'short-input',
|
||||||
|
required: { field: 'operation', value: 'create_booking', not: true },
|
||||||
|
} as SubBlockConfig
|
||||||
|
const values = { operation: { value: 'cancel_booking' } }
|
||||||
|
expect(isFieldRequired(config, values)).toBe(true)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('conditional required - compound conditions', () => {
|
||||||
|
it.concurrent('returns true when both conditions match', () => {
|
||||||
|
const config = {
|
||||||
|
id: 'test',
|
||||||
|
type: 'short-input',
|
||||||
|
required: {
|
||||||
|
field: 'operation',
|
||||||
|
value: 'create_booking',
|
||||||
|
and: { field: 'hasEmail', value: true },
|
||||||
|
},
|
||||||
|
} as SubBlockConfig
|
||||||
|
const values = {
|
||||||
|
operation: { value: 'create_booking' },
|
||||||
|
hasEmail: { value: true },
|
||||||
|
}
|
||||||
|
expect(isFieldRequired(config, values)).toBe(true)
|
||||||
|
})
|
||||||
|
|
||||||
|
it.concurrent('returns false when first matches but and fails', () => {
|
||||||
|
const config = {
|
||||||
|
id: 'test',
|
||||||
|
type: 'short-input',
|
||||||
|
required: {
|
||||||
|
field: 'operation',
|
||||||
|
value: 'create_booking',
|
||||||
|
and: { field: 'hasEmail', value: true },
|
||||||
|
},
|
||||||
|
} as SubBlockConfig
|
||||||
|
const values = {
|
||||||
|
operation: { value: 'create_booking' },
|
||||||
|
hasEmail: { value: false },
|
||||||
|
}
|
||||||
|
expect(isFieldRequired(config, values)).toBe(false)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('condition + required equivalence', () => {
|
||||||
|
const conditionValue = { field: 'operation', value: 'calcom_create_booking' }
|
||||||
|
|
||||||
|
const configWithConditionalRequired = {
|
||||||
|
id: 'attendeeName',
|
||||||
|
type: 'short-input',
|
||||||
|
condition: conditionValue,
|
||||||
|
required: conditionValue,
|
||||||
|
} as SubBlockConfig
|
||||||
|
|
||||||
|
const configWithSimpleRequired = {
|
||||||
|
id: 'attendeeName',
|
||||||
|
type: 'short-input',
|
||||||
|
condition: conditionValue,
|
||||||
|
required: true,
|
||||||
|
} as SubBlockConfig
|
||||||
|
|
||||||
|
describe('when condition IS met (field is visible)', () => {
|
||||||
|
const valuesWhenVisible = { operation: { value: 'calcom_create_booking' } }
|
||||||
|
|
||||||
|
it.concurrent('conditional required returns true', () => {
|
||||||
|
expect(isFieldRequired(configWithConditionalRequired, valuesWhenVisible)).toBe(true)
|
||||||
|
})
|
||||||
|
|
||||||
|
it.concurrent('simple required returns true', () => {
|
||||||
|
expect(isFieldRequired(configWithSimpleRequired, valuesWhenVisible)).toBe(true)
|
||||||
|
})
|
||||||
|
|
||||||
|
it.concurrent('both configs produce the same result', () => {
|
||||||
|
const conditionalResult = isFieldRequired(configWithConditionalRequired, valuesWhenVisible)
|
||||||
|
const simpleResult = isFieldRequired(configWithSimpleRequired, valuesWhenVisible)
|
||||||
|
expect(conditionalResult).toBe(simpleResult)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('when condition is NOT met (field is hidden)', () => {
|
||||||
|
const valuesWhenHidden = { operation: { value: 'calcom_cancel_booking' } }
|
||||||
|
|
||||||
|
it.concurrent('conditional required returns false', () => {
|
||||||
|
expect(isFieldRequired(configWithConditionalRequired, valuesWhenHidden)).toBe(false)
|
||||||
|
})
|
||||||
|
|
||||||
|
it.concurrent('simple required returns true but field is hidden', () => {
|
||||||
|
expect(isFieldRequired(configWithSimpleRequired, valuesWhenHidden)).toBe(true)
|
||||||
|
})
|
||||||
|
|
||||||
|
it.concurrent('results differ but field is hidden when condition fails', () => {
|
||||||
|
const conditionalResult = isFieldRequired(configWithConditionalRequired, valuesWhenHidden)
|
||||||
|
const simpleResult = isFieldRequired(configWithSimpleRequired, valuesWhenHidden)
|
||||||
|
expect(conditionalResult).not.toBe(simpleResult)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('practical equivalence for user-facing behavior', () => {
|
||||||
|
it.concurrent('when field is visible both show required indicator', () => {
|
||||||
|
const valuesWhenVisible = { operation: { value: 'calcom_create_booking' } }
|
||||||
|
const showsRequiredIndicatorA = isFieldRequired(
|
||||||
|
configWithConditionalRequired,
|
||||||
|
valuesWhenVisible
|
||||||
|
)
|
||||||
|
const showsRequiredIndicatorB = isFieldRequired(configWithSimpleRequired, valuesWhenVisible)
|
||||||
|
expect(showsRequiredIndicatorA).toBe(true)
|
||||||
|
expect(showsRequiredIndicatorB).toBe(true)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
import { type JSX, type MouseEvent, memo, useRef, useState } from 'react'
|
import { type JSX, type MouseEvent, memo, useCallback, useRef, useState } from 'react'
|
||||||
import { isEqual } from 'lodash'
|
import { isEqual } from 'lodash'
|
||||||
import { AlertTriangle, ArrowLeftRight, ArrowUp } from 'lucide-react'
|
import { AlertTriangle, ArrowLeftRight, ArrowUp, Check, Clipboard } from 'lucide-react'
|
||||||
import { Button, Input, Label, Tooltip } from '@/components/emcn/components'
|
import { Button, Input, Label, Tooltip } from '@/components/emcn/components'
|
||||||
import { cn } from '@/lib/core/utils/cn'
|
import { cn } from '@/lib/core/utils/cn'
|
||||||
import type { FieldDiffStatus } from '@/lib/workflows/diff/types'
|
import type { FieldDiffStatus } from '@/lib/workflows/diff/types'
|
||||||
@@ -44,6 +44,7 @@ import {
|
|||||||
} from '@/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/editor/components/sub-block/components'
|
} from '@/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/editor/components/sub-block/components'
|
||||||
import { useDependsOnGate } from '@/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/editor/components/sub-block/hooks/use-depends-on-gate'
|
import { useDependsOnGate } from '@/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/editor/components/sub-block/hooks/use-depends-on-gate'
|
||||||
import type { SubBlockConfig } from '@/blocks/types'
|
import type { SubBlockConfig } from '@/blocks/types'
|
||||||
|
import { useWebhookManagement } from '@/hooks/use-webhook-management'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Interface for wand control handlers exposed by sub-block inputs
|
* Interface for wand control handlers exposed by sub-block inputs
|
||||||
@@ -195,7 +196,12 @@ const renderLabel = (
|
|||||||
disabled?: boolean
|
disabled?: boolean
|
||||||
onToggle?: () => void
|
onToggle?: () => void
|
||||||
},
|
},
|
||||||
canonicalToggleIsDisabled?: boolean
|
canonicalToggleIsDisabled?: boolean,
|
||||||
|
copyState?: {
|
||||||
|
showCopyButton: boolean
|
||||||
|
copied: boolean
|
||||||
|
onCopy: () => void
|
||||||
|
}
|
||||||
): JSX.Element | null => {
|
): JSX.Element | null => {
|
||||||
if (config.type === 'switch') return null
|
if (config.type === 'switch') return null
|
||||||
if (!config.title) return null
|
if (!config.title) return null
|
||||||
@@ -203,6 +209,7 @@ const renderLabel = (
|
|||||||
const required = isFieldRequired(config, subBlockValues)
|
const required = isFieldRequired(config, subBlockValues)
|
||||||
const showWand = wandState?.isWandEnabled && !wandState.isPreview && !wandState.disabled
|
const showWand = wandState?.isWandEnabled && !wandState.isPreview && !wandState.disabled
|
||||||
const showCanonicalToggle = !!canonicalToggle && !wandState?.isPreview
|
const showCanonicalToggle = !!canonicalToggle && !wandState?.isPreview
|
||||||
|
const showCopy = copyState?.showCopyButton && !wandState?.isPreview
|
||||||
const canonicalToggleDisabledResolved = canonicalToggleIsDisabled ?? canonicalToggle?.disabled
|
const canonicalToggleDisabledResolved = canonicalToggleIsDisabled ?? canonicalToggle?.disabled
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@@ -226,7 +233,28 @@ const renderLabel = (
|
|||||||
</Tooltip.Root>
|
</Tooltip.Root>
|
||||||
)}
|
)}
|
||||||
</Label>
|
</Label>
|
||||||
<div className='flex items-center gap-[6px]'>
|
<div className='flex min-w-0 flex-1 items-center justify-end gap-[6px]'>
|
||||||
|
{showCopy && (
|
||||||
|
<Tooltip.Root>
|
||||||
|
<Tooltip.Trigger asChild>
|
||||||
|
<button
|
||||||
|
type='button'
|
||||||
|
onClick={copyState.onCopy}
|
||||||
|
className='-my-1 flex h-5 w-5 items-center justify-center'
|
||||||
|
aria-label='Copy value'
|
||||||
|
>
|
||||||
|
{copyState.copied ? (
|
||||||
|
<Check className='h-3 w-3 text-green-500' />
|
||||||
|
) : (
|
||||||
|
<Clipboard className='h-3 w-3 text-muted-foreground' />
|
||||||
|
)}
|
||||||
|
</button>
|
||||||
|
</Tooltip.Trigger>
|
||||||
|
<Tooltip.Content side='top'>
|
||||||
|
<p>{copyState.copied ? 'Copied!' : 'Copy'}</p>
|
||||||
|
</Tooltip.Content>
|
||||||
|
</Tooltip.Root>
|
||||||
|
)}
|
||||||
{showWand && (
|
{showWand && (
|
||||||
<>
|
<>
|
||||||
{!wandState.isSearchActive ? (
|
{!wandState.isSearchActive ? (
|
||||||
@@ -238,14 +266,19 @@ const renderLabel = (
|
|||||||
Generate
|
Generate
|
||||||
</Button>
|
</Button>
|
||||||
) : (
|
) : (
|
||||||
<div className='-my-1 flex items-center gap-[4px]'>
|
<div className='-my-1 flex min-w-[120px] max-w-[280px] flex-1 items-center gap-[4px]'>
|
||||||
<Input
|
<Input
|
||||||
ref={wandState.searchInputRef}
|
ref={wandState.searchInputRef}
|
||||||
value={wandState.isStreaming ? 'Generating...' : wandState.searchQuery}
|
value={wandState.isStreaming ? 'Generating...' : wandState.searchQuery}
|
||||||
onChange={(e: React.ChangeEvent<HTMLInputElement>) =>
|
onChange={(e: React.ChangeEvent<HTMLInputElement>) =>
|
||||||
wandState.onSearchChange(e.target.value)
|
wandState.onSearchChange(e.target.value)
|
||||||
}
|
}
|
||||||
onBlur={wandState.onSearchBlur}
|
onBlur={(e: React.FocusEvent<HTMLInputElement>) => {
|
||||||
|
// Only close if clicking outside the input container (not on the submit button)
|
||||||
|
const relatedTarget = e.relatedTarget as HTMLElement | null
|
||||||
|
if (relatedTarget?.closest('button')) return
|
||||||
|
wandState.onSearchBlur()
|
||||||
|
}}
|
||||||
onKeyDown={(e: React.KeyboardEvent<HTMLInputElement>) => {
|
onKeyDown={(e: React.KeyboardEvent<HTMLInputElement>) => {
|
||||||
if (
|
if (
|
||||||
e.key === 'Enter' &&
|
e.key === 'Enter' &&
|
||||||
@@ -259,7 +292,7 @@ const renderLabel = (
|
|||||||
}}
|
}}
|
||||||
disabled={wandState.isStreaming}
|
disabled={wandState.isStreaming}
|
||||||
className={cn(
|
className={cn(
|
||||||
'h-5 max-w-[200px] flex-1 text-[11px]',
|
'h-5 min-w-[80px] flex-1 text-[11px]',
|
||||||
wandState.isStreaming && 'text-muted-foreground'
|
wandState.isStreaming && 'text-muted-foreground'
|
||||||
)}
|
)}
|
||||||
placeholder='Generate with AI...'
|
placeholder='Generate with AI...'
|
||||||
@@ -385,9 +418,18 @@ function SubBlockComponent({
|
|||||||
const [isValidJson, setIsValidJson] = useState(true)
|
const [isValidJson, setIsValidJson] = useState(true)
|
||||||
const [isSearchActive, setIsSearchActive] = useState(false)
|
const [isSearchActive, setIsSearchActive] = useState(false)
|
||||||
const [searchQuery, setSearchQuery] = useState('')
|
const [searchQuery, setSearchQuery] = useState('')
|
||||||
|
const [copied, setCopied] = useState(false)
|
||||||
const searchInputRef = useRef<HTMLInputElement>(null)
|
const searchInputRef = useRef<HTMLInputElement>(null)
|
||||||
const wandControlRef = useRef<WandControlHandlers | null>(null)
|
const wandControlRef = useRef<WandControlHandlers | null>(null)
|
||||||
|
|
||||||
|
// Use webhook management hook when config has useWebhookUrl enabled
|
||||||
|
const webhookManagement = useWebhookManagement({
|
||||||
|
blockId,
|
||||||
|
triggerId: undefined,
|
||||||
|
isPreview,
|
||||||
|
useWebhookUrl: config.useWebhookUrl,
|
||||||
|
})
|
||||||
|
|
||||||
const handleMouseDown = (e: MouseEvent<HTMLDivElement>): void => {
|
const handleMouseDown = (e: MouseEvent<HTMLDivElement>): void => {
|
||||||
e.stopPropagation()
|
e.stopPropagation()
|
||||||
}
|
}
|
||||||
@@ -398,6 +440,18 @@ function SubBlockComponent({
|
|||||||
|
|
||||||
const isWandEnabled = config.wandConfig?.enabled ?? false
|
const isWandEnabled = config.wandConfig?.enabled ?? false
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handles copying the webhook URL to clipboard.
|
||||||
|
*/
|
||||||
|
const handleCopy = useCallback(() => {
|
||||||
|
const textToCopy = webhookManagement?.webhookUrl
|
||||||
|
if (textToCopy) {
|
||||||
|
navigator.clipboard.writeText(textToCopy)
|
||||||
|
setCopied(true)
|
||||||
|
setTimeout(() => setCopied(false), 2000)
|
||||||
|
}
|
||||||
|
}, [webhookManagement?.webhookUrl])
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handles wand icon click to activate inline prompt mode.
|
* Handles wand icon click to activate inline prompt mode.
|
||||||
* Focuses the input after a brief delay to ensure DOM is ready.
|
* Focuses the input after a brief delay to ensure DOM is ready.
|
||||||
@@ -482,7 +536,6 @@ function SubBlockComponent({
|
|||||||
placeholder={config.placeholder}
|
placeholder={config.placeholder}
|
||||||
password={config.password}
|
password={config.password}
|
||||||
readOnly={config.readOnly}
|
readOnly={config.readOnly}
|
||||||
showCopyButton={config.showCopyButton}
|
|
||||||
useWebhookUrl={config.useWebhookUrl}
|
useWebhookUrl={config.useWebhookUrl}
|
||||||
config={config}
|
config={config}
|
||||||
isPreview={isPreview}
|
isPreview={isPreview}
|
||||||
@@ -979,7 +1032,12 @@ function SubBlockComponent({
|
|||||||
searchInputRef,
|
searchInputRef,
|
||||||
},
|
},
|
||||||
canonicalToggle,
|
canonicalToggle,
|
||||||
Boolean(canonicalToggle?.disabled || disabled || isPreview)
|
Boolean(canonicalToggle?.disabled || disabled || isPreview),
|
||||||
|
{
|
||||||
|
showCopyButton: Boolean(config.showCopyButton && config.useWebhookUrl),
|
||||||
|
copied,
|
||||||
|
onCopy: handleCopy,
|
||||||
|
}
|
||||||
)}
|
)}
|
||||||
{renderInput()}
|
{renderInput()}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -58,7 +58,9 @@ export function getBlockColor(blockType: string): string {
|
|||||||
*/
|
*/
|
||||||
export function formatDuration(ms?: number): string {
|
export function formatDuration(ms?: number): string {
|
||||||
if (ms === undefined || ms === null) return '-'
|
if (ms === undefined || ms === null) return '-'
|
||||||
if (ms < 1000) return `${ms}ms`
|
if (ms < 1000) {
|
||||||
|
return `${Math.round(ms)}ms`
|
||||||
|
}
|
||||||
return `${(ms / 1000).toFixed(2)}s`
|
return `${(ms / 1000).toFixed(2)}s`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -964,8 +964,8 @@ export function useWorkflowExecution() {
|
|||||||
const isContainerBlock = data.blockType === 'loop' || data.blockType === 'parallel'
|
const isContainerBlock = data.blockType === 'loop' || data.blockType === 'parallel'
|
||||||
if (isContainerBlock) return
|
if (isContainerBlock) return
|
||||||
|
|
||||||
const startedAt = new Date(Date.now() - data.durationMs).toISOString()
|
const startedAt = data.startedAt
|
||||||
const endedAt = new Date().toISOString()
|
const endedAt = data.endedAt
|
||||||
|
|
||||||
accumulatedBlockLogs.push({
|
accumulatedBlockLogs.push({
|
||||||
blockId: data.blockId,
|
blockId: data.blockId,
|
||||||
@@ -1013,8 +1013,8 @@ export function useWorkflowExecution() {
|
|||||||
// Track failed block execution in run path
|
// Track failed block execution in run path
|
||||||
setBlockRunStatus(data.blockId, 'error')
|
setBlockRunStatus(data.blockId, 'error')
|
||||||
|
|
||||||
const startedAt = new Date(Date.now() - data.durationMs).toISOString()
|
const startedAt = data.startedAt
|
||||||
const endedAt = new Date().toISOString()
|
const endedAt = data.endedAt
|
||||||
|
|
||||||
// Accumulate block error log for the execution result
|
// Accumulate block error log for the execution result
|
||||||
accumulatedBlockLogs.push({
|
accumulatedBlockLogs.push({
|
||||||
@@ -1603,8 +1603,8 @@ export function useWorkflowExecution() {
|
|||||||
const isContainerBlock = data.blockType === 'loop' || data.blockType === 'parallel'
|
const isContainerBlock = data.blockType === 'loop' || data.blockType === 'parallel'
|
||||||
if (isContainerBlock) return
|
if (isContainerBlock) return
|
||||||
|
|
||||||
const startedAt = new Date(Date.now() - data.durationMs).toISOString()
|
const startedAt = data.startedAt
|
||||||
const endedAt = new Date().toISOString()
|
const endedAt = data.endedAt
|
||||||
|
|
||||||
accumulatedBlockLogs.push({
|
accumulatedBlockLogs.push({
|
||||||
blockId: data.blockId,
|
blockId: data.blockId,
|
||||||
@@ -1642,8 +1642,8 @@ export function useWorkflowExecution() {
|
|||||||
|
|
||||||
setBlockRunStatus(data.blockId, 'error')
|
setBlockRunStatus(data.blockId, 'error')
|
||||||
|
|
||||||
const startedAt = new Date(Date.now() - data.durationMs).toISOString()
|
const startedAt = data.startedAt
|
||||||
const endedAt = new Date().toISOString()
|
const endedAt = data.endedAt
|
||||||
|
|
||||||
accumulatedBlockLogs.push({
|
accumulatedBlockLogs.push({
|
||||||
blockId: data.blockId,
|
blockId: data.blockId,
|
||||||
|
|||||||
@@ -461,12 +461,14 @@ function WorkflowPreviewBlockInner({ data }: NodeProps<WorkflowPreviewBlockData>
|
|||||||
className={`flex items-center justify-between p-[8px] ${hasContentBelowHeader ? 'border-[var(--border-1)] border-b' : ''}`}
|
className={`flex items-center justify-between p-[8px] ${hasContentBelowHeader ? 'border-[var(--border-1)] border-b' : ''}`}
|
||||||
>
|
>
|
||||||
<div className='relative z-10 flex min-w-0 flex-1 items-center gap-[10px]'>
|
<div className='relative z-10 flex min-w-0 flex-1 items-center gap-[10px]'>
|
||||||
|
{!isNoteBlock && (
|
||||||
<div
|
<div
|
||||||
className='flex h-[24px] w-[24px] flex-shrink-0 items-center justify-center rounded-[6px]'
|
className='flex h-[24px] w-[24px] flex-shrink-0 items-center justify-center rounded-[6px]'
|
||||||
style={{ background: enabled ? blockConfig.bgColor : 'gray' }}
|
style={{ background: enabled ? blockConfig.bgColor : 'gray' }}
|
||||||
>
|
>
|
||||||
<IconComponent className='h-[16px] w-[16px] text-white' />
|
<IconComponent className='h-[16px] w-[16px] text-white' />
|
||||||
</div>
|
</div>
|
||||||
|
)}
|
||||||
<span
|
<span
|
||||||
className={`truncate font-medium text-[16px] ${!enabled ? 'text-[var(--text-muted)]' : ''}`}
|
className={`truncate font-medium text-[16px] ${!enabled ? 'text-[var(--text-muted)]' : ''}`}
|
||||||
title={name}
|
title={name}
|
||||||
|
|||||||
@@ -21,8 +21,9 @@ interface DeleteModalProps {
|
|||||||
isDeleting: boolean
|
isDeleting: boolean
|
||||||
/**
|
/**
|
||||||
* Type of item being deleted
|
* Type of item being deleted
|
||||||
|
* - 'mixed' is used when both workflows and folders are selected
|
||||||
*/
|
*/
|
||||||
itemType: 'workflow' | 'folder' | 'workspace'
|
itemType: 'workflow' | 'folder' | 'workspace' | 'mixed'
|
||||||
/**
|
/**
|
||||||
* Name(s) of the item(s) being deleted (optional, for display)
|
* Name(s) of the item(s) being deleted (optional, for display)
|
||||||
* Can be a single name or an array of names for multiple items
|
* Can be a single name or an array of names for multiple items
|
||||||
@@ -54,7 +55,9 @@ export function DeleteModal({
|
|||||||
if (itemType === 'workflow') {
|
if (itemType === 'workflow') {
|
||||||
title = isMultiple ? 'Delete Workflows' : 'Delete Workflow'
|
title = isMultiple ? 'Delete Workflows' : 'Delete Workflow'
|
||||||
} else if (itemType === 'folder') {
|
} else if (itemType === 'folder') {
|
||||||
title = 'Delete Folder'
|
title = isMultiple ? 'Delete Folders' : 'Delete Folder'
|
||||||
|
} else if (itemType === 'mixed') {
|
||||||
|
title = 'Delete Items'
|
||||||
} else {
|
} else {
|
||||||
title = 'Delete Workspace'
|
title = 'Delete Workspace'
|
||||||
}
|
}
|
||||||
@@ -85,6 +88,18 @@ export function DeleteModal({
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (itemType === 'folder') {
|
if (itemType === 'folder') {
|
||||||
|
if (isMultiple) {
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
Are you sure you want to delete{' '}
|
||||||
|
<span className='font-medium text-[var(--text-primary)]'>
|
||||||
|
{displayNames.join(', ')}
|
||||||
|
</span>
|
||||||
|
? This will permanently remove all workflows, logs, and knowledge bases within these
|
||||||
|
folders.
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
||||||
if (isSingle && displayNames.length > 0) {
|
if (isSingle && displayNames.length > 0) {
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
@@ -97,6 +112,23 @@ export function DeleteModal({
|
|||||||
return 'Are you sure you want to delete this folder? This will permanently remove all associated workflows, logs, and knowledge bases.'
|
return 'Are you sure you want to delete this folder? This will permanently remove all associated workflows, logs, and knowledge bases.'
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (itemType === 'mixed') {
|
||||||
|
if (displayNames.length > 0) {
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
Are you sure you want to delete{' '}
|
||||||
|
<span className='font-medium text-[var(--text-primary)]'>
|
||||||
|
{displayNames.join(', ')}
|
||||||
|
</span>
|
||||||
|
? This will permanently remove all selected workflows and folders, including their
|
||||||
|
contents.
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
return 'Are you sure you want to delete the selected items? This will permanently remove all selected workflows and folders, including their contents.'
|
||||||
|
}
|
||||||
|
|
||||||
|
// workspace type
|
||||||
if (isSingle && displayNames.length > 0) {
|
if (isSingle && displayNames.length > 0) {
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
'use client'
|
'use client'
|
||||||
|
|
||||||
import { useCallback, useMemo, useState } from 'react'
|
import { useCallback, useMemo, useRef, useState } from 'react'
|
||||||
import { createLogger } from '@sim/logger'
|
import { createLogger } from '@sim/logger'
|
||||||
import clsx from 'clsx'
|
import clsx from 'clsx'
|
||||||
import { ChevronRight, Folder, FolderOpen, MoreHorizontal } from 'lucide-react'
|
import { ChevronRight, Folder, FolderOpen, MoreHorizontal } from 'lucide-react'
|
||||||
@@ -14,17 +14,23 @@ import {
|
|||||||
useFolderExpand,
|
useFolderExpand,
|
||||||
useItemDrag,
|
useItemDrag,
|
||||||
useItemRename,
|
useItemRename,
|
||||||
|
useSidebarDragContext,
|
||||||
} from '@/app/workspace/[workspaceId]/w/components/sidebar/hooks'
|
} from '@/app/workspace/[workspaceId]/w/components/sidebar/hooks'
|
||||||
import { SIDEBAR_SCROLL_EVENT } from '@/app/workspace/[workspaceId]/w/components/sidebar/sidebar'
|
import { SIDEBAR_SCROLL_EVENT } from '@/app/workspace/[workspaceId]/w/components/sidebar/sidebar'
|
||||||
import {
|
import {
|
||||||
useCanDelete,
|
useCanDelete,
|
||||||
useDeleteFolder,
|
useDeleteFolder,
|
||||||
|
useDeleteSelection,
|
||||||
useDuplicateFolder,
|
useDuplicateFolder,
|
||||||
|
useDuplicateSelection,
|
||||||
useExportFolder,
|
useExportFolder,
|
||||||
|
useExportSelection,
|
||||||
} from '@/app/workspace/[workspaceId]/w/hooks'
|
} from '@/app/workspace/[workspaceId]/w/hooks'
|
||||||
import { useCreateFolder, useUpdateFolder } from '@/hooks/queries/folders'
|
import { useCreateFolder, useUpdateFolder } from '@/hooks/queries/folders'
|
||||||
import { useCreateWorkflow } from '@/hooks/queries/workflows'
|
import { useCreateWorkflow } from '@/hooks/queries/workflows'
|
||||||
|
import { useFolderStore } from '@/stores/folders/store'
|
||||||
import type { FolderTreeNode } from '@/stores/folders/types'
|
import type { FolderTreeNode } from '@/stores/folders/types'
|
||||||
|
import { useWorkflowRegistry } from '@/stores/workflows/registry/store'
|
||||||
import { generateCreativeWorkflowName } from '@/stores/workflows/registry/utils'
|
import { generateCreativeWorkflowName } from '@/stores/workflows/registry/utils'
|
||||||
|
|
||||||
const logger = createLogger('FolderItem')
|
const logger = createLogger('FolderItem')
|
||||||
@@ -37,26 +43,21 @@ interface FolderItemProps {
|
|||||||
onDragEnter?: (e: React.DragEvent<HTMLElement>) => void
|
onDragEnter?: (e: React.DragEvent<HTMLElement>) => void
|
||||||
onDragLeave?: (e: React.DragEvent<HTMLElement>) => void
|
onDragLeave?: (e: React.DragEvent<HTMLElement>) => void
|
||||||
}
|
}
|
||||||
|
onFolderClick?: (folderId: string, shiftKey: boolean, metaKey: boolean) => void
|
||||||
onDragStart?: () => void
|
onDragStart?: () => void
|
||||||
onDragEnd?: () => void
|
onDragEnd?: () => void
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* FolderItem component displaying a single folder with drag and expand/collapse support.
|
|
||||||
* Uses item drag and folder expand hooks for unified behavior.
|
|
||||||
* Supports hover-to-expand during drag operations via hoverHandlers.
|
|
||||||
*
|
|
||||||
* @param props - Component props
|
|
||||||
* @returns Folder item with drag and expand support
|
|
||||||
*/
|
|
||||||
export function FolderItem({
|
export function FolderItem({
|
||||||
folder,
|
folder,
|
||||||
level,
|
level,
|
||||||
dragDisabled = false,
|
dragDisabled = false,
|
||||||
hoverHandlers,
|
hoverHandlers,
|
||||||
|
onFolderClick,
|
||||||
onDragStart: onDragStartProp,
|
onDragStart: onDragStartProp,
|
||||||
onDragEnd: onDragEndProp,
|
onDragEnd: onDragEndProp,
|
||||||
}: FolderItemProps) {
|
}: FolderItemProps) {
|
||||||
|
const { isAnyDragActive } = useSidebarDragContext()
|
||||||
const params = useParams()
|
const params = useParams()
|
||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
const workspaceId = params.workspaceId as string
|
const workspaceId = params.workspaceId as string
|
||||||
@@ -64,27 +65,64 @@ export function FolderItem({
|
|||||||
const createWorkflowMutation = useCreateWorkflow()
|
const createWorkflowMutation = useCreateWorkflow()
|
||||||
const createFolderMutation = useCreateFolder()
|
const createFolderMutation = useCreateFolder()
|
||||||
const userPermissions = useUserPermissionsContext()
|
const userPermissions = useUserPermissionsContext()
|
||||||
|
const selectedFolders = useFolderStore((state) => state.selectedFolders)
|
||||||
|
const isSelected = selectedFolders.has(folder.id)
|
||||||
|
|
||||||
const { canDeleteFolder } = useCanDelete({ workspaceId })
|
const { canDeleteFolder, canDeleteWorkflows } = useCanDelete({ workspaceId })
|
||||||
const canDelete = useMemo(() => canDeleteFolder(folder.id), [canDeleteFolder, folder.id])
|
|
||||||
|
|
||||||
const [isDeleteModalOpen, setIsDeleteModalOpen] = useState(false)
|
const [isDeleteModalOpen, setIsDeleteModalOpen] = useState(false)
|
||||||
|
const [deleteItemType, setDeleteItemType] = useState<'folder' | 'mixed'>('folder')
|
||||||
|
const [deleteItemNames, setDeleteItemNames] = useState<string | string[]>(folder.name)
|
||||||
|
|
||||||
const { isDeleting, handleDeleteFolder } = useDeleteFolder({
|
const capturedSelectionRef = useRef<{
|
||||||
|
workflowIds: string[]
|
||||||
|
folderIds: string[]
|
||||||
|
isMixed: boolean
|
||||||
|
names: string[]
|
||||||
|
} | null>(null)
|
||||||
|
|
||||||
|
const [canDeleteSelection, setCanDeleteSelection] = useState(true)
|
||||||
|
|
||||||
|
const { isDeleting: isDeletingThisFolder, handleDeleteFolder: handleDeleteThisFolder } =
|
||||||
|
useDeleteFolder({
|
||||||
workspaceId,
|
workspaceId,
|
||||||
folderIds: folder.id,
|
folderIds: folder.id,
|
||||||
onSuccess: () => setIsDeleteModalOpen(false),
|
onSuccess: () => setIsDeleteModalOpen(false),
|
||||||
})
|
})
|
||||||
|
|
||||||
const { handleDuplicateFolder } = useDuplicateFolder({
|
const { isDeleting: isDeletingSelection, handleDeleteSelection } = useDeleteSelection({
|
||||||
|
workspaceId,
|
||||||
|
workflowIds: capturedSelectionRef.current?.workflowIds || [],
|
||||||
|
folderIds: capturedSelectionRef.current?.folderIds || [],
|
||||||
|
isActiveWorkflow: (id) => id === params.workflowId,
|
||||||
|
onSuccess: () => setIsDeleteModalOpen(false),
|
||||||
|
})
|
||||||
|
|
||||||
|
const isDeleting = isDeletingThisFolder || isDeletingSelection
|
||||||
|
|
||||||
|
const { handleDuplicateFolder: handleDuplicateThisFolder } = useDuplicateFolder({
|
||||||
workspaceId,
|
workspaceId,
|
||||||
folderIds: folder.id,
|
folderIds: folder.id,
|
||||||
})
|
})
|
||||||
|
|
||||||
const { isExporting, hasWorkflows, handleExportFolder } = useExportFolder({
|
const { isDuplicating: isDuplicatingSelection, handleDuplicateSelection } = useDuplicateSelection(
|
||||||
|
{
|
||||||
|
workspaceId,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
const {
|
||||||
|
isExporting: isExportingThisFolder,
|
||||||
|
hasWorkflows,
|
||||||
|
handleExportFolder: handleExportThisFolder,
|
||||||
|
} = useExportFolder({
|
||||||
folderId: folder.id,
|
folderId: folder.id,
|
||||||
})
|
})
|
||||||
|
|
||||||
|
const { isExporting: isExportingSelection, handleExportSelection } = useExportSelection()
|
||||||
|
|
||||||
|
const isExporting = isExportingThisFolder || isExportingSelection
|
||||||
|
|
||||||
const {
|
const {
|
||||||
isExpanded,
|
isExpanded,
|
||||||
handleToggleExpanded,
|
handleToggleExpanded,
|
||||||
@@ -94,11 +132,8 @@ export function FolderItem({
|
|||||||
folderId: folder.id,
|
folderId: folder.id,
|
||||||
})
|
})
|
||||||
|
|
||||||
/**
|
const isEditingRef = useRef(false)
|
||||||
* Handle create workflow in folder using React Query mutation.
|
|
||||||
* Generates name and color upfront for optimistic UI updates.
|
|
||||||
* The UI disables the trigger when isPending, so no guard needed here.
|
|
||||||
*/
|
|
||||||
const handleCreateWorkflowInFolder = useCallback(async () => {
|
const handleCreateWorkflowInFolder = useCallback(async () => {
|
||||||
try {
|
try {
|
||||||
const name = generateCreativeWorkflowName()
|
const name = generateCreativeWorkflowName()
|
||||||
@@ -123,10 +158,6 @@ export function FolderItem({
|
|||||||
}
|
}
|
||||||
}, [createWorkflowMutation, workspaceId, folder.id, router, expandFolder])
|
}, [createWorkflowMutation, workspaceId, folder.id, router, expandFolder])
|
||||||
|
|
||||||
/**
|
|
||||||
* Handle create sub-folder using React Query mutation.
|
|
||||||
* Creates a new folder inside the current folder.
|
|
||||||
*/
|
|
||||||
const handleCreateFolderInFolder = useCallback(async () => {
|
const handleCreateFolderInFolder = useCallback(async () => {
|
||||||
try {
|
try {
|
||||||
const result = await createFolderMutation.mutateAsync({
|
const result = await createFolderMutation.mutateAsync({
|
||||||
@@ -147,12 +178,25 @@ export function FolderItem({
|
|||||||
|
|
||||||
const onDragStart = useCallback(
|
const onDragStart = useCallback(
|
||||||
(e: React.DragEvent) => {
|
(e: React.DragEvent) => {
|
||||||
if (isEditing) {
|
if (isEditingRef.current) {
|
||||||
e.preventDefault()
|
e.preventDefault()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
e.dataTransfer.setData('folder-id', folder.id)
|
const { selectedWorkflows, selectedFolders } = useFolderStore.getState()
|
||||||
|
const isCurrentlySelected = selectedFolders.has(folder.id)
|
||||||
|
|
||||||
|
const selection = isCurrentlySelected
|
||||||
|
? {
|
||||||
|
workflowIds: Array.from(selectedWorkflows),
|
||||||
|
folderIds: Array.from(selectedFolders),
|
||||||
|
}
|
||||||
|
: {
|
||||||
|
workflowIds: [],
|
||||||
|
folderIds: [folder.id],
|
||||||
|
}
|
||||||
|
|
||||||
|
e.dataTransfer.setData('sidebar-selection', JSON.stringify(selection))
|
||||||
e.dataTransfer.effectAllowed = 'move'
|
e.dataTransfer.effectAllowed = 'move'
|
||||||
onDragStartProp?.()
|
onDragStartProp?.()
|
||||||
},
|
},
|
||||||
@@ -177,11 +221,59 @@ export function FolderItem({
|
|||||||
isOpen: isContextMenuOpen,
|
isOpen: isContextMenuOpen,
|
||||||
position,
|
position,
|
||||||
menuRef,
|
menuRef,
|
||||||
handleContextMenu,
|
handleContextMenu: handleContextMenuBase,
|
||||||
closeMenu,
|
closeMenu,
|
||||||
preventDismiss,
|
preventDismiss,
|
||||||
} = useContextMenu()
|
} = useContextMenu()
|
||||||
|
|
||||||
|
const captureSelectionState = useCallback(() => {
|
||||||
|
const store = useFolderStore.getState()
|
||||||
|
const isFolderSelected = store.selectedFolders.has(folder.id)
|
||||||
|
|
||||||
|
if (!isFolderSelected) {
|
||||||
|
store.selectFolder(folder.id)
|
||||||
|
}
|
||||||
|
|
||||||
|
const finalFolderSelection = useFolderStore.getState().selectedFolders
|
||||||
|
const finalWorkflowSelection = useFolderStore.getState().selectedWorkflows
|
||||||
|
|
||||||
|
const folderIds = Array.from(finalFolderSelection)
|
||||||
|
const workflowIds = Array.from(finalWorkflowSelection)
|
||||||
|
const isMixed = folderIds.length > 0 && workflowIds.length > 0
|
||||||
|
|
||||||
|
const { folders } = useFolderStore.getState()
|
||||||
|
const { workflows } = useWorkflowRegistry.getState()
|
||||||
|
|
||||||
|
const names: string[] = []
|
||||||
|
for (const id of folderIds) {
|
||||||
|
const f = folders[id]
|
||||||
|
if (f) names.push(f.name)
|
||||||
|
}
|
||||||
|
for (const id of workflowIds) {
|
||||||
|
const w = workflows[id]
|
||||||
|
if (w) names.push(w.name)
|
||||||
|
}
|
||||||
|
|
||||||
|
capturedSelectionRef.current = {
|
||||||
|
workflowIds,
|
||||||
|
folderIds,
|
||||||
|
isMixed,
|
||||||
|
names,
|
||||||
|
}
|
||||||
|
|
||||||
|
const canDeleteAllFolders = folderIds.every((id) => canDeleteFolder(id))
|
||||||
|
const canDeleteAllWorkflows = workflowIds.length === 0 || canDeleteWorkflows(workflowIds)
|
||||||
|
setCanDeleteSelection(canDeleteAllFolders && canDeleteAllWorkflows)
|
||||||
|
}, [folder.id, canDeleteFolder, canDeleteWorkflows])
|
||||||
|
|
||||||
|
const handleContextMenu = useCallback(
|
||||||
|
(e: React.MouseEvent) => {
|
||||||
|
captureSelectionState()
|
||||||
|
handleContextMenuBase(e)
|
||||||
|
},
|
||||||
|
[captureSelectionState, handleContextMenuBase]
|
||||||
|
)
|
||||||
|
|
||||||
const {
|
const {
|
||||||
isEditing,
|
isEditing,
|
||||||
editValue,
|
editValue,
|
||||||
@@ -204,9 +296,8 @@ export function FolderItem({
|
|||||||
itemId: folder.id,
|
itemId: folder.id,
|
||||||
})
|
})
|
||||||
|
|
||||||
/**
|
isEditingRef.current = isEditing
|
||||||
* Handle double-click on folder name to enter rename mode
|
|
||||||
*/
|
|
||||||
const handleDoubleClick = useCallback(
|
const handleDoubleClick = useCallback(
|
||||||
(e: React.MouseEvent) => {
|
(e: React.MouseEvent) => {
|
||||||
e.preventDefault()
|
e.preventDefault()
|
||||||
@@ -216,11 +307,6 @@ export function FolderItem({
|
|||||||
[handleStartEdit]
|
[handleStartEdit]
|
||||||
)
|
)
|
||||||
|
|
||||||
/**
|
|
||||||
* Handle click - toggles folder expansion
|
|
||||||
*
|
|
||||||
* @param e - React mouse event
|
|
||||||
*/
|
|
||||||
const handleClick = useCallback(
|
const handleClick = useCallback(
|
||||||
(e: React.MouseEvent<HTMLDivElement>) => {
|
(e: React.MouseEvent<HTMLDivElement>) => {
|
||||||
e.stopPropagation()
|
e.stopPropagation()
|
||||||
@@ -229,14 +315,21 @@ export function FolderItem({
|
|||||||
e.preventDefault()
|
e.preventDefault()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const isModifierClick = e.shiftKey || e.metaKey || e.ctrlKey
|
||||||
|
|
||||||
|
if (isModifierClick && onFolderClick) {
|
||||||
|
e.preventDefault()
|
||||||
|
onFolderClick(folder.id, e.shiftKey, e.metaKey || e.ctrlKey)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
useFolderStore.getState().clearFolderSelection()
|
||||||
handleToggleExpanded()
|
handleToggleExpanded()
|
||||||
},
|
},
|
||||||
[handleToggleExpanded, shouldPreventClickRef, isEditing]
|
[handleToggleExpanded, shouldPreventClickRef, isEditing, onFolderClick, folder.id]
|
||||||
)
|
)
|
||||||
|
|
||||||
/**
|
|
||||||
* Combined keyboard handler for both expand and rename
|
|
||||||
*/
|
|
||||||
const handleKeyDown = useCallback(
|
const handleKeyDown = useCallback(
|
||||||
(e: React.KeyboardEvent<HTMLDivElement>) => {
|
(e: React.KeyboardEvent<HTMLDivElement>) => {
|
||||||
if (isEditing) {
|
if (isEditing) {
|
||||||
@@ -248,18 +341,12 @@ export function FolderItem({
|
|||||||
[isEditing, handleRenameKeyDown, handleExpandKeyDown]
|
[isEditing, handleRenameKeyDown, handleExpandKeyDown]
|
||||||
)
|
)
|
||||||
|
|
||||||
/**
|
|
||||||
* Handle more button pointerdown - prevents click-outside dismissal when toggling
|
|
||||||
*/
|
|
||||||
const handleMorePointerDown = useCallback(() => {
|
const handleMorePointerDown = useCallback(() => {
|
||||||
if (isContextMenuOpen) {
|
if (isContextMenuOpen) {
|
||||||
preventDismiss()
|
preventDismiss()
|
||||||
}
|
}
|
||||||
}, [isContextMenuOpen, preventDismiss])
|
}, [isContextMenuOpen, preventDismiss])
|
||||||
|
|
||||||
/**
|
|
||||||
* Handle more button click - toggles context menu at button position
|
|
||||||
*/
|
|
||||||
const handleMoreClick = useCallback(
|
const handleMoreClick = useCallback(
|
||||||
(e: React.MouseEvent<HTMLButtonElement>) => {
|
(e: React.MouseEvent<HTMLButtonElement>) => {
|
||||||
e.preventDefault()
|
e.preventDefault()
|
||||||
@@ -270,17 +357,83 @@ export function FolderItem({
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
captureSelectionState()
|
||||||
const rect = e.currentTarget.getBoundingClientRect()
|
const rect = e.currentTarget.getBoundingClientRect()
|
||||||
handleContextMenu({
|
handleContextMenuBase({
|
||||||
preventDefault: () => {},
|
preventDefault: () => {},
|
||||||
stopPropagation: () => {},
|
stopPropagation: () => {},
|
||||||
clientX: rect.right,
|
clientX: rect.right,
|
||||||
clientY: rect.top,
|
clientY: rect.top,
|
||||||
} as React.MouseEvent)
|
} as React.MouseEvent)
|
||||||
},
|
},
|
||||||
[isContextMenuOpen, closeMenu, handleContextMenu]
|
[isContextMenuOpen, closeMenu, captureSelectionState, handleContextMenuBase]
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const handleOpenDeleteModal = useCallback(() => {
|
||||||
|
if (!capturedSelectionRef.current) return
|
||||||
|
|
||||||
|
const { isMixed, names, folderIds } = capturedSelectionRef.current
|
||||||
|
|
||||||
|
if (isMixed) {
|
||||||
|
setDeleteItemType('mixed')
|
||||||
|
setDeleteItemNames(names)
|
||||||
|
} else if (folderIds.length > 1) {
|
||||||
|
setDeleteItemType('folder')
|
||||||
|
setDeleteItemNames(names)
|
||||||
|
} else {
|
||||||
|
setDeleteItemType('folder')
|
||||||
|
setDeleteItemNames(folder.name)
|
||||||
|
}
|
||||||
|
|
||||||
|
setIsDeleteModalOpen(true)
|
||||||
|
}, [folder.name])
|
||||||
|
|
||||||
|
const handleConfirmDelete = useCallback(async () => {
|
||||||
|
if (!capturedSelectionRef.current) return
|
||||||
|
|
||||||
|
const { isMixed, folderIds } = capturedSelectionRef.current
|
||||||
|
|
||||||
|
if (isMixed || folderIds.length > 1) {
|
||||||
|
await handleDeleteSelection()
|
||||||
|
} else {
|
||||||
|
await handleDeleteThisFolder()
|
||||||
|
}
|
||||||
|
}, [handleDeleteSelection, handleDeleteThisFolder])
|
||||||
|
|
||||||
|
const handleExport = useCallback(async () => {
|
||||||
|
if (!capturedSelectionRef.current) return
|
||||||
|
|
||||||
|
const { isMixed, workflowIds, folderIds } = capturedSelectionRef.current
|
||||||
|
|
||||||
|
if (isMixed || folderIds.length > 1) {
|
||||||
|
await handleExportSelection(workflowIds, folderIds)
|
||||||
|
} else {
|
||||||
|
await handleExportThisFolder()
|
||||||
|
}
|
||||||
|
}, [handleExportSelection, handleExportThisFolder])
|
||||||
|
|
||||||
|
const handleDuplicate = useCallback(async () => {
|
||||||
|
if (!capturedSelectionRef.current) return
|
||||||
|
|
||||||
|
const { isMixed, workflowIds, folderIds } = capturedSelectionRef.current
|
||||||
|
|
||||||
|
if (isMixed || folderIds.length > 1) {
|
||||||
|
await handleDuplicateSelection(workflowIds, folderIds)
|
||||||
|
} else {
|
||||||
|
await handleDuplicateThisFolder()
|
||||||
|
}
|
||||||
|
}, [handleDuplicateSelection, handleDuplicateThisFolder])
|
||||||
|
|
||||||
|
const isMixedSelection = useMemo(() => {
|
||||||
|
return capturedSelectionRef.current?.isMixed ?? false
|
||||||
|
}, [isContextMenuOpen])
|
||||||
|
|
||||||
|
const hasExportableContent = useMemo(() => {
|
||||||
|
if (!capturedSelectionRef.current) return hasWorkflows
|
||||||
|
const { workflowIds } = capturedSelectionRef.current
|
||||||
|
return workflowIds.length > 0 || hasWorkflows
|
||||||
|
}, [isContextMenuOpen, hasWorkflows])
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<div
|
<div
|
||||||
@@ -290,8 +443,10 @@ export function FolderItem({
|
|||||||
aria-expanded={isExpanded}
|
aria-expanded={isExpanded}
|
||||||
aria-label={`${folder.name} folder, ${isExpanded ? 'expanded' : 'collapsed'}`}
|
aria-label={`${folder.name} folder, ${isExpanded ? 'expanded' : 'collapsed'}`}
|
||||||
className={clsx(
|
className={clsx(
|
||||||
'group flex h-[26px] cursor-pointer items-center gap-[8px] rounded-[8px] px-[6px] text-[14px] hover:bg-[var(--surface-6)] dark:hover:bg-[var(--surface-5)]',
|
'group flex h-[26px] cursor-pointer items-center gap-[8px] rounded-[8px] px-[6px] text-[14px]',
|
||||||
isDragging ? 'opacity-50' : ''
|
!isAnyDragActive && 'hover:bg-[var(--surface-6)] dark:hover:bg-[var(--surface-5)]',
|
||||||
|
isSelected ? 'bg-[var(--surface-6)] dark:bg-[var(--surface-5)]' : '',
|
||||||
|
(isDragging || (isAnyDragActive && isSelected)) && 'opacity-50'
|
||||||
)}
|
)}
|
||||||
onClick={handleClick}
|
onClick={handleClick}
|
||||||
onKeyDown={handleKeyDown}
|
onKeyDown={handleKeyDown}
|
||||||
@@ -303,20 +458,26 @@ export function FolderItem({
|
|||||||
>
|
>
|
||||||
<ChevronRight
|
<ChevronRight
|
||||||
className={clsx(
|
className={clsx(
|
||||||
'h-3.5 w-3.5 flex-shrink-0 transition-transform duration-100',
|
'h-3.5 w-3.5 flex-shrink-0 text-[var(--text-tertiary)] transition-transform duration-100',
|
||||||
'text-[var(--text-tertiary)] group-hover:text-[var(--text-primary)]',
|
!isAnyDragActive && 'group-hover:text-[var(--text-primary)]',
|
||||||
isExpanded && 'rotate-90'
|
isExpanded && 'rotate-90'
|
||||||
)}
|
)}
|
||||||
aria-hidden='true'
|
aria-hidden='true'
|
||||||
/>
|
/>
|
||||||
{isExpanded ? (
|
{isExpanded ? (
|
||||||
<FolderOpen
|
<FolderOpen
|
||||||
className='h-[14px] w-[14px] flex-shrink-0 text-[var(--text-tertiary)] group-hover:text-[var(--text-primary)]'
|
className={clsx(
|
||||||
|
'h-[14px] w-[14px] flex-shrink-0 text-[var(--text-tertiary)]',
|
||||||
|
!isAnyDragActive && 'group-hover:text-[var(--text-primary)]'
|
||||||
|
)}
|
||||||
aria-hidden='true'
|
aria-hidden='true'
|
||||||
/>
|
/>
|
||||||
) : (
|
) : (
|
||||||
<Folder
|
<Folder
|
||||||
className='h-[14px] w-[14px] flex-shrink-0 text-[var(--text-tertiary)] group-hover:text-[var(--text-primary)]'
|
className={clsx(
|
||||||
|
'h-[14px] w-[14px] flex-shrink-0 text-[var(--text-tertiary)]',
|
||||||
|
!isAnyDragActive && 'group-hover:text-[var(--text-primary)]'
|
||||||
|
)}
|
||||||
aria-hidden='true'
|
aria-hidden='true'
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
@@ -344,16 +505,23 @@ export function FolderItem({
|
|||||||
) : (
|
) : (
|
||||||
<div className='flex min-w-0 flex-1 items-center gap-[8px]'>
|
<div className='flex min-w-0 flex-1 items-center gap-[8px]'>
|
||||||
<span
|
<span
|
||||||
className='min-w-0 flex-1 truncate font-medium text-[var(--text-tertiary)] group-hover:text-[var(--text-primary)]'
|
className={clsx(
|
||||||
|
'min-w-0 flex-1 truncate font-medium text-[var(--text-tertiary)]',
|
||||||
|
!isAnyDragActive && 'group-hover:text-[var(--text-primary)]'
|
||||||
|
)}
|
||||||
onDoubleClick={handleDoubleClick}
|
onDoubleClick={handleDoubleClick}
|
||||||
>
|
>
|
||||||
{folder.name}
|
{folder.name}
|
||||||
</span>
|
</span>
|
||||||
<button
|
<button
|
||||||
type='button'
|
type='button'
|
||||||
|
aria-label='Folder options'
|
||||||
onPointerDown={handleMorePointerDown}
|
onPointerDown={handleMorePointerDown}
|
||||||
onClick={handleMoreClick}
|
onClick={handleMoreClick}
|
||||||
className='flex h-[18px] w-[18px] flex-shrink-0 items-center justify-center rounded-[4px] opacity-0 transition-opacity hover:bg-[var(--surface-7)] group-hover:opacity-100'
|
className={clsx(
|
||||||
|
'flex h-[18px] w-[18px] flex-shrink-0 items-center justify-center rounded-[4px] opacity-0 transition-opacity hover:bg-[var(--surface-7)]',
|
||||||
|
!isAnyDragActive && 'group-hover:opacity-100'
|
||||||
|
)}
|
||||||
>
|
>
|
||||||
<MoreHorizontal className='h-[14px] w-[14px] text-[var(--text-tertiary)]' />
|
<MoreHorizontal className='h-[14px] w-[14px] text-[var(--text-tertiary)]' />
|
||||||
</button>
|
</button>
|
||||||
@@ -361,7 +529,6 @@ export function FolderItem({
|
|||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Context Menu */}
|
|
||||||
<ContextMenu
|
<ContextMenu
|
||||||
isOpen={isContextMenuOpen}
|
isOpen={isContextMenuOpen}
|
||||||
position={position}
|
position={position}
|
||||||
@@ -370,28 +537,31 @@ export function FolderItem({
|
|||||||
onRename={handleStartEdit}
|
onRename={handleStartEdit}
|
||||||
onCreate={handleCreateWorkflowInFolder}
|
onCreate={handleCreateWorkflowInFolder}
|
||||||
onCreateFolder={handleCreateFolderInFolder}
|
onCreateFolder={handleCreateFolderInFolder}
|
||||||
onDuplicate={handleDuplicateFolder}
|
onDuplicate={handleDuplicate}
|
||||||
onExport={handleExportFolder}
|
onExport={handleExport}
|
||||||
onDelete={() => setIsDeleteModalOpen(true)}
|
onDelete={handleOpenDeleteModal}
|
||||||
showCreate={true}
|
showCreate={!isMixedSelection}
|
||||||
showCreateFolder={true}
|
showCreateFolder={!isMixedSelection}
|
||||||
|
showRename={!isMixedSelection && selectedFolders.size <= 1}
|
||||||
|
showDuplicate={true}
|
||||||
showExport={true}
|
showExport={true}
|
||||||
disableRename={!userPermissions.canEdit}
|
disableRename={!userPermissions.canEdit}
|
||||||
disableCreate={!userPermissions.canEdit || createWorkflowMutation.isPending}
|
disableCreate={!userPermissions.canEdit || createWorkflowMutation.isPending}
|
||||||
disableCreateFolder={!userPermissions.canEdit || createFolderMutation.isPending}
|
disableCreateFolder={!userPermissions.canEdit || createFolderMutation.isPending}
|
||||||
disableDuplicate={!userPermissions.canEdit || !hasWorkflows}
|
disableDuplicate={
|
||||||
disableExport={!userPermissions.canEdit || isExporting || !hasWorkflows}
|
!userPermissions.canEdit || isDuplicatingSelection || !hasExportableContent
|
||||||
disableDelete={!userPermissions.canEdit || !canDelete}
|
}
|
||||||
|
disableExport={!userPermissions.canEdit || isExporting || !hasExportableContent}
|
||||||
|
disableDelete={!userPermissions.canEdit || !canDeleteSelection}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
{/* Delete Modal */}
|
|
||||||
<DeleteModal
|
<DeleteModal
|
||||||
isOpen={isDeleteModalOpen}
|
isOpen={isDeleteModalOpen}
|
||||||
onClose={() => setIsDeleteModalOpen(false)}
|
onClose={() => setIsDeleteModalOpen(false)}
|
||||||
onConfirm={handleDeleteFolder}
|
onConfirm={handleConfirmDelete}
|
||||||
isDeleting={isDeleting}
|
isDeleting={isDeleting}
|
||||||
itemType='folder'
|
itemType={deleteItemType}
|
||||||
itemName={folder.name}
|
itemName={deleteItemNames}
|
||||||
/>
|
/>
|
||||||
</>
|
</>
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -51,7 +51,7 @@ function UserAvatar({ user, index }: UserAvatarProps) {
|
|||||||
)}
|
)}
|
||||||
<AvatarFallback
|
<AvatarFallback
|
||||||
style={{ background: color }}
|
style={{ background: color }}
|
||||||
className='border-0 font-semibold text-[7px] text-white'
|
className='border-0 font-semibold text-[7px] text-white leading-none'
|
||||||
>
|
>
|
||||||
{initials}
|
{initials}
|
||||||
</AvatarFallback>
|
</AvatarFallback>
|
||||||
@@ -132,7 +132,7 @@ export function Avatars({ workflowId }: AvatarsProps) {
|
|||||||
<Tooltip.Root>
|
<Tooltip.Root>
|
||||||
<Tooltip.Trigger asChild>
|
<Tooltip.Trigger asChild>
|
||||||
<Avatar size='xs' style={{ zIndex: 0 } as CSSProperties}>
|
<Avatar size='xs' style={{ zIndex: 0 } as CSSProperties}>
|
||||||
<AvatarFallback className='border-0 bg-[#404040] font-semibold text-[7px] text-white'>
|
<AvatarFallback className='border-0 bg-[#404040] font-semibold text-[7px] text-white leading-none'>
|
||||||
+{overflowCount}
|
+{overflowCount}
|
||||||
</AvatarFallback>
|
</AvatarFallback>
|
||||||
</Avatar>
|
</Avatar>
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
'use client'
|
'use client'
|
||||||
|
|
||||||
import { useCallback, useRef, useState } from 'react'
|
import { useCallback, useMemo, useRef, useState } from 'react'
|
||||||
import clsx from 'clsx'
|
import clsx from 'clsx'
|
||||||
import { MoreHorizontal } from 'lucide-react'
|
import { MoreHorizontal } from 'lucide-react'
|
||||||
import Link from 'next/link'
|
import Link from 'next/link'
|
||||||
@@ -13,11 +13,15 @@ import {
|
|||||||
useContextMenu,
|
useContextMenu,
|
||||||
useItemDrag,
|
useItemDrag,
|
||||||
useItemRename,
|
useItemRename,
|
||||||
|
useSidebarDragContext,
|
||||||
} from '@/app/workspace/[workspaceId]/w/components/sidebar/hooks'
|
} from '@/app/workspace/[workspaceId]/w/components/sidebar/hooks'
|
||||||
import {
|
import {
|
||||||
useCanDelete,
|
useCanDelete,
|
||||||
|
useDeleteSelection,
|
||||||
useDeleteWorkflow,
|
useDeleteWorkflow,
|
||||||
|
useDuplicateSelection,
|
||||||
useDuplicateWorkflow,
|
useDuplicateWorkflow,
|
||||||
|
useExportSelection,
|
||||||
useExportWorkflow,
|
useExportWorkflow,
|
||||||
} from '@/app/workspace/[workspaceId]/w/hooks'
|
} from '@/app/workspace/[workspaceId]/w/hooks'
|
||||||
import { useFolderStore } from '@/stores/folders/store'
|
import { useFolderStore } from '@/stores/folders/store'
|
||||||
@@ -50,6 +54,7 @@ export function WorkflowItem({
|
|||||||
onDragStart: onDragStartProp,
|
onDragStart: onDragStartProp,
|
||||||
onDragEnd: onDragEndProp,
|
onDragEnd: onDragEndProp,
|
||||||
}: WorkflowItemProps) {
|
}: WorkflowItemProps) {
|
||||||
|
const { isAnyDragActive } = useSidebarDragContext()
|
||||||
const params = useParams()
|
const params = useParams()
|
||||||
const workspaceId = params.workspaceId as string
|
const workspaceId = params.workspaceId as string
|
||||||
const selectedWorkflows = useFolderStore((state) => state.selectedWorkflows)
|
const selectedWorkflows = useFolderStore((state) => state.selectedWorkflows)
|
||||||
@@ -57,50 +62,101 @@ export function WorkflowItem({
|
|||||||
const userPermissions = useUserPermissionsContext()
|
const userPermissions = useUserPermissionsContext()
|
||||||
const isSelected = selectedWorkflows.has(workflow.id)
|
const isSelected = selectedWorkflows.has(workflow.id)
|
||||||
|
|
||||||
const { canDeleteWorkflows } = useCanDelete({ workspaceId })
|
const { canDeleteWorkflows, canDeleteFolder } = useCanDelete({ workspaceId })
|
||||||
|
|
||||||
const [isDeleteModalOpen, setIsDeleteModalOpen] = useState(false)
|
const [isDeleteModalOpen, setIsDeleteModalOpen] = useState(false)
|
||||||
const [workflowIdsToDelete, setWorkflowIdsToDelete] = useState<string[]>([])
|
const [deleteItemType, setDeleteItemType] = useState<'workflow' | 'mixed'>('workflow')
|
||||||
const [deleteModalNames, setDeleteModalNames] = useState<string | string[]>('')
|
const [deleteModalNames, setDeleteModalNames] = useState<string | string[]>('')
|
||||||
const [canDeleteCaptured, setCanDeleteCaptured] = useState(true)
|
const [canDeleteSelection, setCanDeleteSelection] = useState(true)
|
||||||
|
|
||||||
const capturedSelectionRef = useRef<{
|
const capturedSelectionRef = useRef<{
|
||||||
workflowIds: string[]
|
workflowIds: string[]
|
||||||
workflowNames: string | string[]
|
folderIds: string[]
|
||||||
|
isMixed: boolean
|
||||||
|
names: string[]
|
||||||
} | null>(null)
|
} | null>(null)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handle opening the delete modal - uses pre-captured selection state
|
* Handle opening the delete modal - uses pre-captured selection state
|
||||||
*/
|
*/
|
||||||
const handleOpenDeleteModal = useCallback(() => {
|
const handleOpenDeleteModal = useCallback(() => {
|
||||||
if (capturedSelectionRef.current) {
|
if (!capturedSelectionRef.current) return
|
||||||
setWorkflowIdsToDelete(capturedSelectionRef.current.workflowIds)
|
|
||||||
setDeleteModalNames(capturedSelectionRef.current.workflowNames)
|
const { isMixed, names } = capturedSelectionRef.current
|
||||||
setIsDeleteModalOpen(true)
|
|
||||||
|
if (isMixed) {
|
||||||
|
setDeleteItemType('mixed')
|
||||||
|
} else {
|
||||||
|
setDeleteItemType('workflow')
|
||||||
}
|
}
|
||||||
|
|
||||||
|
setDeleteModalNames(names.length > 1 ? names : names[0] || '')
|
||||||
|
setIsDeleteModalOpen(true)
|
||||||
}, [])
|
}, [])
|
||||||
|
|
||||||
const { isDeleting, handleDeleteWorkflow } = useDeleteWorkflow({
|
const { isDeleting: isDeletingWorkflows, handleDeleteWorkflow: handleDeleteWorkflows } =
|
||||||
|
useDeleteWorkflow({
|
||||||
workspaceId,
|
workspaceId,
|
||||||
workflowIds: workflowIdsToDelete,
|
workflowIds: capturedSelectionRef.current?.workflowIds || [],
|
||||||
isActive: (workflowIds) => workflowIds.includes(params.workflowId as string),
|
isActive: (workflowIds) => workflowIds.includes(params.workflowId as string),
|
||||||
onSuccess: () => setIsDeleteModalOpen(false),
|
onSuccess: () => setIsDeleteModalOpen(false),
|
||||||
})
|
})
|
||||||
|
|
||||||
const { handleDuplicateWorkflow: duplicateWorkflow } = useDuplicateWorkflow({ workspaceId })
|
const { isDeleting: isDeletingSelection, handleDeleteSelection } = useDeleteSelection({
|
||||||
|
workspaceId,
|
||||||
|
workflowIds: capturedSelectionRef.current?.workflowIds || [],
|
||||||
|
folderIds: capturedSelectionRef.current?.folderIds || [],
|
||||||
|
isActiveWorkflow: (id) => id === params.workflowId,
|
||||||
|
onSuccess: () => setIsDeleteModalOpen(false),
|
||||||
|
})
|
||||||
|
|
||||||
const { handleExportWorkflow: exportWorkflow } = useExportWorkflow()
|
const isDeleting = isDeletingWorkflows || isDeletingSelection
|
||||||
const handleDuplicateWorkflow = useCallback(() => {
|
|
||||||
const workflowIds = capturedSelectionRef.current?.workflowIds || []
|
|
||||||
if (workflowIds.length === 0) return
|
|
||||||
duplicateWorkflow(workflowIds)
|
|
||||||
}, [duplicateWorkflow])
|
|
||||||
|
|
||||||
const handleExportWorkflow = useCallback(() => {
|
const handleConfirmDelete = useCallback(async () => {
|
||||||
const workflowIds = capturedSelectionRef.current?.workflowIds || []
|
if (!capturedSelectionRef.current) return
|
||||||
|
|
||||||
|
const { isMixed } = capturedSelectionRef.current
|
||||||
|
|
||||||
|
if (isMixed) {
|
||||||
|
await handleDeleteSelection()
|
||||||
|
} else {
|
||||||
|
await handleDeleteWorkflows()
|
||||||
|
}
|
||||||
|
}, [handleDeleteSelection, handleDeleteWorkflows])
|
||||||
|
|
||||||
|
const { handleDuplicateWorkflow: duplicateWorkflows } = useDuplicateWorkflow({ workspaceId })
|
||||||
|
const { isDuplicating: isDuplicatingSelection, handleDuplicateSelection } = useDuplicateSelection(
|
||||||
|
{ workspaceId }
|
||||||
|
)
|
||||||
|
|
||||||
|
const { handleExportWorkflow: handleExportWorkflows } = useExportWorkflow()
|
||||||
|
const { handleExportSelection } = useExportSelection()
|
||||||
|
|
||||||
|
const handleDuplicate = useCallback(() => {
|
||||||
|
if (!capturedSelectionRef.current) return
|
||||||
|
|
||||||
|
const { isMixed, workflowIds, folderIds } = capturedSelectionRef.current
|
||||||
|
|
||||||
|
if (isMixed) {
|
||||||
|
handleDuplicateSelection(workflowIds, folderIds)
|
||||||
|
} else {
|
||||||
if (workflowIds.length === 0) return
|
if (workflowIds.length === 0) return
|
||||||
exportWorkflow(workflowIds)
|
duplicateWorkflows(workflowIds)
|
||||||
}, [exportWorkflow])
|
}
|
||||||
|
}, [duplicateWorkflows, handleDuplicateSelection])
|
||||||
|
|
||||||
|
const handleExport = useCallback(() => {
|
||||||
|
if (!capturedSelectionRef.current) return
|
||||||
|
|
||||||
|
const { isMixed, workflowIds, folderIds } = capturedSelectionRef.current
|
||||||
|
|
||||||
|
if (isMixed) {
|
||||||
|
handleExportSelection(workflowIds, folderIds)
|
||||||
|
} else {
|
||||||
|
if (workflowIds.length === 0) return
|
||||||
|
handleExportWorkflows(workflowIds)
|
||||||
|
}
|
||||||
|
}, [handleExportWorkflows, handleExportSelection])
|
||||||
|
|
||||||
const handleOpenInNewTab = useCallback(() => {
|
const handleOpenInNewTab = useCallback(() => {
|
||||||
window.open(`/workspace/${workspaceId}/w/${workflow.id}`, '_blank')
|
window.open(`/workspace/${workspaceId}/w/${workflow.id}`, '_blank')
|
||||||
@@ -124,41 +180,51 @@ export function WorkflowItem({
|
|||||||
preventDismiss,
|
preventDismiss,
|
||||||
} = useContextMenu()
|
} = useContextMenu()
|
||||||
|
|
||||||
/**
|
const isMixedSelection = useMemo(() => {
|
||||||
* Captures selection state for context menu operations
|
return capturedSelectionRef.current?.isMixed ?? false
|
||||||
*/
|
}, [isContextMenuOpen])
|
||||||
|
|
||||||
const captureSelectionState = useCallback(() => {
|
const captureSelectionState = useCallback(() => {
|
||||||
const { selectedWorkflows: currentSelection, selectOnly } = useFolderStore.getState()
|
const store = useFolderStore.getState()
|
||||||
const isCurrentlySelected = currentSelection.has(workflow.id)
|
const isCurrentlySelected = store.selectedWorkflows.has(workflow.id)
|
||||||
|
|
||||||
if (!isCurrentlySelected) {
|
if (!isCurrentlySelected) {
|
||||||
selectOnly(workflow.id)
|
store.selectWorkflow(workflow.id)
|
||||||
}
|
}
|
||||||
|
|
||||||
const finalSelection = useFolderStore.getState().selectedWorkflows
|
const finalWorkflowSelection = useFolderStore.getState().selectedWorkflows
|
||||||
const finalIsSelected = finalSelection.has(workflow.id)
|
const finalFolderSelection = useFolderStore.getState().selectedFolders
|
||||||
|
|
||||||
const workflowIds =
|
const workflowIds = Array.from(finalWorkflowSelection)
|
||||||
finalIsSelected && finalSelection.size > 1 ? Array.from(finalSelection) : [workflow.id]
|
const folderIds = Array.from(finalFolderSelection)
|
||||||
|
const isMixed = workflowIds.length > 0 && folderIds.length > 0
|
||||||
|
|
||||||
const { workflows } = useWorkflowRegistry.getState()
|
const { workflows } = useWorkflowRegistry.getState()
|
||||||
const workflowNames = workflowIds
|
const { folders } = useFolderStore.getState()
|
||||||
.map((id) => workflows[id]?.name)
|
|
||||||
.filter((name): name is string => !!name)
|
const names: string[] = []
|
||||||
|
for (const id of workflowIds) {
|
||||||
|
const w = workflows[id]
|
||||||
|
if (w) names.push(w.name)
|
||||||
|
}
|
||||||
|
for (const id of folderIds) {
|
||||||
|
const f = folders[id]
|
||||||
|
if (f) names.push(f.name)
|
||||||
|
}
|
||||||
|
|
||||||
capturedSelectionRef.current = {
|
capturedSelectionRef.current = {
|
||||||
workflowIds,
|
workflowIds,
|
||||||
workflowNames: workflowNames.length > 1 ? workflowNames : workflowNames[0],
|
folderIds,
|
||||||
|
isMixed,
|
||||||
|
names,
|
||||||
}
|
}
|
||||||
|
|
||||||
setCanDeleteCaptured(canDeleteWorkflows(workflowIds))
|
const canDeleteAllWorkflows = canDeleteWorkflows(workflowIds)
|
||||||
}, [workflow.id, canDeleteWorkflows])
|
const canDeleteAllFolders =
|
||||||
|
folderIds.length === 0 || folderIds.every((id) => canDeleteFolder(id))
|
||||||
|
setCanDeleteSelection(canDeleteAllWorkflows && canDeleteAllFolders)
|
||||||
|
}, [workflow.id, canDeleteWorkflows, canDeleteFolder])
|
||||||
|
|
||||||
/**
|
|
||||||
* Handle right-click - ensure proper selection behavior and capture selection state
|
|
||||||
* If right-clicking on an unselected workflow, select only that workflow
|
|
||||||
* If right-clicking on a selected workflow with multiple selections, keep all selections
|
|
||||||
*/
|
|
||||||
const handleContextMenu = useCallback(
|
const handleContextMenu = useCallback(
|
||||||
(e: React.MouseEvent) => {
|
(e: React.MouseEvent) => {
|
||||||
captureSelectionState()
|
captureSelectionState()
|
||||||
@@ -167,18 +233,12 @@ export function WorkflowItem({
|
|||||||
[captureSelectionState, handleContextMenuBase]
|
[captureSelectionState, handleContextMenuBase]
|
||||||
)
|
)
|
||||||
|
|
||||||
/**
|
|
||||||
* Handle more button pointerdown - prevents click-outside dismissal when toggling
|
|
||||||
*/
|
|
||||||
const handleMorePointerDown = useCallback(() => {
|
const handleMorePointerDown = useCallback(() => {
|
||||||
if (isContextMenuOpen) {
|
if (isContextMenuOpen) {
|
||||||
preventDismiss()
|
preventDismiss()
|
||||||
}
|
}
|
||||||
}, [isContextMenuOpen, preventDismiss])
|
}, [isContextMenuOpen, preventDismiss])
|
||||||
|
|
||||||
/**
|
|
||||||
* Handle more button click - toggles context menu at button position
|
|
||||||
*/
|
|
||||||
const handleMoreClick = useCallback(
|
const handleMoreClick = useCallback(
|
||||||
(e: React.MouseEvent<HTMLButtonElement>) => {
|
(e: React.MouseEvent<HTMLButtonElement>) => {
|
||||||
e.preventDefault()
|
e.preventDefault()
|
||||||
@@ -228,14 +288,20 @@ export function WorkflowItem({
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
const currentSelection = useFolderStore.getState().selectedWorkflows
|
const { selectedWorkflows, selectedFolders } = useFolderStore.getState()
|
||||||
const isCurrentlySelected = currentSelection.has(workflow.id)
|
const isCurrentlySelected = selectedWorkflows.has(workflow.id)
|
||||||
const workflowIds =
|
|
||||||
isCurrentlySelected && currentSelection.size > 1
|
|
||||||
? Array.from(currentSelection)
|
|
||||||
: [workflow.id]
|
|
||||||
|
|
||||||
e.dataTransfer.setData('workflow-ids', JSON.stringify(workflowIds))
|
const selection = isCurrentlySelected
|
||||||
|
? {
|
||||||
|
workflowIds: Array.from(selectedWorkflows),
|
||||||
|
folderIds: Array.from(selectedFolders),
|
||||||
|
}
|
||||||
|
: {
|
||||||
|
workflowIds: [workflow.id],
|
||||||
|
folderIds: [],
|
||||||
|
}
|
||||||
|
|
||||||
|
e.dataTransfer.setData('sidebar-selection', JSON.stringify(selection))
|
||||||
e.dataTransfer.effectAllowed = 'move'
|
e.dataTransfer.effectAllowed = 'move'
|
||||||
onDragStartProp?.()
|
onDragStartProp?.()
|
||||||
},
|
},
|
||||||
@@ -256,9 +322,6 @@ export function WorkflowItem({
|
|||||||
onDragEndProp?.()
|
onDragEndProp?.()
|
||||||
}, [handleDragEndBase, onDragEndProp])
|
}, [handleDragEndBase, onDragEndProp])
|
||||||
|
|
||||||
/**
|
|
||||||
* Handle double-click on workflow name to enter rename mode
|
|
||||||
*/
|
|
||||||
const handleDoubleClick = useCallback(
|
const handleDoubleClick = useCallback(
|
||||||
(e: React.MouseEvent) => {
|
(e: React.MouseEvent) => {
|
||||||
e.preventDefault()
|
e.preventDefault()
|
||||||
@@ -268,11 +331,6 @@ export function WorkflowItem({
|
|||||||
[handleStartEdit]
|
[handleStartEdit]
|
||||||
)
|
)
|
||||||
|
|
||||||
/**
|
|
||||||
* Handle click - manages workflow selection with shift-key and cmd/ctrl-key support
|
|
||||||
*
|
|
||||||
* @param e - React mouse event
|
|
||||||
*/
|
|
||||||
const handleClick = useCallback(
|
const handleClick = useCallback(
|
||||||
(e: React.MouseEvent<HTMLAnchorElement>) => {
|
(e: React.MouseEvent<HTMLAnchorElement>) => {
|
||||||
e.stopPropagation()
|
e.stopPropagation()
|
||||||
@@ -300,13 +358,15 @@ export function WorkflowItem({
|
|||||||
data-item-id={workflow.id}
|
data-item-id={workflow.id}
|
||||||
className={clsx(
|
className={clsx(
|
||||||
'group flex h-[26px] items-center gap-[8px] rounded-[8px] px-[6px] text-[14px]',
|
'group flex h-[26px] items-center gap-[8px] rounded-[8px] px-[6px] text-[14px]',
|
||||||
active
|
active && 'bg-[var(--surface-6)] dark:bg-[var(--surface-5)]',
|
||||||
? 'bg-[var(--surface-6)] dark:bg-[var(--surface-5)]'
|
!active &&
|
||||||
: 'hover:bg-[var(--surface-6)] dark:hover:bg-[var(--surface-5)]',
|
!isAnyDragActive &&
|
||||||
isSelected && selectedWorkflows.size > 1 && !active
|
'hover:bg-[var(--surface-6)] dark:hover:bg-[var(--surface-5)]',
|
||||||
? 'bg-[var(--surface-6)] dark:bg-[var(--surface-5)]'
|
isSelected &&
|
||||||
: '',
|
selectedWorkflows.size > 1 &&
|
||||||
isDragging ? 'opacity-50' : ''
|
!active &&
|
||||||
|
'bg-[var(--surface-6)] dark:bg-[var(--surface-5)]',
|
||||||
|
(isDragging || (isAnyDragActive && isSelected)) && 'opacity-50'
|
||||||
)}
|
)}
|
||||||
draggable={!isEditing && !dragDisabled}
|
draggable={!isEditing && !dragDisabled}
|
||||||
onDragStart={handleDragStart}
|
onDragStart={handleDragStart}
|
||||||
@@ -329,9 +389,8 @@ export function WorkflowItem({
|
|||||||
onBlur={handleInputBlur}
|
onBlur={handleInputBlur}
|
||||||
className={clsx(
|
className={clsx(
|
||||||
'w-full min-w-0 border-0 bg-transparent p-0 font-medium text-[14px] outline-none focus:outline-none focus:ring-0 focus-visible:outline-none focus-visible:ring-0 focus-visible:ring-offset-0',
|
'w-full min-w-0 border-0 bg-transparent p-0 font-medium text-[14px] outline-none focus:outline-none focus:ring-0 focus-visible:outline-none focus-visible:ring-0 focus-visible:ring-offset-0',
|
||||||
active
|
active ? 'text-[var(--text-primary)]' : 'text-[var(--text-tertiary)]',
|
||||||
? 'text-[var(--text-primary)]'
|
!active && !isAnyDragActive && 'group-hover:text-[var(--text-primary)]'
|
||||||
: 'text-[var(--text-tertiary)] group-hover:text-[var(--text-primary)]'
|
|
||||||
)}
|
)}
|
||||||
maxLength={100}
|
maxLength={100}
|
||||||
disabled={isRenaming}
|
disabled={isRenaming}
|
||||||
@@ -348,9 +407,8 @@ export function WorkflowItem({
|
|||||||
<div
|
<div
|
||||||
className={clsx(
|
className={clsx(
|
||||||
'min-w-0 truncate font-medium',
|
'min-w-0 truncate font-medium',
|
||||||
active
|
active ? 'text-[var(--text-primary)]' : 'text-[var(--text-tertiary)]',
|
||||||
? 'text-[var(--text-primary)]'
|
!active && !isAnyDragActive && 'group-hover:text-[var(--text-primary)]'
|
||||||
: 'text-[var(--text-tertiary)] group-hover:text-[var(--text-primary)]'
|
|
||||||
)}
|
)}
|
||||||
onDoubleClick={handleDoubleClick}
|
onDoubleClick={handleDoubleClick}
|
||||||
>
|
>
|
||||||
@@ -364,9 +422,13 @@ export function WorkflowItem({
|
|||||||
<>
|
<>
|
||||||
<button
|
<button
|
||||||
type='button'
|
type='button'
|
||||||
|
aria-label='Workflow options'
|
||||||
onPointerDown={handleMorePointerDown}
|
onPointerDown={handleMorePointerDown}
|
||||||
onClick={handleMoreClick}
|
onClick={handleMoreClick}
|
||||||
className='flex h-[18px] w-[18px] flex-shrink-0 items-center justify-center rounded-[4px] opacity-0 transition-opacity hover:bg-[var(--surface-7)] group-hover:opacity-100'
|
className={clsx(
|
||||||
|
'flex h-[18px] w-[18px] flex-shrink-0 items-center justify-center rounded-[4px] opacity-0 transition-opacity hover:bg-[var(--surface-7)]',
|
||||||
|
!isAnyDragActive && 'group-hover:opacity-100'
|
||||||
|
)}
|
||||||
>
|
>
|
||||||
<MoreHorizontal className='h-[14px] w-[14px] text-[var(--text-tertiary)]' />
|
<MoreHorizontal className='h-[14px] w-[14px] text-[var(--text-tertiary)]' />
|
||||||
</button>
|
</button>
|
||||||
@@ -374,7 +436,6 @@ export function WorkflowItem({
|
|||||||
)}
|
)}
|
||||||
</Link>
|
</Link>
|
||||||
|
|
||||||
{/* Context Menu */}
|
|
||||||
<ContextMenu
|
<ContextMenu
|
||||||
isOpen={isContextMenuOpen}
|
isOpen={isContextMenuOpen}
|
||||||
position={position}
|
position={position}
|
||||||
@@ -382,30 +443,29 @@ export function WorkflowItem({
|
|||||||
onClose={closeMenu}
|
onClose={closeMenu}
|
||||||
onOpenInNewTab={handleOpenInNewTab}
|
onOpenInNewTab={handleOpenInNewTab}
|
||||||
onRename={handleStartEdit}
|
onRename={handleStartEdit}
|
||||||
onDuplicate={handleDuplicateWorkflow}
|
onDuplicate={handleDuplicate}
|
||||||
onExport={handleExportWorkflow}
|
onExport={handleExport}
|
||||||
onDelete={handleOpenDeleteModal}
|
onDelete={handleOpenDeleteModal}
|
||||||
onColorChange={handleColorChange}
|
onColorChange={handleColorChange}
|
||||||
currentColor={workflow.color}
|
currentColor={workflow.color}
|
||||||
showOpenInNewTab={selectedWorkflows.size <= 1}
|
showOpenInNewTab={!isMixedSelection && selectedWorkflows.size <= 1}
|
||||||
showRename={selectedWorkflows.size <= 1}
|
showRename={!isMixedSelection && selectedWorkflows.size <= 1}
|
||||||
showDuplicate={true}
|
showDuplicate={true}
|
||||||
showExport={true}
|
showExport={true}
|
||||||
showColorChange={selectedWorkflows.size <= 1}
|
showColorChange={!isMixedSelection && selectedWorkflows.size <= 1}
|
||||||
disableRename={!userPermissions.canEdit}
|
disableRename={!userPermissions.canEdit}
|
||||||
disableDuplicate={!userPermissions.canEdit}
|
disableDuplicate={!userPermissions.canEdit || isDuplicatingSelection}
|
||||||
disableExport={!userPermissions.canEdit}
|
disableExport={!userPermissions.canEdit}
|
||||||
disableColorChange={!userPermissions.canEdit}
|
disableColorChange={!userPermissions.canEdit}
|
||||||
disableDelete={!userPermissions.canEdit || !canDeleteCaptured}
|
disableDelete={!userPermissions.canEdit || !canDeleteSelection}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
{/* Delete Confirmation Modal */}
|
|
||||||
<DeleteModal
|
<DeleteModal
|
||||||
isOpen={isDeleteModalOpen}
|
isOpen={isDeleteModalOpen}
|
||||||
onClose={() => setIsDeleteModalOpen(false)}
|
onClose={() => setIsDeleteModalOpen(false)}
|
||||||
onConfirm={handleDeleteWorkflow}
|
onConfirm={handleConfirmDelete}
|
||||||
isDeleting={isDeleting}
|
isDeleting={isDeleting}
|
||||||
itemType='workflow'
|
itemType={deleteItemType}
|
||||||
itemName={deleteModalNames}
|
itemName={deleteModalNames}
|
||||||
/>
|
/>
|
||||||
</>
|
</>
|
||||||
|
|||||||
@@ -7,8 +7,11 @@ import { EmptyAreaContextMenu } from '@/app/workspace/[workspaceId]/w/components
|
|||||||
import { FolderItem } from '@/app/workspace/[workspaceId]/w/components/sidebar/components/workflow-list/components/folder-item/folder-item'
|
import { FolderItem } from '@/app/workspace/[workspaceId]/w/components/sidebar/components/workflow-list/components/folder-item/folder-item'
|
||||||
import { WorkflowItem } from '@/app/workspace/[workspaceId]/w/components/sidebar/components/workflow-list/components/workflow-item/workflow-item'
|
import { WorkflowItem } from '@/app/workspace/[workspaceId]/w/components/sidebar/components/workflow-list/components/workflow-item/workflow-item'
|
||||||
import {
|
import {
|
||||||
|
SidebarDragContext,
|
||||||
useContextMenu,
|
useContextMenu,
|
||||||
useDragDrop,
|
useDragDrop,
|
||||||
|
useFolderSelection,
|
||||||
|
useSidebarDragContextValue,
|
||||||
useWorkflowSelection,
|
useWorkflowSelection,
|
||||||
} from '@/app/workspace/[workspaceId]/w/components/sidebar/hooks'
|
} from '@/app/workspace/[workspaceId]/w/components/sidebar/hooks'
|
||||||
import { useFolders } from '@/hooks/queries/folders'
|
import { useFolders } from '@/hooks/queries/folders'
|
||||||
@@ -46,17 +49,22 @@ interface WorkflowListProps {
|
|||||||
const DropIndicatorLine = memo(function DropIndicatorLine({
|
const DropIndicatorLine = memo(function DropIndicatorLine({
|
||||||
show,
|
show,
|
||||||
level = 0,
|
level = 0,
|
||||||
|
position = 'before',
|
||||||
}: {
|
}: {
|
||||||
show: boolean
|
show: boolean
|
||||||
level?: number
|
level?: number
|
||||||
|
position?: 'before' | 'after'
|
||||||
}) {
|
}) {
|
||||||
if (!show) return null
|
if (!show) return null
|
||||||
|
|
||||||
|
const positionStyle = position === 'before' ? { top: '-2px' } : { bottom: '-2px' }
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
className='pointer-events-none absolute right-0 left-0 z-20 flex items-center'
|
className='pointer-events-none absolute right-0 left-0 z-20'
|
||||||
style={{ paddingLeft: `${level * TREE_SPACING.INDENT_PER_LEVEL}px` }}
|
style={{ ...positionStyle, paddingLeft: `${level * TREE_SPACING.INDENT_PER_LEVEL}px` }}
|
||||||
>
|
>
|
||||||
<div className='h-[2px] flex-1 rounded-full bg-[#33b4ff]/70' />
|
<div className='h-[2px] rounded-full bg-[#33b4ff]/70' />
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
@@ -98,10 +106,13 @@ export function WorkflowList({
|
|||||||
createEmptyFolderDropZone,
|
createEmptyFolderDropZone,
|
||||||
createFolderContentDropZone,
|
createFolderContentDropZone,
|
||||||
createRootDropZone,
|
createRootDropZone,
|
||||||
|
createEdgeDropZone,
|
||||||
handleDragStart,
|
handleDragStart,
|
||||||
handleDragEnd,
|
handleDragEnd,
|
||||||
} = useDragDrop({ disabled: !canReorder })
|
} = useDragDrop({ disabled: !canReorder })
|
||||||
|
|
||||||
|
const dragContextValue = useSidebarDragContextValue(isDragging)
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (scrollContainerRef.current) {
|
if (scrollContainerRef.current) {
|
||||||
setScrollContainer(scrollContainerRef.current)
|
setScrollContainer(scrollContainerRef.current)
|
||||||
@@ -157,11 +168,32 @@ export function WorkflowList({
|
|||||||
return ids
|
return ids
|
||||||
}, [folderTree, workflowsByFolder])
|
}, [folderTree, workflowsByFolder])
|
||||||
|
|
||||||
|
const orderedFolderIds = useMemo(() => {
|
||||||
|
const ids: string[] = []
|
||||||
|
|
||||||
|
const collectFolderIds = (folder: FolderTreeNode) => {
|
||||||
|
ids.push(folder.id)
|
||||||
|
for (const childFolder of folder.children) {
|
||||||
|
collectFolderIds(childFolder)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const folder of folderTree) {
|
||||||
|
collectFolderIds(folder)
|
||||||
|
}
|
||||||
|
|
||||||
|
return ids
|
||||||
|
}, [folderTree])
|
||||||
|
|
||||||
const { handleWorkflowClick } = useWorkflowSelection({
|
const { handleWorkflowClick } = useWorkflowSelection({
|
||||||
workflowIds: orderedWorkflowIds,
|
workflowIds: orderedWorkflowIds,
|
||||||
activeWorkflowId: workflowId,
|
activeWorkflowId: workflowId,
|
||||||
})
|
})
|
||||||
|
|
||||||
|
const { handleFolderClick } = useFolderSelection({
|
||||||
|
folderIds: orderedFolderIds,
|
||||||
|
})
|
||||||
|
|
||||||
const isWorkflowActive = useCallback(
|
const isWorkflowActive = useCallback(
|
||||||
(wfId: string) => pathname === `/workspace/${workspaceId}/w/${wfId}`,
|
(wfId: string) => pathname === `/workspace/${workspaceId}/w/${wfId}`,
|
||||||
[pathname, workspaceId]
|
[pathname, workspaceId]
|
||||||
@@ -190,7 +222,7 @@ export function WorkflowList({
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div key={workflow.id} className='relative'>
|
<div key={workflow.id} className='relative'>
|
||||||
<DropIndicatorLine show={showBefore} level={level} />
|
<DropIndicatorLine show={showBefore} level={level} position='before' />
|
||||||
<div
|
<div
|
||||||
style={{ paddingLeft: `${level * TREE_SPACING.INDENT_PER_LEVEL}px` }}
|
style={{ paddingLeft: `${level * TREE_SPACING.INDENT_PER_LEVEL}px` }}
|
||||||
{...createWorkflowDragHandlers(workflow.id, folderId)}
|
{...createWorkflowDragHandlers(workflow.id, folderId)}
|
||||||
@@ -201,11 +233,11 @@ export function WorkflowList({
|
|||||||
level={level}
|
level={level}
|
||||||
dragDisabled={dragDisabled}
|
dragDisabled={dragDisabled}
|
||||||
onWorkflowClick={handleWorkflowClick}
|
onWorkflowClick={handleWorkflowClick}
|
||||||
onDragStart={() => handleDragStart('workflow', folderId)}
|
onDragStart={() => handleDragStart(folderId)}
|
||||||
onDragEnd={handleDragEnd}
|
onDragEnd={handleDragEnd}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<DropIndicatorLine show={showAfter} level={level} />
|
<DropIndicatorLine show={showAfter} level={level} position='after' />
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
@@ -265,12 +297,11 @@ export function WorkflowList({
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div key={folder.id} className='relative'>
|
<div key={folder.id} className='relative'>
|
||||||
<DropIndicatorLine show={showBefore} level={level} />
|
<DropIndicatorLine show={showBefore} level={level} position='before' />
|
||||||
{/* Drop target highlight overlay - covers entire folder section */}
|
|
||||||
<div
|
<div
|
||||||
className={clsx(
|
className={clsx(
|
||||||
'pointer-events-none absolute inset-0 z-10 rounded-[4px] transition-opacity duration-75',
|
'pointer-events-none absolute inset-0 z-10 rounded-[4px]',
|
||||||
showInside && isDragging ? 'bg-[#33b4ff1a] opacity-100' : 'opacity-0'
|
showInside && isDragging ? 'bg-[#33b4ff1a]' : 'hidden'
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
<div
|
<div
|
||||||
@@ -281,11 +312,12 @@ export function WorkflowList({
|
|||||||
folder={folder}
|
folder={folder}
|
||||||
level={level}
|
level={level}
|
||||||
dragDisabled={dragDisabled}
|
dragDisabled={dragDisabled}
|
||||||
onDragStart={() => handleDragStart('folder', parentFolderId)}
|
onFolderClick={handleFolderClick}
|
||||||
|
onDragStart={() => handleDragStart(parentFolderId)}
|
||||||
onDragEnd={handleDragEnd}
|
onDragEnd={handleDragEnd}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<DropIndicatorLine show={showAfter} level={level} />
|
<DropIndicatorLine show={showAfter} level={level} position='after' />
|
||||||
|
|
||||||
{isExpanded && (hasChildren || isDragging) && (
|
{isExpanded && (hasChildren || isDragging) && (
|
||||||
<div className='relative' {...createFolderContentDropZone(folder.id)}>
|
<div className='relative' {...createFolderContentDropZone(folder.id)}>
|
||||||
@@ -319,6 +351,7 @@ export function WorkflowList({
|
|||||||
createFolderContentDropZone,
|
createFolderContentDropZone,
|
||||||
handleDragStart,
|
handleDragStart,
|
||||||
handleDragEnd,
|
handleDragEnd,
|
||||||
|
handleFolderClick,
|
||||||
renderWorkflowItem,
|
renderWorkflowItem,
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
@@ -356,12 +389,19 @@ export function WorkflowList({
|
|||||||
}, [folderTree, rootWorkflows])
|
}, [folderTree, rootWorkflows])
|
||||||
|
|
||||||
const hasRootItems = rootItems.length > 0
|
const hasRootItems = rootItems.length > 0
|
||||||
|
const firstItemId = rootItems[0]?.id ?? null
|
||||||
|
const lastItemId = rootItems[rootItems.length - 1]?.id ?? null
|
||||||
const showRootInside = dropIndicator?.targetId === 'root' && dropIndicator?.position === 'inside'
|
const showRootInside = dropIndicator?.targetId === 'root' && dropIndicator?.position === 'inside'
|
||||||
|
const showTopIndicator =
|
||||||
|
firstItemId && dropIndicator?.targetId === firstItemId && dropIndicator?.position === 'before'
|
||||||
|
const showBottomIndicator =
|
||||||
|
lastItemId && dropIndicator?.targetId === lastItemId && dropIndicator?.position === 'after'
|
||||||
|
|
||||||
const handleContainerClick = useCallback(
|
const handleContainerClick = useCallback(
|
||||||
(e: React.MouseEvent<HTMLDivElement>) => {
|
(e: React.MouseEvent<HTMLDivElement>) => {
|
||||||
if (e.target !== e.currentTarget) return
|
if (e.target !== e.currentTarget) return
|
||||||
const { selectOnly, clearSelection } = useFolderStore.getState()
|
const { selectOnly, clearSelection, clearFolderSelection } = useFolderStore.getState()
|
||||||
|
clearFolderSelection()
|
||||||
workflowId ? selectOnly(workflowId) : clearSelection()
|
workflowId ? selectOnly(workflowId) : clearSelection()
|
||||||
},
|
},
|
||||||
[workflowId]
|
[workflowId]
|
||||||
@@ -382,7 +422,7 @@ export function WorkflowList({
|
|||||||
)
|
)
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<SidebarDragContext.Provider value={dragContextValue}>
|
||||||
<div
|
<div
|
||||||
className='flex min-h-full flex-col pb-[8px]'
|
className='flex min-h-full flex-col pb-[8px]'
|
||||||
onClick={handleContainerClick}
|
onClick={handleContainerClick}
|
||||||
@@ -394,13 +434,23 @@ export function WorkflowList({
|
|||||||
{...rootDropZoneHandlers}
|
{...rootDropZoneHandlers}
|
||||||
data-empty-area
|
data-empty-area
|
||||||
>
|
>
|
||||||
{/* Root drop target highlight overlay */}
|
|
||||||
<div
|
<div
|
||||||
className={clsx(
|
className={clsx(
|
||||||
'pointer-events-none absolute inset-0 z-10 rounded-[4px] transition-opacity duration-75',
|
'pointer-events-none absolute inset-0 z-10 rounded-[4px]',
|
||||||
showRootInside && isDragging ? 'bg-[#33b4ff1a] opacity-100' : 'opacity-0'
|
showRootInside && isDragging ? 'bg-[#33b4ff1a]' : 'hidden'
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
|
{isDragging && hasRootItems && (
|
||||||
|
<div
|
||||||
|
className='absolute top-0 right-0 left-0 z-30 h-[12px]'
|
||||||
|
{...createEdgeDropZone(firstItemId, 'before')}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
{showTopIndicator && (
|
||||||
|
<div className='pointer-events-none absolute top-0 right-0 left-0 z-20'>
|
||||||
|
<div className='h-[2px] rounded-full bg-[#33b4ff]/70' />
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
<div className='space-y-[2px]' data-empty-area>
|
<div className='space-y-[2px]' data-empty-area>
|
||||||
{rootItems.map((item) =>
|
{rootItems.map((item) =>
|
||||||
item.type === 'folder'
|
item.type === 'folder'
|
||||||
@@ -408,6 +458,17 @@ export function WorkflowList({
|
|||||||
: renderWorkflowItem(item.data as WorkflowMetadata, 0, null)
|
: renderWorkflowItem(item.data as WorkflowMetadata, 0, null)
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
{isDragging && hasRootItems && (
|
||||||
|
<div
|
||||||
|
className='absolute right-0 bottom-0 left-0 z-30 h-[12px]'
|
||||||
|
{...createEdgeDropZone(lastItemId, 'after')}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
{showBottomIndicator && (
|
||||||
|
<div className='pointer-events-none absolute right-0 bottom-0 left-0 z-20'>
|
||||||
|
<div className='h-[2px] rounded-full bg-[#33b4ff]/70' />
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<input
|
<input
|
||||||
@@ -432,6 +493,6 @@ export function WorkflowList({
|
|||||||
disableCreateFolder={disableCreate}
|
disableCreateFolder={disableCreate}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
</>
|
</SidebarDragContext.Provider>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -50,9 +50,8 @@ export function InviteModal({ open, onOpenChange, workspaceName }: InviteModalPr
|
|||||||
>({})
|
>({})
|
||||||
const [isSubmitting, setIsSubmitting] = useState(false)
|
const [isSubmitting, setIsSubmitting] = useState(false)
|
||||||
const [isSaving, setIsSaving] = useState(false)
|
const [isSaving, setIsSaving] = useState(false)
|
||||||
const [showSent, setShowSent] = useState(false)
|
const cooldownIntervalsRef = useRef<Map<string, NodeJS.Timeout>>(new Map())
|
||||||
const [errorMessage, setErrorMessage] = useState<string | null>(null)
|
const [errorMessage, setErrorMessage] = useState<string | null>(null)
|
||||||
const [successMessage, setSuccessMessage] = useState<string | null>(null)
|
|
||||||
const [memberToRemove, setMemberToRemove] = useState<{ userId: string; email: string } | null>(
|
const [memberToRemove, setMemberToRemove] = useState<{ userId: string; email: string } | null>(
|
||||||
null
|
null
|
||||||
)
|
)
|
||||||
@@ -121,10 +120,17 @@ export function InviteModal({ open, onOpenChange, workspaceName }: InviteModalPr
|
|||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (open) {
|
if (open) {
|
||||||
setErrorMessage(null)
|
setErrorMessage(null)
|
||||||
setSuccessMessage(null)
|
|
||||||
}
|
}
|
||||||
}, [open])
|
}, [open])
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const intervalsRef = cooldownIntervalsRef.current
|
||||||
|
return () => {
|
||||||
|
intervalsRef.forEach((interval) => clearInterval(interval))
|
||||||
|
intervalsRef.clear()
|
||||||
|
}
|
||||||
|
}, [])
|
||||||
|
|
||||||
const addEmail = useCallback(
|
const addEmail = useCallback(
|
||||||
(email: string) => {
|
(email: string) => {
|
||||||
if (!email.trim()) return false
|
if (!email.trim()) return false
|
||||||
@@ -255,11 +261,6 @@ export function InviteModal({ open, onOpenChange, workspaceName }: InviteModalPr
|
|||||||
}
|
}
|
||||||
|
|
||||||
setExistingUserPermissionChanges({})
|
setExistingUserPermissionChanges({})
|
||||||
|
|
||||||
setSuccessMessage(
|
|
||||||
`Permission changes saved for ${updates.length} user${updates.length !== 1 ? 's' : ''}!`
|
|
||||||
)
|
|
||||||
setTimeout(() => setSuccessMessage(null), 3000)
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
logger.error('Error saving permission changes:', error)
|
logger.error('Error saving permission changes:', error)
|
||||||
const errorMsg =
|
const errorMsg =
|
||||||
@@ -282,9 +283,6 @@ export function InviteModal({ open, onOpenChange, workspaceName }: InviteModalPr
|
|||||||
if (!userPerms.canAdmin || !hasPendingChanges) return
|
if (!userPerms.canAdmin || !hasPendingChanges) return
|
||||||
|
|
||||||
setExistingUserPermissionChanges({})
|
setExistingUserPermissionChanges({})
|
||||||
setSuccessMessage('Changes restored to original permissions!')
|
|
||||||
|
|
||||||
setTimeout(() => setSuccessMessage(null), 3000)
|
|
||||||
}, [userPerms.canAdmin, hasPendingChanges])
|
}, [userPerms.canAdmin, hasPendingChanges])
|
||||||
|
|
||||||
const handleRemoveMemberClick = useCallback((userId: string, email: string) => {
|
const handleRemoveMemberClick = useCallback((userId: string, email: string) => {
|
||||||
@@ -337,9 +335,6 @@ export function InviteModal({ open, onOpenChange, workspaceName }: InviteModalPr
|
|||||||
delete updated[memberToRemove.userId]
|
delete updated[memberToRemove.userId]
|
||||||
return updated
|
return updated
|
||||||
})
|
})
|
||||||
|
|
||||||
setSuccessMessage(`${memberToRemove.email} has been removed from the workspace`)
|
|
||||||
setTimeout(() => setSuccessMessage(null), 3000)
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
logger.error('Error removing member:', error)
|
logger.error('Error removing member:', error)
|
||||||
const errorMsg =
|
const errorMsg =
|
||||||
@@ -385,9 +380,6 @@ export function InviteModal({ open, onOpenChange, workspaceName }: InviteModalPr
|
|||||||
setPendingInvitations((prev) =>
|
setPendingInvitations((prev) =>
|
||||||
prev.filter((inv) => inv.invitationId !== invitationToRemove.invitationId)
|
prev.filter((inv) => inv.invitationId !== invitationToRemove.invitationId)
|
||||||
)
|
)
|
||||||
|
|
||||||
setSuccessMessage(`Invitation for ${invitationToRemove.email} has been cancelled`)
|
|
||||||
setTimeout(() => setSuccessMessage(null), 3000)
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
logger.error('Error cancelling invitation:', error)
|
logger.error('Error cancelling invitation:', error)
|
||||||
const errorMsg =
|
const errorMsg =
|
||||||
@@ -427,9 +419,6 @@ export function InviteModal({ open, onOpenChange, workspaceName }: InviteModalPr
|
|||||||
throw new Error(data.error || 'Failed to resend invitation')
|
throw new Error(data.error || 'Failed to resend invitation')
|
||||||
}
|
}
|
||||||
|
|
||||||
setSuccessMessage(`Invitation resent to ${email}`)
|
|
||||||
setTimeout(() => setSuccessMessage(null), 3000)
|
|
||||||
|
|
||||||
setResentInvitationIds((prev) => ({ ...prev, [invitationId]: true }))
|
setResentInvitationIds((prev) => ({ ...prev, [invitationId]: true }))
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
setResentInvitationIds((prev) => {
|
setResentInvitationIds((prev) => {
|
||||||
@@ -450,6 +439,12 @@ export function InviteModal({ open, onOpenChange, workspaceName }: InviteModalPr
|
|||||||
return next
|
return next
|
||||||
})
|
})
|
||||||
setResendCooldowns((prev) => ({ ...prev, [invitationId]: 60 }))
|
setResendCooldowns((prev) => ({ ...prev, [invitationId]: 60 }))
|
||||||
|
|
||||||
|
const existingInterval = cooldownIntervalsRef.current.get(invitationId)
|
||||||
|
if (existingInterval) {
|
||||||
|
clearInterval(existingInterval)
|
||||||
|
}
|
||||||
|
|
||||||
const interval = setInterval(() => {
|
const interval = setInterval(() => {
|
||||||
setResendCooldowns((prev) => {
|
setResendCooldowns((prev) => {
|
||||||
const current = prev[invitationId]
|
const current = prev[invitationId]
|
||||||
@@ -458,11 +453,14 @@ export function InviteModal({ open, onOpenChange, workspaceName }: InviteModalPr
|
|||||||
const next = { ...prev }
|
const next = { ...prev }
|
||||||
delete next[invitationId]
|
delete next[invitationId]
|
||||||
clearInterval(interval)
|
clearInterval(interval)
|
||||||
|
cooldownIntervalsRef.current.delete(invitationId)
|
||||||
return next
|
return next
|
||||||
}
|
}
|
||||||
return { ...prev, [invitationId]: current - 1 }
|
return { ...prev, [invitationId]: current - 1 }
|
||||||
})
|
})
|
||||||
}, 1000)
|
}, 1000)
|
||||||
|
|
||||||
|
cooldownIntervalsRef.current.set(invitationId, interval)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
[workspaceId, userPerms.canAdmin, resendCooldowns]
|
[workspaceId, userPerms.canAdmin, resendCooldowns]
|
||||||
@@ -473,7 +471,6 @@ export function InviteModal({ open, onOpenChange, workspaceName }: InviteModalPr
|
|||||||
e.preventDefault()
|
e.preventDefault()
|
||||||
|
|
||||||
setErrorMessage(null)
|
setErrorMessage(null)
|
||||||
setSuccessMessage(null)
|
|
||||||
|
|
||||||
if (validEmails.length === 0 || !workspaceId) {
|
if (validEmails.length === 0 || !workspaceId) {
|
||||||
return
|
return
|
||||||
@@ -562,11 +559,6 @@ export function InviteModal({ open, onOpenChange, workspaceName }: InviteModalPr
|
|||||||
setEmailItems([])
|
setEmailItems([])
|
||||||
setUserPermissions([])
|
setUserPermissions([])
|
||||||
}
|
}
|
||||||
setShowSent(true)
|
|
||||||
|
|
||||||
setTimeout(() => {
|
|
||||||
setShowSent(false)
|
|
||||||
}, 4000)
|
|
||||||
}
|
}
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
logger.error('Error inviting members:', err)
|
logger.error('Error inviting members:', err)
|
||||||
@@ -588,13 +580,16 @@ export function InviteModal({ open, onOpenChange, workspaceName }: InviteModalPr
|
|||||||
setExistingUserPermissionChanges({})
|
setExistingUserPermissionChanges({})
|
||||||
setIsSubmitting(false)
|
setIsSubmitting(false)
|
||||||
setIsSaving(false)
|
setIsSaving(false)
|
||||||
setShowSent(false)
|
|
||||||
setErrorMessage(null)
|
setErrorMessage(null)
|
||||||
setSuccessMessage(null)
|
|
||||||
setMemberToRemove(null)
|
setMemberToRemove(null)
|
||||||
setIsRemovingMember(false)
|
setIsRemovingMember(false)
|
||||||
setInvitationToRemove(null)
|
setInvitationToRemove(null)
|
||||||
setIsRemovingInvitation(false)
|
setIsRemovingInvitation(false)
|
||||||
|
setResendCooldowns({})
|
||||||
|
setResentInvitationIds({})
|
||||||
|
|
||||||
|
cooldownIntervalsRef.current.forEach((interval) => clearInterval(interval))
|
||||||
|
cooldownIntervalsRef.current.clear()
|
||||||
}, [])
|
}, [])
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@@ -703,7 +698,6 @@ export function InviteModal({ open, onOpenChange, workspaceName }: InviteModalPr
|
|||||||
variant='default'
|
variant='default'
|
||||||
disabled={isSaving || isSubmitting}
|
disabled={isSaving || isSubmitting}
|
||||||
onClick={handleRestoreChanges}
|
onClick={handleRestoreChanges}
|
||||||
className='h-[32px] gap-[8px] px-[12px] font-medium'
|
|
||||||
>
|
>
|
||||||
Restore Changes
|
Restore Changes
|
||||||
</Button>
|
</Button>
|
||||||
@@ -712,7 +706,6 @@ export function InviteModal({ open, onOpenChange, workspaceName }: InviteModalPr
|
|||||||
variant='tertiary'
|
variant='tertiary'
|
||||||
disabled={isSaving || isSubmitting}
|
disabled={isSaving || isSubmitting}
|
||||||
onClick={handleSaveChanges}
|
onClick={handleSaveChanges}
|
||||||
className='h-[32px] gap-[8px] px-[12px] font-medium'
|
|
||||||
>
|
>
|
||||||
{isSaving ? 'Saving...' : 'Save Changes'}
|
{isSaving ? 'Saving...' : 'Save Changes'}
|
||||||
</Button>
|
</Button>
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
import { useEffect, useRef, useState } from 'react'
|
import { useEffect, useRef, useState } from 'react'
|
||||||
import { createLogger } from '@sim/logger'
|
import { createLogger } from '@sim/logger'
|
||||||
import { ArrowDown, Plus } from 'lucide-react'
|
import { ArrowDown, MoreHorizontal, Plus } from 'lucide-react'
|
||||||
import {
|
import {
|
||||||
Badge,
|
Badge,
|
||||||
Button,
|
Button,
|
||||||
@@ -202,12 +202,9 @@ export function WorkspaceHeader({
|
|||||||
const activeWorkspaceFull = workspaces.find((w) => w.id === workspaceId) || null
|
const activeWorkspaceFull = workspaces.find((w) => w.id === workspaceId) || null
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handle right-click context menu
|
* Opens the context menu for a workspace at the specified position
|
||||||
*/
|
*/
|
||||||
const handleContextMenu = (e: React.MouseEvent, workspace: Workspace) => {
|
const openContextMenuAt = (workspace: Workspace, x: number, y: number) => {
|
||||||
e.preventDefault()
|
|
||||||
e.stopPropagation()
|
|
||||||
|
|
||||||
isContextMenuOpeningRef.current = true
|
isContextMenuOpeningRef.current = true
|
||||||
contextMenuClosedRef.current = false
|
contextMenuClosedRef.current = false
|
||||||
|
|
||||||
@@ -216,10 +213,19 @@ export function WorkspaceHeader({
|
|||||||
name: workspace.name,
|
name: workspace.name,
|
||||||
permissions: workspace.permissions,
|
permissions: workspace.permissions,
|
||||||
}
|
}
|
||||||
setContextMenuPosition({ x: e.clientX, y: e.clientY })
|
setContextMenuPosition({ x, y })
|
||||||
setIsContextMenuOpen(true)
|
setIsContextMenuOpen(true)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handle right-click context menu
|
||||||
|
*/
|
||||||
|
const handleContextMenu = (e: React.MouseEvent, workspace: Workspace) => {
|
||||||
|
e.preventDefault()
|
||||||
|
e.stopPropagation()
|
||||||
|
openContextMenuAt(workspace, e.clientX, e.clientY)
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Close context menu and optionally the workspace dropdown
|
* Close context menu and optionally the workspace dropdown
|
||||||
* When renaming, we keep the workspace menu open so the input is visible
|
* When renaming, we keep the workspace menu open so the input is visible
|
||||||
@@ -501,11 +507,25 @@ export function WorkspaceHeader({
|
|||||||
</div>
|
</div>
|
||||||
) : (
|
) : (
|
||||||
<PopoverItem
|
<PopoverItem
|
||||||
|
className='group'
|
||||||
active={workspace.id === workspaceId}
|
active={workspace.id === workspaceId}
|
||||||
onClick={() => onWorkspaceSwitch(workspace)}
|
onClick={() => onWorkspaceSwitch(workspace)}
|
||||||
onContextMenu={(e) => handleContextMenu(e, workspace)}
|
onContextMenu={(e) => handleContextMenu(e, workspace)}
|
||||||
>
|
>
|
||||||
<span className='min-w-0 flex-1 truncate'>{workspace.name}</span>
|
<span className='min-w-0 flex-1 truncate'>{workspace.name}</span>
|
||||||
|
<button
|
||||||
|
type='button'
|
||||||
|
aria-label='Workspace options'
|
||||||
|
onClick={(e) => {
|
||||||
|
e.preventDefault()
|
||||||
|
e.stopPropagation()
|
||||||
|
const rect = e.currentTarget.getBoundingClientRect()
|
||||||
|
openContextMenuAt(workspace, rect.right, rect.top)
|
||||||
|
}}
|
||||||
|
className='flex h-[18px] w-[18px] flex-shrink-0 items-center justify-center rounded-[4px] opacity-0 transition-opacity hover:bg-[var(--surface-7)] group-hover:opacity-100'
|
||||||
|
>
|
||||||
|
<MoreHorizontal className='h-[14px] w-[14px] text-[var(--text-tertiary)]' />
|
||||||
|
</button>
|
||||||
</PopoverItem>
|
</PopoverItem>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -3,8 +3,14 @@ export { useContextMenu } from './use-context-menu'
|
|||||||
export { type DropIndicator, useDragDrop } from './use-drag-drop'
|
export { type DropIndicator, useDragDrop } from './use-drag-drop'
|
||||||
export { useFolderExpand } from './use-folder-expand'
|
export { useFolderExpand } from './use-folder-expand'
|
||||||
export { useFolderOperations } from './use-folder-operations'
|
export { useFolderOperations } from './use-folder-operations'
|
||||||
|
export { useFolderSelection } from './use-folder-selection'
|
||||||
export { useItemDrag } from './use-item-drag'
|
export { useItemDrag } from './use-item-drag'
|
||||||
export { useItemRename } from './use-item-rename'
|
export { useItemRename } from './use-item-rename'
|
||||||
|
export {
|
||||||
|
SidebarDragContext,
|
||||||
|
useSidebarDragContext,
|
||||||
|
useSidebarDragContextValue,
|
||||||
|
} from './use-sidebar-drag-context'
|
||||||
export { useSidebarResize } from './use-sidebar-resize'
|
export { useSidebarResize } from './use-sidebar-resize'
|
||||||
export { useWorkflowOperations } from './use-workflow-operations'
|
export { useWorkflowOperations } from './use-workflow-operations'
|
||||||
export { useWorkflowSelection } from './use-workflow-selection'
|
export { useWorkflowSelection } from './use-workflow-selection'
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ const logger = createLogger('WorkflowList:DragDrop')
|
|||||||
const SCROLL_THRESHOLD = 60
|
const SCROLL_THRESHOLD = 60
|
||||||
const SCROLL_SPEED = 8
|
const SCROLL_SPEED = 8
|
||||||
const HOVER_EXPAND_DELAY = 400
|
const HOVER_EXPAND_DELAY = 400
|
||||||
|
const DRAG_OVER_THROTTLE_MS = 16
|
||||||
|
|
||||||
export interface DropIndicator {
|
export interface DropIndicator {
|
||||||
targetId: string
|
targetId: string
|
||||||
@@ -22,17 +23,25 @@ interface UseDragDropOptions {
|
|||||||
disabled?: boolean
|
disabled?: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type SiblingItem = {
|
||||||
|
type: 'folder' | 'workflow'
|
||||||
|
id: string
|
||||||
|
sortOrder: number
|
||||||
|
createdAt: Date
|
||||||
|
}
|
||||||
|
|
||||||
export function useDragDrop(options: UseDragDropOptions = {}) {
|
export function useDragDrop(options: UseDragDropOptions = {}) {
|
||||||
const { disabled = false } = options
|
const { disabled = false } = options
|
||||||
const [dropIndicator, setDropIndicator] = useState<DropIndicator | null>(null)
|
const [dropIndicator, setDropIndicator] = useState<DropIndicator | null>(null)
|
||||||
const [isDragging, setIsDragging] = useState(false)
|
const [isDragging, setIsDragging] = useState(false)
|
||||||
const [hoverFolderId, setHoverFolderId] = useState<string | null>(null)
|
const [hoverFolderId, setHoverFolderId] = useState<string | null>(null)
|
||||||
const scrollContainerRef = useRef<HTMLDivElement | null>(null)
|
const scrollContainerRef = useRef<HTMLDivElement | null>(null)
|
||||||
const scrollIntervalRef = useRef<number | null>(null)
|
const scrollAnimationRef = useRef<number | null>(null)
|
||||||
const hoverExpandTimerRef = useRef<number | null>(null)
|
const hoverExpandTimerRef = useRef<number | null>(null)
|
||||||
const lastDragYRef = useRef<number>(0)
|
const lastDragYRef = useRef<number>(0)
|
||||||
const draggedTypeRef = useRef<'workflow' | 'folder' | null>(null)
|
const lastDragOverTimeRef = useRef<number>(0)
|
||||||
const draggedSourceFolderRef = useRef<string | null>(null)
|
const draggedSourceFolderRef = useRef<string | null>(null)
|
||||||
|
const siblingsCacheRef = useRef<Map<string, SiblingItem[]>>(new Map())
|
||||||
|
|
||||||
const params = useParams()
|
const params = useParams()
|
||||||
const workspaceId = params.workspaceId as string | undefined
|
const workspaceId = params.workspaceId as string | undefined
|
||||||
@@ -41,13 +50,19 @@ export function useDragDrop(options: UseDragDropOptions = {}) {
|
|||||||
const { setExpanded, expandedFolders } = useFolderStore()
|
const { setExpanded, expandedFolders } = useFolderStore()
|
||||||
|
|
||||||
const handleAutoScroll = useCallback(() => {
|
const handleAutoScroll = useCallback(() => {
|
||||||
if (!scrollContainerRef.current || !isDragging) return
|
if (!scrollContainerRef.current) {
|
||||||
|
scrollAnimationRef.current = null
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
const container = scrollContainerRef.current
|
const container = scrollContainerRef.current
|
||||||
const rect = container.getBoundingClientRect()
|
const rect = container.getBoundingClientRect()
|
||||||
const mouseY = lastDragYRef.current
|
const mouseY = lastDragYRef.current
|
||||||
|
|
||||||
if (mouseY < rect.top || mouseY > rect.bottom) return
|
if (mouseY < rect.top || mouseY > rect.bottom) {
|
||||||
|
scrollAnimationRef.current = requestAnimationFrame(handleAutoScroll)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
const distanceFromTop = mouseY - rect.top
|
const distanceFromTop = mouseY - rect.top
|
||||||
const distanceFromBottom = rect.bottom - mouseY
|
const distanceFromBottom = rect.bottom - mouseY
|
||||||
@@ -68,21 +83,22 @@ export function useDragDrop(options: UseDragDropOptions = {}) {
|
|||||||
if (scrollDelta !== 0) {
|
if (scrollDelta !== 0) {
|
||||||
container.scrollTop += scrollDelta
|
container.scrollTop += scrollDelta
|
||||||
}
|
}
|
||||||
}, [isDragging])
|
|
||||||
|
scrollAnimationRef.current = requestAnimationFrame(handleAutoScroll)
|
||||||
|
}, [])
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (isDragging) {
|
if (isDragging) {
|
||||||
scrollIntervalRef.current = window.setInterval(handleAutoScroll, 10)
|
scrollAnimationRef.current = requestAnimationFrame(handleAutoScroll)
|
||||||
} else {
|
} else if (scrollAnimationRef.current) {
|
||||||
if (scrollIntervalRef.current) {
|
cancelAnimationFrame(scrollAnimationRef.current)
|
||||||
clearInterval(scrollIntervalRef.current)
|
scrollAnimationRef.current = null
|
||||||
scrollIntervalRef.current = null
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return () => {
|
return () => {
|
||||||
if (scrollIntervalRef.current) {
|
if (scrollAnimationRef.current) {
|
||||||
clearInterval(scrollIntervalRef.current)
|
cancelAnimationFrame(scrollAnimationRef.current)
|
||||||
|
scrollAnimationRef.current = null
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}, [isDragging, handleAutoScroll])
|
}, [isDragging, handleAutoScroll])
|
||||||
@@ -112,7 +128,6 @@ export function useDragDrop(options: UseDragDropOptions = {}) {
|
|||||||
if (!isDragging) {
|
if (!isDragging) {
|
||||||
setHoverFolderId(null)
|
setHoverFolderId(null)
|
||||||
setDropIndicator(null)
|
setDropIndicator(null)
|
||||||
draggedTypeRef.current = null
|
|
||||||
}
|
}
|
||||||
}, [isDragging])
|
}, [isDragging])
|
||||||
|
|
||||||
@@ -130,7 +145,6 @@ export function useDragDrop(options: UseDragDropOptions = {}) {
|
|||||||
const rect = element.getBoundingClientRect()
|
const rect = element.getBoundingClientRect()
|
||||||
const relativeY = e.clientY - rect.top
|
const relativeY = e.clientY - rect.top
|
||||||
const height = rect.height
|
const height = rect.height
|
||||||
// Top 25% = before, middle 50% = inside, bottom 25% = after
|
|
||||||
if (relativeY < height * 0.25) return 'before'
|
if (relativeY < height * 0.25) return 'before'
|
||||||
if (relativeY > height * 0.75) return 'after'
|
if (relativeY > height * 0.75) return 'after'
|
||||||
return 'inside'
|
return 'inside'
|
||||||
@@ -138,13 +152,6 @@ export function useDragDrop(options: UseDragDropOptions = {}) {
|
|||||||
[]
|
[]
|
||||||
)
|
)
|
||||||
|
|
||||||
type SiblingItem = {
|
|
||||||
type: 'folder' | 'workflow'
|
|
||||||
id: string
|
|
||||||
sortOrder: number
|
|
||||||
createdAt: Date
|
|
||||||
}
|
|
||||||
|
|
||||||
const compareSiblingItems = (a: SiblingItem, b: SiblingItem): number => {
|
const compareSiblingItems = (a: SiblingItem, b: SiblingItem): number => {
|
||||||
if (a.sortOrder !== b.sortOrder) return a.sortOrder - b.sortOrder
|
if (a.sortOrder !== b.sortOrder) return a.sortOrder - b.sortOrder
|
||||||
const timeA = a.createdAt.getTime()
|
const timeA = a.createdAt.getTime()
|
||||||
@@ -207,17 +214,34 @@ export function useDragDrop(options: UseDragDropOptions = {}) {
|
|||||||
return !relatedTarget || !currentTarget.contains(relatedTarget)
|
return !relatedTarget || !currentTarget.contains(relatedTarget)
|
||||||
}, [])
|
}, [])
|
||||||
|
|
||||||
const initDragOver = useCallback((e: React.DragEvent<HTMLElement>, stopPropagation = true) => {
|
const initDragOver = useCallback(
|
||||||
|
(e: React.DragEvent<HTMLElement>, stopPropagation = true): boolean => {
|
||||||
e.preventDefault()
|
e.preventDefault()
|
||||||
if (stopPropagation) e.stopPropagation()
|
if (stopPropagation) e.stopPropagation()
|
||||||
lastDragYRef.current = e.clientY
|
lastDragYRef.current = e.clientY
|
||||||
|
|
||||||
|
if (!isDragging) {
|
||||||
setIsDragging(true)
|
setIsDragging(true)
|
||||||
}, [])
|
}
|
||||||
|
|
||||||
|
const now = performance.now()
|
||||||
|
if (now - lastDragOverTimeRef.current < DRAG_OVER_THROTTLE_MS) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
lastDragOverTimeRef.current = now
|
||||||
|
return true
|
||||||
|
},
|
||||||
|
[isDragging]
|
||||||
|
)
|
||||||
|
|
||||||
const getSiblingItems = useCallback((folderId: string | null): SiblingItem[] => {
|
const getSiblingItems = useCallback((folderId: string | null): SiblingItem[] => {
|
||||||
|
const cacheKey = folderId ?? 'root'
|
||||||
|
const cached = siblingsCacheRef.current.get(cacheKey)
|
||||||
|
if (cached) return cached
|
||||||
|
|
||||||
const currentFolders = useFolderStore.getState().folders
|
const currentFolders = useFolderStore.getState().folders
|
||||||
const currentWorkflows = useWorkflowRegistry.getState().workflows
|
const currentWorkflows = useWorkflowRegistry.getState().workflows
|
||||||
return [
|
const siblings = [
|
||||||
...Object.values(currentFolders)
|
...Object.values(currentFolders)
|
||||||
.filter((f) => f.parentId === folderId)
|
.filter((f) => f.parentId === folderId)
|
||||||
.map((f) => ({
|
.map((f) => ({
|
||||||
@@ -235,6 +259,9 @@ export function useDragDrop(options: UseDragDropOptions = {}) {
|
|||||||
createdAt: w.createdAt,
|
createdAt: w.createdAt,
|
||||||
})),
|
})),
|
||||||
].sort(compareSiblingItems)
|
].sort(compareSiblingItems)
|
||||||
|
|
||||||
|
siblingsCacheRef.current.set(cacheKey, siblings)
|
||||||
|
return siblings
|
||||||
}, [])
|
}, [])
|
||||||
|
|
||||||
const setNormalizedDropIndicator = useCallback(
|
const setNormalizedDropIndicator = useCallback(
|
||||||
@@ -269,155 +296,114 @@ export function useDragDrop(options: UseDragDropOptions = {}) {
|
|||||||
[getSiblingItems]
|
[getSiblingItems]
|
||||||
)
|
)
|
||||||
|
|
||||||
const isNoOpMove = useCallback(
|
const canMoveFolderTo = useCallback(
|
||||||
(
|
(folderId: string, destinationFolderId: string | null): boolean => {
|
||||||
indicator: DropIndicator,
|
if (folderId === destinationFolderId) return false
|
||||||
draggedIds: string[],
|
if (!destinationFolderId) return true
|
||||||
draggedType: 'folder' | 'workflow',
|
const targetPath = useFolderStore.getState().getFolderPath(destinationFolderId)
|
||||||
destinationFolderId: string | null,
|
return !targetPath.some((f) => f.id === folderId)
|
||||||
currentFolderId: string | null | undefined
|
|
||||||
): boolean => {
|
|
||||||
if (indicator.position !== 'inside' && draggedIds.includes(indicator.targetId)) {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
if (currentFolderId !== destinationFolderId) {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
const siblingItems = getSiblingItems(destinationFolderId)
|
|
||||||
const remaining = siblingItems.filter(
|
|
||||||
(item) => !(item.type === draggedType && draggedIds.includes(item.id))
|
|
||||||
)
|
|
||||||
const insertAt = calculateInsertIndex(remaining, indicator)
|
|
||||||
const originalIdx = siblingItems.findIndex(
|
|
||||||
(item) => item.type === draggedType && item.id === draggedIds[0]
|
|
||||||
)
|
|
||||||
return insertAt === originalIdx
|
|
||||||
},
|
},
|
||||||
[getSiblingItems, calculateInsertIndex]
|
[]
|
||||||
)
|
)
|
||||||
|
|
||||||
const handleWorkflowDrop = useCallback(
|
const collectMovingItems = useCallback(
|
||||||
async (workflowIds: string[], indicator: DropIndicator) => {
|
(
|
||||||
if (!workflowIds.length || !workspaceId) return
|
workflowIds: string[],
|
||||||
|
folderIds: string[],
|
||||||
|
destinationFolderId: string | null
|
||||||
|
): { fromDestination: SiblingItem[]; fromOther: SiblingItem[] } => {
|
||||||
|
const { folders } = useFolderStore.getState()
|
||||||
|
const { workflows } = useWorkflowRegistry.getState()
|
||||||
|
|
||||||
|
const fromDestination: SiblingItem[] = []
|
||||||
|
const fromOther: SiblingItem[] = []
|
||||||
|
|
||||||
|
for (const id of workflowIds) {
|
||||||
|
const workflow = workflows[id]
|
||||||
|
if (!workflow) continue
|
||||||
|
const item: SiblingItem = {
|
||||||
|
type: 'workflow',
|
||||||
|
id,
|
||||||
|
sortOrder: workflow.sortOrder,
|
||||||
|
createdAt: workflow.createdAt,
|
||||||
|
}
|
||||||
|
if (workflow.folderId === destinationFolderId) {
|
||||||
|
fromDestination.push(item)
|
||||||
|
} else {
|
||||||
|
fromOther.push(item)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const id of folderIds) {
|
||||||
|
const folder = folders[id]
|
||||||
|
if (!folder) continue
|
||||||
|
const item: SiblingItem = {
|
||||||
|
type: 'folder',
|
||||||
|
id,
|
||||||
|
sortOrder: folder.sortOrder,
|
||||||
|
createdAt: folder.createdAt,
|
||||||
|
}
|
||||||
|
if (folder.parentId === destinationFolderId) {
|
||||||
|
fromDestination.push(item)
|
||||||
|
} else {
|
||||||
|
fromOther.push(item)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fromDestination.sort(compareSiblingItems)
|
||||||
|
fromOther.sort(compareSiblingItems)
|
||||||
|
|
||||||
|
return { fromDestination, fromOther }
|
||||||
|
},
|
||||||
|
[]
|
||||||
|
)
|
||||||
|
|
||||||
|
const handleSelectionDrop = useCallback(
|
||||||
|
async (selection: { workflowIds: string[]; folderIds: string[] }, indicator: DropIndicator) => {
|
||||||
|
if (!workspaceId) return
|
||||||
|
|
||||||
|
const { workflowIds, folderIds } = selection
|
||||||
|
if (workflowIds.length === 0 && folderIds.length === 0) return
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const destinationFolderId = getDestinationFolderId(indicator)
|
const destinationFolderId = getDestinationFolderId(indicator)
|
||||||
const currentWorkflows = useWorkflowRegistry.getState().workflows
|
const validFolderIds = folderIds.filter((id) => canMoveFolderTo(id, destinationFolderId))
|
||||||
const firstWorkflow = currentWorkflows[workflowIds[0]]
|
if (workflowIds.length === 0 && validFolderIds.length === 0) return
|
||||||
|
|
||||||
if (
|
|
||||||
isNoOpMove(
|
|
||||||
indicator,
|
|
||||||
workflowIds,
|
|
||||||
'workflow',
|
|
||||||
destinationFolderId,
|
|
||||||
firstWorkflow?.folderId
|
|
||||||
)
|
|
||||||
) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
const siblingItems = getSiblingItems(destinationFolderId)
|
const siblingItems = getSiblingItems(destinationFolderId)
|
||||||
const movingSet = new Set(workflowIds)
|
const movingIds = new Set([...workflowIds, ...validFolderIds])
|
||||||
const remaining = siblingItems.filter(
|
const remaining = siblingItems.filter((item) => !movingIds.has(item.id))
|
||||||
(item) => !(item.type === 'workflow' && movingSet.has(item.id))
|
|
||||||
|
const { fromDestination, fromOther } = collectMovingItems(
|
||||||
|
workflowIds,
|
||||||
|
validFolderIds,
|
||||||
|
destinationFolderId
|
||||||
)
|
)
|
||||||
const moving = workflowIds
|
|
||||||
.map((id) => ({
|
|
||||||
type: 'workflow' as const,
|
|
||||||
id,
|
|
||||||
sortOrder: currentWorkflows[id]?.sortOrder ?? 0,
|
|
||||||
createdAt: currentWorkflows[id]?.createdAt ?? new Date(),
|
|
||||||
}))
|
|
||||||
.sort(compareSiblingItems)
|
|
||||||
|
|
||||||
const insertAt = calculateInsertIndex(remaining, indicator)
|
const insertAt = calculateInsertIndex(remaining, indicator)
|
||||||
|
const newOrder = [
|
||||||
const newOrder: SiblingItem[] = [
|
|
||||||
...remaining.slice(0, insertAt),
|
...remaining.slice(0, insertAt),
|
||||||
...moving,
|
...fromDestination,
|
||||||
|
...fromOther,
|
||||||
...remaining.slice(insertAt),
|
...remaining.slice(insertAt),
|
||||||
]
|
]
|
||||||
|
|
||||||
await buildAndSubmitUpdates(newOrder, destinationFolderId)
|
await buildAndSubmitUpdates(newOrder, destinationFolderId)
|
||||||
|
|
||||||
|
const { clearSelection, clearFolderSelection } = useFolderStore.getState()
|
||||||
|
clearSelection()
|
||||||
|
clearFolderSelection()
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
logger.error('Failed to reorder workflows:', error)
|
logger.error('Failed to drop selection:', error)
|
||||||
}
|
|
||||||
},
|
|
||||||
[
|
|
||||||
getDestinationFolderId,
|
|
||||||
getSiblingItems,
|
|
||||||
calculateInsertIndex,
|
|
||||||
isNoOpMove,
|
|
||||||
buildAndSubmitUpdates,
|
|
||||||
]
|
|
||||||
)
|
|
||||||
|
|
||||||
const handleFolderDrop = useCallback(
|
|
||||||
async (draggedFolderId: string, indicator: DropIndicator) => {
|
|
||||||
if (!draggedFolderId || !workspaceId) return
|
|
||||||
|
|
||||||
try {
|
|
||||||
const folderStore = useFolderStore.getState()
|
|
||||||
const currentFolders = folderStore.folders
|
|
||||||
|
|
||||||
const targetParentId = getDestinationFolderId(indicator)
|
|
||||||
|
|
||||||
if (draggedFolderId === targetParentId) {
|
|
||||||
logger.info('Cannot move folder into itself')
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if (targetParentId) {
|
|
||||||
const targetPath = folderStore.getFolderPath(targetParentId)
|
|
||||||
if (targetPath.some((f) => f.id === draggedFolderId)) {
|
|
||||||
logger.info('Cannot move folder into its own descendant')
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const draggedFolder = currentFolders[draggedFolderId]
|
|
||||||
if (
|
|
||||||
isNoOpMove(
|
|
||||||
indicator,
|
|
||||||
[draggedFolderId],
|
|
||||||
'folder',
|
|
||||||
targetParentId,
|
|
||||||
draggedFolder?.parentId
|
|
||||||
)
|
|
||||||
) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
const siblingItems = getSiblingItems(targetParentId)
|
|
||||||
const remaining = siblingItems.filter(
|
|
||||||
(item) => !(item.type === 'folder' && item.id === draggedFolderId)
|
|
||||||
)
|
|
||||||
|
|
||||||
const insertAt = calculateInsertIndex(remaining, indicator)
|
|
||||||
|
|
||||||
const newOrder: SiblingItem[] = [
|
|
||||||
...remaining.slice(0, insertAt),
|
|
||||||
{
|
|
||||||
type: 'folder',
|
|
||||||
id: draggedFolderId,
|
|
||||||
sortOrder: 0,
|
|
||||||
createdAt: draggedFolder?.createdAt ?? new Date(),
|
|
||||||
},
|
|
||||||
...remaining.slice(insertAt),
|
|
||||||
]
|
|
||||||
|
|
||||||
await buildAndSubmitUpdates(newOrder, targetParentId)
|
|
||||||
} catch (error) {
|
|
||||||
logger.error('Failed to reorder folder:', error)
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
[
|
[
|
||||||
workspaceId,
|
workspaceId,
|
||||||
getDestinationFolderId,
|
getDestinationFolderId,
|
||||||
|
canMoveFolderTo,
|
||||||
getSiblingItems,
|
getSiblingItems,
|
||||||
|
collectMovingItems,
|
||||||
calculateInsertIndex,
|
calculateInsertIndex,
|
||||||
isNoOpMove,
|
|
||||||
buildAndSubmitUpdates,
|
buildAndSubmitUpdates,
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
@@ -430,32 +416,30 @@ export function useDragDrop(options: UseDragDropOptions = {}) {
|
|||||||
const indicator = dropIndicator
|
const indicator = dropIndicator
|
||||||
setDropIndicator(null)
|
setDropIndicator(null)
|
||||||
setIsDragging(false)
|
setIsDragging(false)
|
||||||
|
siblingsCacheRef.current.clear()
|
||||||
|
|
||||||
if (!indicator) return
|
if (!indicator) return
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const workflowIdsData = e.dataTransfer.getData('workflow-ids')
|
const selectionData = e.dataTransfer.getData('sidebar-selection')
|
||||||
if (workflowIdsData) {
|
if (!selectionData) return
|
||||||
const workflowIds = JSON.parse(workflowIdsData) as string[]
|
|
||||||
await handleWorkflowDrop(workflowIds, indicator)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
const folderIdData = e.dataTransfer.getData('folder-id')
|
const selection = JSON.parse(selectionData) as {
|
||||||
if (folderIdData) {
|
workflowIds: string[]
|
||||||
await handleFolderDrop(folderIdData, indicator)
|
folderIds: string[]
|
||||||
}
|
}
|
||||||
|
await handleSelectionDrop(selection, indicator)
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
logger.error('Failed to handle drop:', error)
|
logger.error('Failed to handle drop:', error)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
[dropIndicator, handleWorkflowDrop, handleFolderDrop]
|
[dropIndicator, handleSelectionDrop]
|
||||||
)
|
)
|
||||||
|
|
||||||
const createWorkflowDragHandlers = useCallback(
|
const createWorkflowDragHandlers = useCallback(
|
||||||
(workflowId: string, folderId: string | null) => ({
|
(workflowId: string, folderId: string | null) => ({
|
||||||
onDragOver: (e: React.DragEvent<HTMLElement>) => {
|
onDragOver: (e: React.DragEvent<HTMLElement>) => {
|
||||||
initDragOver(e)
|
if (!initDragOver(e)) return
|
||||||
const isSameFolder = draggedSourceFolderRef.current === folderId
|
const isSameFolder = draggedSourceFolderRef.current === folderId
|
||||||
if (isSameFolder) {
|
if (isSameFolder) {
|
||||||
const position = calculateDropPosition(e, e.currentTarget)
|
const position = calculateDropPosition(e, e.currentTarget)
|
||||||
@@ -468,33 +452,20 @@ export function useDragDrop(options: UseDragDropOptions = {}) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
onDragLeave: (e: React.DragEvent<HTMLElement>) => {
|
||||||
|
if (isLeavingElement(e)) setNormalizedDropIndicator(null)
|
||||||
|
},
|
||||||
onDrop: handleDrop,
|
onDrop: handleDrop,
|
||||||
}),
|
}),
|
||||||
[initDragOver, calculateDropPosition, setNormalizedDropIndicator, handleDrop]
|
[initDragOver, calculateDropPosition, setNormalizedDropIndicator, isLeavingElement, handleDrop]
|
||||||
)
|
)
|
||||||
|
|
||||||
const createFolderDragHandlers = useCallback(
|
const createFolderDragHandlers = useCallback(
|
||||||
(folderId: string, parentFolderId: string | null) => ({
|
(folderId: string, parentFolderId: string | null) => ({
|
||||||
onDragOver: (e: React.DragEvent<HTMLElement>) => {
|
onDragOver: (e: React.DragEvent<HTMLElement>) => {
|
||||||
initDragOver(e)
|
if (!initDragOver(e)) return
|
||||||
if (draggedTypeRef.current === 'folder') {
|
|
||||||
const isSameParent = draggedSourceFolderRef.current === parentFolderId
|
const isSameParent = draggedSourceFolderRef.current === parentFolderId
|
||||||
if (isSameParent) {
|
if (isSameParent) {
|
||||||
const position = calculateDropPosition(e, e.currentTarget)
|
|
||||||
setNormalizedDropIndicator({ targetId: folderId, position, folderId: parentFolderId })
|
|
||||||
} else {
|
|
||||||
setNormalizedDropIndicator({
|
|
||||||
targetId: folderId,
|
|
||||||
position: 'inside',
|
|
||||||
folderId: parentFolderId,
|
|
||||||
})
|
|
||||||
setHoverFolderId(folderId)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// Workflow being dragged over a folder
|
|
||||||
const isSameParent = draggedSourceFolderRef.current === parentFolderId
|
|
||||||
if (isSameParent) {
|
|
||||||
// Same level - use three zones: top=before, middle=inside, bottom=after
|
|
||||||
const position = calculateFolderDropPosition(e, e.currentTarget)
|
const position = calculateFolderDropPosition(e, e.currentTarget)
|
||||||
setNormalizedDropIndicator({ targetId: folderId, position, folderId: parentFolderId })
|
setNormalizedDropIndicator({ targetId: folderId, position, folderId: parentFolderId })
|
||||||
if (position === 'inside') {
|
if (position === 'inside') {
|
||||||
@@ -503,7 +474,6 @@ export function useDragDrop(options: UseDragDropOptions = {}) {
|
|||||||
setHoverFolderId(null)
|
setHoverFolderId(null)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// Different container - drop into folder
|
|
||||||
setNormalizedDropIndicator({
|
setNormalizedDropIndicator({
|
||||||
targetId: folderId,
|
targetId: folderId,
|
||||||
position: 'inside',
|
position: 'inside',
|
||||||
@@ -511,7 +481,6 @@ export function useDragDrop(options: UseDragDropOptions = {}) {
|
|||||||
})
|
})
|
||||||
setHoverFolderId(folderId)
|
setHoverFolderId(folderId)
|
||||||
}
|
}
|
||||||
}
|
|
||||||
},
|
},
|
||||||
onDragLeave: (e: React.DragEvent<HTMLElement>) => {
|
onDragLeave: (e: React.DragEvent<HTMLElement>) => {
|
||||||
if (isLeavingElement(e)) setHoverFolderId(null)
|
if (isLeavingElement(e)) setHoverFolderId(null)
|
||||||
@@ -520,7 +489,6 @@ export function useDragDrop(options: UseDragDropOptions = {}) {
|
|||||||
}),
|
}),
|
||||||
[
|
[
|
||||||
initDragOver,
|
initDragOver,
|
||||||
calculateDropPosition,
|
|
||||||
calculateFolderDropPosition,
|
calculateFolderDropPosition,
|
||||||
setNormalizedDropIndicator,
|
setNormalizedDropIndicator,
|
||||||
isLeavingElement,
|
isLeavingElement,
|
||||||
@@ -531,34 +499,37 @@ export function useDragDrop(options: UseDragDropOptions = {}) {
|
|||||||
const createEmptyFolderDropZone = useCallback(
|
const createEmptyFolderDropZone = useCallback(
|
||||||
(folderId: string) => ({
|
(folderId: string) => ({
|
||||||
onDragOver: (e: React.DragEvent<HTMLElement>) => {
|
onDragOver: (e: React.DragEvent<HTMLElement>) => {
|
||||||
initDragOver(e)
|
if (!initDragOver(e)) return
|
||||||
setNormalizedDropIndicator({ targetId: folderId, position: 'inside', folderId })
|
setNormalizedDropIndicator({ targetId: folderId, position: 'inside', folderId })
|
||||||
},
|
},
|
||||||
|
onDragLeave: (e: React.DragEvent<HTMLElement>) => {
|
||||||
|
if (isLeavingElement(e)) setNormalizedDropIndicator(null)
|
||||||
|
},
|
||||||
onDrop: handleDrop,
|
onDrop: handleDrop,
|
||||||
}),
|
}),
|
||||||
[initDragOver, setNormalizedDropIndicator, handleDrop]
|
[initDragOver, setNormalizedDropIndicator, isLeavingElement, handleDrop]
|
||||||
)
|
)
|
||||||
|
|
||||||
const createFolderContentDropZone = useCallback(
|
const createFolderContentDropZone = useCallback(
|
||||||
(folderId: string) => ({
|
(folderId: string) => ({
|
||||||
onDragOver: (e: React.DragEvent<HTMLElement>) => {
|
onDragOver: (e: React.DragEvent<HTMLElement>) => {
|
||||||
e.preventDefault()
|
if (!initDragOver(e)) return
|
||||||
e.stopPropagation()
|
|
||||||
lastDragYRef.current = e.clientY
|
|
||||||
setIsDragging(true)
|
|
||||||
if (e.target === e.currentTarget && draggedSourceFolderRef.current !== folderId) {
|
if (e.target === e.currentTarget && draggedSourceFolderRef.current !== folderId) {
|
||||||
setNormalizedDropIndicator({ targetId: folderId, position: 'inside', folderId: null })
|
setNormalizedDropIndicator({ targetId: folderId, position: 'inside', folderId: null })
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
onDragLeave: (e: React.DragEvent<HTMLElement>) => {
|
||||||
|
if (isLeavingElement(e)) setNormalizedDropIndicator(null)
|
||||||
|
},
|
||||||
onDrop: handleDrop,
|
onDrop: handleDrop,
|
||||||
}),
|
}),
|
||||||
[setNormalizedDropIndicator, handleDrop]
|
[initDragOver, setNormalizedDropIndicator, isLeavingElement, handleDrop]
|
||||||
)
|
)
|
||||||
|
|
||||||
const createRootDropZone = useCallback(
|
const createRootDropZone = useCallback(
|
||||||
() => ({
|
() => ({
|
||||||
onDragOver: (e: React.DragEvent<HTMLElement>) => {
|
onDragOver: (e: React.DragEvent<HTMLElement>) => {
|
||||||
initDragOver(e, false)
|
if (!initDragOver(e, false)) return
|
||||||
if (e.target === e.currentTarget) {
|
if (e.target === e.currentTarget) {
|
||||||
setNormalizedDropIndicator({ targetId: 'root', position: 'inside', folderId: null })
|
setNormalizedDropIndicator({ targetId: 'root', position: 'inside', folderId: null })
|
||||||
}
|
}
|
||||||
@@ -571,21 +542,35 @@ export function useDragDrop(options: UseDragDropOptions = {}) {
|
|||||||
[initDragOver, setNormalizedDropIndicator, isLeavingElement, handleDrop]
|
[initDragOver, setNormalizedDropIndicator, isLeavingElement, handleDrop]
|
||||||
)
|
)
|
||||||
|
|
||||||
const handleDragStart = useCallback(
|
const createEdgeDropZone = useCallback(
|
||||||
(type: 'workflow' | 'folder', sourceFolderId: string | null) => {
|
(itemId: string | null, position: 'before' | 'after') => ({
|
||||||
draggedTypeRef.current = type
|
onDragOver: (e: React.DragEvent<HTMLElement>) => {
|
||||||
|
if (!initDragOver(e)) return
|
||||||
|
if (itemId) {
|
||||||
|
setDropIndicator({ targetId: itemId, position, folderId: null })
|
||||||
|
} else {
|
||||||
|
setNormalizedDropIndicator({ targetId: 'root', position: 'inside', folderId: null })
|
||||||
|
}
|
||||||
|
},
|
||||||
|
onDragLeave: (e: React.DragEvent<HTMLElement>) => {
|
||||||
|
if (isLeavingElement(e)) setDropIndicator(null)
|
||||||
|
},
|
||||||
|
onDrop: handleDrop,
|
||||||
|
}),
|
||||||
|
[initDragOver, setNormalizedDropIndicator, isLeavingElement, handleDrop]
|
||||||
|
)
|
||||||
|
|
||||||
|
const handleDragStart = useCallback((sourceFolderId: string | null) => {
|
||||||
draggedSourceFolderRef.current = sourceFolderId
|
draggedSourceFolderRef.current = sourceFolderId
|
||||||
setIsDragging(true)
|
setIsDragging(true)
|
||||||
},
|
}, [])
|
||||||
[]
|
|
||||||
)
|
|
||||||
|
|
||||||
const handleDragEnd = useCallback(() => {
|
const handleDragEnd = useCallback(() => {
|
||||||
setIsDragging(false)
|
setIsDragging(false)
|
||||||
setDropIndicator(null)
|
setDropIndicator(null)
|
||||||
draggedTypeRef.current = null
|
|
||||||
draggedSourceFolderRef.current = null
|
draggedSourceFolderRef.current = null
|
||||||
setHoverFolderId(null)
|
setHoverFolderId(null)
|
||||||
|
siblingsCacheRef.current.clear()
|
||||||
}, [])
|
}, [])
|
||||||
|
|
||||||
const setScrollContainer = useCallback((element: HTMLDivElement | null) => {
|
const setScrollContainer = useCallback((element: HTMLDivElement | null) => {
|
||||||
@@ -595,6 +580,7 @@ export function useDragDrop(options: UseDragDropOptions = {}) {
|
|||||||
const noopDragHandlers = {
|
const noopDragHandlers = {
|
||||||
onDragOver: (e: React.DragEvent<HTMLElement>) => e.preventDefault(),
|
onDragOver: (e: React.DragEvent<HTMLElement>) => e.preventDefault(),
|
||||||
onDrop: (e: React.DragEvent<HTMLElement>) => e.preventDefault(),
|
onDrop: (e: React.DragEvent<HTMLElement>) => e.preventDefault(),
|
||||||
|
onDragLeave: () => {},
|
||||||
}
|
}
|
||||||
|
|
||||||
if (disabled) {
|
if (disabled) {
|
||||||
@@ -604,10 +590,11 @@ export function useDragDrop(options: UseDragDropOptions = {}) {
|
|||||||
disabled: true,
|
disabled: true,
|
||||||
setScrollContainer,
|
setScrollContainer,
|
||||||
createWorkflowDragHandlers: () => noopDragHandlers,
|
createWorkflowDragHandlers: () => noopDragHandlers,
|
||||||
createFolderDragHandlers: () => ({ ...noopDragHandlers, onDragLeave: () => {} }),
|
createFolderDragHandlers: () => noopDragHandlers,
|
||||||
createEmptyFolderDropZone: () => noopDragHandlers,
|
createEmptyFolderDropZone: () => noopDragHandlers,
|
||||||
createFolderContentDropZone: () => noopDragHandlers,
|
createFolderContentDropZone: () => noopDragHandlers,
|
||||||
createRootDropZone: () => ({ ...noopDragHandlers, onDragLeave: () => {} }),
|
createRootDropZone: () => noopDragHandlers,
|
||||||
|
createEdgeDropZone: () => noopDragHandlers,
|
||||||
handleDragStart: () => {},
|
handleDragStart: () => {},
|
||||||
handleDragEnd: () => {},
|
handleDragEnd: () => {},
|
||||||
}
|
}
|
||||||
@@ -623,6 +610,7 @@ export function useDragDrop(options: UseDragDropOptions = {}) {
|
|||||||
createEmptyFolderDropZone,
|
createEmptyFolderDropZone,
|
||||||
createFolderContentDropZone,
|
createFolderContentDropZone,
|
||||||
createRootDropZone,
|
createRootDropZone,
|
||||||
|
createEdgeDropZone,
|
||||||
handleDragStart,
|
handleDragStart,
|
||||||
handleDragEnd,
|
handleDragEnd,
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,61 @@
|
|||||||
|
import { useCallback } from 'react'
|
||||||
|
import { useFolderStore } from '@/stores/folders/store'
|
||||||
|
|
||||||
|
interface UseFolderSelectionProps {
|
||||||
|
/**
|
||||||
|
* Flat array of all folder IDs in display order
|
||||||
|
*/
|
||||||
|
folderIds: string[]
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Hook for managing folder selection with support for single, range, and toggle selection.
|
||||||
|
* Handles shift-click for range selection and cmd/ctrl-click for toggle selection.
|
||||||
|
* Uses the last selected folder ID (tracked in store) as the anchor point for range selections.
|
||||||
|
*
|
||||||
|
* @param props - Hook props
|
||||||
|
* @returns Selection handlers
|
||||||
|
*/
|
||||||
|
export function useFolderSelection({ folderIds }: UseFolderSelectionProps) {
|
||||||
|
const {
|
||||||
|
selectedFolders,
|
||||||
|
lastSelectedFolderId,
|
||||||
|
selectFolderOnly,
|
||||||
|
selectFolderRange,
|
||||||
|
toggleFolderSelection,
|
||||||
|
} = useFolderStore()
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handle folder click with support for shift-click range selection and cmd/ctrl-click toggle
|
||||||
|
*
|
||||||
|
* @param folderId - ID of clicked folder
|
||||||
|
* @param shiftKey - Whether shift key was pressed
|
||||||
|
* @param metaKey - Whether cmd (Mac) or ctrl (Windows) key was pressed
|
||||||
|
*/
|
||||||
|
const handleFolderClick = useCallback(
|
||||||
|
(folderId: string, shiftKey: boolean, metaKey: boolean) => {
|
||||||
|
// Cmd/Ctrl+Click: Toggle individual selection
|
||||||
|
if (metaKey) {
|
||||||
|
toggleFolderSelection(folderId)
|
||||||
|
}
|
||||||
|
// Shift+Click: Range selection from last selected folder to clicked folder
|
||||||
|
else if (shiftKey && lastSelectedFolderId && lastSelectedFolderId !== folderId) {
|
||||||
|
selectFolderRange(folderIds, lastSelectedFolderId, folderId)
|
||||||
|
}
|
||||||
|
// Shift+Click without anchor: Select only this folder (establishes anchor)
|
||||||
|
else if (shiftKey) {
|
||||||
|
selectFolderOnly(folderId)
|
||||||
|
}
|
||||||
|
// Regular click: Select only this folder
|
||||||
|
else {
|
||||||
|
selectFolderOnly(folderId)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
[folderIds, lastSelectedFolderId, selectFolderOnly, selectFolderRange, toggleFolderSelection]
|
||||||
|
)
|
||||||
|
|
||||||
|
return {
|
||||||
|
selectedFolders,
|
||||||
|
handleFolderClick,
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -4,9 +4,23 @@ interface UseItemDragProps {
|
|||||||
onDragStart: (e: React.DragEvent) => void
|
onDragStart: (e: React.DragEvent) => void
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Lazily initialized invisible drag image (1x1 transparent pixel)
|
||||||
|
// Created on first use to avoid SSR issues with browser-only Image constructor
|
||||||
|
let invisibleDragImage: HTMLImageElement | null = null
|
||||||
|
|
||||||
|
function getInvisibleDragImage(): HTMLImageElement {
|
||||||
|
if (!invisibleDragImage) {
|
||||||
|
invisibleDragImage = new Image()
|
||||||
|
invisibleDragImage.src =
|
||||||
|
'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNkYAAAAAYAAjCB0C8AAAAASUVORK5CYII='
|
||||||
|
}
|
||||||
|
return invisibleDragImage
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Custom hook to handle drag operations for workflow and folder items.
|
* Custom hook to handle drag operations for workflow and folder items.
|
||||||
* Manages drag state and provides unified drag event handlers.
|
* Manages drag state and provides unified drag event handlers.
|
||||||
|
* Uses an invisible drag image for cleaner UX (only drop indicator shows).
|
||||||
*
|
*
|
||||||
* @param props - Configuration object containing drag start callback
|
* @param props - Configuration object containing drag start callback
|
||||||
* @returns Drag state and event handlers
|
* @returns Drag state and event handlers
|
||||||
@@ -16,12 +30,20 @@ export function useItemDrag({ onDragStart }: UseItemDragProps) {
|
|||||||
const shouldPreventClickRef = useRef(false)
|
const shouldPreventClickRef = useRef(false)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handle drag start - sets dragging state and prevents click
|
* Handle drag start - sets dragging state, hides default drag ghost, and prevents click
|
||||||
*/
|
*/
|
||||||
const handleDragStart = useCallback(
|
const handleDragStart = useCallback(
|
||||||
(e: React.DragEvent) => {
|
(e: React.DragEvent) => {
|
||||||
shouldPreventClickRef.current = true
|
shouldPreventClickRef.current = true
|
||||||
setIsDragging(true)
|
setIsDragging(true)
|
||||||
|
|
||||||
|
// Hide the default browser drag ghost image
|
||||||
|
// Defensive check ensures image is loaded (data URIs are typically synchronous)
|
||||||
|
const dragImage = getInvisibleDragImage()
|
||||||
|
if (dragImage.complete) {
|
||||||
|
e.dataTransfer.setDragImage(dragImage, 0, 0)
|
||||||
|
}
|
||||||
|
|
||||||
onDragStart(e)
|
onDragStart(e)
|
||||||
},
|
},
|
||||||
[onDragStart]
|
[onDragStart]
|
||||||
|
|||||||
@@ -0,0 +1,36 @@
|
|||||||
|
'use client'
|
||||||
|
|
||||||
|
import { createContext, useContext, useMemo } from 'react'
|
||||||
|
|
||||||
|
interface SidebarDragContextValue {
|
||||||
|
/** Whether any drag operation is currently in progress */
|
||||||
|
isAnyDragActive: boolean
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Context for sharing drag state across sidebar components.
|
||||||
|
* Eliminates prop drilling of isAnyDragActive through component tree.
|
||||||
|
*/
|
||||||
|
export const SidebarDragContext = createContext<SidebarDragContextValue>({
|
||||||
|
isAnyDragActive: false,
|
||||||
|
})
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Hook to access the sidebar drag state.
|
||||||
|
* Use this in WorkflowItem, FolderItem, etc. to check if any drag is in progress.
|
||||||
|
*
|
||||||
|
* @returns The current drag state
|
||||||
|
*/
|
||||||
|
export function useSidebarDragContext(): SidebarDragContextValue {
|
||||||
|
return useContext(SidebarDragContext)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Hook to create the sidebar drag context value.
|
||||||
|
*
|
||||||
|
* @param isDragging - Whether a drag is currently in progress
|
||||||
|
* @returns Context value to provide to SidebarDragContext.Provider
|
||||||
|
*/
|
||||||
|
export function useSidebarDragContextValue(isDragging: boolean): SidebarDragContextValue {
|
||||||
|
return useMemo(() => ({ isAnyDragActive: isDragging }), [isDragging])
|
||||||
|
}
|
||||||
@@ -24,7 +24,8 @@ export function useWorkflowSelection({ workflowIds, activeWorkflowId }: UseWorkf
|
|||||||
const { selectedWorkflows, selectOnly, selectRange, toggleWorkflowSelection } = useFolderStore()
|
const { selectedWorkflows, selectOnly, selectRange, toggleWorkflowSelection } = useFolderStore()
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handle workflow click with support for shift-click range selection and cmd/ctrl-click toggle
|
* Handle workflow click with support for shift-click range selection and cmd/ctrl-click toggle.
|
||||||
|
* Does not clear folder selection to allow unified selection of workflows and folders.
|
||||||
*
|
*
|
||||||
* @param workflowId - ID of clicked workflow
|
* @param workflowId - ID of clicked workflow
|
||||||
* @param shiftKey - Whether shift key was pressed
|
* @param shiftKey - Whether shift key was pressed
|
||||||
@@ -44,7 +45,7 @@ export function useWorkflowSelection({ workflowIds, activeWorkflowId }: UseWorkf
|
|||||||
else if (shiftKey) {
|
else if (shiftKey) {
|
||||||
toggleWorkflowSelection(workflowId)
|
toggleWorkflowSelection(workflowId)
|
||||||
}
|
}
|
||||||
// Regular click: Select only this workflow
|
// Regular click: Select only this workflow (preserves folder selection for unified multi-select)
|
||||||
else {
|
else {
|
||||||
selectOnly(workflowId)
|
selectOnly(workflowId)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,10 +1,13 @@
|
|||||||
export { useCanDelete } from './use-can-delete'
|
export { useCanDelete } from './use-can-delete'
|
||||||
export { useDeleteFolder } from './use-delete-folder'
|
export { useDeleteFolder } from './use-delete-folder'
|
||||||
|
export { useDeleteSelection } from './use-delete-selection'
|
||||||
export { useDeleteWorkflow } from './use-delete-workflow'
|
export { useDeleteWorkflow } from './use-delete-workflow'
|
||||||
export { useDuplicateFolder } from './use-duplicate-folder'
|
export { useDuplicateFolder } from './use-duplicate-folder'
|
||||||
|
export { useDuplicateSelection } from './use-duplicate-selection'
|
||||||
export { useDuplicateWorkflow } from './use-duplicate-workflow'
|
export { useDuplicateWorkflow } from './use-duplicate-workflow'
|
||||||
export { useDuplicateWorkspace } from './use-duplicate-workspace'
|
export { useDuplicateWorkspace } from './use-duplicate-workspace'
|
||||||
export { useExportFolder } from './use-export-folder'
|
export { useExportFolder } from './use-export-folder'
|
||||||
|
export { useExportSelection } from './use-export-selection'
|
||||||
export { useExportWorkflow } from './use-export-workflow'
|
export { useExportWorkflow } from './use-export-workflow'
|
||||||
export { useExportWorkspace } from './use-export-workspace'
|
export { useExportWorkspace } from './use-export-workspace'
|
||||||
export { useImportWorkflow } from './use-import-workflow'
|
export { useImportWorkflow } from './use-import-workflow'
|
||||||
|
|||||||
@@ -0,0 +1,166 @@
|
|||||||
|
import { useCallback, useState } from 'react'
|
||||||
|
import { createLogger } from '@sim/logger'
|
||||||
|
import { useRouter } from 'next/navigation'
|
||||||
|
import { useDeleteFolderMutation } from '@/hooks/queries/folders'
|
||||||
|
import { useFolderStore } from '@/stores/folders/store'
|
||||||
|
import { useWorkflowRegistry } from '@/stores/workflows/registry/store'
|
||||||
|
|
||||||
|
const logger = createLogger('useDeleteSelection')
|
||||||
|
|
||||||
|
interface UseDeleteSelectionProps {
|
||||||
|
/**
|
||||||
|
* Current workspace ID
|
||||||
|
*/
|
||||||
|
workspaceId: string
|
||||||
|
/**
|
||||||
|
* Workflow IDs to delete
|
||||||
|
*/
|
||||||
|
workflowIds: string[]
|
||||||
|
/**
|
||||||
|
* Folder IDs to delete
|
||||||
|
*/
|
||||||
|
folderIds: string[]
|
||||||
|
/**
|
||||||
|
* Function to check if a workflow ID is the active workflow
|
||||||
|
*/
|
||||||
|
isActiveWorkflow?: (id: string) => boolean
|
||||||
|
/**
|
||||||
|
* Optional callback after successful deletion
|
||||||
|
*/
|
||||||
|
onSuccess?: () => void
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Hook for managing unified deletion of workflows and folders.
|
||||||
|
* Handles mixed selection by deleting folders first (which may contain workflows),
|
||||||
|
* then deleting standalone workflows.
|
||||||
|
*
|
||||||
|
* @param props - Hook configuration
|
||||||
|
* @returns Delete selection handlers and state
|
||||||
|
*/
|
||||||
|
export function useDeleteSelection({
|
||||||
|
workspaceId,
|
||||||
|
workflowIds,
|
||||||
|
folderIds,
|
||||||
|
isActiveWorkflow,
|
||||||
|
onSuccess,
|
||||||
|
}: UseDeleteSelectionProps) {
|
||||||
|
const router = useRouter()
|
||||||
|
const { workflows, removeWorkflow } = useWorkflowRegistry()
|
||||||
|
const deleteFolderMutation = useDeleteFolderMutation()
|
||||||
|
const [isDeleting, setIsDeleting] = useState(false)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Delete all selected folders and workflows
|
||||||
|
*/
|
||||||
|
const handleDeleteSelection = useCallback(async () => {
|
||||||
|
if (isDeleting) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
const hasWorkflows = workflowIds.length > 0
|
||||||
|
const hasFolders = folderIds.length > 0
|
||||||
|
|
||||||
|
if (!hasWorkflows && !hasFolders) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
setIsDeleting(true)
|
||||||
|
try {
|
||||||
|
const activeWorkflowBeingDeleted = isActiveWorkflow
|
||||||
|
? workflowIds.some((id) => isActiveWorkflow(id))
|
||||||
|
: false
|
||||||
|
|
||||||
|
const sidebarWorkflows = Object.values(workflows).filter((w) => w.workspaceId === workspaceId)
|
||||||
|
|
||||||
|
const workflowsInFolders = sidebarWorkflows
|
||||||
|
.filter((w) => w.folderId && folderIds.includes(w.folderId))
|
||||||
|
.map((w) => w.id)
|
||||||
|
|
||||||
|
const allWorkflowsToDelete = [...new Set([...workflowIds, ...workflowsInFolders])]
|
||||||
|
|
||||||
|
const activeInDeletedFolder = isActiveWorkflow
|
||||||
|
? workflowsInFolders.some((id) => isActiveWorkflow(id))
|
||||||
|
: false
|
||||||
|
|
||||||
|
const needsNavigation = activeWorkflowBeingDeleted || activeInDeletedFolder
|
||||||
|
|
||||||
|
let nextWorkflowId: string | null = null
|
||||||
|
if (needsNavigation && sidebarWorkflows.length > allWorkflowsToDelete.length) {
|
||||||
|
const remainingWorkflows = sidebarWorkflows.filter(
|
||||||
|
(w) => !allWorkflowsToDelete.includes(w.id)
|
||||||
|
)
|
||||||
|
|
||||||
|
if (remainingWorkflows.length > 0) {
|
||||||
|
const activeId = isActiveWorkflow
|
||||||
|
? workflowIds.find((id) => isActiveWorkflow(id)) ||
|
||||||
|
workflowsInFolders.find((id) => isActiveWorkflow(id))
|
||||||
|
: null
|
||||||
|
|
||||||
|
if (activeId) {
|
||||||
|
const currentIndex = sidebarWorkflows.findIndex((w) => w.id === activeId)
|
||||||
|
const workflowsAfterCurrent = remainingWorkflows.filter((w) => {
|
||||||
|
const idx = sidebarWorkflows.findIndex((sw) => sw.id === w.id)
|
||||||
|
return idx > currentIndex
|
||||||
|
})
|
||||||
|
|
||||||
|
nextWorkflowId =
|
||||||
|
workflowsAfterCurrent.length > 0
|
||||||
|
? workflowsAfterCurrent[0].id
|
||||||
|
: remainingWorkflows[0].id
|
||||||
|
} else {
|
||||||
|
nextWorkflowId = remainingWorkflows[0].id
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (needsNavigation) {
|
||||||
|
if (nextWorkflowId) {
|
||||||
|
router.push(`/workspace/${workspaceId}/w/${nextWorkflowId}`)
|
||||||
|
} else {
|
||||||
|
router.push(`/workspace/${workspaceId}/w`)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const folderId of folderIds) {
|
||||||
|
await deleteFolderMutation.mutateAsync({ id: folderId, workspaceId })
|
||||||
|
}
|
||||||
|
|
||||||
|
const standaloneWorkflowIds = workflowIds.filter((id) => !workflowsInFolders.includes(id))
|
||||||
|
await Promise.all(standaloneWorkflowIds.map((id) => removeWorkflow(id)))
|
||||||
|
|
||||||
|
const { clearSelection, clearFolderSelection } = useFolderStore.getState()
|
||||||
|
clearSelection()
|
||||||
|
clearFolderSelection()
|
||||||
|
|
||||||
|
logger.info('Selection deleted successfully', {
|
||||||
|
workflowIds: standaloneWorkflowIds,
|
||||||
|
folderIds,
|
||||||
|
totalWorkflowsDeleted: allWorkflowsToDelete.length,
|
||||||
|
})
|
||||||
|
|
||||||
|
onSuccess?.()
|
||||||
|
} catch (error) {
|
||||||
|
logger.error('Error deleting selection:', { error })
|
||||||
|
throw error
|
||||||
|
} finally {
|
||||||
|
setIsDeleting(false)
|
||||||
|
}
|
||||||
|
}, [
|
||||||
|
workflowIds,
|
||||||
|
folderIds,
|
||||||
|
isDeleting,
|
||||||
|
workflows,
|
||||||
|
workspaceId,
|
||||||
|
isActiveWorkflow,
|
||||||
|
router,
|
||||||
|
removeWorkflow,
|
||||||
|
deleteFolderMutation,
|
||||||
|
onSuccess,
|
||||||
|
])
|
||||||
|
|
||||||
|
return {
|
||||||
|
isDeleting,
|
||||||
|
handleDeleteSelection,
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,153 @@
|
|||||||
|
import { useCallback, useRef, useState } from 'react'
|
||||||
|
import { createLogger } from '@sim/logger'
|
||||||
|
import { useRouter } from 'next/navigation'
|
||||||
|
import { getNextWorkflowColor } from '@/lib/workflows/colors'
|
||||||
|
import { useDuplicateFolderMutation } from '@/hooks/queries/folders'
|
||||||
|
import { useDuplicateWorkflowMutation } from '@/hooks/queries/workflows'
|
||||||
|
import { useFolderStore } from '@/stores/folders/store'
|
||||||
|
import { useWorkflowRegistry } from '@/stores/workflows/registry/store'
|
||||||
|
|
||||||
|
const logger = createLogger('useDuplicateSelection')
|
||||||
|
|
||||||
|
interface UseDuplicateSelectionProps {
|
||||||
|
/**
|
||||||
|
* Current workspace ID
|
||||||
|
*/
|
||||||
|
workspaceId: string
|
||||||
|
/**
|
||||||
|
* Optional callback after successful duplication
|
||||||
|
*/
|
||||||
|
onSuccess?: () => void
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Hook for managing unified duplication of workflows and folders.
|
||||||
|
* Handles mixed selection by duplicating all selected items.
|
||||||
|
*
|
||||||
|
* @param props - Hook configuration
|
||||||
|
* @returns Duplicate selection handlers and state
|
||||||
|
*/
|
||||||
|
export function useDuplicateSelection({ workspaceId, onSuccess }: UseDuplicateSelectionProps) {
|
||||||
|
const router = useRouter()
|
||||||
|
const duplicateWorkflowMutation = useDuplicateWorkflowMutation()
|
||||||
|
const duplicateFolderMutation = useDuplicateFolderMutation()
|
||||||
|
const [isDuplicating, setIsDuplicating] = useState(false)
|
||||||
|
|
||||||
|
const workspaceIdRef = useRef(workspaceId)
|
||||||
|
workspaceIdRef.current = workspaceId
|
||||||
|
|
||||||
|
const onSuccessRef = useRef(onSuccess)
|
||||||
|
onSuccessRef.current = onSuccess
|
||||||
|
|
||||||
|
const generateDuplicateFolderName = useCallback((baseName: string, siblingNames: Set<string>) => {
|
||||||
|
const trimmedName = (baseName || 'Untitled Folder').trim()
|
||||||
|
let candidate = `${trimmedName} Copy`
|
||||||
|
let counter = 2
|
||||||
|
|
||||||
|
while (siblingNames.has(candidate)) {
|
||||||
|
candidate = `${trimmedName} Copy ${counter}`
|
||||||
|
counter += 1
|
||||||
|
}
|
||||||
|
|
||||||
|
return candidate
|
||||||
|
}, [])
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Duplicate all selected workflows and folders
|
||||||
|
*/
|
||||||
|
const handleDuplicateSelection = useCallback(
|
||||||
|
async (workflowIds: string[], folderIds: string[]) => {
|
||||||
|
if (isDuplicating) return
|
||||||
|
if (workflowIds.length === 0 && folderIds.length === 0) return
|
||||||
|
|
||||||
|
setIsDuplicating(true)
|
||||||
|
try {
|
||||||
|
const { workflows } = useWorkflowRegistry.getState()
|
||||||
|
const folderStore = useFolderStore.getState()
|
||||||
|
|
||||||
|
const duplicatedWorkflowIds: string[] = []
|
||||||
|
const duplicatedFolderIds: string[] = []
|
||||||
|
|
||||||
|
for (const folderId of folderIds) {
|
||||||
|
const folder = folderStore.getFolderById(folderId)
|
||||||
|
if (!folder) {
|
||||||
|
logger.warn(`Folder ${folderId} not found, skipping`)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
const siblingNames = new Set(
|
||||||
|
folderStore.getChildFolders(folder.parentId).map((sibling) => sibling.name)
|
||||||
|
)
|
||||||
|
siblingNames.add(folder.name)
|
||||||
|
|
||||||
|
const duplicateName = generateDuplicateFolderName(folder.name, siblingNames)
|
||||||
|
|
||||||
|
const result = await duplicateFolderMutation.mutateAsync({
|
||||||
|
id: folderId,
|
||||||
|
workspaceId: workspaceIdRef.current,
|
||||||
|
name: duplicateName,
|
||||||
|
parentId: folder.parentId,
|
||||||
|
color: folder.color,
|
||||||
|
})
|
||||||
|
|
||||||
|
if (result?.id) {
|
||||||
|
duplicatedFolderIds.push(result.id)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const workflowId of workflowIds) {
|
||||||
|
const workflow = workflows[workflowId]
|
||||||
|
if (!workflow) {
|
||||||
|
logger.warn(`Workflow ${workflowId} not found, skipping`)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
const result = await duplicateWorkflowMutation.mutateAsync({
|
||||||
|
workspaceId: workspaceIdRef.current,
|
||||||
|
sourceId: workflowId,
|
||||||
|
name: `${workflow.name} (Copy)`,
|
||||||
|
description: workflow.description,
|
||||||
|
color: getNextWorkflowColor(),
|
||||||
|
folderId: workflow.folderId,
|
||||||
|
})
|
||||||
|
|
||||||
|
duplicatedWorkflowIds.push(result.id)
|
||||||
|
}
|
||||||
|
|
||||||
|
const { clearSelection, clearFolderSelection } = useFolderStore.getState()
|
||||||
|
clearSelection()
|
||||||
|
clearFolderSelection()
|
||||||
|
|
||||||
|
logger.info('Selection duplicated successfully', {
|
||||||
|
workflowIds,
|
||||||
|
folderIds,
|
||||||
|
duplicatedWorkflowIds,
|
||||||
|
duplicatedFolderIds,
|
||||||
|
})
|
||||||
|
|
||||||
|
if (duplicatedWorkflowIds.length === 1 && duplicatedFolderIds.length === 0) {
|
||||||
|
router.push(`/workspace/${workspaceIdRef.current}/w/${duplicatedWorkflowIds[0]}`)
|
||||||
|
}
|
||||||
|
|
||||||
|
onSuccessRef.current?.()
|
||||||
|
} catch (error) {
|
||||||
|
logger.error('Error duplicating selection:', { error })
|
||||||
|
throw error
|
||||||
|
} finally {
|
||||||
|
setIsDuplicating(false)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
[
|
||||||
|
isDuplicating,
|
||||||
|
generateDuplicateFolderName,
|
||||||
|
duplicateFolderMutation,
|
||||||
|
duplicateWorkflowMutation,
|
||||||
|
router,
|
||||||
|
]
|
||||||
|
)
|
||||||
|
|
||||||
|
return {
|
||||||
|
isDuplicating,
|
||||||
|
handleDuplicateSelection,
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,207 @@
|
|||||||
|
import { useCallback, useRef, useState } from 'react'
|
||||||
|
import { createLogger } from '@sim/logger'
|
||||||
|
import {
|
||||||
|
downloadFile,
|
||||||
|
exportWorkflowsToZip,
|
||||||
|
type FolderExportData,
|
||||||
|
fetchWorkflowForExport,
|
||||||
|
type WorkflowExportData,
|
||||||
|
} from '@/lib/workflows/operations/import-export'
|
||||||
|
import { useFolderStore } from '@/stores/folders/store'
|
||||||
|
import type { WorkflowFolder } from '@/stores/folders/types'
|
||||||
|
import { useWorkflowRegistry } from '@/stores/workflows/registry/store'
|
||||||
|
import type { WorkflowMetadata } from '@/stores/workflows/registry/types'
|
||||||
|
|
||||||
|
const logger = createLogger('useExportSelection')
|
||||||
|
|
||||||
|
interface UseExportSelectionProps {
|
||||||
|
/**
|
||||||
|
* Optional callback after successful export
|
||||||
|
*/
|
||||||
|
onSuccess?: () => void
|
||||||
|
}
|
||||||
|
|
||||||
|
interface CollectedWorkflow {
|
||||||
|
id: string
|
||||||
|
folderId: string | null
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Recursively collects all workflows within a folder and its subfolders.
|
||||||
|
*/
|
||||||
|
function collectWorkflowsInFolder(
|
||||||
|
folderId: string,
|
||||||
|
workflows: Record<string, WorkflowMetadata>,
|
||||||
|
folders: Record<string, WorkflowFolder>
|
||||||
|
): CollectedWorkflow[] {
|
||||||
|
const collectedWorkflows: CollectedWorkflow[] = []
|
||||||
|
|
||||||
|
for (const workflow of Object.values(workflows)) {
|
||||||
|
if (workflow.folderId === folderId) {
|
||||||
|
collectedWorkflows.push({ id: workflow.id, folderId: workflow.folderId ?? null })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const folder of Object.values(folders)) {
|
||||||
|
if (folder.parentId === folderId) {
|
||||||
|
const childWorkflows = collectWorkflowsInFolder(folder.id, workflows, folders)
|
||||||
|
collectedWorkflows.push(...childWorkflows)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return collectedWorkflows
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Collects all subfolders recursively under multiple root folders.
|
||||||
|
*/
|
||||||
|
function collectSubfoldersForMultipleFolders(
|
||||||
|
rootFolderIds: string[],
|
||||||
|
folders: Record<string, WorkflowFolder>
|
||||||
|
): FolderExportData[] {
|
||||||
|
const subfolders: FolderExportData[] = []
|
||||||
|
|
||||||
|
function collect(parentId: string, isRootLevel: boolean) {
|
||||||
|
for (const folder of Object.values(folders)) {
|
||||||
|
if (folder.parentId === parentId) {
|
||||||
|
subfolders.push({
|
||||||
|
id: folder.id,
|
||||||
|
name: folder.name,
|
||||||
|
parentId: isRootLevel ? null : folder.parentId,
|
||||||
|
})
|
||||||
|
collect(folder.id, false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const folderId of rootFolderIds) {
|
||||||
|
collect(folderId, true)
|
||||||
|
}
|
||||||
|
|
||||||
|
return subfolders
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Hook for managing unified export of workflows and folders.
|
||||||
|
* Handles mixed selection by collecting all workflows from selected folders
|
||||||
|
* and combining with directly selected workflows.
|
||||||
|
*/
|
||||||
|
export function useExportSelection({ onSuccess }: UseExportSelectionProps = {}) {
|
||||||
|
const [isExporting, setIsExporting] = useState(false)
|
||||||
|
|
||||||
|
const onSuccessRef = useRef(onSuccess)
|
||||||
|
onSuccessRef.current = onSuccess
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Export all selected workflows and folders to a ZIP file.
|
||||||
|
* - Collects workflows from selected folders recursively
|
||||||
|
* - Deduplicates workflows that exist in both direct selection and folder contents
|
||||||
|
* - Preserves folder structure in the export
|
||||||
|
*/
|
||||||
|
const handleExportSelection = useCallback(
|
||||||
|
async (workflowIds: string[], folderIds: string[]) => {
|
||||||
|
if (isExporting) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
const hasWorkflows = workflowIds.length > 0
|
||||||
|
const hasFolders = folderIds.length > 0
|
||||||
|
|
||||||
|
if (!hasWorkflows && !hasFolders) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
setIsExporting(true)
|
||||||
|
try {
|
||||||
|
const { workflows } = useWorkflowRegistry.getState()
|
||||||
|
const { folders } = useFolderStore.getState()
|
||||||
|
|
||||||
|
const workflowsFromFolders: CollectedWorkflow[] = []
|
||||||
|
for (const folderId of folderIds) {
|
||||||
|
const collected = collectWorkflowsInFolder(folderId, workflows, folders)
|
||||||
|
workflowsFromFolders.push(...collected)
|
||||||
|
}
|
||||||
|
|
||||||
|
const subfolders = collectSubfoldersForMultipleFolders(folderIds, folders)
|
||||||
|
|
||||||
|
const selectedFoldersData: FolderExportData[] = folderIds.map((folderId) => {
|
||||||
|
const folder = folders[folderId]
|
||||||
|
return {
|
||||||
|
id: folder.id,
|
||||||
|
name: folder.name,
|
||||||
|
parentId: null,
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
const allFolders = [...selectedFoldersData, ...subfolders]
|
||||||
|
const workflowIdsFromFolders = workflowsFromFolders.map((w) => w.id)
|
||||||
|
const allWorkflowIds = [...new Set([...workflowIds, ...workflowIdsFromFolders])]
|
||||||
|
|
||||||
|
if (allWorkflowIds.length === 0) {
|
||||||
|
logger.warn('No workflows found to export')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
logger.info('Starting selection export', {
|
||||||
|
directWorkflowCount: workflowIds.length,
|
||||||
|
folderCount: folderIds.length,
|
||||||
|
totalWorkflowCount: allWorkflowIds.length,
|
||||||
|
subfolderCount: subfolders.length,
|
||||||
|
})
|
||||||
|
|
||||||
|
const workflowExportData: WorkflowExportData[] = []
|
||||||
|
|
||||||
|
for (const workflowId of allWorkflowIds) {
|
||||||
|
const workflowMeta = workflows[workflowId]
|
||||||
|
if (!workflowMeta) {
|
||||||
|
logger.warn(`Workflow ${workflowId} not found in registry`)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
const exportData = await fetchWorkflowForExport(workflowId, {
|
||||||
|
name: workflowMeta.name,
|
||||||
|
description: workflowMeta.description,
|
||||||
|
color: workflowMeta.color,
|
||||||
|
folderId: workflowMeta.folderId ?? null,
|
||||||
|
})
|
||||||
|
|
||||||
|
if (exportData) {
|
||||||
|
workflowExportData.push(exportData)
|
||||||
|
logger.info(`Workflow ${workflowId} prepared for export`)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (workflowExportData.length === 0) {
|
||||||
|
logger.warn('No workflows were successfully prepared for export')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
const zipBlob = await exportWorkflowsToZip(workflowExportData)
|
||||||
|
const zipFilename = `selection-export-${Date.now()}.zip`
|
||||||
|
downloadFile(zipBlob, zipFilename, 'application/zip')
|
||||||
|
|
||||||
|
const { clearSelection, clearFolderSelection } = useFolderStore.getState()
|
||||||
|
clearSelection()
|
||||||
|
clearFolderSelection()
|
||||||
|
|
||||||
|
logger.info('Selection exported successfully', {
|
||||||
|
workflowCount: workflowExportData.length,
|
||||||
|
folderCount: allFolders.length,
|
||||||
|
})
|
||||||
|
|
||||||
|
onSuccessRef.current?.()
|
||||||
|
} catch (error) {
|
||||||
|
logger.error('Error exporting selection:', { error })
|
||||||
|
throw error
|
||||||
|
} finally {
|
||||||
|
setIsExporting(false)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
[isExporting]
|
||||||
|
)
|
||||||
|
|
||||||
|
return {
|
||||||
|
isExporting,
|
||||||
|
handleExportSelection,
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -17,6 +17,19 @@ import { getEnv } from '@/lib/core/config/env'
|
|||||||
|
|
||||||
const logger = createLogger('SocketContext')
|
const logger = createLogger('SocketContext')
|
||||||
|
|
||||||
|
const TAB_SESSION_ID_KEY = 'sim_tab_session_id'
|
||||||
|
|
||||||
|
function getTabSessionId(): string {
|
||||||
|
if (typeof window === 'undefined') return ''
|
||||||
|
|
||||||
|
let tabSessionId = sessionStorage.getItem(TAB_SESSION_ID_KEY)
|
||||||
|
if (!tabSessionId) {
|
||||||
|
tabSessionId = crypto.randomUUID()
|
||||||
|
sessionStorage.setItem(TAB_SESSION_ID_KEY, tabSessionId)
|
||||||
|
}
|
||||||
|
return tabSessionId
|
||||||
|
}
|
||||||
|
|
||||||
interface User {
|
interface User {
|
||||||
id: string
|
id: string
|
||||||
name?: string
|
name?: string
|
||||||
@@ -36,11 +49,13 @@ interface SocketContextType {
|
|||||||
socket: Socket | null
|
socket: Socket | null
|
||||||
isConnected: boolean
|
isConnected: boolean
|
||||||
isConnecting: boolean
|
isConnecting: boolean
|
||||||
|
authFailed: boolean
|
||||||
currentWorkflowId: string | null
|
currentWorkflowId: string | null
|
||||||
currentSocketId: string | null
|
currentSocketId: string | null
|
||||||
presenceUsers: PresenceUser[]
|
presenceUsers: PresenceUser[]
|
||||||
joinWorkflow: (workflowId: string) => void
|
joinWorkflow: (workflowId: string) => void
|
||||||
leaveWorkflow: () => void
|
leaveWorkflow: () => void
|
||||||
|
retryConnection: () => void
|
||||||
emitWorkflowOperation: (
|
emitWorkflowOperation: (
|
||||||
operation: string,
|
operation: string,
|
||||||
target: string,
|
target: string,
|
||||||
@@ -63,8 +78,6 @@ interface SocketContextType {
|
|||||||
|
|
||||||
onCursorUpdate: (handler: (data: any) => void) => void
|
onCursorUpdate: (handler: (data: any) => void) => void
|
||||||
onSelectionUpdate: (handler: (data: any) => void) => void
|
onSelectionUpdate: (handler: (data: any) => void) => void
|
||||||
onUserJoined: (handler: (data: any) => void) => void
|
|
||||||
onUserLeft: (handler: (data: any) => void) => void
|
|
||||||
onWorkflowDeleted: (handler: (data: any) => void) => void
|
onWorkflowDeleted: (handler: (data: any) => void) => void
|
||||||
onWorkflowReverted: (handler: (data: any) => void) => void
|
onWorkflowReverted: (handler: (data: any) => void) => void
|
||||||
onOperationConfirmed: (handler: (data: any) => void) => void
|
onOperationConfirmed: (handler: (data: any) => void) => void
|
||||||
@@ -75,11 +88,13 @@ const SocketContext = createContext<SocketContextType>({
|
|||||||
socket: null,
|
socket: null,
|
||||||
isConnected: false,
|
isConnected: false,
|
||||||
isConnecting: false,
|
isConnecting: false,
|
||||||
|
authFailed: false,
|
||||||
currentWorkflowId: null,
|
currentWorkflowId: null,
|
||||||
currentSocketId: null,
|
currentSocketId: null,
|
||||||
presenceUsers: [],
|
presenceUsers: [],
|
||||||
joinWorkflow: () => {},
|
joinWorkflow: () => {},
|
||||||
leaveWorkflow: () => {},
|
leaveWorkflow: () => {},
|
||||||
|
retryConnection: () => {},
|
||||||
emitWorkflowOperation: () => {},
|
emitWorkflowOperation: () => {},
|
||||||
emitSubblockUpdate: () => {},
|
emitSubblockUpdate: () => {},
|
||||||
emitVariableUpdate: () => {},
|
emitVariableUpdate: () => {},
|
||||||
@@ -90,8 +105,6 @@ const SocketContext = createContext<SocketContextType>({
|
|||||||
onVariableUpdate: () => {},
|
onVariableUpdate: () => {},
|
||||||
onCursorUpdate: () => {},
|
onCursorUpdate: () => {},
|
||||||
onSelectionUpdate: () => {},
|
onSelectionUpdate: () => {},
|
||||||
onUserJoined: () => {},
|
|
||||||
onUserLeft: () => {},
|
|
||||||
onWorkflowDeleted: () => {},
|
onWorkflowDeleted: () => {},
|
||||||
onWorkflowReverted: () => {},
|
onWorkflowReverted: () => {},
|
||||||
onOperationConfirmed: () => {},
|
onOperationConfirmed: () => {},
|
||||||
@@ -112,33 +125,43 @@ export function SocketProvider({ children, user }: SocketProviderProps) {
|
|||||||
const [currentWorkflowId, setCurrentWorkflowId] = useState<string | null>(null)
|
const [currentWorkflowId, setCurrentWorkflowId] = useState<string | null>(null)
|
||||||
const [currentSocketId, setCurrentSocketId] = useState<string | null>(null)
|
const [currentSocketId, setCurrentSocketId] = useState<string | null>(null)
|
||||||
const [presenceUsers, setPresenceUsers] = useState<PresenceUser[]>([])
|
const [presenceUsers, setPresenceUsers] = useState<PresenceUser[]>([])
|
||||||
|
const [authFailed, setAuthFailed] = useState(false)
|
||||||
const initializedRef = useRef(false)
|
const initializedRef = useRef(false)
|
||||||
|
const socketRef = useRef<Socket | null>(null)
|
||||||
|
|
||||||
const params = useParams()
|
const params = useParams()
|
||||||
const urlWorkflowId = params?.workflowId as string | undefined
|
const urlWorkflowId = params?.workflowId as string | undefined
|
||||||
|
const urlWorkflowIdRef = useRef(urlWorkflowId)
|
||||||
|
urlWorkflowIdRef.current = urlWorkflowId
|
||||||
|
|
||||||
const eventHandlers = useRef<{
|
const eventHandlers = useRef<{
|
||||||
workflowOperation?: (data: any) => void
|
workflowOperation?: (data: any) => void
|
||||||
subblockUpdate?: (data: any) => void
|
subblockUpdate?: (data: any) => void
|
||||||
variableUpdate?: (data: any) => void
|
variableUpdate?: (data: any) => void
|
||||||
|
|
||||||
cursorUpdate?: (data: any) => void
|
cursorUpdate?: (data: any) => void
|
||||||
selectionUpdate?: (data: any) => void
|
selectionUpdate?: (data: any) => void
|
||||||
userJoined?: (data: any) => void
|
|
||||||
userLeft?: (data: any) => void
|
|
||||||
workflowDeleted?: (data: any) => void
|
workflowDeleted?: (data: any) => void
|
||||||
workflowReverted?: (data: any) => void
|
workflowReverted?: (data: any) => void
|
||||||
operationConfirmed?: (data: any) => void
|
operationConfirmed?: (data: any) => void
|
||||||
operationFailed?: (data: any) => void
|
operationFailed?: (data: any) => void
|
||||||
}>({})
|
}>({})
|
||||||
|
|
||||||
|
const positionUpdateTimeouts = useRef<Map<string, number>>(new Map())
|
||||||
|
const isRejoiningRef = useRef<boolean>(false)
|
||||||
|
const pendingPositionUpdates = useRef<Map<string, any>>(new Map())
|
||||||
|
|
||||||
const generateSocketToken = async (): Promise<string> => {
|
const generateSocketToken = async (): Promise<string> => {
|
||||||
const res = await fetch('/api/auth/socket-token', {
|
const res = await fetch('/api/auth/socket-token', {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
credentials: 'include',
|
credentials: 'include',
|
||||||
headers: { 'cache-control': 'no-store' },
|
headers: { 'cache-control': 'no-store' },
|
||||||
})
|
})
|
||||||
if (!res.ok) throw new Error('Failed to generate socket token')
|
if (!res.ok) {
|
||||||
|
if (res.status === 401) {
|
||||||
|
throw new Error('Authentication required')
|
||||||
|
}
|
||||||
|
throw new Error('Failed to generate socket token')
|
||||||
|
}
|
||||||
const body = await res.json().catch(() => ({}))
|
const body = await res.json().catch(() => ({}))
|
||||||
const token = body?.token
|
const token = body?.token
|
||||||
if (!token || typeof token !== 'string') throw new Error('Invalid socket token')
|
if (!token || typeof token !== 'string') throw new Error('Invalid socket token')
|
||||||
@@ -148,6 +171,11 @@ export function SocketProvider({ children, user }: SocketProviderProps) {
|
|||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!user?.id) return
|
if (!user?.id) return
|
||||||
|
|
||||||
|
if (authFailed) {
|
||||||
|
logger.info('Socket initialization skipped - auth failed, waiting for retry')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
if (initializedRef.current || socket || isConnecting) {
|
if (initializedRef.current || socket || isConnecting) {
|
||||||
logger.info('Socket already exists or is connecting, skipping initialization')
|
logger.info('Socket already exists or is connecting, skipping initialization')
|
||||||
return
|
return
|
||||||
@@ -180,8 +208,12 @@ export function SocketProvider({ children, user }: SocketProviderProps) {
|
|||||||
cb({ token: freshToken })
|
cb({ token: freshToken })
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
logger.error('Failed to generate fresh token for connection:', error)
|
logger.error('Failed to generate fresh token for connection:', error)
|
||||||
|
if (error instanceof Error && error.message === 'Authentication required') {
|
||||||
|
// True auth failure - pass null token, server will reject with "Authentication required"
|
||||||
cb({ token: null })
|
cb({ token: null })
|
||||||
}
|
}
|
||||||
|
// For server errors, don't call cb - connection will timeout and Socket.IO will retry
|
||||||
|
}
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -194,26 +226,19 @@ export function SocketProvider({ children, user }: SocketProviderProps) {
|
|||||||
connected: socketInstance.connected,
|
connected: socketInstance.connected,
|
||||||
transport: socketInstance.io.engine?.transport?.name,
|
transport: socketInstance.io.engine?.transport?.name,
|
||||||
})
|
})
|
||||||
|
// Note: join-workflow is handled by the useEffect watching isConnected
|
||||||
if (urlWorkflowId) {
|
|
||||||
logger.info(`Joining workflow room after connection: ${urlWorkflowId}`)
|
|
||||||
socketInstance.emit('join-workflow', {
|
|
||||||
workflowId: urlWorkflowId,
|
|
||||||
})
|
|
||||||
setCurrentWorkflowId(urlWorkflowId)
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
|
|
||||||
socketInstance.on('disconnect', (reason) => {
|
socketInstance.on('disconnect', (reason) => {
|
||||||
setIsConnected(false)
|
setIsConnected(false)
|
||||||
setIsConnecting(false)
|
setIsConnecting(false)
|
||||||
setCurrentSocketId(null)
|
setCurrentSocketId(null)
|
||||||
|
setCurrentWorkflowId(null)
|
||||||
|
setPresenceUsers([])
|
||||||
|
|
||||||
logger.info('Socket disconnected', {
|
logger.info('Socket disconnected', {
|
||||||
reason,
|
reason,
|
||||||
})
|
})
|
||||||
|
|
||||||
setPresenceUsers([])
|
|
||||||
})
|
})
|
||||||
|
|
||||||
socketInstance.on('connect_error', (error: any) => {
|
socketInstance.on('connect_error', (error: any) => {
|
||||||
@@ -226,24 +251,34 @@ export function SocketProvider({ children, user }: SocketProviderProps) {
|
|||||||
transport: error.transport,
|
transport: error.transport,
|
||||||
})
|
})
|
||||||
|
|
||||||
if (
|
// Check if this is an authentication failure
|
||||||
|
const isAuthError =
|
||||||
error.message?.includes('Token validation failed') ||
|
error.message?.includes('Token validation failed') ||
|
||||||
error.message?.includes('Authentication failed') ||
|
error.message?.includes('Authentication failed') ||
|
||||||
error.message?.includes('Authentication required')
|
error.message?.includes('Authentication required')
|
||||||
) {
|
|
||||||
|
if (isAuthError) {
|
||||||
logger.warn(
|
logger.warn(
|
||||||
'Authentication failed - this could indicate session expiry or token generation issues'
|
'Authentication failed - stopping reconnection attempts. User may need to refresh/re-login.'
|
||||||
)
|
)
|
||||||
|
// Stop reconnection attempts to prevent infinite loop
|
||||||
|
socketInstance.disconnect()
|
||||||
|
// Reset state to allow re-initialization when session is restored
|
||||||
|
setSocket(null)
|
||||||
|
setAuthFailed(true)
|
||||||
|
initializedRef.current = false
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
socketInstance.on('reconnect', (attemptNumber) => {
|
socketInstance.on('reconnect', (attemptNumber) => {
|
||||||
|
setIsConnected(true)
|
||||||
setCurrentSocketId(socketInstance.id ?? null)
|
setCurrentSocketId(socketInstance.id ?? null)
|
||||||
logger.info('Socket reconnected successfully', {
|
logger.info('Socket reconnected successfully', {
|
||||||
attemptNumber,
|
attemptNumber,
|
||||||
socketId: socketInstance.id,
|
socketId: socketInstance.id,
|
||||||
transport: socketInstance.io.engine?.transport?.name,
|
transport: socketInstance.io.engine?.transport?.name,
|
||||||
})
|
})
|
||||||
|
// Note: join-workflow is handled by the useEffect watching isConnected
|
||||||
})
|
})
|
||||||
|
|
||||||
socketInstance.on('reconnect_attempt', (attemptNumber) => {
|
socketInstance.on('reconnect_attempt', (attemptNumber) => {
|
||||||
@@ -284,6 +319,26 @@ export function SocketProvider({ children, user }: SocketProviderProps) {
|
|||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// Handle join workflow success - confirms room membership with presence list
|
||||||
|
socketInstance.on('join-workflow-success', ({ workflowId, presenceUsers }) => {
|
||||||
|
isRejoiningRef.current = false
|
||||||
|
// Ignore stale success responses from previous navigation
|
||||||
|
if (workflowId !== urlWorkflowIdRef.current) {
|
||||||
|
logger.debug(`Ignoring stale join-workflow-success for ${workflowId}`)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
setCurrentWorkflowId(workflowId)
|
||||||
|
setPresenceUsers(presenceUsers || [])
|
||||||
|
logger.info(`Successfully joined workflow room: ${workflowId}`, {
|
||||||
|
presenceCount: presenceUsers?.length || 0,
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
socketInstance.on('join-workflow-error', ({ error }) => {
|
||||||
|
isRejoiningRef.current = false
|
||||||
|
logger.error('Failed to join workflow:', error)
|
||||||
|
})
|
||||||
|
|
||||||
socketInstance.on('workflow-operation', (data) => {
|
socketInstance.on('workflow-operation', (data) => {
|
||||||
eventHandlers.current.workflowOperation?.(data)
|
eventHandlers.current.workflowOperation?.(data)
|
||||||
})
|
})
|
||||||
@@ -298,10 +353,13 @@ export function SocketProvider({ children, user }: SocketProviderProps) {
|
|||||||
|
|
||||||
socketInstance.on('workflow-deleted', (data) => {
|
socketInstance.on('workflow-deleted', (data) => {
|
||||||
logger.warn(`Workflow ${data.workflowId} has been deleted`)
|
logger.warn(`Workflow ${data.workflowId} has been deleted`)
|
||||||
if (currentWorkflowId === data.workflowId) {
|
setCurrentWorkflowId((current) => {
|
||||||
setCurrentWorkflowId(null)
|
if (current === data.workflowId) {
|
||||||
setPresenceUsers([])
|
setPresenceUsers([])
|
||||||
|
return null
|
||||||
}
|
}
|
||||||
|
return current
|
||||||
|
})
|
||||||
eventHandlers.current.workflowDeleted?.(data)
|
eventHandlers.current.workflowDeleted?.(data)
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -310,11 +368,7 @@ export function SocketProvider({ children, user }: SocketProviderProps) {
|
|||||||
eventHandlers.current.workflowReverted?.(data)
|
eventHandlers.current.workflowReverted?.(data)
|
||||||
})
|
})
|
||||||
|
|
||||||
const rehydrateWorkflowStores = async (
|
const rehydrateWorkflowStores = async (workflowId: string, workflowState: any) => {
|
||||||
workflowId: string,
|
|
||||||
workflowState: any,
|
|
||||||
source: 'copilot' | 'workflow-state'
|
|
||||||
) => {
|
|
||||||
const [
|
const [
|
||||||
{ useOperationQueueStore },
|
{ useOperationQueueStore },
|
||||||
{ useWorkflowRegistry },
|
{ useWorkflowRegistry },
|
||||||
@@ -339,7 +393,7 @@ export function SocketProvider({ children, user }: SocketProviderProps) {
|
|||||||
.getState()
|
.getState()
|
||||||
.operations.some((op: any) => op.workflowId === workflowId && op.status !== 'confirmed')
|
.operations.some((op: any) => op.workflowId === workflowId && op.status !== 'confirmed')
|
||||||
if (hasPending) {
|
if (hasPending) {
|
||||||
logger.info(`Skipping ${source} rehydration due to pending operations in queue`)
|
logger.info('Skipping rehydration due to pending operations in queue')
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -368,32 +422,10 @@ export function SocketProvider({ children, user }: SocketProviderProps) {
|
|||||||
},
|
},
|
||||||
}))
|
}))
|
||||||
|
|
||||||
logger.info(`Successfully rehydrated stores from ${source}`)
|
logger.info('Successfully rehydrated workflow stores')
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
socketInstance.on('copilot-workflow-edit', async (data) => {
|
|
||||||
logger.info(
|
|
||||||
`Copilot edited workflow ${data.workflowId} - rehydrating stores from database`
|
|
||||||
)
|
|
||||||
|
|
||||||
try {
|
|
||||||
const response = await fetch(`/api/workflows/${data.workflowId}`)
|
|
||||||
if (response.ok) {
|
|
||||||
const responseData = await response.json()
|
|
||||||
const workflowData = responseData.data
|
|
||||||
|
|
||||||
if (workflowData?.state) {
|
|
||||||
await rehydrateWorkflowStores(data.workflowId, workflowData.state, 'copilot')
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
logger.error('Failed to fetch fresh workflow state:', response.statusText)
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
logger.error('Failed to rehydrate stores after copilot edit:', error)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
socketInstance.on('operation-confirmed', (data) => {
|
socketInstance.on('operation-confirmed', (data) => {
|
||||||
logger.debug('Operation confirmed', { operationId: data.operationId })
|
logger.debug('Operation confirmed', { operationId: data.operationId })
|
||||||
eventHandlers.current.operationConfirmed?.(data)
|
eventHandlers.current.operationConfirmed?.(data)
|
||||||
@@ -444,25 +476,35 @@ export function SocketProvider({ children, user }: SocketProviderProps) {
|
|||||||
|
|
||||||
socketInstance.on('operation-forbidden', (error) => {
|
socketInstance.on('operation-forbidden', (error) => {
|
||||||
logger.warn('Operation forbidden:', error)
|
logger.warn('Operation forbidden:', error)
|
||||||
})
|
|
||||||
|
|
||||||
socketInstance.on('operation-confirmed', (data) => {
|
if (error?.type === 'SESSION_ERROR') {
|
||||||
logger.debug('Operation confirmed:', data)
|
const workflowId = urlWorkflowIdRef.current
|
||||||
|
|
||||||
|
if (workflowId && !isRejoiningRef.current) {
|
||||||
|
isRejoiningRef.current = true
|
||||||
|
logger.info(`Session expired, rejoining workflow: ${workflowId}`)
|
||||||
|
socketInstance.emit('join-workflow', {
|
||||||
|
workflowId,
|
||||||
|
tabSessionId: getTabSessionId(),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
socketInstance.on('workflow-state', async (workflowData) => {
|
socketInstance.on('workflow-state', async (workflowData) => {
|
||||||
logger.info('Received workflow state from server')
|
logger.info('Received workflow state from server')
|
||||||
|
|
||||||
if (workflowData?.state) {
|
if (workflowData?.state) {
|
||||||
await rehydrateWorkflowStores(workflowData.id, workflowData.state, 'workflow-state')
|
try {
|
||||||
|
await rehydrateWorkflowStores(workflowData.id, workflowData.state)
|
||||||
|
} catch (error) {
|
||||||
|
logger.error('Error rehydrating workflow state:', error)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
socketRef.current = socketInstance
|
||||||
setSocket(socketInstance)
|
setSocket(socketInstance)
|
||||||
|
|
||||||
return () => {
|
|
||||||
socketInstance.close()
|
|
||||||
}
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
logger.error('Failed to initialize socket with token:', error)
|
logger.error('Failed to initialize socket with token:', error)
|
||||||
setIsConnecting(false)
|
setIsConnecting(false)
|
||||||
@@ -477,12 +519,20 @@ export function SocketProvider({ children, user }: SocketProviderProps) {
|
|||||||
})
|
})
|
||||||
positionUpdateTimeouts.current.clear()
|
positionUpdateTimeouts.current.clear()
|
||||||
pendingPositionUpdates.current.clear()
|
pendingPositionUpdates.current.clear()
|
||||||
|
|
||||||
|
// Close socket on unmount
|
||||||
|
if (socketRef.current) {
|
||||||
|
logger.info('Closing socket connection on unmount')
|
||||||
|
socketRef.current.close()
|
||||||
|
socketRef.current = null
|
||||||
}
|
}
|
||||||
}, [user?.id])
|
}
|
||||||
|
}, [user?.id, authFailed])
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!socket || !isConnected || !urlWorkflowId) return
|
if (!socket || !isConnected || !urlWorkflowId) return
|
||||||
|
|
||||||
|
// Skip if already in the correct room
|
||||||
if (currentWorkflowId === urlWorkflowId) return
|
if (currentWorkflowId === urlWorkflowId) return
|
||||||
|
|
||||||
logger.info(
|
logger.info(
|
||||||
@@ -497,19 +547,10 @@ export function SocketProvider({ children, user }: SocketProviderProps) {
|
|||||||
logger.info(`Joining workflow room: ${urlWorkflowId}`)
|
logger.info(`Joining workflow room: ${urlWorkflowId}`)
|
||||||
socket.emit('join-workflow', {
|
socket.emit('join-workflow', {
|
||||||
workflowId: urlWorkflowId,
|
workflowId: urlWorkflowId,
|
||||||
|
tabSessionId: getTabSessionId(),
|
||||||
})
|
})
|
||||||
setCurrentWorkflowId(urlWorkflowId)
|
|
||||||
}, [socket, isConnected, urlWorkflowId, currentWorkflowId])
|
}, [socket, isConnected, urlWorkflowId, currentWorkflowId])
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
return () => {
|
|
||||||
if (socket) {
|
|
||||||
logger.info('Cleaning up socket connection on unmount')
|
|
||||||
socket.disconnect()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}, [])
|
|
||||||
|
|
||||||
const joinWorkflow = useCallback(
|
const joinWorkflow = useCallback(
|
||||||
(workflowId: string) => {
|
(workflowId: string) => {
|
||||||
if (!socket || !user?.id) {
|
if (!socket || !user?.id) {
|
||||||
@@ -530,8 +571,9 @@ export function SocketProvider({ children, user }: SocketProviderProps) {
|
|||||||
logger.info(`Joining workflow: ${workflowId}`)
|
logger.info(`Joining workflow: ${workflowId}`)
|
||||||
socket.emit('join-workflow', {
|
socket.emit('join-workflow', {
|
||||||
workflowId,
|
workflowId,
|
||||||
|
tabSessionId: getTabSessionId(),
|
||||||
})
|
})
|
||||||
setCurrentWorkflowId(workflowId)
|
// currentWorkflowId will be set by join-workflow-success handler
|
||||||
},
|
},
|
||||||
[socket, user, currentWorkflowId]
|
[socket, user, currentWorkflowId]
|
||||||
)
|
)
|
||||||
@@ -539,10 +581,13 @@ export function SocketProvider({ children, user }: SocketProviderProps) {
|
|||||||
const leaveWorkflow = useCallback(() => {
|
const leaveWorkflow = useCallback(() => {
|
||||||
if (socket && currentWorkflowId) {
|
if (socket && currentWorkflowId) {
|
||||||
logger.info(`Leaving workflow: ${currentWorkflowId}`)
|
logger.info(`Leaving workflow: ${currentWorkflowId}`)
|
||||||
try {
|
import('@/stores/operation-queue/store')
|
||||||
const { useOperationQueueStore } = require('@/stores/operation-queue/store')
|
.then(({ useOperationQueueStore }) => {
|
||||||
useOperationQueueStore.getState().cancelOperationsForWorkflow(currentWorkflowId)
|
useOperationQueueStore.getState().cancelOperationsForWorkflow(currentWorkflowId)
|
||||||
} catch {}
|
})
|
||||||
|
.catch((error) => {
|
||||||
|
logger.warn('Failed to cancel operations for workflow:', error)
|
||||||
|
})
|
||||||
socket.emit('leave-workflow')
|
socket.emit('leave-workflow')
|
||||||
setCurrentWorkflowId(null)
|
setCurrentWorkflowId(null)
|
||||||
setPresenceUsers([])
|
setPresenceUsers([])
|
||||||
@@ -555,8 +600,20 @@ export function SocketProvider({ children, user }: SocketProviderProps) {
|
|||||||
}
|
}
|
||||||
}, [socket, currentWorkflowId])
|
}, [socket, currentWorkflowId])
|
||||||
|
|
||||||
const positionUpdateTimeouts = useRef<Map<string, number>>(new Map())
|
/**
|
||||||
const pendingPositionUpdates = useRef<Map<string, any>>(new Map())
|
* Retry socket connection after auth failure.
|
||||||
|
* Call this when user has re-authenticated (e.g., after login redirect).
|
||||||
|
*/
|
||||||
|
const retryConnection = useCallback(() => {
|
||||||
|
if (!authFailed) {
|
||||||
|
logger.info('retryConnection called but no auth failure - ignoring')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
logger.info('Retrying socket connection after auth failure')
|
||||||
|
setAuthFailed(false)
|
||||||
|
// initializedRef.current was already reset in connect_error handler
|
||||||
|
// Effect will re-run and attempt connection
|
||||||
|
}, [authFailed])
|
||||||
|
|
||||||
const emitWorkflowOperation = useCallback(
|
const emitWorkflowOperation = useCallback(
|
||||||
(operation: string, target: string, payload: any, operationId?: string) => {
|
(operation: string, target: string, payload: any, operationId?: string) => {
|
||||||
@@ -716,14 +773,6 @@ export function SocketProvider({ children, user }: SocketProviderProps) {
|
|||||||
eventHandlers.current.selectionUpdate = handler
|
eventHandlers.current.selectionUpdate = handler
|
||||||
}, [])
|
}, [])
|
||||||
|
|
||||||
const onUserJoined = useCallback((handler: (data: any) => void) => {
|
|
||||||
eventHandlers.current.userJoined = handler
|
|
||||||
}, [])
|
|
||||||
|
|
||||||
const onUserLeft = useCallback((handler: (data: any) => void) => {
|
|
||||||
eventHandlers.current.userLeft = handler
|
|
||||||
}, [])
|
|
||||||
|
|
||||||
const onWorkflowDeleted = useCallback((handler: (data: any) => void) => {
|
const onWorkflowDeleted = useCallback((handler: (data: any) => void) => {
|
||||||
eventHandlers.current.workflowDeleted = handler
|
eventHandlers.current.workflowDeleted = handler
|
||||||
}, [])
|
}, [])
|
||||||
@@ -745,11 +794,13 @@ export function SocketProvider({ children, user }: SocketProviderProps) {
|
|||||||
socket,
|
socket,
|
||||||
isConnected,
|
isConnected,
|
||||||
isConnecting,
|
isConnecting,
|
||||||
|
authFailed,
|
||||||
currentWorkflowId,
|
currentWorkflowId,
|
||||||
currentSocketId,
|
currentSocketId,
|
||||||
presenceUsers,
|
presenceUsers,
|
||||||
joinWorkflow,
|
joinWorkflow,
|
||||||
leaveWorkflow,
|
leaveWorkflow,
|
||||||
|
retryConnection,
|
||||||
emitWorkflowOperation,
|
emitWorkflowOperation,
|
||||||
emitSubblockUpdate,
|
emitSubblockUpdate,
|
||||||
emitVariableUpdate,
|
emitVariableUpdate,
|
||||||
@@ -760,8 +811,6 @@ export function SocketProvider({ children, user }: SocketProviderProps) {
|
|||||||
onVariableUpdate,
|
onVariableUpdate,
|
||||||
onCursorUpdate,
|
onCursorUpdate,
|
||||||
onSelectionUpdate,
|
onSelectionUpdate,
|
||||||
onUserJoined,
|
|
||||||
onUserLeft,
|
|
||||||
onWorkflowDeleted,
|
onWorkflowDeleted,
|
||||||
onWorkflowReverted,
|
onWorkflowReverted,
|
||||||
onOperationConfirmed,
|
onOperationConfirmed,
|
||||||
@@ -771,11 +820,13 @@ export function SocketProvider({ children, user }: SocketProviderProps) {
|
|||||||
socket,
|
socket,
|
||||||
isConnected,
|
isConnected,
|
||||||
isConnecting,
|
isConnecting,
|
||||||
|
authFailed,
|
||||||
currentWorkflowId,
|
currentWorkflowId,
|
||||||
currentSocketId,
|
currentSocketId,
|
||||||
presenceUsers,
|
presenceUsers,
|
||||||
joinWorkflow,
|
joinWorkflow,
|
||||||
leaveWorkflow,
|
leaveWorkflow,
|
||||||
|
retryConnection,
|
||||||
emitWorkflowOperation,
|
emitWorkflowOperation,
|
||||||
emitSubblockUpdate,
|
emitSubblockUpdate,
|
||||||
emitVariableUpdate,
|
emitVariableUpdate,
|
||||||
@@ -786,8 +837,6 @@ export function SocketProvider({ children, user }: SocketProviderProps) {
|
|||||||
onVariableUpdate,
|
onVariableUpdate,
|
||||||
onCursorUpdate,
|
onCursorUpdate,
|
||||||
onSelectionUpdate,
|
onSelectionUpdate,
|
||||||
onUserJoined,
|
|
||||||
onUserLeft,
|
|
||||||
onWorkflowDeleted,
|
onWorkflowDeleted,
|
||||||
onWorkflowReverted,
|
onWorkflowReverted,
|
||||||
onOperationConfirmed,
|
onOperationConfirmed,
|
||||||
|
|||||||
@@ -774,8 +774,7 @@ Example 3 (Array Input):
|
|||||||
providerTiming: {
|
providerTiming: {
|
||||||
type: 'json',
|
type: 'json',
|
||||||
description: 'Provider timing information',
|
description: 'Provider timing information',
|
||||||
hiddenFromDisplay: true,
|
|
||||||
},
|
},
|
||||||
cost: { type: 'number', description: 'Cost of the API call', hiddenFromDisplay: true },
|
cost: { type: 'json', description: 'Cost of the API call' },
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|||||||
828
apps/sim/blocks/blocks/calcom.ts
Normal file
828
apps/sim/blocks/blocks/calcom.ts
Normal file
@@ -0,0 +1,828 @@
|
|||||||
|
import { CalComIcon } from '@/components/icons'
|
||||||
|
import type { BlockConfig } from '@/blocks/types'
|
||||||
|
import { AuthMode } from '@/blocks/types'
|
||||||
|
import type { ToolResponse } from '@/tools/types'
|
||||||
|
import { getTrigger } from '@/triggers'
|
||||||
|
|
||||||
|
export const CalComBlock: BlockConfig<ToolResponse> = {
|
||||||
|
type: 'calcom',
|
||||||
|
name: 'CalCom',
|
||||||
|
description: 'Manage Cal.com bookings, event types, schedules, and availability',
|
||||||
|
authMode: AuthMode.OAuth,
|
||||||
|
triggerAllowed: true,
|
||||||
|
longDescription:
|
||||||
|
'Integrate Cal.com into your workflow. Create and manage bookings, event types, schedules, and check availability slots. Supports creating, listing, rescheduling, and canceling bookings, as well as managing event types and schedules. Can also trigger workflows based on Cal.com webhook events (booking created, cancelled, rescheduled). Connect your Cal.com account via OAuth.',
|
||||||
|
docsLink: 'https://docs.sim.ai/tools/calcom',
|
||||||
|
category: 'tools',
|
||||||
|
bgColor: '#FFFFFE',
|
||||||
|
icon: CalComIcon,
|
||||||
|
subBlocks: [
|
||||||
|
{
|
||||||
|
id: 'operation',
|
||||||
|
title: 'Operation',
|
||||||
|
type: 'dropdown',
|
||||||
|
options: [
|
||||||
|
{ label: 'List Bookings', id: 'calcom_list_bookings' },
|
||||||
|
{ label: 'Create Booking', id: 'calcom_create_booking' },
|
||||||
|
{ label: 'Get Booking', id: 'calcom_get_booking' },
|
||||||
|
{ label: 'Cancel Booking', id: 'calcom_cancel_booking' },
|
||||||
|
{ label: 'Reschedule Booking', id: 'calcom_reschedule_booking' },
|
||||||
|
{ label: 'Confirm Booking', id: 'calcom_confirm_booking' },
|
||||||
|
{ label: 'Decline Booking', id: 'calcom_decline_booking' },
|
||||||
|
{ label: 'Create Event Type', id: 'calcom_create_event_type' },
|
||||||
|
{ label: 'Get Event Type', id: 'calcom_get_event_type' },
|
||||||
|
{ label: 'List Event Types', id: 'calcom_list_event_types' },
|
||||||
|
{ label: 'Update Event Type', id: 'calcom_update_event_type' },
|
||||||
|
{ label: 'Delete Event Type', id: 'calcom_delete_event_type' },
|
||||||
|
{ label: 'Create Schedule', id: 'calcom_create_schedule' },
|
||||||
|
{ label: 'Get Schedule', id: 'calcom_get_schedule' },
|
||||||
|
{ label: 'List Schedules', id: 'calcom_list_schedules' },
|
||||||
|
{ label: 'Update Schedule', id: 'calcom_update_schedule' },
|
||||||
|
{ label: 'Delete Schedule', id: 'calcom_delete_schedule' },
|
||||||
|
{ label: 'Get Default Schedule', id: 'calcom_get_default_schedule' },
|
||||||
|
{ label: 'Get Available Slots', id: 'calcom_get_slots' },
|
||||||
|
],
|
||||||
|
value: () => 'calcom_list_bookings',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'credential',
|
||||||
|
title: 'Cal.com Account',
|
||||||
|
type: 'oauth-input',
|
||||||
|
serviceId: 'calcom',
|
||||||
|
placeholder: 'Select Cal.com account',
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
|
||||||
|
// === Create Booking fields ===
|
||||||
|
{
|
||||||
|
id: 'eventTypeId',
|
||||||
|
title: 'Event Type ID',
|
||||||
|
type: 'short-input',
|
||||||
|
placeholder: 'Enter event type ID (number)',
|
||||||
|
condition: {
|
||||||
|
field: 'operation',
|
||||||
|
value: ['calcom_create_booking', 'calcom_get_slots'],
|
||||||
|
},
|
||||||
|
required: { field: 'operation', value: 'calcom_create_booking' },
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'start',
|
||||||
|
title: 'Start Time',
|
||||||
|
type: 'short-input',
|
||||||
|
placeholder: 'ISO 8601 format (e.g., 2024-01-15T10:00:00Z)',
|
||||||
|
condition: {
|
||||||
|
field: 'operation',
|
||||||
|
value: ['calcom_create_booking', 'calcom_reschedule_booking', 'calcom_get_slots'],
|
||||||
|
},
|
||||||
|
required: {
|
||||||
|
field: 'operation',
|
||||||
|
value: ['calcom_create_booking', 'calcom_reschedule_booking', 'calcom_get_slots'],
|
||||||
|
},
|
||||||
|
wandConfig: {
|
||||||
|
enabled: true,
|
||||||
|
prompt: `Generate an ISO 8601 timestamp in UTC based on the user's description.
|
||||||
|
Format: YYYY-MM-DDTHH:MM:SSZ
|
||||||
|
Examples:
|
||||||
|
- "tomorrow at 2pm" -> Tomorrow's date at 14:00:00Z
|
||||||
|
- "next Monday 9am" -> Next Monday at 09:00:00Z
|
||||||
|
- "in 3 hours" -> Current time + 3 hours
|
||||||
|
|
||||||
|
Return ONLY the timestamp string - no explanations or quotes.`,
|
||||||
|
placeholder: 'Describe the start time (e.g., "tomorrow at 2pm")...',
|
||||||
|
generationType: 'timestamp',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'end',
|
||||||
|
title: 'End Time',
|
||||||
|
type: 'short-input',
|
||||||
|
placeholder: 'ISO 8601 format (e.g., 2024-01-15T11:00:00Z)',
|
||||||
|
condition: { field: 'operation', value: 'calcom_get_slots' },
|
||||||
|
required: { field: 'operation', value: 'calcom_get_slots' },
|
||||||
|
wandConfig: {
|
||||||
|
enabled: true,
|
||||||
|
prompt: `Generate an ISO 8601 timestamp in UTC based on the user's description.
|
||||||
|
Format: YYYY-MM-DDTHH:MM:SSZ
|
||||||
|
Examples:
|
||||||
|
- "end of tomorrow" -> Tomorrow at 23:59:59Z
|
||||||
|
- "next Friday" -> Next Friday at 23:59:59Z
|
||||||
|
- "in 1 week" -> Current date + 7 days
|
||||||
|
|
||||||
|
Return ONLY the timestamp string - no explanations or quotes.`,
|
||||||
|
placeholder: 'Describe the end time (e.g., "end of next week")...',
|
||||||
|
generationType: 'timestamp',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'attendeeName',
|
||||||
|
title: 'Attendee Name',
|
||||||
|
type: 'short-input',
|
||||||
|
placeholder: 'Enter attendee name',
|
||||||
|
condition: { field: 'operation', value: 'calcom_create_booking' },
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'attendeeEmail',
|
||||||
|
title: 'Attendee Email',
|
||||||
|
type: 'short-input',
|
||||||
|
placeholder: 'Enter attendee email',
|
||||||
|
condition: { field: 'operation', value: 'calcom_create_booking' },
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'attendeeTimeZone',
|
||||||
|
title: 'Attendee Time Zone',
|
||||||
|
type: 'short-input',
|
||||||
|
placeholder: 'e.g., America/New_York, Europe/London',
|
||||||
|
condition: { field: 'operation', value: 'calcom_create_booking' },
|
||||||
|
required: true,
|
||||||
|
wandConfig: {
|
||||||
|
enabled: true,
|
||||||
|
prompt: `Convert the user's timezone description to a valid IANA timezone identifier.
|
||||||
|
|
||||||
|
Common examples:
|
||||||
|
- "New York" or "Eastern" -> America/New_York
|
||||||
|
- "Los Angeles" or "Pacific" -> America/Los_Angeles
|
||||||
|
- "Chicago" or "Central" -> America/Chicago
|
||||||
|
- "London" -> Europe/London
|
||||||
|
- "Paris" -> Europe/Paris
|
||||||
|
- "Tokyo" -> Asia/Tokyo
|
||||||
|
- "Sydney" -> Australia/Sydney
|
||||||
|
- "UTC" or "GMT" -> UTC
|
||||||
|
|
||||||
|
Return ONLY the IANA timezone string - no explanations or quotes.`,
|
||||||
|
placeholder: 'Describe the timezone (e.g., "New York", "Pacific time")...',
|
||||||
|
generationType: 'timezone',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'attendeePhone',
|
||||||
|
title: 'Attendee Phone',
|
||||||
|
type: 'short-input',
|
||||||
|
placeholder: 'International format (e.g., +1234567890)',
|
||||||
|
condition: { field: 'operation', value: 'calcom_create_booking' },
|
||||||
|
mode: 'advanced',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'guests',
|
||||||
|
title: 'Guests',
|
||||||
|
type: 'short-input',
|
||||||
|
placeholder: 'Comma-separated email addresses',
|
||||||
|
condition: { field: 'operation', value: 'calcom_create_booking' },
|
||||||
|
mode: 'advanced',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'lengthInMinutes',
|
||||||
|
title: 'Duration (minutes)',
|
||||||
|
type: 'short-input',
|
||||||
|
placeholder: 'Override default event duration',
|
||||||
|
condition: { field: 'operation', value: 'calcom_create_booking' },
|
||||||
|
mode: 'advanced',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'metadata',
|
||||||
|
title: 'Metadata',
|
||||||
|
type: 'code',
|
||||||
|
language: 'json',
|
||||||
|
placeholder: '{"key": "value"}',
|
||||||
|
condition: { field: 'operation', value: 'calcom_create_booking' },
|
||||||
|
mode: 'advanced',
|
||||||
|
},
|
||||||
|
|
||||||
|
// === Get/Cancel/Reschedule/Confirm/Decline Booking fields ===
|
||||||
|
{
|
||||||
|
id: 'bookingUid',
|
||||||
|
title: 'Booking UID',
|
||||||
|
type: 'short-input',
|
||||||
|
placeholder: 'Enter booking UID',
|
||||||
|
condition: {
|
||||||
|
field: 'operation',
|
||||||
|
value: [
|
||||||
|
'calcom_get_booking',
|
||||||
|
'calcom_cancel_booking',
|
||||||
|
'calcom_reschedule_booking',
|
||||||
|
'calcom_confirm_booking',
|
||||||
|
'calcom_decline_booking',
|
||||||
|
],
|
||||||
|
},
|
||||||
|
required: {
|
||||||
|
field: 'operation',
|
||||||
|
value: [
|
||||||
|
'calcom_get_booking',
|
||||||
|
'calcom_cancel_booking',
|
||||||
|
'calcom_reschedule_booking',
|
||||||
|
'calcom_confirm_booking',
|
||||||
|
'calcom_decline_booking',
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'cancellationReason',
|
||||||
|
title: 'Cancellation Reason',
|
||||||
|
type: 'long-input',
|
||||||
|
placeholder: 'Reason for cancellation',
|
||||||
|
rows: 3,
|
||||||
|
condition: { field: 'operation', value: 'calcom_cancel_booking' },
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'reschedulingReason',
|
||||||
|
title: 'Rescheduling Reason',
|
||||||
|
type: 'long-input',
|
||||||
|
placeholder: 'Reason for rescheduling',
|
||||||
|
rows: 3,
|
||||||
|
condition: { field: 'operation', value: 'calcom_reschedule_booking' },
|
||||||
|
mode: 'advanced',
|
||||||
|
},
|
||||||
|
|
||||||
|
// === List Bookings filters ===
|
||||||
|
{
|
||||||
|
id: 'bookingStatus',
|
||||||
|
title: 'Status',
|
||||||
|
type: 'dropdown',
|
||||||
|
options: [
|
||||||
|
{ label: 'All', id: '' },
|
||||||
|
{ label: 'Upcoming', id: 'upcoming' },
|
||||||
|
{ label: 'Recurring', id: 'recurring' },
|
||||||
|
{ label: 'Past', id: 'past' },
|
||||||
|
{ label: 'Cancelled', id: 'cancelled' },
|
||||||
|
{ label: 'Unconfirmed', id: 'unconfirmed' },
|
||||||
|
],
|
||||||
|
condition: { field: 'operation', value: 'calcom_list_bookings' },
|
||||||
|
},
|
||||||
|
|
||||||
|
// === Event Type fields ===
|
||||||
|
{
|
||||||
|
id: 'eventTypeIdParam',
|
||||||
|
title: 'Event Type ID',
|
||||||
|
type: 'short-input',
|
||||||
|
placeholder: 'Enter event type ID',
|
||||||
|
condition: {
|
||||||
|
field: 'operation',
|
||||||
|
value: ['calcom_get_event_type', 'calcom_update_event_type', 'calcom_delete_event_type'],
|
||||||
|
},
|
||||||
|
required: {
|
||||||
|
field: 'operation',
|
||||||
|
value: ['calcom_get_event_type', 'calcom_update_event_type', 'calcom_delete_event_type'],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'title',
|
||||||
|
title: 'Title',
|
||||||
|
type: 'short-input',
|
||||||
|
placeholder: 'Event type title',
|
||||||
|
condition: {
|
||||||
|
field: 'operation',
|
||||||
|
value: ['calcom_create_event_type', 'calcom_update_event_type'],
|
||||||
|
},
|
||||||
|
required: { field: 'operation', value: 'calcom_create_event_type' },
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'slug',
|
||||||
|
title: 'Slug',
|
||||||
|
type: 'short-input',
|
||||||
|
placeholder: 'URL-friendly identifier (e.g., 30-min-meeting)',
|
||||||
|
condition: {
|
||||||
|
field: 'operation',
|
||||||
|
value: ['calcom_create_event_type', 'calcom_update_event_type'],
|
||||||
|
},
|
||||||
|
required: { field: 'operation', value: 'calcom_create_event_type' },
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'eventLength',
|
||||||
|
title: 'Duration (minutes)',
|
||||||
|
type: 'short-input',
|
||||||
|
placeholder: 'Event duration in minutes (e.g., 30)',
|
||||||
|
condition: {
|
||||||
|
field: 'operation',
|
||||||
|
value: ['calcom_create_event_type', 'calcom_update_event_type'],
|
||||||
|
},
|
||||||
|
required: { field: 'operation', value: 'calcom_create_event_type' },
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'description',
|
||||||
|
title: 'Description',
|
||||||
|
type: 'long-input',
|
||||||
|
placeholder: 'Event type description',
|
||||||
|
rows: 3,
|
||||||
|
condition: {
|
||||||
|
field: 'operation',
|
||||||
|
value: ['calcom_create_event_type', 'calcom_update_event_type'],
|
||||||
|
},
|
||||||
|
mode: 'advanced',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'slotInterval',
|
||||||
|
title: 'Slot Interval (minutes)',
|
||||||
|
type: 'short-input',
|
||||||
|
placeholder: 'Minutes between available slots',
|
||||||
|
condition: {
|
||||||
|
field: 'operation',
|
||||||
|
value: ['calcom_create_event_type', 'calcom_update_event_type'],
|
||||||
|
},
|
||||||
|
mode: 'advanced',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'minimumBookingNotice',
|
||||||
|
title: 'Minimum Notice (minutes)',
|
||||||
|
type: 'short-input',
|
||||||
|
placeholder: 'Minimum advance notice required',
|
||||||
|
condition: {
|
||||||
|
field: 'operation',
|
||||||
|
value: ['calcom_create_event_type', 'calcom_update_event_type'],
|
||||||
|
},
|
||||||
|
mode: 'advanced',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'beforeEventBuffer',
|
||||||
|
title: 'Buffer Before (minutes)',
|
||||||
|
type: 'short-input',
|
||||||
|
placeholder: 'Buffer time before event',
|
||||||
|
condition: {
|
||||||
|
field: 'operation',
|
||||||
|
value: ['calcom_create_event_type', 'calcom_update_event_type'],
|
||||||
|
},
|
||||||
|
mode: 'advanced',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'afterEventBuffer',
|
||||||
|
title: 'Buffer After (minutes)',
|
||||||
|
type: 'short-input',
|
||||||
|
placeholder: 'Buffer time after event',
|
||||||
|
condition: {
|
||||||
|
field: 'operation',
|
||||||
|
value: ['calcom_create_event_type', 'calcom_update_event_type'],
|
||||||
|
},
|
||||||
|
mode: 'advanced',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'eventTypeScheduleId',
|
||||||
|
title: 'Schedule ID',
|
||||||
|
type: 'short-input',
|
||||||
|
placeholder: 'Assign to a specific schedule',
|
||||||
|
condition: {
|
||||||
|
field: 'operation',
|
||||||
|
value: ['calcom_create_event_type', 'calcom_update_event_type'],
|
||||||
|
},
|
||||||
|
mode: 'advanced',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'disableGuests',
|
||||||
|
title: 'Disable Guests',
|
||||||
|
type: 'switch',
|
||||||
|
description: 'Prevent attendees from adding guests',
|
||||||
|
condition: {
|
||||||
|
field: 'operation',
|
||||||
|
value: ['calcom_create_event_type', 'calcom_update_event_type'],
|
||||||
|
},
|
||||||
|
mode: 'advanced',
|
||||||
|
},
|
||||||
|
|
||||||
|
// === Schedule fields ===
|
||||||
|
{
|
||||||
|
id: 'scheduleId',
|
||||||
|
title: 'Schedule ID',
|
||||||
|
type: 'short-input',
|
||||||
|
placeholder: 'Enter schedule ID',
|
||||||
|
condition: {
|
||||||
|
field: 'operation',
|
||||||
|
value: ['calcom_get_schedule', 'calcom_update_schedule', 'calcom_delete_schedule'],
|
||||||
|
},
|
||||||
|
required: {
|
||||||
|
field: 'operation',
|
||||||
|
value: ['calcom_get_schedule', 'calcom_update_schedule', 'calcom_delete_schedule'],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'name',
|
||||||
|
title: 'Name',
|
||||||
|
type: 'short-input',
|
||||||
|
placeholder: 'Schedule name (e.g., Working Hours)',
|
||||||
|
condition: {
|
||||||
|
field: 'operation',
|
||||||
|
value: ['calcom_create_schedule', 'calcom_update_schedule'],
|
||||||
|
},
|
||||||
|
required: { field: 'operation', value: 'calcom_create_schedule' },
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'timeZone',
|
||||||
|
title: 'Time Zone',
|
||||||
|
type: 'short-input',
|
||||||
|
placeholder: 'e.g., America/New_York',
|
||||||
|
condition: {
|
||||||
|
field: 'operation',
|
||||||
|
value: ['calcom_create_schedule', 'calcom_update_schedule', 'calcom_get_slots'],
|
||||||
|
},
|
||||||
|
required: { field: 'operation', value: 'calcom_create_schedule' },
|
||||||
|
wandConfig: {
|
||||||
|
enabled: true,
|
||||||
|
prompt: `Convert the user's timezone description to a valid IANA timezone identifier.
|
||||||
|
|
||||||
|
Common examples:
|
||||||
|
- "New York" or "Eastern" -> America/New_York
|
||||||
|
- "Los Angeles" or "Pacific" -> America/Los_Angeles
|
||||||
|
- "Chicago" or "Central" -> America/Chicago
|
||||||
|
- "London" -> Europe/London
|
||||||
|
- "Paris" -> Europe/Paris
|
||||||
|
- "Tokyo" -> Asia/Tokyo
|
||||||
|
- "Sydney" -> Australia/Sydney
|
||||||
|
- "UTC" or "GMT" -> UTC
|
||||||
|
|
||||||
|
Return ONLY the IANA timezone string - no explanations or quotes.`,
|
||||||
|
placeholder: 'Describe the timezone (e.g., "New York", "Pacific time")...',
|
||||||
|
generationType: 'timezone',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'isDefault',
|
||||||
|
title: 'Default Schedule',
|
||||||
|
type: 'switch',
|
||||||
|
description: 'Set as the default schedule',
|
||||||
|
condition: {
|
||||||
|
field: 'operation',
|
||||||
|
value: ['calcom_create_schedule', 'calcom_update_schedule'],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'availability',
|
||||||
|
title: 'Availability',
|
||||||
|
type: 'code',
|
||||||
|
language: 'json',
|
||||||
|
placeholder: `[
|
||||||
|
{
|
||||||
|
"days": ["Monday", "Tuesday", "Wednesday", "Thursday", "Friday"],
|
||||||
|
"startTime": "09:00",
|
||||||
|
"endTime": "17:00"
|
||||||
|
}
|
||||||
|
]`,
|
||||||
|
condition: {
|
||||||
|
field: 'operation',
|
||||||
|
value: ['calcom_create_schedule', 'calcom_update_schedule'],
|
||||||
|
},
|
||||||
|
wandConfig: {
|
||||||
|
enabled: true,
|
||||||
|
prompt: `Generate a Cal.com availability JSON array based on the user's description.
|
||||||
|
|
||||||
|
Each availability object has:
|
||||||
|
- days: Array of weekday names (Monday, Tuesday, Wednesday, Thursday, Friday, Saturday, Sunday)
|
||||||
|
- startTime: HH:MM format (24-hour)
|
||||||
|
- endTime: HH:MM format (24-hour)
|
||||||
|
|
||||||
|
Example for "9-5 weekdays":
|
||||||
|
[{"days": ["Monday", "Tuesday", "Wednesday", "Thursday", "Friday"], "startTime": "09:00", "endTime": "17:00"}]
|
||||||
|
|
||||||
|
Example for "mornings only, Monday and Wednesday":
|
||||||
|
[{"days": ["Monday", "Wednesday"], "startTime": "08:00", "endTime": "12:00"}]
|
||||||
|
|
||||||
|
Return ONLY valid JSON - no explanations.`,
|
||||||
|
placeholder: 'Describe your availability (e.g., "9-5 weekdays")...',
|
||||||
|
generationType: 'json-object',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
// === Slots fields ===
|
||||||
|
{
|
||||||
|
id: 'eventTypeSlug',
|
||||||
|
title: 'Event Type Slug',
|
||||||
|
type: 'short-input',
|
||||||
|
placeholder: 'Event type slug (alternative to ID)',
|
||||||
|
condition: { field: 'operation', value: 'calcom_get_slots' },
|
||||||
|
mode: 'advanced',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'username',
|
||||||
|
title: 'Username',
|
||||||
|
type: 'short-input',
|
||||||
|
placeholder: 'Cal.com username (required with slug)',
|
||||||
|
condition: { field: 'operation', value: 'calcom_get_slots' },
|
||||||
|
mode: 'advanced',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'duration',
|
||||||
|
title: 'Duration (minutes)',
|
||||||
|
type: 'short-input',
|
||||||
|
placeholder: 'Slot duration in minutes',
|
||||||
|
condition: { field: 'operation', value: 'calcom_get_slots' },
|
||||||
|
mode: 'advanced',
|
||||||
|
},
|
||||||
|
|
||||||
|
// === List Event Types sorting ===
|
||||||
|
{
|
||||||
|
id: 'sortCreatedAt',
|
||||||
|
title: 'Sort by Created',
|
||||||
|
type: 'dropdown',
|
||||||
|
options: [
|
||||||
|
{ label: 'None', id: '' },
|
||||||
|
{ label: 'Ascending', id: 'asc' },
|
||||||
|
{ label: 'Descending', id: 'desc' },
|
||||||
|
],
|
||||||
|
condition: { field: 'operation', value: 'calcom_list_event_types' },
|
||||||
|
mode: 'advanced',
|
||||||
|
},
|
||||||
|
// Trigger SubBlocks
|
||||||
|
...getTrigger('calcom_booking_created').subBlocks,
|
||||||
|
...getTrigger('calcom_booking_cancelled').subBlocks,
|
||||||
|
...getTrigger('calcom_booking_rescheduled').subBlocks,
|
||||||
|
...getTrigger('calcom_booking_requested').subBlocks,
|
||||||
|
...getTrigger('calcom_booking_rejected').subBlocks,
|
||||||
|
...getTrigger('calcom_booking_paid').subBlocks,
|
||||||
|
...getTrigger('calcom_meeting_ended').subBlocks,
|
||||||
|
...getTrigger('calcom_recording_ready').subBlocks,
|
||||||
|
...getTrigger('calcom_webhook').subBlocks,
|
||||||
|
],
|
||||||
|
tools: {
|
||||||
|
access: [
|
||||||
|
'calcom_create_booking',
|
||||||
|
'calcom_get_booking',
|
||||||
|
'calcom_list_bookings',
|
||||||
|
'calcom_cancel_booking',
|
||||||
|
'calcom_reschedule_booking',
|
||||||
|
'calcom_confirm_booking',
|
||||||
|
'calcom_decline_booking',
|
||||||
|
'calcom_create_event_type',
|
||||||
|
'calcom_get_event_type',
|
||||||
|
'calcom_list_event_types',
|
||||||
|
'calcom_update_event_type',
|
||||||
|
'calcom_delete_event_type',
|
||||||
|
'calcom_create_schedule',
|
||||||
|
'calcom_get_schedule',
|
||||||
|
'calcom_list_schedules',
|
||||||
|
'calcom_update_schedule',
|
||||||
|
'calcom_delete_schedule',
|
||||||
|
'calcom_get_default_schedule',
|
||||||
|
'calcom_get_slots',
|
||||||
|
],
|
||||||
|
config: {
|
||||||
|
tool: (params) => params.operation || 'calcom_list_bookings',
|
||||||
|
params: (params) => {
|
||||||
|
const {
|
||||||
|
operation,
|
||||||
|
credential,
|
||||||
|
attendeeName,
|
||||||
|
attendeeEmail,
|
||||||
|
attendeeTimeZone,
|
||||||
|
attendeePhone,
|
||||||
|
guests,
|
||||||
|
start,
|
||||||
|
end,
|
||||||
|
bookingUid,
|
||||||
|
cancellationReason,
|
||||||
|
reschedulingReason,
|
||||||
|
bookingStatus,
|
||||||
|
lengthInMinutes,
|
||||||
|
eventTypeIdParam,
|
||||||
|
eventTypeId,
|
||||||
|
eventLength,
|
||||||
|
eventTypeScheduleId,
|
||||||
|
slotInterval,
|
||||||
|
minimumBookingNotice,
|
||||||
|
beforeEventBuffer,
|
||||||
|
afterEventBuffer,
|
||||||
|
disableGuests,
|
||||||
|
name,
|
||||||
|
scheduleId,
|
||||||
|
isDefault,
|
||||||
|
eventTypeSlug,
|
||||||
|
username,
|
||||||
|
duration,
|
||||||
|
metadata,
|
||||||
|
availability,
|
||||||
|
...rest
|
||||||
|
} = params
|
||||||
|
|
||||||
|
const result: Record<string, unknown> = {}
|
||||||
|
|
||||||
|
const toNumber = (value: unknown): number | undefined => {
|
||||||
|
if (value === undefined || value === null || value === '') {
|
||||||
|
return undefined
|
||||||
|
}
|
||||||
|
const num = Number(value)
|
||||||
|
return Number.isNaN(num) ? undefined : num
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (operation) {
|
||||||
|
case 'calcom_create_booking':
|
||||||
|
result.attendee = {
|
||||||
|
name: attendeeName,
|
||||||
|
...(attendeeEmail && { email: attendeeEmail }),
|
||||||
|
timeZone: attendeeTimeZone,
|
||||||
|
...(attendeePhone && { phoneNumber: attendeePhone }),
|
||||||
|
}
|
||||||
|
{
|
||||||
|
const eventTypeIdNum = toNumber(eventTypeId)
|
||||||
|
if (eventTypeIdNum !== undefined) result.eventTypeId = eventTypeIdNum
|
||||||
|
}
|
||||||
|
if (start) result.start = start
|
||||||
|
if (end) result.end = end
|
||||||
|
if (guests) result.guests = guests.split(',').map((g: string) => g.trim())
|
||||||
|
{
|
||||||
|
const lengthNum = toNumber(lengthInMinutes)
|
||||||
|
if (lengthNum !== undefined) result.lengthInMinutes = lengthNum
|
||||||
|
}
|
||||||
|
if (metadata) {
|
||||||
|
try {
|
||||||
|
result.metadata = typeof metadata === 'string' ? JSON.parse(metadata) : metadata
|
||||||
|
} catch {
|
||||||
|
throw new Error('Invalid JSON for metadata')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break
|
||||||
|
|
||||||
|
case 'calcom_cancel_booking':
|
||||||
|
if (bookingUid) result.bookingUid = bookingUid
|
||||||
|
if (cancellationReason) result.cancellationReason = cancellationReason
|
||||||
|
break
|
||||||
|
|
||||||
|
case 'calcom_reschedule_booking':
|
||||||
|
if (bookingUid) result.bookingUid = bookingUid
|
||||||
|
if (start) result.start = start
|
||||||
|
if (reschedulingReason) result.reschedulingReason = reschedulingReason
|
||||||
|
break
|
||||||
|
|
||||||
|
case 'calcom_list_bookings':
|
||||||
|
if (bookingStatus) result.status = bookingStatus
|
||||||
|
break
|
||||||
|
|
||||||
|
case 'calcom_create_event_type':
|
||||||
|
case 'calcom_update_event_type':
|
||||||
|
{
|
||||||
|
if (operation === 'calcom_update_event_type') {
|
||||||
|
const eventTypeIdNum = toNumber(eventTypeIdParam)
|
||||||
|
if (eventTypeIdNum !== undefined) result.eventTypeId = eventTypeIdNum
|
||||||
|
}
|
||||||
|
const lengthNum = toNumber(eventLength)
|
||||||
|
if (lengthNum !== undefined) result.lengthInMinutes = lengthNum
|
||||||
|
const scheduleIdNum = toNumber(eventTypeScheduleId)
|
||||||
|
if (scheduleIdNum !== undefined) result.scheduleId = scheduleIdNum
|
||||||
|
const slotIntervalNum = toNumber(slotInterval)
|
||||||
|
if (slotIntervalNum !== undefined) result.slotInterval = slotIntervalNum
|
||||||
|
const minNoticeNum = toNumber(minimumBookingNotice)
|
||||||
|
if (minNoticeNum !== undefined) result.minimumBookingNotice = minNoticeNum
|
||||||
|
const beforeBufferNum = toNumber(beforeEventBuffer)
|
||||||
|
if (beforeBufferNum !== undefined) result.beforeEventBuffer = beforeBufferNum
|
||||||
|
const afterBufferNum = toNumber(afterEventBuffer)
|
||||||
|
if (afterBufferNum !== undefined) result.afterEventBuffer = afterBufferNum
|
||||||
|
if (disableGuests !== undefined && disableGuests !== null) {
|
||||||
|
result.disableGuests = disableGuests
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break
|
||||||
|
|
||||||
|
case 'calcom_get_event_type':
|
||||||
|
case 'calcom_delete_event_type':
|
||||||
|
{
|
||||||
|
const eventTypeIdNum = toNumber(eventTypeIdParam)
|
||||||
|
if (eventTypeIdNum !== undefined) result.eventTypeId = eventTypeIdNum
|
||||||
|
}
|
||||||
|
break
|
||||||
|
|
||||||
|
case 'calcom_create_schedule':
|
||||||
|
if (name) result.name = name
|
||||||
|
result.isDefault = isDefault === true
|
||||||
|
if (availability) {
|
||||||
|
try {
|
||||||
|
result.availability =
|
||||||
|
typeof availability === 'string' ? JSON.parse(availability) : availability
|
||||||
|
} catch {
|
||||||
|
throw new Error('Invalid JSON for availability')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break
|
||||||
|
|
||||||
|
case 'calcom_get_schedule':
|
||||||
|
case 'calcom_update_schedule':
|
||||||
|
case 'calcom_delete_schedule':
|
||||||
|
{
|
||||||
|
const scheduleIdNum = toNumber(scheduleId)
|
||||||
|
if (scheduleIdNum !== undefined) result.scheduleId = scheduleIdNum
|
||||||
|
}
|
||||||
|
if (operation === 'calcom_update_schedule') {
|
||||||
|
if (name) result.name = name
|
||||||
|
if (isDefault !== undefined && isDefault !== null) result.isDefault = isDefault
|
||||||
|
if (availability) {
|
||||||
|
try {
|
||||||
|
result.availability =
|
||||||
|
typeof availability === 'string' ? JSON.parse(availability) : availability
|
||||||
|
} catch {
|
||||||
|
throw new Error('Invalid JSON for availability')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break
|
||||||
|
|
||||||
|
case 'calcom_get_slots':
|
||||||
|
{
|
||||||
|
const eventTypeIdNum = toNumber(eventTypeId)
|
||||||
|
const hasEventTypeId = eventTypeIdNum !== undefined
|
||||||
|
const hasSlugAndUsername = Boolean(eventTypeSlug) && Boolean(username)
|
||||||
|
|
||||||
|
if (!hasEventTypeId && !hasSlugAndUsername) {
|
||||||
|
throw new Error(
|
||||||
|
'Event Type ID is required. Alternatively, provide both Event Type Slug and Username in advanced mode.'
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hasEventTypeId) result.eventTypeId = eventTypeIdNum
|
||||||
|
}
|
||||||
|
if (eventTypeSlug) result.eventTypeSlug = eventTypeSlug
|
||||||
|
if (username) result.username = username
|
||||||
|
if (start) result.start = start
|
||||||
|
if (end) result.end = end
|
||||||
|
{
|
||||||
|
const durationNum = toNumber(duration)
|
||||||
|
if (durationNum !== undefined) result.duration = durationNum
|
||||||
|
}
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
Object.entries(rest).forEach(([key, value]) => {
|
||||||
|
if (value !== undefined && value !== null && value !== '') {
|
||||||
|
result[key] = value
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
return result
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
inputs: {
|
||||||
|
operation: { type: 'string', description: 'Operation to perform' },
|
||||||
|
credential: { type: 'string', description: 'Cal.com OAuth credential' },
|
||||||
|
eventTypeId: { type: 'number', description: 'Event type ID' },
|
||||||
|
start: { type: 'string', description: 'Start time (ISO 8601)' },
|
||||||
|
end: { type: 'string', description: 'End time (ISO 8601)' },
|
||||||
|
attendeeName: { type: 'string', description: 'Attendee name' },
|
||||||
|
attendeeEmail: { type: 'string', description: 'Attendee email' },
|
||||||
|
attendeeTimeZone: { type: 'string', description: 'Attendee time zone' },
|
||||||
|
attendeePhone: { type: 'string', description: 'Attendee phone number' },
|
||||||
|
guests: { type: 'string', description: 'Comma-separated guest emails' },
|
||||||
|
lengthInMinutes: { type: 'number', description: 'Duration override in minutes' },
|
||||||
|
metadata: { type: 'json', description: 'Custom metadata object' },
|
||||||
|
bookingUid: { type: 'string', description: 'Booking UID' },
|
||||||
|
cancellationReason: { type: 'string', description: 'Reason for cancellation' },
|
||||||
|
reschedulingReason: { type: 'string', description: 'Reason for rescheduling' },
|
||||||
|
bookingStatus: { type: 'string', description: 'Filter by booking status' },
|
||||||
|
eventTypeIdParam: { type: 'number', description: 'Event type ID for get/update/delete' },
|
||||||
|
title: { type: 'string', description: 'Event type title' },
|
||||||
|
slug: { type: 'string', description: 'URL-friendly slug' },
|
||||||
|
eventLength: { type: 'number', description: 'Event duration in minutes' },
|
||||||
|
description: { type: 'string', description: 'Event type description' },
|
||||||
|
slotInterval: { type: 'number', description: 'Minutes between available slots' },
|
||||||
|
minimumBookingNotice: { type: 'number', description: 'Minimum advance notice' },
|
||||||
|
beforeEventBuffer: { type: 'number', description: 'Buffer before event' },
|
||||||
|
afterEventBuffer: { type: 'number', description: 'Buffer after event' },
|
||||||
|
eventTypeScheduleId: { type: 'number', description: 'Schedule ID for event type' },
|
||||||
|
disableGuests: { type: 'boolean', description: 'Disable guest additions' },
|
||||||
|
sortCreatedAt: { type: 'string', description: 'Sort order for event types' },
|
||||||
|
scheduleId: { type: 'number', description: 'Schedule ID' },
|
||||||
|
name: { type: 'string', description: 'Schedule name' },
|
||||||
|
timeZone: { type: 'string', description: 'Time zone' },
|
||||||
|
isDefault: { type: 'boolean', description: 'Set as default schedule' },
|
||||||
|
availability: { type: 'json', description: 'Availability configuration' },
|
||||||
|
eventTypeSlug: { type: 'string', description: 'Event type slug' },
|
||||||
|
username: { type: 'string', description: 'Cal.com username' },
|
||||||
|
duration: { type: 'number', description: 'Slot duration in minutes' },
|
||||||
|
},
|
||||||
|
outputs: {
|
||||||
|
success: { type: 'boolean', description: 'Whether operation succeeded' },
|
||||||
|
bookingUid: { type: 'string', description: 'Booking unique identifier' },
|
||||||
|
bookingId: { type: 'number', description: 'Booking ID' },
|
||||||
|
status: { type: 'string', description: 'Booking or event status' },
|
||||||
|
title: { type: 'string', description: 'Booking or event type title' },
|
||||||
|
startTime: { type: 'string', description: 'Booking start time (ISO 8601)' },
|
||||||
|
endTime: { type: 'string', description: 'Booking end time (ISO 8601)' },
|
||||||
|
attendees: { type: 'json', description: 'List of attendees' },
|
||||||
|
hosts: { type: 'json', description: 'List of hosts' },
|
||||||
|
location: { type: 'string', description: 'Meeting location' },
|
||||||
|
meetingUrl: { type: 'string', description: 'Video meeting URL' },
|
||||||
|
bookings: { type: 'json', description: 'List of bookings' },
|
||||||
|
eventTypes: { type: 'json', description: 'List of event types' },
|
||||||
|
schedules: { type: 'json', description: 'List of schedules' },
|
||||||
|
slots: { type: 'json', description: 'Available time slots' },
|
||||||
|
id: { type: 'number', description: 'Event type or schedule ID' },
|
||||||
|
slug: { type: 'string', description: 'Event type slug' },
|
||||||
|
lengthInMinutes: { type: 'number', description: 'Event duration' },
|
||||||
|
description: { type: 'string', description: 'Event type description' },
|
||||||
|
name: { type: 'string', description: 'Schedule name' },
|
||||||
|
timeZone: { type: 'string', description: 'Schedule time zone' },
|
||||||
|
isDefault: { type: 'boolean', description: 'Whether schedule is default' },
|
||||||
|
availability: { type: 'json', description: 'Availability configuration' },
|
||||||
|
deleted: { type: 'boolean', description: 'Whether deletion succeeded' },
|
||||||
|
message: { type: 'string', description: 'Status or error message' },
|
||||||
|
triggerEvent: { type: 'string', description: 'Webhook event type' },
|
||||||
|
createdAt: { type: 'string', description: 'Webhook event timestamp' },
|
||||||
|
payload: { type: 'json', description: 'Complete webhook payload data' },
|
||||||
|
},
|
||||||
|
triggers: {
|
||||||
|
enabled: true,
|
||||||
|
available: [
|
||||||
|
'calcom_booking_created',
|
||||||
|
'calcom_booking_cancelled',
|
||||||
|
'calcom_booking_rescheduled',
|
||||||
|
'calcom_booking_requested',
|
||||||
|
'calcom_booking_rejected',
|
||||||
|
'calcom_booking_paid',
|
||||||
|
'calcom_meeting_ended',
|
||||||
|
'calcom_recording_ready',
|
||||||
|
'calcom_webhook',
|
||||||
|
],
|
||||||
|
},
|
||||||
|
}
|
||||||
200
apps/sim/blocks/blocks/similarweb.ts
Normal file
200
apps/sim/blocks/blocks/similarweb.ts
Normal file
@@ -0,0 +1,200 @@
|
|||||||
|
import { SimilarwebIcon } from '@/components/icons'
|
||||||
|
import type { BlockConfig } from '@/blocks/types'
|
||||||
|
import { AuthMode } from '@/blocks/types'
|
||||||
|
|
||||||
|
export const SimilarwebBlock: BlockConfig = {
|
||||||
|
type: 'similarweb',
|
||||||
|
name: 'Similarweb',
|
||||||
|
description: 'Website traffic and analytics data',
|
||||||
|
longDescription:
|
||||||
|
'Access comprehensive website analytics including traffic estimates, engagement metrics, rankings, and traffic sources using the Similarweb API.',
|
||||||
|
docsLink: 'https://developers.similarweb.com/docs/similarweb-web-traffic-api',
|
||||||
|
category: 'tools',
|
||||||
|
bgColor: '#000922',
|
||||||
|
icon: SimilarwebIcon,
|
||||||
|
authMode: AuthMode.ApiKey,
|
||||||
|
|
||||||
|
subBlocks: [
|
||||||
|
{
|
||||||
|
id: 'operation',
|
||||||
|
title: 'Operation',
|
||||||
|
type: 'dropdown',
|
||||||
|
options: [
|
||||||
|
{ label: 'Website Overview', id: 'similarweb_website_overview' },
|
||||||
|
{ label: 'Traffic Visits', id: 'similarweb_traffic_visits' },
|
||||||
|
{ label: 'Bounce Rate', id: 'similarweb_bounce_rate' },
|
||||||
|
{ label: 'Pages Per Visit', id: 'similarweb_pages_per_visit' },
|
||||||
|
{ label: 'Visit Duration (Desktop)', id: 'similarweb_visit_duration' },
|
||||||
|
],
|
||||||
|
value: () => 'similarweb_website_overview',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'domain',
|
||||||
|
title: 'Domain',
|
||||||
|
type: 'short-input',
|
||||||
|
placeholder: 'example.com',
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'country',
|
||||||
|
title: 'Country',
|
||||||
|
type: 'dropdown',
|
||||||
|
options: [
|
||||||
|
{ label: 'Worldwide', id: 'world' },
|
||||||
|
{ label: 'United States', id: 'us' },
|
||||||
|
{ label: 'United Kingdom', id: 'gb' },
|
||||||
|
{ label: 'Germany', id: 'de' },
|
||||||
|
{ label: 'France', id: 'fr' },
|
||||||
|
{ label: 'Spain', id: 'es' },
|
||||||
|
{ label: 'Italy', id: 'it' },
|
||||||
|
{ label: 'Canada', id: 'ca' },
|
||||||
|
{ label: 'Australia', id: 'au' },
|
||||||
|
{ label: 'Japan', id: 'jp' },
|
||||||
|
{ label: 'Brazil', id: 'br' },
|
||||||
|
{ label: 'India', id: 'in' },
|
||||||
|
{ label: 'Netherlands', id: 'nl' },
|
||||||
|
{ label: 'Poland', id: 'pl' },
|
||||||
|
{ label: 'Russia', id: 'ru' },
|
||||||
|
{ label: 'Mexico', id: 'mx' },
|
||||||
|
{ label: 'South Korea', id: 'kr' },
|
||||||
|
{ label: 'China', id: 'cn' },
|
||||||
|
],
|
||||||
|
value: () => 'world',
|
||||||
|
condition: {
|
||||||
|
field: 'operation',
|
||||||
|
value: 'similarweb_website_overview',
|
||||||
|
not: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'granularity',
|
||||||
|
title: 'Granularity',
|
||||||
|
type: 'dropdown',
|
||||||
|
options: [
|
||||||
|
{ label: 'Monthly', id: 'monthly' },
|
||||||
|
{ label: 'Weekly', id: 'weekly' },
|
||||||
|
{ label: 'Daily', id: 'daily' },
|
||||||
|
],
|
||||||
|
value: () => 'monthly',
|
||||||
|
condition: {
|
||||||
|
field: 'operation',
|
||||||
|
value: 'similarweb_website_overview',
|
||||||
|
not: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'startDate',
|
||||||
|
title: 'Start Date',
|
||||||
|
type: 'short-input',
|
||||||
|
placeholder: 'YYYY-MM (e.g., 2024-01)',
|
||||||
|
condition: {
|
||||||
|
field: 'operation',
|
||||||
|
value: 'similarweb_website_overview',
|
||||||
|
not: true,
|
||||||
|
},
|
||||||
|
wandConfig: {
|
||||||
|
enabled: true,
|
||||||
|
prompt: `Generate a date in YYYY-MM format based on the user's description.
|
||||||
|
Examples:
|
||||||
|
- "this month" -> Current month in YYYY-MM format
|
||||||
|
- "last month" -> Previous month in YYYY-MM format
|
||||||
|
- "3 months ago" -> Date 3 months ago in YYYY-MM format
|
||||||
|
- "beginning of year" -> January of current year (e.g., 2024-01)
|
||||||
|
|
||||||
|
Return ONLY the date string in YYYY-MM format - no explanations, no quotes, no extra text.`,
|
||||||
|
placeholder: 'Describe the start date (e.g., "3 months ago", "last month")...',
|
||||||
|
generationType: 'timestamp',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'endDate',
|
||||||
|
title: 'End Date',
|
||||||
|
type: 'short-input',
|
||||||
|
placeholder: 'YYYY-MM (e.g., 2024-12)',
|
||||||
|
condition: {
|
||||||
|
field: 'operation',
|
||||||
|
value: 'similarweb_website_overview',
|
||||||
|
not: true,
|
||||||
|
},
|
||||||
|
wandConfig: {
|
||||||
|
enabled: true,
|
||||||
|
prompt: `Generate a date in YYYY-MM format based on the user's description.
|
||||||
|
Examples:
|
||||||
|
- "this month" -> Current month in YYYY-MM format
|
||||||
|
- "last month" -> Previous month in YYYY-MM format
|
||||||
|
- "now" -> Current month in YYYY-MM format
|
||||||
|
|
||||||
|
Return ONLY the date string in YYYY-MM format - no explanations, no quotes, no extra text.`,
|
||||||
|
placeholder: 'Describe the end date (e.g., "this month", "now")...',
|
||||||
|
generationType: 'timestamp',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'mainDomainOnly',
|
||||||
|
title: 'Main Domain Only',
|
||||||
|
type: 'switch',
|
||||||
|
condition: {
|
||||||
|
field: 'operation',
|
||||||
|
value: 'similarweb_website_overview',
|
||||||
|
not: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'apiKey',
|
||||||
|
title: 'API Key',
|
||||||
|
type: 'short-input',
|
||||||
|
placeholder: 'Enter your Similarweb API key',
|
||||||
|
password: true,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
|
||||||
|
tools: {
|
||||||
|
access: [
|
||||||
|
'similarweb_website_overview',
|
||||||
|
'similarweb_traffic_visits',
|
||||||
|
'similarweb_bounce_rate',
|
||||||
|
'similarweb_pages_per_visit',
|
||||||
|
'similarweb_visit_duration',
|
||||||
|
],
|
||||||
|
config: {
|
||||||
|
tool: (params) => params.operation,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
inputs: {
|
||||||
|
operation: { type: 'string', description: 'Operation to perform' },
|
||||||
|
domain: { type: 'string', description: 'Website domain to analyze' },
|
||||||
|
apiKey: { type: 'string', description: 'Similarweb API key' },
|
||||||
|
country: { type: 'string', description: '2-letter ISO country code or "world"' },
|
||||||
|
granularity: { type: 'string', description: 'Data granularity (daily, weekly, monthly)' },
|
||||||
|
startDate: { type: 'string', description: 'Start date in YYYY-MM format' },
|
||||||
|
endDate: { type: 'string', description: 'End date in YYYY-MM format' },
|
||||||
|
mainDomainOnly: { type: 'boolean', description: 'Exclude subdomains from results' },
|
||||||
|
},
|
||||||
|
|
||||||
|
outputs: {
|
||||||
|
// Website Overview outputs
|
||||||
|
siteName: { type: 'string', description: 'Website name' },
|
||||||
|
description: { type: 'string', description: 'Website description' },
|
||||||
|
globalRank: { type: 'number', description: 'Global traffic rank' },
|
||||||
|
countryRank: { type: 'number', description: 'Country traffic rank' },
|
||||||
|
categoryRank: { type: 'number', description: 'Category traffic rank' },
|
||||||
|
category: { type: 'string', description: 'Website category' },
|
||||||
|
monthlyVisits: { type: 'number', description: 'Estimated monthly visits' },
|
||||||
|
engagementVisitDuration: { type: 'number', description: 'Average visit duration (seconds)' },
|
||||||
|
engagementPagesPerVisit: { type: 'number', description: 'Average pages per visit' },
|
||||||
|
engagementBounceRate: { type: 'number', description: 'Bounce rate (0-1)' },
|
||||||
|
topCountries: { type: 'json', description: 'Top countries by traffic share' },
|
||||||
|
trafficSources: { type: 'json', description: 'Traffic source breakdown' },
|
||||||
|
// Time series outputs
|
||||||
|
domain: { type: 'string', description: 'Analyzed domain' },
|
||||||
|
country: { type: 'string', description: 'Country filter applied' },
|
||||||
|
granularity: { type: 'string', description: 'Data granularity' },
|
||||||
|
lastUpdated: { type: 'string', description: 'Data last updated timestamp' },
|
||||||
|
visits: { type: 'json', description: 'Visit data over time' },
|
||||||
|
bounceRate: { type: 'json', description: 'Bounce rate data over time' },
|
||||||
|
pagesPerVisit: { type: 'json', description: 'Pages per visit data over time' },
|
||||||
|
averageVisitDuration: { type: 'json', description: 'Desktop visit duration data over time' },
|
||||||
|
},
|
||||||
|
}
|
||||||
@@ -9,6 +9,7 @@ import { ApolloBlock } from '@/blocks/blocks/apollo'
|
|||||||
import { ArxivBlock } from '@/blocks/blocks/arxiv'
|
import { ArxivBlock } from '@/blocks/blocks/arxiv'
|
||||||
import { AsanaBlock } from '@/blocks/blocks/asana'
|
import { AsanaBlock } from '@/blocks/blocks/asana'
|
||||||
import { BrowserUseBlock } from '@/blocks/blocks/browser_use'
|
import { BrowserUseBlock } from '@/blocks/blocks/browser_use'
|
||||||
|
import { CalComBlock } from '@/blocks/blocks/calcom'
|
||||||
import { CalendlyBlock } from '@/blocks/blocks/calendly'
|
import { CalendlyBlock } from '@/blocks/blocks/calendly'
|
||||||
import { ChatTriggerBlock } from '@/blocks/blocks/chat_trigger'
|
import { ChatTriggerBlock } from '@/blocks/blocks/chat_trigger'
|
||||||
import { CirclebackBlock } from '@/blocks/blocks/circleback'
|
import { CirclebackBlock } from '@/blocks/blocks/circleback'
|
||||||
@@ -111,6 +112,7 @@ import { ServiceNowBlock } from '@/blocks/blocks/servicenow'
|
|||||||
import { SftpBlock } from '@/blocks/blocks/sftp'
|
import { SftpBlock } from '@/blocks/blocks/sftp'
|
||||||
import { SharepointBlock } from '@/blocks/blocks/sharepoint'
|
import { SharepointBlock } from '@/blocks/blocks/sharepoint'
|
||||||
import { ShopifyBlock } from '@/blocks/blocks/shopify'
|
import { ShopifyBlock } from '@/blocks/blocks/shopify'
|
||||||
|
import { SimilarwebBlock } from '@/blocks/blocks/similarweb'
|
||||||
import { SlackBlock } from '@/blocks/blocks/slack'
|
import { SlackBlock } from '@/blocks/blocks/slack'
|
||||||
import { SmtpBlock } from '@/blocks/blocks/smtp'
|
import { SmtpBlock } from '@/blocks/blocks/smtp'
|
||||||
import { SpotifyBlock } from '@/blocks/blocks/spotify'
|
import { SpotifyBlock } from '@/blocks/blocks/spotify'
|
||||||
@@ -165,6 +167,7 @@ export const registry: Record<string, BlockConfig> = {
|
|||||||
arxiv: ArxivBlock,
|
arxiv: ArxivBlock,
|
||||||
asana: AsanaBlock,
|
asana: AsanaBlock,
|
||||||
browser_use: BrowserUseBlock,
|
browser_use: BrowserUseBlock,
|
||||||
|
calcom: CalComBlock,
|
||||||
calendly: CalendlyBlock,
|
calendly: CalendlyBlock,
|
||||||
chat_trigger: ChatTriggerBlock,
|
chat_trigger: ChatTriggerBlock,
|
||||||
circleback: CirclebackBlock,
|
circleback: CirclebackBlock,
|
||||||
@@ -280,6 +283,7 @@ export const registry: Record<string, BlockConfig> = {
|
|||||||
sftp: SftpBlock,
|
sftp: SftpBlock,
|
||||||
sharepoint: SharepointBlock,
|
sharepoint: SharepointBlock,
|
||||||
shopify: ShopifyBlock,
|
shopify: ShopifyBlock,
|
||||||
|
similarweb: SimilarwebBlock,
|
||||||
slack: SlackBlock,
|
slack: SlackBlock,
|
||||||
smtp: SmtpBlock,
|
smtp: SmtpBlock,
|
||||||
spotify: SpotifyBlock,
|
spotify: SpotifyBlock,
|
||||||
|
|||||||
@@ -38,6 +38,7 @@ export type GenerationType =
|
|||||||
| 'neo4j-cypher'
|
| 'neo4j-cypher'
|
||||||
| 'neo4j-parameters'
|
| 'neo4j-parameters'
|
||||||
| 'timestamp'
|
| 'timestamp'
|
||||||
|
| 'timezone'
|
||||||
|
|
||||||
export type SubBlockType =
|
export type SubBlockType =
|
||||||
| 'short-input' // Single line input
|
| 'short-input' // Single line input
|
||||||
|
|||||||
@@ -513,18 +513,10 @@ const PopoverContent = React.forwardRef<
|
|||||||
return () => window.removeEventListener('keydown', handleKeyDown, true)
|
return () => window.removeEventListener('keydown', handleKeyDown, true)
|
||||||
}, [context])
|
}, [context])
|
||||||
|
|
||||||
React.useEffect(() => {
|
// Note: scrollIntoView for keyboard navigation is intentionally disabled here.
|
||||||
const content = contentRef.current
|
// Components using Popover (like TagDropdown) should handle their own scroll
|
||||||
if (!content || !context?.isKeyboardNav || context.selectedIndex < 0) return
|
// management to avoid conflicts between the popover's internal selection index
|
||||||
|
// and the component's custom navigation state.
|
||||||
const items = content.querySelectorAll<HTMLElement>(
|
|
||||||
'[role="menuitem"]:not([aria-disabled="true"])'
|
|
||||||
)
|
|
||||||
const selectedItem = items[context.selectedIndex]
|
|
||||||
if (selectedItem) {
|
|
||||||
selectedItem.scrollIntoView({ block: 'nearest', behavior: 'smooth' })
|
|
||||||
}
|
|
||||||
}, [context?.selectedIndex, context?.isKeyboardNav])
|
|
||||||
|
|
||||||
const hasUserWidthConstraint =
|
const hasUserWidthConstraint =
|
||||||
maxWidth !== undefined ||
|
maxWidth !== undefined ||
|
||||||
@@ -715,7 +707,8 @@ const PopoverItem = React.forwardRef<HTMLDivElement, PopoverItemProps>(
|
|||||||
|
|
||||||
const handleMouseEnter = (e: React.MouseEvent<HTMLDivElement>) => {
|
const handleMouseEnter = (e: React.MouseEvent<HTMLDivElement>) => {
|
||||||
context?.setLastHoveredItem(null)
|
context?.setLastHoveredItem(null)
|
||||||
if (itemIndex >= 0 && context) {
|
// Don't update selection during keyboard navigation to prevent scroll jumps
|
||||||
|
if (itemIndex >= 0 && context && !context.isKeyboardNav) {
|
||||||
context.setSelectedIndex(itemIndex)
|
context.setSelectedIndex(itemIndex)
|
||||||
}
|
}
|
||||||
onMouseEnter?.(e)
|
onMouseEnter?.(e)
|
||||||
@@ -896,7 +889,8 @@ const PopoverFolder = React.forwardRef<HTMLDivElement, PopoverFolderProps>(
|
|||||||
}
|
}
|
||||||
|
|
||||||
const handleMouseEnter = () => {
|
const handleMouseEnter = () => {
|
||||||
if (itemIndex >= 0) {
|
// Don't update selection during keyboard navigation to prevent scroll jumps
|
||||||
|
if (itemIndex >= 0 && !isKeyboardNav) {
|
||||||
setSelectedIndex(itemIndex)
|
setSelectedIndex(itemIndex)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -5113,3 +5113,60 @@ export function PulseIcon(props: SVGProps<SVGSVGElement>) {
|
|||||||
</svg>
|
</svg>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function SimilarwebIcon(props: SVGProps<SVGSVGElement>) {
|
||||||
|
return (
|
||||||
|
<svg
|
||||||
|
{...props}
|
||||||
|
role='img'
|
||||||
|
viewBox='0 0 24 24'
|
||||||
|
xmlns='http://www.w3.org/2000/svg'
|
||||||
|
height='24'
|
||||||
|
width='24'
|
||||||
|
>
|
||||||
|
<path
|
||||||
|
d='M22.099 5.781c-1.283 -2 -3.14 -3.67 -5.27 -4.52l-0.63 -0.213a7.433 7.433 0 0 0 -2.15 -0.331c-2.307 0.01 -4.175 1.92 -4.175 4.275a4.3 4.3 0 0 0 0.867 2.602l-0.26 -0.342c0.124 0.186 0.26 0.37 0.417 0.556 0.663 0.802 1.604 1.635 2.822 2.58 2.999 2.32 4.943 4.378 5.104 6.93 0.038 0.344 0.062 0.696 0.062 1.051 0 1.297 -0.283 2.67 -0.764 3.635h0.005s-0.207 0.377 -0.077 0.487c0.066 0.057 0.21 0.1 0.46 -0.053a12.104 12.104 0 0 0 3.4 -3.33 12.111 12.111 0 0 0 2.088 -6.635 12.098 12.098 0 0 0 -1.9 -6.692zm-9.096 8.718 -1.878 -1.55c-3.934 -2.87 -5.98 -5.966 -4.859 -9.783a8.73 8.73 0 0 1 0.37 -1.016v-0.004s0.278 -0.583 -0.327 -0.295a12.067 12.067 0 0 0 -6.292 9.975 12.11 12.11 0 0 0 2.053 7.421 9.394 9.394 0 0 0 2.154 2.168H4.22c4.148 3.053 7.706 1.446 7.706 1.446h0.003a4.847 4.847 0 0 0 2.962 -4.492 4.855 4.855 0 0 0 -1.889 -3.87z'
|
||||||
|
fill='currentColor'
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export function CalComIcon(props: SVGProps<SVGSVGElement>) {
|
||||||
|
return (
|
||||||
|
<svg
|
||||||
|
{...props}
|
||||||
|
width='101'
|
||||||
|
height='22'
|
||||||
|
viewBox='0 0 101 22'
|
||||||
|
fill='currentColor'
|
||||||
|
xmlns='http://www.w3.org/2000/svg'
|
||||||
|
>
|
||||||
|
<path
|
||||||
|
d='M10.0582 20.817C4.32115 20.817 0 16.2763 0 10.6704C0 5.04589 4.1005 0.467773 10.0582 0.467773C13.2209 0.467773 15.409 1.43945 17.1191 3.66311L14.3609 5.96151C13.2025 4.72822 11.805 4.11158 10.0582 4.11158C6.17833 4.11158 4.04533 7.08268 4.04533 10.6704C4.04533 14.2582 6.38059 17.1732 10.0582 17.1732C11.7866 17.1732 13.2577 16.5566 14.4161 15.3233L17.1375 17.7151C15.501 19.8453 13.2577 20.817 10.0582 20.817Z'
|
||||||
|
fill='#292929'
|
||||||
|
/>
|
||||||
|
<path
|
||||||
|
d='M29.0161 5.88601H32.7304V20.4612H29.0161V18.331C28.2438 19.8446 26.9566 20.8536 24.4927 20.8536C20.5577 20.8536 17.4133 17.4341 17.4133 13.2297C17.4133 9.02528 20.5577 5.60571 24.4927 5.60571C26.9383 5.60571 28.2438 6.61477 29.0161 8.12835V5.88601ZM29.1264 13.2297C29.1264 10.95 27.5634 9.06266 25.0995 9.06266C22.7274 9.06266 21.1828 10.9686 21.1828 13.2297C21.1828 15.4346 22.7274 17.3967 25.0995 17.3967C27.5451 17.3967 29.1264 15.4907 29.1264 13.2297Z'
|
||||||
|
fill='#292929'
|
||||||
|
/>
|
||||||
|
<path d='M35.3599 0H39.0742V20.4427H35.3599V0Z' fill='#292929' />
|
||||||
|
<path
|
||||||
|
d='M40.7291 18.5182C40.7291 17.3223 41.6853 16.3132 42.9908 16.3132C44.2964 16.3132 45.2158 17.3223 45.2158 18.5182C45.2158 19.7515 44.278 20.7605 42.9908 20.7605C41.7037 20.7605 40.7291 19.7515 40.7291 18.5182Z'
|
||||||
|
fill='#292929'
|
||||||
|
/>
|
||||||
|
<path
|
||||||
|
d='M59.4296 18.1068C58.0505 19.7885 55.9543 20.8536 53.4719 20.8536C49.0404 20.8536 45.7858 17.4341 45.7858 13.2297C45.7858 9.02528 49.0404 5.60571 53.4719 5.60571C55.8623 5.60571 57.9402 6.61477 59.3193 8.20309L56.4508 10.6136C55.7336 9.71667 54.7958 9.04397 53.4719 9.04397C51.0999 9.04397 49.5553 10.95 49.5553 13.211C49.5553 15.472 51.0999 17.378 53.4719 17.378C54.9062 17.378 55.8991 16.6306 56.6346 15.6215L59.4296 18.1068Z'
|
||||||
|
fill='#292929'
|
||||||
|
/>
|
||||||
|
<path
|
||||||
|
d='M59.7422 13.2297C59.7422 9.02528 62.9968 5.60571 67.4283 5.60571C71.8598 5.60571 75.1144 9.02528 75.1144 13.2297C75.1144 17.4341 71.8598 20.8536 67.4283 20.8536C62.9968 20.8349 59.7422 17.4341 59.7422 13.2297ZM71.3449 13.2297C71.3449 10.95 69.8003 9.06266 67.4283 9.06266C65.0563 9.04397 63.5117 10.95 63.5117 13.2297C63.5117 15.4907 65.0563 17.3967 67.4283 17.3967C69.8003 17.3967 71.3449 15.4907 71.3449 13.2297Z'
|
||||||
|
fill='#292929'
|
||||||
|
/>
|
||||||
|
<path
|
||||||
|
d='M100.232 11.5482V20.4428H96.518V12.4638C96.518 9.94119 95.3412 8.85739 93.576 8.85739C91.921 8.85739 90.7442 9.67958 90.7442 12.4638V20.4428H87.0299V12.4638C87.0299 9.94119 85.8346 8.85739 84.0878 8.85739C82.4329 8.85739 80.9802 9.67958 80.9802 12.4638V20.4428H77.2659V5.8676H80.9802V7.88571C81.7525 6.31607 83.15 5.53125 85.3014 5.53125C87.3425 5.53125 89.0525 6.5403 89.9903 8.24074C90.9281 6.50293 92.3072 5.53125 94.8079 5.53125C97.8603 5.54994 100.232 7.86702 100.232 11.5482Z'
|
||||||
|
fill='#292929'
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|||||||
@@ -71,7 +71,7 @@ export class BlockExecutor {
|
|||||||
this.callOnBlockStart(ctx, node, block)
|
this.callOnBlockStart(ctx, node, block)
|
||||||
}
|
}
|
||||||
|
|
||||||
const startTime = Date.now()
|
const startTime = performance.now()
|
||||||
let resolvedInputs: Record<string, any> = {}
|
let resolvedInputs: Record<string, any> = {}
|
||||||
|
|
||||||
const nodeMetadata = this.buildNodeMetadata(node)
|
const nodeMetadata = this.buildNodeMetadata(node)
|
||||||
@@ -145,7 +145,7 @@ export class BlockExecutor {
|
|||||||
})) as NormalizedBlockOutput
|
})) as NormalizedBlockOutput
|
||||||
}
|
}
|
||||||
|
|
||||||
const duration = Date.now() - startTime
|
const duration = performance.now() - startTime
|
||||||
|
|
||||||
if (blockLog) {
|
if (blockLog) {
|
||||||
blockLog.endedAt = new Date().toISOString()
|
blockLog.endedAt = new Date().toISOString()
|
||||||
@@ -169,7 +169,9 @@ export class BlockExecutor {
|
|||||||
block,
|
block,
|
||||||
this.sanitizeInputsForLog(resolvedInputs),
|
this.sanitizeInputsForLog(resolvedInputs),
|
||||||
displayOutput,
|
displayOutput,
|
||||||
duration
|
duration,
|
||||||
|
blockLog!.startedAt,
|
||||||
|
blockLog!.endedAt
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -221,7 +223,7 @@ export class BlockExecutor {
|
|||||||
isSentinel: boolean,
|
isSentinel: boolean,
|
||||||
phase: 'input_resolution' | 'execution'
|
phase: 'input_resolution' | 'execution'
|
||||||
): NormalizedBlockOutput {
|
): NormalizedBlockOutput {
|
||||||
const duration = Date.now() - startTime
|
const duration = performance.now() - startTime
|
||||||
const errorMessage = normalizeError(error)
|
const errorMessage = normalizeError(error)
|
||||||
const hasResolvedInputs =
|
const hasResolvedInputs =
|
||||||
resolvedInputs && typeof resolvedInputs === 'object' && Object.keys(resolvedInputs).length > 0
|
resolvedInputs && typeof resolvedInputs === 'object' && Object.keys(resolvedInputs).length > 0
|
||||||
@@ -274,7 +276,9 @@ export class BlockExecutor {
|
|||||||
block,
|
block,
|
||||||
this.sanitizeInputsForLog(input),
|
this.sanitizeInputsForLog(input),
|
||||||
displayOutput,
|
displayOutput,
|
||||||
duration
|
duration,
|
||||||
|
blockLog!.startedAt,
|
||||||
|
blockLog!.endedAt
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -423,7 +427,9 @@ export class BlockExecutor {
|
|||||||
block: SerializedBlock,
|
block: SerializedBlock,
|
||||||
input: Record<string, any>,
|
input: Record<string, any>,
|
||||||
output: NormalizedBlockOutput,
|
output: NormalizedBlockOutput,
|
||||||
duration: number
|
duration: number,
|
||||||
|
startedAt: string,
|
||||||
|
endedAt: string
|
||||||
): void {
|
): void {
|
||||||
const blockId = node.id
|
const blockId = node.id
|
||||||
const blockName = block.metadata?.name ?? blockId
|
const blockName = block.metadata?.name ?? blockId
|
||||||
@@ -440,6 +446,8 @@ export class BlockExecutor {
|
|||||||
input,
|
input,
|
||||||
output,
|
output,
|
||||||
executionTime: duration,
|
executionTime: duration,
|
||||||
|
startedAt,
|
||||||
|
endedAt,
|
||||||
},
|
},
|
||||||
iterationContext
|
iterationContext
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -101,7 +101,7 @@ export class ExecutionEngine {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async run(triggerBlockId?: string): Promise<ExecutionResult> {
|
async run(triggerBlockId?: string): Promise<ExecutionResult> {
|
||||||
const startTime = Date.now()
|
const startTime = performance.now()
|
||||||
try {
|
try {
|
||||||
this.initializeQueue(triggerBlockId)
|
this.initializeQueue(triggerBlockId)
|
||||||
|
|
||||||
@@ -125,8 +125,8 @@ export class ExecutionEngine {
|
|||||||
return this.buildPausedResult(startTime)
|
return this.buildPausedResult(startTime)
|
||||||
}
|
}
|
||||||
|
|
||||||
const endTime = Date.now()
|
const endTime = performance.now()
|
||||||
this.context.metadata.endTime = new Date(endTime).toISOString()
|
this.context.metadata.endTime = new Date().toISOString()
|
||||||
this.context.metadata.duration = endTime - startTime
|
this.context.metadata.duration = endTime - startTime
|
||||||
|
|
||||||
if (this.cancelledFlag) {
|
if (this.cancelledFlag) {
|
||||||
@@ -146,8 +146,8 @@ export class ExecutionEngine {
|
|||||||
metadata: this.context.metadata,
|
metadata: this.context.metadata,
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
const endTime = Date.now()
|
const endTime = performance.now()
|
||||||
this.context.metadata.endTime = new Date(endTime).toISOString()
|
this.context.metadata.endTime = new Date().toISOString()
|
||||||
this.context.metadata.duration = endTime - startTime
|
this.context.metadata.duration = endTime - startTime
|
||||||
|
|
||||||
if (this.cancelledFlag) {
|
if (this.cancelledFlag) {
|
||||||
@@ -433,8 +433,8 @@ export class ExecutionEngine {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private buildPausedResult(startTime: number): ExecutionResult {
|
private buildPausedResult(startTime: number): ExecutionResult {
|
||||||
const endTime = Date.now()
|
const endTime = performance.now()
|
||||||
this.context.metadata.endTime = new Date(endTime).toISOString()
|
this.context.metadata.endTime = new Date().toISOString()
|
||||||
this.context.metadata.duration = endTime - startTime
|
this.context.metadata.duration = endTime - startTime
|
||||||
this.context.metadata.status = 'paused'
|
this.context.metadata.status = 'paused'
|
||||||
|
|
||||||
|
|||||||
@@ -103,7 +103,13 @@ export interface ContextExtensions {
|
|||||||
blockId: string,
|
blockId: string,
|
||||||
blockName: string,
|
blockName: string,
|
||||||
blockType: string,
|
blockType: string,
|
||||||
output: { input?: any; output: NormalizedBlockOutput; executionTime: number },
|
output: {
|
||||||
|
input?: any
|
||||||
|
output: NormalizedBlockOutput
|
||||||
|
executionTime: number
|
||||||
|
startedAt: string
|
||||||
|
endedAt: string
|
||||||
|
},
|
||||||
iterationContext?: IterationContext
|
iterationContext?: IterationContext
|
||||||
) => Promise<void>
|
) => Promise<void>
|
||||||
|
|
||||||
|
|||||||
@@ -281,9 +281,12 @@ export class LoopOrchestrator {
|
|||||||
|
|
||||||
// Emit onBlockComplete for the loop container so the UI can track it
|
// Emit onBlockComplete for the loop container so the UI can track it
|
||||||
if (this.contextExtensions?.onBlockComplete) {
|
if (this.contextExtensions?.onBlockComplete) {
|
||||||
|
const now = new Date().toISOString()
|
||||||
this.contextExtensions.onBlockComplete(loopId, 'Loop', 'loop', {
|
this.contextExtensions.onBlockComplete(loopId, 'Loop', 'loop', {
|
||||||
output,
|
output,
|
||||||
executionTime: DEFAULTS.EXECUTION_TIME,
|
executionTime: DEFAULTS.EXECUTION_TIME,
|
||||||
|
startedAt: now,
|
||||||
|
endedAt: now,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -265,9 +265,12 @@ export class ParallelOrchestrator {
|
|||||||
|
|
||||||
// Emit onBlockComplete for the parallel container so the UI can track it
|
// Emit onBlockComplete for the parallel container so the UI can track it
|
||||||
if (this.contextExtensions?.onBlockComplete) {
|
if (this.contextExtensions?.onBlockComplete) {
|
||||||
|
const now = new Date().toISOString()
|
||||||
this.contextExtensions.onBlockComplete(parallelId, 'Parallel', 'parallel', {
|
this.contextExtensions.onBlockComplete(parallelId, 'Parallel', 'parallel', {
|
||||||
output,
|
output,
|
||||||
executionTime: 0,
|
executionTime: 0,
|
||||||
|
startedAt: now,
|
||||||
|
endedAt: now,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -232,6 +232,8 @@ export function addSubflowErrorLog(
|
|||||||
input: inputData,
|
input: inputData,
|
||||||
output: { error: errorMessage },
|
output: { error: errorMessage },
|
||||||
executionTime: 0,
|
executionTime: 0,
|
||||||
|
startedAt: now,
|
||||||
|
endedAt: now,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user