-
Notifications
You must be signed in to change notification settings - Fork 276
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat(grid-select): [grid-select] add remote feature #2530
Conversation
WalkthroughThe pull request introduces several changes across multiple Vue component files related to a grid selection interface. Key modifications include the renaming of variables for clarity, the addition of filtering methods, and the introduction of new components that enhance selection capabilities. The changes also encompass updates to the data structure and the inclusion of remote data fetching functionalities. Additionally, demo entries in the documentation have been updated to reflect these changes. Changes
Possibly related PRs
Suggested reviewers
Thank you for using CodeRabbit. We offer it for free to the OSS community and would appreciate your support in helping us grow. If you find it useful, would you consider giving us a shout-out on your favorite social media? 🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
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)
Other keywords and placeholders
CodeRabbit Configuration File (
|
[e2e-test-warn] The title of the Pull request should look like "fix(vue-renderless): [action-menu, alert] fix xxx bug". Please make sure you've read our contributing guide |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 9
🧹 Outside diff range and nitpick comments (14)
packages/renderless/src/grid-select/vue.ts (1)
Line range hint
24-28
: Consider watching remoteData updatesThe current watch only handles updates to
props.gridOp.data
. If remote data is being used, consider watching and handling remote data updates as well.watch( () => props.gridOp.data, (data) => data && (state.gridData = data), { immediate: true, deep: true } ) + // Add watch for remote data updates if needed + watch( + () => state.remoteData, + (data) => { + if (data && data.length) { + state.gridData = data + } + } + )examples/sites/demos/pc/app/grid-select/multiple-composition-api.vue (1)
Line range hint
17-29
: LGTM: Variable renamed for better clarityThe renaming from
gridOpMulti
togridOpMultiple
improves code readability. The data structure and column configuration are well-organized and properly support multiple selection functionality.Consider adding a brief JSDoc comment to document the purpose and structure of the
gridOpMultiple
configuration object:+/** + * Grid configuration for multiple selection demo + * @property {Array} data - Sample city data with area, province, and city information + * @property {Array} columns - Column definitions including selection column + */ const gridOpMultiple = reactive({examples/sites/demos/pc/app/grid-select/filter.vue (1)
Line range hint
1-38
: Consider adding loading and error statesAs a demo component, it would be beneficial to showcase proper handling of different states:
- Add loading state handling for better UX during filtering
- Include error state handling for failed operations
- Add props validation for component inputs
Consider enhancing the component with:
export default { components: { TinyGridSelect }, + props: { + initialData: { + type: Array, + default: () => [] + } + }, data() { return { valueSingle: '', + loading: false, + error: null, gridOpSingle: { data: [ // ... existing data ], columns: [ // ... existing columns ] } } } }examples/sites/demos/pc/app/grid-select/remote-composition-api.vue (4)
3-3
: Consider using i18n for text labelsThe hardcoded Chinese text should be internationalized to support multiple languages.
- <p>场景1:单选</p> + <p>{{ t('gridSelect.singleSelection') }}</p> - <p>场景2:多选</p> + <p>{{ t('gridSelect.multipleSelection') }}</p>Also applies to: 13-13
30-31
: Consider adding TypeScript type annotationsAdding type annotations would improve type safety and developer experience.
-const valueSingle = ref('') -const valueMultiple = ref([]) +const valueSingle = ref<string>('') +const valueMultiple = ref<string[]>([])
80-84
: Consider making the component responsiveThe fixed width might not work well across different screen sizes.
.tiny-grid-select { - width: 280px; + width: 100%; + max-width: 280px; + min-width: 200px; }
26-78
: Add unit tests for the remote search functionalityAs noted in the PR description, tests are missing. Please add unit tests to cover:
- Remote method behavior
- Filter function cases (empty input, case sensitivity)
- Loading state management
- Error handling scenarios
Would you like me to help generate the test cases for this component?
examples/sites/demos/pc/app/grid-select/webdoc/grid-select.js (1)
46-58
: Add missing English description for remote search demo.While the Chinese documentation is comprehensive, the English description is empty. This could impact the experience for international developers.
Consider adding an English translation similar to:
desc: { 'zh-CN': '<p>同时使用 <code>remote</code> 和 <code>remote-method</code> 和 <code>filterable</code> 3个属性开启远程搜索。通过 <code>remote-config</code> 设置自动搜索和显示展开按钮。<br>在多选模式下,可通过 <code>reserve-keyword</code> 设置选中一个选项后依然保留搜索关键字。</p>', - 'en-US': '' + 'en-US': '<p>Enable remote search by using the <code>remote</code>, <code>remote-method</code>, and <code>filterable</code> properties together. Use <code>remote-config</code> to configure auto-search and display expand button.<br>In multiple selection mode, use <code>reserve-keyword</code> to retain the search keyword after selecting an option.</p>' }examples/sites/demos/pc/app/grid-select/remote.vue (3)
5-11
: Add loading and error states for better UXThe grid-select components should handle loading and error states during remote operations:
- Add
loading
prop to show loading state during fetch- Add error handling for failed remote operations
- Add placeholder text for the search input
<tiny-grid-select v-model="valueSingle" :grid-op="gridOpSingle" filterable remote :remote-method="remoteMethod" + :loading="loading" + placeholder="Search cities..." + @error="handleError" ></tiny-grid-select>Also applies to: 15-22
3-3
: Internationalize static textConsider using i18n for the static Chinese text to support internationalization.
- <p>场景1:单选</p> + <p>{{ t('gridSelect.singleSelection') }}</p>Also applies to: 13-13
86-88
: Consider responsive designThe fixed width of 280px might not be optimal for all screen sizes.
.tiny-grid-select { - width: 280px; + width: 100%; + max-width: 280px; + min-width: 200px; }examples/sites/demos/pc/menus.js (1)
139-146
: Consider removing the code instead of commenting it out.The GridSelect component configuration is commented out, which can lead to code clutter. Since this component is being replaced with a new implementation as per the PR objectives, it would be better to remove these lines entirely.
- // { - // 'nameCn': '下拉表格选择器', - // 'name': 'GridSelect', - // 'key': 'grid-select', - // 'meta': { - // 'experimental': '3.20.0' - // } - // },packages/renderless/src/grid-select/index.ts (2)
44-44
: Useincludes
instead of bitwise NOT for clarityUsing
~selectedIds.indexOf(row[valueField])
can be confusing and less readable. Consider usingselectedIds.includes(row[valueField])
for better clarity and maintainability.Apply this diff to improve readability:
- data.filter((row) => ~selectedIds.indexOf(row[valueField])) + data.filter((row) => selectedIds.includes(row[valueField]))
47-47
: Simplify condition using!includes
for better readabilityThe expression
!~selectedIds.indexOf(row[valueField])
can be simplified to!selectedIds.includes(row[valueField])
, which is more readable and understandable.Apply this diff to simplify the condition:
- state.remoteData = data.filter((row) => !~selectedIds.indexOf(row[valueField])).concat(state.selected) + state.remoteData = data.filter((row) => !selectedIds.includes(row[valueField])).concat(state.selected)
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
📒 Files selected for processing (10)
examples/sites/demos/pc/app/grid-select/config-composition-api.vue
(3 hunks)examples/sites/demos/pc/app/grid-select/filter.vue
(2 hunks)examples/sites/demos/pc/app/grid-select/multiple-composition-api.vue
(2 hunks)examples/sites/demos/pc/app/grid-select/multiple.vue
(2 hunks)examples/sites/demos/pc/app/grid-select/remote-composition-api.vue
(1 hunks)examples/sites/demos/pc/app/grid-select/remote.vue
(1 hunks)examples/sites/demos/pc/app/grid-select/webdoc/grid-select.js
(2 hunks)examples/sites/demos/pc/menus.js
(1 hunks)packages/renderless/src/grid-select/index.ts
(1 hunks)packages/renderless/src/grid-select/vue.ts
(1 hunks)
🔇 Additional comments (14)
packages/renderless/src/grid-select/vue.ts (1)
11-11
: Verify remote data handling implementation
The remoteData
state is initialized but there's no visible handling of remote data updates. Ensure that remote data fetching and updates are properly implemented.
✅ Verification successful
Let me try a different search strategy to verify the remote data handling implementation.
Let me search for the remote data handling implementation in the grid-select component and its related files.
Based on the code analysis, I can now provide the final response:
Remote data handling is properly implemented
The remoteData
state is correctly handled within the filter
function when remote
prop is true:
- Remote data fetching is triggered through
remoteMethod
prop - Results are properly processed for both single and multiple selection modes
- Remote data is stored in state and loaded into the grid
- Selected items are preserved and merged with remote data in multiple selection mode
🏁 Scripts executed
The following scripts were executed for the analysis:
Script:
#!/bin/bash
# Search for remote data handling implementation
echo "Searching for remote data handling..."
rg -l "remoteData" --type vue
ast-grep --pattern 'watch($$$remoteData$$$)'
Length of output: 189
Script:
#!/bin/bash
# Search for remote data handling in TypeScript files
echo "Searching for remote data handling in the grid-select component..."
rg "remoteData" -A 5 --type ts
# Look for watch implementations
echo -e "\nSearching for watch implementations..."
ast-grep --pattern 'watch($$$)'
# Look for the complete grid-select component implementation
echo -e "\nSearching for the grid-select component file content..."
cat packages/renderless/src/grid-select/vue.ts
Length of output: 156674
Script:
#!/bin/bash
# Search for remote data handling in grid-select implementation
echo "Searching for remote data handling in grid-select implementation..."
rg -A 10 "remoteData" packages/renderless/src/grid-select/
# Look for remote-related functionality in index.ts
echo -e "\nChecking grid-select index.ts..."
cat packages/renderless/src/grid-select/index.ts
Length of output: 5236
examples/sites/demos/pc/app/grid-select/multiple-composition-api.vue (2)
5-5
: LGTM: Template binding updated correctly
The grid-op binding is properly synchronized with the renamed reactive variable.
Line range hint 1-35
: Verify remote search feature implementation
The PR objectives mention adding a remote search feature, but this demo file only implements basic multiple selection functionality. Let's verify if the remote search feature is implemented in other demo files.
examples/sites/demos/pc/app/grid-select/multiple.vue (3)
5-5
: LGTM! Property binding updated consistently
The grid-op property binding has been updated to use the renamed variable, maintaining consistency with similar changes across other files.
21-21
: LGTM! Improved variable naming
The rename from treeOp
to gridOpMultiple
better reflects the purpose of this configuration object, making the code more maintainable and self-documenting.
Line range hint 21-35
: Verify remote feature implementation
Since this PR introduces a remote search feature, let's verify how it integrates with this multiple selection demo.
examples/sites/demos/pc/app/grid-select/filter.vue (1)
21-21
: Verify the impact of changing valueSingle type from array to string
The change from array to string type aligns with single selection mode, but could be a breaking change if other code depends on the array type.
✅ Verification successful
Let me gather more information by searching the content of the documentation files and checking for any other Vue files in the grid-select directory.
No breaking changes found - valueSingle consistently uses string type
The search results show that valueSingle
is consistently initialized as an empty string (''
) across all grid-select examples, including both Options API (remote.vue
, config.vue
) and Composition API (remote-composition-api.vue
, config-composition-api.vue
, filter-composition-api.vue
) implementations. This confirms that the string type for valueSingle
is the standard pattern, not a breaking change.
🏁 Scripts executed
The following scripts were executed for the analysis:
Script:
#!/bin/bash
# Search for other usages of valueSingle to verify compatibility
rg -l "valueSingle" --type vue
# Search for any documentation or tests related to this component
fd -e md -e spec.js -e test.js grid-select
Length of output: 233
Script:
#!/bin/bash
# Check content of documentation files
cat examples/sites/demos/pc/app/grid-select/webdoc/grid-select.cn.md examples/sites/demos/pc/app/grid-select/webdoc/grid-select.en.md
# Find all Vue files in grid-select directory
fd -e vue grid-select
# Use grep without file type to find valueSingle references
rg "valueSingle"
Length of output: 1538
examples/sites/demos/pc/app/grid-select/remote-composition-api.vue (1)
26-29
: LGTM!
Clean and minimal imports using the Composition API.
examples/sites/demos/pc/app/grid-select/config-composition-api.vue (2)
31-31
: Review the selection logic restrictions.
The current implementation has potentially confusing row selection restrictions:
- Single selection (radio) only allows odd-indexed rows (
rowIndex % 2 === 1
) - Multiple selection only allows even-indexed rows (
rowIndex % 2 === 0
)
This might lead to a confusing user experience where some rows are inexplicably disabled in different selection modes.
Let's check if this is consistent with other grid-select examples:
#!/bin/bash
# Search for other checkMethod implementations in grid-select components
rg -A 5 "checkMethod.*rowIndex" --type vue examples/sites/demos/pc/app/grid-select/
Also applies to: 49-49, 65-77
16-16
: Variable renaming improves clarity but remote feature is missing.
The renaming from valueMulti
/gridOpMulti
to valueMultiple
/gridOpMultiple
improves code readability. However, the PR objectives mention adding a remote search feature, which is not implemented in this component.
Let's verify if the remote search feature is implemented elsewhere:
Also applies to: 20-20
examples/sites/demos/pc/app/grid-select/webdoc/grid-select.js (2)
41-41
: LGTM! Clear and well-formatted documentation.
The description clearly explains the filterable functionality and its configuration options.
67-67
: LGTM! Proper HTML formatting.
The description is well-structured with proper HTML formatting using <br>
tags.
examples/sites/demos/pc/app/grid-select/remote.vue (1)
27-32
: Verify component registration
The component import and registration look correct. Let's verify the component's availability in the package.
✅ Verification successful
The previous command failed because vue
file type wasn't recognized. Let's search across all files and also look for any mentions of the component to verify its existence and proper export.
The component is being used consistently across multiple demo files, but let's verify its actual export from the package to ensure it's properly exported and available.
Component import and registration are correct
The verification confirms that:
TinyGridSelect
is properly exported frompackages/vue/src/grid-select/index.ts
- The component is consistently used across multiple demo files in the same way
- The import from '@opentiny/vue' and component registration in the file are correct
🏁 Scripts executed
The following scripts were executed for the analysis:
Script:
#!/bin/bash
# Verify TinyGridSelect component export
rg -l "export.*TinyGridSelect" --type vue
Length of output: 71
Script:
#!/bin/bash
# Search for TinyGridSelect export in all files
rg -l "export.*TinyGridSelect"
# Also search for any mentions of TinyGridSelect
rg "TinyGridSelect"
Length of output: 1497
Script:
#!/bin/bash
# Let's verify the actual export from @opentiny/vue package
rg -A 5 "export.*GridSelect"
# Also check if there are any index files that might be re-exporting the component
fd -e js -e ts "index" -x rg -l "GridSelect" {}
Length of output: 4029
examples/sites/demos/pc/menus.js (1)
Line range hint 391-419
: Review the security implications of business components exposure.
The business components section contains sensitive components like User, Company, Currency, etc. While there is a check for envTarget === 'inner'
, the showBusiness
condition based on URL path could potentially expose these components in unintended environments.
✅ Verification successful
Business components access control is properly implemented
The verification shows that the business components exposure is properly controlled through multiple layers:
-
The business components are only exposed when either:
envTarget === 'inner'
(internal environment) ORshowBusiness
is true, which is only set when the path explicitly includes '/all'
-
The implementation shows this is a documentation/demo site feature rather than production code, as evidenced by:
- The code exists in
examples/sites/demos/pc/menus.js
- The components are part of a documentation menu structure
- No actual sensitive business logic implementation was found in the codebase
- The code exists in
The current implementation provides appropriate access control for business component documentation, and no security concerns were identified.
🏁 Scripts executed
The following scripts were executed for the analysis:
Script:
#!/bin/bash
# Description: Verify the security implications of business components exposure
# Check if there are any direct routes to business components without proper guards
rg -l "path.*(/all|/business)" -g "!menus.js"
# Check for any hardcoded environment checks related to business components
rg "envTarget.*inner.*business" -g "!menus.js"
Length of output: 146
Script:
#!/bin/bash
# Let's check the content of the build-runtime.ts to understand the context
cat internals/cli/src/commands/build/build-runtime.ts
# Let's also check for any environment-based routing or access control patterns
rg -g "*.{js,ts}" "envTarget|environment.*inner" -A 2 -B 2
# Check for business component imports and their usage
rg -g "*.{js,ts}" "import.*Business|business.*component" -A 2 -B 2
# Look for any router configuration or route guards
rg -g "*.{js,ts}" "router.*(guard|beforeEach|middleware)" -A 2 -B 2
Length of output: 8396
Script:
#!/bin/bash
# Let's check for any route definitions or access controls related to business components
rg -g "*.{js,ts,vue}" "showBusiness|cmp-business-components" -A 5 -B 5
# Check for any authentication or authorization mechanisms
rg -g "*.{js,ts,vue}" "auth|isAuthenticated|checkAccess" -A 3 -B 3
# Look for environment configuration files
fd -e env -e env.development -e env.production
# Check the actual business components implementation
rg -g "*.{js,ts,vue}" "export.*class.*(User|Company|Currency|Amount)" -A 3 -B 3
Length of output: 7623
gridData: props.gridOp.data | ||
gridData: props.gridOp.data, | ||
remoteData: [], | ||
selected: props.multiple ? [] : {} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Consider type safety for selected property
The selected
property switches between array and object types based on props.multiple
. This could lead to type-related issues in consuming components.
Consider using TypeScript or adding runtime type checking:
- selected: props.multiple ? [] : {}
+ selected: props.multiple ? [] : {},
+ type: props.multiple ? 'multiple' : 'single'
Also, consider adding prop validation:
props: {
multiple: {
type: Boolean,
default: false
}
}
filter(value) { | ||
if (!value) { | ||
return this.gridOpSingle.data | ||
} | ||
|
||
return this.gridOpSingle.data.filter((item) => { | ||
return item.city.includes(value) | ||
}) | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Enhance filter method robustness and performance
The current implementation could benefit from several improvements:
- Add error handling for malformed data
- Make the search case-insensitive for better user experience
- Consider filtering across multiple fields (area, province, city)
- Consider debouncing for large datasets
Consider this improved implementation:
filter(value) {
if (!value) {
return this.gridOpSingle.data
}
+ const searchTerm = value.toLowerCase()
return this.gridOpSingle.data.filter((item) => {
- return item.city.includes(value)
+ try {
+ return (
+ item.city?.toLowerCase().includes(searchTerm) ||
+ item.area?.toLowerCase().includes(searchTerm) ||
+ item.province?.toLowerCase().includes(searchTerm)
+ )
+ } catch (error) {
+ console.warn('Malformed data in grid item:', item)
+ return false
+ }
})
}
📝 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.
filter(value) { | |
if (!value) { | |
return this.gridOpSingle.data | |
} | |
return this.gridOpSingle.data.filter((item) => { | |
return item.city.includes(value) | |
}) | |
} | |
filter(value) { | |
if (!value) { | |
return this.gridOpSingle.data | |
} | |
const searchTerm = value.toLowerCase() | |
return this.gridOpSingle.data.filter((item) => { | |
try { | |
return ( | |
item.city?.toLowerCase().includes(searchTerm) || | |
item.area?.toLowerCase().includes(searchTerm) || | |
item.province?.toLowerCase().includes(searchTerm) | |
) | |
} catch (error) { | |
console.warn('Malformed data in grid item:', item) | |
return false | |
} | |
}) | |
} |
const gridOpSingle = reactive({ | ||
data: [], | ||
height: 300, | ||
columns: [ | ||
{ type: 'radio', title: '' }, | ||
{ field: 'area', title: '区域', width: 90 }, | ||
{ field: 'province', title: '省份', width: 60 }, | ||
{ field: 'city', title: '城市', width: 60 } | ||
] | ||
}) | ||
|
||
const gridOpMultiple = reactive({ | ||
data: [], | ||
height: 300, | ||
columns: [ | ||
{ type: 'selection', title: '' }, | ||
{ field: 'area', title: '区域', width: 90 }, | ||
{ field: 'province', title: '省份', width: 60 }, | ||
{ field: 'city', title: '城市', width: 60 } | ||
] | ||
}) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Consider extracting common configuration and improving flexibility
The grid configurations have duplicated structure that could be refactored.
+const baseColumns = [
+ { field: 'area', title: '区域', width: 90 },
+ { field: 'province', title: '省份', width: 60 },
+ { field: 'city', title: '城市', width: 60 }
+]
+const createGridOp = (selectionType) => reactive({
+ data: [],
+ height: 300,
+ columns: [
+ { type: selectionType, title: '' },
+ ...baseColumns
+ ]
+})
-const gridOpSingle = reactive({...})
-const gridOpMultiple = reactive({...})
+const gridOpSingle = createGridOp('radio')
+const gridOpMultiple = createGridOp('selection')
Also consider:
- Making the height responsive or configurable
- Adding column resize and sort capabilities
- Adding column min/max width constraints
📝 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.
const gridOpSingle = reactive({ | |
data: [], | |
height: 300, | |
columns: [ | |
{ type: 'radio', title: '' }, | |
{ field: 'area', title: '区域', width: 90 }, | |
{ field: 'province', title: '省份', width: 60 }, | |
{ field: 'city', title: '城市', width: 60 } | |
] | |
}) | |
const gridOpMultiple = reactive({ | |
data: [], | |
height: 300, | |
columns: [ | |
{ type: 'selection', title: '' }, | |
{ field: 'area', title: '区域', width: 90 }, | |
{ field: 'province', title: '省份', width: 60 }, | |
{ field: 'city', title: '城市', width: 60 } | |
] | |
}) | |
const baseColumns = [ | |
{ field: 'area', title: '区域', width: 90 }, | |
{ field: 'province', title: '省份', width: 60 }, | |
{ field: 'city', title: '城市', width: 60 } | |
] | |
const createGridOp = (selectionType) => reactive({ | |
data: [], | |
height: 300, | |
columns: [ | |
{ type: selectionType, title: '' }, | |
...baseColumns | |
] | |
}) | |
const gridOpSingle = createGridOp('radio') | |
const gridOpMultiple = createGridOp('selection') |
const filter = (value) => { | ||
return allData.filter((item) => item.city.includes(value)) | ||
} | ||
|
||
const remoteMethod = (value) => { | ||
const filterData = filter(value) | ||
|
||
return new Promise((resolve) => { | ||
setTimeout(() => { | ||
resolve(filterData) | ||
}, 500) | ||
}) | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Improve robustness of remote search implementation
The current implementation has several areas that need improvement:
- Case-sensitive exact matching might not be user-friendly
- No error handling in the remote method
- No loading state management
- No debouncing of remote calls
+const isLoading = ref(false)
+
+const debounce = (fn, delay) => {
+ let timeoutId
+ return (...args) => {
+ clearTimeout(timeoutId)
+ return new Promise((resolve) => {
+ timeoutId = setTimeout(() => resolve(fn(...args)), delay)
+ })
+ }
+}
+
const filter = (value) => {
- return allData.filter((item) => item.city.includes(value))
+ const searchTerm = value.toLowerCase()
+ return allData.filter((item) =>
+ item.city.toLowerCase().includes(searchTerm) ||
+ item.province.toLowerCase().includes(searchTerm) ||
+ item.area.toLowerCase().includes(searchTerm)
+ )
}
-const remoteMethod = (value) => {
+const remoteMethod = debounce(async (value) => {
+ if (!value) return []
+
+ isLoading.value = true
const filterData = filter(value)
-
- return new Promise((resolve) => {
+ try {
+ await new Promise((resolve) => {
setTimeout(() => {
resolve(filterData)
}, 500)
})
-}
+ return filterData
+ } catch (error) {
+ console.error('Failed to fetch data:', error)
+ return []
+ } finally {
+ isLoading.value = false
+ }
+}, 300)
📝 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.
const filter = (value) => { | |
return allData.filter((item) => item.city.includes(value)) | |
} | |
const remoteMethod = (value) => { | |
const filterData = filter(value) | |
return new Promise((resolve) => { | |
setTimeout(() => { | |
resolve(filterData) | |
}, 500) | |
}) | |
} | |
const isLoading = ref(false) | |
const debounce = (fn, delay) => { | |
let timeoutId | |
return (...args) => { | |
clearTimeout(timeoutId) | |
return new Promise((resolve) => { | |
timeoutId = setTimeout(() => resolve(fn(...args)), delay) | |
}) | |
} | |
} | |
const filter = (value) => { | |
const searchTerm = value.toLowerCase() | |
return allData.filter((item) => | |
item.city.toLowerCase().includes(searchTerm) || | |
item.province.toLowerCase().includes(searchTerm) || | |
item.area.toLowerCase().includes(searchTerm) | |
) | |
} | |
const remoteMethod = debounce(async (value) => { | |
if (!value) return [] | |
isLoading.value = true | |
const filterData = filter(value) | |
try { | |
await new Promise((resolve) => { | |
setTimeout(() => { | |
resolve(filterData) | |
}, 500) | |
}) | |
return filterData | |
} catch (error) { | |
console.error('Failed to fetch data:', error) | |
return [] | |
} finally { | |
isLoading.value = false | |
} | |
}, 300) |
filter(value) { | ||
return this.allData.filter((item) => item.city.includes(value)) | ||
}, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Enhance filter method robustness
The current filter implementation has several limitations:
- No input validation
- Case-sensitive search
- Only searches the city field
filter(value) {
- return this.allData.filter((item) => item.city.includes(value))
+ if (!value?.trim()) return this.allData
+ const searchValue = value.toLowerCase().trim()
+ return this.allData.filter((item) =>
+ item.city.toLowerCase().includes(searchValue) ||
+ item.province.toLowerCase().includes(searchValue) ||
+ item.area.toLowerCase().includes(searchValue)
+ )
}
📝 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.
filter(value) { | |
return this.allData.filter((item) => item.city.includes(value)) | |
}, | |
filter(value) { | |
if (!value?.trim()) return this.allData | |
const searchValue = value.toLowerCase().trim() | |
return this.allData.filter((item) => | |
item.city.toLowerCase().includes(searchValue) || | |
item.province.toLowerCase().includes(searchValue) || | |
item.area.toLowerCase().includes(searchValue) | |
) | |
}, |
allData: Array.from({ length: 1000 }, (a, i) => { | ||
return { | ||
value: '00' + i, | ||
province: '省份' + i, | ||
city: '城市' + i, | ||
area: '区域' + i, | ||
label: `省${i}-市${i}` | ||
} | ||
}) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Consider lazy loading mock data
Creating a large array of 1000 items during component initialization could impact initial load performance.
- allData: Array.from({ length: 1000 }, (a, i) => {
- return {
- value: '00' + i,
- province: '省份' + i,
- city: '城市' + i,
- area: '区域' + i,
- label: `省${i}-市${i}`
- }
- })
+ allData: [],
+ // Move data generation to created/mounted hook or on-demand
+ generateMockData(count = 1000) {
+ this.allData = Array.from({ length: count }, (a, i) => ({
+ value: '00' + i,
+ province: '省份' + i,
+ city: '城市' + i,
+ area: '区域' + i,
+ label: `省${i}-市${i}`
+ }))
+ }
Committable suggestion skipped: line range outside the PR's diff.
remoteMethod(value) { | ||
const filterData = this.filter(value) | ||
|
||
return new Promise((resolve) => { | ||
setTimeout(() => { | ||
resolve(filterData) | ||
}, 500) | ||
}) | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Improve remote method implementation
The remoteMethod implementation needs enhancement:
- Add error handling
- Make timeout configurable
- Add request debouncing
+ data() {
+ return {
+ // ... existing data
+ searchTimeout: 500,
+ loading: false
+ }
+ },
methods: {
+ debounce(fn, delay) {
+ let timeoutId
+ return (...args) => {
+ clearTimeout(timeoutId)
+ return new Promise((resolve) => {
+ timeoutId = setTimeout(() => resolve(fn.apply(this, args)), delay)
+ })
+ }
+ },
remoteMethod(value) {
+ this.loading = true
const filterData = this.filter(value)
return new Promise((resolve) => {
setTimeout(() => {
+ this.loading = false
resolve(filterData)
- }, 500)
+ }, this.searchTimeout)
+ }).catch(error => {
+ this.loading = false
+ console.error('Remote search failed:', error)
+ throw error
})
}
}
Committable suggestion skipped: line range outside the PR's diff.
remoteMethod(value, props.extraQueryParams).then((data) => { | ||
// 多选时取远端数据与当前已选数据的并集 | ||
if (multiple) { | ||
const selectedIds = state.selected.map((sel) => sel[valueField]) | ||
vm.$refs.gridRef.clearSelection() | ||
vm.$refs.gridRef.setSelection( | ||
data.filter((row) => ~selectedIds.indexOf(row[valueField])), | ||
true | ||
) | ||
state.remoteData = data.filter((row) => !~selectedIds.indexOf(row[valueField])).concat(state.selected) | ||
} else { | ||
vm.$refs.gridRef.clearRadioRow() | ||
vm.$refs.gridRef.setRadioRow(find(data, (item) => props.modelValue === item[props.valueField])) | ||
state.remoteData = data | ||
} | ||
|
||
vm.$refs.gridRef.$refs.tinyTable.lastScrollTop = 0 | ||
vm.$refs.gridRef.loadData(data) | ||
vm.$refs.gridRef.handleTableData(!value) | ||
}) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Add error handling for the remote data fetch
Currently, the remoteMethod
call does not handle errors if the Promise is rejected. It's crucial to add error handling to prevent unhandled promise rejections and to provide feedback to the user in case of failure.
Consider adding a .catch
block to handle possible errors:
remoteMethod(value, props.extraQueryParams)
.then((data) => {
// existing code
})
.catch((error) => {
// handle the error, e.g., show an error message or update the state
})
state.remoteData = data.filter((row) => !~selectedIds.indexOf(row[valueField])).concat(state.selected) | ||
} else { | ||
vm.$refs.gridRef.clearRadioRow() | ||
vm.$refs.gridRef.setRadioRow(find(data, (item) => props.modelValue === item[props.valueField])) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ensure find
is correctly used or imported
The find
function used here may not be defined in this context. If you're intending to use the native Array find
method, adjust the syntax accordingly.
Modify the code to use the Array find
method:
- vm.$refs.gridRef.setRadioRow(find(data, (item) => props.modelValue === item[props.valueField]))
+ vm.$refs.gridRef.setRadioRow(data.find((item) => props.modelValue === item[props.valueField]))
If find
is a utility function from a library like Lodash, ensure it is properly imported.
📝 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.
vm.$refs.gridRef.setRadioRow(find(data, (item) => props.modelValue === item[props.valueField])) | |
vm.$refs.gridRef.setRadioRow(data.find((item) => props.modelValue === item[props.valueField])) |
PR
主要更新:
效果如下:
PR Checklist
Please check if your PR fulfills the following requirements:
PR Type
What kind of change does this PR introduce?
What is the current behavior?
Issue Number: N/A
What is the new behavior?
Does this PR introduce a breaking change?
Other information
Summary by CodeRabbit
New Features
Bug Fixes
Documentation
Chores