mirror of
https://github.com/johndoe6345789/low-code-react-app-b.git
synced 2026-04-25 06:04:54 +00:00
Fix: Inline deleted JSON components to resolve build errors
Co-authored-by: johndoe6345789 <224850594+johndoe6345789@users.noreply.github.com>
This commit is contained in:
@@ -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) {
|
||||
|
||||
@@ -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>
|
||||
)
|
||||
})}
|
||||
|
||||
@@ -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>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -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>
|
||||
)}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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 (
|
||||
|
||||
Reference in New Issue
Block a user