2022-05-12 07:28:21 +00:00
|
|
|
<script lang="ts" setup>
|
2024-05-27 08:30:57 +00:00
|
|
|
import UserFilterDropdown from "@/components/filter/UserFilterDropdown.vue";
|
|
|
|
import LazyImage from "@/components/image/LazyImage.vue";
|
|
|
|
import { isImage } from "@/utils/image";
|
|
|
|
import type { Attachment, Group } from "@halo-dev/api-client";
|
2024-06-26 04:26:49 +00:00
|
|
|
import { coreApiClient } from "@halo-dev/api-client";
|
2022-05-24 10:05:05 +00:00
|
|
|
import {
|
2022-09-04 17:06:11 +00:00
|
|
|
IconArrowLeft,
|
|
|
|
IconArrowRight,
|
2022-05-26 06:21:31 +00:00
|
|
|
IconCheckboxFill,
|
2022-08-12 08:15:08 +00:00
|
|
|
IconDatabase2Line,
|
2024-05-23 02:54:49 +00:00
|
|
|
IconFolder,
|
2022-05-25 07:47:03 +00:00
|
|
|
IconGrid,
|
|
|
|
IconList,
|
2022-10-24 03:18:16 +00:00
|
|
|
IconRefreshLine,
|
2024-05-23 02:54:49 +00:00
|
|
|
IconUpload,
|
|
|
|
Toast,
|
2022-06-14 07:56:55 +00:00
|
|
|
VButton,
|
|
|
|
VCard,
|
2024-05-23 02:54:49 +00:00
|
|
|
VDropdown,
|
|
|
|
VDropdownItem,
|
|
|
|
VEmpty,
|
|
|
|
VLoading,
|
2022-06-14 07:56:55 +00:00
|
|
|
VPageHeader,
|
2022-07-11 10:16:45 +00:00
|
|
|
VPagination,
|
2022-06-14 07:56:55 +00:00
|
|
|
VSpace,
|
|
|
|
} from "@halo-dev/components";
|
2024-05-27 08:30:57 +00:00
|
|
|
import { useLocalStorage } from "@vueuse/core";
|
|
|
|
import { useRouteQuery } from "@vueuse/router";
|
2024-05-23 02:54:49 +00:00
|
|
|
import type { Ref } from "vue";
|
|
|
|
import { computed, onMounted, provide, ref, watch } from "vue";
|
2023-03-23 08:54:33 +00:00
|
|
|
import { useI18n } from "vue-i18n";
|
2024-05-27 08:30:57 +00:00
|
|
|
import AttachmentDetailModal from "./components/AttachmentDetailModal.vue";
|
|
|
|
import AttachmentGroupList from "./components/AttachmentGroupList.vue";
|
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 附件管理列表项的操作按钮支持被插件扩展。
```
2023-10-08 09:58:37 +00:00
|
|
|
import AttachmentListItem from "./components/AttachmentListItem.vue";
|
2024-05-27 08:30:57 +00:00
|
|
|
import AttachmentPoliciesModal from "./components/AttachmentPoliciesModal.vue";
|
|
|
|
import AttachmentUploadModal from "./components/AttachmentUploadModal.vue";
|
2024-07-10 02:13:24 +00:00
|
|
|
import AttachmentLoading from "./components/AttachmentLoading.vue";
|
|
|
|
import AttachmentError from "./components/AttachmentError.vue";
|
2024-05-27 08:30:57 +00:00
|
|
|
import { useAttachmentControl } from "./composables/use-attachment";
|
|
|
|
import { useFetchAttachmentGroup } from "./composables/use-attachment-group";
|
|
|
|
import { useFetchAttachmentPolicy } from "./composables/use-attachment-policy";
|
2024-07-10 02:13:24 +00:00
|
|
|
import LazyVideo from "@/components/video/LazyVideo.vue";
|
2022-09-30 09:48:19 +00:00
|
|
|
|
2023-03-23 08:54:33 +00:00
|
|
|
const { t } = useI18n();
|
2022-05-17 13:51:19 +00:00
|
|
|
|
2022-09-04 17:06:11 +00:00
|
|
|
const policyVisible = ref(false);
|
|
|
|
const uploadVisible = ref(false);
|
|
|
|
const detailVisible = ref(false);
|
|
|
|
|
2023-02-23 09:08:12 +00:00
|
|
|
const { policies } = useFetchAttachmentPolicy();
|
2024-05-27 08:30:57 +00:00
|
|
|
const { groups } = useFetchAttachmentGroup();
|
2022-09-04 17:06:11 +00:00
|
|
|
|
2024-05-23 02:54:49 +00:00
|
|
|
const selectedGroup = useRouteQuery<string | undefined>("group");
|
2022-09-04 17:06:11 +00:00
|
|
|
|
|
|
|
// Filter
|
2023-07-21 03:50:14 +00:00
|
|
|
const keyword = useRouteQuery<string>("keyword", "");
|
|
|
|
const page = useRouteQuery<number>("page", 1, {
|
|
|
|
transform: Number,
|
|
|
|
});
|
|
|
|
const size = useRouteQuery<number>("size", 60, {
|
|
|
|
transform: Number,
|
|
|
|
});
|
|
|
|
const selectedPolicy = useRouteQuery<string | undefined>("policy");
|
|
|
|
const selectedUser = useRouteQuery<string | undefined>("user");
|
|
|
|
const selectedSort = useRouteQuery<string | undefined>("sort");
|
2024-05-16 02:32:35 +00:00
|
|
|
const selectedAccepts = useRouteQuery<string | undefined>("accepts");
|
2022-09-04 17:06:11 +00:00
|
|
|
|
2023-07-13 03:31:17 +00:00
|
|
|
watch(
|
|
|
|
() => [
|
|
|
|
selectedPolicy.value,
|
|
|
|
selectedUser.value,
|
|
|
|
selectedSort.value,
|
2024-05-16 02:32:35 +00:00
|
|
|
selectedAccepts.value,
|
2023-07-13 03:31:17 +00:00
|
|
|
keyword.value,
|
|
|
|
],
|
|
|
|
() => {
|
|
|
|
page.value = 1;
|
2022-11-23 04:59:28 +00:00
|
|
|
}
|
2023-07-13 03:31:17 +00:00
|
|
|
);
|
2022-11-23 04:59:28 +00:00
|
|
|
|
|
|
|
const hasFilters = computed(() => {
|
2024-05-16 02:32:35 +00:00
|
|
|
return (
|
|
|
|
selectedPolicy.value ||
|
|
|
|
selectedUser.value ||
|
|
|
|
selectedSort.value ||
|
|
|
|
selectedAccepts.value
|
|
|
|
);
|
2022-11-23 04:59:28 +00:00
|
|
|
});
|
|
|
|
|
|
|
|
function handleClearFilters() {
|
|
|
|
selectedPolicy.value = undefined;
|
|
|
|
selectedUser.value = undefined;
|
2023-07-13 03:31:17 +00:00
|
|
|
selectedSort.value = undefined;
|
2024-05-16 02:32:35 +00:00
|
|
|
selectedAccepts.value = undefined;
|
2022-11-17 02:50:22 +00:00
|
|
|
}
|
|
|
|
|
2022-09-04 17:06:11 +00:00
|
|
|
const {
|
|
|
|
attachments,
|
|
|
|
selectedAttachment,
|
|
|
|
selectedAttachments,
|
|
|
|
checkedAll,
|
2023-02-23 09:08:12 +00:00
|
|
|
isLoading,
|
|
|
|
isFetching,
|
|
|
|
total,
|
2022-09-04 17:06:11 +00:00
|
|
|
handleFetchAttachments,
|
|
|
|
handleSelectNext,
|
|
|
|
handleSelectPrevious,
|
|
|
|
handleDeleteInBatch,
|
|
|
|
handleCheckAll,
|
|
|
|
handleSelect,
|
|
|
|
isChecked,
|
|
|
|
handleReset,
|
|
|
|
} = useAttachmentControl({
|
2024-05-23 02:54:49 +00:00
|
|
|
groupName: selectedGroup,
|
|
|
|
policyName: selectedPolicy,
|
2022-09-04 17:06:11 +00:00
|
|
|
user: selectedUser,
|
2024-05-16 02:32:35 +00:00
|
|
|
accepts: computed(() => {
|
|
|
|
if (!selectedAccepts.value) {
|
|
|
|
return [];
|
|
|
|
}
|
|
|
|
return selectedAccepts.value.split(",");
|
|
|
|
}),
|
2022-09-04 17:06:11 +00:00
|
|
|
keyword: keyword,
|
2023-07-13 03:31:17 +00:00
|
|
|
sort: selectedSort,
|
2023-02-23 09:08:12 +00:00
|
|
|
page: page,
|
|
|
|
size: size,
|
2022-09-04 17:06:11 +00:00
|
|
|
});
|
|
|
|
|
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 附件管理列表项的操作按钮支持被插件扩展。
```
2023-10-08 09:58:37 +00:00
|
|
|
provide<Ref<Set<Attachment>>>("selectedAttachments", selectedAttachments);
|
|
|
|
|
2022-09-04 17:06:11 +00:00
|
|
|
const handleMove = async (group: Group) => {
|
|
|
|
try {
|
|
|
|
const promises = Array.from(selectedAttachments.value).map((attachment) => {
|
2024-06-25 04:31:44 +00:00
|
|
|
return coreApiClient.storage.attachment.patchAttachment({
|
|
|
|
name: attachment.metadata.name,
|
|
|
|
jsonPatchInner: [
|
|
|
|
{
|
|
|
|
op: "add",
|
|
|
|
path: "/spec/groupName",
|
|
|
|
value: group.metadata.name,
|
|
|
|
},
|
|
|
|
],
|
|
|
|
});
|
2022-09-04 17:06:11 +00:00
|
|
|
});
|
|
|
|
|
|
|
|
await Promise.all(promises);
|
|
|
|
selectedAttachments.value.clear();
|
2022-12-20 11:04:29 +00:00
|
|
|
|
2023-03-23 08:54:33 +00:00
|
|
|
Toast.success(t("core.attachment.operations.move.toast_success"));
|
2022-09-04 17:06:11 +00:00
|
|
|
} catch (e) {
|
|
|
|
console.error(e);
|
|
|
|
} finally {
|
|
|
|
handleFetchAttachments();
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
const handleClickItem = (attachment: Attachment) => {
|
|
|
|
if (attachment.metadata.deletionTimestamp) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (selectedAttachments.value.size > 0) {
|
|
|
|
handleSelect(attachment);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
selectedAttachment.value = attachment;
|
|
|
|
selectedAttachments.value.clear();
|
|
|
|
detailVisible.value = true;
|
|
|
|
};
|
|
|
|
|
|
|
|
const handleCheckAllChange = (e: Event) => {
|
|
|
|
const { checked } = e.target as HTMLInputElement;
|
|
|
|
handleCheckAll(checked);
|
|
|
|
};
|
|
|
|
|
|
|
|
const onDetailModalClose = () => {
|
|
|
|
selectedAttachment.value = undefined;
|
2022-09-28 06:50:16 +00:00
|
|
|
nameQuery.value = undefined;
|
|
|
|
nameQueryAttachment.value = undefined;
|
2024-04-12 09:46:07 +00:00
|
|
|
detailVisible.value = false;
|
2023-02-23 09:08:12 +00:00
|
|
|
handleFetchAttachments();
|
2022-09-04 17:06:11 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
const onUploadModalClose = () => {
|
|
|
|
routeQueryAction.value = undefined;
|
|
|
|
handleFetchAttachments();
|
2024-05-23 02:54:49 +00:00
|
|
|
uploadVisible.value = false;
|
2022-09-04 17:06:11 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
// View type
|
2022-05-25 07:47:03 +00:00
|
|
|
const viewTypes = [
|
|
|
|
{
|
|
|
|
name: "list",
|
2023-10-28 16:15:38 +00:00
|
|
|
tooltip: t("core.attachment.filters.view_type.items.list"),
|
2022-05-25 07:47:03 +00:00
|
|
|
icon: IconList,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name: "grid",
|
2023-10-28 16:15:38 +00:00
|
|
|
tooltip: t("core.attachment.filters.view_type.items.grid"),
|
2022-05-25 07:47:03 +00:00
|
|
|
icon: IconGrid,
|
|
|
|
},
|
|
|
|
];
|
|
|
|
|
2023-08-24 14:38:14 +00:00
|
|
|
const viewType = useLocalStorage("attachment-view-type", "list");
|
2022-08-18 07:35:32 +00:00
|
|
|
|
2022-09-04 17:06:11 +00:00
|
|
|
// Route query action
|
|
|
|
const routeQueryAction = useRouteQuery<string | undefined>("action");
|
2022-05-17 13:51:19 +00:00
|
|
|
|
2022-09-04 17:06:11 +00:00
|
|
|
onMounted(() => {
|
|
|
|
if (!routeQueryAction.value) {
|
|
|
|
return;
|
2022-05-24 10:05:05 +00:00
|
|
|
}
|
2022-09-04 17:06:11 +00:00
|
|
|
if (routeQueryAction.value === "upload") {
|
|
|
|
uploadVisible.value = true;
|
|
|
|
}
|
|
|
|
});
|
2022-09-28 06:50:16 +00:00
|
|
|
|
|
|
|
const nameQuery = useRouteQuery<string | undefined>("name");
|
|
|
|
const nameQueryAttachment = ref<Attachment>();
|
|
|
|
|
|
|
|
watch(
|
|
|
|
() => selectedAttachment.value,
|
|
|
|
() => {
|
|
|
|
if (selectedAttachment.value) {
|
|
|
|
nameQuery.value = selectedAttachment.value.metadata.name;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
);
|
|
|
|
|
|
|
|
onMounted(() => {
|
|
|
|
if (!nameQuery.value) {
|
|
|
|
return;
|
|
|
|
}
|
2024-06-25 04:31:44 +00:00
|
|
|
coreApiClient.storage.attachment
|
|
|
|
.getAttachment({
|
2022-09-28 06:50:16 +00:00
|
|
|
name: nameQuery.value,
|
|
|
|
})
|
|
|
|
.then((response) => {
|
|
|
|
nameQueryAttachment.value = response.data;
|
|
|
|
detailVisible.value = true;
|
|
|
|
});
|
|
|
|
});
|
2022-05-12 07:28:21 +00:00
|
|
|
</script>
|
|
|
|
<template>
|
2022-09-04 17:06:11 +00:00
|
|
|
<AttachmentDetailModal
|
2024-04-12 09:46:07 +00:00
|
|
|
v-if="detailVisible"
|
2022-09-28 06:50:16 +00:00
|
|
|
:attachment="selectedAttachment || nameQueryAttachment"
|
2022-09-04 17:06:11 +00:00
|
|
|
@close="onDetailModalClose"
|
|
|
|
>
|
|
|
|
<template #actions>
|
2022-09-11 09:10:25 +00:00
|
|
|
<span @click="handleSelectPrevious">
|
2022-09-04 17:06:11 +00:00
|
|
|
<IconArrowLeft />
|
2022-09-11 09:10:25 +00:00
|
|
|
</span>
|
|
|
|
<span @click="handleSelectNext">
|
2022-09-04 17:06:11 +00:00
|
|
|
<IconArrowRight />
|
2022-09-11 09:10:25 +00:00
|
|
|
</span>
|
2022-09-04 17:06:11 +00:00
|
|
|
</template>
|
|
|
|
</AttachmentDetailModal>
|
2024-05-23 02:54:49 +00:00
|
|
|
<AttachmentUploadModal v-if="uploadVisible" @close="onUploadModalClose" />
|
|
|
|
<AttachmentPoliciesModal
|
|
|
|
v-if="policyVisible"
|
|
|
|
@close="policyVisible = false"
|
2022-09-04 17:06:11 +00:00
|
|
|
/>
|
2023-03-23 08:54:33 +00:00
|
|
|
<VPageHeader :title="$t('core.attachment.title')">
|
2022-05-12 07:28:21 +00:00
|
|
|
<template #icon>
|
2022-09-04 17:06:11 +00:00
|
|
|
<IconFolder class="mr-2 self-center" />
|
2022-05-12 07:28:21 +00:00
|
|
|
</template>
|
|
|
|
<template #actions>
|
2022-05-23 07:16:23 +00:00
|
|
|
<VSpace>
|
2022-09-30 09:48:19 +00:00
|
|
|
<VButton
|
|
|
|
v-permission="['system:attachments:manage']"
|
|
|
|
size="sm"
|
|
|
|
@click="policyVisible = true"
|
|
|
|
>
|
2022-08-12 08:15:08 +00:00
|
|
|
<template #icon>
|
|
|
|
<IconDatabase2Line class="h-full w-full" />
|
|
|
|
</template>
|
2023-03-23 08:54:33 +00:00
|
|
|
{{ $t("core.attachment.actions.storage_policies") }}
|
2022-08-12 08:15:08 +00:00
|
|
|
</VButton>
|
2022-09-30 09:48:19 +00:00
|
|
|
<VButton
|
|
|
|
v-permission="['system:attachments:manage']"
|
|
|
|
type="secondary"
|
|
|
|
@click="uploadVisible = true"
|
|
|
|
>
|
2022-08-12 08:15:08 +00:00
|
|
|
<template #icon>
|
|
|
|
<IconUpload class="h-full w-full" />
|
|
|
|
</template>
|
2023-03-23 08:54:33 +00:00
|
|
|
{{ $t("core.common.buttons.upload") }}
|
2022-05-24 10:05:05 +00:00
|
|
|
</VButton>
|
2022-05-23 07:16:23 +00:00
|
|
|
</VSpace>
|
2022-05-12 07:28:21 +00:00
|
|
|
</template>
|
|
|
|
</VPageHeader>
|
|
|
|
|
2022-05-25 07:47:03 +00:00
|
|
|
<div class="m-0 md:m-4">
|
2022-05-29 15:55:06 +00:00
|
|
|
<div class="flex flex-col gap-2 sm:flex-row">
|
2022-05-17 13:51:19 +00:00
|
|
|
<div class="w-full">
|
2022-05-25 07:47:03 +00:00
|
|
|
<VCard :body-class="[viewType === 'list' ? '!p-0' : '']">
|
|
|
|
<template #header>
|
2022-05-29 15:55:06 +00:00
|
|
|
<div class="block w-full bg-gray-50 px-4 py-3">
|
2022-05-17 13:51:19 +00:00
|
|
|
<div
|
2023-09-14 16:14:14 +00:00
|
|
|
class="relative flex flex-col flex-wrap items-start gap-4 sm:flex-row sm:items-center"
|
2022-05-17 13:51:19 +00:00
|
|
|
>
|
2022-09-30 09:48:19 +00:00
|
|
|
<div
|
|
|
|
v-permission="['system:attachments:manage']"
|
2023-09-14 16:14:14 +00:00
|
|
|
class="hidden items-center sm:flex"
|
2022-09-30 09:48:19 +00:00
|
|
|
>
|
2022-05-25 07:47:03 +00:00
|
|
|
<input
|
2022-09-04 17:06:11 +00:00
|
|
|
v-model="checkedAll"
|
2022-05-25 07:47:03 +00:00
|
|
|
type="checkbox"
|
2022-09-04 17:06:11 +00:00
|
|
|
@change="handleCheckAllChange"
|
2022-05-25 07:47:03 +00:00
|
|
|
/>
|
|
|
|
</div>
|
2022-09-04 17:06:11 +00:00
|
|
|
<div class="flex w-full flex-1 items-center sm:w-auto">
|
2023-07-13 03:31:17 +00:00
|
|
|
<SearchInput
|
2022-09-04 17:06:11 +00:00
|
|
|
v-if="!selectedAttachments.size"
|
2023-07-13 03:31:17 +00:00
|
|
|
v-model="keyword"
|
|
|
|
/>
|
2022-05-25 07:47:03 +00:00
|
|
|
<VSpace v-else>
|
2022-09-04 17:06:11 +00:00
|
|
|
<VButton type="danger" @click="handleDeleteInBatch">
|
2023-03-23 08:54:33 +00:00
|
|
|
{{ $t("core.common.buttons.delete") }}
|
2022-09-04 17:06:11 +00:00
|
|
|
</VButton>
|
|
|
|
<VButton @click="selectedAttachments.clear()">
|
2023-03-23 08:54:33 +00:00
|
|
|
{{
|
|
|
|
$t("core.attachment.operations.deselect_items.button")
|
|
|
|
}}
|
2022-09-04 17:06:11 +00:00
|
|
|
</VButton>
|
2024-06-26 04:26:49 +00:00
|
|
|
<VDropdown v-if="groups?.length">
|
2023-03-23 08:54:33 +00:00
|
|
|
<VButton>
|
|
|
|
{{ $t("core.attachment.operations.move.button") }}
|
|
|
|
</VButton>
|
2022-09-04 17:06:11 +00:00
|
|
|
<template #popper>
|
2023-03-27 08:06:13 +00:00
|
|
|
<VDropdownItem
|
|
|
|
v-for="(group, index) in groups"
|
|
|
|
:key="index"
|
|
|
|
@click="handleMove(group)"
|
|
|
|
>
|
|
|
|
{{ group.spec.displayName }}
|
|
|
|
</VDropdownItem>
|
2022-09-04 17:06:11 +00:00
|
|
|
</template>
|
2023-03-27 08:06:13 +00:00
|
|
|
</VDropdown>
|
2022-05-25 07:47:03 +00:00
|
|
|
</VSpace>
|
|
|
|
</div>
|
2023-09-14 16:14:14 +00:00
|
|
|
<VSpace spacing="lg" class="flex-wrap">
|
|
|
|
<FilterCleanButton
|
|
|
|
v-if="hasFilters"
|
|
|
|
@click="handleClearFilters"
|
|
|
|
/>
|
|
|
|
<FilterDropdown
|
|
|
|
v-model="selectedPolicy"
|
|
|
|
:label="$t('core.attachment.filters.storage_policy.label')"
|
|
|
|
:items="[
|
|
|
|
{
|
|
|
|
label: t('core.common.filters.item_labels.all'),
|
|
|
|
},
|
|
|
|
...(policies?.map((policy) => {
|
|
|
|
return {
|
|
|
|
label: policy.spec.displayName,
|
|
|
|
value: policy.metadata.name,
|
|
|
|
};
|
|
|
|
}) || []),
|
|
|
|
]"
|
|
|
|
/>
|
2024-05-16 02:32:35 +00:00
|
|
|
<FilterDropdown
|
|
|
|
v-model="selectedAccepts"
|
|
|
|
:label="$t('core.attachment.filters.accept.label')"
|
|
|
|
:items="[
|
|
|
|
{
|
|
|
|
label: t('core.common.filters.item_labels.all'),
|
|
|
|
},
|
|
|
|
{
|
|
|
|
label: t('core.attachment.filters.accept.items.image'),
|
|
|
|
value: 'image/*',
|
|
|
|
},
|
|
|
|
{
|
|
|
|
label: t('core.attachment.filters.accept.items.audio'),
|
|
|
|
value: 'audio/*',
|
|
|
|
},
|
|
|
|
{
|
|
|
|
label: t('core.attachment.filters.accept.items.video'),
|
|
|
|
value: 'video/*',
|
|
|
|
},
|
|
|
|
{
|
|
|
|
label: t('core.attachment.filters.accept.items.file'),
|
|
|
|
value: 'text/*,application/*',
|
|
|
|
},
|
|
|
|
]"
|
|
|
|
/>
|
2023-09-22 08:11:53 +00:00
|
|
|
<HasPermission :permissions="['system:users:view']">
|
|
|
|
<UserFilterDropdown
|
|
|
|
v-model="selectedUser"
|
|
|
|
:label="$t('core.attachment.filters.owner.label')"
|
|
|
|
/>
|
|
|
|
</HasPermission>
|
2023-09-14 16:14:14 +00:00
|
|
|
<FilterDropdown
|
|
|
|
v-model="selectedSort"
|
|
|
|
:label="$t('core.common.filters.labels.sort')"
|
|
|
|
:items="[
|
|
|
|
{
|
|
|
|
label: t('core.common.filters.item_labels.default'),
|
|
|
|
},
|
|
|
|
{
|
|
|
|
label: t(
|
|
|
|
'core.attachment.filters.sort.items.create_time_desc'
|
|
|
|
),
|
2024-02-20 02:58:09 +00:00
|
|
|
value: 'metadata.creationTimestamp,desc',
|
2023-09-14 16:14:14 +00:00
|
|
|
},
|
|
|
|
{
|
|
|
|
label: t(
|
|
|
|
'core.attachment.filters.sort.items.create_time_asc'
|
|
|
|
),
|
2024-02-20 02:58:09 +00:00
|
|
|
value: 'metadata.creationTimestamp,asc',
|
2023-09-14 16:14:14 +00:00
|
|
|
},
|
2024-03-11 08:58:08 +00:00
|
|
|
{
|
|
|
|
label: t(
|
|
|
|
'core.attachment.filters.sort.items.display_name_desc'
|
|
|
|
),
|
|
|
|
value: 'spec.displayName,desc',
|
|
|
|
},
|
|
|
|
{
|
|
|
|
label: t(
|
|
|
|
'core.attachment.filters.sort.items.display_name_asc'
|
|
|
|
),
|
|
|
|
value: 'spec.displayName,asc',
|
|
|
|
},
|
2023-09-14 16:14:14 +00:00
|
|
|
{
|
|
|
|
label: t(
|
|
|
|
'core.attachment.filters.sort.items.size_desc'
|
|
|
|
),
|
2024-02-20 02:58:09 +00:00
|
|
|
value: 'spec.size,desc',
|
2023-09-14 16:14:14 +00:00
|
|
|
},
|
|
|
|
{
|
|
|
|
label: t('core.attachment.filters.sort.items.size_asc'),
|
2024-02-20 02:58:09 +00:00
|
|
|
value: 'spec.size,asc',
|
2023-09-14 16:14:14 +00:00
|
|
|
},
|
|
|
|
]"
|
|
|
|
/>
|
|
|
|
<div class="flex flex-row gap-2">
|
|
|
|
<div
|
|
|
|
v-for="(item, index) in viewTypes"
|
|
|
|
:key="index"
|
|
|
|
v-tooltip="`${item.tooltip}`"
|
|
|
|
:class="{
|
|
|
|
'bg-gray-200 font-bold text-black':
|
|
|
|
viewType === item.name,
|
|
|
|
}"
|
|
|
|
class="cursor-pointer rounded p-1 hover:bg-gray-200"
|
|
|
|
@click="viewType = item.name"
|
|
|
|
>
|
|
|
|
<component :is="item.icon" class="h-4 w-4" />
|
2022-10-24 03:18:16 +00:00
|
|
|
</div>
|
2023-09-14 16:14:14 +00:00
|
|
|
</div>
|
|
|
|
<div class="flex flex-row gap-2">
|
|
|
|
<div
|
|
|
|
class="group cursor-pointer rounded p-1 hover:bg-gray-200"
|
|
|
|
@click="handleFetchAttachments()"
|
|
|
|
>
|
|
|
|
<IconRefreshLine
|
|
|
|
v-tooltip="$t('core.common.buttons.refresh')"
|
|
|
|
:class="{ 'animate-spin text-gray-900': isFetching }"
|
|
|
|
class="h-4 w-4 text-gray-600 group-hover:text-gray-900"
|
|
|
|
/>
|
2022-05-25 07:47:03 +00:00
|
|
|
</div>
|
2023-09-14 16:14:14 +00:00
|
|
|
</div>
|
|
|
|
</VSpace>
|
2022-05-25 07:47:03 +00:00
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
</template>
|
|
|
|
|
2022-09-04 17:06:11 +00:00
|
|
|
<div :style="`${viewType === 'list' ? 'padding:12px 16px 0' : ''}`">
|
2024-05-27 08:30:57 +00:00
|
|
|
<AttachmentGroupList @select="handleReset" />
|
2022-05-25 07:47:03 +00:00
|
|
|
</div>
|
|
|
|
|
2023-02-23 09:08:12 +00:00
|
|
|
<VLoading v-if="isLoading" />
|
2022-11-24 03:46:10 +00:00
|
|
|
|
2023-02-23 09:08:12 +00:00
|
|
|
<Transition v-else-if="!attachments?.length" appear name="fade">
|
2022-11-24 03:46:10 +00:00
|
|
|
<VEmpty
|
2023-03-23 08:54:33 +00:00
|
|
|
:message="$t('core.attachment.empty.message')"
|
|
|
|
:title="$t('core.attachment.empty.title')"
|
2022-11-24 03:46:10 +00:00
|
|
|
>
|
|
|
|
<template #actions>
|
|
|
|
<VSpace>
|
2023-03-23 08:54:33 +00:00
|
|
|
<VButton @click="handleFetchAttachments">
|
|
|
|
{{ $t("core.common.buttons.refresh") }}
|
|
|
|
</VButton>
|
2022-11-24 03:46:10 +00:00
|
|
|
<VButton
|
|
|
|
v-permission="['system:attachments:manage']"
|
|
|
|
type="secondary"
|
|
|
|
@click="uploadVisible = true"
|
|
|
|
>
|
|
|
|
<template #icon>
|
|
|
|
<IconUpload class="h-full w-full" />
|
|
|
|
</template>
|
2023-03-23 08:54:33 +00:00
|
|
|
{{ $t("core.attachment.empty.actions.upload") }}
|
2022-11-24 03:46:10 +00:00
|
|
|
</VButton>
|
|
|
|
</VSpace>
|
|
|
|
</template>
|
|
|
|
</VEmpty>
|
|
|
|
</Transition>
|
2022-09-04 17:06:11 +00:00
|
|
|
|
|
|
|
<div v-else>
|
2022-11-24 03:46:10 +00:00
|
|
|
<Transition v-if="viewType === 'grid'" appear name="fade">
|
2022-05-25 07:47:03 +00:00
|
|
|
<div
|
2022-09-04 17:06:11 +00:00
|
|
|
class="mt-2 grid grid-cols-3 gap-x-2 gap-y-3 sm:grid-cols-3 md:grid-cols-6 xl:grid-cols-8 2xl:grid-cols-12"
|
|
|
|
role="list"
|
2022-05-25 07:47:03 +00:00
|
|
|
>
|
2022-09-04 17:06:11 +00:00
|
|
|
<VCard
|
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 附件管理列表项的操作按钮支持被插件扩展。
```
2023-10-08 09:58:37 +00:00
|
|
|
v-for="attachment in attachments"
|
|
|
|
:key="attachment.metadata.name"
|
2022-09-04 17:06:11 +00:00
|
|
|
:body-class="['!p-0']"
|
|
|
|
:class="{
|
|
|
|
'ring-1 ring-primary': isChecked(attachment),
|
|
|
|
'ring-1 ring-red-600':
|
|
|
|
attachment.metadata.deletionTimestamp,
|
|
|
|
}"
|
|
|
|
class="hover:shadow"
|
|
|
|
@click="handleClickItem(attachment)"
|
|
|
|
>
|
|
|
|
<div class="group relative bg-white">
|
|
|
|
<div
|
2023-03-29 13:44:14 +00:00
|
|
|
class="aspect-h-8 aspect-w-10 block h-full w-full cursor-pointer overflow-hidden bg-gray-100"
|
2022-09-04 17:06:11 +00:00
|
|
|
>
|
|
|
|
<LazyImage
|
|
|
|
v-if="isImage(attachment.spec.mediaType)"
|
|
|
|
:key="attachment.metadata.name"
|
|
|
|
:alt="attachment.spec.displayName"
|
|
|
|
:src="attachment.status?.permalink"
|
2023-04-24 03:20:19 +00:00
|
|
|
classes="pointer-events-none object-cover group-hover:opacity-75 transform-gpu"
|
2022-05-25 07:47:03 +00:00
|
|
|
>
|
2022-09-04 17:06:11 +00:00
|
|
|
<template #loading>
|
2024-07-10 02:13:24 +00:00
|
|
|
<AttachmentLoading />
|
2022-09-04 17:06:11 +00:00
|
|
|
</template>
|
|
|
|
<template #error>
|
2024-07-10 02:13:24 +00:00
|
|
|
<AttachmentError />
|
2022-09-04 17:06:11 +00:00
|
|
|
</template>
|
|
|
|
</LazyImage>
|
2024-07-10 02:13:24 +00:00
|
|
|
<LazyVideo
|
|
|
|
v-else-if="
|
|
|
|
attachment?.spec.mediaType?.startsWith('video/')
|
|
|
|
"
|
|
|
|
:src="attachment.status?.permalink"
|
|
|
|
classes="object-cover group-hover:opacity-75"
|
|
|
|
>
|
|
|
|
<template #loading>
|
|
|
|
<AttachmentLoading />
|
|
|
|
</template>
|
|
|
|
<template #error>
|
|
|
|
<AttachmentError />
|
|
|
|
</template>
|
|
|
|
</LazyVideo>
|
2022-09-04 17:06:11 +00:00
|
|
|
<AttachmentFileTypeIcon
|
|
|
|
v-else
|
|
|
|
:file-name="attachment.spec.displayName"
|
|
|
|
/>
|
2022-05-25 07:47:03 +00:00
|
|
|
</div>
|
2022-09-04 17:06:11 +00:00
|
|
|
|
|
|
|
<p
|
|
|
|
v-tooltip="attachment.spec.displayName"
|
|
|
|
class="block cursor-pointer truncate px-2 py-1 text-center text-xs font-medium text-gray-700"
|
|
|
|
>
|
|
|
|
{{ attachment.spec.displayName }}
|
|
|
|
</p>
|
|
|
|
|
|
|
|
<div
|
|
|
|
v-if="attachment.metadata.deletionTimestamp"
|
2023-03-29 13:44:14 +00:00
|
|
|
class="absolute right-1 top-1 text-xs text-red-300"
|
2022-09-04 17:06:11 +00:00
|
|
|
>
|
2023-03-23 08:54:33 +00:00
|
|
|
{{ $t("core.common.status.deleting") }}...
|
2022-05-25 07:47:03 +00:00
|
|
|
</div>
|
2022-09-04 17:06:11 +00:00
|
|
|
|
2022-05-25 07:47:03 +00:00
|
|
|
<div
|
2022-09-04 17:06:11 +00:00
|
|
|
v-if="!attachment.metadata.deletionTimestamp"
|
2022-09-30 09:48:19 +00:00
|
|
|
v-permission="['system:attachments:manage']"
|
2022-09-04 17:06:11 +00:00
|
|
|
:class="{ '!flex': selectedAttachments.has(attachment) }"
|
2023-03-29 13:44:14 +00:00
|
|
|
class="absolute left-0 top-0 hidden h-1/3 w-full cursor-pointer justify-end bg-gradient-to-b from-gray-300 to-transparent ease-in-out group-hover:flex"
|
2022-05-25 07:47:03 +00:00
|
|
|
>
|
2022-09-04 17:06:11 +00:00
|
|
|
<IconCheckboxFill
|
|
|
|
:class="{
|
|
|
|
'!text-primary': selectedAttachments.has(attachment),
|
|
|
|
}"
|
2023-03-29 13:44:14 +00:00
|
|
|
class="mr-1 mt-1 h-6 w-6 cursor-pointer text-white transition-all hover:text-primary"
|
2022-09-04 17:06:11 +00:00
|
|
|
@click.stop="handleSelect(attachment)"
|
2022-05-25 07:47:03 +00:00
|
|
|
/>
|
|
|
|
</div>
|
|
|
|
</div>
|
2022-09-04 17:06:11 +00:00
|
|
|
</VCard>
|
2022-05-25 07:47:03 +00:00
|
|
|
</div>
|
2022-11-24 03:46:10 +00:00
|
|
|
</Transition>
|
|
|
|
<Transition v-if="viewType === 'list'" appear name="fade">
|
|
|
|
<ul
|
|
|
|
class="box-border h-full w-full divide-y divide-gray-100"
|
|
|
|
role="list"
|
|
|
|
>
|
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 附件管理列表项的操作按钮支持被插件扩展。
```
2023-10-08 09:58:37 +00:00
|
|
|
<li
|
|
|
|
v-for="attachment in attachments"
|
|
|
|
:key="attachment.metadata.name"
|
|
|
|
>
|
|
|
|
<AttachmentListItem
|
|
|
|
:attachment="attachment"
|
|
|
|
:is-selected="isChecked(attachment)"
|
|
|
|
@select="handleSelect"
|
|
|
|
@open-detail="handleClickItem"
|
|
|
|
/>
|
2022-11-24 03:46:10 +00:00
|
|
|
</li>
|
|
|
|
</ul>
|
|
|
|
</Transition>
|
2022-09-04 17:06:11 +00:00
|
|
|
</div>
|
2022-05-25 07:47:03 +00:00
|
|
|
|
|
|
|
<template #footer>
|
2023-07-28 03:15:08 +00:00
|
|
|
<VPagination
|
|
|
|
v-model:page="page"
|
|
|
|
v-model:size="size"
|
|
|
|
:page-label="$t('core.components.pagination.page_label')"
|
|
|
|
:size-label="$t('core.components.pagination.size_label')"
|
|
|
|
:total-label="
|
|
|
|
$t('core.components.pagination.total_label', { total: total })
|
|
|
|
"
|
|
|
|
:total="total"
|
|
|
|
:size-options="[60, 120, 200]"
|
|
|
|
/>
|
2022-05-25 07:47:03 +00:00
|
|
|
</template>
|
|
|
|
</VCard>
|
2022-05-17 13:51:19 +00:00
|
|
|
</div>
|
|
|
|
</div>
|
2022-05-12 07:28:21 +00:00
|
|
|
</div>
|
|
|
|
</template>
|