mirror of
https://github.com/liamcottle/reticulum-meshchat.git
synced 2026-04-27 16:10:32 +00:00
refactor and ui adjustments
This commit is contained in:
parent
b12aa387bd
commit
d767c5c002
1 changed files with 61 additions and 36 deletions
|
|
@ -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);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue