Skip to content

Commit

Permalink
feat: 支持批量恢复 --story=119850786 (#17)
Browse files Browse the repository at this point in the history
  • Loading branch information
Yuikill authored Oct 29, 2024
1 parent 727761d commit 6afab1c
Show file tree
Hide file tree
Showing 7 changed files with 206 additions and 76 deletions.
20 changes: 20 additions & 0 deletions ui/src/api/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -675,3 +675,23 @@ export const createVersionNameCheck = (bizId: string, appId: number, name: strin
*/
export const importConfigFromTemplate = (bizId: string, appId: number, query: any) =>
http.post(`/config/biz/${bizId}/apps/${appId}/template_bindings/import_template_set`, query);

/**
* 批量恢复kv配置项
* @param bizId 业务ID
* @param appId 应用ID
* @param ids 恢复的id列表
* @returns
*/
export const batchUndeleteKv = (bizId: string, appId: number, keys: string[], exclusion_operation: boolean) =>
http.post(`config/biz/${bizId}/apps/${appId}/kvs/batch_undelete`, { keys, exclusion_operation });

/**
* 批量恢复服务型配置项
* @param bizId 业务ID
* @param appId 应用ID
* @param ids 恢复的id列表
* @returns
*/
export const batchUndeleteFile = (bizId: string, appId: number, ids: number[]) =>
http.post(`config/biz_id/${bizId}/app_id/${appId}/config_items/batch_undelete`, { ids });
7 changes: 7 additions & 0 deletions ui/src/i18n/en-us.ts
Original file line number Diff line number Diff line change
Expand Up @@ -528,6 +528,13 @@ export default {
'为确保最佳用户体验,此服务的配置文件数量限制为 {n} 个。当前已有 {m} 个,还可添加 {p} 个': 'In order to ensure the best user experience, the number of config files for this service is limited to {n}. There are currently {m} and you can add {p} more',
'为确保最佳用户体验,此服务的配置项数量限制为 {n} 个。当前已有 {m} 个,还可添加 {p} 个': 'In order to ensure the best user experience, the number of config items for this service is limited to {n}. There are currently {m} and you can add {p} more',
'为确保最佳用户体验,此服务的模板文件数量限制为 {n} 个。当前已有 {m} 个,还可添加 {p} 个': 'In order to ensure the best user experience, the number of template files for this service is limited to {n}. There are currently {m} and you can add {p} more',
批量恢复: 'Batch restore',
批量恢复配置文件成功: 'Batch restore configuration file successfully',
批量恢复配置项成功: 'Batch restore configuration item successfully',
'确认恢复所选的 {n} 个配置文件?': 'Confirm to restore the selected {n} configuration files?',
'确认恢复所选的 {n} 个配置项?': 'Confirm to restore the selected {n} configuration items?',
'如果所选待恢复的配置文件已存在,那么现有配置文件将被覆盖。': 'If the selected configuration file to be restored already exists, the existing configuration file will be overwritten.',
'如果所选待恢复的配置项已存在,那么现有配置项将被覆盖。': 'If the selected configuration item to be restored already exists, the existing configuration item will be overwritten.',

// 分组管理
新增分组: 'New group',
Expand Down
7 changes: 7 additions & 0 deletions ui/src/i18n/zh-cn.ts
Original file line number Diff line number Diff line change
Expand Up @@ -525,6 +525,13 @@ export default {
'为确保最佳用户体验,此服务的配置文件数量限制为 {n} 个。当前已有 {m} 个,还可添加 {p} 个': '为确保最佳用户体验,此服务的配置文件数量限制为 {n} 个。当前已有 {m} 个,还可添加 {p} 个',
'为确保最佳用户体验,此服务的配置项数量限制为 {n} 个。当前已有 {m} 个,还可添加 {p} 个': '为确保最佳用户体验,此服务的配置项数量限制为 {n} 个。当前已有 {m} 个,还可添加 {p} 个',
'为确保最佳用户体验,此服务的模板文件数量限制为 {n} 个。当前已有 {m} 个,还可添加 {p} 个': '为确保最佳用户体验,此服务的模板文件数量限制为 {n} 个。当前已有 {m} 个,还可添加 {p} 个',
批量恢复: '批量恢复',
批量恢复配置文件成功: '批量恢复配置文件成功',
批量恢复配置项成功: '批量恢复配置项成功',
'确认恢复所选的 {n} 个配置文件?': '确认恢复所选的 {n} 个配置文件?',
'确认恢复所选的 {n} 个配置项?': '确认恢复所选的 {n} 个配置项?',
'如果所选待恢复的配置文件已存在,那么现有配置文件将被覆盖。': '如果所选待恢复的配置文件已存在,那么现有配置文件将被覆盖。',
'如果所选待恢复的配置项已存在,那么现有配置项将被覆盖。': '如果所选待恢复的配置项已存在,那么现有配置项将被覆盖。',

// 分组管理
新增分组: '新增分组',
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
<template>
<bk-popover
v-if="isFileType"
ref="buttonRef"
theme="light batch-operation-button-popover"
placement="bottom-end"
Expand All @@ -9,53 +8,82 @@
:arrow="false"
@after-show="isPopoverOpen = true"
@after-hidden="isPopoverOpen = false">
<bk-button :disabled="props.selectedIds.length === 0" :class="['batch-set-btn', { 'popover-open': isPopoverOpen }]">
<bk-button
:disabled="props.selectedIds.length === 0 && !isAcrossChecked"
:class="['batch-set-btn', { 'popover-open': isPopoverOpen }]">
{{ t('批量操作') }}
<AngleDown class="angle-icon" />
</bk-button>
<template #content>
<div class="operation-item" @click="handleOpenBantchEditPerm">
<div
v-if="isFileType"
:class="['operation-item', { disabled: selectedExistCount === 0 }]"
@click="handleBatchOperation('edit')">
{{ t('批量修改权限') }}
</div>
<div class="operation-item" @click="handleOpenBantchDelet">
<div
:class="['operation-item', { disabled: selectedExistCount === 0 }]"
@click="handleBatchOperation('delete')">
{{ t('批量删除') }}
</div>
<div
:class="['operation-item', { disabled: selectedDeleteCount === 0 }]"
@click="handleBatchOperation('undelete')">
{{ t('批量恢复') }}
</div>
</template>
</bk-popover>
<bk-button
v-else
class="batch-delete-btn"
:disabled="props.selectedIds.length === 0 && !isAcrossChecked"
@click="isBatchDeleteDialogShow = true">
{{ t('批量删除') }}
</bk-button>
<DeleteConfirmDialog
v-model:is-show="isBatchDeleteDialogShow"
:title="
t('确认删除所选的 {n} 项配置项?', {
n: isAcrossChecked ? dataCount - props.selectedIds.length : props.selectedIds.length,
n: selectedExistCount,
})
"
:pending="batchDeletePending"
:pending="loading"
@confirm="handleBatchDeleteConfirm">
<div>
{{
t('已生成版本中存在的配置项,可以通过恢复按钮撤销删除,新增且未生成版本的配置项,将无法撤销删除,请谨慎操作。')
}}
</div>
</DeleteConfirmDialog>
<DeleteConfirmDialog
v-model:is-show="isBatchUndeleteDialogShow"
:title="
t(isFileType ? '确认恢复所选的 {n} 个配置文件?' : '确认恢复所选的 {n} 个配置项?', {
n: selectedDeleteCount,
})
"
:pending="loading"
:confirm-text="t('恢复')"
@confirm="handleBatchUnDeleteConfirm">
<div>
{{
isFileType
? t('如果所选待恢复的配置文件已存在,那么现有配置文件将被覆盖。')
: t('如果所选待恢复的配置项已存在,那么现有配置项将被覆盖。')
}}
</div>
</DeleteConfirmDialog>
<EditPermissionDialog
v-model:show="isBatchEditPermDialogShow"
:loading="editLoading"
:configs-length="props.selectedIds.length"
:loading="loading"
:configs-length="props.selectedItems!.length"
@confirm="handleConfimEditPermission" />
</template>
<script lang="ts" setup>
import { ref } from 'vue';
import { AngleDown } from 'bkui-vue/lib/icon';
import { useI18n } from 'vue-i18n';
import Message from 'bkui-vue/lib/message';
import { batchDeleteServiceConfigs, batchDeleteKv, batchAddConfigList } from '../../../../../../../api/config';
import {
batchDeleteServiceConfigs,
batchDeleteKv,
batchAddConfigList,
batchUndeleteKv,
batchUndeleteFile,
} from '../../../../../../../api/config';
import DeleteConfirmDialog from '../../../../../../../components/delete-confirm-dialog.vue';
import EditPermissionDialog from '../../../../../templates/list/package-detail/operations/edit-permission/edit-permission-dialog.vue';
import { IConfigItem } from '../../../../../../../../types/config';
Expand All @@ -72,54 +100,89 @@
bkBizId: string;
appId: number;
selectedIds: number[];
selectedKeys: string[];
isFileType: boolean; // 是否为文件型配置
selectedItems: IConfigItem[];
selectedItems?: IConfigItem[];
isAcrossChecked: boolean;
dataCount: number;
selectedDeleteCount: number; // 选中的删除项
selectedExistCount: number; // 选中的存在项
}>();
const emits = defineEmits(['deleted']);
const batchDeletePending = ref(false);
const loading = ref(false);
const isBatchDeleteDialogShow = ref(false);
const isBatchEditPermDialogShow = ref(false);
const isBatchUndeleteDialogShow = ref(false);
const isPopoverOpen = ref(false);
const buttonRef = ref();
const editLoading = ref(false);
const handleBatchDeleteConfirm = async () => {
batchDeletePending.value = true;
if (props.isFileType) {
await batchDeleteServiceConfigs(props.bkBizId, props.appId, props.selectedIds);
} else {
await batchDeleteKv(props.bkBizId, props.appId, props.selectedIds, props.isAcrossChecked);
loading.value = true;
try {
if (props.isFileType) {
await batchDeleteServiceConfigs(props.bkBizId, props.appId, props.selectedIds);
} else {
await batchDeleteKv(props.bkBizId, props.appId, props.selectedIds, props.isAcrossChecked);
}
Message({
theme: 'success',
message: props.isFileType ? t('批量删除配置文件成功') : t('批量删除配置项成功'),
});
isBatchDeleteDialogShow.value = false;
setTimeout(() => {
emits('deleted');
}, 300);
} catch (error) {
console.error(error);
} finally {
loading.value = false;
}
Message({
theme: 'success',
message: props.isFileType ? t('批量删除配置文件成功') : t('批量删除配置项成功'),
});
isBatchDeleteDialogShow.value = false;
setTimeout(() => {
emits('deleted');
batchDeletePending.value = false;
}, 300);
};
const handleOpenBantchEditPerm = () => {
buttonRef.value.hide();
isBatchEditPermDialogShow.value = true;
const handleBatchUnDeleteConfirm = async () => {
loading.value = true;
try {
if (props.isFileType) {
await batchUndeleteFile(props.bkBizId, props.appId, props.selectedIds);
} else {
await batchUndeleteKv(props.bkBizId, props.appId, props.selectedKeys, props.isAcrossChecked);
}
Message({
theme: 'success',
message: props.isFileType ? t('批量恢复配置文件成功') : t('批量恢复配置项成功'),
});
isBatchUndeleteDialogShow.value = false;
setTimeout(() => {
emits('deleted');
}, 300);
} catch (error) {
console.error(error);
} finally {
loading.value = false;
}
};
const handleOpenBantchDelet = () => {
const handleBatchOperation = (type: string) => {
if (type === 'delete') {
if (props.selectedExistCount === 0) return;
isBatchDeleteDialogShow.value = true;
} else if (type === 'edit') {
if (props.selectedExistCount === 0) return;
isBatchEditPermDialogShow.value = true;
} else if (type === 'undelete') {
if (props.selectedDeleteCount === 0) return;
isBatchUndeleteDialogShow.value = true;
}
buttonRef.value.hide();
isBatchDeleteDialogShow.value = true;
};
const handleConfimEditPermission = async ({ permission }: { permission: IPermissionType }) => {
try {
editLoading.value = true;
loading.value = true;
const { privilege, user, user_group } = permission;
const editConfigList = props.selectedItems.map((item) => {
const editConfigList = props.selectedItems!.map((item) => {
const { id, spec, commit_spec } = item;
return {
id,
Expand All @@ -140,7 +203,7 @@
} catch (error) {
console.error(error);
} finally {
editLoading.value = false;
loading.value = false;
}
emits('deleted');
};
Expand Down Expand Up @@ -251,7 +314,6 @@
padding: 4px 0;
border: 1px solid #dcdee5;
box-shadow: 0 2px 6px 0 #0000001a;
width: auto !important;
.operation-item {
padding: 0 12px;
min-width: 58px;
Expand All @@ -263,6 +325,10 @@
&:hover {
background: #f5f7fa;
}
&.disabled {
color: #c4c6cc;
cursor: not-allowed;
}
}
}
</style>
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,10 @@
:is-file-type="isFileType"
:selected-items="selectedItems"
:is-across-checked="isAcrossChecked"
:selected-keys="selectedKeys"
:data-count="selecTableDataCount"
:selected-delete-count="selectedDeleteCount"
:selected-exist-count="selectedExistCount"
@deleted="handleBatchDeleted" />
</div>
<SearchInput
Expand All @@ -62,8 +65,7 @@
:search-str="searchStr"
@clear-str="clearStr"
@delete-config="refreshVariable"
@update-selected-ids="selectedIds = $event"
@update-selected-items="selectedItems = $event" />
@update-selected-items="handleTmpSelectedItems" />
<TableWithKv
v-else
ref="tableRef"
Expand All @@ -72,10 +74,13 @@
:search-str="searchStr"
@send-table-data-count="selecTableDataCount = $event"
@clear-str="clearStr"
@update-selected-ids="
@update-selected-items="
(data) => {
selectedKeys = data.selectedConfigKeys;
selectedIds = data.selectedConfigIds;
isAcrossChecked = data.isAcrossChecked;
selectedExistCount = data.selectedExistCount;
selectedDeleteCount = data.selectedDeleteCount;
}
" />
</section>
Expand Down Expand Up @@ -117,6 +122,9 @@
const selectedItems = ref<any[]>([]);
const isAcrossChecked = ref(false);
const selecTableDataCount = ref(0);
const selectedKeys = ref<string[]>([]);
const selectedExistCount = ref(0); // 选中的删除项个数
const selectedDeleteCount = ref(0); // 选中的恢复项个数
const refreshConfigList = (createConfig = false) => {
if (isFileType.value) {
Expand Down Expand Up @@ -146,6 +154,13 @@
});
};
const handleTmpSelectedItems = (items: any[]) => {
selectedItems.value = items;
selectedIds.value = items.map((item) => item.id);
selectedExistCount.value = items.filter((item) => item.file_state !== 'DELETE').length;
selectedDeleteCount.value = selectedIds.value.length - selectedExistCount.value;
};
defineExpose({
refreshConfigList,
});
Expand Down
Loading

0 comments on commit 6afab1c

Please sign in to comment.