Fix: Inline deleted JSON components to resolve build errors

Co-authored-by: johndoe6345789 <224850594+johndoe6345789@users.noreply.github.com>
This commit is contained in:
copilot-swe-agent[bot]
2026-01-18 21:58:04 +00:00
parent 56aeb492e6
commit 1bb2eadbe8
9 changed files with 174 additions and 46 deletions

View File

@@ -1,5 +1,4 @@
import { PageRenderer } from '@/lib/json-ui/page-renderer'
import { LoadingFallback } from '@/components/molecules'
import { useSchemaLoader } from '@/hooks/use-schema-loader'
interface JSONSchemaPageLoaderProps {
@@ -12,7 +11,14 @@ export function JSONSchemaPageLoader({ schemaPath, data, functions }: JSONSchema
const { schema, loading, error } = useSchemaLoader(schemaPath)
if (loading) {
return <LoadingFallback message={`Loading ${schemaPath}...`} />
return (
<div className="flex items-center justify-center h-full w-full">
<div className="flex flex-col items-center gap-3">
<div className="w-8 h-8 border-2 border-primary border-t-transparent rounded-full animate-spin" />
<p className="text-sm text-muted-foreground">Loading {schemaPath}...</p>
</div>
</div>
)
}
if (error || !schema) {

View File

@@ -4,7 +4,7 @@ import { Sidebar, SidebarContent, SidebarHeader } from '@/components/ui/sidebar'
import { ScrollArea } from '@/components/ui/scroll-area'
import { Collapsible, CollapsibleContent } from '@/components/ui/collapsible'
import { CaretDoubleDown, CaretDoubleUp } from '@phosphor-icons/react'
import { NavigationItem, NavigationGroupHeader } from '@/components/molecules'
import { NavigationGroupHeader, Badge, Flex, Text, IconWrapper } from '@/components/atoms'
import { navigationGroups, NavigationItemData } from '@/lib/navigation-config'
import { FeatureToggles } from '@/types/project'
import { useRoutePreload } from '@/hooks/use-route-preload'
@@ -126,19 +126,41 @@ function NavigationMenuGroupList({
{group.items.map((item) => {
if (!isItemVisible(item)) return null
const isActive = activeTab === item.value
const badge = getItemBadge(item)
return (
<div
key={item.id}
onMouseEnter={() => onItemHover(item.value)}
onMouseLeave={() => onItemLeave(item.value)}
>
<NavigationItem
icon={item.icon}
label={item.label}
isActive={activeTab === item.value}
badge={getItemBadge(item)}
{/* NavigationItem - inlined */}
<button
onClick={() => onItemClick(item.value)}
/>
className={`w-full flex items-center gap-3 px-3 py-2 rounded-lg transition-colors ${
isActive
? 'bg-primary text-primary-foreground'
: 'hover:bg-muted text-foreground'
}`}
>
<IconWrapper
icon={item.icon}
size="md"
variant={isActive ? 'default' : 'muted'}
/>
<Text className="flex-1 text-left font-medium" variant="small">
{item.label}
</Text>
{badge !== undefined && badge > 0 && (
<Badge
variant={isActive ? 'secondary' : 'destructive'}
className="ml-auto"
>
{badge}
</Badge>
)}
</button>
</div>
)
})}

View File

@@ -1,5 +1,4 @@
import { PageHeaderContent } from '@/components/molecules'
import { Stack, Container } from '@/components/atoms'
import { Stack, Container, TabIcon } from '@/components/atoms'
import { tabInfo } from '@/lib/navigation-config'
interface PageHeaderProps {
@@ -17,11 +16,18 @@ export function PageHeader({ activeTab }: PageHeaderProps) {
spacing="none"
className="border-b border-border bg-card px-4 sm:px-6 py-3 sm:py-4"
>
<PageHeaderContent
title={info.title}
icon={info.icon}
description={info.description}
/>
{/* PageHeaderContent - inlined */}
<div className="flex items-center gap-3">
<TabIcon icon={info.icon} variant="gradient" />
<div className="min-w-0">
<h2 className="text-lg sm:text-xl font-bold truncate">{info.title}</h2>
{info.description && (
<p className="text-xs sm:text-sm text-muted-foreground hidden sm:block">
{info.description}
</p>
)}
</div>
</div>
</Stack>
)
}

View File

@@ -1,6 +1,5 @@
import { ScrollArea } from '@/components/ui/scroll-area'
import { TreeCard, TreeListHeader } from '@/components/molecules'
import { EmptyState, Stack, Container } from '@/components/atoms'
import { EmptyState, Stack, Container, Card, Badge, ActionIcon, IconButton, Flex, Text, Heading, Button, TreeIcon } from '@/components/atoms'
import { ComponentTree } from '@/types/project'
import { FolderOpen } from '@phosphor-icons/react'
@@ -29,12 +28,42 @@ export function TreeListPanel({
}: TreeListPanelProps) {
return (
<div className="w-80 border-r border-border bg-card p-4 flex flex-col gap-4">
<TreeListHeader
onCreateNew={onCreateNew}
onImportJson={onImportJson}
onExportJson={onExportJson}
hasSelectedTree={!!selectedTreeId}
/>
{/* TreeListHeader - inlined */}
<Stack spacing="sm">
<Flex justify="between" align="center">
<Flex align="center" gap="sm">
<TreeIcon size={20} />
<Heading level={2} className="text-lg font-semibold">Component Trees</Heading>
</Flex>
<IconButton
icon={<ActionIcon action="add" size={16} />}
size="sm"
onClick={onCreateNew}
/>
</Flex>
<Flex gap="sm">
<Button
size="sm"
variant="outline"
onClick={onImportJson}
className="flex-1 text-xs"
leftIcon={<ActionIcon action="upload" size={14} />}
>
Import JSON
</Button>
<Button
size="sm"
variant="outline"
onClick={onExportJson}
disabled={!selectedTreeId}
className="flex-1 text-xs"
leftIcon={<ActionIcon action="download" size={14} />}
>
Export JSON
</Button>
</Flex>
</Stack>
{trees.length === 0 ? (
<Stack
@@ -56,18 +85,65 @@ export function TreeListPanel({
) : (
<ScrollArea className="flex-1">
<Stack direction="vertical" spacing="sm">
{trees.map((tree) => (
<TreeCard
key={tree.id}
tree={tree}
isSelected={selectedTreeId === tree.id}
onSelect={() => onTreeSelect(tree.id)}
onEdit={() => onTreeEdit(tree)}
onDuplicate={() => onTreeDuplicate(tree)}
onDelete={() => onTreeDelete(tree.id)}
disableDelete={trees.length === 1}
/>
))}
{trees.map((tree) => {
const isSelected = selectedTreeId === tree.id
const disableDelete = trees.length === 1
return (
// TreeCard - inlined
<Card
key={tree.id}
className={`cursor-pointer transition-all p-4 ${
isSelected ? 'ring-2 ring-primary bg-accent' : 'hover:bg-accent/50'
}`}
onClick={() => onTreeSelect(tree.id)}
>
<Stack spacing="sm">
<Flex justify="between" align="start" gap="sm">
<Stack spacing="xs" className="flex-1 min-w-0">
<Heading level={4} className="text-sm truncate">{tree.name}</Heading>
{tree.description && (
<Text variant="caption" className="line-clamp-2">
{tree.description}
</Text>
)}
<div>
<Badge variant="outline" className="text-xs">
{tree.rootNodes.length} components
</Badge>
</div>
</Stack>
</Flex>
<div onClick={(e) => e.stopPropagation()}>
<Flex gap="xs" className="mt-1">
<IconButton
icon={<ActionIcon action="edit" size={14} />}
variant="ghost"
size="sm"
onClick={() => onTreeEdit(tree)}
title="Edit tree"
/>
<IconButton
icon={<ActionIcon action="duplicate" size={14} />}
variant="ghost"
size="sm"
onClick={() => onTreeDuplicate(tree)}
title="Duplicate tree"
/>
<IconButton
icon={<ActionIcon action="delete" size={14} />}
variant="ghost"
size="sm"
onClick={() => onTreeDelete(tree.id)}
disabled={disableDelete}
title={disableDelete ? "Can't delete last tree" : "Delete tree"}
/>
</Flex>
</div>
</Stack>
</Card>
)
})}
</Stack>
</ScrollArea>
)}

View File

@@ -1,6 +1,5 @@
import { lazy } from 'react'
import { lazyWithRetry, lazyWithPreload } from '@/lib/lazy-loader'
import { preloadMonacoEditor } from '@/components/molecules'
import componentRegistryConfig from '../../component-registry.json'
type ComponentConfig = {
@@ -31,6 +30,14 @@ type RegistryConfig = {
const config = componentRegistryConfig as RegistryConfig
// Monaco editor preloader - inlined
const preloadMonacoEditor = () => {
console.log('[MONACO] 🎯 Preloading Monaco Editor')
import('@monaco-editor/react')
.then(() => console.log('[MONACO] ✅ Monaco Editor preloaded'))
.catch(err => console.warn('[MONACO] ⚠️ Monaco Editor preload failed:', err))
}
const dependencyPreloaders: Record<string, () => void> = {
preloadMonacoEditor
}

View File

@@ -1,6 +1,5 @@
import { lazy, Suspense } from 'react'
import { RouteObject, Navigate } from 'react-router-dom'
import { LoadingFallback } from '@/components/molecules'
import { JSONSchemaPageLoader } from '@/components/JSONSchemaPageLoader'
import { NotFoundPage } from '@/components/NotFoundPage'
import { getEnabledPages, resolveProps } from '@/config/page-loader'
@@ -23,11 +22,22 @@ const LazyComponent = ({
if (!Component) {
console.error('[ROUTES] ❌ Component not found:', componentName)
return <LoadingFallback message={`Component ${componentName} not found`} />
return (
<div className="flex items-center justify-center h-full w-full">
<p className="text-sm text-muted-foreground">Component {componentName} not found</p>
</div>
)
}
return (
<Suspense fallback={<LoadingFallback message={`Loading ${componentName.toLowerCase()}...`} />}>
<Suspense fallback={
<div className="flex items-center justify-center h-full w-full">
<div className="flex flex-col items-center gap-3">
<div className="w-8 h-8 border-2 border-primary border-t-transparent rounded-full animate-spin" />
<p className="text-sm text-muted-foreground">Loading {componentName.toLowerCase()}...</p>
</div>
</div>
}>
<Component {...props} />
</Suspense>
)
@@ -46,7 +56,11 @@ const ResizableLayout = ({
if (!LeftComponent || !RightComponent) {
console.error('[ROUTES] ❌ Resizable components not found:', { leftComponent, rightComponent })
return <LoadingFallback message="Layout components not found" />
return (
<div className="flex items-center justify-center h-full w-full">
<p className="text-sm text-muted-foreground">Layout components not found</p>
</div>
)
}
return (