Skip to content

Commit

Permalink
feat: add multi-role assignment support for users
Browse files Browse the repository at this point in the history
Signed-off-by: Ryan Wang <[email protected]>
  • Loading branch information
ruibaby committed Nov 15, 2024
1 parent 06f3c28 commit 87546da
Show file tree
Hide file tree
Showing 5 changed files with 71 additions and 61 deletions.
13 changes: 6 additions & 7 deletions ui/console-src/modules/system/users/UserList.vue
Original file line number Diff line number Diff line change
Expand Up @@ -469,19 +469,18 @@ function onGrantPermissionModalClose() {
<template #end>
<VEntityField>
<template #description>
<div
v-for="(role, roleIndex) in user.roles"
:key="roleIndex"
class="flex items-center"
>
<VTag>
<VSpace>
<VTag
v-for="role in user.roles"
:key="role.metadata.name"
>
{{
role.metadata.annotations?.[
rbacAnnotations.DISPLAY_NAME
] || role.metadata.name
}}
</VTag>
</div>
</VSpace>
</template>
</VEntityField>
<VEntityField v-if="user.user.metadata.deletionTimestamp">
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,14 @@
<script lang="ts" setup>
import SubmitButton from "@/components/button/SubmitButton.vue";
import { rbacAnnotations } from "@/constants/annotations";
import type { User } from "@halo-dev/api-client";
import { consoleApiClient } from "@halo-dev/api-client";
import { VButton, VModal, VSpace } from "@halo-dev/components";
import { ref } from "vue";
import { Toast, VButton, VModal, VSpace } from "@halo-dev/components";
import { useMutation } from "@tanstack/vue-query";
import { computed, ref } from "vue";
import { useI18n } from "vue-i18n";
const { t } = useI18n();
const props = withDefaults(
defineProps<{
Expand All @@ -19,25 +24,35 @@ const emit = defineEmits<{
}>();
const modal = ref<InstanceType<typeof VModal> | null>(null);
const selectedRole = ref("");
const isSubmitting = ref(false);
const handleGrantPermission = async () => {
try {
isSubmitting.value = true;
await consoleApiClient.user.grantPermission({
const currentRoles = computed(() => {
if (!props.user) {
return [];
}
return JSON.parse(
props.user.metadata.annotations?.[rbacAnnotations.ROLE_NAMES] || "[]"
);
});
const { mutate, isLoading } = useMutation({
mutationKey: ["core:user:grant-permissions"],
mutationFn: async ({ roles }: { roles: string[] }) => {
return await consoleApiClient.user.grantPermission({
name: props.user?.metadata.name as string,
grantRequest: {
roles: [selectedRole.value],
roles: roles,
},
});
},
onSuccess() {
Toast.success(t("core.common.toast.operation_success"));
modal.value?.close();
} catch (error) {
console.error("Failed to grant permission to user", error);
} finally {
isSubmitting.value = false;
}
};
},
});
function onSubmit(data: { roles: string[] }) {
mutate({ roles: data.roles });
}
</script>

<template>
Expand All @@ -52,18 +67,23 @@ const handleGrantPermission = async () => {
name="grant-permission-form"
:config="{ validationVisibility: 'submit' }"
type="form"
@submit="handleGrantPermission"
@submit="onSubmit"
>
<FormKit
v-model="selectedRole"
multiple
name="roles"
:value="currentRoles"
:label="$t('core.user.grant_permission_modal.fields.role.label')"
type="roleSelect"
:placeholder="
$t('core.user.grant_permission_modal.fields.role.placeholder')
"
></FormKit>
</FormKit>
<template #footer>
<VSpace>
<SubmitButton
:loading="isSubmitting"
:loading="isLoading"
type="secondary"
:text="$t('core.common.buttons.submit')"
@submit="$formkit.submit('grant-permission-form')"
Expand Down
37 changes: 18 additions & 19 deletions ui/console-src/modules/system/users/tabs/Detail.vue
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@ import { formatDatetime } from "@/utils/date";
import type { DetailedUser } from "@halo-dev/api-client";
import {
IconInformation,
IconUserSettings,
VDescription,
VDescriptionItem,
VSpace,
VTag,
} from "@halo-dev/components";
import RiVerifiedBadgeLine from "~icons/ri/verified-badge-line";
Expand Down Expand Up @@ -55,24 +55,23 @@ withDefaults(defineProps<{ user?: DetailedUser }>(), {
:label="$t('core.user.detail.fields.roles')"
class="!px-2"
>
<VTag
v-for="(role, index) in user?.roles"
:key="index"
@click="
$router.push({
name: 'RoleDetail',
params: { name: role.metadata.name },
})
"
>
<template #leftIcon>
<IconUserSettings />
</template>
{{
role.metadata.annotations?.[rbacAnnotations.DISPLAY_NAME] ||
role.metadata.name
}}
</VTag>
<VSpace>
<VTag
v-for="role in user?.roles"
:key="role.metadata.name"
@click="
$router.push({
name: 'RoleDetail',
params: { name: role.metadata.name },
})
"
>
{{
role.metadata.annotations?.[rbacAnnotations.DISPLAY_NAME] ||
role.metadata.name
}}
</VTag>
</VSpace>
</VDescriptionItem>
<VDescriptionItem
:label="$t('core.user.detail.fields.bio')"
Expand Down
7 changes: 0 additions & 7 deletions ui/src/formkit/inputs/role-select.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import { rbacAnnotations } from "@/constants/annotations";
import { roleLabels } from "@/constants/labels";
import { i18n } from "@/locales";
import type { FormKitNode, FormKitTypeDefinition } from "@formkit/core";
import { coreApiClient } from "@halo-dev/api-client";
import { select } from "./select";
Expand All @@ -14,12 +13,6 @@ function optionsHandler(node: FormKitNode) {
});

const options = [
{
label: i18n.global.t(
"core.user.grant_permission_modal.fields.role.placeholder"
),
value: "",
},
...data.items.map((role) => {
return {
label:
Expand Down
19 changes: 9 additions & 10 deletions ui/uc-src/modules/profile/tabs/Detail.vue
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,11 @@ import type { DetailedUser, ListedAuthProvider } from "@halo-dev/api-client";
import { consoleApiClient } from "@halo-dev/api-client";
import {
Dialog,
IconUserSettings,
VAlert,
VButton,
VDescription,
VDescriptionItem,
VSpace,
VTag,
} from "@halo-dev/components";
import { useQuery } from "@tanstack/vue-query";
Expand Down Expand Up @@ -133,15 +133,14 @@ const emailVerifyModal = ref(false);
:label="$t('core.uc_profile.detail.fields.roles')"
class="!px-2"
>
<VTag v-for="role in user?.roles" :key="role.metadata.name">
<template #leftIcon>
<IconUserSettings />
</template>
{{
role.metadata.annotations?.[rbacAnnotations.DISPLAY_NAME] ||
role.metadata.name
}}
</VTag>
<VSpace>
<VTag v-for="role in user?.roles" :key="role.metadata.name">
{{
role.metadata.annotations?.[rbacAnnotations.DISPLAY_NAME] ||
role.metadata.name
}}
</VTag>
</VSpace>
</VDescriptionItem>
<VDescriptionItem
:label="$t('core.uc_profile.detail.fields.bio')"
Expand Down

0 comments on commit 87546da

Please sign in to comment.