Skip to content

Commit 5b0ee25

Browse files
authored
Allow Floating Versions in PM UI (#4478)
* Allow Floating Versions in PM UI
1 parent 081f5d0 commit 5b0ee25

File tree

25 files changed

+1312
-55
lines changed

25 files changed

+1312
-55
lines changed

Diff for: src/NuGet.Clients/NuGet.PackageManagement.UI/Actions/UIActionEngine.cs

+1
Original file line numberDiff line numberDiff line change
@@ -835,6 +835,7 @@ private async Task<IReadOnlyList<ProjectAction>> GetActionsAsync(
835835
includePrelease,
836836
uiService.DependencyBehavior,
837837
packageSourceNames,
838+
userAction.VersionRange,
838839
token);
839840

840841
results.AddRange(actions);

Diff for: src/NuGet.Clients/NuGet.PackageManagement.UI/DisplayVersion.cs

+15-2
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,19 @@ public DisplayVersion(
3636
bool autoReferenced = false,
3737
bool isDeprecated = false,
3838
string versionFormat = "N")
39+
: this(range, version: null, additionalInfo, isValidVersion, isCurrentInstalled, autoReferenced, isDeprecated, versionFormat)
40+
{
41+
}
42+
43+
public DisplayVersion(
44+
VersionRange range,
45+
NuGetVersion version,
46+
string additionalInfo,
47+
bool isValidVersion = true,
48+
bool isCurrentInstalled = false,
49+
bool autoReferenced = false,
50+
bool isDeprecated = false,
51+
string versionFormat = "N")
3952
{
4053
if (versionFormat == null)
4154
{
@@ -48,13 +61,13 @@ public DisplayVersion(
4861

4962
IsValidVersion = isValidVersion;
5063

51-
Version = range.MinVersion;
64+
Version = version ?? range.MinVersion;
5265
IsCurrentInstalled = isCurrentInstalled;
5366
AutoReferenced = autoReferenced;
5467
IsDeprecated = isDeprecated;
5568

5669
// Display a single version if the range is locked
57-
if (range.HasLowerAndUpperBounds && range.MinVersion == range.MaxVersion)
70+
if (range.OriginalString == null && range.HasLowerAndUpperBounds && range.MinVersion == range.MaxVersion)
5871
{
5972
var formattedVersionString = Version.ToString(versionFormat, VersionFormatter.Instance);
6073

Diff for: src/NuGet.Clients/NuGet.PackageManagement.UI/Models/DetailControlModel.cs

+78-9
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,8 @@ protected DetailControlModel(
6161

6262
// hook event handler for dependency behavior changed
6363
_options.SelectedChanged += DependencyBehavior_SelectedChanged;
64+
65+
_versions = new ItemsChangeObservableCollection<DisplayVersion>();
6466
}
6567

6668
/// <summary>
@@ -70,6 +72,8 @@ public virtual void CleanUp()
7072
{
7173
}
7274

75+
public ICollectionView VersionsView { get; set; }
76+
7377
public void Dispose()
7478
{
7579
Dispose(disposing: true);
@@ -539,16 +543,39 @@ private string GetPackageDeprecationAlternatePackageText(AlternatePackageMetadat
539543
protected abstract Task CreateVersionsAsync(CancellationToken cancellationToken);
540544

541545
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1051:DoNotDeclareVisibleInstanceFields")]
542-
protected List<DisplayVersion> _versions;
546+
protected ItemsChangeObservableCollection<DisplayVersion> _versions;
543547

544548
// The list of versions that can be installed
545-
public List<DisplayVersion> Versions
549+
public ItemsChangeObservableCollection<DisplayVersion> Versions
546550
{
547551
get { return _versions; }
548552
}
549553

550554
public virtual void OnSelectedVersionChanged() { }
551555

556+
private string _userInput;
557+
public string UserInput
558+
{
559+
get
560+
{
561+
return _userInput;
562+
}
563+
set
564+
{
565+
if (_userInput != value)
566+
{
567+
_userInput = value;
568+
569+
if (Versions != null)
570+
{
571+
Versions.Refresh();
572+
}
573+
574+
OnPropertyChanged(nameof(UserInput));
575+
}
576+
}
577+
}
578+
552579
private DisplayVersion _selectedVersion;
553580

554581
public DisplayVersion SelectedVersion
@@ -639,7 +666,7 @@ private async ValueTask SelectedVersionChangedAsync(PackageItemViewModel package
639666
}
640667

641668
// Calculate the version to select among _versions and select it
642-
protected void SelectVersion()
669+
protected void SelectVersion(NuGetVersion latestVersion = null)
643670
{
644671
if (_versions.Count == 0)
645672
{
@@ -656,12 +683,37 @@ protected void SelectVersion()
656683
(_versions.Any(v => v != null && !v.IsValidVersion) &&
657684
_versions.IndexOf(SelectedVersion) > _versions.IndexOf(_versions.FirstOrDefault(v => v != null && !v.IsValidVersion))))
658685
{
659-
// Select the installed version by default.
660-
// Otherwise, select the first version in the version list.
661-
var possibleVersions = _versions.Where(v => v != null);
662-
SelectedVersion =
663-
possibleVersions.FirstOrDefault(v => v.Version.Equals(_searchResultPackage.InstalledVersion))
664-
?? possibleVersions.FirstOrDefault(v => v.IsValidVersion);
686+
// The project level is the only one that has an editable combobox and we can only see one project.
687+
if (!IsSolution && _nugetProjects.Count() == 1 && _nugetProjects.First().ProjectStyle.Equals(ProjectModel.ProjectStyle.PackageReference))
688+
{
689+
// For the Updates and Browse tab we select the latest version, for the installed tab
690+
// select the installed version by default. Otherwise, select the first version in the version list.
691+
IEnumerable<DisplayVersion> possibleVersions = _versions.Where(v => v != null);
692+
if (_filter.Equals(ItemFilter.UpdatesAvailable) || _filter.Equals(ItemFilter.All))
693+
{
694+
SelectedVersion = possibleVersions.FirstOrDefault(v => v.Range.OriginalString.Equals(latestVersion.ToString(), StringComparison.OrdinalIgnoreCase));
695+
UserInput = SelectedVersion.ToString();
696+
}
697+
else
698+
{
699+
SelectedVersion =
700+
possibleVersions.FirstOrDefault(v => StringComparer.OrdinalIgnoreCase.Equals(v.Range?.OriginalString, _searchResultPackage?.AllowedVersions?.OriginalString))
701+
?? possibleVersions.FirstOrDefault(v => v.IsValidVersion);
702+
UserInput = _searchResultPackage.AllowedVersions?.OriginalString ?? SelectedVersion.ToString();
703+
}
704+
705+
if (FirstDisplayedVersion == null)
706+
{
707+
FirstDisplayedVersion = SelectedVersion;
708+
}
709+
}
710+
else
711+
{
712+
var possibleVersions = _versions.Where(v => v != null);
713+
SelectedVersion =
714+
possibleVersions.FirstOrDefault(v => v.Version.Equals(_searchResultPackage.InstalledVersion))
715+
?? possibleVersions.FirstOrDefault(v => v.IsValidVersion);
716+
}
665717
}
666718
}
667719

@@ -674,10 +726,14 @@ public void ClearVersions()
674726
if (_versions != null)
675727
{
676728
_versions.Clear();
729+
FirstDisplayedVersion = null;
677730
OnPropertyChanged(nameof(Versions));
678731
}
679732
}
680733

734+
// Because filtering affects the versions list, we want to display every version when it's opened the first time.
735+
public DisplayVersion FirstDisplayedVersion { get; set; }
736+
681737
public abstract bool IsSolution { get; }
682738

683739
private string _optionsBlockedMessage;
@@ -786,6 +842,19 @@ public bool InstalledVersionIsAutoReferenced
786842
}
787843
}
788844

845+
private string _previousSelectedVersion;
846+
public string PreviousSelectedVersion
847+
{
848+
get
849+
{
850+
return _previousSelectedVersion ?? string.Empty;
851+
}
852+
set
853+
{
854+
_previousSelectedVersion = value;
855+
}
856+
}
857+
789858
protected void SetAutoReferencedCheck(NuGetVersion installedVersion)
790859
{
791860
var autoReferenced = installedVersion != null
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
// Copyright (c) .NET Foundation. All rights reserved.
2+
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
3+
4+
using System.Collections.ObjectModel;
5+
using System.Collections.Specialized;
6+
7+
namespace NuGet.PackageManagement.UI
8+
{
9+
/// <summary>
10+
/// When we bind to an <see cref="ObservableCollection{T}">ObservableCollection</see>, and change Filter criteria based on user input, the WPF binding mechanism doesn't know to refresh the View.
11+
/// This collection provides an event to say the entire collection needs to be re-evaluated, without raising events for each item, and without refreshing the entire View.
12+
/// </summary>
13+
/// <typeparam name="T"></typeparam>
14+
public class ItemsChangeObservableCollection<T> : ObservableCollection<T>
15+
{
16+
public void Refresh()
17+
{
18+
OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset));
19+
}
20+
}
21+
}

0 commit comments

Comments
 (0)