1
1
<script setup lang="ts">
2
- import { computed , onMounted , ref , watch } from " vue" ;
2
+ import { computed , getCurrentInstance , onMounted , ref , watch } from " vue" ;
3
3
import {
4
+ IconCheckboxCircle ,
4
5
IconRefreshLine ,
5
6
Toast ,
6
7
VButton ,
@@ -12,25 +13,47 @@ import {
12
13
VModal ,
13
14
VPageHeader ,
14
15
VSpace ,
16
+ VStatusDot ,
15
17
VTag ,
16
18
} from " @halo-dev/components" ;
17
19
import CarbonFolderDetailsReference from " ~icons/carbon/folder-details-reference" ;
18
20
import IconErrorWarning from " ~icons/ri/error-warning-line" ;
19
- import { axiosInstance } from " @halo-dev/api-client" ;
21
+ import { axiosInstance , coreApiClient , type Group } from " @halo-dev/api-client" ;
20
22
import { S3LinkControllerApi } from " @/api" ;
21
23
import type { S3ListResult , LinkResultItem , Policy , ObjectVo } from " @/api" ;
22
24
23
25
const s3LinkControllerApi = new S3LinkControllerApi (undefined , axiosInstance .defaults .baseURL , axiosInstance );
24
26
27
+ const componentInstance = getCurrentInstance ();
28
+ const t = (key : string ) => {
29
+ // @ts-ignore
30
+ if (typeof componentInstance ?.proxy ?.$t === ' function' ) {
31
+ // @ts-ignore
32
+ return componentInstance .proxy .$t (key );
33
+ }
34
+ return key ;
35
+ };
36
+
25
37
const selectedFiles = ref <string []>([]);
26
38
const policyName = ref <string >(" " );
27
39
const page = ref (1 );
28
40
const size = ref (50 );
41
+ const selectedGroup = ref (" " )
29
42
const policyOptions = ref <{ label: string ; value: string ; attrs: any }[]>([{
30
43
label: " 请选择存储策略" ,
31
44
value: " " ,
32
45
attrs: {disabled: true }
33
46
}]);
47
+ const defaultGroup = ref <Group >({
48
+ apiVersion: " " ,
49
+ kind: " " ,
50
+ metadata: {
51
+ name: " " ,
52
+ },
53
+ spec: {
54
+ displayName: t (" core.attachment.common.text.ungrouped" ),
55
+ },
56
+ });
34
57
// update when fetch first page
35
58
const filePrefix = ref <string >(" " );
36
59
// update when user input
@@ -43,6 +66,7 @@ const s3Objects = ref<S3ListResult>({
43
66
currentContinuationObject: " " ,
44
67
nextContinuationObject: " " ,
45
68
});
69
+ const customGroups = ref <Group []>([]);
46
70
// view state
47
71
const isFetching = ref (false );
48
72
const isShowModal = ref (false );
@@ -91,7 +115,7 @@ const handleCheckAllChange = (e: Event) => {
91
115
const fetchPolicies = async () => {
92
116
try {
93
117
const {status, data} = await s3LinkControllerApi .listS3Policies ();
94
- if (status == 200 ) {
118
+ if (status === 200 ) {
95
119
policyOptions .value = [{
96
120
label: " 请选择存储策略" ,
97
121
value: " " ,
@@ -174,7 +198,8 @@ const handleLink = async () => {
174
198
const linkResult = await s3LinkControllerApi .addAttachmentRecord ({
175
199
linkRequest: {
176
200
policyName: policyName .value ,
177
- objectKeys: selectedFiles .value
201
+ objectKeys: selectedFiles .value ,
202
+ groupName: selectedGroup .value ,
178
203
}
179
204
});
180
205
const items = linkResult .data .items || [];
@@ -219,7 +244,20 @@ const handleModalClose = () => {
219
244
fetchObjects ();
220
245
};
221
246
222
- onMounted (fetchPolicies );
247
+ const fetchCustomGroups = async () => {
248
+ const {status, data} = await coreApiClient .storage .group .listGroup ({
249
+ labelSelector: [" !halo.run/hidden" ],
250
+ sort: [" metadata.creationTimestamp,asc" ],
251
+ });
252
+ if (status === 200 ) {
253
+ customGroups .value = data .items ;
254
+ }
255
+ };
256
+
257
+ onMounted (() => {
258
+ fetchPolicies ();
259
+ fetchCustomGroups ();
260
+ });
223
261
224
262
watch (selectedFiles , (newValue ) => {
225
263
checkedAll .value = s3Objects .value .objects ?.filter (file => ! file .isLinked )
@@ -232,7 +270,7 @@ watch(selectedLinkedStatusItem, handleFirstPage);
232
270
</script >
233
271
234
272
<template >
235
- <VPageHeader title =" 关联S3文件(Beta) " >
273
+ <VPageHeader title =" 关联S3文件" >
236
274
<template #icon >
237
275
<CarbonFolderDetailsReference class =" mr-2 self-center" />
238
276
</template >
@@ -327,6 +365,37 @@ watch(selectedLinkedStatusItem, handleFirstPage);
327
365
class =" box-border h-full w-full divide-y divide-gray-100"
328
366
role =" list"
329
367
>
368
+ <li style =" padding : 0.5rem 1rem 0 " >
369
+ <span class =" ml-1 mb-1 block text-sm text-gray-500" >关联后所加入的分组</span >
370
+ <div class =" mb-5 grid grid-cols-2 gap-x-2 gap-y-3 md:grid-cols-3 lg:grid-cols-4 2xl:grid-cols-6" >
371
+ <button
372
+ type =" button"
373
+ class =" inline-flex h-full w-full items-center gap-2 rounded-md border border-gray-200 bg-white px-3 py-2.5 text-sm font-medium text-gray-800 hover:bg-gray-50 hover:shadow-sm"
374
+ v-for =" (group, index) in [defaultGroup, ...customGroups]"
375
+ :key =" index"
376
+ :class =" { '!bg-gray-100 shadow-sm': group.metadata.name === selectedGroup }"
377
+ @click =" selectedGroup = group.metadata.name"
378
+ >
379
+ <div class =" inline-flex w-full flex-1 gap-x-2 break-all text-left" >
380
+ <slot name =" text" >
381
+ {{ group?.spec.displayName }}
382
+ </slot >
383
+ <VStatusDot
384
+ v-if =" group?.metadata.deletionTimestamp"
385
+ v-tooltip =" $t('core.common.status.deleting')"
386
+ state =" warning"
387
+ animate
388
+ />
389
+ </div >
390
+ <div class =" flex-none" >
391
+ <IconCheckboxCircle
392
+ v-if =" group.metadata.name === selectedGroup"
393
+ class =" text-primary"
394
+ />
395
+ </div >
396
+ </button >
397
+ </div >
398
+ </li >
330
399
<li v-for =" (file, index) in s3Objects.objects" :key =" index" >
331
400
<VEntity :is-selected =" checkSelection(file)" >
332
401
<template
0 commit comments