'use client' import { useCallback, useEffect, useMemo, useState, } from 'react' import { useTranslation } from 'react-i18next' import type { BlockEnum, OnSelectBlock } from '../types' import type { TriggerDefaultValue, TriggerWithProvider } from './types' import StartBlocks from './start-blocks' import TriggerPluginList from './trigger-plugin/list' import { ENTRY_NODE_TYPES } from './constants' import cn from '@/utils/classnames' import Link from 'next/link' import { RiArrowRightUpLine } from '@remixicon/react' import { getMarketplaceUrl } from '@/utils/var' import Button from '@/app/components/base/button' import { SearchMenu } from '@/app/components/base/icons/src/vender/line/general' import { BlockEnum as BlockEnumValue } from '../types' import FeaturedTriggers from './featured-triggers' import Divider from '@/app/components/base/divider' import { useGlobalPublicStore } from '@/context/global-public-context' import { useAllTriggerPlugins, useInvalidateAllTriggerPlugins } from '@/service/use-triggers' import { useFeaturedTriggersRecommendations } from '@/service/use-plugins' const marketplaceFooterClassName = 'system-sm-medium z-10 flex h-8 flex-none cursor-pointer items-center rounded-b-lg border-[0.5px] border-t border-components-panel-border bg-components-panel-bg-blur px-4 py-1 text-text-accent-light-mode-only shadow-lg' type AllStartBlocksProps = { className?: string searchText: string onSelect: (type: BlockEnum, trigger?: TriggerDefaultValue) => void availableBlocksTypes?: BlockEnum[] tags?: string[] allowUserInputSelection?: boolean // Allow user input option even when trigger node already exists (e.g. when no Start node yet or changing node type). } const AllStartBlocks = ({ className, searchText, onSelect, availableBlocksTypes, tags = [], allowUserInputSelection = false, }: AllStartBlocksProps) => { const { t } = useTranslation() const [hasStartBlocksContent, setHasStartBlocksContent] = useState(false) const [hasPluginContent, setHasPluginContent] = useState(false) const { enable_marketplace } = useGlobalPublicStore(s => s.systemFeatures) const entryNodeTypes = availableBlocksTypes?.length ? availableBlocksTypes : ENTRY_NODE_TYPES const enableTriggerPlugin = entryNodeTypes.includes(BlockEnumValue.TriggerPlugin) const { data: triggerProviders = [] } = useAllTriggerPlugins(enableTriggerPlugin) const providerMap = useMemo(() => { const map = new Map() triggerProviders.forEach((provider) => { const keys = [ provider.plugin_id, provider.plugin_unique_identifier, provider.id, ].filter(Boolean) as string[] keys.forEach((key) => { if (!map.has(key)) map.set(key, provider) }) }) return map }, [triggerProviders]) const invalidateTriggers = useInvalidateAllTriggerPlugins() const trimmedSearchText = searchText.trim() const hasSearchText = trimmedSearchText.length > 0 const { plugins: featuredPlugins = [], isLoading: featuredLoading, } = useFeaturedTriggersRecommendations(enableTriggerPlugin && enable_marketplace && !hasSearchText) const shouldShowFeatured = enableTriggerPlugin && enable_marketplace && !hasSearchText const handleStartBlocksContentChange = useCallback((hasContent: boolean) => { setHasStartBlocksContent(hasContent) }, []) const handlePluginContentChange = useCallback((hasContent: boolean) => { setHasPluginContent(hasContent) }, []) const hasAnyContent = hasStartBlocksContent || hasPluginContent || shouldShowFeatured const shouldShowEmptyState = hasSearchText && !hasAnyContent useEffect(() => { if (!enableTriggerPlugin && hasPluginContent) setHasPluginContent(false) }, [enableTriggerPlugin, hasPluginContent]) return (
{shouldShowFeatured && ( <> { invalidateTriggers() }} />
)}
{t('workflow.tabs.allTriggers')}
{enableTriggerPlugin && ( )}
{shouldShowEmptyState && (
{t('workflow.tabs.noPluginsFound')}
)}
{!shouldShowEmptyState && ( // Footer - Same as Tools tab marketplace footer {t('plugin.findMoreInMarketplace')} )}
) } export default AllStartBlocks