mirror of
https://github.com/Tencent/WeKnora.git
synced 2026-09-24 16:29:01 +08:00
fix(knowledge): harden batch tag dialog submit and list refresh
Keep the batch tag dialog open until the API succeeds, reset pagination after batch updates, and add structural tests for BatchTagDialog.
This commit is contained in:
@@ -1922,6 +1922,7 @@ const handleBatchTag = () => {
|
||||
};
|
||||
|
||||
const onBatchTagConfirm = async (tagIds: string[]) => {
|
||||
if (batchTagging.value || selectedIds.value.size === 0) return;
|
||||
const ids = Array.from(selectedIds.value);
|
||||
const updateMap: Record<string, string[]> = {};
|
||||
for (const id of ids) {
|
||||
@@ -1931,8 +1932,10 @@ const onBatchTagConfirm = async (tagIds: string[]) => {
|
||||
try {
|
||||
await updateKnowledgeTagBatch({ updates: updateMap });
|
||||
MessagePlugin.success(t('knowledgeBase.batchTagSuccess', { count: ids.length }));
|
||||
batchTagDialogVisible.value = false;
|
||||
clearSelection();
|
||||
batchMode.value = false;
|
||||
resetPage();
|
||||
loadKnowledgeFiles(kbId.value);
|
||||
loadTags(kbId.value, true);
|
||||
} catch (e: any) {
|
||||
@@ -2427,6 +2430,7 @@ async function createNewSession(value: string): Promise<void> {
|
||||
<BatchTagDialog :visible="batchTagDialogVisible"
|
||||
:count="selectedIds.size" :kb-id="kbId" :tag-list="tagList"
|
||||
:pre-selected-tag-ids="batchTagPreSelectedIds" :can-manage="canEdit"
|
||||
:confirm-loading="batchTagging"
|
||||
@update:visible="batchTagDialogVisible = $event" @confirm="onBatchTagConfirm"
|
||||
@tag-created="loadTags(kbId, true)" @open-manage="openTagManageFromBatchDialog" />
|
||||
|
||||
|
||||
@@ -0,0 +1,42 @@
|
||||
import assert from 'node:assert/strict'
|
||||
import test from 'node:test'
|
||||
import { readFileSync } from 'node:fs'
|
||||
|
||||
const component = readFileSync(new URL('./BatchTagDialog.vue', import.meta.url), 'utf8')
|
||||
const zhCN = readFileSync(new URL('../../../i18n/locales/zh-CN.ts', import.meta.url), 'utf8')
|
||||
const enUS = readFileSync(new URL('../../../i18n/locales/en-US.ts', import.meta.url), 'utf8')
|
||||
const koKR = readFileSync(new URL('../../../i18n/locales/ko-KR.ts', import.meta.url), 'utf8')
|
||||
const ruRU = readFileSync(new URL('../../../i18n/locales/ru-RU.ts', import.meta.url), 'utf8')
|
||||
|
||||
test('uses a compact flat dialog with selected and available sections', () => {
|
||||
assert.match(component, /dialog-class-name="batch-tag-dialog"/)
|
||||
assert.match(component, /width="420px"/)
|
||||
assert.match(component, /<template #header>/)
|
||||
assert.match(component, /class="batch-tag-heading-icon"/)
|
||||
assert.match(component, /name="discount"/)
|
||||
assert.match(component, /class="setting-drawer__section"/)
|
||||
assert.match(component, /class="setting-drawer__section-title"/)
|
||||
assert.match(component, /batchTagSelectedSection/)
|
||||
assert.match(component, /batchTagAvailableSection/)
|
||||
assert.match(component, /preSelectedTagIds/)
|
||||
assert.match(component, /confirmLoading/)
|
||||
assert.match(component, /canManage/)
|
||||
assert.match(component, /tagManageLink/)
|
||||
assert.match(component, /open-manage/)
|
||||
assert.match(component, /selectedTagsList/)
|
||||
assert.match(component, /availableTagsList/)
|
||||
assert.match(component, /class="batch-tag-chip"/)
|
||||
assert.match(component, /class="batch-tag-create-row"/)
|
||||
assert.match(component, /class="batch-tag-footer"/)
|
||||
assert.match(component, /function handleConfirm\(\) {\s*if \(props\.confirmLoading\) return;\s*emit\('confirm', Array.from\(selectedSet\.value\)\);\s*}/)
|
||||
})
|
||||
|
||||
test('defines batch tag dialog strings in every supported locale', () => {
|
||||
for (const locale of [zhCN, enUS, koKR, ruRU]) {
|
||||
assert.match(locale, /batchTagDialogHeading:/)
|
||||
assert.match(locale, /batchTagSelectedSection:/)
|
||||
assert.match(locale, /batchTagAvailableSection:/)
|
||||
assert.match(locale, /batchTagSuccess:/)
|
||||
assert.match(locale, /batchTagFailed:/)
|
||||
}
|
||||
})
|
||||
@@ -75,10 +75,10 @@
|
||||
{{ $t('knowledgeBase.tagSelectedCount', { count: selectedSet.size }) }}
|
||||
</span>
|
||||
<div class="batch-tag-footer-right">
|
||||
<t-button variant="outline" size="small" @click="handleClose">
|
||||
<t-button variant="outline" size="small" :disabled="confirmLoading" @click="handleClose">
|
||||
{{ $t('common.cancel') }}
|
||||
</t-button>
|
||||
<t-button theme="primary" size="small" :loading="saving" @click="handleConfirm">
|
||||
<t-button theme="primary" size="small" :loading="confirmLoading" @click="handleConfirm">
|
||||
{{ $t('common.confirm') }}
|
||||
</t-button>
|
||||
</div>
|
||||
@@ -106,6 +106,7 @@ const props = defineProps<{
|
||||
tagList: Tag[];
|
||||
preSelectedTagIds?: string[];
|
||||
canManage?: boolean;
|
||||
confirmLoading?: boolean;
|
||||
}>();
|
||||
|
||||
const emit = defineEmits<{
|
||||
@@ -120,7 +121,6 @@ const { t } = useI18n();
|
||||
const searchQuery = ref('');
|
||||
const selectedSet = ref<Set<string>>(new Set());
|
||||
const creatingTag = ref(false);
|
||||
const saving = ref(false);
|
||||
const newTagName = ref('');
|
||||
|
||||
watch(
|
||||
@@ -213,14 +213,9 @@ async function handleAddNewTag() {
|
||||
}
|
||||
}
|
||||
|
||||
async function handleConfirm() {
|
||||
saving.value = true;
|
||||
try {
|
||||
emit('confirm', Array.from(selectedSet.value));
|
||||
emit('update:visible', false);
|
||||
} finally {
|
||||
saving.value = false;
|
||||
}
|
||||
function handleConfirm() {
|
||||
if (props.confirmLoading) return;
|
||||
emit('confirm', Array.from(selectedSet.value));
|
||||
}
|
||||
|
||||
function handleClose() {
|
||||
|
||||
@@ -118,7 +118,9 @@ const { t } = useI18n();
|
||||
.batch-bar-actions {
|
||||
flex-shrink: 0;
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
align-items: center;
|
||||
justify-content: flex-end;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user