main #2

Open
julap wants to merge 7 commits from main into notifications
6 changed files with 100 additions and 114 deletions
Showing only changes of commit bcbf2f0958 - Show all commits

View File

@ -12,16 +12,49 @@ const refreshPage = () => {
window.location.reload(true);
};
// Fast loading logo - fetch during SSR to prevent hydration flash
const { data: quickLoadingData } = await useLazyFetch("/api/devtool/config/loading-logo", {
default: () => ({
data: {
siteLoadingLogo: '',
siteName: 'Loading...'
}
}),
transform: (response) => response.data || {
siteLoadingLogo: '',
siteName: 'Loading...'
}
});
const loadingLogoSrc = computed(() => {
return 'http://localhost:3003/uploads/site-settings/loading-logo.png';
// First priority: Quick loading data if available
if (quickLoadingData.value?.siteLoadingLogo) {
return quickLoadingData.value.siteLoadingLogo;
}
// Second priority: Full site settings if loaded
if (!siteSettingsLoading.value && siteSettings.value.siteLoadingLogo) {
return siteSettings.value.siteLoadingLogo;
}
// Fallback: Default logo
return '/img/logo/corradAF-logo.svg';
});
// Get site name with fallback
const getSiteName = () => {
if (siteSettingsLoading.value) {
return 'Loading Logo';
// First priority: Quick loading data
if (quickLoadingData.value?.siteName) {
return quickLoadingData.value.siteName;
}
return siteSettings.value?.siteName || 'Loading Logo';
// Second priority: Full site settings
if (!siteSettingsLoading.value && siteSettings.value.siteName) {
return siteSettings.value.siteName;
}
// Fallback
return 'Loading...';
};
</script>

View File

@ -9,18 +9,6 @@ export default [
"icon": "ic:outline-dashboard",
"child": [],
"meta": {}
},
{
"title": "Notes",
"path": "/notes",
"icon": "",
"child": []
},
{
"title": "Metabase",
"path": "/metabase",
"icon": "",
"child": []
}
],
"meta": {}

View File

@ -5,7 +5,7 @@ definePageMeta({
requiresAuth: true,
});
const { $swal, $toast } = useNuxtApp();
const { $swal } = useNuxtApp();
const { siteSettings, updateSiteSettings, applyThemeSettings, updateGlobalMeta } = useSiteSettings();
// Reactive data
@ -139,7 +139,7 @@ const loadSettings = async () => {
}
} catch (error) {
console.error("Error loading settings:", error);
$toast.error("Failed to load site settings");
alert("Failed to load site settings");
} finally {
loading.value = false;
}
@ -148,7 +148,7 @@ const loadSettings = async () => {
// Save settings
const saveSettings = async () => {
if (!validateForm()) {
$toast.error("Please fix the validation errors");
alert("Please fix the validation errors");
return;
}
@ -160,7 +160,7 @@ const saveSettings = async () => {
if (result && result.success) {
originalSettings.value = { ...settings.value };
$toast.success("Settings saved successfully");
alert("Settings saved successfully");
// Apply changes
// applyChanges(); // Temporarily commented out to isolate the error source
@ -175,7 +175,7 @@ const saveSettings = async () => {
console.error("[SiteSettingsPage] 'result' from updateSiteSettings was undefined.");
}
$toast.error(errorMsg);
alert(errorMsg);
if (result && result.error && result.error.details) {
console.error("[SiteSettingsPage] Save settings error details:", result.error.details);
@ -189,7 +189,7 @@ const saveSettings = async () => {
// This catch block is for unexpected errors during the saveSettings execution itself,
// or if updateSiteSettings somehow re-throws an error not caught by its own try-catch.
console.error("Critical error saving settings:", error);
$toast.error("A critical error occurred. Failed to save settings.");
alert("A critical error occurred. Failed to save settings.");
} finally {
saving.value = false;
}
@ -220,7 +220,7 @@ const applyFontFromSource = () => {
}
}
$toast.success('Font applied successfully');
alert('Font applied successfully');
}
};
@ -241,7 +241,7 @@ const uploadFile = async (file, type) => {
return response.data.url;
} catch (error) {
console.error(`Error uploading ${type}:`, error);
$toast.error(`Failed to upload ${type}`);
alert(`Failed to upload ${type}`);
return null;
}
};
@ -253,7 +253,7 @@ const handleLogoUpload = async (event) => {
const url = await uploadFile(file, 'logo');
if (url) {
settings.value.siteLogo = url;
$toast.success('Logo uploaded successfully');
alert('Logo uploaded successfully');
}
}
};
@ -264,7 +264,7 @@ const handleLoadingLogoUpload = async (event) => {
const url = await uploadFile(file, 'loading-logo');
if (url) {
settings.value.siteLoadingLogo = url;
$toast.success('Loading logo uploaded successfully');
alert('Loading logo uploaded successfully');
}
}
};
@ -275,7 +275,7 @@ const handleFaviconUpload = async (event) => {
const url = await uploadFile(file, 'favicon');
if (url) {
settings.value.siteFavicon = url;
$toast.success('Favicon uploaded successfully');
alert('Favicon uploaded successfully');
}
}
};
@ -286,7 +286,7 @@ const handleLoginLogoUpload = async (event) => {
const url = await uploadFile(file, 'login-logo');
if (url) {
settings.value.siteLoginLogo = url;
$toast.success('Login logo uploaded successfully');
alert('Login logo uploaded successfully');
}
}
};
@ -295,14 +295,14 @@ const handleCSSUpload = async (event) => {
const file = event.target.files[0];
if (file) {
if (!file.name.endsWith('.css')) {
$toast.error('Please upload a valid CSS file');
alert('Please upload a valid CSS file');
return;
}
const reader = new FileReader();
reader.onload = (e) => {
settings.value.customCSS = e.target.result;
$toast.success('CSS file loaded successfully');
alert('CSS file loaded successfully');
};
reader.readAsText(file);
}
@ -314,7 +314,7 @@ const handleOgImageUpload = async (event) => {
const url = await uploadFile(file, 'og-image');
if (url) {
settings.value.seoOgImage = url;
$toast.success('OG image uploaded successfully');
alert('OG image uploaded successfully');
}
}
};
@ -332,7 +332,7 @@ const resetSettings = () => {
settings.value = { ...originalSettings.value };
errors.value = {};
applyChanges();
$toast.info('Settings reset to last saved state');
alert('Settings reset to last saved state');
};
// Check for changes
@ -364,7 +364,7 @@ const applyGoogleFont = (font) => {
settings.value.fontSource = googleFontUrl;
settings.value.currentFont = font.name;
applyFontFromSource();
$toast.success(`${font.name} font applied successfully`);
alert(`${font.name} font applied successfully`);
// Reset the dropdown after selection
selectedGoogleFont.value = '';
}
@ -451,7 +451,7 @@ watch(() => settings.value.showSiteNameInHeader, (newValue) => {
<div v-else>
<!-- Tab Navigation -->
<div class="border-b border-gray-200 dark:border-gray-700 mb-8">
<nav class="flex space-x-8" role="tablist">
<nav class="flex space-x-4" role="tablist">
<button
v-for="tab in [
{ id: 'basic', name: 'Basic', icon: 'ic:outline-info' },
@ -466,7 +466,7 @@ watch(() => settings.value.showSiteNameInHeader, (newValue) => {
activeTab === tab.id
? 'border-primary text-primary bg-primary/5'
: 'border-transparent text-gray-500 hover:text-gray-700 hover:border-gray-300 dark:text-gray-400 dark:hover:text-gray-300',
'whitespace-nowrap py-3 px-3 border-b-2 font-medium text-sm flex items-center space-x-2 rounded-t-lg transition-all duration-200'
'whitespace-nowrap py-2 px-2 border-b-2 font-medium text-sm flex items-center space-x-2 rounded-t-lg transition-all duration-200'
]"
:aria-selected="activeTab === tab.id"
role="tab"

View File

@ -1,49 +0,0 @@
<template>
<div>
<LayoutsBreadcrumb />
<section class="flex flex-col h-screen">
<div class="mb-4 flex-shrink-0">
<h3>Metabase</h3>
<p>
Metabase is a powerful data visualization and analytics tool that allows you to
create and share dashboards, reports, and visualizations with your team.
</p>
</div>
<div v-if="pending" class="flex justify-center items-center flex-1">
<div class="text-lg">Loading Metabase dashboard...</div>
</div>
<div v-else-if="error" class="flex justify-center items-center flex-1">
<div class="text-red-500">Error loading dashboard: {{ error.message }}</div>
</div>
<iframe
v-else
:src="iframeUrl"
frameborder="0"
width="100%"
class="flex-1"
allowtransparency
/>
</section>
</div>
</template>
<script setup>
// Fetch the JWT token from our server API
const { data: tokenData, pending, error } = await useFetch("/api/metabase/token");
const iframeUrl = computed(() => {
if (tokenData.value?.token && tokenData.value?.siteUrl) {
return (
tokenData.value.siteUrl +
"/embed/dashboard/" +
tokenData.value.token +
"#bordered=true&titled=true"
);
}
return "";
});
</script>
<style lang="scss" scoped></style>

View File

@ -1,30 +0,0 @@
<script setup>
definePageMeta({
title: "Notes",
middleware: ["auth"],
requiresAuth: true,
});
</script>
<template>
<div>
<LayoutsBreadcrumb />
<rs-card>
<template #header>
<div>
Notes
</div>
</template>
<template #body>
<div>
Content for Notes
</div>
</template>
</rs-card>
</div>
</template>
<style scoped>
/* Add your styles here */
</style>

View File

@ -0,0 +1,44 @@
import { PrismaClient } from "@prisma/client";
const prisma = new PrismaClient();
export default defineEventHandler(async (event) => {
const method = getMethod(event);
try {
if (method === "GET") {
// Get only the loading logo and site name for faster loading
const settings = await prisma.site_settings.findFirst({
select: {
siteLoadingLogo: true,
siteName: true,
},
orderBy: { settingID: "desc" },
});
return {
statusCode: 200,
message: "Success",
data: {
siteLoadingLogo: settings?.siteLoadingLogo || '',
siteName: settings?.siteName || 'corradAF',
},
};
}
return {
statusCode: 405,
message: "Method not allowed",
};
} catch (error) {
console.error("Loading logo API error:", error);
return {
statusCode: 500,
message: "Internal server error",
error: error.message,
};
} finally {
await prisma.$disconnect();
}
});