refactor: improve code base of attachment-related (#5967)

#### What type of PR is this?

/area ui
/kind improvement
/milestone 2.16.x

#### What this PR does / why we need it:

优化附件管理的相关代码。

1. 优化附件管理相关的对话框组件,减少重复和不必要的请求。
2. 简化附件存储策略编辑组件的逻辑。

#### Special notes for your reviewer:

需要测试:

1. 附件上传的相关功能。
2. 附件存储策略的编辑和新建。
3. 附件筛选条件功能。

#### Does this PR introduce a user-facing change?

```release-note
优化附件管理相关代码,减少重复和不必要的请求。
```
pull/5975/head
Ryan Wang 2024-05-23 10:54:49 +08:00 committed by GitHub
parent ce5757ae10
commit 89b20bf5a3
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
13 changed files with 278 additions and 631 deletions

View File

@ -2,185 +2,11 @@
// types // types
import { computed, watch, type ComputedRef, type Ref } from "vue"; import { computed, watch, type ComputedRef, type Ref } from "vue";
import { ref } from "vue"; import { ref } from "vue";
import { apiClient } from "@/utils/api-client";
// libs // libs
import { cloneDeep, merge } from "lodash-es"; import { cloneDeep } from "lodash-es";
import type { ConfigMap, Setting, SettingForm } from "@halo-dev/api-client"; import type { ConfigMap, Setting, SettingForm } from "@halo-dev/api-client";
import type { FormKitSchemaCondition, FormKitSchemaNode } from "@formkit/core"; import type { FormKitSchemaCondition, FormKitSchemaNode } from "@formkit/core";
import { Toast } from "@halo-dev/components";
import { useI18n } from "vue-i18n";
const initialConfigMap: ConfigMap = {
apiVersion: "v1alpha1",
kind: "ConfigMap",
metadata: {
name: "",
},
data: {},
};
interface useSettingFormReturn {
setting: Ref<Setting | undefined>;
configMap: Ref<ConfigMap>;
configMapFormData: Ref<Record<string, Record<string, string>> | undefined>;
saving: Ref<boolean>;
handleFetchSettings: () => void;
handleFetchConfigMap: () => void;
handleSaveConfigMap: () => void;
handleReset: () => void;
}
export function useSettingForm(
settingName: Ref<string | undefined>,
configMapName: Ref<string | undefined>
): useSettingFormReturn {
const { t } = useI18n();
const setting = ref<Setting>();
const configMap = ref<ConfigMap>(cloneDeep(initialConfigMap));
const configMapFormData = ref<
Record<string, Record<string, string>> | undefined
>();
const saving = ref(false);
const handleFetchSettings = async () => {
if (!settingName.value) {
setting.value = undefined;
return;
}
try {
const { data } = await apiClient.extension.setting.getv1alpha1Setting({
name: settingName.value,
});
setting.value = data;
// init configMapFormData
if (!configMapFormData.value) {
const { forms } = setting.value.spec;
const initialConfigMapFormData: Record<
string,
Record<string, string>
> = {};
forms.forEach((form) => {
initialConfigMapFormData[form.group] = {};
const formSchema = form.formSchema as (
| FormKitSchemaCondition
| FormKitSchemaNode
)[];
formSchema.forEach((schema) => {
// @ts-ignore
if ("name" in schema && "$formkit" in schema) {
initialConfigMapFormData[form.group][schema.name] =
schema.value || undefined;
}
});
});
configMapFormData.value = cloneDeep(initialConfigMapFormData);
}
} catch (e) {
console.error("Failed to fetch setting", e);
}
};
const handleFetchConfigMap = async () => {
if (!configMapName.value) {
configMap.value = cloneDeep(initialConfigMap);
configMapFormData.value = undefined;
return;
}
try {
const response = await apiClient.extension.configMap.getv1alpha1ConfigMap(
{
name: configMapName.value,
},
{
mute: true,
}
);
configMap.value = response.data;
const { data } = configMap.value;
if (data) {
// merge objects value
const { forms } = setting.value?.spec || {};
forms?.forEach((form) => {
if (!configMapFormData.value) {
return;
}
configMapFormData.value[form.group] = merge(
configMapFormData.value[form.group] || {},
JSON.parse(data[form.group] || "{}")
);
});
}
} catch (e) {
console.error("Failed to fetch configMap", e);
}
};
const handleSaveConfigMap = async () => {
try {
saving.value = true;
if (!configMap.value.metadata.name && configMapName.value) {
configMap.value.metadata.name = configMapName.value;
}
setting.value?.spec.forms.forEach((item: SettingForm) => {
// @ts-ignore
configMap.value.data[item.group] = JSON.stringify(
configMapFormData?.value?.[item.group]
);
});
if (!configMap.value.metadata.creationTimestamp) {
const { data } =
await apiClient.extension.configMap.createv1alpha1ConfigMap({
configMap: configMap.value,
});
configMapName.value = data.metadata.name;
} else {
const { data } =
await apiClient.extension.configMap.updatev1alpha1ConfigMap({
configMap: configMap.value,
name: configMap.value.metadata.name,
});
configMapName.value = data.metadata.name;
}
Toast.success(t("core.common.toast.save_success"));
} catch (e) {
console.error("Failed to save configMap", e);
} finally {
await handleFetchSettings();
await handleFetchConfigMap();
saving.value = false;
}
};
const handleReset = () => {
setting.value = undefined;
configMap.value = cloneDeep(initialConfigMap);
configMapFormData.value = undefined;
};
return {
setting,
configMap,
configMapFormData,
saving,
handleFetchSettings,
handleFetchConfigMap,
handleSaveConfigMap,
handleReset,
};
}
interface useSettingFormConvertReturn { interface useSettingFormConvertReturn {
formSchema: ComputedRef< formSchema: ComputedRef<

View File

@ -4,28 +4,29 @@ import {
IconArrowRight, IconArrowRight,
IconCheckboxFill, IconCheckboxFill,
IconDatabase2Line, IconDatabase2Line,
IconFolder,
IconGrid, IconGrid,
IconList, IconList,
IconUpload,
IconRefreshLine, IconRefreshLine,
IconUpload,
Toast,
VButton, VButton,
VCard, VCard,
VDropdown,
VDropdownItem,
VEmpty,
VLoading,
VPageHeader, VPageHeader,
VPagination, VPagination,
VSpace, VSpace,
VEmpty,
IconFolder,
VLoading,
Toast,
VDropdown,
VDropdownItem,
} from "@halo-dev/components"; } from "@halo-dev/components";
import LazyImage from "@/components/image/LazyImage.vue"; import LazyImage from "@/components/image/LazyImage.vue";
import AttachmentDetailModal from "./components/AttachmentDetailModal.vue"; import AttachmentDetailModal from "./components/AttachmentDetailModal.vue";
import AttachmentUploadModal from "./components/AttachmentUploadModal.vue"; import AttachmentUploadModal from "./components/AttachmentUploadModal.vue";
import AttachmentPoliciesModal from "./components/AttachmentPoliciesModal.vue"; import AttachmentPoliciesModal from "./components/AttachmentPoliciesModal.vue";
import AttachmentGroupList from "./components/AttachmentGroupList.vue"; import AttachmentGroupList from "./components/AttachmentGroupList.vue";
import { computed, onMounted, ref, watch } from "vue"; import type { Ref } from "vue";
import { computed, onMounted, provide, ref, watch } from "vue";
import type { Attachment, Group } from "@halo-dev/api-client"; import type { Attachment, Group } from "@halo-dev/api-client";
import { useFetchAttachmentPolicy } from "./composables/use-attachment-policy"; import { useFetchAttachmentPolicy } from "./composables/use-attachment-policy";
import { useAttachmentControl } from "./composables/use-attachment"; import { useAttachmentControl } from "./composables/use-attachment";
@ -37,8 +38,6 @@ import { useFetchAttachmentGroup } from "./composables/use-attachment-group";
import { useI18n } from "vue-i18n"; import { useI18n } from "vue-i18n";
import { useLocalStorage } from "@vueuse/core"; import { useLocalStorage } from "@vueuse/core";
import UserFilterDropdown from "@/components/filter/UserFilterDropdown.vue"; import UserFilterDropdown from "@/components/filter/UserFilterDropdown.vue";
import { provide } from "vue";
import type { Ref } from "vue";
import AttachmentListItem from "./components/AttachmentListItem.vue"; import AttachmentListItem from "./components/AttachmentListItem.vue";
const { t } = useI18n(); const { t } = useI18n();
@ -50,7 +49,7 @@ const detailVisible = ref(false);
const { policies } = useFetchAttachmentPolicy(); const { policies } = useFetchAttachmentPolicy();
const { groups, handleFetchGroups } = useFetchAttachmentGroup(); const { groups, handleFetchGroups } = useFetchAttachmentGroup();
const selectedGroup = ref<Group>(); const selectedGroup = useRouteQuery<string | undefined>("group");
// Filter // Filter
const keyword = useRouteQuery<string>("keyword", ""); const keyword = useRouteQuery<string>("keyword", "");
@ -111,12 +110,8 @@ const {
isChecked, isChecked,
handleReset, handleReset,
} = useAttachmentControl({ } = useAttachmentControl({
group: selectedGroup, groupName: selectedGroup,
policy: computed(() => { policyName: selectedPolicy,
return policies.value?.find(
(policy) => policy.metadata.name === selectedPolicy.value
);
}),
user: selectedUser, user: selectedUser,
accepts: computed(() => { accepts: computed(() => {
if (!selectedAccepts.value) { if (!selectedAccepts.value) {
@ -187,6 +182,7 @@ const onDetailModalClose = () => {
const onUploadModalClose = () => { const onUploadModalClose = () => {
routeQueryAction.value = undefined; routeQueryAction.value = undefined;
handleFetchAttachments(); handleFetchAttachments();
uploadVisible.value = false;
}; };
// View type // View type
@ -258,11 +254,11 @@ onMounted(() => {
</span> </span>
</template> </template>
</AttachmentDetailModal> </AttachmentDetailModal>
<AttachmentUploadModal <AttachmentUploadModal v-if="uploadVisible" @close="onUploadModalClose" />
v-model:visible="uploadVisible" <AttachmentPoliciesModal
@close="onUploadModalClose" v-if="policyVisible"
@close="policyVisible = false"
/> />
<AttachmentPoliciesModal v-model:visible="policyVisible" />
<VPageHeader :title="$t('core.attachment.title')"> <VPageHeader :title="$t('core.attachment.title')">
<template #icon> <template #icon>
<IconFolder class="mr-2 self-center" /> <IconFolder class="mr-2 self-center" />
@ -470,7 +466,6 @@ onMounted(() => {
<div :style="`${viewType === 'list' ? 'padding:12px 16px 0' : ''}`"> <div :style="`${viewType === 'list' ? 'padding:12px 16px 0' : ''}`">
<AttachmentGroupList <AttachmentGroupList
v-model:selected-group="selectedGroup"
@select="handleReset" @select="handleReset"
@update="handleFetchGroups" @update="handleFetchGroups"
@reload-attachments="handleFetchAttachments" @reload-attachments="handleFetchAttachments"

View File

@ -2,32 +2,29 @@
import { Toast, VButton, VModal, VSpace } from "@halo-dev/components"; import { Toast, VButton, VModal, VSpace } from "@halo-dev/components";
import SubmitButton from "@/components/button/SubmitButton.vue"; import SubmitButton from "@/components/button/SubmitButton.vue";
import type { Group } from "@halo-dev/api-client"; import type { Group } from "@halo-dev/api-client";
import { computed, ref, watch } from "vue"; import { onMounted, ref } from "vue";
import { cloneDeep } from "lodash-es";
import { apiClient } from "@/utils/api-client"; import { apiClient } from "@/utils/api-client";
import { reset } from "@formkit/core";
import { setFocus } from "@/formkit/utils/focus"; import { setFocus } from "@/formkit/utils/focus";
import { useI18n } from "vue-i18n"; import { useI18n } from "vue-i18n";
import { cloneDeep } from "lodash-es";
const props = withDefaults( const props = withDefaults(
defineProps<{ defineProps<{
visible: boolean; group?: Group;
group: Group | null;
}>(), }>(),
{ {
visible: false, group: undefined,
group: null,
} }
); );
const emit = defineEmits<{ const emit = defineEmits<{
(event: "update:visible", visible: boolean): void;
(event: "close"): void; (event: "close"): void;
}>(); }>();
const { t } = useI18n(); const { t } = useI18n();
const initialFormState: Group = { const modal = ref();
const formState = ref<Group>({
spec: { spec: {
displayName: "", displayName: "",
}, },
@ -37,25 +34,17 @@ const initialFormState: Group = {
name: "", name: "",
generateName: "attachment-group-", generateName: "attachment-group-",
}, },
}; });
const formState = ref<Group>(cloneDeep(initialFormState));
const saving = ref(false); const saving = ref(false);
const isUpdateMode = computed(() => { const modalTitle = props.group
return !!formState.value.metadata.creationTimestamp;
});
const modalTitle = computed(() => {
return isUpdateMode.value
? t("core.attachment.group_editing_modal.titles.update") ? t("core.attachment.group_editing_modal.titles.update")
: t("core.attachment.group_editing_modal.titles.create"); : t("core.attachment.group_editing_modal.titles.create");
});
const handleSave = async () => { const handleSave = async () => {
try { try {
saving.value = true; saving.value = true;
if (isUpdateMode.value) { if (props.group) {
await apiClient.extension.storage.group.updatestorageHaloRunV1alpha1Group( await apiClient.extension.storage.group.updatestorageHaloRunV1alpha1Group(
{ {
name: formState.value.metadata.name, name: formState.value.metadata.name,
@ -71,7 +60,7 @@ const handleSave = async () => {
} }
Toast.success(t("core.common.toast.save_success")); Toast.success(t("core.common.toast.save_success"));
onVisibleChange(false); modal.value.close();
} catch (e) { } catch (e) {
console.error("Failed to save attachment group", e); console.error("Failed to save attachment group", e);
} finally { } finally {
@ -79,47 +68,16 @@ const handleSave = async () => {
} }
}; };
const onVisibleChange = (visible: boolean) => { onMounted(() => {
emit("update:visible", visible);
if (!visible) {
emit("close");
}
};
const handleResetForm = () => {
formState.value = cloneDeep(initialFormState);
reset("attachment-group-form");
};
watch(
() => props.visible,
(visible) => {
if (visible) {
setFocus("displayNameInput"); setFocus("displayNameInput");
} else {
handleResetForm();
}
}
);
watch( if (props.group) {
() => props.group, formState.value = cloneDeep(props.group);
(group) => {
if (group) {
formState.value = cloneDeep(group);
} else {
handleResetForm();
} }
} });
);
</script> </script>
<template> <template>
<VModal <VModal ref="modal" :title="modalTitle" :width="500" @close="emit('close')">
:title="modalTitle"
:visible="visible"
:width="500"
@update:visible="onVisibleChange"
>
<FormKit <FormKit
id="attachment-group-form" id="attachment-group-form"
name="attachment-group-form" name="attachment-group-form"
@ -142,14 +100,13 @@ watch(
<template #footer> <template #footer>
<VSpace> <VSpace>
<SubmitButton <SubmitButton
v-if="visible"
:loading="saving" :loading="saving"
type="secondary" type="secondary"
:text="$t('core.common.buttons.submit')" :text="$t('core.common.buttons.submit')"
@submit="$formkit.submit('attachment-group-form')" @submit="$formkit.submit('attachment-group-form')"
> >
</SubmitButton> </SubmitButton>
<VButton @click="onVisibleChange(false)"> <VButton @click="modal.close()">
{{ $t("core.common.buttons.cancel_and_shortcut") }} {{ $t("core.common.buttons.cancel_and_shortcut") }}
</VButton> </VButton>
</VSpace> </VSpace>

View File

@ -1,6 +1,6 @@
<script lang="ts" setup> <script lang="ts" setup>
// core libs // core libs
import { onMounted, ref, watch } from "vue"; import { ref } from "vue";
// components // components
import { import {
@ -26,17 +26,14 @@ const { t } = useI18n();
const props = withDefaults( const props = withDefaults(
defineProps<{ defineProps<{
selectedGroup: Group | undefined;
readonly?: boolean; readonly?: boolean;
}>(), }>(),
{ {
selectedGroup: undefined,
readonly: false, readonly: false,
} }
); );
const emit = defineEmits<{ const emit = defineEmits<{
(event: "update:selectedGroup", group: Group): void;
(event: "select", group: Group): void; (event: "select", group: Group): void;
(event: "update"): void; (event: "update"): void;
(event: "reload-attachments"): void; (event: "reload-attachments"): void;
@ -67,19 +64,17 @@ const defaultGroups: Group[] = [
const { groups, handleFetchGroups } = useFetchAttachmentGroup(); const { groups, handleFetchGroups } = useFetchAttachmentGroup();
const groupToUpdate = ref<Group | null>(null); const groupToUpdate = ref<Group>();
const loading = ref<boolean>(false); const loading = ref<boolean>(false);
const editingModal = ref(false); const editingModal = ref(false);
const routeQuery = useRouteQuery<string>("group"); const selectedGroup = props.readonly
? ref("")
: useRouteQuery<string>("group", "");
const handleSelectGroup = (group: Group) => { const handleSelectGroup = (group: Group) => {
emit("update:selectedGroup", group);
emit("select", group); emit("select", group);
selectedGroup.value = group.metadata.name;
if (!props.readonly) {
routeQuery.value = group.metadata.name;
}
}; };
const handleOpenEditingModal = (group: Group) => { const handleOpenEditingModal = (group: Group) => {
@ -90,6 +85,7 @@ const handleOpenEditingModal = (group: Group) => {
const onEditingModalClose = () => { const onEditingModalClose = () => {
emit("update"); emit("update");
handleFetchGroups(); handleFetchGroups();
editingModal.value = false;
}; };
const handleDelete = (group: Group) => { const handleDelete = (group: Group) => {
@ -181,51 +177,20 @@ const handleDeleteWithAttachments = (group: Group) => {
}, },
}); });
}; };
watch(
() => groups.value?.length,
() => {
const allGroups = [...defaultGroups, ...(groups.value || [])];
const groupIndex = allGroups.findIndex(
(group) => group.metadata.name === routeQuery.value
);
if (groupIndex < 0) {
handleSelectGroup(defaultGroups[0]);
}
}
);
onMounted(async () => {
await handleFetchGroups();
if (routeQuery.value && !props.readonly) {
const allGroups = [...defaultGroups, ...(groups.value || [])];
const group = allGroups.find(
(group) => group.metadata.name === routeQuery.value
);
if (group) {
handleSelectGroup(group);
return;
}
}
handleSelectGroup(defaultGroups[0]);
});
</script> </script>
<template> <template>
<AttachmentGroupEditingModal <AttachmentGroupEditingModal
v-if="!readonly" v-if="!readonly && editingModal"
v-model:visible="editingModal"
:group="groupToUpdate" :group="groupToUpdate"
@close="onEditingModalClose" @close="onEditingModalClose"
/> />
<div class="mb-5 grid grid-cols-2 gap-x-2 gap-y-3 sm:grid-cols-6"> <div class="mb-5 grid grid-cols-2 gap-x-2 gap-y-3 sm:grid-cols-6">
<div <div
v-for="(defaultGroup, index) in defaultGroups" v-for="defaultGroup in defaultGroups"
:key="index" :key="defaultGroup.metadata.name"
:class="{ :class="{
'!bg-gray-200 !text-gray-900': '!bg-gray-200 !text-gray-900':
defaultGroup.metadata.name === selectedGroup?.metadata.name, defaultGroup.metadata.name === selectedGroup,
}" }"
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" 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="handleSelectGroup(defaultGroup)" @click="handleSelectGroup(defaultGroup)"
@ -235,11 +200,10 @@ onMounted(async () => {
</div> </div>
</div> </div>
<div <div
v-for="(group, index) in groups" v-for="group in groups"
:key="index" :key="group.metadata.name"
:class="{ :class="{
'!bg-gray-200 !text-gray-900': '!bg-gray-200 !text-gray-900': group.metadata.name === selectedGroup,
group.metadata.name === selectedGroup?.metadata.name,
}" }"
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" 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="handleSelectGroup(group)" @click="handleSelectGroup(group)"

View File

@ -1,15 +1,16 @@
<script lang="ts" setup> <script lang="ts" setup>
import { import {
VSpace, Dialog,
VStatusDot, Toast,
VDropdownDivider,
VDropdownItem,
VEntity, VEntity,
VEntityField, VEntityField,
Toast, VSpace,
VDropdownItem, VStatusDot,
Dialog,
VDropdownDivider,
} from "@halo-dev/components"; } from "@halo-dev/components";
import { computed, ref } from "vue"; import type { Ref } from "vue";
import { computed, inject, markRaw, ref, toRefs } from "vue";
import type { Attachment } from "@halo-dev/api-client"; import type { Attachment } from "@halo-dev/api-client";
import { formatDatetime } from "@/utils/date"; import { formatDatetime } from "@/utils/date";
import prettyBytes from "pretty-bytes"; import prettyBytes from "pretty-bytes";
@ -17,14 +18,10 @@ import { useFetchAttachmentPolicy } from "../composables/use-attachment-policy";
import { apiClient } from "@/utils/api-client"; import { apiClient } from "@/utils/api-client";
import { usePermission } from "@/utils/permission"; import { usePermission } from "@/utils/permission";
import { useI18n } from "vue-i18n"; import { useI18n } from "vue-i18n";
import { inject } from "vue";
import type { Ref } from "vue";
import { useQueryClient } from "@tanstack/vue-query"; import { useQueryClient } from "@tanstack/vue-query";
import { useOperationItemExtensionPoint } from "@console/composables/use-operation-extension-points"; import { useOperationItemExtensionPoint } from "@console/composables/use-operation-extension-points";
import { toRefs } from "vue";
import type { OperationItem } from "@halo-dev/console-shared"; import type { OperationItem } from "@halo-dev/console-shared";
import EntityDropdownItems from "@/components/entity/EntityDropdownItems.vue"; import EntityDropdownItems from "@/components/entity/EntityDropdownItems.vue";
import { markRaw } from "vue";
const { currentUserHasPermission } = usePermission(); const { currentUserHasPermission } = usePermission();
const { t } = useI18n(); const { t } = useI18n();
@ -52,7 +49,7 @@ const selectedAttachments = inject<Ref<Set<Attachment>>>(
ref<Set<Attachment>>(new Set()) ref<Set<Attachment>>(new Set())
); );
const policyName = computed(() => { const policyDisplayName = computed(() => {
const policy = policies.value?.find( const policy = policies.value?.find(
(p) => p.metadata.name === props.attachment.spec.policyName (p) => p.metadata.name === props.attachment.spec.policyName
); );
@ -180,7 +177,7 @@ const { operationItems } = useOperationItemExtensionPoint<Attachment>(
</VEntityField> </VEntityField>
</template> </template>
<template #end> <template #end>
<VEntityField :description="policyName" /> <VEntityField :description="policyDisplayName" />
<VEntityField> <VEntityField>
<template #description> <template #description>
<RouterLink <RouterLink

View File

@ -2,16 +2,14 @@
import { VButton } from "@halo-dev/components"; import { VButton } from "@halo-dev/components";
import type { Attachment } from "@halo-dev/api-client"; import type { Attachment } from "@halo-dev/api-client";
import { useAttachmentPermalinkCopy } from "../composables/use-attachment"; import { useAttachmentPermalinkCopy } from "../composables/use-attachment";
import { toRefs, computed } from "vue"; import { computed, toRefs } from "vue";
const props = withDefaults( const props = withDefaults(
defineProps<{ defineProps<{
visible: boolean;
attachment?: Attachment; attachment?: Attachment;
mountToBody?: boolean; mountToBody?: boolean;
}>(), }>(),
{ {
visible: false,
attachment: undefined, attachment: undefined,
mountToBody: false, mountToBody: false,
} }

View File

@ -1,17 +1,17 @@
<script lang="ts" setup> <script lang="ts" setup>
import { import {
IconAddCircle,
VButton,
VModal,
VSpace,
VEmpty,
Dialog, Dialog,
VEntity, IconAddCircle,
VEntityField, Toast,
VStatusDot, VButton,
VDropdown, VDropdown,
VDropdownItem, VDropdownItem,
Toast, VEmpty,
VEntity,
VEntityField,
VModal,
VSpace,
VStatusDot,
} from "@halo-dev/components"; } from "@halo-dev/components";
import AttachmentPolicyEditingModal from "./AttachmentPolicyEditingModal.vue"; import AttachmentPolicyEditingModal from "./AttachmentPolicyEditingModal.vue";
import { ref } from "vue"; import { ref } from "vue";
@ -24,17 +24,7 @@ import {
import { apiClient } from "@/utils/api-client"; import { apiClient } from "@/utils/api-client";
import { useI18n } from "vue-i18n"; import { useI18n } from "vue-i18n";
withDefaults(
defineProps<{
visible: boolean;
}>(),
{
visible: false,
}
);
const emit = defineEmits<{ const emit = defineEmits<{
(event: "update:visible", visible: boolean): void;
(event: "close"): void; (event: "close"): void;
}>(); }>();
@ -43,36 +33,19 @@ const { t } = useI18n();
const { policies, isLoading, handleFetchPolicies } = useFetchAttachmentPolicy(); const { policies, isLoading, handleFetchPolicies } = useFetchAttachmentPolicy();
const { policyTemplates } = useFetchAttachmentPolicyTemplate(); const { policyTemplates } = useFetchAttachmentPolicyTemplate();
const modal = ref();
const selectedPolicy = ref<Policy>(); const selectedPolicy = ref<Policy>();
const selectedTemplateName = ref();
const policyEditingModal = ref(false); const policyEditingModal = ref(false);
function onVisibleChange(visible: boolean) {
emit("update:visible", visible);
if (!visible) {
emit("close");
}
}
const handleOpenEditingModal = (policy: Policy) => { const handleOpenEditingModal = (policy: Policy) => {
selectedPolicy.value = policy; selectedPolicy.value = policy;
policyEditingModal.value = true; policyEditingModal.value = true;
}; };
const handleOpenCreateNewPolicyModal = (policyTemplate: PolicyTemplate) => { const handleOpenCreateNewPolicyModal = (policyTemplate: PolicyTemplate) => {
selectedPolicy.value = { selectedTemplateName.value = policyTemplate.metadata.name;
spec: {
displayName: "",
templateName: policyTemplate.metadata.name,
configMapName: "",
},
apiVersion: "storage.halo.run/v1alpha1",
kind: "Policy",
metadata: {
name: "",
generateName: "attachment-policy-",
},
};
policyEditingModal.value = true; policyEditingModal.value = true;
}; };
@ -116,16 +89,17 @@ const handleDelete = async (policy: Policy) => {
const onEditingModalClose = () => { const onEditingModalClose = () => {
selectedPolicy.value = undefined; selectedPolicy.value = undefined;
handleFetchPolicies(); handleFetchPolicies();
policyEditingModal.value = false;
}; };
</script> </script>
<template> <template>
<VModal <VModal
:visible="visible" ref="modal"
:width="750" :width="750"
:title="$t('core.attachment.policies_modal.title')" :title="$t('core.attachment.policies_modal.title')"
:body-class="['!p-0']" :body-class="['!p-0']"
:layer-closable="true" :layer-closable="true"
@update:visible="onVisibleChange" @close="emit('close')"
> >
<template #actions> <template #actions>
<VDropdown> <VDropdown>
@ -216,16 +190,16 @@ const onEditingModalClose = () => {
</li> </li>
</ul> </ul>
<template #footer> <template #footer>
<VButton @click="onVisibleChange(false)"> <VButton @click="modal.close()">
{{ $t("core.common.buttons.close_and_shortcut") }} {{ $t("core.common.buttons.close_and_shortcut") }}
</VButton> </VButton>
</template> </template>
</VModal> </VModal>
<AttachmentPolicyEditingModal <AttachmentPolicyEditingModal
v-if="visible" v-if="policyEditingModal"
v-model:visible="policyEditingModal"
:policy="selectedPolicy" :policy="selectedPolicy"
:template-name="selectedTemplateName"
@close="onEditingModalClose" @close="onEditingModalClose"
/> />
</template> </template>

View File

@ -1,38 +1,37 @@
<script lang="ts" setup> <script lang="ts" setup>
import { Toast, VButton, VModal, VSpace } from "@halo-dev/components"; import { Toast, VButton, VLoading, VModal, VSpace } from "@halo-dev/components";
import SubmitButton from "@/components/button/SubmitButton.vue"; import SubmitButton from "@/components/button/SubmitButton.vue";
import type { Policy, PolicyTemplate } from "@halo-dev/api-client"; import type { Policy } from "@halo-dev/api-client";
import { cloneDeep } from "lodash-es"; import { cloneDeep } from "lodash-es";
import { computed, ref, toRaw, watch, watchEffect } from "vue"; import { computed, onMounted, ref, toRaw, toRefs } from "vue";
import { useSettingForm } from "@console/composables/use-setting-form"; import { useSettingFormConvert } from "@console/composables/use-setting-form";
import { apiClient } from "@/utils/api-client"; import { apiClient } from "@/utils/api-client";
import {
reset,
type FormKitSchemaCondition,
type FormKitSchemaNode,
} from "@formkit/core";
import { setFocus } from "@/formkit/utils/focus"; import { setFocus } from "@/formkit/utils/focus";
import { useI18n } from "vue-i18n"; import { useI18n } from "vue-i18n";
import { useQuery } from "@tanstack/vue-query";
const props = withDefaults( const props = withDefaults(
defineProps<{ defineProps<{
visible: boolean;
policy?: Policy; policy?: Policy;
templateName?: string;
}>(), }>(),
{ {
visible: false,
policy: undefined, policy: undefined,
templateName: undefined,
} }
); );
const { policy } = toRefs(props);
const emit = defineEmits<{ const emit = defineEmits<{
(event: "update:visible", visible: boolean): void;
(event: "close"): void; (event: "close"): void;
}>(); }>();
const { t } = useI18n(); const { t } = useI18n();
const initialFormState: Policy = { const modal = ref();
const formState = ref<Policy>({
spec: { spec: {
displayName: "", displayName: "",
templateName: "", templateName: "",
@ -44,82 +43,106 @@ const initialFormState: Policy = {
name: "", name: "",
generateName: "attachment-policy-", generateName: "attachment-policy-",
}, },
}; });
const formState = ref<Policy>(cloneDeep(initialFormState)); const isUpdateMode = !!props.policy;
const policyTemplate = ref<PolicyTemplate | undefined>();
const settingName = computed(() => policyTemplate.value?.spec?.settingName); onMounted(async () => {
if (props.policy) {
formState.value = cloneDeep(props.policy);
}
if (props.templateName) {
formState.value.spec.templateName = props.templateName;
}
const configMapName = computed({ setFocus("displayNameInput");
get() { });
return formState.value.spec.configMapName;
}, const { data: policyTemplate } = useQuery({
set(value) { queryKey: [
formState.value.spec.configMapName = value; "core:attachment:policy-template",
formState.value.spec.templateName,
],
queryFn: async () => {
const { data } =
await apiClient.extension.storage.policyTemplate.getstorageHaloRunV1alpha1PolicyTemplate(
{
name: formState.value.spec.templateName,
}
);
return data;
}, },
retry: 0,
enabled: computed(() => !!formState.value.spec.templateName),
}); });
const { const { data: setting, isLoading } = useQuery({
setting, queryKey: [
configMapFormData, "core:attachment:policy-template:setting",
configMap, policyTemplate.value?.spec?.settingName,
saving, ],
handleFetchConfigMap, queryFn: async () => {
handleFetchSettings, if (!policyTemplate.value?.spec?.settingName) {
handleSaveConfigMap, throw new Error("No setting found");
handleReset: handleResetSettingForm,
} = useSettingForm(settingName, configMapName);
const formSchema = computed(() => {
if (!setting.value) {
return undefined;
} }
const { forms } = setting.value.spec;
return forms.find((item) => item.group === "default")?.formSchema as (
| FormKitSchemaCondition
| FormKitSchemaNode
)[];
});
watchEffect(() => { const { data } = await apiClient.extension.setting.getv1alpha1Setting({
if (settingName.value) { name: policyTemplate.value.spec.settingName,
handleFetchSettings();
}
});
watchEffect(() => {
if (configMapName.value && setting.value) {
handleFetchConfigMap();
}
});
const isUpdateMode = computed(() => {
return !!formState.value.metadata.creationTimestamp;
});
const modalTitle = computed(() => {
return isUpdateMode.value
? t("core.attachment.policy_editing_modal.titles.update", {
policy: props.policy?.spec.displayName,
})
: t("core.attachment.policy_editing_modal.titles.create", {
policy_template: policyTemplate.value?.spec?.displayName,
}); });
return data;
},
retry: 0,
enabled: computed(() => !!policyTemplate.value?.spec?.settingName),
}); });
const { data: configMap } = useQuery({
queryKey: [
"core:attachment:policy-template:configMap",
policy.value?.spec.configMapName,
],
initialData: {
data: {},
apiVersion: "v1alpha1",
kind: "ConfigMap",
metadata: {
generateName: "configMap-",
name: "",
},
},
retry: 0,
queryFn: async () => {
if (!policy.value?.spec.configMapName) {
throw new Error("No configMap found");
}
const { data } = await apiClient.extension.configMap.getv1alpha1ConfigMap({
name: policy.value?.spec.configMapName,
});
return data;
},
enabled: computed(() => !!policy.value?.spec.configMapName),
});
const { configMapFormData, formSchema, convertToSave } = useSettingFormConvert(
setting,
configMap,
ref("default")
);
const submitting = ref(false);
const handleSave = async () => { const handleSave = async () => {
try { try {
saving.value = true; submitting.value = true;
if (!isUpdateMode.value) { const configMapToUpdate = convertToSave();
configMap.value.metadata.name = "";
configMap.value.metadata.generateName = "configMap-";
}
await handleSaveConfigMap(); if (isUpdateMode) {
await apiClient.extension.configMap.updatev1alpha1ConfigMap({
name: configMap.value.metadata.name,
configMap: configMapToUpdate,
});
if (isUpdateMode.value) {
await apiClient.extension.storage.policy.updatestorageHaloRunV1alpha1Policy( await apiClient.extension.storage.policy.updatestorageHaloRunV1alpha1Policy(
{ {
name: formState.value.metadata.name, name: formState.value.metadata.name,
@ -127,7 +150,12 @@ const handleSave = async () => {
} }
); );
} else { } else {
formState.value.spec.configMapName = configMap.value.metadata.name; const { data: newConfigMap } =
await apiClient.extension.configMap.createv1alpha1ConfigMap({
configMap: configMapToUpdate,
});
formState.value.spec.configMapName = newConfigMap.metadata.name;
await apiClient.extension.storage.policy.createstorageHaloRunV1alpha1Policy( await apiClient.extension.storage.policy.createstorageHaloRunV1alpha1Policy(
{ {
policy: formState.value, policy: formState.value,
@ -136,78 +164,27 @@ const handleSave = async () => {
} }
Toast.success(t("core.common.toast.save_success")); Toast.success(t("core.common.toast.save_success"));
onVisibleChange(false); modal.value.close();
} catch (e) { } catch (e) {
console.error("Failed to save attachment policy", e); console.error("Failed to save attachment policy", e);
} finally { } finally {
saving.value = false; submitting.value = false;
} }
}; };
const handleResetForm = () => { const modalTitle = props.policy
formState.value = cloneDeep(initialFormState); ? t("core.attachment.policy_editing_modal.titles.update", {
reset("attachment-policy-form"); policy: props.policy?.spec.displayName,
}; })
: t("core.attachment.policy_editing_modal.titles.create", {
watch( policy_template: policyTemplate.value?.spec?.displayName,
() => props.visible, });
(visible) => {
if (visible) {
setFocus("displayNameInput");
} else {
const timer = setTimeout(() => {
policyTemplate.value = undefined;
handleResetForm();
handleResetSettingForm();
clearTimeout(timer);
}, 100);
}
}
);
watch(
() => props.policy,
async (policy) => {
if (policy) {
formState.value = cloneDeep(policy);
const { templateName } = formState.value.spec;
// Get policy template
if (templateName) {
const { data } =
await apiClient.extension.storage.policyTemplate.getstorageHaloRunV1alpha1PolicyTemplate(
{
name: templateName,
}
);
policyTemplate.value = data;
}
} else {
setTimeout(() => {
policyTemplate.value = undefined;
handleResetForm();
handleResetSettingForm();
}, 100);
}
}
);
const onVisibleChange = (visible: boolean) => {
emit("update:visible", visible);
if (!visible) {
emit("close");
}
};
</script> </script>
<template> <template>
<VModal <VModal ref="modal" :title="modalTitle" :width="600" @close="emit('close')">
:title="modalTitle"
:visible="visible"
:width="600"
@update:visible="onVisibleChange"
>
<div> <div>
<VLoading v-if="isLoading" />
<template v-else>
<FormKit <FormKit
v-if="formSchema && configMapFormData" v-if="formSchema && configMapFormData"
id="attachment-policy-form" id="attachment-policy-form"
@ -223,7 +200,9 @@ const onVisibleChange = (visible: boolean) => {
id="displayNameInput" id="displayNameInput"
v-model="formState.spec.displayName" v-model="formState.spec.displayName"
:label=" :label="
$t('core.attachment.policy_editing_modal.fields.display_name.label') $t(
'core.attachment.policy_editing_modal.fields.display_name.label'
)
" "
type="text" type="text"
name="displayName" name="displayName"
@ -234,19 +213,19 @@ const onVisibleChange = (visible: boolean) => {
:data="configMapFormData['default']" :data="configMapFormData['default']"
/> />
</FormKit> </FormKit>
</template>
</div> </div>
<template #footer> <template #footer>
<VSpace> <VSpace>
<SubmitButton <SubmitButton
v-if="visible" :loading="submitting"
:loading="saving"
type="secondary" type="secondary"
:text="$t('core.common.buttons.submit')" :text="$t('core.common.buttons.submit')"
@submit="$formkit.submit('attachment-policy-form')" @submit="$formkit.submit('attachment-policy-form')"
> >
</SubmitButton> </SubmitButton>
<VButton @click="onVisibleChange(false)"> <VButton @click="modal.close()">
{{ $t("core.common.buttons.cancel_and_shortcut") }} {{ $t("core.common.buttons.cancel_and_shortcut") }}
</VButton> </VButton>
</VSpace> </VSpace>

View File

@ -7,7 +7,7 @@ import {
VModal, VModal,
} from "@halo-dev/components"; } from "@halo-dev/components";
import { ref, watch } from "vue"; import { ref, watch } from "vue";
import type { Policy, PolicyTemplate } from "@halo-dev/api-client"; import type { PolicyTemplate } from "@halo-dev/api-client";
import { import {
useFetchAttachmentPolicy, useFetchAttachmentPolicy,
useFetchAttachmentPolicyTemplate, useFetchAttachmentPolicyTemplate,
@ -16,17 +16,7 @@ import { useFetchAttachmentGroup } from "../composables/use-attachment-group";
import AttachmentPolicyEditingModal from "./AttachmentPolicyEditingModal.vue"; import AttachmentPolicyEditingModal from "./AttachmentPolicyEditingModal.vue";
import { useLocalStorage } from "@vueuse/core"; import { useLocalStorage } from "@vueuse/core";
const props = withDefaults(
defineProps<{
visible: boolean;
}>(),
{
visible: false,
}
);
const emit = defineEmits<{ const emit = defineEmits<{
(event: "update:visible", visible: boolean): void;
(event: "close"): void; (event: "close"): void;
}>(); }>();
@ -34,11 +24,11 @@ const { groups } = useFetchAttachmentGroup();
const { policies, handleFetchPolicies } = useFetchAttachmentPolicy(); const { policies, handleFetchPolicies } = useFetchAttachmentPolicy();
const { policyTemplates } = useFetchAttachmentPolicyTemplate(); const { policyTemplates } = useFetchAttachmentPolicyTemplate();
const modal = ref();
const selectedGroupName = useLocalStorage("attachment-upload-group", ""); const selectedGroupName = useLocalStorage("attachment-upload-group", "");
const selectedPolicyName = useLocalStorage("attachment-upload-policy", ""); const selectedPolicyName = useLocalStorage("attachment-upload-policy", "");
const policyToCreate = ref<Policy>();
const uploadVisible = ref(false);
const policyEditingModal = ref(false); const policyEditingModal = ref(false);
const policyTemplateNameToCreate = ref();
watch( watch(
() => groups.value, () => groups.value,
@ -71,57 +61,24 @@ watch(
); );
const handleOpenCreateNewPolicyModal = (policyTemplate: PolicyTemplate) => { const handleOpenCreateNewPolicyModal = (policyTemplate: PolicyTemplate) => {
policyToCreate.value = { policyTemplateNameToCreate.value = policyTemplate.metadata.name;
spec: {
displayName: "",
templateName: policyTemplate.metadata.name,
configMapName: "",
},
apiVersion: "storage.halo.run/v1alpha1",
kind: "Policy",
metadata: {
name: "",
generateName: "attachment-policy-",
},
};
policyEditingModal.value = true; policyEditingModal.value = true;
}; };
const onEditingModalClose = async () => { const onEditingModalClose = async () => {
await handleFetchPolicies(); await handleFetchPolicies();
policyToCreate.value = policies.value?.[0]; selectedPolicyName.value = policies.value?.[0].metadata.name;
};
const onVisibleChange = (visible: boolean) => {
emit("update:visible", visible);
if (!visible) {
emit("close");
policyEditingModal.value = false; policyEditingModal.value = false;
}
}; };
watch(
() => props.visible,
(newValue) => {
if (newValue) {
uploadVisible.value = true;
} else {
const uploadVisibleTimer = setTimeout(() => {
uploadVisible.value = false;
clearTimeout(uploadVisibleTimer);
}, 200);
}
}
);
</script> </script>
<template> <template>
<VModal <VModal
ref="modal"
:body-class="['!p-0']" :body-class="['!p-0']"
:visible="visible"
:width="650" :width="650"
:centered="false" :centered="false"
:title="$t('core.attachment.upload_modal.title')" :title="$t('core.attachment.upload_modal.title')"
@update:visible="onVisibleChange" @close="emit('close')"
> >
<div class="w-full p-4"> <div class="w-full p-4">
<div class="mb-2"> <div class="mb-2">
@ -213,7 +170,6 @@ watch(
/> />
</div> </div>
<UppyUpload <UppyUpload
v-if="uploadVisible"
endpoint="/apis/api.console.halo.run/v1alpha1/attachments/upload" endpoint="/apis/api.console.halo.run/v1alpha1/attachments/upload"
:disabled="!selectedPolicyName" :disabled="!selectedPolicyName"
:meta="{ :meta="{
@ -226,15 +182,14 @@ watch(
? '' ? ''
: $t('core.attachment.upload_modal.filters.policy.not_select') : $t('core.attachment.upload_modal.filters.policy.not_select')
" "
:done-button-handler="() => onVisibleChange(false)" :done-button-handler="() => modal.close()"
/> />
</div> </div>
</VModal> </VModal>
<AttachmentPolicyEditingModal <AttachmentPolicyEditingModal
v-if="visible" v-if="policyEditingModal"
v-model:visible="policyEditingModal" :template-name="policyTemplateNameToCreate"
:policy="policyToCreate"
@close="onEditingModalClose" @close="onEditingModalClose"
/> />
</template> </template>

View File

@ -1,18 +1,18 @@
<script lang="ts" setup> <script lang="ts" setup>
import { import {
IconCheckboxFill,
IconArrowLeft, IconArrowLeft,
IconArrowRight, IconArrowRight,
IconCheckboxCircle,
IconCheckboxFill,
IconEye,
IconUpload,
VButton,
VCard, VCard,
VEmpty, VEmpty,
VSpace,
VButton,
IconUpload,
VPagination, VPagination,
IconEye, VSpace,
IconCheckboxCircle,
} from "@halo-dev/components"; } from "@halo-dev/components";
import { watchEffect, ref } from "vue"; import { computed, ref, watchEffect } from "vue";
import { isImage } from "@/utils/image"; import { isImage } from "@/utils/image";
import { useAttachmentControl } from "../../composables/use-attachment"; import { useAttachmentControl } from "../../composables/use-attachment";
import LazyImage from "@/components/image/LazyImage.vue"; import LazyImage from "@/components/image/LazyImage.vue";
@ -22,7 +22,6 @@ import AttachmentUploadModal from "../AttachmentUploadModal.vue";
import AttachmentDetailModal from "../AttachmentDetailModal.vue"; import AttachmentDetailModal from "../AttachmentDetailModal.vue";
import AttachmentGroupList from "../AttachmentGroupList.vue"; import AttachmentGroupList from "../AttachmentGroupList.vue";
import { matchMediaTypes } from "@/utils/media-type"; import { matchMediaTypes } from "@/utils/media-type";
import { computed } from "vue";
const props = withDefaults( const props = withDefaults(
defineProps<{ defineProps<{
@ -44,7 +43,7 @@ const emit = defineEmits<{
(event: "change-provider", providerId: string): void; (event: "change-provider", providerId: string): void;
}>(); }>();
const selectedGroup = ref<Group>(); const selectedGroup = ref();
const page = ref(1); const page = ref(1);
const size = ref(60); const size = ref(60);
@ -61,7 +60,7 @@ const {
handleReset, handleReset,
isChecked, isChecked,
} = useAttachmentControl({ } = useAttachmentControl({
group: selectedGroup, groupName: selectedGroup,
accepts: computed(() => { accepts: computed(() => {
return props.accepts; return props.accepts;
}), }),
@ -97,13 +96,19 @@ const isDisabled = (attachment: Attachment) => {
return !isMatchMediaType; return !isMatchMediaType;
}; };
function onUploadModalClose() {
handleFetchAttachments();
uploadVisible.value = false;
}
function onGroupSelect(group: Group) {
selectedGroup.value = group.metadata.name;
handleReset();
}
</script> </script>
<template> <template>
<AttachmentGroupList <AttachmentGroupList readonly @select="onGroupSelect" />
v-model:selected-group="selectedGroup"
readonly
@select="handleReset"
/>
<div v-if="attachments?.length" class="mb-5"> <div v-if="attachments?.length" class="mb-5">
<VButton @click="uploadVisible = true"> <VButton @click="uploadVisible = true">
<template #icon> <template #icon>
@ -216,10 +221,7 @@ const isDisabled = (attachment: Attachment) => {
:size-options="[60, 120, 200]" :size-options="[60, 120, 200]"
/> />
</div> </div>
<AttachmentUploadModal <AttachmentUploadModal v-if="uploadVisible" @close="onUploadModalClose" />
v-model:visible="uploadVisible"
@close="handleFetchAttachments"
/>
<AttachmentDetailModal <AttachmentDetailModal
v-model:visible="detailVisible" v-model:visible="detailVisible"
:mount-to-body="true" :mount-to-body="true"

View File

@ -20,14 +20,15 @@ export function useFetchAttachmentGroup(): useFetchAttachmentGroupReturn {
sort: ["metadata.creationTimestamp,asc"], sort: ["metadata.creationTimestamp,asc"],
} }
); );
return data.items; return data.items;
}, },
refetchInterval(data) { refetchInterval(data) {
const deletingGroups = data?.filter( const hasDeletingGroup = data?.some(
(group) => !!group.metadata.deletionTimestamp (group) => !!group.metadata.deletionTimestamp
); );
return deletingGroups?.length ? 1000 : false; return hasDeletingGroup ? 1000 : false;
}, },
}); });

View File

@ -24,10 +24,10 @@ export function useFetchAttachmentPolicy(): useFetchAttachmentPolicyReturn {
return data.items; return data.items;
}, },
refetchInterval(data) { refetchInterval(data) {
const deletingPolicies = data?.filter( const hasDeletingPolicy = data?.some(
(policy) => !!policy.metadata.deletionTimestamp (policy) => !!policy.metadata.deletionTimestamp
); );
return deletingPolicies?.length ? 1000 : false; return hasDeletingPolicy ? 1000 : false;
}, },
}); });

View File

@ -1,6 +1,5 @@
import type { Attachment, Group, Policy } from "@halo-dev/api-client"; import type { Attachment } from "@halo-dev/api-client";
import { computed, nextTick, type Ref } from "vue"; import { computed, nextTick, type Ref, ref, watch } from "vue";
import { ref, watch } from "vue";
import { apiClient } from "@/utils/api-client"; import { apiClient } from "@/utils/api-client";
import { Dialog, Toast } from "@halo-dev/components"; import { Dialog, Toast } from "@halo-dev/components";
import { useQuery } from "@tanstack/vue-query"; import { useQuery } from "@tanstack/vue-query";
@ -27,8 +26,8 @@ interface useAttachmentControlReturn {
} }
export function useAttachmentControl(filterOptions: { export function useAttachmentControl(filterOptions: {
policy?: Ref<Policy | undefined>; policyName?: Ref<string | undefined>;
group?: Ref<Group | undefined>; groupName?: Ref<string | undefined>;
user?: Ref<string | undefined>; user?: Ref<string | undefined>;
accepts?: Ref<string[]>; accepts?: Ref<string[]>;
keyword?: Ref<string | undefined>; keyword?: Ref<string | undefined>;
@ -38,7 +37,7 @@ export function useAttachmentControl(filterOptions: {
}): useAttachmentControlReturn { }): useAttachmentControlReturn {
const { t } = useI18n(); const { t } = useI18n();
const { user, policy, group, keyword, sort, page, size, accepts } = const { user, policyName, groupName, keyword, sort, page, size, accepts } =
filterOptions; filterOptions;
const selectedAttachment = ref<Attachment>(); const selectedAttachment = ref<Attachment>();
@ -52,9 +51,9 @@ export function useAttachmentControl(filterOptions: {
const { data, isLoading, isFetching, refetch } = useQuery<Attachment[]>({ const { data, isLoading, isFetching, refetch } = useQuery<Attachment[]>({
queryKey: [ queryKey: [
"attachments", "attachments",
policy, policyName,
keyword, keyword,
group, groupName,
user, user,
accepts, accepts,
page, page,
@ -62,12 +61,12 @@ export function useAttachmentControl(filterOptions: {
sort, sort,
], ],
queryFn: async () => { queryFn: async () => {
const isUnGrouped = group?.value?.metadata.name === "ungrouped"; const isUnGrouped = groupName?.value === "ungrouped";
const fieldSelectorMap: Record<string, string | undefined> = { const fieldSelectorMap: Record<string, string | undefined> = {
"spec.policyName": policy?.value?.metadata.name, "spec.policyName": policyName?.value,
"spec.ownerName": user?.value, "spec.ownerName": user?.value,
"spec.groupName": isUnGrouped ? undefined : group?.value?.metadata.name, "spec.groupName": isUnGrouped ? undefined : groupName?.value,
}; };
const fieldSelector = Object.entries(fieldSelectorMap) const fieldSelector = Object.entries(fieldSelectorMap)
@ -95,10 +94,10 @@ export function useAttachmentControl(filterOptions: {
return data.items; return data.items;
}, },
refetchInterval(data) { refetchInterval(data) {
const deletingAttachments = data?.filter( const hasDeletingAttachment = data?.some(
(attachment) => !!attachment.metadata.deletionTimestamp (attachment) => !!attachment.metadata.deletionTimestamp
); );
return deletingAttachments?.length ? 1000 : false; return hasDeletingAttachment ? 1000 : false;
}, },
}); });