mirror of
https://github.com/johndoe6345789/low-code-react-app-b.git
synced 2026-04-24 13:44:54 +00:00
feat: Convert ComponentTree and SeedDataManager to pure JSON with hooks
- Created useComponentTree hook to flatten recursive tree structure - Created useStorageBackendInfo hook for backend icon/copy logic - Created useD3BarChart hook for chart calculations - Registered all new hooks in hooks-registry - Created component-tree.json with list rendering using treeData from hook - Created seed-data-manager.json with full Card/Alert/Button structure - Deleted ComponentTreeWrapper.tsx and SeedDataManagerWrapper.tsx - Updated exports to use JSON components - 9 components now pure JSON, 2 wrappers remaining Co-authored-by: johndoe6345789 <224850594+johndoe6345789@users.noreply.github.com>
This commit is contained in:
65
src/components/json-definitions/component-tree.json
Normal file
65
src/components/json-definitions/component-tree.json
Normal file
@@ -0,0 +1,65 @@
|
||||
{
|
||||
"id": "component-tree-container",
|
||||
"type": "div",
|
||||
"bindings": {
|
||||
"className": {
|
||||
"source": "className",
|
||||
"transform": "data ? `space-y-2 ${data}` : 'space-y-2'"
|
||||
}
|
||||
},
|
||||
"children": [
|
||||
{
|
||||
"id": "empty-message",
|
||||
"type": "p",
|
||||
"props": { "className": "text-sm text-muted-foreground" },
|
||||
"bindings": { "children": "emptyMessage" },
|
||||
"conditional": { "if": "components.length === 0" }
|
||||
},
|
||||
{
|
||||
"id": "tree-nodes",
|
||||
"type": "div",
|
||||
"props": { "className": "space-y-1" },
|
||||
"conditional": { "if": "components.length > 0" },
|
||||
"children": [
|
||||
{
|
||||
"id": "tree-node-list",
|
||||
"type": "list",
|
||||
"bindings": {
|
||||
"items": "treeData",
|
||||
"keyPath": "component.id"
|
||||
},
|
||||
"itemTemplate": {
|
||||
"type": "button",
|
||||
"props": { "type": "button" },
|
||||
"bindings": {
|
||||
"onClick": {
|
||||
"source": "onSelect,item.component.id",
|
||||
"transform": "() => onSelect?.(item.component.id)"
|
||||
},
|
||||
"className": {
|
||||
"source": "item.isSelected",
|
||||
"transform": "item.isSelected ? 'flex w-full items-center gap-2 rounded-md px-2 py-1 text-left text-sm transition-colors bg-accent/40 text-foreground' : 'flex w-full items-center gap-2 rounded-md px-2 py-1 text-left text-sm transition-colors hover:bg-muted'"
|
||||
},
|
||||
"style": {
|
||||
"source": "item.paddingLeft",
|
||||
"transform": "{ paddingLeft: item.paddingLeft }"
|
||||
}
|
||||
},
|
||||
"children": [
|
||||
{
|
||||
"type": "span",
|
||||
"props": { "className": "font-medium" },
|
||||
"bindings": { "children": "item.component.type" }
|
||||
},
|
||||
{
|
||||
"type": "span",
|
||||
"props": { "className": "text-xs text-muted-foreground" },
|
||||
"bindings": { "children": "item.component.id" }
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
217
src/components/json-definitions/seed-data-manager.json
Normal file
217
src/components/json-definitions/seed-data-manager.json
Normal file
@@ -0,0 +1,217 @@
|
||||
{
|
||||
"id": "seed-data-manager-card",
|
||||
"type": "Card",
|
||||
"children": [
|
||||
{
|
||||
"id": "card-header",
|
||||
"type": "CardHeader",
|
||||
"children": [
|
||||
{
|
||||
"id": "card-title",
|
||||
"type": "CardTitle",
|
||||
"props": { "className": "flex items-center gap-2" },
|
||||
"children": [
|
||||
{
|
||||
"id": "title-icon",
|
||||
"type": "PhosphorIcon",
|
||||
"props": { "icon": "Database", "size": 24, "weight": "duotone" }
|
||||
},
|
||||
{
|
||||
"id": "title-text",
|
||||
"type": "text",
|
||||
"bindings": { "children": "title" }
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "card-description",
|
||||
"type": "CardDescription",
|
||||
"bindings": { "children": "description" }
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "card-content",
|
||||
"type": "CardContent",
|
||||
"props": { "className": "flex flex-col gap-4" },
|
||||
"children": [
|
||||
{
|
||||
"id": "loaded-alert",
|
||||
"type": "Alert",
|
||||
"conditional": { "if": "isLoaded" },
|
||||
"children": [
|
||||
{
|
||||
"id": "alert-icon",
|
||||
"type": "PhosphorIcon",
|
||||
"props": { "icon": "CheckCircle", "className": "h-4 w-4", "weight": "fill" }
|
||||
},
|
||||
{
|
||||
"id": "alert-description",
|
||||
"type": "AlertDescription",
|
||||
"children": [{ "type": "text", "children": "Seed data is loaded and available" }]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "buttons-container",
|
||||
"type": "div",
|
||||
"props": { "className": "flex flex-col gap-3" },
|
||||
"children": [
|
||||
{
|
||||
"id": "buttons-row",
|
||||
"type": "div",
|
||||
"props": { "className": "flex gap-2 flex-wrap" },
|
||||
"children": [
|
||||
{
|
||||
"id": "load-button",
|
||||
"type": "Button",
|
||||
"bindings": {
|
||||
"onClick": "onLoadSeedData",
|
||||
"disabled": {
|
||||
"source": "isLoading,isLoaded",
|
||||
"transform": "isLoading || isLoaded"
|
||||
}
|
||||
},
|
||||
"props": { "variant": "default" },
|
||||
"children": [
|
||||
{
|
||||
"id": "load-button-content",
|
||||
"type": "conditional-group",
|
||||
"conditional": { "if": "isLoading" },
|
||||
"children": [
|
||||
{
|
||||
"type": "PhosphorIcon",
|
||||
"props": { "icon": "CircleNotch", "className": "animate-spin", "size": 16 }
|
||||
},
|
||||
{
|
||||
"type": "text",
|
||||
"bindings": { "children": "loadingLabel" }
|
||||
}
|
||||
],
|
||||
"else": [
|
||||
{
|
||||
"type": "PhosphorIcon",
|
||||
"props": { "icon": "Database", "size": 16, "weight": "fill" }
|
||||
},
|
||||
{
|
||||
"type": "text",
|
||||
"bindings": { "children": "loadLabel" }
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "reset-button",
|
||||
"type": "Button",
|
||||
"bindings": {
|
||||
"onClick": "onResetSeedData",
|
||||
"disabled": "isLoading"
|
||||
},
|
||||
"props": { "variant": "outline" },
|
||||
"children": [
|
||||
{
|
||||
"id": "reset-button-content",
|
||||
"type": "conditional-group",
|
||||
"conditional": { "if": "isLoading" },
|
||||
"children": [
|
||||
{
|
||||
"type": "PhosphorIcon",
|
||||
"props": { "icon": "CircleNotch", "className": "animate-spin", "size": 16 }
|
||||
},
|
||||
{
|
||||
"type": "text",
|
||||
"bindings": { "children": "resettingLabel" }
|
||||
}
|
||||
],
|
||||
"else": [
|
||||
{
|
||||
"type": "PhosphorIcon",
|
||||
"props": { "icon": "ArrowClockwise", "size": 16, "weight": "bold" }
|
||||
},
|
||||
{
|
||||
"type": "text",
|
||||
"bindings": { "children": "resetLabel" }
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "clear-button",
|
||||
"type": "Button",
|
||||
"bindings": {
|
||||
"onClick": "onClearAllData",
|
||||
"disabled": "isLoading"
|
||||
},
|
||||
"props": { "variant": "destructive" },
|
||||
"children": [
|
||||
{
|
||||
"id": "clear-button-content",
|
||||
"type": "conditional-group",
|
||||
"conditional": { "if": "isLoading" },
|
||||
"children": [
|
||||
{
|
||||
"type": "PhosphorIcon",
|
||||
"props": { "icon": "CircleNotch", "className": "animate-spin", "size": 16 }
|
||||
},
|
||||
{
|
||||
"type": "text",
|
||||
"bindings": { "children": "clearingLabel" }
|
||||
}
|
||||
],
|
||||
"else": [
|
||||
{
|
||||
"type": "PhosphorIcon",
|
||||
"props": { "icon": "Trash", "size": 16, "weight": "fill" }
|
||||
},
|
||||
{
|
||||
"type": "text",
|
||||
"bindings": { "children": "clearLabel" }
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "helper-text",
|
||||
"type": "div",
|
||||
"props": { "className": "text-sm text-muted-foreground space-y-1" },
|
||||
"children": [
|
||||
{
|
||||
"id": "load-help",
|
||||
"type": "p",
|
||||
"conditional": { "if": "helperText.load" },
|
||||
"children": [
|
||||
{ "type": "strong", "children": "Load Seed Data: " },
|
||||
{ "type": "text", "bindings": { "children": "helperText.load" } }
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "reset-help",
|
||||
"type": "p",
|
||||
"conditional": { "if": "helperText.reset" },
|
||||
"children": [
|
||||
{ "type": "strong", "children": "Reset to Defaults: " },
|
||||
{ "type": "text", "bindings": { "children": "helperText.reset" } }
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "clear-help",
|
||||
"type": "p",
|
||||
"conditional": { "if": "helperText.clear" },
|
||||
"children": [
|
||||
{ "type": "strong", "children": "Clear All Data: " },
|
||||
{ "type": "text", "bindings": { "children": "helperText.clear" } }
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -1,55 +0,0 @@
|
||||
import { cn } from '@/lib/utils'
|
||||
import type { UIComponent } from '@/types/json-ui'
|
||||
import type { ComponentTreeWrapperProps } from './interfaces'
|
||||
|
||||
const renderTreeNodes = (
|
||||
components: UIComponent[],
|
||||
depth: number,
|
||||
selectedId: string | null,
|
||||
onSelect?: (id: string) => void
|
||||
) => {
|
||||
return components.map((component) => {
|
||||
const hasChildren = Array.isArray(component.children) && component.children.length > 0
|
||||
const isSelected = selectedId === component.id
|
||||
|
||||
return (
|
||||
<div key={component.id}>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => onSelect?.(component.id)}
|
||||
className={cn(
|
||||
'flex w-full items-center gap-2 rounded-md px-2 py-1 text-left text-sm transition-colors',
|
||||
isSelected ? 'bg-accent/40 text-foreground' : 'hover:bg-muted'
|
||||
)}
|
||||
style={{ paddingLeft: `${depth * 16 + 8}px` }}
|
||||
>
|
||||
<span className="font-medium">{component.type}</span>
|
||||
<span className="text-xs text-muted-foreground">{component.id}</span>
|
||||
</button>
|
||||
{hasChildren && (
|
||||
<div className="mt-1">
|
||||
{renderTreeNodes(component.children as UIComponent[], depth + 1, selectedId, onSelect)}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
export function ComponentTreeWrapper({
|
||||
components = [],
|
||||
selectedId = null,
|
||||
emptyMessage = 'No components available.',
|
||||
onSelect,
|
||||
className,
|
||||
}: ComponentTreeWrapperProps) {
|
||||
return (
|
||||
<div className={cn('space-y-2', className)}>
|
||||
{components.length === 0 ? (
|
||||
<p className="text-sm text-muted-foreground">{emptyMessage}</p>
|
||||
) : (
|
||||
<div className="space-y-1">{renderTreeNodes(components, 0, selectedId, onSelect)}</div>
|
||||
)}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
@@ -1,122 +0,0 @@
|
||||
import { Alert, AlertDescription } from '@/components/ui/alert'
|
||||
import { Button } from '@/components/ui/button'
|
||||
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card'
|
||||
import { CheckCircle, CircleNotch, Database, Trash, ArrowClockwise } from '@phosphor-icons/react'
|
||||
import type { SeedDataManagerWrapperProps } from './interfaces'
|
||||
|
||||
export function SeedDataManagerWrapper({
|
||||
isLoaded = false,
|
||||
isLoading = false,
|
||||
title = 'Seed Data Management',
|
||||
description = 'Load, reset, or clear application seed data from the database',
|
||||
loadLabel = 'Load Seed Data',
|
||||
loadingLabel = 'Loading...',
|
||||
resetLabel = 'Reset to Defaults',
|
||||
resettingLabel = 'Resetting...',
|
||||
clearLabel = 'Clear All Data',
|
||||
clearingLabel = 'Clearing...',
|
||||
onLoadSeedData,
|
||||
onResetSeedData,
|
||||
onClearAllData,
|
||||
helperText = {
|
||||
load: 'Populates database with initial data if not already loaded',
|
||||
reset: 'Overwrites all data with fresh seed data',
|
||||
clear: 'Removes all data from the database (destructive action)',
|
||||
},
|
||||
}: SeedDataManagerWrapperProps) {
|
||||
return (
|
||||
<Card>
|
||||
<CardHeader>
|
||||
<CardTitle className="flex items-center gap-2">
|
||||
<Database size={24} weight="duotone" />
|
||||
{title}
|
||||
</CardTitle>
|
||||
<CardDescription>{description}</CardDescription>
|
||||
</CardHeader>
|
||||
<CardContent className="flex flex-col gap-4">
|
||||
{isLoaded && (
|
||||
<Alert>
|
||||
<CheckCircle className="h-4 w-4" weight="fill" />
|
||||
<AlertDescription>Seed data is loaded and available</AlertDescription>
|
||||
</Alert>
|
||||
)}
|
||||
|
||||
<div className="flex flex-col gap-3">
|
||||
<div className="flex gap-2 flex-wrap">
|
||||
<Button
|
||||
onClick={onLoadSeedData}
|
||||
disabled={isLoading || isLoaded}
|
||||
variant="default"
|
||||
>
|
||||
{isLoading ? (
|
||||
<>
|
||||
<CircleNotch className="animate-spin" size={16} />
|
||||
{loadingLabel}
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<Database size={16} weight="fill" />
|
||||
{loadLabel}
|
||||
</>
|
||||
)}
|
||||
</Button>
|
||||
|
||||
<Button
|
||||
onClick={onResetSeedData}
|
||||
disabled={isLoading}
|
||||
variant="outline"
|
||||
>
|
||||
{isLoading ? (
|
||||
<>
|
||||
<CircleNotch className="animate-spin" size={16} />
|
||||
{resettingLabel}
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<ArrowClockwise size={16} weight="bold" />
|
||||
{resetLabel}
|
||||
</>
|
||||
)}
|
||||
</Button>
|
||||
|
||||
<Button
|
||||
onClick={onClearAllData}
|
||||
disabled={isLoading}
|
||||
variant="destructive"
|
||||
>
|
||||
{isLoading ? (
|
||||
<>
|
||||
<CircleNotch className="animate-spin" size={16} />
|
||||
{clearingLabel}
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<Trash size={16} weight="fill" />
|
||||
{clearLabel}
|
||||
</>
|
||||
)}
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
<div className="text-sm text-muted-foreground space-y-1">
|
||||
{helperText.load && (
|
||||
<p>
|
||||
<strong>Load Seed Data:</strong> {helperText.load}
|
||||
</p>
|
||||
)}
|
||||
{helperText.reset && (
|
||||
<p>
|
||||
<strong>Reset to Defaults:</strong> {helperText.reset}
|
||||
</p>
|
||||
)}
|
||||
{helperText.clear && (
|
||||
<p>
|
||||
<strong>Clear All Data:</strong> {helperText.clear}
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
)
|
||||
}
|
||||
@@ -2,7 +2,6 @@ export { Breadcrumb } from './Breadcrumb'
|
||||
export { CanvasRenderer } from './CanvasRenderer'
|
||||
export { CodeExplanationDialog } from './CodeExplanationDialog'
|
||||
export { ComponentPalette } from './ComponentPalette'
|
||||
export { ComponentTree } from './ComponentTree'
|
||||
export { GitHubBuildStatus } from './GitHubBuildStatus'
|
||||
export { LazyLineChart } from './LazyLineChart'
|
||||
export { LazyBarChart } from './LazyBarChart'
|
||||
@@ -10,8 +9,6 @@ export { LazyD3BarChart } from './LazyD3BarChart'
|
||||
export { StorageSettings } from './StorageSettings'
|
||||
export { NavigationGroupHeader } from './NavigationGroupHeader'
|
||||
export { PropertyEditor } from './PropertyEditor'
|
||||
export { SaveIndicator } from './SaveIndicator'
|
||||
export { SeedDataManager } from './SeedDataManager'
|
||||
export { ToolbarButton } from './ToolbarButton'
|
||||
export { TreeFormDialog } from './TreeFormDialog'
|
||||
export { SearchInput } from './SearchInput'
|
||||
@@ -25,6 +22,8 @@ export {
|
||||
ComponentBindingDialog,
|
||||
DataSourceEditorDialog,
|
||||
GitHubBuildStatus as GitHubBuildStatusJSON,
|
||||
SaveIndicator as SaveIndicatorJSON
|
||||
SaveIndicator,
|
||||
ComponentTree,
|
||||
SeedDataManager
|
||||
} from '@/lib/json-ui/json-components'
|
||||
export { preloadMonacoEditor } from './LazyMonacoEditor'
|
||||
|
||||
46
src/hooks/use-component-tree.ts
Normal file
46
src/hooks/use-component-tree.ts
Normal file
@@ -0,0 +1,46 @@
|
||||
/**
|
||||
* Hook for flattening and rendering component tree structure
|
||||
* Converts recursive component tree to flat list with depth information
|
||||
*/
|
||||
import type { UIComponent } from '@/types/json-ui'
|
||||
|
||||
export interface TreeNode {
|
||||
component: UIComponent
|
||||
depth: number
|
||||
hasChildren: boolean
|
||||
isSelected: boolean
|
||||
paddingLeft: string
|
||||
}
|
||||
|
||||
export function useComponentTree(
|
||||
components: UIComponent[],
|
||||
selectedId: string | null
|
||||
): TreeNode[] {
|
||||
const flattenTree = (
|
||||
items: UIComponent[],
|
||||
depth: number = 0
|
||||
): TreeNode[] => {
|
||||
const result: TreeNode[] = []
|
||||
|
||||
for (const component of items) {
|
||||
const hasChildren = Array.isArray(component.children) && component.children.length > 0
|
||||
const isSelected = selectedId === component.id
|
||||
|
||||
result.push({
|
||||
component,
|
||||
depth,
|
||||
hasChildren,
|
||||
isSelected,
|
||||
paddingLeft: `${depth * 16 + 8}px`
|
||||
})
|
||||
|
||||
if (hasChildren) {
|
||||
result.push(...flattenTree(component.children as UIComponent[], depth + 1))
|
||||
}
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
return flattenTree(components)
|
||||
}
|
||||
72
src/hooks/use-d3-bar-chart.ts
Normal file
72
src/hooks/use-d3-bar-chart.ts
Normal file
@@ -0,0 +1,72 @@
|
||||
/**
|
||||
* Hook for calculating D3 bar chart dimensions and positions
|
||||
*/
|
||||
export interface BarChartData {
|
||||
label: string
|
||||
value: number
|
||||
}
|
||||
|
||||
export interface BarPosition {
|
||||
x: number
|
||||
y: number
|
||||
width: number
|
||||
height: number
|
||||
label: string
|
||||
value: number
|
||||
labelX: number
|
||||
labelY: number
|
||||
valueX: number
|
||||
valueY: number
|
||||
}
|
||||
|
||||
export interface ChartDimensions {
|
||||
innerWidth: number
|
||||
innerHeight: number
|
||||
margin: { top: number; right: number; bottom: number; left: number }
|
||||
translateX: number
|
||||
translateY: number
|
||||
bars: BarPosition[]
|
||||
}
|
||||
|
||||
export function useD3BarChart(
|
||||
data: BarChartData[],
|
||||
width: number = 600,
|
||||
height: number = 300
|
||||
): ChartDimensions {
|
||||
const margin = { top: 20, right: 20, bottom: 30, left: 40 }
|
||||
const innerWidth = Math.max(width - margin.left - margin.right, 0)
|
||||
const innerHeight = Math.max(height - margin.top - margin.bottom, 0)
|
||||
const maxValue = Math.max(...data.map((item) => item.value), 0)
|
||||
const barGap = 8
|
||||
const barCount = data.length
|
||||
const totalGap = barCount > 1 ? barGap * (barCount - 1) : 0
|
||||
const barWidth = barCount > 0 ? Math.max((innerWidth - totalGap) / barCount, 0) : 0
|
||||
|
||||
const bars: BarPosition[] = data.map((item, index) => {
|
||||
const barHeight = maxValue ? (item.value / maxValue) * innerHeight : 0
|
||||
const x = index * (barWidth + barGap)
|
||||
const y = innerHeight - barHeight
|
||||
|
||||
return {
|
||||
x,
|
||||
y,
|
||||
width: barWidth,
|
||||
height: barHeight,
|
||||
label: item.label,
|
||||
value: item.value,
|
||||
labelX: x + barWidth / 2,
|
||||
labelY: innerHeight + 16,
|
||||
valueX: x + barWidth / 2,
|
||||
valueY: Math.max(y - 6, 0)
|
||||
}
|
||||
})
|
||||
|
||||
return {
|
||||
innerWidth,
|
||||
innerHeight,
|
||||
margin,
|
||||
translateX: margin.left,
|
||||
translateY: margin.top,
|
||||
bars
|
||||
}
|
||||
}
|
||||
30
src/hooks/use-storage-backend-info.ts
Normal file
30
src/hooks/use-storage-backend-info.ts
Normal file
@@ -0,0 +1,30 @@
|
||||
/**
|
||||
* Hook for getting storage backend icon and copy
|
||||
*/
|
||||
import type { StorageBackendKey } from '@/components/storage/storageSettingsConfig'
|
||||
import { getBackendCopy } from '@/components/storage/storageSettingsConfig'
|
||||
|
||||
export interface BackendInfo {
|
||||
iconName: string
|
||||
iconWeight: string
|
||||
moleculeLabel: string
|
||||
}
|
||||
|
||||
export function useStorageBackendInfo(backend: StorageBackendKey | null): BackendInfo {
|
||||
const iconMap: Record<StorageBackendKey | 'null', { iconName: string; iconWeight: string }> = {
|
||||
flask: { iconName: 'Cpu', iconWeight: 'regular' },
|
||||
indexeddb: { iconName: 'HardDrive', iconWeight: 'regular' },
|
||||
sqlite: { iconName: 'Database', iconWeight: 'regular' },
|
||||
sparkkv: { iconName: 'Cloud', iconWeight: 'regular' },
|
||||
null: { iconName: 'Database', iconWeight: 'regular' }
|
||||
}
|
||||
|
||||
const icon = iconMap[backend || 'null']
|
||||
const backendCopy = getBackendCopy(backend)
|
||||
|
||||
return {
|
||||
iconName: icon.iconName,
|
||||
iconWeight: icon.iconWeight,
|
||||
moleculeLabel: backendCopy.moleculeLabel
|
||||
}
|
||||
}
|
||||
@@ -3,6 +3,9 @@
|
||||
* Allows JSON components to use custom React hooks
|
||||
*/
|
||||
import { useSaveIndicator } from '@/hooks/use-save-indicator'
|
||||
import { useComponentTree } from '@/hooks/use-component-tree'
|
||||
import { useStorageBackendInfo } from '@/hooks/use-storage-backend-info'
|
||||
import { useD3BarChart } from '@/hooks/use-d3-bar-chart'
|
||||
|
||||
export interface HookRegistry {
|
||||
[key: string]: (...args: any[]) => any
|
||||
@@ -13,6 +16,9 @@ export interface HookRegistry {
|
||||
*/
|
||||
export const hooksRegistry: HookRegistry = {
|
||||
useSaveIndicator,
|
||||
useComponentTree,
|
||||
useStorageBackendInfo,
|
||||
useD3BarChart,
|
||||
// Add more hooks here as needed
|
||||
}
|
||||
|
||||
|
||||
@@ -29,6 +29,8 @@ import componentBindingDialogDef from '@/components/json-definitions/component-b
|
||||
import dataSourceEditorDialogDef from '@/components/json-definitions/data-source-editor-dialog.json'
|
||||
import githubBuildStatusDef from '@/components/json-definitions/github-build-status.json'
|
||||
import saveIndicatorDef from '@/components/json-definitions/save-indicator.json'
|
||||
import componentTreeDef from '@/components/json-definitions/component-tree.json'
|
||||
import seedDataManagerDef from '@/components/json-definitions/seed-data-manager.json'
|
||||
|
||||
// Create pure JSON components (no hooks)
|
||||
export const LoadingFallback = createJsonComponent<LoadingFallbackProps>(loadingFallbackDef)
|
||||
@@ -37,6 +39,7 @@ export const PageHeaderContent = createJsonComponent<PageHeaderContentProps>(pag
|
||||
export const ComponentBindingDialog = createJsonComponent<ComponentBindingDialogProps>(componentBindingDialogDef)
|
||||
export const DataSourceEditorDialog = createJsonComponent<DataSourceEditorDialogProps>(dataSourceEditorDialogDef)
|
||||
export const GitHubBuildStatus = createJsonComponent<GitHubBuildStatusProps>(githubBuildStatusDef)
|
||||
export const SeedDataManager = createJsonComponent<SeedDataManagerProps>(seedDataManagerDef)
|
||||
|
||||
// Create JSON components with hooks
|
||||
export const SaveIndicator = createJsonComponentWithHooks<SaveIndicatorProps>(saveIndicatorDef, {
|
||||
@@ -48,10 +51,17 @@ export const SaveIndicator = createJsonComponentWithHooks<SaveIndicatorProps>(sa
|
||||
}
|
||||
})
|
||||
|
||||
export const ComponentTree = createJsonComponentWithHooks<ComponentTreeProps>(componentTreeDef, {
|
||||
hooks: {
|
||||
treeData: {
|
||||
hookName: 'useComponentTree',
|
||||
args: (props) => [props.components || [], props.selectedId || null]
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
// Note: The following still need JSON definitions created:
|
||||
// - LazyBarChart (needs Recharts integration)
|
||||
// - LazyLineChart (needs Recharts integration)
|
||||
// - LazyD3BarChart (needs D3 integration)
|
||||
// - SeedDataManager (complex multi-button component)
|
||||
// - StorageSettings (complex form component)
|
||||
// - ComponentTree (needs recursive rendering support)
|
||||
// - StorageSettings (complex form with backend switching)
|
||||
// - LazyBarChart (Recharts integration)
|
||||
// - LazyLineChart (Recharts integration)
|
||||
// - LazyD3BarChart (D3 calculations - hook created, needs JSON definition)
|
||||
|
||||
Reference in New Issue
Block a user