diff --git a/src/components/DataBindingDesigner.tsx b/src/components/DataBindingDesigner.tsx index 1c32c81..b2fa87a 100644 --- a/src/components/DataBindingDesigner.tsx +++ b/src/components/DataBindingDesigner.tsx @@ -7,30 +7,9 @@ import { ComponentBindingsCard } from '@/components/data-binding-designer/Compon import { HowItWorksCard } from '@/components/data-binding-designer/HowItWorksCard' import dataBindingCopy from '@/data/data-binding-designer.json' -interface SeedDataSource extends Omit { - computeId?: string -} - -const computeRegistry: Record) => any> = { - displayName: (data) => `Welcome, ${data.userProfile?.name || 'Guest'}!`, -} - -const buildSeedDataSources = (sources: SeedDataSource[]): DataSource[] => { - return sources.map((source) => { - if (source.type === 'computed' && source.computeId) { - return { - ...source, - compute: computeRegistry[source.computeId], - } - } - - return source - }) -} - export function DataBindingDesigner() { const [dataSources, setDataSources] = useState( - buildSeedDataSources(dataBindingCopy.seed.dataSources as SeedDataSource[]), + dataBindingCopy.seed.dataSources as DataSource[], ) const [mockComponents] = useState(dataBindingCopy.seed.components) diff --git a/src/components/ProjectDashboard.tsx b/src/components/ProjectDashboard.tsx index 3d72c11..7e7b733 100644 --- a/src/components/ProjectDashboard.tsx +++ b/src/components/ProjectDashboard.tsx @@ -45,11 +45,12 @@ function getCompletionMessage(score: number): string { } export function ProjectDashboard(props: ProjectDashboardProps) { + const completionSummary = calculateCompletionScore(props) + return ( ) } diff --git a/src/components/atoms/DataSourceBadge.tsx b/src/components/atoms/DataSourceBadge.tsx index 8d2b2de..0837490 100644 --- a/src/components/atoms/DataSourceBadge.tsx +++ b/src/components/atoms/DataSourceBadge.tsx @@ -1,6 +1,6 @@ import { Badge } from '@/components/ui/badge' import { DataSourceType } from '@/types/json-ui' -import { Database, Function, File } from '@phosphor-icons/react' +import { Database, File } from '@phosphor-icons/react' interface DataSourceBadgeProps { type: DataSourceType @@ -13,11 +13,6 @@ const dataSourceConfig = { label: 'KV Storage', className: 'bg-accent/20 text-accent border-accent/30' }, - computed: { - icon: Function, - label: 'Computed', - className: 'bg-primary/20 text-primary border-primary/30' - }, static: { icon: File, label: 'Static', diff --git a/src/components/json-page-renderer/SectionRenderer.tsx b/src/components/json-page-renderer/SectionRenderer.tsx index e698c50..17fbe00 100644 --- a/src/components/json-page-renderer/SectionRenderer.tsx +++ b/src/components/json-page-renderer/SectionRenderer.tsx @@ -5,6 +5,8 @@ import { Progress } from '@/components/ui/progress' import { StatCard } from '@/components/atoms' import { cn } from '@/lib/utils' import { getIcon, resolveBinding } from './utils' +import { evaluateBindingExpression } from '@/lib/json-ui/expression-helpers' +import { evaluateTemplate } from '@/lib/json-ui/expression-evaluator' import { LegacyPageSchema, PageSectionConfig } from './types' interface PageSectionRendererProps { @@ -107,8 +109,21 @@ function PageCard({ card, data, functions }: PageCardProps) { const icon = card.icon ? getIcon(card.icon) : null if (card.type === 'gradient-card') { - const computeFn = functions[card.dataSource?.compute] - const computedData = computeFn ? computeFn(data) : {} + const dataSource = card.dataSource + let computedData: Record = {} + + if (dataSource?.expression) { + const resolved = evaluateBindingExpression(dataSource.expression, data, { + fallback: {}, + label: `dashboard card (${card.id})`, + }) + computedData = resolved || {} + } else if (dataSource?.valueTemplate) { + computedData = evaluateTemplate(dataSource.valueTemplate, { data }) + } else if (dataSource?.compute) { + const computeFn = functions[dataSource.compute] + computedData = computeFn ? computeFn(data) : {} + } return ( diff --git a/src/components/molecules/DataSourceCard.tsx b/src/components/molecules/DataSourceCard.tsx index 2387604..57b6336 100644 --- a/src/components/molecules/DataSourceCard.tsx +++ b/src/components/molecules/DataSourceCard.tsx @@ -1,23 +1,15 @@ -import { Card, Badge, IconButton, Stack, Flex, Text } from '@/components/atoms' +import { Card, IconButton, Stack, Flex, Text } from '@/components/atoms' import { DataSourceBadge } from '@/components/atoms/DataSourceBadge' import { DataSource } from '@/types/json-ui' -import { Pencil, Trash, ArrowsDownUp } from '@phosphor-icons/react' +import { Pencil, Trash } from '@phosphor-icons/react' interface DataSourceCardProps { dataSource: DataSource - dependents?: DataSource[] onEdit: (id: string) => void onDelete: (id: string) => void } -export function DataSourceCard({ dataSource, dependents = [], onEdit, onDelete }: DataSourceCardProps) { - const getDependencyCount = () => { - if (dataSource.type === 'computed') { - return dataSource.dependencies?.length || 0 - } - return 0 - } - +export function DataSourceCard({ dataSource, onEdit, onDelete }: DataSourceCardProps) { const renderTypeSpecificInfo = () => { if (dataSource.type === 'kv') { return ( @@ -26,19 +18,7 @@ export function DataSourceCard({ dataSource, dependents = [], onEdit, onDelete } ) } - - if (dataSource.type === 'computed') { - const depCount = getDependencyCount() - return ( - - - - {depCount} {depCount === 1 ? 'dependency' : 'dependencies'} - - - ) - } - + return null } @@ -56,13 +36,6 @@ export function DataSourceCard({ dataSource, dependents = [], onEdit, onDelete } {renderTypeSpecificInfo()} - {dependents.length > 0 && ( -
- - Used by {dependents.length} computed {dependents.length === 1 ? 'source' : 'sources'} - -
- )} @@ -78,7 +51,6 @@ export function DataSourceCard({ dataSource, dependents = [], onEdit, onDelete } size="sm" onClick={() => onDelete(dataSource.id)} className="text-destructive hover:text-destructive" - disabled={dependents.length > 0} /> diff --git a/src/components/molecules/DataSourceEditorDialog.tsx b/src/components/molecules/DataSourceEditorDialog.tsx index 20de4ae..1fa2ced 100644 --- a/src/components/molecules/DataSourceEditorDialog.tsx +++ b/src/components/molecules/DataSourceEditorDialog.tsx @@ -5,14 +5,12 @@ import { DataSourceBadge } from '@/components/atoms/DataSourceBadge' import { DataSourceIdField } from '@/components/molecules/data-source-editor/DataSourceIdField' import { KvSourceFields } from '@/components/molecules/data-source-editor/KvSourceFields' import { StaticSourceFields } from '@/components/molecules/data-source-editor/StaticSourceFields' -import { ComputedSourceFields } from '@/components/molecules/data-source-editor/ComputedSourceFields' import dataSourceEditorCopy from '@/data/data-source-editor-dialog.json' import { useDataSourceEditor } from '@/hooks/data/use-data-source-editor' interface DataSourceEditorDialogProps { open: boolean dataSource: DataSource | null - allDataSources: DataSource[] onOpenChange: (open: boolean) => void onSave: (dataSource: DataSource) => void } @@ -20,19 +18,13 @@ interface DataSourceEditorDialogProps { export function DataSourceEditorDialog({ open, dataSource, - allDataSources, onOpenChange, onSave, }: DataSourceEditorDialogProps) { const { editingSource, updateField, - addDependency, - removeDependency, - availableDeps, - selectedDeps, - unselectedDeps, - } = useDataSourceEditor(dataSource, allDataSources) + } = useDataSourceEditor(dataSource) const handleSave = () => { if (!editingSource) return @@ -80,18 +72,6 @@ export function DataSourceEditorDialog({ /> )} - {editingSource.type === 'computed' && ( - - )} diff --git a/src/components/molecules/data-source-editor/ComputedSourceFields.tsx b/src/components/molecules/data-source-editor/ComputedSourceFields.tsx deleted file mode 100644 index 17019ec..0000000 --- a/src/components/molecules/data-source-editor/ComputedSourceFields.tsx +++ /dev/null @@ -1,110 +0,0 @@ -import { Button } from '@/components/ui/button' -import { Label } from '@/components/ui/label' -import { Textarea } from '@/components/ui/textarea' -import { Badge } from '@/components/ui/badge' -import { DataSource } from '@/types/json-ui' -import { X } from '@phosphor-icons/react' - -interface ComputedSourceFieldsCopy { - computeLabel: string - computePlaceholder: string - computeHelp: string - dependenciesLabel: string - availableSourcesLabel: string - emptyDependencies: string -} - -interface ComputedSourceFieldsProps { - editingSource: DataSource - availableDeps: DataSource[] - selectedDeps: string[] - unselectedDeps: DataSource[] - copy: ComputedSourceFieldsCopy - onUpdateField: (field: K, value: DataSource[K]) => void - onAddDependency: (depId: string) => void - onRemoveDependency: (depId: string) => void -} - -export function ComputedSourceFields({ - editingSource, - availableDeps, - selectedDeps, - unselectedDeps, - copy, - onUpdateField, - onAddDependency, - onRemoveDependency, -}: ComputedSourceFieldsProps) { - return ( - <> -
- -