permission additional content

This commit is contained in:
Julian Krauser 2025-03-28 11:25:06 +01:00
parent 8a28dcd535
commit b6fc8de978
4 changed files with 57 additions and 8 deletions

View file

@ -2,12 +2,7 @@
<div class="grow flex flex-col gap-2 overflow-hidden"> <div class="grow flex flex-col gap-2 overflow-hidden">
<div v-if="useSearch" class="relative self-end flex flex-row items-center gap-2"> <div v-if="useSearch" class="relative self-end flex flex-row items-center gap-2">
<Spinner v-if="deferingSearch" /> <Spinner v-if="deferingSearch" />
<input <input type="text" class="!max-w-64 !w-64" placeholder="Suche" v-model="searchString" />
type="text"
class="!max-w-64 !w-64 rounded-md shadow-sm relative block px-3 py-2 pr-5 border border-gray-300 placeholder-gray-500 text-gray-900 rounded-b-md focus:outline-none focus:ring-indigo-500 focus:border-indigo-500 focus:z-10 sm:text-sm"
placeholder="Suche"
v-model="searchString"
/>
<XMarkIcon <XMarkIcon
class="absolute h-4 stroke-2 right-2 top-1/2 -translate-y-1/2 cursor-pointer z-10" class="absolute h-4 stroke-2 right-2 top-1/2 -translate-y-1/2 cursor-pointer z-10"
@click="searchString = ''" @click="searchString = ''"

View file

@ -68,6 +68,31 @@
</div> </div>
</div> </div>
</div> </div>
<div
v-if="sectionsAndModules.additional"
class="flex flex-col gap-2 h-fit w-full border border-primary rounded-md"
:class="isAdmin && !disableEdit ? ' pointer-events-none opacity-60 bg-gray-100' : ''"
>
<div class="bg-primary p-2 text-white flex flex-row justify-between items-center">
<p>weitere Berechtigungen</p>
</div>
<div
v-for="add in permissionStructure.additional"
:key="add.key"
class="p-1 px-2 flex flex-row justify-between items-center"
>
<p>{{ add.name }}</p>
<div class="self-end flex flex-row items-center gap-2">
<input
:type="add.type"
class="max-w-64 sm:w-64"
:value="_canValue(permissionUpdate, add.key, add.emptyIfAdmin)"
@input="(e) => changeValue(add.key, (e.target as HTMLInputElement).value)"
/>
<XMarkIcon class="h-4 stroke-2 cursor-pointer" @click="clearValue(add.key)" />
</div>
</div>
</div>
<div v-if="!disableEdit" class="flex flex-row gap-2 self-end pt-4"> <div v-if="!disableEdit" class="flex flex-row gap-2 self-end pt-4">
<button primary-outline class="!w-fit" @click="reset" :disabled="canSaveOrReset">verwerfen</button> <button primary-outline class="!w-fit" @click="reset" :disabled="canSaveOrReset">verwerfen</button>
<button primary class="!w-fit" @click="submit" :disabled="status == 'loading' || canSaveOrReset"> <button primary class="!w-fit" @click="submit" :disabled="status == 'loading' || canSaveOrReset">
@ -92,7 +117,7 @@ import type {
} from "@/types/permissionTypes"; } from "@/types/permissionTypes";
import { sectionsAndModules, permissionSections, permissionTypes } from "@/types/permissionTypes"; import { sectionsAndModules, permissionSections, permissionTypes } from "@/types/permissionTypes";
import { mapState, mapActions } from "pinia"; import { mapState, mapActions } from "pinia";
import { EyeIcon, PencilIcon, PlusIcon, TrashIcon } from "@heroicons/vue/24/outline"; import { EyeIcon, PencilIcon, PlusIcon, TrashIcon, XMarkIcon } from "@heroicons/vue/24/outline";
import { useAbilityStore } from "@/stores/ability"; import { useAbilityStore } from "@/stores/ability";
import cloneDeep from "lodash.clonedeep"; import cloneDeep from "lodash.clonedeep";
import isEqual from "lodash.isequal"; import isEqual from "lodash.isequal";
@ -132,7 +157,7 @@ export default defineComponent({
}; };
}, },
computed: { computed: {
...mapState(useAbilityStore, ["_can"]), ...mapState(useAbilityStore, ["_can", "_canValue"]),
canSaveOrReset(): boolean { canSaveOrReset(): boolean {
return isEqual(this.permissions, this.permissionUpdate); return isEqual(this.permissions, this.permissionUpdate);
}, },
@ -186,6 +211,15 @@ export default defineComponent({
this.permissionUpdate[section]![modul] = permissions; this.permissionUpdate[section]![modul] = permissions;
} }
}, },
changeValue(key: string, value: string) {
if (this.permissionUpdate.additional == undefined) {
this.permissionUpdate.additional = {};
}
this.permissionUpdate.additional![key] = value;
},
clearValue(key: string) {
delete this.permissionUpdate?.additional?.[key];
},
reset() { reset() {
this.permissionUpdate = cloneDeep(this.permissions); this.permissionUpdate = cloneDeep(this.permissions);
this.isAdmin = this.permissions.admin ?? false; this.isAdmin = this.permissions.admin ?? false;

View file

@ -71,6 +71,12 @@ export const useAbilityStore = defineStore("ability", {
return true; return true;
return false; return false;
}, },
_canValue:
() =>
(permissions: PermissionObject, key: string, emptyIfAdmin: boolean = false): string => {
if (emptyIfAdmin && permissions.admin) return "";
return permissions?.additional?.[key] ?? "";
},
}, },
actions: { actions: {
setAbility(permissions: PermissionObject, isOwner: boolean) { setAbility(permissions: PermissionObject, isOwner: boolean) {

View file

@ -9,6 +9,7 @@ export type PermissionString =
| `${PermissionSection}.${PermissionModule}.*` // für alle Berechtigungen in einem Modul | `${PermissionSection}.${PermissionModule}.*` // für alle Berechtigungen in einem Modul
| `${PermissionSection}.${PermissionType}` // für spezifische Berechtigungen in einem Abschnitt | `${PermissionSection}.${PermissionType}` // für spezifische Berechtigungen in einem Abschnitt
| `${PermissionSection}.*` // für alle Berechtigungen in einem Abschnitt | `${PermissionSection}.*` // für alle Berechtigungen in einem Abschnitt
| `additional.${string}.${string}` // additional
| "*"; // für Admin | "*"; // für Admin
export type PermissionObject = { export type PermissionObject = {
@ -17,10 +18,19 @@ export type PermissionObject = {
} & { all?: Array<PermissionType> | "*" }; } & { all?: Array<PermissionType> | "*" };
} & { } & {
admin?: boolean; admin?: boolean;
} & {
additional?: { [key: string]: string };
}; };
export type SectionsAndModulesObject = { export type SectionsAndModulesObject = {
[section in PermissionSection]: Array<PermissionModule>; [section in PermissionSection]: Array<PermissionModule>;
} & {
additional?: Array<{
key: string;
name: string;
type: "number" | "string";
emptyIfAdmin: boolean;
}>;
}; };
export const permissionSections: Array<PermissionSection> = ["operation", "configuration", "management"]; export const permissionSections: Array<PermissionSection> = ["operation", "configuration", "management"];
@ -39,4 +49,8 @@ export const sectionsAndModules: SectionsAndModulesObject = {
operation: ["mission"], operation: ["mission"],
configuration: ["force", "vehicle", "equipment"], configuration: ["force", "vehicle", "equipment"],
management: ["user", "role", "backup", "import"], management: ["user", "role", "backup", "import"],
additional: [
{ key: "maxVisInDays", name: "max Sichtbarkeit in Tagen", type: "number", emptyIfAdmin: true },
{ key: "maxVisByMissions", name: "max Sichtbarkeit an Einsätzen", type: "number", emptyIfAdmin: true },
],
}; };