Skip to content

Conversation

Gr8z
Copy link
Contributor

@Gr8z Gr8z commented May 23, 2025

Description

This pull request introduces a new feature to filter changes in the repository by file type and status (new, modified, deleted, unstaged, and staged files). The most important changes include updates to the state management, UI components, and dispatcher logic to support these new filters.

State Management Updates:

  • Added new state properties (filterNewFiles, filterModifiedFiles, filterDeletedFiles, filterUnstagedFiles) to IChangesState and initialized them in getInitialRepositoryState. [1] [2]
  • Updated the createState helper in tests to include the new filter properties.

UI Enhancements:

  • Expanded the FilterChangesList component to include checkboxes for the new filters, dynamically calculate filter counts, and display the number of active filters. [1] [2] [3] [4]
  • Adjusted the "no results" message to account for the new filters and their combinations.
  • Updated the ChangesSidebar to pass the new filter states to the FilterChangesList component.

Dispatcher and Store Logic:

  • Added methods in AppStore and Dispatcher to handle updates to the new filter states (_setFilterNewFiles, _setFilterModifiedFiles, etc.). [1] [2]

These changes collectively enhance the user experience by allowing more granular control over the displayed changes in the repository.

Screenshots

image
image
image

Release notes

Notes: Added comprehensive filter functionality for the changes list, allowing users to filter files by status (modified, new, deleted, untracked) for better repository management.

- Implement robust filtering for working directory file changes
- Add filter state management to app store and repository cache
- Update UI components (sidebar, filter-changes-list) for filter support
- Enhance dispatcher with filter-related actions
- Add comprehensive test suite covering all filter scenarios
- Include unit tests and integration tests for filter functionality
@github-actions github-actions bot added external Pull request originating outside of the Desktop core team triage For incoming issues labels May 23, 2025
@Gr8z Gr8z marked this pull request as ready for review May 26, 2025 07:56
@Gr8z
Copy link
Contributor Author

Gr8z commented May 26, 2025

Why are GH Actions not running on this PR?

@tidy-dev
Copy link
Contributor

tidy-dev commented May 27, 2025

@Gr8z Thank you for wanting to contribute.

I will bring this up for team discussion

And, a few things off hand:

  • PR's that do not solve an existing issue with the "help-wanted" label are not likely to be merged. It is unclear that the change is a largely desired by the user base - in this case we want to ensure we are adding meaningful filters not a filters for sake of filtering. Secondly, we don't want to see you commit your time to a PR that will not get approved.
  • GitHub Desktop does not stage files when you check them. It stages the files upon the user hitting commit. Thus "staged" and "unstaged" is inaccurate terminology; we would need to keep along the lines of "Included in commit"/"Excluded in commit".
  • Lastly, just curious why you chose filtering via exclusion versus inclusion? Aka, having all filters checked where unchecking narrows the filter as opposed to starting with filters unchecked and checking a filter option narrows the search. I can see a person saying "I don't want to see deleted files" and thus this being quicker, but equally a user saying "I only want to see deleted files" and thus needing to uncheck multiple. Each direction indirectly gives preference to a particular flow. This feels like something we would want to base on user research on what problems are most common that a filter could solve.

@Gr8z
Copy link
Contributor Author

Gr8z commented May 27, 2025

Hi @tidy-dev, thank you for the detailed feedback.

Regarding the issue requirement - You're absolutely right. I should have first opened an issue to discuss the need and gather feedback on whether this feature would be valuable to the user base. I'll create an issue to start that discussion.

Thank you for the clarification about GitHub Desktop's staging behavior. I'll revise the terminology to use "Included in commit"/"Excluded from commit".

Filter approach—I did not go for exclusion; I think the screenshot might be misleading. The default state is all unchecked. Filters can be included when you select them, and the condition for multiple filters is "OR." That means if I select Deleted and Modified filters, it will show me Deleted "OR" modified files.

However, I agree that this assumption should be validated with user research. We should understand:

  • What are the most common filtering needs?
  • Do users more often want to exclude certain types or focus on specific types?
  • What mental model do users have when thinking about filtering their changes?

Would you recommend:

  • Pausing this PR while we gather user feedback through an issue discussion?
  • Or would you prefer I update the PR with the correct terminology first, so we can better evaluate the implementation while the user research is conducted?

I'm happy to take either approach and appreciate your guidance on making this contribution more aligned with the project's needs.

@tidy-dev
Copy link
Contributor

tidy-dev commented May 27, 2025

Pausing this PR while we gather user feedback through an issue discussion

Yes. Pausing for now as I do not want to utilize your time on something that will likely take quite some time to garner feedback. Once I discuss it with my team, I will update on if we think we might move forward with it soon or it should be closed until more user feedback is obtained. Thank you for being so understanding. :)

@tidy-dev tidy-dev marked this pull request as draft May 27, 2025 13:32
@tidy-dev
Copy link
Contributor

@Gr8z We discussed this today in a team sync and filtering by file status is one of the iterations that we had considered being a next iteration as it was requested in the original filtering changes issue. Thus, there is prior intention for this filter to be added. We may like to move forward with, but have tabled it for further discussion in an upcoming sync in mid June.

Thus, I moved it to draft instead of closing it.

Things we know without in depth review:

  • Previously mentioned "Included in commit"/"Excluded in commit" copy
  • A "Clear all" link or button at the bottom of the filter options.
  • The desktop/desktop work for adding in stats tracking on usage of these new filters. (Search incrementMetric for prior art)
  • Updating the "No results" message to have a bulleted list of applied filters "Sorry, I can't find any changes files matching the following filters: " Such that the applied filters list is scannable.

I will leave it up to you if you want to work on those with out a solid yes.

@Gr8z
Copy link
Contributor Author

Gr8z commented May 28, 2025

Thank you @tidy-dev, I'm happy to work on the suggested improvements while your team continues the discussion:

  • Update terminology to "Included in commit/Excluded from commit"
  • Add a "Clear all" button for better UX
  • Implement usage metrics tracking using incrementMetric
  • Improve the "No results" message with a scannable bulleted list of applied filters

I'll start working on these changes to have them ready for when you guys make a final decision in mid-June.

Gr8z added 2 commits June 12, 2025 17:21
- Update terminology from "staged/unstaged" to "included in commit/excluded from commit"
- Add clear filters functionality with buttons in dropdown and empty state
- Implement comprehensive metrics tracking for all filter operations
- Enhance no results message with bulleted list of active filters
- Add responsive empty state design with proper container queries
- Fix hidden changes warning to work with all filter types
- Add extensive test coverage for clear filters functionality
- Verify OR logic implementation in filter operations

This completes PR desktop#20537 with full feature implementation and test coverage.
@Gr8z
Copy link
Contributor Author

Gr8z commented Jun 13, 2025

Hi @tidy-dev

I have added the changes that you requested. Please take a look now.

  • Update terminology from "staged/unstaged" to "included in commit/excluded from commit"
  • Add clear filters functionality with buttons in dropdown and empty state
  • Implement comprehensive metrics tracking for all filter operations
  • Enhance no results message with bulleted list of active filters
  • Add responsive empty state design with proper container queries
  • Fix hidden changes warning to work with all filter types
  • Add extensive test coverage for clear filters functionality

Screenshots

image
image

@Gr8z Gr8z marked this pull request as ready for review June 16, 2025 07:04
Copy link
Contributor

@tidy-dev tidy-dev left a comment

Choose a reason for hiding this comment

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

Thank you for all your work thus far. 💖 This is generally looking good.

Lots of feedback for you for my initial review on the logical "OR" approach. Feel free to ask questions if anything isn't clear.

FYI, going to gather some feedback from a coworker on the unit tests as they just did a bunch of work in that realm

@@ -242,6 +242,11 @@ const DefaultDailyMeasures: IDailyMeasures = {
previewedPullRequestCount: 0,
typedInChangesFilterCount: 0,
appliesIncludedInCommitFilterCount: 0,
appliesExcludedFromCommitFilterCount: 0,
appliesNewFilesFilterCount: 0,
Copy link
Contributor

Choose a reason for hiding this comment

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

Just for future proofing, Can we add the word Changes in from of Filter for all these files status stats since there are files lists elsewhere in the app. e.g. appliesNewFilesChangesFilterCount

.. The Include/Exclude from commit should be unique enough since that is something you do in the changes list.

@Gr8z
Copy link
Contributor Author

Gr8z commented Jun 18, 2025

  • Updated filter state interface - Refactored to use the new FileListFilterState interface for better type safety
  • Improved filter statistics naming - Added "Changes" prefix to filter stats for clarity
  • Enhanced no results message - Changed to comma-delimited format for better readability when multiple filters are active
  • Improved CSS overflow handling - Updated styles for better overflow behavior and top alignment in the filter dropdown

image
image

I am waiting for a decision on the AND and OR discussion for me to add those changes (or not).

niik
niik previously requested changes Jun 18, 2025
Copy link
Member

@niik niik left a comment

Choose a reason for hiding this comment

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

I was asked to review the tests in this PR and the sheer volume of tests here made it impossible for me to go through them all but I've skimmed through a lot of them and I see a lot of the same patterns so I've reviewed the patterns and not each test so I apologize if I've missed something of substance but the tests that I've looked at are all self-contained in so far that the only way they could break is if we changed the tests themselves.

Copy link
Contributor

@tidy-dev tidy-dev left a comment

Choose a reason for hiding this comment

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

Thank you for those changes. Just a couple more nits I think. Will do some functional testing today.

@Gr8z
Copy link
Contributor Author

Gr8z commented Jun 25, 2025

  • Removed duplicate IFileFilterState interface from filter-changes-logic.ts
  • Now using single IFileListFilterState interface from app-state.ts throughout the codebase
  • Exported IChangesListItem from filter-changes-list.tsx instead of duplicating it
  • Kept getCheckBoxValueFromIncludeAll outside the component as requested
  • Direct function calls to getNoResultsMessage without wrapper

@Gr8z
Copy link
Contributor Author

Gr8z commented Jul 7, 2025

@tidy-dev do you have any more updates to move this forward?

Copy link
Contributor

@tidy-dev tidy-dev left a comment

Choose a reason for hiding this comment

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

@Gr8z Sorry it took me a while to get back to you!

There are few things we haven't addressed from some of my previous feedback. I apologize for not summarizing it in one place. I decided to see if I could wrap that up real quick for you so we can get this merged and found a few places we can make the code a little cleaner/more efficient Take a look and see if you agree with the changes and pull them in if so. :)

Things it does previously discussed or inferred:

  • Makes the filter options count reflect the number of changes that are currently in the list that match the filter. (respecting the AND logic) (So that when you apply a filter the list will narrow to the number shown)
  • Makes a couple of the methods not have a redundant filterText parameter since that is now on the filter state object.
  • Removes the redundant get fileFilterState method in favor of directly referring to the props since there is no mutation of the props state happening.

In addition,

  • Consolidated the count methods into a single memoized method such that we don't need to loop through all the filtered values for every count metric as they should all be recounted anytime the filtered values or working directory changes.
  • I moved the filter popover logic into it's own component to group it's logic together. (Not necessary, just seems easier to digest to me and possibly something I should have done originally when introducing the popover)
  • Added some helper methods on to the FileChange classes to make the filter logic a little cleaner.

@Gr8z
Copy link
Contributor Author

Gr8z commented Jul 9, 2025

Nice @tidy-dev, took a look at your changes and it looks super clean. I apologize if I missed any of your comments or misinterpreted them.

One thing, though, I am not sure if showing the count this way is the right way to go. The filter option counts should show the independent counts, not the combined AND counts.

image

I have two files here to be committed, but you can't tell because the count is 0.

@tidy-dev
Copy link
Contributor

tidy-dev commented Jul 9, 2025

The filter option counts should show the independent counts, not the combined AND counts.

I can see where you are coming from. And, I view them as filters and I think the number should help the user use the filter. Just like on any e-commerce site, if you put a search term in, and you receive 100 results. There are additional filters usually provided such as color or rating. Those filters often tell you of the 100 results present 60 are blue and 50 have 4 star rating. But.. if I apply the blue filter, now my list has 60 items and now the ratings counts are updated to say there are 10 items with 4 star ratings in the list (that are blue and match the search term).

If we flip this and leave them as independent counts, say I have 100 files in the list and 50 are new, 30 are modified, and 20 are deleted. 50 of them are checked and 50 are not. I open the filter and see those counts. I apply the "New files" filter. The lists filters down to the 50 files. I open the filter options again and I still see 50 are checked and 50 are not checked.. but there are only 50 files in the list.. so I have no idea how many are going to show if I checked "Included in commit".

Where as if the filter options inform you of how many files the filter will filter to, when I opened it the second time it should look like "New files" (50), modified/deleted (0), and could look something like "Included in commit" (10) and "Excluded from commit" (40). Now I know if I apply the modified or deleted filter, there will be 0 left in the list and if I apply the "Included in commit" there will be 10 left in the list.

Additionally, that is the way the filter works today, if you have 100 files in the list and apply a "test" string then open the filter options the "Included in commit" count will be something < 100 even if all 100 were checked prior to the search string.

I propose for now we keep the logic inline with the first iteration and see what kind of community feedback we get for it. Another iteration could be completely switching this logic or could be something like having a (0/100) where the first number shows the filter applied and the second number is the independent count. We do this for the string filter.

@Gr8z
Copy link
Contributor Author

Gr8z commented Jul 10, 2025

The e-commerce analogy misses a key difference in user intent. In e-commerce, users refine searches to shrink choices and discover products from an unknown catalog. In Git clients, users aren't discovering files - they're verifying and organizing work they've already done. They need transparency about repository state to maintain accurate mental models, not guidance on what subset to focus on.

When I see "Included in commit (0)" but know I have staged files, it's unclear whether the filter is working correctly, there's a bug, or I've misunderstood the interface. Independent counts would show "Included in commit (2)" regardless of other filters, making it clear that 2 files are staged and the current 0 result is due to filter intersection. The dual format "Included in commit (0/2)" could provide both contextual and absolute info.

is there a beta testing branch with an enough user pool to test both approaches and gather actual feedback before committing to either pattern?

@tidy-dev
Copy link
Contributor

tidy-dev commented Jul 10, 2025

e-commerce, users refine searches to shrink choices

That is my analogy. Using the filter to shrink (filter) choices to smaller subset to commit.. or just find a file to look at in the diff. This component is a tool to accomplish filtering not about summarizing what they already know. Tho, I do agree that it is not perfect analogy as you note about unknown total list versus a finite known list. I revert back to the purpose of the list. The purpose is to allow users to either (1) select a file to review the diff or (2) check files to include in the commit. The filter was made to assist in those purposes when the list is long enough to be hard to scan or you must scroll to find a file. Thus, it purpose is to narrow the list.. not provide ancillary information about the list.

The dual format "Included in commit (0/2)" could provide both contextual and absolute info.

Again to your point, I can see someone using the ancillary information as form of confirmation that the list reflects what they expect it to before they commit so it can also be useful in assisting in commit files.

The reason I am hesitant in implementing this solution now is a prior design discussion my team held where we considered it on the first iteration, but chose to limit the design to necessary information for the filter function instead of more numbers to figure out what they represent as the space is too limited to really communicate what they represent.

beta testing branch

Great idea! Check out the feature-flag.ts and add a new one to encapsulate these new filters and we will hold to the beta channel for a few months to have a chance to gather some feedback. The beta channel is not a large cohort so it takes time to reasonably obtain some feedback.

@Gr8z
Copy link
Contributor Author

Gr8z commented Jul 11, 2025

I completely understand your perspective, and I trust your judgment. The space constraints you mention are also valid concerns.

Either we can implement a feature flag and wait, or, since, in my opinion, this isn't a disruptive feature, users can choose not to use it or completely hide it from view. We can then merge it as is and get fast feedback.

@tidy-dev
Copy link
Contributor

Not disruptive.

I agree. If you like to just pull the changes in from my commit, I will take another look and maybe we can get this merged. :)

tidy-dev and others added 3 commits July 11, 2025 16:00
- Make counts reflect "AND" logic
- Simply some methods that can just consume the filter state
Replaces direct property checks and enum comparisons with method calls on the FileChange object for filtering changes. This improves encapsulation and readability by delegating status checks to the change object's methods.
@Gr8z
Copy link
Contributor Author

Gr8z commented Jul 11, 2025

Sounds good, Done!

Copy link
Contributor

@tidy-dev tidy-dev left a comment

Choose a reason for hiding this comment

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

Working as expected. ✨ Super close to merge, but build is failing due to test relying on a object cast instead of instantiating the class as well as a linter error. I have added suggestions to fix the unit test error and then should just need to run yarn lint:fix to address the formatting issue.

@Gr8z
Copy link
Contributor Author

Gr8z commented Jul 15, 2025

Updated the tests, they are all passing now @tidy-dev

Copy link
Contributor

@tidy-dev tidy-dev left a comment

Choose a reason for hiding this comment

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

🎉 Thanks for all the iterations and thoughtful discussion @Gr8z!

@tidy-dev tidy-dev merged commit d59e155 into desktop:development Jul 15, 2025
7 checks passed
Copy link

@materesarmt-coder materesarmt-coder left a comment

Choose a reason for hiding this comment

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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
external Pull request originating outside of the Desktop core team triage For incoming issues
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants