diff --git a/src/Models/HistoryFilter.cs b/src/Models/HistoryFilter.cs index 369b237d7..610dcd5a0 100644 --- a/src/Models/HistoryFilter.cs +++ b/src/Models/HistoryFilter.cs @@ -10,6 +10,7 @@ public enum FilterType RemoteBranch, RemoteBranchFolder, Tag, + TagFolder, } public enum FilterMode diff --git a/src/Models/RepositoryUIStates.cs b/src/Models/RepositoryUIStates.cs index 4bf58d02b..1b66e80b6 100644 --- a/src/Models/RepositoryUIStates.cs +++ b/src/Models/RepositoryUIStates.cs @@ -406,7 +406,25 @@ public void RemoveBranchFiltersByPrefix(string pattern) foreach (var filter in HistoryFilters) { - if (filter.Type == FilterType.Tag) + if (filter.Type is FilterType.Tag or FilterType.TagFolder) + continue; + + if (filter.Pattern.StartsWith(prefix, StringComparison.Ordinal)) + dirty.Add(filter); + } + + foreach (var filter in dirty) + HistoryFilters.Remove(filter); + } + + public void RemoveTagFiltersByPrefix(string pattern) + { + var dirty = new List(); + var prefix = $"{pattern}/"; + + foreach (var filter in HistoryFilters) + { + if (filter.Type is not (FilterType.Tag or FilterType.TagFolder)) continue; if (filter.Pattern.StartsWith(prefix, StringComparison.Ordinal)) @@ -483,6 +501,8 @@ private void BuildHistoryParamsForIncluded(StringBuilder builder) builder.Append($"--remotes={filter.Pattern.AsSpan(13)}/* "); else if (filter.Type == FilterType.Tag) builder.Append($"refs/tags/{filter.Pattern} "); + else if (filter.Type == FilterType.TagFolder) + builder.Append($"--tags={filter.Pattern}/* "); } } @@ -503,6 +523,8 @@ private void BuildHistoryParamsForExcluded(StringBuilder builder, string gitDir) excludedRemotes.Add($"--exclude=\"{filter.Pattern.AsSpan(13)}/*\" --decorate-refs-exclude=\"{filter.Pattern}/*\" "); else if (filter.Type == FilterType.Tag) excludedTags.Add($"--exclude=\"{filter.Pattern}\" --decorate-refs-exclude=\"refs/tags/{filter.Pattern}\" "); + else if (filter.Type == FilterType.TagFolder) + excludedTags.Add($"--exclude=\"{filter.Pattern}/*\" --decorate-refs-exclude=\"refs/tags/{filter.Pattern}/*\" "); } foreach (var b in excludedBranches) diff --git a/src/ViewModels/Repository.cs b/src/ViewModels/Repository.cs index e303facd5..aab132968 100644 --- a/src/ViewModels/Repository.cs +++ b/src/ViewModels/Repository.cs @@ -1007,6 +1007,11 @@ public void UpdateBranchNodeIsExpanded(BranchTreeNode node) } public void SetTagFilterMode(Models.Tag tag, Models.FilterMode mode) + { + SetTagFilterMode(tag.Name, false, mode); + } + + public void SetTagFilterMode(string path, bool isFolder, Models.FilterMode mode) { // Auto turn off `FocusOnCurrentBranch` when user set a tag filter manually. if (_uiStates.FocusOnCurrentBranch) @@ -1015,9 +1020,23 @@ public void SetTagFilterMode(Models.Tag tag, Models.FilterMode mode) OnPropertyChanged(nameof(FocusOnCurrentBranch)); } - var changed = _uiStates.UpdateHistoryFilters(tag.Name, Models.FilterType.Tag, mode); - if (changed) - RefreshHistoryFilters(true); + var type = isFolder ? Models.FilterType.TagFolder : Models.FilterType.Tag; + var changed = _uiStates.UpdateHistoryFilters(path, type, mode); + if (!changed) + return; + + if (isFolder) + _uiStates.RemoveTagFiltersByPrefix(path); + + var lastSepIdx = path.LastIndexOf('/'); + while (lastSepIdx > 0) + { + path = path.Substring(0, lastSepIdx); + _uiStates.UpdateHistoryFilters(path, Models.FilterType.TagFolder, Models.FilterMode.None); + lastSepIdx = path.LastIndexOf('/'); + } + + RefreshHistoryFilters(true); } public void SetBranchFilterMode(Models.Branch branch, Models.FilterMode mode, bool clearExists, bool refresh) diff --git a/src/ViewModels/TagCollection.cs b/src/ViewModels/TagCollection.cs index 05b04f5b1..83a45cd0e 100644 --- a/src/ViewModels/TagCollection.cs +++ b/src/ViewModels/TagCollection.cs @@ -88,15 +88,13 @@ public TagTreeNode(string path, bool isExpanded, int depth) public void UpdateFilterMode(Dictionary filters) { + FilterMode = filters.GetValueOrDefault(FullPath, Models.FilterMode.None); + if (Tag == null) { foreach (var child in Children) child.UpdateFilterMode(filters); } - else - { - FilterMode = filters.GetValueOrDefault(FullPath, Models.FilterMode.None); - } } public static List Build(List tags, HashSet expanded) diff --git a/src/Views/FilterModeSwitchButton.axaml.cs b/src/Views/FilterModeSwitchButton.axaml.cs index 91c20d823..a7cbe83a4 100644 --- a/src/Views/FilterModeSwitchButton.axaml.cs +++ b/src/Views/FilterModeSwitchButton.axaml.cs @@ -70,9 +70,9 @@ private void OnChangeFilterModeButtonClicked(object sender, RoutedEventArgs e) var menu = new ContextMenu(); if (DataContext is ViewModels.TagListItem tagItem) - FillContextMenuForTag(menu, repo, tagItem.Tag, tagItem.FilterMode); + FillContextMenuForTag(menu, repo, tagItem.Tag.Name, false, tagItem.FilterMode); else if (DataContext is ViewModels.TagTreeNode tagNode) - FillContextMenuForTag(menu, repo, tagNode.Tag, tagNode.FilterMode); + FillContextMenuForTag(menu, repo, tagNode.FullPath, tagNode.IsFolder, tagNode.FilterMode); else if (DataContext is ViewModels.BranchTreeNode branchNode) FillContextMenuForBranch(menu, repo, branchNode, branchNode.FilterMode); @@ -83,7 +83,7 @@ private void OnChangeFilterModeButtonClicked(object sender, RoutedEventArgs e) e.Handled = true; } - private void FillContextMenuForTag(ContextMenu menu, ViewModels.Repository repo, Models.Tag tag, Models.FilterMode current) + private void FillContextMenuForTag(ContextMenu menu, ViewModels.Repository repo, string path, bool isFolder, Models.FilterMode current) { if (current != Models.FilterMode.None) { @@ -91,7 +91,7 @@ private void FillContextMenuForTag(ContextMenu menu, ViewModels.Repository repo, unset.Header = App.Text("Repository.FilterCommits.Default"); unset.Click += (_, ev) => { - repo.SetTagFilterMode(tag, Models.FilterMode.None); + repo.SetTagFilterMode(path, isFolder, Models.FilterMode.None); ev.Handled = true; }; @@ -105,7 +105,7 @@ private void FillContextMenuForTag(ContextMenu menu, ViewModels.Repository repo, include.IsEnabled = current != Models.FilterMode.Included; include.Click += (_, ev) => { - repo.SetTagFilterMode(tag, Models.FilterMode.Included); + repo.SetTagFilterMode(path, isFolder, Models.FilterMode.Included); ev.Handled = true; }; @@ -115,7 +115,7 @@ private void FillContextMenuForTag(ContextMenu menu, ViewModels.Repository repo, exclude.IsEnabled = current != Models.FilterMode.Excluded; exclude.Click += (_, ev) => { - repo.SetTagFilterMode(tag, Models.FilterMode.Excluded); + repo.SetTagFilterMode(path, isFolder, Models.FilterMode.Excluded); ev.Handled = true; }; diff --git a/src/Views/TagsView.axaml b/src/Views/TagsView.axaml index 92e77c1f4..20526b914 100644 --- a/src/Views/TagsView.axaml +++ b/src/Views/TagsView.axaml @@ -51,9 +51,7 @@ - - - +