mirror of https://github.com/halo-dev/halo-admin
feat: add granting roles for user support
Signed-off-by: Ryan Wang <i@ryanc.cc>pull/588/head
parent
dc1da8fc91
commit
9546abf1e2
|
@ -1,10 +1,19 @@
|
|||
<script lang="ts" setup>
|
||||
import { IconUserSettings, VTag } from "@halo-dev/components";
|
||||
import { inject } from "vue";
|
||||
import type { Ref } from "vue";
|
||||
import { computed, inject } from "vue";
|
||||
import { useRouter } from "vue-router";
|
||||
import type { User } from "@/types/extension";
|
||||
|
||||
const user = inject<User>("user");
|
||||
const user = inject<Ref<User>>("user");
|
||||
|
||||
const roles = computed(() => {
|
||||
return JSON.parse(
|
||||
user?.value?.metadata?.annotations?.[
|
||||
"rbac.authorization.halo.run/role-names"
|
||||
] || "[]"
|
||||
);
|
||||
});
|
||||
|
||||
const router = useRouter();
|
||||
</script>
|
||||
|
@ -40,11 +49,15 @@ const router = useRouter();
|
|||
>
|
||||
<dt class="text-sm font-medium text-gray-900">角色</dt>
|
||||
<dd class="mt-1 text-sm text-gray-900 sm:col-span-3 sm:mt-0">
|
||||
<VTag @click="router.push({ name: 'RoleDetail', params: { id: 1 } })">
|
||||
<VTag
|
||||
v-for="(role, index) in roles"
|
||||
:key="index"
|
||||
@click="router.push({ name: 'RoleDetail', params: { id: 1 } })"
|
||||
>
|
||||
<template #leftIcon>
|
||||
<IconUserSettings />
|
||||
</template>
|
||||
{{ user?.metadata?.name }}
|
||||
{{ role }}
|
||||
</VTag>
|
||||
</dd>
|
||||
</div>
|
||||
|
|
|
@ -45,6 +45,13 @@ const handleOpenCreateModal = (user: User) => {
|
|||
creationModal.value = true;
|
||||
};
|
||||
|
||||
const getRoles = (user: User) => {
|
||||
return JSON.parse(
|
||||
user.metadata.annotations?.["rbac.authorization.halo.run/role-names"] ||
|
||||
"[]"
|
||||
);
|
||||
};
|
||||
|
||||
onMounted(() => {
|
||||
handleFetchUsers();
|
||||
});
|
||||
|
@ -254,9 +261,13 @@ onMounted(() => {
|
|||
<div
|
||||
class="inline-flex flex-col flex-col-reverse items-end gap-4 sm:flex-row sm:items-center sm:gap-6"
|
||||
>
|
||||
<div class="hidden items-center sm:flex">
|
||||
<div
|
||||
v-for="(role, index) in getRoles(user)"
|
||||
:key="index"
|
||||
class="hidden items-center sm:flex"
|
||||
>
|
||||
<VTag>
|
||||
{{ user.metadata.name }}
|
||||
{{ role }}
|
||||
</VTag>
|
||||
</div>
|
||||
<time class="text-sm text-gray-500" datetime="2020-01-07">
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
<script lang="ts" name="UserCreationModal" setup>
|
||||
import type { PropType } from "vue";
|
||||
import { computed, ref, watch } from "vue";
|
||||
import { computed, onMounted, ref, watch } from "vue";
|
||||
import { axiosInstance } from "@halo-dev/admin-shared";
|
||||
import { IconSave, VButton, VModal } from "@halo-dev/components";
|
||||
import type { User } from "@/types/extension";
|
||||
import type { Role, User } from "@/types/extension";
|
||||
import { v4 as uuid } from "uuid";
|
||||
|
||||
const props = defineProps({
|
||||
|
@ -24,6 +24,7 @@ interface creationFormState {
|
|||
saving: boolean;
|
||||
}
|
||||
|
||||
const roles = ref<Role[]>([]);
|
||||
const creationForm = ref<creationFormState>({
|
||||
user: {
|
||||
spec: {
|
||||
|
@ -44,6 +45,7 @@ const creationForm = ref<creationFormState>({
|
|||
},
|
||||
saving: false,
|
||||
});
|
||||
const selectedRole = ref("");
|
||||
|
||||
const isUpdateMode = computed(() => {
|
||||
return !!creationForm.value.user.metadata.creationTimestamp;
|
||||
|
@ -53,12 +55,28 @@ const creationModalTitle = computed(() => {
|
|||
return isUpdateMode.value ? "编辑用户" : "新增用户";
|
||||
});
|
||||
|
||||
const basicRoles = computed(() => {
|
||||
return roles.value.filter(
|
||||
(role) =>
|
||||
role.metadata?.labels?.["plugin.halo.run/role-template"] !== "true"
|
||||
);
|
||||
});
|
||||
|
||||
watch(props, (newVal) => {
|
||||
if (newVal.visible && props.user) {
|
||||
creationForm.value.user = props.user;
|
||||
}
|
||||
});
|
||||
|
||||
const handleFetchRoles = async () => {
|
||||
try {
|
||||
const { data } = await axiosInstance.get("/api/v1alpha1/roles");
|
||||
roles.value = data;
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
}
|
||||
};
|
||||
|
||||
const handleVisibleChange = (visible: boolean) => {
|
||||
emit("update:visible", visible);
|
||||
if (!visible) {
|
||||
|
@ -69,14 +87,29 @@ const handleVisibleChange = (visible: boolean) => {
|
|||
const handleCreateUser = async () => {
|
||||
try {
|
||||
creationForm.value.saving = true;
|
||||
let user: User;
|
||||
|
||||
if (isUpdateMode.value) {
|
||||
await axiosInstance.put(
|
||||
const response = await axiosInstance.put(
|
||||
`/api/v1alpha1/users/${creationForm.value.user.metadata.name}`,
|
||||
creationForm.value.user
|
||||
);
|
||||
user = response.data;
|
||||
} else {
|
||||
await axiosInstance.post("/api/v1alpha1/users", creationForm.value.user);
|
||||
const response = await axiosInstance.post(
|
||||
"/api/v1alpha1/users",
|
||||
creationForm.value.user
|
||||
);
|
||||
user = response.data;
|
||||
}
|
||||
|
||||
if (selectedRole.value) {
|
||||
await axiosInstance.post(
|
||||
`/apis/api.halo.run/v1alpha1/users/${user.metadata.name}/permissions`,
|
||||
{
|
||||
roles: [selectedRole.value],
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
handleVisibleChange(false);
|
||||
|
@ -86,6 +119,8 @@ const handleCreateUser = async () => {
|
|||
creationForm.value.saving = false;
|
||||
}
|
||||
};
|
||||
|
||||
onMounted(handleFetchRoles);
|
||||
</script>
|
||||
<template>
|
||||
<VModal
|
||||
|
@ -113,6 +148,20 @@ const handleCreateUser = async () => {
|
|||
type="email"
|
||||
validation="required"
|
||||
></FormKit>
|
||||
<FormKit
|
||||
v-model="selectedRole"
|
||||
:options="
|
||||
basicRoles.map((role:Role) => {
|
||||
return {
|
||||
label: role.metadata?.annotations?.['plugin.halo.run/display-name'] || role.metadata.name,
|
||||
value: role.metadata?.name,
|
||||
};
|
||||
})
|
||||
"
|
||||
label="角色"
|
||||
type="select"
|
||||
validation="required"
|
||||
></FormKit>
|
||||
<FormKit
|
||||
v-model="creationForm.user.spec.phone"
|
||||
label="手机号"
|
||||
|
|
Loading…
Reference in New Issue