-
-
Notifications
You must be signed in to change notification settings - Fork 5.7k
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
Mark parent directory as viewed when all files are viewed #33958
base: main
Are you sure you want to change the base?
Conversation
web_src/js/utils/filetree.ts
Outdated
@@ -83,3 +83,7 @@ export function mergeChildIfOnlyOneDir(nodes: Item[]): void { | |||
} | |||
} | |||
} | |||
|
|||
export function fileIsViewed(item: Item): boolean { | |||
return item.isFile ? item.file.IsViewed : (item as DirItem).children.every(fileIsViewed); |
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.
Is this algorithm performant?
Suppose the tree it list this: a/b/c/d
and there are 100 files in the deepest dir d
.
Then you need to call fileIsViewed
about 4 * 100 = 400 times? The performance will become worse when there are more parent directories and more files.
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.
This approach should be acceptable for now, though I can't think of a more optimal algorithm at the moment. Not sure what else to try, haha.
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.
Because there are already some UI performance problems.
When using complex algorithm in Reactivity APIs, the problem becomes more complex and hard to handle.
I just want to make sure there the performance is overall good.
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.
Hmm, interesting choice with the top-down check.
I would have used a bottom-up algorithm:
When a file changes its state, the parent sets its state to are all of my direct children viewed?
.
This can propagate recursively up to the root node.
That way there shouldn't be a performance concern unless a directory has an enormous number of children.
In that case, some slowdown is to be expected however.
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.
I would have used a bottom-up algorithm:
When a file changes its state, the parent sets its state toare all of my direct children viewed?
.
Yup, that's also my intuition
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.
I've adopted a different implementation approach where child components propagate their state upwards to the parent. This helps eliminate redundant computation. Could you experts please review this approach? While my local tests confirm it achieves the same results, I'd like to get your professional opinions. @wxiaoguang @delvh
* - Directories: Compare children count with viewed count | ||
*/ | ||
const isViewed = computed(() => { | ||
return props.item.isFile ? props.item.file.IsViewed : (props.item as DirItem).children.length === count.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.
Batching the update sounds like over-engineering to me.
After all, if I read the code correctly, there's a chance of flickering for a frame.
Why not simply
return props.item.isFile ? props.item.file.IsViewed : (props.item as DirItem).children.length === count.value; | |
return props.item.isFile ? props.item.file.IsViewed : (props.item as DirItem).children.every(child => child.file.IsViewed); |
?
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.
The code(props.item.isFile ? props.item.file.IsViewed : (props.item as DirItem).children.every(child => child.file.IsViewed);
) fails to accurately retrieve folder statuses in deeply nested folder hierarchies, as the isViewed state isn't backend-maintained but dynamically computed on the fly.
This explains why I initially implemented it this way:
export function fileIsViewed(item: Item): boolean {
return item.isFile ? item.file.IsViewed : (item as DirItem).children.every(fileIsViewed);
}
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.
Ah, right.
However, that difference should be mainly for historical reasons:
Prior to this PR, the Viewed
state didn't make sense on directories, so DirItem
didn't have the attribute.
Now, it does make sense.
So we should be able to move the attribute one layer up into FileItem
and DirItem
and convert it from computed on demand into an actual attribute we update.
Then, every tree item has this attribute and we can use this approach.
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.
As discussed, moving the folder status calculation logic to the backend would require:
1. Backend complexity increase: Implementing similar computational logic as in this PR, adding architectural overhead
2. Frontend adaptation: Introducing new logic to synchronize folder read status updates
In contrast, the current PR's approach:
1. Zero backend changes: Maintains existing backend architecture
2. Frontend-driven computation: Handles folder status calculation entirely on the client-side
The biggest difference between the two is that the front - end needs to add a new logic of "reading the folder status from the back - end". The reason why the file status doesn't need to be read separately is that the interaction is initiated by the front - end, so the front - end can directly read its own status. However, if the folder status is calculated by the back - end, a new logic has to be added for reading.
I’m not sure if I’ve made myself clear.
Fix #25644
before:


after:

