From a00c9b82a6cb74bf3f7da997349ce5b60feb59f1 Mon Sep 17 00:00:00 2001 From: LordMathis Date: Mon, 27 Oct 2025 20:11:22 +0100 Subject: [PATCH] Add import functionality for instance configuration from JSON file --- .../instance/InstanceSettingsCard.tsx | 72 ++++++++++++++++++- 1 file changed, 71 insertions(+), 1 deletion(-) diff --git a/webui/src/components/instance/InstanceSettingsCard.tsx b/webui/src/components/instance/InstanceSettingsCard.tsx index 1834eab..87b32fb 100644 --- a/webui/src/components/instance/InstanceSettingsCard.tsx +++ b/webui/src/components/instance/InstanceSettingsCard.tsx @@ -1,14 +1,16 @@ -import React, { useState, useEffect } from 'react' +import React, { useState, useEffect, useRef } from 'react' import type { CreateInstanceOptions } from '@/types/instance' import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card' import { Label } from '@/components/ui/label' import { Input } from '@/components/ui/input' +import { Button } from '@/components/ui/button' import AutoRestartConfiguration from '@/components/instance/AutoRestartConfiguration' import NumberInput from '@/components/form/NumberInput' import CheckboxInput from '@/components/form/CheckboxInput' import EnvironmentVariablesInput from '@/components/form/EnvironmentVariablesInput' import SelectInput from '@/components/form/SelectInput' import { nodesApi, type NodesMap } from '@/lib/api' +import { Upload } from 'lucide-react' interface InstanceSettingsCardProps { instanceName: string @@ -29,6 +31,7 @@ const InstanceSettingsCard: React.FC = ({ }) => { const [nodes, setNodes] = useState({}) const [loadingNodes, setLoadingNodes] = useState(true) + const fileInputRef = useRef(null) useEffect(() => { const fetchNodes = async () => { @@ -67,12 +70,79 @@ const InstanceSettingsCard: React.FC = ({ const selectedNode = formData.nodes && formData.nodes.length > 0 ? formData.nodes[0] : '' + const handleImportFile = () => { + fileInputRef.current?.click() + } + + const handleFileChange = (event: React.ChangeEvent) => { + const file = event.target.files?.[0] + if (!file) return + + const reader = new FileReader() + reader.onload = (e) => { + try { + const content = e.target?.result as string + const importedData = JSON.parse(content) + + // Validate that it's an instance export + if (!importedData.name || !importedData.options) { + alert('Invalid instance file: Missing required fields (name, options)') + return + } + + // Set the instance name (only for new instances, not editing) + if (!isEditing) { + onNameChange(importedData.name) + } + + // Populate all the options from the imported file + if (importedData.options) { + // Set all the options fields + Object.entries(importedData.options).forEach(([key, value]) => { + onChange(key as keyof CreateInstanceOptions, value) + }) + } + + // Reset the file input + event.target.value = '' + } catch (error) { + console.error('Failed to parse instance file:', error) + alert(`Failed to parse instance file: ${error instanceof Error ? error.message : 'Invalid JSON'}`) + } + } + + reader.readAsText(file) + } + return ( Instance Settings + {/* Import Instance Section - only show when creating new instance */} + {!isEditing && ( +
+ + +
+ )} + {/* Instance Name */}