Passport/web/src/components/admin/UserAssignPermsPanel.vue

165 lines
4.9 KiB
Vue

<template>
<v-dialog class="max-w-[720px]" :model-value="data != null" @update:model-value="(val) => !val && emits('close')">
<template v-slot:default="{ isActive }">
<v-card title="Assign permissions" :subtitle="`To user @${props.data?.name}`" :loading="submitting">
<v-card-text>
<v-sheet elevation="2" rounded="lg">
<v-table density="comfortable">
<thead>
<tr>
<th class="text-left">
Key
</th>
<th class="text-left">
Value
</th>
</tr>
</thead>
<tbody>
<tr
v-for="[key, val] in Object.entries(perms)"
:key="key"
>
<td class="w-1/2">
<div>
<p>{{ key }}</p>
<div class="flex mx-[-8px]">
<v-btn color="error" text="Delete" variant="plain" size="x-small"
@click="() => deleteNode(key)" />
<v-btn class="ms-[-8px]" color="info" text="Change" variant="plain" size="x-small"
@click="() => changeNodeType(key)" />
</div>
</div>
</td>
<td class="w-1/2">
<div class="w-full flex items-center">
<v-checkbox v-if="typeof val === 'boolean'" class="my-1" density="comfortable"
:hide-details="true"
v-model="perms[key]" />
<v-number-input v-else-if="typeof val === 'number'"
controlVariant="default"
:reverse="false"
:hideInput="false"
:inset="false"
class="font-mono my-2"
density="compact" :hide-details="true"
v-model="perms[key]" />
<v-text-field v-else class="font-mono my-2" density="compact" :hide-details="true"
v-model="perms[key]" />
</div>
</td>
</tr>
<tr>
<td>
<v-text-field class="my-3.5" label="Key" density="compact" variant="solo-filled"
v-model="pendingNodeKey"
:hide-details="true" />
</td>
<td>
<div class="w-full flex justify-center">
<v-btn prepend-icon="mdi-plus-circle" text="Add one" block rounded="md" @click="addNode" />
</div>
</td>
</tr>
</tbody>
</v-table>
</v-sheet>
</v-card-text>
<v-card-actions>
<v-spacer></v-spacer>
<v-btn
:disabled="submitting"
text="Cancel"
color="grey"
@click="isActive.value = false"
></v-btn>
<v-btn
:disabled="submitting"
text="Apply Changes"
@click="saveNode"
></v-btn>
</v-card-actions>
</v-card>
</template>
</v-dialog>
</template>
<script setup lang="ts">
import { ref, watch } from "vue"
import { request } from "@/scripts/request"
import { getAtk } from "@/stores/userinfo"
const perms = ref<any>({})
const pendingNodeKey = ref("")
const props = defineProps<{ data: any }>()
const emits = defineEmits(["close", "success", "error"])
watch(props, (v) => {
if (v.data != null) {
perms.value = v.data["perm_nodes"]
}
}, { immediate: true, deep: true })
function addNode() {
if (pendingNodeKey.value) {
perms.value[pendingNodeKey.value] = false
pendingNodeKey.value = ""
}
}
function deleteNode(key: string) {
delete perms.value[key]
}
function changeNodeType(key: string) {
const typelist = [
"boolean",
"number",
"string",
]
const idx = typelist.indexOf(typeof perms.value[key])
if (idx == -1 || idx == typelist.length - 1) {
perms.value[key] = false
return
}
switch (typelist[idx + 1]) {
case "boolean":
perms.value[key] = false
break
case "number":
perms.value[key] = 0
break
default:
perms.value[key] = ""
break
}
}
const submitting = ref(false)
async function saveNode() {
submitting.value = true
const res = await request(`/api/admin/users/${props.data.id}/permissions`, {
method: 'PUT',
headers: {
"Content-Type": "application/json",
"Authorization": `Bearer ${getAtk()}`,
},
body: JSON.stringify({
'perm_nodes': perms.value,
}),
})
if (res.status !== 200) {
emits("error", await res.text())
} else {
emits("success")
emits("close")
}
submitting.value = false
}
</script>