Generated by Spark: Got weird problem - Publish to https://low-code-react-app-b--johndoe6345789.github.app/ works fine but preview just shows Purple dot and loading.. + white page

This commit is contained in:
2026-01-17 00:07:35 +00:00
committed by GitHub
parent 90e3cb9c4d
commit 128d2ae6f4
4 changed files with 168 additions and 99 deletions

View File

@@ -83,10 +83,24 @@ function App() {
const [shortcutsOpen, setShortcutsOpen] = useState(false)
const [lastSaved] = useState<number | null>(Date.now())
const [errorCount] = useState(0)
const [appReady, setAppReady] = useState(false)
useEffect(() => {
const timer = setTimeout(() => {
setAppReady(true)
}, 100)
loadSeedData()
}, [])
.catch(err => {
console.error('Seed data loading failed:', err)
})
.finally(() => {
clearTimeout(timer)
setAppReady(true)
})
return () => clearTimeout(timer)
}, [loadSeedData])
const pageConfig = useMemo(() => getPageConfig(), [])
const enabledPages = useMemo(() => getEnabledPages(featureToggles), [featureToggles])
@@ -186,92 +200,112 @@ function App() {
}
const renderPageContent = (page: any) => {
const Component = componentMap[page.component]
if (!Component) {
return <LoadingFallback message={`Component ${page.component} not found`} />
}
if (page.requiresResizable && page.resizableConfig) {
const config = page.resizableConfig
const LeftComponent = componentMap[config.leftComponent]
const RightComponent = Component
if (!LeftComponent) {
return <LoadingFallback message={`Component ${config.leftComponent} not found`} />
try {
const Component = componentMap[page.component]
if (!Component) {
return <LoadingFallback message={`Component ${page.component} not found`} />
}
const stateContext = {
files,
models,
components,
componentTrees,
workflows,
lambdas,
theme,
playwrightTests,
storybookStories,
unitTests,
flaskConfig,
nextjsConfig,
npmSettings,
featureToggles,
activeFileId,
if (page.requiresResizable && page.resizableConfig) {
const config = page.resizableConfig
const LeftComponent = componentMap[config.leftComponent]
const RightComponent = Component
if (!LeftComponent) {
return <LoadingFallback message={`Component ${config.leftComponent} not found`} />
}
const stateContext = {
files,
models,
components,
componentTrees,
workflows,
lambdas,
theme,
playwrightTests,
storybookStories,
unitTests,
flaskConfig,
nextjsConfig,
npmSettings,
featureToggles,
activeFileId,
}
const actionContext = {
handleFileChange,
setActiveFileId,
handleFileClose,
handleFileAdd,
setModels,
setComponents,
setComponentTrees,
setWorkflows,
setLambdas,
setTheme,
setPlaywrightTests,
setStorybookStories,
setUnitTests,
setFlaskConfig,
setNextjsConfig,
setNpmSettings,
setFeatureToggles,
}
const leftProps = resolveProps(config.leftProps, stateContext, actionContext)
const rightProps = getPropsForComponent(page.id)
return (
<ResizablePanelGroup direction="horizontal">
<ResizablePanel
defaultSize={config.leftPanel.defaultSize}
minSize={config.leftPanel.minSize}
maxSize={config.leftPanel.maxSize}
>
<Suspense fallback={<LoadingFallback message={`Loading ${config.leftComponent.toLowerCase()}...`} />}>
<LeftComponent {...leftProps} />
</Suspense>
</ResizablePanel>
<ResizableHandle />
<ResizablePanel defaultSize={config.rightPanel.defaultSize}>
<Suspense fallback={<LoadingFallback message={`Loading ${page.title.toLowerCase()}...`} />}>
<RightComponent {...rightProps} />
</Suspense>
</ResizablePanel>
</ResizablePanelGroup>
)
}
const actionContext = {
handleFileChange,
setActiveFileId,
handleFileClose,
handleFileAdd,
setModels,
setComponents,
setComponentTrees,
setWorkflows,
setLambdas,
setTheme,
setPlaywrightTests,
setStorybookStories,
setUnitTests,
setFlaskConfig,
setNextjsConfig,
setNpmSettings,
setFeatureToggles,
}
const leftProps = resolveProps(config.leftProps, stateContext, actionContext)
const rightProps = getPropsForComponent(page.id)
const props = getPropsForComponent(page.id)
return (
<ResizablePanelGroup direction="horizontal">
<ResizablePanel
defaultSize={config.leftPanel.defaultSize}
minSize={config.leftPanel.minSize}
maxSize={config.leftPanel.maxSize}
>
<Suspense fallback={<LoadingFallback message={`Loading ${config.leftComponent.toLowerCase()}...`} />}>
<LeftComponent {...leftProps} />
</Suspense>
</ResizablePanel>
<ResizableHandle />
<ResizablePanel defaultSize={config.rightPanel.defaultSize}>
<Suspense fallback={<LoadingFallback message={`Loading ${page.title.toLowerCase()}...`} />}>
<RightComponent {...rightProps} />
</Suspense>
</ResizablePanel>
</ResizablePanelGroup>
<Suspense fallback={<LoadingFallback message={`Loading ${page.title.toLowerCase()}...`} />}>
<Component {...props} />
</Suspense>
)
} catch (error) {
console.error(`Failed to render page ${page.id}:`, error)
return (
<div className="flex items-center justify-center h-full">
<div className="text-center">
<p className="text-destructive font-semibold">Failed to load {page.title}</p>
<p className="text-sm text-muted-foreground mt-2">Check console for details</p>
</div>
</div>
)
}
const props = getPropsForComponent(page.id)
return (
<Suspense fallback={<LoadingFallback message={`Loading ${page.title.toLowerCase()}...`} />}>
<Component {...props} />
</Suspense>
)
}
return (
<div className="h-screen flex flex-col bg-background">
{!appReady && (
<div className="fixed inset-0 bg-background z-50 flex items-center justify-center">
<div className="flex flex-col items-center gap-4">
<div className="w-12 h-12 border-4 border-primary border-t-transparent rounded-full animate-spin" />
<p className="text-sm text-muted-foreground">Loading CodeForge...</p>
</div>
</div>
)}
<Suspense fallback={<div className="h-1 bg-primary animate-pulse" />}>
<PWAStatusBar />
</Suspense>

View File

@@ -9,6 +9,8 @@ interface ErrorFallbackProps {
}
export const ErrorFallback = ({ error, resetErrorBoundary }: ErrorFallbackProps) => {
console.error('ErrorFallback caught:', error);
if (import.meta.env.DEV) throw error;
return (
@@ -27,6 +29,11 @@ export const ErrorFallback = ({ error, resetErrorBoundary }: ErrorFallbackProps)
<pre className="text-xs text-destructive bg-muted/50 p-3 rounded border overflow-auto max-h-32">
{error.message}
</pre>
{error.stack && (
<pre className="text-xs text-muted-foreground bg-muted/50 p-3 rounded border overflow-auto max-h-48 mt-2">
{error.stack}
</pre>
)}
</div>
<Button

View File

@@ -83,26 +83,38 @@ export function resolveProps(propConfig: PropConfig | undefined, stateContext: R
const resolvedProps: Record<string, any> = {}
if (propConfig.state) {
for (const stateKey of propConfig.state) {
const [propName, contextKey] = stateKey.includes(':')
? stateKey.split(':')
: [stateKey, stateKey]
if (stateContext[contextKey] !== undefined) {
resolvedProps[propName] = stateContext[contextKey]
try {
if (propConfig.state) {
for (const stateKey of propConfig.state) {
try {
const [propName, contextKey] = stateKey.includes(':')
? stateKey.split(':')
: [stateKey, stateKey]
if (stateContext[contextKey] !== undefined) {
resolvedProps[propName] = stateContext[contextKey]
}
} catch (err) {
console.warn(`Failed to resolve state prop: ${stateKey}`, err)
}
}
}
}
if (propConfig.actions) {
for (const actionKey of propConfig.actions) {
const [propName, contextKey] = actionKey.split(':')
if (actionContext[contextKey]) {
resolvedProps[propName] = actionContext[contextKey]
if (propConfig.actions) {
for (const actionKey of propConfig.actions) {
try {
const [propName, contextKey] = actionKey.split(':')
if (actionContext[contextKey]) {
resolvedProps[propName] = actionContext[contextKey]
}
} catch (err) {
console.warn(`Failed to resolve action prop: ${actionKey}`, err)
}
}
}
} catch (err) {
console.error('Failed to resolve props:', err)
}
return resolvedProps

View File

@@ -1,15 +1,20 @@
import { useEffect, useState } from 'react'
import { useCallback, useState } from 'react'
import seedDataConfig from '@/config/seed-data.json'
export function useSeedData() {
const [isLoaded, setIsLoaded] = useState(false)
const [isLoading, setIsLoading] = useState(false)
const loadSeedData = async () => {
const loadSeedData = useCallback(async () => {
if (isLoading || isLoaded) return
setIsLoading(true)
try {
if (!window.spark?.kv) {
console.warn('Spark KV not available, skipping seed data')
return
}
const keys = await window.spark.kv.keys()
for (const [key, value] of Object.entries(seedDataConfig)) {
@@ -21,14 +26,20 @@ export function useSeedData() {
setIsLoaded(true)
} catch (error) {
console.error('Failed to load seed data:', error)
setIsLoaded(true)
} finally {
setIsLoading(false)
}
}
}, [isLoading, isLoaded])
const resetSeedData = async () => {
const resetSeedData = useCallback(async () => {
setIsLoading(true)
try {
if (!window.spark?.kv) {
console.warn('Spark KV not available')
return
}
for (const [key, value] of Object.entries(seedDataConfig)) {
await window.spark.kv.set(key, value)
}
@@ -38,11 +49,16 @@ export function useSeedData() {
} finally {
setIsLoading(false)
}
}
}, [])
const clearAllData = async () => {
const clearAllData = useCallback(async () => {
setIsLoading(true)
try {
if (!window.spark?.kv) {
console.warn('Spark KV not available')
return
}
const keys = await window.spark.kv.keys()
for (const key of keys) {
await window.spark.kv.delete(key)
@@ -53,7 +69,7 @@ export function useSeedData() {
} finally {
setIsLoading(false)
}
}
}, [])
return {
isLoaded,