feat: introducing Auth for admin dashboard (HBE-138) (#32)
This commit is contained in:
19
packages/hoppscotch-sh-admin/src/modules/admin.ts
Normal file
19
packages/hoppscotch-sh-admin/src/modules/admin.ts
Normal file
@@ -0,0 +1,19 @@
|
||||
import { auth } from '~/helpers/auth';
|
||||
import { HoppModule } from '.';
|
||||
|
||||
const isAdmin = () => {
|
||||
const user = auth.getCurrentUser();
|
||||
return user ? user.isAdmin : false;
|
||||
};
|
||||
|
||||
export default <HoppModule>{
|
||||
onBeforeRouteChange(to, from, next) {
|
||||
if (to.name !== 'index' && !isAdmin()) {
|
||||
next({ name: 'index' });
|
||||
} else if (to.name === 'index' && isAdmin()) {
|
||||
next({ name: 'dashboard' });
|
||||
} else {
|
||||
next();
|
||||
}
|
||||
},
|
||||
};
|
||||
57
packages/hoppscotch-sh-admin/src/modules/index.ts
Normal file
57
packages/hoppscotch-sh-admin/src/modules/index.ts
Normal file
@@ -0,0 +1,57 @@
|
||||
import { App } from 'vue';
|
||||
import { pipe } from 'fp-ts/function';
|
||||
import * as A from 'fp-ts/Array';
|
||||
import {
|
||||
NavigationGuardNext,
|
||||
RouteLocationNormalized,
|
||||
Router,
|
||||
} from 'vue-router';
|
||||
|
||||
export type HoppModule = {
|
||||
/**
|
||||
* Define this function to get access to Vue App instance and augment
|
||||
* it (installing components, directives and plugins). Also useful for
|
||||
* early generic initializations. This function should be called first
|
||||
*/
|
||||
onVueAppInit?: (app: App) => void;
|
||||
|
||||
/**
|
||||
* Called when the router is done initializing.
|
||||
* Used if a module requires access to the router instance
|
||||
*/
|
||||
onRouterInit?: (app: App, router: Router) => void;
|
||||
|
||||
/**
|
||||
* Called when the root component (App.vue) is running setup.
|
||||
* This function is generally called last in the lifecycle.
|
||||
* This function executes with a component setup context, so you can
|
||||
* run composables within this and it should just be scoped to the
|
||||
* root component
|
||||
*/
|
||||
onRootSetup?: () => void;
|
||||
|
||||
/**
|
||||
* Called by the router to tell all the modules before a route navigation
|
||||
* is made.
|
||||
*/
|
||||
onBeforeRouteChange?: (
|
||||
to: RouteLocationNormalized,
|
||||
from: RouteLocationNormalized,
|
||||
next: NavigationGuardNext,
|
||||
router: Router
|
||||
) => void;
|
||||
|
||||
/**
|
||||
* Called by the router to tell all the modules that a route navigation has completed
|
||||
*/
|
||||
onAfterRouteChange?: (to: RouteLocationNormalized, router: Router) => void;
|
||||
};
|
||||
|
||||
/**
|
||||
* All the modules Hoppscotch loads into the app
|
||||
*/
|
||||
export const HOPP_MODULES = pipe(
|
||||
import.meta.glob('@modules/*.ts', { eager: true }),
|
||||
Object.values,
|
||||
A.map(({ default: defaultVal }) => defaultVal as HoppModule)
|
||||
);
|
||||
72
packages/hoppscotch-sh-admin/src/modules/router.ts
Normal file
72
packages/hoppscotch-sh-admin/src/modules/router.ts
Normal file
@@ -0,0 +1,72 @@
|
||||
import { HoppModule, HOPP_MODULES } from '.';
|
||||
import {
|
||||
createRouter,
|
||||
createWebHistory,
|
||||
RouteLocationNormalized,
|
||||
} from 'vue-router';
|
||||
import { setupLayouts } from 'virtual:generated-layouts';
|
||||
import generatedRoutes from 'virtual:generated-pages';
|
||||
import { readonly, ref } from 'vue';
|
||||
|
||||
const routes = setupLayouts(generatedRoutes);
|
||||
|
||||
/**
|
||||
* A reactive value signifying whether we are currently navigating
|
||||
* into the first route the application is routing into.
|
||||
* Useful, if you want to do stuff for the initial page load (for example splash screens!)
|
||||
*/
|
||||
const _isLoadingInitialRoute = ref(false);
|
||||
|
||||
/**
|
||||
* Says whether a given route looks like an initial route which
|
||||
* is loaded as the first route.
|
||||
*
|
||||
* NOTE: This function assumes Vue Router represents that initial route
|
||||
* in the way we expect (fullPath == "/" and name == undefined). If this
|
||||
* function breaks later on, most probs vue-router updated its semantics
|
||||
* and we have to correct this function.
|
||||
*/
|
||||
function isInitialRoute(route: RouteLocationNormalized) {
|
||||
return route.fullPath === '/' && route.name === undefined;
|
||||
}
|
||||
|
||||
/**
|
||||
* A reactive value signifying whether we are currently navigating
|
||||
* into the first route the application is routing into.
|
||||
* Useful, if you want to do stuff for the initial page load (for example splash screens!)
|
||||
*
|
||||
* NOTE: This reactive value is READONLY
|
||||
*/
|
||||
export const isLoadingInitialRoute = readonly(_isLoadingInitialRoute);
|
||||
|
||||
export default <HoppModule>{
|
||||
onVueAppInit(app) {
|
||||
const router = createRouter({
|
||||
history: createWebHistory(),
|
||||
routes,
|
||||
});
|
||||
|
||||
router.beforeEach((to, from, next) => {
|
||||
_isLoadingInitialRoute.value = isInitialRoute(from);
|
||||
|
||||
HOPP_MODULES.forEach((mod) => {
|
||||
mod.onBeforeRouteChange?.(to, from, next, router);
|
||||
});
|
||||
});
|
||||
|
||||
// Instead of this a better architecture is for the router
|
||||
// module to expose a stream of router events that can be independently
|
||||
// subbed to
|
||||
router.afterEach((to) => {
|
||||
_isLoadingInitialRoute.value = false;
|
||||
|
||||
HOPP_MODULES.forEach((mod) => {
|
||||
mod.onAfterRouteChange?.(to, router);
|
||||
});
|
||||
});
|
||||
|
||||
app.use(router);
|
||||
|
||||
HOPP_MODULES.forEach((mod) => mod.onRouterInit?.(app, router));
|
||||
},
|
||||
};
|
||||
19
packages/hoppscotch-sh-admin/src/modules/toast.ts
Normal file
19
packages/hoppscotch-sh-admin/src/modules/toast.ts
Normal file
@@ -0,0 +1,19 @@
|
||||
import Toasted from '@hoppscotch/vue-toasted';
|
||||
import type { ToastOptions } from '@hoppscotch/vue-toasted';
|
||||
import { HoppModule } from '.';
|
||||
|
||||
import '@hoppscotch/vue-toasted/style.css';
|
||||
|
||||
// We are using a fork of Vue Toasted (github.com/clayzar/vue-toasted) which is a bit of
|
||||
// an untrusted fork, we will either want to make our own fork or move to a more stable one
|
||||
// The original Vue Toasted doesn't support Vue 3 and the OP has been irresponsive.
|
||||
|
||||
export default <HoppModule>{
|
||||
onVueAppInit(app) {
|
||||
app.use(Toasted, <ToastOptions>{
|
||||
position: 'bottom-center',
|
||||
duration: 3000,
|
||||
keepOnHover: true,
|
||||
});
|
||||
},
|
||||
};
|
||||
13
packages/hoppscotch-sh-admin/src/modules/ui.ts
Normal file
13
packages/hoppscotch-sh-admin/src/modules/ui.ts
Normal file
@@ -0,0 +1,13 @@
|
||||
import { HoppModule } from '.';
|
||||
import { plugin as HoppUI, HoppUIPluginOptions } from '@hoppscotch/ui';
|
||||
|
||||
const HoppUIOptions: HoppUIPluginOptions = {};
|
||||
|
||||
export default <HoppModule>{
|
||||
onVueAppInit(app) {
|
||||
// disable eslint for this line. it's a hack because there's some unknown type error
|
||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||
// @ts-ignore
|
||||
app.use(HoppUI, HoppUIOptions);
|
||||
},
|
||||
};
|
||||
15
packages/hoppscotch-sh-admin/src/modules/v-focus.ts
Normal file
15
packages/hoppscotch-sh-admin/src/modules/v-focus.ts
Normal file
@@ -0,0 +1,15 @@
|
||||
import { nextTick } from "vue"
|
||||
import { HoppModule } from "."
|
||||
|
||||
/*
|
||||
Declares a `v-focus` directive that can be used for components
|
||||
to acquire focus instantly once mounted
|
||||
*/
|
||||
|
||||
export default <HoppModule>{
|
||||
onVueAppInit(app) {
|
||||
app.directive("focus", {
|
||||
mounted: (el) => nextTick(() => el.focus()),
|
||||
})
|
||||
},
|
||||
}
|
||||
Reference in New Issue
Block a user