mirror of https://github.com/halo-dev/halo
feat: make attachment list item operations extendable (#4689)
#### What type of PR is this? /area console /kind feature /milestone 2.10.x #### What this PR does / why we need it: 附件管理列表项的操作按钮支持被插件扩展。 <img width="1669" alt="image" src="https://github.com/halo-dev/halo/assets/21301288/be938c07-2976-4e22-9bf3-cdfaf53896e5"> #### Which issue(s) this PR fixes: Fixes https://github.com/halo-dev/halo/issues/4667 #### Special notes for your reviewer: 需要测试附件的关于列表的已有功能是否正常。 如果需要测试扩展点是否有效,可以使用此插件测试:[plugin-s3-1.5.0-SNAPSHOT.jar.zip](https://github.com/halo-dev/halo/files/12839986/plugin-s3-1.5.0-SNAPSHOT.jar.zip) ```diff export default definePlugin({ components: {}, routes: [], extensionPoints: { "plugin:self:tabs:create": (): PluginTab[] => { return [ { id: "s3-link", label: "关联S3文件", component: markRaw(HomeView), permissions: [], }, ]; }, + "attachment:list-item:operation:create": (attachment: Ref<Attachment>) => { + return [ + { + priority: 21, + component: markRaw(VDropdownDivider), + }, + { + priority: 22, + component: markRaw(VDropdownItem), + props: { + type: "danger", + }, + label: "解除 S3 关联", + permissions: ["system:attachments:manage"], + action: () => { + console.log(attachment); + }, + }, + ]; + }, }, }); ``` #### Does this PR introduce a user-facing change? ```release-note Console 附件管理列表项的操作按钮支持被插件扩展。 ```pull/4694/head
parent
815f6b82c5
commit
da021658c8
|
@ -12,6 +12,7 @@
|
||||||
- 插件:`"plugin:list-item:operation:create"?: (plugin: Ref<Plugin>) => | OperationItem<Plugin>[] | Promise<OperationItem<Plugin>[]>`
|
- 插件:`"plugin:list-item:operation:create"?: (plugin: Ref<Plugin>) => | OperationItem<Plugin>[] | Promise<OperationItem<Plugin>[]>`
|
||||||
- 备份:`"backup:list-item:operation:create"?: (backup: Ref<Backup>) => | OperationItem<Backup>[] | Promise<OperationItem<Backup>[]>`
|
- 备份:`"backup:list-item:operation:create"?: (backup: Ref<Backup>) => | OperationItem<Backup>[] | Promise<OperationItem<Backup>[]>`
|
||||||
- 主题:`"theme:list-item:operation:create"?: (theme: Ref<Theme>) => | OperationItem<Theme>[] | Promise<OperationItem<Theme>[]>`
|
- 主题:`"theme:list-item:operation:create"?: (theme: Ref<Theme>) => | OperationItem<Theme>[] | Promise<OperationItem<Theme>[]>`
|
||||||
|
- 附件:`"attachment:list-item:operation:create"?: (attachment: Ref<Attachment>) => | OperationItem<Attachment>[] | Promise<OperationItem<Attachment>[]>`
|
||||||
|
|
||||||
示例:
|
示例:
|
||||||
|
|
||||||
|
|
|
@ -10,7 +10,13 @@ import type { PluginInstallationTab } from "@/states/plugin-installation-tabs";
|
||||||
import type { EntityFieldItem } from "@/states/entity";
|
import type { EntityFieldItem } from "@/states/entity";
|
||||||
import type { OperationItem } from "@/states/operation";
|
import type { OperationItem } from "@/states/operation";
|
||||||
import type { ThemeListTab } from "@/states/theme-list-tabs";
|
import type { ThemeListTab } from "@/states/theme-list-tabs";
|
||||||
import type { Backup, ListedPost, Plugin, Theme } from "@halo-dev/api-client";
|
import type {
|
||||||
|
Attachment,
|
||||||
|
Backup,
|
||||||
|
ListedPost,
|
||||||
|
Plugin,
|
||||||
|
Theme,
|
||||||
|
} from "@halo-dev/api-client";
|
||||||
|
|
||||||
export interface RouteRecordAppend {
|
export interface RouteRecordAppend {
|
||||||
parentName: RouteRecordName;
|
parentName: RouteRecordName;
|
||||||
|
@ -53,6 +59,10 @@ export interface ExtensionPoint {
|
||||||
backup: Ref<Backup>
|
backup: Ref<Backup>
|
||||||
) => OperationItem<Backup>[] | Promise<OperationItem<Backup>[]>;
|
) => OperationItem<Backup>[] | Promise<OperationItem<Backup>[]>;
|
||||||
|
|
||||||
|
"attachment:list-item:operation:create"?: (
|
||||||
|
attachment: Ref<Attachment>
|
||||||
|
) => OperationItem<Attachment>[] | Promise<OperationItem<Attachment>[]>;
|
||||||
|
|
||||||
"plugin:list-item:field:create"?: (
|
"plugin:list-item:field:create"?: (
|
||||||
plugin: Ref<Plugin>
|
plugin: Ref<Plugin>
|
||||||
) => EntityFieldItem[] | Promise<EntityFieldItem[]>;
|
) => EntityFieldItem[] | Promise<EntityFieldItem[]>;
|
||||||
|
|
|
@ -15,9 +15,6 @@ import {
|
||||||
VSpace,
|
VSpace,
|
||||||
VEmpty,
|
VEmpty,
|
||||||
IconFolder,
|
IconFolder,
|
||||||
VStatusDot,
|
|
||||||
VEntity,
|
|
||||||
VEntityField,
|
|
||||||
VLoading,
|
VLoading,
|
||||||
Toast,
|
Toast,
|
||||||
VDropdown,
|
VDropdown,
|
||||||
|
@ -30,8 +27,6 @@ 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 { computed, onMounted, ref, watch } from "vue";
|
||||||
import type { Attachment, Group } from "@halo-dev/api-client";
|
import type { Attachment, Group } from "@halo-dev/api-client";
|
||||||
import { formatDatetime } from "@/utils/date";
|
|
||||||
import prettyBytes from "pretty-bytes";
|
|
||||||
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";
|
||||||
import { apiClient } from "@/utils/api-client";
|
import { apiClient } from "@/utils/api-client";
|
||||||
|
@ -39,12 +34,13 @@ import cloneDeep from "lodash.clonedeep";
|
||||||
import { isImage } from "@/utils/image";
|
import { isImage } from "@/utils/image";
|
||||||
import { useRouteQuery } from "@vueuse/router";
|
import { useRouteQuery } from "@vueuse/router";
|
||||||
import { useFetchAttachmentGroup } from "./composables/use-attachment-group";
|
import { useFetchAttachmentGroup } from "./composables/use-attachment-group";
|
||||||
import { usePermission } from "@/utils/permission";
|
|
||||||
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";
|
||||||
|
|
||||||
const { currentUserHasPermission } = usePermission();
|
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
|
|
||||||
const policyVisible = ref(false);
|
const policyVisible = ref(false);
|
||||||
|
@ -101,7 +97,6 @@ const {
|
||||||
handleFetchAttachments,
|
handleFetchAttachments,
|
||||||
handleSelectNext,
|
handleSelectNext,
|
||||||
handleSelectPrevious,
|
handleSelectPrevious,
|
||||||
handleDelete,
|
|
||||||
handleDeleteInBatch,
|
handleDeleteInBatch,
|
||||||
handleCheckAll,
|
handleCheckAll,
|
||||||
handleSelect,
|
handleSelect,
|
||||||
|
@ -121,6 +116,8 @@ const {
|
||||||
size: size,
|
size: size,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
provide<Ref<Set<Attachment>>>("selectedAttachments", selectedAttachments);
|
||||||
|
|
||||||
const handleMove = async (group: Group) => {
|
const handleMove = async (group: Group) => {
|
||||||
try {
|
try {
|
||||||
const promises = Array.from(selectedAttachments.value).map((attachment) => {
|
const promises = Array.from(selectedAttachments.value).map((attachment) => {
|
||||||
|
@ -177,11 +174,6 @@ const onUploadModalClose = () => {
|
||||||
handleFetchAttachments();
|
handleFetchAttachments();
|
||||||
};
|
};
|
||||||
|
|
||||||
const getPolicyName = (name: string | undefined) => {
|
|
||||||
const policy = policies.value?.find((p) => p.metadata.name === name);
|
|
||||||
return policy?.spec.displayName;
|
|
||||||
};
|
|
||||||
|
|
||||||
// View type
|
// View type
|
||||||
const viewTypes = [
|
const viewTypes = [
|
||||||
{
|
{
|
||||||
|
@ -468,8 +460,8 @@ onMounted(() => {
|
||||||
role="list"
|
role="list"
|
||||||
>
|
>
|
||||||
<VCard
|
<VCard
|
||||||
v-for="(attachment, index) in attachments"
|
v-for="attachment in attachments"
|
||||||
:key="index"
|
:key="attachment.metadata.name"
|
||||||
:body-class="['!p-0']"
|
:body-class="['!p-0']"
|
||||||
:class="{
|
:class="{
|
||||||
'ring-1 ring-primary': isChecked(attachment),
|
'ring-1 ring-primary': isChecked(attachment),
|
||||||
|
@ -552,118 +544,16 @@ onMounted(() => {
|
||||||
class="box-border h-full w-full divide-y divide-gray-100"
|
class="box-border h-full w-full divide-y divide-gray-100"
|
||||||
role="list"
|
role="list"
|
||||||
>
|
>
|
||||||
<li v-for="(attachment, index) in attachments" :key="index">
|
<li
|
||||||
<VEntity :is-selected="isChecked(attachment)">
|
v-for="attachment in attachments"
|
||||||
<template
|
:key="attachment.metadata.name"
|
||||||
v-if="
|
>
|
||||||
currentUserHasPermission(['system:attachments:manage'])
|
<AttachmentListItem
|
||||||
"
|
:attachment="attachment"
|
||||||
#checkbox
|
:is-selected="isChecked(attachment)"
|
||||||
>
|
@select="handleSelect"
|
||||||
<input
|
@open-detail="handleClickItem"
|
||||||
:checked="selectedAttachments.has(attachment)"
|
/>
|
||||||
class="h-4 w-4 rounded border-gray-300 text-indigo-600"
|
|
||||||
type="checkbox"
|
|
||||||
@click="handleSelect(attachment)"
|
|
||||||
/>
|
|
||||||
</template>
|
|
||||||
<template #start>
|
|
||||||
<VEntityField>
|
|
||||||
<template #description>
|
|
||||||
<div
|
|
||||||
class="h-10 w-10 rounded border bg-white p-1 hover:shadow-sm"
|
|
||||||
>
|
|
||||||
<AttachmentFileTypeIcon
|
|
||||||
:display-ext="false"
|
|
||||||
:file-name="attachment.spec.displayName"
|
|
||||||
:width="8"
|
|
||||||
:height="8"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
</VEntityField>
|
|
||||||
<VEntityField
|
|
||||||
:title="attachment.spec.displayName"
|
|
||||||
@click="handleClickItem(attachment)"
|
|
||||||
>
|
|
||||||
<template #description>
|
|
||||||
<VSpace>
|
|
||||||
<span class="text-xs text-gray-500">
|
|
||||||
{{ attachment.spec.mediaType }}
|
|
||||||
</span>
|
|
||||||
<span class="text-xs text-gray-500">
|
|
||||||
{{ prettyBytes(attachment.spec.size || 0) }}
|
|
||||||
</span>
|
|
||||||
</VSpace>
|
|
||||||
</template>
|
|
||||||
</VEntityField>
|
|
||||||
</template>
|
|
||||||
<template #end>
|
|
||||||
<VEntityField
|
|
||||||
:description="getPolicyName(attachment.spec.policyName)"
|
|
||||||
/>
|
|
||||||
<VEntityField>
|
|
||||||
<template #description>
|
|
||||||
<RouterLink
|
|
||||||
:to="{
|
|
||||||
name: 'UserDetail',
|
|
||||||
params: {
|
|
||||||
name: attachment.spec.ownerName,
|
|
||||||
},
|
|
||||||
}"
|
|
||||||
class="text-xs text-gray-500"
|
|
||||||
:class="{
|
|
||||||
'pointer-events-none': !currentUserHasPermission([
|
|
||||||
'system:users:view',
|
|
||||||
]),
|
|
||||||
}"
|
|
||||||
>
|
|
||||||
{{ attachment.spec.ownerName }}
|
|
||||||
</RouterLink>
|
|
||||||
</template>
|
|
||||||
</VEntityField>
|
|
||||||
<VEntityField
|
|
||||||
v-if="attachment.metadata.deletionTimestamp"
|
|
||||||
>
|
|
||||||
<template #description>
|
|
||||||
<VStatusDot
|
|
||||||
v-tooltip="$t('core.common.status.deleting')"
|
|
||||||
state="warning"
|
|
||||||
animate
|
|
||||||
/>
|
|
||||||
</template>
|
|
||||||
</VEntityField>
|
|
||||||
<VEntityField>
|
|
||||||
<template #description>
|
|
||||||
<span
|
|
||||||
class="truncate text-xs tabular-nums text-gray-500"
|
|
||||||
>
|
|
||||||
{{
|
|
||||||
formatDatetime(
|
|
||||||
attachment.metadata.creationTimestamp
|
|
||||||
)
|
|
||||||
}}
|
|
||||||
</span>
|
|
||||||
</template>
|
|
||||||
</VEntityField>
|
|
||||||
</template>
|
|
||||||
<template #dropdownItems>
|
|
||||||
<VDropdownItem @click="handleClickItem(attachment)">
|
|
||||||
{{ $t("core.common.buttons.detail") }}
|
|
||||||
</VDropdownItem>
|
|
||||||
<VDropdownItem
|
|
||||||
v-if="
|
|
||||||
currentUserHasPermission([
|
|
||||||
'system:attachments:manage',
|
|
||||||
])
|
|
||||||
"
|
|
||||||
type="danger"
|
|
||||||
@click="handleDelete(attachment)"
|
|
||||||
>
|
|
||||||
{{ $t("core.common.buttons.delete") }}
|
|
||||||
</VDropdownItem>
|
|
||||||
</template>
|
|
||||||
</VEntity>
|
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
</Transition>
|
</Transition>
|
||||||
|
|
|
@ -0,0 +1,205 @@
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import {
|
||||||
|
VSpace,
|
||||||
|
VStatusDot,
|
||||||
|
VEntity,
|
||||||
|
VEntityField,
|
||||||
|
Toast,
|
||||||
|
VDropdownItem,
|
||||||
|
Dialog,
|
||||||
|
} from "@halo-dev/components";
|
||||||
|
import { computed, ref } from "vue";
|
||||||
|
import type { Attachment } from "@halo-dev/api-client";
|
||||||
|
import { formatDatetime } from "@/utils/date";
|
||||||
|
import prettyBytes from "pretty-bytes";
|
||||||
|
import { useFetchAttachmentPolicy } from "../composables/use-attachment-policy";
|
||||||
|
import { apiClient } from "@/utils/api-client";
|
||||||
|
import { usePermission } from "@/utils/permission";
|
||||||
|
import { useI18n } from "vue-i18n";
|
||||||
|
import { inject } from "vue";
|
||||||
|
import type { Ref } from "vue";
|
||||||
|
import { useQueryClient } from "@tanstack/vue-query";
|
||||||
|
import { useOperationItemExtensionPoint } from "@/composables/use-operation-extension-points";
|
||||||
|
import { toRefs } from "vue";
|
||||||
|
import type { OperationItem } from "@halo-dev/console-shared";
|
||||||
|
import EntityDropdownItems from "@/components/entity/EntityDropdownItems.vue";
|
||||||
|
import { markRaw } from "vue";
|
||||||
|
|
||||||
|
const { currentUserHasPermission } = usePermission();
|
||||||
|
const { t } = useI18n();
|
||||||
|
const queryClient = useQueryClient();
|
||||||
|
|
||||||
|
const props = withDefaults(
|
||||||
|
defineProps<{
|
||||||
|
attachment: Attachment;
|
||||||
|
isSelected?: boolean;
|
||||||
|
}>(),
|
||||||
|
{ isSelected: false }
|
||||||
|
);
|
||||||
|
|
||||||
|
const { attachment } = toRefs(props);
|
||||||
|
|
||||||
|
const { policies } = useFetchAttachmentPolicy();
|
||||||
|
|
||||||
|
const emit = defineEmits<{
|
||||||
|
(event: "select", attachment?: Attachment): void;
|
||||||
|
(event: "open-detail", attachment: Attachment): void;
|
||||||
|
}>();
|
||||||
|
|
||||||
|
const selectedAttachments = inject<Ref<Set<Attachment>>>(
|
||||||
|
"selectedAttachments",
|
||||||
|
ref<Set<Attachment>>(new Set())
|
||||||
|
);
|
||||||
|
|
||||||
|
const policyName = computed(() => {
|
||||||
|
const policy = policies.value?.find(
|
||||||
|
(p) => p.metadata.name === props.attachment.spec.policyName
|
||||||
|
);
|
||||||
|
return policy?.spec.displayName;
|
||||||
|
});
|
||||||
|
|
||||||
|
const handleDelete = () => {
|
||||||
|
Dialog.warning({
|
||||||
|
title: t("core.attachment.operations.delete.title"),
|
||||||
|
description: t("core.common.dialog.descriptions.cannot_be_recovered"),
|
||||||
|
confirmType: "danger",
|
||||||
|
confirmText: t("core.common.buttons.confirm"),
|
||||||
|
cancelText: t("core.common.buttons.cancel"),
|
||||||
|
onConfirm: async () => {
|
||||||
|
try {
|
||||||
|
await apiClient.extension.storage.attachment.deletestorageHaloRunV1alpha1Attachment(
|
||||||
|
{
|
||||||
|
name: props.attachment.metadata.name,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
selectedAttachments.value.delete(props.attachment);
|
||||||
|
|
||||||
|
Toast.success(t("core.common.toast.delete_success"));
|
||||||
|
} catch (e) {
|
||||||
|
console.error("Failed to delete attachment", e);
|
||||||
|
} finally {
|
||||||
|
queryClient.invalidateQueries({ queryKey: ["attachments"] });
|
||||||
|
}
|
||||||
|
},
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const { operationItems } = useOperationItemExtensionPoint<Attachment>(
|
||||||
|
"attachment:list-item:operation:create",
|
||||||
|
attachment,
|
||||||
|
computed((): OperationItem<Attachment>[] => [
|
||||||
|
{
|
||||||
|
priority: 10,
|
||||||
|
component: markRaw(VDropdownItem),
|
||||||
|
label: t("core.common.buttons.detail"),
|
||||||
|
permissions: [],
|
||||||
|
action: () => {
|
||||||
|
emit("open-detail", attachment.value);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
priority: 20,
|
||||||
|
component: markRaw(VDropdownItem),
|
||||||
|
props: {
|
||||||
|
type: "danger",
|
||||||
|
},
|
||||||
|
label: t("core.common.buttons.delete"),
|
||||||
|
permissions: ["system:attachments:manage"],
|
||||||
|
action: () => {
|
||||||
|
handleDelete();
|
||||||
|
},
|
||||||
|
},
|
||||||
|
])
|
||||||
|
);
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<VEntity :is-selected="isSelected">
|
||||||
|
<template
|
||||||
|
v-if="currentUserHasPermission(['system:attachments:manage'])"
|
||||||
|
#checkbox
|
||||||
|
>
|
||||||
|
<input
|
||||||
|
:checked="selectedAttachments.has(attachment)"
|
||||||
|
class="h-4 w-4 rounded border-gray-300 text-indigo-600"
|
||||||
|
type="checkbox"
|
||||||
|
@click="emit('select', attachment)"
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
|
<template #start>
|
||||||
|
<VEntityField>
|
||||||
|
<template #description>
|
||||||
|
<div class="h-10 w-10 rounded border bg-white p-1 hover:shadow-sm">
|
||||||
|
<AttachmentFileTypeIcon
|
||||||
|
:display-ext="false"
|
||||||
|
:file-name="attachment.spec.displayName"
|
||||||
|
:width="8"
|
||||||
|
:height="8"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</VEntityField>
|
||||||
|
<VEntityField
|
||||||
|
:title="attachment.spec.displayName"
|
||||||
|
@click="emit('open-detail', attachment)"
|
||||||
|
>
|
||||||
|
<template #description>
|
||||||
|
<VSpace>
|
||||||
|
<span class="text-xs text-gray-500">
|
||||||
|
{{ attachment.spec.mediaType }}
|
||||||
|
</span>
|
||||||
|
<span class="text-xs text-gray-500">
|
||||||
|
{{ prettyBytes(attachment.spec.size || 0) }}
|
||||||
|
</span>
|
||||||
|
</VSpace>
|
||||||
|
</template>
|
||||||
|
</VEntityField>
|
||||||
|
</template>
|
||||||
|
<template #end>
|
||||||
|
<VEntityField :description="policyName" />
|
||||||
|
<VEntityField>
|
||||||
|
<template #description>
|
||||||
|
<RouterLink
|
||||||
|
:to="{
|
||||||
|
name: 'UserDetail',
|
||||||
|
params: {
|
||||||
|
name: attachment.spec.ownerName,
|
||||||
|
},
|
||||||
|
}"
|
||||||
|
class="text-xs text-gray-500"
|
||||||
|
:class="{
|
||||||
|
'pointer-events-none': !currentUserHasPermission([
|
||||||
|
'system:users:view',
|
||||||
|
]),
|
||||||
|
}"
|
||||||
|
>
|
||||||
|
{{ attachment.spec.ownerName }}
|
||||||
|
</RouterLink>
|
||||||
|
</template>
|
||||||
|
</VEntityField>
|
||||||
|
<VEntityField v-if="attachment.metadata.deletionTimestamp">
|
||||||
|
<template #description>
|
||||||
|
<VStatusDot
|
||||||
|
v-tooltip="$t('core.common.status.deleting')"
|
||||||
|
state="warning"
|
||||||
|
animate
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
|
</VEntityField>
|
||||||
|
<VEntityField>
|
||||||
|
<template #description>
|
||||||
|
<span class="truncate text-xs tabular-nums text-gray-500">
|
||||||
|
{{ formatDatetime(attachment.metadata.creationTimestamp) }}
|
||||||
|
</span>
|
||||||
|
</template>
|
||||||
|
</VEntityField>
|
||||||
|
</template>
|
||||||
|
<template #dropdownItems>
|
||||||
|
<EntityDropdownItems
|
||||||
|
:dropdown-items="operationItems"
|
||||||
|
:item="attachment"
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
|
</VEntity>
|
||||||
|
</template>
|
|
@ -21,7 +21,6 @@ interface useAttachmentControlReturn {
|
||||||
handleFetchAttachments: () => void;
|
handleFetchAttachments: () => void;
|
||||||
handleSelectPrevious: () => void;
|
handleSelectPrevious: () => void;
|
||||||
handleSelectNext: () => void;
|
handleSelectNext: () => void;
|
||||||
handleDelete: (attachment: Attachment) => void;
|
|
||||||
handleDeleteInBatch: () => void;
|
handleDeleteInBatch: () => void;
|
||||||
handleCheckAll: (checkAll: boolean) => void;
|
handleCheckAll: (checkAll: boolean) => void;
|
||||||
handleSelect: (attachment: Attachment | undefined) => void;
|
handleSelect: (attachment: Attachment | undefined) => void;
|
||||||
|
@ -128,37 +127,6 @@ export function useAttachmentControl(filterOptions: {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleDelete = (attachment: Attachment) => {
|
|
||||||
Dialog.warning({
|
|
||||||
title: t("core.attachment.operations.delete.title"),
|
|
||||||
description: t("core.common.dialog.descriptions.cannot_be_recovered"),
|
|
||||||
confirmType: "danger",
|
|
||||||
confirmText: t("core.common.buttons.confirm"),
|
|
||||||
cancelText: t("core.common.buttons.cancel"),
|
|
||||||
onConfirm: async () => {
|
|
||||||
try {
|
|
||||||
await apiClient.extension.storage.attachment.deletestorageHaloRunV1alpha1Attachment(
|
|
||||||
{
|
|
||||||
name: attachment.metadata.name,
|
|
||||||
}
|
|
||||||
);
|
|
||||||
if (
|
|
||||||
selectedAttachment.value?.metadata.name === attachment.metadata.name
|
|
||||||
) {
|
|
||||||
selectedAttachment.value = undefined;
|
|
||||||
}
|
|
||||||
selectedAttachments.value.delete(attachment);
|
|
||||||
|
|
||||||
Toast.success(t("core.common.toast.delete_success"));
|
|
||||||
} catch (e) {
|
|
||||||
console.error("Failed to delete attachment", e);
|
|
||||||
} finally {
|
|
||||||
await refetch();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleDeleteInBatch = () => {
|
const handleDeleteInBatch = () => {
|
||||||
Dialog.warning({
|
Dialog.warning({
|
||||||
title: t("core.attachment.operations.delete_in_batch.title"),
|
title: t("core.attachment.operations.delete_in_batch.title"),
|
||||||
|
@ -243,7 +211,6 @@ export function useAttachmentControl(filterOptions: {
|
||||||
handleFetchAttachments: refetch,
|
handleFetchAttachments: refetch,
|
||||||
handleSelectPrevious,
|
handleSelectPrevious,
|
||||||
handleSelectNext,
|
handleSelectNext,
|
||||||
handleDelete,
|
|
||||||
handleDeleteInBatch,
|
handleDeleteInBatch,
|
||||||
handleCheckAll,
|
handleCheckAll,
|
||||||
handleSelect,
|
handleSelect,
|
||||||
|
|
Loading…
Reference in New Issue