Skip to content

feat: Optimize the internationalization management page#42

Merged
kagol merged 3 commits into
devfrom
feat/i18info-20250521
May 27, 2025
Merged

feat: Optimize the internationalization management page#42
kagol merged 3 commits into
devfrom
feat/i18info-20250521

Conversation

@chenxi-20

@chenxi-20 chenxi-20 commented May 21, 2025

Copy link
Copy Markdown
Collaborator

PR

PR Checklist

Please check if your PR fulfills the following requirements:

  • The commit message follows our Commit Message Guidelines
  • Tests for the changes have been added (for bug fixes / features)
  • Docs have been added / updated (for bug fixes / features)

PR Type

What kind of change does this PR introduce?

  • Bugfix
  • Feature
  • Code style update (formatting, local variables)
  • Refactoring (no functional changes, no api changes)
  • Build related changes
  • CI related changes
  • Documentation content changes
  • Other... Please describe:

What is the current behavior?

Issue Number: N/A

What is the new behavior?

Does this PR introduce a breaking change?

  • Yes
  • No

Other information

Summary by CodeRabbit

  • New Features
    • Introduced batch deletion functionality for locale entries, allowing users to select and remove multiple items at once.
    • Added a new "Batch Remove" button for easy access to batch deletion.
    • Enhanced the locale table with multi-row selection and improved column layout.
  • Improvements
    • Updated single-item deletion to include a confirmation prompt.
    • Increased default page size in the locale table for better data visibility.
    • Improved button styling and table appearance for a more consistent user experience.
    • Prevented modal dialogs from closing when clicking outside to avoid accidental dismissals.

@chenxi-20 chenxi-20 added the enhancement New feature or request label May 21, 2025
@coderabbitai

coderabbitai Bot commented May 21, 2025

Copy link
Copy Markdown

Walkthrough

A batch deletion feature was introduced for i18n/locale items. Backend changes add a batch removal endpoint and service method, while frontend updates provide UI controls for selecting and deleting multiple items, with confirmation dialogs and feedback. Supporting API and styling changes were also made to integrate the new batch operation seamlessly.

Changes

Files/Paths Change Summary
template/nestJs/src/i18/i18.controller.ts
template/nestJs/src/i18/i18.service.ts
Added a POST /i18/batch endpoint and corresponding batchRemove method in both controller and service for batch deletion of i18n items by IDs, with error handling and permission checks.
template/tinyvue/src/api/local.ts Introduced batchDeleteLocal API function to send a POST request for batch deletion of locale items.
template/tinyvue/src/views/locale/components/add-locale.vue Added a "batchRemove" button next to "add", which emits a batchRemove event when clicked. The "add" button styling was updated for consistency. Dialog modals updated to disable close on outside click.
template/tinyvue/src/views/locale/components/locale-table.vue Added selection column, batch deletion logic (batchRemoveLocale), confirmation dialogs, and adjusted UI for multi-row operations. Enhanced single deletion with confirmation. Updated pager and added icon styling.
template/tinyvue/src/views/locale/index.vue Listens for batch-remove event from add-locale and triggers batch deletion on the table. Adjusted bottom padding for add button area.

Sequence Diagram(s)

sequenceDiagram
  participant User
  participant AddLocale (Button)
  participant IndexVue
  participant LocaleTable
  participant API
  participant BackendController
  participant BackendService

  User->>AddLocale: Click "Batch Remove" button
  AddLocale->>IndexVue: Emit batch-remove event
  IndexVue->>LocaleTable: Call batchRemoveLocale()
  LocaleTable->>User: Show confirmation dialog
  User-->>LocaleTable: Confirm
  LocaleTable->>API: batchDeleteLocal([ids])
  API->>BackendController: POST /i18/batch [ids]
  BackendController->>BackendService: batchRemove(ids)
  BackendService->>BackendController: Return removed items
  BackendController->>API: Respond with result
  API->>LocaleTable: Return result
  LocaleTable->>User: Show success/error message
  LocaleTable->>LocaleTable: Reload data
Loading

Poem

The bunnies now can batch away
Old locales in a single sway.
With buttons round and icons neat,
They hop through lists and clean up fleet.
A click, confirm, and off they go—
Spring cleaning, rabbit-style, you know!
🐇✨


📜 Recent review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 50498d5 and 578c319.

📒 Files selected for processing (1)
  • template/tinyvue/src/views/locale/components/add-locale.vue (3 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • template/tinyvue/src/views/locale/components/add-locale.vue

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Explain this complex logic.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai explain this code block.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and explain its main purpose.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai generate sequence diagram to generate a sequence diagram of the changes in this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 5

🔭 Outside diff range comments (1)
template/tinyvue/src/views/locale/components/add-locale.vue (1)

95-98: ⚠️ Potential issue

Update emits declaration to include the batchRemove event.

The component emits a 'batchRemove' event but it's not declared in the emits definition.

Apply this diff to update the emits declaration:

const emits = defineEmits<{
  langChange: [];
  localChange: [];
+  batchRemove: [];
}>();
🧹 Nitpick comments (1)
template/tinyvue/src/views/locale/components/add-locale.vue (1)

114-117: Clean up empty line in onBatchRemove method.

The onBatchRemove method contains an unnecessary empty line.

const onBatchRemove = () => {
-  
  emits('batchRemove') 
}
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between dcb55a5 and ee13fc1.

📒 Files selected for processing (6)
  • template/nestJs/src/i18/i18.controller.ts (1 hunks)
  • template/nestJs/src/i18/i18.service.ts (1 hunks)
  • template/tinyvue/src/api/local.ts (1 hunks)
  • template/tinyvue/src/views/locale/components/add-locale.vue (2 hunks)
  • template/tinyvue/src/views/locale/components/locale-table.vue (6 hunks)
  • template/tinyvue/src/views/locale/index.vue (2 hunks)
🔇 Additional comments (11)
template/tinyvue/src/views/locale/index.vue (3)

8-8: Event handler for batch removal added correctly.

The event listener connects the batch removal action from the add-locale component to the handler function in this component.


24-26: Implementation follows established pattern.

The onRemove function follows the same pattern as the existing onChange function, delegating the actual batch removal logic to the localTable component.


31-31: Improved vertical spacing in UI.

Increasing the bottom padding from 10px to 24px provides better visual separation between components.

template/tinyvue/src/views/locale/components/locale-table.vue (8)

16-16: Selection column added for multi-row selection.

This properly enables the batch deletion functionality by allowing users to select multiple rows.


17-17: Column widths adjusted appropriately.

The width adjustments balance the table layout to accommodate the new selection column.

Also applies to: 23-23, 30-30, 38-38


40-40: UI improvements for delete operation.

The button styling change to "text" type and the addition of an icon improve the visual consistency and user experience.

Also applies to: 44-48


56-58: Added necessary imports and initializations.

All required imports for batch deletion functionality, internationalization, and icons have been correctly added.

Also applies to: 71-74


108-109: Improved pagination configuration.

Increasing the default page size from 5 to 10 items and reorganizing the pager layout enhances usability.

Also applies to: 114-115


255-280: Added confirmation for single item deletion.

Adding a confirmation dialog before deletion is a good practice for destructive operations.


291-291: Properly exposed batch removal method.

The batch removal method is correctly exposed for use by parent components.


295-300: Added appropriate styling for delete icon.

The CSS styles for the operation icon provide proper spacing and color inheritance.

Comment on lines +178 to +189
async batchRemove(ids: number[]) {
const result = []
for (const id of ids) {
try {
const item = await this.remove(id);
result.push(item);
} catch (error) {
console.log(`删除词条 ${id} 时出错`, error);
}
}
return result;
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Consider optimizing the batch operation and improving error handling.

The current implementation has some opportunities for improvement:

  1. Sequential processing might not be efficient for large batches
  2. Error messages are in Chinese, which might not be ideal for internationalization
  3. The error handling only logs errors but doesn't provide structured feedback

Here's a suggested implementation with improved error handling:

async batchRemove(ids: number[]) {
-  const result = []
+  const result: I18[] = [];
+  const errors: {id: number, message: string}[] = [];
  for (const id of ids) {
    try {
      const item = await this.remove(id);
      result.push(item); 
    } catch (error) {
-     console.log(`删除词条 ${id} 时出错`, error);
+     const errorMessage = error instanceof HttpException 
+       ? error.message 
+       : this.i18n.t('exception.i18.removeError', {
+           args: { id },
+           lang: I18nContext.current().lang,
+         });
+     errors.push({ id, message: errorMessage });
+     console.error(`Error removing item ${id}:`, error);
    }
  } 
-  return result;
+  return { removed: result, errors };
}
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
async batchRemove(ids: number[]) {
const result = []
for (const id of ids) {
try {
const item = await this.remove(id);
result.push(item);
} catch (error) {
console.log(`删除词条 ${id} 时出错`, error);
}
}
return result;
}
async batchRemove(ids: number[]) {
// collect successful removals
const result: I18[] = [];
// collect any errors that occur
const errors: { id: number; message: string }[] = [];
for (const id of ids) {
try {
const item = await this.remove(id);
result.push(item);
} catch (error) {
// derive a user-friendly message, falling back to a translation key
const errorMessage = error instanceof HttpException
? error.message
: this.i18n.t('exception.i18.removeError', {
args: { id },
lang: I18nContext.current().lang,
});
errors.push({ id, message: errorMessage });
console.error(`Error removing item ${id}:`, error);
}
}
// return both successes and failures in a structured form
return { removed: result, errors };
}
🤖 Prompt for AI Agents
In template/nestJs/src/i18/i18.service.ts around lines 178 to 189, the
batchRemove method processes removals sequentially, uses non-internationalized
error messages, and only logs errors without structured feedback. Refactor to
process removals concurrently using Promise.allSettled for better performance,
replace Chinese error messages with English for internationalization, and
collect both successful results and errors in a structured response object to
provide comprehensive feedback.

Comment on lines +68 to +70
export const batchDeleteLocal = (ids: string[]) => {
return axios.post('/api/i18/batch', ids)
} No newline at end of file

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Fix type mismatch and add proper return type.

There's a type mismatch between the API function (using string[] ids) and the backend controller (expecting number[] ids). Also, the return type is not defined.

Apply this diff to fix the issues:

-export const batchDeleteLocal = (ids: string[]) => {
-  return axios.post('/api/i18/batch', ids)
+export const batchDeleteLocal = (ids: number[]) => {
+  return axios.post<Local[]>('/api/i18/batch', ids)
}
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
export const batchDeleteLocal = (ids: string[]) => {
return axios.post('/api/i18/batch', ids)
}
export const batchDeleteLocal = (ids: number[]) => {
return axios.post<Local[]>('/api/i18/batch', ids)
}
🤖 Prompt for AI Agents
In template/tinyvue/src/api/local.ts around lines 68 to 70, the batchDeleteLocal
function currently accepts an array of strings for ids, but the backend expects
an array of numbers, and the function lacks a defined return type. To fix this,
change the parameter type from string[] to number[], and explicitly define the
return type of the function to match the axios.post response type, ensuring type
consistency and clarity.

Comment on lines +80 to +85
@Reject()
@Permission('i18n::batch-remove')
@Post('/batch')
batchRemove(@Body() ids: number[]) {
return this.i18Service.batchRemove(ids);
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Add input validation for batch operations.

The batch removal endpoint should validate that the input is a valid array of numbers.

Apply this diff to add validation:

@Reject()
@Permission('i18n::batch-remove')
@Post('/batch')
-batchRemove(@Body() ids: number[]) {
+batchRemove(
+  @Body(new ParseArrayPipe({ items: Number, separator: ',' }))
+  ids: number[]
+) {
  return this.i18Service.batchRemove(ids);
}
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
@Reject()
@Permission('i18n::batch-remove')
@Post('/batch')
batchRemove(@Body() ids: number[]) {
return this.i18Service.batchRemove(ids);
}
@Reject()
@Permission('i18n::batch-remove')
@Post('/batch')
batchRemove(
@Body(new ParseArrayPipe({ items: Number, separator: ',' }))
ids: number[]
) {
return this.i18Service.batchRemove(ids);
}
🤖 Prompt for AI Agents
In template/nestJs/src/i18/i18.controller.ts around lines 80 to 85, the
batchRemove method lacks input validation for the ids parameter. To fix this,
add validation decorators to ensure that the input is a non-empty array of
numbers. Use class-validator decorators such as IsArray, ArrayNotEmpty, and
IsNumber on the DTO or directly on the parameter to enforce this validation
before calling the service method.

Comment on lines +216 to +253
const batchRemoveLocale = () => {
const rowIds = grid.value.getAllSelection().flatMap((row) => row.id);
if(rowIds.length === 0) {
TinyModal.message({
message: '请选择要删除的词条',
status: 'error',
});
return;
}
TinyModal.confirm({
title: '删除确认',
message: '确定要批量删除选中的用户吗?',
onConfirm: () => {
setLoading(true);
batchDeleteLocal(rowIds)
.then(() => {
TinyModal.message({
message: '批量删除成功',
status: 'success',
});
grid.value.handleFetch();
})
.catch((error) => {
if (error.response && error.response.data) {
const errorMessage = error.response.data.message || '未知错误';
TinyModal.message({
message: errorMessage,
status: 'error',
});
}
})
.finally(() => {
setLoading(false);
});
}})


}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Missing store update in batch deletion.

Unlike the single item deletion method, the batch deletion doesn't update the store state, which creates an inconsistency in state management.

Consider adding the store update after successful batch deletion:

          .then(() => {
            TinyModal.message({
              message: '批量删除成功',
              status: 'success',
            });
+           localeStore.$patch({
+             locales: localeStore.locales.filter((locale) => !rowIds.includes(locale.id)),
+           });
            grid.value.handleFetch(); 
          })
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const batchRemoveLocale = () => {
const rowIds = grid.value.getAllSelection().flatMap((row) => row.id);
if(rowIds.length === 0) {
TinyModal.message({
message: '请选择要删除的词条',
status: 'error',
});
return;
}
TinyModal.confirm({
title: '删除确认',
message: '确定要批量删除选中的用户吗?',
onConfirm: () => {
setLoading(true);
batchDeleteLocal(rowIds)
.then(() => {
TinyModal.message({
message: '批量删除成功',
status: 'success',
});
grid.value.handleFetch();
})
.catch((error) => {
if (error.response && error.response.data) {
const errorMessage = error.response.data.message || '未知错误';
TinyModal.message({
message: errorMessage,
status: 'error',
});
}
})
.finally(() => {
setLoading(false);
});
}})
}
const batchRemoveLocale = () => {
const rowIds = grid.value.getAllSelection().flatMap((row) => row.id);
if (rowIds.length === 0) {
TinyModal.message({
message: '请选择要删除的词条',
status: 'error',
});
return;
}
TinyModal.confirm({
title: '删除确认',
message: '确定要批量删除选中的用户吗?',
onConfirm: () => {
setLoading(true);
batchDeleteLocal(rowIds)
.then(() => {
TinyModal.message({
message: '批量删除成功',
status: 'success',
});
// update the store to remove the deleted locales
localeStore.$patch({
locales: localeStore.locales.filter((locale) => !rowIds.includes(locale.id)),
});
grid.value.handleFetch();
})
.catch((error) => {
if (error.response && error.response.data) {
const errorMessage = error.response.data.message || '未知错误';
TinyModal.message({
message: errorMessage,
status: 'error',
});
}
})
.finally(() => {
setLoading(false);
});
},
});
}
🤖 Prompt for AI Agents
In template/tinyvue/src/views/locale/components/locale-table.vue between lines
216 and 253, the batchRemoveLocale function performs batch deletion but does not
update the store state afterward, causing inconsistency with single item
deletion. To fix this, after the batchDeleteLocal promise resolves successfully,
add code to update the store state accordingly, ensuring the local state
reflects the deletions just like in the single deletion method.

⚠️ Potential issue

Incorrect confirmation message in batch delete.

The confirmation message refers to deleting "users" instead of locale entries.

-      message: '确定要批量删除选中的用户吗?',
+      message: '确定要批量删除选中的词条吗?',
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const batchRemoveLocale = () => {
const rowIds = grid.value.getAllSelection().flatMap((row) => row.id);
if(rowIds.length === 0) {
TinyModal.message({
message: '请选择要删除的词条',
status: 'error',
});
return;
}
TinyModal.confirm({
title: '删除确认',
message: '确定要批量删除选中的用户吗?',
onConfirm: () => {
setLoading(true);
batchDeleteLocal(rowIds)
.then(() => {
TinyModal.message({
message: '批量删除成功',
status: 'success',
});
grid.value.handleFetch();
})
.catch((error) => {
if (error.response && error.response.data) {
const errorMessage = error.response.data.message || '未知错误';
TinyModal.message({
message: errorMessage,
status: 'error',
});
}
})
.finally(() => {
setLoading(false);
});
}})
}
const batchRemoveLocale = () => {
const rowIds = grid.value.getAllSelection().flatMap((row) => row.id);
if (rowIds.length === 0) {
TinyModal.message({
message: '请选择要删除的词条',
status: 'error',
});
return;
}
TinyModal.confirm({
title: '删除确认',
message: '确定要批量删除选中的词条吗?',
onConfirm: () => {
setLoading(true);
batchDeleteLocal(rowIds)
.then(() => {
TinyModal.message({
message: '批量删除成功',
status: 'success',
});
grid.value.handleFetch();
})
.catch((error) => {
if (error.response && error.response.data) {
const errorMessage = error.response.data.message || '未知错误';
TinyModal.message({
message: errorMessage,
status: 'error',
});
}
})
.finally(() => {
setLoading(false);
});
},
});
};
🤖 Prompt for AI Agents
In template/tinyvue/src/views/locale/components/locale-table.vue between lines
216 and 253, the confirmation dialog message incorrectly mentions deleting
"users" instead of locale entries. Update the message property in
TinyModal.confirm to correctly state that the batch deletion is for selected
locale entries, ensuring the text accurately reflects the action being
performed.

@kagol kagol merged commit 09fe9c1 into dev May 27, 2025
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request nestjs web

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants