2024-08-27 11:46:24 +02:00
|
|
|
<template>
|
2024-11-20 10:13:10 +01:00
|
|
|
<div
|
|
|
|
class="flex flex-col gap-2 max-w-2xl mx-auto w-full select-none"
|
|
|
|
:class="disableEdit ? ' pointer-events-none opacity-60 bg-gray-100/50' : ''"
|
|
|
|
>
|
2024-08-27 11:46:24 +02:00
|
|
|
<div class="flex flex-row gap-2 h-fit w-full border border-gray-300 rounded-md p-2">
|
|
|
|
<input type="checkbox" name="admin" id="admin" class="cursor-pointer" :checked="isAdmin" @change="toggleAdmin" />
|
|
|
|
<label for="admin" class="cursor-pointer">Administratorrecht</label>
|
|
|
|
</div>
|
|
|
|
<div
|
|
|
|
v-for="section in sections"
|
|
|
|
:key="section"
|
|
|
|
class="flex flex-col gap-2 h-fit w-full border border-primary rounded-md"
|
2024-11-20 10:13:10 +01:00
|
|
|
:class="isAdmin && !disableEdit ? ' pointer-events-none opacity-60 bg-gray-100' : ''"
|
2024-08-27 11:46:24 +02:00
|
|
|
>
|
|
|
|
<div class="bg-primary p-2 text-white flex flex-row justify-between items-center">
|
|
|
|
<p>Abschnitt: {{ section }}</p>
|
|
|
|
<div class="flex flex-row border border-white rounded-md overflow-hidden">
|
|
|
|
<EyeIcon
|
|
|
|
class="w-5 h-5 p-1 box-content cursor-pointer"
|
|
|
|
:class="_can(permissionUpdate, 'read', section) ? 'bg-success' : ''"
|
|
|
|
@click="togglePermission('read', section)"
|
|
|
|
/>
|
|
|
|
<PlusIcon
|
|
|
|
class="w-5 h-5 p-1 box-content cursor-pointer"
|
|
|
|
:class="_can(permissionUpdate, 'create', section) ? 'bg-success' : ''"
|
|
|
|
@click="togglePermission('create', section)"
|
|
|
|
/>
|
|
|
|
<PencilIcon
|
|
|
|
class="w-5 h-5 p-1 box-content cursor-pointer"
|
|
|
|
:class="_can(permissionUpdate, 'update', section) ? 'bg-success' : ''"
|
|
|
|
@click="togglePermission('update', section)"
|
|
|
|
/>
|
|
|
|
<TrashIcon
|
|
|
|
class="w-5 h-5 p-1 box-content cursor-pointer"
|
|
|
|
:class="_can(permissionUpdate, 'delete', section) ? 'bg-success' : ''"
|
|
|
|
@click="togglePermission('delete', section)"
|
|
|
|
/>
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
<div
|
|
|
|
v-for="modul in permissionStructure[section]"
|
|
|
|
:key="modul"
|
|
|
|
class="p-1 px-2 flex flex-row justify-between items-center"
|
|
|
|
>
|
|
|
|
<p>Modul: {{ modul }}</p>
|
|
|
|
<div class="flex flex-row border border-gray-300 rounded-md overflow-hidden">
|
|
|
|
<EyeIcon
|
|
|
|
class="w-5 h-5 p-1 box-content cursor-pointer"
|
|
|
|
:class="_can(permissionUpdate, 'read', section, modul) ? 'bg-success' : ''"
|
|
|
|
@click="togglePermission('read', section, modul)"
|
|
|
|
/>
|
|
|
|
<PlusIcon
|
|
|
|
class="w-5 h-5 p-1 box-content cursor-pointer"
|
|
|
|
:class="_can(permissionUpdate, 'create', section, modul) ? 'bg-success' : ''"
|
|
|
|
@click="togglePermission('create', section, modul)"
|
|
|
|
/>
|
|
|
|
<PencilIcon
|
|
|
|
class="w-5 h-5 p-1 box-content cursor-pointer"
|
|
|
|
:class="_can(permissionUpdate, 'update', section, modul) ? 'bg-success' : ''"
|
|
|
|
@click="togglePermission('update', section, modul)"
|
|
|
|
/>
|
|
|
|
<TrashIcon
|
|
|
|
class="w-5 h-5 p-1 box-content cursor-pointer"
|
|
|
|
:class="_can(permissionUpdate, 'delete', section, modul) ? 'bg-success' : ''"
|
|
|
|
@click="togglePermission('delete', section, modul)"
|
|
|
|
/>
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
</div>
|
2024-11-20 10:13:10 +01:00
|
|
|
<div v-if="!disableEdit" class="flex flex-row gap-2 self-end pt-4">
|
2024-09-15 13:52:54 +02:00
|
|
|
<button primary-outline class="!w-fit" @click="reset" :disabled="canSaveOrReset">verwerfen</button>
|
|
|
|
<button primary class="!w-fit" @click="submit" :disabled="status == 'loading' || canSaveOrReset">
|
|
|
|
speichern
|
|
|
|
</button>
|
2024-09-02 15:57:03 +02:00
|
|
|
<Spinner v-if="status == 'loading'" class="my-auto" />
|
|
|
|
<SuccessCheckmark v-else-if="status?.status == 'success'" />
|
|
|
|
<FailureXMark v-else-if="status?.status == 'failed'" />
|
2024-08-27 11:46:24 +02:00
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
</template>
|
|
|
|
|
|
|
|
<script setup lang="ts">
|
|
|
|
import { defineComponent } from "vue";
|
|
|
|
import type { PropType } from "vue";
|
|
|
|
import type {
|
|
|
|
PermissionModule,
|
|
|
|
PermissionObject,
|
|
|
|
PermissionSection,
|
|
|
|
PermissionType,
|
|
|
|
SectionsAndModulesObject,
|
|
|
|
} from "@/types/permissionTypes";
|
|
|
|
import { sectionsAndModules, permissionSections, permissionTypes } from "@/types/permissionTypes";
|
|
|
|
import { mapState, mapActions } from "pinia";
|
2024-09-02 15:57:03 +02:00
|
|
|
import { EyeIcon, PencilIcon, PlusIcon, TrashIcon } from "@heroicons/vue/24/outline";
|
2024-09-01 14:54:49 +02:00
|
|
|
import { useAbilityStore } from "@/stores/ability";
|
2024-09-15 13:52:54 +02:00
|
|
|
import cloneDeep from "lodash.clonedeep";
|
2024-11-27 17:06:39 +01:00
|
|
|
import isEqual from "lodash.isequal";
|
2024-09-02 15:57:03 +02:00
|
|
|
import Spinner from "@/components/Spinner.vue";
|
|
|
|
import SuccessCheckmark from "@/components/SuccessCheckmark.vue";
|
|
|
|
import FailureXMark from "@/components/FailureXMark.vue";
|
2024-08-27 11:46:24 +02:00
|
|
|
</script>
|
|
|
|
|
|
|
|
<script lang="ts">
|
|
|
|
export default defineComponent({
|
|
|
|
props: {
|
|
|
|
permissions: {
|
|
|
|
type: Object as PropType<PermissionObject>,
|
|
|
|
default: {},
|
|
|
|
},
|
2024-09-02 15:57:03 +02:00
|
|
|
status: {
|
2024-09-18 09:58:29 +02:00
|
|
|
type: [Object, String, null] as PropType<null | "loading" | { status: "success" | "failed"; message?: string }>,
|
2024-09-02 15:57:03 +02:00
|
|
|
default: null,
|
|
|
|
},
|
2024-11-20 10:13:10 +01:00
|
|
|
disableEdit: {
|
|
|
|
type: Boolean,
|
|
|
|
default: false,
|
|
|
|
},
|
2024-08-27 11:46:24 +02:00
|
|
|
},
|
2024-09-18 09:58:29 +02:00
|
|
|
watch: {
|
|
|
|
permissions() {
|
|
|
|
this.permissionUpdate = cloneDeep(this.permissions);
|
|
|
|
},
|
|
|
|
},
|
2024-09-15 13:52:54 +02:00
|
|
|
emits: ["savePermissions"],
|
2024-08-27 11:46:24 +02:00
|
|
|
data() {
|
|
|
|
return {
|
|
|
|
isAdmin: false,
|
|
|
|
sections: [] as Array<PermissionSection>,
|
|
|
|
permissionStructure: {} as SectionsAndModulesObject,
|
|
|
|
permissionUpdate: {} as PermissionObject,
|
|
|
|
};
|
|
|
|
},
|
|
|
|
computed: {
|
|
|
|
...mapState(useAbilityStore, ["_can"]),
|
2024-09-15 13:52:54 +02:00
|
|
|
canSaveOrReset(): boolean {
|
|
|
|
return isEqual(this.permissions, this.permissionUpdate);
|
|
|
|
},
|
2024-08-27 11:46:24 +02:00
|
|
|
},
|
|
|
|
mounted() {
|
|
|
|
this.sections = permissionSections;
|
|
|
|
this.permissionStructure = sectionsAndModules;
|
2024-09-15 13:52:54 +02:00
|
|
|
this.permissionUpdate = cloneDeep(this.permissions);
|
2024-08-27 11:46:24 +02:00
|
|
|
|
|
|
|
this.isAdmin = this.permissions.admin ?? false;
|
|
|
|
},
|
|
|
|
methods: {
|
|
|
|
toggleAdmin(e: Event) {
|
|
|
|
const target = e.target as HTMLInputElement;
|
|
|
|
this.isAdmin = target.checked ?? false;
|
|
|
|
this.permissionUpdate.admin = this.isAdmin;
|
2024-09-18 09:58:29 +02:00
|
|
|
if (!this.isAdmin) {
|
|
|
|
delete this.permissionUpdate.admin;
|
|
|
|
}
|
2024-08-27 11:46:24 +02:00
|
|
|
},
|
|
|
|
togglePermission(type: PermissionType, section: PermissionSection, modul?: PermissionModule) {
|
|
|
|
let permissions = [] as Array<PermissionType> | "*";
|
|
|
|
if (!modul) {
|
|
|
|
permissions = this.permissionUpdate[section]?.all ?? [];
|
|
|
|
} else {
|
|
|
|
permissions = this.permissionUpdate[section]?.[modul] ?? [];
|
|
|
|
}
|
|
|
|
|
|
|
|
if (permissions == "*") {
|
|
|
|
permissions = permissionTypes;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (permissions.includes(type)) {
|
|
|
|
let add = permissions.slice(-1)[0] == type ? 0 : 1;
|
|
|
|
let whatToRemove = permissionTypes.slice(permissionTypes.indexOf(type) + add);
|
|
|
|
permissions = permissions.filter((permission) => !whatToRemove.includes(permission));
|
|
|
|
} else {
|
|
|
|
let whatToAdd = permissionTypes.slice(0, permissionTypes.indexOf(type) + 1);
|
|
|
|
permissions = whatToAdd;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!modul) {
|
|
|
|
if (!this.permissionUpdate[section]) {
|
|
|
|
this.permissionUpdate[section] = {};
|
|
|
|
}
|
2025-01-29 08:53:42 +01:00
|
|
|
this.permissionUpdate[section]!.all = permissions;
|
2024-08-27 11:46:24 +02:00
|
|
|
} else {
|
|
|
|
if (!this.permissionUpdate[section]) {
|
|
|
|
this.permissionUpdate[section] = {};
|
|
|
|
}
|
2025-01-29 08:53:42 +01:00
|
|
|
this.permissionUpdate[section]![modul] = permissions;
|
2024-08-27 11:46:24 +02:00
|
|
|
}
|
|
|
|
},
|
2024-09-10 17:11:51 +02:00
|
|
|
reset() {
|
2024-09-15 13:52:54 +02:00
|
|
|
this.permissionUpdate = cloneDeep(this.permissions);
|
2024-09-10 17:11:51 +02:00
|
|
|
this.isAdmin = this.permissions.admin ?? false;
|
|
|
|
},
|
|
|
|
submit() {
|
|
|
|
this.$emit("savePermissions", this.permissionUpdate);
|
|
|
|
},
|
2024-08-27 11:46:24 +02:00
|
|
|
},
|
|
|
|
});
|
|
|
|
</script>
|