mirror of https://github.com/halo-dev/halo
refactor: improve code base of role-related (#5984)
#### What type of PR is this? /area ui /kind improvement /milestone 2.16.x #### What this PR does / why we need it: 优化和角色相关的对话框显示逻辑,减少不必要的渲染开销和请求。 #### Does this PR introduce a user-facing change? ```release-note 优化和角色相关的对话框显示逻辑,减少不必要的渲染开销和请求。 ```pull/5987/head^2
parent
cb2138580c
commit
769b19c23c
|
@ -1,14 +1,14 @@
|
|||
<script lang="ts" setup>
|
||||
import {
|
||||
IconShieldUser,
|
||||
VAlert,
|
||||
VButton,
|
||||
VCard,
|
||||
VDescription,
|
||||
VDescriptionItem,
|
||||
VPageHeader,
|
||||
VTabbar,
|
||||
VTag,
|
||||
VAlert,
|
||||
VDescription,
|
||||
VDescriptionItem,
|
||||
} from "@halo-dev/components";
|
||||
import { useRoute } from "vue-router";
|
||||
import { computed, ref, watch } from "vue";
|
||||
|
@ -43,7 +43,7 @@ const { data: roleTemplates } = useQuery({
|
|||
const { roleTemplateGroups, handleRoleTemplateSelect, selectedRoleTemplates } =
|
||||
useRoleTemplateSelection(roleTemplates);
|
||||
|
||||
const { formState, saving, handleCreateOrUpdate } = useRoleForm();
|
||||
const { formState, isSubmitting, handleCreateOrUpdate } = useRoleForm();
|
||||
|
||||
const isSystemReserved = computed(() => {
|
||||
return (
|
||||
|
@ -285,7 +285,7 @@ const handleUpdateRole = async () => {
|
|||
</dl>
|
||||
<div v-permission="['system:roles:manage']" class="p-4">
|
||||
<VButton
|
||||
:loading="saving"
|
||||
:loading="isSubmitting"
|
||||
type="secondary"
|
||||
:disabled="isSystemReserved"
|
||||
@click="handleUpdateRole"
|
||||
|
|
|
@ -5,19 +5,19 @@ import type { Role, RoleList } from "@halo-dev/api-client";
|
|||
|
||||
// components
|
||||
import {
|
||||
Dialog,
|
||||
IconAddCircle,
|
||||
IconShieldUser,
|
||||
Dialog,
|
||||
Toast,
|
||||
VButton,
|
||||
VCard,
|
||||
VPageHeader,
|
||||
VTag,
|
||||
VStatusDot,
|
||||
VDropdownItem,
|
||||
VEntity,
|
||||
VEntityField,
|
||||
VLoading,
|
||||
Toast,
|
||||
VDropdownItem,
|
||||
VPageHeader,
|
||||
VStatusDot,
|
||||
VTag,
|
||||
} from "@halo-dev/components";
|
||||
import RoleEditingModal from "./components/RoleEditingModal.vue";
|
||||
|
||||
|
@ -130,6 +130,7 @@ const handleOpenEditingModal = (role: Role) => {
|
|||
|
||||
const onEditingModalClose = () => {
|
||||
selectedRole.value = undefined;
|
||||
editingModal.value = false;
|
||||
refetch();
|
||||
};
|
||||
|
||||
|
@ -198,7 +199,7 @@ const handleDelete = async (role: Role) => {
|
|||
</script>
|
||||
<template>
|
||||
<RoleEditingModal
|
||||
v-model:visible="editingModal"
|
||||
v-if="editingModal"
|
||||
:role="selectedRole"
|
||||
@close="onEditingModalClose"
|
||||
/>
|
||||
|
|
|
@ -1,12 +1,11 @@
|
|||
<script lang="ts" setup>
|
||||
import { VButton, VModal, VSpace } from "@halo-dev/components";
|
||||
import SubmitButton from "@/components/button/SubmitButton.vue";
|
||||
import { computed, watch } from "vue";
|
||||
import { onMounted, ref, watch } from "vue";
|
||||
import { rbacAnnotations } from "@/constants/annotations";
|
||||
import type { Role } from "@halo-dev/api-client";
|
||||
import { useRoleForm, useRoleTemplateSelection } from "@/composables/use-role";
|
||||
import { cloneDeep } from "lodash-es";
|
||||
import { reset } from "@formkit/core";
|
||||
import { setFocus } from "@/formkit/utils/focus";
|
||||
import { pluginLabels, roleLabels } from "@/constants/labels";
|
||||
import { useI18n } from "vue-i18n";
|
||||
|
@ -17,20 +16,19 @@ const { t } = useI18n();
|
|||
|
||||
const props = withDefaults(
|
||||
defineProps<{
|
||||
visible: boolean;
|
||||
role?: Role;
|
||||
}>(),
|
||||
{
|
||||
visible: false,
|
||||
role: undefined,
|
||||
}
|
||||
);
|
||||
|
||||
const emit = defineEmits<{
|
||||
(event: "update:visible", visible: boolean): void;
|
||||
(event: "close"): void;
|
||||
}>();
|
||||
|
||||
const modal = ref<InstanceType<typeof VModal>>();
|
||||
|
||||
const { data: roleTemplates } = useQuery({
|
||||
queryKey: ["role-templates"],
|
||||
queryFn: async () => {
|
||||
|
@ -46,13 +44,7 @@ const { data: roleTemplates } = useQuery({
|
|||
const { roleTemplateGroups, handleRoleTemplateSelect, selectedRoleTemplates } =
|
||||
useRoleTemplateSelection(roleTemplates);
|
||||
|
||||
const {
|
||||
formState,
|
||||
isUpdateMode,
|
||||
initialFormState,
|
||||
saving,
|
||||
handleCreateOrUpdate,
|
||||
} = useRoleForm();
|
||||
const { formState, isSubmitting, handleCreateOrUpdate } = useRoleForm();
|
||||
|
||||
watch(
|
||||
() => selectedRoleTemplates.value,
|
||||
|
@ -64,67 +56,39 @@ watch(
|
|||
}
|
||||
);
|
||||
|
||||
watch(
|
||||
() => props.visible,
|
||||
(visible) => {
|
||||
if (visible) {
|
||||
setFocus("displayNameInput");
|
||||
} else {
|
||||
handleResetForm();
|
||||
onMounted(() => {
|
||||
setFocus("displayNameInput");
|
||||
|
||||
if (props.role) {
|
||||
formState.value = cloneDeep(props.role);
|
||||
const dependencies =
|
||||
props.role.metadata.annotations?.[rbacAnnotations.DEPENDENCIES];
|
||||
if (dependencies) {
|
||||
selectedRoleTemplates.value = new Set(JSON.parse(dependencies));
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
watch(
|
||||
() => props.role,
|
||||
(role) => {
|
||||
if (role) {
|
||||
formState.value = cloneDeep(role);
|
||||
const dependencies =
|
||||
role.metadata.annotations?.[rbacAnnotations.DEPENDENCIES];
|
||||
if (dependencies) {
|
||||
selectedRoleTemplates.value = new Set(JSON.parse(dependencies));
|
||||
}
|
||||
} else {
|
||||
handleResetForm();
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
const editingModalTitle = computed(() => {
|
||||
return isUpdateMode.value
|
||||
? t("core.role.editing_modal.titles.update")
|
||||
: t("core.role.editing_modal.titles.create");
|
||||
});
|
||||
|
||||
const editingModalTitle = props.role
|
||||
? t("core.role.editing_modal.titles.update")
|
||||
: t("core.role.editing_modal.titles.create");
|
||||
|
||||
const handleCreateOrUpdateRole = async () => {
|
||||
try {
|
||||
await handleCreateOrUpdate();
|
||||
onVisibleChange(false);
|
||||
|
||||
modal.value?.close();
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
}
|
||||
};
|
||||
|
||||
const onVisibleChange = (visible: boolean) => {
|
||||
emit("update:visible", visible);
|
||||
if (!visible) {
|
||||
emit("close");
|
||||
}
|
||||
};
|
||||
|
||||
const handleResetForm = () => {
|
||||
formState.value = cloneDeep(initialFormState);
|
||||
selectedRoleTemplates.value.clear();
|
||||
reset("role-form");
|
||||
};
|
||||
</script>
|
||||
<template>
|
||||
<VModal
|
||||
ref="modal"
|
||||
:title="editingModalTitle"
|
||||
:visible="visible"
|
||||
:width="700"
|
||||
@update:visible="onVisibleChange"
|
||||
@close="emit('close')"
|
||||
>
|
||||
<div>
|
||||
<div class="md:grid md:grid-cols-4 md:gap-6">
|
||||
|
@ -301,14 +265,13 @@ const handleResetForm = () => {
|
|||
<template #footer>
|
||||
<VSpace>
|
||||
<SubmitButton
|
||||
v-if="visible"
|
||||
:loading="saving"
|
||||
:loading="isSubmitting"
|
||||
type="secondary"
|
||||
:text="$t('core.common.buttons.submit')"
|
||||
@submit="$formkit.submit('role-form')"
|
||||
>
|
||||
</SubmitButton>
|
||||
<VButton @click="onVisibleChange(false)">
|
||||
<VButton @click="modal?.close()">
|
||||
{{ $t("core.common.buttons.cancel_and_shortcut") }}
|
||||
</VButton>
|
||||
</VSpace>
|
||||
|
|
|
@ -247,6 +247,12 @@ function onPasswordChangeModalClose() {
|
|||
passwordChangeModal.value = false;
|
||||
refetch();
|
||||
}
|
||||
|
||||
function onGrantPermissionModalClose() {
|
||||
grantPermissionModal.value = false;
|
||||
selectedUser.value = undefined;
|
||||
refetch();
|
||||
}
|
||||
</script>
|
||||
<template>
|
||||
<UserEditingModal
|
||||
|
@ -264,9 +270,9 @@ function onPasswordChangeModalClose() {
|
|||
/>
|
||||
|
||||
<GrantPermissionModal
|
||||
v-model:visible="grantPermissionModal"
|
||||
v-if="grantPermissionModal"
|
||||
:user="selectedUser"
|
||||
@close="refetch"
|
||||
@close="onGrantPermissionModalClose"
|
||||
/>
|
||||
|
||||
<VPageHeader :title="$t('core.user.title')">
|
||||
|
|
|
@ -1,60 +1,51 @@
|
|||
<script lang="ts" setup>
|
||||
import { apiClient } from "@/utils/api-client";
|
||||
import type { User } from "@halo-dev/api-client";
|
||||
import { VModal, VSpace, VButton } from "@halo-dev/components";
|
||||
import { VButton, VModal, VSpace } from "@halo-dev/components";
|
||||
import SubmitButton from "@/components/button/SubmitButton.vue";
|
||||
import { ref } from "vue";
|
||||
|
||||
const props = withDefaults(
|
||||
defineProps<{
|
||||
visible: boolean;
|
||||
user?: User;
|
||||
}>(),
|
||||
{
|
||||
visible: false,
|
||||
user: undefined,
|
||||
}
|
||||
);
|
||||
|
||||
const emit = defineEmits<{
|
||||
(event: "update:visible", visible: boolean): void;
|
||||
(event: "close"): void;
|
||||
}>();
|
||||
|
||||
const modal = ref<InstanceType<typeof VModal>>();
|
||||
const selectedRole = ref("");
|
||||
const saving = ref(false);
|
||||
const isSubmitting = ref(false);
|
||||
|
||||
const handleGrantPermission = async () => {
|
||||
try {
|
||||
saving.value = true;
|
||||
isSubmitting.value = true;
|
||||
await apiClient.user.grantPermission({
|
||||
name: props.user?.metadata.name as string,
|
||||
grantRequest: {
|
||||
roles: [selectedRole.value],
|
||||
},
|
||||
});
|
||||
onVisibleChange(false);
|
||||
modal.value?.close();
|
||||
} catch (error) {
|
||||
console.error("Failed to grant permission to user", error);
|
||||
} finally {
|
||||
saving.value = false;
|
||||
}
|
||||
};
|
||||
|
||||
const onVisibleChange = (visible: boolean) => {
|
||||
emit("update:visible", visible);
|
||||
if (!visible) {
|
||||
emit("close");
|
||||
isSubmitting.value = false;
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<VModal
|
||||
ref="modal"
|
||||
:title="$t('core.user.grant_permission_modal.title')"
|
||||
:visible="visible"
|
||||
:width="500"
|
||||
@update:visible="onVisibleChange"
|
||||
@close="emit('close')"
|
||||
>
|
||||
<FormKit
|
||||
id="grant-permission-form"
|
||||
|
@ -72,14 +63,13 @@ const onVisibleChange = (visible: boolean) => {
|
|||
<template #footer>
|
||||
<VSpace>
|
||||
<SubmitButton
|
||||
v-if="visible"
|
||||
:loading="saving"
|
||||
:loading="isSubmitting"
|
||||
type="secondary"
|
||||
:text="$t('core.common.buttons.submit')"
|
||||
@submit="$formkit.submit('grant-permission-form')"
|
||||
>
|
||||
</SubmitButton>
|
||||
<VButton @click="onVisibleChange(false)">
|
||||
<VButton @click="modal?.close()">
|
||||
{{ $t("core.common.buttons.cancel_and_shortcut") }}
|
||||
</VButton>
|
||||
</VSpace>
|
||||
|
|
|
@ -1,6 +1,12 @@
|
|||
import type { Role } from "@halo-dev/api-client";
|
||||
import { onUnmounted, type ComputedRef, type Ref } from "vue";
|
||||
import { computed, onMounted, ref } from "vue";
|
||||
import {
|
||||
computed,
|
||||
type ComputedRef,
|
||||
onMounted,
|
||||
onUnmounted,
|
||||
type Ref,
|
||||
ref,
|
||||
} from "vue";
|
||||
import { roleLabels } from "@/constants/labels";
|
||||
import { rbacAnnotations } from "@/constants/annotations";
|
||||
import { apiClient } from "@/utils/api-client";
|
||||
|
@ -13,21 +19,6 @@ interface RoleTemplateGroup {
|
|||
roles: Role[];
|
||||
}
|
||||
|
||||
const initialFormState: Role = {
|
||||
apiVersion: "v1alpha1",
|
||||
kind: "Role",
|
||||
metadata: {
|
||||
name: "",
|
||||
generateName: "role-",
|
||||
labels: {},
|
||||
annotations: {
|
||||
[rbacAnnotations.DEPENDENCIES]: "",
|
||||
[rbacAnnotations.DISPLAY_NAME]: "",
|
||||
},
|
||||
},
|
||||
rules: [],
|
||||
};
|
||||
|
||||
interface useFetchRoleReturn {
|
||||
roles: Ref<Role[]>;
|
||||
loading: Ref<boolean>;
|
||||
|
@ -36,8 +27,7 @@ interface useFetchRoleReturn {
|
|||
|
||||
interface useRoleFormReturn {
|
||||
formState: Ref<Role>;
|
||||
initialFormState: Role;
|
||||
saving: Ref<boolean>;
|
||||
isSubmitting: Ref<boolean>;
|
||||
isUpdateMode: ComputedRef<boolean>;
|
||||
handleCreateOrUpdate: () => Promise<void>;
|
||||
}
|
||||
|
@ -110,8 +100,21 @@ export function useFetchRole(): useFetchRoleReturn {
|
|||
export function useRoleForm(): useRoleFormReturn {
|
||||
const { t } = useI18n();
|
||||
|
||||
const formState = ref<Role>(initialFormState);
|
||||
const saving = ref(false);
|
||||
const formState = ref<Role>({
|
||||
apiVersion: "v1alpha1",
|
||||
kind: "Role",
|
||||
metadata: {
|
||||
name: "",
|
||||
generateName: "role-",
|
||||
labels: {},
|
||||
annotations: {
|
||||
[rbacAnnotations.DEPENDENCIES]: "",
|
||||
[rbacAnnotations.DISPLAY_NAME]: "",
|
||||
},
|
||||
},
|
||||
rules: [],
|
||||
});
|
||||
const isSubmitting = ref(false);
|
||||
|
||||
const isUpdateMode = computed(() => {
|
||||
return !!formState.value.metadata.creationTimestamp;
|
||||
|
@ -119,7 +122,7 @@ export function useRoleForm(): useRoleFormReturn {
|
|||
|
||||
const handleCreateOrUpdate = async () => {
|
||||
try {
|
||||
saving.value = true;
|
||||
isSubmitting.value = true;
|
||||
if (isUpdateMode.value) {
|
||||
const { data } = await apiClient.extension.role.updateV1alpha1Role({
|
||||
name: formState.value.metadata.name,
|
||||
|
@ -139,14 +142,13 @@ export function useRoleForm(): useRoleFormReturn {
|
|||
} catch (e) {
|
||||
console.error(e);
|
||||
} finally {
|
||||
saving.value = false;
|
||||
isSubmitting.value = false;
|
||||
}
|
||||
};
|
||||
|
||||
return {
|
||||
formState,
|
||||
initialFormState,
|
||||
saving,
|
||||
isSubmitting,
|
||||
isUpdateMode,
|
||||
handleCreateOrUpdate,
|
||||
};
|
||||
|
|
Loading…
Reference in New Issue