diff --git a/src/components/global-search/RecentSearches.tsx b/src/components/global-search/RecentSearches.tsx index 99b2728..161b134 100644 --- a/src/components/global-search/RecentSearches.tsx +++ b/src/components/global-search/RecentSearches.tsx @@ -2,25 +2,7 @@ import { ClockCounterClockwise, X } from '@phosphor-icons/react' import { Badge } from '@/components/ui/badge' import { Button } from '@/components/ui/button' import { CommandGroup, CommandItem, CommandSeparator } from '@/components/ui/command' - -interface SearchHistoryItem { - id: string - query: string - timestamp: number - resultId?: string - resultTitle?: string - resultCategory?: string -} - -interface SearchResult { - id: string - title: string - subtitle?: string - category: string - icon: React.ReactNode - action: () => void - tags?: string[] -} +import type { SearchHistoryItem, SearchResult } from './types' interface RecentSearchesProps { recentSearches: Array<{ historyItem: SearchHistoryItem; result?: SearchResult }> diff --git a/src/components/global-search/SearchResults.tsx b/src/components/global-search/SearchResults.tsx index 87a8dc1..d5093ba 100644 --- a/src/components/global-search/SearchResults.tsx +++ b/src/components/global-search/SearchResults.tsx @@ -1,15 +1,6 @@ import { Badge } from '@/components/ui/badge' import { CommandGroup, CommandItem, CommandSeparator } from '@/components/ui/command' - -interface SearchResult { - id: string - title: string - subtitle?: string - category: string - icon: React.ReactNode - action: () => void - tags?: string[] -} +import type { SearchResult } from './types' interface SearchResultsProps { groupedResults: Record diff --git a/src/components/global-search/types.ts b/src/components/global-search/types.ts new file mode 100644 index 0000000..8fa320f --- /dev/null +++ b/src/components/global-search/types.ts @@ -0,0 +1,18 @@ +export interface SearchResult { + id: string + title: string + subtitle?: string + category: string + icon: React.ReactNode + action: () => void + tags?: string[] +} + +export interface SearchHistoryItem { + id: string + query: string + timestamp: number + resultId?: string + resultTitle?: string + resultCategory?: string +} diff --git a/src/components/global-search/useGlobalSearchData.tsx b/src/components/global-search/useGlobalSearchData.tsx index cb217b3..26113b4 100644 --- a/src/components/global-search/useGlobalSearchData.tsx +++ b/src/components/global-search/useGlobalSearchData.tsx @@ -33,25 +33,7 @@ import { Workflow, } from '@/types/project' import navigationData from '@/data/global-search.json' - -export interface SearchResult { - id: string - title: string - subtitle?: string - category: string - icon: React.ReactNode - action: () => void - tags?: string[] -} - -export interface SearchHistoryItem { - id: string - query: string - timestamp: number - resultId?: string - resultTitle?: string - resultCategory?: string -} +import type { SearchHistoryItem, SearchResult } from './types' const navigationIconMap = { BookOpen, diff --git a/src/components/molecules/ComponentBindingDialog.tsx b/src/components/molecules/ComponentBindingDialog.tsx index 95ac768..344660b 100644 --- a/src/components/molecules/ComponentBindingDialog.tsx +++ b/src/components/molecules/ComponentBindingDialog.tsx @@ -23,8 +23,9 @@ export function ComponentBindingDialog({ }: ComponentBindingDialogProps) { const { editingComponent, handleSave, updateBindings } = useComponentBindingDialog({ component, - onSave, + open, onOpenChange, + onSave, }) if (!editingComponent) return null diff --git a/src/components/molecules/DataSourceEditorDialog.tsx b/src/components/molecules/DataSourceEditorDialog.tsx index cce4a0c..ceec274 100644 --- a/src/components/molecules/DataSourceEditorDialog.tsx +++ b/src/components/molecules/DataSourceEditorDialog.tsx @@ -6,6 +6,7 @@ import { DataSourceIdField } from '@/components/molecules/data-source-editor/Dat import { KvSourceFields } from '@/components/molecules/data-source-editor/KvSourceFields' import { StaticSourceFields } from '@/components/molecules/data-source-editor/StaticSourceFields' import { ComputedSourceFields } from '@/components/molecules/data-source-editor/ComputedSourceFields' +import { useDataSourceEditor } from '@/hooks/data/use-data-source-editor' import dataSourceEditorCopy from '@/data/data-source-editor-dialog.json' import { useDataSourceEditor } from '@/hooks/use-data-source-editor' @@ -29,16 +30,16 @@ export function DataSourceEditorDialog({ updateField, addDependency, removeDependency, - handleSave, availableDeps, selectedDeps, unselectedDeps, - } = useDataSourceEditor({ - dataSource, - allDataSources, - onSave, - onOpenChange, - }) + } = useDataSourceEditor(dataSource, allDataSources) + + const handleSave = () => { + if (!editingSource) return + onSave(editingSource) + onOpenChange(false) + } if (!editingSource) return null diff --git a/src/components/project-settings/NextJsApplicationCard.tsx b/src/components/project-settings/NextJsApplicationCard.tsx index ac97ba6..a9ab41d 100644 --- a/src/components/project-settings/NextJsApplicationCard.tsx +++ b/src/components/project-settings/NextJsApplicationCard.tsx @@ -1,18 +1,13 @@ import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card' import { Input } from '@/components/ui/input' import { Label } from '@/components/ui/label' -import { NextJsConfig } from '@/types/project' import projectSettingsCopy from '@/data/project-settings.json' - -interface NextJsApplicationCardProps { - nextjsConfig: NextJsConfig - onNextjsConfigChange: (config: NextJsConfig | ((current: NextJsConfig) => NextJsConfig)) => void -} +import { NextJsConfigSectionProps } from '@/components/project-settings/types' export function NextJsApplicationCard({ nextjsConfig, onNextjsConfigChange, -}: NextJsApplicationCardProps) { +}: NextJsConfigSectionProps) { const { application } = projectSettingsCopy.nextjs return ( diff --git a/src/components/project-settings/NextJsConfigTab.tsx b/src/components/project-settings/NextJsConfigTab.tsx index fab7665..43501bc 100644 --- a/src/components/project-settings/NextJsConfigTab.tsx +++ b/src/components/project-settings/NextJsConfigTab.tsx @@ -1,16 +1,11 @@ -import { NextJsConfig } from '@/types/project' import { NextJsApplicationCard } from '@/components/project-settings/NextJsApplicationCard' import { NextJsFeaturesCard } from '@/components/project-settings/NextJsFeaturesCard' - -interface NextJsConfigTabProps { - nextjsConfig: NextJsConfig - onNextjsConfigChange: (config: NextJsConfig | ((current: NextJsConfig) => NextJsConfig)) => void -} +import { NextJsConfigSectionProps } from '@/components/project-settings/types' export function NextJsConfigTab({ nextjsConfig, onNextjsConfigChange, -}: NextJsConfigTabProps) { +}: NextJsConfigSectionProps) { return (
NextJsConfig)) => void -} +import { NextJsConfigSectionProps } from '@/components/project-settings/types' export function NextJsFeaturesCard({ nextjsConfig, onNextjsConfigChange, -}: NextJsFeaturesCardProps) { +}: NextJsConfigSectionProps) { const { features } = projectSettingsCopy.nextjs return ( diff --git a/src/components/project-settings/types.ts b/src/components/project-settings/types.ts new file mode 100644 index 0000000..eeead81 --- /dev/null +++ b/src/components/project-settings/types.ts @@ -0,0 +1,6 @@ +import { NextJsConfig } from '@/types/project' + +export type NextJsConfigSectionProps = { + nextjsConfig: NextJsConfig + onNextjsConfigChange: (config: NextJsConfig | ((current: NextJsConfig) => NextJsConfig)) => void +} diff --git a/src/hooks/data/use-data-source-editor.ts b/src/hooks/data/use-data-source-editor.ts new file mode 100644 index 0000000..8c5c9af --- /dev/null +++ b/src/hooks/data/use-data-source-editor.ts @@ -0,0 +1,58 @@ +import { useCallback, useEffect, useMemo, useState } from 'react' +import { DataSource } from '@/types/json-ui' + +export function useDataSourceEditor( + dataSource: DataSource | null, + allDataSources: DataSource[], +) { + const [editingSource, setEditingSource] = useState(dataSource) + + useEffect(() => { + setEditingSource(dataSource) + }, [dataSource]) + + const updateField = useCallback((field: K, value: DataSource[K]) => { + setEditingSource(prev => (prev ? { ...prev, [field]: value } : prev)) + }, []) + + const addDependency = useCallback((depId: string) => { + setEditingSource(prev => { + if (!prev || prev.type !== 'computed') return prev + const deps = prev.dependencies || [] + if (deps.includes(depId)) return prev + return { ...prev, dependencies: [...deps, depId] } + }) + }, []) + + const removeDependency = useCallback((depId: string) => { + setEditingSource(prev => { + if (!prev || prev.type !== 'computed') return prev + const deps = prev.dependencies || [] + return { ...prev, dependencies: deps.filter(dep => dep !== depId) } + }) + }, []) + + const availableDeps = useMemo(() => { + if (!editingSource) return [] + return allDataSources.filter( + ds => ds.id !== editingSource.id && ds.type !== 'computed', + ) + }, [allDataSources, editingSource]) + + const selectedDeps = useMemo(() => editingSource?.dependencies || [], [editingSource]) + + const unselectedDeps = useMemo( + () => availableDeps.filter(ds => !selectedDeps.includes(ds.id)), + [availableDeps, selectedDeps], + ) + + return { + editingSource, + updateField, + addDependency, + removeDependency, + availableDeps, + selectedDeps, + unselectedDeps, + } +} diff --git a/src/hooks/use-component-binding-dialog.ts b/src/hooks/use-component-binding-dialog.ts index f76752a..148c651 100644 --- a/src/hooks/use-component-binding-dialog.ts +++ b/src/hooks/use-component-binding-dialog.ts @@ -1,28 +1,29 @@ import { useCallback, useEffect, useState } from 'react' import { UIComponent } from '@/types/json-ui' -interface UseComponentBindingDialogParams { +interface UseComponentBindingDialogOptions { component: UIComponent | null - onSave: (component: UIComponent) => void + open: boolean onOpenChange: (open: boolean) => void + onSave: (component: UIComponent) => void } export function useComponentBindingDialog({ component, - onSave, + open, onOpenChange, -}: UseComponentBindingDialogParams) { + onSave, +}: UseComponentBindingDialogOptions) { const [editingComponent, setEditingComponent] = useState(component) useEffect(() => { - setEditingComponent(component) - }, [component]) + if (open) { + setEditingComponent(component) + } + }, [component, open]) const updateBindings = useCallback((bindings: Record) => { - setEditingComponent((prev) => { - if (!prev) return prev - return { ...prev, bindings } - }) + setEditingComponent(prev => (prev ? { ...prev, bindings } : prev)) }, []) const handleSave = useCallback(() => { @@ -33,7 +34,7 @@ export function useComponentBindingDialog({ return { editingComponent, - updateBindings, handleSave, + updateBindings, } }