117 lines
3.5 KiB
TypeScript
117 lines
3.5 KiB
TypeScript
import { createRouter, createWebHistory, type RouteRecordRaw } from 'vue-router';
|
|
import { useUserStore } from '@KTXC/stores/userStore';
|
|
import { useLayoutStore } from '@KTXC/stores/layoutStore';
|
|
import BlankLayout from '@KTXC/layouts/blank/BlankLayout.vue';
|
|
import PrivateLayout from '@KTXC/views/PrivateLayout.vue';
|
|
import { usePreferencesStore } from '@KTXC/stores/preferencesStore';
|
|
import { useIntegrationStore } from '@KTXC/stores/integrationStore';
|
|
|
|
const routes: RouteRecordRaw[] = [
|
|
// Public login route
|
|
{
|
|
name: 'login',
|
|
path: '/login',
|
|
meta: { requiresAuth: false },
|
|
component: BlankLayout,
|
|
children: [
|
|
{
|
|
path: '',
|
|
component: () => import('@KTXC/views/authentication/LoginPage.vue')
|
|
}
|
|
]
|
|
},
|
|
// Logout performs action then redirects
|
|
{
|
|
name: 'logout',
|
|
path: '/logout',
|
|
meta: { requiresAuth: true },
|
|
component: BlankLayout,
|
|
beforeEnter: async () => {
|
|
const userStore = useUserStore();
|
|
await userStore.logout();
|
|
return false;
|
|
}
|
|
},
|
|
// Private area (shell layout). Module routes under /m/{namespace} are added at runtime.
|
|
{
|
|
name: 'private',
|
|
path: '/',
|
|
component: PrivateLayout,
|
|
meta: { requiresAuth: true },
|
|
children: [
|
|
// Index redirects to the first available module route (if any)
|
|
{
|
|
name: 'home',
|
|
path: '',
|
|
meta: { requiresAuth: true },
|
|
component: BlankLayout,
|
|
beforeEnter: (to, from, next) => {
|
|
const integrationStore = useIntegrationStore();
|
|
const preferences = usePreferencesStore();
|
|
|
|
// Treat preference as a route name (e.g., "samples.overview")
|
|
const preferredRouteName = preferences.preferences.default_module;
|
|
if (preferredRouteName) {
|
|
// If a route with this name exists, go there
|
|
try {
|
|
// using router variable at runtime:
|
|
// eslint-disable-next-line @typescript-eslint/no-use-before-define
|
|
const exists = router.getRoutes().some(r => r.name === preferredRouteName);
|
|
if (exists) return next({ name: preferredRouteName });
|
|
} catch {}
|
|
}
|
|
|
|
// Get first available menu item from app_menu
|
|
const entries = integrationStore.getPoint('app_menu');
|
|
for (const entry of entries) {
|
|
// Check if it's a group with items
|
|
if ('items' in entry && entry.items.length > 0) {
|
|
const first = entry.items[0]?.to;
|
|
if (first) return next(first);
|
|
}
|
|
// Or a standalone item
|
|
if ('to' in entry && entry.to) {
|
|
return next(entry.to);
|
|
}
|
|
}
|
|
return next();
|
|
}
|
|
}
|
|
]
|
|
}
|
|
];
|
|
|
|
export const router = createRouter({
|
|
history: createWebHistory(import.meta.env.BASE_URL),
|
|
routes
|
|
});
|
|
|
|
router.beforeEach(async (to, from, next) => {
|
|
const userStore = useUserStore();
|
|
|
|
const authRequired = to.matched.some((record) => record.meta?.requiresAuth);
|
|
|
|
if (authRequired && !userStore.user && to.path !== '/login') {
|
|
userStore.returnUrl = to.fullPath;
|
|
return next('/login');
|
|
}
|
|
|
|
if (userStore.user && to.path === '/login') {
|
|
const dest = userStore.returnUrl && userStore.returnUrl !== '/' ? userStore.returnUrl : '/';
|
|
return next(dest);
|
|
}
|
|
|
|
return next();
|
|
});
|
|
|
|
router.beforeEach(() => {
|
|
const layoutStore = useLayoutStore();
|
|
layoutStore.isLoading = true;
|
|
});
|
|
|
|
router.afterEach(() => {
|
|
const layoutStore = useLayoutStore();
|
|
layoutStore.isLoading = false;
|
|
});
|
|
|
|
export default router |