Skip to content

Commit 97f653b

Browse files
authored
feat: support selecting groups to join when link (#165)
fixes #152 ```release-note S3关联时支持选择加入的分组 ``` ![image](https://github.com/user-attachments/assets/2380688c-3e04-4485-986d-b9118e05fe95)
1 parent d4df735 commit 97f653b

File tree

6 files changed

+97
-15
lines changed

6 files changed

+97
-15
lines changed

console/src/api/models/link-request.ts

+6
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,12 @@
2020
* @interface LinkRequest
2121
*/
2222
export interface LinkRequest {
23+
/**
24+
*
25+
* @type {string}
26+
* @memberof LinkRequest
27+
*/
28+
'groupName'?: string;
2329
/**
2430
*
2531
* @type {Array<string>}

console/src/views/S3Link.vue

+75-6
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
<script setup lang="ts">
2-
import { computed, onMounted, ref, watch } from "vue";
2+
import { computed, getCurrentInstance, onMounted, ref, watch } from "vue";
33
import {
4+
IconCheckboxCircle,
45
IconRefreshLine,
56
Toast,
67
VButton,
@@ -12,25 +13,47 @@ import {
1213
VModal,
1314
VPageHeader,
1415
VSpace,
16+
VStatusDot,
1517
VTag,
1618
} from "@halo-dev/components";
1719
import CarbonFolderDetailsReference from "~icons/carbon/folder-details-reference";
1820
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";
2022
import { S3LinkControllerApi } from "@/api";
2123
import type { S3ListResult, LinkResultItem, Policy, ObjectVo } from "@/api";
2224
2325
const s3LinkControllerApi = new S3LinkControllerApi(undefined, axiosInstance.defaults.baseURL, axiosInstance);
2426
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+
2537
const selectedFiles = ref<string[]>([]);
2638
const policyName = ref<string>("");
2739
const page = ref(1);
2840
const size = ref(50);
41+
const selectedGroup = ref("")
2942
const policyOptions = ref<{ label: string; value: string; attrs: any }[]>([{
3043
label: "请选择存储策略",
3144
value: "",
3245
attrs: {disabled: true}
3346
}]);
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+
});
3457
// update when fetch first page
3558
const filePrefix = ref<string>("");
3659
// update when user input
@@ -43,6 +66,7 @@ const s3Objects = ref<S3ListResult>({
4366
currentContinuationObject: "",
4467
nextContinuationObject: "",
4568
});
69+
const customGroups = ref<Group[]>([]);
4670
// view state
4771
const isFetching = ref(false);
4872
const isShowModal = ref(false);
@@ -91,7 +115,7 @@ const handleCheckAllChange = (e: Event) => {
91115
const fetchPolicies = async () => {
92116
try {
93117
const {status, data} = await s3LinkControllerApi.listS3Policies();
94-
if (status == 200) {
118+
if (status === 200) {
95119
policyOptions.value = [{
96120
label: "请选择存储策略",
97121
value: "",
@@ -174,7 +198,8 @@ const handleLink = async () => {
174198
const linkResult = await s3LinkControllerApi.addAttachmentRecord({
175199
linkRequest: {
176200
policyName: policyName.value,
177-
objectKeys: selectedFiles.value
201+
objectKeys: selectedFiles.value,
202+
groupName: selectedGroup.value,
178203
}
179204
});
180205
const items = linkResult.data.items || [];
@@ -219,7 +244,20 @@ const handleModalClose = () => {
219244
fetchObjects();
220245
};
221246
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+
});
223261
224262
watch(selectedFiles, (newValue) => {
225263
checkedAll.value = s3Objects.value.objects?.filter(file => !file.isLinked)
@@ -232,7 +270,7 @@ watch(selectedLinkedStatusItem, handleFirstPage);
232270
</script>
233271

234272
<template>
235-
<VPageHeader title="关联S3文件(Beta)">
273+
<VPageHeader title="关联S3文件">
236274
<template #icon>
237275
<CarbonFolderDetailsReference class="mr-2 self-center"/>
238276
</template>
@@ -327,6 +365,37 @@ watch(selectedLinkedStatusItem, handleFirstPage);
327365
class="box-border h-full w-full divide-y divide-gray-100"
328366
role="list"
329367
>
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>
330399
<li v-for="(file, index) in s3Objects.objects" :key="index">
331400
<VEntity :is-selected="checkSelection(file)">
332401
<template

src/main/java/run/halo/s3os/LinkRequest.java

+1
Original file line numberDiff line numberDiff line change
@@ -9,4 +9,5 @@
99
public class LinkRequest {
1010
private String policyName;
1111
private Set<String> objectKeys;
12+
private String groupName;
1213
}

src/main/java/run/halo/s3os/S3LinkController.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,6 @@ public Mono<S3ListResult> listObjects(@PathVariable(value = "policyName") String
4141
@PostMapping("/attachments/link")
4242
public Mono<LinkResult> addAttachmentRecord(@RequestBody LinkRequest linkRequest) {
4343
return s3LinkService.addAttachmentRecords(linkRequest.getPolicyName(),
44-
linkRequest.getObjectKeys());
44+
linkRequest.getObjectKeys(), linkRequest.getGroupName());
4545
}
4646
}

src/main/java/run/halo/s3os/S3LinkService.java

+5-3
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,12 @@ public interface S3LinkService {
1010
Flux<Policy> listS3Policies();
1111

1212
Mono<S3ListResult> listObjects(String policyName, String continuationToken,
13-
Integer pageSize, String filePrefix);
13+
Integer pageSize, String filePrefix);
1414

15-
Mono<LinkResult> addAttachmentRecords(String policyName, Set<String> objectKeys);
15+
Mono<LinkResult> addAttachmentRecords(String policyName, Set<String> objectKeys,
16+
String groupName);
1617

1718
Mono<S3ListResult> listObjectsUnlinked(String policyName, String continuationToken,
18-
String continuationObject, Integer pageSize, String filePrefix);
19+
String continuationObject, Integer pageSize,
20+
String filePrefix);
1921
}

src/main/java/run/halo/s3os/S3LinkServiceImpl.java

+9-5
Original file line numberDiff line numberDiff line change
@@ -113,11 +113,11 @@ public Mono<S3ListResult> listObjects(String policyName, String continuationToke
113113
}
114114

115115
@Override
116-
public Mono<LinkResult> addAttachmentRecords(String policyName, Set<String> objectKeys) {
116+
public Mono<LinkResult> addAttachmentRecords(String policyName, Set<String> objectKeys, String groupName) {
117117
return getOperableObjectKeys(objectKeys, policyName)
118118
.flatMap(operableObjectKeys -> getExistingAttachments(objectKeys, policyName)
119119
.flatMap(existingAttachments -> getLinkResultItems(objectKeys, operableObjectKeys,
120-
existingAttachments, policyName)
120+
existingAttachments, policyName, groupName)
121121
.collectList()
122122
.map(LinkResult::new)));
123123
}
@@ -147,12 +147,13 @@ private Mono<Set<String>> getExistingAttachments(Set<String> objectKeys,
147147
private Flux<LinkResult.LinkResultItem> getLinkResultItems(Set<String> objectKeys,
148148
Set<String> operableObjectKeys,
149149
Set<String> existingAttachments,
150-
String policyName) {
150+
String policyName,
151+
String groupName) {
151152
return Flux.fromIterable(objectKeys)
152153
.flatMap((objectKey) -> {
153154
if (operableObjectKeys.contains(objectKey) &&
154155
!existingAttachments.contains(objectKey)) {
155-
return addAttachmentRecord(policyName, objectKey)
156+
return addAttachmentRecord(policyName, objectKey, groupName)
156157
.onErrorResume((throwable) -> Mono.just(
157158
new LinkResult.LinkResultItem(objectKey, false,
158159
throwable.getMessage())));
@@ -223,7 +224,7 @@ record TokenState(String currToken, String nextToken) {
223224
}
224225

225226
public Mono<LinkResult.LinkResultItem> addAttachmentRecord(String policyName,
226-
String objectKey) {
227+
String objectKey, String groupName) {
227228
return authenticationConsumer(authentication -> client.fetch(Policy.class, policyName)
228229
.flatMap((policy) -> {
229230
var configMapName = policy.getSpec().getConfigMapName();
@@ -255,6 +256,9 @@ public Mono<LinkResult.LinkResultItem> addAttachmentRecord(String policyName,
255256
}
256257
spec.setOwnerName(authentication.getName());
257258
spec.setPolicyName(policyName);
259+
if (StringUtils.isNotBlank(groupName)){
260+
spec.setGroupName(groupName);
261+
}
258262
})
259263
.flatMap(client::create)
260264
.thenReturn(new LinkResult.LinkResultItem(objectKey, true, null));

0 commit comments

Comments
 (0)