mirror of
https://github.com/rustfs/console.git
synced 2026-08-31 01:37:52 +08:00
feat : retention
This commit is contained in:
Vendored
+3
@@ -43,6 +43,7 @@ declare module 'vue' {
|
||||
NInput: typeof import('naive-ui')['NInput']
|
||||
NInputGroup: typeof import('naive-ui')['NInputGroup']
|
||||
NInputGroupLabel: typeof import('naive-ui')['NInputGroupLabel']
|
||||
NInputNumber: typeof import('naive-ui')['NInputNumber']
|
||||
NLayout: typeof import('naive-ui')['NLayout']
|
||||
NLayoutSider: typeof import('naive-ui')['NLayoutSider']
|
||||
NLi: typeof import('naive-ui')['NLi']
|
||||
@@ -56,6 +57,8 @@ declare module 'vue' {
|
||||
NPageHeader: typeof import('naive-ui')['NPageHeader']
|
||||
NPopconfirm: typeof import('naive-ui')['NPopconfirm']
|
||||
NProgress: typeof import('naive-ui')['NProgress']
|
||||
NRadio: typeof import('naive-ui')['NRadio']
|
||||
NRadioGroup: typeof import('naive-ui')['NRadioGroup']
|
||||
NScrollbar: typeof import('naive-ui')['NScrollbar']
|
||||
NSelect: typeof import('naive-ui')['NSelect']
|
||||
NSpace: typeof import('naive-ui')['NSpace']
|
||||
|
||||
@@ -68,6 +68,35 @@
|
||||
:loading="statusLoading"
|
||||
@update:value="handleChangeVersionStatus" />
|
||||
</n-descriptions-item>
|
||||
|
||||
<n-descriptions-item>
|
||||
<template #label>保留</template>
|
||||
<n-switch
|
||||
v-model:value="retentionEnabled"
|
||||
:loading="objectLockLoading"
|
||||
:round="false"
|
||||
@update:value="handleChangeVersionStatus" />
|
||||
<n-space v-if="retentionEnabled">
|
||||
<div v-if="retentionEnabled" class="flex flex-col gap-4">
|
||||
<div v-if="retentionEnabled">
|
||||
<div class="flex items-center justify-between">
|
||||
<n-space>{{ t("Retention Mode") }}:</n-space>
|
||||
<n-radio-group v-model:value="retentionMode">
|
||||
<n-radio value="COMPLIANCE">Compliance</n-radio>
|
||||
<n-radio value="GOVERNANCE">Governance</n-radio>
|
||||
</n-radio-group>
|
||||
</div>
|
||||
<div class="flex items-center justify-between gap-4">
|
||||
<n-space class="w-24">{{ t("Validity") }}*</n-space>
|
||||
<n-input-group class="justify-end">
|
||||
<n-input-number v-model:value="retentionPeriod" :min="1" />
|
||||
<n-select v-model:value="retentionUnit" :options="retentionUnitOptions" class="w-16" />
|
||||
</n-input-group>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</n-space>
|
||||
</n-descriptions-item>
|
||||
</n-descriptions>
|
||||
</n-drawer-content>
|
||||
|
||||
@@ -132,6 +161,8 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { useI18n } from "vue-i18n";
|
||||
const { t } = useI18n();
|
||||
const dialog = useDialog();
|
||||
const visibel = ref(false);
|
||||
const bucketName = ref("");
|
||||
@@ -145,13 +176,18 @@ defineExpose({
|
||||
openDrawer,
|
||||
});
|
||||
|
||||
const getData = () => {
|
||||
getbucketPolicy();
|
||||
getTags();
|
||||
getVersioningStatus();
|
||||
getObjectLockConfig();
|
||||
const getData = async () => {
|
||||
await getTags();
|
||||
await getVersioningStatus();
|
||||
await getObjectLockConfig();
|
||||
await getbucketPolicy();
|
||||
};
|
||||
|
||||
const retentionUnitOptions = [
|
||||
{ label: t("Day"), value: "DAYS" },
|
||||
{ label: t("Year"), value: "YEARS" },
|
||||
];
|
||||
|
||||
const message = useMessage();
|
||||
const {
|
||||
getBucketTagging,
|
||||
@@ -168,14 +204,28 @@ const {
|
||||
/**********object lock ***********************/
|
||||
const lockStatus = ref(false);
|
||||
const objectLockLoading = ref(false);
|
||||
const retentionEnabled = ref(false);
|
||||
const retentionMode = ref("COMPLIANCE");
|
||||
const retentionPeriod = ref(180);
|
||||
const retentionUnit = ref("DAYS");
|
||||
|
||||
const getObjectLockConfig = async () => {
|
||||
objectLockLoading.value = true;
|
||||
getObjectLockConfiguration(bucketName.value)
|
||||
.then((res) => {
|
||||
if (res.ObjectLockConfiguration?.ObjectLockEnabled) {
|
||||
lockStatus.value = res.ObjectLockConfiguration?.ObjectLockEnabled == "Enabled" ? true : false;
|
||||
console.log(res.ObjectLockConfiguration?.Rule);
|
||||
if (res.ObjectLockConfiguration?.Rule) {
|
||||
console.log(1111);
|
||||
retentionEnabled.value = true;
|
||||
retentionMode.value = res.ObjectLockConfiguration?.Rule?.DefaultRetention?.Mode || "COMPLIANCE";
|
||||
retentionPeriod.value = res.ObjectLockConfiguration?.Rule?.DefaultRetention?.Days || 180;
|
||||
retentionUnit.value = res.ObjectLockConfiguration?.Rule?.DefaultRetention?.Years ? "YEARS" : "DAYS";
|
||||
}
|
||||
} else {
|
||||
lockStatus.value = false;
|
||||
retentionEnabled.value = false;
|
||||
}
|
||||
})
|
||||
.finally(() => {
|
||||
|
||||
+107
-51
@@ -2,9 +2,9 @@
|
||||
<n-modal :show="show" @update:show="(val: boolean) => $emit('update:show', val)" size="huge">
|
||||
<n-card class="max-w-screen-sm">
|
||||
<template #header>
|
||||
<div style="display:flex; justify-content: space-between; align-items:center;">
|
||||
<span>{{ t('Create Bucket') }}</span>
|
||||
<n-button size="small" ghost @click="closeModal">{{ t('Close') }}</n-button>
|
||||
<div style="display: flex; justify-content: space-between; align-items: center">
|
||||
<span>{{ t("Create Bucket") }}</span>
|
||||
<n-button size="small" ghost @click="closeModal">{{ t("Close") }}</n-button>
|
||||
</div>
|
||||
</template>
|
||||
<div class="flex flex-col gap-4">
|
||||
@@ -20,17 +20,43 @@
|
||||
<div class="flex items-center gap-4">
|
||||
<n-input :placeholder="t('Please enter name')" v-model:value="objectKey" />
|
||||
</div>
|
||||
<div class="flex items-center gap-4">
|
||||
<n-space class=" w-12">{{ t('Version') }}:</n-space>
|
||||
<n-switch v-model:value="version" @change="handleVersionChange"/>
|
||||
<div class="flex items-center justify-between gap-4">
|
||||
<n-space class="w-24">{{ t("Version") }}:</n-space>
|
||||
<n-switch v-model:value="version" @change="handleVersionChange" />
|
||||
</div>
|
||||
<div class="flex items-center gap-4">
|
||||
<n-space class=" w-12">{{ t('Object Lock') }}:</n-space>
|
||||
<n-switch v-model:value="objectLock" @change="handleObjectLock"/>
|
||||
<div class="flex items-center justify-between gap-4">
|
||||
<n-space class="w-24">{{ t("Object Lock") }}:</n-space>
|
||||
<n-switch v-model:value="objectLock" @change="handleObjectLock" />
|
||||
</div>
|
||||
|
||||
<!-- Retention 配置区块,仅对象锁开启时显示 -->
|
||||
<div v-if="objectLock" class="flex flex-col gap-4">
|
||||
<div class="flex items-center justify-between gap-4">
|
||||
<n-space class="w-24">{{ t("Retention") }}</n-space>
|
||||
<n-switch v-model:value="retentionEnabled" />
|
||||
</div>
|
||||
<div v-if="retentionEnabled">
|
||||
<div class="flex items-center justify-between gap-4">
|
||||
<n-space class="w-24">{{ t("Retention Mode") }}:</n-space>
|
||||
<n-radio-group v-model:value="retentionMode">
|
||||
<n-radio value="COMPLIANCE">Compliance</n-radio>
|
||||
<n-radio value="GOVERNANCE">Governance</n-radio>
|
||||
</n-radio-group>
|
||||
</div>
|
||||
<div class="flex items-center justify-between gap-4">
|
||||
<n-space class="w-24">{{ t("Validity") }}*</n-space>
|
||||
<n-input-group class="justify-end">
|
||||
<n-input-number v-model:value="retentionPeriod" :min="1" class="w-96" />
|
||||
<n-select v-model:value="retentionUnit" :options="retentionUnitOptions" class="w-16" />
|
||||
</n-input-group>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="flex justify-center gap-4">
|
||||
<n-button type="primary" :disabled="objectKey.trim().length < 1" @click="handlePutObject">{{ t('Create') }}</n-button>
|
||||
<n-button type="primary" :disabled="objectKey.trim().length < 1" @click="handlePutObject">
|
||||
{{ t("Create") }}
|
||||
</n-button>
|
||||
</div>
|
||||
</div>
|
||||
</n-card>
|
||||
@@ -38,64 +64,94 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { defineEmits, defineProps } from 'vue';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
import { defineEmits, defineProps } from "vue";
|
||||
import { useI18n } from "vue-i18n";
|
||||
|
||||
const { t } = useI18n()
|
||||
const emit = defineEmits(['update:show'])
|
||||
const { t } = useI18n();
|
||||
const emit = defineEmits(["update:show"]);
|
||||
|
||||
const props = defineProps<{ show: boolean; }>()
|
||||
const props = defineProps<{ show: boolean }>();
|
||||
|
||||
const closeModal = () => emit('update:show', false)
|
||||
const closeModal = () => emit("update:show", false);
|
||||
|
||||
const objectKey = ref('')
|
||||
const version = ref(false)
|
||||
const objectLock = ref(false)
|
||||
const objectKey = ref("");
|
||||
const version = ref(false);
|
||||
const objectLock = ref(false);
|
||||
|
||||
const { createBucket ,putBucketVersioning} = useBucket({})
|
||||
// Retention 相关变量
|
||||
const retentionEnabled = ref(false);
|
||||
const retentionMode = ref("COMPLIANCE");
|
||||
const retentionPeriod = ref(180);
|
||||
const retentionUnit = ref("day");
|
||||
const retentionUnitOptions = [
|
||||
{ label: t("Day"), value: "day" },
|
||||
{ label: t("Year"), value: "year" },
|
||||
];
|
||||
|
||||
const $message = useMessage()
|
||||
const { createBucket, putBucketVersioning, putObjectLockConfiguration } = useBucket({});
|
||||
|
||||
const $message = useMessage();
|
||||
|
||||
// 如果开启对象锁,必须开启版本控制
|
||||
const handleObjectLock = () => {
|
||||
if (objectLock.value) {
|
||||
version.value = true
|
||||
}
|
||||
}
|
||||
version.value = true;
|
||||
}
|
||||
};
|
||||
|
||||
// 如果关闭版本控制,关闭对象锁
|
||||
const handleVersionChange = () => {
|
||||
if (!version.value) {
|
||||
objectLock.value = false
|
||||
objectLock.value = false;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const handlePutObject = () => {
|
||||
const params = {
|
||||
const params: any = {
|
||||
Bucket: objectKey.value,
|
||||
ObjectLockEnabledForBucket: objectLock.value,
|
||||
}
|
||||
createBucket(params).then(() => {
|
||||
// 开启版本控制
|
||||
if (version.value) {
|
||||
putBucketVersioning(
|
||||
objectKey.value,
|
||||
version.value?"Enabled":"Suspended",
|
||||
).then(() => {
|
||||
emit('update:show', false)
|
||||
objectKey.value = ''
|
||||
$message.success(t('Create Success'))
|
||||
}).catch((e) => {
|
||||
$message.error(t('Create Failed'))
|
||||
})
|
||||
}else {
|
||||
emit('update:show', false)
|
||||
objectKey.value = ''
|
||||
$message.success(t('Create Success'))
|
||||
}
|
||||
|
||||
}).catch((e) => {
|
||||
$message.error(e.message)
|
||||
})
|
||||
}
|
||||
};
|
||||
createBucket(params)
|
||||
.then(() => {
|
||||
// 开启版本控制
|
||||
const afterVersioning = () => {
|
||||
// 如果需要设置 retention
|
||||
if (objectLock.value && retentionEnabled.value) {
|
||||
putObjectLockConfiguration(objectKey.value, {
|
||||
ObjectLockEnabled: "Enabled",
|
||||
Rule: {
|
||||
DefaultRetention: {
|
||||
Mode: retentionMode.value,
|
||||
Days: retentionUnit.value === "day" ? retentionPeriod.value : undefined,
|
||||
Years: retentionUnit.value === "year" ? retentionPeriod.value : undefined,
|
||||
},
|
||||
},
|
||||
})
|
||||
.then(() => {
|
||||
emit("update:show", false);
|
||||
objectKey.value = "";
|
||||
$message.success(t("Create Success"));
|
||||
})
|
||||
.catch((e) => {
|
||||
$message.error(t("Retention Save Failed"));
|
||||
});
|
||||
} else {
|
||||
emit("update:show", false);
|
||||
objectKey.value = "";
|
||||
$message.success(t("Create Success"));
|
||||
}
|
||||
};
|
||||
|
||||
if (version.value) {
|
||||
putBucketVersioning(objectKey.value, version.value ? "Enabled" : "Suspended")
|
||||
.then(afterVersioning)
|
||||
.catch(() => $message.error(t("Create Failed")));
|
||||
} else {
|
||||
afterVersioning();
|
||||
}
|
||||
})
|
||||
.catch((e) => {
|
||||
$message.error(e.message);
|
||||
});
|
||||
};
|
||||
</script>
|
||||
|
||||
+363
-147
@@ -1,128 +1,122 @@
|
||||
<template>
|
||||
<n-modal v-model:show="visible" :mask-closable="false" preset="card" :title="t('Add Lifecycle Rule') + ` (${t('Bucket')}: ${bucketName})`" class="max-w-screen-md" :segmented="{
|
||||
content: true,
|
||||
action: true,
|
||||
}">
|
||||
<n-modal
|
||||
v-model:show="visible"
|
||||
:mask-closable="false"
|
||||
preset="card"
|
||||
:title="t('Add Lifecycle Rule') + ` (${t('Bucket')}: ${bucketName})`"
|
||||
class="max-w-screen-md"
|
||||
:segmented="{
|
||||
content: true,
|
||||
action: true,
|
||||
}">
|
||||
<n-card>
|
||||
<n-tabs default-value="expire" justify-content="space-evenly" type="line">
|
||||
<n-tab-pane name="expire" :tab="t('Expiration')">
|
||||
<n-form class="my-4" ref="formRef" :model="formData">
|
||||
<n-form-item :label="t('Object Version')" path="versionType">
|
||||
<n-form class="my-4" ref="formRef" :model="formData">
|
||||
<n-tabs default-value="expire" justify-content="space-evenly" type="line" @update:value="handleUpdateValue">
|
||||
<n-tab-pane name="expire" :tab="t('Expiration')">
|
||||
<n-form-item :label="t('Object Version')" path="versionType" v-if="versioningStatus">
|
||||
<n-select v-model:value="formData.versionType" :options="versionOptions" />
|
||||
</n-form-item>
|
||||
<n-form-item label="" path="type">
|
||||
<n-form-item label="时间周期" path="type">
|
||||
<div class="w-full flex items-center justify-between">
|
||||
<span>{{ t('After') }}</span>
|
||||
<n-input-number class="flex-auto mx-4" v-model:value="formData.days" :min="1" :placeholder="t('Days')" style="width: 100px" />
|
||||
<span>{{ t('days execute') }}</span>
|
||||
<!-- <n-select
|
||||
class="flex-auto mx-4"
|
||||
v-model:value="formData.action"
|
||||
:options="actionOptions"
|
||||
style="width: 120px"
|
||||
/> -->
|
||||
<n-input-number
|
||||
class="flex-auto"
|
||||
v-model:value="formData.days"
|
||||
:min="1"
|
||||
:placeholder="t('Days')"
|
||||
style="width: 100px" />
|
||||
<span class="ms-4">{{ t("Days After") }}</span>
|
||||
</div>
|
||||
</n-form-item>
|
||||
<!-- 生命周期 -->
|
||||
<n-card>
|
||||
<n-collapse>
|
||||
<n-collapse-item :title="t('More Configurations')" name="advanced">
|
||||
<n-form-item :label="t('Prefix')">
|
||||
<n-input v-model="formData.prefix" :placeholder="t('Please enter prefix')" />
|
||||
</n-form-item>
|
||||
<n-form-item :label="t('Tags')">
|
||||
<n-dynamic-input
|
||||
v-model:value="formData.tags"
|
||||
preset="pair"
|
||||
:key-placeholder="t('Tag Name')"
|
||||
:value-placeholder="t('Tag Value')" />
|
||||
</n-form-item>
|
||||
</n-collapse-item>
|
||||
</n-collapse>
|
||||
</n-card>
|
||||
<!-- 高级设置 -->
|
||||
<n-card class="my-4" v-if="formData.versionType == 'non-current'">
|
||||
<n-collapse>
|
||||
<n-collapse-item title="高级设置" name="advanced">
|
||||
<n-form-item label="删除标记处理">
|
||||
<n-space>
|
||||
<n-switch v-model:value="formData.expiredDeleteMark" :round="false" />
|
||||
<span class="ml-4 text-gray-500">如果没有留下任何版本,请删除对该对象的引用</span>
|
||||
</n-space>
|
||||
</n-form-item>
|
||||
|
||||
<!-- <n-form-item label="版本清理">
|
||||
<n-space >
|
||||
<n-switch
|
||||
v-model:value="formData.deleteAllExpired"
|
||||
:round="false"
|
||||
/>
|
||||
<span class="ml-4 text-gray-500">删除所有过期版本</span>
|
||||
</n-space>
|
||||
</n-form-item> -->
|
||||
</n-collapse-item>
|
||||
</n-collapse>
|
||||
</n-card>
|
||||
</n-tab-pane>
|
||||
<n-tab-pane name="transition" :tab="t('Transition')">
|
||||
<n-form-item :label="t('Object Version')" path="versionType" v-if="versioningStatus">
|
||||
<n-select v-model:value="formData.versionType" :options="versionOptions" />
|
||||
</n-form-item>
|
||||
<n-form-item :label="t('Time Cycle')" path="type">
|
||||
<div class="w-full flex items-center justify-between">
|
||||
<n-input-number
|
||||
class="flex-auto"
|
||||
v-model:value="formData.days"
|
||||
:min="1"
|
||||
:placeholder="t('Days')"
|
||||
style="width: 100px" />
|
||||
<span class="ms-4">{{ t("Days After") }}</span>
|
||||
</div>
|
||||
</n-form-item>
|
||||
<n-form-item :label="t('Stroage Type')" path="storageType">
|
||||
<n-select v-model:value="formData.storageType" :options="tiers" />
|
||||
</n-form-item>
|
||||
|
||||
<!-- 生命周期 -->
|
||||
<n-card>
|
||||
<n-collapse>
|
||||
<n-collapse-item :title="t('Search Lifecycle')" name="advanced">
|
||||
<n-collapse-item :title="t('More Configurations')" name="advanced">
|
||||
<n-form-item :label="t('Prefix')">
|
||||
<n-input v-model="formData.prefix" :placeholder="t('Please enter prefix')" />
|
||||
</n-form-item>
|
||||
<n-form-item :label="t('Tags')">
|
||||
<n-dynamic-input v-model:value="formData.tags" preset="pair" :key-placeholder="t('Tag Name')" :value-placeholder="t('Tag Value')" />
|
||||
<n-dynamic-input
|
||||
v-model:value="formData.tags"
|
||||
preset="pair"
|
||||
:key-placeholder="t('Tag Name')"
|
||||
:value-placeholder="t('Tag Value')" />
|
||||
</n-form-item>
|
||||
</n-collapse-item>
|
||||
</n-collapse>
|
||||
</n-card>
|
||||
|
||||
<!-- 高级设置 -->
|
||||
<n-card class="my-4">
|
||||
<n-collapse>
|
||||
<n-collapse-item :title="t('Advanced Settings')" name="advanced">
|
||||
<n-form-item :label="t('Delete Marker Handling')">
|
||||
<n-space vertical>
|
||||
<n-switch v-model:value="formData.expiredDeleteMark" :round="false" />
|
||||
<span class="ml-4 text-gray-500">{{ t('If no versions remain, delete references to this object') }}</span>
|
||||
</n-space>
|
||||
</n-form-item>
|
||||
|
||||
<n-form-item :label="t('Version Cleanup')">
|
||||
<n-space vertical>
|
||||
<n-switch v-model:value="formData.deleteAllExpired" :round="false" />
|
||||
<span class="ml-4 text-gray-500">{{ t('Delete all expired versions') }}</span>
|
||||
</n-space>
|
||||
</n-form-item>
|
||||
</n-collapse-item>
|
||||
</n-collapse>
|
||||
</n-card>
|
||||
</n-form>
|
||||
</n-tab-pane>
|
||||
<n-tab-pane name="transition" :tab="t('Transition')">
|
||||
<n-form class="my-4" ref="formRef" :model="formData">
|
||||
<n-form-item :label="t('Object Version')" path="versionType">
|
||||
<n-select v-model:value="formData.versionType" :options="versionOptions" />
|
||||
</n-form-item>
|
||||
<n-form-item label="" path="type">
|
||||
<div class="w-full flex items-center justify-between">
|
||||
<span>{{ t('After') }}</span>
|
||||
<n-input-number class="flex-auto mx-4" v-model:value="formData.days" :min="1" :placeholder="t('Days')" style="width: 100px" />
|
||||
<span>{{ t('days execute') }}</span>
|
||||
<n-select class="flex-auto mx-4" v-model:value="formData.action" :options="actionOptions" style="width: 120px" />
|
||||
</div>
|
||||
</n-form-item>
|
||||
|
||||
<!-- 生命周期 -->
|
||||
<n-card>
|
||||
<n-collapse>
|
||||
<n-collapse-item :title="t('Search Lifecycle')" name="advanced">
|
||||
<n-form-item :label="t('Prefix')">
|
||||
<n-input v-model="formData.prefix" :placeholder="t('Please enter prefix')" />
|
||||
</n-form-item>
|
||||
<n-form-item :label="t('Tags')">
|
||||
<n-dynamic-input v-model:value="formData.tags" preset="pair" :key-placeholder="t('Tag Name')" :value-placeholder="t('Tag Value')" />
|
||||
</n-form-item>
|
||||
</n-collapse-item>
|
||||
</n-collapse>
|
||||
</n-card>
|
||||
|
||||
|
||||
<!-- 高级设置 -->
|
||||
<n-card class="my-4">
|
||||
<n-collapse>
|
||||
<n-collapse-item :title="t('Advanced Settings')" name="advanced">
|
||||
<n-form-item :label="t('Delete Marker Handling')">
|
||||
<n-space vertical>
|
||||
<n-switch v-model:value="formData.expiredDeleteMark" :round="false" />
|
||||
<span class="ml-4 text-gray-500">{{ t('If no versions remain, delete references to this object') }}</span>
|
||||
</n-space>
|
||||
</n-form-item>
|
||||
|
||||
<n-form-item :label="t('Version Cleanup')">
|
||||
<n-space vertical>
|
||||
<n-switch v-model:value="formData.deleteAllExpired" :round="false" />
|
||||
<span class="ml-4 text-gray-500">{{ t('Delete all expired versions') }}</span>
|
||||
</n-space>
|
||||
</n-form-item>
|
||||
</n-collapse-item>
|
||||
</n-collapse>
|
||||
</n-card>
|
||||
</n-form>
|
||||
</n-tab-pane>
|
||||
</n-tabs>
|
||||
|
||||
</n-tab-pane>
|
||||
</n-tabs>
|
||||
</n-form>
|
||||
|
||||
<n-space justify="center">
|
||||
<n-button @click="handleCancel">{{ t('Cancel') }}</n-button>
|
||||
<n-button type="primary" @click="handleSave">{{ t('Save') }}</n-button>
|
||||
<n-button @click="handleCancel">{{ t("Cancel") }}</n-button>
|
||||
<n-button type="primary" @click="handleSave">{{ t("Save") }}</n-button>
|
||||
</n-space>
|
||||
</n-card>
|
||||
</n-modal>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
<script setup lang="ts">
|
||||
import {
|
||||
NButton,
|
||||
NCollapse,
|
||||
@@ -133,69 +127,291 @@ import {
|
||||
NInput,
|
||||
NInputNumber,
|
||||
NSelect,
|
||||
NSwitch
|
||||
} from 'naive-ui'
|
||||
import { ref } from 'vue'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
} from "naive-ui";
|
||||
import { randomUUID } from "uncrypto";
|
||||
import { ref } from "vue";
|
||||
import { useI18n } from "vue-i18n";
|
||||
const { putBucketLifecycleConfiguration, getBucketVersioning } = useBucket({});
|
||||
const { listTiers } = useTiers();
|
||||
const { t } = useI18n();
|
||||
const message = useMessage();
|
||||
// 定义 tiers 数据结构的接口
|
||||
interface TierItem {
|
||||
label: string;
|
||||
value: string;
|
||||
}
|
||||
|
||||
const { t } = useI18n()
|
||||
const formRef = ref(null)
|
||||
const emit = defineEmits(["search"]);
|
||||
const formRef = ref();
|
||||
const formData = ref({
|
||||
ruleName: '',
|
||||
ruleName: "",
|
||||
type: null,
|
||||
versionType: 'current',
|
||||
versionType: "current",
|
||||
days: null,
|
||||
action: 'transition',
|
||||
tags: [{
|
||||
key: '',
|
||||
value: ''
|
||||
}],
|
||||
action: "transition",
|
||||
prefix: "",
|
||||
expiredDeleteMark: false,
|
||||
deleteAllExpired: false
|
||||
})
|
||||
deleteAllExpired: false,
|
||||
storageType: "",
|
||||
tags: [
|
||||
{
|
||||
key: "",
|
||||
value: "",
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
|
||||
const typeOptions = [
|
||||
{ label: t('Expiration'), value: 'expire' },
|
||||
{ label: t('Transition'), value: 'transition' }
|
||||
]
|
||||
|
||||
const versionOptions = [
|
||||
{ label: t('Current Version'), value: 'current' },
|
||||
{ label: t('Non-current Version'), value: 'non-current' }
|
||||
]
|
||||
|
||||
const actionOptions = [
|
||||
{ label: t('Transition'), value: 'transition' },
|
||||
{ label: t('Delete'), value: 'delete' }
|
||||
]
|
||||
const versionOptions = ref([
|
||||
{ label: t("Current Version"), value: "current" },
|
||||
{ label: t("Non-current Version"), value: "non-current" },
|
||||
]);
|
||||
|
||||
const props = defineProps({
|
||||
bucketName: {
|
||||
type: String,
|
||||
required: true
|
||||
}
|
||||
})
|
||||
required: true,
|
||||
},
|
||||
// 已经存在的生命周期
|
||||
lifecycleList: {
|
||||
type: Array,
|
||||
default: () => [],
|
||||
},
|
||||
});
|
||||
|
||||
const visible = ref(false)
|
||||
watch(
|
||||
() => props.bucketName,
|
||||
(newVal) => {
|
||||
// 获取是都开启版本管理
|
||||
getVersioningStatus();
|
||||
}
|
||||
);
|
||||
|
||||
const visible = ref(false);
|
||||
const open = () => {
|
||||
visible.value = true
|
||||
}
|
||||
visible.value = true;
|
||||
};
|
||||
|
||||
defineExpose({
|
||||
open
|
||||
})
|
||||
const handleSave = () => {
|
||||
formRef.value?.validate((errors) => {
|
||||
if (!errors) {
|
||||
console.log('提交数据:', formData.value)
|
||||
// 调用保存接口
|
||||
}
|
||||
})
|
||||
}
|
||||
open,
|
||||
});
|
||||
|
||||
const handleUpdateValue = (value: string) => {
|
||||
if (value === "expire") {
|
||||
formData.value.action = "expire";
|
||||
} else {
|
||||
formData.value.action = "transition";
|
||||
}
|
||||
};
|
||||
|
||||
const handleSave = () => {
|
||||
formRef.value?.validate((errors: any) => {
|
||||
if (!errors) {
|
||||
// 调用保存接口
|
||||
// const params = {
|
||||
// Rules: [
|
||||
// {
|
||||
// Status: 'Enabled',
|
||||
// Filter: {
|
||||
// Prefix: formData.value.prefix || '',
|
||||
// Tag: formData.value.tags.filter(item => item.key && item.value).map(item => {
|
||||
// return {
|
||||
// Key: item.key,
|
||||
// Value: item.value
|
||||
// }
|
||||
// }) || []
|
||||
// },
|
||||
// Expiration: {
|
||||
// Date: new Date(),
|
||||
// Days: formData.value.days,
|
||||
// },
|
||||
// }
|
||||
// ]
|
||||
// }
|
||||
|
||||
const params = {
|
||||
Rules: [
|
||||
{
|
||||
Status: "Enabled",
|
||||
Filter: {
|
||||
Prefix: "logs/", // 仅对 logs/ 前缀的对象生效
|
||||
},
|
||||
Expiration: {
|
||||
// "Days": 7,
|
||||
},
|
||||
Transition: {
|
||||
Days: 7,
|
||||
StorageClass: "MINIO",
|
||||
},
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
// const params = {
|
||||
// Rules: [
|
||||
// {
|
||||
// "ID": randomUUID(),
|
||||
// "Expiration": {
|
||||
// },
|
||||
// "Status": "Enabled",
|
||||
// "Transition": {
|
||||
// "Days": 3,
|
||||
// "StorageClass": "MINIO"
|
||||
// }
|
||||
// },
|
||||
// {
|
||||
// "ID": randomUUID(),
|
||||
// "Expiration": {
|
||||
// "Days": 5
|
||||
// },
|
||||
// "Status": "Disabled",
|
||||
// "Transition": {
|
||||
// }
|
||||
// },
|
||||
// {
|
||||
// "ID": randomUUID(),
|
||||
// "Expiration": {
|
||||
// },
|
||||
// "Status": "Enabled",
|
||||
// "Transition": {
|
||||
// "StorageClass": "MINIO",
|
||||
// "Days": 4
|
||||
// }
|
||||
// },
|
||||
// {
|
||||
// "ID": randomUUID(),
|
||||
// "Expiration": {
|
||||
// "Days": 3
|
||||
// },
|
||||
// "Status": "Enabled",
|
||||
// "Transition": {
|
||||
// }
|
||||
// },
|
||||
// {
|
||||
// "ID": randomUUID(),
|
||||
// "Expiration": {
|
||||
// "Days": 5
|
||||
// },
|
||||
// "Status": "Enabled",
|
||||
// "Transition": {
|
||||
// }
|
||||
// },
|
||||
// {
|
||||
// "ID": randomUUID(),
|
||||
// "Expiration": {
|
||||
// "ExpiredObjectDeleteMarker": true,
|
||||
// "Days": 2
|
||||
// },
|
||||
// "Status": "Enabled",
|
||||
// "Transition": {
|
||||
// }
|
||||
// },
|
||||
// {
|
||||
// "ID": randomUUID(),
|
||||
// "Expiration": {
|
||||
// "ExpiredObjectDeleteMarker": true,
|
||||
// "Days": 730
|
||||
// },
|
||||
// "Status": "Enabled",
|
||||
// "Transition": {
|
||||
// }
|
||||
// }
|
||||
// ]
|
||||
// }
|
||||
|
||||
// const params = {
|
||||
// Rules: [
|
||||
// {
|
||||
// "Status": "Enabled",
|
||||
// "Filter": { "Prefix": "archives/" },
|
||||
// "Transitions": [
|
||||
// {
|
||||
// "StorageClass": "SBHJA",
|
||||
// "Days": 90 // 90天后归档到Glacier
|
||||
// }
|
||||
// ],
|
||||
// "Expiration": {
|
||||
// "Days": 5, // 5天后删除当前版本对象
|
||||
// "ExpiredObjectDeleteMarker": true // 清理过期删除标记
|
||||
// },
|
||||
// "NoncurrentVersionTransitions": [
|
||||
// {
|
||||
// "StorageClass": "SBHJA",
|
||||
// "NoncurrentDays": 5 // 非当前版本180天后转入深度归档
|
||||
// }
|
||||
// ],
|
||||
// "NoncurrentVersionExpiration": {
|
||||
// "NoncurrentDays": 5 // 非当前版本5天后彻底删除
|
||||
// }
|
||||
// }
|
||||
// ]
|
||||
// }
|
||||
|
||||
console.log("🚀 ~ formRef.value?.validate ~ params:", params);
|
||||
|
||||
putBucketLifecycleConfiguration(props.bucketName, params)
|
||||
.then((res) => {
|
||||
visible.value = false;
|
||||
emit("search");
|
||||
message.success(t("Create Success"));
|
||||
formData.value = {
|
||||
ruleName: "",
|
||||
type: null,
|
||||
versionType: "current",
|
||||
days: null,
|
||||
action: "transition",
|
||||
expiredDeleteMark: false,
|
||||
deleteAllExpired: false,
|
||||
storageType: "",
|
||||
prefix: "",
|
||||
tags: [
|
||||
{
|
||||
key: "",
|
||||
value: "",
|
||||
},
|
||||
],
|
||||
};
|
||||
})
|
||||
.catch((e) => {
|
||||
message.error(e.message);
|
||||
});
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
// 分层列表
|
||||
const tiers = ref<TierItem[]>([]);
|
||||
const getTiers = async () => {
|
||||
const res = await listTiers();
|
||||
if (res) {
|
||||
tiers.value = res.map((item: any) => {
|
||||
return {
|
||||
label: item[item.type].name,
|
||||
value: item[item.type].name,
|
||||
};
|
||||
});
|
||||
}
|
||||
if (tiers.value.length) {
|
||||
formData.value.storageType = tiers.value[0].value;
|
||||
}
|
||||
};
|
||||
getTiers();
|
||||
|
||||
// 获取版本控制状态
|
||||
const versioningStatus: any = ref(false);
|
||||
const getVersioningStatus = async () => {
|
||||
try {
|
||||
const resp = await getBucketVersioning(props.bucketName);
|
||||
versioningStatus.value = resp.Status == "Enabled";
|
||||
} catch (error) {
|
||||
console.error("获取版本控制状态失败:", error);
|
||||
}
|
||||
};
|
||||
|
||||
onMounted(() => {
|
||||
getVersioningStatus();
|
||||
});
|
||||
const handleCancel = () => {
|
||||
// 取消逻辑
|
||||
visible.value = false
|
||||
}
|
||||
visible.value = false;
|
||||
};
|
||||
</script>
|
||||
|
||||
+74
-54
@@ -15,63 +15,65 @@ import {
|
||||
GetBucketPolicyStatusCommand,
|
||||
GetObjectLockConfigurationCommand,
|
||||
PutObjectLockConfigurationCommand,
|
||||
PutObjectRetentionCommand,
|
||||
GetObjectRetentionCommand,
|
||||
// GetBucketEncryptionCommand,
|
||||
GetBucketLifecycleConfigurationCommand,
|
||||
PutBucketLifecycleConfigurationCommand,
|
||||
DeleteBucketLifecycleCommand,
|
||||
} from "@aws-sdk/client-s3"
|
||||
} from "@aws-sdk/client-s3";
|
||||
|
||||
export function useBucket({ region }: { region?: string }) {
|
||||
const $client = useNuxtApp().$s3Client
|
||||
const $client = useNuxtApp().$s3Client;
|
||||
|
||||
const listBuckets = async () => {
|
||||
return await $client.send(new ListBucketsCommand({}))
|
||||
}
|
||||
return await $client.send(new ListBucketsCommand({}));
|
||||
};
|
||||
|
||||
const createBucket = async (params: any) => {
|
||||
return await $client.send(new CreateBucketCommand(params))
|
||||
}
|
||||
return await $client.send(new CreateBucketCommand(params));
|
||||
};
|
||||
|
||||
const headBucket = async (bucket: string) => {
|
||||
const params = {
|
||||
Bucket: bucket,
|
||||
}
|
||||
};
|
||||
|
||||
return await $client.send(new HeadBucketCommand(params));
|
||||
};
|
||||
|
||||
return await $client.send(new HeadBucketCommand(params))
|
||||
}
|
||||
|
||||
const deleteBucket = async (bucket: string) => {
|
||||
const params = {
|
||||
Bucket: bucket,
|
||||
}
|
||||
};
|
||||
|
||||
return await $client.send(new DeleteBucketCommand(params))
|
||||
}
|
||||
return await $client.send(new DeleteBucketCommand(params));
|
||||
};
|
||||
|
||||
const getBucketTagging = async (bucket: string) => {
|
||||
const params = {
|
||||
Bucket: bucket,
|
||||
}
|
||||
};
|
||||
|
||||
return await $client.send(new GetBucketTaggingCommand(params))
|
||||
}
|
||||
return await $client.send(new GetBucketTaggingCommand(params));
|
||||
};
|
||||
|
||||
const putBucketTagging = async (bucket: string, tagging: any) => {
|
||||
const params = {
|
||||
Bucket: bucket,
|
||||
Tagging: tagging,
|
||||
}
|
||||
};
|
||||
|
||||
return await $client.send(new PutBucketTaggingCommand(params))
|
||||
}
|
||||
return await $client.send(new PutBucketTaggingCommand(params));
|
||||
};
|
||||
|
||||
const deleteBucketTagging = async (bucket: string) => {
|
||||
const params = {
|
||||
Bucket: bucket,
|
||||
}
|
||||
};
|
||||
|
||||
return await $client.send(new DeleteBucketTaggingCommand(params))
|
||||
}
|
||||
return await $client.send(new DeleteBucketTaggingCommand(params));
|
||||
};
|
||||
|
||||
const putBucketVersioning = async (bucket: string, status: string) => {
|
||||
const params = {
|
||||
@@ -80,80 +82,96 @@ export function useBucket({ region }: { region?: string }) {
|
||||
Status: status == "Enabled" ? BucketVersioningStatus.Enabled : BucketVersioningStatus.Suspended,
|
||||
MFADelete: MFADelete.Enabled,
|
||||
},
|
||||
}
|
||||
};
|
||||
|
||||
return await $client.send(new PutBucketVersioningCommand(params))
|
||||
}
|
||||
return await $client.send(new PutBucketVersioningCommand(params));
|
||||
};
|
||||
|
||||
const getBucketVersioning = async (bucket: string) => {
|
||||
const params = {
|
||||
Bucket: bucket,
|
||||
}
|
||||
};
|
||||
|
||||
return await $client.send(new GetBucketVersioningCommand(params))
|
||||
}
|
||||
return await $client.send(new GetBucketVersioningCommand(params));
|
||||
};
|
||||
|
||||
const getBucketPolicy = async (bucket: string) => {
|
||||
const params = {
|
||||
Bucket: bucket,
|
||||
}
|
||||
};
|
||||
|
||||
return await $client.send(new GetBucketPolicyCommand(params))
|
||||
}
|
||||
return await $client.send(new GetBucketPolicyCommand(params));
|
||||
};
|
||||
|
||||
const getBucketPolicyStatus = async (bucket: string) => {
|
||||
const params = {
|
||||
Bucket: bucket,
|
||||
}
|
||||
};
|
||||
|
||||
return await $client.send(new GetBucketPolicyStatusCommand(params))
|
||||
}
|
||||
return await $client.send(new GetBucketPolicyStatusCommand(params));
|
||||
};
|
||||
|
||||
const putBucketPolicy = async (bucket: string, policy: string) => {
|
||||
const params = {
|
||||
Bucket: bucket,
|
||||
Policy: policy,
|
||||
}
|
||||
};
|
||||
|
||||
return await $client.send(new PutBucketPolicyCommand(params))
|
||||
}
|
||||
return await $client.send(new PutBucketPolicyCommand(params));
|
||||
};
|
||||
|
||||
const getObjectLockConfiguration = async (bucket: string) => {
|
||||
const params = {
|
||||
Bucket: bucket,
|
||||
}
|
||||
};
|
||||
|
||||
return await $client.send(new GetObjectLockConfigurationCommand(params))
|
||||
}
|
||||
return await $client.send(new GetObjectLockConfigurationCommand(params));
|
||||
};
|
||||
|
||||
const putObjectLockConfiguration = async (bucket: string, objectLockConfiguration: any) => {
|
||||
const params = {
|
||||
Bucket: bucket,
|
||||
ObjectLockConfiguration: objectLockConfiguration,
|
||||
}
|
||||
};
|
||||
|
||||
return await $client.send(new PutObjectLockConfigurationCommand(params))
|
||||
}
|
||||
return await $client.send(new PutObjectLockConfigurationCommand(params));
|
||||
};
|
||||
|
||||
const getBucketLifecycleConfiguration = async (bucket: string) => {
|
||||
const params = {
|
||||
Bucket: bucket,
|
||||
}
|
||||
return await $client.send(new GetBucketLifecycleConfigurationCommand(params))
|
||||
}
|
||||
};
|
||||
return await $client.send(new GetBucketLifecycleConfigurationCommand(params));
|
||||
};
|
||||
const putBucketLifecycleConfiguration = async (bucket: string, lifecycleConfiguration: any) => {
|
||||
const params = {
|
||||
Bucket: bucket,
|
||||
LifecycleConfiguration: lifecycleConfiguration,
|
||||
}
|
||||
return await $client.send(new PutBucketLifecycleConfigurationCommand(params))
|
||||
}
|
||||
};
|
||||
return await $client.send(new PutBucketLifecycleConfigurationCommand(params));
|
||||
};
|
||||
const deleteBucketLifecycle = async (bucket: string) => {
|
||||
const params = {
|
||||
Bucket: bucket,
|
||||
}
|
||||
return await $client.send(new DeleteBucketLifecycleCommand(params))
|
||||
}
|
||||
};
|
||||
return await $client.send(new DeleteBucketLifecycleCommand(params));
|
||||
};
|
||||
|
||||
const putObjectRetention = async (bucket: string, key: string, retention: any) => {
|
||||
const params = {
|
||||
Bucket: bucket,
|
||||
Key: key,
|
||||
Retention: retention,
|
||||
};
|
||||
return await $client.send(new PutObjectRetentionCommand(params));
|
||||
};
|
||||
const getObjectRetention = async (bucket: string, key: string) => {
|
||||
const params = {
|
||||
Bucket: bucket,
|
||||
Key: key,
|
||||
};
|
||||
return await $client.send(new GetObjectRetentionCommand(params));
|
||||
};
|
||||
|
||||
return {
|
||||
listBuckets,
|
||||
@@ -172,6 +190,8 @@ export function useBucket({ region }: { region?: string }) {
|
||||
putObjectLockConfiguration,
|
||||
getBucketLifecycleConfiguration,
|
||||
putBucketLifecycleConfiguration,
|
||||
deleteBucketLifecycle
|
||||
}
|
||||
deleteBucketLifecycle,
|
||||
putObjectRetention,
|
||||
getObjectRetention,
|
||||
};
|
||||
}
|
||||
|
||||
+22
-11
@@ -259,6 +259,11 @@
|
||||
"Rule Name Required": "Rule Name Required",
|
||||
"Rule Type Required": "Rule Type Required",
|
||||
"Version Type Required": "Version Type Required",
|
||||
"Time Cycle": "Time Cycle",
|
||||
"Transition": "Transition",
|
||||
"Days": "Days",
|
||||
"Current Version": "Current Version",
|
||||
"Non-current Version": "Non-current Version",
|
||||
"Events Management": "Events Management",
|
||||
"Events List": "Events List",
|
||||
"Add Site Replication": "Add Site Replication",
|
||||
@@ -280,19 +285,25 @@
|
||||
"S3 Compatible": "S3 Compatible",
|
||||
"Reliable distributed file system": "Reliable distributed file system",
|
||||
"Visit website": "Visit website",
|
||||
"Update Key": "Update Key" ,
|
||||
"Update Key": "Update Key",
|
||||
"Update Success": "Update Success",
|
||||
"Update Failed": "Update Failed",
|
||||
"TierNameAlreadyExist": "tier name already exists!",
|
||||
"TierNameNotUppercase" :"tier name not uppercase!",
|
||||
"TierNameBackendInUse" :"tier name backend in use!",
|
||||
"TierConnectError" :"tier connect error!",
|
||||
"TierNameAlreadyExist": "tier name already exists!",
|
||||
"TierNameNotUppercase": "tier name not uppercase!",
|
||||
"TierNameBackendInUse": "tier name backend in use!",
|
||||
"TierConnectError": "tier connect error!",
|
||||
"XRustFSAdminTierInvalidCredentials": "Invalid remote tier credentials",
|
||||
"TierAddFailed" :"tier add failed",
|
||||
"TierNotFound" :"tier not found!",
|
||||
"TierAddFailed": "tier add failed",
|
||||
"TierNotFound": "tier not found!",
|
||||
"TierMissingCredentials": "tier missing credentials!",
|
||||
"TierEditFailed" : "tier edit failed",
|
||||
"TierRemoveFailed" : "tier remove failed",
|
||||
"Usage": "Usage"
|
||||
|
||||
"TierEditFailed": "tier edit failed",
|
||||
"TierRemoveFailed": "tier remove failed",
|
||||
"Usage": "Usage",
|
||||
"Retention": "Retention",
|
||||
"Compliance": "Compliance",
|
||||
"Governance": "Governance",
|
||||
"Retention Mode": "Mode",
|
||||
"Validity": "Validity",
|
||||
"Day": "Day",
|
||||
"Year": "Year"
|
||||
}
|
||||
|
||||
+26
-12
@@ -14,7 +14,7 @@
|
||||
"Bucket Events": "存储桶事件",
|
||||
"Bucket Replication": "存储桶复制",
|
||||
"Tiered Storage": "分层存储",
|
||||
"Lifecycle": "生命周期",
|
||||
"Lifecycle": "桶生命周期",
|
||||
"Site Replication": "站点复制",
|
||||
"Performance": "性能",
|
||||
"Documentation": "文档",
|
||||
@@ -361,7 +361,15 @@
|
||||
"If no versions remain, delete references to this object": "如果没有剩余版本,则删除此对象的引用",
|
||||
"Version Cleanup": "版本清理",
|
||||
"Delete all expired versions": "删除所有过期的版本",
|
||||
"Transition": "转换",
|
||||
"Object Version": "对象版本",
|
||||
"Time Cycle": "时间周期",
|
||||
"Transition": "迁移",
|
||||
"Current Version": "当前版本",
|
||||
"Non-current Version": "非当前版本",
|
||||
"Days After": "天之后",
|
||||
"Days": "天",
|
||||
"More Configurations": "更多配置",
|
||||
"Stroage Type": "存储类型",
|
||||
"Add Bucket Replication Rule": "添加存储桶复制规则",
|
||||
"Definitions": "定义",
|
||||
"License definition paragraph": "许可证定义段落",
|
||||
@@ -472,16 +480,22 @@
|
||||
"Update Key": "更新密钥",
|
||||
"Update Success": "更新成功",
|
||||
"Update Failed": "更新失败",
|
||||
"TierNameAlreadyExist": "",
|
||||
"TierNameNotUppercase" :"分层名称必须大写!",
|
||||
"TierNameBackendInUse" :"分层名称已占用!",
|
||||
"TierConnectError" :"连接错误!",
|
||||
"TierNameAlreadyExist": "",
|
||||
"TierNameNotUppercase": "分层名称必须大写!",
|
||||
"TierNameBackendInUse": "分层名称已占用!",
|
||||
"TierConnectError": "连接错误!",
|
||||
"XRustFSAdminTierInvalidCredentials": "远程验证错误",
|
||||
"TierAddFailed" :"分层添加失败",
|
||||
"TierNotFound" :"未找到分层!",
|
||||
"TierAddFailed": "分层添加失败",
|
||||
"TierNotFound": "未找到分层!",
|
||||
"TierMissingCredentials": "验证缺失!",
|
||||
"TierEditFailed" : "分层修改失败",
|
||||
"TierRemoveFailed" : "分层删除失败",
|
||||
"Usage": "使用情况"
|
||||
|
||||
"TierEditFailed": "分层修改失败",
|
||||
"TierRemoveFailed": "分层删除失败",
|
||||
"Usage": "使用情况",
|
||||
"Retention": "保留",
|
||||
"Compliance": "合规",
|
||||
"Governance": "治理",
|
||||
"Retention Mode": "保留模式",
|
||||
"Validity": "有效期",
|
||||
"Day": "天",
|
||||
"Year": "年"
|
||||
}
|
||||
|
||||
+139
-67
@@ -2,107 +2,149 @@
|
||||
<div>
|
||||
<page-header>
|
||||
<template #title>
|
||||
<h1 class="text-2xl font-bold">{{ t('Lifecycle') }}</h1>
|
||||
<h1 class="text-2xl font-bold">{{ t("Lifecycle") }}</h1>
|
||||
</template>
|
||||
</page-header>
|
||||
<page-content class="flex flex-col gap-4">
|
||||
<div class="flex items-center justify-between">
|
||||
<div style="width:300px">
|
||||
<div style="width: 300px">
|
||||
<n-form-item :label="t('Bucket')" path="" class="flex-auto" label-placement="left">
|
||||
<n-select filterable v-model:value="bucketName" :placeholder="t('Please select bucket')" :options="bucketList" />
|
||||
<n-select
|
||||
filterable
|
||||
v-model:value="bucketName"
|
||||
:placeholder="t('Please select bucket')"
|
||||
:options="bucketList" />
|
||||
</n-form-item>
|
||||
</div>
|
||||
|
||||
<div class="flex items-center gap-4">
|
||||
<n-button @click="() => handleNew()">
|
||||
<Icon name="ri:add-line" class="mr-2" />
|
||||
<span>{{ t('Add Lifecycle Rule') }}</span>
|
||||
<span>{{ t("Add Lifecycle Rule") }}</span>
|
||||
</n-button>
|
||||
<n-button @click="">
|
||||
<n-button @click="refresh">
|
||||
<Icon name="ri:refresh-line" class="mr-2" />
|
||||
<span>{{ t('Refresh') }}</span>
|
||||
<span>{{ t("Refresh") }}</span>
|
||||
</n-button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<n-card class="flex flex-center" style="height:400px">
|
||||
<n-empty :description="t('No Data')" ></n-empty>
|
||||
<n-data-table
|
||||
class="border dark:border-neutral-700 rounded overflow-hidden"
|
||||
v-if="pageData.length > 0"
|
||||
:columns="columns"
|
||||
:data="pageData"
|
||||
:pagination="false"
|
||||
:bordered="false" />
|
||||
|
||||
<n-card class="flex flex-center" style="height: 400px" v-else>
|
||||
<n-empty :description="t('No Data')"></n-empty>
|
||||
</n-card>
|
||||
<!-- <n-data-table class="border dark:border-neutral-700 rounded overflow-hidden" :columns="columns" :data="pageData" :pagination="false" :bordered="false" /> -->
|
||||
<lifecycle-new-form ref="newRef" :bucketName="bucketName"></lifecycle-new-form>
|
||||
<lifecycle-new-form ref="newRef" :bucketName="bucketName" @search="refresh"></lifecycle-new-form>
|
||||
</page-content>
|
||||
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { Icon } from '#components'
|
||||
import { NButton, NSpace, type DataTableColumns } from 'naive-ui'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
import { Icon } from "#components";
|
||||
import { NButton, NSpace, NPopconfirm, type DataTableColumns } from "naive-ui";
|
||||
import { useI18n } from "vue-i18n";
|
||||
|
||||
const { t } = useI18n()
|
||||
const { listBuckets } = useBucket({});
|
||||
const { t } = useI18n();
|
||||
const message = useMessage();
|
||||
const { listBuckets, getBucketLifecycleConfiguration, deleteBucketLifecycle, putBucketLifecycleConfiguration } =
|
||||
useBucket({});
|
||||
const formVisible = ref(false);
|
||||
const searchTerm = ref('');
|
||||
|
||||
interface RowData {
|
||||
Name: string;
|
||||
CreationDate: string;
|
||||
Status?: string;
|
||||
ID?: string;
|
||||
Expiration?: {
|
||||
StorageClass?: string;
|
||||
Days?: number;
|
||||
Date?: string;
|
||||
};
|
||||
Filter?: {
|
||||
Prefix?: string;
|
||||
};
|
||||
Transition?: {
|
||||
Days?: number;
|
||||
StorageClass?: string;
|
||||
};
|
||||
}
|
||||
|
||||
const columns: DataTableColumns<RowData> = [
|
||||
{
|
||||
title: t('Type'),
|
||||
key: '',
|
||||
|
||||
title: t("Type"),
|
||||
key: "",
|
||||
render: (row) => {
|
||||
return h(NSpace, {}, () => {
|
||||
console.log(row?.Transition);
|
||||
if (row?.Transition?.StorageClass) {
|
||||
return t("Expire");
|
||||
} else {
|
||||
return t("Transition");
|
||||
}
|
||||
});
|
||||
},
|
||||
},
|
||||
{
|
||||
title: t('Version'),
|
||||
key: '',
|
||||
},
|
||||
{
|
||||
title: t('Expiration Delete Mark'),
|
||||
key: '',
|
||||
},
|
||||
{
|
||||
title: t('Tier'),
|
||||
key: '',
|
||||
},
|
||||
{
|
||||
title: t('Prefix'),
|
||||
key: '',
|
||||
},
|
||||
{
|
||||
title: t('Time'),
|
||||
key: '',
|
||||
},
|
||||
{
|
||||
title: t('Status'),
|
||||
key: '',
|
||||
title: t("Version"),
|
||||
key: "Transition",
|
||||
render: (row) => {
|
||||
return h(NSpace, {}, row?.Transition ? t("Current Version") : t("Non-current Version"));
|
||||
},
|
||||
},
|
||||
{
|
||||
title: t('Actions'),
|
||||
key: 'actions',
|
||||
align: 'center',
|
||||
title: t("Expiration Delete Mark"),
|
||||
key: "",
|
||||
},
|
||||
{
|
||||
title: t("Tier"),
|
||||
key: "",
|
||||
render: (row) => {
|
||||
return h(NSpace, {}, row?.Expiration?.StorageClass || "--");
|
||||
},
|
||||
},
|
||||
{
|
||||
title: t("Prefix"),
|
||||
key: "Filter",
|
||||
render: (row) => {
|
||||
return h(NSpace, {}, row?.Filter?.Prefix || "");
|
||||
},
|
||||
},
|
||||
{
|
||||
title: t("Status"),
|
||||
key: "Status",
|
||||
},
|
||||
{
|
||||
title: t("Actions"),
|
||||
key: "actions",
|
||||
align: "center",
|
||||
width: 100,
|
||||
render: (row: RowData) => {
|
||||
return h(
|
||||
NSpace,
|
||||
{
|
||||
justify: 'center',
|
||||
justify: "center",
|
||||
},
|
||||
{
|
||||
default: () => [
|
||||
h(
|
||||
NButton,
|
||||
NPopconfirm,
|
||||
{ onPositiveClick: () => handleRowDelete(row) },
|
||||
{
|
||||
size: 'small',
|
||||
secondary: true,
|
||||
onClick: (e) => handleRowDelete(row,e),
|
||||
},
|
||||
{
|
||||
default: () => '',
|
||||
icon: () => h(Icon, { name: 'ri:delete-bin-7-line' }),
|
||||
default: () => t("Confirm Delete"),
|
||||
trigger: () =>
|
||||
h(
|
||||
NButton,
|
||||
{ size: "small", secondary: true },
|
||||
{
|
||||
default: () => "",
|
||||
icon: () => h(Icon, { name: "ri:delete-bin-5-line" }),
|
||||
}
|
||||
),
|
||||
}
|
||||
),
|
||||
],
|
||||
@@ -114,10 +156,14 @@ const columns: DataTableColumns<RowData> = [
|
||||
|
||||
// 获取桶列表
|
||||
const { data } = await useAsyncData(
|
||||
'buckets',
|
||||
"buckets",
|
||||
async () => {
|
||||
const response = await listBuckets();
|
||||
return response.Buckets?.sort((a:any, b:any) => {return a.Name.localeCompare(b.Name) }) || [];
|
||||
return (
|
||||
response.Buckets?.sort((a: any, b: any) => {
|
||||
return a.Name.localeCompare(b.Name);
|
||||
}) || []
|
||||
);
|
||||
},
|
||||
{ default: () => [] }
|
||||
);
|
||||
@@ -129,19 +175,45 @@ const bucketList = computed(() => {
|
||||
}));
|
||||
});
|
||||
|
||||
const bucketName = ref<string>(
|
||||
bucketList.value.length > 0 ? bucketList.value[0]?.value ?? '' : ''
|
||||
const bucketName = ref<string>(bucketList.value.length > 0 ? bucketList.value[0]?.value ?? "" : "");
|
||||
const pageData = ref<any[]>([]);
|
||||
const loading = ref<boolean>(false);
|
||||
watch(
|
||||
() => bucketName.value,
|
||||
async (newVal) => {
|
||||
if (!newVal) return;
|
||||
|
||||
loading.value = true;
|
||||
try {
|
||||
refresh();
|
||||
} catch (error) {
|
||||
pageData.value = [];
|
||||
} finally {
|
||||
loading.value = false;
|
||||
}
|
||||
},
|
||||
{ immediate: true }
|
||||
);
|
||||
|
||||
const pageData = ref([])
|
||||
|
||||
const handleRowDelete = (row: RowData, e: Event) => {
|
||||
e.stopPropagation();
|
||||
console.log(row);
|
||||
const handleRowDelete = (row: RowData) => {
|
||||
const params = pageData.value.filter((item) => item.ID !== row.ID);
|
||||
putBucketLifecycleConfiguration(bucketName.value, { Rules: params })
|
||||
.then(async (res) => {
|
||||
message.success(t("Delete Success"));
|
||||
refresh();
|
||||
})
|
||||
.catch((e) => {
|
||||
message.error(e.message);
|
||||
});
|
||||
};
|
||||
|
||||
const newRef= ref()
|
||||
const refresh = async () => {
|
||||
const response = await getBucketLifecycleConfiguration(bucketName.value);
|
||||
pageData.value = response.Rules?.sort((a: any, b: any) => a.ID.localeCompare(b.ID)) || [];
|
||||
};
|
||||
|
||||
const newRef = ref();
|
||||
const handleNew = () => {
|
||||
newRef.value.open()
|
||||
}
|
||||
newRef.value.open();
|
||||
};
|
||||
</script>
|
||||
|
||||
@@ -140,7 +140,7 @@ const columns: DataTableColumns<RowData> = [
|
||||
},
|
||||
{
|
||||
default: () => [
|
||||
h(
|
||||
h(
|
||||
NPopconfirm,
|
||||
{ onPositiveClick: () => deleteItem(row) },
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user