mirror of https://github.com/halo-dev/halo-admin
perf: optimize the creation of attachment storage policies (#681)
#### What type of PR is this? /kind improvement /milestone 2.0 #### What this PR does / why we need it: 优化首次上传附件时,创建存储策略的流程,现在可以直接打开新建策略的表单。 #### Screenshots: before: <img width="898" alt="image" src="https://user-images.githubusercontent.com/21301288/199915792-92547e21-ffbb-4c9f-9614-b1f89f7d6f75.png"> after: <img width="1087" alt="image" src="https://user-images.githubusercontent.com/21301288/199915494-00447427-060a-4744-83b0-d1067e745517.png"> #### Special notes for your reviewer: /cc @halo-dev/sig-halo-console 测试方式: 1. 测试在上传弹窗中新建存储策略。 #### Does this PR introduce a user-facing change? ```release-note 优化首次上传附件时,创建存储策略的流程。 ```pull/684/head
parent
b0359c4e17
commit
d3d28dd3da
|
@ -95,7 +95,7 @@ const handleClose = () => {
|
|||
mr-3
|
||||
flex-1
|
||||
font-medium
|
||||
text-base;
|
||||
text-sm;
|
||||
}
|
||||
|
||||
.alert-close {
|
||||
|
@ -113,7 +113,7 @@ const handleClose = () => {
|
|||
}
|
||||
|
||||
.alert-description {
|
||||
@apply text-sm
|
||||
@apply text-xs
|
||||
mt-2;
|
||||
}
|
||||
|
||||
|
|
|
@ -10,10 +10,12 @@ import {
|
|||
import AttachmentPolicyEditingModal from "./AttachmentPolicyEditingModal.vue";
|
||||
import { ref, watch } from "vue";
|
||||
import type { Policy, PolicyTemplate } from "@halo-dev/api-client";
|
||||
import { apiClient } from "@/utils/api-client";
|
||||
import { v4 as uuid } from "uuid";
|
||||
import { formatDatetime } from "@/utils/date";
|
||||
import { useFetchAttachmentPolicy } from "../composables/use-attachment-policy";
|
||||
import {
|
||||
useFetchAttachmentPolicy,
|
||||
useFetchAttachmentPolicyTemplate,
|
||||
} from "../composables/use-attachment-policy";
|
||||
|
||||
const props = withDefaults(
|
||||
defineProps<{
|
||||
|
@ -30,22 +32,15 @@ const emit = defineEmits<{
|
|||
}>();
|
||||
|
||||
const { policies, loading, handleFetchPolicies } = useFetchAttachmentPolicy();
|
||||
const { policyTemplates, handleFetchPolicyTemplates } =
|
||||
useFetchAttachmentPolicyTemplate({
|
||||
fetchOnMounted: false,
|
||||
});
|
||||
|
||||
const selectedPolicy = ref<Policy | null>(null);
|
||||
const policyTemplates = ref<PolicyTemplate[]>([] as PolicyTemplate[]);
|
||||
const selectedPolicy = ref<Policy>();
|
||||
|
||||
const policyEditingModal = ref(false);
|
||||
|
||||
const handleFetchPolicyTemplates = async () => {
|
||||
try {
|
||||
const { data } =
|
||||
await apiClient.extension.storage.policyTemplate.liststorageHaloRunV1alpha1PolicyTemplate();
|
||||
policyTemplates.value = data.items;
|
||||
} catch (e) {
|
||||
console.error("Failed to fetch attachment policy templates", e);
|
||||
}
|
||||
};
|
||||
|
||||
function onVisibleChange(visible: boolean) {
|
||||
emit("update:visible", visible);
|
||||
if (!visible) {
|
||||
|
@ -79,14 +74,14 @@ const handleOpenCreateNewPolicyModal = (policyTemplate: PolicyTemplate) => {
|
|||
};
|
||||
|
||||
const onEditingModalClose = () => {
|
||||
selectedPolicy.value = null;
|
||||
selectedPolicy.value = undefined;
|
||||
handleFetchPolicies();
|
||||
};
|
||||
|
||||
watch(
|
||||
() => props.visible,
|
||||
(newValue) => {
|
||||
if (newValue) {
|
||||
(visible) => {
|
||||
if (visible) {
|
||||
handleFetchPolicyTemplates();
|
||||
handleFetchPolicies();
|
||||
}
|
||||
|
|
|
@ -17,11 +17,11 @@ import { setFocus } from "@/formkit/utils/focus";
|
|||
const props = withDefaults(
|
||||
defineProps<{
|
||||
visible: boolean;
|
||||
policy: Policy | null;
|
||||
policy?: Policy;
|
||||
}>(),
|
||||
{
|
||||
visible: false,
|
||||
policy: null,
|
||||
policy: undefined,
|
||||
}
|
||||
);
|
||||
|
||||
|
|
|
@ -52,6 +52,18 @@ const onVisibleChange = (visible: boolean) => {
|
|||
}
|
||||
};
|
||||
|
||||
const onChangeProvider = (providerId: string) => {
|
||||
const provider = attachmentSelectorPublicState.value.providers.find(
|
||||
(provider) => provider.id === providerId
|
||||
);
|
||||
|
||||
if (!provider) {
|
||||
return;
|
||||
}
|
||||
|
||||
activeId.value = providerId;
|
||||
};
|
||||
|
||||
const handleConfirm = () => {
|
||||
emit("select", Array.from(selected.value));
|
||||
onVisibleChange(false);
|
||||
|
@ -69,7 +81,7 @@ const handleConfirm = () => {
|
|||
<VTabbar
|
||||
v-model:active-id="activeId"
|
||||
:items="attachmentSelectorPublicState.providers"
|
||||
class="w-full !rounded-none"
|
||||
class="w-full"
|
||||
type="outline"
|
||||
></VTabbar>
|
||||
|
||||
|
@ -83,6 +95,7 @@ const handleConfirm = () => {
|
|||
:is="provider.component"
|
||||
v-if="activeId === provider.id"
|
||||
v-model:selected="selected"
|
||||
@change-provider="onChangeProvider"
|
||||
></component>
|
||||
<template #fallback> 加载中 </template>
|
||||
</Suspense>
|
||||
|
|
|
@ -1,16 +1,14 @@
|
|||
<script lang="ts" setup>
|
||||
import {
|
||||
VModal,
|
||||
VEmpty,
|
||||
IconAddCircle,
|
||||
VButton,
|
||||
VSpace,
|
||||
} from "@halo-dev/components";
|
||||
import { VModal, IconAddCircle, VAlert } from "@halo-dev/components";
|
||||
import UppyUpload from "@/components/upload/UppyUpload.vue";
|
||||
import { computed, ref, watch, watchEffect } from "vue";
|
||||
import type { Policy, Group } from "@halo-dev/api-client";
|
||||
import { useFetchAttachmentPolicy } from "../composables/use-attachment-policy";
|
||||
import AttachmentPoliciesModal from "./AttachmentPoliciesModal.vue";
|
||||
import type { Policy, Group, PolicyTemplate } from "@halo-dev/api-client";
|
||||
import {
|
||||
useFetchAttachmentPolicy,
|
||||
useFetchAttachmentPolicyTemplate,
|
||||
} from "../composables/use-attachment-policy";
|
||||
import AttachmentPolicyEditingModal from "./AttachmentPolicyEditingModal.vue";
|
||||
import { v4 as uuid } from "uuid";
|
||||
|
||||
const props = withDefaults(
|
||||
defineProps<{
|
||||
|
@ -28,15 +26,19 @@ const emit = defineEmits<{
|
|||
(event: "close"): void;
|
||||
}>();
|
||||
|
||||
const { policies, loading, handleFetchPolicies } = useFetchAttachmentPolicy();
|
||||
const { policies, handleFetchPolicies } = useFetchAttachmentPolicy({
|
||||
fetchOnMounted: false,
|
||||
});
|
||||
const { policyTemplates, handleFetchPolicyTemplates } =
|
||||
useFetchAttachmentPolicyTemplate();
|
||||
|
||||
const selectedPolicy = ref<Policy | null>(null);
|
||||
const policyVisible = ref(false);
|
||||
const selectedPolicy = ref<Policy>();
|
||||
const uploadVisible = ref(false);
|
||||
const policyEditingModal = ref(false);
|
||||
|
||||
const modalTitle = computed(() => {
|
||||
if (props.group && props.group.metadata.name) {
|
||||
return `上传附件:${props.group.spec.displayName}`;
|
||||
return `上传附件到分组:${props.group.spec.displayName}`;
|
||||
}
|
||||
return "上传附件";
|
||||
});
|
||||
|
@ -47,11 +49,36 @@ watchEffect(() => {
|
|||
}
|
||||
});
|
||||
|
||||
const handleOpenCreateNewPolicyModal = (policyTemplate: PolicyTemplate) => {
|
||||
selectedPolicy.value = {
|
||||
spec: {
|
||||
displayName: "",
|
||||
templateRef: {
|
||||
name: policyTemplate.metadata.name,
|
||||
},
|
||||
configMapRef: {
|
||||
name: uuid(),
|
||||
},
|
||||
},
|
||||
apiVersion: "storage.halo.run/v1alpha1",
|
||||
kind: "Policy",
|
||||
metadata: {
|
||||
name: uuid(),
|
||||
},
|
||||
};
|
||||
policyEditingModal.value = true;
|
||||
};
|
||||
|
||||
const onEditingModalClose = async () => {
|
||||
await handleFetchPolicies();
|
||||
selectedPolicy.value = policies.value[0];
|
||||
};
|
||||
|
||||
const onVisibleChange = (visible: boolean) => {
|
||||
emit("update:visible", visible);
|
||||
if (!visible) {
|
||||
emit("close");
|
||||
policyVisible.value = false;
|
||||
policyEditingModal.value = false;
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -60,6 +87,7 @@ watch(
|
|||
(newValue) => {
|
||||
if (newValue) {
|
||||
handleFetchPolicies();
|
||||
handleFetchPolicyTemplates();
|
||||
uploadVisible.value = true;
|
||||
} else {
|
||||
const uploadVisibleTimer = setTimeout(() => {
|
||||
|
@ -74,28 +102,11 @@ watch(
|
|||
<VModal
|
||||
:body-class="['!p-0']"
|
||||
:visible="visible"
|
||||
:width="600"
|
||||
:width="650"
|
||||
:title="modalTitle"
|
||||
@update:visible="onVisibleChange"
|
||||
>
|
||||
<VEmpty
|
||||
v-if="!policies.length && !loading"
|
||||
message="当前没有上传附件的存储策略,请先创建存储策略"
|
||||
title="无存储策略"
|
||||
>
|
||||
<template #actions>
|
||||
<VSpace>
|
||||
<VButton @click="handleFetchPolicies">刷新</VButton>
|
||||
<VButton type="secondary" @click="policyVisible = true">
|
||||
<template #icon>
|
||||
<IconAddCircle class="h-full w-full" />
|
||||
</template>
|
||||
新建策略
|
||||
</VButton>
|
||||
</VSpace>
|
||||
</template>
|
||||
</VEmpty>
|
||||
<div v-else class="w-full p-4">
|
||||
<div class="w-full p-4">
|
||||
<div class="mb-2">
|
||||
<span class="text-sm text-gray-900">选择存储策略:</span>
|
||||
</div>
|
||||
|
@ -119,15 +130,41 @@ watch(
|
|||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="flex cursor-pointer items-center rounded-base bg-gray-100 p-2 text-gray-500 transition-all hover:bg-gray-200 hover:text-gray-900 hover:shadow-sm"
|
||||
@click="policyVisible = true"
|
||||
>
|
||||
<div class="flex flex-1 items-center truncate">
|
||||
<span class="truncate text-sm">新建策略</span>
|
||||
|
||||
<FloatingDropdown>
|
||||
<div
|
||||
class="flex h-full cursor-pointer items-center rounded-base bg-gray-100 p-2 text-gray-500 transition-all hover:bg-gray-200 hover:text-gray-900 hover:shadow-sm"
|
||||
>
|
||||
<div class="flex flex-1 items-center truncate">
|
||||
<span class="truncate text-sm">新建策略</span>
|
||||
</div>
|
||||
<IconAddCircle />
|
||||
</div>
|
||||
<IconAddCircle />
|
||||
</div>
|
||||
<template #popper>
|
||||
<div class="w-72 p-4">
|
||||
<ul class="space-y-1">
|
||||
<li
|
||||
v-for="(policyTemplate, index) in policyTemplates"
|
||||
:key="index"
|
||||
v-close-popper
|
||||
class="flex cursor-pointer items-center rounded px-3 py-2 text-sm text-gray-600 hover:bg-gray-100 hover:text-gray-900"
|
||||
@click="handleOpenCreateNewPolicyModal(policyTemplate)"
|
||||
>
|
||||
<span class="truncate">
|
||||
{{ policyTemplate.spec?.displayName }}
|
||||
</span>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</template>
|
||||
</FloatingDropdown>
|
||||
</div>
|
||||
<div v-if="policies.length <= 0" class="mb-3">
|
||||
<VAlert
|
||||
title="没有存储策略"
|
||||
description="在上传之前,需要新建一个存储策略"
|
||||
:closable="false"
|
||||
/>
|
||||
</div>
|
||||
<UppyUpload
|
||||
v-if="uploadVisible"
|
||||
|
@ -143,8 +180,9 @@ watch(
|
|||
</div>
|
||||
</VModal>
|
||||
|
||||
<AttachmentPoliciesModal
|
||||
v-model:visible="policyVisible"
|
||||
@close="handleFetchPolicies"
|
||||
<AttachmentPolicyEditingModal
|
||||
v-model:visible="policyEditingModal"
|
||||
:policy="selectedPolicy"
|
||||
@close="onEditingModalClose"
|
||||
/>
|
||||
</template>
|
||||
|
|
|
@ -34,6 +34,7 @@ withDefaults(
|
|||
|
||||
const emit = defineEmits<{
|
||||
(event: "update:selected", attachments: AttachmentLike[]): void;
|
||||
(event: "change-provider", providerId: string): void;
|
||||
}>();
|
||||
|
||||
const selectedGroup = ref<Group>();
|
||||
|
@ -85,7 +86,7 @@ await handleFetchAttachments();
|
|||
<template #actions>
|
||||
<VSpace>
|
||||
<VButton @click="handleFetchAttachments">刷新</VButton>
|
||||
<VButton type="secondary" @click="uploadVisible = true">
|
||||
<VButton type="secondary" @click="emit('change-provider', 'upload')">
|
||||
<template #icon>
|
||||
<IconUpload class="h-full w-full" />
|
||||
</template>
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import { onMounted, ref } from "vue";
|
||||
import type { Ref } from "vue";
|
||||
import type { Policy } from "@halo-dev/api-client";
|
||||
import type { Policy, PolicyTemplate } from "@halo-dev/api-client";
|
||||
import { apiClient } from "@/utils/api-client";
|
||||
|
||||
interface useFetchAttachmentPolicyReturn {
|
||||
|
@ -9,6 +9,12 @@ interface useFetchAttachmentPolicyReturn {
|
|||
handleFetchPolicies: () => void;
|
||||
}
|
||||
|
||||
interface useFetchAttachmentPolicyTemplatesReturn {
|
||||
policyTemplates: Ref<PolicyTemplate[]>;
|
||||
loading: Ref<boolean>;
|
||||
handleFetchPolicyTemplates: () => void;
|
||||
}
|
||||
|
||||
export function useFetchAttachmentPolicy(options?: {
|
||||
fetchOnMounted: boolean;
|
||||
}): useFetchAttachmentPolicyReturn {
|
||||
|
@ -40,3 +46,35 @@ export function useFetchAttachmentPolicy(options?: {
|
|||
handleFetchPolicies,
|
||||
};
|
||||
}
|
||||
|
||||
export function useFetchAttachmentPolicyTemplate(options?: {
|
||||
fetchOnMounted: boolean;
|
||||
}): useFetchAttachmentPolicyTemplatesReturn {
|
||||
const { fetchOnMounted } = options || {};
|
||||
|
||||
const policyTemplates = ref<PolicyTemplate[]>([] as PolicyTemplate[]);
|
||||
const loading = ref<boolean>(false);
|
||||
|
||||
const handleFetchPolicyTemplates = async () => {
|
||||
try {
|
||||
loading.value = true;
|
||||
const { data } =
|
||||
await apiClient.extension.storage.policyTemplate.liststorageHaloRunV1alpha1PolicyTemplate();
|
||||
policyTemplates.value = data.items;
|
||||
} catch (e) {
|
||||
console.error("Failed to fetch attachment policy templates", e);
|
||||
} finally {
|
||||
loading.value = false;
|
||||
}
|
||||
};
|
||||
|
||||
onMounted(() => {
|
||||
fetchOnMounted && handleFetchPolicyTemplates();
|
||||
});
|
||||
|
||||
return {
|
||||
policyTemplates,
|
||||
loading,
|
||||
handleFetchPolicyTemplates,
|
||||
};
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue