Enhance loading experience by implementing quick loading logo fetch during SSR, update loading logo and site name retrieval logic, and replace toast notifications with alert prompts in site settings management. Remove unused Metabase and Notes pages.
This commit is contained in:
parent
4fed69246f
commit
bcbf2f0958
@ -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>
|
||||
|
||||
|
@ -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": {}
|
||||
|
@ -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"
|
||||
|
@ -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>
|
@ -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>
|
||||
|
44
server/api/devtool/config/loading-logo.js
Normal file
44
server/api/devtool/config/loading-logo.js
Normal 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();
|
||||
}
|
||||
});
|
Loading…
x
Reference in New Issue
Block a user