windsurf/converter/components/schema-definition.tsx
2024-11-20 18:27:41 -05:00

285 lines
7.4 KiB
TypeScript

'use client';
import { useState } from 'react';
import { Plus, Minus, ChevronDown, ChevronRight } from 'lucide-react';
import { Button } from './ui/button';
import { Input } from './ui/input';
import { Card } from './ui/card';
export interface SchemaField {
id: string;
name: string;
type: 'field' | 'group';
description: string;
fields?: SchemaField[];
}
const defaultSchema: SchemaField[] = [
{
id: '1',
name: 'company',
type: 'field',
description: 'name of company'
},
{
id: '2',
name: 'address',
type: 'field',
description: 'address of company'
},
{
id: '3',
name: 'total_sum',
type: 'field',
description: 'total amount we purchased'
},
{
id: '4',
name: 'items',
type: 'group',
description: 'list of items purchased',
fields: [
{
id: '4.1',
name: 'item',
type: 'field',
description: 'name of item'
},
{
id: '4.2',
name: 'unit_price',
type: 'field',
description: 'unit price of item'
},
{
id: '4.3',
name: 'quantity',
type: 'field',
description: 'quantity we purchased'
},
{
id: '4.4',
name: 'sum',
type: 'field',
description: 'total amount we purchased'
}
]
}
];
interface SchemaDefinitionProps {
onSchemaChange: (schema: SchemaField[]) => void;
}
export function SchemaDefinition({ onSchemaChange }: SchemaDefinitionProps) {
const [schema, setSchema] = useState<SchemaField[]>(defaultSchema);
const [expandedGroups, setExpandedGroups] = useState<Set<string>>(new Set(['4']));
const toggleGroup = (id: string) => {
setExpandedGroups(prev => {
const next = new Set(prev);
if (next.has(id)) {
next.delete(id);
} else {
next.add(id);
}
return next;
});
};
const addField = (parentId?: string) => {
const newField: SchemaField = {
id: Date.now().toString(),
name: '',
type: 'field',
description: ''
};
if (parentId) {
setSchema(prev => {
const updateFields = (fields: SchemaField[]): SchemaField[] => {
return fields.map(field => {
if (field.id === parentId) {
return {
...field,
fields: [...(field.fields || []), newField]
};
}
if (field.fields) {
return {
...field,
fields: updateFields(field.fields)
};
}
return field;
});
};
return updateFields(prev);
});
} else {
setSchema(prev => [...prev, newField]);
}
};
const addGroup = (parentId?: string) => {
const newGroup: SchemaField = {
id: Date.now().toString(),
name: '',
type: 'group',
description: '',
fields: []
};
if (parentId) {
setSchema(prev => {
const updateFields = (fields: SchemaField[]): SchemaField[] => {
return fields.map(field => {
if (field.id === parentId) {
return {
...field,
fields: [...(field.fields || []), newGroup]
};
}
if (field.fields) {
return {
...field,
fields: updateFields(field.fields)
};
}
return field;
});
};
return updateFields(prev);
});
} else {
setSchema(prev => [...prev, newGroup]);
}
setExpandedGroups(prev => new Set([...prev, newGroup.id]));
};
const removeField = (id: string) => {
const removeFieldFromArray = (fields: SchemaField[]): SchemaField[] => {
return fields.filter(field => {
if (field.id === id) return false;
if (field.fields) {
field.fields = removeFieldFromArray(field.fields);
}
return true;
});
};
setSchema(prev => removeFieldFromArray(prev));
};
const updateField = (id: string, updates: Partial<SchemaField>) => {
const updateFieldInArray = (fields: SchemaField[]): SchemaField[] => {
return fields.map(field => {
if (field.id === id) {
return { ...field, ...updates };
}
if (field.fields) {
return {
...field,
fields: updateFieldInArray(field.fields)
};
}
return field;
});
};
const updatedSchema = updateFieldInArray(schema);
setSchema(updatedSchema);
onSchemaChange(updatedSchema);
};
const renderField = (field: SchemaField, depth = 0) => {
const isExpanded = expandedGroups.has(field.id);
return (
<div key={field.id} className="space-y-2" style={{ marginLeft: `${depth * 20}px` }}>
<Card className="p-4">
<div className="flex items-center space-x-2">
{field.type === 'group' && (
<Button
variant="ghost"
size="icon"
onClick={() => toggleGroup(field.id)}
>
{isExpanded ? (
<ChevronDown className="h-4 w-4" />
) : (
<ChevronRight className="h-4 w-4" />
)}
</Button>
)}
<Input
placeholder="Field name"
value={field.name}
onChange={(e) => updateField(field.id, { name: e.target.value })}
className="flex-1"
/>
<Input
placeholder="Description"
value={field.description}
onChange={(e) => updateField(field.id, { description: e.target.value })}
className="flex-1"
/>
<Button
variant="destructive"
size="icon"
onClick={() => removeField(field.id)}
>
<Minus className="h-4 w-4" />
</Button>
</div>
</Card>
{field.type === 'group' && isExpanded && (
<div className="space-y-2">
{field.fields?.map(subField => renderField(subField, depth + 1))}
<div className="flex space-x-2" style={{ marginLeft: `${(depth + 1) * 20}px` }}>
<Button
variant="outline"
size="sm"
onClick={() => addField(field.id)}
>
<Plus className="h-4 w-4 mr-2" />
Add Field
</Button>
<Button
variant="outline"
size="sm"
onClick={() => addGroup(field.id)}
>
<Plus className="h-4 w-4 mr-2" />
Add Group
</Button>
</div>
</div>
)}
</div>
);
};
return (
<div className="space-y-4">
<div className="flex justify-between items-center">
<h2 className="text-lg font-semibold">Schema Definition</h2>
<div className="space-x-2">
<Button variant="outline" onClick={() => addField()}>
<Plus className="h-4 w-4 mr-2" />
Add Field
</Button>
<Button variant="outline" onClick={() => addGroup()}>
<Plus className="h-4 w-4 mr-2" />
Add Group
</Button>
</div>
</div>
<div className="space-y-2">
{schema.map(field => renderField(field))}
</div>
</div>
);
}