Repository navigation
fix: workflow search keyword #7729
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
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -24,7 +24,20 @@ const matchedNodes = computed(() => { | |
| function focusCurrentNode() { | ||
| const node = matchedNodes.value[currentIndex.value] | ||
| props.logicFlow.clearSelectElements() | ||
| const keyword = searchKeyword.value.trim() | ||
| props.logicFlow.graphModel.nodes.forEach((nodeModel) => { | ||
| nodeModel.clearSelectOn?.() | ||
| if ( | ||
| keyword && | ||
| String(nodeModel.properties.stepName ?? '') | ||
| .toLocaleLowerCase() | ||
| .includes(keyword.toLocaleLowerCase()) | ||
| ) { | ||
| nodeModel.selectOn?.(keyword) | ||
| } | ||
| }) | ||
| if (!node) return | ||
| props.logicFlow.getNodeModelById(node.id)?.focusOn?.() | ||
| props.logicFlow.selectElementById(node.id) | ||
| props.logicFlow.focusOn(node.id) | ||
| } | ||
|
|
@@ -44,7 +57,7 @@ function closeSearch() { | |
| searchVisible.value = false | ||
| searchKeyword.value = '' | ||
| currentIndex.value = 0 | ||
| props.logicFlow.clearSelectElements() | ||
| focusCurrentNode() | ||
| } | ||
|
|
||
| function handleShortcut(event: KeyboardEvent) { | ||
|
|
@@ -61,7 +74,10 @@ watch(searchKeyword, () => { | |
| }) | ||
|
|
||
| onMounted(() => window.addEventListener('keydown', handleShortcut)) | ||
| onBeforeUnmount(() => window.removeEventListener('keydown', handleShortcut)) | ||
| onBeforeUnmount(() => { | ||
| window.removeEventListener('keydown', handleShortcut) | ||
| props.logicFlow.graphModel.nodes.forEach((node) => node.clearSelectOn?.()) | ||
| }) | ||
| </script> | ||
|
|
||
| <template> | ||
|
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Here's a review of the changes: Issues
Minor optimizations
Overall: functionally plausible, but #1 (behavior change in |
||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,7 +1,7 @@ | ||
| <script setup lang="ts"> | ||
| import { reaction, type BaseNodeModel, type Model } from '@logicflow/core' | ||
| import { computed, inject, onBeforeUnmount, onMounted, ref, watch } from 'vue' | ||
| import { cloneDeep } from 'lodash' | ||
| import { cloneDeep, escape, escapeRegExp } from 'lodash' | ||
| import { iconComponent } from '@/workflow-canvas/icons/utils' | ||
| import { copyText } from '@/utils/clipboard' | ||
| import { WorkflowMode, WorkflowNodeType, type WorkflowNodeField } from '@/workflow-canvas/types' | ||
|
|
@@ -218,23 +218,18 @@ const clearSelectOn = () => { | |
| // 高亮选中关键字 | ||
|
|
||
| const highlightedStepName = (contentText: string) => { | ||
| let res = contentText | ||
| if (keyWord.value === '') { | ||
| return res | ||
| } else { | ||
| const wordsArray = contentText.split('') | ||
| for (let i = 0; i < wordsArray.length; i++) { | ||
| const word = wordsArray[i] | ||
| if (word && keyWord.value.includes(word)) { | ||
| wordsArray[i] = currentKeyWord.value | ||
| ? `<span style='background: #FF8800;'>${word}</span>` | ||
| : `<span style='background: #FFC60A;'>${word}</span>` | ||
| } | ||
| } | ||
| res = wordsArray.join('') | ||
| return res | ||
| } | ||
| if (!keyWord.value) return escape(contentText) | ||
| const keywordPattern = new RegExp(`(${escapeRegExp(keyWord.value)})`, 'gi') | ||
| return contentText | ||
| .split(keywordPattern) | ||
| .map((part, index) => { | ||
| const text = escape(part) | ||
| if (index % 2 === 0) return text | ||
| return currentKeyWord.value ? `<span style='background: var(--mk-warning);'>${text}</span>` : `<span style='background: #FFC60A'>${text}</span>` | ||
| }) | ||
| .join('') | ||
| } | ||
|
|
||
| onMounted(() => { | ||
| model.openNodeMenu = (anchor: Model.AnchorConfig) => { | ||
| showAnchor.value && anchorData.value?.id === anchor.id ? closeNodeMenu() : openNodeMenu(anchor) | ||
|
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Code Review:
|
||
|
|
||
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.
Code Review
Main issue:
reactive(node)usage is problematicreactive()created inside the loopreactive(node)on every iteration creates an ephemeral proxy. Vue caches proxies internally, so writes do go through the same cached proxy for the same raw object, but this relies on implementation details of how LogicFlow stores nodes.reactive()may silently do nothing or cause two separate reactive systems fighting over updates.Better alternative: mutate properties via LogicFlow's own API instead of hijacking Vue reactivity:
or if direct mutation is truly needed, wrap once at a higher level (e.g.,
const nodes = reactive(props.logicFlow.graphModel.nodes)) rather than callingreactive()repeatedly inside the loop.Unavailable while batch operation — mutating every node synchronously triggers N reactive notifications; if there are many nodes, consider batching (e.g., toggling only collapsed/visible ones or using
pauseTracking-style strategies).Comment drift: the comment changed from “不替换节点数据,保留表单内容” to “与节点视图共用 Vue 响应式代理…” — that's fine, but make sure it actually describes behavior; if the "shared proxy" only works by accident of Vue's proxy cache, the comment may mislead future maintainers.
Minor suggestions
node.propertiesmay beRecord<string, unknown>; ensureshowNodeis typed, e.g. via a custom node model type.const { nodes } = props.logicFlow.graphModelbefore the loop for readability (negligible perf impact).Summary: the core risk is depending on
reactive()against non-Vue-owned objects (LogicFlow models). Prefer LogicFlow'ssetPropertyAPI; keepreactive()only for objects you create and own.