refactor and ui adjustments

This commit is contained in:
liamcottle 2025-01-01 16:34:25 +13:00
commit d767c5c002

View file

@ -1,19 +1,19 @@
<template>
<div v-if="showingImportDialog" class="fixed inset-0 bg-gray-500 bg-opacity-75 transition-opacity flex items-center justify-center">
<div v-if="isShowing" class="fixed inset-0 bg-gray-500 bg-opacity-75 transition-opacity flex items-center justify-center">
<div class="bg-white dark:bg-zinc-900 rounded-lg shadow-xl max-w-2xl w-full mx-4">
<!-- title -->
<div class="p-4 border-b dark:border-zinc-700">
<h3 class="text-lg font-semibold dark:text-white">Import Interfaces</h3>
</div>
<div class="p-4 space-y-4">
<!-- content -->
<div class="divide-y">
<!-- File Input -->
<div>
<!-- file input -->
<div class="p-4">
<label class="block text-sm font-medium text-gray-700 dark:text-zinc-200">Select Configuration File</label>
<input type="file"
@change="onFileSelected"
accept="*"
<input ref="import-interfaces-file-input" type="file" @change="onFileSelected" accept="*"
class="mt-1 block w-full text-sm text-gray-500 dark:text-zinc-400
file:mr-4 file:py-2 file:px-4
file:rounded-md file:border-0
@ -23,8 +23,8 @@
dark:file:bg-zinc-700 dark:hover:file:bg-zinc-600">
</div>
<!-- Interface Selection -->
<div v-if="importableInterfaces.length > 0">
<!-- select interfaces -->
<div v-if="importableInterfaces.length > 0" class="p-4">
<div class="flex justify-between mb-2">
<label class="block text-sm font-medium text-gray-700 dark:text-zinc-200">Select Interfaces to Import</label>
<div class="space-x-2">
@ -33,12 +33,8 @@
</div>
</div>
<div class="space-y-2 max-h-60 overflow-y-auto">
<div v-for="iface in importableInterfaces" :key="iface.name"
class="flex items-center p-2 border rounded dark:border-zinc-700">
<input type="checkbox"
v-model="selectedInterfaces"
:value="iface.name"
class="h-4 w-4 text-blue-600 rounded border-gray-300 dark:border-zinc-600">
<div v-for="iface in importableInterfaces" :key="iface.name" class="flex items-center p-2 border rounded dark:border-zinc-700">
<input type="checkbox" v-model="selectedInterfaces" :value="iface.name" class="h-4 w-4 text-blue-600 rounded border-gray-300 dark:border-zinc-600">
<label class="ml-2 text-sm text-gray-700 dark:text-zinc-200">
{{ iface.name }} ({{ iface.type }})
</label>
@ -47,6 +43,7 @@
</div>
</div>
<!-- actions -->
<div class="p-4 border-t dark:border-zinc-700 flex justify-end space-x-2">
<button @click="dismiss" class="px-4 py-2 text-sm font-medium text-gray-700 bg-white border border-gray-300 rounded-md hover:bg-gray-50 dark:bg-zinc-800 dark:text-zinc-200 dark:border-zinc-600 dark:hover:bg-zinc-700">
Cancel
@ -70,47 +67,64 @@ export default {
],
data() {
return {
showingImportDialog: false,
isShowing: false,
selectedFile: null,
importableInterfaces: [],
selectedInterfaces: [],
importFile: null,
};
},
methods: {
show() {
this.showingImportDialog = true;
this.isShowing = true;
this.selectedFile = null;
this.importableInterfaces = [];
this.selectedInterfaces = [];
this.importFile = null;
},
dismiss() {
this.showingImportDialog = false;
this.isShowing = false;
this.$emit("dismissed");
},
clearSelectedFile() {
this.selectedFile = null;
this.$refs["import-interfaces-file-input"].value = null;
},
async onFileSelected(event) {
const file = event.target.files[0];
if (!file) return;
this.importFile = file;
// get selected file
const file = event.target.files[0];
if(!file){
return;
}
// update ui
this.selectedFile = file;
this.importableInterfaces = [];
this.selectedInterfaces = [];
const formData = new FormData();
formData.append('config', file);
try {
// fetch preview of interfaces to import
const formData = new FormData();
formData.append('config', file);
const response = await window.axios.post('/api/v1/reticulum/interfaces/preview', formData);
if (response.data.interfaces && response.data.interfaces.length > 0) {
this.importableInterfaces = response.data.interfaces;
this.selectedInterfaces = this.importableInterfaces.map(i => i.name);
} else {
DialogUtils.alert("No valid interfaces found in configuration file");
this.dismiss();
// ensure there are some interfaces available to import
if(!response.data.interfaces || response.data.interfaces.length === 0){
this.clearSelectedFile();
DialogUtils.alert("No interfaces were found in the selected configuration file");
return;
}
// update ui
this.importableInterfaces = response.data.interfaces;
// auto select all interfaces
this.selectAllInterfaces();
} catch(e) {
this.clearSelectedFile();
DialogUtils.alert("Failed to parse configuration file");
console.error(e);
this.dismiss();
}
},
selectAllInterfaces() {
@ -120,24 +134,35 @@ export default {
this.selectedInterfaces = [];
},
async importSelectedInterfaces() {
if (!this.importFile) {
// ensure user selected a file to import from
if(!this.selectedFile){
DialogUtils.alert("Please select a configuration file");
return;
}
if (this.selectedInterfaces.length === 0) {
// ensure user selected some interfaces
if(this.selectedInterfaces.length === 0){
DialogUtils.alert("Please select at least one interface to import");
return;
}
// create form data to send to server
const formData = new FormData();
formData.append('config', this.importFile);
formData.append('config', this.selectedFile);
formData.append('selected_interfaces', JSON.stringify(this.selectedInterfaces));
try {
// import interfaces
await window.axios.post('/api/v1/reticulum/interfaces/import', formData);
// dismiss modal
this.dismiss();
DialogUtils.alert("Interfaces imported successfully");
// tell user interfaces were imported
DialogUtils.alert("Interfaces imported successfully. MeshChat must be restarted for these changes to take effect.");
} catch(e) {
const message = e.response?.data?.message || "Failed to import interfaces";
DialogUtils.alert(message);