routing inside url
This commit is contained in:
parent
2d0fb30558
commit
6247c385c3
15 changed files with 278 additions and 203 deletions
|
@ -1,6 +1,6 @@
|
|||
<template>
|
||||
<footer
|
||||
v-if="authCheck && routeName == 'admin'"
|
||||
v-if="authCheck && routeName.includes('admin')"
|
||||
class="md:hidden flex flex-row h-16 justify-center md:justify-normal p-1 bg-white"
|
||||
>
|
||||
<div class="w-full flex flex-row gap-2 h-full align-middle">
|
||||
|
@ -23,7 +23,7 @@ export default defineComponent({
|
|||
...mapState(useAuthStore, ["authCheck"]),
|
||||
...mapState(useNavigationStore, ["topLevel"]),
|
||||
routeName() {
|
||||
return this.$route.name;
|
||||
return typeof this.$route.name == "string" ? this.$route.name : "";
|
||||
},
|
||||
},
|
||||
});
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
<h1 v-if="false" class="font-bold text-3xl w-fit whitespace-nowrap">Mitgliederverwaltung</h1>
|
||||
</RouterLink>
|
||||
<div class="flex flex-row gap-2 items-center">
|
||||
<div v-if="authCheck && routeName == 'admin'" class="hidden md:flex flex-row gap-2 h-full align-middle">
|
||||
<div v-if="authCheck && routeName.includes('admin')" class="hidden md:flex flex-row gap-2 h-full align-middle">
|
||||
<TopLevelLink v-for="item in topLevel" :key="item.key" :link="item" />
|
||||
</div>
|
||||
<UserMenu v-if="authCheck" />
|
||||
|
@ -29,7 +29,7 @@ export default defineComponent({
|
|||
...mapState(useAuthStore, ["authCheck"]),
|
||||
...mapState(useNavigationStore, ["topLevel"]),
|
||||
routeName() {
|
||||
return this.$route.name;
|
||||
return typeof this.$route.name == "string" ? this.$route.name : "";
|
||||
},
|
||||
},
|
||||
});
|
||||
|
|
|
@ -1,16 +1,14 @@
|
|||
<template>
|
||||
<div
|
||||
v-if="link"
|
||||
class="cursor-pointer w-full px-2 py-3"
|
||||
:class="
|
||||
activeLink?.key == link.key
|
||||
? 'rounded-r-lg bg-red-200 border-l-4 border-l-primary'
|
||||
: 'pl-3 hover:bg-red-200 rounded-lg'
|
||||
"
|
||||
@click="setLink(link.key)"
|
||||
>
|
||||
{{ link.title }}
|
||||
</div>
|
||||
<RouterLink v-if="link" v-slot="{ isExactActive }" :to="{ name: `admin-${activeNavigation}-${link.key}` }">
|
||||
<p
|
||||
class="cursor-pointer w-full px-2 py-3"
|
||||
:class="
|
||||
isExactActive ? 'rounded-r-lg bg-red-200 border-l-4 border-l-primary' : 'pl-3 hover:bg-red-200 rounded-lg'
|
||||
"
|
||||
>
|
||||
{{ link.title }}
|
||||
</p>
|
||||
</RouterLink>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
|
@ -20,6 +18,7 @@ import { useNavigationStore, type navigationLinkModel } from "@/stores/admin/nav
|
|||
|
||||
<script lang="ts">
|
||||
import { defineComponent, type PropType } from "vue";
|
||||
import { RouterLink } from "vue-router";
|
||||
export default defineComponent({
|
||||
props: {
|
||||
link: {
|
||||
|
@ -28,11 +27,7 @@ export default defineComponent({
|
|||
},
|
||||
},
|
||||
computed: {
|
||||
...mapState(useNavigationStore, ["activeLink"]),
|
||||
},
|
||||
methods: {
|
||||
...mapActions(useNavigationStore, ["setLink"]),
|
||||
...mapState(useNavigationStore, ["activeNavigation"]),
|
||||
},
|
||||
});
|
||||
</script>
|
||||
@/stores/contest/viewManager
|
||||
|
|
|
@ -1,25 +1,30 @@
|
|||
<template>
|
||||
<div
|
||||
<RouterLink
|
||||
v-if="link"
|
||||
class="cursor-pointer w-full flex flex-col md:flex-row items-center md:gap-2 justify-center p-1 md:rounded-full md:px-3 font-medium text-center text-base self-center"
|
||||
:class="
|
||||
activeNavigation == link.key
|
||||
? 'text-primary md:bg-primary md:text-white'
|
||||
: 'text-gray-700 hover:text-accent md:hover:bg-accent md:hover:text-white'
|
||||
"
|
||||
@click="setTopLevel(link.key, disableSubLink)"
|
||||
:to="{ name: `admin-${link.key}-${!disableSubLink ? link.levelDefault : 'default'}` }"
|
||||
class="cursor-pointer w-full flex items-center justify-center self-center"
|
||||
>
|
||||
{{ link.title }}
|
||||
</div>
|
||||
<p
|
||||
class="cursor-pointer w-full flex flex-col md:flex-row items-center md:gap-2 justify-center p-1 md:rounded-full md:px-3 font-medium text-center text-base self-center"
|
||||
:class="
|
||||
activeNavigation == link.key
|
||||
? 'text-primary md:bg-primary md:text-white'
|
||||
: 'text-gray-700 hover:text-accent md:hover:bg-accent md:hover:text-white'
|
||||
"
|
||||
>
|
||||
{{ link.title }}
|
||||
</p>
|
||||
</RouterLink>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { mapState, mapActions } from "pinia";
|
||||
import { useNavigationStore, type topLevelNavigationModel } from "@/stores/admin/navigation";
|
||||
import { mapState } from "pinia";
|
||||
</script>
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent, type PropType } from "vue";
|
||||
import { RouterLink } from "vue-router";
|
||||
export default defineComponent({
|
||||
props: {
|
||||
link: {
|
||||
|
@ -34,8 +39,5 @@ export default defineComponent({
|
|||
computed: {
|
||||
...mapState(useNavigationStore, ["activeNavigation"]),
|
||||
},
|
||||
methods: {
|
||||
...mapActions(useNavigationStore, ["setTopLevel"]),
|
||||
},
|
||||
});
|
||||
</script>
|
||||
|
|
|
@ -2,16 +2,18 @@
|
|||
<div class="flex flex-col h-fit w-full border border-primary rounded-md">
|
||||
<div class="bg-primary p-2 text-white flex flex-row justify-between items-center">
|
||||
<p>{{ role.role }} <small v-if="role.permissions?.isAdmin">(Admin)</small></p>
|
||||
<PencilIcon class="w-5 h-5 p-1 box-content cursor-pointer" />
|
||||
<PencilIcon class="w-5 h-5 p-1 box-content cursor-pointer" @click="openUpdateModal" />
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { defineComponent, type PropType } from "vue";
|
||||
import { defineComponent, defineAsyncComponent, markRaw, type PropType } from "vue";
|
||||
import { mapState, mapActions } from "pinia";
|
||||
import { PencilIcon } from "@heroicons/vue/outline";
|
||||
import type { RoleViewModel } from "@/viewmodels/admin/role.models";
|
||||
import { useModalStore } from "@/stores/modal";
|
||||
import { useNavigationStore } from "@/stores/admin/navigation";
|
||||
</script>
|
||||
|
||||
<script lang="ts">
|
||||
|
@ -23,5 +25,14 @@ export default defineComponent({
|
|||
return {};
|
||||
},
|
||||
mounted() {},
|
||||
methods: {
|
||||
...mapActions(useModalStore, ["openModal"]),
|
||||
openUpdateModal() {
|
||||
this.openModal(
|
||||
markRaw(defineAsyncComponent(() => import("@/components/admin/user/role/UpdateRoleModal.vue"))),
|
||||
this.role.id
|
||||
);
|
||||
},
|
||||
},
|
||||
});
|
||||
</script>
|
||||
|
|
54
src/components/admin/user/role/UpdateRoleModal.vue
Normal file
54
src/components/admin/user/role/UpdateRoleModal.vue
Normal file
|
@ -0,0 +1,54 @@
|
|||
<template>
|
||||
<div class="flex flex-col items-center gap-2 w-full max-w-6xl h-1/2 max-h-3/4">
|
||||
<div class="flex flex-col">
|
||||
<p class="text-xl font-medium">Rolle bearbeiten</p>
|
||||
</div>
|
||||
<form class="flex flex-col gap-4 py-2 w-full max-w-xl" @submit.prevent="">
|
||||
<div>
|
||||
<label for="role">Rollenbezeichnung</label>
|
||||
<input type="text" id="role" required />
|
||||
</div>
|
||||
<div class="flex flex-row gap-2">
|
||||
<button primary type="submit" :disabled="createStatus == 'loading' || createStatus?.status == 'success'">
|
||||
speichern
|
||||
</button>
|
||||
<Spinner v-if="createStatus == 'loading'" class="my-auto" />
|
||||
<SuccessCheckmark v-else-if="createStatus?.status == 'success'" />
|
||||
<FailureXMark v-else-if="createStatus?.status == 'failed'" />
|
||||
</div>
|
||||
</form>
|
||||
|
||||
<div class="flex flex-row self-end mt-auto">
|
||||
<div class="flex flex-row gap-4 py-2">
|
||||
<button primary-outline @click="closeModal">schließen</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { defineComponent } from "vue";
|
||||
import { mapState, mapActions } from "pinia";
|
||||
import { useModalStore } from "@/stores/modal";
|
||||
import Spinner from "@/components/Spinner.vue";
|
||||
import SuccessCheckmark from "@/components/SuccessCheckmark.vue";
|
||||
import FailureXMark from "@/components/FailureXMark.vue";
|
||||
import { useRoleStore } from "@/stores/admin/role";
|
||||
import Permission from "../../Permission.vue";
|
||||
</script>
|
||||
|
||||
<script lang="ts">
|
||||
export default defineComponent({
|
||||
mounted() {
|
||||
this.fetchRoleById(this.data);
|
||||
},
|
||||
computed: {
|
||||
...mapState(useRoleStore, ["createStatus", "role"]),
|
||||
...mapState(useModalStore, ["data"]),
|
||||
},
|
||||
methods: {
|
||||
...mapActions(useModalStore, ["closeModal"]),
|
||||
...mapActions(useRoleStore, ["fetchRoleById"]),
|
||||
},
|
||||
});
|
||||
</script>
|
|
@ -6,7 +6,7 @@
|
|||
>
|
||||
<slot name="sidebar"></slot>
|
||||
</div>
|
||||
<div class="max-w-full grow flex-col gap-4" :class="defaultRoute && defaultSidebar ? 'hidden md:flex' : 'flex'">
|
||||
<div class="max-w-full grow flex-col gap-2" :class="defaultRoute && defaultSidebar ? 'hidden md:flex' : 'flex'">
|
||||
<slot name="main"></slot>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -29,7 +29,7 @@ export default defineComponent({
|
|||
computed: {
|
||||
...mapState(useNavigationStore, ["activeLink"]),
|
||||
defaultRoute() {
|
||||
return this.activeLink == null;
|
||||
return ((this.$route?.name as string) ?? "").includes("-default");
|
||||
},
|
||||
},
|
||||
});
|
||||
|
|
24
src/router/adminGuard.ts
Normal file
24
src/router/adminGuard.ts
Normal file
|
@ -0,0 +1,24 @@
|
|||
import NProgress from "nprogress";
|
||||
import { useAbilityStore } from "../stores/ability";
|
||||
import { useNavigationStore } from "../stores/admin/navigation";
|
||||
|
||||
export async function abilityAndNavUpdate(to: any, from: any, next: any) {
|
||||
NProgress.start();
|
||||
const ability = useAbilityStore();
|
||||
const navigation = useNavigationStore();
|
||||
|
||||
let type = to.meta.type;
|
||||
let section = to.meta.section;
|
||||
let module = to.meta.module;
|
||||
|
||||
navigation.activeNavigation = to.name.split("-")[1];
|
||||
navigation.activeLink = to.name.split("-")[2];
|
||||
|
||||
if (ability.can(type, section, module)) {
|
||||
NProgress.done();
|
||||
next();
|
||||
} else {
|
||||
NProgress.done();
|
||||
next(false);
|
||||
}
|
||||
}
|
|
@ -4,6 +4,8 @@ import Login from "../views/Login.vue";
|
|||
import { isAuthenticated } from "./authGuards";
|
||||
import { loadAccountData } from "./accountGuard";
|
||||
import { isSetup } from "./setupGuard";
|
||||
import { abilityAndNavUpdate } from "./adminGuard";
|
||||
import type { PermissionType, PermissionSection, PermissionModule } from "../types/permissionTypes";
|
||||
|
||||
const router = createRouter({
|
||||
history: createWebHistory(import.meta.env.BASE_URL),
|
||||
|
@ -41,6 +43,110 @@ const router = createRouter({
|
|||
name: "admin",
|
||||
component: () => import("../views/admin/View.vue"),
|
||||
beforeEnter: [isAuthenticated],
|
||||
children: [
|
||||
{
|
||||
path: "",
|
||||
name: "admin-default",
|
||||
component: () => import("../views/RouterView.vue"),
|
||||
},
|
||||
{
|
||||
path: "club",
|
||||
name: "admin-club",
|
||||
component: () => import("../views/RouterView.vue"),
|
||||
meta: { type: "read", section: "club" },
|
||||
beforeEnter: [abilityAndNavUpdate],
|
||||
children: [
|
||||
{
|
||||
path: "",
|
||||
name: "admin-club-default",
|
||||
component: () => import("../views/admin/ViewSelect.vue"),
|
||||
},
|
||||
{
|
||||
path: "members",
|
||||
name: "admin-club-members",
|
||||
component: () => import("../views/admin/members/Overview.vue"),
|
||||
},
|
||||
{
|
||||
path: "calendar",
|
||||
name: "admin-club-calendar",
|
||||
component: () => import("../views/admin/members/Overview.vue"),
|
||||
},
|
||||
{
|
||||
path: "newsletter",
|
||||
name: "admin-club-newsletter",
|
||||
component: () => import("../views/admin/members/Overview.vue"),
|
||||
},
|
||||
{
|
||||
path: "protocol",
|
||||
name: "admin-club-protocol",
|
||||
component: () => import("../views/admin/members/Overview.vue"),
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
path: "settings",
|
||||
name: "admin-settings",
|
||||
component: () => import("../views/RouterView.vue"),
|
||||
meta: { type: "read", section: "settings" },
|
||||
beforeEnter: [abilityAndNavUpdate],
|
||||
children: [
|
||||
{
|
||||
path: "",
|
||||
name: "admin-settings-default",
|
||||
component: () => import("../views/admin/ViewSelect.vue"),
|
||||
},
|
||||
{
|
||||
path: "qualification",
|
||||
name: "admin-settings-qualification",
|
||||
component: () => import("../views/admin/members/Overview.vue"),
|
||||
},
|
||||
{
|
||||
path: "award",
|
||||
name: "admin-settings-award",
|
||||
component: () => import("../views/admin/members/Overview.vue"),
|
||||
},
|
||||
{
|
||||
path: "executive-position",
|
||||
name: "admin-settings-executive_position",
|
||||
component: () => import("../views/admin/members/Overview.vue"),
|
||||
},
|
||||
{
|
||||
path: "communication",
|
||||
name: "admin-settings-communication",
|
||||
component: () => import("../views/admin/members/Overview.vue"),
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
path: "user",
|
||||
name: "admin-user",
|
||||
component: () => import("../views/RouterView.vue"),
|
||||
meta: { type: "read", section: "user" },
|
||||
beforeEnter: [abilityAndNavUpdate],
|
||||
children: [
|
||||
{
|
||||
path: "",
|
||||
name: "admin-user-default",
|
||||
component: () => import("../views/admin/ViewSelect.vue"),
|
||||
},
|
||||
{
|
||||
path: "user",
|
||||
name: "admin-user-user",
|
||||
component: () => import("../views/admin/user/User.vue"),
|
||||
},
|
||||
{
|
||||
path: "role",
|
||||
name: "admin-user-role",
|
||||
component: () => import("../views/admin/user/Role.vue"),
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
path: ":pathMatch(.*)*",
|
||||
name: "admin-404",
|
||||
component: () => import("../views/notFound.vue"),
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
path: "/nopermissions",
|
||||
|
@ -56,3 +162,11 @@ const router = createRouter({
|
|||
});
|
||||
|
||||
export default router;
|
||||
|
||||
declare module "vue-router" {
|
||||
interface RouteMeta {
|
||||
type?: PermissionType | "admin";
|
||||
section?: PermissionSection;
|
||||
module?: PermissionModule;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import { defineStore } from "pinia";
|
||||
import { shallowRef, defineAsyncComponent } from "vue";
|
||||
import { useAbilityStore } from "../ability";
|
||||
import router from "../../router";
|
||||
|
||||
export interface navigationModel {
|
||||
club: navigationSplitModel;
|
||||
|
@ -26,17 +26,15 @@ export interface topLevelNavigationModel {
|
|||
export interface navigationLinkModel {
|
||||
key: string;
|
||||
title: string;
|
||||
component: any;
|
||||
}
|
||||
|
||||
export const useNavigationStore = defineStore("navigation", {
|
||||
state: () => {
|
||||
return {
|
||||
activeNavigation: "club" as topLevelNavigationType,
|
||||
activeLink: null as null | navigationLinkModel,
|
||||
activeLink: null as null | string,
|
||||
topLevel: [] as Array<topLevelNavigationModel>,
|
||||
navigation: {} as navigationModel,
|
||||
componentOverwrite: null as null | any,
|
||||
};
|
||||
},
|
||||
getters: {
|
||||
|
@ -45,42 +43,10 @@ export const useNavigationStore = defineStore("navigation", {
|
|||
(state.topLevel.find((elem) => elem.key == state.activeNavigation) ?? {}) as topLevelNavigationModel,
|
||||
},
|
||||
actions: {
|
||||
setTopLevel(key: topLevelNavigationType, disableSubLink: boolean = true) {
|
||||
let level = this.topLevel.find((e) => e.key == key) ?? null;
|
||||
if (!level) {
|
||||
this.activeNavigation = "club";
|
||||
if (!disableSubLink) this.setLink(this.topLevel.find((e) => e.key == "club")?.levelDefault ?? null);
|
||||
else this.setLink(null);
|
||||
} else {
|
||||
this.activeNavigation = level.key;
|
||||
if (!disableSubLink) this.setLink(level.levelDefault);
|
||||
else this.setLink(null);
|
||||
}
|
||||
this.resetComponentOverwrite();
|
||||
},
|
||||
setLink(key: string | null) {
|
||||
let nav = this.navigation[this.activeNavigation];
|
||||
if (!nav) {
|
||||
this.activeLink = null;
|
||||
return;
|
||||
}
|
||||
let links = [...Object.values(nav.main), ...Object.values(nav.top ?? {})];
|
||||
this.activeLink = links.find((e) => e.key == key) ?? null;
|
||||
this.resetComponentOverwrite();
|
||||
},
|
||||
setTopLevelNav(topLeveLinks: Array<topLevelNavigationModel>) {
|
||||
this.topLevel = topLeveLinks;
|
||||
},
|
||||
setComponentOverwrite(component: any) {
|
||||
this.componentOverwrite = component;
|
||||
},
|
||||
resetComponentOverwrite() {
|
||||
this.componentOverwrite = null;
|
||||
},
|
||||
resetNavigation() {
|
||||
this.$reset();
|
||||
},
|
||||
updateTopLevel() {
|
||||
updateTopLevel(first: boolean = false) {
|
||||
const abilityStore = useAbilityStore();
|
||||
this.topLevel = [
|
||||
...(abilityStore.canSection("read", "club")
|
||||
|
@ -88,7 +54,7 @@ export const useNavigationStore = defineStore("navigation", {
|
|||
{
|
||||
key: "club",
|
||||
title: "Verein",
|
||||
levelDefault: "#members",
|
||||
levelDefault: "members",
|
||||
} as topLevelNavigationModel,
|
||||
]
|
||||
: []),
|
||||
|
@ -97,7 +63,7 @@ export const useNavigationStore = defineStore("navigation", {
|
|||
{
|
||||
key: "settings",
|
||||
title: "Einstellungen",
|
||||
levelDefault: "#qualification",
|
||||
levelDefault: "qualification",
|
||||
} as topLevelNavigationModel,
|
||||
]
|
||||
: []),
|
||||
|
@ -106,124 +72,51 @@ export const useNavigationStore = defineStore("navigation", {
|
|||
{
|
||||
key: "user",
|
||||
title: "Benutzer",
|
||||
levelDefault: "#user",
|
||||
levelDefault: "user",
|
||||
} as topLevelNavigationModel,
|
||||
]
|
||||
: []),
|
||||
];
|
||||
if (this.topLevel.findIndex((e) => e.key == this.activeNavigation) == -1)
|
||||
this.activeNavigation = this.topLevel[0]?.key ?? "club";
|
||||
if (this.topLevel.findIndex((e) => e.key == this.activeNavigation) == -1 && !first)
|
||||
router.push({ name: `admin-${this.topLevel[0]?.key ?? "club"}-default` });
|
||||
},
|
||||
updateNavigation() {
|
||||
updateNavigation(first: boolean = false) {
|
||||
const abilityStore = useAbilityStore();
|
||||
this.navigation = {
|
||||
club: {
|
||||
mainTitle: "Verein",
|
||||
main: [
|
||||
...(abilityStore.can("read", "club", "members")
|
||||
? [
|
||||
{
|
||||
key: "#members",
|
||||
title: "Mitglieder",
|
||||
component: shallowRef(defineAsyncComponent(() => import("@/views/admin/members/Overview.vue"))),
|
||||
},
|
||||
]
|
||||
: []),
|
||||
...(abilityStore.can("read", "club", "calendar")
|
||||
? [
|
||||
{
|
||||
key: "#calendar",
|
||||
title: "Termine",
|
||||
component: shallowRef(defineAsyncComponent(() => import("@/views/admin/members/Overview.vue"))),
|
||||
},
|
||||
]
|
||||
: []),
|
||||
...(abilityStore.can("read", "club", "newsletter")
|
||||
? [
|
||||
{
|
||||
key: "#newsletter",
|
||||
title: "Newsletter",
|
||||
component: shallowRef(defineAsyncComponent(() => import("@/views/admin/members/Overview.vue"))),
|
||||
},
|
||||
]
|
||||
: []),
|
||||
...(abilityStore.can("read", "club", "protocoll")
|
||||
? [
|
||||
{
|
||||
key: "#protocol",
|
||||
title: "Protokolle",
|
||||
component: shallowRef(defineAsyncComponent(() => import("@/views/admin/members/Overview.vue"))),
|
||||
},
|
||||
]
|
||||
: []),
|
||||
...(abilityStore.can("read", "club", "members") ? [{ key: "members", title: "Mitglieder" }] : []),
|
||||
...(abilityStore.can("read", "club", "calendar") ? [{ key: "calendar", title: "Termine" }] : []),
|
||||
...(abilityStore.can("read", "club", "newsletter") ? [{ key: "newsletter", title: "Newsletter" }] : []),
|
||||
...(abilityStore.can("read", "club", "protocoll") ? [{ key: "protocol", title: "Protokolle" }] : []),
|
||||
],
|
||||
},
|
||||
settings: {
|
||||
mainTitle: "Einstellungen",
|
||||
main: [
|
||||
...(abilityStore.can("read", "settings", "qualification")
|
||||
? [
|
||||
{
|
||||
key: "#qualification",
|
||||
title: "Qualifikationen",
|
||||
component: shallowRef(defineAsyncComponent(() => import("@/views/admin/members/Overview.vue"))),
|
||||
},
|
||||
]
|
||||
: []),
|
||||
...(abilityStore.can("read", "settings", "award")
|
||||
? [
|
||||
{
|
||||
key: "#award",
|
||||
title: "Auszeichnungen",
|
||||
component: shallowRef(defineAsyncComponent(() => import("@/views/admin/members/Overview.vue"))),
|
||||
},
|
||||
]
|
||||
? [{ key: "qualification", title: "Qualifikationen" }]
|
||||
: []),
|
||||
...(abilityStore.can("read", "settings", "award") ? [{ key: "award", title: "Auszeichnungen" }] : []),
|
||||
...(abilityStore.can("read", "settings", "executive_position")
|
||||
? [
|
||||
{
|
||||
key: "#executive_position",
|
||||
title: "Vereinsämter",
|
||||
component: shallowRef(defineAsyncComponent(() => import("@/views/admin/members/Overview.vue"))),
|
||||
},
|
||||
]
|
||||
? [{ key: "executive_position", title: "Vereinsämter" }]
|
||||
: []),
|
||||
...(abilityStore.can("read", "settings", "communication")
|
||||
? [
|
||||
{
|
||||
key: "#communication",
|
||||
title: "Mitgliederdaten",
|
||||
component: shallowRef(defineAsyncComponent(() => import("@/views/admin/members/Overview.vue"))),
|
||||
},
|
||||
]
|
||||
? [{ key: "communication", title: "Mitgliederdaten" }]
|
||||
: []),
|
||||
],
|
||||
},
|
||||
user: {
|
||||
mainTitle: "Benutzer",
|
||||
main: [
|
||||
...(abilityStore.can("read", "user", "user")
|
||||
? [
|
||||
{
|
||||
key: "#user",
|
||||
title: "Benutzer",
|
||||
component: shallowRef(defineAsyncComponent(() => import("@/views/admin/user/User.vue"))),
|
||||
},
|
||||
]
|
||||
: []),
|
||||
...(abilityStore.can("read", "user", "role")
|
||||
? [
|
||||
{
|
||||
key: "#role",
|
||||
title: "Rollen",
|
||||
component: shallowRef(defineAsyncComponent(() => import("@/views/admin/user/Role.vue"))),
|
||||
},
|
||||
]
|
||||
: []),
|
||||
...(abilityStore.can("read", "user", "user") ? [{ key: "user", title: "Benutzer" }] : []),
|
||||
...(abilityStore.can("read", "user", "role") ? [{ key: "role", title: "Rollen" }] : []),
|
||||
],
|
||||
},
|
||||
} as navigationModel;
|
||||
if (this.topLevel.findIndex((e) => e.key == this.activeLink?.key) == -1) this.setLink(null);
|
||||
if (this.topLevel.findIndex((e) => e.key == this.activeLink) == -1 && !first)
|
||||
router.push({ name: `admin-${this.activeNavigation}-default` });
|
||||
},
|
||||
},
|
||||
});
|
||||
|
|
|
@ -25,7 +25,7 @@ export const useRoleStore = defineStore("role", {
|
|||
this.loadingAll = "failed";
|
||||
});
|
||||
},
|
||||
fetchRolesById(id: number) {
|
||||
fetchRoleById(id: number) {
|
||||
this.role = null;
|
||||
this.loadingSingle = "loading";
|
||||
http
|
||||
|
|
|
@ -24,7 +24,7 @@ export const useUserStore = defineStore("user", {
|
|||
this.loadingAll = "failed";
|
||||
});
|
||||
},
|
||||
fetchUsersById(id: number) {
|
||||
fetchUserById(id: number) {
|
||||
this.user = null;
|
||||
this.loadingSingle = "loading";
|
||||
http
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
<template>
|
||||
<div v-if="!defaultRoute && showBack" class="flex md:hidden flex-row items-baseline">
|
||||
<p v-if="!defaultRoute && showBack" class="text-primary" @click="setLink(null)">zur Übersicht</p>
|
||||
<RouterLink v-if="!defaultRoute && showBack" :to="{ name: `${rootRoute}-default` }" class="mid:hidden text-primary">
|
||||
zur Übersicht
|
||||
</RouterLink>
|
||||
</div>
|
||||
<slot v-if="headerInsert" name="headerInsert"></slot>
|
||||
<div
|
||||
|
@ -37,7 +39,10 @@ export default defineComponent({
|
|||
computed: {
|
||||
...mapState(useNavigationStore, ["activeLink"]),
|
||||
defaultRoute() {
|
||||
return this.activeLink == null;
|
||||
return ((this.$route?.name as string) ?? "").includes("-default");
|
||||
},
|
||||
rootRoute() {
|
||||
return ((this.$route?.name as string) ?? "").split("-")[0];
|
||||
},
|
||||
diffMain() {
|
||||
return this.$slots.diffMain;
|
||||
|
@ -49,8 +54,5 @@ export default defineComponent({
|
|||
return window.matchMedia("(min-width: 800px)").matches;
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
...mapActions(useNavigationStore, ["setLink"]),
|
||||
},
|
||||
});
|
||||
</script>
|
||||
|
|
|
@ -15,8 +15,7 @@
|
|||
</SidebarTemplate>
|
||||
</template>
|
||||
<template #main>
|
||||
<component v-if="display" :is="displayed" />
|
||||
<div v-else class="w-full h-full bg-white rounded-lg"></div>
|
||||
<RouterView />
|
||||
</template>
|
||||
</SidebarLayout>
|
||||
</template>
|
||||
|
@ -29,6 +28,7 @@ import SidebarLayout from "@/layouts/Sidebar.vue";
|
|||
import SidebarTemplate from "@/templates/Sidebar.vue";
|
||||
import RoutingLink from "@/components/admin/RoutingLink.vue";
|
||||
import { useAbilityStore } from "../../stores/ability";
|
||||
import RouterView from "../RouterView.vue";
|
||||
</script>
|
||||
|
||||
<script lang="ts">
|
||||
|
@ -40,44 +40,21 @@ export default defineComponent({
|
|||
},
|
||||
},
|
||||
computed: {
|
||||
...mapState(useNavigationStore, [
|
||||
"activeNavigationObject",
|
||||
"activeTopLevelObject",
|
||||
"activeLink",
|
||||
"componentOverwrite",
|
||||
]),
|
||||
display(): boolean {
|
||||
return this.activeLink?.component || this.componentOverwrite;
|
||||
},
|
||||
displayed() {
|
||||
if (this.componentOverwrite != null) {
|
||||
return this.componentOverwrite;
|
||||
} else {
|
||||
return this.activeLink?.component;
|
||||
}
|
||||
},
|
||||
...mapState(useNavigationStore, ["activeNavigationObject", "activeTopLevelObject", "activeLink"]),
|
||||
},
|
||||
created() {
|
||||
useAbilityStore().$subscribe(() => {
|
||||
this.updateTopLevel();
|
||||
this.updateNavigation();
|
||||
});
|
||||
this.updateTopLevel();
|
||||
this.updateNavigation();
|
||||
|
||||
this.setLink(this.activeTopLevelObject.levelDefault);
|
||||
this.updateTopLevel(true);
|
||||
this.updateNavigation(true);
|
||||
},
|
||||
beforeUnmount() {
|
||||
this.resetNavigation();
|
||||
},
|
||||
methods: {
|
||||
...mapActions(useNavigationStore, [
|
||||
"setLink",
|
||||
"resetNavigation",
|
||||
"setTopLevel",
|
||||
"updateTopLevel",
|
||||
"updateNavigation",
|
||||
]),
|
||||
...mapActions(useNavigationStore, ["resetNavigation", "updateTopLevel", "updateNavigation"]),
|
||||
},
|
||||
});
|
||||
</script>
|
||||
|
|
3
src/views/admin/ViewSelect.vue
Normal file
3
src/views/admin/ViewSelect.vue
Normal file
|
@ -0,0 +1,3 @@
|
|||
<template>
|
||||
<div class="w-full h-full bg-white rounded-md flex items-center justify-center">bitte auswählen</div>
|
||||
</template>
|
Loading…
Reference in a new issue