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>
|
<script lang="ts" setup>
|
||||||
import { IconUserSettings, VTag } from "@halo-dev/components";
|
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 { useRouter } from "vue-router";
|
||||||
import type { User } from "@/types/extension";
|
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();
|
const router = useRouter();
|
||||||
</script>
|
</script>
|
||||||
|
@ -40,11 +49,15 @@ const router = useRouter();
|
||||||
>
|
>
|
||||||
<dt class="text-sm font-medium text-gray-900">角色</dt>
|
<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">
|
<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>
|
<template #leftIcon>
|
||||||
<IconUserSettings />
|
<IconUserSettings />
|
||||||
</template>
|
</template>
|
||||||
{{ user?.metadata?.name }}
|
{{ role }}
|
||||||
</VTag>
|
</VTag>
|
||||||
</dd>
|
</dd>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -45,6 +45,13 @@ const handleOpenCreateModal = (user: User) => {
|
||||||
creationModal.value = true;
|
creationModal.value = true;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const getRoles = (user: User) => {
|
||||||
|
return JSON.parse(
|
||||||
|
user.metadata.annotations?.["rbac.authorization.halo.run/role-names"] ||
|
||||||
|
"[]"
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
handleFetchUsers();
|
handleFetchUsers();
|
||||||
});
|
});
|
||||||
|
@ -254,9 +261,13 @@ onMounted(() => {
|
||||||
<div
|
<div
|
||||||
class="inline-flex flex-col flex-col-reverse items-end gap-4 sm:flex-row sm:items-center sm:gap-6"
|
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>
|
<VTag>
|
||||||
{{ user.metadata.name }}
|
{{ role }}
|
||||||
</VTag>
|
</VTag>
|
||||||
</div>
|
</div>
|
||||||
<time class="text-sm text-gray-500" datetime="2020-01-07">
|
<time class="text-sm text-gray-500" datetime="2020-01-07">
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
<script lang="ts" name="UserCreationModal" setup>
|
<script lang="ts" name="UserCreationModal" setup>
|
||||||
import type { PropType } from "vue";
|
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 { axiosInstance } from "@halo-dev/admin-shared";
|
||||||
import { IconSave, VButton, VModal } from "@halo-dev/components";
|
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";
|
import { v4 as uuid } from "uuid";
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
|
@ -24,6 +24,7 @@ interface creationFormState {
|
||||||
saving: boolean;
|
saving: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const roles = ref<Role[]>([]);
|
||||||
const creationForm = ref<creationFormState>({
|
const creationForm = ref<creationFormState>({
|
||||||
user: {
|
user: {
|
||||||
spec: {
|
spec: {
|
||||||
|
@ -44,6 +45,7 @@ const creationForm = ref<creationFormState>({
|
||||||
},
|
},
|
||||||
saving: false,
|
saving: false,
|
||||||
});
|
});
|
||||||
|
const selectedRole = ref("");
|
||||||
|
|
||||||
const isUpdateMode = computed(() => {
|
const isUpdateMode = computed(() => {
|
||||||
return !!creationForm.value.user.metadata.creationTimestamp;
|
return !!creationForm.value.user.metadata.creationTimestamp;
|
||||||
|
@ -53,12 +55,28 @@ const creationModalTitle = computed(() => {
|
||||||
return isUpdateMode.value ? "编辑用户" : "新增用户";
|
return isUpdateMode.value ? "编辑用户" : "新增用户";
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const basicRoles = computed(() => {
|
||||||
|
return roles.value.filter(
|
||||||
|
(role) =>
|
||||||
|
role.metadata?.labels?.["plugin.halo.run/role-template"] !== "true"
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
watch(props, (newVal) => {
|
watch(props, (newVal) => {
|
||||||
if (newVal.visible && props.user) {
|
if (newVal.visible && props.user) {
|
||||||
creationForm.value.user = 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) => {
|
const handleVisibleChange = (visible: boolean) => {
|
||||||
emit("update:visible", visible);
|
emit("update:visible", visible);
|
||||||
if (!visible) {
|
if (!visible) {
|
||||||
|
@ -69,14 +87,29 @@ const handleVisibleChange = (visible: boolean) => {
|
||||||
const handleCreateUser = async () => {
|
const handleCreateUser = async () => {
|
||||||
try {
|
try {
|
||||||
creationForm.value.saving = true;
|
creationForm.value.saving = true;
|
||||||
|
let user: User;
|
||||||
|
|
||||||
if (isUpdateMode.value) {
|
if (isUpdateMode.value) {
|
||||||
await axiosInstance.put(
|
const response = await axiosInstance.put(
|
||||||
`/api/v1alpha1/users/${creationForm.value.user.metadata.name}`,
|
`/api/v1alpha1/users/${creationForm.value.user.metadata.name}`,
|
||||||
creationForm.value.user
|
creationForm.value.user
|
||||||
);
|
);
|
||||||
|
user = response.data;
|
||||||
} else {
|
} 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);
|
handleVisibleChange(false);
|
||||||
|
@ -86,6 +119,8 @@ const handleCreateUser = async () => {
|
||||||
creationForm.value.saving = false;
|
creationForm.value.saving = false;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
onMounted(handleFetchRoles);
|
||||||
</script>
|
</script>
|
||||||
<template>
|
<template>
|
||||||
<VModal
|
<VModal
|
||||||
|
@ -113,6 +148,20 @@ const handleCreateUser = async () => {
|
||||||
type="email"
|
type="email"
|
||||||
validation="required"
|
validation="required"
|
||||||
></FormKit>
|
></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
|
<FormKit
|
||||||
v-model="creationForm.user.spec.phone"
|
v-model="creationForm.user.spec.phone"
|
||||||
label="手机号"
|
label="手机号"
|
||||||
|
|
Loading…
Reference in New Issue