refactor(skill): remove React.FC type annotations from all components

Replace FC<Props> pattern with direct props typing in function parameters
for better TypeScript inference and modern React best practices.
This commit is contained in:
yyh
2026-01-28 23:34:08 +08:00
parent 999587fbdd
commit 8326b9e3e5
47 changed files with 88 additions and 120 deletions

View File

@ -1,9 +1,9 @@
import type { FC, PropsWithChildren } from 'react'
import type { PropsWithChildren } from 'react'
import * as React from 'react'
type ContentAreaProps = PropsWithChildren
const ContentArea: FC<ContentAreaProps> = ({ children }) => {
const ContentArea = ({ children }: ContentAreaProps) => {
return (
<section className="flex min-h-0 min-w-0 flex-1 flex-col rounded-lg">
{children}

View File

@ -1,9 +1,9 @@
import type { FC, PropsWithChildren } from 'react'
import type { PropsWithChildren } from 'react'
import * as React from 'react'
type ContentBodyProps = PropsWithChildren
const ContentBody: FC<ContentBodyProps> = ({ children }) => {
const ContentBody = ({ children }: ContentBodyProps) => {
return (
<div className="flex min-h-0 min-w-0 flex-1">
{children}

View File

@ -1,4 +1,3 @@
import type { FC } from 'react'
import Editor from '@monaco-editor/react'
import * as React from 'react'
import Loading from '@/app/components/base/loading'
@ -11,7 +10,7 @@ type CodeFileEditorProps = {
onMount: (editor: any, monaco: any) => void
}
const CodeFileEditor: FC<CodeFileEditorProps> = ({ language, theme, value, onChange, onMount }) => {
const CodeFileEditor = ({ language, theme, value, onChange, onMount }: CodeFileEditorProps) => {
return (
<Editor
language={language}

View File

@ -1,4 +1,3 @@
import type { FC } from 'react'
import * as React from 'react'
import { useTranslation } from 'react-i18next'
import SkillEditor from './skill-editor'
@ -10,12 +9,12 @@ type MarkdownFileEditorProps = {
collaborationEnabled?: boolean
}
const MarkdownFileEditor: FC<MarkdownFileEditorProps> = ({
const MarkdownFileEditor = ({
instanceId,
value,
onChange,
collaborationEnabled,
}) => {
}: MarkdownFileEditorProps) => {
const { t } = useTranslation()
const handleChange = React.useCallback((val: string) => {
if (val !== value) {

View File

@ -1,7 +1,6 @@
'use client'
import type { EditorState } from 'lexical'
import type { FC } from 'react'
import { CodeNode } from '@lexical/code'
import { LexicalComposer } from '@lexical/react/LexicalComposer'
import { ContentEditable } from '@lexical/react/LexicalContentEditable'
@ -52,7 +51,7 @@ export type SkillEditorProps = {
toolPickerScope?: string
}
const SkillEditor: FC<SkillEditorProps> = ({
const SkillEditor = ({
instanceId,
compact,
wrapperClassName,
@ -68,7 +67,7 @@ const SkillEditor: FC<SkillEditorProps> = ({
onBlur,
onFocus,
toolPickerScope = 'all',
}) => {
}: SkillEditorProps) => {
const initialConfig = {
namespace: 'skill-editor',
nodes: [

View File

@ -1,5 +1,4 @@
import type { LexicalNode } from 'lexical'
import type { FC } from 'react'
import { useLexicalComposerContext } from '@lexical/react/LexicalComposerContext'
import { LexicalTypeaheadMenuPlugin, MenuOption } from '@lexical/react/LexicalTypeaheadMenuPlugin'
import {
@ -24,7 +23,7 @@ class FilePickerMenuOption extends MenuOption {
}
}
const FilePickerBlock: FC = () => {
const FilePickerBlock = () => {
const [editor] = useLexicalComposerContext()
const checkForTriggerMatch = useBasicTypeaheadTriggerMatch('/', {
minLength: 0,

View File

@ -1,4 +1,3 @@
import type { FC } from 'react'
import type { NodeRendererProps } from 'react-arborist'
import type { FileAppearanceType } from '@/app/components/base/file-uploader/types'
import type { TreeNodeData } from '@/app/components/workflow/skill/type'
@ -20,7 +19,7 @@ type FilePickerTreeNodeProps = NodeRendererProps<TreeNodeData> & {
onSelectNode: (node: TreeNodeData) => void
}
const FilePickerTreeNode: FC<FilePickerTreeNodeProps> = ({ node, style, dragHandle, onSelectNode }) => {
const FilePickerTreeNode = ({ node, style, dragHandle, onSelectNode }: FilePickerTreeNodeProps) => {
const { t } = useTranslation('workflow')
const isFolder = node.data.node_type === 'folder'
const isSelected = node.isSelected
@ -114,13 +113,13 @@ type FilePickerPanelProps = {
showHeader?: boolean
}
const FilePickerPanel: FC<FilePickerPanelProps> = ({
const FilePickerPanel = ({
onSelectNode,
focusNodeId,
className,
contentClassName,
showHeader = true,
}) => {
}: FilePickerPanelProps) => {
const { t } = useTranslation('workflow')
const { data: treeData, isLoading, error } = useSkillAssetTreeData()
const containerRef = useRef<HTMLDivElement>(null)

View File

@ -1,5 +1,4 @@
import type { LexicalNode } from 'lexical'
import type { FC } from 'react'
import type { FileAppearanceType } from '@/app/components/base/file-uploader/types'
import type { TreeNodeData } from '@/app/components/workflow/skill/type'
import { useLexicalComposerContext } from '@lexical/react/LexicalComposerContext'
@ -24,7 +23,7 @@ type FileReferenceBlockProps = {
resourceId: string
}
const FileReferenceBlock: FC<FileReferenceBlockProps> = ({ nodeKey, resourceId }) => {
const FileReferenceBlock = ({ nodeKey, resourceId }: FileReferenceBlockProps) => {
const [editor] = useLexicalComposerContext()
const [ref, isSelected] = useSelectOrDelete(nodeKey)
const { data: nodeMap } = useSkillAssetNodeMap()

View File

@ -1,6 +1,5 @@
'use client'
import type { RangeSelection, TextNode } from 'lexical'
import type { FC } from 'react'
import type { OnlineUser } from '@/app/components/workflow/collaboration/types'
import { useLexicalComposerContext } from '@lexical/react/LexicalComposerContext'
import {
@ -316,10 +315,12 @@ const getSelectionRects = (
return rects
}
export const LocalCursorPlugin: FC<{
type LocalCursorPluginProps = {
fileId?: string
enabled?: boolean
}> = ({ fileId, enabled }) => {
}
export const LocalCursorPlugin = ({ fileId, enabled }: LocalCursorPluginProps) => {
const [editor] = useLexicalComposerContext()
const lastEmittedCursorRef = useRef<{ start: number, end: number } | null>(null)
const lastEmitRef = useRef(0)
@ -461,10 +462,12 @@ export const LocalCursorPlugin: FC<{
return null
}
export const SkillRemoteCursors: FC<{
type SkillRemoteCursorsProps = {
fileId?: string
enabled?: boolean
}> = ({ fileId, enabled }) => {
}
export const SkillRemoteCursors = ({ fileId, enabled }: SkillRemoteCursorsProps) => {
const [editor] = useLexicalComposerContext()
const { userProfile } = useAppContext()
const myUserId = userProfile?.id || null

View File

@ -1,4 +1,3 @@
import type { FC } from 'react'
import type { PluginDetail } from '@/app/components/plugins/types'
import type { Emoji } from '@/app/components/tools/types'
import type { ToolValue } from '@/app/components/workflow/block-selector/types'
@ -107,7 +106,7 @@ type ToolConfigValueItem = {
type ToolConfigValueMap = Record<string, ToolConfigValueItem>
const ToolBlockComponent: FC<ToolBlockComponentProps> = ({
const ToolBlockComponent = ({
nodeKey,
provider,
tool,
@ -115,7 +114,7 @@ const ToolBlockComponent: FC<ToolBlockComponentProps> = ({
label,
icon,
iconDark,
}) => {
}: ToolBlockComponentProps) => {
const [ref, isSelected] = useSelectOrDelete(nodeKey, DELETE_TOOL_BLOCK_COMMAND)
const language = useGetLanguage()
const { t } = useTranslation()

View File

@ -1,4 +1,3 @@
import type { FC } from 'react'
import type { ToolToken } from './utils'
import type { PluginDetail } from '@/app/components/plugins/types'
import type { ToolParameter } from '@/app/components/tools/types'
@ -102,10 +101,10 @@ const normalizeProviderIcon = (icon?: ToolWithProvider['icon']) => {
return icon
}
const ToolGroupBlockComponent: FC<ToolGroupBlockComponentProps> = ({
const ToolGroupBlockComponent = ({
nodeKey,
tools,
}) => {
}: ToolGroupBlockComponentProps) => {
const [ref, isSelected] = useSelectOrDelete(nodeKey, DELETE_TOOL_BLOCK_COMMAND)
const { t } = useTranslation()
const authBadgeLabel = t('skillEditor.authorizationBadge', { ns: 'workflow' })

View File

@ -1,6 +1,5 @@
'use client'
import type { FC } from 'react'
import type { Emoji } from '@/app/components/tools/types'
import { RiArrowLeftSLine, RiCloseLine } from '@remixicon/react'
import AppIcon from '@/app/components/base/app-icon'
@ -15,7 +14,7 @@ type ToolHeaderProps = {
backLabel?: string
}
const ToolHeader: FC<ToolHeaderProps> = ({
const ToolHeader = ({
icon,
providerLabel,
toolLabel,
@ -23,7 +22,7 @@ const ToolHeader: FC<ToolHeaderProps> = ({
onClose,
onBack,
backLabel,
}) => {
}: ToolHeaderProps) => {
const renderHeaderIcon = () => {
if (!icon)
return null

View File

@ -1,5 +1,4 @@
import type { LexicalNode } from 'lexical'
import type { FC } from 'react'
import type { ToolParameter } from '@/app/components/tools/types'
import type { ToolDefaultValue } from '@/app/components/workflow/block-selector/types'
import { useLexicalComposerContext } from '@lexical/react/LexicalComposerContext'
@ -32,7 +31,7 @@ type ToolPickerBlockProps = {
scope?: string
}
const ToolPickerBlock: FC<ToolPickerBlockProps> = ({ scope = 'all' }) => {
const ToolPickerBlock = ({ scope = 'all' }: ToolPickerBlockProps) => {
const [editor] = useLexicalComposerContext()
const checkForTriggerMatch = useBasicTypeaheadTriggerMatch('@', {
minLength: 0,

View File

@ -1,6 +1,5 @@
'use client'
import type { FC } from 'react'
import type { Tool } from '@/app/components/tools/types'
import type { ToolValue } from '@/app/components/workflow/block-selector/types'
import type { ToolWithProvider } from '@/app/components/workflow/types'
@ -38,13 +37,13 @@ type ToolSettingsSectionProps = {
onChange?: (value: ToolValue) => void
}
const ToolSettingsSection: FC<ToolSettingsSectionProps> = ({
const ToolSettingsSection = ({
currentProvider,
currentTool,
value,
nodeId,
onChange,
}) => {
}: ToolSettingsSectionProps) => {
const { t } = useTranslation()
const safeNodeId = nodeId ?? ''

View File

@ -1,7 +1,6 @@
'use client'
import type { OnMount } from '@monaco-editor/react'
import type { FC } from 'react'
import { loader } from '@monaco-editor/react'
import dynamic from 'next/dynamic'
import * as React from 'react'
@ -34,7 +33,7 @@ const SQLiteFilePreview = dynamic(
if (typeof window !== 'undefined')
loader.config({ paths: { vs: `${window.location.origin}${basePath}/vs` } })
const FileContentPanel: FC = () => {
const FileContentPanel = () => {
const { t } = useTranslation('workflow')
const { theme: appTheme } = useTheme()
const [isMounted, setIsMounted] = useState(false)

View File

@ -1,6 +1,5 @@
'use client'
import type { FC } from 'react'
import type { FileAppearanceType } from '@/app/components/base/file-uploader/types'
import { RiCloseLine } from '@remixicon/react'
import * as React from 'react'
@ -22,7 +21,7 @@ type FileTabItemProps = {
onDoubleClick: (fileId: string) => void
}
const FileTabItem: FC<FileTabItemProps> = ({
const FileTabItem = ({
fileId,
name,
extension,
@ -32,7 +31,7 @@ const FileTabItem: FC<FileTabItemProps> = ({
onClick,
onClose,
onDoubleClick,
}) => {
}: FileTabItemProps) => {
const { t } = useTranslation()
const iconType = getFileIconType(name, extension)

View File

@ -1,6 +1,5 @@
'use client'
import type { FC } from 'react'
import * as React from 'react'
import { useCallback, useState } from 'react'
import { useTranslation } from 'react-i18next'
@ -12,7 +11,7 @@ import FileTabItem from './file-tab-item'
import { useSkillAssetNodeMap } from './hooks/use-skill-asset-tree'
import StartTabItem from './start-tab-item'
const FileTabs: FC = () => {
const FileTabs = () => {
const { t } = useTranslation('workflow')
const openTabIds = useStore(s => s.openTabIds)
const activeTabId = useStore(s => s.activeTabId)

View File

@ -1,6 +1,5 @@
'use client'
import type { FC } from 'react'
import type { SandboxFileTreeNode } from '@/types/sandbox-file'
import { RiArrowDownSLine, RiArrowRightSLine, RiLoader2Line } from '@remixicon/react'
import * as React from 'react'
@ -16,7 +15,7 @@ type ArtifactsSectionProps = {
className?: string
}
const ArtifactsSection: FC<ArtifactsSectionProps> = ({ className }) => {
const ArtifactsSection = ({ className }: ArtifactsSectionProps) => {
const { t } = useTranslation('workflow')
const { userProfile } = useAppContext()
const sandboxId = userProfile?.id

View File

@ -1,6 +1,5 @@
'use client'
import type { FC } from 'react'
import type { FileAppearanceType } from '@/app/components/base/file-uploader/types'
import type { SandboxFileTreeNode } from '@/types/sandbox-file'
import { RiDownloadLine, RiFolderLine, RiFolderOpenLine } from '@remixicon/react'
@ -30,14 +29,14 @@ type ArtifactsTreeNodeProps = {
isDownloading?: boolean
}
const ArtifactsTreeNode: FC<ArtifactsTreeNodeProps> = ({
const ArtifactsTreeNode = ({
node,
depth,
onDownload,
onSelect,
selectedPath,
isDownloading,
}) => {
}: ArtifactsTreeNodeProps) => {
const [isExpanded, setIsExpanded] = useState(false)
const isFolder = node.node_type === 'folder'
const hasChildren = isFolder && node.children.length > 0
@ -132,13 +131,13 @@ const ArtifactsTreeNode: FC<ArtifactsTreeNodeProps> = ({
)
}
const ArtifactsTree: FC<ArtifactsTreeProps> = ({
const ArtifactsTree = ({
data,
onDownload,
onSelect,
selectedPath,
isDownloading,
}) => {
}: ArtifactsTreeProps) => {
if (!data || data.length === 0)
return null

View File

@ -1,6 +1,5 @@
'use client'
import type { FC } from 'react'
import * as React from 'react'
import { useMemo } from 'react'
import { useTranslation } from 'react-i18next'
@ -14,7 +13,7 @@ type DragActionTooltipProps = {
action: DragAction
}
const DragActionTooltip: FC<DragActionTooltipProps> = ({ action }) => {
const DragActionTooltip = ({ action }: DragActionTooltipProps) => {
const { t } = useTranslation('workflow')
const dragOverFolderId = useStore(s => s.dragOverFolderId)
const { data: nodeMap } = useSkillAssetNodeMap()

View File

@ -88,7 +88,7 @@ const DropTip = () => {
)
}
const FileTree: React.FC<FileTreeProps> = ({ className }) => {
const FileTree = ({ className }: FileTreeProps) => {
const { t } = useTranslation('workflow')
const treeRef = useRef<TreeApi<TreeNodeData>>(null)
const containerRef = useRef<HTMLDivElement>(null)

View File

@ -1,7 +1,6 @@
'use client'
import type { VariantProps } from 'class-variance-authority'
import type { FC } from 'react'
import { cva } from 'class-variance-authority'
import * as React from 'react'
import ShortcutsName from '@/app/components/workflow/shortcuts-name'
@ -58,7 +57,7 @@ export type MenuItemProps = {
disabled?: boolean
} & VariantProps<typeof menuItemVariants>
const MenuItem: FC<MenuItemProps> = ({ icon: Icon, label, kbd, onClick, disabled, variant }) => {
const MenuItem = ({ icon: Icon, label, kbd, onClick, disabled, variant }: MenuItemProps) => {
const handleClick = React.useCallback((event: React.MouseEvent<HTMLButtonElement>) => {
event.stopPropagation()
onClick(event)

View File

@ -1,6 +1,5 @@
'use client'
import type { FC } from 'react'
import type { NodeApi, TreeApi } from 'react-arborist'
import type { NodeMenuType } from '../constants'
import type { TreeNodeData } from '../type'
@ -42,14 +41,14 @@ type NodeMenuProps = {
node?: NodeApi<TreeNodeData>
}
const NodeMenu: FC<NodeMenuProps> = ({
const NodeMenu = ({
type,
nodeId,
onClose,
className,
treeRef,
node,
}) => {
}: NodeMenuProps) => {
const { t } = useTranslation('workflow')
const storeApi = useWorkflowStore()
const selectedNodeIds = useStore(s => s.selectedNodeIds)

View File

@ -1,6 +1,5 @@
'use client'
import type { FC } from 'react'
import type { TreeApi } from 'react-arborist'
import type { TreeNodeData } from '../type'
import { useClickAway } from 'ahooks'
@ -14,7 +13,7 @@ type TreeContextMenuProps = {
treeRef: React.RefObject<TreeApi<TreeNodeData> | null>
}
const TreeContextMenu: FC<TreeContextMenuProps> = ({ treeRef }) => {
const TreeContextMenu = ({ treeRef }: TreeContextMenuProps) => {
const ref = useRef<HTMLDivElement>(null)
const contextMenu = useStore(s => s.contextMenu)
const storeApi = useWorkflowStore()

View File

@ -10,7 +10,7 @@ type TreeEditInputProps = {
node: NodeApi<TreeNodeData>
}
const TreeEditInput: React.FC<TreeEditInputProps> = ({ node }) => {
const TreeEditInput = ({ node }: TreeEditInputProps) => {
const { t } = useTranslation('workflow')
const inputRef = useRef<HTMLInputElement>(null)
const isFolder = node.data.node_type === 'folder'

View File

@ -12,11 +12,11 @@ type TreeGuideLinesProps = {
const INDENT_SIZE = 20
const DEFAULT_LINE_OFFSET = 10
const TreeGuideLines: React.FC<TreeGuideLinesProps> = ({
const TreeGuideLines = ({
level,
indentSize = INDENT_SIZE,
lineOffset = DEFAULT_LINE_OFFSET,
}) => {
}: TreeGuideLinesProps) => {
const guides = useMemo(() => {
if (level === 0)
return null

View File

@ -2,7 +2,6 @@
// Icon rendering for tree nodes (folder/file icons with dirty indicator)
import type { FC } from 'react'
import type { FileAppearanceType } from '@/app/components/base/file-uploader/types'
import { RiFolderLine, RiFolderOpenLine } from '@remixicon/react'
import { useTranslation } from 'react-i18next'
@ -19,14 +18,14 @@ type TreeNodeIconProps = {
onToggle?: (e: React.MouseEvent) => void
}
export const TreeNodeIcon: FC<TreeNodeIconProps> = ({
export const TreeNodeIcon = ({
isFolder,
isOpen,
fileName,
extension,
isDirty,
onToggle,
}) => {
}: TreeNodeIconProps) => {
const { t } = useTranslation('workflow')
if (isFolder) {

View File

@ -1,6 +1,6 @@
'use client'
import type { FC, ReactNode } from 'react'
import type { ReactNode } from 'react'
import {
RiAlertFill,
RiCheckboxCircleFill,
@ -18,7 +18,7 @@ type UploadStatusTooltipProps = {
const SUCCESS_DISPLAY_MS = 2000
const UploadStatusTooltip: FC<UploadStatusTooltipProps> = ({ fallback }) => {
const UploadStatusTooltip = ({ fallback }: UploadStatusTooltipProps) => {
const { t } = useTranslation('workflow')
const storeApi = useWorkflowStore()
const uploadStatus = useStore(s => s.uploadStatus)

View File

@ -1,6 +1,5 @@
'use client'
import type { FC } from 'react'
import * as React from 'react'
import { useStore as useAppStore } from '@/app/components/app/store'
import ContentArea from './content-area'
@ -15,12 +14,12 @@ import Sidebar from './sidebar'
import SidebarSearchAdd from './sidebar-search-add'
import SkillPageLayout from './skill-page-layout'
const SkillAutoSaveManager: FC = () => {
const SkillAutoSaveManager = () => {
useSkillAutoSave()
return null
}
const SkillMain: FC = () => {
const SkillMain = () => {
const appDetail = useAppStore(s => s.appDetail)
const appId = appDetail?.id || ''

View File

@ -1,6 +1,5 @@
'use client'
import type { FC } from 'react'
import {
RiAddLine,
RiFileAddLine,
@ -32,7 +31,7 @@ type MenuItemProps = {
disabled?: boolean
}
const MenuItem: React.FC<MenuItemProps> = ({ icon: Icon, label, onClick, disabled }) => (
const MenuItem = ({ icon: Icon, label, onClick, disabled }: MenuItemProps) => (
<button
type="button"
onClick={onClick}
@ -50,7 +49,7 @@ const MenuItem: React.FC<MenuItemProps> = ({ icon: Icon, label, onClick, disable
</button>
)
const SidebarSearchAdd: FC = () => {
const SidebarSearchAdd = () => {
const { t } = useTranslation('workflow')
const searchValue = useStore(s => s.fileTreeSearchTerm)
const storeApi = useWorkflowStore()

View File

@ -1,6 +1,6 @@
'use client'
import type { FC, PropsWithChildren } from 'react'
import type { PropsWithChildren } from 'react'
import { useDebounceFn } from 'ahooks'
import * as React from 'react'
import { useCallback } from 'react'
@ -11,7 +11,7 @@ import { SIDEBAR_DEFAULT_WIDTH, SIDEBAR_MAX_WIDTH, SIDEBAR_MIN_WIDTH } from './c
type SidebarProps = PropsWithChildren
const Sidebar: FC<SidebarProps> = ({ children }) => {
const Sidebar = ({ children }: SidebarProps) => {
const { run: persistWidth } = useDebounceFn(
(width: number) => storage.set(STORAGE_KEYS.SKILL.SIDEBAR_WIDTH, width),
{ wait: 200 },

View File

@ -1,9 +1,9 @@
import type { FC, PropsWithChildren } from 'react'
import type { PropsWithChildren } from 'react'
import * as React from 'react'
type SkillPageLayoutProps = PropsWithChildren
const SkillPageLayout: FC<SkillPageLayoutProps> = ({ children }) => {
const SkillPageLayout = ({ children }: SkillPageLayoutProps) => {
return (
<div className="flex h-full gap-3 overflow-hidden">
{children}

View File

@ -1,6 +1,5 @@
'use client'
import type { FC } from 'react'
import * as React from 'react'
import { useTranslation } from 'react-i18next'
import Home from '@/app/components/base/icons/src/vender/workflow/Home'
@ -11,10 +10,10 @@ type StartTabItemProps = {
onClick: () => void
}
const StartTabItem: FC<StartTabItemProps> = ({
const StartTabItem = ({
isActive,
onClick,
}) => {
}: StartTabItemProps) => {
const { t } = useTranslation('workflow')
return (

View File

@ -1,6 +1,6 @@
'use client'
import type { FC, ReactNode } from 'react'
import type { ReactNode } from 'react'
import { memo } from 'react'
import { cn } from '@/utils/classnames'
@ -11,12 +11,12 @@ type ActionCardProps = {
onClick?: () => void
}
const ActionCard: FC<ActionCardProps> = ({
const ActionCard = ({
icon,
title,
description,
onClick,
}) => {
}: ActionCardProps) => {
return (
<button
type="button"

View File

@ -1,6 +1,5 @@
'use client'
import type { FC } from 'react'
import { memo } from 'react'
import TabItem from './tab-item'
@ -24,11 +23,11 @@ type CategoryTabsProps = {
onCategoryChange: (categoryId: string) => void
}
const CategoryTabs: FC<CategoryTabsProps> = ({
const CategoryTabs = ({
categories = MOCK_CATEGORIES,
activeCategory,
onCategoryChange,
}) => {
}: CategoryTabsProps) => {
return (
<div className="flex flex-1 items-center gap-1">
{categories.map(category => (

View File

@ -1,6 +1,5 @@
'use client'
import type { FC } from 'react'
import { memo } from 'react'
import { cn } from '@/utils/classnames'
@ -10,11 +9,11 @@ type TabItemProps = {
onClick: () => void
}
const TabItem: FC<TabItemProps> = ({
const TabItem = ({
label,
isActive,
onClick,
}) => {
}: TabItemProps) => {
return (
<button
type="button"

View File

@ -1,12 +1,11 @@
'use client'
import type { FC } from 'react'
import { RiAddCircleFill, RiUploadLine } from '@remixicon/react'
import { memo } from 'react'
import { useTranslation } from 'react-i18next'
import ActionCard from './action-card'
const CreateImportSection: FC = () => {
const CreateImportSection = () => {
const { t } = useTranslation('workflow')
return (

View File

@ -1,11 +1,10 @@
'use client'
import type { FC } from 'react'
import { memo } from 'react'
import CreateImportSection from './create-import-section'
import SkillTemplatesSection from './skill-templates-section'
const StartTabContent: FC = () => {
const StartTabContent = () => {
return (
<div className="h-full w-full overflow-auto bg-components-panel-bg">
<CreateImportSection />

View File

@ -1,6 +1,5 @@
'use client'
import type { FC } from 'react'
import { memo } from 'react'
type SectionHeaderProps = {
@ -9,11 +8,11 @@ type SectionHeaderProps = {
className?: string
}
const SectionHeader: FC<SectionHeaderProps> = ({
const SectionHeader = ({
title,
description,
className,
}) => {
}: SectionHeaderProps) => {
return (
<header className={className}>
<h2 className="title-xl-semi-bold text-text-primary">

View File

@ -1,13 +1,12 @@
'use client'
import type { FC } from 'react'
import { memo, useState } from 'react'
import { useTranslation } from 'react-i18next'
import CategoryTabs from './category-tabs'
import SectionHeader from './section-header'
import TemplateSearch from './template-search'
const SkillTemplatesSection: FC = () => {
const SkillTemplatesSection = () => {
const { t } = useTranslation('workflow')
const [activeCategory, setActiveCategory] = useState('all')
const [searchValue, setSearchValue] = useState('')

View File

@ -1,6 +1,5 @@
'use client'
import type { FC } from 'react'
import { RiSearchLine } from '@remixicon/react'
import { memo } from 'react'
import { useTranslation } from 'react-i18next'
@ -10,10 +9,10 @@ type TemplateSearchProps = {
onChange: (value: string) => void
}
const TemplateSearch: FC<TemplateSearchProps> = ({
const TemplateSearch = ({
value,
onChange,
}) => {
}: TemplateSearchProps) => {
const { t } = useTranslation('workflow')
return (

View File

@ -1,4 +1,3 @@
import type { FC } from 'react'
import * as React from 'react'
import { useTranslation } from 'react-i18next'
@ -7,7 +6,7 @@ type MediaFilePreviewProps = {
src: string
}
const MediaFilePreview: FC<MediaFilePreviewProps> = ({ type, src }) => {
const MediaFilePreview = ({ type, src }: MediaFilePreviewProps) => {
const { t } = useTranslation('workflow')
if (!src) {

View File

@ -1,5 +1,5 @@
import type { TFunction } from 'i18next'
import type { FC, RefObject } from 'react'
import type { RefObject } from 'react'
import type { SQLiteValue } from '../../hooks/use-sqlite-database'
import { useVirtualizer } from '@tanstack/react-virtual'
import * as React from 'react'
@ -32,7 +32,7 @@ const truncateValue = (value: string): string => {
return `${value.slice(0, MAX_CELL_LENGTH)}`
}
const DataTable: FC<DataTableProps> = ({ columns, values, scrollRef, isTruncated = false }) => {
const DataTable = ({ columns, values, scrollRef, isTruncated = false }: DataTableProps) => {
const { t } = useTranslation('workflow')
const keyColumnIndex = useMemo(() => {
const candidates = new Set(['id', 'rowid', 'uuid'])

View File

@ -1,4 +1,3 @@
import type { FC } from 'react'
import * as React from 'react'
import { useMemo, useRef, useState } from 'react'
import { useTranslation } from 'react-i18next'
@ -13,9 +12,9 @@ type SQLiteFilePreviewProps = {
downloadUrl: string
}
const SQLiteFilePreview: FC<SQLiteFilePreviewProps> = ({
const SQLiteFilePreview = ({
downloadUrl,
}) => {
}: SQLiteFilePreviewProps) => {
const { t } = useTranslation('workflow')
const { tables, isLoading, error, queryTable } = useSQLiteDatabase(downloadUrl)
const [selectedTableId, setSelectedTableId] = useState<string>('')

View File

@ -1,4 +1,4 @@
import type { FC, RefObject } from 'react'
import type { RefObject } from 'react'
import type { SQLiteQueryResult } from '../../hooks/sqlite/types'
import * as React from 'react'
import { useTranslation } from 'react-i18next'
@ -13,13 +13,13 @@ type TablePanelProps = {
isTruncated?: boolean
}
const TablePanel: FC<TablePanelProps> = ({
const TablePanel = ({
data,
isLoading,
error,
scrollRef,
isTruncated = false,
}) => {
}: TablePanelProps) => {
const { t } = useTranslation('workflow')
return (

View File

@ -1,4 +1,3 @@
import type { FC } from 'react'
import { RiArrowDownSLine } from '@remixicon/react'
import * as React from 'react'
import { useMemo, useState } from 'react'
@ -19,12 +18,12 @@ type TableSelectorProps = {
onTableChange: (tableName: string) => void
}
const TableSelector: FC<TableSelectorProps> = ({
const TableSelector = ({
tables,
selectedTable,
isLoading = false,
onTableChange,
}) => {
}: TableSelectorProps) => {
const { t } = useTranslation('workflow')
const [open, setOpen] = useState(false)
const items = useMemo(() => {

View File

@ -1,4 +1,3 @@
import type { FC } from 'react'
import * as React from 'react'
import { useCallback } from 'react'
import { useTranslation } from 'react-i18next'
@ -13,7 +12,7 @@ type UnsupportedFileDownloadProps = {
downloadUrl?: string
}
const UnsupportedFileDownload: FC<UnsupportedFileDownloadProps> = ({ name, size, downloadUrl }) => {
const UnsupportedFileDownload = ({ name, size, downloadUrl }: UnsupportedFileDownloadProps) => {
const { t } = useTranslation('workflow')
const fileSize = size ? formatFileSize(size) : ''