mirror of
https://github.com/johndoe6345789/low-code-react-app-b.git
synced 2026-04-24 13:44:54 +00:00
Merge pull request #140 from johndoe6345789/codex/identify-components-for-hooks-and-context
Add JSON wrappers for hook-dependent components and register them in the registry
This commit is contained in:
@@ -67,7 +67,20 @@
|
|||||||
"description": "ComponentBindingDialog component",
|
"description": "ComponentBindingDialog component",
|
||||||
"status": "supported",
|
"status": "supported",
|
||||||
"source": "molecules",
|
"source": "molecules",
|
||||||
"jsonCompatible": true
|
"jsonCompatible": false,
|
||||||
|
"wrapperRequired": true,
|
||||||
|
"wrapperComponent": "ComponentBindingDialogWrapper"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "ComponentBindingDialogWrapper",
|
||||||
|
"name": "ComponentBindingDialogWrapper",
|
||||||
|
"category": "layout",
|
||||||
|
"canHaveChildren": true,
|
||||||
|
"description": "JSON wrapper for component binding dialog with props-driven bindings",
|
||||||
|
"status": "json-compatible",
|
||||||
|
"source": "wrappers",
|
||||||
|
"jsonCompatible": true,
|
||||||
|
"wrapperFor": "ComponentBindingDialog"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"type": "Container",
|
"type": "Container",
|
||||||
@@ -96,7 +109,20 @@
|
|||||||
"description": "DataSourceEditorDialog component",
|
"description": "DataSourceEditorDialog component",
|
||||||
"status": "supported",
|
"status": "supported",
|
||||||
"source": "molecules",
|
"source": "molecules",
|
||||||
"jsonCompatible": true
|
"jsonCompatible": false,
|
||||||
|
"wrapperRequired": true,
|
||||||
|
"wrapperComponent": "DataSourceEditorDialogWrapper"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "DataSourceEditorDialogWrapper",
|
||||||
|
"name": "DataSourceEditorDialogWrapper",
|
||||||
|
"category": "layout",
|
||||||
|
"canHaveChildren": true,
|
||||||
|
"description": "JSON wrapper for data source editor dialog with props-driven fields",
|
||||||
|
"status": "json-compatible",
|
||||||
|
"source": "wrappers",
|
||||||
|
"jsonCompatible": true,
|
||||||
|
"wrapperFor": "DataSourceEditorDialog"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"type": "Dialog",
|
"type": "Dialog",
|
||||||
@@ -893,7 +919,20 @@
|
|||||||
"description": "GitHubBuildStatus component",
|
"description": "GitHubBuildStatus component",
|
||||||
"status": "supported",
|
"status": "supported",
|
||||||
"source": "molecules",
|
"source": "molecules",
|
||||||
"jsonCompatible": false
|
"jsonCompatible": false,
|
||||||
|
"wrapperRequired": true,
|
||||||
|
"wrapperComponent": "GitHubBuildStatusWrapper"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "GitHubBuildStatusWrapper",
|
||||||
|
"name": "GitHubBuildStatusWrapper",
|
||||||
|
"category": "feedback",
|
||||||
|
"canHaveChildren": false,
|
||||||
|
"description": "JSON wrapper for props-driven GitHub build status summary",
|
||||||
|
"status": "json-compatible",
|
||||||
|
"source": "wrappers",
|
||||||
|
"jsonCompatible": true,
|
||||||
|
"wrapperFor": "GitHubBuildStatus"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"type": "InfoBox",
|
"type": "InfoBox",
|
||||||
@@ -1039,30 +1078,69 @@
|
|||||||
"name": "LazyBarChart",
|
"name": "LazyBarChart",
|
||||||
"category": "data",
|
"category": "data",
|
||||||
"canHaveChildren": true,
|
"canHaveChildren": true,
|
||||||
|
"description": "Lazy-loaded Recharts bar chart with runtime library loading",
|
||||||
|
"status": "supported",
|
||||||
|
"source": "molecules",
|
||||||
|
"jsonCompatible": false,
|
||||||
|
"wrapperRequired": true,
|
||||||
|
"wrapperComponent": "LazyBarChartWrapper"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "LazyBarChartWrapper",
|
||||||
|
"name": "LazyBarChartWrapper",
|
||||||
|
"category": "data",
|
||||||
|
"canHaveChildren": true,
|
||||||
"description": "JSON wrapper for a props-driven bar chart (no lazy hooks)",
|
"description": "JSON wrapper for a props-driven bar chart (no lazy hooks)",
|
||||||
"status": "json-compatible",
|
"status": "json-compatible",
|
||||||
"source": "molecules",
|
"source": "wrappers",
|
||||||
"jsonCompatible": true
|
"jsonCompatible": true,
|
||||||
|
"wrapperFor": "LazyBarChart"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"type": "LazyD3BarChart",
|
"type": "LazyD3BarChart",
|
||||||
"name": "LazyD3BarChart",
|
"name": "LazyD3BarChart",
|
||||||
"category": "data",
|
"category": "data",
|
||||||
"canHaveChildren": true,
|
"canHaveChildren": true,
|
||||||
|
"description": "Lazy-loaded D3 bar chart with runtime library loading",
|
||||||
|
"status": "supported",
|
||||||
|
"source": "molecules",
|
||||||
|
"jsonCompatible": false,
|
||||||
|
"wrapperRequired": true,
|
||||||
|
"wrapperComponent": "LazyD3BarChartWrapper"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "LazyD3BarChartWrapper",
|
||||||
|
"name": "LazyD3BarChartWrapper",
|
||||||
|
"category": "data",
|
||||||
|
"canHaveChildren": true,
|
||||||
"description": "JSON wrapper for a simple SVG bar chart (no D3 hooks)",
|
"description": "JSON wrapper for a simple SVG bar chart (no D3 hooks)",
|
||||||
"status": "json-compatible",
|
"status": "json-compatible",
|
||||||
"source": "molecules",
|
"source": "wrappers",
|
||||||
"jsonCompatible": true
|
"jsonCompatible": true,
|
||||||
|
"wrapperFor": "LazyD3BarChart"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"type": "LazyLineChart",
|
"type": "LazyLineChart",
|
||||||
"name": "LazyLineChart",
|
"name": "LazyLineChart",
|
||||||
"category": "data",
|
"category": "data",
|
||||||
"canHaveChildren": true,
|
"canHaveChildren": true,
|
||||||
|
"description": "Lazy-loaded Recharts line chart with runtime library loading",
|
||||||
|
"status": "supported",
|
||||||
|
"source": "molecules",
|
||||||
|
"jsonCompatible": false,
|
||||||
|
"wrapperRequired": true,
|
||||||
|
"wrapperComponent": "LazyLineChartWrapper"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "LazyLineChartWrapper",
|
||||||
|
"name": "LazyLineChartWrapper",
|
||||||
|
"category": "data",
|
||||||
|
"canHaveChildren": true,
|
||||||
"description": "JSON wrapper for a props-driven line chart (no lazy hooks)",
|
"description": "JSON wrapper for a props-driven line chart (no lazy hooks)",
|
||||||
"status": "json-compatible",
|
"status": "json-compatible",
|
||||||
"source": "molecules",
|
"source": "wrappers",
|
||||||
"jsonCompatible": true
|
"jsonCompatible": true,
|
||||||
|
"wrapperFor": "LazyLineChart"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"type": "List",
|
"type": "List",
|
||||||
@@ -1105,10 +1183,23 @@
|
|||||||
"name": "SeedDataManager",
|
"name": "SeedDataManager",
|
||||||
"category": "data",
|
"category": "data",
|
||||||
"canHaveChildren": true,
|
"canHaveChildren": true,
|
||||||
|
"description": "Seed data management with app-level hook state",
|
||||||
|
"status": "supported",
|
||||||
|
"source": "molecules",
|
||||||
|
"jsonCompatible": false,
|
||||||
|
"wrapperRequired": true,
|
||||||
|
"wrapperComponent": "SeedDataManagerWrapper"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "SeedDataManagerWrapper",
|
||||||
|
"name": "SeedDataManagerWrapper",
|
||||||
|
"category": "data",
|
||||||
|
"canHaveChildren": true,
|
||||||
"description": "JSON wrapper for seed data management with props-driven state",
|
"description": "JSON wrapper for seed data management with props-driven state",
|
||||||
"status": "json-compatible",
|
"status": "json-compatible",
|
||||||
"source": "molecules",
|
"source": "wrappers",
|
||||||
"jsonCompatible": true
|
"jsonCompatible": true,
|
||||||
|
"wrapperFor": "SeedDataManager"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"type": "StatCard",
|
"type": "StatCard",
|
||||||
@@ -1337,7 +1428,20 @@
|
|||||||
"description": "ComponentTree component",
|
"description": "ComponentTree component",
|
||||||
"status": "supported",
|
"status": "supported",
|
||||||
"source": "molecules",
|
"source": "molecules",
|
||||||
"jsonCompatible": true
|
"jsonCompatible": false,
|
||||||
|
"wrapperRequired": true,
|
||||||
|
"wrapperComponent": "ComponentTreeWrapper"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "ComponentTreeWrapper",
|
||||||
|
"name": "ComponentTreeWrapper",
|
||||||
|
"category": "custom",
|
||||||
|
"canHaveChildren": true,
|
||||||
|
"description": "JSON wrapper for a props-driven component tree view",
|
||||||
|
"status": "json-compatible",
|
||||||
|
"source": "wrappers",
|
||||||
|
"jsonCompatible": true,
|
||||||
|
"wrapperFor": "ComponentTree"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"type": "ComponentTreeNode",
|
"type": "ComponentTreeNode",
|
||||||
@@ -1564,10 +1668,23 @@
|
|||||||
"name": "SaveIndicator",
|
"name": "SaveIndicator",
|
||||||
"category": "custom",
|
"category": "custom",
|
||||||
"canHaveChildren": true,
|
"canHaveChildren": true,
|
||||||
|
"description": "Save status indicator with hook-driven state",
|
||||||
|
"status": "supported",
|
||||||
|
"source": "molecules",
|
||||||
|
"jsonCompatible": false,
|
||||||
|
"wrapperRequired": true,
|
||||||
|
"wrapperComponent": "SaveIndicatorWrapper"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "SaveIndicatorWrapper",
|
||||||
|
"name": "SaveIndicatorWrapper",
|
||||||
|
"category": "custom",
|
||||||
|
"canHaveChildren": true,
|
||||||
"description": "JSON wrapper for save status indicator with pure-props API",
|
"description": "JSON wrapper for save status indicator with pure-props API",
|
||||||
"status": "json-compatible",
|
"status": "json-compatible",
|
||||||
"source": "molecules",
|
"source": "wrappers",
|
||||||
"jsonCompatible": true
|
"jsonCompatible": true,
|
||||||
|
"wrapperFor": "SaveIndicator"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"type": "SchemaEditorCanvas",
|
"type": "SchemaEditorCanvas",
|
||||||
@@ -1715,10 +1832,23 @@
|
|||||||
"name": "StorageSettings",
|
"name": "StorageSettings",
|
||||||
"category": "custom",
|
"category": "custom",
|
||||||
"canHaveChildren": true,
|
"canHaveChildren": true,
|
||||||
|
"description": "Storage settings controls with hook-driven state",
|
||||||
|
"status": "supported",
|
||||||
|
"source": "molecules",
|
||||||
|
"jsonCompatible": false,
|
||||||
|
"wrapperRequired": true,
|
||||||
|
"wrapperComponent": "StorageSettingsWrapper"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "StorageSettingsWrapper",
|
||||||
|
"name": "StorageSettingsWrapper",
|
||||||
|
"category": "custom",
|
||||||
|
"canHaveChildren": true,
|
||||||
"description": "JSON wrapper for storage settings controls with props-driven state",
|
"description": "JSON wrapper for storage settings controls with props-driven state",
|
||||||
"status": "json-compatible",
|
"status": "json-compatible",
|
||||||
"source": "molecules",
|
"source": "wrappers",
|
||||||
"jsonCompatible": true
|
"jsonCompatible": true,
|
||||||
|
"wrapperFor": "StorageSettings"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"type": "Timestamp",
|
"type": "Timestamp",
|
||||||
|
|||||||
@@ -265,12 +265,20 @@ export function registerComponent(name: string, component: ComponentType<any>) {
|
|||||||
uiComponentRegistry[name] = component
|
uiComponentRegistry[name] = component
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const resolveWrapperComponent = (type: string): ComponentType<any> | null => {
|
||||||
|
const entry = registryEntryByType.get(type)
|
||||||
|
if (entry?.wrapperRequired && entry.wrapperComponent) {
|
||||||
|
return uiComponentRegistry[entry.wrapperComponent] || null
|
||||||
|
}
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
export function getUIComponent(type: string): ComponentType<any> | string | null {
|
export function getUIComponent(type: string): ComponentType<any> | string | null {
|
||||||
return uiComponentRegistry[type] || null
|
return resolveWrapperComponent(type) ?? uiComponentRegistry[type] ?? null
|
||||||
}
|
}
|
||||||
|
|
||||||
export function hasComponent(type: string): boolean {
|
export function hasComponent(type: string): boolean {
|
||||||
return type in uiComponentRegistry
|
return Boolean(resolveWrapperComponent(type) ?? uiComponentRegistry[type])
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getDeprecatedComponentInfo(type: string): DeprecatedComponentInfo | null {
|
export function getDeprecatedComponentInfo(type: string): DeprecatedComponentInfo | null {
|
||||||
|
|||||||
@@ -205,6 +205,11 @@ export function ComponentRenderer({ component, data, context = {}, state, onEven
|
|||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const resolvedChildren = component.children ?? resolvedProps.children
|
||||||
|
if (resolvedChildren !== undefined && resolvedChildren !== component.children) {
|
||||||
|
delete resolvedProps.children
|
||||||
|
}
|
||||||
|
|
||||||
if (component.loop) {
|
if (component.loop) {
|
||||||
const items = resolveDataBinding(component.loop.source, data, context, { state, bindings: context }) || []
|
const items = resolveDataBinding(component.loop.source, data, context, { state, bindings: context }) || []
|
||||||
const loopChildren = items.map((item: unknown, index: number) => {
|
const loopChildren = items.map((item: unknown, index: number) => {
|
||||||
@@ -232,7 +237,7 @@ export function ComponentRenderer({ component, data, context = {}, state, onEven
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<Fragment key={`${component.id}-${index}`}>
|
<Fragment key={`${component.id}-${index}`}>
|
||||||
{renderChildren(component.children, loopContext)}
|
{renderChildren(resolvedChildren as UIComponent[] | string | undefined, loopContext)}
|
||||||
</Fragment>
|
</Fragment>
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
@@ -254,5 +259,9 @@ export function ComponentRenderer({ component, data, context = {}, state, onEven
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return createElement(Component, resolvedProps, renderChildren(component.children, context))
|
return createElement(
|
||||||
|
Component,
|
||||||
|
resolvedProps,
|
||||||
|
renderChildren(resolvedChildren as UIComponent[] | string | undefined, context)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
47
src/lib/json-ui/wrappers/ComponentBindingDialogWrapper.tsx
Normal file
47
src/lib/json-ui/wrappers/ComponentBindingDialogWrapper.tsx
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
import type { ChangeEvent } from 'react'
|
||||||
|
import { ComponentRenderer } from '@/lib/json-ui/component-renderer'
|
||||||
|
import { cn } from '@/lib/utils'
|
||||||
|
import componentBindingDialogDefinition from './definitions/component-binding-dialog.json'
|
||||||
|
import type { ComponentBindingDialogWrapperProps } from './interfaces'
|
||||||
|
|
||||||
|
export function ComponentBindingDialogWrapper({
|
||||||
|
open = false,
|
||||||
|
title = 'Component Bindings',
|
||||||
|
description = 'Connect component props to data sources.',
|
||||||
|
componentType,
|
||||||
|
componentId,
|
||||||
|
bindings = [],
|
||||||
|
onBindingChange,
|
||||||
|
onSave,
|
||||||
|
onCancel,
|
||||||
|
onOpenChange,
|
||||||
|
className,
|
||||||
|
}: ComponentBindingDialogWrapperProps) {
|
||||||
|
const handleBindingFieldChange = (event: ChangeEvent<HTMLInputElement>) => {
|
||||||
|
const fieldId = event.currentTarget?.dataset?.fieldId || event.target?.dataset?.fieldId
|
||||||
|
if (!fieldId) return
|
||||||
|
onBindingChange?.(fieldId, event.target.value)
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<ComponentRenderer
|
||||||
|
component={componentBindingDialogDefinition}
|
||||||
|
data={{
|
||||||
|
open,
|
||||||
|
title,
|
||||||
|
description,
|
||||||
|
componentType,
|
||||||
|
componentId,
|
||||||
|
bindingFields: bindings,
|
||||||
|
emptyMessage: 'No bindings configured.',
|
||||||
|
contentClassName: cn('max-w-2xl', className),
|
||||||
|
onBindingFieldChange: handleBindingFieldChange,
|
||||||
|
onSave,
|
||||||
|
onCancel,
|
||||||
|
onOpenChange,
|
||||||
|
cancelLabel: 'Cancel',
|
||||||
|
saveLabel: 'Save',
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
}
|
||||||
55
src/lib/json-ui/wrappers/ComponentTreeWrapper.tsx
Normal file
55
src/lib/json-ui/wrappers/ComponentTreeWrapper.tsx
Normal file
@@ -0,0 +1,55 @@
|
|||||||
|
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>
|
||||||
|
)
|
||||||
|
}
|
||||||
43
src/lib/json-ui/wrappers/DataSourceEditorDialogWrapper.tsx
Normal file
43
src/lib/json-ui/wrappers/DataSourceEditorDialogWrapper.tsx
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
import type { ChangeEvent } from 'react'
|
||||||
|
import { ComponentRenderer } from '@/lib/json-ui/component-renderer'
|
||||||
|
import { cn } from '@/lib/utils'
|
||||||
|
import dataSourceEditorDialogDefinition from './definitions/data-source-editor-dialog.json'
|
||||||
|
import type { DataSourceEditorDialogWrapperProps } from './interfaces'
|
||||||
|
|
||||||
|
export function DataSourceEditorDialogWrapper({
|
||||||
|
open = false,
|
||||||
|
title = 'Data Source',
|
||||||
|
description = 'Update data source details and fields.',
|
||||||
|
fields = [],
|
||||||
|
onFieldChange,
|
||||||
|
onSave,
|
||||||
|
onCancel,
|
||||||
|
onOpenChange,
|
||||||
|
className,
|
||||||
|
}: DataSourceEditorDialogWrapperProps) {
|
||||||
|
const handleFieldChange = (event: ChangeEvent<HTMLInputElement>) => {
|
||||||
|
const fieldId = event.currentTarget?.dataset?.fieldId || event.target?.dataset?.fieldId
|
||||||
|
if (!fieldId) return
|
||||||
|
onFieldChange?.(fieldId, event.target.value)
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<ComponentRenderer
|
||||||
|
component={dataSourceEditorDialogDefinition}
|
||||||
|
data={{
|
||||||
|
open,
|
||||||
|
title,
|
||||||
|
description,
|
||||||
|
fields,
|
||||||
|
emptyMessage: 'No fields configured.',
|
||||||
|
contentClassName: cn('max-w-2xl', className),
|
||||||
|
onFieldChange: handleFieldChange,
|
||||||
|
onSave,
|
||||||
|
onCancel,
|
||||||
|
onOpenChange,
|
||||||
|
cancelLabel: 'Cancel',
|
||||||
|
saveLabel: 'Save',
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
}
|
||||||
64
src/lib/json-ui/wrappers/GitHubBuildStatusWrapper.tsx
Normal file
64
src/lib/json-ui/wrappers/GitHubBuildStatusWrapper.tsx
Normal file
@@ -0,0 +1,64 @@
|
|||||||
|
import { ComponentRenderer } from '@/lib/json-ui/component-renderer'
|
||||||
|
import { cn } from '@/lib/utils'
|
||||||
|
import gitHubBuildStatusDefinition from './definitions/github-build-status.json'
|
||||||
|
import type { GitHubBuildStatusWrapperProps, GitHubBuildStatusWorkflowItem } from './interfaces'
|
||||||
|
|
||||||
|
const getWorkflowStatus = (workflow: GitHubBuildStatusWorkflowItem) => {
|
||||||
|
if (workflow.status === 'completed') {
|
||||||
|
if (workflow.conclusion === 'success') {
|
||||||
|
return {
|
||||||
|
label: 'Success',
|
||||||
|
className: 'bg-green-500/10 text-green-600 border-green-500/20',
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (workflow.conclusion === 'failure') {
|
||||||
|
return { label: 'Failed', className: 'bg-red-500/10 text-red-600 border-red-500/20' }
|
||||||
|
}
|
||||||
|
if (workflow.conclusion === 'cancelled') {
|
||||||
|
return { label: 'Cancelled', className: 'bg-yellow-500/10 text-yellow-600 border-yellow-500/20' }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return { label: 'Running', className: 'border-blue-500/50 text-blue-500' }
|
||||||
|
}
|
||||||
|
|
||||||
|
export function GitHubBuildStatusWrapper({
|
||||||
|
title = 'GitHub Build Status',
|
||||||
|
description = 'Latest workflow runs and status badges.',
|
||||||
|
workflows = [],
|
||||||
|
isLoading = false,
|
||||||
|
errorMessage,
|
||||||
|
emptyMessage = 'No workflows to display yet.',
|
||||||
|
footerLinkLabel = 'View on GitHub',
|
||||||
|
footerLinkUrl,
|
||||||
|
className,
|
||||||
|
}: GitHubBuildStatusWrapperProps) {
|
||||||
|
const normalizedWorkflows = workflows.map((workflow) => {
|
||||||
|
const status = getWorkflowStatus(workflow)
|
||||||
|
return {
|
||||||
|
...workflow,
|
||||||
|
statusLabel: status.label,
|
||||||
|
statusClass: status.className,
|
||||||
|
summaryLine: [workflow.branch, workflow.updatedAt, workflow.event].filter(Boolean).join(' • '),
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
return (
|
||||||
|
<ComponentRenderer
|
||||||
|
component={gitHubBuildStatusDefinition}
|
||||||
|
data={{
|
||||||
|
title,
|
||||||
|
description,
|
||||||
|
workflows: normalizedWorkflows,
|
||||||
|
isLoading,
|
||||||
|
errorMessage,
|
||||||
|
emptyMessage,
|
||||||
|
loadingMessage: 'Loading workflows…',
|
||||||
|
hasWorkflows: normalizedWorkflows.length > 0,
|
||||||
|
footerLinkLabel,
|
||||||
|
footerLinkUrl,
|
||||||
|
className: cn(className),
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
}
|
||||||
@@ -0,0 +1,200 @@
|
|||||||
|
{
|
||||||
|
"id": "component-binding-dialog",
|
||||||
|
"type": "Dialog",
|
||||||
|
"bindings": {
|
||||||
|
"open": "open",
|
||||||
|
"onOpenChange": "onOpenChange"
|
||||||
|
},
|
||||||
|
"children": [
|
||||||
|
{
|
||||||
|
"id": "component-binding-dialog-content",
|
||||||
|
"type": "DialogContent",
|
||||||
|
"bindings": {
|
||||||
|
"className": "contentClassName"
|
||||||
|
},
|
||||||
|
"children": [
|
||||||
|
{
|
||||||
|
"id": "component-binding-dialog-header",
|
||||||
|
"type": "DialogHeader",
|
||||||
|
"children": [
|
||||||
|
{
|
||||||
|
"id": "component-binding-dialog-title",
|
||||||
|
"type": "DialogTitle",
|
||||||
|
"bindings": {
|
||||||
|
"children": "title"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "component-binding-dialog-description",
|
||||||
|
"type": "DialogDescription",
|
||||||
|
"bindings": {
|
||||||
|
"children": "description"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "component-binding-dialog-info",
|
||||||
|
"type": "div",
|
||||||
|
"props": {
|
||||||
|
"className": "rounded-md border border-border bg-muted/30 p-3 text-sm"
|
||||||
|
},
|
||||||
|
"conditional": {
|
||||||
|
"if": "componentType || componentId"
|
||||||
|
},
|
||||||
|
"children": [
|
||||||
|
{
|
||||||
|
"id": "component-binding-dialog-type",
|
||||||
|
"type": "div",
|
||||||
|
"props": {
|
||||||
|
"className": "flex items-center gap-2"
|
||||||
|
},
|
||||||
|
"conditional": {
|
||||||
|
"if": "componentType"
|
||||||
|
},
|
||||||
|
"children": [
|
||||||
|
{
|
||||||
|
"id": "component-binding-dialog-type-label",
|
||||||
|
"type": "span",
|
||||||
|
"props": {
|
||||||
|
"className": "text-muted-foreground"
|
||||||
|
},
|
||||||
|
"children": "Component:"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "component-binding-dialog-type-value",
|
||||||
|
"type": "span",
|
||||||
|
"props": {
|
||||||
|
"className": "font-mono font-medium"
|
||||||
|
},
|
||||||
|
"bindings": {
|
||||||
|
"children": "componentType"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "component-binding-dialog-id",
|
||||||
|
"type": "div",
|
||||||
|
"props": {
|
||||||
|
"className": "flex items-center gap-2"
|
||||||
|
},
|
||||||
|
"conditional": {
|
||||||
|
"if": "componentId"
|
||||||
|
},
|
||||||
|
"children": [
|
||||||
|
{
|
||||||
|
"id": "component-binding-dialog-id-label",
|
||||||
|
"type": "span",
|
||||||
|
"props": {
|
||||||
|
"className": "text-muted-foreground"
|
||||||
|
},
|
||||||
|
"children": "ID:"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "component-binding-dialog-id-value",
|
||||||
|
"type": "span",
|
||||||
|
"props": {
|
||||||
|
"className": "font-mono text-xs"
|
||||||
|
},
|
||||||
|
"bindings": {
|
||||||
|
"children": "componentId"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "component-binding-dialog-body",
|
||||||
|
"type": "div",
|
||||||
|
"props": {
|
||||||
|
"className": "space-y-4"
|
||||||
|
},
|
||||||
|
"children": [
|
||||||
|
{
|
||||||
|
"id": "component-binding-dialog-empty",
|
||||||
|
"type": "p",
|
||||||
|
"props": {
|
||||||
|
"className": "text-sm text-muted-foreground"
|
||||||
|
},
|
||||||
|
"bindings": {
|
||||||
|
"children": "emptyMessage"
|
||||||
|
},
|
||||||
|
"conditional": {
|
||||||
|
"if": "!bindingFields || bindingFields.length === 0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "component-binding-dialog-fields",
|
||||||
|
"type": "div",
|
||||||
|
"props": {
|
||||||
|
"className": "space-y-4"
|
||||||
|
},
|
||||||
|
"conditional": {
|
||||||
|
"if": "bindingFields && bindingFields.length > 0"
|
||||||
|
},
|
||||||
|
"loop": {
|
||||||
|
"source": "bindingFields",
|
||||||
|
"itemVar": "field"
|
||||||
|
},
|
||||||
|
"children": [
|
||||||
|
{
|
||||||
|
"id": "component-binding-dialog-field",
|
||||||
|
"type": "div",
|
||||||
|
"props": {
|
||||||
|
"className": "space-y-2"
|
||||||
|
},
|
||||||
|
"children": [
|
||||||
|
{
|
||||||
|
"id": "component-binding-dialog-field-label",
|
||||||
|
"type": "Label",
|
||||||
|
"bindings": {
|
||||||
|
"children": "field.label"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "component-binding-dialog-field-input",
|
||||||
|
"type": "Input",
|
||||||
|
"bindings": {
|
||||||
|
"value": "field.value",
|
||||||
|
"placeholder": "field.placeholder",
|
||||||
|
"onChange": "onBindingFieldChange",
|
||||||
|
"data-field-id": "field.id"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "component-binding-dialog-footer",
|
||||||
|
"type": "DialogFooter",
|
||||||
|
"children": [
|
||||||
|
{
|
||||||
|
"id": "component-binding-dialog-cancel",
|
||||||
|
"type": "Button",
|
||||||
|
"props": {
|
||||||
|
"variant": "outline"
|
||||||
|
},
|
||||||
|
"bindings": {
|
||||||
|
"onClick": "onCancel",
|
||||||
|
"children": "cancelLabel"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "component-binding-dialog-save",
|
||||||
|
"type": "Button",
|
||||||
|
"bindings": {
|
||||||
|
"onClick": "onSave",
|
||||||
|
"children": "saveLabel"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
@@ -0,0 +1,141 @@
|
|||||||
|
{
|
||||||
|
"id": "data-source-editor-dialog",
|
||||||
|
"type": "Dialog",
|
||||||
|
"bindings": {
|
||||||
|
"open": "open",
|
||||||
|
"onOpenChange": "onOpenChange"
|
||||||
|
},
|
||||||
|
"children": [
|
||||||
|
{
|
||||||
|
"id": "data-source-editor-dialog-content",
|
||||||
|
"type": "DialogContent",
|
||||||
|
"bindings": {
|
||||||
|
"className": "contentClassName"
|
||||||
|
},
|
||||||
|
"children": [
|
||||||
|
{
|
||||||
|
"id": "data-source-editor-dialog-header",
|
||||||
|
"type": "DialogHeader",
|
||||||
|
"children": [
|
||||||
|
{
|
||||||
|
"id": "data-source-editor-dialog-title",
|
||||||
|
"type": "DialogTitle",
|
||||||
|
"bindings": {
|
||||||
|
"children": "title"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "data-source-editor-dialog-description",
|
||||||
|
"type": "DialogDescription",
|
||||||
|
"bindings": {
|
||||||
|
"children": "description"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "data-source-editor-dialog-body",
|
||||||
|
"type": "div",
|
||||||
|
"props": {
|
||||||
|
"className": "space-y-4"
|
||||||
|
},
|
||||||
|
"children": [
|
||||||
|
{
|
||||||
|
"id": "data-source-editor-dialog-empty",
|
||||||
|
"type": "p",
|
||||||
|
"props": {
|
||||||
|
"className": "text-sm text-muted-foreground"
|
||||||
|
},
|
||||||
|
"bindings": {
|
||||||
|
"children": "emptyMessage"
|
||||||
|
},
|
||||||
|
"conditional": {
|
||||||
|
"if": "!fields || fields.length === 0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "data-source-editor-dialog-fields",
|
||||||
|
"type": "div",
|
||||||
|
"props": {
|
||||||
|
"className": "space-y-4"
|
||||||
|
},
|
||||||
|
"conditional": {
|
||||||
|
"if": "fields && fields.length > 0"
|
||||||
|
},
|
||||||
|
"loop": {
|
||||||
|
"source": "fields",
|
||||||
|
"itemVar": "field"
|
||||||
|
},
|
||||||
|
"children": [
|
||||||
|
{
|
||||||
|
"id": "data-source-editor-dialog-field",
|
||||||
|
"type": "div",
|
||||||
|
"props": {
|
||||||
|
"className": "space-y-2"
|
||||||
|
},
|
||||||
|
"children": [
|
||||||
|
{
|
||||||
|
"id": "data-source-editor-dialog-field-label",
|
||||||
|
"type": "Label",
|
||||||
|
"bindings": {
|
||||||
|
"children": "field.label"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "data-source-editor-dialog-field-input",
|
||||||
|
"type": "Input",
|
||||||
|
"bindings": {
|
||||||
|
"value": "field.value",
|
||||||
|
"placeholder": "field.placeholder",
|
||||||
|
"onChange": "onFieldChange",
|
||||||
|
"data-field-id": "field.id"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "data-source-editor-dialog-field-helper",
|
||||||
|
"type": "p",
|
||||||
|
"props": {
|
||||||
|
"className": "text-xs text-muted-foreground"
|
||||||
|
},
|
||||||
|
"bindings": {
|
||||||
|
"children": "field.helperText"
|
||||||
|
},
|
||||||
|
"conditional": {
|
||||||
|
"if": "field.helperText"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "data-source-editor-dialog-footer",
|
||||||
|
"type": "DialogFooter",
|
||||||
|
"children": [
|
||||||
|
{
|
||||||
|
"id": "data-source-editor-dialog-cancel",
|
||||||
|
"type": "Button",
|
||||||
|
"props": {
|
||||||
|
"variant": "outline"
|
||||||
|
},
|
||||||
|
"bindings": {
|
||||||
|
"onClick": "onCancel",
|
||||||
|
"children": "cancelLabel"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "data-source-editor-dialog-save",
|
||||||
|
"type": "Button",
|
||||||
|
"bindings": {
|
||||||
|
"onClick": "onSave",
|
||||||
|
"children": "saveLabel"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
210
src/lib/json-ui/wrappers/definitions/github-build-status.json
Normal file
210
src/lib/json-ui/wrappers/definitions/github-build-status.json
Normal file
@@ -0,0 +1,210 @@
|
|||||||
|
{
|
||||||
|
"id": "github-build-status-card",
|
||||||
|
"type": "Card",
|
||||||
|
"bindings": {
|
||||||
|
"className": "className"
|
||||||
|
},
|
||||||
|
"children": [
|
||||||
|
{
|
||||||
|
"id": "github-build-status-header",
|
||||||
|
"type": "CardHeader",
|
||||||
|
"children": [
|
||||||
|
{
|
||||||
|
"id": "github-build-status-title",
|
||||||
|
"type": "CardTitle",
|
||||||
|
"props": {
|
||||||
|
"className": "flex items-center gap-2"
|
||||||
|
},
|
||||||
|
"bindings": {
|
||||||
|
"children": "title"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "github-build-status-description",
|
||||||
|
"type": "CardDescription",
|
||||||
|
"bindings": {
|
||||||
|
"children": "description"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "github-build-status-content",
|
||||||
|
"type": "CardContent",
|
||||||
|
"props": {
|
||||||
|
"className": "space-y-4"
|
||||||
|
},
|
||||||
|
"children": [
|
||||||
|
{
|
||||||
|
"id": "github-build-status-loading",
|
||||||
|
"type": "p",
|
||||||
|
"props": {
|
||||||
|
"className": "text-sm text-muted-foreground"
|
||||||
|
},
|
||||||
|
"bindings": {
|
||||||
|
"children": "loadingMessage"
|
||||||
|
},
|
||||||
|
"conditional": {
|
||||||
|
"if": "isLoading"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "github-build-status-error",
|
||||||
|
"type": "div",
|
||||||
|
"props": {
|
||||||
|
"className": "flex items-center gap-2 text-sm text-red-500"
|
||||||
|
},
|
||||||
|
"conditional": {
|
||||||
|
"if": "errorMessage"
|
||||||
|
},
|
||||||
|
"children": [
|
||||||
|
{
|
||||||
|
"id": "github-build-status-error-text",
|
||||||
|
"type": "span",
|
||||||
|
"bindings": {
|
||||||
|
"children": "errorMessage"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "github-build-status-empty",
|
||||||
|
"type": "p",
|
||||||
|
"props": {
|
||||||
|
"className": "text-sm text-muted-foreground"
|
||||||
|
},
|
||||||
|
"bindings": {
|
||||||
|
"children": "emptyMessage"
|
||||||
|
},
|
||||||
|
"conditional": {
|
||||||
|
"if": "!isLoading && !errorMessage && !hasWorkflows"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "github-build-status-list",
|
||||||
|
"type": "div",
|
||||||
|
"props": {
|
||||||
|
"className": "space-y-3"
|
||||||
|
},
|
||||||
|
"conditional": {
|
||||||
|
"if": "hasWorkflows"
|
||||||
|
},
|
||||||
|
"loop": {
|
||||||
|
"source": "workflows",
|
||||||
|
"itemVar": "workflow"
|
||||||
|
},
|
||||||
|
"children": [
|
||||||
|
{
|
||||||
|
"id": "github-build-status-item",
|
||||||
|
"type": "div",
|
||||||
|
"props": {
|
||||||
|
"className": "flex items-center justify-between gap-3 rounded-lg border border-border p-3"
|
||||||
|
},
|
||||||
|
"children": [
|
||||||
|
{
|
||||||
|
"id": "github-build-status-item-info",
|
||||||
|
"type": "div",
|
||||||
|
"props": {
|
||||||
|
"className": "min-w-0"
|
||||||
|
},
|
||||||
|
"children": [
|
||||||
|
{
|
||||||
|
"id": "github-build-status-item-row",
|
||||||
|
"type": "div",
|
||||||
|
"props": {
|
||||||
|
"className": "flex items-center gap-2"
|
||||||
|
},
|
||||||
|
"children": [
|
||||||
|
{
|
||||||
|
"id": "github-build-status-item-name",
|
||||||
|
"type": "p",
|
||||||
|
"props": {
|
||||||
|
"className": "text-sm font-medium truncate"
|
||||||
|
},
|
||||||
|
"bindings": {
|
||||||
|
"children": "workflow.name"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "github-build-status-item-badge",
|
||||||
|
"type": "Badge",
|
||||||
|
"bindings": {
|
||||||
|
"className": "workflow.statusClass",
|
||||||
|
"children": "workflow.statusLabel"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "github-build-status-item-meta",
|
||||||
|
"type": "div",
|
||||||
|
"props": {
|
||||||
|
"className": "text-xs text-muted-foreground truncate"
|
||||||
|
},
|
||||||
|
"bindings": {
|
||||||
|
"children": "workflow.summaryLine"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "github-build-status-item-link",
|
||||||
|
"type": "Button",
|
||||||
|
"props": {
|
||||||
|
"variant": "ghost",
|
||||||
|
"size": "sm",
|
||||||
|
"asChild": true
|
||||||
|
},
|
||||||
|
"conditional": {
|
||||||
|
"if": "workflow.url"
|
||||||
|
},
|
||||||
|
"children": [
|
||||||
|
{
|
||||||
|
"id": "github-build-status-item-anchor",
|
||||||
|
"type": "a",
|
||||||
|
"bindings": {
|
||||||
|
"href": "workflow.url"
|
||||||
|
},
|
||||||
|
"props": {
|
||||||
|
"target": "_blank",
|
||||||
|
"rel": "noopener noreferrer"
|
||||||
|
},
|
||||||
|
"children": "View"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "github-build-status-footer",
|
||||||
|
"type": "Button",
|
||||||
|
"props": {
|
||||||
|
"variant": "outline",
|
||||||
|
"size": "sm",
|
||||||
|
"asChild": true,
|
||||||
|
"className": "w-full"
|
||||||
|
},
|
||||||
|
"conditional": {
|
||||||
|
"if": "footerLinkUrl"
|
||||||
|
},
|
||||||
|
"children": [
|
||||||
|
{
|
||||||
|
"id": "github-build-status-footer-anchor",
|
||||||
|
"type": "a",
|
||||||
|
"bindings": {
|
||||||
|
"href": "footerLinkUrl",
|
||||||
|
"children": "footerLinkLabel"
|
||||||
|
},
|
||||||
|
"props": {
|
||||||
|
"target": "_blank",
|
||||||
|
"rel": "noopener noreferrer"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
@@ -5,3 +5,7 @@ export { LazyLineChartWrapper } from './LazyLineChartWrapper'
|
|||||||
export { LazyD3BarChartWrapper } from './LazyD3BarChartWrapper'
|
export { LazyD3BarChartWrapper } from './LazyD3BarChartWrapper'
|
||||||
export { SeedDataManagerWrapper } from './SeedDataManagerWrapper'
|
export { SeedDataManagerWrapper } from './SeedDataManagerWrapper'
|
||||||
export { StorageSettingsWrapper } from './StorageSettingsWrapper'
|
export { StorageSettingsWrapper } from './StorageSettingsWrapper'
|
||||||
|
export { GitHubBuildStatusWrapper } from './GitHubBuildStatusWrapper'
|
||||||
|
export { ComponentBindingDialogWrapper } from './ComponentBindingDialogWrapper'
|
||||||
|
export { DataSourceEditorDialogWrapper } from './DataSourceEditorDialogWrapper'
|
||||||
|
export { ComponentTreeWrapper } from './ComponentTreeWrapper'
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import type { StorageBackendKey } from '@/components/storage/storageSettingsConfig'
|
import type { StorageBackendKey } from '@/components/storage/storageSettingsConfig'
|
||||||
|
import type { UIComponent } from '@/types/json-ui'
|
||||||
|
|
||||||
export interface BreadcrumbItem {
|
export interface BreadcrumbItem {
|
||||||
label: string
|
label: string
|
||||||
@@ -89,3 +90,75 @@ export interface StorageSettingsWrapperProps {
|
|||||||
onExport?: () => void
|
onExport?: () => void
|
||||||
onImport?: () => void
|
onImport?: () => void
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface GitHubBuildStatusWorkflowItem {
|
||||||
|
id: string
|
||||||
|
name: string
|
||||||
|
status?: string
|
||||||
|
conclusion?: string | null
|
||||||
|
branch?: string
|
||||||
|
updatedAt?: string
|
||||||
|
event?: string
|
||||||
|
url?: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface GitHubBuildStatusWrapperProps {
|
||||||
|
title?: string
|
||||||
|
description?: string
|
||||||
|
workflows?: GitHubBuildStatusWorkflowItem[]
|
||||||
|
isLoading?: boolean
|
||||||
|
errorMessage?: string
|
||||||
|
emptyMessage?: string
|
||||||
|
footerLinkLabel?: string
|
||||||
|
footerLinkUrl?: string
|
||||||
|
className?: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ComponentBindingField {
|
||||||
|
id: string
|
||||||
|
label: string
|
||||||
|
value?: string
|
||||||
|
placeholder?: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ComponentBindingDialogWrapperProps {
|
||||||
|
open?: boolean
|
||||||
|
title?: string
|
||||||
|
description?: string
|
||||||
|
componentType?: string
|
||||||
|
componentId?: string
|
||||||
|
bindings?: ComponentBindingField[]
|
||||||
|
onBindingChange?: (id: string, value: string) => void
|
||||||
|
onSave?: () => void
|
||||||
|
onCancel?: () => void
|
||||||
|
onOpenChange?: (open: boolean) => void
|
||||||
|
className?: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface DataSourceField {
|
||||||
|
id: string
|
||||||
|
label: string
|
||||||
|
value?: string
|
||||||
|
placeholder?: string
|
||||||
|
helperText?: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface DataSourceEditorDialogWrapperProps {
|
||||||
|
open?: boolean
|
||||||
|
title?: string
|
||||||
|
description?: string
|
||||||
|
fields?: DataSourceField[]
|
||||||
|
onFieldChange?: (id: string, value: string) => void
|
||||||
|
onSave?: () => void
|
||||||
|
onCancel?: () => void
|
||||||
|
onOpenChange?: (open: boolean) => void
|
||||||
|
className?: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ComponentTreeWrapperProps {
|
||||||
|
components?: UIComponent[]
|
||||||
|
selectedId?: string | null
|
||||||
|
emptyMessage?: string
|
||||||
|
onSelect?: (id: string) => void
|
||||||
|
className?: string
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user