added in new crud apis made
This commit is contained in:
@@ -30,10 +30,26 @@ export function ConfigPanel({ node, onClose, onUpdateNode }: ConfigPanelProps) {
|
|||||||
HTMLInputElement | HTMLTextAreaElement | HTMLSelectElement
|
HTMLInputElement | HTMLTextAreaElement | HTMLSelectElement
|
||||||
>
|
>
|
||||||
) => {
|
) => {
|
||||||
|
console.log('Changing', e.target.name, 'to', e.target.value); // Debug log
|
||||||
|
|
||||||
|
if (e.target.name === 'outputType') {
|
||||||
|
// Create entirely new data object for output type change
|
||||||
|
const newData = {
|
||||||
|
...node.data,
|
||||||
|
outputType: e.target.value,
|
||||||
|
// Reset fields based on new type
|
||||||
|
fields: e.target.value === 'mockup' ? [] : (node.data.fields || []),
|
||||||
|
responseRaw: e.target.value === 'mockup' ? '{}' : undefined,
|
||||||
|
};
|
||||||
|
console.log('New data after output type change:', newData); // Debug log
|
||||||
|
onUpdateNode(node.id, newData);
|
||||||
|
} else {
|
||||||
|
// Handle other changes normally
|
||||||
onUpdateNode(node.id, {
|
onUpdateNode(node.id, {
|
||||||
...node.data,
|
...node.data,
|
||||||
[e.target.name]: e.target.value,
|
[e.target.name]: e.target.value,
|
||||||
});
|
});
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleArrayChange = (
|
const handleArrayChange = (
|
||||||
@@ -103,17 +119,30 @@ export function ConfigPanel({ node, onClose, onUpdateNode }: ConfigPanelProps) {
|
|||||||
>
|
>
|
||||||
<option value="">Select Model</option>
|
<option value="">Select Model</option>
|
||||||
{models.map((model) => (
|
{models.map((model) => (
|
||||||
<option key={model.id} value={model.id}>
|
<option key={model.id} value={model.name}>
|
||||||
{model.name}
|
{model.name}
|
||||||
</option>
|
</option>
|
||||||
))}
|
))}
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
|
<div className="mb-4">
|
||||||
|
<label className="block text-sm font-medium mb-1">Operation</label>
|
||||||
|
<select
|
||||||
|
name="operation"
|
||||||
|
value={node.data.operation || "findMany"}
|
||||||
|
onChange={handleChange}
|
||||||
|
className="w-full p-2 border rounded"
|
||||||
|
>
|
||||||
|
<option value="findMany">Find Many</option>
|
||||||
|
<option value="findOne">Find One</option>
|
||||||
|
<option value="findFirst">Find First</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
<div className="mb-4">
|
<div className="mb-4">
|
||||||
<label className="block text-sm font-medium mb-1">SQL Query</label>
|
<label className="block text-sm font-medium mb-1">SQL Query</label>
|
||||||
<textarea
|
<textarea
|
||||||
name="query"
|
name="query"
|
||||||
value={node.data.query || ""}
|
value={node.data.query || `SELECT * FROM ${node.data.model}`}
|
||||||
onChange={handleChange}
|
onChange={handleChange}
|
||||||
className="w-full p-2 border rounded h-32 font-mono text-sm"
|
className="w-full p-2 border rounded h-32 font-mono text-sm"
|
||||||
placeholder="SELECT * FROM table WHERE id = :id"
|
placeholder="SELECT * FROM table WHERE id = :id"
|
||||||
@@ -124,7 +153,7 @@ export function ConfigPanel({ node, onClose, onUpdateNode }: ConfigPanelProps) {
|
|||||||
<input
|
<input
|
||||||
type="text"
|
type="text"
|
||||||
name="resultVar"
|
name="resultVar"
|
||||||
value={node.data.resultVar || ""}
|
value={node.data.resultVar || "result"}
|
||||||
onChange={handleChange}
|
onChange={handleChange}
|
||||||
className="w-full p-2 border rounded"
|
className="w-full p-2 border rounded"
|
||||||
placeholder="result"
|
placeholder="result"
|
||||||
@@ -392,17 +421,43 @@ export function ConfigPanel({ node, onClose, onUpdateNode }: ConfigPanelProps) {
|
|||||||
case "output":
|
case "output":
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
|
<div className="mb-4">
|
||||||
|
<label className="block text-sm font-medium mb-1">Output Type</label>
|
||||||
|
<select
|
||||||
|
name="outputType"
|
||||||
|
value={node.data.outputType || "definition"}
|
||||||
|
onChange={handleChange}
|
||||||
|
className="w-full p-2 border rounded"
|
||||||
|
>
|
||||||
|
<option value="definition">Definition</option>
|
||||||
|
<option value="mockup">Mockup</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{node.data.outputType === "mockup" ? (
|
||||||
|
<div className="mb-4">
|
||||||
|
<label className="block text-sm font-medium mb-1">Response Raw</label>
|
||||||
|
<textarea
|
||||||
|
name="responseRaw"
|
||||||
|
value={node.data.responseRaw || ""}
|
||||||
|
onChange={handleChange}
|
||||||
|
className="w-full p-2 border rounded h-32"
|
||||||
|
placeholder="Enter raw response here..."
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
) : (
|
||||||
<div className="mb-4">
|
<div className="mb-4">
|
||||||
<label className="block text-sm font-medium mb-1">Fields</label>
|
<label className="block text-sm font-medium mb-1">Fields</label>
|
||||||
|
<div className="flex flex-wrap gap-2 mb-2">
|
||||||
{(node.data.fields || []).map((field: Field, index: number) => (
|
{(node.data.fields || []).map((field: Field, index: number) => (
|
||||||
<div key={index} className="flex gap-2 mb-2">
|
<div key={index} className="flex items-center">
|
||||||
<input
|
<input
|
||||||
type="text"
|
type="text"
|
||||||
value={field.name}
|
value={field.name}
|
||||||
onChange={(e) =>
|
onChange={(e) =>
|
||||||
handleArrayChange(index, "name", e.target.value, "fields")
|
handleArrayChange(index, "name", e.target.value, "fields")
|
||||||
}
|
}
|
||||||
className="flex-1 p-2 border rounded"
|
className="flex-1 p-2 border rounded text-sm"
|
||||||
placeholder="Field name"
|
placeholder="Field name"
|
||||||
/>
|
/>
|
||||||
<select
|
<select
|
||||||
@@ -410,12 +465,14 @@ export function ConfigPanel({ node, onClose, onUpdateNode }: ConfigPanelProps) {
|
|||||||
onChange={(e) =>
|
onChange={(e) =>
|
||||||
handleArrayChange(index, "type", e.target.value, "fields")
|
handleArrayChange(index, "type", e.target.value, "fields")
|
||||||
}
|
}
|
||||||
className="w-24 p-2 border rounded"
|
className="w-24 p-2 border rounded text-sm"
|
||||||
>
|
>
|
||||||
<option value="string">String</option>
|
<option value="string">String</option>
|
||||||
<option value="number">Number</option>
|
<option value="number">Number</option>
|
||||||
<option value="boolean">Boolean</option>
|
<option value="boolean">Boolean</option>
|
||||||
<option value="date">Date</option>
|
<option value="date">Date</option>
|
||||||
|
<option value="object">Object</option>
|
||||||
|
<option value="array">Array</option>
|
||||||
</select>
|
</select>
|
||||||
<button
|
<button
|
||||||
onClick={() => removeField(index, "fields")}
|
onClick={() => removeField(index, "fields")}
|
||||||
@@ -425,14 +482,15 @@ export function ConfigPanel({ node, onClose, onUpdateNode }: ConfigPanelProps) {
|
|||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
))}
|
))}
|
||||||
<div className="flex gap-2 mt-2">
|
</div>
|
||||||
|
<div className="flex items-center gap-2 mt-2">
|
||||||
<input
|
<input
|
||||||
type="text"
|
type="text"
|
||||||
value={newField.name}
|
value={newField.name}
|
||||||
onChange={(e) =>
|
onChange={(e) =>
|
||||||
setNewField({ ...newField, name: e.target.value })
|
setNewField({ ...newField, name: e.target.value })
|
||||||
}
|
}
|
||||||
className="flex-1 p-2 border rounded"
|
className="flex-1 p-2 border rounded text-sm"
|
||||||
placeholder="New field name"
|
placeholder="New field name"
|
||||||
/>
|
/>
|
||||||
<select
|
<select
|
||||||
@@ -440,21 +498,48 @@ export function ConfigPanel({ node, onClose, onUpdateNode }: ConfigPanelProps) {
|
|||||||
onChange={(e) =>
|
onChange={(e) =>
|
||||||
setNewField({ ...newField, type: e.target.value })
|
setNewField({ ...newField, type: e.target.value })
|
||||||
}
|
}
|
||||||
className="w-24 p-2 border rounded"
|
className="w-24 p-2 border rounded text-sm"
|
||||||
>
|
>
|
||||||
<option value="string">String</option>
|
<option value="string">String</option>
|
||||||
<option value="number">Number</option>
|
<option value="number">Number</option>
|
||||||
<option value="boolean">Boolean</option>
|
<option value="boolean">Boolean</option>
|
||||||
<option value="date">Date</option>
|
<option value="date">Date</option>
|
||||||
|
<option value="object">Object</option>
|
||||||
|
<option value="array">Array</option>
|
||||||
</select>
|
</select>
|
||||||
<button
|
<button
|
||||||
onClick={() => addField("fields")}
|
onClick={() => {
|
||||||
|
if (newField.name.trim()) {
|
||||||
|
const updatedFields = [
|
||||||
|
...(node.data.fields || []),
|
||||||
|
{ ...newField },
|
||||||
|
];
|
||||||
|
onUpdateNode(node.id, {
|
||||||
|
...node.data,
|
||||||
|
fields: updatedFields,
|
||||||
|
});
|
||||||
|
setNewField({ name: "", type: newField.type }); // Use the selected type here
|
||||||
|
}
|
||||||
|
}}
|
||||||
className="px-3 py-1 bg-blue-500 text-white rounded hover:bg-blue-600"
|
className="px-3 py-1 bg-blue-500 text-white rounded hover:bg-blue-600"
|
||||||
>
|
>
|
||||||
<Plus className="w-4 h-4" />
|
<Plus className="w-4 h-4" />
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
|
<div className="mb-4">
|
||||||
|
<label className="block text-sm font-medium mb-1">Status Code</label>
|
||||||
|
<input
|
||||||
|
type="number"
|
||||||
|
name="statusCode"
|
||||||
|
value={node.data.statusCode || 200}
|
||||||
|
onChange={handleChange}
|
||||||
|
className="w-full p-2 border rounded"
|
||||||
|
placeholder="200"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -522,6 +607,8 @@ export function ConfigPanel({ node, onClose, onUpdateNode }: ConfigPanelProps) {
|
|||||||
);
|
);
|
||||||
|
|
||||||
case "db-find":
|
case "db-find":
|
||||||
|
return renderDatabaseFields();
|
||||||
|
|
||||||
case "db-query":
|
case "db-query":
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
|
|||||||
@@ -80,10 +80,15 @@ const createInitialModelData = () => ({
|
|||||||
});
|
});
|
||||||
|
|
||||||
export function ModelModal({ isOpen, onClose, model }: ModelModalProps) {
|
export function ModelModal({ isOpen, onClose, model }: ModelModalProps) {
|
||||||
const [modelData, setModelData] = useState(createInitialModelData());
|
const [modelData, setModelData] = useState<{
|
||||||
|
id: string;
|
||||||
|
name: string;
|
||||||
|
fields: Field[];
|
||||||
|
}>(createInitialModelData());
|
||||||
const [newField, setNewField] = useState<Field>(initialNewField);
|
const [newField, setNewField] = useState<Field>(initialNewField);
|
||||||
|
const [createCrudApis, setCreateCrudApis] = useState(false); // New state for CRUD API checkbox
|
||||||
|
|
||||||
const { addModel, updateModel } = useFlowStore();
|
const { addModel, updateModel, addRoute } = useFlowStore();
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (model) {
|
if (model) {
|
||||||
@@ -122,9 +127,139 @@ export function ModelModal({ isOpen, onClose, model }: ModelModalProps) {
|
|||||||
updateModel(modelData);
|
updateModel(modelData);
|
||||||
} else {
|
} else {
|
||||||
addModel(modelData);
|
addModel(modelData);
|
||||||
|
if (createCrudApis) {
|
||||||
|
// Create GET route for fetching all records
|
||||||
|
const uniqueId = Date.now(); // Generate a unique identifier based on the current timestamp
|
||||||
|
const getRoute = {
|
||||||
|
id: `route_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`,
|
||||||
|
name: `Get All ${modelData.name}`,
|
||||||
|
method: 'GET',
|
||||||
|
url: `/api/${modelData.name.toLowerCase()}`,
|
||||||
|
flowData: {
|
||||||
|
nodes: [
|
||||||
|
{
|
||||||
|
id: `url_node_${uniqueId}`,
|
||||||
|
type: 'url',
|
||||||
|
position: { x: 100, y: 100 },
|
||||||
|
data: {
|
||||||
|
label: 'URL',
|
||||||
|
path: `/api/${modelData.name.toLowerCase()}`,
|
||||||
|
method: 'GET'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: `db_find_node_${uniqueId}`,
|
||||||
|
type: 'db-find',
|
||||||
|
position: { x: 100, y: 200 },
|
||||||
|
data: {
|
||||||
|
label: 'Database Find',
|
||||||
|
model: modelData.name,
|
||||||
|
operation: 'findMany',
|
||||||
|
query: `SELECT * FROM ${modelData.name}`,
|
||||||
|
resultVar: `${modelData.name}Result`
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: `output_node_${uniqueId}`,
|
||||||
|
type: 'output',
|
||||||
|
position: { x: 100, y: 300 },
|
||||||
|
data: {
|
||||||
|
label: 'Output',
|
||||||
|
outputType: 'definition',
|
||||||
|
fields: modelData.fields.map(field => ({
|
||||||
|
name: field.name,
|
||||||
|
type: field.type === 'primary key' ? 'number' :
|
||||||
|
field.type === 'long text' ? 'string' :
|
||||||
|
field.type === 'big number' ? 'number' :
|
||||||
|
field.type
|
||||||
|
})),
|
||||||
|
statusCode: 200
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
edges: [
|
||||||
|
{
|
||||||
|
id: `url-to-db_${uniqueId}`,
|
||||||
|
source: `url_node_${uniqueId}`,
|
||||||
|
target: `db_find_node_${uniqueId}`
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: `db-to-output_${uniqueId}`,
|
||||||
|
source: `db_find_node_${uniqueId}`,
|
||||||
|
target: `output_node_${uniqueId}`
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const getOneRoute = {
|
||||||
|
id: `route_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`,
|
||||||
|
name: `Get One ${modelData.name}`,
|
||||||
|
method: 'GET',
|
||||||
|
url: `/api/${modelData.name.toLowerCase()}/:id`,
|
||||||
|
flowData: {
|
||||||
|
nodes: [
|
||||||
|
{
|
||||||
|
id: `url_node_${uniqueId}_1`,
|
||||||
|
type: 'url',
|
||||||
|
position: { x: 100, y: 100 },
|
||||||
|
data: {
|
||||||
|
label: 'URL',
|
||||||
|
path: `/api/${modelData.name.toLowerCase()}/:id`,
|
||||||
|
method: 'GET'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: `db_find_node_${uniqueId}_1`,
|
||||||
|
type: 'db-find',
|
||||||
|
position: { x: 100, y: 200 },
|
||||||
|
data: {
|
||||||
|
label: 'Database Find',
|
||||||
|
model: modelData.name,
|
||||||
|
operation: 'findOne',
|
||||||
|
query: `SELECT * FROM ${modelData.name} WHERE id=id`,
|
||||||
|
resultVar: `${modelData.name}OneResult`
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: `output_node_${uniqueId}_1`,
|
||||||
|
type: 'output',
|
||||||
|
position: { x: 100, y: 300 },
|
||||||
|
data: {
|
||||||
|
label: 'Output',
|
||||||
|
outputType: 'definition',
|
||||||
|
fields: modelData.fields.map(field => ({
|
||||||
|
name: field.name,
|
||||||
|
type: field.type === 'primary key' ? 'number' :
|
||||||
|
field.type === 'long text' ? 'string' :
|
||||||
|
field.type === 'big number' ? 'number' :
|
||||||
|
field.type
|
||||||
|
})),
|
||||||
|
statusCode: 200
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
edges: [
|
||||||
|
{
|
||||||
|
id: `url-to-db_${uniqueId}_1`,
|
||||||
|
source: `url_node_${uniqueId}_1`,
|
||||||
|
target: `db_find_node_${uniqueId}_1`
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: `db-to-output_${uniqueId}_1`,
|
||||||
|
source: `db_find_node_${uniqueId}_1`,
|
||||||
|
target: `output_node_${uniqueId}_1`
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
addRoute(getRoute as any);
|
||||||
|
addRoute(getOneRoute as any);
|
||||||
}
|
}
|
||||||
onClose();
|
onClose();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
if (!isOpen) return null;
|
if (!isOpen) return null;
|
||||||
@@ -327,6 +462,18 @@ export function ModelModal({ isOpen, onClose, model }: ModelModalProps) {
|
|||||||
<Plus className="w-4 h-4" />
|
<Plus className="w-4 h-4" />
|
||||||
Add Field
|
Add Field
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
|
|
||||||
|
<div className="flex items-center mt-4">
|
||||||
|
<input
|
||||||
|
type="checkbox"
|
||||||
|
checked={createCrudApis}
|
||||||
|
onChange={(e) => setCreateCrudApis(e.target.checked)}
|
||||||
|
className="mr-2"
|
||||||
|
/>
|
||||||
|
<label className="text-sm">Create CRUD APIs</label>
|
||||||
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -30,11 +30,11 @@ interface Role {
|
|||||||
interface Route {
|
interface Route {
|
||||||
id: string;
|
id: string;
|
||||||
name: string;
|
name: string;
|
||||||
url: string;
|
|
||||||
method: string;
|
method: string;
|
||||||
|
url: string;
|
||||||
flowData?: {
|
flowData?: {
|
||||||
nodes: Node[];
|
nodes: any[];
|
||||||
edges: Edge[];
|
edges: any[];
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user