Add NocoDB configuration tab to admin settings for persistent database connectivity
Build And Push Image / docker (push) Successful in 2m12s
Details
Build And Push Image / docker (push) Successful in 2m12s
Details
This commit is contained in:
parent
3b455a3989
commit
f84adeff21
|
|
@ -61,7 +61,11 @@
|
||||||
"Read(/Z:\\Repos\\monacousa-portal\\assets\\scss/**)",
|
"Read(/Z:\\Repos\\monacousa-portal\\assets\\scss/**)",
|
||||||
"Read(/Z:\\Repos\\monacousa-portal\\pages\\admin/**)",
|
"Read(/Z:\\Repos\\monacousa-portal\\pages\\admin/**)",
|
||||||
"Read(/Z:\\Repos\\monacousa-portal\\pages\\admin/**)",
|
"Read(/Z:\\Repos\\monacousa-portal\\pages\\admin/**)",
|
||||||
"Read(/Z:\\Repos\\monacousa-portal\\pages\\admin/**)"
|
"Read(/Z:\\Repos\\monacousa-portal\\pages\\admin/**)",
|
||||||
|
"Read(/Z:\\Repos\\monacousa-portal\\pages\\admin\\dashboard/**)",
|
||||||
|
"Read(/Z:\\Repos\\monacousa-portal\\components/**)",
|
||||||
|
"Read(/Z:\\Repos\\monacousa-portal\\components/**)",
|
||||||
|
"Read(/Z:\\Repos\\monacousa-portal\\pages\\admin\\settings/**)"
|
||||||
],
|
],
|
||||||
"deny": [],
|
"deny": [],
|
||||||
"ask": []
|
"ask": []
|
||||||
|
|
|
||||||
Binary file not shown.
|
|
@ -118,14 +118,14 @@
|
||||||
</v-card-text>
|
</v-card-text>
|
||||||
|
|
||||||
<!-- Action Buttons -->
|
<!-- Action Buttons -->
|
||||||
<v-card-actions class="pa-4 pt-0">
|
<v-card-actions class="pa-4 pt-0 d-flex justify-center">
|
||||||
<v-btn
|
<v-btn
|
||||||
color="success"
|
color="success"
|
||||||
variant="elevated"
|
variant="elevated"
|
||||||
size="small"
|
height="44"
|
||||||
:loading="loading"
|
:loading="loading"
|
||||||
@click="showPaymentDateDialog = true"
|
@click="showPaymentDateDialog = true"
|
||||||
block
|
class="px-4"
|
||||||
>
|
>
|
||||||
<v-icon start size="16">mdi-check-circle</v-icon>
|
<v-icon start size="16">mdi-check-circle</v-icon>
|
||||||
Mark as Paid
|
Mark as Paid
|
||||||
|
|
|
||||||
|
|
@ -19,6 +19,10 @@
|
||||||
<v-icon start>mdi-email</v-icon>
|
<v-icon start>mdi-email</v-icon>
|
||||||
Email
|
Email
|
||||||
</v-tab>
|
</v-tab>
|
||||||
|
<v-tab value="nocodb">
|
||||||
|
<v-icon start>mdi-database</v-icon>
|
||||||
|
NocoDB
|
||||||
|
</v-tab>
|
||||||
</v-tabs>
|
</v-tabs>
|
||||||
|
|
||||||
<v-window v-model="activeTab">
|
<v-window v-model="activeTab">
|
||||||
|
|
@ -327,6 +331,178 @@
|
||||||
</v-row>
|
</v-row>
|
||||||
</v-card-text>
|
</v-card-text>
|
||||||
</v-window-item>
|
</v-window-item>
|
||||||
|
|
||||||
|
<!-- NocoDB Settings -->
|
||||||
|
<v-window-item value="nocodb">
|
||||||
|
<v-card-text>
|
||||||
|
<!-- Edit Mode Toggle -->
|
||||||
|
<v-row class="mb-4">
|
||||||
|
<v-col>
|
||||||
|
<v-alert
|
||||||
|
v-if="!nocodbEditMode"
|
||||||
|
type="info"
|
||||||
|
variant="tonal"
|
||||||
|
density="compact"
|
||||||
|
>
|
||||||
|
<template v-slot:text>
|
||||||
|
Click "Edit NocoDB Configuration" to modify database settings
|
||||||
|
</template>
|
||||||
|
</v-alert>
|
||||||
|
<v-alert
|
||||||
|
v-if="nocodbEditMode"
|
||||||
|
type="warning"
|
||||||
|
variant="tonal"
|
||||||
|
density="compact"
|
||||||
|
>
|
||||||
|
<template v-slot:text>
|
||||||
|
NocoDB configuration is required for member management functionality
|
||||||
|
</template>
|
||||||
|
</v-alert>
|
||||||
|
</v-col>
|
||||||
|
<v-col cols="auto">
|
||||||
|
<v-btn
|
||||||
|
v-if="!nocodbEditMode"
|
||||||
|
color="primary"
|
||||||
|
variant="outlined"
|
||||||
|
@click="nocodbEditMode = true"
|
||||||
|
>
|
||||||
|
<v-icon start>mdi-pencil</v-icon>
|
||||||
|
Edit NocoDB Configuration
|
||||||
|
</v-btn>
|
||||||
|
<v-btn-group v-else>
|
||||||
|
<v-btn
|
||||||
|
color="success"
|
||||||
|
variant="flat"
|
||||||
|
@click="saveNocodbSettings"
|
||||||
|
>
|
||||||
|
<v-icon start>mdi-check</v-icon>
|
||||||
|
Save
|
||||||
|
</v-btn>
|
||||||
|
<v-btn
|
||||||
|
color="warning"
|
||||||
|
variant="outlined"
|
||||||
|
@click="testNocodbConnection"
|
||||||
|
:loading="testingNocodb"
|
||||||
|
>
|
||||||
|
<v-icon start>mdi-connection</v-icon>
|
||||||
|
Test Connection
|
||||||
|
</v-btn>
|
||||||
|
<v-btn
|
||||||
|
color="error"
|
||||||
|
variant="outlined"
|
||||||
|
@click="cancelNocodbEdit"
|
||||||
|
>
|
||||||
|
<v-icon start>mdi-close</v-icon>
|
||||||
|
Cancel
|
||||||
|
</v-btn>
|
||||||
|
</v-btn-group>
|
||||||
|
</v-col>
|
||||||
|
</v-row>
|
||||||
|
|
||||||
|
<v-row>
|
||||||
|
<v-col cols="12">
|
||||||
|
<h3 class="text-h6 mb-4">NocoDB Database Configuration</h3>
|
||||||
|
</v-col>
|
||||||
|
<v-col cols="12">
|
||||||
|
<v-text-field
|
||||||
|
v-model="settings.nocodb.url"
|
||||||
|
label="NocoDB URL"
|
||||||
|
variant="outlined"
|
||||||
|
placeholder="https://your-nocodb-instance.com"
|
||||||
|
:readonly="!nocodbEditMode"
|
||||||
|
:disabled="!nocodbEditMode"
|
||||||
|
autocomplete="off"
|
||||||
|
:class="{ 'readonly-field': !nocodbEditMode }"
|
||||||
|
/>
|
||||||
|
</v-col>
|
||||||
|
<v-col cols="12">
|
||||||
|
<v-text-field
|
||||||
|
v-model="settings.nocodb.apiKey"
|
||||||
|
label="API Key"
|
||||||
|
variant="outlined"
|
||||||
|
:type="showNocodbApiKey ? 'text' : 'password'"
|
||||||
|
placeholder="Enter your NocoDB API token"
|
||||||
|
:readonly="!nocodbEditMode"
|
||||||
|
:disabled="!nocodbEditMode"
|
||||||
|
autocomplete="new-password"
|
||||||
|
:class="{ 'readonly-field': !nocodbEditMode }"
|
||||||
|
>
|
||||||
|
<template v-slot:append-inner>
|
||||||
|
<v-icon
|
||||||
|
v-if="nocodbEditMode"
|
||||||
|
@click="showNocodbApiKey = !showNocodbApiKey"
|
||||||
|
:icon="showNocodbApiKey ? 'mdi-eye-off' : 'mdi-eye'"
|
||||||
|
class="cursor-pointer"
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
|
</v-text-field>
|
||||||
|
</v-col>
|
||||||
|
<v-col cols="12">
|
||||||
|
<v-text-field
|
||||||
|
v-model="settings.nocodb.baseId"
|
||||||
|
label="Base ID"
|
||||||
|
variant="outlined"
|
||||||
|
placeholder="Your NocoDB base ID"
|
||||||
|
:readonly="!nocodbEditMode"
|
||||||
|
:disabled="!nocodbEditMode"
|
||||||
|
autocomplete="off"
|
||||||
|
:class="{ 'readonly-field': !nocodbEditMode }"
|
||||||
|
/>
|
||||||
|
</v-col>
|
||||||
|
<v-col cols="12">
|
||||||
|
<v-divider class="my-4" />
|
||||||
|
</v-col>
|
||||||
|
<v-col cols="12">
|
||||||
|
<h3 class="text-h6 mb-4">Table Mappings</h3>
|
||||||
|
</v-col>
|
||||||
|
<v-col cols="12" md="4">
|
||||||
|
<v-text-field
|
||||||
|
v-model="settings.nocodb.tables.members"
|
||||||
|
label="Members Table"
|
||||||
|
variant="outlined"
|
||||||
|
:readonly="!nocodbEditMode"
|
||||||
|
:disabled="!nocodbEditMode"
|
||||||
|
autocomplete="off"
|
||||||
|
:class="{ 'readonly-field': !nocodbEditMode }"
|
||||||
|
/>
|
||||||
|
</v-col>
|
||||||
|
<v-col cols="12" md="4">
|
||||||
|
<v-text-field
|
||||||
|
v-model="settings.nocodb.tables.events"
|
||||||
|
label="Events Table"
|
||||||
|
variant="outlined"
|
||||||
|
:readonly="!nocodbEditMode"
|
||||||
|
:disabled="!nocodbEditMode"
|
||||||
|
autocomplete="off"
|
||||||
|
:class="{ 'readonly-field': !nocodbEditMode }"
|
||||||
|
/>
|
||||||
|
</v-col>
|
||||||
|
<v-col cols="12" md="4">
|
||||||
|
<v-text-field
|
||||||
|
v-model="settings.nocodb.tables.rsvps"
|
||||||
|
label="RSVPs Table"
|
||||||
|
variant="outlined"
|
||||||
|
:readonly="!nocodbEditMode"
|
||||||
|
:disabled="!nocodbEditMode"
|
||||||
|
autocomplete="off"
|
||||||
|
:class="{ 'readonly-field': !nocodbEditMode }"
|
||||||
|
/>
|
||||||
|
</v-col>
|
||||||
|
</v-row>
|
||||||
|
|
||||||
|
<!-- Connection Status -->
|
||||||
|
<v-row v-if="nocodbConnectionStatus" class="mt-4">
|
||||||
|
<v-col>
|
||||||
|
<v-alert
|
||||||
|
:type="nocodbConnectionStatus.success ? 'success' : 'error'"
|
||||||
|
variant="tonal"
|
||||||
|
>
|
||||||
|
{{ nocodbConnectionStatus.message }}
|
||||||
|
</v-alert>
|
||||||
|
</v-col>
|
||||||
|
</v-row>
|
||||||
|
</v-card-text>
|
||||||
|
</v-window-item>
|
||||||
</v-window>
|
</v-window>
|
||||||
</v-card>
|
</v-card>
|
||||||
|
|
||||||
|
|
@ -359,8 +535,12 @@ definePageMeta({
|
||||||
const activeTab = ref('general');
|
const activeTab = ref('general');
|
||||||
const generalEditMode = ref(false);
|
const generalEditMode = ref(false);
|
||||||
const emailEditMode = ref(false);
|
const emailEditMode = ref(false);
|
||||||
|
const nocodbEditMode = ref(false);
|
||||||
const showPassword = ref(false);
|
const showPassword = ref(false);
|
||||||
|
const showNocodbApiKey = ref(false);
|
||||||
const testingEmail = ref(false);
|
const testingEmail = ref(false);
|
||||||
|
const testingNocodb = ref(false);
|
||||||
|
const nocodbConnectionStatus = ref<{ success: boolean; message: string } | null>(null);
|
||||||
const snackbar = ref(false);
|
const snackbar = ref(false);
|
||||||
const snackbarText = ref('');
|
const snackbarText = ref('');
|
||||||
const snackbarColor = ref('success');
|
const snackbarColor = ref('success');
|
||||||
|
|
@ -386,6 +566,16 @@ const settings = ref({
|
||||||
useTLS: true,
|
useTLS: true,
|
||||||
fromName: 'MonacoUSA',
|
fromName: 'MonacoUSA',
|
||||||
fromEmail: 'noreply@monacousa.org'
|
fromEmail: 'noreply@monacousa.org'
|
||||||
|
},
|
||||||
|
nocodb: {
|
||||||
|
url: '',
|
||||||
|
apiKey: '',
|
||||||
|
baseId: '',
|
||||||
|
tables: {
|
||||||
|
members: 'Members',
|
||||||
|
events: 'Events',
|
||||||
|
rsvps: 'RSVPs'
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -413,6 +603,7 @@ const currencies = [
|
||||||
// Load settings on mount
|
// Load settings on mount
|
||||||
onMounted(async () => {
|
onMounted(async () => {
|
||||||
await loadSettings();
|
await loadSettings();
|
||||||
|
await loadNocodbSettings();
|
||||||
});
|
});
|
||||||
|
|
||||||
// Methods
|
// Methods
|
||||||
|
|
@ -488,6 +679,84 @@ const showNotification = (text: string, color: string = 'success') => {
|
||||||
snackbar.value = true;
|
snackbar.value = true;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const loadNocodbSettings = async () => {
|
||||||
|
try {
|
||||||
|
const response = await $fetch<{ success: boolean; data?: any }>('/api/admin/nocodb-config');
|
||||||
|
if (response.success && response.data) {
|
||||||
|
settings.value.nocodb = {
|
||||||
|
url: response.data.url || '',
|
||||||
|
apiKey: response.data.apiKey || '',
|
||||||
|
baseId: response.data.baseId || '',
|
||||||
|
tables: response.data.tables || {
|
||||||
|
members: 'Members',
|
||||||
|
events: 'Events',
|
||||||
|
rsvps: 'RSVPs'
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error loading NocoDB settings:', error);
|
||||||
|
showNotification('Failed to load NocoDB settings', 'error');
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const saveNocodbSettings = async () => {
|
||||||
|
try {
|
||||||
|
const response = await $fetch('/api/admin/nocodb-config', {
|
||||||
|
method: 'POST',
|
||||||
|
body: settings.value.nocodb
|
||||||
|
});
|
||||||
|
nocodbEditMode.value = false;
|
||||||
|
showNocodbApiKey.value = false;
|
||||||
|
showNotification('NocoDB settings saved successfully', 'success');
|
||||||
|
// Reload settings to ensure they're persistent
|
||||||
|
await loadNocodbSettings();
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error saving NocoDB settings:', error);
|
||||||
|
showNotification('Failed to save NocoDB settings', 'error');
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const testNocodbConnection = async () => {
|
||||||
|
testingNocodb.value = true;
|
||||||
|
nocodbConnectionStatus.value = null;
|
||||||
|
|
||||||
|
try {
|
||||||
|
const response = await $fetch<{ success: boolean; message: string }>('/api/admin/nocodb-test', {
|
||||||
|
method: 'POST',
|
||||||
|
body: settings.value.nocodb
|
||||||
|
});
|
||||||
|
|
||||||
|
nocodbConnectionStatus.value = {
|
||||||
|
success: response.success,
|
||||||
|
message: response.message
|
||||||
|
};
|
||||||
|
|
||||||
|
if (response.success) {
|
||||||
|
showNotification('NocoDB connection successful', 'success');
|
||||||
|
} else {
|
||||||
|
showNotification(response.message, 'error');
|
||||||
|
}
|
||||||
|
} catch (error: any) {
|
||||||
|
nocodbConnectionStatus.value = {
|
||||||
|
success: false,
|
||||||
|
message: error.data?.message || 'Failed to connect to NocoDB'
|
||||||
|
};
|
||||||
|
showNotification('Connection test failed', 'error');
|
||||||
|
} finally {
|
||||||
|
testingNocodb.value = false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const cancelNocodbEdit = () => {
|
||||||
|
if (originalSettings.value) {
|
||||||
|
settings.value.nocodb = { ...originalSettings.value.nocodb };
|
||||||
|
}
|
||||||
|
nocodbEditMode.value = false;
|
||||||
|
showNocodbApiKey.value = false;
|
||||||
|
nocodbConnectionStatus.value = null;
|
||||||
|
};
|
||||||
|
|
||||||
// Watch for edit mode changes to backup original settings
|
// Watch for edit mode changes to backup original settings
|
||||||
watch(generalEditMode, (newVal) => {
|
watch(generalEditMode, (newVal) => {
|
||||||
if (newVal) {
|
if (newVal) {
|
||||||
|
|
@ -505,6 +774,14 @@ watch(emailEditMode, (newVal) => {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
watch(nocodbEditMode, (newVal) => {
|
||||||
|
if (newVal) {
|
||||||
|
originalSettings.value = {
|
||||||
|
nocodb: { ...settings.value.nocodb }
|
||||||
|
};
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
// Prevent browser autofill on mount
|
// Prevent browser autofill on mount
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
// Disable autofill for all inputs initially
|
// Disable autofill for all inputs initially
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue