Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
57 changes: 29 additions & 28 deletions src/NuGet.Clients/NuGet.PackageManagement.UI/PackageItemLoader.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,8 @@
using Microsoft.VisualStudio.Shell;
using Microsoft.VisualStudio.Threading;
using NuGet.Common;
using NuGet.PackageManagement.UI.ViewModels;
using NuGet.PackageManagement.VisualStudio;
using NuGet.Packaging.Core;
using NuGet.Protocol.Core.Types;
using NuGet.Versioning;
using NuGet.VisualStudio;
Expand Down Expand Up @@ -262,17 +262,17 @@ public IEnumerable<PackageItemViewModel> GetCurrent()
return Enumerable.Empty<PackageItemViewModel>();
}

var listItemViewModels = new List<PackageItemViewModel>();
var listItemViewModels = new List<PackageItemViewModel>(capacity: _state.ItemsCount);

foreach (PackageSearchMetadataContextInfo metadata in _state.Results.PackageSearchItems)
foreach (PackageSearchMetadataContextInfo metadataContextInfo in _state.Results.PackageSearchItems)
Comment thread
nkolev92 marked this conversation as resolved.
{
VersionRange allowedVersions = VersionRange.All;
VersionRange versionOverride = null;

// get the allowed version range and pass it to package item view model to choose the latest version based on that
if (_packageReferences != null)
{
IEnumerable<IPackageReferenceContextInfo> matchedPackageReferences = _packageReferences.Where(r => StringComparer.OrdinalIgnoreCase.Equals(r.Identity.Id, metadata.Identity.Id));
IEnumerable<IPackageReferenceContextInfo> matchedPackageReferences = _packageReferences.Where(r => StringComparer.OrdinalIgnoreCase.Equals(r.Identity.Id, metadataContextInfo.Identity.Id));
VersionRange[] allowedVersionsRange = matchedPackageReferences.Select(r => r.AllowedVersions).Where(v => v != null).ToArray();
VersionRange[] versionOverrides = matchedPackageReferences.Select(r => r.VersionOverride).Where(v => v != null).ToArray();

Expand All @@ -287,30 +287,34 @@ public IEnumerable<PackageItemViewModel> GetCurrent()
}
}

var packageLevel = metadata.TransitiveOrigins != null ? PackageLevel.Transitive : PackageLevel.TopLevel;
var packageLevel = metadataContextInfo.TransitiveOrigins != null ? PackageLevel.Transitive : PackageLevel.TopLevel;

var transitiveToolTipMessage = string.Empty;
if (packageLevel == PackageLevel.Transitive)
{
transitiveToolTipMessage = string.Format(CultureInfo.CurrentCulture, Resources.PackageVersionWithTransitiveOrigins, metadata.Identity.Version, string.Join(", ", metadata.TransitiveOrigins));
transitiveToolTipMessage = string.Format(CultureInfo.CurrentCulture, Resources.PackageVersionWithTransitiveOrigins, metadataContextInfo.Identity.Version, string.Join(", ", metadataContextInfo.TransitiveOrigins));
}

ImmutableList<KnownOwnerViewModel> knownOwnerViewModels = LoadKnownOwnerViewModels(metadataContextInfo);

var listItem = new PackageItemViewModel(_searchService, _packageVulnerabilityService)
{
Id = metadata.Identity.Id,
Version = metadata.Identity.Version,
IconUrl = metadata.IconUrl,
Author = metadata.Authors,
DownloadCount = metadata.DownloadCount,
Summary = metadata.Summary,
Id = metadataContextInfo.Identity.Id,
Version = metadataContextInfo.Identity.Version,
IconUrl = metadataContextInfo.IconUrl,
Owner = metadataContextInfo.Owners,
KnownOwnerViewModels = knownOwnerViewModels,
Author = metadataContextInfo.Authors,
DownloadCount = metadataContextInfo.DownloadCount,
Summary = metadataContextInfo.Summary,
AllowedVersions = allowedVersions,
VersionOverride = versionOverride,
PrefixReserved = metadata.PrefixReserved && !IsMultiSource,
Recommended = metadata.IsRecommended,
RecommenderVersion = metadata.RecommenderVersion,
Vulnerabilities = metadata.Vulnerabilities,
PrefixReserved = metadataContextInfo.PrefixReserved && !IsMultiSource,
Recommended = metadataContextInfo.IsRecommended,
RecommenderVersion = metadataContextInfo.RecommenderVersion,
Vulnerabilities = metadataContextInfo.Vulnerabilities,
Sources = _packageSources,
PackagePath = metadata.PackagePath,
PackagePath = metadataContextInfo.PackagePath,
PackageFileService = _packageFileService,
IncludePrerelease = _includePrerelease,
PackageLevel = packageLevel,
Expand All @@ -323,7 +327,7 @@ public IEnumerable<PackageItemViewModel> GetCurrent()
}
else
{
listItem.UpdateTransitivePackageStatus(metadata.Identity.Version);
listItem.UpdateTransitivePackageStatus(metadataContextInfo.Identity.Version);
}

listItemViewModels.Add(listItem);
Expand All @@ -332,18 +336,15 @@ public IEnumerable<PackageItemViewModel> GetCurrent()
return listItemViewModels.ToArray();
}

private async Task<IReadOnlyCollection<VersionInfoContextInfo>> GetVersionInfoAsync(PackageIdentity identity)
private static ImmutableList<KnownOwnerViewModel> LoadKnownOwnerViewModels(PackageSearchMetadataContextInfo metadataContextInfo)
{
Assumes.NotNull(identity);

return await _searchService.GetPackageVersionsAsync(identity, _packageSources, _includePrerelease, CancellationToken.None);
}

private async Task<(PackageSearchMetadataContextInfo, PackageDeprecationMetadataContextInfo)> GetDetailedPackageSearchMetadataContextInfoAsync(PackageIdentity identity)
{
Assumes.NotNull(identity);
ImmutableList<KnownOwnerViewModel> knownOwnerViewModels = null;
if (metadataContextInfo.KnownOwners != null)
{
knownOwnerViewModels = metadataContextInfo.KnownOwners.Select(knownOwner => new KnownOwnerViewModel(knownOwner)).ToImmutableList();
}

return await _searchService.GetPackageMetadataAsync(identity, _packageSources, _includePrerelease, CancellationToken.None);
return knownOwnerViewModels;
}

public void Dispose()
Expand Down

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 6 additions & 0 deletions src/NuGet.Clients/NuGet.PackageManagement.UI/Resources.resx
Original file line number Diff line number Diff line change
Expand Up @@ -1042,4 +1042,10 @@ Please see https://aka.ms/troubleshoot_nuget_cache for more help.</value>
<value>The package `{0}` is available in the Global packages folder, but the source it came from `{1}` is not one of the configured sources.</value>
<comment>{0} is the package ID. {1} is the URI of the package source found in the Global packages folder.</comment>
</data>
<data name="Text_ByOwner" xml:space="preserve">
<value>by {0}</value>
</data>
<data name="Text_By" xml:space="preserve">
<value>by</value>
</data>
</root>
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@
x:Key="EmptyEnumerableToVisibilityConverter" />
<nuget:EnumerableToVisibilityConverter
x:Key="EnumerableToVisibilityConverter" />
<nuget:LastItemToVisibilityConverter
x:Key="LastItemToVisibilityConverter" />
<nuget:InverseBooleanConverter
x:Key="InverseBooleanConverter" />
<nuget:BooleanToGridRowHeightConverter
Expand Down Expand Up @@ -684,6 +686,29 @@
</Style.Triggers>
</Style>

<Style x:Key="HyperlinkSelectorAware" TargetType="{x:Type Hyperlink}" BasedOn="{StaticResource {x:Static vs:VsResourceKeys.ThemedDialogHyperlinkStyleKey}}">
<Style.Triggers>
<MultiDataTrigger>
<MultiDataTrigger.Conditions>
<Condition Binding="{Binding IsSelected, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=ListBoxItem}}" Value="True" />
<Condition Binding="{Binding (Selector.IsSelectionActive), RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=ListBoxItem}}" Value="False" />
</MultiDataTrigger.Conditions>
<Setter
Property="Foreground"
Value="{DynamicResource {x:Static nuget:Brushes.ContentInactiveSelectedTextBrushKey}}" />
</MultiDataTrigger>
<MultiDataTrigger>
<MultiDataTrigger.Conditions>
<Condition Binding="{Binding IsSelected, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=ListBoxItem}}" Value="True" />
<Condition Binding="{Binding (Selector.IsSelectionActive), RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=ListBoxItem}}" Value="True" />
</MultiDataTrigger.Conditions>
<Setter
Property="Foreground"
Value="{DynamicResource {x:Static nuget:Brushes.ContentSelectedTextBrushKey}}" />
</MultiDataTrigger>
</Style.Triggers>
</Style>

<Style
x:Key="PackageIconImageStyle"
TargetType="{x:Type Image}">
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.

using System;
using System.Diagnostics;
using System.Globalization;
using System.Windows;
using System.Windows.Data;

namespace NuGet.PackageManagement.UI
{
internal class LastItemToVisibilityConverter : IMultiValueConverter
{
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
{
if (values != null && values.Length == 2
&& values[0] is int currentIndex
&& values[1] is int length)
{
if (currentIndex < 0 || length < 1 || currentIndex >= length)
{
return DependencyProperty.UnsetValue;
}

int lastIndex = length - 1;
return Equals(currentIndex, lastIndex) ? Visibility.Collapsed : Visibility.Visible;
}

return DependencyProperty.UnsetValue;
}

public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
{
Debug.Fail("Not Implemented");
return null;
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.

using System;
using NuGet.VisualStudio.Internal.Contracts;

namespace NuGet.PackageManagement.UI.ViewModels
{
public class KnownOwnerViewModel
{
private string _name;
private Uri _link;

public KnownOwnerViewModel(KnownOwner knownOwner)
{
_name = knownOwner.Name;
_link = knownOwner.Link;
}

public string Name => _name;
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

public string Name {get;} is syntactic sugar over having a private and public field.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

True, I created a field at some point during development, but it's not really necessary, I'll revise that.


public Uri Link => _link;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.ComponentModel;
using System.Globalization;
using System.IO;
Expand All @@ -15,6 +16,7 @@
using System.Windows.Media.Imaging;
using Microsoft;
using Microsoft.VisualStudio.Threading;
using NuGet.PackageManagement.UI.ViewModels;
using NuGet.PackageManagement.VisualStudio;
using NuGet.Packaging.Core;
using NuGet.Versioning;
Expand Down Expand Up @@ -64,6 +66,10 @@ public PackageItemViewModel(INuGetSearchService searchService, IPackageVulnerabi

public bool IncludePrerelease { get; set; }

public ImmutableList<KnownOwnerViewModel> KnownOwnerViewModels { get; internal set; }

public string Owner { get; internal set; }

private string _author;
public string Author
{
Expand All @@ -79,11 +85,54 @@ public string Author
}
}

/// <summary>
/// When a collection of <see cref="KnownOwnerViewModels"/> is available, this property returns the <see cref="PackageSearchMetadataContextInfo.Owners"/>
/// string which contains the package owner name(s).
/// If the collection exists but is empty, it's treated as there being no assigned owner for this package by returning an empty string.
/// Otherwise, when there's no collection or no Owners string, it returns null.
/// </summary>
private string ByOwner
{
get
{
// Owners is only used when we have Known Owners.
if (KnownOwnerViewModels == null)
{
return null;
}

// Empty Known Owners is treated as there being no assigned owner for this package.
if (KnownOwnerViewModels.IsEmpty)
{
return string.Empty;
}

// Having Known Owners but with an empty Owners string is treated as there being no assigned owner for this package.
if (string.IsNullOrWhiteSpace(Owner))
{
return string.Empty;
}

return string.Format(CultureInfo.CurrentCulture, Resx.Text_ByOwner, Owner);
}
}

public string ByAuthor
{
get
{
return _author != null ? string.Format(CultureInfo.CurrentCulture, Resx.Text_ByAuthor, _author) : null;
return !string.IsNullOrWhiteSpace(_author) ? string.Format(CultureInfo.CurrentCulture, Resx.Text_ByAuthor, _author) : null;
}
}

/// <summary>
/// Fallback to <see cref="ByAuthor"/> only when <see cref="ByOwner"> is null.
/// </summary>
public string ByOwnerOrAuthor
{
get
{
return ByOwner ?? ByAuthor;
}
}

Expand Down
Loading